source: trunk/src/ATrous/ReconSearch.cc @ 845

Last change on this file since 845 was 788, checked in by MatthewWhiting, 13 years ago

First part of dealing with #110. Have defined a Beam & DuchampBeam? class and use these to hold the beam information. FitsHeader? holds the one that we work with, and copies it to Param for use with outputs. Parameters will be taken into account if no header information is present. Still need to add code to deal with the case of neither being present (the beam being EMPTY) and how that affects the integrated flux calculations.

File size: 13.7 KB
RevLine 
[299]1// -----------------------------------------------------------------------
2// ReconSearch.cc: Searching a wavelet-reconstructed cube.
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// -----------------------------------------------------------------------
[3]28#include <fstream>
29#include <iostream>
30#include <iomanip>
31#include <vector>
[393]32#include <duchamp/duchamp.hh>
33#include <duchamp/PixelMap/Object3D.hh>
34#include <duchamp/Cubes/cubes.hh>
35#include <duchamp/Detection/detection.hh>
36#include <duchamp/ATrous/atrous.hh>
37#include <duchamp/Utils/utils.hh>
38#include <duchamp/Utils/feedback.hh>
39#include <duchamp/Utils/Statistics.hh>
[3]40
[258]41using namespace PixelInfo;
[274]42using namespace Statistics;
[258]43
[378]44namespace duchamp
[103]45{
[285]46
[378]47  void Cube::ReconSearch()
48  {
[528]49    /// The Cube is first reconstructed, using Cube::ReconCube().
50    /// The statistics of the cube are calculated next.
51    /// It is then searched, using searchReconArray.
52    /// The resulting object list is stored in the Cube, and outputted
53    ///  to the log file if the user so requests.
[378]54
55    if(!this->par.getFlagATrous()){
56      duchampWarning("ReconSearch",
57                     "You've requested a reconSearch, but not allocated space for the reconstructed array.\nDoing the basic CubicSearch.\n");
58      this->CubicSearch();
59    }
60    else {
[188]61 
[378]62      this->ReconCube();
[188]63
[378]64      if(this->par.isVerbose()) std::cout << "  ";
[219]65
[378]66      this->setCubeStats();
[189]67   
[378]68      if(this->par.isVerbose()) std::cout << "  Searching... " << std::flush;
[188]69 
[686]70      *this->objectList = searchReconArray(this->axisDim,this->array,
71                                           this->recon,this->par,this->Stats);
[188]72
[378]73      if(this->par.isVerbose()) std::cout << "  Updating detection map... "
74                                          << std::flush;
75      this->updateDetectMap();
[285]76      if(this->par.isVerbose()) std::cout << "Done.\n";
77
[378]78      if(this->par.getFlagLog()){
79        if(this->par.isVerbose())
80          std::cout << "  Logging intermediate detections... " << std::flush;
81        this->logDetectionList();
82        if(this->par.isVerbose()) std::cout << "Done.\n";
83      }
[188]84
[378]85    }
[285]86  }
[120]87
[378]88  /////////////////////////////////////////////////////////////////////////////
89  void Cube::ReconCube()
90  {
[528]91    /// A front-end to the various reconstruction functions, the choice of
92    ///  which is determined by the use of the reconDim parameter.
93    /// Differs from ReconSearch only in that no searching is done.
94
[378]95    int dimRecon = this->par.getReconDim();
96    // Test whether we have eg. an image, but have requested a 3-d
97    //  reconstruction.
98    // If dimension of data array is less than dimRecon, change dimRecon
99    //  to the dimension of the array.
100    int numGoodDim = this->head.getNumAxes();
101    if(numGoodDim<dimRecon){
102      dimRecon = numGoodDim;
103      this->par.setReconDim(dimRecon);
104      std::stringstream errmsg;
105      errmsg << "You requested a " << dimRecon << "-dimensional reconstruction,"
106             << " but the FITS file is only " << numGoodDim << "-dimensional.\n"
107             << "Changing reconDim to " << numGoodDim << ".\n";
108      duchampWarning("Reconstruction",errmsg.str());
[103]109    }
110
[378]111    switch(dimRecon)
112      {
113      case 1: this->ReconCube1D(); break;
114      case 2: this->ReconCube2D(); break;
115      case 3: this->ReconCube3D(); break;
116      default:
117        if(dimRecon<=0){
118          std::stringstream errmsg;
119          errmsg << "reconDim (" << dimRecon
120                 << ") is less than 1. Performing 1-D reconstruction.\n";
121          duchampWarning("Reconstruction", errmsg.str());
122          this->par.setReconDim(1);
123          this->ReconCube1D();
124        }
125        else if(dimRecon>3){
126          //this probably won't happen with new code above, but just in case...
127          std::stringstream errmsg;
128          errmsg << "reconDim (" << dimRecon
129                 << ") is more than 3. Performing 3-D reconstruction.\n";
130          duchampWarning("Reconstruction", errmsg.str());
131          this->par.setReconDim(3);
132          this->ReconCube3D();
133        }
134        break;
135      }
[3]136  }
[103]137
[378]138  /////////////////////////////////////////////////////////////////////////////
139  void Cube::ReconCube1D()
140  {
[528]141    /// This reconstructs a cube by performing a 1D a trous reconstruction
142    ///  in the spectrum of each spatial pixel.
143
[378]144    long xySize = this->axisDim[0] * this->axisDim[1];
[3]145
[378]146    long zdim = this->axisDim[2];
[3]147
[378]148    ProgressBar bar;
149    if(!this->reconExists){
[725]150      if(this->par.isVerbose()){
151        std::cout<<"  Reconstructing... ";
152        bar.init(xySize);
153      }
[378]154      for(int npix=0; npix<xySize; npix++){
[175]155
[725]156        if( this->par.isVerbose() ) bar.update(npix+1);
[175]157
[378]158        float *spec = new float[zdim];
159        float *newSpec = new float[zdim];
160        for(int z=0;z<zdim;z++) spec[z] = this->array[z*xySize + npix];
[103]161        bool verboseFlag = this->par.isVerbose();
162        this->par.setVerbosity(false);
[378]163        atrous1DReconstruct(this->axisDim[2],spec,newSpec,this->par);
[103]164        this->par.setVerbosity(verboseFlag);
[378]165        for(int z=0;z<zdim;z++) this->recon[z*xySize+npix] = newSpec[z];
166        delete [] spec;
167        delete [] newSpec;
[3]168      }
[378]169      this->reconExists = true;
[725]170      if(this->par.isVerbose()){
171        bar.fillSpace(" All Done.");
172        printSpace(22);
173        std::cout << "\n";
174      }
[3]175    }
[378]176
[3]177  }
178
[378]179  /////////////////////////////////////////////////////////////////////////////
180  void Cube::ReconCube2D()
181  {
[528]182    /// This reconstructs a cube by performing a 2D a trous reconstruction
183    ///  in each spatial image (ie. each channel map) of the cube.
184
[378]185    long xySize = this->axisDim[0] * this->axisDim[1];
186    ProgressBar bar;
187    bool useBar = (this->axisDim[2]>1);
[3]188
[71]189    if(!this->reconExists){
[725]190      if(this->par.isVerbose()) std::cout<<"  Reconstructing... ";
191      if(useBar&&this->par.isVerbose()) bar.init(this->axisDim[2]);
[378]192      for(int z=0;z<this->axisDim[2];z++){
193
[725]194        if( this->par.isVerbose() && useBar ) bar.update((z+1));
[378]195
196        if(!this->par.isInMW(z)){
197          float *im = new float[xySize];
198          float *newIm = new float[xySize];
199          for(int npix=0; npix<xySize; npix++)
200            im[npix] = this->array[z*xySize+npix];
201          bool verboseFlag = this->par.isVerbose();
202          this->par.setVerbosity(false);
203          atrous2DReconstruct(this->axisDim[0],this->axisDim[1],
204                              im,newIm,this->par);
205          this->par.setVerbosity(verboseFlag);
206          for(int npix=0; npix<xySize; npix++)
207            this->recon[z*xySize+npix] = newIm[npix];
208          delete [] im;
209          delete [] newIm;
210        }
211        else {
212          for(int i=z*xySize; i<(z+1)*xySize; i++)
213            this->recon[i] = this->array[i];
214        }
215      }
[71]216      this->reconExists = true;
[725]217      if(this->par.isVerbose()) {
218        if(useBar) bar.fillSpace(" All Done.");
219        printSpace(22);
220        std::cout << "\n";
221      }
[71]222    }
[3]223  }
224
[378]225  /////////////////////////////////////////////////////////////////////////////
226  void Cube::ReconCube3D()
227  {
[528]228    /// This performs a full 3D a trous reconstruction of the cube
229
[378]230    if(this->axisDim[2]==1) this->ReconCube2D();
231    else {
[3]232
[378]233      if(!this->reconExists){
[725]234        if(this->par.isVerbose()) std::cout<<"  Reconstructing... "<<std::flush;
[378]235        atrous3DReconstruct(this->axisDim[0],this->axisDim[1],this->axisDim[2],
236                            this->array,this->recon,this->par);
237        this->reconExists = true;
[725]238        if(this->par.isVerbose()) {
239          std::cout << "  All Done.";
240          printSpace(22);
241          std::cout << "\n";
242        }
[378]243      }
244
[175]245    }
[378]246  }
[3]247
[378]248  /////////////////////////////////////////////////////////////////////////////
249  std::vector <Detection> searchReconArray(long *dim, float *originalArray,
250                                           float *reconArray, Param &par,
251                                           StatsContainer<float> &stats)
252  {
[686]253
254  if(par.getSearchType()=="spectral")
255    return searchReconArraySpectral(dim,originalArray,reconArray,par,stats);
256  else if(par.getSearchType()=="spatial")
257    return searchReconArraySpatial(dim,originalArray,reconArray,par,stats);
258  else{
259    std::stringstream ss;
260    ss << "Unknown search type : " << par.getSearchType();
261    duchampError("searchReconArray",ss.str());
262    return std::vector<Detection>(0);
263  }
264  }
265  /////////////////////////////////////////////////////////////////////////////
266  std::vector <Detection> searchReconArraySpectral(long *dim, float *originalArray,
267                                                   float *reconArray, Param &par,
268                                                   StatsContainer<float> &stats)
269  {
[528]270    ///  This searches for objects in a cube that has been reconstructed.
271    ///
[686]272    ///  The search is conducted just in each spatial pixel (xdim*ydim 1D
273    ///   searches).
[528]274    ///  The searches are done on the reconstructed array, although the detected
275    ///   objects have fluxes drawn from the corresponding pixels of the original
276    ///   array.
277    ///
278    ///  \param dim Array of dimension sizes
279    ///  \param originalArray Original, un-reconstructed image array.
280    ///  \param reconArray Reconstructed image array
281    ///  \param par The Param set.
282    ///  \param stats The StatsContainer that defines what a detection is.
283    ///
284    ///  \return A vector of Detections resulting from the search.
285
[378]286    std::vector <Detection> outputList;
287    long zdim = dim[2];
288    long xySize = dim[0] * dim[1];
289    int num=0;
290
291    // First search --  in each spectrum.
292    if(zdim > 1){
[3]293
[691]294      ProgressBar bar;
295      if(par.isVerbose()) bar.init(xySize);
296
[378]297      bool *doPixel = new bool[xySize];
298      // doPixel is a bool array to say whether to look in a given spectrum
299      for(int npix=0; npix<xySize; npix++){
300        doPixel[npix] = false;
301        for(int z=0;z<zdim;z++) {
302          doPixel[npix] = doPixel[npix] ||
303            (!par.isBlank(originalArray[npix]) && !par.isInMW(z));
304        }
305        // doPixel[i] is false only when there are no good pixels in spectrum
306        //  of pixel #i.
307      }
[3]308
[378]309      long *specdim = new long[2];
310      specdim[0] = zdim; specdim[1]=1;
311      Image *spectrum = new Image(specdim);
312      delete [] specdim;
313      spectrum->saveParam(par);
314      spectrum->saveStats(stats);
315      spectrum->setMinSize(par.getMinChannels());
[788]316      // NB the beam is not used after this point
317      // spectrum->pars().setBeamSize(2.);
318      // // beam size: for spectrum, only neighbouring channels correlated
[192]319
[378]320      for(int y=0; y<dim[1]; y++){
321        for(int x=0; x<dim[0]; x++){
[258]322
[378]323          int npix = y*dim[0] + x;
324          if( par.isVerbose() ) bar.update(npix+1);
[258]325
[378]326          if(doPixel[npix]){
327
328            spectrum->extractSpectrum(reconArray,dim,npix);
329            spectrum->removeMW(); // only works if flagMW is true
[582]330            std::vector<Scan> objlist = spectrum->findSources1D();
[623]331            std::vector<Scan>::iterator obj;
[378]332            num += objlist.size();
[623]333            for(obj=objlist.begin();obj!=objlist.end();obj++){
[378]334              Detection newObject;
335              // Fix up coordinates of each pixel to match original array
[623]336              for(int z=obj->getX();z<=obj->getXmax();z++) {
[570]337                newObject.addPixel(x,y,z);
[378]338              }
339              newObject.setOffsets(par);
[691]340              if(par.getFlagTwoStageMerging()) mergeIntoList(newObject,outputList,par);
341              else outputList.push_back(newObject);
[258]342            }
[103]343          }
[378]344
[3]345        }
[378]346      }
[258]347
[378]348      delete spectrum;
349      delete [] doPixel;
[691]350     
351      if(par.isVerbose()){
352        bar.remove();
353        std::cout << "Found " << num << ".\n";
354      }
[378]355
[3]356    }
357
[378]358    return outputList;
359  }
[263]360
[378]361  /////////////////////////////////////////////////////////////////////////////
[686]362  std::vector <Detection> searchReconArraySpatial(long *dim, float *originalArray,
363                                                  float *reconArray, Param &par,
364                                                  StatsContainer<float> &stats)
[378]365  {
[528]366    ///  This searches for objects in a cube that has been reconstructed.
367    ///
368    ///  The search is conducted only in each channel image (zdim 2D
[686]369    ///  searches).
[528]370    ///
371    ///  The searches are done on the reconstructed array, although the detected
372    ///   objects have fluxes drawn from the corresponding pixels of the original
373    ///   array.
374    ///
375    ///  \param dim Array of dimension sizes
376    ///  \param originalArray Original, un-reconstructed image array.
377    ///  \param reconArray Reconstructed image array
378    ///  \param par The Param set.
379    ///  \param stats The StatsContainer that defines what a detection is.
380    ///
381    ///  \return A vector of Detections resulting from the search.
382
[378]383    std::vector <Detection> outputList;
384    long zdim = dim[2];
385    int num=0;
386    ProgressBar bar;
387    bool useBar = (zdim>1);
388    if(useBar&&par.isVerbose()) bar.init(zdim);
[263]389 
[378]390    long *imdim = new long[2];
391    imdim[0] = dim[0]; imdim[1] = dim[1];
392    Image *channelImage = new Image(imdim);
393    delete [] imdim;
394    channelImage->saveParam(par);
395    channelImage->saveStats(stats);
396    channelImage->setMinSize(1);
[263]397
[378]398    for(int z=0; z<zdim; z++){  // loop over all channels
[263]399
[378]400      if( par.isVerbose() && useBar ) bar.update(z+1);
[263]401
[378]402      if(!par.isInMW(z)){
403        // purpose of this is to ignore the Milky Way channels
404        //  if we are flagging them
[263]405
[378]406        channelImage->extractImage(reconArray,dim,z);
[582]407        std::vector<Object2D> objlist = channelImage->findSources2D();
[623]408        std::vector<Object2D>::iterator obj;
[378]409        num += objlist.size();
[623]410        for(obj=objlist.begin();obj!=objlist.end();obj++){
[378]411          Detection newObject;
[623]412          newObject.addChannel(z,*obj);
[378]413          newObject.setOffsets(par);
[691]414          if(par.getFlagTwoStageMerging()) mergeIntoList(newObject,outputList,par);
415          else outputList.push_back(newObject);
[378]416        }
[263]417      }
[378]418   
[263]419    }
420
[378]421    delete channelImage;
[263]422
[378]423    if(par.isVerbose()){
424      if(useBar) bar.remove();
425      std::cout << "Found " << num << ".\n";
426    }
427
428
429    return outputList;
[263]430  }
431
432}
Note: See TracBrowser for help on using the repository browser.