Beispiel #1
0
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

# This script is an example in the simuPOP user's guide. Please refer to
# the user's guide (http://simupop.sourceforge.net/manual) for a detailed
# description of this example.
#

import simuPOP as sim
import time
pop = sim.Population(1000, loci=10)
pop.dvars().init_time = time.time()
pop.dvars().last_time = time.time()
exec('import time', pop.vars(), pop.vars())
pop.evolve(
    initOps=sim.InitSex(),
    matingScheme=sim.RandomMating(),
    postOps=[
        sim.IfElse('time.time() - last_time > 5', [
            sim.PyEval(r'"Gen: %d\n" % gen'),
            sim.PyExec('last_time = time.time()')
            ]),
        sim.TerminateIf('time.time() - init_time > 20')
    ]
)
        

Beispiel #2
0
import simuOpt
simuOpt.setOptions(quiet=True, alleleType='long')
import simuPOP as sim
pop = sim.Population(size=1000, loci=[1])
simu = sim.Simulator(pop, 5)
simu.evolve(
    initOps=[
        sim.InitSex(),
        sim.PyExec('introGen=[]')
    ],
    preOps=[
        sim.Stat(alleleFreq=0),
        sim.IfElse('alleleFreq[0][1] == 0', ifOps=[
            sim.PointMutator(loci=0, allele=1, inds=0),
            sim.PyExec('introGen.append(gen)')
        ]),
        sim.TerminateIf('alleleFreq[0][1] >= 0.05')
    ],
    matingScheme=sim.RandomMating()
)
# number of attempts
print([len(x.dvars().introGen) for x in simu.populations()])
# age of mutant
print([x.dvars().gen - x.dvars().introGen[-1] for x in simu.populations()])
Beispiel #3
0
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

# This script is an example in the simuPOP user's guide. Please refer to
# the user's guide (http://simupop.sourceforge.net/manual) for a detailed
# description of this example.
#

import simuPOP as sim
simu = sim.Simulator(sim.Population(50, loci=[10], ploidy=1),
    rep=3)
simu.evolve(gen = 5)
simu.dvars(0).gen
simu.evolve(
    initOps=[sim.InitGenotype(freq=[0.5, 0.5])],
    matingScheme=sim.RandomSelection(),
    postOps=[
        sim.Stat(alleleFreq=5),
        sim.IfElse('alleleNum[5][0] == 0',
            sim.PyEval(r"'Allele 0 is lost in rep %d at gen %d\n' % (rep, gen)")),
        sim.IfElse('alleleNum[5][0] == 50',
            sim.PyEval(r"'Allele 0 is fixed in rep %d at gen %d\n' % (rep, gen)")),
        sim.TerminateIf('len(alleleNum[5]) == 1'),
    ],
)
[simu.dvars(x).gen for x in range(3)]

