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

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