Commit 5fbb6c3ebc420786b47bafa922080533fc08b6c3

Authored by Josh Cardenzana
2 parents 76bc331f e0d833e6

Merge branch 'devel' into 1948-implement-smoothbrokenpowerlaw

ChangeLog
1 -2017-03-18 1 +2017-03-22
2 2
3 * Version 1.3.0 released 3 * Version 1.3.0 released
4 ========================= 4 =========================
5 5
  6 + Implement lazy loading of energy dispersion in GCTAEdisp2D (#1940)
6 Add GCTARoi::contains method 7 Add GCTARoi::contains method
7 Do no longer interpret a CTA calibration database as file path (#1969) 8 Do no longer interpret a CTA calibration database as file path (#1969)
8 Add GCTAResponseIrf::rspname() method 9 Add GCTAResponseIrf::rspname() method
1 -New Features and Important Changes in GammaLib 1.3.0 1 +New Features and Important Changes in GammaLib 1.3.0.dev1
2 2
3 -18 March 2017 3 +22 March 2017
4 4
5 5
6 1. Introduction 6 1. Introduction
@@ -24,6 +24,7 @@ The following classes have been renamed: @@ -24,6 +24,7 @@ The following classes have been renamed:
24 The following methods have been added: 24 The following methods have been added:
25 - GCTAResponseIrf::rspname 25 - GCTAResponseIrf::rspname
26 - GCTARoi::contains 26 - GCTARoi::contains
  27 +- GCTAEdisp2D::fetch
27 28
28 The following methods have been removed: 29 The following methods have been removed:
29 - ... 30 - ...
@@ -141,6 +142,10 @@ GCTAResponseIrf::read() method (#1969). @@ -141,6 +142,10 @@ GCTAResponseIrf::read() method (#1969).
141 Add GCTARoi::contains() method that checks whether an instrument direction 142 Add GCTARoi::contains() method that checks whether an instrument direction
142 is contained within the region of interest. 143 is contained within the region of interest.
143 144
  145 +Lazy loading of the energy dispersion in GCTAEdisp2D has been implemented by
  146 +adding a fetch() method to the class. Now the energy dispersion is only loaded
  147 +when needed, for example for function evaluation or Monte Carlo sampling (#1940).
  148 +
144 149
145 21. COMPTEL interface 150 21. COMPTEL interface
146 --------------------- 151 ---------------------
inst/cta/include/GCTAEdisp2D.hpp
1 /*************************************************************************** 1 /***************************************************************************
2 * GCTAEdisp2D.hpp - CTA 2D energy dispersion class * 2 * GCTAEdisp2D.hpp - CTA 2D energy dispersion class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2015-2016 by Florent Forest * 4 + * copyright (C) 2015-2017 by Florent Forest *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -90,12 +90,14 @@ public: @@ -90,12 +90,14 @@ public:
90 std::string print(const GChatter& chatter = NORMAL) const; 90 std::string print(const GChatter& chatter = NORMAL) const;
91 91
92 // Methods 92 // Methods
  93 + void fetch(void) const;
93 const GCTAResponseTable& table(void) const; 94 const GCTAResponseTable& table(void) const;
94 void table(const GCTAResponseTable& table); 95 void table(const GCTAResponseTable& table);
95 void read(const GFitsTable& table); 96 void read(const GFitsTable& table);
96 void write(GFitsBinTable& table) const; 97 void write(GFitsBinTable& table) const;
97 void save(const GFilename& filename, 98 void save(const GFilename& filename,
98 const bool& clobber = false) const; 99 const bool& clobber = false) const;
  100 +
99 private: 101 private:
100 // Methods 102 // Methods
101 void init_members(void); 103 void init_members(void);
@@ -133,6 +135,7 @@ private: @@ -133,6 +135,7 @@ private:
133 // Members 135 // Members
134 mutable GFilename m_filename; //!< Name of Edisp response file 136 mutable GFilename m_filename; //!< Name of Edisp response file
135 GCTAResponseTable m_edisp; //!< Edisp response table 137 GCTAResponseTable m_edisp; //!< Edisp response table
  138 + mutable bool m_fetched; //!< Signals that Edisp has been fetched
136 int m_inx_etrue; //!< True energy index 139 int m_inx_etrue; //!< True energy index
137 int m_inx_migra; //!< Migration index 140 int m_inx_migra; //!< Migration index
138 int m_inx_theta; //!< Theta index 141 int m_inx_theta; //!< Theta index
inst/cta/src/GCTAEdisp2D.cpp
@@ -45,6 +45,7 @@ @@ -45,6 +45,7 @@
45 #define G_READ "GCTAEdisp2D::read(GFitsTable&)" 45 #define G_READ "GCTAEdisp2D::read(GFitsTable&)"
46 #define G_MC "GCTAEdisp2D::mc(GRan&, double&, double&, double&, double&, "\ 46 #define G_MC "GCTAEdisp2D::mc(GRan&, double&, double&, double&, double&, "\
47 "double&)" 47 "double&)"
  48 +#define G_FETCH "GCTAEdisp2D::fetch()"
48 49
49 /* __ Macros _____________________________________________________________ */ 50 /* __ Macros _____________________________________________________________ */
50 51
@@ -191,6 +192,9 @@ double GCTAEdisp2D::operator()(const double&amp; logEobs, @@ -191,6 +192,9 @@ double GCTAEdisp2D::operator()(const double&amp; logEobs,
191 const double& zenith, 192 const double& zenith,
192 const double& azimuth) const 193 const double& azimuth) const
193 { 194 {
  195 + // Make sure that energy dispersion is online
  196 + fetch();
  197 +
194 // Initalize edisp 198 // Initalize edisp
195 double edisp = 0.0; 199 double edisp = 0.0;
196 200
@@ -407,6 +411,9 @@ void GCTAEdisp2D::read(const GFitsTable&amp; table) @@ -407,6 +411,9 @@ void GCTAEdisp2D::read(const GFitsTable&amp; table)
407 ***************************************************************************/ 411 ***************************************************************************/
408 void GCTAEdisp2D::write(GFitsBinTable& table) const 412 void GCTAEdisp2D::write(GFitsBinTable& table) const
409 { 413 {
  414 + // Make sure that energy dispersion is online
  415 + fetch();
  416 +
410 // Write background table 417 // Write background table
411 m_edisp.write(table); 418 m_edisp.write(table);
412 419
@@ -427,17 +434,8 @@ void GCTAEdisp2D::write(GFitsBinTable&amp; table) const @@ -427,17 +434,8 @@ void GCTAEdisp2D::write(GFitsBinTable&amp; table) const
427 ***************************************************************************/ 434 ***************************************************************************/
428 void GCTAEdisp2D::load(const GFilename& filename) 435 void GCTAEdisp2D::load(const GFilename& filename)
429 { 436 {
430 - // Open FITS file  
431 - GFits fits(filename);  
432 -  
433 - // Get energy dispersion table  
434 - const GFitsTable& table = *fits.table(filename.extname("ENERGY DISPERSION"));  
435 -  
436 - // Read energy dispersion from table  
437 - read(table);  
438 -  
439 - // Close FITS file  
440 - fits.close(); 437 + // Clear object
  438 + clear();
441 439
442 // Store filename 440 // Store filename
443 m_filename = filename; 441 m_filename = filename;
@@ -521,6 +519,9 @@ GEnergy GCTAEdisp2D::mc(GRan&amp; ran, @@ -521,6 +519,9 @@ GEnergy GCTAEdisp2D::mc(GRan&amp; ran,
521 const double& zenith, 519 const double& zenith,
522 const double& azimuth) const 520 const double& azimuth) const
523 { 521 {
  522 + // Make sure that energy dispersion is online
  523 + fetch();
  524 +
524 // Get boundaries for observed energy 525 // Get boundaries for observed energy
525 GEbounds ebounds = ebounds_obs(logEsrc, theta, phi, zenith, azimuth); 526 GEbounds ebounds = ebounds_obs(logEsrc, theta, phi, zenith, azimuth);
526 double emin = ebounds.emin().log10TeV(); 527 double emin = ebounds.emin().log10TeV();
@@ -582,6 +583,9 @@ GEbounds GCTAEdisp2D::ebounds_obs(const double&amp; logEsrc, @@ -582,6 +583,9 @@ GEbounds GCTAEdisp2D::ebounds_obs(const double&amp; logEsrc,
582 const double& zenith, 583 const double& zenith,
583 const double& azimuth) const 584 const double& azimuth) const
584 { 585 {
  586 + // Make sure that energy dispersion is online
  587 + fetch();
  588 +
585 // Compute only if parameters changed 589 // Compute only if parameters changed
586 if (!m_ebounds_obs_computed || theta != m_last_theta_obs) { 590 if (!m_ebounds_obs_computed || theta != m_last_theta_obs) {
587 591
@@ -644,6 +648,9 @@ GEbounds GCTAEdisp2D::ebounds_src(const double&amp; logEobs, @@ -644,6 +648,9 @@ GEbounds GCTAEdisp2D::ebounds_src(const double&amp; logEobs,
644 const double& zenith, 648 const double& zenith,
645 const double& azimuth) const 649 const double& azimuth) const
646 { 650 {
  651 + // Make sure that energy dispersion is online
  652 + fetch();
  653 +
647 // Compute only if parameters changed 654 // Compute only if parameters changed
648 if (!m_ebounds_src_computed || theta != m_last_theta_src) { 655 if (!m_ebounds_src_computed || theta != m_last_theta_src) {
649 656
@@ -687,9 +694,101 @@ GEbounds GCTAEdisp2D::ebounds_src(const double&amp; logEobs, @@ -687,9 +694,101 @@ GEbounds GCTAEdisp2D::ebounds_src(const double&amp; logEobs,
687 694
688 695
689 /***********************************************************************//** 696 /***********************************************************************//**
  697 + * @brief Fetch energy dispersion
  698 + *
  699 + * @exception GException::file_error
  700 + * File not found.
  701 + * Unable to load energy dispersion.
  702 + * @exception GException::invalid_value
  703 + * No file name has been specified.
  704 + *
  705 + * Fetches the energy dispersion by reading it from a FITS file. This method
  706 + * does nothing if the energy dispersion is already loaded, if there is
  707 + * nothing to fetch, or if the m_filename member is empty.
  708 + *
  709 + * The method is thread save. The method checks whether the file from which
  710 + * the energy dispersion should be loaded actually exists.
  711 + ***************************************************************************/
  712 +void GCTAEdisp2D::fetch(void) const
  713 +{
  714 + // Continue only if energy dispersion has not yet been fetched
  715 + if (!m_fetched) {
  716 +
  717 + // Continue only if the file name is not empty
  718 + if (!m_filename.is_empty()) {
  719 +
  720 + // Throw an exception if the file does not exist
  721 + if (!m_filename.exists()) {
  722 + std::string msg = "File \""+m_filename+"\" not found. Cannot "
  723 + "fetch energy dispersion. Maybe the file has "
  724 + "been deleted in the meantime.";
  725 + GException::file_error(G_FETCH, msg);
  726 + }
  727 +
  728 + // Signal that energy dispersion will be fetched (has to come
  729 + // before reading since the ebounds_obs() and ebounds_src() methods
  730 + // will otherwise call the fetch() method recursively.
  731 + m_fetched = true;
  732 +
  733 + // Initialise exception flag
  734 + bool has_exception = false;
  735 +
  736 + // Load energy dispersion. Catch any exception. Put the code into
  737 + // a critical zone as it might be called from within a parallelized
  738 + // thread.
  739 + #pragma omp critical
  740 + {
  741 + try {
  742 +
  743 +
  744 + // Open FITS file
  745 + GFits fits(m_filename);
  746 +
  747 + // Initialise energy dispersion extension name
  748 + std::string extname = m_filename.extname("ENERGY DISPERSION");
  749 +
  750 + // Get energy dispersion table
  751 + const GFitsTable& table = *fits.table(extname);
  752 +
  753 + // Read energy dispersion from table
  754 + const_cast<GCTAEdisp2D*>(this)->read(table);
  755 +
  756 + // Close FITS file
  757 + fits.close();
  758 +
  759 + }
  760 + catch (...) {
  761 + has_exception = true;
  762 + }
  763 + }
  764 +
  765 + // Throw an exception if an exception has occured
  766 + if (has_exception) {
  767 + std::string msg = "Unable to load energy dispersion from "
  768 + "file \""+m_filename+"\".";
  769 + throw GException::file_error(G_FETCH, msg);
  770 + }
  771 +
  772 + } // endif: filename was not empty
  773 +
  774 + // Throw an exception if the FITS file name is not known
  775 + else {
  776 + std::string msg = "Unable to fetch energy dispersion since no "
  777 + "filename is specified.";
  778 + throw GException::invalid_value(G_FETCH, msg);
  779 + }
  780 +
  781 + } // endif: energy dispersion had not yet been fetched
  782 +
  783 + // Return
  784 + return;
  785 +}
  786 +
  787 +
  788 +/***********************************************************************//**
690 * @brief Print energy dispersion information 789 * @brief Print energy dispersion information
691 * 790 *
692 - * @param[in] chatter Chattiness (defaults to NORMAL). 791 + * @param[in] chatter Chattiness.
693 * @return String containing energy dispersion information. 792 * @return String containing energy dispersion information.
694 ***************************************************************************/ 793 ***************************************************************************/
695 std::string GCTAEdisp2D::print(const GChatter& chatter) const 794 std::string GCTAEdisp2D::print(const GChatter& chatter) const
@@ -700,6 +799,9 @@ std::string GCTAEdisp2D::print(const GChatter&amp; chatter) const @@ -700,6 +799,9 @@ std::string GCTAEdisp2D::print(const GChatter&amp; chatter) const
700 // Continue only if chatter is not silent 799 // Continue only if chatter is not silent
701 if (chatter != SILENT) { 800 if (chatter != SILENT) {
702 801
  802 + // Make sure that energy dispersion is online
  803 + fetch();
  804 +
703 // Compute energy boundaries in TeV 805 // Compute energy boundaries in TeV
704 double emin = m_edisp.axis_lo(m_inx_etrue,0); 806 double emin = m_edisp.axis_lo(m_inx_etrue,0);
705 double emax = m_edisp.axis_hi(m_inx_etrue, 807 double emax = m_edisp.axis_hi(m_inx_etrue,
@@ -754,6 +856,7 @@ void GCTAEdisp2D::init_members(void) @@ -754,6 +856,7 @@ void GCTAEdisp2D::init_members(void)
754 // Initialise members 856 // Initialise members
755 m_filename.clear(); 857 m_filename.clear();
756 m_edisp.clear(); 858 m_edisp.clear();
  859 + m_fetched = false;
757 m_inx_etrue = 0; 860 m_inx_etrue = 0;
758 m_inx_migra = 1; 861 m_inx_migra = 1;
759 m_inx_theta = 2; 862 m_inx_theta = 2;
@@ -787,6 +890,7 @@ void GCTAEdisp2D::copy_members(const GCTAEdisp2D&amp; edisp) @@ -787,6 +890,7 @@ void GCTAEdisp2D::copy_members(const GCTAEdisp2D&amp; edisp)
787 // Copy members 890 // Copy members
788 m_filename = edisp.m_filename; 891 m_filename = edisp.m_filename;
789 m_edisp = edisp.m_edisp; 892 m_edisp = edisp.m_edisp;
  893 + m_fetched = edisp.m_fetched;
790 m_inx_etrue = edisp.m_inx_etrue; 894 m_inx_etrue = edisp.m_inx_etrue;
791 m_inx_migra = edisp.m_inx_migra; 895 m_inx_migra = edisp.m_inx_migra;
792 m_inx_theta = edisp.m_inx_theta; 896 m_inx_theta = edisp.m_inx_theta;
inst/cta/src/GCTAObservation.cpp
@@ -1441,7 +1441,7 @@ std::string GCTAObservation::print(const GChatter&amp; chatter) const @@ -1441,7 +1441,7 @@ std::string GCTAObservation::print(const GChatter&amp; chatter) const
1441 if (m_events != NULL) { 1441 if (m_events != NULL) {
1442 result.append("\n"+m_events->print(reduced_chatter)); 1442 result.append("\n"+m_events->print(reduced_chatter));
1443 } 1443 }
1444 - 1444 +
1445 } // endif: appended detailed information 1445 } // endif: appended detailed information
1446 1446
1447 } // endif: chatter was not silent 1447 } // endif: chatter was not silent
inst/cta/test/dev/test_background_integration.py 0 โ†’ 100755
  1 +#! /usr/bin/env python
  2 +# ==========================================================================
  3 +# This energy integration of GCTABackground3D
  4 +#
  5 +# Copyright (C) 2017 Juergen Knoedlseder
  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 +import os
  22 +import math
  23 +import gammalib
  24 +import matplotlib.pyplot as plt
  25 +
  26 +
  27 +# ========================================= #
  28 +# Integrate using Trapezoid rule in log-log #
  29 +# ========================================= #
  30 +def integrate_trapezoid_loglog(bkg, logE1, logE2):
  31 + """
  32 + Integrate using Trapezoid rule in log-log
  33 + """
  34 + # Get function values
  35 + logf1 = math.log(bkg(logE1, 0.0, 0.0))
  36 + logf2 = math.log(bkg(logE2, 0.0, 0.0))
  37 +
  38 + # Compute ln of energy boundaries
  39 + lnE1 = logE1 * gammalib.ln10
  40 + lnE2 = logE2 * gammalib.ln10
  41 +
  42 + # Compute integral using Trapezoid rule in log-log
  43 + integral = (lnE2 - lnE1) * (math.exp(lnE1 + logf1) +
  44 + math.exp(lnE2 + logf2)) * 0.5
  45 +
  46 + # Return integral
  47 + return integral
  48 +
  49 +
  50 +# ========================================= #
  51 +# Integrate using Trapezoid rule in lin-lin #
  52 +# ========================================= #
  53 +def integrate_trapezoid_linlin(bkg, logE1, logE2):
  54 + """
  55 + Integrate using Trapezoid rule in lin-lin
  56 + """
  57 + # Set number of energy bins
  58 + nbins = 1000
  59 +
  60 + # Compute log energy bin size
  61 + dlogE = (logE2-logE1)/float(nbins-1)
  62 +
  63 + # Perform integration
  64 + integral = 0.0
  65 + for i in range(nbins-1):
  66 + logE_low = logE1 + i*dlogE
  67 + logE_high = logE_low + dlogE
  68 + dE = math.pow(10.0, logE_high) - math.pow(10.0, logE_low)
  69 + integral += dE * (bkg(logE_low, 0.0, 0.0) + bkg(logE_high, 0.0, 0.0)) * 0.5
  70 +
  71 + # Return integral
  72 + return integral
  73 +
  74 +
  75 +# =============== #
  76 +# Plot background #
  77 +# =============== #
  78 +def plot_background(bkg, emin=0.020, emax=120.0):
  79 + """
  80 + Plot background
  81 + """
  82 + # Generate energy vector
  83 + energies = gammalib.GEnergies(100, gammalib.GEnergy(emin,'TeV'),
  84 + gammalib.GEnergy(emax,'TeV'))
  85 +
  86 + # Set energy values
  87 + x = [energy.TeV() for energy in energies]
  88 + y = [bkg(energy.log10TeV(), 0.0, 0.0) for energy in energies]
  89 +
  90 + # Get node energies
  91 + i_eng = bkg.table().axis('ENERG')
  92 + e_nodes = bkg.table().axis_nodes(i_eng)
  93 + xo = [math.pow(10.0,logE) for logE in e_nodes]
  94 + yo = [bkg(logE, 0.0, 0.0) for logE in e_nodes]
  95 +
  96 + # Compute integrals
  97 + for i in range(len(xo)-1):
  98 + if yo[i] > 0 and yo[i+1] > 0:
  99 + integral_loglog = integrate_trapezoid_loglog(bkg, e_nodes[i], e_nodes[i+1])
  100 + integral_linlin = integrate_trapezoid_linlin(bkg, e_nodes[i], e_nodes[i+1])
  101 + print('%f-%f: %e %e (%f)' % (xo[i], xo[i+1], integral_loglog,
  102 + integral_linlin,
  103 + integral_loglog/integral_linlin))
  104 +
  105 + # Create figure
  106 + plt.figure(1)
  107 + plt.title('CTA Background')
  108 +
  109 + # Plot background
  110 + plt.loglog(x, y, 'r-')
  111 + plt.loglog(xo, yo, 'ro')
  112 +
  113 + # Set axes
  114 + plt.xlabel("Energy (TeV)")
  115 + plt.ylabel("Background (events/s/MeV/sr)")
  116 +
  117 + # Show plot
  118 + plt.show()
  119 +
  120 +
  121 +# ======================== #
  122 +# Main routine entry point #
  123 +# ======================== #
  124 +if __name__ == '__main__':
  125 +
  126 + # Load background
  127 + bkg = gammalib.GCTABackground3D('../../caldb/data/cta/prod2/bcf/South_50h/irf_file.fits')
  128 + print(bkg)
  129 +
  130 + # Plot background
  131 + plot_background(bkg)
src/numerics/GIntegral.cpp
@@ -385,11 +385,18 @@ double GIntegral::romberg(std::vector&lt;double&gt; bounds, const int&amp; order) @@ -385,11 +385,18 @@ double GIntegral::romberg(std::vector&lt;double&gt; bounds, const int&amp; order)
385 // Initialise integral 385 // Initialise integral
386 double value = 0.0; 386 double value = 0.0;
387 387
  388 + // Initialise integration status information
  389 + int calls = 0;
  390 +
388 // Add integral of all intervals 391 // Add integral of all intervals
389 for (int i = 0; i < bounds.size()-1; ++i) { 392 for (int i = 0; i < bounds.size()-1; ++i) {
390 value += romberg(bounds[i], bounds[i+1], order); 393 value += romberg(bounds[i], bounds[i+1], order);
  394 + calls += m_calls;
391 } 395 }
392 396
  397 + // Set integration status information
  398 + m_calls = calls;
  399 +
393 // Return value 400 // Return value
394 return value; 401 return value;
395 } 402 }
src/obs/GObservation.cpp
@@ -352,17 +352,17 @@ double GObservation::model(const GModels&amp; models, @@ -352,17 +352,17 @@ double GObservation::model(const GModels&amp; models,
352 * 352 *
353 * @returns Total number of observed events. 353 * @returns Total number of observed events.
354 * 354 *
355 - * Returns the total number of observed events. 355 + * Returns the total number of observed events. If the observation does not
  356 + * contain any events the method returns zero.
356 ***************************************************************************/ 357 ***************************************************************************/
357 int GObservation::nobserved(void) const 358 int GObservation::nobserved(void) const
358 { 359 {
359 // Initialise number of observed events 360 // Initialise number of observed events
360 int nobserved = 0; 361 int nobserved = 0;
361 362
362 - // Extract number of observed events from event contained  
363 - const GEvents* events = this->events();  
364 - if (events != NULL) {  
365 - nobserved = events->number(); 363 + // Extract number of observed events
  364 + if (m_events != NULL) {
  365 + nobserved = m_events->number();
366 } 366 }
367 367
368 // Return number of observed events 368 // Return number of observed events