def test_rmf1d_delta_no_pha_zero_energy_bin(): "What happens when the first bin starts at 0, no replacement" ethresh = None egrid = np.asarray([0.0, 0.1, 0.2, 0.4, 0.5, 0.7, 0.8]) elo = egrid[:-1] ehi = egrid[1:] with pytest.raises(DataErr) as exc: create_delta_rmf(elo, ehi, ethresh=ethresh) emsg = "The RMF 'delta-rmf' has an ENERG_LO value <= 0" assert str(exc.value) == emsg
def test_save_source_pha_fits(clean_astro_ui, tmp_path): """Can we write out data for save_source? DataPHA and FITS """ from sherpa.astro.io import read_table_blocks ui.load_arrays(1, [1, 2], [5, 10], ui.DataPHA) # we need a response egrid = np.asarray([0.1, 0.2, 0.4]) elo = egrid[:-1] ehi = egrid[1:] rmf = create_delta_rmf(elo, ehi, e_min=elo, e_max=ehi) ui.set_rmf(rmf) yarf = np.asarray([10, 20]) arf = create_arf(elo, ehi, yarf) ui.set_arf(arf) ui.set_source(ui.const1d.cmdl) cmdl.c0 = 2 out = tmp_path / 'model.dat' outfile = str(out) ui.save_source(outfile) ans = read_table_blocks(outfile) blocks = ans[1] assert len(blocks) == 2 check_table(blocks[2], { 'XLO': [0.1, 0.2], 'XHI': [0.2, 0.4], 'SOURCE': [2, 2] })
def test_save_model_pha_ascii(clean_astro_ui, tmp_path): """Can we write out data for save_model? DataPHA and ASCII""" ui.load_arrays(1, [1, 2], [5, 10], ui.DataPHA) # we need a response egrid = np.asarray([0.1, 0.2, 0.4]) elo = egrid[:-1] ehi = egrid[1:] rmf = create_delta_rmf(elo, ehi, e_min=elo, e_max=ehi) ui.set_rmf(rmf) yarf = np.asarray([10, 20]) arf = create_arf(elo, ehi, yarf) ui.set_arf(arf) ui.set_source(ui.const1d.cmdl) cmdl.c0 = 2 out = tmp_path / 'model.dat' ui.save_model(str(out), ascii=True) cts = out.read_text() check_output(cts, ['XLO', 'XHI', 'MODEL'], [[0.1, 0.2, 20], [0.2, 0.4, 40]])
def test_save_resid_datapha_fits(tmp_path): """Residual, DataPHA, FITS""" from sherpa.astro.io import read_table_blocks ui.load_arrays(1, [1, 2], [5, 10], ui.DataPHA) # we need a response egrid = np.asarray([0.1, 0.2, 0.4]) elo = egrid[:-1] ehi = egrid[1:] rmf = create_delta_rmf(elo, ehi, e_min=elo, e_max=ehi) ui.set_rmf(rmf) yarf = np.asarray([10, 20]) arf = create_arf(elo, ehi, yarf) ui.set_arf(arf) ui.set_source(ui.const1d.cmdl) cmdl.c0 = 2 out = tmp_path / 'resid.out' outfile = str(out) ui.save_resid(outfile) ans = read_table_blocks(outfile) blocks = ans[1] assert len(blocks) == 2 check_table(blocks[2], {'X': [0.15, 0.3], 'RESID': [30, 10]})
def test_save_resid_datapha(tmp_path): """Residual, DataPHA, ASCII""" ui.load_arrays(1, [1, 2], [5, 10], ui.DataPHA) # we need a response egrid = np.asarray([0.1, 0.2, 0.4]) elo = egrid[:-1] ehi = egrid[1:] rmf = create_delta_rmf(elo, ehi, e_min=elo, e_max=ehi) ui.set_rmf(rmf) yarf = np.asarray([10, 20]) arf = create_arf(elo, ehi, yarf) ui.set_arf(arf) ui.set_source(ui.const1d.cmdl) cmdl.c0 = 2 out = tmp_path / 'resid.out' outfile = str(out) ui.save_resid(outfile, ascii=True) cts = out.read_text() check_output(cts, ['X', 'RESID'], [[0.15, 30], [0.3, 10]])
def test_cstat_rsppha(): """What does CSTAT calculate when there is an RSP+PHA instrument model. This includes the AREASCAL when evaluating the model. See Also -------- test_cstat_nophamodel, test_cstat_arfpha, test_cstat_rmfpha """ dset, mdl, expected = setup_likelihood(scale=True) # use the full channel grid; the energy grid has to be # "the same" as the channel values since the model # has a dependency on the independent axis # egrid = 1.0 * np.concatenate((dset.channel, [dset.channel.max() + 1])) arf = create_arf(egrid[:-1], egrid[1:]) rmf = create_delta_rmf(egrid[:-1], egrid[1:]) mdl_ascal = RSPModelPHA(arf, rmf, dset, mdl) stat = CStat() sval_ascal = stat.calc_stat(dset, mdl_ascal) assert sval_ascal[0] == pytest.approx(expected)
def test_pha_get_xerr_all_bad_energy_group(): """get_xerr handles all bad values [energy] The behavior with grouping is different, presumably because we assume we have grouping when we have a quality array. """ pha = DataPHA('name', [1, 2, 3], [1, 1, 1], grouping=[1, 1, 1], quality=[2, 2, 2]) ebins = np.asarray([3.0, 5., 8.0, 12.0]) rlo = ebins[:-1] rhi = ebins[1:] rmf = create_delta_rmf(rlo, rhi, e_min=rlo, e_max=rhi) pha.set_rmf(rmf) pha.units = 'energy' assert pha.get_xerr() == pytest.approx([2.0, 3.0, 4.0]) assert pha.grouped pha.ignore_bad() # Should this error out or not? assert pha.get_filter() == '' # with pytest.raises(DataErr) as de: # pha.get_filter() # assert str(de.value) == 'mask excludes all data' assert pha.get_xerr() == pytest.approx([])
def test_rmf1d_delta_no_pha_zero_energy_bin_replace(): "What happens when the first bin starts at 0, with replacement" ethresh = 1e-8 egrid = np.asarray([0.0, 0.1, 0.2, 0.4, 0.5, 0.7, 0.8]) elo = egrid[:-1] ehi = egrid[1:] with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") rdata = create_delta_rmf(elo, ehi, ethresh=ethresh) validate_zero_replacement(ws, 'RMF', 'delta-rmf', ethresh) rmf = RMF1D(rdata) mdl = MyPowLaw1D() tmdl = PowLaw1D() wrapped = rmf(mdl) out = wrapped([0.1, 0.2]) elo[0] = ethresh expected = tmdl(elo, ehi) assert_allclose(out, expected) assert not np.isnan(out[0])
def test_rspmodelnopha_delta_call(): "What happens calling an RMF (delta)+ARF with no pha?" exposure = 200.1 egrid = np.arange(0.01, 0.06, 0.01) elo = egrid[:-1] ehi = egrid[1:] specresp = np.asarray([1.2, 0.0, 0.5, 4.3]) rdata = create_delta_rmf(elo, ehi) adata = create_arf(elo, ehi, specresp, exposure=exposure) constant = 2.3 mdl = Const1D('flat') mdl.c0 = constant wrapped = RSPModelNoPHA(adata, rdata, mdl) # The model is evaluated on the RMF grid, not whatever # is sent in. It is also integrated across the bins, # which is why there is a multiplication by the # grid width (for this constant model). # de = egrid[1:] - egrid[:-1] expected = constant * specresp * de out = wrapped([4, 5]) assert_allclose(out, expected)
def test_rmfmodelpha_delta_no_ebounds(analysis, caplog): """What happens calling an rmf with a pha and no EBOUNDS is set Ensure we can't filter on energy or wavelength since there's no EBOUNDS information. This behavior was seen when writing test_rmfmodelpha_call, so a test was written for it. The code used to raise a DataErr but now just displays a logged warning. """ estep = 0.01 egrid = np.arange(0.01, 0.06, estep) rdata = create_delta_rmf(egrid[:-1], egrid[1:]) channels = np.arange(1, 5, dtype=np.int16) counts = np.asarray([10, 5, 12, 7], dtype=np.int16) pha = DataPHA('test-pha', channel=channels, counts=counts) pha.set_rmf(rdata) pha.set_analysis(analysis) with caplog.at_level(logging.INFO, logger='sherpa'): pha.notice(0.025, 0.045, ignore=False) assert len(caplog.records) == 1 log_name, log_level, message = caplog.record_tuples[0] assert log_name == 'sherpa.astro.data' assert log_level == logging.INFO assert message == 'Skipping dataset test-pha: RMF does not specify energy bins'
def example_pha_data(): """Create an example data set.""" etime = 1201.0 d = DataPHA('example', _data_chan.copy(), _data_counts.copy(), exposure=etime, backscal=0.2) a = DataARF('example-arf', _energies_lo.copy(), _energies_hi.copy(), _arf.copy(), exposure=etime) r = create_delta_rmf(_energies_lo.copy(), _energies_hi.copy(), e_min=_energies_lo.copy(), e_max=_energies_hi.copy(), offset=1, name='example-rmf') d.set_arf(a) d.set_rmf(r) return d
def test_288_a_energy(): """The issue from #288 which was working test_288_a but with a response so we test energy filters """ channels = np.arange(1, 6) counts = np.asarray([5, 5, 10, 10, 2]) grouping = np.asarray([1, -1, 1, -1, 1], dtype=np.int16) pha = DataPHA('x', channels, counts, grouping=grouping) rlo = channels rhi = channels + 1 rmf = create_delta_rmf(rlo, rhi, e_min=rlo, e_max=rhi) pha.set_arf(rmf) pha.set_analysis('energy') assert pha.mask pha.ignore(3, 4) # I use approx because it gives a nice answer, even though # I want equality not approximation in this test. Fortunately # with bools the use of approx is okay (it can tell the # difference between 0 and 1, aka False and True). # assert pha.mask == pytest.approx([True, False, True])
def test_rmf(header, override_plot_backend): ebins = np.arange(0.1, 1, 0.1) elo, ehi = ebins[:-1], ebins[1:] d = create_delta_rmf(elo, ehi, header=header) r = d._repr_html_() nmeta = 0 if (header is None) or (header == {}) else 4 check(r, 'RMF', 'delta-rmf', 'MATRIX', nmeta=nmeta)
def test_rspmodelpha_delta_call(ignore): """What happens calling a rsp with a pha (RMF is a delta fn)? The ignore value gives the channel to ignore (counting from 0). """ exposure = 200.1 estep = 0.025 egrid = np.arange(0.1, 0.8, estep) elo = egrid[:-1] ehi = egrid[1:] specresp = 2.4 * np.ones(elo.size, dtype=np.float32) specresp[2:5] = 0.0 specresp[16:19] = 3.2 adata = create_arf(elo, ehi, specresp, exposure=exposure) rdata = create_delta_rmf(elo, ehi, e_min=elo, e_max=ehi) nchans = elo.size constant = 2.3 mdl = Const1D('flat') mdl.c0 = constant channels = np.arange(1, nchans + 1, dtype=np.int16) counts = np.ones(nchans, dtype=np.int16) pha = DataPHA('test-pha', channel=channels, counts=counts, exposure=exposure) pha.set_rmf(rdata) # force energy units (only needed if ignore is set) pha.set_analysis('energy') if ignore is not None: de = estep * 0.9 e0 = egrid[ignore] pha.notice(lo=e0, hi=e0 + de, ignore=True) # The assert are intended to help people reading this # code rather than being a useful check that the code # is working. mask = [True] * nchans mask[ignore] = False assert (pha.mask == mask).all() wrapped = RSPModelPHA(adata, rdata, pha, mdl) # The model is evaluated on the RMF grid, not whatever # is sent in. It is also integrated across the bins, # which is why there is a multiplication by the # grid width (for this constant model). # # Note that the filter doesn't change the grid. # de = egrid[1:] - egrid[:-1] expected = constant * specresp * de out = wrapped([4, 5]) assert_allclose(out, expected)
def test_416_c(): """The third test case from issue #416 This used to use channels but it has been changed to add an RMF so we can filter in energy space, as it is not clear what non-integer channels should mean. """ x = np.asarray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) y = np.asarray([0, 0, 0, 2, 1, 1, 0, 0, 0, 0]) pha = DataPHA('416', x, y) rmf = create_delta_rmf(x, x + 1, e_min=x, e_max=x + 1, name='416') pha.set_arf(rmf) pha.set_analysis('energy') # When using channels this used notice(3.5, 6.5) # but using energy space we need to use a different # range to match the ones the original channel filter # used. # pha.notice(4.5, 6.5) # this should be ~pha.mask tabstops = [True] * 3 + [False] * 3 + [True] * 4 assert ~pha.mask == pytest.approx(tabstops) pha.group_counts(3, tabStops=~pha.mask) pha.ignore_bad() grouping = [0] * 3 + [1, -1, 1] + [0] * 4 assert pha.grouping == pytest.approx(grouping) # the second grouped bin has a quality of 2 as # it only contains 1 count quality = np.zeros(10, dtype=int) quality[5] = 2 assert pha.quality == pytest.approx(quality) dep = pha.get_dep(filter=False) assert dep == pytest.approx(y) # It is not at all obvious why we get 8 bins returned # here. The ignore_bad has removed any existing # filters, but why do we get 8, not 10, values? # Well, one bin has been removed (quality=2) # and two bins have merged into 1. Hence the 8. # dep = pha.get_dep(filter=True) exp = np.zeros(8) exp[3] = 3 assert dep == pytest.approx(exp)
def test_rsp1d_delta_pha_zero_energy_bin(): "What happens when the first bin starts at 0, with replacement" ethresh = 2.0e-7 # PHA and ARF have different exposure ties exposure1 = 0.1 exposure2 = 2.4 egrid = np.asarray([0.0, 0.1, 0.2, 0.4, 0.5, 0.7, 0.8]) elo = egrid[:-1] ehi = egrid[1:] specresp = np.asarray([10.2, 9.8, 10.0, 12.0, 8.0, 10.0]) with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") adata = create_arf(elo, ehi, specresp, exposure=exposure1, ethresh=ethresh) validate_zero_replacement(ws, 'ARF', 'user-arf', ethresh) with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") rdata = create_delta_rmf(elo, ehi, ethresh=ethresh) validate_zero_replacement(ws, 'RMF', 'delta-rmf', ethresh) channels = np.arange(1, 7, dtype=np.int16) counts = np.ones(6, dtype=np.int16) pha = DataPHA('test-pha', channel=channels, counts=counts, exposure=exposure2) pha.set_rmf(rdata) pha.set_arf(adata) pha.set_analysis('energy') mdl = MyPowLaw1D() tmdl = PowLaw1D() wrapped = RSPModelPHA(adata, rdata, pha, mdl) out = wrapped([0.1, 0.2]) elo[0] = ethresh expected = specresp * tmdl(elo, ehi) assert_allclose(out, expected) assert not np.isnan(out[0])
def test_416_b(caplog): """The second test case from issue #416 This is to make sure this hasn't changed. This used to use channels but it has been changed to add an RMF so we can filter in energy space, as it is not clear what non-integer channels should mean. """ x = np.asarray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) y = np.asarray([0, 0, 0, 2, 1, 1, 0, 0, 0, 0]) pha = DataPHA('416', x, y) rmf = create_delta_rmf(x, x + 1, e_min=x, e_max=x + 1, name='416') pha.set_arf(rmf) pha.set_analysis('energy') pha.notice(3.5, 6.5) pha.group_counts(3) with caplog.at_level(logging.INFO, logger='sherpa'): pha.ignore_bad() # It's not obvious why this has switched to a boolean assert pha.mask # Mask is also interesting (currently just reporting # this behavior) mask = [True] * 5 + [False] * 5 assert pha.get_mask() == pytest.approx(mask) grouping = [1, -1, -1, -1, -1, 1, -1, -1, -1, -1.] assert pha.grouping == pytest.approx(grouping) quality = [0, 0, 0, 0, 0, 2, 2, 2, 2, 2] assert pha.quality == pytest.approx(quality) dep = pha.get_dep(filter=True) assert dep == pytest.approx([3]) # check captured log # emsg = 'filtering grouped data with quality flags, previous filters deleted' assert caplog.record_tuples == [ ('sherpa.astro.data', logging.WARNING, emsg) ]
def test_rmf1d_simple_no_pha_call(): "Can we call an RMF (delta function) with no PHA" egrid = np.arange(0.1, 0.6, 0.1) rdata = create_delta_rmf(egrid[:-1], egrid[1:]) rmf = RMF1D(rdata) mdl = Const1D('flat') mdl.c0 = 2.3 wrapped = rmf(mdl) assert isinstance(wrapped, RMFModelNoPHA) wmdl = wrapped.model assert wmdl == mdl
def test_416_a(): """The first test case from issue #416 This used to use channels but it has been changed to add an RMF so we can filter in energy space, as it is not clear what non-integer channels should mean. """ # if y is not a numpy array then group_counts errors out # with a strange error. Another reason why DataPHA needs # to validate input # x = np.asarray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) y = np.asarray([0, 0, 0, 2, 1, 1, 0, 0, 0, 0]) pha = DataPHA('416', x, y) rmf = create_delta_rmf(x, x + 1, e_min=x, e_max=x + 1, name='416') pha.set_arf(rmf) pha.set_analysis('energy') pha.notice(4.5, 6.5) mask = [False, False, False, True, True, True, False, False, False, False] assert pha.mask == pytest.approx(mask) pha.group_counts(3) # We have a simplified mask mask = [True, True] assert pha.mask == pytest.approx(mask) # the "full" mask can be retrieved with get_mask mask = [True] * 10 assert pha.get_mask() == pytest.approx(mask) grouping = [1, -1, -1, -1, -1, 1, -1, -1, -1, -1.] assert pha.grouping == pytest.approx(grouping) quality = [0, 0, 0, 0, 0, 2, 2, 2, 2, 2] assert pha.quality == pytest.approx(quality) dep = pha.get_dep(filter=True) assert dep == pytest.approx([3, 1])
def test_rspmodelpha_delta_call_wave(): """What happens calling a rsp with a pha (RMF is a delta fn)? Wavelength. Unlike the energy case no bins are ignored, as this code path has already been tested. """ exposure = 200.1 estep = 0.025 egrid = np.arange(0.1, 0.8, estep) elo = egrid[:-1] ehi = egrid[1:] specresp = 2.4 * np.ones(elo.size, dtype=np.float32) specresp[2:5] = 0.0 specresp[16:19] = 3.2 adata = create_arf(elo, ehi, specresp, exposure=exposure) rdata = create_delta_rmf(elo, ehi, e_min=elo, e_max=ehi) nchans = elo.size constant = 2.3 mdl = Const1D('flat') mdl.c0 = constant channels = np.arange(1, nchans + 1, dtype=np.int16) counts = np.ones(nchans, dtype=np.int16) pha = DataPHA('test-pha', channel=channels, counts=counts, exposure=exposure) pha.set_rmf(rdata) pha.set_analysis('wave') wrapped = RSPModelPHA(adata, rdata, pha, mdl) # Note that this is a Sherpa model, so it's normalization is # per unit x axis, so when integrated here the bins are in # Angstroms, so the bin width to multiply by is # Angstroms, not keV. # dl = (DataPHA._hc / elo) - (DataPHA._hc / ehi) expected = constant * specresp * dl out = wrapped([4, 5]) assert_allclose(out, expected)
def test_rspmodelpha_delta_call_channel(): """What happens calling a rsp with a pha (RMF is a delta fn)? Channels. I am not convinced I understand the bin width calculation here, as it doesn't seem to match the wavelength case. """ exposure = 200.1 estep = 0.025 egrid = np.arange(0.1, 0.8, estep) elo = egrid[:-1] ehi = egrid[1:] specresp = 2.4 * np.ones(elo.size, dtype=np.float32) specresp[2:5] = 0.0 specresp[16:19] = 3.2 adata = create_arf(elo, ehi, specresp, exposure=exposure) rdata = create_delta_rmf(elo, ehi, e_min=elo, e_max=ehi) nchans = elo.size constant = 2.3 mdl = Const1D('flat') mdl.c0 = constant channels = np.arange(1, nchans + 1, dtype=np.int16) counts = np.ones(nchans, dtype=np.int16) pha = DataPHA('test-pha', channel=channels, counts=counts, exposure=exposure) pha.set_rmf(rdata) pha.set_analysis('channel') wrapped = RSPModelPHA(adata, rdata, pha, mdl) # Since this is channels you might expect the bin width to be 1, # but it is actually still dE. # de = ehi - elo expected = constant * specresp * de out = wrapped([4, 5]) assert_allclose(out, expected)
def test_pha_get_xerr_all_bad_energy_no_group(): """get_xerr handles all bad values [energy] It's not obvious what it is meant to be doing here. """ pha = DataPHA('name', [1, 2, 3], [1, 1, 1], quality=[2, 2, 2]) ebins = np.asarray([3.0, 5., 8.0, 12.0]) rlo = ebins[:-1] rhi = ebins[1:] rmf = create_delta_rmf(rlo, rhi, e_min=rlo, e_max=rhi) pha.set_rmf(rmf) pha.units = 'energy' assert pha.get_xerr() == pytest.approx([2.0, 3.0, 4.0]) pha.ignore_bad() assert pha.get_filter() == '' assert pha.get_xerr() == pytest.approx([2.0, 3.0, 4.0])
def test_288_b_energy(): """The issue from #288 which was failing test_288_b but with a response so we test energy filters """ channels = np.arange(1, 6) counts = np.asarray([5, 5, 10, 10, 2]) grouping = np.asarray([1, -1, 1, -1, 1], dtype=np.int16) pha = DataPHA('x', channels, counts, grouping=grouping) rlo = channels rhi = channels + 1 rmf = create_delta_rmf(rlo, rhi, e_min=rlo, e_max=rhi) pha.set_arf(rmf) pha.set_analysis('energy') assert pha.mask pha.ignore(3.1, 4) assert pha.mask == pytest.approx([True, False, True])
def test_rmfmodelnopha_delta_call(): "What happens calling an rmf (delta function) with no pha?" egrid = np.arange(0.01, 0.06, 0.01) rdata = create_delta_rmf(egrid[:-1], egrid[1:]) constant = 2.3 mdl = Const1D('flat') mdl.c0 = constant wrapped = RMFModelNoPHA(rdata, mdl) # The model is evaluated on the RMF grid, not whatever # is sent in. It is also integrated across the bins, # which is why there is a multiplication by the # grid width (for this constant model). # de = egrid[1:] - egrid[:-1] expected = constant * de out = wrapped([4, 5]) assert_allclose(out, expected)
def test_rmfmodelpha_delta_no_ebounds(analysis): """What happens calling an rmf with a pha and no EBOUNDS is set Ensure we can't filter on energy or wavelength since there's no EBOUNDS information. This behavior was seen when writing test_rmfmodelpha_call, so a test was written for it. """ estep = 0.01 egrid = np.arange(0.01, 0.06, estep) rdata = create_delta_rmf(egrid[:-1], egrid[1:]) channels = np.arange(1, 5, dtype=np.int16) counts = np.asarray([10, 5, 12, 7], dtype=np.int16) pha = DataPHA('test-pha', channel=channels, counts=counts) pha.set_rmf(rdata) pha.set_analysis(analysis) with pytest.raises(DataErr) as exc: pha.notice(0.025, 0.045, ignore=False) assert str(exc.value) == 'RMF does not specify energy bins'
def test_rmf1d_no_pha_delta(): "Can we create an RMF (delta function) with no PHA?" egrid = np.arange(0.1, 0.6, 0.1) rdata = create_delta_rmf(egrid[:-1], egrid[1:]) rmf = RMF1D(rdata) assert rmf._rmf == rdata assert rmf._pha is None # Does the RMF1D pass through functionality to the DataRMF? assert rmf.name == 'delta-rmf' assert str(rmf) == str(rdata) assert dir(rmf) == dir(rdata) matrix = np.ones(egrid.size - 1, dtype=np.float32) assert (matrix == rmf.matrix).all() # Unlike the ARF, the RMF doesn't have an exposure field with pytest.raises(AttributeError): rmf.exposure
def test_rsp1d_delta_no_pha_zero_energy_bin(): "What happens when the first bin starts at 0, with replacement" ethresh = 1.0e-9 exposure = 0.1 egrid = np.asarray([0.0, 0.1, 0.2, 0.4, 0.5, 0.7, 0.8]) elo = egrid[:-1] ehi = egrid[1:] specresp = np.asarray([10.2, 9.8, 10.0, 12.0, 8.0, 10.0]) with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") adata = create_arf(elo, ehi, specresp, exposure=exposure, ethresh=ethresh) validate_zero_replacement(ws, 'ARF', 'user-arf', ethresh) with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") rdata = create_delta_rmf(elo, ehi, ethresh=ethresh) validate_zero_replacement(ws, 'RMF', 'delta-rmf', ethresh) mdl = MyPowLaw1D() tmdl = PowLaw1D() wrapped = RSPModelNoPHA(adata, rdata, mdl) out = wrapped([0.1, 0.2]) elo[0] = ethresh expected = specresp * tmdl(elo, ehi) assert_allclose(out, expected) assert not np.isnan(out[0])
def test_rmf1d_delta_pha_zero_energy_bin(): "What happens when the first bin starts at 0, with replacement" ethresh = 2e-7 egrid = np.asarray([0.0, 0.1, 0.2, 0.4, 0.5, 0.7, 0.8]) elo = egrid[:-1] ehi = egrid[1:] with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") rdata = create_delta_rmf(elo, ehi, ethresh=ethresh) validate_zero_replacement(ws, 'RMF', 'delta-rmf', ethresh) exposure = 2.4 channels = np.arange(1, 7, dtype=np.int16) counts = np.ones(6, dtype=np.int16) pha = DataPHA('test-pha', channel=channels, counts=counts, exposure=exposure) pha.set_rmf(rdata) pha.set_analysis('energy') mdl = MyPowLaw1D() tmdl = PowLaw1D() wrapped = RMFModelPHA(rdata, pha, mdl) out = wrapped([0.1, 0.2]) elo[0] = ethresh expected = tmdl(elo, ehi) assert_allclose(out, expected) assert not np.isnan(out[0])
def test_rmf1d_delta_arf_no_pha_call(): "Can we call an RMF (delta function) with ARF (no PHA)" egrid = np.arange(0.1, 0.6, 0.1) elo = egrid[:-1] ehi = egrid[1:] rdata = create_delta_rmf(elo, ehi) adata = create_arf(elo, ehi) rmf = RMF1D(rdata, arf=adata) mdl = Const1D('flat') mdl.c0 = 2.3 wrapped = rmf(mdl) # It seems like the wrapper should match the following: # assert isinstance(wrapped, RSPModelNoPHA) # but at the time the test was written (June 2017) it # does not. # assert isinstance(wrapped, RMFModelNoPHA) wmdl = wrapped.model assert wmdl == mdl
def setup_single_pha(stat, sys, background=True, areascal="none"): """Return a single data set and model. This is aimed at wstat calculation. The data set is grouped which is a bit against the ethos of WSTAT (fit all the channels). Parameters ---------- stat, sys : bool Should statistical and systematic errors be explicitly set (True) or taken from the statistic (False)? background : bool Should a background data set be included (True) or not (False)? The background is *not* subtracted when True. areascal : {'none', 'scalar', 'array'} Is the AREASCAL set and, if so, to a scalar or array value? If background is True then it is also applied to the background data set. Returns ------- data, model DataPHA and Model objects. """ # For the array of areascals, ensure that areascal is not # constant within at least one group # areascals = { 'source': { 'none': None, 'scalar': 1.0, 'array': np.asarray([0.9, 0.9, 0.8, 0.9, 0.7], dtype=np.float32) }, 'background': { 'none': None, 'scalar': 0.8, 'array': np.asarray([1.2, 1.2, 1.2, 1.1, 1.4], dtype=np.float32) } } # If used the same bins as setup_single_1dint then could # re-use the results, but the bins are different, and it # is useful for the Data1DInt case to test non-consecutive # histogram bins. # channels = np.arange(1, 6, dtype=np.int16) counts = np.asarray([10, 13, 9, 17, 21], dtype=np.int16) rlo = channels - 0.5 rhi = channels + 0.5 if stat: staterror = np.asarray([3.0, 4.0, 3.0, 4.0, 5.0]) else: staterror = None if sys: syserror = 0.2 * counts else: syserror = None grouping = np.asarray([1, -1, 1, -1, 1], dtype=np.int16) # quality = np.asarray([0, 0, 0, 0, 0], dtype=np.int16) quality = None exposure = 150.0 backscal = 0.01 ascal = areascals['source'][areascal] # does not set areascal or header data = DataPHA(name='tstpha', channel=channels, counts=counts, staterror=staterror, syserror=syserror, grouping=grouping, quality=quality, exposure=exposure, backscal=backscal, areascal=ascal) rmf = create_delta_rmf(rlo, rhi, e_min=rlo, e_max=rhi) data.set_rmf(rmf) data.units = 'energy' if background: bgcounts = np.asarray([2, 1, 0, 2, 2], dtype=np.int16) if stat: bgstaterror = np.asarray([0.2, 0.4, 0.5, 0.3, 0.2]) else: bgstaterror = None if sys: bgsyserror = 0.3 * bgcounts else: bgsyserror = None bggrouping = None bgquality = None bgexposure = 550.0 bgbackscal = np.asarray([0.05, 0.06, 0.04, 0.04, 0.07]) bgascal = areascals['background'][areascal] bgdata = DataPHA(name='bgpha', channel=channels, counts=bgcounts, staterror=bgstaterror, syserror=bgsyserror, grouping=bggrouping, quality=bgquality, exposure=bgexposure, backscal=bgbackscal, areascal=bgascal) data.set_background(bgdata) # Trying a multi-component model, even though this actual # model is degenerate (cnst.c0 and poly.c0) cnst = Const1D('cnst') poly = Polynom1D('poly') cnst.c0 = 1.2 poly.c0 = 7.9 poly.c1 = 2.1 poly.c1.frozen = False mdl = cnst + poly return data, mdl