source: trunk/src/Detection/detection.cc @ 269

Last change on this file since 269 was 265, checked in by Matthew Whiting, 17 years ago
  • Enabled output for centroid and peak pixel locations (centroid is proper name for centre-of-mass):
    • New parameter: pixelCentre to determine preferred one for output. Needed similar parameter in the Detection class.
    • Detection::getXCentre() etc now return value based on this parameter. Have new function getXAverage() etc that accesses the average value from the Object3D.
    • Rejigged output functions so there is a difference between screen and file outputs -- screen doesn't have all the different pixel centres, but the file does.
    • Had to change the columns setup in the process.
  • Improved output for merging process.
  • Updated documentation.
File size: 13.1 KB
Line 
1#include <iostream>
2#include <iomanip>
3#include <vector>
4#include <string>
5#include <wcs.h>
6#include <math.h>
7#include <param.hh>
8#include <Utils/utils.hh>
9#include <PixelMap/Voxel.hh>
10#include <PixelMap/Object3D.hh>
11#include <Detection/detection.hh>
12
13using std::setw;
14using std::setprecision;
15using std::endl;
16using std::vector;
17
18using namespace PixelInfo;
19
20Detection::Detection(const Detection& d)
21{
22  this->pixelArray   = d.pixelArray;
23  this->xSubOffset   = d.xSubOffset;
24  this->ySubOffset   = d.ySubOffset;
25  this->zSubOffset   = d.zSubOffset;
26  this->totalFlux    = d.totalFlux;
27  this->intFlux      = d.intFlux;
28  this->peakFlux     = d.peakFlux;
29  this->xpeak        = d.xpeak;
30  this->ypeak        = d.ypeak;
31  this->zpeak        = d.zpeak;
32  this->peakSNR      = d.peakSNR;
33  this->xCentroid    = d.xCentroid;
34  this->yCentroid    = d.yCentroid;
35  this->zCentroid    = d.zCentroid;
36  this->centreType   = d.centreType;
37  this->negSource    = d.negSource;
38  this->flagText     = d.flagText;
39  this->id           = d.id;
40  this->name         = d.name;
41  this->flagWCS      = d.flagWCS;
42  this->raS          = d.raS;
43  this->decS         = d.decS;
44  this->ra           = d.ra;
45  this->dec          = d.dec;
46  this->raWidth      = d.raWidth;
47  this->decWidth     = d.decWidth;
48  this->specUnits    = d.specUnits;
49  this->fluxUnits    = d.fluxUnits;
50  this->intFluxUnits = d.intFluxUnits;
51  this->lngtype      = d.lngtype;
52  this->lattype      = d.lattype;
53  this->vel          = d.vel;
54  this->velWidth     = d.velWidth;
55  this->velMin       = d.velMin;
56  this->velMax       = d.velMax;
57  this->posPrec      = d.posPrec;
58  this->xyzPrec      = d.xyzPrec;
59  this->fintPrec     = d.fintPrec;
60  this->fpeakPrec    = d.fpeakPrec;
61  this->velPrec      = d.velPrec;
62  this->snrPrec      = d.snrPrec;
63}
64
65//--------------------------------------------------------------------
66
67  Detection& Detection::operator= (const Detection& d)
68{
69  this->pixelArray   = d.pixelArray;
70  this->xSubOffset   = d.xSubOffset;
71  this->ySubOffset   = d.ySubOffset;
72  this->zSubOffset   = d.zSubOffset;
73  this->totalFlux    = d.totalFlux;
74  this->intFlux      = d.intFlux;
75  this->peakFlux     = d.peakFlux;
76  this->xpeak        = d.xpeak;
77  this->ypeak        = d.ypeak;
78  this->zpeak        = d.zpeak;
79  this->peakSNR      = d.peakSNR;
80  this->xCentroid    = d.xCentroid;
81  this->yCentroid    = d.yCentroid;
82  this->zCentroid    = d.zCentroid;
83  this->centreType   = d.centreType;
84  this->negSource    = d.negSource;
85  this->flagText     = d.flagText;
86  this->id           = d.id;
87  this->name         = d.name;
88  this->flagWCS      = d.flagWCS;
89  this->raS          = d.raS;
90  this->decS         = d.decS;
91  this->ra           = d.ra;
92  this->dec          = d.dec;
93  this->raWidth      = d.raWidth;
94  this->decWidth     = d.decWidth;
95  this->specUnits    = d.specUnits;
96  this->fluxUnits    = d.fluxUnits;
97  this->intFluxUnits = d.intFluxUnits;
98  this->lngtype      = d.lngtype;
99  this->lattype      = d.lattype;
100  this->vel          = d.vel;
101  this->velWidth     = d.velWidth;
102  this->velMin       = d.velMin;
103  this->velMax       = d.velMax;
104  this->posPrec      = d.posPrec;
105  this->xyzPrec      = d.xyzPrec;
106  this->fintPrec     = d.fintPrec;
107  this->fpeakPrec    = d.fpeakPrec;
108  this->velPrec      = d.velPrec;
109  this->snrPrec      = d.snrPrec;
110}
111
112//--------------------------------------------------------------------
113
114void Detection::calcFluxes(float *fluxArray, long *dim)
115{
116  /**
117   *  A function that calculates total & peak fluxes (and the location
118   *  of the peak flux) for a Detection.
119   *
120   *  \param fluxArray The array of flux values to calculate the
121   *  flux parameters from.
122   *  \param dim The dimensions of the flux array.
123   */
124
125  this->totalFlux = this->peakFlux = 0;
126  this->xCentroid = this->yCentroid = this->zCentroid = 0.;
127  long x,y,z,count=0;
128
129  for(int m=0; m<this->pixelArray.getNumChanMap(); m++){
130    ChanMap tempmap = this->pixelArray.getChanMap(m);
131    z = tempmap.getZ();
132    for(int s=0; s<tempmap.getNumScan(); s++){
133      Scan tempscan = tempmap.getScan(s);
134      y = tempscan.getY();
135      for(long x=tempscan.getX(); x<=tempscan.getXmax(); x++){
136
137        float f = fluxArray[x + y*dim[0] + z*dim[0]*dim[1]];
138        this->totalFlux += f;
139        this->xCentroid += x*f;
140        this->yCentroid += y*f;
141        this->zCentroid += z*f;
142        if( (count==0) ||  //first time round
143            (this->negSource&&(f<this->peakFlux)) ||
144            (!this->negSource&&(f>this->peakFlux))   )
145          {
146            this->peakFlux = f;
147            this->xpeak =    x;
148            this->ypeak =    y;
149            this->zpeak =    z;
150          }
151        count++;
152      }
153    }
154  }
155
156  this->xCentroid /= this->totalFlux;
157  this->yCentroid /= this->totalFlux;
158  this->zCentroid /= this->totalFlux;
159}
160//--------------------------------------------------------------------
161
162void Detection::calcWCSparams(float *fluxArray, long *dim, FitsHeader &head)
163{
164  /**
165   *  Use the input wcs to calculate the position and velocity
166   *    information for the Detection.
167   *  Quantities calculated:
168   *  <ul><li> RA: ra [deg], ra (string), ra width.
169   *      <li> Dec: dec [deg], dec (string), dec width.
170   *      <li> Vel: vel [km/s], min & max vel, vel width.
171   *      <li> coord type for all three axes, nuRest,
172   *      <li> name (IAU-style, in equatorial or Galactic)
173   *  </ul>
174   *  Uses Detection::getIntegFlux(FitsHeader &) to calculate the
175   *  integrated flux in (say) [Jy km/s]
176   *
177   *  Note that the regular parameters are NOT recalculated!
178   *
179   *  \param fluxArray The array of flux values to calculate the
180   *  integrated flux from.
181   *  \param dim The dimensions of the flux array.
182   *  \param head FitsHeader object that contains the WCS information.
183   */
184
185  if(head.isWCS()){
186
187    double *pixcrd = new double[15];
188    double *world  = new double[15];
189    /*
190      define a five-point array in 3D:
191      (x,y,z), (x,y,z1), (x,y,z2), (x1,y1,z), (x2,y2,z)
192      [note: x = central point, x1 = minimum x, x2 = maximum x etc.]
193      and convert to world coordinates.   
194    */
195    pixcrd[0]  = pixcrd[3] = pixcrd[6] = this->getXcentre();
196    pixcrd[9]  = this->getXmin()-0.5;
197    pixcrd[12] = this->getXmax()+0.5;
198    pixcrd[1]  = pixcrd[4] = pixcrd[7] = this->getYcentre();
199    pixcrd[10] = this->getYmin()-0.5;
200    pixcrd[13] = this->getYmax()+0.5;
201    pixcrd[2] = pixcrd[11] = pixcrd[14] = this->getZcentre();
202    pixcrd[5] = this->getZmin();
203    pixcrd[8] = this->getZmax();
204    int flag = head.pixToWCS(pixcrd, world, 5);
205    delete [] pixcrd;
206
207    // world now has the WCS coords for the five points
208    //    -- use this to work out WCS params
209 
210    this->lngtype = head.getWCS()->lngtyp;
211    this->lattype = head.getWCS()->lattyp;
212    this->specUnits = head.getSpectralUnits();
213    this->fluxUnits = head.getFluxUnits();
214    // if fluxUnits are eg. Jy/beam, make intFluxUnits = Jy km/s
215    this->intFluxUnits = head.getIntFluxUnits();
216    this->ra   = world[0];
217    this->dec  = world[1];
218    this->raS  = decToDMS(this->ra, this->lngtype);
219    this->decS = decToDMS(this->dec,this->lattype);
220    this->raWidth = angularSeparation(world[9],world[1],world[12],world[1])*60.;
221    this->decWidth  = angularSeparation(world[0],world[10],world[0],world[13]) * 60.;
222    this->name = head.getIAUName(this->ra, this->dec);
223    this->vel    = head.specToVel(world[2]);
224    this->velMin = head.specToVel(world[5]);
225    this->velMax = head.specToVel(world[8]);
226    this->velWidth = fabs(this->velMax - this->velMin);
227
228    this->getIntegFlux(fluxArray,dim,head);
229   
230    this->flagWCS = true;
231
232    delete [] world;
233
234  }
235}
236//--------------------------------------------------------------------
237
238float Detection::getIntegFlux(float *fluxArray, long *dim, FitsHeader &head)
239{
240  /**
241   *  Uses the input WCS to calculate the velocity-integrated flux,
242   *   putting velocity in units of km/s.
243   *  Integrates over full spatial and velocity range as given
244   *   by the extrema calculated by calcWCSparams.
245   *  If the flux units end in "/beam" (eg. Jy/beam), then the
246   *   flux is corrected by the beam size (in pixels).
247   *
248   *  \param fluxArray The array of flux values.
249   *  \param dim The dimensions of the flux array.
250   *  \param head FitsHeader object that contains the WCS information.
251   */
252
253  // include one pixel either side in each direction
254  long xsize = (this->getXmax()-this->getXmin()+3);
255  long ysize = (this->getYmax()-this->getYmin()+3);
256  long zsize = (this->getZmax()-this->getZmin()+3);
257  vector <bool> isObj(xsize*ysize*zsize,false);
258  vector <float> localFlux(xsize*ysize*zsize,0.);
259  // work out which pixels are object pixels
260  for(int m=0; m<this->pixelArray.getNumChanMap(); m++){
261    ChanMap tempmap = this->pixelArray.getChanMap(m);
262    long z = this->pixelArray.getChanMap(m).getZ();
263    for(int s=0; s<this->pixelArray.getChanMap(m).getNumScan(); s++){
264      long y = this->pixelArray.getChanMap(m).getScan(s).getY();
265      for(long x=this->pixelArray.getChanMap(m).getScan(s).getX();
266          x<=this->pixelArray.getChanMap(m).getScan(s).getXmax();
267          x++){
268        long pos = (x-this->getXmin()+1) + (y-this->getYmin()+1)*xsize
269          + (z-this->getZmin()+1)*xsize*ysize;
270        localFlux[pos] = fluxArray[x + y*dim[0] + z*dim[0]*dim[1]];
271        isObj[pos] = true;
272      }
273    }
274  }
275 
276  // work out the WCS coords for each pixel
277  double *world  = new double[xsize*ysize*zsize];
278  double xpt,ypt,zpt;
279  for(int i=0;i<xsize*ysize*zsize;i++){
280    xpt = double( this->getXmin() -1 + i%xsize );
281    ypt = double( this->getYmin() -1 + (i/xsize)%ysize );
282    zpt = double( this->getZmin() -1 + i/(xsize*ysize) );
283    world[i] = head.pixToVel(xpt,ypt,zpt);
284  }
285
286  this->intFlux = 0.;
287  for(int pix=0; pix<xsize*ysize; pix++){ // loop over each spatial pixel.
288    for(int z=0; z<zsize; z++){
289      int pos =  z*xsize*ysize + pix;
290      if(isObj[pos]){ // if it's an object pixel...
291        float deltaVel;
292        if(z==0)
293          deltaVel = (world[pos+xsize*ysize] - world[pos]);
294        else if(z==(zsize-1))
295          deltaVel = (world[pos] - world[pos-xsize*ysize]);
296        else
297          deltaVel = (world[pos+xsize*ysize] - world[pos-xsize*ysize]) / 2.;
298        this->intFlux += localFlux[pos] * fabs(deltaVel);
299      }
300    }
301  }
302
303  // correct for the beam size if the flux units string ends in "/beam"
304  int size = this->fluxUnits.size();
305  std::string tailOfFluxUnits = this->fluxUnits.substr(size-5,size);
306  if(tailOfFluxUnits == "/beam") this->intFlux /= head.getBeamSize();
307
308  delete [] world;
309}
310//--------------------------------------------------------------------
311
312Detection operator+ (Detection lhs, Detection rhs)
313{
314  /**
315   *  Combines two objects by adding all the pixels using the Object3D
316   *  operator.
317   *
318   *  The pixel parameters are recalculated in the process (equivalent
319   *  to calling pixels().calcParams()), but WCS parameters
320   *  are not.
321   */
322  Detection output;
323  output.pixelArray = lhs.pixelArray + rhs.pixelArray;
324//   output.totalFlux  = lhs.totalFlux  + rhs.totalFlux;
325//   if(lhs.peakFlux > rhs.peakFlux){
326//     output.peakFlux = lhs.peakFlux;
327//     output.xpeak    = lhs.xpeak;
328//     output.ypeak    = lhs.ypeak;
329//     output.zpeak    = lhs.zpeak;
330//     output.peakSNR  = lhs.peakSNR;
331//   }
332//   else{
333//     output.peakFlux = rhs.peakFlux;
334//     output.xpeak    = rhs.xpeak;
335//     output.ypeak    = rhs.ypeak;
336//     output.zpeak    = rhs.zpeak;
337//     output.peakSNR  = rhs.peakSNR;
338//   }
339  return output;
340}
341//--------------------------------------------------------------------
342
343void Detection::setOffsets(Param &par)
344{
345  /**
346   * This function stores the values of the offsets for each cube axis.
347   * The offsets are the starting values of the cube axes that may differ from
348   *  the default value of 0 (for instance, if a subsection is being used).
349   * The values will be used when the detection is outputted.
350   */
351  this->xSubOffset = par.getXOffset();
352  this->ySubOffset = par.getYOffset();
353  this->zSubOffset = par.getZOffset();
354}
355//--------------------------------------------------------------------
356
357bool Detection::hasEnoughChannels(int minNumber)
358{
359  /**
360   * A function to determine if the Detection has enough
361   * contiguous channels to meet the minimum requirement
362   * given as the argument.
363   * \param minNumber How many channels is the minimum acceptable number?
364   * \return True if there is at least one occurence of minNumber consecutive
365   * channels present to return true. False otherwise.
366   */
367
368// Preferred method -- need a set of minNumber consecutive channels present.
369  this->pixelArray.order();
370  int numChannels = 0;
371  bool result = false;
372  int size = this->pixelArray.getNumChanMap();
373  if(size>0) numChannels++;
374  for(int i=1;(i<size && !result);i++) {
375    if( (this->pixelArray.getZ(i) - this->pixelArray.getZ(i-1)) == 1)
376      numChannels++;
377    else if( (this->pixelArray.getZ(i) - this->pixelArray.getZ(i-1)) >= 2)
378      numChannels = 1;
379
380    if( numChannels >= minNumber) result = true;
381  }
382  return result;
383 
384}
385//--------------------------------------------------------------------
386
387std::ostream& operator<< ( std::ostream& theStream, Detection& obj)
388{
389  /**
390   *  A convenient way of printing the coordinate values for each
391   *  pixel in the Detection. 
392   *
393   *  NOTE THAT THERE IS CURRENTLY NO FLUX INFORMATION BEING PRINTED!
394   *
395   *  Use as front end to the Object3D::operator<< function.
396   */ 
397
398  theStream << obj.pixelArray << "---\n";
399}
400//--------------------------------------------------------------------
401
Note: See TracBrowser for help on using the repository browser.