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

Last change on this file since 1160 was 1157, checked in by MatthewWhiting, 11 years ago

Adding version number to the binary catalogue output, and changing the usage message when we create the binary catalogue.

File size: 15.2 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#include <duchamp/Outputs/DS9AnnotationWriter.hh>
47#include <duchamp/Outputs/CasaAnnotationWriter.hh>
48 
49using std::endl;
50using std::setw;
51using std::setprecision;
52using namespace PixelInfo;
53using namespace Statistics;
54
55namespace duchamp
56{
57
58  void Cube::outputAnnotations()
59  {
60   
61    for(int i=0;i<3;i++){
62      AnnotationWriter *writer=0;
63      switch(i){
64      case 0: //Karma
65        if(this->par.getFlagKarma())
66          writer = new KarmaAnnotationWriter(this->par.getKarmaFile());
67        break;
68      case 1://DS9
69        if(this->par.getFlagDS9())
70          writer = new DS9AnnotationWriter(this->par.getDS9File());
71        break;
72      case 2://DS9
73        if(this->par.getFlagCasa())
74          writer = new CasaAnnotationWriter(this->par.getCasaFile());
75        break; 
76      }
77      if(writer!=0){
78        writer->setup(this);
79        writer->openCatalogue();
80        writer->writeHeader();
81        writer->writeParameters();
82        writer->writeStats();
83        writer->writeTableHeader();
84        writer->writeEntries();
85        writer->writeFooter();
86        writer->closeCatalogue();
87      }
88
89      delete writer;
90    }
91
92  }
93
94  void Cube::outputDetectionsKarma()
95  {
96    KarmaAnnotationWriter writer(this->pars().getKarmaFile());
97    writer.setup(this);
98    writer.openCatalogue();
99    writer.writeHeader();
100    writer.writeParameters();
101    writer.writeStats();
102    writer.writeTableHeader();
103    writer.writeEntries();
104    writer.writeFooter();
105    writer.closeCatalogue();
106
107  }
108
109  void Cube::outputDetectionsDS9()
110  {
111    DS9AnnotationWriter writer(this->pars().getDS9File());
112    writer.setup(this);
113    writer.openCatalogue();
114    writer.writeHeader();
115    writer.writeParameters();
116    writer.writeStats();
117    writer.writeTableHeader();
118    writer.writeEntries();
119    writer.writeFooter();
120    writer.closeCatalogue();
121
122  }
123
124  void Cube::outputDetectionsCasa()
125  {
126    CasaAnnotationWriter writer(this->pars().getCasaFile());
127    writer.setup(this);
128    writer.openCatalogue();
129    writer.writeHeader();
130    writer.writeParameters();
131    writer.writeStats();
132    writer.writeTableHeader();
133    writer.writeEntries();
134    writer.writeFooter();
135    writer.closeCatalogue();
136
137  }
138
139  void Cube::outputCatalogue()
140  {
141    this->setupColumns();
142
143    ASCIICatalogueWriter catWriter(this->par.getOutFile(),Catalogues::FILE);
144    catWriter.setup(this);
145    ASCIICatalogueWriter headerWriter(this->par.getHeaderFile(),Catalogues::FILE);
146    headerWriter.setup(this);
147    ASCIICatalogueWriter screenWriter(Catalogues::SCREEN);
148    screenWriter.setup(this);
149    ASCIICatalogueWriter *writer;
150
151    // write the header information
152    if(this->par.getFlagSeparateHeader()) writer = &headerWriter;
153    else writer=&catWriter;
154
155    writer->openCatalogue();
156    writer->writeHeader();
157    writer->writeParameters();
158    writer->writeStats();
159
160    if(this->par.getFlagSeparateHeader()){
161      writer->closeCatalogue();
162      writer = &catWriter;
163      writer->openCatalogue();
164    }
165
166    // write the catalogue
167    writer->writeTableHeader();
168    writer->writeEntries();
169    writer->closeCatalogue();
170
171    screenWriter.openCatalogue();
172    screenWriter.writeTableHeader();
173    screenWriter.writeEntries();
174    screenWriter.closeCatalogue();
175
176  }
177
178
179  void Cube::outputDetectionsVOTable()
180  {
181    VOTableCatalogueWriter writer(this->pars().getVOTFile());
182    writer.setup(this);
183    writer.setTableName("Detections");
184    writer.setTableDescription("Detected sources and parameters from running the Duchamp source finder.");
185    writer.openCatalogue();
186    writer.writeHeader();
187    writer.writeParameters();
188    writer.writeStats();
189    writer.writeTableHeader();
190    writer.writeEntries();
191    writer.writeFooter();
192    writer.closeCatalogue();
193
194  }
195
196
197  void Cube::prepareOutputFile()
198  {
199    ///  @details
200    ///  A function to write the paramters, time of execution, and
201    ///  statistical information to the output file.
202
203    std::string outfile;
204    if(this->par.getFlagSeparateHeader()) outfile = this->par.getHeaderFile();
205    else outfile = this->par.getOutFile();
206    std::ofstream output(outfile.c_str());
207    output<<"Results of the Duchamp source finder v."<<VERSION<<": ";
208    time_t now = time(NULL);
209    output << asctime( localtime(&now) );
210    this->showParam(output);
211    output<<"--------------------\n";
212    output.close();
213    this->outputStats();
214 
215  }
216
217  void Cube::outputStats()
218  {
219    ///  @details
220    ///  A function to write the statistical information to the output
221    ///  file. This writes the threshold, its equivalent S/N ratio, and
222    ///  the noise level and spread.
223    ///
224    ///  If smoothing has been done, the noise level & spread for the
225    ///  original array are calculated and printed as well.
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(),std::ios::app);
231    output<<"Summary of statistics:\n";
232    output<<"Detection threshold = " << this->Stats.getThreshold()
233          <<" " << this->head.getFluxUnits();
234    if(this->par.getFlagFDR())
235      output<<" (or S/N=" << this->Stats.getThresholdSNR()<<")";
236    if(this->par.getFlagSmooth()){
237      output << " in smoothed cube.";
238      if(!this->par.getFlagUserThreshold())
239        output<<"\nNoise level = " << this->Stats.getMiddle()
240              <<", Noise spread = " << this->Stats.getSpread()
241              <<" in smoothed cube.";
242   
243      // calculate the stats for the original array, so that we can
244      // quote S/N values correctly.
245      this->par.setFlagSmooth(false);
246      bool verb=this->par.isVerbose();
247      bool fdrflag=this->par.getFlagFDR();
248      this->par.setVerbosity(false);
249      this->par.setFlagFDR(false);
250      this->setCubeStats();
251      this->par.setVerbosity(verb);
252      this->par.setFlagFDR(fdrflag);
253      this->par.setFlagSmooth(true);
254     
255      output << "\nNoise properties for the original cube are:";
256    }
257     
258    if(!this->par.getFlagUserThreshold())
259      output<<"\nNoise level = " << this->Stats.getMiddle()
260            <<", Noise spread = " << this->Stats.getSpread();
261
262    if(this->par.getFlagGrowth()){
263      StatsContainer<float> growthStats = this->Stats;
264      if(this->par.getFlagUserGrowthThreshold())
265        growthStats.setThreshold(this->par.getGrowthThreshold());
266      else
267        growthStats.setThresholdSNR(this->par.getGrowthCut());
268      growthStats.setUseFDR(false);
269      output<<"\nDetections grown down to threshold of "
270            << growthStats.getThreshold() << " "
271            << this->head.getFluxUnits();
272    }
273
274    if(!this->par.getFlagUserThreshold())
275      output << "\nFull stats:\n" << this->Stats;
276    else
277      output << "\n\nNot calculating full stats since threshold was provided directly.\n";
278
279    output<<"--------------------\n";
280    output.close();
281  }
282
283  void Cube::prepareLogFile(int argc, char *argv[])
284  {
285    /// @details
286    ///  Opens the log file so that it can be written to, and writes
287    ///  the parameter summary as well as the time of execution to the
288    ///  file.
289    ///
290    ///  It also writes the command-line statement, hence the need for
291    ///  argv and argc.
292
293    ASCIICatalogueWriter logwriter(this->par.getLogFile(),Catalogues::LOG);
294    logwriter.setup(this);
295    logwriter.openCatalogue();
296    logwriter.writeHeader();
297    logwriter.writeCommandLineEntry(argc,argv);
298    logwriter.writeParameters();
299    logwriter.closeCatalogue();
300  }
301
302
303  void Cube::logDetectionList(bool calcFluxes)
304  {
305    /// @details
306    ///  A front-end to writing a list of detected objects to the log file.
307    ///  Does not assume WCS is present.
308    ///  Designed to be used by searching routines before returning their
309    ///   final list.
310    ///  @param[in] calcFluxes If true (the default), calculate the various flux parameters for each object.
311
312    if(this->objectList->size()>0){
313
314      long left = this->par.getBorderLeft();
315      long bottom = this->par.getBorderBottom();
316
317      if(calcFluxes) this->calcObjectFluxes();
318      this->setupColumns();
319
320      ASCIICatalogueWriter logwriter(this->par.getLogFile(),Catalogues::LOG);
321      logwriter.setup(this);
322      logwriter.openCatalogue(std::ios::app);
323      logwriter.writeTableHeader();
324
325      if(this->par.getFlagBaseline()){
326        for(size_t i=0;i<this->axisDim[0]*this->axisDim[1]*this->axisDim[2];i++)
327          this->array[i] += this->baseline[i];
328      }
329
330      for(size_t objCtr=0;objCtr<this->objectList->size();objCtr++){
331        Detection obj = this->objectList->at(objCtr);
332        obj.setOffsets(par);
333        if(this->par.getFlagCubeTrimmed()){
334          obj.addOffsets(left,bottom,0);
335        }
336        if(calcFluxes) obj.calcFluxes(this->array, this->axisDim);
337        obj.setID(objCtr+1);
338        logwriter.writeEntry(&obj);
339      }
340
341      if(this->par.getFlagBaseline()){
342        for(size_t i=0;i<this->axisDim[0]*this->axisDim[1]*this->axisDim[2];i++)
343          this->array[i] -= this->baseline[i];
344      }
345
346      logwriter.closeCatalogue();
347 
348    }
349
350  }
351
352  void Cube::logSummary()
353  {
354    ASCIICatalogueWriter logwriter(this->par.getLogFile(),Catalogues::LOG);
355    logwriter.setup(this);
356    logwriter.openCatalogue(std::ios::app);
357    logwriter.writeCubeSummary();
358    logwriter.closeCatalogue();
359  }
360
361  void Cube::writeBinaryCatalogue()
362  {
363    if(this->par.getFlagWriteBinaryCatalogue()){
364     
365      std::ofstream bincat(this->par.getBinaryCatalogue().c_str(), std::ios::out | std::ios::binary);
366      writeStringToBinaryFile(bincat,PACKAGE_VERSION);
367      time_t now = time(NULL);
368      std::string nowstr(asctime(localtime(&now)));
369      writeStringToBinaryFile(bincat,nowstr);
370      bincat.close();
371      this->par.writeToBinaryFile();
372
373      this->Stats.writeToBinaryFile(this->par.getBinaryCatalogue());
374 
375      bincat.open(this->par.getBinaryCatalogue().c_str(), std::ios::out | std::ios::binary | std::ios::app);
376      size_t numObj=this->objectList->size();
377      bincat.write(reinterpret_cast<const char*>(&numObj), sizeof numObj);
378      bincat.close();
379
380      for(size_t i=0;i<numObj;i++)
381        this->objectList->at(i).write(this->par.getBinaryCatalogue());
382
383    }
384  }
385
386  OUTCOME Cube::readBinaryCatalogue()
387  {
388    std::ifstream bincat(this->par.getBinaryCatalogue().c_str(), std::ios::in | std::ios::binary);
389    if(!bincat.is_open()){
390      DUCHAMPERROR("read binary catalogue", "Could not open binary catalogue \""<<this->par.getBinaryCatalogue()<<"\".");
391      return FAILURE;
392    }
393    std::string bincatVersion = readStringFromBinaryFile(bincat);
394    if(bincatVersion != std::string(PACKAGE_VERSION))
395        DUCHAMPWARN("read binary catalogue","Duchamp versions don't match: Binary catalogue has " << bincatVersion << " compared to " << PACKAGE_VERSION<<". Attempting to continue, but beware!");
396
397    std::string nowstr=readStringFromBinaryFile(bincat);
398    if(this->par.isVerbose()) std::cout << "  Reading from binary catalogue " << this->par.getBinaryCatalogue() << " made on " << nowstr << std::flush;
399    std::streampos loc=bincat.tellg();
400    bincat.close();
401
402    loc = this->par.readFromBinaryFile(loc);
403    if(loc<0) {
404      DUCHAMPERROR("read binary catalogue","Error reading catalogue");
405      return FAILURE;
406    }
407
408    loc=this->Stats.readFromBinaryFile(this->par.getBinaryCatalogue(),loc);
409    if(loc<0) {
410      DUCHAMPERROR("read binary catalogue","Error reading catalogue");
411      return FAILURE;
412    }
413
414    bincat.open(this->par.getBinaryCatalogue().c_str(), std::ios::in | std::ios::binary);
415    bincat.seekg(loc);
416    size_t numObj;
417    bincat.read(reinterpret_cast<char*>(&numObj), sizeof numObj);
418    loc=bincat.tellg();
419    bincat.close();
420
421    for(size_t i=0;i<numObj;i++){
422      Object3D obj;
423      loc=obj.read(this->par.getBinaryCatalogue(),loc);
424      this->objectList->push_back(obj);
425    }
426
427    if(this->par.isVerbose()) std::cout << "  Successfully read " << numObj << " objects from the binary catalogue.\n";
428
429    this->updateDetectMap();
430
431    return SUCCESS;
432
433  }
434
435
436  void Cube::writeSpectralData()
437  {
438    /// @details
439    ///  A function to write, in ascii form, the spectra of each
440    ///  detected object to a file. The file consists of a column for
441    ///  the spectral coordinates, and one column for each object
442    ///  showing the flux at that spectral position. The units are the
443    ///  same as those shown in the graphical output. The filename is
444    ///  given by the Param::spectraTextFile parameter in the Cube::par
445    ///  parameter set.
446
447    const int zdim = this->axisDim[2];
448    float *specxOut = new float[zdim];
449
450    std::vector<bool> objectChoice = this->par.getObjectChoices(this->objectList->size());
451    size_t numObj = 0;
452    for(size_t i=0;i<this->objectList->size();i++) if(objectChoice[i]) numObj++;
453
454    float *spectra = new float[numObj*zdim];
455   
456    size_t obj=0;
457    for(size_t i=0;i<this->objectList->size();i++){
458      if(objectChoice[i]){
459        float *temp = new float[zdim];
460        float *specx = new float[zdim];
461        float *recon = new float[zdim];
462        float *base = new float[zdim];
463        this->getSpectralArrays(i, specx, temp, recon, base);
464        for(int z=0;z<zdim;z++) spectra[obj*zdim+z] = temp[z];
465        if(obj==0) for(int z=0;z<zdim;z++) specxOut[z] = specx[z];
466        obj++;
467        delete [] specx;
468        delete [] recon;
469        delete [] base;
470        delete [] temp;
471      }
472    }
473   
474    std::ofstream fspec(this->par.getSpectraTextFile().c_str());
475    fspec.setf(std::ios::fixed);
476
477    for(int z=0;z<zdim;z++){
478     
479      fspec << std::setprecision(8);
480      fspec << specxOut[z] << "  ";
481      obj=0;
482      for(size_t i=0;i<this->objectList->size();i++){
483        if(objectChoice[i]){
484          fspec << spectra[obj*zdim+z] << "  ";
485          obj++;
486        }
487      }
488      fspec << "\n";
489
490    }
491    fspec.close();
492
493    delete [] spectra;
494    delete [] specxOut;
495
496  }
497  //--------------------------------------------------------------------
498
499
500}
Note: See TracBrowser for help on using the repository browser.