source: branches/fitshead-branch/Cubes/cubes.cc @ 1441

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

Four major sets of changes and a couple of minor ones:

  • Changed name of saved recon/resid FITS file, so that it incorporates all reconstruction parameters.
  • Removed MW parameters from header file
  • Added hashed box to be drawn over MW range in spectral plots
  • Fixed bug that meant reon would be done in 1- or 2-d even if recon array has been read in.

Summary:
param.hh -- prototypes for FITS file name calculation functions
param.cc -- FITS file name calculation functions
Cubes/plots.hh -- drawMWRange function
ATrous/ReconSearch.cc -- tests to see if reconExists for 1- and 2-D recon
Cubes/cubes.cc -- work out enclosed flux correctly for flagNegative
Cubes/detectionIO.cc -- added reconDim line to VOTable output
Cubes/outputSpectra.cc -- added code to draw MW range
Cubes/readRecon.cc -- added call to FITS file name function, and removed

MW params and superfluous tests on atrous parameters

Cubes/saveImage.cc -- improved logical flow. added call to FITS file name func

removed MW keywords.

Detection/columns.cc -- added extra column to fluxes if negative.

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