Пример #1
0
    def to_energy_dependent_table_psf(self, offset, rad=None):
        """Convert to energy-dependent table PSF.

        Parameters
        ----------
        offset : `~astropy.coordinates.Angle`
            Offset in the field of view. Default theta = 0 deg
        rad : `~astropy.coordinates.Angle`
            Offset from PSF center used for evaluating the PSF on a grid.
            Default offset = [0, 0.005, ..., 1.495, 1.5] deg.

        Returns
        -------
        table_psf : `~gammapy.irf.EnergyDependentTablePSF`
            Energy-dependent PSF
        """
        from gammapy.irf import EnergyDependentTablePSF
        from gammapy.datasets.map import RAD_AXIS_DEFAULT

        energy_axis_true = self.axes["energy_true"]

        if rad is None:
            rad_axis = RAD_AXIS_DEFAULT
        else:
            rad_axis = MapAxis.from_edges(rad, name="rad")

        axes = MapAxes([energy_axis_true, rad_axis])
        data = self.evaluate(**axes.get_coord(), offset=offset)
        return EnergyDependentTablePSF(axes=axes,
                                       data=data.value,
                                       unit=data.unit)
Пример #2
0
    def get_energy_dependent_table_psf(self, position):
        """Get energy-dependent PSF at a given position.

        Parameters
        ----------
        position : `~astropy.coordinates.SkyCoord`
            the target position. Should be a single coordinates

        Returns
        -------
        psf_table : `~gammapy.irf.EnergyDependentTablePSF`
            the table PSF
        """
        if position.size != 1:
            raise ValueError(
                "EnergyDependentTablePSF can be extracted at one single position only."
            )

        # axes ordering fixed. Could be changed.
        pix_ener = np.arange(self.psf_map.geom.axes[1].nbin)
        pix_rad = np.arange(self.psf_map.geom.axes[0].nbin)

        # Convert position to pixels
        pix_lon, pix_lat = self.psf_map.geom.to_image().coord_to_pix(position)

        # Build the pixels tuple
        pix = np.meshgrid(pix_lon, pix_lat, pix_rad, pix_ener)

        # Interpolate in the PSF map. Squeeze to remove dimensions of length 1
        psf_values = np.squeeze(
            self.psf_map.interp_by_pix(pix) * u.Unit(self.psf_map.unit)
        )

        energies = self.psf_map.geom.axes[1].center
        rad = self.psf_map.geom.axes[0].center

        if self.exposure_map is not None:
            exposure_3d = self.exposure_map.slice_by_idx({"theta": 0})
            coords = {
                "skycoord": position,
                "energy": energies.reshape((-1, 1, 1))
            }
            data = exposure_3d.interp_by_coord(coords).squeeze()
            exposure = data * self.exposure_map.unit
        else:
            exposure = None

        # Beware. Need to revert rad and energies to follow the TablePSF scheme.
        return EnergyDependentTablePSF(
            energy=energies,
            rad=rad,
            psf_value=psf_values.T,
            exposure=exposure
        )
Пример #3
0
    def get_energy_dependent_table_psf(self, position):
        """Get energy-dependent PSF at a given position.

        Parameters
        ----------
        position : `~astropy.coordinates.SkyCoord`
            the target position. Should be a single coordinates

        Returns
        -------
        psf_table : `~gammapy.irf.EnergyDependentTablePSF`
            the table PSF
        """
        if position.size != 1:
            raise ValueError(
                "EnergyDependentTablePSF can be extracted at one single position only."
            )

        energy = self.psf_map.geom.get_axis_by_name("energy").center
        rad = self.psf_map.geom.get_axis_by_name("theta").center

        coords = {
            "skycoord": position,
            "energy": energy.reshape((-1, 1, 1, 1)),
            "theta": rad.reshape((1, -1, 1, 1)),
        }

        data = self.psf_map.interp_by_coord(coords)
        psf_values = u.Quantity(data[:, :, 0, 0],
                                unit=self.psf_map.unit,
                                copy=False)

        if self.exposure_map is not None:
            coords = {
                "skycoord": position,
                "energy": energy.reshape((-1, 1, 1)),
                "theta": 0 * u.deg,
            }
            data = self.exposure_map.interp_by_coord(coords).squeeze()
            exposure = data * self.exposure_map.unit
        else:
            exposure = None

        # Beware. Need to revert rad and energies to follow the TablePSF scheme.
        return EnergyDependentTablePSF(energy=energy,
                                       rad=rad,
                                       psf_value=psf_values,
                                       exposure=exposure)
Пример #4
0
def test_apply_containment_fraction():
    n_edges_energy = 5
    energy = energy_logspace(0.1, 10.0, nbins=n_edges_energy + 1, unit="TeV")
    area = np.ones(n_edges_energy) * 4 * u.m**2
    aeff = EffectiveAreaTable(energy[:-1], energy[1:], data=area)

    nrad = 100
    rad = Angle(np.linspace(0, 0.5, nrad), "deg")
    psf_table = TablePSF.from_shape(shape="disk", width="0.2 deg", rad=rad)
    psf_values = (np.resize(psf_table.psf_value.value,
                            (n_edges_energy, nrad)) * psf_table.psf_value.unit)
    edep_psf_table = EnergyDependentTablePSF(aeff.energy.center,
                                             rad,
                                             psf_value=psf_values)

    new_aeff = apply_containment_fraction(aeff, edep_psf_table,
                                          Angle("0.1 deg"))

    assert_allclose(new_aeff.data.data.value, 1.0, rtol=5e-4)
    assert new_aeff.data.data.unit == "m2"