Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test all cases of DIT & NDIT vs. exptime and AutoExposure #428

Merged
merged 8 commits into from
Jun 26, 2024
2 changes: 1 addition & 1 deletion scopesim/tests/mocks/basic_instrument/YAML_telescope.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ name : basic_telescope
description : The telescope properties and effects

properties :
telescope : Basic Telescope
temperature : 0 # [deg C]

effects :
Expand All @@ -26,4 +27,3 @@ effects :
outer_unit : m
inner : 0
inner_unit : m

1 change: 1 addition & 0 deletions scopesim/tests/mocks/basic_instrument/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ yamls :
- YAML_detector.yaml # electronic and detector effects and properties

properties :
instrument: "basic_instrument"
psf_fwhm: 1.5 # [arcsec]
modes : ["imaging"] # default mode name
dit: 60
Expand Down
160 changes: 160 additions & 0 deletions scopesim/tests/test_basic_instrument/test_basic_instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import scopesim as sim
from scopesim.source import source_templates as st
from scopesim.effects import AutoExposure, Quantization


PLOTS = False
Expand Down Expand Up @@ -196,3 +197,162 @@ def test_source_keywords_in_header(self):
assert hdr["SIM EFF14 class"] == 'SourceDescriptionFitsKeywords'
assert hdr["SIM CONFIG OBS filter_name"] == 'J'
assert hdr["ESO ATM SEEING"] == opt.cmds["!OBS.psf_fwhm"]


@pytest.fixture(scope="function", name="obs")
def basic_opt_observed():
src = st.star(flux=15)
cmd = sim.UserCommands(use_instrument="basic_instrument",
ignore_effects=SWITCHOFF,
properties={"!OBS.dit": 10, "!OBS.ndit": 1})
opt = sim.OpticalTrain(cmd)
opt.observe(src)
default = int(opt.readout()[0][1].data.sum())
return opt, default


@pytest.fixture(scope="function", name="obs_aeq")
def basic_opt_with_autoexp_and_quant_observed():
src = st.star(flux=15)
cmd = sim.UserCommands(use_instrument="basic_instrument",
ignore_effects=SWITCHOFF,
properties={"!OBS.dit": 10, "!OBS.ndit": 1})
opt = sim.OpticalTrain(cmd)
opt.observe(src)
default = int(opt.readout()[0][1].data.sum())

autoexp = AutoExposure(cmds=opt.cmds, mindit=1,
full_well=100, fill_frac=0.8)
quanteff = Quantization(cmds=opt.cmds)
opt.optics_manager["basic_detector"].effects.insert(2, autoexp)
opt.optics_manager["basic_detector"].effects.append(quanteff)
opt.cmds["!OBS.exptime"] = 60
return opt, default, quanteff


@pytest.mark.usefixtures("protect_currsys", "patch_all_mock_paths")
class TestDitNdit:
@pytest.mark.parametrize(("dit", "ndit", "factor"),
[(20, 1, 2), (10, 3, 3)])
def test_obs_dict(self, obs, dit, ndit, factor):
"""This should just use dit, ndit from !OBS."""
opt, default = obs
# This should work with patch.dict, but doesn't :(
o_dit, o_ndit = opt.cmds["!OBS.dit"], opt.cmds["!OBS.ndit"]
opt.cmds["!OBS.dit"] = dit
opt.cmds["!OBS.ndit"] = ndit
kwarged = int(opt.readout()[0][1].data.sum())
opt.cmds["!OBS.dit"] = o_dit
opt.cmds["!OBS.ndit"] = o_ndit
assert int(kwarged / default) == factor

@pytest.mark.parametrize(("dit", "ndit", "factor"),
[pytest.param(20, 1, 2, marks=pytest.mark.xfail(reason="S.E. doesn't get kwargs without A.E..")),
pytest.param(10, 3, 3, marks=pytest.mark.xfail(reason="S.E. doesn't get kwargs without A.E..")),
(None, None, 1)])
def test_kwargs_override_obs_dict(self, obs, dit, ndit, factor):
"""This should prioritize kwargs and fallback to !OBS."""
opt, default = obs
kwarged = int(opt.readout(dit=dit, ndit=ndit)[0][1].data.sum())
assert int(kwarged / default) == factor

@pytest.mark.parametrize(("dit", "ndit", "factor", "quant"),
[pytest.param(20, 1, 2, True, marks=pytest.mark.xfail(reason="S.E. doesn't get kwargs without A.E..")),
pytest.param(10, 3, 3, False, marks=pytest.mark.xfail(reason="S.E. doesn't get kwargs without A.E..")),
pytest.param(None, None, 1, True, marks=pytest.mark.xfail(reason="A.E. dosen't use dit, ndit from !OBS if those are None in kwargs."))])
def test_kwargs_override_obs_dict_also_with_autoexp(
self, obs_aeq, dit, ndit, factor, quant):
"""This should prioritize dit, ndit from kwargs.

Lacking those, dit and ndit from !OBS should be used over exptime.
"""
opt, default, quanteff = obs_aeq
kwarged = int(opt.readout(dit=dit, ndit=ndit)[0][1].data.sum())
assert int(kwarged / default) == factor
assert quanteff._should_apply() == quant

