Ejemplo n.º 1
0
/***********************************************************************//**
 * @brief Returns MC energy between [emin, emax]
 *
 * @param[in] emin Minimum photon energy.
 * @param[in] emax Maximum photon energy.
 * @param[in] time True photon arrival time.
 * @param[in,out] ran Random number generator.
 * @return Energy.
 *
 * @exception GException::erange_invalid
 *            Energy range is invalid (emin < emax required).
 *
 * Returns Monte Carlo energy by randomly drawing from a constant between
 * the minimum and maximum photon energy.
 *
 * Method Used: Box-Muller transform, outlined here:
 * http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
 *
 * Code from: http://www.design.caltech.edu/erik/Misc/Gaussian.html
 ***************************************************************************/
GEnergy GModelSpectralGauss::mc(const GEnergy& emin,
                                const GEnergy& emax,
                                const GTime&   time,
                                GRan&          ran) const
{
    // Get energy boundaries in MeV
	double xmax = emax.MeV();
	double xmin = emin.MeV();

    // Initialize return energy
	double energy = 0.0;

    // Throw an exception if energy range is invalid
    if (xmin >= xmax) {
        throw GException::erange_invalid(G_MC, xmin, xmax,
              "Minimum energy < maximum energy required.");
    }

    // Sample until we find a value within the requested energy range
    do {

        // Compute random value
    	double val = ran.normal();

    	// Scale to specified width and shift by mean value
    	energy = m_sigma.value() * val + m_mean.value();

    } while (energy < xmin || energy > xmax);


    // Return energy
    return GEnergy(energy, "MeV");
}
Ejemplo n.º 2
0
/***********************************************************************//**
 * @brief Returns model energy flux between [emin, emax] (units: erg/cm2/s)
 *
 * @param[in] emin Minimum photon energy.
 * @param[in] emax Maximum photon energy.
 * @return Energy flux (erg/cm2/s).
 *
 * Computes
 *
 * \f[
 *    \int_{\tt emin}^{\tt emax} S_{\rm E}(E | t) E \, dE
 * \f]
 *
 * where
 * - [@p emin, @p emax] is an energy interval, and
 * - \f$S_{\rm E}(E | t)\f$ is the spectral model (ph/cm2/s/MeV).
 * The integration is done numerically.
 ***************************************************************************/
double GModelSpectralExpPlaw::eflux(const GEnergy& emin,
                                    const GEnergy& emax) const
{
    // Initialise flux
    double eflux = 0.0;
    
    // Compute only if integration range is valid
    if (emin < emax) {

        // Setup integration kernel
        eflux_kernel integrand(m_norm.value(),  m_index.value(),
                               m_pivot.value(), m_ecut.value());
        GIntegral integral(&integrand);

        // Get integration boundaries in MeV
        double e_min = emin.MeV();
        double e_max = emax.MeV();

        // Perform integration
        eflux = integral.romberg(e_min, e_max);

        // Convert from MeV/cm2/s to erg/cm2/s
        eflux *= gammalib::MeV2erg;

    } // endif: integration range was valid

    // Return
    return eflux;
}
Ejemplo n.º 3
0
/***********************************************************************//**
 * @brief Convert value into flux
 *
 * @param[in] energy Energy at which flux is given.
 * @param[in] flux Flux value.
 * @param[in] unit Unit of value.
 *
 * @exception GMWLException::invalid_unit
 *            Invalid unit string encountered
 *
 * Converts a flux value into units of ph/cm2/s/MeV based on the specified
 * units. The following units are supported (case insensitive):
 * ph/cm2/s/MeV, ph/s/cm2/MeV, erg/cm2/s and erg/s/cm2.
 ***************************************************************************/
double GMWLSpectrum::conv_flux(const GEnergy& energy, const double& flux,
                               const std::string& unit)
{
    // Initialise energy
    double result;

    // Convert unit string to upper base without any leading/trailing
    // whitespace
    std::string str_unit = gammalib::strip_whitespace(gammalib::toupper(unit));

    // High-energy units
    if (str_unit == "PH/CM2/S/MEV" || str_unit == "PH/S/CM2/MEV") {
        result = flux;
    }
    else if (str_unit == "ERG/CM2/S" || str_unit == "ERG/S/CM2") {
        result = (gammalib::erg2MeV*flux) / (energy.MeV()*energy.MeV());
    }

    // ... otherwise throw exception
    else {
        throw GMWLException::invalid_unit(G_CONV_FLUX, unit);
    }

    // Return energy
    return result;
}
Ejemplo n.º 4
0
/***********************************************************************//**
 * @brief Returns model photon flux between [emin, emax] (ph/cm2/s)
 *
 * @param[in] emin Minimum photon energy.
 * @param[in] emax Maximum photon energy.
 * @return Photon flux (ph/cm2/s).
 *
 * Computes
 *
 * \f[
 *    \int_{\tt emin}^{\tt emax} S_{\rm E}(E | t) dE
 * \f]
 *
 * where
 * - [@p emin, @p emax] is an energy interval, and
 * - \f$S_{\rm E}(E | t)\f$ is the spectral model (ph/cm2/s/MeV).
 * The integration is done analytically.
 ***************************************************************************/
