source: tags/release-0.9/Detection/detection.cc @ 813

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

param.cc Made sure the velocity threshold is always

printed when parameters are outputted.

Detection/detection.cc Corrected determination of object name -- was

in the wrong place.

Detection/outputDetection.cc Added space so that F_peak is separated

from F_int.

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