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,6 +27,7 @@ ctools
27 ctselect --- Selects event data <ctselect> 27 ctselect --- Selects event data <ctselect>
28 ctskymap --- Generates sky map <ctskymap> 28 ctskymap --- Generates sky map <ctskymap>
29 cttsmap --- Generates Test Statistics map <cttsmap> 29 cttsmap --- Generates Test Statistics map <cttsmap>
  30 + ctulimit --- Calculates upper limit <ctulimit>
30 31
31 32
32 cscripts 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 * copyright (C) 2014 by Michael Mayer * 4 * copyright (C) 2014 by Michael Mayer *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
@@ -31,10 +31,12 @@ @@ -31,10 +31,12 @@
31 #include <cstdio> 31 #include <cstdio>
32 #include "ctulimit.hpp" 32 #include "ctulimit.hpp"
33 #include "GTools.hpp" 33 #include "GTools.hpp"
  34 +#include "GOptimizer.hpp"
34 35
35 /* __ Method name definitions ____________________________________________ */ 36 /* __ Method name definitions ____________________________________________ */
36 #define G_GET_PARAMETERS "ctulimit::get_parameters()" 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 /* __ Debug definitions __________________________________________________ */ 40 /* __ Debug definitions __________________________________________________ */
39 41
40 /* __ Coding definitions _________________________________________________ */ 42 /* __ Coding definitions _________________________________________________ */
@@ -225,17 +227,200 @@ void ctulimit::run(void) @@ -225,17 +227,200 @@ void ctulimit::run(void)
225 log << m_obs << std::endl; 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 // Write header 270 // Write header
229 if (logTerse()) { 271 if (logTerse()) {
230 log << std::endl; 272 log << std::endl;
231 log.header1("Compute upper limit"); 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 // Return 421 // Return
238 return; 422 return;
  423 +
239 } 424 }
240 425
241 426
@@ -249,12 +434,21 @@ void ctulimit::save(void) @@ -249,12 +434,21 @@ void ctulimit::save(void)
249 // Write header 434 // Write header
250 if (logTerse()) { 435 if (logTerse()) {
251 log << std::endl; 436 log << std::endl;
252 - log.header1("Save TS map"); 437 + log.header1("Save upper limit");
253 } 438 }
254 439
255 // Get output filename 440 // Get output filename
256 m_outfile = (*this)["outfile"].filename(); 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 // Return 453 // Return
260 return; 454 return;
@@ -273,13 +467,25 @@ void ctulimit::save(void) @@ -273,13 +467,25 @@ void ctulimit::save(void)
273 void ctulimit::init_members(void) 467 void ctulimit::init_members(void)
274 { 468 {
275 // Initialise members 469 // Initialise members
276 - m_infile.clear();  
277 m_outfile.clear(); 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 // Initialise protected members 486 // Initialise protected members
281 m_obs.clear(); 487 m_obs.clear();
282 - 488 + m_models.clear();
283 489
284 // Return 490 // Return
285 return; 491 return;
@@ -294,15 +500,27 @@ void ctulimit::init_members(void) @@ -294,15 +500,27 @@ void ctulimit::init_members(void)
294 void ctulimit::copy_members(const ctulimit& app) 500 void ctulimit::copy_members(const ctulimit& app)
295 { 501 {
296 // Copy attributes 502 // Copy attributes
297 - m_infile = app.m_infile;  
298 m_outfile = app.m_outfile; 503 m_outfile = app.m_outfile;
299 - m_modelfile = app.m_modelfile;  
300 m_srcname = app.m_srcname; 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 // Copy protected members 518 // Copy protected members
305 m_obs = app.m_obs; 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 // Return 525 // Return
308 return; 526 return;
@@ -334,51 +552,25 @@ void ctulimit::free_members(void) @@ -334,51 +552,25 @@ void ctulimit::free_members(void)
334 ***************************************************************************/ 552 ***************************************************************************/
335 void ctulimit::get_parameters(void) 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 if (m_obs.size() == 0) { 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 } // endif: there was no observation in the container 565 } // endif: there was no observation in the container
375 566
  567 +
376 // If there is are no models associated with the observations then 568 // If there is are no models associated with the observations then
377 // load now the model definition 569 // load now the model definition
378 if (m_obs.models().size() == 0) { 570 if (m_obs.models().size() == 0) {
379 571
380 // Get models XML filename 572 // Get models XML filename
381 - std::string filename = (*this)["srcmdl"].filename(); 573 + std::string filename = (*this)["inmodel"].filename();
382 574
383 // Setup models for optimizing. 575 // Setup models for optimizing.
384 m_obs.models(GModels(filename)); 576 m_obs.models(GModels(filename));
@@ -390,10 +582,34 @@ void ctulimit::get_parameters(void) @@ -390,10 +582,34 @@ void ctulimit::get_parameters(void)
390 if (!m_obs.models().contains(m_srcname)) { 582 if (!m_obs.models().contains(m_srcname)) {
391 std::string msg = "Source \""+m_srcname+"\" not found in model " 583 std::string msg = "Source \""+m_srcname+"\" not found in model "
392 "container. Please add a source with that name " 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 // Optionally read ahead parameters so that they get correctly 614 // Optionally read ahead parameters so that they get correctly
399 // dumped into the log file 615 // dumped into the log file
@@ -401,8 +617,6 @@ void ctulimit::get_parameters(void) @@ -401,8 +617,6 @@ void ctulimit::get_parameters(void)
401 m_outfile = (*this)["outfile"].filename(); 617 m_outfile = (*this)["outfile"].filename();
402 } 618 }
403 619
404 - // TODO read other parameters here  
405 -  
406 // Return 620 // Return
407 return; 621 return;
408 } 622 }
src/ctulimit/ctulimit.hpp
@@ -69,7 +69,9 @@ public: @@ -69,7 +69,9 @@ public:
69 void run(void); 69 void run(void);
70 void save(void); 70 void save(void);
71 const GObservations& obs(void) const; 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 protected: 76 protected:
75 // Protected methods 77 // Protected methods
@@ -77,19 +79,32 @@ protected: @@ -77,19 +79,32 @@ protected:
77 void copy_members(const ctulimit& app); 79 void copy_members(const ctulimit& app);
78 void free_members(void); 80 void free_members(void);
79 void get_parameters(void); 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 // User parameters 85 // User parameters
82 - std::string m_infile; //!< Input file  
83 - std::string m_modelfile;//!< Name of model optimised model file  
84 std::string m_srcname; //!< Name of source which is moved around 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 // Protected members 105 // Protected members
90 GObservations m_obs; //!< Observation container 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,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 inline 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 #endif /* CTULIMIT_HPP */ 156 #endif /* CTULIMIT_HPP */
src/ctulimit/ctulimit.par
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 # # 9 # #
10 # Author: Michael Mayer # 10 # Author: Michael Mayer #
11 # michael.mayer@physik.hu-berlin.de # 11 # michael.mayer@physik.hu-berlin.de #
12 -# DESY # 12 +# HU Berlin #
13 # # 13 # #
14 # Purpose: Parameter file for the ctulimit application # 14 # Purpose: Parameter file for the ctulimit application #
15 # # 15 # #
@@ -17,15 +17,26 @@ @@ -17,15 +17,26 @@
17 # 17 #
18 # General parameters 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 caldb, s, a, "dummy",,, "Calibration database" 25 caldb, s, a, "dummy",,, "Calibration database"
26 irf, s, a, "cta_dummy_irf",,, "Instrument response function" 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 # Standard parameters 42 # Standard parameters
@@ -34,4 +45,4 @@ chatter, i, h, 2,0,4, &quot;Chattiness of output&quot; @@ -34,4 +45,4 @@ chatter, i, h, 2,0,4, &quot;Chattiness of output&quot;
34 clobber, b, h, yes,,, "Overwrite existing output files with new output files?" 45 clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
35 debug, b, h, no,,, "Debugging mode activated" 46 debug, b, h, no,,, "Debugging mode activated"
36 mode, s, h, "ql",,, "Mode of automatic parameters" 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,7 +62,7 @@ int main (int argc, char *argv[])
62 // Extract error message 62 // Extract error message
63 std::string message = e.what(); 63 std::string message = e.what();
64 std::string signal = "*** ERROR encounterted in the execution of" 64 std::string signal = "*** ERROR encounterted in the execution of"
65 - " cttsmap. Run aborted ..."; 65 + " ctulimit. Run aborted ...";
66 66
67 // Write error in logger 67 // Write error in logger
68 application.log << signal << std::endl; 68 application.log << signal << std::endl;
test/test_ctools.sh
@@ -46,12 +46,14 @@ ctpsfcube=../src/ctpsfcube/ctpsfcube @@ -46,12 +46,14 @@ ctpsfcube=../src/ctpsfcube/ctpsfcube
46 ctbkgcube=../src/ctbkgcube/ctbkgcube 46 ctbkgcube=../src/ctbkgcube/ctbkgcube
47 ctcubemask=../src/ctcubemask/ctcubemask 47 ctcubemask=../src/ctcubemask/ctcubemask
48 ctbutterfly=../src/ctbutterfly/ctbutterfly 48 ctbutterfly=../src/ctbutterfly/ctbutterfly
  49 +ctulimit=../src/ctulimit/ctulimit
49 50
50 51
51 # 52 #
52 # Remove any existing result files 53 # Remove any existing result files
53 # ================================ 54 # ================================
54 rm -rf *.fits *.xml 55 rm -rf *.fits *.xml
  56 +rm -rf ulimit.dat butterfly.txt
55 57
56 58
57 # 59 #
@@ -597,3 +599,25 @@ else @@ -597,3 +599,25 @@ else
597 exit 1 599 exit 1
598 fi 600 fi
599 $ECHO " ok" 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,6 +34,7 @@ import test_ctpsfcube
34 import test_ctbkgcube 34 import test_ctbkgcube
35 import test_ctcubemask 35 import test_ctcubemask
36 import test_ctbutterfly 36 import test_ctbutterfly
  37 +import test_ctulimit
37 import test_pipelines 38 import test_pipelines
38 39
39 40
@@ -60,6 +61,7 @@ if __name__ == &#39;__main__&#39;: @@ -60,6 +61,7 @@ if __name__ == &#39;__main__&#39;:
60 suite_ctbkgcube = test_ctbkgcube.Test() 61 suite_ctbkgcube = test_ctbkgcube.Test()
61 suite_ctcubemask = test_ctcubemask.Test() 62 suite_ctcubemask = test_ctcubemask.Test()
62 suite_ctbutterfly = test_ctbutterfly.Test() 63 suite_ctbutterfly = test_ctbutterfly.Test()
  64 + suite_ctulimit = test_ctulimit.Test()
63 suite_pipelines = test_pipelines.Test() 65 suite_pipelines = test_pipelines.Test()
64 66
65 # Setup unit tests 67 # Setup unit tests
@@ -75,6 +77,7 @@ if __name__ == &#39;__main__&#39;: @@ -75,6 +77,7 @@ if __name__ == &#39;__main__&#39;:
75 suite_ctbkgcube.set() 77 suite_ctbkgcube.set()
76 suite_ctcubemask.set() 78 suite_ctcubemask.set()
77 suite_ctbutterfly.set() 79 suite_ctbutterfly.set()
  80 + suite_ctulimit.set()
78 suite_pipelines.set() 81 suite_pipelines.set()
79 82
80 # Append tests to container 83 # Append tests to container
@@ -90,6 +93,7 @@ if __name__ == &#39;__main__&#39;: @@ -90,6 +93,7 @@ if __name__ == &#39;__main__&#39;:
90 suites.append(suite_ctbkgcube) 93 suites.append(suite_ctbkgcube)
91 suites.append(suite_ctcubemask) 94 suites.append(suite_ctcubemask)
92 suites.append(suite_ctbutterfly) 95 suites.append(suite_ctbutterfly)
  96 + suites.append(suite_ctulimit)
93 suites.append(suite_pipelines) 97 suites.append(suite_pipelines)
94 98
95 # Set PFILES environment variable 99 # Set PFILES environment variable