Beispiel #4
0
def simuGWAS(pop,
             mutaRate=1.8e-8,
             recIntensity=1e-8,
             migrRate=0.0001,
             expandGen=500,
             expandSize=[10000],
             DPL=[],
             curFreq=[],
             fitness=[1, 1, 1],
             scale=1,
             logger=None):
    # handling scaling...
    mutaRate *= scale
    recIntensity *= scale
    migrRate *= scale
    expandGen = int(expandGen / scale)
    fitness = [1 + (x - 1) * scale for x in fitness]
    pop.dvars().scale = scale
    # Demographic function
    demoFunc = linearExpansion(pop.subPopSizes(), expandSize, expandGen)
    # define a trajectory function
    trajFunc = None
    introOps = []
    if len(DPL) > 0:
        stat(pop, alleleFreq=DPL, vars='alleleFreq_sp')
        currentFreq = []
        for sp in range(pop.numSubPop()):
            for loc in pop.lociByNames(DPL):
                currentFreq.append(pop.dvars(sp).alleleFreq[loc][1])
        # if there is no existing mutants at DPL
        if sum(currentFreq) == 0.:
            endFreq = [(x - min(0.01, x / 5.), x + min(0.01, x / 5.,
                                                       (1 - x) / 5.))
                       for x in curFreq]
            traj = simulateForwardTrajectory(N=demoFunc,
                                             beginGen=0,
                                             endGen=expandGen,
                                             beginFreq=currentFreq,
                                             endFreq=endFreq,
                                             nLoci=len(DPL),
                                             fitness=fitness,
                                             maxAttempts=1000,
                                             logger=logger)
            introOps = []
        else:
            traj = simulateBackwardTrajectory(N=demoFunc,
                                              endGen=expandGen,
                                              endFreq=curFreq,
                                              nLoci=len(DPL),
                                              fitness=fitness,
                                              minMutAge=1,
                                              maxMutAge=expandGen,
                                              logger=logger)
            introOps = traj.mutators(loci=DPL)
        if traj is None:
            raise SystemError(
                'Failed to generated trajectory after 1000 attempts.')
        trajFunc = traj.func()
    if pop.numSubPop() > 1:
        pop.addInfoFields('migrate_to')
    pop.dvars().scale = scale
    pop.evolve(
        initOps=sim.InitSex(),
        preOps=[
            sim.SNPMutator(u=mutaRate, v=mutaRate),
            sim.IfElse(
                pop.numSubPop() > 1,
                sim.Migrator(
                    rate=migrSteppingStoneRates(migrRate, pop.numSubPop()))),
        ] + introOps,
        matingScheme=sim.ControlledRandomMating(
            loci=DPL,
            alleles=[1] * len(DPL),
            freqFunc=trajFunc,
            ops=sim.Recombinator(intensity=recIntensity),
            subPopSize=demoFunc),
        postOps=[
            sim.Stat(popSize=True, structure=range(pop.totNumLoci())),
            sim.PyEval(
                r'"After %3d generations, size=%s\n" % ((gen + 1 )* scale, subPopSize)'
            ),
            sim.IfElse(pop.numSubPop() > 1,
                       sim.PyEval(r"'F_st = %.3f\n' % F_st", step=10),
                       step=10),
        ],
        gen=expandGen)
    return pop
Beispiel #5
0
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

# This script is an example in the simuPOP user's guide. Please refer to
# the user's guide (http://simupop.sourceforge.net/manual) for a detailed
# description of this example.
#

import simuPOP as sim
pop = sim.Population(size=1000, loci=1)
verbose = True
pop.evolve(
    initOps=[
        sim.InitSex(),
        sim.InitGenotype(freq=[0.5, 0.5]),
    ],
    matingScheme=sim.RandomMating(),
    postOps=sim.IfElse(verbose,
        ifOps=[
            sim.Stat(alleleFreq=0),
            sim.PyEval(r"'Gen: %3d, allele freq: %.3f\n' % (gen, alleleFreq[0][1])",
                step=5)
        ],
        begin=10),
    gen = 30
)

# use a pedigree object recovered from a file saved by operator PedigreeTagger
ped = sim.loadPedigree('structured.ped')
# create a top most population, but we do not need all of them
# so we record only used individuals
IDs = [x.ind_id for x in ped.allIndividuals(ancGens=ped.ancestralGens())]
sex = [x.sex() for x in ped.allIndividuals(ancGens=ped.ancestralGens())]
# create a population, this time with genotype. Note that we do not need
# populaton structure because PedigreeMating disregard population structure.
pop = sim.Population(size=len(IDs), loci=1000, infoFields='ind_id')
# manually initialize ID and sex
sim.initInfo(pop, IDs, infoFields='ind_id')
sim.initSex(pop, sex=sex)
pop.evolve(
    initOps=sim.InitGenotype(freq=[0.4, 0.6]),
    # we do not need migration, or set number of offspring,
    # or demographic model, but we do need a genotype transmitter
    matingScheme=sim.PedigreeMating(ped, 
        ops=sim.IfElse(lambda mom: mom is None,
                sim.CloneGenoTransmitter(),
                sim.MendelianGenoTransmitter())
    ),
    gen=100
)
# 
print(pop.indInfo('ind_id')[:5])
print([pop.individual(x).sex() for x in range(5)])
# The pedigree object does not have population structure
print(pop.subPopSizes())

