source: trunk/src/Cubes/VOTable.cc @ 512

Last change on this file since 512 was 512, checked in by MatthewWhiting, 16 years ago

Fixing up VOtable output: fixing bug #44, and improving the PARAM output.

File size: 15.1 KB
RevLine 
[440]1// -----------------------------------------------------------------------
2// VOTable.cc: Output of the detected objects to a VOTable
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
29#include <iostream>
30#include <sstream>
31#include <fstream>
32#include <iomanip>
33#include <string>
34#include <vector>
35#include <time.h>
36#include <duchamp/Cubes/VOTable.hh>
37#include <duchamp/param.hh>
38#include <duchamp/fitsHeader.hh>
39#include <duchamp/Cubes/cubes.hh>
40#include <duchamp/Detection/detection.hh>
41#include <duchamp/Detection/columns.hh>
42 
43namespace duchamp
44{
45
46  using namespace Column;
47  std::string fixUnitsVOT(std::string oldstring)
48  {
49    /**
50     * Fix a string containing units to make it acceptable for a VOTable.
51     *
52     * This function makes the provided units string acceptable
53     * according to the standard found at
54     * http://vizier.u-strasbg.fr/doc/catstd-3.2.htx
55     * This should then be able to convert the units used in the text
56     * table to units suitable for putting in a VOTable.
57     *
58     * Specifically, it removes any square brackets [] from the
59     * start/end of the string, and replaces blank spaces (representing
60     * multiplication) with a '.' (full stop).
[484]61     *
62     * \param oldstring Input unit string to be fixed
63     * \return String with fixed units
[440]64     */
65
66    std::string newstring;
67    for(int i=0;i<oldstring.size();i++){
68      if((oldstring[i]!='[')&&(oldstring[i]!=']')){
69        if(oldstring[i]==' ') newstring += '.';
70        else newstring += oldstring[i];
71      }
72    }
73    return newstring; 
74  }
75 
76
77  void VOField::define(std::string i, std::string n, std::string U, std::string u, std::string d, std::string r, int w, int p)
78  {
[441]79    /**
[484]80     * A basic definition function, defining each parameter individually.
81     * \param i The ID parameter
82     * \param n The name parameter
83     * \param U The UCD
84     * \param u The units (fixed by fixUnits())
85     * \param d The datatype
86     * \param r The ref
87     * \param w The width
88     * \param p The precision
[441]89     */
[440]90    this->ID = i;
91    this->name = n;
92    this->UCD = U;
93    this->unit = fixUnitsVOT(u);
94    this->datatype = d;
95    this->ref = r;
96    this->width = w;
97    this->precision = p;
98  }
99
100  void VOField::define(Column::Col column, std::string i, std::string U, std::string d, std::string r)
101  {
[441]102    /**
103     * Another definition function, using the information in a Column::Col object for some parameters.
[484]104     * \param column A Column::Col object, used for name, unit, width & precision
105     * \param i The ID parameter
106     * \param U The UCD
107     * \param d The datatype
108     * \param r The ref
[441]109     */
[440]110    this->ID = i;
111    this->name = column.getName();
112    this->UCD = U;
113    this->unit = fixUnitsVOT(column.getUnits());
114    this->datatype = d;
115    this->ref = r;
116    this->width = column.getWidth();
117    this->precision = column.getPrecision();
118  }
119
120  void VOField::define(Column::Col column)
121  {
[441]122    /**
123     * A more useful definition function, using the Column::COLNAME
124     * key to specify particular values for each of the parameters for
125     * different columns.
[484]126     * \param column A Column::Col object of a particular type. The
127     * column.getType() function is used to decide which call to
128     * VOField::define(Column::Col column, std::string i, std::string
129     * U, std::string d, std::string r) to use
[441]130     */
[440]131    switch(column.getType())
132      {
133      case NUM:
134        this->define(column,"col01","meta.id","int","");
135        break;
136      case NAME:
137        this->define(column,"col02","meta.id;meta.main","char","");
138        break;
139      case RAJD:
140        this->define(column,"col03","","float","J2000");
141        break;
142      case DECJD:
143        this->define(column,"col04","","float","J2000");
144        break;
145      case VEL:
146        this->define(column,"col05","phys.veloc;src.dopplerVeloc","float","");
147        break;
148      case WRA:
149        this->define(column,"col06","","float","J2000");
150        break;
151      case WDEC:
152        this->define(column,"col07","","float","J2000");
153        break;
[512]154      case W50:
[440]155        this->define(column,"col08","phys.veloc;src.dopplerVeloc;spect.line.width","float","");
156        break;
[512]157      case W20:
158        this->define(column,"col09","phys.veloc;src.dopplerVeloc;spect.line.width","float","");
159        break;
160      case WVEL:
161        this->define(column,"col10","phys.veloc;src.dopplerVeloc;spect.line.width","float","");
162        break;
[440]163      case FINT:
[512]164        this->define(column,"col11","phot.flux;spect.line.intensity","float","");
[440]165        this->name = "Integrated_Flux";
166        break;
167      case FTOT:
[512]168        this->define(column,"col11","phot.flux;spect.line.intensity","float","");
[440]169        this->name = "Total_Flux";
170        break;
171      case FPEAK:
[512]172        this->define(column,"col12","phot.flux;spect.line.intensity","float","");
[440]173        this->name = "Peak_Flux";
174        break;
175      case SNRPEAK:
[512]176        this->define(column,"col13","phot.flux;stat.snr","float","");
[440]177        break;
178      case FLAG:
[512]179        this->define(column,"col14","meta.code.qual","char","");
[440]180        break;
181      case XAV:
[512]182        this->define(column,"col15","pos.cartesian.x","float","");
[440]183        break;
184      case YAV:
[512]185        this->define(column,"col16","pos.cartesian.y","float","");
[440]186        break;
187      case ZAV:
[512]188        this->define(column,"col17","pos.cartesian.z","float","");
[440]189        break;
190      case XCENT:
[512]191        this->define(column,"col18","pos.cartesian.x","float","");
[440]192        this->name = "X_Centroid";
193        break;
194      case YCENT:
[512]195        this->define(column,"col19","pos.cartesian.y","float","");
[440]196        this->name = "Y_Centroid";
197        break;
198      case ZCENT:
[512]199        this->define(column,"col20","pos.cartesian.z","float","");
[440]200        this->name = "Z_Centroid";
201        break;
202      case XPEAK:
[512]203        this->define(column,"col21","pos.cartesian.x","int","");
[440]204        break;
205      case YPEAK:
[512]206        this->define(column,"col22","pos.cartesian.y","int","");
[440]207        break;
208      case ZPEAK:
[512]209        this->define(column,"col23","pos.cartesian.z","int","");
[440]210        break;
211      default:
212        break;
213      };
214  }
215
216  void VOField::printField(std::ostream &stream)
217  {
[441]218    /**
219     * Print the Field entry with appropriate formatting.
[484]220     * \param stream The output stream to send the text to.
[441]221     */
[440]222    stream << "<FIELD name=\"" <<this->name
223           << "\" ID=\"" << this->ID
224           << "\" ucd=\"" << this->UCD;
225    if(this->ref!="") stream << "\" ref=\"" << this->ref;
226    stream << "\" datatype=\"" << this->datatype;
227    stream << "\" unit=\"" << this->unit;
228    if(datatype=="char")
229      stream << "\" arraysize=\"" << this->width;
230    else{
231      stream << "\" width=\"" << this->width;
232      if(datatype=="float" || datatype=="double")
233        stream << "\" precision=\"" << this->precision;
234    }
235    stream << "\"/>\n";
236
237  }
238
239
240
241  //------------------------------------------------
242
243
[512]244  template <class T> void VOParam::define(std::string n, std::string U, std::string d, T v, int w, std::string u)
[440]245  {
[441]246    /**
247     * A basic definition function, defining each parameter
248     * individually. The value (v) is written to a stringstream, and
249     * from there stored as a string.
[484]250     * \param n The name
251     * \param U The UCD
252     * \param d The datatype
253     * \param v The value
254     * \param w The width
[512]255     * \param u The units
[441]256     */
[440]257    this->name = n;
258    this->UCD = U;
259    this->datatype = d;
260    this->width = w;
261    std::stringstream ss;
262    ss << v;
263    this->value = ss.str();
[512]264    this->units = u;
[440]265  }
[512]266  template void VOParam::define<int>(std::string n, std::string U, std::string d, int v, int w, std::string u);
267  template void VOParam::define<long>(std::string n, std::string U, std::string d, long v, int w, std::string u);
268  template void VOParam::define<float>(std::string n, std::string U, std::string d, float v, int w, std::string u);
269  template void VOParam::define<double>(std::string n, std::string U, std::string d, double v, int w, std::string u);
270  template void VOParam::define<std::string>(std::string n, std::string U, std::string d, std::string v, int w, std::string u);
[440]271
272  void VOParam::printParam(std::ostream &stream)
273  {
[441]274    /**
275     * Print the Param entry with appropriate formatting.
[484]276     * \param stream The output stream to send the text to.
[441]277     */
[440]278    stream << "<PARAM name=\"" <<this->name
279           << "\" ucd=\"" << this->UCD
280           << "\" datatype=\"" << this->datatype;
[512]281    if(this->units!="")
282      stream << "\" units=\"" << this->units;
[440]283    if(this->width!=0){
284      if(datatype=="char")
285        stream << "\" arraysize=\"" << this->width;
286      else
287        stream << "\" width=\"" << this->width;
288    }
289    stream << "\" value=\"" << this->value
290           << "\"/>\n";
291  }
292
293  //------------------------------------------------
294
295
296 
297  void Cube::outputDetectionsVOTable(std::ostream &stream)
298  {
[441]299    /**
300     *  Prints to a stream (provided) the list of detected objects in the cube
301     *   in a VOTable format.
302     *  Uses WCS information and assumes WCS parameters have been calculated for each
303     *   detected object.
[484]304     * \param stream The output stream to send the text to.
[441]305     */
306   
[440]307    stream<<"<?xml version=\"1.0\"?>\n";
308    stream<<"<VOTABLE version=\"1.1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
309    stream<<" xsi:noNamespaceSchemaLocation=\"http://www.ivoa.net/xml/VOTable/VOTable/v1.1\">\n";
310
311    stream<<"  <COOSYS ID=\"J2000\" equinox=\"J2000.\" epoch=\"J2000.\" system=\"eq_FK5\"/>\n";
312    stream<<"  <RESOURCE name=\"Duchamp Output\">\n";
313    stream<<"    <TABLE name=\"Detections\">\n";
314    stream<<"      <DESCRIPTION>Detected sources and parameters from running the Duchamp source finder.</DESCRIPTION>\n";
315
316    // PARAM section -- parts that are not entry-specific ie. apply to whole dataset
317    std::vector<VOParam> paramList;
318    std::vector<VOParam>::iterator param;
319    VOParam singleParam;
320
321    std::string fname = this->par.getImageFile();
322    if(this->par.getFlagSubsection()) fname+=this->par.getSubsection();
323   
[512]324    singleParam.define("FITS file","meta.file;meta.fits","char",fname,fname.size(),"");
[440]325    paramList.push_back(singleParam);
326    if(this->par.getFlagFDR())
[512]327      singleParam.define("FDR Significance","stat.param","float",this->par.getAlpha(),0,"");
[440]328    else
[512]329      singleParam.define("Threshold (SNR)","stat.snr","float",this->par.getCut(),0,"");
[440]330    paramList.push_back(singleParam);
[512]331    singleParam.define("Flux Threshold","phot.flux;stat.min","float",this->Stats.getThreshold(),0,this->head.getFluxUnits());
332    paramList.push_back(singleParam);
[440]333   
334    if(this->par.getFlagATrous()){
335      std::string note = "The a trous reconstruction method was used, with the following parameters.";
[512]336      singleParam.define("ATrous note","meta.note","char",note,note.size(),"");
[440]337      paramList.push_back(singleParam);
[512]338      singleParam.define("ATrous Dimension","meta.code;stat","int",this->par.getReconDim(),0,"");
[440]339      paramList.push_back(singleParam);
[512]340      singleParam.define("ATrous Threshold","stat.snr","float",this->par.getAtrousCut(),0,"");
[440]341      paramList.push_back(singleParam);
[512]342      singleParam.define("ATrous Minimum Scale","stat.param","int",this->par.getMinScale(),0,"");
[440]343      paramList.push_back(singleParam);
[512]344      singleParam.define("ATrous Filter","meta.code;stat","char",this->par.getFilterName(),this->par.getFilterName().size(),"");
[440]345      paramList.push_back(singleParam);
346    }
347    if(this->par.getFlagSmooth()){
348      if(this->par.getSmoothType()=="spectral"){
349        std::string note = "The cube was smoothed spectrally with a Hanning filter, with the following parameters.";
[512]350        singleParam.define("Smoothing note","meta.note","char",note,note.size(),"");
[440]351        paramList.push_back(singleParam);
[512]352        singleParam.define("Hanning filter width","meta.code;stat","int",this->par.getHanningWidth(),0,"");
[440]353        paramList.push_back(singleParam);
354      }
355      else if(this->par.getSmoothType()=="spatial"){
356        std::string note = "The cube was smoothed spatially with a Gaussian kernel, with the following parameters.";
[512]357        singleParam.define("Smoothing note","meta.note","char",note,note.size(),"");
[440]358        paramList.push_back(singleParam);
[512]359        singleParam.define("Gaussian kernel major-axis FWHM","meta.code;stat","int",this->par.getKernMaj(),0,"");
[440]360        paramList.push_back(singleParam);
[512]361        singleParam.define("Gaussian kernel minor-axis FWHM","meta.code;stat","int",this->par.getKernMin(),0,"");
[440]362        paramList.push_back(singleParam);
[512]363        singleParam.define("Gaussian kernel position angle","meta.code;stat","int",this->par.getKernPA(),0,"");
[440]364        paramList.push_back(singleParam);
365      }   
366    }
367
368    for(param=paramList.begin();param<paramList.end();param++){
369      stream << "      ";
370      param->printParam(stream);
371    }   
372
373
[461]374    if(this->fullCols.size()==0) this->setupColumns();
375    // in case cols haven't been set -- need the column names
376
[440]377    std::string posUCD[4];
378    if(makelower(this->fullCols[Column::RAJD].getName())=="ra"){
379      posUCD[0] = "pos.eq.ra;meta.main";
380      posUCD[2] = "phys.angSize;pos.eq.ra";
381    }
382    else{
383      posUCD[0] = "pos.galactic.lat;meta.main";
384      posUCD[2] = "phys.angSize;pos.galactic.lat";
385    }
386    if(makelower(this->fullCols[DECJD].getName())=="dec"){
387      posUCD[1] = "pos.eq.dec;meta.main";
388      posUCD[3] = "phys.angSize;pos.eq.dec";
389    }
390    else{
391      posUCD[1] = "pos.galactic.lon;meta.main";
392      posUCD[3] = "phys.angSize;pos.galactic.lon";
393    }
394
395    std::vector<Column::Col>::iterator col;
396    for(col=this->fullCols.begin();col<this->fullCols.end();col++){
397
398      if(col->doCol("votable",this->head.isSpecOK())){
399        VOField field;
400        field.define(*col);
401        if(col->getType()==RAJD)  field.setUCD(posUCD[0]);
402        if(col->getType()==WRA)   field.setUCD(posUCD[1]);
403        if(col->getType()==DECJD) field.setUCD(posUCD[2]);
404        if(col->getType()==WDEC)  field.setUCD(posUCD[3]);     
405        stream << "      ";
406        field.printField(stream);
407      }
408
409    }
410
411    stream<<"      <DATA>\n"
412          <<"        <TABLEDATA>\n";
413
414    stream.setf(std::ios::fixed); 
415
416    std::vector<Detection>::iterator obj;
417    for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
418
419      stream<<"        <TR>\n";
420      stream<<"          ";
421      std::vector<Column::Col>::iterator col;
422      for(col=this->fullCols.begin();col<this->fullCols.end();col++){
423        if(col->doCol("votable",this->head.isSpecOK())){
424          stream<<"<TD>";
425          obj->printTableEntry(stream, *col);
426          stream<<"</TD>";
427        }
428      }
429      stream<<"\n";
430      stream<<"        </TR>\n";
431
432    }
433
434    stream<<"        </TABLEDATA>\n";
435    stream<<"      </DATA>\n";
436    stream<<"    </TABLE>\n";
437    stream<<"  </RESOURCE>\n";
438    stream<<"</VOTABLE>\n";
439    resetiosflags(std::ios::fixed);
440 
441  }
442
443
444
445
446}
Note: See TracBrowser for help on using the repository browser.