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

Last change on this file since 1302 was 1297, checked in by MatthewWhiting, 11 years ago

Silencing some compiler warnings that are cropping up with the new Xcode on the mac.

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