Skip to content

Describing a Model

Back to Building Models

Model.describe() returns a description of a model as data: sections of tables, equations, state graphs and text. You can read it in Python, render it as text, Markdown, LaTeX or JSON, save it to a file, or draw its state graph. The description works for every kind of model, and it is built from what the engine simulates, so the equations it shows are the equations that run. Use this page to document a model, to check the equations Commol derived, or to write the methods section of a paper.

Quick path

from commol import Aggregate, ModelBuilder

model = (
    ModelBuilder(name="Described", bin_unit="item", step_unit="day")
    .add_bin(id="A", name="State A")
    .add_bin(id="B", name="State B")
    .add_bin(id="C", name="State C")
    .add_parameter(id="k1", value=0.5, unit="1/day")
    .add_parameter(id="k2", value=0.1, unit="1/day")
    .add_transition(id="t_ab", source=["A"], target=["B"], rate="k1 * A * B / total")
    .add_transition(id="t_bc", source=["B"], target=["C"], rate="k2 * B")
    .build(
        Aggregate(bin_amounts={"A": 900, "B": 100, "C": 0}),
        engine="DifferenceEquations",
    )
)

description = model.describe()
print(description.render("text"))   # every section, in plain text
description.save("model.md")        # Markdown, with the state graph as a Mermaid diagram
description.save("model.tex")       # a LaTeX document
description.save("model.dot")       # every state graph, in Graphviz DOT

In a Jupyter notebook, model.describe() as the last line of a cell shows the Markdown rendering, with the state graph drawn (JupyterLab draws Mermaid from version 4.1).

What a description holds

A ModelDescription has a title, a layout and a list of sections. Each section has a key, a title and blocks. Model.describe() builds the sections every kind shares from the model, and the structure of the model adds the sections of its kind (ModelStructure.describe):

Key Content For an Aggregate model
overview Name, description, version, kind, engine, its settings and the step unit From Model
entities What holds the state Bins, accumulators, stratifications and their categories, the expanded compartments
dynamics How the state changes The state graphs, the compact and expanded forms of the equations, the impulses, the neighbors
schedule How the engine advances, and the settings it advances with From the engine (EngineType.schedule) and Model.engine.settings
initialization The state the model starts from Bin amounts, category fractions, overrides, and the initial state the engine builds
parameters Every parameter Value, unit, whether calibration sets it, description
outputs What a run returns The outputs of each bin and accumulator

A section with no blocks is left out of every rendering.

dynamics = description.section("dynamics")
print([type(block).__name__ for block in dynamics.blocks])
# ['StateGraph', 'StateGraph', 'Equations', 'Text', 'Equations']

The blocks are a closed set (commol.context.description):

Block Holds
Text A paragraph
Table Columns and rows of cells
Equations Groups of equations, each in plain text and in LaTeX
StateGraph Nodes and edges; expanded marks the graph of the expanded compartments
Matrix Labelled rows and columns of numbers, such as the weights of neighbors

Formats

render(format) returns a string; save(path, format=None) writes it and, without format, takes the format from the suffix of the path.

Format Suffix Equations Diagrams
"text" .txt Compact and expanded forms in plain text None
"markdown" .md LaTeX math The state graph of the model as a Mermaid diagram
"latex" .tex align* environments in a full document None
"json" .json As data The graphs as data; ModelDescription.model_validate_json reads it back
"dot" .dot None Every state graph, the expanded one included

The Markdown rendering does not draw the graph of the expanded compartments: a stratified model can have hundreds of edges, more than a Mermaid diagram draws. It gives the size of the graph instead. The DOT file holds every graph; dot -Tpdf model.dot -o model.pdf draws them with Graphviz.

The LaTeX document uses only standard packages (amsmath, amssymb, longtable, fontenc, geometry), so latexmk -pdf model.tex builds it.

The equations

The dynamics section of an aggregate model holds the flows that the engine plans, after it has decided which rates are proportional (see Transitions):

Part Content
Compact form Each transition and its flows, source -> target: rate. With units, each symbol shows its unit and each flow its resulting unit.
Expanded form One equation per compartment. The left-hand side comes from the engine: [A(t+Dt) - A(t)] / Dt for DifferenceEquations, dA/dt for DifferentialEquations.
Events For a stochastic engine, instead of the expanded form: one row per flow, with the change of the state of one event and its propensity (StochasticEvents) or its draw in a step (StochasticSteps). See Stochastic Simulation.
Impulses Each impulse transition, the positions where it acts and the amounts it moves; an impulse is not part of the equations.

For the model above, the text rendering holds:

Bin Transitions:
t_ab (A -> B):
  A -> B: k1(1/day) * A(item) * B(item) / total(item) [item / day]

t_bc (B -> C):
  B -> C: k2(1/day) * B(item) [item / day]

Total System: 3 coupled equations (3 bins)
[A(t+Dt) - A(t)] / Dt = - (k1 * A * B / total)
[B(t+Dt) - B(t)] / Dt = (k1 * A * B / total) - (k2 * B)
[C(t+Dt) - C(t)] / Dt = (k2 * B)

Units appear only when every bin and every constant parameter has one; with some units missing, the equations show none. To check the units, use check_unit_consistency.

The ODD layout

model.describe(layout="odd") follows the ODD protocol (Overview, Design concepts, Details), the standard description of individual-based and agent-based models, used for other simulation models too (Grimm et al. 2006, updated in 2010 and 2020). The same layout works for every kind of model, so a paper can describe an aggregate model and an agent model in one format.

odd = model.describe(layout="odd")
print([section.title for section in odd.sections])
# ['Purpose and patterns', 'Entities, state variables and scales',
#  'Process overview and scheduling', 'Design concepts', 'Initialization',
#  'Input data', 'Submodels']
odd.save("model_odd.tex")
Element What Commol fills for an Aggregate model
Purpose and patterns Model.description; without one, the marker
Entities, state variables and scales Bins, accumulators, stratifications, compartments; the step unit and how the engine advances
Process overview and scheduling Each transition, where it moves, whether it is an impulse; the schedule of the engine and its settings
Design concepts Interaction (when the structure has neighbors), stochasticity (from the engine) and observation (the outputs); the marker for the others
Initialization The bin amounts and their units, the category fractions, the overrides and the initial state
Input data The series parameters, or "None"
Submodels The state graphs and equations, the parameters and the outputs

An element Commol cannot fill says "To be written by the modeller.": write it in the saved file. The layout of a description changes which sections it has and their order; the format of render is independent of it.

References:

  • Grimm, V., et al. (2006). A standard protocol for describing individual-based and agent-based models. Ecological Modelling, 198, 115–126. doi:10.1016/j.ecolmodel.2006.04.023
  • Grimm, V., et al. (2010). The ODD protocol: A review and first update. Ecological Modelling, 221, 2760–2768. doi:10.1016/j.ecolmodel.2010.08.019
  • Grimm, V., et al. (2020). The ODD protocol for describing agent-based and other simulation models: A second update to improve clarity, replication, and structural realism. Journal of Artificial Societies and Social Simulation, 23(2), 7. doi:10.18564/jasss.4259

Checklist

  • [ ] model.describe().render("text") shows the equations you expect.
  • [ ] Saved files use a suffix of the table above, or pass format=.
  • [ ] For a paper, layout="odd" and the markers it leaves are filled in.

Next steps

To learn Read
How rates become flows Transitions
Unit checking Units
Running the model Running Simulations