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

Last change on this file since 272 was 272, checked in by Matthew Whiting, 17 years ago
  • Moved the FitsHeader? class & functions to a separate file (fitsHeader.{cc,hh}).
  • This entailed changing a bunch of #include statements.
  • Also fixed up the declaration/implementation of Col functions.
File size: 16.0 KB
Line 
1#include <iostream>
2#include <sstream>
3#include <fstream>
4#include <iomanip>
5#include <string>
6#include <vector>
7#include <time.h>
8#include <param.hh>
9#include <fitsHeader.hh>
10#include <Cubes/cubes.hh>
11#include <PixelMap/Object3D.hh>
12#include <Detection/detection.hh>
13#include <Detection/columns.hh>
14#include <Utils/utils.hh>
15 
16using std::endl;
17using std::setw;
18using std::setprecision;
19using namespace Column;
20using namespace PixelInfo;
21
22void Cube::outputDetectionsKarma(std::ostream &stream)
23{
24  /**
25   *  Prints to a stream (provided) the list of detected objects in the cube
26   *   in the format of an annotation file for the Karma suite of programs.
27   *  Annotation file draws a box enclosing the detection, and writes the
28   *   ID number of the detection to the right of the box.
29   */
30
31  std::string fname = this->par.getImageFile();
32  if(this->par.getFlagSubsection()) fname+=this->par.getSubsection();
33  stream << "# Duchamp Source Finder results for FITS file: " << fname << endl;
34  if(this->par.getFlagFDR())
35    stream<<"# FDR Significance = " << this->par.getAlpha() << endl;
36  else
37    stream<<"# Threshold = " << this->par.getCut() << endl;
38  if(this->par.getFlagATrous()){
39    stream<<"# The a trous reconstruction method was used, with the following parameters." << endl;
40    stream<<"#  ATrous Dimension = " << this->par.getReconDim() << endl;
41    stream<<"#  ATrous Threshold = " << this->par.getAtrousCut() << endl;
42    stream<<"#  ATrous Minimum Scale =" << this->par.getMinScale() << endl;
43    stream<<"#  ATrous Filter = " << this->par.getFilterName() << endl;
44  }
45  else stream << "# No ATrous reconstruction done." << endl;
46  stream << "#\n";
47  stream << "COLOR RED" << endl;
48  stream << "COORD W" << endl;
49  for(int i=0;i<this->objectList.size();i++){
50    if(this->head.isWCS()){
51      float radius = this->objectList[i].getRAWidth()/120.;
52      if(this->objectList[i].getDecWidth()/120.>radius)
53        radius = this->objectList[i].getDecWidth()/120.;
54      stream << "CIRCLE "
55             << this->objectList[i].getRA() << " "
56             << this->objectList[i].getDec() << " "
57             << radius << endl;
58      stream << "TEXT "
59             << this->objectList[i].getRA() << " "
60             << this->objectList[i].getDec() << " "
61             << this->objectList[i].getID() << endl;
62    }
63    else{
64      float radius = this->objectList[i].getXmax() -
65        this->objectList[i].getXmin() + 1;
66      if(this->objectList[i].getYmax()-this->objectList[i].getYmin() + 1
67         > radius)
68        radius = this->objectList[i].getYmax() -
69          this->objectList[i].getYmin() + 1;
70      stream << "CIRCLE "
71             << this->objectList[i].getXcentre() << " "
72             << this->objectList[i].getYcentre() << " "
73             << radius << endl;
74      stream << "TEXT "
75             << this->objectList[i].getXcentre() << " "
76             << this->objectList[i].getYcentre() << " "
77             << this->objectList[i].getID() << endl;
78    }
79  }     
80
81}
82
83std::string fixUnitsVOT(std::string oldstring)
84{
85  /** Fix a string containing units to make it acceptable for a VOTable.
86   *
87   * This function makes the provided units string acceptable
88   * according to the standard found at
89   * http://vizier.u-strasbg.fr/doc/catstd-3.2.htx
90   * This should then be able to convert the units used in the text
91   * table to units suitable for putting in a VOTable.
92   *
93   * Specifically, it removes any square brackets [] from the
94   * start/end of the string, and replaces blank spaces (representing
95   * multiplication) with a '.' (full stop).
96   */
97
98  std::string newstring;
99  for(int i=0;i<oldstring.size();i++){
100    if((oldstring[i]!='[')&&(oldstring[i]!=']')){
101      if(oldstring[i]==' ') newstring += '.';
102      else newstring += oldstring[i];
103    }
104  }
105  return newstring; 
106}
107
108void Cube::outputDetectionsVOTable(std::ostream &stream)
109{
110  /**
111   *  Prints to a stream (provided) the list of detected objects in the cube
112   *   in a VOTable format.
113   *  Uses WCS information and assumes WCS parameters have been calculated for each
114   *   detected object.
115   *  If they have not (given by the isWCS() function), then those objects are not written...
116   */
117
118  // Set up Column definitions here
119  std::vector<Col> localCol;
120  std::string posUCD[4];
121  localCol.push_back(this->fullCols[NUM]);  // objID
122  localCol.push_back(this->fullCols[NAME]);  // name
123  localCol.push_back(this->fullCols[RA]);  // ra
124  if(makelower(localCol[2].getName())=="ra"){
125    posUCD[0] = "pos.eq.ra;meta.main";
126    posUCD[2] = "phys.angSize;pos.eq.ra";
127  }
128  else{
129    posUCD[0] = "pos.galactic.lat;meta.main";
130    posUCD[2] = "phys.angSize;pos.galactic.lat";
131  }
132  localCol.push_back(this->fullCols[DEC]);  // dec
133  if(makelower(localCol[2].getName())=="dec"){
134    posUCD[1] = "pos.eq.dec;meta.main";
135    posUCD[3] = "phys.angSize;pos.eq.dec";
136  }
137  else{
138    posUCD[1] = "pos.galactic.lon;meta.main";
139    posUCD[3] = "phys.angSize;pos.galactic.lon";
140  }
141  localCol.push_back(this->fullCols[WRA]);  // w_ra
142  localCol.push_back(this->fullCols[WDEC]);  // w_dec
143  localCol.push_back(this->fullCols[VEL]);  // vel
144  localCol.push_back(this->fullCols[WVEL]); // w_vel
145  localCol.push_back(this->fullCols[FINT]); // f_int
146  localCol.push_back(this->fullCols[FPEAK]); // f_peak
147  localCol.push_back(this->fullCols[FLAG]); // flag
148
149  stream<<"<?xml version=\"1.0\"?>\n";
150  stream<<"<VOTABLE version=\"1.1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
151  stream<<" xsi:noNamespaceSchemaLocation=\"http://www.ivoa.net/xml/VOTable/VOTable/v1.1\">\n";
152
153  stream<<"  <COOSYS ID=\"J2000\" equinox=\"J2000.\" epoch=\"J2000.\" system=\"eq_FK5\"/>\n";
154  stream<<"  <RESOURCE name=\"Duchamp Output\">\n";
155  stream<<"    <TABLE name=\"Detections\">\n";
156  stream<<"      <DESCRIPTION>Detected sources and parameters from running the Duchamp source finder.</DESCRIPTION>\n";
157
158  // PARAM section -- parts that are not entry-specific ie. apply to whole dataset
159  std::string fname = this->par.getImageFile();
160  if(this->par.getFlagSubsection()) fname+=this->par.getSubsection();
161  stream<<"      <PARAM name=\"FITS file\" datatype=\"char\" ucd=\"meta.file;meta.fits\" value=\""
162        << fname << "\" arraysize=\""<<fname.size()<<"\"/>\n";
163  if(this->par.getFlagFDR())
164    stream<<"      <PARAM name=\"FDR Significance\" datatype=\"float\" ucd=\"stat.param\" value=\""
165          << this->par.getAlpha() << "\"/>\n";
166  else
167    stream<<"      <PARAM name=\"Threshold\" datatype=\"float\" ucd=\"stat.snr\" value=\""
168          << this->par.getCut() << "\"/>\n";
169  if(this->par.getFlagATrous()){
170    std::string note = "The a trous reconstruction method was used, with the following parameters.";
171    stream<<"      <PARAM name=\"ATrous note\" datatype=\"char\" ucd=\"meta.note\" value=\""
172          <<note << "\" arraysize=\"" << note.size() << "\"/>\n";
173    stream<<"      <PARAM name=\"ATrous Dimension\" datatype=\"int\" ucd=\"meta.code;stat\" value=\""
174          << this->par.getReconDim() << "\"/>\n";
175    stream<<"      <PARAM name=\"ATrous Threshold\" datatype=\"float\" ucd=\"stat.snr\" value=\""
176          << this->par.getAtrousCut() << "\"/>\n";
177    stream<<"      <PARAM name=\"ATrous Minimum Scale\" datatype=\"int\" ucd=\"stat.param\" value=\""
178          << this->par.getMinScale() << "\"/>\n";
179    stream<<"      <PARAM name=\"ATrous Filter\" datatype=\"char\" ucd=\"meta.code;stat\" value=\""
180          << this->par.getFilterName() << "\" arraysize=\"" << this->par.getFilterName().size() << "\"/>\n";
181  }
182  // FIELD section -- names, titles and info for each column.
183  stream<<"      <FIELD name=\"ID\" ID=\"col01\" ucd=\"meta.id\" datatype=\"int\" width=\""
184        <<localCol[0].getWidth()<<"\" unit=\"--\"/>\n";
185  stream<<"      <FIELD name=\"Name\" ID=\"col02\" ucd=\"meta.id;meta.main\" datatype=\"char\" arraysize=\""
186        <<localCol[1].getWidth()<<"\" unit=\"--\"/>\n";
187  stream<<"      <FIELD name=\""<<localCol[2].getName()<<"\" ID=\"col03\" ucd=\""
188        <<posUCD[0]<<"\" ref=\"J2000\" datatype=\"float\" width=\""
189        <<localCol[2].getWidth()<<"\" precision=\""<<prec[prPOS]<<"\" unit=\"deg\"/>\n";
190  stream<<"      <FIELD name=\""<<localCol[3].getName()<<"\" ID=\"col04\" ucd=\""
191        <<posUCD[1]<<"\" ref=\"J2000\" datatype=\"float\" width=\""
192        <<localCol[3].getWidth()<<"\" precision=\""<<prec[prPOS]<<"\" unit=\"deg\"/>\n";
193  stream<<"      <FIELD name=\""<<localCol[4].getName()<<"\" ID=\"col05\" ucd=\""
194        <<posUCD[2]<<"\" ref=\"J2000\" datatype=\"float\" width=\""
195        <<localCol[4].getWidth()<<"\" precision=\""<<prec[prWPOS]<<"\" unit=\""
196        <<fixUnitsVOT(localCol[4].getUnits())<<"\"/>\n";
197  stream<<"      <FIELD name=\""<<localCol[5].getName()<<"\" ID=\"col06\" ucd=\""
198        <<posUCD[2]<<"\" ref=\"J2000\" datatype=\"float\" width=\""
199        <<localCol[5].getWidth()<<"\" precision=\""<<prec[prWPOS]<<"\" unit=\""
200        <<fixUnitsVOT(localCol[5].getUnits())<<"\"/>\n";
201  stream<<"      <FIELD name=\"Vel\" ID=\"col07\" ucd=\"phys.veloc;src.dopplerVeloc\" datatype=\"float\" width=\""
202        <<localCol[6].getWidth()<<"\" precision=\""<<prec[prVEL]<<"\" unit=\""
203        <<fixUnitsVOT(localCol[6].getUnits())<<"\"/>\n";
204  stream<<"      <FIELD name=\"w_Vel\" ID=\"col08\" ucd=\"phys.veloc;src.dopplerVeloc;spect.line.width\""
205        <<" datatype=\"float\" width=\""<<localCol[7].getWidth()<<"\" precision=\""
206        <<prec[prVEL]<<"\" unit=\""<<fixUnitsVOT(localCol[7].getUnits())<<"\"/>\n";
207  stream<<"      <FIELD name=\"Integrated_Flux\" ID=\"col09\" ucd=\"phot.flux;spect.line.intensity\""
208        <<" datatype=\"float\" width=\""<<localCol[8].getWidth()<<"\" precision=\""
209        <<prec[prFLUX]<<"\" unit=\""<<fixUnitsVOT(localCol[8].getUnits())<<"\"/>\n";
210  stream<<"      <FIELD name=\"Peak_Flux\" ID=\"col10\" ucd=\"phot.flux;spect.line.intensity\""
211        <<" datatype=\"float\" width=\""<<localCol[9].getWidth()<<"\" precision=\""
212        <<prec[prFLUX]<<"\" unit=\""<<fixUnitsVOT(localCol[9].getUnits())<<"\"/>\n";
213  stream<<"      <FIELD name=\"Flag\" ID=\"col11\" ucd=\"meta.code.qual\" datatype=\"char\" arraysize=\"3\" unit=\"--\"/>\n";
214
215
216  stream<<"      <DATA>\n"
217        <<"        <TABLEDATA>\n";
218
219  stream.setf(std::ios::fixed); 
220  for(int i=0;i<this->objectList.size();i++){
221    if(this->objectList[i].isWCS()){
222      stream<<"        <TR>\n";
223      stream<<"          <TD>"<<setw(localCol[0].getWidth())<<i+1<<"</TD>";
224      stream<<"<TD>" << setw(localCol[1].getWidth()) << this->objectList[i].getName()       <<"</TD>";
225      stream<<setprecision(prec[prPOS]);
226      stream<<"<TD>" << setw(localCol[2].getWidth()) << this->objectList[i].getRA()         <<"</TD>";
227      stream<<"<TD>" << setw(localCol[3].getWidth()) << this->objectList[i].getDec()        <<"</TD>";
228      stream<<setprecision(prec[prWPOS]);
229      stream<<"<TD>" << setw(localCol[4].getWidth()) << this->objectList[i].getRAWidth()    <<"</TD>";
230      stream<<"<TD>" << setw(localCol[5].getWidth()) << this->objectList[i].getDecWidth()   <<"</TD>";
231      stream<<setprecision(prec[prVEL]);
232      stream<<"<TD>" << setw(localCol[6].getWidth()) << this->objectList[i].getVel()        <<"</TD>";
233      stream<<"<TD>" << setw(localCol[7].getWidth()) << this->objectList[i].getVelWidth()   <<"</TD>";
234      stream<<setprecision(prec[prFLUX]);
235      stream<<"<TD>" << setw(localCol[8].getWidth()) << this->objectList[i].getIntegFlux()  <<"</TD>";
236      stream<<"<TD>" << setw(localCol[9].getWidth()) << this->objectList[i].getPeakFlux()   <<"</TD>";
237      stream<<"<TD>" << setw(localCol[10].getWidth())<< this->objectList[i].getFlagText()   <<"</TD>";
238     
239      stream<<endl;
240      stream<<"        </TR>\n";
241    }
242  }
243  stream<<"        </TABLEDATA>\n";
244  stream<<"      </DATA>\n";
245  stream<<"    </TABLE>\n";
246  stream<<"  </RESOURCE>\n";
247  stream<<"</VOTABLE>\n";
248  resetiosflags(std::ios::fixed);
249 
250}
251
252
253void Cube::outputDetectionList()
254{
255  /**
256   *  A front-end to writing the full list of detected objects to a results
257   *   file and to cout.
258   *  Uses outputDetectionTextWCS for each objects.
259   *  Leaves the testing of whether the WCS parameters for each object
260   *   have been calculated to outputDetectionTextWCS.
261   */
262
263  std::ofstream output(this->par.getOutFile().c_str());
264  output<<"Results of the Duchamp source finder: ";
265  time_t now = time(NULL);
266  output << asctime( localtime(&now) );
267  this->showParam(output);
268  output<<"--------------------\n";
269  output<<"Detection threshold = " << this->Stats.getThreshold()
270        <<" " << this->head.getFluxUnits();
271  if(this->par.getFlagFDR())
272    output<<" (or S/N=" << this->Stats.getThresholdSNR()<<")";
273  output<<endl;
274  if(!this->par.getFlagUserThreshold())
275    output<<"  Noise level = " << this->Stats.getMiddle()
276          <<", Noise spread = " << this->Stats.getSpread() << endl;
277  output<<"Total number of detections = "<<this->objectList.size()<<endl;
278  output<<"--------------------\n";
279  this->setupColumns();
280  this->objectList[0].outputDetectionTextHeaderFull(output,this->fullCols);
281  this->objectList[0].outputDetectionTextHeader(std::cout,this->fullCols);
282  for(int i=0;i<this->objectList.size();i++){
283    this->objectList[i].outputDetectionTextWCSFull(output,this->fullCols);
284    this->objectList[i].outputDetectionTextWCS(std::cout,this->fullCols);
285  }
286}
287
288void Cube::logDetectionList()
289{
290  /**
291   *  A front-end to writing a list of detected objects to the log file.
292   *  Does not assume WCS, so uses outputDetectionText.
293   *  Designed to be used by searching routines before returning their
294   *   final list.
295   */
296
297  long left = this->par.getBorderLeft();
298  long bottom = this->par.getBorderBottom();
299
300  std::ofstream fout(this->par.getLogFile().c_str(),std::ios::app);
301  this->setupColumns();
302  this->objectList[0].outputDetectionTextHeader(fout,this->logCols);
303
304  if(this->par.getFlagBaseline()){
305    for(int i=0;i<this->axisDim[0]*this->axisDim[1]*this->axisDim[2];i++)
306      this->array[i] += this->baseline[i];
307  }
308
309  for(int objCtr=0;objCtr<this->objectList.size();objCtr++){
310    Detection *obj = new Detection;
311    *obj = objectList[objCtr];
312    obj->setOffsets(par);
313    obj->calcFluxes(this->array, this->axisDim);
314    if(this->par.getFlagCubeTrimmed()){
315      obj->pixels().addOffsets(left,bottom,0);
316    }
317    obj->outputDetectionText(fout,this->logCols,objCtr+1);
318    delete obj;
319  }
320
321  if(this->par.getFlagBaseline()){
322    for(int i=0;i<this->axisDim[0]*this->axisDim[1]*this->axisDim[2];i++)
323      this->array[i] -= this->baseline[i];
324  }
325  fout.close();
326}
327
328void Cube::logDetection(Detection obj, int counter)
329{
330  /**
331   *  A front-end to writing a detected object to the log file.
332   *  Does not assume WCS, so uses outputDetectionText.
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
343  std::ofstream fout(this->par.getLogFile().c_str(),std::ios::app);
344  // Need to deal with possibility of trimmed array
345  long left = this->par.getBorderLeft();
346  long right = this->par.getBorderRight();
347  long top = this->par.getBorderTop();
348  long bottom = this->par.getBorderBottom();
349  long *tempDim = new long[3];
350  tempDim[0] = (this->axisDim[0] + left + right);
351  tempDim[1] = (this->axisDim[1] + bottom + top);
352  tempDim[2] = this->axisDim[2];
353  long tempsize = tempDim[0] * tempDim[1] * tempDim[2];
354  float *temparray = new float[tempsize];
355  //  for(int i=0;i<this->numPixels;i++){ // loop over this->array
356  for(int z=0;z<tempDim[2];z++){
357    for(int y=0;y<tempDim[1];y++){
358      for(int x=0;x<tempDim[0];x++){
359
360        bool isDud = (x<left) || (x>=this->axisDim[0]+left) ||
361          (y<bottom) || (y>=this->axisDim[1]+bottom);
362       
363        int temppos = x + tempDim[0]*y + tempDim[1]*tempDim[0]*z;
364
365        int pos = (x-left) + (y-bottom)*this->axisDim[0] +
366          z*this->axisDim[0]*this->axisDim[1];
367
368        if(isDud) temparray[temppos] = this->par.getBlankPixVal();
369        else temparray[temppos] = this->array[pos];
370 
371        if(this->par.getFlagBaseline() && !isDud)
372          temparray[temppos] += this->baseline[pos];
373
374      }
375    }
376  }
377
378  if(this->par.getFlagCubeTrimmed()){
379    obj.pixels().addOffsets(left,bottom,0);
380  }
381  obj.calcFluxes(temparray, this->axisDim);
382  obj.outputDetectionText(fout,this->logCols,counter);
383  delete [] temparray;
384  delete [] tempDim;
385  fout.close();
386}
Note: See TracBrowser for help on using the repository browser.