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

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

Simplifying the syntax...

File size: 36.8 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      std::vector<Voxel> voxlist = this->getPixelSet();
573      for(std::vector<Voxel>::iterator v=voxlist.begin();v<voxlist.end();v++){
574        long pos=(v->getX()-this->xmin+1) + (v->getY()-this->ymin+1)*xsize
575          + (v->getZ()-this->zmin+1)*xsize*ysize;
576        localFlux[pos] = fluxArray[v->arrayIndex(dim)];
577        isObj[pos] = true;
578      }
579 
580      // work out the WCS coords for each pixel
581      double *world  = new double[size];
582      double xpt,ypt,zpt;
583      for(int i=0;i<xsize*ysize*zsize;i++){
584        xpt = double( this->getXmin() -1 + i%xsize );
585        ypt = double( this->getYmin() -1 + (i/xsize)%ysize );
586        zpt = double( this->getZmin() -1 + i/(xsize*ysize) );
587        world[i] = head.pixToVel(xpt,ypt,zpt);
588      }
589
590      double integrated = 0.;
591      for(int pix=0; pix<xsize*ysize; pix++){ // loop over each spatial pixel.
592        for(int z=0; z<zsize; z++){
593          int pos =  z*xsize*ysize + pix;
594          if(isObj[pos]){ // if it's an object pixel...
595            double deltaVel;
596            if(z==0)
597              deltaVel = (world[pos+xsize*ysize] - world[pos]);
598            else if(z==(zsize-1))
599              deltaVel = (world[pos] - world[pos-xsize*ysize]);
600            else
601              deltaVel = (world[pos+xsize*ysize] - world[pos-xsize*ysize]) / 2.;
602            integrated += localFlux[pos] * fabs(deltaVel);
603          }
604        }
605      }
606      this->intFlux = integrated;
607
608      delete [] world;
609      delete [] localFlux;
610
611      calcVelWidths(fluxArray, dim, head);
612
613    }
614    else // in this case there is just a 2D image.
615      this->intFlux = this->totalFlux;
616
617    if(head.isWCS()){
618      // correct for the beam size if the flux units string ends in "/beam"
619      if(head.needBeamSize()) this->intFlux  /= head.getBeamSize();
620    }
621
622  }
623  //--------------------------------------------------------------------
624
625  void Detection::calcVelWidths(long zdim, std::vector<Voxel> voxelList, FitsHeader &head)
626  {
627    ///  @details
628    /// Calculates the widths of the detection at 20% and 50% of the
629    /// peak integrated flux. The procedure is as follows: first
630    /// generate an integrated flux spectrum (using all given voxels
631    /// that lie in the object's spatial map); find the peak; starting
632    /// at the spectral edges of the detection, move in or out until
633    /// you reach the 20% or 50% peak flux level. Linear interpolation
634    /// between points is done.
635    ///
636    ///  \param zdim The size of the spectral axis in the cube
637    ///  \param voxelList The list of Voxels with flux information
638    ///  \param head FitsHeader object that contains the WCS information.
639
640//     this->haveParams = true;
641
642//     const int border = 1;
643// //     long zsize = (this->getZmax()-this->getZmin()+border*2+1);
644//     double xpt = double(this->getXcentre());
645//     double ypt = double(this->getYcentre());
646//     double zpt;
647
648//     float *intSpec = new float[zsize];
649//     for(int i=0;i<zsize;i++) intSpec[i]=0;
650    float *intSpec = new float[zdim];
651    for(int i=0;i<zdim;i++) intSpec[i]=0;
652       
653    Object2D spatMap = this->getSpatialMap();
654    for(int s=0;s<spatMap.getNumScan();s++){
655      std::vector<Voxel>::iterator vox;
656      for(vox=voxelList.begin();vox<voxelList.end();vox++){
657        if(spatMap.isInObject(*vox)){
658//        if(vox->getZ()>=this->getZmin()-border &&
659//           vox->getZ()<=this->getZmax()+border)
660//          intSpec[vox->getZ()-this->getZmin()+1] += vox->getF();
661          intSpec[vox->getZ()] += vox->getF();
662        }
663      }
664    }
665   
666//     std::vector<std::pair<int,float> > goodPix;
667//     float peak=0.;
668//     int peakLoc=0;
669// //     for(int z=0;z<zsize;z++) {
670//     for(int z=0;z<zdim;z++) {
671//       if(z==0 || peak<intSpec[z]){
672//      peak = intSpec[z];
673//      peakLoc = z;
674//       }
675//       goodPix.push_back(std::pair<int,float>(z,intSpec[z]));
676//     }
677
678//     // finding the 20% & 50% points.  Start at the velmin & velmax
679//     //  points. Then, if the int flux there is above the 20%/50%
680//     //  limit, go out, otherwise go in. This is to deal with the
681//     //  problems from double peaked sources.
682
683//     int z;
684//     bool goLeft;
685//     z=border;
686//     goLeft = intSpec[z]>peak*0.5;
687//     if(goLeft) while(z>0 && intSpec[z]>peak*0.5) z--;
688//     else       while(z<peakLoc && intSpec[z]<peak*0.5) z++;
689//     if(z==0) this->v50min = this->velMin;
690//     else{
691//       if(goLeft) zpt = z + (peak*0.5-intSpec[z])/(intSpec[z+1]-intSpec[z]) + this->getZmin() - border;
692//       else       zpt = z - (peak*0.5-intSpec[z])/(intSpec[z-1]-intSpec[z]) + this->getZmin() - border;
693//       this->v50min = head.pixToVel(xpt,ypt,zpt);
694//     }
695//     z=this->getZmax()-this->getZmin();
696//     goLeft = intSpec[z]<peak*0.5;
697//     if(goLeft) while(z>peakLoc && intSpec[z]<peak*0.5) z--;
698//     else       while(z<zsize && intSpec[z]>peak*0.5) z++;
699//     if(z==zsize) this->v50max = this->velMax;
700//     else{
701//       if(goLeft) zpt = z + (peak*0.5-intSpec[z])/(intSpec[z+1]-intSpec[z]) + this->getZmin() - border;
702//       else       zpt = z - (peak*0.5-intSpec[z])/(intSpec[z-1]-intSpec[z]) + this->getZmin() - border;
703//       this->v50max = head.pixToVel(xpt,ypt,zpt);
704//     }
705//     z=border;
706//     goLeft = intSpec[z]>peak*0.2;
707//     if(goLeft) while(z>0 && intSpec[z]>peak*0.2) z--;
708//     else       while(z<peakLoc && intSpec[z]<peak*0.2) z++;
709//     if(z==0) this->v20min = this->velMin;
710//     else{
711//       if(goLeft) zpt = z + (peak*0.2-intSpec[z])/(intSpec[z+1]-intSpec[z]) + this->getZmin() - border;
712//       else       zpt = z - (peak*0.2-intSpec[z])/(intSpec[z-1]-intSpec[z]) + this->getZmin() - border;
713//       this->v20min = head.pixToVel(xpt,ypt,zpt);
714//     }
715//     z=this->getZmax()-this->getZmin();
716//     goLeft = intSpec[z]<peak*0.2;
717//     if(goLeft) while(z>peakLoc && intSpec[z]<peak*0.2) z--;
718//     else       while(z<zsize && intSpec[z]>peak*0.2) z++;
719//     if(z==zsize) this->v20max = this->velMax;
720//     else{
721//       if(goLeft) zpt = z + (peak*0.2-intSpec[z])/(intSpec[z+1]-intSpec[z]) + this->getZmin() - border;
722//       else       zpt = z - (peak*0.2-intSpec[z])/(intSpec[z-1]-intSpec[z]) + this->getZmin() - border;
723//       this->v20max = head.pixToVel(xpt,ypt,zpt);
724//     }
725
726//     this->w20 = fabs(this->v20min - this->v20max);
727//     this->w50 = fabs(this->v50min - this->v50max);
728
729    calcVelWidths(zdim, intSpec, head);
730
731    delete [] intSpec;
732
733  }
734
735  //--------------------------------------------------------------------
736
737  void Detection::calcVelWidths(long zdim, float *intSpec, FitsHeader &head)
738  {
739
740      // finding the 20% & 50% points.  Start at the velmin & velmax
741      //  points. Then, if the int flux there is above the 20%/50%
742      //  limit, go out, otherwise go in. This is to deal with the
743      //  problems from double- (or multi-) peaked sources.
744
745    this->haveParams = true;
746
747    int z=this->getZmin();
748    double zpt,xpt=double(this->getXcentre()),ypt=double(this->getXcentre());
749    bool goLeft;
750   
751//     std::vector<std::pair<int,float> > goodPix;
752    float peak=0.;
753    int peakLoc=0;
754    for(int z=0;z<zdim;z++) {
755      if(z==0 || peak<intSpec[z]){
756        peak = intSpec[z];
757        peakLoc = z;
758      }
759//       goodPix.push_back(std::pair<int,float>(z,intSpec[z]));
760    }
761   
762    goLeft = intSpec[z]>peak*0.5;
763    if(goLeft) while(z>0 && intSpec[z]>peak*0.5) z--;
764    else       while(z<peakLoc && intSpec[z]<peak*0.5) z++;
765    if(z==0) this->v50min = this->velMin;
766    else{
767      if(goLeft) zpt = z + (peak*0.5-intSpec[z])/(intSpec[z+1]-intSpec[z]);
768      else       zpt = z - (peak*0.5-intSpec[z])/(intSpec[z-1]-intSpec[z]);
769      this->v50min = head.pixToVel(xpt,ypt,zpt);
770    }
771    z=this->getZmax();
772    goLeft = intSpec[z]<peak*0.5;
773    if(goLeft) while(z>peakLoc && intSpec[z]<peak*0.5) z--;
774    else       while(z<zdim    && intSpec[z]>peak*0.5) z++;
775    if(z==zdim) this->v50max = this->velMax;
776    else{
777      if(goLeft) zpt = z + (peak*0.5-intSpec[z])/(intSpec[z+1]-intSpec[z]);
778      else       zpt = z - (peak*0.5-intSpec[z])/(intSpec[z-1]-intSpec[z]);
779      this->v50max = head.pixToVel(xpt,ypt,zpt);
780    }
781    z=this->getZmin();
782    goLeft = intSpec[z]>peak*0.2;
783    if(goLeft) while(z>0 && intSpec[z]>peak*0.2) z--;
784    else       while(z<peakLoc && intSpec[z]<peak*0.2) z++;
785    if(z==0) this->v20min = this->velMin;
786    else{
787      if(goLeft) zpt = z + (peak*0.2-intSpec[z])/(intSpec[z+1]-intSpec[z]);
788      else       zpt = z - (peak*0.2-intSpec[z])/(intSpec[z-1]-intSpec[z]);
789      this->v20min = head.pixToVel(xpt,ypt,zpt);
790    }
791    z=this->getZmax();
792    goLeft = intSpec[z]<peak*0.2;
793    if(goLeft) while(z>peakLoc && intSpec[z]<peak*0.2) z--;
794    else       while(z<zdim    && intSpec[z]>peak*0.2) z++;
795    if(z==zdim) this->v20max = this->velMax;
796    else{
797      if(goLeft) zpt = z + (peak*0.2-intSpec[z])/(intSpec[z+1]-intSpec[z]);
798      else       zpt = z - (peak*0.2-intSpec[z])/(intSpec[z-1]-intSpec[z]);
799      this->v20max = head.pixToVel(xpt,ypt,zpt);
800    }
801
802    this->w20 = fabs(this->v20min - this->v20max);
803    this->w50 = fabs(this->v50min - this->v50max);
804
805
806  }
807
808
809
810  void Detection::calcVelWidths(float *fluxArray, long *dim, FitsHeader &head)
811  {
812    ///  @details
813    /// Calculates the widths of the detection at 20% and 50% of the
814    /// peak integrated flux. The procedure is as follows: first
815    /// generate an integrated flux spectrum (summing each spatial
816    /// pixel's spectrum); find the peak; starting at the spectral
817    /// edges of the detection, move in or out until you reach the 20%
818    /// or 50% peak flux level. Linear interpolation between points is
819    /// done.
820    ///
821    ///  \param fluxArray The array of flux values.
822    ///  \param dim The dimensions of the flux array.
823    ///  \param head FitsHeader object that contains the WCS information.
824
825    if(dim[2] > 2){
826
827//       this->haveParams = true;
828
829//       double xpt = double(this->getXcentre());
830//       double ypt = double(this->getYcentre());
831//       double zpt;
832
833      float *intSpec = new float[dim[2]];
834      long size=dim[0]*dim[1]*dim[2];
835      std::vector<bool> mask(size,true);
836      getIntSpec(*this,fluxArray,dim,mask,1.,intSpec);
837
838//       std::vector<std::pair<int,float> > goodPix;
839//       float peak=0.;
840//       int peakLoc=0;
841//       for(int z=this->getZmin();z<=this->getZmax();z++) {
842//      if(z==this->getZmin() || peak<intSpec[z]){
843//        peak = intSpec[z];
844//        peakLoc = z;
845//      }
846//      goodPix.push_back(std::pair<int,float>(z,intSpec[z]));
847//       }
848
849//       // finding the 20% & 50% points.  Start at the velmin & velmax
850//       //  points. Then, if the int flux there is above the 20%/50%
851//       //  limit, go out, otherwise go in. This is to deal with the
852//       //  problems from double- (or multi-) peaked sources.
853
854//       int z;
855//       bool goLeft;
856//       z=this->getZmin();
857//       goLeft = intSpec[z]>peak*0.5;
858//       if(goLeft) while(z>0 && intSpec[z]>peak*0.5) z--;
859//       else       while(z<peakLoc && intSpec[z]<peak*0.5) z++;
860//       if(z==0) this->v50min = this->velMin;
861//       else{
862//      if(goLeft) zpt = z + (peak*0.5-intSpec[z])/(intSpec[z+1]-intSpec[z]);
863//      else       zpt = z - (peak*0.5-intSpec[z])/(intSpec[z-1]-intSpec[z]);
864//      this->v50min = head.pixToVel(xpt,ypt,zpt);
865//       }
866//       z=this->getZmax();
867//       goLeft = intSpec[z]<peak*0.5;
868//       if(goLeft) while(z>peakLoc && intSpec[z]<peak*0.5) z--;
869//       else       while(z<dim[2] && intSpec[z]>peak*0.5) z++;
870//       if(z==dim[2]) this->v50max = this->velMax;
871//       else{
872//      if(goLeft) zpt = z + (peak*0.5-intSpec[z])/(intSpec[z+1]-intSpec[z]);
873//      else       zpt = z - (peak*0.5-intSpec[z])/(intSpec[z-1]-intSpec[z]);
874//      this->v50max = head.pixToVel(xpt,ypt,zpt);
875//       }
876//       z=this->getZmin();
877//       goLeft = intSpec[z]>peak*0.2;
878//       if(goLeft) while(z>0 && intSpec[z]>peak*0.2) z--;
879//       else       while(z<peakLoc && intSpec[z]<peak*0.2) z++;
880//       if(z==0) this->v20min = this->velMin;
881//       else{
882//      if(goLeft) zpt = z + (peak*0.2-intSpec[z])/(intSpec[z+1]-intSpec[z]);
883//      else       zpt = z - (peak*0.2-intSpec[z])/(intSpec[z-1]-intSpec[z]);
884//      this->v20min = head.pixToVel(xpt,ypt,zpt);
885//       }
886//       z=this->getZmax();
887//       goLeft = intSpec[z]<peak*0.2;
888//       if(goLeft) while(z>peakLoc && intSpec[z]<peak*0.2) z--;
889//       else       while(z<dim[2] && intSpec[z]>peak*0.2) z++;
890//       if(z==dim[2]) this->v20max = this->velMax;
891//       else{
892//      if(goLeft) zpt = z + (peak*0.2-intSpec[z])/(intSpec[z+1]-intSpec[z]);
893//      else       zpt = z - (peak*0.2-intSpec[z])/(intSpec[z-1]-intSpec[z]);
894//      this->v20max = head.pixToVel(xpt,ypt,zpt);
895//       }
896
897      this->calcVelWidths(dim[2],intSpec,head);
898
899      delete [] intSpec;
900
901    }
902    else{
903      this->v50min = this->v20min = this->velMin;
904      this->v50max = this->v20max = this->velMax;
905      this->w20 = fabs(this->v20min - this->v20max);
906      this->w50 = fabs(this->v50min - this->v50max);
907    }
908
909//     this->w20 = fabs(this->v20min - this->v20max);
910//     this->w50 = fabs(this->v50min - this->v50max);
911
912  }
913  //--------------------------------------------------------------------
914
915  void Detection::setOffsets(Param &par)
916  {
917    ///  @details
918    /// This function stores the values of the offsets for each cube axis.
919    /// The offsets are the starting values of the cube axes that may differ from
920    ///  the default value of 0 (for instance, if a subsection is being used).
921    /// The values will be used when the detection is outputted.
922
923    this->xSubOffset = par.getXOffset();
924    this->ySubOffset = par.getYOffset();
925    this->zSubOffset = par.getZOffset();
926  }
927  //--------------------------------------------------------------------
928
929  bool Detection::hasEnoughChannels(int minNumber)
930  {
931    ///  @details
932    /// A function to determine if the Detection has enough
933    /// contiguous channels to meet the minimum requirement
934    /// given as the argument.
935    /// \param minNumber How many channels is the minimum acceptable number?
936    /// \return True if there is at least one occurence of minNumber consecutive
937    /// channels present to return true. False otherwise.
938
939    // Preferred method -- need a set of minNumber consecutive channels present.
940
941    int numChan = this->getMaxAdjacentChannels();
942    bool result = (numChan >= minNumber);
943
944    return result;
945 
946  }
947  //--------------------------------------------------------------------
948
949  std::vector<int> Detection::getVertexSet()
950  {
951    ///  @details
952    /// Gets a list of points being the end-points of 1-pixel long
953    /// segments drawing a border around the spatial extend of a
954    /// detection. The vector is a series of 4 integers, being: x_0,
955    /// y_0, x_1, y_1.
956    /// \return The vector of vertex positions.
957
958    std::vector<int> vertexSet;
959
960    int xmin = this->getXmin() - 1;
961    int xmax = this->getXmax() + 1;
962    int ymin = this->getYmin() - 1;
963    int ymax = this->getYmax() + 1;
964    int xsize = xmax - xmin + 1;
965    int ysize = ymax - ymin + 1;
966
967    std::vector<Voxel> voxlist = this->getPixelSet();
968    std::vector<bool> isObj(xsize*ysize,false);
969    std::vector<Voxel>::iterator vox;
970    for(vox=voxlist.begin();vox<voxlist.end();vox++){
971      int pos = (vox->getX()-xmin) +
972        (vox->getY()-ymin)*xsize;
973      isObj[pos] = true;
974    }
975    voxlist.clear();
976   
977    for(int x=xmin; x<=xmax; x++){
978      // for each column...
979      for(int y=ymin+1;y<=ymax;y++){
980        int current  = (y-ymin)*xsize + x-xmin;
981        int previous = (y-ymin-1)*xsize + x-xmin;
982        if((isObj[current]&&!isObj[previous])   ||
983           (!isObj[current]&&isObj[previous])){
984          vertexSet.push_back(x);
985          vertexSet.push_back(y);
986          vertexSet.push_back(x+1);
987          vertexSet.push_back(y);
988        }
989      }
990    }
991    for(int y=ymin; y<=ymax; y++){
992      // now for each row...
993      for(int x=xmin+1;x<=xmax;x++){
994        int current  = (y-ymin)*xsize + x-xmin;
995        int previous = (y-ymin)*xsize + x-xmin - 1;
996        if((isObj[current]&&!isObj[previous])   ||
997           (!isObj[current]&&isObj[previous])){
998          vertexSet.push_back(x);
999          vertexSet.push_back(y);
1000          vertexSet.push_back(x);
1001          vertexSet.push_back(y+1);
1002        }
1003      }
1004    }
1005
1006    return vertexSet;
1007 
1008  }
1009
1010 
1011  void Detection::addDetection(Detection &other)
1012  {
1013    for(std::map<long, Object2D>::iterator it = other.chanlist.begin(); it!=other.chanlist.end();it++)
1014      //      this->addChannel(*it);
1015      this->addChannel(it->first, it->second);
1016    this->haveParams = false; // make it appear as if the parameters haven't been calculated, so that we can re-calculate them 
1017  }
1018
1019  Detection operator+ (Detection &lhs, Detection &rhs)
1020  {
1021    Detection output = lhs;
1022    for(std::map<long, Object2D>::iterator it = rhs.chanlist.begin(); it!=rhs.chanlist.end();it++)
1023      output.addChannel(it->first, it->second);
1024    output.haveParams = false; // make it appear as if the parameters haven't been calculated, so that we can re-calculate them
1025    return output;
1026  }
1027   
1028
1029  bool Detection::canMerge(Detection &other, Param &par)
1030  {
1031    bool near = this->isNear(other,par);
1032    if(near) return this->isClose(other,par);
1033    else return near;
1034  }
1035
1036  bool Detection::isNear(Detection &other, Param &par)
1037  {
1038
1039    bool flagAdj = par.getFlagAdjacent();
1040    float threshS = par.getThreshS();
1041    float threshV = par.getThreshV();
1042
1043    long gap;
1044    if(flagAdj) gap = 1;
1045    else gap = long( ceil(threshS) );
1046
1047    bool areNear;
1048    // Test X ranges
1049    if((this->xmin-gap)<other.xmin) areNear=((this->xmax+gap)>=other.xmin);
1050    else areNear=(other.xmax>=(this->xmin-gap));
1051    // Test Y ranges
1052    if(areNear){
1053      if((this->ymin-gap)<other.ymin) areNear=areNear&&((this->ymax+gap)>=other.ymin);
1054      else areNear=areNear&&(other.ymax>=(this->ymin-gap));
1055    }
1056    // Test Z ranges
1057    if(areNear){
1058      gap = long(ceil(threshV));
1059      if((this->zmin-gap)<other.zmin) areNear=areNear&&((this->zmax+gap)>=other.zmin);
1060      else areNear=areNear&&(other.zmax>=(this->zmin-gap));
1061    }
1062   
1063    return areNear;
1064
1065  }
1066
1067  bool Detection::isClose(Detection &other, Param &par)
1068  {
1069    bool close = false;   // this will be the value returned
1070   
1071    bool flagAdj = par.getFlagAdjacent();
1072    float threshS = par.getThreshS();
1073    float threshV = par.getThreshV();
1074
1075    //
1076    // If we get to here, the pixel ranges overlap -- so we do a
1077    // pixel-by-pixel comparison to make sure they are actually
1078    // "close" according to the thresholds.  Otherwise, close=false,
1079    // and so don't need to do anything else before returning.
1080    //
1081
1082    std::vector<long> zlist1 = this->getChannelList();
1083    std::vector<long> zlist2 = other.getChannelList();
1084    Scan test1,test2;
1085
1086    for(size_t ct1=0; (!close && (ct1<zlist1.size())); ct1++){
1087      for(size_t ct2=0; (!close && (ct2<zlist2.size())); ct2++){
1088       
1089        if(abs(zlist1[ct1]-zlist2[ct2])<=threshV){
1090             
1091          Object2D temp1 = this->getChanMap(zlist1[ct1]);
1092          Object2D temp2 = other.getChanMap(zlist2[ct2]);
1093
1094          close = temp1.canMerge(temp2,threshS,flagAdj);
1095
1096        }
1097
1098      }
1099    }
1100       
1101    return close;
1102   
1103  }
1104
1105
1106
1107}
Note: See TracBrowser for help on using the repository browser.