-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathFITS.cpp
267 lines (243 loc) · 7.58 KB
/
FITS.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
// FITSFile and FITSImage manipulations
#include "FITS.h"
#include <algorithm>
using namespace FITS;
// Static bookkeeping structures:
list<const FitsioHandle*>
FitsioHandle::openFiles;
FitsFile::HMap FitsFile::readFiles;
FitsFile::HMap FitsFile::writeFiles;
// Function to unroll the CFITSIO error stack into exception string
void
FITS::throw_CFITSIO(const string m1) {
string m= m1 + " CFITSIO Error: ";
char ebuff[FLEN_ERRMSG];
while (fits_read_errmsg(ebuff)) {m+= "\n\t"; m+=ebuff;}
// Do not throw if we are already unwinding stack from
// another thrown exception:
if (std::uncaught_exception()) {
cerr << "During exception processing: " << m << endl;
} else {
throw FITSError(m);
}
}
// Utility to throw exception, or if already processing exception, just print error
// Use this for things that might be thrown in destructor
// But be careful, does not interrupt control flow!!!
void
FITS::throwFitsOrDump(const string err) {
if (std::uncaught_exception())
cerr << "During exception processing: " << err << endl;
else
throw FITSError(err);
}
void
FITS::flushFitsErrors() {
fits_clear_errmsg();
}
// FitsFile constructor: open the file to test for existence
FitsFile::FitsFile(const string& fname, Flags f) {
typedef std::pair<string,HCount> Entry;
// First: be careful not to overwrite a file that is already in use,
// either R/W or RO:
if (f & OverwriteFile) {
if ( readFiles.find(fname)!=readFiles.end()
|| writeFiles.find(fname)!=writeFiles.end())
throw FITSError("OverwriteFile specified on FITS file "
+ fname + " that is already open.");
}
// Is this a duplicate filename?
HMap* usemap = (f==FITS::ReadOnly) ? &readFiles : &writeFiles;
HMap::iterator j = usemap->find(fname);
if (j == usemap->end()) {
// New file, get new handle
ffile = new FitsioHandle(fname, f);
usemap->insert(Entry(fname,HCount(ffile,1)));
} else {
// it's a duplicate, use it and increment link count:
ffile = j->second.first;
++(j->second.second);
}
}
FitsFile::~FitsFile() {
// Find ourselves in the appropriate set of FitsHandles
HMap* usemap = isWriteable() ? &writeFiles : &readFiles;
HMap::iterator j = usemap->find(getFilename());
if (j==usemap->end()) {
ostringstream oss;
cerr << "ERROR: Could not find file <" << getFilename()
<< "> on FitsHandle lists in ~FitsFile()";
}
// Decrement link count
--(j->second.second);
// If links down to zero, delete the FitsHandle
if (j->second.second <= 0) {
delete ffile;
usemap->erase(j);
}
}
//////////////////////////////////////////////////////////////////
// Open/close the CFITSIO files themselves. Automatically
// keep number of open files under some limit.
//////////////////////////////////////////////////////////////////
// FitsioHandle constructor: open the file to test for existence
FitsioHandle::FitsioHandle(const string& fname, Flags f):
filename(fname), fitsptr(0) {
int status = 0;
writeable = !(f == FITS::ReadOnly);
// Try to open the file - prepend "!" to filename to instruct CFITSIO to overwrite
if (f & OverwriteFile) {
// Stomp any existing file:
string openName = "!" + filename;
fits_create_file(&fitsptr, openName.c_str(),
&status);
} else {
fits_open_file(&fitsptr, filename.c_str(),
isWriteable() ? READWRITE : READONLY,
&status);
}
if (status == FILE_NOT_OPENED) {
if (f & FITS::Create) {
// Presumably file is not there, try creating one
status = 0;
flushFitsErrors();
fits_create_file(&fitsptr, filename.c_str(), &status);
} else {
// Throw special exception for failure to open
char ebuff[256];
fits_read_errmsg(ebuff);
string m(ebuff);
throw FITSCantOpen(filename, m);
}
}
if (status) throw_CFITSIO("Error opening FITS file " + fname);
// Add this freshly opened file to front of the queue:
openFiles.push_front(this);
}
FitsioHandle::~FitsioHandle() {
// If file is currently open:
if (fitsptr) {
// close file with CFITSIO
closeFile();
// Find and remove ourself from the list of open files
lptr me = find(openFiles.begin(), openFiles.end(), this);
if (me==openFiles.end()) {
cerr << "ERROR: Did not find open file <" + filename
+ "> in FitsioHandle::openFiles!" << endl;;
} else {
openFiles.erase(me);
}
}
}
// Open a file if it's not already open. Close others if needed.
void
FitsioHandle::useThis() const {
if (fitsptr) {
// already open; push to front of Q for recent usage
if (*openFiles.begin() != this) {
lptr me = find(openFiles.begin(), openFiles.end(), this);
openFiles.erase(me); openFiles.push_front(this);
}
} else {
makeRoom();
reopenFile();
openFiles.push_front(this);
}
}
void
FitsioHandle::makeRoom() const {
static int hashReportInterval=1000; //issue warning for file hashing.
// set to zero to disable this reporting.
static int hashCount=0; //count # times need to close a file
while (openFiles.size() >= MAX_FITS_FILES_OPEN) {
// choose the one to close - last in queue that's open
openFiles.back()->closeFile();
openFiles.pop_back();
hashCount++;
if (hashReportInterval!=0 && (hashCount%hashReportInterval)==0)
cerr << "WARNING: possible FitsioHandle hashing, "
<< hashCount
<< " files closed so far"
<< endl;
}
}
void
FitsioHandle::reopenFile() const {
int status=0;
fits_open_file(&fitsptr, filename.c_str(),
isWriteable() ? READWRITE : READONLY, &status);
if (status!=0) {
char ebuff[256];
fits_read_errmsg(ebuff);
string m(ebuff);
throw FITSCantOpen(filename, m);
}
}
void
FitsioHandle::closeFile() const {
if (fitsptr==0) return;
int status=0;
#ifdef FITSDEBUG
cerr << "fits_close_file " << filename << endl;
#endif
fits_close_file(fitsptr, &status);
if (status && !std::uncaught_exception())
if (status) throw_CFITSIO("closeFile() on "
+ getFilename());
fitsptr = 0;
}
void
FitsioHandle::flush() {
if (fitsptr==0) return; //No need to flush if no CFITSIO buffer
int status=0;
fits_flush_file(fitsptr, &status);
if (status) throw_CFITSIO("flushing " + filename);
}
/////////////////////////////////////////////////////////////////////////
// Access FitsFile information
/////////////////////////////////////////////////////////////////////////
int
FitsFile::HDUCount() const {
int status=0, count=0;
fits_get_num_hdus(getFitsptr(), &count, &status);
if (status) throw_CFITSIO("HDUCount() on " + getFilename());
return count;
}
HDUType
FitsFile::getHDUType(const int HDUnumber) const {
int status=0, retval;
if (HDUnumber < 0 || HDUnumber >= HDUCount())
return HDUNull;
// CFITSIO is 1-index numbers, I am 0-indexe:
fits_movabs_hdu(getFitsptr(), HDUnumber+1, &retval, &status);
if (status) throw_CFITSIO("getHDUType() on " + getFilename());
return HDUType(retval);
}
HDUType
FitsFile::getHDUType(const string HDUname, int &HDUnum) const {
int status=0, retval;
if (HDUCount()==0) {
HDUnum = -1;
return HDUNull; // empty file
}
fits_movnam_hdu(getFitsptr(), ANY_HDU,
const_cast<char*> (HDUname.c_str()),
0, &status);
if (status==BAD_HDU_NUM) {
//name does not exist, return HDUAny
status = 0;
fits_clear_errmsg();
HDUnum = -1;
return HDUNull;
}
fits_get_hdu_num(getFitsptr(), &HDUnum);
HDUnum -= 1; //Make zero-indexed
fits_get_hdu_type(getFitsptr(), &retval, &status);
if (status) throw_CFITSIO("getHDUType() by name on " + getFilename());
return HDUType(retval);
}
HDUType
FitsFile::getHDUType(const string HDUname) const {
int junk;
return getHDUType(HDUname, junk);
}