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

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

Cleaning up - removing all the old commented out code. We can also remove entirely the file src/Cubes/VOTable.cc, by incorporating the outputDetectionsVOTable() function to detectionIO.cc

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