GammaLib 2.0.0
Loading...
Searching...
No Matches
GFitsHeader.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GFitsHeader.hpp - FITS header cards container class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2008-2017 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- *
6 * *
7 * This program is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 * *
20 ***************************************************************************/
21/**
22 * @file GFitsHeader.cpp
23 * @brief FITS header cards container class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include "GException.hpp"
32#include "GFitsCfitsio.hpp"
33#include "GFits.hpp"
34#include "GFitsHeader.hpp"
35#include "GTools.hpp"
36
37/* __ Method name definitions ____________________________________________ */
38#define G_AT1 "GFitsHeaderCard& GFitsHeader::at(int&)"
39#define G_AT2 "GFitsHeaderCard& GFitsHeader::at(std::string&)"
40#define G_STRING1 "GFitsHeader::string(int&)"
41#define G_STRING2 "GFitsHeader::string(std::string&)"
42#define G_REAL1 "GFitsHeader::real(int&)"
43#define G_REAL2 "GFitsHeader::real(std::string&)"
44#define G_INTEGER1 "GFitsHeader::integer(int&)"
45#define G_INTEGER2 "GFitsHeader::integer(std::string&)"
46#define G_INSERT1 "GFitsHeader::insert(int&, GFitsHeaderCard&)"
47#define G_INSERT2 "GFitsHeader::insert(std::string&, GFitsHeaderCard&)"
48#define G_REMOVE1 "GFitsHeader::remove(int&)"
49#define G_REMOVE2 "GFitsHeader::remove(std::string&)"
50#define G_OPEN "GFitsHeader::open(void*)"
51#define G_SAVE "GFitsHeader::save(void*)"
52
53/* __ Macros _____________________________________________________________ */
54
55/* __ Coding definitions _________________________________________________ */
56
57/* __ Debug definitions __________________________________________________ */
58
59
60
61/*==========================================================================
62 = =
63 = Constructors/destructors =
64 = =
65 ==========================================================================*/
66
67/***********************************************************************//**
68 * @brief Constructor
69 ***************************************************************************/
71{
72 // Initialise class members for clean destruction
74
75 // Return
76 return;
77}
78
79
80/***********************************************************************//**
81 * @brief Copy constructor
82 *
83 * @param header FITS header.
84 ***************************************************************************/
86{
87 // Initialise class members for clean destruction
89
90 // Copy members
91 copy_members(header);
92
93 // Return
94 return;
95}
96
97
98/***********************************************************************//**
99 * @brief Destructor
100 ***************************************************************************/
102{
103 // Free members
104 free_members();
105
106 // Return
107 return;
108}
109
110
111/*==========================================================================
112 = =
113 = Operators =
114 = =
115 ==========================================================================*/
116
117/***********************************************************************//**
118 * @brief Assignment operator
119 *
120 * @param header FITS header.
121 * @return FITS header.
122 ***************************************************************************/
124{
125 // Execute only if object is not identical
126 if (this != &header) {
127
128 // Free members
129 free_members();
130
131 // Initialise private members for clean destruction
132 init_members();
133
134 // Copy members
135 copy_members(header);
136
137 } // endif: object was not identical
138
139 // Return this object
140 return *this;
141}
142
143
144/*==========================================================================
145 = =
146 = Public methods =
147 = =
148 ==========================================================================*/
149
150/***********************************************************************//**
151 * @brief Clear header
152 ***************************************************************************/
154{
155 // Free members
156 free_members();
157
158 // Initialise members
159 init_members();
160
161 // Return
162 return;
163}
164
165
166/***********************************************************************//**
167 * @brief Clone header
168 *
169 * @return Pointer to deep copy of header.
170 ***************************************************************************/
172{
173 return new GFitsHeader(*this);
174}
175
176
177/***********************************************************************//**
178 * @brief Return header card
179 *
180 * @param[in] cardno Number of card in header [0,...,size()-1]
181 * @return Header card.
182 *
183 * @exception GException::out_of_range
184 * Card number out of range.
185 ***************************************************************************/
187{
188 // Compile option: raise an exception if cardno is out of range
189 #if defined(G_RANGE_CHECK)
190 if (!contains(cardno)) {
191 throw GException::out_of_range(G_AT1, "Header card number", cardno, size());
192 }
193 #endif
194
195 // Return card
196 return (m_cards[cardno]);
197}
198
199
200/***********************************************************************//**
201 * @brief Return header card (const version)
202 *
203 * @param[in] cardno Number of card in header [0,...,size()-1]
204 * @return Header card.
205 *
206 * @exception GException::out_of_range
207 * Card number out of range.
208 ***************************************************************************/
209const GFitsHeaderCard& GFitsHeader::at(const int& cardno) const
210{
211 // Compile option: raise an exception if cardno is out of range
212 #if defined(G_RANGE_CHECK)
213 if (!contains(cardno)) {
214 throw GException::out_of_range(G_AT1, "Header card number", cardno, size());
215 }
216 #endif
217
218 // Return card
219 return (m_cards[cardno]);
220}
221
222
223/***********************************************************************//**
224 * @brief Return header card
225 *
226 * @param[in] keyname Name of header card
227 * @return Header card.
228 *
229 * @exception GException::invalid_argument
230 * Key name not found.
231 ***************************************************************************/
232GFitsHeaderCard& GFitsHeader::at(const std::string& keyname)
233{
234 // Get card number
235 int cardno = get_index(keyname);
236
237 // Throw an exception if keyname is not found
238 if (cardno == -1) {
239 std::string msg = "Keyword \""+keyname+"\" not found in FITS header.";
241 }
242
243 // Return card
244 return (m_cards[cardno]);
245}
246
247
248/***********************************************************************//**
249 * @brief Return header card (const version)
250 *
251 * @param[in] keyname Name of header card
252 * @return Header card.
253 *
254 * @exception GException::invalid_argument
255 * Key name not found.
256 ***************************************************************************/
257const GFitsHeaderCard& GFitsHeader::at(const std::string& keyname) const
258{
259 // Get card number
260 int cardno = get_index(keyname);
261
262 // Throw an exception if keyname is not found
263 if (cardno == -1) {
264 std::string msg = "Keyword \""+keyname+"\" not found in FITS header.";
266 }
267
268 // Return card
269 return (m_cards[cardno]);
270}
271
272
273/***********************************************************************//**
274 * @brief Return header card value as string value
275 *
276 * @param[in] cardno Header card number [0,...,size()-1].
277 * @return Header card string value.
278 *
279 * @exception GException::out_of_range
280 * Card number out of range.
281 ***************************************************************************/
282std::string GFitsHeader::string(const int& cardno) const
283{
284 // Compile option: raise an exception if cardno is out of range
285 #if defined(G_RANGE_CHECK)
286 if (!contains(cardno)) {
287 throw GException::out_of_range(G_STRING1, "Header card number", cardno, size());
288 }
289 #endif
290
291 // Return card value
292 return (m_cards[cardno].string());
293}
294
295
296/***********************************************************************//**
297 * @brief Return header card value as string value
298 *
299 * @param[in] keyname Header card key name.
300 * @return Header card string value.
301 *
302 * @exception GException::invalid_argument
303 * Key name not found.
304 ***************************************************************************/
305std::string GFitsHeader::string(const std::string& keyname) const
306{
307 // Get card number
308 int cardno = get_index(keyname);
309
310 // Throw an exception if keyname is not found
311 if (cardno == -1) {
312 std::string msg = "Keyword \""+keyname+"\" not found in FITS header.";
314 }
315
316 // Return card value
317 return (m_cards[cardno].string());
318}
319
320
321/***********************************************************************//**
322 * @brief Return header card value as double precision value
323 *
324 * @param[in] cardno Header card number [0,...,size()-1].
325 * @return Header card double precision value.
326 *
327 * @exception GException::out_of_range
328 * Card number out of range.
329 ***************************************************************************/
330double GFitsHeader::real(const int& cardno) const
331{
332 // Compile option: raise an exception if cardno is out of range
333 #if defined(G_RANGE_CHECK)
334 if (!contains(cardno)) {
335 throw GException::out_of_range(G_REAL1, "Header card number", cardno, size());
336 }
337 #endif
338
339 // Return card value
340 return (m_cards[cardno].real());
341}
342
343
344/***********************************************************************//**
345 * @brief Return header card value as double precision value
346 *
347 * @param[in] keyname Header card key name.
348 * @return Header card double precision value.
349 *
350 * @exception GException::invalid_argument
351 * Key name not found.
352 ***************************************************************************/
353double GFitsHeader::real(const std::string& keyname) const
354{
355 // Get card number
356 int cardno = get_index(keyname);
357
358 // Throw an exception if keyname is not found
359 if (cardno == -1) {
360 std::string msg = "Keyword \""+keyname+"\" not found in FITS header.";
362 }
363
364 // Return card value
365 return (m_cards[cardno].real());
366}
367
368
369/***********************************************************************//**
370 * @brief Return header card value as integer value
371 *
372 * @param[in] cardno Header card number [0,...,size()-1].
373 * @return Header card integer value.
374 *
375 * @exception GException::out_of_range
376 * Card number out of range.
377 ***************************************************************************/
378int GFitsHeader::integer(const int& cardno) const
379{
380 // Compile option: raise an exception if cardno is out of range
381 #if defined(G_RANGE_CHECK)
382 if (!contains(cardno)) {
383 throw GException::out_of_range(G_INTEGER1, "Header card number", cardno, size());
384 }
385 #endif
386
387 // Return card value
388 return (m_cards[cardno].integer());
389}
390
391
392/***********************************************************************//**
393 * @brief Return header card value as integer value
394 *
395 * @param[in] keyname Header card key name.
396 * @return Header card integer value.
397 *
398 * @exception GException::invalid_argument
399 * Key name not found.
400 ***************************************************************************/
401int GFitsHeader::integer(const std::string& keyname) const
402{
403 // Get card number
404 int cardno = get_index(keyname);
405
406 // Throw an exception if keyname is not found
407 if (cardno == -1) {
408 std::string msg = "Keyword \""+keyname+"\" not found in FITS header.";
410 }
411
412 // Return card value
413 return (m_cards[cardno].integer());
414}
415
416
417/***********************************************************************//**
418 * @brief Append or update header card
419 *
420 * @param[in] card Header card.
421 * @return Reference to appended header card.
422 *
423 * If the keyname of the header @p card does not yet exist in the header
424 * (or if the keyname is COMMENT or HISTORY) then append the header card
425 * to the header. If the keyname exists already, the header card is updated.
426 ***************************************************************************/
428{
429 // If card keyname is not COMMENT or HISTORY, then check first if
430 // card exists. If yes then update existing card
431 int cardno = -1;
432 if (card.keyname() != "COMMENT" && card.keyname() != "HISTORY") {
433 cardno = get_index(card.keyname());
434 if (cardno != -1) {
435 m_cards[cardno] = card;
436 m_keyname_map[card.keyname()] = &m_cards[cardno];
437 }
438 }
439
440 // If card has not yet been updated then append card to header
441 if (cardno == -1) {
442 m_cards.push_back(card);
444 cardno = size()-1;
445 }
446
447 // Return reference
448 return (m_cards[cardno]);
449}
450
451
452/***********************************************************************//**
453 * @brief Insert card into header
454 *
455 * @param[in] cardno Header card number [0,...,size()-1].
456 * @param[in] card Header card.
457 * @return Reference to inserted header card.
458 *
459 * @exception GException::out_of_range
460 * Card number out of range.
461 *
462 * Inserts a @p card into the header before the card with the specified card
463 * number @p cardno.
464 ***************************************************************************/
466 const GFitsHeaderCard& card)
467{
468 // Compile option: raise exception if index is out of range
469 #if defined(G_RANGE_CHECK)
470 if (is_empty()) {
471 if (cardno > 0) {
472 throw GException::out_of_range(G_INSERT1, "Header card number",
473 cardno, size());
474 }
475 }
476 else {
477 if (cardno < 0 || cardno >= size()) {
478 throw GException::out_of_range(G_INSERT1, "Header card number",
479 cardno, size());
480 }
481 }
482 #endif
483
484 // Inserts card
485 m_cards.insert(m_cards.begin()+cardno, card);
486
487 // Update map of header cards
489
490 // Return reference
491 return m_cards[cardno];
492}
493
494
495/***********************************************************************//**
496 * @brief Insert card into header
497 *
498 * @param[in] keyname Header card key name.
499 * @param[in] card Header card.
500 * @return Reference to inserted header card.
501 *
502 * @exception GException::invalid_argument
503 * Key name not found.
504 *
505 * Inserts a @p card into the header before the card with the specified
506 * @p keyname.
507 ***************************************************************************/
508GFitsHeaderCard& GFitsHeader::insert(const std::string& keyname,
509 const GFitsHeaderCard& card)
510{
511 // Get card number
512 int cardno = get_index(keyname);
513
514 // Throw an exception if keyname is not found
515 if (cardno == -1) {
516 std::string msg = "Keyword \""+keyname+"\" not found in FITS header.";
518 }
519
520 // Inserts card
521 m_cards.insert(m_cards.begin()+cardno, card);
522
523 // Update map of header cards
525
526 // Return reference
527 return m_cards[cardno];
528}
529
530
531/***********************************************************************//**
532 * @brief Remove card from header
533 *
534 * @param[in] cardno Header card number [0,...,size()-1].
535 *
536 * @exception GException::out_of_range
537 * Card number out of range.
538 *
539 * Remove header card of specified card number from container.
540 ***************************************************************************/
541void GFitsHeader::remove(const int& cardno)
542{
543 // Compile option: raise an exception if cardno is out of range
544 #if defined(G_RANGE_CHECK)
545 if (!contains(cardno)) {
546 throw GException::out_of_range(G_REMOVE1, "Header card number", cardno, size());
547 }
548 #endif
549
550 // Erase card from header
551 m_cards.erase(m_cards.begin() + cardno);
552
553 // Update map of header cards
555
556 // Return
557 return;
558}
559
560
561/***********************************************************************//**
562 * @brief Remove card from header
563 *
564 * @param[in] keyname Header card key name.
565 *
566 * @exception GException::invalid_argument
567 * Key name not found.
568 *
569 * Remove card with specified @p keyname from header.
570 ***************************************************************************/
571void GFitsHeader::remove(const std::string& keyname)
572{
573 // Get card number
574 int cardno = get_index(keyname);
575
576 // Throw an exception if keyname is not found
577 if (cardno == -1) {
578 std::string msg = "Keyword \""+keyname+"\" not found in FITS header.";
580 }
581
582 // Erase card from header
583 m_cards.erase(m_cards.begin() + cardno);
584
585 // Update map of header cards
587
588 // Return
589 return;
590}
591
592
593/***********************************************************************//**
594 * @brief Append header
595 *
596 * @param[in] header FITS header.
597 *
598 * Append all cards from a FITS header to the actual header.
599 ***************************************************************************/
601{
602 // Do nothing if header is empty
603 if (!header.is_empty()) {
604
605 // Get size. Note that we extract the size first to avoid an
606 // endless loop that arises when a container is appended to
607 // itself.
608 int num = header.size();
609
610 // Reserve enough space
611 reserve(size() + num);
612
613 // Loop over all card and append them to the header
614 for (int i = 0; i < num; ++i) {
615 m_cards.push_back(header[i]);
616 }
617
618 // Update map of header cards
620
621 } // endif: header was not empty
622
623 // Return
624 return;
625}
626
627
628/***********************************************************************//**
629 * @brief Load header from FITS file
630 *
631 * @param[in] vptr FITS file void pointer.
632 *
633 * @exception GException::fits_error
634 * FITS error occured.
635 *
636 * Loads all header cards into memory. Any header cards that existed before
637 * will be dropped.
638 ***************************************************************************/
639void GFitsHeader::load(void* vptr)
640{
641 // Move to HDU
643
644 // Determine number of cards in header
645 int status = 0;
646 int num_cards = 0;
647 status = __ffghsp(FPTR(vptr), &num_cards, NULL, &status);
648 if (status != 0) {
649 throw GException::fits_error(G_OPEN, status);
650 }
651
652 // Drop any old cards and reserve space for new cards
653 m_cards.clear();
654 reserve(num_cards);
655
656 // Read all cards
657 for (int i = 0; i < num_cards; ++i) {
658 GFitsHeaderCard card;
659 card.read(FPTR(vptr), i+1);
660 m_cards.push_back(card);
661 }
662
663 // Update map of header cards
665
666 // Return
667 return;
668}
669
670
671/***********************************************************************//**
672 * @brief Save header to FITS file
673 *
674 * @param[in] vptr FITS file void pointer.
675 *
676 * @exception GException::fits_error
677 * FITS error occured.
678 *
679 * Saves all header cards into HDU. This method does not write the following
680 * mandatory keywords to the HDU (those will be written by methods handling
681 * the data of the HDU):
682 * 'SIMPLE'
683 * 'BITPIX'
684 * 'NAXIS', 'NAXIS1', 'NAXIS2', etc.
685 * 'EXTEND'
686 * 'PCOUNT'
687 * 'GCOUNT'
688 ***************************************************************************/
689void GFitsHeader::save(void* vptr) const
690{
691 // Save all cards
692 for (int i = 0; i < size(); ++i) {
693 if (m_cards[i].keyname() != "SIMPLE" &&
694 m_cards[i].keyname() != "XTENSION" &&
695 m_cards[i].keyname() != "BITPIX" &&
696 m_cards[i].keyname() != "EXTEND" &&
697 m_cards[i].keyname() != "PCOUNT" &&
698 m_cards[i].keyname() != "GCOUNT" &&
699 m_cards[i].keyname().find("NAXIS") == std::string::npos) {
700 m_cards[i].write(FPTR(vptr));
701 }
702 }
703
704 // Return
705 return;
706}
707
708
709/***********************************************************************//**
710 * @brief Print FITS header information
711 *
712 * @param[in] chatter Chattiness.
713 * @return String containing FITS header information.
714 ***************************************************************************/
715std::string GFitsHeader::print(const GChatter& chatter) const
716{
717 // Initialise result string
718 std::string result;
719
720 // Continue only if chatter is not silent
721 if (chatter != SILENT) {
722
723 // Append header
724 result.append("=== GFitsHeader ("+gammalib::str(size())+" cards) ===");
725
726 // NORMAL: Append cards
727 if (chatter >= NORMAL) {
728 for (int i = 0; i < size(); ++i) {
729 result.append("\n"+m_cards[i].print());
730 }
731 }
732
733 } // endif: chatter was not silent
734
735 // Return result
736 return result;
737}
738
739
740/*==========================================================================
741 = =
742 = Private methods =
743 = =
744 ==========================================================================*/
745
746/***********************************************************************//**
747 * @brief Initialise class members
748 ***************************************************************************/
750{
751 // Initialise members
752 m_cards.clear();
753 m_keyname_map.clear();
754
755 // Return
756 return;
757}
758
759
760/***********************************************************************//**
761 * @brief Copy class members
762 *
763 * @param[in] header FITS header.
764 ***************************************************************************/
766{
767 // Copy members
768 m_cards = header.m_cards;
769
770 // Update map of header cards
772
773 // Return
774 return;
775}
776
777
778/***********************************************************************//**
779 * @brief Delete class members
780 ***************************************************************************/
782{
783 // Return
784 return;
785}
786
787
788/***********************************************************************//**
789 * @brief Get index of header card
790 *
791 * @param[in] keyname Header card key name.
792 * @return Index of header card (-1 if @p keyname is not found)
793 *
794 * Returns index of header card based on the @p keyname. If no header card
795 * is found, -1 is returned.
796 ***************************************************************************/
797int GFitsHeader::get_index(const std::string& keyname) const
798{
799 // Initialise index
800 int index = -1;
801
802 // Set iterator over header cards
803 std::map<std::string, GFitsHeaderCard*>::const_iterator iter =
804 m_keyname_map.find(keyname);
805
806 // If the iterator does not point to the end the return the header card
807 if (iter != m_keyname_map.end()){
808 // Taking the difference between the addresses allows us to derive
809 // the index of the entry, since std::vector guarantess its entries
810 // are stored contiguously in memory
811 index = iter->second - &m_cards[0];
812 }
813
814 // Return index
815 return index;
816}
817
818
819/***********************************************************************//**
820* @brief Update the header card pointers
821*
822* Sets up a map between header card keywords and pointers to header cards.
823* This enables fast access of header cards in a FITS header.
824*
825* This method needs to be called whenever the list of header cards is
826* modified.
827***************************************************************************/
829{
830 // Clear header card maps
831 m_keyname_map.clear();
832
833 // Setup a map between header card keywords and header card pointers
834 for (int i = 0; i < m_cards.size(); ++i) {
835 m_keyname_map.insert(std::make_pair(m_cards[i].keyname(), &m_cards[i]));
836 }
837
838 // Return
839 return;
840}
#define G_REMOVE1
#define G_INSERT2
#define G_INSERT1
#define G_REMOVE2
Exception handler interface definition.
CFITSIO interface header.
#define FPTR(A)
#define __ffghsp(A, B, C, D)
#define G_REAL2
#define G_INTEGER2
#define G_INTEGER1
#define G_REAL1
#define G_STRING1
#define G_STRING2
FITS header cards container class definition.
#define G_AT2
Definition GFits.cpp:52
#define G_AT1
Definition GFits.cpp:51
#define G_OPEN
Definition GFits.cpp:63
FITS file class interface definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ NORMAL
Definition GTypemaps.hpp:36
@ SILENT
Definition GTypemaps.hpp:34
Implements FITS header card interface.
void keyname(const std::string &keyname)
Set name of header card.
void read(void *vptr, const int &keynum)
Read header card from FITS file.
Interface for FITS header class.
void free_members(void)
Delete class members.
std::vector< GFitsHeaderCard > m_cards
Header cards.
GFitsHeader * clone(void) const
Clone header.
bool contains(const int &cardno) const
Check if card is present in header.
virtual ~GFitsHeader(void)
Destructor.
void reserve(const int &num)
Reserves space for cards in FITS header.
std::string string(const int &cardno) const
Return header card value as string value.
int get_index(const std::string &keyname) const
Get index of header card.
GFitsHeader(void)
Constructor.
GFitsHeaderCard & at(const int &cardno)
Return header card.
void init_members(void)
Initialise class members.
void save(void *vptr) const
Save header to FITS file.
void remove(const int &cardno)
Remove card from header.
void copy_members(const GFitsHeader &header)
Copy class members.
GFitsHeaderCard & append(const GFitsHeaderCard &card)
Append or update header card.
GFitsHeader & operator=(const GFitsHeader &header)
Assignment operator.
std::string print(const GChatter &chatter=NORMAL) const
Print FITS header information.
void extend(const GFitsHeader &header)
Append header.
void clear(void)
Clear header.
int integer(const int &cardno) const
Return header card value as integer value.
std::map< std::string, GFitsHeaderCard * > m_keyname_map
Header pointers.
GFitsHeaderCard & insert(const int &cardno, const GFitsHeaderCard &card)
Insert card into header.
void update_keyname_map(void)
Update the header card pointers.
double real(const int &cardno) const
Return header card value as double precision value.
void load(void *vptr)
Load header from FITS file.
int size(void) const
Return number of cards in header.
bool is_empty(void) const
Signals if there are no cards in the FITS header.
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
int fits_move_to_hdu(const std::string &caller, void *vptr, const int &hdunum=0)
Move to FITS extension.
Definition GFits.cpp:1774