src/model/GModelSpectralPlaw2.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *         GModelSpectralPlaw2.cpp - Spectral power law model class        *
00003  * ----------------------------------------------------------------------- *
00004  *  copyright (C) 2010-2016 by Juergen Knoedlseder                         *
00005  * ----------------------------------------------------------------------- *
00006  *                                                                         *
00007  *  This program is free software: you can redistribute it and/or modify   *
00008  *  it under the terms of the GNU General Public License as published by   *
00009  *  the Free Software Foundation, either version 3 of the License, or      *
00010  *  (at your option) any later version.                                    *
00011  *                                                                         *
00012  *  This program is distributed in the hope that it will be useful,        *
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
00015  *  GNU General Public License for more details.                           *
00016  *                                                                         *
00017  *  You should have received a copy of the GNU General Public License      *
00018  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
00019  *                                                                         *
00020  ***************************************************************************/
00021 /**
00022  * @file GModelSpectralPlaw2.cpp
00023  * @brief Flux normalized power law spectral model class implementation
00024  * @author Juergen Knoedlseder
00025  */
00026 
00027 /* __ Includes ___________________________________________________________ */
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 #include <cmath>
00032 #include "GException.hpp"
00033 #include "GTools.hpp"
00034 #include "GMath.hpp"
00035 #include "GRan.hpp"
00036 #include "GModelSpectralPlaw2.hpp"
00037 #include "GModelSpectralRegistry.hpp"
00038 
00039 /* __ Constants __________________________________________________________ */
00040 
00041 /* __ Globals ____________________________________________________________ */
00042 const GModelSpectralPlaw2    g_spectral_plaw2_seed1("PowerLaw",
00043                                                     "PhotonFlux",
00044                                                     "Index",
00045                                                     "LowerLimit",
00046                                                     "UpperLimit");
00047 const GModelSpectralRegistry g_spectral_plaw2_registry1(&g_spectral_plaw2_seed1);
00048 #if defined(G_LEGACY_XML_FORMAT)
00049 const GModelSpectralPlaw2    g_spectral_plaw2_seed2("PowerLaw2",
00050                                                     "Integral",
00051                                                     "Index",
00052                                                     "LowerLimit",
00053                                                     "UpperLimit");
00054 const GModelSpectralRegistry g_spectral_plaw2_registry2(&g_spectral_plaw2_seed2);
00055 #endif
00056 
00057 /* __ Method name definitions ____________________________________________ */
00058 #define G_FLUX                "GModelSpectralPlaw2::flux(GEnergy&, GEnergy&)"
00059 #define G_EFLUX              "GModelSpectralPlaw2::eflux(GEnergy&, GEnergy&)"
00060 #define G_MC     "GModelSpectralPlaw2::mc(GEnergy&, GEnergy&, GTime&, GRan&)"
00061 #define G_READ                      "GModelSpectralPlaw2::read(GXmlElement&)"
00062 #define G_WRITE                    "GModelSpectralPlaw2::write(GXmlElement&)"
00063 
00064 /* __ Macros _____________________________________________________________ */
00065 
00066 /* __ Coding definitions _________________________________________________ */
00067 
00068 /* __ Debug definitions __________________________________________________ */
00069 
00070 
00071 /*==========================================================================
00072  =                                                                         =
00073  =                        Constructors/destructors                         =
00074  =                                                                         =
00075  ==========================================================================*/
00076 
00077 /***********************************************************************//**
00078  * @brief Void constructor
00079  *
00080  * Constructs empty power law photon flux model.
00081  ***************************************************************************/
00082 GModelSpectralPlaw2::GModelSpectralPlaw2(void) : GModelSpectral()
00083 {
00084     // Initialise members
00085     init_members();
00086 
00087     // Return
00088     return;
00089 }
00090 
00091 
00092 /***********************************************************************//**
00093  * @brief Model type and parameter name constructor
00094  *
00095  * @param[in] type Model type.
00096  * @param[in] integral Name of integral parameter.
00097  * @param[in] index Name of index parameter.
00098  * @param[in] emin Name of emin parameter.
00099  * @param[in] emax Name of emax parameter.
00100  ***************************************************************************/
00101 GModelSpectralPlaw2::GModelSpectralPlaw2(const std::string& type,
00102                                          const std::string& integral,
00103                                          const std::string& index,
00104                                          const std::string& emin,
00105                                          const std::string& emax) :
00106                      GModelSpectral()
00107 {
00108     // Initialise members
00109     init_members();
00110 
00111     // Set model type
00112     m_type = type;
00113 
00114     // Set parameter names
00115     m_integral.name(integral);
00116     m_index.name(index);
00117     m_emin.name(emin);
00118     m_emax.name(emax);
00119 
00120     // Return
00121     return;
00122 }
00123 
00124 
00125 /***********************************************************************//**
00126  * @brief Constructor
00127  *
00128  * @param[in] integral Integral flux (ph/cm2/s).
00129  * @param[in] index Power law index.
00130  * @param[in] emin Minimum energy.
00131  * @param[in] emax Maximum energy.
00132  *
00133  * Construct a spectral power law from the
00134  * - integral flux (in ph/cm2/s),
00135  * - spectral index,
00136  * - minimum energy and
00137  * - maximum energy.
00138  ***************************************************************************/
00139 GModelSpectralPlaw2::GModelSpectralPlaw2(const double&  integral,
00140                                          const double&  index,
00141                                          const GEnergy& emin,
00142                                          const GEnergy& emax) :
00143                      GModelSpectral()
00144 {
00145     // Initialise members
00146     init_members();
00147 
00148     // Set parameters
00149     m_integral.value(integral);
00150     m_index.value(index);
00151     m_emin.value(emin.MeV());
00152     m_emax.value(emax.MeV());
00153 
00154     // Return
00155     return;
00156 }
00157 
00158 
00159 /***********************************************************************//**
00160  * @brief XML constructor
00161  *
00162  * @param[in] xml XML element.
00163  *
00164  * Constructs flux normalized power law spectral model by extracting
00165  * information from an XML element. See the read() method for more
00166  * information about the expected structure of the XML element.
00167  ***************************************************************************/
00168 GModelSpectralPlaw2::GModelSpectralPlaw2(const GXmlElement& xml) :
00169                      GModelSpectral()
00170 {
00171     // Initialise members
00172     init_members();
00173 
00174     // Read information from XML element
00175     read(xml);
00176 
00177     // Return
00178     return;
00179 }
00180 
00181 
00182 /***********************************************************************//**
00183  * @brief Copy constructor
00184  *
00185  * @param[in] model Spectral power law model.
00186  ***************************************************************************/
00187 GModelSpectralPlaw2::GModelSpectralPlaw2(const GModelSpectralPlaw2& model) :
00188                      GModelSpectral(model)
00189 {
00190     // Initialise members
00191     init_members();
00192 
00193     // Copy members
00194     copy_members(model);
00195 
00196     // Return
00197     return;
00198 }
00199 
00200 
00201 /***********************************************************************//**
00202  * @brief Destructor
00203  ***************************************************************************/
00204 GModelSpectralPlaw2::~GModelSpectralPlaw2(void)
00205 {
00206     // Free members
00207     free_members();
00208 
00209     // Return
00210     return;
00211 }
00212 
00213 
00214 /*==========================================================================
00215  =                                                                         =
00216  =                                Operators                                =
00217  =                                                                         =
00218  ==========================================================================*/
00219 
00220 /***********************************************************************//**
00221  * @brief Assignment operator
00222  *
00223  * @param[in] model Spectral power law model.
00224  * @return Spectral power law model.
00225  ***************************************************************************/
00226 GModelSpectralPlaw2& GModelSpectralPlaw2::operator=(const GModelSpectralPlaw2& model)
00227 {
00228     // Execute only if object is not identical
00229     if (this != &model) {
00230 
00231         // Copy base class members
00232         this->GModelSpectral::operator=(model);
00233 
00234         // Free members
00235         free_members();
00236 
00237         // Initialise members
00238         init_members();
00239 
00240         // Copy members
00241         copy_members(model);
00242 
00243     } // endif: object was not identical
00244 
00245     // Return
00246     return *this;
00247 }
00248 
00249 
00250 /*==========================================================================
00251  =                                                                         =
00252  =                              Public methods                             =
00253  =                                                                         =
00254  ==========================================================================*/
00255 
00256 /***********************************************************************//**
00257  * @brief Clear power law model
00258  ***************************************************************************/
00259 void GModelSpectralPlaw2::clear(void)
00260 {
00261     // Free class members (base and derived classes, derived class first)
00262     free_members();
00263     this->GModelSpectral::free_members();
00264 
00265     // Initialise members
00266     this->GModelSpectral::init_members();
00267     init_members();
00268 
00269     // Return
00270     return;
00271 }
00272 
00273 
00274 /***********************************************************************//**
00275  * @brief Clone power law model
00276  *
00277  * @return Pointer to deep copy of power law model
00278  ***************************************************************************/
00279 GModelSpectralPlaw2* GModelSpectralPlaw2::clone(void) const
00280 {
00281     // Clone power law model
00282     return new GModelSpectralPlaw2(*this);
00283 }
00284 
00285 
00286 /***********************************************************************//**
00287  * @brief Evaluate function
00288  *
00289  * @param[in] srcEng True photon energy.
00290  * @param[in] srcTime True photon arrival time.
00291  * @return Model value (ph/cm2/s/MeV).
00292  *
00293  * Computes
00294  *
00295  * \f[
00296  *    S_{\rm E}(E | t) = {\tt m\_integral}
00297  *    \frac{{\tt m\_index}+1}
00298  *         {{\tt e\_max}^{{\tt m\_index}+1} -
00299  *          {\tt e\_min}^{{\tt m\_index}+1}}
00300  *    E^{\tt m\_index}
00301  * \f]
00302  *
00303  * for \f${\tt m\_index} \ne -1\f$ and
00304  *
00305  * \f[
00306  *    S_{\rm E}(E | t) = 
00307  *    \frac{{\tt m\_integral}}
00308  *         {\log {\tt e\_max} - \log {\tt e\_min}}
00309  *    E^{\tt m\_index}
00310  * \f]
00311  *
00312  * for \f${\tt m\_index} = -1\f$, where
00313  * - \f${\tt e\_min}\f$ is the minimum energy of an interval,
00314  * - \f${\tt e\_max}\f$ is the maximum energy of an interval,
00315  * - \f${\tt m\_integral}\f$ is the integral flux between 
00316  *   \f${\tt e\_min}\f$ and \f${\tt e\_max}\f$, and
00317  * - \f${\tt m\_index}\f$ is the spectral index.
00318  ***************************************************************************/
00319 double GModelSpectralPlaw2::eval(const GEnergy& srcEng,
00320                                  const GTime&   srcTime) const
00321 {
00322     // Update precomputed values
00323     update(srcEng);
00324 
00325     // Compute function value
00326     double value = m_integral.value() * m_norm * m_power;
00327 
00328     // Compile option: Check for NaN/Inf
00329     #if defined(G_NAN_CHECK)
00330     if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) {
00331         std::cout << "*** ERROR: GModelSpectralPlaw2::eval";
00332         std::cout << "(srcEng=" << srcEng;
00333         std::cout << ", srcTime=" << srcTime << "):";
00334         std::cout << " NaN/Inf encountered";
00335         std::cout << " (value=" << value;
00336         std::cout << ", integral=" << integral();
00337         std::cout << ", m_norm=" << m_norm;
00338         std::cout << ", m_power=" << m_power;
00339         std::cout << ")" << std::endl;
00340     }
00341     #endif
00342 
00343     // Return
00344     return value;
00345 }
00346 
00347 
00348 /***********************************************************************//**
00349  * @brief Evaluate function and gradients
00350  *
00351  * @param[in] srcEng True photon energy.
00352  * @param[in] srcTime True photon arrival time.
00353  * @return Model value (ph/cm2/s/MeV).
00354  *
00355  * Computes
00356  *
00357  * \f[
00358  *    S_{\rm E}(E | t) = {\tt m\_integral}
00359  *    \frac{{\tt m\_index}+1}
00360  *         {{\tt e\_max}^{{\tt m\_index}+1} -
00361  *          {\tt e\_min}^{{\tt m\_index}+1}}
00362  *    E^{\tt m\_index}
00363  * \f]
00364  *
00365  * for \f${\tt m\_index} \ne -1\f$ and
00366  *
00367  * \f[
00368  *    S_{\rm E}(E | t) = 
00369  *    \frac{{\tt m\_integral}}
00370  *         {\log {\tt e\_max} - \log {\tt e\_min}}
00371  *    E^{\tt m\_index}
00372  * \f]
00373  *
00374  * for \f${\tt m\_index} = -1\f$, where
00375  * - \f${\tt e\_min}\f$ is the minimum energy of an interval,
00376  * - \f${\tt e\_max}\f$ is the maximum energy of an interval,
00377  * - \f${\tt m\_integral}\f$ is the integral flux between 
00378  *   \f${\tt e\_min}\f$ and \f${\tt e\_max}\f$, and
00379  * - \f${\tt m\_index}\f$ is the spectral index.
00380  *
00381  * The method also evaluates the partial derivatives of the model with
00382  * respect to the parameters using
00383  *
00384  * \f[
00385  *    \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_integral}} =
00386  *      \frac{S_{\rm E}(E | t)}{{\tt m\_integral}}
00387  * \f]
00388  *
00389  * \f[
00390  *    \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_index}} =
00391  *      S_{\rm E}(E | t) \,
00392  *      \left( \frac{1}{{\tt m\_index}+1} -
00393  *             \frac{\log({\tt e\_max}) {\tt e\_max}^{{\tt m\_index}+1} -
00394  *                   \log({\tt e\_min}) {\tt e\_min}^{{\tt m\_index}+1}}
00395  *                        {{\tt e\_max}^{{\tt m\_index}+1} -
00396  *                         {\tt e\_min}^{{\tt m\_index}+1}}
00397  *                 + \ln(E) \right)
00398  * \f]
00399  *
00400  * for \f${\tt m\_index} \ne -1\f$ and
00401  *
00402  * \f[
00403  *    \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_index}} =
00404  *      S_{\rm E}(E | t) \, \ln(E)
00405  * \f]
00406  *
00407  * for \f${\tt m\_index} = -1\f$.
00408  *
00409  * No partial derivatives are supported for the energy boundaries.
00410  ***************************************************************************/
00411 double GModelSpectralPlaw2::eval_gradients(const GEnergy& srcEng,
00412                                            const GTime&   srcTime)
00413 {
00414     // Initialise gradients
00415     double g_integral = 0.0;
00416     double g_index    = 0.0;
00417     
00418     // Update precomputed values
00419     update(srcEng);
00420 
00421     // Compute function value
00422     double value = m_integral.value() * m_norm * m_power;
00423 
00424     // Integral flux gradient
00425     if (m_integral.is_free() && m_integral.factor_value() > 0.0) {
00426          g_integral = value / m_integral.factor_value();
00427     }
00428 
00429     // Index gradient
00430     if (m_index.is_free()) {
00431         g_index = value * (m_g_norm + gammalib::ln10 * srcEng.log10MeV()) *
00432                   m_index.scale();
00433     }
00434 
00435     // Set gradients
00436     m_integral.factor_gradient(g_integral);
00437     m_index.factor_gradient(g_index);
00438 
00439     // Compile option: Check for NaN/Inf
00440     #if defined(G_NAN_CHECK)
00441     if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) {
00442         std::cout << "*** ERROR: GModelSpectralPlaw2::eval_gradients";
00443         std::cout << "(srcEng=" << srcEng;
00444         std::cout << ", srcTime=" << srcTime << "):";
00445         std::cout << " NaN/Inf encountered";
00446         std::cout << " (value=" << value;
00447         std::cout << ", integral=" << integral();
00448         std::cout << ", m_norm=" << m_norm;
00449         std::cout << ", m_power=" << m_power;
00450         std::cout << ", g_integral=" << g_integral;
00451         std::cout << ", g_index=" << g_index;
00452         std::cout << ")" << std::endl;
00453     }
00454     #endif
00455 
00456     // Return
00457     return value;
00458 }
00459 
00460 
00461 /***********************************************************************//**
00462  * @brief Returns model photon flux between [emin, emax] (units: ph/cm2/s)
00463  *
00464  * @param[in] emin Minimum photon energy.
00465  * @param[in] emax Minimum photon energy.
00466  * @return Photon flux (ph/cm2/s).
00467  *
00468  * Computes
00469  *
00470  * \f[
00471  *    \int_{\tt emin}^{\tt emax} S_{\rm E}(E | t) dE
00472  * \f]
00473  *
00474  * where
00475  * - [@p emin, @p emax] is an energy interval, and
00476  * - \f$S_{\rm E}(E | t)\f$ is the spectral model (ph/cm2/s/MeV).
00477  ***************************************************************************/
00478 double GModelSpectralPlaw2::flux(const GEnergy& emin,
00479                                  const GEnergy& emax) const
00480 {
00481     // Initialise flux
00482     double flux = 0.0;
00483 
00484     // Compute only if integration range is valid
00485     if (emin < emax) {
00486 
00487         // Case A: Index is not -1
00488         if (index() != -1.0) {
00489             double gamma        = m_index.value() + 1.0;
00490             double pow_emin     = std::pow(emin.MeV(), gamma);
00491             double pow_emax     = std::pow(emax.MeV(), gamma);
00492             double pow_ref_emin = std::pow(this->emin().MeV(), gamma);
00493             double pow_ref_emax = std::pow(this->emax().MeV(), gamma);
00494             double factor       = (pow_emax - pow_emin) /
00495                                   (pow_ref_emax - pow_ref_emin);
00496             flux                = m_integral.value() * factor;
00497         }
00498 
00499         // Case B: Index is -1
00500         else {
00501             double log_emin     = std::log(emin.MeV());
00502             double log_emax     = std::log(emax.MeV());
00503             double log_ref_emin = std::log(this->emin().MeV());
00504             double log_ref_emax = std::log(this->emax().MeV());
00505             double factor       = (log_emax - log_emin) /
00506                                   (log_ref_emax - log_ref_emin);
00507             flux                = m_integral.value() * factor;
00508         }
00509 
00510     } // endif: integration range was valid
00511 
00512     // Return flux
00513     return flux;
00514 }
00515 
00516 
00517 /***********************************************************************//**
00518  * @brief Returns model energy flux between [emin, emax] (units: ph/cm2/s)
00519  *
00520  * @param[in] emin Minimum photon energy.
00521  * @param[in] emax Minimum photon energy.
00522  * @return Photon flux (ph/cm2/s).
00523  *
00524  * Computes
00525  *
00526  * \f[
00527  *    \int_{\tt emin}^{\tt emax} S_{\rm E}(E | t) E \, dE
00528  * \f]
00529  *
00530  * where
00531  * - [@p emin, @p emax] is an energy interval, and
00532  * - \f$S_{\rm E}(E | t)\f$ is the spectral model (ph/cm2/s/MeV).
00533  ***************************************************************************/
00534 double GModelSpectralPlaw2::eflux(const GEnergy& emin,
00535                                   const GEnergy& emax) const
00536 {
00537     // Initialise flux
00538     double eflux = 0.0;
00539 
00540     // Compute only if integration range is valid
00541     if (emin < emax) {
00542 
00543         // Compute power law normalization
00544         double norm;
00545         if (index() != -1.0) {
00546             double gamma        = m_index.value() + 1.0;
00547             double pow_ref_emin = std::pow(this->emin().MeV(), gamma);
00548             double pow_ref_emax = std::pow(this->emax().MeV(), gamma);
00549             norm = m_integral.value() * gamma / (pow_ref_emax - pow_ref_emin);
00550         }
00551         else {
00552             double log_ref_emin = std::log(this->emin().MeV());
00553             double log_ref_emax = std::log(this->emax().MeV());
00554             norm = m_integral.value() / (log_ref_emax - log_ref_emin);
00555         }
00556 
00557         // Compute energy flux
00558         if (index() != -2.0) {
00559             double gamma    = m_index.value() + 2.0;
00560             double pow_emin = std::pow(emin.MeV(), gamma);
00561             double pow_emax = std::pow(emax.MeV(), gamma);
00562             eflux = norm / gamma * (pow_emax - pow_emin);
00563         }
00564 
00565         // Case B: Index is -2
00566         else {
00567             double log_emin = std::log(emin.MeV());
00568             double log_emax = std::log(emax.MeV());
00569             eflux = norm * (log_emax - log_emin);
00570         }
00571 
00572         // Convert from MeV/cm2/s to erg/cm2/s
00573         eflux *= gammalib::MeV2erg;
00574 
00575     } // endif: integration range was valid
00576 
00577     // Return flux
00578     return eflux;
00579 }
00580 
00581 
00582 /***********************************************************************//**
00583  * @brief Returns MC energy between [emin, emax]
00584  *
00585  * @param[in] emin Minimum photon energy.
00586  * @param[in] emax Maximum photon energy.
00587  * @param[in] time True photon arrival time.
00588  * @param[in,out] ran Random number generator.
00589  * @return Energy.
00590  *
00591  * @exception GException::erange_invalid
00592  *            Energy range is invalid (emin < emax required).
00593  *
00594  * Returns Monte Carlo energy by randomly drawing from a power law.
00595  ***************************************************************************/
00596 GEnergy GModelSpectralPlaw2::mc(const GEnergy& emin,
00597                                 const GEnergy& emax,
00598                                 const GTime&   time,
00599                                 GRan&          ran) const
00600 {
00601     // Throw an exception if energy range is invalid
00602     if (emin >= emax) {
00603         throw GException::erange_invalid(G_MC, emin.MeV(), emax.MeV(),
00604               "Minimum energy < maximum energy required.");
00605     }
00606 
00607     // Allocate energy
00608     GEnergy energy;
00609 
00610     // Case A: Index is not -1
00611     if (index() != -1.0) {
00612         double exponent = index() + 1.0;
00613         double e_max    = std::pow(emax.MeV(), exponent);
00614         double e_min    = std::pow(emin.MeV(), exponent);
00615         double u        = ran.uniform();
00616         double eng      = (u > 0.0) 
00617                           ? std::exp(std::log(u * (e_max - e_min) + e_min) / exponent)
00618                           : 0.0;
00619         energy.MeV(eng);
00620     }
00621 
00622     // Case B: Index is -1
00623     else {
00624         double e_max = std::log(emax.MeV());
00625         double e_min = std::log(emin.MeV());
00626         double u     = ran.uniform();
00627         double eng   = std::exp(u * (e_max - e_min) + e_min);
00628         energy.MeV(eng);
00629     }
00630 
00631     // Return energy
00632     return energy;
00633 }
00634 
00635 
00636 /***********************************************************************//**
00637  * @brief Read model from XML element
00638  *
00639  * @param[in] xml XML element.
00640  *
00641  * Reads the spectral information from an XML element.
00642  ***************************************************************************/
00643 void GModelSpectralPlaw2::read(const GXmlElement& xml)
00644 {
00645     // Get parameter pointers
00646     const GXmlElement* integral = gammalib::xml_get_par(G_READ, xml, m_integral.name());
00647     const GXmlElement* index    = gammalib::xml_get_par(G_READ, xml, m_index.name());
00648     const GXmlElement* emin     = gammalib::xml_get_par(G_READ, xml, m_emin.name());
00649     const GXmlElement* emax     = gammalib::xml_get_par(G_READ, xml, m_emax.name());
00650 
00651     // Read parameters
00652     m_integral.read(*integral);
00653     m_index.read(*index);
00654     m_emin.read(*emin);
00655     m_emax.read(*emax);
00656 
00657     // Return
00658     return;
00659 }
00660 
00661 
00662 /***********************************************************************//**
00663  * @brief Write model into XML element
00664  *
00665  * @param[in] xml XML element.
00666  *
00667  * @exception GException::model_invalid_spectral
00668  *            Existing XML element is not of type "PowerLaw2"
00669  *
00670  * Writes the spectral information into an XML element.
00671  ***************************************************************************/
00672 void GModelSpectralPlaw2::write(GXmlElement& xml) const
00673 {
00674     // Set model type
00675     if (xml.attribute("type") == "") {
00676         xml.attribute("type", type());
00677     }
00678 
00679     // Verify model type
00680     if (xml.attribute("type") != type()) {
00681         throw GException::model_invalid_spectral(G_WRITE, xml.attribute("type"),
00682               "Spectral model is not of type \""+type()+"\".");
00683     }
00684 
00685     // Get XML parameters
00686     GXmlElement* integral = gammalib::xml_need_par(G_WRITE, xml, m_integral.name());
00687     GXmlElement* index    = gammalib::xml_need_par(G_WRITE, xml, m_index.name());
00688     GXmlElement* emin     = gammalib::xml_need_par(G_WRITE, xml, m_emin.name());
00689     GXmlElement* emax     = gammalib::xml_need_par(G_WRITE, xml, m_emax.name());
00690 
00691     // Write parameters
00692     m_integral.write(*integral);
00693     m_index.write(*index);
00694     m_emin.write(*emin);
00695     m_emax.write(*emax);
00696 
00697     // Return
00698     return;
00699 }
00700 
00701 
00702 /***********************************************************************//**
00703  * @brief Print power law information
00704  *
00705  * @param[in] chatter Chattiness (defaults to NORMAL).
00706  * @return String containing power law information.
00707  ***************************************************************************/
00708 std::string GModelSpectralPlaw2::print(const GChatter& chatter) const
00709 {
00710     // Initialise result string
00711     std::string result;
00712 
00713     // Continue only if chatter is not silent
00714     if (chatter != SILENT) {
00715 
00716         // Append header
00717         result.append("=== GModelSpectralPlaw2 ===");
00718 
00719         // Append information
00720         result.append("\n"+gammalib::parformat("Number of parameters"));
00721         result.append(gammalib::str(size()));
00722         for (int i = 0; i < size(); ++i) {
00723             result.append("\n"+m_pars[i]->print(chatter));
00724         }
00725 
00726     } // endif: chatter was not silent
00727 
00728     // Return result
00729     return result;
00730 }
00731 
00732 
00733 /*==========================================================================
00734  =                                                                         =
00735  =                             Private methods                             =
00736  =                                                                         =
00737  ==========================================================================*/
00738 
00739 /***********************************************************************//**
00740  * @brief Initialise class members
00741  ***************************************************************************/
00742 void GModelSpectralPlaw2::init_members(void)
00743 {
00744     // Initialise model type
00745     m_type = "PowerLaw";
00746 
00747     // Initialise integral flux
00748     m_integral.clear();
00749     m_integral.name("PhotonFlux");
00750     m_integral.unit("ph/cm2/s");
00751     m_integral.scale(1.0);
00752     m_integral.value(1.0);       // default: 1.0
00753     m_integral.range(0.0, 10.0); // range:   [0,10]
00754     m_integral.free();
00755     m_integral.gradient(0.0);
00756     m_integral.has_grad(true);
00757 
00758     // Initialise powerlaw index
00759     m_index.clear();
00760     m_index.name("Index");
00761     m_index.scale(1.0);
00762     m_index.value(-2.0);        // default: -2.0
00763     m_index.range(-10.0,+10.0); // range:   [-10,+10]
00764     m_index.free();
00765     m_index.gradient(0.0);
00766     m_index.has_grad(true);
00767 
00768     // Initialise lower limit
00769     m_emin.clear();
00770     m_emin.name("LowerLimit");
00771     m_emin.unit("MeV");
00772     m_emin.scale(1.0);
00773     m_emin.value(100.0);         // default: 100
00774     m_emin.range(0.001, 1.0e15); // range:   [0.001, 1e15]
00775     m_emin.fix();
00776     m_emin.gradient(0.0);
00777     m_emin.has_grad(false);
00778 
00779     // Initialise upper limit
00780     m_emax.clear();
00781     m_emax.name("UpperLimit");
00782     m_emax.unit("MeV");
00783     m_emax.scale(1.0);
00784     m_emax.value(500000.0);      // default: 500000
00785     m_emin.range(0.001, 1.0e15); // range:   [0.001, 1e15]
00786     m_emax.fix();
00787     m_emax.gradient(0.0);
00788     m_emax.has_grad(false);
00789 
00790     // Set parameter pointer(s)
00791     m_pars.clear();
00792     m_pars.push_back(&m_integral);
00793     m_pars.push_back(&m_index);
00794     m_pars.push_back(&m_emin);
00795     m_pars.push_back(&m_emax);
00796 
00797     // Initialise last parameters (for fast computation)
00798     m_log_emin        = 0.0;
00799     m_log_emax        = 0.0;
00800     m_pow_emin        = 0.0;
00801     m_pow_emax        = 0.0;
00802     m_norm            = 0.0;
00803     m_power           = 0.0;
00804     m_last_integral   = 0.0;
00805     m_last_index      = 1000.0;
00806     m_last_emin.MeV(0.0);
00807     m_last_emax.MeV(0.0);
00808     m_last_energy.MeV(0.0);
00809     m_last_value      = 0.0;
00810     m_last_g_integral = 0.0;
00811     m_last_g_index    = 0.0;
00812 
00813     // Return
00814     return;
00815 }
00816 
00817 
00818 /***********************************************************************//**
00819  * @brief Copy class members
00820  *
00821  * @param[in] model Spectral power law model.
00822  ***************************************************************************/
00823 void GModelSpectralPlaw2::copy_members(const GModelSpectralPlaw2& model)
00824 {
00825     // Copy members
00826     m_type     = model.m_type;
00827     m_integral = model.m_integral;
00828     m_index    = model.m_index;
00829     m_emin     = model.m_emin;
00830     m_emax     = model.m_emax;
00831 
00832     // Set parameter pointer(s)
00833     m_pars.clear();
00834     m_pars.push_back(&m_integral);
00835     m_pars.push_back(&m_index);
00836     m_pars.push_back(&m_emin);
00837     m_pars.push_back(&m_emax);
00838 
00839     // Copy bookkeeping information
00840     m_log_emin        = model.m_log_emin;
00841     m_log_emax        = model.m_log_emax;
00842     m_pow_emin        = model.m_pow_emin;
00843     m_pow_emax        = model.m_pow_emax;
00844     m_norm            = model.m_norm;
00845     m_power           = model.m_power;
00846     m_last_integral   = model.m_last_integral;
00847     m_last_index      = model.m_last_index;
00848     m_last_emin       = model.m_last_emin;
00849     m_last_emax       = model.m_last_emax;
00850     m_last_energy     = model.m_last_energy;
00851     m_last_value      = model.m_last_value;
00852     m_last_g_integral = model.m_last_g_integral;
00853     m_last_g_index    = model.m_last_g_index;
00854 
00855     // Return
00856     return;
00857 }
00858 
00859 
00860 /***********************************************************************//**
00861  * @brief Delete class members
00862  ***************************************************************************/
00863 void GModelSpectralPlaw2::free_members(void)
00864 {
00865     // Return
00866     return;
00867 }
00868 
00869 
00870 /***********************************************************************//**
00871  * @brief Update precomputed values
00872  *
00873  * @param[in] srcEng Source energy
00874  ***************************************************************************/
00875 void GModelSpectralPlaw2::update(const GEnergy& srcEng) const
00876 {
00877     // Compute index+1
00878     double gamma = index() + 1.0;
00879 
00880     // Change in spectral index?
00881     if (index() != m_last_index) {
00882 
00883         // Save actual spectral index
00884         m_last_index = index();
00885 
00886         // Change in energy boundaries?
00887         if (emin() != m_last_emin || emax() != m_last_emax) {
00888             m_log_emin  = std::log(emin().MeV());
00889             m_last_emin = emin();
00890             m_log_emax  = std::log(emax().MeV());
00891             m_last_emax = emax();
00892         }
00893 
00894         // Compute normalization factors
00895         if (gamma != 0.0) {
00896             m_pow_emin  = std::pow(emin().MeV(), gamma);
00897             m_pow_emax  = std::pow(emax().MeV(), gamma);
00898             double d    = m_pow_emax - m_pow_emin;
00899             m_norm      = gamma / d;
00900             m_g_norm    = 1.0/gamma - 
00901                           (m_pow_emax*m_log_emax - m_pow_emin*m_log_emin)/d;
00902         }
00903         else {
00904             m_norm   = 1.0 / (m_log_emax - m_log_emin);
00905             m_g_norm = 0.0;
00906         }
00907 
00908         // Update power law factor
00909         m_power       = std::pow(srcEng.MeV(), index());
00910         m_last_energy = srcEng;
00911 
00912     } // endif: change in spectral index
00913 
00914     // ... no change in spectral index
00915     else {
00916 
00917         // Change in energy boundaries?
00918         if (emin() != m_last_emin || emax() != m_last_emax) {
00919 
00920             // Update energy boundaries
00921             m_log_emin  = std::log(emin().MeV());
00922             m_last_emin = emin();
00923             m_log_emax  = std::log(emax().MeV());
00924             m_last_emax = emax();
00925         
00926             // Compute power law normalization
00927             if (gamma != 0.0) {
00928                 m_pow_emin  = std::pow(emin().MeV(), gamma);
00929                 m_pow_emax  = std::pow(emax().MeV(), gamma);
00930                 double d    = m_pow_emax - m_pow_emin;
00931                 m_norm      = gamma / d;
00932                 m_g_norm    = 1.0/gamma - 
00933                               (m_pow_emax*m_log_emax - m_pow_emin*m_log_emin)/d;
00934             }
00935             else {
00936                 m_norm = 1.0 / (m_log_emax - m_log_emin);
00937                 m_g_norm = 0.0;
00938             }
00939 
00940         } // endif: change in energy boundaries
00941 
00942         // Change in energy?
00943         if (srcEng != m_last_energy) {
00944             m_power       = std::pow(srcEng.MeV(), index());
00945             m_last_energy = srcEng;
00946         }
00947 
00948     } // endelse: no change in spectral index
00949 
00950     // Return
00951     return;
00952 }

Generated on Wed Jul 27 22:39:10 2016 for GammaLib by  doxygen 1.4.7