show_spill_over.py

Knödlseder Jürgen, 11/09/2018 11:26 PM

Download (12.7 KB)

 
1
#! /usr/bin/env python
2
# ==========================================================================
3
# Show spill over for a given observation and model
4
#
5
# Copyright (C) 2018 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 os
22
import math
23
import gammalib
24
import ctools
25
import cscripts
26
import matplotlib.pyplot as plt
27

    
28

    
29
# ====================== #
30
# Plot residual spectrum #
31
# ====================== #
32
def plot_resspec(frame, energies, resspec, errspec):
33
    """
34
    Plot residual spectrum
35

36
    Parameters
37
    ----------
38
    frame : pyplot
39
        Frame for spectrum
40
    """
41
    # Set axes scales and limit
42
    frame.set_xscale('log')
43
    frame.set_xlim([0.5, 40])
44

    
45
    # Counts and model
46
    frame.errorbar(energies, resspec, yerr=errspec,
47
                   fmt='ko', capsize=0, linewidth=2, zorder=2, label='Data')
48
    frame.plot(frame.get_xlim(),[0,0], 'r-')
49
    frame.set_xlabel('Energy (TeV)')
50
    frame.set_ylabel('Stacked - Joint Binned')
51

    
52
    # Return
53
    return
54

    
55

    
56
# ================= #
57
# Plot residual map #
58
# ================= #
59
def plot_resmap(plt1, plt2, map, error, steps=1):
60
    """
61
    Plot pull histogram
62

63
    Parameters
64
    ----------
65
    plt1 : pyplot
66
        Frame for first map
67
    plt2 : pyplot
68
        Frame for second map
69
    map : `~gammalib.GSkyMap()`
70
        Sky map
71
    error : `~gammalib.GSkyMap()`
72
        Sky map
73
    steps : int
74
        Number of steps for rebinning
75
    """
76
    # Create longitude array from skymap
77
    x_lon = []
78
    y_lon = []
79
    e_lon = []
80
    for ix in range(0, map.nx(), steps):
81
        value = 0.0
82
        err   = 0.0
83
        for istep in range(steps):
84
            if istep+ix < map.nx():
85
                for iy in range(map.ny()):
86
                    index  = istep+ix+iy*map.nx()
87
                    value += map[index]
88
                    err   += error[index]*error[index]
89
        x_lon.append(ix)
90
        y_lon.append(value)
91
        e_lon.append(math.sqrt(err))
92

    
93
    # Create latitude array from skymap
94
    x_lat = []
95
    y_lat = []
96
    e_lat = []
97
    for iy in range(0, map.ny(), steps):
98
        value = 0.0
99
        err   = 0.0
100
        for istep in range(steps):
101
            if istep+iy < map.ny():
102
                for ix in range(map.nx()):
103
                    index  = ix+(istep+iy)*map.nx()
104
                    value += map[index]
105
                    err   += error[index]*error[index]
106
        x_lat.append(iy)
107
        y_lat.append(value)
108
        e_lat.append(math.sqrt(err))
109

    
110
    # Plot longitude distribution
111
    plt1.errorbar(x_lon, y_lon, yerr=e_lon,
112
                  fmt='ko', capsize=0, linewidth=2, zorder=2)
113
    plt1.axhline(0, color='r', linestyle='--')
114
    plt1.set_xlabel('Right Ascension (pixels)')
115
    plt1.set_ylabel('Stacked - Joint Binned')
116
    plt1.grid(True)
117

    
118
    # Plot latitude distribution
119
    plt2.errorbar(x_lat, y_lat, yerr=e_lat,
120
                  fmt='ko', capsize=0, linewidth=2, zorder=2)
121
    plt2.axhline(0, color='r', linestyle='--')
122
    plt2.set_xlabel('Declination (pixels)')
123
    plt2.set_ylabel('Stacked - Joint Binned')
124
    plt2.grid(True)
125

    
126
    # Return
127
    return
