Source code for gammapy.makers.background.onoffpair

# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""On-Off background estimation for dedicated On Off Pair runs"""

import numpy as np
import logging

from astropy.coordinates import SkyCoord
from astropy.table import QTable

from gammapy.data import EventList
from gammapy.datasets import (
    MapDataset,
    MapDatasetOnOff,
    SpectrumDataset,
    SpectrumDatasetOnOff,
)
from ..core import Maker
from gammapy.maps import Map
from gammapy.utils.coordinates import fov_to_sky, sky_to_fov

log = logging.getLogger(__name__)

__all__ = ["OnOffBackgroundMaker"]


[docs] class OnOffBackgroundMaker(Maker): """Estimate OFF background from a paired OFF observation. Turns a reduced `~gammapy.datasets.MapDataset` or `~gammapy.datasets.SpectrumDataset` into its OnOff counterpart by mirroring the OFF run's events into the ON pointing FoV frame and setting acceptances from livetime. ON-OFF pairs should be created beforehand by the user. .. note:: Currently, this supports only one OFF observation for each ON observation. It also only works for pointing observations, and drift mode is not supported. Parameters ---------- acceptance_method : str, optional Allowed options are {"livetime_ratio", "counts_ratio"} Strategy for the acceptance calculation. Available options are: * "livetime_ratio": takes the ratio of livetimes. * "counts_ratio": takes the ratio of the counts outside an exclusion mask, passed through kwargs. Default is "livetime_ratio". kwargs : dict, optional Additional arguments passed to the maker. Should contain `exclusion_mask` if acceptance_method is `counts_ratio`, otherwise assume no mask. Returns ------- dataset : `~gammapy.datasets.MapDatasetOnOff` or `~gammapy.datasets.SpectrumDatasetOnOff` Either a spectrum dataset or a map on off dataset. """ tag = "OnOffBackgroundMaker" available_acceptance_methods = ["livetime_ratio", "counts_ratio"]
[docs] def __init__(self, acceptance_method="livetime_ratio", **kwargs): if acceptance_method not in self.available_acceptance_methods: raise ValueError( f"Unknown acceptance_method {acceptance_method!r}, " f"choose from {self.available_acceptance_methods}" ) self.acceptance_method = acceptance_method self.mask = kwargs.get("exclusion_mask", None)
def _mirror_off_events(self, on_observation, off_observation): """Reproject OFF events into the ON pointing FoV frame (aligned with RA/DEC).""" events = off_observation.events off_pointing = off_observation.get_pointing_icrs(off_observation.tmid) on_pointing = on_observation.get_pointing_icrs(on_observation.tmid) fov_lon, fov_lat = sky_to_fov( events.radec.ra, events.radec.dec, off_pointing.ra, off_pointing.dec ) off_ra, off_dec = fov_to_sky(fov_lon, fov_lat, on_pointing.ra, on_pointing.dec) table = events.table.copy() off_coord = SkyCoord(off_ra, off_dec, frame="icrs") table["RA"] = off_coord.ra table["DEC"] = off_coord.dec return EventList(table) def _make_acceptance(self, dataset, on_observation, off_observation, counts_off): geom = dataset.counts.geom if self.acceptance_method == "livetime_ratio": val_on = on_observation.observation_live_time_duration.to_value("s") val_off = off_observation.observation_live_time_duration.to_value("s") elif self.acceptance_method == "counts_ratio": if self.mask is None: mask = Map.from_geom(geom=geom, data=1, dtype=bool) val_on = (dataset.counts * mask).data.sum() val_off = (counts_off * mask).data.sum() acceptance = Map.from_geom(geom, unit="", data=val_on) acceptance_off = Map.from_geom(geom, unit="", data=val_off) return acceptance, acceptance_off
[docs] def run(self, dataset, on_observation, off_observation): """Create background using dedicated off pointing. Parameters ---------- dataset : `~gammapy.datasets.MapDataset` or `~gammapy.datasets.SpectrumDataset` Reduced dataset for the ON observation. on_observation : `~gammapy.data.Observation` The ON observation. off_observation : `~gammapy.data.Observation` The paired OFF observation. Returns ------- dataset : `~gammapy.datasets.MapDatasetOnOff` or `~gammapy.datasets.SpectrumDatasetOnOff` Either a spectrum dataset or a map on off dataset. """ if ( on_observation.pointing.mode == "DRIFT" or off_observation.pointing.mode == "DRIFT" ): log.warning( f"{on_observation.obs_id}/{off_observation.obs_id} pair is in DRIFT mode. IGNORING." ) return if not isinstance(dataset, MapDataset): raise TypeError( f"Expected MapDataset or SpectrumDataset, got {type(dataset).__name__}" ) geom = dataset.counts.geom counts_off = Map.from_geom(geom, unit="") counts_off.fill_events(self._mirror_off_events(on_observation, off_observation)) acceptance, acceptance_off = self._make_acceptance( dataset, on_observation, off_observation, counts_off ) if isinstance(dataset, SpectrumDataset): return SpectrumDatasetOnOff.from_spectrum_dataset( dataset=dataset, acceptance=acceptance, acceptance_off=acceptance_off, counts_off=counts_off, name=dataset.name, ) elif isinstance(dataset, MapDataset): return MapDatasetOnOff.from_map_dataset( dataset=dataset, acceptance=acceptance, acceptance_off=acceptance_off, counts_off=counts_off, name=dataset.name, ) return