double GModelSpectralGauss::flux(const GEnergy& emin,
                                 const GEnergy& emax) const
{
    // Initialise flux
    double flux = 0.0;
    
    // Compute only if integration range is valid
    if (emin < emax) {

        // Precomputations
        double energy_min = emin.MeV();
        double energy_max = emax.MeV();
        double norm       = m_norm.value();
        double mean       = m_mean.value();
        double sigma      = m_sigma.value();
        double denom      = 1.0 / (gammalib::sqrt_two*sigma);
        double zmin       = (energy_min - mean) * denom;
        double zmax       = (energy_max - mean) * denom;

        // Compute flux for a constant model
        flux = norm*(gammalib::erfcc(zmin) - gammalib::erfcc(zmax))/2.0;
    
    } // endif: integration range was valid

    // Return
    return flux;
}
Ejemplo n.º 5
0
/***********************************************************************//**
 * @brief Returns model energy flux between [emin, emax] (units: erg/cm2/s)
 *
 * @param[in] emin Minimum photon energy.
 * @param[in] emax Maximum photon energy.
 * @return Energy flux (erg/cm2/s).
 *
 * Computes
 *
 * \f[
 *    \int_{\tt emin}^{\tt emax} S_{\rm E}(E | t) E \, dE
 * \f]
 *
 * where
 * - [@p emin, @p emax] is an energy interval, and
 * - \f$S_{\rm E}(E | t)\f$ is the spectral model (ph/cm2/s/MeV).
 * The integration is done numerically.
 ***************************************************************************/
double GModelSpectralSmoothBrokenPlaw::eflux(const GEnergy& emin,
                                             const GEnergy& emax) const
{
    // Initialise flux
    double eflux = 0.0;
    
    // Compute only if integration range is valid
    if (emin < emax) {
        
        // Initialise function to integrate
        eflux_kern kernel(prefactor(), index1(), pivot(),
                          index2(), breakenergy(), beta());
        
        // Initialise integral class with function
        GIntegral integral(&kernel);
        
        // Set integration precision
        integral.eps(1.0e-8);
        
        // Calculate integral between emin and emax
        eflux = integral.romberg(emin.MeV(), emax.MeV());
        
        // Convert from MeV/cm2/s to erg/cm2/s
        eflux *= gammalib::MeV2erg;
        
    } // endif: integration range was valid
    
    // Return flux
    return eflux;
}
Ejemplo n.º 6
0
/***********************************************************************//**
 * @brief Parameter constructor
 *
 * @param[in] prefactor Smoothly broken power law pre factor (ph/cm2/s/MeV).
 * @param[in] index1 Smoothly broken power law index1.
 * @param[in] pivot Smoothly broken power law pivot energy
 * @param[in] index2 Smoothly broken power law index1.
 * @param[in] breakenergy Break energy.
 * @param[in] beta Break smoothness parameter
 *
 * Constructs a smoothly broken power law using the model parameters
 * power law @p prefactor (ph/cm2/s/MeV),
 * spectral @p index1,
 * @p pivot energy,
 * spectral @p index2,
 * @p breakenergy of spectral break, and
 * smoothness parameter @p beta.
 ***************************************************************************/
GModelSpectralSmoothBrokenPlaw::GModelSpectralSmoothBrokenPlaw(
                                        const double&  prefactor,
                                        const double&  index1,
                                        const GEnergy& pivot,
                                        const double&  index2,
                                        const GEnergy& breakenergy,
                                        const double&  beta) :
                                GModelSpectral()
{
    // Initialise members
    init_members();
    
    // Set parameters
    m_norm.value(prefactor);
    m_index1.value(index1);
    m_pivot.value(pivot.MeV());              // Internally stored in MeV
    m_index2.value(index2);
    m_breakenergy.value(breakenergy.MeV());  // Internally stored in MeV
    m_beta.value(beta);
    
    // Perform autoscaling of parameter
    autoscale();
    
    // Return
    return;
}
Ejemplo n.º 7
0
/***********************************************************************//**
 * @brief Set logarithmically spaced energy intervals
 *
 * @param[in] num Number of energy intervals.
 * @param[in] emin Minimum energy of first interval.
 * @param[in] emax Maximum energy of last interval.
 *
 * Creates @p num logarithmically spaced energy boundaries running from
 * @p emin to @p emax.
 ***************************************************************************/
void GEbounds::set_log(const int& num, const GEnergy& emin, const GEnergy& emax)
{
    // Initialise members
    clear();

    // Compute bin width
    double elogmin = std::log10(emin.MeV());
    double elogmax = std::log10(emax.MeV());
    double elogbin = (elogmax - elogmin)/double(num);

    // Append boundaries
    GEnergy min;
    GEnergy max;
    for (int i = 0; i < num; ++i) {
        min.MeV(std::pow(10.0, double(i)*elogbin   + elogmin));
        max.MeV(std::pow(10.0, double(i+1)*elogbin + elogmin));
        append(min, max);
    }

    // Set attributes
    set_attributes();

    // Return
    return;
}
Ejemplo n.º 8
0
/***********************************************************************//**
 * @brief Returns MC energy between [emin, emax]
 *
 * @param[in] emin Minimum photon energy.
 * @param[in] emax Maximum photon energy.
 * @param[in] ran Random number generator.
 * @return Energy.
 *
 * @exception GException::erange_invalid
 *            Energy range is invalid (emin < emax required).
 *
 * Simulates a random energy in the interval [emin, emax] for a spectral
 * function.
 ***************************************************************************/
