def test_rsp_normf_error(analysis): """Check that an error is raised on set_analysis """ exposure = 200.1 # rdata is only used to define the grids rdata = create_non_delta_rmf() specresp = create_non_delta_specresp() adata = create_arf(rdata.energ_lo, rdata.energ_hi, specresp, exposure=exposure) nchans = rdata.e_min.size 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_arf(adata) with pytest.raises(DataErr) as exc: pha.set_analysis(analysis) emsg = "response incomplete for dataset test-pha, " + \ "check the instrument model" assert str(exc.value) == emsg
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_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 test_arfmodelpha_call(ignore): """What happens calling an arf with a pha? The ignore value indicates what channel to ignore (0 means nothing is ignored). The aim is to check edge effects, and as there are only a few channels, it was decided to test all channels. """ # Note: the exposure is set in the PHA and ARF, but should not be # used when evaluating the model; it's value has been # set to a value that the test will fail it it is. # exposure = 200.1 estep = 0.01 egrid = np.arange(0.01, 0.06, estep) svals = [1.1, 1.2, 1.3, 1.4] specresp = np.asarray(svals) adata = create_arf(egrid[:-1], egrid[1:], specresp, exposure=exposure) constant = 2.3 mdl = Const1D('flat') mdl.c0 = constant 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, exposure=exposure) pha.set_arf(adata) # 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, True, True, True] mask[ignore] = False assert (pha.mask == mask).all() wrapped = ARFModelPHA(adata, pha, mdl) # The model is evaluated on the ARF 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 * np.asarray(svals) * de out = wrapped([4, 5]) assert_allclose(out, expected)
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_rsp_no_arf_matrix_call(analysis, phaexp): """Check out Response1D with matrix but no ARF analysis is the analysis setting arfexp determines whether the arf has an exposure time phaexp determines whether the PHA has an exposure time """ if phaexp: pha_exposure = 220.9 else: pha_exposure = None if phaexp: exposure = pha_exposure mdl_label = '({} * flat)'.format(exposure) else: exposure = 1.0 mdl_label = 'flat' rdata = create_non_delta_rmf() constant = 2.3 mdl = Const1D('flat') mdl.c0 = constant # Turn off integration on this model, so that it is not integrated # across the bin width. # mdl.integrate = False nchans = rdata.e_min.size 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=pha_exposure) pha.set_rmf(rdata) rsp = Response1D(pha) wrapped = rsp(mdl) assert isinstance(wrapped, ArithmeticModel) expname = 'apply_rmf({})'.format(mdl_label) assert wrapped.name == expname modvals = exposure * constant * np.ones(rdata.energ_lo.size) matrix = get_non_delta_matrix() expected = np.matmul(modvals, matrix) pha.set_analysis(analysis) 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_matrix_pha_zero_energy_bin(): """What happens when the first bin starts at 0, with replacement. Unlike test_rsp1d_delta_pha_zero_energy_bin this directly calls Response1D to create the model. """ ethresh = 1.0e-5 rdata = create_non_delta_rmf() # hack the first bin to have 0 energy rdata.energ_lo[0] = 0.0 # PHA and ARF have different exposure ties exposure_arf = 0.1 exposure_pha = 2.4 specresp = create_non_delta_specresp() with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") adata = create_arf(rdata.energ_lo, rdata.energ_hi, specresp, exposure=exposure_arf, ethresh=ethresh) validate_zero_replacement(ws, 'ARF', 'user-arf', ethresh) nchans = rdata.e_min.size 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) pha.set_rmf(rdata) pha.set_arf(adata) pha.set_analysis('energy') mdl = MyPowLaw1D() rsp = Response1D(pha) wrapped = rsp(mdl) # Evaluate the statistic / model. The value was calculated using # commit a65fb94004664eab219cc09652172ffe1dad80a6 on a linux # system (Ubuntu 17.04). # f = Fit(pha, wrapped) ans = f.calc_stat() assert ans == pytest.approx(37971.8716151947)
def test_rspmodelpha_matrix_call(ignore): """What happens calling a rsp with a pha (RMF is a matrix)? The ignore value gives the channel to ignore (counting from 0). """ exposure = 200.1 rdata = create_non_delta_rmf() specresp = create_non_delta_specresp() elo = rdata.energ_lo ehi = rdata.energ_hi adata = create_arf(elo, ehi, specresp, exposure=exposure) nchans = rdata.e_min.size constant = 22.3 slope = -1.2 mdl = Polynom1D('sloped') mdl.c0 = constant mdl.c1 = slope 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: e0 = rdata.e_min[ignore] e1 = rdata.e_max[ignore] de = 0.9 * (e1 - e0) 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 filter does not change the grid modvals = specresp * mdl(rdata.energ_lo, rdata.energ_hi) matrix = get_non_delta_matrix() expected = np.matmul(modvals, matrix) out = wrapped([4, 5]) assert_allclose(out, expected)
def test_pha_set_analysis_rate_invalid(): """Just check we error out""" chans = np.arange(1, 4) counts = np.ones_like(chans) pha = DataPHA("dummy", chans, counts) with pytest.raises(DataErr) as de: pha.set_analysis("channel", type=None) assert str(de.value) == "unknown plot type 'None', choose 'rate' or 'counts'"
def test_rmfmodelpha_matrix_call(ignore): """What happens calling an rmf (matrix) with a pha? The ignore value gives the channel to ignore (counting from 0). """ exposure = 200.1 rdata = create_non_delta_rmf() elo = rdata.e_min ehi = rdata.e_max nchans = elo.size constant = 12.2 slope = 0.01 mdl = Polynom1D('not-flat') mdl.c0 = constant mdl.c1 = slope 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: e0 = elo[ignore] e1 = ehi[ignore] de = 0.9 * (e1 - e0) 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 = RMFModelPHA(rdata, pha, mdl) # Note that the evaluation ignores any filter we've applied. # and the exposure time is not used. # modvals = mdl(rdata.energ_lo, rdata.energ_hi) matrix = get_non_delta_matrix() expected = np.matmul(modvals, matrix) out = wrapped([4, 5]) assert_allclose(out, expected)
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_rspmodelpha_matrix_call_xspec(): """Check XSPEC constant is invariant to wavelength/energy setting. As XSPEC models internally convert from Angstrom to keV, do a simple check here. """ exposure = 200.1 rdata = create_non_delta_rmf() specresp = create_non_delta_specresp() adata = create_arf(rdata.energ_lo, rdata.energ_hi, specresp, exposure=exposure) constant = 2.3 mdl = XSconstant('flat') mdl.factor = constant nchans = rdata.e_min.size 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) # The set_arf call isn't necessary, but leave in pha.set_arf(adata) pha.set_rmf(rdata) # The XSPEC models are evaluated on an energy grid, even when # the analysis setting is wavelength. Also, unlike the Sherpa # Constant model, the XSPEC XSconstant model is defined # over the integrated bin, so no correction is needed for the # bin width. # modvals = constant * specresp matrix = get_non_delta_matrix() expected = np.matmul(modvals, matrix) wrapped = RSPModelPHA(adata, rdata, pha, mdl) pha.set_analysis('wave') out_wl = wrapped([4, 5]) assert_allclose(out_wl, expected) pha.set_analysis('energy') out_en = wrapped([4, 5]) assert_allclose(out_en, expected)
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_arf1d_pha_zero_energy_bin(): "What happens when the first bin starts at 0, with replacement" ethresh = 1.0e-10 # Note: the two exposures are different to check which is # used (the answer is neither, which seems surprising) # exposure1 = 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=exposure1, ethresh=ethresh) validate_zero_replacement(ws, 'ARF', 'user-arf', ethresh) arf = ARF1D(adata) exposure2 = 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=exposure2) pha.set_arf(adata) pha.set_analysis('energy') mdl = MyPowLaw1D() tmdl = PowLaw1D() wrapped = ARFModelPHA(arf, 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_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_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_rmfmodelpha_matrix_mismatch(analysis): """Check that an error is raised if there's a mismatch. """ exposure = 200.1 rdata = create_non_delta_rmf() # nchans should be rdata.e_min.size for the sizes to match nchans = rdata.energ_lo.size 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) with pytest.raises(DataErr) as exc: pha.set_analysis(analysis) emsg = "RMF 'non-delta-rmf' is incompatible with PHA dataset 'test-pha'" assert str(exc.value) == emsg
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_pha_model_with_gaps_977(): """If the lo/hi edges don't quite match what happens? See test_pha_data_with_gaps_977. """ chans = np.arange(1, 6) vals = np.arange(1, 6) blo = np.asarray([100, 99, 98, 97, 96]) bhi = np.asarray([101, 100.0000000001, 99, 98, 97]) d = DataPHA('x', chans, vals, bin_lo=blo, bin_hi=bhi) d.set_analysis('wave') mdl = Polynom1D() mdl.c0 = 0.1 mdl.c1 = 1.1 p = ModelPHAHistogram() p.prepare(d, mdl) assert p.y == pytest.approx([1.2, 2.3, 3.4, 4.5, 5.6]) xlo = p.xlo xhi = p.xhi assert xlo.size == 5 assert xlo[0] == pytest.approx(101) assert xhi[0] == pytest.approx(100) assert xlo[-1] == pytest.approx(97) assert xhi[-1] == pytest.approx(96) # This is an equality check, not with pytest.approx, # since this is enforced by the plot code. This fails # before #977 is fixed. # assert (xlo[1:] == xhi[:-1]).all()
def test_pha_data_with_gaps_977(): """If the lo/hi edges don't quite match what happens? Ideally it recognizes the data is the same (to float32 "precision"). At the moment this is only done for PHA data and model plots, not for generic histogram plots. See issue #977 """ chans = np.arange(1, 6) vals = np.arange(1, 6) blo = np.asarray([100, 99, 98, 97, 96]) bhi = np.asarray([101, 100.0000000001, 99, 98, 97]) d = DataPHA('x', chans, vals, bin_lo=blo, bin_hi=bhi) d.set_analysis('wave') p = DataPHAPlot() p.prepare(d) assert p.y == pytest.approx([1, 2, 3, 4, 5]) xlo = p.xlo xhi = p.xhi assert xlo.size == 5 assert xlo[0] == pytest.approx(101) assert xhi[0] == pytest.approx(100) assert xlo[-1] == pytest.approx(97) assert xhi[-1] == pytest.approx(96) # This is an equality check, not with pytest.approx, # since this is enforced by the plot code. This fails # before #977 is fixed. # assert (xlo[1:] == xhi[:-1]).all()
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_rsp_normf_call(arfexp, phaexp): """Check out Response1D with no RMF. analysis is the analysis setting arfexp determines whether the arf has an exposure time phaexp determines whether the PHA has an exposure time This only uses the channel setting """ # Chose different exposure times for ARF and PHA to see which # gets picked up. # if arfexp: arf_exposure = 200.1 else: arf_exposure = None if phaexp: pha_exposure = 220.9 else: pha_exposure = None if phaexp: exposure = pha_exposure mdl_label = '({} * flat)'.format(exposure) elif arfexp: exposure = arf_exposure mdl_label = '({} * flat)'.format(exposure) else: exposure = 1.0 mdl_label = 'flat' # rdata is only used to define the grids rdata = create_non_delta_rmf() specresp = create_non_delta_specresp() adata = create_arf(rdata.energ_lo, rdata.energ_hi, specresp, exposure=arf_exposure) constant = 2.3 mdl = Const1D('flat') mdl.c0 = constant # Turn off integration on this model, so that it is not integrated # across the bin width. # mdl.integrate = False nchans = rdata.e_min.size 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=pha_exposure) pha.set_arf(adata) rsp = Response1D(pha) wrapped = rsp(mdl) assert isinstance(wrapped, ArithmeticModel) expname = 'apply_arf({})'.format(mdl_label) assert wrapped.name == expname expected = exposure * constant * specresp pha.set_analysis('channel') out = wrapped([4, 5]) assert_allclose(out, expected)