ContDisease — Contagious Diseases#

This is a simple model of a contagious disease on a 2D grid.

Fundamentals#

We model a “forest” on a two-dimensional square grid of cells. Each cell can be in one of five different states: empty, tree, infected, source, or stone.

Implementation#

Update Rules#

In each time step, the cells update their respective states according to the following rules:

  1. An infected cell turns into an empty cell.

  2. An empty cell can become a tree cell with probability p_growth.

  3. A tree cell can become infected in the following ways:

    • from a neighboring infected cell with probability 1-p_immunity per neighbor,

    • via a random point infection with probability p_infect,

    • via a constantly infected cell, an infection source.

For the neighborhood, both the von Neumann neighborhood (5-neighborhood) and the Moore neighborhood (9-neighborhood) are supported (see model configuration).

Heterogeneities#

As in the Forest Fire model, there is the possibility to introduce heterogeneities into the grid, which are implemented as two additional possible cell states:

  • source: these are constant infection sources. They spread infection like normal infected trees, but don not revert back to the empty state. If activated, they are per default on the lower boundary of the grid, though this can be changed in the configuration.

  • stone: stones are cells that can not be infected nor turn into trees. They are used to represent barriers in the forest. If enabled, the default mode is clustered_simple, which leads to randomly distributed stones whose neighbours have a certain probability to also be a stone.

Both make use of the entity selection interface.

Infection Control#

Via the infection_control parameter in the model configuration, additional infections can be introduced at desired times. The infections are introduced before the update rule above is carried out.

Data Output#

The following data is stored alongside the simulation:

  • kind: the state of each cell. Possible values:

    • 0: empty

    • 1: tree

    • 2: infected

    • 3: source, is constantly ignited

    • 4: stone, does not take part in any interaction

  • age: the age of each tree, reset after lightning strikes

  • cluster_id: a number identifying to which cluster a cell belongs; 0 for non-tree cells

  • densities: the densities of each of the kind of cells over time; this is a labeled 2D array with the dimensions time and kind.

Default configuration parameters#

Below are the default configuration parameters for the ContDisease model.

# --- Space parameters --------------------------------------------------------
# The physical space this model is embedded in
space:
  periodic: false

# --- CellManager and cell initialization -------------------------------------
cell_manager:
  grid:
    structure: square
    resolution: 64      # in cells per unit length of physical space

  neighborhood:
    mode: vonNeumann

  # Cell initialization parameters
  cell_params:
    # Initial tree density, value in [0, 1]
    # With this probability, a cell is initialized as tree (instead of empty)
    p_tree: !is-probability 0

# --- Model Dynamics ----------------------------------------------------------
# Probability per site and time step to transition from state empty to tree
p_growth: !is-probability 7.5e-3

# Probability per site and time step for a tree cell to not become infected if
# an infected cell is in the neighborhood. This probability applies per event
# so it does _not_ mean that an immune cell is also immune in the next
# iteration step
p_immunity: !is-probability 0.

# Probability per site and time step for a random point infection of a tree
p_infect: !is-probability 0.
# NOTE This is affected by the infection control, see below.

# --- Infection Control -------------------------------------------------------
# Infection control to investigate the time-dependent influence of the 
# disease driving force. Note that infection control is applied at the
# beginning of an iteration step. It's effect is seen in the following
# time step
infection_control:
  enabled: !is-bool false

  # The number of additional infections to be placed on the grid
  num_additional_infections: !is-unsigned 10

  # Add the additional infections at the given times
  # Note the the !listgen tag creates a list from the parameters 
  # (start, stop, step_size)
  # To disable, pass an empty sequence.
  at_times: !listgen [0, 100, 20]

  # Change the probability of a random infection.
  # The expected value is a list of [iteration_step, new_value] pairs, e.g.
  #   - [10, .5]
  #   - [42, 0.]
  # ... will set p_infect from the default value to .5 at time 10 and set it
  # back to 0. at time 42.
  # To disable, pass an empty sequence.
  change_p_infect: []

