Commit 411b731669f58bb0b28c6b1874d3cb89df2b2311

Authored by Jürgen Knödlseder
1 parent 24cd52b8

Integrate ctulimit tool.

doc/source/reference_manual/ctulimit.rst
@@ -3,14 +3,15 @@ @@ -3,14 +3,15 @@
3 ctulimit 3 ctulimit
4 =========== 4 ===========
5 5
6 -Computes upper limit. 6 +Computes upper limit for a specific sky model component.
7 7
8 8
9 Synopsis 9 Synopsis
10 -------- 10 --------
11 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. 12 +Computes the upper limit flux of a given source and stores the value
  13 +in an ASCII file.
  14 +
14 15
15 General parameters 16 General parameters
16 ------------------ 17 ------------------
@@ -39,26 +40,29 @@ General parameters @@ -39,26 +40,29 @@ General parameters
39 ``outfile [file]`` 40 ``outfile [file]``
40 Output ASCII file name. 41 Output ASCII file name.
41 42
42 -``(cl = 0.95) [real]``  
43 - Confidence Level of upper limit 43 +``(confidence = 0.95) [real]``
  44 + Confidence Level of upper limit.
44 45
45 ``(sigma_min = 0.0) [real]`` 46 ``(sigma_min = 0.0) [real]``
46 - Minimum boundary to start searching for upper limit value. Number of standard deviations above best fit value 47 + Minimum boundary to start searching for upper limit value.
  48 + Number of standard deviations above best fit value
47 49
48 ``(sigma_max = 10.0) [real]`` 50 ``(sigma_max = 10.0) [real]``
49 - Maximum boundary to start searching for upper limit value. Number of standard deviations above best fit value 51 + Maximum boundary to start searching for upper limit value.
  52 + Number of standard deviations above best fit value
50 53
51 ``(emin = 1.0) [real])`` 54 ``(emin = 1.0) [real])``
52 - Minimum energy of flux upper limit (in TeV). 55 + Minimum energy of flux limits (in TeV).
53 56
54 ``(emax = 100) [real]`` 57 ``(emax = 100) [real]``
55 - Maximum energy of flux upper limit (in TeV). 58 + Maximum energy of flux limits (in TeV).
56 59
57 ``(tol = 1e-5) [real]`` 60 ``(tol = 1e-5) [real]``
58 - Computation tolerance for minimum 61 + Computation tolerance.
59 62
60 ``(max_iter = 50) [integer]`` 63 ``(max_iter = 50) [integer]``
61 - Maximum number of iterations before throwing an exception 64 + Maximum number of iterations before stopping the upper
  65 + limit computations.
