Commit d9f31901af4bbdd60f1faef8b38d84dfe3fcd7fe

Authored by Michael Mayer
1 parent e5a1a87e

implemented first version of ctulimit

doc/source/reference_manual/ctulimit.rst 0 → 100644
  1 +.. _ctulimit:
  2 +
  3 +ctulimit
  4 +===========
  5 +
  6 +Computes upper limit.
  7 +
  8 +
  9 +Synopsis
  10 +--------
  11 +
  12 +Calculates the upper limit flux of a given source and stores the value in ascii file.
  13 +The input model has to be optimised for ctulimit to converge.
  14 +
  15 +General parameters
  16 +------------------
  17 +
  18 +``inobs [file]``
  19 + Input event list, counts cube or observation definition XML file.
  20 +
  21 +``inmodel [file]``
  22 + Model XML file containing the optimised source and background definitions.
  23 +
  24 +``srcname [string]``
  25 + Name of model component for which upper limit should be computed.
  26 +
  27 +``expcube = NONE [file]``
  28 + Exposure cube file (only needed for stacked analysis).
  29 +
  30 +``psfcube = NONE [file]``
  31 + PSF cube file (only needed for stacked analysis).
  32 +
  33 +``caldb [string]``
  34 + Calibration database.
  35 +
  36 +``irf [string]``
  37 + Instrumental response function.
  38 +
  39 +``outfile [file]``
  40 + Output ASCII file name.
  41 +
  42 +``(cl = 0.95) [real]``
  43 + Confidence Level of upper limit
  44 +
  45 +``(sigma_min = 0.0) [real]``
  46 + Minimum boundary to start searching for upper limit value. Number of standard deviations above best fit value
  47 +
  48 +``(sigma_max = 10.0) [real]``
  49 + Maximum boundary to start searching for upper limit value. Number of standard deviations above best fit value
  50 +
  51 +``(emin = 1.0) [real])``
  52 + Minimum energy of flux upper limit (in TeV).
  53 +
  54 +``(emax = 100) [real]``
  55 + Maximum energy of flux upper limit (in TeV).
  56 +
  57 +``(tol = 1e-5) [real]``
  58 + Computation tolerance for minimum
  59 +
  60 +``(max_iter = 50) [integer]``
  61 + Maximum number of iterations before throwing an exception
  62 +
  63 +
  64 +Standard parameters
  65 +-------------------
  66 +
  67 +``(chatter = 2) [integer]``
  68 + Verbosity of the executable:
  69 + chatter = 0: no information will be logged
  70 +
  71 + chatter = 1: only errors will be logged
  72 +
  73 + chatter = 2: errors and actions will be logged
  74 +
  75 + chatter = 3: report about the task execution
  76 +
  77 + chatter = 4: detailed report about the task execution
  78 +
  79 +``(clobber = yes) [boolean]``
  80 + Specifies whether an existing output counts cube should be overwritten.
  81 +
  82 +``(debug = no) [boolean]``
  83 + Enables debug mode. In debug mode the executable will dump any log file output to the console.
  84 +
  85 +``(mode = ql) [string]``
  86 + Mode of automatic parameters (default is "ql", i.e. "query and learn").
  87 +
  88 +``(logfile = ctskymap.log) [string]``
  89 + Name of log file.
  90 +
  91 +
  92 +Related tools
  93 +-------------
  94 +
  95 +None
... ...
doc/source/reference_manual/index.rst
... ... @@ -27,6 +27,7 @@ ctools
27 27 ctselect --- Selects event data <ctselect>
28 28 ctskymap --- Generates sky map <ctskymap>
29 29 cttsmap --- Generates Test Statistics map <cttsmap>
  30 + ctulimit --- Calculates upper limit <ctulimit>
