class TestSpectrumDataset: """Test fit on counts spectra without any IRFs""" def setup(self): self.nbins = 30 binning = np.logspace(-1, 1, self.nbins + 1) * u.TeV self.source_model = SkyModel(spectral_model=PowerLawSpectralModel( index=2.1, amplitude=1e5 * u.Unit("cm-2 s-1 TeV-1"), reference=0.1 * u.TeV, )) self.livetime = 100 * u.s aeff = EffectiveAreaTable.from_constant(binning, "1 cm2") bkg_rate = np.ones(self.nbins) / u.s bkg_expected = (bkg_rate * self.livetime).to_value("") self.bkg = CountsSpectrum(energy_lo=binning[:-1], energy_hi=binning[1:], data=bkg_expected) random_state = get_random_state(23) flux = self.source_model.spectral_model.integral( binning[:-1], binning[1:]) self.npred = (flux * aeff.data.data[0] * self.livetime).to_value("") self.npred += bkg_expected source_counts = random_state.poisson(self.npred) self.src = CountsSpectrum(energy_lo=binning[:-1], energy_hi=binning[1:], data=source_counts) self.dataset = SpectrumDataset( models=self.source_model, counts=self.src, aeff=aeff, livetime=self.livetime, background=self.bkg, name="test", ) def test_data_shape(self): assert self.dataset.data_shape[0] == self.nbins def test_energy_range(self): energy_range = self.dataset.energy_range assert energy_range.unit == u.TeV assert_allclose(energy_range.to_value("TeV"), [0.1, 10.0]) def test_cash(self): """Simple CASH fit to the on vector""" fit = Fit([self.dataset]) result = fit.run() # assert result.success assert "minuit" in repr(result) npred = self.dataset.npred().data.sum() assert_allclose(npred, self.npred.sum(), rtol=1e-3) assert_allclose(result.total_stat, -18087404.624, rtol=1e-3) pars = result.parameters assert_allclose(pars["index"].value, 2.1, rtol=1e-2) assert_allclose(pars.error("index"), 0.00127, rtol=1e-2) assert_allclose(pars["amplitude"].value, 1e5, rtol=1e-3) assert_allclose(pars.error("amplitude"), 153.450, rtol=1e-2) def test_fake(self): """Test the fake dataset""" real_dataset = self.dataset.copy() self.dataset.fake(314) assert real_dataset.counts.data.shape == self.dataset.counts.data.shape assert real_dataset.background.data.sum( ) == self.dataset.background.data.sum() assert int(real_dataset.counts.data.sum()) == 907010 assert self.dataset.counts.data.sum() == 907331 def test_incorrect_mask(self): mask_fit = np.ones(self.nbins, dtype=np.dtype("float")) with pytest.raises(ValueError): SpectrumDataset( models=self.source_model, counts=self.src, livetime=self.livetime, mask_fit=mask_fit, background=self.bkg, ) def test_set_model(self): aeff = EffectiveAreaTable.from_parametrization(self.src.energy.edges, "HESS") edisp = EDispKernel.from_diagonal_response(self.src.energy.edges, self.src.energy.edges) dataset = SpectrumDataset(None, self.src, self.livetime, None, aeff, edisp, self.bkg) spectral_model = PowerLawSpectralModel() model = SkyModel(spectral_model=spectral_model, name="test") dataset.models = model assert dataset.models["test"] is model models = Models([model]) dataset.models = models assert dataset.models["test"] is model def test_npred_models(self): e_reco = MapAxis.from_energy_bounds("1 TeV", "10 TeV", nbin=3).edges dataset = SpectrumDataset.create(e_reco=e_reco) dataset.livetime = 1 * u.h dataset.aeff.data.data += 1e10 * u.Unit("cm2") pwl_1 = PowerLawSpectralModel(index=2) pwl_2 = PowerLawSpectralModel(index=2) model_1 = SkyModel(spectral_model=pwl_1) model_2 = SkyModel(spectral_model=pwl_2) dataset.models = Models([model_1, model_2]) npred = dataset.npred() assert_allclose(npred.data.sum(), 64.8) def test_str(self): assert "SpectrumDataset" in str(self.dataset) def test_spectrumdataset_create(self): e_reco = u.Quantity([0.1, 1, 10.0], "TeV") e_true = u.Quantity([0.05, 0.5, 5, 20.0], "TeV") empty_dataset = SpectrumDataset.create(e_reco, e_true, name="test") assert empty_dataset.name == "test" assert empty_dataset.counts.total_counts == 0 assert empty_dataset.data_shape[0] == 2 assert empty_dataset.background.total_counts == 0 assert empty_dataset.background.energy.nbin == 2 assert empty_dataset.aeff.data.axis("energy").nbin == 3 assert empty_dataset.edisp.data.axis("e_reco").nbin == 2 assert empty_dataset.livetime.value == 0 assert len(empty_dataset.gti.table) == 0 assert empty_dataset.energy_range[0] is None assert_allclose(empty_dataset.mask_safe, 0) def test_spectrum_dataset_stack_diagonal_safe_mask(self): aeff = EffectiveAreaTable.from_parametrization(self.src.energy.edges, "HESS") edisp = EDispKernel.from_diagonal_response(self.src.energy.edges, self.src.energy.edges) livetime = self.livetime dataset1 = SpectrumDataset( counts=self.src.copy(), livetime=livetime, aeff=aeff, edisp=edisp, background=self.bkg.copy(), ) livetime2 = 0.5 * livetime aeff2 = EffectiveAreaTable(self.src.energy.edges[:-1], self.src.energy.edges[1:], 2 * aeff.data.data) bkg2 = CountsSpectrum( self.src.energy.edges[:-1], self.src.energy.edges[1:], data=2 * self.bkg.data, ) safe_mask2 = np.ones_like(self.src.data, bool) safe_mask2[0] = False dataset2 = SpectrumDataset( counts=self.src.copy(), livetime=livetime2, aeff=aeff2, edisp=edisp, background=bkg2, mask_safe=safe_mask2, ) dataset1.stack(dataset2) assert_allclose(dataset1.counts.data[1:], self.src.data[1:] * 2) assert_allclose(dataset1.counts.data[0], self.src.data[0]) assert dataset1.livetime == 1.5 * self.livetime assert_allclose(dataset1.background.data[1:], 3 * self.bkg.data[1:]) assert_allclose(dataset1.background.data[0], self.bkg.data[0]) assert_allclose( dataset1.aeff.data.data.to_value("m2"), 4.0 / 3 * aeff.data.data.to_value("m2"), ) assert_allclose(dataset1.edisp.pdf_matrix[1:], edisp.pdf_matrix[1:]) assert_allclose(dataset1.edisp.pdf_matrix[0], 0.5 * edisp.pdf_matrix[0]) def test_spectrum_dataset_stack_nondiagonal_no_bkg(self): aeff = EffectiveAreaTable.from_parametrization(self.src.energy.edges, "HESS") edisp1 = EDispKernel.from_gauss(self.src.energy.edges, self.src.energy.edges, 0.1, 0.0) livetime = self.livetime dataset1 = SpectrumDataset(counts=None, livetime=livetime, aeff=aeff, edisp=edisp1, background=None) livetime2 = livetime aeff2 = EffectiveAreaTable(self.src.energy.edges[:-1], self.src.energy.edges[1:], aeff.data.data) edisp2 = EDispKernel.from_gauss(self.src.energy.edges, self.src.energy.edges, 0.2, 0.0) dataset2 = SpectrumDataset( counts=self.src.copy(), livetime=livetime2, aeff=aeff2, edisp=edisp2, background=None, ) dataset1.stack(dataset2) assert dataset1.counts is None assert dataset1.background is None assert dataset1.livetime == 2 * self.livetime assert_allclose(dataset1.aeff.data.data.to_value("m2"), aeff.data.data.to_value("m2")) assert_allclose(dataset1.edisp.get_bias(1 * u.TeV), 0.0, atol=1.2e-3) assert_allclose(dataset1.edisp.get_resolution(1 * u.TeV), 0.1581, atol=1e-2) def test_info_dict(self): info_dict = self.dataset.info_dict() assert_allclose(info_dict["n_on"], 907010) assert_allclose(info_dict["background"], 3000.0) assert_allclose(info_dict["significance"], 2924.522174) assert_allclose(info_dict["excess"], 904010) assert_allclose(info_dict["livetime"].value, 1e2) assert info_dict["name"] == "test" @requires_dependency("matplotlib") def test_peek(self): with mpl_plot_check(): self.dataset.peek() self.dataset.edisp = None with mpl_plot_check(): self.dataset.peek() @requires_dependency("matplotlib") def test_plot_fit(self): with mpl_plot_check(): self.dataset.plot_fit()
class TestSpectrumDataset: """Test fit on counts spectra without any IRFs""" def setup(self): self.nbins = 30 binning = np.logspace(-1, 1, self.nbins + 1) * u.TeV self.source_model = PowerLawSpectralModel(index=2.1, amplitude=1e5 / u.TeV / u.s, reference=0.1 * u.TeV) self.livetime = 100 * u.s bkg_rate = np.ones(self.nbins) / u.s bkg_expected = bkg_rate * self.livetime self.bkg = CountsSpectrum(energy_lo=binning[:-1], energy_hi=binning[1:], data=bkg_expected) random_state = get_random_state(23) self.npred = (self.source_model.integral(binning[:-1], binning[1:]) * self.livetime) self.npred += bkg_expected source_counts = random_state.poisson(self.npred) self.src = CountsSpectrum(energy_lo=binning[:-1], energy_hi=binning[1:], data=source_counts) self.dataset = SpectrumDataset( model=self.source_model, counts=self.src, livetime=self.livetime, background=self.bkg, ) def test_data_shape(self): assert self.dataset.data_shape[0] == self.nbins def test_energy_range(self): energy_range = self.dataset.energy_range assert energy_range.unit == u.TeV assert_allclose(energy_range.to_value("TeV"), [0.1, 10.0]) def test_cash(self): """Simple CASH fit to the on vector""" fit = Fit(self.dataset) result = fit.run() assert result.success assert "minuit" in repr(result) npred = self.dataset.npred().data.sum() assert_allclose(npred, self.npred.sum(), rtol=1e-3) assert_allclose(result.total_stat, -18087404.624, rtol=1e-3) pars = result.parameters assert_allclose(pars["index"].value, 2.1, rtol=1e-2) assert_allclose(pars.error("index"), 0.00127, rtol=1e-2) assert_allclose(pars["amplitude"].value, 1e5, rtol=1e-3) assert_allclose(pars.error("amplitude"), 153.450, rtol=1e-2) def test_fake(self): """Test the fake dataset""" real_dataset = self.dataset.copy() self.dataset.fake(314) assert real_dataset.counts.data.shape == self.dataset.counts.data.shape assert real_dataset.background.data.sum( ) == self.dataset.background.data.sum() assert int(real_dataset.counts.data.sum()) == 907010 assert self.dataset.counts.data.sum() == 907331 def test_incorrect_mask(self): mask_fit = np.ones(self.nbins, dtype=np.dtype("float")) with pytest.raises(ValueError): SpectrumDataset( model=self.source_model, counts=self.src, livetime=self.livetime, mask_fit=mask_fit, background=self.bkg, ) def test_set_model(self): aeff = EffectiveAreaTable.from_parametrization(self.src.energy.edges, "HESS") edisp = EnergyDispersion.from_diagonal_response( self.src.energy.edges, self.src.energy.edges) dataset = SpectrumDataset(None, self.src, self.livetime, None, aeff, edisp, self.bkg) with pytest.raises(AttributeError): dataset.parameters dataset.model = self.source_model assert dataset.parameters[0] == self.source_model.parameters[0] def test_str(self): assert "SpectrumDataset" in str(self.dataset) def test_spectrumdataset_create(self): e_reco = u.Quantity([0.1, 1, 10.0], "TeV") e_true = u.Quantity([0.05, 0.5, 5, 20.0], "TeV") empty_dataset = SpectrumDataset.create(e_reco, e_true) assert empty_dataset.counts.total_counts == 0 assert empty_dataset.data_shape[0] == 2 assert empty_dataset.background.total_counts == 0 assert empty_dataset.background.energy.nbin == 2 assert empty_dataset.aeff.data.axis("energy").nbin == 3 assert empty_dataset.edisp.data.axis("e_reco").nbin == 2 assert empty_dataset.livetime.value == 0 assert len(empty_dataset.gti.table) == 0 assert empty_dataset.energy_range[0] is None assert_allclose(empty_dataset.mask_safe, 0) def test_spectrum_dataset_stack_diagonal_safe_mask(self): aeff = EffectiveAreaTable.from_parametrization(self.src.energy.edges, "HESS") edisp = EnergyDispersion.from_diagonal_response( self.src.energy.edges, self.src.energy.edges) livetime = self.livetime dataset1 = SpectrumDataset( counts=self.src.copy(), livetime=livetime, aeff=aeff, edisp=edisp, background=self.bkg.copy(), ) livetime2 = 0.5 * livetime aeff2 = EffectiveAreaTable(self.src.energy.edges[:-1], self.src.energy.edges[1:], 2 * aeff.data.data) bkg2 = CountsSpectrum( self.src.energy.edges[:-1], self.src.energy.edges[1:], data=2 * self.bkg.data, ) safe_mask2 = np.ones_like(self.src.data, bool) safe_mask2[0] = False dataset2 = SpectrumDataset( counts=self.src.copy(), livetime=livetime2, aeff=aeff2, edisp=edisp, background=bkg2, mask_safe=safe_mask2, ) dataset1.stack(dataset2) assert_allclose(dataset1.counts.data[1:], self.src.data[1:] * 2) assert_allclose(dataset1.counts.data[0], self.src.data[0]) assert dataset1.livetime == 1.5 * self.livetime assert_allclose(dataset1.background.data[1:], 3 * self.bkg.data[1:]) assert_allclose(dataset1.background.data[0], self.bkg.data[0]) assert_allclose( dataset1.aeff.data.data.to_value("m2"), 4.0 / 3 * aeff.data.data.to_value("m2"), ) assert_allclose(dataset1.edisp.pdf_matrix[1:], edisp.pdf_matrix[1:]) assert_allclose(dataset1.edisp.pdf_matrix[0], 0.5 * edisp.pdf_matrix[0]) def test_spectrum_dataset_stack_nondiagonal_no_bkg(self): aeff = EffectiveAreaTable.from_parametrization(self.src.energy.edges, "HESS") edisp1 = EnergyDispersion.from_gauss(self.src.energy.edges, self.src.energy.edges, 0.1, 0.0) livetime = self.livetime dataset1 = SpectrumDataset(counts=None, livetime=livetime, aeff=aeff, edisp=edisp1, background=None) livetime2 = livetime aeff2 = EffectiveAreaTable(self.src.energy.edges[:-1], self.src.energy.edges[1:], aeff.data.data) edisp2 = EnergyDispersion.from_gauss(self.src.energy.edges, self.src.energy.edges, 0.2, 0.0) dataset2 = SpectrumDataset( counts=self.src.copy(), livetime=livetime2, aeff=aeff2, edisp=edisp2, background=None, ) dataset1.stack(dataset2) assert dataset1.counts is None assert dataset1.background is None assert dataset1.livetime == 2 * self.livetime assert_allclose(dataset1.aeff.data.data.to_value("m2"), aeff.data.data.to_value("m2")) assert_allclose(dataset1.edisp.get_bias(1 * u.TeV), 0.0, atol=1e-3) assert_allclose(dataset1.edisp.get_resolution(1 * u.TeV), 0.1581, atol=1e-2)
edisp = cta_irf["edisp"].to_energy_dispersion(offset=offset, e_true=energy, e_reco=energy) edisp.plot_matrix() print(edisp.data) # In[ ]: dataset = SpectrumDataset(aeff=aeff, edisp=edisp, model=model_ref, livetime=livetime, obs_id=0) dataset.fake(random_state=42) # In[ ]: # Take a quick look at the simulated counts dataset.counts.plot() # ## Include Background # # In this section we will include a background component. Furthermore, we will also simulate more than one observation and fit each one individually in order to get average fit results. # In[ ]: # We assume a PowerLaw shape of the background as well bkg_model = PowerLaw(index=2.5, amplitude=1e-11 * u.Unit("cm-2 s-1 TeV-1"),
class TestSpectrumDataset: """Test fit on counts spectra without any IRFs""" def setup(self): self.nbins = 30 binning = np.logspace(-1, 1, self.nbins + 1) * u.TeV self.source_model = PowerLaw(index=2.1, amplitude=1e5 / u.TeV / u.s, reference=0.1 * u.TeV) self.livetime = 100 * u.s bkg_rate = np.ones(self.nbins) / u.s bkg_expected = bkg_rate * self.livetime self.bkg = CountsSpectrum(energy_lo=binning[:-1], energy_hi=binning[1:], data=bkg_expected) random_state = get_random_state(23) self.npred = (self.source_model.integral(binning[:-1], binning[1:]) * self.livetime) self.npred += bkg_expected source_counts = random_state.poisson(self.npred) self.src = CountsSpectrum(energy_lo=binning[:-1], energy_hi=binning[1:], data=source_counts) self.dataset = SpectrumDataset( model=self.source_model, counts=self.src, livetime=self.livetime, background=self.bkg, ) def test_data_shape(self): assert self.dataset.data_shape[0] == self.nbins def test_energy_range(self): energy_range = self.dataset.energy_range assert energy_range.unit == u.TeV assert_allclose(energy_range.to_value("TeV"), [0.1, 10.0]) def test_cash(self): """Simple CASH fit to the on vector""" fit = Fit(self.dataset) result = fit.run() assert result.success assert "minuit" in repr(result) npred = self.dataset.npred().data.sum() assert_allclose(npred, self.npred.sum(), rtol=1e-3) assert_allclose(result.total_stat, -18087404.624, rtol=1e-3) pars = result.parameters assert_allclose(pars["index"].value, 2.1, rtol=1e-2) assert_allclose(pars.error("index"), 0.00127, rtol=1e-2) assert_allclose(pars["amplitude"].value, 1e5, rtol=1e-3) assert_allclose(pars.error("amplitude"), 153.450, rtol=1e-2) def test_fake(self): """Test the fake dataset""" real_dataset = self.dataset.copy() self.dataset.fake(314) assert real_dataset.counts.data.shape == self.dataset.counts.data.shape assert real_dataset.background.data.sum( ) == self.dataset.background.data.sum() assert int(real_dataset.counts.data.sum()) == 907010 assert self.dataset.counts.data.sum() == 907331 def test_incorrect_mask(self): mask_fit = np.ones(self.nbins, dtype=np.dtype("float")) with pytest.raises(ValueError): SpectrumDataset( model=self.source_model, counts=self.src, livetime=self.livetime, mask_fit=mask_fit, background=self.bkg, ) def test_set_model(self): aeff = EffectiveAreaTable.from_parametrization(self.src.energy.edges, "HESS") edisp = EnergyDispersion.from_diagonal_response( self.src.energy.edges, self.src.energy.edges) dataset = SpectrumDataset(None, self.src, self.livetime, None, aeff, edisp, self.bkg) with pytest.raises(AttributeError): dataset.parameters dataset.model = self.source_model assert dataset.parameters[0] == self.source_model.parameters[0] def test_str(self): assert "SpectrumDataset" in str(self.dataset)