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

Last change on this file since 16991 was 16964, checked in by lyard, 11 years ago
replaced fits with fact fits to be able to read compressed files
File size: 28.2 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);
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) : factfits(fname, "Events"), 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#ifdef HAVE_ROOT
926 ("root,r", po_switch(), "Enable root mode")
927 ("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)")
928#endif
929 ;
930
931 po::positional_options_description p;
932 p.add("fitsfile", 1); // The first positional options
933 p.add("col", -1); // All others
934
935 conf.AddOptions(configs);
936 conf.SetArgumentPositions(p);
937}
938
939int main(int argc, const char** argv)
940{
941 Configuration conf(argv[0]);
942 conf.SetPrintUsage(PrintUsage);
943 SetupConfiguration(conf);
944
945 if (!conf.DoParse(argc, argv, PrintHelp))
946 return -1;
947
948 if (!conf.Has("fitsfile"))
949 {
950 cerr << "Filename required." << endl;
951 return -1;
952 }
953
954 FitsDumper loader(conf.Get<string>("fitsfile"));
955 if (!loader)
956 {
957 cerr << "ERROR - Opening " << conf.Get<string>("fitsfile");
958 cerr << " failed: " << strerror(errno) << endl;
959 return -1;
960 }
961
962 return loader.Exec(conf);
963}
Note: See TracBrowser for help on using the repository browser.