30 31  
31 32  
32 33 cscripts
... ...
pyext/ctulimit.i 0 → 100644
  1 +/***************************************************************************
  2 + * ctulimit - ctulimit calculation tool *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2015 by Michael Mayer *
  5 + * ----------------------------------------------------------------------- *
  6 + * *
  7 + * This program is free software: you can redistribute it and/or modify *
  8 + * it under the terms of the GNU General Public License as published by *
  9 + * the Free Software Foundation, either version 3 of the License, or *
  10 + * (at your option) any later version. *
  11 + * *
  12 + * This program is distributed in the hope that it will be useful, *
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  15 + * GNU General Public License for more details. *
  16 + * *
  17 + * You should have received a copy of the GNU General Public License *
  18 + * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  19 + * *
  20 + ***************************************************************************/
  21 +/**
  22 + * @file ctulimit
  23 + * @brief upper limit calculation tool
  24 + * @author Michael Mayer
  25 + */
  26 +%{
  27 +/* Put headers and other declarations here that are needed for compilation */
  28 +#include "ctulimit.hpp"
  29 +%}
  30 +
  31 +
  32 +/***********************************************************************//**
  33 + * @class ctulimit
  34 + *
  35 + * @brief upper limit calculation tool
  36 + ***************************************************************************/
  37 +class ctulimit : public ctool {
  38 +public:
  39 + // Constructors and destructors
  40 + ctulimit(void);
  41 + explicit ctulimit(const GObservations& obs);
  42 + ctulimit(int argc, char *argv[]);
  43 + ctulimit(const ctulimit& app);
  44 + virtual ~ctulimit(void);
  45 +
  46 + // Methods
  47 + void clear(void);
  48 + void run(void);
  49 + void save(void);
  50 + const GObservations& obs(void) const;
  51 + const double& diff_ulimit(void) const;
  52 + const double& flux_ulimit(void) const;
  53 + const double& eflux_ulimit(void) const;
  54 +};
  55 +
  56 +
  57 +/***********************************************************************//**
  58 + * @brief upper limit calculation tool Python extensions
  59 + ***************************************************************************/
  60 +%extend ctulimit {
  61 + ctulimit copy() {
  62 + return (*self);
  63 + }
  64 +}
... ...
src/ctulimit/ctulimit.cpp
1 1 /***************************************************************************
2   - * ctulimitt - upper limit calculation tool *
  2 + * ctulimit - upper limit calculation tool *
3 3 * ----------------------------------------------------------------------- *
4 4 * copyright (C) 2014 by Michael Mayer *
5 5 * ----------------------------------------------------------------------- *
... ... @@ -31,10 +31,12 @@
31 31 #include <cstdio>
32 32 #include "ctulimit.hpp"
33 33 #include "GTools.hpp"
  34 +#include "GOptimizer.hpp"
34 35  
35 36 /* __ Method name definitions ____________________________________________ */
36 37 #define G_GET_PARAMETERS "ctulimit::get_parameters()"
37   -
  38 +#define G_UL_BISECTION "ctulimit::ul_bisection(const double&, const double&)"
  39 +#define G_EVALUATE "ctulimit::evaluate(const double&)"
38 40 /* __ Debug definitions __________________________________________________ */
39 41  
40 42 /* __ Coding definitions _________________________________________________ */
... ... @@ -225,17 +227,200 @@ void ctulimit::run(void)
225 227 log << m_obs << std::endl;
226 228 }
227 229  
  230 + GModels models_orig = m_obs.models();
  231 +
  232 +
  233 + m_bestloglike = m_obs.logL();
  234 + if (m_bestloglike == 0.0) {
  235 +
  236 + // Write header
  237 + if (logTerse()) {
  238 + log << std::endl;
  239 + log.header1("Recompute best-fit likelihood");
  240 + }
  241 +
  242 + // Reoptimize if likelihood was not given before
  243 + GOptimizerLM* opt = new GOptimizerLM();
  244 + m_obs.optimize(*opt);
  245 + m_obs.errors(*opt);
  246 + m_bestloglike = m_obs.logL();
  247 +
  248 + } //endif: likelihood was 0.0
  249 +
  250 + // Store optimized models and pointer to skymodel of interest
  251 + m_models = m_obs.models();
  252 + m_skymodel = dynamic_cast<GModelSky*>(m_models[m_srcname])->clone();
  253 +
  254 + // Get reference energy for differential upper limit
  255 + GEnergy eref = GEnergy(m_eref, "TeV");
  256 +
  257 + // Create energy range for flux limits
  258 + GEnergy emin = GEnergy(m_emin, "TeV");
  259 + GEnergy emax = GEnergy(m_emax, "TeV");
  260 +
  261 + // Get value, scale and error of parameter
  262 + double value = (*m_skymodel->spectral())[0].value();
  263 + double error = (*m_skymodel->spectral())[0].error();
  264 + double scale = (*m_skymodel->spectral())[0].scale();
  265 +
  266 + // Compute starting boundaries
  267 + double parmin = value / scale + m_sigma_min * error / scale;
  268 + double parmax = value / scale + m_sigma_max * error / scale;
  269 +
