source: tags/release-1.0.7/src/Detection/detection.cc

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

Changes here mostly aimed at reducing/removing memory leaks. These were one of:

  • Forgetting to delete something allocated with "new". The Cube destructor has improved with the use of bool variables to keep track of when recon & baseline ahave been allocated.
  • Incorrectly using the wcs->flag parameter (eg. wcsIO had it set to -1 *after* calling wcsini)
  • Not closing a fits file once finished with (dataIO)
  • Allocating the wcsprm structs with calloc before calling wcsini, so that wcsvfree can work (it calls "free", so the memory needs to be allocated with calloc or malloc).

The only other change was the following:

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