128

    
129

    
130
# ======== #
131
# Plot map #
132
# ======== #
133
def plot_map(frame, map, smooth=0.0):
134
    """
135
    Plot Aitoff map
136

137
    Parameters
138
    ----------
139
    frame : pyplot
140
        Frame for map
141
    map : `~gammalib.GSkyMap()`
142
        Sky map
143
    smooth : float, optional
144
        Map smoothing parameter (degrees)
145
    """
146
    # Optionally smooth map
147
    if smooth > 0.0:
148
        _map = map.copy()
149
        _map.smooth('DISK', smooth)
150
    else:
151
        _map = map
152
    
153
    # Create array from skymap
154
    array = []
155
    v_max = 0.0
156
    for iy in range(_map.ny()):
157
        row = []
158
        for ix in range(_map.nx()):
159
            index = ix+iy*_map.nx()
160
            value = _map[index]
161
            row.append(value)
162
        array.append(row)
163

    
164
    # Show Aitoff projection
165
    c = frame.imshow(array, aspect=1.0)
166
    cbar = plt.colorbar(c, orientation='vertical', shrink=0.7)
167
    frame.grid(True)
168
    frame.set_xlabel('Right Ascension (pixels)')
169
    frame.set_ylabel('Declination (pixels)')
170

    
171
    # Return
172
    return
173

    
174

    
175
# =========================== #
176
# Determine spatial residuals #
177
# =========================== #
178
def residual_spatial(modcube1, modcube2):
179
    """
180
    Determine spatial residuals
181

182
    Parameters
183
    ----------
184
    modcube1 : `~gammalib.GCTAEventCube`
185
        First model cube
186
    modcube2 : `~gammalib.GCTAEventCube`
187
        Second model cube
188

189
    Returns
190
    -------
191
    map, error : `~gammalib.GSkyMap()`
192
        Residual sky map and error
193
    """
194
    # Get model cube maps
195
    map1 = modcube1.counts()
196
    map2 = modcube2.counts()
197

    
198
    # Generate residual map
199
    map = map1 - map2
200
    map.stack_maps()
201

    
202
    # Generate residual error bars
203
    error = map2.copy()
204
    error.stack_maps()
205
    error = error.sqrt()
206

    
207
    # Return residual map and error map
208
    return map, error
209

    
210

    
211
# ============================ #
212
# Determine spectral residuals #
213
# ============================ #
214
def residual_spectral(modcube1, modcube2):
215
    """
216
    Determine spectral residuals
217

218
    Parameters
219
    ----------
220
    modcube1 : `~gammalib.GCTAEventCube`
221
        First model cube
222
    modcube2 : `~gammalib.GCTAEventCube`
223
        Second model cube
224

225
    Returns
226
    -------
227
    map, error : list
228
        Residual vector
229
    """
230
    # Get model cube maps
231
    map1 = modcube1.counts()
232
    map2 = modcube2.counts()
233

    
234
    # Compute spectra
235
    spec1    = []
236
    spec2    = []
237
    residual = []
238
    error    = []
239
    energies = []
240
    for ieng in range(map1.nmaps()):
241
        sum1 = 0.0
242
        sum2 = 0.0
243
        for ipix in range(map1.npix()):
244
            sum1 += map1[ipix, ieng]
245
            sum2 += map2[ipix, ieng]
246
        spec1.append(sum1)
247
        spec2.append(sum2)
248
        residual.append(sum1 - sum2)
249
        error.append(math.sqrt(sum2))
250
        energies.append(modcube2.energy(ieng).TeV())
251

    
252
    # Return residual and error
253
    return energies, residual, error
254

    
255

    
256
# ================= #
257
# Create model cube #
258
# ================= #
259
def create_modcube(obs, ebins=20, edisp=False):
260
    """
261
    Create model cube
262

263
    Parameters
264
    ----------
265
    obs : `~gammalib.GObservations`
266
        Observation container
267
    ebins : int, optional
268
        Number of energy bins for binned or stacked analysis
269
    edisp : boolean, optional
270
        Use energy dispersion
271
    """
272
    # Create model cube
273
    ctmodel = ctools.ctmodel(obs)