228 270 // Write header
229 271 if (logTerse()) {
230 272 log << std::endl;
231 273 log.header1("Compute upper limit");
  274 + log << "Searching for upper limit between ";
  275 + log << parmin * scale;
  276 + log << " and ";
  277 + log << parmax * scale;
  278 + log << ": "<<std::endl;
  279 + }
  280 +
  281 + // compute upper limit
  282 + ulimit_bisection(parmin, parmax, scale);
  283 +
  284 + m_diff_ulimit = m_skymodel->spectral()->eval(eref, GTime());
  285 + m_flux_ulimit = m_skymodel->spectral()->flux(emin, emax);
  286 + m_eflux_ulimit = m_skymodel->spectral()->eflux(emin, emax);
  287 +
  288 + // Write results to logfile
  289 + if (logTerse()) {
  290 + log << std::endl;
  291 + log.header1("Upper limit computation finished");
  292 + log << "Upper limits are:" << std::endl;
  293 + log << " Differential at ";
  294 + log << m_eref <<" TeV: ";
  295 + log << m_diff_ulimit << " ph/cm2/s/MeV" << std::endl;
  296 + log << " Integral [";
  297 + log << m_emin << " - " << m_emax;
  298 + log << "] TeV: ";
  299 + log << m_flux_ulimit << " ph/cm2/s" <<std::endl;
  300 + log << " Energy flux [";
  301 + log << m_emin << " - " << m_emax;
  302 + log << "] TeV: ";
  303 + log << m_eflux_ulimit << " erg/cm2/s" <<std::endl;
  304 + }
  305 +
  306 + // Recover original models
  307 + m_obs.models(models_orig);
  308 +
  309 + // Return
  310 + return;
  311 +}
  312 +
  313 +/***********************************************************************//**
  314 + * @brief Evaluates the likelihood
  315 + *
  316 + * @param[in] value Factorised parameter value of the parameter of interest
  317 + * @return likelihood value
  318 + *
  319 + * This method evaluates the likelihood as a function of the parameter of interest
  320 + ***************************************************************************/
  321 +double ctulimit::evaluate(const double& value)
  322 +{
  323 + // Initialise likelihood value
  324 + double LogL = 0.0;
  325 +
  326 + // Check if given parameter is within boundaries
  327 + if (value > (*m_skymodel->spectral())[0].factor_min() && value < (*m_skymodel->spectral())[0].factor_max()) {
  328 +
  329 + // Remove source model
  330 + m_models.remove(m_srcname);
  331 +
  332 + // Change spectral model value
  333 + (*m_skymodel->spectral())[0].factor_value(value);
  334 +
  335 + // Re-append model to container
  336 + m_models.append(*m_skymodel);
  337 +
  338 + // Assign new models to observations
  339 + m_obs.models(m_models);
  340 +
  341 + // Evaluate likelihood for new model container
  342 + m_obs.eval();
  343 +
  344 + // Retrieve likelihood
  345 + LogL = m_obs.logL();
  346 +
  347 + } // endif: value was inside allowed range
  348 +
  349 + else {
  350 + // throw exception if value out of range
  351 + std::string msg = "Value out of range requested: "
  352 + "To omit this error, you could increase the allowed "
  353 + "parameter range in the model xml file.";
  354 + throw GException::invalid_value(G_EVALUATE, msg);
232 355 }
233 356  
  357 + // Compute function value
  358 + double difflike = LogL - m_bestloglike - m_dloglike;
234 359  
235   - // Compute upper limit here
  360 + // Return
  361 + return difflike;
  362 +}
  363 +
  364 +/***********************************************************************//**
  365 + * @brief Induces upper limit computation by using a bisection method
  366 + *
  367 + * This method calculates the upper limit using a bisection method
  368 + ***************************************************************************/
  369 +void ctulimit::ulimit_bisection(const double& min, const double& max, const double& scale)
  370 +{
  371 + // copy values to working values
  372 + double wrk_min = min;
  373 + double wrk_max = max;
  374 +
  375 + // Initialise counter
  376 + int iter=0;
  377 +
  378 + // Loop until breaking condition is reached
  379 + while (true) {
  380 +
  381 + // Log information
  382 + if (logExplicit()) {
  383 + log << " Iteration ";
  384 + log << iter;
  385 + log << ": Parameter range reduced to [";
  386 + log << wrk_min * scale;
  387 + log <<"; ";
  388 + log << wrk_max * scale;
  389 + log << "]" << std::endl;
  390 + }
  391 +
  392 + // Throw exception if maximum iterations are reached
  393 + if( iter > m_max_iter) {
  394 + throw GException::invalid_value(G_UL_BISECTION, "Maximum iterations reached");;
  395 + }
  396 +
  397 + // compute center of boundary
  398 + double mid = (wrk_min + wrk_max) / 2.0;
  399 +
  400 + // Calculate function value
  401 + double eval_mid = evaluate(mid);
  402 +
  403 + // Check for convergence inside tolerance
  404 + if (std::abs(eval_mid) < m_tol) {
  405 + break;
  406 + }
  407 +
  408 + // change boundaries for further iteration
  409 + if (eval_mid > 0.0) {
  410 + wrk_max = mid;
  411 + }
  412 + else if (eval_mid < 0.0) {
  413 + wrk_min = mid;
  414 + }
  415 +
  416 + // increment counter
  417 + iter++;
  418 +
  419 + } // endwhile
236 420  
237 421 // Return
238 422 return;
  423 +
239 424 }
240 425  
241 426  
... ... @@ -249,12 +434,21 @@ void ctulimit::save(void)
249 434 // Write header
250 435 if (logTerse()) {
251 436 log << std::endl;
252   - log.header1("Save TS map");
  437 + log.header1("Save upper limit");
253 438 }
254 439  
255 440 // Get output filename
256 441 m_outfile = (*this)["outfile"].filename();
257 442  
  443 + // Create CSV table with 3 columns
  444 + GCsv table(1, 3);
  445 +
  446 + table.real(0, 0, m_diff_ulimit);
  447 + table.real(0, 1, m_flux_ulimit);
  448 + table.real(0, 2, m_eflux_ulimit);
  449 +
  450 + // Save CSV table
  451 + table.save(m_outfile, " ", clobber());
