Commit 59d3205fd82194ed570ced239171e9d7020b9e81

Authored by Jürgen Knödlseder
2 parents 997a7f46 c0a3fbd1

Merge branch '3510-test-rst' into integration

.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)
cscripts/cstsmapsplit.py
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 # ========================================================================== 2 # ==========================================================================
3 # Create commands to split TS map computation 3 # Create commands to split TS map computation
4 # 4 #
5 -# Copyright (C) 2016-2019 Michael Mayer 5 +# Copyright (C) 2016-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
@@ -247,6 +247,9 @@ class cstsmapsplit(ctools.cslikelihood): @@ -247,6 +247,9 @@ class cstsmapsplit(ctools.cslikelihood):
247 for cmd in self._cmd: 247 for cmd in self._cmd:
248 f.write(cmd + '\n') 248 f.write(cmd + '\n')
249 249
  250 + # Add wait statement
  251 + f.write('wait\n')
  252 +
250 # Close file 253 # Close file
251 f.close() 254 f.close()
252 255
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
@@ -152,16 +154,18 @@ def show_spectrum_butterfly(): @@ -152,16 +154,18 @@ def show_spectrum_butterfly():
152 plt.grid() 154 plt.grid()
153 155
154 # Set usage string 156 # Set usage string
155 - usage = 'show_onoff_spectrum.py [-t title] [specfile] [butterfile]' 157 + usage = 'show_onoff_spectrum.py [-p plotfile] [-t title] [specfile] [butterfile]'
156 158
157 # Set default options 159 # Set default options
158 - options = [{'option': '-t', 'value': 'Cassiopeia A'}] 160 + options = [{'option': '-p', 'value': ''},
  161 + {'option': '-t', 'value': 'Cassiopeia A'}]
159 162
160 # Get arguments and options from command line arguments 163 # Get arguments and options from command line arguments
161 args, options = cscripts.ioutils.get_args_options(options, usage) 164 args, options = cscripts.ioutils.get_args_options(options, usage)
162 165
163 # Extract script parameters from options 166 # Extract script parameters from options
164 - title = options[0]['value'] 167 + plotfile = options[0]['value']
  168 + title = options[1]['value']
165 169
166 # Set filenames 170 # Set filenames
167 specfile = 'spectrum.fits' 171 specfile = 'spectrum.fits'
@@ -182,7 +186,10 @@ def show_spectrum_butterfly(): @@ -182,7 +186,10 @@ def show_spectrum_butterfly():
182 plt.title(title) 186 plt.title(title)
183 187
184 # Show figure 188 # Show figure
185 - plt.show() 189 + if len(plotfile) > 0:
  190 + plt.savefig(plotfile)
  191 + else:
  192 + plt.show()
186 193
187 # Return 194 # Return
188 return 195 return
doc/source/users/tutorials/howto/extended_model.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" scale="1" value="266.424" free="1" />
  12 + <parameter name="DEC" scale="1" value="-29.005" free="1" />
  13 + </spatialModel>
  14 + </source>
  15 + <source name="Src002" type="PointSource">
  16 + <spectrum type="PowerLaw">
  17 + <parameter name="Prefactor" scale="1e-18" value="5.7" min="1e-07" max="1000.0" free="1"/>
  18 + <parameter name="Index" scale="-1" value="2.48" min="0.0" max="5.0" free="1"/>
  19 + <parameter name="PivotEnergy" scale="1e6" value="0.3" min="0.01" max="1000.0" free="0"/>
  20 + </spectrum>
  21 + <spatialModel type="PointSource">
  22 + <parameter name="RA" scale="1" value="266.832" free="1" />
  23 + <parameter name="DEC" scale="1" value="-28.146" free="1" />
  24 + </spatialModel>
  25 + </source>
  26 + <source name="Src003" type="ExtendedSource" tscalc="1">
  27 + <spectrum type="PowerLaw">
  28 + <parameter name="Prefactor" scale="5.7e-18" value="1.0" min="0" max="1000.0" free="1"/>
  29 + <parameter name="Index" scale="-2.48" value="1.0" min="-4.0" max="4.0" free="1"/>
  30 + <parameter name="PivotEnergy" scale="300000" value="1.0" free="0" />
  31 + </spectrum>
  32 + <spatialModel type="RadialDisk">
  33 + <parameter name="RA" scale="1.0" value="266.3070" min="-360" max="360" free="1"/>
  34 + <parameter name="DEC" scale="1.0" value="-30.1876" min="-90" max="90" free="1"/>
  35 + <parameter name="Radius" scale="1.0" value="0.3" min="0.001" max="10" free="1"/>
  36 + </spatialModel>
  37 + </source>
  38 + <source name="IEM" type="DiffuseSource">
  39 + <spectrum type="ConstantValue">
  40 + <parameter name="Value" scale="1" value="1" min="1e-05" max="100000" free="1"/>
  41 + </spectrum>
  42 + <spatialModel type="MapCubeFunction" file="$CTADATA/models/cube_iem.fits">
  43 + <parameter name="Normalization" scale="1" value="1" min="0.001" max="1000" free="0"/>
  44 + </spatialModel>
  45 + </source>
  46 + <source name="Background" type="CTACubeBackground" instrument="CTA">
  47 + <spectrum type="PowerLaw">
  48 + <parameter name="Prefactor" scale="1" value="1" min="0.01" max="100" free="1"/>
  49 + <parameter name="Index" scale="1" value="0" min="-5" max="5" free="1"/>
  50 + <parameter name="PivotEnergy" scale="1000000" value="1" min="0.01" max="1000.0" free="0"/>
  51 + </spectrum>
  52 + </source>
  53 +</source_library>
