source: trunk/FACT++/src/fitsdump.cc@ 10795

Last change on this file since 10795 was 10793, checked in by tbretz, 15 years ago
fitsdump - the program.
File size: 17.0 KB
Line 
1//****************************************************************
2/** @class FitsDumper
3
4 @brief Dumps contents of fits tables to stdout or a file
5
6 */
7 //****************************************************************
8#include "FACT.h"
9#include "Configuration.h"
10
11#include <map>
12#include <fstream>
13
14#include <CCfits/CCfits>
15
16using namespace std;
17
18class FitsDumper
19{
20
21public:
22 FitsDumper();
23 ~FitsDumper();
24
25private:
26
27 CCfits::FITS *fFile; /// FITS pointer
28 CCfits::Table *fTable; /// Table pointer
29 map<string, CCfits::Column*> fColMap; /// map between the column names and their CCfits objects
30
31 // Convert CCfits::ValueType into a human readable string
32 string ValueTypeToStr(CCfits::ValueType type) const;
33
34 // Convert CCfits::ValueType into a number of associated bytes
35 int ValueTypeToSize(CCfits::ValueType type) const;
36
37 /// Calculate the buffer size required to read a row of the fits table, as well as the offsets to each column
38 vector<int> CalculateOffsets() const;
39
40 template<class T>
41 void Write(ostream &out, const unsigned char* &ptr) const;
42
43 /// Write a single row of the selected data
44 int WriteRow(ostream &, const vector<string> &, const vector<int> &, unsigned char *) const;
45
46 bool OpenFile(const string &); /// Open a file
47 bool OpenTable(const string &); /// Open a table
48
49 /// Lists all columns of an open file
50 void List();
51 void ListHeader();
52 void ListKeywords(ostream &);
53
54 /// Perform the dumping, based on the current dump list
55 bool Dump(const string &, const vector<string> &list, int);
56
57
58public:
59 ///Configures the fitsLoader from the config file and/or command arguments.
60 int ExecConfig(Configuration& conf);
61};
62
63// --------------------------------------------------------------------------
64//
65//! Constructor
66//! @param out
67//! the ostream where to redirect the outputs
68//
69FitsDumper::FitsDumper() : fFile(0), fTable(0)
70{
71}
72
73// --------------------------------------------------------------------------
74//
75//! Destructor
76//
77FitsDumper::~FitsDumper()
78{
79 if (fFile)
80 delete fFile;
81}
82
83
84string FitsDumper::ValueTypeToStr(CCfits::ValueType type) const
85{
86 switch (type)
87 {
88 case CCfits::Tbyte: return "uint8_t";
89 case CCfits::Tushort: return "uint16_t";
90 case CCfits::Tshort: return "int16_t";
91 case CCfits::Tuint: return "uint32_t";
92 case CCfits::Tint: return "int32_t";
93 case CCfits::Tulong: return "uint32_t";
94 case CCfits::Tlong: return "int32_t";
95 case CCfits::Tlonglong: return "int64_t";
96 case CCfits::Tfloat: return "float";
97 case CCfits::Tdouble: return "double";
98
99 default:
100 return "unknwown";
101 }
102}
103
104int FitsDumper::ValueTypeToSize(CCfits::ValueType type) const
105{
106 switch (type)
107 {
108 case CCfits::Tbyte: return sizeof(uint8_t);
109 case CCfits::Tushort:
110 case CCfits::Tshort: return sizeof(uint16_t);
111 case CCfits::Tuint:
112 case CCfits::Tint:
113 case CCfits::Tulong:
114 case CCfits::Tlong: return sizeof(uint32_t);
115 case CCfits::Tlonglong: return sizeof(uint64_t);
116 case CCfits::Tfloat: return sizeof(float);
117 case CCfits::Tdouble: return sizeof(double);
118
119 default:
120 return 0;
121 }
122}
123
124template<class T>
125void FitsDumper::Write(ostream &out, const unsigned char* &ptr) const
126{
127 T t;
128 reverse_copy(ptr, ptr+sizeof(T), reinterpret_cast<unsigned char*>(&t));
129 out << t;
130
131 ptr += sizeof(T);
132}
133
134
135// --------------------------------------------------------------------------
136//
137//! Writes a single row of the selected FITS data to the output file.
138//!
139//! Data type \b not yet implemented:
140//! CCfits::Tnull, CCfits::Tbit, CCfits::Tlogical, CCfits::Tstring,
141//! CCfits::Tcomplex, CCfits::Tdblcomplex, CCfits::VTbit,
142//! CCfits::VTbyte, CCfits::VTlogical, CCfits::VTushort,
143//! CCfits::VTshort, CCfits::VTuint, CCfits::VTint, CCfits::VTulong,
144//! CCfits::VTlong, CCfits::VTlonglong, CCfits::VTfloat,
145//! CCfits::VTdouble, CCfits::VTcomplex, CCfits::VTdblcomplex
146//!
147//! @param offsets
148//! a vector containing the offsets to the columns (in bytes)
149//! @param targetFile
150//! the ofstream where to write to
151//! @param fitsBuffer
152//! the memory were the row has been loaded by cfitsio
153//
154int FitsDumper::WriteRow(ostream &out, const vector<string> &list, const vector<int> &offsets, unsigned char* fitsBuffer) const
155{
156 int cnt = 0;
157
158 for (vector<string>::const_iterator it=list.begin(); it!=list.end(); it++)
159 {
160 // Loop over all columns in our list of requested columns
161 const CCfits::Column *col = fColMap.find(*it)->second;
162
163 // CCfits starts counting at 1 not 0
164 const int offset = offsets[col->index()-1];
165
166 // Get the pointer to the array which we are supposed to print
167 const unsigned char *ptr = fitsBuffer + offset;
168
169 // Loop over all array entries
170 for (int width=0; width<col->width(); width++)
171 {
172 switch (col->type())
173 {
174 case CCfits::Tbyte: Write<uint8_t> (out, ptr); break;
175 case CCfits::Tushort: Write<uint16_t>(out, ptr); break;
176 case CCfits::Tuint:
177 case CCfits::Tulong: Write<uint32_t>(out, ptr); break;
178 case CCfits::Tshort: Write<int16_t> (out, ptr); break;
179 case CCfits::Tint:
180 case CCfits::Tlong: Write<int32_t> (out, ptr); break;
181 case CCfits::Tlonglong: Write<int64_t> (out, ptr); break;
182 case CCfits::Tfloat: Write<float> (out, ptr); break;
183 case CCfits::Tdouble: Write<double> (out, ptr); break;
184
185 default:
186 cerr << "Data type not implemented yet." << endl;
187 return 0;
188 }
189
190 out << " ";
191 cnt++;
192
193 if (out.fail())
194 {
195 cerr << "ERROR - writing output: " << strerror(errno) << endl;
196 return 0;
197 }
198 }
199 }
200
201 if (cnt>0)
202 out << endl;
203
204 return cnt;
205}
206
207// --------------------------------------------------------------------------
208//
209//! Calculates the required buffer size for reading one row of the current
210//! table. Also calculates the offsets to all the columns
211//
212vector<int> FitsDumper::CalculateOffsets() const
213{
214 map<int,int> sizes;
215
216 for (map<string, CCfits::Column*>::const_iterator it=fColMap.begin();
217 it!=fColMap.end(); it++)
218 {
219 const int &width = it->second->width();
220 const int &idx = it->second->index();
221
222 const int size = ValueTypeToSize(it->second->type());
223 if (size==0)
224 {
225 cerr << "Data type " << (int)it->second->type() << " not implemented yet." << endl;
226 return vector<int>();
227 }
228
229 sizes[idx] = size*width;
230 }
231
232 //calculate the offsets in the vector.
233 vector<int> result(1, 0);
234
235 int size = 0;
236 int idx = 0;
237
238 for (map<int,int>::const_iterator it=sizes.begin(); it!=sizes.end(); it++)
239 {
240 size += it->second;
241 result.push_back(size);
242
243 if (it->first == ++idx)
244 continue;
245
246 cerr << "Expected index " << idx << ", but found " << it->first << endl;
247 return vector<int>();
248 }
249
250 return result;
251}
252
253// --------------------------------------------------------------------------
254//
255//! Loads the fits file based on the current parameters
256//
257bool FitsDumper::OpenFile(const string &filename)
258{
259 if (fFile)
260 delete fFile;
261
262 ostringstream str;
263 try
264 {
265 fFile = new CCfits::FITS(filename);
266 }
267 catch (CCfits::FitsException e)
268 {
269 cerr << "Could not open FITS file " << filename << " reason: " << e.message() << endl;
270 return false;
271 }
272
273 return true;
274}
275
276bool FitsDumper::OpenTable(const string &tablename)
277{
278 if (!fFile)
279 {
280 cerr << "No file open." << endl;
281 return false;
282 }
283
284 const multimap< string, CCfits::ExtHDU * > extMap = fFile->extension();
285 if (extMap.find(tablename) == extMap.end())
286 {
287 cerr << "Table '" << tablename << "' not found." << endl;
288 return false;
289 }
290
291 fTable = dynamic_cast<CCfits::Table*>(extMap.find(tablename)->second);
292 if (!fTable)
293 {
294 cerr << "Object '" << tablename << "' returned not a CCfits::Table." << endl;
295 return false;
296 }
297
298 fColMap = fTable->column();
299
300 fTable->makeThisCurrent();
301
302 fTable->getComments();
303 fTable->getHistory();
304 fTable->readAllKeys();
305
306 return true;
307}
308
309class MyColumn : public CCfits::Column
310{
311public:
312 const string &comment() const { return CCfits::Column::comment(); }
313};
314
315void FitsDumper::List()
316{
317 if (!fFile)
318 {
319 cerr << "No file open." << endl;
320 return;
321 }
322
323 cout << "\nFile: " << fFile->name() << "\n";
324
325 const multimap< string, CCfits::ExtHDU * > extMap = fFile->extension();
326 for (std::multimap<string, CCfits::ExtHDU*>::const_iterator it=extMap.begin(); it != extMap.end(); it++)
327 {
328
329 CCfits::Table *table = dynamic_cast<CCfits::Table*>(extMap.find(it->first)->second);
330
331 cout << " " << it->first << " [" << table->rows() << "]\n";
332
333 const map<string, CCfits::Column*> &cols = table->column();
334
335 for (map<string, CCfits::Column*>::const_iterator ic=cols.begin();
336 ic != cols.end(); ic++)
337 {
338 const MyColumn *col = static_cast<MyColumn*>(ic->second);
339
340 cout << " " << col->name() << "[" << col->width() << "] * " << col->scale() << " (" << col->unit() << ":" << ValueTypeToStr(col->type())<< ") " << col->comment() << "\n";
341 /*
342 inline size_t Column::repeat () const
343 inline bool Column::varLength () const
344 inline double Column::zero () const
345 inline const String& Column::display () const
346 inline const String& Column::dimen () const
347 inline const String& Column::TBCOL ()
348 inline const String& Column::TTYPE ()
349 inline const String& Column::TFORM ()
350 inline const String& Column::TDISP ()
351 inline const String& Column::TZERO ()
352 inline const String& Column::TDIM ()
353 inline const String& Column::TNULL ()
354 inline const String& Column::TLMIN ()
355 inline const String& Column::TLMAX ()
356 inline const String& Column::TDMAX ()
357 inline const String& Column::TDMIN ()
358 */
359 }
360 cout << '\n';
361 }
362 cout << flush;
363}
364
365class MyKeyword : public CCfits::Keyword
366{
367public:
368 CCfits::ValueType keytype() const { return CCfits::Keyword::keytype(); }
369};
370
371void FitsDumper::ListKeywords(ostream &out)
372{
373 map<string,CCfits::Keyword*> keys = fTable->keyWord();
374 for (map<string,CCfits::Keyword*>::const_iterator it=keys.begin();
375 it!=keys.end(); it++)
376 {
377 string str;
378 double d;
379
380 const MyKeyword *kw = static_cast<MyKeyword*>(it->second);
381 kw->keytype();
382 out << "## " << setw(8) << kw->name() << "='";
383 if (kw->keytype()==16)
384 out << kw->value(str);
385 if (kw->keytype()==82)
386 out << kw->value(d);
387 out << "' \t(" << kw->comment() << ")" << endl;
388 }
389}
390
391void FitsDumper::ListHeader()
392{
393 if (!fTable)
394 {
395 cerr << "No table open." << endl;
396 return;
397 }
398
399 cout << "\nTable: " << fTable->name() << " (rows=" << fTable->rows() << ")\n";
400 if (!fTable->comment().empty())
401 cout << "Comment: \t" << fTable->comment() << '\n';
402 if (!fTable->history().empty())
403 cout << "History: \t" << fTable->history() << '\n';
404
405 ListKeywords(cout);
406 cout << endl;
407}
408
409
410// --------------------------------------------------------------------------
411//
412//! Perform the actual dump, based on the current parameters
413//
414bool FitsDumper::Dump(const string &filename, const vector<string> &list, int precision)
415{
416 for (vector<string>::const_iterator it=list.begin(); it!=list.end(); it++)
417 if (fColMap.find(*it) == fColMap.end())
418 {
419 cerr << "WARNING - Column '" << *it << "' not found in table." << endl;
420 return false;
421 }
422
423
424 const vector<int> offsets = CalculateOffsets();
425 if (offsets.size()==0)
426 return false;
427
428 const int size = offsets[offsets.size()-1];
429
430 ofstream out(filename=="-"?"/dev/stdout":filename);
431 if (!out)
432 {
433 cerr << "Cannot open file " << filename << ": " << strerror(errno) << endl;
434 return false;
435 }
436
437 out.precision(precision);
438
439 out << "## --------------------------------------------------------------------------\n";
440 if (filename!="-")
441 out << "## File: \t" << filename << '\n';
442 out << "## Table: \t" << fTable->name() << '\n';
443 if (!fTable->comment().empty())
444 out << "## Comment: \t" << fTable->comment() << '\n';
445 if (!fTable->history().empty())
446 out << "## History: \t" << fTable->history() << '\n';
447 out << "## NumRows: \t" << fTable->rows() << '\n';
448 out << "## --------------------------------------------------------------------------\n";
449 ListKeywords(out);
450 out << "## --------------------------------------------------------------------------\n";
451 out << "#\n";
452 for (vector<string>::const_iterator it=list.begin(); it!=list.end(); it++)
453 {
454 const MyColumn *col = static_cast<MyColumn*>(fTable->column()[*it]);
455 out << "# " << col->name() << "[" << col->width() << "]: " << col->unit();
456 if (!col->comment().empty())
457 out << " (" <<col->comment() << ")";
458 out << '\n';
459 }
460 out << "#" << endl;
461
462 unsigned char* fitsBuffer = new unsigned char[size];
463
464 int status = 0;
465 for (int i=1; i<=fTable->rows(); i++)
466 {
467 fits_read_tblbytes(fFile->fitsPointer(), i, 1, size, fitsBuffer, &status);
468 if (status)
469 {
470 cerr << "An error occurred while reading fits row #" << i << " error code: " << status << endl;
471 break;
472 }
473 WriteRow(out, list, offsets, fitsBuffer);
474 }
475 delete[] fitsBuffer;
476
477 return status;
478}
479
480// --------------------------------------------------------------------------
481//
482//! Retrieves the configuration parameters
483//! @param conf
484//! the configuration object
485//
486int FitsDumper::ExecConfig(Configuration& conf)
487{
488 if (conf.Has("fitsfile"))
489 {
490 if (!OpenFile(conf.Get<string>("fitsfile")))
491 return -1;
492 }
493
494 if (conf.Get<bool>("list"))
495 List();
496
497 if (conf.Has("tablename"))
498 {
499 if (!OpenTable(conf.Get<string>("tablename")))
500 return -1;
501 }
502
503 if (conf.Get<bool>("header"))
504 ListHeader();
505
506 if (conf.Get<bool>("header") || conf.Get<bool>("list"))
507 return 1;
508
509 if (conf.Has("outfile"))
510 {
511 if (!Dump(conf.Get<string>("outfile"),
512 conf.Get<vector<string>>("col"),
513 conf.Get<int>("precision")))
514 return -1;
515 }
516
517 return 0;
518}
519
520void PrintUsage()
521{
522 cout <<
523 "fitsdump is a tool to dump data from a FITS table as ascii.\n"
524 "\n"
525 "Usage: fitsdump [OPTIONS] fitsfile col col ... \n"
526 " or: fitsdump [OPTIONS]\n";
527 cout << endl;
528}
529
530void PrintHelp()
531{
532 //
533}
534
535void SetupConfiguration(Configuration& conf)
536{
537 po::options_description configs("Fitsdump options");
538 configs.add_options()
539 ("fitsfile,f", var<string>()
540#if BOOST_VERSION >= 104200
541 ->required()
542#endif
543 , "Name of FITS file")
544 ("tablename,t", var<string>("DATA")
545#if BOOST_VERSION >= 104200
546 ->required()
547#endif
548 , "Name of input table")
549 ("col,c", vars<string>(), "List of columns to dump")
550 ("outfile,o", var<string>("/dev/stdout"), "Name of output file (-:/dev/stdout)")
551 ("precision,p", var<int>(20), "Precision of ofstream")
552 ("list,l", po_switch(), "List all tables and columns in file")
553 ("header,h", po_switch(), "Dump header of given table")
554 ;
555
556 po::positional_options_description p;
557 p.add("fitsfile", 1); // The first positional options
558 p.add("col", -1); // All others
559
560 conf.AddOptions(configs);
561 conf.SetArgumentPositions(p);
562}
563
564int main(int argc, const char** argv)
565{
566 Configuration conf(argv[0]);
567 conf.SetPrintUsage(PrintUsage);
568 SetupConfiguration(conf);
569
570 po::variables_map vm;
571 try
572 {
573 vm = conf.Parse(argc, argv);
574 }
575#if BOOST_VERSION > 104000
576 catch (po::multiple_occurrences &e)
577 {
578 cerr << "Program options invalid due to: " << e.what() << " of option '" << e.get_option_name() << "'." << endl;
579 return -1;
580 }
581#endif
582 catch (exception& e)
583 {
584 cerr << "Program options invalid due to: " << e.what() << endl;
585 return -1;
586 }
587
588 if (conf.HasPrint())
589 return -1;
590 if (conf.HasVersion())
591 {
592 FACT::PrintVersion(argv[0]);
593 return -1;
594 }
595
596 if (conf.HasHelp())
597 {
598 PrintHelp();
599 return -1;
600 }
601
602 FitsDumper loader;
603 return loader.ExecConfig(conf);
604}
Note: See TracBrowser for help on using the repository browser.