274
    ctmodel['edisp']    = edisp
275
    ctmodel['incube']   = 'NONE'
276
    ctmodel['ebinalg']  = 'LOG'
277
    ctmodel['emin']     = 0.67
278
    ctmodel['emax']     = 30.0
279
    ctmodel['enumbins'] = ebins
280
    ctmodel['coordsys'] = 'CEL'
281
    ctmodel['proj']     = 'CAR'
282
    ctmodel['xref']     = 83.63
283
    ctmodel['yref']     = 22.01
284
    ctmodel['nxpix']    = 50
285
    ctmodel['nypix']    = 50
286
    ctmodel['binsz']    = 0.02
287
    #ctmodel['debug']    = True
288
    ctmodel.run()
289
    #print(ctmodel.cube())
290

    
291
    # Return model cube
292
    return ctmodel.cube().copy()
293

    
294

    
295
# ========================== #
296
# Create stacked observation #
297
# ========================== #
298
def create_stacked(obs, ebins=20, edisp=False, enumbins=300):
299
    """
300
    Create stacked observation
301

302
    Parameters
303
    ----------
304
    obs : `~gammalib.GObservations`
305
        Observation container
306
    ebins : int, optional
307
        Number of energy bins for binned or stacked analysis
308
    edisp : boolean, optional
309
        Use energy dispersion
310
    """
311
    # Create counts cube
312
    ctbin = ctools.ctbin(obs)
313
    ctbin['stack']    = True
314
    ctbin['ebinalg']  = 'LOG'
315
    ctbin['emin']     = 0.67
316
    ctbin['emax']     = 30.0
317
    ctbin['enumbins'] = ebins
318
    ctbin['coordsys'] = 'CEL'
319
    ctbin['proj']     = 'CAR'
320
    ctbin['xref']     = 83.63
321
    ctbin['yref']     = 22.01
322
    ctbin['nxpix']    = 50
323
    ctbin['nypix']    = 50
324
    ctbin['binsz']    = 0.02
325
    ctbin.run()
326

    
327
    # Create exposure cube
328
    ctexpcube = ctools.ctexpcube(obs)
329
    ctexpcube['incube']  = 'NONE'
330
    ctexpcube['ebinalg']  = 'LOG'
331
    ctexpcube['emin']     =   0.1
332
    ctexpcube['emax']     = 100.0
333
    ctexpcube['enumbins'] = enumbins
334
    ctexpcube['coordsys'] = 'CEL'
335
    ctexpcube['proj']     = 'CAR'
336
    ctexpcube['xref']     = 83.63
337
    ctexpcube['yref']     = 22.01
338
    ctexpcube['nxpix']    = 50
339
    ctexpcube['nypix']    = 50
340
    ctexpcube['binsz']    = 0.02
341
    ctexpcube.run()
342

    
343
    # Create PSF cube
344
    ctpsfcube = ctools.ctpsfcube(obs)
345
    ctpsfcube['incube']    = 'NONE'
346
    ctpsfcube['ebinalg']   = 'LOG'
347
    ctpsfcube['emin']      =   0.1
348
    ctpsfcube['emax']      = 100.0
349
    ctpsfcube['enumbins']  = enumbins
350
    ctpsfcube['coordsys']  = 'CEL'
351
    ctpsfcube['proj']      = 'CAR'
352
    ctpsfcube['xref']      = 83.63
353
    ctpsfcube['yref']      = 22.01
354
    ctpsfcube['nxpix']     = 35
355
    ctpsfcube['nypix']     = 25
356
    ctpsfcube['binsz']     = 0.2
357
    ctpsfcube['amax']      = 0.7
358
    ctpsfcube['anumbins']  = 300
359
    ctpsfcube.run()
360

    
361
    # Create energy dispersion cube
362
    if edisp:
363
        ctedispcube = ctools.ctedispcube(obs)
364
        ctedispcube['incube']    = 'NONE'
365
        ctedispcube['ebinalg']   = 'LOG'
366
        ctedispcube['emin']      =   0.1 # Full energy range
