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

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

Getting rid of the FONT definition in the karma annotation files. If this font is not present it becomes very annoying...

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