62 66
63 67
64 Standard parameters 68 Standard parameters
@@ -85,7 +89,7 @@ Standard parameters @@ -85,7 +89,7 @@ Standard parameters
85 ``(mode = ql) [string]`` 89 ``(mode = ql) [string]``
86 Mode of automatic parameters (default is "ql", i.e. "query and learn"). 90 Mode of automatic parameters (default is "ql", i.e. "query and learn").
87 91
88 -``(logfile = ctskymap.log) [string]`` 92 +``(logfile = ctulimit.log) [string]``
89 Name of log file. 93 Name of log file.
90 94
91 95
pyext/ctulimit.i
1 /*************************************************************************** 1 /***************************************************************************
2 - * ctulimit - ctulimit calculation tool * 2 + * ctulimit - Upper limit calculation tool *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2015 by Michael Mayer * 4 * copyright (C) 2015 by Michael Mayer *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 ***************************************************************************/ 20 ***************************************************************************/
21 /** 21 /**
22 * @file ctulimit 22 * @file ctulimit
23 - * @brief upper limit calculation tool 23 + * @brief Upper limit calculation tool
24 * @author Michael Mayer 24 * @author Michael Mayer
25 */ 25 */
26 %{ 26 %{
@@ -32,7 +32,7 @@ @@ -32,7 +32,7 @@
32 /***********************************************************************//** 32 /***********************************************************************//**
33 * @class ctulimit 33 * @class ctulimit
34 * 34 *
35 - * @brief upper limit calculation tool 35 + * @brief Upper limit calculation tool
36 ***************************************************************************/ 36 ***************************************************************************/
37 class ctulimit : public ctool { 37 class ctulimit : public ctool {
38 public: 38 public:
@@ -48,14 +48,14 @@ public: @@ -48,14 +48,14 @@ public:
48 void run(void); 48 void run(void);
49 void save(void); 49 void save(void);
50 const GObservations& obs(void) const; 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; 51 + const double& diff_ulimit(void) const;
  52 + const double& flux_ulimit(void) const;
  53 + const double& eflux_ulimit(void) const;
54 }; 54 };
55 55
56 56
57 /***********************************************************************//** 57 /***********************************************************************//**
58 - * @brief upper limit calculation tool Python extensions 58 + * @brief Upper limit calculation tool Python extensions
59 ***************************************************************************/ 59 ***************************************************************************/
60 %extend ctulimit { 60 %extend ctulimit {
61 ctulimit copy() { 61 ctulimit copy() {
src/ctulimit/ctulimit.cpp
1 /*************************************************************************** 1 /***************************************************************************
2 - * ctulimit - upper limit calculation tool * 2 + * ctulimit - Upper limit calculation tool *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2014 by Michael Mayer * 4 + * copyright (C) 2015 by Michael Mayer *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 ***************************************************************************/ 20 ***************************************************************************/
21 /** 21 /**
22 * @file ctulimit.hpp 22 * @file ctulimit.hpp
23 - * @brief upper limit calculation tool interface implementation 23 + * @brief Upper limit calculation tool interface implementation
24 * @author Michael Mayer 24 * @author Michael Mayer
25 */ 25 */
26 26
@@ -34,9 +34,11 @@ @@ -34,9 +34,11 @@
34 #include "GOptimizer.hpp" 34 #include "GOptimizer.hpp"
35 35
36 /* __ Method name definitions ____________________________________________ */ 36 /* __ Method name definitions ____________________________________________ */
37 -#define G_GET_PARAMETERS "ctulimit::get_parameters()"  
38 -#define G_UL_BISECTION "ctulimit::ul_bisection(const double&, const double&)"  
39 -#define G_EVALUATE "ctulimit::evaluate(const double&)" 37 +#define G_GET_PARAMETERS "ctulimit::get_parameters()"
  38 +#define G_GET_MODEL_PARAMETER "ctulimit::get_model_parameter()"
  39 +#define G_UL_BISECTION "ctulimit::ul_bisection(double&, double&)"
  40 +#define G_EVALUATE "ctulimit::evaluate(double&)"
  41 +
40 /* __ Debug definitions __________________________________________________ */ 42 /* __ Debug definitions __________________________________________________ */
41 43
42 /* __ Coding definitions _________________________________________________ */ 44 /* __ Coding definitions _________________________________________________ */
@@ -70,7 +72,7 @@ ctulimit::ctulimit(void) : ctool(CTULIMIT_NAME, CTULIMIT_VERSION) @@ -70,7 +72,7 @@ ctulimit::ctulimit(void) : ctool(CTULIMIT_NAME, CTULIMIT_VERSION)
70 * observations container. 72 * observations container.
71 ***************************************************************************/ 73 ***************************************************************************/
72 ctulimit::ctulimit(const GObservations& obs) : 74 ctulimit::ctulimit(const GObservations& obs) :
73 - ctool(CTULIMIT_NAME, CTULIMIT_VERSION) 75 + ctool(CTULIMIT_NAME, CTULIMIT_VERSION)
74 { 76 {
75 // Initialise members 77 // Initialise members
76 init_members(); 78 init_members();
@@ -91,7 +93,7 @@ ctulimit::ctulimit(const GObservations& obs) : @@ -91,7 +93,7 @@ ctulimit::ctulimit(const GObservations& obs) :
91 * @param[in] argv Array of command line arguments. 93 * @param[in] argv Array of command line arguments.
92 ***************************************************************************/ 94 ***************************************************************************/
93 ctulimit::ctulimit(int argc, char *argv[]) : 95 ctulimit::ctulimit(int argc, char *argv[]) :
94 - ctool(CTULIMIT_NAME, CTULIMIT_VERSION, argc, argv) 96 + ctool(CTULIMIT_NAME, CTULIMIT_VERSION, argc, argv)
95 { 97 {
96 // Initialise members 98 // Initialise members
97 init_members(); 99 init_members();
@@ -227,80 +229,97 @@ void ctulimit::run(void) @@ -227,80 +229,97 @@ void ctulimit::run(void)
227 log << m_obs << std::endl; 229 log << m_obs << std::endl;
228 } 230 }
229 231
  232 + // Save original models
230 GModels models_orig = m_obs.models(); 233 GModels models_orig = m_obs.models();
231 234
232 -  
233 - m_bestloglike = m_obs.logL();  
234 - if (m_bestloglike == 0.0) { 235 + // Save original log-likelihood. If the value is zero it has never been
  236 + // computed hence we compute it now.
  237 + m_best_logL = m_obs.logL();
  238 + if (m_best_logL == 0.0) {
235 239
236 // Write header 240 // Write header
237 if (logTerse()) { 241 if (logTerse()) {
238 log << std::endl; 242 log << std::endl;
239 - log.header1("Recompute best-fit likelihood"); 243 + log.header1("Compute best-fit likelihood");
240 } 244 }
241 245
242 // Reoptimize if likelihood was not given before 246 // Reoptimize if likelihood was not given before
243 GOptimizerLM* opt = new GOptimizerLM(); 247 GOptimizerLM* opt = new GOptimizerLM();
244 m_obs.optimize(*opt); 248 m_obs.optimize(*opt);
245 m_obs.errors(*opt); 249 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"); 250 + m_best_logL = m_obs.logL();
256 251
257 - // Create energy range for flux limits  
258 - GEnergy emin = GEnergy(m_emin, "TeV");  
259 - GEnergy emax = GEnergy(m_emax, "TeV"); 252 + // Write optimised model into logger
  253 + if (logTerse()) {
  254 + log << m_obs.models() << std::endl;
  255 + }
260 256
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(); 257 + } // endif: likelihood was zero
265 258
266 - // Compute starting boundaries  
267 - double parmin = value / scale + m_sigma_min * error / scale;  
268 - double parmax = value / scale + m_sigma_max * error / scale; 259 + // Compute parameter bracketing
  260 + double value = m_model_par->value();
  261 + double error = m_model_par->error();
  262 + double parmin = value + m_sigma_min * error;
  263 + double parmax = value + m_sigma_max * error;
269 264
270 // Write header 265 // Write header
271 if (logTerse()) { 266 if (logTerse()) {
272 log << std::endl; 267 log << std::endl;
273 log.header1("Compute upper limit"); 268 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; 269 + log << gammalib::parformat("Model name");
  270 + log << m_skymodel->name() << std::endl;
  271 + log << gammalib::parformat("Parameter name");
  272 + log << m_model_par->name() << std::endl;
  273 + log << gammalib::parformat("Initial parameter range");
  274 + log << "[";
  275 + log << parmin;
  276 + log << ", ";
  277 + log << parmax;
  278 + log << "]" << std::endl;
279 } 279 }
280 280
281 - // compute upper limit  
282 - ulimit_bisection(parmin, parmax, scale); 281 + // Compute upper limit
  282 + ulimit_bisection(parmin, parmax);
283 283
284 - m_diff_ulimit = m_skymodel->spectral()->eval(eref, GTime());  
285 - m_flux_ulimit = m_skymodel->spectral()->flux(emin, emax); 284 + // Write final parameter range
  285 + if (logTerse()) {
  286 + log << gammalib::parformat("Final parameter");
  287 + log << m_model_par->value() << std::endl;
  288 + }
  289 +
  290 + // Get reference energy for differential upper limit
  291 + GEnergy eref = GEnergy(m_eref, "TeV");
  292 +
  293 + // Create energy range for flux limits
  294 + GEnergy emin = GEnergy(m_emin, "TeV");
  295 + GEnergy emax = GEnergy(m_emax, "TeV");
  296 +
  297 + // Compute upper limit intensity and fluxes
  298 + m_diff_ulimit = m_skymodel->spectral()->eval(eref, GTime());
  299 + m_flux_ulimit = m_skymodel->spectral()->flux(emin, emax);
286 m_eflux_ulimit = m_skymodel->spectral()->eflux(emin, emax); 300 m_eflux_ulimit = m_skymodel->spectral()->eflux(emin, emax);
287 301
288 // Write results to logfile 302 // Write results to logfile
289 if (logTerse()) { 303 if (logTerse()) {
290 log << std::endl; 304 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; 305 + log.header1("Upper limit results");
  306 + log << gammalib::parformat("Differential flux limit");
  307 + log << m_diff_ulimit;
  308 + log << " ph/cm2/s/MeV at ";
  309 + log << m_eref << " TeV";
  310 + log << std::endl;
  311 + log << gammalib::parformat("Integral flux limit");
  312 + log << m_flux_ulimit;
  313 + log << " ph/cm2/s within [";
  314 + log << m_emin << "-" << m_emax;
  315 + log << "] TeV";
  316 + log << std::endl;
  317 + log << gammalib::parformat("Energy flux limit");
  318 + log << m_eflux_ulimit;
  319 + log << " erg/cm2/s within [";
  320 + log << m_emin << "-" << m_emax;
  321 + log << "] TeV";
  322 + log << std::endl;
304 } 323 }
305 324
306 // Recover original models 325 // Recover original models
@@ -310,119 +329,6 @@ void ctulimit::run(void) @@ -310,119 +329,6 @@ void ctulimit::run(void)
310 return; 329 return;
311 } 330 }
312 331
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);  
355 - }  
356 -  
357 - // Compute function value  
358 - double difflike = LogL - m_bestloglike - m_dloglike;  
359 -  
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  
420 -  
421 - // Return  
422 - return;  
423 -  
424 -}  
425 -  
426 332
427 /***********************************************************************//** 333 /***********************************************************************//**
428 * @brief Save maps 334 * @brief Save maps
@@ -466,26 +372,27 @@ void ctulimit::save(void) @@ -466,26 +372,27 @@ void ctulimit::save(void)
466 ***************************************************************************/ 372 ***************************************************************************/
467 void ctulimit::init_members(void) 373 void ctulimit::init_members(void)
468 { 374 {
469 - // Initialise members 375 + // Initialise user parameters
470 m_outfile.clear(); 376 m_outfile.clear();
471 m_srcname.clear(); 377 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; 378 + m_sigma_min = 0.0;
  379 + m_sigma_max = 0.0;
  380 + m_eref = 0.0;
  381 + m_emin = 0.0;
  382 + m_emax = 0.0;
  383 + m_tol = 1.0e-6;
  384 + m_max_iter = 50;
485 385
486 // Initialise protected members 386 // Initialise protected members
487 m_obs.clear(); 387 m_obs.clear();
488 m_models.clear(); 388 m_models.clear();
  389 + m_dlogL = 0.0;
  390 + m_skymodel = NULL;
  391 + m_model_par = NULL;
  392 + m_best_logL = 0.0;
  393 + m_flux_ulimit = 0.0;
  394 + m_diff_ulimit = 0.0;
  395 + m_eflux_ulimit = 0.0;
489 396
490 // Return 397 // Return
491 return; 398 return;
@@ -499,28 +406,29 @@ void ctulimit::init_members(void) @@ -499,28 +406,29 @@ void ctulimit::init_members(void)
499 ***************************************************************************/ 406 ***************************************************************************/
500 void ctulimit::copy_members(const ctulimit& app) 407 void ctulimit::copy_members(const ctulimit& app)
501 { 408 {
502 - // Copy attributes  
503 - m_outfile = app.m_outfile;  
504 - m_srcname = app.m_srcname;  
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; 409 + // Copy user parameters
  410 + m_outfile = app.m_outfile;
  411 + m_srcname = app.m_srcname;
  412 + m_sigma_min = app.m_sigma_min;
  413 + m_sigma_max = app.m_sigma_max;
  414 + m_eref = app.m_eref;
  415 + m_emin = app.m_emin;
  416 + m_emax = app.m_emax;
  417 + m_tol = app.m_tol;
  418 + m_max_iter = app.m_max_iter;
  419 +
517 420
518 // Copy protected members 421 // Copy protected members
519 - m_obs = app.m_obs;  
520 - m_models = app.m_models; 422 + m_obs = app.m_obs;
  423 + m_models = app.m_models;
  424 + m_dlogL = app.m_dlogL;
  425 + m_best_logL = app.m_best_logL;
  426 + m_diff_ulimit = app.m_diff_ulimit;
  427 + m_flux_ulimit = app.m_flux_ulimit;
  428 + m_eflux_ulimit = app.m_eflux_ulimit;
521 429
522 - // Clone protected members  
523 - m_skymodel = (app.m_skymodel != NULL) ? app.m_skymodel->clone() : NULL; 430 + // Extract model parameter
  431 + get_model_parameter();
524 432
525 // Return 433 // Return
526 return; 434 return;
@@ -541,14 +449,10 @@ void ctulimit::free_members(void) @@ -541,14 +449,10 @@ void ctulimit::free_members(void)
541 * @brief Get application parameters 449 * @brief Get application parameters
542 * 450 *
543 * @exception GException::invalid_value 451 * @exception GException::invalid_value
544 - * Test source not found or no RA/DEC parameters found for test  
545 - * source. 452 + * Test source not found.
546 * 453 *
547 * Get all task parameters from parameter file or (if required) by querying 454 * Get all task parameters from parameter file or (if required) by querying
548 - * the user. Most parameters are only required if no observation exists so  
549 - * far in the observation container. In this case, a single CTA observation  
550 - * will be added to the container, using the definition provided in the  
551 - * parameter file. 455 + * the user.
552 ***************************************************************************/ 456 ***************************************************************************/
553 void ctulimit::get_parameters(void) 457 void ctulimit::get_parameters(void)
554 { 458 {
@@ -586,16 +490,20 @@ void ctulimit::get_parameters(void) @@ -586,16 +490,20 @@ void ctulimit::get_parameters(void)
586 throw GException::invalid_value(G_GET_PARAMETERS, msg); 490 throw GException::invalid_value(G_GET_PARAMETERS, msg);
587 } 491 }
588 492
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"; 493 + // Get relevant model and parameter for upper limit computation
  494 + get_model_parameter();
  495 +
  496 + // Get confidence level
  497 + double confidence = (*this)["confidence"].real();
  498 + if (confidence != 0.95) {
  499 + std::string msg = "Confidence level different from 95% requested."
  500 + " Currently only 95% is supported.";
593 throw GException::invalid_value(G_GET_PARAMETERS, msg); 501 throw GException::invalid_value(G_GET_PARAMETERS, msg);
594 } 502 }
595 else { 503 else {
596 // Set Likelihood difference for 95% CL. 504 // Set Likelihood difference for 95% CL.
597 // See Minuit Handbook 505 // See Minuit Handbook
598 - m_dloglike = 3.84 / 2.0; 506 + m_dlogL = 3.84 / 2.0;
599 } 507 }
600 508
601 // Read starting boundaries for bisection 509 // Read starting boundaries for bisection
@@ -608,7 +516,7 @@ void ctulimit::get_parameters(void) @@ -608,7 +516,7 @@ void ctulimit::get_parameters(void)
608 m_emax = (*this)["emax"].real(); 516 m_emax = (*this)["emax"].real();
609 517
610 // Read precision 518 // Read precision
611 - m_tol = (*this)["tol"].real(); 519 + m_tol = (*this)["tol"].real();
612 m_max_iter = (*this)["max_iter"].integer(); 520 m_max_iter = (*this)["max_iter"].integer();
613 521
614 // Optionally read ahead parameters so that they get correctly 522 // Optionally read ahead parameters so that they get correctly
@@ -622,3 +530,156 @@ void ctulimit::get_parameters(void) @@ -622,3 +530,156 @@ void ctulimit::get_parameters(void)
622 } 530 }
623 531
624 532
  533 +/***********************************************************************//**
  534 + * @brief Get application parameters
  535 + *
  536 + * @exception GException::invalid_value
  537 + * Did not find a valid model parameter
  538 + *
  539 + * Extracts a pointer to the sky model (m_skymodel) and a pointer to the
  540 + * relevant model parameter (m_model_par) from the model container.
  541 + ***************************************************************************/
  542 +void ctulimit::get_model_parameter(void)
  543 +{
  544 + // Get relevant model and parameter for upper limit computation.
  545 + GModels& models = const_cast<GModels&>(m_obs.models());
  546 + m_skymodel = dynamic_cast<GModelSky*>(models[m_srcname]);
  547 + if (m_skymodel == NULL) {
  548 + std::string msg = "Source \""+m_srcname+"\" is not a sky model. "
  549 + "Please specify the name of a sky model for "
  550 + "upper limit computation.";
  551 + throw GException::invalid_value(G_GET_MODEL_PARAMETER, msg);
  552 + }
  553 + if (m_skymodel->spectral()->has_par("Normalization")) {
  554 + m_model_par = &(m_skymodel->spectral()->operator[]("Normalization"));
  555 + }
  556 + else if (m_skymodel->spectral()->has_par("Prefactor")) {
  557 + m_model_par = &(m_skymodel->spectral()->operator[]("Prefactor"));
  558 + }
  559 + else if (m_skymodel->spectral()->has_par("Integral")) {
  560 + m_model_par = &(m_skymodel->spectral()->operator[]("Integral"));
  561 + }
  562 + else {
  563 + std::string msg = "Require spectral parameter \"Normalization\", "
  564 + "\"Prefactor\" or \"Integral\" for upper limit "
  565 + "computation. The specified source \""+m_srcname+
  566 + "\" does not have such a parameter.";
  567 + throw GException::invalid_value(G_GET_MODEL_PARAMETER, msg);
  568 + }
  569 +
  570 + // Return
  571 + return;
  572 +}
  573 +
  574 +
  575 +/***********************************************************************//**
  576 + * @brief Performs upper limit computation by using a bisection method
  577 + *
  578 + * @param[in] min Minimum parameter value
  579 + * @param[in] max Maximum parameter value
  580 + *
  581 + * This method calculates the upper limit using a bisection method.
  582 + ***************************************************************************/
  583 +void ctulimit::ulimit_bisection(const double& min, const double& max)
  584 +{
  585 + // Copy values to working values
  586 + double wrk_min = min;
  587 + double wrk_max = max;
  588 +
  589 + // Initialise iteration counter
  590 + int iter = 0;
  591 +
  592 + // Loop until breaking condition is reached
  593 + while (true) {
  594 +
  595 + // Log information
  596 + if (logExplicit()) {
  597 + log << gammalib::parformat("Iteration "+gammalib::str(iter));
  598 + log << "[";
  599 + log << wrk_min;
  600 + log << ", ";
  601 + log << wrk_max;
  602 + log << "]" << std::endl;
  603 + }
  604 +
  605 + // Throw exception if maximum iterations are reached
  606 + if (iter > m_max_iter) {
  607 + std::string msg = "The maximum number of "+gammalib::str(m_max_iter)+
  608 + " has been reached. You may consider to increase"
  609 + " the \"max_iter\" parameter and re-run ctulimit.";
  610 + throw GException::invalid_value(G_UL_BISECTION, msg);
  611 + }
  612 +
  613 + // Compute center of boundary
  614 + double mid = (wrk_min + wrk_max) / 2.0;
  615 +
  616 + // Calculate function value
  617 + double eval_mid = evaluate(mid);
  618 +
  619 + // Check for convergence inside tolerance
  620 + if (std::abs(eval_mid) < m_tol) {
  621 + break;
  622 + }
  623 +
  624 + // Change boundaries for further iteration
  625 + if (eval_mid > 0.0) {
  626 + wrk_max = mid;
  627 + }
  628 + else if (eval_mid < 0.0) {
  629 + wrk_min = mid;
  630 + }
  631 +
  632 + // Increment counter
  633 + iter++;
  634 +
  635 + } // endwhile
  636 +
  637 + // Return
  638 + return;
  639 +
  640 +}
  641 +
  642 +
  643 +/***********************************************************************//**
  644 + * @brief Evaluates the log-likelihood
  645 + *
  646 + * @param[in] value Parameter factor value
  647 + * @return Log-likelihood value
  648 + *
  649 + * This method evaluates the log-likelihood as a function of the parameter
  650 + * of interest.
  651 + ***************************************************************************/
  652 +double ctulimit::evaluate(const double& value)
  653 +{
  654 + // Initialise log-likelihood value
  655 + double logL = 0.0;
  656 +
  657 + // Check if given parameter is within boundaries
  658 + if (value > m_model_par->min() && value < m_model_par->max()) {
  659 +
  660 + // Change parameter factor
  661 + m_model_par->value(value);
  662 +
  663 + // Evaluate likelihood for new model container
  664 + m_obs.eval();
  665 +
  666 + // Retrieve likelihood
  667 + logL = m_obs.logL();
  668 +
  669 + } // endif: value was inside allowed range
  670 +
  671 + // ... otherwise signal that the parameter went outside the boundaries
  672 + else {
  673 + std::string msg = "Value of parameter \""+m_model_par->name()+"\" "
  674 + "outside of validity range requested. To omit "
  675 + "this error please enlarge the parameter range "
  676 + "in the model XML file.";
  677 + throw GException::invalid_value(G_EVALUATE, msg);
  678 + }
  679 +
  680 + // Compute function value
  681 + double logL_difference = logL - m_best_logL - m_dlogL;
  682 +
  683 + // Return
  684 + return logL_difference;
  685 +}
src/ctulimit/ctulimit.hpp
1 /*************************************************************************** 1 /***************************************************************************
2 - * ctulimit - Upper limit calculation tool * 2 + * ctulimit - Upper limit calculation tool *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2014 by Michael Mayer * 4 + * copyright (C) 2015 by Michael Mayer *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 ***************************************************************************/ 20 ***************************************************************************/
21 /** 21 /**
22 * @file ctulimit.hpp 22 * @file ctulimit.hpp
23 - * @brief upper limit calculation tool interface definition 23 + * @brief Upper limit calculation tool interface definition
24 * @author Michael Mayer 24 * @author Michael Mayer
25 */ 25 */
26 26
@@ -34,7 +34,7 @@ @@ -34,7 +34,7 @@
34 34
35 /* __Definitions _________________________________________________________ */ 35 /* __Definitions _________________________________________________________ */
36 #define CTULIMIT_NAME "ctulimit" 36 #define CTULIMIT_NAME "ctulimit"
37 -#define CTULIMIT_VERSION "00-01-00" 37 +#define CTULIMIT_VERSION "01-00-00"
38 38
39 39
40 /***********************************************************************//** 40 /***********************************************************************//**
@@ -42,14 +42,13 @@ @@ -42,14 +42,13 @@
42 * 42 *
43 * @brief Upper limit calculation tool 43 * @brief Upper limit calculation tool
44 * 44 *
45 - * This class computes and upper limit for a given parameter. 45 + * This class computes and upper limit for a given source.
46 * 46 *
47 * The class operates on predefined observation containers, an individual 47 * The class operates on predefined observation containers, an individual
48 * event list or an observation definition XML file. 48 * event list or an observation definition XML file.
49 * 49 *
50 - * During the computation the likelihood function is inspected to find the best  
51 - * value for the upper limit.  
52 - * 50 + * During the computation the likelihood function is inspected to find the
  51 + * best value for the upper limit.
53 ***************************************************************************/ 52 ***************************************************************************/
54 class ctulimit : public ctool { 53 class ctulimit : public ctool {
55 54
@@ -69,43 +68,41 @@ public: @@ -69,43 +68,41 @@ public:
69 void run(void); 68 void run(void);
70 void save(void); 69 void save(void);
71 const GObservations& obs(void) const; 70 const GObservations& obs(void) const;
72 - const double& diff_ulimit(void) const;  
73 - const double& flux_ulimit(void) const;  
74 - const double& eflux_ulimit(void) const; 71 + const double& diff_ulimit(void) const;
  72 + const double& flux_ulimit(void) const;
  73 + const double& eflux_ulimit(void) const;
75 74
76 protected: 75 protected:
77 // Protected methods 76 // Protected methods
78 - void init_members(void);  
79 - void copy_members(const ctulimit& app);  
80 - void free_members(void);  
81 - void get_parameters(void);  
82 - void ulimit_bisection(const double& parmin, const double& parmax, const double& scale); 77 + void init_members(void);
  78 + void copy_members(const ctulimit& app);
  79 + void free_members(void);
  80 + void get_parameters(void);
  81 + void get_model_parameter(void);
  82 + void ulimit_bisection(const double& parmin, const double& parmax);
83 double evaluate(const double& value); 83 double evaluate(const double& value);
84 84
85 // User parameters 85 // User parameters
86 - std::string m_srcname; //!< Name of source which is moved around  
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 86 + std::string m_srcname; //!< Name of source which is moved around
  87 + std::string m_outfile; //!< Output ascii file
  88 + double m_sigma_min; //!< Starting value minimum (multiple fit errors above fit values)
  89 + double m_sigma_max; //!< Starting value maximum (multiple fit errors above fit values)
  90 + double m_eref; //!< Reference energy for flux limits (TeV)
  91 + double m_emin; //!< Minimum energy for flux limits (TeV)
  92 + double m_emax; //!< Maximum energy for flux limits (TeV)
  93 + double m_tol; //!< Tolerance for limit determination
  94 + int m_max_iter; //!< Maximum number of iterations
104 95
105 // Protected members 96 // Protected members
106 - GObservations m_obs; //!< Observation container  
107 - GModels m_models;  
108 - 97 + GObservations m_obs; //!< Observation container
  98 + GModels m_models;
  99 + double m_dlogL; //!< Likelihood difference for upper limit computation
  100 + GModelSky* m_skymodel; //!< Pointer to sky model
  101 + GModelPar* m_model_par; //!< Pointer to model parameter
  102 + double m_best_logL; //!< Best fit log likelihood of given model
  103 + double m_diff_ulimit; //!< Differential upper limit value
  104 + double m_flux_ulimit; //!< Flux upper limit value
  105 + double m_eflux_ulimit; //!< Energy flux upper limits
109 }; 106 };
110 107
111 108
src/ctulimit/ctulimit.par
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 # ------------------------------------------------------------------------- # 5 # ------------------------------------------------------------------------- #
6 # # 6 # #
7 # File: ctulimit.par # 7 # File: ctulimit.par #
8 -# Version: 00-01-00 # 8 +# Version: 01-00-00 #
9 # # 9 # #
10 # Author: Michael Mayer # 10 # Author: Michael Mayer #
11 # michael.mayer@physik.hu-berlin.de # 11 # michael.mayer@physik.hu-berlin.de #
@@ -17,26 +17,26 @@ @@ -17,26 +17,26 @@
17 # 17 #
18 # General parameters 18 # General parameters
19 #=================== 19 #===================
20 -inobs, f, a, "events.fits",,,"Input event list, counts cube or observation definition file" 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" 21 inmodel, f, a, "$CTOOLS/share/models/crab.xml",,, "Source model"
22 -srcname, s, a, "Crab",,,"Source of interest" 22 +srcname, s, a, "Crab",,, "Source of interest"
23 expcube, f, a, "NONE",,, "Exposure cube file (only needed for stacked analysis)" 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)" 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, "upperlimit.txt",,, "Output ascii file" 27 +outfile, f, a, "upperlimit.txt",,, "Output ASCII file"
28 28
29 # 29 #
30 # Upper limit calculation parameters 30 # Upper limit calculation parameters
31 #=================================== 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" 32 +confidence, r, h, 0.95,0.0,1.0, "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 (TeV)"
  36 +emin, r, h, 1.0,,, "Minimum energy for flux limits (TeV)"
  37 +emax, r, h, 100.0,,, "Maximum energy for flux limits (TeV)"
  38 +tol, r, h, 1e-5,,, "Computation tolerance"
  39 +max_iter, i, h, 50,,, "Maximum number of iterations"
40 40
41 # 41 #
42 # Standard parameters 42 # Standard parameters
src/ctulimit/main.cpp
1 /*************************************************************************** 1 /***************************************************************************
2 - * ctulimit - upper limit calculation tool * 2 + * ctulimit - upper limit calculation tool *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2014 by Michael Mayer * 4 + * copyright (C) 2015 by Michael Mayer *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
test/test_ctulimit.py
1 #! /usr/bin/env python 1 #! /usr/bin/env python
2 # ========================================================================== 2 # ==========================================================================
3 -# This scripts performs unit tests for the cttsmap tool. 3 +# This scripts performs unit tests for the ctulimit tool.
4 # 4 #
5 -# Copyright (C) 2014 Juergen Knoedlseder 5 +# Copyright (C) 2015 Michael Mayer
6 # 6 #
7 # This program is free software: you can redistribute it and/or modify 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 8 # it under the terms of the GNU General Public License as published by