source: trunk/FACT++/src/FitsFile.cc@ 12555

Last change on this file since 12555 was 12536, checked in by lyard, 13 years ago
added flushing of nightly files after each row
File size: 12.8 KB
Line 
1// **************************************************************************
2/** @class FitsFile
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 "FitsFile.h"
17
18//#include "Time.h"
19//#include "Converter.h"
20//#include "MessageImp.h"
21
22using namespace std;
23using namespace CCfits;
24
25bool FitsFile::WriteDefaultKeys(const string &prgname, float version)
26{
27 if (!fTable)
28 return false;
29
30 try
31 {
32 const Time now;
33 WriteKey("TELESCOP", "FACT", "Telescope that acquired this data");
34 WriteKey("PACKAGE", PACKAGE_NAME, "Package name");
35 WriteKey("VERSION", PACKAGE_VERSION, "Package description");
36 WriteKey("CREATOR", prgname, "Program that wrote this file");
37 WriteKey("EXTREL", version, "Release Number");
38 WriteKey("COMPILED", __DATE__" "__TIME__, "Compile time");
39 WriteKey("REVISION", REVISION, "SVN revision");
40 WriteKey("ORIGIN", "FACT", "Institution that wrote the file");
41 WriteKey("DATE", now.Iso(), "File creation date");
42 WriteKey("NIGHT", now.NightAsInt(), "Night as int");
43 WriteKey("TIMESYS", "UTC", "Time systen");
44
45 //WriteKey("CONTACT", PACKAGE_BUGREPORT, "Current package maintainer");
46 //WriteKey("URL", PACKAGE_URL, "Current repositiory location");
47 }
48 catch (const CCfits::FitsException &e)
49 {
50 Error("CCfits::Table::addKey failed for '"+fTable->name()+"' in '"+fFile->name()+"': "+e.message());
51 return false;
52 }
53
54 return true;
55}
56
57// --------------------------------------------------------------------------
58//
59//! Add a new column to the vectors storing the column data.
60//! @param names the vector of string storing the columns names
61//! @param types the vector of string storing the FITS data format
62//! @param numElems the number of elements in this column
63//! @param type the char describing the FITS data format
64//! @param name the name of the particular column to be added.
65//
66void FitsFile::AddColumn(char type, const string &name, int numElems, const string &unit)
67{
68 fColNames.push_back(name);
69 fColUnits.push_back(unit);
70
71 ostringstream str;
72 if (numElems != 1)
73 str << numElems;
74
75 switch (toupper(type))
76 {
77 case 'B': str << 'L'; break; // logical
78 case 'C': str << 'B'; break; // byte
79 case 'S': str << 'I'; break; // short
80 case 'I': str << 'J'; break; // int
81 case 'X': str << 'K'; break; // long long
82 case 'F': str << 'E'; break; // float
83 case 'D': str << 'D'; break; // double
84 }
85
86 fColTypes.push_back(str.str());
87}
88
89void FitsFile::AddColumn(const string &name, const string &format, const string &unit)
90{
91 fColNames.push_back(name);
92 fColUnits.push_back(unit);
93 fColTypes.push_back(format);
94}
95
96bool FitsFile::OpenFile(const string &filename, bool allow_open)
97{
98 if (fFile || fTable)
99 {
100 Error("FitsFile::OpenFile - File already open.");
101 return false;
102 }
103
104 // fFileName = fileName;
105 if (!allow_open && access(filename.c_str(), F_OK)==0)
106 {
107 Error("File '"+filename+"' already existing.");
108 return false;
109 }
110
111 //create the FITS object
112 try
113 {
114 fFile = new CCfits::FITS(filename, CCfits::RWmode::Write);
115 }
116 catch (CCfits::FitsException e)
117 {
118 Error("CCfits::FITS failed for '"+filename+"': "+e.message());
119 return false;
120 }
121
122 /*
123 "SIMPLE = T / file does conform to FITS standard "
124 "BITPIX = 8 / number of bits per data pixel "
125 "NAXIS = 0 / number of data axes "
126 "EXTEND = T / FITS dataset may contain extensions "
127 "COMMENT FITS (Flexible Image Transport System) format is defined in 'Astronomy"
128 "COMMENT and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H "
129 "END ";
130 */
131
132 fIsOwner = true;
133
134 return true;
135}
136
137void FitsFile::ResetColumns()
138{
139 fColNames.clear();
140 fColTypes.clear();
141 fColUnits.clear();
142}
143
144bool FitsFile::SetFile(CCfits::FITS *file)
145{
146 if (!file)
147 {
148 Error("Fits::SetFile failed: NULL argument.");
149 return false;
150 }
151
152 if (fFile)
153 {
154 Error("Fits::SetFile failed: File already set.");
155 return false;
156 }
157
158 fFile = file;
159 fIsOwner = false;
160
161 return true;
162}
163
164bool FitsFile::OpenTable(const string &tablename)
165{
166 if (!fFile)
167 {
168 Error("FitsFile::OpenTable - No file open.");
169 return false;
170 }
171 if (fTable)
172 {
173 Error("FitsFile::OpenTable - Table already open.");
174 return false;
175 }
176
177 //actually create the table
178 CCfits::Table *table = 0;
179 try
180 {
181 table = fFile->addTable(tablename, 0, fColNames, fColTypes, fColUnits);
182 }
183 catch (const CCfits::FitsException &e)
184 {
185 Error("CCfits::Table::addTable failed for '"+tablename+"' in '"+fFile->name()+"': "+e.message());
186 return false;
187 }
188
189 if (table->rows() != 0)
190 {
191 Error("FITS table '"+tablename+"' created in '"+fFile->name()+"' on the fly looks non-empty.");
192 return false;
193 }
194
195 // Set this as last - we use it for IsOpen()
196 fTable = table;
197 fNumRows = 0;
198
199 return true;
200}
201
202// --------------------------------------------------------------------------
203//
204//! This looks for a suitable table in the fits file, i.e. that corresponds to the name and column names. (no format check yet)
205//! @param tableName. the base table name to be obtained. If not suitable, numbers are appened to the name
206//! @param allNames. the name of all columns
207//! @param allDataTypes. the data types of all columns
208//! @param allUnits. the units of the columns
209//! @return a pointer to the newly retrieved/created table
210//
211bool FitsFile::OpenNewTable(const string &tableName, int maxtry)
212{
213 if (!fFile)
214 {
215 Error("FitsFile::OpenNewTable - No file open.");
216 return false;
217 }
218
219 if (fTable)
220 {
221 Error("FitsFile::OpenNewTable - Table already open.");
222 return false;
223 }
224
225 //first, let's check if the table already exist in the file
226 fFile->read(vector<string>(1, tableName));
227
228 // FIXME: Check for fFile and fTable
229 const multimap<string, CCfits::ExtHDU *> &extMap = fFile->extension();
230
231 for (int i=0; i<maxtry; i++)
232 {
233 //if (i==10)
234 // fMess->Warn("Already 10 different tables with different formats exist in this file. Please consider re-creating the file entirely (i.e. delete it please)");
235
236 ostringstream str;
237 str << tableName;
238 if (i != 0)
239 str << "-" << i;
240
241 const string tname = str.str();
242
243 const multimap<string,CCfits::ExtHDU*>::const_iterator it = extMap.find(tname);
244
245 //current table name does not exist yet. return its associated fits table newly created
246 if (it == extMap.end())
247 {
248 // What is this for?
249 //for (multimap<string, CCfits::ExtHDU*>::const_iterator it=extMap.begin();
250 // it!= extMap.end(); it++)
251 // fMess->Debug(it->first);
252
253 return OpenTable(tname);
254 }
255
256 CCfits::Table *table = dynamic_cast<CCfits::Table*>(it->second);
257
258 // something wrong happened while getting the table pointer
259 if (!table)
260 {
261 Error("HDU '"+tname+"' found in file, but it is not a proper CCfits::Table.");
262 return false;
263 }
264
265 //now check that the table columns are the same
266 //as the service columns
267 table->makeThisCurrent();
268
269 // FIXME: To be checked...
270 /*
271 const map<string, Column*> cMap = table->column();
272 for (vector<string>::const_iterator ii=fFile->fColNames;
273 ii!=fFile->fColNames.end(); ii++)
274 if (cMap.find(*ii) == cMap.end())
275 continue;
276 */
277
278 fNumRows = table->rows();
279
280 // ----------- This is just a simple sanity check ----------
281
282 // This is not necessary this is done already in
283 // findSuitableTable (either directly or indirectly through OpenTable)
284 // fFile->fTable->makeThisCurrent();
285
286 //If the file already existed, then we must load its data to memory before writing to it.
287 if (fNumRows>0)
288 {
289 CCfits::BinTable* bTable = dynamic_cast<CCfits::BinTable*>(table);
290 if (!bTable)
291 {
292 Error("Table '"+tableName+"' found in '"+fFile->name()+"' is not a binary table.");
293 return false;
294 }
295
296 //read the table binary data.
297 vector<string> colName;
298 bTable->readData(true, colName);
299
300 // double check that the data was indeed read from the disk.
301 // Go through the fTable instead as colName is empty (yes, it is !)
302 const map<string,CCfits::Column*> &cMap = table->column();
303
304 for (map<string,CCfits::Column*>::const_iterator cMapIt = cMap.begin();
305 cMapIt != cMap.end(); cMapIt++)
306 {
307 if (!cMapIt->second->isRead())
308 {
309 Error("Reading column '"+cMapIt->first+"' back from '"+fFile->name()+"' failed.");
310 return false;
311 }
312 }
313 }
314
315 // Set this as last - we use it for IsOpen()
316 fTable = table;
317
318 return true;
319 }
320
321 ostringstream str;
322 str << "FitsFile::OpenNewTable failed - more than " << maxtry << " tables tried." << endl;
323 Error(str);
324
325 return false;
326}
327
328bool FitsFile::AddRow()
329{
330 if (!fFile || !fTable)
331 {
332 Error("FitsFile::AddRow - No table open.");
333 return false;
334 }
335
336 //insert a new row (1==number of rows to insert)
337 int status(0);
338 fits_insert_rows(fFile->fitsPointer(), fNumRows, 1, &status);
339
340 // Status is also directly returned, but we need to give the
341 // pointer anyway
342 if (status)
343 {
344 char text[30];//max length of cfitsio error strings (from doc)
345 fits_get_errstatus(status, text);
346
347 ostringstream str;
348 str << "Inserting row " << fNumRows << " failed in '"+fFile->name()+"': " << text << " (fits_insert_rows,rc=" << status << ")";
349 Error(str);
350
351 return false;
352 }
353
354 fNumRows++;
355 fCursor = 1;
356
357 return true;
358}
359
360bool FitsFile::WriteData(size_t &start, const void *ptr, size_t size)
361{
362 if (!fFile || !fTable)
363 {
364 Error("FitsFile::AddRow - No table open.");
365 return false;
366 }
367
368 int status = 0;
369 fits_write_tblbytes(fFile->fitsPointer(), fNumRows, start, size,
370 (unsigned char*)ptr, &status);
371
372 // Status is also directly returned, but we need to give the
373 // pointer anyway
374 if (status)
375 {
376 char text[30];//max length of cfitsio error strings (from doc)
377 fits_get_errstatus(status, text);
378
379 ostringstream str;
380 str << "Writing row " << fNumRows << " failed in '"+fFile->name()+"': " << text << " (file_write_tblbytes,rc=" << status << ")";
381 Error(str);
382 }
383
384 start += size;
385 return status==0;
386}
387
388void FitsFile::Close()
389{
390 if (!fFile)
391 return;
392
393 if (fIsOwner)
394 {
395 const string name = fFile->name();
396 delete fFile;
397 }
398
399 //WARNING: do NOT delete the table as it gets deleted by the
400 // fFile object
401 fFile = NULL;
402 fTable = NULL;
403}
404
405void FitsFile::Flush()
406{
407 if (!fFile)
408 return;
409
410 int status = 0;
411 fits_flush_file(fFile->fitsPointer(), &status);
412
413 if (status)
414 {
415 char text[30];
416 fits_get_errstatus(status, text);
417
418 ostringstream str;
419 str << "Flushing file " << fFile->name() << " failed: " << text << " (fits_flush_file, rc=" << status << ")";
420 Error(str);
421 }
422}
423size_t FitsFile::GetDataSize() const
424{
425 size_t size = 0;
426
427 for (vector<string>::const_iterator it=fColTypes.begin();
428 it!=fColTypes.end(); it++)
429 {
430 size_t id=0;
431
432 int n=1;
433 try { n = stoi(*it, &id); }
434 catch (const exception&) { }
435
436 if (n==0)
437 continue;
438
439 switch ((*it)[id])
440 {
441 case 'L':
442 case 'B': size += n*1; break; // logical/byte
443 case 'I': size += n*2; break; // short
444 case 'J': size += n*4; break; // int
445 case 'K': size += n*8; break; // long long
446 case 'E': size += n*4; break; // float
447 case 'D': size += n*8; break; // double
448 default:
449 throw runtime_error("FitsFile::GetDataSize - id not known.");
450 }
451 }
452
453 return size;
454}
Note: See TracBrowser for help on using the repository browser.