/***********************************************************************//** * @brief Evaluate function * * @param[in] srcEng True photon energy. * @param[in] srcTime True photon arrival time. * @return Model value. * * Evaluates * * \f[ * S_{\rm E}(E | t) = {\tt m\_norm} * \left( \frac{E}{\tt m\_pivot} \right)^{\tt m\_index} * \exp \left( \frac{-E}{\tt m\_ecut} \right) * \f] * * where * - \f${\tt m\_norm}\f$ is the normalization or prefactor, * - \f${\tt m\_pivot}\f$ is the pivot energy, * - \f${\tt m\_index}\f$ is the spectral index, and * - \f${\tt m\_ecut}\f$ is the cut off energy. * * @todo The method expects that pivot!=0 and ecut!=0. Otherwise Inf or NaN * may result. We should add a test that prevents using invalid * values. ***************************************************************************/ double GModelSpectralExpPlaw::eval(const GEnergy& srcEng, const GTime& srcTime) const { // Update the evaluation cache update_eval_cache(srcEng); // Compute function value double value = m_norm.value() * m_last_power; // Compile option: Check for NaN/Inf #if defined(G_NAN_CHECK) if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) { std::cout << "*** ERROR: GModelSpectralExpPlaw::eval"; std::cout << "(srcEng=" << srcEng; std::cout << ", srcTime=" << srcTime << "):"; std::cout << " NaN/Inf encountered"; std::cout << " (value=" << value; std::cout << ", power=" << m_last_power; std::cout << ")" << std::endl; } #endif // Return return value; }
/***********************************************************************//** * @brief Evaluate function and gradients * * @param[in] srcEng True photon energy. * @param[in] srcTime True photon arrival time. * @return Model value. * * Evaluates * * \f[ * S_{\rm E}(E | t) = {\tt m\_norm} * \left( \frac{E}{\tt m\_pivot} \right)^{\tt m\_index} * \exp \left( \frac{-E}{\tt m\_ecut} \right) * \f] * * where * - \f${\tt m\_norm}\f$ is the normalization or prefactor, * - \f${\tt m\_index}\f$ is the spectral index, * - \f${\tt m\_ecut}\f$ is the cut off energy, and * - \f${\tt m\_pivot}\f$ is the pivot energy. * * The method also evaluates the partial derivatives of the model with * respect to the parameters using * * \f[ * \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_norm}} = * \frac{S_{\rm E}(E | t)}{{\tt m\_norm}} * \f] * * \f[ * \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_index}} = * S_{\rm E}(E | t) \, \ln(E/{\tt m_pivot}) * \f] * * \f[ * \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_ecut}} = * S_{\rm E}(E | t) \, \left( \frac{E}{{\tt m\_ecut}^2} \right) * \f] * * \f[ * \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_pivot}} = * -S_{\rm E}(E | t) \, * \left( \frac{{\tt m\_index}}{{\tt m\_pivot}} \right) * \f] * * @todo The method expects that pivot!=0 and ecut!=0. Otherwise Inf or NaN * may result. We should add a test that prevents using invalid * values. ***************************************************************************/ double GModelSpectralExpPlaw::eval_gradients(const GEnergy& srcEng, const GTime& srcTime) { // Update the evaluation cache update_eval_cache(srcEng); // Compute function value double value = m_norm.value() * m_last_power; // Compute partial derivatives with respect to the parameter factor // values. The partial derivatives with respect to the parameter // values are obtained by division by the scale factor. double g_norm = (m_norm.is_free()) ? m_norm.scale() * m_last_power : 0.0; double g_index = (m_index.is_free()) ? value * m_index.scale() * std::log(m_last_e_norm) : 0.0; double g_ecut = (m_ecut.is_free()) ? value * m_last_e_cut / m_ecut.factor_value() : 0.0; double g_pivot = (m_pivot.is_free()) ? -value * m_last_index / m_pivot.factor_value() : 0.0; // Set gradients m_norm.factor_gradient(g_norm); m_index.factor_gradient(g_index); m_ecut.factor_gradient(g_ecut); m_pivot.factor_gradient(g_pivot); // Compile option: Check for NaN/Inf #if defined(G_NAN_CHECK) if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) { std::cout << "*** ERROR: GModelSpectralExpPlaw::eval_gradients"; std::cout << "(srcEng=" << srcEng; std::cout << ", srcTime=" << srcTime << "):"; std::cout << " NaN/Inf encountered"; std::cout << " (value=" << value; std::cout << ", e_norm=" << m_last_e_norm; std::cout << ", e_cut=" << m_last_e_cut; std::cout << ", power=" << m_last_power; std::cout << ")" << std::endl; } #endif // Return return value; }
/***********************************************************************//** * @brief Evaluate function * * @param[in] srcEng True photon energy. * @param[in] srcTime True photon arrival time. * @param[in] gradients Compute gradients? * @return Model value (ph/cm2/s/MeV). * * Evaluates * * \f[ * S_{\rm E}(E | t) = k_0 \left( \frac{E}{E_0} \right)^{\gamma_1} * \left[ 1 + \left( \frac{E}{E_b} \right)^{\frac{\gamma_1 - \gamma_2}{\beta}} * \right]^{-\beta} * \f] * * where: * - \f$k_0\f$ is the normalization or prefactor, * - \f$\gamma_1\f$ is the spectral index before the break, * - \f$\gamma_2\f$ is the spectral index after the break, * - \f$E_0\f$ is the pivot energy, * - \f$E_b\f$ is the break energy, * - \f$\beta\f$ is the break smoothness. * * If the @p gradients flag is true the method will also compute the * partial derivatives of the model with respect to the parameters using * * \f[ * \frac{\delta S_{\rm E}(E | t)}{\delta k_0} = * \frac{S_{\rm E}(E | t)}{k_0} * \f] * * \f[ * \frac{\delta S_{\rm E}(E | t)}{\delta \gamma_1} = * S_{\rm E}(E | t) \left[ \ln\left( \frac{E}{E_0} \right) - * \frac{\left(\frac{E}{E_b}\right)^{\frac{\gamma_1 - \gamma_2}{\beta}} * \ln\left( \frac{E}{E_b} \right)} * {\left(\frac{E}{E_b}\right)^{\frac{\gamma_1 - \gamma_2}{\beta}} + 1}\right] * \f] * * \f[ * \frac{\delta S_{\rm E}(E | t)}{\delta \gamma_2} = * S_{\rm E}(E | t) * \frac{\left(\frac{E}{E_b}\right)^{\frac{\gamma_1 - \gamma_2}{\beta}} * \ln\left( \frac{E}{E_b} \right)} * {\left(\frac{E}{E_b}\right)^{\frac{\gamma_1 - \gamma_2}{\beta}} + 1} * \f] * * \f[ * \frac{\delta S_{\rm E}(E | t)}{\delta E_0} = * S_{\rm E}(E | t) \frac{\gamma_1}{E_0} * \f] * * \f[ * \frac{\delta S_{\rm E}(E | t)}{\delta E_b} = * S_{\rm E}(E | t) \frac{\left(\gamma_1 - \gamma_2 \right) * \left( \frac{E}{E_b} \right)^{\frac{\gamma_1 - \gamma_2}{\beta}}} {E_b \left(1 + \left(\frac{E}{E_b}\right)^{\frac{\gamma_1 - \gamma_2}{\beta}} \right)} * \f] * * \f[ * \frac{\delta S_{\rm E}(E | t)}{\delta \beta} = S_{\rm E}(E | t) * \left[ * \frac{ \left( \frac{E}{E_b} \right)^{\frac{\gamma_1 - \gamma_2}{\beta}} * \ln \left( \left( \frac{E}{E_b}\right)^{ \frac{\gamma_1 - \gamma_2}{\beta}} \right)} * {1 + \left(\frac{E}{E_b}\right)^{\frac{\gamma_1 - \gamma_2}{\beta}}} * - \ln \left( 1 + \left(\frac{E}{E_b}\right)^{\frac{\gamma_1 - \gamma_2}{\beta}} \right) * \right] * \f] * * @todo The method expects that energy!=0. Otherwise Inf or NaN may result. ***************************************************************************/ double GModelSpectralSmoothBrokenPlaw::eval(const GEnergy& srcEng, const GTime& srcTime, const bool& gradients) const { // Update the evaluation cache update_eval_cache(srcEng); // Compute function value double value = m_norm.value() * m_last_epivot_pow * std::pow(1.0 + m_last_ebreak_pow, -m_last_beta); // Optionally compute gradients if (gradients) { // Compute normalisation gradient double g_norm = (m_norm.is_free()) ? m_norm.scale() * m_last_epivot_pow * std::pow(1.0 + m_last_ebreak_pow, -m_last_beta) : 0.0; // Compute index1 and index2 value gradients double g_index1 = (m_index1.is_free()) ? value * m_index1.scale() * (m_last_log_epivot_norm - ((m_last_ebreak_pow * m_last_log_ebreak_norm) / (m_last_ebreak_pow + 1.0))) : 0.0; double g_index2 = (m_index2.is_free()) ? value * m_index2.scale() * m_last_log_ebreak_norm * m_last_ebreak_pow / (1.0 + m_last_ebreak_pow) : 0.0; // Compute pivot and break energy value gradients double g_pivot = (m_pivot.is_free()) ? -value * m_last_index1 / m_pivot.factor_value() : 0.0; double g_break = (m_breakenergy.is_free()) ? value * (m_last_index1-m_last_index2) * m_last_ebreak_pow / ((1.0+m_last_ebreak_pow) * m_breakenergy.factor_value()) : 0.0; // Compute beta gradient double g_beta = (m_beta.is_free()) ? value * m_beta.scale() * ((std::log(m_last_ebreak_pow) * m_last_ebreak_pow) / (1.0+m_last_ebreak_pow) - std::log(1.0+m_last_ebreak_pow)) : 0.0; // Store the gradient values m_norm.factor_gradient(g_norm); m_index1.factor_gradient(g_index1); m_index2.factor_gradient(g_index2); m_pivot.factor_gradient(g_pivot); m_breakenergy.factor_gradient(g_break); m_beta.factor_gradient(g_beta); } // endif: gradient computation was requested // Compile option: Check for NaN/Inf #if defined(G_NAN_CHECK) if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) { std::cout << "*** ERROR: GModelSpectralSmoothBrokenPlaw::eval"; std::cout << "(srcEng=" << srcEng; std::cout << ", srcTime=" << srcTime << "):"; std::cout << " NaN/Inf encountered"; std::cout << " (value=" << value; std::cout << ", m_norm=" << m_norm.value(); std::cout << ", m_index1=" << m_index1.value(); std::cout << ", m_index2=" << m_index2.value(); std::cout << ", m_pivot=" << m_pivot.value(); std::cout << ", m_breakenergy=" << m_breakenergy.value(); std::cout << ", m_beta=" << m_beta.value(); std::cout << ", m_last_epivot_norm=" << m_last_epivot_norm; std::cout << ", m_last_ebreak_norm=" << m_last_ebreak_norm; std::cout << ", m_last_log_epivot_norm=" << m_last_log_epivot_norm; std::cout << ", m_last_log_ebreak_norm=" << m_last_log_ebreak_norm; std::cout << ", m_last_epivot_pow=" << m_last_epivot_pow; std::cout << ", m_last_ebreak_pow=" << m_last_ebreak_pow; std::cout << ")" << std::endl; } #endif // Return return value; }