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

Last change on this file since 11913 was 11913, checked in by lyard, 13 years ago
added time display
File size: 33.8 KB
Line 
1//****************************************************************
2/** @class FitsDumper
3
4 @brief Dumps contents of fits tables to stdout or a file
5
6 */
7 //****************************************************************
8#include "Configuration.h"
9
10#include <map>
11#include <fstream>
12
13#include <CCfits/CCfits>
14
15//#define PLOTTING_PLEASE
16
17#ifdef PLOTTING_PLEASE
18#include <qapplication.h>
19#include <qlayout.h>
20#include <qwt_plot.h>
21#include <qwt-qt4/qwt_plot_grid.h>
22#include <QPen>
23#include <qwt-qt4/qwt_plot_curve.h>
24#include <qwt-qt4/qwt_plot_zoomer.h>
25#include <qwt-qt4/qwt_legend.h>
26#include <qwt-qt4/qwt_scale_draw.h>
27#include "Time.h"
28#endif
29using namespace std;
30
31class MyColumn : public CCfits::Column
32{
33public:
34 const string &comment() const { return CCfits::Column::comment(); }
35 long width() const
36 {//the width() method seems to be buggy (or empty ?) as it always return 1... redo it ourselves.
37 string inter = format();
38 inter = inter.substr(0, inter.size()-1);
39 return atoi(inter.c_str());
40 }
41};
42
43#ifdef PLOTTING_PLEASE
44class TimeScaleDraw: public QwtScaleDraw
45{
46public:
47 virtual QwtText label(double v) const
48 {
49 Time t(v);
50 string time = t.GetAsStr("%H:%M:%S%F");
51 while (time[time.size()-1] == '0' && time.size() > 2)
52 {
53 time = time.substr(0, time.size()-1);
54 }
55 return QwtText(time.c_str());
56 }
57};
58#endif
59
60class FitsDumper
61{
62public:
63 FitsDumper();
64 ~FitsDumper();
65
66private:
67
68 CCfits::FITS *fFile; /// FITS pointer
69 CCfits::Table *fTable; /// Table pointer
70 map<string, MyColumn*> fColMap; /// map between the column names and their CCfits objects
71
72 // Convert CCfits::ValueType into a human readable string
73 string ValueTypeToStr(CCfits::ValueType type) const;
74
75 // Convert CCfits::ValueType into a number of associated bytes
76 int ValueTypeToSize(CCfits::ValueType type) const;
77
78 /// Calculate the buffer size required to read a row of the fits table, as well as the offsets to each column
79 vector<int> CalculateOffsets() const;
80
81 template<class T>
82 T PtrToValue(const unsigned char* &ptr) const;
83// template<class T>
84// double PtrToDouble(const unsigned char *ptr) const;
85// double PtrToDouble(const unsigned char *ptr, CCfits::ValueType type) const;
86
87 /// Write a single row of the selected data
88 int WriteRow(ostream &, const vector<MyColumn*> &, const vector<int> &, unsigned char *, const vector<pair<int, int> >&) const;
89
90 bool OpenFile(const string &); /// Open a file
91 bool OpenTable(const string &); /// Open a table
92
93 /// Lists all columns of an open file
94 void List();
95 void ListHeader();
96 void ListKeywords(ostream &);
97
98 bool separateColumnsFromRanges(const vector<string>& list,
99 vector<pair<int, int> >& ranges,
100 vector<string>& listNamesOnly);
101 /// Perform the dumping, based on the current dump list
102 bool Dump(const string &, const vector<string> &list, int);
103 ///Display the selected columns values VS time
104 int doCurvesDisplay( const vector<string> &list, const string& tableName);
105// bool Plot(const vector<string> &list);
106
107public:
108 ///Configures the fitsLoader from the config file and/or command arguments.
109 int ExecConfig(Configuration& conf);
110};
111
112// --------------------------------------------------------------------------
113//
114//! Constructor
115//! @param out
116//! the ostream where to redirect the outputs
117//
118FitsDumper::FitsDumper() : fFile(0), fTable(0)
119{
120}
121
122// --------------------------------------------------------------------------
123//
124//! Destructor
125//
126FitsDumper::~FitsDumper()
127{
128 if (fFile)
129 delete fFile;
130}
131
132
133string FitsDumper::ValueTypeToStr(CCfits::ValueType type) const
134{
135 switch (type)
136 {
137 case CCfits::Tbyte: return "uint8_t";
138 case CCfits::Tushort: return "uint16_t";
139 case CCfits::Tshort: return "int16_t";
140 case CCfits::Tuint: return "uint32_t";
141 case CCfits::Tint: return "int32_t";
142 case CCfits::Tulong: return "uint32_t";
143 case CCfits::Tlong: return "int32_t";
144 case CCfits::Tlonglong: return "int64_t";
145 case CCfits::Tfloat: return "float";
146 case CCfits::Tdouble: return "double";
147
148 default:
149 return "unknwown";
150 }
151}
152
153int FitsDumper::ValueTypeToSize(CCfits::ValueType type) const
154{
155 switch (type)
156 {
157 case CCfits::Tbyte: return sizeof(uint8_t);
158 case CCfits::Tushort:
159 case CCfits::Tshort: return sizeof(uint16_t);
160 case CCfits::Tuint:
161 case CCfits::Tint:
162 case CCfits::Tulong:
163 case CCfits::Tlong: return sizeof(uint32_t);
164 case CCfits::Tlonglong: return sizeof(uint64_t);
165 case CCfits::Tfloat: return sizeof(float);
166 case CCfits::Tdouble: return sizeof(double);
167
168 default:
169 return 0;
170 }
171}
172
173template<class T>
174T FitsDumper::PtrToValue(const unsigned char* &ptr) const
175{
176 T t;
177 reverse_copy(ptr, ptr+sizeof(T), reinterpret_cast<unsigned char*>(&t));
178 ptr += sizeof(T);
179
180 return t;
181}
182/*
183template<class T>
184double FitsDumper::PtrToDouble(const unsigned char *ptr) const
185{
186 T t;
187 reverse_copy(ptr, ptr+sizeof(T), reinterpret_cast<unsigned char*>(&t));
188 return t;
189}
190
191double FitsDumper::PtrToDouble(const unsigned char *ptr, CCfits::ValueType type) const
192{
193 switch (type)
194 {
195 case CCfits::Tbyte: return PtrToDouble<uint8_t> (ptr);
196 case CCfits::Tushort: return PtrToDouble<uint16_t>(ptr);
197 case CCfits::Tuint:
198 case CCfits::Tulong: return PtrToDouble<uint32_t>(ptr);
199 case CCfits::Tshort: return PtrToDouble<int16_t> (ptr);
200 case CCfits::Tint:
201 case CCfits::Tlong: return PtrToDouble<int32_t> (ptr);
202 case CCfits::Tlonglong: return PtrToDouble<int64_t> (ptr);
203 case CCfits::Tfloat: return PtrToDouble<float> (ptr);
204 case CCfits::Tdouble: return PtrToDouble<double> (ptr);
205
206 default:
207 throw runtime_error("Data type not implemented yet.");
208 }
209}
210*/
211
212// --------------------------------------------------------------------------
213//
214//! Writes a single row of the selected FITS data to the output file.
215//!
216//! Data type \b not yet implemented:
217//! CCfits::Tnull, CCfits::Tbit, CCfits::Tlogical, CCfits::Tstring,
218//! CCfits::Tcomplex, CCfits::Tdblcomplex, CCfits::VTbit,
219//! CCfits::VTbyte, CCfits::VTlogical, CCfits::VTushort,
220//! CCfits::VTshort, CCfits::VTuint, CCfits::VTint, CCfits::VTulong,
221//! CCfits::VTlong, CCfits::VTlonglong, CCfits::VTfloat,
222//! CCfits::VTdouble, CCfits::VTcomplex, CCfits::VTdblcomplex
223//!
224//! @param offsets
225//! a vector containing the offsets to the columns (in bytes)
226//! @param targetFile
227//! the ofstream where to write to
228//! @param fitsBuffer
229//! the memory were the row has been loaded by cfitsio
230//
231int FitsDumper::WriteRow(ostream &out, const vector<MyColumn*> &list, const vector<int> &offsets, unsigned char* fitsBuffer, const vector<pair<int, int> >& ranges) const
232{
233 int cnt = 0;
234 vector<pair<int, int> >::const_iterator jt = ranges.begin();
235 for (vector<MyColumn*>::const_iterator it=list.begin(); it!=list.end(); it++, jt++)
236 {
237 if (jt == ranges.end())
238 {
239 cout << "ERROR: END OF RANGE POINTER REACHED" << endl;
240 return false;
241 }
242 const MyColumn *col = *it;
243
244 // CCfits starts counting at 1 not 0
245 const int offset = offsets[col->index()-1];
246
247 // Get the pointer to the array which we are supposed to print
248 const unsigned char *ptr = fitsBuffer + offset;
249
250 // Loop over all array entries
251 int sizeToSkip = 0;
252 switch (col->type())
253 {
254 case CCfits::Tbyte: sizeToSkip = sizeof(uint8_t); break;
255 case CCfits::Tushort: sizeToSkip = sizeof(uint16_t); break;
256 case CCfits::Tuint:
257 case CCfits::Tulong: sizeToSkip = sizeof(uint32_t); break;
258 case CCfits::Tshort: sizeToSkip = sizeof(int16_t); break;
259 case CCfits::Tint:
260 case CCfits::Tlong: sizeToSkip = sizeof(int32_t); break;
261 case CCfits::Tlonglong: sizeToSkip = sizeof(int64_t); break;
262 case CCfits::Tfloat: sizeToSkip = sizeof(float); break;
263 case CCfits::Tdouble: sizeToSkip = sizeof(double); break;
264 default:
265 cerr << "Data type not implemented yet." << endl;
266 return 0;
267 }
268 ptr += sizeToSkip*jt->first;
269 for (int width=jt->first; width<jt->second; width++)
270 {
271 switch (col->type())
272 {
273 case CCfits::Tbyte: out << PtrToValue<uint8_t> (ptr); break;
274 case CCfits::Tushort: out << PtrToValue<uint16_t>(ptr); break;
275 case CCfits::Tuint:
276 case CCfits::Tulong: out << PtrToValue<uint32_t>(ptr); break;
277 case CCfits::Tshort: out << PtrToValue<int16_t> (ptr); break;
278 case CCfits::Tint:
279 case CCfits::Tlong: out << PtrToValue<int32_t> (ptr); break;
280 case CCfits::Tlonglong: out << PtrToValue<int64_t> (ptr); break;
281 case CCfits::Tfloat: out << PtrToValue<float> (ptr); break;
282 case CCfits::Tdouble: out << PtrToValue<double> (ptr); break;
283
284 default:
285 cerr << "Data type not implemented yet." << endl;
286 return 0;
287 }
288
289 out << " ";
290 cnt++;
291 }
292 }
293
294 if (cnt>0)
295 out << endl;
296
297 if (out.fail())
298 {
299 cerr << "ERROR - writing output: " << strerror(errno) << endl;
300 return -1;
301 }
302
303 return cnt;
304}
305
306// --------------------------------------------------------------------------
307//
308//! Calculates the required buffer size for reading one row of the current
309//! table. Also calculates the offsets to all the columns
310//
311vector<int> FitsDumper::CalculateOffsets() const
312{
313 map<int,int> sizes;
314
315 for (map<string, MyColumn*>::const_iterator it=fColMap.begin();
316 it!=fColMap.end(); it++)
317 {
318 const int &width = it->second->width();
319 const int &idx = it->second->index();
320
321 const int size = ValueTypeToSize(it->second->type());
322 if (size==0)
323 {
324 cerr << "Data type " << (int)it->second->type() << " not implemented yet." << endl;
325 return vector<int>();
326 }
327
328 sizes[idx] = size*width;
329 }
330
331 //calculate the offsets in the vector.
332 vector<int> result(1, 0);
333
334 int size = 0;
335 int idx = 0;
336
337 for (map<int,int>::const_iterator it=sizes.begin(); it!=sizes.end(); it++)
338 {
339 size += it->second;
340 result.push_back(size);
341
342 if (it->first == ++idx)
343 continue;
344
345 cerr << "Expected index " << idx << ", but found " << it->first << endl;
346 return vector<int>();
347 }
348
349 return result;
350}
351
352// --------------------------------------------------------------------------
353//
354//! Loads the fits file based on the current parameters
355//
356bool FitsDumper::OpenFile(const string &filename)
357{
358 if (fFile)
359 delete fFile;
360
361 ostringstream str;
362 try
363 {
364 fFile = new CCfits::FITS(filename);
365 }
366 catch (CCfits::FitsException e)
367 {
368 cerr << "Could not open FITS file " << filename << " reason: " << e.message() << endl;
369 return false;
370 }
371
372 return true;
373}
374
375bool FitsDumper::OpenTable(const string &tablename)
376{
377 if (!fFile)
378 {
379 cerr << "No file open." << endl;
380 return false;
381 }
382
383 const multimap< string, CCfits::ExtHDU * > extMap = fFile->extension();
384 if (extMap.find(tablename) == extMap.end())
385 {
386 cerr << "Table '" << tablename << "' not found." << endl;
387 return false;
388 }
389
390 fTable = dynamic_cast<CCfits::Table*>(extMap.find(tablename)->second);
391 if (!fTable)
392 {
393 cerr << "Object '" << tablename << "' returned not a CCfits::Table." << endl;
394 return false;
395 }
396
397 map<string, CCfits::Column*>& tCols = fTable->column();
398 for (map<string, CCfits::Column*>::const_iterator it = tCols.begin(); it != tCols.end(); it++)
399 {
400 fColMap.insert(make_pair(it->first, static_cast<MyColumn*>(it->second)));
401 }
402// fColMap = fTable->column();
403
404 fTable->makeThisCurrent();
405
406 fTable->getComments();
407 fTable->getHistory();
408 fTable->readAllKeys();
409
410 return true;
411}
412
413
414void FitsDumper::List()
415{
416 if (!fFile)
417 {
418 cerr << "No file open." << endl;
419 return;
420 }
421
422 cout << "\nFile: " << fFile->name() << "\n";
423
424 const multimap< string, CCfits::ExtHDU * > extMap = fFile->extension();
425 for (std::multimap<string, CCfits::ExtHDU*>::const_iterator it=extMap.begin(); it != extMap.end(); it++)
426 {
427
428 CCfits::Table *table = dynamic_cast<CCfits::Table*>(extMap.find(it->first)->second);
429
430 table->makeThisCurrent();
431 table->readData();
432
433 cout << " " << it->first << " [" << table->rows() << "]\n";
434
435 const map<string, CCfits::Column*> &cols = table->column();
436
437// for (map<string, CCfits::Column*>::const_iterator id = cols.begin(); ib != cols.end(); ib++)
438// {
439// TFORM
440// }
441
442 for (map<string, CCfits::Column*>::const_iterator ic=cols.begin();
443 ic != cols.end(); ic++)
444 {
445 const MyColumn *col = static_cast<MyColumn*>(ic->second);
446
447 cout << " " << col->name() << "[" << col->width() << "] * " << col->scale() << " (" << col->unit() << ":" << ValueTypeToStr(col->type())<< ") " << col->comment() << "\n";
448 /*
449 inline size_t Column::repeat () const
450 inline bool Column::varLength () const
451 inline double Column::zero () const
452 inline const String& Column::display () const
453 inline const String& Column::dimen () const
454 inline const String& Column::TBCOL ()
455 inline const String& Column::TTYPE ()
456 inline const String& Column::TFORM ()
457 inline const String& Column::TDISP ()
458 inline const String& Column::TZERO ()
459 inline const String& Column::TDIM ()
460 inline const String& Column::TNULL ()
461 inline const String& Column::TLMIN ()
462 inline const String& Column::TLMAX ()
463 inline const String& Column::TDMAX ()
464 inline const String& Column::TDMIN ()
465 */
466 }
467 cout << '\n';
468 }
469 cout << flush;
470}
471
472class MyKeyword : public CCfits::Keyword
473{
474public:
475 CCfits::ValueType keytype() const { return CCfits::Keyword::keytype(); }
476};
477
478void FitsDumper::ListKeywords(ostream &out)
479{
480 map<string,CCfits::Keyword*> keys = fTable->keyWord();
481 for (map<string,CCfits::Keyword*>::const_iterator it=keys.begin();
482 it!=keys.end(); it++)
483 {
484 string str;
485 double d;
486 int l;
487
488 const MyKeyword *kw = static_cast<MyKeyword*>(it->second);
489 kw->keytype();
490 out << "## " << setw(8) << kw->name() << " = " << setw(10);
491 if (kw->keytype()==16)
492 out << ("'"+kw->value(str)+"'");
493 if (kw->keytype()==31)
494 out << kw->value(l);
495 if (kw->keytype()==82)
496 out << kw->value(d);
497 out << " / " << kw->comment() << endl;
498 }
499}
500
501void FitsDumper::ListHeader()
502{
503 if (!fTable)
504 {
505 cerr << "No table open." << endl;
506 return;
507 }
508
509 cout << "\nTable: " << fTable->name() << " (rows=" << fTable->rows() << ")\n";
510 if (!fTable->comment().empty())
511 cout << "Comment: \t" << fTable->comment() << '\n';
512 if (!fTable->history().empty())
513 cout << "History: \t" << fTable->history() << '\n';
514
515 ListKeywords(cout);
516 cout << endl;
517}
518
519bool FitsDumper::separateColumnsFromRanges(const vector<string>& list,
520 vector<pair<int, int> >& ranges,
521 vector<string>& listNamesOnly)
522{
523 for (vector<string>::const_iterator it=list.begin(); it!=list.end(); it++)
524 {
525 string columnNameOnly = *it;
526 unsigned long bracketIndex0 = columnNameOnly.find_first_of('[');
527 unsigned long bracketIndex1 = columnNameOnly.find_first_of(']');
528 unsigned long colonIndex = columnNameOnly.find_first_of(':');
529// cout << bracketIndex0 << " " << bracketIndex1 << " " << colonIndex << endl;
530 int columnStart = -1;
531 int columnEnd = -1;
532 if (bracketIndex0 != string::npos)
533 {//there is a range given. Extract the range
534 if (colonIndex != string::npos)
535 {//we have a range here
536 columnStart = atoi(columnNameOnly.substr(bracketIndex0+1, colonIndex-(bracketIndex0+1)).c_str());
537 columnEnd = atoi(columnNameOnly.substr(colonIndex+1, bracketIndex1-(colonIndex+1)).c_str());
538 columnEnd++;
539 }
540 else
541 {//only a single index there
542 columnStart = atoi(columnNameOnly.substr(bracketIndex0+1, bracketIndex1 - (bracketIndex0+1)).c_str());
543 columnEnd = columnStart+1;
544// cout << "Cstart " << columnStart << " end: " << columnEnd << endl;
545 }
546 columnNameOnly = columnNameOnly.substr(0, bracketIndex0);
547 }
548
549 if (fColMap.find(columnNameOnly) == fColMap.end())
550 {
551 cerr << "ERROR - Column '" << columnNameOnly << "' not found in table." << endl;
552 return false;
553 }
554// cout << "The column name is: " << columnNameOnly << endl;
555 MyColumn *cCol = static_cast<MyColumn*>(fColMap.find(columnNameOnly)->second);
556 if (bracketIndex0 == string::npos)
557 {//no range given: use the full range
558 ranges.push_back(make_pair(0, cCol->width()));
559 columnStart = 0;
560 columnEnd = 1;
561 }
562 else
563 {//use the range extracted earlier
564 if (columnStart < 0)
565 {
566 cerr << "ERROR - Start range for column " << columnNameOnly << " is less than zero (" << columnStart << "). Aborting" << endl;
567 return false;
568 }
569 if (columnEnd > cCol->width())
570 {
571 cerr << "ERROR - End range for column " << columnNameOnly << " is greater than the last element (" << cCol->width() << " vs " << columnEnd << "). Aborting" << endl;
572 return false;
573 }
574 ranges.push_back(make_pair(columnStart, columnEnd));
575 }
576// cout << "Will be exporting from " << columnStart << " to " << columnEnd-1 << " for column " << columnNameOnly << endl;
577 listNamesOnly.push_back(columnNameOnly);
578 }
579 return true;
580}
581// --------------------------------------------------------------------------
582//
583//! Perform the actual dump, based on the current parameters
584//
585bool FitsDumper::Dump(const string &filename, const vector<string> &list, int precision)
586{
587
588 //first of all, let's separate the columns from their ranges and check that the requested columns are indeed part of the file
589 vector<pair<int, int> > ranges;
590 vector<string> listNamesOnly;
591
592 if (!separateColumnsFromRanges(list, ranges, listNamesOnly))
593 {
594 cerr << "Something went wrong while extracting the columns names from parameters. Aborting" << endl;
595 return false;
596 }
597
598 // FIXME: Maybe do this when opening a table?
599 const vector<int> offsets = CalculateOffsets();
600 if (offsets.size()==0)
601 return false;
602
603 ofstream out(filename=="-"?"/dev/stdout":filename);
604 if (!out)
605 {
606 cerr << "Cannot open file " << filename << ": " << strerror(errno) << endl;
607 return false;
608 }
609
610 out.precision(precision);
611
612 out << "## --------------------------------------------------------------------------\n";
613 if (filename!="-")
614 out << "## File: \t" << filename << '\n';
615 out << "## Table: \t" << fTable->name() << '\n';
616 if (!fTable->comment().empty())
617 out << "## Comment: \t" << fTable->comment() << '\n';
618 if (!fTable->history().empty())
619 out << "## History: \t" << fTable->history() << '\n';
620 out << "## NumRows: \t" << fTable->rows() << '\n';
621 out << "## --------------------------------------------------------------------------\n";
622 ListKeywords(out);
623 out << "## --------------------------------------------------------------------------\n";
624 out << "#\n";
625 //vector<pair<int, int> >::const_iterator rangesIt = ranges.begin();
626 //the above is soooo yesterday ;) let's try the new auto feature of c++0x
627 auto rangesIt = ranges.begin();
628 for (vector<string>::const_iterator it=listNamesOnly.begin(); it!=listNamesOnly.end(); it++, rangesIt++)
629 {
630 const MyColumn *col = static_cast<MyColumn*>(fTable->column()[*it]);
631 if (rangesIt->first != 0 || rangesIt->second != col->width())
632 {
633 out << "#";
634 for (int i=rangesIt->first; i<rangesIt->second; i++)
635 out << " " << col->name() << "[" << i << "]";
636 out << ": " << col->unit();
637 }
638 else
639 out << "# " << col->name() << "[" << col->width() << "]: " << col->unit();
640
641 if (!col->comment().empty())
642 out << " (" <<col->comment() << ")";
643 out << '\n';
644 }
645 out << "#" << endl;
646
647
648 // Loop over all columns in our list of requested columns
649 vector<MyColumn*> columns;
650 for (vector<string>::const_iterator it=listNamesOnly.begin(); it!=listNamesOnly.end(); it++)
651 {
652 MyColumn *cCol = static_cast<MyColumn*>(fColMap.find(*it)->second);
653 columns.push_back(cCol);
654 }
655 const int size = offsets[offsets.size()-1];
656 unsigned char* fitsBuffer = new unsigned char[size];
657
658 int status = 0;
659 for (int i=1; i<=fTable->rows(); i++)
660 {
661 fits_read_tblbytes(fFile->fitsPointer(), i, 1, size, fitsBuffer, &status);
662 if (status)
663 {
664 cerr << "An error occurred while reading fits row #" << i << " error code: " << status << endl;
665 break;
666 }
667 if (WriteRow(out, columns, offsets, fitsBuffer, ranges)<0)
668 {
669 status=1;
670 break;
671 }
672 }
673 delete[] fitsBuffer;
674
675 return status==0;
676}
677
678// --------------------------------------------------------------------------
679//
680//! Perform the actual dump, based on the current parameters
681//
682/*
683bool FitsDumper::Plot(const vector<string> &list)
684{
685 for (vector<string>::const_iterator it=list.begin(); it!=list.end(); it++)
686 if (fColMap.find(*it) == fColMap.end())
687 {
688 cerr << "WARNING - Column '" << *it << "' not found in table." << endl;
689 return false;
690 }
691
692 // FIXME: Maybe do this when opening a table?
693 const vector<int> offsets = CalculateOffsets();
694 if (offsets.size()==0)
695 return false;
696
697 // Loop over all columns in our list of requested columns
698 const CCfits::Column *col[3] =
699 {
700 list.size()>0 ? fColMap.find(list[0])->second : 0,
701 list.size()>1 ? fColMap.find(list[1])->second : 0,
702 list.size()>2 ? fColMap.find(list[2])->second : 0
703 };
704
705 const int size = offsets[offsets.size()-1];
706 unsigned char* fitsBuffer = new unsigned char[size];
707
708 const int idx = 0;
709
710 // CCfits starts counting at 1 not 0
711 const size_t pos[3] =
712 {
713 col[0] ? offsets[col[0]->index()-1] + idx*col[0]->width()*ValueTypeToSize(col[0]->type()) : 0,
714 col[1] ? offsets[col[1]->index()-1] + idx*col[1]->width()*ValueTypeToSize(col[1]->type()) : 0,
715 col[2] ? offsets[col[2]->index()-1] + idx*col[2]->width()*ValueTypeToSize(col[2]->type()) : 0
716 };
717
718 int status = 0;
719 for (int i=1; i<=fTable->rows(); i++)
720 {
721 fits_read_tblbytes(fFile->fitsPointer(), i, 1, size, fitsBuffer, &status);
722 if (status)
723 {
724 cerr << "An error occurred while reading fits row #" << i << " error code: " << status << endl;
725 break;
726 }
727
728 try
729 {
730 const double x[3] =
731 {
732 col[0] ? PtrToDouble(fitsBuffer+pos[0], col[0]->type()) : 0,
733 col[1] ? PtrToDouble(fitsBuffer+pos[1], col[1]->type()) : 0,
734 col[2] ? PtrToDouble(fitsBuffer+pos[2], col[2]->type()) : 0
735 };
736 }
737 catch (const runtime_error &e)
738 {
739 cerr << e.what() << endl;
740 status=1;
741 break;
742 }
743 }
744 delete[] fitsBuffer;
745
746 return status==0;
747}
748*/
749
750// --------------------------------------------------------------------------
751//
752//! Retrieves the configuration parameters
753//! @param conf
754//! the configuration object
755//
756int FitsDumper::ExecConfig(Configuration& conf)
757{
758 if (conf.Has("fitsfile"))
759 {
760 if (!OpenFile(conf.Get<string>("fitsfile")))
761 return -1;
762 }
763
764
765 if (conf.Get<bool>("list"))
766 List();
767
768 if (conf.Has("tablename"))
769 {
770 if (!OpenTable(conf.Get<string>("tablename")))
771 return -1;
772 }
773
774 if (conf.Get<bool>("graph"))
775 {
776 if (!conf.Has("col"))
777 {
778 cout << "Please specify the columns that should be dumped as arguments. Aborting" << endl;
779 return 0;
780 }
781 doCurvesDisplay(conf.Get<vector<string>>("col"),
782 conf.Get<string>("tablename"));
783 return 1;
784 }
785
786
787 if (conf.Get<bool>("header"))
788 ListHeader();
789
790 if (conf.Get<bool>("header") || conf.Get<bool>("list"))
791 return 1;
792
793 if (conf.Has("outfile"))
794 {
795 if (!conf.Has("col"))
796 {
797 cout << "Please specify the columns that should be dumped as arguments. Aborting" << endl;
798 return 0;
799 }
800 if (!Dump(conf.Get<string>("outfile"),
801 conf.Get<vector<string>>("col"),
802 conf.Get<int>("precision")))
803 return -1;
804 }
805
806
807 return 0;
808}
809
810void PrintUsage()
811{
812 cout <<
813 "fitsdump is a tool to dump data from a FITS table as ascii.\n"
814 "\n"
815 "Usage: fitsdump [OPTIONS] fitsfile col col ... \n"
816 " or: fitsdump [OPTIONS]\n";
817 cout << endl;
818}
819
820void PrintHelp()
821{
822 //
823}
824#ifdef PLOTTING_PLEASE
825int FitsDumper::doCurvesDisplay( const vector<string> &list, const string& tableName)
826{
827 //first of all, let's separate the columns from their ranges and check that the requested columns are indeed part of the file
828 vector<pair<int, int> > ranges;
829 vector<string> listNamesOnly;
830 if (!separateColumnsFromRanges(list, ranges, listNamesOnly))
831 {
832 cerr << "Something went wrong while extracting the columns names from parameters. Aborting" << endl;
833 return false;
834 }
835 vector<string> curvesNames;
836 stringstream str;
837 for (auto it=ranges.begin(), jt=listNamesOnly.begin(); it != ranges.end(); it++, jt++)
838 {
839 for (int i=it->first; i<it->second;i++)
840 {
841 str.str("");
842 str << *jt << "[" << i << "]";
843 curvesNames.push_back(str.str());
844 }
845 }
846 char* handle = new char[17];
847 sprintf(handle,"FitsDump Display");
848// Qt::HANDLE h = *handle;//NULL
849 int argc = 1;
850 char ** argv = &handle;
851 QApplication a(argc, argv);
852
853
854
855 QwtPlot* plot = new QwtPlot();
856 QwtPlotGrid* grid = new QwtPlotGrid;
857 grid->enableX(false);
858 grid->enableY(true);
859 grid->enableXMin(false);
860 grid->enableYMin(false);
861 grid->setMajPen(QPen(Qt::black, 0, Qt::DotLine));
862 grid->attach(plot);
863 plot->setAutoReplot(true);
864 string title = tableName;
865 plot->setAxisScaleDraw( QwtPlot::xBottom, new TimeScaleDraw());
866
867 QWidget window;
868 QHBoxLayout* layout = new QHBoxLayout(&window);
869 layout->setContentsMargins(0,0,0,0);
870 layout->addWidget(plot);
871
872 QwtPlotZoomer zoom(plot->canvas());
873 zoom.setRubberBandPen(QPen(Qt::gray, 2, Qt::DotLine));
874 zoom.setTrackerPen(QPen(Qt::gray));
875 int totalSize = 0;
876 for (unsigned int i=0;i<list.size();i++)
877 totalSize += ranges[i].second - ranges[i].first;
878 cout << "Total size: " << totalSize << endl;
879 vector<QwtPlotCurve*> curves(totalSize);
880 int ii=0;
881 for (auto it = curves.begin(), jt=curvesNames.begin(); it != curves.end(); it++, jt++)
882 {
883 *it = new QwtPlotCurve(jt->c_str());
884 switch (ii%6)
885 {
886 case 0:
887 (*it)->setPen(QColor(255,0,0));
888 break;
889 case 1:
890 (*it)->setPen(QColor(0,255,0));
891 break;
892 case 2:
893 (*it)->setPen(QColor(0,0,255));
894 break;
895 case 3:
896 (*it)->setPen(QColor(255,255,0));
897 break;
898 case 4:
899 (*it)->setPen(QColor(0,255,255));
900 break;
901 case 5:
902 (*it)->setPen(QColor(255,0,255));
903 break;
904 default:
905 (*it)->setPen(QColor(0,0,0));
906 };
907 ii++;
908 (*it)->setStyle(QwtPlotCurve::Lines);
909 (*it)->attach(plot);
910 }
911 plot->insertLegend(new QwtLegend(), QwtPlot::RightLegend);
912
913 const vector<int> offsets = CalculateOffsets();
914 if (offsets.size()==0)
915 return false;
916
917
918 // Loop over all columns in our list of requested columns
919 vector<MyColumn*> columns;
920 for (vector<string>::const_iterator it=listNamesOnly.begin(); it!=listNamesOnly.end(); it++)
921 {
922 MyColumn *cCol = static_cast<MyColumn*>(fColMap.find(*it)->second);
923 columns.push_back(cCol);
924 }
925 //add the time column to the given columns
926 MyColumn* timeCol = static_cast<MyColumn*>(fColMap.find("Time")->second);
927 if (!timeCol)
928 {
929 cerr << "Error: time column could not be found in given table. Aborting" << endl;
930 return false;
931 }
932 columns.push_back(timeCol);
933 ranges.push_back(make_pair(0,1));
934 /////
935 const int size = offsets[offsets.size()-1];
936 unsigned char* fitsBuffer = new unsigned char[size];
937
938// stringstream str;
939 str.str("");
940 int status = 0;
941
942 vector<double*> xValues(totalSize);
943 double* yValues;
944 cout.precision(10);
945 str.precision(20);
946 for (auto it=xValues.begin(); it!=xValues.end(); it++)
947 *it = new double[fTable->rows()];
948
949 yValues = new double[fTable->rows()];
950
951 for (int i=1; i<=fTable->rows(); i++)
952 {
953 fits_read_tblbytes(fFile->fitsPointer(), i, 1, size, fitsBuffer, &status);
954 if (status)
955 {
956 cerr << "An error occurred while reading fits row #" << i << " error code: " << status << endl;
957 break;
958 }
959 if (WriteRow(str, columns, offsets, fitsBuffer, ranges)<0)
960 {
961 status=1;
962 cerr << "An Error occured while reading the fits row " << i << endl;
963 return -1;
964 }
965// yValues[i-1] = i;
966 for (auto it=xValues.begin(); it!= xValues.end(); it++)
967 {
968 str >> (*it)[i-1];
969 cout << (*it)[i-1] << " ";
970 }
971 str >> yValues[i-1];
972 if (i==1)
973 {
974 Time t(yValues[0]);
975 title += " - " + t.GetAsStr("%Y-%m-%d");
976 plot->setTitle(title.c_str());
977 }
978 cout << yValues[i-1] << " ";
979 cout << endl;
980 }
981 //set the actual data.
982 auto jt = xValues.begin();
983 for (auto it=curves.begin(); it != curves.end(); it++, jt++)
984 (*it)->setRawData(yValues, *jt, fTable->rows());
985
986 QStack<QRectF> stack;
987 double minX, minY, maxX, maxY;
988 minX = minY = 1e10;
989 maxX = maxY = -1e10;
990 QRectF rect;
991 QPointF point;
992 for (auto it=curves.begin(); it!= curves.end(); it++)
993 {
994 rect = (*it)->boundingRect();
995 point = rect.bottomRight();
996 if (point.x() < minX) minX = point.x();
997 if (point.y() < minY) minY = point.y();
998 if (point.x() > maxX) maxX = point.x();
999 if (point.y() > maxY) maxY = point.y();
1000 point = rect.topLeft();
1001 if (point.x() < minX) minX = point.x();
1002 if (point.y() < minY) minY = point.y();
1003 if (point.x() > maxX) maxX = point.x();
1004 if (point.y() > maxY) maxY = point.y();
1005 }
1006 QPointF bottomRight(maxX, minY);
1007 QPointF topLeft(minX, maxY);
1008 QPointF center((bottomRight+topLeft)/2.f);
1009 stack.push(QRectF(topLeft + (topLeft-center)*(.5f),bottomRight + (bottomRight-center)*(.5f)));
1010 zoom.setZoomStack(stack);
1011
1012 delete[] fitsBuffer;
1013 window.resize(600, 400);
1014 window.show();
1015
1016 a.exec();
1017
1018 for (auto it = curves.begin(); it != curves.end(); it++)
1019 delete *it;
1020 for (auto it = xValues.begin(); it != xValues.end(); it++)
1021 delete[] *it;
1022 delete[] yValues;
1023 delete[] handle;
1024 return 0;
1025}
1026#else
1027int FitsDumper::doCurvesDisplay( const vector<string> &list, const string& tableName)
1028{
1029 cerr << "Sorry, but plotting features seem to have been disabled at compilation time." << endl;
1030 cerr << "Please recompile with PLOTTING_PLEASE defined and try again." << endl;
1031 return 0;
1032}
1033#endif
1034void SetupConfiguration(Configuration& conf)
1035{
1036 po::options_description configs("Fitsdump options");
1037 configs.add_options()
1038 ("fitsfile,f", var<string>()
1039#if BOOST_VERSION >= 104200
1040 ->required()
1041#endif
1042 , "Name of FITS file")
1043 ("tablename,t", var<string>("DATA")
1044#if BOOST_VERSION >= 104200
1045 ->required()
1046#endif
1047 , "Name of input table")
1048 ("col,c", vars<string>(), "List of columns to dump")
1049 ("outfile,o", var<string>("/dev/stdout"), "Name of output file (-:/dev/stdout)")
1050 ("precision,p", var<int>(20), "Precision of ofstream")
1051 ("list,l", po_switch(), "List all tables and columns in file")
1052 ("header,h", po_switch(), "Dump header of given table")
1053 ("graph,g", po_switch(), "Plot the columns instead of dumping them")
1054 ;
1055
1056 po::positional_options_description p;
1057 p.add("fitsfile", 1); // The first positional options
1058 p.add("col", -1); // All others
1059
1060 conf.AddOptions(configs);
1061 conf.SetArgumentPositions(p);
1062}
1063
1064int main(int argc, const char** argv)
1065{
1066 Configuration conf(argv[0]);
1067 conf.SetPrintUsage(PrintUsage);
1068 SetupConfiguration(conf);
1069
1070 if (!conf.DoParse(argc, argv, PrintHelp))
1071 return -1;
1072
1073 FitsDumper loader;
1074 return loader.ExecConfig(conf);
1075}
Note: See TracBrowser for help on using the repository browser.