Commit 337b228b2362edceadfabfe37c36710d33af4ce4

Authored by Jürgen Knödlseder
1 parent 420ad0e2

Add spectrum() function to obsutils and create make_spectrum.py example script t…

…o demonstrate its usage.
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 \ No newline at end of file 118 \ No newline at end of file
pyext/ctools/obsutils.py
@@ -522,109 +522,94 @@ def set_obs_patterns(pattern, ra=83.6331, dec=22.0145, offset=1.5): @@ -522,109 +522,94 @@ def set_obs_patterns(pattern, ra=83.6331, dec=22.0145, offset=1.5):
522 522
523 # Return observation definition list 523 # Return observation definition list
524 return obsdeflist 524 return obsdeflist
525 -  
526 -# ================================================= #  
527 -# Make spectrum for one Source in a CTA Observation #  
528 -# ================================================= #  
529 525
530 -def getlogbins(nbins=12,emin=0.1,emax=100):  
531 - """  
532 - Returns list with logarithmiscenergy bins in  
533 - format [[emin1,emax1],[emin2,emax2],..]  
534 -  
535 - Parameters:  
536 - nbins Number of bins  
537 - emin Minimum energy  
538 - emax Maximum energy  
539 - """  
540 - lgemin=math.log10(emin)  
541 - lgemax=math.log10(emax)  
542 - lgsize=(lgemax-lgemin)/nbins  
543 - ebins=[]  
544 - for ii in range(0,nbins):  
545 - ebins.append([math.pow(10,lgemin),math.pow(10,lgemin+lgsize)])  
546 - lgemin=lgemin+lgsize  
547 - return ebins  
548 -  
549 -# Please note that specpoints can make spectra for any given  
550 -# spectral model, as long as it has a "Prefactor" or "Integral"  
551 -# parameter which scales the function  
552 -def specpoints(obs,source,ebins): 526 +
  527 +# ================================================================= #
  528 +# Generate a spectrum by fitting an observation in energy intervals #
  529 +# ================================================================= #
  530 +def spectrum(obs, source, ebounds):
553 """ 531 """
554 - Returns spectral points in the given binning for  
555 - the passed observations and source. 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
556 538
557 Parameters: 539 Parameters:
558 - obs - Pointing direction  
559 - source - Source name for which spectrum should be done  
560 - ebins - Binning passed as a list in units of TeV as  
561 - [[emin1,emax1],[emin2,emax2],..] 540 + obs - Observation container
  541 + source - Source name for which spectrum should be computed
  542 + ebounds - GEbounds energy boundaries
562 Keywords: 543 Keywords:
  544 + None
563 """ 545 """
564 - #Check if parameters Prefactor or Integral exist to scale mdoel  
565 - normpar = "Prefactor" 546 + # Check if parameters Prefactor or Integral exist to scale mdoel
  547 + normpar = "Prefactor"
566 srcmodel = obs.models()[source] 548 srcmodel = obs.models()[source]
567 if not srcmodel.has_par(normpar): 549 if not srcmodel.has_par(normpar):
568 if srcmodel.has_par("Integral"): 550 if srcmodel.has_par("Integral"):
569 normpar = "Integral" 551 normpar = "Integral"
570 else: 552 else:
571 - print "Error: your spectral model of ",source,"does not\  
572 - have a scaling parameter named 'Prefactor' or 'Integral'" 553 + print("Error: your spectral model of "+source+"does not"+\
  554 + "have a scaling parameter named 'Prefactor'"+\
  555 + " or 'Integral'")
