source: branches/pixelmap-refactor-branch/src/Detection/detection.cc @ 1441

Last change on this file since 1441 was 569, checked in by MatthewWhiting, 15 years ago

Improving the updateDetectMap functions and the default values for Detection. Otherwise just cleaning up.

File size: 30.4 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#include <duchamp/Cubes/cubeUtils.hh>
42#include <duchamp/Detection/columns.hh>
43
44using namespace PixelInfo;
45
46namespace duchamp
47{
48
49  void Detection::defaultDetection()
50  {
51    this->xSubOffset = 0;
52    this->ySubOffset = 0;
53    this->zSubOffset = 0;
54    this->totalFlux = 0.;
55    this->peakFlux = 0.;
56    this->intFlux = 0.;
57    this->xpeak = 0;
58    this->ypeak = 0;
59    this->zpeak = 0;
60    this->peakSNR = 0.;
61    this->xCentroid = 0.;
62    this->yCentroid = 0.;
63    this->zCentroid = 0.;
64    this->centreType="centroid";
65    this->negSource = false;
66    this->flagText="";
67    this->id = -1;
68    this->name = "";
69    this->flagWCS=false;
70    this->specOK = true;
71    this->raS = "";
72    this->decS = "";
73    this->ra = 0.;
74    this->dec = 0.;
75    this->raWidth = 0.;
76    this->decWidth = 0.;
77    this->majorAxis = 0.;
78    this->minorAxis = 0.;
79    this->posang = 0.;
80    this->specUnits = "";
81    this->fluxUnits = "";
82    this->intFluxUnits = "";
83    this->lngtype = "RA";
84    this->lattype = "DEC";
85    this->vel = 0.;
86    this->velWidth = 0.;
87    this->velMin = 0.;
88    this->velMax = 0.;
89    this->w20 = 0.;
90    this->v20min = 0.;
91    this->v20max = 0.;
92    this->w50 = 0.;
93    this->v50min = 0.;
94    this->v50max = 0.;
95    this->posPrec = Column::prPOS;
96    this->xyzPrec = Column::prXYZ;
97    this->fintPrec = Column::prFLUX;
98    this->fpeakPrec = Column::prFLUX;
99    this->velPrec = Column::prVEL;
100    this->snrPrec = Column::prSNR;
101  }
102
103  Detection::Detection():
104    Object3D()
105  {
106    this->defaultDetection();
107  }
108
109  Detection::Detection(const Object3D& o):
110    Object3D(o)
111  {
112    this->defaultDetection();
113  }
114
115  Detection::Detection(const Detection& d):
116    Object3D(d)
117  {
118    operator=(d);
119  }
120
121  Detection& Detection::operator= (const Detection& d)
122  {
123    ((Object3D &) *this) = d;
124    this->xSubOffset   = d.xSubOffset;
125    this->ySubOffset   = d.ySubOffset;
126    this->zSubOffset   = d.zSubOffset;
127    this->totalFlux    = d.totalFlux;
128    this->intFlux      = d.intFlux;
129    this->peakFlux     = d.peakFlux;
130    this->xpeak        = d.xpeak;
131    this->ypeak        = d.ypeak;
132    this->zpeak        = d.zpeak;
133    this->peakSNR      = d.peakSNR;
134    this->xCentroid    = d.xCentroid;
135    this->yCentroid    = d.yCentroid;
136    this->zCentroid    = d.zCentroid;
137    this->centreType   = d.centreType;
138    this->negSource    = d.negSource;
139    this->flagText     = d.flagText;
140    this->id           = d.id;
141    this->name         = d.name;
142    this->flagWCS      = d.flagWCS;
143    this->specOK       = d.specOK;
144    this->raS          = d.raS;
145    this->decS         = d.decS;
146    this->ra           = d.ra;
147    this->dec          = d.dec;
148    this->raWidth      = d.raWidth;
149    this->decWidth     = d.decWidth;
150    this->majorAxis    = d.majorAxis;
151    this->minorAxis    = d.minorAxis;
152    this->posang       = d.posang;
153    this->specUnits    = d.specUnits;
154    this->fluxUnits    = d.fluxUnits;
155    this->intFluxUnits = d.intFluxUnits;
156    this->lngtype      = d.lngtype;
157    this->lattype      = d.lattype;
158    this->vel          = d.vel;
159    this->velWidth     = d.velWidth;
160    this->velMin       = d.velMin;
161    this->velMax       = d.velMax;
162    this->w20          = d.w20;
163    this->v20min       = d.v20min;
164    this->v20max       = d.v20max;
165    this->w50          = d.w50;
166    this->v50min       = d.v50min;
167    this->v50max       = d.v50max;
168    this->posPrec      = d.posPrec;
169    this->xyzPrec      = d.xyzPrec;
170    this->fintPrec     = d.fintPrec;
171    this->fpeakPrec    = d.fpeakPrec;
172    this->velPrec      = d.velPrec;
173    this->snrPrec      = d.snrPrec;
174    return *this;
175  }
176
177  //--------------------------------------------------------------------
178  float Detection::getXcentre()
179  {
180    if(this->centreType=="peak") return this->xpeak;
181    else if(this->centreType=="average") return this->getXaverage();
182    else return this->xCentroid;
183  }
184
185  float Detection::getYcentre()
186  {
187    if(this->centreType=="peak") return this->ypeak;
188    else if(this->centreType=="average") return this->getYaverage();
189    else return this->yCentroid;
190  }
191
192  float Detection::getZcentre()
193  {
194    if(this->centreType=="peak") return this->zpeak;
195    else if(this->centreType=="average") return this->getZaverage();
196    else return this->zCentroid;
197  }
198
199  //--------------------------------------------------------------------
200
201  bool Detection::voxelListsMatch(std::vector<Voxel> voxelList)
202  {
203    /// @details
204    ///  A test to see whether there is a 1-1 correspondence between
205    ///  the given list of Voxels and the voxel positions contained in
206    ///  this Detection's pixel list. No testing of the fluxes of the
207    ///  Voxels is done.
208    ///
209    /// \param voxelList The std::vector list of Voxels to be tested.
210
211    bool listsMatch = true;
212    // compare sizes
213    listsMatch = listsMatch && (voxelList.size() == this->getSize());
214    if(!listsMatch) return listsMatch;
215
216    // make sure all Detection pixels are in voxel list
217    listsMatch = listsMatch && this->voxelListCovered(voxelList);
218
219    // make sure all voxels are in Detection
220    for(unsigned int i=0;i<voxelList.size();i++)
221      listsMatch = listsMatch && this->isInObject(voxelList[i]);
222
223    return listsMatch;
224
225  }
226  //--------------------------------------------------------------------
227
228  bool Detection::voxelListCovered(std::vector<Voxel> voxelList)
229  {
230    ///  @details
231    ///  A test to see whether the given list of Voxels contains each
232    ///  position in this Detection's pixel list. It does not look for
233    ///  a 1-1 correspondence: the given list can be a super-set of the
234    ///  Detection. No testing of the fluxes of the Voxels is done.
235    ///
236    /// \param voxelList The std::vector list of Voxels to be tested.
237
238    bool listsMatch = true;
239
240    // make sure all Detection pixels are in voxel list
241    unsigned int v1=0;
242    std::vector<Voxel> detpixlist = this->getPixelSet();
243    while(listsMatch && v1<detpixlist.size()){
244      bool inList = false;
245      unsigned int v2=0;
246      while(!inList && v2<voxelList.size()){
247        inList = inList || detpixlist[v1].match(voxelList[v2]);
248        v2++;
249      }
250      listsMatch = listsMatch && inList;
251      v1++;
252    }
253
254    return listsMatch;
255
256  }
257  //--------------------------------------------------------------------
258
259  void Detection::calcFluxes(std::vector<Voxel> voxelList)
260  {
261    ///  @details
262    ///  A function that calculates total & peak fluxes (and the location
263    ///  of the peak flux) for a Detection.
264    ///
265    ///  \param fluxArray The array of flux values to calculate the
266    ///  flux parameters from.
267    ///  \param dim The dimensions of the flux array.
268
269    this->totalFlux = this->peakFlux = 0;
270    this->xCentroid = this->yCentroid = this->zCentroid = 0.;
271
272    // first check that the voxel list and the Detection's pixel list
273    // have a 1-1 correspondence
274
275    if(!this->voxelListCovered(voxelList)){
276      duchampError("Detection::calcFluxes","Voxel list provided does not match");
277      return;
278    }
279
280    for(unsigned int i=0;i<voxelList.size();i++) {
281      if(this->isInObject(voxelList[i])){
282        long x = voxelList[i].getX();
283        long y = voxelList[i].getY();
284        long z = voxelList[i].getZ();
285        float f = voxelList[i].getF();
286        this->totalFlux += f;
287        this->xCentroid += x*f;
288        this->yCentroid += y*f;
289        this->zCentroid += z*f;
290        if( (i==0) ||  //first time round
291            (this->negSource&&(f<this->peakFlux)) ||
292            (!this->negSource&&(f>this->peakFlux))   )
293          {
294            this->peakFlux = f;
295            this->xpeak =    x;
296            this->ypeak =    y;
297            this->zpeak =    z;
298          }
299      }
300    }
301
302    this->xCentroid /= this->totalFlux;
303    this->yCentroid /= this->totalFlux;
304    this->zCentroid /= this->totalFlux;
305  }
306  //--------------------------------------------------------------------
307
308  void Detection::calcFluxes(float *fluxArray, long *dim)
309  {
310    ///  @details
311    ///  A function that calculates total & peak fluxes (and the location
312    ///  of the peak flux) for a Detection.
313    ///
314    ///  \param fluxArray The array of flux values to calculate the
315    ///  flux parameters from.
316    ///  \param dim The dimensions of the flux array.
317
318    this->totalFlux = this->peakFlux = 0;
319    this->xCentroid = this->yCentroid = this->zCentroid = 0.;
320
321    std::vector<Voxel> voxList = this->getPixelSet();
322    std::vector<Voxel>::iterator vox=voxList.begin();
323    for(;vox<voxList.end();vox++){
324
325      long x=vox->getX();
326      long y=vox->getY();
327      long z=vox->getZ();
328      long ind = vox->arrayIndex(dim);
329      float f = fluxArray[ind];
330      this->totalFlux += f;
331      this->xCentroid += x*f;
332      this->yCentroid += y*f;
333      this->zCentroid += z*f;
334      if( (vox==voxList.begin()) ||
335          (this->negSource&&(f<this->peakFlux)) ||
336          (!this->negSource&&(f>this->peakFlux))   )
337        {
338          this->peakFlux = f;
339          this->xpeak = x;
340          this->ypeak = y;
341          this->zpeak = z;
342        }
343 
344    }
345
346    this->xCentroid /= this->totalFlux;
347    this->yCentroid /= this->totalFlux;
348    this->zCentroid /= this->totalFlux;
349  }
350  //--------------------------------------------------------------------
351
352  void Detection::calcWCSparams(FitsHeader &head)
353  {
354    ///  @details
355    ///  Use the input wcs to calculate the position and velocity
356    ///    information for the Detection.
357    ///  Quantities calculated:
358    ///  <ul><li> RA: ra [deg], ra (string), ra width.
359    ///      <li> Dec: dec [deg], dec (string), dec width.
360    ///      <li> Vel: vel [km/s], min & max vel, vel width.
361    ///      <li> coord type for all three axes, nuRest,
362    ///      <li> name (IAU-style, in equatorial or Galactic)
363    ///  </ul>
364    ///
365    ///  Note that the regular parameters are NOT recalculated!
366    ///
367    ///  \param head FitsHeader object that contains the WCS information.
368
369    if(head.isWCS()){
370
371      double *pixcrd = new double[15];
372      double *world  = new double[15];
373      /*
374        define a five-point array in 3D:
375        (x,y,z), (x,y,z1), (x,y,z2), (x1,y1,z), (x2,y2,z)
376        [note: x = central point, x1 = minimum x, x2 = maximum x etc.]
377        and convert to world coordinates.   
378      */
379      pixcrd[0]  = pixcrd[3] = pixcrd[6] = this->getXcentre();
380      pixcrd[9]  = this->getXmin()-0.5;
381      pixcrd[12] = this->getXmax()+0.5;
382      pixcrd[1]  = pixcrd[4] = pixcrd[7] = this->getYcentre();
383      pixcrd[10] = this->getYmin()-0.5;
384      pixcrd[13] = this->getYmax()+0.5;
385      pixcrd[2] = pixcrd[11] = pixcrd[14] = this->getZcentre();
386      pixcrd[5] = this->getZmin();
387      pixcrd[8] = this->getZmax();
388      int flag = head.pixToWCS(pixcrd, world, 5);
389      delete [] pixcrd;
390      if(flag!=0) duchampError("calcWCSparams",
391                               "Error in calculating the WCS for this object.\n");
392      else{
393
394        // world now has the WCS coords for the five points
395        //    -- use this to work out WCS params
396 
397        this->specOK = head.canUseThirdAxis();
398        this->lngtype = head.WCS().lngtyp;
399        this->lattype = head.WCS().lattyp;
400        this->specUnits = head.getSpectralUnits();
401        this->fluxUnits = head.getFluxUnits();
402        // if fluxUnits are eg. Jy/beam, make intFluxUnits = Jy km/s
403        this->intFluxUnits = head.getIntFluxUnits();
404        this->ra   = world[0];
405        this->dec  = world[1];
406        this->raS  = decToDMS(this->ra, this->lngtype);
407        this->decS = decToDMS(this->dec,this->lattype);
408        this->raWidth = angularSeparation(world[9],world[1],
409                                          world[12],world[1]) * 60.;
410        this->decWidth  = angularSeparation(world[0],world[10],
411                                            world[0],world[13]) * 60.;
412
413        Object2D spatMap = this->getSpatialMap();
414        std::pair<double,double> axes = spatMap.getPrincipleAxes();
415        this->majorAxis = std::max(axes.first,axes.second) * head.getAvPixScale();
416        this->minorAxis = std::min(axes.first,axes.second) * head.getAvPixScale();
417        this->posang = spatMap.getPositionAngle() * 180. / M_PI;
418
419        this->name = head.getIAUName(this->ra, this->dec);
420        this->vel    = head.specToVel(world[2]);
421        this->velMin = head.specToVel(world[5]);
422        this->velMax = head.specToVel(world[8]);
423        this->velWidth = fabs(this->velMax - this->velMin);
424
425        this->flagWCS = true;
426      }
427      delete [] world;
428
429    }
430  }
431  //--------------------------------------------------------------------
432
433  void Detection::calcIntegFlux(std::vector<Voxel> voxelList, FitsHeader &head)
434  {
435    ///  @details
436    ///  Uses the input WCS to calculate the velocity-integrated flux,
437    ///   putting velocity in units of km/s.
438    ///  The fluxes used are taken from the Voxels, rather than an
439    ///   array of flux values.
440    ///  Integrates over full spatial and velocity range as given
441    ///   by the extrema calculated by calcWCSparams.
442    ///
443    ///  If the flux units end in "/beam" (eg. Jy/beam), then the flux is
444    ///  corrected by the beam size (in pixels). This is done by
445    ///  multiplying the integrated flux by the number of spatial pixels,
446    ///  and dividing by the beam size in pixels (e.g. Jy/beam * pix /
447    ///  pix/beam --> Jy)
448    ///
449    ///  \param voxelList The list of Voxels with flux information
450    ///  \param head FitsHeader object that contains the WCS information.
451
452    const int border = 1;
453
454    if(!this->voxelListCovered(voxelList)){
455      duchampError("Detection::calcIntegFlux","Voxel list provided does not match");
456      return;
457    }
458
459    if(!head.is2D()){
460
461      // include one pixel either side in each direction
462      long xsize = (this->getXmax()-this->getXmin()+border*2+1);
463      long ysize = (this->getYmax()-this->getYmin()+border*2+1);
464      long zsize = (this->getZmax()-this->getZmin()+border*2+1);
465      long size = xsize*ysize*zsize;
466      std::vector <bool> isObj(size,false);
467      double *localFlux = new double[size];
468      for(int i=0;i<size;i++) localFlux[i]=0.;
469
470      for(unsigned int i=0;i<voxelList.size();i++){
471        if(this->isInObject(voxelList[i])){
472          long x = voxelList[i].getX();
473          long y = voxelList[i].getY();
474          long z = voxelList[i].getZ();
475          long pos = (x-this->getXmin()+border) + (y-this->getYmin()+border)*xsize
476            + (z-this->getZmin()+border)*xsize*ysize;
477          localFlux[pos] = voxelList[i].getF();
478          isObj[pos] = true;
479        }
480      }
481 
482      // work out the WCS coords for each pixel
483      double *world  = new double[size];
484      double xpt,ypt,zpt;
485      for(int i=0;i<xsize*ysize*zsize;i++){
486        xpt = double( this->getXmin() - border + i%xsize );
487        ypt = double( this->getYmin() - border + (i/xsize)%ysize );
488        zpt = double( this->getZmin() - border + i/(xsize*ysize) );
489        world[i] = head.pixToVel(xpt,ypt,zpt);
490      }
491
492      double integrated = 0.;
493      for(int pix=0; pix<xsize*ysize; pix++){ // loop over each spatial pixel.
494        for(int z=0; z<zsize; z++){
495          int pos =  z*xsize*ysize + pix;
496          if(isObj[pos]){ // if it's an object pixel...
497            double deltaVel;
498            if(z==0)
499              deltaVel = (world[pos+xsize*ysize] - world[pos]);
500            else if(z==(zsize-1))
501              deltaVel = (world[pos] - world[pos-xsize*ysize]);
502            else
503              deltaVel = (world[pos+xsize*ysize] - world[pos-xsize*ysize]) / 2.;
504            integrated += localFlux[pos] * fabs(deltaVel);
505          }
506        }
507      }
508      this->intFlux = integrated;
509
510      delete [] world;
511      delete [] localFlux;
512
513      calcVelWidths(voxelList,head);
514
515    }
516    else // in this case there is just a 2D image.
517      this->intFlux = this->totalFlux;
518
519    if(head.isWCS()){
520      // correct for the beam size if the flux units string ends in "/beam"
521      if(head.needBeamSize()) this->intFlux  /= head.getBeamSize();
522    }
523
524  }
525  //--------------------------------------------------------------------
526
527  void Detection::calcIntegFlux(float *fluxArray, long *dim, FitsHeader &head)
528  {
529    ///  @details
530    ///  Uses the input WCS to calculate the velocity-integrated flux,
531    ///   putting velocity in units of km/s.
532    ///  Integrates over full spatial and velocity range as given
533    ///   by the extrema calculated by calcWCSparams.
534    ///
535    ///  If the flux units end in "/beam" (eg. Jy/beam), then the flux is
536    ///  corrected by the beam size (in pixels). This is done by
537    ///  multiplying the integrated flux by the number of spatial pixels,
538    ///  and dividing by the beam size in pixels (e.g. Jy/beam * pix /
539    ///  pix/beam --> Jy)
540    ///
541    ///  \param fluxArray The array of flux values.
542    ///  \param dim The dimensions of the flux array.
543    ///  \param head FitsHeader object that contains the WCS information.
544
545    if(!head.is2D()){
546
547      // include one pixel either side in each direction
548      long xsize = (this->xmax-this->xmin+3);
549      long ysize = (this->ymax-this->ymin+3);
550      long zsize = (this->zmax-this->zmin+3);
551      long size = xsize*ysize*zsize;
552      std::vector <bool> isObj(size,false);
553      double *localFlux = new double[size];
554      for(int i=0;i<size;i++) localFlux[i]=0.;
555      // work out which pixels are object pixels
556      for(std::map<long,Object2D>::iterator it=this->chanlist.begin();
557          it!=this->chanlist.end(); it++){
558        long z = it->first;
559        for(int s=0; s<it->second.getNumScan();s++){
560          long y = it->second.getScan(s).getY();
561          for(long x=it->second.getScan(s).getX();
562              x<=it->second.getScan(s).getXmax();
563              x++){
564            long pos = (x-this->xmin+1) + (y-this->ymin+1)*xsize
565              + (z-this->zmin+1)*xsize*ysize;
566            localFlux[pos] = fluxArray[x + y*dim[0] + z*dim[0]*dim[1]];
567            isObj[pos] = true;
568          }
569        }
570      }
571
572 
573      // work out the WCS coords for each pixel
574      double *world  = new double[size];
575      double xpt,ypt,zpt;
576      for(int i=0;i<xsize*ysize*zsize;i++){
577        xpt = double( this->getXmin() -1 + i%xsize );
578        ypt = double( this->getYmin() -1 + (i/xsize)%ysize );
579        zpt = double( this->getZmin() -1 + i/(xsize*ysize) );
580        world[i] = head.pixToVel(xpt,ypt,zpt);
581      }
582
583      double integrated = 0.;
584      for(int pix=0; pix<xsize*ysize; pix++){ // loop over each spatial pixel.
585        for(int z=0; z<zsize; z++){
586          int pos =  z*xsize*ysize + pix;
587          if(isObj[pos]){ // if it's an object pixel...
588            double deltaVel;
589            if(z==0)
590              deltaVel = (world[pos+xsize*ysize] - world[pos]);
591            else if(z==(zsize-1))
592              deltaVel = (world[pos] - world[pos-xsize*ysize]);
593            else
594              deltaVel = (world[pos+xsize*ysize] - world[pos-xsize*ysize]) / 2.;
595            integrated += localFlux[pos] * fabs(deltaVel);
596          }
597        }
598      }
599      this->intFlux = integrated;
600
601      delete [] world;
602      delete [] localFlux;
603
604      calcVelWidths(fluxArray, dim, head);
605
606    }
607    else // in this case there is just a 2D image.
608      this->intFlux = this->totalFlux;
609
610    if(head.isWCS()){
611      // correct for the beam size if the flux units string ends in "/beam"
612      if(head.needBeamSize()) this->intFlux  /= head.getBeamSize();
613    }
614
615  }
616  //--------------------------------------------------------------------
617
618  void Detection::calcVelWidths(std::vector<Voxel> voxelList, FitsHeader &head)
619  {
620    ///  @details
621    /// Calculates the widths of the detection at 20% and 50% of the
622    /// peak integrated flux. The procedure is as follows: first
623    /// generate an integrated flux spectrum (using all given voxels
624    /// that lie in the object's spatial map); find the peak; starting
625    /// at the spectral edges of the detection, move in or out until
626    /// you reach the 20% or 50% peak flux level. Linear interpolation
627    /// between points is done.
628    ///
629    ///  \param voxelList The list of Voxels with flux information
630    ///  \param head FitsHeader object that contains the WCS information.
631
632    const int border = 1;
633    long zsize = (this->getZmax()-this->getZmin()+border*2+1);
634    double xpt = double(this->getXcentre());
635    double ypt = double(this->getYcentre());
636    double zpt;
637
638    float *intSpec = new float[zsize];
639    for(int i=0;i<zsize;i++) intSpec[i]=0;
640       
641    Object2D spatMap = this->getSpatialMap();
642    for(int s=0;s<spatMap.getNumScan();s++){
643      for(unsigned int i=0;i<voxelList.size();i++){
644        if(spatMap.isInObject(voxelList[i])){
645          if(voxelList[i].getZ()>=this->getZmin()-border &&
646             voxelList[i].getZ()<=this->getZmax()+border)
647            intSpec[voxelList[i].getZ()-this->getZmin()+1] += voxelList[i].getF();
648        }
649      }
650    }
651   
652    std::vector<std::pair<int,float> > goodPix;
653    float peak;
654    int peakLoc;
655    for(int z=0;z<zsize;z++) {
656      if(z==0 || peak<intSpec[z]){
657        peak = intSpec[z];
658        peakLoc = z;
659      }
660      goodPix.push_back(std::pair<int,float>(z,intSpec[z]));
661    }
662
663    // finding the 20% & 50% points.  Start at the velmin & velmax
664    //  points. Then, if the int flux there is above the 20%/50%
665    //  limit, go out, otherwise go in. This is to deal with the
666    //  problems from double peaked sources.
667
668    int z;
669    bool goLeft;
670    z=border;
671    goLeft = intSpec[z]>peak*0.5;
672    if(goLeft) while(z>0 && intSpec[z]>peak*0.5) z--;
673    else       while(z<peakLoc && intSpec[z]<peak*0.5) z++;
674    if(z==0) this->v50min = this->velMin;
675    else{
676      if(goLeft) zpt = z + (peak*0.5-intSpec[z])/(intSpec[z+1]-intSpec[z]) + this->getZmin() - border;
677      else       zpt = z - (peak*0.5-intSpec[z])/(intSpec[z-1]-intSpec[z]) + this->getZmin() - border;
678      this->v50min = head.pixToVel(xpt,ypt,zpt);
679    }
680    z=this->getZmax()-this->getZmin();
681    goLeft = intSpec[z]<peak*0.5;
682    if(goLeft) while(z>peakLoc && intSpec[z]<peak*0.5) z--;
683    else       while(z<zsize && intSpec[z]>peak*0.5) z++;
684    if(z==zsize) this->v50max = this->velMax;
685    else{
686      if(goLeft) zpt = z + (peak*0.5-intSpec[z])/(intSpec[z+1]-intSpec[z]) + this->getZmin() - border;
687      else       zpt = z - (peak*0.5-intSpec[z])/(intSpec[z-1]-intSpec[z]) + this->getZmin() - border;
688      this->v50max = head.pixToVel(xpt,ypt,zpt);
689    }
690    z=border;
691    goLeft = intSpec[z]>peak*0.5;
692    if(goLeft) while(z>0 && intSpec[z]>peak*0.2) z--;
693    else       while(z<peakLoc && intSpec[z]<peak*0.2) z++;
694    if(z==0) this->v20min = this->velMin;
695    else{
696      if(goLeft) zpt = z + (peak*0.2-intSpec[z])/(intSpec[z+1]-intSpec[z]) + this->getZmin() - border;
697      else       zpt = z - (peak*0.2-intSpec[z])/(intSpec[z-1]-intSpec[z]) + this->getZmin() - border;
698      this->v20min = head.pixToVel(xpt,ypt,zpt);
699    }
700    z=this->getZmax()-this->getZmin();
701    goLeft = intSpec[z]<peak*0.5;
702    if(goLeft) while(z>peakLoc && intSpec[z]<peak*0.2) z--;
703    else       while(z<zsize && intSpec[z]>peak*0.2) z++;
704    if(z==zsize) this->v20max = this->velMax;
705    else{
706      if(goLeft) zpt = z + (peak*0.2-intSpec[z])/(intSpec[z+1]-intSpec[z]) + this->getZmin() - border;
707      else       zpt = z - (peak*0.2-intSpec[z])/(intSpec[z-1]-intSpec[z]) + this->getZmin() - border;
708      this->v20max = head.pixToVel(xpt,ypt,zpt);
709    }
710
711    this->w20 = fabs(this->v20min - this->v20max);
712    this->w50 = fabs(this->v50min - this->v50max);
713
714    delete [] intSpec;
715
716  }
717
718  //--------------------------------------------------------------------
719
720  void Detection::calcVelWidths(float *fluxArray, long *dim, FitsHeader &head)
721  {
722    ///  @details
723    /// Calculates the widths of the detection at 20% and 50% of the
724    /// peak integrated flux. The procedure is as follows: first
725    /// generate an integrated flux spectrum (summing each spatial
726    /// pixel's spectrum); find the peak; starting at the spectral
727    /// edges of the detection, move in or out until you reach the 20%
728    /// or 50% peak flux level. Linear interpolation between points is
729    /// done.
730    ///
731    ///  \param fluxArray The array of flux values.
732    ///  \param dim The dimensions of the flux array.
733    ///  \param head FitsHeader object that contains the WCS information.
734
735    if(dim[2] > 2){
736
737      double xpt = double(this->getXcentre());
738      double ypt = double(this->getYcentre());
739      double zpt;
740
741      float *intSpec = new float[dim[2]];
742      bool *mask = new bool[dim[0]*dim[1]*dim[2]];
743      for(int i=0;i<dim[0]*dim[1]*dim[2];i++) mask[i] = true;
744      getIntSpec(*this,fluxArray,dim,mask,1.,intSpec);
745
746      std::vector<std::pair<int,float> > goodPix;
747      float peak;
748      int peakLoc;
749      for(int z=this->getZmin();z<=this->getZmax();z++) {
750        if(z==this->getZmin() || peak<intSpec[z]){
751          peak = intSpec[z];
752          peakLoc = z;
753        }
754        goodPix.push_back(std::pair<int,float>(z,intSpec[z]));
755      }
756
757      // finding the 20% & 50% points.  Start at the velmin & velmax
758      //  points. Then, if the int flux there is above the 20%/50%
759      //  limit, go out, otherwise go in. This is to deal with the
760      //  problems from double- (or multi-) peaked sources.
761
762      int z;
763      bool goLeft;
764      z=this->getZmin();
765      goLeft = intSpec[z]>peak*0.5;
766      if(goLeft) while(z>0 && intSpec[z]>peak*0.5) z--;
767      else       while(z<peakLoc && intSpec[z]<peak*0.5) z++;
768      if(z==0) this->v50min = this->velMin;
769      else{
770        if(goLeft) zpt = z + (peak*0.5-intSpec[z])/(intSpec[z+1]-intSpec[z]);
771        else       zpt = z - (peak*0.5-intSpec[z])/(intSpec[z-1]-intSpec[z]);
772        this->v50min = head.pixToVel(xpt,ypt,zpt);
773      }
774      z=this->getZmax();
775      goLeft = intSpec[z]<peak*0.5;
776      if(goLeft) while(z>peakLoc && intSpec[z]<peak*0.5) z--;
777      else       while(z<dim[2] && intSpec[z]>peak*0.5) z++;
778      if(z==dim[2]) this->v50max = this->velMax;
779      else{
780        if(goLeft) zpt = z + (peak*0.5-intSpec[z])/(intSpec[z+1]-intSpec[z]);
781        else       zpt = z - (peak*0.5-intSpec[z])/(intSpec[z-1]-intSpec[z]);
782        this->v50max = head.pixToVel(xpt,ypt,zpt);
783      }
784      z=this->getZmin();
785      goLeft = intSpec[z]>peak*0.5;
786      if(goLeft) while(z>0 && intSpec[z]>peak*0.2) z--;
787      else       while(z<peakLoc && intSpec[z]<peak*0.2) z++;
788      if(z==0) this->v20min = this->velMin;
789      else{
790        if(goLeft) zpt = z + (peak*0.2-intSpec[z])/(intSpec[z+1]-intSpec[z]);
791        else       zpt = z - (peak*0.2-intSpec[z])/(intSpec[z-1]-intSpec[z]);
792        this->v20min = head.pixToVel(xpt,ypt,zpt);
793      }
794      z=this->getZmax();
795      goLeft = intSpec[z]<peak*0.5;
796      if(goLeft) while(z>peakLoc && intSpec[z]<peak*0.2) z--;
797      else       while(z<dim[2] && intSpec[z]>peak*0.2) z++;
798      if(z==dim[2]) this->v20max = this->velMax;
799      else{
800        if(goLeft) zpt = z + (peak*0.2-intSpec[z])/(intSpec[z+1]-intSpec[z]);
801        else       zpt = z - (peak*0.2-intSpec[z])/(intSpec[z-1]-intSpec[z]);
802        this->v20max = head.pixToVel(xpt,ypt,zpt);
803      }
804
805      delete [] intSpec;
806      delete [] mask;
807
808    }
809    else{
810      this->v50min = this->v20min = this->velMin;
811      this->v50max = this->v20max = this->velMax;
812    }
813
814    this->w20 = fabs(this->v20min - this->v20max);
815    this->w50 = fabs(this->v50min - this->v50max);
816
817  }
818  //--------------------------------------------------------------------
819
820  void Detection::setOffsets(Param &par)
821  {
822    ///  @details
823    /// This function stores the values of the offsets for each cube axis.
824    /// The offsets are the starting values of the cube axes that may differ from
825    ///  the default value of 0 (for instance, if a subsection is being used).
826    /// The values will be used when the detection is outputted.
827
828    this->xSubOffset = par.getXOffset();
829    this->ySubOffset = par.getYOffset();
830    this->zSubOffset = par.getZOffset();
831  }
832  //--------------------------------------------------------------------
833
834  bool Detection::hasEnoughChannels(int minNumber)
835  {
836    ///  @details
837    /// A function to determine if the Detection has enough
838    /// contiguous channels to meet the minimum requirement
839    /// given as the argument.
840    /// \param minNumber How many channels is the minimum acceptable number?
841    /// \return True if there is at least one occurence of minNumber consecutive
842    /// channels present to return true. False otherwise.
843
844    // Preferred method -- need a set of minNumber consecutive channels present.
845
846    int numChan = this->getMaxAdjacentChannels();
847    bool result = (numChan >= minNumber);
848
849    return result;
850 
851  }
852  //--------------------------------------------------------------------
853
854  std::vector<int> Detection::getVertexSet()
855  {
856    ///  @details
857    /// Gets a list of points being the end-points of 1-pixel long
858    /// segments drawing a border around the spatial extend of a
859    /// detection. The vector is a series of 4 integers, being: x_0,
860    /// y_0, x_1, y_1.
861    /// \return The vector of vertex positions.
862
863    std::vector<int> vertexSet;
864
865    int xmin = this->getXmin() - 1;
866    int xmax = this->getXmax() + 1;
867    int ymin = this->getYmin() - 1;
868    int ymax = this->getYmax() + 1;
869    int xsize = xmax - xmin + 1;
870    int ysize = ymax - ymin + 1;
871
872    std::vector<Voxel> voxlist = this->getPixelSet();
873    std::vector<bool> isObj(xsize*ysize,false);
874    for(unsigned int i=0;i<voxlist.size();i++){
875      int pos = (voxlist[i].getX()-xmin) +
876        (voxlist[i].getY()-ymin)*xsize;
877      isObj[pos] = true;
878    }
879    voxlist.clear();
880   
881    for(int x=xmin; x<=xmax; x++){
882      // for each column...
883      for(int y=ymin+1;y<=ymax;y++){
884        int current  = (y-ymin)*xsize + x-xmin;
885        int previous = (y-ymin-1)*xsize + x-xmin;
886        if((isObj[current]&&!isObj[previous])   ||
887           (!isObj[current]&&isObj[previous])){
888          vertexSet.push_back(x);
889          vertexSet.push_back(y);
890          vertexSet.push_back(x+1);
891          vertexSet.push_back(y);
892        }
893      }
894    }
895    for(int y=ymin; y<=ymax; y++){
896      // now for each row...
897      for(int x=xmin+1;x<=xmax;x++){
898        int current  = (y-ymin)*xsize + x-xmin;
899        int previous = (y-ymin)*xsize + x-xmin - 1;
900        if((isObj[current]&&!isObj[previous])   ||
901           (!isObj[current]&&isObj[previous])){
902          vertexSet.push_back(x);
903          vertexSet.push_back(y);
904          vertexSet.push_back(x);
905          vertexSet.push_back(y+1);
906        }
907      }
908    }
909
910    return vertexSet;
911 
912  }
913
914}
Note: See TracBrowser for help on using the repository browser.