258 452  
259 453 // Return
260 454 return;
... ... @@ -273,13 +467,25 @@ void ctulimit::save(void)
273 467 void ctulimit::init_members(void)
274 468 {
275 469 // Initialise members
276   - m_infile.clear();
277 470 m_outfile.clear();
278   -
  471 + m_srcname.clear();
  472 + m_bestloglike = 0.0;
  473 + m_flux_ulimit = 0.0;
  474 + m_diff_ulimit = 0.0;
  475 + m_eflux_ulimit = 0.0;
  476 + m_dloglike = 0.0;
  477 + m_tol = 1e-6;
  478 + m_max_iter = 50;
  479 + m_eref = 0.0;
  480 + m_emin = 0.0;
  481 + m_emax = 0.0;
  482 + m_sigma_min = 0.0;
  483 + m_sigma_max = 0.0;
  484 + m_skymodel = NULL;
279 485  
280 486 // Initialise protected members
281 487 m_obs.clear();
282   -
  488 + m_models.clear();
283 489  
284 490 // Return
285 491 return;
... ... @@ -294,15 +500,27 @@ void ctulimit::init_members(void)
294 500 void ctulimit::copy_members(const ctulimit& app)
295 501 {
296 502 // Copy attributes
297   - m_infile = app.m_infile;
298 503 m_outfile = app.m_outfile;
299   - m_modelfile = app.m_modelfile;
300 504 m_srcname = app.m_srcname;
301   - m_parname = app.m_parname;
302   - m_algorithm = app.m_algorithm;
  505 + m_diff_ulimit = app.m_diff_ulimit;
  506 + m_flux_ulimit = app.m_flux_ulimit;
  507 + m_eflux_ulimit = app.m_eflux_ulimit;
  508 + m_bestloglike = app.m_bestloglike;
  509 + m_dloglike = app.m_dloglike;
  510 + m_tol = app.m_tol;
  511 + m_max_iter = app.m_max_iter;
  512 + m_eref = app.m_eref;
  513 + m_emin = app.m_emin;
  514 + m_emax = app.m_emax;
  515 + m_sigma_min = app.m_sigma_min;
  516 + m_sigma_max = app.m_sigma_max;
303 517  
304 518 // Copy protected members
305 519 m_obs = app.m_obs;
  520 + m_models = app.m_models;
  521 +
  522 + // Clone protected members
  523 + m_skymodel = (app.m_skymodel != NULL) ? app.m_skymodel->clone() : NULL;
306 524  
307 525 // Return
308 526 return;
... ... @@ -334,51 +552,25 @@ void ctulimit::free_members(void)
334 552 ***************************************************************************/
335 553 void ctulimit::get_parameters(void)
336 554 {
337   - // If there are no observations in container then add a single CTA
338   - // observation using the parameters from the parameter file
  555 + // If there are no observations in container then load them via user
  556 + // parameters
339 557 if (m_obs.size() == 0) {
340 558  
341   - // Allocate CTA observation
342   - GCTAObservation obs;
343   -
344   - // Get event file name
345   - std::string filename = (*this)["infile"].filename();
346   -
347   - // Try first to open as FITS file
348   - try {
349   -
350   - // Load data
351   - obs.load(filename);
352   -
353   - // Set response
354   - set_obs_response(&obs);
355   -
356   - // Append observation to container
357   - m_obs.append(obs);
358   -
359   - }
360   -
361   - // ... otherwise try to open as XML file
362   - catch (GException::fits_open_error &e) {
363   -
364   - // Load observations from XML file
365   - m_obs.load(filename);
366   -
367   - // Check if all observations have response information. If
368   - // not, get the calibration database parameters and set
369   - // the response properly
370   - set_response(m_obs);
  559 + // Throw exception if no input observation file is given
  560 + require_inobs(G_GET_PARAMETERS);
371 561  
372   - } // endcatch: file was an XML file
  562 + // Build observation container
  563 + m_obs = get_observations();
373 564  
374 565 } // endif: there was no observation in the container
375 566  
  567 +
376 568 // If there is are no models associated with the observations then
377 569 // load now the model definition
378 570 if (m_obs.models().size() == 0) {
379 571  
380 572 // Get models XML filename
381   - std::string filename = (*this)["srcmdl"].filename();
  573 + std::string filename = (*this)["inmodel"].filename();
382 574  
383 575 // Setup models for optimizing.
384 576 m_obs.models(GModels(filename));
... ... @@ -390,10 +582,34 @@ void ctulimit::get_parameters(void)
390 582 if (!m_obs.models().contains(m_srcname)) {
391 583 std::string msg = "Source \""+m_srcname+"\" not found in model "
392 584 "container. Please add a source with that name "
393   - "or check for a possible typos.";
394   - throw GException::invalid_value(G_GET_PARAMETERS, msg);
  585 + "or check for possible typos.";
  586 + throw GException::invalid_value(G_GET_PARAMETERS, msg);
  587 + }
  588 +
  589 + double CL = (*this)["cl"].real();
  590 + if (CL != 0.95) {
  591 + std::string msg = "Confidence level different from 95% requested"
  592 + "Currently only 95% CL is possible";
  593 + throw GException::invalid_value(G_GET_PARAMETERS, msg);
  594 + }
  595 + else {
  596 + // Set Likelihood difference for 95% CL.
  597 + // See Minuit Handbook
  598 + m_dloglike = 3.84 / 2.0;
395 599 }
396 600  
  601 + // Read starting boundaries for bisection
  602 + m_sigma_min = (*this)["sigma_min"].real();
  603 + m_sigma_max = (*this)["sigma_max"].real();
  604 +
  605 + // Read energy values
  606 + m_eref = (*this)["eref"].real();
  607 + m_emin = (*this)["emin"].real();
  608 + m_emax = (*this)["emax"].real();
  609 +
  610 + // Read precision
  611 + m_tol = (*this)["tol"].real();
  612 + m_max_iter = (*this)["max_iter"].integer();
397 613  
398 614 // Optionally read ahead parameters so that they get correctly
399 615 // dumped into the log file
... ... @@ -401,8 +617,6 @@ void ctulimit::get_parameters(void)
401 617 m_outfile = (*this)["outfile"].filename();
402 618 }
403 619  
404   - // TODO read other parameters here
405   -
406 620 // Return
407 621 return;
408 622 }
... ...
src/ctulimit/ctulimit.hpp
... ... @@ -69,7 +69,9 @@ public:
69 69 void run(void);
70 70 void save(void);
71 71 const GObservations& obs(void) const;
72   - const double& ulimit(void) const;
  72 + const double& diff_ulimit(void) const;
  73 + const double& flux_ulimit(void) const;
  74 + const double& eflux_ulimit(void) const;
73 75  
74 76 protected:
75 77 // Protected methods
... ... @@ -77,19 +79,32 @@ protected:
77 79 void copy_members(const ctulimit& app);
78 80 void free_members(void);
79 81 void get_parameters(void);
  82 + void ulimit_bisection(const double& parmin, const double& parmax, const double& scale);
  83 + double evaluate(const double& value);
80 84  
81 85 // User parameters
82   - std::string m_infile; //!< Input file
83   - std::string m_modelfile;//!< Name of model optimised model file
84 86 std::string m_srcname; //!< Name of source which is moved around
85   - std::string m_parname; //!< Name of parameter upper limit should be computed
86   - std::string m_outfile; //!< Output counts map or XML file
87   - std::string m_algorithm; //!< algorithm of upper limit computation
  87 + std::string m_outfile; //!< Output ascii file
  88 +
  89 + GModelSky* m_skymodel; //!< Pointer to variable spectral model
  90 +
  91 + int m_max_iter; //!< maximum number of iterations
  92 + double m_dloglike; //!< Likelihood difference for upper limit computation
  93 + double m_bestloglike ; //!< Best fit log likelihood of given model
  94 + double m_tol; //!< tolerance for limit determination
  95 + double m_sigma_min; //!< Starting value minimum (multiple fit errors above fit values)
  96 + double m_sigma_max; //!< Starting value maximum (multiple fit errors above fit values)
  97 + double m_eref; //!< reference energy for flux limits
  98 + double m_emin; //!< minimum energy for flux limits
  99 + double m_emax; //!< maximum energy for flux limits
  100 +
  101 + double m_diff_ulimit; //!<Differential upper limit value
  102 + double m_flux_ulimit; //!< Flux upper limit value
  103 + double m_eflux_ulimit; //!< Energy flux upper limits
88 104  
89 105 // Protected members
90 106 GObservations m_obs; //!< Observation container
91   -
92   - double m_ulimit; //!<Upper limit value
  107 + GModels m_models;
93 108  
94 109 };
95 110  
... ... @@ -106,15 +121,36 @@ const GObservations&amp; ctulimit::obs(void) const
106 121 }
107 122  
108 123 /***********************************************************************//**
109   - * @brief Return observation container
  124 + * @brief Return differential upper limit
110 125 *
111   - * @return Reference to observation container
  126 + * @return differential upper limit
112 127 ***************************************************************************/
113 128 inline
114   -const double& ctulimit::ulimit(void) const
  129 +const double& ctulimit::diff_ulimit(void) const
