Changeset 12723 for trunk/FACT++/src


Ignore:
Timestamp:
12/15/11 10:39:26 (13 years ago)
Author:
lyard
Message:
replaced cfitsio by fits.h
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/FACT++/src/fitsdump.cc

    r12687 r12723  
    1111#include <fstream>
    1212
    13 #include <CCfits/CCfits>
    14 
    15 //#define PLOTTING_PLEASE
     13#include "externals/fits.h"
     14
     15#define PLOTTING_PLEASE
    1616
    1717#ifdef PLOTTING_PLEASE
     
    3232using namespace std;
    3333
    34 class MyColumn : public CCfits::Column
    35 {
    36 public:
    37     const string &comment() const { return CCfits::Column::comment(); }
    38     long width() const
    39     {//the width() method seems to be buggy (or empty ?) as it always return 1... redo it ourselves.
    40         string inter = format();
    41         inter = inter.substr(0, inter.size()-1);
    42         return atoi(inter.c_str());
    43     }
    44 };
    4534
    4635#ifdef PLOTTING_PLEASE
     
    6857
    6958private:
    70    
    71     CCfits::FITS  *fFile;                 /// FITS pointer
    72     CCfits::Table *fTable;                /// Table pointer
    73     map<string, MyColumn*> fColMap; /// map between the column names and their CCfits objects
     59    bool fDotsPlease;
     60    fits* fFile;
     61    string fFilename;
     62
     63    fits::Table::Columns fColMap;
     64    fits::Table::Keys fKeyMap;
    7465
    7566    // Convert CCfits::ValueType into a human readable string
    76     string ValueTypeToStr(CCfits::ValueType type) const;
     67    string ValueTypeToStr(char type) const;
    7768
    7869    // Convert CCfits::ValueType into a number of associated bytes
    79     int    ValueTypeToSize(CCfits::ValueType type) const;
     70    int    ValueTypeToSize(char type) const;
    8071
    8172    /// Calculate the buffer size required to read a row of the fits table, as well as the offsets to each column
    82     vector<int> CalculateOffsets() const;
     73//    vector<int> CalculateOffsets() const;
    8374
    8475    template<class T>
     
    8980
    9081    /// Write a single row of the selected data
    91     int  WriteRow(ostream &, const vector<MyColumn*> &, const vector<int> &, unsigned char *, const vector<pair<int, int> >&) const;
     82 //   int  WriteRow(ostream &, const vector<MyColumn*> &, const vector<int> &, unsigned char *, const vector<pair<int, int> >&) const;
    9283
    9384    bool OpenFile(const string &);        /// Open a file
     
    10899    int doCurvesDisplay( const vector<string> &list, const string& tableName);
    109100#endif
     101    int doStatsPlease(const string &filename, const vector<string>& list, int precision);
    110102    //    bool Plot(const vector<string> &list);
    111103
     
    121113//!        the ostream where to redirect the outputs
    122114//
    123 FitsDumper::FitsDumper() : fFile(0), fTable(0)
     115FitsDumper::FitsDumper() : fFile(0), fDotsPlease(false)
    124116{
    125117}
     
    136128
    137129
    138 string FitsDumper::ValueTypeToStr(CCfits::ValueType type) const
     130string FitsDumper::ValueTypeToStr(char type) const
    139131{
    140132    switch (type)
    141133    {
    142     case CCfits::Tbyte:     return "uint8_t";
    143     case CCfits::Tushort:   return "uint16_t";
    144     case CCfits::Tshort:    return "int16_t";
    145     case CCfits::Tuint:     return "uint32_t";
    146     case CCfits::Tint:      return "int32_t";
    147     case CCfits::Tulong:    return "uint32_t";
    148     case CCfits::Tlong:     return "int32_t";
    149     case CCfits::Tlonglong: return "int64_t";
    150     case CCfits::Tfloat:    return "float";
    151     case CCfits::Tdouble:   return "double";
    152 
     134        case 'L': return "bool(8)";
     135        case 'B': return "byte(8)";
     136        case 'I': return "short(16)";
     137        case 'J': return "int(32)";
     138        case 'K': return "int(64)";
     139        case 'E': return "float(32)";
     140        case 'D': return "double(64)";
    153141    default:
    154142        return "unknwown";
     
    156144}
    157145
    158 int FitsDumper::ValueTypeToSize(CCfits::ValueType type) const
     146int FitsDumper::ValueTypeToSize(char type) const
    159147{
    160148    switch (type)
    161149    {
    162     case CCfits::Tbyte:     return sizeof(uint8_t);
    163     case CCfits::Tushort:
    164     case CCfits::Tshort:    return sizeof(uint16_t);
    165     case CCfits::Tuint:
    166     case CCfits::Tint:
    167     case CCfits::Tulong:
    168     case CCfits::Tlong:     return sizeof(uint32_t);
    169     case CCfits::Tlonglong: return sizeof(uint64_t);
    170     case CCfits::Tfloat:    return sizeof(float);
    171     case CCfits::Tdouble:   return sizeof(double);
    172 
     150        case 'L': return sizeof(uint8_t);
     151        case 'B': return sizeof(int8_t);
     152        case 'I': return sizeof(int16_t);
     153        case 'J': return sizeof(int32_t);
     154        case 'K': return sizeof(int64_t);
     155        case 'E': return sizeof(float);
     156        case 'D': return sizeof(double);
    173157    default:
    174158        return 0;
     
    185169    return t;
    186170}
    187 /*
    188 template<class T>
    189 double FitsDumper::PtrToDouble(const unsigned char *ptr) const
    190 {
    191     T t;
    192     reverse_copy(ptr, ptr+sizeof(T), reinterpret_cast<unsigned char*>(&t));
    193     return t;
    194 }
    195 
    196 double FitsDumper::PtrToDouble(const unsigned char *ptr, CCfits::ValueType type) const
    197 {
    198     switch (type)
    199     {
    200     case CCfits::Tbyte:     return PtrToDouble<uint8_t> (ptr);
    201     case CCfits::Tushort:   return PtrToDouble<uint16_t>(ptr);
    202     case CCfits::Tuint:
    203     case CCfits::Tulong:    return PtrToDouble<uint32_t>(ptr);
    204     case CCfits::Tshort:    return PtrToDouble<int16_t> (ptr);
    205     case CCfits::Tint:
    206     case CCfits::Tlong:     return PtrToDouble<int32_t> (ptr);
    207     case CCfits::Tlonglong: return PtrToDouble<int64_t> (ptr);
    208     case CCfits::Tfloat:    return PtrToDouble<float>   (ptr);
    209     case CCfits::Tdouble:   return PtrToDouble<double>  (ptr);
    210 
    211     default:
    212         throw runtime_error("Data type not implemented yet.");
    213     }
    214 }
    215 */
    216 
    217 // --------------------------------------------------------------------------
    218 //
    219 //! Writes a single row of the selected FITS data to the output file.
    220 //!
    221 //! Data type \b not yet implemented:
    222 //!   CCfits::Tnull, CCfits::Tbit, CCfits::Tlogical, CCfits::Tstring,
    223 //!   CCfits::Tcomplex, CCfits::Tdblcomplex, CCfits::VTbit,
    224 //!   CCfits::VTbyte, CCfits::VTlogical, CCfits::VTushort,
    225 //!   CCfits::VTshort, CCfits::VTuint, CCfits::VTint, CCfits::VTulong,
    226 //!   CCfits::VTlong, CCfits::VTlonglong, CCfits::VTfloat,
    227 //!   CCfits::VTdouble, CCfits::VTcomplex, CCfits::VTdblcomplex
    228 //!
    229 //! @param offsets
    230 //!         a vector containing the offsets to the columns (in bytes)
    231 //! @param targetFile
    232 //!         the ofstream where to write to
    233 //! @param fitsBuffer
    234 //!         the memory were the row has been loaded by cfitsio
    235 //
    236 int FitsDumper::WriteRow(ostream &out, const vector<MyColumn*> &list, const vector<int> &offsets, unsigned char* fitsBuffer, const vector<pair<int, int> >& ranges) const
    237 {
    238     int cnt = 0;
    239     vector<pair<int, int> >::const_iterator jt = ranges.begin();
    240     for (vector<MyColumn*>::const_iterator it=list.begin(); it!=list.end(); it++, jt++)
    241     {
    242         if (jt == ranges.end())
    243         {
    244             cout << "ERROR: END OF RANGE POINTER REACHED" << endl;
    245             return false;
    246         }
    247         const MyColumn *col = *it;
    248 
    249         // CCfits starts counting at 1 not 0
    250         const int offset = offsets[col->index()-1];
    251 
    252         // Get the pointer to the array which we are supposed to print
    253         const unsigned char *ptr = fitsBuffer + offset;
    254 
    255         // Loop over all array entries
    256         int sizeToSkip = 0;
    257         switch (col->type())
    258         {
    259         case CCfits::Tbyte:     sizeToSkip = sizeof(uint8_t); break;
    260         case CCfits::Tushort:   sizeToSkip = sizeof(uint16_t); break;
    261         case CCfits::Tuint:
    262         case CCfits::Tulong:    sizeToSkip = sizeof(uint32_t); break;
    263         case CCfits::Tshort:    sizeToSkip = sizeof(int16_t); break;
    264         case CCfits::Tint:
    265         case CCfits::Tlong:     sizeToSkip = sizeof(int32_t); break;
    266         case CCfits::Tlonglong: sizeToSkip = sizeof(int64_t); break;
    267         case CCfits::Tfloat:    sizeToSkip = sizeof(float); break;
    268         case CCfits::Tdouble:   sizeToSkip = sizeof(double); break;
    269         default:
    270             cerr << "Data type not implemented yet." << endl;
    271             return 0;
    272         }
    273         ptr += sizeToSkip*jt->first;
    274         for (int width=jt->first; width<jt->second; width++)
    275         {
    276             switch (col->type())
    277             {
    278             case CCfits::Tbyte:     out << PtrToValue<uint8_t> (ptr); break;
    279             case CCfits::Tushort:   out << PtrToValue<uint16_t>(ptr); break;
    280             case CCfits::Tuint:
    281             case CCfits::Tulong:    out << PtrToValue<uint32_t>(ptr); break;
    282             case CCfits::Tshort:    out << PtrToValue<int16_t> (ptr); break;
    283             case CCfits::Tint:
    284             case CCfits::Tlong:     out << PtrToValue<int32_t> (ptr); break;
    285             case CCfits::Tlonglong: out << PtrToValue<int64_t> (ptr); break;
    286             case CCfits::Tfloat:    out << PtrToValue<float>   (ptr); break;
    287             case CCfits::Tdouble:   out << PtrToValue<double>  (ptr); break;
    288 
    289             default:
    290                 cerr << "Data type not implemented yet." << endl;
    291                 return 0;
    292             }
    293 
    294             out << " ";
    295             cnt++;
    296         }
    297     }
    298 
    299     if (cnt>0)
    300         out << endl;
    301 
    302     if (out.fail())
    303     {
    304         cerr << "ERROR - writing output: " << strerror(errno) << endl;
    305         return -1;
    306     }
    307 
    308     return cnt;
    309 }
    310 
    311 // --------------------------------------------------------------------------
    312 //
    313 //! Calculates the required buffer size for reading one row of the current
    314 //! table. Also calculates the offsets to all the columns
    315 //
    316 vector<int> FitsDumper::CalculateOffsets() const
    317 {
    318     map<int,int> sizes;
    319 
    320     for (map<string, MyColumn*>::const_iterator it=fColMap.begin();
    321          it!=fColMap.end(); it++)
    322     {
    323         const int &width = it->second->width();
    324         const int &idx   = it->second->index();
    325 
    326         const int size = ValueTypeToSize(it->second->type());
    327         if (size==0)
    328         {
    329             cerr << "Data type " << (int)it->second->type() << " not implemented yet." << endl;
    330             return vector<int>();
    331         }
    332 //cout << "data size: " << size << " width: " << width << " index: " << idx << endl;
    333         int realwidth = (width == 0)? 1 : width;
    334         sizes[idx] = size*realwidth;
    335     }
    336 
    337     //calculate the offsets in the vector.
    338     vector<int> result(1, 0);
    339 
    340     int size = 0;
    341     int idx  = 0;
    342 
    343     for (map<int,int>::const_iterator it=sizes.begin(); it!=sizes.end(); it++)
    344     {
    345         size += it->second;
    346         result.push_back(size);
    347 
    348         if (it->first == ++idx)
    349             continue;
    350 
    351         cerr << "Expected index " << idx << ", but found " << it->first << endl;
    352         return vector<int>();
    353     }
    354 
    355     return result;
    356 }
    357 
    358171// --------------------------------------------------------------------------
    359172//
     
    363176{
    364177    if (fFile)
     178    {
     179        fFile->close();
    365180        delete fFile;
    366 
    367     ostringstream str;
    368     try
    369     {
    370         fFile = new CCfits::FITS(filename);
    371     }
    372     catch (CCfits::FitsException e)
    373     {
    374         cerr << "Could not open FITS file " << filename << " reason: " << e.message() << endl;
     181    }
     182
     183    try {
     184        fFile = new fits(filename);
     185    }
     186    catch (std::runtime_error e)
     187    {
     188        cout << "Something went wrong while trying to open " << filename;
     189        cout << ": " << e.what() << " Aborting dump." << endl;
    375190        return false;
    376191    }
     192    fFilename = filename;
     193
     194    const fits::Table::Columns& tCols = fFile->getColumns();
     195
     196    for (auto it=tCols.begin(); it != tCols.end(); it++)
     197        fColMap.insert(*it);
     198
     199    const fits::Table::Keys& tkeys = fFile->getKeys();
     200
     201    for (auto it=tkeys.begin(); it != tkeys.end(); it++)
     202        fKeyMap.insert(*it);
    377203
    378204    return true;
     
    387213    }
    388214
    389     const multimap< string, CCfits::ExtHDU * > extMap = fFile->extension();
    390     if (extMap.find(tablename) == extMap.end())
    391     {
    392         cerr << "Table '" << tablename << "' not found." << endl;
    393         return false;
    394     }
    395 
    396     fTable  = dynamic_cast<CCfits::Table*>(extMap.find(tablename)->second);
    397     if (!fTable)
    398     {
    399         cerr << "Object '" << tablename << "' returned not a CCfits::Table." << endl;
    400         return false;
    401     }
    402 
    403     map<string, CCfits::Column*>& tCols = fTable->column();
    404     for (map<string, CCfits::Column*>::const_iterator it = tCols.begin(); it != tCols.end(); it++)
    405     {
    406         fColMap.insert(make_pair(it->first, static_cast<MyColumn*>(it->second)));
    407     }
    408 //    fColMap = fTable->column();
    409 
    410     fTable->makeThisCurrent();
    411 
    412     fTable->getComments();
    413     fTable->getHistory();
    414     fTable->readAllKeys();
    415215
    416216    return true;
     
    426226    }
    427227
    428     cout << "\nFile: " << fFile->name() << "\n";
    429 
    430     const multimap< string, CCfits::ExtHDU * > extMap = fFile->extension();
    431     for (std::multimap<string, CCfits::ExtHDU*>::const_iterator it=extMap.begin(); it != extMap.end(); it++)
    432     {
    433 
    434         CCfits::Table *table = dynamic_cast<CCfits::Table*>(extMap.find(it->first)->second);
    435 
    436         table->makeThisCurrent();
    437         table->readData();
    438 
    439         cout << " " << it->first << " [" << table->rows() << "]\n";
    440 
    441         const map<string, CCfits::Column*> &cols = table->column();
    442 
    443 //        for (map<string, CCfits::Column*>::const_iterator id = cols.begin(); ib != cols.end(); ib++)
    444 //        {
    445 //            TFORM
    446 //        }
    447 
    448         for (map<string, CCfits::Column*>::const_iterator ic=cols.begin();
    449              ic != cols.end(); ic++)
    450         {
    451             const MyColumn *col = static_cast<MyColumn*>(ic->second);
    452 
    453             cout << "   " << col->name() << "[" ;
    454             if (col->width() == 0)
    455                 cout << 1;
    456             else
    457                 cout << col->width();
    458             cout  << "] * " << col->scale() << " (" << col->unit() << ":" <<  ValueTypeToStr(col->type())<<  ") " << col->comment() << "\n";
    459             /*
    460              inline size_t Column::repeat () const
    461              inline bool   Column::varLength () const
    462              inline double Column::zero () const
    463              inline const  String& Column::display () const
    464              inline const  String& Column::dimen () const
    465              inline const  String& Column::TBCOL ()
    466              inline const  String& Column::TTYPE ()
    467              inline const  String& Column::TFORM ()
    468              inline const  String& Column::TDISP ()
    469              inline const  String& Column::TZERO ()
    470              inline const  String& Column::TDIM  ()
    471              inline const  String& Column::TNULL ()
    472              inline const  String& Column::TLMIN ()
    473              inline const  String& Column::TLMAX ()
    474              inline const  String& Column::TDMAX ()
    475              inline const  String& Column::TDMIN ()
    476             */
    477         }
    478         cout << '\n';
    479     }
     228    cout << "\nFile: " << fFilename << "\n";
     229
     230    cout << " " << fKeyMap.find("EXTNAME")->second.value << " [";
     231    cout << fKeyMap.find("NAXIS2")->second.value << "]\n";
     232
     233    for (auto it = fColMap.begin(); it != fColMap.end(); it++)
     234    {
     235        cout << "   " << it->first << "[" << it->second.num << "] (" << it->second.unit << ":" << ValueTypeToStr(it->second.type) << ") ";
     236        for (auto jt = fKeyMap.begin(); jt != fKeyMap.end(); jt++)
     237            if (jt->second.value == it->first)
     238                cout << jt->second.comment << endl;
     239    }
     240
     241    cout << endl;
    480242    cout << flush;
    481243}
    482244
    483 class MyKeyword : public CCfits::Keyword
    484 {
    485 public:
    486     CCfits::ValueType keytype() const { return CCfits::Keyword::keytype(); }
    487 };
    488 
    489245void FitsDumper::ListKeywords(ostream &out)
    490246{
    491     map<string,CCfits::Keyword*> keys = fTable->keyWord();
    492     for (map<string,CCfits::Keyword*>::const_iterator it=keys.begin();
    493          it!=keys.end(); it++)
    494     {
    495         string str;
    496         double d;
    497         int l;
    498 
    499         const MyKeyword *kw = static_cast<MyKeyword*>(it->second);
    500         kw->keytype();
    501         out << "## " << setw(8) << kw->name() << " = " << setw(10);
    502         if (kw->keytype()==16)
    503             out << ("'"+kw->value(str)+"'");
    504         if (kw->keytype()==31)
    505             out << kw->value(l);
    506         if (kw->keytype()==82)
    507             out << kw->value(d);
    508         out << " / " << kw->comment() << endl;
     247    for (auto it=fKeyMap.begin(); it != fKeyMap.end(); it++) {
     248        out << "## " << setw(8) << it->first << " = " << setw(10);
     249        out << "'" << it->second.value << "'" << " / " << it->second.comment << endl;
    509250    }
    510251}
     
    512253void FitsDumper::ListHeader()
    513254{
    514     if (!fTable)
     255    if (!fFile)
    515256    {
    516257        cerr << "No table open." << endl;
     
    518259    }
    519260
    520     cout << "\nTable: " << fTable->name() << " (rows=" << fTable->rows() << ")\n";
    521     if (!fTable->comment().empty())
    522         cout << "Comment: \t" << fTable->comment() << '\n';
    523     if (!fTable->history().empty())
    524         cout << "History: \t" << fTable->history() << '\n';
     261    cout << "\nTable: " << fKeyMap.find("EXTNAME")->second.value << " (rows=" << fKeyMap.find("NAXIS2")->second.value << ")\n";
     262    if (fKeyMap.find("COMMENT") != fKeyMap.end())
     263        cout << "Comment: \t" << fKeyMap.find("COMMENT")->second.value << "\n";
    525264
    526265    ListKeywords(cout);
    527266    cout << endl;
     267
    528268}
    529269
     
    538278        unsigned long bracketIndex1 = columnNameOnly.find_first_of(']');
    539279        unsigned long colonIndex = columnNameOnly.find_first_of(':');
    540 //        cout << bracketIndex0 << " " << bracketIndex1 << " " << colonIndex << endl;
    541280        int columnStart = -1;
    542281        int columnEnd = -1;
     
    553292                columnStart = atoi(columnNameOnly.substr(bracketIndex0+1, bracketIndex1 - (bracketIndex0+1)).c_str());
    554293                columnEnd = columnStart+1;
    555 //                cout << "Cstart " << columnStart  << " end: " << columnEnd << endl;
    556294            }
    557295            columnNameOnly = columnNameOnly.substr(0, bracketIndex0);
     
    563301            return false;
    564302        }
    565 //        cout << "The column name is: " << columnNameOnly << endl;
    566         MyColumn *cCol = static_cast<MyColumn*>(fColMap.find(columnNameOnly)->second);
     303        fits::Table::Column& cCol = fColMap.find(columnNameOnly)->second;
    567304        if (bracketIndex0 == string::npos)
    568305        {//no range given: use the full range
    569             ranges.push_back(make_pair(0, cCol->width()));
     306            ranges.push_back(make_pair(0, cCol.num));
    570307            columnStart = 0;
    571308            columnEnd = 1;
     
    578315                return false;
    579316            }
    580             if (columnEnd>1 && columnEnd > cCol->width())
     317            if (columnEnd>1 && columnEnd > (int)(cCol.num))
    581318            {
    582                 cerr << "ERROR - End range for column " << columnNameOnly << " is greater than the last element (" << cCol->width() << " vs " << columnEnd << "). Aborting" << endl;
     319                cerr << "ERROR - End range for column " << columnNameOnly << " is greater than the last element (" << cCol.num << " vs " << columnEnd << "). Aborting" << endl;
    583320                return false;
    584321            }
     
    607344    }
    608345
    609     // FIXME: Maybe do this when opening a table?
    610     const vector<int> offsets = CalculateOffsets();
    611  //   for (int i=0;i<offsets.size(); i++)
    612  //       cout << offsets[i] << " ";
    613 //    cout << endl;
    614     if (offsets.size()==0)
    615         return false;
    616 
    617346    ofstream out(filename=="-"?"/dev/stdout":filename);
    618347    if (!out)
     
    627356    if (filename!="-")
    628357        out << "## File:    \t" << filename << '\n';
    629     out << "## Table:   \t" << fTable->name() << '\n';
    630     if (!fTable->comment().empty())
    631         out << "## Comment: \t" << fTable->comment() << '\n';
    632     if (!fTable->history().empty())
    633         out << "## History: \t" << fTable->history() << '\n';
    634     out << "## NumRows: \t" << fTable->rows() << '\n';
     358    out << "## Table:   \t" << fKeyMap.find("EXTNAME")->second.value << '\n';
     359        out << "## Comment: \t" << ((fKeyMap.find("COMMENT") != fKeyMap.end()) ? fKeyMap.find("COMMENT")->second.value : "") << '\n';
     360
     361    out << "## NumRows: \t" << fFile->GetInt("NAXIS2") << '\n';
    635362    out << "## --------------------------------------------------------------------------\n";
    636363    ListKeywords(out);
    637364    out << "## --------------------------------------------------------------------------\n";
    638365    out << "#\n";
    639     //vector<pair<int, int> >::const_iterator rangesIt = ranges.begin();
    640     //the above is soooo yesterday ;) let's try the new auto feature of c++0x
     366
    641367    auto rangesIt = ranges.begin();
    642368    for (vector<string>::const_iterator it=listNamesOnly.begin(); it!=listNamesOnly.end(); it++, rangesIt++)
    643369    {
    644         const MyColumn *col = static_cast<MyColumn*>(fTable->column()[*it]);
    645         if (rangesIt->first != 0 || rangesIt->second != col->width())
     370        const fits::Table::Column& col = fColMap[*it];
     371//        const MyColumn *col = static_cast<MyColumn*>(fTable->column()[*it]);
     372        if (rangesIt->first != 0 || rangesIt->second != col.num)
    646373        {
    647374            out << "#";
    648375            for (int i=rangesIt->first; i<rangesIt->second; i++)
    649                 out << " " << col->name() << "[" << i << "]";
    650             out << ": " << col->unit();
     376                out << " " << *it << "[" << i << "]";
     377            out << ": " << col.unit;
    651378        }
    652379        else
    653             out << "# " << col->name() << "[" << col->width() << "]: " << col->unit();
    654 
    655         if (!col->comment().empty())
    656             out << " (" <<col->comment() << ")";
     380            out << "# " << *it << "[" << col.num << "]: " << col.unit;
     381
     382//        FIXME: retrive the column comment
     383//        if (!col->comment().empty())
     384//            out << " (" <<col->comment() << ")";
    657385        out << '\n';
    658386    }
     
    661389
    662390    // Loop over all columns in our list of requested columns
    663     vector<MyColumn*> columns;
     391    vector<pair<char, char*> > columnsData;
     392
    664393    for (vector<string>::const_iterator it=listNamesOnly.begin(); it!=listNamesOnly.end(); it++)
    665394    {
    666         MyColumn *cCol = static_cast<MyColumn*>(fColMap.find(*it)->second);
    667         columns.push_back(cCol);
    668     }
    669     const int size = offsets[offsets.size()-1];
    670     unsigned char* fitsBuffer = new unsigned char[size];
    671 
    672     int status = 0;
    673     int endIndex = (fColMap.find("Time") == fColMap.end()) ? fTable->rows()-1 : fTable->rows();
    674     for (int i=1; i<=endIndex; i++)
    675     {
    676         fits_read_tblbytes(fFile->fitsPointer(), i, 1, size, fitsBuffer, &status);
    677         if (status)
     395        fits::Table::Column& cCol = fColMap.find(*it)->second;
     396        columnsData.push_back(make_pair(cCol.type, new char[cCol.num*cCol.size]));
     397        fFile->SetPtrAddress(*it, columnsData[columnsData.size()-1].second);
     398    }
     399    int numRows = fFile->GetInt("NAXIS2");
     400    int row = 0;
     401    while (fFile->GetNextRow() && row < numRows)
     402    {
     403        row++;
     404        rangesIt = ranges.begin();
     405        for (auto it=columnsData.begin(); it != columnsData.end(); it++, rangesIt++)
    678406        {
    679             char text[30];//max length of cfitsio error strings (from doc)
    680             fits_get_errstatus(status, text);
    681 
    682             cerr << "Reading row " << i << " failed: " << text << " (fits_insert_rows,rc=" << status << ")" << endl;
    683             break;
    684         }
    685         if (WriteRow(out, columns, offsets, fitsBuffer, ranges)<0)
    686         {
    687             status=1;
    688             break;
    689         }
    690     }
    691     delete[] fitsBuffer;
    692 
    693     return status==0;
    694 }
    695 
    696 // --------------------------------------------------------------------------
    697 //
    698 //! Perform the actual dump, based on the current parameters
    699 //
    700 /*
    701 bool FitsDumper::Plot(const vector<string> &list)
    702 {
    703    for (vector<string>::const_iterator it=list.begin(); it!=list.end(); it++)
    704         if (fColMap.find(*it) == fColMap.end())
    705         {
    706             cerr << "WARNING - Column '" << *it << "' not found in table." << endl;
    707             return false;
    708         }
    709 
    710     // FIXME: Maybe do this when opening a table?
    711     const vector<int> offsets = CalculateOffsets();
    712     if (offsets.size()==0)
    713         return false;
    714 
    715     // Loop over all columns in our list of requested columns
    716     const CCfits::Column *col[3] =
    717     {
    718         list.size()>0 ? fColMap.find(list[0])->second : 0,
    719         list.size()>1 ? fColMap.find(list[1])->second : 0,
    720         list.size()>2 ? fColMap.find(list[2])->second : 0
    721     };
    722 
    723     const int size = offsets[offsets.size()-1];
    724     unsigned char* fitsBuffer = new unsigned char[size];
    725 
    726     const int idx = 0;
    727 
    728     // CCfits starts counting at 1 not 0
    729     const size_t pos[3] =
    730     {
    731         col[0] ? offsets[col[0]->index()-1] + idx*col[0]->width()*ValueTypeToSize(col[0]->type()) : 0,
    732         col[1] ? offsets[col[1]->index()-1] + idx*col[1]->width()*ValueTypeToSize(col[1]->type()) : 0,
    733         col[2] ? offsets[col[2]->index()-1] + idx*col[2]->width()*ValueTypeToSize(col[2]->type()) : 0
    734     };
    735 
    736     int status = 0;
    737     for (int i=1; i<=fTable->rows(); i++)
    738     {
    739         fits_read_tblbytes(fFile->fitsPointer(), i, 1, size, fitsBuffer, &status);
    740         if (status)
    741         {
    742             cerr << "An error occurred while reading fits row #" << i << " error code: " << status << endl;
    743             break;
    744         }
    745 
    746         try
    747         {
    748             const double x[3] =
     407            for (int i=rangesIt->first; i<rangesIt->second; i++)
    749408            {
    750                 col[0] ? PtrToDouble(fitsBuffer+pos[0], col[0]->type()) : 0,
    751                 col[1] ? PtrToDouble(fitsBuffer+pos[1], col[1]->type()) : 0,
    752                 col[2] ? PtrToDouble(fitsBuffer+pos[2], col[2]->type()) : 0
    753             };
    754         }
    755         catch (const runtime_error &e)
    756         {
    757             cerr << e.what() << endl;
    758             status=1;
    759             break;
    760         }
    761     }
    762     delete[] fitsBuffer;
    763 
    764     return status==0;
    765 }
    766 */
     409            switch (it->first) {
     410                case 'L':
     411                        out << reinterpret_cast<bool*>(it->second)[i] << " ";
     412                        break;
     413                case 'B':
     414                        out << reinterpret_cast<char*>(it->second)[i] << " ";
     415                        break;
     416                case 'I':
     417                        out << reinterpret_cast<int16_t*>(it->second)[i] << " ";
     418                        break;
     419                case 'J':
     420                        out << reinterpret_cast<int32_t*>(it->second)[i] << " ";
     421                        break;
     422                case 'K':
     423                        out << reinterpret_cast<int64_t*>(it->second)[i] << " ";
     424                        break;
     425                case 'E':
     426                        out << reinterpret_cast<float*>(it->second)[i] << " ";
     427                        break;
     428                case 'D':
     429                        out << reinterpret_cast<double*>(it->second)[i] << " ";
     430                        break;
     431                default:
     432                    ;
     433            }
     434            }
     435        }
     436    }
     437    for (auto it = columnsData.begin(); it != columnsData.end(); it++)
     438        delete[] it->second;
     439    return true;
     440}
    767441
    768442// --------------------------------------------------------------------------
     
    780454    }
    781455
     456    if (conf.Get<bool>("stat") && conf.Get<bool>("graph"))
     457    {
     458        cout << "Invalid conbination of options: cannot graph stats. Aborting" << endl;
     459        return -1;
     460    }
     461
    782462    if (conf.Get<bool>("list"))
    783463        List();
     
    789469    }
    790470
    791 #ifdef PLOTTING_PLEASE
    792     if (conf.Get<bool>("graph"))
     471    if (conf.Get<bool>("stat"))
    793472    {
    794473        if (!conf.Has("col"))
     
    797476            return 0;
    798477        }
     478        doStatsPlease(conf.Get<string>("outfile"), conf.Get<vector<string>>("col"), conf.Get<int>("precision"));
     479        return 0;
     480    }
     481
     482#ifdef PLOTTING_PLEASE
     483    if (conf.Get<bool>("graph"))
     484    {
     485        if (!conf.Has("col"))
     486        {
     487            cout << "Please specify the columns that should be dumped as arguments. Aborting" << endl;
     488            return 0;
     489        }
     490        if (conf.Get<bool>("dots"))
     491            fDotsPlease = true;
    799492        doCurvesDisplay(conf.Get<vector<string>>("col"),
    800493                        conf.Get<string>("tablename"));
     
    839532{
    840533    //
     534}
     535
     536template<typename T>
     537void displayStats(char* array, int numElems)
     538{
     539    sort(reinterpret_cast<T*>(array), &reinterpret_cast<T*>(array)[numElems]);
     540    cout << "Min: " << reinterpret_cast<T*>(array)[0] << endl;
     541    cout << "Max: " << reinterpret_cast<T*>(array)[numElems-1] << endl;
     542    if (numElems%2 == 0)
     543        cout << "Med: " << (reinterpret_cast<T*>(array)[numElems/2] + reinterpret_cast<int16_t*>(array)[numElems/2+1])/2.f << endl;
     544    else
     545        cout << "Med: " << reinterpret_cast<T*>(array)[numElems/2+1] << endl;
     546
     547    double average = 0;
     548    for (int i=0;i<numElems;i++)
     549        average += reinterpret_cast<T*>(array)[i];
     550    cout << "Mea: " << average/(double)numElems << endl;
     551
     552}
     553int FitsDumper::doStatsPlease(const string &filename, const vector<string>& list, int precision)
     554{
     555
     556    //first of all, let's separate the columns from their ranges and check that the requested columns are indeed part of the file
     557    vector<pair<int, int> > ranges;
     558    vector<string> listNamesOnly;
     559
     560    if (!separateColumnsFromRanges(list, ranges, listNamesOnly))
     561    {
     562        cerr << "Something went wrong while extracting the columns names from parameters. Aborting" << endl;
     563        return false;
     564    }
     565
     566    ofstream out(filename=="-"?"/dev/stdout":filename);
     567    if (!out)
     568    {
     569        cerr << "Cannot open file " << filename << ": " << strerror(errno) << endl;
     570        return false;
     571    }
     572
     573    out.precision(precision);
     574
     575    // Loop over all columns in our list of requested columns
     576    vector<pair<char, char*> > columnsData;
     577    vector<char*> statData;
     578    int numRows = fFile->GetInt("NAXIS2");
     579    auto rangesIt = ranges.begin();
     580    for (vector<string>::const_iterator it=listNamesOnly.begin(); it!=listNamesOnly.end(); it++, rangesIt++)
     581    {
     582        fits::Table::Column& cCol = fColMap.find(*it)->second;
     583        columnsData.push_back(make_pair(cCol.type, new char[cCol.num*cCol.size]));
     584        statData.push_back(new char[(rangesIt->second - rangesIt->first)*cCol.size*numRows]);
     585        fFile->SetPtrAddress(*it, columnsData[columnsData.size()-1].second);
     586    }
     587
     588    int row = 0;
     589    while (fFile->GetNextRow() && row < numRows)
     590    {
     591        rangesIt = ranges.begin();
     592        auto statsIt = statData.begin();
     593        for (auto it=columnsData.begin(); it != columnsData.end(); it++, rangesIt++, statsIt++)
     594        {
     595            int span = rangesIt->second - rangesIt->first;
     596            for (int i=rangesIt->first; i<rangesIt->second; i++)
     597            {
     598            switch (it->first) {
     599                case 'L':
     600                        reinterpret_cast<bool*>(*statsIt)[i - rangesIt->first + row*span] = reinterpret_cast<bool*>(it->second)[i];
     601                        break;
     602                case 'B':
     603                        reinterpret_cast<char*>(*statsIt)[i - rangesIt->first + row*span] = reinterpret_cast<char*>(it->second)[i];
     604                        break;
     605                case 'I':
     606                        reinterpret_cast<int16_t*>(*statsIt)[i - rangesIt->first + row*span] = reinterpret_cast<int16_t*>(it->second)[i];
     607                        break;
     608                case 'J':
     609                        reinterpret_cast<int32_t*>(*statsIt)[i - rangesIt->first + row*span] = reinterpret_cast<int32_t*>(it->second)[i];
     610                        break;
     611                case 'K':
     612                        reinterpret_cast<int64_t*>(*statsIt)[i - rangesIt->first + row*span] = reinterpret_cast<int64_t*>(it->second)[i];
     613                        break;
     614                case 'E':
     615                        reinterpret_cast<float*>(*statsIt)[i - rangesIt->first + row*span] = reinterpret_cast<float*>(it->second)[i];
     616                        break;
     617                case 'D':
     618                        reinterpret_cast<float*>(*statsIt)[i - rangesIt->first + row*span] = reinterpret_cast<double*>(it->second)[i];
     619                        break;
     620                default:
     621                    ;
     622            }
     623            }
     624        }
     625        row++;
     626    }
     627    for (auto it = columnsData.begin(); it != columnsData.end(); it++)
     628        delete[] it->second;
     629
     630    //okay. So now I've got ALL the data, loaded.
     631    //let's do the summing and averaging in a safe way (i.e. avoid overflow of variables as much as possible)
     632    rangesIt = ranges.begin();
     633    auto statsIt = statData.begin();
     634    int round;
     635    auto nameIt = listNamesOnly.begin();
     636    for (auto it=columnsData.begin(); it != columnsData.end(); it++, rangesIt++, statsIt++, nameIt++)
     637    {
     638        int span = rangesIt->second - rangesIt->first;
     639        cout << *nameIt << ": " << endl;
     640        switch (it->first) {
     641            case 'L':
     642                    displayStats<bool>(*statsIt, numRows*span);
     643                    break;
     644            case 'B':
     645                    displayStats<char>(*statsIt, numRows*span);
     646                    break;
     647            case 'I':
     648                    displayStats<int16_t>(*statsIt, numRows*span);
     649                    break;
     650            case 'J':
     651                    displayStats<int32_t>(*statsIt, numRows*span);
     652                    break;
     653            case 'K':
     654                    displayStats<int64_t>(*statsIt, numRows*span);
     655                    break;
     656            case 'E':
     657                    displayStats<float>(*statsIt, numRows*span);
     658                    break;
     659            case 'D':
     660                    displayStats<double>(*statsIt, numRows*span);
     661                    break;
     662            default:
     663                ;
     664        }
     665    }
     666    return true;
    841667}
    842668#ifdef PLOTTING_PLEASE
     
    894720    for (unsigned int i=0;i<list.size();i++)
    895721        totalSize += ranges[i].second - ranges[i].first;
    896  //   cout << "Total size: " << totalSize << endl;
     722
    897723    vector<QwtPlotCurve*> curves(totalSize);
    898724    int ii=0;
     
    924750        };
    925751        ii++;
    926         (*it)->setStyle(QwtPlotCurve::Lines);
     752        if (fDotsPlease)
     753            (*it)->setStyle(QwtPlotCurve::Dots);
     754        else
     755            (*it)->setStyle(QwtPlotCurve::Lines);
    927756        (*it)->attach(plot);
    928757    }
    929758    plot->insertLegend(new QwtLegend(), QwtPlot::RightLegend);
    930759
    931      const vector<int> offsets = CalculateOffsets();
    932      if (offsets.size()==0)
    933          return false;
    934 
    935 
    936      // Loop over all columns in our list of requested columns
    937       vector<MyColumn*> columns;
     760
     761      vector<pair<char, char*> > columnsData;
     762
    938763      for (vector<string>::const_iterator it=listNamesOnly.begin(); it!=listNamesOnly.end(); it++)
    939764      {
    940           MyColumn *cCol = static_cast<MyColumn*>(fColMap.find(*it)->second);
    941           columns.push_back(cCol);
     765          fits::Table::Column& cCol = fColMap.find(*it)->second;
     766          columnsData.push_back(make_pair(cCol.type, new char[cCol.num*cCol.size]));
     767          fFile->SetPtrAddress(*it, columnsData[columnsData.size()-1].second);
    942768      }
     769
    943770      //add the time column to the given columns
    944771      if (fColMap.find("Time") == fColMap.end() && fColMap.find("UnixTimeUTC") == fColMap.end())
     
    947774          return false;
    948775      }
    949       MyColumn* timeCol;
    950       bool unixTime = false;
    951       int endIndex = 0;
    952       if (fColMap.find("Time") != fColMap.end())
    953       {
    954           timeCol = static_cast<MyColumn*>(fColMap.find("Time")->second);
     776      const fits::Table::Column& timeCol = (fColMap.find("Time") != fColMap.end()) ? fColMap.find("Time")->second : fColMap.find("UnixTimeUTC")->second;
     777      bool unixTime = (fColMap.find("Time") == fColMap.end());
     778      if (unixTime)
     779          ranges.push_back(make_pair(0,2));
     780      else
    955781          ranges.push_back(make_pair(0,1));
    956           endIndex = fTable->rows();
    957       }
    958       if (fColMap.find("UnixTimeUTC") != fColMap.end())
    959       {
    960           timeCol = static_cast<MyColumn*>(fColMap.find("UnixTimeUTC")->second);
    961           ranges.push_back(make_pair(0,2));
    962           endIndex = fTable->rows()-1;
    963           unixTime = true;
    964       }
    965       columns.push_back(timeCol);
    966       /////
    967       const int size = offsets[offsets.size()-1];
    968       unsigned char* fitsBuffer = new unsigned char[size];
     782      columnsData.push_back(make_pair(timeCol.type, new char[timeCol.num*timeCol.size]));
     783      fFile->SetPtrAddress(unixTime ? "UnixTimeUTC" : "Time", columnsData[columnsData.size()-1].second);
    969784
    970785//      stringstream str;
     
    977792      str.precision(20);
    978793      for (auto it=xValues.begin(); it!=xValues.end(); it++)
    979           *it = new double[fTable->rows()];
    980 
    981       yValues = new double[fTable->rows()];
     794          *it = new double[fFile->GetInt("NAXIS2")];
     795
     796      yValues = new double[fFile->GetInt("NAXIS2")];
    982797
    983798      cout.precision(3);
    984       for (int i=1; i<=endIndex; i++)
     799      int endIndex = 0;
     800      int numRows = fFile->GetInt("NAXIS2");
     801      for (int i=1;i<numRows;i++)
    985802      {
    986           cout << "/r" << "Constructing graph " << ((float)(i)/(float)(endIndex))*100.0 << "%";
    987           fits_read_tblbytes(fFile->fitsPointer(), i, 1, size, fitsBuffer, &status);
    988           if (status)
     803          fFile->GetNextRow();
     804          cout << "\r" << "Constructing graph " << ((float)(endIndex)/(float)(fFile->GetInt("NAXIS2")))*100.0 << "%";
     805          endIndex++;
     806          auto rangesIt = ranges.begin();
     807          for (auto it=columnsData.begin(); it != columnsData.end(); it++, rangesIt++)
    989808          {
    990               cerr << "An error occurred while reading fits row #" << i << " error code: " << status << endl;
    991               break;
     809              for (int i=rangesIt->first; i<rangesIt->second; i++)
     810              {
     811              switch (it->first) {
     812                  case 'L':
     813                          str << reinterpret_cast<bool*>(it->second)[i] << " ";
     814                          break;
     815                  case 'B':
     816                          str << reinterpret_cast<char*>(it->second)[i] << " ";
     817                          break;
     818                  case 'I':
     819                          str << reinterpret_cast<int16_t*>(it->second)[i] << " ";
     820                          break;
     821                  case 'J':
     822                          str << reinterpret_cast<int32_t*>(it->second)[i] << " ";
     823                          break;
     824                  case 'K':
     825                          str << reinterpret_cast<int64_t*>(it->second)[i] << " ";
     826                          break;
     827                  case 'E':
     828                          str << reinterpret_cast<float*>(it->second)[i] << " ";
     829                          break;
     830                  case 'D':
     831                          str << reinterpret_cast<double*>(it->second)[i] << " ";
     832                          break;
     833                  default:
     834                      ;
     835              }
     836              }
    992837          }
    993           if (WriteRow(str, columns, offsets, fitsBuffer, ranges)<0)
    994           {
    995               status=1;
    996               cerr << "An Error occured while reading the fits row " << i << endl;
    997               return -1;
    998           }
    999 //          yValues[i-1] = i;
     838
    1000839          for (auto it=xValues.begin(); it!= xValues.end(); it++)
    1001840          {
    1002841              str >> (*it)[i-1];
    1003 //              cout << (*it)[i-1] << " ";
    1004842          }
    1005843          if (unixTime)
     
    1007845              long u1, u2;
    1008846              str >> u1 >> u2;
    1009  //             cout << u1 << " " << u2;
     847
    1010848              boost::posix_time::ptime unixTimeT( boost::gregorian::date(1970, boost::gregorian::Jan, 1),
    1011849                      boost::posix_time::seconds(u1) +  boost::posix_time::microsec(u2));
     
    1013851              Time mjdTime(unixTimeT);
    1014852              yValues[i-1] = mjdTime.Mjd();
    1015  //             cout << " " << mjdTime.Mjd() << endl;
    1016853          }
    1017854          else
     
    1020857              if (yValues[i-1] < 40587)
    1021858                  yValues[i-1] += 40587;
     859
     860              Time t(yValues[i-1]);
     861              string time = t.GetAsStr("%H:%M:%S%F");
     862              while (time[time.size()-1] == '0' && time.size() > 2)
     863              {
     864                  time = time.substr(0, time.size()-1);
     865              }
    1022866          }
    1023867          if (i==1)
     
    1027871              plot->setTitle(title.c_str());
    1028872          }
    1029 //          cout << yValues[i-1] << " ";
    1030 //          cout << endl;
    1031873      }
    1032874      //set the actual data.
    1033875      auto jt = xValues.begin();
    1034876      for (auto it=curves.begin(); it != curves.end(); it++, jt++)
    1035           (*it)->setRawData(yValues, *jt, endIndex);
     877          (*it)->setRawData(yValues, *jt, endIndex-1);
    1036878
    1037879      QStack<QRectF> stack;
     
    1061903      zoom.setZoomStack(stack);
    1062904
    1063       delete[] fitsBuffer;
     905//      delete[] fitsBuffer;
     906      for (auto it = columnsData.begin(); it != columnsData.end(); it++)
     907          delete[] it->second;
    1064908    window.resize(600, 400);
    1065909    window.show();
     
    1101945        ("list,l",      po_switch(),                "List all tables and columns in file")
    1102946        ("header,h",    po_switch(),                "Dump header of given table")
     947        ("stat,s",      po_switch(),                "Perform statistics instead of dump")
    1103948#ifdef PLOTTING_PLEASE
    1104949        ("graph,g",     po_switch(),                "Plot the columns instead of dumping them")
     950        ("dots,d",      po_switch(),                "Plot using dots instead of lines")
    1105951#endif
    1106952        ;
Note: See TracChangeset for help on using the changeset viewer.