573 return 556 return
574 557
575 - #Fix all parameters except prefactor 558 + # Fix all parameters except prefactor
576 opt_spectral = srcmodel.spectral() 559 opt_spectral = srcmodel.spectral()
577 for model in obs.models(): 560 for model in obs.models():
578 for par in range(model.size()): 561 for par in range(model.size()):
579 model[par].fix() 562 model[par].fix()
580 opt_spectral[normpar].free() 563 opt_spectral[normpar].free()
581 564
582 - #Define spectrum dictionary, units are in format readable by astropy 565 + # Define spectrum dictionary, units are in format readable by astropy
583 spec = {"energy":{"value":[],"eu_value":[],"ed_value":[],"unit":"none"}, 566 spec = {"energy":{"value":[],"eu_value":[],"ed_value":[],"unit":"none"},
584 "flux" :{"value":[],"eu_value":[],"ed_value":[],"unit":"none"}, 567 "flux" :{"value":[],"eu_value":[],"ed_value":[],"unit":"none"},
585 "TS" :{"value":[],"eu_value":[],"ed_value":[],"unit":"none"}} 568 "TS" :{"value":[],"eu_value":[],"ed_value":[],"unit":"none"}}
586 569
587 - #Loop over energy bins, fit and write result to spectrum  
588 - for ebin in ebins:  
589 - #Get logarithmic bin center and flux value of all energy fit  
590 - ecenter = math.pow(10,(math.log10(ebin[1])+math.log10(ebin[0]))/2.)  
591 - allflux = opt_spectral.eval(gammalib.GEnergy(ecenter,"TeV"),gammalib.GTime(0)) 570 + # Loop over energy bins, fit and write result to spectrum
  571 + for i in range(len(ebounds)):
592 572
593 - #Clone observations and reset energy thresholds 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
594 select = ctools.ctselect(obs) 578 select = ctools.ctselect(obs)
595 select["ra"].real(-1.0) 579 select["ra"].real(-1.0)
596 select["dec"].real(-1.0) 580 select["dec"].real(-1.0)
597 select["rad"].real(-1.0) 581 select["rad"].real(-1.0)
598 - select["tmin"].real(0)  
599 - select["tmax"].real(0)  
600 - select["emin"].real(ebin[0])  
601 - select["emax"].real(ebin[1]) 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())
602 select.run() 586 select.run()
603 - obsclone = select.obs()  
604 587
605 - #Refit and write out to spectrum  
606 - binlike=fit(obsclone,log=False, debug=False, edisp=False,tscalc=True) 588 + # Refit and write out to spectrum
  589 + binlike = fit(select.obs(), log=False, debug=False, edisp=False, tscalc=True)
607 binopt_spectral = binlike.obs().models()[source].spectral() 590 binopt_spectral = binlike.obs().models()[source].spectral()
608 - binflux=binopt_spectral.eval(gammalib.GEnergy(ecenter,"TeV"),gammalib.GTime(0))  
609 - if binopt_spectral[normpar].value()>0:  
610 - relerr=binopt_spectral[normpar].error()/binopt_spectral[normpar].value() 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()
611 else: 594 else:
612 - relerr=0 595 + relerr = 0.0
613 596
614 - #Store and convert to TeV from MeV  
615 - spec["energy"]["value"].append(ecenter)  
616 - spec["energy"]["ed_value"].append(ecenter-ebin[0])  
617 - spec["energy"]["eu_value"].append(ebin[1]-ecenter)  
618 - spec["energy"]["unit"]="1e12 eV" 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"
619 602
620 - spec["flux"]["value"].append(binflux*1e6)  
621 - spec["flux"]["ed_value"].append(relerr*binflux*1e6)  
622 - spec["flux"]["eu_value"].append(relerr*binflux*1e6)  
623 - spec["flux"]["unit"]="cm-2 1e-12 eV-1" 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"
624 607
625 spec["TS"]["value"].append(binlike.obs().models()[source].ts()) 608 spec["TS"]["value"].append(binlike.obs().models()[source].ts())
626 609
627 - print spec["energy"]["value"]  
628 - print spec["flux"]["value"]  
629 - #Return spectrum 610 + # Debugging???
  611 + #print(spec["energy"]["value"])
  612 + #print(spec["flux"]["value"])
  613 +
  614 + # Return spectrum
630 return spec 615 return spec