115 130 {
116   - return m_ulimit;
  131 + return m_diff_ulimit;
117 132 }
118 133  
  134 +/***********************************************************************//**
  135 + * @brief Return flux upper limit
  136 + *
  137 + * @return flux upper limit
  138 + ***************************************************************************/
  139 +inline
  140 +const double& ctulimit::flux_ulimit(void) const
  141 +{
  142 + return m_flux_ulimit;
  143 +}
  144 +
  145 +/***********************************************************************//**
  146 + * @brief return energy flux upper limit
  147 + *
  148 + * @return energy flux upper limits
  149 + ***************************************************************************/
  150 +inline
  151 +const double& ctulimit::eflux_ulimit(void) const
  152 +{
  153 + return m_eflux_ulimit;
  154 +}
119 155  
120 156 #endif /* CTULIMIT_HPP */
... ...
src/ctulimit/ctulimit.par
... ... @@ -9,7 +9,7 @@
9 9 # #
10 10 # Author: Michael Mayer #
11 11 # michael.mayer@physik.hu-berlin.de #
12   -# DESY #
  12 +# HU Berlin #
13 13 # #
14 14 # Purpose: Parameter file for the ctulimit application #
15 15 # #
... ... @@ -17,15 +17,26 @@
17 17 #
18 18 # General parameters
19 19 #===================
20   -infile, f, a, "events.fits",,,"Input event list, cube or observation definition file"
21   -srcmdl, f, a, "$CTOOLS/share/models/crab.xml",,, "Source model"
22   -srcname, s, a, "Crab",,,"Test source"
23   -parname, s, a, "Prefactor",,,"Parameter name for which upper limit should be computed"
24   -algorithm, s, a, "Bayesian",,,"Limit calculation algorithm"
  20 +inobs, f, a, "events.fits",,,"Input event list, counts cube or observation definition file"
  21 +inmodel, f, a, "$CTOOLS/share/models/crab.xml",,, "Source model"
  22 +srcname, s, a, "Crab",,,"Source of interest"
  23 +expcube, f, a, "NONE",,, "Exposure cube file (only needed for stacked analysis)"
  24 +psfcube, f, a, "NONE",,, "PSF cube file (only needed for stacked analysis)"
