Skip to content

Commit 2c303c3

Browse files
dweindlclaude
andcommitted
Add petab.v2.reparametrize_log
PEtab v2 has no `parameterScale`. To estimate a parameter `p` on log scale (and to specify priors for `log10(p)`), `p` has to be replaced by a new parameter `log10_p` with `p = 10^log10_p`. `reparametrize_log` does this for a given set of parameters on a copy of the problem and returns the copy and the mapping of old to new IDs: * parameter table: log-transformed bounds and nominal values (a lower bound of 0 becomes -inf); priors given explicitly, or derived from `log-normal`, `log-laplace` and `log-uniform` priors * SBML model: new parameter `log10_p` and initial assignment `p = 10^log10_p` * observable/noise formulas and condition table target values: `p` -> `10^log10_p` * measurement table overrides: `p` -> `log10_p`, numeric overrides are log-transformed, and the placeholder `ph` -> `10^ph` in the formulas Base e is supported as well. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent f7612ec commit 2c303c3

7 files changed

Lines changed: 877 additions & 8 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@
7272
* `petab.v1.math.petab_symbol` (also in `petab.v2.math`) creates sympy
7373
symbols with the same assumptions as `sympify_petab`
7474
(by @dweindl in https://github.com/PEtab-dev/libpetab-python/pull/563)
75+
* `petab.v2.reparametrize_log` estimates parameters on log scale by replacing
76+
them with new log-transformed parameters
77+
(by @dweindl in https://github.com/PEtab-dev/libpetab-python/pull/560)
7578

7679
## 0.9 series
7780

‎doc/modules.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,4 @@ API Reference
4040
petab.v2.models
4141
petab.v2.options
4242
petab.v2.petab1to2
43+
petab.v2.reparametrize

‎petab/v2/__init__.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,4 @@
3838
from .lint import lint_problem # noqa: F401
3939
from .models import MODEL_TYPE_PYSB, MODEL_TYPE_SBML, Model # noqa: F401
4040
from .options import *
41+
from .reparametrize import reparametrize_log # noqa: F401

‎petab/v2/converters.py‎

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717
ExperimentPeriod,
1818
Problem,
1919
)
20-
from .models._sbml_utils import add_sbml_parameter, check
20+
from .models._sbml_utils import (
21+
add_sbml_parameter,
22+
check,
23+
set_initial_assignment,
24+
)
2125
from .models.sbml_model import SbmlModel
2226

2327
__all__ = ["ExperimentsToSbmlConverter", "assignments_to_experiments"]
@@ -351,13 +355,7 @@ def _create_initial_assignments(
351355
(default, True),
352356
)
353357

354-
# Create a new initial assignment if necessary, otherwise
355-
# overwrite the existing one.
356-
if ia is None:
357-
ia = model.createInitialAssignment()
358-
ia.setSymbol(target_id)
359-
360-
set_math(ia, expr)
358+
set_initial_assignment(model, target_id, expr)
361359
free_symbols_in_assignments |= expr.free_symbols
362360

363361
# the target value may depend on parameters that are only

‎petab/v2/models/_sbml_utils.py‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"""Private utility functions for SBML handling."""
22

33
import libsbml
4+
import sympy as sp
5+
from sbmlmath.mathml_printer import SBMLMathMLPrinter
46

57
retval_to_str = {
68
getattr(libsbml, attr): attr
@@ -49,3 +51,32 @@ def add_sbml_parameter(
4951
check(param.setConstant(constant))
5052

5153
return param
54+
55+
56+
def set_initial_assignment(
57+
model: libsbml.Model,
58+
symbol_id: str,
59+
expr: sp.Expr,
60+
literals_dimensionless: bool = True,
61+
) -> libsbml.InitialAssignment:
62+
"""Set the initial assignment for the given symbol.
63+
64+
Overwrites any existing initial assignment for that symbol.
65+
66+
:param literals_dimensionless:
67+
Whether to annotate numeric literals as dimensionless.
68+
(`sbmlmath` can't read back, e.g., ``10^x`` with a dimensionless
69+
base.)
70+
"""
71+
if (ia := model.getInitialAssignmentBySymbol(symbol_id)) is None:
72+
ia = model.createInitialAssignment()
73+
check(ia.setSymbol(symbol_id))
74+
mathml = SBMLMathMLPrinter(
75+
sbml_level=model.getLevel(),
76+
sbml_version=model.getVersion(),
77+
literals_dimensionless=literals_dimensionless,
78+
).doprint(expr)
79+
if (ast := libsbml.readMathMLFromString(mathml)) is None:
80+
raise ValueError(f"Failed to convert `{expr}' to MathML.")
81+
check(ia.setMath(ast))
82+
return ia

0 commit comments

Comments
 (0)