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

Last change on this file since 572 was 570, checked in by MatthewWhiting, 15 years ago

Merging the pixelmap-refactor changes back into the trunk.

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.