Exemplo n.º 1
0
def test_mixed_axes():
    label_axis = LabelMapAxis(labels=["label-1", "label-2", "label-3"],
                              name="label")

    time_axis = TimeMapAxis(
        edges_min=[1, 10] * u.day,
        edges_max=[2, 13] * u.day,
        reference_time=Time("2020-03-19"),
    )

    energy_axis = MapAxis.from_energy_bounds("1 TeV", "10 TeV", nbin=4)

    axes = MapAxes(axes=[energy_axis, time_axis, label_axis])

    coords = axes.get_coord()

    assert coords["label"].shape == (1, 1, 3)
    assert coords["energy"].shape == (4, 1, 1)
    assert coords["time"].shape == (1, 2, 1)

    idx = axes.coord_to_idx(coords)

    assert_allclose(idx[0], np.arange(4).reshape((4, 1, 1)))
    assert_allclose(idx[1], np.arange(2).reshape((1, 2, 1)))
    assert_allclose(idx[2], np.arange(3).reshape((1, 1, 3)))

    hdu = axes.to_table_hdu(format="gadf")

    table = Table.read(hdu)

    assert table["LABEL"].dtype == np.dtype("<U7")
    assert len(table) == 24
Exemplo n.º 2
0
    def __init__(
            self,
            energy_axis_true,
            offset_axis,
            rad_axis,
            psf_value,
            energy_thresh_lo=u.Quantity(0.1, "TeV"),
            energy_thresh_hi=u.Quantity(100, "TeV"),
            interp_kwargs=None,
    ):

        axes = MapAxes([energy_axis_true, offset_axis, rad_axis])
        axes.assert_names(["energy_true", "offset", "rad"])

        if psf_value.shape != axes.shape:
            raise ValueError("PSF has wrong shape"
                             f", expected {axes.shape}, got {psf_value.shape}")

        self._energy_axis_true = energy_axis_true
        self._offset_axis = offset_axis
        self._rad_axis = rad_axis
        self.psf_value = psf_value.to("sr^-1")
        self.energy_thresh_lo = energy_thresh_lo.to("TeV")
        self.energy_thresh_hi = energy_thresh_hi.to("TeV")

        self._interp_kwargs = interp_kwargs or {}
Exemplo 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())
Exemplo n.º 4
0
    def __init__(
        self,
        energy_axis_true,
        rad_axis,
        exposure=None,
        psf_value=None,
        interp_kwargs=None,
    ):
        self._rad_axis = rad_axis
        self._energy_axis_true = energy_axis_true

        axes = MapAxes([energy_axis_true, rad_axis])
        axes.assert_names(["energy_true", "rad"])

        if exposure is None:
            self.exposure = u.Quantity(np.ones(self.energy_axis_true.nbin), "cm^2 s")
        else:
            self.exposure = u.Quantity(exposure).to("cm^2 s")

        if psf_value is None:
            self.psf_value = np.zeros(axes.shape) * u.Unit("sr^-1")
        else:
            if np.shape(psf_value) != axes.shape:
                raise ValueError(
                    "psf_value has wrong shape"
                    f", expected {axes.shape}, got {np.shape(psf_value)}"
                )
            self.psf_value = u.Quantity(psf_value).to("sr^-1")

        self._interp_kwargs = interp_kwargs or {}
Exemplo n.º 5
0
    def to_hdulist(self):
        """
        Convert PSF table data to FITS HDU list.

        Returns
        -------
        hdu_list : `~astropy.io.fits.HDUList`
            PSF in HDU list format.
        """
        axes = MapAxes([self.energy_axis_true, self.offset_axis])
        table = axes.to_table(format="gadf-dl3")

        # Set up data
        names = ["SIGMA", "GAMMA"]
        units = ["deg", ""]
        data = [
            self.sigma,
            self.gamma,
        ]

        for name_, data_, unit_ in zip(names, data, units):
            table[name_] = [data_]
            table[name_].unit = unit_

        hdu = fits.BinTableHDU(table)
        hdu.header.update(self.meta)
        return fits.HDUList([fits.PrimaryHDU(), hdu])
