Mutations

Most types of simulations must have mutations in order to do anything “interesting”. fwdpp allows you to define your own mutation type.

A valid mutation type publicly inherits from fwdpp::mutation_base. This class defines a very minimal interface. It has no concept of an “effect size” for a mutation, etc.. To add the relevant concepts for your model, create a derived class.

For example:

#pragma once

#include <tuple>
#include <fwdpp/type_traits.hpp>
#include <fwdpp/fundamental_types/mutation_base.hpp>

/*
 * The simplest mutation type, adding just a selection coefficient
 * and dominance to the interface.
*/
struct mutation : public fwdpp::mutation_base
{
    // selection coefficient
    double s;
    // dominance coefficient
    double h;
    mutation(const double &position, const double &sel_coeff,
             const double &dominance = 0.5) noexcept
        : mutation_base(position, (sel_coeff == 0)), s(sel_coeff), h(dominance)
    {
    }

    bool
    operator==(const mutation &rhs) const
    {
        return std::tie(this->s, this->h) == std::tie(rhs.s, rhs.h) && is_equal(rhs);
    }
};

static_assert(fwdpp::traits::is_mutation_v<mutation>,
              "Mutation is not a valid mutation type!");

Containers of mutations

In a simulation, mutation objects must be stored in random-access containers of objects. You must not use, for example, smart pointers to fwdpp::mutation_base.

In other words, the value_type of your container must equal a type derived from the mutation base class.

For example:

using mutation_container = std::vector<mutation>;

By using such a container, each mutation is represented only once in a simulation. To represent individual genotypes, we need a method of tracking which mutations are present in genomes. See here for details.