doc/source/users/tutorials/howto/howto_connect_irfs.rst
@@ -52,21 +52,11 @@ array: @@ -52,21 +52,11 @@ array:
52 Output event data file or observation definition XML file [north.fits] south.fits 52 Output event data file or observation definition XML file [north.fits] south.fits
53 53
54 You now need to combine the information about these two observations in an 54 You now need to combine the information about these two observations in an
55 -observation definition XML file: 55 +observation definition XML file. Let's put the following content in in the
  56 +``obs_irf.xml``:
56 57
57 -.. code-block:: xml  
58 -  
59 - <?xml version="1.0" standalone="no"?>  
60 - <observation_list title="observation library">  
61 - <observation name="Crab" id="00001" instrument="CTA">  
62 - <parameter name="EventList" file="north.fits"/>  
63 - <parameter name="Calibration" database="prod2" response="North_0.5h"/>  
64 - </observation>  
65 - <observation name="Crab" id="00002" instrument="CTA">  
66 - <parameter name="EventList" file="south.fits"/>  
67 - <parameter name="Calibration" database="prod2" response="South_0.5h"/>  
68 - </observation>  
69 - </observation_list> 58 +.. literalinclude:: obs_irf.xml
  59 + :language: xml
70 60
71 Each observation now has a ``Calibration`` parameter with the attributes 61 Each observation now has a ``Calibration`` parameter with the attributes
72 ``database`` and ``response``. 62 ``database`` and ``response``.
doc/source/users/tutorials/howto/howto_extent.rst
@@ -33,22 +33,12 @@ To do this, copy the 1DC :ref:`model definition &lt;glossary_moddef&gt;` file @@ -33,22 +33,12 @@ To do this, copy the 1DC :ref:`model definition &lt;glossary_moddef&gt;` file
33 33
34 $ cp $CTOOLS/share/models/1dc_howto.xml extended_model.xml 34 $ cp $CTOOLS/share/models/1dc_howto.xml extended_model.xml
35 35
36 -and add the following source to it  
37 -  
38 -.. code-block:: xml  
39 -  
40 - <source name="Src003" type="ExtendedSource" tscalc="1">  
41 - <spectrum type="PowerLaw">  
42 - <parameter name="Prefactor" scale="5.7e-18" value="1.0" min="0" max="1000.0" free="1"/>  
43 - <parameter name="Index" scale="-2.48" value="1.0" min="-4.0" max="4.0" free="1"/>  
44 - <parameter name="PivotEnergy" scale="300000" value="1.0" free="0" />  
45 - </spectrum>  
46 - <spatialModel type="RadialDisk">  
47 - <parameter name="RA" scale="1.0" value="266.3070" min="-360" max="360" free="1"/>  
48 - <parameter name="DEC" scale="1.0" value="-30.1876" min="-90" max="90" free="1"/>  
49 - <parameter name="Radius" scale="1.0" value="0.3" min="0.001" max="10" free="1"/>  
50 - </spatialModel>  
51 - </source> 36 +to :download:`extended_model.xml <extended_model.xml>` and add the following
  37 +source to it:
  38 +
  39 +.. literalinclude:: extended_model.xml
  40 + :language: xml
  41 + :lines: 26-37
52 42
53 Then run :ref:`ctlike` to fit the parameters of ``Src003`` together with the 43 Then run :ref:`ctlike` to fit the parameters of ``Src003`` together with the
54 other source parameters 44 other source parameters
doc/source/users/tutorials/howto/howto_ts.rst
@@ -19,28 +19,13 @@ Copy the 1DC :ref:`model definition &lt;glossary_moddef&gt;` file @@ -19,28 +19,13 @@ Copy the 1DC :ref:`model definition &lt;glossary_moddef&gt;` file
19 $ cp $CTOOLS/share/models/1dc_howto.xml ts_model.xml 19 $ cp $CTOOLS/share/models/1dc_howto.xml ts_model.xml
20 20
21 and modify the file by adding ``tscalc="1"`` to the ``<source>`` tag for 21 and modify the file by adding ``tscalc="1"`` to the ``<source>`` tag for
22 -source ``Src1``. Your 22 +source ``Src1``. The first lines of the :download:`ts_model.xml <ts_model.xml>`
23 :ref:`model definition XML file <glossary_moddef>` 23 :ref:`model definition XML file <glossary_moddef>`
24 should then look like this: 24 should then look like this:
25 25
26 -.. code-block:: xml  
27 -  
28 - <?xml version="1.0" encoding="UTF-8" standalone="no"?>  
29 - <source_library title="source library">  
30 - <source name="Src001" type="PointSource" tscalc="1">  
31 - <spectrum type="ExponentialCutoffPowerLaw">  
32 - <parameter name="Prefactor" scale="1e-18" value="5.7" min="1e-07" max="1000.0" free="1"/>  
33 - <parameter name="Index" scale="-1" value="2.48" min="0.0" max="+5.0" free="1"/>  
34 - <parameter name="CutoffEnergy" scale="1e7" value="1.0" min="0.01" max="1000.0" free="1"/>  
35 - <parameter name="PivotEnergy" scale="1e6" value="0.3" min="0.01" max="1000.0" free="0"/>  
36 - </spectrum>  
37 - <spatialModel type="PointSource">  
38 - <parameter name="RA" scale="1" value="266.424" free="1" />  
39 - <parameter name="DEC" scale="1" value="-29.005" free="1" />  
40 - </spatialModel>  
41 - </source>  
42 - ...  
43 - </source_library> 26 +.. literalinclude:: ts_model.xml
  27 + :language: xml
  28 + :lines: 1-14
