Skip to content

Fisher-KPP

The Fisher-KPP equation, whose step invades the empty line as a front of speed 2 sqrt(r D).

  • Name: fisher_kpp
  • Field: biology/ecology
  • Formalism: ordinary differential equations
  • References: Fisher 1937; Kolmogorov, Petrovsky, and Piskunov 1937

Factory

@register_model(
    field='biology/ecology',
    tags=('field', 'fronts', 'reaction-diffusion', 'pde'),
    references=('Fisher 1937', 'Kolmogorov, Petrovsky, and Piskunov 1937'),
    defaults={'until': 40.0, 'dt': 1.0},
)
def fisher_kpp(
    length: int = 800,
    *,
    D: float = 1.0,
    r: float = 1.0,
    spacing: float = 0.25,
    front: float = 0.05,
) -> System:
    """Return the Fisher-KPP equation, whose step invades the empty line as a front of speed `2 sqrt(r D)`.

    Args:
        length:
            The number of sites of the line.

        D:
            The diffusion coefficient.

        r:
            The growth rate.

        spacing:
            The distance between sites.

        front:
            The fraction of the line that starts occupied, on its left.

    Returns:
        system:
            The model, with the density `line.u`.

    Examples:
        >>> from skcomplex.models.biology.ecology import fisher_kpp
        >>> int(fisher_kpp(100, front=0.1).elements[0].values['u'].sum())
        10
    """
    u = (np.arange(length) < front * length).astype(float)
    space = LatticeSpace(length, spacing=spacing)
    return System(
        elements=[
            FieldElement(
                'line',
                element=FisherKPPElement,
                space=space,
                boundary={'u': 'zero-flux'},
                values={'u': u, 'D': D, 'r': r},
            ),
        ],
    )

Components

class FisherKPPElement(Element):
    """Site of a line whose density `u` diffuses and grows logistically, `du/dt = D laplacian(u) + r u (1 - u)`.

    Args:
        label:
            The label of the site.

        visual:
            How the element is drawn, or `None` for `default_visual_`.

        u:
            The initial density, as a fraction of the carrying capacity.

        D:
            The diffusion coefficient.

        r:
            The growth rate.

    Examples:
        >>> from skcomplex.models.biology.ecology import FisherKPPElement
        >>> FisherKPPElement('site', u=0.5).u
        0.5
    """

    def __init__(
        self,
        label: str,
        visual: VisualSpec | None = None,
        *,
        u: Annotated[object, StateSpec(domain=RealSet.closed_open(0, oo))] = 0.0,
        D: Annotated[object, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 1.0,
        r: Annotated[object, ParameterSpec()] = 1.0,
    ) -> None:
        super().__init__(label, visual=visual)
        self.u = u
        self.D = D
        self.r = r

    def _get_laws(self, s: SimpleNamespace) -> list[BaseLaw]:
        """Return the diffusion and the logistic growth of the density.

        Args:
            s:
                The namespace of the symbols the laws can use.

        Returns:
            laws:
                The rate law of the density.
        """
        return [RateLaw(s.u, s.D * laplacian(s.u) + s.r * s.u * (1 - s.u))]

Equations

line.u[i]: diff(u_line(t), t) == -r_line*(u_line(t) - 1)*u_line(t) + D_line*laplacian(u_line(t))