Beispiel #7
0
def simuRareVariants(regions,
                     N,
                     G,
                     mu,
                     selDist,
                     selCoef,
                     selModel='exponential',
                     recRate=0,
                     splitTo=[1],
                     splitAt=0,
                     migrRate=0,
                     steps=[100],
                     mutationModel='finite_sites',
                     initPop='',
                     extMutantFile='',
                     addMutantsAt=0,
                     postHook=None,
                     statFile='',
                     popFile='',
                     markerFile='',
                     mutantFile='',
                     genotypeFile='',
                     verbose=1,
                     logger=None):
    '''
    Please refer to simuRareVariants.py -h for a detailed description of all parameters.
    Note that a user-defined function can be passed to parameter selDist to specify
    arbitrary distribution of fitness. A script-only feature is that a Python function
    can be provided through parameter postHook to process the population at each generation.
    '''
    #
    # convert regions to start/end positions
    ranges = []
    chromTypes = []
    for region in regions:
        start, end = [int(x) for x in region.split(':')[1].split('..')]
        ranges.append((start, end + 1))
        if region.split(':')[0] == 'chrX':
            chromTypes.append(sim.CHROMOSOME_X)
            if len(regions) > 1:
                raise ValueError(
                    'The current implementation only allows one region if it is on chromosome X'
                )
            logger.info('Chromosome {} is on chromosome X'.format(region))
        elif region.split(':')[0] == 'chrY':
            raise ValueError(
                'The current implementation does not support chromosome Y')
            chromTypes.append(sim.CHROMOSOME_Y)
            logger.info('Chromosome {} is on chromosome Y'.format(region))
        else:
            chromTypes.append(sim.AUTOSOME)
    if logger:
        logger.info('%s regions with a total length of %d basepair.' %
                    (len(ranges), sum([x[1] - x[0] for x in ranges])))
    #
    # set default parameter
    if selCoef is None:
        # set default parameters
        if selDist == 'mixed_gamma':
            selCoef = [0.0186, 0.0001, 0.184, 0.160 * 2, 0.5, 0.0001, 0.1]
        elif selDist == 'mixed_gamma1':
            selCoef = [0, -1, 0.562341, 0.01, 0.5, 0.00001, 0.1]
        elif selDist == 'gamma1':
            selCoef = [0.23, 0.185 * 2, 0.5]
        elif selDist == 'gamma2':
            selCoef = [0.184, 0.160 * 2, 0.5]
        elif selDist == 'gamma3':
            selCoef = [0.206, 0.146 * 2, 0.5]
        elif selDist == 'constant':
            selCoef = [0.01, 0.5]
        elif not isinstance(selDist, collections.Callable):
            raise ValueError("Unsupported random distribution")
    else:
        # force to list type
        selCoef = list(selCoef)
    if len(steps) == 0:
        # at the end of each stage
        steps = G
    elif len(steps) == 1:
        # save step for each stage
        steps = steps * len(G)
    # use a right selection operator.
    collector = fitnessCollector()
    mode = {
        'multiplicative': sim.MULTIPLICATIVE,
        'additive': sim.ADDITIVE,
        'exponential': sim.EXPONENTIAL
    }[selModel]
    #
    if type(popFile) == str:
        popFile = [popFile, -1]
    #
    if isinstance(selDist, collections.Callable):
        mySelector = MutSpaceSelector(selDist=selDist,
                                      mode=mode,
                                      output=collector.getCoef)
    elif selDist == 'mixed_gamma':
        mySelector = MutSpaceSelector(selDist=mixedGamma(selCoef),
                                      mode=mode,
                                      output=collector.getCoef)
    elif selDist == 'mixed_gamma1':
        mySelector = MutSpaceSelector(selDist=mixedGamma1(selCoef),
                                      mode=mode,
                                      output=collector.getCoef)
    elif selDist.startswith('gamma'):
        mySelector = MutSpaceSelector(selDist=[sim.GAMMA_DISTRIBUTION] +
                                      selCoef,
                                      mode=mode,
                                      output=collector.getCoef)
    elif selDist == 'constant':
        if selCoef == 0:
            mySelector = sim.NoneOp()
        else:
            mySelector = MutSpaceSelector(selDist=[sim.CONSTANT] + selCoef,
                                          mode=mode,
                                          output=collector.getCoef)
    #
    # Evolve
    if os.path.isfile(initPop):
        if logger:
            logger.info('Loading initial population %s...' % initPop)
        pop = sim.loadPopulation(initPop)
        if pop.numChrom() != len(regions):
            raise ValueError(
                'Initial population %s does not have specified regions.' %
                initPop)
        for ch, reg in enumerate(regions):
            if pop.chromName(ch) != reg:
                raise ValueError(
                    'Initial population %s does not have region %s' %
                    (initPop, reg))
        pop.addInfoFields(['fitness', 'migrate_to'])
    else:
        pop = sim.Population(size=N[0],
                             loci=[10] * len(regions),
                             chromNames=regions,
                             infoFields=['fitness', 'migrate_to'],
                             chromTypes=chromTypes)
    if logger:
        startTime = time.clock()
    #
    progGen = []
    # 0, G[0], G[0]+G[1], ..., sum(G)
    Gens = [sum(G[:i]) for i in range(len(G) + 1)]
    for i in range(len(Gens) - 1):
        progGen += list(range(Gens[i], Gens[i + 1], steps[i]))
    pop.evolve(
        initOps=sim.InitSex(),
        preOps=[
            sim.PyOutput('''Statistics outputted are
1. Generation number,
2. population size (a list),
3. number of segregation sites,
4. average number of segregation sites per individual
5. average allele frequency * 100
6. average fitness value
7. minimal fitness value of the parental population
''', at = 0)] + \
            [sim.PyOutput('Starting stage %d\n' % i, at = Gens[i]) for i in range(0, len(Gens))] + \
            # add alleles from an existing population

            [sim.IfElse(extMutantFile != '',
                ifOps = [
                    sim.PyOutput('Loading and converting population %s' % extMutantFile),
                    sim.PyOperator(func=addMutantsFrom, param=(extMutantFile, regions, logger)),
                ], at = addMutantsAt),
            # revert alleles at fixed loci to wildtype
            MutSpaceRevertFixedSites(),
            # mutate in a region at rate mu, if verbose > 2, save mutation events to a file
            MutSpaceMutator(mu, ranges, {'finite_sites':1, 'infinite_sites':2}[mutationModel],
                output='' if verbose < 2 else '>>mutations.lst'),
            # selection on all loci
            mySelector,
            # output statistics in verbose mode
            sim.IfElse(verbose > 0, ifOps=[
                sim.Stat(popSize=True, meanOfInfo='fitness', minOfInfo='fitness'),
                NumSegregationSites(),
                sim.PyEval(r'"%5d %s %5d %.6f %.6f %.6f %.6f\n" '
                    '% (gen, subPopSize, numSites, avgSites, avgFreq*100, meanOfInfo["fitness"], minOfInfo["fitness"])',
                    output='>>' + statFile),
                ], at = progGen
            ),
            sim.IfElse(len(splitTo) > 1,
                sim.Migrator(rate=migrIslandRates(migrRate, len(splitTo)),
                    begin=splitAt + 1)
            ),
        ],
        matingScheme=sim.RandomMating(ops=MutSpaceRecombinator(recRate, ranges),
            subPopSize=multiStageDemoFunc(N, G, splitTo, splitAt)),
        postOps = [
            sim.NoneOp() if postHook is None else sim.PyOperator(func=postHook),
            sim.SavePopulation(popFile[0], at=popFile[1]),
        ],
        finalOps=[
            # revert fixed sites so that the final population does not have fixed sites
            MutSpaceRevertFixedSites(),
            sim.IfElse(verbose > 0, ifOps=[
                # statistics after evolution
                sim.Stat(popSize=True),
                NumSegregationSites(),
                sim.PyEval(r'"%5d %s %5d %.6f %.6f %.6f %.6f\n" '
                    '% (gen+1, subPopSize, numSites, avgSites, avgFreq*100, meanOfInfo["fitness"], minOfInfo["fitness"])',
                    output='>>' + statFile),
                sim.PyEval(r'"Simulated population has %d individuals, %d segregation sites.'
                           r'There are on average %.1f sites per individual. Mean allele frequency is %.4f%%.\n"'
                           r'% (popSize, numSites, avgSites, avgFreq*100)'),
            ]),
        ],
        gen = Gens[-1]
    )
    # record selection coefficients to population
    if len(collector.selCoef) == 0:
        # this must be the neutral case where a NonOp has been used.
        pop.dvars().selCoef = 0
    else:
        pop.dvars().selCoef = collector.selCoef
    # re-save the file with the added selCoef
    if popFile[-1] == -1:
        pop.save(popFile[0])
    #
    if logger:
        logger.info('Population simulation takes %.2f seconds' %
                    (time.clock() - startTime))
    if markerFile or genotypeFile:
        if logger:
            logger.info('Saving marker information to file %s' % markerFile)
        mutants = saveMarkerInfoToFile(pop, markerFile, logger)
        if genotypeFile:
            if logger:
                logger.info('Saving genotype in .ped format to file %s' %
                            genotypeFile)
            saveGenotypeToFile(pop, genotypeFile, mutants, logger)
    if mutantFile:
        if logger:
            logger.info('Saving mutants to file %s' % mutantFile)
        saveMutantsToFile(pop, mutantFile, logger=logger)
    return pop
