source: trunk/src/Cubes/cubes.cc @ 1014

Last change on this file since 1014 was 986, checked in by MatthewWhiting, 12 years ago

Ticket #148: Getting the 1D plotting working for a single spectrum out of a HIPASS cube (ie. the WCS works). Also needed some tweaks to the integrated flux calculations, and some adjustments to the minPix/Channels parameters

File size: 67.9 KB
Line 
1// -----------------------------------------------------------------------
2// cubes.cc: Member functions for the DataArray, Cube and Image classes.
3// -----------------------------------------------------------------------
4// Copyright (C) 2006, Matthew Whiting, ATNF
5//
6// This program is free software; you can redistribute it and/or modify it
7// under the terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 2 of the License, or (at your
9// option) any later version.
10//
11// Duchamp is distributed in the hope that it will be useful, but WITHOUT
12// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14// for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with Duchamp; if not, write to the Free Software Foundation,
18// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
19//
20// Correspondence concerning Duchamp may be directed to:
21//    Internet email: Matthew.Whiting [at] atnf.csiro.au
22//    Postal address: Dr. Matthew Whiting
23//                    Australia Telescope National Facility, CSIRO
24//                    PO Box 76
25//                    Epping NSW 1710
26//                    AUSTRALIA
27// -----------------------------------------------------------------------
28#include <unistd.h>
29#include <iostream>
30#include <iomanip>
31#include <vector>
32#include <algorithm>
33#include <string>
34#include <math.h>
35
36#include <wcslib/wcs.h>
37
38#include <duchamp/pgheader.hh>
39
40#include <duchamp/duchamp.hh>
41#include <duchamp/param.hh>
42#include <duchamp/fitsHeader.hh>
43#include <duchamp/Cubes/cubes.hh>
44#include <duchamp/PixelMap/Voxel.hh>
45#include <duchamp/PixelMap/Object3D.hh>
46#include <duchamp/Detection/detection.hh>
47#include <duchamp/Detection/columns.hh>
48#include <duchamp/Detection/finders.hh>
49#include <duchamp/Utils/utils.hh>
50#include <duchamp/Utils/feedback.hh>
51#include <duchamp/Utils/mycpgplot.hh>
52#include <duchamp/Utils/Statistics.hh>
53#include <duchamp/FitsIO/DuchampBeam.hh>
54
55using namespace mycpgplot;
56using namespace Statistics;
57using namespace PixelInfo;
58
59#ifdef TEST_DEBUG
60const bool TESTING=true;
61#else
62const bool TESTING=false;
63#endif
64
65namespace duchamp
66{
67
68  using namespace Column;
69
70  /****************************************************************/
71  ///////////////////////////////////////////////////
72  //// Functions for DataArray class:
73  ///////////////////////////////////////////////////
74
75  DataArray::DataArray(){
76    /// Fundamental constructor for DataArray.
77    /// Number of dimensions and pixels are set to 0. Nothing else allocated.
78
79    this->numDim=0;
80    this->numPixels=0;
81    this->objectList = new std::vector<Detection>;
82    this->axisDimAllocated = false;
83    this->arrayAllocated = false;
84  }
85  //--------------------------------------------------------------------
86
87  DataArray::DataArray(const DataArray &d){
88    operator=(d);
89  }
90
91  DataArray& DataArray::operator=(const DataArray &d){
92    if(this==&d) return *this;
93    this->numDim = d.numDim;
94    if(this->axisDimAllocated) delete [] this->axisDim;
95    this->axisDimAllocated = d.axisDimAllocated;
96    if(this->axisDimAllocated){
97      this->axisDim = new size_t[this->numDim];
98      for(size_t i=0;i<size_t(this->numDim);i++) this->axisDim[i] = d.axisDim[i];
99    }
100    this->numPixels = d.numPixels;
101    if(this->arrayAllocated) delete [] this->array;
102    this->arrayAllocated = d.arrayAllocated;
103    if(this->arrayAllocated) {
104      this->array = new float[this->numPixels];
105      for(size_t i=0;i<size_t(this->numPixels);i++) this->array[i] = d.array[i];
106    }
107    this->objectList = d.objectList;
108    this->par = d.par;
109    this->Stats = d.Stats;
110    return *this;
111  }
112
113
114  DataArray::DataArray(short int nDim){
115    /// @details
116    /// N-dimensional constructor for DataArray.
117    /// Number of dimensions defined, and dimension array allocated.
118    /// Number of pixels are set to 0.
119    /// \param nDim Number of dimensions.
120
121    this->axisDimAllocated = false;
122    this->arrayAllocated = false;
123    if(nDim>0){
124      this->axisDim = new size_t[nDim];
125      this->axisDimAllocated = true;
126    }
127    this->numDim=nDim;
128    this->numPixels=0;
129    this->objectList = new std::vector<Detection>;
130  }
131  //--------------------------------------------------------------------
132
133  DataArray::DataArray(short int nDim, size_t size){
134    /// @details
135    /// N-dimensional constructor for DataArray.
136    /// Number of dimensions and number of pixels defined.
137    /// Arrays allocated based on these values.
138    /// \param nDim Number of dimensions.
139    /// \param size Number of pixels.
140    ///
141    /// Note that we can assign values to the dimension array.
142
143    this->axisDimAllocated = false;
144    this->arrayAllocated = false;
145    if(size<0){
146      DUCHAMPERROR("DataArray(nDim,size)", "Negative size -- could not define DataArray");
147    }
148    else if(nDim<0){
149      DUCHAMPERROR("DataArray(nDim,size)", "Negative number of dimensions: could not define DataArray");
150    }
151    else {
152      if(size>0){
153        this->array = new float[size];
154        this->arrayAllocated = true;
155      }
156      this->numPixels = size;
157      if(nDim>0){
158        this->axisDim = new size_t[nDim];
159        this->axisDimAllocated = true;
160      }
161      this->numDim = nDim;
162    }
163    this->objectList = new std::vector<Detection>;
164  }
165  //--------------------------------------------------------------------
166
167  DataArray::DataArray(short int nDim, size_t *dimensions)
168  {
169    /// @details
170    /// Most robust constructor for DataArray.
171    /// Number and sizes of dimensions are defined, and hence the number of
172    /// pixels. Arrays allocated based on these values.
173    /// \param nDim Number of dimensions.
174    /// \param dimensions Array giving sizes of dimensions.
175
176    this->axisDimAllocated = false;
177    this->arrayAllocated = false;
178    if(nDim<0){
179      DUCHAMPERROR("DataArray(nDim,dimArray)", "Negative number of dimensions: could not define DataArray");
180    }
181    else {
182      int size = dimensions[0];
183      for(int i=1;i<nDim;i++) size *= dimensions[i];
184      if(size<0){
185        DUCHAMPERROR("DataArray(nDim,dimArray)", "Negative size: could not define DataArray");
186      }
187      else{
188        this->numPixels = size;
189        if(size>0){
190          this->array = new float[size];
191          this->arrayAllocated = true;
192        }
193        this->numDim=nDim;
194        if(nDim>0){
195          this->axisDim = new size_t[nDim];
196          this->axisDimAllocated = true;
197        }
198        for(int i=0;i<nDim;i++) this->axisDim[i] = dimensions[i];
199      }
200    }
201  }
202  //--------------------------------------------------------------------
203
204  DataArray::~DataArray()
205  {
206    ///  @details
207    ///  Destructor -- arrays deleted if they have been allocated, and the
208    ///   object list is deleted.
209
210    if(this->numPixels>0 && this->arrayAllocated){
211      delete [] this->array;
212      this->arrayAllocated = false;
213    }
214    if(this->numDim>0 && this->axisDimAllocated){
215      delete [] this->axisDim;
216      this->axisDimAllocated = false;
217    }
218    delete this->objectList;
219  }
220  //--------------------------------------------------------------------
221  //--------------------------------------------------------------------
222
223  void DataArray::getDim(size_t &x, size_t &y, size_t &z)
224  {
225    /// @details
226    /// The sizes of the first three dimensions (if they exist) are returned.
227    /// \param x The first dimension. Defaults to 0 if numDim \f$\le\f$ 0.
228    /// \param y The second dimension. Defaults to 1 if numDim \f$\le\f$ 1.
229    /// \param z The third dimension. Defaults to 1 if numDim \f$\le\f$ 2.
230
231    if(this->numDim>0) x=this->axisDim[0];
232    else x=0;
233    if(this->numDim>1) y=this->axisDim[1];
234    else y=1;
235    if(this->numDim>2) z=this->axisDim[2];
236    else z=1;
237  }
238  //--------------------------------------------------------------------
239
240  void DataArray::getDimArray(size_t *output)
241  {
242    /// @details
243    /// The axisDim array is written to output. This needs to be defined
244    ///  beforehand: no checking is done on the memory.
245    /// \param output The array that is written to.
246
247    for(int i=0;i<this->numDim;i++) output[i] = this->axisDim[i];
248  }
249  //--------------------------------------------------------------------
250
251  void DataArray::getArray(float *output)
252  {
253    /// @details
254    /// The pixel value array is written to output. This needs to be defined
255    ///  beforehand: no checking is done on the memory.
256    /// \param output The array that is written to.
257
258    for(size_t i=0;i<this->numPixels;i++) output[i] = this->array[i];
259  }
260  //--------------------------------------------------------------------
261
262  void DataArray::saveArray(float *input, size_t size)
263  {
264    /// @details
265    /// Saves the array in input to the pixel array DataArray::array.
266    /// The size of the array given must be the same as the current number of
267    /// pixels, else an error message is returned and nothing is done.
268    /// \param input The array of values to be saved.
269    /// \param size The size of input.
270
271    if(size != this->numPixels){
272      DUCHAMPERROR("DataArray::saveArray", "Input array different size to existing array. Cannot save.");
273    }
274    else {
275      if(this->numPixels>0 && this->arrayAllocated) delete [] this->array;
276      this->numPixels = size;
277      this->array = new float[size];
278      this->arrayAllocated = true;
279      for(size_t i=0;i<size;i++) this->array[i] = input[i];
280    }
281  }
282  //--------------------------------------------------------------------
283
284  void DataArray::addObject(Detection object)
285  {
286    /// \param object The object to be added to the object list.
287
288    // objectList is a vector, so just use push_back()
289    this->objectList->push_back(object);
290  }
291  //--------------------------------------------------------------------
292
293  void DataArray::addObjectList(std::vector <Detection> newlist)
294  {
295    /// \param newlist The list of objects to be added to the object list.
296
297    std::vector<Detection>::iterator obj;
298    for(obj=newlist.begin();obj<newlist.end();obj++) this->objectList->push_back(*obj);
299  }
300  //--------------------------------------------------------------------
301
302  bool DataArray::isDetection(float value)
303  {
304    ///  @details
305    /// Is a given value a detection, based on the statistics in the
306    /// DataArray's StatsContainer?
307    /// \param value The pixel value to test.
308
309    if(par.isBlank(value)) return false;
310    else return Stats.isDetection(value);
311  }
312  //--------------------------------------------------------------------
313
314  bool DataArray::isDetection(size_t voxel)
315  {
316    ///  @details
317    /// Is a given pixel a detection, based on the statistics in the
318    /// DataArray's StatsContainer?
319    /// If the pixel lies outside the valid range for the data array, return false.
320    /// \param voxel Location of the DataArray's pixel to be tested.
321
322    if((voxel<0)||(voxel>this->numPixels)) return false;
323    else if(par.isBlank(this->array[voxel])) return false;
324    else return Stats.isDetection(this->array[voxel]);
325  } 
326  //--------------------------------------------------------------------
327
328  std::ostream& operator<< ( std::ostream& theStream, DataArray &array)
329  {
330    /// @details
331    /// A way to print out the pixel coordinates & flux values of the
332    /// list of detected objects belonging to the DataArray.
333    /// These are formatted nicely according to the << operator for Detection,
334    ///  with a line indicating the number of detections at the start.
335    /// \param theStream The ostream object to which the output should be sent.
336    /// \param array The DataArray containing the list of objects.
337
338    for(int i=0;i<array.numDim;i++){
339      if(i>0) theStream<<"x";
340      theStream<<array.axisDim[i];
341    }
342    theStream<<std::endl;
343
344    theStream<<"Threshold\tmiddle\tspread\trobust\n" << array.stats().getThreshold() << "\t";
345    if(array.pars().getFlagUserThreshold())
346      theStream << "0.0000\t" << array.stats().getThreshold() << "\t";
347    else
348      theStream << array.stats().getMiddle() << " " << array.stats().getSpread() << "\t";
349    theStream << array.stats().getRobust()<<"\n";
350
351    theStream<<array.objectList->size()<<" detections:\n--------------\n";
352    std::vector<Detection>::iterator obj;
353    for(obj=array.objectList->begin();obj<array.objectList->end();obj++){
354      theStream << "Detection #" << obj->getID()<<std::endl;
355      Detection *newobj = new Detection;
356      *newobj = *obj;
357      newobj->addOffsets();
358      theStream<<*newobj;
359      delete newobj;
360    }
361    theStream<<"--------------\n";
362    return theStream;
363  }
364
365  /****************************************************************/
366  /////////////////////////////////////////////////////////////
367  //// Functions for Cube class
368  /////////////////////////////////////////////////////////////
369
370  Cube::Cube()
371  {
372    /// @details
373    /// Basic Constructor for Cube class.
374    /// numDim set to 3, but numPixels to 0 and all bool flags to false.
375    /// No allocation done.
376
377    numPixels=0; numDim=3;
378    reconExists = false; reconAllocated = false; baselineAllocated = false;
379  }
380  //--------------------------------------------------------------------
381
382  Cube::Cube(size_t size)
383  {
384    /// @details
385    /// Alternative Cube constructor, where size is given but not individual
386    ///  dimensions. Arrays are allocated as appropriate (according to the
387    ///  relevant flags in Param set), but the Cube::axisDim array is not.
388
389    this->reconAllocated = false;
390    this->baselineAllocated = false;
391    this->axisDimAllocated = false;
392    this->arrayAllocated = false;
393    this->numPixels = this->numDim = 0;
394    if(size<0){
395      DUCHAMPERROR("Cube(size)","Negative size -- could not define Cube");
396    }
397    else{
398      if(size>0){
399        this->array = new float[size];
400        this->arrayAllocated = true;
401        if(this->par.getFlagATrous()||this->par.getFlagSmooth()){
402          this->recon = new float[size];
403          this->reconAllocated = true;
404        }
405        if(this->par.getFlagBaseline()){
406          this->baseline = new float[size];
407          this->baselineAllocated = true;
408        }
409      }
410      this->numPixels = size;
411      this->axisDim = new size_t[3];
412      this->axisDimAllocated = true;
413      this->numDim = 3;
414      this->reconExists = false;
415    }
416  }
417  //--------------------------------------------------------------------
418
419  Cube::Cube(size_t *dimensions)
420  {
421    /// Alternative Cube constructor, where sizes of dimensions are given.
422    /// Arrays are allocated as appropriate (according to the
423    ///  relevant flags in Param set), as is the Cube::axisDim array.
424
425    int size   = dimensions[0] * dimensions[1] * dimensions[2];
426    int imsize = dimensions[0] * dimensions[1];
427    this->reconAllocated = false;
428    this->baselineAllocated = false;
429    this->axisDimAllocated = false;
430    this->arrayAllocated = false;
431    this->numPixels = this->numDim = 0;
432    if((size<0) || (imsize<0) ){
433      DUCHAMPERROR("Cube(dimArray)","Negative size -- could not define Cube");
434    }
435    else{
436      this->numPixels = size;
437      if(size>0){
438        this->array      = new float[size];
439        this->arrayAllocated = true;
440        this->detectMap  = new short[imsize];
441        if(this->par.getFlagATrous()||this->par.getFlagSmooth()){
442          this->recon    = new float[size];
443          this->reconAllocated = true;
444        }
445        if(this->par.getFlagBaseline()){
446          this->baseline = new float[size];
447          this->baselineAllocated = true;
448        }
449      }
450      this->numDim  = 3;
451      this->axisDim = new size_t[3];
452      this->axisDimAllocated = true;
453      for(int i=0;i<3     ;i++) this->axisDim[i]   = dimensions[i];
454      for(int i=0;i<imsize;i++) this->detectMap[i] = 0;
455      this->reconExists = false;
456    }
457  }
458  //--------------------------------------------------------------------
459
460  Cube::~Cube()
461  {
462    /// @details
463    ///  The destructor deletes the memory allocated for Cube::detectMap, and,
464    ///  if these have been allocated, Cube::recon and Cube::baseline.
465
466    if(this->numPixels>0 && this->arrayAllocated) delete [] this->detectMap;
467    if(this->reconAllocated)    delete [] this->recon;
468    if(this->baselineAllocated) delete [] this->baseline;
469  }
470  //--------------------------------------------------------------------
471
472  Cube::Cube(const Cube &c):
473    DataArray(c)
474  {
475    this->operator=(c);
476  }
477  //--------------------------------------------------------------------
478
479  Cube& Cube::operator=(const Cube &c)
480  {
481    if(this==&c) return *this;
482    if(this->arrayAllocated) delete [] this->detectMap;
483    ((DataArray &) *this) = c;
484    this->reconExists = c.reconExists;
485    if(this->reconAllocated) delete [] this->recon;
486    this->reconAllocated = c.reconAllocated;
487    if(this->reconAllocated) {
488      this->recon = new float[this->numPixels];
489      for(size_t i=0;i<size_t(this->numPixels);i++) this->recon[i] = c.recon[i];
490    }
491    if(this->arrayAllocated){
492      this->detectMap = new short[this->axisDim[0]*this->axisDim[1]];
493      for(size_t i=0;i<size_t(this->axisDim[0]*this->axisDim[1]);i++) this->detectMap[i] = c.detectMap[i];
494    }
495    if(this->baselineAllocated) delete [] this->baseline;
496    this->baselineAllocated = c.baselineAllocated;
497    if(this->baselineAllocated){
498      this->baseline = new float[this->numPixels];
499      for(size_t i=0;i<size_t(this->numPixels);i++) this->baseline[i] = c.baseline[i];
500    }
501    this->head = c.head;
502    this->fullCols = c.fullCols;
503    this->logCols = c.logCols;
504    return *this;
505  }
506  //--------------------------------------------------------------------
507
508  Cube* Cube::slice(Section subsection)
509  {
510    Cube *output = new Cube;
511    Section thisSection;
512    std::string nullsec=nullSection(this->numDim);
513    if(this->par.section().isParsed()) thisSection=this->par.section();
514    else{
515      thisSection = Section(nullsec);
516      thisSection.parse(this->axisDim, this->numDim);
517    }
518
519    subsection.parse(this->axisDim, this->numDim);
520    if(subsection.isValid()){
521      output->par = this->par;
522      output->par.section() = thisSection * subsection;
523      output->par.setXOffset(output->par.getXOffset()+subsection.getStart(0));
524      output->par.setYOffset(output->par.getYOffset()+subsection.getStart(1));
525      output->par.setZOffset(output->par.getZOffset()+subsection.getStart(2));
526      output->head = this->head;
527      // correct the reference pixel in the WCS
528      output->head.WCS().crpix[output->head.WCS().lng] -= subsection.getStart(output->head.WCS().lng);
529      output->head.WCS().crpix[output->head.WCS().lat] -= subsection.getStart(output->head.WCS().lat);
530      if(output->head.WCS().spec>0)
531        output->head.WCS().crpix[output->head.WCS().spec] -= subsection.getStart(output->head.WCS().spec);
532      output->Stats = this->Stats;
533      output->fullCols = this->fullCols;
534      output->logCols = this->logCols;
535      size_t *dims = new size_t[3];
536      for(size_t i=0;i<3;i++){
537        dims[i] = subsection.getDimList()[i];
538        std::cout << "Dim " << i+1 << " = " << dims[i] << "\n";
539      }
540     
541      output->initialiseCube(dims,true);
542      for(size_t z=0;z<output->axisDim[2];z++){
543        for(size_t y=0;y<output->axisDim[1];y++){
544          for(size_t x=0;x<output->axisDim[0];x++){
545            size_t impos=x+y*output->axisDim[0];
546            size_t pos=impos+z*output->axisDim[0]*output->axisDim[1];
547            if(pos>=output->numPixels) DUCHAMPERROR("cube slicer","Out of bounds in new Cube");
548            size_t imposIn=(x+subsection.getStart(0)) + (y+subsection.getStart(1))*this->axisDim[0];
549            size_t posIn=imposIn + (z+subsection.getStart(2))*this->axisDim[0]*this->axisDim[1];
550            if(posIn>=this->numPixels) DUCHAMPERROR("cube slicer","Out of bounds in new Cube");
551            output->array[pos] = this->array[posIn];
552            output->detectMap[impos] = this->detectMap[imposIn];
553            if(this->reconAllocated) output->recon[pos] = this->recon[posIn];
554            if(this->baselineAllocated) output->baseline[pos] = this->baseline[posIn];
555          }
556        }
557      }
558       std::cout << this->par << "\n"<<output->par <<"\n";
559    }
560    else{
561      DUCHAMPERROR("cube slicer","Subsection does not parse");
562    }
563
564    return output;
565
566  }
567  //--------------------------------------------------------------------
568
569  OUTCOME Cube::initialiseCube(long *dimensions, bool allocateArrays)
570  {
571    int numAxes = this->head.getNumAxes();
572    if(numAxes<=0) numAxes=3;
573    size_t *dim = new size_t[numAxes];
574    for(int i=0;i<numAxes;i++) dim[i]=dimensions[i];
575    OUTCOME outcome=this->initialiseCube(dim,allocateArrays);
576    delete [] dim;
577    return outcome;
578  }
579
580
581  OUTCOME Cube::initialiseCube(size_t *dimensions, bool allocateArrays)
582  {
583    /// @details
584    ///  This function will set the sizes of all arrays that will be used by Cube.
585    ///  It will also define the values of the axis dimensions: this will be done
586    ///   using the WCS in the FitsHeader class, so the WCS needs to be good and
587    ///   have three axes. If this is not the case, the axes are assumed to be
588    ///   ordered in the sense of lng,lat,spc.
589    ///
590    ///  \param dimensions An array of values giving the dimensions (sizes) for
591    ///  all axes. 
592    ///  \param allocateArrays A flag indicating whether to allocate
593    ///  the memory for the data arrays: the default is true. The
594    ///  dimension arrays will be allocated and filled.
595
596    int lng,lat,spc;
597    size_t size,imsize;
598 
599    int numAxes = this->head.getNumAxes();
600    if(numAxes<=0) numAxes=3;
601
602    if(this->head.isWCS() && (numAxes>=3) && (this->head.WCS().spec>=0)){
603      // if there is a WCS and there is at least 3 axes
604      lng = this->head.WCS().lng;
605      lat = this->head.WCS().lat;
606      spc = this->head.WCS().spec;
607    }
608    else{
609      // just take dimensions[] at face value
610      lng = 0;
611      lat = 1;
612      spc = 2;
613    }
614
615    size   = dimensions[lng];
616    if(numAxes>1) size *= dimensions[lat];
617    if(this->head.canUseThirdAxis() && numAxes>spc) size *= dimensions[spc];
618
619    imsize = dimensions[lng];
620    if(numAxes>1) imsize *= dimensions[lat];
621
622    this->reconAllocated = false;
623    this->baselineAllocated = false;
624
625    if(this->axisDimAllocated){
626      delete [] this->axisDim;
627      this->axisDimAllocated = false;
628    }
629
630    if(this->arrayAllocated){
631      delete [] this->array;
632      delete [] this->detectMap;
633      this->arrayAllocated = false;
634    }
635    if(this->reconAllocated){
636      delete [] this->recon;
637      this->reconAllocated = false;
638    }
639    if(this->baselineAllocated){
640      delete [] this->baseline;
641      this->baselineAllocated = false;
642    }
643
644    if((size<0) || (imsize<0) ) {
645      DUCHAMPERROR("Cube::initialiseCube(dimArray)", "Negative size -- could not define Cube.");
646      return FAILURE;
647    }
648    else{
649      this->numPixels = size;
650      this->numDim  = 3;
651
652      this->axisDim = new size_t[this->numDim];
653      this->axisDimAllocated = true;
654      this->axisDim[0] = dimensions[lng];
655      if(numAxes>1) this->axisDim[1] = dimensions[lat];
656      else this->axisDim[1] = 1;
657      if(this->head.canUseThirdAxis() && numAxes>spc) this->axisDim[2] = dimensions[spc];
658      else this->axisDim[2] = 1;
659
660      this->numNondegDim=0;
661      for(int i=0;i<3;i++) if(this->axisDim[i]>1) this->numNondegDim++;
662
663      if(this->numNondegDim == 1){
664        if(!head.isWCS()) std::swap(this->axisDim[0],this->axisDim[2]);
665        imsize=this->axisDim[2];
666      }
667
668      bool haveChanged=false;
669      int change=0;
670      if(this->par.getMinPix() > this->axisDim[0]*this->axisDim[1]){
671        DUCHAMPWARN("Cube::initialiseCube", "The value of minPix ("<<this->par.getMinPix()<<") is greater than the image size. Setting to "<<this->axisDim[0]*this->axisDim[1]);
672        change=this->par.getMinPix() - this->axisDim[0]*this->axisDim[1];
673        haveChanged=true;
674        this->par.setMinPix(this->axisDim[0]*this->axisDim[1]);
675      }
676      if(this->par.getMinChannels() > this->axisDim[2]){
677        DUCHAMPWARN("Cube::initialiseCube", "The value of minChannels ("<<this->par.getMinChannels()<<") is greater than the spectral size. Setting to "<<this->axisDim[2]);
678        change=this->par.getMinPix() - this->axisDim[0]*this->axisDim[1];
679        haveChanged=true;
680        this->par.setMinChannels(this->axisDim[2]);
681      }
682      if(haveChanged){
683        DUCHAMPWARN("Cube::initialiseCube","Reducing minVoxels to "<<this->par.getMinVoxels() - change<<" to accomodate these changes" );
684        this->par.setMinVoxels(this->par.getMinVoxels() - change);
685      }
686     
687      if(this->par.getFlagSmooth()){
688        if(this->par.getSmoothType()=="spectral" && this->numNondegDim==2){
689          DUCHAMPWARN("Cube::initialiseCube", "Spectral smooth requested, but have a 2D image. Setting flagSmooth=false");
690          this->par.setFlagSmooth(false);
691        }
692        if(this->par.getSmoothType()=="spatial" && this->numNondegDim==1){
693          DUCHAMPWARN("Cube::initialiseCube", "Spatial smooth requested, but have a 1D image. Setting flagSmooth=false");
694          this->par.setFlagSmooth(false);
695        }
696      }
697      if(this->par.getFlagATrous()){
698        for(int d=3; d>=1; d--){
699          if(this->par.getReconDim()==d && this->numNondegDim==(d-1)){
700            DUCHAMPWARN("Cube::initialiseCube", d << "D reconstruction requested, but image is " << d-1 <<"D. Setting flagAtrous=false");
701            this->par.setFlagATrous(false);
702          }
703        }
704      }
705
706      if(allocateArrays && this->par.isVerbose()) this->reportMemorySize(std::cout,allocateArrays);
707
708      this->reconExists = false;
709      if(size>0 && allocateArrays){
710        this->array      = new float[size];
711        this->arrayAllocated = true;
712        this->detectMap  = new short[imsize];
713        for(size_t i=0;i<imsize;i++) this->detectMap[i] = 0;
714        if(this->par.getFlagATrous() || this->par.getFlagSmooth()){
715          this->recon    = new float[size];
716          this->reconAllocated = true;
717          for(size_t i=0;i<size;i++) this->recon[i] = 0.;
718        }
719        if(this->par.getFlagBaseline()){
720          this->baseline = new float[size];
721          this->baselineAllocated = true;
722          for(size_t i=0;i<size;i++) this->baseline[i] = 0.;
723        }
724      }
725    }
726    return SUCCESS;
727  }
728  //--------------------------------------------------------------------
729
730  void Cube::reportMemorySize(std::ostream &theStream, bool allocateArrays)
731  {
732    std::string unitlist[4]={"kB","MB","GB","TB"};
733    size_t size=axisDim[0]*axisDim[1]*axisDim[2];
734    size_t imsize=axisDim[0]*axisDim[1];
735   
736      // Calculate and report the total size of memory to be allocated.
737      float allocSize=3*sizeof(size_t);  // axisDim
738      float arrAllocSize=0.;
739      if(size>0 && allocateArrays){
740        allocSize += size * sizeof(float); // array
741        arrAllocSize = size*sizeof(float);
742        allocSize += imsize * sizeof(short); // detectMap
743        if(this->par.getFlagATrous() || this->par.getFlagSmooth())
744          allocSize += size * sizeof(float); // recon
745        if(this->par.getFlagBaseline())
746          allocSize += size * sizeof(float); // baseline
747      }
748      std::string units="bytes";
749      for(int i=0;i<4 && allocSize>1024.;i++){
750        allocSize/=1024.;
751        arrAllocSize /= 1024.;
752        units=unitlist[i];
753      }
754
755      theStream << "\n About to allocate " << allocSize << units;
756      if(arrAllocSize > 0.) theStream << " of which " << arrAllocSize << units << " is for the image\n";
757      else theStream << "\n";
758  }
759
760
761  bool Cube::is2D()
762  {
763    /// @details
764    ///   Check whether the image is 2-dimensional, by counting
765    ///   the number of dimensions that are greater than 1
766
767    if(this->head.WCS().naxis==2) return true;
768    else{
769      int numDim=0;
770      for(int i=0;i<this->numDim;i++) if(axisDim[i]>1) numDim++;
771      return numDim<=2;
772    }
773
774  }
775  //--------------------------------------------------------------------
776
777  OUTCOME Cube::getCube()
778  { 
779    ///  @details
780    /// A front-end to the Cube::getCube() function, that does
781    ///  subsection checks.
782    /// Assumes the Param is set up properly.
783
784    std::string fname = par.getImageFile();
785    if(par.getFlagSubsection()) fname+=par.getSubsection();
786    return getCube(fname);
787  }
788  //--------------------------------------------------------------------
789
790  void Cube::saveArray(float *input, size_t size)
791  {
792    if(size != this->numPixels){
793      DUCHAMPERROR("Cube::saveArray","Input array different size to existing array (" << size << " cf. " << this->numPixels << "). Cannot save.");
794    }
795    else {
796      if(this->numPixels>0 && this->arrayAllocated) delete [] array;
797      this->numPixels = size;
798      this->array = new float[size];
799      this->arrayAllocated = true;
800      for(size_t i=0;i<size;i++) this->array[i] = input[i];
801    }
802  }
803  //--------------------------------------------------------------------
804
805  void Cube::saveArray(std::vector<float> &input)
806  {
807    /// @details
808    /// Saves the array in input to the pixel array Cube::array.
809    /// The size of the array given must be the same as the current number of
810    /// pixels, else an error message is returned and nothing is done.
811    /// \param input The array of values to be saved.
812
813    if(input.size() != this->numPixels){
814      DUCHAMPERROR("Cube::saveArray","Input array different size to existing array (" << input.size() << " cf. " << this->numPixels << "). Cannot save.");
815    }
816    else {
817      if(this->numPixels>0 && this->arrayAllocated) delete [] this->array;
818      this->numPixels = input.size();
819      this->array = new float[input.size()];
820      this->arrayAllocated = true;
821      for(size_t i=0;i<input.size();i++) this->array[i] = input[i];
822    }
823  }
824  //--------------------------------------------------------------------
825
826  void Cube::saveRecon(float *input, size_t size)
827  {
828    /// @details
829    /// Saves the array in input to the reconstructed array Cube::recon
830    /// The size of the array given must be the same as the current number of
831    /// pixels, else an error message is returned and nothing is done.
832    /// If the recon array has already been allocated, it is deleted first, and
833    /// then the space is allocated.
834    /// Afterwards, the appropriate flags are set.
835    /// \param input The array of values to be saved.
836    /// \param size The size of input.
837
838    if(size != this->numPixels){
839      DUCHAMPERROR("Cube::saveRecon","Input array different size to existing array (" << size << " cf. " << this->numPixels << "). Cannot save.");
840    }
841    else {
842      if(this->numPixels>0){
843        if(this->reconAllocated) delete [] this->recon;
844        this->numPixels = size;
845        this->recon = new float[size];
846        this->reconAllocated = true;
847        for(size_t i=0;i<size;i++) this->recon[i] = input[i];
848        this->reconExists = true;
849      }
850    }
851  }
852  //--------------------------------------------------------------------
853
854  void Cube::getRecon(float *output)
855  {
856    /// @details
857    /// The reconstructed array is written to output. The output array needs to
858    ///  be defined beforehand: no checking is done on the memory.
859    /// \param output The array that is written to.
860
861    // Need check for change in number of pixels!
862    for(size_t i=0;i<this->numPixels;i++){
863      if(this->reconExists) output[i] = this->recon[i];
864      else output[i] = 0.;
865    }
866  }
867  //--------------------------------------------------------------------
868
869  void Cube::removeMW()
870  {
871    /// @details
872    /// The channels corresponding to the Milky Way range (as given by the Param
873    ///  set) are all set to 0 in the pixel array.
874    /// Only done if the appropriate flag is set, and the pixels are not BLANK.
875    /// \deprecated
876
877    if(this->par.getFlagMW()){
878      for(size_t pix=0;pix<this->axisDim[0]*this->axisDim[1];pix++){
879        for(size_t z=0;z<this->axisDim[2];z++){
880          size_t pos = z*this->axisDim[0]*this->axisDim[1] + pix;
881          if(!this->isBlank(pos) && this->par.isInMW(z)) this->array[pos]=0.;
882        }
883      }
884    }
885  }
886  //--------------------------------------------------------------------
887
888  void Cube::setCubeStats()
889  {
890    ///   @details
891    ///   Calculates the full statistics for the cube:
892    ///     mean, rms, median, madfm
893    ///   Only do this if the threshold has not been defined (ie. is still 0.,
894    ///    its default).
895    ///   Also work out the threshold and store it in the par set.
896    ///   
897    ///   Different from Cube::setCubeStatsOld() as it doesn't use the
898    ///    getStats functions but has own versions of them hardcoded to
899    ///    ignore BLANKs and MW channels. This saves on memory usage -- necessary
900    ///    for dealing with very big files.
901    ///
902    ///   Three cases exist:
903    ///  <ul><li>Simple case, with no reconstruction/smoothing: all stats
904    ///          calculated from the original array.
905    ///      <li>Wavelet reconstruction: mean & median calculated from the
906    ///          original array, and stddev & madfm from the residual.
907    ///      <li>Smoothing: all four stats calculated from the recon array
908    ///          (which holds the smoothed data).
909    ///  </ul>
910
911    if(this->par.getFlagUserThreshold() ){
912      // if the user has defined a threshold, set this in the StatsContainer
913      this->Stats.setThreshold( this->par.getThreshold() );
914    }
915    else{
916      // only work out the stats if we need to.
917      // the only reason we don't is if the user has specified a threshold.
918   
919      this->Stats.setRobust(this->par.getFlagRobustStats());
920
921      if(this->par.isVerbose())
922        std::cout << "Calculating the cube statistics... " << std::flush;
923   
924      // size_t xysize = this->axisDim[0]*this->axisDim[1];
925
926      bool *mask = new bool[this->numPixels];
927      size_t vox=0,goodSize = 0;
928      for(size_t z=0;z<this->axisDim[2];z++){
929        for(size_t y=0;y<this->axisDim[1];y++){
930          for(size_t x=0;x<this->axisDim[0];x++){
931            //      vox = z * xysize + y*this->axisDim[0] + x;
932            bool isBlank=this->isBlank(vox);
933            bool isMW = this->par.isInMW(z);
934            bool statOK = this->par.isStatOK(x,y,z);
935            mask[vox] = (!isBlank && !isMW && statOK );
936            if(mask[vox]) goodSize++;
937            vox++;
938          }
939        }
940      }
941
942      //      float mean,median,stddev,madfm;
943      if( this->par.getFlagATrous() ){
944        // Case #2 -- wavelet reconstruction
945        // just get mean & median from orig array, and rms & madfm from
946        // residual recompute array values to be residuals & then find
947        // stddev & madfm
948        if(!this->reconExists){
949          DUCHAMPERROR("setCubeStats", "Reconstruction not yet done! Cannot calculate stats!");
950        }
951        else{
952          float *tempArray = new float[goodSize];
953
954          goodSize=0;
955          vox=0;
956          for(size_t z=0;z<this->axisDim[2];z++){
957            for(size_t y=0;y<this->axisDim[1];y++){
958              for(size_t x=0;x<this->axisDim[0];x++){
959                //              vox = z * xysize + y*this->axisDim[0] + x;
960                if(mask[vox]) tempArray[goodSize++] = this->array[vox];
961                vox++;
962              }
963            }
964          }
965
966          // First, find the mean of the original array. Store it.
967          this->Stats.setMean( findMean<float>(tempArray, goodSize) );
968       
969          // Now sort it and find the median. Store it.
970          this->Stats.setMedian( findMedian<float>(tempArray, goodSize, true) );
971
972          // Now calculate the residuals and find the mean & median of
973          // them. We don't store these, but they are necessary to find
974          // the sttdev & madfm.
975          goodSize = 0;
976          //      for(int p=0;p<xysize;p++){
977          vox=0;
978          for(size_t z=0;z<this->axisDim[2];z++){
979            for(size_t y=0;y<this->axisDim[1];y++){
980              for(size_t x=0;x<this->axisDim[0];x++){
981                //            vox = z * xysize + p;
982              if(mask[vox])
983                tempArray[goodSize++] = this->array[vox] - this->recon[vox];
984              vox++;
985              }
986            }
987          }
988           
989          this->Stats.setStddev( findStddev<float>(tempArray, goodSize) );
990
991          // Now find the madfm of the residuals. Store it.
992          this->Stats.setMadfm( findMADFM(tempArray, goodSize, true) );
993
994          delete [] tempArray;
995        }
996      }
997      else if(this->par.getFlagSmooth()) {
998        // Case #3 -- smoothing
999        // get all four stats from the recon array, which holds the
1000        // smoothed data. This can just be done with the
1001        // StatsContainer::calculate function, using the mask generated
1002        // earlier.
1003        if(!this->reconExists){
1004          DUCHAMPERROR("setCubeStats","Smoothing not yet done! Cannot calculate stats!");
1005        }
1006        else this->Stats.calculate(this->recon,this->numPixels,mask);
1007      }
1008      else{
1009        // Case #1 -- default case, with no smoothing or reconstruction.
1010        // get all four stats from the original array. This can just be
1011        // done with the StatsContainer::calculate function, using the
1012        // mask generated earlier.
1013        this->Stats.calculate(this->array,this->numPixels,mask);
1014      }
1015
1016      this->Stats.setUseFDR( this->par.getFlagFDR() );
1017      // If the FDR method has been requested, define the P-value
1018      // threshold
1019      if(this->par.getFlagFDR())  this->setupFDR();
1020      else{
1021        // otherwise, calculate threshold based on the requested SNR cut
1022        // level, and then set the threshold parameter in the Par set.
1023        this->Stats.setThresholdSNR( this->par.getCut() );
1024        this->par.setThreshold( this->Stats.getThreshold() );
1025      }
1026   
1027      delete [] mask;
1028
1029    }
1030
1031    if(this->par.isVerbose()){
1032      std::cout << "Using ";
1033      if(this->par.getFlagFDR()) std::cout << "effective ";
1034      std::cout << "flux threshold of: ";
1035      float thresh = this->Stats.getThreshold();
1036      if(this->par.getFlagNegative()) thresh *= -1.;
1037      std::cout << thresh;
1038      if(this->par.getFlagGrowth()){
1039        std::cout << " and growing to threshold of: ";
1040        if(this->par.getFlagUserGrowthThreshold()) thresh= this->par.getGrowthThreshold();
1041        else thresh= this->Stats.snrToValue(this->par.getGrowthCut());
1042        if(this->par.getFlagNegative()) thresh *= -1.;
1043        std::cout << thresh;
1044      }
1045      std::cout << std::endl;
1046    }
1047
1048  }
1049  //--------------------------------------------------------------------
1050
1051  void Cube::setupFDR()
1052  {
1053    /// @details
1054    ///  Call the setupFDR(float *) function on the pixel array of the
1055    ///  cube. This is the usual way of running it.
1056    ///
1057    ///  However, if we are in smoothing mode, we calculate the FDR
1058    ///  parameters using the recon array, which holds the smoothed
1059    ///  data. Gives an error message if the reconExists flag is not set.
1060
1061    if(this->par.getFlagSmooth())
1062      if(this->reconExists) this->setupFDR(this->recon);
1063      else{
1064        DUCHAMPERROR("setupFDR", "Smoothing not done properly! Using original array for defining threshold.");
1065        this->setupFDR(this->array);
1066      }
1067    else if( this->par.getFlagATrous() ){
1068      if(this->reconExists) this->setupFDR(this->recon);
1069      else{
1070        DUCHAMPERROR("setupFDR", "Reconstruction not done properly! Using original array for defining threshold.");
1071        this->setupFDR(this->array);
1072      }
1073    }
1074    else{
1075      this->setupFDR(this->array);
1076    }
1077  }
1078  //--------------------------------------------------------------------
1079
1080  void Cube::setupFDR(float *input)
1081  {
1082    ///   @details
1083    ///   Determines the critical Probability value for the False
1084    ///   Discovery Rate detection routine. All pixels in the given arry
1085    ///   with Prob less than this value will be considered detections.
1086    ///
1087    ///   Note that the Stats of the cube need to be calculated first.
1088    ///
1089    ///   The Prob here is the probability, assuming a Normal
1090    ///   distribution, of obtaining a value as high or higher than the
1091    ///   pixel value (ie. only the positive tail of the PDF).
1092    ///
1093    ///   The probabilities are calculated using the
1094    ///   StatsContainer::getPValue(), which calculates the z-statistic,
1095    ///   and then the probability via
1096    ///   \f$0.5\operatorname{erfc}(z/\sqrt{2})\f$ -- giving the positive
1097    ///   tail probability.
1098
1099    // first calculate p-value for each pixel -- assume Gaussian for now.
1100
1101    float *orderedP = new float[this->numPixels];
1102    size_t count = 0;
1103    for(size_t x=0;x<this->axisDim[0];x++){
1104      for(size_t y=0;y<this->axisDim[1];y++){
1105        for(size_t z=0;z<this->axisDim[2];z++){
1106          size_t pix = z * this->axisDim[0]*this->axisDim[1] +
1107            y*this->axisDim[0] + x;
1108
1109          if(!(this->par.isBlank(this->array[pix])) && !this->par.isInMW(z)){
1110            // only look at non-blank, valid pixels
1111            //            orderedP[count++] = this->Stats.getPValue(this->array[pix]);
1112            orderedP[count++] = this->Stats.getPValue(input[pix]);
1113          }
1114        }
1115      }
1116    }
1117
1118    // now order them
1119    std::stable_sort(orderedP,orderedP+count);
1120 
1121    // now find the maximum P value.
1122    size_t max = 0;
1123    double cN = 0.;
1124    // Calculate number of correlated pixels. Assume all spatial
1125    // pixels within the beam are correlated, and multiply this by the
1126    // number of correlated pixels as determined by the beam
1127    int numVox;
1128    if(this->head.beam().isDefined()) numVox = int(ceil(this->head.beam().area()));
1129    else  numVox = 1;
1130    if(this->head.canUseThirdAxis()) numVox *= this->par.getFDRnumCorChan();
1131    for(int psfCtr=1;psfCtr<=numVox;psfCtr++) cN += 1./float(psfCtr);
1132
1133    double slope = this->par.getAlpha()/cN;
1134    for(size_t loopCtr=0;loopCtr<count;loopCtr++) {
1135      if( orderedP[loopCtr] < (slope * double(loopCtr+1)/ double(count)) ){
1136        max = loopCtr;
1137      }
1138    }
1139
1140    this->Stats.setPThreshold( orderedP[max] );
1141
1142
1143    // Find real value of the P threshold by finding the inverse of the
1144    //  error function -- root finding with brute force technique
1145    //  (relatively slow, but we only do it once).
1146    double zStat     = 0.;
1147    double deltaZ    = 0.1;
1148    double tolerance = 1.e-6;
1149    double initial   = 0.5 * erfc(zStat/M_SQRT2) - this->Stats.getPThreshold();
1150    do{
1151      zStat+=deltaZ;
1152      double current = 0.5 * erfc(zStat/M_SQRT2) - this->Stats.getPThreshold();
1153      if((initial*current)<0.){
1154        zStat-=deltaZ;
1155        deltaZ/=2.;
1156      }
1157    }while(deltaZ>tolerance);
1158    this->Stats.setThreshold( zStat*this->Stats.getSpread() +
1159                              this->Stats.getMiddle() );
1160
1161    ///////////////////////////
1162    //   if(TESTING){
1163    //     std::stringstream ss;
1164    //     float *xplot = new float[2*max];
1165    //     for(int i=0;i<2*max;i++) xplot[i]=float(i)/float(count);
1166    //     cpgopen("latestFDR.ps/vcps");
1167    //     cpgpap(8.,1.);
1168    //     cpgslw(3);
1169    //     cpgenv(0,float(2*max)/float(count),0,orderedP[2*max],0,0);
1170    //     cpglab("i/N (index)", "p-value","");
1171    //     cpgpt(2*max,xplot,orderedP,DOT);
1172
1173    //     ss.str("");
1174    //     ss << "\\gm = " << this->Stats.getMiddle();
1175    //     cpgtext(max/(4.*count),0.9*orderedP[2*max],ss.str().c_str());
1176    //     ss.str("");
1177    //     ss << "\\gs = " << this->Stats.getSpread();
1178    //     cpgtext(max/(4.*count),0.85*orderedP[2*max],ss.str().c_str());
1179    //     ss.str("");
1180    //     ss << "Slope = " << slope;
1181    //     cpgtext(max/(4.*count),0.8*orderedP[2*max],ss.str().c_str());
1182    //     ss.str("");
1183    //     ss << "Alpha = " << this->par.getAlpha();
1184    //     cpgtext(max/(4.*count),0.75*orderedP[2*max],ss.str().c_str());
1185    //     ss.str("");
1186    //     ss << "c\\dN\\u = " << cN;
1187    //     cpgtext(max/(4.*count),0.7*orderedP[2*max],ss.str().c_str());
1188    //     ss.str("");
1189    //     ss << "max = "<<max << " (out of " << count << ")";
1190    //     cpgtext(max/(4.*count),0.65*orderedP[2*max],ss.str().c_str());
1191    //     ss.str("");
1192    //     ss << "Threshold = "<<zStat*this->Stats.getSpread()+this->Stats.getMiddle();
1193    //     cpgtext(max/(4.*count),0.6*orderedP[2*max],ss.str().c_str());
1194 
1195    //     cpgslw(1);
1196    //     cpgsci(RED);
1197    //     cpgmove(0,0);
1198    //     cpgdraw(1,slope);
1199    //     cpgsci(BLUE);
1200    //     cpgsls(DOTTED);
1201    //     cpgmove(0,orderedP[max]);
1202    //     cpgdraw(2*max/float(count),orderedP[max]);
1203    //     cpgmove(max/float(count),0);
1204    //     cpgdraw(max/float(count),orderedP[2*max]);
1205    //     cpgsci(GREEN);
1206    //     cpgsls(SOLID);
1207    //     for(int i=1;i<=10;i++) {
1208    //       ss.str("");
1209    //       ss << float(i)/2. << "\\gs";
1210    //       float prob = 0.5*erfc((float(i)/2.)/M_SQRT2);
1211    //       cpgtick(0, 0, 0, orderedP[2*max],
1212    //        prob/orderedP[2*max],
1213    //        0, 1, 1.5, 90., ss.str().c_str());
1214    //     }
1215    //     cpgend();
1216    //     delete [] xplot;
1217    //   }
1218    delete [] orderedP;
1219
1220  }
1221  //--------------------------------------------------------------------
1222
1223  void Cube::Search()
1224  {
1225    /// @details
1226    /// This acts as a switching function to select the correct searching function based on the user's parameters.
1227    /// @param verboseFlag If true, text is written to stdout describing the search function being used.
1228    if(this->par.getFlagATrous()){
1229      if(this->par.isVerbose()) std::cout<<"Commencing search in reconstructed cube..."<<std::endl;
1230      this->ReconSearch();
1231    } 
1232    else if(this->par.getFlagSmooth()){
1233      if(this->par.isVerbose()) std::cout<<"Commencing search in smoothed cube..."<<std::endl;
1234      this->SmoothSearch();
1235    }
1236    else{
1237      if(this->par.isVerbose()) std::cout<<"Commencing search in cube..."<<std::endl;
1238      this->CubicSearch();
1239    }
1240
1241  }
1242
1243  bool Cube::isDetection(size_t x, size_t y, size_t z)
1244  {
1245    ///  @details
1246    /// Is a given voxel at position (x,y,z) a detection, based on the statistics
1247    ///  in the Cube's StatsContainer?
1248    /// If the pixel lies outside the valid range for the data array,
1249    /// return false.
1250    /// \param x X-value of the Cube's voxel to be tested.
1251    /// \param y Y-value of the Cube's voxel to be tested.
1252    /// \param z Z-value of the Cube's voxel to be tested.
1253
1254    size_t voxel = z*axisDim[0]*axisDim[1] + y*axisDim[0] + x;
1255    return DataArray::isDetection(array[voxel]);
1256  }
1257  //--------------------------------------------------------------------
1258
1259  void Cube::calcObjectFluxes()
1260  {
1261    /// @details
1262    ///  A function to calculate the fluxes and centroids for each
1263    ///  object in the Cube's list of detections. Uses
1264    ///  Detection::calcFluxes() for each object.
1265
1266    std::vector<Detection>::iterator obj;
1267    for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
1268      obj->calcFluxes(this->array, this->axisDim);
1269      if(this->par.getFlagUserThreshold())
1270        obj->setPeakSNR( obj->getPeakFlux() / this->Stats.getThreshold() );
1271      else
1272        obj->setPeakSNR( (obj->getPeakFlux() - this->Stats.getMiddle()) / this->Stats.getSpread() );
1273    }
1274  }
1275  //--------------------------------------------------------------------
1276
1277  void Cube::calcObjectWCSparams()
1278  {
1279    ///  @details
1280    ///  A function that calculates the WCS parameters for each object in the
1281    ///  Cube's list of detections.
1282    ///  Each object gets an ID number assigned to it (which is simply its order
1283    ///   in the list), and if the WCS is good, the WCS paramters are calculated.
1284
1285    std::vector<Detection>::iterator obj;
1286    int ct=0;
1287    ProgressBar bar;
1288    if(this->par.isVerbose()) bar.init(this->objectList->size());
1289    for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
1290      //      std::cerr << ct << ' ' << this->array << '\n';
1291      if(this->par.isVerbose()) bar.update(ct);
1292      obj->setID(ct++);
1293      if(!obj->hasParams()){
1294        obj->setCentreType(this->par.getPixelCentre());
1295        obj->calcFluxes(this->array,this->axisDim);
1296        //      obj->calcWCSparams(this->array,this->axisDim,this->head);
1297        obj->calcWCSparams(this->head);
1298        obj->calcIntegFlux(this->array,this->axisDim,this->head);
1299
1300        if(this->par.getFlagUserThreshold())
1301          obj->setPeakSNR( obj->getPeakFlux() / this->Stats.getThreshold() );
1302        else
1303          obj->setPeakSNR( (obj->getPeakFlux() - this->Stats.getMiddle()) / this->Stats.getSpread() );
1304      }
1305    } 
1306    if(this->par.isVerbose()) bar.remove();
1307
1308    if(!this->head.isWCS()){
1309      // if the WCS is bad, set the object names to Obj01 etc
1310      int numspaces = int(log10(this->objectList->size())) + 1;
1311      std::stringstream ss;
1312      for(size_t i=0;i<this->objectList->size();i++){
1313        ss.str("");
1314        ss << "Obj" << std::setfill('0') << std::setw(numspaces) << i+1;
1315        this->objectList->at(i).setName(ss.str());
1316      }
1317    }
1318 
1319  }
1320  //--------------------------------------------------------------------
1321
1322  void Cube::calcObjectWCSparams(std::vector< std::vector<PixelInfo::Voxel> > bigVoxList)
1323  {
1324    ///  @details
1325    ///  A function that calculates the WCS parameters for each object in the
1326    ///  Cube's list of detections.
1327    ///  Each object gets an ID number assigned to it (which is simply its order
1328    ///   in the list), and if the WCS is good, the WCS paramters are calculated.
1329    ///
1330    ///  This version uses vectors of Voxels to define the fluxes.
1331    ///
1332    /// \param bigVoxList A vector of vectors of Voxels, with the same
1333    /// number of elements as this->objectList, where each element is a
1334    /// vector of Voxels corresponding to the same voxels in each
1335    /// detection and indicating the flux of each voxel.
1336 
1337    std::vector<Detection>::iterator obj;
1338    int ct=0;
1339    for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
1340      obj->setID(ct+1);
1341      if(!obj->hasParams()){
1342        obj->setCentreType(this->par.getPixelCentre());
1343        obj->calcFluxes(bigVoxList[ct]);
1344        obj->calcWCSparams(this->head);
1345        obj->calcIntegFlux(this->axisDim[2],bigVoxList[ct],this->head);
1346       
1347        if(this->par.getFlagUserThreshold())
1348          obj->setPeakSNR( obj->getPeakFlux() / this->Stats.getThreshold() );
1349        else
1350          obj->setPeakSNR( (obj->getPeakFlux() - this->Stats.getMiddle()) / this->Stats.getSpread() );
1351      }
1352      ct++;
1353    } 
1354
1355    if(!this->head.isWCS()){
1356      // if the WCS is bad, set the object names to Obj01 etc
1357      int numspaces = int(log10(this->objectList->size())) + 1;
1358      std::stringstream ss;
1359      for(size_t i=0;i<this->objectList->size();i++){
1360        ss.str("");
1361        ss << "Obj" << std::setfill('0') << std::setw(numspaces) << i+1;
1362        this->objectList->at(i).setName(ss.str());
1363      }
1364    }
1365 
1366  }
1367  //--------------------------------------------------------------------
1368
1369  void Cube::calcObjectWCSparams(std::map<PixelInfo::Voxel,float> &voxelMap)
1370  {
1371    ///  @details
1372    ///  A function that calculates the WCS parameters for each object in the
1373    ///  Cube's list of detections.
1374    ///  Each object gets an ID number assigned to it (which is simply its order
1375    ///   in the list), and if the WCS is good, the WCS paramters are calculated.
1376    ///
1377    ///  This version uses vectors of Voxels to define the fluxes.
1378    ///
1379    /// \param bigVoxList A vector of vectors of Voxels, with the same
1380    /// number of elements as this->objectList, where each element is a
1381    /// vector of Voxels corresponding to the same voxels in each
1382    /// detection and indicating the flux of each voxel.
1383 
1384    std::vector<Detection>::iterator obj;
1385    int ct=0;
1386    for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
1387      obj->setID(ct+1);
1388      if(!obj->hasParams()){
1389        obj->setCentreType(this->par.getPixelCentre());
1390        obj->calcFluxes(voxelMap);
1391        obj->calcWCSparams(this->head);
1392        obj->calcIntegFlux(this->axisDim[2],voxelMap,this->head);
1393       
1394        if(this->par.getFlagUserThreshold())
1395          obj->setPeakSNR( obj->getPeakFlux() / this->Stats.getThreshold() );
1396        else
1397          obj->setPeakSNR( (obj->getPeakFlux() - this->Stats.getMiddle()) / this->Stats.getSpread() );
1398      }
1399      ct++;
1400    } 
1401
1402    if(!this->head.isWCS()){
1403      // if the WCS is bad, set the object names to Obj01 etc
1404      int numspaces = int(log10(this->objectList->size())) + 1;
1405      std::stringstream ss;
1406      for(size_t i=0;i<this->objectList->size();i++){
1407        ss.str("");
1408        ss << "Obj" << std::setfill('0') << std::setw(numspaces) << i+1;
1409        this->objectList->at(i).setName(ss.str());
1410      }
1411    }
1412 
1413  }
1414  //--------------------------------------------------------------------
1415
1416  void Cube::updateDetectMap()
1417  {
1418    /// @details A function that, for each detected object in the
1419    ///  cube's list, increments the cube's detection map by the
1420    ///  required amount at each pixel. Uses
1421    ///  updateDetectMap(Detection).
1422
1423    std::vector<Detection>::iterator obj;
1424    for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
1425      this->updateDetectMap(*obj);
1426    }
1427
1428  }
1429  //--------------------------------------------------------------------
1430
1431  void Cube::updateDetectMap(Detection obj)
1432  {
1433    ///  @details
1434    ///  A function that, for the given object, increments the cube's
1435    ///  detection map by the required amount at each pixel.
1436    ///
1437    ///  \param obj A Detection object that is being incorporated into the map.
1438
1439    std::vector<Voxel> vlist = obj.getPixelSet();
1440    for(std::vector<Voxel>::iterator vox=vlist.begin();vox<vlist.end();vox++) {
1441      if(this->numNondegDim==1)
1442        this->detectMap[vox->getZ()]++;
1443      else
1444        this->detectMap[vox->getX()+vox->getY()*this->axisDim[0]]++;
1445    }
1446  }
1447  //--------------------------------------------------------------------
1448
1449  float Cube::enclosedFlux(Detection obj)
1450  {
1451    ///  @details
1452    ///   A function to calculate the flux enclosed by the range
1453    ///    of pixels detected in the object obj (not necessarily all
1454    ///    pixels will have been detected).
1455    ///
1456    ///   \param obj The Detection under consideration.
1457
1458    obj.calcFluxes(this->array, this->axisDim);
1459    int xsize = obj.getXmax()-obj.getXmin()+1;
1460    int ysize = obj.getYmax()-obj.getYmin()+1;
1461    int zsize = obj.getZmax()-obj.getZmin()+1;
1462    std::vector <float> fluxArray(xsize*ysize*zsize,0.);
1463    for(int x=0;x<xsize;x++){
1464      for(int y=0;y<ysize;y++){
1465        for(int z=0;z<zsize;z++){
1466          fluxArray[x+y*xsize+z*ysize*xsize] =
1467            this->getPixValue(x+obj.getXmin(),
1468                              y+obj.getYmin(),
1469                              z+obj.getZmin());
1470          if(this->par.getFlagNegative())
1471            fluxArray[x+y*xsize+z*ysize*xsize] *= -1.;
1472        }
1473      }
1474    }
1475    float sum = 0.;
1476    for(size_t i=0;i<fluxArray.size();i++)
1477      if(!this->par.isBlank(fluxArray[i])) sum+=fluxArray[i];
1478    return sum;
1479  }
1480  //--------------------------------------------------------------------
1481
1482  void Cube::setupColumns()
1483  {
1484    /// @details
1485    ///  A front-end to the two setup routines in columns.cc. 
1486    ///
1487    ///  This first gets the starting precisions, which may be from
1488    ///  the input parameters. It then sets up the columns (calculates
1489    ///  their widths and precisions and so on based on the values
1490    ///  within). The precisions are also stored in each Detection
1491    ///  object.
1492    ///
1493    ///  Need to have called calcObjectWCSparams() somewhere
1494    ///  beforehand.
1495
1496    std::vector<Detection>::iterator obj;
1497    for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
1498      obj->setVelPrec( this->par.getPrecVel() );
1499      obj->setFpeakPrec( this->par.getPrecFlux() );
1500      obj->setXYZPrec( Column::prXYZ );
1501      obj->setPosPrec( Column::prWPOS );
1502      obj->setFintPrec( this->par.getPrecFlux() );
1503      obj->setSNRPrec( this->par.getPrecSNR() );
1504    }
1505 
1506    this->fullCols.clear();
1507    this->fullCols = getFullColSet(*(this->objectList), this->head);
1508
1509    this->logCols.clear();
1510    this->logCols = getLogColSet(*(this->objectList), this->head);
1511
1512    int vel,fpeak,fint,pos,xyz,snr;
1513    vel = fullCols[VEL].getPrecision();
1514    fpeak = fullCols[FPEAK].getPrecision();
1515    snr = fullCols[SNRPEAK].getPrecision();
1516    xyz = fullCols[X].getPrecision();
1517    xyz = std::max(xyz, fullCols[Y].getPrecision());
1518    xyz = std::max(xyz, fullCols[Z].getPrecision());
1519    if(this->head.isWCS()) fint = fullCols[FINT].getPrecision();
1520    else fint = fullCols[FTOT].getPrecision();
1521    pos = fullCols[WRA].getPrecision();
1522    pos = std::max(pos, fullCols[WDEC].getPrecision());
1523 
1524    for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
1525      obj->setVelPrec(vel);
1526      obj->setFpeakPrec(fpeak);
1527      obj->setXYZPrec(xyz);
1528      obj->setPosPrec(pos);
1529      obj->setFintPrec(fint);
1530      obj->setSNRPrec(snr);
1531    }
1532
1533  }
1534  //--------------------------------------------------------------------
1535
1536  bool Cube::objAtSpatialEdge(Detection obj)
1537  {
1538    ///  @details
1539    ///   A function to test whether the object obj
1540    ///    lies at the edge of the cube's spatial field --
1541    ///    either at the boundary, or next to BLANKs.
1542    ///
1543    ///   \param obj The Detection under consideration.
1544
1545    bool atEdge = false;
1546
1547    size_t pix = 0;
1548    std::vector<Voxel> voxlist = obj.getPixelSet();
1549    while(!atEdge && pix<voxlist.size()){
1550      // loop over each pixel in the object, until we find an edge pixel.
1551      for(int dx=-1;dx<=1;dx+=2){
1552        if( ((voxlist[pix].getX()+dx)<0) ||
1553            ((voxlist[pix].getX()+dx)>=int(this->axisDim[0])) )
1554          atEdge = true;
1555        else if(this->isBlank(voxlist[pix].getX()+dx,
1556                              voxlist[pix].getY(),
1557                              voxlist[pix].getZ()))
1558          atEdge = true;
1559      }
1560      for(int dy=-1;dy<=1;dy+=2){
1561        if( ((voxlist[pix].getY()+dy)<0) ||
1562            ((voxlist[pix].getY()+dy)>=int(this->axisDim[1])) )
1563          atEdge = true;
1564        else if(this->isBlank(voxlist[pix].getX(),
1565                              voxlist[pix].getY()+dy,
1566                              voxlist[pix].getZ()))
1567          atEdge = true;
1568      }
1569      pix++;
1570    }
1571
1572    return atEdge;
1573  }
1574  //--------------------------------------------------------------------
1575
1576  bool Cube::objAtSpectralEdge(Detection obj)
1577  {
1578    ///   @details
1579    ///   A function to test whether the object obj
1580    ///    lies at the edge of the cube's spectral extent --
1581    ///    either at the boundary, or next to BLANKs.
1582    ///
1583    ///   \param obj The Detection under consideration.
1584
1585    bool atEdge = false;
1586
1587    size_t pix = 0;
1588    std::vector<Voxel> voxlist = obj.getPixelSet();
1589    while(!atEdge && pix<voxlist.size()){
1590      // loop over each pixel in the object, until we find an edge pixel.
1591      for(int dz=-1;dz<=1;dz+=2){
1592        if( ((voxlist[pix].getZ()+dz)<0) ||
1593            ((voxlist[pix].getZ()+dz)>=int(this->axisDim[2])) )
1594          atEdge = true;
1595        else if(this->isBlank(voxlist[pix].getX(),
1596                              voxlist[pix].getY(),
1597                              voxlist[pix].getZ()+dz))
1598          atEdge = true;
1599      }
1600      pix++;
1601    }
1602
1603    return atEdge;
1604  }
1605  //--------------------------------------------------------------------
1606
1607  bool Cube::objNextToMW(Detection obj)
1608  {
1609    ///   @details A function to test whether the object obj lies
1610    ///   adjacent to the MW range or straddles it (conceivably, you
1611    ///   could have disconnected channels in your object that don't
1612    ///   touch the MW range, but lie either side - in this case we
1613    ///   want the flag). If flagMW=false we will always return false.
1614    ///
1615    ///   \param obj The Detection under consideration.
1616
1617    bool isNext = this->par.getFlagMW() &&
1618      ((obj.getZmin() <= this->par.getMaxMW()+1) && (obj.getZmax() >= this->par.getMinMW()-1));
1619   
1620    return isNext;
1621
1622  }
1623  //--------------------------------------------------------------------
1624
1625  void Cube::setObjectFlags()
1626  {
1627    /// @details
1628    ///   A function to set any warning flags for all the detected objects
1629    ///    associated with the cube.
1630    ///   Flags to be looked for:
1631    ///    <ul><li> Negative enclosed flux (N)
1632    ///        <li> Detection at edge of field (spatially) (E)
1633    ///        <li> Detection at edge of spectral region (S)
1634    ///    </ul>
1635
1636    std::vector<Detection>::iterator obj;
1637    for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
1638
1639      if( this->enclosedFlux(*obj) < 0. ) 
1640        obj->addToFlagText("N");
1641
1642      if( this->objAtSpatialEdge(*obj) )
1643        obj->addToFlagText("E");
1644
1645      if( this->objAtSpectralEdge(*obj) && (this->axisDim[2] > 2))
1646        obj->addToFlagText("S");
1647
1648      if( this->objNextToMW(*obj) )
1649        obj->addToFlagText("M");
1650
1651      if(obj->getFlagText()=="") obj->addToFlagText("-");
1652
1653    }
1654
1655  }
1656  //--------------------------------------------------------------------
1657
1658  /****************************************************************/
1659  /////////////////////////////////////////////////////////////
1660  //// Functions for Image class
1661  /////////////////////////////////////////////////////////////
1662
1663  Image::Image(size_t size)
1664  {
1665    // need error handling in case size<0 !!!
1666    this->numPixels = this->numDim = 0;
1667    this->minSize = 2;
1668    if(size<0){
1669      DUCHAMPERROR("Image(size)","Negative size -- could not define Image");
1670    }
1671    else{
1672      if(size>0 && !this->arrayAllocated){
1673        this->array = new float[size];
1674        this->arrayAllocated = true;
1675      }
1676      this->numPixels = size;
1677      this->axisDim = new size_t[2];
1678      this->axisDimAllocated = true;
1679      this->numDim = 2;
1680    }
1681  }
1682  //--------------------------------------------------------------------
1683
1684  Image::Image(size_t *dimensions)
1685  {
1686    this->numPixels = this->numDim = 0;
1687    this->minSize = 2;
1688    int size = dimensions[0] * dimensions[1];
1689    if(size<0){
1690      DUCHAMPERROR("Image(dimArray)","Negative size -- could not define Image");
1691    }
1692    else{
1693      this->numPixels = size;
1694      if(size>0){
1695        this->array = new float[size];
1696        this->arrayAllocated = true;
1697      }
1698      this->numDim=2;
1699      this->axisDim = new size_t[2];
1700      this->axisDimAllocated = true;
1701      for(int i=0;i<2;i++) this->axisDim[i] = dimensions[i];
1702    }
1703  }
1704  //--------------------------------------------------------------------
1705  Image::Image(const Image &i):
1706    DataArray(i)
1707  {
1708    this->operator=(i);
1709  }
1710
1711  Image& Image::operator=(const Image &i)
1712  {
1713    if(this==&i) return *this;
1714    ((DataArray &) *this) = i;
1715    this->minSize = i.minSize;
1716    return *this;
1717  }
1718
1719  //--------------------------------------------------------------------
1720
1721  void Image::saveArray(float *input, size_t size)
1722  {
1723    /// @details
1724    /// Saves the array in input to the pixel array Image::array.
1725    /// The size of the array given must be the same as the current number of
1726    /// pixels, else an error message is returned and nothing is done.
1727    /// \param input The array of values to be saved.
1728    /// \param size The size of input.
1729
1730    if(size != this->numPixels){
1731      DUCHAMPERROR("Image::saveArray", "Input array different size to existing array. Cannot save.");
1732    }
1733    else {
1734      if(this->numPixels>0 && this->arrayAllocated) delete [] array;
1735      this->numPixels = size;
1736      if(this->numPixels>0){
1737        this->array = new float[size];
1738        this->arrayAllocated = true;
1739        for(size_t i=0;i<size;i++) this->array[i] = input[i];
1740      }
1741    }
1742  }
1743  //--------------------------------------------------------------------
1744
1745  void Image::extractSpectrum(float *Array, size_t *dim, size_t pixel)
1746  {
1747    /// @details
1748    ///  A function to extract a 1-D spectrum from a 3-D array.
1749    ///  The array is assumed to be 3-D with the third dimension the spectral one.
1750    ///  The spectrum extracted is the one lying in the spatial pixel referenced
1751    ///    by the third argument.
1752    ///  The extracted spectrum is stored in the pixel array Image::array.
1753    /// \param Array The array containing the pixel values, from which
1754    ///               the spectrum is extracted.
1755    /// \param dim The array of dimension values.
1756    /// \param pixel The spatial pixel that contains the desired spectrum.
1757
1758    if((pixel<0)||(pixel>=dim[0]*dim[1])){
1759      DUCHAMPERROR("Image::extractSpectrum", "Requested spatial pixel outside allowed range. Cannot save.");
1760    }
1761    else if(dim[2] != this->numPixels){
1762      DUCHAMPERROR("Image::extractSpectrum", "Input array different size to existing array. Cannot save.");
1763    }
1764    else {
1765      if(this->numPixels>0 && this->arrayAllocated) delete [] array;
1766      this->numPixels = dim[2];
1767      if(this->numPixels>0){
1768        this->array = new float[dim[2]];
1769        this->arrayAllocated = true;
1770        for(size_t z=0;z<dim[2];z++) this->array[z] = Array[z*dim[0]*dim[1] + pixel];
1771      }
1772    }
1773  }
1774  //--------------------------------------------------------------------
1775
1776  void Image::extractSpectrum(Cube &cube, size_t pixel)
1777  {
1778    /// @details
1779    ///  A function to extract a 1-D spectrum from a Cube class
1780    ///  The spectrum extracted is the one lying in the spatial pixel referenced
1781    ///    by the second argument.
1782    ///  The extracted spectrum is stored in the pixel array Image::array.
1783    /// \param cube The Cube containing the pixel values, from which the spectrum is extracted.
1784    /// \param pixel The spatial pixel that contains the desired spectrum.
1785
1786    size_t zdim = cube.getDimZ();
1787    size_t spatSize = cube.getDimX()*cube.getDimY();
1788    if((pixel<0)||(pixel>=spatSize)){
1789      DUCHAMPERROR("Image::extractSpectrum", "Requested spatial pixel outside allowed range. Cannot save.");
1790    }
1791    else if(zdim != this->numPixels){
1792      DUCHAMPERROR("Image::extractSpectrum", "Input array different size to existing array. Cannot save.");
1793    }
1794    else {
1795      if(this->numPixels>0 && this->arrayAllocated) delete [] array;
1796      this->numPixels = zdim;
1797      if(this->numPixels>0){
1798        this->array = new float[zdim];
1799        this->arrayAllocated = true;
1800        for(size_t z=0;z<zdim;z++)
1801          this->array[z] = cube.getPixValue(z*spatSize + pixel);
1802      }
1803    }
1804  }
1805  //--------------------------------------------------------------------
1806
1807  void Image::extractImage(float *Array, size_t *dim, size_t channel)
1808  {
1809    /// @details
1810    ///  A function to extract a 2-D image from a 3-D array.
1811    ///  The array is assumed to be 3-D with the third dimension the spectral one.
1812    ///  The dimensions of the array are in the dim[] array.
1813    ///  The image extracted is the one lying in the channel referenced
1814    ///    by the third argument.
1815    ///  The extracted image is stored in the pixel array Image::array.
1816    /// \param Array The array containing the pixel values, from which the image is extracted.
1817    /// \param dim The array of dimension values.
1818    /// \param channel The spectral channel that contains the desired image.
1819
1820    size_t spatSize = dim[0]*dim[1];
1821    if((channel<0)||(channel>=dim[2])){
1822      DUCHAMPERROR("Image::extractImage", "Requested channel outside allowed range. Cannot save.");
1823    }
1824    else if(spatSize != this->numPixels){
1825      DUCHAMPERROR("Image::extractImage", "Input array different size to existing array. Cannot save.");
1826    }
1827    else {
1828      if(this->numPixels>0 && this->arrayAllocated) delete [] array;
1829      this->numPixels = spatSize;
1830      if(this->numPixels>0){
1831        this->array = new float[spatSize];
1832        this->arrayAllocated = true;
1833        for(size_t npix=0; npix<spatSize; npix++)
1834          this->array[npix] = Array[channel*spatSize + npix];
1835      }
1836    }
1837  }
1838  //--------------------------------------------------------------------
1839
1840  void Image::extractImage(Cube &cube, size_t channel)
1841  {
1842    /// @details
1843    ///  A function to extract a 2-D image from Cube class.
1844    ///  The image extracted is the one lying in the channel referenced
1845    ///    by the second argument.
1846    ///  The extracted image is stored in the pixel array Image::array.
1847    /// \param cube The Cube containing the pixel values, from which the image is extracted.
1848    /// \param channel The spectral channel that contains the desired image.
1849
1850    size_t spatSize = cube.getDimX()*cube.getDimY();
1851    if((channel<0)||(channel>=cube.getDimZ())){
1852      DUCHAMPERROR("Image::extractImage", "Requested channel outside allowed range. Cannot save.");
1853    }
1854    else if(spatSize != this->numPixels){
1855      DUCHAMPERROR("Image::extractImage", "Input array different size to existing array. Cannot save.");
1856    }
1857    else {
1858      if(this->numPixels>0 && this->arrayAllocated) delete [] array;
1859      this->numPixels = spatSize;
1860      if(this->numPixels>0){
1861        this->array = new float[spatSize];
1862        this->arrayAllocated = true;
1863        for(size_t npix=0; npix<spatSize; npix++)
1864          this->array[npix] = cube.getPixValue(channel*spatSize + npix);
1865      }
1866    }
1867  }
1868  //--------------------------------------------------------------------
1869
1870  void Image::removeMW()
1871  {
1872    /// @details
1873    ///  A function to remove the Milky Way range of channels from a 1-D spectrum.
1874    ///  The array in this Image is assumed to be 1-D, with only the first axisDim
1875    ///    equal to 1.
1876    ///  The values of the MW channels are set to 0, unless they are BLANK.
1877
1878    if(this->par.getFlagMW() && (this->axisDim[1]==1) ){
1879      for(size_t z=0;z<this->axisDim[0];z++){
1880        if(!this->isBlank(z) && this->par.isInMW(z)) this->array[z]=0.;
1881      }
1882    }
1883  }
1884  //--------------------------------------------------------------------
1885
1886  std::vector<Object2D> Image::findSources2D()
1887  {
1888    std::vector<bool> thresholdedArray(this->axisDim[0]*this->axisDim[1]);
1889    for(size_t posY=0;posY<this->axisDim[1];posY++){
1890      for(size_t posX=0;posX<this->axisDim[0];posX++){
1891        size_t loc = posX + this->axisDim[0]*posY;
1892        thresholdedArray[loc] = this->isDetection(posX,posY);
1893      }
1894    }
1895    return lutz_detect(thresholdedArray, this->axisDim[0], this->axisDim[1], this->minSize);
1896  }
1897
1898  std::vector<Scan> Image::findSources1D()
1899  {
1900    std::vector<bool> thresholdedArray(this->axisDim[0]);
1901    for(size_t posX=0;posX<this->axisDim[0];posX++){
1902      thresholdedArray[posX] = this->isDetection(posX,0);
1903    }
1904    return spectrumDetect(thresholdedArray, this->axisDim[0], this->minSize);
1905  }
1906
1907
1908  std::vector< std::vector<PixelInfo::Voxel> > Cube::getObjVoxList()
1909  {
1910   
1911    std::vector< std::vector<PixelInfo::Voxel> > biglist;
1912   
1913    std::vector<Detection>::iterator obj;
1914    for(obj=this->objectList->begin(); obj<this->objectList->end(); obj++) {
1915
1916      Cube *subcube = new Cube;
1917      subcube->pars() = this->par;
1918      subcube->pars().setVerbosity(false);
1919      subcube->pars().setFlagSubsection(true);
1920      duchamp::Section sec = obj->getBoundingSection();
1921      subcube->pars().setSubsection( sec.getSection() );
1922      if(subcube->pars().verifySubsection() == FAILURE)
1923        DUCHAMPERROR("get object voxel list","Unable to verify the subsection - something's wrong!");
1924      if(subcube->getCube() == FAILURE)
1925        DUCHAMPERROR("get object voxel list","Unable to read the FITS file - something's wrong!");
1926      std::vector<PixelInfo::Voxel> voxlist = obj->getPixelSet();
1927      std::vector<PixelInfo::Voxel>::iterator vox;
1928      for(vox=voxlist.begin(); vox<voxlist.end(); vox++){
1929        size_t pix = (vox->getX()-subcube->pars().getXOffset()) +
1930          subcube->getDimX()*(vox->getY()-subcube->pars().getYOffset()) +
1931          subcube->getDimX()*subcube->getDimY()*(vox->getZ()-subcube->pars().getZOffset());
1932        vox->setF( subcube->getPixValue(pix) );
1933      }
1934      biglist.push_back(voxlist);
1935      delete subcube;
1936
1937    }
1938
1939    return biglist;
1940
1941  }
1942
1943}
Note: See TracBrowser for help on using the repository browser.