Exemplo n.º 6
0
    def __init__(
        self,
        axes,
        data=0,
        unit="",
        is_pointlike=False,
        fov_alignment=FoVAlignment.RADEC,
        meta=None,
        interp_kwargs=None,
    ):
        axes = MapAxes(axes)
        axes.assert_names(self.required_axes)
        self._axes = axes
        self._fov_alignment = FoVAlignment(fov_alignment)
        self._is_pointlike = is_pointlike

        if isinstance(data, u.Quantity):
            self.data = data.value
            if not self.default_unit.is_equivalent(data.unit):
                raise ValueError(
                    f"Error: {data.unit} is not an allowed unit. {self.tag} requires {self.default_unit} data quantities."
                )
            else:
                self._unit = data.unit
        else:
            self.data = data
            self._unit = unit
        self.meta = meta or {}
        if interp_kwargs is None:
            interp_kwargs = self.default_interp_kwargs.copy()
        self.interp_kwargs = interp_kwargs
Exemplo n.º 7
0
 def __init__(self, axes, data=0, unit="", meta=None):
     axes = MapAxes(axes)
     axes.assert_names(self.required_axes)
     self._axes = axes
     self.data = data
     self.unit = unit
     self.meta = meta or {}
Exemplo n.º 8
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)
Exemplo n.º 9
0
    def from_parametrization(cls, energy_axis_true=None, instrument="HESS"):
        r"""Create parametrized effective area.

        Parametrizations of the effective areas of different Cherenkov
        telescopes taken from Appendix B of Abramowski et al. (2010), see
        https://ui.adsabs.harvard.edu/abs/2010MNRAS.402.1342A .

        .. math::
            A_{eff}(E) = g_1 \left(\frac{E}{\mathrm{MeV}}\right)^{-g_2}\exp{\left(-\frac{g_3}{E}\right)}

        This method does not model the offset dependence of the effective area,
        but just assumes that it is constant.

        Parameters
        ----------
        energy_axis_true : `MapAxis`
            Energy binning, analytic function is evaluated at log centers
        instrument : {'HESS', 'HESS2', 'CTA'}
            Instrument name

        Returns
        -------
        aeff : `EffectiveAreaTable2D`
            Effective area table
        """
        # Put the parameters g in a dictionary.
        # Units: g1 (cm^2), g2 (), g3 (MeV)
        pars = {
            "HESS": [6.85e9, 0.0891, 5e5],
            "HESS2": [2.05e9, 0.0891, 1e5],
            "CTA": [1.71e11, 0.0891, 1e5],
        }

        if instrument not in pars.keys():
            ss = f"Unknown instrument: {instrument}\n"
            ss += f"Valid instruments: {list(pars.keys())}"
            raise ValueError(ss)

        if energy_axis_true is None:
            energy_axis_true = MapAxis.from_energy_bounds("2 GeV",
                                                          "200 TeV",
                                                          nbin=20,
                                                          per_decade=True,
                                                          name="energy_true")

        g1, g2, g3 = pars[instrument]

        offset_axis = MapAxis.from_edges([0., 5.] * u.deg, name="offset")
        axes = MapAxes([energy_axis_true, offset_axis])
        coords = axes.get_coord()

        energy, offset = coords["energy_true"].to_value(
            "MeV"), coords["offset"]
        data = np.ones_like(offset.value) * g1 * energy**(-g2) * np.exp(
            -g3 / energy)

        # TODO: fake offset dependence?
        meta = {"TELESCOP": instrument}
        return cls(axes=axes, data=data, unit="cm2", meta=meta)
Exemplo n.º 10
0
 def to_table(self):
     """Convert to `~astropy.table.Table`."""
     # TODO: fix axis order
     axes = MapAxes(self.data.axes[::-1])
     table = axes.to_table(format="gadf-dl3")
     table.meta = self.meta.copy()
     table["BKG"] = self.data.data.T[np.newaxis]
     return table
