Details of demes integration#

This page gives various technical details regarding fwdpy11 and demes models. See the vignette for an overview.

“Burn-in” times#

When specifying a burn-in time for a population, that time corresponds to epochs in the past where the demographic history of all ancestral demes (those with start times of infinity) are constant.

For example, let’s revisit the model from before:

description: An example demes model
time_units: generations
demes:
 - name: ancestor1
   epochs:
    - start_size: 100
      end_time: 50
 - name: ancestor2
   epochs:
    - start_size: 250
      end_time: 50
 - name: admixed
   start_time: 50
   ancestors: [ancestor1, ancestor2]
   proportions: [0.90, 0.10]
   epochs:
    - start_size: 100

Here, we have two ancestral demes, each with a single epoch. In other words, the size history of these two demes is constant from time 50 in the past back to “infinity”.

For cases like this one, any “burn in” time is simply the history of the ancestral demes.

For such a model, 49 generations ago will correspond to first time offspring are born after the burning phase has ended.

Let’s modify the model to add a second epoch to ancestor2:

description: An example demes model
time_units: generations
demes:
 - name: ancestor1
   epochs:
    - start_size: 100
      end_time: 50
 - name: ancestor2
   epochs:
    - start_size: 100
      end_time: 60
    - start_size: 250
      end_time: 50
 - name: admixed
   start_time: 50
   ancestors: [ancestor1, ancestor2]
   proportions: [0.90, 0.10]
   epochs:
    - start_size: 100

Now we have a size change in the ancestral population 60 generations ago. That event is relevant to contemporary patterns of variation. Therefore, our burn-in phase must end one generation prior to the size change.

See fwdpy11.ForwardDemesGraph.from_demes() for details on how to set the burn-in times. The vignette has examples.

Selfing#

fwdpy11 simulates according to Wright-Fisher dynamics. This means that parents are chosen with replacement and proportionally to their fitnesses.

When an epoch has a selfing rate of zero, sampling with replacement actually implies a residual selfing rate of \(O(1/N)\) (assuming that individual fitnesses are all close to 1.0).

Further, an epoch with a selfing rate \(0 < S \leq 1/N\) will have a realized selfing rate larger than \(S\). (An individual will not self with probability \(1-S\) and will then be chosen again as a parent with probability \(O(1/N)\).)

If this behavior is not desired, pass allow_residual_selfing = False when constructing instances of fwdpy11.ModelParams. Passing False will prevent an individual from being picked twice as a parent. See the documentation of fwdpy11.ModelParams for details about errors that may occur if deme sizes get down to a single individual.

“Default” demographic models.#

If None is passed to the demography field of fwdpy11.ModelParams, then fwdpy11.evolvets() will build a model of constant sizes for all demes in the population using fwdpy11.ForwardDemesGraph.tubes(). The model with have a “burn-in” time of 10N generations where N is the sum of all deme sizes in the :class:fwdpy11.DiploidPopulation.

The code raises a UserWarning when these models are constructed, letting you know that some default magic is happening.

Note

This default behavior was introduced in v0.20.0 in order to maintain backwards compatability with the previous releases. Moving forwward, in the spirit of “explicit is better than implicit”, using None for a demographic model will become a hard error.