/*************************************************************************** * ctlike - CTA maximum likelihood tool * * ----------------------------------------------------------------------- * * copyright (C) 2010-2011 by Jurgen Knodlseder * * ----------------------------------------------------------------------- * * * * 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 ctlike.cpp * @brief CTA maximum likelihood tool implementation * @author J. Knodlseder */ /* __ Includes ___________________________________________________________ */ #ifdef HAVE_CONFIG_H #include #endif #include #include "ctlike.hpp" #include "GTools.hpp" /* __ Method name definitions ____________________________________________ */ #define G_GET_PARAMETERS "ctlike::get_parameters()" /* __ Debug definitions __________________________________________________ */ /* __ Coding definitions _________________________________________________ */ /*========================================================================== = = = Constructors/destructors = = = ==========================================================================*/ /***********************************************************************//** * @brief Void constructor ***************************************************************************/ ctlike::ctlike(void) : GApplication(CTLIKE_NAME, CTLIKE_VERSION) { // Initialise members init_members(); // Write header into logger log_header(); // Return return; } /***********************************************************************//** * @brief Observations constructor * * This method creates an instance of the class by copying an existing * observations container. ***************************************************************************/ ctlike::ctlike(GObservations obs) : GApplication(CTLIKE_NAME, CTLIKE_VERSION) { // Initialise members init_members(); // Set observations m_obs = obs; // Write header into logger log_header(); // Return return; } /***********************************************************************//** * @brief Command line constructor * * @param[in] argc Number of arguments in command line. * @param[in] argv Array of command line arguments. ***************************************************************************/ ctlike::ctlike(int argc, char *argv[]) : GApplication(CTLIKE_NAME, CTLIKE_VERSION, argc, argv) { // Initialise members init_members(); // Write header into logger log_header(); // Return return; } /***********************************************************************//** * @brief Copy constructor * * @param[in] app Application. ***************************************************************************/ ctlike::ctlike(const ctlike& app) : GApplication(app) { // Initialise members init_members(); // Copy members copy_members(app); // Return return; } /***********************************************************************//** * @brief Destructor ***************************************************************************/ ctlike::~ctlike(void) { // Free members free_members(); // Return return; } /*========================================================================== = = = Operators = = = ==========================================================================*/ /***********************************************************************//** * @brief Assignment operator * * @param[in] app Application. ***************************************************************************/ ctlike& ctlike::operator= (const ctlike& app) { // Execute only if object is not identical if (this != &app) { // Copy base class members this->GApplication::operator=(app); // Free members free_members(); // Initialise members init_members(); // Copy members copy_members(app); } // endif: object was not identical // Return this object return *this; } /*========================================================================== = = = Public methods = = = ==========================================================================*/ /***********************************************************************//** * @brief Clear instance ***************************************************************************/ void ctlike::clear(void) { // Free members free_members(); this->GApplication::free_members(); // Initialise members this->GApplication::init_members(); init_members(); // Return return; } /***********************************************************************//** * @brief Execute application * * This method performs a maximum likelihood analysis of a observation given * in an observation container and saves the results in an XML file. ***************************************************************************/ void ctlike::execute(void) { // Read ahead output filename so that it gets dumped correctly in the // parameters log m_outmdl = (*this)["outmdl"].filename(); // Bin the event data run(); // Save the results into XML file save(); // Return return; } /***********************************************************************//** * @brief Run maximum likelihood analysis * * The following analysis steps are performed: * 1. Read the parameters (and write them into logger) * 2. Load observation * 3. Setup models for optimizing * 4. Optimize model (and write result into logger) ***************************************************************************/ void ctlike::run(void) { // Switch screen logging on in debug mode if (logDebug()) log.cout(true); // Get parameters get_parameters(); // Write parameters into logger if (logTerse()) { log_parameters(); log << std::endl; } // Write observation(s) into logger if (logTerse()) { log << std::endl; if (m_obs.size() > 1) log.header1("Observations"); else log.header1("Observation"); log << m_obs << std::endl; } // Optimize model parameters using LM optimizer optimize_lm(); // Write results into logger if (logTerse()) { log << " Maximum log likelihood ....: " << m_logL << std::endl; log << " Npred .....................: " << m_obs.npred() << std::endl; log << m_obs.models() << std::endl; } // Return return; } /***********************************************************************//** * @brief Save results * * This method saves the fit results in a XML file. ***************************************************************************/ void ctlike::save(void) { // Write header if (logTerse()) { log << std::endl; log.header1("Save results"); } // Get output filename m_outmdl = (*this)["outmdl"].value(); // Write results out as XML model if (toupper(m_outmdl) != "NONE") m_obs.models().save(m_outmdl); // Return return; } /***********************************************************************//** * @brief Get application parameters * * GException::par_error * Invalid analysis method specified (neither BINNED nor UNBINNED). * * Get all required task parameters from the parameter file or (if specified) * by querying the user. Observation dependent parameters will only be read * if the observation container is actually empty. Observation dependent * parameters are: * "method" (analysis method), * "stat" (statistics to be used for observation), * "caldb" (calibration database), * "irf" (instrument response function), * "evfile" (event file name), and * "cntmap" (counts map file name). * The model will only be loaded if no model components exist in the * observation container. ***************************************************************************/ void ctlike::get_parameters(void) { // If there is are no models associated with the observations then // load now the model definition if (m_obs.models().size() == 0) { // Get models XML filename std::string filename = (*this)["srcmdl"].filename(); // Setup models for optimizing. m_obs.models(GModels(filename)); } // endif: no models were associated with observations // If there are no observations in container then add a single CTA // observation using the parameters from the parameter file if (m_obs.size() == 0) { // Get observation parameters m_method = toupper((*this)["method"].string()); m_stat = toupper((*this)["stat"].string()); m_caldb = (*this)["caldb"].string(); m_irf = (*this)["irf"].string(); // Case A: set-up unbinned CTA observation if (m_method == "UNBINNED") { // Get event file name std::string filename = (*this)["evfile"].filename(); // Load and append unbinned CTA observation load_unbinned(filename); } // endif: unbinned analysis mode // Case B: set-up binned CTA observation else if (m_method == "BINNED") { // Get counts map file name std::string filename = (*this)["cntmap"].filename(); // Load and append binned CTA observation load_binned(filename); } // endif: binned analysis mode // ... otherwise signal an invalid analysis method else { throw GException::par_error(G_GET_PARAMETERS, "method", "only \"BINNED\" or \"UNBINNED\" supported."); } } // endif: there was no observation in the container // Get standard parameters m_refit = (*this)["refit"].boolean(); // Return return; } /***********************************************************************//** * @brief Optimize model parameters using Levenberg-Marquardt method ***************************************************************************/ void ctlike::optimize_lm(void) { // Free any existing optimizer if (m_opt != NULL) delete m_opt; m_opt = NULL; // Allocate optimizer. The logger is only passed to the optimizer // constructor if optimizer logging is requested. GOptimizerLM* opt = (logTerse()) ? new GOptimizerLM(log) : new GOptimizerLM(); // Assign optimizer m_opt = opt; // Set optimizer parameters opt->max_iter(m_max_iter); opt->max_stalls(m_max_stall); // Write Header for optimization and indent for optimizer logging if (logTerse()) { log << std::endl; log.header1("Maximum likelihood optimisation"); log.indent(1); } // Perform LM optimization m_obs.optimize(*opt); // Optionally refit if (m_refit) m_obs.optimize(*opt); // Store maximum log likelihood value m_logL = -(opt->value()); // Write optimization results log.indent(0); if (logTerse()) { log << std::endl; log.header1("Maximum likelihood optimization results"); log << *opt << std::endl; } // Return return; } /***********************************************************************//** * @brief Load unbinned observation and append it to observations container * * @param[in] evfile Events file name. ***************************************************************************/ void ctlike::load_unbinned(const std::string& evfile) { // Declare CTA observation GCTAObservation obs; // Set statistics obs.statistics(m_stat); // Load data obs.load_unbinned(evfile); // Set reponse obs.response(m_irf, m_caldb); // Append observation to contained m_obs.append(obs); // Return return; } /***********************************************************************//** * @brief Load binned observation and append it to observations container * * @param[in] cntmap Counts map file name. ***************************************************************************/ void ctlike::load_binned(const std::string& cntmap) { // Declare CTA observation GCTAObservation obs; // Set statistics obs.statistics(m_stat); // Load data obs.load_binned(cntmap); // Set reponse obs.response(m_irf, m_caldb); // Append observation to contained m_obs.append(obs); // Return return; } /*========================================================================== = = = Private methods = = = ==========================================================================*/ /***********************************************************************//** * @brief Initialise class members ***************************************************************************/ void ctlike::init_members(void) { // Initialise members m_method.clear(); m_stat.clear(); m_caldb.clear(); m_irf.clear(); m_outmdl.clear(); m_obs.clear(); m_refit = false; m_max_iter = 100; // Set maximum number of iterations m_max_stall = 10; // Set maximum number of stalls m_logL = 0.0; m_opt = NULL; // Set logger properties log.date(true); // Return return; } /***********************************************************************//** * @brief Copy class members * * @param[in] app Application. ***************************************************************************/ void ctlike::copy_members(const ctlike& app) { // Copy attributes m_method = app.m_method; m_stat = app.m_stat; m_refit = app.m_refit; m_caldb = app.m_caldb; m_irf = app.m_irf; m_outmdl = app.m_outmdl; m_obs = app.m_obs; m_max_iter = app.m_max_iter; m_max_stall = app.m_max_stall; m_logL = app.m_logL; m_opt = app.m_opt->clone(); // Return return; } /***********************************************************************//** * @brief Delete class members ***************************************************************************/ void ctlike::free_members(void) { // Free members if (m_opt != NULL) delete m_opt; // Mark pointers as free m_opt = NULL; // Write separator into logger if (logTerse()) log << std::endl; // Return return; }