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

Last change on this file since 521 was 509, checked in by MatthewWhiting, 16 years ago

Adding a font call to the karma annotation file.

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