Changeset 10949


Ignore:
Timestamp:
06/09/11 14:28:21 (14 years ago)
Author:
tbretz
Message:
Added some code to write FITS files.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/FACT++/src/EventBuilderWrapper.h

    r10942 r10949  
    1515#include <boost/date_time/posix_time/posix_time_types.hpp>
    1616
     17#include <CCfits/CCfits>
     18
    1719#include "EventBuilder.h"
    1820
     
    2123    extern int CloseRunFile(uint32_t runId, uint32_t closeTime);
    2224}
     25
     26class DataFileImp
     27{
     28    uint32_t fRunId;
     29
     30public:
     31    DataFileImp(uint32_t id) : fRunId(id) { }
     32
     33    virtual bool OpenFile(uint32_t runid, RUN_HEAD* h) = 0;
     34    virtual bool Write(EVENT *) = 0;
     35    virtual bool Close(RUN_TAIL * = 0) = 0;
     36
     37    uint32_t GetRunId() const { return fRunId; }
     38};
     39
     40
     41#include "FAD.h"
     42
     43class DataFileRaw : public DataFileImp
     44{
     45public:
     46    DataFileRaw(uint32_t id) : DataFileImp(id)  { }
     47    ~DataFileRaw() { Close(); }
     48
     49    virtual bool OpenFile(uint32_t, RUN_HEAD* ) { return true; }
     50    virtual bool Write(EVENT *) { return true; }
     51    virtual bool Close(RUN_TAIL * = 0) { return true; }
     52};
     53
     54
     55class DataFileFits : public DataFileImp
     56{
     57    CCfits::FITS*  fFile;        /// The pointer to the CCfits FITS file
     58    CCfits::Table* fTable;       /// The pointer to the CCfits binary table
     59
     60    uint64_t fNumRows;                ///the number of rows that have been written already to the FITS file.
     61    uint32_t fRoi;                ///the number of rows that have been written already to the FITS file.
     62
     63public:
     64    DataFileFits(uint32_t runid) : DataFileImp(runid), fFile(0)
     65    {
     66    }
     67
     68    // --------------------------------------------------------------------------
     69    //
     70    //! Default destructor
     71    //! The Fits file SHOULD have been closed already, otherwise the informations
     72    //! related to the RUN_TAIL will NOT be written to the file.
     73    //
     74    ~DataFileFits() { Close(); }
     75
     76    // --------------------------------------------------------------------------
     77    //
     78    //! Add a new column to the vectors storing the column data.
     79    //! @param names the vector of string storing the columns names
     80    //! @param types the vector of string storing the FITS data format
     81    //! @param numElems the number of elements in this column
     82    //! @param type the char describing the FITS data format
     83    //! @param name the name of the particular column to be added.
     84    //
     85    inline void AddColumnEntry(vector<string>& names, vector<string>& types, int numElems, char type, string name)
     86    {
     87        names.push_back(name);
     88
     89        ostringstream str;
     90        if (numElems != 1)
     91            str << numElems;
     92        str << type;
     93        types.push_back(str.str());
     94    }
     95
     96    // --------------------------------------------------------------------------
     97    //
     98    //! Writes a single header key entry
     99    //! @param name the name of the key
     100    //! @param value its value
     101    //! @param comment the comment associated to that key
     102    //
     103    //FIXME this function is a duplicate from the class Fits. should we try to merge it ?
     104    template <typename T>
     105    void WriteKey(const string &name, const T &value, const string &comment)
     106    {
     107        try
     108        {
     109            fTable->addKey(name, value, comment);
     110        }
     111        catch (CCfits::FitsException e)
     112        {
     113            ostringstream str;
     114            str << "Could not add header key ";
     115            //TODO pipe the error message somewhere
     116        }
     117    }
     118
     119    template <typename T>
     120    void WriteKey(const string &name, const int idx, const T &value, const string &comment)
     121    {
     122        ostringstream str;
     123        str << name << idx;
     124
     125        WriteKey(str.str(), value, comment);
     126    }
     127
     128    // --------------------------------------------------------------------------
     129    //
     130    //! This creates an appropriate file name for a particular run number and type
     131    //! @param runNumber the run number for which a filename is to be created
     132    //! @param runType an int describing the kind of run. 0=Data, 1=Pedestal, 2=Calibration, 3=Calibrated data
     133    //! @param extension a string containing the extension to be appened to the file name
     134    //
     135    string FormFileName(uint32_t runNumber, uint32_t runType, string extension)
     136    {
     137        //TODO where am I supposed to get the base directory from ?
     138        //TODO also, for creating subsequent directories, should I use the functions from the dataLogger ?
     139        string baseDirectory = "./Run";
     140        ostringstream result;
     141        result << baseDirectory;
     142        result << Time::fmt("/%Y/%m/%d/") << (Time() - boost::posix_time::time_duration(12,0,0));
     143        result << setfill('0') << setw(8) << runNumber;
     144        result << "_001_";
     145        switch (runType)
     146        {
     147        case 0:
     148            result << 'D';
     149            break;
     150        case 1:
     151            result << 'P';
     152            break;
     153        case 2:
     154            result << 'C';
     155            break;
     156        case 3:
     157            result << 'Y';
     158            break;
     159        default:
     160            //TODO pipe this error message to the appropriate error stream
     161            cout << "Error unexpected event" << endl;
     162        };
     163        result << "_data." << extension;
     164
     165        return result.str();
     166    }
     167
     168    // --------------------------------------------------------------------------
     169    //
     170    //! DataFileFits constructor. This is the one that should be used, not the default one (parameter-less)
     171    //! @param runid This parameter should probably be removed. I first thought it was the run number, but apparently it is not
     172    //! @param h a pointer to the RUN_HEAD structure that contains the informations relative to this run
     173    //
     174    bool OpenFile(uint32_t /*runid*/, RUN_HEAD* h)
     175    {
     176        //Form filename, based on runid and run-type
     177        string fileName = FormFileName(h->FADhead[0].runnumber, h->RunType, "fits");
     178
     179        //create the FITS object
     180        try
     181        {
     182            fFile = new CCfits::FITS(fileName, CCfits::RWmode::Write);
     183        }
     184        catch (CCfits::FitsException e)
     185        {
     186            ostringstream str;
     187            str << "Could not open FITS file " << fileName << " reason: " << e.message();
     188            //TODO display the message somewhere
     189
     190            return false;
     191        }
     192
     193        //create columns according to header
     194        ostringstream arrayTypes;
     195
     196        // uint32_t EventNum ;       // EventNumber as from FTM
     197        // uint16_t TriggerType ;    // Trigger Type from FTM
     198        // uint32_t SoftTrig ;       // SoftTrigger Info (TBD)
     199        // uint32_t PCTime ;         // when did event start to arrive at PC
     200        // uint32_t BoardTime[NBOARDS];//
     201        // int16_t  StartPix[NPIX];  // First Channel per Pixel (Pixels sorted according Software ID)  ; -1 if not filled
     202        // int16_t  StartTM[NTMARK]; // First Channel for TimeMark (sorted Hardware ID) ; -1 if not filled
     203        // uint16_t Adc_Data[];      // final length defined by malloc ....
     204
     205        vector<string> colNames;
     206        vector<string> dataTypes;
     207        AddColumnEntry(colNames, dataTypes, 1,              'V', "EventNum");
     208        AddColumnEntry(colNames, dataTypes, 1,              'U', "TriggerType");
     209        AddColumnEntry(colNames, dataTypes, 1,              'V', "SoftTrig");
     210        AddColumnEntry(colNames, dataTypes, 1,              'V', "PCTime");
     211        AddColumnEntry(colNames, dataTypes, NBOARDS,        'V', "BoardTime");
     212        AddColumnEntry(colNames, dataTypes, NPIX,           'I', "StartPix");
     213        AddColumnEntry(colNames, dataTypes, NTMARK,         'I', "StartTM");
     214        AddColumnEntry(colNames, dataTypes, NPIX*h->Nroi,   'U', "Data");
     215
     216        fRoi = h->Nroi;
     217
     218        //actually create the table
     219        try
     220        {
     221            fTable = fFile->addTable("Events", 0, colNames, dataTypes);
     222            if (fTable->rows() != 0)
     223            {
     224                ostringstream str;
     225                str << "Error: table created on the fly looks non-empty.";
     226                //TODO giev the error text to some error handler
     227                //FIXME I guess that this error checking is useless. remove it for performances.
     228            }
     229        }
     230        catch(CCfits::FitsException e)
     231        {
     232            ostringstream str;
     233            str << "Could not create FITS table " << "Events" << " in file " << fileName << " reason: " << e.message();
     234            //TODO give the error text to some error handler
     235
     236            Close();
     237            return false;
     238        }
     239
     240        //write header data
     241        //first the "standard" keys
     242        string stringValue;
     243        WriteKey("EXTREL",   1.0f,   "Release Number");
     244        WriteKey("TELESCOP", "FACT", "Telescope that acquired this data");
     245        WriteKey("ORIGIN",   "ISDC", "Institution that wrote the file");
     246        WriteKey("CREATOR",  "FACT++ Event Builder", "Program that wrote this file");
     247
     248        stringValue = Time().GetAsStr();
     249        stringValue[10]= 'T';
     250        WriteKey("DATE",     stringValue, "File creation data");
     251        WriteKey("TIMESYS",  "TT",        "Time frame system");
     252        WriteKey("TIMEUNIT", "d",         "Time unit");
     253        WriteKey("TIMEREF",  "UTC",       "Time reference frame");
     254        //FIXME should we also put the start and stop time of the received data ?
     255        //now the events header related variables
     256        WriteKey("VERSION",  h->Version,  "Builder version");
     257        WriteKey("RUNTYPE",  h->RunType,  "Type of run");
     258        WriteKey("NBOARD",   h->NBoard,   "Number of acquisition boards");
     259        WriteKey("NPIX",     h->NPix,     "Number of pixels");
     260        WriteKey("NTM",      h->NTm,      "Number of Time marks");
     261        WriteKey("NROI",     h->Nroi,     "Number of slices per pixels");
     262
     263        //now the boards related keywords
     264        for (int i=0; i<h->NBoard; i++)
     265        {
     266            const PEVNT_HEADER &hh = h->FADhead[i];
     267
     268            WriteKey("STPKGFG", i, hh.start_package_flag,
     269                     "Start package flag");
     270
     271            WriteKey("PKGLEN",  i, hh.package_length,
     272                     "Package length");
     273
     274            WriteKey("VERNO",   i, hh.version_no,
     275                     "Version number");
     276
     277            WriteKey("PLLLCK",  i, hh.PLLLCK,
     278                     "");
     279/*
     280            WriteKey("TRIGCRC", i, hh.trigger_crc,
     281                     "Trigger CRC");
     282
     283            WriteKey("TRIGTYP", i, hh.trigger_type,
     284                     "Trigger type");
     285
     286            WriteKey("TRIGID",  i, hh.trigger_id,
     287                     "Trigger ID");
     288
     289            WriteKey("EVTCNTR", i, hh.fad_evt_counter,
     290                     "FAD Event Counter");
     291*/
     292            WriteKey("REFCLK",  i, hh.REFCLK_frequency,
     293                     "Reference Clock Frequency");
     294
     295            WriteKey("BOARDID", i, hh.board_id,
     296                     "Board ID");
     297
     298            WriteKey("PHASESH", i, hh.adc_clock_phase_shift,
     299                     "ADC clock phase shift");
     300
     301            //WriteKey("TRGGEN",  i, hh.number_of_triggers_to_generate,
     302            //         "Number of triggers to generate");
     303
     304            WriteKey("PRESC",   i, hh.trigger_generator_prescaler,
     305                    "Trigger generator prescaler");
     306
     307            WriteKey("DNA",     i, hh.DNA,       "DNA");
     308            WriteKey("TIME",    i, hh.time,      "Time");
     309            WriteKey("RUNNB",   i, hh.runnumber, "Run number");
     310/*
     311            for (int j=0;j<NTemp;j++)
     312            {
     313                str.str(""); str2.str("");
     314                str << "DRS_T" << i << j;
     315                str2 << "DRS temperature #" << i << " " << j;
     316                WriteKey(str.str(), h->FADhead[i].drs_temperature[j], str2.str());
     317            }
     318*/
     319            for (int j=0;j<NDAC;j++)
     320                WriteKey("DAC", i*NDAC+j, hh.dac[j], "DAC");
     321
     322            //Last but not least, add header keys that will be updated when closing the file
     323            WriteFooter(NULL);
     324        }
     325
     326        return true;
     327    }
     328
     329
     330    int WriteColumns(size_t &start, size_t size, void *e)
     331    {
     332        int status = 0;
     333        fits_write_tblbytes(fFile->fitsPointer(), fNumRows, start, size, reinterpret_cast<unsigned char*>(e), &status);
     334        start += size;
     335        return status;
     336    }
     337
     338    // --------------------------------------------------------------------------
     339    //
     340    //! This writes one event to the file
     341    //! @param e the pointer to the EVENT
     342    //
     343    virtual bool Write(EVENT *e)
     344    {
     345        //FIXME As discussed earlier, we do not swap the bytes yet.
     346        fTable->makeThisCurrent();
     347
     348        //insert a new row
     349        int status(0);
     350        if (fits_insert_rows(fTable->fitsPointer(), fNumRows, 1, &status))
     351        {
     352            ostringstream str;
     353            str << "Could not insert a row in fits file";
     354            //TODO pipe this error message to the appropriate error stream
     355        }
     356        fNumRows++;
     357
     358        const int sh = sizeof(PEVNT_HEADER)-1;
     359
     360        // column size pointer
     361        size_t col = 1;
     362        if (!WriteColumns(col, sh + NPIX*fRoi*2, e))
     363            return true;
     364
     365        //TODO output an error
     366        return false;
     367
     368        /*
     369        //write the data, chunk by chunk
     370        //FIXME hard-coded size corresponds to current variables of the event, in bytes.
     371        //FIXME no padding was taken into account. Because smallest member is 2 bytes, I don't think that this should be a problem.
     372        const long sizeInBytesOfEventBeforePointers = 16;
     373
     374        long col = 1;
     375        if (FitsWriteTblBytes(col, sizeInBytesOfEventBeforePointers, e))
     376        {
     377            //TODO output an error
     378            return false;
     379        }
     380        if (FitsWriteTblBytes(col, NBOARDS*2, e->BoardTime))
     381        {
     382            //TODO output an error
     383            return false;
     384        }
     385        if (FitsWriteTblBytes(col, NPIX*2, e->StartPix))
     386        {
     387            //TODO output an error
     388            return false;
     389        }
     390        if (FitsWriteTblBytes(col, NTMARK*2, e->StartTM))
     391        {
     392            //TODO output an error
     393            return false;
     394        }
     395        if (FitsWriteTblBytes(col, NPIX*fRoi*2, e->Adc_Data))
     396        {
     397            //TODO output an error
     398            return false;
     399        }
     400        return true;*/
     401    }
     402
     403    void WriteFooter(RUN_TAIL *rt)
     404    {
     405        //write final header keys
     406        fTable->makeThisCurrent();
     407
     408        WriteKey("NBEVTOK",  rt ? rt->nEventsOk  : uint32_t(0),
     409                 "How many events were written");
     410
     411        WriteKey("NBEVTREJ", rt ? rt->nEventsRej : uint32_t(0),
     412                 "How many events were rejected by SW-trig");
     413
     414        WriteKey("NBEVTBAD", rt ? rt->nEventsBad : uint32_t(0),
     415                 "How many events were rejected by Error");
     416
     417        //FIXME shouldn't we convert start and stop time to MjD first ?
     418        //FIXME shouldn't we also add an MjD reference ?
     419
     420        WriteKey("TSTART",   rt ? rt->PCtime0    : uint32_t(0),
     421                 "Time when first event received");
     422
     423        WriteKey("TSTOP",    rt ? rt->PCtimeX    : uint32_t(0),
     424                 "Time when last event received");
     425    }
     426
     427    // --------------------------------------------------------------------------
     428    //
     429    //! Closes the file, and before this it write the TAIL data
     430    //! @param rt the pointer to the RUN_TAIL data structure
     431    //
     432    virtual bool Close(RUN_TAIL *rt = 0)
     433    {
     434        if (!fFile)
     435            return false;
     436
     437        WriteFooter(rt);
     438
     439        delete fFile;
     440        fFile = NULL;
     441
     442        return true;
     443    }
     444
     445};
    23446
    24447class EventBuilderWrapper
     
    212635    // -------------- Mapped event builder callbacks ------------------
    213636
    214     class DataFileImp
    215     {
    216         uint32_t fRunId;
    217 
    218     public:
    219         DataFileImp(uint32_t id) : fRunId(id) { }
    220 
    221         virtual bool Write() = 0;
    222         virtual bool Close() = 0;
    223 
    224         uint32_t GetRunId() const { return fRunId; }
    225     };
    226 
    227 
    228     class DataFileRaw : public DataFileImp
    229     {
    230     public:
    231         DataFileRaw(uint32_t id) : DataFileImp(id)  { }
    232         ~DataFileRaw() { Close(); }
    233 
    234         virtual bool Write() { return true; }
    235         virtual bool Close() { return true; }
    236     };
    237 
    238     class DataFileFits : public DataFileImp
    239     {
    240     public:
    241         DataFileFits(uint32_t id) :DataFileImp(id) { }
    242         ~DataFileFits() { Close(); }
    243 
    244         virtual bool Write() { return true; }
    245         virtual bool Close() { return true; }
    246     };
    247 
    248637    vector<DataFileImp*> fFiles;
    249638
     
    259648    {
    260649        // Check if file already exists...
    261         DataFileImp *file = NULL;
     650        DataFileImp *file = fFitsFormat ?
     651            static_cast<DataFileImp*>(new DataFileFits(runid)) :
     652            static_cast<DataFileImp*>(new DataFileRaw(runid));
     653
    262654        try
    263655        {
    264             file = fFitsFormat ?
    265                 static_cast<DataFileImp*>(new DataFileFits(runid)) :
    266                 static_cast<DataFileImp*>(new DataFileRaw(runid));
     656            if (!file->OpenFile(runid, h))
     657                return 0;
    267658        }
    268659        catch (const exception &e)
     
    311702        cout << " tim=" << e->PCTime << endl;
    312703
    313         if (!file->Write())
     704        if (!file->Write(e))
    314705            return -1;
    315706
     
    333724    }
    334725
    335     int runClose(FileHandle_t handler, RUN_TAIL *, size_t)
     726    int runClose(FileHandle_t handler, RUN_TAIL *tail, size_t)
    336727    {
    337728        DataFileImp *file = reinterpret_cast<DataFileImp*>(handler);
     
    357748        //fDimFiles.update();
    358749
    359         const bool rc = file->Close();
     750        const bool rc = file->Close(tail);
    360751        if (!rc)
    361752        {
     
    395786    void factOut(int severity, int err, char *message)
    396787    {
    397         //replace(message, message+strlen(message), '\n', ' ');
    398 
    399788        // FIXME: Make the output to the console stream thread-safe
    400789        ostringstream str;
Note: See TracChangeset for help on using the changeset viewer.