/*************************************************************************** * GModelSpectralPlaw2.cpp - Spectral power law model class * * ----------------------------------------------------------------------- * * copyright (C) 2010-2014 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * 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 GModelSpectralPlaw2.cpp * @brief Flux normalized power law spectral model class implementation * @author Juergen Knoedlseder */ /* __ Includes ___________________________________________________________ */ #ifdef HAVE_CONFIG_H #include #endif #include #include "GException.hpp" #include "GTools.hpp" #include "GMath.hpp" #include "GModelSpectralPlaw2.hpp" #include "GModelSpectralRegistry.hpp" /* __ Constants __________________________________________________________ */ /* __ Globals ____________________________________________________________ */ const GModelSpectralPlaw2 g_spectral_plaw2_seed; const GModelSpectralRegistry g_spectral_plaw2_registry(&g_spectral_plaw2_seed); /* __ Method name definitions ____________________________________________ */ #define G_FLUX "GModelSpectralPlaw2::flux(GEnergy&, GEnergy&)" #define G_EFLUX "GModelSpectralPlaw2::eflux(GEnergy&, GEnergy&)" #define G_MC "GModelSpectralPlaw2::mc(GEnergy&, GEnergy&, GTime&, GRan&)" #define G_READ "GModelSpectralPlaw2::read(GXmlElement&)" #define G_WRITE "GModelSpectralPlaw2::write(GXmlElement&)" /* __ Macros _____________________________________________________________ */ /* __ Coding definitions _________________________________________________ */ /* __ Debug definitions __________________________________________________ */ /*========================================================================== = = = Constructors/destructors = = = ==========================================================================*/ /***********************************************************************//** * @brief Void constructor ***************************************************************************/ GModelSpectralPlaw2::GModelSpectralPlaw2(void) : GModelSpectral() { // Initialise members init_members(); // Return return; } /***********************************************************************//** * @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; } /***********************************************************************//** * @brief XML constructor * * @param[in] xml XML element. * * Constructs flux normalized power law spectral model by extracting * information from an XML element. See the read() method for more * information about the expected structure of the XML element. ***************************************************************************/ GModelSpectralPlaw2::GModelSpectralPlaw2(const GXmlElement& xml) : GModelSpectral() { // Initialise members init_members(); // Read information from XML element read(xml); // Return return; } /***********************************************************************//** * @brief Copy constructor * * @param[in] model Spectral power law model. ***************************************************************************/ GModelSpectralPlaw2::GModelSpectralPlaw2(const GModelSpectralPlaw2& model) : GModelSpectral(model) { // Initialise members init_members(); // Copy members copy_members(model); // Return return; } /***********************************************************************//** * @brief Destructor ***************************************************************************/ GModelSpectralPlaw2::~GModelSpectralPlaw2(void) { // Free members free_members(); // Return return; } /*========================================================================== = = = Operators = = = ==========================================================================*/ /***********************************************************************//** * @brief Assignment operator * * @param[in] model Spectral power law model. * @return Spectral power law model. ***************************************************************************/ GModelSpectralPlaw2& GModelSpectralPlaw2::operator=(const GModelSpectralPlaw2& 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 power law model ***************************************************************************/ void GModelSpectralPlaw2::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 power law model * * @return Pointer to deep copy of power law model ***************************************************************************/ GModelSpectralPlaw2* GModelSpectralPlaw2::clone(void) const { // Clone power law model return new GModelSpectralPlaw2(*this); } /***********************************************************************//** * @brief Evaluate function * * @param[in] srcEng True photon energy. * @param[in] srcTime True photon arrival time. * @return Model value (ph/cm2/s/MeV). * * Computes * * \f[ * S_{\rm E}(E | t) = {\tt m\_integral} * \frac{{\tt m\_index}+1} * {{\tt e\_max}^{{\tt m\_index}+1} - * {\tt e\_min}^{{\tt m\_index}+1}} * E^{\tt m\_index} * \f] * * for \f${\tt m\_index} \ne -1\f$ and * * \f[ * S_{\rm E}(E | t) = * \frac{{\tt m\_integral}} * {\log {\tt e\_max} - \log {\tt e\_min}} * E^{\tt m\_index} * \f] * * for \f${\tt m\_index} = -1\f$, where * - \f${\tt e\_min}\f$ is the minimum energy of an interval, * - \f${\tt e\_max}\f$ is the maximum energy of an interval, * - \f${\tt m\_integral}\f$ is the integral flux between * \f${\tt e\_min}\f$ and \f${\tt e\_max}\f$, and * - \f${\tt m\_index}\f$ is the spectral index. ***************************************************************************/ double GModelSpectralPlaw2::eval(const GEnergy& srcEng, const GTime& srcTime) const { // Update precomputed values update(srcEng); // Compute function value double value = m_integral.value() * m_norm * m_power; // Compile option: Check for NaN/Inf #if defined(G_NAN_CHECK) if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) { std::cout << "*** ERROR: GModelSpectralPlaw2::eval"; std::cout << "(srcEng=" << srcEng; std::cout << ", srcTime=" << srcTime << "):"; std::cout << " NaN/Inf encountered"; std::cout << " (value=" << value; std::cout << ", integral=" << integral(); std::cout << ", m_norm=" << m_norm; std::cout << ", m_power=" << m_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 (ph/cm2/s/MeV). * * Computes * * \f[ * S_{\rm E}(E | t) = {\tt m\_integral} * \frac{{\tt m\_index}+1} * {{\tt e\_max}^{{\tt m\_index}+1} - * {\tt e\_min}^{{\tt m\_index}+1}} * E^{\tt m\_index} * \f] * * for \f${\tt m\_index} \ne -1\f$ and * * \f[ * S_{\rm E}(E | t) = * \frac{{\tt m\_integral}} * {\log {\tt e\_max} - \log {\tt e\_min}} * E^{\tt m\_index} * \f] * * for \f${\tt m\_index} = -1\f$, where * - \f${\tt e\_min}\f$ is the minimum energy of an interval, * - \f${\tt e\_max}\f$ is the maximum energy of an interval, * - \f${\tt m\_integral}\f$ is the integral flux between * \f${\tt e\_min}\f$ and \f${\tt e\_max}\f$, and * - \f${\tt m\_index}\f$ is the spectral index. * * 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\_integral}} = * \frac{S_{\rm E}(E | t)}{{\tt m\_integral}} * \f] * * \f[ * \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_index}} = * S_{\rm E}(E | t) \, * \left( \frac{1}{{\tt m\_index}+1} - * \frac{\log({\tt e\_max}) {\tt e\_max}^{{\tt m\_index}+1} - * \log({\tt e\_min}) {\tt e\_min}^{{\tt m\_index}+1}} * {{\tt e\_max}^{{\tt m\_index}+1} - * {\tt e\_min}^{{\tt m\_index}+1}} * + \ln(E) \right) * \f] * * for \f${\tt m\_index} \ne -1\f$ and * * \f[ * \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_index}} = * S_{\rm E}(E | t) \, \ln(E) * \f] * * for \f${\tt m\_index} = -1\f$. * * No partial derivatives are supported for the energy boundaries. ***************************************************************************/ double GModelSpectralPlaw2::eval_gradients(const GEnergy& srcEng, const GTime& srcTime) { // Initialise gradients double g_integral = 0.0; double g_index = 0.0; // Update precomputed values update(srcEng); // Compute function value double value = m_integral.value() * m_norm * m_power; // Integral flux gradient if (m_integral.is_free() && m_integral.factor_value() > 0.0) { g_integral = value / m_integral.factor_value(); } // Index gradient if (m_index.is_free()) { g_index = value * (m_g_norm + gammalib::ln10 * srcEng.log10MeV()) * m_index.scale(); } // Set gradients m_integral.factor_gradient(g_integral); m_index.factor_gradient(g_index); // Compile option: Check for NaN/Inf #if defined(G_NAN_CHECK) if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) { std::cout << "*** ERROR: GModelSpectralPlaw2::eval_gradients"; std::cout << "(srcEng=" << srcEng; std::cout << ", srcTime=" << srcTime << "):"; std::cout << " NaN/Inf encountered"; std::cout << " (value=" << value; std::cout << ", integral=" << integral(); std::cout << ", m_norm=" << m_norm; std::cout << ", m_power=" << m_power; std::cout << ", g_integral=" << g_integral; std::cout << ", g_index=" << g_index; 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 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; } /***********************************************************************//** * @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; } /***********************************************************************//** * @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 power law. ***************************************************************************/ GEnergy GModelSpectralPlaw2::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."); } // Allocate energy GEnergy energy; // Case A: Index is not -1 if (index() != -1.0) { double exponent = index() + 1.0; double e_max = std::pow(emax.MeV(), exponent); double e_min = std::pow(emin.MeV(), exponent); double u = ran.uniform(); double eng = (u > 0.0) ? std::exp(std::log(u * (e_max - e_min) + e_min) / exponent) : 0.0; energy.MeV(eng); } // Case B: Index is -1 else { double e_max = std::log(emax.MeV()); double e_min = std::log(emin.MeV()); double u = ran.uniform(); double eng = std::exp(u * (e_max - e_min) + e_min); energy.MeV(eng); } // Return energy return energy; } /***********************************************************************//** * @brief Read model from XML element * * @param[in] xml XML element. * * @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. * * Reads the spectral information from an XML element. The format of the XML * elements is * * * * * * * * * @todo Add parameter validity check ***************************************************************************/ void GModelSpectralPlaw2::read(const GXmlElement& xml) { // Verify that XML element has exactly 4 parameters if (xml.elements() != 4 || xml.elements("parameter") != 4) { throw GException::model_invalid_parnum(G_READ, xml, "Power law 2 spectral model requires exactly 4 parameters."); } // Extract model parameters int npar[] = {0, 0, 0, 0}; for (int i = 0; i < 4; ++i) { // Get parameter element const GXmlElement* par = xml.element("parameter", i); // Handle prefactor if (par->attribute("name") == "Integral") { m_integral.read(*par); npar[0]++; } // Handle index else if (par->attribute("name") == "Index") { m_index.read(*par); npar[1]++; } // Handle lower limit else if (par->attribute("name") == "LowerLimit") { m_emin.read(*par); npar[2]++; } // Handle upper limit else if (par->attribute("name") == "UpperLimit") { m_emax.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, "Power law 2 spectral model requires \"Integral\", \"Index\"," " \"LowerLimit\" and \"UpperLimit\" parameters."); } // Return return; } /***********************************************************************//** * @brief Write model into XML element * * @param[in] xml XML element. * * @exception GException::model_invalid_spectral * Existing XML element is not of type "PowerLaw2" * @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. * * Writes the spectral information into an XML element. The format of the XML * element is * * * * * * * ***************************************************************************/ void GModelSpectralPlaw2::write(GXmlElement& xml) const { // Set model type if (xml.attribute("type") == "") { xml.attribute("type", "PowerLaw2"); } // Verify model type if (xml.attribute("type") != "PowerLaw2") { throw GException::model_invalid_spectral(G_WRITE, xml.attribute("type"), "Spectral model is not of type \"PowerLaw2\"."); } // If XML element has 0 nodes then append 4 parameter nodes if (xml.elements() == 0) { xml.append(GXmlElement("parameter name=\"Integral\"")); xml.append(GXmlElement("parameter name=\"Index\"")); xml.append(GXmlElement("parameter name=\"LowerLimit\"")); xml.append(GXmlElement("parameter name=\"UpperLimit\"")); } // Verify that XML element has exactly 4 parameters if (xml.elements() != 4 || xml.elements("parameter") != 4) { throw GException::model_invalid_parnum(G_WRITE, xml, "Power law 2 spectral 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 = xml.element("parameter", i); // Handle prefactor if (par->attribute("name") == "Integral") { npar[0]++; m_integral.write(*par); } // Handle index else if (par->attribute("name") == "Index") { npar[1]++; m_index.write(*par); } // Handle lower limit else if (par->attribute("name") == "LowerLimit") { m_emin.write(*par); npar[2]++; } // Handle lower limit else if (par->attribute("name") == "UpperLimit") { m_emax.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, "Power law 2 spectral model requires \"Integral\", \"Index\"," " \"LowerLimit\" and \"UpperLimit\" parameters."); } // Return return; } /***********************************************************************//** * @brief Print power law information * * @param[in] chatter Chattiness (defaults to NORMAL). * @return String containing power law information. ***************************************************************************/ std::string GModelSpectralPlaw2::print(const GChatter& chatter) const { // Initialise result string std::string result; // Continue only if chatter is not silent if (chatter != SILENT) { // Append header result.append("=== GModelSpectralPlaw2 ==="); // Append information result.append("\n"+gammalib::parformat("Number of parameters")); result.append(gammalib::str(size())); for (int i = 0; i < size(); ++i) { result.append("\n"+m_pars[i]->print(chatter)); } } // endif: chatter was not silent // Return result return result; } /*========================================================================== = = = Private methods = = = ==========================================================================*/ /***********************************************************************//** * @brief Initialise class members ***************************************************************************/ void GModelSpectralPlaw2::init_members(void) { // Initialise integral flux m_integral.clear(); m_integral.name("Integral"); m_integral.unit("ph/cm2/s"); m_integral.scale(1.0); m_integral.value(1.0); // default: 1.0 m_integral.range(0.0, 10.0); // range: [0,10] m_integral.free(); m_integral.gradient(0.0); m_integral.has_grad(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.has_grad(true); // Initialise lower limit m_emin.clear(); m_emin.name("LowerLimit"); m_emin.unit("MeV"); m_emin.scale(1.0); m_emin.value(100.0); // default: 100 m_emin.range(0.001, 1.0e15); // range: [0.001, 1e15] m_emin.fix(); m_emin.gradient(0.0); m_emin.has_grad(false); // Initialise upper limit m_emax.clear(); m_emax.name("UpperLimit"); m_emax.unit("MeV"); m_emax.scale(1.0); m_emax.value(500000.0); // default: 500000 m_emin.range(0.001, 1.0e15); // range: [0.001, 1e15] m_emax.fix(); m_emax.gradient(0.0); m_emax.has_grad(false); // Set parameter pointer(s) m_pars.clear(); m_pars.push_back(&m_integral); m_pars.push_back(&m_index); m_pars.push_back(&m_emin); m_pars.push_back(&m_emax); // Initialise last parameters (for fast computation) m_log_emin = 0.0; m_log_emax = 0.0; m_pow_emin = 0.0; m_pow_emax = 0.0; m_norm = 0.0; m_power = 0.0; m_last_integral = 0.0; m_last_index = 1000.0; m_last_emin.MeV(0.0); m_last_emax.MeV(0.0); m_last_energy.MeV(0.0); m_last_value = 0.0; m_last_g_integral = 0.0; m_last_g_index = 0.0; // Return return; } /***********************************************************************//** * @brief Copy class members * * @param[in] model Spectral power law model. ***************************************************************************/ void GModelSpectralPlaw2::copy_members(const GModelSpectralPlaw2& model) { // Copy members m_integral = model.m_integral; m_index = model.m_index; m_emin = model.m_emin; m_emax = model.m_emax; // Set parameter pointer(s) m_pars.clear(); m_pars.push_back(&m_integral); m_pars.push_back(&m_index); m_pars.push_back(&m_emin); m_pars.push_back(&m_emax); // Copy bookkeeping information m_log_emin = model.m_log_emin; m_log_emax = model.m_log_emax; m_pow_emin = model.m_pow_emin; m_pow_emax = model.m_pow_emax; m_norm = model.m_norm; m_power = model.m_power; m_last_integral = model.m_last_integral; m_last_index = model.m_last_index; m_last_emin = model.m_last_emin; m_last_emax = model.m_last_emax; m_last_energy = model.m_last_energy; m_last_value = model.m_last_value; m_last_g_integral = model.m_last_g_integral; m_last_g_index = model.m_last_g_index; // Return return; } /***********************************************************************//** * @brief Delete class members ***************************************************************************/ void GModelSpectralPlaw2::free_members(void) { // Return return; } /***********************************************************************//** * @brief Update precomputed values * * @param[in] srcEng Source energy ***************************************************************************/ void GModelSpectralPlaw2::update(const GEnergy& srcEng) const { // Compute index+1 double gamma = index() + 1.0; // Change in spectral index? if (index() != m_last_index) { // Save actual spectral index m_last_index = index(); // Change in energy boundaries? if (emin() != m_last_emin || emax() != m_last_emax) { m_log_emin = std::log(emin().MeV()); m_last_emin = emin(); m_log_emax = std::log(emax().MeV()); m_last_emax = emax(); } // Compute normalization factors if (gamma != 0.0) { m_pow_emin = std::pow(emin().MeV(), gamma); m_pow_emax = std::pow(emax().MeV(), gamma); double d = m_pow_emax - m_pow_emin; m_norm = gamma / d; m_g_norm = 1.0/gamma - (m_pow_emax*m_log_emax - m_pow_emin*m_log_emin)/d; } else { m_norm = 1.0 / (m_log_emax - m_log_emin); m_g_norm = 0.0; } // Update power law factor m_power = std::pow(srcEng.MeV(), index()); m_last_energy = srcEng; } // endif: change in spectral index // ... no change in spectral index else { // Change in energy boundaries? if (emin() != m_last_emin || emax() != m_last_emax) { // Update energy boundaries m_log_emin = std::log(emin().MeV()); m_last_emin = emin(); m_log_emax = std::log(emax().MeV()); m_last_emax = emax(); // Compute power law normalization if (gamma != 0.0) { m_pow_emin = std::pow(emin().MeV(), gamma); m_pow_emax = std::pow(emax().MeV(), gamma); double d = m_pow_emax - m_pow_emin; m_norm = gamma / d; m_g_norm = 1.0/gamma - (m_pow_emax*m_log_emax - m_pow_emin*m_log_emin)/d; } else { m_norm = 1.0 / (m_log_emax - m_log_emin); m_g_norm = 0.0; } } // endif: change in energy boundaries // Change in energy? if (srcEng != m_last_energy) { m_power = std::pow(srcEng.MeV(), index()); m_last_energy = srcEng; } } // endelse: no change in spectral index // Return return; }