47
47
import itertools
48
48
import collections
49
49
import contextlib
50
+ import random
50
51
51
52
import stdpopsim
52
53
import numpy as np
122
123
}
123
124
}
124
125
125
- // Check if burn- in has completed.
126
+ // Check if burn in has completed.
126
127
1 {
127
128
if (!check_coalescence) {
128
129
setup();
152
153
sim.registerEarlyEvent(NULL, "{setup();}", g, g);
153
154
} else {
154
155
if (sim.generation == 1)
155
- dbg("Waiting for burn- in...");
156
+ dbg("Waiting for burn in...");
156
157
// Reschedule the current script block 10 generations hence.
157
158
// XXX: find a less arbitrary generation interval.
158
159
g = sim.generation + 10;
165
166
166
167
dbg("setup()");
167
168
168
- // Once burn- in is complete, we know the starting generation (which
169
+ // Once burn in is complete, we know the starting generation (which
169
170
// corresponds to T_0) and can thus calculate the generation
170
171
// for each remaining event.
171
172
G_start = sim.generation;
@@ -554,18 +555,19 @@ def get_version(self):
554
555
return s .split ()[2 ].decode ("ascii" ).rstrip ("," )
555
556
556
557
def simulate (
557
- self , demographic_model = None , contig = None , samples = None ,
558
- seed = None , verbosity = 0 ,
559
- slim_script = False , slim_scaling_factor = 10 , slim_no_burnin = False ,
560
- slim_path = None ,
561
- ** kwargs ):
558
+ self , demographic_model = None , contig = None , samples = None , seed = None ,
559
+ verbosity = 0 , slim_path = None , slim_script = False , slim_scaling_factor = 10 ,
560
+ slim_no_recapitation = False , slim_no_burnin = False , ** kwargs ):
562
561
"""
563
562
Simulate the demographic model using SLiM.
564
563
See :meth:`.Engine.simulate()` for definitions of the
565
564
``demographic_model``, ``contig``, and ``samples`` parameters.
566
565
567
566
:param seed: The seed for the random number generator.
568
567
:type seed: int
568
+ :param slim_path: The full path to the slim executable, or the name of
569
+ a command in the current PATH.
570
+ :type slim_path: str
569
571
:param slim_script: If true, the simulation will not be executed.
570
572
Instead the generated SLiM script will be printed to stdout.
571
573
:type slim_script: bool
@@ -576,23 +578,34 @@ def simulate(
576
578
See SLiM manual: `5.5 Rescaling population sizes to improve
577
579
simulation performance.`
578
580
:type slim_scaling_factor: float
579
- :param slim_no_burnin: Do not perform a `burn in` at the start of the
580
- simulation. The default `burn in` behaviour is to wait until all
581
- individuals in the ancestral population(s) have a common ancestor
582
- within their respective population, and then wait another 10*N
583
- generations.
581
+ :param slim_no_recapitation: Do an explicit burn in, and add
582
+ mutations, within the SLiM simulation. This may be much slower than
583
+ the defaults (recapitation and neutral mutation overlay with
584
+ msprime). The burn in behaviour is to wait until all individuals in
585
+ the ancestral populations have a common ancestor within their
586
+ respective population, and then wait another 10*N generations.
587
+ :type slim_no_recapitation: bool
588
+ :param slim_no_burnin: Do not perform a burn in at the start of the
589
+ simulation. This option is only relevant when
590
+ ``slim_no_recapitation=True``.
584
591
:type slim_no_burnin: bool
585
- :param slim_path: The full path to the slim executable, or the name of
586
- a command in the current PATH.
587
- :type slim_path: str
588
592
"""
589
593
590
594
run_slim = not slim_script
591
- check_coalescence = not slim_no_burnin
595
+ do_recap = not slim_no_recapitation
596
+ check_coalescence = slim_no_recapitation and not slim_no_burnin
592
597
593
598
if slim_path is None :
594
599
slim_path = self .slim_path ()
595
600
601
+ if do_recap :
602
+ mutation_rate = contig .mutation_rate
603
+ # Ensure no mutations are introduced by SLiM.
604
+ contig = stdpopsim .Contig (
605
+ recombination_map = contig .recombination_map ,
606
+ mutation_rate = 0 ,
607
+ genetic_map = contig .genetic_map )
608
+
596
609
slim_cmd = [slim_path ]
597
610
if seed is not None :
598
611
slim_cmd .extend (["-s" , f"{ seed } " ])
@@ -625,41 +638,28 @@ def script_file_f():
625
638
626
639
ts = pyslim .load (ts_file .name )
627
640
628
- # random.seed(seed)
629
- # s1, s2 = random.randint(1,2**32-1), random.randint(1,2**32-1)
641
+ if do_recap :
642
+ rng = random .Random (seed )
643
+ s1 , s2 = rng .randrange (1 , 2 ** 32 ), rng .randrange (1 , 2 ** 32 )
630
644
631
- # Recapitation.
632
- # r = recombination_map.mean_recombination_rate
633
- # N0 = ?
634
- # ts = ts.recapitate(Ne=N0, recombination_rate=r, random_seed=s1)
645
+ # Recapitation.
646
+ r_map = contig .recombination_map
647
+ pop_configs = demographic_model .population_configurations
648
+ ts = ts .recapitate (
649
+ recombination_rate = r_map .mean_recombination_rate ,
650
+ population_configurations = pop_configs ,
651
+ random_seed = s1 )
635
652
636
653
ts = simplify_remembered (ts )
637
654
638
- # Add neutral mutations.
639
- # ts = pyslim.SlimTreeSequence(msprime.mutate(ts, rate=mutation_rate,
640
- # keep=True, random_seed=s2))
655
+ if do_recap :
656
+ # Add neutral mutations.
657
+ ts = pyslim .SlimTreeSequence (msprime .mutate (
658
+ ts , rate = mutation_rate , keep = True , random_seed = s2 ))
641
659
642
660
return ts
643
661
644
662
def add_arguments (self , parser ):
645
- parser .add_argument (
646
- "--slim-scaling-factor" , metavar = "Q" , default = 10 , type = float ,
647
- help = "Rescale model parameters by Q to speed up simulation "
648
- "See SLiM manual: `5.5 Rescaling population sizes to "
649
- "improve simulation performance`. "
650
- "[%(default)s]." )
651
- parser .add_argument (
652
- "--slim-script" , action = "store_true" , default = False ,
653
- help = "Write script to stdout and exit without running SLiM." )
654
- parser .add_argument (
655
- "--slim-no-burnin" , action = "store_true" , default = False ,
656
- help = "Don't wait for coalescence in SLiM before proceeding." )
657
- # parser.add_argument(
658
- # "--pyslim-recap", action="store_true", default=False,
659
- # help="Recapitate trees with pyslim, and overlay neutral "
660
- # "mutations with msprime, after running SLiM."
661
- # "This implies --slim-no-burnin.")
662
-
663
663
def slim_exec (path ):
664
664
# Hack to set the SLIM environment variable at parse time,
665
665
# before get_version() can be called.
@@ -668,6 +668,26 @@ def slim_exec(path):
668
668
parser .add_argument (
669
669
"--slim-path" , metavar = "PATH" , type = slim_exec , default = None ,
670
670
help = "Full path to `slim' executable." )
671
+ parser .add_argument (
672
+ "--slim-script" , action = "store_true" , default = False ,
673
+ help = "Write script to stdout and exit without running SLiM." )
674
+ parser .add_argument (
675
+ "--slim-scaling-factor" , metavar = "Q" , default = 10 , type = float ,
676
+ help = "Rescale model parameters by Q to speed up simulation. "
677
+ "See SLiM manual: `5.5 Rescaling population sizes to "
678
+ "improve simulation performance`. "
679
+ "[default=%(default)s]." )
680
+ parser .add_argument (
681
+ "--slim-no-recapitation" , action = "store_true" , default = False ,
682
+ help = "Explicitly wait for coalescence, and add "
683
+ "mutations, within the SLiM simulation. This may be much "
684
+ "slower than the defaults (recapitation and neutral mutation "
685
+ "overlay with msprime)." )
686
+ parser .add_argument (
687
+ "--slim-no-burnin" , action = "store_true" , default = False ,
688
+ help = "Don't wait for coalescence in SLiM before proceeding. "
689
+ "This option is only relevant in combination with "
690
+ "--slim-no-recapitation." )
671
691
672
692
673
693
stdpopsim .register_engine (_SLiMEngine ())
0 commit comments