source: trunk/Mars/mcore/ofits.h @ 14792

Last change on this file since 14792 was 14792, checked in by lyard, 8 years ago
Added fits output for MC data
File size: 23.9 KB
Line 
1#ifndef MARS_ofits
2#define MARS_ofits
3
4#include <string>
5#include <string.h>
6#include <algorithm>
7#include <sstream>
8#include <iostream>
9#include <fstream>
10#include <iomanip>
11#include <vector>
12#include <algorithm>
13
14#ifdef __EXCEPTIONS
15#include <stdexcept>
16#endif
17
18#include "checksum.h"
19
20namespace std
21{
22// Sloppy:  allow / <--- left
23//          allow all characters (see specs for what is possible)
24
25// units: m kg s rad sr K A mol cd Hz J W V N Pa C Ohm S F Wb T Hlm lx
26
27class ofits : public ofstream
28{
29public:
30    struct Key
31    {
32        string key;
33        bool   delim;
34        string value;
35        string comment;
36
37        off_t offset;   // offset in file
38
39        bool changed;   // For closing the file
40
41        Key(const string &k="") : key(k), delim(false), offset(0), changed(true) { }
42
43        string Trim(const string &str)
44        {
45            // Trim Both leading and trailing spaces
46            const size_t first = str.find_first_not_of(' '); // Find the first character position after excluding leading blank spaces
47            const size_t last  = str.find_last_not_of(' ');  // Find the first character position from reverse af
48
49            // if all spaces or empty return an empty string
50            if (string::npos==first || string::npos==last)
51                return string();
52
53            return str.substr(first, last-first+1);
54        }
55
56        bool FormatKey()
57        {
58            key = Trim(key);
59            if (key.size()==0)
60            {
61#ifdef __EXCEPTIONS
62                throw runtime_error("Key name empty.");
63#else
64                gLog << ___err___ << "ERROR - Key name empty." << endl;
65                return false;
66#endif
67            }
68            if (key.size()>8)
69            {
70                ostringstream sout;
71                sout << "Key '" << key << "' exceeds 8 bytes.";
72#ifdef __EXCEPTIONS
73                throw runtime_error(sout.str());
74#else
75                gLog << ___err___ << "ERROR - " << sout.str() << endl;
76                return false;
77#endif
78            }
79
80            //transform(key.begin(), key.end(), key.begin(), toupper);
81
82            for (string::const_iterator c=key.begin(); c<key.end(); c++)
83                if ((*c<'A' || *c>'Z') && (*c<'0' || *c>'9') && *c!='-' && *c!='_')
84                {
85                    ostringstream sout;
86                    sout << "Invalid character '" << *c << "' found in key '" << key << "'";
87#ifdef __EXCEPTIONS
88                    throw runtime_error(sout.str());
89#else
90                    gLog << ___err___ << "ERROR - " << sout.str() << endl;
91                    return false;
92#endif
93                }
94
95            return true;
96        }
97
98        bool FormatComment()
99        {
100            comment = Trim(comment);
101
102            for (string::const_iterator c=key.begin(); c<key.end(); c++)
103                if (*c<32 || *c>126)
104                {
105                    ostringstream sout;
106                    sout << "Invalid character '" << *c << "' [" << int(*c) << "] found in comment '" << comment << "'";
107#ifdef __EXCEPTIONS
108                    throw runtime_error(sout.str());
109#else
110                    gLog << ___err___ << "ERROR - " << sout.str() << endl;
111                    return false;
112#endif
113                }
114
115            return true;
116        }
117
118        bool check()
119        {
120            if (!FormatKey())
121                return false;
122
123            if (!FormatComment())
124                return false;
125
126            const size_t sz = CalcSize();
127            if (sz>80)
128            {
129                ostringstream sout;
130                sout << "Size " << sz << " of entry for key '" << key << "' exceeds 80 characters.";
131#ifdef __EXCEPTIONS
132                throw runtime_error(sout.str());
133#else
134                gLog << ___err___ << "ERROR - " << sout.str() << endl;
135                return false;
136#endif
137            }
138
139            return true;
140        }
141
142        size_t CalcSize() const
143        {
144            if (!delim)
145                return 10+comment.size();
146
147            return 10 + (value.size()<20?20:value.size()) + 3 + comment.size();
148        }
149
150        string Compile()
151        {
152            ostringstream sout;
153            sout << std::left << setw(8) << key;
154
155            if (!delim)
156            {
157                sout << "  " << comment;
158                return sout.str();
159            }
160
161            sout << "= ";
162            sout << (value[0]=='\''?std::left:std::right);
163            sout << setw(20) << value << std::left;
164
165            if (comment.size()>0)
166                sout << " / " << comment;
167
168            return sout.str();
169        }
170
171        Checksum checksum;
172
173        void Out(ofstream &fout)
174        {
175            if (!changed)
176                return;
177
178            string str = Compile();
179            str.insert(str.end(), 80-str.size(), ' ');
180
181            if (offset==0)
182                offset = fout.tellp();
183
184            //cout << "Write[" << offset << "]: " << key << "/" << value << endl;
185
186            fout.seekp(offset);
187            fout << str;
188
189            checksum.reset();
190            checksum.add(str.c_str(), 80);
191
192            changed = false;
193        }
194        /*
195        void Out(ostream &out)
196        {
197            string str = Compile();
198
199            str.insert(str.end(), 80-str.size(), ' ');
200
201            out << str;
202            changed = false;
203        }*/
204    };
205
206private:
207    vector<Key> fKeys;
208
209    vector<Key>::iterator findkey(const string &key)
210    {
211        for (auto it=fKeys.begin(); it!=fKeys.end(); it++)
212            if (key==it->key)
213                return it;
214
215        return fKeys.end();
216    }
217
218    bool Set(const string &key="", bool delim=false, const string &value="", const string &comment="")
219    {
220        // If no delimit add the row no matter if it alread exists
221        if (delim)
222        {
223            // if the row already exists: update it
224            auto it = findkey(key);
225            if (it!=fKeys.end())
226            {
227                it->value   = value;
228                it->changed = true;
229                return true;
230            }
231        }
232
233        if (fTable.num_rows>0)
234        {
235            ostringstream sout;
236            sout << "No new header key can be defined, rows were already written to the file... ignoring new key '" << key << "'";
237#ifdef __EXCEPTIONS
238                throw runtime_error(sout.str());
239#else
240                gLog << ___err___ << "ERROR - " << sout.str() << endl;
241                return false;
242#endif
243        }
244
245        Key entry;
246
247        entry.key     = key;
248        entry.delim   = delim;
249        entry.value   = value;
250        entry.comment = comment;
251        entry.offset  = 0;
252        entry.changed = true;
253
254        if (!entry.check())
255        {//ETIENNE
256            //looks like something went wrong. Maybe entry is too long ?
257            //try to remove the comment
258            entry.comment = "";
259            if (!entry.check())
260                return false;
261            gLog << "WARNING: removed comment from over-sized entry " << key << endl;
262        }
263        fKeys.push_back(entry);
264        return true;
265    }
266
267    struct Table
268    {
269        off_t offset;
270
271        size_t bytes_per_row;
272        size_t num_rows;
273        size_t num_cols;
274
275        struct Column
276        {
277            string name;
278            size_t offset;
279            size_t num;
280            size_t size;
281            char   type;
282        };
283
284        vector<Column> cols;
285
286        Table() : offset(0), bytes_per_row(0), num_rows(0), num_cols(0)
287        {
288        }
289    };
290
291
292    Table fTable;
293
294    vector<char> fOutputBuffer;
295
296    vector<Table::Column>::iterator findcol(const string &name)
297    {
298        for (auto it=fTable.cols.begin(); it!=fTable.cols.end(); it++)
299            if (name==it->name)
300                return it;
301
302        return fTable.cols.end();
303    }
304
305    Checksum fDataSum;
306    Checksum fHeaderSum;
307
308public:
309    ofits()
310    {
311    }
312    ofits(const char *fname) : ofstream()
313    {
314        this->open(fname);
315    }
316    ~ofits() { close(); }
317
318    void open(const char * filename)
319    {
320        fDataSum  = 0;
321        fHeaderSum = 0;
322
323        fTable = Table();
324        fKeys.clear();
325
326        SetStr("XTENSION", "BINTABLE", "binary table extension");
327        SetInt("BITPIX",                     8, "8-bit bytes");
328        SetInt("NAXIS",                      2, "2-dimensional binary table");
329        SetInt("NAXIS1",                     0, "width of table in bytes");
330        SetInt("NAXIS2",                     0, "number of rows in table");
331        SetInt("PCOUNT",                     0, "size of special data area");
332        SetInt("GCOUNT",                     1, "one data group (required keyword)");
333        SetInt("TFIELDS",                    0, "number of fields in each row");
334        SetStr("EXTNAME", "", "name of extension table");
335        SetStr("CHECKSUM", "0000000000000000", "Checksum for the whole HDU");
336        SetStr("DATASUM",  "         0", "Checksum for the data block");
337
338        ofstream::open(filename);
339    }
340
341    bool SetRaw(const string &key, const string &val, const string &comment)
342    {
343        return Set(key, true, val, comment);
344    }
345
346    bool SetBool(const string &key, bool b, const string &comment="")
347    {
348        return Set(key, true, b?"T":"F", comment);
349    }
350
351    bool AddEmpty(const string &key, const string &comment="")
352    {
353        return Set(key, true, "", comment);
354    }
355
356    bool SetStr(const string &key, string s, const string &comment="")
357    {
358        for (string::iterator c=s.begin(); c<s.end(); c++)
359            if (*c=='\'')
360                s.insert(c++, '\'');
361
362        return Set(key, true, "'"+s+"'", comment);
363    }
364
365    bool SetInt(const string &key, int64_t i, const string &comment="")
366    {
367        ostringstream sout;
368        sout << i;
369
370        return Set(key, true, sout.str(), comment);
371    }
372
373    bool SetFloat(const string &key, double f, int p, const string &comment="")
374    {
375        ostringstream sout;
376
377        if (p<0)
378            sout << setprecision(-p) << fixed;
379        if (p>0)
380            sout << setprecision(p);
381        if (p==0)
382            sout << setprecision(f>1e-100 && f<1e100 ? 15 : 14);
383
384        sout << f;
385
386        string str = sout.str();
387
388        replace(str.begin(), str.end(), 'e', 'E');
389
390        if (str.find_first_of('E')==string::npos && str.find_first_of('.')==string::npos)
391            str += ".";
392
393        return Set(key, true, str, comment);
394    }
395
396    bool SetFloat(const string &key, double f, const string &comment="")
397    {
398        return SetFloat(key, f, 0, comment);
399    }
400
401    bool SetHex(const string &key, uint64_t i, const string &comment="")
402    {
403        ostringstream sout;
404        sout << std::hex << "0x" << i;
405        return SetStr(key, sout.str(), comment);
406    }
407
408    bool AddComment(const string &comment)
409    {
410        return Set("COMMENT", false, "", comment);
411    }
412
413    bool AddHistory(const string &comment)
414    {
415        return Set("HISTORY", false, "", comment);
416    }
417
418    void End()
419    {
420        Set("END");
421        while (fKeys.size()%36!=0)
422            fKeys.push_back(Key());
423    }
424
425    bool AddColumn(uint32_t cnt, char typechar, const string &name, const string &unit, const string &comment="")
426    {
427        if (tellp()<0)
428        {
429            ostringstream sout;
430            sout << "File not open... ignoring column '" << name << "'";
431#ifdef __EXCEPTIONS
432            throw runtime_error(sout.str());
433#else
434            gLog << ___err___ << "ERROR - " << sout.str() << endl;
435            return false;
436#endif
437        }
438
439        if (tellp()>0)
440        {
441            ostringstream sout;
442            sout << "Header already writtenm, no new column can be defined... ignoring column '" << name << "'";
443#ifdef __EXCEPTIONS
444            throw runtime_error(sout.str());
445#else
446            gLog << ___err___ << "ERROR - " << sout.str() << endl;
447            return false;
448#endif
449        }
450
451        if (findcol(name)!=fTable.cols.end())
452        {
453            ostringstream sout;
454            sout << "A column with the name '" << name << "' already exists.";
455#ifdef __EXCEPTIONS
456            throw runtime_error(sout.str());
457#else
458            gLog << ___err___ << "ERROR - " << sout.str() << endl;
459            return false;
460#endif
461        }
462
463        typechar = toupper(typechar);
464
465        static const string allow("LABIJKED");
466        if (std::find(allow.begin(), allow.end(), typechar)==allow.end())
467        {
468            ostringstream sout;
469            sout << "Column type '" << typechar << "' not supported.";
470#ifdef __EXCEPTIONS
471            throw runtime_error(sout.str());
472#else
473            gLog << ___err___ << "ERROR - " << sout.str() << endl;
474            return false;
475#endif
476        }
477
478        ostringstream type;
479        type << cnt << typechar;
480
481        fTable.num_cols++;
482
483        ostringstream typekey, formkey, unitkey, unitcom, typecom;
484        typekey << "TTYPE" << fTable.num_cols;
485        formkey << "TFORM" << fTable.num_cols;
486        unitkey << "TUNIT" << fTable.num_cols;
487        unitcom << "unit of " << name;
488
489        typecom << "format of " << name << " [";
490
491        switch (typechar)
492        {
493        case 'L': typecom << "1-byte BOOL]";  break;
494        case 'A': typecom << "1-byte CHAR]";  break;
495        case 'B': typecom << "1-byte BOOL]";  break;
496        case 'I': typecom << "2-byte INT]";   break;
497        case 'J': typecom << "4-byte INT]";   break;
498        case 'K': typecom << "8-byte INT]";   break;
499        case 'E': typecom << "4-byte FLOAT]"; break;
500        case 'D': typecom << "8-byte FLOAT]"; break;
501        }
502
503        SetStr(formkey.str(), type.str(), typecom.str());
504        SetStr(typekey.str(), name,       comment);
505
506        if (!unit.empty())
507            SetStr(unitkey.str(), unit, unitcom.str());
508
509        size_t size = 0;
510
511        switch (typechar)
512        {
513        case 'L': size = 1; break;
514        case 'A': size = 1; break;
515        case 'B': size = 1; break;
516        case 'I': size = 2; break;
517        case 'J': size = 4; break;
518        case 'K': size = 8; break;
519        case 'E': size = 4; break;
520        case 'D': size = 8; break;
521        }
522
523        Table::Column col;
524        col.name   = name;
525        col.type   = typechar;
526        col.num    = cnt;
527        col.size   = size;
528        col.offset = fTable.bytes_per_row;
529
530        fTable.cols.push_back(col);
531
532        fTable.bytes_per_row += size*cnt;
533
534        // Align to four bytes
535        fOutputBuffer.resize(fTable.bytes_per_row + 4-fTable.bytes_per_row%4);
536
537        return true;
538    }
539
540    bool AddColumnShort(uint32_t cnt, const string &name, const string &unit="", const string &comment="")
541    { return AddColumn(cnt, 'I', name, unit, comment); }
542    bool AddColumnInt(uint32_t cnt, const string &name, const string &unit="", const string &comment="")
543    { return AddColumn(cnt, 'J', name, unit, comment); }
544    bool AddColumnLong(uint32_t cnt, const string &name, const string &unit="", const string &comment="")
545    { return AddColumn(cnt, 'K', name, unit, comment); }
546    bool AddColumnFloat(uint32_t cnt, const string &name, const string &unit="", const string &comment="")
547    { return AddColumn(cnt, 'E', name, unit, comment); }
548    bool AddColumnDouble(uint32_t cnt, const string &name, const string &unit="", const string &comment="")
549    { return AddColumn(cnt, 'D', name, unit, comment); }
550    bool AddColumnChar(uint32_t cnt, const string &name, const string &unit="", const string &comment="")
551    { return AddColumn(cnt, 'A', name, unit, comment); }
552    bool AddColumnByte(uint32_t cnt, const string &name, const string &unit="", const string &comment="")
553    { return AddColumn(cnt, 'B', name, unit, comment); }
554    bool AddColumnBool(uint32_t cnt, const string &name, const string &unit="", const string &comment="")
555    { return AddColumn(cnt, 'L', name, unit, comment); }
556
557    bool AddColumnShort(const string &name, const string &unit="", const string &comment="")
558    { return AddColumn(1, 'I', name, unit, comment); }
559    bool AddColumnInt(const string &name, const string &unit="", const string &comment="")
560    { return AddColumn(1, 'J', name, unit, comment); }
561    bool AddColumnLong(const string &name, const string &unit="", const string &comment="")
562    { return AddColumn(1, 'K', name, unit, comment); }
563    bool AddColumnFloat(const string &name, const string &unit="", const string &comment="")
564    { return AddColumn(1, 'E', name, unit, comment); }
565    bool AddColumnDouble(const string &name, const string &unit="", const string &comment="")
566    { return AddColumn(1, 'D', name, unit, comment); }
567    bool AddColumnChar(const string &name, const string &unit="", const string &comment="")
568    { return AddColumn(1, 'A', name, unit, comment); }
569    bool AddColumnByte(const string &name, const string &unit="", const string &comment="")
570    { return AddColumn(1, 'B', name, unit, comment); }
571    bool AddColumnBool(const string &name, const string &unit="", const string &comment="")
572    { return AddColumn(1, 'L', name, unit, comment); }
573
574    /*
575    bool AddKey(string key, double d, const string &comment)
576    {
577        ostringstream out;
578        out << d;
579
580        string s = out.str();
581
582        replace(s.begin(), s.end(), "e", "E");
583
584        return AddKey(key, s, comment);
585        }*/
586
587
588    Checksum WriteHeader(ofstream &fout)
589    {
590        Checksum sum;
591        for (auto it=fKeys.begin(); it!=fKeys.end(); it++)
592        {
593            it->Out(fout);
594            sum += it->checksum;
595        }
596        fout.flush();
597
598        return sum;
599    }
600
601    Checksum WriteHeader()
602    {
603        return WriteHeader(*this);
604    }
605
606    void FlushHeader()
607    {
608        const off_t pos = tellp();
609        WriteHeader();
610        seekp(pos);
611    }
612
613    Checksum WriteFitsHeader()
614    {
615        ofits h;
616
617        h.SetBool("SIMPLE", true, "file does conform to FITS standard");
618        h.SetInt ("BITPIX",    8, "number of bits per data pixel");
619        h.SetInt ("NAXIS",     0, "number of data axes");
620        h.SetBool("EXTEND", true, "FITS dataset may contain extensions");
621        h.SetStr ("CHECKSUM","0000000000000000", "Checksum for the whole HDU");
622        h.SetStr ("DATASUM", "         0", "Checksum for the data block");
623        h.AddComment("FITS (Flexible Image Transport System) format is defined in 'Astronomy");
624        h.AddComment("and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H");
625        h.End();
626
627        const Checksum sum = h.WriteHeader(*this);
628
629        h.SetStr("CHECKSUM", sum.str());
630
631        const size_t offset = tellp();
632        h.WriteHeader(*this);
633        seekp(offset);
634
635        return sum;
636    }
637
638    bool WriteTableHeader(const char *name="DATA")
639    {
640        if (tellp()>0)
641        {
642#ifdef __EXCEPTIONS
643            throw runtime_error("File not empty anymore.");
644#else
645            gLog << ___err___ << "ERROR - File not empty anymore." << endl;
646            return false;
647#endif
648        }
649
650        fHeaderSum = WriteFitsHeader();
651
652        SetStr("EXTNAME", name);
653        SetInt("NAXIS1",  fTable.bytes_per_row);
654        SetInt("TFIELDS", fTable.cols.size());
655
656        End();
657
658        WriteHeader();
659
660        return good();
661    }
662
663    template<size_t N>
664        void revcpy(char *dest, const char *src, int num)
665    {
666        const char *pend = src + num*N;
667        for (const char *ptr = src; ptr<pend; ptr+=N, dest+=N)
668            reverse_copy(ptr, ptr+N, dest);
669    }
670
671    uint32_t GetBytesPerRow() const { return fTable.bytes_per_row; }
672
673    bool WriteRow(const void *ptr, size_t cnt, bool byte_swap=true)
674    {
675        // FIXME: Make sure that header was already written
676        //        or write header now!
677        if (cnt!=fTable.bytes_per_row)
678        {
679            ostringstream sout;
680            sout << "WriteRow - Size " << cnt << " does not match expected size " << fTable.bytes_per_row;
681#ifdef __EXCEPTIONS
682            throw runtime_error(sout.str());
683#else
684            gLog << ___err___ << "ERROR - " << sout.str() << endl;
685            return false;
686#endif
687        }
688
689        // For the checksum we need everything to be correctly aligned
690        const uint8_t offset = fTable.offset%4;
691
692        char *buffer = fOutputBuffer.data() + offset;
693
694        auto ib = fOutputBuffer.begin();
695        auto ie = fOutputBuffer.end();
696        *ib++ = 0;
697        *ib++ = 0;
698        *ib++ = 0;
699        *ib   = 0;
700
701        *--ie = 0;
702        *--ie = 0;
703        *--ie = 0;
704        *--ie = 0;
705
706        if (!byte_swap)
707            memcpy(buffer, ptr, cnt);
708        else
709        {
710            for (auto it=fTable.cols.begin(); it!=fTable.cols.end(); it++)
711            {
712                const char *src  = reinterpret_cast<const char*>(ptr) + it->offset;
713                char       *dest = buffer + it->offset;
714
715                // Let the compiler do some optimization by
716                // knowing the we only have 1, 2, 4 and 8
717                switch (it->size)
718                {
719                case 1: memcpy   (dest, src, it->num*it->size); break;
720                case 2: revcpy<2>(dest, src, it->num);          break;
721                case 4: revcpy<4>(dest, src, it->num);          break;
722                case 8: revcpy<8>(dest, src, it->num);          break;
723                }
724            }
725        }
726
727        write(buffer, cnt);
728        fDataSum.add(fOutputBuffer);
729
730        fTable.num_rows++;
731        fTable.offset += cnt;
732        return good();
733    }
734
735    template<typename N>
736    bool WriteRow(const vector<N> &vec)
737    {
738        return WriteRow(vec.data(), vec.size()*sizeof(N));
739    }
740
741    // Flushes the number of rows to the header on disk
742    void FlushNumRows()
743    {
744        SetInt("NAXIS2", fTable.num_rows);
745        FlushHeader();
746    }
747
748    bool close()
749    {
750        if (tellp()<0)
751            return false;
752
753        if (tellp()%(80*36)>0)
754        {
755            const vector<char> filler(80*36-tellp()%(80*36));
756            write(filler.data(), filler.size());
757        }
758
759        // We don't have to jump back to the end of the file
760        SetInt("NAXIS2",  fTable.num_rows);
761
762        ostringstream dataSumStr;
763        dataSumStr << fDataSum.val();
764        SetStr("DATASUM", dataSumStr.str());
765
766        const Checksum sum = WriteHeader();
767
768        //sum += headersum;
769
770        SetStr("CHECKSUM", (sum+fDataSum).str());
771
772        const Checksum chk = WriteHeader();
773
774        ofstream::close();
775
776        if ((chk+fDataSum).valid())
777            return true;
778
779        ostringstream sout;
780        sout << "Checksum (" << std::hex << chk.val() << ") invalid.";
781#ifdef __EXCEPTIONS
782        throw runtime_error(sout.str());
783#else
784        gLog << ___err___ << "ERROR - " << sout.str() << endl;
785        return false;
786#endif
787    }
788};
789
790}
791
792#if 0
793#include "fits.h"
794
795int main()
796{
797    using namespace std;
798
799    ofits h2("delme.fits");
800
801    h2.SetInt("KEY1", 1, "comment 1");
802    h2.AddColumnInt(2, "testcol1", "counts", "My comment");
803    h2.AddColumnInt("testcol2", "counts", "My comment");
804    //h2.AddColumnInt("testcol2", "counts", "My comment");
805    h2.SetInt("KEY2", 2, "comment 2");
806
807    /*
808     AddFloat("X0",           0.000123456, "number of fields in each row");
809     AddFloat("X1",           0, "number of fields in each row");
810     AddFloat("X2",      12345, "number of fields in each row");
811     AddFloat("X3",      123456.67890, "number of fields in each row");
812     AddFloat("X4", 1234567890123456789.12345678901234567890, "number of fields in each row");
813     AddFloat("X5", 1234567890.1234567890e20, "number of fields in each row");
814     AddFloat("X6", 1234567890.1234567890e-20, "number of fields in each row");
815     AddFloat("XB", 1234567890.1234567890e-111, "number of fields in each row");
816     AddFloat("X7", 1e-5, "number of fields in each row");
817     AddFloat("X8", 1e-6, "number of fields in each row");
818     //AddStr("12345678", "123456789012345678", "12345678901234567890123456789012345678901234567");
819     */
820    // -
821
822    h2.WriteTableHeader("TABLE_NAME");
823
824    for (int i=0; i<10; i++)
825    {
826        int j[3] = { i+10, i*10, i*100 };
827        h2.WriteRow(j, 3*sizeof(i));
828    }
829
830    //h2.AddColumnInt("testcol2", "counts", "My comment");
831    //h2.SetInt("KEY3", 2, "comment 2");
832    h2.SetInt("KEY2", 2, "comment 2xxx");
833    h2.SetInt("KEY1", 11);
834
835    h2.close();
836
837    cout << "---" << endl;
838
839    fits f("delme.fits");
840    if (!f)
841        throw runtime_error("xxx");
842
843    cout << "Header is valid: " << f.IsHeaderOk() << endl;
844
845    while (f.GetNextRow());
846
847    cout << "File   is valid: " << f.IsFileOk() << endl;
848
849    cout << "---" << endl;
850
851    return 0;
852}
853#endif
854
855#endif
Note: See TracBrowser for help on using the repository browser.