Commit b554fc2efa1c85d671fd8fc1844fc497b86b6732

Authored by Jürgen Knödlseder
1 parent 9617e53e

Allow energy boundaries and energy value FITS file as input to ebinfile parameters (#1978)

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)
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&amp; obs, @@ -503,15 +503,19 @@ void ctool::setup_models(GObservations&amp; 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