source: tags/release-1.0.2/src/Cubes/cubes.cc @ 1455

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

Some bugfixes, and improved image/spectrum extraction routines:
Corrected bug that meant blank pixels weren't being seen by the
drawMomentMap function. Improved the blankpixel testing in that
function, and changed getImage so that the blank pixel info is
always stored (if it is in the fits header).
Added new functions to Image class that can read a spectrum or
channel map given a cube and a channel/pixel number.
Other minor corrections as well:
src/Utils/cpgcumul.c -- changed way _swap is declared (pointers
rather than references, which don't work in C)
src/Cubes/cubes.cc -- new extraction functions
src/Cubes/cubes.hh -- prototypes thereof
src/Cubes/drawMomentCutout.cc -- improved blank pixel handling
src/Cubes/getImage.cc -- made sure blank pixel info is always
read in.
src/param.cc -- tidied up code slightly.
src/Detection/thresholding_functions.cc -- corrected setupFDR
to remove potential for accessing outside allocated memory.

File size: 18.1 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 *, long *, 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::extractSpectrum(Cube &cube, long pixel)
167{
168  /**
169   * Image::extractSpectrum(Cube &, int)
170   *  A function to extract a 1-D spectrum from a Cube class
171   *  The spectrum extracted is the one lying in the spatial pixel referenced
172   *    by the second argument.
173   */
174  long zdim = cube.getDimZ();
175  long spatSize = cube.getDimX()*cube.getDimY();
176  float *spec = new float[zdim];
177  for(int z=0;z<zdim;z++) spec[z] = cube.getPixValue(z*spatSize + pixel);
178  this->saveArray(spec,zdim);
179  delete [] spec;
180}
181
182void Image::extractImage(float *Array, long *dim, long channel)
183{
184  /**
185   * Image::extractImage(float *, long *, int)
186   *  A function to extract a 2-D image from a 3-D array.
187   *  The array is assumed to be 3-D with the third dimension the spectral one.
188   *  The dimensions of the array are in the dim[] array.
189   *  The image extracted is the one lying in the channel referenced
190   *    by the third argument.
191   */
192  float *image = new float[dim[0]*dim[1]];
193  for(int npix=0; npix<dim[0]*dim[1]; npix++){
194    image[npix] = Array[channel*dim[0]*dim[1] + npix];
195  }
196  this->saveArray(image,dim[0]*dim[1]);
197  delete [] image;
198}
199
200void Image::extractImage(Cube &cube, long channel)
201{
202  /**
203   * Image::extractImage(Cube &, int)
204   *  A function to extract a 2-D image from Cube class.
205   *  The image extracted is the one lying in the channel referenced
206   *    by the second argument.
207   */
208  long spatSize = cube.getDimX()*cube.getDimY();
209  float *image = new float[spatSize];
210  for(int npix=0; npix<spatSize; npix++)
211    image[npix] = cube.getPixValue(channel*spatSize + npix);
212  this->saveArray(image,spatSize);
213  delete [] image;
214}
215
216void Image::removeMW()
217{
218  /**
219   * Image::removeMW()
220   *  A function to remove the Milky Way range of channels from a 1-D spectrum.
221   *  The array in this Image is assumed to be 1-D, with only the first axisDim
222   *    equal to 1.
223   *  The values of the MW channels are set to 0, unless they are BLANK.
224   */
225  int maxMW = this->par.getMaxMW();
226  int minMW = this->par.getMinMW();
227  if(this->par.getFlagMW() && (this->axisDim[1]==1)){
228    for(int z=0;z<this->axisDim[0];z++){
229      if(!this->isBlank(z) && this->par.isInMW(z)) this->array[z]=0.;
230    }
231  }
232}
233
234void Image::findStats(int code)
235{
236  /**
237   *  Image::findStats(int code)
238   *    Front-end to function to find the stats (mean/median & sigma/madfm) and
239   *     store them in the "mean" and "sigma" members of Image.
240   *    The choice of normal(mean & sigma) or robust (median & madfm) is made via the
241   *      code parameter. This is stored as a decimal number, with 0s representing
242   *      normal stats, and 1s representing robust.
243   *      The 10s column is the mean, the 1s column the sigma.
244   *      Eg: 00 -- mean&sigma; 01 -- mean&madfm; 10 -- median&sigma; 11 -- median&madfm
245   *    If calculated, the madfm value is corrected to sigma units.
246   *    The Image member "cut" is also assigned using the parameter in Image's par
247   *      (needs to be defined first -- also for the blank pixel determination).
248   */
249  float *tempArray = new float[this->numPixels];
250  int goodSize=0;
251  for(int i=0; i<this->numPixels; i++)
252    if(!this->isBlank(i)) tempArray[goodSize++] = this->array[i];
253  float tempMean,tempSigma,tempMedian,tempMADFM;
254  if(code != 0) findMedianStats(tempArray,goodSize,tempMedian,tempMADFM);
255  if(code != 11) findNormalStats(tempArray,goodSize,tempMean,tempSigma);
256  switch(code)
257    {
258    case 0:
259      findNormalStats(tempArray,goodSize,tempMean,tempSigma);
260      this->mean = tempMean;
261      this->sigma = tempSigma;
262      break;
263    case 10:
264      this->mean  = findMedian(tempArray,goodSize);;
265      this->sigma = findStddev(tempArray,goodSize);
266      break;
267    case 1:
268      this->mean  = findMean(tempArray,goodSize);
269      this->sigma = findMADFM(tempArray,goodSize)/correctionFactor;
270      break;
271    case 11:
272    default:
273      if(code!=11) std::cerr <<
274                     "Invalid code ("<<code<<") in findStats. Using robust method.\n";
275      findMedianStats(tempArray,goodSize,tempMedian,tempMADFM);
276      this->mean = tempMedian;
277      this->sigma = tempMADFM/correctionFactor;
278      break;
279    }
280  this->cutLevel = this->par.getCut();
281  delete [] tempArray;
282}
283
284/****************************************************************/
285/////////////////////////////////////////////////////////////
286//// Functions for Cube class
287/////////////////////////////////////////////////////////////
288
289Cube::Cube(long size){
290  // need error handling in case size<0 !!!
291  if(size>0){
292    this->array = new float[size];
293    this->recon = new float[size];
294  }
295  this->numPixels = size;
296  this->axisDim = new long[2];
297  this->numDim = 3;
298  this->reconExists = false;
299//   flagWCS = false;
300}
301
302Cube::Cube(long *dimensions){
303  int size   = dimensions[0] * dimensions[1] * dimensions[2];
304  int imsize = dimensions[0] * dimensions[1];
305  this->numPixels = size;
306  if(size>0){
307    this->array      = new float[size];
308    this->detectMap  = new short[imsize];
309    if(this->par.getFlagATrous())
310      this->recon    = new float[size];
311    if(this->par.getFlagBaseline())
312      this->baseline = new float[size];
313  }
314  this->numDim  = 3;
315  this->axisDim = new long[3];
316  for(int i=0;i<3     ;i++) this->axisDim[i]   = dimensions[i];
317  for(int i=0;i<imsize;i++) this->detectMap[i] = 0;
318//   this->wcs = new wcsprm;
319//   this->wcs->flag=-1;
320//   wcsini(true,3,this->wcs);
321//   flagWCS = false;
322}
323
324void Cube::initialiseCube(long *dimensions){
325  int size   = dimensions[0] * dimensions[1] * dimensions[2];
326  int imsize = dimensions[0] * dimensions[1];
327  this->numPixels = size;
328  if(size>0){
329    this->array      = new float[size];
330    this->detectMap  = new short[imsize];
331    this->specMean   = new float[imsize];
332    this->specSigma  = new float[imsize];
333    this->chanMean   = new float[dimensions[2]];
334    this->chanSigma  = new float[dimensions[2]];
335    if(this->par.getFlagATrous())
336      this->recon    = new float[size];
337    if(this->par.getFlagBaseline())
338      this->baseline = new float[size];
339  }
340  this->numDim  = 3;
341  this->axisDim = new long[3];
342  for(int i=0;i<3     ;i++) this->axisDim[i]   = dimensions[i];
343  for(int i=0;i<imsize;i++) this->detectMap[i] = 0;
344//   this->wcs = new wcsprm;
345//   this->wcs->flag=-1;
346//   wcsini(true,3,this->wcs);
347}
348
349void Cube::saveArray(float *input, long size){
350  // Need check for change in number of pixels!
351  if(this->numPixels>0) delete [] array;
352  this->numPixels = size;
353  this->array = new float[size];
354  for(int i=0;i<size;i++) this->array[i] = input[i];
355}
356
357void Cube::saveRecon(float *input, long size){
358  // Need check for change in number of pixels!
359  if(this->numPixels>0) delete [] this->recon;
360  this->numPixels = size;
361  this->recon = new float[size];
362  for(int i=0;i<size;i++) this->recon[i] = input[i];
363  this->reconExists = true;
364}
365
366void Cube::getRecon(float *output){
367  // Need check for change in number of pixels!
368  long size = this->numPixels;
369  for(int i=0;i<size;i++){
370    if(this->reconExists) output[i] = this->recon[i];
371    else output[i] = 0.;
372  }
373}
374
375void Cube::removeMW()
376{
377  if(this->par.getFlagMW()){
378    for(int pix=0;pix<this->axisDim[0]*this->axisDim[1];pix++){
379      for(int z=0;z<this->axisDim[2];z++){
380        int pos = z*this->axisDim[0]*this->axisDim[1] + pix;
381        if(!this->isBlank(pos) && this->par.isInMW(z)) this->array[pos]=0.;
382      }
383    }
384  }
385}
386
387////////// WCS-related functions
388
389// void Cube::setWCS(wcsprm *w)
390// {
391//   /**
392//    * Cube::setWCS(wcsprm *)
393//    *  A function that assigns the cube's wcs parameters, and runs
394//    *   wcsset to set it up correctly.
395//    *  Performs a check to see if the WCS is good (by looking at
396//    *   the lng and lat wcsprm parameters), and sets the flagWCS accordingly.
397//    */
398
399//   wcscopy(true,w,this->wcs);
400//   wcsset(this->wcs);
401//   if( (w->lng!=-1) && (w->lat!=-1) ) this->flagWCS = true;
402// }
403
404// wcsprm *Cube::getWCS()
405// {
406//   /**
407//    * Cube::getWCS()
408//    *  A function that returns a wcsprm object corresponding to the cube's WCS.
409//    */
410
411//   wcsprm *wNew = new wcsprm;
412//   wNew->flag=-1;
413//   wcsini(true,this->wcs->naxis,wNew);
414//   wcscopy(true,this->wcs,wNew);
415//   return wNew;
416// }
417
418void Cube::calcObjectWCSparams()
419{
420  /**
421   * Cube::calcObjectWCSparams()
422   *  A function that calculates the WCS parameters for each object in the
423   *  cube's list of detections.
424   *  Each object gets an ID number set (just the order in the list), and if the
425   *   WCS is good, the WCS paramters are calculated.
426   */
427 
428  for(int i=0; i<this->objectList.size();i++){
429    this->objectList[i].setID(i+1);
430//     if(this->flagWCS) this->objectList[i].calcWCSparams(this->wcs);
431    this->objectList[i].calcWCSparams(this->head);
432    //    this->objectList[i].setIntegFlux( this->objectList[i].getIntegFlux()/this->par.getBeamSize() );
433    // this corrects the integrated flux for the beam size.
434  } 
435
436 
437}
438
439void Cube::sortDetections()
440{
441  /**
442   * Cube::sortDetections()
443   *  A front end to the sort-by functions.
444   *  If there is a good WCS, the detection list is sorted by velocity.
445   *  Otherwise, it is sorted by increasing z-pixel value.
446   *  The ID numbers are then re-calculated.
447   */
448 
449  if(this->head.isWCS()) SortByVel(this->objectList);
450  else SortByZ(this->objectList);
451  for(int i=0; i<this->objectList.size();i++) this->objectList[i].setID(i+1);
452
453}
454
455void Cube::updateDetectMap()
456{
457  /**
458   * Cube::updateDetectMap()
459   *  A function that, for each detected object in the cube's list, increments the
460   *  cube's detection map by the required amount at each pixel.
461   */
462
463  for(int obj=0;obj<this->objectList.size();obj++)
464    for(int pix=0;pix<this->objectList[obj].getSize();pix++)
465      this->detectMap[this->objectList[obj].getX(pix)+this->objectList[obj].getY(pix)*this->axisDim[0]]++;
466}
467
468void Cube::updateDetectMap(Detection obj)
469{
470  /**
471   * Cube::updateDetectMap(Detection)
472   *  A function that, for the given object, increments the cube's
473   *  detection map by the required amount at each pixel.
474   */
475  for(int pix=0;pix<obj.getSize();pix++)
476    this->detectMap[obj.getX(pix)+obj.getY(pix)*this->axisDim[0]]++;
477}
478
479void Cube::setCubeStats()
480{
481  // First set the stats for each spectrum (ie. each spatial pixel)
482  long xySize = this->axisDim[0]*this->axisDim[1];
483  float *spec = new float[this->axisDim[2]];
484  for(int i=0;i<xySize;i++){
485    for(int z=0;z<this->axisDim[2];z++){
486      //Two cases: i) have reconstructed -- use residuals
487      //          ii) otherwise          -- use original array
488      if(this->reconExists) spec[z] = this->array[z*xySize+i] - this->recon[z*xySize+1];
489      else                  spec[z] = this->array[z*xySize+i];
490    }
491    findMedianStats(spec,this->axisDim[2],this->specMean[i],this->specSigma[i]);
492  }
493  delete spec;
494  // Then set the stats for each channel map
495  float *im = new float[xySize];
496  for(int z=0;z<this->axisDim[2];z++){
497    for(int i=0;i<xySize;i++){
498      if(this->reconExists) im[i] = this->array[z*xySize+i] - this->recon[z*xySize+1];
499      else                  im[i] = this->array[z*xySize+i];
500     
501    }
502    findMedianStats(im,this->axisDim[2],this->chanMean[z],this->chanSigma[z]);
503    this->chanSigma[z] /= correctionFactor;
504  }
505  delete im;
506
507}
508
509float Cube::enclosedFlux(Detection obj)
510{
511  /**
512   *  float Cube::enclosedFlux(Detection obj)
513   *   A function to calculate the flux enclosed by the range
514   *    of pixels detected in the object obj (not necessarily all
515   *    pixels will have been detected).
516   */
517  obj.calcParams();
518  int xsize = obj.getXmax()-obj.getXmin()+1;
519  int ysize = obj.getYmax()-obj.getYmin()+1;
520  int zsize = obj.getZmax()-obj.getZmin()+1;
521  vector <float> fluxArray(xsize*ysize*zsize,0.);
522  for(int x=0;x<xsize;x++){
523    for(int y=0;y<ysize;y++){
524      for(int z=0;z<zsize;z++){
525        fluxArray[x+y*xsize+z*ysize*xsize] =
526          this->getPixValue(x+obj.getXmin(),y+obj.getYmin(),z+obj.getZmin());
527        if(this->par.getFlagNegative()) fluxArray[x+y*xsize+z*ysize*xsize] *= -1.;
528      }
529    }
530  }
531  float sum = 0.;
532  for(int i=0;i<fluxArray.size();i++)
533    if(!this->par.isBlank(fluxArray[i])) sum+=fluxArray[i];
534  return sum;
535}
536
537bool Cube::objAtEdge(Detection obj)
538{
539  /**
540   *  bool Cube::objAtEdge()
541   *   A function to test whether the object obj
542   *    lies at the edge of the cube's field --
543   *    either at the boundary, or next to BLANKs
544   */
545
546  bool atEdge = false;
547
548  int pix = 0;
549  while(!atEdge && pix<obj.getSize()){
550    // loop over each pixel in the object, until we find an edge pixel.
551    Voxel vox = obj.getPixel(pix);
552    for(int dx=-1;dx<=1;dx+=2){
553      if(((vox.getX()+dx)<0) || ((vox.getX()+dx)>=this->axisDim[0])) atEdge = true;
554      else if(this->isBlank(vox.getX()+dx,vox.getY(),vox.getZ())) atEdge = true;
555    }
556    for(int dy=-1;dy<=1;dy+=2){
557      if(((vox.getY()+dy)<0) || ((vox.getY()+dy)>=this->axisDim[1])) atEdge = true;
558      else if(this->isBlank(vox.getX(),vox.getY()+dy,vox.getZ())) atEdge = true;
559    }
560    for(int dz=-1;dz<=1;dz+=2){
561      if(((vox.getZ()+dz)<0) || ((vox.getZ()+dz)>=this->axisDim[2])) atEdge = true;
562      else if(this->isBlank(vox.getX(),vox.getY(),vox.getZ()+dz)) atEdge = true;
563    }
564    pix++;
565  }
566
567  return atEdge;
568}
569
570void Cube::setObjectFlags()
571{
572  /**
573   *  void Cube::setObjectFlags()
574   *   A function to set any warning flags for all the detected objects
575   *    associated with the cube.
576   *   Flags to be looked for:
577   *       * Negative enclosed flux (N)
578   *       * Object at edge of field (E)
579   */
580
581  for(int i=0;i<this->objectList.size();i++){
582
583    if( this->enclosedFlux(this->objectList[i]) < 0. ) 
584      this->objectList[i].addToFlagText("N");
585
586    if( this->objAtEdge(this->objectList[i]) )
587      this->objectList[i].addToFlagText("E");
588
589  }
590
591}
Note: See TracBrowser for help on using the repository browser.