Skip to content

Commit f719e0f

Browse files
authored
Use sbmlmath package for sympification of SBML math constructs (#2681)
* Use sbmlmath package for sympification of SBML math Directly parse the SBML MathML constructs without going through SBML L3 formula strings are sympy.sympify due to various issues (#2146). * .. * fix rateof * log_as_log10 * time * log10; hardcoded symbols * units, XOR * evalf, heaviside where needed * fixup; avogadro * simplify, trigger==False, exception type * bool, None * expr/basic * redundant formula * Revert "redundant formula" This reverts commit 73bec7b. * Revert "expr/basic" This reverts commit e592b5b. * BooleanFunction to Piecewise * Fix passenv * cleanup avogadro * evaluate / simplify * cleanup * -git+https * simplify still needed? * .. * cleanup * .. * exception type; DRY * none * doc
1 parent a87058e commit f719e0f

7 files changed

Lines changed: 237 additions & 144 deletions

File tree

python/sdist/amici/de_model.py

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,8 @@ def states(self) -> list[State]:
409409

410410
def _process_sbml_rate_of(self) -> None:
411411
"""Substitute any SBML-rateOf constructs in the model equations"""
412-
rate_of_func = sp.core.function.UndefinedFunction("rateOf")
412+
from sbmlmath import rate_of as rate_of_func
413+
413414
species_sym_to_xdot = dict(
414415
zip(self.sym("x"), self.sym("xdot"), strict=True)
415416
)
@@ -449,25 +450,21 @@ def get_rate(symbol: sp.Symbol):
449450

450451
# replace rateOf-instances in x0 by xdot equation
451452
for i_state in range(len(self.eq("x0"))):
452-
if rate_ofs := self._eqs["x0"][i_state].find(rate_of_func):
453-
self._eqs["x0"][i_state] = self._eqs["x0"][i_state].subs(
454-
{
455-
rate_of: get_rate(rate_of.args[0])
456-
for rate_of in rate_ofs
457-
}
458-
)
453+
new, replacement = self._eqs["x0"][i_state].replace(
454+
rate_of_func, get_rate, map=True
455+
)
456+
if replacement:
457+
self._eqs["x0"][i_state] = new
459458

460459
# replace rateOf-instances in w by xdot equation
461460
# here we may need toposort, as xdot may depend on w
462461
made_substitutions = False
463462
for i_expr in range(len(self.eq("w"))):
464-
if rate_ofs := self._eqs["w"][i_expr].find(rate_of_func):
465-
self._eqs["w"][i_expr] = self._eqs["w"][i_expr].subs(
466-
{
467-
rate_of: get_rate(rate_of.args[0])
468-
for rate_of in rate_ofs
469-
}
470-
)
463+
new, replacement = self._eqs["w"][i_expr].replace(
464+
rate_of_func, get_rate, map=True
465+
)
466+
if replacement:
467+
self._eqs["w"][i_expr] = new
471468
made_substitutions = True
472469

473470
if made_substitutions:

python/sdist/amici/import_utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,8 @@ def _parse_heaviside_trigger(trigger: sp.Expr) -> sp.Expr:
540540
]
541541
)
542542

543+
# TODO: x XOR y = (A & ~B) | (~A & B)
544+
# TODO: x == y
543545
if isinstance(trigger, sp.And):
544546
return sp.Mul(*[_parse_heaviside_trigger(arg) for arg in trigger.args])
545547

@@ -598,6 +600,7 @@ def _check_unsupported_functions(
598600
sp.functions.factorial,
599601
sp.functions.ceiling,
600602
sp.functions.floor,
603+
sp.functions.tan,
601604
sp.functions.sec,
602605
sp.functions.csc,
603606
sp.functions.cot,

0 commit comments

Comments
 (0)