Skip to content

Simulation rate not calculated correctly when compartments are present #79

@jmrohwer

Description

@jmrohwer

I picked up an issue when species are in conc, and output is in conc as well, with a model that has compartments (even only a single compartment) with a volume other than 1.

Illustrated with a simple mass-action model of a closed system. The following notebook shows the issue. In a nutshell, the starting concentrations and amounts seem to be correct, but the rate constant is evaluated wrong when the volume is not 1.

As far as I could ascertain this has to do with PySCeS converts species to amounts in Simulate() even when there is only a single compartment:

pysces/pysces/PyscesModel.py

Lines 4639 to 4640 in 1831cb2

if self.__HAS_COMPARTMENTS__ and self.__KeyWords__['Species_In_Conc']:
self.__inspec__ = self._SpeciesConcToAmount(self.__inspec__)

For EvalReq() the species are converted back to concentrations:

pysces/pysces/PyscesModel.py

Lines 3603 to 3607 in 1831cb2

def _EvalREq(self, s, Vtemp):
if self.__HAS_RATE_RULES__:
exec(self._CODE_raterule_map)
if self.__HAS_COMPARTMENTS__ and self.__KeyWords__['Species_In_Conc']:
s = self._SpeciesAmountToConc(s)

(Note that _EvalODE() calls EvalReq()).

However, CVODE() and LSODA() both assume in this case that the ODEs are actually in amounts, with the conversion to concentrations occurring at the end after the simulation. For CVODE:

pysces/pysces/PyscesModel.py

Lines 3909 to 3915 in 1831cb2

# convert to concentrations
if (
self.__HAS_COMPARTMENTS__
and self.__KeyWords__['Output_In_Conc']
):
for x in range(0, sim_res.shape[0]):
sim_res[x] = self._SpeciesAmountToConc(sim_res[x])

For LSODA:

pysces/pysces/PyscesModel.py

Lines 4052 to 4054 in 1831cb2

if self.__HAS_COMPARTMENTS__ and self.__KeyWords__['Output_In_Conc']:
for x in range(0, sim_res.shape[0]):
sim_res[x] = self._SpeciesAmountToConc(sim_res[x])

This means that when an ODE is evaluated in such a case, the LHS is assumed to be in amounts, while the RHS is in concentrations. Obviously this can't work if the compartment volume is not 1, and will give an error for all rate parameters (kcat, k, Vmax, etc.)

Finally, maybe this has to do with the following warning (not shown by default):

pysces/pysces/PyscesModel.py

Lines 3443 to 3446 in 1831cb2

if warn:
warnings += "# {}: {}\n# assuming kinetic constants are flow constants.\n".format(
rr, rrobj.formula
)

This is, however, not very practical.

I stumbled on this bug through the PySCeS Thinlayer for the PyEnzyme library used for analysing, processing and fitting enzyme kinetics data: https://github.com/EnzymeML/PyEnzyme specifically https://github.com/EnzymeML/PyEnzyme/tree/main/pyenzyme/thinlayers. The data are captured in an EnzymeML document (extension of SBML) which outputs the compartment (reaction vessel) by default with its volume (generally not equal to 1). However, for fitting purposes, all species are generally reported in concentrations, leading to an issue when fitting time courses with PySCeS.

Metadata

Metadata

Assignees

No one assigned

    Labels

    infoUseful information

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions