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

Last change on this file since 11746 was 11744, checked in by tbretz, 13 years ago
Set fNumRows to 0 in OpenFile; added ResetColumns function
File size: 12.4 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 (FACT++ datalogger)");
37 WriteKey("EXTREL", version, "Release Number");
38 WriteKey("COMPILED", __DATE__" "__TIME__, "Compile time");
39 WriteKey("REVISION", REVISION, "SVN revision");
40 WriteKey("ORIGIN", "ISDC", "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 Close();
148
149 if (fFile)
150 {
151 Error("Fits::SetFile failed: File already set.");
152 return false;
153 }
154
155 fFile = file;
156 fIsOwner = false;
157
158 return true;
159}
160
161bool FitsFile::OpenTable(const string &tablename)
162{
163 if (!fFile)
164 {
165 Error("FitsFile::OpenTable - No file open.");
166 return false;
167 }
168 if (fTable)
169 {
170 Error("FitsFile::OpenTable - Table already open.");
171 return false;
172 }
173
174 //actually create the table
175 CCfits::Table *table = 0;
176 try
177 {
178 table = fFile->addTable(tablename, 0, fColNames, fColTypes, fColUnits);
179 }
180 catch (const CCfits::FitsException &e)
181 {
182 Error("CCfits::Table::addTable failed for '"+tablename+"' in '"+fFile->name()+"': "+e.message());
183 return false;
184 }
185
186 if (table->rows() != 0)
187 {
188 Error("FITS table '"+tablename+"' created in '"+fFile->name()+"' on the fly looks non-empty.");
189 return false;
190 }
191
192 // Set this as last - we use it for IsOpen()
193 fTable = table;
194 fNumRows = 0;
195
196 return true;
197}
198
199// --------------------------------------------------------------------------
200//
201//! This looks for a suitable table in the fits file, i.e. that corresponds to the name and column names. (no format check yet)
202//! @param tableName. the base table name to be obtained. If not suitable, numbers are appened to the name
203//! @param allNames. the name of all columns
204//! @param allDataTypes. the data types of all columns
205//! @param allUnits. the units of the columns
206//! @return a pointer to the newly retrieved/created table
207//
208bool FitsFile::OpenNewTable(const string &tableName, int maxtry)
209{
210 if (!fFile)
211 {
212 Error("FitsFile::OpenNewTable - No file open.");
213 return false;
214 }
215
216 if (fTable)
217 {
218 Error("FitsFile::OpenNewTable - Table already open.");
219 return false;
220 }
221
222 //first, let's check if the table already exist in the file
223 fFile->read(vector<string>(1, tableName));
224
225 // FIXME: Check for fFile and fTable
226 const multimap<string, CCfits::ExtHDU *> &extMap = fFile->extension();
227
228 for (int i=0; i<maxtry; i++)
229 {
230 //if (i==10)
231 // 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)");
232
233 ostringstream str;
234 str << tableName;
235 if (i != 0)
236 str << "-" << i;
237
238 const string tname = str.str();
239
240 const multimap<string,CCfits::ExtHDU*>::const_iterator it = extMap.find(tname);
241
242 //current table name does not exist yet. return its associated fits table newly created
243 if (it == extMap.end())
244 {
245 // What is this for?
246 //for (multimap<string, CCfits::ExtHDU*>::const_iterator it=extMap.begin();
247 // it!= extMap.end(); it++)
248 // fMess->Debug(it->first);
249
250 return OpenTable(tname);
251 }
252
253 CCfits::Table *table = dynamic_cast<CCfits::Table*>(it->second);
254
255 // something wrong happened while getting the table pointer
256 if (!table)
257 {
258 Error("HDU '"+tname+"' found in file, but it is not a proper CCfits::Table.");
259 return false;
260 }
261
262 //now check that the table columns are the same
263 //as the service columns
264 table->makeThisCurrent();
265
266 // FIXME: To be checked...
267 /*
268 const map<string, Column*> cMap = table->column();
269 for (vector<string>::const_iterator ii=fFile->fColNames;
270 ii!=fFile->fColNames.end(); ii++)
271 if (cMap.find(*ii) == cMap.end())
272 continue;
273 */
274
275 fNumRows = table->rows();
276
277 // ----------- This is just a simple sanity check ----------
278
279 // This is not necessary this is done already in
280 // findSuitableTable (either directly or indirectly through OpenTable)
281 // fFile->fTable->makeThisCurrent();
282
283 //If the file already existed, then we must load its data to memory before writing to it.
284 if (fNumRows>0)
285 {
286 CCfits::BinTable* bTable = dynamic_cast<CCfits::BinTable*>(table);
287 if (!bTable)
288 {
289 Error("Table '"+tableName+"' found in '"+fFile->name()+"' is not a binary table.");
290 return false;
291 }
292
293 //read the table binary data.
294 vector<string> colName;
295 bTable->readData(true, colName);
296
297 // double check that the data was indeed read from the disk.
298 // Go through the fTable instead as colName is empty (yes, it is !)
299 const map<string,CCfits::Column*> &cMap = table->column();
300
301 for (map<string,CCfits::Column*>::const_iterator cMapIt = cMap.begin();
302 cMapIt != cMap.end(); cMapIt++)
303 {
304 if (!cMapIt->second->isRead())
305 {
306 Error("Reading column '"+cMapIt->first+"' back from '"+fFile->name()+"' failed.");
307 return false;
308 }
309 }
310 }
311
312 // Set this as last - we use it for IsOpen()
313 fTable = table;
314
315 return true;
316 }
317
318 ostringstream str;
319 str << "FitsFile::OpenNewTable failed - more than " << maxtry << " tables tried." << endl;
320 Error(str);
321
322 return false;
323}
324
325bool FitsFile::AddRow()
326{
327 if (!fFile || !fTable)
328 {
329 Error("FitsFile::AddRow - No table open.");
330 return false;
331 }
332
333 //insert a new row (1==number of rows to insert)
334 int status(0);
335 fits_insert_rows(fFile->fitsPointer(), fNumRows, 1, &status);
336
337 // Status is also directly returned, but we need to give the
338 // pointer anyway
339 if (status)
340 {
341 char text[30];//max length of cfitsio error strings (from doc)
342 fits_get_errstatus(status, text);
343
344 ostringstream str;
345 str << "Inserting row " << fNumRows << " failed in '"+fFile->name()+"': " << text << " (fits_insert_rows,rc=" << status << ")";
346 Error(str);
347
348 return false;
349 }
350
351 fNumRows++;
352 fCursor = 1;
353
354 return true;
355}
356
357bool FitsFile::WriteData(size_t &start, const void *ptr, size_t size)
358{
359 if (!fFile || !fTable)
360 {
361 Error("FitsFile::AddRow - No table open.");
362 return false;
363 }
364
365 int status = 0;
366 fits_write_tblbytes(fFile->fitsPointer(), fNumRows, start, size,
367 (unsigned char*)ptr, &status);
368
369 // Status is also directly returned, but we need to give the
370 // pointer anyway
371 if (status)
372 {
373 char text[30];//max length of cfitsio error strings (from doc)
374 fits_get_errstatus(status, text);
375
376 ostringstream str;
377 str << "Writing row " << fNumRows << " failed in '"+fFile->name()+"': " << text << " (file_write_tblbytes,rc=" << status << ")";
378 Error(str);
379 }
380
381 start += size;
382 return status==0;
383}
384
385void FitsFile::Close()
386{
387 if (!fFile)
388 return;
389
390 if (fIsOwner)
391 {
392 const string name = fFile->name();
393 delete fFile;
394 Info("Closed: "+name);
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
403size_t FitsFile::GetDataSize() const
404{
405 size_t size = 0;
406
407 for (vector<string>::const_iterator it=fColTypes.begin();
408 it!=fColTypes.end(); it++)
409 {
410 size_t id=0;
411
412 int n=1;
413 try { n = stoi(*it, &id); }
414 catch (const exception&) { }
415
416 if (n==0)
417 continue;
418
419 switch ((*it)[id])
420 {
421 case 'L':
422 case 'B': size += n*1; break; // logical/byte
423 case 'I': size += n*2; break; // short
424 case 'J': size += n*4; break; // int
425 case 'K': size += n*8; break; // long long
426 case 'E': size += n*4; break; // float
427 case 'D': size += n*8; break; // double
428 default:
429 throw runtime_error("FitsFile::GetDataSize - id not known.");
430 }
431 }
432
433 return size;
434}
Note: See TracBrowser for help on using the repository browser.