Ejemplo n.º 1
0
def fake_psf3d(sigma=0.15 * u.deg, shape="gauss"):
    offset_axis = MapAxis.from_nodes([0, 1, 2, 3] * u.deg, name="offset")

    energy_axis_true = MapAxis.from_energy_bounds("0.1 TeV",
                                                  "10 TeV",
                                                  nbin=4,
                                                  name="energy_true")

    rad = np.linspace(0, 1.0, 101) * u.deg
    rad_axis = MapAxis.from_edges(rad, name="rad")

    O, R, E = np.meshgrid(offset_axis.center, rad_axis.edges,
                          energy_axis_true.center)

    Rmid = 0.5 * (R[:-1] + R[1:])
    if shape == "gauss":
        val = np.exp(-0.5 * Rmid**2 / sigma**2)
    else:
        val = Rmid < sigma

    drad = 2 * np.pi * (np.cos(R[:-1]) - np.cos(R[1:])) * u.Unit("sr")
    psf_value = val / ((val * drad).sum(0)[0])

    return PSF3D(
        energy_axis_true=energy_axis_true,
        rad_axis=rad_axis,
        offset_axis=offset_axis,
        data=psf_value.T,
    )
Ejemplo n.º 2
0
def test_psf_table():
    '''Test our psf is readable by gammapy'''
    pytest.importorskip('gammapy')
    from pyirf.io import create_psf_table_hdu
    from pyirf.utils import cone_solid_angle
    from gammapy.irf import PSF3D

    e_bins = np.geomspace(0.1, 100, 31) * u.TeV
    source_bins = np.linspace(0, 1, 101) * u.deg
    fov_bins = [0, 1, 2, 3] * u.deg
    psf = np.zeros((30, 100, 3))
    psf[:, 0, :] = 1
    psf = psf / cone_solid_angle(source_bins[1])

    for point_like in [True, False]:
        with tempfile.NamedTemporaryFile(suffix='.fits') as f:
            hdu = create_psf_table_hdu(psf,
                                       e_bins,
                                       source_bins,
                                       fov_bins,
                                       point_like=point_like)

            fits.HDUList([fits.PrimaryHDU(), hdu]).writeto(f.name)

            # test reading with gammapy works
            psf3d = PSF3D.read(f.name, 'PSF')

            # gammapy does not transpose psf when reading from fits,
            # unlike how it handles effective area and edisp
            # see https://github.com/gammapy/gammapy/issues/3025
            assert u.allclose(psf, psf3d.psf_value.T, atol=1e-16 / u.sr)
Ejemplo n.º 3
0
    def to_psf3d(self, rad=None):
        """Create a PSF3D from a parametric PSF.

        It will be defined on the same energy and offset values than the input psf.

        Parameters
        ----------
        rad : `~astropy.units.Quantity`
            Rad values

        Returns
        -------
        psf3d : `~gammapy.irf.PSF3D`
            PSF3D.
        """
        from gammapy.irf import PSF3D
        from gammapy.datasets.map import RAD_AXIS_DEFAULT

        offset_axis = self.axes["offset"]
        energy_axis_true = self.axes["energy_true"]

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

        axes = MapAxes([energy_axis_true, offset_axis, rad_axis])
        data = self.evaluate(**axes.get_coord())

        return PSF3D(axes=axes,
                     data=data.value,
                     unit=data.unit,
                     meta=self.meta.copy())
Ejemplo n.º 4
0
def test_psf_3d_wrong_units():
    energy_axis = MapAxis.from_energy_edges([80, 125] * u.GeV,
                                            name="energy_true")

    offset_axis = MapAxis.from_edges([0, 1, 2], unit="deg", name="offset")

    rad_axis = MapAxis.from_edges([0, 1, 2], unit="deg", name="rad")

    wrong_unit = u.cm**2 * u.s
    data = np.ones(
        (energy_axis.nbin, offset_axis.nbin, rad_axis.nbin)) * wrong_unit
    psf3d_test = PSF3D(axes=[energy_axis, offset_axis, rad_axis])
    with pytest.raises(ValueError) as error:
        PSF3D(axes=[energy_axis, offset_axis, rad_axis], data=data)
        assert error.match(
            f"Error: {wrong_unit} is not an allowed unit. {psf3d_test.tag} requires {psf3d_test.default_unit} data quantities."
        )