Exemplo n.º 11
0
def test_map_axes_pad():
    axis_1 = MapAxis.from_energy_bounds("1 TeV", "10 TeV", nbin=1)
    axis_2 = MapAxis.from_bounds(0, 1, nbin=2, unit="deg", name="rad")

    axes = MapAxes([axis_1, axis_2])

    axes = axes.pad(axis_name="energy", pad_width=1)

    assert_allclose(axes["energy"].edges, [0.1, 1, 10, 100] * u.TeV)
Exemplo n.º 12
0
 def __init__(self, axes, data=0, unit="", meta=None, interp_kwargs=None):
     axes = MapAxes(axes)
     axes.assert_names(self.required_axes)
     self._axes = axes
     self.data = data
     self.unit = unit
     self.meta = meta or {}
     if interp_kwargs is None:
         interp_kwargs = self.default_interp_kwargs.copy()
     self.interp_kwargs = interp_kwargs
Exemplo n.º 13
0
    def to_edisp_kernel(self, offset, energy_true=None, energy=None):
        """Detector response R(Delta E_reco, Delta E_true)

        Probability to reconstruct an energy in a given true energy band
        in a given reconstructed energy band

        Parameters
        ----------
        offset : `~astropy.coordinates.Angle`
            Offset
        energy_true : `~astropy.units.Quantity`, None
            True energy axis
        energy : `~astropy.units.Quantity`
            Reconstructed energy axis

        Returns
        -------
        edisp : `~gammapy.irf.EDispKernel`
            Energy dispersion matrix
        """
        offset = Angle(offset)

        # TODO: expect directly MapAxis here?
        if energy is None:
            energy_axis = self.axes["energy_true"].copy(name="energy")
        else:
            energy_axis = MapAxis.from_energy_edges(energy)

        if energy_true is None:
            energy_axis_true = self.axes["energy_true"]
        else:
            energy_axis_true = MapAxis.from_energy_edges(
                energy_true,
                name="energy_true",
            )

        axes = MapAxes([energy_axis_true, energy_axis])
        coords = axes.get_coord(mode="edges", axis_name="energy")

        # migration value of energy bounds
        migra = coords["energy"] / coords["energy_true"]

        values = self.integral(
            axis_name="migra",
            offset=offset,
            energy_true=coords["energy_true"],
            migra=migra,
        )

        data = np.diff(values)

        return EDispKernel(
            axes=axes,
            data=data.to_value(""),
        )
Exemplo n.º 14
0
    def from_gauss(cls,
                   energy_axis_true,
                   migra_axis,
                   offset_axis,
                   bias,
                   sigma,
                   pdf_threshold=1e-6):
        """Create Gaussian energy dispersion matrix (`EnergyDispersion2D`).

        The output matrix will be Gaussian in (energy_true / energy).

        The ``bias`` and ``sigma`` should be either floats or arrays of same dimension than
        ``energy_true``. ``bias`` refers to the mean value of the ``migra``
        distribution minus one, i.e. ``bias=0`` means no bias.

        Note that, the output matrix is flat in offset.

        Parameters
        ----------
        energy_axis_true : `MapAxis`
            True energy axis
        migra_axis : `~astropy.units.Quantity`
            Migra axis
        offset_axis : `~astropy.units.Quantity`
            Bin edges of offset
        bias : float or `~numpy.ndarray`
            Center of Gaussian energy dispersion, bias
        sigma : float or `~numpy.ndarray`
            RMS width of Gaussian energy dispersion, resolution.
        pdf_threshold : float, optional
            Zero suppression threshold
        """
        axes = MapAxes([energy_axis_true, migra_axis, offset_axis])
        coords = axes.get_coord(mode="edges", axis_name="migra")

        migra_min = coords["migra"][:, :-1, :]
        migra_max = coords["migra"][:, 1:, :]

        # Analytical formula for integral of Gaussian
        s = np.sqrt(2) * sigma
        t1 = (migra_max - 1 - bias) / s
        t2 = (migra_min - 1 - bias) / s
        pdf = (scipy.special.erf(t1) - scipy.special.erf(t2)) / 2
        pdf = pdf / (migra_max - migra_min)

        # no offset dependence
        data = pdf * np.ones(axes.shape)
        data[data < pdf_threshold] = 0

        return cls(
            axes=axes,
            data=data.value,
        )
