source: tags/release-1.1.12/src/Cubes/detectionIO.cc @ 1455

Last change on this file since 1455 was 783, checked in by MatthewWhiting, 13 years ago

Moving the function for writeSpectralData away from the files that depend on pgplot existing, so that we can write it in the absence of plotting.

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