Using demes to specify demographic models.#

Note

The lists of objects described here are passed to the demography and simlen parameters when initializing instances of fwdpy11.ModelParams.

Starting with version 0.14.0, it is possible to specify a demographic model using the demes specification. This method of specifying models uses a YAML syntax, which is described in detail in the demes specification.

It is a good idea to browse both the tutorial and the gallery before continuing.

There are several advantages to using demes:

  • The YAML files can be used by many pieces of related software, including msprime and moments.

  • You’ll get an extra layer of model validation when demes loads your model prior to it being converted into fwpdy11 objects.

  • Tools to visualize the models are under active development.

YAML input#

The following YAML specifies a model of a derived population created from unequal admixture of two ancestral populations 50 generations ago:

yaml="""
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
"""

A visual representation of the model looks like:

Hide code cell source
import demes
import demesdraw
graph = demes.loads(yaml)
demesdraw.tubes(graph);
../_images/5dca1536ad84573b6409f70d72aa22aa08205f732ab03c2c8257734e25a5f7a9.png

We can generate demographic models directly from these YAML files using fwdpy11.ForwardDemesGraph.from_demes().

import fwdpy11

demography = fwdpy11.ForwardDemesGraph.from_demes(yaml, burnin=100, burnin_is_exact=True)

The previous command defines a model where we evolve the population for 100 generations of a “burn-in”. When burnin_is_exact=False, the value passed to burnin is treated as a multiple of the sum of all ancestral deme sizes (those having a start time of inf in the demes model).

Note

Be sure to read the documentation for fwdpy11.ForwardDemesGraph.from_demes()! There are important options concerning the run time of the simulation, etc.

The return value is an instance of fwdpy11.ForwardDemesGraph. The object contains several properties that are useful in setting up your simulation.

First, the sizes of all demes extant at generation zero:

demography.initial_sizes
[100, 250]

This property can be used to correctly initialize a population:

pop = fwdpy11.DiploidPopulation(demography.initial_sizes, 1000.)
print(pop.deme_sizes())
(array([0, 1], dtype=int32), array([100, 250]))

The generation corresponding to the end of the model:

demography.final_generation
150

We can now set up our simulation parameters:

pdict = {'simlen': demography.final_generation,
         'demography': demography,
         # Everything below is standard
         # and covered in other vignettes
         'recregions': [],
         'nregions': [],
         'sregions': [],
         'rates': (0,0,0),
         'gvalue': fwdpy11.Multiplicative(2.)
         }
params = fwdpy11.ModelParams(**pdict)

We are now ready to run a simulaton:

  • We have a valid fwdpy11.ModelParams object.

  • Our population has its initial sizes correctly set.

Obtaining the demes present at the end of a simulation#

demography.demes_at_final_generation
[2]

To get the names of those demes:

for deme in demography.demes_at_final_generation:
    print(demography.deme_labels[deme])
admixed

It is probably useful to read more about how fwdpy11 handles demes models here.

More information#

See here for concrete examples about reasoning through when demographic events occur.