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

Last change on this file since 674 was 674, checked in by MatthewWhiting, 14 years ago

Minor changes to annotation output following #64.

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<<"#  Dimension = " << this->par.getReconDim() << endl;
71      stream<<"#  Threshold = " << this->par.getAtrousCut() << endl;
72      stream<<"#  Minimum Scale =" << this->par.getMinScale() << endl;
73      stream<<"#  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    stream << "#\n";
91    stream << "COLOR RED" << endl;
92    stream << "COORD W" << endl;
93    stream << "FONT lucidasans-12" << endl;
94    stream << std::setprecision(6);
95    stream.setf(std::ios::fixed);
96    double *pix = new double[3];
97    double *wld = new double[3];
98    std::vector<Detection>::iterator obj;
99    for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
100
101      if(this->par.getAnnotationType()=="borders"){
102        std::vector<int> vertexSet = obj->getVertexSet();
103        for(size_t i=0;i<vertexSet.size()/4;i++){
104          pix[0] = vertexSet[i*4]-0.5;
105          pix[1] = vertexSet[i*4+1]-0.5;
106          pix[2] = obj->getZcentre();
107          this->head.pixToWCS(pix,wld);
108          stream << "LINE " << wld[0] << " " << wld[1];
109          pix[0] = vertexSet[i*4+2]-0.5;
110          pix[1] = vertexSet[i*4+3]-0.5;
111          this->head.pixToWCS(pix,wld);
112          stream << " " << wld[0] << " " << wld[1] << "\n";
113        }
114      }
115      else if(this->par.getAnnotationType()=="circles"){
116        float radius = obj->getRAWidth()/120.;
117        if(obj->getDecWidth()/120.>radius)
118          radius = obj->getDecWidth()/120.;
119        stream << "CIRCLE "
120               << obj->getRA() << " "
121               << obj->getDec() << " "
122               << radius << "\n";
123      }
124
125      stream << "TEXT "
126             << obj->getRA() << " "
127             << obj->getDec() << " "
128             << obj->getID() << "\n\n";
129    }
130
131    delete [] pix;
132    delete [] wld;
133
134  }
135
136  void Cube::prepareOutputFile()
137  {
138    ///  @details
139    ///  A function to write the paramters, time of execution, and
140    ///  statistical information to the output file.
141
142    std::string outfile;
143    if(this->par.getFlagSeparateHeader()) outfile = this->par.getHeaderFile();
144    else outfile = this->par.getOutFile();
145    std::ofstream output(outfile.c_str());
146    output<<"Results of the Duchamp source finder: ";
147    time_t now = time(NULL);
148    output << asctime( localtime(&now) );
149    this->showParam(output);
150    output<<"--------------------\n";
151    output.close();
152    this->outputStats();
153 
154  }
155
156  void Cube::outputStats()
157  {
158    ///  @details
159    ///  A function to write the statistical information to the output
160    ///  file. This writes the threshold, its equivalent S/N ratio, and
161    ///  the noise level and spread.
162    ///
163    ///  If smoothing has been done, the noise level & spread for the
164    ///  original array are calculated and printed as well.
165
166    std::string outfile;
167    if(this->par.getFlagSeparateHeader()) outfile = this->par.getHeaderFile();
168    else outfile = this->par.getOutFile();
169    std::ofstream output(outfile.c_str(),std::ios::app);
170    output<<"Summary of statistics:\n";
171    output<<"Detection threshold = " << this->Stats.getThreshold()
172          <<" " << this->head.getFluxUnits();
173    if(this->par.getFlagFDR())
174      output<<" (or S/N=" << this->Stats.getThresholdSNR()<<")";
175    if(this->par.getFlagSmooth()){
176      output << " in smoothed cube.";
177      if(!this->par.getFlagUserThreshold())
178        output<<"\nNoise level = " << this->Stats.getMiddle()
179              <<", Noise spread = " << this->Stats.getSpread()
180              <<" in smoothed cube.";
181   
182      // calculate the stats for the original array, so that we can
183      // quote S/N values correctly.
184      this->par.setFlagSmooth(false);
185      bool verb=this->par.isVerbose();
186      bool fdrflag=this->par.getFlagFDR();
187      this->par.setVerbosity(false);
188      this->par.setFlagFDR(false);
189      this->setCubeStats();
190      this->par.setVerbosity(verb);
191      this->par.setFlagFDR(fdrflag);
192      this->par.setFlagSmooth(true);
193     
194      output << "\nNoise properties for the original cube are:";
195    }
196     
197    if(!this->par.getFlagUserThreshold())
198      output<<"\nNoise level = " << this->Stats.getMiddle()
199            <<", Noise spread = " << this->Stats.getSpread();
200
201    if(this->par.getFlagGrowth()){
202      StatsContainer<float> growthStats = this->Stats;
203      if(this->par.getFlagUserGrowthThreshold())
204        growthStats.setThreshold(this->par.getGrowthThreshold());
205      else
206        growthStats.setThresholdSNR(this->par.getGrowthCut());
207      growthStats.setUseFDR(false);
208      output<<"\nDetections grown down to threshold of "
209            << growthStats.getThreshold() << " "
210            << this->head.getFluxUnits();
211    }
212
213    if(!this->par.getFlagUserThreshold())
214      output << "\nFull stats:\n" << this->Stats;
215    else
216      output << "\n\nNot calculating full stats since threshold was provided directly.\n";
217
218    output<<"--------------------\n";
219    output.close();
220  }
221
222  void Cube::outputDetectionList()
223  {
224    ///  @details
225    ///  A front-end to writing the full list of detected objects to a results
226    ///   file and to cout.
227    ///  Leaves the testing of whether the WCS parameters for each object
228    ///   have been calculated to the printing function.
229
230    std::string outfile;
231    if(this->par.getFlagSeparateHeader()) outfile = this->par.getHeaderFile();
232    else outfile = this->par.getOutFile();
233    std::ofstream output(outfile.c_str(),std::ios::app);
234    output<<"Total number of detections = "<<this->objectList->size()<<endl;
235    output<<"--------------------\n";
236    output.close();
237
238    if(this->par.getFlagSeparateHeader())
239      output.open(this->par.getOutFile().c_str());
240    else
241      output.open(this->par.getOutFile().c_str(),std::ios::app);
242
243    if(this->objectList->size()>0){
244      this->setupColumns();
245      outputTableHeader(output,this->fullCols,"file",this->head.isWCS());
246      outputTableHeader(std::cout,this->fullCols,"screen",this->head.isWCS());
247      std::vector<Detection>::iterator obj;
248      for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
249        obj->printTableRow(output,this->fullCols,"file");
250        obj->printTableRow(std::cout,this->fullCols,"screen");
251      }
252    }
253
254    output.close();
255  }
256
257  void Cube::prepareLogFile(int argc, char *argv[])
258  {
259    /// @details
260    ///  Opens the log file so that it can be written to, and writes
261    ///  the parameter summary as well as the time of execution to the
262    ///  file.
263    ///
264    ///  It also writes the command-line statement, hence the need for
265    ///  argv and argc.
266
267    // Open the logfile and write the time on the first line
268    std::ofstream logfile(this->par.getLogFile().c_str());
269    logfile << "New run of the Duchamp sourcefinder: ";
270    time_t now = time(NULL);
271    logfile << asctime( localtime(&now) );
272    // Write out the command-line statement
273    logfile << "Executing statement : ";
274    for(int i=0;i<argc;i++) logfile << argv[i] << " ";
275    logfile << std::endl;
276    logfile << this->par;
277    logfile.close();
278
279  }
280
281
282  void Cube::logDetectionList(bool calcFluxes)
283  {
284    /// @details
285    ///  A front-end to writing a list of detected objects to the log file.
286    ///  Does not assume WCS is present.
287    ///  Designed to be used by searching routines before returning their
288    ///   final list.
289    ///  @param[in] calcFluxes If true (the default), calculate the various flux parameters for each object.
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      if(calcFluxes) 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(size_t objCtr=0;objCtr<this->objectList->size();objCtr++){
307        Detection obj = this->objectList->at(objCtr);
308        obj.setOffsets(par);
309        if(this->par.getFlagCubeTrimmed()){
310          obj.addOffsets(left,bottom,0);
311        }
312        if(calcFluxes) 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.