Commit 9a31a268c3f8ad382361945d1c1b595184dc5023

Authored by Jürgen Knödlseder
1 parent 51307080

Add BINS method to csspec (#3606)

ChangeLog
1   -2021-03-05
  1 +2021-04-13
2 2  
3 3 * Version 2.0.0 released
4 4 ========================
5 5  
  6 + Add BINS method to csspec (#3606)
6 7 Add hidden "fix_spat" parameter to cttsmap (#3562)
7 8 Add optimizer setter to ctlikelihood base class
8 9 Add Sphinx tutorials test script (#3510)
... ...
1 1 New Features and Important Changes in ctools 2.0.0
2 2  
3   -5 March 2021
  3 +13 April 2021
4 4  
5 5  
6 6 Introduction
... ... @@ -285,7 +285,9 @@ None
285 285  
286 286 csspec - Generates Spectral Energy Distribution
287 287 -----------------------------------------------
288   -None
  288 +Added BINS method that replaces the spectral model by a bin function that is
  289 +implemented by the GammaLib class GModelSpectralBins. Using a bin function
  290 +assures that spectral points are statistically independent (#3606).
289 291  
290 292  
291 293 cssrcdetect - Detects sources in sky map
... ...
README.md
1 1 ctools information
2 2 ==================
3   -* Version: 2.0.0.dev (5 March 2021)
  3 +* Version: 2.0.0.dev (13 April 2021)
4 4 * GammaLib dependency: 2.0.0.dev
5 5  
6 6 [![Build Status](https://cta-jenkins.irap.omp.eu/buildStatus/icon?job=ctools-integrate-os)](https://cta-jenkins.irap.omp.eu/job/ctools-integrate-os/)
... ...
cscripts/csspec.par
... ... @@ -31,7 +31,7 @@ outfile, f, a, spectrum.fits,,, "Output spectrum file"
31 31 #
32 32 # Script parameters
33 33 #==================
34   -method, s, a, AUTO,SLICE|NODES|AUTO,, "Spectrum generation method"
  34 +method, s, a, AUTO,SLICE|NODES|BINS|AUTO,, "Spectrum generation method"
35 35 ebinalg, s, a, LOG,FILE|LIN|LOG|POW,, "Algorithm for defining energy bins"
36 36 emin, r, a, 0.1,,, "Start value for first energy bin in TeV"
37 37 emax, r, a, 100.0,,, "Stop value for last energy bin in TeV"
... ... @@ -43,6 +43,7 @@ calc_ts, b, h, yes,,, "Compute TS value in each bin"
43 43 calc_ulim, b, h, yes,,, "Compute upper limit in each bin"
44 44 fix_srcs, b, h, yes,,, "Fix other skymodel parameters"
45 45 fix_bkg, b, h, no,,, "Fix background parameters"
  46 +bingamma, r, h, -2.0,,, "Spectral index for BINS method"
46 47 dll_sigstep, r, h, 0.0,0.0,100.0, "Step size in standard deviations for log-like profiles"
47 48 dll_sigmax, r, h, 5.0,1.0,100.0, "Maximum number of standard deviations for log-like profiles"
48 49 dll_freenodes, b, h, no,,, "Free nodes not being fit when computing log-like profiles"
... ...
cscripts/csspec.py
... ... @@ -144,9 +144,9 @@ class csspec(ctools.csobservation):
144 144 n_cta = n_unbinned + n_binned + n_onoff
145 145 n_other = self.obs().size() - n_cta
146 146  
147   - # If spectrum method is not "NODES" then set spectrum method and
148   - # script mode according to type of observations
149   - if self._method != 'NODES':
  147 + # If spectrum method is not "NODES" or 'BINS" then set spectrum method
  148 + # and script mode according to type of observations
  149 + if self._method != 'NODES' and self._method != 'BINS':
150 150 if n_other > 0:
151 151 self._method = 'NODES'
152 152 else:
... ... @@ -178,6 +178,7 @@ class csspec(ctools.csobservation):
178 178 self['calc_ts'].boolean()
179 179 self['fix_bkg'].boolean()
180 180 self['fix_srcs'].boolean()
  181 + self['bingamma'].real()
181 182  
182 183 # Setup dlog-likelihood parameters
183 184 self['dll_sigstep'].real()
... ... @@ -213,10 +214,10 @@ class csspec(ctools.csobservation):
213 214 elif n_other > 0:
214 215 if self._method == 'SLICE':
215 216 msg = 'Selected "SLICE" method but none of the observations ' \
216   - 'is a CTA observation. Please select "AUTO" or "NODES" ' \
217   - 'if no CTA observation is provided.'
  217 + 'is a CTA observation. Please select "AUTO", "NODES" ' \
  218 + 'or "BINS" if no CTA observation is provided.'
218 219 raise RuntimeError(msg)
219   - else:
  220 + elif self._method == 'AUTO':
220 221 self._method = 'NODES'
221 222  
222 223 # Log selected spectrum method
... ... @@ -456,6 +457,64 @@ class csspec(ctools.csobservation):
456 457 # Return
457 458 return
458 459  
  460 + def _set_replace_src_spectrum_by_bins(self):
  461 + """
  462 + Replace source spectrum by bin function
  463 + """
  464 + # Initialise model container
  465 + models = gammalib.GModels()
  466 +
  467 + # Loop over model containers
  468 + for model in self.obs().models():
  469 +
  470 + # If we deal with source model then replace the spectral model
  471 + # by a bin function
  472 + if model.name() == self['srcname'].string():
  473 +
  474 + # Get spectral bins index
  475 + bingamma = self['bingamma'].real()
  476 +
  477 + # Setup spectral bin function
  478 + spectrum = gammalib.GModelSpectralBins(model.spectral(),
  479 + self._ebounds,
  480 + bingamma)
  481 + spectrum.autoscale()
  482 +
  483 + # Make sure that all bins are positive. Autoscale all
  484 + # parameters so that their nominal value is unity.
  485 + for i in range(spectrum.bins()):
  486 + name = 'Intensity%d' % i
  487 + par = spectrum[name]
  488 + par.autoscale()
  489 + value = par.value()
  490 + minimum = 1.0e-20 * value
  491 + if minimum <= 0.0:
  492 + minimum = 1.0e-20
  493 + if minimum < value:
  494 + value = minimum
  495 + par.value(value)
  496 + par.min(minimum)
  497 +
  498 + # Set spectral component of source model
  499 + model.spectral(spectrum)
  500 +
  501 + # Make sure that TS computation is disabled (makes computation
  502 + # faster)
  503 + model.tscalc(False)
  504 +
  505 + # Append model
  506 + models.append(model)
  507 +
  508 + # ... otherwise just append model
  509 + else:
  510 + models.append(model)
  511 +
  512 + # Put new model in observation containers
  513 + self.obs().models(models)
  514 +
  515 + # Return
  516 + return
  517 +
459 518 def _select_onoff_obs(self, obs, emin, emax):
460 519 """
461 520 Select an energy interval from one CTA On/Off observation
... ... @@ -854,8 +913,8 @@ class csspec(ctools.csobservation):
854 913 # Write model results for explicit chatter level
855 914 self._log_string(gammalib.EXPLICIT, str(like.obs().models()))
856 915  
857   - # Loop over all nodes
858   - for i in range(spectrum.nodes()):
  916 + # Loop over all nodes or bins
  917 + for i in range(self._ebounds.size()):
859 918  
860 919 # Get energy boundaries
861 920 emin = self._ebounds.emin(i)
... ... @@ -878,23 +937,26 @@ class csspec(ctools.csobservation):
878 937  
879 938 # Convert differential flux and flux error to nuFnu
880 939 norm = elogmean.MeV() * elogmean.MeV() * gammalib.MeV2erg
881   - result['flux'] = spectrum[i*2+1].value()
882   - result['e2dnde'] = spectrum[i*2+1].value() * norm
883   - result['flux_err'] = spectrum[i*2+1].error()
  940 + result['flux'] = spectrum.intensity(i)
  941 + result['e2dnde'] = spectrum.intensity(i) * norm
  942 + result['flux_err'] = spectrum.error(i)
884 943  
885 944 # Compute upper flux limit
886 945 ulimit_value = -1.0
887   - parname = 'Intensity%d' % i
  946 + parname = 'Intensity%d' % i
888 947  
889 948 # Compute delta log-likelihood
890 949 if self['dll_sigstep'].real() > 0.0:
891 950  
892 951 # Extract the normalization scan values
893   - (norm_scan, dlogL, loglike) = self._profile_logL(like.copy(), parname, elogmean)
  952 + (norm_scan, dlogL, loglike) = self._profile_logL(like.copy(),
  953 + parname,
  954 + elogmean)
894 955 result['norm_scan'] = norm_scan
895 956 result['dloglike'] = dlogL
896 957 result['logL'] = loglike
897 958  
  959 + # Compute upper limit
898 960 if self['calc_ulim'].boolean():
899 961  
900 962 # Logging information
... ... @@ -1006,7 +1068,8 @@ class csspec(ctools.csobservation):
1006 1068 source.tscalc(False)
1007 1069  
1008 1070 # Fix all parameters in the spectral model
1009   - if (self._method != 'NODES') or (not self['dll_freenodes'].boolean()):
  1071 + if (self._method != 'NODES' and self._method != 'BINS') or \
  1072 + (not self['dll_freenodes'].boolean()):
1010 1073 for par in spectral:
1011 1074 par.fix()
1012 1075  
... ... @@ -1197,6 +1260,15 @@ class csspec(ctools.csobservation):
1197 1260 # Fit model
1198 1261 results = self._fit_model()
1199 1262  
  1263 + # Case C: "BINS" method
  1264 + elif self._method == 'BINS':
  1265 +
  1266 + # Replace source spectrum by bins function
  1267 + self._set_replace_src_spectrum_by_bins()
  1268 +
  1269 + # Fit model
  1270 + results = self._fit_model()
  1271 +
1200 1272 # Create FITS file
1201 1273 self._create_fits(results)
1202 1274  
... ...
doc/source/admin/release_history/2.0.rst
1 1 .. _2.0:
2 2  
3   -ctools 2.0 release (5 March 2021)
4   -=================================
  3 +ctools 2.0 release (13 April 2021)
  4 +==================================
5 5  
6 6 Overview
7 7 --------
... ... @@ -24,6 +24,8 @@ Bug fixes
24 24 Improvements
25 25 ------------
26 26  
  27 +* [`3606 <https://cta-redmine.irap.omp.eu/issues/3606>`_] -
  28 + Add ``BINS`` method to :ref:`csspec`
27 29 * [`3562 <https://cta-redmine.irap.omp.eu/issues/3562>`_] -
28 30 Add hidden ``fix_spat`` parameter to :ref:`cttsmap`
29 31 * Add optimizer setter to ``ctlikelihood`` base class.
... ...
doc/source/users/reference_manual/csspec.rst
... ... @@ -19,15 +19,20 @@ significance of the source detection. Optionally, it also computes an upper
19 19 flux limit that is particularly useful in case that the source is not
20 20 significantly detected within a spectral bin (hidden parameter ``calc_ulim``).
21 21  
22   -There are two fundamental methods to run the script depending on the value of
  22 +There are three fundamental methods to run the script depending on the value of
23 23 the ``method`` parameter. If ``method=SLICE`` the energy interval defined by the
24 24 ``emin`` and ``emax`` parameters is divided into a number of energy bins and an
25   -independent maximum likelihood fit is performed in each of the energy bins,
26   -while if ``method=NODES`` the spectral model will be replaced by a node function
27   -that will be fit to all data. The latter is particularly useful if non-CTA data
28   -should be fitted such as data from Fermi/LAT or COMPTEL. By default, ``method`` is
29   -set to ``AUTO`` which will automatically select the method based on the input data.
30   -For CTA-only observations ``SLICE`` will be used, otherwise ``NODES`` will be used.
  25 +independent maximum likelihood fit is performed in each of the energy bins. If
  26 +``method=NODES`` the spectral model will be replaced by a node function that will
  27 +be fit to all data. Alternatively, if ``method=BINS`` the spectral model will be
  28 +replaced by a bin function that will be fit to all data. While with the ``NODES``
  29 +method the spectral points are in general not statistically independent, the
  30 +``BINS`` method assures that the spectral points are statistically independent.
  31 +The ``NODES`` and ``BINS`` methods are particularly useful if data from instruments
  32 +other than CTA should be analyses, such as data from Fermi/LAT, COMPTEL or
  33 +INTEGRAL/SPI. By default, ``method`` is set to ``AUTO`` which will automatically
  34 +select the method based on the input data. For CTA-only observations ``SLICE`` will
  35 +be used, otherwise ``NODES`` will be used.
31 36  
32 37 The spectral binning is either defined by a FITS file containing the energy
33 38 boundaries of each bin (option ``ebinalg=FILE``) or as ``enumbins`` bins spread
... ... @@ -95,13 +100,17 @@ General parameters
95 100 ``outfile [file]``
96 101 Output spectrum FITS file.
97 102  
98   -``method <SLICE|NODES|AUTO> [string]``
  103 +``method <SLICE|NODES|BINS|AUTO> [string]``
99 104 Spectrum generation method.
100   - ``SLICE`` will slice energy interval into ``enumbins`` independent bins,
101   - ``NODES`` will replace spectral model by node function with ``enumbins``
102   - nodes, and ``AUTO`` will automatically select the method based on the input
103   - data. For CTA-only observations ``SLICE`` will be used, otherwise ``NODES``
104   - will be used.
  105 + ``SLICE`` will slice the energy interval into ``enumbins`` independent
  106 + bins,
  107 + ``NODES`` will replace the spectral model by a node function with
  108 + ``enumbins`` nodes,
  109 + ``BINS`` will replace the spectral model by a bin function with
  110 + ``enumbins`` nodes,
  111 + and ``AUTO`` will automatically select the method based on the input
  112 + data. If ``AUTO`` is selected and there are only CTA observations
  113 + then ``SLICE`` will be used, otherwise ``NODES`` will be used.
105 114  
106 115 ``ebinalg <FILE|LIN|LOG|POW> [string]``
107 116 Algorithm for defining energy bins. For ``FILE``, the energy bins are defined
... ... @@ -151,6 +160,10 @@ General parameters
151 160 ``(fix_bkg = no) [boolean]``
152 161 Fix background model parameters?
153 162  
  163 +``(bingamma = -2.0) [real]``
  164 + Spectral index for ``BINS`` method. Within each spectral bin a power law
  165 + will be assumed with the specified spectral index.
  166 +
154 167 ``(dll_sigstep = 0) [real]``
155 168 Step size in standard deviations for log-like profiles. Note this value
156 169 determines the number of steps to use.
... ...