source: tags/release-0.9.2/Cubes/cubes.cc @ 1323

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

Added code to produce warning flags for detections: for either edge location
or negative enclosed flux. Summary of changes:
Cubes/cubes.cc -- three new routines
Cubes/cubes.hh -- prototypes for new routines. New isBlank functions.
Detection/outputDetection.cc -- output of warning flags.
mainDuchamp.cc -- calling of new routines. Other minor changes.
docs/Guide.tex -- explanation of new warning flags. Other minor changes.
docs/example_spectrum.pdf -- shows the new formatting.
docs/example_spectrum.ps -- ditto
InputComplete? -- all values are now the same as the default param values

File size: 16.5 KB
Line 
1#include <iostream>
2#include <iomanip>
3#include <vector>
4#include <string>
5#include <wcs.h>
6#include <Cubes/cubes.hh>
7#include <Utils/utils.hh>
8using std::endl;
9
10/****************************************************************/
11///////////////////////////////////////////////////
12//// Functions for DataArray class:
13///////////////////////////////////////////////////
14
15DataArray::DataArray(short int nDim, long size){
16  // need error handling in case size<0 !!!
17  if(size>0) this->array = new float[size];
18  this->numPixels = size;
19  if(nDim>0) this->axisDim = new long[nDim];
20  this->numDim = nDim;
21}
22
23DataArray::DataArray(short int nDim, long *dimensions){
24  int size = dimensions[0];
25  for(int i=1;i<nDim;i++) size *= dimensions[i];
26  this->numPixels = size;
27  if(size>0){
28    this->array = new float[size];
29  }
30  this->numDim=nDim;
31  if(nDim>0) this->axisDim = new long[nDim];
32  for(int i=0;i<nDim;i++) this->axisDim[i] = dimensions[i];
33}
34
35void DataArray::getDimArray(long *output){
36  for(int i=0;i<this->numDim;i++) output[i] = this->axisDim[i];
37}
38
39void DataArray::getArray(float *output){
40  for(int i=0;i<this->numPixels;i++) output[i] = this->array[i];
41}
42
43void DataArray::saveArray(float *input, long size){
44  delete [] this->array;
45  // Need check for change in number of pixels!
46  this->numPixels = size;
47  this->array = new float[size];
48  for(int i=0;i<size;i++) this->array[i] = input[i];
49}
50
51void DataArray::getDim(long &x, long &y, long &z){
52  if(numDim>0) x=axisDim[0];
53  else x=0;
54  if(numDim>1) y=axisDim[1];
55  else y=0;
56  if(numDim>2) z=axisDim[2];
57  else z=0;
58}
59
60void DataArray::addObject(Detection object){
61  // adds a single detection to the object list
62  // objectList is a vector, so just use push_back()
63  this->objectList.push_back(object);
64}
65
66void DataArray::addObjectList(vector <Detection> newlist) {
67  for(int i=0;i<newlist.size();i++) this->objectList.push_back(newlist[i]);
68}
69
70std::ostream& operator<< ( std::ostream& theStream, DataArray &array){
71
72  for(int i=0;i<array.numDim;i++){
73    if(i>0) theStream<<"x";
74    theStream<<array.axisDim[i];
75  }
76  theStream<<endl;
77  theStream<<array.objectList.size()<<" detections:"<<endl<<"--------------\n";
78  for(int i=0;i<array.objectList.size();i++){
79    theStream << "Detection #" << array.objectList[i].getID()<<endl;
80    Detection *obj = new Detection;
81    *obj = array.objectList[i];
82    for(int j=0;j<obj->getSize();j++){
83      obj->setX(j,obj->getX(j)+obj->getXOffset());
84      obj->setY(j,obj->getY(j)+obj->getYOffset());
85      obj->setZ(j,obj->getZ(j)+obj->getZOffset());
86    }
87    theStream<<*obj;
88    delete obj;
89  }
90  theStream<<"--------------\n";
91}
92
93/****************************************************************/
94/////////////////////////////////////////////////////////////
95//// Functions for Image class
96/////////////////////////////////////////////////////////////
97
98Image::Image(long size){
99  // need error handling in case size<0 !!!
100  if(size>0){
101    this->array = new float[size];
102    this->pValue = new float[size];
103    this->mask = new short int[size];
104  }
105  this->numPixels = size;
106  this->axisDim = new long[2];
107  this->numDim = 2;
108}
109
110Image::Image(long *dimensions){
111  int size = dimensions[0] * dimensions[1];
112  this->numPixels = size;
113  if(size>0){
114    this->array = new float[size];
115    this->pValue = new float[size];
116    this->mask = new short int[size];
117  }
118  this->numDim=2;
119  this->axisDim = new long[2];
120  for(int i=0;i<2;i++) this->axisDim[i] = dimensions[i];
121  for(int i=0;i<size;i++) this->mask[i] = 0;
122}
123
124void Image::saveArray(float *input, long size){
125  // Need check for change in number of pixels!
126  if(this->numPixels>0){
127    delete [] array;
128    delete [] pValue;
129    delete [] mask;
130  }
131  this->numPixels = size;
132  this->array = new float[size];
133  this->pValue = new float[size];
134  this->mask = new short int[size];
135  for(int i=0;i<size;i++) this->array[i] = input[i];
136  for(int i=0;i<size;i++) this->mask[i] = 0;
137}
138
139void Image::maskObject(Detection &object)
140{
141  /**
142   * Image::maskObject(Detection &)
143   *  A function that increments the mask for each pixel of the detection.
144   */
145  for(long i=0;i<object.getSize();i++){
146    this->setMaskValue(object.getX(i),object.getY(i),1);
147  }
148}
149
150void Image::extractSpectrum(float *Array, long *dim, long pixel)
151{
152  /**
153   * Image::extractSpectrum(float *, int)
154   *  A function to extract a 1-D spectrum from a 3-D array.
155   *  The array is assumed to be 3-D with the third dimension the spectral one.
156   *  The dimensions of the array are in the dim[] array.
157   *  The spectrum extracted is the one lying in the spatial pixel referenced
158   *    by the third argument.
159   */
160  float *spec = new float[dim[2]];
161  for(int z=0;z<dim[2];z++) spec[z] = Array[z*dim[0]*dim[1] + pixel];
162  this->saveArray(spec,dim[2]);
163  delete [] spec;
164}
165
166void Image::extractImage(float *Array, long *dim, long channel)
167{
168  /**
169   * Image::extractImage(float *, int)
170   *  A function to extract a 2-D image from a 3-D array.
171   *  The array is assumed to be 3-D with the third dimension the spectral one.
172   *  The dimensions of the array are in the dim[] array.
173   *  The image extracted is the one lying in the channel referenced
174   *    by the third argument.
175   */
176  float *image = new float[dim[0]*dim[1]];
177  for(int npix=0; npix<dim[0]*dim[1]; npix++){
178    image[npix] = Array[channel*dim[0]*dim[1] + npix];
179  }
180  this->saveArray(image,dim[0]*dim[1]);
181  delete [] image;
182}
183
184void Image::findStats(int code)
185{
186  /**
187   *  Image::findStats(int code)
188   *    Front-end to function to find the stats (mean/median & sigma/madfm) and
189   *     store them in the "mean" and "sigma" members of Image.
190   *    The choice of normal(mean & sigma) or robust (median & madfm) is made via the
191   *      code parameter. This is stored as a decimal number, with 0s representing
192   *      normal stats, and 1s representing robust.
193   *      The 10s column is the mean, the 1s column the sigma.
194   *      Eg: 00 -- mean&sigma; 01 -- mean&madfm; 10 -- median&sigma; 11 -- median&madfm
195   *    If calculated, the madfm value is corrected to sigma units.
196   *    The Image member "cut" is also assigned using the parameter in Image's par
197   *      (needs to be defined first -- also for the blank pixel determination).
198   */
199  float *tempArray = new float[this->numPixels];
200  int goodSize=0;
201  for(int i=0; i<this->numPixels; i++)
202    if(!this->isBlank(i)) tempArray[goodSize++] = this->array[i];
203  float tempMean,tempSigma,tempMedian,tempMADFM;
204  if(code != 0) findMedianStats(tempArray,goodSize,tempMedian,tempMADFM);
205  if(code != 11) findNormalStats(tempArray,goodSize,tempMean,tempSigma);
206  switch(code)
207    {
208    case 0:
209      findNormalStats(tempArray,goodSize,tempMean,tempSigma);
210      this->mean = tempMean;
211      this->sigma = tempSigma;
212      break;
213    case 10:
214      this->mean  = findMedian(tempArray,goodSize);;
215      this->sigma = findStddev(tempArray,goodSize);
216      break;
217    case 1:
218      this->mean  = findMean(tempArray,goodSize);
219      this->sigma = findMADFM(tempArray,goodSize)/correctionFactor;
220      break;
221    case 11:
222    default:
223      if(code!=11) std::cerr <<
224                     "Invalid code ("<<code<<") in findStats. Using robust method.\n";
225      findMedianStats(tempArray,goodSize,tempMedian,tempMADFM);
226      this->mean = tempMedian;
227      this->sigma = tempMADFM/correctionFactor;
228      break;
229    }
230  this->cutLevel = this->par.getCut();
231  delete [] tempArray;
232}
233
234/****************************************************************/
235/////////////////////////////////////////////////////////////
236//// Functions for Cube class
237/////////////////////////////////////////////////////////////
238
239Cube::Cube(long size){
240  // need error handling in case size<0 !!!
241  if(size>0){
242    this->array = new float[size];
243    this->recon = new float[size];
244  }
245  this->numPixels = size;
246  this->axisDim = new long[2];
247  this->numDim = 3;
248  this->reconExists = false;
249  flagWCS = false;
250}
251
252Cube::Cube(long *dimensions){
253  int size   = dimensions[0] * dimensions[1] * dimensions[2];
254  int imsize = dimensions[0] * dimensions[1];
255  this->numPixels = size;
256  if(size>0){
257    this->array      = new float[size];
258    this->detectMap  = new short[imsize];
259    if(this->par.getFlagATrous())
260      this->recon    = new float[size];
261    if(this->par.getFlagBaseline())
262      this->baseline = new float[size];
263  }
264  this->numDim  = 3;
265  this->axisDim = new long[3];
266  for(int i=0;i<3     ;i++) this->axisDim[i]   = dimensions[i];
267  for(int i=0;i<imsize;i++) this->detectMap[i] = 0;
268  this->wcs = new wcsprm;
269  this->wcs->flag=-1;
270  wcsini(true,3,this->wcs);
271  flagWCS = false;
272}
273
274void Cube::initialiseCube(long *dimensions){
275  int size   = dimensions[0] * dimensions[1] * dimensions[2];
276  int imsize = dimensions[0] * dimensions[1];
277  this->numPixels = size;
278  if(size>0){
279    this->array      = new float[size];
280    this->detectMap  = new short[imsize];
281    this->specMean   = new float[imsize];
282    this->specSigma  = new float[imsize];
283    this->chanMean   = new float[dimensions[2]];
284    this->chanSigma  = new float[dimensions[2]];
285    if(this->par.getFlagATrous())
286      this->recon    = new float[size];
287    if(this->par.getFlagBaseline())
288      this->baseline = new float[size];
289  }
290  this->numDim  = 3;
291  this->axisDim = new long[3];
292  for(int i=0;i<3     ;i++) this->axisDim[i]   = dimensions[i];
293  for(int i=0;i<imsize;i++) this->detectMap[i] = 0;
294  this->wcs = new wcsprm;
295  this->wcs->flag=-1;
296  wcsini(true,3,this->wcs);
297}
298
299void Cube::saveArray(float *input, long size){
300  // Need check for change in number of pixels!
301  if(this->numPixels>0) delete [] array;
302  this->numPixels = size;
303  this->array = new float[size];
304  for(int i=0;i<size;i++) this->array[i] = input[i];
305}
306
307void Cube::saveRecon(float *input, long size){
308  // Need check for change in number of pixels!
309  if(this->numPixels>0) delete [] this->recon;
310  this->numPixels = size;
311  this->recon = new float[size];
312  for(int i=0;i<size;i++) this->recon[i] = input[i];
313  this->reconExists = true;
314}
315
316void Cube::getRecon(float *output){
317  // Need check for change in number of pixels!
318  long size = this->numPixels;
319  for(int i=0;i<size;i++){
320    if(this->reconExists) output[i] = this->recon[i];
321    else output[i] = 0.;
322  }
323}
324
325void Cube::removeMW()
326{
327  int maxMW = this->par.getMaxMW();
328  int minMW = this->par.getMinMW();
329  bool flagBlank = this->par.getFlagBlankPix();
330  bool flagMW = this->par.getFlagMW();
331  float nPV = this->par.getBlankPixVal();
332  long xdim=axisDim[0], ydim=axisDim[1], zdim=axisDim[2];
333  for(int pix=0;pix<xdim*ydim;pix++){
334    for(int z=0;z<zdim;z++){
335      int pos = z*xdim*ydim + pix;
336      bool isMW = flagMW && (z>=minMW) && (z<=maxMW);
337      if(!(this->par.isBlank(this->array[pos])) && isMW) this->array[pos]=0.;
338    }
339  }
340}
341
342////////// WCS-related functions
343
344void Cube::setWCS(wcsprm *w)
345{
346  /**
347   * Cube::setWCS(wcsprm *)
348   *  A function that assigns the cube's wcs parameters, and runs
349   *   wcsset to set it up correctly.
350   *  Performs a check to see if the WCS is good (by looking at
351   *   the lng and lat wcsprm parameters), and sets the flagWCS accordingly.
352   */
353
354  wcscopy(true,w,this->wcs);
355  wcsset(this->wcs);
356  if( (w->lng!=-1) && (w->lat!=-1) ) this->flagWCS = true;
357}
358
359wcsprm *Cube::getWCS()
360{
361  /**
362   * Cube::getWCS()
363   *  A function that returns a wcsprm object corresponding to the cube's WCS.
364   */
365
366  wcsprm *wNew = new wcsprm;
367  wNew->flag=-1;
368  wcsini(true,this->wcs->naxis,wNew);
369  wcscopy(true,this->wcs,wNew);
370  return wNew;
371}
372
373void Cube::calcObjectWCSparams()
374{
375  /**
376   * Cube::calcObjectWCSparams()
377   *  A function that calculates the WCS parameters for each object in the
378   *  cube's list of detections.
379   *  Each object gets an ID number set (just the order in the list), and if the
380   *   WCS is good, the WCS paramters are calculated.
381   */
382 
383  for(int i=0; i<this->objectList.size();i++){
384    this->objectList[i].setID(i+1);
385    if(this->flagWCS) this->objectList[i].calcWCSparams(this->wcs);
386    this->objectList[i].setIntegFlux( this->objectList[i].getIntegFlux()/this->par.getBeamSize() );
387    // this corrects the integrated flux for the beam size.
388  } 
389
390 
391}
392
393void Cube::sortDetections()
394{
395  /**
396   * Cube::sortDetections()
397   *  A front end to the sort-by functions.
398   *  If there is a good WCS, the detection list is sorted by velocity.
399   *  Otherwise, it is sorted by increasing z-pixel value.
400   *  The ID numbers are then re-calculated.
401   */
402 
403  if(this->flagWCS) SortByVel(this->objectList);
404  else SortByZ(this->objectList);
405  for(int i=0; i<this->objectList.size();i++) this->objectList[i].setID(i+1);
406
407}
408
409void Cube::updateDetectMap()
410{
411  /**
412   * Cube::updateDetectMap()
413   *  A function that, for each detected object in the cube's list, increments the
414   *  cube's detection map by the required amount at each pixel.
415   */
416
417  for(int obj=0;obj<this->objectList.size();obj++)
418    for(int pix=0;pix<this->objectList[obj].getSize();pix++)
419      this->detectMap[this->objectList[obj].getX(pix)+this->objectList[obj].getY(pix)*this->axisDim[0]]++;
420}
421
422void Cube::updateDetectMap(Detection obj)
423{
424  /**
425   * Cube::updateDetectMap(Detection)
426   *  A function that, for the given object, increments the cube's
427   *  detection map by the required amount at each pixel.
428   */
429  for(int pix=0;pix<obj.getSize();pix++)
430    this->detectMap[obj.getX(pix)+obj.getY(pix)*this->axisDim[0]]++;
431}
432
433void Cube::setCubeStats()
434{
435  // First set the stats for each spectrum (ie. each spatial pixel)
436  long xySize = this->axisDim[0]*this->axisDim[1];
437  float *spec = new float[this->axisDim[2]];
438  for(int i=0;i<xySize;i++){
439    for(int z=0;z<this->axisDim[2];z++){
440      //Two cases: i) have reconstructed -- use residuals
441      //          ii) otherwise          -- use original array
442      if(this->reconExists) spec[z] = this->array[z*xySize+i] - this->recon[z*xySize+1];
443      else                  spec[z] = this->array[z*xySize+i];
444    }
445    findMedianStats(spec,this->axisDim[2],this->specMean[i],this->specSigma[i]);
446  }
447  delete spec;
448  // Then set the stats for each channel map
449  float *im = new float[xySize];
450  for(int z=0;z<this->axisDim[2];z++){
451    for(int i=0;i<xySize;i++){
452      if(this->reconExists) im[i] = this->array[z*xySize+i] - this->recon[z*xySize+1];
453      else                  im[i] = this->array[z*xySize+i];
454     
455    }
456    findMedianStats(im,this->axisDim[2],this->chanMean[z],this->chanSigma[z]);
457    this->chanSigma[z] /= correctionFactor;
458  }
459  delete im;
460
461}
462
463float Cube::enclosedFlux(Detection obj)
464{
465  /**
466   *  float Cube::enclosedFlux(Detection obj)
467   *   A function to calculate the flux enclosed by the range
468   *    of pixels detected in the object obj (not necessarily all
469   *    pixels will have been detected).
470   */
471  obj.calcParams();
472  int xsize = obj.getXmax()-obj.getXmin()+1;
473  int ysize = obj.getYmax()-obj.getYmin()+1;
474  int zsize = obj.getZmax()-obj.getZmin()+1;
475  vector <float> fluxArray(xsize*ysize*zsize,0.);
476  for(int x=0;x<xsize;x++){
477    for(int y=0;y<ysize;y++){
478      for(int z=0;z<zsize;z++){
479        fluxArray[x+y*xsize+z*ysize*xsize] =
480          this->getPixValue(x+obj.getXmin(),y+obj.getYmin(),z+obj.getZmin());
481      }
482    }
483  }
484  float sum = 0.;
485  for(int i=0;i<fluxArray.size();i++)
486    if(!this->par.isBlank(fluxArray[i])) sum+=fluxArray[i];
487  return sum;
488}
489
490bool Cube::objAtEdge(Detection obj)
491{
492  /**
493   *  bool Cube::objAtEdge()
494   *   A function to test whether the object obj
495   *    lies at the edge of the cube's field --
496   *    either at the boundary, or next to BLANKs
497   */
498
499  bool atEdge = false;
500
501  int pix = 0;
502  while(!atEdge && pix<obj.getSize()){
503    // loop over each pixel in the object, until we find an edge pixel.
504    Voxel vox = obj.getPixel(pix);
505    for(int dx=-1;dx<=1;dx+=2){
506      if(((vox.getX()+dx)<0) || ((vox.getX()+dx)>this->axisDim[0])) atEdge = true;
507      else if(this->isBlank(vox.getX()+dx,vox.getY(),vox.getZ())) atEdge = true;
508    }
509    for(int dy=-1;dy<=1;dy+=2){
510      if(((vox.getY()+dy)<0) || ((vox.getY()+dy)>this->axisDim[1])) atEdge = true;
511      else if(this->isBlank(vox.getX(),vox.getY()+dy,vox.getZ())) atEdge = true;
512    }
513    for(int dz=-1;dz<=1;dz+=2){
514      if(((vox.getZ()+dz)<0) || ((vox.getZ()+dz)>this->axisDim[2])) atEdge = true;
515      else if(this->isBlank(vox.getX(),vox.getY(),vox.getZ()+dz)) atEdge = true;
516    }
517    pix++;
518  }
519
520  return atEdge;
521}
522
523void Cube::setObjectFlags()
524{
525  /**
526   *  void Cube::setObjectFlags()
527   *   A function to set any warning flags for all the detected objects
528   *    associated with the cube.
529   *   Flags to be looked for:
530   *       * Negative enclosed flux (N)
531   *       * Object at edge of field (E)
532   */
533
534  for(int i=0;i<this->objectList.size();i++){
535
536    if( this->enclosedFlux(this->objectList[i]) < 0. ) 
537      this->objectList[i].addToFlagText("N");
538
539    if( this->objAtEdge(this->objectList[i]) )
540      this->objectList[i].addToFlagText("E");
541
542  }
543
544}
Note: See TracBrowser for help on using the repository browser.