@pytest.mark.parametrize(("exptime", "factor"),
[(20, 2), (30, 3),
pytest.param(None, 6, marks=pytest.mark.xfail(reason="A.E. doesn't understand None yet."))])
def test_autoexp(self, obs_aeq, exptime, factor):
"""This should prioritize kwargs and fallback to !OBS."""
opt, default, quanteff = obs_aeq
# This should work with patch.dict, but doesn't :(
o_dit, o_ndit = opt.cmds["!OBS.dit"], opt.cmds["!OBS.ndit"]
opt.cmds["!OBS.dit"] = None
opt.cmds["!OBS.ndit"] = None
kwarged = int(opt.readout(exptime=exptime)[0][1].data.sum())
assert not quanteff._should_apply()
opt.cmds["!OBS.dit"] = o_dit
opt.cmds["!OBS.ndit"] = o_ndit
assert int(kwarged / default) == factor

@pytest.mark.parametrize(("exptime", "factor", "quant"),
[pytest.param(30, 3, False, marks=pytest.mark.xfail(reason="dit, ndit in !OBS overrides kwargs exptime.")),
(None, 1, True)])
def test_autoexp_overrides_obs_dict(self, obs_aeq, exptime, factor, quant):
"""This should prioritize kwargs and use dit, ndit when None."""
opt, default, quanteff = obs_aeq
kwarged = int(opt.readout(exptime=exptime)[0][1].data.sum())
assert quanteff._should_apply() == quant
# Quantization results in ~4% loss, which is fine:
assert pytest.approx(kwarged / default, rel=.05) == factor

@pytest.mark.parametrize(("dit", "ndit", "factor", "quant"),
[pytest.param(90, 1, 90, True, marks=pytest.mark.xfail(reason="S.E. doesn't get kwargs.")),
pytest.param(2, 90, 180, False, marks=pytest.mark.xfail(reason="S.E. doesn't get kwargs."))])
def test_ditndit_in_kwargs_while_also_having_autoexp(
self, obs_aeq, dit, ndit, factor, quant):
"""This should prioritize dit, ndit from kwargs."""
opt, default, quanteff = obs_aeq
kwarged = int(opt.readout(dit=dit, ndit=ndit)[0][1].data.sum())
assert int(kwarged / default) == factor
assert quanteff._should_apply() == quant

@pytest.mark.parametrize(("dit", "ndit", "exptime", "factor", "quant"),
[pytest.param(90, 1, None, 90, True, marks=pytest.mark.xfail(reason="S.E. doesn't get kwargs.")),
pytest.param(2, 90, 20, 180, False, marks=pytest.mark.xfail(reason="S.E. doesn't get kwargs."))])
def test_ditndit_in_kwargs_while_also_having_autoexp_and_exptime(
self, obs_aeq, dit, ndit, exptime, factor, quant):
"""This should prioritize dit, ndit from kwargs and ignore exptime."""
opt, default, quanteff = obs_aeq
kwarged = int(opt.readout(exptime=exptime,
dit=dit, ndit=ndit)[0][1].data.sum())
assert int(kwarged / default) == factor
assert quanteff._should_apply() == quant

@pytest.mark.xfail(reason="Currently raises TypeError, but should be ValueError.")
def test_throws_for_no_anything(self, obs):
"""No specification whatsoever, so throw error."""
opt, default = obs
opt.cmds["!OBS.exptime"] = None
# This should work with patch.dict, but doesn't :(
o_dit, o_ndit = opt.cmds["!OBS.dit"], opt.cmds["!OBS.ndit"]
opt.cmds["!OBS.dit"] = None
opt.cmds["!OBS.ndit"] = None
with pytest.raises(ValueError):
opt.readout()
opt.cmds["!OBS.dit"] = o_dit
opt.cmds["!OBS.ndit"] = o_ndit

@pytest.mark.xfail(reason="Currently doesn't raise anything, b/c dit, ndit from !OBS is prioitized.")
def test_throws_for_no_ditndit_no_autoexp_kwargs(self, obs):
"""This should use exptime from kwargs, but fail w/o AutoExp."""
opt, default = obs
opt.cmds["!OBS.exptime"] = None
with pytest.raises(ValueError):
opt.readout(exptime=60)

@pytest.mark.xfail(reason="Currently raises TypeError, but should be ValueError.")
def test_throws_for_no_ditndit_no_autoexp_obs(self, obs):
"""This should fallback to !OBS.exptime, but fail w/o AutoExp."""
opt, default = obs
opt.cmds["!OBS.exptime"] = 60
# This should work with patch.dict, but doesn't :(
o_dit, o_ndit = opt.cmds["!OBS.dit"], opt.cmds["!OBS.ndit"]
opt.cmds["!OBS.dit"] = None
opt.cmds["!OBS.ndit"] = None
with pytest.raises(ValueError):
opt.readout()
opt.cmds["!OBS.dit"] = o_dit
opt.cmds["!OBS.ndit"] = o_ndit
Loading