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

Last change on this file since 747 was 747, checked in by MatthewWhiting, 14 years ago

More improvements based on some profiling with Shark. Tara's test case down to just over a minute!

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