def test_dfe_errors(self): m1 = stdpopsim.MutationType() m2 = stdpopsim.MutationType() for bad_props in [["abc"], 1.0, [1.0], [0.2, 0.4, 0.4], [-0.1, -0.1]]: with pytest.raises(ValueError): _ = stdpopsim.DFE( id="abc", description="test test", long_description="test test test test", proportions=bad_props, mutation_types=[m1, m2], ) for bad_mut_types in ["abc", {}, [1.0, 2.0], [m1], m1, ["a", "b"]]: with pytest.raises(ValueError): _ = stdpopsim.DFE( id="abc", description="test test", long_description="test test test test", proportions=[0.6, 0.4], mutation_types=bad_mut_types, ) for bad_sums in [[-0.4, 0.5], [0.6, 0.8], [139487135987, 0.0], [0.2, 0.3]]: print(bad_sums) with pytest.raises(ValueError): _ = stdpopsim.DFE( id="abc", description="test test", long_description="test test test test", proportions=bad_sums, mutation_types=[m1, m2], )
def test_is_neutral(self): for neutral in (True, False): for dist in ("f", "e"): contig = stdpopsim.Contig.basic_contig(length=100) contig.clear_dfes() props = [0.3, 0.7] if neutral: s = 0 else: s = 0.1 mt = [ stdpopsim.MutationType(distribution_type=dist, distribution_args=[s]) for _ in props ] dfes = [ stdpopsim.DFE( id=str(j), description="test", long_description="test test", proportions=props, mutation_types=mt, ) for j in range(2) ] contig.add_dfe( intervals=np.array([[10, 30], [50, 100]]), DFE=dfes[0], ) contig.add_dfe(intervals=np.array([[30, 40]]), DFE=dfes[1]) # exponential with mean zero doesn't count as neutral! assert contig.is_neutral is (neutral and dist == "f")
def test_no_msprime_DFE(self): # test we cannot simulate a non-neutral DFE with msprime m1 = stdpopsim.ext.MutationType( dominance_coeff=0.2, distribution_type="e", distribution_args=[0.1], ) desc = "test test" long_desc = "test test 🐢" dfe = stdpopsim.DFE( id="abc", description=desc, long_description=long_desc, mutation_types=[m1], ) contig = stdpopsim.Contig.basic_contig( length=10000, mutation_rate=1e-6, ) contig.clear_genomic_mutation_types() contig.add_DFE( intervals=np.array([[0, contig.length / 2]], dtype="int"), DFE=dfe, ) model = stdpopsim.PiecewiseConstantSize(1000) samples = model.get_samples(2) engine = stdpopsim.get_engine("msprime") with pytest.raises(ValueError): _ = engine.simulate( model, contig, samples, )
def _KimDFE(): id = "Gamma_K17" description = "Deleterious Gamma DFE" long_description = """ Return neutral and negative MutationType()s representing a human DFE. Kim et al. (2017), https://doi.org/10.1534/genetics.116.197145 """ citations = [ stdpopsim.Citation( author="Kim et al.", year=2017, doi="https://doi.org/10.1534/genetics.116.197145", reasons="to be defined", # include the dfe_model reason ) ] neutral = stdpopsim.ext.MutationType() gamma_shape = 0.186 # shape gamma_mean = -0.01314833 # expected value h = 0.5 # dominance coefficient negative = stdpopsim.ext.MutationType( dominance_coeff=h, distribution_type="g", # gamma distribution distribution_args=[gamma_mean, gamma_shape], ) return stdpopsim.DFE( id=id, description=description, long_description=long_description, mutation_types=[neutral, negative], proportions=[0.3, 0.7], citations=citations, )
def test_too_many_dfes(self): contig = stdpopsim.Contig.basic_contig(length=100) contig.clear_DFEs() props = [0.3, 0.7] mt = [ stdpopsim.ext.MutationType(distribution_type="e", distribution_args=[1]) for _ in props ] dfes = [ stdpopsim.DFE( id=str(j), description="test", long_description="test test", proportions=props, mutation_types=mt, ) for j in range(3) ] contig.add_DFE(intervals=np.array([[10, 30], [50, 100]]), DFE=dfes[0], fill_neutral=False) contig.add_DFE(intervals=np.array([[30, 40]]), DFE=dfes[1], fill_neutral=False) with pytest.raises(ValueError): contig.add_DFE(intervals=np.array([[30, 40]]), DFE=dfes[2], fill_neutral=False)
def test_DFE_defaults(self): m1 = stdpopsim.ext.MutationType() desc = "test test" long_desc = "test test 🐢" dfe = stdpopsim.DFE( id="abc", description=desc, long_description=long_desc, mutation_types=[m1], proportions=[], ) assert isinstance(dfe.proportions, list) assert len(dfe.proportions) == 1 assert dfe.proportions[0] == 1
def test_add_DFE_errors(self): contig = stdpopsim.Contig.basic_contig(length=100) props = [0.3, 0.7] mt = [stdpopsim.ext.MutationType() for _ in props] # bad intervals dfe = stdpopsim.DFE( id="abc", description="test", long_description="test test", proportions=props, mutation_types=mt, ) with pytest.raises(ValueError): contig.add_DFE(np.array([10, 20]), dfe)
def test_non_neutral_contig(self): species = stdpopsim.get_species("HomSap") model = species.get_demographic_model("AshkSub_7G19") samples = model.get_samples(10) contig = stdpopsim.Contig.basic_contig(length=100) contig.clear_DFEs() props = [1] mt = [stdpopsim.ext.MutationType(distribution_type="f", distribution_args=[1])] dfes = [ stdpopsim.DFE( id=str(0), description="test", long_description="test test", proportions=props, mutation_types=mt, ) ] contig.add_DFE(intervals=np.array([[0, 50]]), DFE=dfes[0]) engine = stdpopsim.get_engine("msprime") with pytest.raises(ValueError): engine.simulate(model, contig, samples, seed=1) # okay now change selection coefficient to neutral contig.clear_DFEs() props = [1] mt = [stdpopsim.ext.MutationType(distribution_type="f", distribution_args=[0])] dfes = [ stdpopsim.DFE( id=str(0), description="test", long_description="test test", proportions=props, mutation_types=mt, ) ] contig.add_DFE(intervals=np.array([[0, 50]]), DFE=dfes[0]) engine = stdpopsim.get_engine("msprime") engine.simulate(model, contig, samples, seed=1)
def test_printing_DFE(self, capsys): m1 = stdpopsim.ext.MutationType() desc = "test test" long_desc = "test test 🐢" dfe = stdpopsim.DFE( id="abc", description=desc, long_description=long_desc, mutation_types=[m1], ) print(dfe) captured = capsys.readouterr() assert "DFE:\n" in captured.out assert "║" in captured.out assert "║ id = abc\n" in captured.out
def test_basic_DFE(self): desc = "test test" long_desc = "test test 🐢" for props in ([0.4, 0.6], [1.0, 0.0], [1.0], [1 / 3, 1 / 3, 1 / 3]): mt = [stdpopsim.ext.MutationType() for _ in props] dfe = stdpopsim.DFE( id="abc", description=desc, long_description=long_desc, proportions=props, mutation_types=mt, ) assert dfe.id == "abc" assert dfe.description == desc assert dfe.long_description == long_desc for a, b in zip(props, dfe.proportions): assert a == b for a, b in zip(mt, dfe.mutation_types): assert a == b
def test_add_dfe(self): for clear in (True, False): contig = stdpopsim.Contig.basic_contig(length=100) if clear: contig.clear_dfes() props = [0.3, 0.7] mt = [stdpopsim.MutationType() for _ in props] dfes = [ stdpopsim.DFE( id=str(j), description="test", long_description="test test", proportions=props, mutation_types=mt, ) for j in range(3) ] contig.add_dfe( intervals=np.array([[10, 30], [50, 100]]), DFE=dfes[0], ) contig.add_dfe(intervals=np.array([[30, 40]]), DFE=dfes[1]) contig.add_dfe(intervals=np.array([[20, 60]]), DFE=dfes[2]) assert len(contig.dfe_list) == 4 - clear assert len(contig.mutation_types()) == 7 - clear if clear: dfe_ids = [] true_ints = [] else: true_ints = [np.array([[0, 10]])] dfe_ids = ["neutral"] dfe_ids += [dfe.id for dfe in dfes] true_ints += [ np.array([[10, 20], [60, 100]]), np.empty((0, 2)), np.array([[20, 60]]), ] for d, i in zip(contig.dfe_list, dfe_ids): assert d.id == i for a1, a2 in zip(contig.interval_list, true_ints): assert np.all(a1.shape == a2.shape) assert np.all(a1 == a2) self.verify_dfe_breakpoints(contig)
def test_dfe_breakpoints(self): contig = stdpopsim.Contig.basic_contig(length=100) contig.clear_dfes() mt = stdpopsim.MutationType() for j in range(3): dfe = stdpopsim.DFE( id=str(j), description="test", long_description="test test", mutation_types=[mt], ) contig.add_dfe( np.array( [[(j + 1) * 5, (j + 1) * 10], [(j + 1) * 20, (j + 1) * 20 + 1]], dtype="int", ), dfe, ) self.verify_dfe_breakpoints(contig)
def test_is_neutral2(self): contig = stdpopsim.Contig.basic_contig(length=100) contig.clear_DFEs() props = [0.3, 0.7] mt = [stdpopsim.ext.MutationType() for _ in props] dfes = [ stdpopsim.DFE( id=str(j), description="test", long_description="test test", proportions=props, mutation_types=mt, ) for j in range(2) ] contig.add_DFE(intervals=np.array([[10, 30], [50, 100]]), DFE=dfes[0], fill_neutral=False) contig.add_DFE(intervals=np.array([[30, 40]]), DFE=dfes[1], fill_neutral=False) assert contig.is_neutral
def test_dfe_is_neutral(self): for neutral in (True, False): for dist in ("f", "e"): props = [0.3, 0.7] if neutral: svals = [0.0, 0.0] else: svals = [0.0, 0.1] mt = [ stdpopsim.MutationType(distribution_type=dist, distribution_args=[s]) for s in svals ] dfe = stdpopsim.DFE( id=0, description="test", long_description="test test", proportions=props, mutation_types=mt, ) assert dfe.is_neutral is (neutral and dist == "f")
def _HuberDFE(): id = "Gamma_H17" description = "Deleterious Gamma DFE" long_description = """ Return neutral and negative MutationType()s representing a H**o sapiens DFE. Huber et al. (2017), https://doi.org/10.1073/pnas.1619508114. DFE parameters are based on the Full Model described in Table S2, in which All Data (none of the listed filters) were used. """ # [this was a different filtering scheme than the Huber et al DroMel DFE ] citations = [ stdpopsim.Citation( author="Huber et al.", year=2017, doi="https://doi.org/10.1073/pnas.1619508114", reasons="to be defined", # include the dfe_model reason ) ] neutral = stdpopsim.MutationType() gamma_shape = 0.19 # shape gamma_mean = -0.014 # expected value h = 0.5 # dominance coefficient negative = stdpopsim.MutationType( dominance_coeff=h, distribution_type="g", # gamma distribution distribution_args=[gamma_mean, gamma_shape], ) return stdpopsim.DFE( id=id, description=description, long_description=long_description, mutation_types=[neutral, negative], proportions=[ 0.3, 0.7, ], # [0.3 and 0.7 were used in Xin's analysis, # but I couldn't find these values in the Huber paper] citations=citations, )
def _HuberDFE(): id = "Gamma_H17" description = "Deleterious Gamma DFE" long_description = """ Return neutral and negative MutationType()s representing a drosophila DFE. Huber et al. (2017), https://doi.org/10.1073/pnas.1619508114. DFE parameters are based on the Full model described in Table S2, in which singletons are excluded and a recent mutation rate estimate is used (mu=3x10e-9, Keightley 2014). """ citations = [ stdpopsim.Citation( author="Huber et al.", year=2017, doi="https://doi.org/10.1073/pnas.1619508114", reasons="to be defined", # include the dfe_model reason ) ] neutral = stdpopsim.ext.MutationType() gamma_shape = 0.33 # shape gamma_mean = -3.96e-04 # expected value h = 0.5 # dominance coefficient negative = stdpopsim.ext.MutationType( dominance_coeff=h, distribution_type="g", # gamma distribution distribution_args=[gamma_mean, gamma_shape], ) return stdpopsim.DFE( id=id, description=description, long_description=long_description, mutation_types=[neutral, negative], proportions=[0.26, 0.74], # LNS = 2.85 x LS citations=citations, )
class TestContig(object): example_dfe = stdpopsim.DFE( id="abc", description="example DFE", long_description="test test beep boop beep", proportions=[0.3, 0.7], mutation_types=[stdpopsim.MutationType() for _ in range(2)], ) def verify_dfe_breakpoints(self, contig): breaks, dfe_labels = contig.dfe_breakpoints() for j, intervals in enumerate(contig.interval_list): for left, right in intervals: assert left in breaks assert right in breaks k = np.searchsorted(breaks, left) assert dfe_labels[k] == j def test_default_dfe(self): contig = stdpopsim.Contig.basic_contig(length=100) assert len(contig.dfe_list) == 1 assert len(contig.interval_list) == 1 assert contig.dfe_list[0].id == "neutral" assert np.all( contig.interval_list[0] == np.array([[0, contig.length]])) def test_add_dfe_errors(self): contig = stdpopsim.Contig.basic_contig(length=100) # bad intervals with pytest.raises(ValueError): contig.add_dfe(np.array([10, 20]), self.example_dfe) with pytest.raises(ValueError): contig.add_dfe("abc", self.example_dfe) def test_dfe_breakpoints(self): contig = stdpopsim.Contig.basic_contig(length=100) contig.clear_dfes() mt = stdpopsim.MutationType() for j in range(3): dfe = stdpopsim.DFE( id=str(j), description="test", long_description="test test", mutation_types=[mt], ) contig.add_dfe( np.array( [[(j + 1) * 5, (j + 1) * 10], [(j + 1) * 20, (j + 1) * 20 + 1]], dtype="int", ), dfe, ) self.verify_dfe_breakpoints(contig) def test_add_dfe(self): for clear in (True, False): contig = stdpopsim.Contig.basic_contig(length=100) if clear: contig.clear_dfes() props = [0.3, 0.7] mt = [stdpopsim.MutationType() for _ in props] dfes = [ stdpopsim.DFE( id=str(j), description="test", long_description="test test", proportions=props, mutation_types=mt, ) for j in range(3) ] contig.add_dfe( intervals=np.array([[10, 30], [50, 100]]), DFE=dfes[0], ) contig.add_dfe(intervals=np.array([[30, 40]]), DFE=dfes[1]) contig.add_dfe(intervals=np.array([[20, 60]]), DFE=dfes[2]) assert len(contig.dfe_list) == 4 - clear assert len(contig.mutation_types()) == 7 - clear if clear: dfe_ids = [] true_ints = [] else: true_ints = [np.array([[0, 10]])] dfe_ids = ["neutral"] dfe_ids += [dfe.id for dfe in dfes] true_ints += [ np.array([[10, 20], [60, 100]]), np.empty((0, 2)), np.array([[20, 60]]), ] for d, i in zip(contig.dfe_list, dfe_ids): assert d.id == i for a1, a2 in zip(contig.interval_list, true_ints): assert np.all(a1.shape == a2.shape) assert np.all(a1 == a2) self.verify_dfe_breakpoints(contig) @pytest.mark.skip(reason="TODO allow more flexible inputs") def test_add_dfe_interval_formats(self): L = 50818 for intervals in ( [[0, L]], [[0, int(0.2 * L)]], ([0, int(0.2 * L)], [int(0.6 * L), L]), ): contig = stdpopsim.Contig.basic_contig(length=L) contig.add_dfe(intervals=intervals, DFE=self.example_dfe) np.testing.assert_array_equal(intervals, contig.interval_list[1]) def test_is_neutral(self): for neutral in (True, False): for dist in ("f", "e"): contig = stdpopsim.Contig.basic_contig(length=100) contig.clear_dfes() props = [0.3, 0.7] if neutral: s = 0 else: s = 0.1 mt = [ stdpopsim.MutationType(distribution_type=dist, distribution_args=[s]) for _ in props ] dfes = [ stdpopsim.DFE( id=str(j), description="test", long_description="test test", proportions=props, mutation_types=mt, ) for j in range(2) ] contig.add_dfe( intervals=np.array([[10, 30], [50, 100]]), DFE=dfes[0], ) contig.add_dfe(intervals=np.array([[30, 40]]), DFE=dfes[1]) # exponential with mean zero doesn't count as neutral! assert contig.is_neutral is (neutral and dist == "f")