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

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