def validate_pha(idval): """Check that the PHA dataset in id=idval is as expected. """ assert ui.list_data_ids() == [idval] pha = ui.get_data(idval) assert isinstance(pha, DataPHA) arf = ui.get_arf(idval) assert isinstance(arf, ARF1D) rmf = ui.get_rmf(idval) assert isinstance(rmf, RMF1D) bpha = ui.get_bkg(idval, bkg_id=1) assert isinstance(bpha, DataPHA) barf = ui.get_arf(idval, bkg_id=1) assert isinstance(barf, ARF1D) brmf = ui.get_rmf(idval, bkg_id=1) assert isinstance(brmf, RMF1D) # normally the background data set would have a different name, # but this is a PHA Type 3 file. # assert pha.name == bpha.name assert arf.name == barf.name assert rmf.name == brmf.name
def validate_pha(self, idval): """Check that the PHA dataset in id=idval is as expected. """ self.assertEqual(ui.list_data_ids(), [idval]) pha = ui.get_data(idval) self.assertIsInstance(pha, DataPHA) arf = ui.get_arf(idval) self.assertIsInstance(arf, ARF1D) rmf = ui.get_rmf(idval) self.assertIsInstance(rmf, RMF1D) bpha = ui.get_bkg(idval, bkg_id=1) self.assertIsInstance(bpha, DataPHA) barf = ui.get_arf(idval, bkg_id=1) self.assertIsInstance(barf, ARF1D) brmf = ui.get_rmf(idval, bkg_id=1) self.assertIsInstance(brmf, RMF1D) # normally the background data set would have a different name, # but this is a PHA Type 3 file. # self.assertEqual(pha.name, bpha.name) self.assertEqual(arf.name, barf.name) self.assertEqual(rmf.name, brmf.name)
def test_xmm2(self): self.run_thread('xmm2') self.assertEqualWithinTol(ui.get_data().channel[0], 1.0, 1e-4) self.assertEqual(ui.get_rmf().detchans, 800) self.assertEqual(len(ui.get_rmf().energ_lo), 2400) self.assertEqual(len(ui.get_rmf().energ_hi), 2400) self.assertEqual(len(ui.get_rmf().n_grp), 2400) self.assertEqual(len(ui.get_rmf().f_chan), 2394) self.assertEqual(len(ui.get_rmf().n_chan), 2394) self.assertEqual(len(ui.get_rmf().matrix), 1281216) self.assertEqual(ui.get_rmf().offset, 0) self.assertEqual(len(ui.get_rmf().e_min), 800) self.assertEqual(len(ui.get_rmf().e_max), 800) self.assertEqual(len(ui.get_arf().energ_lo), 2400) self.assertEqual(len(ui.get_arf().energ_hi), 2400) self.assertEqual(len(ui.get_arf().specresp), 2400)
def get_identity_response(i): n = ui.get_bkg(i).counts.size rmf = ui.get_rmf(i) try: arf = ui.get_arf(i) return lambda model: IdentityResponse(n, model, arf=arf, rmf=rmf) except: return lambda model: IdentityRMF(n, model, rmf=rmf)
def test_xmm2(run_thread, fix_xspec): with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") run_thread('xmm2') # NOTE: if this test is run on its own it can generate three warnings, # with the first being a RuntimeWarnnig about numpy.ndarray size # changed. We filter this out as it's not at all clear what is going # on and we have filters in conftest to remove similar warnings # ws = [ w for w in ws if not (w.category == RuntimeWarning and str(w.message).startswith( 'numpy.ndarray size changed, may indicate binary incompatibility.') ) ] assert len(ws) == 2 cats = set([w.category for w in ws]) assert cats == set([UserWarning]) # The order of reading the ARF and RMF is not guaranteed, # so do not force it here when testing the two warning # messages. # arffile = 'MNLup_2138_0670580101_EMOS1_S001_spec.arf' rmffile = 'MNLup_2138_0670580101_EMOS1_S001_spec.rmf' emsg_arf = "The minimum ENERG_LO in the ARF " + \ "'{}' ".format(arffile) + \ "was 0 and has been replaced by {}".format(EMIN) emsg_rmf = "The minimum ENERG_LO in the RMF " + \ "'{}' ".format(rmffile) + \ "was 0 and has been replaced by {}".format(EMIN) emsgs = set([emsg_arf, emsg_rmf]) wmsgs = set([str(w.message) for w in ws]) assert wmsgs == emsgs assert ui.get_data().channel[0] == approx(1.0, rel=1e-4) rmf = ui.get_rmf() arf = ui.get_arf() assert rmf.detchans == 800 assert len(rmf.energ_lo) == 2400 assert len(rmf.energ_hi) == 2400 assert len(rmf.n_grp) == 2400 assert len(rmf.f_chan) == 2394 assert len(rmf.n_chan) == 2394 assert len(rmf.matrix) == 1281216 assert rmf.offset == 0 assert len(rmf.e_min) == 800 assert len(rmf.e_max) == 800 assert len(arf.energ_lo) == 2400 assert len(arf.energ_hi) == 2400 assert len(arf.specresp) == 2400 etol = EMIN / 100.0 assert rmf.energ_lo[0] == approx(EMIN, rel=etol) assert arf.energ_lo[0] == approx(EMIN, rel=etol)
def test_more_ui_string_model_with_rmf(make_data_path): ui.load_pha("foo", make_data_path('pi2286.fits')) ui.load_rmf("foo", make_data_path('rmf2286.fits')) # Check that get_rmf(id)('modelexpression') works. If it # raises an error the test will fail. # m = ui.get_rmf("foo")("powlaw1d.pl1") assert isinstance(m, RMFModelPHA)
def test_string_model_with_rmf(self): ui.load_pha("foo", self.pha) ui.load_rmf("foo", self.rmf) # Check that get_rmf(id)('modelexpression') works caught = False try: m = ui.get_rmf("foo")("powlaw1d.pl1") except: caught = True if caught: self.fail("Exception caught when it shouldn't") from sherpa.astro.instrument import RMFModelPHA self.assertTrue(isinstance(m, RMFModelPHA))
def test_xmm2(self): with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") self.run_thread('xmm2') assert len(ws) == 2 cats = set([w.category for w in ws]) assert cats == set([UserWarning]) # The order of reading the ARF and RMF is not guaranteed, # so do not force it here when testing the two warning # messages. # arffile = 'MNLup_2138_0670580101_EMOS1_S001_spec.arf' rmffile = 'MNLup_2138_0670580101_EMOS1_S001_spec.rmf' emsg_arf = "The minimum ENERG_LO in the ARF " + \ "'{}' ".format(arffile) + \ "was 0 and has been replaced by {}".format(EMIN) emsg_rmf = "The minimum ENERG_LO in the RMF " + \ "'{}' ".format(rmffile) + \ "was 0 and has been replaced by {}".format(EMIN) emsgs = set([emsg_arf, emsg_rmf]) wmsgs = set([str(w.message) for w in ws]) assert wmsgs == emsgs assert ui.get_data().channel[0] == approx(1.0, rel=1e-4) rmf = ui.get_rmf() arf = ui.get_arf() self.assertEqual(rmf.detchans, 800) self.assertEqual(len(rmf.energ_lo), 2400) self.assertEqual(len(rmf.energ_hi), 2400) self.assertEqual(len(rmf.n_grp), 2400) self.assertEqual(len(rmf.f_chan), 2394) self.assertEqual(len(rmf.n_chan), 2394) self.assertEqual(len(rmf.matrix), 1281216) self.assertEqual(rmf.offset, 0) self.assertEqual(len(rmf.e_min), 800) self.assertEqual(len(rmf.e_max), 800) self.assertEqual(len(arf.energ_lo), 2400) self.assertEqual(len(arf.energ_hi), 2400) self.assertEqual(len(arf.specresp), 2400) etol = EMIN / 100.0 assert rmf.energ_lo[0] == approx(EMIN, rel=etol) assert arf.energ_lo[0] == approx(EMIN, rel=etol)
def test_can_use_swift_data(make_data_path, is_known_warning): """A basic check that we can read in and use the Swift data. Unlike the previous tests, that directly access the io module, this uses the ui interface. """ # QUS are there pytest fixtures that ensure the state is # clean on entry and exit? ui.clean() # The Swift PHA file does not have the ANCRFILE/RESPFILE keywords # set up, so the responses have to be manually added. # ui.load_pha(make_data_path(PHAFILE)) rmffile = make_data_path(RMFFILE) with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") ui.load_rmf(rmffile) validate_replacement_warning(ws, 'RMF', rmffile, is_known_warning) arffile = make_data_path(ARFFILE) with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") ui.load_arf(arffile) validate_replacement_warning(ws, 'ARF', arffile, is_known_warning) assert ui.get_analysis() == 'energy' arf = ui.get_arf() rmf = ui.get_rmf() assert arf.energ_lo[0] == EMIN assert rmf.energ_lo[0] == EMIN assert rmf.e_min[0] == 0.0 ui.set_source(ui.powlaw1d.pl) ui.set_par('pl.ampl', 0.0003) stat = ui.calc_stat() # This check is purely a regression test, so the value has # not been externally validated. # assert_allclose(stat, 58.2813692358182) # Pick an energy range which isn't affected by the first # bin. # # Unfortunately, using a range of 0.3-8.0 gives 771 bins # in XSPEC - channels 30 to 800 - but 772 bins in Sherpa. # If I use ignore(None, 0.3); ignore(8.0, None) instead # then the result is 771 bins. This is because the e_min/max # of the RMF has channel widths of 0.01 keV, starting at 0, # so both 0.3 and 8.0 fall on a bin boundary. So, it's either # a difference in < or <= (or > vs >=), or a rounding issue # due to floating-point conversion leading to one bin boundary # being slightly different in Sherpa vs XSPEC). # # When using ui.notice(0.3, 8.0); ui.get_indep(filter=True) # returns 772 channels, 30 to 801. # # Using ui.notice(0.3, 7.995) selects channels 30 to 800. So # this range is used. Alternatively, channel 801 could have been # excluded explicitly. # # ui.notice(0.3, 8.0) ui.notice(0.3, 7.995) # XSPEC 12.9.1b calculation of the statistic: # chi sq = 203.88 from 771 bins with 769 dof # cstat = 568.52 # # There are known differences between XSPEC and Sherpa # with chi2xspecvar. This only affects data sets where # there is background subtraction, which is not the case # here. See https://github.com/sherpa/sherpa/issues/356 # ui.set_stat('chi2xspecvar') stat_xvar = ui.get_stat_info() assert len(stat_xvar) == 1 stat_xvar = stat_xvar[0] assert stat_xvar.numpoints == 771 assert stat_xvar.dof == 769 assert_allclose(stat_xvar.statval, 203.88, rtol=0, atol=0.005) ui.set_stat('cstat') stat_cstat = ui.get_stat_info() assert len(stat_cstat) == 1 stat_cstat = stat_cstat[0] assert stat_cstat.numpoints == 771 assert stat_cstat.dof == 769 assert_allclose(stat_cstat.statval, 568.52, rtol=0, atol=0.005) ui.clean()
def test_can_use_swift_data(make_data_path, clean_astro_ui): """A basic check that we can read in and use the Swift data. Unlike the previous tests, that directly access the io module, this uses the ui interface. """ # The Swift PHA file does not have the ANCRFILE/RESPFILE keywords # set up, so the responses have to be manually added. # ui.load_pha(make_data_path(PHAFILE)) rmffile = make_data_path(RMFFILE) with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") ui.load_rmf(rmffile) validate_replacement_warning(ws, 'RMF', rmffile) arffile = make_data_path(ARFFILE) with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") ui.load_arf(arffile) validate_replacement_warning(ws, 'ARF', arffile) assert ui.get_analysis() == 'energy' arf = ui.get_arf() rmf = ui.get_rmf() assert arf.energ_lo[0] == EMIN assert rmf.energ_lo[0] == EMIN assert rmf.e_min[0] == 0.0 ui.set_source(ui.powlaw1d.pl) ui.set_par('pl.ampl', 0.0003) stat = ui.calc_stat() # This check is purely a regression test, so the value has # not been externally validated. # assert_allclose(stat, 58.2813692358182) # Pick an energy range which isn't affected by the first # bin. # # Unfortunately, using a range of 0.3-8.0 gives 771 bins # in XSPEC - channels 30 to 800 - but 770 bins in Sherpa, # channels 31 to 800. # # Note that the channel numbering starts at 0: # % dmlist target_sr.pha header,clean,raw | grep TLMIN # TLMIN1 = 0 / Lowest legal channel number # # and so it's not clear when XSPEC says 30-800 what it # means. From https://github.com/sherpa/sherpa/issues/1211#issuecomment-881647128 # we have that the first bin it is using is # 0.29-0.30 # and the last bin is # 7.99-8.00 # and I've checked with iplot that it has renumbered the # channels to 1-1024 from 0-1023 # # % dmlist swxpc0to12s6_20130101v014.rmf.gz"[ebounds][channel=28:31]" data,clean # CHANNEL E_MIN E_MAX # 28 0.28000000119209 0.28999999165535 # 29 0.28999999165535 0.30000001192093 # 30 0.30000001192093 0.31000000238419 # 31 0.31000000238419 0.31999999284744 # % dmlist swxpc0to12s6_20130101v014.rmf.gz"[ebounds][channel=798:801]" data,clean # CHANNEL E_MIN E_MAX # 798 7.9800000191 7.9899997711 # 799 7.9899997711 8.0 # 800 8.0 8.0100002289 # 801 8.0100002289 8.0200004578 # # If I use ignore(None, 0.3); ignore(8.0, None) instead then the # result is 771 bins (channels 31 to 800). This is because the # e_min/max of the RMF has channel widths of 0.01 keV, starting at # 0, so both 0.3 and 8.0 fall on a bin boundary. So, it's either a # difference in < or <= (or > vs >=), or a rounding issue due to # floating-point conversion leading to one bin boundary being # slightly different in Sherpa vs XSPEC). # # When using ui.notice(0.3, 8.0); ui.get_indep(filter=True) # returns 770 channels, 31 to 800. # # Using ui.notice(0.3, 7.995) selects channels 31 to 800. # Using ui.notice(0.299, 8.0) selects channels 30 to 800. # Using ui.notice(0.299, 7.995) selects channels 30 to 800. # ui.notice(0.299, 8.0) # Check the selected range pha = ui.get_data() expected = np.zeros(1024, dtype=bool) expected[29:800] = True assert pha.mask == pytest.approx(expected) assert pha.get_mask() == pytest.approx(expected) # XSPEC 12.9.1b calculation of the statistic: # chi sq = 203.88 from 771 bins with 769 dof # cstat = 568.52 # # There are known differences between XSPEC and Sherpa # with chi2xspecvar. This only affects data sets where # there is background subtraction, which is not the case # here. See https://github.com/sherpa/sherpa/issues/356 # ui.set_stat('chi2xspecvar') stat_xvar = ui.get_stat_info() assert len(stat_xvar) == 1 stat_xvar = stat_xvar[0] assert stat_xvar.numpoints == 771 assert stat_xvar.dof == 769 assert_allclose(stat_xvar.statval, 203.88, rtol=0, atol=0.005) ui.set_stat('cstat') stat_cstat = ui.get_stat_info() assert len(stat_cstat) == 1 stat_cstat = stat_cstat[0] assert stat_cstat.numpoints == 771 assert stat_cstat.dof == 769 assert_allclose(stat_cstat.statval, 568.52, rtol=0, atol=0.005)
def test_load_multi_arfsrmfs(make_data_path, clean_astro_ui): """Added in #728 to ensure cache parameter is sent along by MultiResponseSumModel (fix #717). This has since been simplified to switch from xsapec to powlaw1d as it drops the need for XSPEC and is a simpler model, so is less affected by changes in the model code. A fit of the Sherpa powerlaw-model to 3c273.pi with a single response in CIAO 4.11 (background subtracted, 0.5-7 keV) returns gamma = 1.9298, ampl = 1.73862e-4 so doubling the response should halve the amplitude but leave the gamma value the same when using two responses, as below. This is with chi2datavar. """ pha_pi = make_data_path("3c273.pi") ui.load_pha(1, pha_pi) ui.load_pha(2, pha_pi) arf = make_data_path("3c273.arf") rmf = make_data_path("3c273.rmf") ui.load_multi_arfs(1, [arf, arf], [1, 2]) ui.load_multi_arfs(2, [arf, arf], [1, 2]) ui.load_multi_rmfs(1, [rmf, rmf], [1, 2]) ui.load_multi_rmfs(2, [rmf, rmf], [1, 2]) # Check multiple responses have been loaded # d1 = ui.get_data(1) d2 = ui.get_data(2) assert d1.response_ids == [1, 2] assert d2.response_ids == [1, 2] # Unfortunately we load the same response so it's hard # to tell the difference here! # assert ui.get_arf(resp_id=1).name == arf assert ui.get_arf(resp_id=2).name == arf assert ui.get_rmf(2, resp_id=1).name == rmf assert ui.get_rmf(2, resp_id=2).name == rmf ui.notice(0.5, 7) ui.subtract(1) ui.subtract(2) src = ui.create_model_component('powlaw1d', 'src') ui.set_model(1, src) ui.set_model(2, src) # ensure the test is repeatable by running with a known # statistic and method # ui.set_method('levmar') ui.set_stat('chi2datavar') # Really what we care about for fixing #717 is that # fit does not error out, but it's useful to know that # the fit has changed the parameter values (which were # both 1 before the fit). # ui.fit() fr = ui.get_fit_results() assert fr.succeeded assert fr.datasets == (1, 2) assert src.gamma.val == pytest.approx(1.9298, rel=1.0e-4) assert src.ampl.val == pytest.approx(1.73862e-4 / 2, rel=1.0e-4)
def test_fake_pha_issue_1209(make_data_path, clean_astro_ui, tmp_path): """Check issue #1209. See also sherpa/astro/tests/test_fake_pha.py for test_fake_pha_has_valid_ogip_keywords_all_fake test_fake_pha_has_valid_ogip_keywords_from_real The session fake_pha includes quite a lot of logic which makes that the test case for #1209 should be done at this level, to complement the tests mentioned above. """ infile = make_data_path("acisf01575_001N001_r0085_pha3.fits.gz") ui.load_pha(infile) ui.set_source(ui.powlaw1d.pl) pl.gamma = 1.8 pl.ampl = 1e-4 arf = ui.get_arf() rmf = ui.get_rmf() # check the TOTCTS setting in the input file d1 = ui.get_data() assert d1.header["TOTCTS"] == 855 assert d1.counts.sum() == 855 ui.set_source("newid", pl) ui.fake_pha("newid", exposure=ui.get_exposure(), bkg=ui.get_bkg(), rmf=rmf, arf=arf, backscal=ui.get_backscal()) stat = ui.calc_stat("newid") outfile = tmp_path / "sim.pha" ui.save_pha("newid", str(outfile)) ui.load_pha(3, str(outfile)) d3 = ui.get_data(3) assert isinstance(d3, ui.DataPHA) assert d3.exposure == pytest.approx(37664.157219191) assert d3.areascal == pytest.approx(1.0) assert d3.backscal == pytest.approx(2.2426552620567e-06) assert d3.background_ids == [] assert d3.response_ids == [] # check the header hdr = d3.header assert hdr["TELESCOP"] == "CHANDRA" assert hdr["INSTRUME"] == "ACIS" assert hdr["FILTER"] == "none" # check some other values related to #1209 and #488 (OGIP) # assert "TOTCTS" not in hdr assert hdr["GROUPING"] == 0 assert hdr["QUALITY"] == 0 assert hdr["SYS_ERR"] == 0 # We should get the same value - the responses are not written # to the temporary directory and so we need to load them # directly. # ui.set_rmf(3, rmf) ui.set_arf(3, arf) ui.set_source(3, pl) assert ui.calc_stat(3) == pytest.approx(stat)
def test_can_use_swift_data(make_data_path): """A basic check that we can read in and use the Swift data. Unlike the previous tests, that directly access the io module, this uses the ui interface. """ # QUS are there pytest fixtures that ensure the state is # clean on entry and exit? ui.clean() # The Swift PHA file does not have the ANCRFILE/RESPFILE keywords # set up, so the responses have to be manually added. # ui.load_pha(make_data_path(PHAFILE)) ui.load_rmf(make_data_path(RMFFILE)) ui.load_arf(make_data_path(ARFFILE)) assert ui.get_analysis() == 'energy' ui.set_source(ui.powlaw1d.pl) ui.set_par('pl.ampl', 0.0003) # The responses have the first bin start at an energy of 0, # which causes issues for Sherpa. There should be a # RuntimeWarning due to a divide by zero. # with pytest.warns(RuntimeWarning) as record: stat = ui.calc_stat() # The exact form of the message depends on the Python version; # this could be checked, but it feels excessive for this # particular test, which is just a regression check, so use a # more lax approach. # assert len(record) == 1 assert record[0].message.args[0] in \ ['divide by zero encountered in divide', 'divide by zero encountered in true_divide'] # The stat value depends on what power-law model is used. With # xspowerlaw it is NaN, but with powlaw1d it is finite. # # This check is purely a regression test, so the value has # not been externally validated. # # assert np.isnan(stat) assert_allclose(stat, 58.2813692358182) # Manually adjust the first bin to avoid this problem. # Add in asserts just in case this gets "fixed" in the # I/O layer (as XSPEC does). # arf = ui.get_arf() rmf = ui.get_rmf() assert arf.energ_lo[0] == 0.0 assert rmf.energ_lo[0] == 0.0 assert rmf.e_min[0] == 0.0 # The bin widths are ~ 0.005 or ~ 0.01 keV, so pick a value # smaller than this. # ethresh = 1e-6 arf.energ_lo[0] = ethresh rmf.energ_lo[0] = ethresh rmf.e_min[0] = ethresh # Pick an energy range which isn't affected by the first # bin. # # Unfortunately, using a range of 0.3-8.0 gives 771 bins # in XSPEC - channels 30 to 800 - but 772 bins in Sherpa. # If I use ignore(None, 0.3); ignore(8.0, None) instead # then the result is 771 bins. This is because the e_min/max # of the RMF has channel widths of 0.01 keV, starting at 0, # so both 0.3 and 8.0 fall on a bin boundary. So, it's either # a difference in < or <= (or > vs >=), or a rounding issue # due to floating-point conversion leading to one bin boundary # being slightly different in Sherpa vs XSPEC). # # When using ui.notice(0.3, 8.0); ui.get_indep(filter=True) # returns 772 channels, 30 to 801. # # Using ui.notice(0.3, 7.995) selects channels 30 to 800. So # this range is used. Alternatively, channel 801 could have been # excluded explicitly. # # ui.notice(0.3, 8.0) ui.notice(0.3, 7.995) # XSPEC 12.9.1b calculation of the statistic: # chi sq = 203.88 from 771 bins with 769 dof # cstat = 568.52 # # There are known differences between XSPEC and Sherpa # with chi2xspecvar. This only affects data sets where # there is background subtraction, which is not the case # here. See https://github.com/sherpa/sherpa/issues/356 # ui.set_stat('chi2xspecvar') stat_xvar = ui.get_stat_info() assert len(stat_xvar) == 1 stat_xvar = stat_xvar[0] assert stat_xvar.numpoints == 771 assert stat_xvar.dof == 769 assert_allclose(stat_xvar.statval, 203.88, rtol=0, atol=0.005) ui.set_stat('cstat') stat_cstat = ui.get_stat_info() assert len(stat_cstat) == 1 stat_cstat = stat_cstat[0] assert stat_cstat.numpoints == 771 assert stat_cstat.dof == 769 assert_allclose(stat_cstat.statval, 568.52, rtol=0, atol=0.005) ui.clean()
nargs='+', type=str, help="Spectra files (*.pi, *.pha)") args = parser.parse_args() from sherpa.astro.ui import load_pha, get_rmf, get_arf, get_fit_plot, load_table_model, set_xsabund, set_xsxsect, ignore, notice, set_xlog, set_ylog from sherpa.astro.ui import xsapec, set_full_model, get_bkg_model, get_bkg_scale, set_stat, get_bkg, group_adapt, set_analysis, calc_stat, get_data, set_model, get_response, get_model, calc_energy_flux id = 1 filename = args.filenames[0] elo, ehi = args.energyrange.split(':') elo, ehi = float(elo), float(ehi) load_pha(id, filename) try: assert get_rmf(id).energ_lo[0] > 0 assert get_arf(id).energ_lo[0] > 0 assert (get_bkg(id).counts > 0).sum() > 0 except: traceback.print_exc() sys.exit(0) set_xlog() set_ylog() set_stat('cstat') set_xsabund('wilm') set_xsxsect('vern') set_analysis(id, 'ener', 'counts') ignore(None, elo) ignore(ehi, None) notice(elo, ehi)
import datastack from acis_bkg_model import acis_bkg_model import sherpa.astro.ui as ui ds = datastack.DataStack() ds[1].load_pha("acisf04938_000N002_r0043_pha3.fits") ds[2].load_pha("acisf07867_000N001_r0002_pha3.fits") detnam = "acis2i" for dataset in ds.datasets: id_ = dataset["id"] rmf = ui.get_rmf(id_) arf = ui.get_arf(id_) ui.load_bkg_arf(id_, arf.name) bkg_arf = ui.get_bkg_arf(id_) bkg_rmf = ui.get_bkg_rmf(id_) bkg_arf.specresp = bkg_arf.specresp * 0 + 100.0 bkg_scale = ui.get_data(id_).sum_background_data(lambda x, y: 1) bkg_model = bkg_rmf(bkg_arf(ui.const1d.bkg_constID * acis_bkg_model(detnam))) src_model = rmf(arf(ui.const1d.src_constID * ui.powlaw1d.powlaw)) ds[id_].set_full_model(src_model + bkg_scale * bkg_model) ds[id_].set_bkg_full_model(bkg_model) ds[1].set_par("src_const.c0", 1.0) ds[1].freeze("src_const") ds.ignore(None, 0.5) ds.ignore(7, None) ds.fit()
def test_can_use_swift_data(make_data_path): """A basic check that we can read in and use the Swift data. Unlike the previous tests, that directly access the io module, this uses the ui interface. """ # QUS are there pytest fixtures that ensure the state is # clean on entry and exit? ui.clean() # The Swift PHA file does not have the ANCRFILE/RESPFILE keywords # set up, so the responses have to be manually added. # ui.load_pha(make_data_path(PHAFILE)) rmffile = make_data_path(RMFFILE) with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") ui.load_rmf(rmffile) validate_replacement_warning(ws, 'RMF', rmffile) arffile = make_data_path(ARFFILE) with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") ui.load_arf(arffile) validate_replacement_warning(ws, 'ARF', arffile) assert ui.get_analysis() == 'energy' arf = ui.get_arf() rmf = ui.get_rmf() assert arf.energ_lo[0] == EMIN assert rmf.energ_lo[0] == EMIN assert rmf.e_min[0] == 0.0 ui.set_source(ui.powlaw1d.pl) ui.set_par('pl.ampl', 0.0003) stat = ui.calc_stat() # This check is purely a regression test, so the value has # not been externally validated. # assert_allclose(stat, 58.2813692358182) # Pick an energy range which isn't affected by the first # bin. # # Unfortunately, using a range of 0.3-8.0 gives 771 bins # in XSPEC - channels 30 to 800 - but 772 bins in Sherpa. # If I use ignore(None, 0.3); ignore(8.0, None) instead # then the result is 771 bins. This is because the e_min/max # of the RMF has channel widths of 0.01 keV, starting at 0, # so both 0.3 and 8.0 fall on a bin boundary. So, it's either # a difference in < or <= (or > vs >=), or a rounding issue # due to floating-point conversion leading to one bin boundary # being slightly different in Sherpa vs XSPEC). # # When using ui.notice(0.3, 8.0); ui.get_indep(filter=True) # returns 772 channels, 30 to 801. # # Using ui.notice(0.3, 7.995) selects channels 30 to 800. So # this range is used. Alternatively, channel 801 could have been # excluded explicitly. # # ui.notice(0.3, 8.0) ui.notice(0.3, 7.995) # XSPEC 12.9.1b calculation of the statistic: # chi sq = 203.88 from 771 bins with 769 dof # cstat = 568.52 # # There are known differences between XSPEC and Sherpa # with chi2xspecvar. This only affects data sets where # there is background subtraction, which is not the case # here. See https://github.com/sherpa/sherpa/issues/356 # ui.set_stat('chi2xspecvar') stat_xvar = ui.get_stat_info() assert len(stat_xvar) == 1 stat_xvar = stat_xvar[0] assert stat_xvar.numpoints == 771 assert stat_xvar.dof == 769 assert_allclose(stat_xvar.statval, 203.88, rtol=0, atol=0.005) ui.set_stat('cstat') stat_cstat = ui.get_stat_info() assert len(stat_cstat) == 1 stat_cstat = stat_cstat[0] assert stat_cstat.numpoints == 771 assert stat_cstat.dof == 769 assert_allclose(stat_cstat.statval, 568.52, rtol=0, atol=0.005) ui.clean()