Exemplo n.º 15
0
 def __init__(self, axes, data=0, unit="", meta=None, interp_kwargs=None):
     axes = MapAxes(axes)
     axes.assert_names(self.required_axes)
     self._axes = axes
     if isinstance(data, u.Quantity):
         self.data = data.value
         self.unit = data.unit
     else:
         self.data = data
         self.unit = unit
     self.meta = meta or {}
     if interp_kwargs is None:
         interp_kwargs = self.default_interp_kwargs.copy()
     self.interp_kwargs = interp_kwargs
Exemplo n.º 16
0
    def test_write(self):
        energy_axis_true = MapAxis.from_energy_bounds("1 TeV",
                                                      "10 TeV",
                                                      nbin=10,
                                                      name="energy_true")

        offset_axis = MapAxis.from_bounds(0,
                                          1,
                                          nbin=3,
                                          unit="deg",
                                          name="offset",
                                          node_type="edges")

        migra_axis = MapAxis.from_bounds(0,
                                         3,
                                         nbin=3,
                                         name="migra",
                                         node_type="edges")

        axes = MapAxes([energy_axis_true, migra_axis, offset_axis])

        data = np.ones(shape=axes.shape)
        edisp = EnergyDispersion2D(axes=axes, data=data)

        hdu = edisp.to_table_hdu()
        energy = edisp.axes["energy_true"].edges
        assert_equal(hdu.data["ENERG_LO"][0], energy[:-1].value)
        assert hdu.header["TUNIT1"] == edisp.axes["energy_true"].unit
Exemplo n.º 17
0
    def from_table(cls, table):
        """Create from `~astropy.table.Table`.

        Parameters
        ----------
        table : `~astropy.table.Table`
            Table with effective area.

        Returns
        -------
        aeff : `EffectiveArea2D`
            Effective area
        """

        if "ENERG_LO" in table.colnames:
            column_prefixes = ["ENERG", "THETA", "MIGRA"]
        elif "ETRUE_LO" in table.colnames:
            column_prefixes = ["ETRUE", "THETA", "MIGRA"]
        else:
            raise ValueError(
                'Invalid column names. Need "ENERG_LO/ENERG_HI" or "ETRUE_LO/ETRUE_HI"'
            )

        axes = MapAxes.from_table(table,
                                  column_prefixes=column_prefixes,
                                  format="gadf-dl3")

        data = table["MATRIX"].quantity[0].transpose()

        return cls(
            energy_axis_true=axes["energy_true"],
            offset_axis=axes["offset"],
            migra_axis=axes["migra"],
            data=data,
        )
Exemplo n.º 18
0
    def from_table(cls, table, format="gadf-dl3"):
        """Read from `~astropy.table.Table`.

        Parameters
        ----------
        table : `~astropy.table.Table`
            Table with irf data
        format : {"gadf-dl3"}
            Format specification

        Returns
        -------
        irf : `IRF`
            IRF class.
        """
        axes = MapAxes.from_table(table=table,
                                  format=format)[cls.required_axes]
        column_name = IRF_DL3_HDU_SPECIFICATION[cls.tag]["column_name"]
        data = table[column_name].quantity[0].transpose()

        return cls(
            axes=axes,
            data=data.value,
            meta=table.meta,
            unit=data.unit,
            is_pointlike=gadf_is_pointlike(table.meta),
            fov_alignment=table.meta.get("FOVALIGN", "RADEC"),
        )
