Commit 39e9c7a9ef47cf59d1cf393f9d470cfe055063ea

Authored by knodlseder
1 parent a30f58c8

implement plotting

Showing 1 changed file with 274 additions and 71 deletions
test/example_binned.py
1 1 #! /usr/bin/env python
2 2 # ===========================================================================================#
3   -# This script illustrates how to build a binned analysis chain using CTAtools.
  3 +# This script illustrates how to build a binned analysis pipeline using CTAtools.
4 4 #
5   -# If matplotlib is installed, the spectrum will be displayed on the screen.
  5 +# If matplotlib is installed, a counts spectrum and an offset histogram will be displayed.
6 6 # ===========================================================================================#
7 7 from ctatools import *
  8 +from gammalib import *
8 9 from math import *
  10 +import os
  11 +import glob
9 12  
10 13  
11   -# =================== #
12   -# Processing pipeline #
13   -# =================== #
14   -def process():
  14 +# ============================= #
  15 +# Analysis pipeline - version 1 #
  16 +# ============================= #
  17 +def pipeline_v1():
15 18 """
16   - Binned analysis processing pipeline.
  19 + Binned analysis pipeline - save intermediate results.
  20 +
  21 + This function implements an analysis pipeline that successively calls
  22 + ctobssim, ctbin and ctlike by saving the intermediate results as FITS
  23 + files on disk. This replicates the way how the analysis would be done
  24 + in a ftools-like approach.
17 25 """
18 26 # Set script parameters
19 27 model_name = "data/crab.xml"
... ... @@ -42,6 +50,7 @@ def process():
42 50  
43 51 # Simulate events
44 52 sim = ctobssim()
  53 + sim.logFileOpen() # We need this to explicitely open the log file in Python mode
45 54 sim["infile"].filename(model_name)
46 55 sim["outfile"].filename(events_name)
47 56 sim["caldb"].string(caldb)
... ... @@ -53,7 +62,7 @@ def process():
53 62 sim["tmax"].real(tstop)
54 63 sim["emin"].real(emin)
55 64 sim["emax"].real(emax)
56   - sim.run()
  65 + sim.execute()
57 66 print "Simulated events ("+str(sim.celapse())+" CPU seconds)"
58 67  
59 68 # Update timing
... ... @@ -62,6 +71,7 @@ def process():
62 71  
63 72 # Bin events into counts map
64 73 bin = ctbin()
  74 + bin.logFileOpen() # We need this to explicitely open the log file in Python mode
65 75 bin["evfile"].filename(events_name)
66 76 bin["outfile"].filename(cntmap_name)
67 77 bin["emin"].real(emin)
... ... @@ -74,7 +84,7 @@ def process():
74 84 bin["xref"].real(ra)
75 85 bin["yref"].real(dec)
76 86 bin["proj"].string(proj)
77   - bin.run()
  87 + bin.execute()
78 88 print "Binned events into counts map ("+str(bin.celapse())+" CPU seconds)"
79 89  
80 90 # Update timing
... ... @@ -83,6 +93,7 @@ def process():
83 93  
84 94 # Perform maximum likelihood fitting
85 95 like = ctlike()
  96 + like.logFileOpen() # We need this to explicitely open the log file in Python mode
86 97 like["cntmap"].filename(cntmap_name)
87 98 like["srcmdl"].filename(model_name)
88 99 like["outmdl"].filename(result_name)
... ... @@ -90,7 +101,7 @@ def process():
90 101 like["stat"].string("POISSON")
91 102 like["caldb"].string(caldb)
92 103 like["irf"].string(irf)
93   - like.run()
  104 + like.execute()
94 105 print "Maximum likelihood fitting ("+str(like.celapse())+" CPU seconds)"
95 106  
96 107 # Update timing
... ... @@ -105,74 +116,242 @@ def process():
105 116 return
106 117  
107 118  
108   -# ============ #
109   -# Show photons #
110   -# ============ #
111   -def show_photons(photons, xmlname, e_min, e_max, area, duration, ebins=30):
  119 +# ============================= #
  120 +# Analysis pipeline - version 2 #
  121 +# ============================= #
  122 +def pipeline_v2():
