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

Last change on this file since 10727 was 10725, checked in by lyard, 13 years ago
Small changes asked by Thomas
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#include "MessageImp.h"
21
22//for file stats
23#include <sys/stat.h>
24
25using namespace std;
26using namespace CCfits;
27
28// --------------------------------------------------------------------------
29//
30//! This gives a standard variable to the file writter.
31//! This variable should not be related to the DIM service being logged.
32//! @param desc the description of the variable to add
33//! @param dataFormat the FITS data format corresponding to the variable to add.
34//! @param dataPointer the memory location where the variable is stored
35//! @param numDataBytes the number of bytes taken by the variable
36//
37void Fits::AddStandardColumn(Description& desc, std::string dataFormat, void* dataPointer, long unsigned int numDataBytes)
38{
39 //check if entry already exist
40 for (std::vector<Description>::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}
48// --------------------------------------------------------------------------
49//
50//! This gives the file writter access to the DIM data
51//! @param desc a vector containing the description of all the columns to log
52//! @param dataFormat a vector containing the FITS data format of all the columsn to log
53//! @param dataPointer the memory location where the DIM data starts
54//! @param numDataBytes the number of bytes taken by the DIM data.
55//
56void Fits::InitDataColumns(std::vector<Description> desc, std::vector<std::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 std::stringstream 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 opens the FITS file (after the columns have been passed)
79//! @param fileName the filename with complete or relative path of the file to open
80//! @param tableName the name of the table that will receive the logged data.
81//! @param file a pointer to an existing FITS file. If NULL, file will be opened and managed internally
82//! @param fitsCounter a pointer to the integer keeping track of the opened FITS files
83//! @param out a pointer to the MessageImp that should be used to log errors
84//
85void Fits::Open(const std::string& fileName, const std::string& tableName, FITS* file, int* fitsCounter, MessageImp* out)//std::ostream& out)
86{
87// if (fMess)
88// delete fMess;
89// fMess = new MessageImp(out);
90 fMess = out;
91 fFileName = fileName;
92 if (file == NULL)
93 {
94 try
95 {
96 fFile = new FITS(fileName, RWmode::Write);
97 }
98 catch (CCfits::FitsError e)
99 {
100 std::stringstream str;
101 str << "Could not open FITS file " << fileName << " reason: " << e.message();
102 fMess->Error(str);
103 fFile = NULL;
104 return;
105 }
106 fOwner = true;
107 fNumOpenFitsFiles = fitsCounter;
108 (*fNumOpenFitsFiles)++;
109 }
110 else
111 {
112 fFile = file;
113 fOwner = false;
114 }
115 //concatenate the standard and data columns
116 //do it the inneficient way first: its easier and faster to code.
117 std::vector<std::string> allNames;
118 std::vector<std::string> allDataTypes;
119 std::vector<std::string> allUnits;
120 fTotalNumBytes = 0;
121 for (unsigned int i=0;i<fStandardColDesc.size();i++)
122 {
123 allNames.push_back(fStandardColDesc[i].name);
124 allDataTypes.push_back(fStandardFormats[i]);
125 allUnits.push_back(fStandardColDesc[i].unit);
126 fTotalNumBytes += fStandardNumBytes[i];
127 }
128 //for (int i=static_cast<int>(fDataColDesc.size())-1;i>=0;i--)
129 for (int i=0; i< static_cast<int>(fDataColDesc.size()); i++)
130 {
131 if (fDataColDesc[i].name != "")
132 allNames.push_back(fDataColDesc[i].name);
133 else
134 {
135 std::stringstream stt;
136 stt << "Data" << i;
137 allNames.push_back(stt.str());
138 }
139 allDataTypes.push_back(fDataFormats[i]);
140 allUnits.push_back(fDataColDesc[i].unit);
141 }
142 fTotalNumBytes += fDataNumBytes;
143
144 bool updating = false;
145 try
146 {
147 std::string factTableName = "FACT-" + tableName;
148 fTable = fFile->addTable(factTableName, 0, allNames, allDataTypes, allUnits);
149 fTable->makeThisCurrent();
150 fCopyBuffer = new unsigned char[fTotalNumBytes];
151 fNumRows = fTable->rows();
152 if (fNumRows !=0)
153 {//If the file already existed, then we must load its data to memory before writing to it.
154 BinTable* bTable = dynamic_cast<BinTable*>(fTable);
155 if (!bTable)
156 {
157 fMess->Error("The table " + factTableName + " could not be converted to a binary table. skipping");
158 return;
159 }
160 //read the table binary data.
161 std::vector<string> colName;
162 bTable->readData(true, colName);
163
164 //double check that the data was indeed read from the disk. Go through the fTable instead as colName is empty (yes, it is !)
165 std::map<std::string, Column*> cMap = fTable->column();
166 std::map<std::string, Column*>::iterator cMapIt;
167
168 for (cMapIt = cMap.begin(); cMapIt != cMap.end(); cMapIt++)
169 {
170 if (!cMapIt->second->isRead())
171 {
172 fMess->Error("Column " + cMapIt->first + "Could not be read back from the disk");
173 return;
174 }
175 }
176 updating = true;
177 }
178 }
179 catch(CCfits::FitsError e)
180 {
181 std::stringstream str;
182 str << "Could not open or create FITS table " << tableName << " in file " << fileName << " reason: " << e.message();
183 fMess->Error(str);
184 fTable = NULL;
185 }
186
187 //As requested by Roland, the reference MjD is 0.0
188 fRefMjD = 0;//* static_cast<double*>(fStandardPointers[0]);
189 if (!updating)
190 WriteHeaderKeys();
191}
192template <typename T>
193void Fits::WriteSingleHeaderKey(string name, T value, string comment)
194{
195 try
196 {
197 fTable->addKey(name, value, comment);
198 }
199 catch (CCfits::FitsError e)
200 {
201 std::stringstream str;
202 str << "Could not add header keys in file " << fFileName << " reason: " << e.message();
203 fMess->Error(str);
204 }
205}
206// --------------------------------------------------------------------------
207//
208//! This writes the standard header
209//
210void Fits::WriteHeaderKeys()
211{
212 if (!fTable)
213 return;
214 std::string name;
215 std::string comment;
216
217// float floatValue;
218// double doubleValue;
219 std::string stringValue;
220
221 WriteSingleHeaderKey("EXTREL", 1.0f, "Release Number");
222 WriteSingleHeaderKey("TELESCOP", "FACT", "Telescope that acquired this data");
223 WriteSingleHeaderKey("ORIGIN", "ISDC", "Institution that wrote the file");
224 WriteSingleHeaderKey("CREATOR", "FACT++ DataLogger", "Program that wrote this file");
225 stringValue = Time().GetAsStr();
226 stringValue[10]= 'T';
227 WriteSingleHeaderKey("DATE", stringValue, "File creation data");
228 WriteSingleHeaderKey("TIMESYS", "TT", "Time frame system");
229 WriteSingleHeaderKey("TIMEUNIT", "d", "Time unit");
230 WriteSingleHeaderKey("TIMEREF", "UTC", "Time reference frame");
231 WriteSingleHeaderKey("MJDREF", fRefMjD, "Modified Julian Date of origin");
232}
233// --------------------------------------------------------------------------
234//
235//! This writes one line of data to the file.
236//! @param conv the converter corresponding to the service being logged
237//
238void Fits::Write(Converter* conv)
239{
240
241// try
242// {
243 fTable->makeThisCurrent();
244 int status(0);
245 if (fits_insert_rows(fTable->fitsPointer(), fNumRows, 1, &status))
246 {
247 std::stringstream str;
248 str << "Could not insert row in file " << fFileName << ". cfitsio error code: " << status;
249 fMess->Error(str);
250 }
251// fTable->insertRows(fNumRows);
252// }
253// catch(CCfits::FitsError e)
254// {
255// std::stringstream str;
256// str << "Could not insert row in file " << fFileName << " reason: " << e.message();
257// fMess->Error(str);
258// }
259 fNumRows++;
260
261 //the first standard variable is the current MjD
262 if (fEndMjD == 0)
263 {
264 double doubleValue = *static_cast<double*>(fStandardPointers[0]);// - fRefMjD;
265 WriteSingleHeaderKey("TSTART", doubleValue, "Time of the first received data");
266 }
267 fEndMjD = * static_cast<double*>(fStandardPointers[0]);
268
269 //first copy the standard variables to the copy buffer
270 int shift = 0;
271
272 for (unsigned int i=0;i<fStandardNumBytes.size();i++)
273 {
274 const char * charSrc = static_cast<char*>(fStandardPointers[i]);
275
276 reverse_copy(charSrc, charSrc+fStandardNumBytes[i], &fCopyBuffer[shift]);
277// for (int j=0; j<fStandardNumBytes[i]; j++)
278// fCopyBuffer[shift+j] = static_cast<char*>(fStandardPointers[i])[fStandardNumBytes[i]-(j+1)];
279 shift+= fStandardNumBytes[i];
280 }
281
282 //now take care of the DIM data. The Converter is here for that purpose
283 conv->ToFits(static_cast<void*>(&fCopyBuffer[shift]), fDataPointer, fDataNumBytes);
284
285 //data copied to buffer, can write to fits
286// int status = 0;
287 //TODO check the status after the write operation
288 fits_write_tblbytes(fFile->fitsPointer(), fNumRows, 1, fTotalNumBytes, fCopyBuffer, &status);
289 if (status)
290 {
291 char text[30];//max length of cfitsio error strings (from doc)
292 fits_get_errstatus(status, text);
293 std::stringstream str;
294 str << "Error while writing FITS row in " << fFileName << ". Message: " << text << " [" << status << "]";
295 fMess->Error(str);
296 }
297 //This forces the writting of each row to the disk. Otherwise all rows are written when the file is closed.
298 ///TODO check whether this consumes too much resources or not. If it does, flush every N write operations instead
299/* try
300 {
301 fFile->flush();
302 }
303 catch (CCfits::FitsError e)
304 {
305 std::stringstream str;
306 str << "Error while flushing bytes to disk. File: " << fFileName << " reason: " << e.message();
307 fMess->Error(str);
308 }
309*/}
310// --------------------------------------------------------------------------
311//
312//! This closes the currently openned FITS file.
313//! it also updates the header to reflect the time of the last logged row
314//
315void Fits::Close()
316{
317//WARNING: do NOT delete the table as it gets deleted by the fFile object
318// if (fTable != NULL)
319// delete fTable;
320
321 WriteSingleHeaderKey("TSTOP", fEndMjD, "Time of the last receied data");
322 if (fFile != NULL && fOwner)
323 delete fFile;
324 fFile = NULL;
325 if (fCopyBuffer != NULL)
326 delete [] fCopyBuffer;
327 fCopyBuffer = NULL;
328 if (fOwner && fNumOpenFitsFiles != NULL)
329 (*fNumOpenFitsFiles)--;
330//fMess is the MessageImp part of the dataLogger itself. Thus it should NOT be deleted by the Fits files destructor.
331// if (fMess)
332// delete fMess;
333 fMess = NULL;
334}
335
336// --------------------------------------------------------------------------
337//
338int Fits::GetWrittenSize()
339{
340 if (!IsOpen())
341 return 0;
342
343 struct stat st;
344 if (stat(fFileName.c_str(), &st))
345 return 0;
346 else
347 return st.st_size;
348}
Note: See TracBrowser for help on using the repository browser.