25 25 caldb, s, a, "dummy",,, "Calibration database"
26 26 irf, s, a, "cta_dummy_irf",,, "Instrument response function"
27   -outfile, f, a, "crab_limit.txt",,, "Output file"
  27 +outfile, f, a, "upperlimit.txt",,, "Output ascii file"
28 28  
  29 +#
  30 +# Upper limit calculation parameters
  31 +#===================================
  32 +cl, r, h, 0.95,,,"Confidence Level"
  33 +sigma_min,r, h, 0.0,,, "Start minimum value (multiple sigmas above fit value)"
  34 +sigma_max,r, h, 10.0,,, "Start maximum value (multiple sigmas above fit value)"
  35 +eref, r, h, 1.0,,, "Reference energy for differential limits"
  36 +emin, r, h, 1.0,,, "Minimum energy for flux limits"
  37 +emax, r, h, 100.0,,, "Maximum energy for flux limits"
  38 +tol, r, h, 1e-5,,, "Calculation tolerance"
  39 +max_iter, i, h, 50,,, "Maximum number of iterations"
29 40  
30 41 #
31 42 # Standard parameters
... ... @@ -34,4 +45,4 @@ chatter, i, h, 2,0,4, &quot;Chattiness of output&quot;
34 45 clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
35 46 debug, b, h, no,,, "Debugging mode activated"
36 47 mode, s, h, "ql",,, "Mode of automatic parameters"
37   -logfile, f, h, "cttsmap.log",,, "Log filename"
  48 +logfile, f, h, "ctulimit.log",,, "Log filename"
