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

Last change on this file since 218 was 218, checked in by Matthew Whiting, 18 years ago
  • New program, Rrose, to re-plot the spectra with a different method (eg. sum rather than peak), in response to ticket [2]. Still needs some tweaking (better command-line options for instance?), but works fine.
  • Added copy constructors to detection.hh
  • Fixed sort in cubes.cc.
File size: 15.2 KB
RevLine 
[3]1#include <iostream>
2#include <iomanip>
3#include <vector>
4#include <string>
5#include <wcs.h>
[69]6#include <math.h>
[3]7#include <param.hh>
[69]8#include <Utils/utils.hh>
[3]9#include <Detection/detection.hh>
10
11using std::setw;
12using std::setprecision;
13using std::endl;
14
15std::ostream& operator<< ( std::ostream& theStream, Voxel& vox)
16{
17  /**
18   * << operator for Voxel class
[140]19   * A convenient way of printing the coordinate
20   *  and flux values of a voxel.
[3]21   */ 
22
23  theStream << setw(4) << vox.itsX ;
24  theStream << " " << setw(4) << vox.itsY;
25  theStream << " " << setw(4) << vox.itsZ;
26  theStream << setprecision(4);
27  theStream << "  " << vox.itsF;
28
29}
[191]30//--------------------------------------------------------------------
[3]31
[218]32Detection::Detection(const Detection& d)
33{
34  pix             = d.pix;
35  xcentre         = d.xcentre;
36  ycentre         = d.ycentre;
37  zcentre         = d.zcentre;
38  xmin,xmax       = d.xmin,xmax;
39  ymin,ymax       = d.ymin,ymax;
40  zmin,zmax       = d.zmin,zmax;
41  xSubOffset      = d.xSubOffset;
42  ySubOffset      = d.ySubOffset;
43  zSubOffset      = d.zSubOffset;
44  totalFlux       = d.totalFlux;
45  intFlux         = d.intFlux;
46  peakFlux        = d.peakFlux;
47  xpeak           = d.xpeak;
48  ypeak           = d.ypeak;
49  zpeak           = d.zpeak;
50  peakSNR         = d.peakSNR;
51  negativeSource  = d.negativeSource;
52  flagText        = d.flagText;
53  id              = d.id;
54  name            = d.name;
55  flagWCS         = d.flagWCS;
56  raS             = d.raS;
57  decS            = d.decS;
58  ra              = d.ra;
59  dec             = d.dec;
60  raWidth         = d.raWidth;
61  decWidth        = d.decWidth;
62  specUnits       = d.specUnits;
63  fluxUnits       = d.fluxUnits;
64  intFluxUnits    = d.intFluxUnits;
65  lngtype         = d.lngtype;
66  lattype         = d.lattype;
67  vel             = d.vel;
68  velWidth        = d.velWidth;
69  velMin          = d.velMin;
70  velMax          = d.velMax;
71  posPrec         = d.posPrec;
72  xyzPrec         = d.xyzPrec;
73  fintPrec        = d.fintPrec;
74  fpeakPrec       = d.fpeakPrec;
75  velPrec         = d.velPrec;
76  snrPrec         = d.snrPrec;
77}
78
79//--------------------------------------------------------------------
80
81  Detection& Detection::operator= (const Detection& d)
82{
83  pix             = d.pix;
84  xcentre         = d.xcentre;
85  ycentre         = d.ycentre;
86  zcentre         = d.zcentre;
87  xmin,xmax       = d.xmin,xmax;
88  ymin,ymax       = d.ymin,ymax;
89  zmin,zmax       = d.zmin,zmax;
90  xSubOffset      = d.xSubOffset;
91  ySubOffset      = d.ySubOffset;
92  zSubOffset      = d.zSubOffset;
93  totalFlux       = d.totalFlux;
94  intFlux         = d.intFlux;
95  peakFlux        = d.peakFlux;
96  xpeak           = d.xpeak;
97  ypeak           = d.ypeak;
98  zpeak           = d.zpeak;
99  peakSNR         = d.peakSNR;
100  negativeSource  = d.negativeSource;
101  flagText        = d.flagText;
102  id              = d.id;
103  name            = d.name;
104  flagWCS         = d.flagWCS;
105  raS             = d.raS;
106  decS            = d.decS;
107  ra              = d.ra;
108  dec             = d.dec;
109  raWidth         = d.raWidth;
110  decWidth        = d.decWidth;
111  specUnits       = d.specUnits;
112  fluxUnits       = d.fluxUnits;
113  intFluxUnits    = d.intFluxUnits;
114  lngtype         = d.lngtype;
115  lattype         = d.lattype;
116  vel             = d.vel;
117  velWidth        = d.velWidth;
118  velMin          = d.velMin;
119  velMax          = d.velMax;
120  posPrec         = d.posPrec;
121  xyzPrec         = d.xyzPrec;
122  fintPrec        = d.fintPrec;
123  fpeakPrec       = d.fpeakPrec;
124  velPrec         = d.velPrec;
125  snrPrec         = d.snrPrec;
126}
127
128//--------------------------------------------------------------------
129
[3]130void Detection::calcParams()
131{
132  /**
133   * Detection::calcParams()
[140]134   *  A function that calculates centroid positions,
135   *   minima & maxima of coordinates,
[3]136   *   and total & peak fluxes for a detection.
137   */
138
[187]139  this->xcentre = 0;
140  this->ycentre = 0;
141  this->zcentre = 0;
142  this->totalFlux = 0;
143  this->peakFlux = 0;
144  this->xmin = 0;
145  this->xmax = 0;
146  this->ymin = 0;
147  this->ymax = 0;
148  this->zmin = 0;
149  this->zmax = 0;
[62]150  if(this->pix.size()>0){
151    this->peakFlux = this->pix[0].itsF;
[82]152    for(int ctr=0;ctr<this->pix.size();ctr++){
153      this->xcentre   += this->pix[ctr].itsX;
154      this->ycentre   += this->pix[ctr].itsY;
155      this->zcentre   += this->pix[ctr].itsZ;
156      this->totalFlux += this->pix[ctr].itsF;
[140]157      if((ctr==0)||(this->pix[ctr].itsX<this->xmin))
158        this->xmin = this->pix[ctr].itsX;
159      if((ctr==0)||(this->pix[ctr].itsX>this->xmax))
160        this->xmax = this->pix[ctr].itsX;
161      if((ctr==0)||(this->pix[ctr].itsY<this->ymin))
162        this->ymin = this->pix[ctr].itsY;
163      if((ctr==0)||(this->pix[ctr].itsY>this->ymax))
164        this->ymax = this->pix[ctr].itsY;
165      if((ctr==0)||(this->pix[ctr].itsZ<this->zmin))
166        this->zmin = this->pix[ctr].itsZ;
167      if((ctr==0)||(this->pix[ctr].itsZ>this->zmax))
168        this->zmax = this->pix[ctr].itsZ;
[62]169      if(this->negativeSource){
170        // if negative feature, peakFlux is most negative flux
[82]171        if((ctr==0)||(this->pix[ctr].itsF < this->peakFlux)){
172          this->peakFlux = this->pix[ctr].itsF;
173          this->xpeak = this->pix[ctr].itsX;
174          this->ypeak = this->pix[ctr].itsY;
175          this->zpeak = this->pix[ctr].itsZ;
[62]176        }
177      }
178      else{
[140]179        // otherwise, it's a regular detection,
180        //   and peakFlux is most positive flux
[82]181        if((ctr==0)||(this->pix[ctr].itsF > this->peakFlux)){
182          this->peakFlux = this->pix[ctr].itsF;
183          this->xpeak = this->pix[ctr].itsX;
184          this->ypeak = this->pix[ctr].itsY;
185          this->zpeak = this->pix[ctr].itsZ;
[62]186        }
187      }
[45]188    }
[62]189    this->xcentre /= this->pix.size();
190    this->ycentre /= this->pix.size();
191    this->zcentre /= this->pix.size();
[3]192  }
193}
[191]194//--------------------------------------------------------------------
[3]195
[129]196void Detection::calcWCSparams(FitsHeader &head)
[3]197{
198  /**
[140]199   * Detection::calcWCSparams(FitsHeader &)
200   *  Use the input wcs to calculate the position and velocity
201   *    information for the Detection.
[3]202   *  Quantities calculated:
[22]203   *     RA: ra [deg], ra (string), ra width.
204   *     Dec: dec [deg], dec (string), dec width.
205   *     Vel: vel [km/s], min & max vel, vel width.
[129]206   *     Other: coord type for all three axes, nuRest,
207   *            name (IAU-style, in equatorial or Galactic)
[22]208   *     Uses getIntegFlux to calculate the integrated flux in (say) [Jy km/s]
[3]209   */
210
[103]211  if(head.isWCS()){
[60]212
[103]213    this->calcParams(); // make sure this is up to date.
214
215    double *pixcrd = new double[15];
216    double *world  = new double[15];
217    /*
218      define a five-point array in 3D:
[86]219      (x,y,z), (x,y,z1), (x,y,z2), (x1,y1,z), (x2,y2,z)
220      [note: x = central point, x1 = minimum x, x2 = maximum x etc.]
[103]221      and convert to world coordinates.   
222    */
223    pixcrd[0]  = pixcrd[3] = pixcrd[6] = this->xcentre;
224    pixcrd[9]  = this->xmin-0.5;
225    pixcrd[12] = this->xmax+0.5;
226    pixcrd[1]  = pixcrd[4] = pixcrd[7] = this->ycentre;
227    pixcrd[10] = this->ymin-0.5;
228    pixcrd[13] = this->ymax+0.5;
229    pixcrd[2] = pixcrd[11] = pixcrd[14] = this->zcentre;
230    pixcrd[5] = this->zmin;
231    pixcrd[8] = this->zmax;
232    int flag = head.pixToWCS(pixcrd, world, 5);
233    delete [] pixcrd;
[3]234
[140]235    // world now has the WCS coords for the five points
236    //    -- use this to work out WCS params
[22]237 
[103]238    this->lngtype = head.getWCS()->lngtyp;
239    this->lattype = head.getWCS()->lattyp;
240    this->specUnits = head.getSpectralUnits();
241    this->fluxUnits = head.getFluxUnits();
242    // if fluxUnits are eg. Jy/beam, make intFluxUnits = Jy km/s
243    this->intFluxUnits = head.getIntFluxUnits();
244    this->ra   = world[0];
245    this->dec  = world[1];
246    this->raS  = decToDMS(this->ra, this->lngtype);
247    this->decS = decToDMS(this->dec,this->lattype);
[205]248    this->raWidth = angularSeparation(world[9],world[1],world[12],world[1])*60.;
[103]249    this->decWidth  = angularSeparation(world[0],world[10],world[0],world[13]) * 60.;
250    this->name = head.getIAUName(this->ra, this->dec);
251    this->vel    = head.specToVel(world[2]);
252    this->velMin = head.specToVel(world[5]);
253    this->velMax = head.specToVel(world[8]);
254    this->velWidth = fabs(this->velMax - this->velMin);
[3]255
[103]256    this->getIntegFlux(head);
[129]257   
[103]258    this->flagWCS = true;
[3]259
[103]260    delete [] world;
[3]261
[103]262  }
[3]263}
[191]264//--------------------------------------------------------------------
[3]265
[129]266float Detection::getIntegFlux(FitsHeader &head)
[3]267{
268  /**
[103]269   * Detection::getIntegFlux(FitsHeader)
[3]270   *  Uses the input wcs to calculate the velocity-integrated flux,
[140]271   *   putting velocity in units of km/s.
272   *  Integrates over full spatial and velocity range as given
273   *   by the extrema calculated by calcWCSparams.
274   *  If the flux units end in "/beam" (eg. Jy/beam), then the
275   *   flux is corrected by the beam size (in pixels).
[3]276   */
277
278  // include one pixel either side in each direction
279  int xsize = (this->xmax-this->xmin+3);
280  int ysize = (this->ymax-this->ymin+3);
281  int zsize = (this->zmax-this->zmin+3);
282  vector <bool> isObj(xsize*ysize*zsize,false);
283  vector <float> fluxArray(xsize*ysize*zsize,0.);
[22]284  // work out which pixels are object pixels
[3]285  for(int p=0;p<this->pix.size();p++){
[139]286    int pos = (this->pix[p].getX()-this->xmin+1)
287      + (this->pix[p].getY()-this->ymin+1)*xsize
288      + (this->pix[p].getZ()-this->zmin+1)*xsize*ysize;
[3]289    fluxArray[pos] = this->pix[p].getF();
290    isObj[pos] = true;
291  }
[22]292 
293  // work out the WCS coords for each pixel
[103]294  double *world  = new double[xsize*ysize*zsize];
295  double x,y,z;
[3]296  for(int i=0;i<xsize*ysize*zsize;i++){
[103]297    x = double( this->xmin -1 + i%xsize );
298    y = double( this->ymin -1 + (i/xsize)%ysize );
299    z = double( this->zmin -1 + i/(xsize*ysize) );
300    world[i] = head.pixToVel(x,y,z);
[3]301  }
302
303  this->intFlux = 0.;
304  for(int pix=0; pix<xsize*ysize; pix++){ // loop over each spatial pixel.
305    for(int z=0; z<zsize; z++){
306      int pos =  z*xsize*ysize + pix;
307      if(isObj[pos]){ // if it's an object pixel...
[103]308        float deltaVel;
[139]309        if(z==0)
310          deltaVel = (world[pos+xsize*ysize] - world[pos]);
311        else if(z==(zsize-1))
312          deltaVel = (world[pos] - world[pos-xsize*ysize]);
313        else
314          deltaVel = (world[pos+xsize*ysize] - world[pos-xsize*ysize]) / 2.;
[125]315        this->intFlux += fluxArray[pos] * fabs(deltaVel);
[3]316      }
317    }
318  }
[103]319
[140]320  // correct for the beam size if the flux units string ends in "/beam"
321  int size = this->fluxUnits.size();
322  string tailOfFluxUnits = this->fluxUnits.substr(size-5,size);
323  if(tailOfFluxUnits == "/beam") this->intFlux /= head.getBeamSize();
[103]324
[3]325  delete [] world;
326}
[191]327//--------------------------------------------------------------------
[3]328
[82]329void Detection::addAnObject(Detection &toAdd)
330{
[3]331  /**
332   * Detection::addAnObject(Detection &)
[139]333   *  Combines two objects by adding all the pixels of the argument
334   *   to the instigator.
335   *  All pixel & flux parameters are recalculated (so that
336   *   calcParams does not need to be called a second time),
337   *   but WCS parameters are not.
[187]338   *  If the instigator is empty (pix.size()==0) then we just make it
339   *   equal to the argument, and call calcParams to initialise the
340   *   necessary parameters
[3]341   */
[139]342
[187]343  int size = this->pix.size();
344  if(size==0){
345    *this = toAdd;
346    this->calcParams();
347  }
348  else if(size>0){
349
350    this->xcentre *= size;
351    this->ycentre *= size;
352    this->zcentre *= size;
353 
354    for(int ctr=0;ctr<toAdd.getSize();ctr++){
355      long x  = toAdd.getX(ctr);
356      long y  = toAdd.getY(ctr);
357      long z  = toAdd.getZ(ctr);
358      float f = toAdd.getF(ctr);
359      bool isNewPix = true;
360      int ctr2 = 0;
361      // For each pixel in the new object, test to see if it already
362      //  appears in the object
363      while( isNewPix && (ctr2<this->pix.size()) ){
364        isNewPix = isNewPix && (( this->pix[ctr2].itsX != x ) ||
365                                ( this->pix[ctr2].itsY != y ) ||
366                                ( this->pix[ctr2].itsZ != z ) );
367        ctr2++;
368      }
369      if(isNewPix){
370        // If the pixel is new, add it to the object and
371        //   re-calculate the parameters.
372        this->pix.push_back(toAdd.getPixel(ctr));
373        this->xcentre += x;
374        this->ycentre += y;
375        this->zcentre += z;
376        this->totalFlux += f;
377        if     (x < this->xmin) this->xmin = x;
378        else if(x > this->xmax) this->xmax = x;
379        if     (y < this->ymin) this->ymin = y;
380        else if(y > this->ymax) this->ymax = y;
381        if     (z < this->zmin) this->zmin = z;
382        else if(z > this->zmax) this->zmax = z;
383        if(f > this->peakFlux) this->peakFlux = f;
384      }
[82]385    }
[187]386    size = this->pix.size();
387    this->xcentre /= size;
388    this->ycentre /= size;
389    this->zcentre /= size;
390
[3]391  }
392}
[191]393//--------------------------------------------------------------------
[3]394
395void Detection::addOffsets(Param &par)
396{
397  this->xSubOffset = par.getXOffset();
398  this->ySubOffset = par.getYOffset();
399  this->zSubOffset = par.getZOffset();
400}
[191]401//--------------------------------------------------------------------
[3]402
403bool Detection::hasEnoughChannels(int minNumber)
404{
405  /**
406   *  bool hasEnoughChannels(int)
407   *    A function to determine if the Detection has enough
408   *    contiguous channels to meet the minimum requirement
409   *    given as the argument.
410   *    Needs to have at least one occurence of minNumber consecutive
411   *    channels present to return true. Otherwise returns false.
412   */
413
414  // Original requirement -- based on total span
415// int numChannels = this->getZmax() - this->getZmin() + 1;
416
417// Alternative -- number of distinct channels detected
418//   int numChannels = 0;
419//   this->SortByZ();
420//   if(this->getSize()>0) numChannels++;
421//   for(int i=1;i<this->getSize();i++)
422//     if(this->getZ(i)>this->getZ(i-1)) numChannels++; 
423//   return (numChannels < minNumber);
424
425// Preferred method -- need a set of minNumber consecutive channels present.
426  this->SortByZ();
427  int numChannels = 0;
428  bool result = false;
429  if(this->getSize()>0) numChannels++;
430  for(int i=1;i<this->getSize();i++) {
431    if( (this->getZ(i) - this->getZ(i-1)) == 1) numChannels++;
432    else if( (this->getZ(i) - this->getZ(i-1)) >= 2) numChannels = 1;
433
[120]434    if( numChannels >= minNumber) result = true;
[3]435  }
436  return result;
437 
438}
[191]439//--------------------------------------------------------------------
[3]440
[16]441int Detection::getSpatialSize()
442{
443  /**
444   *  int getSpatialSize()
445   *    A function that returns the number of distinct spatial
446   *     pixels in a Detection.
447   */
448
449  vector<Pixel> spatialPix;
450  Pixel newpix;
451  bool addThisOne;
452  newpix.setXY(this->getX(0),this->getY(0));
453  spatialPix.push_back(newpix);
454  for(int i=1;i<this->pix.size();i++){
455    newpix.setXY(this->getX(i),this->getY(i));
456    addThisOne = true;
457    for(int j=0;(j<spatialPix.size())&&addThisOne;j++) {
458      // do whole list or until addThisOne=false
459      addThisOne = ( (newpix.getX()!=spatialPix[j].getX()) ||
460                     (newpix.getY()!=spatialPix[j].getY())   );
461      // ie. if one of X or Y is different, addThisOne is true.
462    }
463    if(addThisOne) spatialPix.push_back(newpix);
464  }
465  return spatialPix.size();
466}
[191]467//--------------------------------------------------------------------
[16]468
[3]469std::ostream& operator<< ( std::ostream& theStream, Detection& obj)
470{
471  /**
472   * << operator for Detection class
473   *  A convenient way of printing the coordinate & flux
474   *  values for each pixel in the Detection
[86]475   *   --> use as front end to the << operator for Voxels.
[3]476   */ 
477
478  for(int i=0;i<obj.pix.size();i++) theStream << obj.pix[i] << endl;
479  theStream<<"---"<<endl;
480}
[191]481//--------------------------------------------------------------------
[3]482
483Detection combineObjects(Detection &first, Detection &second)
484{
485  // make the new object
486  Detection *newObject = new Detection;
[205]487  for(int ctr=0;ctr<first.getSize();ctr++){
488    newObject->addPixel(first.getPixel(ctr));
[3]489  }
[205]490  for(int ctr=0;ctr<second.getSize();ctr++){
491    newObject->addPixel(second.getPixel(ctr));
[3]492  }
493  newObject->calcParams();
494  return *newObject;
495}
[191]496//--------------------------------------------------------------------
[3]497
[205]498vector <Detection> combineLists(vector <Detection> &first,
499                                vector <Detection> &second)
[3]500{
501  // make the new object
502  vector <Detection> newList(first.size()+second.size());
503  for(int i=0;i<first.size();i++) newList[i] = first[i];
504  for(int i=0;i<second.size();i++) newList[i+first.size()] = second[i];
505 
506  return newList;
507}
508
Note: See TracBrowser for help on using the repository browser.