Gaussian stabilizing selection with an optimum shift#

This vignette simulates the evolution of a population to a single sudden shift in the optimum trait value.

First, we define a class that will track the mean genetic value and mean fitness of the population over time. See Recording data during a simulation for details.

import numpy as np

class Recorder(object):
    def __init__(self, start):
        self.generation = []
        self.gbar = []
        self.wbar = []
        self.start = start    
        
    def __call__(self, pop, sampler):
        if pop.generation > self.start:
            self.generation.append(pop.generation)
            md=np.array(pop.diploid_metadata, copy=False)
            self.gbar.append(md['g'].mean())
            self.wbar.append(md['w'].mean())

Now, we will set up and simulate the model. We use fwdpy11.GaussianStabilizingSelection to specify when/how the optimum value shifts.

We will simulate the population for \(10N\) generations around an optimum of zero. Then, we shift the optimum to 1 and evolve another 200 generations. We set our Recorder type defined above to start tracking things after the initial “burn in”.

import fwdpy11

pop = fwdpy11.DiploidPopulation(500, 1.0)

rng = fwdpy11.GSLrng(54321)

gssmo = fwdpy11.GaussianStabilizingSelection.single_trait(
    [
        fwdpy11.Optimum(when=0, optimum=0.0, VS=1.0),
        fwdpy11.Optimum(when=10 * pop.N - 200, optimum=1.0, VS=1.0),
    ]
)

rho = 1000.

p = {
    "nregions": [],
    "gvalue": fwdpy11.Additive(2.0, gssmo),
    "sregions": [fwdpy11.GaussianS(0, 1., 1, 0.1)],
    "recregions": [fwdpy11.PoissonInterval(0, 1., rho / float(4 * pop.N))],
    "rates": (0.0, 1e-3, None),
    # Keep mutations at frequency 1 in the pop if they affect fitness.
    "prune_selected": False,
    "demography": fwdpy11.ForwardDemesGraph.tubes([pop.N], burnin=10*pop.N, burnin_is_exact=True),
    "simlen": 10 * pop.N,
}
params = fwdpy11.ModelParams(**p)

r = Recorder(start=10 * pop.N - 200)
fwdpy11.evolvets(rng, pop, params, 100, recorder=r, suppress_table_indexing=True)

Finally, let’s plot the results:

import matplotlib.pyplot as plt

f, ax = plt.subplots()
ax.plot(r.generation, r.gbar, label="Mean trait value")
ax.plot(r.generation, r.wbar, label="Mean fitness")
ax.set_xlabel("Generation")
ax.set_ylabel("Value")
plt.legend()
plt.show()
../_images/a7c77bf66d610e246c4694031adeebe504bef0b56d42ac0d925ad298ff2cc2e7.png