def make_aeff(self, observation): """Make effective area Parameters ---------- observation: `DataStoreObservation` Observation to compute effective area for. Returns ------- aeff : `EffectiveAreaTable` Effective area table. """ offset = observation.pointing_radec.separation(self.region.center) aeff = observation.aeff.to_effective_area_table(offset, energy=self.e_true) if self.containment_correction: if not isinstance(self.region, CircleSkyRegion): raise TypeError( "Containment correction only supported for circular regions." ) table_psf = observation.psf.to_energy_dependent_table_psf( theta=offset) aeff = apply_containment_fraction(aeff, table_psf, self.region.radius) return aeff
def apply_containment_correction(self, observation, bkg): """Apply PSF containment correction. Parameters ---------- observation : `~gammapy.data.DataStoreObservation` observation bkg : `~gammapy.background.BackgroundEstimate` background esimate """ if not isinstance(bkg.on_region, CircleSkyRegion): raise TypeError("Incorrect region type for containment correction." " Should be CircleSkyRegion.") log.info("Apply containment correction") # First need psf angles = np.linspace(0.0, 1.5, 150) * u.deg offset = observation.pointing_radec.separation(bkg.on_region.center) if isinstance(observation.psf, PSF3D): psf = observation.psf.to_energy_dependent_table_psf(theta=offset) else: psf = observation.psf.to_energy_dependent_table_psf(offset, angles) new_aeff = apply_containment_fraction(self._aeff, psf, bkg.on_region.radius) # TODO: check whether keeping containment is necessary self.containment = new_aeff.data.data.value / self._aeff.data.data.value self._aeff = new_aeff
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"
def to_spectrum_dataset(self, on_region, containment_correction=False): """Return a ~gammapy.spectrum.SpectrumDataset from on_region. Counts and background are summed in the on_region. Effective area is taken from the average exposure divided by the livetime. Here we assume it is the sum of the GTIs. EnergyDispersion is obtained at the on_region center. Only regions with centers are supported. Parameters ---------- on_region : `~regions.SkyRegion` the input ON region on which to extract the spectrum containment_correction : bool Apply containment correction for point sources and circular on regions Returns ------- dataset : `~gammapy.spectrum.SpectrumDataset` the resulting reduced dataset """ if self.gti is not None: livetime = self.gti.time_sum else: raise ValueError("No GTI in `MapDataset`, cannot compute livetime") if self.counts is not None: counts = self.counts.get_spectrum(on_region, np.sum) else: counts = None if self.background_model is not None: background = self.background_model.evaluate().get_spectrum( on_region, np.sum ) else: background = None if self.exposure is not None: exposure = self.exposure.get_spectrum(on_region, np.mean) aeff = EffectiveAreaTable( energy_lo=exposure.energy.edges[:-1], energy_hi=exposure.energy.edges[1:], data=exposure.data / livetime, ) else: aeff = None if containment_correction: if not isinstance(on_region, CircleSkyRegion): raise TypeError( "Containement correction is only supported for" " `CircleSkyRegion`." ) elif self.psf is None or isinstance(self.psf, PSFKernel): raise ValueError("No PSFMap set. Containement correction impossible") else: psf_table = self.psf.get_energy_dependent_table_psf(on_region.center) aeff = apply_containment_fraction(aeff, psf_table, on_region.radius) if self.edisp is not None: if isinstance(self.edisp, EnergyDispersion): edisp = self.edisp else: self.edisp.get_energy_dispersion(on_region.center, self._energy_axis) else: edisp = None return SpectrumDataset( counts=counts, background=background, aeff=aeff, edisp=edisp, livetime=livetime, gti=self.gti, name=self.name, )