Exemplo n.º 19
0
    def test_write(self):
        energy_axis_true = MapAxis.from_energy_bounds(
            "1 TeV", "10 TeV", nbin=10, name="energy_true"
        )

        offset_axis = MapAxis.from_bounds(
            0, 1, nbin=3, unit="deg", name="offset", node_type="edges"
        )

        migra_axis = MapAxis.from_bounds(0, 3, nbin=3, name="migra", node_type="edges")

        axes = MapAxes([energy_axis_true, migra_axis, offset_axis])

        data = np.ones(shape=axes.shape)
        
        edisp_test = EnergyDispersion2D(axes=axes)
        with pytest.raises(ValueError) as error:
            wrong_unit = u.m**2
            EnergyDispersion2D(axes=axes, data=data * wrong_unit)
            assert error.match(f"Error: {wrong_unit} is not an allowed unit. {edisp_test.tag} requires {edisp_test.default_unit} data quantities.")

        edisp = EnergyDispersion2D(axes=axes, data=data)

        hdu = edisp.to_table_hdu()
        energy = edisp.axes["energy_true"].edges
        assert_equal(hdu.data["ENERG_LO"][0], energy[:-1].value)
        assert hdu.header["TUNIT1"] == edisp.axes["energy_true"].unit
Exemplo n.º 20
0
    def from_table(cls, table):
        """Create from `~astropy.table.Table` in ARF format.

        Data format specification: :ref:`gadf:ogip-arf`
        """
        axes = MapAxes.from_table(table, format="ogip-arf")[cls.required_axes]
        data = table["SPECRESP"].quantity
        return cls(axes=axes, data=data.value, unit=data.unit)
Exemplo n.º 21
0
    def from_table(cls, table, format="gadf-dl3"):
        """Read from `~astropy.table.Table`.

        Parameters
        ----------
        table : `~astropy.table.Table`
            Table with background data
        format : {"gadf-dl3"}
            Format specification

        Returns
        -------
        bkg : `Background2D` or `Background2D`
            Background IRF class.
        """
        # TODO: some of the existing background files have missing HDUCLAS keywords
        #  which are required to define the correct Gammapy axis names

        if "HDUCLAS2" not in table.meta:
            log.warning("Missing 'HDUCLAS2' keyword assuming 'BKG'")
            table = table.copy()
            table.meta["HDUCLAS2"] = "BKG"

        axes = MapAxes.from_table(table, format=format)[cls.required_axes]

        # TODO: spec says key should be "BKG", but there are files around
        #  (e.g. CTA 1DC) that use "BGD". For now we support both
        if "BKG" in table.colnames:
            bkg_name = "BKG"
        elif "BGD" in table.colnames:
            bkg_name = "BGD"
        else:
            raise ValueError("Invalid column names. Need 'BKG' or 'BGD'.")

        data = table[bkg_name].quantity[0].T

        if data.unit == "" or isinstance(data.unit, u.UnrecognizedUnit):
            data = u.Quantity(data.value, "s-1 MeV-1 sr-1", copy=False)
            log.warning(
                "Invalid unit found in background table! Assuming (s-1 MeV-1 sr-1)"
            )

        # TODO: The present HESS and CTA background fits files
        #  have a reverse order (lon, lat, E) than recommended in GADF(E, lat, lon)
        #  For now, we support both.

        if axes.shape == axes.shape[::-1]:
            log.error("Ambiguous axes order in Background fits files!")

        if np.shape(data) != axes.shape:
            log.debug("Transposing background table on read")
            data = data.transpose()

        return cls(
            axes=axes, data=data.value, meta=table.meta, unit=data.unit,
            is_pointlike=gadf_is_pointlike(table.meta),
            fov_alignment=table.meta.get("FOVALIGN", "RADEC"),
        )
Exemplo n.º 22
0
    def get_edisp_kernel(self, position=None, energy_axis=None):
        """Get energy dispersion at a given position.

        Parameters
        ----------
        position : `~astropy.coordinates.SkyCoord`
            the target position. Should be a single coordinates
        energy_axis : `MapAxis`
            Reconstructed energy axis

        Returns
        -------
        edisp : `~gammapy.irf.EnergyDispersion`
            the energy dispersion (i.e. rmf object)
        """
        if position is None:
            position = self.edisp_map.geom.center_skydir

        if position.size != 1:
            raise ValueError(
                "EnergyDispersion can be extracted at one single position only."
            )

        position = self._get_nearest_valid_position(position)
        energy_axis_true = self.edisp_map.geom.axes["energy_true"]

        axes = MapAxes([energy_axis_true, energy_axis])

        coords = axes.get_coord(mode="edges", axis_name="energy")

        # migration value of energy bounds
        migra = coords["energy"] / coords["energy_true"]

        coords = {
            "skycoord": position,
            "energy_true": coords["energy_true"],
            "migra": migra,
        }

        values = self.edisp_map.integral(axis_name="migra", coords=coords)
        data = np.diff(np.clip(values, 0, np.inf))

        return EDispKernel(axes=axes, data=data.to_value(""))
