Commit d9f31901af4bbdd60f1faef8b38d84dfe3fcd7fe
1 parent
e5a1a87e
implemented first version of ctulimit
Showing
10 changed files
with
613 additions
and
70 deletions
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
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& 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, "Chattiness of output" |
| 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__ == '__main__': |
| 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__ == '__main__': |
| 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__ == '__main__': |
| 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 | ... | ... |