Commit 115eb8a9ed6d424e6043afcf214098b3e5cd3e57
1 parent
b8e1637c
Use new GApplication logger methods and enhance ctool unit tests (#1828)
Showing
7 changed files
with
459 additions
and
271 deletions
src/cterror/cterror.cpp
| @@ -228,35 +228,15 @@ void cterror::run(void) | @@ -228,35 +228,15 @@ void cterror::run(void) | ||
| 228 | // Get task parameters | 228 | // Get task parameters |
| 229 | get_parameters(); | 229 | get_parameters(); |
| 230 | 230 | ||
| 231 | - // Set energy dispersion flag for all CTA observations and save old | 231 | + // Set energy dispersion flags of all CTA observations and save old |
| 232 | // values in save_edisp vector | 232 | // values in save_edisp vector |
| 233 | - std::vector<bool> save_edisp; | ||
| 234 | - save_edisp.assign(m_obs.size(), false); | ||
| 235 | - for (int i = 0; i < m_obs.size(); ++i) { | ||
| 236 | - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); | ||
| 237 | - if (obs != NULL) { | ||
| 238 | - save_edisp[i] = obs->response()->apply_edisp(); | ||
| 239 | - obs->response()->apply_edisp(m_apply_edisp); | ||
| 240 | - } | ||
| 241 | - } | 233 | + std::vector<bool> save_edisp = set_edisp(m_obs, m_apply_edisp); |
| 242 | 234 | ||
| 243 | - // Write observation(s) into logger | ||
| 244 | - if (logTerse()) { | ||
| 245 | - log << std::endl; | ||
| 246 | - if (m_obs.size() > 1) { | ||
| 247 | - log.header1("Observations"); | ||
| 248 | - } | ||
| 249 | - else { | ||
| 250 | - log.header1("Observation"); | ||
| 251 | - } | ||
| 252 | - log << m_obs << std::endl; | ||
| 253 | - } | 235 | + // Write input observation container into logger |
| 236 | + log_observations(NORMAL, m_obs, "Input observation"); | ||
| 254 | 237 | ||
| 255 | - // Write header | ||
| 256 | - if (logTerse()) { | ||
| 257 | - log << std::endl; | ||
| 258 | - log.header1("Compute best-fit likelihood"); | ||
| 259 | - } | 238 | + // Write header into logger |
| 239 | + log_header1(TERSE, "Compute best-fit likelihood"); | ||
| 260 | 240 | ||
| 261 | // Optimize and save best log-likelihood | 241 | // Optimize and save best log-likelihood |
| 262 | m_obs.optimize(m_opt); | 242 | m_obs.optimize(m_opt); |
| @@ -266,13 +246,10 @@ void cterror::run(void) | @@ -266,13 +246,10 @@ void cterror::run(void) | ||
| 266 | // Store optimizer for later recovery | 246 | // Store optimizer for later recovery |
| 267 | GOptimizerLM best_opt = m_opt; | 247 | GOptimizerLM best_opt = m_opt; |
| 268 | 248 | ||
| 269 | - // Write optimised model into logger | ||
| 270 | - if (logTerse()) { | ||
| 271 | - log << m_opt << std::endl; | ||
| 272 | - log << gammalib::parformat("Maximum log likelihood"); | ||
| 273 | - log << gammalib::str(m_best_logL,3) << std::endl; | ||
| 274 | - log << m_obs.models() << std::endl; | ||
| 275 | - } | 249 | + // Write optimisation results and models into logger |
| 250 | + log_string(NORMAL, m_opt.print(m_chatter)); | ||
| 251 | + log_value(NORMAL, "Maximum log likelihood", gammalib::str(m_best_logL,3)); | ||
| 252 | + log_string(NORMAL, m_obs.models().print(m_chatter)); | ||
| 276 | 253 | ||
| 277 | // Continue only if source model exists | 254 | // Continue only if source model exists |
| 278 | if (m_obs.models().contains(m_srcname)) { | 255 | if (m_obs.models().contains(m_srcname)) { |
| @@ -310,63 +287,39 @@ void cterror::run(void) | @@ -310,63 +287,39 @@ void cterror::run(void) | ||
| 310 | double parmax = std::min(m_model_par->factor_max(), | 287 | double parmax = std::min(m_model_par->factor_max(), |
| 311 | m_value + 10.0*m_model_par->factor_error()); | 288 | m_value + 10.0*m_model_par->factor_error()); |
| 312 | 289 | ||
| 313 | - // Write header | ||
| 314 | - if (logTerse()) { | ||
| 315 | - log << std::endl; | ||
| 316 | - log.header1("Compute error for source \""+m_srcname+"\"" | ||
| 317 | - " parameter \""+m_model_par->name()+"\""); | ||
| 318 | - log << gammalib::parformat("Confidence level"); | ||
| 319 | - log << m_confidence*100.0 << "%" << std::endl; | ||
| 320 | - log << gammalib::parformat("Log-likelihood difference"); | ||
| 321 | - log << m_dlogL << std::endl; | ||
| 322 | - log << gammalib::parformat("Initial factor range"); | ||
| 323 | - log << "["; | ||
| 324 | - log << parmin; | ||
| 325 | - log << ", "; | ||
| 326 | - log << parmax; | ||
| 327 | - log << "]" << std::endl; | ||
| 328 | - } | 290 | + // Write header and initial parameters into logger |
| 291 | + log_header1(TERSE, "Compute error for source \""+m_srcname+"\"" | ||
| 292 | + " parameter \""+m_model_par->name()+"\""); | ||
| 293 | + log_value(NORMAL, "Confidence level", | ||
| 294 | + gammalib::str(m_confidence*100.0)+" %"); | ||
| 295 | + log_value(NORMAL, "Log-likelihood difference", m_dlogL); | ||
| 296 | + log_value(NORMAL, "Initial factor range", | ||
| 297 | + "["+gammalib::str(parmin)+", "+gammalib::str(parmax)+"]"); | ||
| 329 | 298 | ||
| 330 | - // Compute lower boundary | 299 | + // Compute lower and upper boundaries |
| 331 | double value_lo = error_bisection(parmin, m_value); | 300 | double value_lo = error_bisection(parmin, m_value); |
| 332 | - | ||
| 333 | - // Write lower parameter value | ||
| 334 | - if (logTerse()) { | ||
| 335 | - log << gammalib::parformat("Lower parameter factor"); | ||
| 336 | - log << value_lo << std::endl; | ||
| 337 | - } | ||
| 338 | - | ||
| 339 | - // Compute upper boundary | ||
| 340 | double value_hi = error_bisection(m_value, parmax); | 301 | double value_hi = error_bisection(m_value, parmax); |
| 341 | 302 | ||
| 342 | - // Write upper parameter value | ||
| 343 | - if (logTerse()) { | ||
| 344 | - log << gammalib::parformat("Upper parameter factor"); | ||
| 345 | - log << value_hi << std::endl; | ||
| 346 | - } | ||
| 347 | - | ||
| 348 | // Compute errors | 303 | // Compute errors |
| 349 | - double error = 0.5 * (value_hi - value_lo); | ||
| 350 | - double error_neg = m_value - value_lo; | ||
| 351 | - double error_pos = value_hi - m_value; | ||
| 352 | - //double error_max = std::max(value_hi-m_value, m_value-value_lo); | ||
| 353 | - //double error_min = std::min(value_hi-m_value, m_value-value_lo); | ||
| 354 | - | ||
| 355 | - // Write errors | ||
| 356 | - if (logTerse()) { | ||
| 357 | - log << gammalib::parformat("Error from curvature"); | ||
| 358 | - log << m_model_par->error(); | ||
| 359 | - log << " " << m_model_par->unit() << std::endl; | ||
| 360 | - log << gammalib::parformat("Error from profile"); | ||
| 361 | - log << std::abs(error*m_model_par->scale()); | ||
| 362 | - log << " " << m_model_par->unit() << std::endl; | ||
| 363 | - log << gammalib::parformat("Negative profile error"); | ||
| 364 | - log << std::abs(error_neg*m_model_par->scale()); | ||
| 365 | - log << " " << m_model_par->unit() << std::endl; | ||
| 366 | - log << gammalib::parformat("Positive profile error"); | ||
| 367 | - log << std::abs(error_pos*m_model_par->scale()); | ||
| 368 | - log << " " << m_model_par->unit() << std::endl; | ||
| 369 | - } | 304 | + double error = 0.5 * (value_hi - value_lo); |
| 305 | + double error_neg = m_value - value_lo; | ||
| 306 | + double error_pos = value_hi - m_value; | ||
| 307 | + double error_value = std::abs(error*m_model_par->scale()); | ||
| 308 | + double error_value_neg = std::abs(error_neg*m_model_par->scale()); | ||
| 309 | + double error_value_pos = std::abs(error_pos*m_model_par->scale()); | ||
| 310 | + | ||
| 311 | + // Write results into logger | ||
| 312 | + std::string unit = " " + m_model_par->unit(); | ||
| 313 | + log_value(NORMAL, "Lower parameter factor", value_lo); | ||
| 314 | + log_value(NORMAL, "Upper parameter factor", value_hi); | ||
| 315 | + log_value(NORMAL, "Error from curvature", | ||
| 316 | + gammalib::str(m_model_par->error()) + unit); | ||
| 317 | + log_value(NORMAL, "Error from profile", | ||
| 318 | + gammalib::str(error_value) + unit); | ||
| 319 | + log_value(NORMAL, "Negative profile error", | ||
| 320 | + gammalib::str(error_value_neg) + unit); | ||
| 321 | + log_value(NORMAL, "Positive profile error", | ||
| 322 | + gammalib::str(error_value_pos) + unit); | ||
| 370 | 323 | ||
| 371 | // Save error result | 324 | // Save error result |
| 372 | model->at(i).factor_error(error); | 325 | model->at(i).factor_error(error); |
| @@ -381,13 +334,8 @@ void cterror::run(void) | @@ -381,13 +334,8 @@ void cterror::run(void) | ||
| 381 | // Recover optimizer | 334 | // Recover optimizer |
| 382 | m_opt = best_opt; | 335 | m_opt = best_opt; |
| 383 | 336 | ||
| 384 | - // Restore energy dispersion flag for all CTA observations | ||
| 385 | - for (int i = 0; i < m_obs.size(); ++i) { | ||
| 386 | - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); | ||
| 387 | - if (obs != NULL) { | ||
| 388 | - obs->response()->apply_edisp(save_edisp[i]); | ||
| 389 | - } | ||
| 390 | - } | 337 | + // Restore energy dispersion flags of all CTA observations |
| 338 | + restore_edisp(m_obs, save_edisp); | ||
| 391 | 339 | ||
| 392 | // Return | 340 | // Return |
| 393 | return; | 341 | return; |
| @@ -402,27 +350,26 @@ void cterror::run(void) | @@ -402,27 +350,26 @@ void cterror::run(void) | ||
| 402 | void cterror::save(void) | 350 | void cterror::save(void) |
| 403 | { | 351 | { |
| 404 | // Write header | 352 | // Write header |
| 405 | - if (logTerse()) { | ||
| 406 | - log << std::endl; | ||
| 407 | - log.header1("Save results"); | ||
| 408 | - } | 353 | + log_header1(TERSE, "Save results"); |
| 409 | 354 | ||
| 410 | // Get output filename | 355 | // Get output filename |
| 411 | m_outmodel = (*this)["outmodel"].filename(); | 356 | m_outmodel = (*this)["outmodel"].filename(); |
| 412 | 357 | ||
| 413 | - // Save only if filename is non-empty | 358 | + // Save only if filename is not empty and not "NONE" |
| 414 | if (!m_outmodel.is_empty() && | 359 | if (!m_outmodel.is_empty() && |
| 415 | gammalib::toupper(m_outmodel.url()) != "NONE") { | 360 | gammalib::toupper(m_outmodel.url()) != "NONE") { |
| 416 | 361 | ||
| 417 | // Log filename | 362 | // Log filename |
| 418 | - if (logTerse()) { | ||
| 419 | - log << "Save errors into file \""+m_outmodel+"\"."; | ||
| 420 | - log << std::endl; | ||
| 421 | - } | 363 | + log_value(NORMAL, "Model definition file", m_outmodel.url()); |
| 422 | 364 | ||
| 423 | // Write results out as XML model | 365 | // Write results out as XML model |
| 424 | - m_obs.models().save(m_outmodel); | 366 | + m_obs.models().save(m_outmodel.url()); |
| 367 | + | ||
| 368 | + } | ||
| 425 | 369 | ||
| 370 | + // ... otherwise signal that file was not save | ||
| 371 | + else { | ||
| 372 | + log_value(NORMAL, "Model definition file", "NONE"); | ||
| 426 | } | 373 | } |
| 427 | 374 | ||
| 428 | // Return | 375 | // Return |
| @@ -448,6 +395,7 @@ void cterror::init_members(void) | @@ -448,6 +395,7 @@ void cterror::init_members(void) | ||
| 448 | m_tol = 1.0e-3; | 395 | m_tol = 1.0e-3; |
| 449 | m_max_iter = 50; | 396 | m_max_iter = 50; |
| 450 | m_value = 0.0; | 397 | m_value = 0.0; |
| 398 | + m_chatter = static_cast<GChatter>(2); | ||
| 451 | 399 | ||
| 452 | // Initialise protected members | 400 | // Initialise protected members |
| 453 | m_obs.clear(); | 401 | m_obs.clear(); |
| @@ -480,6 +428,7 @@ void cterror::copy_members(const cterror& app) | @@ -480,6 +428,7 @@ void cterror::copy_members(const cterror& app) | ||
| 480 | m_tol = app.m_tol; | 428 | m_tol = app.m_tol; |
| 481 | m_max_iter = app.m_max_iter; | 429 | m_max_iter = app.m_max_iter; |
| 482 | m_apply_edisp = app.m_apply_edisp; | 430 | m_apply_edisp = app.m_apply_edisp; |
| 431 | + m_chatter = app.m_chatter; | ||
| 483 | 432 | ||
| 484 | // Copy protected members | 433 | // Copy protected members |
| 485 | m_obs = app.m_obs; | 434 | m_obs = app.m_obs; |
| @@ -559,6 +508,7 @@ void cterror::get_parameters(void) | @@ -559,6 +508,7 @@ void cterror::get_parameters(void) | ||
| 559 | // Read other parameters | 508 | // Read other parameters |
| 560 | m_tol = (*this)["tol"].real(); | 509 | m_tol = (*this)["tol"].real(); |
| 561 | m_max_iter = (*this)["max_iter"].integer(); | 510 | m_max_iter = (*this)["max_iter"].integer(); |
| 511 | + m_chatter = static_cast<GChatter>((*this)["chatter"].integer()); | ||
| 562 | 512 | ||
| 563 | // Read ahead parameters that are only needed when the tool gets | 513 | // Read ahead parameters that are only needed when the tool gets |
| 564 | // executed | 514 | // executed |
| @@ -606,9 +556,7 @@ double cterror::error_bisection(const double& min, const double& max) | @@ -606,9 +556,7 @@ double cterror::error_bisection(const double& min, const double& max) | ||
| 606 | "consider setting the minimum parameter " | 556 | "consider setting the minimum parameter " |
| 607 | "value to a lower value, and re-run " | 557 | "value to a lower value, and re-run " |
| 608 | "cterror."; | 558 | "cterror."; |
| 609 | - if (logTerse()) { | ||
| 610 | - log << msg; | ||
| 611 | - } | 559 | + log_string(TERSE, msg); |
| 612 | break; | 560 | break; |
| 613 | } | 561 | } |
| 614 | else if (m_model_par->factor_max() - wrk_max < m_tol) { | 562 | else if (m_model_par->factor_max() - wrk_max < m_tol) { |
| @@ -618,9 +566,7 @@ double cterror::error_bisection(const double& min, const double& max) | @@ -618,9 +566,7 @@ double cterror::error_bisection(const double& min, const double& max) | ||
| 618 | "consider setting the maximum parameter " | 566 | "consider setting the maximum parameter " |
| 619 | "value to a higher value, and re-run " | 567 | "value to a higher value, and re-run " |
| 620 | "cterror."; | 568 | "cterror."; |
| 621 | - if (logTerse()) { | ||
| 622 | - log << msg; | ||
| 623 | - } | 569 | + log_string(TERSE, msg); |
| 624 | break; | 570 | break; |
| 625 | } | 571 | } |
| 626 | else { | 572 | else { |
| @@ -639,17 +585,9 @@ double cterror::error_bisection(const double& min, const double& max) | @@ -639,17 +585,9 @@ double cterror::error_bisection(const double& min, const double& max) | ||
| 639 | // Calculate function value | 585 | // Calculate function value |
| 640 | double eval_mid = evaluate(mid); | 586 | double eval_mid = evaluate(mid); |
| 641 | 587 | ||
| 642 | - // Log interval | ||
| 643 | - if (logExplicit()) { | ||
| 644 | - log << gammalib::parformat(" Iteration "+gammalib::str(iter)); | ||
| 645 | - log << "["; | ||
| 646 | - log << wrk_min; | ||
| 647 | - log << ", "; | ||
| 648 | - log << wrk_max; | ||
| 649 | - log << "] "; | ||
| 650 | - log << eval_mid; | ||
| 651 | - log << std::endl; | ||
| 652 | - } | 588 | + // Write interval into logger |
| 589 | + log_value(EXPLICIT, " Iteration "+gammalib::str(iter), | ||
| 590 | + "["+gammalib::str(wrk_min)+", "+gammalib::str(wrk_max)+"]"); | ||
| 653 | 591 | ||
| 654 | // Check for convergence inside tolerance | 592 | // Check for convergence inside tolerance |
| 655 | if (std::abs(eval_mid) < m_tol) { | 593 | if (std::abs(eval_mid) < m_tol) { |
src/cterror/cterror.hpp
| @@ -35,7 +35,7 @@ | @@ -35,7 +35,7 @@ | ||
| 35 | 35 | ||
| 36 | /* __Definitions _________________________________________________________ */ | 36 | /* __Definitions _________________________________________________________ */ |
| 37 | #define CTERROR_NAME "cterror" | 37 | #define CTERROR_NAME "cterror" |
| 38 | -#define CTERROR_VERSION "1.1.0" | 38 | +#define CTERROR_VERSION "1.2.0" |
| 39 | 39 | ||
| 40 | 40 | ||
| 41 | /***********************************************************************//** | 41 | /***********************************************************************//** |
| @@ -80,6 +80,7 @@ protected: | @@ -80,6 +80,7 @@ protected: | ||
| 80 | int m_max_iter; //!< Maximum number of iterations | 80 | int m_max_iter; //!< Maximum number of iterations |
| 81 | double m_value; //!< Parameter value | 81 | double m_value; //!< Parameter value |
| 82 | bool m_apply_edisp; //!< Apply energy dispersion? | 82 | bool m_apply_edisp; //!< Apply energy dispersion? |
| 83 | + GChatter m_chatter; //!< Chattiness | ||
| 83 | 84 | ||
| 84 | // Protected members | 85 | // Protected members |
| 85 | GObservations m_obs; //!< Observation container | 86 | GObservations m_obs; //!< Observation container |
| @@ -87,7 +88,6 @@ protected: | @@ -87,7 +88,6 @@ protected: | ||
| 87 | GModelPar* m_model_par; //!< Pointer to model parameter | 88 | GModelPar* m_model_par; //!< Pointer to model parameter |
| 88 | double m_best_logL; //!< Best fit log likelihood of given model | 89 | double m_best_logL; //!< Best fit log likelihood of given model |
| 89 | GOptimizerLM m_opt; //!< Optimizer | 90 | GOptimizerLM m_opt; //!< Optimizer |
| 90 | - | ||
| 91 | }; | 91 | }; |
| 92 | 92 | ||
| 93 | 93 |
src/ctlike/ctlike.cpp
| @@ -215,24 +215,12 @@ void ctlike::run(void) | @@ -215,24 +215,12 @@ void ctlike::run(void) | ||
| 215 | // Get parameters | 215 | // Get parameters |
| 216 | get_parameters(); | 216 | get_parameters(); |
| 217 | 217 | ||
| 218 | - // Set energy dispersion flag for all CTA observations and save old | 218 | + // Set energy dispersion flags of all CTA observations and save old |
| 219 | // values in save_edisp vector | 219 | // values in save_edisp vector |
| 220 | - std::vector<bool> save_edisp; | ||
| 221 | - save_edisp.assign(m_obs.size(), false); | ||
| 222 | - for (int i = 0; i < m_obs.size(); ++i) { | ||
| 223 | - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); | ||
| 224 | - if (obs != NULL) { | ||
| 225 | - save_edisp[i] = obs->response()->apply_edisp(); | ||
| 226 | - obs->response()->apply_edisp(m_apply_edisp); | ||
| 227 | - } | ||
| 228 | - } | 220 | + std::vector<bool> save_edisp = set_edisp(m_obs, m_apply_edisp); |
| 229 | 221 | ||
| 230 | - // Write observation(s) into logger | ||
| 231 | - if (logTerse()) { | ||
| 232 | - log << std::endl; | ||
| 233 | - log.header1(gammalib::number("Observation",m_obs.size())); | ||
| 234 | - log << m_obs.print(m_chatter) << std::endl; | ||
| 235 | - } | 222 | + // Write input observation container into logger |
| 223 | + log_observations(NORMAL, m_obs, "Input observation"); | ||
| 236 | 224 | ||
| 237 | // Optimize model parameters using LM optimizer | 225 | // Optimize model parameters using LM optimizer |
| 238 | optimize_lm(); | 226 | optimize_lm(); |
| @@ -303,29 +291,16 @@ void ctlike::run(void) | @@ -303,29 +291,16 @@ void ctlike::run(void) | ||
| 303 | } | 291 | } |
| 304 | 292 | ||
| 305 | // Write results into logger | 293 | // Write results into logger |
| 306 | - if (logTerse()) { | ||
| 307 | - log << std::endl; | ||
| 308 | - log.header1("Maximum likelihood optimisation results"); | ||
| 309 | - log << m_opt->print(m_chatter) << std::endl; | ||
| 310 | - log << gammalib::parformat("Maximum log likelihood"); | ||
| 311 | - log << gammalib::str(m_logL,3) << std::endl; | ||
| 312 | - log << gammalib::parformat("Observed events (Nobs)"); | ||
| 313 | - log << gammalib::str(num_events, 3) << std::endl; | ||
| 314 | - log << gammalib::parformat("Predicted events (Npred)"); | ||
| 315 | - log << gammalib::str(npred, 3); | ||
| 316 | - log << " (Nobs - Npred = "; | ||
| 317 | - log << gammalib::str(num_events-npred); | ||
| 318 | - log << ")" << std::endl; | ||
| 319 | - log << m_obs.models().print(m_chatter) << std::endl; | ||
| 320 | - } | 294 | + log_header1(NORMAL, "Maximum likelihood optimisation results"); |
| 295 | + log_string(NORMAL, m_opt->print(m_chatter)); | ||
| 296 | + log_value(NORMAL, "Maximum log likelihood", gammalib::str(m_logL,3)); | ||
| 297 | + log_value(NORMAL, "Observed events (Nobs)", gammalib::str(num_events,3)); | ||
| 298 | + log_value(NORMAL, "Predicted events (Npred)", gammalib::str(npred,3)+ | ||
| 299 | + " (Nobs - Npred = "+gammalib::str(num_events-npred)+")"); | ||
| 300 | + log_string(NORMAL, m_obs.models().print(m_chatter)); | ||
| 321 | 301 | ||
| 322 | - // Restore energy dispersion flag for all CTA observations | ||
| 323 | - for (int i = 0; i < m_obs.size(); ++i) { | ||
| 324 | - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); | ||
| 325 | - if (obs != NULL) { | ||
| 326 | - obs->response()->apply_edisp(save_edisp[i]); | ||
| 327 | - } | ||
| 328 | - } | 302 | + // Restore energy dispersion flags of all CTA observations |
| 303 | + restore_edisp(m_obs, save_edisp); | ||
| 329 | 304 | ||
| 330 | // Return | 305 | // Return |
| 331 | return; | 306 | return; |
| @@ -340,10 +315,7 @@ void ctlike::run(void) | @@ -340,10 +315,7 @@ void ctlike::run(void) | ||
| 340 | void ctlike::save(void) | 315 | void ctlike::save(void) |
| 341 | { | 316 | { |
| 342 | // Write header | 317 | // Write header |
| 343 | - if (logTerse()) { | ||
| 344 | - log << std::endl; | ||
| 345 | - log.header1("Save results"); | ||
| 346 | - } | 318 | + log_header1(TERSE, "Save results"); |
| 347 | 319 | ||
| 348 | // Get output filename | 320 | // Get output filename |
| 349 | m_outmodel = (*this)["outmodel"].filename(); | 321 | m_outmodel = (*this)["outmodel"].filename(); |
| @@ -353,16 +325,18 @@ void ctlike::save(void) | @@ -353,16 +325,18 @@ void ctlike::save(void) | ||
| 353 | gammalib::toupper(m_outmodel.url()) != "NONE") { | 325 | gammalib::toupper(m_outmodel.url()) != "NONE") { |
| 354 | 326 | ||
| 355 | // Log filename | 327 | // Log filename |
| 356 | - if (logTerse()) { | ||
| 357 | - log << "Save fitted parameters into file \""+m_outmodel+"\"."; | ||
| 358 | - log << std::endl; | ||
| 359 | - } | 328 | + log_value(NORMAL, "Model definition file", m_outmodel.url()); |
| 360 | 329 | ||
| 361 | // Write results out as XML model | 330 | // Write results out as XML model |
| 362 | m_obs.models().save(m_outmodel); | 331 | m_obs.models().save(m_outmodel); |
| 363 | 332 | ||
| 364 | } | 333 | } |
| 365 | 334 | ||
| 335 | + // ... otherwise signal that file was not save | ||
| 336 | + else { | ||
| 337 | + log_value(NORMAL, "Model definition file", "NONE"); | ||
| 338 | + } | ||
| 339 | + | ||
| 366 | // Return | 340 | // Return |
| 367 | return; | 341 | return; |
| 368 | } | 342 | } |
| @@ -434,7 +408,7 @@ void ctlike::get_parameters(void) | @@ -434,7 +408,7 @@ void ctlike::get_parameters(void) | ||
| 434 | } | 408 | } |
| 435 | 409 | ||
| 436 | // Set optimizer logger | 410 | // Set optimizer logger |
| 437 | - if (logTerse()) { | 411 | + if (logNormal()) { |
| 438 | static_cast<GOptimizerLM*>(m_opt)->logger(&log); | 412 | static_cast<GOptimizerLM*>(m_opt)->logger(&log); |
| 439 | } | 413 | } |
| 440 | else { | 414 | else { |
| @@ -456,12 +430,9 @@ void ctlike::get_parameters(void) | @@ -456,12 +430,9 @@ void ctlike::get_parameters(void) | ||
| 456 | ***************************************************************************/ | 430 | ***************************************************************************/ |
| 457 | void ctlike::optimize_lm(void) | 431 | void ctlike::optimize_lm(void) |
| 458 | { | 432 | { |
| 459 | - // Write Header for optimization and indent for optimizer logging | ||
| 460 | - if (logTerse()) { | ||
| 461 | - log << std::endl; | ||
| 462 | - log.header1("Maximum likelihood optimisation"); | ||
| 463 | - log.indent(1); | ||
| 464 | - } | 433 | + // Write header |
| 434 | + log_header1(TERSE, "Maximum likelihood optimisation"); | ||
| 435 | + log.indent(1); | ||
| 465 | 436 | ||
| 466 | // Compute number of fitted parameters | 437 | // Compute number of fitted parameters |
| 467 | int nfit = 0; | 438 | int nfit = 0; |
| @@ -476,14 +447,9 @@ void ctlike::optimize_lm(void) | @@ -476,14 +447,9 @@ void ctlike::optimize_lm(void) | ||
| 476 | 447 | ||
| 477 | // Notify if all parameters are fixed | 448 | // Notify if all parameters are fixed |
| 478 | if (nfit == 0) { | 449 | if (nfit == 0) { |
| 479 | - if (logTerse()) { | ||
| 480 | - log << "WARNING: All model parameters are fixed!"; | ||
| 481 | - log << std::endl; | ||
| 482 | - log << " ctlike will proceed without fitting parameters."; | ||
| 483 | - log << std::endl; | ||
| 484 | - log << " All curvature matrix elements will be zero."; | ||
| 485 | - log << std::endl; | ||
| 486 | - } | 450 | + log_string(TERSE, "WARNING: All model parameters are fixed!"); |
| 451 | + log_string(TERSE, " ctlike will proceed without fitting parameters."); | ||
| 452 | + log_string(TERSE, " All curvature matrix elements will be zero."); | ||
| 487 | } | 453 | } |
| 488 | 454 | ||
| 489 | // Perform LM optimization | 455 | // Perform LM optimization |
| @@ -494,11 +460,8 @@ void ctlike::optimize_lm(void) | @@ -494,11 +460,8 @@ void ctlike::optimize_lm(void) | ||
| 494 | 460 | ||
| 495 | // Dump new header | 461 | // Dump new header |
| 496 | log.indent(0); | 462 | log.indent(0); |
| 497 | - if (logTerse()) { | ||
| 498 | - log << std::endl; | ||
| 499 | - log.header1("Maximum likelihood re-optimisation"); | ||
| 500 | - log.indent(1); | ||
| 501 | - } | 463 | + log_header1(TERSE, "Maximum likelihood re-optimisation"); |
| 464 | + log.indent(1); | ||
| 502 | 465 | ||
| 503 | // Optimise again | 466 | // Optimise again |
| 504 | m_obs.optimize(*m_opt); | 467 | m_obs.optimize(*m_opt); |
| @@ -506,13 +469,10 @@ void ctlike::optimize_lm(void) | @@ -506,13 +469,10 @@ void ctlike::optimize_lm(void) | ||
| 506 | } | 469 | } |
| 507 | 470 | ||
| 508 | // Optionally show curvature matrix | 471 | // Optionally show curvature matrix |
| 509 | - if (logNormal()) { | ||
| 510 | - log << std::endl; | ||
| 511 | - log.header1("Curvature matrix"); | ||
| 512 | - log.indent(1); | ||
| 513 | - log << *(const_cast<GObservations::likelihood&>(m_obs.function()).curvature()); | ||
| 514 | - log << std::endl; | ||
| 515 | - } | 472 | + log_header1(EXPLICIT, "Curvature matrix"); |
| 473 | + log.indent(1); | ||
| 474 | + log_string(EXPLICIT, (const_cast<GObservations::likelihood&> | ||
| 475 | + (m_obs.function()).curvature())->print()); | ||
| 516 | 476 | ||
| 517 | // Compute errors | 477 | // Compute errors |
| 518 | m_obs.errors(*m_opt); | 478 | m_obs.errors(*m_opt); |
| @@ -537,11 +497,8 @@ void ctlike::optimize_lm(void) | @@ -537,11 +497,8 @@ void ctlike::optimize_lm(void) | ||
| 537 | double ctlike::reoptimize_lm(void) | 497 | double ctlike::reoptimize_lm(void) |
| 538 | { | 498 | { |
| 539 | // Write Header for optimization and indent for optimizer logging | 499 | // Write Header for optimization and indent for optimizer logging |
| 540 | - if (logTerse()) { | ||
| 541 | - log << std::endl; | ||
| 542 | - log.header1("Maximum likelihood re-optimisation"); | ||
| 543 | - log.indent(1); | ||
| 544 | - } | 500 | + log_header1(TERSE, "Maximum likelihood re-optimisation"); |
| 501 | + log.indent(1); | ||
| 545 | 502 | ||
| 546 | // Create a clone of the optimizer for the re-optimisation | 503 | // Create a clone of the optimizer for the re-optimisation |
| 547 | GOptimizer* opt = m_opt->clone(); | 504 | GOptimizer* opt = m_opt->clone(); |
| @@ -559,11 +516,8 @@ double ctlike::reoptimize_lm(void) | @@ -559,11 +516,8 @@ double ctlike::reoptimize_lm(void) | ||
| 559 | 516 | ||
| 560 | // Write optimization results | 517 | // Write optimization results |
| 561 | log.indent(0); | 518 | log.indent(0); |
| 562 | - if (logTerse()) { | ||
| 563 | - log << std::endl; | ||
| 564 | - log.header1("Maximum likelihood re-optimisation results"); | ||
| 565 | - log << *opt << std::endl; | ||
| 566 | - } | 519 | + log_header1(NORMAL, "Maximum likelihood re-optimisation results"); |
| 520 | + log_string(NORMAL, opt->print(m_chatter)); | ||
| 567 | 521 | ||
| 568 | // Return | 522 | // Return |
| 569 | return (logL); | 523 | return (logL); |
src/support/ctool.cpp
| @@ -52,6 +52,8 @@ | @@ -52,6 +52,8 @@ | ||
| 52 | #define G_SETUP_OBSERVATION "ctool::setup_observations(GObservations&)" | 52 | #define G_SETUP_OBSERVATION "ctool::setup_observations(GObservations&)" |
| 53 | #define G_GET_MEAN_POINTING "ctool::get_mean_pointing(GObservations&)" | 53 | #define G_GET_MEAN_POINTING "ctool::get_mean_pointing(GObservations&)" |
| 54 | #define G_CREATE_EBOUNDS "ctool::create_ebounds()" | 54 | #define G_CREATE_EBOUNDS "ctool::create_ebounds()" |
| 55 | +#define G_RESTORE_EDISP "ctool::restore_edisp(GObservations&, "\ | ||
| 56 | + "std::vector<bool>&)" | ||
| 55 | #define G_SET_OBS_RESPONSE "ctool::set_obs_response(GCTAObservation*)" | 57 | #define G_SET_OBS_RESPONSE "ctool::set_obs_response(GCTAObservation*)" |
| 56 | #define G_PROVIDE_HELP "ctool::provide_help()" | 58 | #define G_PROVIDE_HELP "ctool::provide_help()" |
| 57 | 59 | ||
| @@ -994,7 +996,7 @@ void ctool::set_response(GObservations& obs) | @@ -994,7 +996,7 @@ void ctool::set_response(GObservations& obs) | ||
| 994 | // Is this observation a CTA observation? | 996 | // Is this observation a CTA observation? |
| 995 | GCTAObservation* cta = dynamic_cast<GCTAObservation*>(obs[i]); | 997 | GCTAObservation* cta = dynamic_cast<GCTAObservation*>(obs[i]); |
| 996 | 998 | ||
| 997 | - // Yes ... | 999 | + // Yes, the set the response if the observation does not yet have one |
| 998 | if (cta != NULL) { | 1000 | if (cta != NULL) { |
| 999 | 1001 | ||
| 1000 | // Set response if we don't have one | 1002 | // Set response if we don't have one |
| @@ -1012,6 +1014,87 @@ void ctool::set_response(GObservations& obs) | @@ -1012,6 +1014,87 @@ void ctool::set_response(GObservations& obs) | ||
| 1012 | 1014 | ||
| 1013 | 1015 | ||
| 1014 | /***********************************************************************//** | 1016 | /***********************************************************************//** |
| 1017 | + * @brief Set energy dispersion to CTA observations | ||
| 1018 | + * | ||
| 1019 | + * @param[in] obs Observation container. | ||
| 1020 | + * @param[in] edisp Requested energy dispersion flag. | ||
| 1021 | + * @return Vector of old energy dispersion flags. | ||
| 1022 | + * | ||
| 1023 | + * Applies energy dispersion to all CTA observations. The method returns a | ||
| 1024 | + * vector with the old energy dispersion flags. | ||
| 1025 | + ***************************************************************************/ | ||
| 1026 | +std::vector<bool> ctool::set_edisp(GObservations& obs, const bool& edisp) const | ||
| 1027 | +{ | ||
| 1028 | + // Allocate vector for energy dispersion flags of all observation in | ||
| 1029 | + // the container | ||
| 1030 | + std::vector<bool> old_edisp(obs.size(), false); | ||
| 1031 | + | ||
| 1032 | + // Loop over all observations in observation container | ||
| 1033 | + for (int i = 0; i < obs.size(); ++i) { | ||
| 1034 | + | ||
| 1035 | + // Is this observation a CTA observation? | ||
| 1036 | + GCTAObservation* cta = dynamic_cast<GCTAObservation*>(obs[i]); | ||
| 1037 | + | ||
| 1038 | + // Yes, then set the energy dispersion flag | ||
| 1039 | + if (cta != NULL) { | ||
| 1040 | + | ||
| 1041 | + // Save old energy dispersion flag | ||
| 1042 | + old_edisp[i] = cta->response()->apply_edisp(); | ||
| 1043 | + | ||
| 1044 | + // Set energy dispersion flag according to input parameter | ||
| 1045 | + cta->response()->apply_edisp(edisp); | ||
| 1046 | + | ||
| 1047 | + } // endif: observation was CTA observation | ||
| 1048 | + | ||
| 1049 | + } // endfor: loop over all observations in container | ||
| 1050 | + | ||
| 1051 | + // Return old energy dispersion flags | ||
| 1052 | + return old_edisp; | ||
| 1053 | +} | ||
| 1054 | + | ||
| 1055 | + | ||
| 1056 | +/***********************************************************************//** | ||
| 1057 | + * @brief Restore energy dispersion flags of CTA observations | ||
| 1058 | + * | ||
| 1059 | + * @param[in] obs Observation container. | ||
| 1060 | + * @param[in] edisp Vector of energy dispersion flags. | ||
| 1061 | + * | ||
| 1062 | + * Restores energy dispersion flags that have previously been returned by | ||
| 1063 | + * the set_edisp() method. The number of observations between the calls | ||
| 1064 | + * of the set_edisp() and this method has to be the same. | ||
| 1065 | + ***************************************************************************/ | ||
| 1066 | +void ctool::restore_edisp(GObservations& obs, const std::vector<bool>& edisp) const | ||
| 1067 | +{ | ||
| 1068 | + // Check that energy dispersion flag vector has the same size as the | ||
| 1069 | + // observation container | ||
| 1070 | + if (edisp.size() != obs.size()) { | ||
| 1071 | + std::string msg = "Size of energy dispersion flag vector ("+ | ||
| 1072 | + gammalib::str(edisp.size())+" elements) is " | ||
| 1073 | + "incompatible with number of observations in the " | ||
| 1074 | + "observation container ("+gammalib::str(obs.size())+ | ||
| 1075 | + " observation)."; | ||
| 1076 | + throw GException::invalid_value(G_RESTORE_EDISP, msg); | ||
| 1077 | + } | ||
| 1078 | + | ||
| 1079 | + // Loop over all observations in observation container | ||
| 1080 | + for (int i = 0; i < obs.size(); ++i) { | ||
| 1081 | + | ||
| 1082 | + // Is this observation a CTA observation? | ||
| 1083 | + GCTAObservation* cta = dynamic_cast<GCTAObservation*>(obs[i]); | ||
| 1084 | + | ||
| 1085 | + // Yes, then restore the energy dispersion flag | ||
| 1086 | + if (cta != NULL) { | ||
| 1087 | + cta->response()->apply_edisp(edisp[i]); | ||
| 1088 | + } | ||
| 1089 | + | ||
| 1090 | + } // endfor: loop over all observations in container | ||
| 1091 | + | ||
| 1092 | + // Return | ||
| 1093 | + return; | ||
| 1094 | +} | ||
| 1095 | + | ||
| 1096 | + | ||
| 1097 | +/***********************************************************************//** | ||
| 1015 | * @brief Set response for CTA observation | 1098 | * @brief Set response for CTA observation |
| 1016 | * | 1099 | * |
| 1017 | * @param[in,out] obs CTA observation | 1100 | * @param[in,out] obs CTA observation |
src/support/ctool.hpp
| @@ -94,14 +94,17 @@ protected: | @@ -94,14 +94,17 @@ protected: | ||
| 94 | const std::string& what = "Model"); | 94 | const std::string& what = "Model"); |
| 95 | 95 | ||
| 96 | // Protected support methods | 96 | // Protected support methods |
| 97 | - void set_response(GObservations& obs); | ||
| 98 | - void set_obs_response(GCTAObservation* obs); | ||
| 99 | - void set_obs_bounds(GObservations& obs); | ||
| 100 | - GSkyDir get_mean_pointing(const GObservations& obs); | ||
| 101 | - size_t get_current_rss(void); | ||
| 102 | - std::string get_obs_header(const GObservation* obs); | ||
| 103 | - GEnergies insert_energy_boundaries(const GEnergies& energies, | ||
| 104 | - const GCTAObservation& obs); | 97 | + void set_response(GObservations& obs); |
| 98 | + std::vector<bool> set_edisp(GObservations& obs, const bool& edisp) const; | ||
| 99 | + void restore_edisp(GObservations& obs, | ||
| 100 | + const std::vector<bool>& edisp) const; | ||
| 101 | + void set_obs_response(GCTAObservation* obs); | ||
| 102 | + void set_obs_bounds(GObservations& obs); | ||
| 103 | + GSkyDir get_mean_pointing(const GObservations& obs); | ||
| 104 | + size_t get_current_rss(void); | ||
| 105 | + std::string get_obs_header(const GObservation* obs); | ||
| 106 | + GEnergies insert_energy_boundaries(const GEnergies& energies, | ||
| 107 | + const GCTAObservation& obs); | ||
| 105 | 108 | ||
| 106 | // Protected warning strings | 109 | // Protected warning strings |
| 107 | std::string warn_too_few_energies(const GEnergies& energies) const; | 110 | std::string warn_too_few_energies(const GEnergies& energies) const; |
test/test_cterror.py
| @@ -101,14 +101,31 @@ class Test(test): | @@ -101,14 +101,31 @@ class Test(test): | ||
| 101 | """ | 101 | """ |
| 102 | Test cterror from Python | 102 | Test cterror from Python |
| 103 | """ | 103 | """ |
| 104 | - # Set-up cterror | 104 | + # Allocate cterror |
| 105 | error = ctools.cterror() | 105 | error = ctools.cterror() |
| 106 | + | ||
| 107 | + # Check that empty cterror tool holds an empty observation and | ||
| 108 | + # optimizer | ||
| 109 | + self._check_obs(error.obs(), nobs=0, nmodels=0) | ||
| 110 | + self._check_opt(error.opt()) | ||
| 111 | + | ||
| 112 | + # Check that saving saves an empty model definition file | ||
| 113 | + error['outmodel'] = 'cterror_py0.xml' | ||
| 114 | + error['logfile'] = 'cterror_py0.log' | ||
| 115 | + error.logFileOpen() | ||
| 116 | + error.save() | ||
| 117 | + self._check_result_file('cterror_py0.xml', nmodels=0) | ||
| 118 | + | ||
| 119 | + # Check that clearing does not lead to an exception or segfault | ||
| 120 | + error.clear() | ||
| 121 | + | ||
| 122 | + # Now set cterror parameters | ||
| 106 | error['inobs'] = self._events | 123 | error['inobs'] = self._events |
| 107 | error['inmodel'] = self._model | 124 | error['inmodel'] = self._model |
| 108 | - error['outmodel'] = 'cterror_py1.xml' | ||
| 109 | error['srcname'] = 'Crab' | 125 | error['srcname'] = 'Crab' |
| 110 | error['caldb'] = self._caldb | 126 | error['caldb'] = self._caldb |
| 111 | error['irf'] = self._irf | 127 | error['irf'] = self._irf |
| 128 | + error['outmodel'] = 'cterror_py1.xml' | ||
| 112 | error['logfile'] = 'cterror_py1.log' | 129 | error['logfile'] = 'cterror_py1.log' |
| 113 | error['chatter'] = 2 | 130 | error['chatter'] = 2 |
| 114 | 131 | ||
| @@ -120,38 +137,130 @@ class Test(test): | @@ -120,38 +137,130 @@ class Test(test): | ||
| 120 | # Check result file | 137 | # Check result file |
| 121 | self._check_result_file('cterror_py1.xml') | 138 | self._check_result_file('cterror_py1.xml') |
| 122 | 139 | ||
| 140 | + # Copy cterror tool | ||
| 141 | + cpy_error = error.copy() | ||
| 142 | + | ||
| 143 | + # Check observation and optimizer of copy | ||
| 144 | + self._check_obs(cpy_error.obs()) | ||
| 145 | + self._check_opt(cpy_error.opt()) | ||
| 146 | + | ||
| 147 | + # Execute copy of cterror tool again, now with a higher chatter | ||
| 148 | + # level than before | ||
| 149 | + cpy_error['outmodel'] = 'cterror_py2.xml' | ||
| 150 | + cpy_error['logfile'] = 'cterror_py2.log' | ||
| 151 | + cpy_error['chatter'] = 3 | ||
| 152 | + cpy_error.logFileOpen() # Needed to get a new log file | ||
| 153 | + cpy_error.execute() | ||
| 154 | + | ||
| 155 | + # Check result file | ||
| 156 | + self._check_result_file('cterror_py2.xml') | ||
| 157 | + | ||
| 158 | + # Now clear copy of cterror tool | ||
| 159 | + cpy_error.clear() | ||
| 160 | + | ||
| 161 | + # Check that the cleared copy has also cleared the observations | ||
| 162 | + self._check_obs(cpy_error.obs(), nobs=0, nmodels=0) | ||
| 163 | + | ||
| 123 | # Return | 164 | # Return |
| 124 | return | 165 | return |
| 125 | 166 | ||
| 126 | # Check result file | 167 | # Check result file |
| 127 | - def _check_result_file(self, filename): | 168 | + def _check_result_file(self, filename, nmodels=2): |
| 128 | """ | 169 | """ |
| 129 | Check result file | 170 | Check result file |
| 171 | + | ||
| 172 | + Parameters | ||
| 173 | + ---------- | ||
| 174 | + filename : str | ||
| 175 | + Model definition XML file | ||
| 176 | + nmodels : int, optional | ||
| 177 | + Expected number of models | ||
| 178 | + """ | ||
| 179 | + # Open models from result file | ||
| 180 | + models = gammalib.GModels(filename) | ||
| 181 | + | ||
| 182 | + # Check models | ||
| 183 | + self._check_models(models, nmodels=nmodels) | ||
| 184 | + | ||
| 185 | + # Return | ||
| 186 | + return | ||
| 187 | + | ||
| 188 | + # Check observation and models | ||
| 189 | + def _check_obs(self, obs, nobs=1, nmodels=2): | ||
| 190 | + """ | ||
| 191 | + Check observation and models | ||
| 192 | + | ||
| 193 | + Parameters | ||
| 194 | + ---------- | ||
| 195 | + obs : `~gammalib.GObservations` | ||
| 196 | + Models | ||
| 197 | + nobs : int, optional | ||
| 198 | + Expected number of observations | ||
| 199 | + nmodels : int, optional | ||
| 200 | + Expected number of models | ||
| 201 | + """ | ||
| 202 | + # Check number of observations | ||
| 203 | + self.test_value(obs.size(), nobs, 'Check number of observations') | ||
| 204 | + | ||
| 205 | + # Check models | ||
| 206 | + self._check_models(obs.models(), nmodels=nmodels) | ||
| 207 | + | ||
| 208 | + # Return | ||
| 209 | + return | ||
| 210 | + | ||
| 211 | + # Check models | ||
| 212 | + def _check_models(self, models, nmodels=2): | ||
| 213 | + """ | ||
| 214 | + Check observation and models | ||
| 215 | + | ||
| 216 | + Parameters | ||
| 217 | + ---------- | ||
| 218 | + models : `~gammalib.GModels` | ||
| 219 | + Models | ||
| 220 | + nmodels : int, optional | ||
| 221 | + Expected number of models | ||
| 222 | + """ | ||
| 223 | + # Check number of models | ||
| 224 | + self.test_value(models.size(), nmodels, 'Check number of models') | ||
| 225 | + | ||
| 226 | + # If there are models in the container then check them | ||
| 227 | + if nmodels > 0: | ||
| 228 | + self.test_value(models['Crab']['Prefactor'].value(), 1.58907e-16, | ||
| 229 | + 1.0e-3, 'Check fitted Crab Prefactor') | ||
| 230 | + self.test_value(models['Crab']['Prefactor'].error(), 0.0529105e-16, | ||
| 231 | + 1.0e-3, 'Check Crab Prefactor error') | ||
| 232 | + self.test_value(models['Crab']['Index'].value(), -2.43549, | ||
| 233 | + 1.0e-3, 'Check fitted Crab Index') | ||
| 234 | + self.test_value(models['Crab']['Index'].error(), 0.027804, | ||
| 235 | + 1.0e-3, 'Check Crab Index error') | ||
| 236 | + self.test_value(models['Background']['Prefactor'].value(), 61.6919e-6, | ||
| 237 | + 1.0e-3, 'Check fitted background Prefactor') | ||
| 238 | + self.test_value(models['Background']['Prefactor'].error(), 1.49438e-6, | ||
| 239 | + 1.0e-3, 'Check background Prefactor error') | ||
| 240 | + self.test_value(models['Background']['Index'].value(), -2.20535, | ||
| 241 | + 1.0e-3, 'Check fitted background Index') | ||
| 242 | + self.test_value(models['Background']['Index'].error(), 0.0113269, | ||
| 243 | + 1.0e-3, 'Check background Index error') | ||
| 244 | + self.test_value(models['Background']['Sigma'].value(), 3.04252, | ||
| 245 | + 1.0e-3, 'Check fitted background Sigma') | ||
| 246 | + self.test_value(models['Background']['Sigma'].error(), 0.0307008, | ||
| 247 | + 1.0e-3, 'Check background Sigma error') | ||
| 248 | + | ||
| 249 | + # Return | ||
| 250 | + return | ||
| 251 | + | ||
| 252 | + # Check optimizer | ||
| 253 | + def _check_opt(self, opt): | ||
| 254 | + """ | ||
| 255 | + Check optimizer | ||
| 256 | + | ||
| 257 | + Parameters | ||
| 258 | + ---------- | ||
| 259 | + opt : `~gammalib.GOptimizerLM` | ||
| 260 | + Optimizer | ||
| 130 | """ | 261 | """ |
| 131 | - # Open result file | ||
| 132 | - result = gammalib.GModels(filename) | ||
| 133 | - | ||
| 134 | - # Check results | ||
| 135 | - self.test_value(result['Crab']['Prefactor'].value(), 1.58907e-16, | ||
| 136 | - 1.0e-3, 'Check fitted Crab Prefactor') | ||
| 137 | - self.test_value(result['Crab']['Prefactor'].error(), 0.0529105e-16, | ||
| 138 | - 1.0e-3, 'Check Crab Prefactor error') | ||
| 139 | - self.test_value(result['Crab']['Index'].value(), -2.43549, | ||
| 140 | - 1.0e-3, 'Check fitted Crab Index') | ||
| 141 | - self.test_value(result['Crab']['Index'].error(), 0.027804, | ||
| 142 | - 1.0e-3, 'Check Crab Index error') | ||
| 143 | - self.test_value(result['Background']['Prefactor'].value(), 61.6919e-6, | ||
| 144 | - 1.0e-3, 'Check fitted background Prefactor') | ||
| 145 | - self.test_value(result['Background']['Prefactor'].error(), 1.49438e-6, | ||
| 146 | - 1.0e-3, 'Check background Prefactor error') | ||
| 147 | - self.test_value(result['Background']['Index'].value(), -2.20535, | ||
| 148 | - 1.0e-3, 'Check fitted background Index') | ||
| 149 | - self.test_value(result['Background']['Index'].error(), 0.0113269, | ||
| 150 | - 1.0e-3, 'Check background Index error') | ||
| 151 | - self.test_value(result['Background']['Sigma'].value(), 3.04252, | ||
| 152 | - 1.0e-3, 'Check fitted background Sigma') | ||
| 153 | - self.test_value(result['Background']['Sigma'].error(), 0.0307008, | ||
| 154 | - 1.0e-3, 'Check background Sigma error') | 262 | + # Check optimizer |
| 263 | + self.test_value(opt.status(), 0, 'Check optimizer status') | ||
| 155 | 264 | ||
| 156 | # Return | 265 | # Return |
| 157 | return | 266 | return |
test/test_ctlike.py
| @@ -101,8 +101,25 @@ class Test(test): | @@ -101,8 +101,25 @@ class Test(test): | ||
| 101 | """ | 101 | """ |
| 102 | Test ctlike from Python | 102 | Test ctlike from Python |
| 103 | """ | 103 | """ |
| 104 | - # Set-up ctlike | 104 | + # Allocate ctlike |
| 105 | like = ctools.ctlike() | 105 | like = ctools.ctlike() |
| 106 | + | ||
| 107 | + # Check that empty ctlike tool holds an empty observation and | ||
| 108 | + # optimizer | ||
| 109 | + self._check_obs(like.obs(), nobs=0, nmodels=0) | ||
| 110 | + self._check_opt(like.opt()) | ||
| 111 | + | ||
| 112 | + # Check that saving saves an empty model definition file | ||
| 113 | + like['outmodel'] = 'ctlike_py0.xml' | ||
| 114 | + like['logfile'] = 'ctlike_py0.log' | ||
| 115 | + like.logFileOpen() | ||
| 116 | + like.save() | ||
| 117 | + self._check_result_file('ctlike_py0.xml', nmodels=0) | ||
| 118 | + | ||
| 119 | + # Check that clearing does not lead to an exception or segfault | ||
| 120 | + like.clear() | ||
| 121 | + | ||
| 122 | + # Now set ctlike parameters | ||
| 106 | like['inobs'] = self._events | 123 | like['inobs'] = self._events |
| 107 | like['inmodel'] = self._model | 124 | like['inmodel'] = self._model |
| 108 | like['caldb'] = self._caldb | 125 | like['caldb'] = self._caldb |
| @@ -119,46 +136,130 @@ class Test(test): | @@ -119,46 +136,130 @@ class Test(test): | ||
| 119 | # Check result file | 136 | # Check result file |
| 120 | self._check_result_file('ctlike_py1.xml') | 137 | self._check_result_file('ctlike_py1.xml') |
| 121 | 138 | ||
| 122 | - # Retrieve observation container, save and check model file | ||
| 123 | - obs = like.obs() | ||
| 124 | - obs.models().save('ctlike_py2.xml') | 139 | + # Copy ctlike tool |
| 140 | + cpy_like = like.copy() | ||
| 141 | + | ||
| 142 | + # Check observation and optimizer of copy | ||
| 143 | + self._check_obs(cpy_like.obs()) | ||
| 144 | + self._check_opt(cpy_like.opt()) | ||
| 145 | + | ||
| 146 | + # Execute copy of ctlike tool again, now with a higher chatter | ||
| 147 | + # level than before | ||
| 148 | + cpy_like['outmodel'] = 'ctlike_py2.xml' | ||
| 149 | + cpy_like['logfile'] = 'ctlike_py2.log' | ||
| 150 | + cpy_like['chatter'] = 3 | ||
| 151 | + cpy_like.logFileOpen() # Needed to get a new log file | ||
| 152 | + cpy_like.execute() | ||
| 153 | + | ||
| 154 | + # Check result file | ||
| 125 | self._check_result_file('ctlike_py2.xml') | 155 | self._check_result_file('ctlike_py2.xml') |
| 126 | 156 | ||
| 127 | - # Retrieve optimizer | ||
| 128 | - opt = like.opt() | 157 | + # Now clear copy of ctlike tool |
| 158 | + cpy_like.clear() | ||
| 159 | + | ||
| 160 | + # Check that the cleared copy has also cleared the observations | ||
| 161 | + self._check_obs(cpy_like.obs(), nobs=0, nmodels=0) | ||
| 129 | 162 | ||
| 130 | # Return | 163 | # Return |
| 131 | return | 164 | return |
| 132 | 165 | ||
| 133 | # Check result file | 166 | # Check result file |
| 134 | - def _check_result_file(self, filename): | 167 | + def _check_result_file(self, filename, nmodels=2): |
| 135 | """ | 168 | """ |
| 136 | Check result file | 169 | Check result file |
| 170 | + | ||
| 171 | + Parameters | ||
| 172 | + ---------- | ||
| 173 | + filename : str | ||
| 174 | + Model definition XML file | ||
| 175 | + nmodels : int, optional | ||
| 176 | + Expected number of models | ||
| 177 | + """ | ||
| 178 | + # Open models from result file | ||
| 179 | + models = gammalib.GModels(filename) | ||
| 180 | + | ||
| 181 | + # Check models | ||
| 182 | + self._check_models(models, nmodels=nmodels) | ||
| 183 | + | ||
| 184 | + # Return | ||
| 185 | + return | ||
| 186 | + | ||
| 187 | + # Check observation and models | ||
| 188 | + def _check_obs(self, obs, nobs=1, nmodels=2): | ||
| 189 | + """ | ||
| 190 | + Check observation and models | ||
| 191 | + | ||
| 192 | + Parameters | ||
| 193 | + ---------- | ||
| 194 | + obs : `~gammalib.GObservations` | ||
| 195 | + Models | ||
| 196 | + nobs : int, optional | ||
| 197 | + Expected number of observations | ||
| 198 | + nmodels : int, optional | ||
| 199 | + Expected number of models | ||
| 200 | + """ | ||
| 201 | + # Check number of observations | ||
| 202 | + self.test_value(obs.size(), nobs, 'Check number of observations') | ||
| 203 | + | ||
| 204 | + # Check models | ||
| 205 | + self._check_models(obs.models(), nmodels=nmodels) | ||
| 206 | + | ||
| 207 | + # Return | ||
| 208 | + return | ||
| 209 | + | ||
| 210 | + # Check models | ||
| 211 | + def _check_models(self, models, nmodels=2): | ||
| 212 | + """ | ||
| 213 | + Check observation and models | ||
| 214 | + | ||
| 215 | + Parameters | ||
| 216 | + ---------- | ||
| 217 | + models : `~gammalib.GModels` | ||
| 218 | + Models | ||
| 219 | + nmodels : int, optional | ||
| 220 | + Expected number of models | ||
| 221 | + """ | ||
| 222 | + # Check number of models | ||
| 223 | + self.test_value(models.size(), nmodels, 'Check number of models') | ||
| 224 | + | ||
| 225 | + # If there are models in the container then check them | ||
| 226 | + if nmodels > 0: | ||
| 227 | + self.test_value(models['Crab']['Prefactor'].value(), 1.58907e-16, | ||
| 228 | + 1.0e-3, 'Check fitted Crab Prefactor') | ||
| 229 | + self.test_value(models['Crab']['Prefactor'].error(), 0.0526982e-16, | ||
| 230 | + 1.0e-3, 'Check Crab Prefactor error') | ||
| 231 | + self.test_value(models['Crab']['Index'].value(), -2.43549, | ||
| 232 | + 1.0e-3, 'Check fitted Crab Index') | ||
| 233 | + self.test_value(models['Crab']['Index'].error(), 0.0248116, | ||
| 234 | + 1.0e-3, 'Check Crab Index error') | ||
| 235 | + self.test_value(models['Background']['Prefactor'].value(), 61.6919e-6, | ||
| 236 | + 1.0e-3, 'Check fitted background Prefactor') | ||
| 237 | + self.test_value(models['Background']['Prefactor'].error(), 1.49438e-6, | ||
| 238 | + 1.0e-3, 'Check background Prefactor error') | ||
| 239 | + self.test_value(models['Background']['Index'].value(), -2.20535, | ||
| 240 | + 1.0e-3, 'Check fitted background Index') | ||
| 241 | + self.test_value(models['Background']['Index'].error(), 0.0113269, | ||
| 242 | + 1.0e-3, 'Check background Index error') | ||
| 243 | + self.test_value(models['Background']['Sigma'].value(), 3.04252, | ||
| 244 | + 1.0e-3, 'Check fitted background Sigma') | ||
| 245 | + self.test_value(models['Background']['Sigma'].error(), 0.0307008, | ||
| 246 | + 1.0e-3, 'Check background Sigma error') | ||
| 247 | + | ||
| 248 | + # Return | ||
| 249 | + return | ||
| 250 | + | ||
| 251 | + # Check optimizer | ||
| 252 | + def _check_opt(self, opt): | ||
| 253 | + """ | ||
| 254 | + Check optimizer | ||
| 255 | + | ||
| 256 | + Parameters | ||
| 257 | + ---------- | ||
| 258 | + opt : `~gammalib.GOptimizerLM` | ||
| 259 | + Optimizer | ||
| 137 | """ | 260 | """ |
| 138 | - # Open result file | ||
| 139 | - result = gammalib.GModels(filename) | ||
| 140 | - | ||
| 141 | - # Check results | ||
| 142 | - self.test_value(result['Crab']['Prefactor'].value(), 1.58907e-16, | ||
| 143 | - 1.0e-3, 'Check fitted Crab Prefactor') | ||
| 144 | - self.test_value(result['Crab']['Prefactor'].error(), 0.0526982e-16, | ||
| 145 | - 1.0e-3, 'Check Crab Prefactor error') | ||
| 146 | - self.test_value(result['Crab']['Index'].value(), -2.43549, | ||
| 147 | - 1.0e-3, 'Check fitted Crab Index') | ||
| 148 | - self.test_value(result['Crab']['Index'].error(), 0.0248116, | ||
| 149 | - 1.0e-3, 'Check Crab Index error') | ||
| 150 | - self.test_value(result['Background']['Prefactor'].value(), 61.6919e-6, | ||
| 151 | - 1.0e-3, 'Check fitted background Prefactor') | ||
| 152 | - self.test_value(result['Background']['Prefactor'].error(), 1.49438e-6, | ||
| 153 | - 1.0e-3, 'Check background Prefactor error') | ||
| 154 | - self.test_value(result['Background']['Index'].value(), -2.20535, | ||
| 155 | - 1.0e-3, 'Check fitted background Index') | ||
| 156 | - self.test_value(result['Background']['Index'].error(), 0.0113269, | ||
| 157 | - 1.0e-3, 'Check background Index error') | ||
| 158 | - self.test_value(result['Background']['Sigma'].value(), 3.04252, | ||
| 159 | - 1.0e-3, 'Check fitted background Sigma') | ||
| 160 | - self.test_value(result['Background']['Sigma'].error(), 0.0307008, | ||
| 161 | - 1.0e-3, 'Check background Sigma error') | 261 | + # Check optimizer |
| 262 | + self.test_value(opt.status(), 0, 'Check optimizer status') | ||
| 162 | 263 | ||
| 163 | # Return | 264 | # Return |
| 164 | return | 265 | return |