Exemplo n.º 23
0
    def to_3d(self):
        """ "Convert to Background3D"""

        edges = np.concatenate((
            np.negative(self.axes["offset"].edges)[::-1][:-1],
            self.axes["offset"].edges,
        ))
        fov_lat = MapAxis.from_edges(edges=edges, name="fov_lat")
        fov_lon = MapAxis.from_edges(edges=edges, name="fov_lon")

        axes = MapAxes([self.axes["energy"], fov_lon, fov_lat])
        coords = axes.get_coord()
        offset = np.sqrt(coords["fov_lat"]**2 + coords["fov_lon"]**2)
        data = self.evaluate(offset=offset, energy=coords["energy"])

        return Background3D(
            axes=axes,
            data=data,
        )
Exemplo n.º 24
0
    def to_hdulist(self):
        """Convert PSF table data to FITS HDU list.

        Returns
        -------
        hdu_list : `~astropy.io.fits.HDUList`
            PSF in HDU list format.
        """
        axes = MapAxes(
            [self.offset_axis, self.energy_axis_true, self.rad_axis])
        table = axes.to_table(format="gadf-dl3")

        table["RPSF"] = self.psf_value.T[np.newaxis]

        hdu = fits.BinTableHDU(table)
        hdu.header["LO_THRES"] = self.energy_thresh_lo.value
        hdu.header["HI_THRES"] = self.energy_thresh_hi.value

        return fits.HDUList([fits.PrimaryHDU(), hdu])
Exemplo n.º 25
0
    def to_hdulist(self):
        """
        Convert psf table data to FITS hdu list.

        Returns
        -------
        hdu_list : `~astropy.io.fits.HDUList`
            PSF in HDU list format.
        """
        # Set up data
        names = [
            "SCALE",
            "SIGMA_1",
            "AMPL_2",
            "SIGMA_2",
            "AMPL_3",
            "SIGMA_3",
        ]
        units = ["", "deg", "", "deg", "", "deg"]

        data = [
            self.norms[0],
            self.sigmas[0],
            self.norms[1],
            self.sigmas[1],
            self.norms[2],
            self.sigmas[2],
        ]

        axes = MapAxes([self.energy_axis_true, self.offset_axis])
        table = axes.to_table(format="gadf-dl3")

        for name_, data_, unit_ in zip(names, data, units):
            table[name_] = [data_]
            table[name_].unit = unit_

        # Create hdu and hdu list
        hdu = fits.BinTableHDU(table)
        hdu.header["LO_THRES"] = self.energy_thresh_lo.value
        hdu.header["HI_THRES"] = self.energy_thresh_hi.value

        return fits.HDUList([fits.PrimaryHDU(), hdu])
Exemplo n.º 26
0
    def __init__(
        self,
        energy_axis_true,
        offset_axis,
        rad_axis,
        data,
        meta=None,
        interp_kwargs=None,
    ):

        interp_kwargs = interp_kwargs or {}

        axes = MapAxes([energy_axis_true, offset_axis, rad_axis])
        axes.assert_names(["energy_true", "offset", "rad"])

        self.data = NDDataArray(axes=axes,
                                data=u.Quantity(data).to("sr^-1"),
                                interp_kwargs=interp_kwargs)

        self.meta = meta or {}
