Beispiel #1
0
class TestSimpleFit:
    """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,
                                                  amplitude=1e5 / u.TeV,
                                                  reference=0.1 * u.TeV)
        self.bkg_model = PowerLawSpectralModel(index=3,
                                               amplitude=1e4 / u.TeV,
                                               reference=0.1 * u.TeV)

        self.alpha = 0.1
        random_state = get_random_state(23)
        npred = self.source_model.integral(binning[:-1], binning[1:])
        source_counts = random_state.poisson(npred)
        self.src = CountsSpectrum(energy_lo=binning[:-1],
                                  energy_hi=binning[1:],
                                  data=source_counts)
        # Currently it's necessary to specify a lifetime
        self.src.livetime = 1 * u.s

        npred_bkg = self.bkg_model.integral(binning[:-1], binning[1:])

        bkg_counts = random_state.poisson(npred_bkg)
        off_counts = random_state.poisson(npred_bkg * 1.0 / self.alpha)
        self.bkg = CountsSpectrum(energy_lo=binning[:-1],
                                  energy_hi=binning[1:],
                                  data=bkg_counts)
        self.off = CountsSpectrum(energy_lo=binning[:-1],
                                  energy_hi=binning[1:],
                                  data=off_counts)

    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)
Beispiel #2
0
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()
Beispiel #3
0
class TestFit:
    """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,
                                                  amplitude=1e5 *
                                                  u.Unit("cm-2 s-1 TeV-1"),
                                                  reference=0.1 * u.TeV)
        bkg_model = PowerLawSpectralModel(index=3,
                                          amplitude=1e4 *
                                          u.Unit("cm-2 s-1 TeV-1"),
                                          reference=0.1 * u.TeV)

        self.alpha = 0.1
        random_state = get_random_state(23)
        npred = self.source_model.integral(binning[:-1], binning[1:]).value
        source_counts = random_state.poisson(npred)
        self.src = CountsSpectrum(energy_lo=binning[:-1],
                                  energy_hi=binning[1:],
                                  data=source_counts)

        self.src.livetime = 1 * u.s
        self.aeff = EffectiveAreaTable.from_constant(binning, "1 cm2")

        npred_bkg = bkg_model.integral(binning[:-1], binning[1:]).value

        bkg_counts = random_state.poisson(npred_bkg)
        off_counts = random_state.poisson(npred_bkg * 1.0 / self.alpha)
        self.bkg = CountsSpectrum(energy_lo=binning[:-1],
                                  energy_hi=binning[1:],
                                  data=bkg_counts)
        self.off = CountsSpectrum(energy_lo=binning[:-1],
                                  energy_hi=binning[1:],
                                  data=off_counts)

    def test_cash(self):
        """Simple CASH fit to the on vector"""
        dataset = SpectrumDataset(
            model=self.source_model,
            counts=self.src,
            aeff=self.aeff,
            livetime=self.src.livetime,
        )

        npred = dataset.npred().data
        assert_allclose(npred[5], 660.5171, rtol=1e-5)

        stat_val = dataset.likelihood()
        assert_allclose(stat_val, -107346.5291, rtol=1e-5)

        self.source_model.parameters["index"].value = 1.12

        fit = Fit([dataset])
        result = fit.run()

        # These values are check with sherpa fits, do not change
        pars = result.parameters
        assert_allclose(pars["index"].value, 1.995525, rtol=1e-3)
        assert_allclose(pars["amplitude"].value, 100245.9, rtol=1e-3)

    def test_wstat(self):
        """WStat with on source and background spectrum"""
        on_vector = self.src.copy()
        on_vector.data += self.bkg.data
        dataset = SpectrumDatasetOnOff(
            counts=on_vector,
            counts_off=self.off,
            aeff=self.aeff,
            livetime=self.src.livetime,
            acceptance=1,
            acceptance_off=1 / self.alpha,
        )
        dataset.model = self.source_model

        self.source_model.parameters.index = 1.12

        fit = Fit([dataset])
        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)

    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_likelihood_profile(self):
        dataset = SpectrumDataset(
            model=self.source_model,
            aeff=self.aeff,
            livetime=self.src.livetime,
            counts=self.src,
            mask_safe=np.ones(self.src.energy.nbin, dtype=bool),
        )
        fit = Fit([dataset])
        result = fit.run()
        true_idx = result.parameters["index"].value
        values = np.linspace(0.95 * true_idx, 1.05 * true_idx, 100)
        profile = fit.likelihood_profile("index", values=values)
        actual = values[np.argmin(profile["likelihood"])]
        assert_allclose(actual, true_idx, rtol=0.01)
Beispiel #4
0
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)