Commit 31d34ecd3763ff910d5d3f6322291a99d13fced2

Authored by Jürgen Knödlseder
1 parent f9342fcb

Add "POW" energy binning to ctool::create_energies() method and csbkgmodel script

cscripts/csbkgmodel.par
@@ -31,11 +31,12 @@ smin, r, a, 0.1,,, "Lower energy limit of energy nodes for GAUSS(E) spatia @@ -31,11 +31,12 @@ smin, r, a, 0.1,,, "Lower energy limit of energy nodes for GAUSS(E) spatia
31 smax, r, a, 10.0,,, "Upper energy limit of energy nodes for GAUSS(E) spatial model (TeV)" 31 smax, r, a, 10.0,,, "Upper energy limit of energy nodes for GAUSS(E) spatial model (TeV)"
32 gradient, b, a, yes,,, "Allow for spatial gradient?" 32 gradient, b, a, yes,,, "Allow for spatial gradient?"
33 spectral, s, a, NODES,PLAW|NODES,, "Spectral model component" 33 spectral, s, a, NODES,PLAW|NODES,, "Spectral model component"
34 -ebinalg, s, a, LOG,FILE|LIN|LOG,, "Algorithm for defining spectral energy nodes" 34 +ebinalg, s, a, LOG,FILE|LIN|LOG|POW,, "Algorithm for defining spectral energy nodes"
35 emin, r, a, 0.1,,, "Lower energy limit (TeV)" 35 emin, r, a, 0.1,,, "Lower energy limit (TeV)"
36 emax, r, a, 100.0,,, "Upper energy limit (TeV)" 36 emax, r, a, 100.0,,, "Upper energy limit (TeV)"
37 enumbins, i, a, 8,1,200, "Number of spectral energy nodes" 37 enumbins, i, a, 8,1,200, "Number of spectral energy nodes"
38 ebinfile, f, a, NONE,,, "Name of the file containing the energy node definition" 38 ebinfile, f, a, NONE,,, "Name of the file containing the energy node definition"
  39 +ebingamma, r, a, 1.0,,, "Exponent for POW energy node definition"
39 runwise, b, a, yes,,, "Generate runwise background model?" 40 runwise, b, a, yes,,, "Generate runwise background model?"
40 rad, r, h, 2.0,,, "Radius for event selection (degrees)" 41 rad, r, h, 2.0,,, "Radius for event selection (degrees)"
41 42
cscripts/csspec.py
@@ -652,7 +652,7 @@ class csspec(ctools.csobservation): @@ -652,7 +652,7 @@ class csspec(ctools.csobservation):
652 'Npred': 0.0} 652 'Npred': 0.0}
653 653
654 # Write header for fitting 654 # Write header for fitting
655 - self._log_header3(gammalib.EXPLICIT, 'Performing fit') 655 + self._log_header3(gammalib.EXPLICIT, 'Performing fit in energy bin')
656 656
657 # Setup maximum likelihood fit 657 # Setup maximum likelihood fit
658 like = ctools.ctlike(obs) 658 like = ctools.ctlike(obs)
@@ -667,6 +667,9 @@ class csspec(ctools.csobservation): @@ -667,6 +667,9 @@ class csspec(ctools.csobservation):
667 # Perform maximum likelihood fit 667 # Perform maximum likelihood fit
668 like.run() 668 like.run()
669 669
  670 + # Write model results for explicit chatter level
  671 + self._log_string(gammalib.EXPLICIT, str(like.obs().models()))
  672 +
670 # Continue only if log-likelihood is non-zero 673 # Continue only if log-likelihood is non-zero
671 if like.obs().logL() != 0.0: 674 if like.obs().logL() != 0.0:
672 675
@@ -688,7 +691,8 @@ class csspec(ctools.csobservation): @@ -688,7 +691,8 @@ class csspec(ctools.csobservation):
688 if self['calc_ulim'].boolean(): 691 if self['calc_ulim'].boolean():
689 692
690 # Logging information 693 # Logging information
691 - self._log_header3(gammalib.EXPLICIT, 'Computing upper limit') 694 + self._log_header3(gammalib.EXPLICIT,
  695 + 'Computing upper limit for energy bin')
