source: tags/release-1.0.6/src/Cubes/cubes.cc @ 1441

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

Fixes related to negative searches:

  • Recon array is now inverted if read in from file rather than calculated.
  • Threshold reported is given the appropriate sign.
  • Label on the image brightness wedge is presented better.
File size: 28.5 KB
Line 
1#include <unistd.h>
2#include <iostream>
3#include <iomanip>
4#include <vector>
5#include <string>
6
7#include <wcs.h>
8
9#include <duchamp.hh>
10#include <param.hh>
11#include <Cubes/cubes.hh>
12#include <Detection/detection.hh>
13#include <Detection/columns.hh>
14#include <Utils/utils.hh>
15#include <Utils/mycpgplot.hh>
16#include <Utils/Statistics.hh>
17using std::endl;
18using namespace Column;
19using namespace mycpgplot;
20using namespace Statistics;
21
22/****************************************************************/
23///////////////////////////////////////////////////
24//// Functions for DataArray class:
25///////////////////////////////////////////////////
26
27DataArray::DataArray(short int nDim, long size){
28
29  if(size<0)
30    duchampError("DataArray(nDim,size)",
31                 "Negative size -- could not define DataArray");
32  else if(nDim<0)
33    duchampError("DataArray(nDim,size)",
34                 "Negative number of dimensions: could not define DataArray");
35  else {
36    if(size>0) this->array = new float[size];
37    this->numPixels = size;
38    if(nDim>0) this->axisDim = new long[nDim];
39    this->numDim = nDim;
40  }
41}
42//--------------------------------------------------------------------
43
44DataArray::DataArray(short int nDim, long *dimensions){
45  if(nDim<0)
46    duchampError("DataArray(nDim,dimArray)",
47                 "Negative number of dimensions: could not define DataArray");
48  else {
49    int size = dimensions[0];
50    for(int i=1;i<nDim;i++) size *= dimensions[i];
51    if(size<0)
52      duchampError("DataArray(nDim,dimArray)",
53                   "Negative size: could not define DataArray");
54    else{
55      this->numPixels = size;
56      if(size>0){
57        this->array = new float[size];
58      }
59      this->numDim=nDim;
60      if(nDim>0) this->axisDim = new long[nDim];
61      for(int i=0;i<nDim;i++) this->axisDim[i] = dimensions[i];
62    }
63  }
64}
65//--------------------------------------------------------------------
66
67DataArray::~DataArray()
68{
69  delete [] array;
70  delete [] axisDim;
71  objectList.clear();
72}
73//--------------------------------------------------------------------
74
75void DataArray::getDimArray(long *output){
76  for(int i=0;i<this->numDim;i++) output[i] = this->axisDim[i];
77}
78//--------------------------------------------------------------------
79
80void DataArray::getArray(float *output){
81  for(int i=0;i<this->numPixels;i++) output[i] = this->array[i];
82}
83//--------------------------------------------------------------------
84
85void DataArray::saveArray(float *input, long size){
86  if(size != this->numPixels)
87    duchampError("DataArray::saveArray",
88                 "Input array different size to existing array. Cannot save.");
89  else {
90    if(this->numPixels>0) delete [] this->array;
91    this->numPixels = size;
92    this->array = new float[size];
93    for(int i=0;i<size;i++) this->array[i] = input[i];
94  }
95}
96//--------------------------------------------------------------------
97
98void DataArray::getDim(long &x, long &y, long &z){
99  if(numDim>0) x=axisDim[0];
100  else x=0;
101  if(numDim>1) y=axisDim[1];
102  else y=0;
103  if(numDim>2) z=axisDim[2];
104  else z=0;
105}
106//--------------------------------------------------------------------
107
108void DataArray::addObject(Detection object){
109  // adds a single detection to the object list
110  // objectList is a vector, so just use push_back()
111  this->objectList.push_back(object);
112}
113//--------------------------------------------------------------------
114
115void DataArray::addObjectList(vector <Detection> newlist) {
116  for(int i=0;i<newlist.size();i++) this->objectList.push_back(newlist[i]);
117}
118//--------------------------------------------------------------------
119
120void DataArray::addObjectOffsets(){
121  for(int i=0;i<this->objectList.size();i++){
122    for(int p=0;p<this->objectList[i].getSize();p++){
123      this->objectList[i].setX(p,this->objectList[i].getX(p)+
124                               this->par.getXOffset());
125      this->objectList[i].setY(p,this->objectList[i].getY(p)+
126                               this->par.getYOffset());
127      this->objectList[i].setZ(p,this->objectList[i].getZ(p)+
128                               this->par.getZOffset());
129    }
130  }
131}
132//--------------------------------------------------------------------
133
134std::ostream& operator<< ( std::ostream& theStream, DataArray &array)
135{
136  for(int i=0;i<array.numDim;i++){
137    if(i>0) theStream<<"x";
138    theStream<<array.axisDim[i];
139  }
140  theStream<<endl;
141  theStream<<array.objectList.size()<<" detections:"<<endl<<"--------------\n";
142  for(int i=0;i<array.objectList.size();i++){
143    theStream << "Detection #" << array.objectList[i].getID()<<endl;
144    Detection *obj = new Detection;
145    *obj = array.objectList[i];
146    for(int j=0;j<obj->getSize();j++){
147      obj->setX(j,obj->getX(j)+obj->getXOffset());
148      obj->setY(j,obj->getY(j)+obj->getYOffset());
149      obj->setZ(j,obj->getZ(j)+obj->getZOffset());
150    }
151    theStream<<*obj;
152    delete obj;
153  }
154  theStream<<"--------------\n";
155}
156
157/****************************************************************/
158/////////////////////////////////////////////////////////////
159//// Functions for Image class
160/////////////////////////////////////////////////////////////
161
162Image::Image(long size){
163  // need error handling in case size<0 !!!
164  if(size<0)
165    duchampError("Image(size)","Negative size -- could not define Image");
166  else{
167    if(size>0){
168      this->array = new float[size];
169//       this->pValue = new float[size];
170//       this->mask = new short int[size];
171    }
172    this->numPixels = size;
173    this->axisDim = new long[2];
174    this->numDim = 2;
175  }
176}
177//--------------------------------------------------------------------
178
179Image::Image(long *dimensions){
180  int size = dimensions[0] * dimensions[1];
181  if(size<0)
182    duchampError("Image(dimArray)","Negative size -- could not define Image");
183  else{
184    this->numPixels = size;
185    if(size>0){
186      this->array = new float[size];
187//       this->pValue = new float[size];
188//       this->mask = new short int[size];
189    }
190    this->numDim=2;
191    this->axisDim = new long[2];
192    for(int i=0;i<2;i++) this->axisDim[i] = dimensions[i];
193//     for(int i=0;i<size;i++) this->mask[i] = 0;
194  }
195}
196//--------------------------------------------------------------------
197
198Image::~Image(){
199  if(this->numPixels > 0){
200//     delete [] this->pValue;
201//     delete [] this->mask;
202  }
203}
204//--------------------------------------------------------------------
205
206void Image::saveArray(float *input, long size){
207  if(size != this->numPixels)
208    duchampError("Image::saveArray",
209                 "Input array different size to existing array. Cannot save.");
210  else {
211    if(this->numPixels>0){
212      delete [] array;
213//       delete [] pValue;
214//       delete [] mask;
215    }
216    this->numPixels = size;
217    if(this->numPixels>0){
218      this->array = new float[size];
219//       this->pValue = new float[size];
220//       this->mask = new short int[size];
221    }
222    for(int i=0;i<size;i++) this->array[i] = input[i];
223//     for(int i=0;i<size;i++) this->mask[i] = 0;
224  }
225}
226//--------------------------------------------------------------------
227
228void Image::extractSpectrum(float *Array, long *dim, long pixel)
229{
230  /**
231   * Image::extractSpectrum(float *, long *, int)
232   *  A function to extract a 1-D spectrum from a 3-D array.
233   *  The array is assumed to be 3-D with the third dimension the spectral one.
234   *  The dimensions of the array are in the dim[] array.
235   *  The spectrum extracted is the one lying in the spatial pixel referenced
236   *    by the third argument.
237   */
238  float *spec = new float[dim[2]];
239  for(int z=0;z<dim[2];z++) spec[z] = Array[z*dim[0]*dim[1] + pixel];
240  this->saveArray(spec,dim[2]);
241  delete [] spec;
242}
243//--------------------------------------------------------------------
244
245void Image::extractSpectrum(Cube &cube, long pixel)
246{
247  /**
248   * Image::extractSpectrum(Cube &, int)
249   *  A function to extract a 1-D spectrum from a Cube class
250   *  The spectrum extracted is the one lying in the spatial pixel referenced
251   *    by the second argument.
252   */
253  long zdim = cube.getDimZ();
254  long spatSize = cube.getDimX()*cube.getDimY();
255  float *spec = new float[zdim];
256  for(int z=0;z<zdim;z++) spec[z] = cube.getPixValue(z*spatSize + pixel);
257  this->saveArray(spec,zdim);
258  delete [] spec;
259}
260//--------------------------------------------------------------------
261
262void Image::extractImage(float *Array, long *dim, long channel)
263{
264  /**
265   * Image::extractImage(float *, long *, int)
266   *  A function to extract a 2-D image from a 3-D array.
267   *  The array is assumed to be 3-D with the third dimension the spectral one.
268   *  The dimensions of the array are in the dim[] array.
269   *  The image extracted is the one lying in the channel referenced
270   *    by the third argument.
271   */
272  float *image = new float[dim[0]*dim[1]];
273  for(int npix=0; npix<dim[0]*dim[1]; npix++){
274    image[npix] = Array[channel*dim[0]*dim[1] + npix];
275  }
276  this->saveArray(image,dim[0]*dim[1]);
277  delete [] image;
278}
279//--------------------------------------------------------------------
280
281void Image::extractImage(Cube &cube, long channel)
282{
283  /**
284   * Image::extractImage(Cube &, int)
285   *  A function to extract a 2-D image from Cube class.
286   *  The image extracted is the one lying in the channel referenced
287   *    by the second argument.
288   */
289  long spatSize = cube.getDimX()*cube.getDimY();
290  float *image = new float[spatSize];
291  for(int npix=0; npix<spatSize; npix++)
292    image[npix] = cube.getPixValue(channel*spatSize + npix);
293  this->saveArray(image,spatSize);
294  delete [] image;
295}
296//--------------------------------------------------------------------
297
298void Image::removeMW()
299{
300  /**
301   * Image::removeMW()
302   *  A function to remove the Milky Way range of channels from a 1-D spectrum.
303   *  The array in this Image is assumed to be 1-D, with only the first axisDim
304   *    equal to 1.
305   *  The values of the MW channels are set to 0, unless they are BLANK.
306   */
307  if(this->par.getFlagMW() && (this->axisDim[1]==1) ){
308    for(int z=0;z<this->axisDim[0];z++){
309      if(!this->isBlank(z) && this->par.isInMW(z)) this->array[z]=0.;
310    }
311  }
312}
313
314/****************************************************************/
315/////////////////////////////////////////////////////////////
316//// Functions for Cube class
317/////////////////////////////////////////////////////////////
318
319Cube::Cube(long size){
320  // need error handling in case size<0 !!!
321  if(size<0)
322    duchampError("Cube(size)","Negative size -- could not define Cube");
323  else{
324    if(size>0){
325      this->array = new float[size];
326      this->recon = new float[size];
327    }
328    this->numPixels = size;
329    this->axisDim = new long[2];
330    this->numDim = 3;
331    this->reconExists = false;
332  }
333}
334//--------------------------------------------------------------------
335
336Cube::Cube(long *dimensions){
337  int size   = dimensions[0] * dimensions[1] * dimensions[2];
338  int imsize = dimensions[0] * dimensions[1];
339  if((size<0) || (imsize<0) )
340    duchampError("Cube(dimArray)","Negative size -- could not define Cube");
341  else{
342    this->numPixels = size;
343    if(size>0){
344      this->array      = new float[size];
345      this->detectMap  = new short[imsize];
346      if(this->par.getFlagATrous())
347        this->recon    = new float[size];
348      if(this->par.getFlagBaseline())
349        this->baseline = new float[size];
350    }
351    this->numDim  = 3;
352    this->axisDim = new long[3];
353    for(int i=0;i<3     ;i++) this->axisDim[i]   = dimensions[i];
354    for(int i=0;i<imsize;i++) this->detectMap[i] = 0;
355    this->reconExists = false;
356  }
357}
358//--------------------------------------------------------------------
359
360Cube::~Cube()
361{
362  delete [] detectMap;
363  if(this->par.getFlagATrous())   delete [] recon;
364  if(this->par.getFlagBaseline()) delete [] baseline;
365}
366//--------------------------------------------------------------------
367
368void Cube::initialiseCube(long *dimensions)
369{
370  /**
371   *  Cube::initialiseCube(long *dim)
372   *   A function that defines the sizes of all the necessary
373   *    arrays in the Cube class.
374   *   It also defines the values of the axis dimensions.
375   *   This is done with the WCS in the FitsHeader class, so the
376   *    WCS needs to be good and have three axes.
377   */
378
379  int lng,lat,spc,size,imsize;
380
381  if(this->head.isWCS() && (this->head.getWCS()->naxis>=3)){
382    // if there is a WCS and there is at least 3 axes
383    lng = this->head.getWCS()->lng;
384    lat = this->head.getWCS()->lat;
385    spc = this->head.getWCS()->spec;
386  }
387  else{
388    // just take dimensions[] at face value
389    lng = 0;
390    lat = 1;
391    spc = 2;
392  }
393  size   = dimensions[lng] * dimensions[lat] * dimensions[spc];
394  imsize = dimensions[lng] * dimensions[lat];
395
396
397  if((size<0) || (imsize<0) )
398    duchampError("Cube::initialiseCube(dimArray)",
399                 "Negative size -- could not define Cube.\n");
400  else{
401    this->numPixels = size;
402    if(size>0){
403      this->array      = new float[size];
404      this->detectMap  = new short[imsize];
405      if(this->par.getFlagATrous())
406        this->recon    = new float[size];
407      if(this->par.getFlagBaseline())
408        this->baseline = new float[size];
409    }
410    this->numDim  = 3;
411    this->axisDim = new long[3];
412    this->axisDim[0] = dimensions[lng];
413    this->axisDim[1] = dimensions[lat];
414    this->axisDim[2] = dimensions[spc];
415    for(int i=0;i<imsize;i++) this->detectMap[i] = 0;
416    this->reconExists = false;
417  }
418}
419//--------------------------------------------------------------------
420
421int Cube::getopts(int argc, char ** argv)
422{
423  /**
424   *   Cube::getopt
425   *    A front-end to read in the command-line options,
426   *     and then read in the correct parameters to the cube->par
427   */
428
429  int returnValue;
430  if(argc==1){
431    std::cout << ERR_USAGE_MSG;
432    returnValue = FAILURE;
433  }
434  else {
435    string file;
436    Param *par = new Param;
437    char c;
438    while( ( c = getopt(argc,argv,"p:f:hv") )!=-1){
439      switch(c) {
440      case 'p':
441        file = optarg;
442        if(this->readParam(file)==FAILURE){
443          stringstream errmsg;
444          errmsg << "Could not open parameter file " << file << ".\n";
445          duchampError("Duchamp",errmsg.str());
446          returnValue = FAILURE;
447        }
448        else returnValue = SUCCESS;
449        break;
450      case 'f':
451        file = optarg;
452        par->setImageFile(file);
453        this->saveParam(*par);
454        returnValue = SUCCESS;
455        break;
456      case 'v':
457        std::cout << PROGNAME << " version " << VERSION << std::endl;
458        returnValue = FAILURE;
459        break;
460      case 'h':
461      default :
462        std::cout << ERR_USAGE_MSG;
463        returnValue = FAILURE;
464        break;
465      }
466    }
467    delete par;
468  }
469  return returnValue;
470}
471//--------------------------------------------------------------------
472
473void Cube::saveArray(float *input, long size){
474  if(size != this->numPixels){
475    stringstream errmsg;
476    errmsg << "Input array different size to existing array ("
477           << size << " cf. " << this->numPixels << "). Cannot save.\n";
478    duchampError("Cube::saveArray",errmsg.str());
479  }
480  else {
481    if(this->numPixels>0) delete [] array;
482    this->numPixels = size;
483    this->array = new float[size];
484    for(int i=0;i<size;i++) this->array[i] = input[i];
485  }
486}
487//--------------------------------------------------------------------
488
489void Cube::saveRecon(float *input, long size){
490  if(size != this->numPixels){
491    stringstream errmsg;
492    errmsg << "Input array different size to existing array ("
493           << size << " cf. " << this->numPixels << "). Cannot save.\n";
494    duchampError("Cube::saveRecon",errmsg.str());
495  }
496  else {
497    if(this->numPixels>0) delete [] this->recon;
498    this->numPixels = size;
499    this->recon = new float[size];
500    for(int i=0;i<size;i++) this->recon[i] = input[i];
501    this->reconExists = true;
502  }
503}
504//--------------------------------------------------------------------
505
506void Cube::getRecon(float *output){
507  // Need check for change in number of pixels!
508  long size = this->numPixels;
509  for(int i=0;i<size;i++){
510    if(this->reconExists) output[i] = this->recon[i];
511    else output[i] = 0.;
512  }
513}
514//--------------------------------------------------------------------
515
516void Cube::removeMW()
517{
518  if(this->par.getFlagMW()){
519    for(int pix=0;pix<this->axisDim[0]*this->axisDim[1];pix++){
520      for(int z=0;z<this->axisDim[2];z++){
521        int pos = z*this->axisDim[0]*this->axisDim[1] + pix;
522        if(!this->isBlank(pos) && this->par.isInMW(z)) this->array[pos]=0.;
523      }
524    }
525  }
526}
527//--------------------------------------------------------------------
528
529void Cube::calcObjectWCSparams()
530{
531  /**
532   * Cube::calcObjectWCSparams()
533   *  A function that calculates the WCS parameters for each object in the
534   *  cube's list of detections.
535   *  Each object gets an ID number set (just the order in the list), and if
536   *   the WCS is good, the WCS paramters are calculated.
537   */
538 
539  for(int i=0; i<this->objectList.size();i++){
540    this->objectList[i].setID(i+1);
541    this->objectList[i].calcWCSparams(this->head);
542    this->objectList[i].setPeakSNR( (this->objectList[i].getPeakFlux() - this->Stats.getMiddle()) / this->Stats.getSpread() );
543  } 
544
545 
546}
547//--------------------------------------------------------------------
548
549void Cube::sortDetections()
550{
551  /**
552   * Cube::sortDetections()
553   *  A front end to the sort-by functions.
554   *  If there is a good WCS, the detection list is sorted by velocity.
555   *  Otherwise, it is sorted by increasing z-pixel value.
556   *  The ID numbers are then re-calculated.
557   */
558 
559  if(this->head.isWCS()) SortByVel(this->objectList);
560  else SortByZ(this->objectList);
561  for(int i=0; i<this->objectList.size();i++) this->objectList[i].setID(i+1);
562
563}
564//--------------------------------------------------------------------
565
566void Cube::updateDetectMap()
567{
568  /**
569   * Cube::updateDetectMap()
570   *  A function that, for each detected object in the cube's list, increments
571   *   the cube's detection map by the required amount at each pixel.
572   */
573
574  for(int obj=0;obj<this->objectList.size();obj++){
575    for(int pix=0;pix<this->objectList[obj].getSize();pix++) {
576      int spatialPos = this->objectList[obj].getX(pix)+
577        this->objectList[obj].getY(pix)*this->axisDim[0];
578      this->detectMap[spatialPos]++;
579    }
580  }
581}
582//--------------------------------------------------------------------
583
584void Cube::updateDetectMap(Detection obj)
585{
586  /**
587   * Cube::updateDetectMap(Detection)
588   *  A function that, for the given object, increments the cube's
589   *  detection map by the required amount at each pixel.
590   */
591  for(int pix=0;pix<obj.getSize();pix++) {
592    int spatialPos = obj.getX(pix)+obj.getY(pix)*this->axisDim[0];
593    this->detectMap[spatialPos]++;
594  }
595}
596//--------------------------------------------------------------------
597
598void Cube::setCubeStats()
599{
600  /**
601   *  Cube::setCubeStats()
602   *   Calculates the full statistics for the cube:
603   *     mean, rms, median, madfm
604   *   Only do this if the threshold has not been defined (ie. is still 0.,
605   *    its default).
606   *   Also work out the threshold and store it in the par set.
607   *   
608   *   For stats calculations, ignore BLANKs and MW channels.
609   */
610
611  // get number of good pixels;
612  int goodSize = 0;
613  for(int p=0;p<this->axisDim[0]*this->axisDim[1];p++){
614    for(int z=0;z<this->axisDim[2];z++){
615      int vox = z * this->axisDim[0] * this->axisDim[1] + p;
616      if(!this->isBlank(vox) && !this->par.isInMW(z)) goodSize++;
617    }
618  }
619  float *tempArray = new float[goodSize];
620
621  goodSize=0;
622  for(int p=0;p<this->axisDim[0]*this->axisDim[1];p++){
623    for(int z=0;z<this->axisDim[2];z++){
624      int vox = z * this->axisDim[0] * this->axisDim[1] + p;
625      if(!this->isBlank(vox) && !this->par.isInMW(z))
626        tempArray[goodSize++] = this->array[vox];
627    }
628  }
629  if(!this->reconExists){
630    // if there's no recon array, calculate everything from orig array
631    this->Stats.calculate(tempArray,goodSize);
632  }
633  else{
634    // just get mean & median from orig array, and rms & madfm from recon
635    StatsContainer<float> origStats,reconStats;
636    origStats.calculate(tempArray,goodSize);
637    goodSize=0;
638    for(int p=0;p<this->axisDim[0]*this->axisDim[1];p++){
639      for(int z=0;z<this->axisDim[2];z++){
640        int vox = z * this->axisDim[0] * this->axisDim[1] + p;
641        if(!this->isBlank(vox) && !this->par.isInMW(z))
642          tempArray[goodSize++] = this->array[vox] - this->recon[vox];
643      }
644    }
645    reconStats.calculate(tempArray,goodSize);
646
647    // Get the "middle" estimators from the original array.
648    // Get the "spread" estimators from the residual (orig-recon) array
649    this->Stats.setMean(origStats.getMean());
650    this->Stats.setMedian(origStats.getMedian());
651    this->Stats.setStddev(reconStats.getStddev());
652    this->Stats.setMadfm(reconStats.getMadfm());
653  }
654
655  this->Stats.setUseFDR( this->par.getFlagFDR() );
656  // If the FDR method has been requested
657  if(this->par.getFlagFDR())  this->setupFDR();
658  else{
659    if(this->par.getFlagUserThreshold()){
660      // if the user has defined a threshold, set this in the StatsContainer
661      this->Stats.setThreshold( this->par.getThreshold() );
662    }
663    else{
664      // otherwise, calculate one based on the requested SNR cut level, and
665      //   then set the threshold parameter in the Par set.
666      this->Stats.setThresholdSNR( this->par.getCut() );
667      this->par.setThreshold( this->Stats.getThreshold() );
668    }
669//       std::cout << "Median = " << this->Stats.getMedian()
670//              << ", MADFM = " << this->Stats.getMadfm()
671//              << ", Robust Threshold = "
672//              << this->Stats.getMedian() +
673//      this->par.getCut()*madfmToSigma(this->Stats.getMadfm()) << std::endl;
674//       std::cout << "Mean = " << this->Stats.getMean()
675//              << ", Sigma = " << this->Stats.getStddev()
676//              << ", Threshold = "
677//              << this->Stats.getMean() +
678//                 this->par.getCut()*this->Stats.getStddev()
679//              << std::endl;
680  }
681  std::cout << "Using ";
682  if(this->par.getFlagFDR()) std::cout << "effective ";
683  std::cout << "flux threshold of: ";
684  float thresh = this->Stats.getThreshold();
685  if(this->par.getFlagNegative()) thresh *= -1.;
686  std::cout << thresh << std::endl;
687
688}
689//--------------------------------------------------------------------
690
691int Cube::setupFDR()
692{
693  /**
694   *  Cube::setupFDR()
695   *   Determines the critical Prob value for the False Discovery Rate
696   *    detection routine. All pixels with Prob less than this value will
697   *    be considered detections.
698   *   The Prob here is the probability, assuming a Normal distribution, of
699   *    obtaining a value as high or higher than the pixel value (ie. only the
700   *    positive tail of the PDF)
701   */
702
703  // first calculate p-value for each pixel -- assume Gaussian for now.
704
705  float *orderedP = new float[this->numPixels];
706  int count = 0;
707  float zStat;
708  for(int pix=0; pix<this->numPixels; pix++){
709
710    if( !(this->par.isBlank(this->array[pix])) ){
711      // only look at non-blank pixels
712      zStat = (this->array[pix] - this->Stats.getMiddle()) /
713        this->Stats.getSpread();
714     
715      orderedP[count++] = 0.5 * erfc(zStat/M_SQRT2);
716      // Need the factor of 0.5 here, as we are only considering the positive
717      //  tail of the distribution. Don't care about negative detections.
718    }
719  }
720
721  // now order them
722  sort(orderedP,0,count);
723 
724  // now find the maximum P value.
725  int max = 0;
726  float cN = 0.;
727  int psfCtr;
728  int numVox = int(this->par.getBeamSize()) * 2;
729  // why beamSize*2? we are doing this in 3D, so spectrally assume just the
730  //  neighbouring channels are correlated, but spatially all those within
731  //  the beam, so total number of voxels is 2*beamSize
732  for(psfCtr=1;psfCtr<=numVox;(psfCtr)++)
733    cN += 1./float(psfCtr);
734
735  for(int loopCtr=0;loopCtr<count;loopCtr++) {
736    if( orderedP[loopCtr] <
737        (double(loopCtr+1)*this->par.getAlpha()/(cN * double(count))) ) {
738      max = loopCtr;
739    }
740  }
741
742  this->Stats.setPThreshold( orderedP[max] );
743
744  delete [] orderedP;
745
746  // Find real value of the P threshold by finding the inverse of the
747  //  error function -- root finding with brute force technique
748  //  (relatively slow, but we only do it once).
749  zStat = 0;
750  float deltaZ = 0.1;
751  float tolerance = 1.e-6;
752  float zeroP = 0.5 * erfc(zStat/M_SQRT2) - this->Stats.getPThreshold();
753  do{
754    zStat+=deltaZ;
755    if((zeroP * (erfc(zStat/M_SQRT2)-this->Stats.getPThreshold()))<0.){
756      zStat-=deltaZ;
757      deltaZ/=2.;
758    }
759  }while(deltaZ>tolerance);
760  this->Stats.setThreshold( zStat*this->Stats.getSpread() +
761                            this->Stats.getMiddle() );
762
763}
764//--------------------------------------------------------------------
765
766float Cube::enclosedFlux(Detection obj)
767{
768  /**
769   *  float Cube::enclosedFlux(Detection obj)
770   *   A function to calculate the flux enclosed by the range
771   *    of pixels detected in the object obj (not necessarily all
772   *    pixels will have been detected).
773   */
774  obj.calcParams();
775  int xsize = obj.getXmax()-obj.getXmin()+1;
776  int ysize = obj.getYmax()-obj.getYmin()+1;
777  int zsize = obj.getZmax()-obj.getZmin()+1;
778  vector <float> fluxArray(xsize*ysize*zsize,0.);
779  for(int x=0;x<xsize;x++){
780    for(int y=0;y<ysize;y++){
781      for(int z=0;z<zsize;z++){
782        fluxArray[x+y*xsize+z*ysize*xsize] =
783          this->getPixValue(x+obj.getXmin(),
784                            y+obj.getYmin(),
785                            z+obj.getZmin());
786        if(this->par.getFlagNegative())
787          fluxArray[x+y*xsize+z*ysize*xsize] *= -1.;
788      }
789    }
790  }
791  float sum = 0.;
792  for(int i=0;i<fluxArray.size();i++)
793    if(!this->par.isBlank(fluxArray[i])) sum+=fluxArray[i];
794  return sum;
795}
796//--------------------------------------------------------------------
797
798void Cube::setupColumns()
799{
800  /**
801   *  Cube::setupColumns()
802   *   A front-end to the two setup routines in columns.cc.
803   */
804  this->calcObjectWCSparams(); 
805  // need this as the colSet functions use vel, RA, Dec, etc...
806 
807  this->fullCols.clear();
808  this->fullCols = getFullColSet(this->objectList, this->head);
809
810  this->logCols.clear();
811  this->logCols = getLogColSet(this->objectList, this->head);
812
813  int vel,fpeak,fint,pos,xyz,temp,snr;
814  vel = fullCols[VEL].getPrecision();
815  fpeak = fullCols[FPEAK].getPrecision();
816  snr = fullCols[SNRPEAK].getPrecision();
817  xyz = fullCols[X].getPrecision();
818  if(temp=fullCols[Y].getPrecision() > xyz) xyz = temp;
819  if(temp=fullCols[Z].getPrecision() > xyz) xyz = temp;
820  if(this->head.isWCS()) fint = fullCols[FINT].getPrecision();
821  else fint = fullCols[FTOT].getPrecision();
822  pos = fullCols[WRA].getPrecision();
823  if(temp=fullCols[WDEC].getPrecision() > pos) pos = temp;
824 
825  for(int obj=0;obj<this->objectList.size();obj++){
826    this->objectList[obj].setVelPrec(vel);
827    this->objectList[obj].setFpeakPrec(fpeak);
828    this->objectList[obj].setXYZPrec(xyz);
829    this->objectList[obj].setPosPrec(pos);
830    this->objectList[obj].setFintPrec(fint);
831    this->objectList[obj].setSNRPrec(snr);
832  }
833
834}
835//--------------------------------------------------------------------
836
837bool Cube::objAtSpatialEdge(Detection obj)
838{
839  /**
840   *  bool Cube::objAtSpatialEdge()
841   *   A function to test whether the object obj
842   *    lies at the edge of the cube's spatial field --
843   *    either at the boundary, or next to BLANKs
844   */
845
846  bool atEdge = false;
847
848  int pix = 0;
849  while(!atEdge && pix<obj.getSize()){
850    // loop over each pixel in the object, until we find an edge pixel.
851    Voxel vox = obj.getPixel(pix);
852    for(int dx=-1;dx<=1;dx+=2){
853      if(((vox.getX()+dx)<0) || ((vox.getX()+dx)>=this->axisDim[0]))
854        atEdge = true;
855      else if(this->isBlank(vox.getX()+dx,vox.getY(),vox.getZ()))
856        atEdge = true;
857    }
858    for(int dy=-1;dy<=1;dy+=2){
859      if(((vox.getY()+dy)<0) || ((vox.getY()+dy)>=this->axisDim[1]))
860        atEdge = true;
861      else if(this->isBlank(vox.getX(),vox.getY()+dy,vox.getZ()))
862        atEdge = true;
863    }
864    pix++;
865  }
866
867  return atEdge;
868}
869//--------------------------------------------------------------------
870
871bool Cube::objAtSpectralEdge(Detection obj)
872{
873  /**
874   *  bool Cube::objAtSpectralEdge()
875   *   A function to test whether the object obj
876   *    lies at the edge of the cube's spectral extent --
877   *    either at the boundary, or next to BLANKs
878   */
879
880  bool atEdge = false;
881
882  int pix = 0;
883  while(!atEdge && pix<obj.getSize()){
884    // loop over each pixel in the object, until we find an edge pixel.
885    Voxel vox = obj.getPixel(pix);
886    for(int dz=-1;dz<=1;dz+=2){
887      if(((vox.getZ()+dz)<0) || ((vox.getZ()+dz)>=this->axisDim[2]))
888        atEdge = true;
889      else if(this->isBlank(vox.getX(),vox.getY(),vox.getZ()+dz))
890        atEdge = true;
891    }
892    pix++;
893  }
894
895  return atEdge;
896}
897//--------------------------------------------------------------------
898
899void Cube::setObjectFlags()
900{
901  /**
902   *  void Cube::setObjectFlags()
903   *   A function to set any warning flags for all the detected objects
904   *    associated with the cube.
905   *   Flags to be looked for:
906   *       * Negative enclosed flux (N)
907   *       * Object at edge of field (E)
908   */
909
910  for(int i=0;i<this->objectList.size();i++){
911
912    if( this->enclosedFlux(this->objectList[i]) < 0. ) 
913      this->objectList[i].addToFlagText("N");
914
915    if( this->objAtSpatialEdge(this->objectList[i]) )
916      this->objectList[i].addToFlagText("E");
917
918    if( this->objAtSpectralEdge(this->objectList[i]) )
919      this->objectList[i].addToFlagText("S");
920
921  }
922
923}
924//--------------------------------------------------------------------
925
926void Cube::plotBlankEdges()
927{
928  if(this->par.drawBlankEdge()){
929    int colour;
930    cpgqci(&colour);
931    cpgsci(MAGENTA);
932    drawBlankEdges(this->array,this->axisDim[0],this->axisDim[1],this->par);
933    cpgsci(colour);
934  }
935}
Note: See TracBrowser for help on using the repository browser.