source: tags/release-1.1.12/src/ATrous/ReconSearch.cc

Last change on this file 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
Line 
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// -----------------------------------------------------------------------
28#include <fstream>
29#include <iostream>
30#include <iomanip>
31#include <vector>
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>
40
41using namespace PixelInfo;
42using namespace Statistics;
43
44namespace duchamp
45{
46
47  void Cube::ReconSearch()
48  {
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.
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 {
61 
62      this->ReconCube();
63
64      if(this->par.isVerbose()) std::cout << "  ";
65
66      this->setCubeStats();
67   
68      if(this->par.isVerbose()) std::cout << "  Searching... " << std::flush;
69 
70      *this->objectList = searchReconArray(this->axisDim,this->array,
71                                           this->recon,this->par,this->Stats);
72
73      if(this->par.isVerbose()) std::cout << "  Updating detection map... "
74                                          << std::flush;
75      this->updateDetectMap();
76      if(this->par.isVerbose()) std::cout << "Done.\n";
77
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      }
84
85    }
86  }
87
88  /////////////////////////////////////////////////////////////////////////////
89  void Cube::ReconCube()
90  {
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
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());
109    }
110
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      }
136  }
137
138  /////////////////////////////////////////////////////////////////////////////
139  void Cube::ReconCube1D()
140  {
141    /// This reconstructs a cube by performing a 1D a trous reconstruction
142    ///  in the spectrum of each spatial pixel.
143
144    long xySize = this->axisDim[0] * this->axisDim[1];
145
146    long zdim = this->axisDim[2];
147
148    ProgressBar bar;
149    if(!this->reconExists){
150      if(this->par.isVerbose()){
151        std::cout<<"  Reconstructing... ";
152        bar.init(xySize);
153      }
154      for(int npix=0; npix<xySize; npix++){
155
156        if( this->par.isVerbose() ) bar.update(npix+1);
157
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];
161        bool verboseFlag = this->par.isVerbose();
162        this->par.setVerbosity(false);
163        atrous1DReconstruct(this->axisDim[2],spec,newSpec,this->par);
164        this->par.setVerbosity(verboseFlag);
165        for(int z=0;z<zdim;z++) this->recon[z*xySize+npix] = newSpec[z];
166        delete [] spec;
167        delete [] newSpec;
168      }
169      this->reconExists = true;
170      if(this->par.isVerbose()){
171        bar.fillSpace(" All Done.");
172        printSpace(22);
173        std::cout << "\n";
174      }
175    }
176
177  }
178
179  /////////////////////////////////////////////////////////////////////////////
180  void Cube::ReconCube2D()
181  {
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
185    long xySize = this->axisDim[0] * this->axisDim[1];
186    ProgressBar bar;
187    bool useBar = (this->axisDim[2]>1);
188
189    if(!this->reconExists){
190      if(this->par.isVerbose()) std::cout<<"  Reconstructing... ";
191      if(useBar&&this->par.isVerbose()) bar.init(this->axisDim[2]);
192      for(int z=0;z<this->axisDim[2];z++){
193
194        if( this->par.isVerbose() && useBar ) bar.update((z+1));
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      }
216      this->reconExists = true;
217      if(this->par.isVerbose()) {
218        if(useBar) bar.fillSpace(" All Done.");
219        printSpace(22);
220        std::cout << "\n";
221      }
222    }
223  }
224
225  /////////////////////////////////////////////////////////////////////////////
226  void Cube::ReconCube3D()
227  {
228    /// This performs a full 3D a trous reconstruction of the cube
229
230    if(this->axisDim[2]==1) this->ReconCube2D();
231    else {
232
233      if(!this->reconExists){
234        if(this->par.isVerbose()) std::cout<<"  Reconstructing... "<<std::flush;
235        atrous3DReconstruct(this->axisDim[0],this->axisDim[1],this->axisDim[2],
236                            this->array,this->recon,this->par);
237        this->reconExists = true;
238        if(this->par.isVerbose()) {
239          std::cout << "  All Done.";
240          printSpace(22);
241          std::cout << "\n";
242        }
243      }
244
245    }
246  }
247
248  /////////////////////////////////////////////////////////////////////////////
249  std::vector <Detection> searchReconArray(long *dim, float *originalArray,
250                                           float *reconArray, Param &par,
251                                           StatsContainer<float> &stats)
252  {
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  {
270    ///  This searches for objects in a cube that has been reconstructed.
271    ///
272    ///  The search is conducted just in each spatial pixel (xdim*ydim 1D
273    ///   searches).
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
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){
293
294      ProgressBar bar;
295      if(par.isVerbose()) bar.init(xySize);
296
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      }
308
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());
316      // NB the beam is not used after this point
317      // spectrum->pars().setBeamSize(2.);
318      // // beam size: for spectrum, only neighbouring channels correlated
319
320      for(int y=0; y<dim[1]; y++){
321        for(int x=0; x<dim[0]; x++){
322
323          int npix = y*dim[0] + x;
324          if( par.isVerbose() ) bar.update(npix+1);
325
326          if(doPixel[npix]){
327
328            spectrum->extractSpectrum(reconArray,dim,npix);
329            spectrum->removeMW(); // only works if flagMW is true
330            std::vector<Scan> objlist = spectrum->findSources1D();
331            std::vector<Scan>::iterator obj;
332            num += objlist.size();
333            for(obj=objlist.begin();obj!=objlist.end();obj++){
334              Detection newObject;
335              // Fix up coordinates of each pixel to match original array
336              for(int z=obj->getX();z<=obj->getXmax();z++) {
337                newObject.addPixel(x,y,z);
338              }
339              newObject.setOffsets(par);
340              if(par.getFlagTwoStageMerging()) mergeIntoList(newObject,outputList,par);
341              else outputList.push_back(newObject);
342            }
343          }
344
345        }
346      }
347
348      delete spectrum;
349      delete [] doPixel;
350     
351      if(par.isVerbose()){
352        bar.remove();
353        std::cout << "Found " << num << ".\n";
354      }
355
356    }
357
358    return outputList;
359  }
360
361  /////////////////////////////////////////////////////////////////////////////
362  std::vector <Detection> searchReconArraySpatial(long *dim, float *originalArray,
363                                                  float *reconArray, Param &par,
364                                                  StatsContainer<float> &stats)
365  {
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
369    ///  searches).
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
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);
389 
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);
397
398    for(int z=0; z<zdim; z++){  // loop over all channels
399
400      if( par.isVerbose() && useBar ) bar.update(z+1);
401
402      if(!par.isInMW(z)){
403        // purpose of this is to ignore the Milky Way channels
404        //  if we are flagging them
405
406        channelImage->extractImage(reconArray,dim,z);
407        std::vector<Object2D> objlist = channelImage->findSources2D();
408        std::vector<Object2D>::iterator obj;
409        num += objlist.size();
410        for(obj=objlist.begin();obj!=objlist.end();obj++){
411          Detection newObject;
412          newObject.addChannel(z,*obj);
413          newObject.setOffsets(par);
414          if(par.getFlagTwoStageMerging()) mergeIntoList(newObject,outputList,par);
415          else outputList.push_back(newObject);
416        }
417      }
418   
419    }
420
421    delete channelImage;
422
423    if(par.isVerbose()){
424      if(useBar) bar.remove();
425      std::cout << "Found " << num << ".\n";
426    }
427
428
429    return outputList;
430  }
431
432}
Note: See TracBrowser for help on using the repository browser.