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 | 96 | void mean(const GEnergy& mean); |
| 97 | 97 | GEnergy sigma(void) const; |
| 98 | 98 | void sigma(const GEnergy& sigma); |
| 99 | - | |
| 99 | + void update_eval_cache(const GEnergy& energy) const; | |
| 100 | 100 | |
| 101 | 101 | |
| 102 | 102 | protected: |
| ... | ... | @@ -104,6 +104,7 @@ protected: |
| 104 | 104 | void init_members(void); |
| 105 | 105 | void copy_members(const GModelSpectralGauss& model); |
| 106 | 106 | void free_members(void); |
| 107 | + void update_eval_cache(const GEnergy& energy) const; | |
| 107 | 108 | |
| 108 | 109 | // Energy flux integration kernel |
| 109 | 110 | class eflux_kernel : public GFunction { |
| ... | ... | @@ -125,6 +126,10 @@ protected: |
| 125 | 126 | GModelPar m_norm; //!< Normalization factor |
| 126 | 127 | GModelPar m_mean; //!< Gaussian mean energy |
| 127 | 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 | 223 | return; |
| 219 | 224 | } |
| 220 | 225 | |
| 226 | + | |
| 221 | 227 | #endif /* GMODELSPECTRALGAUSS_HPP */ | ... | ... |
src/model/GModelSpectralGauss.cpp
| ... | ... | @@ -240,8 +240,7 @@ GModelSpectralGauss* GModelSpectralGauss::clone(void) const |
| 240 | 240 | * Evaluates |
| 241 | 241 | * |
| 242 | 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 | 244 | * \f] |
| 246 | 245 | ***************************************************************************/ |
| 247 | 246 | double GModelSpectralGauss::eval(const GEnergy& srcEng, |
| ... | ... | @@ -271,12 +270,62 @@ double GModelSpectralGauss::eval(const GEnergy& srcEng, |
| 271 | 270 | * |
| 272 | 271 | * This method simply calls the eval() method as no analytical gradients will |
| 273 | 272 | * be computed. See the eval() method for details. |
| 273 | + * | |
| 274 | + * TODO: update docstring. | |
| 274 | 275 | ***************************************************************************/ |
| 275 | 276 | double GModelSpectralGauss::eval_gradients(const GEnergy& srcEng, |
| 276 | 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 | 347 | * - \f$S_{\rm E}(E | t)\f$ is the spectral model (ph/cm2/s/MeV). |
| 299 | 348 | * The integration is done analytically. |
| 300 | 349 | ***************************************************************************/ |
| 350 | + | |
| 301 | 351 | double GModelSpectralGauss::flux(const GEnergy& emin, |
| 302 | 352 | const GEnergy& emax) const |
| 303 | 353 | { |
| ... | ... | @@ -412,15 +462,14 @@ GEnergy GModelSpectralGauss::mc(const GEnergy& emin, |
| 412 | 462 | } |
| 413 | 463 | |
| 414 | 464 | // Get uniform value between 0 and 1 |
| 415 | - double u = ran.uniform(); | |
| 416 | 465 | |
| 417 | 466 | // Do ... |
| 418 | 467 | do { |
| 419 | 468 | double x1; |
| 420 | 469 | double w; |
| 421 | 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 | 473 | w = x1 * x1 + x2 * x2; |
| 425 | 474 | } while (w >= 1.0); |
| 426 | 475 | |
| ... | ... | @@ -431,7 +480,7 @@ GEnergy GModelSpectralGauss::mc(const GEnergy& emin, |
| 431 | 480 | double val = x1 * w; |
| 432 | 481 | |
| 433 | 482 | // Map into [emin,emax] range |
| 434 | - energy = (xmax - xmin) * val + xmin; | |
| 483 | + energy = m_sigma.value() * val + m_mean.value(); | |
| 435 | 484 | |
| 436 | 485 | } while ((xmin <= energy) && (energy < xmax)); |
| 437 | 486 | |
| ... | ... | @@ -439,7 +488,6 @@ GEnergy GModelSpectralGauss::mc(const GEnergy& emin, |
| 439 | 488 | return GEnergy(energy, "MeV"); |
| 440 | 489 | } |
| 441 | 490 | |
| 442 | - | |
| 443 | 491 | /***********************************************************************//** |
| 444 | 492 | * @brief Read model from XML element |
| 445 | 493 | * |
| ... | ... | @@ -509,7 +557,6 @@ void GModelSpectralGauss::read(const GXmlElement& xml) |
| 509 | 557 | return; |
| 510 | 558 | } |
| 511 | 559 | |
| 512 | - | |
| 513 | 560 | /***********************************************************************//** |
| 514 | 561 | * @brief Write model into XML element |
| 515 | 562 | * |
| ... | ... | @@ -672,6 +719,11 @@ void GModelSpectralGauss::init_members(void) |
| 672 | 719 | m_sigma.gradient(0.0); |
| 673 | 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 | 727 | // Set parameter pointer(s) |
| 676 | 728 | m_pars.clear(); |
| 677 | 729 | m_pars.push_back(&m_norm); |
| ... | ... | @@ -701,6 +753,11 @@ void GModelSpectralGauss::copy_members(const GModelSpectralGauss& model) |
| 701 | 753 | m_pars.push_back(&m_mean); |
| 702 | 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 | 761 | // Return |
| 705 | 762 | return; |
| 706 | 763 | } |
| ... | ... | @@ -730,3 +787,44 @@ double GModelSpectralGauss::eflux_kernel::eval(const double& energy) |
| 730 | 787 | // Return value |
| 731 | 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 | + | ... | ... |