source: tags/release-1.0.2/src/Detection/detection.cc @ 1455

Last change on this file since 1455 was 126, checked in by Matthew Whiting, 18 years ago

Changed all instances of fabsf to fabs so that compilation on venice works.
(Mirror commit of rev.125)

File size: 12.1 KB
Line 
1#include <iostream>
2#include <iomanip>
3#include <vector>
4#include <string>
5#include <wcs.h>
6#include <math.h>
7#include <param.hh>
8#include <Utils/utils.hh>
9#include <Detection/detection.hh>
10
11using std::setw;
12using std::setprecision;
13using std::endl;
14
15std::ostream& operator<< ( std::ostream& theStream, Voxel& vox)
16{
17  /**
18   * << operator for Voxel class
19   * A convenient way of printing the coordinate & flux values of a voxel.
20   */ 
21
22  theStream << setw(4) << vox.itsX ;
23  theStream << " " << setw(4) << vox.itsY;
24  theStream << " " << setw(4) << vox.itsZ;
25  theStream << setprecision(4);
26  theStream << "  " << vox.itsF;
27
28}
29
30
31void Detection::calcParams()
32{
33  /**
34   * Detection::calcParams()
35   *  A function that calculates centroid positions, minima & maxima of coordinates,
36   *   and total & peak fluxes for a detection.
37   */
38
39  if(this->pix.size()>0){
40    this->xcentre = 0;
41    this->ycentre = 0;
42    this->zcentre = 0;
43    this->totalFlux = 0;
44    this->peakFlux = this->pix[0].itsF;
45    this->xmin = 0;
46    this->xmax = 0;
47    this->ymin = 0;
48    this->ymax = 0;
49    this->zmin = 0;
50    this->zmax = 0;
51    for(int ctr=0;ctr<this->pix.size();ctr++){
52      this->xcentre   += this->pix[ctr].itsX;
53      this->ycentre   += this->pix[ctr].itsY;
54      this->zcentre   += this->pix[ctr].itsZ;
55      this->totalFlux += this->pix[ctr].itsF;
56      if((ctr==0)||(this->pix[ctr].itsX<this->xmin)) this->xmin = this->pix[ctr].itsX;
57      if((ctr==0)||(this->pix[ctr].itsX>this->xmax)) this->xmax = this->pix[ctr].itsX;
58      if((ctr==0)||(this->pix[ctr].itsY<this->ymin)) this->ymin = this->pix[ctr].itsY;
59      if((ctr==0)||(this->pix[ctr].itsY>this->ymax)) this->ymax = this->pix[ctr].itsY;
60      if((ctr==0)||(this->pix[ctr].itsZ<this->zmin)) this->zmin = this->pix[ctr].itsZ;
61      if((ctr==0)||(this->pix[ctr].itsZ>this->zmax)) this->zmax = this->pix[ctr].itsZ;
62      if(this->negativeSource){
63        // if negative feature, peakFlux is most negative flux
64        if((ctr==0)||(this->pix[ctr].itsF < this->peakFlux)){
65          this->peakFlux = this->pix[ctr].itsF;
66          this->xpeak = this->pix[ctr].itsX;
67          this->ypeak = this->pix[ctr].itsY;
68          this->zpeak = this->pix[ctr].itsZ;
69        }
70      }
71      else{
72        // otherwise, it's a regular detection, and peakFlux is most positive flux
73        if((ctr==0)||(this->pix[ctr].itsF > this->peakFlux)){
74          this->peakFlux = this->pix[ctr].itsF;
75          this->xpeak = this->pix[ctr].itsX;
76          this->ypeak = this->pix[ctr].itsY;
77          this->zpeak = this->pix[ctr].itsZ;
78        }
79      }
80    }
81    this->xcentre /= this->pix.size();
82    this->ycentre /= this->pix.size();
83    this->zcentre /= this->pix.size();
84  }
85}
86
87//void Detection::calcWCSparams(wcsprm *wcs)
88void Detection::calcWCSparams(FitsHeader head)
89{
90  /**
91   * Detection::calcWCSparams(FitsHeader)
92   *  Use the input wcs to calculate the position and velocity information for the Detection.
93   *  Makes no judgement as to whether the WCS is good -- this needs to be done beforehand.
94   *  Quantities calculated:
95   *     RA: ra [deg], ra (string), ra width.
96   *     Dec: dec [deg], dec (string), dec width.
97   *     Vel: vel [km/s], min & max vel, vel width.
98   *     Other: coord type for all three axes, nuRest, name (IAU-style, in equatorial or Galactic)
99   *     Uses getIntegFlux to calculate the integrated flux in (say) [Jy km/s]
100   */
101
102  if(head.isWCS()){
103
104    this->calcParams(); // make sure this is up to date.
105
106    double *pixcrd = new double[15];
107    double *world  = new double[15];
108    /*
109      define a five-point array in 3D:
110      (x,y,z), (x,y,z1), (x,y,z2), (x1,y1,z), (x2,y2,z)
111      [note: x = central point, x1 = minimum x, x2 = maximum x etc.]
112      and convert to world coordinates.   
113    */
114    pixcrd[0]  = pixcrd[3] = pixcrd[6] = this->xcentre;
115    pixcrd[9]  = this->xmin-0.5;
116    pixcrd[12] = this->xmax+0.5;
117    pixcrd[1]  = pixcrd[4] = pixcrd[7] = this->ycentre;
118    pixcrd[10] = this->ymin-0.5;
119    pixcrd[13] = this->ymax+0.5;
120    pixcrd[2] = pixcrd[11] = pixcrd[14] = this->zcentre;
121    pixcrd[5] = this->zmin;
122    pixcrd[8] = this->zmax;
123    int flag = head.pixToWCS(pixcrd, world, 5);
124    delete [] pixcrd;
125
126    // world now has the WCS coords for the five points -- use this to work out WCS params
127 
128    this->lngtype = head.getWCS()->lngtyp;
129    this->lattype = head.getWCS()->lattyp;
130    this->specUnits = head.getSpectralUnits();
131    this->fluxUnits = head.getFluxUnits();
132    // if fluxUnits are eg. Jy/beam, make intFluxUnits = Jy km/s
133    this->intFluxUnits = head.getIntFluxUnits();
134    this->ra   = world[0];
135    this->dec  = world[1];
136    this->raS  = decToDMS(this->ra, this->lngtype);
137    this->decS = decToDMS(this->dec,this->lattype);
138    this->raWidth   = angularSeparation(world[9],world[1],world[12],world[1]) * 60.;
139    this->decWidth  = angularSeparation(world[0],world[10],world[0],world[13]) * 60.;
140    this->name = head.getIAUName(this->ra, this->dec);
141    this->vel    = head.specToVel(world[2]);
142    this->velMin = head.specToVel(world[5]);
143    this->velMax = head.specToVel(world[8]);
144    this->velWidth = fabs(this->velMax - this->velMin);
145
146    this->getIntegFlux(head);
147
148    this->flagWCS = true;
149
150    delete [] world;
151
152  }
153}
154
155// float Detection::getIntegFlux(wcsprm *wcs)
156float Detection::getIntegFlux(FitsHeader head)
157{
158  /**
159   * Detection::getIntegFlux(FitsHeader)
160   *  Uses the input wcs to calculate the velocity-integrated flux,
161   *  putting velocity in units of km/s.
162   *  Integrates over full spatial and velocity range as given by extrema calculated
163   *  by calcWCSparams.
164   *  Units are (Jy/beam) . km/s  (no correction for the beam is made here...)
165   */
166
167  // include one pixel either side in each direction
168  int xsize = (this->xmax-this->xmin+3);
169  int ysize = (this->ymax-this->ymin+3);
170  int zsize = (this->zmax-this->zmin+3);
171  vector <bool> isObj(xsize*ysize*zsize,false);
172  vector <float> fluxArray(xsize*ysize*zsize,0.);
173  // work out which pixels are object pixels
174  for(int p=0;p<this->pix.size();p++){
175    int pos = (this->pix[p].getX()-this->xmin+1) + (this->pix[p].getY()-this->ymin+1)*xsize +
176      (this->pix[p].getZ()-this->zmin+1)*xsize*ysize;
177    fluxArray[pos] = this->pix[p].getF();
178    isObj[pos] = true;
179  }
180 
181  // work out the WCS coords for each pixel
182  double *world  = new double[xsize*ysize*zsize];
183  double x,y,z;
184  for(int i=0;i<xsize*ysize*zsize;i++){
185    x = double( this->xmin -1 + i%xsize );
186    y = double( this->ymin -1 + (i/xsize)%ysize );
187    z = double( this->zmin -1 + i/(xsize*ysize) );
188    world[i] = head.pixToVel(x,y,z);
189  }
190
191  this->intFlux = 0.;
192  for(int pix=0; pix<xsize*ysize; pix++){ // loop over each spatial pixel.
193    for(int z=0; z<zsize; z++){
194      int pos =  z*xsize*ysize + pix;
195      if(isObj[pos]){ // if it's an object pixel...
196        float deltaVel;
197        if(z==0) deltaVel = (world[pos+xsize*ysize] - world[pos]);
198        else if(z==(zsize-1)) deltaVel = (world[pos] - world[pos-xsize*ysize]);
199        else deltaVel = (world[pos+xsize*ysize] - world[pos-xsize*ysize]) / 2.;
200        this->intFlux += fluxArray[pos] * fabs(deltaVel);
201      }
202    }
203  }
204
205  if(this->fluxUnits.substr(this->fluxUnits.size()-5,this->fluxUnits.size())=="/beam")
206    this->intFlux /= head.getBeamSize();
207
208  delete [] world;
209}
210
211
212void Detection::addAnObject(Detection &toAdd)
213{
214  /**
215   * Detection::addAnObject(Detection &)
216   *  Combines two objects by adding all the pixels of the argument to the instigator.
217   *  All pixel & flux parameters are recalculated (so that calcParams does not need to be
218   *   called a second time), but WCS parameters are not.
219   */
220  /*  */
221  this->xcentre *= this->pix.size();
222  this->ycentre *= this->pix.size();
223  this->zcentre *= this->pix.size();
224  for(int ctr=0;ctr<toAdd.getSize();ctr++){
225    long x  = toAdd.getX(ctr);
226    long y  = toAdd.getY(ctr);
227    long z  = toAdd.getZ(ctr);
228    float f = toAdd.getF(ctr);
229    bool isNewPix = true;
230    int ctr2 = 0;
231    // For each pixel in the new object, test to see if it already appears in the object
232    while( isNewPix && (ctr2<this->pix.size()) ){
233      isNewPix = isNewPix && (( this->pix[ctr2].itsX != x ) ||
234                              ( this->pix[ctr2].itsY != y ) ||
235                              ( this->pix[ctr2].itsZ != z ) );
236      ctr2++;
237    }
238    if(isNewPix){
239      // If the pixel is new, add it to the object and re-calculate the parameters.
240      this->pix.push_back(toAdd.getPixel(ctr));
241      this->xcentre += toAdd.getX(ctr);
242      this->ycentre += toAdd.getY(ctr);
243      this->zcentre += toAdd.getZ(ctr);
244      this->totalFlux += toAdd.getF(ctr);
245      if(toAdd.getX(ctr)<this->xmin) this->xmin=toAdd.getX(ctr);
246      if(toAdd.getX(ctr)>this->xmax) this->xmax=toAdd.getX(ctr);
247      if(toAdd.getY(ctr)<this->ymin) this->ymin=toAdd.getY(ctr);
248      if(toAdd.getY(ctr)>this->ymax) this->ymax=toAdd.getY(ctr);
249      if(toAdd.getZ(ctr)<this->zmin) this->zmin=toAdd.getZ(ctr);
250      if(toAdd.getZ(ctr)>this->zmax) this->zmax=toAdd.getZ(ctr);
251      if(toAdd.getF(ctr)>this->peakFlux) this->peakFlux=toAdd.getF(ctr);
252    }
253  }
254  this->xcentre /= this->pix.size();
255  this->ycentre /= this->pix.size();
256  this->zcentre /= this->pix.size();
257
258}
259/*  */
260
261
262void Detection::addOffsets(Param &par)
263{
264  this->xSubOffset = par.getXOffset();
265  this->ySubOffset = par.getYOffset();
266  this->zSubOffset = par.getZOffset();
267}
268
269bool Detection::hasEnoughChannels(int minNumber)
270{
271  /**
272   *  bool hasEnoughChannels(int)
273   *    A function to determine if the Detection has enough
274   *    contiguous channels to meet the minimum requirement
275   *    given as the argument.
276   *    Needs to have at least one occurence of minNumber consecutive
277   *    channels present to return true. Otherwise returns false.
278   */
279
280  // Original requirement -- based on total span
281// int numChannels = this->getZmax() - this->getZmin() + 1;
282
283// Alternative -- number of distinct channels detected
284//   int numChannels = 0;
285//   this->SortByZ();
286//   if(this->getSize()>0) numChannels++;
287//   for(int i=1;i<this->getSize();i++)
288//     if(this->getZ(i)>this->getZ(i-1)) numChannels++; 
289//   return (numChannels < minNumber);
290
291// Preferred method -- need a set of minNumber consecutive channels present.
292  this->SortByZ();
293  int numChannels = 0;
294  bool result = false;
295  if(this->getSize()>0) numChannels++;
296  for(int i=1;i<this->getSize();i++) {
297    if( (this->getZ(i) - this->getZ(i-1)) == 1) numChannels++;
298    else if( (this->getZ(i) - this->getZ(i-1)) >= 2) numChannels = 1;
299
300    if( numChannels >= minNumber) result = true;
301  }
302  return result;
303 
304}
305
306int Detection::getSpatialSize()
307{
308  /**
309   *  int getSpatialSize()
310   *    A function that returns the number of distinct spatial
311   *     pixels in a Detection.
312   */
313
314  vector<Pixel> spatialPix;
315  Pixel newpix;
316  bool addThisOne;
317  newpix.setXY(this->getX(0),this->getY(0));
318  spatialPix.push_back(newpix);
319  for(int i=1;i<this->pix.size();i++){
320    newpix.setXY(this->getX(i),this->getY(i));
321    addThisOne = true;
322    for(int j=0;(j<spatialPix.size())&&addThisOne;j++) {
323      // do whole list or until addThisOne=false
324      addThisOne = ( (newpix.getX()!=spatialPix[j].getX()) ||
325                     (newpix.getY()!=spatialPix[j].getY())   );
326      // ie. if one of X or Y is different, addThisOne is true.
327    }
328    if(addThisOne) spatialPix.push_back(newpix);
329  }
330  return spatialPix.size();
331}
332
333std::ostream& operator<< ( std::ostream& theStream, Detection& obj)
334{
335  /**
336   * << operator for Detection class
337   *  A convenient way of printing the coordinate & flux
338   *  values for each pixel in the Detection
339   *   --> use as front end to the << operator for Voxels.
340   */ 
341
342  for(int i=0;i<obj.pix.size();i++) theStream << obj.pix[i] << endl;
343  theStream<<"---"<<endl;
344}
345
346Detection combineObjects(Detection &first, Detection &second)
347{
348  // make the new object
349  int *ctr = new int;
350  Detection *newObject = new Detection;
351  for(*ctr=0;(*ctr)<first.getSize();(*ctr)++){
352    newObject->addPixel(first.getPixel(*ctr));
353  }
354  for(*ctr=0;(*ctr)<second.getSize();(*ctr)++){
355    newObject->addPixel(second.getPixel(*ctr));
356  }
357  delete ctr;
358  newObject->calcParams();
359  return *newObject;
360}
361
362vector <Detection> combineLists(vector <Detection> &first, vector <Detection> &second)
363{
364  // make the new object
365  vector <Detection> newList(first.size()+second.size());
366  for(int i=0;i<first.size();i++) newList[i] = first[i];
367  for(int i=0;i<second.size();i++) newList[i+first.size()] = second[i];
368 
369  return newList;
370}
371
Note: See TracBrowser for help on using the repository browser.