Beispiel #8
0
def evolvePop(model,
              N0,
              N1,
              G0,
              G1,
              initSpec,
              mu,
              k,
              fitness,
              m=1,
              migrRate=0,
              logfile='',
              sp_logfile='',
              **kwargs):
    '''Evolve a population with specified allele frequencies (parameter
    initSpec) using given demographic (model, N0, N1, G0, G1, m), mutation
    (a k-allele model with parameters mu and k) and natural selection models
    (a multi-locus selection model with fitness vector s). Total disease
    allele frequency and effective number of alleles in the population
    and in all subpopulations are recorded if names of log files are provided.
    This function returns a tuple of these two statistics at the end of the
    evolution. Additional keyword arguments could be used to control when and
    how often statisitcs are outputed.
    '''
    L = len(fitness) // 3
    if not hasattr(mu, '__iter__'):  # if a single mutation rate is given
        mu = [mu] * L
    # Create expressions to output f_e and ne at all loci, which are
    #   "%d\t%.4f\t%.4f\n" % (gen, 1-alleleFreq[x][0], ne[x])
    # for locus x.
    statExpr = '"%d' + r'\t%.4f\t%.4f'*L + r'\n" % (gen,' + \
        ', '.join(['1-alleleFreq[%d][0], ne[%d]' % (x, x) for x in range(L)]) + ')'
    demo_func = demoModel(model, N0, N1, G0, G1, m)
    pop = sim.Population(size=demo_func(0),
                         loci=[1] * L,
                         infoFields=['fitness', 'migrate_to'])
    pop.evolve(
        initOps=[sim.InitSex(), sim.InitGenotype(freq=initSpec)],
        preOps=[
            sim.KAlleleMutator(k=k, rates=mu, loci=range(L)),
            sim.MlSelector([
                sim.MaSelector(loci=i, fitness=fitness[3 * i:3 * (i + 1)])
                for i in range(L)
            ],
                           mode=sim.MULTIPLICATIVE),
            sim.Migrator(rate=migrIslandRates(migrRate, m), begin=G0 + 1),
        ],
        matingScheme=sim.RandomMating(subPopSize=demo_func),
        postOps=[
            sim.IfElse(
                logfile != '' or sp_logfile != '',
                Ne(loci=sim.ALL_AVAIL,
                   vars=['ne'] if m == 1 else ['ne', 'ne_sp']), **kwargs),
            sim.IfElse(logfile != '',
                       sim.PyEval(statExpr, output='>>' + logfile), **kwargs),
            sim.IfElse(
                m > 1 and sp_logfile != '',
                sim.PyEval(
                    statExpr,
                    output='>>' + sp_logfile,
                    # subPops=sim.ALL_AVAIL will evalulate the expression in each
                    # subpopulation's local namespace (vars(sp)).
                    subPops=sim.ALL_AVAIL,
                    begin=G0),
                **kwargs),
        ],
        finalOps=Ne(loci=sim.ALL_AVAIL),
        gen=G0 + G1)
    return tuple([1-pop.dvars().alleleFreq[x][0] for x in range(L)] + \
        [pop.dvars().ne[x] for x in range(L)])
