/*************************************************************************** * GModelSpatialDiffuseConst.cpp - Spatial isotropic model class * * ----------------------------------------------------------------------- * * copyright (C) 2010-2016 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 GModelSpatialDiffuseConst.cpp * @brief Isotropic spatial model class implementation * @author Juergen Knoedlseder */ /* __ Includes ___________________________________________________________ */ #ifdef HAVE_CONFIG_H #include #endif #include "GException.hpp" #include "GTools.hpp" #include "GMath.hpp" #include "GModelSpatialDiffuseConst.hpp" #include "GModelSpatialRegistry.hpp" /* __ Constants __________________________________________________________ */ /* __ Globals ____________________________________________________________ */ const GModelSpatialDiffuseConst g_spatial_const_seed; const GModelSpatialRegistry g_spatial_const_registry(&g_spatial_const_seed); #if defined(G_LEGACY_XML_FORMAT) const GModelSpatialDiffuseConst g_spatial_const_legacy_seed(true, "ConstantValue"); const GModelSpatialRegistry g_spatial_const_legacy_registry(&g_spatial_const_legacy_seed); #endif /* __ Method name definitions ____________________________________________ */ #define G_MC_NORM "GModelSpatialDiffuseConst::mc_norm(GSkyDir&, double&)" #define G_READ "GModelSpatialDiffuseConst::read(GXmlElement&)" #define G_WRITE "GModelSpatialDiffuseConst::write(GXmlElement&)" /* __ Macros _____________________________________________________________ */ /* __ Coding definitions _________________________________________________ */ /* __ Debug definitions __________________________________________________ */ /*========================================================================== = = = Constructors/destructors = = = ==========================================================================*/ /***********************************************************************//** * @brief Void constructor * * Constructs empty isotropic spatial model. ***************************************************************************/ GModelSpatialDiffuseConst::GModelSpatialDiffuseConst(void) : GModelSpatialDiffuse() { // Initialise members init_members(); // Return return; } /***********************************************************************//** * @brief Model type constructor * * @param[in] dummy Dummy flag. * @param[in] type Model type. * * Constructs empty isotropic spatial model by specifying a model @p type. ***************************************************************************/ GModelSpatialDiffuseConst::GModelSpatialDiffuseConst(const bool& dummy, const std::string& type) : GModelSpatialDiffuse() { // Initialise members init_members(); // Set model type m_type = type; // Return return; } /***********************************************************************//** * @brief XML constructor * * @param[in] xml XML element. * * Constructs isotropic spatial model by extracting information from an XML * element. See the read() method for more information about the expected * structure of the XML element. ***************************************************************************/ GModelSpatialDiffuseConst::GModelSpatialDiffuseConst(const GXmlElement& xml) : GModelSpatialDiffuse() { // Initialise members init_members(); // Read information from XML element read(xml); // Return return; } /***********************************************************************//** * @brief Value constructor * * @param[in] value Isotropic intensity value (\f$sr^{-1}\f$). * * Constructs isotropic spatial model by assigning an intensity of @p value * in units of \f$sr^{-1}\f$ to the diffuse emission. This constructor * explicitly sets the @a m_value member of the model. ***************************************************************************/ GModelSpatialDiffuseConst::GModelSpatialDiffuseConst(const double& value) : GModelSpatialDiffuse() { // Initialise members init_members(); // Set parameter m_value.value(value); // Perform autoscaling of parameter autoscale(); // Return return; } /***********************************************************************//** * @brief Copy constructor * * @param[in] model Isotropic spatial model. * * Constructs isotropic spatial model by copying another isotropic spatial * model. ***************************************************************************/ GModelSpatialDiffuseConst::GModelSpatialDiffuseConst(const GModelSpatialDiffuseConst& model) : GModelSpatialDiffuse(model) { // Initialise members init_members(); // Copy members copy_members(model); // Return return; } /***********************************************************************//** * @brief Destructor * * Destructs isotropic spatial model. ***************************************************************************/ GModelSpatialDiffuseConst::~GModelSpatialDiffuseConst(void) { // Free members free_members(); // Return return; } /*========================================================================== = = = Operators = = = ==========================================================================*/ /***********************************************************************//** * @brief Assignment operator * * @param[in] model Isotropic spatial model. * @return Isotropic spatial model. * * Assigns an isotropic spatial model. ***************************************************************************/ GModelSpatialDiffuseConst& GModelSpatialDiffuseConst::operator=(const GModelSpatialDiffuseConst& model) { // Execute only if object is not identical if (this != &model) { // Copy base class members this->GModelSpatialDiffuse::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 isotropic spatial model * * Clears the isotropic spatial model. This method is equivalent to creating * an isotropic spatial model using the void constructor. ***************************************************************************/ void GModelSpatialDiffuseConst::clear(void) { // Free class members free_members(); this->GModelSpatialDiffuse::free_members(); this->GModelSpatial::free_members(); // Initialise members this->GModelSpatial::init_members(); this->GModelSpatialDiffuse::init_members(); init_members(); // Return return; } /***********************************************************************//** * @brief Clone isotropic spatial model * * @return Pointer to deep copy of isotropic spatial model. * * Returns a pointer to a deep copy of the isotropic spatial model. ***************************************************************************/ GModelSpatialDiffuseConst* GModelSpatialDiffuseConst::clone(void) const { // Clone isotropic spatial model return new GModelSpatialDiffuseConst(*this); } /***********************************************************************//** * @brief Evaluate isotropic spatial model value * * @param[in] photon Incident photon. * @param[in] gradients Compute gradients? * @return Model value (\f$sr^{-1}\f$). * * Evaluates the isotropic spatial model for a given @p photon, characterised * by a sky direction, energy and arrival time \f$(\vec{p},E,t)\f$. By * definition, the isotropic spatial model and gradient are independent of * sky direction, energy and time. The model value is given by * * \f[ * M_\mathrm{S}(\vec{p}|E,t) = \frac{v}{4\pi} * \f] * * where \f$v\f$ is the value() parameter, which is divided by the solid * angle \f$4\pi\f$ of the celestial sphere. * * If the @p gradients flag is true the method will also evaluate the partial * derivatives of the model. The value() gradient is given by * * \f[ * \frac{\partial M_\mathrm{S}(\vec{p}|E,t)}{\partial v_v} = * \frac{v_s}{4\pi} * \f] * * where \f$v=v_v v_s\f$ is the factorisation of the value() parameter into * a value \f$v_v\f$ and scale \f$v_s\f$ term. ***************************************************************************/ double GModelSpatialDiffuseConst::eval(const GPhoton& photon, const bool& gradients) const { // Set normalization constant const double norm = 1.0 / gammalib::fourpi; // Compute model value double value = norm * m_value.value(); // Optionally compute partial derivatives if (gradients) { // Compute partial derivatives of the parameter values double g_norm = (m_value.is_free()) ? norm * m_value.scale() : 0.0; // Set gradient m_value.factor_gradient(g_norm); } // endif: computed partial derivatives // Return model value return (value); } /***********************************************************************//** * @brief Return MC sky direction * * @param[in] energy Photon energy. * @param[in] time Photon arrival time. * @param[in,out] ran Random number generator. * @return Sky direction. * * Returns an arbitrary direction on the celestial sphere within a simulation * cone region that has been defined by a previous call to the mc_norm() * method (if no such call was made the entire sky will be assumed as the * simulation cone). The sky direction is independent of event @p energy and * arrival @p time. ***************************************************************************/ GSkyDir GModelSpatialDiffuseConst::mc(const GEnergy& energy, const GTime& time, GRan& ran) const { // Simulate offset from simulation cone centre double theta = std::acos(1.0 - ran.uniform() * (1.0 - m_mc_cos_radius)) * gammalib::rad2deg; double phi = 360.0 * ran.uniform(); // Initialise sky direction with simulation cone centre GSkyDir dir(m_mc_centre); // Rotate sky direction by offset angles (phi, theta) dir.rotate_deg(phi, theta); // Return sky direction return dir; } /***********************************************************************//** * @brief Return normalization of constant diffuse source for Monte Carlo * simulations * * @param[in] dir Centre of simulation cone. * @param[in] radius Radius of simulation cone (deg). * @return Model normalization. * * @exception GException::invalid_argument * Radius of simulation cone not coprised in [0,180] degrees. * * Returns the normalization of a constant diffuse source. The normalization * is given by the product between the fraction \f$f\f$ of the sky covered * by the simulation cone * * \f[ * f = \frac{2\pi \left( 1-\cos(r) \right)}{4\pi} * \f] * * (where \f$r\f$ is the radius of the simulation cone) and the model * parameter value(). The normalization only depends of the radius of the * simulation cone and is invariant to its centre. ***************************************************************************/ double GModelSpatialDiffuseConst::mc_norm(const GSkyDir& dir, const double& radius) const { // Throw exception if the radius is invalid if (radius < 0.0 || radius > 180.0) { std::string msg = "Invalid simulation cone radius "+ gammalib::str(radius)+" specified. Please provide " "a value comprised within 0 and 180 degrees."; throw GException::invalid_argument(G_MC_NORM, msg); } // Store cosine of simulation cone radius and cone centre m_mc_centre = dir; m_mc_cos_radius = std::cos(radius * gammalib::deg2rad); // Compute fraction of sky covered by the simulation cone double fraction = 0.5 * (1.0 - m_mc_cos_radius); // Multiply by normalization value of model double norm = fraction * value(); // Return normalization return (norm); } /***********************************************************************//** * @brief Read model from XML element * * @param[in] xml XML element. * * Read the isotropic source model information from an XML element. The XML * element is expected to have the following format: * * * * * ***************************************************************************/ void GModelSpatialDiffuseConst::read(const GXmlElement& xml) { // Get value parameter const GXmlElement* par = gammalib::xml_get_par(G_READ, xml, "Value"); // Read value parameter m_value.read(*par); // Return return; } /***********************************************************************//** * @brief Write model into XML element * * @param[in] xml XML element. * * @exception GException::model_invalid_spatial * Existing XML element is not of type "ConstantValue" * * Write the isotropic source model information into an XML element. The XML * element will have the following format: * * * * * ***************************************************************************/ void GModelSpatialDiffuseConst::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_spatial(G_WRITE, xml.attribute("type"), "Spatial model is not of type \""+type()+"\"."); } // Get or create Value parameter GXmlElement* par = gammalib::xml_need_par(G_WRITE, xml, "Value"); // Write parameter m_value.write(*par); // Return return; } /***********************************************************************//** * @brief Print isotropic source model information * * @param[in] chatter Chattiness (defaults to NORMAL). * @return String containing model information. ***************************************************************************/ std::string GModelSpatialDiffuseConst::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("=== GModelSpatialDiffuseConst ==="); // Append parameters 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 GModelSpatialDiffuseConst::init_members(void) { // Initialise model type m_type = "DiffuseIsotropic"; // Initialise Value m_value.clear(); m_value.name("Value"); m_value.fix(); m_value.value(1.0); m_value.scale(1.0); m_value.range(0.0, 10.0); m_value.gradient(0.0); m_value.has_grad(true); // Initialise other members m_mc_centre.clear(); m_mc_cos_radius = -1.0; // Set simulation cone to allsky // Set parameter pointer(s) m_pars.clear(); m_pars.push_back(&m_value); // Return return; } /***********************************************************************//** * @brief Copy class members * * @param[in] model Isotropic spatial model. ***************************************************************************/ void GModelSpatialDiffuseConst::copy_members(const GModelSpatialDiffuseConst& model) { // Copy members m_type = model.m_type; m_value = model.m_value; m_mc_centre = model.m_mc_centre; m_mc_cos_radius = model.m_mc_cos_radius; // Set parameter pointer(s) m_pars.clear(); m_pars.push_back(&m_value); // Return return; } /***********************************************************************//** * @brief Delete class members ***************************************************************************/ void GModelSpatialDiffuseConst::free_members(void) { // Return return; }