367
        ctedispcube['emax']      = 100.0 # Full energy range
368
        ctedispcube['enumbins']  = enumbins
369
        ctedispcube['coordsys']  = 'CEL'
370
        ctedispcube['proj']      = 'CAR'
371
        ctedispcube['xref']      = 83.63
372
        ctedispcube['yref']      = 22.01
373
        ctedispcube['nxpix']     = 35
374
        ctedispcube['nypix']     = 25
375
        ctedispcube['binsz']     = 0.2
376
        ctedispcube['migramax']  = 5.0
377
        ctedispcube['migrabins'] = 300
378
        ctedispcube.run()
379

    
380
    # Create dummy background cube
381
    bkgcube = gammalib.GCTACubeBackground()
382

    
383
    # Get stacked observation
384
    obs_stacked = ctbin.obs().copy()
385

    
386
    # Build stacked observation
387
    if edisp:
388
        obs_stacked[0].response(ctexpcube.expcube(),
389
                                ctpsfcube.psfcube(),
390
                                ctedispcube.edispcube(),
391
                                bkgcube)
392
    else:
393
        obs_stacked[0].response(ctexpcube.expcube(),
394
                                ctpsfcube.psfcube(),
395
                                bkgcube)
396

    
397
    # Return stacked observation
398
    return obs_stacked
399

    
400

    
401
# =============== #
402
# Show spill over #
403
# =============== #
404
def show_spill_over(obsname, modelname, srcname, ebins=20, edisp=False):
405
    """
406
    """
407
    # Load observations
408
    obs_unbinned = gammalib.GObservations(obsname)
409

    
410
    # Create stacked observation
411
    obs_stacked = create_stacked(obs_unbinned, ebins=ebins, edisp=edisp)
412
    #print(obs_stacked)
413
    #print(obs_stacked[0].response())
414

    
415
    # Setup model
416
    models      = gammalib.GModels()
417
    models_full = gammalib.GModels(modelname)
418
    models.append(models_full[srcname])
419

    
420
    # Append model to observations
421
    obs_unbinned.models(models)
422
    obs_stacked.models(models)
423

    
424
    # Compute model cubes
425
    modcube_unbinned = create_modcube(obs_unbinned, ebins=ebins, edisp=edisp)
426
    modcube_stacked  = create_modcube(obs_stacked, ebins=ebins, edisp=edisp)
427

    
428
    # Create residual map
429
    resmap, errmap             = residual_spatial(modcube_stacked, modcube_unbinned)
430
    energies, resspec, errspec = residual_spectral(modcube_stacked, modcube_unbinned)
431

    
432
    # Create figure
433
    fig = plt.figure(figsize=(14,5))
434

    
435
    # Create subplot for residual spectrum
436
    frame1 = fig.add_subplot(131)
437
    plot_resspec(frame1, energies, resspec, errspec)
438

    
439
    # Create subplots for residual profiles
440
    frame2 = fig.add_subplot(232)
441
    frame3 = fig.add_subplot(235)
442
    plot_resmap(frame2, frame3, resmap, errmap)
443

    
444
    # Create subplot for residual map
445
    frame4 = fig.add_subplot(133)
446
    plot_map(frame4, resmap, smooth=0.0)
447

    
448
    # Show figure
449
    plt.show()
450

    
451
    # Return
452
    return
453

    
454

    
455
# ======================== #
456
# Main routine entry point #
457
# ======================== #
458
if __name__ == '__main__':
459

    
460
    # Check if $HESSDATA has been set
461
    if 'HESSDATA' not in os.environ:
462
        print('HESSDATA environment variable not set. Please set HESSDATA to '
463
              'the root directory of the H.E.S.S. data.')
464
        exit(1)
465

    
466
    # Set parameters
467
    obsname   = 'obs_crab_selected.xml'
468
    modelname = 'crab_results_ptsrc_plaw_gauss_grad_hess.xml'
469
    srcname   = 'Crab'
470

    
471
    # Show spill over
472
    show_spill_over(obsname, modelname, srcname, ebins=40, edisp=False)