692 696
693 # Create upper limit object 697 # Create upper limit object
694 ulimit = ctools.ctulimit(like.obs()) 698 ulimit = ctools.ctulimit(like.obs())
@@ -801,7 +805,7 @@ class csspec(ctools.csobservation): @@ -801,7 +805,7 @@ class csspec(ctools.csobservation):
801 self._log_header1(gammalib.TERSE, 'Generate spectrum') 805 self._log_header1(gammalib.TERSE, 'Generate spectrum')
802 806
803 # Write header for fitting 807 # Write header for fitting
804 - self._log_header3(gammalib.EXPLICIT, 'Performing fit') 808 + self._log_header3(gammalib.EXPLICIT, 'Performing model fit')
805 809
806 # Perform maximum likelihood fit 810 # Perform maximum likelihood fit
807 like = ctools.ctlike(self.obs()) 811 like = ctools.ctlike(self.obs())
@@ -816,6 +820,9 @@ class csspec(ctools.csobservation): @@ -816,6 +820,9 @@ class csspec(ctools.csobservation):
816 spectrum = model.spectral() 820 spectrum = model.spectral()
817 logL0 = like.obs().logL() 821 logL0 = like.obs().logL()
818 822
  823 + # Write model results for explicit chatter level
  824 + self._log_string(gammalib.EXPLICIT, str(like.obs().models()))
  825 +
819 # Loop over all nodes 826 # Loop over all nodes
820 for i in range(spectrum.nodes()): 827 for i in range(spectrum.nodes()):
821 828
@@ -844,7 +851,9 @@ class csspec(ctools.csobservation): @@ -844,7 +851,9 @@ class csspec(ctools.csobservation):
844 if self['calc_ulim'].boolean(): 851 if self['calc_ulim'].boolean():
845 852
846 # Logging information 853 # Logging information
847 - self._log_header3(gammalib.EXPLICIT, 'Computing upper limit') 854 + self._log_header3(gammalib.EXPLICIT,
  855 + 'Computing upper limit for node energy %f TeV' %
  856 + result['energy'])
848 857
849 # Copy observation container 858 # Copy observation container
850 obs = like.obs().copy() 859 obs = like.obs().copy()
doc/source/users/reference_manual/csbkgmodel.rst
@@ -75,11 +75,17 @@ General parameters @@ -75,11 +75,17 @@ General parameters
75 Spectral model component. ``PLAW`` specifies a simple power law model, 75 Spectral model component. ``PLAW`` specifies a simple power law model,
76 ``NODES`` specifies a piecewise broken power-law. 76 ``NODES`` specifies a piecewise broken power-law.
77 77
78 -``ebinalg <FILE|LIN|LOG> [string]`` 78 +``ebinalg <FILE|LIN|LOG|POW> [string]``
79 Algorithm for defining energy nodes. For ``FILE``, the energy nodes are 79 Algorithm for defining energy nodes. For ``FILE``, the energy nodes are
80 defined in a FITS file that is specified by the ``ebinfile`` parameter, 80 defined in a FITS file that is specified by the ``ebinfile`` parameter,
81 for ``LIN`` and ``LOG`` there will be ``enumbins`` energy nodes spaced 81 for ``LIN`` and ``LOG`` there will be ``enumbins`` energy nodes spaced
82 linearly or logarithmically between ``emin`` and ``emax``, respectively. 82 linearly or logarithmically between ``emin`` and ``emax``, respectively.
  83 + For ``POW`` a spacing with ``enumbins`` nodes between ``emin`` and ``emax``
  84 + will be defined so that the integral over a power law with a spectral index
  85 + defined by the parameter ``ebingamma`` will be constant. A value of
  86 + ``ebingamma=1`` correspond to the ``LOG`` algorithm, a smaller value provides
  87 + a finer binning for larger energies while a larger value provides a finer
  88 + binning for smaller energies.
