-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathFITS.cxx
More file actions
1525 lines (1320 loc) · 46 KB
/
FITS.cxx
File metadata and controls
1525 lines (1320 loc) · 46 KB
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
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Astrophysics Science Division,
// NASA/ Goddard Space Flight Center
// HEASARC
// http://heasarc.gsfc.nasa.gov
// e-mail: ccfits@legacy.gsfc.nasa.gov
//
// Original author: Ben Dorman
// Table
#include "Table.h"
// PHDU
#include "PHDU.h"
// PrimaryHDU
#include "PrimaryHDU.h"
// FITS
#include "FITS.h"
#ifdef _MSC_VER
#include "MSconfig.h" // for truncation warning
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef SSTREAM_DEFECT
#include <strstream>
#else
#include <sstream>
#endif
using std::endl;
using std::cout;
using std::cerr;
#include <memory>
#include <iterator>
namespace CCfits {
typedef std::multimap<string,ExtHDU*> ExtMap;
typedef std::multimap<string,ExtHDU*>::iterator ExtMapIt;
typedef std::multimap<string,ExtHDU*>::const_iterator ExtMapConstIt;
// Class CCfits::FITS::NoSuchHDU
FITS::NoSuchHDU::NoSuchHDU (const String& diag, bool silent)
: FitsException("FITS Error: Cannot read HDU in FITS file: ",silent)
{
//! Exception to be thrown by failed seek operations
addToMessage(diag);
if ( FITS::verboseMode() || !silent) std::cerr << diag << "\n";
}
// Class CCfits::FITS::OperationNotSupported
FITS::OperationNotSupported::OperationNotSupported (const String& msg, bool silent)
: FitsException("FITS Error: Operation not supported: ",silent)
{
addToMessage(msg);
if ( FITS::verboseMode() || !silent) std::cerr << msg << "\n";
}
// Class CCfits::FITS::CantOpen
FITS::CantOpen::CantOpen (const String& diag, bool silent)
: FitsException("FITS Error: Cannot open file ",silent)
{
addToMessage(diag);
if ( FITS::verboseMode() || !silent) std::cerr << diag << "\n";
}
// Class CCfits::FITS::CantCreate
FITS::CantCreate::CantCreate (const String& diag, bool silent)
: FitsException(string("FITS Error: Cannot create file "),silent)
{
addToMessage(diag);
if ( FITS::verboseMode() || !silent) std::cerr << diag << '\n';
}
// Class CCfits::FITS
bool FITS::s_verboseMode = false;
FITS::FITS (const String &fileName, RWmode rwmode, bool readDataFlag, const std::vector<String>& primaryKeys)
: m_currentCompressionTileDim(0),
m_mode(rwmode), m_currentExtensionName(""), m_filename(fileName),
m_pHDU(0), m_extension(), m_fptr(0)
{
if (rwmode == Read)
{
// If name includes extended file syntax, the initial hdu position
// upon opening is not necessarily the primary header.
int hduIdx = open(rwmode);
// Read the primary header. This also moves the current hdu
// to the primary.
read(readDataFlag,primaryKeys);
readExtensions(readDataFlag);
// If extended syntax asked for a particular extension,
// restore it as the current hdu position.
if (hduIdx)
{
// This also calls makeThisCurrent.
extension(hduIdx);
}
}
else
{
// create a primary header in the receiving structure.
// PHDU has a private constructor and must be instantiated here only.
// this ensures that every FITS object has exactly one PHDU.
if (create() )
{
// create returns true if the file is either new
// or overwritten, in which case we need to create
// and write a new primary with BITPIX=8 and NAXIS=0.
// Also if in here, no extended syntax was used.
HDUCreator makePrimary(this);
pHDU(makePrimary.createImage(8,0,std::vector<long>()));
}
else
{
// The create call above will have opened the file in rw mode.
read(readDataFlag,primaryKeys);
readExtensions(readDataFlag);
// For backwards compatibility, reposition the current HDU to
// be the primary. (In earlier versions, only the primary was
// ever read when opening a pre-existing file in Write mode.)
resetPosition();
}
}
}
FITS::FITS (const String &fileName, RWmode rwmode, const string &hduName, bool readDataFlag, const std::vector<String>& hduKeys, const std::vector<String>& primaryKey, int version)
: m_currentCompressionTileDim(0),
m_mode(rwmode), m_currentExtensionName(""), m_filename(fileName),
m_pHDU(0), m_extension(), m_fptr(0)
{
int extSyntHdu = open(rwmode);
// create and read the Primary: assume here that a single HDU other than
// the primary is requested, so don't read primary data. We can however
// read some header info from the primary if (optionally) specified.
read(false,primaryKey);
read(hduName, readDataFlag, hduKeys,version);
if (extSyntHdu && currentExtension().index() != extSyntHdu)
{
std::ostringstream msg;
msg << "Hdu (" << hduName << ") requested with extended syntax ("
<< extSyntHdu << ") differs from that requested by name argument ("
<< currentExtension().index() << ").";
throw OperationNotSupported(msg.str());
}
}
FITS::FITS (const String &fileName, RWmode rwmode, const std::vector<String>& hduNames, bool readDataFlag, const std::vector<String>& primaryKey)
: m_currentCompressionTileDim(0),
m_mode(rwmode), m_currentExtensionName(""), m_filename(fileName),
m_pHDU(0), m_extension(), m_fptr(0)
{
int extSyntHdu = open(rwmode);
read(readDataFlag,primaryKey);
read(hduNames,readDataFlag);
if (extSyntHdu)
{
// If hdu specified in extension is not included in
// hduNames, throw.
bool savVerbose = s_verboseMode;
s_verboseMode = false;
try
{
extension(extSyntHdu);
}
catch (...)
{
s_verboseMode = savVerbose;
string msg("Hdu requested with extended syntax was not included ");
msg += "in FITS constructor hduNames array.";
throw OperationNotSupported(msg);
}
s_verboseMode = savVerbose;
}
}
FITS::FITS (const String& fileName, const FITS& source)
: m_currentCompressionTileDim(0),
m_mode(Write), m_currentExtensionName(""), m_filename(fileName),
m_pHDU(0), m_extension(), m_fptr(0)
{
if (create() )
{
// create returns true if the file is either new
// or overwritten, in which case we need to create
// and write a new primary which is a clone of the source PHDU.
pHDU(static_cast<PHDU*>(source.pHDU().clone(this)));
}
else
{
// Assume file already exists and user is not attempting to
// overwrite with the '!' symbol.
throw CantCreate(fileName);
}
int status(0);
source.pHDU().makeThisCurrent();
if (fits_copy_hdu(source.fitsPointer(),m_fptr,0,&status)) throw FitsError(status);
}
FITS::FITS (const String &fileName, RWmode rwmode, const std::vector<String>& hduNames, const std::vector<std::vector<String> >& hduKeys, bool readDataFlag, const std::vector<String>& primaryKeys, const std::vector<int>& hduVersions)
: m_currentCompressionTileDim(0),
m_mode(rwmode), m_currentExtensionName(""), m_filename(fileName),
m_pHDU(0), m_extension(), m_fptr(0)
{
int extSyntHdu = open(rwmode);
// read the primary header and read the data if readDataFlag is set.
read(readDataFlag,primaryKeys);
read(hduNames, hduKeys, readDataFlag, hduVersions);
if (extSyntHdu)
{
// If hdu specified in extension is not included in
// hduNames, throw.
bool savVerbose = s_verboseMode;
s_verboseMode = false;
try
{
extension(extSyntHdu);
}
catch (...)
{
s_verboseMode = savVerbose;
string msg("Hdu requested with extended syntax was not included ");
msg += "in FITS constructor hduNames array.";
throw OperationNotSupported(msg);
}
s_verboseMode = savVerbose;
}
}
FITS::FITS (const String& fileName, int bitpix, int naxis, long *naxes)
: m_currentCompressionTileDim(0),
m_mode(Write), m_currentExtensionName(""), m_filename(fileName),
m_pHDU(0), m_extension(), m_fptr(0)
{
std::vector<long> va_naxes(naxis);
std::copy(&naxes[0],&naxes[naxis],va_naxes.begin());
if (!create())
{
// Assume file already exists and user did not specify overwrite
// with the '!' symbol.
throw CantCreate(fileName);
}
// create an HDU factory.
HDUCreator makePrimary(this);
// set the PrimaryHDU. bitpix will determine the data type.
pHDU(makePrimary.createImage(bitpix,naxis,va_naxes));
// If file name is explicitly indicating image compression,
// pHDU won't hold the image. Therefore need to create an
// extension here.
string::size_type compressLoc =
FITSUtil::checkForCompressString(name());
if (compressLoc != string::npos)
{
HDUCreator newImage(this);
ExtHDU* newHDU = newImage.createImage(string("NoName"),bitpix, naxis, va_naxes, 1);
addExtension(newHDU);
string actualFileName(name().substr(0, compressLoc));
m_filename = actualFileName;
currentCompressionTileDim(naxis);
}
}
FITS::FITS (const string &fileName, RWmode rwmode, int hduIndex, bool readDataFlag, const std::vector<String>& hduKeys, const std::vector<String>& primaryKey)
: m_currentCompressionTileDim(0),
m_mode(rwmode), m_currentExtensionName(""), m_filename(fileName),
m_pHDU(0), m_extension(), m_fptr(0)
{
int extSyntHdu = open(rwmode);
if (extSyntHdu && extSyntHdu != hduIndex)
{
string msg("FITS constructor hduIndex conflicts with HDU requested by extended syntax.");
throw OperationNotSupported(msg);
}
// read the primary header. Allowing the user to read the primary data
// and optional keys costs nothing here, although the likely use of this
// constructor is to read a specified HDU from a file other than the Primary.
read(readDataFlag,primaryKey);
read(hduIndex,readDataFlag,hduKeys);
}
FITS::FITS (const String &fileName, RWmode rwmode, const std::vector<String>& searchKeys, const std::vector<String> &searchValues, bool readDataFlag, const std::vector<String>& hduKeys, const std::vector<String>& primaryKey, int version)
: m_currentCompressionTileDim(0),
m_mode(rwmode), m_currentExtensionName(""), m_filename(fileName),
m_pHDU(0), m_extension(), m_fptr(0)
{
open(rwmode);
// read the primary header and read the data if readDataFlag is set.
// create returns a PHDU if the index is 0.
read(false,primaryKey);
// create a primary header in the receiving structure.
// PHDU has a private constructor and must be instantiated here only.
// this ensures that every FITS object has exactly one PHDU
read(searchKeys, searchValues, readDataFlag, hduKeys, version);
}
FITS::~FITS()
{
destroy();
}
void FITS::unmapExtension (ExtHDU& doomed)
{
const string& doomedName = doomed.name();
if ( m_extension.count(doomedName) == 1 )
{
ExtMapIt x = m_extension.lower_bound(doomedName);
delete (*x).second;
m_extension.erase(x);
}
else
{
std::pair<ExtMapIt,ExtMapIt> named = m_extension.equal_range(doomedName);
ExtMapIt x = named.first;
while ( x != named.second)
{
if ( (*x).second->version() == doomed.version())
{
delete (*x).second;
m_extension.erase(x);
break;
}
++x;
}
}
}
void FITS::clearErrors ()
{
fits_clear_errmsg();
}
void FITS::deleteExtension (const String& doomed, int version)
{
int status(0);
ExtHDU& d = extension(doomed,version); // throws NoSuchHDU if it's not there.
const int removeIdx = d.index();
std::vector<ExtHDU*> trailingExts;
ExtMapConstIt itExtMap = m_extension.begin();
ExtMapConstIt itExtMapEnd = m_extension.end();
while (itExtMap != itExtMapEnd)
{
if (itExtMap->second->index() > removeIdx)
trailingExts.push_back(itExtMap->second);
++itExtMap;
}
if (fits_delete_hdu(m_fptr,0,&status)) throw FitsError(status);
unmapExtension(d);
// Reindex the extensions that follow the deleted.
for (size_t i=0; i<trailingExts.size(); ++i)
trailingExts[i]->index(trailingExts[i]->index()-1);
}
int FITS::nextVersionNumber (const String& inputName) const
{
int n(0);
int status(0);
int current(0);
if (fits_get_num_hdus(m_fptr,&n,&status)) throw FitsError(status);
fits_get_hdu_num(m_fptr,¤t);
int count(0);
for (int j = 2; j <= n; ++j)
{
if (nameOfUnmapped(j) == inputName) ++count;
}
if (fits_movabs_hdu(m_fptr,current,0,&status)) throw FitsError(status);
return count+1;
}
void FITS::read (bool readDataFlag, const std::vector<String>& keys)
{
// Move to and create primary header object.
HDUCreator create(this);
int status=0, hduType=0;
if (fits_movabs_hdu(m_fptr, 1, &hduType, &status))
throw FitsError(status);
pHDU(static_cast<PHDU*>(create.getHdu(0,readDataFlag,keys)));
}
void FITS::read (const String &hduName, bool readDataFlag, const std::vector<String> &keys, int version)
{
// grab the requested extension if present. If not, create an ExtHDU object and add it, if it
// exists in the file. The first clause copes with the results from the ctor that reads the
// entire file for HDUs, the second when adding a new HDU from a file which selected HDUs were
// read on construction.
ExtHDU* requested = checkAlreadyRead(0, hduName, version);
if (!requested)
{
HDUCreator create(this);
try
{
// primary is always false here.
ExtHDU* newHDU = static_cast<ExtHDU*>(create.getHdu(hduName, readDataFlag, keys, false, version));
// add a specified HDU in the file to the list of extensions.
addExtension(newHDU);
}
catch ( ... )
{
std::ostringstream msg;
msg << hduName << " with version " << version;
throw NoSuchHDU(msg.str());
}
}
else
{
requested->makeThisCurrent();
requested->readData(readDataFlag,keys);
}
}
void FITS::read (const std::vector<String> &hduNames, bool readDataFlag)
{
const size_t nHdu = hduNames.size();
const std::vector<String> dummy;
for (size_t i=0; i<nHdu; ++i)
{
try
{
read(hduNames[i], readDataFlag, dummy, 1);
}
catch (NoSuchHDU&)
{
// If one Hdu is missing, keep trying the rest.
continue;
}
}
}
void FITS::read (const std::vector<String> &hduNames, const std::vector<std::vector<String> > &keys, bool readDataFlag, const std::vector<int>& hduVersions)
{
const size_t nHdu = hduNames.size();
const size_t nKeys = keys.size();
const size_t nVersions = hduVersions.size();
const std::vector<String> dummy;
for (size_t i=0; i<nHdu; ++i)
{
const std::vector<String>& hduKeys = (i < nKeys) ? keys[i] : dummy;
int version = (i < nVersions) ? hduVersions[i] : 1;
try
{
read(hduNames[i], readDataFlag, hduKeys, version);
}
catch (NoSuchHDU&)
{
continue;
}
}
}
void FITS::read (int hduIndex, bool readDataFlag, const std::vector<String> &keys)
{
if (hduIndex == 0)
{
std::cerr << "Primary header is always read, doesn't need to be requested."
<< std::endl;
return;
}
ExtHDU* requested = checkAlreadyRead(hduIndex);
if (!requested)
{
HDUCreator create(this);
try
{
ExtHDU* newHDU = static_cast<ExtHDU*>(create.getHdu(hduIndex,readDataFlag,keys));
// add a specified HDU in the file to the list of extensions.
addExtension(newHDU);
}
catch ( ... )
{
std::ostringstream msg;
msg << "Error: Could not read extension: " << hduIndex;
throw NoSuchHDU(msg.str());
}
}
else
{
requested->makeThisCurrent();
requested->readData(readDataFlag,keys);
}
}
void FITS::read (const std::vector<String>& searchKeys, const std::vector<String> &searchValues, bool readDataFlag, const std::vector<String>& hduKeys, int version)
{
int totalHDUs = 1;
int status = 0;
if (fits_get_num_hdus(m_fptr,&totalHDUs,&status) != 0) throw FitsError(status);
HDUCreator createTest(this);
int hduIndex;
// there's one less extension than total HDUs!
bool gotIt = false;
for (hduIndex = 1; hduIndex < totalHDUs; hduIndex++ )
{
try
{
std::unique_ptr<ExtHDU>
testHDU(static_cast<ExtHDU*>(createTest.getHdu(hduIndex,false,searchKeys)));
std::vector<String> testKeys(searchKeys);
std::vector<String> testResults(searchKeys.size(),"");
// Missing key exceptions are caught and handled at a lower level.
// The result will be a smaller sized testKeys vector.
testHDU->readKeys(testKeys,testResults);
using namespace FITSUtil;
// first: we need to have matched as many keys as were input.
if (testKeys.size() == searchKeys.size())
{
// now go through and check the values that were read
// against the input value list.
size_t k = 0;
gotIt = true;
std::vector<String>::const_iterator vi(searchValues.begin());
std::vector<String>::const_iterator viEnd(searchValues.end());
while (vi != viEnd && gotIt)
{
if (vi->length())
{
// we can at least ignore whitespace
size_t first (testResults[k].find_first_not_of(" \t"));
size_t last (testResults[k].find_last_not_of(" \t"));
gotIt = (lowerCase(testResults[k].substr(first,last+first+1)) == lowerCase(*vi));
}
++k,++vi;
}
if (gotIt)
{
if (version == 1) break;
else
{
int extver = 1;
#ifdef TEMPLATE_AMBIG_DEFECT
testHDU->readKeyMS("EXTVER",extver);
#else
testHDU->readKey("EXTVER",extver);
#endif
if (extver == version) break;
else gotIt = false;
}
}
}
}
catch (HDU::NoSuchKeyword)
{
// catches the case where the version is requested but there
// is no version key present.
createTest.reset();
continue;
}
catch (FitsError)
{
createTest.reset();
continue;
}
catch (...)
{
throw;
}
createTest.reset();
}
if (gotIt)
{
String extname("");
int extver = 1;
ExtHDU::readHduName(m_fptr,hduIndex,extname,extver);
read(extname,readDataFlag,hduKeys,extver);
currentExtensionName(extname);
}
else
{
#ifdef SSTREAM_DEFECT
std::ostrstream err;
#else
std::ostringstream err;
#endif
err << "Error: Unable to find extension containing keywords ";
std::copy(searchKeys.begin(),searchKeys.end(),
std::ostream_iterator<String>(err," "));
err << "\nwith required values and version number ";
#ifdef SSTREAM_DEFECT
err << std::ends;
#endif
throw NoSuchHDU(err.str());
}
}
int FITS::open (RWmode rwmode)
{
int status=0;
// unused: bool silentMode = true;
status = fits_open_file(&m_fptr, name().c_str(), rwmode, &status);
if (status != 0)
{
if (status == FILE_NOT_OPENED) throw CantOpen(name());
else throw FitsError(status);
}
int currentHDU=0;
fits_get_hdu_num(m_fptr, ¤tHDU);
// convert to 0-based
currentHDU -= 1;
return currentHDU;
}
bool FITS::create ()
{
int status(0);
// if the filename indicates overwrite (starts with a '!' - see
// fits_create_file documentation)
// or the filename does not correspond to an existing file, create file.
// otherwise throw an overwrite exception.
// if the file is writeable and the name doesn't begin with '!'
// we want read/write access so should use fits_open_file,
// otherwise create it. We let cfitsio worry about what
// happens if open-with-write-mode or create fails.
// but we must know whether the file exists.
string fName = m_filename;
if (fName[0] == '!')
{
m_filename = fName.substr(1);
}
// Create a new file, the '!' is processed by ffinit.
// If '[]' extended syntax is used this returns an error of
// one kind or another (which includes FILE_NOT_CREATED if
// the file already exists).
fits_create_file(&m_fptr,fName.c_str(),&status);
if ( status )
{
// The open function must succeed, else we're left with
// a NULL m_fptr with which we can't continue.
try
{
if (status == FILE_NOT_CREATED )
{
string warn(" File already exists: ");
warn += fName;
warn += " attempting to open existing file";
if (verboseMode()) std::cerr << warn << '\n';
open(Write);
}
else
{
throw CantCreate(fName);
}
}
catch (FitsException&) { throw; }
return false;
}
return true;
}
int FITS::close () throw ()
{
int status=0;
status = fits_close_file(m_fptr, &status);
if (!status) m_fptr = 0;
return status;
}
const ExtHDU& FITS::extension (int i) const
{
const ExtMap& ext = m_extension;
ExtMapConstIt hduByNum = ext.begin();
ExtMapConstIt endOfList = ext.end();
while (hduByNum != endOfList)
{
if ((*hduByNum).second->index() == i) break;
++hduByNum;
}
if (hduByNum == endOfList)
{
#ifdef SSTREAM_DEFECT
std::strstream msg;
#else
std::ostringstream msg;
#endif
msg << "No HDU with index " << i << '\n';
throw NoSuchHDU(msg.str());
}
(*hduByNum).second->makeThisCurrent();
return *((*hduByNum).second);
}
std::ostream & FITS::put (std::ostream &s) const
{
s << "FITS:: Primary HDU: \n" ;
s << pHDU() << endl;
s << "FITS:: Extensions: \n";
const ExtMap& ext = m_extension;
ExtMapConstIt endOfList = ext.end();
for (ExtMapConstIt it = ext.begin();
it != endOfList;
++it)
s << *((*it).second) << endl;
return s;
}
ExtHDU& FITS::extension (int i)
{
ExtMap& ext = m_extension;
ExtMapIt hduByNum = ext.begin();
ExtMapIt endOfList = ext.end();
while (hduByNum != endOfList)
{
if ((*hduByNum).second->index() == i) break;
++hduByNum;
}
if (hduByNum == endOfList)
{
#ifdef SSTREAM_DEFECT
std:: strstream msg;
#else
std::ostringstream msg;
#endif
msg << "No HDU with index " << i;
throw NoSuchHDU(msg.str());
}
(*hduByNum).second->makeThisCurrent();
return *((*hduByNum).second);
}
const ExtHDU& FITS::extension (const String& hduName, int version) const
{
return extbyVersion(hduName,version);
}
ExtHDU& FITS::extbyVersion (const String& hduName, int version) const
{
// hey! remember it's a multimap and we need to work a little harder!
// first, for convenience...
// how many extensions with name hduName?
const ExtMap& ext = m_extension;
ExtMap::size_type n = ext.count(hduName);
if (n == 0)
{
#ifdef SSTREAM_DEFECT
std::strstream msg;
#else
std::ostringstream msg;
#endif
msg << "No HDU with name " << hduName;
if (version) msg << " and version " << version;
throw NoSuchHDU(msg.str());
}
// ignore version checking if there is only one version present.
ExtMapConstIt c = ext.lower_bound(hduName);
if ( n > 1)
{
ExtMapConstIt last = ext.upper_bound(hduName);
while ( c != last )
{
if ((*c).second->version() == version) break;
c++;
}
if ( c == last )
{
#ifdef SSTREAM_DEFECT
std::ostrstream msg;
#else
std::ostringstream msg;
#endif
msg << "No HDU with name " << hduName;
if (version != 1) msg << " and version " << version;
#ifdef SSTREAM_DEFECT
msg << std::ends;
#endif
throw NoSuchHDU(msg.str());
}
}
(*c).second->makeThisCurrent();
return *((*c).second);
}
void FITS::readExtensions (bool readDataFlag)
{
HDUCreator create(this);
int status = 0;
int numHDUs = 0;
if (fits_get_num_hdus(m_fptr,&numHDUs,&status) != 0) throw FitsError(status);
// Not clearly exception safe : revisit!!!
// Unused: ExtHDU* newExt = 0;
// there's one less Extension than HDUs. Here, if there are 5 HDUs there are 4 extensions,
// and this loop should execute 4 times. HDU index 1 is the first extension, not the primary.
for (int i = 1; i < numHDUs ; i++)
{
addExtension(static_cast<ExtHDU*>(create.getHdu(i,readDataFlag)));
create.reset();
}
}
Table* FITS::addTable (const String& hduName, int rows,
const std::vector<String>& columnName,
const std::vector<String>& columnFmt,
const std::vector<String>& columnUnit,
HduType type, int version)
{
ExtHDU* current(0);
size_t N(m_extension.count(hduName));
std::pair<ExtMapIt,ExtMapIt> matches(m_extension.equal_range(hduName));
if ( N > 0 )
{
ExtMapIt s(matches.first);
while ( s != matches.second )
{
if (s->second->version() == version && dynamic_cast<Table*>(s->second) )
{
current = s->second;
std::cerr << " Table Extension " << hduName << " with version "
<< version << " already exists "
<< " returning token for existing version \n";
}
++s;
}
}
if ( !current )
{
HDUCreator newTable(this);
Table* newHDU = static_cast<Table*>(newTable.createTable(hduName, type, rows,
columnName, columnFmt, columnUnit, version));
current = addExtension(newHDU);
}
return static_cast<Table*>(current);
}
Table * FITS::addGroupTable(const String & groupName, int groupID)
{
// +++ if I wanted to call addTable and specify HduType type = GroupTbl, I would need to provide column defs
// plus, GroupTbl isn't a real HduType according to cfitsio, so I don't know if I want to add it to that enum
// so I will mimic a lot of addTable. I'm not sure if all this repeating is correct.
string hduName("GROUPING");
ExtHDU* current(0);
size_t N(m_extension.count(hduName));
std::pair<ExtMapIt,ExtMapIt> matches(m_extension.equal_range(hduName));
if ( N > 0 )
{
ExtMapIt s(matches.first);
while ( s != matches.second )
{
// +++ I think version means EXTVER
if (s->second->version() == groupID && dynamic_cast<Table*>(s->second) )
{
current = s->second;
std::cerr << " Table Extension " << hduName << " with version "
<< groupID << " already exists "
<< " returning token for existing version \n";
}
++s;
}
}
if ( !current )
{
HDUCreator newTable(this);
ExtHDU* newHDU = static_cast<Table*>(newTable.createTable(groupName, GroupTbl, 0, std::vector<String>(), std::vector<String>(), std::vector<String>(), groupID));
current = addExtension(newHDU);
}
// now assign the grouping name
// +++ but HDU::addKeyword is private?
return static_cast<Table*>(current);
//return static_cast<GroupTable*>(current);
//
// // the C prototypes don't use const, so these casts are necessary.
// char * gName = const_cast<char*>(groupName.c_str());
//
// // +++ another option is to call addTable with the columns we want, and not use the built in cfitsio fn
// // +++ just add it to the end of the file for now
// if ( fits_create_group(m_fptr, gName, GT_ID_ALL_URI, &status) ) throw FitsError(status);
//
// // which extension index is the new ext
// int numHDUs = fits_get_num_hdus (m_fptr, > int *hdunum, &status);
// if (status) throw FitsError(status);
//
// HDUCreator newTable(this);
// // index of primary = 0
// HDU * newHDU = newTable.getHdu(numHDUs-1);
//
// // create the GroupTable
// GroupTable * groupTable;
//
//
// // now add the GroupTable to this FITS file
// // I know that this latest HDU is an extension, since I just added it,
// // so I can safely cast
// ExtHDU * newExtHDU = addExtension(static_cast<ExtHDU*>());
// //+++ if (newExtHDU == 0) throw ;
//
}
ExtHDU* FITS::addImage (const String& hduName, int bpix, std::vector<long>& naxes, int version)
{
ExtHDU* current(0);
size_t N(m_extension.count(hduName));
std::pair<ExtMapIt,ExtMapIt> matches(m_extension.equal_range(hduName));
if ( N > 0 )
{
ExtMapIt s(matches.first);
while (!current && s != matches.second )
{
if ( s->second->version() == version )
{
std::cerr << " Extension " << hduName << " with version "
<< version << " already exists "
<< " returning token for existing version \n";
current = s->second;
}
++s;
}
}
if (!current)