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

Last change on this file since 872 was 863, checked in by MatthewWhiting, 13 years ago

Adding in versions of the parametrisation functions that take std:maps of Voxels (suggested in #123).

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