44 29
45 Then run :ref:`ctlike` to compute the so-called Test Statistic, which is twice 30 Then run :ref:`ctlike` to compute the so-called Test Statistic, which is twice
46 the difference between the log-likelihood value obtained for a fit that includes 31 the difference between the log-likelihood value obtained for a fit that includes
doc/source/users/tutorials/howto/howto_tsmap.rst
@@ -100,12 +100,13 @@ The figure below shows the resulting Test Statistic map. @@ -100,12 +100,13 @@ The figure below shows the resulting Test Statistic map.
100 cttsmap inobs=cntcube.fits inmodel=$CTOOLS/share/models/test_cube.xml srcname=Test expcube=expcube.fits psfcube=psfcube.fits bkgcube=bkgcube.fits nxpix=10 nypix=10 binsz=0.05 coordsys=GAL proj=CAR xref=0.0 yref=0.0 logL0=-447785.5939102234 binmin=70 binmax=80 outmap=tsmap_split_7.fits logfile=tsmap_split_7.log & 100 cttsmap inobs=cntcube.fits inmodel=$CTOOLS/share/models/test_cube.xml srcname=Test expcube=expcube.fits psfcube=psfcube.fits bkgcube=bkgcube.fits nxpix=10 nypix=10 binsz=0.05 coordsys=GAL proj=CAR xref=0.0 yref=0.0 logL0=-447785.5939102234 binmin=70 binmax=80 outmap=tsmap_split_7.fits logfile=tsmap_split_7.log &
101 cttsmap inobs=cntcube.fits inmodel=$CTOOLS/share/models/test_cube.xml srcname=Test expcube=expcube.fits psfcube=psfcube.fits bkgcube=bkgcube.fits nxpix=10 nypix=10 binsz=0.05 coordsys=GAL proj=CAR xref=0.0 yref=0.0 logL0=-447785.5939102234 binmin=80 binmax=90 outmap=tsmap_split_8.fits logfile=tsmap_split_8.log & 101 cttsmap inobs=cntcube.fits inmodel=$CTOOLS/share/models/test_cube.xml srcname=Test expcube=expcube.fits psfcube=psfcube.fits bkgcube=bkgcube.fits nxpix=10 nypix=10 binsz=0.05 coordsys=GAL proj=CAR xref=0.0 yref=0.0 logL0=-447785.5939102234 binmin=80 binmax=90 outmap=tsmap_split_8.fits logfile=tsmap_split_8.log &
102 cttsmap inobs=cntcube.fits inmodel=$CTOOLS/share/models/test_cube.xml srcname=Test expcube=expcube.fits psfcube=psfcube.fits bkgcube=bkgcube.fits nxpix=10 nypix=10 binsz=0.05 coordsys=GAL proj=CAR xref=0.0 yref=0.0 logL0=-447785.5939102234 binmin=90 binmax=100 outmap=tsmap_split_9.fits logfile=tsmap_split_9.log & 102 cttsmap inobs=cntcube.fits inmodel=$CTOOLS/share/models/test_cube.xml srcname=Test expcube=expcube.fits psfcube=psfcube.fits bkgcube=bkgcube.fits nxpix=10 nypix=10 binsz=0.05 coordsys=GAL proj=CAR xref=0.0 yref=0.0 logL0=-447785.5939102234 binmin=90 binmax=100 outmap=tsmap_split_9.fits logfile=tsmap_split_9.log &
  103 + wait
103 104
104 Now run the ASCII file by typing 105 Now run the ASCII file by typing
105 106
106 .. code-block:: bash 107 .. code-block:: bash
107 108
108 - ./tsmap_commands.dat 109 + $ ./tsmap_commands.dat
109 110
110 This will execute 10 :ref:`cttsmap` jobs in parallel. Each of the jobs will 111 This will execute 10 :ref:`cttsmap` jobs in parallel. Each of the jobs will
111 compute 10 pixels of the Test Statistic map. You combine the resulting 10 112 compute 10 pixels of the Test Statistic map. You combine the resulting 10
doc/source/users/tutorials/howto/howto_ulimit.rst
@@ -22,21 +22,12 @@ To do this, copy the 1DC :ref:`model definition &lt;glossary_moddef&gt;` file @@ -22,21 +22,12 @@ To do this, copy the 1DC :ref:`model definition &lt;glossary_moddef&gt;` file
22 22
23 $ cp $CTOOLS/share/models/1dc_howto.xml ulimit_model.xml 23 $ cp $CTOOLS/share/models/1dc_howto.xml ulimit_model.xml
24 24
25 -and add the following source to it  
26 -  
27 -.. code-block:: xml  
28 -  
29 - <source name="Test" type="PointSource">  
30 - <spectrum type="PowerLaw">  
31 - <parameter name="Prefactor" value="1" scale="1.0e-20" min="0" free="1"/>  
32 - <parameter name="Index" value="1" scale="-2.48" min="-5" max="5" free="0"/>  
33 - <parameter name="PivotEnergy" value="1" scale="300000" free="0"/>  
34 - </spectrum>  
35 - <spatialModel type="PointSource">  
36 - <parameter name="GLON" value="0.1" scale="1" free="0"/>  
37 - <parameter name="GLAT" value="0.4" scale="1" free="0"/>  
38 - </spatialModel>  
39 - </source> 25 +to :download:`ulimit_model.xml <ulimit_model.xml>` and add the following
  26 +source to it:
  27 +
  28 +.. literalinclude:: ulimit_model.xml
  29 + :language: xml
  30 + :lines: 3-13
40 31
41 Now run the :ref:`ctulimit` tool as follows: 32 Now run the :ref:`ctulimit` tool as follows:
42 33
doc/source/users/tutorials/howto/obs_irf.xml 0 → 100644
  1 +<?xml version="1.0" standalone="no"?>
  2 +<observation_list title="observation library">
  3 + <observation name="Crab" id="00001" instrument="CTA">
  4 + <parameter name="EventList" file="north.fits"/>
  5 + <parameter name="Calibration" database="prod2" response="North_0.5h"/>
  6 + </observation>
  7 + <observation name="Crab" id="00002" instrument="CTA">
  8 + <parameter name="EventList" file="south.fits"/>
  9 + <parameter name="Calibration" database="prod2" response="South_0.5h"/>
  10 + </observation>
  11 +</observation_list>
  12 +
