Commit 6205af2a12232cf79fc6ef3b314ab4b4c0a0b384

Authored by Jürgen Knödlseder
1 parent e1129812

Add Sphinx tutorials test script (#3510)

The current script covers all 1DC tutorials.
.gitignore
@@ -99,6 +99,7 @@ test/butterfly.txt @@ -99,6 +99,7 @@ test/butterfly.txt
99 test/.coverage 99 test/.coverage
100 test/test_python_ctools.sh 100 test/test_python_ctools.sh
101 test/test_python_cscripts.sh 101 test/test_python_cscripts.sh
  102 +test/tutorials
102 examples/*.fits 103 examples/*.fits
103 examples/*.xml 104 examples/*.xml
104 examples/*.dat 105 examples/*.dat
ChangeLog
1 -2020-12-03 1 +2020-02-03
2 2
3 * Version 2.0.0 released 3 * Version 2.0.0 released
4 ======================== 4 ========================
5 5
  6 + Add Sphinx tutorials test script (#3510)
6 Add "refit_if_failed" parameter to ctlike 7 Add "refit_if_failed" parameter to ctlike
7 Add models() method to ctobssim (#3441) 8 Add models() method to ctobssim (#3441)
8 Add ctlike results to XML file (#3431) 9 Add ctlike results to XML file (#3431)
Makefile.am
1 ############################################################################# 1 #############################################################################
2 # Makefile for ctools package # 2 # Makefile for ctools package #
3 # ------------------------------------------------------------------------- # 3 # ------------------------------------------------------------------------- #
4 -# Copyright (C) 2016-2017 Juergen Knoedlseder # 4 +# Copyright (C) 2016-2021 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 #
@@ -211,13 +211,23 @@ valgrind: @@ -211,13 +211,23 @@ valgrind:
211 # Add science verification rule 211 # Add science verification rule
212 science-verification: 212 science-verification:
213 @if type test/science_verification.py >/dev/null 2>&1; then \ 213 @if type test/science_verification.py >/dev/null 2>&1; then \
214 - cd test; \  
215 - ./science_verification.py; \  
216 - cd ..; \ 214 + cd test; \
  215 + ./science_verification.py; \
  216 + cd ..; \
217 else \ 217 else \
218 echo "science_verification.py not found in test."; \ 218 echo "science_verification.py not found in test."; \
219 fi 219 fi
220 220
  221 +# Add tutorials verification rule
  222 +check-tutorials:
  223 + @if type test/tutorials.py >/dev/null 2>&1; then \
  224 + cd test; \
  225 + ./tutorials.py; \
  226 + cd ..; \
  227 + else \
  228 + echo "tutorials.py not found in test."; \
  229 + fi
  230 +
221 # Add Sphinx rule 231 # Add Sphinx rule
222 sphinx: 232 sphinx:
223 @if type sphinx-build >/dev/null 2>&1; then \ 233 @if type sphinx-build >/dev/null 2>&1; then \
1 New Features and Important Changes in ctools 2.0.0 1 New Features and Important Changes in ctools 2.0.0
2 2
3 -3 December 2020 3 +3 February 2021
4 4
5 5
6 Introduction 6 Introduction
@@ -16,7 +16,8 @@ None @@ -16,7 +16,8 @@ None
16 16
17 Documentation 17 Documentation
18 ------------- 18 -------------
19 -None 19 +Add test/tutorials.py script and check-tutorial target to test the code in the
  20 +Sphinx tutorials (#3510).
20 21
21 22
22 Python interface 23 Python interface
README.md
1 ctools information 1 ctools information
2 ================== 2 ==================
3 -* Version: 2.0.0.dev (3 December 2020) 3 +* Version: 2.0.0.dev (3 February 2021)
4 * GammaLib dependency: 2.0.0.dev 4 * GammaLib dependency: 2.0.0.dev
5 5
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/) 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.py
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 # ========================================================================== 2 # ==========================================================================
3 # Generates a spectrum. 3 # Generates a spectrum.
4 # 4 #
5 -# Copyright (C) 2014-2020 Michael Mayer 5 +# Copyright (C) 2014-2021 Michael Mayer
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
@@ -1071,7 +1071,7 @@ class csspec(ctools.csobservation): @@ -1071,7 +1071,7 @@ class csspec(ctools.csobservation):
1071 energy_high = gammalib.GFitsTableDoubleCol('e_max', nrows) 1071 energy_high = gammalib.GFitsTableDoubleCol('e_max', nrows)
1072 norm = gammalib.GFitsTableDoubleCol('norm', nrows) 1072 norm = gammalib.GFitsTableDoubleCol('norm', nrows)
1073 norm_err = gammalib.GFitsTableDoubleCol('norm_err', nrows) 1073 norm_err = gammalib.GFitsTableDoubleCol('norm_err', nrows)
1074 - ulim_values = gammalib.GFitsTableDoubleCol('norm_ul', nrows) 1074 + norm_ul = gammalib.GFitsTableDoubleCol('norm_ul', nrows)
1075 e2dnde = gammalib.GFitsTableDoubleCol('ref_e2dnde', nrows) 1075 e2dnde = gammalib.GFitsTableDoubleCol('ref_e2dnde', nrows)
1076 dnde = gammalib.GFitsTableDoubleCol('ref_dnde', nrows) 1076 dnde = gammalib.GFitsTableDoubleCol('ref_dnde', nrows)
1077 Npred_values = gammalib.GFitsTableDoubleCol('ref_npred', nrows) 1077 Npred_values = gammalib.GFitsTableDoubleCol('ref_npred', nrows)
@@ -1084,7 +1084,7 @@ class csspec(ctools.csobservation): @@ -1084,7 +1084,7 @@ class csspec(ctools.csobservation):
1084 energy_high.unit('TeV') 1084 energy_high.unit('TeV')
1085 norm.unit('') 1085 norm.unit('')
1086 norm_err.unit('') 1086 norm_err.unit('')
1087 - ulim_values.unit('') 1087 + norm_ul.unit('')
1088 e2dnde.unit('erg/cm2/s') 1088 e2dnde.unit('erg/cm2/s')
1089 dnde.unit('counts/MeV/cm2/s') 1089 dnde.unit('counts/MeV/cm2/s')
1090 Npred_values.unit('counts') 1090 Npred_values.unit('counts')
@@ -1098,8 +1098,12 @@ class csspec(ctools.csobservation): @@ -1098,8 +1098,12 @@ class csspec(ctools.csobservation):
1098 energy_low[i] = result['energy_low'] 1098 energy_low[i] = result['energy_low']
1099 energy_high[i] = result['energy_high'] 1099 energy_high[i] = result['energy_high']
1100 norm[i] = 1.0 1100 norm[i] = 1.0
1101 - norm_err[i] = result['flux_err'] / result['flux']  
1102 - ulim_values[i] = result['ulimit'] / result['flux'] 1101 + if result['flux'] != 0.0:
  1102 + norm_err[i] = result['flux_err'] / result['flux']
  1103 + norm_ul[i] = result['ulimit'] / result['flux']
  1104 + else:
  1105 + norm_err[i] = 0.0
  1106 + norm_ul[i] = 0.0
1103 e2dnde[i] = result['e2dnde'] 1107 e2dnde[i] = result['e2dnde']
1104 dnde[i] = result['flux'] 1108 dnde[i] = result['flux']
1105 Npred_values[i] = result['Npred'] 1109 Npred_values[i] = result['Npred']
@@ -1109,7 +1113,10 @@ class csspec(ctools.csobservation): @@ -1109,7 +1113,10 @@ class csspec(ctools.csobservation):
1109 # Add likelihood scan values 1113 # Add likelihood scan values
1110 for fbin in range(ncols): 1114 for fbin in range(ncols):
1111 dloglike_scan[i,fbin] = result['dloglike'][fbin] 1115 dloglike_scan[i,fbin] = result['dloglike'][fbin]
1112 - norm_scan[i,fbin] = result['norm_scan'][fbin] / result['flux'] 1116 + if result['flux'] != 0.0:
  1117 + norm_scan[i,fbin] = result['norm_scan'][fbin] / result['flux']
  1118 + else:
  1119 + norm_scan[i,fbin] = 0.0
1113 1120
1114 # Initialise FITS Table with extension "SPECTRUM" 1121 # Initialise FITS Table with extension "SPECTRUM"
1115 table = gammalib.GFitsBinTable(nrows) 1122 table = gammalib.GFitsBinTable(nrows)
@@ -1125,7 +1132,7 @@ class csspec(ctools.csobservation): @@ -1125,7 +1132,7 @@ class csspec(ctools.csobservation):
1125 table.append(energy_high) 1132 table.append(energy_high)
1126 table.append(norm) 1133 table.append(norm)
1127 table.append(norm_err) 1134 table.append(norm_err)
1128 - table.append(ulim_values) 1135 + table.append(norm_ul)
1129 table.append(e2dnde) 1136 table.append(e2dnde)
1130 table.append(dnde) 1137 table.append(dnde)
1131 table.append(TSvalues) 1138 table.append(TSvalues)
doc/source/users/tutorials/1dc/CasA_model.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2 +<source_library title="source library">
  3 + <source name="Cassiopeia A" type="PointSource">
  4 + <spectrum type="PowerLaw">
  5 + <parameter name="Prefactor" value="1.45" scale="1e-18" min="0" free="1"/>
  6 + <parameter name="Index" value="2.75" scale="-1" min="-10" max="10" free="1"/>
  7 + <parameter name="PivotEnergy" value="1" scale="1e6" free="0"/>
  8 + </spectrum>
  9 + <spatialModel type="PointSource">
  10 + <parameter name="RA" value="350.8500" scale="1" free="0"/>
  11 + <parameter name="DEC" value="58.8150" scale="1" free="0"/>
  12 + </spatialModel>
  13 + </source>
  14 + <source name="Background model" type="CTAIrfBackground" instrument="CTA">
  15 + <spectrum type="PowerLaw">
  16 + <parameter name="Prefactor" value="1" scale="1" min="0.001" max="1000" free="1"/>
  17 + <parameter name="Index" value="0" scale="1" min="-5" max="5" free="1"/>
  18 + <parameter name="Scale" value="1" scale="1e6" min="0.01" max="1000" free="0"/>
  19 + </spectrum>
  20 + </source>
  21 +</source_library>
doc/source/users/tutorials/1dc/first_fitting.rst
@@ -39,7 +39,7 @@ You run the :ref:`ctlike` tool as follows: @@ -39,7 +39,7 @@ You run the :ref:`ctlike` tool as follows:
39 Input model definition XML file [$CTOOLS/share/models/crab.xml] bkgcube.xml 39 Input model definition XML file [$CTOOLS/share/models/crab.xml] bkgcube.xml
40 Output model definition XML file [crab_results.xml] results_stacked.xml 40 Output model definition XML file [crab_results.xml] results_stacked.xml
41 41
42 -The tool will take a few minutes (on Mac OS X) to perform the model fitting, 42 +The tool will take a few minutes (on Mac OS) to perform the model fitting,
43 and will write the results into an updated 43 and will write the results into an updated
44 :ref:`model definition file <glossary_moddef>` 44 :ref:`model definition file <glossary_moddef>`
45 containing the fitted model parameters and their statistical uncertainties. 45 containing the fitted model parameters and their statistical uncertainties.
@@ -124,7 +124,7 @@ You create the butterfly diagram for ``Src001`` using @@ -124,7 +124,7 @@ You create the butterfly diagram for ``Src001`` using
124 Stop value for last energy bin in TeV [100.0] 124 Stop value for last energy bin in TeV [100.0]
125 Output ASCII file [butterfly.txt] butterfly_src001.txt 125 Output ASCII file [butterfly.txt] butterfly_src001.txt
126 126
127 -and for `Src003`` using 127 +and for ``Src003`` using
128 128
129 .. code-block:: bash 129 .. code-block:: bash
130 130
@@ -192,28 +192,14 @@ a maximum likelihood model fit. @@ -192,28 +192,14 @@ a maximum likelihood model fit.
192 192
193 Obviously, ``Src001`` has a spectral cut-off (red flux points) and hence is not 193 Obviously, ``Src001`` has a spectral cut-off (red flux points) and hence is not
194 adequately described by a power law model. You should therefore replace the 194 adequately described by a power law model. You should therefore replace the
195 -power law in the  
196 -:ref:`model definition file <glossary_moddef>`  
197 -by an exponentially cutoff power law, as shown below:  
198 -  
199 -.. code-block:: xml  
200 -  
201 - <?xml version="1.0" encoding="UTF-8" standalone="no"?>  
202 - <source_library title="source library">  
203 - <source name="Src001" type="PointSource">  
204 - <spectrum type="ExponentialCutoffPowerLaw">  
205 - <parameter name="Prefactor" scale="1e-18" value="5.7" min="1e-07" max="1000.0" free="1"/>  
206 - <parameter name="Index" scale="-1" value="2.48" min="0.0" max="+5.0" free="1"/>  
207 - <parameter name="CutoffEnergy" scale="1e7" value="1.0" min="0.01" max="1000.0" free="1"/>  
208 - <parameter name="PivotEnergy" scale="1e6" value="0.3" min="0.01" max="1000.0" free="0"/>  
209 - </spectrum>  
210 - <spatialModel type="PointSource">  
211 - <parameter name="RA" value="266.424004498437" scale="1" free="1" />  
212 - <parameter name="DEC" value="-29.0049010253548" scale="1" free="1" />  
213 - </spatialModel>  
214 - </source>  
215 - ...  
216 - </source_library> 195 +power law spectrum in the :ref:`model definition file <glossary_moddef>`
  196 +by an exponentially cutoff power law spectrum, as shown below (only the first
  197 +lines of the :ref:`model definition file <glossary_moddef>` are shown for
  198 +illustration):
  199 +
  200 +.. literalinclude:: results_stacked_eplaw.xml
  201 + :language: xml
  202 + :lines: 1-16
217 203
218 Fitting this model to the data improves the fit and the resulting butterfly 204 Fitting this model to the data improves the fit and the resulting butterfly
219 diagram follows now reasonably well the spectral points: 205 diagram follows now reasonably well the spectral points:
doc/source/users/tutorials/1dc/first_onoff.rst
@@ -208,6 +208,7 @@ follows: @@ -208,6 +208,7 @@ follows:
208 Output observation definition XML file [onoff_obs.xml] 208 Output observation definition XML file [onoff_obs.xml]
209 Output model definition XML file [onoff_model.xml] 209 Output model definition XML file [onoff_model.xml]
210 Method for background estimation (REFLECTED|CUSTOM) [REFLECTED] 210 Method for background estimation (REFLECTED|CUSTOM) [REFLECTED]
  211 + Shape of the source region (CIRCLE|RECT) [CIRCLE]
211 Coordinate system (CEL - celestial, GAL - galactic) (CEL|GAL) [CEL] 212 Coordinate system (CEL - celestial, GAL - galactic) (CEL|GAL) [CEL]
212 Right Ascension of source region centre (deg) (0-360) [83.63] 350.85 213 Right Ascension of source region centre (deg) (0-360) [83.63] 350.85
213 Declination of source region centre (deg) (-90-90) [22.01] 58.815 214 Declination of source region centre (deg) (-90-90) [22.01] 58.815
@@ -355,29 +356,8 @@ The fit result can be inspected by peeking the log file: @@ -355,29 +356,8 @@ The fit result can be inspected by peeking the log file:
355 provided as input model to :ref:`csphagen`. Here an example for an 356 provided as input model to :ref:`csphagen`. Here an example for an
356 input model: 357 input model:
357 358
358 - .. code-block:: xml  
359 -  
360 - <?xml version="1.0" encoding="UTF-8" standalone="no"?>  
361 - <source_library title="source library">  
362 - <source name="Cassiopeia A" type="PointSource">  
363 - <spectrum type="PowerLaw">  
364 - <parameter name="Prefactor" value="1.45" scale="1e-18" min="0" free="1"/>  
365 - <parameter name="Index" value="2.75" scale="-1" min="-10" max="10" free="1"/>  
366 - <parameter name="PivotEnergy" value="1" scale="1e6" free="0"/>  
367 - </spectrum>  
368 - <spatialModel type="PointSource">  
369 - <parameter name="RA" value="350.8500" scale="1" free="0"/>  
370 - <parameter name="DEC" value="58.8150" scale="1" free="0"/>  
371 - </spatialModel>  
372 - </source>  
373 - <source name="Background model" type="CTAIrfBackground" instrument="CTA">  
374 - <spectrum type="PowerLaw">  
375 - <parameter name="Prefactor" value="1" scale="1" min="0.001" max="1000" free="1"/>  
376 - <parameter name="Index" value="0" scale="1" min="-5" max="5" free="1"/>  
377 - <parameter name="Scale" value="1" scale="1e6" min="0.01" max="1000" free="0"/>  
378 - </spectrum>  
379 - </source>  
380 - </source_library> 359 + .. literalinclude:: CasA_model.xml
  360 + :language: xml
381 361
382 Now rerun :ref:`csphagen` as follows: 362 Now rerun :ref:`csphagen` as follows:
383 363
@@ -395,6 +375,7 @@ The fit result can be inspected by peeking the log file: @@ -395,6 +375,7 @@ The fit result can be inspected by peeking the log file:
395 Output observation definition XML file [onoff_obs.xml] onoff_obs_cstat.xml 375 Output observation definition XML file [onoff_obs.xml] onoff_obs_cstat.xml
396 Output model definition XML file [onoff_model.xml] onoff_model_cstat.xml 376 Output model definition XML file [onoff_model.xml] onoff_model_cstat.xml
397 Method for background estimation (REFLECTED|CUSTOM) [REFLECTED] 377 Method for background estimation (REFLECTED|CUSTOM) [REFLECTED]
  378 + Shape of the source region (CIRCLE|RECT) [CIRCLE]
398 Coordinate system (CEL - celestial, GAL - galactic) (CEL|GAL) [CEL] 379 Coordinate system (CEL - celestial, GAL - galactic) (CEL|GAL) [CEL]
399 Right Ascension of source region centre (deg) (0-360) [350.85] 380 Right Ascension of source region centre (deg) (0-360) [350.85]
400 Declination of source region centre (deg) (-90-90) [58.815] 381 Declination of source region centre (deg) (-90-90) [58.815]
@@ -452,7 +433,7 @@ Like for a binned or unbinned analysis, you can create a butterfly diagram by ty @@ -452,7 +433,7 @@ Like for a binned or unbinned analysis, you can create a butterfly diagram by ty
452 433
453 $ ctbutterfly 434 $ ctbutterfly
454 Input event list, counts cube or observation definition XML file [events.fits] onoff_obs.xml 435 Input event list, counts cube or observation definition XML file [events.fits] onoff_obs.xml
455 - Source of interest [Crab] Cassiopeia A 436 + Source of interest [Crab] Dummy
456 Input model definition XML file [$CTOOLS/share/models/crab.xml] CasA_results.xml 437 Input model definition XML file [$CTOOLS/share/models/crab.xml] CasA_results.xml
457 Lower energy limit (TeV) [0.1] 438 Lower energy limit (TeV) [0.1]
458 Upper energy limit (TeV) [100.0] 50.0 439 Upper energy limit (TeV) [100.0] 50.0
@@ -465,7 +446,7 @@ and the SED by typing @@ -465,7 +446,7 @@ and the SED by typing
465 $ csspec 446 $ csspec
466 Input event list, counts cube, or observation definition XML file [events.fits] onoff_obs.xml 447 Input event list, counts cube, or observation definition XML file [events.fits] onoff_obs.xml
467 Input model definition XML file [$CTOOLS/share/models/crab.xml] CasA_results.xml 448 Input model definition XML file [$CTOOLS/share/models/crab.xml] CasA_results.xml
468 - Source name [Crab] Cassiopeia A 449 + Source name [Crab] Dummy
469 Spectrum generation method (SLICE|NODES|AUTO) [AUTO] 450 Spectrum generation method (SLICE|NODES|AUTO) [AUTO]
470 Binning algorithm (FILE|LIN|LOG|POW) [LOG] 451 Binning algorithm (FILE|LIN|LOG|POW) [LOG]
471 Lower energy limit (TeV) [0.1] 452 Lower energy limit (TeV) [0.1]
doc/source/users/tutorials/1dc/results_stacked_eplaw.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2 +<source_library title="source library">
  3 + <source name="Src001" type="PointSource">
  4 + <spectrum type="ExponentialCutoffPowerLaw">
  5 + <parameter name="Prefactor" scale="1e-18" value="5.7" min="1e-07" max="1000.0" free="1"/>
  6 + <parameter name="Index" scale="-1" value="2.48" min="0.0" max="+5.0" free="1"/>
  7 + <parameter name="CutoffEnergy" scale="1e7" value="1.0" min="0.01" max="1000.0" free="1"/>
  8 + <parameter name="PivotEnergy" scale="1e6" value="0.3" min="0.01" max="1000.0" free="0"/>
  9 + </spectrum>
  10 + <spatialModel type="PointSource">
  11 + <parameter name="RA" value="266.424004498437" scale="1" free="1"/>
  12 + <parameter name="DEC" value="-29.0049010253548" scale="1" free="1"/>
  13 + </spatialModel>
  14 + </source>
  15 + <source name="Src002" type="PointSource">
  16 + <spectrum type="PowerLaw">
  17 + <parameter name="Prefactor" value="1" scale="5.7e-18" min="0" free="1" />
  18 + <parameter name="Index" value="1" scale="-2.48" min="-4.03225806451613" max="4.03225806451613" free="1" />
  19 + <parameter name="PivotEnergy" value="1" scale="300000" free="0" />
  20 + </spectrum>
  21 + <spatialModel type="PointSource">
  22 + <parameter name="RA" value="264.802012181975" error="0" scale="1" free="1" />
  23 + <parameter name="DEC" value="-31.0050720432975" error="0" scale="1" free="1" />
  24 + </spatialModel>
  25 + </source>
  26 + <source name="Src003" type="PointSource">
  27 + <spectrum type="PowerLaw">
  28 + <parameter name="Prefactor" value="1" error="0" scale="5.7e-18" min="0" free="1" />
  29 + <parameter name="Index" value="1" error="-0" scale="-2.48" min="-4.03225806451613" max="4.03225806451613" free="1" />
  30 + <parameter name="PivotEnergy" value="1" scale="300000" free="0" />
  31 + </spectrum>
  32 + <spatialModel type="PointSource">
  33 + <parameter name="RA" value="266.831945177213" error="0" scale="1" free="1" />
  34 + <parameter name="DEC" value="-28.1460284439951" error="0" scale="1" free="1" />
  35 + </spatialModel>
  36 + </source>
  37 + <source name="Src004" type="PointSource">
  38 + <spectrum type="PowerLaw">
  39 + <parameter name="Prefactor" value="1" error="0" scale="5.7e-18" min="0" free="1" />
  40 + <parameter name="Index" value="1" error="-0" scale="-2.48" min="-4.03225806451613" max="4.03225806451613" free="1" />
  41 + <parameter name="PivotEnergy" value="1" scale="300000" free="0" />
  42 + </spectrum>
  43 + <spatialModel type="PointSource">
  44 + <parameter name="RA" value="268.244867737546" error="0" scale="1" free="1" />
  45 + <parameter name="DEC" value="-30.3728286753247" error="0" scale="1" free="1" />
  46 + </spatialModel>
  47 + </source>
  48 + <source name="Src005" type="PointSource">
  49 + <spectrum type="PowerLaw">
  50 + <parameter name="Prefactor" value="1" error="0" scale="5.7e-18" min="0" free="1" />
  51 + <parameter name="Index" value="1" error="-0" scale="-2.48" min="-4.03225806451613" max="4.03225806451613" free="1" />
  52 + <parameter name="PivotEnergy" value="1" scale="300000" free="0" />
  53 + </spectrum>
  54 + <spatialModel type="PointSource">
  55 + <parameter name="RA" value="270.424492131939" error="0" scale="1" free="1" />
  56 + <parameter name="DEC" value="-29.6624142779832" error="0" scale="1" free="1" />
  57 + </spatialModel>
  58 + </source>
  59 + <source name="Src006" type="PointSource">
  60 + <spectrum type="PowerLaw">
  61 + <parameter name="Prefactor" value="1" error="0" scale="5.7e-18" min="0" free="1" />
  62 + <parameter name="Index" value="1" error="-0" scale="-2.48" min="-4.03225806451613" max="4.03225806451613" free="1" />
  63 + <parameter name="PivotEnergy" value="1" scale="300000" free="0" />
  64 + </spectrum>
  65 + <spatialModel type="PointSource">
  66 + <parameter name="RA" value="263.809469183313" error="0" scale="1" free="1" />
  67 + <parameter name="DEC" value="-31.2230130593475" error="0" scale="1" free="1" />
  68 + </spatialModel>
  69 + </source>
  70 + <source name="BackgroundModel" type="CTACubeBackground" instrument="CTA,HESS,MAGIC,VERITAS">
  71 + <spectrum type="PowerLaw">
  72 + <parameter name="Prefactor" value="1" error="0" scale="1" min="0.01" max="100" free="1" />
  73 + <parameter name="Index" value="0" error="0" scale="1" min="-5" max="5" free="1" />
  74 + <parameter name="PivotEnergy" value="1" scale="1000000" free="0" />
  75 + </spectrum>
  76 + </source>
  77 +</source_library>
doc/source/users/tutorials/1dc/show_onoff_spectrum.py
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 # ========================================================================== 2 # ==========================================================================
3 # Display butterfly generated by ctbutterfly and spectrum generated by csspec 3 # Display butterfly generated by ctbutterfly and spectrum generated by csspec
4 # 4 #
5 -# Copyright (C) 2018 Juergen Knoedlseder 5 +# Copyright (C) 2018-2021 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
@@ -51,13 +51,14 @@ def plot_spectrum_butterfly(specfile, butterfile, fmt=&#39;o&#39;, color=&#39;red&#39;): @@ -51,13 +51,14 @@ def plot_spectrum_butterfly(specfile, butterfile, fmt=&#39;o&#39;, color=&#39;red&#39;):
51 # Read spectrum file 51 # Read spectrum file
52 fits = gammalib.GFits(specfile) 52 fits = gammalib.GFits(specfile)
53 table = fits.table(1) 53 table = fits.table(1)
54 - c_energy = table['Energy']  
55 - c_ed = table['ed_Energy']  
56 - c_eu = table['eu_Energy']  
57 - c_flux = table['Flux']  
58 - c_eflux = table['e_Flux']  
59 - c_ts = table['TS']  
60 - c_upper = table['UpperLimit'] 54 + c_energy = table['e_ref']
  55 + c_ed = table['e_min']
  56 + c_eu = table['e_max']
  57 + c_flux = table['ref_e2dnde']
  58 + c_norm = table['norm']
  59 + c_eflux = table['norm_err']
  60 + c_upper = table['norm_ul']
  61 + c_ts = table['ts']
61 62
62 # Read butterfly file 63 # Read butterfly file
63 csv = gammalib.GCsv(butterfile) 64 csv = gammalib.GCsv(butterfile)
@@ -83,22 +84,23 @@ def plot_spectrum_butterfly(specfile, butterfile, fmt=&#39;o&#39;, color=&#39;red&#39;): @@ -83,22 +84,23 @@ def plot_spectrum_butterfly(specfile, butterfile, fmt=&#39;o&#39;, color=&#39;red&#39;):
83 84
84 # Get Test Statistic, flux and flux error 85 # Get Test Statistic, flux and flux error
85 ts = c_ts.real(row) 86 ts = c_ts.real(row)
86 - flx = c_flux.real(row)  
87 - e_flx = c_eflux.real(row) 87 + norm = c_norm.real(row)
  88 + flx = norm * c_flux.real(row)
  89 + e_flx = flx * c_eflux.real(row)
88 90
89 # If Test Statistic is larger than 9 and flux error is smaller than 91 # If Test Statistic is larger than 9 and flux error is smaller than
90 # flux then append flux plots ... 92 # flux then append flux plots ...
91 if ts > 9.0 and e_flx < flx: 93 if ts > 9.0 and e_flx < flx:
92 energies.append(c_energy.real(row)) 94 energies.append(c_energy.real(row))
93 - flux.append(c_flux.real(row)) 95 + flux.append(flx)
94 ed_engs.append(c_ed.real(row)) 96 ed_engs.append(c_ed.real(row))
95 eu_engs.append(c_eu.real(row)) 97 eu_engs.append(c_eu.real(row))
96 - e_flux.append(c_eflux.real(row)) 98 + e_flux.append(e_flx)
97 99
98 # ... otherwise append upper limit 100 # ... otherwise append upper limit
99 else: 101 else:
100 ul_energies.append(c_energy.real(row)) 102 ul_energies.append(c_energy.real(row))
101 - ul_flux.append(c_upper.real(row)) 103 + ul_flux.append(flx*c_upper.real(row))
102 ul_ed_engs.append(c_ed.real(row)) 104 ul_ed_engs.append(c_ed.real(row))
103 ul_eu_engs.append(c_eu.real(row)) 105 ul_eu_engs.append(c_eu.real(row))
104 106
test/tutorials.py
@@ -46,47 +46,128 @@ class tutorials(gammalib.GPythonTestSuite): @@ -46,47 +46,128 @@ class tutorials(gammalib.GPythonTestSuite):
46 # Call base class constructor 46 # Call base class constructor
47 gammalib.GPythonTestSuite.__init__(self) 47 gammalib.GPythonTestSuite.__init__(self)
48 48
49 - # Initialise results  
50 - self.results = None 49 + # Initialise private members
  50 + self._rst_step = 0 # Step counter
  51 + self._rst_path = '' # Path where the tested RST file resides
51 52
52 # Return 53 # Return
53 return 54 return
54 55
55 - # Set test functions  
56 - def set(self): 56 + # Clean pfiles directory
  57 + def _clean_pfiles(self):
57 """ 58 """
58 - Set all test functions 59 + Clean pfiles directory
59 """ 60 """
60 - # Set test name  
61 - self.name('Tutorials Verification')  
62 -  
63 - # Append tutorials  
64 - self.append(self.tutorials_1dc, 'Test 1DC tutorial') 61 + # Remove all files from pfiles directory
  62 + os.system('rm -rf %s/*.par' % os.environ['PFILES'])
65 63
66 # Return 64 # Return
67 return 65 return
68 66
69 - # Test line execution  
70 - def _execute_cmd(self, cmd, args): 67 + # Set result directory
  68 + def _set_result_dir(self, path):
71 """ 69 """
72 - Execute command 70 + Set result directory
  71 +
  72 + Parameters
  73 + ----------
  74 + path : str
  75 + Result directory path
73 """ 76 """
74 - # Create subprocess for tool  
75 - p = subprocess.Popen(cmd.split(' '), stdout=subprocess.PIPE,  
76 - stdin=subprocess.PIPE,  
77 - stderr=subprocess.PIPE) 77 + # Create result directory
  78 + try:
  79 + os.makedirs(path)
  80 + except:
  81 + pass
78 82
79 - # Write command arguments parameters  
80 - if len(args) > 0:  
81 - p.stdin.write(b'%s' % args)  
82 - p.stdin.close() 83 + # Clear result directory
  84 + os.system('rm -rf %s/*' % path)
83 85
84 - # Get results  
85 - res = p.communicate() 86 + # Step in result directory
  87 + os.chdir(path)
86 88
87 - # Set error flag and text  
88 - name = 'Test execution of command %s.' % cmd  
89 - self.test_assert((len(res[1]) == 0), name, res[1]) 89 + # Return
  90 + return
  91 +
  92 + # Test command execution
  93 + def _test_execute_cmd(self, cmd, args):
  94 + """
  95 + Test command execution
  96 +
  97 + Tests the execution of a command. Currently supported commands are:
  98 + - cd
  99 + - mkdir
  100 + - nano
  101 + - ./xxxxxx (any command xxxxxx that resides in the directory of the RST file)
  102 +
  103 + Parameters
  104 + ----------
  105 + cmd : str
  106 + Command line
  107 + args : list of str
  108 + Additional lines following the command line
  109 + """
  110 + # Split command line
  111 + cmdline = cmd.split(' ')
  112 +
  113 + # Check command line
  114 + self.test_assert((len(cmdline) > 0), 'Test command.', cmd)
  115 +
  116 + # Continue only if valid
  117 + if len(cmdline) > 0:
  118 +
  119 + # Extract command
  120 + command = gammalib.strip_whitespace(cmdline[0])
  121 +
  122 + # Handle commands
  123 + if command == 'mkdir':
  124 + self.test_value(len(cmdline), 2, 'Test command "mkdir".')
  125 + self.test_value(len(args), 0, 'Test that no lines follow "mkdir".')
  126 + if len(cmdline) > 1:
  127 + dirname = gammalib.strip_whitespace(cmdline[1])
  128 + os.system('mkdir -p %s' % dirname)
  129 +
  130 + elif command == 'cd':
  131 + self.test_value(len(cmdline), 2, 'Test command "cd".')
  132 + self.test_value(len(args), 0, 'Test that no lines follow "cd".')
  133 + if len(cmdline) > 1:
  134 + dirname = gammalib.strip_whitespace(cmdline[1])
  135 + os.chdir(dirname)
  136 +
  137 + elif command == 'nano':
  138 + self.test_value(len(cmdline), 2, 'Test command "nano".')
  139 + self.test_assert((len(args) > 0), 'Test that lines follow "nano".')
  140 + if len(cmdline) > 1:
  141 + fname = gammalib.strip_whitespace(cmdline[1])
  142 + f = open(fname, 'wb')
  143 + for arg in args:
  144 + f.write(arg)
  145 + f.close()
  146 +
  147 + elif command[0:2] == './':
  148 + scriptname = command[2:]
  149 + self.test_assert((len(args) == 0), 'Test script "%s".' % scriptname)
  150 + tool = '%s/%s' % (self._rst_path, scriptname)
  151 +
  152 + # Debug: show tool
  153 + #print tool.split(' '),
  154 +
  155 + # Create subprocess for tool
  156 + p = subprocess.Popen(tool.split(' '), stdout=subprocess.PIPE,
  157 + stdin=subprocess.PIPE,
  158 + stderr=subprocess.PIPE)
  159 +
  160 + # Get results
  161 + res = p.communicate()
  162 +
  163 + # Set error flag and text
  164 + name = 'Test execution of %s.' % tool
  165 + self.test_assert((len(res[1]) == 0), name, res[1])
  166 +
  167 + else:
  168 + name = 'Test command "%s".' % command
  169 + msg = 'Unknown command "%s"' % command
  170 + self.test_assert(False, name, msg)
90 171
91 # Return 172 # Return
92 return 173 return
@@ -113,8 +194,7 @@ class tutorials(gammalib.GPythonTestSuite): @@ -113,8 +194,7 @@ class tutorials(gammalib.GPythonTestSuite):
113 194
114 # If we have a command then execute it 195 # If we have a command then execute it
115 if cmd != '': 196 if cmd != '':
116 - print(cmd, args)  
117 - self._execute_cmd(cmd, args) 197 + self._test_execute_cmd(cmd, args)
118 198
119 # Set new command 199 # Set new command
120 cmd = line[2:] 200 cmd = line[2:]
@@ -126,8 +206,7 @@ class tutorials(gammalib.GPythonTestSuite): @@ -126,8 +206,7 @@ class tutorials(gammalib.GPythonTestSuite):
126 206
127 # If there is a pending command then execute it 207 # If there is a pending command then execute it
128 if cmd != '': 208 if cmd != '':
129 - print(cmd, args)  
130 - self._execute_cmd(cmd, args) 209 + self._test_execute_cmd(cmd, args)
131 210
132 # Return 211 # Return
133 return 212 return
@@ -149,23 +228,32 @@ class tutorials(gammalib.GPythonTestSuite): @@ -149,23 +228,32 @@ class tutorials(gammalib.GPythonTestSuite):
149 lines : list of str 228 lines : list of str
150 Command lines 229 Command lines
151 """ 230 """
152 - # Initialise command  
153 - cmd = '' 231 + # Increment step counter
  232 + self._rst_step += 1
  233 +
  234 + # Initialise arguments
  235 + args = ''
  236 +
  237 + # Set command
  238 + cmd = tool.split(' ')
154 239
155 # Append lines 240 # Append lines
156 for line in lines: 241 for line in lines:
157 pos = line.find(']') 242 pos = line.find(']')
158 if pos != -1: 243 if pos != -1:
159 arg = gammalib.strip_whitespace(line[pos+1:]) 244 arg = gammalib.strip_whitespace(line[pos+1:])
160 - cmd += '%s\n' % arg 245 + args += '%s\n' % arg
  246 +
  247 + # Debug: show tool
  248 + #print cmd,
161 249
162 # Create subprocess for tool 250 # Create subprocess for tool
163 - p = subprocess.Popen([tool], stdout=subprocess.PIPE,  
164 - stdin=subprocess.PIPE,  
165 - stderr=subprocess.PIPE) 251 + p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
  252 + stdin=subprocess.PIPE,
  253 + stderr=subprocess.PIPE)
166 254
167 # Write command line parameters 255 # Write command line parameters
168 - p.stdin.write(b'%s' % cmd) 256 + p.stdin.write(b'%s' % args)
169 257
170 # Get results 258 # Get results
171 res = p.communicate() 259 res = p.communicate()
@@ -177,13 +265,20 @@ class tutorials(gammalib.GPythonTestSuite): @@ -177,13 +265,20 @@ class tutorials(gammalib.GPythonTestSuite):
177 name = 'Test execution of %s.' % tool 265 name = 'Test execution of %s.' % tool
178 self.test_assert((len(res[1]) == 0), name, res[1]) 266 self.test_assert((len(res[1]) == 0), name, res[1])
179 267
  268 + # Preprend step counter to logfile
  269 + logfile = gammalib.GFilename('%s.log' % (cmd[0]))
  270 + if logfile.exists():
  271 + src = logfile.url()
  272 + dst = '%2.2d_%s' % (self._rst_step, src)
  273 + os.system('mv %s %s' % (src, dst))
  274 +
180 # Return 275 # Return
181 return 276 return
182 277
183 - # Add workflow step  
184 - def _add_workflow_step(self, tool, lines): 278 + # Test workflow step
  279 + def _test_step(self, tool, lines):
185 """ 280 """
186 - Add workflow step 281 + Test workflow step
187 282
188 Parameters 283 Parameters
189 ---------- 284 ----------
@@ -191,18 +286,12 @@ class tutorials(gammalib.GPythonTestSuite): @@ -191,18 +286,12 @@ class tutorials(gammalib.GPythonTestSuite):
191 Tool name 286 Tool name
192 lines : list of str 287 lines : list of str
193 Command lines 288 Command lines
194 -  
195 - Returns  
196 - -------  
197 - cmd : str  
198 - Workflow command  
199 """ 289 """
200 - # If tool is a ctool or cscript then add a ctool or cscript workflow  
201 - # step 290 + # If tool is a ctool or cscript then test ctool or cscript execution
202 if tool[0:2] == 'ct' or tool[0:2] == 'cs': 291 if tool[0:2] == 'ct' or tool[0:2] == 'cs':
203 self._test_ctool_execution(tool, lines) 292 self._test_ctool_execution(tool, lines)
204 293
205 - # ... otherwise execute lines 294 + # ... otherwise test line execution
206 else: 295 else:
207 all_lines = ['$ %s' % tool] 296 all_lines = ['$ %s' % tool]
208 all_lines.extend(lines) 297 all_lines.extend(lines)
@@ -211,21 +300,33 @@ class tutorials(gammalib.GPythonTestSuite): @@ -211,21 +300,33 @@ class tutorials(gammalib.GPythonTestSuite):
211 # Return 300 # Return
212 return 301 return
213 302
214 - # Extract workflow  
215 - def _get_workflow(self, filename): 303 + # Copy file
  304 + def _copy_file(self, filename):
216 """ 305 """
217 - Extract workflow from Sphinx rst file 306 + Copy file from rst directory into working directory
  307 + """
  308 + # Set source filename
  309 + src = self._rst_path + '/' + filename
  310 +
  311 + # Copy file
  312 + os.system('cp %s %s' % (src, filename))
  313 +
  314 + # Return
  315 + return
  316 +
  317 + # Test Sphinx rst file
  318 + def _test_rst_file(self, filename):
  319 + """
  320 + Test Sphinx rst file
218 321
219 Parameters 322 Parameters
220 ---------- 323 ----------
221 filename : str 324 filename : str
222 - RST filename  
223 -  
224 - Returns  
225 - -------  
226 - workflow : `~gammalib.GXml`  
227 - Workflow XML file 325 + Sphinx rst filename
228 """ 326 """
  327 + # Set RST path
  328 + self._rst_path = os.path.abspath(os.path.dirname(filename))
  329 +
229 # Open RST file 330 # Open RST file
230 f = open(filename, 'r') 331 f = open(filename, 'r')
231 332
@@ -238,6 +339,8 @@ class tutorials(gammalib.GPythonTestSuite): @@ -238,6 +339,8 @@ class tutorials(gammalib.GPythonTestSuite):
238 # If we are not in a code block then check whether a code block 339 # If we are not in a code block then check whether a code block
239 # starts 340 # starts
240 if not code: 341 if not code:
  342 +
  343 + # Check for start of a code block
241 pos = line.find('code-block:: bash') 344 pos = line.find('code-block:: bash')
242 if pos != -1: 345 if pos != -1:
243 code = True 346 code = True
@@ -246,6 +349,14 @@ class tutorials(gammalib.GPythonTestSuite): @@ -246,6 +349,14 @@ class tutorials(gammalib.GPythonTestSuite):
246 lines = [] 349 lines = []
247 continue 350 continue
248 351
  352 + # ... otherwise check for literalinclude, and if found, copy
  353 + # relevant file
  354 + pos = line.find('literalinclude::')
  355 + if pos != -1:
  356 + filename = gammalib.strip_whitespace(line[pos+16:-1])
  357 + self._copy_file(filename)
  358 + continue
  359 +
249 # ... otherwise 360 # ... otherwise
250 else: 361 else:
251 362
@@ -257,7 +368,7 @@ class tutorials(gammalib.GPythonTestSuite): @@ -257,7 +368,7 @@ class tutorials(gammalib.GPythonTestSuite):
257 tool = line[pos+3:-1] 368 tool = line[pos+3:-1]
258 continue 369 continue
259 370
260 - # ... otherwise append lines or add workflow step 371 + # ... otherwise append lines or test step
261 else: 372 else:
262 blank = gammalib.strip_whitespace(line[0:start]) 373 blank = gammalib.strip_whitespace(line[0:start])
263 cmd = line[start:-1] 374 cmd = line[start:-1]
@@ -265,13 +376,27 @@ class tutorials(gammalib.GPythonTestSuite): @@ -265,13 +376,27 @@ class tutorials(gammalib.GPythonTestSuite):
265 lines.append(cmd) 376 lines.append(cmd)
266 continue 377 continue
267 else: 378 else:
268 - self._add_workflow_step(tool, lines) 379 + self._test_step(tool, lines)
269 code = False 380 code = False
270 continue 381 continue
271 382
272 - # Add step if some code is pending 383 + # Test step if some code is pending
273 if code: 384 if code:
274 - self._add_workflow_step(tool, lines) 385 + self._test_step(tool, lines)
  386 +
  387 + # Return
  388 + return
  389 +
  390 + # Set test functions
  391 + def set(self):
  392 + """
  393 + Set all test functions
  394 + """
  395 + # Set test name
  396 + self.name('Tutorials Verification')
  397 +
  398 + # Append tutorials
  399 + self.append(self.tutorials_1dc, 'Test 1DC tutorial')
275 400
276 # Return 401 # Return
277 return 402 return
@@ -281,15 +406,49 @@ class tutorials(gammalib.GPythonTestSuite): @@ -281,15 +406,49 @@ class tutorials(gammalib.GPythonTestSuite):
281 """ 406 """
282 Test 1DC tutorials 407 Test 1DC tutorials
283 """ 408 """
284 - # Set environment variables  
285 - os.environ['CTADATA'] = '/project-data/cta/data/1dc'  
286 - os.environ['CALDB'] = '/project-data/cta/data/1dc/caldb' 409 + # Continue only if CTADATA1DC environment variable is set
  410 + if 'CTADATA1DC' in os.environ:
  411 +
  412 + # Set environment variables
  413 + os.environ['CTADATA'] = os.environ['CTADATA1DC']
  414 + os.environ['CALDB'] = os.environ['CTADATA1DC']+'/caldb'
  415 +
  416 + # Set Sphinx rst file path
  417 + path = os.path.abspath('../doc/source/users/tutorials/1dc')
  418 +
  419 + # Set result directory
  420 + self._set_result_dir('tutorials/1dc')
287 421
288 - # Extract workflow  
289 - #workflow = self._get_workflow('../doc/source/users/tutorials/1dc/first_onoff.rst')  
290 - workflow = self._get_workflow('first_onoff.rst') 422 + # Get current working directory
  423 + cwd = os.getcwd()
291 424
292 - # Run workflow 425 + # Clean pfiles
  426 + self._clean_pfiles()
  427 +
  428 + # Initialise step counter
  429 + self._rst_step = 0
  430 +
  431 + # Test Sphinx rst files
  432 + self._test_rst_file('%s/first_select_obs.rst' % path)
  433 + self._test_rst_file('%s/first_select_events.rst' % path)
  434 + self._test_rst_file('%s/first_skymap.rst' % path)
  435 + self._test_rst_file('%s/first_detect.rst' % path)
  436 + self._test_rst_file('%s/first_stacked.rst' % path)
  437 + self._test_rst_file('%s/first_fitting.rst' % path)
  438 + self._test_rst_file('%s/first_improving.rst' % path)
  439 + self._test_rst_file('%s/first_unbinned.rst' % path)
  440 +
  441 + # Reset working directory
  442 + os.chdir(cwd)
  443 +
  444 + # Clean pfiles
  445 + self._clean_pfiles()
  446 +
  447 + # Initialise step counter
  448 + self._rst_step = 0
  449 +
  450 + # Test Sphinx rst file for On/Off analysis
  451 + self._test_rst_file('%s/first_onoff.rst' % path)
293 452
294 # Return 453 # Return
295 return 454 return
@@ -318,15 +477,18 @@ if __name__ == &#39;__main__&#39;: @@ -318,15 +477,18 @@ if __name__ == &#39;__main__&#39;:
318 except: 477 except:
319 pass 478 pass
320 479
321 - # Copy ctools parameter files into pfiles directory  
322 - os.system('cp -r ../src/*/*.par pfiles/')  
323 -  
324 # Set PFILES environment variable 480 # Set PFILES environment variable
325 - os.environ['PFILES'] = 'pfiles' 481 + os.environ['PFILES'] = os.path.abspath('pfiles')
  482 +
  483 + # Get current working directory
  484 + cwd = os.getcwd()
326 485
327 # Run test suite 486 # Run test suite
328 success = suites.run() 487 success = suites.run()
329 488
  489 + # Reset working directory
  490 + os.chdir(cwd)
  491 +
330 # Save test results 492 # Save test results
331 suites.save('reports/tutorials.xml') 493 suites.save('reports/tutorials.xml')
332 494