-
Notifications
You must be signed in to change notification settings - Fork 87
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
Drift trajectory implementation #1803
base: main
Are you sure you want to change the base?
Changes from all commits
64d781a
d126ad3
99d55c1
c9ae7bf
f90e5b2
c7de424
ea5fc6e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1077,9 +1077,10 @@ Simulator_parse_simulation_model(Simulator *self, PyObject *py_model) | |
PyObject *dirac_s = NULL; | ||
PyObject *beta_s = NULL; | ||
PyObject *sweep_genic_selection_s = NULL; | ||
PyObject *neutral_fixation_s = NULL; | ||
PyObject *value; | ||
int is_hudson, is_dtwf, is_smc, is_smc_prime, is_dirac, is_beta, is_sweep_genic_selection; | ||
int is_wf_ped; | ||
int is_wf_ped, is_neutral_fixation; | ||
double psi, c, alpha, truncation_point; | ||
|
||
hudson_s = Py_BuildValue("s", "hudson"); | ||
|
@@ -1114,6 +1115,10 @@ Simulator_parse_simulation_model(Simulator *self, PyObject *py_model) | |
if (sweep_genic_selection_s == NULL) { | ||
goto out; | ||
} | ||
neutral_fixation_s = Py_BuildValue("s", "neutral_fixation"); | ||
if (neutral_fixation_s == NULL) { | ||
goto out; | ||
} | ||
|
||
py_name = get_dict_value(py_model, "name"); | ||
if (py_name == NULL) { | ||
|
@@ -1219,9 +1224,23 @@ Simulator_parse_simulation_model(Simulator *self, PyObject *py_model) | |
goto out; | ||
} | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can't comment on the CPython bits -- need @jeromekelleher for that. |
||
is_neutral_fixation = PyObject_RichCompareBool(py_name, | ||
neutral_fixation_s, Py_EQ); | ||
if (is_neutral_fixation == -1) { | ||
goto out; | ||
} | ||
if (is_neutral_fixation) { | ||
/* currently using all the machinery from the genic model */ | ||
ret = Simulator_parse_sweep_genic_selection_model(self, py_model); | ||
if (ret != 0) { | ||
goto out; | ||
} | ||
} | ||
|
||
if (! (is_hudson || is_dtwf || is_smc || is_smc_prime || is_dirac | ||
|| is_beta || is_sweep_genic_selection || is_wf_ped)) { | ||
|| is_beta || is_sweep_genic_selection || is_neutral_fixation | ||
|| is_wf_ped)) { | ||
PyErr_SetString(PyExc_ValueError, "Unknown simulation model"); | ||
goto out; | ||
} | ||
|
@@ -1239,6 +1258,7 @@ Simulator_parse_simulation_model(Simulator *self, PyObject *py_model) | |
Py_XDECREF(beta_s); | ||
Py_XDECREF(dirac_s); | ||
Py_XDECREF(sweep_genic_selection_s); | ||
Py_XDECREF(neutral_fixation_s); | ||
return ret; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1314,7 +1314,9 @@ def _choose_num_labels(self, models): | |
""" | ||
num_labels = 1 | ||
for model in models: | ||
if isinstance(model, SweepGenicSelection): | ||
if isinstance(model, SweepGenicSelection) or isinstance( | ||
model, NeutralFixation | ||
): | ||
num_labels = 2 | ||
return num_labels | ||
|
||
|
@@ -1922,3 +1924,63 @@ def __init__( | |
self.end_frequency = end_frequency | ||
self.s = s | ||
self.dt = dt | ||
|
||
|
||
@dataclasses.dataclass | ||
class NeutralFixation(ParametricAncestryModel): | ||
""" | ||
A fixation of a neutral mutation has occured in the history of the sample. | ||
This will lead to a weak reduction in polymorphism near the fixed site. | ||
|
||
The model is one of a structured coalescent where selective backgrounds are | ||
defined as in | ||
`Braverman et al. (1995) <https://www.ncbi.nlm.nih.gov/pmc/articles/PMC1206652/>`_ | ||
The implementation details here follow closely those in discoal | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the scaling identical to Schrider and Kern? The sweep model wasn't, so any differences here also need to be documented. |
||
`(Kern and Schrider, 2016) | ||
<https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5167068/>`_ | ||
|
||
See :ref:`sec_ancestry_models_neutral_fixations` for examples and | ||
details on how to specify different types of sweeps. | ||
|
||
.. warning:: | ||
Currently models with more than one population and a sweep | ||
are not implemented. Population size changes during the sweep | ||
are not yet possible in msprime. | ||
|
||
:param float position: the location of the fixation along the | ||
chromosome. | ||
:param float start_frequency: population frequency of the neutral | ||
allele at the start of the sojourn that we will follow. E.g., for a *de novo* | ||
allele in a diploid population of size N, start frequency would be | ||
:math:`1/2N`. | ||
:param float end_frequency: population frequency of neutral allele | ||
allele at the end of its sojourn. | ||
:param float dt: dt is the small increment of time for stepping through | ||
the sweep phase of the model. a good rule of thumb is for this to be | ||
approximately :math:`1/40N` or smaller. | ||
""" | ||
|
||
name = "neutral_fixation" | ||
|
||
position: float | None | ||
start_frequency: float | None | ||
end_frequency: float | None | ||
dt: float | None | ||
s: float | 0 | ||
|
||
# We have to define an __init__ to enfore keyword-only behaviour | ||
def __init__( | ||
self, | ||
*, | ||
duration=None, | ||
position=None, | ||
start_frequency=None, | ||
end_frequency=None, | ||
dt=None, | ||
): | ||
self.duration = duration | ||
self.position = position | ||
self.start_frequency = start_frequency | ||
self.end_frequency = end_frequency | ||
self.s = 0 | ||
self.dt = dt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we think of reasonable ways to handle the possibility of numeric errors here? It seems that there are no restrictions placed on the input values, so one can get negative frequencies out:
Perhaps this should return
max(value, 0.0)
?