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

Last change on this file since 11788 was 11716, checked in by tbretz, 13 years ago
Make use of the new FitsFile class.
File size: 8.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#include "MessageImp.h"
21
22
23#include <sys/stat.h> //for file stats
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(const Description& desc, const string &dataFormat, void* dataPointer, long unsigned int numDataBytes)
38{
39 //check if entry already exist
40 for (vector<Description>::const_iterator it=fStandardColDesc.begin(); it != fStandardColDesc.end(); it++)
41 if (it->name == desc.name)
42 return;
43
44 fStandardColDesc.push_back(desc);
45 fStandardFormats.push_back(dataFormat);
46 fStandardPointers.push_back(dataPointer);
47 fStandardNumBytes.push_back(numDataBytes);
48}
49
50// --------------------------------------------------------------------------
51//
52//! This gives the file writter access to the DIM data
53//! @param desc a vector containing the description of all the columns to log
54//! @param dataFormat a vector containing the FITS data format of all the columsn to log
55//! @param dataPointer the memory location where the DIM data starts
56//! @param numDataBytes the number of bytes taken by the DIM data.
57//
58void Fits::InitDataColumns(const vector<Description> &desc, const vector<string>& dataFormat, void* dataPointer)
59{
60 fDataFormats = dataFormat;
61 fDataPointer = dataPointer;
62
63 //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
64 if (desc.size() == dataFormat.size())
65 {
66 fDataColDesc = desc;
67 return;
68 }
69
70 fDataColDesc.clear();
71 for (unsigned int i=0;i<dataFormat.size();i++)
72 {
73 ostringstream stt;
74 stt << "Data" << i;
75 fDataColDesc.push_back(Description(stt.str(), "comment", "unit"));
76 }
77}
78
79// --------------------------------------------------------------------------
80//
81//! This opens the FITS file (after the columns have been passed)
82//! @param fileName the filename with complete or relative path of the file to open
83//! @param tableName the name of the table that will receive the logged data.
84//! @param file a pointer to an existing FITS file. If NULL, file will be opened and managed internally
85//! @param fitsCounter a pointer to the integer keeping track of the opened FITS files
86//! @param out a pointer to the MessageImp that should be used to log errors
87//! @param runNumber the runNumber for which this file is opened. 0 means nightly file.
88//
89bool Fits::Open(const string& fileName, const string& tableName, uint32_t* fitsCounter, MessageImp* out, int runNumber, FITS* file)
90{
91 fRunNumber = runNumber;
92 fMess = out;
93
94 if (fFile)
95 {
96 fMess->Error("File already open...");
97 return false;
98 }
99
100 fFile = new FitsFile(*fMess);
101
102 if (file == NULL)
103 {
104 if (!fFile->OpenFile(fileName, true))
105 return false;
106
107 fNumOpenFitsFiles = fitsCounter;
108 (*fNumOpenFitsFiles)++;
109 }
110 else
111 {
112 if (!fFile->SetFile(file))
113 return false;
114 }
115
116 //concatenate the standard and data columns
117 //do it the inneficient way first: its easier and faster to code.
118 for (unsigned int i=0;i<fStandardColDesc.size();i++)
119 {
120 fFile->AddColumn(fStandardColDesc[i].name, fStandardFormats[i],
121 fStandardColDesc[i].unit);
122 }
123
124 for (unsigned int i=0; i<fDataColDesc.size(); i++)
125 {
126 string name = fDataColDesc[i].name;
127 if (name.empty())
128 {
129 ostringstream stt;
130 stt << "Data" << i;
131 name = stt.str();
132 }
133
134 fFile->AddColumn(name, fDataFormats[i], fDataColDesc[i].unit);
135 }
136
137 try
138 {
139 if (!fFile->OpenNewTable(tableName, 100))
140 {
141 Close();
142 return false;
143 }
144
145 fCopyBuffer.resize(fFile->GetDataSize());
146
147 return fFile->GetNumRows()==0 ? true : WriteHeaderKeys();
148 }
149 catch (const CCfits::FitsException &e)
150 {
151 fMess->Error("Opening or creating table '"+tableName+"' in '"+fileName+"': "+e.message());
152
153 fFile->fTable = NULL;
154 Close();
155 return false;
156 }
157}
158
159// --------------------------------------------------------------------------
160//
161//! This writes the standard header
162//
163bool Fits::WriteHeaderKeys()
164{
165 if (!fFile->fTable)
166 return false;
167
168 if (!fFile->WriteDefaultKeys("datalogger"))
169 return false;
170
171 if (!fFile->WriteKeyNT("TSTART", "", "Time of the first receied data"))
172 return false;
173
174 if (!fFile->WriteKeyNT("TSTOP", "", "Time of the last receied data"))
175 return false;
176
177 return true;
178}
179
180// --------------------------------------------------------------------------
181//
182//! This writes one line of data to the file.
183//! @param conv the converter corresponding to the service being logged
184//
185bool Fits::Write(const Converter &conv)
186{
187 //first copy the standard variables to the copy buffer
188 int shift = 0;
189 for (unsigned int i=0;i<fStandardNumBytes.size();i++)
190 {
191 const char *charSrc = reinterpret_cast<char*>(fStandardPointers[i]);
192 reverse_copy(charSrc, charSrc+fStandardNumBytes[i], fCopyBuffer.data()+shift);
193 shift += fStandardNumBytes[i];
194 }
195
196 try
197 {
198 //now take care of the DIM data. The Converter is here for that purpose
199 conv.ToFits(fCopyBuffer.data()+shift, fDataPointer, fCopyBuffer.size()-shift);
200 }
201 catch (const runtime_error &e)
202 {
203 ostringstream str;
204 str << fFile->GetName() << ": " << e.what();
205 fMess->Error(str);
206 return false;
207 }
208
209 // This is not necessary, is it?
210 // fFile->fTable->makeThisCurrent();
211
212 if (!fFile->AddRow())
213 {
214 Close();
215 return false;
216 }
217
218 if (!fFile->WriteData(fCopyBuffer))
219 {
220 Close();
221 return false;
222 }
223
224 //the first standard variable is the current MjD
225 if (fEndMjD==0)
226 {
227 // FIXME: Check error?
228 const double doubleValue = *reinterpret_cast<double*>(fStandardPointers[0]);
229 fFile->WriteKeyNT("TSTART", Time(doubleValue).Iso(),
230 "Time of the first received data");
231 }
232 fEndMjD = *reinterpret_cast<double*>(fStandardPointers[0]);
233
234 return true;
235}
236
237// --------------------------------------------------------------------------
238//
239//! This closes the currently openned FITS file.
240//! it also updates the header to reflect the time of the last logged row
241//
242void Fits::Close()
243{
244 if (!fFile)
245 return;
246
247 if (fFile->IsOpen() && fFile->IsOwner())
248 {
249 // FIMXE: Check for error? (It is allowed that fFile is NULL)
250 fFile->WriteKeyNT("TSTOP", Time(fEndMjD).Iso(),
251 "Time of the last receied data");
252 }
253
254 if (fFile->IsOwner())
255 {
256 if (fNumOpenFitsFiles != NULL)
257 (*fNumOpenFitsFiles)--;
258 }
259
260 delete fFile;
261 fFile = NULL;
262
263 fMess = NULL;
264}
265
266// --------------------------------------------------------------------------
267//! Returns the size on the disk of the Fits file being written.
268int Fits::GetWrittenSize() const
269{
270 if (!IsOpen())
271 return 0;
272
273 struct stat st;
274 if (stat(fFile->GetName().c_str(), &st))
275 return 0;
276
277 return st.st_size;
278}
279
280/*
281 To be done:
282 - Check the check for column names in opennewtable
283 - If Open return false we end in an infinite loop (at least if
284 the dynamic cats to Bintable fails.
285
286*/
Note: See TracBrowser for help on using the repository browser.