Commit 3186c66e81ccba1c3eabdebfbc603ed71196fa1c

Authored by Jürgen Knödlseder
1 parent 48526cfc

Update CTA developed test scripts

inst/cta/test/dev/README.md
... ... @@ -32,16 +32,38 @@ if needed.
32 32 > matplotlib is installed, the simulated photons are shown as
33 33 > a spectrum.
34 34  
  35 +`show_model_mc.py`
  36 +> For a given model, compares Monte Carlo simulation to model
  37 +> ecaluation.
  38 +
  39 +`test_background_integration.py`
  40 +> Test the event simulation using GCTAModelBackground.
  41 +
  42 +`test_cta_bkgcube.py`
  43 +> Test energy integration of GCTABackground3D.
  44 +
35 45 `test_gauss.py`
36 46 > Test Gaussian.
37 47  
  48 +`test_irf_elliptical.py`
  49 +> Test the response computation for elliptical models.
  50 +
38 51 `test_irf_offset.py`
39 52 > Creates images of source models for various offset angles. This
40 53 > tests the IRF variation with offset angle.
41 54  
  55 +`test_irf_radial.py`
  56 +> Test the response computation for radial models.
  57 +
42 58 `test_irf_trafo.py`
43 59 > Test coordinate transformations for IRF computation.
44 60  
  61 +`test_likelihood_profile.py`
  62 +> Performs likelihood profile computation.
  63 +
  64 +`test_ml_fitting.py`
  65 +> Performs a binned maximum likelihood analysis.
  66 +
45 67 `test_model.py`
46 68 > Creates images of sources models convolved with the CTA instrument
47 69 > response function. Also allows the creation of gradient images.
... ... @@ -49,15 +71,27 @@ if needed.
49 71 `test_npred_computation.py`
50 72 > Test the Npred computation of the CTA response.
51 73  
  74 +`test_npred_elliptical.py`
  75 +> Test the Npred computation of the CTA response for elliptical models.
  76 +
52 77 `test_npred_integration.py`
53 78 > Compare numerical to analytical Npred computation for CTA response.
54 79  
  80 +`test_psf_radial.py`
  81 +> Tests the radial response computation.
  82 +
  83 +`test_psf_shape.py`
  84 +> Simulates the PSF distribution.
  85 +
55 86 `test_radial_acceptance.py`
56 87 > Displays the various radial acceptance models.
57 88  
58 89 `test_response_table.py`
59 90 > Display CTA response table.
60 91  
  92 +`test_shell.py`
  93 +> Shows the shell model radial distribution.
  94 +