doc/source/users/tutorials/howto/ts_model.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" tscalc="1">
  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" scale="1" value="266.424" free="1" />
  12 + <parameter name="DEC" scale="1" value="-29.005" free="1" />
  13 + </spatialModel>
  14 + </source>
  15 + <source name="Src002" type="PointSource">
  16 + <spectrum type="PowerLaw">
  17 + <parameter name="Prefactor" scale="1e-18" value="5.7" min="1e-07" max="1000.0" free="1"/>
  18 + <parameter name="Index" scale="-1" value="2.48" min="0.0" max="5.0" free="1"/>
  19 + <parameter name="PivotEnergy" scale="1e6" value="0.3" min="0.01" max="1000.0" free="0"/>
  20 + </spectrum>
  21 + <spatialModel type="PointSource">
  22 + <parameter name="RA" scale="1" value="266.832" free="1" />
  23 + <parameter name="DEC" scale="1" value="-28.146" free="1" />
  24 + </spatialModel>
  25 + </source>
  26 + <source name="IEM" type="DiffuseSource">
  27 + <spectrum type="ConstantValue">
  28 + <parameter name="Value" scale="1" value="1" min="1e-05" max="100000" free="1"/>
  29 + </spectrum>
  30 + <spatialModel type="MapCubeFunction" file="$CTADATA/models/cube_iem.fits">
  31 + <parameter name="Normalization" scale="1" value="1" min="0.001" max="1000" free="0"/>
  32 + </spatialModel>
  33 + </source>
  34 + <source name="Background" type="CTACubeBackground" instrument="CTA">
  35 + <spectrum type="PowerLaw">
  36 + <parameter name="Prefactor" scale="1" value="1" min="0.01" max="100" free="1"/>
  37 + <parameter name="Index" scale="1" value="0" min="-5" max="5" free="1"/>
  38 + <parameter name="PivotEnergy" scale="1000000" value="1" min="0.01" max="1000.0" free="0"/>
  39 + </spectrum>
  40 + </source>
  41 +</source_library>
doc/source/users/tutorials/howto/ulimit_model.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2 +<source_library title="source library">
  3 + <source name="Test" type="PointSource">
  4 + <spectrum type="PowerLaw">
  5 + <parameter name="Prefactor" value="1" scale="1.0e-20" min="0" free="1"/>
  6 + <parameter name="Index" value="1" scale="-2.48" min="-5" max="5" free="0"/>
  7 + <parameter name="PivotEnergy" value="1" scale="300000" free="0"/>
  8 + </spectrum>
  9 + <spatialModel type="PointSource">
  10 + <parameter name="GLON" value="0.1" scale="1" free="0"/>
  11 + <parameter name="GLAT" value="0.4" scale="1" free="0"/>
  12 + </spatialModel>
  13 + </source>
  14 + <source name="Src001" type="PointSource">
  15 + <spectrum type="ExponentialCutoffPowerLaw">
  16 + <parameter name="Prefactor" scale="1e-18" value="5.7" min="1e-07" max="1000.0" free="1"/>
  17 + <parameter name="Index" scale="-1" value="2.48" min="0.0" max="+5.0" free="1"/>
  18 + <parameter name="CutoffEnergy" scale="1e7" value="1.0" min="0.01" max="1000.0" free="1"/>
  19 + <parameter name="PivotEnergy" scale="1e6" value="0.3" min="0.01" max="1000.0" free="0"/>
  20 + </spectrum>
  21 + <spatialModel type="PointSource">
  22 + <parameter name="RA" scale="1" value="266.424" free="1" />
  23 + <parameter name="DEC" scale="1" value="-29.005" free="1" />
  24 + </spatialModel>
  25 + </source>
  26 + <source name="Src002" type="PointSource">
  27 + <spectrum type="PowerLaw">
  28 + <parameter name="Prefactor" scale="1e-18" value="5.7" min="1e-07" max="1000.0" free="1"/>
  29 + <parameter name="Index" scale="-1" value="2.48" min="0.0" max="5.0" free="1"/>
  30 + <parameter name="PivotEnergy" scale="1e6" value="0.3" min="0.01" max="1000.0" free="0"/>
  31 + </spectrum>
  32 + <spatialModel type="PointSource">
  33 + <parameter name="RA" scale="1" value="266.832" free="1" />
  34 + <parameter name="DEC" scale="1" value="-28.146" free="1" />
  35 + </spatialModel>
  36 + </source>
  37 + <source name="IEM" type="DiffuseSource">
  38 + <spectrum type="ConstantValue">
  39 + <parameter name="Value" scale="1" value="1" min="1e-05" max="100000" free="1"/>
  40 + </spectrum>
  41 + <spatialModel type="MapCubeFunction" file="$CTADATA/models/cube_iem.fits">
  42 + <parameter name="Normalization" scale="1" value="1" min="0.001" max="1000" free="0"/>
  43 + </spatialModel>
  44 + </source>
  45 + <source name="Background" type="CTACubeBackground" instrument="CTA">
  46 + <spectrum type="PowerLaw">
  47 + <parameter name="Prefactor" scale="1" value="1" min="0.01" max="100" free="1"/>
  48 + <parameter name="Index" scale="1" value="0" min="-5" max="5" free="1"/>
  49 + <parameter name="PivotEnergy" scale="1000000" value="1" min="0.01" max="1000.0" free="0"/>
  50 + </spectrum>
  51 + </source>
  52 +</source_library>
