Commit eac7d1c21bc2c55bca923523f99ea4486abb62c1
Merge branch '1290-SpecpointsAndTS' into integration
Showing
2 changed files
with
215 additions
and
1 deletions
examples/make_spectrum.py
0 → 100755
| 1 | +#! /usr/bin/env python | |
| 2 | +# ========================================================================== | |
| 3 | +# This script shows how to make a spectrum using obsutils. | |
| 4 | +# | |
| 5 | +# Copyright (C) 2014 Juergen Knoedlseder | |
| 6 | +# | |
| 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 | |
| 9 | +# the Free Software Foundation, either version 3 of the License, or | |
| 10 | +# (at your option) any later version. | |
| 11 | +# | |
| 12 | +# This program is distributed in the hope that it will be useful, | |
| 13 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 15 | +# GNU General Public License for more details. | |
| 16 | +# | |
| 17 | +# You should have received a copy of the GNU General Public License | |
| 18 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 19 | +# | |
| 20 | +# ========================================================================== | |
| 21 | +import gammalib | |
| 22 | +import ctools | |
| 23 | +try: | |
| 24 | + import matplotlib.pyplot as plt | |
| 25 | + has_matplotlib = True | |
| 26 | +except: | |
| 27 | + has_matplotlib = False | |
| 28 | + | |
| 29 | + | |
| 30 | +# =============== # | |
| 31 | +# Make a spectrum # | |
| 32 | +# =============== # | |
| 33 | +def make_spectrum(): | |
| 34 | + """ | |
| 35 | + """ | |
| 36 | + # Set script parameters | |
| 37 | + model_name = "${CTOOLS}/share/models/crab.xml" | |
| 38 | + caldb = "dummy" | |
| 39 | + irf = "cta_dummy_irf" | |
| 40 | + ra = 83.63 | |
| 41 | + dec = 22.01 | |
| 42 | + rad_sim = 3.0 | |
| 43 | + tstart = 0.0 | |
| 44 | + tstop = 1800.0 | |
| 45 | + emin = 0.1 | |
| 46 | + emax = 100.0 | |
| 47 | + | |
| 48 | + # Simulate events | |
| 49 | + sim = ctools.ctobssim() | |
| 50 | + sim["infile"].filename(model_name) | |
| 51 | + sim["caldb"].string(caldb) | |
| 52 | + sim["irf"].string(irf) | |
| 53 | + sim["ra"].real(ra) | |
| 54 | + sim["dec"].real(dec) | |
| 55 | + sim["rad"].real(rad_sim) | |
| 56 | + sim["tmin"].real(tstart) | |
| 57 | + sim["tmax"].real(tstop) | |
| 58 | + sim["emin"].real(emin) | |
| 59 | + sim["emax"].real(emax) | |
| 60 | + sim.run() | |
| 61 | + | |
| 62 | + # Generate an energy binning | |
| 63 | + e_min = gammalib.GEnergy(emin, "TeV") | |
| 64 | + e_max = gammalib.GEnergy(emax, "TeV") | |
| 65 | + ebounds = gammalib.GEbounds(10, e_min, e_max) | |
| 66 | + | |
| 67 | + # Generate spectral points | |
| 68 | + spectrum = ctools.obsutils.spectrum(sim.obs(), "Crab", ebounds) | |
| 69 | + | |
| 70 | + # Return spectrum | |
| 71 | + return spectrum | |
| 72 | + | |
| 73 | + | |
| 74 | +# ============= # | |
| 75 | +# Plot spectrum # | |
| 76 | +# ============= # | |
| 77 | +def plot_spectrum(spectrum): | |
| 78 | + """ | |
| 79 | + Plot spectrum. | |
| 80 | + """ | |
| 81 | + # Create figure | |
| 82 | + plt.figure(1) | |
| 83 | + plt.title("Crab spectrum") | |
| 84 | + | |
| 85 | + # Plot spectrum | |
| 86 | + plt.loglog(spectrum['energy']['value'], \ | |
| 87 | + spectrum['flux']['value'], 'ro', label='Crab') | |
| 88 | + plt.errorbar(spectrum['energy']['value'], \ | |
| 89 | + spectrum['flux']['value'], \ | |
| 90 | + spectrum['flux']['ed_value'], fmt=None, ecolor='r') | |
| 91 | + | |
| 92 | + # Put labels | |
| 93 | + plt.xlabel("Energy ("+spectrum['energy']['unit']+")") | |
| 94 | + plt.ylabel("Flux ("+spectrum['flux']['unit']+")") | |
| 95 | + plt.legend(loc="lower left") | |
| 96 | + | |
| 97 | + # Show spectrum | |
| 98 | + plt.show() | |
| 99 | + | |
| 100 | + # Return | |
| 101 | + return | |
| 102 | + | |
| 103 | + | |
| 104 | +#==========================# | |
| 105 | +# Main routine entry point # | |
| 106 | +#==========================# | |
| 107 | +if __name__ == '__main__': | |
| 108 | + """ | |
| 109 | + Generate a Crab spectrum. | |
| 110 | + """ | |
| 111 | + # Generate spectrum | |
| 112 | + spectrum = make_spectrum() | |
| 113 | + | |
| 114 | + # Plot spectrum | |
| 115 | + if has_matplotlib: | |
| 116 | + plot_spectrum(spectrum) | |
| 117 | + | |
| 0 | 118 | \ No newline at end of file | ... | ... |
pyext/ctools/obsutils.py
| ... | ... | @@ -20,6 +20,7 @@ |
| 20 | 20 | # ========================================================================== |
| 21 | 21 | import ctools |
| 22 | 22 | import gammalib |
| 23 | +import math | |
| 23 | 24 | |
| 24 | 25 | |
| 25 | 26 | # ===================== # |
| ... | ... | @@ -124,7 +125,7 @@ def sim(obs, log=False, debug=False, edisp=False, seed=0, nbins=0, |
| 124 | 125 | # ================ # |
| 125 | 126 | # Fit observations # |
| 126 | 127 | # ================ # |
| 127 | -def fit(obs, log=False, debug=False, edisp=False): | |
| 128 | +def fit(obs, log=False, debug=False, edisp=False, tscalc=False): | |
| 128 | 129 | """ |
| 129 | 130 | Perform maximum likelihood fitting of observations in the container. |
| 130 | 131 | |
| ... | ... | @@ -145,9 +146,14 @@ def fit(obs, log=False, debug=False, edisp=False): |
| 145 | 146 | # Optionally switch-on debugging model |
| 146 | 147 | if debug: |
| 147 | 148 | like["debug"].boolean(True) |
| 149 | + | |
| 150 | + # Optionally turn on TS calculation | |
| 151 | + if tscalc: | |
| 152 | + like["tscalc"].boolean(True) | |
| 148 | 153 | |
| 149 | 154 | # Optionally apply energy dispersion |
| 150 | 155 | like["edisp"].boolean(edisp) |
| 156 | + like["edisp"].boolean(edisp) | |
| 151 | 157 | |
| 152 | 158 | # Run ctlike application. |
| 153 | 159 | like.run() |
| ... | ... | @@ -516,3 +522,94 @@ def set_obs_patterns(pattern, ra=83.6331, dec=22.0145, offset=1.5): |
| 516 | 522 | |
| 517 | 523 | # Return observation definition list |
| 518 | 524 | return obsdeflist |
| 525 | + | |
| 526 | + | |
| 527 | +# ================================================================= # | |
| 528 | +# Generate a spectrum by fitting an observation in energy intervals # | |
| 529 | +# ================================================================= # | |
| 530 | +def spectrum(obs, source, ebounds): | |
| 531 | + """ | |
| 532 | + Returns spectral points in the given binning for the passed observations | |
| 533 | + and source. | |
| 534 | + | |
| 535 | + Please note that specpoints can make spectra for any given spectral | |
| 536 | + model, as long as it has a "Prefactor" or "Integral" parameter which | |
| 537 | + scales the function | |
| 538 | + | |
| 539 | + Parameters: | |
| 540 | + obs - Observation container | |
| 541 | + source - Source name for which spectrum should be computed | |
| 542 | + ebounds - GEbounds energy boundaries | |
| 543 | + Keywords: | |
| 544 | + None | |
| 545 | + """ | |
| 546 | + # Check if parameters Prefactor or Integral exist to scale mdoel | |
| 547 | + normpar = "Prefactor" | |
| 548 | + srcmodel = obs.models()[source] | |
| 549 | + if not srcmodel.has_par(normpar): | |
| 550 | + if srcmodel.has_par("Integral"): | |
| 551 | + normpar = "Integral" | |
| 552 | + else: | |
| 553 | + print("Error: your spectral model of "+source+"does not"+\ | |
| 554 | + "have a scaling parameter named 'Prefactor'"+\ | |
| 555 | + " or 'Integral'") | |
| 556 | + return | |
| 557 | + | |
| 558 | + # Fix all parameters except prefactor | |
| 559 | + opt_spectral = srcmodel.spectral() | |
| 560 | + for model in obs.models(): | |
| 561 | + for par in range(model.size()): | |
| 562 | + model[par].fix() | |
| 563 | + opt_spectral[normpar].free() | |
| 564 | + | |
| 565 | + # Define spectrum dictionary, units are in format readable by astropy | |
| 566 | + spec = {"energy":{"value":[],"eu_value":[],"ed_value":[],"unit":"none"}, | |
| 567 | + "flux" :{"value":[],"eu_value":[],"ed_value":[],"unit":"none"}, | |
| 568 | + "TS" :{"value":[],"eu_value":[],"ed_value":[],"unit":"none"}} | |
| 569 | + | |
| 570 | + # Loop over energy bins, fit and write result to spectrum | |
| 571 | + for i in range(len(ebounds)): | |
| 572 | + | |
| 573 | + # Get logarithmic bin center and flux value of all energy fit | |
| 574 | + ecenter = ebounds.elogmean(i) | |
| 575 | + allflux = opt_spectral.eval(ecenter, gammalib.GTime(0.0)) | |
| 576 | + | |
| 577 | + # Clone observations and reset energy thresholds | |
| 578 | + select = ctools.ctselect(obs) | |
| 579 | + select["ra"].real(-1.0) | |
| 580 | + select["dec"].real(-1.0) | |
| 581 | + select["rad"].real(-1.0) | |
| 582 | + select["tmin"].real(0.0) | |
| 583 | + select["tmax"].real(0.0) | |
| 584 | + select["emin"].real(ebounds.emin(i).TeV()) | |
| 585 | + select["emax"].real(ebounds.emax(i).TeV()) | |
| 586 | + select.run() | |
| 587 | + | |
| 588 | + # Refit and write out to spectrum | |
| 589 | + binlike = fit(select.obs(), log=False, debug=False, edisp=False, tscalc=True) | |
| 590 | + binopt_spectral = binlike.obs().models()[source].spectral() | |
| 591 | + binflux = binopt_spectral.eval(ecenter, gammalib.GTime(0.0)) | |
| 592 | + if binopt_spectral[normpar].value() > 0.0: | |
| 593 | + relerr = binopt_spectral[normpar].error()/binopt_spectral[normpar].value() | |
| 594 | + else: | |
| 595 | + relerr = 0.0 | |
| 596 | + | |
| 597 | + # Store and convert to TeV from MeV | |
| 598 | + spec["energy"]["value"].append(ecenter.TeV()) | |
| 599 | + spec["energy"]["ed_value"].append(ecenter.TeV()-ebounds.emin(i).TeV()) | |
| 600 | + spec["energy"]["eu_value"].append(ebounds.emax(i).TeV()-ecenter.TeV()) | |
| 601 | + spec["energy"]["unit"] = "TeV" | |
| 602 | + | |
| 603 | + spec["flux"]["value"].append(binflux*1.0e6) | |
| 604 | + spec["flux"]["ed_value"].append(relerr*binflux*1.0e6) | |
| 605 | + spec["flux"]["eu_value"].append(relerr*binflux*1.0e6) | |
| 606 | + spec["flux"]["unit"] = "ph/cm2/s/TeV" | |
| 607 | + | |
| 608 | + spec["TS"]["value"].append(binlike.obs().models()[source].ts()) | |
| 609 | + | |
| 610 | + # Debugging??? | |
| 611 | + #print(spec["energy"]["value"]) | |
| 612 | + #print(spec["flux"]["value"]) | |
| 613 | + | |
| 614 | + # Return spectrum | |
| 615 | + return spec | ... | ... |