def make_observation_list(): """obs with dummy IRF""" nbin = 3 energy = np.logspace(-1, 1, nbin + 1) * u.TeV livetime = 2 * u.h data_on = np.arange(nbin) dataoff_1 = np.ones(3) dataoff_2 = np.ones(3) * 3 dataoff_1[1] = 0 dataoff_2[1] = 0 on_vector = CountsSpectrum(energy_lo=energy[:-1], energy_hi=energy[1:], data=data_on) off_vector1 = CountsSpectrum(energy_lo=energy[:-1], energy_hi=energy[1:], data=dataoff_1) off_vector2 = CountsSpectrum(energy_lo=energy[:-1], energy_hi=energy[1:], data=dataoff_2) aeff = EffectiveAreaTable.from_constant(energy, "1 cm2") edisp = EDispKernel.from_gauss(e_true=energy, e_reco=energy, sigma=0.2, bias=0) time_ref = Time("2010-01-01") gti1 = make_gti({ "START": [5, 6, 1, 2], "STOP": [8, 7, 3, 4] }, time_ref=time_ref) gti2 = make_gti({"START": [14], "STOP": [15]}, time_ref=time_ref) obs1 = SpectrumDatasetOnOff( counts=on_vector, counts_off=off_vector1, aeff=aeff, edisp=edisp, livetime=livetime, mask_safe=np.ones(on_vector.energy.nbin, dtype=bool), acceptance=1, acceptance_off=2, name="1", gti=gti1, ) obs2 = SpectrumDatasetOnOff( counts=on_vector, counts_off=off_vector2, aeff=aeff, edisp=edisp, livetime=livetime, mask_safe=np.ones(on_vector.energy.nbin, dtype=bool), acceptance=1, acceptance_off=4, name="2", gti=gti2, ) obs_list = [obs1, obs2] return obs_list
def setup(self): etrue = np.logspace(-1, 1, 10) * u.TeV self.e_true = etrue ereco = np.logspace(-1, 1, 5) * u.TeV elo = ereco[:-1] ehi = ereco[1:] self.e_reco = ereco self.aeff = EffectiveAreaTable(etrue[:-1], etrue[1:], np.ones(9) * u.cm**2) self.edisp = EDispKernel.from_diagonal_response(etrue, ereco) data = np.ones(elo.shape) data[-1] = 0 # to test stats calculation with empty bins self.on_counts = CountsSpectrum(elo, ehi, data) self.off_counts = CountsSpectrum(elo, ehi, np.ones(elo.shape) * 10) start = u.Quantity([0], "s") stop = u.Quantity([1000], "s") time_ref = Time("2010-01-01 00:00:00.0") self.gti = GTI.create(start, stop, time_ref) self.livetime = self.gti.time_sum self.dataset = SpectrumDatasetOnOff( counts=self.on_counts, counts_off=self.off_counts, aeff=self.aeff, edisp=self.edisp, livetime=self.livetime, acceptance=np.ones(elo.shape), acceptance_off=np.ones(elo.shape) * 10, name="test", gti=self.gti, )
def test_fake(self): """Test the fake dataset""" source_model = SkyModel(spectral_model=PowerLawSpectralModel()) dataset = SpectrumDatasetOnOff( counts=self.on_counts, counts_off=self.off_counts, models=source_model, aeff=self.aeff, livetime=self.livetime, edisp=self.edisp, acceptance=1, acceptance_off=10, ) real_dataset = dataset.copy() # Define background model counts elo = self.on_counts.energy.edges[:-1] ehi = self.on_counts.energy.edges[1:] data = np.ones(self.on_counts.data.shape) background_model = CountsSpectrum(elo, ehi, data) dataset.fake(background_model=background_model, random_state=314, name="fake") assert real_dataset.counts.data.shape == dataset.counts.data.shape assert real_dataset.counts_off.data.shape == dataset.counts_off.data.shape assert (real_dataset.counts.energy.center.mean() == dataset.counts.energy.center.mean()) assert real_dataset.acceptance.mean() == dataset.acceptance.mean() assert real_dataset.acceptance_off.mean( ) == dataset.acceptance_off.mean() assert dataset.counts_off.data.sum() == 39 assert dataset.counts.data.sum() == 5 assert dataset.name == "fake"
def setup(self): etrue = np.logspace(-1, 1, 10) * u.TeV self.e_true = etrue ereco = np.logspace(-1, 1, 5) * u.TeV elo = ereco[:-1] ehi = ereco[1:] self.aeff = EffectiveAreaTable(etrue[:-1], etrue[1:], np.ones(9) * u.cm**2) self.edisp = EnergyDispersion.from_diagonal_response(etrue, ereco) data = np.ones(elo.shape) data[-1] = 0 # to test stats calculation with empty bins self.on_counts = CountsSpectrum(elo, ehi, data) self.off_counts = CountsSpectrum(elo, ehi, np.ones(elo.shape) * 10) self.livetime = 1000 * u.s self.dataset = SpectrumDatasetOnOff( counts=self.on_counts, counts_off=self.off_counts, aeff=self.aeff, edisp=self.edisp, livetime=self.livetime, acceptance=np.ones(elo.shape), acceptance_off=np.ones(elo.shape) * 10, obs_id="test", )
def test_fit_range(self): """Test fit range without complication of thresholds""" dataset = SpectrumDatasetOnOff(counts=self.src, mask_safe=np.ones(self.src.energy.nbin, dtype=bool)) dataset.model = self.source_model assert np.sum(dataset.mask_safe) == self.nbins e_min, e_max = dataset.energy_range assert_allclose(e_max.value, 10) assert_allclose(e_min.value, 0.1)
def test_peek(self): dataset = SpectrumDatasetOnOff( counts=self.on_counts, counts_off=self.off_counts, aeff=self.aeff, livetime=self.livetime, edisp=self.edisp, acceptance=1, acceptance_off=10, ) with mpl_plot_check(): dataset.peek()
def test_str(self): model = SkyModel(spectral_model=PowerLawSpectralModel()) dataset = SpectrumDatasetOnOff( counts=self.on_counts, counts_off=self.off_counts, models=model, aeff=self.aeff, livetime=self.livetime, edisp=self.edisp, acceptance=1, acceptance_off=10, ) assert "SpectrumDatasetOnOff" in str(dataset) assert "wstat" in str(dataset)
def test_plot_fit(self): model = SkyModel(spectral_model=PowerLawSpectralModel()) dataset = SpectrumDatasetOnOff( counts=self.on_counts, counts_off=self.off_counts, models=model, aeff=self.aeff, livetime=self.livetime, edisp=self.edisp, acceptance=1, acceptance_off=10, ) with mpl_plot_check(): dataset.plot_fit()
def simulate_spectrum_dataset(model, random_state=0): energy = np.logspace(-0.5, 1.5, 21) * u.TeV aeff = EffectiveAreaTable.from_parametrization(energy=energy) bkg_model = PowerLawSpectralModel(index=2.5, amplitude="1e-12 cm-2 s-1 TeV-1") dataset = SpectrumDatasetOnOff( aeff=aeff, model=model, livetime=100 * u.h, acceptance=1, acceptance_off=5 ) eval = SpectrumEvaluator(model=bkg_model, aeff=aeff, livetime=100 * u.h) bkg_model = eval.compute_npred() dataset.fake(random_state=random_state, background_model=bkg_model) return dataset
def test_to_from_ogip_files_no_edisp(self, tmpdir): dataset = SpectrumDatasetOnOff( counts=self.on_counts, aeff=self.aeff, livetime=self.livetime, mask_safe=np.ones(self.on_counts.energy.nbin, dtype=bool), acceptance=1, obs_id="test", ) dataset.to_ogip_files(outdir=tmpdir, overwrite=True) filename = tmpdir / "pha_obstest.fits" newdataset = SpectrumDatasetOnOff.from_ogip_files(filename) assert_allclose(self.on_counts.data, newdataset.counts.data) assert newdataset.counts_off is None assert newdataset.edisp is None
def test_to_from_ogip_files_no_edisp(self, tmp_path): dataset = SpectrumDatasetOnOff( counts=self.on_counts, aeff=self.aeff, livetime=self.livetime, mask_safe=np.ones(self.on_counts.energy.nbin, dtype=bool), acceptance=1, name="test", ) dataset.to_ogip_files(outdir=tmp_path) newdataset = SpectrumDatasetOnOff.from_ogip_files(tmp_path / "pha_obstest.fits") assert_allclose(self.on_counts.data, newdataset.counts.data) assert newdataset.counts_off is None assert newdataset.edisp is None assert newdataset.gti is None
def test_npred_no_edisp(self): const = 1 / u.TeV / u.cm**2 / u.s model = ConstantSpectralModel(const) livetime = 1 * u.s dataset = SpectrumDatasetOnOff( counts=self.on_counts, counts_off=self.off_counts, aeff=self.aeff, model=model, livetime=livetime, ) energy = self.aeff.energy.edges * self.aeff.energy.unit expected = self.aeff.data.data[0] * (energy[-1] - energy[0]) * const * livetime assert_allclose(dataset.npred_sig().data.sum(), expected.value)
def test_to_from_ogip_files(self, tmp_path): dataset = SpectrumDatasetOnOff( counts=self.on_counts, counts_off=self.off_counts, aeff=self.aeff, edisp=self.edisp, livetime=self.livetime, mask_safe=np.ones(self.on_counts.energy.nbin, dtype=bool), acceptance=1, acceptance_off=10, name="test", gti=self.gti, ) dataset.to_ogip_files(outdir=tmp_path) newdataset = SpectrumDatasetOnOff.from_ogip_files(tmp_path / "pha_obstest.fits") assert_allclose(self.on_counts.data, newdataset.counts.data) assert_allclose(self.off_counts.data, newdataset.counts_off.data) assert_allclose(self.edisp.pdf_matrix, newdataset.edisp.pdf_matrix) assert_time_allclose(newdataset.gti.time_start, dataset.gti.time_start)
def test_npred_no_edisp(self): const = 1 * u.Unit("cm-2 s-1 TeV-1") model = SkyModel(spectral_model=ConstantSpectralModel(const=const)) livetime = 1 * u.s e_reco = self.on_counts.energy.edges aeff = EffectiveAreaTable(e_reco[:-1], e_reco[1:], np.ones(4) * u.cm**2) dataset = SpectrumDatasetOnOff( counts=self.on_counts, counts_off=self.off_counts, aeff=aeff, models=model, livetime=livetime, ) energy = aeff.energy.edges expected = aeff.data.data[0] * (energy[-1] - energy[0]) * const * livetime assert_allclose(dataset.npred_sig().data.sum(), expected.value)
def test_wstat(self): """WStat with on source and background spectrum""" on_vector = self.src.copy() on_vector.data += self.bkg.data obs = SpectrumDatasetOnOff( counts=on_vector, counts_off=self.off, acceptance=1, acceptance_off=1 / self.alpha, ) obs.model = self.source_model self.source_model.parameters.index = 1.12 fit = Fit(obs) result = fit.run() pars = self.source_model.parameters assert_allclose(pars["index"].value, 1.997342, rtol=1e-3) assert_allclose(pars["amplitude"].value, 100245.187067, rtol=1e-3) assert_allclose(result.total_stat, 30.022316, rtol=1e-3)
# 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"), reference=1 * u.TeV) evaluator = SpectrumEvaluator(model=bkg_model, aeff=aeff, livetime=livetime) npred_bkg = evaluator.compute_npred() # In[ ]: dataset = SpectrumDatasetOnOff( aeff=aeff, edisp=edisp, model=model_ref, livetime=livetime, acceptance=1, acceptance_off=5, ) # In[ ]: get_ipython().run_cell_magic( 'time', '', '# Now simulate 30 indepenent spectra using the same set of observation conditions.\nn_obs = 100\nseeds = np.arange(n_obs)\n\ndatasets = []\n\nfor idx in range(n_obs):\n dataset.fake(random_state=idx, background_model=npred_bkg)\n datasets.append(dataset.copy())' ) # Before moving on to the fit let's have a look at the simulated observations. # In[ ]:
dataset.model = model dataset.fake(random_state=42) print(dataset) # You can see that backgound counts are now simulated # ### OnOff analysis # # To do `OnOff` spectral analysis, which is the usual science case, the standard would be to use `SpectrumDatasetOnOff`, which uses the acceptance to fake off-counts # In[ ]: dataset_onoff = SpectrumDatasetOnOff( aeff=dataset.aeff, edisp=dataset.edisp, models=model, livetime=livetime, acceptance=1, acceptance_off=5, ) dataset_onoff.fake(background_model=dataset.background) print(dataset_onoff) # You can see that off counts are now simulated as well. We now simulate several spectra using the same set of observation conditions. # In[ ]: get_ipython().run_cell_magic( 'time', '', '\nn_obs = 100\ndatasets = []\n\nfor idx in range(n_obs):\n dataset_onoff.fake(random_state=idx, background_model=dataset.background)\n dataset_onoff.name = f"obs_{idx}"\n datasets.append(dataset_onoff.copy())' )