112 123 """
113   - Show photons using matplotlib (if available).
  124 + Binned analysis pipeline - keep intermediate results in memory.
  125 +
  126 + This function implements an analysis pipeline that successively calls
  127 + ctobssim, ctbin and ctlike without saving the intermediate results as
  128 + FITS files on disk. All data are hold in memory.
  129 +
  130 + At the end, results are plotted (if matplotlib is installed)
  131 + """
  132 + # Set script parameters
  133 + model_name = "data/crab.xml"
  134 + caldb = "irf"
  135 + irf = "kb_E_50h_v3"
  136 + ra = 83.63
  137 + dec = 22.01
  138 + rad_sim = 10.0
  139 + tstart = 0.0
  140 + tstop = 1800.0
  141 + emin = 0.1
  142 + emax = 100.0
  143 + enumbins = 20
  144 + nxpix = 200
  145 + nypix = 200
  146 + binsz = 0.02
  147 + coordsys = "CEL"
  148 + proj = "CAR"
  149 +
  150 + # Initialise timing
  151 + wall_seconds = 0.0
  152 + cpu_seconds = 0.0
  153 +
  154 + # Simulate events
  155 + sim = ctobssim()
  156 + sim["infile"].filename(model_name)
  157 + sim["caldb"].string(caldb)
  158 + sim["irf"].string(irf)
  159 + sim["ra"].real(ra)
  160 + sim["dec"].real(dec)
  161 + sim["rad"].real(rad_sim)
  162 + sim["tmin"].real(tstart)
  163 + sim["tmax"].real(tstop)
  164 + sim["emin"].real(emin)
  165 + sim["emax"].real(emax)
  166 + sim.run()
  167 + print "Simulated events ("+str(sim.celapse())+" CPU seconds)"
  168 +
  169 + # Update timing
  170 + wall_seconds += sim.telapse()
  171 + cpu_seconds += sim.celapse()
  172 +
  173 + # Bin events into counts map
  174 + bin = ctbin(sim.obs())
  175 + bin["emin"].real(emin)
  176 + bin["emax"].real(emax)
  177 + bin["enumbins"].integer(enumbins)
  178 + bin["nxpix"].integer(nxpix)
  179 + bin["nypix"].integer(nypix)
  180 + bin["binsz"].real(binsz)
  181 + bin["coordsys"].string(coordsys)
  182 + bin["xref"].real(ra)
  183 + bin["yref"].real(dec)
  184 + bin["proj"].string(proj)
  185 + bin.run()
  186 + print "Binned events into counts map ("+str(bin.celapse())+" CPU seconds)"
  187 +
  188 + # Update timing
  189 + wall_seconds += bin.telapse()
  190 + cpu_seconds += bin.celapse()
  191 +
  192 + # Perform maximum likelihood fitting
  193 + like = ctlike(bin.obs())
  194 + like.run()
  195 + print "Maximum likelihood fitting ("+str(like.celapse())+" CPU seconds)"
  196 +
  197 + # Update timing
  198 + wall_seconds += like.telapse()
  199 + cpu_seconds += like.celapse()
  200 +
  201 + # Show total times
  202 + print "Total wall time elapsed: "+str(wall_seconds)+" seconds"
  203 + print "Total CPU time used ...: "+str(cpu_seconds)+" seconds"
  204 +
  205 + # Show model fitting results
  206 + #print like.obs().models()
  207 +
  208 + # Plot counts
  209 + plot_counts(bin.obs())
  210 +
  211 + # Return
  212 + return
  213 +
  214 +
  215 +# =========== #
  216 +# Plot counts #
  217 +# =========== #
  218 +def plot_counts(observations):
  219 + """
  220 + Plot counts.
114 221 """
115 222 # Only proceed if matplotlib is available
116 223 try:
117 224 # Import matplotlib
118 225 import matplotlib.pyplot as plt
119 226  
120   - # Create figure
121   - plt.figure(1)
122   - plt.title("MC simulated photon spectrum ("+str(e_min)+'-'+str(e_max)+" TeV)")
  227 + # Set legend fontsize
  228 + params = {'legend.fontsize': 10}
  229 + plt.rcParams.update(params)
  230 +
  231 + # Set plot styles
  232 + styles = ['b-', 'g-', 'y-', 'n-']
  233 +
  234 + # Dump header
  235 + print ""
  236 + print "Make plots (using matplotlib):"
  237 + print "=============================="
