show_spectrum_last.py
1 |
#! /usr/bin/env python
|
---|---|
2 |
# ==========================================================================
|
3 |
# Display spectrum generated by csspec
|
4 |
#
|
5 |
# Copyright (C) 2015-2020 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 sys |
22 |
try:
|
23 |
import matplotlib.pyplot as plt |
24 |
plt.figure() |
25 |
plt.close() |
26 |
except (ImportError, RuntimeError): |
27 |
print('This script needs the "matplotlib" module')
|
28 |
sys.exit() |
29 |
try:
|
30 |
import numpy as np |
31 |
except ImportError: |
32 |
print('This script needs the "numpy" module')
|
33 |
sys.exit() |
34 |
import gammalib |
35 |
import cscripts |
36 |
|
37 |
|
38 |
# ===================================== #
|
39 |
# Extract the spectrum info from a file #
|
40 |
# ===================================== #
|
41 |
def get_spectrum_file(filename): |
42 |
"""
|
43 |
Extract the spectrum info from a file for plotting
|
44 |
|
45 |
Parameters
|
46 |
----------
|
47 |
filename : str
|
48 |
Name of spectrum FITS file
|
49 |
|
50 |
Returns
|
51 |
-------
|
52 |
spec : dict
|
53 |
Python dictionary defining spectral plot parameters
|
54 |
"""
|
55 |
# Read spectrum file
|
56 |
fits = gammalib.GFits(filename) |
57 |
|
58 |
# Return dictionary
|
59 |
return get_spectrum_fits(fits)
|
60 |
|
61 |
|
62 |
# ============================================= #
|
63 |
# Extract the spectrum info from a GFits object #
|
64 |
# ============================================= #
|
65 |
def get_spectrum_fits(fits): |
66 |
"""
|
67 |
Extract the spectrum info from a GFits object
|
68 |
|
69 |
Parameters
|
70 |
----------
|
71 |
fits : `~gammalib.GFits`
|
72 |
Spectral GFits object
|
73 |
|
74 |
Returns
|
75 |
-------
|
76 |
spec : dict
|
77 |
Python dictionary defining spectral plot parameters
|
78 |
"""
|
79 |
# Read spectrum objects
|
80 |
table = fits.table(1)
|
81 |
c_energy = table['e_ref']
|
82 |
c_ed = table['e_min']
|
83 |
c_eu = table['e_max']
|
84 |
c_flux = table['ref_e2dnde']
|
85 |
c_norm = table['norm']
|
86 |
c_eflux = table['norm_err']
|
87 |
c_upper = table['norm_ul']
|
88 |
c_ts = table['ts']
|
89 |
|
90 |
# Initialise arrays to be filled
|
91 |
spec = { |
92 |
'energies' : [],
|
93 |
'flux' : [],
|
94 |
'ed_engs' : [],
|
95 |
'eu_engs' : [],
|
96 |
'e_flux' : [],
|
97 |
'ul_energies' : [],
|
98 |
'ul_ed_engs' : [],
|
99 |
'ul_eu_engs' : [],
|
100 |
'ul_flux' : [],
|
101 |
'yerr' : [],
|
102 |
'loglike' : [],
|
103 |
'engs_scan' : [],
|
104 |
'e2dnde_scan' : [],
|
105 |
'dll_scan' : []
|
106 |
} |
107 |
|
108 |
# Determine if we can load the delta-log-likelihood profiles
|
109 |
has_sedtype = table.has_card('SED_TYPE')
|
110 |
load_dll = False
|
111 |
if has_sedtype:
|
112 |
seds = table.card('SED_TYPE').string().split(',') |
113 |
|
114 |
# Load likelhood columns if present
|
115 |
if seds[0] == 'likelihood': |
116 |
load_dll = True
|
117 |
c_loglike = table['loglike']
|
118 |
c_norm_scan = table['norm_scan']
|
119 |
c_dll_scan = table['dloglike_scan']
|
120 |
|
121 |
# Loop over rows of the file
|
122 |
nrows = table.nrows() |
123 |
for row in range(nrows): |
124 |
|
125 |
# Get Test Statistic, flux and flux error
|
126 |
ts = c_ts.real(row) |
127 |
norm = c_norm.real(row) |
128 |
flx = norm * c_flux.real(row) |
129 |
e_flx = flx * c_eflux.real(row) |
130 |
|
131 |
# If Test Statistic is larger than 9 and flux error is smaller than
|
132 |
# flux then append flux plots ...
|
133 |
if ts > 9.0 and e_flx < flx: |
134 |
spec['energies'].append(c_energy.real(row))
|
135 |
spec['flux'].append(flx)
|
136 |
spec['ed_engs'].append(c_ed.real(row))
|
137 |
spec['eu_engs'].append(c_eu.real(row))
|
138 |
spec['e_flux'].append(e_flx)
|
139 |
|
140 |
# ... otherwise append upper limit
|
141 |
else:
|
142 |
spec['ul_energies'].append(c_energy.real(row))
|
143 |
spec['ul_flux'].append(flx*c_upper.real(row))
|
144 |
spec['ul_ed_engs'].append(c_ed.real(row))
|
145 |
spec['ul_eu_engs'].append(c_eu.real(row))
|
146 |
|
147 |
# Load the delta log-likelihood values
|
148 |
if load_dll:
|
149 |
spec['e2dnde_scan'] = np.zeros((nrows, c_norm_scan.elements(0))) |
150 |
spec['dll_scan'] = np.zeros((nrows, c_norm_scan.elements(0))) |
151 |
|
152 |
for row in range(nrows): |
153 |
loglike = c_loglike.real(row) |
154 |
spec['loglike'].append(loglike)
|
155 |
spec['engs_scan'].append(c_energy.real(row) - c_ed.real(row))
|
156 |
for col in range(c_norm_scan.elements(row)): |
157 |
spec['e2dnde_scan'][row,col] = c_norm_scan.real(row,col) * c_flux.real(row)
|
158 |
spec['dll_scan'][row,col] = c_dll_scan.real(row,col)
|
159 |
spec['engs_scan'].append(c_energy.real(nrows-1)+c_eu.real(nrows-1)) |
160 |
|
161 |
# Set upper limit errors
|
162 |
spec['yerr'] = [0.6 * x for x in spec['ul_flux']] |
163 |
|
164 |
# Return dictionary
|
165 |
return spec
|
166 |
|
167 |
|
168 |
# ========================= #
|
169 |
# Plot delta log-likelihood #
|
170 |
# ========================= #
|
171 |
def plot_dloglike(spec): |
172 |
"""
|
173 |
Plot delta log-likelihood
|
174 |
|
175 |
Parameters
|
176 |
----------
|
177 |
spec : dict
|
178 |
Python dictionary defining spectral plot parameters
|
179 |
"""
|
180 |
# Establish the bounds on the x,y plot
|
181 |
ymin,ymax = plt.gca().get_ylim() |
182 |
ymin = np.log10(ymin) |
183 |
ymax = np.log10(ymax) |
184 |
steps = 1000
|
185 |
ebins = len(spec['e2dnde_scan']) |
186 |
y_bounds = np.linspace(ymin, ymax, steps+1)
|
187 |
|
188 |
# Compute the logarithmic center of each bin
|
189 |
fluxpnts = 10 ** ((y_bounds[1:]+y_bounds[:-1]) / 2.0) |
190 |
|
191 |
# Scale the boundaries on the grid
|
192 |
y_bounds = 10 ** y_bounds
|
193 |
|
194 |
# Interpolate the dlogLike values
|
195 |
dll_hist = [[]]*ebins |
196 |
for ebin in range(ebins): |
197 |
dll_hist[ebin] = np.interp(fluxpnts, spec['e2dnde_scan'][ebin],
|
198 |
spec['dll_scan'][ebin])
|
199 |
|
200 |
# Transpose the dll_hist array so x=energy, y=dnde
|
201 |
dll_hist = [[row[i] for row in dll_hist] for i in range(steps)] |
202 |
|
203 |
# Plot the likelihood profiles
|
204 |
plt.pcolormesh(np.array(spec['engs_scan']), y_bounds,
|
205 |
np.array(dll_hist), vmin=-10.0, vmax=0.0, |
206 |
cmap='Reds', alpha=0.9) |
207 |
cbar = plt.colorbar() |
208 |
cbar.set_label(r'$\Delta$ log-likelihood')
|
209 |
plt.grid() |
210 |
|
211 |
# Return
|
212 |
return
|
213 |
|
214 |
|
215 |
# ============= #
|
216 |
# Plot spectrum #
|
217 |
# ============= #
|
218 |
def plot_spectrum(filename, plotfile): |
219 |
"""
|
220 |
Plot spectrum
|
221 |
|
222 |
Parameters
|
223 |
----------
|
224 |
filename : str
|
225 |
Name of spectrum FITS file
|
226 |
plotfile : str
|
227 |
Plot file name
|
228 |
"""
|
229 |
# Get spectrum parameters
|
230 |
spec = get_spectrum_file(filename) |
231 |
|
232 |
# Create the plot
|
233 |
plt.figure() |
234 |
plt.loglog() |
235 |
plt.grid() |
236 |
plt.xlabel('Energy (TeV)')
|
237 |
plt.ylabel(r'E$^2$ $\times$ dN/dE (erg cm$^{-2}$ s$^{-1}$)')
|
238 |
|
239 |
# Plot the spectrum
|
240 |
plt.errorbar(spec['energies'], spec['flux'], |
241 |
yerr=spec['e_flux'], xerr=[spec['ed_engs'], spec['eu_engs']], |
242 |
fmt='ro')
|
243 |
|
244 |
# Plot upper limits
|
245 |
if len(spec['ul_energies']) > 0: |
246 |
plt.errorbar(spec['ul_energies'], spec['ul_flux'], yerr=spec['yerr'], |
247 |
xerr=[spec['ul_ed_engs'], spec['ul_eu_engs']], |
248 |
uplims=True, fmt='ro') |
249 |
|
250 |
# Plot log-likelihood profiles
|
251 |
if len(spec['dll_scan']) > 0: |
252 |
plot_dloglike(spec) |
253 |
|
254 |
# Show figure
|
255 |
if len(plotfile) > 0: |
256 |
plt.savefig(plotfile) |
257 |
else:
|
258 |
plt.show() |
259 |
|
260 |
# Return
|
261 |
return
|
262 |
|
263 |
|
264 |
# ============= #
|
265 |
# Show spectrum #
|
266 |
# ============= #
|
267 |
def show_spectrum(): |
268 |
"""
|
269 |
Show spectrum
|
270 |
"""
|
271 |
# Set usage string
|
272 |
usage = 'show_spectrum.py [-p plotfile] [file]'
|
273 |
|
274 |
# Set default options
|
275 |
options = [{'option': '-p', 'value': ''}] |
276 |
|
277 |
# Get arguments and options from command line arguments
|
278 |
args, options = cscripts.ioutils.get_args_options(options, usage) |
279 |
|
280 |
# Extract script parameters from options
|
281 |
plotfile = options[0]['value'] |
282 |
|
283 |
# Show spectrum
|
284 |
plot_spectrum(args[0], plotfile)
|
285 |
|
286 |
# Return
|
287 |
return
|
288 |
|
289 |
|
290 |
# ======================== #
|
291 |
# Main routine entry point #
|
292 |
# ======================== #
|
293 |
if __name__ == '__main__': |
294 |
|
295 |
# Show spectrum
|
296 |
show_spectrum() |