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

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

Ticket #170, #105 - The bulk of the work allowing this to happen. Have implemented different classes for each of the output types, including the baselines (which required new parameters etc.) Not yet implemented in mainDuchamp, so needs testing.

File size: 71.0 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/Cubes/WriteReconArray.hh>
55#include <duchamp/Cubes/WriteSmoothArray.hh>
56#include <duchamp/Cubes/WriteMaskArray.hh>
57#include <duchamp/Cubes/WriteMomentMapArray.hh>
58#include <duchamp/Cubes/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    if(!this->par.getFlagUsePrevious()){
1675      std::string report;
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          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.outputReconFile());
1691          writer.setIsRecon(false);
1692          OUTCOME result = writer.write();
1693          report=(result==FAILURE)?"Failed!":"done.";
1694          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        std::cout << report << "\n";
1705      }
1706      if(this->par.getFlagOutputMomentMap()){
1707        if(this->par.isVerbose())
1708          std::cout << "  Saving moment map to " << this->par.outputMomentMapFile() << "... "<<std::flush;
1709        WriteMomentMapArray writer(this);
1710        writer.setFilename(this->par.outputMomentMapFile());
1711        OUTCOME result = writer.write();
1712        report=(result==FAILURE)?"Failed!":"done.";
1713        std::cout << report << "\n";
1714      }
1715      if(this->par.getFlagOutputBaseline()){
1716        if(this->par.isVerbose())
1717          std::cout << "  Saving baseline cube to " << this->par.outputBaselineFile() << "... "<<std::flush;
1718        WriteBaselineArray writer(this);
1719        writer.setFilename(this->par.outputBaselineFile());
1720        OUTCOME result = writer.write();
1721        report=(result==FAILURE)?"Failed!":"done.";
1722        std::cout << report << "\n";
1723      }
1724      if(this->par.getFlagOutputMask()){
1725        if(this->par.isVerbose())
1726          std::cout << "  Saving mask cube to " << this->par.outputMaskFile() << "... "<<std::flush;
1727        WriteMaskArray writer(this);
1728        writer.setFilename(this->par.outputMaskFile());
1729        OUTCOME result = writer.write();
1730        report=(result==FAILURE)?"Failed!":"done.";
1731        std::cout << report << "\n";
1732      }
1733
1734
1735    }
1736  }
1737
1738
1739  /****************************************************************/
1740  /////////////////////////////////////////////////////////////
1741  //// Functions for Image class
1742  /////////////////////////////////////////////////////////////
1743
1744  Image::Image(size_t size)
1745  {
1746    // need error handling in case size<0 !!!
1747    this->numPixels = this->numDim = 0;
1748    this->minSize = 2;
1749    if(size<0){
1750      DUCHAMPERROR("Image(size)","Negative size -- could not define Image");
1751    }
1752    else{
1753      if(size>0 && !this->arrayAllocated){
1754        this->array = new float[size];
1755        this->arrayAllocated = true;
1756      }
1757      this->numPixels = size;
1758      this->axisDim = new size_t[2];
1759      this->axisDimAllocated = true;
1760      this->numDim = 2;
1761    }
1762  }
1763  //--------------------------------------------------------------------
1764
1765  Image::Image(size_t *dimensions)
1766  {
1767    this->numPixels = this->numDim = 0;
1768    this->minSize = 2;
1769    int size = dimensions[0] * dimensions[1];
1770    if(size<0){
1771      DUCHAMPERROR("Image(dimArray)","Negative size -- could not define Image");
1772    }
1773    else{
1774      this->numPixels = size;
1775      if(size>0){
1776        this->array = new float[size];
1777        this->arrayAllocated = true;
1778      }
1779      this->numDim=2;
1780      this->axisDim = new size_t[2];
1781      this->axisDimAllocated = true;
1782      for(int i=0;i<2;i++) this->axisDim[i] = dimensions[i];
1783    }
1784  }
1785  //--------------------------------------------------------------------
1786  Image::Image(const Image &i):
1787    DataArray(i)
1788  {
1789    this->operator=(i);
1790  }
1791
1792  Image& Image::operator=(const Image &i)
1793  {
1794    if(this==&i) return *this;
1795    ((DataArray &) *this) = i;
1796    this->minSize = i.minSize;
1797    return *this;
1798  }
1799
1800  //--------------------------------------------------------------------
1801
1802  void Image::saveArray(float *input, size_t size)
1803  {
1804    /// @details
1805    /// Saves the array in input to the pixel array Image::array.
1806    /// The size of the array given must be the same as the current number of
1807    /// pixels, else an error message is returned and nothing is done.
1808    /// \param input The array of values to be saved.
1809    /// \param size The size of input.
1810
1811    if(size != this->numPixels){
1812      DUCHAMPERROR("Image::saveArray", "Input array different size to existing array. Cannot save.");
1813    }
1814    else {
1815      if(this->numPixels>0 && this->arrayAllocated) delete [] array;
1816      this->numPixels = size;
1817      if(this->numPixels>0){
1818        this->array = new float[size];
1819        this->arrayAllocated = true;
1820        for(size_t i=0;i<size;i++) this->array[i] = input[i];
1821      }
1822    }
1823  }
1824  //--------------------------------------------------------------------
1825
1826  void Image::extractSpectrum(float *Array, size_t *dim, size_t pixel)
1827  {
1828    /// @details
1829    ///  A function to extract a 1-D spectrum from a 3-D array.
1830    ///  The array is assumed to be 3-D with the third dimension the spectral one.
1831    ///  The spectrum extracted is the one lying in the spatial pixel referenced
1832    ///    by the third argument.
1833    ///  The extracted spectrum is stored in the pixel array Image::array.
1834    /// \param Array The array containing the pixel values, from which
1835    ///               the spectrum is extracted.
1836    /// \param dim The array of dimension values.
1837    /// \param pixel The spatial pixel that contains the desired spectrum.
1838
1839    if((pixel<0)||(pixel>=dim[0]*dim[1])){
1840      DUCHAMPERROR("Image::extractSpectrum", "Requested spatial pixel outside allowed range. Cannot save.");
1841    }
1842    else if(dim[2] != this->numPixels){
1843      DUCHAMPERROR("Image::extractSpectrum", "Input array different size to existing array. Cannot save.");
1844    }
1845    else {
1846      if(this->numPixels>0 && this->arrayAllocated) delete [] array;
1847      this->numPixels = dim[2];
1848      if(this->numPixels>0){
1849        this->array = new float[dim[2]];
1850        this->arrayAllocated = true;
1851        for(size_t z=0;z<dim[2];z++) this->array[z] = Array[z*dim[0]*dim[1] + pixel];
1852      }
1853    }
1854  }
1855  //--------------------------------------------------------------------
1856
1857  void Image::extractSpectrum(Cube &cube, size_t pixel)
1858  {
1859    /// @details
1860    ///  A function to extract a 1-D spectrum from a Cube class
1861    ///  The spectrum extracted is the one lying in the spatial pixel referenced
1862    ///    by the second argument.
1863    ///  The extracted spectrum is stored in the pixel array Image::array.
1864    /// \param cube The Cube containing the pixel values, from which the spectrum is extracted.
1865    /// \param pixel The spatial pixel that contains the desired spectrum.
1866
1867    size_t zdim = cube.getDimZ();
1868    size_t spatSize = cube.getDimX()*cube.getDimY();
1869    if((pixel<0)||(pixel>=spatSize)){
1870      DUCHAMPERROR("Image::extractSpectrum", "Requested spatial pixel outside allowed range. Cannot save.");
1871    }
1872    else if(zdim != this->numPixels){
1873      DUCHAMPERROR("Image::extractSpectrum", "Input array different size to existing array. Cannot save.");
1874    }
1875    else {
1876      if(this->numPixels>0 && this->arrayAllocated) delete [] array;
1877      this->numPixels = zdim;
1878      if(this->numPixels>0){
1879        this->array = new float[zdim];
1880        this->arrayAllocated = true;
1881        for(size_t z=0;z<zdim;z++)
1882          this->array[z] = cube.getPixValue(z*spatSize + pixel);
1883      }
1884    }
1885  }
1886  //--------------------------------------------------------------------
1887
1888  void Image::extractImage(float *Array, size_t *dim, size_t channel)
1889  {
1890    /// @details
1891    ///  A function to extract a 2-D image from a 3-D array.
1892    ///  The array is assumed to be 3-D with the third dimension the spectral one.
1893    ///  The dimensions of the array are in the dim[] array.
1894    ///  The image extracted is the one lying in the channel referenced
1895    ///    by the third argument.
1896    ///  The extracted image is stored in the pixel array Image::array.
1897    /// \param Array The array containing the pixel values, from which the image is extracted.
1898    /// \param dim The array of dimension values.
1899    /// \param channel The spectral channel that contains the desired image.
1900
1901    size_t spatSize = dim[0]*dim[1];
1902    if((channel<0)||(channel>=dim[2])){
1903      DUCHAMPERROR("Image::extractImage", "Requested channel outside allowed range. Cannot save.");
1904    }
1905    else if(spatSize != this->numPixels){
1906      DUCHAMPERROR("Image::extractImage", "Input array different size to existing array. Cannot save.");
1907    }
1908    else {
1909      if(this->numPixels>0 && this->arrayAllocated) delete [] array;
1910      this->numPixels = spatSize;
1911      if(this->numPixels>0){
1912        this->array = new float[spatSize];
1913        this->arrayAllocated = true;
1914        for(size_t npix=0; npix<spatSize; npix++)
1915          this->array[npix] = Array[channel*spatSize + npix];
1916      }
1917    }
1918  }
1919  //--------------------------------------------------------------------
1920
1921  void Image::extractImage(Cube &cube, size_t channel)
1922  {
1923    /// @details
1924    ///  A function to extract a 2-D image from Cube class.
1925    ///  The image extracted is the one lying in the channel referenced
1926    ///    by the second argument.
1927    ///  The extracted image is stored in the pixel array Image::array.
1928    /// \param cube The Cube containing the pixel values, from which the image is extracted.
1929    /// \param channel The spectral channel that contains the desired image.
1930
1931    size_t spatSize = cube.getDimX()*cube.getDimY();
1932    if((channel<0)||(channel>=cube.getDimZ())){
1933      DUCHAMPERROR("Image::extractImage", "Requested channel outside allowed range. Cannot save.");
1934    }
1935    else if(spatSize != this->numPixels){
1936      DUCHAMPERROR("Image::extractImage", "Input array different size to existing array. Cannot save.");
1937    }
1938    else {
1939      if(this->numPixels>0 && this->arrayAllocated) delete [] array;
1940      this->numPixels = spatSize;
1941      if(this->numPixels>0){
1942        this->array = new float[spatSize];
1943        this->arrayAllocated = true;
1944        for(size_t npix=0; npix<spatSize; npix++)
1945          this->array[npix] = cube.getPixValue(channel*spatSize + npix);
1946      }
1947    }
1948  }
1949  //--------------------------------------------------------------------
1950
1951  void Image::removeMW()
1952  {
1953    /// @details
1954    ///  A function to remove the Milky Way range of channels from a 1-D spectrum.
1955    ///  The array in this Image is assumed to be 1-D, with only the first axisDim
1956    ///    equal to 1.
1957    ///  The values of the MW channels are set to 0, unless they are BLANK.
1958
1959    if(this->par.getFlagMW() && (this->axisDim[1]==1) ){
1960      for(size_t z=0;z<this->axisDim[0];z++){
1961        if(!this->isBlank(z) && this->par.isInMW(z)) this->array[z]=0.;
1962      }
1963    }
1964  }
1965  //--------------------------------------------------------------------
1966
1967  std::vector<Object2D> Image::findSources2D()
1968  {
1969    std::vector<bool> thresholdedArray(this->axisDim[0]*this->axisDim[1]);
1970    for(size_t posY=0;posY<this->axisDim[1];posY++){
1971      for(size_t posX=0;posX<this->axisDim[0];posX++){
1972        size_t loc = posX + this->axisDim[0]*posY;
1973        thresholdedArray[loc] = this->isDetection(posX,posY);
1974      }
1975    }
1976    return lutz_detect(thresholdedArray, this->axisDim[0], this->axisDim[1], this->minSize);
1977  }
1978
1979  std::vector<Scan> Image::findSources1D()
1980  {
1981    std::vector<bool> thresholdedArray(this->axisDim[0]);
1982    for(size_t posX=0;posX<this->axisDim[0];posX++){
1983      thresholdedArray[posX] = this->isDetection(posX,0);
1984    }
1985    return spectrumDetect(thresholdedArray, this->axisDim[0], this->minSize);
1986  }
1987
1988
1989  std::vector< std::vector<PixelInfo::Voxel> > Cube::getObjVoxList()
1990  {
1991   
1992    std::vector< std::vector<PixelInfo::Voxel> > biglist;
1993   
1994    std::vector<Detection>::iterator obj;
1995    for(obj=this->objectList->begin(); obj<this->objectList->end(); obj++) {
1996
1997      Cube *subcube = new Cube;
1998      subcube->pars() = this->par;
1999      subcube->pars().setVerbosity(false);
2000      subcube->pars().setFlagSubsection(true);
2001      duchamp::Section sec = obj->getBoundingSection();
2002      subcube->pars().setSubsection( sec.getSection() );
2003      if(subcube->pars().verifySubsection() == FAILURE)
2004        DUCHAMPERROR("get object voxel list","Unable to verify the subsection - something's wrong!");
2005      if(subcube->getCube() == FAILURE)
2006        DUCHAMPERROR("get object voxel list","Unable to read the FITS file - something's wrong!");
2007      std::vector<PixelInfo::Voxel> voxlist = obj->getPixelSet();
2008      std::vector<PixelInfo::Voxel>::iterator vox;
2009      for(vox=voxlist.begin(); vox<voxlist.end(); vox++){
2010        size_t pix = (vox->getX()-subcube->pars().getXOffset()) +
2011          subcube->getDimX()*(vox->getY()-subcube->pars().getYOffset()) +
2012          subcube->getDimX()*subcube->getDimY()*(vox->getZ()-subcube->pars().getZOffset());
2013        vox->setF( subcube->getPixValue(pix) );
2014      }
2015      biglist.push_back(voxlist);
2016      delete subcube;
2017
2018    }
2019
2020    return biglist;
2021
2022  }
2023
2024}
Note: See TracBrowser for help on using the repository browser.