GEnergy GModelSpectralFunc::mc(const GEnergy& emin, const GEnergy& emax,
                               GRan& ran) const
{
    // Throw an exception if energy range is invalid
    if (emin >= emax) {
        throw GException::erange_invalid(G_MC, emin.MeV(), emax.MeV(),
              "Minimum energy < maximum energy required.");
        
    }

    // Allocate energy
    GEnergy energy;
    
    // Continue only if emax > emin
    if (emax > emin) {
    
        // Update cache
        mc_update(emin, emax);

        // Determine in which bin we reside
        int inx = 0;
        if (m_mc_cum.size() > 1) {
            double u = ran.uniform();
            for (inx = m_mc_cum.size()-1; inx > 0; --inx) {
                if (m_mc_cum[inx-1] <= u) {
                    break;
                }
            }
        }

        // Get random energy for specific bin
        if (m_mc_exp[inx] != 0.0) {
            double e_min = m_mc_min[inx];
            double e_max = m_mc_max[inx];
            double u     = ran.uniform();
            double eng   = (u > 0.0) 
                            ? std::exp(std::log(u * (e_max - e_min) + e_min) / m_mc_exp[inx])
                            : 0.0;
            energy.MeV(eng);
        }
        else {
            double e_min = m_mc_min[inx];
            double e_max = m_mc_max[inx];
            double u     = ran.uniform();
            double eng   = std::exp(u * (e_max - e_min) + e_min);
            energy.MeV(eng);
        }

    } // endif: emax > emin
    
    // Return energy
    return energy;
}
Ejemplo n.º 9
0
/***********************************************************************//**
 * @brief Update Monte Carlo pre computation cache
 *
 * @param[in] emin Minimum photon energy.
 * @param[in] emax Maximum photon energy.
 *
 * Updates the precomputation cache for Monte Carlo simulations.
 ***************************************************************************/
void GModelSpectralExpPlaw::update_mc_cache(const GEnergy& emin,
                                            const GEnergy& emax) const

{
    // Case A: Index is not -1
    if (index() != -1.0) {

        // Change in energy boundaries?
        if (emin.MeV() != m_mc_emin || emax.MeV() != m_mc_emax) {
            m_mc_emin       = emin.MeV();
            m_mc_emax       = emax.MeV();
            m_mc_exponent   = index() + 1.0;
            m_mc_pow_emin   = std::pow(m_mc_emin, m_mc_exponent);
            m_mc_pow_ewidth = std::pow(m_mc_emax, m_mc_exponent) - m_mc_pow_emin;
        }

    }

    // Case B: Index is -1
    else {

        // Change in energy boundaries?
        if (emin.MeV() != m_mc_emin || emax.MeV() != m_mc_emax) {
            m_mc_emin       = emin.MeV();
            m_mc_emax       = emax.MeV();
            m_mc_exponent   = 0.0;
            m_mc_pow_emin   = std::log(m_mc_emin);
            m_mc_pow_ewidth = std::log(m_mc_emax) - m_mc_pow_emin;
        }

    }

    // Return
    return;
}
Ejemplo n.º 10
0
/***********************************************************************//**
 * @brief Returns model photon flux between [emin, emax] (units: ph/cm2/s)
 *
 * @param[in] emin Minimum photon energy.
 * @param[in] emax Maximum photon energy.
 * @return Photon flux (ph/cm2/s).
 *
 * @exception GException::erange_invalid
 *            Energy range is invalid (emin < emax required).
 *
 * Computes
 * \f[\int_{E_{\rm min}}^{E_{\rm max}} I(E) dE\f]
 * where
 * \f$E_{\rm min}\f$ and \f$E_{\rm max}\f$ are the minimum and maximum
 * energy, respectively, and
 * \f$I(E)\f$ is the spectral model (units: ph/cm2/s/MeV).
 * The integration is done analytically.
 ***************************************************************************/
double GModelSpectralConst::flux(const GEnergy& emin, const GEnergy& emax) const
{
    // Throw an exception if energy range is invalid
    if (emin >= emax) {
        throw GException::erange_invalid(G_FLUX, emin.MeV(), emax.MeV(),
              "Minimum energy < maximum energy required.");
        
    }

    // Compute flux for a constant model
    double flux = norm() * (emax.MeV() - emin.MeV());

    // Return
    return flux;
}
Ejemplo n.º 11
0
/***********************************************************************//**
 * @brief Evaluate model value
 *
 * @param[in] srcEng True photon energy.
 * @param[in] srcTime True photon arrival time.
 * @return Model value (ph/cm2/s/MeV).
 *
 * Evaluates
 *
 * \f[
 * S_{\rm E}(E | t) = \frac{m\_norm}{\sqrt{2\pi}m\_sigma}
 *                    \exp(\frac{-(E-m\_mean)^2}{2 m\_sigma^2})
 * \f]
 *
 * where
 * - \f${\tt m\_norm}\f$ is the normalization,
 * - \f${\tt m\_mean}\f$ is the mean energy, and
 * - \f${\tt m\_sigma}\f$ is the energy width.
 ***************************************************************************/