test/tutorials.py 0 → 100755
  1 +#! /usr/bin/env python
  2 +# ==========================================================================
  3 +# This script tests the Sphinx tutorials
  4 +#
  5 +# Usage:
  6 +# ./tutorials.py
  7 +#
  8 +# --------------------------------------------------------------------------
  9 +#
  10 +# Copyright (C) 2021 Juergen Knoedlseder
  11 +#
  12 +# This program is free software: you can redistribute it and/or modify
  13 +# it under the terms of the GNU General Public License as published by
  14 +# the Free Software Foundation, either version 3 of the License, or
  15 +# (at your option) any later version.
  16 +#
  17 +# This program is distributed in the hope that it will be useful,
  18 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20 +# GNU General Public License for more details.
  21 +#
  22 +# You should have received a copy of the GNU General Public License
  23 +# along with this program. If not, see <http://www.gnu.org/licenses/>.
  24 +#
  25 +# ==========================================================================
  26 +import os
  27 +import sys
  28 +import stat
  29 +import subprocess
  30 +import gammalib
  31 +import ctools
  32 +import cscripts
  33 +
  34 +
  35 +# ===================================== #
  36 +# Test class for tutorials verification #
  37 +# ===================================== #
  38 +class tutorials(gammalib.GPythonTestSuite):
  39 + """
  40 + Test class for tutorials verification
  41 + """
  42 + # Constructor
  43 + def __init__(self):
  44 + """
  45 + Constructor
  46 + """
  47 + # Call base class constructor
  48 + gammalib.GPythonTestSuite.__init__(self)
  49 +
  50 + # Initialise private members
  51 + self._rst_step = 0 # Step counter
  52 + self._rst_path = '' # Path where the tested RST file resides
  53 + self._cwd = '.' # Current working directory
  54 +
  55 + # Return
  56 + return
  57 +
  58 + # Clean pfiles directory
  59 + def _clean_pfiles(self):
  60 + """
  61 + Clean pfiles directory
  62 + """
  63 + # Remove all files from pfiles directory
  64 + os.system('rm -rf %s/*.par' % os.environ['PFILES'])
  65 +
  66 + # Return
  67 + return
  68 +
  69 + # Set result directory
  70 + def _set_result_dir(self, path):
  71 + """
  72 + Set result directory
  73 +
  74 + Parameters
  75 + ----------
  76 + path : str
  77 + Result directory path
  78 + """
  79 + # Set default working directory
  80 + os.chdir(self._cwd)
  81 +
  82 + # Create result directory
  83 + try:
  84 + os.makedirs(path)
  85 + except:
  86 + pass
  87 +
  88 + # Clear result directory
  89 + os.system('rm -rf %s/*' % path)
  90 +
  91 + # Step in result directory
  92 + os.chdir(path)
  93 +
  94 + # Return
  95 + return
  96 +
  97 + # Test command execution
  98 + def _test_execute_cmd(self, cmd, args):
  99 + """
  100 + Test command execution
  101 +
  102 + Tests the execution of a command. Currently supported commands are:
  103 + - cd
  104 + - mkdir
  105 + - nano
  106 + - ./xxxxxx (any command xxxxxx that resides in the directory of the RST file)
  107 +
  108 + Parameters
  109 + ----------
  110 + cmd : str
  111 + Command line
  112 + args : list of str
  113 + Additional lines following the command line
  114 + """
  115 + # Split command line
  116 + cmdline = cmd.split(' ')
  117 +
  118 + # Check command line
  119 + self.test_assert((len(cmdline) > 0), 'Test that command line is not empty.', cmd)
  120 +
  121 + # Continue only if valid
  122 + if len(cmdline) > 0:
  123 +
  124 + # Extract command
  125 + command = gammalib.strip_whitespace(cmdline[0])
  126 +
  127 + # Handle "mkdir" command
  128 + if command == 'mkdir':
  129 + self.test_value(len(cmdline), 2, 'Test number of arguments for "mkdir".')
  130 + self.test_value(len(args), 0, 'Test that no lines follow "mkdir".')
  131 + if len(cmdline) > 1:
  132 + dirname = gammalib.strip_whitespace(cmdline[1])
  133 + os.system('mkdir -p %s' % dirname)
  134 +
  135 + # Handle "cd" command
  136 + elif command == 'cd':
  137 + self.test_value(len(cmdline), 2, 'Test number of arguments for "cd".')
  138 + self.test_value(len(args), 0, 'Test that no lines follow "cd".')
  139 + if len(cmdline) > 1:
  140 + dirname = gammalib.strip_whitespace(cmdline[1])
  141 + os.chdir(dirname)
  142 +
  143 + # Handle "cp" command
  144 + elif command == 'cp':
  145 + self.test_value(len(cmdline), 3, 'Test number of arguments for "cp".')
  146 + self.test_value(len(args), 0, 'Test that no lines follow "cp".')
  147 + if len(cmdline) > 2:
  148 + src = gammalib.expand_env(gammalib.strip_whitespace(cmdline[1]))
  149 + dst = gammalib.expand_env(gammalib.strip_whitespace(cmdline[2]))
  150 + os.system('cp %s %s' % (src, dst))
  151 +
  152 + # Handle "nano" command
  153 + elif command == 'nano':
  154 + self.test_value(len(cmdline), 2, 'Test number of arguments for "nano".')
  155 + self.test_assert((len(args) > 0), 'Test that lines follow "nano".')
  156 + if len(cmdline) > 1:
  157 + fname = gammalib.strip_whitespace(cmdline[1])
  158 + f = open(fname, 'wb')
  159 + for arg in args:
  160 + f.write(arg)
  161 + f.close()
  162 +
  163 + # Handle script execution
  164 + elif command[0:2] == './':
  165 +
  166 + # Set script name. If the script does not exist in result
  167 + # directory then assume it exists in Sphinx rst directory
  168 + if os.path.isfile(command[2:]):
  169 + script = './%s' % (command[2:])
  170 + else:
  171 + script = '%s/%s' % (self._rst_path, command[2:])
  172 +
  173 + # Make sure that script is executable
  174 + mode = os.stat(script).st_mode
  175 + mode |= (mode & 0o444) >> 2
  176 + os.chmod(script, mode)
  177 +
  178 + # Build command line
  179 + plotname, _ = os.path.splitext(command[2:])
  180 + cmd = '%s -p %s.png' % (script, plotname)
  181 + self.test_assert((len(args) == 0), 'Test script "%s".' % command[2:])
  182 +
  183 + # Execute command, make sure we catch any exception
  184 + try:
  185 + rc = os.system(cmd+' > tutorials_test_output.dmp 2>&1')
  186 + except:
  187 + rc = -1
  188 +
  189 + # If an exception occured then put output on screen
  190 + msg = ''
  191 + if rc != 0:
  192 + f = open('tutorials_test_output.dmp', 'r')
  193 + for line in f:
  194 + msg += line
  195 + f.close()
  196 +
  197 + # Remove test output
  198 + os.remove('tutorials_test_output.dmp')
  199 +
  200 + # Set error flag and text
  201 + name = 'Test execution of "%s".' % command[2:]
  202 + self.test_value(rc, 0, name, msg)
  203 +
  204 + # Handle plotting scripts
  205 + elif command[0:7] == '$CTOOLS':
  206 +
  207 + # Build command line
  208 + script = gammalib.expand_env(cmdline[0])
  209 + filename = cmdline[1]
  210 + plotname, _ = os.path.splitext(filename)
  211 + cmd = '%s -p %s.png %s' % (script, plotname, filename)
  212 + self.test_assert((len(args) == 0), 'Test script "%s".' % command)
  213 +
  214 + # Execute command, make sure we catch any exception
  215 + try:
  216 + rc = os.system(cmd+' > tutorials_test_output.dmp 2>&1')
  217 + except:
  218 + rc = -1
  219 +
  220 + # If an exception occured then put output on screen
  221 + msg = ''
  222 + if rc != 0:
  223 + f = open('tutorials_test_output.dmp', 'r')
  224 + for line in f:
  225 + msg += line
  226 + f.close()
  227 +
  228 + # Remove test output
  229 + os.remove('tutorials_test_output.dmp')
  230 +
  231 + # Set error flag and text
  232 + name = 'Test execution of "%s".' % script
  233 + self.test_value(rc, 0, name, msg)
  234 +
  235 + # Handle unsupported Xspec commands
  236 + elif command[0:5] == 'xspec':
  237 + pass
  238 +
  239 + # Signal that the command was not known
  240 + else:
  241 + name = 'Test command "%s".' % command
  242 + msg = 'Unknown command "%s"' % command
  243 + self.test_assert(False, name, msg)
  244 +
  245 + # Return
  246 + return
  247 +
  248 + # Test line execution
  249 + def _test_line_execution(self, lines):
  250 + """
  251 + Test the execution of a sequence of commands
  252 +
  253 + Parameters
  254 + ----------
  255 + lines : list of str
  256 + Command lines
  257 + """
  258 + # Initialise commands and arguments
  259 + cmd = ''
  260 + args = ''
  261 +
  262 + # Loop over all lines
  263 + for line in lines:
  264 +
  265 + # If line starts with a string then extract or execute command
  266 + if line[0:2] == '$ ':
  267 +
  268 + # If we have a command then execute it
  269 + if cmd != '':
  270 + self._test_execute_cmd(cmd, args)
  271 +
  272 + # Set new command
  273 + cmd = line[2:]
  274 + args = ''
  275 +
  276 + # ... otherwise add argument
  277 + else:
  278 + args += '%s\n' % (gammalib.strip_whitespace(line))
  279 +
  280 + # If there is a pending command then execute it
  281 + if cmd != '':
  282 + self._test_execute_cmd(cmd, args)
  283 +
  284 + # Return
  285 + return
  286 +
  287 + # Test ctool or cscript execution
  288 + def _test_ctool_execution(self, tool, lines):
  289 + """
  290 + Test the execution of a ctool or cscript
  291 +
  292 + The methods test the execution of a ctool or cscript as executed from
  293 + the command line emulating the entering of the queried parameters. Any
  294 + error that occurs in the execution will be signaled and the Python
  295 + traceback will be put in the error message field.
  296 +
  297 + Parameters
  298 + ----------
  299 + tool : str
  300 + ctool name
  301 + lines : list of str
  302 + Command lines
  303 + """
  304 + # Increment step counter
  305 + self._rst_step += 1
  306 +
  307 + # Initialise arguments
  308 + args = ''
  309 +
  310 + # Set command
  311 + cmd = tool.split(' ')
  312 +
  313 + # Append lines
  314 + for line in lines:
  315 + pos = line.find(']')
  316 + if pos != -1:
  317 + arg = gammalib.strip_whitespace(line[pos+1:])
  318 + args += '%s\n' % arg
  319 +
  320 + # Create subprocess for tool
  321 + p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
  322 + stdin=subprocess.PIPE,
  323 + stderr=subprocess.PIPE)
  324 +
  325 + # Write command line parameters
  326 + p.stdin.write(b'%s' % args)
  327 +
  328 + # Get results
  329 + res = p.communicate()
  330 +
  331 + # Close pipeline
  332 + p.stdin.close()
  333 +
  334 + # Set error flag and message
  335 + if '*** ERROR' in res[0]:
  336 + success = False
  337 + msg = res[0]
  338 + elif len(res[1]) > 0:
  339 + success = False
  340 + msg = res[1]
  341 + else:
  342 + success = True
  343 + msg = ''
  344 + name = 'Test execution of "%s".' % tool
  345 + self.test_assert(success, name, msg)
  346 +
  347 + # Preprend step counter to logfile
  348 + logfile = gammalib.GFilename('%s.log' % (cmd[0]))
  349 + if logfile.exists():
  350 + src = logfile.url()
  351 + dst = '%2.2d_%s' % (self._rst_step, src)
  352 + os.system('mv %s %s' % (src, dst))
  353 +
  354 + # Return
  355 + return
  356 +
  357 + # Test workflow step
  358 + def _test_step(self, tool, lines):
  359 + """
  360 + Test workflow step
  361 +
  362 + Parameters
  363 + ----------
  364 + tool : str
  365 + Tool name
  366 + lines : list of str
  367 + Command lines
  368 + """
  369 + # If tool is a ctool or cscript then test ctool or cscript execution
  370 + if tool[0:2] == 'ct' or tool[0:2] == 'cs':
  371 + self._test_ctool_execution(tool, lines)
  372 +
  373 + # ... otherwise test line execution
  374 + else:
  375 + all_lines = ['$ %s' % tool]
  376 + all_lines.extend(lines)
  377 + self._test_line_execution(all_lines)
  378 +
  379 + # Return
  380 + return
  381 +
  382 + # Copy file
  383 + def _copy_file(self, filename):
  384 + """
  385 + Copy file from rst directory into working directory
  386 + """
  387 + # Set source filename
  388 + src = self._rst_path + '/' + filename
  389 +
  390 + # Copy file
  391 + os.system('cp %s %s' % (src, filename))
  392 +
  393 + # Return
  394 + return
  395 +
  396 + # Test Sphinx rst file
  397 + def _test_rst_file(self, filename):
  398 + """
  399 + Test Sphinx rst file
  400 +
  401 + Parameters
  402 + ----------
  403 + filename : str
  404 + Sphinx rst filename
  405 + """
  406 + # Set RST path
  407 + self._rst_path = os.path.abspath(os.path.dirname(filename))
  408 +
  409 + # Open RST file
  410 + f = open(filename, 'r')
  411 +
  412 + # Signal code block
  413 + code = False
  414 +
  415 + # Loop over lines
  416 + for line in f:
  417 +
  418 + # If we are not in a code block then check whether a code block
  419 + # starts
  420 + if not code:
  421 +
  422 + # Check for start of a code block
  423 + pos = line.find('code-block:: bash')
  424 + if pos != -1:
  425 + code = True
  426 + start = -1
  427 + tool = ''
  428 + lines = []
  429 + continue
  430 +
  431 + # ... otherwise check for literalinclude, and if found, copy
  432 + # relevant file
  433 + pos = line.find('literalinclude::')
  434 + if pos != -1:
  435 + filename = gammalib.strip_whitespace(line[pos+16:-1])
  436 + self._copy_file(filename)
  437 + continue
  438 +
  439 + # ... otherwise
  440 + else:
  441 +
  442 + # If we have no tool name then find tool name
  443 + if tool == '':
  444 + pos = line.find(' $ ')
  445 + if pos != -1:
  446 + start = pos+1
  447 + tool = line[pos+3:-1]
  448 + continue
  449 +
  450 + # ... otherwise append lines or test step
  451 + else:
  452 + blank = gammalib.strip_whitespace(line[0:start])
  453 + cmd = line[start:-1]
  454 + if len(blank) == 0 and cmd[0] != ' ':
  455 + lines.append(cmd)
  456 + continue
  457 + else:
  458 + self._test_step(tool, lines)
  459 + code = False
  460 + continue
  461 +
  462 + # Test step if some code is pending
  463 + if code:
  464 + self._test_step(tool, lines)
  465 +
  466 + # Return
  467 + return
  468 +
  469 + # Set test functions
  470 + def set(self):
  471 + """
  472 + Set all test functions
  473 + """
  474 + # Set current working directory
  475 + self._cwd = os.path.abspath(os.getcwd())
  476 +
  477 + # Set test name
  478 + self.name('Tutorials Verification')
  479 +
  480 + # Append tutorials
  481 + self.append(self.tutorials_quickstart, 'Test quickstart tutorial')
  482 + self.append(self.tutorials_howto, 'Test howto tutorial')
  483 + self.append(self.tutorials_1dc, 'Test 1DC tutorial')
  484 +
  485 + # Return
  486 + return
  487 +
  488 + # Test quickstart tutorials
  489 + def tutorials_quickstart(self):
  490 + """
  491 + Test quickstart tutorials
  492 + """
  493 + # Set Sphinx rst file path
  494 + os.chdir(self._cwd)
  495 + path = os.path.abspath('../doc/source/users/tutorials/quickstart')
  496 +
  497 + # Set result directory
  498 + self._set_result_dir('tutorials/quickstart')
  499 +
  500 + # Clean pfiles
  501 + self._clean_pfiles()
  502 +
  503 + # Initialise step counter
  504 + self._rst_step = 0
  505 +
  506 + # Test Sphinx rst files
  507 + self._test_rst_file('%s/simulating.rst' % path)
  508 + self._test_rst_file('%s/selecting.rst' % path)
  509 + self._test_rst_file('%s/skymap.rst' % path)
  510 + self._test_rst_file('%s/binning.rst' % path)
  511 + self._test_rst_file('%s/response.rst' % path)
  512 + self._test_rst_file('%s/fitting.rst' % path)
  513 + self._test_rst_file('%s/residual_map.rst' % path)
  514 + self._test_rst_file('%s/residual_spectrum.rst' % path)
  515 + self._test_rst_file('%s/butterfly.rst' % path)
  516 + self._test_rst_file('%s/spectrum.rst' % path)
  517 + self._test_rst_file('%s/unbinned.rst' % path)
  518 + self._test_rst_file('%s/energy_dispersion.rst' % path)
  519 + self._test_rst_file('%s/onoff.rst' % path)
  520 +
  521 + # Reset working directory
  522 + os.chdir(self._cwd)
  523 +
  524 + # Return
  525 + return
  526 +
  527 + # Test 1DC tutorials
  528 + def tutorials_1dc(self):
  529 + """
  530 + Test 1DC tutorials
  531 + """
  532 + # Continue only if CTADATA1DC environment variable is set
  533 + if 'CTADATA1DC' in os.environ:
  534 +
  535 + # Set environment variables
  536 + os.environ['CTADATA'] = os.environ['CTADATA1DC']
  537 + os.environ['CALDB'] = os.environ['CTADATA1DC']+'/caldb'
  538 +
  539 + # Set Sphinx rst file paths
  540 + os.chdir(self._cwd)
  541 + path_1dc = os.path.abspath('../doc/source/users/tutorials/1dc')
  542 + path_howto = os.path.abspath('../doc/source/users/tutorials/howto')
  543 +
  544 + # Set result directory
  545 + self._set_result_dir('tutorials/1dc')
  546 +
  547 + # Clean pfiles
  548 + self._clean_pfiles()
  549 +
  550 + # Initialise step counter
  551 + self._rst_step = 0
  552 +
  553 + # Test Sphinx rst files
  554 + self._test_rst_file('%s/first_select_obs.rst' % path_1dc)
  555 + self._test_rst_file('%s/first_select_events.rst' % path_1dc)
  556 + self._test_rst_file('%s/first_skymap.rst' % path_1dc)
  557 + self._test_rst_file('%s/first_detect.rst' % path_1dc)
  558 + self._test_rst_file('%s/first_stacked.rst' % path_1dc)
  559 + self._test_rst_file('%s/first_fitting.rst' % path_1dc)
  560 + self._test_rst_file('%s/first_improving.rst' % path_1dc)
  561 + self._test_rst_file('%s/first_unbinned.rst' % path_1dc)
  562 +
  563 + # Test Sphinx rst files
  564 + self._test_rst_file('%s/howto_ts.rst' % path_howto)
  565 + self._test_rst_file('%s/howto_tsmap.rst' % path_howto)
  566 + self._test_rst_file('%s/howto_extent.rst' % path_howto)
  567 + self._test_rst_file('%s/howto_ulimit.rst' % path_howto)
  568 + self._test_rst_file('%s/howto_lightcurve.rst' % path_howto)
  569 + self._test_rst_file('%s/howto_phasecurve.rst' % path_howto)
  570 + self._test_rst_file('%s/howto_exclude.rst' % path_howto)
  571 +
  572 + # Reset working directory
  573 + os.chdir(self._cwd)
  574 +
  575 + # Clean pfiles
  576 + self._clean_pfiles()
  577 +
  578 + # Initialise step counter
  579 + self._rst_step = 0
  580 +
  581 + # Test Sphinx rst file for On/Off analysis
  582 + self._test_rst_file('%s/first_onoff.rst' % path_1dc)
  583 +
  584 + # Reset working directory
  585 + os.chdir(self._cwd)
  586 +
  587 + # Return
  588 + return
  589 +
  590 + # Test howto tutorials
  591 + def tutorials_howto(self):
  592 + """
  593 + Test howto tutorials
  594 + """
  595 + # Set Sphinx rst file path
  596 + os.chdir(self._cwd)
  597 + path = os.path.abspath('../doc/source/users/tutorials/howto')
  598 +
  599 + # Set result directory
  600 + self._set_result_dir('tutorials/howto')
  601 +
  602 + # Initialise step counter
  603 + self._rst_step = 0
  604 +
  605 + # Test Sphinx rst files
  606 + self._clean_pfiles()
  607 + self._test_rst_file('%s/howto_connect_irfs.rst' % path)
  608 + self._clean_pfiles()
  609 + self._test_rst_file('%s/howto_xspec.rst' % path)
  610 +
  611 + # Reset working directory
  612 + os.chdir(self._cwd)
  613 +
  614 + # Return
  615 + return
  616 +
  617 +
  618 +
  619 +# ======================== #
  620 +# Main routine entry point #
  621 +# ======================== #
  622 +if __name__ == '__main__':
  623 +
  624 + # Allocate test suite container
  625 + suites = gammalib.GTestSuites('ctools tutorials verification')
  626 +
  627 + # Allocate test suite and append it to the container
  628 + suite_tutorials = tutorials()
  629 +
  630 + # Setup test suit
  631 + suite_tutorials.set()
  632 +
  633 + # Append test suite to container
  634 + suites.append(suite_tutorials)
  635 +
  636 + # Create tutorials/pfiles directory
  637 + try:
  638 + os.makedirs('tutorials/pfiles')
  639 + except:
  640 + pass
  641 +
  642 + # Set PFILES environment variable
  643 + os.environ['PFILES'] = os.path.abspath('tutorials/pfiles')
  644 +
  645 + # Get current working directory
  646 + cwd = os.getcwd()
  647 +
  648 + # Run test suite
  649 + success = suites.run()
  650 +
  651 + # Reset working directory
  652 + os.chdir(cwd)
  653 +
  654 + # Save test results
  655 + suites.save('reports/tutorials.xml')
  656 +
  657 + # Set return code
  658 + if success:
  659 + rc = 0
  660 + else:
  661 + rc = 1
  662 +
  663 + # Exit with return code
  664 + sys.exit(rc)