Ignore:
Timestamp:
07/30/11 16:09:27 (13 years ago)
Author:
tbretz
Message:
Make use of the new FitsFile class.
File:
1 edited

Legend:

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

    r11593 r11716  
    3737void Fits::AddStandardColumn(const Description& desc, const string &dataFormat, void* dataPointer, long unsigned int numDataBytes)
    3838{
    39         //check if entry already exist
    40         for (vector<Description>::const_iterator it=fStandardColDesc.begin(); it != fStandardColDesc.end(); it++)
    41                 if (it->name == desc.name)
    42                         return;
    43         fStandardColDesc.push_back(desc);
    44         fStandardFormats.push_back(dataFormat);
    45         fStandardPointers.push_back(dataPointer);
    46         fStandardNumBytes.push_back(numDataBytes);
    47 }
     39    //check if entry already exist
     40    for (vector<Description>::const_iterator it=fStandardColDesc.begin(); it != fStandardColDesc.end(); it++)
     41        if (it->name == desc.name)
     42            return;
     43
     44    fStandardColDesc.push_back(desc);
     45    fStandardFormats.push_back(dataFormat);
     46    fStandardPointers.push_back(dataPointer);
     47    fStandardNumBytes.push_back(numDataBytes);
     48}
     49
    4850// --------------------------------------------------------------------------
    4951//
     
    5456//! @param numDataBytes the number of bytes taken by the DIM data.
    5557//     
    56 void Fits::InitDataColumns(const vector<Description> &desc, vector<string>& dataFormat, void* dataPointer, int numDataBytes)
    57 {//we will copy this information here. It duplicates the data, which is not great, but it is the easiest way of doing it right now
    58         if (desc.size() == dataFormat.size())
    59         {
    60                 fDataColDesc = desc;
    61         }
    62         else
    63         {
    64                 fDataColDesc.clear();
    65                 for (unsigned int i=0;i<dataFormat.size();i++)
    66                 {
    67                         ostringstream stt;
    68                         stt << "Data" << i;
    69                         fDataColDesc.push_back(Description(stt.str(), "comment", "unit"));
    70                 }
    71         }               
    72         fDataFormats = dataFormat;
    73         fDataPointer = dataPointer;
    74         fDataNumBytes = numDataBytes;   
    75 }
    76 // --------------------------------------------------------------------------
    77 //
    78 //! This looks for a suitable table in the fits file, i.e. that corresponds to the name and column names. (no format check yet)
    79 //! @param tableName. the base table name to be obtained. If not suitable, numbers are appened to the name
    80 //! @param allNames. the name of all columns
    81 //! @param allDataTypes. the data types of all columns
    82 //! @param allUnits. the units of the columns
    83 //! @return a pointer to the newly retrieved/created table
    84 //
    85 CCfits::Table* Fits::findSuitableTableInFitsFile(const string& tableName,const vector<string>& allNames, const vector<string>& allDataTypes, const vector<string>& allUnits)
    86 {
    87     const multimap< string, CCfits::ExtHDU * >& extMap = fFile->extension();
    88     for (int i=0;i<100;i++)
    89     {
    90         if (i==10)
    91             fMess->Error("Already 10 different tables with different formats exist in this file. Please consider re-creating the file entirely (i.e. delete it please)");
    92         ostringstream cTableName;
    93         cTableName << tableName;
    94         if (i != 0)
    95             cTableName << "-" << i;
    96         //current table name does not exist yet. return its associated fits table newly created
    97         if (extMap.find(cTableName.str()) == extMap.end())
    98         {
    99             for (multimap<string, CCfits::ExtHDU*>::const_iterator it=extMap.begin(); it!= extMap.end(); it++)
    100                 fMess->Debug(it->first);
    101             return fFile->addTable(cTableName.str(), 0, allNames, allDataTypes, allUnits);
    102         }
    103         CCfits::Table* cTable;
    104         cTable = dynamic_cast<CCfits::Table*>(extMap.find(cTableName.str())->second);
    105 
    106         if (!cTable)
    107             return NULL;//something wrong happened while getting the table pointer
    108 
    109         //now check that the table columns are the same as the service columns
    110         cTable->makeThisCurrent();
    111         const map<string, Column*> cMap = cTable->column();
    112         for (unsigned int j=0;j<allNames.size();j++)
    113             if (cMap.find(allNames[j]) == cMap.end())
    114                 continue;
    115 
    116         return cTable;
    117     }
    118     fMess->Error("One hundred trials for new table format failed. aborting");
    119     return NULL;
    120 }
     58void Fits::InitDataColumns(const vector<Description> &desc, const vector<string>& dataFormat, void* dataPointer)
     59{
     60    fDataFormats = dataFormat;
     61    fDataPointer = dataPointer;
     62
     63    //we will copy this information here. It duplicates the data, which is not great, but it is the easiest way of doing it right now
     64    if (desc.size() == dataFormat.size())
     65    {
     66        fDataColDesc = desc;
     67        return;
     68    }
     69
     70    fDataColDesc.clear();
     71    for (unsigned int i=0;i<dataFormat.size();i++)
     72    {
     73        ostringstream stt;
     74        stt << "Data" << i;
     75        fDataColDesc.push_back(Description(stt.str(), "comment", "unit"));
     76    }
     77}
     78
    12179// --------------------------------------------------------------------------
    12280//
     
    12987//! @param runNumber the runNumber for which this file is opened. 0 means nightly file.
    13088//
    131 bool Fits::Open(const string& fileName, const string& tableName, FITS* file, uint32_t* fitsCounter, MessageImp* out, int runNumber)
    132 {               
    133 //      if (fMess)
    134 //              delete fMess;
    135 //      fMess = new MessageImp(out);
     89bool Fits::Open(const string& fileName, const string& tableName, uint32_t* fitsCounter, MessageImp* out, int runNumber, FITS* file)
     90{
    13691    fRunNumber = runNumber;
    137         fMess = out;
    138         fFileName = fileName;
    139         if (file == NULL)
    140         {
    141                 try
    142                 {
    143                         fFile = new FITS(fileName, RWmode::Write);
    144                 }
    145                 catch (CCfits::FitsException e)
    146                 {                       
    147                         ostringstream str;
    148                         str << "Opening FITS file " << fileName << ": " << e.message();
    149                         fMess->Error(str);
    150                         fFile = NULL;
    151                         return false;
    152                 }       
    153                 fOwner = true;
    154                 fNumOpenFitsFiles = fitsCounter;
    155                 (*fNumOpenFitsFiles)++;
    156         }
    157         else
    158         {
    159                 fFile = file;
    160                 fOwner = false;
    161         }
    162         //concatenate the standard and data columns
    163         //do it the inneficient way first: its easier and faster to code.
    164         vector<string> allNames;
    165         vector<string> allDataTypes;
    166         vector<string> allUnits;
    167         fTotalNumBytes = 0;
    168         for (unsigned int i=0;i<fStandardColDesc.size();i++)
    169         {
    170                 allNames.push_back(fStandardColDesc[i].name);
    171                 allDataTypes.push_back(fStandardFormats[i]);
    172                 allUnits.push_back(fStandardColDesc[i].unit);
    173                 fTotalNumBytes += fStandardNumBytes[i];
    174         }
    175         //for (int i=static_cast<int>(fDataColDesc.size())-1;i>=0;i--)
    176         for (unsigned int i=0; i<fDataColDesc.size(); i++)
    177         {
    178                 if (fDataColDesc[i].name != "")
    179                         allNames.push_back(fDataColDesc[i].name);
    180                 else
    181                 {
    182                         ostringstream stt;
    183                         stt << "Data" << i;
    184                         allNames.push_back(stt.str());
    185                 }
    186                 allDataTypes.push_back(fDataFormats[i]);
    187                 allUnits.push_back(fDataColDesc[i].unit);       
    188         }
    189         fTotalNumBytes += fDataNumBytes;
    190        
    191         bool updating = false;
    192         try
    193         {
    194                 //first, let's check if the table already exist in the file
    195                 vector<string> tryToLoadName;
    196                 tryToLoadName.push_back(tableName);
    197                 fFile->read(tryToLoadName);
    198 
    199 //          const multimap< string, CCfits::ExtHDU * >& extMap = fFile->extension();
    200 //          if (extMap.find(tableName) == extMap.end())
    201 //          {
    202 //              for (multimap<string, CCfits::ExtHDU*>::const_iterator it=extMap.begin(); it!= extMap.end(); it++)
    203 //                  fMess->Debug(it->first);
    204 //              fTable = fFile->addTable(tableName, 0, allNames, allDataTypes, allUnits);
    205 //          }
    206 //          else
    207 //          {
    208 //              fTable = dynamic_cast<CCfits::Table*>(extMap.find(tableName)->second);
    209 //          }
    210         fTable = findSuitableTableInFitsFile(tableName, allNames, allDataTypes, allUnits);
    211 
    212             if (!fTable)
    213             {
    214                 fMess->Error("Table " + tableName + " could not be created nor loaded from "+fileName);
    215                 Close();
    216                 return false;
    217             }
    218             fTable->makeThisCurrent();
    219                 fCopyBuffer = new unsigned char[fTotalNumBytes];
    220                 fNumRows = fTable->rows();
    221                 if (fNumRows !=0)
    222                 {//If the file already existed, then we must load its data to memory before writing to it.
    223                         BinTable* bTable = dynamic_cast<BinTable*>(fTable);
    224                         if (!bTable)
    225                         {
    226                                 fMess->Error("Table " + tableName + " in "+fileName+" could not be converted to a binary table.");
    227                                 Close();
    228                                 return false;
    229                         }       
    230                         //read the table binary data.
    231                         vector<string> colName;
    232                         bTable->readData(true, colName);
    233 
    234                         //double check that the data was indeed read from the disk. Go through the fTable instead as colName is empty (yes, it is !)
    235                         const map<string, Column*> cMap = fTable->column();
    236 
    237             for (map<string, Column*>::const_iterator cMapIt = cMap.begin(); cMapIt != cMap.end(); cMapIt++)
    238                         {
    239                                 if (!cMapIt->second->isRead())
    240                                 {
    241                                         fMess->Error("Reading column " + cMapIt->first + " back from "+fileName+" failed.");
    242                                         Close();
    243                                         return false;
    244                                 }       
    245                         }
    246                         updating = true;
    247                 }
    248 
    249         }
    250         catch(CCfits::FitsException e)
    251         {
    252                 ostringstream str;
    253                 str << "Opening or creating table " << tableName << " in " << fileName << ": " << e.message();
    254                 fMess->Error(str);
    255                 fTable = NULL;
    256                 Close();
    257                 return false;
    258         }
    259                        
    260         if (!updating)
    261                 return WriteHeaderKeys();
    262 
    263         return true;
    264 }
    265 // --------------------------------------------------------------------------
    266 //
    267 //!This writes a single header key in the currently open file.
    268 //!@param name the key
    269 //!@param value the key value
    270 //!@param a comment explaining the meaning of the key
    271 template <typename T>
    272 bool Fits::WriteSingleHeaderKey(const string &name, const T &value, const string &comment)
    273 {
    274         try
    275         {
    276                 fTable->addKey(name, value, comment);
    277         }
    278         catch (CCfits::FitsException e)
    279         {
    280                 ostringstream str;
    281                 str << "Could not add header keys in file " << fFileName << " reason: " << e.message();
    282                 fMess->Error(str);
    283                 return false;
    284         }
    285         return true;
    286 }
     92    fMess = out;
     93
     94    if (fFile)
     95    {
     96        fMess->Error("File already open...");
     97        return false;
     98    }
     99
     100    fFile = new FitsFile(*fMess);
     101
     102    if (file == NULL)
     103    {
     104        if (!fFile->OpenFile(fileName, true))
     105            return false;
     106
     107        fNumOpenFitsFiles = fitsCounter;
     108        (*fNumOpenFitsFiles)++;
     109    }
     110    else
     111    {
     112        if (!fFile->SetFile(file))
     113            return false;
     114    }
     115
     116    //concatenate the standard and data columns
     117    //do it the inneficient way first: its easier and faster to code.
     118    for (unsigned int i=0;i<fStandardColDesc.size();i++)
     119    {
     120        fFile->AddColumn(fStandardColDesc[i].name, fStandardFormats[i],
     121                         fStandardColDesc[i].unit);
     122    }
     123
     124    for (unsigned int i=0; i<fDataColDesc.size(); i++)
     125    {
     126        string name = fDataColDesc[i].name;
     127        if (name.empty())
     128        {
     129            ostringstream stt;
     130            stt << "Data" << i;
     131            name = stt.str();
     132        }
     133
     134        fFile->AddColumn(name, fDataFormats[i], fDataColDesc[i].unit);
     135    }
     136
     137    try
     138    {
     139        if (!fFile->OpenNewTable(tableName, 100))
     140        {
     141            Close();
     142            return false;
     143        }
     144
     145        fCopyBuffer.resize(fFile->GetDataSize());
     146
     147        return fFile->GetNumRows()==0 ? true : WriteHeaderKeys();
     148    }
     149    catch (const CCfits::FitsException &e)
     150    {
     151        fMess->Error("Opening or creating table '"+tableName+"' in '"+fileName+"': "+e.message());
     152
     153        fFile->fTable = NULL;
     154        Close();
     155        return false;
     156    }
     157}
     158
    287159// --------------------------------------------------------------------------
    288160//
     
    291163bool Fits::WriteHeaderKeys()
    292164{
    293     if (!fTable)
    294         return false;
    295 
    296     const Time now;
    297     if (!WriteSingleHeaderKey("EXTREL",   1.0f, "Release Number")) return false;
    298     if (!WriteSingleHeaderKey("TELESCOP", "FACT", "Telescope that acquired this data")) return false;
    299     if (!WriteSingleHeaderKey("ORIGIN",   "ISDC", "Institution that wrote the file")) return false;
    300     if (!WriteSingleHeaderKey("CREATOR",  "fadctrl", "Program that wrote this file (FACT++ datalogger)")) return false;
    301     if (!WriteSingleHeaderKey("PACKAGE",   PACKAGE_NAME, "Package name")) return false;
    302     if (!WriteSingleHeaderKey("VERSION",   PACKAGE_VERSION, "Package description")) return false;
    303     if (!WriteSingleHeaderKey("COMPILED",  __DATE__" "__TIME__, "Compile time")) return false;
    304     if (!WriteSingleHeaderKey("REVISION",  REVISION, "SVN revision")) return false;
    305     if (!WriteSingleHeaderKey("DATE",     now.Iso(), "File creation date")) return false;
    306     if (!WriteSingleHeaderKey("NIGHT",    now.NightAsInt(), "Night as int")) return false;
    307     if (!WriteSingleHeaderKey("TIMESYS",  "UTC", "Time systen")) return false;
    308     if (!WriteSingleHeaderKey("TSTART",   "", "Time of the first receied data")) return false;
    309     if (!WriteSingleHeaderKey("TSTOP",    "", "Time of the last receied data")) return false;
     165    if (!fFile->fTable)
     166        return false;
     167
     168    if (!fFile->WriteDefaultKeys("datalogger"))
     169        return false;
     170
     171    if (!fFile->WriteKeyNT("TSTART", "", "Time of the first receied data"))
     172        return false;
     173
     174    if (!fFile->WriteKeyNT("TSTOP",  "", "Time of the last receied data"))
     175        return false;
     176
    310177    return true;
    311178}
     179
    312180// --------------------------------------------------------------------------
    313181//
     
    322190    {
    323191        const char *charSrc = reinterpret_cast<char*>(fStandardPointers[i]);
    324         reverse_copy(charSrc, charSrc+fStandardNumBytes[i], &fCopyBuffer[shift]);
     192        reverse_copy(charSrc, charSrc+fStandardNumBytes[i], fCopyBuffer.data()+shift);
    325193        shift += fStandardNumBytes[i];
    326194    }
     
    329197    {
    330198        //now take care of the DIM data. The Converter is here for that purpose
    331         conv.ToFits(&fCopyBuffer[shift], fDataPointer, fDataNumBytes);
     199        conv.ToFits(fCopyBuffer.data()+shift, fDataPointer, fCopyBuffer.size()-shift);
    332200    }
    333201    catch (const runtime_error &e)
    334202    {
    335203        ostringstream str;
    336         str << fFileName << ": " << e.what();
     204        str << fFile->GetName() << ": " << e.what();
    337205        fMess->Error(str);
    338206        return false;
    339207    }
    340208
    341     fTable->makeThisCurrent();
    342 
    343     int status(0);
    344     if (fits_insert_rows(fTable->fitsPointer(), fNumRows, 1, &status))
    345     {
    346         ostringstream str;
    347         char text[30];
    348         fits_get_errstatus(status, text);
    349         str << "Inserting row into " << fFileName << ": " << text << " (fits_insert_rows, rc=" << status << ")";
    350         fMess->Error(str);
     209    // This is not necessary, is it?
     210    // fFile->fTable->makeThisCurrent();
     211
     212    if (!fFile->AddRow())
     213    {
    351214        Close();
    352215        return false;
    353216    }
    354217
    355     fNumRows++;
     218    if (!fFile->WriteData(fCopyBuffer))
     219    {
     220        Close();
     221        return false;
     222    }
    356223
    357224    //the first standard variable is the current MjD
    358225    if (fEndMjD==0)
    359226    {
     227        // FIXME: Check error?
    360228        const double doubleValue = *reinterpret_cast<double*>(fStandardPointers[0]);
    361         WriteSingleHeaderKey("TSTART", Time(doubleValue).Iso(),
    362                              "Time of the first received data");
     229        fFile->WriteKeyNT("TSTART", Time(doubleValue).Iso(),
     230                          "Time of the first received data");
    363231    }
    364232    fEndMjD = *reinterpret_cast<double*>(fStandardPointers[0]);
    365233
    366     //data copied to buffer, can write to fits
    367     if (fits_write_tblbytes(fFile->fitsPointer(), fNumRows, 1, fTotalNumBytes, fCopyBuffer, &status))
    368     {
    369         char text[30];//max length of cfitsio error strings (from doc)
    370         fits_get_errstatus(status, text);
    371         ostringstream str;
    372         str << "Writing FITS row " << fNumRows << " in " << fFileName << ": " << text << " (file_write_tblbytes, rc=" << status << ")";
    373         fMess->Error(str);
    374         Close();
    375         return false;
    376     }
    377234    return true;
    378235}
     
    385242void Fits::Close()
    386243{
    387 //WARNING: do NOT delete the table as it gets deleted by the fFile object
    388 //                      if (fTable != NULL)
    389 //                              delete fTable;
    390         if (fFile != NULL && fOwner)
    391         {
    392 //          CCfits::FITS* backupFits = fFile;
    393 //          fFile = NULL;
    394             WriteSingleHeaderKey("TSTOP", Time(fEndMjD).Iso(), "Time of the last receied data");
    395             delete fFile;
    396 
    397         fMess->Info("Closed: "+fFileName);
     244    if (!fFile)
     245        return;
     246
     247    if (fFile->IsOpen() && fFile->IsOwner())
     248    {
     249        // FIMXE: Check for error? (It is allowed that fFile is NULL)
     250        fFile->WriteKeyNT("TSTOP", Time(fEndMjD).Iso(),
     251                          "Time of the last receied data");
     252    }
     253
     254    if (fFile->IsOwner())
     255    {
    398256        if (fNumOpenFitsFiles != NULL)
    399257            (*fNumOpenFitsFiles)--;
    400         }
    401         fFile = NULL;
    402         if (fCopyBuffer != NULL)
    403                 delete [] fCopyBuffer;
    404         fCopyBuffer = NULL;
    405 
    406 //fMess is the MessageImp part of the dataLogger itself. Thus it should NOT be deleted by the Fits files destructor.
    407 //      if (fMess)
    408 //              delete fMess;
    409         fMess = NULL;
     258    }
     259
     260    delete fFile;
     261    fFile = NULL;
     262
     263    fMess = NULL;
    410264}
    411265
     
    414268int Fits::GetWrittenSize() const
    415269{
    416         if (!IsOpen())
    417                 return 0;
    418                
    419         struct stat st;
    420         if (stat(fFileName.c_str(), &st))
    421                 return 0;
    422 
    423         return st.st_size;
    424 }
     270    if (!IsOpen())
     271        return 0;
     272
     273    struct stat st;
     274    if (stat(fFile->GetName().c_str(), &st))
     275        return 0;
     276
     277    return st.st_size;
     278}
     279
     280/*
     281 To be done:
     282 - Check the check for column names in opennewtable
     283 - If Open return false we end in an infinite loop (at least if
     284   the dynamic cats to Bintable fails.
     285
     286*/
Note: See TracChangeset for help on using the changeset viewer.