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

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

Some tidying up of code -- easier readability mostly.

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