GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GEnergies.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GEnergies.cpp - Energy container class *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2013-2021 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 GEnergies.cpp
23  * @brief Energy container class implementation
24  * @author Juergen Knoedlseder
25  */
26 
27 /* __ Includes ___________________________________________________________ */
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include "GTools.hpp"
32 #include "GException.hpp"
33 #include "GFilename.hpp"
34 #include "GEnergies.hpp"
35 #include "GEbounds.hpp"
36 #include "GFits.hpp"
37 #include "GFitsTable.hpp"
38 #include "GFitsBinTable.hpp"
39 #include "GFitsTableCol.hpp"
40 #include "GFitsTableDoubleCol.hpp"
41 
42 /* __ Method name definitions ____________________________________________ */
43 #define G_AT "GEnergies::at(int&)"
44 #define G_INSERT "GEnergies::insert(int&, GEnergy&)"
45 #define G_REMOVE "GEnergies::remove(int&)"
46 #define G_SET "GEnergies::set(int&, GEnergy&, GEnergy&, std::string&, "\
47  "double&)"
48 #define G_SET_LIN "GEnergies::set_lin(int&, GEnergy&, GEnergy&)"
49 #define G_SET_LOG "GEnergies::set_log(int&, GEnergy&, GEnergy&)"
50 #define G_SET_POW "GEnergies::set_pow(int&, GEnergy&, GEnergy&, double&)"
51 
52 /* __ Macros _____________________________________________________________ */
53 
54 /* __ Coding definitions _________________________________________________ */
55 
56 /* __ Debug definitions __________________________________________________ */
57 
58 
59 /*==========================================================================
60  = =
61  = Constructors/destructors =
62  = =
63  ==========================================================================*/
64 
65 /***********************************************************************//**
66  * @brief Void constructor
67  *
68  * Constructs empty energy container.
69  ***************************************************************************/
71 {
72  // Initialise members
73  init_members();
74 
75  // Return
76  return;
77 }
78 
79 
80 /***********************************************************************//**
81  * @brief FITS file constructor
82  *
83  * @param[in] filename FITS file name.
84  *
85  * Constructs energy container from a FITS file.
86  ***************************************************************************/
88 {
89  // Initialise members
90  init_members();
91 
92  // Load energies
93  load(filename);
94 
95  // Return
96  return;
97 }
98 
99 
100 /***********************************************************************//**
101  * @brief Energy boundaries constructor
102  *
103  * @param[in] ebounds Energy boundaries.
104  *
105  * Constructs energy container from energy boundaries.
106  ***************************************************************************/
108 {
109  // Initialise members
110  init_members();
111 
112  // Set energies from energy boundaries
113  set(ebounds);
114 
115  // Return
116  return;
117 }
118 
119 
120 /***********************************************************************//**
121  * @brief Copy constructor
122  *
123  * @param[in] energies Energy container.
124  *
125  * Construct energy container by copying from another energy container.
126  ***************************************************************************/
128 {
129  // Initialise members
130  init_members();
131 
132  // Copy members
133  copy_members(energies);
134 
135  // Return
136  return;
137 }
138 
139 
140 /***********************************************************************//**
141  * @brief Interval constructor
142  *
143  * @param[in] num Number of energies.
144  * @param[in] emin Minimum energy.
145  * @param[in] emax Maximum energy.
146  * @param[in] method Energy spacing method (one of "LIN", "LOG" or "POW").
147  * @param[in] gamma Power law index for @p POW method.
148  *
149  * Constructs energy container by defining @p num energies between @p emin
150  * and @p emax. The @p method parameter controls the energy spacing of the
151  * energies. See the set() method for more information.
152  ***************************************************************************/
153 GEnergies::GEnergies(const int& num,
154  const GEnergy& emin,
155  const GEnergy& emax,
156  const std::string& method,
157  const double& gamma)
158 {
159  // Initialise members
160  init_members();
161 
162  // Set intervals
163  set(num, emin, emax, method, gamma);
164 
165  // Return
166  return;
167 }
168 
169 
170 /***********************************************************************//**
171  * @brief Destructor
172  ***************************************************************************/
174 {
175  // Free members
176  free_members();
177 
178  // Return
179  return;
180 }
181 
182 
183 /*==========================================================================
184  = =
185  = Operators =
186  = =
187  ==========================================================================*/
188 
189 /***********************************************************************//**
190  * @brief Assignment operator
191  *
192  * @param[in] energies Energy container.
193  * @return Energy container.
194  ***************************************************************************/
196 {
197  // Execute only if object is not identical
198  if (this != &energies) {
199 
200  // Free members
201  free_members();
202 
203  // Initialise members
204  init_members();
205 
206  // Copy members
207  copy_members(energies);
208 
209  } // endif: object was not identical
210 
211  // Return this object
212  return *this;
213 }
214 
215 
216 /*==========================================================================
217  = =
218  = Public methods =
219  = =
220  ==========================================================================*/
221 
222 /***********************************************************************//**
223  * @brief Clear energy container
224  *
225  * Removes all energies from the container.
226  ***************************************************************************/
228 {
229  // Free members
230  free_members();
231 
232  // Initialise members
233  init_members();
234 
235  // Return
236  return;
237 }
238 
239 
240 /***********************************************************************//**
241  * @brief Clone energy container
242  *
243  * @return Pointer to deep copy of energy container
244  *
245  * Makes a deep copy of the energy container instance.
246  ***************************************************************************/
248 {
249  return new GEnergies(*this);
250 }
251 
252 
253 /***********************************************************************//**
254  * @brief Return reference to energy
255  *
256  * @param[in] index Energy index [0,...,size()[.
257  *
258  * @exception GException::out_of_range
259  * Energy index is out of range.
260  *
261  * Returns a reference to the energy with the specified @p index.
262  ***************************************************************************/
263 GEnergy& GEnergies::at(const int& index)
264 {
265  // Raise exception if index is out of range
266  if (index < 0 || index >= size()) {
267  throw GException::out_of_range(G_AT, "Energy index", index, size());
268  }
269 
270  // Return reference
271  return m_energies[index];
272 }
273 
274 
275 /***********************************************************************//**
276  * @brief Return reference to energy (const version)
277  *
278  * @param[in] index Energy index [0,...,size()[.
279  *
280  * @exception GException::out_of_range
281  * Energy index is out of range.
282  *
283  * Returns a reference to the energy with the specified @p index.
284  ***************************************************************************/
285 const GEnergy& GEnergies::at(const int& index) const
286 {
287  // Raise exception if index is out of range
288  if (index < 0 || index >= size()) {
289  throw GException::out_of_range(G_AT, "Energy index", index, size());
290  }
291 
292  // Return reference
293  return m_energies[index];
294 }
295 
296 
297 /***********************************************************************//**
298  * @brief Append energy to container
299  *
300  * @param[in] energy Energy.
301  * @return Reference to appended energy.
302  *
303  * Appends energy to the container by making a deep copy of the energy.
304  ***************************************************************************/
306 {
307  // Append energy to list
308  m_energies.push_back(energy);
309 
310  // Return reference
311  return m_energies[size()-1];
312 }
313 
314 
315 /***********************************************************************//**
316  * @brief Insert energy into container
317  *
318  * @param[in] index Energy index (0,...,size()[.
319  * @param[in] energy Energy.
320  *
321  * @exception GException::out_of_range
322  * Energy index is out of range.
323  *
324  * Inserts an @p energy into the container before the energy with the
325  * specified @p index.
326  ***************************************************************************/
327 GEnergy& GEnergies::insert(const int& index, const GEnergy& energy)
328 {
329  // Compile option: raise exception if index is out of range
330  #if defined(G_RANGE_CHECK)
331  if (is_empty()) {
332  if (index > 0) {
333  throw GException::out_of_range(G_INSERT, "Energy index",
334  index, size());
335  }
336  }
337  else {
338  if (index < 0 || index >= size()) {
339  throw GException::out_of_range(G_INSERT, "Energy index",
340  index, size());
341  }
342  }
343  #endif
344 
345  // Inserts energy
346  m_energies.insert(m_energies.begin()+index, energy);
347 
348  // Return reference
349  return m_energies[index];
350 }
351 
352 
353 /***********************************************************************//**
354  * @brief Remove energy from container
355  *
356  * @param[in] index Energy index (0,...,size()[.
357  *
358  * @exception GException::out_of_range
359  * Energy index is out of range.
360  *
361  * Remove energy of specified @p index from container.
362  ***************************************************************************/
363 void GEnergies::remove(const int& index)
364 {
365  // Compile option: raise exception if index is out of range
366  #if defined(G_RANGE_CHECK)
367  if (index < 0 || index >= size()) {
368  throw GException::out_of_range(G_REMOVE, "Energy index",
369  index, size());
370  }
371  #endif
372 
373  // Erase energy from container
374  m_energies.erase(m_energies.begin() + index);
375 
376  // Return
377  return;
378 }
379 
380 
381 /***********************************************************************//**
382  * @brief Append energy container
383  *
384  * @param[in] energies Energy container.
385  *
386  * Append energy container to the container.
387  ***************************************************************************/
388 void GEnergies::extend(const GEnergies& energies)
389 {
390  // Do nothing if energy container is empty
391  if (!energies.is_empty()) {
392 
393  // Get size. Note that we extract the size first to avoid an
394  // endless loop that arises when a container is appended to
395  // itself.
396  int num = energies.size();
397 
398  // Reserve enough space
399  reserve(size() + num);
400 
401  // Loop over all elements and append them to container
402  for (int i = 0; i < num; ++i) {
403  m_energies.push_back(energies[i]);
404  }
405 
406  } // endif: energy container was not empty
407 
408  // Return
409  return;
410 }
411 
412 
413 /***********************************************************************//**
414  * @brief Set energies from energy boundaries
415  *
416  * @param[in] ebounds Energy boundaries.
417  *
418  * Sets the energies from energy boundaries. Each unique minimum and maximum
419  * energy boundary will be appended as energy to the container.
420  ***************************************************************************/
421 void GEnergies::set(const GEbounds& ebounds)
422 {
423  // Initialise members
424  clear();
425 
426  // Get number of energy boundaries
427  int num = ebounds.size();
428 
429  // Append energy boundaries
430  for (int i = 0; i < num; ++i) {
431 
432  // Loop over minimum and maximum boundaries
433  for (int j = 0; j < 2; ++j) {
434 
435  // Get energy
436  GEnergy energy = (j == 0) ? ebounds.emin(i) : ebounds.emax(i);
437 
438  // Append energy if it does not yet exist in the container
439  bool not_found = true;
440  for (int k = 0; k < m_energies.size(); ++k) {
441  if (energy == m_energies[k]) {
442  not_found = false;
443  break;
444  }
445  }
446  if (not_found) {
447  m_energies.push_back(energy);
448  }
449 
450  } // endfor: looped over minimum and maximum boundaries
451 
452  } // endfor: looped over energy boundaries
453 
454  // Return
455  return;
456 }
457 
458 
459 /***********************************************************************//**
460  * @brief Set energies
461  *
462  * @param[in] num Number of energies.
463  * @param[in] emin Minimum energy.
464  * @param[in] emax Maximum energy.
465  * @param[in] method Energy spacing method (one of "LIN", "LOG" or "POW").
466  * @param[in] gamma Power law index for @p POW method.
467  *
468  * @exception GException::invalid_argument
469  * Invalid number of energies, energy interval or energy spacing
470  * method specified.
471  *
472  * Sets energies by defining @p num successive energies between @p emin and
473  * @p emax. The @p method parameter controls the energy spacing. See the
474  * set_lin(), set_log() and set_pow() methods for more information.
475  ***************************************************************************/
476 void GEnergies::set(const int& num,
477  const GEnergy& emin,
478  const GEnergy& emax,
479  const std::string& method,
480  const double& gamma)
481 {
482  // Check validity of number of energies
483  if (num < 0) {
484  std::string msg = "Negative number of energies "+gammalib::str(num)+
485  " specified. Please specify a non-negative number "
486  "of energies.";
488  }
489 
490  // Check validity of energies
491  if (emin > emax) {
492  std::string msg = "Minimum energy "+emin.print()+" is larger than "
493  "maximum energy "+emax.print()+". Please specify "
494  "a minimum energy that does not exceed the "
495  "maximum energy.";
497  }
498 
499  // If one energy is requested then check that emin and emax are equal
500  if (num == 1) {
501 
502  // Check that emin and emax are equal
503  if (emin != emax) {
504  std::string msg = "Single energy is requested but the minimum "
505  "energy "+emin.print()+" differs from the "
506  "maximum energy "+emax.print()+". Please "
507  "specify identical energies.";
509  }
510 
511  }
512 
513  // Convert method to upper-case string
514  std::string umethod = gammalib::toupper(method);
515 
516  // Dispatch to corresponding set methos
517  if (umethod == "LIN") {
518  set_lin(num, emin, emax);
519  }
520  else if (umethod == "LOG") {
521  set_log(num, emin, emax);
522  }
523  else if (umethod == "POW") {
524  set_pow(num, emin, emax, gamma);
525  }
526  else {
527  std::string msg = "Invalid energy spacing method \""+umethod+"\" "
528  "specified. Please provide one of \"LIN\", \"LOG\""
529  ", or \"POW\".";
531  }
532 
533  // Return
534  return;
535 }
536 
537 
538 /***********************************************************************//**
539  * @brief Load energies from FITS file
540  *
541  * @param[in] filename FITS file name.
542  *
543  * Loads the energies from FITS file.
544  *
545  * If no extension name is provided, the energies are loaded from the
546  * `ENERGIES` extension.
547  ***************************************************************************/
548 void GEnergies::load(const GFilename& filename)
549 {
550  // Open FITS file
551  GFits fits(filename);
552 
553  // Get energies table
554  const GFitsTable& table =
555  *fits.table(filename.extname(gammalib::extname_energies));
556 
557  // Read energies from table
558  read(table);
559 
560  // Close FITS file
561  fits.close();
562 
563  // Return
564  return;
565 }
566 
567 
568 /***********************************************************************//**
569  * @brief Save energies into FITS file
570  *
571  * @param[in] filename FITS filename.
572  * @param[in] clobber Overwrite an existing energies extension?
573  *
574  * Saves energies into a FITS file. If a file with the given @p filename
575  * does not yet exist it will be created, otherwise the method opens the
576  * existing file. Energies can only be appended to an existing file if the
577  * @p clobber flag is set to `true` (otherwise an exception is thrown).
578  *
579  * The method will append a binary FITS table containing the energies to the
580  * FITS file. The extension name can be specified as part of the
581  * @p filename. For example the @p filename
582  *
583  * myfile.fits[ENERGY VALUES]
584  *
585  * will save the energies in the `ENERGY VALUES` extension of the
586  * `myfile.fits` file. If the extension exists already in the file it will be
587  * replaced, otherwise a new extension will be created. If no extension name
588  * is provided, the method will use `ENERGIES` as the default extension name
589  * for energies.
590  ***************************************************************************/
591 void GEnergies::save(const GFilename& filename, const bool& clobber) const
592 {
593  // Open or create FITS file (without extension name since the requested
594  // extension may not yet exist in the file)
595  GFits fits(filename.url(), true);
596 
597  // Write energies to FITS file
598  write(fits, filename.extname(gammalib::extname_energies));
599 
600  // Save to file
601  fits.save(clobber);
602 
603  // Return
604  return;
605 }
606 
607 
608 /***********************************************************************//**
609  * @brief Read energies from FITS table
610  *
611  * @param[in] table FITS table.
612  *
613  * Reads the energies from a FITS table.
614  ***************************************************************************/
615 void GEnergies::read(const GFitsTable& table)
616 {
617  // Free members
618  free_members();
619 
620  // Initialise attributes
621  init_members();
622 
623  // Extract number of energy bins in FITS file
624  int num = table.integer("NAXIS2");
625 
626  // Continue only if there are energy bins
627  if (num > 0) {
628 
629  // Get the unit of the energies. If no TUNIT1 header keyword is
630  // found then use MeV
631  std::string unit = "MeV";
632  if (table.has_card("TUNIT1")) {
633  unit = table.string("TUNIT1");
634  }
635 
636  // Get the column with the name "Energy"
637  const GFitsTableCol* col_energy = table["Energy"];
638 
639  // Set energies
640  for (int i = 0; i < num; ++i) {
641  append(GEnergy(col_energy->real(i), unit));
642  }
643 
644  } // endif: there were energy bins
645 
646  // Return
647  return;
648 }
649 
650 
651 /***********************************************************************//**
652  * @brief Write energies into FITS object
653  *
654  * @param[in] fits FITS file.
655  * @param[in] extname Energy extension name.
656  *
657  * Writes energies into FITS object.
658  ***************************************************************************/
659 void GEnergies::write(GFits& fits, const std::string& extname) const
660 {
661  // Set number of energies
662  int num = m_energies.size();
663 
664  // Create Energy column
665  GFitsTableDoubleCol col_energy("Energy", num);
666 
667  // Fill energy column in units of MeV
668  for (int i = 0; i < num; ++i) {
669  col_energy(i) = (*this)[i].MeV();
670  }
671  col_energy.unit("MeV");
672 
673  // Create energies table
674  GFitsBinTable table(num);
675  table.append(col_energy);
676  table.extname(extname);
677 
678  // If the FITS object contains already an extension with the same
679  // name then remove now this extension
680  if (fits.contains(extname)) {
681  fits.remove(extname);
682  }
683 
684  // Append energies table to FITS file
685  fits.append(table);
686 
687  // Return
688  return;
689 }
690 
691 
692 /***********************************************************************//**
693  * @brief Print energy container information
694  *
695  * @param[in] chatter Chattiness.
696  * @return String containing energy container information.
697  ***************************************************************************/
698 std::string GEnergies::print(const GChatter& chatter) const
699 {
700  // Initialise result string
701  std::string result;
702 
703  // Continue only if chatter is not silent
704  if (chatter != SILENT) {
705 
706  // Append header
707  result.append("=== GEnergies ===");
708 
709  // Append energy container information
710  result.append("\n"+gammalib::parformat("Number of energies"));
711  result.append(gammalib::str(size()));
712 
713  // EXPLICIT: Append energies
714  if (chatter >= EXPLICIT) {
715  for (int i = 0; i < size(); ++i) {
716  result.append("\n");
717  result.append(gammalib::parformat("Energy "+gammalib::str(i)));
718  result.append(m_energies[i].print(chatter));
719  }
720  }
721 
722  } // endif: chatter was not silent
723 
724  // Return result
725  return result;
726 }
727 
728 
729 /*==========================================================================
730  = =
731  = Private methods =
732  = =
733  ==========================================================================*/
734 
735 /***********************************************************************//**
736  * @brief Initialise class members
737  ***************************************************************************/
739 {
740  // Initialise members
741  m_energies.clear();
742 
743  // Return
744  return;
745 }
746 
747 
748 /***********************************************************************//**
749  * @brief Copy class members
750  *
751  * @param[in] energies Energy container.
752  ***************************************************************************/
753 void GEnergies::copy_members(const GEnergies& energies)
754 {
755  // Copy attributes
756  m_energies = energies.m_energies;
757 
758  // Return
759  return;
760 }
761 
762 
763 /***********************************************************************//**
764  * @brief Delete class members
765  ***************************************************************************/
767 {
768  // Return
769  return;
770 }
771 
772 
773 /***********************************************************************//**
774  * @brief Set linearly spaced energies
775  *
776  * @param[in] num Number of energies (>0).
777  * @param[in] emin Minimum energy.
778  * @param[in] emax Maximum energy.
779  *
780  * Creates \f$N\f$ linearly spaced energy boundaries running from
781  * \f$E_{\rm min}\f$ to \f$E_{\rm max}\f$ defined by
782  *
783  * \f[
784  * E_i = E_{\rm min} + \frac{E_{\rm max} - E_{\rm min}}{N-1}
785  * \times i
786  * \f]
787  *
788  * The method does not check the validity of the @p num, @p emin and @p emax
789  * arguments.
790  ***************************************************************************/
791 void GEnergies::set_lin(const int& num,
792  const GEnergy& emin,
793  const GEnergy& emax)
794 {
795  // Initialise members
796  clear();
797 
798  // If a single energy is requested then just append the minimum energy
799  if (num == 1) {
800  append(emin);
801  }
802 
803  // ... otherwise append linearly spaced energies
804  else if (num > 1) {
805 
806  // Compute bin width
807  GEnergy ebin = (emax - emin)/double(num-1);
808 
809  // Append energies
810  GEnergy energy = emin;
811  for (int i = 0; i < num; ++i) {
812  append(energy);
813  energy += ebin;
814  }
815 
816  }
817 
818  // Return
819  return;
820 }
821 
822 
823 /***********************************************************************//**
824  * @brief Set logarithmically spaced energies
825  *
826  * @param[in] num Number of energies (>0).
827  * @param[in] emin Minimum energy.
828  * @param[in] emax Maximum energy.
829  *
830  * @exception GException::invalid_argument
831  * Minimum or maximum energy are not positive.
832  *
833  * Creates \f$N\f$ logarithmically spaced energy boundaries running from
834  * \f$E_{\rm min}\f$ to \f$E_{\rm max}\f$ defined by
835  *
836  * \f[
837  * E_i = 10^{\log_{10} E_{\rm min} +
838  * \frac{\log_{10} E_{\rm max} - \log_{10} E_{\rm min}}{N-1}
839  * \times i}
840  * \f]
841  *
842  * The method does not check the validity of the @p num, @p emin and @p emax
843  * arguments except for the positivity of @p emin and @p emax.
844  ***************************************************************************/
845 void GEnergies::set_log(const int& num,
846  const GEnergy& emin,
847  const GEnergy& emax)
848 {
849  // Initialise members
850  clear();
851 
852  // Throw an exception if the minimum or maximum energy is not positive
853  if (emin.MeV() <= 0.0) {
854  std::string msg = "Non-positive minimum energy "+emin.print()+
855  " specified. Please provide a positive minimum "
856  "energy value.";
858  }
859  if (emax.MeV() <= 0.0) {
860  std::string msg = "Non-positive maximum energy "+emax.print()+
861  " specified. Please provide a positive minimum "
862  "energy value.";
864  }
865 
866  // If a single energy is requested then just append the minimum energy
867  if (num == 1) {
868  append(emin);
869  }
870 
871  // ... otherwise append logarithmically spaced energies
872  else if (num > 1) {
873 
874  // Compute bin width
875  double elogmin = std::log10(emin.MeV());
876  double elogmax = std::log10(emax.MeV());
877  double elogbin = (elogmax - elogmin)/double(num-1);
878 
879  // Append energies
880  GEnergy energy;
881  for (int i = 0; i < num; ++i) {
882  energy.MeV(std::pow(10.0, double(i)*elogbin + elogmin));
883  append(energy);
884  }
885 
886  }
887 
888  // Return
889  return;
890 }
891 
892 
893 /***********************************************************************//**
894  * @brief Set power-law spaced energy intervals
895  *
896  * @param[in] num Number of energy intervals (>0).
897  * @param[in] emin Minimum energy of first interval.
898  * @param[in] emax Maximum energy of last interval.
899  * @param[in] gamma Power law index.
900  *
901  * @exception GException::invalid_argument
902  * Minimum or maximum energy are not positive.
903  *
904  * Creates \f$N\f$ power-law spaced energy boundaries running from
905  * \f$E_{\rm min}\f$ to \f$E_{\rm max}\f$ defined by
906  *
907  * \f[
908  * E_i = \left \{
909  * \begin{array}{l l}
910  * \exp \left( \frac{\log E_{\rm max} - \log E_{\rm min}}{N-1} +
911  * \log E_{i-1} \right)
912  * & \mbox{if $a = 0$} \\
913  * \\
914  * \exp \left( \frac{\log \left(\frac{E_{\rm max}^a - E_{\rm min}^a}{N-1} \right) +
915  * E_{i-1}^{a}}{a} \right)
916  * & \mbox{else}
917  * \end{array}
918  * \right .
919  * \f]
920  *
921  * where \f$i>0\f$, \f$a=1-\gamma\f$ and \f$E_0=E_{\rm min}\f$.
922  *
923  * The method does not check the validity of the @p num, @p emin and @p emax
924  * arguments except for the positivity of @p emin and @p emax.
925  ***************************************************************************/
926 void GEnergies::set_pow(const int& num,
927  const GEnergy& emin,
928  const GEnergy& emax,
929  const double& gamma)
930 {
931  // Initialise members
932  clear();
933 
934  // Throw an exception if the minimum or maximum energy is not positive
935  if (emin.MeV() <= 0.0) {
936  std::string msg = "Non-positive minimum energy "+emin.print()+
937  " specified. Please provide a positive minimum "
938  "energy value.";
940  }
941  if (emax.MeV() <= 0.0) {
942  std::string msg = "Non-positive maximum energy "+emax.print()+
943  " specified. Please provide a positive minimum "
944  "energy value.";
946  }
947 
948  // If a single energy is requested then just append the minimum energy
949  if (num == 1) {
950  append(emin);
951  }
952 
953  // ... otherwise append logarithmically spaced energies
954  else if (num > 1) {
955 
956  // Append first energy
957  append(emin);
958 
959  // Precomputation (we work in MeV from now on)
960  double a = 1.0 - gamma;
961  double c = (a == 0.0) ? 1.0 / (std::log(emax.MeV()) - std::log(emin.MeV()))
962  : a / (std::pow(emax.MeV(),a) - std::pow(emin.MeV(),a));
963  double b = double(c*(num-1.0));
964 
965  // Initialse first energy
966  double e = emin.MeV();
967 
968  // Loop over energies
969  for (int i = 0; i < num-1; ++i) {
970 
971  // Compute next energy
972  double log_e_next = (a == 0.0)
973  ? 1.0/b + std::log(e)
974  : std::log(a/b + std::pow(e,a)) / a;
975  double e_next = std::exp(log_e_next);
976 
977  // Append next energy
978  append(GEnergy(e_next, "MeV"));
979 
980  // Set next energy as starting energy for next iteration
981  e = e_next;
982 
983  } // endfor: looped over energies
984 
985  } // endif: number of energies was positive
986 
987  // Return
988  return;
989 }
std::string print(const GChatter &chatter=NORMAL) const
Print energy container information.
Definition: GEnergies.cpp:698
void unit(const std::string &unit)
Set column unit.
void clear(void)
Clear energy container.
Definition: GEnergies.cpp:227
FITS table double column class interface definition.
void read(const GFitsTable &table)
Read energies from FITS table.
Definition: GEnergies.cpp:615
GFitsTable * table(const int &extno)
Get pointer to table HDU.
Definition: GFits.cpp:482
bool contains(const int &extno) const
Check if HDU exists in FITS file.
Definition: GFits.hpp:282
bool has_card(const int &cardno) const
Check existence of header card.
Definition: GFitsHDU.hpp:233
void write(GFits &file, const std::string &extname=gammalib::extname_energies) const
Write energies into FITS object.
Definition: GEnergies.cpp:659
int size(void) const
Return number of energy boundaries.
Definition: GEbounds.hpp:163
void set_pow(const int &num, const GEnergy &emin, const GEnergy &emax, const double &gamma)
Set power-law spaced energy intervals.
Definition: GEnergies.cpp:926
void reserve(const int &num)
Reserves space for energies in container.
Definition: GEnergies.hpp:198
void set_lin(const int &num, const GEnergy &emin, const GEnergy &emax)
Set linearly spaced energies.
Definition: GEnergies.cpp:791
#define G_INSERT
Definition: GEnergies.cpp:44
std::string extname(const std::string &defaultname="") const
Return extension name.
Definition: GFilename.cpp:385
GFitsTableCol * append(const GFitsTableCol &column)
Append column to the table.
Definition: GFitsTable.hpp:147
double MeV(void) const
Return energy in MeV.
Definition: GEnergy.cpp:321
Gammalib tools definition.
FITS file class.
Definition: GFits.hpp:63
FITS file class interface definition.
virtual ~GEnergies(void)
Destructor.
Definition: GEnergies.cpp:173
FITS table column abstract base class definition.
Energy container class.
Definition: GEnergies.hpp:60
void remove(const int &index)
Remove energy from container.
Definition: GEnergies.cpp:363
void free_members(void)
Delete class members.
Definition: GEnergies.cpp:766
GEnergy & insert(const int &index, const GEnergy &energy)
Insert energy into container.
Definition: GEnergies.cpp:327
std::vector< GEnergy > m_energies
List of energies.
Definition: GEnergies.hpp:118
#define G_AT
Definition: GEnergies.cpp:43
#define G_SET_LOG
Definition: GEnergies.cpp:49
GEnergies(void)
Void constructor.
Definition: GEnergies.cpp:70
Energy boundaries container class.
Definition: GEbounds.hpp:60
void remove(const int &extno)
Remove HDU from FITS file.
Definition: GFits.cpp:862
std::string print(const GChatter &chatter=NORMAL) const
Print energy.
Definition: GEnergy.cpp:748
Filename class.
Definition: GFilename.hpp:62
Energy container class definition.
const GEnergy & emin(void) const
Return minimum energy of all intervals.
Definition: GEbounds.hpp:187
Abstract interface for FITS table column.
GEnergy & at(const int &index)
Return reference to energy.
Definition: GEnergies.cpp:263
int size(void) const
Return number of energies in container.
Definition: GEnergies.hpp:170
GVector log(const GVector &vector)
Computes natural logarithm of vector elements.
Definition: GVector.cpp:1274
#define G_SET_POW
Definition: GEnergies.cpp:50
Abstract interface for FITS table.
Definition: GFitsTable.hpp:44
GChatter
Definition: GTypemaps.hpp:33
int integer(const std::string &keyname) const
Return card value as integer.
Definition: GFitsHDU.hpp:436
void extend(const GEnergies &energies)
Append energy container.
Definition: GEnergies.cpp:388
const std::string & extname(void) const
Return extension name.
Definition: GFitsHDU.hpp:162
void save(const GFilename &filename, const bool &clobber=false) const
Save energies into FITS file.
Definition: GEnergies.cpp:591
bool is_empty(void) const
Signals if there are no energies in container.
Definition: GEnergies.hpp:184
const std::string extname_energies
Definition: GEnergies.hpp:44
void set(const GEbounds &ebounds)
Set energies from energy boundaries.
Definition: GEnergies.cpp:421
GEnergies & operator=(const GEnergies &energies)
Assignment operator.
Definition: GEnergies.cpp:195
std::string url(void) const
Return Uniform Resource Locator (URL)
Definition: GFilename.hpp:189
virtual double real(const int &row, const int &inx=0) const =0
FITS binary table class.
GVector pow(const GVector &vector, const double &power)
Computes tanh of vector elements.
Definition: GVector.cpp:1422
std::string string(const std::string &keyname) const
Return card value as string.
Definition: GFitsHDU.hpp:410
Energy boundaries class interface definition.
GEnergy & append(const GEnergy &energy)
Append energy to container.
Definition: GEnergies.cpp:305
void copy_members(const GEnergies &energies)
Copy class members.
Definition: GEnergies.cpp:753
Exception handler interface definition.
GFitsHDU * append(const GFitsHDU &hdu)
Append HDU to FITS file.
Definition: GFits.cpp:678
std::string toupper(const std::string &s)
Convert string to upper case.
Definition: GTools.cpp:941
FITS binary table class definition.
GVector exp(const GVector &vector)
Computes exponential of vector elements.
Definition: GVector.cpp:1232
#define G_SET
Definition: GEnergies.cpp:46
const GEnergy & emax(void) const
Return maximum energy of all intervals.
Definition: GEbounds.hpp:199
#define G_REMOVE
Definition: GEnergies.cpp:45
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition: GTools.cpp:1143
GEnergies * clone(void) const
Clone energy container.
Definition: GEnergies.cpp:247
void set_log(const int &num, const GEnergy &emin, const GEnergy &emax)
Set logarithmically spaced energies.
Definition: GEnergies.cpp:845
void load(const GFilename &filename)
Load energies from FITS file.
Definition: GEnergies.cpp:548
void close(void)
Close FITS file.
Definition: GFits.cpp:1342
FITS table double column.
void init_members(void)
Initialise class members.
Definition: GEnergies.cpp:738
Filename class interface definition.
GVector log10(const GVector &vector)
Computes base10 logarithm of vector elements.
Definition: GVector.cpp:1295
Class that handles energies in a unit independent way.
Definition: GEnergy.hpp:48
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489
FITS table abstract base class interface definition.