def make_prof(self, sp_datasets): """ Utility to make the profile in each region Parameters ---------- sp_datasets : `~gammapy.datasets.MapDatasets` of `~gammapy.datasets.SpectrumDataset` or \ `~gammapy.datasets.SpectrumDatasetOnOff` the dataset to use for profile extraction Returns -------- results : list of dictionary the list of results (list of keys: x_min, x_ref, x_max, alpha, counts, background, excess, ts, sqrt_ts, \ err, errn, errp, ul, exposure, solid_angle) """ results = [] distance = self._get_projected_distance() for index, spds in enumerate(sp_datasets): old_model = None if spds.models is not None: old_model = spds.models spds.models = SkyModel(spectral_model=self.spectrum) e_reco = spds.counts.geom.axes["energy"].edges # ToDo: When the function to_spectrum_dataset will manage the masks, use the following line # mask = spds.mask if spds.mask is not None else slice(None) mask = slice(None) if isinstance(spds, SpectrumDatasetOnOff): stats = WStatCountsStatistic( spds.counts.data[mask][:, 0, 0], spds.counts_off.data[mask][:, 0, 0], spds.alpha.data[mask][:, 0, 0], ) else: stats = CashCountsStatistic( spds.counts.data[mask][:, 0, 0], spds.npred_background().data[mask][:, 0, 0], ) result = { "x_min": distance.edges[index], "x_max": distance.edges[index + 1], "x_ref": distance.center[index], "energy_edge": e_reco, } if isinstance(spds, SpectrumDatasetOnOff): result["alpha"] = stats.alpha result.update( { "counts": stats.n_on, "background": stats.mu_bkg, "excess": stats.n_sig, } ) result["ts"] = stats.ts result["sqrt_ts"] = stats.sqrt_ts result["err"] = stats.error * self.n_sigma if "errn-errp" in self.selection_optional: result["errn"] = stats.compute_errn(self.n_sigma) result["errp"] = stats.compute_errp(self.n_sigma) if "ul" in self.selection_optional: result["ul"] = stats.compute_upper_limit(self.n_sigma_ul) npred = spds.npred().data[mask][:, 0, 0] e_reco_lo = e_reco[:-1] e_reco_hi = e_reco[1:] flux = ( stats.n_sig / npred * spds.models[0].spectral_model.integral(e_reco_lo, e_reco_hi).value ) result["flux"] = flux result["flux_err"] = stats.error / stats.n_sig * flux if "errn-errp" in self.selection_optional: result["flux_errn"] = np.abs(result["errn"]) / stats.n_sig * flux result["flux_errp"] = result["errp"] / stats.n_sig * flux if "ul" in self.selection_optional: result["flux_ul"] = result["ul"] / stats.n_sig * flux solid_angle = spds.counts.geom.solid_angle() result["solid_angle"] = ( np.full(result["counts"].shape, solid_angle.to_value("sr")) * u.sr ) results.append(result) if old_model is not None: spds.models = old_model return results
def test_wstat_ul(n_on, n_off, alpha, result): stat = WStatCountsStatistic(n_on, n_off, alpha) ul = stat.compute_upper_limit() assert_allclose(ul, result[0], atol=1e-5)