Ejemplo n.º 5
0
def test_psf_table_gammapy(psf_hdu):
    '''Test our psf is readable by gammapy'''
    from gammapy.irf import PSF3D

    psf, hdu = psf_hdu

    with tempfile.NamedTemporaryFile(suffix='.fits') as f:
        fits.HDUList([fits.PrimaryHDU(), hdu]).writeto(f.name)

        # test reading with gammapy works
        psf3d = PSF3D.read(f.name, 'PSF')
        assert u.allclose(psf, psf3d.psf_value, atol=1e-16 / u.sr)
Ejemplo n.º 6
0
def test_psf_table_gammapy(psf_hdu):
    '''Test our psf is readable by gammapy'''
    from gammapy.irf import PSF3D

    psf, hdu = psf_hdu

    with tempfile.NamedTemporaryFile(suffix='.fits') as f:
        fits.HDUList([fits.PrimaryHDU(), hdu]).writeto(f.name)

        # test reading with gammapy works
        psf3d = PSF3D.read(f.name, 'PSF')

        # gammapy does not transpose psf when reading from fits,
        # unlike how it handles effective area and edisp
        # see https://github.com/gammapy/gammapy/issues/3025
        assert u.allclose(psf, psf3d.psf_value.T, atol=1e-16 / u.sr)
Ejemplo n.º 7
0
    def load(self):
        """Load HDU as appropriate class.

        TODO: this should probably go via an extensible registry.
        """
        hdu_class = self.hdu_class
        filename = self.path()
        hdu = self.hdu_name

        if hdu_class == "events":
            from gammapy.data import EventList

            return EventList.read(filename, hdu=hdu)
        elif hdu_class == "gti":
            from gammapy.data import GTI

            return GTI.read(filename, hdu=hdu)
        elif hdu_class == "aeff_2d":
            from gammapy.irf import EffectiveAreaTable2D

            return EffectiveAreaTable2D.read(filename, hdu=hdu)
        elif hdu_class == "edisp_2d":
            from gammapy.irf import EnergyDispersion2D

            return EnergyDispersion2D.read(filename, hdu=hdu)
        elif hdu_class == "psf_table":
            from gammapy.irf import PSF3D

            return PSF3D.read(filename, hdu=hdu)
        elif hdu_class == "psf_3gauss":
            from gammapy.irf import EnergyDependentMultiGaussPSF

            return EnergyDependentMultiGaussPSF.read(filename, hdu=hdu)
        elif hdu_class == "psf_king":
            from gammapy.irf import PSFKing

            return PSFKing.read(filename, hdu=hdu)
        elif hdu_class == "bkg_2d":
            from gammapy.irf import Background2D

            return Background2D.read(filename, hdu=hdu)
        elif hdu_class == "bkg_3d":
            from gammapy.irf import Background3D

            return Background3D.read(filename, hdu=hdu)
        else:
            raise ValueError(f"Invalid hdu_class: {hdu_class}")
Ejemplo n.º 8
0
def test_psf_3d_basics(psf_3d):
    rad_axis = psf_3d.axes["rad"]
    assert_allclose(rad_axis.edges[-2].value, 0.659048, rtol=1e-5)
    assert rad_axis.nbin == 144
    assert rad_axis.unit == "deg"

    energy_axis_true = psf_3d.axes["energy_true"]
    assert_allclose(energy_axis_true.edges[0].value, 0.01)
    assert energy_axis_true.nbin == 32
    assert energy_axis_true.unit == "TeV"

    assert psf_3d.data.shape == (32, 6, 144)
    assert psf_3d.unit == "sr-1"

    assert_allclose(psf_3d.meta["LO_THRES"], 0.01)

    assert "PSF3D" in str(psf_3d)

    with pytest.raises(ValueError):
        PSF3D(axes=psf_3d.axes, data=psf_3d.data.T)
Ejemplo n.º 9
0
def fake_psf3d(sigma=0.15 * u.deg, shape="gauss"):
    offsets = np.array((0.0, 1.0, 2.0, 3.0)) * u.deg
    energy = np.logspace(-1, 1, 5) * u.TeV
    energy_lo = energy[:-1]
    energy_hi = energy[1:]
    energy = np.sqrt(energy_lo * energy_hi)
    rad = np.linspace(0, 1.0, 101) * u.deg
    rad_lo = rad[:-1]
    rad_hi = rad[1:]

    O, R, E = np.meshgrid(offsets, rad, energy)

    Rmid = 0.5 * (R[:-1] + R[1:])
    if shape == "gauss":
        val = np.exp(-0.5 * Rmid**2 / sigma**2)
    else:
        val = Rmid < sigma
    drad = 2 * np.pi * (np.cos(R[:-1]) - np.cos(R[1:])) * u.Unit("sr")
    psf_values = val / ((val * drad).sum(0)[0])

    return PSF3D(energy_lo, energy_hi, offsets, rad_lo, rad_hi, psf_values)
