Skip to content

Units

Every SBML model declares units for its parameters, species and compartments. sbmlsim reads them and uses pint quantities for changes and results, so a dose given in milligram is converted to the substance unit of the model instead of being assumed to match.

Units of a model

The units are read into a UnitsInformation, a mapping from identifier to unit string with the unit registry of the model:

from sbmlsim.resources import DEMO_SBML
from sbmlsim.units import UnitsInformation

uinfo = UnitsInformation.from_sbml(DEMO_SBML)
print(uinfo["Vmax_bA"])
print(uinfo["e__A"])  # amount of the species
print(uinfo["[e__A]"])  # concentration of the species

Every RoadrunnerSBMLModel and every SimulatorSerial carry the units of their model as uinfo, and Q_ is the quantity constructor of the registry:

from sbmlsim.simulator import SimulatorSerial

simulator = SimulatorSerial(model=DEMO_SBML)
Q_ = simulator.Q_
dose = Q_(10, "mmole")
print(dose, dose.to("mole"))

Changes with units

Changes of a Timecourse or a Dimension are quantities; they are converted to the units of the model before the simulation. A float without a unit is taken in the units of the model:

import numpy as np

from sbmlsim.simulation import Dimension, ScanSim, Timecourse, TimecourseSim

scan = ScanSim(
    simulation=TimecourseSim(
        Timecourse(
            start=0,
            end=10,
            steps=100,
            changes={
                "[e__A]": Q_(10, "mM"),
                "[e__B]": Q_(1, "mmole/litre"),
                "[e__C]": Q_(1, "mole/m**3"),
                "c__A": Q_(1e-5, "mole"),
                "c__B": Q_(10, "µmole"),
                "Vmax_bA": Q_(300.0, "mole/min"),
            },
        )
    ),
    dimensions=[
        Dimension("dim1", changes={"[e__A]": Q_(np.linspace(5, 15, num=5), "mM")}),
    ],
)
xres = simulator.run_scan(scan)
print(xres["[e__A]"].values[0])

A change with a unit which cannot be converted to the model unit raises a DimensionalityError, which is the point: a dose in mg for a parameter in mmole is a mistake the units catch.

UnitsInformation.normalize_changes performs the conversion; the normalize methods of Timecourse, TimecourseSim and ScanSim call it before a simulation.

Results with units

The result of a simulation knows the units of its variables, so reductions return quantities:

print(xres.uinfo["[e__A]"])
mean = xres.dim_mean("[e__A]")
print(mean.units)
print(mean.to("mole/litre").magnitude[:3])

Data in a Data object or a DataSet are converted into requested units the same way, see Data; the axes of a plot declare their unit and the curves are converted to it, see Plots and reports.

The unit registry

All quantities of a model share one UnitRegistry. A SimulationExperiment creates a single registry which its models, datasets and results share, so quantities from different sources can be combined. The registry is extended with the units SBML uses, e.g., mmole for millimole, in UnitsInformation._default_ureg.