double GModelSpectralGauss::eval(const GEnergy& srcEng,
                                 const GTime&   srcTime) const
{
    // Get parameter values
    double energy = srcEng.MeV();
    double norm   = m_norm.value();
    double mean   = m_mean.value();
    double sigma  = m_sigma.value();

    // Compute function value
    double delta = energy - mean;
    double term1 = (norm / sigma) * gammalib::inv_sqrt2pi;
    double term2 = delta * delta / (2.0 * sigma * sigma);
    double value = term1 * std::exp(-term2);

    // Compile option: Check for NaN/Inf
    #if defined(G_NAN_CHECK)
    if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) {
        std::cout << "*** ERROR: GModelSpectralGauss::eval";
        std::cout << "(srcEng=" << srcEng;
        std::cout << ", srcTime=" << srcTime << "):";
        std::cout << " NaN/Inf encountered";
        std::cout << " (value=" << value;
        std::cout << ")" << std::endl;
    }
    #endif

    // Return
    return value;
}
Ejemplo n.º 12
0
/***********************************************************************//**
 * @brief Return exponential cut-off energy
 *
 * @return Exponential cut-off energy.
 *
 * Returns the exponential cut-off energy.
 ***************************************************************************/
inline
GEnergy GModelSpectralSuperExpPlaw::cutoff(void) const
{
    GEnergy energy;
    energy.MeV(m_ecut.value());
    return energy;
}
Ejemplo n.º 13
0
/***********************************************************************//**
 * @brief Return maximum energy
 *
 * @return Maximum energy.
 *
 * Returns the maximum energy.
 ***************************************************************************/
inline
GEnergy GModelSpectralPlaw2::emax(void) const
{
    GEnergy energy;
    energy.MeV(m_emax.value());
    return energy;
}
/***********************************************************************//**
 * @brief Return breakenergy energy
 *
 * @return breakenergy energy.
 *
 * Returns the breakenergy energy.
 ***************************************************************************/
inline
GEnergy GModelSpectralBrokenPlaw::breakenergy(void) const
{
    GEnergy energy;
    energy.MeV(m_breakenergy.value());
    return energy;
}
Ejemplo n.º 15
0
/***********************************************************************//**
 * @brief Integration kernel for edisp_kern() method
 *
 * @param[in] x Function value.
 *
 * This method implements the integration kernel needed for the edisp_kern()
 * method.
 ***************************************************************************/
double GResponse::edisp_kern::eval(const double& x)
{
    // Set energy
    GEnergy eng;
    double expx = std::exp(x);
    eng.MeV(expx);

    // Get function value
    double value = m_parent->eval_prob(*m_model, *m_event, eng, m_srcTime, *m_obs, m_grad);

    // Save value if needed
    #if defined(G_NAN_CHECK)
    double value_out = value;
    #endif

    // Correct for variable substitution
    value *= expx;

    // Compile option: Check for NaN
    #if defined(G_NAN_CHECK)
    if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) {
        std::cout << "*** ERROR: GResponse::edisp_kern::eval";
        std::cout << "(x=" << x << "): ";
        std::cout << " NaN/Inf encountered";
        std::cout << " (value=" << value_out;
        std::cout << " exp(x)=" << expx;
        std::cout << ")" << std::endl;
    }
    #endif

    // Return value
    return value;
}
Ejemplo n.º 16
0
/***********************************************************************//**
 * @brief Return pivot energy
 *
 * @return Pivot energy.
 *
 * Returns the pivot energy.
 ***************************************************************************/
inline
GEnergy GModelSpectralPlaw::pivot(void) const
{
    GEnergy energy;
    energy.MeV(m_pivot.value());
    return energy;
}
Ejemplo n.º 17
0
/***********************************************************************//**
 * @brief Update eval precomputation cache
 *
 * @param[in] energy Energy.
 *
 * Updates the precomputation cache for eval() and eval_gradients() methods.
 ***************************************************************************/
