source: trunk/FACT++/src/FactFits.cc @ 10365

Last change on this file since 10365 was 10365, checked in by lyard, 9 years ago
Moved from FactFits to Fits
File size: 8.1 KB
Line 
1// **************************************************************************
2/** @class FactFits
3
4@brief FITS writter for the FACT project.
5
6The FactFits class is able to open, manage and update FITS files.
7
8The file columns should be given to the class before the file is openned. Once
9a file has been created, the structure of its columns cannot be changed. Only
10row can be added.
11
12This class relies on the CCfits and CFitsIO packages.
13
14*/
15// **************************************************************************
16#include "Fits.h"
17// --------------------------------------------------------------------------
18//
19//! This gives a standard variable to the file writter.
20//! This variable should not be related to the DIM service being logged.
21//! @param desc the description of the variable to add
22//! @param dataFormat the FITS data format corresponding to the variable to add.
23//! @param dataPointer the memory location where the variable is stored
24//! @param numDataBytes the number of bytes taken by the variable
25//
26void Fits::AddStandardColumn(Description& desc, std::string dataFormat, void* dataPointer, long unsigned int numDataBytes)
27{
28        fStandardColDesc.push_back(desc);
29        fStandardFormats.push_back(dataFormat);
30        fStandardPointers.push_back(dataPointer);
31        fStandardNumBytes.push_back(numDataBytes);
32}
33// --------------------------------------------------------------------------
34//
35//! This gives the file writter access to the DIM data
36//! @param desc a vector containing the description of all the columns to log
37//! @param dataFormat a vector containing the FITS data format of all the columsn to log
38//! @param dataPointer the memory location where the DIM data starts
39//! @param numDataBytes the number of bytes taken by the DIM data.
40//     
41void Fits::InitDataColumns(std::vector<Description> desc, std::vector<std::string>& dataFormat, void* dataPointer, int numDataBytes)
42{//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
43        if (desc.size() == dataFormat.size())
44        {
45                fDataColDesc = desc;
46        }
47        else
48        {
49                for (unsigned int i=0;i<dataFormat.size();i++)
50                {
51                        std::stringstream stt;
52                        stt << "Data" << i;
53                        fDataColDesc.push_back(Description(stt.str(), "unit", "comment"));     
54                }
55        }               
56        fDataFormats = dataFormat;
57        fDataPointer = dataPointer;
58        fDataNumBytes = numDataBytes;   
59}
60// --------------------------------------------------------------------------
61//
62//! This opens the FITS file (after the columns have been passed)
63//! @param fileName the filename with complete or relative path of the file to open
64//! @param tableName the name of the table that will receive the logged data.
65//
66void Fits::Open(const std::string& fileName, const std::string& tableName)
67{               
68        try
69        {
70                fFile = new FITS(fileName, RWmode::Write);
71        }
72        catch (FITS::CantOpen)
73        {
74                std::ostringstream err;
75                err << "Could not open " << fileName << ".Skipping it.";
76                throw runtime_error(err.str()); 
77        }       
78        //concatenate the standard and data columns
79        //do it the inneficient way first: its easier and faster to code.
80        std::vector<std::string> allNames;
81        std::vector<std::string> allDataTypes;
82        std::vector<std::string> allUnits;
83        fTotalNumBytes = 0;
84        for (unsigned int i=0;i<fStandardColDesc.size();i++)
85        {
86                allNames.push_back(fStandardColDesc[i].name);
87                allDataTypes.push_back(fStandardFormats[i]);
88                allUnits.push_back(fStandardColDesc[i].unit);
89                fTotalNumBytes += fStandardNumBytes[i];
90        }
91        //for (int i=static_cast<int>(fDataColDesc.size())-1;i>=0;i--)
92        for (int i=0; i< static_cast<int>(fDataColDesc.size()); i++)
93        {
94                if (fDataColDesc[i].name != "")
95                        allNames.push_back(fDataColDesc[i].name);
96                else 
97                {
98                        std::stringstream stt;
99                        stt << "Data" << i;
100                        allNames.push_back(stt.str());
101                }
102                allDataTypes.push_back(fDataFormats[i]);
103                allUnits.push_back(fDataColDesc[i].unit);       
104        }
105        fTotalNumBytes += fDataNumBytes;
106       
107        bool updating = false;
108        try
109        {
110                fTable = fFile->addTable(tableName, 0, allNames, allDataTypes, allUnits);
111                fCopyBuffer = new unsigned char[fTotalNumBytes]; 
112                fNumRows = fTable->rows();
113                if (fNumRows !=0)
114                {//If the file already existed, then we must load its data to memory before writing to it.
115                        std::vector<std::string> tableNameString;
116                        tableNameString.push_back(tableName);
117                        fFile->read(tableNameString);   
118                        std::map<std::string, Column*> cMap = fTable->column();
119                        std::map<std::string, Column*>::iterator cMapIt;
120                        for (cMapIt = cMap.begin(); cMapIt != cMap.end(); cMapIt++)
121                        {
122                                //TODO this only works for scalar columns I assume. upgrade it to fully read vector columns
123                                cMapIt->second->readData(1, fNumRows);         
124                        }       
125                        updating = true;
126                }
127        }
128        catch(CCfits::FitsError e)
129        {
130                std::ostringstream err;
131                err << "Error when adding table " << tableName << " : " << e.message();
132                throw runtime_error(err.str());
133        }
134                       
135        fEndMjD = * static_cast<double*>(fStandardPointers[0]);
136        if (!updating)
137                WriteHeaderKeys();
138}
139// --------------------------------------------------------------------------
140//
141//! This writes the standard header
142//
143void Fits::WriteHeaderKeys()
144{
145        std::string name;
146        std::string comment;
147       
148        float floatValue;
149        double doubleValue;
150        std::string stringValue;
151                       
152        name = "EXTREL";
153        comment = "Release Number";
154        floatValue = 1.0f;
155        fTable->addKey(name, floatValue, comment);
156                       
157        name = "BASETYPE";
158        comment = "Base class that wrote this file";
159        stringValue = "CCFits_table";
160        fTable->addKey(name, stringValue, comment);
161                       
162        name = "TELESCOP";
163        comment = "Telescope that acquired this data";
164        stringValue = "FACT";
165        fTable->addKey(name, stringValue, comment);
166                       
167        name = "ORIGIN";
168        comment = "Institution that wrote the file";
169        stringValue = "ISDC";
170        fTable->addKey(name, stringValue, comment);
171                       
172        name = "CREATOR";
173        comment = "Program that wrote this file";
174        stringValue = "FACT++_DataLogger";
175        fTable->addKey(name, stringValue, comment);
176                       
177        name = "DATE";
178        stringValue = Time().GetAsStr();
179        stringValue[10] = 'T';
180        comment = "File creation date";
181        fTable->addKey(name, stringValue, comment);
182                       
183        name = "TIMEREF";
184        stringValue = "UTC";
185        comment = "Time reference system";
186        fTable->addKey(name, stringValue, comment);
187                       
188        name = "TSTART";
189        doubleValue = fEndMjD;
190        comment = "Time of the first received data";
191        fTable->addKey(name, doubleValue, comment);
192                       
193        //More ?
194}
195// --------------------------------------------------------------------------
196//
197//! This writes one line of data to the file.
198//! @param conv the converter corresponding to the service being logged
199//
200void Fits::Write(Converter* conv)
201{
202        try
203        {
204                fTable->insertRows(fNumRows);
205        }
206        catch(CCfits::FitsError e)
207        {
208                std::ostringstream err;
209                err << "Error when inserting a row: " << e.message();
210                throw runtime_error(err.str());
211        }
212        fNumRows++;
213                       
214        //the first standard variable is the current MjD
215        fEndMjD = * static_cast<double*>(fStandardPointers[0]);
216                       
217        //first copy the standard variables to the copy buffer
218        int shift = 0;
219
220        for (unsigned int i=0;i<fStandardNumBytes.size();i++)
221        {
222                for (int j=0; j<fStandardNumBytes[i]; j++)
223                        fCopyBuffer[shift+j] = static_cast<char*>(fStandardPointers[i])[fStandardNumBytes[i]-(j+1)];
224                shift+= fStandardNumBytes[i];   
225        }
226
227        //now take care of the DIM data. The Converter is here for that purpose
228        conv->ToFits(static_cast<void*>(&fCopyBuffer[shift]), fDataPointer, fDataNumBytes);
229                         
230        //data copied to buffer, can write to fits
231        int status = 0;
232        //TODO check the status after the write operation
233        fits_write_tblbytes(fFile->fitsPointer(), fNumRows, 1, fTotalNumBytes, fCopyBuffer, &status);
234
235        //This forces the writting of each row to the disk. Otherwise all rows are written when the file is closed.
236        fFile->flush();
237}
238// --------------------------------------------------------------------------
239//
240//! This closes the currently openned FITS file.
241//! it also updates the header to reflect the time of the last logged row
242//     
243void Fits::Close() 
244{
245//WARNING: do NOT delete the table as it gets deleted by the fFile object
246//                      if (fTable != NULL)
247//                              delete fTable;
248        std::string name = "TEND";
249        double doubleValue = fEndMjD;
250        std::string comment = "Time of the last received data";
251        fTable->addKey(name, doubleValue, comment);
252
253        if (fFile != NULL)
254                delete fFile;
255        fFile = NULL;
256        if (fCopyBuffer != NULL)
257                delete [] fCopyBuffer;
258        fCopyBuffer = NULL;
259}
Note: See TracBrowser for help on using the repository browser.