123 238  
124   - # Setup energy range covered by data
125   - emin = GEnergy()
126   - emax = GEnergy()
127   - emin.TeV(e_min)
128   - emax.TeV(e_max)
129   - ebds = GEbounds()
130   - ebds.setlog(emin, emax, ebins)
  239 + # Create figure 1
  240 + plt.figure(1,figsize=(12,6))
  241 + plt.subplots_adjust(hspace=.7)
  242 +
  243 + # Create subplot 1
  244 + plt.subplot(121)
  245 + plt.title("Spectrum (summed over all pixels)")
  246 +
  247 + # Loop over observations
  248 + for obs in observations:
131 249  
132   - # Create energy axis
133   - energy = []
134   - for i in range(ebds.size()):
135   - energy.append(ebds.elogmean(i).TeV())
136   -
137   - # Fill histogram
138   - counts = [0.0 for i in range(ebds.size())]
139   - for photon in photons:
140   - index = ebds.index(photon.energy())
141   - counts[index] = counts[index] + 1.0
142   -
143   - # Create error bars
144   - error = [sqrt(c) for c in counts]
145   -
146   - # Get model values
147   - models = GModels(xmlname)
148   - crab = cast_GModelSky(models[0])
149   - model = []
150   - d = GSkyDir()
151   - d.radec_deg(83.6331, 22.0145)
152   - t = GTime()
153   - for i in range(ebds.size()):
154   - eval = ebds.elogmean(i)
155   - ewidth = ebds.emax(i) - ebds.emin(i)
156   - f = crab.value(d, eval, t) * area * duration * ewidth.MeV()
157   - model.append(f)
158   -
159   - # Plot data
160   - plt.loglog(energy, counts, 'ro')
161   - plt.errorbar(energy, counts, error, fmt=None, ecolor='r')
162   -
163   - # Plot model
164   - plt.plot(energy, model, 'b-')
165   -
166   - # Set axes
  250 + # Get event cube
  251 + cube = cast_GCTAEventCube(obs.events())
  252 +
  253 + # Create energy axis
  254 + energy = []
  255 + ebounds = cube.ebounds()
  256 + for i in range(ebounds.size()):
  257 + energy.append(ebounds.elogmean(i).TeV())
  258 +
  259 + # Create spectrum
  260 + print "Extract data:"
  261 + counts = [0.0 for i in range(ebounds.size())]
  262 + for bin in cube:
  263 + index = ebounds.index(bin.energy())
  264 + counts[index] = counts[index] + bin.counts()
  265 +
  266 + # Create error bars
  267 + error = [sqrt(c) for c in counts]
  268 +
  269 + # Plot spectrum
  270 + plt.loglog(energy, counts, 'ro', label='data')
  271 + plt.errorbar(energy, counts, error, fmt=None, ecolor='r')
  272 +
  273 + # Extract models
  274 + print "Extract models:"
  275 + sum_model = [0.0 for i in range(ebounds.size())]
  276 + for k, m in enumerate(observations.models()):
  277 + print "- "+m.name()
  278 + model = [0.0 for i in range(ebounds.size())]
  279 + for bin in cube:
  280 + index = ebounds.index(bin.energy())
  281 + prob = m.eval(bin, obs)
  282 + model[index] = model[index] + prob * bin.size()
  283 + for i in range(ebounds.size()):
  284 + sum_model[i] = sum_model[i] + model[i]
  285 + plt.loglog(energy, model, styles[k], label=m.name())
  286 + plt.loglog(energy, sum_model, 'r-', label='total')
  287 +
  288 + # Put labels
