Commit 9a31a268c3f8ad382361945d1c1b595184dc5023
1 parent
51307080
Add BINS method to csspec (#3606)
Showing
7 changed files
with
125 additions
and
34 deletions
ChangeLog
NEWS
| 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 | [](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. | ... | ... |