source: branches/pixelmap-refactor-branch/src/Cubes/detectionIO.cc @ 1441

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

Improving the updateDetectMap functions and the default values for Detection. Otherwise just cleaning up.

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(unsigned 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(unsigned int objCtr=0;objCtr<this->objectList->size();objCtr++){
307        Detection obj = objectList->at(objCtr);
308        obj.setOffsets(par);
309        if(this->par.getFlagCubeTrimmed()){
310          obj.addOffsets(left,bottom,0);
311        }
312        obj.calcFluxes(this->array, this->axisDim);
313        obj.setID(objCtr+1);
314        obj.printTableRow(fout,this->fullCols,"log");
315      }
316
317      if(this->par.getFlagBaseline()){
318        for(int i=0;i<this->axisDim[0]*this->axisDim[1]*this->axisDim[2];i++)
319          this->array[i] -= this->baseline[i];
320      }
321      fout.close();
322 
323    }
324
325  }
326
327  void Cube::logDetection(Detection obj, int counter)
328  {
329    /// @details
330    ///  A front-end to writing a detected object to the log file.
331    ///  Does not assume WCS is present.
332    ///  Corrects for changes to positions of pixels and removal of baselines.
333    ///  Designed to be used by searching routines before returning their final
334    ///   list.
335    ///  \param obj Detection object to be written : passed by value, as we want
336    ///    to potentially change positions etc, but not for the object in the
337    ///    calling function.
338    ///  \param counter The number to assign to the object : ideally its number
339    ///    in a list of some kind.
340
341    std::ofstream fout(this->par.getLogFile().c_str(),std::ios::app);
342    // Need to deal with possibility of trimmed array
343    long left = this->par.getBorderLeft();
344    long right = this->par.getBorderRight();
345    long top = this->par.getBorderTop();
346    long bottom = this->par.getBorderBottom();
347    long *tempDim = new long[3];
348    tempDim[0] = (this->axisDim[0] + left + right);
349    tempDim[1] = (this->axisDim[1] + bottom + top);
350    tempDim[2] = this->axisDim[2];
351    long tempsize = tempDim[0] * tempDim[1] * tempDim[2];
352    float *temparray = new float[tempsize];
353    //  for(int i=0;i<this->numPixels;i++){ // loop over this->array
354    for(int z=0;z<tempDim[2];z++){
355      for(int y=0;y<tempDim[1];y++){
356        for(int x=0;x<tempDim[0];x++){
357
358          bool isDud = (x<left) || (x>=this->axisDim[0]+left) ||
359            (y<bottom) || (y>=this->axisDim[1]+bottom);
360       
361          int temppos = x + tempDim[0]*y + tempDim[1]*tempDim[0]*z;
362
363          int pos = (x-left) + (y-bottom)*this->axisDim[0] +
364            z*this->axisDim[0]*this->axisDim[1];
365
366          if(isDud) temparray[temppos] = this->par.getBlankPixVal();
367          else temparray[temppos] = this->array[pos];
368 
369          if(this->par.getFlagBaseline() && !isDud)
370            temparray[temppos] += this->baseline[pos];
371
372        }
373      }
374    }
375
376    if(this->par.getFlagCubeTrimmed()){
377      obj.addOffsets(left,bottom,0);
378    }
379    obj.calcFluxes(temparray, this->axisDim);
380    obj.printTableRow(fout,this->fullCols,"log");
381    delete [] temparray;
382    delete [] tempDim;
383    fout.close();
384  }
385
386}
Note: See TracBrowser for help on using the repository browser.