To receive notifications about scheduled maintenance, please subscribe to the mailing-list gitlab-operations@sympa.ethz.ch. You can subscribe to the mailing-list at https://sympa.ethz.ch

Commit 51bb3591 authored by Victor's avatar Victor
Browse files

updated documentation

parent aed35d01
Pipeline #101397 failed with stage
......@@ -7,7 +7,7 @@
src="https://vboussange.github.io/images/research/conceptual_onlyadapt.png"
alt="" width="400"></img> </div>
EvoId.jl (for **Evo**lutionary **I**n**d**ividual-based model) is a package aimed at simulating the eco-evolutionary dynamics of a population in a multidimensional space, at the individual level.
EvoId.jl (for **Evo**lutionary **I**n**d**ividual-based models) is a package aimed at simulating the eco-evolutionary dynamics of a population in a multidimensional space, at the individual level. The dynamics is specified under the framework of [stochastic models for structured populations](https://arxiv.org/abs/1506.04165).
Individuals are characterised by **a set of traits** in some **combination of evolutionary spaces**. An evolutionary space can represent for example a geographical landscape, a trait space, or genetic structure. Individuals give birth at a rate given by the birth function `b`, and die at a rate given by the death function `d`. When an individual give birth, its offspring can move on the underlying evolutionary spaces. The movement can capture whether migration or mutation processes, and is characterised by a probability `m` and movement range `D`.
......@@ -20,7 +20,7 @@ EvoId.jl provides a **numerical laboratory** for eco-evolutionary dynamics, supp
- store ancestors trait,
- flexible types for **evolutionary spaces**, that can consist of multidimensional **discrete or continuous domains**, as well as **graphs**,
- the possibility to use **callback functions** to save the state of the system at any time step
- several **algorithms** for the simulations (Gillepsie, Wright Fisher, etc...),
- several **algorithms** for the simulations (Gillespie, Wright Fisher, etc...),
- **utility functions** to analyse simulation results.
## Installation
......@@ -34,11 +34,18 @@ Pkg.add("https://github.com/vboussange/EvoId.jl")
This will download latest version from git repo and download all dependencies.
## Getting started
Check out the documentation if you want to use the advanced features of EvoId.jl. Otherwise, you can content yourself with the simple tutorial prodived below.
Check out the tutorial prodived below. You can also dive into the [documentation](https://vboussange.github.io/EvoId.jl/dev) if you want to use the advanced features of EvoId.jl.
## Related papers
- [Topology and habitat assortativity drive neutral and adaptive diversification in spatial graphs](https://www.biorxiv.org/content/10.1101/2021.07.06.451404v2), Boussange et al. 2021.
## Similar packages
[Agents.jl](https://juliadynamics.github.io/Agents.jl/) is a library oriented towards general ABM modelling, and thus is not as easy to deploy as EvoId.jl for simulating stochastic models of structured populations.
## Contributing
Please feel free to contact me! :)
-----
## Tutorial
We provide here a tutorial that sums up the 5 steps necessary to launch a simulation. For the sake of the tutorial, we propose to model a population that is structured over the vertices of a graph and characterised by a trait under selection.
......@@ -82,6 +89,8 @@ Individual movements correspond to migration and mutation processes. On continuo
```julia
D = [nothing,5e-1] # movement ranges
mu = [1.,1.] # movement rates
NMax = 2000 # maximum number of individuals allowed
p = Dict("D"=> D, "mu" => mu, "NMax" => NMax) # storing above parameters
```
### 4. Define the initial population state
......@@ -94,7 +103,7 @@ for i in 1:K
randn() * D[2]]) # random position on the trait space centered around 0
)
end
w0 = World(myagents,evolspace,p) # the initial world, defined at time 0.
w0 = World(myagents, evolspace, p) # the initial world, defined at time 0.
```
### 5. Run
......
# Basics
## Mutations / migration
If `mu[i]` has dimension greater than 1, then mutations happen independently at each component of the trait in high dimensional space. If this is not the case
# Developping the code
I recommend to first clone your branch in the directory you like best, and then to
To develop, you ca
To develop, you can
```julia
using Pkg
Pkg.dev("path_to_EvoId_dir")
......@@ -12,21 +12,9 @@ You can also do the same trick with directly the gitlab address, cf [Pkg.jl](htt
- Make use of CUDA.jl to accelerate the simulations wih the use of GPU.
## Todo
- We do not need to have the `Rates{}` parameter for `Agent` type.
```julia
abstract type AbstractAgent{A<:Ancestors,R<:Rates} end
```
It seems that we do not need to have the `Rates{}` parameter for `Agent` type.
## Notes
### Numerics
:warning:
[Don’t pass expressions, or strings, pass functions](https://www.youtube.com/watch?v=mSgXWpvQEHE&t=573s)
### Birth and Death mechanisms
<!-- > We are always balanced between taking the integral of the competition and resource kernel as constant, or taking its maximum peak as constant. -->
<!-- :poop: -->
### Geotrait
The geotrait is calculated *a posteriori*, and is not taken into account during the simulation.
> It used to be but for the sake of simplicity we now forget about it.
- extend the birth function to the form `b(X,Y,t)` for coherence with death function
- make mutation and disperal range features of agents, so that they can also evolve.
......@@ -31,5 +31,5 @@ w0 = World(myagents,myspace,p,0.)
```@autodocs
Modules = [EvoId]
Pages = ["algo/EvoId_CFM.jl"]
Pages = ["algo/CFM.jl"]
```
# Agent properties
## The `Agent` structure
`Agent` is the atomic structure of EvoId.jl. It has four attributes
- the ancestors' history of traits, and the corresponding time where the traits have changed,
- a death rate and a birth rate.
```julia
mutable struct Agent{A<:Ancestors,R<:Rates,T<:Tuple,U,V} <: AbstractAgent{A,R}
# history of traits for geotraits
x_history::Array{T,1}
# birth time of ancestors
t_history::Array{U,1}
# death rate
d::V
#birth rate
b::V
end
```
!!! note "Specificities"
The type `Agent` has two important composite types
......@@ -24,5 +8,5 @@ end
```@autodocs
Modules = [EvoId]
Pages = ["EvoId_Agent.jl"]
Pages = ["Agent.jl"]
```
......@@ -2,5 +2,5 @@
```@autodocs
Modules = [EvoId]
Pages = ["EvoId_metrics.jl"]
Pages = ["metrics.jl"]
```
# Gillepsie algorithm
# Gillsepie algorithm
## Mathematical foundations
......@@ -16,5 +16,5 @@ A particular event, birth or death, is chosen at random with a probability equal
```@autodocs
Modules = [EvoId]
Pages = ["EvoId_Gillepsie.jl"]
Pages = ["algo/Gillepsie.jl"]
```
......@@ -10,5 +10,5 @@ A `Simulation` object is returned by the function `run!`. It is a container for
```@autodocs
Modules = [EvoId]
Pages = ["EvoId_Sim.jl"]
Pages = ["Sim.jl"]
```
......@@ -2,5 +2,5 @@
```@autodocs
Modules = [EvoId]
Pages = ["EvoId_Space.jl"]
Pages = ["Space.jl"]
```
# Utils
```@autodocs
Modules = [EvoId]
Pages = ["EvoId_utils.jl"]
Pages = ["utils.jl"]
```
# World
```@autodocs
Modules = [EvoId]
Pages = ["EvoId_world.jl"]
Pages = ["world.jl"]
```
......@@ -41,5 +41,5 @@ Parallelism only works with Wright Fisher model.
```@autodocs
Modules = [EvoId]
Pages = ["EvoId_WF.jl"]
Pages = ["algo/WF.jl"]
```
......@@ -41,15 +41,22 @@ end
# default initialiser
"""
$(SIGNATURES)
Initialises agent with 0 values everywhere
# args
- `s` is the underlying space
- `ancestors=true` when agents fitness needs to be updated at each time step.
This is needed for the Gillepsie algorithm, but not for CFM algorithm
- `ancestors=true` when one wants to store ancestors traits.
Agent(s; ancestors=false,rates=true)
Agent(s, pos;ancestors=false,rates=true)
# Arguments
*`s` is the underlying space
* `pos` is the initial agent position. If not provided,
initialises agent with 0 values everywhere
# Keyword arguments
* `rates`. Set `rates=true` when agents fitness
needs to be updated at each time step. This
is required for the Gillepsie algorithm, but not for CFM algorithm
- `ancestors`. Set `ancestors=true` when you want to store ancestors traits.
"""
function Agent(s::S;ancestors=false,rates=true) where {S <: AbstractSpacesTuple}
function Agent(s::S; ancestors=false,rates=true) where {S <: AbstractSpacesTuple}
T,pos = _initpos(s)
t = 0.
U = Float64
......@@ -85,15 +92,6 @@ function Agent(s::S,pos_t::Vector,t::Vector{U};ancestors=false,rates=true) where
Agent{Ancestors{ancestors},Rates{rates},Tuple{T...},U,V}(pos2_t,t,d,b)
end
"""
Agent(s, pos;ancestors=false,rates=true)
Initialises agent with initial position `pos` provided
# args
- `s` is the underlying space
- `ancestors=true` when agents fitness needs to be updated at each time step.
This is needed for the Gillepsie algorithm, but not for CFM algorithm
- `ancestors=true` when one wants to store ancestors traits.
"""
Agent(s, pos; ancestors=false, rates=true) = Agent(s, [pos], [0.],ancestors=ancestors, rates=rates)
......@@ -121,13 +119,12 @@ Base.summary(A::AbstractAgent) = string(TYPE_COLOR,nameof(typeof(a)),NO_COLOR,"
###Agent accessors###
#####################
Base.getindex(a::Agent,i) = a.x_history[end][i]
"""
get_x(a::Agent)
Returns trait i of the agent
"""
Base.getindex(a::Agent,i) = a.x_history[end][i]
get_x(a::Agent) = a.x_history[end]
@deprecate get_x(a) a[:]
......
......@@ -13,6 +13,7 @@ end
"""
$(SIGNATURES)
`Simulation` object, output by the method `run!`
"""
function Simulation(w0::World{A,S,T};cb = nothing) where {A,S,T}
tspan = zeros(1)
......
......@@ -2,13 +2,10 @@
abstract type IsFinite{T} end
#ife stands for is finite
"""
$(TYPEDEF)
`Dim` is the dimension of the space,
`T` is the element type,
`I` to indicate finiteness
"""
# `Dim` is the dimension of the space,
# `T` is the element type,
# `I` to indicate finiteness
abstract type AbstractSpace{Dim,T,I} end
AbstractSpacesTuple = Tuple{Vararg{AbstractSpace}}
import Base:ndims,isfinite,eltype
......@@ -25,6 +22,14 @@ abstract type AbstractStatSpace{Dim,T,I} <: AbstractSpace{Dim,T,I} end
"""
$(TYPEDEF)
Creates a Graph Space.
# Example
```julia
using LightGraphs
g = star_graph(7)
GraphSpace(g)
```
"""
struct GraphSpace{T} <: AbstractStatSpace{1,T,IsFinite{true}}
g::AbstractGraph{T}
......@@ -34,6 +39,14 @@ abstract type AbstractSegment{T<:Number} <: AbstractStatSpace{1,T,IsFinite{true
"""
$(TYPEDEF)
Creates a segment space, where individuals are reflected at both ends.
# Arguments
* `s` start of the segment
* `e` end of the segment
# Example
```julia
ContinuousSegment(1., 2.)
```
"""
struct ContinuousSegment{T<:AbstractFloat} <: AbstractSegment{T}
s::T
......@@ -42,6 +55,14 @@ end
"""
$(TYPEDEF)
Creates a discrete segement space, where individuals are reflected at both ends.
# Arguments
* `s` start of the segment
* `e` end of the segment
# Example
```julia
DiscreteSegment(1, 2)
```
"""
struct DiscreteSegment{T<:Integer} <: AbstractSegment{T}
s::T
......@@ -50,7 +71,10 @@ end
"""
$(TYPEDEF)
A real space with dimension N and type T
Creates a real space.
# Arguments
* `N` dimension of the space
* `T` type of the underlying traits.
"""
struct RealSpace{N,T} <: AbstractStatSpace{N,T,IsFinite{false}} end
RealSpace(N) = RealSpace{N,Float64}()
......@@ -121,11 +145,14 @@ end
abstract type AbstractDynSpace{Dim,T<:Number} <: AbstractSpace{Dim,T,IsFinite{true}} end
"""
$(TYPEDEF)
A dynamic graph space.
A dynamic graph space.
# Arguments
* `g` the underlying graph
* `f` a function that takes as argument time,
and returns the index of the graph to pick at time `t` from array `g`
# Example
`DynGraphSpace(g,f)`
Function `f(t)` takes as argument time, and returns the index of the graph to pick at time `t` from array `g`
# Example
`DynGraphSpace(g,f)`
"""
struct DynGraphSpace{T<:Number} <: AbstractDynSpace{1,T}
g::Vector{AbstractGraph{T}}
......@@ -160,10 +187,8 @@ function get_inc(x,D::Nothing,d::DynGraphSpace{T},t) where {T}
return last(randomwalk(get_graph(d,t),x,2)) - x
end
"""
$(SIGNATURES)
Here we increment the trajectory of trait 1 such that it follows a reflected brownian motion (1D)
"""
#increment the trajectory of trait 1
# such that it follows a reflected brownian motion (1D)
function _reflect1D(x::Number,inc::Number,s::AbstractSegment)
if x + inc < s.s
inc = 2 * ( s.s - x ) - inc
......
......@@ -7,7 +7,45 @@ mutable struct World{A<:AbstractAgent, S<:AbstractSpacesTuple,T<:Number}
t::T
end
#constructor
"""
$(SIGNATURES)
Constructs a world.
# Arguments
* `w` a vector of agents,
* `s` a tuple of evolutionary spaces,
* `p` a dictionary that contains
- `"mu"`, a vector of same length as `s`,
that contains the mutation rate. If `mu[i]`
has dimension greater than 1,
then mutations happen independently at each dimension
of `s[i]`.
- `"sigma"`, a vector of same length as `s`,
that contains the dispersal ranges. Only `nothing` is
supported for `GraphSpace`, equivalent to a random walk of length 1.
- `"NMax"` the maximum number of individuals allowed during the simulation
# Examples
```julia
nodes = 7
g = star_graph(nodes)
landscape = GraphSpace(g)
θ = [rand([-1,1]) for i in 1:nodes]
traitspace = RealSpace(1)
evolspace = (landscape,traitspace)
D = [nothing,5e-2]
mu = [1f-1,1f-1]
p = Dict("NMax" => 2000,
"D" => D,
"mu" => mu)
myagents = [Agent(evolspace,[rand(1:nodes),randn() * D[2]]) for i in 1:K]
w0 = World(myagents,evolspace,p)
```
"""
function World(w::Vector{A},s::S,p::Dict;t::T=0.) where {A<:AbstractAgent,S<:AbstractSpacesTuple,T}
# if typeof(p["D"]) != eltype(skipmissing(w)[1])
# throw(ArgumentError("Diffusion coefficient does not match with underlying space\n `D::Tuple`"))
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment