source: tags/release-1.1/src/Detection/detection.cc @ 1391

Last change on this file since 1391 was 308, checked in by Matthew Whiting, 17 years ago

Updated the verification files again, plus detection.cc, trying to make sitar and delphinus agree on integrated fluxes (still can't).
Also commented out some un-necessary comments.

File size: 15.5 KB
Line 
1// -----------------------------------------------------------------------
2// detection.cc : Member functions for the Detection class.
3// -----------------------------------------------------------------------
4// Copyright (C) 2006, Matthew Whiting, ATNF
5//
6// This program is free software; you can redistribute it and/or modify it
7// under the terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 2 of the License, or (at your
9// option) any later version.
10//
11// Duchamp is distributed in the hope that it will be useful, but WITHOUT
12// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14// for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with Duchamp; if not, write to the Free Software Foundation,
18// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
19//
20// Correspondence concerning Duchamp may be directed to:
21//    Internet email: Matthew.Whiting [at] atnf.csiro.au
22//    Postal address: Dr. Matthew Whiting
23//                    Australia Telescope National Facility, CSIRO
24//                    PO Box 76
25//                    Epping NSW 1710
26//                    AUSTRALIA
27// -----------------------------------------------------------------------
28#include <iostream>
29#include <iomanip>
30#include <vector>
31#include <string>
32#include <wcs.h>
33#include <math.h>
34#include <duchamp.hh>
35#include <param.hh>
36#include <fitsHeader.hh>
37#include <Utils/utils.hh>
38#include <PixelMap/Voxel.hh>
39#include <PixelMap/Object3D.hh>
40#include <Detection/detection.hh>
41
42using std::setw;
43using std::setprecision;
44using std::endl;
45using std::vector;
46
47using namespace PixelInfo;
48
49Detection::Detection(const Detection& d)
50{
51  this->pixelArray   = d.pixelArray;
52  this->xSubOffset   = d.xSubOffset;
53  this->ySubOffset   = d.ySubOffset;
54  this->zSubOffset   = d.zSubOffset;
55  this->totalFlux    = d.totalFlux;
56  this->intFlux      = d.intFlux;
57  this->peakFlux     = d.peakFlux;
58  this->xpeak        = d.xpeak;
59  this->ypeak        = d.ypeak;
60  this->zpeak        = d.zpeak;
61  this->peakSNR      = d.peakSNR;
62  this->xCentroid    = d.xCentroid;
63  this->yCentroid    = d.yCentroid;
64  this->zCentroid    = d.zCentroid;
65  this->centreType   = d.centreType;
66  this->negSource    = d.negSource;
67  this->flagText     = d.flagText;
68  this->id           = d.id;
69  this->name         = d.name;
70  this->flagWCS      = d.flagWCS;
71  this->numAxes      = d.numAxes;
72  this->raS          = d.raS;
73  this->decS         = d.decS;
74  this->ra           = d.ra;
75  this->dec          = d.dec;
76  this->raWidth      = d.raWidth;
77  this->decWidth     = d.decWidth;
78  this->specUnits    = d.specUnits;
79  this->fluxUnits    = d.fluxUnits;
80  this->intFluxUnits = d.intFluxUnits;
81  this->lngtype      = d.lngtype;
82  this->lattype      = d.lattype;
83  this->vel          = d.vel;
84  this->velWidth     = d.velWidth;
85  this->velMin       = d.velMin;
86  this->velMax       = d.velMax;
87  this->posPrec      = d.posPrec;
88  this->xyzPrec      = d.xyzPrec;
89  this->fintPrec     = d.fintPrec;
90  this->fpeakPrec    = d.fpeakPrec;
91  this->velPrec      = d.velPrec;
92  this->snrPrec      = d.snrPrec;
93}
94
95//--------------------------------------------------------------------
96
97Detection& Detection::operator= (const Detection& d)
98{
99  if(this == &d) return *this;
100  this->pixelArray   = d.pixelArray;
101  this->xSubOffset   = d.xSubOffset;
102  this->ySubOffset   = d.ySubOffset;
103  this->zSubOffset   = d.zSubOffset;
104  this->totalFlux    = d.totalFlux;
105  this->intFlux      = d.intFlux;
106  this->peakFlux     = d.peakFlux;
107  this->xpeak        = d.xpeak;
108  this->ypeak        = d.ypeak;
109  this->zpeak        = d.zpeak;
110  this->peakSNR      = d.peakSNR;
111  this->xCentroid    = d.xCentroid;
112  this->yCentroid    = d.yCentroid;
113  this->zCentroid    = d.zCentroid;
114  this->centreType   = d.centreType;
115  this->negSource    = d.negSource;
116  this->flagText     = d.flagText;
117  this->id           = d.id;
118  this->name         = d.name;
119  this->flagWCS      = d.flagWCS;
120  this->numAxes      = d.numAxes;
121  this->raS          = d.raS;
122  this->decS         = d.decS;
123  this->ra           = d.ra;
124  this->dec          = d.dec;
125  this->raWidth      = d.raWidth;
126  this->decWidth     = d.decWidth;
127  this->specUnits    = d.specUnits;
128  this->fluxUnits    = d.fluxUnits;
129  this->intFluxUnits = d.intFluxUnits;
130  this->lngtype      = d.lngtype;
131  this->lattype      = d.lattype;
132  this->vel          = d.vel;
133  this->velWidth     = d.velWidth;
134  this->velMin       = d.velMin;
135  this->velMax       = d.velMax;
136  this->posPrec      = d.posPrec;
137  this->xyzPrec      = d.xyzPrec;
138  this->fintPrec     = d.fintPrec;
139  this->fpeakPrec    = d.fpeakPrec;
140  this->velPrec      = d.velPrec;
141  this->snrPrec      = d.snrPrec;
142  return *this;
143}
144
145//--------------------------------------------------------------------
146
147void Detection::calcFluxes(float *fluxArray, long *dim)
148{
149  /**
150   *  A function that calculates total & peak fluxes (and the location
151   *  of the peak flux) for a Detection.
152   *
153   *  \param fluxArray The array of flux values to calculate the
154   *  flux parameters from.
155   *  \param dim The dimensions of the flux array.
156   */
157
158  this->totalFlux = this->peakFlux = 0;
159  this->xCentroid = this->yCentroid = this->zCentroid = 0.;
160  long y,z,count=0;
161
162  for(int m=0; m<this->pixelArray.getNumChanMap(); m++){
163    ChanMap *tempmap = new ChanMap;
164    *tempmap = this->pixelArray.getChanMap(m);
165    z = tempmap->getZ();
166    for(int s=0; s<tempmap->getNumScan(); s++){
167      Scan *tempscan = new Scan;
168      *tempscan = tempmap->getScan(s);
169      y = tempscan->getY();
170      for(long x=tempscan->getX(); x<=tempscan->getXmax(); x++){
171
172        float f = fluxArray[x + y*dim[0] + z*dim[0]*dim[1]];
173        this->totalFlux += f;
174        this->xCentroid += x*f;
175        this->yCentroid += y*f;
176        this->zCentroid += z*f;
177        if( (count==0) ||  //first time round
178            (this->negSource&&(f<this->peakFlux)) ||
179            (!this->negSource&&(f>this->peakFlux))   )
180          {
181            this->peakFlux = f;
182            this->xpeak =    x;
183            this->ypeak =    y;
184            this->zpeak =    z;
185          }
186        count++;
187      }
188      delete tempscan;
189    }
190    delete tempmap;
191  }
192
193  this->xCentroid /= this->totalFlux;
194  this->yCentroid /= this->totalFlux;
195  this->zCentroid /= this->totalFlux;
196}
197//--------------------------------------------------------------------
198
199void Detection::calcWCSparams(float *fluxArray, long *dim, FitsHeader &head)
200{
201  /**
202   *  Use the input wcs to calculate the position and velocity
203   *    information for the Detection.
204   *  Quantities calculated:
205   *  <ul><li> RA: ra [deg], ra (string), ra width.
206   *      <li> Dec: dec [deg], dec (string), dec width.
207   *      <li> Vel: vel [km/s], min & max vel, vel width.
208   *      <li> coord type for all three axes, nuRest,
209   *      <li> name (IAU-style, in equatorial or Galactic)
210   *  </ul>
211   *  Uses Detection::calcIntegFlux() to calculate the
212   *  integrated flux in (say) [Jy km/s]
213   *
214   *  Note that the regular parameters are NOT recalculated!
215   *
216   *  \param fluxArray The array of flux values to calculate the
217   *  integrated flux from.
218   *  \param dim The dimensions of the flux array.
219   *  \param head FitsHeader object that contains the WCS information.
220   */
221
222  if(head.isWCS()){
223
224    double *pixcrd = new double[15];
225    double *world  = new double[15];
226    /*
227      define a five-point array in 3D:
228      (x,y,z), (x,y,z1), (x,y,z2), (x1,y1,z), (x2,y2,z)
229      [note: x = central point, x1 = minimum x, x2 = maximum x etc.]
230      and convert to world coordinates.   
231    */
232    pixcrd[0]  = pixcrd[3] = pixcrd[6] = this->getXcentre();
233    pixcrd[9]  = this->getXmin()-0.5;
234    pixcrd[12] = this->getXmax()+0.5;
235    pixcrd[1]  = pixcrd[4] = pixcrd[7] = this->getYcentre();
236    pixcrd[10] = this->getYmin()-0.5;
237    pixcrd[13] = this->getYmax()+0.5;
238    pixcrd[2] = pixcrd[11] = pixcrd[14] = this->getZcentre();
239    pixcrd[5] = this->getZmin();
240    pixcrd[8] = this->getZmax();
241    int flag = head.pixToWCS(pixcrd, world, 5);
242    delete [] pixcrd;
243    if(flag!=0) duchampError("calcWCSparams",
244                             "Error in calculating the WCS for this object.");
245    else{
246
247      // world now has the WCS coords for the five points
248      //    -- use this to work out WCS params
249 
250      this->numAxes = head.getNumAxes();
251      this->lngtype = head.WCS().lngtyp;
252      this->lattype = head.WCS().lattyp;
253      this->specUnits = head.getSpectralUnits();
254      this->fluxUnits = head.getFluxUnits();
255      // if fluxUnits are eg. Jy/beam, make intFluxUnits = Jy km/s
256      this->intFluxUnits = head.getIntFluxUnits();
257      this->ra   = world[0];
258      this->dec  = world[1];
259      this->raS  = decToDMS(this->ra, this->lngtype);
260      this->decS = decToDMS(this->dec,this->lattype);
261      this->raWidth = angularSeparation(world[9],world[1],
262                                        world[12],world[1]) * 60.;
263      this->decWidth  = angularSeparation(world[0],world[10],
264                                          world[0],world[13]) * 60.;
265      this->name = head.getIAUName(this->ra, this->dec);
266      this->vel    = head.specToVel(world[2]);
267      this->velMin = head.specToVel(world[5]);
268      this->velMax = head.specToVel(world[8]);
269      this->velWidth = fabs(this->velMax - this->velMin);
270
271      this->calcIntegFlux(fluxArray,dim,head);
272   
273      this->flagWCS = true;
274    }
275    delete [] world;
276
277  }
278}
279//--------------------------------------------------------------------
280
281void Detection::calcIntegFlux(float *fluxArray, long *dim, FitsHeader &head)
282{
283  /**
284   *  Uses the input WCS to calculate the velocity-integrated flux,
285   *   putting velocity in units of km/s.
286   *  Integrates over full spatial and velocity range as given
287   *   by the extrema calculated by calcWCSparams.
288   *
289   *  If the flux units end in "/beam" (eg. Jy/beam), then the flux is
290   *  corrected by the beam size (in pixels). This is done by
291   *  multiplying the integrated flux by the number of spatial pixels,
292   *  and dividing by the beam size in pixels (e.g. Jy/beam * pix /
293   *  pix/beam --> Jy)
294   *
295   *  \param fluxArray The array of flux values.
296   *  \param dim The dimensions of the flux array.
297   *  \param head FitsHeader object that contains the WCS information.
298   */
299
300  if(head.getNumAxes() > 2) {
301
302    // include one pixel either side in each direction
303    long xsize = (this->getXmax()-this->getXmin()+3);
304    long ysize = (this->getYmax()-this->getYmin()+3);
305    long zsize = (this->getZmax()-this->getZmin()+3);
306    vector <bool> isObj(xsize*ysize*zsize,false);
307    double *localFlux = new double[xsize*ysize*zsize];
308    for(int i=0;i<xsize*ysize*zsize;i++) localFlux[i]=0.;
309    // work out which pixels are object pixels
310    for(int m=0; m<this->pixelArray.getNumChanMap(); m++){
311      ChanMap tempmap = this->pixelArray.getChanMap(m);
312      long z = this->pixelArray.getChanMap(m).getZ();
313      for(int s=0; s<this->pixelArray.getChanMap(m).getNumScan(); s++){
314        long y = this->pixelArray.getChanMap(m).getScan(s).getY();
315        for(long x=this->pixelArray.getChanMap(m).getScan(s).getX();
316            x<=this->pixelArray.getChanMap(m).getScan(s).getXmax();
317            x++){
318          long pos = (x-this->getXmin()+1) + (y-this->getYmin()+1)*xsize
319            + (z-this->getZmin()+1)*xsize*ysize;
320          localFlux[pos] = fluxArray[x + y*dim[0] + z*dim[0]*dim[1]];
321          isObj[pos] = true;
322        }
323      }
324    }
325 
326    // work out the WCS coords for each pixel
327    double *world  = new double[xsize*ysize*zsize];
328    double xpt,ypt,zpt;
329    for(int i=0;i<xsize*ysize*zsize;i++){
330      xpt = double( this->getXmin() -1 + i%xsize );
331      ypt = double( this->getYmin() -1 + (i/xsize)%ysize );
332      zpt = double( this->getZmin() -1 + i/(xsize*ysize) );
333      world[i] = head.pixToVel(xpt,ypt,zpt);
334    }
335
336    double integrated = 0.;
337    for(int pix=0; pix<xsize*ysize; pix++){ // loop over each spatial pixel.
338      for(int z=0; z<zsize; z++){
339        int pos =  z*xsize*ysize + pix;
340        if(isObj[pos]){ // if it's an object pixel...
341          double deltaVel;
342          if(z==0)
343            deltaVel = (world[pos+xsize*ysize] - world[pos]);
344          else if(z==(zsize-1))
345            deltaVel = (world[pos] - world[pos-xsize*ysize]);
346          else
347            deltaVel = (world[pos+xsize*ysize] - world[pos-xsize*ysize]) / 2.;
348          integrated += localFlux[pos] * absval(deltaVel);
349        }
350      }
351    }
352    this->intFlux = integrated;
353
354    delete [] world;
355    delete [] localFlux;
356
357  }
358  else // in this case there is just a 2D image.
359    this->intFlux = this->totalFlux;
360
361  if(head.isWCS()){
362    // correct for the beam size if the flux units string ends in "/beam"
363    int size = this->fluxUnits.size();
364    std::string tailOfFluxUnits = this->fluxUnits.substr(size-5,size);
365    if(tailOfFluxUnits == "/beam")
366      this->intFlux  *= this->getSpatialSize()/head.getBeamSize();
367  }
368
369}
370//--------------------------------------------------------------------
371
372Detection operator+ (Detection lhs, Detection rhs)
373{
374  /**
375   *  Combines two objects by adding all the pixels using the Object3D
376   *  operator.
377   *
378   *  The pixel parameters are recalculated in the process (equivalent
379   *  to calling pixels().calcParams()), but WCS parameters
380   *  are not.
381   */
382  Detection output;
383  output.pixelArray = lhs.pixelArray + rhs.pixelArray;
384//   output.totalFlux  = lhs.totalFlux  + rhs.totalFlux;
385//   if(lhs.peakFlux > rhs.peakFlux){
386//     output.peakFlux = lhs.peakFlux;
387//     output.xpeak    = lhs.xpeak;
388//     output.ypeak    = lhs.ypeak;
389//     output.zpeak    = lhs.zpeak;
390//     output.peakSNR  = lhs.peakSNR;
391//   }
392//   else{
393//     output.peakFlux = rhs.peakFlux;
394//     output.xpeak    = rhs.xpeak;
395//     output.ypeak    = rhs.ypeak;
396//     output.zpeak    = rhs.zpeak;
397//     output.peakSNR  = rhs.peakSNR;
398//   }
399  return output;
400}
401//--------------------------------------------------------------------
402
403void Detection::setOffsets(Param &par)
404{
405  /**
406   * This function stores the values of the offsets for each cube axis.
407   * The offsets are the starting values of the cube axes that may differ from
408   *  the default value of 0 (for instance, if a subsection is being used).
409   * The values will be used when the detection is outputted.
410   */
411  this->xSubOffset = par.getXOffset();
412  this->ySubOffset = par.getYOffset();
413  this->zSubOffset = par.getZOffset();
414}
415//--------------------------------------------------------------------
416
417bool Detection::hasEnoughChannels(int minNumber)
418{
419  /**
420   * A function to determine if the Detection has enough
421   * contiguous channels to meet the minimum requirement
422   * given as the argument.
423   * \param minNumber How many channels is the minimum acceptable number?
424   * \return True if there is at least one occurence of minNumber consecutive
425   * channels present to return true. False otherwise.
426   */
427
428// Preferred method -- need a set of minNumber consecutive channels present.
429  this->pixelArray.order();
430  int numChannels = 0;
431  bool result = false;
432  int size = this->pixelArray.getNumChanMap();
433  if(size>0) numChannels++;
434  if( numChannels >= minNumber) result = true;
435  for(int i=1;(i<size && !result);i++) {
436    if( (this->pixelArray.getZ(i) - this->pixelArray.getZ(i-1)) == 1)
437      numChannels++;
438    else if( (this->pixelArray.getZ(i) - this->pixelArray.getZ(i-1)) >= 2)
439      numChannels = 1;
440
441    if( numChannels >= minNumber) result = true;
442  }
443  return result;
444 
445}
446//--------------------------------------------------------------------
447
448std::ostream& operator<< ( std::ostream& theStream, Detection& obj)
449{
450  /**
451   *  A convenient way of printing the coordinate values for each
452   *  pixel in the Detection. 
453   *
454   *  NOTE THAT THERE IS CURRENTLY NO FLUX INFORMATION BEING PRINTED!
455   *
456   *  Use as front end to the Object3D::operator<< function.
457   */ 
458
459  theStream << obj.pixelArray << "---\n";
460  return theStream;
461}
462//--------------------------------------------------------------------
463
Note: See TracBrowser for help on using the repository browser.