/***************************************************************************
* GModelSpectralLogParabola.cpp - Log parabola spectral model class *
* ----------------------------------------------------------------------- *
* copyright (C) 2012 by Michael Mayer *
* ----------------------------------------------------------------------- *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see . *
* *
***************************************************************************/
/**
* @file GModelSpectralLogParabola.cpp
* @brief Log parabola spectral model class definition
* @author Michael Mayer
*/
/* __ Includes ___________________________________________________________ */
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include "GException.hpp"
#include "GTools.hpp"
#include "GIntegral.hpp"
#include "GModelSpectralLogParabola.hpp"
#include "GModelSpectralRegistry.hpp"
/* __ Constants __________________________________________________________ */
/* __ Globals ____________________________________________________________ */
const GModelSpectralLogParabola g_spectral_logparabola_seed;
const GModelSpectralRegistry g_spectral_logparabola_registry(&g_spectral_logparabola_seed);
/* __ Method name definitions ____________________________________________ */
#define G_FLUX "GModelSpectralLogParabola::flux(GEnergy&, GEnergy&)"
#define G_EFLUX "GModelSpectralLogParabola::eflux(GEnergy&, GEnergy&)"
#define G_MC "GModelSpectralLogParabola::mc(GEnergy&, GEnergy&, GRan&)"
#define G_READ "GModelSpectralLogParabola::read(GXmlElement&)"
#define G_WRITE "GModelSpectralLogParabola::write(GXmlElement&)"
/* __ Macros _____________________________________________________________ */
/* __ Coding definitions _________________________________________________ */
/* __ Debug definitions __________________________________________________ */
/*==========================================================================
= =
= Constructors/destructors =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Void constructor
***************************************************************************/
GModelSpectralLogParabola::GModelSpectralLogParabola(void) : GModelSpectral()
{
// Initialise private members
init_members();
// Return
return;
}
/***********************************************************************//**
* @brief Constructor
*
* @param[in] norm Power law normalization.
* @param[in] index Power law index.
* @param[in] curvature Curvature.
*
* Construct a LogParabola model from a normalization value, a spectral
* index and a curvature
***************************************************************************/
GModelSpectralLogParabola::GModelSpectralLogParabola(const double& norm,
const double& index,
const double& curvature) :
GModelSpectral()
{
// Initialise members
init_members();
// Set parameters
m_norm.real_value(norm);
m_index.real_value(index);
m_curvature.real_value(curvature);
// Return
return;
}
/***********************************************************************//**
* @brief XML constructor
*
* @param[in] xml XML element.
*
* Creates instance of a log parabola spectral model by extracting information
* from an XML element. See GModelSpectralLogParabola::read() for more information
* about the expected structure of the XML element.
***************************************************************************/
GModelSpectralLogParabola::GModelSpectralLogParabola(const GXmlElement& xml) :
GModelSpectral()
{
// Initialise members
init_members();
// Read information from XML element
read(xml);
// Return
return;
}
/***********************************************************************//**
* @brief Copy constructor
*
* @param[in] model LogParabola model.
***************************************************************************/
GModelSpectralLogParabola::GModelSpectralLogParabola(const GModelSpectralLogParabola& model) :
GModelSpectral(model)
{
// Initialise members
init_members();
// Copy members
copy_members(model);
// Return
return;
}
/***********************************************************************//**
* @brief Destructor
***************************************************************************/
GModelSpectralLogParabola::~GModelSpectralLogParabola(void)
{
// Free members
free_members();
// Return
return;
}
/*==========================================================================
= =
= Operators =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Assignment operator
*
* @param[in] model LogParabola model.
* @return LogParabola model.
***************************************************************************/
GModelSpectralLogParabola& GModelSpectralLogParabola::operator=(const GModelSpectralLogParabola& model)
{
// Execute only if object is not identical
if (this != &model) {
// Copy base class members
this->GModelSpectral::operator=(model);
// Free members
free_members();
// Initialise members
init_members();
// Copy members
copy_members(model);
} // endif: object was not identical
// Return
return *this;
}
/*==========================================================================
= =
= Public methods =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Clear instance
***************************************************************************/
void GModelSpectralLogParabola::clear(void)
{
// Free class members (base and derived classes, derived class first)
free_members();
this->GModelSpectral::free_members();
// Initialise members
this->GModelSpectral::init_members();
init_members();
// Return
return;
}
/***********************************************************************//**
* @brief Clone instance
*
* @return Pointer to deep copy of log parabola spectrum.
***************************************************************************/
GModelSpectralLogParabola* GModelSpectralLogParabola::clone(void) const
{
return new GModelSpectralLogParabola(*this);
}
/***********************************************************************//**
* @brief Evaluate function
*
* @param[in] srcEng True energy of photon.
* @return Function value.
*
* The logparabola function is defined as
* \f[I(E)=norm (E/pivot)^{index-curvature*log(E/pivot)}\f]
* where
* \f$norm\f$ is the normalization or prefactor,
* \f$pivot\f$ is the pivot energy, and
* \f$index\f$ is the spectral index.
* \f$curvature\f$ is the curvature
*
* @todo For the moment the pivot energy is fixed to units of MeV. This may
* not be ideal and should eventually be improved in the future.
* Furthermore, the method expects that energy!=0. Otherwise Inf or NaN
* may result.
***************************************************************************/
double GModelSpectralLogParabola::eval(const GEnergy& srcEng) const
{
// Compute function value
double energy = srcEng.MeV() / pivot();
double exponent = index() + curvature()*log(energy);
double power = std::pow(energy,exponent);
double value = norm() * power;
// Compile option: Check for NaN/Inf
#if defined(G_NAN_CHECK)
if (isnotanumber(value) || isinfinite(value)) {
std::cout << "*** ERROR: GModelSpectralLogParabola::eval";
std::cout << "(srcEng=" << srcEng << "):";
std::cout << " NaN/Inf encountered";
std::cout << " (value=" << value;
std::cout << ", energy=" << energy;
std::cout << ", index=" << index();
std::cout << ", curvature=" << curvature();
std::cout << ", pivot=" << pivot();
std::cout << ", power=" << power;
std::cout << ")" << std::endl;
}
#endif
// Return
return value;
}
/***********************************************************************//**
* @brief Evaluate function and gradients
*
* @param[in] srcEng True energy of photon.
* @return Function value.
*
* The logparabol function is defined as
* \f[I(E)=norm (E/pivot)^{index-curvature\ln(E/pivot)}\f]
* where
* \f$norm=n_s n_v\f$ is the normalization or prefactor,
* \f$pivot=p_s p_v\f$ is the pivot energy, and
* \f$index=i_s i_v\f$ is the spectral index.
* \f$curvature=i_s i_v\f$ is the curvature
* Note that each parameter is factorised into a scaling factor and a value
* and that the method is expected to return the gradient with respect to
* the parameter value (i.e. n_v, p_v, i_v, and c_v in this case).
*
* The partial derivatives of the parameter values are given by
*@todo implement formulae here
*
* @todo For the moment the pivot energy is fixed to units of MeV. This may
* not be ideal and should eventually be improved in the futur.
* Furthermore, the method expects that energy!=0. Otherwise Inf or NaN
* may result.
***************************************************************************/
double GModelSpectralLogParabola::eval_gradients(const GEnergy& srcEng) const
{
// Compute function value
double energy = srcEng.MeV() / pivot();
double exponent = index() + curvature()*std::log(energy);
double power = std::pow(energy,exponent);
double value = norm() * power;
// Compute partial derivatives of the parameter values
double log_energy = std::log(energy);
double g_norm = (m_norm.isfree()) ? m_norm.scale() * power : 0.0;
double g_index = (m_index.isfree())
? value * m_index.scale() * log_energy : 0.0;
double g_curvature = (m_curvature.isfree())
? value * m_curvature.scale() * log_energy *
log_energy
: 0.0;
double g_pivot = (m_pivot.isfree())
? -value/m_pivot.value() * (exponent + curvature() *
log_energy)
: 0.0;
// Set gradients (circumvent const correctness)
const_cast(this)->m_norm.gradient(g_norm);
const_cast(this)->m_index.gradient(g_index);
const_cast(this)->m_curvature.gradient(g_curvature);
const_cast(this)->m_pivot.gradient(g_pivot);
// Compile option: Check for NaN/Inf
#if defined(G_NAN_CHECK)
if (isnotanumber(value) || isinfinite(value)) {
std::cout << "*** ERROR: GModelSpectralLogParabola::eval_gradients";
std::cout << "(srcEng=" << srcEng << "):";
std::cout << " NaN/Inf encountered";
std::cout << " (value=" << value;
std::cout << ", energy=" << energy;
std::cout << ", index=" << index();
std::cout << ", curvature=" << curvature();
std::cout << ", pivot=" << pivot();
std::cout << ", power=" << power;
std::cout << ", g_norm=" << g_norm;
std::cout << ", g_index=" << g_index;
std::cout << ", g_curvature=" << g_curvature;
std::cout << ", g_pivot=" << g_pivot;
std::cout << ")" << std::endl;
}
#endif
// Return
return value;
}
/***********************************************************************//**
* @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_{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 numerically.
***************************************************************************/
double GModelSpectralLogParabola::flux(const GEnergy& emin,
const GEnergy& emax) const
{
// Initialise function to integrate
flux_kern flux(norm(),index(),curvature(),pivot());
// Initialise integral class with function
GIntegral integral(&flux);
// Set integration precision
integral.eps(1.0e-8);
// Calculate integral between emin and emax
double photonflux = integral.romb(emin.MeV(), emax.MeV());
//Return value
return photonflux;
}
/***********************************************************************//**
* @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_{E_{\rm min}}^{E_{\rm max}} I(E) 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 numerically.
***************************************************************************/
double GModelSpectralLogParabola::eflux(const GEnergy& emin,
const GEnergy& emax) const
{
// Initialise function to integrate
eflux_kern eflux(norm(),index(),curvature(),pivot());
// Initialise integral class with function
GIntegral integral(&eflux);
// Set integration precision
integral.eps(1.0e-8);
// Calculate integral between emin and emax
double energyflux = integral.romb(emin.MeV(), emax.MeV());
// Return value
return energyflux;
}
/***********************************************************************//**
* @brief Returns Monte Carlo 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::feature_not_implemented
* Feature not yet implemented.
*
* Returns Monte Carlo energy by randomly drawing from a power law.
*
***************************************************************************/
GEnergy GModelSpectralLogParabola::mc(const GEnergy& emin,
const GEnergy& emax,
GRan& ran) const
{
if (emin >= emax) {
throw GException::erange_invalid(G_MC, emin.MeV(), emax.MeV(),
"Minimum energy < maximum energy required.");
}
// Allocate energy
GEnergy energy;
// Update cache
update_mc_cache(emin, emax);
// Initialise energy
double eng;
// Initialse acceptance fraction
double acceptance_fraction;
// Use rejection method to draw a random energy. We first draw
// analytically from a 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 {
// Get uniform random number
double u = ran.uniform();
// Case A: Corresponding mc Plaw-Index is not -1
if (m_mc_exponent != 0.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: Corresponding mc Plaw-Index is -1
else {
eng = std::exp(u * m_mc_pow_ewidth + m_mc_pow_emin);
}
// Compute powerlaw at given energy
double e_norm = eng / pivot();
double plaw = m_mc_norm*std::pow(eng/pivot(), m_mc_exponent-1.0);
// Compute logparabola at given energy
double logparabola = norm()*std::pow(e_norm,index()+curvature()*std::log(e_norm));
// Compute acceptance fraction
acceptance_fraction = logparabola / plaw;
} while (ran.uniform() > acceptance_fraction);
// Set energy
energy.MeV(eng);
// Return energy
return energy;
}
/***********************************************************************//**
* @brief Autoscale normalization
*
* Based on the actual value of the m_norm parameter, set the scale of m_norm
* so that the value will be 1. If minimum and/or maximum value boundaries
* exist, the boundaries are also modified accordingly.
***************************************************************************/
void GModelSpectralLogParabola::autoscale(void)
{
// Autoscale normalization to a value of 1.0
if (m_norm.value() != 0.0) {
// Get inverse scaling factor
double invscale = 1.0 / m_norm.value();
// Set values, error, min and max
m_norm.value(m_norm.value() * invscale);
m_norm.error(m_norm.error() * invscale);
if (m_norm.hasmin()) {
m_norm.min(m_norm.min() * invscale);
}
if (m_norm.hasmax()) {
m_norm.max(m_norm.max() * invscale);
}
// Set scale
m_norm.scale(1.0 / invscale);
}
// Return
return;
}
/***********************************************************************//**
* @brief Read model from XML element
*
* @param[in] xml XML element containing logparabola model information.
*
* @exception GException::model_invalid_parnum
* Invalid number of model parameters found in XML element.
* @exception GException::model_invalid_parnames
* Invalid model parameter names found in XML element.
*
* Read the spectral log parabola information from an XML element. The format
* of the XML elements is
*
*
*
*
*
*
*
*
* or for compliance with Fermi-LAT
*
*
*
*
*
*
*
*
* @todo Add parameter validity check
***************************************************************************/
void GModelSpectralLogParabola::read(const GXmlElement& xml)
{
// Verify that XML element has exactly 3 parameters
if (xml.elements() != 4 || xml.elements("parameter") != 4) {
throw GException::model_invalid_parnum(G_READ, xml,
"LogParabola model requires exactly 4 parameters.");
}
// Extract model parameters
int npar[] = {0, 0, 0,0};
for (int i = 0; i < 4; ++i) {
// Get parameter element
GXmlElement* par = static_cast(xml.element("parameter", i));
// Handle prefactor
if (par->attribute("name") == "Prefactor" ||
par->attribute("name") == "norm") {
m_norm.read(*par);
npar[0]++;
}
// Handle index
else if (par->attribute("name") == "Index"){
m_index.read(*par);
npar[1]++;
}
// Change sign if index is defined Fermi-like
else if(par->attribute("name") == "alpha") {
m_index.read(*par);
m_index.scale(-m_index.scale());
npar[1]++;
}
// Handle curvature
else if (par->attribute("name") == "Curvature") {
m_curvature.read(*par);
npar[2]++;
}
// Change sign if curvature is defined Fermi-like
else if(par->attribute("name") == "beta") {
m_curvature.read(*par);
m_curvature.scale(-m_curvature.scale());
npar[2]++;
}
// Handle pivot energy
else if (par->attribute("name") == "Scale" ||
par->attribute("name") == "Eb") {
m_pivot.read(*par);
npar[3]++;
}
} // endfor: looped over all parameters
// Verify that all parameters were found
if (npar[0] != 1 || npar[1] != 1 || npar[2] != 1 || npar[3] != 1) {
throw GException::model_invalid_parnames(G_READ, xml,
"LogParabola requires \"Prefactor\" or \"norm\","
" \"Index\" or \"alpha\", \"Curvature\" or \"beta\""
" and \"Scale\" or \"Eb\" parameters.");
}
// Return
return;
}
/***********************************************************************//**
* @brief Write model into XML element
*
* @param[in] xml XML element into which model information is written.
*
* @exception GException::model_invalid_spectral
* Existing XML element is not of type "LogParabola"
* @exception GException::model_invalid_parnum
* Invalid number of model parameters or nodes found in XML element.
* @exception GException::model_invalid_parnames
* Invalid model parameter names found in XML element.
*
* Write the LogParabola model information into an XML element. The format
* of the XML elements is
*
*
*
*
*
*
*
***************************************************************************/
void GModelSpectralLogParabola::write(GXmlElement& xml) const
{
// Set model type
if (xml.attribute("type") == "") {
xml.attribute("type", type());
}
// Verify model type
if (xml.attribute("type") != type()) {
throw GException::model_invalid_spectral(G_WRITE, xml.attribute("type"),
"Spectral model is not of type \""+type()+"\".");
}
// If XML element has 0 nodes then append 4 parameter nodes
if (xml.elements() == 0) {
xml.append(new GXmlElement("parameter name=\"Prefactor\""));
xml.append(new GXmlElement("parameter name=\"Index\""));
xml.append(new GXmlElement("parameter name=\"Curvature\""));
xml.append(new GXmlElement("parameter name=\"Scale\""));
}
// Verify that XML element has exactly 4 parameters
if (xml.elements() != 4 || xml.elements("parameter") != 4) {
throw GException::model_invalid_parnum(G_WRITE, xml,
"LogParabola law model requires exactly 4 parameters.");
}
// Set or update model parameter attributes
int npar[] = {0, 0, 0,0};
for (int i = 0; i < 4; ++i) {
// Get parameter element
GXmlElement* par = static_cast(xml.element("parameter", i));
// Handle prefactor
if (par->attribute("name") == "Prefactor"){
npar[0]++;
m_norm.write(*par);
}
// Handle index
else if (par->attribute("name") == "Index") {
npar[1]++;
m_index.write(*par);
}
// Handle index
else if (par->attribute("name") == "Curvature"){
npar[2]++;
m_curvature.write(*par);
}
// Handle pivot energy
else if (par->attribute("name") == "Scale") {
m_pivot.write(*par);
npar[3]++;
}
} // endfor: looped over all parameters
// Check of all required parameters are present
if (npar[0] != 1 || npar[1] != 1 || npar[2] != 1 || npar[3] != 1) {
throw GException::model_invalid_parnames(G_WRITE, xml,
"LogParabola requires \"Prefactor\", \"Index\", \"Curvature\""
" and \"Scale\" parameters.");
}
// Return
return;
}
/***********************************************************************//**
* @brief Print LogParabola information
***************************************************************************/
std::string GModelSpectralLogParabola::print(void) const
{
// Initialise result string
std::string result;
// Append header
result.append("=== GModelSpectralLogParabola ===\n");
// Append information
result.append(parformat("Number of parameters")+str(size()));
for (int i = 0; i < size(); ++i) {
result.append("\n"+m_pars[i]->print());
}
// Return result
return result;
}
/*==========================================================================
= =
= Private methods =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Initialise class members
***************************************************************************/
void GModelSpectralLogParabola::init_members(void)
{
// Initialise powerlaw normalisation
m_norm.clear();
m_norm.name("Prefactor");
m_norm.unit("ph/cm2/s/MeV");
m_norm.scale(1.0);
m_norm.value(1.0); // default: 1.0
m_norm.min(0.1); // min: 0.0
m_norm.free();
m_norm.gradient(0.0);
m_norm.hasgrad(true);
// Initialise powerlaw index
m_index.clear();
m_index.name("Index");
m_index.scale(1.0);
m_index.value(-2.0); // default: -2.0
m_index.range(-10.0,+10.0); // range: [-10,+10]
m_index.free();
m_index.gradient(0.0);
m_index.hasgrad(true);
// Initialise curvature
m_curvature.clear();
m_curvature.name("Curvature");
m_curvature.scale(1.0);
m_curvature.value(-0.1); // default: -2.0
m_curvature.range(-10.0,+10.0); // range: [-10,+10]
m_curvature.free();
m_curvature.gradient(0.0);
m_curvature.hasgrad(true);
// Initialise pivot energy
m_pivot.clear();
m_pivot.name("PivotEnergy");
m_pivot.unit("MeV");
m_pivot.scale(1.0);
m_pivot.value(100.0); // default: 100
m_pivot.fix();
m_pivot.gradient(0.0);
m_pivot.hasgrad(true);
// Set parameter pointer(s)
m_pars.clear();
m_pars.push_back(&m_norm);
m_pars.push_back(&m_index);
m_pars.push_back(&m_curvature);
m_pars.push_back(&m_pivot);
// Initialise MC cache
m_mc_emin = 0.0;
m_mc_emax = 0.0;
m_mc_exponent = 0.0;
m_mc_pow_emin = 0.0;
m_mc_pow_ewidth = 0.0;
m_mc_norm = 0.0;
// Return
return;
}
/***********************************************************************//**
* @brief Copy class members
*
* @param[in] model GModelSpectralLogParabola members which should be copied.
***************************************************************************/
void GModelSpectralLogParabola::copy_members(const GModelSpectralLogParabola& model)
{
// Copy members
m_norm = model.m_norm;
m_index = model.m_index;
m_curvature = model.m_curvature;
m_pivot = model.m_pivot;
// Set parameter pointer(s)
m_pars.clear();
m_pars.push_back(&m_norm);
m_pars.push_back(&m_index);
m_pars.push_back(&m_curvature);
m_pars.push_back(&m_pivot);
// Copy MC cache
m_mc_emin = model.m_mc_emin;
m_mc_emax = model.m_mc_emax;
m_mc_exponent = model.m_mc_exponent;
m_mc_pow_emin = model.m_mc_pow_emin;
m_mc_pow_ewidth = model.m_mc_pow_ewidth;
m_mc_norm = model.m_mc_norm;
// Return
return;
}
/***********************************************************************//**
* @brief Delete class members
***************************************************************************/
void GModelSpectralLogParabola::free_members(void)
{
// Return
return;
}
/***********************************************************************//**
* @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 GModelSpectralLogParabola::update_mc_cache(const GEnergy& emin,
const GEnergy& emax) const
{
// Only update if boundaries have changed
if(emin.MeV() != m_mc_emin || emax.MeV() != m_mc_emax){
// Store energy boundaries
m_mc_emin = emin.MeV();
m_mc_emax = emax.MeV();
// Find a corresponding power law with the criterion
// Plaw > LogParabola in the given interval
double index_pl;
// Checking the sign of spectrum curvature
if (curvature() < 0) {
// Use the spectral index at the pivot energy of the LogParabola
index_pl = index();
m_mc_norm = norm();
}
else {
// Use a power law which connects the ends of the convex,
// curved model
// Plaw index defined by the slope of a straight line in the
// log-log-plane
index_pl = std::log(eval(emin)/eval(emax))/std::log(emin.MeV()/emax.MeV());
// Plaw norm defined such that Plaw = LogParabola at emin
m_mc_norm = eval(emin)/std::pow(emin.MeV()/pivot(),index_pl);
}
// Set precomputation cache
if (index_pl != -1.0) {
m_mc_exponent = index_pl + 1.0;
m_mc_pow_emin = std::pow(emin.MeV(), m_mc_exponent);
m_mc_pow_ewidth = std::pow(emax.MeV(), m_mc_exponent) - m_mc_pow_emin;
}
else {
m_mc_exponent = 0.0;
m_mc_pow_emin = std::log(emin.MeV());
m_mc_pow_ewidth = std::log(emax.MeV()) - m_mc_pow_emin;
}
}
// Return
return;
}