.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "tutorials/api/models.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. or to run this example in your browser via Binder .. rst-class:: sphx-glr-example-title .. _sphx_glr_tutorials_api_models.py: Models ====== This is an introduction and overview on how to work with models in Gammapy. The sub-package `~gammapy.modeling` contains all the functionality related to modeling and fitting data. This includes spectral, spatial and temporal model classes, as well as the fit and parameter API.The models follow a naming scheme which contains the category as a suffix to the class name. An overview of all the available models can be found in the :ref:`model-gallery`. Note that there are separate tutorials, :doc:`/tutorials/api/model_management` and :doc:`/tutorials/api/fitting` that explains about `~gammapy.modeling`, the Gammapy modeling and fitting framework. You have to read that to learn how to work with models in order to analyse data. .. GENERATED FROM PYTHON SOURCE LINES 24-27 Setup ----- .. GENERATED FROM PYTHON SOURCE LINES 27-35 .. code-block:: Python # %matplotlib inline import numpy as np from astropy import units as u import matplotlib.pyplot as plt from IPython.display import display from gammapy.maps import Map, MapAxis, WcsGeom .. GENERATED FROM PYTHON SOURCE LINES 36-38 Check setup ----------- .. GENERATED FROM PYTHON SOURCE LINES 38-43 .. code-block:: Python from gammapy.utils.check import check_tutorials_setup check_tutorials_setup() .. rst-class:: sphx-glr-script-out .. code-block:: none System: python_executable : /home/runner/work/gammapy-docs/gammapy-docs/gammapy/.tox/build_docs/bin/python python_version : 3.9.19 machine : x86_64 system : Linux Gammapy package: version : 1.3.dev241+g0271bebfc path : /home/runner/work/gammapy-docs/gammapy-docs/gammapy/.tox/build_docs/lib/python3.9/site-packages/gammapy Other packages: numpy : 1.26.4 scipy : 1.13.0 astropy : 5.2.2 regions : 0.8 click : 8.1.7 yaml : 6.0.1 IPython : 8.18.1 jupyterlab : not installed matplotlib : 3.8.4 pandas : not installed healpy : 1.16.6 iminuit : 2.25.2 sherpa : 4.16.0 naima : 0.10.0 emcee : 3.1.6 corner : 2.2.2 ray : 2.20.0 Gammapy environment variables: GAMMAPY_DATA : /home/runner/work/gammapy-docs/gammapy-docs/gammapy-datasets/dev .. GENERATED FROM PYTHON SOURCE LINES 44-50 Spectral models --------------- All models are imported from the `~gammapy.modeling.models` namespace. Let’s start with a `~gammapy.modeling.models.PowerLawSpectralModel`: .. GENERATED FROM PYTHON SOURCE LINES 50-57 .. code-block:: Python from gammapy.modeling.models import PowerLawSpectralModel pwl = PowerLawSpectralModel() print(pwl) .. rst-class:: sphx-glr-script-out .. code-block:: none PowerLawSpectralModel type name value unit error ... frozen is_norm link prior ---- --------- ---------- -------------- --------- ... ------ ------- ---- ----- index 2.0000e+00 0.000e+00 ... False False amplitude 1.0000e-12 cm-2 s-1 TeV-1 0.000e+00 ... False True reference 1.0000e+00 TeV 0.000e+00 ... True False .. GENERATED FROM PYTHON SOURCE LINES 58-61 To get a list of all available spectral models you can import and print the spectral model registry or take a look at the :ref:`model-gallery` .. GENERATED FROM PYTHON SOURCE LINES 61-67 .. code-block:: Python from gammapy.modeling.models import SPECTRAL_MODEL_REGISTRY print(SPECTRAL_MODEL_REGISTRY) .. rst-class:: sphx-glr-script-out .. code-block:: none Registry -------- ConstantSpectralModel : ['ConstantSpectralModel', 'const'] CompoundSpectralModel : ['CompoundSpectralModel', 'compound'] PowerLawSpectralModel : ['PowerLawSpectralModel', 'pl'] PowerLaw2SpectralModel : ['PowerLaw2SpectralModel', 'pl-2'] BrokenPowerLawSpectralModel : ['BrokenPowerLawSpectralModel', 'bpl'] SmoothBrokenPowerLawSpectralModel : ['SmoothBrokenPowerLawSpectralModel', 'sbpl'] PiecewiseNormSpectralModel : ['PiecewiseNormSpectralModel', 'piecewise-norm'] ExpCutoffPowerLawSpectralModel : ['ExpCutoffPowerLawSpectralModel', 'ecpl'] ExpCutoffPowerLaw3FGLSpectralModel : ['ExpCutoffPowerLaw3FGLSpectralModel', 'ecpl-3fgl'] SuperExpCutoffPowerLaw3FGLSpectralModel : ['SuperExpCutoffPowerLaw3FGLSpectralModel', 'secpl-3fgl'] SuperExpCutoffPowerLaw4FGLDR3SpectralModel: ['SuperExpCutoffPowerLaw4FGLDR3SpectralModel', 'secpl-4fgl-dr3'] SuperExpCutoffPowerLaw4FGLSpectralModel : ['SuperExpCutoffPowerLaw4FGLSpectralModel', 'secpl-4fgl'] LogParabolaSpectralModel : ['LogParabolaSpectralModel', 'lp'] TemplateSpectralModel : ['TemplateSpectralModel', 'template'] TemplateNDSpectralModel : ['TemplateNDSpectralModel', 'templateND'] GaussianSpectralModel : ['GaussianSpectralModel', 'gauss'] EBLAbsorptionNormSpectralModel : ['EBLAbsorptionNormSpectralModel', 'ebl-norm'] NaimaSpectralModel : ['NaimaSpectralModel', 'naima'] ScaleSpectralModel : ['ScaleSpectralModel', 'scale'] PowerLawNormSpectralModel : ['PowerLawNormSpectralModel', 'pl-norm'] LogParabolaNormSpectralModel : ['LogParabolaNormSpectralModel', 'lp-norm'] ExpCutoffPowerLawNormSpectralModel : ['ExpCutoffPowerLawNormSpectralModel', 'ecpl-norm'] DarkMatterAnnihilationSpectralModel : ['DarkMatterAnnihilationSpectralModel', 'dm-annihilation'] DarkMatterDecaySpectralModel : ['DarkMatterDecaySpectralModel', 'dm-decay'] .. GENERATED FROM PYTHON SOURCE LINES 68-73 Spectral models all come with default parameters. Different parameter values can be passed on creation of the model, either as a string defining the value and unit or as an `astropy.units.Quantity` object directly: .. GENERATED FROM PYTHON SOURCE LINES 73-78 .. code-block:: Python amplitude = 1e-12 * u.Unit("TeV-1 cm-2 s-1") pwl = PowerLawSpectralModel(amplitude=amplitude, index=2.2) .. GENERATED FROM PYTHON SOURCE LINES 79-82 For convenience a `str` specifying the value and unit can be passed as well: .. GENERATED FROM PYTHON SOURCE LINES 82-87 .. code-block:: Python pwl = PowerLawSpectralModel(amplitude="2.7e-12 TeV-1 cm-2 s-1", index=2.2) print(pwl) .. rst-class:: sphx-glr-script-out .. code-block:: none PowerLawSpectralModel type name value unit error ... frozen is_norm link prior ---- --------- ---------- -------------- --------- ... ------ ------- ---- ----- index 2.2000e+00 0.000e+00 ... False False amplitude 2.7000e-12 cm-2 s-1 TeV-1 0.000e+00 ... False True reference 1.0000e+00 TeV 0.000e+00 ... True False .. GENERATED FROM PYTHON SOURCE LINES 88-91 The model can be evaluated at given energies by calling the model instance: .. GENERATED FROM PYTHON SOURCE LINES 91-97 .. code-block:: Python energy = [1, 3, 10, 30] * u.TeV dnde = pwl(energy) print(dnde) .. rst-class:: sphx-glr-script-out .. code-block:: none [2.70000000e-12 2.40822469e-13 1.70358483e-14 1.51948705e-15] 1 / (cm2 s TeV) .. GENERATED FROM PYTHON SOURCE LINES 98-103 The returned quantity is a differential photon flux. For spectral models you can additionally compute the integrated and energy flux in a given energy range: .. GENERATED FROM PYTHON SOURCE LINES 103-111 .. code-block:: Python flux = pwl.integral(energy_min=1 * u.TeV, energy_max=10 * u.TeV) print(flux) eflux = pwl.energy_flux(energy_min=1 * u.TeV, energy_max=10 * u.TeV) print(eflux) .. rst-class:: sphx-glr-script-out .. code-block:: none 2.108034597491956e-12 1 / (cm2 s) 4.982075849517389e-12 TeV / (cm2 s) .. GENERATED FROM PYTHON SOURCE LINES 112-114 This also works for a list or an array of integration boundaries: .. GENERATED FROM PYTHON SOURCE LINES 114-120 .. code-block:: Python energy = [1, 3, 10, 30] * u.TeV flux = pwl.integral(energy_min=energy[:-1], energy_max=energy[1:]) print(flux) .. rst-class:: sphx-glr-script-out .. code-block:: none [1.64794383e-12 4.60090769e-13 1.03978226e-13] 1 / (cm2 s) .. GENERATED FROM PYTHON SOURCE LINES 121-124 In some cases it can be useful to find use the inverse of a spectral model, to find the energy at which a given flux is reached: .. GENERATED FROM PYTHON SOURCE LINES 124-130 .. code-block:: Python dnde = 2.7e-12 * u.Unit("TeV-1 cm-2 s-1") energy = pwl.inverse(dnde) print(energy) .. rst-class:: sphx-glr-script-out .. code-block:: none 1.0 TeV .. GENERATED FROM PYTHON SOURCE LINES 131-134 As a convenience you can also plot any spectral model in a given energy range: .. GENERATED FROM PYTHON SOURCE LINES 134-139 .. code-block:: Python pwl.plot(energy_bounds=[1, 100] * u.TeV) plt.show() .. image-sg:: /tutorials/api/images/sphx_glr_models_001.png :alt: models :srcset: /tutorials/api/images/sphx_glr_models_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 140-143 Norm Spectral Models ~~~~~~~~~~~~~~~~~~~~ .. GENERATED FROM PYTHON SOURCE LINES 146-157 Normed spectral models are a special class of Spectral Models, which have a dimension-less normalisation. These spectral models feature a norm parameter instead of amplitude and are named using the `NormSpectralModel` suffix. They **must** be used along with another spectral model, as a multiplicative correction factor according to their spectral shape. They can be typically used for adjusting template based models, or adding a EBL correction to some analytic model. To check if a given `~gammapy.modeling.models.SpectralModel` is a norm model, you can simply look at the `is_norm_spectral_model` property .. GENERATED FROM PYTHON SOURCE LINES 157-164 .. code-block:: Python # To see the available norm models shipped with gammapy: for model in SPECTRAL_MODEL_REGISTRY: if model.is_norm_spectral_model: print(model) .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 165-167 As an example, we see the `~gammapy.modeling.models.PowerLawNormSpectralModel` .. GENERATED FROM PYTHON SOURCE LINES 167-174 .. code-block:: Python from gammapy.modeling.models import PowerLawNormSpectralModel pwl_norm = PowerLawNormSpectralModel(tilt=0.1) print(pwl_norm) .. rst-class:: sphx-glr-script-out .. code-block:: none PowerLawNormSpectralModel type name value unit error min max frozen is_norm link prior ---- --------- ---------- ---- --------- --- --- ------ ------- ---- ----- norm 1.0000e+00 0.000e+00 nan nan False True tilt 1.0000e-01 0.000e+00 nan nan True False reference 1.0000e+00 TeV 0.000e+00 nan nan True False .. GENERATED FROM PYTHON SOURCE LINES 175-177 We can check the correction introduced at each energy .. GENERATED FROM PYTHON SOURCE LINES 177-182 .. code-block:: Python energy = [0.3, 1, 3, 10, 30] * u.TeV print(pwl_norm(energy)) .. rst-class:: sphx-glr-script-out .. code-block:: none [1.12794487 1. 0.89595846 0.79432823 0.7116851 ] .. GENERATED FROM PYTHON SOURCE LINES 183-187 A typical use case of a norm model would be in applying spectral correction to a `~gammapy.modeling.models.TemplateSpectralModel`. A template model is defined by custom tabular values provided at initialization. .. GENERATED FROM PYTHON SOURCE LINES 187-200 .. code-block:: Python from gammapy.modeling.models import TemplateSpectralModel energy = [0.3, 1, 3, 10, 30] * u.TeV values = [40, 30, 20, 10, 1] * u.Unit("TeV-1 s-1 cm-2") template = TemplateSpectralModel(energy, values) template.plot(energy_bounds=[0.2, 50] * u.TeV, label="template model") normed_template = template * pwl_norm normed_template.plot(energy_bounds=[0.2, 50] * u.TeV, label="normed_template model") plt.legend() plt.show() .. image-sg:: /tutorials/api/images/sphx_glr_models_002.png :alt: models :srcset: /tutorials/api/images/sphx_glr_models_002.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 201-208 Compound Spectral Model ~~~~~~~~~~~~~~~~~~~~~~~ A `CompoundSpectralModel` is an arithmetic combination of two spectral models. The model `normed_template` created in the preceding example is an example of a `CompoundSpectralModel` .. GENERATED FROM PYTHON SOURCE LINES 208-212 .. code-block:: Python print(normed_template) .. rst-class:: sphx-glr-script-out .. code-block:: none CompoundSpectralModel Component 1 : TemplateSpectralModel Component 2 : PowerLawNormSpectralModel type name value unit error min max frozen is_norm link prior ---- --------- ---------- ---- --------- --- --- ------ ------- ---- ----- norm 1.0000e+00 0.000e+00 nan nan False True tilt 1.0000e-01 0.000e+00 nan nan True False reference 1.0000e+00 TeV 0.000e+00 nan nan True False Operator : mul .. GENERATED FROM PYTHON SOURCE LINES 213-215 To create an additive model, you can do simply: .. GENERATED FROM PYTHON SOURCE LINES 215-220 .. code-block:: Python model_add = pwl + template print(model_add) .. rst-class:: sphx-glr-script-out .. code-block:: none CompoundSpectralModel Component 1 : PowerLawSpectralModel type name value unit error ... frozen is_norm link prior ---- --------- ---------- -------------- --------- ... ------ ------- ---- ----- index 2.2000e+00 0.000e+00 ... False False amplitude 2.7000e-12 cm-2 s-1 TeV-1 0.000e+00 ... False True reference 1.0000e+00 TeV 0.000e+00 ... True False Component 2 : TemplateSpectralModel Operator : add .. GENERATED FROM PYTHON SOURCE LINES 221-224 Spatial models -------------- .. GENERATED FROM PYTHON SOURCE LINES 227-230 Spatial models are imported from the same `~gammapy.modeling.models` namespace, let’s start with a `~gammapy.modeling.models.GaussianSpatialModel`: .. GENERATED FROM PYTHON SOURCE LINES 230-237 .. code-block:: Python from gammapy.modeling.models import GaussianSpatialModel gauss = GaussianSpatialModel(lon_0="0 deg", lat_0="0 deg", sigma="0.2 deg") print(gauss) .. rst-class:: sphx-glr-script-out .. code-block:: none GaussianSpatialModel type name value unit error ... max frozen is_norm link prior ---- ----- ---------- ---- --------- ... --------- ------ ------- ---- ----- lon_0 0.0000e+00 deg 0.000e+00 ... nan False False lat_0 0.0000e+00 deg 0.000e+00 ... 9.000e+01 False False sigma 2.0000e-01 deg 0.000e+00 ... nan False False e 0.0000e+00 0.000e+00 ... 1.000e+00 True False phi 0.0000e+00 deg 0.000e+00 ... nan True False .. GENERATED FROM PYTHON SOURCE LINES 238-241 Again you can check the `SPATIAL_MODELS` registry to see which models are available or take a look at the :ref:`model-gallery` .. GENERATED FROM PYTHON SOURCE LINES 241-247 .. code-block:: Python from gammapy.modeling.models import SPATIAL_MODEL_REGISTRY print(SPATIAL_MODEL_REGISTRY) .. rst-class:: sphx-glr-script-out .. code-block:: none Registry -------- ConstantSpatialModel : ['ConstantSpatialModel', 'const'] TemplateSpatialModel : ['TemplateSpatialModel', 'template'] TemplateNDSpatialModel : ['TemplateNDSpatialModel', 'templateND'] DiskSpatialModel : ['DiskSpatialModel', 'disk'] GaussianSpatialModel : ['GaussianSpatialModel', 'gauss'] GeneralizedGaussianSpatialModel: ['GeneralizedGaussianSpatialModel', 'gauss-general'] PiecewiseNormSpatialModel : ['PiecewiseNormSpatialModel', 'piecewise-norm'] PointSpatialModel : ['PointSpatialModel', 'point'] ShellSpatialModel : ['ShellSpatialModel', 'shell'] Shell2SpatialModel : ['Shell2SpatialModel', 'shell2'] .. GENERATED FROM PYTHON SOURCE LINES 248-251 The default coordinate frame for all spatial models is `"icrs"`, but the frame can be modified using the `frame` argument: .. GENERATED FROM PYTHON SOURCE LINES 251-257 .. code-block:: Python gauss = GaussianSpatialModel( lon_0="0 deg", lat_0="0 deg", sigma="0.2 deg", frame="galactic" ) .. GENERATED FROM PYTHON SOURCE LINES 258-262 You can specify any valid `astropy.coordinates` frame. The center position of the model can be retrieved as a `astropy.coordinates.SkyCoord` object using `SpatialModel.position`: .. GENERATED FROM PYTHON SOURCE LINES 262-266 .. code-block:: Python print(gauss.position) .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 267-269 Spatial models can be evaluated again by calling the instance: .. GENERATED FROM PYTHON SOURCE LINES 269-277 .. code-block:: Python lon = [0, 0.1] * u.deg lat = [0, 0.1] * u.deg flux_per_omega = gauss(lon, lat) print(flux_per_omega) .. rst-class:: sphx-glr-script-out .. code-block:: none [13061.88470839 10172.60603928] 1 / sr .. GENERATED FROM PYTHON SOURCE LINES 278-282 The returned quantity corresponds to a surface brightness. Spatial model can be also evaluated using `~gammapy.maps.Map` and `~gammapy.maps.Geom` objects: .. GENERATED FROM PYTHON SOURCE LINES 282-289 .. code-block:: Python m = Map.create(skydir=(0, 0), width=(1, 1), binsz=0.02, frame="galactic") m.quantity = gauss.evaluate_geom(m.geom) m.plot(add_cbar=True) plt.show() .. image-sg:: /tutorials/api/images/sphx_glr_models_003.png :alt: models :srcset: /tutorials/api/images/sphx_glr_models_003.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 290-292 Again for convenience the model can be plotted directly: .. GENERATED FROM PYTHON SOURCE LINES 292-296 .. code-block:: Python gauss.plot(add_cbar=True) plt.show() .. image-sg:: /tutorials/api/images/sphx_glr_models_004.png :alt: models :srcset: /tutorials/api/images/sphx_glr_models_004.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 297-301 All spatial models have an associated sky region to it e.g. to illustrate the extension of the model on a sky image. The returned object is an `~regions.SkyRegion` object: .. GENERATED FROM PYTHON SOURCE LINES 301-305 .. code-block:: Python print(gauss.to_region()) .. rst-class:: sphx-glr-script-out .. code-block:: none Region: EllipseSkyRegion center: width: 0.6000000000000001 deg height: 0.6000000000000001 deg angle: 0.0 deg .. GENERATED FROM PYTHON SOURCE LINES 306-308 Now we can plot the region on a sky image: .. GENERATED FROM PYTHON SOURCE LINES 308-321 .. code-block:: Python plt.figure() gauss_elongated = GaussianSpatialModel( lon_0="0 deg", lat_0="0 deg", sigma="0.2 deg", e=0.7, phi="45 deg" ) ax = gauss_elongated.plot(add_cbar=True) region = gauss_elongated.to_region() region_pix = region.to_pixel(ax.wcs) ax.add_artist(region_pix.as_artist(ec="w", fc="None")) plt.show() .. image-sg:: /tutorials/api/images/sphx_glr_models_005.png :alt: models :srcset: /tutorials/api/images/sphx_glr_models_005.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 322-325 The `~gammapy.modeling.models.SpatialModel.to_region()` method can also be useful to write e.g. ds9 region files using `write_ds9` from the `regions` package: .. GENERATED FROM PYTHON SOURCE LINES 325-340 .. code-block:: Python from regions import Regions regions = Regions([gauss.to_region(), gauss_elongated.to_region()]) filename = "regions.reg" regions.write( filename, format="ds9", overwrite=True, ) # !cat regions.reg .. GENERATED FROM PYTHON SOURCE LINES 341-344 Temporal models --------------- .. GENERATED FROM PYTHON SOURCE LINES 347-350 Temporal models are imported from the same `~gammapy.modeling.models` namespace, let’s start with a `~gammapy.modeling.models.GaussianTemporalModel`: .. GENERATED FROM PYTHON SOURCE LINES 350-357 .. code-block:: Python from gammapy.modeling.models import GaussianTemporalModel gauss_temp = GaussianTemporalModel(t_ref=59240.0 * u.d, sigma=2.0 * u.d) print(gauss_temp) .. rst-class:: sphx-glr-script-out .. code-block:: none GaussianTemporalModel type name value unit error min max frozen is_norm link prior ---- ----- ---------- ---- --------- --- --- ------ ------- ---- ----- t_ref 5.9240e+04 d 0.000e+00 nan nan False False sigma 2.0000e+00 d 0.000e+00 nan nan False False .. GENERATED FROM PYTHON SOURCE LINES 358-361 To check the `TEMPORAL_MODELS` registry to see which models are available: .. GENERATED FROM PYTHON SOURCE LINES 361-367 .. code-block:: Python from gammapy.modeling.models import TEMPORAL_MODEL_REGISTRY print(TEMPORAL_MODEL_REGISTRY) .. rst-class:: sphx-glr-script-out .. code-block:: none Registry -------- ConstantTemporalModel : ['ConstantTemporalModel', 'const'] LinearTemporalModel : ['LinearTemporalModel', 'linear'] LightCurveTemplateTemporalModel : ['LightCurveTemplateTemporalModel', 'template'] ExpDecayTemporalModel : ['ExpDecayTemporalModel', 'exp-decay'] GaussianTemporalModel : ['GaussianTemporalModel', 'gauss'] GeneralizedGaussianTemporalModel: ['GeneralizedGaussianTemporalModel', 'gengauss'] PowerLawTemporalModel : ['PowerLawTemporalModel', 'powerlaw'] SineTemporalModel : ['SineTemporalModel', 'sinus'] TemplatePhaseCurveTemporalModel : ['TemplatePhaseCurveTemporalModel', 'template-phase'] .. GENERATED FROM PYTHON SOURCE LINES 368-371 Temporal models can be evaluated on `astropy.time.Time` objects. The returned quantity is a dimensionless number .. GENERATED FROM PYTHON SOURCE LINES 371-378 .. code-block:: Python from astropy.time import Time time = Time("2021-01-29 00:00:00.000") gauss_temp(time) .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 379-381 As for other models, they can be plotted in a given time range .. GENERATED FROM PYTHON SOURCE LINES 381-387 .. code-block:: Python time = Time([59233.0, 59250], format="mjd") gauss_temp.plot(time) plt.show() .. image-sg:: /tutorials/api/images/sphx_glr_models_006.png :alt: models :srcset: /tutorials/api/images/sphx_glr_models_006.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 388-395 SkyModel -------- The `~gammapy.modeling.models.SkyModel` class combines a spectral, and optionally, a spatial model and a temporal. It can be created from existing spectral, spatial and temporal model components: .. GENERATED FROM PYTHON SOURCE LINES 395-407 .. code-block:: Python from gammapy.modeling.models import SkyModel model = SkyModel( spectral_model=pwl, spatial_model=gauss, temporal_model=gauss_temp, name="my-source", ) print(model) .. rst-class:: sphx-glr-script-out .. code-block:: none SkyModel Name : my-source Datasets names : None Spectral model type : PowerLawSpectralModel Spatial model type : GaussianSpatialModel Temporal model type : GaussianTemporalModel Parameters: index : 2.200 +/- 0.00 amplitude : 2.70e-12 +/- 0.0e+00 1 / (cm2 s TeV) reference (frozen): 1.000 TeV lon_0 : 0.000 +/- 0.00 deg lat_0 : 0.000 +/- 0.00 deg sigma : 0.200 +/- 0.00 deg e (frozen): 0.000 phi (frozen): 0.000 deg t_ref : 59240.000 +/- 0.00 d sigma : 2.000 +/- 0.00 d .. GENERATED FROM PYTHON SOURCE LINES 408-413 It is good practice to specify a name for your sky model, so that you can access it later by name and have meaningful identifier you serialisation. If you don’t define a name, a unique random name is generated: .. GENERATED FROM PYTHON SOURCE LINES 413-418 .. code-block:: Python model_without_name = SkyModel(spectral_model=pwl, spatial_model=gauss) print(model_without_name.name) .. rst-class:: sphx-glr-script-out .. code-block:: none HjVc3r-x .. GENERATED FROM PYTHON SOURCE LINES 419-422 The individual components of the source model can be accessed using ``.spectral_model``, ``.spatial_model`` and ``.temporal_model``: .. GENERATED FROM PYTHON SOURCE LINES 422-425 .. code-block:: Python print(model.spectral_model) .. rst-class:: sphx-glr-script-out .. code-block:: none PowerLawSpectralModel type name value unit error ... frozen is_norm link prior ---- --------- ---------- -------------- --------- ... ------ ------- ---- ----- index 2.2000e+00 0.000e+00 ... False False amplitude 2.7000e-12 cm-2 s-1 TeV-1 0.000e+00 ... False True reference 1.0000e+00 TeV 0.000e+00 ... True False .. GENERATED FROM PYTHON SOURCE LINES 426-428 .. code-block:: Python print(model.spatial_model) .. rst-class:: sphx-glr-script-out .. code-block:: none GaussianSpatialModel type name value unit error ... max frozen is_norm link prior ---- ----- ---------- ---- --------- ... --------- ------ ------- ---- ----- lon_0 0.0000e+00 deg 0.000e+00 ... nan False False lat_0 0.0000e+00 deg 0.000e+00 ... 9.000e+01 False False sigma 2.0000e-01 deg 0.000e+00 ... nan False False e 0.0000e+00 0.000e+00 ... 1.000e+00 True False phi 0.0000e+00 deg 0.000e+00 ... nan True False .. GENERATED FROM PYTHON SOURCE LINES 429-432 .. code-block:: Python print(model.temporal_model) .. rst-class:: sphx-glr-script-out .. code-block:: none GaussianTemporalModel type name value unit error min max frozen is_norm link prior ---- ----- ---------- ---- --------- --- --- ------ ------- ---- ----- t_ref 5.9240e+04 d 0.000e+00 nan nan False False sigma 2.0000e+00 d 0.000e+00 nan nan False False .. GENERATED FROM PYTHON SOURCE LINES 433-435 And can be used as you have seen already seen above: .. GENERATED FROM PYTHON SOURCE LINES 435-440 .. code-block:: Python model.spectral_model.plot(energy_bounds=[1, 10] * u.TeV) plt.show() .. image-sg:: /tutorials/api/images/sphx_glr_models_007.png :alt: models :srcset: /tutorials/api/images/sphx_glr_models_007.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 441-451 Note that the gammapy fitting can interface only with a `~gammapy.modeling.models.SkyModel` and **not** its individual components. So, it is customary to work with `~gammapy.modeling.models.SkyModel` even if you are not doing a 3D fit. Since the amplitude parameter resides on the `~gammapy.modeling.models.SpectralModel`, specifying a spectral component is compulsory. The temporal and spatial components are optional. The temporal model needs to be specified only for timing analysis. In some cases (e.g. when doing a spectral analysis) there is no need for a spatial component either, and only a spectral model is associated with the source. .. GENERATED FROM PYTHON SOURCE LINES 451-456 .. code-block:: Python model_spectrum = SkyModel(spectral_model=pwl, name="source-spectrum") print(model_spectrum) .. rst-class:: sphx-glr-script-out .. code-block:: none SkyModel Name : source-spectrum Datasets names : None Spectral model type : PowerLawSpectralModel Spatial model type : Temporal model type : Parameters: index : 2.200 +/- 0.00 amplitude : 2.70e-12 +/- 0.0e+00 1 / (cm2 s TeV) reference (frozen): 1.000 TeV .. GENERATED FROM PYTHON SOURCE LINES 457-462 Additionally the spatial model of `~gammapy.modeling.models.SkyModel` can be used to represent source models based on templates, where the spatial and energy axes are correlated. It can be created e.g. from an existing FITS file: .. GENERATED FROM PYTHON SOURCE LINES 462-472 .. code-block:: Python from gammapy.modeling.models import PowerLawNormSpectralModel, TemplateSpatialModel diffuse_cube = TemplateSpatialModel.read( "$GAMMAPY_DATA/fermi-3fhl-gc/gll_iem_v06_gc.fits.gz", normalize=False ) diffuse = SkyModel(PowerLawNormSpectralModel(), diffuse_cube) print(diffuse) .. rst-class:: sphx-glr-script-out .. code-block:: none SkyModel Name : ezPeAQRO Datasets names : None Spectral model type : PowerLawNormSpectralModel Spatial model type : TemplateSpatialModel Temporal model type : Parameters: norm : 1.000 +/- 0.00 tilt (frozen): 0.000 reference (frozen): 1.000 TeV lon_0 (frozen): 0.000 deg lat_0 (frozen): -0.062 deg .. GENERATED FROM PYTHON SOURCE LINES 473-479 Note that if the spatial model is not normalized over the sky it has to be combined with a normalized spectral model, for example `~gammapy.modeling.models.PowerLawNormSpectralModel`. This is the only case in `~gammapy.models.SkyModel` where the unit is fully attached to the spatial model. .. GENERATED FROM PYTHON SOURCE LINES 482-488 Modifying model parameters -------------------------- Model parameters can be modified (eg: frozen, values changed, etc at any point), eg: .. GENERATED FROM PYTHON SOURCE LINES 488-505 .. code-block:: Python # Freezing a parameter model.spectral_model.index.frozen = True # Making a parameter free model.spectral_model.index.frozen = False # Changing a value model.spectral_model.index.value = 3 # Setting min and max ranges on parameters model.spectral_model.index.min = 1.0 model.spectral_model.index.max = 5.0 # Visualise the model as a table display(model.parameters.to_table()) .. rst-class:: sphx-glr-script-out .. code-block:: none type name value unit error ... frozen is_norm link prior ---- --------- ---------- -------------- --------- ... ------ ------- ---- ----- index 3.0000e+00 0.000e+00 ... False False amplitude 2.7000e-12 cm-2 s-1 TeV-1 0.000e+00 ... False True reference 1.0000e+00 TeV 0.000e+00 ... True False lon_0 0.0000e+00 deg 0.000e+00 ... False False lat_0 0.0000e+00 deg 0.000e+00 ... False False sigma 2.0000e-01 deg 0.000e+00 ... False False e 0.0000e+00 0.000e+00 ... True False phi 0.0000e+00 deg 0.000e+00 ... True False t_ref 5.9240e+04 d 0.000e+00 ... False False sigma 2.0000e+00 d 0.000e+00 ... False False .. GENERATED FROM PYTHON SOURCE LINES 506-509 You can use the interactive boxes to choose model parameters by name, type or other attributes mentioned in the column names. .. GENERATED FROM PYTHON SOURCE LINES 512-519 Model lists and serialisation ----------------------------- In a typical analysis scenario a model consists of multiple model components, or a “catalog” or “source library”. To handle this list of multiple model components, Gammapy has a `~gammapy.modeling.models.Models` class: .. GENERATED FROM PYTHON SOURCE LINES 519-526 .. code-block:: Python from gammapy.modeling.models import Models models = Models([model, diffuse]) print(models) .. rst-class:: sphx-glr-script-out .. code-block:: none Models Component 0: SkyModel Name : my-source Datasets names : None Spectral model type : PowerLawSpectralModel Spatial model type : GaussianSpatialModel Temporal model type : GaussianTemporalModel Parameters: index : 3.000 +/- 0.00 amplitude : 2.70e-12 +/- 0.0e+00 1 / (cm2 s TeV) reference (frozen): 1.000 TeV lon_0 : 0.000 +/- 0.00 deg lat_0 : 0.000 +/- 0.00 deg sigma : 0.200 +/- 0.00 deg e (frozen): 0.000 phi (frozen): 0.000 deg t_ref : 59240.000 +/- 0.00 d sigma : 2.000 +/- 0.00 d Component 1: SkyModel Name : ezPeAQRO Datasets names : None Spectral model type : PowerLawNormSpectralModel Spatial model type : TemplateSpatialModel Temporal model type : Parameters: norm : 1.000 +/- 0.00 tilt (frozen): 0.000 reference (frozen): 1.000 TeV lon_0 (frozen): 0.000 deg lat_0 (frozen): -0.062 deg .. GENERATED FROM PYTHON SOURCE LINES 527-529 Individual model components in the list can be accessed by their name: .. GENERATED FROM PYTHON SOURCE LINES 529-533 .. code-block:: Python print(models["my-source"]) .. rst-class:: sphx-glr-script-out .. code-block:: none SkyModel Name : my-source Datasets names : None Spectral model type : PowerLawSpectralModel Spatial model type : GaussianSpatialModel Temporal model type : GaussianTemporalModel Parameters: index : 3.000 +/- 0.00 amplitude : 2.70e-12 +/- 0.0e+00 1 / (cm2 s TeV) reference (frozen): 1.000 TeV lon_0 : 0.000 +/- 0.00 deg lat_0 : 0.000 +/- 0.00 deg sigma : 0.200 +/- 0.00 deg e (frozen): 0.000 phi (frozen): 0.000 deg t_ref : 59240.000 +/- 0.00 d sigma : 2.000 +/- 0.00 d .. GENERATED FROM PYTHON SOURCE LINES 534-539 **Note:** To make the access by name unambiguous, models are required to have a unique name, otherwise an error will be thrown. To see which models are available you can use the ``.names`` attribute: .. GENERATED FROM PYTHON SOURCE LINES 539-543 .. code-block:: Python print(models.names) .. rst-class:: sphx-glr-script-out .. code-block:: none ['my-source', 'ezPeAQRO'] .. GENERATED FROM PYTHON SOURCE LINES 544-554 Note that a `~gammapy.modeling.models.SkyModel` object can be evaluated for a given longitude, latitude, and energy, but the `~gammapy.modeling.models.Models` object cannot. This `~gammapy.modeling.models.Models` container object will be assigned to `~gammapy.datasets.Dataset` or `~gammapy.datasets.Datasets` together with the data to be fitted. Checkout e.g. the :doc:`/tutorials/api/model_management` tutorial for details. The `~gammapy.modeling.models.Models` class also has in place ``.append()`` and ``.extend()`` methods: .. GENERATED FROM PYTHON SOURCE LINES 554-559 .. code-block:: Python model_copy = model.copy(name="my-source-copy") models.append(model_copy) .. GENERATED FROM PYTHON SOURCE LINES 560-563 This list of models can be also serialised to a custom YAML based format: .. GENERATED FROM PYTHON SOURCE LINES 563-568 .. code-block:: Python models_yaml = models.to_yaml() print(models_yaml) .. rst-class:: sphx-glr-script-out .. code-block:: none components: - name: my-source type: SkyModel spectral: type: PowerLawSpectralModel parameters: - name: index value: 3.0 min: 1.0 max: 5.0 - name: amplitude value: 2.7e-12 unit: cm-2 s-1 TeV-1 - name: reference value: 1.0 unit: TeV spatial: type: GaussianSpatialModel frame: galactic parameters: - name: lon_0 value: 0.0 unit: deg - name: lat_0 value: 0.0 unit: deg - name: sigma value: 0.2 unit: deg - name: e value: 0.0 - name: phi value: 0.0 unit: deg temporal: type: GaussianTemporalModel parameters: - name: t_ref value: 59240.0 unit: d - name: sigma value: 2.0 unit: d scale: utc - name: ezPeAQRO type: SkyModel spectral: type: PowerLawNormSpectralModel parameters: - name: norm value: 1.0 - name: tilt value: 0.0 - name: reference value: 1.0 unit: TeV spatial: type: TemplateSpatialModel frame: galactic parameters: - name: lon_0 value: 0.0 unit: deg - name: lat_0 value: -0.0625 unit: deg filename: /home/runner/work/gammapy-docs/gammapy-docs/gammapy-datasets/dev/fermi-3fhl-gc/gll_iem_v06_gc.fits.gz normalize: false unit: 1 / (cm2 MeV s sr) - name: my-source-copy type: SkyModel spectral: type: PowerLawSpectralModel parameters: - name: index value: 3.0 min: 1.0 max: 5.0 - name: amplitude value: 2.7e-12 unit: cm-2 s-1 TeV-1 - name: reference value: 1.0 unit: TeV spatial: type: GaussianSpatialModel frame: galactic parameters: - name: lon_0 value: 0.0 unit: deg - name: lat_0 value: 0.0 unit: deg - name: sigma value: 0.2 unit: deg - name: e value: 0.0 - name: phi value: 0.0 unit: deg temporal: type: GaussianTemporalModel parameters: - name: t_ref value: 59240.0 unit: d - name: sigma value: 2.0 unit: d scale: utc metadata: creator: Gammapy 1.3.dev241+g0271bebfc date: '2024-05-03T15:09:25.310310' origin: null .. GENERATED FROM PYTHON SOURCE LINES 569-582 The structure of the yaml files follows the structure of the python objects. The ``components`` listed correspond to the `~gammapy.modeling.models.SkyModel` and components of the `~gammapy.modeling.models.Models`. For each `~gammapy.modeling.models.SkyModel` we have information about its ``name``, ``type`` (corresponding to the tag attribute) and sub-models (i.e ``spectral`` model and eventually ``spatial`` model). Then the spatial and spectral models are defined by their type and parameters. The ``parameters`` keys name/value/unit are mandatory, while the keys min/max/frozen are optional (so you can prepare shorter files). If you want to write this list of models to disk and read it back later you can use: .. GENERATED FROM PYTHON SOURCE LINES 582-588 .. code-block:: Python models.write("models.yaml", overwrite=True) models_read = Models.read("models.yaml") .. GENERATED FROM PYTHON SOURCE LINES 589-601 Additionally the models can be exported and imported together with the data using the `~gammapy.datasets.Datasets.read()` and `~gammapy.datasets.Datasets.write()` methods as shown in the :doc:`/tutorials/analysis-3d/analysis_mwl` notebook. Models with shared parameter ---------------------------- A model parameter can be shared with other models, for example we can define two power-law models with the same spectral index but different amplitudes: .. GENERATED FROM PYTHON SOURCE LINES 601-611 .. code-block:: Python pwl2 = PowerLawSpectralModel() pwl2.index = pwl.index pwl.index.value = ( 2.3 # also update pwl2 as the parameter object is now the same as shown below ) print(pwl.index) print(pwl2.index) .. rst-class:: sphx-glr-script-out .. code-block:: none Parameter(name='index', value=2.3, factor=2.3, scale=1.0, unit=Unit(dimensionless), min=1.0, max=5.0, frozen=False, prior=None, id=0x7f8b293542b0) Parameter(name='index', value=2.3, factor=2.3, scale=1.0, unit=Unit(dimensionless), min=1.0, max=5.0, frozen=False, prior=None, id=0x7f8b293542b0) .. GENERATED FROM PYTHON SOURCE LINES 612-615 In the YAML files the shared parameter is flagged by the additional ``link`` entry that follows the convention ``parameter.name@unique_id``: .. GENERATED FROM PYTHON SOURCE LINES 615-621 .. code-block:: Python models = Models([SkyModel(pwl, name="source1"), SkyModel(pwl2, name="source2")]) models_yaml = models.to_yaml() print(models_yaml) .. rst-class:: sphx-glr-script-out .. code-block:: none components: - name: source1 type: SkyModel spectral: type: PowerLawSpectralModel parameters: - name: index value: 2.3 min: 1.0 max: 5.0 link: index@15P2QI1s - name: amplitude value: 2.7e-12 unit: cm-2 s-1 TeV-1 - name: reference value: 1.0 unit: TeV - name: source2 type: SkyModel spectral: type: PowerLawSpectralModel parameters: - name: index value: 2.3 min: 1.0 max: 5.0 link: index@15P2QI1s - name: amplitude value: 1.0e-12 unit: cm-2 s-1 TeV-1 - name: reference value: 1.0 unit: TeV metadata: creator: Gammapy 1.3.dev241+g0271bebfc date: '2024-05-03T15:09:25.495234' origin: null .. GENERATED FROM PYTHON SOURCE LINES 622-640 .. _custom-model: Implementing a custom model --------------------------- In order to add a user defined spectral model you have to create a `~gammapy.modeling.models.SpectralModel` subclass. This new model class should include: - a tag used for serialization (it can be the same as the class name) - an instantiation of each Parameter with their unit, default values and frozen status - the evaluate function where the mathematical expression for the model is defined. As an example we will use a PowerLawSpectralModel plus a Gaussian (with fixed width). First we define the new custom model class that we name ``MyCustomSpectralModel``: .. GENERATED FROM PYTHON SOURCE LINES 640-682 .. code-block:: Python from gammapy.modeling import Parameter from gammapy.modeling.models import SpectralModel class MyCustomSpectralModel(SpectralModel): """My custom spectral model, parametrizing a power law plus a Gaussian spectral line. Parameters ---------- amplitude : `astropy.units.Quantity` Amplitude of the spectra model. index : `astropy.units.Quantity` Spectral index of the model. reference : `astropy.units.Quantity` Reference energy of the power law. mean : `astropy.units.Quantity` Mean value of the Gaussian. width : `astropy.units.Quantity` Sigma width of the Gaussian line. """ tag = "MyCustomSpectralModel" amplitude = Parameter("amplitude", "1e-12 cm-2 s-1 TeV-1", min=0, is_norm=True) index = Parameter("index", 2, min=0) reference = Parameter("reference", "1 TeV", frozen=True) mean = Parameter("mean", "1 TeV", min=0) width = Parameter("width", "0.1 TeV", min=0, frozen=True) @staticmethod def evaluate(energy, index, amplitude, reference, mean, width): pwl = PowerLawSpectralModel.evaluate( energy=energy, index=index, amplitude=amplitude, reference=reference, ) gauss = amplitude * np.exp(-((energy - mean) ** 2) / (2 * width**2)) return pwl + gauss .. GENERATED FROM PYTHON SOURCE LINES 683-691 It is good practice to also implement a docstring for the model, defining the parameters and also defining a ``.tag``, which specifies the name of the model for serialisation. Also note that gammapy assumes that all `~gammapy.modeling.models.SpectralModel` evaluate functions return a flux in unit of `"cm-2 s-1 TeV-1"` (or equivalent dimensions). This model can now be used as any other spectral model in Gammapy: .. GENERATED FROM PYTHON SOURCE LINES 691-701 .. code-block:: Python my_custom_model = MyCustomSpectralModel(mean="3 TeV") print(my_custom_model) print(my_custom_model.integral(1 * u.TeV, 10 * u.TeV)) my_custom_model.plot(energy_bounds=[1, 10] * u.TeV) plt.show() .. image-sg:: /tutorials/api/images/sphx_glr_models_008.png :alt: models :srcset: /tutorials/api/images/sphx_glr_models_008.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none MyCustomSpectralModel type name value unit error ... frozen is_norm link prior ---- --------- ---------- -------------- --------- ... ------ ------- ---- ----- amplitude 1.0000e-12 cm-2 s-1 TeV-1 0.000e+00 ... False True index 2.0000e+00 0.000e+00 ... False False reference 1.0000e+00 TeV 0.000e+00 ... True False mean 3.0000e+00 TeV 0.000e+00 ... False False width 1.0000e-01 TeV 0.000e+00 ... True False 1.1442739329466746e-12 1 / (cm2 s) .. GENERATED FROM PYTHON SOURCE LINES 702-706 As a next step we can also register the custom model in the ``SPECTRAL_MODELS`` registry, so that it becomes available for serialization: .. GENERATED FROM PYTHON SOURCE LINES 706-716 .. code-block:: Python SPECTRAL_MODEL_REGISTRY.append(MyCustomSpectralModel) model = SkyModel(spectral_model=my_custom_model, name="my-source") models = Models([model]) models.write("my-custom-models.yaml", overwrite=True) # !cat my-custom-models.yaml .. GENERATED FROM PYTHON SOURCE LINES 717-722 Similarly you can also create custom spatial models and add them to the ``SPATIAL_MODELS`` registry. In that case gammapy assumes that the evaluate function return a normalized quantity in “sr-1” such as the model integral over the whole sky is one. .. GENERATED FROM PYTHON SOURCE LINES 725-757 Models with energy dependent morphology --------------------------------------- A common science case in the study of extended sources is to probe for energy dependent morphology, eg: in Supernova Remnants or Pulsar Wind Nebulae. Traditionally, this has been done by splitting the data into energy bands and doing individual fits of the morphology in these energy bands. `~gammapy.modeling.models.SkyModel` offers a natural framework to simultaneously model the energy and morphology, e.g. spatial extent described by a parametric model expression with energy dependent parameters. The models shipped within gammapy use a “factorised” representation of the source model, where the spatial (:math:`l,b`), energy (:math:`E`) and time (:math:`t`) dependence are independent model components and not correlated: .. math:: \begin{align}f(l, b, E, t) = F(l, b) \cdot G(E) \cdot H(t)\end{align} To use full 3D models, ie :math:`f(l, b, E) = F(l, b, E) \cdot \ G(E)`, you have to implement your own custom `SpatialModel`. Note that it is still necessary to multiply by a `SpectralModel`, :math:`G(E)` to be dimensionally consistent. In this example, we create Gaussian Spatial Model with the extension varying with energy. For simplicity, we assume a linear dependency on energy and parameterize this by specifying the extension at 2 energies. You can add more complex dependencies, probably motivated by physical models. .. GENERATED FROM PYTHON SOURCE LINES 757-802 .. code-block:: Python from astropy.coordinates import angular_separation from gammapy.modeling.models import SpatialModel class MyCustomGaussianModel(SpatialModel): """My custom Energy Dependent Gaussian model. Parameters ---------- lon_0, lat_0 : `~astropy.coordinates.Angle` Center position sigma_1TeV : `~astropy.coordinates.Angle` Width of the Gaussian at 1 TeV sigma_10TeV : `~astropy.coordinates.Angle` Width of the Gaussian at 10 TeV """ tag = "MyCustomGaussianModel" is_energy_dependent = True lon_0 = Parameter("lon_0", "0 deg") lat_0 = Parameter("lat_0", "0 deg", min=-90, max=90) sigma_1TeV = Parameter("sigma_1TeV", "2.0 deg", min=0) sigma_10TeV = Parameter("sigma_10TeV", "0.2 deg", min=0) @staticmethod def evaluate(lon, lat, energy, lon_0, lat_0, sigma_1TeV, sigma_10TeV): sep = angular_separation(lon, lat, lon_0, lat_0) # Compute sigma for the given energy using linear interpolation in log energy sigma_nodes = u.Quantity([sigma_1TeV, sigma_10TeV]) energy_nodes = [1, 10] * u.TeV log_s = np.log(sigma_nodes.to("deg").value) log_en = np.log(energy_nodes.to("TeV").value) log_e = np.log(energy.to("TeV").value) sigma = np.exp(np.interp(log_e, log_en, log_s)) * u.deg exponent = -0.5 * (sep / sigma) ** 2 norm = 1 / (2 * np.pi * sigma**2) return norm * np.exp(exponent) .. GENERATED FROM PYTHON SOURCE LINES 803-809 Serialisation of this model can be achieved as explained in the previous section. You can now use it as standard `~gammapy.modeling.models.SpatialModel` in your analysis. Note that this is still a `~gammapy.modeling.models.SpatialModel` and not a `~gammapy.modeling.models.SkyModel`, so it needs to be multiplied by a `~gammapy.modeling.models.SpectralModel` as before. .. GENERATED FROM PYTHON SOURCE LINES 809-817 .. code-block:: Python spatial_model = MyCustomGaussianModel() spectral_model = PowerLawSpectralModel() sky_model = SkyModel(spatial_model=spatial_model, spectral_model=spectral_model) print(spatial_model.evaluation_radius) .. rst-class:: sphx-glr-script-out .. code-block:: none None .. GENERATED FROM PYTHON SOURCE LINES 818-820 To visualise it, we evaluate it on a 3D geom. .. GENERATED FROM PYTHON SOURCE LINES 820-830 .. code-block:: Python energy_axis = MapAxis.from_energy_bounds( energy_min=0.1 * u.TeV, energy_max=10.0 * u.TeV, nbin=3, name="energy_true" ) geom = WcsGeom.create(skydir=(0, 0), width=5.0 * u.deg, binsz=0.1, axes=[energy_axis]) spatial_model.plot_grid(geom=geom, add_cbar=True, figsize=(14, 3)) plt.show() .. image-sg:: /tutorials/api/images/sphx_glr_models_009.png :alt: Energy_true 100 GeV - 464 GeV, Energy_true 464 GeV - 2.15 TeV, Energy_true 2.15 TeV - 10.0 TeV :srcset: /tutorials/api/images/sphx_glr_models_009.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 831-837 For computational purposes, it is useful to specify a ``evaluation_radius`` for `~gammapy.modeling.models.SpatialModels` - this gives a size on which to compute the model. Though optional, it is highly recommended for Custom Spatial Models. This can be done, for ex, by defining the following function inside the above class: .. GENERATED FROM PYTHON SOURCE LINES 837-843 .. code-block:: Python @property def evaluation_radius(self): """Evaluation radius (`~astropy.coordinates.Angle`).""" return 5 * np.max([self.sigma_1TeV.value, self.sigma_10TeV.value]) * u.deg .. _sphx_glr_download_tutorials_api_models.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: binder-badge .. image:: images/binder_badge_logo.svg :target: https://mybinder.org/v2/gh/gammapy/gammapy-webpage/main?urlpath=lab/tree/notebooks/dev/tutorials/api/models.ipynb :alt: Launch binder :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: models.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: models.py ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_