Source code for gammapy.cube.utils
# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""
Cube analysis utility functions.
"""
from __future__ import absolute_import, division, print_function, unicode_literals
import numpy as np
from ..utils.energy import EnergyBounds
from .core import SkyCube
__all__ = [
'compute_npred_cube',
'compute_npred_cube_simple',
]
[docs]def compute_npred_cube(flux_cube, exposure_cube, ebounds,
integral_resolution=10):
"""Compute predicted counts cube.
Parameters
----------
flux_cube : `SkyCube`
Flux cube, really differential surface brightness in 'cm-2 s-1 TeV-1 sr-1'
exposure_cube : `SkyCube`
Exposure cube
ebounds : `~astropy.units.Quantity`
Energy bounds for the output cube
integral_resolution : int (optional)
Number of integration steps in energy bin when computing integral flux.
Returns
-------
npred_cube : `SkyCube`
Predicted counts cube with energy bounds as given by the input ``ebounds``.
See also
--------
compute_npred_cube_simple
Examples
--------
Load an example dataset::
from gammapy.datasets import FermiGalacticCenter
from gammapy.utils.energy import EnergyBounds
from gammapy.irf import EnergyDependentTablePSF
from gammapy.cube import SkyCube, compute_npred_cube
filenames = FermiGalacticCenter.filenames()
flux_cube = SkyCube.read(filenames['diffuse_model'], format='fermi-background')
exposure_cube = SkyCube.read(filenames['exposure_cube'], format='fermi-exposure')
psf = EnergyDependentTablePSF.read(filenames['psf'])
Compute an ``npred`` cube and a PSF-convolved version::
flux_cube = flux_cube.reproject(exposure_cube)
ebounds = EnergyBounds([10, 30, 100, 500], 'GeV')
npred_cube = compute_npred_cube(flux_cube, exposure_cube, ebounds)
kernels = psf.kernels(npred_cube)
npred_cube_convolved = npred_cube.convolve(kernels)
"""
_validate_inputs(flux_cube, exposure_cube)
# Make an empty cube with the requested energy binning
sky_geom = exposure_cube.sky_image_ref
energies = EnergyBounds(ebounds)
npred_cube = SkyCube.empty_like(sky_geom, energies=energies, unit='', fill=np.nan)
# Process and fill one energy bin at a time
for idx in range(len(ebounds) - 1):
emin, emax = ebounds[idx: idx + 2]
ecenter = np.sqrt(emin * emax)
flux = flux_cube.sky_image_integral(emin, emax, interpolation='linear', nbins=integral_resolution)
exposure = exposure_cube.sky_image(ecenter, interpolation='linear')
solid_angle = exposure.solid_angle()
npred = flux.data * exposure.data * solid_angle
npred_cube.data[idx] = npred.to('')
return npred_cube
[docs]def compute_npred_cube_simple(flux_cube, exposure_cube):
"""Compute predicted counts cube (using a simple method).
* Simply multiplies flux and exposure and pixel solid angle and energy bin width.
* No spatial reprojection, or interpolation or integration in energy.
* This is very fast, but can be inaccurate (e.g. for very large energy bins.)
* If you want a more fancy method, call `compute_npred_cube` instead.
Output cube energy bounds will be the same as for the exposure cube.
Parameters
----------
flux_cube : `SkyCube`
Differential flux cube
exposure_cube : `SkyCube`
Exposure cube
Returns
-------
npred_cube : `SkyCube`
Predicted counts cube
See also
--------
compute_npred_cube
"""
_validate_inputs(flux_cube, exposure_cube)
bin_size = exposure_cube.bin_size
flux = flux_cube.data
exposure = exposure_cube.data
npred = flux * exposure * bin_size
npred_cube = SkyCube.empty_like(exposure_cube)
npred_cube.data = npred.to('')
return npred_cube
def _validate_inputs(flux_cube, exposure_cube):
if flux_cube.data.shape[1:] != exposure_cube.data.shape[1:]:
raise ValueError('flux_cube and exposure cube must have the same shape!\n'
'flux_cube: {0}\nexposure_cube: {1}'
''.format(flux_cube.data.shape[1:], exposure_cube.data.shape[1:]))