/***********************************************************************//**
 * @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;
}
Beispiel #3
0
/***********************************************************************//**
 * @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;
}