Skip to content

Commit

Permalink
Start rewriting demes vignette
Browse files Browse the repository at this point in the history
  • Loading branch information
molpopgen committed Mar 24, 2023
1 parent 2565dbe commit 9b8b855
Showing 1 changed file with 37 additions and 60 deletions.
97 changes: 37 additions & 60 deletions doc/short_vignettes/demes_vignette.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,94 +26,71 @@ It is a good idea to browse both the [tutorial](https://popsim-consortium.github
There are several advantages to using `demes`:

* The `YAML` files can be used by many pieces of related software, including [`msprime`](https://tskit.dev/msprime/docs/stable/) and [`moments`](https://moments.readthedocs.io).
* The specification is simpler than the low-level `API` provided by any of these tools.
* 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 file input

The following `YAML` specifies the human out-of-Africa model from {cite}`Gutenkunst2009-wd`:

```{literalinclude} gutenkunst_ooa.yml
:language: yaml
```{code-cell} python
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
"""
```

We can generate demographic models directly from these `YAML` files using {func}`fwdpy11.discrete_demography.from_demes`.
We can generate demographic models directly from these `YAML` files using
{func}`fwdpy11.ForwardDemesGraph.from_demes`.

```{code-cell} python
import fwdpy11
model = fwdpy11.discrete_demography.from_demes("gutenkunst_ooa.yml")
demography = fwdpy11.ForwardDemesGraph.from_demes(yaml, burnin=100, burnin_is_exact=True)
```

:::{note}
Be sure to read the documentation for {func}`fwdpy11.discrete_demography.from_demes`!
Be sure to read the documentation for {func}`fwdpy11.ForwardDemesGraph.from_demes`!
There are important options concerning the run time of the simulation, etc.
:::

The return value is an instance of {class}`fwdpy11.DemographicModelDetails` and may be passed as the `demography` keyword argument to initialize an instance of {class}`fwdpy11.ModelParams`.
To extract the simulation length to generate the `simlen` parameter of your {class}`fwdpy11.ModelParams` instance:

```{code-cell} python
model.metadata["total_simulation_length"]
```
The return value is an instance of {class}`fwdpy11.ForwardDemesGraph`.
The object contains several properties that are useful in setting up your
simulation.

If we print the `model` object, we will see how much logic we'd have had to use in order to implement this model using the low-level object `API`:
First, the sizes of all demes extant at generation zero:

```{code-cell} python
print(model.asblack())
```

It is hopefully clear how much simpler it is to use the `demes` `YAML` specification!

## Working with graphs

You may also build models by creating {class}`demes.Builder` objects using the `demes` `API`.
In general, we feel that the `YAML` method will be less error-prone and therefore the preferred approach.
But, for example:

```{code-cell}
import demes
builder = demes.Builder(description="test demography", time_units="generations")
builder.add_deme(
name="deme",
epochs=[
dict(start_size=1000, end_time=100),
dict(start_size=2000, end_time=0),
],
)
graph = builder.resolve()
model = fwdpy11.discrete_demography.from_demes(graph)
print(model.asblack())
demography.initial_sizes
```

Again, it is simpler to build up the demography using `demes` than it is using the `fwdpy11` objects directly.

## Initializing populations

A model specified using `demes` contains enough information to initialize instances of {class}`fwdpy11.DiploidPopulation`.
We recommend that you use this information so that the initial deme size(s) in your simulation is correct!

To see how this works, let's revisit the Gutenkunst model from above.
The value returned contains the initial size of each deme in the model:
This property can be used to correctly initialize a population:

```{code-cell}
model = fwdpy11.discrete_demography.from_demes("gutenkunst_ooa.yml")
print(model.metadata['initial_sizes'])
pop = fwdpy11.DiploidPopulation(demography.initial_sizes, 1000.)
print(pop.deme_sizes())
```

Given that, a sorted list comprehension does the job:
The generation corresponding to the end of the model:

```{code-cell}
initial_sizes= [model.metadata['initial_sizes'][i] for i in sorted(model.metadata['initial_sizes'].keys())]
pop = fwdpy11.DiploidPopulation(initial_sizes, 1000.)
print(pop.deme_sizes())
```{code-cell} python
demography.final_generation
assert False
```

The reason to go through the sorting step is to get the right initial sizes *in the right order* for "rootless" `demes` graphs.
A rootless model is one with more than one ancestral deme in the ancient past.
We can now set up our simulation parameters:

0 comments on commit 9b8b855

Please sign in to comment.