void GModelSpectralExpPlaw::update_eval_cache(const GEnergy& energy) const
{
    // Get parameter values (takes 3 multiplications which are difficult
    // to avoid)
    double index = m_index.value();
    double ecut  = m_ecut.value();
    double pivot = m_pivot.value();
    
    // If the energy or one of the parameters index, cut-off or pivot
    // energy has changed then recompute the cache
    if ((m_last_energy != energy) ||
        (m_last_index  != index)  ||
        (m_last_ecut   != ecut)   ||
        (m_last_pivot  != pivot)) {

        // Store actual energy and parameter values
        m_last_energy = energy;
        m_last_index  = index;
        m_last_ecut   = ecut;
        m_last_pivot  = pivot;

        // Compute and store value
        double eng    = energy.MeV();
        m_last_e_norm = eng / m_last_pivot;
        m_last_e_cut  = eng / m_last_ecut;
        m_last_power  = std::pow(m_last_e_norm, m_last_index) *
                        std::exp(-m_last_e_cut);

    } // endif: recomputation was required

    // Return
    return;
}
Ejemplo n.º 18
0
/***********************************************************************//**
 * @brief Returns model energy flux between [emin, emax] (units: ph/cm2/s)
 *
 * @param[in] emin Minimum photon energy.
 * @param[in] emax Minimum photon energy.
 * @return Photon flux (ph/cm2/s).
 *
 * Computes
 *
 * \f[
 *    \int_{\tt emin}^{\tt emax} S_{\rm E}(E | t) E \, dE
 * \f]
 *
 * where
 * - [@p emin, @p emax] is an energy interval, and
 * - \f$S_{\rm E}(E | t)\f$ is the spectral model (ph/cm2/s/MeV).
 ***************************************************************************/
double GModelSpectralPlaw2::eflux(const GEnergy& emin,
                                  const GEnergy& emax) const
{
    // Initialise flux
    double eflux = 0.0;

    // Compute only if integration range is valid
    if (emin < emax) {

        // Compute power law normalization
        double norm;
        if (index() != -1.0) {
            double gamma        = m_index.value() + 1.0;
            double pow_ref_emin = std::pow(this->emin().MeV(), gamma);
            double pow_ref_emax = std::pow(this->emax().MeV(), gamma);
            norm = m_integral.value() * gamma / (pow_ref_emax - pow_ref_emin);
        }
        else {
            double log_ref_emin = std::log(this->emin().MeV());
            double log_ref_emax = std::log(this->emax().MeV());
            norm = m_integral.value() / (log_ref_emax - log_ref_emin);
        }

        // Compute energy flux
        if (index() != -2.0) {
            double gamma    = m_index.value() + 2.0;
            double pow_emin = std::pow(emin.MeV(), gamma);
            double pow_emax = std::pow(emax.MeV(), gamma);
            eflux = norm / gamma * (pow_emax - pow_emin);
        }

        // Case B: Index is -2
        else {
            double log_emin = std::log(emin.MeV());
            double log_emax = std::log(emax.MeV());
            eflux = norm * (log_emax - log_emin);
        }

        // Convert from MeV/cm2/s to erg/cm2/s
        eflux *= gammalib::MeV2erg;

    } // endif: integration range was valid

    // Return flux
    return eflux;
}
Ejemplo n.º 19
0
/***********************************************************************//**
 * @brief Constructor
 *
 * @param[in] integral Integral flux (ph/cm2/s).
 * @param[in] index Power law index.
 * @param[in] emin Minimum energy.
 * @param[in] emax Maximum energy.
 *
 * Construct a spectral power law from the
 * - integral flux (in ph/cm2/s),
 * - spectral index,
 * - minimum energy and
 * - maximum energy.
 ***************************************************************************/
GModelSpectralPlaw2::GModelSpectralPlaw2(const double&  integral,
                                         const double&  index,
                                         const GEnergy& emin,
                                         const GEnergy& emax) :
                     GModelSpectral()
{
    // Initialise members
    init_members();

    // Set parameters
    m_integral.value(integral);
    m_index.value(index);
    m_emin.value(emin.MeV());
    m_emax.value(emax.MeV());

    // Return
    return;
}
Ejemplo n.º 20
0
/***********************************************************************//**
 * @brief Constructor
 *
 * @param[in] norm Total flux under Gaussian (in ph/cm2/s).
 * @param[in] mean Mean energy.
 * @param[in] sigma Energy width.
 ***************************************************************************/
GModelSpectralGauss::GModelSpectralGauss(const double&  norm,
                                         const GEnergy& mean,
                                         const GEnergy& sigma) :
                     GModelSpectral()
{
    // Initialise members
    init_members();

    // Set parameters
    m_norm.value(norm);
    m_mean.value(mean.MeV());
    m_sigma.value(sigma.MeV());

    // Autoscale parameters
    autoscale();

    // Return
    return;
}
Ejemplo n.º 21
0
/***********************************************************************//**
 * @brief Returns Monte Carlo energy between [emin, emax]
 *
 * @param[in] emin Minimum photon energy.
 * @param[in] emax Maximum photon energy.
 * @param[in] time True photon arrival time.
 * @param[in,out] ran Random number generator.
 * @return Energy.
 *
 * @exception GException::erange_invalid
 *            Energy range is invalid (emin < emax required).
 *
 * Returns Monte Carlo energy by randomly drawing from a power law.
 ***************************************************************************/
