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

Last change on this file since 1074 was 1074, checked in by MatthewWhiting, 12 years ago

Implementing the new annotation writing class, and updating the standard .ann results to include the new statistics information. All looking good.

File size: 14.5 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/Outputs/columns.hh>
41#include <duchamp/Utils/utils.hh>
42#include <duchamp/Utils/Statistics.hh>
43#include <duchamp/Outputs/ASCIICatalogueWriter.hh>
44#include <duchamp/Outputs/VOTableCatalogueWriter.hh>
45#include <duchamp/Outputs/KarmaAnnotationWriter.hh>
46 
47using std::endl;
48using std::setw;
49using std::setprecision;
50using namespace PixelInfo;
51using namespace Statistics;
52
53namespace duchamp
54{
55
56  void Cube::outputDetectionsKarma()
57  {
58    KarmaAnnotationWriter writer(this->pars().getKarmaFile());
59    writer.setup(this);
60    writer.openCatalogue();
61    writer.writeHeader();
62    writer.writeParameters();
63    writer.writeStats();
64    writer.writeTableHeader();
65    writer.writeEntries();
66    writer.writeFooter();
67    writer.closeCatalogue();
68
69  }
70
71  void Cube::outputDetectionsKarma(std::ostream &stream)
72  {
73    /// @details
74    ///  Prints to a stream (provided) the list of detected objects in the cube
75    ///   in the format of an annotation file for the Karma suite of programs.
76    ///  Annotation file draws a box enclosing the detection, and writes the
77    ///   ID number of the detection to the right of the box.
78
79    std::string fname = this->par.getImageFile();
80    if(this->par.getFlagSubsection()) fname+=this->par.getSubsection();
81    stream << "# Duchamp Source Finder v."<< VERSION << endl;
82    stream << "# Results for FITS file: " << fname << endl;
83    if(this->par.getFlagFDR())
84      stream<<"# FDR Significance = " << this->par.getAlpha() << endl;
85    else
86      stream<<"# Threshold = " << this->par.getCut() << endl;
87    if(this->par.getFlagATrous()){
88      stream<<"# The a trous reconstruction method was used, with the following parameters." << endl;
89      stream<<"#  Dimension = " << this->par.getReconDim() << endl;
90      stream<<"#  Threshold = " << this->par.getAtrousCut() << endl;
91      stream<<"#  Minimum Scale =" << this->par.getMinScale() << endl;
92      stream<<"#  Filter = " << this->par.getFilterName() << endl;
93    }
94    else if(this->par.getFlagSmooth()){
95      stream<<"# The data was smoothed prior to searching, with the following parameters." << endl;
96      stream<<"#  Smoothing type = " << this->par.getSmoothType() << endl;
97      if(this->par.getSmoothType()=="spectral"){
98        stream << "#  Hanning width = " << this->par.getHanningWidth() << endl;
99      }
100      else{
101        stream << "#  Kernel Major axis = " << this->par.getKernMaj() << endl;
102        if(this->par.getKernMin()>0)
103          stream << "#  Kernel Minor axis = " << this->par.getKernMin() << endl;
104        else
105          stream << "#  Kernel Minor axis = " << this->par.getKernMaj() << endl;
106        stream << "#  Kernel Major axis = " << this->par.getKernPA() << endl;
107      }
108    }
109    stream << "#\n";
110    stream << "COLOR RED" << endl;
111    if(this->head.isWCS()) stream << "COORD W" << endl;
112    else stream << "COORD P" << endl;
113    stream << std::setprecision(6);
114    stream.setf(std::ios::fixed);
115    double *pix = new double[3];
116    double *wld = new double[3];
117    std::vector<Detection>::iterator obj;
118    for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
119
120      if(this->par.getAnnotationType()=="borders"){
121        std::vector<int> vertexSet = obj->getVertexSet();
122        for(size_t i=0;i<vertexSet.size()/4;i++){
123          pix[0] = vertexSet[i*4]-0.5;
124          pix[1] = vertexSet[i*4+1]-0.5;
125          pix[2] = obj->getZcentre();
126          if(this->head.isWCS()){
127            this->head.pixToWCS(pix,wld);
128            stream << "LINE " << wld[0] << " " << wld[1];
129          }
130          else
131            stream << "LINE " << pix[0] << " " << pix[1];
132          pix[0] = vertexSet[i*4+2]-0.5;
133          pix[1] = vertexSet[i*4+3]-0.5;
134          if(this->head.isWCS()){
135            this->head.pixToWCS(pix,wld);
136            stream << " " << wld[0] << " " << wld[1] << "\n";
137          }
138          else
139            stream << " " << pix[0] << " " << pix[1] << "\n";
140        }
141      }
142      else if(this->par.getAnnotationType()=="circles"){
143        float radius = obj->getRAWidth()/120.;
144        if(obj->getDecWidth()/120.>radius)
145          radius = obj->getDecWidth()/120.;
146        stream << "CIRCLE "
147               << obj->getRA() << " "
148               << obj->getDec() << " "
149               << radius << "\n";
150      }
151
152      stream << "TEXT "
153             << obj->getRA() << " "
154             << obj->getDec() << " "
155             << obj->getID() << "\n\n";
156    }
157
158    delete [] pix;
159    delete [] wld;
160
161  }
162
163  void Cube::outputCatalogue()
164  {
165    this->setupColumns();
166
167    ASCIICatalogueWriter catWriter(this->par.getOutFile(),Catalogues::FILE);
168    catWriter.setup(this);
169    ASCIICatalogueWriter headerWriter(this->par.getHeaderFile(),Catalogues::FILE);
170    headerWriter.setup(this);
171    ASCIICatalogueWriter screenWriter(Catalogues::SCREEN);
172    screenWriter.setup(this);
173    ASCIICatalogueWriter *writer;
174
175    // write the header information
176    if(this->par.getFlagSeparateHeader()) writer = &headerWriter;
177    else writer=&catWriter;
178
179    writer->openCatalogue();
180    writer->writeHeader();
181    writer->writeParameters();
182    writer->writeStats();
183
184    if(this->par.getFlagSeparateHeader()){
185      writer->closeCatalogue();
186      writer = &catWriter;
187      writer->openCatalogue();
188    }
189
190    // write the catalogue
191    writer->writeTableHeader();
192    writer->writeEntries();
193    writer->closeCatalogue();
194
195    screenWriter.openCatalogue();
196    screenWriter.writeTableHeader();
197    screenWriter.writeEntries();
198    screenWriter.closeCatalogue();
199
200  }
201
202
203  void Cube::outputDetectionsVOTable()
204  {
205    VOTableCatalogueWriter writer(this->pars().getVOTFile());
206    writer.setup(this);
207    writer.setTableName("Detections");
208    writer.setTableDescription("Detected sources and parameters from running the Duchamp source finder.");
209    writer.openCatalogue();
210    writer.writeHeader();
211    writer.writeParameters();
212    writer.writeStats();
213    writer.writeTableHeader();
214    writer.writeEntries();
215    writer.writeFooter();
216    writer.closeCatalogue();
217
218  }
219
220
221  void Cube::prepareOutputFile()
222  {
223    ///  @details
224    ///  A function to write the paramters, time of execution, and
225    ///  statistical information to the output file.
226
227    std::string outfile;
228    if(this->par.getFlagSeparateHeader()) outfile = this->par.getHeaderFile();
229    else outfile = this->par.getOutFile();
230    std::ofstream output(outfile.c_str());
231    output<<"Results of the Duchamp source finder v."<<VERSION<<": ";
232    time_t now = time(NULL);
233    output << asctime( localtime(&now) );
234    this->showParam(output);
235    output<<"--------------------\n";
236    output.close();
237    this->outputStats();
238 
239  }
240
241  void Cube::outputStats()
242  {
243    ///  @details
244    ///  A function to write the statistical information to the output
245    ///  file. This writes the threshold, its equivalent S/N ratio, and
246    ///  the noise level and spread.
247    ///
248    ///  If smoothing has been done, the noise level & spread for the
249    ///  original array are calculated and printed as well.
250
251    std::string outfile;
252    if(this->par.getFlagSeparateHeader()) outfile = this->par.getHeaderFile();
253    else outfile = this->par.getOutFile();
254    std::ofstream output(outfile.c_str(),std::ios::app);
255    output<<"Summary of statistics:\n";
256    output<<"Detection threshold = " << this->Stats.getThreshold()
257          <<" " << this->head.getFluxUnits();
258    if(this->par.getFlagFDR())
259      output<<" (or S/N=" << this->Stats.getThresholdSNR()<<")";
260    if(this->par.getFlagSmooth()){
261      output << " in smoothed cube.";
262      if(!this->par.getFlagUserThreshold())
263        output<<"\nNoise level = " << this->Stats.getMiddle()
264              <<", Noise spread = " << this->Stats.getSpread()
265              <<" in smoothed cube.";
266   
267      // calculate the stats for the original array, so that we can
268      // quote S/N values correctly.
269      this->par.setFlagSmooth(false);
270      bool verb=this->par.isVerbose();
271      bool fdrflag=this->par.getFlagFDR();
272      this->par.setVerbosity(false);
273      this->par.setFlagFDR(false);
274      this->setCubeStats();
275      this->par.setVerbosity(verb);
276      this->par.setFlagFDR(fdrflag);
277      this->par.setFlagSmooth(true);
278     
279      output << "\nNoise properties for the original cube are:";
280    }
281     
282    if(!this->par.getFlagUserThreshold())
283      output<<"\nNoise level = " << this->Stats.getMiddle()
284            <<", Noise spread = " << this->Stats.getSpread();
285
286    if(this->par.getFlagGrowth()){
287      StatsContainer<float> growthStats = this->Stats;
288      if(this->par.getFlagUserGrowthThreshold())
289        growthStats.setThreshold(this->par.getGrowthThreshold());
290      else
291        growthStats.setThresholdSNR(this->par.getGrowthCut());
292      growthStats.setUseFDR(false);
293      output<<"\nDetections grown down to threshold of "
294            << growthStats.getThreshold() << " "
295            << this->head.getFluxUnits();
296    }
297
298    if(!this->par.getFlagUserThreshold())
299      output << "\nFull stats:\n" << this->Stats;
300    else
301      output << "\n\nNot calculating full stats since threshold was provided directly.\n";
302
303    output<<"--------------------\n";
304    output.close();
305  }
306
307  void Cube::prepareLogFile(int argc, char *argv[])
308  {
309    /// @details
310    ///  Opens the log file so that it can be written to, and writes
311    ///  the parameter summary as well as the time of execution to the
312    ///  file.
313    ///
314    ///  It also writes the command-line statement, hence the need for
315    ///  argv and argc.
316
317    ASCIICatalogueWriter logwriter(this->par.getLogFile(),Catalogues::LOG);
318    logwriter.setup(this);
319    logwriter.openCatalogue();
320    logwriter.writeHeader();
321    logwriter.writeCommandLineEntry(argc,argv);
322    logwriter.writeParameters();
323    logwriter.closeCatalogue();
324  }
325
326
327  void Cube::logDetectionList(bool calcFluxes)
328  {
329    /// @details
330    ///  A front-end to writing a list of detected objects to the log file.
331    ///  Does not assume WCS is present.
332    ///  Designed to be used by searching routines before returning their
333    ///   final list.
334    ///  @param[in] calcFluxes If true (the default), calculate the various flux parameters for each object.
335
336    if(this->objectList->size()>0){
337
338      ASCIICatalogueWriter logwriter(this->par.getLogFile(),Catalogues::LOG);
339      logwriter.setup(this);
340      logwriter.openCatalogue(std::ios::app);
341
342      long left = this->par.getBorderLeft();
343      long bottom = this->par.getBorderBottom();
344
345      // std::ofstream fout(this->par.getLogFile().c_str(),std::ios::app);
346      if(calcFluxes) this->calcObjectFluxes();
347      this->setupColumns();
348      // outputTableHeader(fout,this->fullCols,Catalogues::LOG,this->head.isWCS());
349      logwriter.writeTableHeader();
350
351      if(this->par.getFlagBaseline()){
352        for(size_t i=0;i<this->axisDim[0]*this->axisDim[1]*this->axisDim[2];i++)
353          this->array[i] += this->baseline[i];
354      }
355
356      for(size_t objCtr=0;objCtr<this->objectList->size();objCtr++){
357        Detection obj = this->objectList->at(objCtr);
358        obj.setOffsets(par);
359        if(this->par.getFlagCubeTrimmed()){
360          obj.addOffsets(left,bottom,0);
361        }
362        if(calcFluxes) obj.calcFluxes(this->array, this->axisDim);
363        obj.setID(objCtr+1);
364        //      obj.printTableRow(fout,this->fullCols,Catalogues::LOG);
365        logwriter.writeEntry(&obj);
366      }
367
368      if(this->par.getFlagBaseline()){
369        for(size_t i=0;i<this->axisDim[0]*this->axisDim[1]*this->axisDim[2];i++)
370          this->array[i] -= this->baseline[i];
371      }
372      //      fout.close();
373      logwriter.closeCatalogue();
374 
375    }
376
377  }
378
379  void Cube::logSummary()
380  {
381    ASCIICatalogueWriter logwriter(this->par.getLogFile(),Catalogues::LOG);
382    logwriter.setup(this);
383    logwriter.openCatalogue(std::ios::app);
384    logwriter.writeCubeSummary();
385    logwriter.closeCatalogue();
386  }
387
388  void Cube::writeSpectralData()
389  {
390    /// @details
391    ///  A function to write, in ascii form, the spectra of each
392    ///  detected object to a file. The file consists of a column for
393    ///  the spectral coordinates, and one column for each object
394    ///  showing the flux at that spectral position. The units are the
395    ///  same as those shown in the graphical output. The filename is
396    ///  given by the Param::spectraTextFile parameter in the Cube::par
397    ///  parameter set.
398
399    const int zdim = this->axisDim[2];
400    const int numObj = this->objectList->size();
401    float *specxOut = new float[zdim];
402    float *spectra = new float[numObj*zdim];
403   
404    for(int obj=0; obj<numObj; obj++){
405      float *temp = new float[zdim];
406      float *specx = new float[zdim];
407      float *recon = new float[zdim];
408      float *base = new float[zdim];
409      this->getSpectralArrays(obj, specx, temp, recon, base);
410      for(int z=0;z<zdim;z++) spectra[obj*zdim+z] = temp[z];
411      if(obj==0) for(int z=0;z<zdim;z++) specxOut[z] = specx[z];
412      delete [] specx;
413      delete [] recon;
414      delete [] base;
415      delete [] temp;
416    }
417   
418    std::ofstream fspec(this->par.getSpectraTextFile().c_str());
419    fspec.setf(std::ios::fixed);
420
421    for(int z=0;z<zdim;z++){
422     
423      fspec << std::setprecision(8);
424      fspec << specxOut[z] << "  ";
425      for(int obj=0;obj<numObj; obj++) {
426        fspec << spectra[obj*zdim+z] << "  ";
427      }
428      fspec << "\n";
429
430    }
431    fspec.close();
432
433    delete [] spectra;
434    delete [] specxOut;
435
436  }
437  //--------------------------------------------------------------------
438
439
440}
Note: See TracBrowser for help on using the repository browser.