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

Last change on this file since 10934 was 10933, checked in by tbretz, 13 years ago
Removed the leading FACT- from the table names.
File size: 11.3 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, string dataFormat, void* dataPointer, long unsigned int numDataBytes)
38{
39 //check if entry already exist
40 for (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(vector<Description> desc, vector<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 ostringstream 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//! @param runNumber the runNumber for which this file is opened. 0 means nightly file.
85//
86void Fits::Open(const string& fileName, const string& tableName, FITS* file, int* fitsCounter, MessageImp* out, int runNumber)
87{
88// if (fMess)
89// delete fMess;
90// fMess = new MessageImp(out);
91 fRunNumber = runNumber;
92 fMess = out;
93 fFileName = fileName;
94 if (file == NULL)
95 {
96 try
97 {
98 fFile = new FITS(fileName, RWmode::Write);
99 }
100 catch (CCfits::FitsException e)
101 {
102 ostringstream str;
103 str << "Could not open FITS file " << fileName << " reason: " << e.message();
104 fMess->Error(str);
105 fFile = NULL;
106 return;
107 }
108 fOwner = true;
109 fNumOpenFitsFiles = fitsCounter;
110 (*fNumOpenFitsFiles)++;
111 }
112 else
113 {
114 fFile = file;
115 fOwner = false;
116 }
117 //concatenate the standard and data columns
118 //do it the inneficient way first: its easier and faster to code.
119 vector<string> allNames;
120 vector<string> allDataTypes;
121 vector<string> allUnits;
122 fTotalNumBytes = 0;
123 for (unsigned int i=0;i<fStandardColDesc.size();i++)
124 {
125 allNames.push_back(fStandardColDesc[i].name);
126 allDataTypes.push_back(fStandardFormats[i]);
127 allUnits.push_back(fStandardColDesc[i].unit);
128 fTotalNumBytes += fStandardNumBytes[i];
129 }
130 //for (int i=static_cast<int>(fDataColDesc.size())-1;i>=0;i--)
131 for (int i=0; i< static_cast<int>(fDataColDesc.size()); i++)
132 {
133 if (fDataColDesc[i].name != "")
134 allNames.push_back(fDataColDesc[i].name);
135 else
136 {
137 ostringstream stt;
138 stt << "Data" << i;
139 allNames.push_back(stt.str());
140 }
141 allDataTypes.push_back(fDataFormats[i]);
142 allUnits.push_back(fDataColDesc[i].unit);
143 }
144 fTotalNumBytes += fDataNumBytes;
145
146 bool updating = false;
147 try
148 {
149 string factTableName = tableName;
150 //first, let's check if the table already exist in the file
151 vector<string> tryToLoadName;
152 tryToLoadName.push_back(factTableName);
153 fFile->read(tryToLoadName);
154 const multimap< string, CCfits::ExtHDU * >& extMap = fFile->extension();
155 if (extMap.find(factTableName) == extMap.end())
156 {
157 for (multimap<string, CCfits::ExtHDU*>::const_iterator it=extMap.begin(); it!= extMap.end(); it++)
158 fMess->Debug(it->first);
159 fTable = fFile->addTable(factTableName, 0, allNames, allDataTypes, allUnits);
160 }
161 else
162 {
163 fTable = dynamic_cast<CCfits::Table*>(extMap.find(factTableName)->second);
164 }
165 if (!fTable)
166 {
167 fMess->Error("The table " + factTableName + " could not be created nor loaded. skipping it");
168 return;
169 }
170 fTable->makeThisCurrent();
171 fCopyBuffer = new unsigned char[fTotalNumBytes];
172 fNumRows = fTable->rows();
173 if (fNumRows !=0)
174 {//If the file already existed, then we must load its data to memory before writing to it.
175 BinTable* bTable = dynamic_cast<BinTable*>(fTable);
176 if (!bTable)
177 {
178 fMess->Error("The table " + factTableName + " could not be converted to a binary table. skipping");
179 return;
180 }
181 //read the table binary data.
182 vector<string> colName;
183 bTable->readData(true, colName);
184
185 //double check that the data was indeed read from the disk. Go through the fTable instead as colName is empty (yes, it is !)
186 map<string, Column*> cMap = fTable->column();
187 map<string, Column*>::iterator cMapIt;
188
189 for (cMapIt = cMap.begin(); cMapIt != cMap.end(); cMapIt++)
190 {
191 if (!cMapIt->second->isRead())
192 {
193 fMess->Error("Column " + cMapIt->first + "Could not be read back from the disk");
194 return;
195 }
196 }
197 updating = true;
198 }
199
200 }
201 catch(CCfits::FitsException e)
202 {
203 ostringstream str;
204 str << "Could not open or create FITS table " << tableName << " in file " << fileName << " reason: " << e.message();
205 fMess->Error(str);
206 fTable = NULL;
207 }
208
209 //As requested by Roland, the reference MjD is 0.0
210 fRefMjD = 0;//* static_cast<double*>(fStandardPointers[0]);
211 if (!updating)
212 WriteHeaderKeys();
213}
214// --------------------------------------------------------------------------
215//
216//!This writes a single header key in the currently open file.
217//!@param name the key
218//!@param value the key value
219//!@param a comment explaining the meaning of the key
220template <typename T>
221void Fits::WriteSingleHeaderKey(string name, T value, string comment)
222{
223 try
224 {
225 fTable->addKey(name, value, comment);
226 }
227 catch (CCfits::FitsException e)
228 {
229 ostringstream str;
230 str << "Could not add header keys in file " << fFileName << " reason: " << e.message();
231 fMess->Error(str);
232 }
233}
234// --------------------------------------------------------------------------
235//
236//! This writes the standard header
237//
238void Fits::WriteHeaderKeys()
239{
240 if (!fTable)
241 return;
242 string name;
243 string comment;
244
245 string stringValue;
246
247 WriteSingleHeaderKey("EXTREL", 1.0f, "Release Number");
248 WriteSingleHeaderKey("TELESCOP", "FACT", "Telescope that acquired this data");
249 WriteSingleHeaderKey("ORIGIN", "ISDC", "Institution that wrote the file");
250 WriteSingleHeaderKey("CREATOR", "FACT++ DataLogger", "Program that wrote this file");
251 stringValue = Time().GetAsStr();
252 stringValue[10]= 'T';
253 WriteSingleHeaderKey("DATE", stringValue, "File creation data");
254 WriteSingleHeaderKey("TIMESYS", "TT", "Time frame system");
255 WriteSingleHeaderKey("TIMEUNIT", "d", "Time unit");
256 WriteSingleHeaderKey("TIMEREF", "UTC", "Time reference frame");
257 WriteSingleHeaderKey("MJDREF", fRefMjD, "Modified Julian Date of origin");
258 WriteSingleHeaderKey("TSTOP", fEndMjD, "Time of the last receied data");
259}
260// --------------------------------------------------------------------------
261//
262//! This writes one line of data to the file.
263//! @param conv the converter corresponding to the service being logged
264//
265void Fits::Write(Converter* conv)
266{
267
268 fTable->makeThisCurrent();
269 int status(0);
270 if (fits_insert_rows(fTable->fitsPointer(), fNumRows, 1, &status))
271 {
272 ostringstream str;
273 str << "Could not insert row in file " << fFileName << ". cfitsio error code: " << status;
274 fMess->Error(str);
275 }
276 fNumRows++;
277
278 //the first standard variable is the current MjD
279 if (fEndMjD == 0)
280 {
281 double doubleValue = *static_cast<double*>(fStandardPointers[0]);// - fRefMjD;
282 WriteSingleHeaderKey("TSTART", doubleValue, "Time of the first received data");
283 }
284 fEndMjD = * static_cast<double*>(fStandardPointers[0]);
285
286 //first copy the standard variables to the copy buffer
287 int shift = 0;
288
289 for (unsigned int i=0;i<fStandardNumBytes.size();i++)
290 {
291 const char * charSrc = static_cast<char*>(fStandardPointers[i]);
292 reverse_copy(charSrc, charSrc+fStandardNumBytes[i], &fCopyBuffer[shift]);
293 shift+= fStandardNumBytes[i];
294 }
295
296 //now take care of the DIM data. The Converter is here for that purpose
297 conv->ToFits(static_cast<void*>(&fCopyBuffer[shift]), fDataPointer, fDataNumBytes);
298
299 //data copied to buffer, can write to fits
300 fits_write_tblbytes(fFile->fitsPointer(), fNumRows, 1, fTotalNumBytes, fCopyBuffer, &status);
301 if (status)
302 {
303 char text[30];//max length of cfitsio error strings (from doc)
304 fits_get_errstatus(status, text);
305 ostringstream str;
306 str << "Error while writing FITS row in " << fFileName << ". Message: " << text << " [" << status << "]";
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 {
324// fFile->flush();
325 delete fFile;
326 }
327 fFile = NULL;
328 if (fCopyBuffer != NULL)
329 delete [] fCopyBuffer;
330 fCopyBuffer = NULL;
331 if (fOwner && fNumOpenFitsFiles != NULL)
332 (*fNumOpenFitsFiles)--;
333//fMess is the MessageImp part of the dataLogger itself. Thus it should NOT be deleted by the Fits files destructor.
334// if (fMess)
335// delete fMess;
336 fMess = NULL;
337}
338
339// --------------------------------------------------------------------------
340//! Returns the size on the disk of the Fits file being written.
341int Fits::GetWrittenSize() const
342{
343 if (!IsOpen())
344 return 0;
345
346 struct stat st;
347 if (stat(fFileName.c_str(), &st))
348 return 0;
349 else
350 return st.st_size;
351}
Note: See TracBrowser for help on using the repository browser.