source: branches/fitshead-branch/Detection/detection.cc @ 1441

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

Large collection of changes. Mostly minor fixes, but major additions are:

  • ability to store flagMW in the recon FITS file
  • slight change to way precision is dealt with in output files
  • improvement to VOTable output
  • generalisation of spectral plotting.

Summary of changes:
duchamp.hh -- added keywords/comments for storing flagMW in FITS files
Utils/wcsFunctions.cc -- minor correction
Cubes/plotting.cc -- minor corrections
Cubes/saveImage.cc -- writing flagMW as header keyword
Cubes/readRecon.cc -- able to read in flagMW. Improved formatting of comments
Cubes/detectionIO.cc -- made VOTable output able to cope with Column

definitions. Added new columns.

Cubes/cubes.hh -- added frontends to wcs-pix functions. Changed prototypes

of some plotting functions.

Cubes/plots.hh -- generalised some functionality of the classes
Cubes/drawMomentCutout.cc -- made a class function
Cubes/outputSpectra.cc -- made a Cube class function that plots a

single spectrum.

param.cc -- improved calling of local variables, and the way units are

dealt with.

docs/example_moment_map.pdf -- new version
docs/cover_image.ps -- new version
docs/example_spectrum.pdf -- new version
docs/cover_image.pdf -- new version
docs/example_moment_map.ps -- new version
docs/example_spectrum.ps -- new version
mainDuchamp.cc -- fixed order of some function calls. Other minor corrections.
ATrous/atrous_2d_reconstruct.cc -- improved speed of loop execution
ATrous/atrous_3d_reconstruct.cc -- improved speed of loop execution
Makefile -- addition of columns.cc
Detection/detection.cc -- minor corrections (removal of commented code)
Detection/outputDetection.cc -- minor change to output style and

precision variable name.

Detection/columns.cc -- use new precision variable
Detection/columns.hh -- new precision variables for position and position

width columns

param.hh -- added prototype for makelower(string) function.

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