source: trunk/Detection/detection.cc @ 82

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

Coding fixes, improving the readability of the code, particularly regarding
the declaration of temporary variables. Files affected:
Detection/areClose.cc
Detection/detection.cc
Detection/thresholding_functions.cc
Detection/growObject.cc
Detection/mergeIntoList.cc
Detection/lutz_detect.cc

File size: 13.5 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
87void Detection::calcWCSparams(wcsprm *wcs)
88{
89  /**
90   * Detection::calcWCSparams(wcsprm *)
91   *  Use the input wcs to calculate the position and velocity information for the Detection.
92   *  Makes no judgement as to whether the WCS is good -- this needs to be done beforehand.
93   *  Quantities calculated:
94   *     RA: ra [deg], ra (string), ra width.
95   *     Dec: dec [deg], dec (string), dec width.
96   *     Vel: vel [km/s], min & max vel, vel width.
97   *     Other: coord type for all three axes, nuRest, name (IAU-style, in equatorial or Galactic)
98   *     Uses getIntegFlux to calculate the integrated flux in (say) [Jy km/s]
99   */
100
101  this->calcParams(); // make sure this is up to date.
102
103  double *pixcrd = new double[15];
104  double *world  = new double[15];
105  /*
106  define a five-point array in 3D:
107     (x,y,z), (x,y,z1), (x,y,z2), (x1,y1,z), (x2,y2,z)
108   note x = central point, x1 = minimum x, x2 = maximum x etc.
109  */
110  pixcrd[0]  = pixcrd[3] = pixcrd[6] = this->xcentre;
111  pixcrd[9]  = this->xmin-0.5;
112  pixcrd[12] = this->xmax+0.5;
113  pixcrd[1]  = pixcrd[4] = pixcrd[7] = this->ycentre;
114  pixcrd[10] = this->ymin-0.5;
115  pixcrd[13] = this->ymax+0.5;
116  pixcrd[2] = pixcrd[11] = pixcrd[14] = this->zcentre;
117  pixcrd[5] = this->zmin;
118  pixcrd[8] = this->zmax;
119  int flag = pixToWCSMulti(wcs, pixcrd, world, 5);
120  delete [] pixcrd;
121
122  // world now has the WCS coords for the five points -- use this to work out WCS params.
123 
124  this->lngtype = wcs->lngtyp;
125  this->lattype = wcs->lattyp;
126  this->ztype   = wcs->ctype[2];
127  this->nuRest  = wcs->restfrq;
128  this->ra   = world[0];
129  this->dec  = world[1];
130  this->raS = decToDMS(this->ra,this->lngtype);
131  this->decS = decToDMS(this->dec,this->lattype);
132  this->raWidth   = angularSeparation(world[9],world[1],world[12],world[1]) * 60.;
133  this->decWidth  = angularSeparation(world[0],world[10],world[0],world[13]) * 60.;
134  if(this->lngtype=="RA") this->name = getIAUNameEQ(this->ra,this->dec,wcs->equinox);
135  else this->name = getIAUNameGAL(this->ra,this->dec);
136  this->vel    = setVel_kms(wcs, world[2]);
137  this->velMin = setVel_kms(wcs, world[5]);
138  this->velMax = setVel_kms(wcs, world[8]);
139  this->velWidth = fabs(this->velMax - this->velMin);
140
141  this->getIntegFlux(wcs);
142
143  this->flagWCS = true;
144
145  delete [] world;
146
147}
148
149float Detection::getIntegFlux(wcsprm *wcs)
150{
151  /**
152   * Detection::getIntegFlux(wcsprm *)
153   *  Uses the input wcs to calculate the velocity-integrated flux,
154   *  putting velocity in units of km/s.
155   *  Integrates over full spatial and velocity range as given by extrema calculated
156   *  by calcWCSparams.
157   *  Units are (Jy/beam) . km/s  (no correction for the beam is made here...)
158   */
159
160  // include one pixel either side in each direction
161  int xsize = (this->xmax-this->xmin+3);
162  int ysize = (this->ymax-this->ymin+3);
163  int zsize = (this->zmax-this->zmin+3);
164  vector <bool> isObj(xsize*ysize*zsize,false);
165  vector <float> fluxArray(xsize*ysize*zsize,0.);
166  // work out which pixels are object pixels
167  for(int p=0;p<this->pix.size();p++){
168    int pos = (this->pix[p].getX()-this->xmin+1) + (this->pix[p].getY()-this->ymin+1)*xsize +
169      (this->pix[p].getZ()-this->zmin+1)*xsize*ysize;
170    fluxArray[pos] = this->pix[p].getF();
171    isObj[pos] = true;
172  }
173 
174  // work out the WCS coords for each pixel
175  double *world  = new double[xsize*ysize*zsize*3];
176  double *pix = new double[xsize*ysize*zsize*3];
177  for(int i=0;i<xsize*ysize*zsize;i++){
178    pix[i*3+0] = this->xmin -1 + i%xsize;
179    pix[i*3+1] = this->ymin -1 + (i/xsize)%ysize;
180    pix[i*3+2] = this->zmin -1 + i/(xsize*ysize);
181  }
182  int flag = pixToWCSMulti(wcs, pix, world, xsize*ysize*zsize);
183  delete [] pix;
184
185  // put velocity coords into km/s
186  for(int i=0;i<xsize*ysize*zsize;i++)
187    world[3*i+2] = setVel_kms(wcs,world[3*i+2]);
188
189  this->intFlux = 0.;
190  for(int pix=0; pix<xsize*ysize; pix++){ // loop over each spatial pixel.
191    for(int z=0; z<zsize; z++){
192      int pos =  z*xsize*ysize + pix;
193      if(isObj[pos]){ // if it's an object pixel...
194        float deltaVel = (world[3*(pos+xsize*ysize)+2] - world[ 3*(pos-xsize*ysize)+2 ]) / 2.;
195        this->intFlux += fluxArray[pos] * fabsf(deltaVel);
196      }
197    }
198  }
199  delete [] world;
200}
201
202
203void Detection::addAnObject(Detection &toAdd)
204{
205  /**
206   * Detection::addAnObject(Detection &)
207   *  Combines two objects by adding all the pixels of the argument to the instigator.
208   *  All pixel & flux parameters are recalculated (so that calcParams does not need to be
209   *   called a second time), but WCS parameters are not.
210   */
211  /*  */
212  this->xcentre *= this->pix.size();
213  this->ycentre *= this->pix.size();
214  this->zcentre *= this->pix.size();
215  for(int ctr=0;ctr<toAdd.getSize();ctr++){
216    long x  = toAdd.getX(ctr);
217    long y  = toAdd.getY(ctr);
218    long z  = toAdd.getZ(ctr);
219    float f = toAdd.getF(ctr);
220    bool isNewPix = true;
221    int ctr2 = 0;
222    // For each pixel in the new object, test to see if it already appears in the object
223    while( isNewPix && (ctr2<this->pix.size()) ){
224      isNewPix = isNewPix && (( this->pix[ctr2].itsX != x ) ||
225                              ( this->pix[ctr2].itsY != y ) ||
226                              ( this->pix[ctr2].itsZ != z ) );
227      ctr2++;
228    }
229    if(isNewPix){
230      // If the pixel is new, add it to the object and re-calculate the parameters.
231      this->pix.push_back(toAdd.getPixel(ctr));
232      this->xcentre += toAdd.getX(ctr);
233      this->ycentre += toAdd.getY(ctr);
234      this->zcentre += toAdd.getZ(ctr);
235      this->totalFlux += toAdd.getF(ctr);
236      if(toAdd.getX(ctr)<this->xmin) this->xmin=toAdd.getX(ctr);
237      if(toAdd.getX(ctr)>this->xmax) this->xmax=toAdd.getX(ctr);
238      if(toAdd.getY(ctr)<this->ymin) this->ymin=toAdd.getY(ctr);
239      if(toAdd.getY(ctr)>this->ymax) this->ymax=toAdd.getY(ctr);
240      if(toAdd.getZ(ctr)<this->zmin) this->zmin=toAdd.getZ(ctr);
241      if(toAdd.getZ(ctr)>this->zmax) this->zmax=toAdd.getZ(ctr);
242      if(toAdd.getF(ctr)>this->peakFlux) this->peakFlux=toAdd.getF(ctr);
243    }
244  }
245  this->xcentre /= this->pix.size();
246  this->ycentre /= this->pix.size();
247  this->zcentre /= this->pix.size();
248
249}
250/*  */
251
252
253// void Detection::addAnObject(Detection &toAdd)
254// {
255  /**
256   * Detection::addAnObject(Detection &)
257   *  Combines two objects by adding all the pixels of the argument to the instigator.
258   *  All pixel & flux parameters are recalculated (so that calcParams does not need to be
259   *   called a second time), but WCS parameters are not.
260   */
261/*
262  int *ctr = new int;
263  int *ctr2 = new int;
264  bool *isNewPix = new bool;
265  this->xcentre *= this->pix.size();
266  this->ycentre *= this->pix.size();
267  this->zcentre *= this->pix.size();
268  for((*ctr)=0;(*ctr)<toAdd.getSize();(*ctr)++){
269    // For each pixel in the new object, test to see if it already appears in the object
270    long *x = new long;
271    *x = toAdd.getX(*ctr);
272    long *y = new long;
273    *y = toAdd.getY(*ctr);
274    long *z = new long;
275    *z = toAdd.getZ(*ctr);
276    float *f = new float;
277    *f = toAdd.getF(*ctr);
278    *isNewPix = true;
279    *ctr2 = 0;
280    while( *isNewPix && (*ctr2<this->pix.size()) ){
281      *isNewPix = *isNewPix && (( this->pix[*ctr2].itsX != *x ) ||
282                                ( this->pix[*ctr2].itsY != *y ) ||
283                                ( this->pix[*ctr2].itsZ != *z ) );
284      *ctr2 += 1;
285    }
286    if(*isNewPix){
287      // If the pixel is new, add it to the object and re-calculate the parameters.
288      this->pix.push_back(toAdd.getPixel(*ctr));
289      this->xcentre += *x;
290      this->ycentre += *y;
291      this->zcentre += *z;
292      this->totalFlux += *f;
293      if(*x<this->xmin) this->xmin=*x;
294      if(*x>this->xmax) this->xmax=*x;
295      if(*y<this->ymin) this->ymin=*y;
296      if(*y>this->ymax) this->ymax=*y;
297      if(*z<this->zmin) this->zmin=*z;
298      if(*z>this->zmax) this->zmax=*z;
299      if(*f>this->peakFlux) this->peakFlux=*f;
300    }
301    delete x,y,z,f;
302  }
303  this->xcentre /= this->pix.size();
304  this->ycentre /= this->pix.size();
305  this->zcentre /= this->pix.size();
306   
307  delete ctr;
308  delete ctr2;
309  delete isNewPix;
310}
311*/
312
313void Detection::addOffsets(Param &par)
314{
315  this->xSubOffset = par.getXOffset();
316  this->ySubOffset = par.getYOffset();
317  this->zSubOffset = par.getZOffset();
318}
319
320bool Detection::hasEnoughChannels(int minNumber)
321{
322  /**
323   *  bool hasEnoughChannels(int)
324   *    A function to determine if the Detection has enough
325   *    contiguous channels to meet the minimum requirement
326   *    given as the argument.
327   *    Needs to have at least one occurence of minNumber consecutive
328   *    channels present to return true. Otherwise returns false.
329   */
330
331  // Original requirement -- based on total span
332// int numChannels = this->getZmax() - this->getZmin() + 1;
333
334// Alternative -- number of distinct channels detected
335//   int numChannels = 0;
336//   this->SortByZ();
337//   if(this->getSize()>0) numChannels++;
338//   for(int i=1;i<this->getSize();i++)
339//     if(this->getZ(i)>this->getZ(i-1)) numChannels++; 
340//   return (numChannels < minNumber);
341
342// Preferred method -- need a set of minNumber consecutive channels present.
343  this->SortByZ();
344  int numChannels = 0;
345  bool result = false;
346  if(this->getSize()>0) numChannels++;
347  for(int i=1;i<this->getSize();i++) {
348    if( (this->getZ(i) - this->getZ(i-1)) == 1) numChannels++;
349    else if( (this->getZ(i) - this->getZ(i-1)) >= 2) numChannels = 1;
350
351    if( numChannels == minNumber) result = true;
352  }
353  return result;
354 
355}
356
357int Detection::getSpatialSize()
358{
359  /**
360   *  int getSpatialSize()
361   *    A function that returns the number of distinct spatial
362   *     pixels in a Detection.
363   */
364
365  vector<Pixel> spatialPix;
366  Pixel newpix;
367  bool addThisOne;
368  newpix.setXY(this->getX(0),this->getY(0));
369  spatialPix.push_back(newpix);
370  for(int i=1;i<this->pix.size();i++){
371    newpix.setXY(this->getX(i),this->getY(i));
372    addThisOne = true;
373    for(int j=0;(j<spatialPix.size())&&addThisOne;j++) {
374      // do whole list or until addThisOne=false
375      addThisOne = ( (newpix.getX()!=spatialPix[j].getX()) ||
376                     (newpix.getY()!=spatialPix[j].getY())   );
377      // ie. if one of X or Y is different, addThisOne is true.
378    }
379    if(addThisOne) spatialPix.push_back(newpix);
380  }
381  return spatialPix.size();
382}
383
384std::ostream& operator<< ( std::ostream& theStream, Detection& obj)
385{
386  /**
387   * << operator for Detection class
388   *  A convenient way of printing the coordinate & flux
389   *  values for each pixel in the Detection
390   */ 
391
392  for(int i=0;i<obj.pix.size();i++) theStream << obj.pix[i] << endl;
393  theStream<<"---"<<endl;
394}
395
396Detection combineObjects(Detection &first, Detection &second)
397{
398  // make the new object
399  int *ctr = new int;
400  Detection *newObject = new Detection;
401  for(*ctr=0;(*ctr)<first.getSize();(*ctr)++){
402    newObject->addPixel(first.getPixel(*ctr));
403  }
404  for(*ctr=0;(*ctr)<second.getSize();(*ctr)++){
405    newObject->addPixel(second.getPixel(*ctr));
406  }
407  delete ctr;
408  newObject->calcParams();
409  return *newObject;
410}
411
412vector <Detection> combineLists(vector <Detection> &first, vector <Detection> &second)
413{
414  // make the new object
415  vector <Detection> newList(first.size()+second.size());
416  for(int i=0;i<first.size();i++) newList[i] = first[i];
417  for(int i=0;i<second.size();i++) newList[i+first.size()] = second[i];
418 
419  return newList;
420}
421
Note: See TracBrowser for help on using the repository browser.