Skip to content
Draft
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
ae9e62a
Chain PEtab v2 experiment periods natively in the JAX simulator
claude Jul 4, 2026
9c84516
Fix JAX PEtab v2 bugs surfaced by petabtests v2 suite
claude Jul 4, 2026
ff3d96a
Fix remaining JAX PEtab v2 bugs found by the full petabtests v2 suite
claude Jul 4, 2026
58d7e7e
Refactor get_overrides into smaller functions; simplify; analytical g…
claude Jul 4, 2026
0dea65e
Fix DTypePromotionError regression in override matrix masking
claude Jul 4, 2026
d2ca2b9
Introduce OverrideColumn/_PeriodMeasurements types; de-nest _get_meas…
claude Jul 4, 2026
07c3691
Fix dtype-freezing default arguments and a missed period-axis call site
claude Jul 4, 2026
1059a4d
Update example notebook for native JAX period chaining
claude Jul 4, 2026
3e58c65
Address PEtab v2 JAX review feedback: override parsing, caching, even…
claude Jul 5, 2026
2932169
Re-evaluate heaviside/event state at every period boundary in the JAX…
claude Jul 5, 2026
49cf79c
Merge remote-tracking branch 'origin/main' into claude/jax-petab-even…
claude Jul 8, 2026
7b2bccd
Merge remote-tracking branch 'origin/main' into claude/jax-petab-even…
claude Jul 29, 2026
414783b
Fix per-experiment preequilibration reinit condition mismatch and sta…
claude Jul 29, 2026
81d4490
Fix per-measurement-row observable-transformation length mismatch and…
claude Jul 29, 2026
8491f6b
Gitignore the JAX SBML test suite's generated model directory
claude Jul 29, 2026
f9bdca7
Fix integer dtype for empty per-period observable-index arrays
claude Jul 29, 2026
c4841dc
Fix missing observable/override data for post-equilibrium measurements
claude Jul 29, 2026
82dba9f
Rename JAXModel.simulate_condition[_unjitted] to simulate_experiment,…
claude Jul 29, 2026
6834d3e
Fix stale docstring wording after simulate_experiment rename
claude Jul 29, 2026
c47d15d
Fix missing period axis in testSBMLSuite.py's jax_sensitivity_check
claude Jul 29, 2026
0a7a919
Simplify per-period measurement bucketing and compile condition-table…
claude Jul 29, 2026
82bece7
Reject state-referencing condition expressions explicitly instead of …
claude Jul 29, 2026
908d2db
Inline _resolve_override_symbol
claude Jul 29, 2026
f7d9aa4
Add deprecated simulate_condition alias; trim multi-period tests redu…
claude Jul 29, 2026
c0bfe91
Merge branch 'main' into claude/jax-petab-event-refactor-j48b04
FFroehlich Aug 5, 2026
8736d5e
Fix PEtab SciML CI failures: float-precision truncation and unrequire…
claude Aug 5, 2026
ea9bd46
Fix IndexError for hybridized parameters/states in periods with no co…
claude Aug 5, 2026
52d77c1
Fix state hybridization/reinitialisation being skipped for condition-…
claude Aug 5, 2026
de50f76
Merge branch 'main' into claude/jax-petab-event-refactor-j48b04
FFroehlich Aug 8, 2026
854bae2
Revert cast_to_sym float-precision workaround, superseded by #3224
claude Aug 8, 2026
d7d126a
Preserve heaviside state across a zero-duration period
claude Aug 8, 2026
c68bd62
Apply network-driven state initialisation only at the start of an exp…
claude Aug 8, 2026
5e83ba4
Add failing test for post-equilibration on a short ragged experiment
claude Aug 8, 2026
5011c2d
Post-equilibrate at each experiment's own last period
claude Aug 8, 2026
2bfc04d
Emit state reinitialisation into the generated JAX model
claude Aug 8, 2026
0a34fc9
Bump synthetic regression models to JAX model API version 0.0.5
claude Aug 8, 2026
35c508d
Document the JAX model API bump and reinitialisation regeneration
claude Aug 8, 2026
1b6f25e
Fix simulating a subset of experiments
claude Aug 8, 2026
c8fd51d
Don't read concrete values out of traced measurement masks
claude Aug 8, 2026
a6119f0
Add regression test for integral measurement row indices
claude Aug 8, 2026
506c090
Anchor padding periods at the end of the experiment's chain
claude Aug 10, 2026
f07b4a4
Post-equilibrate once per experiment, not once per period
claude Aug 10, 2026
3a9316e
Update remaining simulate_experiment callers to the flat time axis
claude Aug 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 59 additions & 17 deletions python/sdist/amici/importers/petab/_petab_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,13 +212,12 @@ def _preprocess_sbml(self):
if not isinstance(self.petab_problem.model, SbmlModel):
raise ValueError("The PEtab problem must contain an SBML model.")

