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
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 <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
19   * A convenient way of printing the coordinate
20   *  and flux values of a voxel.
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}
30//--------------------------------------------------------------------
31
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
130void Detection::calcParams()
131{
132  /**
133   * Detection::calcParams()
134   *  A function that calculates centroid positions,
135   *   minima & maxima of coordinates,
136   *   and total & peak fluxes for a detection.
137   */
138
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;
150  if(this->pix.size()>0){
151    this->peakFlux = this->pix[0].itsF;
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;
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;
169      if(this->negativeSource){
170        // if negative feature, peakFlux is most negative flux
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;
176        }
177      }
178      else{
179        // otherwise, it's a regular detection,
180        //   and peakFlux is most positive flux
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;
186        }
187      }
188    }
189    this->xcentre /= this->pix.size();
190    this->ycentre /= this->pix.size();
191    this->zcentre /= this->pix.size();
192  }
193}
194//--------------------------------------------------------------------
195
196void Detection::calcWCSparams(FitsHeader &head)
197{
198  /**
199   * Detection::calcWCSparams(FitsHeader &)
200   *  Use the input wcs to calculate the position and velocity
201   *    information for the Detection.
202   *  Quantities calculated:
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.
206   *     Other: coord type for all three axes, nuRest,
207   *            name (IAU-style, in equatorial or Galactic)
208   *     Uses getIntegFlux to calculate the integrated flux in (say) [Jy km/s]
209   */
210
211  if(head.isWCS()){
212
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:
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.]
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;
234
235    // world now has the WCS coords for the five points
236    //    -- use this to work out WCS params
237 
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);
248    this->raWidth = angularSeparation(world[9],world[1],world[12],world[1])*60.;
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);
255
256    this->getIntegFlux(head);
257   
258    this->flagWCS = true;
259
260    delete [] world;
261
262  }
263}
264//--------------------------------------------------------------------
265
266float Detection::getIntegFlux(FitsHeader &head)
267{
268  /**
269   * Detection::getIntegFlux(FitsHeader)
270   *  Uses the input wcs to calculate the velocity-integrated flux,
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).
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.);
284  // work out which pixels are object pixels
285  for(int p=0;p<this->pix.size();p++){
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;
289    fluxArray[pos] = this->pix[p].getF();
290    isObj[pos] = true;
291  }
292 
293  // work out the WCS coords for each pixel
294  double *world  = new double[xsize*ysize*zsize];
295  double x,y,z;
296  for(int i=0;i<xsize*ysize*zsize;i++){
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);
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...
308        float deltaVel;
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.;
315        this->intFlux += fluxArray[pos] * fabs(deltaVel);
316      }
317    }
318  }
319
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();
324
325  delete [] world;
326}
327//--------------------------------------------------------------------
328
329void Detection::addAnObject(Detection &toAdd)
330{
331  /**
332   * Detection::addAnObject(Detection &)
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.
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
341   */
342
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      }
385    }
386    size = this->pix.size();
387    this->xcentre /= size;
388    this->ycentre /= size;
389    this->zcentre /= size;
390
391  }
392}
393//--------------------------------------------------------------------
394
395void Detection::addOffsets(Param &par)
396{
397  this->xSubOffset = par.getXOffset();
398  this->ySubOffset = par.getYOffset();
399  this->zSubOffset = par.getZOffset();
400}
401//--------------------------------------------------------------------
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
434    if( numChannels >= minNumber) result = true;
435  }
436  return result;
437 
438}
439//--------------------------------------------------------------------
440
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}
467//--------------------------------------------------------------------
468
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
475   *   --> use as front end to the << operator for Voxels.
476   */ 
477
478  for(int i=0;i<obj.pix.size();i++) theStream << obj.pix[i] << endl;
479  theStream<<"---"<<endl;
480}
481//--------------------------------------------------------------------
482
483Detection combineObjects(Detection &first, Detection &second)
484{
485  // make the new object
486  Detection *newObject = new Detection;
487  for(int ctr=0;ctr<first.getSize();ctr++){
488    newObject->addPixel(first.getPixel(ctr));
489  }
490  for(int ctr=0;ctr<second.getSize();ctr++){
491    newObject->addPixel(second.getPixel(ctr));
492  }
493  newObject->calcParams();
494  return *newObject;
495}
496//--------------------------------------------------------------------
497
498vector <Detection> combineLists(vector <Detection> &first,
499                                vector <Detection> &second)
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.