Skip to content

Model creation

A model is a python object. Model holds the elements of the model — compartments, species, parameters, reactions, rules, events — and create_model turns that definition into an SBML file.

The model definition

from pathlib import Path

from sbmlutils.factory import (
    Compartment,
    Model,
    ModelUnits,
    Parameter,
    Reaction,
    Species,
    UnitDefinition,
    Units,
    create_model,
)


class U(Units):
    """Units of the model."""

    min = UnitDefinition("min")
    mmole = UnitDefinition("mmole")
    l = UnitDefinition("l", "liter")
    mM = UnitDefinition("mM", "mmole/liter")
    mmole_per_min = UnitDefinition("mmole_per_min", "mmole/min")


model = Model(
    sid="glycolysis",
    name="minimal glycolysis model",
    notes="""
    # Minimal glycolysis model
    Glucose is taken up and phosphorylated.
    """,
    units=U,
    model_units=ModelUnits(time=U.min, extent=U.mmole, substance=U.mmole, volume=U.l),
    compartments=[
        Compartment("cell", value=1.0, unit=U.l, name="cell", constant=True),
    ],
    species=[
        Species(
            "glc", initialConcentration=5.0, compartment="cell", substanceUnit=U.mmole
        ),
        Species(
            "g6p", initialConcentration=0.0, compartment="cell", substanceUnit=U.mmole
        ),
    ],
    parameters=[
        Parameter("Vmax", 1.0, U.mmole_per_min),
        Parameter("Km", 0.1, U.mM),
    ],
    reactions=[
        Reaction(
            "GK",
            name="glucokinase",
            equation="glc -> g6p",
            formula=("Vmax * glc / (Km + glc)", U.mmole_per_min),
        ),
    ],
)

result = create_model(model=model, filepath=Path("glycolysis.xml"))

create_model returns a FactoryResult with the sbml_path it wrote and the created Model. It validates the model by default, see Validation.

The created model can be serialized to additional formats next to the SBML file, which makes the result easy to inspect: create_antimony=True writes the antimony notation of the model to glycolysis.ant, and create_markdown=True writes the ODE system as markdown to glycolysis.md, see Converters. Both are off by default; the paths of the written files are on the result as antimony_path and markdown_path.

result = create_model(
    model=model,
    filepath=Path("glycolysis.xml"),
    create_antimony=True,
    create_markdown=True,
)

The elements can be passed to the constructor or assigned afterwards, which is useful when they are built programmatically:

model.species += [
    Species(
        f"s{k}", initialConcentration=0.0, compartment="cell", substanceUnit=U.mmole
    )
    for k in range(10)
]

objects=[...] accepts elements of any kind in one list; they are sorted into the right collection by their type.

The elements

element what it is
Compartment a compartment, value is its size
Species a species, given as initialConcentration or initialAmount
Parameter a parameter, value is a number or a formula
Reaction a reaction, with an equation and a rate formula
InitialAssignment the initial value of a symbol as a formula
AssignmentRule, RateRule, AlgebraicRule the rules of the model
Event a discrete event with a trigger and assignments
Function a function definition
Constraint a constraint on the state of the model
Objective, FluxObjective, GeneProduct the fbc elements
Submodel, Port, ReplacedElement, ReplacedBy, Deletion the comp elements
Uncertainty, UncertParameter, UncertSpan the distrib elements

Every element is an Sbase and accepts the attributes every SBML element has: sid, name, metaId, sboTerm, notes, annotations, port, uncertainties and keyValuePairs.

Reactions

The stoichiometry of a reaction is written as an equation string, which is parsed by sbmlutils.reaction_equation:

Reaction("R1", equation="2 glc + atp -> g6p + adp")  # stoichiometries
Reaction("R2", equation="glc <-> g6p")  # reversible, `->` is irreversible
Reaction("R3", equation="glc -> g6p [enzyme]")  # modifiers in brackets
Reaction("R4", equation="fS glc -> g6p")  # variable stoichiometry
Reaction("R5", equation="=> cit")  # no reactants
Reaction("R6", equation="acoa =>")  # no products

The rate is given as formula, either as a plain string or as a (formula, unit) tuple, which is what makes the unit check meaningful. The full grammar of the equations is documented in sbmlutils.reaction_equation.

Packages

SBML packages are activated on the model and their elements are then available:

from sbmlutils.factory import Model, Package

model = Model(
    sid="example", packages=[Package.COMP_V1, Package.FBC_V3, Package.DISTRIB_V1]
)
package guide
Package.COMP_V1 Model composition
Package.FBC_V2, Package.FBC_V3 Flux balance constraints
Package.DISTRIB_V1 Distributions and uncertainties

The layout package needs no entry in packages: assigning model.layouts with the objects of sbmlutils.layout activates it.

Several models at once

create_model accepts an iterable of models, which are merged into one before the file is written. This keeps a large model in several files:

from examples import compartments, reactions, species

create_model(
    model=[compartments.model, species.model, reactions.model], filepath="model.xml"
)

The later model wins where the definitions overlap, which is how a base model is parameterized for a specific case.

Examples

The examples/ directory of the repository holds a runnable model for every concept: species in amounts and concentrations, reactions with units, assignments and rules, events, annotations, notes, and complete models from a small demo to a whole body physiological model. They are run as modules from the root of the repository:

python -m examples.species
python -m examples.tutorial.minimal_model