# --- Heterogeneities ---------------------------------------------------------
# Some cells can be permanently infected or turned into stones.
# Both these features are using the `select_entities` interface; consult the
# documentation regarding information on available selection modes.

# Turn some cells into stones: these do not take part in any of the processes
stones:
  enabled: !is-bool false
  mode: clustered_simple

  # Clustering parameters
  # Probability with which a cell is a cluster seed
  p_seed: !is-probability .02
  # Attachment probability (per neighbor) 
  p_attach: !is-probability .1
  num_passes: !is-unsigned 5  # How many attachment procedures to perform

# Set some cells to be permanently infected (invoked after stones are set)
infection_source:
  enabled: !is-bool true
  mode: boundary

  # Boundary selection parameters (requires space to be set to NON-periodic!)
  boundary: bottom

# --- Output Configuration ----------------------------------------------------
# Whether to only write out the densities; useful for runs on large grids
# where spatial information is not needed.
write_only_densities: !is-bool false

Available plots#

The following plot configurations are available for the ContDisease model:

Default Plot Configuration#

# --- Densities time series ---------------------------------------------------
densities:
  enabled: false
  based_on: densities.universe

densities_facet_grid:
  based_on: densities.multiverse
  
# --- Phase plot of two densities ---------------------------------------------
phase_diagram:
  based_on: phase_diagram

  # Select from what densities to create the phase diagram
  x: tree
  y: infected
  hue: time

  helpers:
    set_labels:
      x: Tree Density [1/A]
      y: Infected Density [1/A]
    set_title:
      title: Phase Diagram

  cmap: viridis_r

  # Parameters that are passed on to plt.scatter
  s: 10


# --- Snapshots and animations of the spatial grid ----------------------------
# The snapshot plots show the final state of the CA or, more precisely, the
# last written time step. To adjust these, set the `frames_isel` parameter.

# ... The forest ..............................................................
ca/forest:
  based_on: ca/forest
  enabled: false

ca/forest_snapshot:
  based_on:
    - ca/forest
    - .plot.ca.snapshot

# ... The forest age ..........................................................
ca/forest_age:
  based_on: ca/forest_age
  enabled: false

ca/forest_age_snapshot:
  based_on:
    - ca/forest_age
    - .plot.ca.snapshot

# ... The clusters ............................................................
ca/clusters:
  based_on: ca/clusters
  enabled: false

ca/clusters_snapshot:
  based_on:
    - ca/clusters
    - .plot.ca.snapshot

# ... Combined plot of forest states and clusters .............................
ca/combined:
  based_on: ca/combined

ca/combined_snapshot:
  based_on:
    - ca/combined
    - .plot.ca.snapshot

Base Plot Configuration#

.variables:
  base_path: &base_path data/ContDisease

  colors: &cmap                             # state value
    # NOTE Order is very important here!
    empty: &color_empty darkkhaki           # 0
    tree: &color_tree forestgreen           # 1
    infected: &color_infected firebrick     # 2
    source: &color_source orange            # 3
    stone: &color_stone slategray           # 4

  cycler: &cycler !format
    fstr: "cycler('color', ['{cmap[empty]:}', '{cmap[tree]:}', '{cmap[infected]:}', '{cmap[source]:}', '{cmap[stone]:}'])"
    cmap:
      <<: *cmap




# =============================================================================
#  ╔╦╗╔═╗╔╦╗╔═╗╦  ╔═╗╔╦╗╔═╗╔═╗
#   ║ ║╣ ║║║╠═╝║  ╠═╣ ║ ║╣ ╚═╗
#   ╩ ╚═╝╩ ╩╩  ╩═╝╩ ╩ ╩ ╚═╝╚═╝
# =============================================================================
# -- Overloads ----------------------------------------------------------------
# Overload some configs to insert model-specific settings

# Model-specific defaults
.defaults:
  based_on: .defaults

  # Can define something here ...


# .. Creators .................................................................
.creator.universe:
  based_on:
    - .creator.universe
    - .defaults

  dag_options:
    select_path_prefix: *base_path

.creator.multiverse:
  based_on:
    - .creator.multiverse
    - .defaults

  select_and_combine:
    base_path: *base_path






