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

Last change on this file since 10691 was 10529, checked in by lyard, 14 years ago
Various bug fixes and new commands added
File size: 11.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#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, int* fitsCounter, std::ostream& out)
82{
83 if (fMess)
84 delete fMess;
85 fMess = new MessageImp(out);
86
87 fFileName = fileName;
88 if (file == NULL)
89 {
90 try
91 {
92 fFile = new FITS(fileName, RWmode::Write);
93 }
94 catch (CCfits::FitsError e)
95 {
96 std::stringstream str;
97 str << "Could not open FITS file " << fileName << " reason: " << e.message();
98 fMess->Error(str);
99 fFile = NULL;
100 return;
101 }
102 fOwner = true;
103 fNumOpenFitsFiles = fitsCounter;
104 (*fNumOpenFitsFiles)++;
105 }
106 else
107 {
108 fFile = file;
109 fOwner = false;
110 }
111 //concatenate the standard and data columns
112 //do it the inneficient way first: its easier and faster to code.
113 std::vector<std::string> allNames;
114 std::vector<std::string> allDataTypes;
115 std::vector<std::string> allUnits;
116 fTotalNumBytes = 0;
117 for (unsigned int i=0;i<fStandardColDesc.size();i++)
118 {
119 allNames.push_back(fStandardColDesc[i].name);
120 allDataTypes.push_back(fStandardFormats[i]);
121 allUnits.push_back(fStandardColDesc[i].unit);
122 fTotalNumBytes += fStandardNumBytes[i];
123 }
124 //for (int i=static_cast<int>(fDataColDesc.size())-1;i>=0;i--)
125 for (int i=0; i< static_cast<int>(fDataColDesc.size()); i++)
126 {
127 if (fDataColDesc[i].name != "")
128 allNames.push_back(fDataColDesc[i].name);
129 else
130 {
131 std::stringstream stt;
132 stt << "Data" << i;
133 allNames.push_back(stt.str());
134 }
135 allDataTypes.push_back(fDataFormats[i]);
136 allUnits.push_back(fDataColDesc[i].unit);
137 }
138 fTotalNumBytes += fDataNumBytes;
139
140 bool updating = false;
141 try
142 {
143 std::string factTableName = "FACT-" + tableName;
144 fTable = fFile->addTable(factTableName, 0, allNames, allDataTypes, allUnits);
145 fTable->makeThisCurrent();
146 fCopyBuffer = new unsigned char[fTotalNumBytes];
147 fNumRows = fTable->rows();
148 if (fNumRows !=0)
149 {//If the file already existed, then we must load its data to memory before writing to it.
150 BinTable* bTable = dynamic_cast<BinTable*>(fTable);
151 if (!bTable)
152 {
153 fMess->Error("The table " + factTableName + " could not be converted to a binary table. skipping");
154 return;
155 }
156 //read the table binary data.
157 std::vector<string> colName;
158 bTable->readData(true, colName);
159
160 //double check that the data was indeed read from the disk. Go through the fTable instead as colName is empty (yes, it is !)
161 std::map<std::string, Column*> cMap = fTable->column();
162 std::map<std::string, Column*>::iterator cMapIt;
163
164 for (cMapIt = cMap.begin(); cMapIt != cMap.end(); cMapIt++)
165 {
166 if (!cMapIt->second->isRead())
167 {
168 fMess->Error("Column " + cMapIt->first + "Could not be read back from the disk");
169 return;
170 }
171 }
172 updating = true;
173 }
174 }
175 catch(CCfits::FitsError e)
176 {
177 std::stringstream str;
178 str << "Could not open or create FITS table " << tableName << " in file " << fileName << " reason: " << e.message();
179 fMess->Error(str);
180 fTable = NULL;
181 }
182
183 fRefMjD = * static_cast<double*>(fStandardPointers[0]);
184 if (!updating)
185 WriteHeaderKeys();
186}
187// --------------------------------------------------------------------------
188//
189//! This writes the standard header
190//
191void Fits::WriteHeaderKeys()
192{
193 if (!fTable)
194 return;
195 std::string name;
196 std::string comment;
197
198 float floatValue;
199 double doubleValue;
200 std::string stringValue;
201 try
202 {
203 name = "EXTREL";
204 comment = "Release Number";
205 floatValue = 1.0f;
206 fTable->addKey(name, floatValue, comment);
207
208 name = "BASETYPE";
209 comment = "Base type of the data structure";
210 stringValue = "??????";
211 fTable->addKey(name, stringValue, comment);
212
213 name = "TELESCOP";
214 comment = "Telescope that acquired this data";
215 stringValue = "FACT";
216 fTable->addKey(name, stringValue, comment);
217
218 name = "ORIGIN";
219 comment = "Institution that wrote the file";
220 stringValue = "ISDC";
221 fTable->addKey(name, stringValue, comment);
222
223 name = "CREATOR";
224 comment = "Program that wrote this file";
225 stringValue = "FACT++_DataLogger";
226 fTable->addKey(name, stringValue, comment);
227
228 name = "DATE";
229 stringValue = Time().GetAsStr();
230 stringValue[10] = 'T';
231 comment = "File creation date";
232 fTable->addKey(name, stringValue, comment);
233
234 name = "TIMESYS";
235 stringValue = "TT";
236 comment = "Time frame system";
237 fTable->addKey(name, stringValue, comment);
238
239 name = "TIMEUNIT";
240 stringValue = "d";
241 comment = "Time unit";
242 fTable->addKey(name, stringValue, comment);
243
244 name = "TIMEREF";
245 stringValue = "UTC";
246 comment = "Time reference frame";
247 fTable->addKey(name, stringValue, comment);
248
249 name = "MJDREF";
250 doubleValue = fRefMjD;
251 comment = "Modified Julian Date of origin";
252 fTable->addKey(name, doubleValue, comment);
253 }
254 catch (CCfits::FitsError e)
255 {
256 std::stringstream str;
257 str << "Could not add header keys in file " << fFileName << " reason: " << e.message();
258 fMess->Error(str);
259 }
260 //More ?
261}
262// --------------------------------------------------------------------------
263//
264//! This writes one line of data to the file.
265//! @param conv the converter corresponding to the service being logged
266//
267void Fits::Write(Converter* conv)
268{
269
270 try
271 {
272 fTable->makeThisCurrent();
273 fTable->insertRows(fNumRows);
274 }
275 catch(CCfits::FitsError e)
276 {
277 std::stringstream str;
278 str << "Could not insert row in file " << fFileName << " reason: " << e.message();
279 fMess->Error(str);
280 }
281 fNumRows++;
282
283 //the first standard variable is the current MjD
284 if (fEndMjD == 0)
285 {
286 std::string name = "TSTART";
287 double doubleValue = *static_cast<double*>(fStandardPointers[0]) - fRefMjD;
288 std::string comment = "Time of the first received data";
289 fTable->addKey(name, doubleValue, comment);
290 }
291 fEndMjD = * static_cast<double*>(fStandardPointers[0]);
292
293 //first copy the standard variables to the copy buffer
294 int shift = 0;
295
296 for (unsigned int i=0;i<fStandardNumBytes.size();i++)
297 {
298 for (int j=0; j<fStandardNumBytes[i]; j++)
299 fCopyBuffer[shift+j] = static_cast<char*>(fStandardPointers[i])[fStandardNumBytes[i]-(j+1)];
300 shift+= fStandardNumBytes[i];
301 }
302
303 //now take care of the DIM data. The Converter is here for that purpose
304 conv->ToFits(static_cast<void*>(&fCopyBuffer[shift]), fDataPointer, fDataNumBytes);
305
306 //data copied to buffer, can write to fits
307 int status = 0;
308 //TODO check the status after the write operation
309 fits_write_tblbytes(fFile->fitsPointer(), fNumRows, 1, fTotalNumBytes, fCopyBuffer, &status);
310 if (status)
311 {
312 char text[30];//max length of cfitsio error strings (from doc)
313 fits_get_errstatus(status, text);
314 std::stringstream str;
315 str << "Error while writing FITS row in " << fFileName << ". Message: " << text << " [" << status << "]";
316 fMess->Error(str);
317 }
318 //This forces the writting of each row to the disk. Otherwise all rows are written when the file is closed.
319 ///TODO check whether this consumes too much resources or not. If it does, flush every N write operations instead
320 try
321 {
322 fFile->flush();
323 }
324 catch (CCfits::FitsError e)
325 {
326 std::stringstream str;
327 str << "Error while flushing bytes to disk. File: " << fFileName << " reason: " << e.message();
328 fMess->Error(str);
329 }
330}
331// --------------------------------------------------------------------------
332//
333//! This closes the currently openned FITS file.
334//! it also updates the header to reflect the time of the last logged row
335//
336void Fits::Close()
337{
338//WARNING: do NOT delete the table as it gets deleted by the fFile object
339// if (fTable != NULL)
340// delete fTable;
341 std::string name = "TEND";
342 double doubleValue = fEndMjD - fRefMjD;
343 std::string comment = "Time of the last received data";
344 fTable->addKey(name, doubleValue, comment);
345
346 if (fFile != NULL && fOwner)
347 delete fFile;
348 fFile = NULL;
349 if (fCopyBuffer != NULL)
350 delete [] fCopyBuffer;
351 fCopyBuffer = NULL;
352 if (fOwner && fNumOpenFitsFiles != NULL)
353 (*fNumOpenFitsFiles)--;
354 if (fMess)
355 delete fMess;
356 fMess = NULL;
357}
358
359// --------------------------------------------------------------------------
360//
361//! This closes the currently openned FITS file.
362//! it also updates the header to reflect the time of the last logged row
363//
364int Fits::GetWrittenSize()
365{
366 if (!IsOpen())
367 return 0;
368
369 struct stat st;
370 if (stat(fFileName.c_str(), &st))
371 return 0;
372 else
373 return st.st_size;
374}
Note: See TracBrowser for help on using the repository browser.