Beispiel #9
0
#

import simuPOP as sim
# redirect system stderr
import sys
debugOutput = open('debug.txt', 'w')
old_stderr = sys.stderr
sys.stderr = debugOutput
# start simulation
simu = sim.Simulator(sim.Population(100, loci=1), rep=5)
simu.evolve(
    initOps=[sim.InitSex(), sim.InitGenotype(freq=[0.1, 0.9])],
    matingScheme=sim.RandomMating(),
    postOps=[
        sim.Stat(alleleFreq=0),
        sim.IfElse(
            'alleleNum[0][0] == 0',
            ifOps=[
                # the is None part makes the function return True
                sim.PyOperator(lambda: sim.turnOnDebug("DBG_MUTATOR") is None),
                sim.PointMutator(loci=0, allele=0, inds=0),
            ],
            elseOps=sim.PyOperator(
                lambda: sim.turnOffDebug("DBG_MUTATOR") is None)),
    ],
    gen=100)
# replace standard stdandard error
sys.stderr = old_stderr
debugOutput.close()
print(''.join(open('debug.txt').readlines()[:5]))
Beispiel #10
0
def MutationSelection(N=1000,
                      generations=10000,
                      X_loci=100,
                      A_loci=0,
                      AgingModel='two_phases',
                      seed=2001,
                      reps=1,
                      InitMutFreq=0.001,
                      aging_a1=0.003,
                      aging_a2=0.05,
                      aging_b=-0.019,
                      aging_k=0.1911,
                      MutRate=0.001,
                      StatsStep=100,
                      OutPopPrefix='z1',
                      PrintFreqs=False,
                      debug=False):
    '''Creates and evolves a population to reach mutation-selection balance.'''
    if debug:
        sim.turnOnDebug('DBG_ALL')
    else:
        sim.turnOffDebug('DBG_ALL')
    sim.setRNG('mt19937', seed)
    pop = sim.Population(N,
                         loci=[X_loci, A_loci],
                         ploidy=2,
                         chromTypes=[sim.CHROMOSOME_X, sim.AUTOSOME],
                         infoFields=[
                             'age', 'a', 'b', 'smurf', 'ind_id', 'father_id',
                             'mother_id', 'luck', 't0', 'fitness'
                         ])
    pop.setVirtualSplitter(
        sim.CombinedSplitter(
            splitters=[
                sim.ProductSplitter(splitters=[
                    sim.InfoSplitter(field='age', cutoff=9),
                    sim.InfoSplitter(field='smurf', values=[0, 1])
                ]),
                sim.SexSplitter(),
                sim.InfoSplitter(field='age', values=0)
            ],
            vspMap=[(0), (2), (1, 3), (4), (5), (6)],
            names=['larvae', 'adults', 'smurfs', 'males', 'females', 'zero']))
    pop.dvars().k = aging_k
    pop.dvars().N = N
    pop.dvars().seed = seed
    pop.dvars().X_loci = X_loci
    pop.dvars().A_loci = A_loci
    pop.dvars().AgingModel = AgingModel
    exec("import random\nrandom.seed(seed)", pop.vars(), pop.vars())
    exec("import math", pop.vars(), pop.vars())
    simu = sim.Simulator(pop, rep=reps)
    simu.evolve(
        initOps=[
            sim.InitSex(),
            sim.InitGenotype(freq=[1 - InitMutFreq, InitMutFreq]),
            sim.InitInfo([0], infoFields='age'),
            sim.InitInfo([aging_a1], infoFields='a'),
            sim.InitInfo([aging_b], infoFields='b'),
            sim.InitInfo(lambda: random.random(), infoFields='luck'),
            sim.InfoExec('t0 = -ind.b / ind.a', exposeInd='ind'),
            sim.InfoExec(
                'smurf = 1.0 if AgingModel == "two_phases" and (ind.smurf == 1 or (ind.age > ind.t0 and ind.luck < 1.0 - math.exp(-ind.a * ind.age + ind.a * ind.t0 - ind.a / 2.0))) else 0.0',
                exposeInd='ind'),
            sim.IdTagger(),
            sim.PyExec('XFreqChange={}'),
            sim.PyExec('AFreqChange={}')
        ],
        preOps=[
            sim.InfoExec('luck = random.random()'),
            sim.InfoExec(
                'smurf = 1.0 if AgingModel == "two_phases" and (ind.smurf == 1 or (ind.age > ind.t0 and ind.luck < 1.0 - math.exp(-ind.a * ind.age + ind.a * ind.t0 - ind.a / 2.0))) else 0.0',
                exposeInd='ind'),
            sim.DiscardIf(natural_death(AgingModel)),
            sim.InfoExec('age += 1'),
            sim.PySelector(func=fitness_func1)
        ],
        matingScheme=sim.HeteroMating([
            sim.CloneMating(subPops=[(0, 0), (0, 1), (0, 2)], weight=-1),
            sim.RandomMating(ops=[
                sim.IdTagger(),
                sim.PedigreeTagger(),
                sim.InfoExec('smurf = 0.0'),
                sexSpecificRecombinator(
                    rates=[0.75 / X_loci for x in range(X_loci)] +
                    [2.07 / A_loci for x in range(A_loci)],
                    maleRates=0.0),
                sim.PyQuanTrait(loci=sim.ALL_AVAIL,
                                func=TweakAdditiveRecessive(
                                    aging_a1, aging_a2, aging_b, X_loci),
                                infoFields=['a', 'b'])
            ],
                             weight=1,
                             subPops=[(0, 1)],
                             numOffspring=1)
        ],
                                      subPopSize=demo),
        postOps=[
            sim.SNPMutator(u=MutRate, subPops=[(0, 5)]),
            sim.Stat(alleleFreq=sim.ALL_AVAIL, step=StatsStep),
            sim.IfElse(
                'X_loci > 0',
                ifOps=[
                    sim.PyExec(
                        'XFreqChange[gen] = [alleleFreq[x][1] for x in range(X_loci)]'
                    )
                ],
                elseOps=[sim.PyExec('XFreqChange[gen] = []')],
                step=StatsStep),
            sim.IfElse(
                'A_loci > 0',
                ifOps=[
                    sim.PyExec(
                        'AFreqChange[gen] = [alleleFreq[a][1] for a in range(X_loci, pop.totNumLoci())]',
                        exposePop='pop')
                ],
                elseOps=[sim.PyExec('AFreqChange[gen] = []')],
                step=StatsStep),
            sim.IfElse(
                PrintFreqs,
                ifOps=[
                    sim.PyEval(
                        r"str(rep) + '\t' + str(gen) + '\t' + '\t'.join(map('{0:.4f}'.format, XFreqChange[gen])) + '\t\t' + '\t'.join(map('{0:.4f}'.format, AFreqChange[gen])) + '\n'"
                    )
                ],
                step=StatsStep),
            sim.TerminateIf(
                'sum([alleleFreq[x][0] * alleleFreq[x][1] for x in range(X_loci + A_loci)]) == 0'
            )
        ],
        gen=generations)
    i = 0
    for pop in simu.populations():
        pop.save('{}_{}.pop'.format(OutPopPrefix, i))
        i += 1