# =============================================================================
#  ╔═╗╦  ╔═╗╔╦╗╔═╗
#  ╠═╝║  ║ ║ ║ ╚═╗
#  ╩  ╩═╝╚═╝ ╩ ╚═╝
# =============================================================================
# -- Any kind of phase plot ---------------------------------------------------
phase_diagram:
  based_on:
    - .creator.universe
    - .plot.facet_grid.scatter

  select:
    kind:
      path: densities

  transform:
    - .sel: [ !dag_tag kind, { kind: tree } ]
      kwargs: { drop: true }
      tag: tree
    - .sel: [ !dag_tag kind, { kind: infected } ]
      kwargs: { drop: true }
      tag: infected
    - xr.Dataset:
        data_vars:
          tree: !dag_tag tree
          infected: !dag_tag infected
      tag: data


# -- Densities plot -----------------------------------------------------------
densities.base:
  based_on:
    - .plot.facet_grid.line
    - .hlpr.kind.time_series

  x: time
  hue: kind

  style:
    axes.prop_cycle: *cycler

  helpers:
    set_limits:
      y: [0., 1.]
    set_labels:
      y: Density [1/A]
      only_label_outer: true
    set_suptitle:
      title: Densities
    set_legend:
      loc: best

densities.universe:
  based_on:
    - .creator.universe
    - densities.base

  select:
    data:
      path: densities
      transform:
        - .data

densities.multiverse:
  based_on:
    - .creator.multiverse
    - .skip.if_more_than_3D
    - densities.base
    - .plot.facet_grid.with_auto_encoding
    - .plot.facet_grid.errorbands
    - .hlpr.legend.hide
    - .animation.disabled

  select_and_combine:
    fields:
      _data:
        path: densities
        transform:
          - .data

  transform:
    - xr.full_like: [!dag_tag _data, !expr nan]
      tag: nans

    # Try to compute mean and std over ceratain dimensions, falling back to
    # a NaN array if that dimension is not available
    - .mean: [!dag_tag _data, seed]
      allow_failure: silent
      fallback: !dag_tag _data
      tag: mean
    - .std: [!dag_tag _data, seed]
      allow_failure: silent
      fallback: !dag_tag nans  # use NaN instead
      tag: std

    # Combine into a dataset
    - xr.Dataset:
        data_vars:
          mean: !dag_tag mean
          std: !dag_tag std
      tag: data

  y: mean
  yerr: std
  x: time
  hue: kind


# --- Grid Snapshots ----------------------------------------------------------
# NOTE These can also be used as basis for grid animations.
# ... The forest ..............................................................
ca/forest:
  based_on:
    - .creator.universe
    - .plot.ca

  select:
    kind: kind
  
  to_plot:
    kind:
      title: Forest State
      cmap: *cmap

# ... The forest age ..........................................................
ca/forest_age:
  based_on:
    - .creator.universe
    - .plot.ca

  select:
    age: age

  to_plot:
    age:
      title: Forest Age
      cmap: YlGn
      vmin: 0
      vmax: max

# ... The clusters ............................................................
ca/clusters:
  based_on:
    - .creator.universe
    - .plot.ca

  select:
    cluster_id:
      path: cluster_id
      transform:
        - where: [!dag_prev , "!=", 0]  # not part of the cluster
        - np.fmod: [!dag_prev , 20]     # matching the size of the tab20 cmap
        # NOTE Important to use np.fmod here because it carries through the
        #      container attributes, which are needed for determining the
        #      grid structure. The `mod` operation itself does not do that.

  to_plot:
    cluster_id:
      title: Clusters
      cmap: tab20
      vmin: 0
      vmax: 20
      no_cbar_markings: true

# ... Combined plot of forest states and clusters .............................

ca/combined:
  based_on:
    - ca/forest
    - ca/forest_age
    - ca/clusters

  # col_wrap: false

For available base plots, see Base Plot Configuration Pool.

References#

Kurt Roth: Chaotic, Complex, and Evolving Environmental Systems. Unpublished lecture notes, University of Heidelberg, 2018.