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

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

Large commit, mostly removing dud commented code, and adding comments and
documentation to the existing code. No new features.

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