... ...
src/ctulimit/main.cpp
... ... @@ -62,7 +62,7 @@ int main (int argc, char *argv[])
62 62 // Extract error message
63 63 std::string message = e.what();
64 64 std::string signal = "*** ERROR encounterted in the execution of"
65   - " cttsmap. Run aborted ...";
  65 + " ctulimit. Run aborted ...";
66 66  
67 67 // Write error in logger
68 68 application.log << signal << std::endl;
... ...
test/test_ctools.sh
... ... @@ -46,12 +46,14 @@ ctpsfcube=../src/ctpsfcube/ctpsfcube
46 46 ctbkgcube=../src/ctbkgcube/ctbkgcube
47 47 ctcubemask=../src/ctcubemask/ctcubemask
48 48 ctbutterfly=../src/ctbutterfly/ctbutterfly
  49 +ctulimit=../src/ctulimit/ctulimit
49 50  
50 51  
51 52 #
52 53 # Remove any existing result files
53 54 # ================================
54 55 rm -rf *.fits *.xml
  56 +rm -rf ulimit.dat butterfly.txt
55 57  
56 58  
57 59 #
... ... @@ -597,3 +599,25 @@ else
597 599 exit 1
598 600 fi
599 601 $ECHO " ok"
  602 +
  603 +
  604 +#
  605 +# Test ctulimit
  606 +# ===============
  607 +$ECHO -n "Test ctulimit: "
  608 +$ctulimit inobs="selected_events.fits" \
  609 + inmodel="results_unbinned.xml" \
  610 + srcname="Crab" \
  611 + outfile="ulimit.dat" \
  612 + caldb="irf" \
  613 + irf="cta_dummy_irf"
  614 +$ECHO -n "."
  615 +if [ -s "ulimit.dat" ]
  616 +then
  617 + $ECHO -n "."
  618 +else
  619 + $ECHO " ulimit.dat file is not found"
  620 + exit 1
  621 +fi
  622 +$ECHO " ok"
  623 +
