source: tags/release-1.1.2/src/Detection/detection.cc

Last change on this file was 394, checked in by MatthewWhiting, 17 years ago

Fixing wcslib include calls so that it is a bit more robust.

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