/*************************************************************************** * GModels.cpp - Model container class * * ----------------------------------------------------------------------- * * copyright (C) 2009-2012 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 GModels.cpp * @brief Model container class implementation * @author Juergen Knoedlseder */ /* __ Includes ___________________________________________________________ */ #ifdef HAVE_CONFIG_H #include #endif #include "GTools.hpp" #include "GException.hpp" #include "GModels.hpp" #include "GModel.hpp" #include "GModelRegistry.hpp" #include "GXml.hpp" #include "GXmlElement.hpp" /* __ Method name definitions ____________________________________________ */ #define G_ACCESS1 "GModels::operator[](int&)" #define G_ACCESS2 "GModels::operator[](std::string&)" #define G_SET1 "GModels::set(int&,GModel&)" #define G_SET2 "GModels::set(std::string&,GModel&)" #define G_READ "GModels::read(GXml&)" /* __ Macros _____________________________________________________________ */ /* __ Coding definitions _________________________________________________ */ /* __ Debug definitions __________________________________________________ */ /*========================================================================== = = = Constructors/destructors = = = ==========================================================================*/ /***********************************************************************//** * @brief Void constructor * * Constructs an empty model container. ***************************************************************************/ GModels::GModels(void) : GOptimizerPars() { // Initialise members init_members(); // Return return; } /***********************************************************************//** * @brief Copy constructor * * @param[in] models Model container. * * Constructs a copy of a model container. ***************************************************************************/ GModels::GModels(const GModels& models) : GOptimizerPars(models) { // Initialise members init_members(); // Copy members copy_members(models); // Return return; } /***********************************************************************//** * @brief Load constructor * * @param[in] filename XML filename. * * Constructs model container from the model information of an XML file. ***************************************************************************/ GModels::GModels(const std::string& filename) { // Initialise members init_members(); // Load XML file load(filename); // Return return; } /***********************************************************************//** * @brief Destructor * * Destroys the model container. ***************************************************************************/ GModels::~GModels(void) { // Free members free_members(); // Return return; } /*========================================================================== = = = Operators = = = ==========================================================================*/ /***********************************************************************//** * @brief Assignment operator * * @param[in] models Model container. * * Assigns a model container to the instance. ***************************************************************************/ GModels& GModels::operator= (const GModels& models) { // Execute only if object is not identical if (this != &models) { // Copy base class members this->GOptimizerPars::operator=(models); // Free members free_members(); // Initialise members init_members(); // Copy members copy_members(models); } // endif: object was not identical // Return return *this; } /***********************************************************************//** * @brief Returns pointer to model * * @param[in] index Model index [0,...,size()-1]. * * @exception GException::out_of_range * Model index is out of range. * * Returns a model pointer by index. The return value will never be NULL. ***************************************************************************/ GModel* GModels::operator[](const int& index) { // Compile option: raise exception if index is out of range #if defined(G_RANGE_CHECK) if (index < 0 || index >= size()) { throw GException::out_of_range(G_ACCESS1, index, 0, size()-1); } #endif // Return pointer return m_models[index]; } /***********************************************************************//** * @brief Returns pointer to model (const version) * * @param[in] index Model index [0,...,size()-1]. * * @exception GException::out_of_range * Model index is out of range. * * Returns a constant model pointer by index. The return value will never be * NULL. ***************************************************************************/ const GModel* GModels::operator[](const int& index) const { // Compile option: raise exception if index is out of range #if defined(G_RANGE_CHECK) if (index < 0 || index >= size()) { throw GException::out_of_range(G_ACCESS1, index, 0, size()-1); } #endif // Return pointer return m_models[index]; } /***********************************************************************//** * @brief Returns pointer to model * * @param[in] name Model name. * * @exception GException::model_not_found * Model with specified name not found in container. * * Returns a model pointer by model name. The return value will never be * NULL. ***************************************************************************/ GModel* GModels::operator[](const std::string& name) { // Get parameter index int index = get_index(name); // Throw exception if parameter name was not found if (index >= size()) { throw GException::model_not_found(G_ACCESS2, name); } // Return pointer return m_models[index]; } /***********************************************************************//** * @brief Returns pointer to model (const version) * * @param[in] name Model name. * * @exception GException::model_not_found * Model with specified name not found in container. * * Returns a constant model pointer by model name. The return value will * never be NULL. ***************************************************************************/ const GModel* GModels::operator[](const std::string& name) const { // Get parameter index int index = get_index(name); // Throw exception if parameter name was not found if (index >= size()) { throw GException::model_not_found(G_ACCESS2, name); } // Return pointer return m_models[index]; } /*========================================================================== = = = Public methods = = = ==========================================================================*/ /***********************************************************************//** * @brief Clear object * * Removes all models from the container. ***************************************************************************/ void GModels::clear(void) { // Free class members (base and derived classes, derived class first) free_members(); this->GOptimizerPars::free_members(); // Initialise members this->GOptimizerPars::init_members(); init_members(); // Return return; } /***********************************************************************//** * @brief Clone instance * * Makes a deep copy of the model container instance. ***************************************************************************/ GModels* GModels::clone(void) const { return new GModels(*this); } /***********************************************************************//** * @brief Append model to container * * @param[in] model Model. * * Appends one model to the container by making a deep copy. ***************************************************************************/ void GModels::append(const GModel& model) { // Make deep copy of model GModel* model_copy = model.clone(); // If copy is valid, append it to the container if (model_copy != NULL) { m_models.push_back(model_copy); } // Set parameter pointers set_pointers(); // Return return; } /***********************************************************************//** * @brief Set model in container * * @param[in] index Model index [0,...,size()-1]. * @param[in] model Model. * * @exception GException::out_of_range * Model index is out of range. * * Set model in the container. A deep copy of the model will be made. ***************************************************************************/ void GModels::set(const int& index, const GModel& model) { // Compile option: raise exception if index is out of range #if defined(G_RANGE_CHECK) if (index < 0 || index >= size()) { throw GException::out_of_range(G_SET1, index, 0, size()-1); } #endif // Delete any existing model if (m_models[index] != NULL) delete m_models[index]; // Assign new model by cloning m_models[index] = model.clone(); // Set parameter pointers set_pointers(); // Return return; } /***********************************************************************//** * @brief Set model in container * * @param[in] name Model name. * @param[in] model Model pointer. * * @exception GException::model_not_found * Model with specified name not found in container. * * Set model in the container. A deep copy of the model will be made. ***************************************************************************/ void GModels::set(const std::string& name, const GModel& model) { // Get parameter index int index = get_index(name); // Throw exception if parameter name was not found if (index >= size()) { throw GException::model_not_found(G_SET2, name); } // Delete any existing model if (m_models[index] != NULL) delete m_models[index]; // Assign new model by cloning m_models[index] = model.clone(); // Set parameter pointers set_pointers(); // Return return; } /***********************************************************************//** * @brief Load models from XML file * * @param[in] filename XML filename. * * Loads all models that are defined in an XML file. ***************************************************************************/ void GModels::load(const std::string& filename) { // Clear any existing models clear(); // Load XML document GXml xml(filename); // Read models from XML document read(xml); // Return return; } /***********************************************************************//** * @brief Save models into XML file * * @param[in] filename XML filename. * * Saves all models in the container into an XML file. ***************************************************************************/ void GModels::save(const std::string& filename) const { // Declare empty XML document GXml xml; // Write models into XML file write(xml); // Save XML document xml.save(filename); // Return return; } /***********************************************************************//** * @brief Read models from XML document * * @param[in] xml XML document. * * @exception GException::model_invalid * Invalid model type encountered. * * Read models from the first source library found in the XML document. It is * assumed that each model is composed of a spectral and a spatial model * (Fermi-LAT style). The decoding of the spatial and spectral XML elements * is done within a GModel constructor. * * @todo Sources names are not verified so far for uniqueness. This would be * required to achieve an unambiguous update of parameters in an already * existing XML file when using the write method. Also, no control is * performed that only a single spectral and spatial component exists in * each source definition. ***************************************************************************/ void GModels::read(const GXml& xml) { // Get pointer on source library GXmlElement* lib = xml.element("source_library", 0); // Loop over all sources int n = lib->elements("source"); for (int i = 0; i < n; ++i) { // Get pointer on source GXmlElement* src = static_cast(lib->element("source", i)); // Get model type std::string type = src->attribute("type"); // Get model GModelRegistry registry; GModel* ptr = registry.alloc(type); // If model if valid then read model from XML file if (ptr != NULL) { ptr->read(*src); } // ... otherwise throw an exception else { throw GException::model_invalid(G_READ, type); } // Append model append(*ptr); // Free model (appending clones the model) delete ptr; } // endfor: looped over all sources // Return return; } /***********************************************************************//** * @brief Write models into XML document * * @param[in] xml XML document. * * Write models into the first source library that is found in the XML * document. In case that no source library exists, one is added to the * document. ***************************************************************************/ void GModels::write(GXml& xml) const { // If there is no source library then append one if (xml.elements("source_library") == 0) { xml.append(new GXmlElement("source_library title=\"source library\"")); } // Get pointer on source library GXmlElement* lib = xml.element("source_library", 0); // Write all sources into library for (int i = 0; i < size(); ++i) { m_models[i]->write(*lib); } // Return return; } /***********************************************************************//** * @brief Evaluate sum of all models * * @param[in] event Observed event. * @param[in] obs Observation. * * Evaluates the sum of all models for the specified event and observation. ***************************************************************************/ double GModels::eval(const GEvent& event, const GObservation& obs) const { // Initialise function value double value = 0.0; // Evaluate function for all models for (int i = 0; i < size(); ++i) { value += m_models[i]->eval(event, obs); } // Return return value; } /***********************************************************************//** * @brief Evaluate sum and gradients of all models * * @param[in] event Observed event. * @param[in] obs Observation. * * Evaluates the sum and the parameter gradients of all models for the * specified event and observation. ***************************************************************************/ double GModels::eval_gradients(const GEvent& event, const GObservation& obs) const { // Initialise function value double value = 0.0; // Evaluate function for all models for (int i = 0; i < size(); ++i) { value += m_models[i]->eval_gradients(event, obs); } // Return return value; } /***********************************************************************//** * @brief Print models * * Prints all models into a string. ***************************************************************************/ std::string GModels::print(void) const { // Initialise result string std::string result; // Append header result.append("=== GModels ==="); result.append("\n"+parformat("Number of models")+str(size())); result.append("\n"+parformat("Number of parameters")+str(npars())); // Append models for (int i = 0; i < size(); ++i) { result.append("\n"+m_models[i]->print()); } // Return result return result; } /*========================================================================== = = = Private methods = = = ==========================================================================*/ /***********************************************************************//** * @brief Initialise class members ***************************************************************************/ void GModels::init_members(void) { // Initialise members m_models.clear(); // Return return; } /***********************************************************************//** * @brief Copy class members * * @param[in] models Model container. * * Makes a copy of all class members. All models are deep copied, and the * linear pointer array for parameter access through the GOptimizerPars * base class is set. ***************************************************************************/ void GModels::copy_members(const GModels& models) { // Copy models m_models.clear(); for (int i = 0; i < models.m_models.size(); ++i) { m_models.push_back((models.m_models[i]->clone())); } // Set parameter pointers set_pointers(); // Return return; } /***********************************************************************//** * @brief Delete class members * * Deallocates all models. The method loops over the model container and * deallocates the memory that has been allocated before. ***************************************************************************/ void GModels::free_members(void) { // Free models for (int i = 0; i < m_models.size(); ++i) { delete m_models[i]; m_models[i] = NULL; } // Return return; } /***********************************************************************//** * @brief Set parameter pointers * * Gathers all parameter pointers from the models into a linear array of * GModelPar pointers. This exposes all model parameters to the base class * GOptimizerPars in form of a linear array. ***************************************************************************/ void GModels::set_pointers(void) { // Clear parameters m_pars.clear(); // Gather all pointers for (int i = 0; i < size(); ++i) { for (int k = 0; k < m_models[i]->size(); ++k) { m_pars.push_back(&(*m_models[i])[k]); } } // Return return; } /***********************************************************************//** * @brief Returns index to model * * @param[in] name Model name. * * Returns index to model specified by the model name. If no model is found * the method returns the size of the model container. ***************************************************************************/ int GModels::get_index(const std::string& name) const { // Get parameter index int index = 0; for (; index < size(); ++index) { if (m_models[index]->name() == name) { break; } } // Return index return index; }