# Now we have to compute `npred` maps, i.e. "predicted counts per pixel" given the model and the observation infos: exposure, background, PSF and EDISP. For this we use the `MapDataset` object: # In[ ]: background_model = BackgroundModel(background) dataset = MapDataset( model=sky_model, exposure=exposure, background_model=background_model, psf=psf_kernel, edisp=edisp, ) # In[ ]: npred = dataset.npred() # In[ ]: npred.sum_over_axes().plot(add_cbar=True) # In[ ]: # This one line is the core of how to simulate data when # using binned simulation / analysis: you Poisson fluctuate # npred to obtain simulated observed counts. # Compute counts as a Poisson fluctuation rng = np.random.RandomState(seed=42) counts = rng.poisson(npred.data) counts_map = WcsNDMap(geom, counts)
get_ipython().run_cell_magic( 'time', '', 'fit = Fit(dataset)\nresult = fit.run(optimize_opts={"print_level": 1})') # In[ ]: result.parameters.to_table() # ### Check model fit # # We check the model fit by computing a residual image. For this we first get the number of predicted counts: # In[ ]: npred = dataset.npred() # And compute a residual image: # In[ ]: residual = maps["counts"] - npred # In[ ]: residual.sum_over_axes().smooth(width=0.05 * u.deg).plot(cmap="coolwarm", vmin=-1, vmax=1, add_cbar=True) # We can also plot the best fit spectrum. For that need to extract the covariance of the spectral parameters.
def simulate_dataset( skymodel, geom, pointing, irfs, livetime=1 * u.h, offset=0 * u.deg, max_radius=0.8 * u.deg, random_state="random-seed", ): """Simulate a 3D dataset. Simulate a source defined with a sky model for a given pointing, geometry and irfs for a given exposure time. This will return a dataset object which includes the counts cube, the exposure cube, the psf cube, the background model and the sky model. Parameters ---------- skymodel : `~gammapy.modeling.models.SkyModel` Background model map geom : `~gammapy.maps.WcsGeom` Geometry object for the observation pointing : `~astropy.coordinates.SkyCoord` Pointing position irfs : dict Irfs used for simulating the observation livetime : `~astropy.units.Quantity` Livetime exposure of the simulated observation offset : `~astropy.units.Quantity` Offset from the center of the pointing position. This is used for the PSF and Edisp estimation max_radius : `~astropy.coordinates.Angle` The maximum radius of the PSF kernel. random_state: {int, 'random-seed', 'global-rng', `~numpy.random.RandomState`} Defines random number generator initialisation. Returns ------- dataset : `~gammapy.cube.MapDataset` A dataset of the simulated observation. """ background = make_map_background_irf( pointing=pointing, ontime=livetime, bkg=irfs["bkg"], geom=geom ) background_model = BackgroundModel(background) psf = irfs["psf"].to_energy_dependent_table_psf(theta=offset) psf_kernel = PSFKernel.from_table_psf(psf, geom, max_radius=max_radius) exposure = make_map_exposure_true_energy( pointing=pointing, livetime=livetime, aeff=irfs["aeff"], geom=geom ) if "edisp" in irfs: energy = geom.axes[0].edges edisp = irfs["edisp"].to_energy_dispersion(offset, e_reco=energy, e_true=energy) else: edisp = None dataset = MapDataset( model=skymodel, exposure=exposure, background_model=background_model, psf=psf_kernel, edisp=edisp, ) npred_map = dataset.npred() rng = get_random_state(random_state) counts = rng.poisson(npred_map.data) dataset.counts = WcsNDMap(geom, counts) return dataset
psf=psf_kernel, ) fit = Fit(dataset) result = fit.run() # In[ ]: print(result) # In[ ]: dataset.parameters.to_table() # In[ ]: residual = counts - dataset.npred() residual.sum_over_axes().smooth("0.1 deg").plot(cmap="coolwarm", vmin=-3, vmax=3, add_cbar=True) # ## Exercises # # - Fit the position and spectrum of the source [SNR G0.9+0.1](http://gamma-sky.net/#/cat/tev/110). # - Make maps and fit the position and spectrum of the [Crab nebula](http://gamma-sky.net/#/cat/tev/25). # ## Summary # # In this tutorial you have seen how to work with Fermi-LAT data with Gammapy. You have to use the Fermi ST to prepare the exposure cube and PSF, and then you can use Gammapy for any event or map analysis using the same methods that are used to analyse IACT data. # # This works very well at high energies (here above 10 GeV), where the exposure and PSF is almost constant spatially and only varies a little with energy. It is not expected to give good results for low-energy data, where the Fermi-LAT PSF is very large. If you are interested to help us validate down to what energy Fermi-LAT analysis with Gammapy works well (e.g. by re-computing results from 3FHL or other published analysis results), or to extend the Gammapy capabilities (e.g. to work with energy-dependent multi-resolution maps and PSF), that would be very welcome!