61 95 `test_sim_edisp.py`
62 96 > Compares energy dispersion simulation to energy dispersion
63 97 > model.
... ...
inst/cta/test/dev/show_model_mc.py 0 → 100755
  1 +#! /usr/bin/env python
  2 +# ==========================================================================
  3 +# Show simulation - model for a given 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 +from cscripts import obsutils
  27 +import matplotlib.pyplot as plt
  28 +
  29 +
  30 +# ====================== #
  31 +# Plot residual spectrum #
  32 +# ====================== #
  33 +def plot_resspec(frame, energies, resspec, errspec, emin=0.1, emax=100.0):
  34 + """
  35 + Plot residual spectrum
  36 +
  37 + Parameters
  38 + ----------
  39 + frame : pyplot
  40 + Frame for spectrum
  41 + """
  42 + # Set axes scales and limit
  43 + frame.set_xscale('log')
  44 + frame.set_xlim([emin, emax])
  45 +
  46 + # Counts and model
  47 + frame.errorbar(energies, resspec, yerr=errspec,
  48 + fmt='ko', capsize=0, linewidth=2, zorder=2, label='Data')
  49 + frame.plot(frame.get_xlim(),[0,0], 'r-')
  50 + frame.set_xlabel('Energy (TeV)')
  51 + frame.set_ylabel('Simulation - Model')
  52 +
  53 + # Return
  54 + return
  55 +
  56 +
  57 +# ================= #
  58 +# Plot residual map #
  59 +# ================= #
  60 +def plot_resmap(plt1, plt2, map, error, steps=1):
  61 + """
  62 + Plot pull histogram
  63 +
  64 + Parameters
  65 + ----------
  66 + plt1 : pyplot
  67 + Frame for first map
  68 + plt2 : pyplot
  69 + Frame for second map
  70 + map : `~gammalib.GSkyMap()`
  71 + Sky map
  72 + error : `~gammalib.GSkyMap()`
  73 + Sky map
  74 + steps : int
  75 + Number of steps for rebinning
  76 + """
  77 + # Create longitude array from skymap
  78 + x_lon = []
  79 + y_lon = []
  80 + e_lon = []
  81 + for ix in range(0, map.nx(), steps):
  82 + value = 0.0
  83 + err = 0.0
  84 + for istep in range(steps):
  85 + if istep+ix < map.nx():
  86 + for iy in range(map.ny()):
  87 + index = istep+ix+iy*map.nx()
  88 + value += map[index]
  89 + err += error[index]*error[index]
  90 + x_lon.append(ix)
  91 + y_lon.append(value)
  92 + e_lon.append(math.sqrt(err))
  93 +
  94 + # Create latitude array from skymap
  95 + x_lat = []
  96 + y_lat = []
  97 + e_lat = []
  98 + for iy in range(0, map.ny(), steps):
  99 + value = 0.0
  100 + err = 0.0
  101 + for istep in range(steps):
  102 + if istep+iy < map.ny():
  103 + for ix in range(map.nx()):
  104 + index = ix+(istep+iy)*map.nx()
  105 + value += map[index]
  106 + err += error[index]*error[index]
  107 + x_lat.append(iy)
  108 + y_lat.append(value)
  109 + e_lat.append(math.sqrt(err))
  110 +
  111 + # Plot longitude distribution
  112 + plt1.errorbar(x_lon, y_lon, yerr=e_lon,
  113 + fmt='ko', capsize=0, linewidth=2, zorder=2)
  114 + plt1.axhline(0, color='r', linestyle='--')
  115 + plt1.set_xlabel('Right Ascension (pixels)')
  116 + plt1.set_ylabel('Simulation - Model')
  117 + plt1.grid(True)
  118 +
  119 + # Plot latitude distribution
  120 + plt2.errorbar(x_lat, y_lat, yerr=e_lat,
  121 + fmt='ko', capsize=0, linewidth=2, zorder=2)
  122 + plt2.axhline(0, color='r', linestyle='--')
  123 + plt2.set_xlabel('Declination (pixels)')
  124 + plt2.set_ylabel('Simulation - Model')
  125 + plt2.grid(True)
  126 +
  127 + # Return
  128 + return
  129 +
  130 +
  131 +# ======== #
  132 +# Plot map #
  133 +# ======== #
  134 +def plot_map(frame, map, smooth=0.0):
  135 + """
  136 + Plot Aitoff map
  137 +
  138 + Parameters
  139 + ----------
  140 + frame : pyplot
  141 + Frame for map
  142 + map : `~gammalib.GSkyMap()`
  143 + Sky map
  144 + smooth : float, optional
  145 + Map smoothing parameter (degrees)
  146 + """
  147 + # Optionally smooth map
  148 + if smooth > 0.0:
  149 + _map = map.copy()
  150 + _map.smooth('DISK', smooth)
  151 + else:
  152 + _map = map
  153 +
  154 + # Create array from skymap
  155 + array = []
  156 + v_max = 0.0
  157 + for iy in range(_map.ny()):
  158 + row = []
  159 + for ix in range(_map.nx()):
  160 + index = ix+iy*_map.nx()
  161 + value = _map[index]
  162 + row.append(value)
  163 + array.append(row)
  164 +
  165 + # Show Aitoff projection
  166 + c = frame.imshow(array, aspect=1.0)
  167 + cbar = plt.colorbar(c, orientation='vertical', shrink=0.7)
  168 + frame.grid(True)
  169 + frame.set_xlabel('Right Ascension (pixels)')
  170 + frame.set_ylabel('Declination (pixels)')
  171 +
  172 + # Return
  173 + return
  174 +
  175 +
  176 +# =========================== #
  177 +# Determine spatial residuals #
  178 +# =========================== #
  179 +def residual_spatial(countscube, modelcube):
  180 + """
  181 + Determine spatial residuals
  182 +
  183 + Parameters
  184 + ----------
  185 + countscube : `~gammalib.GCTAEventCube`
  186 + Simulated counts cube
  187 + modelcube : `~gammalib.GCTAEventCube`
  188 + Model cube
  189 +
  190 + Returns
  191 + -------
  192 + map, error : `~gammalib.GSkyMap()`
  193 + Residual sky map and error
  194 + """
  195 + # Get model cube maps
  196 + map1 = countscube.counts()
  197 + map2 = modelcube.counts()
  198 +
  199 + # Generate residual map
  200 + map = map1 - map2
  201 + map.stack_maps()
  202 +
  203 + # Generate residual error bars
  204 + error = map2.copy()
  205 + error.stack_maps()
  206 + error = error.sqrt()
  207 +
  208 + # Return residual map and error map
  209 + return map, error
  210 +
  211 +
  212 +# ============================ #
  213 +# Determine spectral residuals #
  214 +# ============================ #
  215 +def residual_spectral(countscube, modelcube):
  216 + """
  217 + Determine spectral residuals
  218 +
  219 + Parameters
  220 + ----------
  221 + countscube : `~gammalib.GCTAEventCube`
  222 + Simulated counts cube
  223 + modelcube : `~gammalib.GCTAEventCube`
  224 + Model cube
  225 +
  226 + Returns
  227 + -------
  228 + map, error : list
  229 + Residual vector
  230 + """
  231 + # Get model cube maps
  232 + map1 = countscube.counts()
  233 + map2 = modelcube.counts()
  234 +
  235 + # Compute spectra
  236 + spec1 = []
  237 + spec2 = []
  238 + residual = []
  239 + error = []
  240 + energies = []
  241 + for ieng in range(map1.nmaps()):
  242 + sum1 = 0.0
  243 + sum2 = 0.0
  244 + for ipix in range(map1.npix()):
  245 + sum1 += map1[ipix, ieng]
  246 + sum2 += map2[ipix, ieng]
  247 + spec1.append(sum1)
  248 + spec2.append(sum2)
  249 + residual.append(sum1 - sum2)
  250 + error.append(math.sqrt(sum2))
  251 + energies.append(modelcube.energy(ieng).TeV())
  252 +
  253 + # Return residual and error
  254 + return energies, residual, error
  255 +
  256 +
  257 +# ==================== #
  258 +# Simulate counts cube #
  259 +# ==================== #
  260 +def simulate_counts_cube(obs, ra=83.63, dec=22.01, npix=50, binsz=0.02,
  261 + emin=0.1, emax=100.0, ebins=20, seed=1, edisp=False):
  262 + """
  263 + Simulate counts cube
  264 +
  265 + Parameters
  266 + ----------
  267 + obs : `~gammalib.GObservations`
  268 + Observation container
  269 + ebins : int, optional
  270 + Number of energy bins for binned or stacked analysis
  271 + edisp : boolean, optional
  272 + Use energy dispersion
  273 + """
  274 + # Simulate events
  275 + ctobssim = ctools.ctobssim(obs)
  276 + ctobssim['seed'] = seed
  277 + ctobssim['edisp'] = edisp
  278 + ctobssim.run()
  279 +
  280 + # Create counts cube
  281 + ctbin = ctools.ctbin(ctobssim.obs())
  282 + ctbin['stack'] = True
  283 + ctbin['ebinalg'] = 'LOG'
  284 + ctbin['emin'] = emin
  285 + ctbin['emax'] = emax
  286 + ctbin['enumbins'] = ebins
  287 + ctbin['coordsys'] = 'CEL'
  288 + ctbin['proj'] = 'CAR'
  289 + ctbin['xref'] = ra
  290 + ctbin['yref'] = dec
  291 + ctbin['nxpix'] = npix
  292 + ctbin['nypix'] = npix
  293 + ctbin['binsz'] = binsz
  294 + ctbin.run()
  295 +
  296 + # Return counts cube
  297 + return ctbin.cube().copy()
  298 +
  299 +
  300 +# ================= #
  301 +# Create model cube #
  302 +# ================= #
  303 +def create_model_cube(obs, countscube, edisp=False):
  304 + """
  305 + Create model cube
  306 +
  307 + Parameters
  308 + ----------
  309 + obs : `~gammalib.GObservations`
  310 + Observation container
  311 + countscube : `~gammalib.GCTAEventCube`
  312 + Counts cube for binning
  313 + edisp : boolean, optional
  314 + Use energy dispersion
  315 + """
  316 + # Create model cube
  317 + ctmodel = ctools.ctmodel(obs)
  318 + ctmodel.cube(countscube)
  319 + ctmodel['edisp'] = edisp
  320 + ctmodel.run()
  321 +
  322 + # Return model cube
  323 + return ctmodel.cube().copy()
  324 +
  325 +
  326 +# ================= #
  327 +# Show model and MC #
  328 +# ================= #
  329 +def show_model_mc(modelname, duration=180000.0, caldb='prod2', irf='South_50h',
  330 + ebins=20, edisp=False):
  331 + """
  332 + """
  333 + # Set pointing direction
  334 + pntdir = gammalib.GSkyDir()
  335 + pntdir.radec_deg(83.63, 22.01)
  336 +
  337 + # Set single CTA observation
  338 + run = obsutils.set_obs(pntdir, duration=duration, caldb=caldb, irf=irf)
  339 +
  340 + # Set observation container
  341 + obs = gammalib.GObservations()
  342 + obs.append(run)
  343 +
  344 + # Load and append model
  345 + models = gammalib.GModels(modelname)
  346 + obs.models(models)
  347 +
  348 + # Create simulated counts cube
  349 + countscube = simulate_counts_cube(obs, npix=400, binsz=0.002, ebins=ebins,
  350 + edisp=edisp)
  351 + print(countscube)
  352 +
  353 + # Create model cube
  354 + modelcube = create_model_cube(obs, countscube, edisp=edisp)
  355 + print(modelcube)
  356 +
  357 + # Create residual map and spectrum
  358 + resmap, errmap = residual_spatial(countscube, modelcube)
  359 + energies, resspec, errspec = residual_spectral(countscube, modelcube)
  360 +
  361 + # Create figure
  362 + fig = plt.figure(figsize=(14,5))
  363 +
  364 + # Create subplot for residual spectrum
  365 + frame1 = fig.add_subplot(131)
  366 + plot_resspec(frame1, energies, resspec, errspec, emin=0.05, emax=150.0)
  367 +
  368 + # Create subplots for residual profiles
  369 + frame2 = fig.add_subplot(232)
  370 + frame3 = fig.add_subplot(235)
  371 + plot_resmap(frame2, frame3, resmap, errmap, steps=5)
  372 +
  373 + # Create subplot for residual map
  374 + frame4 = fig.add_subplot(133)
  375 + plot_map(frame4, resmap, smooth=0.02)
  376 +
  377 + # Show figure
  378 + plt.show()
  379 +
  380 + # Return
  381 + return
  382 +
  383 +
  384 +# ======================== #
  385 +# Main routine entry point #
  386 +# ======================== #
  387 +if __name__ == '__main__':
  388 +
  389 + # Set model name
  390 + modelname = 'crab.xml'
  391 +
  392 + # Show model and MC
  393 + #show_model_mc(modelname, ebins=50, edisp=False)
  394 + show_model_mc(modelname, ebins=50, edisp=True)
... ...
inst/cta/test/dev/test_background_integration.py
1 1 #! /usr/bin/env python
2 2 # ==========================================================================
3   -# This energy integration of GCTABackground3D
  3 +# Test energy integration of GCTABackground3D
4 4 #
5 5 # Copyright (C) 2017 Juergen Knoedlseder
6 6 #
... ...