GEnergy GModelSpectralPlaw::mc(const GEnergy& emin,
                               const GEnergy& emax,
                               const GTime&   time,
                               GRan&          ran) const
{
    // Throw an exception if energy range is invalid
    if (emin >= emax) {
        throw GException::erange_invalid(G_MC, emin.MeV(), emax.MeV(),
              "Minimum energy < maximum energy required.");
    }

    // Update cache
    update_mc_cache(emin, emax);

    // Get uniform random number
    double u = ran.uniform();

    // Initialise energy
    double eng;

    // Case A: Index is not -1
    if (index() != -1.0) {
        if (u > 0.0) {
            eng = std::exp(std::log(u * m_mc_pow_ewidth + m_mc_pow_emin) /
                           m_mc_exponent);
        }
        else {
            eng = 0.0;
        }
    }

    // Case B: Index is -1
    else {
        eng = std::exp(u * m_mc_pow_ewidth + m_mc_pow_emin);
    }

    // Set energy
    GEnergy energy;
    energy.MeV(eng);

    // Return energy
    return energy;
}
Ejemplo n.º 22
0
/***********************************************************************//**
 * @brief Constructor
 *
 * @param[in] prefactor Pre factor normalization (ph/cm2/s/MeV).
 * @param[in] index Power law index.
 * @param[in] pivot Pivot energy.
 * @param[in] cutoff Cut off energy.
 *
 * Construct an exponentially cut off power law from
 * - a prefactor value (in units of ph/cm2/s/MeV)
 * - a spectral index,
 * - a pivot energy, and
 * - a cut off energy.
 ***************************************************************************/
GModelSpectralExpPlaw::GModelSpectralExpPlaw(const double&  prefactor,
                                             const double&  index,
                                             const GEnergy& pivot,
                                             const GEnergy& cutoff) :
                       GModelSpectral()
{
    // Initialise members
    init_members();

    // Set parameters
    m_norm.value(prefactor);
    m_index.value(index);
    m_pivot.value(pivot.MeV()); // Internally stored in MeV
    m_ecut.value(cutoff.MeV()); // Internally stored in MeV

    // Autoscale parameters
    autoscale();

    // Return
    return;
}
Ejemplo n.º 23
0
/***********************************************************************//**
 * @brief Returns model photon flux between [emin, emax] (units: ph/cm2/s)
 *
 * @param[in] emin Minimum photon energy.
 * @param[in] emax Maximum photon energy.
 * @return Photon flux (ph/cm2/s).
 *
 * Computes
 *
 * \f[
 *    \int_{\tt emin}^{\tt emax} S_{\rm E}(E | t) dE
 * \f]
 *
 * where
 * - [@p emin, @p emax] is an energy interval, and
 * - \f$S_{\rm E}(E | t)\f$ is the spectral model (ph/cm2/s/MeV).
 * The integration is done analytically.
 ***************************************************************************/
double GModelSpectralPlaw::flux(const GEnergy& emin,
                                const GEnergy& emax) const
{
    // Initialise flux
    double flux = 0.0;

    // Compute only if integration range is valid
    if (emin < emax) {

        // Compute photon flux
        flux = m_norm.value() *
               gammalib::plaw_photon_flux(emin.MeV(),
                                          emax.MeV(),
                                          m_pivot.value(),
                                          m_index.value());

    } // endif: integration range was valid

    // Return flux
    return flux;
}
Ejemplo n.º 24
0
/***********************************************************************//**
 * @brief Evaluate model value and gradient
 *
 * @param[in] srcEng True photon energy.
 * @param[in] srcTime True photon arrival time.
 * @return Model value (ph/cm2/s/MeV).
 *
 * Evaluates
 *
 * \f[
 * S_{\rm E}(E | t) = \frac{m\_norm}{\sqrt{2\pi}m\_sigma}
 *                    \exp(\frac{-(E-m\_mean)^2}{2 m\_sigma^2})
 * \f]
 *
 * where
 * - \f${\tt m\_norm}\f$ is the normalization,
 * - \f${\tt m\_mean}\f$ is the mean energy, and
 * - \f${\tt m\_sigma}\f$ is the energy width.
 *
 * 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\_mean}} =
 *      S_{\rm E}(E | t) \frac{E-m\_mean}{m\_sigma^2}
 * \f]
 *
 * \f[
 *    \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_sigma}} =
 *      \frac{S_{\rm E}(E | t)}{{\tt m\_sigma}}
 *      \left( \frac{(E-m\_mean)^2}{m\_sigma^2} - 1 \right)
 * \f]
 *
 ***************************************************************************/
