Commit 6205af2a12232cf79fc6ef3b314ab4b4c0a0b384
1 parent
e1129812
Add Sphinx tutorials test script (#3510)
The current script covers all 1DC tutorials.
Showing
12 changed files
with
398 additions
and
149 deletions
.gitignore
ChangeLog
Makefile.am
| 1 | 1 | ############################################################################# |
| 2 | 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 | 7 | # This program is free software: you can redistribute it and/or modify # |
| ... | ... | @@ -211,13 +211,23 @@ valgrind: |
| 211 | 211 | # Add science verification rule |
| 212 | 212 | science-verification: |
| 213 | 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 | 217 | else \ |
| 218 | 218 | echo "science_verification.py not found in test."; \ |
| 219 | 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 | 231 | # Add Sphinx rule |
| 222 | 232 | sphinx: |
| 223 | 233 | @if type sphinx-build >/dev/null 2>&1; then \ | ... | ... |
NEWS
| 1 | 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 | 6 | Introduction |
| ... | ... | @@ -16,7 +16,8 @@ None |
| 16 | 16 | |
| 17 | 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 | 23 | Python interface | ... | ... |
README.md
| 1 | 1 | ctools information |
| 2 | 2 | ================== |
| 3 | -* Version: 2.0.0.dev (3 December 2020) | |
| 3 | +* Version: 2.0.0.dev (3 February 2021) | |
| 4 | 4 | * GammaLib dependency: 2.0.0.dev |
| 5 | 5 | |
| 6 | 6 | [](https://cta-jenkins.irap.omp.eu/job/ctools-integrate-os/) | ... | ... |
cscripts/csspec.py
| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # ========================================================================== |
| 3 | 3 | # Generates a spectrum. |
| 4 | 4 | # |
| 5 | -# Copyright (C) 2014-2020 Michael Mayer | |
| 5 | +# Copyright (C) 2014-2021 Michael Mayer | |
| 6 | 6 | # |
| 7 | 7 | # This program is free software: you can redistribute it and/or modify |
| 8 | 8 | # it under the terms of the GNU General Public License as published by |
| ... | ... | @@ -1071,7 +1071,7 @@ class csspec(ctools.csobservation): |
| 1071 | 1071 | energy_high = gammalib.GFitsTableDoubleCol('e_max', nrows) |
| 1072 | 1072 | norm = gammalib.GFitsTableDoubleCol('norm', nrows) |
| 1073 | 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 | 1075 | e2dnde = gammalib.GFitsTableDoubleCol('ref_e2dnde', nrows) |
| 1076 | 1076 | dnde = gammalib.GFitsTableDoubleCol('ref_dnde', nrows) |
| 1077 | 1077 | Npred_values = gammalib.GFitsTableDoubleCol('ref_npred', nrows) |
| ... | ... | @@ -1084,7 +1084,7 @@ class csspec(ctools.csobservation): |
| 1084 | 1084 | energy_high.unit('TeV') |
| 1085 | 1085 | norm.unit('') |
| 1086 | 1086 | norm_err.unit('') |
| 1087 | - ulim_values.unit('') | |
| 1087 | + norm_ul.unit('') | |
| 1088 | 1088 | e2dnde.unit('erg/cm2/s') |
| 1089 | 1089 | dnde.unit('counts/MeV/cm2/s') |
| 1090 | 1090 | Npred_values.unit('counts') |
| ... | ... | @@ -1098,8 +1098,12 @@ class csspec(ctools.csobservation): |
| 1098 | 1098 | energy_low[i] = result['energy_low'] |
| 1099 | 1099 | energy_high[i] = result['energy_high'] |
| 1100 | 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 | 1107 | e2dnde[i] = result['e2dnde'] |
| 1104 | 1108 | dnde[i] = result['flux'] |
| 1105 | 1109 | Npred_values[i] = result['Npred'] |
| ... | ... | @@ -1109,7 +1113,10 @@ class csspec(ctools.csobservation): |
| 1109 | 1113 | # Add likelihood scan values |
| 1110 | 1114 | for fbin in range(ncols): |
| 1111 | 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 | 1121 | # Initialise FITS Table with extension "SPECTRUM" |
| 1115 | 1122 | table = gammalib.GFitsBinTable(nrows) |
| ... | ... | @@ -1125,7 +1132,7 @@ class csspec(ctools.csobservation): |
| 1125 | 1132 | table.append(energy_high) |
| 1126 | 1133 | table.append(norm) |
| 1127 | 1134 | table.append(norm_err) |
| 1128 | - table.append(ulim_values) | |
| 1135 | + table.append(norm_ul) | |
| 1129 | 1136 | table.append(e2dnde) |
| 1130 | 1137 | table.append(dnde) |
| 1131 | 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 | 39 | Input model definition XML file [$CTOOLS/share/models/crab.xml] bkgcube.xml |
| 40 | 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 | 43 | and will write the results into an updated |
| 44 | 44 | :ref:`model definition file <glossary_moddef>` |
| 45 | 45 | containing the fitted model parameters and their statistical uncertainties. |
| ... | ... | @@ -124,7 +124,7 @@ You create the butterfly diagram for ``Src001`` using |
| 124 | 124 | Stop value for last energy bin in TeV [100.0] |
| 125 | 125 | Output ASCII file [butterfly.txt] butterfly_src001.txt |
| 126 | 126 | |
| 127 | -and for `Src003`` using | |
| 127 | +and for ``Src003`` using | |
| 128 | 128 | |
| 129 | 129 | .. code-block:: bash |
| 130 | 130 | |
| ... | ... | @@ -192,28 +192,14 @@ a maximum likelihood model fit. |
| 192 | 192 | |
| 193 | 193 | Obviously, ``Src001`` has a spectral cut-off (red flux points) and hence is not |
| 194 | 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 | 204 | Fitting this model to the data improves the fit and the resulting butterfly |
| 219 | 205 | diagram follows now reasonably well the spectral points: | ... | ... |
doc/source/users/tutorials/1dc/first_onoff.rst
| ... | ... | @@ -208,6 +208,7 @@ follows: |
| 208 | 208 | Output observation definition XML file [onoff_obs.xml] |
| 209 | 209 | Output model definition XML file [onoff_model.xml] |
| 210 | 210 | Method for background estimation (REFLECTED|CUSTOM) [REFLECTED] |
| 211 | + Shape of the source region (CIRCLE|RECT) [CIRCLE] | |
| 211 | 212 | Coordinate system (CEL - celestial, GAL - galactic) (CEL|GAL) [CEL] |
| 212 | 213 | Right Ascension of source region centre (deg) (0-360) [83.63] 350.85 |
| 213 | 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 | 356 | provided as input model to :ref:`csphagen`. Here an example for an |
| 356 | 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 | 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 | 375 | Output observation definition XML file [onoff_obs.xml] onoff_obs_cstat.xml |
| 396 | 376 | Output model definition XML file [onoff_model.xml] onoff_model_cstat.xml |
| 397 | 377 | Method for background estimation (REFLECTED|CUSTOM) [REFLECTED] |
| 378 | + Shape of the source region (CIRCLE|RECT) [CIRCLE] | |
| 398 | 379 | Coordinate system (CEL - celestial, GAL - galactic) (CEL|GAL) [CEL] |
| 399 | 380 | Right Ascension of source region centre (deg) (0-360) [350.85] |
| 400 | 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 | 433 | |
| 453 | 434 | $ ctbutterfly |
| 454 | 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 | 437 | Input model definition XML file [$CTOOLS/share/models/crab.xml] CasA_results.xml |
| 457 | 438 | Lower energy limit (TeV) [0.1] |
| 458 | 439 | Upper energy limit (TeV) [100.0] 50.0 |
| ... | ... | @@ -465,7 +446,7 @@ and the SED by typing |
| 465 | 446 | $ csspec |
| 466 | 447 | Input event list, counts cube, or observation definition XML file [events.fits] onoff_obs.xml |
| 467 | 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 | 450 | Spectrum generation method (SLICE|NODES|AUTO) [AUTO] |
| 470 | 451 | Binning algorithm (FILE|LIN|LOG|POW) [LOG] |
| 471 | 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 | 2 | # ========================================================================== |
| 3 | 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 | 7 | # This program is free software: you can redistribute it and/or modify |
| 8 | 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='o', color='red'): |
| 51 | 51 | # Read spectrum file |
| 52 | 52 | fits = gammalib.GFits(specfile) |
| 53 | 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 | 63 | # Read butterfly file |
| 63 | 64 | csv = gammalib.GCsv(butterfile) |
| ... | ... | @@ -83,22 +84,23 @@ def plot_spectrum_butterfly(specfile, butterfile, fmt='o', color='red'): |
| 83 | 84 | |
| 84 | 85 | # Get Test Statistic, flux and flux error |
| 85 | 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 | 91 | # If Test Statistic is larger than 9 and flux error is smaller than |
| 90 | 92 | # flux then append flux plots ... |
| 91 | 93 | if ts > 9.0 and e_flx < flx: |
| 92 | 94 | energies.append(c_energy.real(row)) |
| 93 | - flux.append(c_flux.real(row)) | |
| 95 | + flux.append(flx) | |
| 94 | 96 | ed_engs.append(c_ed.real(row)) |
| 95 | 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 | 100 | # ... otherwise append upper limit |
| 99 | 101 | else: |
| 100 | 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 | 104 | ul_ed_engs.append(c_ed.real(row)) |
| 103 | 105 | ul_eu_engs.append(c_eu.real(row)) |
| 104 | 106 | ... | ... |
test/tutorials.py
| ... | ... | @@ -46,47 +46,128 @@ class tutorials(gammalib.GPythonTestSuite): |
| 46 | 46 | # Call base class constructor |
| 47 | 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 | 53 | # Return |
| 53 | 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 | 64 | # Return |
| 67 | 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 | 172 | # Return |
| 92 | 173 | return |
| ... | ... | @@ -113,8 +194,7 @@ class tutorials(gammalib.GPythonTestSuite): |
| 113 | 194 | |
| 114 | 195 | # If we have a command then execute it |
| 115 | 196 | if cmd != '': |
| 116 | - print(cmd, args) | |
| 117 | - self._execute_cmd(cmd, args) | |
| 197 | + self._test_execute_cmd(cmd, args) | |
| 118 | 198 | |
| 119 | 199 | # Set new command |
| 120 | 200 | cmd = line[2:] |
| ... | ... | @@ -126,8 +206,7 @@ class tutorials(gammalib.GPythonTestSuite): |
| 126 | 206 | |
| 127 | 207 | # If there is a pending command then execute it |
| 128 | 208 | if cmd != '': |
| 129 | - print(cmd, args) | |
| 130 | - self._execute_cmd(cmd, args) | |
| 209 | + self._test_execute_cmd(cmd, args) | |
| 131 | 210 | |
| 132 | 211 | # Return |
| 133 | 212 | return |
| ... | ... | @@ -149,23 +228,32 @@ class tutorials(gammalib.GPythonTestSuite): |
| 149 | 228 | lines : list of str |
| 150 | 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 | 240 | # Append lines |
| 156 | 241 | for line in lines: |
| 157 | 242 | pos = line.find(']') |
| 158 | 243 | if pos != -1: |
| 159 | 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 | 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 | 255 | # Write command line parameters |
| 168 | - p.stdin.write(b'%s' % cmd) | |
| 256 | + p.stdin.write(b'%s' % args) | |
| 169 | 257 | |
| 170 | 258 | # Get results |
| 171 | 259 | res = p.communicate() |
| ... | ... | @@ -177,13 +265,20 @@ class tutorials(gammalib.GPythonTestSuite): |
| 177 | 265 | name = 'Test execution of %s.' % tool |
| 178 | 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 | 275 | # Return |
| 181 | 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 | 283 | Parameters |
| 189 | 284 | ---------- |
| ... | ... | @@ -191,18 +286,12 @@ class tutorials(gammalib.GPythonTestSuite): |
| 191 | 286 | Tool name |
| 192 | 287 | lines : list of str |
| 193 | 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 | 291 | if tool[0:2] == 'ct' or tool[0:2] == 'cs': |
| 203 | 292 | self._test_ctool_execution(tool, lines) |
| 204 | 293 | |
| 205 | - # ... otherwise execute lines | |
| 294 | + # ... otherwise test line execution | |
| 206 | 295 | else: |
| 207 | 296 | all_lines = ['$ %s' % tool] |
| 208 | 297 | all_lines.extend(lines) |
| ... | ... | @@ -211,21 +300,33 @@ class tutorials(gammalib.GPythonTestSuite): |
| 211 | 300 | # Return |
| 212 | 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 | 322 | Parameters |
| 220 | 323 | ---------- |
| 221 | 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 | 330 | # Open RST file |
| 230 | 331 | f = open(filename, 'r') |
| 231 | 332 | |
| ... | ... | @@ -238,6 +339,8 @@ class tutorials(gammalib.GPythonTestSuite): |
| 238 | 339 | # If we are not in a code block then check whether a code block |
| 239 | 340 | # starts |
| 240 | 341 | if not code: |
| 342 | + | |
| 343 | + # Check for start of a code block | |
| 241 | 344 | pos = line.find('code-block:: bash') |
| 242 | 345 | if pos != -1: |
| 243 | 346 | code = True |
| ... | ... | @@ -246,6 +349,14 @@ class tutorials(gammalib.GPythonTestSuite): |
| 246 | 349 | lines = [] |
| 247 | 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 | 360 | # ... otherwise |
| 250 | 361 | else: |
| 251 | 362 | |
| ... | ... | @@ -257,7 +368,7 @@ class tutorials(gammalib.GPythonTestSuite): |
| 257 | 368 | tool = line[pos+3:-1] |
| 258 | 369 | continue |
| 259 | 370 | |
| 260 | - # ... otherwise append lines or add workflow step | |
| 371 | + # ... otherwise append lines or test step | |
| 261 | 372 | else: |
| 262 | 373 | blank = gammalib.strip_whitespace(line[0:start]) |
| 263 | 374 | cmd = line[start:-1] |
| ... | ... | @@ -265,13 +376,27 @@ class tutorials(gammalib.GPythonTestSuite): |
| 265 | 376 | lines.append(cmd) |
| 266 | 377 | continue |
| 267 | 378 | else: |
| 268 | - self._add_workflow_step(tool, lines) | |
| 379 | + self._test_step(tool, lines) | |
| 269 | 380 | code = False |
| 270 | 381 | continue |
| 271 | 382 | |
| 272 | - # Add step if some code is pending | |
| 383 | + # Test step if some code is pending | |
| 273 | 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 | 401 | # Return |
| 277 | 402 | return |
| ... | ... | @@ -281,15 +406,49 @@ class tutorials(gammalib.GPythonTestSuite): |
| 281 | 406 | """ |
| 282 | 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 | 453 | # Return |
| 295 | 454 | return |
| ... | ... | @@ -318,15 +477,18 @@ if __name__ == '__main__': |
| 318 | 477 | except: |
| 319 | 478 | pass |
| 320 | 479 | |
| 321 | - # Copy ctools parameter files into pfiles directory | |
| 322 | - os.system('cp -r ../src/*/*.par pfiles/') | |
| 323 | - | |
| 324 | 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 | 486 | # Run test suite |
| 328 | 487 | success = suites.run() |
| 329 | 488 | |
| 489 | + # Reset working directory | |
| 490 | + os.chdir(cwd) | |
| 491 | + | |
| 330 | 492 | # Save test results |
| 331 | 493 | suites.save('reports/tutorials.xml') |
| 332 | 494 | ... | ... |