source: trunk/FACT++/src/Fits.cc @ 10442

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