source: trunk/src/Cubes/detectionIO.cc

Last change on this file was 1424, checked in by MatthewWhiting, 7 years ago

Applying patch from ASKAPsoft development, where we allow more
flexibility in specifying the RESOURCE and TABLE names for the VOTable
output.
ASKAPSDP revision r6758

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