Ejemplo n.º 10
0
def test_psf_3d_to_gadf():
    from gammapy.irf import PSF3D
    from gammapy.maps import MapAxis

    energy_axis = MapAxis.from_energy_bounds(1 * u.TeV,
                                             10 * u.TeV,
                                             nbin=3,
                                             name='energy_true')
    offset_axis = MapAxis.from_bounds(0 * u.deg,
                                      2 * u.deg,
                                      nbin=2,
                                      name='offset')
    rad_axis = MapAxis.from_bounds(0.0 * u.deg, 1 * u.deg, nbin=10, name='rad')
    data = np.zeros((energy_axis.nbin, offset_axis.nbin, rad_axis.nbin)) / u.sr

    psf = PSF3D(data=data, axes=[energy_axis, offset_axis, rad_axis])
    hdu = psf.to_table_hdu(format='gadf-dl3')

    mandatory_columns = {
        'ENERG_LO',
        'ENERG_HI',
        'THETA_LO',
        'THETA_HI',
        'RAD_LO',
        'RAD_HI',
        'RPSF',
    }
    columns = {column.name for column in hdu.columns}
    missing = mandatory_columns.difference(columns)
    assert len(missing) == 0, f'GADF HDU missing required column(s) {missing}'

    header = hdu.header
    assert header['HDUCLASS'] == 'GADF'
    assert header[
        'HDUDOC'] == 'https://github.com/open-gamma-ray-astro/gamma-astro-data-formats'
    assert header['HDUVERS'] == '0.2'
    assert header['HDUCLAS1'] == 'RESPONSE'
    assert header['HDUCLAS2'] == 'RPSF'
    assert header['HDUCLAS3'] == 'FULL-ENCLOSURE'
    assert header['HDUCLAS4'] == 'PSF_TABLE'
Ejemplo n.º 11
0
def test_psf_3d_basics(psf_3d):
    assert_allclose(psf_3d.rad_axis.edges[-2].value, 0.659048, rtol=1e-5)
    assert psf_3d.rad_axis.nbin == 144
    assert psf_3d.rad_axis.unit == "deg"

    assert_allclose(psf_3d.energy_axis_true.edges[0].value, 0.01)
    assert psf_3d.energy_axis_true.nbin == 32
    assert psf_3d.energy_axis_true.unit == "TeV"

    assert psf_3d.psf_value.shape == (32, 6, 144)
    assert psf_3d.psf_value.unit == "sr-1"

    assert_allclose(psf_3d.energy_thresh_lo.value, 0.01)

    assert "PSF3D" in str(psf_3d)

    with pytest.raises(ValueError):
        PSF3D(
            energy_axis_true=psf_3d.energy_axis_true,
            offset_axis=psf_3d.offset_axis,
            rad_axis=psf_3d.rad_axis,
            psf_value=psf_3d.psf_value.T,
        )
Ejemplo n.º 12
0
def psf_3d_plot(irf_file_path, ax=None, hdu="PSF"):
    if not ax:
        fig = plt.figure(figsize=(10, 7), )
        ax = fig.add_subplot(111, projection='3d')

    psf = PSF3D.read(irf_file_path, hdu=hdu)
    energy_reco = np.logspace(-2, 2, 20) * u.TeV
    offsets = np.linspace(0, 6, 7) * u.deg

    d = np.linspace(0.01, 1.1, 11)[1::2]
    ticks = np.log10(d)
    # ticks = np.append(ticks, 1 + ticks)

    X, Y = np.meshgrid(energy_reco, offsets)
    Z = []
    for x in energy_reco:
        zs = psf.containment_radius(x, offsets, fraction=0.68)
        Z.append(zs)

    Z = np.vstack(Z).T
    ax.plot_surface(np.log10(X.to_value('TeV')),
                    Y,
                    np.log10(Z),
                    cmap='viridis',
                    linewidth=1,
                    antialiased=True)

    ax.xaxis.set_major_locator(mticker.FixedLocator([-2, -1, 0, 1, 2]))
    ax.zaxis.set_major_locator(mticker.FixedLocator(ticks))

    ax.zaxis.set_major_formatter(mticker.FuncFormatter(_log_scale_formatter))
    ax.xaxis.set_major_formatter(mticker.FuncFormatter(_log_tick_formatter))
    ax.set_zlim([-1, 0.4])
    ax.set_ylabel('Offset in FoV / deg')
    ax.set_zlabel('Angular Resolution / deg')
    ax.set_xlabel('Reconstructed Energy / TeV')
    return ax
