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

Check minimum epoch lengths in demes models #931

Merged
merged 1 commit into from
May 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/misc/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Testing

* Added many more tests related to models defined using `demes`
PR {pr}`891`.
PR {pr}`931`.
Issue {issue}`890`.
{user}`apragsdale`,
{user}`molpopgen`.
Expand All @@ -57,6 +58,10 @@ Back end changes
PR {pr}`906`.
* Added infrastructure to separate out back end from Python-specific C++ code.
PR {pr}`936`.
* Assert that epochs from `demes` models are at least 1 generation long.
PR {pr}`931`
* Added infrastructure to separate out back end from Python-specific C++ code.
PR {pr}`936`.

Dependencies

Expand Down
6 changes: 5 additions & 1 deletion fwdpy11/_functions/import_demes.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,10 @@ def _process_epoch(

start_size = int(np.rint(e.start_size))
end_size = int(np.rint(e.end_size))
time_span = int(np.rint(e.time_span))

if time_span < 1:
raise ValueError("epoch durations must be >= 1 time step")

# Handle size change functions
events.set_deme_sizes.append(
Expand All @@ -529,7 +533,7 @@ def _process_epoch(
raise ValueError(
f"Size change function must be exponential. We got {e.size_function}"
)
G = exponential_growth_rate(start_size, end_size, int(np.rint(e.time_span)))
G = exponential_growth_rate(start_size, end_size, time_span)
events.set_growth_rates.append(
SetExponentialGrowth(when=when, deme=idmap[deme_id], G=G)
)
Expand Down
5 changes: 4 additions & 1 deletion fwdpy11/discrete_demography.py
Original file line number Diff line number Diff line change
Expand Up @@ -1065,7 +1065,10 @@ def from_demes_graph(
if start > 0:
start = start + 1
end = model_times.convert_time(e.end_time) + 1
assert end > start, f"{e}, {start}, {end}"
if not end > start:
raise ValueError(
f"epoch end time must be > start, got end: {end}, start: {start}"
)
# NOTE: 1.0 is a HACK for growth rate and is WRONG
itree[start:end] = _EpochData(
idmap[d.name], None, int(e.start_size), 1.0
Expand Down
48 changes: 48 additions & 0 deletions tests/test_demes2fwdpy11.py
Original file line number Diff line number Diff line change
Expand Up @@ -1857,3 +1857,51 @@ def test_non_integer_initial_epoch_size():
for i in sorted(demog.metadata["initial_sizes"].keys())
]
_ = fwdpy11.DiploidPopulation(initial_sizes, 1)


def test_very_short_epoch():
b = demes.Builder()
b.add_deme("A", epochs=[{"start_size": 100}])
b.add_deme(
"B",
ancestors=["A"],
start_time=10,
epochs=[
{"start_size": 100, "end_time": 1e-3},
{"start_size": 200, "end_time": 0.0},
],
)
g = b.resolve()

with pytest.raises(ValueError):
_ = fwdpy11.discrete_demography.from_demes(g)


def test_epoch_rounding_01():
yaml = """
time_units: generations
demes:
- name: bad
epochs:
- {end_time: 1.75, start_size: 1}
- {end_time: 1.25, start_size: 2}
- {end_time: 0.5, start_size: 3}
- {end_time: 0, start_size: 4}
"""
graph = demes.loads(yaml)
with pytest.raises(ValueError):
_ = fwdpy11.discrete_demography.from_demes(graph, burnin=0)

def test_epoch_rounding_02():
yaml = """
time_units: generations
demes:
- name: bad
epochs:
- {end_time: 1.5, start_size: 1}
- {end_time: 0.5, start_size: 2}
- {end_time: 0, start_size: 3}
"""
graph = demes.loads(yaml)
with pytest.raises(ValueError):
_ = fwdpy11.discrete_demography.from_demes(graph, burnin=0)