def test_stats_calc_stat_wstat_pha_nobg(): """wstat statistic fails with no background: PHA dataset""" statobj = WStat() data, model = setup_single_pha(False, False, background=False) with pytest.raises(StatErr): statobj.calc_stat(data, model)
def test_stats_calc_stat_wstat_diffbins(): """wstat statistic fails when src/bg bin sizes do not match""" statobj = WStat() data, model = setup_single_pha(True, False, background=True) # Tweak data to have one-less bin than the background. This # used to be easy but with data validation we need to # create a new object. # data2 = DataPHA("faked", channel=data.channel[:-1], counts=data.counts[:-1], staterror=data.staterror[:-1], grouping=data.grouping[:-1], exposure=data.exposure, backscal=data.backscal, areascal=data.areascal) # We might expect the ARF/RMF calls to fail if we add validation # (to check the ARF/RMF is valid for the PHA dataset). # data2.set_arf(data.get_arf()) data2.set_rmf(data.get_rmf()) data2.set_background(data.get_background()) # There is no Sherpa error for this, which seems surprising with pytest.raises(TypeError) as err: statobj.calc_stat(data2, model) assert str( err.value) == "input array sizes do not match, data: 5 vs group: 4"
def test_stats_calc_stat_wstat_nobg(usestat, usesys): """wstat statistic fails with no background""" statobj = WStat() data, model = setup_single(usestat, usesys) with pytest.raises(StatErr): statobj.calc_stat(data, model)
def test_wstat(self): fit = Fit(self.data, self.model, WStat(), LevMar()) results = fit.fit() # On a local linux machine I have to bump the tolerance to # 3e-4, but this isn't seen on Travis. The fit isn't # "great", so it may be that the results are sensitive to # numerical differences (e.g. as introduced with updated # compilers). # tol = 3e-4 tol = 1e-6 # TODO: investigate difference self.compare_results(self._fit_wstat_results_bench, results, tol=tol)
def test_stats_calc_stat_wstat_diffbins(): """wstat statistic fails when src/bg bin sizes do not match""" statobj = WStat() data, model = setup_single_pha(True, False, background=True) # Tweak data to have one-less bin than the background data.channel = data.channel[:-1] data.counts = data.channel[:-1] for attr in ['staterror', 'syserror', 'grouping', 'quality', 'backscal']: val = getattr(data, attr) if val is not None: try: setattr(data, attr, val[:-1]) except TypeError: # assume a scalar, so leave be pass # There is no Sherpa error for this, which seems surprising with pytest.raises(TypeError): statobj.calc_stat(data, model)
def test_wstat(hide_logging, reset_xspec, setup): fit = Fit(setup['data'], setup['model'], WStat(), LevMar()) results = fit.fit() _fit_wstat_results_bench = { 'succeeded': 1, 'numpoints': 460, 'dof': 457, 'istatval': 21647.48285025895, 'statval': 472.6585709918982, 'parvals': numpy.array([1.750204250228727, 5.47466040324842, -1.9983562007031974]) } compare_results(_fit_wstat_results_bench, results, tol=2e-4)
def test_wstat_error(self): data = self.bkg data.notice(0.5, 7.0) fit = Fit(data, self.model, WStat(), NelderMead()) self.assertRaises(StatErr, fit.fit)
def test_wstat(self): fit = Fit(self.data, self.model, WStat(), NelderMead()) results = fit.fit() self.compare_results(self._fit_wstat_results_bench, results)
def prepare_spectra(group, nH, add_gal, redshift): pha = read_pha("core_spectrum.pi") pha.set_analysis("energy") pha.notice(0.5, 7.0) tabs = ~pha.mask pha.group_counts(group, tabStops=tabs) x = pha.get_x() x = pha.apply_filter(x, pha._middle) y = pha.get_y(filter=True) pha.set_analysis("energy") model = xsphabs.abs1 * powlaw1d.srcp1 print("Fitting the spectrum") zFlag = False if (nH is not None) and (nH > 0.0): if add_gal == 1: model = xsphabs.gal * xszphabs.abs1 * powlaw1d.srcp gal.nH = nH freeze(gal.nH) zFlag = True else: model = xsphabs.abs1 * powlaw1d.srcp1 abs1.nH = nH freeze(abs1.nH) else: model = xszphabs.abs1 * powlaw1d.srcp1 zFlag = True if zFlag is True and add_gal == 1: # print('REDSHIFT',redshift) abs1.redshift = redshift freeze(abs1.redshift) full_model = RSPModelPHA(pha.get_arf(), pha.get_rmf(), pha, pha.exposure * model) print(full_model) fit = Fit(pha, full_model, method=MonCar(), stat=WStat()) res = fit.fit() print(res.format()) print(fit.est_errors()) # calculate the p-value for wstat mplot2 = ModelPlot() mplot2.prepare(pha, full_model) miu = mplot2.y * pha.exposure * 0.0146 obs = y * pha.exposure * 0.0146 c, ce, cv = gof_cstat(miu, obs) print(f"C0={c},C_e={ce},C_v={cv}") zval = (fit.calc_stat() - ce) / np.sqrt(cv) if zval > 0: pval = special.erfc(zval / np.sqrt(2)) else: pval = special.erf(abs(zval) / np.sqrt(2)) print(f"p-value for wstat = {pval}") set_data(pha) set_model(model) save_chart_spectrum("core_flux_chart.dat", elow=0.5, ehigh=7.0) # save_chart_spectrum("core_flux_chart.rdb",format='text/tsv', elow=0.5, ehigh=7.0) save_spectrum_rdb("core_flux_chart.dat")
def test_wstat_error(hide_logging, reset_xspec, setup_bkg): fit = Fit(setup_bkg['bkg'], setup_bkg['model'], WStat(), NelderMead()) with pytest.raises(StatErr): fit.fit()
def prepare_spectra(nH: float, group: int = 1, add_gal: bool = False, redshift: Optional[float] = None, **kwargs) -> float: """ Fit the spectra using an absorbed powerlaw model using the Wstat statistic. The function also returns a p-value for the gof. :param nH: The galactic absorption column density in units of 10^22 /cm3 :param group: The number of counts per energy bin :param add_gal: Setting this to True would add an intrinsic abrosption column density along side the galactic one :param redshift: The redshift to use in the fit. Only takes effect if add_gal is set to True ... :return: Returns the p-value of the gof. The null hypothesis states that the model and the observation differ while alternate says that the model explains the data """ pha = read_pha("core_spectrum.pi") pha.set_analysis("energy") pha.notice(0.5, 7.0) tabs = ~pha.mask pha.group_counts(group, tabStops=tabs) x = pha.get_x() x = pha.apply_filter(x, pha._middle) y = pha.get_y(filter=True) pha.set_analysis("energy") model = xsphabs.abs1 * powlaw1d.srcp1 print("Fitting the spectrum") zFlag = False if (nH is not None) and (nH > 0.0): if add_gal == 1: model = xsphabs.gal * xszphabs.abs1 * powlaw1d.srcp gal.nH = nH freeze(gal.nH) zFlag = True else: model = xsphabs.abs1 * powlaw1d.srcp1 abs1.nH = nH freeze(abs1.nH) else: model = xszphabs.abs1 * powlaw1d.srcp1 zFlag = True if zFlag is True and add_gal == 1: # print('REDSHIFT',redshift) abs1.redshift = redshift freeze(abs1.redshift) full_model = RSPModelPHA(pha.get_arf(), pha.get_rmf(), pha, pha.exposure * model) print(full_model) fit = Fit(pha, full_model, method=MonCar(), stat=WStat()) res = fit.fit() print(res.format()) print(fit.est_errors()) # calculate the p-value for wstat mplot2 = ModelPlot() mplot2.prepare(pha, full_model) miu = mplot2.y * pha.exposure * 0.0146 obs = y * pha.exposure * 0.0146 c, ce, cv = SpecUtils.estimate_gof_cstat(miu, obs) #print(f"C0={c},C_e={ce},C_v={cv}") zval = (fit.calc_stat() - ce) / np.sqrt(cv) if zval > 0: pval = special.erfc(zval / np.sqrt(2)) else: pval = special.erf(abs(zval) / np.sqrt(2)) print(f"p-value for wstat = {pval}") set_data(pha) set_model(model) save_chart_spectrum("core_flux_chart.dat", elow=0.5, ehigh=7.0) # save_chart_spectrum("core_flux_chart.rdb",format='text/tsv', elow=0.5, ehigh=7.0) SAOTraceUtils.save_spectrum_rdb("core_flux_chart.dat") return pval