double GModelSpectralGauss::eval_gradients(const GEnergy& srcEng,
                                           const GTime&   srcTime)
{
    // Get parameter values
    double energy = srcEng.MeV();
    double norm   = m_norm.value();
    double mean   = m_mean.value();
    double sigma  = m_sigma.value();

    // Compute function terms
    double delta  = energy - mean;
    double sigma2 = sigma * sigma;
    double term2  = (1.0 / sigma) * gammalib::inv_sqrt2pi;
    double term1  = norm * term2;
    double term3  = delta * delta / (2.0 * sigma2);
    double term4  = delta / sigma2;
    double term5  = (norm / sigma2) * gammalib::inv_sqrt2pi;
    double eterm3 = std::exp(-term3);

    // Compute function value
    double value = term1 * eterm3;

    // Compute partial derivatives with respect to the parameter factor
    // values (partial differentials were determined analytically).
    double g_norm  = (m_norm.is_free())
                     ? term2 * eterm3 * m_norm.scale() : 0.0;
    double g_mean  = (m_mean.is_free())
                     ? value * term4 * m_mean.scale() : 0.0;
    double g_sigma = (m_sigma.is_free())
                     ? -term5 * eterm3 * (1.0 - (2.0 * term3)) * m_sigma.scale()
                     : 0.0;

    // Set gradients
    m_norm.factor_gradient(g_norm);
    m_mean.factor_gradient(g_mean);
    m_sigma.factor_gradient(g_sigma);

    // Compile option: Check for NaN/Inf
    #if defined(G_NAN_CHECK)
    if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) {
        std::cout << "*** ERROR: GModelSpectralGauss::eval_gradients";
        std::cout << "(srcEng=" << srcEng;
        std::cout << ", srcTime=" << srcTime << "):";
        std::cout << " NaN/Inf encountered";
        std::cout << " (value=" << value;
        std::cout << ")" << std::endl;
    }
    #endif

    // Return
    return value;
}
Ejemplo n.º 25
0
/***********************************************************************//**
 * @brief Returns Monte Carlo energy between [emin, emax]
 *
 * @param[in] emin Minimum photon energy.
 * @param[in] emax Maximum photon energy.
 * @param[in] time True photon arrival time.
 * @param[in,out] ran Random number generator.
 * @return Energy.
 *
 * @exception GException::erange_invalid
 *            Energy range is invalid (emin < emax required).
 *
 * Returns Monte Carlo energy by randomly drawing from a smoothly broken
 * power law.
 ***************************************************************************/
GEnergy GModelSpectralSmoothBrokenPlaw::mc(const GEnergy& emin,
                                           const GEnergy& emax,
                                           const GTime&   time,
                                           GRan&          ran) const
{
    // Throw exception if energy range is not valid
    if (emin >= emax) {
        throw GException::erange_invalid(G_MC, emin.MeV(), emax.MeV(),
                            "Minimum energy < maximum energy required.");
    }
    
    // Allocate energy
    GEnergy energy;
    
    // Update Monte Carlo cache
    update_mc_cache();
    
    // Initialse acceptance fraction
    double acceptance_fraction(0.0);
    
    // Use rejection method to draw a random energy. We first draw
    // analytically from a broken power law, and then compare the power law
    // at the drawn energy to the curved function. This gives an acceptance
    // fraction, and we accept the energy only if a uniform random number
    // is <= the acceptance fraction.
    do {
        // Generate an energy from the broken power law distribution
        energy = m_mc_brokenplaw.mc(emin, emax, time, ran);
        
        // Compute acceptance fraction
        acceptance_fraction = eval(energy) / m_mc_brokenplaw.eval(energy);
        
    } while (ran.uniform() > acceptance_fraction);
    
    // Return energy
    return energy;
}
Ejemplo n.º 26
0
/***********************************************************************//**
 * @brief Returns model photon flux between [emin, emax] (units: ph/cm2/s)
 *
 * @param[in] emin Minimum photon energy.
 * @param[in] emax Minimum photon energy.
 * @return Photon flux (ph/cm2/s).
 *
 * Computes
 *
 * \f[
 *    \int_{\tt emin}^{\tt emax} S_{\rm E}(E | t) dE
 * \f]
 *
 * where
 * - [@p emin, @p emax] is an energy interval, and
 * - \f$S_{\rm E}(E | t)\f$ is the spectral model (ph/cm2/s/MeV).
 ***************************************************************************/
double GModelSpectralPlaw2::flux(const GEnergy& emin,
                                 const GEnergy& emax) const
{
    // Initialise flux
    double flux = 0.0;

    // Compute only if integration range is valid
    if (emin < emax) {

        // Case A: Index is not -1
        if (index() != -1.0) {
            double gamma        = m_index.value() + 1.0;
            double pow_emin     = std::pow(emin.MeV(), gamma);
            double pow_emax     = std::pow(emax.MeV(), gamma);
            double pow_ref_emin = std::pow(this->emin().MeV(), gamma);
            double pow_ref_emax = std::pow(this->emax().MeV(), gamma);
            double factor       = (pow_emax - pow_emin) /
                                  (pow_ref_emax - pow_ref_emin);
            flux                = m_integral.value() * factor;
        }

        // Case B: Index is -1
        else {
            double log_emin     = std::log(emin.MeV());
            double log_emax     = std::log(emax.MeV());
            double log_ref_emin = std::log(this->emin().MeV());
            double log_ref_emax = std::log(this->emax().MeV());
            double factor       = (log_emax - log_emin) /
                                  (log_ref_emax - log_ref_emin);
            flux                = m_integral.value() * factor;
        }

    } // endif: integration range was valid

    // Return flux
    return flux;
}
Ejemplo n.º 27
0
/***********************************************************************//**
 * @brief Returns model energy flux between [emin, emax] (units: erg/cm2/s)
 *
 * @param[in] emin Minimum photon energy.
 * @param[in] emax Maximum photon energy.
 * @return Energy flux (erg/cm2/s).
 *
 * Computes
 *
 * \f[
 *    \int_{\tt emin}^{\tt emax} S_{\rm E}(E | t) E \, dE
 * \f]
 *
 * where
 * - [@p emin, @p emax] is an energy interval, and
 * - \f$S_{\rm E}(E | t)\f$ is the spectral model (ph/cm2/s/MeV).
 * The integration is done analytically.
 ***************************************************************************/
