def test_psf_map_from_gauss(): energy_axis = MapAxis.from_nodes( [1, 3, 10], name="energy_true", interp="log", unit="TeV" ) rad = np.linspace(0, 1.5, 100) * u.deg rad_axis = MapAxis.from_nodes(rad, name="rad", unit="deg") # define sigmas starting at 0.1 in steps of 0.1 deg sigma = [0.1, 0.2, 0.4] * u.deg # with energy-dependent sigma psfmap = PSFMap.from_gauss(energy_axis, rad_axis, sigma) assert psfmap.psf_map.geom.axes[0] == rad_axis assert psfmap.psf_map.geom.axes[1] == energy_axis assert psfmap.exposure_map.geom.axes["rad"].nbin == 1 assert psfmap.exposure_map.geom.axes["energy_true"] == psfmap.psf_map.geom.axes[1] assert psfmap.psf_map.unit == "sr-1" assert psfmap.psf_map.data.shape == (3, 100, 1, 2) radius = psfmap.containment_radius(fraction=0.394, energy_true=[1, 3, 10] * u.TeV) assert_allclose(radius, sigma, rtol=0.01) # test that it won't work with different number of sigmas and energies with pytest.raises(ValueError): PSFMap.from_gauss(energy_axis, rad_axis, sigma=[1, 2] * u.deg)
def test_psfmap_from_gauss(): rad = np.linspace(0, 1.5, 100) * u.deg energy = np.logspace(-1, 2, 10) * u.TeV energy_axis = MapAxis.from_nodes(energy, name="energy_true", interp="log", unit="TeV") rad_axis = MapAxis.from_nodes(rad, name="rad", unit="deg") # define sigmas starting at 0.1 in steps of 0.1 deg sigma = (np.arange(energy.shape[0]) * 0.1 + 0.1) * u.deg # with energy-dependent sigma psfmap = PSFMap.from_gauss(energy_axis, rad_axis, sigma) assert psfmap.psf_map.geom.axes[0] == rad_axis assert psfmap.psf_map.geom.axes[1] == energy_axis assert psfmap.psf_map.unit == Unit("sr-1") assert psfmap.psf_map.data.shape == (energy.shape[0], rad.shape[0], 1, 2) assert_allclose( psfmap.get_energy_dependent_table_psf().containment_radius(1 * u.TeV)[0], psfmap.containment_radius_map(1 * u.TeV).data[0][0] * u.deg, ) assert_allclose( psfmap.containment_radius_map(energy[3], 0.68).data[0][0] / sigma[3].value, 1.51, atol=1e-2, ) assert_allclose( psfmap.containment_radius_map(energy[3], 0.95).data[0][0] / sigma[3].value, 2.45, atol=1e-2, ) # with constant sigma psfmap1 = PSFMap.from_gauss(energy_axis, rad_axis, sigma[0]) assert psfmap1.psf_map.geom.axes[0] == rad_axis assert psfmap1.psf_map.geom.axes[1] == energy_axis assert psfmap1.psf_map.unit == Unit("sr-1") assert psfmap1.psf_map.data.shape == (energy.shape[0], rad.shape[0], 1, 2) assert_allclose( psfmap1.get_energy_dependent_table_psf().containment_radius(1 * u.TeV)[0], psfmap1.containment_radius_map(1 * u.TeV).data[0][0] * u.deg, ) # check that the PSF with the same sigma is the same psfvalue = psfmap.get_energy_dependent_table_psf().data.data[0] psfvalue1 = psfmap1.get_energy_dependent_table_psf().data.data[0] assert_allclose(psfvalue, psfvalue1, atol=1e-7) # test that it won't work with different number of sigmas and energies with pytest.raises(AssertionError): psfmap2 = PSFMap.from_gauss(energy_axis, rad_axis, sigma[:3])
def get_dataset(): counts = Map.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-counts-cube.fits.gz") background = Map.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-background-cube.fits.gz") exposure = Map.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-exposure-cube.fits.gz") # for some reason the WCS defintions are not aligned... exposure.geom._wcs = counts.geom.wcs psf = PSFMap.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-psf-cube.fits.gz", format="gtpsf") # reduce size of the PSF psf = psf.slice_by_idx(slices={"rad": slice(0, 130)}) edisp = EDispKernelMap.from_diagonal_response( energy_axis=counts.geom.axes["energy"], energy_axis_true=exposure.geom.axes["energy_true"], geom=psf.psf_map.geom) mask_safe = counts.geom.boundary_mask(width="0.2 deg") return MapDataset(counts=counts, background=background, exposure=exposure, psf=psf, name="fermi-3fhl-gc", edisp=edisp, mask_safe=mask_safe)
def make_psf(self, geom, observation): """Make psf map. Parameters ---------- geom : `~gammapy.maps.Geom` Reference geom. observation : `~gammapy.data.Observation` Observation container. Returns ------- psf : `~gammapy.irf.PSFMap` Psf map. """ psf = observation.psf if isinstance(psf, PSFMap): return PSFMap(psf.psf_map.interp_to_geom(geom)) exposure = self.make_exposure_irf(geom.squash(axis_name="rad"), observation) return make_psf_map( psf=psf, pointing=observation.pointing_radec, geom=geom, exposure_map=exposure, )
def test_convolve_full(region): energy = MapAxis.from_bounds(1, 100, unit='TeV', nbin=2, name='energy_true') nside = 256 all_sky_geom = HpxGeom(nside=nside, axes=[energy], region=region, nest=False, frame='icrs') all_sky_map = Map.from_geom(all_sky_geom) all_sky_map.set_by_coord((0, 0, [2, 90]), 1) all_sky_map.set_by_coord((10, 10, [2, 90]), 1) all_sky_map.set_by_coord((30, 30, [2, 90]), 1) all_sky_map.set_by_coord((-40, -40, [2, 90]), 1) all_sky_map.set_by_coord((60, 0, [2, 90]), 1) all_sky_map.set_by_coord((-45, 30, [2, 90]), 1) all_sky_map.set_by_coord((30, -45, [2, 90]), 1) wcs_geom = WcsGeom.create(width=5, binsz=0.05, axes=[energy]) psf = PSFMap.from_gauss(energy_axis_true=energy, sigma=[0.5, 0.6] * u.deg) kernel = psf.get_psf_kernel(geom=wcs_geom, max_radius=1 * u.deg) convolved_map = all_sky_map.convolve_full(kernel) assert_allclose(convolved_map.data.sum(), 14, rtol=1e-5)
def test_convolve_nd(): energy_axis = MapAxis.from_edges( np.logspace(-1.0, 1.0, 4), unit="TeV", name="energy_true" ) geom = WcsGeom.create(binsz=0.02 * u.deg, width=4.0 * u.deg, axes=[energy_axis]) m = Map.from_geom(geom) m.fill_by_coord([[0.2, 0.4], [-0.1, 0.6], [0.5, 3.6]]) psf = PSFMap.from_gauss(energy_axis, sigma=[0.1, 0.2, 0.3] * u.deg) psf_kernel = psf.get_psf_kernel(geom=geom, max_radius=1 * u.deg) assert psf_kernel.psf_kernel_map.data.shape == (3, 101, 101) mc = m.convolve(psf_kernel) assert_allclose(mc.data.sum(axis=(1, 2)), [0, 1, 1], atol=1e-5) kernel_2d = Box2DKernel(3, mode="center") kernel_2d.normalize("peak") mc = m.convolve(kernel_2d.array) assert_allclose(mc.data[0, :, :].sum(), 0, atol=1e-5) assert_allclose(mc.data[1, :, :].sum(), 9, atol=1e-5) kernel_2d = Gaussian2DKernel(15, mode="center") kernel_2d.normalize("peak") mc_full = m.convolve(kernel_2d.array, mode="full") mc_same = m.convolve(kernel_2d.array, mode="same") coords = [[0.2, 0.1, 0.4, 0.44, -1.3], [-0.1, -0.13, 0.6, 0.57, 0.91], [0.5, 0.5, 3.6, 3.6, 0.5]] values_full = mc_full.get_by_coord(coords) values_same = mc_same.get_by_coord(coords) assert mc_same.data.shape == (3, 200, 200) assert mc_full.data.shape == (3, 320, 320) assert_allclose(values_full, values_same, rtol=1e-5)
def fermi_dataset(): size = Angle("3 deg", "3.5 deg") counts = Map.read("$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-counts-cube.fits.gz") counts = counts.cutout(counts.geom.center_skydir, size) background = Map.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-background-cube.fits.gz" ) background = background.cutout(background.geom.center_skydir, size) background = BackgroundModel(background, datasets_names=["fermi-3fhl-gc"]) exposure = Map.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-exposure-cube.fits.gz" ) exposure = exposure.cutout(exposure.geom.center_skydir, size) exposure.unit = "cm2s" mask_safe = counts.copy(data=np.ones_like(counts.data).astype("bool")) psf = EnergyDependentTablePSF.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-psf-cube.fits.gz" ) psfmap = PSFMap.from_energy_dependent_table_psf(psf) dataset = MapDataset( counts=counts, models=[background], exposure=exposure, mask_safe=mask_safe, psf=psfmap, name="fermi-3fhl-gc", ) dataset = dataset.to_image() return dataset
def fermi_dataset(): size = Angle("3 deg", "3.5 deg") counts = Map.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-counts-cube.fits.gz") counts = counts.cutout(counts.geom.center_skydir, size) background = Map.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-background-cube.fits.gz") background = background.cutout(background.geom.center_skydir, size) background = BackgroundModel(background, datasets_names=["fermi-3fhl-gc"]) exposure = Map.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-exposure-cube.fits.gz") exposure = exposure.cutout(exposure.geom.center_skydir, size) exposure.unit = "cm2 s" psf = EnergyDependentTablePSF.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-psf-cube.fits.gz") psfmap = PSFMap.from_energy_dependent_table_psf(psf) edisp = EDispKernelMap.from_diagonal_response( energy_axis=counts.geom.axes["energy"], energy_axis_true=exposure.geom.axes["energy_true"], ) return MapDataset( counts=counts, models=[background], exposure=exposure, psf=psfmap, name="fermi-3fhl-gc", edisp=edisp, )
def test_psfmap_read_write(tmp_path): psfmap = make_test_psfmap(0.15 * u.deg) psfmap.write(tmp_path / "tmp.fits") new_psfmap = PSFMap.read(tmp_path / "tmp.fits") assert_allclose(psfmap.psf_map.quantity, new_psfmap.psf_map.quantity)
def test_significance_map_estimator_map_dataset(simple_dataset): estimator = ExcessMapEstimator(0.1 * u.deg, selection_optional=["all"]) result = estimator.run(simple_dataset) assert_allclose(result["counts"].data[0, 10, 10], 162) assert_allclose(result["excess"].data[0, 10, 10], 81) assert_allclose(result["background"].data[0, 10, 10], 81) assert_allclose(result["sqrt_ts"].data[0, 10, 10], 7.910732, atol=1e-5) assert_allclose(result["err"].data[0, 10, 10], 12.727922, atol=1e-3) assert_allclose(result["errp"].data[0, 10, 10], 13.063328, atol=1e-3) assert_allclose(result["errn"].data[0, 10, 10], -12.396716, atol=1e-3) assert_allclose(result["ul"].data[0, 10, 10], 107.806275, atol=1e-3) simple_dataset.exposure += 1e10 * u.cm**2 * u.s axis = simple_dataset.exposure.geom.axes[0] simple_dataset.psf = PSFMap.from_gauss(axis, sigma="0.05 deg") model = SkyModel( PowerLawSpectralModel(amplitude="1e-9 cm-2 s-1 TeV-1"), GaussianSpatialModel(lat_0=0.0 * u.deg, lon_0=0.0 * u.deg, sigma=0.1 * u.deg, frame="icrs"), name="sky_model", ) simple_dataset.models = [model] simple_dataset.npred() estimator = ExcessMapEstimator(0.1 * u.deg, selection_optional="all") result = estimator.run(simple_dataset) assert_allclose(result["excess"].data.sum(), 19733.602, rtol=1e-3) assert_allclose(result["background"].data.sum(), 31818.398, rtol=1e-3) assert_allclose(result["sqrt_ts"].data[0, 10, 10], 4.217129, rtol=1e-3)
def test_npred_psf_after_edisp(): energy_axis = MapAxis.from_energy_bounds("1 TeV", "10 TeV", nbin=3) energy_axis_true = MapAxis.from_energy_bounds( "0.8 TeV", "15 TeV", nbin=6, name="energy_true" ) geom = WcsGeom.create(width=4 * u.deg, binsz=0.02, axes=[energy_axis]) dataset = MapDataset.create(geom=geom, energy_axis_true=energy_axis_true) dataset.background.data += 1 dataset.exposure.data += 1e12 dataset.mask_safe.data += True dataset.psf = PSFMap.from_gauss( energy_axis_true=energy_axis_true, sigma=0.2 * u.deg ) model = SkyModel( spectral_model=PowerLawSpectralModel(), spatial_model=PointSpatialModel(), name="test-model", ) model.apply_irf["psf_after_edisp"] = True bkg_model = FoVBackgroundModel(dataset_name=dataset.name) dataset.models = [bkg_model, model] npred = dataset.npred() assert_allclose(npred.data.sum(), 129553.858658)
def fermi_dataset(): size = Angle("3 deg", "3.5 deg") counts = Map.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-counts-cube.fits.gz") counts = counts.cutout(counts.geom.center_skydir, size) background = Map.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-background-cube.fits.gz") background = background.cutout(background.geom.center_skydir, size) exposure = Map.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-exposure-cube.fits.gz") exposure = exposure.cutout(exposure.geom.center_skydir, size) psfmap = PSFMap.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-psf-cube.fits.gz", format="gtpsf") edisp = EDispKernelMap.from_diagonal_response( energy_axis=counts.geom.axes["energy"], energy_axis_true=exposure.geom.axes["energy_true"], ) return MapDataset( counts=counts, background=background, exposure=exposure, psf=psfmap, name="fermi-3fhl-gc", edisp=edisp, )
def data_prep(): counts = Map.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-counts-cube.fits.gz") background = Map.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-background-cube.fits.gz") exposure = Map.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-exposure-cube.fits.gz") # unit is not properly stored on the file. We add it manually exposure = Map.from_geom(exposure.geom, data=exposure.data, unit="cm2s") psfmap = PSFMap.read( "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-psf-cube.fits.gz", format="gtpsf") edisp = EDispKernelMap.from_diagonal_response( energy_axis=counts.geom.axes["energy"], energy_axis_true=exposure.geom.axes["energy_true"], ) dataset = MapDataset( counts=counts, background=background, exposure=exposure, psf=psfmap, name="fermi-3fhl-gc", edisp=edisp, ) return dataset
def test_psf_map_read(position): position = SkyCoord(position) filename = "$GAMMAPY_DATA/fermi_3fhl/fermi_3fhl_psf_gc.fits.gz" psf = PSFMap.read(filename, format="gtpsf") value = psf.containment(position=position, energy_true=100 * u.GeV, rad=0.1 * u.deg) assert_allclose(value, 0.682022, rtol=1e-5) assert psf.psf_map.unit == "sr-1"
def get_psf(): filename = ( "$GAMMAPY_DATA/cta-1dc/caldb/data/cta/1dc/bcf/South_z20_50h/irf_file.fits" ) psf = EnergyDependentMultiGaussPSF.read(filename, hdu="POINT SPREAD FUNCTION") table_psf = psf.to_energy_dependent_table_psf(theta=0.5 * u.deg) psf_map = PSFMap.from_energy_dependent_table_psf(table_psf) return psf_map
def test_psf_map_write_gtpsf(tmpdir): energy_axis_true = MapAxis.from_energy_bounds( "1 TeV", "10 TeV", nbin=3, name="energy_true" ) geom = RegionGeom.create("icrs;circle(0, 0, 0.1)") psf = PSFMap.from_gauss( energy_axis_true=energy_axis_true, sigma=[0.1, 0.2, 0.3] * u.deg, geom=geom ) psf.exposure_map = Map.from_geom(geom.to_cube([energy_axis_true]), unit="cm2 s") filename = tmpdir / "test_psf.fits" psf.write(filename, format="gtpsf") psf = PSFMap.read(filename, format="gtpsf") value = psf.containment_radius(energy_true=energy_axis_true.center, fraction=0.394) assert_allclose(value, [0.1, 0.2, 0.3] * u.deg, rtol=1e-5) assert psf.psf_map.unit == "sr-1"
def __init__( self, evt_file="../data/joint-crab/fermi/events.fits.gz", exp_file="../data/joint-crab/fermi/exposure_cube.fits.gz", psf_file="../data/joint-crab/fermi/psf.fits.gz", ): # Read data self.events = EventList.read(evt_file) self.exposure = HpxNDMap.read(exp_file) self.exposure.unit = u.Unit("cm2s") # no unit stored on map... self.psf = PSFMap.read(psf_file, format="gtpsf")
def test_psf_containment_coords(): # regression test to check the cooordinate conversion for PSFMap.containment psf = PSFMap.read("$GAMMAPY_DATA/cta-1dc-gc/cta-1dc-gc.fits.gz", hdu="PSF") position = SkyCoord("266.415d", "-29.006d", frame="icrs") radius = psf.containment_radius(energy_true=1 * u.TeV, fraction=0.99, position=position) assert_allclose(radius, 0.10575 * u.deg, rtol=1e-5)
def test_psfmap_to_from_hdulist(): psfmap = make_test_psfmap(0.15 * u.deg) hdulist = psfmap.to_hdulist(psf_hdu="PSF", psf_hdubands="BANDS") assert "PSF" in hdulist assert "BANDS" in hdulist assert "EXPMAP" in hdulist assert "BANDSEXP" in hdulist new_psfmap = PSFMap.from_hdulist(hdulist, psf_hdu="PSF", psf_hdubands="BANDS") assert_allclose(psfmap.psf_map.data, new_psfmap.psf_map.data) assert new_psfmap.psf_map.geom == psfmap.psf_map.geom assert new_psfmap.exposure_map.geom == psfmap.exposure_map.geom
def test_psfmap_to_from_hdulist(): psfmap = make_test_psfmap(0.15 * u.deg) hdulist = psfmap.to_hdulist() assert "PSF" in hdulist assert "PSF_BANDS" in hdulist assert "PSF_EXPOSURE" in hdulist assert "PSF_EXPOSURE_BANDS" in hdulist new_psfmap = PSFMap.from_hdulist(hdulist) assert_allclose(psfmap.psf_map.data, new_psfmap.psf_map.data) assert new_psfmap.psf_map.geom == psfmap.psf_map.geom assert new_psfmap.exposure_map.geom == psfmap.exposure_map.geom
def test_psf_map_from_table_psf(position): position = SkyCoord(position) filename = "$GAMMAPY_DATA/fermi_3fhl/fermi_3fhl_psf_gc.fits.gz" table_psf = EnergyDependentTablePSF.read(filename) psf_map = PSFMap.from_energy_dependent_table_psf(table_psf) table_psf_new = psf_map.get_energy_dependent_table_psf(position) assert_allclose(table_psf_new.data.data, table_psf.data.data) assert table_psf_new.data.data.unit == "sr-1" assert_allclose(table_psf_new.exposure.value, table_psf.exposure.value) assert table_psf_new.exposure.unit == "cm2 s"
def make_psf_map(psf, pointing, geom, exposure_map=None): """Make a psf map for a single observation Expected axes : rad and true energy in this specific order The name of the rad MapAxis is expected to be 'rad' Parameters ---------- psf : `~gammapy.irf.PSF3D` the PSF IRF pointing : `~astropy.coordinates.SkyCoord` the pointing direction geom : `~gammapy.maps.Geom` the map geom to be used. It provides the target geometry. rad and true energy axes should be given in this specific order. exposure_map : `~gammapy.maps.Map`, optional the associated exposure map. default is None Returns ------- psfmap : `~gammapy.cube.PSFMap` the resulting PSF map """ energy_axis = geom.get_axis_by_name("energy_true") energy = energy_axis.center rad_axis = geom.get_axis_by_name("theta") rad = rad_axis.center # Compute separations with pointing position offset = geom.separation(pointing) # Compute PSF values # TODO: allow broadcasting in PSF3D.evaluate() psf_values = psf._interpolate( ( rad[:, np.newaxis, np.newaxis], offset, energy[:, np.newaxis, np.newaxis, np.newaxis], ) ) # TODO: this probably does not ensure that probability is properly normalized in the PSFMap # Create Map and fill relevant entries data = psf_values.to_value("sr-1") psfmap = Map.from_geom(geom, data=data, unit="sr-1") return PSFMap(psfmap, exposure_map)
def test_psf_map_from_gauss_const_sigma(): energy_axis = MapAxis.from_nodes( [1, 3, 10], name="energy_true", interp="log", unit="TeV" ) rad = np.linspace(0, 1.5, 100) * u.deg rad_axis = MapAxis.from_nodes(rad, name="rad", unit="deg") # with constant sigma psfmap = PSFMap.from_gauss(energy_axis, rad_axis, sigma=0.1 * u.deg) assert psfmap.psf_map.geom.axes[0] == rad_axis assert psfmap.psf_map.geom.axes[1] == energy_axis assert psfmap.psf_map.unit == Unit("sr-1") assert psfmap.psf_map.data.shape == (3, 100, 1, 2) radius = psfmap.containment_radius(energy_true=[1, 3, 10] * u.TeV, fraction=0.394) assert_allclose(radius, 0.1 * u.deg, rtol=0.01)
def make_psf_map(psf, pointing, geom, exposure_map=None): """Make a psf map for a single observation Expected axes : rad and true energy in this specific order The name of the rad MapAxis is expected to be 'rad' Parameters ---------- psf : `~gammapy.irf.PSF3D` the PSF IRF pointing : `~astropy.coordinates.SkyCoord` the pointing direction geom : `~gammapy.maps.Geom` the map geom to be used. It provides the target geometry. rad and true energy axes should be given in this specific order. exposure_map : `~gammapy.maps.Map`, optional the associated exposure map. default is None use_region_center: bool If geom is a RegionGeom, whether to just consider the values at the region center or the insted the average over the whole region Returns ------- psfmap : `~gammapy.irf.PSFMap` the resulting PSF map """ energy_true = geom.axes["energy_true"].center rad = geom.axes["rad"].center # Compute separations with pointing position offset = geom.separation(pointing) # Compute PSF values psf_values = psf.evaluate( energy_true=energy_true[:, np.newaxis, np.newaxis, np.newaxis], offset=offset, rad=rad[:, np.newaxis, np.newaxis], ) # TODO: this probably does not ensure that probability is properly normalized in the PSFMap # Create Map and fill relevant entries data = psf_values.to_value("sr-1") psfmap = Map.from_geom(geom, data=data, unit="sr-1") return PSFMap(psfmap, exposure_map)
def fake_dataset(): axis = MapAxis.from_energy_bounds(0.1, 10, 5, unit="TeV", name="energy") axis_true = MapAxis.from_energy_bounds(0.05, 20, 10, unit="TeV", name="energy_true") geom = WcsGeom.create(npix=50, binsz=0.02, axes=[axis]) dataset = MapDataset.create(geom) dataset.psf = PSFMap.from_gauss(axis_true, sigma="0.05 deg") dataset.mask_safe += np.ones(dataset.data_shape, dtype=bool) dataset.background += 1 dataset.exposure += 1e12 * u.cm ** 2 * u.s spatial_model = PointSpatialModel() spectral_model = PowerLawSpectralModel(amplitude="1e-10 cm-2s-1TeV-1", index=2) model = SkyModel( spatial_model=spatial_model, spectral_model=spectral_model, name="source" ) dataset.models = [model] dataset.fake(random_state=42) return dataset
def prepare_dataset(): energy = MapAxis.from_energy_bounds(0.1, 100, 5, per_decade=True, unit="TeV") energy_true = MapAxis.from_energy_bounds(0.1, 100, 5, unit="TeV", per_decade=True, name="energy_true") geom = WcsGeom.create(npix=500, binsz=0.01, axes=[energy]) dataset = MapDataset.create(geom, energy_axis_true=energy_true) dataset.exposure += "1 m2 s" dataset.psf = PSFMap.from_gauss(energy_true) dataset.edisp = EDispKernelMap.from_gauss(energy, energy_true, 0.1, 0.) return Datasets([dataset])
def make_psf_map(psf, pointing, geom, exposure_map=None): """Make a psf map for a single observation Expected axes : rad and true energy in this specific order The name of the rad MapAxis is expected to be 'rad' Parameters ---------- psf : `~gammapy.irf.PSF3D` the PSF IRF pointing : `~astropy.coordinates.SkyCoord` the pointing direction geom : `~gammapy.maps.Geom` the map geom to be used. It provides the target geometry. rad and true energy axes should be given in this specific order. exposure_map : `~gammapy.maps.Map`, optional the associated exposure map. default is None Returns ------- psfmap : `~gammapy.irf.PSFMap` the resulting PSF map """ coords = geom.get_coord(sparse=True) # Compute separations with pointing position offset = coords.skycoord.separation(pointing) # Compute PSF values data = psf.evaluate( energy_true=coords["energy_true"], offset=offset, rad=coords["rad"], ) # Create Map and fill relevant entries psf_map = Map.from_geom(geom, data=data.value, unit=data.unit) psf_map.normalize(axis_name="rad") return PSFMap(psf_map, exposure_map)
def test_significance_map_estimator_map_dataset_exposure(simple_dataset): simple_dataset.exposure += 1e10 * u.cm**2 * u.s axis = simple_dataset.exposure.geom.axes[0] simple_dataset.psf = PSFMap.from_gauss(axis, sigma="0.05 deg") model = SkyModel( PowerLawSpectralModel(amplitude="1e-9 cm-2 s-1 TeV-1"), GaussianSpatialModel(lat_0=0.0 * u.deg, lon_0=0.0 * u.deg, sigma=0.1 * u.deg, frame="icrs"), name="sky_model", ) simple_dataset.models = [model] simple_dataset.npred() estimator = ExcessMapEstimator(0.1 * u.deg, selection_optional="all") result = estimator.run(simple_dataset) assert_allclose(result["npred_excess"].data.sum(), 19733.602, rtol=1e-3) assert_allclose(result["sqrt_ts"].data[0, 10, 10], 4.217129, rtol=1e-3)
"""Plot Fermi PSF.""" from gammapy.irf import PSFMap from gammapy.maps import MapAxis, WcsGeom filename = "$GAMMAPY_DATA/fermi_3fhl/fermi_3fhl_psf_gc.fits.gz" psf = PSFMap.read(filename, format="gtpsf") axis = MapAxis.from_energy_bounds("10 GeV", "2 TeV", nbin=20, name="energy_true") geom = WcsGeom.create(npix=50, binsz=0.01, axes=[axis]) # .to_image() computes the exposure weighted mean PSF kernel = psf.get_psf_kernel(geom=geom).to_image() kernel.psf_kernel_map.plot()
def test_interpolate_map_dataset(): energy = MapAxis.from_energy_bounds("1 TeV", "300 TeV", nbin=5, name="energy") energy_true = MapAxis.from_nodes(np.logspace(-1, 3, 20), name="energy_true", interp="log", unit="TeV") # make dummy map IRFs geom_allsky = WcsGeom.create(npix=(5, 3), proj="CAR", binsz=60, axes=[energy], skydir=(0, 0)) geom_allsky_true = geom_allsky.drop('energy').to_cube([energy_true]) #background value = 30 bkg_map = Map.from_geom(geom_allsky, unit="") bkg_map.data = value*np.ones(bkg_map.data.shape) #effective area - with a gradient that also depends on energy aeff_map = Map.from_geom(geom_allsky_true, unit="cm2 s") ra_arr = np.arange(aeff_map.data.shape[1]) dec_arr = np.arange(aeff_map.data.shape[2]) for i in np.arange(aeff_map.data.shape[0]): aeff_map.data[i, :, :] = (i+1)*10*np.meshgrid(dec_arr, ra_arr)[0]+10*np.meshgrid(dec_arr, ra_arr)[1]+10 aeff_map.meta["TELESCOP"] = "HAWC" #psf map width = 0.2*u.deg rad_axis = MapAxis.from_nodes(np.linspace(0, 2, 50), name="rad", unit="deg") psfMap = PSFMap.from_gauss(energy_true, rad_axis, width) #edispmap edispmap = EDispKernelMap.from_gauss(energy, energy_true, sigma=0.1, bias=0.0, geom=geom_allsky) #events and gti nr_ev = 10 ev_t = Table() gti_t = Table() ev_t['EVENT_ID'] = np.arange(nr_ev) ev_t['TIME'] = nr_ev*[Time('2011-01-01 00:00:00', scale='utc', format='iso')] ev_t['RA'] = np.linspace(-1, 1, nr_ev)*u.deg ev_t['DEC'] = np.linspace(-1, 1, nr_ev)*u.deg ev_t['ENERGY'] = np.logspace(0, 2, nr_ev)*u.TeV gti_t['START'] = [Time('2010-12-31 00:00:00', scale='utc', format='iso')] gti_t['STOP'] = [Time('2011-01-02 00:00:00', scale='utc', format='iso')] events = EventList(ev_t) gti = GTI(gti_t) #define observation obs = Observation( obs_id=0, obs_info={}, gti=gti, aeff=aeff_map, edisp=edispmap, psf=psfMap, bkg=bkg_map, events=events, obs_filter=None, ) #define analysis geometry geom_target = WcsGeom.create( skydir=(0, 0), width=(10, 10), binsz=0.1*u.deg, axes=[energy] ) maker = MapDatasetMaker(selection=["exposure", "counts", "background", "edisp", "psf"]) dataset = MapDataset.create(geom=geom_target, energy_axis_true=energy_true, name="test") dataset = maker.run(dataset, obs) # test counts assert dataset.counts.data.sum() == nr_ev #test background coords_bg = { 'skycoord' : SkyCoord("0 deg", "0 deg"), 'energy' : energy.center[0] } assert_allclose( dataset.background_model.evaluate().get_by_coord(coords_bg)[0], value, atol=1e-7) #test effective area coords_aeff = { 'skycoord' : SkyCoord("0 deg", "0 deg"), 'energy_true' : energy_true.center[0] } assert_allclose( aeff_map.get_by_coord(coords_aeff)[0]/dataset.exposure.get_by_coord(coords_aeff)[0], 1, atol=1e-3) #test edispmap pdfmatrix_preinterp = edispmap.get_edisp_kernel(SkyCoord("0 deg", "0 deg")).pdf_matrix pdfmatrix_postinterp = dataset.edisp.get_edisp_kernel(SkyCoord("0 deg", "0 deg")).pdf_matrix assert_allclose(pdfmatrix_preinterp, pdfmatrix_postinterp, atol=1e-7) #test psfmap geom_psf = geom_target.drop('energy').to_cube([energy_true]) psfkernel_preinterp = psfMap.get_psf_kernel(SkyCoord("0 deg", "0 deg"), geom_psf, max_radius=2*u.deg).data psfkernel_postinterp = dataset.psf.get_psf_kernel(SkyCoord("0 deg", "0 deg"), geom_psf, max_radius=2*u.deg).data assert_allclose(psfkernel_preinterp, psfkernel_postinterp, atol=1e-4)