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

Last change on this file since 234 was 234, checked in by Matthew Whiting, 17 years ago

Changes made to VOTable output in response to Ticket #9. Fixed bug that had tags not closing, and improved the output of units (with a new function) and the arraysize of strings.

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