83 89
84 ``emin [real]`` 90 ``emin [real]``
85 Lower energy limit (in TeV). 91 Lower energy limit (in TeV).
@@ -88,11 +94,15 @@ General parameters @@ -88,11 +94,15 @@ General parameters
88 Upper energy limit (in TeV). 94 Upper energy limit (in TeV).
89 95
90 ``enumbins [integer]`` 96 ``enumbins [integer]``
91 - Number of energy nodes if ``LIN`` or ``LOG`` energy algorithms are used. 97 + Number of energy nodes if ``LIN``, ``LOG`` or ``POW`` energy algorithms are
  98 + used.
92 99
93 ``ebinfile [file]`` 100 ``ebinfile [file]``
94 Name of the file containing the energy node definition if ``ebinalg=FILE``. 101 Name of the file containing the energy node definition if ``ebinalg=FILE``.
95 102
  103 +``ebingamma [real]``
  104 + Power law index for energy node definition if ``ebinalg=POW``.
  105 +
96 ``runwise [boolean]`` 106 ``runwise [boolean]``
97 Generate runwise background model? If ``yes`` is specified a background 107 Generate runwise background model? If ``yes`` is specified a background
98 model component for each observation in the observation definition XML 108 model component for each observation in the observation definition XML
src/support/ctool.cpp
@@ -696,10 +696,11 @@ GEbounds ctool::create_ebounds(void) @@ -696,10 +696,11 @@ GEbounds ctool::create_ebounds(void)
696 * The following parameters are read: 696 * The following parameters are read:
697 * 697 *
698 * ebinalg - Energy binning algorithm 698 * ebinalg - Energy binning algorithm
699 - * ebinfile - Name of file with energy binning 699 + * ebinfile - Name of file with energy binning (if ebinalg == FILE)
700 * emin - Minimum energy (if ebinalg != FILE) 700 * emin - Minimum energy (if ebinalg != FILE)
701 * emax - Maximum energy (if ebinalg != FILE) 701 * emax - Maximum energy (if ebinalg != FILE)
702 * enumbins - Number of energy bins (if ebinalg != FILE) 702 * enumbins - Number of energy bins (if ebinalg != FILE)
  703 + * ebingamma - Power law index (if ebinalg == POW)
703 ***************************************************************************/ 704 ***************************************************************************/
704 GEnergies ctool::create_energies(void) 705 GEnergies ctool::create_energies(void)
705 { 706 {
@@ -783,6 +784,38 @@ GEnergies ctool::create_energies(void) @@ -783,6 +784,38 @@ GEnergies ctool::create_energies(void)
783 784
784 } // endif: ebinalg was "FILE" 785 } // endif: ebinalg was "FILE"
785 786
  787 + // ... otherwise, if energy binning algorithm is of type "POW" (case
  788 + // sensitive), then set the energy binning according to a power-law
  789 + else if (ebinalg == "POW") {
  790 +
  791 + // Get task parameters
  792 + double emin = (*this)["emin"].real();
  793 + double emax = (*this)["emax"].real();
  794 + int enumbins = (*this)["enumbins"].integer();
  795 + double ebingamma = (*this)["ebingamma"].real();
  796 +
  797 + // Precomputation
  798 + double a = 1.0 - ebingamma;
  799 + double c = (a == 0.0)
  800 + ? 1.0 / (std::log(emax) - std::log(emin))
  801 + : a / (std::pow(emax,a) - std::pow(emin,a));
  802 + double b = double(c*(enumbins-1.0));
  803 +
  804 + // Initialise first energy
  805 + double e = emin;
  806 + energies.append(GEnergy(e, "TeV"));
  807 +
  808 + // Loop over energy bins
  809 + for (int i = 0; i < enumbins-1; ++i) {
  810 + double log_e_next = (a == 0.0)
  811 + ? 1.0/b + std::log(e)
  812 + : std::log(a/b + std::pow(e,a)) / a;
  813 + double e_next = std::exp(log_e_next);
  814 + energies.append(GEnergy(e_next, "TeV"));
  815 + e = e_next;
  816 + }
  817 + }
  818 +
786 // ... otherwise use a linear or a logarithmically-spaced energy binning 819 // ... otherwise use a linear or a logarithmically-spaced energy binning
787 else { 820 else {
788 821