Commit 3a334a8c1ad43a639fd3602be4d3d18195e29094
Merge branch 'issue_1014_gradients' into integration
Showing
2 changed files
with
115 additions
and
11 deletions
include/GModelSpectralGauss.hpp
| @@ -96,7 +96,7 @@ public: | @@ -96,7 +96,7 @@ public: | ||
| 96 | void mean(const GEnergy& mean); | 96 | void mean(const GEnergy& mean); |
| 97 | GEnergy sigma(void) const; | 97 | GEnergy sigma(void) const; |
| 98 | void sigma(const GEnergy& sigma); | 98 | void sigma(const GEnergy& sigma); |
| 99 | - | 99 | + void update_eval_cache(const GEnergy& energy) const; |
| 100 | 100 | ||
| 101 | 101 | ||
| 102 | protected: | 102 | protected: |
| @@ -104,6 +104,7 @@ protected: | @@ -104,6 +104,7 @@ protected: | ||
| 104 | void init_members(void); | 104 | void init_members(void); |
| 105 | void copy_members(const GModelSpectralGauss& model); | 105 | void copy_members(const GModelSpectralGauss& model); |
| 106 | void free_members(void); | 106 | void free_members(void); |
| 107 | + void update_eval_cache(const GEnergy& energy) const; | ||
| 107 | 108 | ||
| 108 | // Energy flux integration kernel | 109 | // Energy flux integration kernel |
| 109 | class eflux_kernel : public GFunction { | 110 | class eflux_kernel : public GFunction { |
| @@ -125,6 +126,10 @@ protected: | @@ -125,6 +126,10 @@ protected: | ||
| 125 | GModelPar m_norm; //!< Normalization factor | 126 | GModelPar m_norm; //!< Normalization factor |
| 126 | GModelPar m_mean; //!< Gaussian mean energy | 127 | GModelPar m_mean; //!< Gaussian mean energy |
| 127 | GModelPar m_sigma; //!< Gaussian energy width | 128 | GModelPar m_sigma; //!< Gaussian energy width |
| 129 | + | ||
| 130 | + mutable double m_last_norm; //!< Last Normalization value | ||
| 131 | + mutable double m_last_mean; //!< Last Mean value | ||
| 132 | + mutable double m_last_sigma; //!< Last Sigma value | ||
| 128 | }; | 133 | }; |
| 129 | 134 | ||
| 130 | 135 | ||
| @@ -218,4 +223,5 @@ void GModelSpectralGauss::sigma(const GEnergy& sigma) | @@ -218,4 +223,5 @@ void GModelSpectralGauss::sigma(const GEnergy& sigma) | ||
| 218 | return; | 223 | return; |
| 219 | } | 224 | } |
| 220 | 225 | ||
| 226 | + | ||
| 221 | #endif /* GMODELSPECTRALGAUSS_HPP */ | 227 | #endif /* GMODELSPECTRALGAUSS_HPP */ |
src/model/GModelSpectralGauss.cpp
| @@ -240,8 +240,7 @@ GModelSpectralGauss* GModelSpectralGauss::clone(void) const | @@ -240,8 +240,7 @@ GModelSpectralGauss* GModelSpectralGauss::clone(void) const | ||
| 240 | * Evaluates | 240 | * Evaluates |
| 241 | * | 241 | * |
| 242 | * \f[ | 242 | * \f[ |
| 243 | - * \frac{dN}{dE} = \frac{\norm}{\sqrt{2\pi}\sigma} | ||
| 244 | - * \exp(\frac{(E-\bar{E})^2}{2\sigma^2}) | 243 | + * \frac{dN}{dE}=\frac{\norm}{\sqrt{2\pi}\sigma}\exp(\frac{-(E-\bar{E})^2}{2\sigma^2}) |
| 245 | * \f] | 244 | * \f] |
| 246 | ***************************************************************************/ | 245 | ***************************************************************************/ |
| 247 | double GModelSpectralGauss::eval(const GEnergy& srcEng, | 246 | double GModelSpectralGauss::eval(const GEnergy& srcEng, |
| @@ -271,12 +270,62 @@ double GModelSpectralGauss::eval(const GEnergy& srcEng, | @@ -271,12 +270,62 @@ double GModelSpectralGauss::eval(const GEnergy& srcEng, | ||
| 271 | * | 270 | * |
| 272 | * This method simply calls the eval() method as no analytical gradients will | 271 | * This method simply calls the eval() method as no analytical gradients will |
| 273 | * be computed. See the eval() method for details. | 272 | * be computed. See the eval() method for details. |
| 273 | + * | ||
| 274 | + * TODO: update docstring. | ||
| 274 | ***************************************************************************/ | 275 | ***************************************************************************/ |
| 275 | double GModelSpectralGauss::eval_gradients(const GEnergy& srcEng, | 276 | double GModelSpectralGauss::eval_gradients(const GEnergy& srcEng, |
| 276 | const GTime& srcTime) | 277 | const GTime& srcTime) |
| 277 | { | 278 | { |
| 278 | - // Return | ||
| 279 | - return eval(srcEng, srcTime); | 279 | + double energy = srcEng.MeV(); |
| 280 | + double norm = m_norm.value(); | ||
| 281 | + double mean = m_mean.value(); | ||
| 282 | + double sigma = m_sigma.value(); | ||
| 283 | + | ||
| 284 | + // Update the evaluation cache | ||
| 285 | + update_eval_cache(srcEng); | ||
| 286 | + | ||
| 287 | + // Compute function terms | ||
| 288 | + double term1 = (norm / sigma) * gammalib::inv_sqrt2pi; | ||
| 289 | + double term2 = (1 / sigma) * gammalib::inv_sqrt2pi; | ||
| 290 | + double term3 = (energy - mean) * (energy - mean) / (2 * sigma * sigma); | ||
| 291 | + double term4 = (energy - mean) / (sigma * sigma); | ||
| 292 | + double term5 = (norm / (sigma * sigma)) * gammalib::inv_sqrt2pi; | ||
| 293 | + | ||
| 294 | + // Compute function value | ||
| 295 | + double value = term1 * std::exp(- term3); | ||
| 296 | + | ||
| 297 | + | ||
| 298 | + // Compute partial derivatives with respect to the parameter factor | ||
| 299 | + // values (partial differentials were determined analytically). | ||
| 300 | + | ||
| 301 | + double g_norm = term2 * std::exp(- term3); | ||
| 302 | + double g_mean = term1 * term4 * std::exp(- term3); | ||
| 303 | + double g_sigma = - term5 * std::exp(- term3) * (1 - (2 * term3)); | ||
| 304 | + | ||
| 305 | + // Set gradients | ||
| 306 | + m_norm.factor_gradient(g_norm); | ||
| 307 | + m_mean.factor_gradient(g_mean); | ||
| 308 | + m_sigma.factor_gradient(g_sigma); | ||
| 309 | + | ||
| 310 | + // Compile option: Check for NaN/Inf | ||
| 311 | + #if defined(G_NAN_CHECK) | ||
| 312 | + if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) { | ||
| 313 | + std::cout << "*** ERROR: GModelSpectralGauss::eval_gradients"; | ||
| 314 | + std::cout << "(srcEng=" << srcEng; | ||
| 315 | + std::cout << ", srcTime=" << srcTime << "):"; | ||
| 316 | + std::cout << " NaN/Inf encountered"; | ||
| 317 | + std::cout << " (value=" << value; | ||
| 318 | + std::cout << ", norm=" << m_last_norm; | ||
| 319 | + std::cout << ", mean=" << m_last_mean; | ||
| 320 | + std::cout << ", Sigma=" << m_last_sigma; | ||
| 321 | + std::cout << ")" << std::endl; | ||
| 322 | + } | ||
| 323 | + #endif | ||
| 324 | + | ||
| 325 | + // Return | ||
| 326 | + return value; | ||
| 327 | + } | ||
| 328 | + | ||
| 280 | } | 329 | } |
| 281 | 330 | ||
| 282 | 331 | ||
| @@ -298,6 +347,7 @@ double GModelSpectralGauss::eval_gradients(const GEnergy& srcEng, | @@ -298,6 +347,7 @@ double GModelSpectralGauss::eval_gradients(const GEnergy& srcEng, | ||
| 298 | * - \f$S_{\rm E}(E | t)\f$ is the spectral model (ph/cm2/s/MeV). | 347 | * - \f$S_{\rm E}(E | t)\f$ is the spectral model (ph/cm2/s/MeV). |
| 299 | * The integration is done analytically. | 348 | * The integration is done analytically. |
| 300 | ***************************************************************************/ | 349 | ***************************************************************************/ |
| 350 | + | ||
| 301 | double GModelSpectralGauss::flux(const GEnergy& emin, | 351 | double GModelSpectralGauss::flux(const GEnergy& emin, |
| 302 | const GEnergy& emax) const | 352 | const GEnergy& emax) const |
| 303 | { | 353 | { |
| @@ -412,15 +462,14 @@ GEnergy GModelSpectralGauss::mc(const GEnergy& emin, | @@ -412,15 +462,14 @@ GEnergy GModelSpectralGauss::mc(const GEnergy& emin, | ||
| 412 | } | 462 | } |
| 413 | 463 | ||
| 414 | // Get uniform value between 0 and 1 | 464 | // Get uniform value between 0 and 1 |
| 415 | - double u = ran.uniform(); | ||
| 416 | 465 | ||
| 417 | // Do ... | 466 | // Do ... |
| 418 | do { | 467 | do { |
| 419 | double x1; | 468 | double x1; |
| 420 | double w; | 469 | double w; |
| 421 | do{ | 470 | do{ |
| 422 | - x1 = 2.0 * u - 1.0; | ||
| 423 | - double x2 = 2.0 * u - 1.0; | 471 | + x1 = 2.0 * ran.uniform() - 1.0; |
| 472 | + double x2 = 2.0 * ran.uniform() - 1.0; | ||
| 424 | w = x1 * x1 + x2 * x2; | 473 | w = x1 * x1 + x2 * x2; |
| 425 | } while (w >= 1.0); | 474 | } while (w >= 1.0); |
| 426 | 475 | ||
| @@ -431,7 +480,7 @@ GEnergy GModelSpectralGauss::mc(const GEnergy& emin, | @@ -431,7 +480,7 @@ GEnergy GModelSpectralGauss::mc(const GEnergy& emin, | ||
| 431 | double val = x1 * w; | 480 | double val = x1 * w; |
| 432 | 481 | ||
| 433 | // Map into [emin,emax] range | 482 | // Map into [emin,emax] range |
| 434 | - energy = (xmax - xmin) * val + xmin; | 483 | + energy = m_sigma.value() * val + m_mean.value(); |
| 435 | 484 | ||
| 436 | } while ((xmin <= energy) && (energy < xmax)); | 485 | } while ((xmin <= energy) && (energy < xmax)); |
| 437 | 486 | ||
| @@ -439,7 +488,6 @@ GEnergy GModelSpectralGauss::mc(const GEnergy& emin, | @@ -439,7 +488,6 @@ GEnergy GModelSpectralGauss::mc(const GEnergy& emin, | ||
| 439 | return GEnergy(energy, "MeV"); | 488 | return GEnergy(energy, "MeV"); |
| 440 | } | 489 | } |
| 441 | 490 | ||
| 442 | - | ||
| 443 | /***********************************************************************//** | 491 | /***********************************************************************//** |
| 444 | * @brief Read model from XML element | 492 | * @brief Read model from XML element |
| 445 | * | 493 | * |
| @@ -509,7 +557,6 @@ void GModelSpectralGauss::read(const GXmlElement& xml) | @@ -509,7 +557,6 @@ void GModelSpectralGauss::read(const GXmlElement& xml) | ||
| 509 | return; | 557 | return; |
| 510 | } | 558 | } |
| 511 | 559 | ||
| 512 | - | ||
| 513 | /***********************************************************************//** | 560 | /***********************************************************************//** |
| 514 | * @brief Write model into XML element | 561 | * @brief Write model into XML element |
| 515 | * | 562 | * |
| @@ -672,6 +719,11 @@ void GModelSpectralGauss::init_members(void) | @@ -672,6 +719,11 @@ void GModelSpectralGauss::init_members(void) | ||
| 672 | m_sigma.gradient(0.0); | 719 | m_sigma.gradient(0.0); |
| 673 | m_sigma.has_grad(false); | 720 | m_sigma.has_grad(false); |
| 674 | 721 | ||
| 722 | + // Initialise eval cache | ||
| 723 | + m_last_norm = 0.0; | ||
| 724 | + m_last_mean = 0.0; | ||
| 725 | + m_last_sigma = 0.0; | ||
| 726 | + | ||
| 675 | // Set parameter pointer(s) | 727 | // Set parameter pointer(s) |
| 676 | m_pars.clear(); | 728 | m_pars.clear(); |
| 677 | m_pars.push_back(&m_norm); | 729 | m_pars.push_back(&m_norm); |
| @@ -701,6 +753,11 @@ void GModelSpectralGauss::copy_members(const GModelSpectralGauss& model) | @@ -701,6 +753,11 @@ void GModelSpectralGauss::copy_members(const GModelSpectralGauss& model) | ||
| 701 | m_pars.push_back(&m_mean); | 753 | m_pars.push_back(&m_mean); |
| 702 | m_pars.push_back(&m_sigma); | 754 | m_pars.push_back(&m_sigma); |
| 703 | 755 | ||
| 756 | + // Copy eval cache | ||
| 757 | + m_last_norm = model.m_last_norm; | ||
| 758 | + m_last_mean = model.m_last_mean; | ||
| 759 | + m_last_sigma = model.m_last_sigma; | ||
| 760 | + | ||
| 704 | // Return | 761 | // Return |
| 705 | return; | 762 | return; |
| 706 | } | 763 | } |
| @@ -730,3 +787,44 @@ double GModelSpectralGauss::eflux_kernel::eval(const double& energy) | @@ -730,3 +787,44 @@ double GModelSpectralGauss::eflux_kernel::eval(const double& energy) | ||
| 730 | // Return value | 787 | // Return value |
| 731 | return value; | 788 | return value; |
| 732 | } | 789 | } |
| 790 | + | ||
| 791 | +/***********************************************************************//** | ||
| 792 | + * @brief Update eval precomputation cache | ||
| 793 | + * | ||
| 794 | + * @param[in] energy Energy. | ||
| 795 | + * | ||
| 796 | + * Updates the precomputation cache for eval() and eval_gradients() methods. | ||
| 797 | + * | ||
| 798 | + ***************************************************************************/ | ||
| 799 | +void GModelSpectralGauss::update_eval_cache(const GEnergy& energy) const | ||
| 800 | +{ | ||
| 801 | + // Get parameter values (takes 3 multiplications which are difficult | ||
| 802 | + // to avoid) | ||
| 803 | + double norm = m_norm.value(); | ||
| 804 | + double mean = m_mean.value(); | ||
| 805 | + double sigma = m_sigma.value(); | ||
| 806 | + | ||
| 807 | + // If the energy or one of the parameters norm, mean or sigma | ||
| 808 | + // energy has changed then recompute the cache | ||
| 809 | + if ((m_last_norm != norm) || | ||
| 810 | + (m_last_mean != mean) || | ||
| 811 | + (m_last_sigma != sigma)) { | ||
| 812 | + | ||
| 813 | + // Store actual energy and parameter values | ||
| 814 | + m_last_norm = norm; | ||
| 815 | + m_last_mean = mean; | ||
| 816 | + m_last_sigma = sigma; | ||
| 817 | + | ||
| 818 | + // Compute and store value | ||
| 819 | + double eng = energy.MeV(); | ||
| 820 | + m_last_norm = eng / m_last_norm; | ||
| 821 | + m_last_mean = eng / m_last_mean; | ||
| 822 | + m_last_sigma = eng/ m_last_sigma; | ||
| 823 | + | ||
| 824 | + } // endif: recomputation was required | ||
| 825 | + | ||
| 826 | + // Return | ||
| 827 | + return; | ||
| 828 | +} | ||
| 829 | + | ||
| 830 | + |