... ...
test/test_ctulimit.py 0 → 100755
  1 +#! /usr/bin/env python
  2 +# ==========================================================================
  3 +# This scripts performs unit tests for the cttsmap tool.
  4 +#
  5 +# Copyright (C) 2014 Juergen Knoedlseder
  6 +#
  7 +# This program is free software: you can redistribute it and/or modify
  8 +# it under the terms of the GNU General Public License as published by
  9 +# the Free Software Foundation, either version 3 of the License, or
  10 +# (at your option) any later version.
  11 +#
  12 +# This program is distributed in the hope that it will be useful,
  13 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 +# GNU General Public License for more details.
  16 +#
  17 +# You should have received a copy of the GNU General Public License
  18 +# along with this program. If not, see <http://www.gnu.org/licenses/>.
  19 +#
  20 +# ==========================================================================
  21 +import gammalib
  22 +import ctools
  23 +
  24 +
  25 +# ========================== #
  26 +# Test class for cttsmap tool #
  27 +# ========================== #
  28 +class Test(gammalib.GPythonTestSuite):
  29 + """
  30 + Test class for cttsmap tool.
  31 + """
  32 + # Constructor
  33 + def __init__(self):
  34 + """
  35 + Constructor.
  36 + """
  37 + # Call base class constructor
  38 + gammalib.GPythonTestSuite.__init__(self)
  39 +
  40 + # Set members
  41 + self.events_name = "data/crab_events.fits"
  42 + self.model_name = "result.xml"
  43 + self.caldb = "irf"
  44 + self.irf = "cta_dummy_irf"
  45 +
  46 + # Return
  47 + return
  48 +
  49 + # Set test functions
  50 + def set(self):
  51 + """
  52 + Set all test functions.
  53 + """
  54 + # Set test name
  55 + self.name("ctulimit")
  56 +
  57 + # Append tests
  58 + self.append(self.test_functional, "Test ctulimit functionality")
  59 +
  60 + # Return
  61 + return
  62 +
  63 + # Test cttsmap functionnality
  64 + def test_functional(self):
  65 + """
  66 + Test cttsmap functionnality.
  67 + """
  68 + # Set-up cttsmap
  69 + ulimit = ctools.ctulimit()
  70 + ulimit["inobs"].filename(self.events_name)
  71 + ulimit["inmodel"].filename(self.model_name)
  72 + ulimit["srcname"].string("Crab")
  73 + ulimit["caldb"].string(self.caldb)
  74 + ulimit["irf"].string(self.irf)
  75 + ulimit["outfile"].filename("ulimit.dat")
  76 +
  77 + # Run tool
  78 + self.test_try("Run ctulimit")
  79 + try:
  80 + ulimit.run()
  81 + self.test_try_success()
  82 + except:
  83 + self.test_try_failure("Exception occured in ctulimit.")
  84 +
  85 + # Save results
  86 + self.test_try("Save results")
  87 + try:
  88 + ulimit.save()
  89 + self.test_try_success()
  90 + except:
  91 + self.test_try_failure("Exception occured in saving results.")
  92 +
  93 + # Return
  94 + return
... ...
test/test_python.py
... ... @@ -34,6 +34,7 @@ import test_ctpsfcube
34 34 import test_ctbkgcube
35 35 import test_ctcubemask
36 36 import test_ctbutterfly
  37 +import test_ctulimit
37 38 import test_pipelines
38 39  
39 40  
... ... @@ -60,6 +61,7 @@ if __name__ == &#39;__main__&#39;:
60 61 suite_ctbkgcube = test_ctbkgcube.Test()
61 62 suite_ctcubemask = test_ctcubemask.Test()
62 63 suite_ctbutterfly = test_ctbutterfly.Test()
  64 + suite_ctulimit = test_ctulimit.Test()
63 65 suite_pipelines = test_pipelines.Test()
64 66  
65 67 # Setup unit tests
... ... @@ -75,6 +77,7 @@ if __name__ == &#39;__main__&#39;:
75 77 suite_ctbkgcube.set()
76 78 suite_ctcubemask.set()
77 79 suite_ctbutterfly.set()
  80 + suite_ctulimit.set()
78 81 suite_pipelines.set()
79 82  
80 83 # Append tests to container
... ... @@ -90,6 +93,7 @@ if __name__ == &#39;__main__&#39;:
90 93 suites.append(suite_ctbkgcube)
91 94 suites.append(suite_ctcubemask)
92 95 suites.append(suite_ctbutterfly)
  96 + suites.append(suite_ctulimit)
93 97 suites.append(suite_pipelines)
94 98  
95 99 # Set PFILES environment variable
... ...