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 31 smax, r, a, 10.0,,, "Upper energy limit of energy nodes for GAUSS(E) spatial model (TeV)"
32 32 gradient, b, a, yes,,, "Allow for spatial gradient?"
33 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 35 emin, r, a, 0.1,,, "Lower energy limit (TeV)"
36 36 emax, r, a, 100.0,,, "Upper energy limit (TeV)"
37 37 enumbins, i, a, 8,1,200, "Number of spectral energy nodes"
38 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 40 runwise, b, a, yes,,, "Generate runwise background model?"
40 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 652 'Npred': 0.0}
653 653  
654 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 657 # Setup maximum likelihood fit
658 658 like = ctools.ctlike(obs)
... ... @@ -667,6 +667,9 @@ class csspec(ctools.csobservation):
667 667 # Perform maximum likelihood fit
668 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 673 # Continue only if log-likelihood is non-zero
671 674 if like.obs().logL() != 0.0:
672 675  
... ... @@ -688,7 +691,8 @@ class csspec(ctools.csobservation):
688 691 if self['calc_ulim'].boolean():
689 692  
690 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 697 # Create upper limit object
694 698 ulimit = ctools.ctulimit(like.obs())
... ... @@ -801,7 +805,7 @@ class csspec(ctools.csobservation):
801 805 self._log_header1(gammalib.TERSE, 'Generate spectrum')
802 806  
803 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 810 # Perform maximum likelihood fit
807 811 like = ctools.ctlike(self.obs())
... ... @@ -816,6 +820,9 @@ class csspec(ctools.csobservation):
816 820 spectrum = model.spectral()
817 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 826 # Loop over all nodes
820 827 for i in range(spectrum.nodes()):
821 828  
... ... @@ -844,7 +851,9 @@ class csspec(ctools.csobservation):
844 851 if self['calc_ulim'].boolean():
845 852  
846 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 858 # Copy observation container
850 859 obs = like.obs().copy()
... ...
doc/source/users/reference_manual/csbkgmodel.rst
... ... @@ -75,11 +75,17 @@ General parameters
75 75 Spectral model component. ``PLAW`` specifies a simple power law model,
76 76 ``NODES`` specifies a piecewise broken power-law.
77 77  
78   -``ebinalg <FILE|LIN|LOG> [string]``
  78 +``ebinalg <FILE|LIN|LOG|POW> [string]``
79 79 Algorithm for defining energy nodes. For ``FILE``, the energy nodes are
80 80 defined in a FITS file that is specified by the ``ebinfile`` parameter,
81 81 for ``LIN`` and ``LOG`` there will be ``enumbins`` energy nodes spaced
82 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 90 ``emin [real]``
85 91 Lower energy limit (in TeV).
... ... @@ -88,11 +94,15 @@ General parameters
88 94 Upper energy limit (in TeV).
89 95  
90 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 100 ``ebinfile [file]``
94 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 106 ``runwise [boolean]``
97 107 Generate runwise background model? If ``yes`` is specified a background
98 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 696 * The following parameters are read:
697 697 *
698 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 700 * emin - Minimum energy (if ebinalg != FILE)
701 701 * emax - Maximum energy (if ebinalg != FILE)
702 702 * enumbins - Number of energy bins (if ebinalg != FILE)
  703 + * ebingamma - Power law index (if ebinalg == POW)
703 704 ***************************************************************************/
704 705 GEnergies ctool::create_energies(void)
705 706 {
... ... @@ -783,6 +784,38 @@ GEnergies ctool::create_energies(void)
783 784  
784 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 819 // ... otherwise use a linear or a logarithmically-spaced energy binning
787 820 else {
788 821  
... ...