GammaLib 2.0.0
Loading...
Searching...
No Matches
GEbounds.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GEbounds.cpp - Energy boundary class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2009-2022 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 GEbounds.cpp
23 * @brief Energy boundary class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <cmath>
32#include "GException.hpp"
33#include "GTools.hpp"
34#include "GFilename.hpp"
35#include "GEbounds.hpp"
36#include "GEnergies.hpp"
37#include "GFits.hpp"
38#include "GFitsTable.hpp"
39#include "GFitsBinTable.hpp"
41#include "GXmlElement.hpp"
42
43/* __ Method name definitions ____________________________________________ */
44#define G_READ_XML "GEbounds::read(GXmlElement&)"
45#define G_WRITE_XML "GEbounds::write(GXmlElement&)"
46#define G_REMOVE_INX "GEbounds::remove(int&)"
47#define G_REMOVE_ENG "GEbounds::remove(GEnergy&, GEnergy&)"
48#define G_EMIN_SET "GEbounds::emin(int&, GEnergy&)"
49#define G_EMAX_SET "GEbounds::emax(int&, GEnergy&)"
50#define G_EMIN_GET "GEbounds::emin(int&)"
51#define G_EMAX_GET "GEbounds::emax(int&)"
52#define G_EMEAN "GEbounds::emean(int&)"
53#define G_ELOGMEAN "GEbounds::elogmean(int&)"
54#define G_EWIDTH "GEbounds::ewidth(int&)"
55#define G_INSERT_ENG "GEbounds::insert_eng(int&, GEnergy&, GEnergy&)"
56
57/* __ Macros _____________________________________________________________ */
58
59/* __ Coding definitions _________________________________________________ */
60
61/* __ Debug definitions __________________________________________________ */
62
63
64/*==========================================================================
65 = =
66 = Constructors/destructors =
67 = =
68 ==========================================================================*/
69
70/***********************************************************************//**
71 * @brief Constructor
72 ***************************************************************************/
74{
75 // Initialise class members for clean destruction
77
78 // Return
79 return;
80}
81
82
83/***********************************************************************//**
84 * @brief FITS file constructor
85 *
86 * @param[in] filename FITS file name.
87 *
88 * Constructs energy boundaries from a FITS file.
89 ***************************************************************************/
91{
92 // Initialise members
94
95 // Load FITS file
96 load(filename);
97
98 // Return
99 return;
100}
101
102
103/***********************************************************************//**
104 * @brief XML element constructor
105 *
106 * @param[in] xml XML element.
107 *
108 * Constructs energy boundaries from an XML element.
109 ***************************************************************************/
111{
112 // Initialise members
113 init_members();
114
115 // Read energy boundaries from XML element
116 read(xml);
117
118 // Return
119 return;
120}
121
122
123/***********************************************************************//**
124 * @brief Energy container constructor
125 *
126 * @param[in] energies Energy container.
127 *
128 * Constructs energy boundaries from an energy container.
129 ***************************************************************************/
131{
132 // Initialise members
133 init_members();
134
135 // Set energy boundaries from energy container
136 set(energies);
137
138 // Return
139 return;
140}
141
142
143/***********************************************************************//**
144 * @brief Copy constructor
145 *
146 * @param[in] ebds Energy boundaries.
147 ***************************************************************************/
149{
150 // Initialise class members for clean destruction
151 init_members();
152
153 // Copy members
154 copy_members(ebds);
155
156 // Return
157 return;
158}
159
160
161/***********************************************************************//**
162 * @brief Single energy band constructor
163 *
164 * @param[in] emin Minimum energy of the interval.
165 * @param[in] emax Maximum energy of the interval.
166 *
167 * Constructs energy boundaries for one (emin, emax) energy band.
168 ***************************************************************************/
169GEbounds::GEbounds(const GEnergy& emin, const GEnergy& emax)
170{
171 // Initialise members
172 init_members();
173
174 // Append energies
175 append(emin, emax);
176
177 // Return
178 return;
179}
180
181
182/***********************************************************************//**
183 * @brief Interval constructor
184 *
185 * @param[in] num Number of energy intervals.
186 * @param[in] emin Minimum energy of first interval.
187 * @param[in] emax Maximum energy of last interval.
188 * @param[in] method Energy spacing method (one of "LIN", "LOG" or "POW").
189 * @param[in] gamma Power law index for @p POW method.
190 *
191 * Constructs energy boundaries by defining @p num successive energy
192 * intervals between @p emin and @p emax. The @p method parameter controls
193 * the energy spacing of the energy boundaries. See the set() method for
194 * more information.
195 ***************************************************************************/
196GEbounds::GEbounds(const int& num,
197 const GEnergy& emin,
198 const GEnergy& emax,
199 const std::string& method,
200 const double& gamma)
201{
202 // Initialise members
203 init_members();
204
205 // Set intervals
206 set(num, emin, emax, method, gamma);
207
208 // Return
209 return;
210}
211
212
213/***********************************************************************//**
214 * @brief Destructor
215 ***************************************************************************/
217{
218 // Free members
219 free_members();
220
221 // Return
222 return;
223}
224
225
226/*==========================================================================
227 = =
228 = Operators =
229 = =
230 ==========================================================================*/
231
232/***********************************************************************//**
233 * @brief Assignment operator
234 *
235 * @param[in] ebds Energy boundaries to be assigned.
236 * @return Energy boundaries.
237 ***************************************************************************/
239{
240 // Execute only if object is not identical
241 if (this != &ebds) {
242
243 // Free members
244 free_members();
245
246 // Initialise private members for clean destruction
247 init_members();
248
249 // Copy members
250 copy_members(ebds);
251
252 } // endif: object was not identical
253
254 // Return this object
255 return *this;
256}
257
258
259/*==========================================================================
260 = =
261 = Public methods =
262 = =
263 ==========================================================================*/
264
265/***********************************************************************//**
266 * @brief Clear energy boundaries
267 ***************************************************************************/
269{
270 // Free members
271 free_members();
272
273 // Initialise private members
274 init_members();
275
276 // Return
277 return;
278}
279
280
281/***********************************************************************//**
282 * @brief Clone energy boundaries
283 *
284 * @return Pointer to deep copy of energy boundaries.
285 ***************************************************************************/
287{
288 return new GEbounds(*this);
289}
290
291
292/***********************************************************************//**
293 * @brief Append energy interval
294 *
295 * @param[in] emin Minimum energy of interval.
296 * @param[in] emax Maximum energy of interval.
297 *
298 * Appends an energy interval to the end of the energy boundaries
299 * container.
300 ***************************************************************************/
301void GEbounds::append(const GEnergy& emin, const GEnergy& emax)
302{
303 // Append interval at the end
305
306 // Return
307 return;
308}
309
310
311/***********************************************************************//**
312 * @brief Insert energy interval
313 *
314 * @param[in] emin Minimum energy of interval.
315 * @param[in] emax Maximum energy of interval.
316 *
317 * Inserts an energy interval into the energy boundaries after the first
318 * boundary that has a minimum energy smaller than @p emin. The method
319 * implicitely assumes that the intervals are ordered by increasing minimum
320 * energy.
321 ***************************************************************************/
322void GEbounds::insert(const GEnergy& emin, const GEnergy& emax)
323{
324 // Determine index at which interval should be inserted
325 int inx = 0;
326 for (; inx < m_num; ++inx) {
327 if (emin < m_min[inx])
328 break;
329 }
330
331 // Insert interval
332 insert_eng(inx, emin, emax);
333
334 // Return
335 return;
336}
337
338
339/***********************************************************************//**
340 * @brief Merge all overlapping or connecting successive energy intervals
341 *
342 * Merges all overlapping or connecting successive energy intervals. The
343 * method implicitely assumes that the intervals are ordered by increasing
344 * minimum energy.
345 *
346 * Note that the method does not actually reduce the memory size but just
347 * updates the information on the number of elements in the array.
348 ***************************************************************************/
350{
351 // Find overlaps
352 int i = 0;
353 int num = m_num;
354 while (i < num-1) {
355
356 // If current energy interval overlaps with successor then merge both
357 // intervals, move all remaining intervals one position up, and
358 // reduce the number of elements
359 if (m_min[i+1] <= m_max[i]) {
360 m_min[i] = (m_min[i] < m_min[i+1]) ? m_min[i] : m_min[i+1];
361 m_max[i] = (m_max[i] > m_max[i+1]) ? m_max[i] : m_max[i+1];
362 for (int k = i+2; k < num; ++k) {
363 m_min[k-1] = m_min[k];
364 m_max[k-1] = m_max[k];
365 }
366 num--;
367 }
368
369 // Otherwise increment interval index
370 else {
371 i++;
372 }
373
374 } // endwhile: there were still intervals to check
375
376 // Update number of elements in object
377 m_num = num;
378
379 // Return
380 return;
381}
382
383
384/***********************************************************************//**
385 * @brief Merge energy interval into energy boundaries
386 *
387 * @param[in] emin Minimum energy of interval.
388 * @param[in] emax Maximum energy of interval.
389 *
390 * Inserts an energy interval into the energy boundaries after the first
391 * boundary that has a minimum energy smaller than @p emin and then merges
392 * any overlapping or connecting energy boundaries. The method implicitely
393 * assumes that the intervals are ordered by increasing minimum energy.
394 ***************************************************************************/
395void GEbounds::merge(const GEnergy& emin, const GEnergy& emax)
396{
397 // Determine index at which interval should be inserted
398 int inx = 0;
399 for (; inx < m_num; ++inx) {
400 if (emin < m_min[inx])
401 break;
402 }
403
404 // Insert interval
405 insert_eng(inx, emin, emax);
406
407 // Merge any overlapping energy intervals
408 merge();
409
410 // Return
411 return;
412}
413
414
415/***********************************************************************//**
416 * @brief Remove energy interval
417 *
418 * @param[in] index Energy interval index [0,...,size()[.
419 *
420 * Removes energy interval at @p index from the energy boundaries container.
421 * All intervals after the specified @p index are moved forward by one
422 * position.
423 *
424 * Note that the method does not actually reduce the memory size but just
425 * updates the information on the number of elements in the array.
426 ***************************************************************************/
427void GEbounds::remove(const int& index)
428{
429 #if defined(G_RANGE_CHECK)
430 // If index is outside boundary then throw an error
432 throw GException::out_of_range(G_REMOVE_INX, "Energy interval index",
433 index, m_num);
434 }
435 #endif
436
437 // Move all elements located after index forward
438 for (int i = index+1; i < m_num; ++i) {
439 m_min[i-1] = m_min[i];
440 m_max[i-1] = m_max[i];
441 }
442
443 // Reduce number of elements by one
444 m_num--;
445
446 // Update attributes
448
449 // Return
450 return;
451}
452
453
454/***********************************************************************//**
455 * @brief Remove energy interval from energy boundaries
456 *
457 * @param[in] emin Minimum energy of interval.
458 * @param[in] emax Maximum energy of interval.
459 *
460 * @exception GException::invalid_argument
461 * Minimum energy larger than maximum energy
462 *
463 * Removes an energy interval from the energy boundaries. If the energy
464 * interval is fully enclosed in an existing energy boundary, the energy
465 * boundary will be split into two, excluding the specified energy interval.
466 * If the energy interval corresponds exactly to an existing energy boundary
467 * the corresponding energy boundary will be removed. Otherwise the existing
468 * energy boundaries will be adjusted to exclude the specified energy
469 * interval.
470 ***************************************************************************/
471void GEbounds::remove(const GEnergy& emin, const GEnergy& emax)
472{
473 // Throw an exception if energy interval is invalid
474 if (emin > emax) {
475 std::string msg = "Invalid energy interval specified. Minimum"
476 " energy "+emin.print(NORMAL)+" can not be"
477 " larger than maximum energy "+
478 emax.print(NORMAL)+".";
480 }
481
482 // Loop over all elements
483 for (int inx = 0; inx < m_num; ++inx) {
484
485 // If energy interval corresponds exactly to the energy
486 // boundary then remove the element
487 if ((m_min[inx] == emin) && (m_max[inx] == emax)) {
488 this->remove(inx);
489 break;
490 }
491
492 // ... otherwise, if energy interval is enclosed in energy boundary
493 // then split the element into two
494 else if ((m_min[inx] < emin) && (m_max[inx] > emax)) {
495 GEnergy emin_old = m_min[inx];
496 GEnergy emax_old = m_max[inx];
497 this->remove(inx);
498 this->insert(emin_old, emin);
499 this->insert(emax, emax_old);
500 break;
501 }
502
503 // ... otherwise
504 else {
505
506 // If emin is comprised in energy interval then set maximum
507 // energy to interval start
508 if ((m_min[inx] <= emin) && (m_max[inx] >= emin)) {
509 m_max[inx] = emin;
510 }
511
512 // If emax is comprised in energy interval then set minimum
513 // energy to interval end
514 if ((m_min[inx] <= emax) && (m_max[inx] >= emax)) {
515 m_min[inx] = emax;
516 }
517
518 }
519
520 } // endfor: looped over boundaries
521
522 // Update attributes
524
525 // Return
526 return;
527}
528
529
530/***********************************************************************//**
531 * @brief Reserve space for energy intervals
532 *
533 * @param[in] num Number of elements.
534 *
535 * This method does nothing (it is needed to satisfy the GContainer
536 * interface).
537 ***************************************************************************/
538void GEbounds::reserve(const int& num)
539{
540 // Return
541 return;
542}
543
544
545/***********************************************************************//**
546 * @brief Append energy boundaries
547 *
548 * @param[in] ebds Energy boundaries.
549 *
550 * Append energy boundaries to the container.
551 ***************************************************************************/
552void GEbounds::extend(const GEbounds& ebds)
553{
554 // Do nothing if energy boundaries are empty
555 if (!ebds.is_empty()) {
556
557 // Allocate new intervals
558 int num = m_num+ebds.size();
559 GEnergy* min = new GEnergy[num];
560 GEnergy* max = new GEnergy[num];
561
562 // Initialise index
563 int inx = 0;
564
565 // Copy existing intervals
566 for (; inx < m_num; ++inx) {
567 min[inx] = m_min[inx];
568 max[inx] = m_max[inx];
569 }
570
571 // Append intervals
572 for (int i = 0; i < ebds.size(); ++i, ++inx) {
573 min[inx] = ebds.m_min[i];
574 max[inx] = ebds.m_max[i];
575 }
576
577 // Free memory
578 if (m_min != NULL) delete [] m_min;
579 if (m_max != NULL) delete [] m_max;
580
581 // Set new memory
582 m_min = min;
583 m_max = max;
584
585 // Set number of elements
586 m_num = num;
587
588 // Set attributes
590
591 } // endif: energy boundaries were not empty
592
593 // Return
594 return;
595}
596
597
598/***********************************************************************//**
599 * @brief Set energy boundaries from energy container
600 *
601 * @param[in] energies Energy container.
602 *
603 * Sets the energy boundaries from an energy container. Each two subsequent
604 * energies in the energy container will form an energy boundary. This
605 * means that n energies will lead to n-1 energy boundaries with the
606 * following mapping:
607 *
608 * [energies[0], energies[1]]
609 * [energies[1], energies[2]]
610 * ...
611 * [energies[n-2], energies[n-1]]
612 *
613 * If there is only one energy in the container the following empty energy
614 * boundary will be appended:
615 *
616 * [energies[0], energies[0]]
617 ***************************************************************************/
618void GEbounds::set(const GEnergies& energies)
619{
620 // Initialise members
621 clear();
622
623 // Get number of energies in container
624 int num = energies.size();
625
626 // If there is only one energy in the container then append an empty
627 // energy boundary
628 if (num == 1) {
629 append(energies[0], energies[0]);
630 }
631
632 // ... otherwise if there is more than one energy in the container
633 // then append subsequent energies as boundaries
634 else if (num > 1) {
635 for (int i = 0; i < num-1; ++i) {
636 append(energies[i], energies[i+1]);
637 }
638 }
639
640 // Set attributes
642
643 // Return
644 return;
645}
646
647
648/***********************************************************************//**
649 * @brief Set energy intervals
650 *
651 * @param[in] num Number of energy intervals.
652 * @param[in] emin Minimum energy of first interval.
653 * @param[in] emax Maximum energy of last interval.
654 * @param[in] method Energy spacing method (one of "LIN", "LOG" or "POW").
655 * @param[in] gamma Power law index for @p POW method.
656 *
657 * Sets energy boundaries by defining @p num successive energy intervals
658 * between @p emin and @p emax. The @p method parameter controls the energy
659 * spacing of the energy boundaries. See the GEnergies::set() method for
660 * more information.
661 ***************************************************************************/
662void GEbounds::set(const int& num,
663 const GEnergy& emin,
664 const GEnergy& emax,
665 const std::string& method,
666 const double& gamma)
667{
668 // Set energies
669 GEnergies energies(num+1, emin, emax, method, gamma);
670
671 // Set energy boundaries from energies
672 set(energies);
673
674 // Return
675 return;
676}
677
678
679/***********************************************************************//**
680 * @brief Load energy boundaries from FITS file
681 *
682 * @param[in] filename FITS file name.
683 *
684 * Loads the energy boundaries from a FITS file.
685 *
686 * If no extension name is provided, the energy boundaries are loaded from
687 * the `EBOUNDS` extension.
688 ***************************************************************************/
689void GEbounds::load(const GFilename& filename)
690{
691 // Open FITS file
692 GFits fits(filename);
693
694 // Get energy boundary table
695 const GFitsTable& table = *fits.table(filename.extname(gammalib::extname_ebounds));
696
697 // Read energy boundaries from table
698 read(table);
699
700 // Close FITS file
701 fits.close();
702
703 // Return
704 return;
705}
706
707
708/***********************************************************************//**
709 * @brief Save energy boundaries into FITS file
710 *
711 * @param[in] filename FITS file name.
712 * @param[in] clobber Overwrite an existing energy boundaries extension?
713 * @param[in] unit Energy unit
714 *
715 * Saves energy boundaries into a FITS file. If a file with the given
716 * @p filename does not yet exist it will be created, otherwise the method
717 * opens the existing file. Energy boundaries can only be appended to an
718 * existing file if the @p clobber flag is set to "true" (otherwise an
719 * exception is thrown).
720 *
721 * The method will append a binary FITS table containing the energy
722 * boundaries to the FITS file. The extension name can be specified as part
723 * of the @p filename. For example the @p filename
724 *
725 * myfile.fits[ENERGY BOUNDARIES]
726 *
727 * will save the energy boundaries in the `ENERGY BOUNDARIES` extension of
728 * the "myfile.fits" file. If the extension exists already in the file it
729 * will be replaced, otherwise a new extension will be created. If no
730 * extension name is provided, the method will use `EBOUNDS` as the default
731 * extension name for energy boundaries.
732 ***************************************************************************/
733void GEbounds::save(const GFilename& filename,
734 const bool& clobber,
735 const std::string& unit) const
736{
737 // Open or create FITS file (without extension name since the requested
738 // extension may not yet exist in the file)
739 GFits fits(filename.url(), true);
740
741 // Write energy boundaries to FITS file
742 write(fits, filename.extname(gammalib::extname_ebounds), unit);
743
744 // Save to file
745 fits.save(clobber);
746
747 // Return
748 return;
749}
750
751
752/***********************************************************************//**
753 * @brief Read energy boundaries from FITS table
754 *
755 * @param[in] table FITS table.
756 *
757 * Reads the energy boundaries from a FITS table. The method interprets the
758 * energy units provide in the FITS header. If no energy units are found it
759 * is assumed that the energies are stored in units of keV.
760 ***************************************************************************/
761void GEbounds::read(const GFitsTable& table)
762{
763 // Free members
764 free_members();
765
766 // Initialise attributes
767 init_members();
768
769 // Extract energy boundary information from FITS table
770 m_num = table.integer("NAXIS2");
771 if (m_num > 0) {
772
773 // Allocate memory
774 m_min = new GEnergy[m_num];
775 m_max = new GEnergy[m_num];
776
777 // Get units
778 std::string emin_unit = table["E_MIN"]->unit();
779 std::string emax_unit = table["E_MAX"]->unit();
780 if (emin_unit.empty()) {
781 emin_unit = "keV";
782 }
783 if (emax_unit.empty()) {
784 emax_unit = "keV";
785 }
786
787 // Copy information
788 for (int i = 0; i < m_num; ++i) {
789 m_min[i](table["E_MIN"]->real(i), emin_unit);
790 m_max[i](table["E_MAX"]->real(i), emax_unit);
791 }
792
793 // Set attributes
795
796 } // endif: there were channels to read
797
798 // Return
799 return;
800}
801
802
803/***********************************************************************//**
804 * @brief Write energy boundaries into FITS object
805 *
806 * @param[in] fits FITS file.
807 * @param[in] extname Energy boundary extension name.
808 * @param[in] unit Energy units.
809 *
810 * Writes the energy boundaries into a FITS object. The @p unit parameter
811 * specifies in which unit the energies are written. By default, the energy
812 * units are keV.
813 *
814 * @todo Write header keywords.
815 ***************************************************************************/
817 const std::string& extname,
818 const std::string& unit) const
819{
820 // Create energy boundary columns
821 GFitsTableDoubleCol cemin("E_MIN", m_num);
822 GFitsTableDoubleCol cemax("E_MAX", m_num);
823
824 // Fill energy boundary columns
825 for (int i = 0; i < m_num; ++i) {
826 cemin(i) = m_min[i](unit);
827 cemax(i) = m_max[i](unit);
828 }
829
830 // Set energy units
831 cemin.unit(unit);
832 cemax.unit(unit);
833
834 // Create binary table
835 GFitsBinTable table(m_num);
836 table.append(cemin);
837 table.append(cemax);
838 table.extname(extname);
839
840 // If the FITS object contains already an extension with the same
841 // name then remove now this extension
842 if (fits.contains(extname)) {
843 fits.remove(extname);
844 }
845
846 // Append energy boundary table to FITS file
847 fits.append(table);
848
849 // Return
850 return;
851}
852
853
854/***********************************************************************//**
855 * @brief Read energy boundaries from XML element
856 *
857 * @param[in] xml XML element.
858 *
859 * @exception GException::invalid_value
860 * Invalid XML format encountered.
861 *
862 * Read energy boundaries from an XML element. The format of the energy
863 * boundaries is
864 *
865 * <parameter name="EnergyBoundaries" emin="0.1" emax="10.0"/>
866 *
867 * The units of the @a emin and @a emax parameters are MeV.
868 ***************************************************************************/
870{
871 // Clear energy boundaries
872 clear();
873
874 // Get energy boundaries parameter
876 "EnergyBoundaries");
877
878 // Extract position attributes
879 if (par->has_attribute("emin") && par->has_attribute("emax")) {
880 double emin = gammalib::todouble(par->attribute("emin"));
881 double emax = gammalib::todouble(par->attribute("emax"));
882 append(GEnergy(emin, "MeV"), GEnergy(emax, "MeV"));
883 }
884 else {
885 std::string msg = "Attributes \"emin\" and/or \"emax\" not found"
886 " in XML parameter \"EnergyBoundaries\"."
887 " Please verify the XML format.";
889 }
890
891 // Set attribues
893
894 // Return
895 return;
896}
897
898
899/***********************************************************************//**
900 * @brief Write energy boundaries into XML element
901 *
902 * @param[in] xml XML element.
903 *
904 * Writes energy boundaries into an XML element. The format of the energy
905 * boundaries is
906 *
907 * <parameter name="EnergyBoundaries" emin="0.1" emax="10.0"/>
908 *
909 * The units of the @a emin and @a emax parameters are MeV.
910 *
911 * This method does nothing if the energy boundaries are empty.
912 ***************************************************************************/
914{
915 // Continue only if there are energy boundaries
916 if (!is_empty()) {
917
918 // Get parameter
920 "EnergyBoundaries");
921
922 // Write attributes
923 par->attribute("emin", gammalib::str(emin().MeV()));
924 par->attribute("emax", gammalib::str(emax().MeV()));
925
926 } // endif: energy boundaries were not empty
927
928 // Return
929 return;
930}
931
932
933/***********************************************************************//**
934 * @brief Returns energy bin index for a given energy
935 *
936 * @param[in] eng Energy.
937 * @return Bin index.
938 *
939 * Returns the energy boundary bin index for a given energy. By convention,
940 * the limits for an energy bin are defined as
941 *
942 * min <= energy < max
943 *
944 * i.e. and energy equals to max falls above the largest energy.
945 *
946 * If the energy falls outside all boundaries, -1 is returned.
947 ***************************************************************************/
948int GEbounds::index(const GEnergy& eng) const
949{
950 // Initialise index with 'not found'
951 int index = -1;
952
953 // Search all energy boundaries for containment
954 for (int i = 0; i < m_num; ++i) {
955 if (eng >= m_min[i] && eng < m_max[i]) {
956 index = i;
957 break;
958 }
959 }
960
961 // Return index
962 return index;
963}
964
965
966/***********************************************************************//**
967 * @brief Set minimum energy for a given energy interval
968 *
969 * @param[in] index Energy interval index (0,...,size()-1).
970 * @param[in] energy Minimum energy of interval.
971 *
972 * @exception GException::out_of_range
973 * Specified index is out of range.
974 *
975 * Sets the minimum energy for the energy interval @p index.
976 ***************************************************************************/
977void GEbounds::emin(const int& index, const GEnergy& energy)
978{
979 #if defined(G_RANGE_CHECK)
980 // Throw an exception if index is outside valid range
983 "Minimum energy of interval",
984 index, m_num);
985 }
986 #endif
987
988 // Set minimum energy
989 m_min[index] = energy;
990
991 // Set attributes
993
994 // Return
995 return;
996}
997
998
999/***********************************************************************//**
1000 * @brief Set maximum energy for a given energy interval
1001 *
1002 * @param[in] index Energy interval index (0,...,size()-1).
1003 * @param[in] energy Maximum energy of interval.
1004 *
1005 * @exception GException::out_of_range
1006 * Specified index is out of range.
1007 *
1008 * Sets the maximum energy for the energy interval @p index.
1009 ***************************************************************************/
1010void GEbounds::emax(const int& index, const GEnergy& energy)
1011{
1012 #if defined(G_RANGE_CHECK)
1013 // Throw an exception if index is outside valid range
1016 "Maximum energy of interval",
1017 index, m_num);
1018 }
1019 #endif
1020
1021 // Set maximum energy
1022 m_max[index] = energy;
1023
1024 // Set attributes
1026
1027 // Return
1028 return;
1029}
1030
1031
1032/***********************************************************************//**
1033 * @brief Returns minimum energy for a given energy interval
1034 *
1035 * @param[in] index Energy interval index (0,...,size()-1).
1036 * @return Minimum energy of interval.
1037 *
1038 * @exception GException::out_of_range
1039 * Specified index is out of range.
1040 ***************************************************************************/
1041GEnergy GEbounds::emin(const int& index) const
1042{
1043 #if defined(G_RANGE_CHECK)
1044 // Throw an exception if index is outside valid range
1047 "Minimum energy of interval",
1048 index, m_num);
1049 }
1050 #endif
1051
1052 // Return minimum energy
1053 return (m_min[index]);
1054}
1055
1056
1057/***********************************************************************//**
1058 * @brief Returns maximum energy for a given energy interval
1059 *
1060 * @param[in] index Energy interval index (0,...,size()-1).
1061 * @return Maximum energy of interval.
1062 *
1063 * @exception GException::out_of_range
1064 * Specified index is out of range.
1065 ***************************************************************************/
1066GEnergy GEbounds::emax(const int& index) const
1067{
1068 #if defined(G_RANGE_CHECK)
1069 // Throw an exception if index is outside valid range
1072 "Maximum energy of interval",
1073 index, m_num);
1074 }
1075 #endif
1076
1077 // Return maximum energy
1078 return (m_max[index]);
1079}
1080
1081
1082/***********************************************************************//**
1083 * @brief Returns mean energy for a given energy interval
1084 *
1085 * @param[in] index Energy interval index [0,...,size()[.
1086 * @return Mean energy of interval.
1087 *
1088 * @exception GException::out_of_range
1089 * Specified index is out of range.
1090 *
1091 * Computes the mean energy
1092 * \f$0.5 * (E_{\rm min} + E_{\rm max})\f$
1093 * for the energy interval @p index.
1094 ***************************************************************************/
1095GEnergy GEbounds::emean(const int& index) const
1096{
1097 #if defined(G_RANGE_CHECK)
1098 // If index is outside boundary then throw an error
1100 throw GException::out_of_range(G_EMEAN, "Energy interval index",
1101 index, m_num);
1102 }
1103 #endif
1104
1105 // Compute mean energy
1106 GEnergy emean = 0.5 * (m_min[index] + m_max[index]);
1107
1108 // Return
1109 return emean;
1110}
1111
1112
1113/***********************************************************************//**
1114 * @brief Returns logarithmic mean energy for a given energy interval
1115 *
1116 * @param[in] index Energy interval index [0,...,size()[.
1117 * @return Logarithmic mean energy of interval.
1118 *
1119 * @exception GException::out_of_range
1120 * Specified index is out of range.
1121 *
1122 * Computes the logarithmic mean energy
1123 * \f$10^{0.5 * (\log E_{\rm min} + \log E_{\rm max})}\f$
1124 * for the energy interval @p index.
1125 ***************************************************************************/
1126GEnergy GEbounds::elogmean(const int& index) const
1127{
1128 #if defined(G_RANGE_CHECK)
1129 // If index is outside boundary then throw an error
1131 throw GException::out_of_range(G_ELOGMEAN, "Energy interval index",
1132 index, m_num);
1133 }
1134 #endif
1135
1136 // Compute logarithmic mean energy
1138 elogmean.MeV(std::sqrt(m_min[index].MeV() * m_max[index].MeV()));
1139
1140 // Return
1141 return elogmean;
1142}
1143
1144
1145/***********************************************************************//**
1146 * @brief Returns energy interval width
1147 *
1148 * @param[in] index Energy interval index [0,...,size()[.
1149 * @return Energy interval width.
1150 *
1151 * @exception GException::out_of_range
1152 * Specified index is out of range.
1153 ***************************************************************************/
1154GEnergy GEbounds::ewidth(const int& index) const
1155{
1156 #if defined(G_RANGE_CHECK)
1157 // If index is outside boundary then throw an error
1159 throw GException::out_of_range(G_EWIDTH, "Energy interval index",
1160 index, m_num);
1161 }
1162 #endif
1163
1164 // Return
1165 return (m_max[index]-m_min[index]);
1166}
1167
1168
1169
1170
1171/***********************************************************************//**
1172 * @brief Checks whether energy boundaries contain energy
1173 *
1174 * @param[in] eng Energy to be checked.
1175 * @return True if energy falls in at least one interval, false otherwise.
1176 *
1177 * Checks if the energy @p eng falls in at least one of the energy intervals.
1178 * The method exits when the first matching interval has been found.
1179 ***************************************************************************/
1180bool GEbounds::contains(const GEnergy& eng) const
1181{
1182 // Initialise test
1183 bool found = false;
1184
1185 // Test all energy boundaries
1186 for (int i = 0; i < m_num; ++i) {
1187 if (eng >= m_min[i] && eng <= m_max[i]) {
1188 found = true;
1189 break;
1190 }
1191 }
1192
1193 // Return result
1194 return found;
1195}
1196
1197
1198/***********************************************************************//**
1199 * @brief Checks whether energy boundaries contain and energy bin
1200 *
1201 * @param[in] emin Minimum energy of bin to be checked.
1202 * @param[in] emax Maximum energy of bin to be checked.
1203 * @return True if energy bin [emin, emax] is fully contained inside energy
1204 * the boundaries, false otherwiese
1205 *
1206 * Checks if the energy interval [@p emin, @p emax ] falls is fully contained
1207 * by energy boundaries
1208 *
1209 * @todo This method is so far only correct for contiguous energy boundaries.
1210 ***************************************************************************/
1211bool GEbounds::contains(const GEnergy& emin, const GEnergy& emax) const
1212{
1213 // Initialise result
1214 bool contained = false;
1215
1216 // Check if emin, emax is fully contained within this ebounds
1217 if (emin >= m_emin && emax <= m_emax) {
1218 contained = true;
1219 }
1220
1221 // Return result
1222 return contained;
1223}
1224
1225
1226/***********************************************************************//**
1227 * @brief Print energy boundaries
1228 *
1229 * @param[in] chatter Chattiness (defaults to NORMAL).
1230 * @return String containing energy boundary information.
1231 ***************************************************************************/
1232std::string GEbounds::print(const GChatter& chatter) const
1233{
1234 // Initialise result string
1235 std::string result;
1236
1237 // Continue only if chatter is not silent
1238 if (chatter != SILENT) {
1239
1240 // Append Header
1241 result.append("=== GEbounds ===");
1242
1243 // Append information
1244 result.append("\n"+gammalib::parformat("Number of intervals"));
1245 result.append(gammalib::str(size()));
1246 result.append("\n"+gammalib::parformat("Energy range"));
1247 result.append(emin().print());
1248 result.append(" - ");
1249 result.append(emax().print());
1250
1251 // If there are multiple energy bins then append them
1252 if (chatter >= EXPLICIT) {
1253 if (size() > 1) {
1254 for (int i = 0; i < size(); ++i) {
1255 result.append("\n");
1256 result.append(gammalib::parformat("Energy interval "+
1257 gammalib::str(i)));
1258 result.append(emin(i).print());
1259 result.append(" - ");
1260 result.append(emax(i).print());
1261 }
1262 }
1263 } // endif: chatter was less than explicit
1264
1265 } // endif: chatter was not silent
1266
1267 // Return
1268 return result;
1269}
1270
1271
1272/*==========================================================================
1273 = =
1274 = Private methods =
1275 = =
1276 ==========================================================================*/
1277
1278/***********************************************************************//**
1279 * @brief Initialise class members
1280 ***************************************************************************/
1282{
1283 // Initialise members
1284 m_num = 0;
1285 m_emin.clear();
1286 m_emax.clear();
1287 m_min = NULL;
1288 m_max = NULL;
1289
1290 // Return
1291 return;
1292}
1293
1294
1295/***********************************************************************//**
1296 * @brief Copy class members
1297 *
1298 * @param[in] ebds Energy boundaries.
1299 ***************************************************************************/
1301{
1302 // Copy attributes
1303 m_num = ebds.m_num;
1304 m_emin = ebds.m_emin;
1305 m_emax = ebds.m_emax;
1306
1307 // Copy arrays
1308 if (m_num > 0) {
1309 m_min = new GEnergy[m_num];
1310 m_max = new GEnergy[m_num];
1311 for (int i = 0; i < m_num; ++i) {
1312 m_min[i] = ebds.m_min[i];
1313 m_max[i] = ebds.m_max[i];
1314 }
1315 }
1316
1317 // Return
1318 return;
1319}
1320
1321
1322/***********************************************************************//**
1323 * @brief Delete class members
1324 ***************************************************************************/
1326{
1327 // Free memory
1328 if (m_min != NULL) delete [] m_min;
1329 if (m_max != NULL) delete [] m_max;
1330
1331 // Signal free pointers
1332 m_min = NULL;
1333 m_max = NULL;
1334
1335 // Return
1336 return;
1337}
1338
1339
1340/***********************************************************************//**
1341 * @brief Set class attributes
1342 *
1343 * Determines the minimum and maximum energy from all intervals. If no
1344 * interval is present the minimum and maximum energies are cleared.
1345 ***************************************************************************/
1347{
1348 // If there are intervals then determine the minimum and maximum
1349 // energy from these intervals ...
1350 if (m_num > 0) {
1351 m_emin = m_min[0];
1352 m_emax = m_max[0];
1353 for (int i = 1; i < m_num; ++i) {
1354 if (m_min[i] < m_emin) m_emin = m_min[i];
1355 if (m_max[i] > m_emax) m_emax = m_max[i];
1356 }
1357 }
1358
1359 // ... otherwise clear the minimum and maximum energy
1360 else {
1361 m_emin.clear();
1362 m_emax.clear();
1363 }
1364
1365 // Return
1366 return;
1367}
1368
1369
1370/***********************************************************************//**
1371 * @brief Insert energy interval
1372 *
1373 * @param[in] index Index after with interval is inserted.
1374 * @param[in] emin Minimum energy of interval.
1375 * @param[in] emax Maximum energy of interval.
1376 *
1377 * @exception GException::invalid_argument
1378 * Minimum energy larger than maximum energy
1379 *
1380 * Inserts an energy interval after the specified @p index in the energy
1381 * boundaries. The method does not reorder the intervals by energy, instead
1382 * the client needs to determine the approriate @p index.
1383 *
1384 * Invalid parameters do not produce any exception, but are handled
1385 * transparently. If the interval is invalid (i.e. @p emin > @p emax) an
1386 * exception is thrown. If the @p index is out of the valid range, the
1387 * index will be adjusted to either the first or the last element.
1388 ***************************************************************************/
1389void GEbounds::insert_eng(const int& index,
1390 const GEnergy& emin,
1391 const GEnergy& emax)
1392{
1393 // Throw an exception if energy interval is invalid
1394 if (emin > emax) {
1395 std::string msg = "Invalid energy interval specified. Minimum"
1396 " energy "+emin.print(NORMAL)+" can not be"
1397 " larger than maximum energy "+
1398 emax.print(NORMAL)+".";
1400 }
1401
1402 // Set index
1403 int inx = index;
1404
1405 // If inx is out of range then adjust it
1406 if (inx < 0) inx = 0;
1407 if (inx > m_num) inx = m_num;
1408
1409 // Allocate new intervals
1410 int num = m_num+1;
1411 GEnergy* min = new GEnergy[num];
1412 GEnergy* max = new GEnergy[num];
1413
1414 // Copy intervals before index to be inserted
1415 for (int i = 0; i < inx; ++i) {
1416 min[i] = m_min[i];
1417 max[i] = m_max[i];
1418 }
1419
1420 // Insert interval
1421 min[inx] = emin;
1422 max[inx] = emax;
1423
1424 // Copy intervals after index to be inserted
1425 for (int i = inx+1; i < num; ++i) {
1426 min[i] = m_min[i-1];
1427 max[i] = m_max[i-1];
1428 }
1429
1430 // Free memory
1431 if (m_min != NULL) delete [] m_min;
1432 if (m_max != NULL) delete [] m_max;
1433
1434 // Set new memory
1435 m_min = min;
1436 m_max = max;
1437
1438 // Set number of elements
1439 m_num = num;
1440
1441 // Set attributes
1443
1444 // Return
1445 return;
1446}
1447
1448
1449/*==========================================================================
1450 = =
1451 = Friends =
1452 = =
1453 ==========================================================================*/
1454
1455/***********************************************************************//**
1456 * @brief Energy boundaries equality operator friend
1457 *
1458 * @param[in] a First energy boundaries.
1459 * @param[in] b Second energy boundaries.
1460 * @return True if both energy boundaries are identical.
1461 ***************************************************************************/
1462bool operator==(const GEbounds& a, const GEbounds& b)
1463{
1464 // Initialise identify flag
1465 bool identity = true;
1466
1467 // Check that both energy boundaries have the same size
1468 if (a.size() != b.size()) {
1469 identity = false;
1470 }
1471
1472 // Check all energy boundaries
1473 else {
1474 for (int i = 0; i < a.size(); ++i) {
1475 if ((a.emin(i) != b.emin(i)) || (a.emax(i) != b.emax(i))) {
1476 identity = false;
1477 break;
1478 }
1479 }
1480 }
1481
1482 // Return identity flag
1483 return identity;
1484}
#define G_REMOVE_ENG
Definition GEbounds.cpp:47
#define G_WRITE_XML
Definition GEbounds.cpp:45
#define G_ELOGMEAN
Definition GEbounds.cpp:53
#define G_EMEAN
Definition GEbounds.cpp:52
#define G_READ_XML
Definition GEbounds.cpp:44
#define G_INSERT_ENG
Definition GEbounds.cpp:55
bool operator==(const GEbounds &a, const GEbounds &b)
Energy boundaries equality operator friend.
#define G_REMOVE_INX
Definition GEbounds.cpp:46
#define G_EWIDTH
Definition GEbounds.cpp:54
Energy boundaries class interface definition.
Energy container class definition.
Exception handler interface definition.
Filename class interface definition.
FITS binary table class definition.
FITS table double column class interface definition.
FITS table abstract base class interface definition.
FITS file class interface definition.
#define G_EMAX_SET
#define G_EMAX_GET
#define G_EMIN_GET
#define G_EMIN_SET
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ NORMAL
Definition GTypemaps.hpp:36
@ EXPLICIT
Definition GTypemaps.hpp:37
@ SILENT
Definition GTypemaps.hpp:34
double min(const GVector &vector)
Computes minimum vector element.
Definition GVector.cpp:886
double max(const GVector &vector)
Computes maximum vector element.
Definition GVector.cpp:915
XML element node class interface definition.
Energy boundaries container class.
Definition GEbounds.hpp:60
GEnergy * m_max
Array of interval maximum energies.
Definition GEbounds.hpp:141
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 remove(const int &index)
Remove energy interval.
Definition GEbounds.cpp:427
void reserve(const int &num)
Reserve space for energy intervals.
Definition GEbounds.cpp:538
bool contains(const GEnergy &eng) const
Checks whether energy boundaries contain energy.
void merge(void)
Merge all overlapping or connecting successive energy intervals.
Definition GEbounds.cpp:349
void set(const GEnergies &energies)
Set energy boundaries from energy container.
Definition GEbounds.cpp:618
GEbounds(void)
Constructor.
Definition GEbounds.cpp:73
void free_members(void)
Delete class members.
GEnergy ewidth(const int &index) const
Returns energy interval width.
void copy_members(const GEbounds &ebds)
Copy class members.
void save(const GFilename &filename, const bool &clobber=false, const std::string &unit="keV") const
Save energy boundaries into FITS file.
Definition GEbounds.cpp:733
void read(const GFitsTable &table)
Read energy boundaries from FITS table.
Definition GEbounds.cpp:761
GEbounds * clone(void) const
Clone energy boundaries.
Definition GEbounds.cpp:286
void init_members(void)
Initialise class members.
GEnergy emean(const int &index) const
Returns mean energy for a given energy interval.
int m_num
Number of energy boundaries.
Definition GEbounds.hpp:137
void insert(const GEnergy &emin, const GEnergy &emax)
Insert energy interval.
Definition GEbounds.cpp:322
std::string print(const GChatter &chatter=NORMAL) const
Print energy boundaries.
void append(const GEnergy &emin, const GEnergy &emax)
Append energy interval.
Definition GEbounds.cpp:301
virtual ~GEbounds(void)
Destructor.
Definition GEbounds.cpp:216
GEnergy * m_min
Array of interval minimum energies.
Definition GEbounds.hpp:140
GEnergy m_emin
Minimum energy of all intervals.
Definition GEbounds.hpp:138
int size(void) const
Return number of energy boundaries.
Definition GEbounds.hpp:163
void clear(void)
Clear energy boundaries.
Definition GEbounds.cpp:268
void load(const GFilename &filename)
Load energy boundaries from FITS file.
Definition GEbounds.cpp:689
GEbounds & operator=(const GEbounds &ebds)
Assignment operator.
Definition GEbounds.cpp:238
void insert_eng(const int &index, const GEnergy &emin, const GEnergy &emax)
Insert energy interval.
void extend(const GEbounds &ebds)
Append energy boundaries.
Definition GEbounds.cpp:552
bool is_empty(void) const
Signal if there are no energy boundaries.
Definition GEbounds.hpp:175
GEnergy elogmean(const int &index) const
Returns logarithmic mean energy for a given energy interval.
const GEnergy & emin(void) const
Return minimum energy of all intervals.
Definition GEbounds.hpp:187
GEnergy m_emax
Maximum energy of all intervals.
Definition GEbounds.hpp:139
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
void set_attributes(void)
Set class attributes.
Energy container class.
Definition GEnergies.hpp:60
int size(void) const
Return number of energies in container.
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)
std::string extname(const std::string &defaultname="") const
Return extension name.
FITS binary table class.
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
int integer(const std::string &keyname) const
Return card value as integer.
Definition GFitsHDU.hpp:436
void unit(const std::string &unit)
Set column unit.
FITS table double column.
Abstract interface for FITS table.
GFitsTableCol * append(const GFitsTableCol &column)
Append column to the table.
FITS file class.
Definition GFits.hpp:63
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
void save(const bool &clobber=false)
Saves FITS file.
Definition GFits.cpp:1178
GFitsTable * table(const int &extno)
Get pointer to table HDU.
Definition GFits.cpp:482
XML element node class.
const GXmlAttribute * attribute(const int &index) const
Return attribute.
bool has_attribute(const std::string &name) const
Check if element has a given attribute.
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 GXmlElement * xml_get_par(const std::string &origin, const GXmlElement &xml, const std::string &name)
Return pointer to parameter with given name in XML element.
Definition GTools.cpp:1689
double todouble(const std::string &arg)
Convert string into double precision value.
Definition GTools.cpp:926
GXmlElement * xml_need_par(const std::string &origin, GXmlElement &xml, const std::string &name)
Return pointer to parameter with given name in XML element.
Definition GTools.cpp:1637