SBML lets a model set a parameter's initial value in two places: the value
attribute on the parameter element, and an initialAssignment. When both are
present the initial assignment wins, and the value attribute is often left as a
placeholder. The same is true for a species, where the placeholder is the
initialAmount or initialConcentration attribute.
PyBNF's SBML reader, pybnf/petab/_sbml.py, only ever reads the attributes. It
has no branch for listOfInitialAssignments. So when a model uses an initial
assignment, the reader reports a number the model does not actually start from,
and says nothing about it.
That number is used. pybnf/petab/export.py:1421 (_numeric_nominal) hands it to
pybnf/petab/conditions.py:183-195, which turns a relative condition, such as
multiply this parameter by two, into an absolute number written to
conditions.tsv. The exported problem then carries a wrong number with no
diagnostic.
Repro. Write this file as m.xml:
<?xml version="1.0" encoding="UTF-8"?>
<sbml xmlns="http://www.sbml.org/sbml/level3/version2/core" level="3" version="2">
<model id="m">
<listOfCompartments><compartment id="c" size="1" constant="true"/></listOfCompartments>
<listOfParameters>
<parameter id="koff" value="1" constant="true"/>
<parameter id="Kd" value="2" constant="true"/>
<parameter id="kon" value="0" constant="true"/>
</listOfParameters>
<listOfInitialAssignments>
<initialAssignment symbol="kon">
<math xmlns="http://www.w3.org/1998/Math/MathML">
<apply><divide/><ci>koff</ci><ci>Kd</ci></apply>
</math>
</initialAssignment>
</listOfInitialAssignments>
</model>
</sbml>
Then run:
from pathlib import Path
from pybnf.petab.export import _read_model, _numeric_nominal
from pybnf.petab.conditions import mutation_target_value
v = _read_model(Path('m.xml').read_text(), Path('m.xml'), 'sbml')
print(_numeric_nominal(v, 'kon'))
print(mutation_target_value('*', 2, nominal=_numeric_nominal(v, 'kon')))
It prints 0.0 and then 0. The model's effective kon is koff/Kd, which is 0.5,
so doubling it should export 1.0.
BioNetGen models are not affected, and only by accident. A BioNetGen expression
is read as a string, so float() on it raises and the relative condition is
refused at conditions.py:183-188 rather than computed from a wrong number.
How much this bites is not yet known, which is why this is an issue rather than
a change folded into other work. Two SBML models in the repository contain
initial assignments: tests/petab_fixtures/boehm_v2, where STAT5A and STAT5B
carry initialConcentration="1" while the initial assignments set them from
207.6*ratio, and tests/full_tests/T2-ade-abcd, which assigns species A. Neither
is currently the target of a relative condition, so no committed artifact is
wrong today. Someone needs to work out how far this reaches, including the
species path, before choosing between the two plausible fixes: read
listOfInitialAssignments and evaluate an assignment when it refers to nothing
else, or refuse the relative condition with a clear error, which is what the
BioNetGen path already does in effect.
For context, the petab library is making the same call for BioNetGen models in
PEtab-dev/libpetab-python#517: a value the model file alone cannot settle is not
reported at all, because a PEtab parameter table may override or estimate what
it depends on. Our SBML reader should end up following the same rule.
SBML lets a model set a parameter's initial value in two places: the value
attribute on the parameter element, and an initialAssignment. When both are
present the initial assignment wins, and the value attribute is often left as a
placeholder. The same is true for a species, where the placeholder is the
initialAmount or initialConcentration attribute.
PyBNF's SBML reader, pybnf/petab/_sbml.py, only ever reads the attributes. It
has no branch for listOfInitialAssignments. So when a model uses an initial
assignment, the reader reports a number the model does not actually start from,
and says nothing about it.
That number is used. pybnf/petab/export.py:1421 (_numeric_nominal) hands it to
pybnf/petab/conditions.py:183-195, which turns a relative condition, such as
multiply this parameter by two, into an absolute number written to
conditions.tsv. The exported problem then carries a wrong number with no
diagnostic.
Repro. Write this file as m.xml:
Then run:
It prints 0.0 and then 0. The model's effective kon is koff/Kd, which is 0.5,
so doubling it should export 1.0.
BioNetGen models are not affected, and only by accident. A BioNetGen expression
is read as a string, so float() on it raises and the relative condition is
refused at conditions.py:183-188 rather than computed from a wrong number.
How much this bites is not yet known, which is why this is an issue rather than
a change folded into other work. Two SBML models in the repository contain
initial assignments: tests/petab_fixtures/boehm_v2, where STAT5A and STAT5B
carry initialConcentration="1" while the initial assignments set them from
207.6*ratio, and tests/full_tests/T2-ade-abcd, which assigns species A. Neither
is currently the target of a relative condition, so no committed artifact is
wrong today. Someone needs to work out how far this reaches, including the
species path, before choosing between the two plausible fixes: read
listOfInitialAssignments and evaluate an assignment when it refers to nothing
else, or refuse the relative condition with a clear error, which is what the
BioNetGen path already does in effect.
For context, the petab library is making the same call for BioNetGen models in
PEtab-dev/libpetab-python#517: a value the model file alone cannot settle is not
reported at all, because a PEtab parameter table may override or estimate what
it depends on. Our SBML reader should end up following the same rule.