diff --git a/configure.ac b/configure.ac
index 8b2c298..ac683df 100644
--- a/configure.ac
+++ b/configure.ac
@@ -887,6 +887,7 @@ AC_CONFIG_FILES([Makefile
src/ctbkgcube/Makefile
src/ctcubemask/Makefile
src/cttsmap/Makefile
+ src/ctbutterfly/Makefile
src/support/Makefile
src/ctools-setup
test/Makefile
diff --git a/pyext/ctbutterfly.i b/pyext/ctbutterfly.i
new file mode 100644
index 0000000..627ebce
--- /dev/null
+++ b/pyext/ctbutterfly.i
@@ -0,0 +1,62 @@
+/***************************************************************************
+ * ctbutterfly - butterfly calculation tool *
+ * ----------------------------------------------------------------------- *
+ * copyright (C) 2014 by Michael Mayer *
+ * ----------------------------------------------------------------------- *
+ * *
+ * 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 ctbutterfly.i
+ * @brief tool for butterfly calculations
+ * @author Michael Mayer
+ */
+%{
+/* Put headers and other declarations here that are needed for compilation */
+#include "ctbutterfly.hpp"
+%}
+
+
+/***********************************************************************//**
+ * @class ctbutterfly
+ *
+ * @brief butterfly calculation tool
+ ***************************************************************************/
+class ctbutterfly : public ctool {
+public:
+ // Constructors and destructors
+ ctbutterfly(void);
+ explicit ctbutterfly(const GObservations& obs);
+ ctbutterfly(int argc, char *argv[]);
+ ctbutterfly(const ctbutterfly& app);
+ virtual ~ctbutterfly(void);
+
+ // Methods
+ void clear(void);
+ void run(void);
+ void save(void);
+ const GObservations& obs(void) const;
+
+};
+
+
+/***********************************************************************//**
+ * @brief butterfly calculation tool Python extensions
+ ***************************************************************************/
+%extend ctbutterfly {
+ ctbutterfly copy() {
+ return (*self);
+ }
+}
diff --git a/pyext/ctools/ctools.i b/pyext/ctools/ctools.i
index c559bee..f84bd71 100755
--- a/pyext/ctools/ctools.i
+++ b/pyext/ctools/ctools.i
@@ -57,3 +57,4 @@
%include "ctbkgcube.i"
%include "ctcubemask.i"
%include "cttsmap.i"
+%include "ctbutterfly.i"
diff --git a/src/Makefile.am b/src/Makefile.am
index 8cd645c..bb0cddf 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -16,7 +16,8 @@ SUBDIRS = support \
ctpsfcube \
ctbkgcube \
ctcubemask \
- cttsmap
+ cttsmap \
+ ctbutterfly
# Scripts to be distributed
scripts = ctools-setup \
@@ -39,7 +40,8 @@ libctools_la_LIBADD = support/libsupport.la \
ctpsfcube/libctpsfcube.la \
ctbkgcube/libctbkgcube.la \
ctcubemask/libctcubemask.la \
- cttsmap/libcttsmap.la
+ cttsmap/libcttsmap.la \
+ ctbutterfly/libctbutterfly.la
# Distribute scripts
diff --git a/src/ctbutterfly/ctbutterfly.cpp b/src/ctbutterfly/ctbutterfly.cpp
new file mode 100644
index 0000000..1d66fbf
--- /dev/null
+++ b/src/ctbutterfly/ctbutterfly.cpp
@@ -0,0 +1,564 @@
+/***************************************************************************
+ * ctbutterfly - butterfly calculation tool *
+ * ----------------------------------------------------------------------- *
+ * copyright (C) 2014 by Michael Mayer *
+ * ----------------------------------------------------------------------- *
+ * *
+ * 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 ctbutterfly.hpp
+ * @brief Butterfly computation tool
+ * @author Michael Mayer
+ */
+
+/* __ Includes ___________________________________________________________ */
+#ifdef HAVE_CONFIG_H
+#include
+#endif
+#include
+#include
+#include "ctbutterfly.hpp"
+#include "GTools.hpp"
+
+/* __ Method name definitions ____________________________________________ */
+#define G_GET_PARAMETERS "ctbutterfly::get_parameters()"
+#define G_SAVE "ctbutterfly::save()"
+
+/* __ Debug definitions __________________________________________________ */
+
+/* __ Coding definitions _________________________________________________ */
+
+
+/*==========================================================================
+ = =
+ = Constructors/destructors =
+ = =
+ ==========================================================================*/
+
+/***********************************************************************//**
+ * @brief Void constructor
+ ***************************************************************************/
+ctbutterfly::ctbutterfly(void) : ctool(CTBUTTERFLY_NAME, CTBUTTERFLY_VERSION)
+{
+ // Initialise members
+ init_members();
+
+ // Return
+ return;
+}
+
+
+/***********************************************************************//**
+ * @brief Observations constructor
+ *
+ * param[in] obs Observation container.
+ *
+ * This method creates an instance of the class by copying an existing
+ * observations container.
+ ***************************************************************************/
+ctbutterfly::ctbutterfly(const GObservations& obs) :
+ ctool(CTBUTTERFLY_NAME, CTBUTTERFLY_VERSION)
+{
+ // Initialise members
+ init_members();
+
+ // Set observations
+ m_obs = obs;
+
+ // Return
+ return;
+}
+
+
+
+/***********************************************************************//**
+ * @brief Command line constructor
+ *
+ * @param[in] argc Number of arguments in command line.
+ * @param[in] argv Array of command line arguments.
+ ***************************************************************************/
+ctbutterfly::ctbutterfly(int argc, char *argv[]) :
+ ctool(CTBUTTERFLY_NAME, CTBUTTERFLY_VERSION, argc, argv)
+{
+ // Initialise members
+ init_members();
+
+ // Return
+ return;
+}
+
+
+/***********************************************************************//**
+ * @brief Copy constructor
+ *
+ * @param[in] app Application.
+ ***************************************************************************/
+ctbutterfly::ctbutterfly(const ctbutterfly& app) : ctool(app)
+{
+ // Initialise members
+ init_members();
+
+ // Copy members
+ copy_members(app);
+
+ // Return
+ return;
+}
+
+
+/***********************************************************************//**
+ * @brief Destructor
+ ***************************************************************************/
+ctbutterfly::~ctbutterfly(void)
+{
+ // Free members
+ free_members();
+
+ // Return
+ return;
+}
+
+
+/*==========================================================================
+ = =
+ = Operators =
+ = =
+ ==========================================================================*/
+
+/***********************************************************************//**
+ * @brief Assignment operator
+ *
+ * @param[in] app Application.
+ * @return Application.
+ ***************************************************************************/
+ctbutterfly& ctbutterfly::operator=(const ctbutterfly& app)
+{
+ // Execute only if object is not identical
+ if (this != &app) {
+
+ // Copy base class members
+ this->ctool::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 ctbutterfly::clear(void)
+{
+ // Free members
+ free_members();
+ this->ctool::free_members();
+ this->GApplication::free_members();
+
+ // Initialise members
+ this->GApplication::init_members();
+ this->ctool::init_members();
+ init_members();
+
+ // Return
+ return;
+}
+
+
+/***********************************************************************//**
+ * @brief Computes the butterfly
+ *
+ * This method takes the spectral fit and its covariance matrix to compute
+ * the confidence band via Gaussian error propagation
+ ***************************************************************************/
+void ctbutterfly::run(void)
+{
+ // If we're in debug mode then all output is also dumped on the screen
+ if (logDebug()) {
+ log.cout(true);
+ }
+
+ // Get task 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;
+ }
+
+ // Get model instance for further computations
+ GModels models = m_obs.models();
+
+ // Compute covariance matrix if necessary
+ if (m_covariance.size() == 0) {
+
+ // Write header
+ if (logTerse()) {
+ log << std::endl;
+ log.header1("Compute covariance matrix");
+ }
+
+ GOptimizerPars pars = models.pars();
+ GObservations::likelihood likelihood = m_obs.function();
+ likelihood.eval(pars);
+ GMatrixSparse* curvature = dynamic_cast(likelihood.curvature());
+ m_covariance = curvature->invert();
+
+ }
+
+ // Write header
+ if (logTerse()) {
+ log << std::endl;
+ log.header1("Generate butterfly");
+ }
+
+ // Initialise dummy time to evaluate spectral model
+ GTime time = GTime();
+
+ // Initialise vector of gradients
+ GVector grad = GVector(m_obs.models().npars());
+
+ // Loop over energy bins positions
+ for (int i = 0; i < m_ebounds.size(); ++i) {
+
+ int num_gradient = 0;
+
+ // Get the energy of current bin
+ GEnergy energy = m_ebounds.elogmean(i);
+
+ // Header for verbose logging
+ if (logExplicit()) {
+ std::string msg = "Computing butterfly for bin number "+gammalib::str(i)+
+ " at "+energy.print();
+ log << std::endl;
+ log.header2(msg);
+ }
+
+ // Initialise model flux value
+ double model_flux = 0.0;
+
+ // Loop over models
+ for (int j = 0; j < models.size(); ++j ) {
+
+ // Check wether model is a skymodel
+ GModelSky* skymodel = dynamic_cast(models[j]);
+
+ // Yes ...
+ if (skymodel != NULL) {
+
+ // Skip spatial models
+ num_gradient += skymodel->spatial()->size();
+
+ // Get pointer to spectral model
+ GModelSpectral* spectral = skymodel->spectral();
+
+ // Set flux value of source of interest
+ if (skymodel->name() == m_srcname) {
+ model_flux = spectral->eval_gradients(energy, time);
+ } // endif: model was source of interest
+
+ // Loop over model parameters, get gradients
+ // and assign them to the vector
+ for (int k = 0; k < spectral->size(); ++k) {
+
+ grad[num_gradient] = (*spectral)[k].gradient();
+ num_gradient += 1;
+
+ }// endfor: loop over spectral parameters
+
+ // Skip temporal models
+ num_gradient += skymodel->temporal()->size();
+
+ } // endif: model was sky model
+
+ else {
+
+ // Skip other models (e.g. GModelData instances)
+ num_gradient += models[j]->size();
+
+ } // endelse: Model was not GModelSky
+
+ } // endfor: Looped over models
+
+ // Multiply covariance to the gradient vector
+ GVector vector = m_covariance * grad;
+
+ // Get the error from the scalar product
+ double error = std::sqrt(grad * vector);
+
+ // Store flux, value and energy for saving
+ m_fluxes.push_back(model_flux);
+ m_energies.push_back(energy.MeV());
+ m_errors.push_back(error);
+
+ // Log information
+ if (logExplicit()) {
+ log << " Flux at ";
+ log << energy.print();
+ log << ": ";
+ log << model_flux;
+ log << " +- ";
+ log << error;
+ log << " ph/cm2/s/MeV";
+ }
+
+ } //endfor: loop over energy bin
+
+ // Return
+ return;
+}
+
+
+/***********************************************************************//**
+ * @brief Save maps
+ *
+ * This method saves the butterfly into an ascii file
+ ***************************************************************************/
+void ctbutterfly::save(void)
+{
+ // Write header
+ if (logTerse()) {
+ log << std::endl;
+ log.header1("Save Butterfly to file");
+ }
+
+ // Get output filename
+ m_outfile = (*this)["outfile"].filename();
+
+ if (gammalib::file_exists(m_outfile)) {
+
+ if ((*this)["clobber"].boolean()) {
+ std::remove(m_outfile.c_str());
+ }
+ else {
+ std::string msg = "File \""+m_outfile+"\" already exists and clobber is set to \"false\"";
+ throw GException::file_open_error(G_SAVE,msg);
+ }
+ }
+
+ // Create file instance
+ std::fstream file;
+
+ file.open(m_outfile, std::fstream::out | std::fstream::app);
+
+ // Write short header
+ file << "# Energy [MeV] | flux [ph/cm2/s/MeV] | e_flux [ph/cm2/s/MeV]" << std::endl;
+
+ // Write values to file
+ for (int i = 0; i < m_fluxes.size(); ++i) {
+
+ file << m_energies[i] << " " << m_fluxes[i] << " " << m_errors[i] << std::endl;
+ }
+
+ // close file
+ file.close();
+
+ // Return
+ return;
+}
+
+
+/*==========================================================================
+ = =
+ = Private methods =
+ = =
+ ==========================================================================*/
+
+/***********************************************************************//**
+ * @brief Initialise class members
+ ***************************************************************************/
+void ctbutterfly::init_members(void)
+{
+ // Initialise members
+ m_infile.clear();
+ m_outfile.clear();
+ m_srcname.clear();
+ m_ebounds.clear();
+
+ // Initialise protected members
+ m_obs.clear();
+ m_covariance.clear();
+ m_fluxes.clear();
+ m_energies.clear();
+ m_errors.clear();
+
+ // Return
+ return;
+}
+
+
+/***********************************************************************//**
+ * @brief Copy class members
+ *
+ * @param[in] app Application.
+ ***************************************************************************/
+void ctbutterfly::copy_members(const ctbutterfly& app)
+{
+ // Copy attributes
+ m_infile = app.m_infile;
+ m_outfile = app.m_outfile;
+ m_srcname = app.m_srcname;
+ m_ebounds = app.m_ebounds;
+
+ // Copy protected members
+ m_obs = app.m_obs;
+ m_covariance = app.m_covariance;
+ m_fluxes = app.m_fluxes;
+ m_energies = app.m_energies;
+ m_errors = app.m_errors;
+
+ // Return
+ return;
+}
+
+
+/***********************************************************************//**
+ * @brief Delete class members
+ ***************************************************************************/
+void ctbutterfly::free_members(void)
+{
+ // Return
+ return;
+}
+
+
+/***********************************************************************//**
+ * @brief Get application parameters
+ *
+ * @exception GException::invalid_value
+ * Test source not found or no RA/DEC parameters found for test
+ * source.
+ *
+ * Get all task parameters from parameter file or (if required) by querying
+ * the user. Most parameters are only required if no observation exists so
+ * far in the observation container. In this case, a single CTA observation
+ * will be added to the container, using the definition provided in the
+ * parameter file.
+ ***************************************************************************/
+void ctbutterfly::get_parameters(void)
+{
+ // 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) {
+
+ // Allocate CTA observation
+ GCTAObservation obs;
+
+ // Get event file name
+ std::string filename = (*this)["infile"].filename();
+
+ // Try first to open as FITS file
+ try {
+
+ // Load data
+ obs.load(filename);
+
+ // Set response
+ set_obs_response(&obs);
+
+ // Append observation to container
+ m_obs.append(obs);
+
+ }
+
+ // ... otherwise try to open as XML file
+ catch (GException::fits_open_error &e) {
+
+ // Load observations from XML file
+ m_obs.load(filename);
+
+ // Check if all observations have response information. If
+ // not, get the calibration database parameters and set
+ // the response properly
+ set_response(m_obs);
+
+ } // endcatch: file was an XML file
+
+ } // endif: there was no observation in the container
+
+ // 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
+
+ // Get name of test source and check container for this name
+ m_srcname = (*this)["srcname"].string();
+ if (!m_obs.models().contains(m_srcname)) {
+ std::string msg = "Source \""+m_srcname+"\" not found in model "
+ "container. Please add a source with that name "
+ "or check for a possible typos.";
+ throw GException::invalid_value(G_GET_PARAMETERS, msg);
+ }
+
+ // get binning information
+ m_ebounds = get_ebounds();
+
+ // Get matrix file name and load if possible
+ std::string matrixfilename = (*this)["matrix"].filename();
+ if (matrixfilename != "NONE") {
+ std::string msg = "Loading of matrix from file not implemented yet. "
+ "Use filename = \"NONE\" to induce a recomputation of "
+ "the matrix internally.";
+ throw GException::feature_not_implemented(G_GET_PARAMETERS, msg);
+ // m_covariance.load(matrixfilename);
+ }
+
+ // Optionally read ahead parameters so that they get correctly
+ // dumped into the log file
+ if (read_ahead()) {
+ m_outfile = (*this)["outfile"].filename();
+ }
+
+ // Return
+ return;
+}
+
diff --git a/src/ctbutterfly/ctbutterfly.hpp b/src/ctbutterfly/ctbutterfly.hpp
new file mode 100644
index 0000000..81367c5
--- /dev/null
+++ b/src/ctbutterfly/ctbutterfly.hpp
@@ -0,0 +1,108 @@
+/***************************************************************************
+ * ctbutterfly - butterfly calculation tool *
+ * ----------------------------------------------------------------------- *
+ * copyright (C) 2014 by Michael Mayer *
+ * ----------------------------------------------------------------------- *
+ * *
+ * 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 ctbutterfly.hpp
+ * @brief Butterfly calculation tool interface definition
+ * @author Michael Mayer
+ */
+
+#ifndef CTBUTTERFLY_HPP
+#define CTBUTTERFLY_HPP
+
+/* __ Includes ___________________________________________________________ */
+#include "GammaLib.hpp"
+#include "GCTALib.hpp"
+#include "ctool.hpp"
+
+/* __Definitions _________________________________________________________ */
+#define CTBUTTERFLY_NAME "ctbutterfly"
+#define CTBUTTERFLY_VERSION "00-01-00"
+
+
+/***********************************************************************//**
+ * @class ctbutterfly
+ *
+ * @brief butterfly calculation tool
+ *
+ * This class computes the confidence interval of a fitted spectrum
+ * (butterfly) for a given set of observations
+ *
+ * The class operates on predefined observation containers, an individual
+ * event list or an observation definition XML file.
+ *
+ * During the computation the covariance matrix of the fit is used to propagate
+ * uncertainties and their correlations through the entire energy range.
+ * The output is saved as an ascii files containing the confidence band boundaries
+ ***************************************************************************/
+class ctbutterfly : public ctool {
+
+public:
+ // Constructors and destructors
+ ctbutterfly(void);
+ explicit ctbutterfly(const GObservations& obs);
+ ctbutterfly(int argc, char *argv[]);
+ ctbutterfly(const ctbutterfly& app);
+ virtual ~ctbutterfly(void);
+
+ // Operators
+ ctbutterfly& operator=(const ctbutterfly& app);
+
+ // Methods
+ void clear(void);
+ void run(void);
+ void save(void);
+ const GObservations& obs(void) const;
+
+protected:
+ // Protected methods
+ void init_members(void);
+ void copy_members(const ctbutterfly& app);
+ void free_members(void);
+ void get_parameters(void);
+
+ // User parameters
+ std::string m_infile; //!< Input file
+ std::string m_srcname; //!< Name of source to compute butterfly
+ std::string m_outfile; //!< Output ascii file
+
+ GEbounds m_ebounds; //!< Energy binning definition
+
+ // Protected members
+ GObservations m_obs; //!< Observation container
+ GMatrixSparse m_covariance; //!< covariance matrix
+
+ std::vector m_energies; //!< energy values for storage
+ std::vector m_fluxes; //!< flux values per energy bin
+ std::vector m_errors; //!< flux errors per energy bin
+};
+
+/***********************************************************************//**
+ * @brief Return observation container
+ *
+ * @return Reference to observation container
+ ***************************************************************************/
+inline
+const GObservations& ctbutterfly::obs(void) const
+{
+ return m_obs;
+}
+
+#endif /* CTBUTTERFLY_HPP */
diff --git a/src/ctbutterfly/ctbutterfly.par b/src/ctbutterfly/ctbutterfly.par
new file mode 100644
index 0000000..dedb4af
--- /dev/null
+++ b/src/ctbutterfly/ctbutterfly.par
@@ -0,0 +1,44 @@
+#############################################################################
+# #
+# CTA Science Analysis Tools #
+# #
+# ------------------------------------------------------------------------- #
+# #
+# File: ctbutterfly #
+# Version: 00-01-00 #
+# #
+# Author: Michael Mayer #
+# michael.mayer@physik.hu-berlin.de #
+# HU Berlin #
+# #
+# Purpose: Parameter file for the ctbutterfly application #
+# #
+#############################################################################
+#
+# General parameters
+#===================
+infile, f, a, "events.fits",,,"Input event list, cube or observation definition file"
+srcmdl, f, a, "$CTOOLS/share/models/crab.xml",,, "Source model"
+srcname, s, a, "CrabNebula",,,"Source of interest"
+caldb, s, a, "dummy",,, "Calibration database"
+irf, s, a, "cta_dummy_irf",,, "Instrument response function"
+outfile, f, a, "butterfly.txt",,, "Output ascii file"
+matrix, f, h, "NONE",,, "Input covariance Matrix FITS file"
+
+#
+# Energy binning parameters
+#==========================
+ebinalg, s, h, "LOG", FILE|LIN|LOG,,"Algorithm for defining energy bins"
+emin, r, a, 0.1,,,"Start value for first energy bin in TeV"
+emax, r, a, 100.0,,,"Stop value for last energy bin in TeV"
+enumbins, i, h, 100,,,"Number of energy bins"
+ebinfile, f, h, "NONE",,,"Name of the file containing the energy bin definition"
+
+#
+# Standard parameters
+#====================
+chatter, i, h, 2,0,4, "Chattiness of output"
+clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
+debug, b, h, no,,, "Debugging mode activated"
+mode, s, h, "ql",,, "Mode of automatic parameters"
+logfile, f, h, "ctbutterfly.log",,, "Log filename"
diff --git a/src/ctbutterfly/main.cpp b/src/ctbutterfly/main.cpp
new file mode 100644
index 0000000..23f5f11
--- /dev/null
+++ b/src/ctbutterfly/main.cpp
@@ -0,0 +1,79 @@
+/***************************************************************************
+ * ctbutterfly - TS map calculation tool *
+ * ----------------------------------------------------------------------- *
+ * copyright (C) 2014 by Michael Mayer *
+ * ----------------------------------------------------------------------- *
+ * *
+ * 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 ctbutterfly/main.cpp
+ * @brief CTA butterfly computation tool
+ * @author Michael Mayer
+ */
+
+/* __ Includes ___________________________________________________________ */
+#ifdef HAVE_CONFIG_H
+#include
+#endif
+#include
+#include "ctbutterfly.hpp"
+
+
+/***********************************************************************//**
+ * @brief Main entry point of application
+ *
+ * @param[in] argc Number of command line arguments.
+ * @param[in] argv Command line arguments.
+ *
+ * This is the main entry point of the ctbutterfly application. It allocates a
+ * ctbutterfly object and runs the application.
+ ***************************************************************************/
+int main (int argc, char *argv[])
+{
+ // Initialise return code
+ int rc = 1;
+
+ // Create instance of application
+ ctbutterfly application(argc, argv);
+
+ // Run application
+ try {
+ // Execute application
+ application.execute();
+
+ // Signal success
+ rc = 0;
+ }
+ catch (std::exception &e) {
+
+ // Extract error message
+ std::string message = e.what();
+ std::string signal = "*** ERROR encounterted in the execution of"
+ " ctbutterfly. Run aborted ...";
+
+ // Write error in logger
+ application.log << signal << std::endl;
+ application.log << message << std::endl;
+
+ // Write error on standard output
+ std::cout << signal << std::endl;
+ std::cout << message << std::endl;
+
+ } // endcatch: catched any application error
+
+ // Return
+ return rc;
+}
diff --git a/src/ctobssim/ctobssim.cpp b/src/ctobssim/ctobssim.cpp
index d70e096..2a1be13 100644
--- a/src/ctobssim/ctobssim.cpp
+++ b/src/ctobssim/ctobssim.cpp
@@ -791,6 +791,7 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models,
photons[i],
*obs,
ran);
+
if (event != NULL) {
// Use event only if it falls within ROI
diff --git a/test/test_ctbutterfly.py b/test/test_ctbutterfly.py
new file mode 100755
index 0000000..3c11324
--- /dev/null
+++ b/test/test_ctbutterfly.py
@@ -0,0 +1,96 @@
+#! /usr/bin/env python
+# ==========================================================================
+# This scripts performs unit tests for the ctbutterfly tool.
+#
+# Copyright (C) 2014 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 .
+#
+# ==========================================================================
+import gammalib
+import ctools
+
+
+# ========================== #
+# Test class for ctbutterfly tool #
+# ========================== #
+class Test(gammalib.GPythonTestSuite):
+ """
+ Test class for ctbutterfly tool.
+ """
+ # Constructor
+ def __init__(self):
+ """
+ Constructor.
+ """
+ # Call base class constructor
+ gammalib.GPythonTestSuite.__init__(self)
+
+ # Set members
+ self.events_name = "data/crab_events.fits"
+ self.model_name = "data/crab.xml"
+ self.caldb = "irf"
+ self.irf = "cta_dummy_irf"
+
+ # Return
+ return
+
+ # Set test functions
+ def set(self):
+ """
+ Set all test functions.
+ """
+ # Set test name
+ self.name("ctbutterfly")
+
+ # Append tests
+ self.append(self.test_functional, "Test ctbutterfly functionality")
+
+ # Return
+ return
+
+ # Test ctbutterfly functionnality
+ def test_functional(self):
+ """
+ Test ctbutterfly functionnality.
+ """
+ # Set-up ctbutterfly
+ butterfly = ctools.ctbutterfly()
+ butterfly["infile"].filename(self.events_name)
+ butterfly["srcmdl"].filename(self.model_name)
+ butterfly["srcname"].string("Crab")
+ butterfly["caldb"].string(self.caldb)
+ butterfly["irf"].string(self.irf)
+ butterfly["emin"].real(0.1)
+ butterfly["emax"].real(100)
+ butterfly["outfile"].filename("butterfly.txt")
+
+ # Run tool
+ self.test_try("Run ctbutterfly")
+ try:
+ butterfly.run()
+ self.test_try_success()
+ except:
+ self.test_try_failure("Exception occured in butterfly.")
+
+ # Save results
+ self.test_try("Save results")
+ try:
+ butterfly.save()
+ self.test_try_success()
+ except:
+ self.test_try_failure("Exception occured in saving results.")
+
+ # Return
+ return
diff --git a/test/test_ctools.sh b/test/test_ctools.sh
index 8853d0c..3577bd3 100755
--- a/test/test_ctools.sh
+++ b/test/test_ctools.sh
@@ -45,6 +45,7 @@ ctexpcube=../src/ctexpcube/ctexpcube
ctpsfcube=../src/ctpsfcube/ctpsfcube
ctbkgcube=../src/ctbkgcube/ctbkgcube
ctcubemask=../src/ctcubemask/ctcubemask
+ctbutterfly=../src/ctbutterfly/ctbutterfly
#
@@ -542,3 +543,27 @@ else
exit 1
fi
$ECHO " ok"
+
+
+
+#
+# Test ctbutterfly
+# ===============
+$ECHO -n "Test ctbutterfly: "
+$ctbutterfly infile="data/crab_events.fits.gz" \
+srcmdl="data/crab.xml" \
+srcname="Crab" \
+outfile="butterfly.txt" \
+caldb="irf" \
+irf="cta_dummy_irf" \
+emin=0.1 \
+emax=100.0
+$ECHO -n "."
+if [ -s "butterfly.txt" ]
+then
+ $ECHO -n "."
+else
+ $ECHO " butterfly.txt file is not valid"
+ exit 1
+fi
+$ECHO " ok"
diff --git a/test/test_cttsmap.py b/test/test_cttsmap.py
index ef731a9..09ddc3d 100755
--- a/test/test_cttsmap.py
+++ b/test/test_cttsmap.py
@@ -40,7 +40,7 @@ class Test(gammalib.GPythonTestSuite):
# Set members
self.events_name = "data/crab_events.fits"
self.model_name = "data/crab.xml"
- self.caldb = "irf"
+ self.caldb = "dummy"
self.irf = "cta_dummy_irf"
# Return
diff --git a/test/test_python.py b/test/test_python.py
index e9031f5..cc4e917 100755
--- a/test/test_python.py
+++ b/test/test_python.py
@@ -34,6 +34,7 @@ import test_ctpsfcube
import test_ctbkgcube
import test_ctcubemask
import test_pipelines
+import test_ctbutterfly
# ======================== #
@@ -59,6 +60,7 @@ if __name__ == '__main__':
suite_ctbkgcube = test_ctbkgcube.Test()
suite_ctcubemask = test_ctcubemask.Test()
suite_pipelines = test_pipelines.Test()
+ suite_ctbutterfly = test_ctbutterfly.Test()
# Setup unit tests
suite_ctobssim.set()
@@ -73,6 +75,7 @@ if __name__ == '__main__':
suite_ctbkgcube.set()
suite_ctcubemask.set()
suite_pipelines.set()
+ suite_ctbutterfly.set()
# Append tests to container
suites.append(suite_ctobssim)
@@ -87,6 +90,7 @@ if __name__ == '__main__':
suites.append(suite_ctbkgcube)
suites.append(suite_ctcubemask)
suites.append(suite_pipelines)
+ suites.append(suite_ctbutterfly)
# Set PFILES environment variable
try: