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
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/Detection/columns.hh>
41#include <duchamp/Utils/utils.hh>
42#include <duchamp/Utils/Statistics.hh>
43 
44using std::endl;
45using std::setw;
46using std::setprecision;
47using namespace PixelInfo;
48using namespace Statistics;
49
50namespace duchamp
51{
52
53  void Cube::outputDetectionsKarma(std::ostream &stream)
54  {
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.
60
61    std::string fname = this->par.getImageFile();
62    if(this->par.getFlagSubsection()) fname+=this->par.getSubsection();
63    stream << "# Duchamp Source Finder v."<< VERSION << endl;
64    stream << "# Results for FITS file: " << fname << endl;
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;
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;
75    }
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    }
91    stream << "#\n";
92    stream << "COLOR RED" << endl;
93    stream << "COORD W" << endl;
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++){
100
101      if(this->par.getAnnotationType()=="borders"){
102        std::vector<int> vertexSet = obj->getVertexSet();
103        for(size_t i=0;i<vertexSet.size()/4;i++){
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        }
114      }
115      else if(this->par.getAnnotationType()=="circles"){
116        float radius = obj->getRAWidth()/120.;
117        if(obj->getDecWidth()/120.>radius)
118          radius = obj->getDecWidth()/120.;
119        stream << "CIRCLE "
120               << obj->getRA() << " "
121               << obj->getDec() << " "
122               << radius << "\n";
123      }
124
125      stream << "TEXT "
126             << obj->getRA() << " "
127             << obj->getDec() << " "
128             << obj->getID() << "\n\n";
129    }
130
131    delete [] pix;
132    delete [] wld;
133
134  }
135
136  void Cube::prepareOutputFile()
137  {
138    ///  @details
139    ///  A function to write the paramters, time of execution, and
140    ///  statistical information to the output file.
141
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());
146    output<<"Results of the Duchamp source finder v."<<VERSION<<": ";
147    time_t now = time(NULL);
148    output << asctime( localtime(&now) );
149    this->showParam(output);
150    output<<"--------------------\n";
151    output.close();
152    this->outputStats();
153 
154  }
155
156  void Cube::outputStats()
157  {
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.
165
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";
171    output<<"Detection threshold = " << this->Stats.getThreshold()
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())
178        output<<"\nNoise level = " << this->Stats.getMiddle()
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     
194      output << "\nNoise properties for the original cube are:";
195    }
196     
197    if(!this->par.getFlagUserThreshold())
198      output<<"\nNoise level = " << this->Stats.getMiddle()
199            <<", Noise spread = " << this->Stats.getSpread();
200
201    if(this->par.getFlagGrowth()){
202      StatsContainer<float> growthStats = this->Stats;
203      if(this->par.getFlagUserGrowthThreshold())
204        growthStats.setThreshold(this->par.getGrowthThreshold());
205      else
206        growthStats.setThresholdSNR(this->par.getGrowthCut());
207      growthStats.setUseFDR(false);
208      output<<"\nDetections grown down to threshold of "
209            << growthStats.getThreshold() << " "
210            << this->head.getFluxUnits();
211    }
212
213    if(!this->par.getFlagUserThreshold())
214      output << "\nFull stats:\n" << this->Stats;
215    else
216      output << "\n\nNot calculating full stats since threshold was provided directly.\n";
217
218    output<<"--------------------\n";
219    output.close();
220  }
221
222  void Cube::outputDetectionList()
223  {
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.
229
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();
237
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);
242
243    if(this->objectList->size()>0){
244      this->setupColumns();
245      outputTableHeader(output,this->fullCols,"file",this->head.isWCS());
246      outputTableHeader(std::cout,this->fullCols,"screen",this->head.isWCS());
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");
251      }
252    }
253
254    output.close();
255  }
256
257  void Cube::prepareLogFile(int argc, char *argv[])
258  {
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
267    // Open the logfile and write the time on the first line
268    std::ofstream logfile(this->par.getLogFile().c_str());
269    logfile << "New run of the Duchamp source finder v."<<VERSION<<": ";
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
282  void Cube::logDetectionList(bool calcFluxes)
283  {
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.
289    ///  @param[in] calcFluxes If true (the default), calculate the various flux parameters for each object.
290
291    if(this->objectList->size()>0){
292
293      long left = this->par.getBorderLeft();
294      long bottom = this->par.getBorderBottom();
295
296      std::ofstream fout(this->par.getLogFile().c_str(),std::ios::app);
297      if(calcFluxes) this->calcObjectFluxes();
298      this->setupColumns();
299      outputTableHeader(fout,this->fullCols,"log",this->head.isWCS());
300
301      if(this->par.getFlagBaseline()){
302        for(size_t i=0;i<this->axisDim[0]*this->axisDim[1]*this->axisDim[2];i++)
303          this->array[i] += this->baseline[i];
304      }
305
306      for(size_t objCtr=0;objCtr<this->objectList->size();objCtr++){
307        Detection obj = this->objectList->at(objCtr);
308        obj.setOffsets(par);
309        if(this->par.getFlagCubeTrimmed()){
310          obj.addOffsets(left,bottom,0);
311        }
312        if(calcFluxes) obj.calcFluxes(this->array, this->axisDim);
313        obj.setID(objCtr+1);
314        obj.printTableRow(fout,this->fullCols,"log");
315      }
316
317      if(this->par.getFlagBaseline()){
318        for(size_t i=0;i<this->axisDim[0]*this->axisDim[1]*this->axisDim[2];i++)
319          this->array[i] -= this->baseline[i];
320      }
321      fout.close();
322 
323    }
324
325  }
326
327  void Cube::logDetection(Detection obj, int counter)
328  {
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.
340
341    std::ofstream fout(this->par.getLogFile().c_str(),std::ios::app);
342    // Need to deal with possibility of trimmed array
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();
347    size_t *tempDim = new size_t[3];
348    tempDim[0] = (this->axisDim[0] + left + right);
349    tempDim[1] = (this->axisDim[1] + bottom + top);
350    tempDim[2] = this->axisDim[2];
351    size_t tempsize = tempDim[0] * tempDim[1] * tempDim[2];
352    float *temparray = new float[tempsize];
353    //  for(int i=0;i<this->numPixels;i++){ // loop over this->array
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++){
357
358          bool isDud = (x<left) || (x>=this->axisDim[0]+left) ||
359            (y<bottom) || (y>=this->axisDim[1]+bottom);
360       
361          size_t temppos = x + tempDim[0]*y + tempDim[1]*tempDim[0]*z;
362
363          size_t pos = (x-left) + (y-bottom)*this->axisDim[0] +
364            z*this->axisDim[0]*this->axisDim[1];
365
366          if(isDud) temparray[temppos] = this->par.getBlankPixVal();
367          else temparray[temppos] = this->array[pos];
368 
369          if(this->par.getFlagBaseline() && !isDud)
370            temparray[temppos] += this->baseline[pos];
371
372        }
373      }
374    }
375
376    if(this->par.getFlagCubeTrimmed()){
377      obj.addOffsets(left,bottom,0);
378    }
379    obj.calcFluxes(temparray, this->axisDim);
380    obj.printTableRow(fout,this->fullCols,"log");
381    delete [] temparray;
382    delete [] tempDim;
383    fout.close();
384  }
385
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
439}
Note: See TracBrowser for help on using the repository browser.