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

Last change on this file since 549 was 547, checked in by MatthewWhiting, 15 years ago

Cleaning up pixelArray references in detection.cc, and improving the copy constructors

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