# Convert petab experiments to events, because so far,
# AMICI only supports preequilibration/presimulation/simulation, but
# no arbitrary list of periods.
exp_event_conv = ExperimentsToSbmlConverter(self.petab_problem)
# This will always create a copy of the problem.
if self._jax:
self._unconverted_problem = exp_event_conv._original_problem
# The JAX backend natively chains one ODE integration per
# experiment period (see amici.sim.jax.petab), so there is no
# need to convert experiments with more than two periods into
# SBML events. The condition table is left untouched.
self._unconverted_problem = None
condition_targets = {
change.target_id
for condition in self.petab_problem.conditions
Expand All @@ -232,13 +231,36 @@ def _preprocess_sbml(self):
"The JAX backend does not currently support PEtab problems where network "
"parameters appear in the conditions table. "
)
self.petab_problem = exp_event_conv.convert()
for experiment in self.petab_problem.experiments:
if len(experiment.periods) > 2:
# This should never happen due to the conversion above
# Condition-table changes are applied directly in Python at
# simulation time (see JAXProblem), by either overriding a
# model parameter or reinitialising a species state. Any other
# target (e.g. a compartment size) has no such mechanism here.
sbml_model = self.petab_problem.model.sbml_model
unsupported_targets = {
target_id
for target_id in condition_targets
if sbml_model.getSpecies(target_id) is None
and sbml_model.getParameter(target_id) is None
}
if unsupported_targets:
raise NotImplementedError(
"AMICI currently does not support more than two periods."
"The JAX backend only supports condition table changes "
"that target a species or a parameter. Got change(s) "
f"targeting: {sorted(unsupported_targets)}."
)
else:
# Convert petab experiments to events, because so far, the
# sundials backend only supports preequilibration/presimulation/
# simulation, but no arbitrary list of periods.
exp_event_conv = ExperimentsToSbmlConverter(self.petab_problem)
# This will always create a copy of the problem.
self.petab_problem = exp_event_conv.convert()
for experiment in self.petab_problem.experiments:
if len(experiment.periods) > 2:
# This should never happen due to the conversion above
raise NotImplementedError(
"AMICI currently does not support more than two periods."
)

if self._debug:
print("PetabImpoter._preprocess_sbml: petab_problem:")
Expand All @@ -265,7 +287,15 @@ def _preprocess_pysb(self):

pysb.bng.generate_equations(self.petab_problem.model.model)

# Convert PEtab v2 experiments/conditions to events
# Convert PEtab v2 experiments/conditions to events. Unlike for SBML
# (see `_preprocess_sbml`), this is not skipped for the JAX backend:
# PySB condition-table targets are frequently pysb.Observable
# names that alias an underlying pysb.Initial/Expression rather
# than a state or free parameter directly, and applying those
# requires the same model-rewriting this converter already does.
# JAXProblem's native per-period parameter/state resolution has no
# equivalent for that, so PySB models keep going through event
# conversion for both backends.
converter = ExperimentsToPySBConverter(self.petab_problem)
self.petab_problem, self._events = converter.convert()

Expand Down Expand Up @@ -333,15 +363,27 @@ def _do_import_sbml(self):
output_parameter_defaults=self._output_parameter_defaults,
)

# All indicator variables, i.e., all remaining targets after
# experiments-to-event in the PEtab problem must be converted
# to fixed parameters
# All condition-table targets that are not estimated must be
# converted to fixed parameters. For the sundials backend, these are
# only ever the indicator variables introduced by the
# experiments-to-event conversion above. For the JAX backend, which
# keeps the original condition table, this may also contain state
# targets (species, or rate-/assignment-rule-governed parameters),
# which must NOT be treated as fixed parameters since they are
# handled via state reinitialisation instead. Compartment targets
# are also excluded here, but are unsupported for the JAX backend
# entirely (see the NotImplementedError raised in
# `_preprocess_sbml`) since AMICI does not support making a
# compartment a runtime-settable fixed parameter either way.
fixed_parameters = {
change.target_id
for experiment in self.petab_problem.experiments
for period in experiment.periods
for condition_id in period.condition_ids
for change in self.petab_problem[condition_id].changes
if not self.petab_problem.model.is_state_variable(
change.target_id
)
}

from .v1._sbml_import import show_model_info
Expand Down Expand Up @@ -771,8 +813,6 @@ def create_simulator(
Whether to force re-import even if the model module already exists.
:return: The created PEtab simulator.
"""
from amici.sim.sundials.petab import ExperimentManager, PetabSimulator

if self._jax:
model_module = self.import_module(force_import=force_import)
model = model_module.Model()
Expand All @@ -787,6 +827,8 @@ def create_simulator(
),
)

from amici.sim.sundials.petab import ExperimentManager, PetabSimulator

model = self.import_module(force_import=force_import).get_model()
em = ExperimentManager(model=model, petab_problem=self.petab_problem)
return PetabSimulator(em=em)
Expand Down
6 changes: 5 additions & 1 deletion python/sdist/amici/sim/jax/_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,11 @@ def solve(
term,
dict(**STARTING_STATS),
)
return sol.ys, jnp.repeat(h[None, :], sol.ys.shape[0]), stats
return (
sol.ys,
jnp.repeat(h[None, :], sol.ys.shape[0], axis=0),
stats,
)

def cond_fn(carry):
_, t_start, y0, _, _, stats = carry
Expand Down
Loading
Loading