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

Last change on this file since 1141 was 1134, checked in by MatthewWhiting, 11 years ago

Fixing the main obvious problem with non-verbose operation (ticket #176).

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