Commit b554fc2efa1c85d671fd8fc1844fc497b86b6732
1 parent
9617e53e
Allow energy boundaries and energy value FITS file as input to ebinfile parameters (#1978)
Showing
7 changed files
with
98 additions
and
108 deletions
ChangeLog
| 1 | -2017-03-22 | 1 | +2017-03-24 |
| 2 | 2 | ||
| 3 | * Version 1.3.0 released | 3 | * Version 1.3.0 released |
| 4 | ======================== | 4 | ======================== |
| 5 | 5 | ||
| 6 | + Support energy boundary FITS file in ctmapcube (#1978) | ||
| 6 | Add csebins script (#1976) | 7 | Add csebins script (#1976) |
| 7 | - Take into account RoI in ctskymap and use numerical integration for IRF (#1975) | 8 | + Consider RoI in ctskymap and use numerical integration for IRF (#1975) |
| 8 | Set local language to english (#1370) | 9 | Set local language to english (#1370) |
| 9 | Enhance logfile output of csroot2caldb script | 10 | Enhance logfile output of csroot2caldb script |
| 10 | Set default deadc value to 0.98 (CTA has <2% deadtime) | 11 | Set default deadc value to 0.98 (CTA has <2% deadtime) |
NEWS
| 1 | New Features and Important Changes in ctools 1.3.0.dev1 | 1 | New Features and Important Changes in ctools 1.3.0.dev1 |
| 2 | 2 | ||
| 3 | -22 March 2017 | 3 | +24 March 2017 |
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | Introduction | 6 | Introduction |
| @@ -87,7 +87,8 @@ None | @@ -87,7 +87,8 @@ None | ||
| 87 | 87 | ||
| 88 | ctmapcube - CTA map cube generation | 88 | ctmapcube - CTA map cube generation |
| 89 | ----------------------------------- | 89 | ----------------------------------- |
| 90 | -None | 90 | +The tool now supports loading the energy binning definition from an energy |
| 91 | +boundary FITS file, behaving now similar to the other cube tools (#1978). | ||
| 91 | 92 | ||
| 92 | 93 | ||
| 93 | ctcubemask - CTA cube filtering | 94 | ctcubemask - CTA cube filtering |
src/ctmapcube/ctmapcube.cpp
| @@ -349,7 +349,7 @@ void ctmapcube::get_parameters(void) | @@ -349,7 +349,7 @@ void ctmapcube::get_parameters(void) | ||
| 349 | } // endif: there were no models | 349 | } // endif: there were no models |
| 350 | 350 | ||
| 351 | // Get energy binning parameters | 351 | // Get energy binning parameters |
| 352 | - GEnergies energies = create_energies(); | 352 | + GEnergies energies(create_ebounds()); |
| 353 | 353 | ||
| 354 | // Get spatial binning parameters | 354 | // Get spatial binning parameters |
| 355 | double xref = (*this)["xref"].real(); | 355 | double xref = (*this)["xref"].real(); |
| @@ -386,68 +386,6 @@ void ctmapcube::get_parameters(void) | @@ -386,68 +386,6 @@ void ctmapcube::get_parameters(void) | ||
| 386 | 386 | ||
| 387 | 387 | ||
| 388 | /***********************************************************************//** | 388 | /***********************************************************************//** |
| 389 | - * @brief Create map cube energies from user parameters | ||
| 390 | - * | ||
| 391 | - * Creates the map cube energies according to the user parameters. If the | ||
| 392 | - * @p ebinfile parameter is "FILE" the method loads the energy information | ||
| 393 | - * from a FITS file. The name of the FITS file is given by the @p ebinfile | ||
| 394 | - * parameter. If no extension name is specified the method will use assume | ||
| 395 | - * the name to be `ENERGIES`. | ||
| 396 | - * | ||
| 397 | - * If the @p ebinfile parameter is "LIN" the method will create a linearly | ||
| 398 | - * spaced series of @p enumbins energies in the interval @p emin to @p emax. | ||
| 399 | - * Otherwise, the @p ebinfile parameter is assumed to be "LOG" and the method | ||
| 400 | - * will create a logarithmically spaced series of @p enumbins energies in the | ||
| 401 | - * interval @p emin to @p emax. | ||
| 402 | - ***************************************************************************/ | ||
| 403 | -GEnergies ctmapcube::create_energies(void) | ||
| 404 | -{ | ||
| 405 | - // Allocate energies | ||
| 406 | - GEnergies energies; | ||
| 407 | - | ||
| 408 | - // Get energy binning algorithm | ||
| 409 | - std::string ebinalg = (*this)["ebinalg"].string(); | ||
| 410 | - | ||
| 411 | - // If energy binning algorithm is of type "FILE" (case sensitive), then | ||
| 412 | - // read energies from FITS file ... | ||
| 413 | - if (ebinalg == "FILE") { | ||
| 414 | - | ||
| 415 | - // Get filename | ||
| 416 | - GFilename ebinfile = (*this)["ebinfile"].filename(); | ||
| 417 | - | ||
| 418 | - // Load energies | ||
| 419 | - energies.load(ebinfile); | ||
| 420 | - | ||
| 421 | - } // endif: ebinalg was "FILE" | ||
| 422 | - | ||
| 423 | - // ... otherwise use a linear or a logarithmically-spaced energy binning | ||
| 424 | - else { | ||
| 425 | - | ||
| 426 | - // Get task parameters | ||
| 427 | - double emin = (*this)["emin"].real(); | ||
| 428 | - double emax = (*this)["emax"].real(); | ||
| 429 | - int enumbins = (*this)["enumbins"].integer(); | ||
| 430 | - | ||
| 431 | - // Initialise log mode for ebinning | ||
| 432 | - bool log = true; | ||
| 433 | - | ||
| 434 | - // Check if algorithm is linear | ||
| 435 | - if (ebinalg == "LIN") { | ||
| 436 | - log = false; | ||
| 437 | - } | ||
| 438 | - | ||
| 439 | - // Setup energies | ||
| 440 | - energies = GEnergies(enumbins, GEnergy(emin, "TeV"), | ||
| 441 | - GEnergy(emax, "TeV"), log); | ||
| 442 | - | ||
| 443 | - } // endelse: ebinalg was not "FILE" | ||
| 444 | - | ||
| 445 | - // Return energies | ||
| 446 | - return energies; | ||
| 447 | -} | ||
| 448 | - | ||
| 449 | - | ||
| 450 | -/***********************************************************************//** | ||
| 451 | * @brief Generate map cube | 389 | * @brief Generate map cube |
| 452 | * | 390 | * |
| 453 | * Generate map cube by looping over all sky models in the container. | 391 | * Generate map cube by looping over all sky models in the container. |
src/ctmapcube/ctmapcube.hpp
| 1 | /*************************************************************************** | 1 | /*************************************************************************** |
| 2 | * ctmapcube - Map cube generation tool * | 2 | * ctmapcube - Map cube generation tool * |
| 3 | * ----------------------------------------------------------------------- * | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2016 by Juergen Knoedlseder * | 4 | + * copyright (C) 2016-2017 by Juergen Knoedlseder * |
| 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 * |
| @@ -34,7 +34,7 @@ | @@ -34,7 +34,7 @@ | ||
| 34 | 34 | ||
| 35 | /* __Definitions _________________________________________________________ */ | 35 | /* __Definitions _________________________________________________________ */ |
| 36 | #define CTMAPCUBE_NAME "ctmapcube" | 36 | #define CTMAPCUBE_NAME "ctmapcube" |
| 37 | -#define CTMAPCUBE_VERSION "1.2.0" | 37 | +#define CTMAPCUBE_VERSION "1.3.0" |
| 38 | 38 | ||
| 39 | 39 | ||
| 40 | /***********************************************************************//** | 40 | /***********************************************************************//** |
| @@ -64,17 +64,16 @@ public: | @@ -64,17 +64,16 @@ public: | ||
| 64 | 64 | ||
| 65 | protected: | 65 | protected: |
| 66 | // Protected methods | 66 | // Protected methods |
| 67 | - void init_members(void); | ||
| 68 | - void copy_members(const ctmapcube& app); | ||
| 69 | - void free_members(void); | ||
| 70 | - void get_parameters(void); | ||
| 71 | - GEnergies create_energies(void); | ||
| 72 | - void create_cube(void); | ||
| 73 | - void add_model(GModelSky* model); | ||
| 74 | - void add_ptsrc_model(GModelSky* model); | ||
| 75 | - void get_bounding_circle(GModelSky* model, | ||
| 76 | - GSkyDir* dir, | ||
| 77 | - double* radius) const; | 67 | + void init_members(void); |
| 68 | + void copy_members(const ctmapcube& app); | ||
| 69 | + void free_members(void); | ||
| 70 | + void get_parameters(void); | ||
| 71 | + void create_cube(void); | ||
| 72 | + void add_model(GModelSky* model); | ||
| 73 | + void add_ptsrc_model(GModelSky* model); | ||
| 74 | + void get_bounding_circle(GModelSky* model, | ||
| 75 | + GSkyDir* dir, | ||
| 76 | + double* radius) const; | ||
| 78 | 77 | ||
| 79 | // User parameters | 78 | // User parameters |
| 80 | GFilename m_outcube; //!< Output map cube filename | 79 | GFilename m_outcube; //!< Output map cube filename |
src/support/ctool.cpp
| @@ -503,15 +503,19 @@ void ctool::setup_models(GObservations& obs, | @@ -503,15 +503,19 @@ void ctool::setup_models(GObservations& obs, | ||
| 503 | * @brief Create energy boundaries from user parameters | 503 | * @brief Create energy boundaries from user parameters |
| 504 | * | 504 | * |
| 505 | * @exception GException::invalid_value | 505 | * @exception GException::invalid_value |
| 506 | - * No valid energy boundary extension found. | 506 | + * No valid energy boundary extension found or invalid extension |
| 507 | + * name. | ||
| 507 | * | 508 | * |
| 508 | * Get the energy boundaries according to the user parameters. The method | 509 | * Get the energy boundaries according to the user parameters. The method |
| 509 | * supports loading of energy boundary information from the `EBOUNDS` or | 510 | * supports loading of energy boundary information from the `EBOUNDS` or |
| 510 | - * `ENERGYBINS` extension, or setting energy boundaries using a linear | ||
| 511 | - * or logarithmical spacing. | 511 | + * `ENERGYBINS` extension, loading of energy value information from the |
| 512 | + * `ENERGIES` extension, or setting energy boundaries using a linear or | ||
| 513 | + * logarithmical spacing. | ||
| 512 | * | 514 | * |
| 513 | * The following parameters are read: | 515 | * The following parameters are read: |
| 516 | + * | ||
| 514 | * ebinalg - Energy binning algorithm | 517 | * ebinalg - Energy binning algorithm |
| 518 | + * ebinfile - Name of file with energy binning | ||
| 515 | * emin - Minimum energy (if ebinalg != FILE) | 519 | * emin - Minimum energy (if ebinalg != FILE) |
| 516 | * emax - Maximum energy (if ebinalg != FILE) | 520 | * emax - Maximum energy (if ebinalg != FILE) |
| 517 | * enumbins - Number of energy bins (if ebinalg != FILE) | 521 | * enumbins - Number of energy bins (if ebinalg != FILE) |
| @@ -529,43 +533,72 @@ GEbounds ctool::create_ebounds(void) | @@ -529,43 +533,72 @@ GEbounds ctool::create_ebounds(void) | ||
| 529 | if (ebinalg == "FILE") { | 533 | if (ebinalg == "FILE") { |
| 530 | 534 | ||
| 531 | // Get filename | 535 | // Get filename |
| 532 | - std::string ebinfile = (*this)["ebinfile"].filename(); | ||
| 533 | - | ||
| 534 | - // Create filename instance | ||
| 535 | - GFilename fname(ebinfile); | 536 | + GFilename ebinfile = (*this)["ebinfile"].filename(); |
| 536 | 537 | ||
| 537 | - // Check if extension name was provided | ||
| 538 | - if (!fname.has_extname()) { | 538 | + // If no extension name was provided then use default extension names |
| 539 | + if (!ebinfile.has_extname()) { | ||
| 539 | 540 | ||
| 540 | // Open energy boundary file using the EBOUNDS or ENERGYBINS | 541 | // Open energy boundary file using the EBOUNDS or ENERGYBINS |
| 541 | - // extension. Throw an exception if opening fails. | ||
| 542 | - GFits file(ebinfile); | 542 | + // extension or energy values using the ENERGIES extension. |
| 543 | + // Throw an exception if opening fails. | ||
| 544 | + GFits file(ebinfile.url()); | ||
| 543 | if (file.contains(gammalib::extname_ebounds)) { | 545 | if (file.contains(gammalib::extname_ebounds)) { |
| 544 | file.close(); | 546 | file.close(); |
| 545 | ebounds.load(ebinfile); | 547 | ebounds.load(ebinfile); |
| 546 | } | 548 | } |
| 547 | else if (file.contains("ENERGYBINS")) { | 549 | else if (file.contains("ENERGYBINS")) { |
| 548 | file.close(); | 550 | file.close(); |
| 549 | - ebinfile += "[ENERGYBINS]"; | 551 | + ebinfile = ebinfile.url() + "[ENERGYBINS]"; |
| 550 | ebounds.load(ebinfile); | 552 | ebounds.load(ebinfile); |
| 551 | } | 553 | } |
| 554 | + else if (file.contains(gammalib::extname_energies)) { | ||
| 555 | + file.close(); | ||
| 556 | + ebounds.set(GEnergies(ebinfile)); | ||
| 557 | + } | ||
| 552 | else { | 558 | else { |
| 553 | file.close(); | 559 | file.close(); |
| 554 | std::string msg = "No extension with name \""+ | 560 | std::string msg = "No extension with name \""+ |
| 555 | - gammalib::extname_ebounds+"\" or" | ||
| 556 | - " \"ENERGYBINS\" found in FITS file" | ||
| 557 | - " \""+ebinfile+"\". An \""+ | ||
| 558 | - gammalib::extname_ebounds+"\" or " | ||
| 559 | - "\"ENERGYBINS\" extension is required if " | ||
| 560 | - "the parameter \"ebinalg\" is set to " | ||
| 561 | - "\"FILE\"."; | 561 | + gammalib::extname_ebounds+"\", " |
| 562 | + "\"ENERGYBINS\" or \""+ | ||
| 563 | + gammalib::extname_energies+"\" found in FITS " | ||
| 564 | + "file \""+ebinfile+"\". Please specify a " | ||
| 565 | + "valid energy binning file."; | ||
| 562 | throw GException::invalid_value(G_CREATE_EBOUNDS, msg); | 566 | throw GException::invalid_value(G_CREATE_EBOUNDS, msg); |
| 563 | } | 567 | } |
| 564 | } | 568 | } |
| 569 | + | ||
| 570 | + // ... otherwise load energy boundaries from filename including | ||
| 571 | + // extension | ||
| 565 | else { | 572 | else { |
| 566 | - // Load ebounds from filename including extension | ||
| 567 | - ebounds.load(ebinfile); | ||
| 568 | - } | 573 | + |
| 574 | + // Open energy boundary file | ||
| 575 | + GFits file(ebinfile.url()); | ||
| 576 | + | ||
| 577 | + // If FITS file does not contain requested extension then throw | ||
| 578 | + // an exception | ||
| 579 | + if (!file.contains(ebinfile.extname())) { | ||
| 580 | + std::string msg = "No extension \""+ebinfile.extname()+"\" " | ||
| 581 | + "found in energy binning file \""+ | ||
| 582 | + ebinfile.url()+"\". Please provide a valid " | ||
| 583 | + "extension name."; | ||
| 584 | + throw GException::invalid_value(G_CREATE_EBOUNDS, msg); | ||
| 585 | + } | ||
| 586 | + | ||
| 587 | + // Get table extension | ||
| 588 | + GFitsTable& table = *file.table(ebinfile.extname()); | ||
| 589 | + | ||
| 590 | + // If table contains one column then load energies, otherwise load | ||
| 591 | + // energy boundaries. | ||
| 592 | + if (table.ncols() == 1) { | ||
| 593 | + file.close(); | ||
| 594 | + ebounds.set(GEnergies(ebinfile)); | ||
| 595 | + } | ||
| 596 | + else { | ||
| 597 | + file.close(); | ||
| 598 | + ebounds.load(ebinfile); | ||
| 599 | + } | ||
| 600 | + | ||
| 601 | + } // endelse: loaded energy boundaries from table extension | ||
| 569 | 602 | ||
| 570 | } // endif: ebinalg was "FILE" | 603 | } // endif: ebinalg was "FILE" |
| 571 | 604 |
test/test_cscript.py
| @@ -238,7 +238,13 @@ class Test(test): | @@ -238,7 +238,13 @@ class Test(test): | ||
| 238 | gammalib.GEnergy(10.0,'TeV')) | 238 | gammalib.GEnergy(10.0,'TeV')) |
| 239 | ebounds.save('test_ebinfile_ebounds.fits[EBOUNDS]', True) | 239 | ebounds.save('test_ebinfile_ebounds.fits[EBOUNDS]', True) |
| 240 | ebounds.save('test_ebinfile_energybins.fits[ENERGYBINS]', True) | 240 | ebounds.save('test_ebinfile_energybins.fits[ENERGYBINS]', True) |
| 241 | - ebounds.save('test_ebinfile_energies.fits[ENERGIES]', True) | 241 | + ebounds.save('test_ebinfile_bins.fits[BINS]', True) |
| 242 | + | ||
| 243 | + # Create energy bin file | ||
| 244 | + energies = gammalib.GEnergies(2, gammalib.GEnergy(1.0,'TeV'), | ||
| 245 | + gammalib.GEnergy(10.0,'TeV')) | ||
| 246 | + energies.save('test_ebinfile_energies.fits[ENERGIES]', True) | ||
| 247 | + energies.save('test_ebinfile_engs.fits[ENGS]', True) | ||
| 242 | 248 | ||
| 243 | # Return | 249 | # Return |
| 244 | return | 250 | return |
| @@ -335,16 +341,28 @@ class Test(test): | @@ -335,16 +341,28 @@ class Test(test): | ||
| 335 | self.test_value(ebounds.emin().TeV(), 1.0, 'Check minimum energy') | 341 | self.test_value(ebounds.emin().TeV(), 1.0, 'Check minimum energy') |
| 336 | self.test_value(ebounds.emax().TeV(), 10.0, 'Check maximum energy') | 342 | self.test_value(ebounds.emax().TeV(), 10.0, 'Check maximum energy') |
| 337 | 343 | ||
| 344 | + # Test create_ebounds() method for "ENERGIES" extension | ||
| 345 | + ebounds = empty.check_create_ebounds('test_ebinfile_energies.fits') | ||
| 346 | + self.test_value(ebounds.size(), 1, 'Check number of energy boundaries') | ||
| 347 | + self.test_value(ebounds.emin().TeV(), 1.0, 'Check minimum energy') | ||
| 348 | + self.test_value(ebounds.emax().TeV(), 10.0, 'Check maximum energy') | ||
| 349 | + | ||
| 338 | # Test create_ebounds() method for invalid extension | 350 | # Test create_ebounds() method for invalid extension |
| 339 | self.test_try('Check create_ebounds() method for invalid extension') | 351 | self.test_try('Check create_ebounds() method for invalid extension') |
| 340 | try: | 352 | try: |
| 341 | - empty.check_create_ebounds('test_ebinfile_energies.fits') | 353 | + empty.check_create_ebounds('test_ebinfile_energies.fits[INVALID]') |
| 342 | self.test_try_failure('Exception not thrown') | 354 | self.test_try_failure('Exception not thrown') |
| 343 | except ValueError: | 355 | except ValueError: |
| 344 | self.test_try_success() | 356 | self.test_try_success() |
| 345 | 357 | ||
| 346 | - # Test create_ebounds() method for "ENERGIES" extension | ||
| 347 | - ebounds = empty.check_create_ebounds('test_ebinfile_energies.fits[ENERGIES]') | 358 | + # Test create_ebounds() method for "BINS" extension |
| 359 | + ebounds = empty.check_create_ebounds('test_ebinfile_bins.fits[BINS]') | ||
| 360 | + self.test_value(ebounds.size(), 1, 'Check number of energy boundaries') | ||
| 361 | + self.test_value(ebounds.emin().TeV(), 1.0, 'Check minimum energy') | ||
| 362 | + self.test_value(ebounds.emax().TeV(), 10.0, 'Check maximum energy') | ||
| 363 | + | ||
| 364 | + # Test create_ebounds() method for "ENGS" extension | ||
| 365 | + ebounds = empty.check_create_ebounds('test_ebinfile_engs.fits[ENGS]') | ||
| 348 | self.test_value(ebounds.size(), 1, 'Check number of energy boundaries') | 366 | self.test_value(ebounds.size(), 1, 'Check number of energy boundaries') |
| 349 | self.test_value(ebounds.emin().TeV(), 1.0, 'Check minimum energy') | 367 | self.test_value(ebounds.emin().TeV(), 1.0, 'Check minimum energy') |
| 350 | self.test_value(ebounds.emax().TeV(), 10.0, 'Check maximum energy') | 368 | self.test_value(ebounds.emax().TeV(), 10.0, 'Check maximum energy') |
test/test_ctmapcube.py
| @@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
| 2 | # ========================================================================== | 2 | # ========================================================================== |
| 3 | # This scripts performs unit tests for the ctmapcube tool. | 3 | # This scripts performs unit tests for the ctmapcube tool. |
| 4 | # | 4 | # |
| 5 | -# Copyright (C) 2016 Juergen Knoedlseder | 5 | +# Copyright (C) 2016-2017 Juergen Knoedlseder |
| 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 |
| @@ -242,7 +242,7 @@ class Test(test): | @@ -242,7 +242,7 @@ class Test(test): | ||
| 242 | return | 242 | return |
| 243 | 243 | ||
| 244 | # Check map cube | 244 | # Check map cube |
| 245 | - def _check_cube(self, cube, nmaps=10, npixels=10000): | 245 | + def _check_cube(self, cube, nmaps=11, npixels=10000): |
| 246 | """ | 246 | """ |
| 247 | Check map cube | 247 | Check map cube |
| 248 | 248 |