Commit eac7d1c21bc2c55bca923523f99ea4486abb62c1

Authored by Jürgen Knödlseder
2 parents 96ec743c 337b228b

Merge branch '1290-SpecpointsAndTS' into integration

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
... ...