Exemplo n.º 27
0
    def from_gauss(cls, energy_axis_true, rad_axis=None, sigma=0.1 * u.deg):
        """Create all -sky PSF map from Gaussian width.

        This is used for testing and examples.

        The width can be the same for all energies
        or be an array with one value per energy node.
        It does not depend on position.

        Parameters
        ----------
        energy_axis_true : `~gammapy.maps.MapAxis`
            True energy axis.
        rad_axis : `~gammapy.maps.MapAxis`
            Offset angle wrt source position axis.
        sigma : `~astropy.coordinates.Angle`
            Gaussian width.

        Returns
        -------
        psf_map : `PSFMap`
            Point spread function map.
        """
        from gammapy.datasets.map import RAD_AXIS_DEFAULT

        if rad_axis is None:
            rad_axis = RAD_AXIS_DEFAULT.copy()

        axes = MapAxes([energy_axis_true, rad_axis])
        coords = axes.get_coord()

        sigma = np.broadcast_to(u.Quantity(sigma),
                                energy_axis_true.nbin,
                                subok=True)
        gauss = Gauss2DPDF(sigma=sigma.reshape((-1, 1)))
        data = gauss(coords["rad"])

        table_psf = EnergyDependentTablePSF(axes=axes,
                                            unit=data.unit,
                                            data=data.value)
        return cls.from_energy_dependent_table_psf(table_psf)
Exemplo n.º 28
0
    def from_table(cls, table):
        """Read from `~astropy.table.Table`."""
        axes = MapAxes.from_table(table=table,
                                  column_prefixes=["ENERG", "THETA"],
                                  format="gadf-dl3")

        return cls(
            energy_axis_true=axes["energy_true"],
            offset_axis=axes["offset"],
            data=table["EFFAREA"].quantity[0].transpose(),
            meta=table.meta,
        )
Exemplo n.º 29
0
    def __init__(
        self,
        energy_axis_true,
        rad_axis,
        exposure=None,
        data=None,
        interp_kwargs=None,
    ):
        interp_kwargs = interp_kwargs or {}
        axes = MapAxes([energy_axis_true, rad_axis])
        axes.assert_names(["energy_true", "rad"])

        self.data = NDDataArray(axes=axes,
                                data=u.Quantity(data).to("sr^-1"),
                                interp_kwargs=interp_kwargs)

        if exposure is None:
            self.exposure = u.Quantity(np.ones(self.energy_axis_true.nbin),
                                       "cm^2 s")
        else:
            self.exposure = u.Quantity(exposure).to("cm^2 s")
Exemplo n.º 30
0
    def from_table(cls, table, format="gadf-dl3"):
        """Read from `~astropy.table.Table`.

        Parameters
        ----------
        table : `~astropy.table.Table`
            Table with background data
        format : {"gadf-dl3"}
            Format specification

        Returns
        -------
        bkg : `Background2D` or `Background2D`
            Background IRF class.
        """
        axes = MapAxes.from_table(table, format=format)[cls.required_axes]
        
        # Spec says key should be "BKG", but there are files around
        # (e.g. CTA 1DC) that use "BGD". For now we support both
        if "BKG" in table.colnames:
            bkg_name = "BKG"
        elif "BGD" in table.colnames:
            bkg_name = "BGD"
        else:
            raise ValueError('Invalid column names. Need "BKG" or "BGD".')

        data = table[bkg_name].quantity[0].T

        if data.unit == "" or isinstance(data.unit, u.UnrecognizedUnit):
            data = u.Quantity(data.value, "s-1 MeV-1 sr-1", copy=False)
            log.warning(
                "Invalid unit found in background table! Assuming (s-1 MeV-1 sr-1)"
            )

        # TODO: The present HESS and CTA backgroundfits files
        #  have a reverse order (lon, lat, E) than recommened in GADF(E, lat, lon)
        #  For now, we suport both.

        if axes.shape == axes.shape[::-1]:
            log.error("Ambiguous axes order in Background fits files!")

        if np.shape(data) != axes.shape:
            log.debug("Transposing background table on read")
            data = data.transpose()

        return cls(
            axes=axes,
            data=data.value,
            meta=table.meta,
            unit=data.unit
        )