167 289 plt.xlabel("Energy (TeV)")
168   - plt.ylabel("Number of incident photons")
  290 + plt.ylabel("Counts")
  291 + plt.legend(loc="lower left")
  292 +
  293 + # Create subplot 2
  294 + plt.subplot(122)
  295 + plt.title("Offset (summed over all energies)")
  296 +
  297 + # Set Crab direction
  298 + crab = GSkyDir()
  299 + crab.radec_deg(83.63, 22.01)
  300 +
  301 + # Loop over observations
  302 + for obs in observations:
  303 +
  304 + # Get event cube
  305 + cube = cast_GCTAEventCube(obs.events())
  306 +
  307 + # Create offset histogram
  308 + print "Extract data:"
  309 + nx = 30
  310 + doffset2 = 0.01
  311 + offset2 = [(i+0.5)*doffset2 for i in range(nx)]
  312 + counts = [0.0 for i in range(nx)]
  313 + for bin in cube:
  314 + off = bin.dir().dist_deg(crab)
  315 + off2 = off*off
  316 + index = int(off2/doffset2)
  317 + if index < nx:
  318 + counts[index] = counts[index] + bin.counts()
  319 +
  320 + # Create error bars
  321 + error = [sqrt(c) for c in counts]
169 322  
170   - # Allocate histogram
171   - # Show plot
  323 + # Plot distribution
  324 + plt.semilogy(offset2, counts, 'ro', label='data')
  325 +
  326 + # Extract models
  327 + print "Extract models:"
  328 + sum_model = [0.0 for i in range(nx)]
  329 + for k, m in enumerate(observations.models()):
  330 + print "- "+m.name()
  331 + model = [0.0 for i in range(nx)]
  332 + for bin in cube:
  333 + off = bin.dir().dist_deg(crab)
  334 + off2 = off*off
  335 + index = int(off2/doffset2)
  336 + if index < nx:
  337 + prob = m.eval(bin, obs)
  338 + model[index] = model[index] + prob * bin.size()
  339 + for i in range(nx):
  340 + sum_model[i] = sum_model[i] + model[i]
  341 + plt.plot(offset2, model, styles[k], label=m.name())
  342 + plt.plot(offset2, sum_model, 'r-', label='total')
  343 + plt.ylim(ymin=0.1)
  344 +
  345 + # Put labels
  346 + plt.xlabel("Offset (deg^2)")
  347 + plt.ylabel("Counts")
  348 + plt.legend(loc="upper right")
  349 +
  350 + # Show counts spectra
172 351 plt.show()
173 352  
174 353 except:
175   - print "Matplotlib is not (correctly) installed on your system. No data are shown."
  354 + print "Matplotlib is not (correctly) installed on your system. No counts spectra are shown."
176 355  
177 356 # Return
178 357 return
... ... @@ -190,14 +369,38 @@ if __name__ == &#39;__main__&#39;:
190 369 - Event simulation
191 370 - Event binning
192 371 - Binned maximum likelihood fitting
  372 +
  373 + Two variations of the script are implemented. One that calls the classes
  374 + like executables, storing the intermediate results on disk, and a second
  375 + that uses the results of the precedent class directly without storing
  376 + any data on disk.
  377 +
  378 + The second variation will also show a counts spectrum of the data after
  379 + fitting (only if matplotlib is available on your system). Note that the
  380 + counts spectrum is summed over the entire data space, i.e. no event selection
  381 + around the Crab has been performed.
193 382 """
194 383 # Dump header
195   - print "*****************************"
196   - print "* CTA binned analysis script *"
197   - print "*****************************"
  384 + print "*************************************"
  385 + print "* CTA binned analysis scripts *"
  386 + print "*************************************"
  387 + print "... this script will take 1-2 minutes"
198 388  
199   - # Process data
200   - process()
  389 + # Remove any existing result files
  390 + list = [glob.glob("*.fits"), glob.glob("*.log"), glob.glob("*.xml")]
  391 + for files in list:
  392 + for file in files:
  393 + os.remove(file)
201 394  
202   - # Show photons
203   - #show_photons(photons, xmlname, e_min, e_max, area, duration)
  395 + # Save intermediate results on disk
  396 + print ""
  397 + print "Executable analysis pipeline:"
  398 + print "============================="
  399 + pipeline_v1()
  400 +
  401 + # Do analysis in memory
  402 + print ""
  403 + print "In memory analysis pipeline:"
  404 + print "============================"
  405 + pipeline_v2()
  406 + print ""
... ...