GammaLib 2.0.0
Loading...
Searching...
No Matches
GPha.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GPha.cpp - XSPEC Pulse Height Analyzer class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2013-2018 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 GPha.cpp
23 * @brief XSPEC Pulse Height Analyzer class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include "GPha.hpp"
32#include "GException.hpp"
33#include "GTools.hpp"
34#include "GEnergy.hpp"
35#include "GFits.hpp"
36#include "GFitsTable.hpp"
37#include "GFitsBinTable.hpp"
40#include "GNdarray.hpp"
41
42/* __ Method name definitions ____________________________________________ */
43#define G_OPERATOR_PLUS "GPha::operator+=(GPha&)"
44#define G_OPERATOR_MINUS "GPha::operator-=(GPha&)"
45#define G_OPERATOR "GPha::operator[](std::string&)"
46#define G_AT1 "GPha::at(int&)"
47#define G_AT2 "GPha::at(int&, int&)"
48#define G_APPEND "GPha::append(std::string&, std::vector<double>&)"
49#define G_AREASCAL_SET "GPha::areascal(int&, double&)"
50#define G_AREASCAL_GET "GPha::areascal(int&)"
51#define G_BACKSCAL_SET "GPha::backscal(int&, double&)"
52#define G_BACKSCAL_GET "GPha::backscal(int&)"
53#define G_READ "GPha::read(GFitsTable*)"
54
55/* __ Macros _____________________________________________________________ */
56
57/* __ Coding definitions _________________________________________________ */
58
59/* __ Debug definitions __________________________________________________ */
60
61
62/*==========================================================================
63 = =
64 = Constructors/destructors =
65 = =
66 ==========================================================================*/
67
68/***********************************************************************//**
69 * @brief Void constructor
70 ***************************************************************************/
72{
73 // Initialise members
75
76 // Return
77 return;
78}
79
80
81/***********************************************************************//**
82 * @brief File constructor
83 *
84 * @param[in] filename File name.
85 ***************************************************************************/
86GPha::GPha(const GFilename& filename)
87{
88 // Initialise members
90
91 // Load PHA file
93
94 // Return
95 return;
96}
97
98
99/***********************************************************************//**
100 * @brief Energy boundary constructor
101 *
102 * @param[in] ebds Energy boundaries.
103 ***************************************************************************/
105{
106 // Initialise members
107 init_members();
108
109 // Set energy boundaries
110 m_ebounds = ebds;
111
112 // Initialize spectrum
113 alloc(ebds.size());
114
115 // Return
116 return;
117}
118
119
120/***********************************************************************//**
121 * @brief Energy bins constructor
122 *
123 * @param[in] bins Number of energy bins.
124 ***************************************************************************/
125GPha::GPha(const int& bins)
126{
127 // Initialise members
128 init_members();
129
130 // Initialize spectrum
131 alloc(bins);
132
133 // Return
134 return;
135}
136
137
138/***********************************************************************//**
139 * @brief Copy constructor
140 *
141 * @param[in] pha Pulse Height Analyzer spectrum.
142 ***************************************************************************/
143GPha::GPha(const GPha& pha)
144{
145 // Initialise members
146 init_members();
147
148 // Copy members
149 copy_members(pha);
150
151 // Return
152 return;
153}
154
155
156/***********************************************************************//**
157 * @brief Destructor
158 ***************************************************************************/
160{
161 // Free members
162 free_members();
163
164 // Return
165 return;
166}
167
168
169/*==========================================================================
170 = =
171 = Operators =
172 = =
173 ==========================================================================*/
174
175/***********************************************************************//**
176 * @brief Assignment operator
177 *
178 * @param[in] pha Pulse Height Analyzer spectrum.
179 * @return Pulse Height Analyzer spectrum.
180 ***************************************************************************/
182{
183 // Execute only if object is not identical
184 if (this != &pha) {
185
186 // Free members
187 free_members();
188
189 // Initialise members
190 init_members();
191
192 // Copy members
193 copy_members(pha);
194
195 } // endif: object was not identical
196
197 // Return
198 return *this;
199}
200
201
202/***********************************************************************//**
203 * @brief Add spectrum
204 *
205 * @param[in] pha Pulse Height Analyzer spectrum.
206 * @return Sum of Pulse Height Analyzer spectra.
207 *
208 * @exception GException::invalid_value
209 * Incompatible spectrum.
210 *
211 * Adds the counts of a spectrum to the counts of the current spectrum. The
212 * operator also adds the exposure times of the spectrum to the current
213 * exposure time. The area scaling factor \f$\alpha\f$ is recomputed for
214 * each spectral bin using
215 *
216 * \f[
217 * \alpha = \frac{N_1 + N_2}{\frac{N_1}{\alpha_1} + \frac{N_2}{\alpha_2}}
218 * \f]
219 *
220 * where
221 * \f$N_1\f$ and \f$N_2\f$ are the number of events in the bin for spectrum
222 * 1 and 2, respectively, and
223 * \f$\alpha_1\f$ and \f$\alpha_2\f$ are the corresponding area scaling
224 * factors.
225 *
226 * The background scaling factor is not altered.
227 *
228 * The operator only works if the provide specturm has the same energy
229 * binning than the current spectrum.
230 ***************************************************************************/
232{
233 // Throw an exception if the spectra are not compatible
234 if (this->ebounds() != pha.ebounds()) {
235 std::string msg = "Incompatible energy binning of Pulse Height "
236 "Analyzer spectrum.";
238 }
239
240 // Add spectra
241 for (int i = 0; i < this->size(); ++i) {
242
243 // Update the area scaling
244 double n1 = m_counts[i];
245 double n2 = pha.m_counts[i];
246 double a1 = m_areascal[i];
247 double a2 = pha.m_areascal[i];
248 double f1 = (a1 > 0.0) ? n1/a1 : 0.0;
249 double f2 = (a2 > 0.0) ? n2/a2 : 0.0;
250 double f = f1 + f2;
251 m_areascal[i] = (f > 0.0) ? (n1+n2)/f : 1.0;
252
253 // Add counts
254 m_counts[i] += pha.m_counts[i];
255 }
256
257 // Add attributes
259 m_overflow += pha.m_overflow;
260 m_outflow += pha.m_outflow;
261 m_exposure += pha.m_exposure;
262
263 // Return
264 return *this;
265}
266
267
268/***********************************************************************//**
269 * @brief Subtract spectrum
270 *
271 * @param[in] pha Pulse Height Analyzer spectrum.
272 * @return Difference of Pulse Height Analyzer spectra.
273 *
274 * @exception GException::invalid_value
275 * Incompatible spectrum.
276 *
277 * Subtracts the counts of a spectrum from the counts of the current
278 * spectrum. The operator also subtracts the exposure times of the spectrum
279 * from the current exposure time. The area scaling factor \f$\alpha\f$ is
280 * recomputed for each spectral bin using
281 *
282 * \f[
283 * \alpha = \frac{N_1 - N_2}{\frac{N_1}{\alpha_1} - \frac{N_2}{\alpha_2}}
284 * \f]
285 *
286 * where
287 * \f$N_1\f$ and \f$N_2\f$ are the number of events in the bin for spectrum
288 * 1 and 2, respectively, and
289 * \f$\alpha_1\f$ and \f$\alpha_2\f$ are the corresponding area scaling
290 * factors.
291 *
292 * The background scaling factor is not altered.
293 *
294 * The operator only works if the provide specturm has the same energy
295 * binning than the current spectrum.
296 ***************************************************************************/
298{
299 // Throw an exception if the spectra are not compatible
300 if (this->ebounds() != pha.ebounds()) {
301 std::string msg = "Incompatible energy binning of Pulse Height "
302 "Analyzer spectrum.";
304 }
305
306 // Subtract spectra
307 for (int i = 0; i < this->size(); ++i) {
308
309 // Update the area scaling
310 double n1 = m_counts[i];
311 double n2 = pha.m_counts[i];
312 double a1 = m_areascal[i];
313 double a2 = pha.m_areascal[i];
314 double f1 = (a1 > 0.0) ? n1/a1 : 0.0;
315 double f2 = (a2 > 0.0) ? n2/a2 : 0.0;
316 double f = f1 - f2;
317 m_areascal[i] = (f > 0.0) ? (n1-n2)/f : 1.0;
318
319 // Subtract counts
320 m_counts[i] -= pha.m_counts[i];
321 }
322
323 // Subtract attributes
325 m_overflow -= pha.m_overflow;
326 m_outflow -= pha.m_outflow;
327 m_exposure -= pha.m_exposure;
328
329 // Return
330 return *this;
331}
332
333
334/***********************************************************************//**
335 * @brief Scale spectrum values
336 *
337 * @param[in] scale Scale factor.
338 * @return Scaled Pulse Height Analyzer spectrum.
339 *
340 * Multiplies the counts of a spectrum with a scale factor. The exposure
341 * time and area and background scale factors are not altered.
342 ***************************************************************************/
343GPha& GPha::operator*=(const double& scale)
344{
345 // Scale spectrums
346 for (int i = 0; i < this->size(); ++i) {
347 m_counts[i] *= scale;
348 }
349
350 // Scale attributes
351 m_underflow *= scale;
352 m_overflow *= scale;
353 m_outflow *= scale;
354
355 // Return
356 return *this;
357}
358
359
360/***********************************************************************//**
361 * @brief Divide spectrum values
362 *
363 * @param[in] scale Division factor.
364 * @return Divided Pulse Height Analyzer spectrum.
365 *
366 * Divides the counts of a spectrum by a scale factor. The exposure time
367 * and the area and background scale factors are not altered.
368 ***************************************************************************/
369GPha& GPha::operator/=(const double& scale)
370{
371 // Scale spectrums
372 for (int i = 0; i < this->size(); ++i) {
373 m_counts[i] /= scale;
374 }
375
376 // Scale attributes
377 m_underflow /= scale;
378 m_overflow /= scale;
379 m_outflow /= scale;
380
381 // Return
382 return *this;
383}
384
385
386/***********************************************************************//**
387 * @brief Return additional vector column
388 *
389 * @param[in] colname Vector column name.
390 * @return Vector column.
391 *
392 * Returns reference to additional vector column.
393 ***************************************************************************/
394std::vector<double>& GPha::operator[](const std::string& colname)
395{
396 // Determine index of additional column (-1 if not found)
397 int index = column_index(colname);
398
399 // Throw exception if index not found
400 if (index == -1) {
401 std::string msg = "Could not find additional column with name \""+
402 colname+"\".";
404 }
405
406 // Return reference to vector column
407 return (m_coldata[index]);
408}
409
410
411/***********************************************************************//**
412 * @brief Return additional vector column (const version)
413 *
414 * @param[in] colname Vector column name.
415 * @return Vector column.
416 *
417 * Returns reference to additional vector column.
418 ***************************************************************************/
419const std::vector<double>& GPha::operator[](const std::string& colname) const
420{
421 // Determine index of additional column (-1 if not found)
422 int index = column_index(colname);
423
424 // Throw exception if index not found
425 if (index == -1) {
426 std::string msg = "Could not find additional column with name \""+
427 colname+"\".";
429 }
430
431 // Return reference to vector column
432 return (m_coldata[index]);
433}
434
435
436/*==========================================================================
437 = =
438 = Public methods =
439 = =
440 ==========================================================================*/
441
442/***********************************************************************//**
443 * @brief Clear object.
444 *
445 * Reset object to a clean initial state.
446 ***************************************************************************/
447void GPha::clear(void)
448{
449 // Free memory
450 free_members();
451
452 // Initialise members
453 init_members();
454
455 // Return
456 return;
457}
458
459
460/***********************************************************************//**
461 * @brief Clone object
462 *
463 * @return Pulse Height Analyzer spectrum.
464 ***************************************************************************/
465GPha* GPha::clone(void) const
466{
467 // Clone client
468 return new GPha(*this);
469}
470
471
472/***********************************************************************//**
473 * @brief Return content of spectral bin
474 *
475 * @param[in] index Bin index [0,...,size()-1].
476 *
477 * @exception GException::out_of_range
478 * Spectral bin index is out of range.
479 *
480 * Returns reference to content of spectral bin with specified @p index.
481 ***************************************************************************/
482double& GPha::at(const int& index)
483{
484 // Raise exception if index is out of range
485 if (index < 0 || index >= size()) {
486 throw GException::out_of_range(G_AT1, "Spectral bin index", index, size());
487 }
488
489 // Return reference
490 return (m_counts[index]);
491}
492
493
494/***********************************************************************//**
495 * @brief Return content of spectral bin (const version)
496 *
497 * @param[in] index Bin index [0,...,size()-1].
498 *
499 * @exception GException::out_of_range
500 * Spectral bin index is out of range.
501 *
502 * Returns reference to content of spectral bin with specified @p index.
503 ***************************************************************************/
504const double& GPha::at(const int& index) const
505{
506 // Raise exception if index is out of range
507 if (index < 0 || index >= size()) {
508 throw GException::out_of_range(G_AT1, "Spectral bin index", index, size());
509 }
510
511 // Return reference
512 return (m_counts[index]);
513}
514
515
516/***********************************************************************//**
517 * @brief Return content of additional columns
518 *
519 * @param[in] index Bin index [0,...,size()-1].
520 * @param[in] col Columns index [0,...,columns()-1].
521 *
522 * @exception GException::out_of_range
523 * Spectral bin or column index is out of range.
524 *
525 * Returns reference to content of additional columns.
526 ***************************************************************************/
527double& GPha::at(const int& index, const int& col)
528{
529 // Throw an exception if bin or column index is out of range
530 if (index < 0 || index >= size()) {
531 throw GException::out_of_range(G_AT2, "Bin index", index, size());
532 }
533 if (col < 0 || col >= columns()) {
534 throw GException::out_of_range(G_AT2, "Column index", col, columns());
535 }
536
537 // Return reference
538 return (m_coldata[col][index]);
539}
540
541
542/***********************************************************************//**
543 * @brief Return content of additional columns (const version)
544 *
545 * @param[in] index Bin index [0,...,size()-1].
546 * @param[in] col Columns index [0,...,columns()-1].
547 *
548 * @exception GException::out_of_range
549 * Spectral bin or column index is out of range.
550 *
551 * Returns reference to content of additional columns.
552 ***************************************************************************/
553const double& GPha::at(const int& index, const int& col) const
554{
555 // Throw an exception if bin or column index is out of range
556 if (index < 0 || index >= size()) {
557 throw GException::out_of_range(G_AT2, "Bin index", index, size());
558 }
559 if (col < 0 || col >= columns()) {
560 throw GException::out_of_range(G_AT2, "Column index", col, columns());
561 }
562
563 // Return reference
564 return (m_coldata[col][index]);
565}
566
567
568/***********************************************************************//**
569 * @brief Append additional column to spectrum
570 *
571 * @param[in] name Additional column name.
572 * @param[in] column Additional column data.
573 ***************************************************************************/
574void GPha::append(const std::string& name, const std::vector<double>& column)
575{
576 // Throw an exception if the number of elements in the column does not
577 // correspond to the size of the spectrum
578 if (column.size() != size()) {
579 std::string msg = "Size of column "+gammalib::str(column.size())+
580 " is incompatible with size of spectrum "+
581 gammalib::str(size())+".";
583 }
584
585 // Append column name
586 m_colnames.push_back(name);
587
588 // Append column data
589 m_coldata.push_back(column);
590
591 // Return
592 return;
593}
594
595
596/***********************************************************************//**
597 * @brief Set area scaling factor
598 *
599 * @param[in] index Bin index [0,...,size()-1].
600 * @param[in] areascal Area scaling factor.
601 *
602 * @exception GException::out_of_range
603 * Spectral bin index is out of range.
604 *
605 * Set area scaling for spectral bin with specified @p index.
606 ***************************************************************************/
607void GPha::areascal(const int& index, const double& areascal)
608{
609 // Raise exception if index is out of range
610 if (index < 0 || index >= size()) {
611 throw GException::out_of_range(G_AREASCAL_SET, "Spectral bin index",
612 index, size());
613 }
614
615 // Set area scaling factor
616 m_areascal[index] = areascal;
617
618 // Return
619 return;
620}
621
622
623/***********************************************************************//**
624 * @brief Return area scaling factor
625 *
626 * @param[in] index Bin index [0,...,size()-1].
627 *
628 * @exception GException::out_of_range
629 * Spectral bin index is out of range.
630 *
631 * Returns reference to area scaling for spectral bin with specified
632 * @p index.
633 ***************************************************************************/
634const double& GPha::areascal(const int& index) const
635{
636 // Raise exception if index is out of range
637 if (index < 0 || index >= size()) {
638 throw GException::out_of_range(G_AREASCAL_GET, "Spectral bin index",
639 index, size());
640 }
641
642 // Return reference
643 return (m_areascal[index]);
644}
645
646
647/***********************************************************************//**
648 * @brief Set background scaling factor
649 *
650 * @param[in] index Bin index [0,...,size()-1].
651 * @param[in] backscal Background scaling factor.
652 *
653 * @exception GException::out_of_range
654 * Spectral bin index is out of range.
655 *
656 * Set background scaling for spectral bin with specified @p index.
657 ***************************************************************************/
658void GPha::backscal(const int& index, const double& backscal)
659{
660 // Raise exception if index is out of range
661 if (index < 0 || index >= size()) {
662 throw GException::out_of_range(G_BACKSCAL_SET, "Spectral bin index",
663 index, size());
664 }
665
666 // Set background scaling factor
667 m_backscal[index] = backscal;
668
669 // Return
670 return;
671}
672
673
674/***********************************************************************//**
675 * @brief Return background scaling factor
676 *
677 * @param[in] index Bin index [0,...,size()-1].
678 *
679 * @exception GException::out_of_range
680 * Spectral bin index is out of range.
681 *
682 * Returns reference to background scaling for spectral bin with specified
683 * @p index.
684 ***************************************************************************/
685const double& GPha::backscal(const int& index) const
686{
687 // Raise exception if index is out of range
688 if (index < 0 || index >= size()) {
689 throw GException::out_of_range(G_BACKSCAL_GET, "Spectral bin index",
690 index, size());
691 }
692
693 // Return reference
694 return (m_backscal[index]);
695}
696
697
698/***********************************************************************//**
699 * @brief Number of counts in spectrum
700 *
701 * Returns the number of counts in the spectrum.
702 ***************************************************************************/
703double GPha::counts(void) const
704{
705 // Initialise counts
706 double counts = 0.0;
707
708 // Compute content
709 for (int i = 0; i < m_counts.size(); ++i) {
710 counts += m_counts[i];
711 }
712
713 // Return counts
714 return counts;
715}
716
717/***********************************************************************//**
718 * @brief Get number of counts in spectrum as GNdarray
719 *
720 * @return GNdarray of number of counts in spectrum.
721 *
722 * Returns the number of counts in the spectrum as GNdarray.
723 ***************************************************************************/
725{
726 // Initialise array
727 int size = m_counts.size();
729
730 // Compute content
731 for (int i = 0; i < size; ++i) {
732 counts(i) = m_counts[i];
733 }
734
735 // Return counts
736 return counts;
737}
738
739
740/***********************************************************************//**
741 * @brief Get background scaling factors as GNdarray
742 *
743 * @return GNdarray of background scaling factors.
744 *
745 * Returns the background scaling factors as GNdarray.
746 ***************************************************************************/
748{
749 // Initialise array
750 int size = m_backscal.size();
751 GNdarray alpha = GNdarray(size);
752
753 // Compute content
754 for (int i = 0; i < size; ++i) {
755 alpha(i) = m_backscal[i];
756 }
757
758 // Return background scaling factors
759 return alpha;
760}
761
762
763/***********************************************************************//**
764 * @brief Fill spectrum with a value.
765 *
766 * @param[in] energy Energy.
767 * @param[in] value Fill value (defaults to 1.0).
768 *
769 * Fills the specified @p value at a given @p energy in the spectrum.
770 ***************************************************************************/
771void GPha::fill(const GEnergy& energy, const double& value)
772{
773 // Get index
774 int index = m_ebounds.index(energy);
775
776 // If index is not valid, then check for underflow, overflow or outflow
777 if (index == -1) {
778 if (energy < m_ebounds.emin()) {
779 m_underflow += value;
780 }
781 else if (energy >= m_ebounds.emax()) {
782 m_overflow += value;
783 }
784 else {
785 m_outflow += value;
786 }
787 }
788
789 // ... otherwise fill the histogram
790 else {
791 m_counts[index] += value;
792 }
793
794 // Return
795 return;
796}
797
798
799/***********************************************************************//**
800 * @brief Load Pulse Height Analyzer spectrum
801 *
802 * @param[in] filename File name.
803 *
804 * Loads the Pulse Height Analyzer spectrum from a FITS file.
805 ***************************************************************************/
806void GPha::load(const GFilename& filename)
807{
808 // Clear spectrum
809 clear();
810
811 // Open FITS file (without extension name as the user is not allowed
812 // to modify the extension names)
813 GFits fits(filename.url());
814
815 // Read PHA data
816 read(fits);
817
818 // Close FITS file
819 fits.close();
820
821 // Store filename
823
824 // Return
825 return;
826}
827
828
829/***********************************************************************//**
830 * @brief Save Pulse Height Analyzer spectrum
831 *
832 * @param[in] filename File name.
833 * @param[in] clobber Overwrite existing file?
834 *
835 * Saves the Pulse Height Analyzer spectrum and energy boundaries into a
836 * FITS file. If a file with the given @p filename does not yet exist it
837 * will be created. If the file exists it can be overwritten if the
838 * @p clobber flag is set to `true`. Otherwise an exception is thrown.
839 *
840 * The method will save two binary FITS tables into the FITS file: a
841 * `SPECTRUM` extension that contains the channel values of the Pulse
842 * Height Analyzer spectrum and an `EBOUNDS` extension that contains the
843 * energy boundaries for all channels.
844 ***************************************************************************/
845void GPha::save(const GFilename& filename, const bool& clobber) const
846{
847 // Create FITS file
848 GFits fits;
849
850 // Write PHA into file
851 write(fits);
852
853 // Save to file (without extension name since the requested extension
854 // may not yet exist in the file)
855 fits.saveto(filename.url(), clobber);
856
857 // Store filename
859
860 // Return
861 return;
862}
863
864
865/***********************************************************************//**
866 * @brief Read Pulse Height Analyzer spectrum
867 *
868 * @param[in] fits File file.
869 *
870 * Reads the Pulse Height Analyzer spectrum from the `SPECTRUM` extension
871 * of the FITS file. If the file contains also an `EBOUNDS` extension the
872 * energy boundaries of all Pulse Height Analyzer channels are also loaded.
873 ***************************************************************************/
874void GPha::read(const GFits& fits)
875{
876 // Clear spectrum
877 clear();
878
879 // Get PHA table
880 const GFitsTable& pha = *fits.table(gammalib::extname_pha);
881
882 // Read PHA data
883 read(pha);
884
885 // Optionally read energy boundaries
887
888 // Get energy boundary table
890
891 // Read energy boundaries
893
894 } // endif: had energy boundary table
895
896 // Return
897 return;
898}
899
900
901/***********************************************************************//**
902 * @brief Read Pulse Height Analyzer spectrum
903 *
904 * @param[in] table FITS table.
905 *
906 * @exception GException::invalid_value
907 * Mismatch between PHA file and energy boundaries.
908 *
909 * Reads the Pulse Height Analyzer spectrum from a FITS table. The channel
910 * values are expected in the `COUNTS` column of the table. All other
911 * columns are ignored.
912 *
913 * See
914 * https://heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/spectra/ogip_92_007/node5.html
915 * for details about the Pulse Height Analyzer spectrum format.
916 ***************************************************************************/
917void GPha::read(const GFitsTable& table)
918{
919 // Clear spectrum
920 clear();
921
922 // Get data column
923 const GFitsTableCol* col_data = table["COUNTS"];
924 const GFitsTableCol* col_area = table["AREASCAL"];
925 const GFitsTableCol* col_back = table["BACKSCAL"];
926
927 // Extract number of channels in FITS file
928 int length = col_data->nrows();
929
930 // Check whether column length is consistent with energy boundaries
931 if (m_ebounds.size() > 0) {
932 if (m_ebounds.size() != length) {
933 std::string msg = "Mismatch between the "+gammalib::str(length)+
934 " channels in the PHA file and the "+
935 gammalib::str(m_ebounds.size())+" energy "
936 "boundaries. Please correct either the energy "
937 "boundaris or the PHA file.";
939 }
940 }
941
942 // Initialize spectrum
943 alloc(length);
944
945 // Copy data
946 for (int i = 0; i < length; ++i) {
947 m_counts[i] = col_data->real(i);
948 m_areascal[i] = col_area->real(i);
949 m_backscal[i] = col_back->real(i);
950 }
951
952 // Read any additional columns
953 for (int icol = 0; icol < table.ncols(); ++icol) {
954
955 // Fall through if the column is a standard column
956 std::string colname(table[icol]->name());
957 if ((colname == "CHANNEL") ||
958 (colname == "COUNTS") ||
959 (colname == "STAT_ERR") ||
960 (colname == "SYS_ERR") ||
961 (colname == "QUALITY") ||
962 (colname == "GROUPING") ||
963 (colname == "AREASCAL") ||
964 (colname == "BACKSCAL")) {
965 continue;
966 }
967
968 // Get pointer to column
969 const GFitsTableCol* column = table[icol];
970
971 // Set column vector
972 std::vector<double> coldata;
973 for (int i = 0; i < length; ++i) {
974 coldata.push_back(column->real(i));
975 }
976
977 // Append column
978 append(colname, coldata);
979
980 } // endfor: looped over all additional columns
981
982 // Read file names
983 std::string backfile = (table.has_card("BACKFILE")) ? table.string("BACKFILE") : "";
984 std::string corrfile = (table.has_card("CORRFILE")) ? table.string("CORRFILE") : "";
985 std::string respfile = (table.has_card("RESPFILE")) ? table.string("RESPFILE") : "";
986 std::string ancrfile = (table.has_card("ANCRFILE")) ? table.string("ANCRFILE") : "";
987
988 // Set file names
989 m_backfile = (gammalib::tolower(backfile) != "none") ? backfile : "";
990 m_corrfile = (gammalib::tolower(corrfile) != "none") ? corrfile : "";
991 m_respfile = (gammalib::tolower(respfile) != "none") ? respfile : "";
992 m_ancrfile = (gammalib::tolower(ancrfile) != "none") ? ancrfile : "";
993
994 // Read energy band for observations
995 if (table.has_card("EMIN_OBS")) {
996 m_emin_obs.MeV(table.real("EMIN_OBS"));
997 }
998 if (table.has_card("EMAX_OBS")) {
999 m_emax_obs.MeV(table.real("EMAX_OBS"));
1000 }
1001
1002 // Read keywords
1003 m_underflow = (table.has_card("UNDEFLOW")) ? table.real("UNDEFLOW") : 0.0;
1004 m_overflow = (table.has_card("OVERFLOW")) ? table.real("OVERFLOW") : 0.0;
1005 m_outflow = (table.has_card("OUTFLOW")) ? table.real("OUTFLOW") : 0.0;
1006 m_exposure = (table.has_card("EXPOSURE")) ? table.real("EXPOSURE") : 0.0;
1007
1008 // Store FITS header
1009 m_header = table.header();
1010
1011 // Return
1012 return;
1013}
1014
1015
1016/***********************************************************************//**
1017 * @brief Write Pulse Height Analyzer spectrum
1018 *
1019 * @param[in] fits FITS file.
1020 *
1021 * Writes the Pulse Height Analyzer spectrum into `SPECTRUM` and `EBOUNDS`
1022 * extensions of the FITS file. Extensions with these names will be removed
1023 * from the FITS file before writing.
1024 *
1025 * The columns `CHANNEL`, `COUNTS`, `STAT_ERR`, `SYS_ERR`, `QUALITY`,
1026 * `GROUPING`, `AREASCAL`, and `BACKSCAL` will be written into the `SPECTRUM`
1027 * extension, but only the `CHANNEL` and `COUNTS` columns will be filled with
1028 * values. Note that the channels start from 1 in the Pulse Height Analyzer
1029 * spectrum.
1030 *
1031 * See
1032 * https://heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/spectra/ogip_92_007/node5.html
1033 * for details about the PHA file format.
1034 ***************************************************************************/
1035void GPha::write(GFits& fits) const
1036{
1037 // Remove extensions if they exist already
1040 }
1041 if (fits.contains(gammalib::extname_pha)) {
1043 }
1044
1045 // Set column length
1046 int length = size();
1047
1048 // Continue only if there are bins
1049 if (length > 0) {
1050
1051 // Create new binary table
1052 GFitsBinTable hdu;
1053
1054 // Allocate floating point vector columns
1055 GFitsTableShortCol col_chan("CHANNEL", length);
1056 GFitsTableFloatCol col_data("COUNTS", length);
1057 GFitsTableFloatCol col_stat("STAT_ERR", length);
1058 GFitsTableFloatCol col_syst("SYS_ERR", length);
1059 GFitsTableShortCol col_qual("QUALITY", length);
1060 GFitsTableShortCol col_grpg("GROUPING", length);
1061 GFitsTableFloatCol col_area("AREASCAL", length);
1062 GFitsTableFloatCol col_back("BACKSCAL", length);
1063
1064 // Fill columns
1065 for (int i = 0; i < length; ++i) {
1066 col_chan(i) = i+1; // Channels start at 1
1067 col_data(i) = float(m_counts[i]);
1068 col_stat(i) = float(std::sqrt(std::abs(m_counts[i])));
1069 col_grpg(i) = 1;
1070 col_area(i) = float(m_areascal[i]);
1071 col_back(i) = float(m_backscal[i]);
1072 }
1073
1074 // Set table attributes
1076
1077 // Append columns to table
1078 hdu.append(col_chan);
1079 hdu.append(col_data);
1080 hdu.append(col_stat);
1081 hdu.append(col_syst);
1082 hdu.append(col_qual);
1083 hdu.append(col_grpg);
1084 hdu.append(col_area);
1085 hdu.append(col_back);
1086
1087 // Append any additional columns
1088 for (int icol = 0; icol < columns(); ++icol) {
1089
1090 // Allocate floating point vector columns
1091 GFitsTableFloatCol column(m_colnames[icol], length);
1092
1093 // Fill columns
1094 for (int i = 0; i < length; ++i) {
1095 column(i) = (float)m_coldata[icol][i];
1096 }
1097
1098 // Append columns to table
1099 hdu.append(column);
1100
1101 } // endfor: looped over all additional columns
1102
1103 // Set file names
1104 std::string backfile = (m_backfile.empty()) ? "none" : m_backfile;
1105 std::string corrfile = (m_corrfile.empty()) ? "none" : m_corrfile;
1106 std::string respfile = (m_respfile.empty()) ? "none" : m_respfile;
1107 std::string ancrfile = (m_ancrfile.empty()) ? "none" : m_ancrfile;
1108
1109 // Write header keywords
1110 hdu.card("TELESCOP", "unknown", "Telescope");
1111 hdu.card("INSTRUME", "unknown", "Instrument");
1112 hdu.card("FILTER", "none", "Filter");
1113 hdu.card("EXPOSURE", m_exposure, "[s] Deadtime corrected exposure time");
1114 hdu.card("BACKFILE", backfile, "Associated background filename");
1115 hdu.card("CORRFILE", corrfile, "Associated correction filename");
1116 hdu.card("CORRSCAL", 1.0, "Correction scaling factor");
1117 hdu.card("RESPFILE", respfile, "Associated RMF filename");
1118 hdu.card("ANCRFILE", ancrfile, "Associated ARF filename");
1119 hdu.card("HDUCLASS", "OGIP", "Format conforms to OGIP standard");
1120 hdu.card("HDUCLAS1", "SPECTRUM", "PHA dataset");
1121 hdu.card("HDUVERS", "1.2.1", "Version of the file format");
1122 hdu.card("POISSERR", true, "Poisson errors to be assumed");
1123 hdu.card("CHANTYPE", "PI", "Channel type");
1124 hdu.card("DETCHANS", size(), "Total number of possible channels");
1125 hdu.card("EMIN_OBS", m_emin_obs.MeV(), "[MeV] Minimum energy of observation");
1126 hdu.card("EMAX_OBS", m_emax_obs.MeV(), "[MeV] Maximum energy of observation");
1127 hdu.card("UNDEFLOW", m_underflow, "Number of underflowing events");
1128 hdu.card("OVERFLOW", m_overflow, "Number of overflowing events");
1129 hdu.card("OUTFLOW", m_outflow, "Number of outflowing events");
1130
1131 // Write additional header keywords (do not overwrite any existing
1132 // keywords, except of "TELESCOP", "INSTRUME" and "FILTER")
1133 for (int i = 0; i < m_header.size(); ++i) {
1134 if ((!hdu.has_card(m_header[i].keyname())) ||
1135 (m_header[i].keyname() == "TELESCOP") ||
1136 (m_header[i].keyname() == "INSTRUME") ||
1137 (m_header[i].keyname() == "FILTER")) {
1138 hdu.card(m_header[i]);
1139 }
1140 }
1141
1142 // Append HDU to FITS file
1143 fits.append(hdu);
1144
1145 // Optionally append energy boundaries
1146 if (m_ebounds.size() > 0) {
1147 m_ebounds.write(fits);
1148 }
1149
1150 } // endif: there were data to write
1151
1152 // Return
1153 return;
1154}
1155
1156
1157/***********************************************************************//**
1158 * @brief Print Pulse Height Analyzer spectrum
1159 *
1160 * @param[in] chatter Chattiness.
1161 * @return String containing Pulse Height Analyzer spectrum information.
1162 ***************************************************************************/
1163std::string GPha::print(const GChatter& chatter) const
1164{
1165 // Initialise result string
1166 std::string result;
1167
1168 // Continue only if chatter is not silent
1169 if (chatter != SILENT) {
1170
1171 // Append header
1172 result.append("=== GPha ===");
1173
1174 // Append energy boundary information
1175 result.append("\n"+gammalib::parformat("Exposure"));
1176 result.append(gammalib::str(exposure())+" s");
1177 result.append("\n"+gammalib::parformat("Number of bins"));
1178 result.append(gammalib::str(size()));
1179 result.append("\n"+gammalib::parformat("Energy range"));
1180 if (m_ebounds.size() > 0) {
1181 result.append(m_ebounds.emin().print());
1182 result.append(" - ");
1183 result.append(m_ebounds.emax().print());
1184 }
1185 else {
1186 result.append("not specified");
1187 }
1188
1189 // Append observation energy range
1190 result.append("\n"+gammalib::parformat("Observation energy range"));
1191 if (m_emax_obs > m_emin_obs) {
1192 result.append(m_emin_obs.print());
1193 result.append(" - ");
1194 result.append(m_emax_obs.print());
1195 }
1196 else {
1197 result.append("not specified");
1198 }
1199
1200 // Append content information
1201 result.append("\n"+gammalib::parformat("Total number of counts"));
1202 result.append(gammalib::str(counts()));
1203 result.append("\n"+gammalib::parformat("Underflow counts"));
1204 result.append(gammalib::str(m_underflow));
1205 result.append("\n"+gammalib::parformat("Overflow counts"));
1206 result.append(gammalib::str(m_overflow));
1207 result.append("\n"+gammalib::parformat("Outflow counts"));
1208 result.append(gammalib::str(m_outflow));
1209
1210 } // endif: chatter was not silent
1211
1212 // Return result
1213 return result;
1214}
1215
1216
1217/*==========================================================================
1218 = =
1219 = Private methods =
1220 = =
1221 ==========================================================================*/
1222
1223/***********************************************************************//**
1224 * @brief Initialise class members
1225 ***************************************************************************/
1227{
1228 // Initialise members
1229 m_filename.clear();
1230 m_ebounds.clear();
1231 m_counts.clear();
1232 m_areascal.clear();
1233 m_backscal.clear();
1234 m_colnames.clear();
1235 m_coldata.clear();
1236 m_emin_obs.clear();
1237 m_emax_obs.clear();
1238 m_underflow = 0.0;
1239 m_overflow = 0.0;
1240 m_outflow = 0.0;
1241 m_exposure = 0.0;
1242 m_backfile.clear();
1243 m_corrfile.clear();
1244 m_respfile.clear();
1245 m_ancrfile.clear();
1246 m_header.clear();
1247
1248 // Return
1249 return;
1250}
1251
1252
1253/***********************************************************************//**
1254 * @brief Copy class members
1255 *
1256 * @param[in] pha Pulse Height Analyzer spectrum.
1257 ***************************************************************************/
1258void GPha::copy_members(const GPha& pha)
1259{
1260 // Copy members
1261 m_filename = pha.m_filename;
1262 m_counts = pha.m_counts;
1263 m_areascal = pha.m_areascal;
1264 m_backscal = pha.m_backscal;
1265 m_colnames = pha.m_colnames;
1266 m_coldata = pha.m_coldata;
1267 m_emin_obs = pha.m_emin_obs;
1268 m_emax_obs = pha.m_emax_obs;
1270 m_overflow = pha.m_overflow;
1271 m_outflow = pha.m_outflow;
1272 m_ebounds = pha.m_ebounds;
1273 m_exposure = pha.m_exposure;
1274 m_backfile = pha.m_backfile;
1275 m_corrfile = pha.m_corrfile;
1276 m_respfile = pha.m_respfile;
1277 m_ancrfile = pha.m_ancrfile;
1278 m_header = pha.m_header;
1279
1280 // Return
1281 return;
1282}
1283
1284
1285/***********************************************************************//**
1286 * @brief Delete class members
1287 ***************************************************************************/
1289{
1290 // Return
1291 return;
1292}
1293
1294
1295/***********************************************************************//**
1296 * @brief Allocate spectrum
1297 *
1298 * @param[in] size Size of spectrum.
1299 *
1300 * Allocates memory for a spectrum of given @p size and sets number of counts
1301 * to zero and area and background scaling factors to one.
1302 ***************************************************************************/
1303void GPha::alloc(const int& size)
1304{
1305 // Initialise attributes
1306 m_underflow = 0.0;
1307 m_overflow = 0.0;
1308 m_outflow = 0.0;
1309 m_exposure = 0.0;
1310
1311 // Initialize vectors
1312 m_counts.assign(size, 0.0);
1313 m_areascal.assign(size, 1.0);
1314 m_backscal.assign(size, 1.0);
1315
1316 // Return
1317 return;
1318}
1319
1320
1321/***********************************************************************//**
1322 * @brief Returns index of additional vector column
1323 *
1324 * @param[in] colname Vector column name.
1325 * @return Vector column index.
1326 *
1327 * Returns index of additional vector column. Returns -1 if the vector column
1328 * has not found.
1329 ***************************************************************************/
1330int GPha::column_index(const std::string& colname) const
1331{
1332 // Initialise index
1333 int index(-1);
1334
1335 // Search vector column name
1336 for (int i = 0; i < columns(); ++i) {
1337 if (m_colnames[i] == colname) {
1338 index = i;
1339 break;
1340 }
1341 }
1342
1343 // Return index
1344 return index;
1345}
#define G_READ
#define G_APPEND
#define G_OPERATOR
Definition GArf.cpp:44
#define G_OPERATOR_PLUS
Definition GArf.cpp:42
#define G_OPERATOR_MINUS
Definition GArf.cpp:43
Energy value class definition.
Exception handler interface definition.
FITS binary table class definition.
FITS table float column class interface definition.
FITS table short integer column class interface definition.
FITS table abstract base class interface definition.
#define G_AT2
Definition GFits.cpp:52
#define G_AT1
Definition GFits.cpp:51
FITS file class interface definition.
N-dimensional array class interface definition.
#define G_BACKSCAL_GET
Definition GPha.cpp:52
#define G_BACKSCAL_SET
Definition GPha.cpp:51
#define G_AREASCAL_GET
Definition GPha.cpp:50
#define G_AREASCAL_SET
Definition GPha.cpp:49
XSPEC Pulse Height Analyzer class definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
Energy boundaries container class.
Definition GEbounds.hpp:60
int index(const GEnergy &eng) const
Returns energy bin index for a given energy.
Definition GEbounds.cpp:948
const GEnergy & emax(void) const
Return maximum energy of all intervals.
Definition GEbounds.hpp:199
void read(const GFitsTable &table)
Read energy boundaries from FITS table.
Definition GEbounds.cpp:761
int size(void) const
Return number of energy boundaries.
Definition GEbounds.hpp:163
void clear(void)
Clear energy boundaries.
Definition GEbounds.cpp:268
const GEnergy & emin(void) const
Return minimum energy of all intervals.
Definition GEbounds.hpp:187
void write(GFits &file, const std::string &extname=gammalib::extname_ebounds, const std::string &unit="keV") const
Write energy boundaries into FITS object.
Definition GEbounds.cpp:816
Class that handles energies in a unit independent way.
Definition GEnergy.hpp:48
double MeV(void) const
Return energy in MeV.
Definition GEnergy.cpp:321
std::string print(const GChatter &chatter=NORMAL) const
Print energy.
Definition GEnergy.cpp:748
void clear(void)
Clear instance.
Definition GEnergy.cpp:261
Filename class.
Definition GFilename.hpp:62
std::string url(void) const
Return Uniform Resource Locator (URL)
void clear(void)
Clear file name.
FITS binary table class.
const GFitsHeader & header(void) const
Return extension header.
Definition GFitsHDU.hpp:205
bool has_card(const int &cardno) const
Check existence of header card.
Definition GFitsHDU.hpp:233
const std::string & extname(void) const
Return extension name.
Definition GFitsHDU.hpp:162
double real(const std::string &keyname) const
Return card value as double precision.
Definition GFitsHDU.hpp:423
std::string string(const std::string &keyname) const
Return card value as string.
Definition GFitsHDU.hpp:410
GFitsHeaderCard & card(const int &cardno)
Return header card.
Definition GFitsHDU.hpp:259
void clear(void)
Clear header.
int size(void) const
Return number of cards in header.
Abstract interface for FITS table column.
virtual double real(const int &row, const int &inx=0) const =0
void nrows(const int &nrows)
Set number of rows in column.
FITS table float column.
FITS table short integer column.
Abstract interface for FITS table.
GFitsTableCol * append(const GFitsTableCol &column)
Append column to the table.
const int & ncols(void) const
Return number of columns in table.
FITS file class.
Definition GFits.hpp:63
void saveto(const GFilename &filename, const bool &clobber=false)
Saves to specified FITS file.
Definition GFits.cpp:1293
bool contains(const int &extno) const
Check if HDU exists in FITS file.
Definition GFits.hpp:282
GFitsHDU * append(const GFitsHDU &hdu)
Append HDU to FITS file.
Definition GFits.cpp:678
void close(void)
Close FITS file.
Definition GFits.cpp:1342
void remove(const int &extno)
Remove HDU from FITS file.
Definition GFits.cpp:862
GFitsTable * table(const int &extno)
Get pointer to table HDU.
Definition GFits.cpp:482
N-dimensional array class.
Definition GNdarray.hpp:44
Pulse Height Analyzer class.
Definition GPha.hpp:64
virtual ~GPha(void)
Destructor.
Definition GPha.cpp:159
void copy_members(const GPha &pha)
Copy class members.
Definition GPha.cpp:1258
const std::string & ancrfile(void) const
Return Ancilliary Response File name.
Definition GPha.hpp:529
std::string print(const GChatter &chatter=NORMAL) const
Print Pulse Height Analyzer spectrum.
Definition GPha.cpp:1163
GPha(void)
Void constructor.
Definition GPha.cpp:71
void save(const GFilename &filename, const bool &clobber=false) const
Save Pulse Height Analyzer spectrum.
Definition GPha.cpp:845
void fill(const GEnergy &energy, const double &value=1.0)
Fill spectrum with a value.
Definition GPha.cpp:771
void alloc(const int &size)
Allocate spectrum.
Definition GPha.cpp:1303
double & operator[](const int &index)
Return content of spectral bin.
Definition GPha.hpp:196
std::vector< double > m_backscal
Background scaling.
Definition GPha.hpp:158
void init_members(void)
Initialise class members.
Definition GPha.cpp:1226
GEnergy m_emax_obs
Minimum energy of observation.
Definition GPha.hpp:162
GNdarray counts_spectrum(void) const
Get number of counts in spectrum as GNdarray.
Definition GPha.cpp:724
std::string m_ancrfile
ARF file.
Definition GPha.hpp:171
double m_outflow
Number of outflowing events.
Definition GPha.hpp:165
GFitsHeader m_header
FITS header cards.
Definition GPha.hpp:172
GPha & operator*=(const double &scale)
Scale spectrum values.
Definition GPha.cpp:343
void free_members(void)
Delete class members.
Definition GPha.cpp:1288
double & at(const int &index)
Return content of spectral bin.
Definition GPha.cpp:482
void read(const GFits &fits)
Read Pulse Height Analyzer spectrum.
Definition GPha.cpp:874
const double & exposure(void) const
Return exposure time.
Definition GPha.hpp:355
void backscal(const int &index, const double &backscal)
Set background scaling factor.
Definition GPha.cpp:658
GFilename m_filename
Filename of origin.
Definition GPha.hpp:155
double m_exposure
Deadtime corr. exp. time (sec)
Definition GPha.hpp:166
void write(GFits &fits) const
Write Pulse Height Analyzer spectrum.
Definition GPha.cpp:1035
const std::string & respfile(void) const
Return Redistribution Matrix File name.
Definition GPha.hpp:500
GEbounds m_ebounds
Energy boundaries.
Definition GPha.hpp:167
GEnergy m_emin_obs
Minimum energy of observation.
Definition GPha.hpp:161
const GFilename & filename(void) const
Return file name.
Definition GPha.hpp:546
std::vector< double > m_counts
Counts data.
Definition GPha.hpp:156
double m_overflow
Number of overflowing events.
Definition GPha.hpp:164
double counts(void) const
Number of counts in spectrum.
Definition GPha.cpp:703
int column_index(const std::string &colname) const
Returns index of additional vector column.
Definition GPha.cpp:1330
double m_underflow
Number of underflowing events.
Definition GPha.hpp:163
GPha & operator-=(const GPha &pha)
Subtract spectrum.
Definition GPha.cpp:297
int size(void) const
Return number of bins in spectrum.
Definition GPha.hpp:254
std::string m_respfile
RMF file.
Definition GPha.hpp:170
GPha & operator/=(const double &scale)
Divide spectrum values.
Definition GPha.cpp:369
const std::string & backfile(void) const
Return background file name.
Definition GPha.hpp:442
GNdarray backscal_spectrum(void) const
Get background scaling factors as GNdarray.
Definition GPha.cpp:747
std::string m_corrfile
Correction file.
Definition GPha.hpp:169
const std::string & corrfile(void) const
Return correction file name.
Definition GPha.hpp:471
GPha * clone(void) const
Clone object.
Definition GPha.cpp:465
void areascal(const int &index, const double &areascal)
Set area scaling factor.
Definition GPha.cpp:607
int columns(void) const
Return number of additional columns.
Definition GPha.hpp:268
std::vector< double > m_areascal
Area scaling.
Definition GPha.hpp:157
std::vector< std::vector< double > > m_coldata
Additional column data.
Definition GPha.hpp:160
void clear(void)
Clear object.
Definition GPha.cpp:447
GPha & operator+=(const GPha &pha)
Add spectrum.
Definition GPha.cpp:231
const GEbounds & ebounds(void) const
Return energy boundaries.
Definition GPha.hpp:282
void load(const GFilename &filename)
Load Pulse Height Analyzer spectrum.
Definition GPha.cpp:806
GPha & operator=(const GPha &pha)
Assignment operator.
Definition GPha.cpp:181
std::vector< std::string > m_colnames
Additional column names.
Definition GPha.hpp:159
void append(const std::string &name, const std::vector< double > &column)
Append additional column to spectrum.
Definition GPha.cpp:574
std::string m_backfile
Background file.
Definition GPha.hpp:168
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1143
const std::string extname_ebounds
Definition GEbounds.hpp:44
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
const std::string extname_pha
Definition GPha.hpp:45
std::string tolower(const std::string &s)
Convert string to lower case.
Definition GTools.cpp:955