diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 752167406..366fc7663 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -41,7 +41,6 @@ jobs: if: runner.os == 'macOS' run: | # Fix incorrect conda permissions on mac that prevent cache restore. - echo "$USER:staff ${{ steps.find-conda.outputs.CONDA }}" sudo chown -R $USER:staff ${{ steps.find-conda.outputs.CONDA }} - name: cache conda diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6db710898..8687235f5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,9 @@ instead of a single value. This will not affect anyone who is not parsing the metadata related to DFEs. +- SLiM extended events and selective sweep infrastructure have been + moved from the `stdpopsim.ext` namespace into `stdpopsim` proper + **New features**: - *Relationship between dominance and selection coefficient:* diff --git a/docs/api.rst b/docs/api.rst index f22ec0cf9..a65155c86 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -169,6 +169,30 @@ that applies to the entire Contig. .. _sec_api_generic_models: + +.. _sec_api_sweeps: + +******************** +Selection and sweeps +******************** + +:class:`ExtendedEvent` and subclasses may be used to condition on sequences of +events at particular loci using the SLiM engine, by passing lists of events to +the `extended_events` argument in `Engine.simulate`. A simplified API is provided +to construct the necessary events for selective sweeps. + +.. autoclass:: stdpopsim.DrawMutation() + :members: + +.. autoclass:: stdpopsim.ChangeMutationFitness() + :members: + +.. autoclass:: stdpopsim.ConditionOnAlleleFrequency() + :members: + +.. autofunction:: stdpopsim.selective_sweep + + ************** Generic models ************** diff --git a/docs/selection_example.py b/docs/selection_example.py index 4fa076d8f..8981877f2 100644 --- a/docs/selection_example.py +++ b/docs/selection_example.py @@ -62,7 +62,7 @@ def adaptive_introgression(seed): # generations before present. extended_events = [ # Draw mutation in DenA. - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=T_mut, single_site_id=locus_id, population="DenA", @@ -74,11 +74,11 @@ def adaptive_introgression(seed): # returned to the point where the mutation was introduced. # Conditioning should start one generation after T_mut (not at T_mut!), # to avoid checking for the mutation before SLiM can introduce it. - stdpopsim.ext.ConditionOnAlleleFrequency( + stdpopsim.ConditionOnAlleleFrequency( # Note: if T_mut ~= T_Den_split, then we end up with: # GenerationAfter(T_mut) < T_Den_split, # which will give an error due to "start_time < end_time". - start_time=stdpopsim.ext.GenerationAfter(T_mut), + start_time=stdpopsim.GenerationAfter(T_mut), end_time=T_Den_split, single_site_id=locus_id, population="DenA", @@ -87,8 +87,8 @@ def adaptive_introgression(seed): ), # Denisovans split into DenA and Den1 at time T_Den_split, # so now we condition on having AF > 0 in Den1. - stdpopsim.ext.ConditionOnAlleleFrequency( - start_time=stdpopsim.ext.GenerationAfter(T_Den_split), + stdpopsim.ConditionOnAlleleFrequency( + start_time=stdpopsim.GenerationAfter(T_Den_split), end_time=T_mig, single_site_id=locus_id, population="Den1", @@ -97,8 +97,8 @@ def adaptive_introgression(seed): ), # The Den1 lineage has migrants entering the Papaun lineage at T_mig, # so condition on AF > 0 in Papuans. - stdpopsim.ext.ConditionOnAlleleFrequency( - start_time=stdpopsim.ext.GenerationAfter(T_mig), + stdpopsim.ConditionOnAlleleFrequency( + start_time=stdpopsim.GenerationAfter(T_mig), end_time=0, single_site_id=locus_id, population="Papuan", @@ -108,7 +108,7 @@ def adaptive_introgression(seed): # The mutation is positively selected in Papuans at T_sel. # Note that this will have no effect, unless/until a mutation with the # specified mutation_type_id is found in the population. - stdpopsim.ext.ChangeMutationFitness( + stdpopsim.ChangeMutationFitness( start_time=T_sel, end_time=0, single_site_id=locus_id, @@ -117,7 +117,7 @@ def adaptive_introgression(seed): dominance_coeff=0.5, ), # Condition on AF > 0.05 in Papuans at the end of the simulation. - stdpopsim.ext.ConditionOnAlleleFrequency( + stdpopsim.ConditionOnAlleleFrequency( start_time=0, end_time=0, single_site_id=locus_id, diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 7a76d64a6..f9d1ff4af 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -1070,7 +1070,7 @@ resulting simulation: .. code-block:: python selection_coeffs = [ - stdpopsim.ext.selection_coeff_from_mutation(ts, mut) for mut in ts.mutations() + stdpopsim.selection_coeff_from_mutation(ts, mut) for mut in ts.mutations() ] num_neutral = sum([s == 0 for s in selection_coeffs]) print( @@ -1131,7 +1131,7 @@ We'll count up the number of neutral and deleterious mutations in the three regi region = np.digitize(site.position, gene_interval.flatten()) for mut in site.mutations: selection_coeffs[region].append( - stdpopsim.ext.selection_coeff_from_mutation(ts, mut) + stdpopsim.selection_coeff_from_mutation(ts, mut) ) for region, coeffs in enumerate(selection_coeffs): @@ -1292,7 +1292,7 @@ frequency :math:`1 / 2N`. "overwritten" and an error will be raised in simulation. Next, we will set up the "extended events" which will modify the demography. -This is done through :func:`stdpopsim.ext.selective_sweep`, which represents a +This is done through :func:`stdpopsim.selective_sweep`, which represents a general model for a mutation that is beneficial within a single population. We specify that the mutation should originate 1000 generations ago in a random individual from the first population (named "pop_0" by default); that the @@ -1302,7 +1302,7 @@ greater than 0.8. .. code-block:: python - extended_events = stdpopsim.ext.selective_sweep( + extended_events = stdpopsim.selective_sweep( single_site_id=locus_id, population="pop_0", selection_coeff=0.5, diff --git a/stdpopsim/__init__.py b/stdpopsim/__init__.py index 2ada49a16..4f82d9bc0 100644 --- a/stdpopsim/__init__.py +++ b/stdpopsim/__init__.py @@ -20,13 +20,11 @@ from .engines import * # NOQA from .warning_categories import * # NOQA -# Extensions. -from . import ext # NOQA - # We import catalog here, but the internal functions # defined are not part of the external API. from .catalog import * # NOQA from . import qc # NOQA +from .selection import * # NOQA from .slim_engine import * # NOQA diff --git a/stdpopsim/ext/__init__.py b/stdpopsim/ext/__init__.py deleted file mode 100644 index af44df34c..000000000 --- a/stdpopsim/ext/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# TODO: -# It's not yet clear where this code should be put, nor how the API(s) should -# be structured. The ``ext`` module is a temporary namespace for experimental -# extensions to stdpopsim. It will probably disappear in the future. The -# interfaces defined here are incomplete, engine specific, and are subject -# to change. -from .selection import * # NOQA diff --git a/stdpopsim/ext/selection.py b/stdpopsim/selection.py similarity index 100% rename from stdpopsim/ext/selection.py rename to stdpopsim/selection.py diff --git a/stdpopsim/slim_engine.py b/stdpopsim/slim_engine.py index b819e12b1..1fa867d2d 100644 --- a/stdpopsim/slim_engine.py +++ b/stdpopsim/slim_engine.py @@ -908,7 +908,7 @@ def fix_time(event): continue t = getattr(event, attr) t_rounded = round(float(t) / scaling_factor) * scaling_factor - if isinstance(t, stdpopsim.ext.GenerationAfter): + if isinstance(t, stdpopsim.GenerationAfter): t_rounded -= scaling_factor if t_rounded < 0: raise ValueError(f"Bad {attr}: {getattr(event, attr)}") @@ -1000,7 +1000,7 @@ def fix_time(event): drawn_mutations = [] fitness_callbacks = [] condition_on_allele_frequency = [] - op_id = stdpopsim.ext.ConditionOnAlleleFrequency.op_id + op_id = stdpopsim.ConditionOnAlleleFrequency.op_id slim_mutation_ids = _dfe_to_mtypes(contig) drawn_single_site_ids = collections.defaultdict(int) referenced_single_site_ids = set() @@ -1061,7 +1061,7 @@ def fix_time(event): if hasattr(ee, "start_time") and hasattr(ee, "end_time"): # Now that GenerationAfter times have been accounted for, we can # properly catch invalid start/end times. - stdpopsim.ext.validate_time_range(ee.start_time, ee.end_time) + stdpopsim.validate_time_range(ee.start_time, ee.end_time) if hasattr(ee, "population"): # Convert population name to integer index. "-1" is used to encode # all populations (currently only valid for ChangeMutationFitness). @@ -1078,7 +1078,7 @@ def fix_time(event): population_id = population_name_to_index[ee.population] # Append attributes to lists per event type - if isinstance(ee, stdpopsim.ext.DrawMutation): + if isinstance(ee, stdpopsim.DrawMutation): assert population_id >= 0 drawn_mutations.append( ( @@ -1090,7 +1090,7 @@ def fix_time(event): ) ) drawn_single_site_ids[ee.single_site_id] += 1 - elif isinstance(ee, stdpopsim.ext.ChangeMutationFitness): + elif isinstance(ee, stdpopsim.ChangeMutationFitness): fitness_callbacks.append( ( ee.start_time * demographic_model.generation_time, @@ -1102,7 +1102,7 @@ def fix_time(event): ) ) referenced_single_site_ids.add(ee.single_site_id) - elif isinstance(ee, stdpopsim.ext.ConditionOnAlleleFrequency): + elif isinstance(ee, stdpopsim.ConditionOnAlleleFrequency): assert population_id >= 0 condition_on_allele_frequency.append( ( @@ -1432,7 +1432,7 @@ def matrix2str( # Allele frequency conditioning op_types = ", ".join( - f'"{op}"' for op in stdpopsim.ext.ConditionOnAlleleFrequency.op_types + f'"{op}"' for op in stdpopsim.ConditionOnAlleleFrequency.op_types ) printsc(f' defineConstant("op_types", c({op_types}));') printsc(" // Allele frequency conditioning, one row for each.") @@ -1560,8 +1560,8 @@ def simulate( :param seed: The seed for the random number generator. :type seed: int - :param extended_events: A list of :class:`ext.ExtendedEvents` to be - passed to SLiM, e.g. produced by :func:`ext.selective_sweep()`. + :param extended_events: A list of :class:`ExtendedEvents` to be + passed to SLiM, e.g. produced by :func:`selective_sweep()`. :type extended_events: list :param slim_path: The full path to the slim executable, or the name of a command in the current PATH. diff --git a/tests/test_slim_engine.py b/tests/test_slim_engine.py index 31bce9c73..b31ab9422 100644 --- a/tests/test_slim_engine.py +++ b/tests/test_slim_engine.py @@ -27,7 +27,7 @@ def count_mut_types(ts): selection_coeffs = [ - stdpopsim.ext.selection_coeff_from_mutation(ts, mut) for mut in ts.mutations() + stdpopsim.selection_coeff_from_mutation(ts, mut) for mut in ts.mutations() ] num_neutral = sum([s == 0 for s in selection_coeffs]) return [num_neutral, abs(len(selection_coeffs) - num_neutral)] @@ -1786,7 +1786,7 @@ def test_draw_mutation(self): contig = get_test_contig() contig.add_single_site(id=self.mut_id, coordinate=100) extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id=self.mut_id, population="pop_0", @@ -1806,12 +1806,12 @@ def test_draw_mutations_at_different_sites(self): contig.add_single_site(id="recent", coordinate=100) contig.add_single_site(id="older", coordinate=101) extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut // 2, single_site_id="recent", population="pop_0", ), - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id="older", population="pop_0", @@ -1830,12 +1830,12 @@ def test_draw_multiple_mutations_at_same_site(self): contig = get_test_contig() contig.add_single_site(id="mutant", coordinate=100) extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut // 2, single_site_id="mutant", population="pop_0", ), - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id="mutant", population="pop_0", @@ -1855,7 +1855,7 @@ def test_invalid_single_site_id(self): engine = stdpopsim.get_engine("slim") for single_site_id in ["deleterious", "sweep"]: extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id=single_site_id, population="pop_0", @@ -1872,7 +1872,7 @@ def test_invalid_single_site_id(self): def test_no_mutation_types_defined(self): extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id=self.mut_id, population="pop_0", @@ -1893,7 +1893,7 @@ def test_no_mutation_types_defined(self): def test_multiple_mutation_types_defined(self): extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id="test", population="pop_0", @@ -1929,7 +1929,7 @@ def test_multiple_mutation_types_defined(self): def test_fitness_distribution_not_fixed(self): extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id="test", population="pop_0", @@ -1956,7 +1956,7 @@ def test_fitness_distribution_not_fixed(self): def test_multiple_intervals(self): extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id="test", population="pop_0", @@ -1992,7 +1992,7 @@ def test_multiple_intervals(self): def test_interval_too_large(self): extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id="test", population="pop_0", @@ -2028,7 +2028,7 @@ def test_interval_too_large(self): def test_duplicate_mutation_ids(self): extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id="test", population="pop_0", @@ -2049,7 +2049,7 @@ def test_duplicate_mutation_ids(self): def test_mutation_has_no_interval(self): extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id="test", population="pop_0", @@ -2071,15 +2071,15 @@ def test_mutation_has_no_interval(self): def test_bad_time(self): for time in (-1,): with pytest.raises(ValueError): - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=time, single_site_id="irrelevant", population="pop_0", ) for time in (0, -1): with pytest.raises(ValueError): - stdpopsim.ext.DrawMutation( - time=stdpopsim.ext.GenerationAfter(time), + stdpopsim.DrawMutation( + time=stdpopsim.GenerationAfter(time), single_site_id="irrelevant", population="pop_0", ) @@ -2094,12 +2094,12 @@ def test_drawn_mutation_not_lost(self): ct.mutation_rate = 0.0 ct.add_single_site(id="test", coordinate=100) extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id="test", population="pop_0", ), - stdpopsim.ext.ConditionOnAlleleFrequency( + stdpopsim.ConditionOnAlleleFrequency( start_time=0, end_time=0, single_site_id="test", @@ -2126,12 +2126,12 @@ def test_drawn_mutation_is_lost(self): ct.mutation_rate = 0.0 ct.add_single_site(id="test", coordinate=100) extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id="test", population="pop_0", ), - stdpopsim.ext.ConditionOnAlleleFrequency( + stdpopsim.ConditionOnAlleleFrequency( start_time=0, end_time=0, single_site_id="test", @@ -2159,13 +2159,13 @@ def test_drawn_mutation_meets_AF_threshold(self): ct.add_single_site(id="test", coordinate=100) for af_threshold, seed in zip((0.01, 0.1, 0.2), (1, 2, 3)): extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id="test", population="pop_0", ), # Condition on desired AF at end of simulation. - stdpopsim.ext.ConditionOnAlleleFrequency( + stdpopsim.ConditionOnAlleleFrequency( start_time=0, end_time=0, single_site_id="test", @@ -2206,7 +2206,7 @@ def test_bad_AF_conditioning_parameters(self): ("<=", 1), ]: with pytest.raises(ValueError): - stdpopsim.ext.ConditionOnAlleleFrequency( + stdpopsim.ConditionOnAlleleFrequency( start_time=0, end_time=0, single_site_id="irrelevant", @@ -2218,7 +2218,7 @@ def test_bad_AF_conditioning_parameters(self): def test_bad_times(self): for start_time, end_time in [(-1, 0), (0, -1), (1, 100)]: with pytest.raises(ValueError): - stdpopsim.ext.ConditionOnAlleleFrequency( + stdpopsim.ConditionOnAlleleFrequency( start_time=start_time, end_time=end_time, single_site_id="irrelevant", @@ -2242,13 +2242,13 @@ def test_bad_GenerationAfter_times(self): ]: with pytest.raises(ValueError): extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id=self.mut_id, population="pop_0", ), - stdpopsim.ext.ConditionOnAlleleFrequency( - start_time=stdpopsim.ext.GenerationAfter(start_time), + stdpopsim.ConditionOnAlleleFrequency( + start_time=stdpopsim.GenerationAfter(start_time), end_time=end_time, single_site_id=self.mut_id, population="pop_0", @@ -2265,18 +2265,18 @@ def test_bad_GenerationAfter_times(self): ) def test_op_id(self): - op_types = stdpopsim.ext.ConditionOnAlleleFrequency.op_types + op_types = stdpopsim.ConditionOnAlleleFrequency.op_types for op in op_types: - id = stdpopsim.ext.ConditionOnAlleleFrequency.op_id(op) + id = stdpopsim.ConditionOnAlleleFrequency.op_id(op) assert 0 <= id < len(op_types) for op in ("==", "=", "!=", {}, ""): with pytest.raises(ValueError): - id = stdpopsim.ext.ConditionOnAlleleFrequency.op_id(op) + id = stdpopsim.ConditionOnAlleleFrequency.op_id(op) def test_no_drawn_mutation(self): extended_events = [ - stdpopsim.ext.ConditionOnAlleleFrequency( - start_time=stdpopsim.ext.GenerationAfter(self.T_mut), + stdpopsim.ConditionOnAlleleFrequency( + start_time=stdpopsim.GenerationAfter(self.T_mut), end_time=0, single_site_id=self.mut_id, population="pop_0", @@ -2297,7 +2297,7 @@ def test_no_drawn_mutation(self): @pytest.mark.skipif(IS_WINDOWS, reason="SLiM not available on windows") class TestChangeMutationFitness(PiecewiseConstantSizeMixin): - # Testing stdpopsim.ext.ChangeMutationFitness is challenging, because + # Testing stdpopsim.ChangeMutationFitness is challenging, because # the side-effects are not deterministic. But if we condition on fixation # of a drawn mutation, such a simulation will be very slow without strong # positive selection (because we effectively do rejection sampling on the @@ -2309,13 +2309,13 @@ def test_positive_mutation_meets_AF_threshold(self): engine = stdpopsim.get_engine("slim") for af_threshold, seed in zip((0.5, 1), (1, 2)): extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id=self.mut_id, population="pop_0", ), - stdpopsim.ext.ChangeMutationFitness( - start_time=stdpopsim.ext.GenerationAfter(self.T_mut), + stdpopsim.ChangeMutationFitness( + start_time=stdpopsim.GenerationAfter(self.T_mut), end_time=0, single_site_id=self.mut_id, population="pop_0", @@ -2324,8 +2324,8 @@ def test_positive_mutation_meets_AF_threshold(self): ), # Condition on AF > 0, to restore() immediately if the # allele is lost. - stdpopsim.ext.ConditionOnAlleleFrequency( - start_time=stdpopsim.ext.GenerationAfter(self.T_mut), + stdpopsim.ConditionOnAlleleFrequency( + start_time=stdpopsim.GenerationAfter(self.T_mut), end_time=0, single_site_id=self.mut_id, population="pop_0", @@ -2333,7 +2333,7 @@ def test_positive_mutation_meets_AF_threshold(self): allele_frequency=0, ), # Condition on desired AF at end of simulation. - stdpopsim.ext.ConditionOnAlleleFrequency( + stdpopsim.ConditionOnAlleleFrequency( start_time=0, end_time=0, single_site_id=self.mut_id, @@ -2362,7 +2362,7 @@ def test_referenced_single_site_is_nonneutral(self): contig.add_single_site("one", coordinate=100) contig.add_single_site("two", coordinate=101) extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id="one", population="pop_0", @@ -2383,8 +2383,8 @@ def test_referenced_single_site_is_nonneutral(self): def test_no_drawn_mutation(self): extended_events = [ - stdpopsim.ext.ChangeMutationFitness( - start_time=stdpopsim.ext.GenerationAfter(self.T_mut), + stdpopsim.ChangeMutationFitness( + start_time=stdpopsim.GenerationAfter(self.T_mut), end_time=0, single_site_id=self.mut_id, selection_coeff=0.1, @@ -2404,7 +2404,7 @@ def test_no_drawn_mutation(self): def test_bad_times(self): for start_time, end_time in [(-1, 0), (0, -1), (1, 100)]: with pytest.raises(ValueError): - stdpopsim.ext.ChangeMutationFitness( + stdpopsim.ChangeMutationFitness( start_time=start_time, end_time=end_time, single_site_id="irrelevant", @@ -2417,8 +2417,8 @@ def test_population_name(self): engine = stdpopsim.get_engine("slim") for pop in ["not present", 0]: extended_events = [ - stdpopsim.ext.ChangeMutationFitness( - start_time=stdpopsim.ext.GenerationAfter(self.T_mut), + stdpopsim.ChangeMutationFitness( + start_time=stdpopsim.GenerationAfter(self.T_mut), end_time=0, single_site_id=self.mut_id, population=pop, @@ -2450,13 +2450,13 @@ def test_bad_GenerationAfter_times(self): ]: with pytest.raises(ValueError): extended_events = [ - stdpopsim.ext.DrawMutation( + stdpopsim.DrawMutation( time=self.T_mut, single_site_id=self.mut_id, population="pop_0", ), - stdpopsim.ext.ChangeMutationFitness( - start_time=stdpopsim.ext.GenerationAfter(start_time), + stdpopsim.ChangeMutationFitness( + start_time=stdpopsim.GenerationAfter(start_time), end_time=end_time, single_site_id=self.mut_id, population="pop_0", @@ -2573,7 +2573,7 @@ def test_sweep(self, tmp_path): id=locus_id, coordinate=100, ) - extended_events = stdpopsim.ext.selective_sweep( + extended_events = stdpopsim.selective_sweep( single_site_id=locus_id, population="pop_0", mutation_generation_ago=mutation_generation_ago, @@ -2614,7 +2614,7 @@ def test_sweep_meets_min_freq_at_start(self, tmp_path): id=locus_id, coordinate=100, ) - extended_events = stdpopsim.ext.selective_sweep( + extended_events = stdpopsim.selective_sweep( single_site_id=locus_id, population="pop_0", mutation_generation_ago=mutation_generation_ago, @@ -2661,7 +2661,7 @@ def test_sweep_meets_min_freq_at_end(self, tmp_path): id=locus_id, coordinate=100, ) - extended_events = stdpopsim.ext.selective_sweep( + extended_events = stdpopsim.selective_sweep( single_site_id=locus_id, population="pop_0", mutation_generation_ago=mutation_generation_ago, @@ -2695,7 +2695,7 @@ def test_sweep_meets_min_freq_at_end(self, tmp_path): def test_sweep_with_negative_selection_coeff(self): with pytest.raises(ValueError, match="coefficient must be"): - stdpopsim.ext.selective_sweep( + stdpopsim.selective_sweep( single_site_id="irrelevant", population="irrelevant", mutation_generation_ago=1000, @@ -2705,7 +2705,7 @@ def test_sweep_with_negative_selection_coeff(self): def test_sweep_with_bad_AF_conditions(self): for start_freq, end_freq in zip([-0.1, 0.1], [0.1, -0.1]): with pytest.raises(ValueError, match="of the sweep must be in"): - stdpopsim.ext.selective_sweep( + stdpopsim.selective_sweep( single_site_id="irrelevant", population="irrelevant", mutation_generation_ago=1000, @@ -2717,7 +2717,7 @@ def test_sweep_with_bad_AF_conditions(self): with pytest.raises( ValueError, match="coincides with the introduction of the mutation" ): - stdpopsim.ext.selective_sweep( + stdpopsim.selective_sweep( single_site_id="irrelevant", population="irrelevant", mutation_generation_ago=1000, @@ -2740,7 +2740,7 @@ def test_global_sweep(self, tmp_path): id=locus_id, coordinate=100, ) - extended_events = stdpopsim.ext.selective_sweep( + extended_events = stdpopsim.selective_sweep( single_site_id=locus_id, population="pop_1", mutation_generation_ago=mutation_generation_ago, @@ -2795,7 +2795,7 @@ def test_local_sweep(self, tmp_path): id=locus_id, coordinate=100, ) - extended_events = stdpopsim.ext.selective_sweep( + extended_events = stdpopsim.selective_sweep( single_site_id=locus_id, population="pop_1", mutation_generation_ago=mutation_generation_ago, @@ -2850,7 +2850,7 @@ def test_sweeps_at_multiple_sites(self, tmp_path): id=locus_id, coordinate=coord, ) - extended_events += stdpopsim.ext.selective_sweep( + extended_events += stdpopsim.selective_sweep( single_site_id=locus_id, population=pop, mutation_generation_ago=mutation_generation_ago, @@ -2904,7 +2904,7 @@ def test_sweep_with_background_selection(self, tmp_path): id=locus_id, coordinate=100, ) - extended_events = stdpopsim.ext.selective_sweep( + extended_events = stdpopsim.selective_sweep( single_site_id=locus_id, population="pop_1", mutation_generation_ago=mutation_generation_ago, @@ -2971,7 +2971,7 @@ def test_stacked(self): if any(is_stacked): break selection_coeffs = [ - stdpopsim.ext.selection_coeff_from_mutation(ts, m) for m in ts.mutations() + stdpopsim.selection_coeff_from_mutation(ts, m) for m in ts.mutations() ] assert np.all( np.logical_or( @@ -2992,7 +2992,7 @@ def test_msprime(self): if ts.num_mutations > 0: break selection_coeffs = [ - stdpopsim.ext.selection_coeff_from_mutation(ts, m) for m in ts.mutations() + stdpopsim.selection_coeff_from_mutation(ts, m) for m in ts.mutations() ] assert np.allclose(selection_coeffs, 0.0) @@ -3008,9 +3008,9 @@ def test_errors(self): if ts.num_mutations > 0: break with pytest.raises(ValueError, match="must be a"): - stdpopsim.ext.selection_coeff_from_mutation("foo", next(ts.mutations())) + stdpopsim.selection_coeff_from_mutation("foo", next(ts.mutations())) with pytest.raises(ValueError, match="must be a"): - stdpopsim.ext.selection_coeff_from_mutation(ts, "bar") + stdpopsim.selection_coeff_from_mutation(ts, "bar") @pytest.mark.skipif(IS_WINDOWS, reason="SLiM not available on windows")