Ejemplo n.º 13
0
def create_psf_3d(
    psf,
    true_energy_bins,
    source_offset_bins,
    fov_offset_bins,
):
    """
    Create a ``gammapy.irf.PSF3D`` from pyirf outputs.

    Parameters
    ----------
    psf: astropy.units.Quantity[(solid angle)^-1]
        Point spread function array, must have shape
        (n_energy_bins, n_fov_offset_bins, n_source_offset_bins)
    true_energy_bins: astropy.units.Quantity[energy]
        Bin edges in true energy
    source_offset_bins: astropy.units.Quantity[angle]
        Bin edges in the source offset.
    fov_offset_bins: astropy.units.Quantity[angle]
        Bin edges in the field of view offset.
        For Point-Like IRFs, only giving a single bin is appropriate.

    Returns
    -------
    gammapy.irf.PSF3D
    """
    offset_axis = _create_offset_axis(fov_offset_bins)
    energy_axis_true = _create_energy_axis_true(true_energy_bins)
    rad_axis = MapAxis.from_edges(source_offset_bins, name='rad')

    return PSF3D(
        energy_axis_true=energy_axis_true,
        offset_axis=offset_axis,
        rad_axis=rad_axis,
        psf_value=psf,
    )
Ejemplo n.º 14
0
def load_psf():
    """Load a test PSF."""
    filename = '$GAMMAPY_EXTRA/test_datasets/psf_table_023523.fits.gz'
    print('Reading {}'.format(filename))

    return PSF3D.read(filename)
Ejemplo n.º 15
0
def test_psf_3d_write(psf_3d, tmp_path):
    psf_3d.write(tmp_path / "tmp.fits")
    psf_3d = PSF3D.read(tmp_path / "tmp.fits", hdu=1)

    assert_allclose(psf_3d.energy_axis_true.edges[0].value, 0.01)
Ejemplo n.º 16
0
def psf_3d():
    filename = "$GAMMAPY_DATA/tests/psf_table_023523.fits.gz"
    return PSF3D.read(filename)
Ejemplo n.º 17
0
def load_psf():
    """Load a test PSF."""
    filename = '$GAMMAPY_EXTRA/test_datasets/psf_table_023523.fits.gz'
    print('Reading {}'.format(filename))

    return PSF3D.read(filename)
Ejemplo n.º 18
0
 def setup(self):
     filename = "$GAMMAPY_DATA/tests/hess-hap-hd-prod3/psf_table.fits.gz"
     self.psf = PSF3D.read(filename)
Ejemplo n.º 19
0
def psf_3d():
    filename = "$GAMMAPY_DATA/hess-dl3-dr1/data/hess_dl3_dr1_obs_id_023523.fits.gz"
    return PSF3D.read(filename, hdu="PSF")
Ejemplo n.º 20
0
"""Plot the PSF at a given offset from the camera center"""
import matplotlib.pyplot as plt
from astropy.coordinates import Angle
from gammapy.irf import PSF3D

filename = "$GAMMAPY_DATA/hess-dl3-dr1/data/hess_dl3_dr1_obs_id_020136.fits.gz"
psf = PSF3D.read(filename, hdu="PSF")
# offset at which we want to examine the PSF
offset = Angle("0.5 deg") 
psf_table = psf.to_energy_dependent_table_psf(offset)
psf_table.plot_psf_vs_rad()
plt.show()
Ejemplo n.º 21
0
def test_psf_3d_write(psf_3d, tmpdir):
    filename = str(tmpdir / "temp.fits")
    psf_3d.write(filename)
    psf_3d = PSF3D.read(filename)

    assert_allclose(psf_3d.energy_lo[0].value, 0.02)