source: trunk/src/Cubes/detectionIO.cc @ 528

Last change on this file since 528 was 528, checked in by MatthewWhiting, 15 years ago

Changing the documentation comments to match the askapsoft style. Also have split ChanMap? and Object3D into separate files.

File size: 13.6 KB
Line 
1// -----------------------------------------------------------------------
2// detectionIO.cc: Screen and File output of the detected objects.
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 <iostream>
29#include <sstream>
30#include <fstream>
31#include <iomanip>
32#include <string>
33#include <vector>
34#include <time.h>
35#include <duchamp/param.hh>
36#include <duchamp/fitsHeader.hh>
37#include <duchamp/Cubes/cubes.hh>
38#include <duchamp/PixelMap/Object3D.hh>
39#include <duchamp/Detection/detection.hh>
40#include <duchamp/Detection/columns.hh>
41#include <duchamp/Utils/utils.hh>
42#include <duchamp/Utils/Statistics.hh>
43 
44using std::endl;
45using std::setw;
46using std::setprecision;
47using namespace PixelInfo;
48using namespace Statistics;
49
50namespace duchamp
51{
52
53  void Cube::outputDetectionsKarma(std::ostream &stream)
54  {
55    /// @details
56    ///  Prints to a stream (provided) the list of detected objects in the cube
57    ///   in the format of an annotation file for the Karma suite of programs.
58    ///  Annotation file draws a box enclosing the detection, and writes the
59    ///   ID number of the detection to the right of the box.
60
61    std::string fname = this->par.getImageFile();
62    if(this->par.getFlagSubsection()) fname+=this->par.getSubsection();
63    stream << "# Duchamp Source Finder results for FITS file: " << fname << endl;
64    if(this->par.getFlagFDR())
65      stream<<"# FDR Significance = " << this->par.getAlpha() << endl;
66    else
67      stream<<"# Threshold = " << this->par.getCut() << endl;
68    if(this->par.getFlagATrous()){
69      stream<<"# The a trous reconstruction method was used, with the following parameters." << endl;
70      stream<<"#  ATrous Dimension = " << this->par.getReconDim() << endl;
71      stream<<"#  ATrous Threshold = " << this->par.getAtrousCut() << endl;
72      stream<<"#  ATrous Minimum Scale =" << this->par.getMinScale() << endl;
73      stream<<"#  ATrous Filter = " << this->par.getFilterName() << endl;
74    }
75    else if(this->par.getFlagSmooth()){
76      stream<<"# The data was smoothed prior to searching, with the following parameters." << endl;
77      stream<<"#  Smoothing type = " << this->par.getSmoothType() << endl;
78      if(this->par.getSmoothType()=="spectral"){
79        stream << "#  Hanning width = " << this->par.getHanningWidth() << endl;
80      }
81      else{
82        stream << "#  Kernel Major axis = " << this->par.getKernMaj() << endl;
83        if(this->par.getKernMin()>0)
84          stream << "#  Kernel Minor axis = " << this->par.getKernMin() << endl;
85        else
86          stream << "#  Kernel Minor axis = " << this->par.getKernMaj() << endl;
87        stream << "#  Kernel Major axis = " << this->par.getKernPA() << endl;
88      }
89    }
90    else stream << "# No ATrous reconstruction done." << endl;
91    stream << "#\n";
92    stream << "COLOR RED" << endl;
93    stream << "COORD W" << endl;
94    stream << "FONT lucidasans-12" << endl;
95    stream << std::setprecision(6);
96    stream.setf(std::ios::fixed);
97    double *pix = new double[3];
98    double *wld = new double[3];
99    std::vector<Detection>::iterator obj;
100    for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
101
102      if(this->par.getAnnotationType()=="borders"){
103        std::vector<int> vertexSet = obj->getVertexSet();
104        for(int i=0;i<vertexSet.size()/4;i++){
105          pix[0] = vertexSet[i*4]-0.5;
106          pix[1] = vertexSet[i*4+1]-0.5;
107          pix[2] = obj->getZcentre();
108          this->head.pixToWCS(pix,wld);
109          stream << "LINE " << wld[0] << " " << wld[1];
110          pix[0] = vertexSet[i*4+2]-0.5;
111          pix[1] = vertexSet[i*4+3]-0.5;
112          this->head.pixToWCS(pix,wld);
113          stream << " " << wld[0] << " " << wld[1] << "\n";
114        }
115      }
116      else if(this->par.getAnnotationType()=="circles"){
117        float radius = obj->getRAWidth()/120.;
118        if(obj->getDecWidth()/120.>radius)
119          radius = obj->getDecWidth()/120.;
120        stream << "CIRCLE "
121               << obj->getRA() << " "
122               << obj->getDec() << " "
123               << radius << "\n";
124      }
125
126      stream << "TEXT "
127             << obj->getRA() << " "
128             << obj->getDec() << " "
129             << obj->getID() << "\n\n";
130    }
131
132    delete [] pix;
133    delete [] wld;
134
135  }
136
137  void Cube::prepareOutputFile()
138  {
139    ///  @details
140    ///  A function to write the paramters, time of execution, and
141    ///  statistical information to the output file.
142
143    std::string outfile;
144    if(this->par.getFlagSeparateHeader()) outfile = this->par.getHeaderFile();
145    else outfile = this->par.getOutFile();
146    std::ofstream output(outfile.c_str());
147    output<<"Results of the Duchamp source finder: ";
148    time_t now = time(NULL);
149    output << asctime( localtime(&now) );
150    this->showParam(output);
151    output<<"--------------------\n";
152    output.close();
153    this->outputStats();
154 
155  }
156
157  void Cube::outputStats()
158  {
159    ///  @details
160    ///  A function to write the statistical information to the output
161    ///  file. This writes the threshold, its equivalent S/N ratio, and
162    ///  the noise level and spread.
163    ///
164    ///  If smoothing has been done, the noise level & spread for the
165    ///  original array are calculated and printed as well.
166
167    std::string outfile;
168    if(this->par.getFlagSeparateHeader()) outfile = this->par.getHeaderFile();
169    else outfile = this->par.getOutFile();
170    std::ofstream output(outfile.c_str(),std::ios::app);
171    output<<"Summary of statistics:\n";
172    output<<"Detection threshold = " << this->Stats.getThreshold()
173          <<" " << this->head.getFluxUnits();
174    if(this->par.getFlagFDR())
175      output<<" (or S/N=" << this->Stats.getThresholdSNR()<<")";
176    if(this->par.getFlagSmooth()){
177      output << " in smoothed cube.";
178      if(!this->par.getFlagUserThreshold())
179        output<<"\nNoise level = " << this->Stats.getMiddle()
180              <<", Noise spread = " << this->Stats.getSpread()
181              <<" in smoothed cube.";
182   
183      // calculate the stats for the original array, so that we can
184      // quote S/N values correctly.
185      this->par.setFlagSmooth(false);
186      bool verb=this->par.isVerbose();
187      bool fdrflag=this->par.getFlagFDR();
188      this->par.setVerbosity(false);
189      this->par.setFlagFDR(false);
190      this->setCubeStats();
191      this->par.setVerbosity(verb);
192      this->par.setFlagFDR(fdrflag);
193      this->par.setFlagSmooth(true);
194     
195      output << "\nNoise properties for the original cube are:";
196    }
197     
198    if(!this->par.getFlagUserThreshold())
199      output<<"\nNoise level = " << this->Stats.getMiddle()
200            <<", Noise spread = " << this->Stats.getSpread();
201
202    if(this->par.getFlagGrowth()){
203      StatsContainer<float> growthStats = this->Stats;
204      if(this->par.getFlagUserGrowthThreshold())
205        growthStats.setThreshold(this->par.getGrowthThreshold());
206      else
207        growthStats.setThresholdSNR(this->par.getGrowthCut());
208      growthStats.setUseFDR(false);
209      output<<"\nDetections grown down to threshold of "
210            << growthStats.getThreshold() << " "
211            << this->head.getFluxUnits();
212    }
213
214    if(!this->par.getFlagUserThreshold())
215      output << "\nFull stats:\n" << this->Stats;
216    else
217      output << "\n\nNot calculating full stats since threshold was provided directly.\n";
218
219    output<<"--------------------\n";
220    output.close();
221  }
222
223  void Cube::outputDetectionList()
224  {
225    ///  @details
226    ///  A front-end to writing the full list of detected objects to a results
227    ///   file and to cout.
228    ///  Leaves the testing of whether the WCS parameters for each object
229    ///   have been calculated to the printing function.
230
231    std::string outfile;
232    if(this->par.getFlagSeparateHeader()) outfile = this->par.getHeaderFile();
233    else outfile = this->par.getOutFile();
234    std::ofstream output(outfile.c_str(),std::ios::app);
235    output<<"Total number of detections = "<<this->objectList->size()<<endl;
236    output<<"--------------------\n";
237    output.close();
238
239    if(this->par.getFlagSeparateHeader())
240      output.open(this->par.getOutFile().c_str());
241    else
242      output.open(this->par.getOutFile().c_str(),std::ios::app);
243
244    if(this->objectList->size()>0){
245      this->setupColumns();
246      outputTableHeader(output,this->fullCols,"file",this->head.isWCS());
247      outputTableHeader(std::cout,this->fullCols,"screen",this->head.isWCS());
248      std::vector<Detection>::iterator obj;
249      for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
250        obj->printTableRow(output,this->fullCols,"file");
251        obj->printTableRow(std::cout,this->fullCols,"screen");
252      }
253    }
254
255    output.close();
256  }
257
258  void Cube::prepareLogFile(int argc, char *argv[])
259  {
260    /// @details
261    ///  Opens the log file so that it can be written to, and writes
262    ///  the parameter summary as well as the time of execution to the
263    ///  file.
264    ///
265    ///  It also writes the command-line statement, hence the need for
266    ///  argv and argc.
267
268    // Open the logfile and write the time on the first line
269    std::ofstream logfile(this->par.getLogFile().c_str());
270    logfile << "New run of the Duchamp sourcefinder: ";
271    time_t now = time(NULL);
272    logfile << asctime( localtime(&now) );
273    // Write out the command-line statement
274    logfile << "Executing statement : ";
275    for(int i=0;i<argc;i++) logfile << argv[i] << " ";
276    logfile << std::endl;
277    logfile << this->par;
278    logfile.close();
279
280  }
281
282
283  void Cube::logDetectionList()
284  {
285    /// @details
286    ///  A front-end to writing a list of detected objects to the log file.
287    ///  Does not assume WCS is present.
288    ///  Designed to be used by searching routines before returning their
289    ///   final list.
290
291    if(this->objectList->size()>0){
292
293      long left = this->par.getBorderLeft();
294      long bottom = this->par.getBorderBottom();
295
296      std::ofstream fout(this->par.getLogFile().c_str(),std::ios::app);
297      this->calcObjectFluxes();
298      this->setupColumns();
299      outputTableHeader(fout,this->fullCols,"log",this->head.isWCS());
300
301      if(this->par.getFlagBaseline()){
302        for(int i=0;i<this->axisDim[0]*this->axisDim[1]*this->axisDim[2];i++)
303          this->array[i] += this->baseline[i];
304      }
305
306      for(int objCtr=0;objCtr<this->objectList->size();objCtr++){
307        Detection *obj = new Detection;
308        *obj = objectList->at(objCtr);
309        obj->setOffsets(par);
310        if(this->par.getFlagCubeTrimmed()){
311          obj->pixels().addOffsets(left,bottom,0);
312        }
313        obj->calcFluxes(this->array, this->axisDim);
314        obj->setID(objCtr+1);
315        obj->printTableRow(fout,this->fullCols,"log");
316        delete obj;
317      }
318
319      if(this->par.getFlagBaseline()){
320        for(int i=0;i<this->axisDim[0]*this->axisDim[1]*this->axisDim[2];i++)
321          this->array[i] -= this->baseline[i];
322      }
323      fout.close();
324 
325    }
326
327  }
328
329  void Cube::logDetection(Detection obj, int counter)
330  {
331    /// @details
332    ///  A front-end to writing a detected object to the log file.
333    ///  Does not assume WCS is present.
334    ///  Corrects for changes to positions of pixels and removal of baselines.
335    ///  Designed to be used by searching routines before returning their final
336    ///   list.
337    ///  \param obj Detection object to be written : passed by value, as we want
338    ///    to potentially change positions etc, but not for the object in the
339    ///    calling function.
340    ///  \param counter The number to assign to the object : ideally its number
341    ///    in a list of some kind.
342
343    std::ofstream fout(this->par.getLogFile().c_str(),std::ios::app);
344    // Need to deal with possibility of trimmed array
345    long left = this->par.getBorderLeft();
346    long right = this->par.getBorderRight();
347    long top = this->par.getBorderTop();
348    long bottom = this->par.getBorderBottom();
349    long *tempDim = new long[3];
350    tempDim[0] = (this->axisDim[0] + left + right);
351    tempDim[1] = (this->axisDim[1] + bottom + top);
352    tempDim[2] = this->axisDim[2];
353    long tempsize = tempDim[0] * tempDim[1] * tempDim[2];
354    float *temparray = new float[tempsize];
355    //  for(int i=0;i<this->numPixels;i++){ // loop over this->array
356    for(int z=0;z<tempDim[2];z++){
357      for(int y=0;y<tempDim[1];y++){
358        for(int x=0;x<tempDim[0];x++){
359
360          bool isDud = (x<left) || (x>=this->axisDim[0]+left) ||
361            (y<bottom) || (y>=this->axisDim[1]+bottom);
362       
363          int temppos = x + tempDim[0]*y + tempDim[1]*tempDim[0]*z;
364
365          int pos = (x-left) + (y-bottom)*this->axisDim[0] +
366            z*this->axisDim[0]*this->axisDim[1];
367
368          if(isDud) temparray[temppos] = this->par.getBlankPixVal();
369          else temparray[temppos] = this->array[pos];
370 
371          if(this->par.getFlagBaseline() && !isDud)
372            temparray[temppos] += this->baseline[pos];
373
374        }
375      }
376    }
377
378    if(this->par.getFlagCubeTrimmed()){
379      obj.pixels().addOffsets(left,bottom,0);
380    }
381    obj.calcFluxes(temparray, this->axisDim);
382    obj.printTableRow(fout,this->fullCols,"log");
383    delete [] temparray;
384    delete [] tempDim;
385    fout.close();
386  }
387
388}
Note: See TracBrowser for help on using the repository browser.