double GModelSpectralPlaw::eflux(const GEnergy& emin,
                                 const GEnergy& emax) const
{
    // Initialise flux
    double eflux = 0.0;

    // Compute only if integration range is valid
    if (emin < emax) {

        // Compute photon flux
        eflux = m_norm.value() *
                gammalib::plaw_energy_flux(emin.MeV(),
                                           emax.MeV(),
                                           m_pivot.value(),
                                           m_index.value());

        // Convert from MeV/cm2/s to erg/cm2/s
        eflux *= gammalib::MeV2erg;

    } // endif: integration range was valid

    // Return flux
    return eflux;
}
Ejemplo n.º 28
0
/***********************************************************************//**
 * @brief Returns logarithmic mean energy for a given energy interval
 *
 * @param[in] index Energy interval index (0,...,size()-1).
 * @return Logarithmic mean energy of interval.
 *
 * @exception GException::out_of_range
 *            Specified index is out of range.
 *
 * Computes the logarithmic mean energy
 * \f$10^{0.5 * (\log E_{\rm min} + \log E_{\rm max})}\f$
 * for the energy interval @p index.
 ***************************************************************************/
GEnergy GEbounds::elogmean(const int& index) const
{
#if defined(G_RANGE_CHECK)
    // If index is outside boundary then throw an error
    if (index < 0 || index >= m_num) {
        throw GException::out_of_range(G_ELOGMEAN, index, 0, m_num-1);
    }
#endif

    // Compute logarithmic mean energy
    GEnergy elogmean;
    elogmean.MeV(std::sqrt(m_min[index].MeV() * m_max[index].MeV()));

    // Return
    return elogmean;
}
Ejemplo n.º 29
0
/***********************************************************************//**
 * @brief Parameter constructor
 *
 * @param[in] prefactor Power law pre factor (ph/cm2/s/MeV).
 * @param[in] index Power law index.
 * @param[in] pivot Pivot energy.
 *
 * Constructs a spectral power law using the model parameters
 * - power law @p prefactor (ph/cm2/s/MeV)
 * - spectral @p index
 * - @p pivot energy.
 ***************************************************************************/
GModelSpectralPlaw::GModelSpectralPlaw(const double&  prefactor,
                                       const double&  index,
                                       const GEnergy& pivot) :
                    GModelSpectral()
{
    // Initialise members
    init_members();

    // Set parameters
    m_norm.value(prefactor);
    m_index.value(index);
    m_pivot.value(pivot.MeV());  // Internally stored in MeV

    // Perform autoscaling of parameter
    autoscale();

    // Return
    return;
}
Ejemplo n.º 30
0
/***********************************************************************//**
 * @brief Update eval precomputation cache
 *
 * @param[in] energy Energy.
 *
 * Updates the precomputation cache for eval() the method.
 ***************************************************************************/
void GModelSpectralSmoothBrokenPlaw::update_eval_cache(const GEnergy& energy) const
{
    // Get parameter values
    double index1    = m_index1.value();
    double index2    = m_index2.value();
    double pivot_eng = pivot().MeV();
    double break_eng = breakenergy().MeV();
    double beta      = m_beta.value();
    
    // If the energy or one of the parameters index1, index2, breakenergy
    // energy, or beta has changed then recompute the cache
    if ((m_last_energy      != energy) ||
        (m_last_index1      != index1) ||
        (m_last_index2      != index2) ||
        (m_last_pivot       != pivot_eng) ||
        (m_last_breakenergy != break_eng) ||
        (m_last_beta        != beta)) {
        
        // Store actual energy and parameter values
        m_last_energy      = energy;
        m_last_index1      = index1;
        m_last_index2      = index2;
        m_last_pivot       = pivot_eng;
        m_last_breakenergy = break_eng;
        m_last_beta        = beta;
        
        // Compute and store value
        double eng             = energy.MeV();
        m_last_epivot_norm     = eng / m_last_pivot;
        m_last_ebreak_norm     = eng / m_last_breakenergy;
        m_last_log_epivot_norm = std::log(m_last_epivot_norm);
        m_last_log_ebreak_norm = std::log(m_last_ebreak_norm);
        
        m_last_epivot_pow = std::pow(m_last_epivot_norm,m_last_index1);
        m_last_ebreak_pow = std::pow(m_last_ebreak_norm,
                                     (m_last_index1-m_last_index2)/m_last_beta) ;
        
    } // endif: recomputation was required
    
    // Return
    return;
}