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

Last change on this file since 17051 was 17000, checked in by lyard, 11 years ago
added option to load appropriate table among several ones in a single file
File size: 28.4 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 <float.h>
11
12#include <map>
13#include <fstream>
14
15#include <boost/regex.hpp>
16
17#include "Time.h"
18#include "externals/factfits.h"
19
20#ifdef HAVE_ROOT
21#include "TFormula.h"
22#endif
23
24using namespace std;
25
26struct MyColumn
27{
28 string name;
29
30 fits::Table::Column col;
31
32 uint32_t first;
33 uint32_t last;
34
35 void *ptr;
36};
37
38struct minMaxStruct
39{
40 double min;
41 double max;
42 long double average;
43 long double squared;
44 long numValues;
45 minMaxStruct() : min(FLT_MAX), max(-FLT_MAX), average(0), squared(0), numValues(0) { }
46
47 void add(double val)
48 {
49 average += val;
50 squared += val*val;
51
52 if (val<min)
53 min = val;
54
55 if (val>max)
56 max = val;
57
58 numValues++;
59 }
60};
61
62
63class FitsDumper : public factfits
64{
65private:
66 string fFilename;
67
68 // Convert CCfits::ValueType into a human readable string
69 string ValueTypeToStr(char type) const;
70
71 /// Lists all columns of an open file
72 void List();
73 void ListHeader(const string& filename);
74 void ListKeywords(ostream &);
75
76 vector<MyColumn> InitColumns(vector<string> list);
77 vector<MyColumn> InitColumnsRoot(vector<string> &list);
78
79 double GetDouble(const MyColumn &, size_t) const;
80
81 ///Display the selected columns values VS time
82 void Dump(ofstream &, const vector<MyColumn> &, const string &, size_t, size_t, const string &);
83 void DumpRoot(ofstream &, const vector<string> &, const string &, size_t, size_t, const string &);
84 void DumpMinMax(ofstream &, const vector<MyColumn> &, size_t, size_t, bool);
85 void DumpStats(ofstream &, const vector<MyColumn> &, size_t, size_t);
86
87public:
88 FitsDumper(const string &fname, const string &tablename);
89
90 ///Configures the fitsLoader from the config file and/or command arguments.
91 int Exec(Configuration& conf);
92};
93
94// --------------------------------------------------------------------------
95//
96//! Constructor
97//! @param out
98//! the ostream where to redirect the outputs
99//
100FitsDumper::FitsDumper(const string &fname, const string &tablename) : factfits(fname, tablename), fFilename(fname)
101{
102}
103
104string FitsDumper::ValueTypeToStr(char type) const
105{
106 switch (type)
107 {
108 case 'L': return "bool(8)";
109 case 'A': return "char(8)";
110 case 'B': return "byte(8)";
111 case 'I': return "short(16)";
112 case 'J': return "int(32)";
113 case 'K': return "int(64)";
114 case 'E': return "float(32)";
115 case 'D': return "double(64)";
116 default:
117 return "unknown";
118 }
119}
120
121void FitsDumper::List()
122{
123 const fits::Table::Keys &fKeyMap = GetKeys();
124 const fits::Table::Columns &fColMap = GetColumns();
125
126 cout << "\nFile: " << fFilename << "\n";
127
128 cout << " " << fKeyMap.find("EXTNAME")->second.value << " [";
129 cout << fKeyMap.find("NAXIS2")->second.value << "]\n";
130
131 for (auto it = fColMap.begin(); it != fColMap.end(); it++)
132 {
133 cout << " " << it->first << "[" << it->second.num << "] (" << it->second.unit << ":" << ValueTypeToStr(it->second.type) << ") ";
134 for (auto jt = fKeyMap.begin(); jt != fKeyMap.end(); jt++)
135 if (jt->second.value == it->first)
136 cout << "/ " << jt->second.comment << endl;
137 }
138
139 cout << endl;
140}
141
142void FitsDumper::ListKeywords(ostream &fout)
143{
144 const fits::Table::Keys &fKeyMap = GetKeys();
145
146 for (auto it=fKeyMap.begin(); it != fKeyMap.end(); it++)
147 {
148 fout << "## " << ::left << setw(8) << it->first << "= ";
149
150 if (it->second.type=='T')
151 fout << ::left << setw(20) << ("'"+it->second.value+"'");
152 else
153 fout << ::right << setw(20) << it->second.value;
154
155 if (!it->second.comment.empty())
156 fout << " / " << it->second.comment;
157 fout << '\n';
158 }
159
160 fout << flush;
161}
162
163void FitsDumper::ListHeader(const string& filename)
164{
165 ofstream fout(filename=="-"?"/dev/stdout":filename);
166 if (!fout)
167 {
168 cerr << "Cannot open file " << filename << ": " << strerror(errno) << endl;
169 return;
170 }
171
172 const fits::Table::Keys &fKeyMap = GetKeys();
173
174 fout << "\nTable: " << fKeyMap.find("EXTNAME")->second.value << " (rows=" << fKeyMap.find("NAXIS2")->second.value << ")\n";
175 if (fKeyMap.find("COMMENT") != fKeyMap.end())
176 fout << "Comment: \t" << fKeyMap.find("COMMENT")->second.value << "\n";
177
178 ListKeywords(fout);
179 fout << endl;
180}
181
182vector<MyColumn> FitsDumper::InitColumns(vector<string> names)
183{
184 static const boost::regex expr("([[:word:].]+)(\\[([[:digit:]]+)?(:)?([[:digit:]]+)?\\])?");
185
186 const fits::Table::Columns &fColMap = GetColumns();
187
188 if (names.empty())
189 for (auto it=fColMap.begin(); it!=fColMap.end(); it++)
190 if (it->second.num>0)
191 names.push_back(it->first);
192
193 vector<MyColumn> vec;
194
195 for (auto it=names.begin(); it!=names.end(); it++)
196 {
197 boost::smatch what;
198 if (!boost::regex_match(*it, what, expr, boost::match_extra))
199 {
200 cerr << "Couldn't parse expression '" << *it << "' " << endl;
201 return vector<MyColumn>();
202 }
203
204 const string name = what[1];
205
206 const auto iter = fColMap.find(name);
207 if (iter==fColMap.end())
208 {
209 cerr << "ERROR - Column '" << name << "' not found in table." << endl;
210 return vector<MyColumn>();
211 }
212
213 const fits::Table::Column &col = iter->second;
214
215 const string val0 = what[3];
216 const string delim = what[4];
217 const string val1 = what[5];
218
219 const uint32_t first = atol(val0.c_str());
220 const uint32_t last = (val0.empty() && delim.empty()) ? col.num-1 : (val1.empty() ? first : atoi(val1.c_str()));
221
222 if (first>=col.num)
223 {
224 cerr << "ERROR - First index " << first << " for column " << name << " exceeds number of elements " << col.num << endl;
225 return vector<MyColumn>();
226 }
227
228 if (last>=col.num)
229 {
230 cerr << "ERROR - Last index " << last << " for column " << name << " exceeds number of elements " << col.num << endl;
231 return vector<MyColumn>();
232 }
233
234 if (first>last)
235 {
236 cerr << "ERROR - Last index " << last << " for column " << name << " exceeds first index " << first << endl;
237 return vector<MyColumn>();
238 }
239
240 MyColumn mycol;
241
242 mycol.name = name;
243 mycol.col = col;
244 mycol.first = first;
245 mycol.last = last;
246 mycol.ptr = SetPtrAddress(name);
247
248 vec.push_back(mycol);
249 }
250
251 return vec;
252}
253
254double FitsDumper::GetDouble(const MyColumn &it, size_t i) const
255{
256 switch (it.col.type)
257 {
258 case 'A':
259 return reinterpret_cast<const char*>(it.ptr)[i];
260
261 case 'L':
262 return reinterpret_cast<const bool*>(it.ptr)[i];
263
264 case 'B':
265 return (unsigned int)reinterpret_cast<const uint8_t*>(it.ptr)[i];
266
267 case 'I':
268 return reinterpret_cast<const int16_t*>(it.ptr)[i];
269
270 case 'J':
271 return reinterpret_cast<const int32_t*>(it.ptr)[i];
272
273 case 'K':
274 return reinterpret_cast<const int64_t*>(it.ptr)[i];
275
276 case 'E':
277 return reinterpret_cast<const float*>(it.ptr)[i];
278
279 case 'D':
280 return reinterpret_cast<const double*>(it.ptr)[i];
281 }
282
283 return 0;
284}
285
286// --------------------------------------------------------------------------
287//
288//! Perform the actual dump, based on the current parameters
289//
290void FitsDumper::Dump(ofstream &fout, const vector<MyColumn> &cols, const string &filter, size_t first, size_t limit, const string &filename)
291{
292 const fits::Table::Keys &fKeyMap = GetKeys();
293
294#ifdef HAVE_ROOT
295 TFormula select;
296 if (!filter.empty() && select.Compile(filter.c_str()))
297 throw runtime_error("Syntax Error: TFormula::Compile failed for '"+filter+"'");
298#endif
299
300 fout << "## --------------------------------------------------------------------------\n";
301 fout << "## Fits file: \t" << fFilename << '\n';
302 if (filename!="-")
303 fout << "## File: \t" << filename << '\n';
304 fout << "## Table: \t" << fKeyMap.find("EXTNAME")->second.value << '\n';
305 fout << "## NumRows: \t" << GetInt("NAXIS2") << '\n';
306 fout << "## Comment: \t" << ((fKeyMap.find("COMMENT") != fKeyMap.end()) ? fKeyMap.find("COMMENT")->second.value : "") << '\n';
307#ifdef HAVE_ROOT
308 if (!filter.empty())
309 fout << "## Selection: \t" << select.GetExpFormula() << '\n';
310#endif
311 fout << "## --------------------------------------------------------------------------\n";
312 ListKeywords(fout);
313 fout << "## --------------------------------------------------------------------------\n";
314 fout << "#\n";
315
316 size_t num = 0;
317 for (auto it=cols.begin(); it!=cols.end(); it++)
318 {
319 fout << "# " << it->name;
320
321 if (it->first==it->last)
322 {
323 if (it->first!=0)
324 fout << "[" << it->first << "]";
325 }
326 else
327 fout << "[" << it->first << ":" << it->last << "]";
328
329 if (!it->col.unit.empty())
330 fout << ": " << it->col.unit;
331 fout << '\n';
332
333 num += it->last-it->first+1;
334 }
335 fout << "#" << endl;
336
337 // -----------------------------------------------------------------
338
339#ifdef HAVE_ROOT
340 vector<Double_t> data(num+1);
341#endif
342
343 const size_t last = limit ? first + limit : size_t(-1);
344
345 while (GetRow(first++))
346 {
347 const size_t row = GetRow();
348 if (row==GetNumRows() || row==last)
349 break;
350
351 size_t p = 0;
352
353#ifdef HAVE_ROOT
354 data[p++] = first-1;
355#endif
356
357 ostringstream sout;
358 sout.precision(fout.precision());
359 for (auto it=cols.begin(); it!=cols.end(); it++)
360 {
361 string msg;
362 for (uint32_t i=it->first; i<=it->last; i++, p++)
363 {
364 switch (it->col.type)
365 {
366 case 'A':
367 msg += reinterpret_cast<const char*>(it->ptr)[i];
368 break;
369 case 'B':
370 sout << (unsigned int)reinterpret_cast<const unsigned char*>(it->ptr)[i] << " ";
371 break;
372 case 'L':
373 sout << reinterpret_cast<const bool*>(it->ptr)[i] << " ";
374 break;
375 case 'I':
376 sout << reinterpret_cast<const int16_t*>(it->ptr)[i] << " ";
377 break;
378 case 'J':
379 sout << reinterpret_cast<const int32_t*>(it->ptr)[i] << " ";
380 break;
381 case 'K':
382 sout << reinterpret_cast<const int64_t*>(it->ptr)[i] << " ";
383 break;
384 case 'E':
385 sout << reinterpret_cast<const float*>(it->ptr)[i] << " ";
386 break;
387 case 'D':
388 sout << reinterpret_cast<const double*>(it->ptr)[i] << " ";
389 break;
390 default:
391 ;
392 }
393
394#ifdef HAVE_ROOT
395 if (!filter.empty())
396 data[p] = GetDouble(*it, i);
397#endif
398 }
399
400 if (it->col.type=='A')
401 sout << "'" << msg.c_str() << "' ";
402 }
403#ifdef HAVE_ROOT
404 if (!filter.empty() && select.EvalPar(0, data.data())<0.5)
405 continue;
406#endif
407 fout << sout.str() << endl;
408 }
409}
410
411vector<MyColumn> FitsDumper::InitColumnsRoot(vector<string> &names)
412{
413 static const boost::regex expr("[^\\[]([[:word:].]+)(\\[([[:digit:]]+)\\])?");
414
415 const fits::Table::Columns &cols = GetColumns();
416
417 vector<MyColumn> vec;
418
419 for (auto it=names.begin(); it!=names.end(); it++)
420 {
421 if (it->empty())
422 continue;
423
424 *it = ' '+*it;
425
426 string::const_iterator ibeg = it->begin();
427 string::const_iterator iend = it->end();
428
429 boost::smatch what;
430 while (boost::regex_search(ibeg, iend, what, expr, boost::match_extra))
431 {
432 const string all = what[0];
433 const string name = what[1];
434 const size_t idx = atol(string(what[3]).c_str());
435
436 // Check if found colum is valid
437 const auto ic = cols.find(name);
438 if (ic==cols.end())
439 {
440 ibeg++;
441 //cout << "Column '" << name << "' does not exist." << endl;
442 //return vector<MyColumn>();
443 continue;
444 }
445 if (idx>=ic->second.num)
446 {
447 cout << "Column '" << name << "' has no index " << idx << "." << endl;
448 return vector<MyColumn>();
449 }
450
451 // find index if column already exists
452 size_t p = 0;
453 for (; p<vec.size(); p++)
454 if (vec[p].name==name)
455 break;
456
457 ostringstream id;
458 id << '[' << p << ']';
459
460 it->replace(ibeg-it->begin()+what.position(1), what.length()-1, id.str());
461
462 ibeg = what[0].first+3;
463 iend = it->end();
464
465 if (p<vec.size())
466 continue;
467
468 // Column not found, add new column
469 MyColumn mycol;
470
471 mycol.name = name;
472 mycol.col = ic->second;
473 mycol.first = idx;
474 mycol.last = idx;
475 mycol.ptr = SetPtrAddress(name);
476
477 vec.push_back(mycol);
478 }
479 }
480
481 ostringstream id;
482 id << '[' << vec.size() << ']';
483
484 for (auto it=names.begin(); it!=names.end(); it++)
485 {
486 while (1)
487 {
488 auto p = it->find_first_of('#');
489 if (p==string::npos)
490 break;
491
492 it->replace(p, 1, id.str());
493 }
494 }
495
496 //cout << endl;
497 //for (size_t i=0; i<vec.size(); i++)
498 // cout << "val[" << i << "] = " << vec[i].name << '[' << vec[i].first << ']' << endl;
499 //cout << endl;
500
501 return vec;
502}
503
504void FitsDumper::DumpRoot(ofstream &fout, const vector<string> &cols, const string &filter, size_t first, size_t limit, const string &filename)
505{
506#ifdef HAVE_ROOT
507 vector<string> names(cols);
508 names.insert(names.begin(), filter);
509
510 const vector<MyColumn> vec = InitColumnsRoot(names);
511 if (vec.empty())
512 return;
513
514 vector<TFormula> form(names.size());
515
516 auto ifo = form.begin();
517 for (auto it=names.begin(); it!=names.end(); it++, ifo++)
518 {
519 if (!it->empty() && ifo->Compile(it->c_str()))
520 throw runtime_error("Syntax Error: TFormula::Compile failed for '"+*it+"'");
521 }
522
523 const fits::Table::Keys &fKeyMap = GetKeys();
524
525 fout << "## --------------------------------------------------------------------------\n";
526 fout << "## Fits file: \t" << fFilename << '\n';
527 if (filename!="-")
528 fout << "## File: \t" << filename << '\n';
529 fout << "## Table: \t" << fKeyMap.find("EXTNAME")->second.value << '\n';
530 fout << "## NumRows: \t" << GetInt("NAXIS2") << '\n';
531 fout << "## Comment: \t" << ((fKeyMap.find("COMMENT") != fKeyMap.end()) ? fKeyMap.find("COMMENT")->second.value : "") << '\n';
532 fout << "## --------------------------------------------------------------------------\n";
533 ListKeywords(fout);
534 fout << "## --------------------------------------------------------------------------\n";
535 fout << "##\n";
536 if (!filter.empty())
537 fout << "## Selection: " << form[0].GetExpFormula() << "\n##\n";
538
539 size_t num = 0;
540 for (auto it=vec.begin(); it!=vec.end(); it++, num++)
541 {
542 fout << "## [" << num << "] = " << it->name;
543
544 if (it->first==it->last)
545 {
546 if (it->first!=0)
547 fout << "[" << it->first << "]";
548 }
549 else
550 fout << "[" << it->first << ":" << it->last << "]";
551
552 if (!it->col.unit.empty())
553 fout << ": " << it->col.unit;
554 fout << '\n';
555 }
556 fout << "##\n";
557 fout << "## --------------------------------------------------------------------------\n";
558 fout << "#\n";
559
560 fout << "# ";
561 for (auto it=form.begin()+1; it!=form.end(); it++)
562 fout << " \"" << it->GetExpFormula() << "\"";
563 fout << "\n#" << endl;
564
565 // -----------------------------------------------------------------
566
567 vector<Double_t> data(vec.size()+1);
568
569 const size_t last = limit ? first + limit : size_t(-1);
570
571 while (GetRow(first++))
572 {
573 const size_t row = GetRow();
574 if (row==GetNumRows() || row==last)
575 break;
576
577 size_t p = 0;
578 for (auto it=vec.begin(); it!=vec.end(); it++, p++)
579 data[p] = GetDouble(*it, it->first);
580
581 data[p] = first;
582
583 if (!filter.empty() && form[0].EvalPar(0, data.data())<0.5)
584 continue;
585
586 for (auto iform=form.begin()+1; iform!=form.end(); iform++)
587 fout << iform->EvalPar(0, data.data()) << " ";
588
589 fout << endl;
590 }
591#endif
592}
593
594void FitsDumper::DumpMinMax(ofstream &fout, const vector<MyColumn> &cols, size_t first, size_t limit, bool fNoZeroPlease)
595{
596 vector<minMaxStruct> statData(cols.size());
597
598 // Loop over all columns in our list of requested columns
599 const size_t last = limit ? first + limit : size_t(-1);
600
601 while (GetRow(first++))
602 {
603 const size_t row = GetRow();
604 if (row==GetNumRows() || row==last)
605 break;
606
607 auto statsIt = statData.begin();
608
609 for (auto it=cols.begin(); it!=cols.end(); it++, statsIt++)
610 {
611 if ((it->name=="UnixTimeUTC" || it->name=="PCTime") && it->first==0 && it->last==1)
612 {
613 const uint32_t *val = reinterpret_cast<const uint32_t*>(it->ptr);
614 if (fNoZeroPlease && val[0]==0 && val[1]==0)
615 continue;
616
617 statsIt->add(Time(val[0], val[1]).Mjd());
618 continue;
619 }
620
621 for (uint32_t i=it->first; i<=it->last; i++)
622 {
623 const double cValue = GetDouble(*it, i);
624
625 if (fNoZeroPlease && cValue == 0)
626 continue;
627
628 statsIt->add(cValue);
629 }
630 }
631 }
632
633 // okay. So now I've got ALL the data, loaded.
634 // let's do the summing and averaging in a safe way (i.e. avoid overflow
635 // of variables as much as possible)
636 auto statsIt = statData.begin();
637 for (auto it=cols.begin(); it!=cols.end(); it++, statsIt++)
638 {
639 fout << "\n[" << it->name << ':' << it->first;
640 if (it->first!=it->last)
641 fout << ':' << it->last;
642 fout << "]\n";
643
644 if (statsIt->numValues == 0)
645 {
646 fout << "Min: -\nMax: -\nAvg: -\nRms: -" << endl;
647 continue;
648 }
649
650 const long &num = statsIt->numValues;
651
652 long double &avg = statsIt->average;
653 long double &rms = statsIt->squared;
654
655 avg /= num;
656 rms = sqrt(rms/num - avg*avg);
657
658 fout << "Min: " << statsIt->min << '\n';
659 fout << "Max: " << statsIt->max << '\n';
660 fout << "Avg: " << avg << '\n';
661 fout << "Rms: " << rms << endl;
662 }
663}
664
665template<typename T>
666void displayStats(vector<char> &array, ofstream& out)
667{
668 const size_t numElems = array.size()/sizeof(T);
669 if (numElems == 0)
670 {
671 out << "Min: -\nMax: -\nMed: -\nAvg: -\nRms: -" << endl;
672 return;
673 }
674
675 T *val = reinterpret_cast<T*>(array.data());
676
677 sort(val, val+numElems);
678
679 out << "Min: " << double(val[0]) << '\n';
680 out << "Max: " << double(val[numElems-1]) << '\n';
681
682 if (numElems>2)
683 {
684 if (numElems%2 == 0)
685 out << "Med: " << (double(val[numElems/2]) + double(val[numElems/2+1]))/2 << '\n';
686 else
687 out << "Med: " << double(val[numElems/2+1]) << '\n';
688 }
689
690 long double avg = 0;
691 long double rms = 0;
692 for (uint32_t i=0;i<numElems;i++)
693 {
694 avg += double(val[i]);
695 rms += double(val[i])*double(val[i]);
696 }
697
698 avg /= numElems;
699 rms = sqrt(rms/numElems - avg*avg);
700
701 out << "Avg: " << avg << '\n';
702 out << "Rms: " << rms << endl;
703
704}
705
706void FitsDumper::DumpStats(ofstream &fout, const vector<MyColumn> &cols, size_t first, size_t limit)
707{
708 // Loop over all columns in our list of requested columns
709 vector<vector<char>> statData;
710
711 const size_t num = limit==0 || GetNumRows()<limit ? GetNumRows() : limit;
712
713 for (auto it=cols.begin(); it!=cols.end(); it++)
714 statData.push_back(vector<char>(it->col.size*num*(it->last-it->first+1)));
715
716 // Loop over all columns in our list of requested columns
717 const size_t last = limit ? first + limit : size_t(-1);
718
719 while (GetRow(first++))
720 {
721 const size_t row = GetRow();
722 if (row==GetNumRows() || row==last)
723 break;
724
725
726 auto statsIt = statData.begin();
727 for (auto it=cols.begin(); it!=cols.end(); it++, statsIt++)
728 {
729 const char *src = reinterpret_cast<const char*>(it->ptr);
730 const size_t sz = (it->last-it->first+1)*it->col.size;
731 memcpy(statsIt->data()+row*sz, src+it->first*it->col.size, sz);
732 }
733 }
734
735 auto statsIt = statData.begin();
736 for (auto it=cols.begin(); it!=cols.end(); it++, statsIt++)
737 {
738 fout << "\n[" << it->name << ':' << it->first;
739 if (it->last!=it->first)
740 fout << ':' << it->last;
741 fout << "]\n";
742
743 switch (it->col.type)
744 {
745 case 'L':
746 displayStats<bool>(*statsIt, fout);
747 break;
748 case 'B':
749 displayStats<char>(*statsIt, fout);
750 break;
751 case 'I':
752 displayStats<int16_t>(*statsIt, fout);
753 break;
754 case 'J':
755 displayStats<int32_t>(*statsIt, fout);
756 break;
757 case 'K':
758 displayStats<int64_t>(*statsIt, fout);
759 break;
760 case 'E':
761 displayStats<float>(*statsIt, fout);
762 break;
763 case 'D':
764 displayStats<double>(*statsIt, fout);
765 break;
766 default:
767 ;
768 }
769 }
770}
771
772// --------------------------------------------------------------------------
773//
774//! Retrieves the configuration parameters
775//! @param conf
776//! the configuration object
777//
778int FitsDumper::Exec(Configuration& conf)
779{
780 if (conf.Get<bool>("list"))
781 List();
782
783 if (conf.Get<bool>("header"))
784 ListHeader(conf.Get<string>("outfile"));
785
786
787 if (conf.Get<bool>("header") || conf.Get<bool>("list"))
788 return 1;
789
790 // ------------------------------------------------------------
791
792 if (conf.Get<bool>("minmax") && conf.Get<bool>("stat"))
793 {
794 cerr << "Invalid combination of options: cannot do stats and minmax. Aborting" << endl;
795 return -1;
796 }
797 if (conf.Get<bool>("stat") && conf.Get<bool>("nozero"))
798 {
799 cerr << "Invalid combination of options: nozero only works with minmax. Aborting" << endl;
800 return -1;
801 }
802
803 // ------------------------------------------------------------
804
805 const string filename = conf.Get<string>("outfile");
806
807 ofstream fout(filename=="-"?"/dev/stdout":filename);
808 if (!fout)
809 {
810 cerr << "Cannot open file " << filename << ": " << strerror(errno) << endl;
811 return false;
812 }
813 fout.precision(conf.Get<int>("precision"));
814
815 const string filter = conf.Has("filter") ? conf.Get<string>("filter") : "";
816
817 const size_t first = conf.Get<size_t>("first");
818 const size_t limit = conf.Get<size_t>("limit");
819
820#ifdef HAVE_ROOT
821 if (conf.Get<bool>("root"))
822 {
823 DumpRoot(fout, conf.Vec<string>("col"), filter, first, limit, filename);
824 return 0;
825 }
826#endif
827
828 const vector<MyColumn> cols = InitColumns(conf.Vec<string>("col"));
829 if (cols.empty())
830 return false;
831
832
833 if (conf.Get<bool>("minmax"))
834 {
835 DumpMinMax(fout, cols, first, limit, conf.Get<bool>("nozero"));
836 return 0;
837 }
838
839 if (conf.Get<bool>("stat"))
840 {
841 DumpStats(fout, cols, first, limit);
842 return 0;
843 }
844
845 Dump(fout, cols, filter, first, limit, filename);
846
847 return 0;
848}
849
850void PrintUsage()
851{
852 cout <<
853 "fitsdump is a tool to dump data from a FITS table as ascii.\n"
854 "\n"
855 "Usage: fitsdump [OPTIONS] fitsfile col col ... \n"
856 " or: fitsdump [OPTIONS]\n"
857 "\n"
858 "Addressing a column:\n"
859 " ColumnName: Will address all fields of a column\n"
860 " ColumnName[n]: Will address the n-th field of a column (starts with 0)\n"
861 " ColumnName[n1:n2]: Will address all fields between n1 and including n2\n"
862#ifdef HAVE_ROOT
863 "\n"
864 "Selecting a column:\n"
865 " Commandline option: --filter\n"
866 " Explanation: Such a selection is evaluated using TFormula, hence, every "
867 "mathematical operation allowed in TFormula is allowed there, too. "
868 "The reference is the column index as printed in the output stream, "
869 "starting with 1. The index 0 is reserved for the row number.\n"
870#endif
871 ;
872 cout << endl;
873}
874
875void PrintHelp()
876{
877#ifdef HAVE_ROOT
878 cout <<
879 "\n\n"
880 "Examples:\n"
881 "In --root mode, fitsdump support TFormula's syntax for all columns and the filter "
882 "You can then refer to a column or a (single) index of the column just by its name "
883 "If the index is omitted, 0 is assumed. Note that the [x:y] syntax in this mode is "
884 "not supported\n"
885 "\n"
886 " fitsdump Zd --filter=\"[0]>20 && cos([1])*TMath::RadToDeg()<45\"\n"
887 "\n"
888 "The columns can also be addressed with their names\n"
889 "\n"
890 " fitsdump -r \"(Zd+Err)*TMath::DegToRad()\" --filter=\"[0]<25 && [1]<0.05\"\n"
891 "\n"
892 "is identical to\n"
893 "\n"
894 " fitsdump -r \"(Zd[0]+Err[0])*TMath::DegToRad()\" --filter=\"[0]<25 && [1]<0.05\"\n"
895 "\n"
896 "A special placeholder exists for the row number\n"
897 "\n"
898 " fitsdump -r \"#\" --filter=\"#>10 && #<100\"\n"
899 "\n";
900 cout << endl;
901#endif
902}
903
904
905void SetupConfiguration(Configuration& conf)
906{
907 po::options_description configs("Fitsdump options");
908 configs.add_options()
909 ("fitsfile,f", var<string>()
910#if BOOST_VERSION >= 104200
911 ->required()
912#endif
913 , "Name of FITS file")
914 ("col,c", vars<string>(), "List of columns to dump\narg is a list of columns, separated by a space.\nAdditionnally, a list of sub-columns can be added\ne.g. Data[3] will dump sub-column 3 of column Data\nData[3:4] will dump sub-columns 3 and 4\nOmitting this argument dump the entire column\nnota: all indices start at zero")
915 ("outfile,o", var<string>("-"), "Name of output file (-:/dev/stdout)")
916 ("precision,p", var<int>(20), "Precision of ofstream")
917 ("list,l", po_switch(), "List all tables and columns in file")
918 ("header,h", po_switch(), "Dump header of given table")
919 ("stat,s", po_switch(), "Perform statistics instead of dump")
920 ("minmax,m", po_switch(), "Calculates min and max of data")
921 ("nozero,z", po_switch(), "skip 0 values for stats")
922 ("force", po_switch(), "Force reading the fits file even if END key is missing")
923 ("first", var<size_t>(size_t(0)), "First number of row to read")
924 ("limit", var<size_t>(size_t(0)), "Limit for the maximum number of rows to read (0=unlimited)")
925 ("tablename,t", var<string>(""), "Name of the table to open. If not specified, first binary table is opened")
926#ifdef HAVE_ROOT
927 ("root,r", po_switch(), "Enable root mode")
928 ("filter,f", var<string>(""), "Filter to restrict the selection of events (e.g. '[0]>10 && [0]<20'; does not work with stat and minmax yet)")
929#endif
930 ;
931
932 po::positional_options_description p;
933 p.add("fitsfile", 1); // The first positional options
934 p.add("col", -1); // All others
935
936 conf.AddOptions(configs);
937 conf.SetArgumentPositions(p);
938}
939
940int main(int argc, const char** argv)
941{
942 Configuration conf(argv[0]);
943 conf.SetPrintUsage(PrintUsage);
944 SetupConfiguration(conf);
945
946 if (!conf.DoParse(argc, argv, PrintHelp))
947 return -1;
948
949 if (!conf.Has("fitsfile"))
950 {
951 cerr << "Filename required." << endl;
952 return -1;
953 }
954
955 FitsDumper loader(conf.Get<string>("fitsfile"), conf.Get<string>("tablename"));
956 if (!loader)
957 {
958 cerr << "ERROR - Opening " << conf.Get<string>("fitsfile");
959 cerr << " failed: " << strerror(errno) << endl;
960 return -1;
961 }
962
963 return loader.Exec(conf);
964}
Note: See TracBrowser for help on using the repository browser.