Skip to content

Commit 7275c45

Browse files
committed
cleanup, numthreads
1 parent 7329b90 commit 7275c45

File tree

5 files changed

+76
-115
lines changed

5 files changed

+76
-115
lines changed

.github/workflows/test_petab_test_suite.yml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ jobs:
174174
&& git checkout c12b9dc4e4c5585b1b83a1d6e89fd22447c46d03 \
175175
&& pip3 install -e .
176176
177+
# TODO: once there is a PEtab v2 benchmark collection
177178
# - name: Install PEtab benchmark collection
178179
# run: |
179180
# git clone --depth 1 https://github.com/benchmarking-initiative/Benchmark-Models-PEtab.git \
@@ -188,12 +189,6 @@ jobs:
188189
&& python3 -m pip install git+https://github.com/pysb/pysb@master \
189190
&& python3 -m pip install sympy>=1.12.1
190191
191-
# - name: Run PEtab-related unit tests
192-
# run: |
193-
# source ./venv/bin/activate \
194-
# && pytest --cov-report=xml:coverage.xml \
195-
# --cov=./ python/tests/test_*petab*.py python/tests/petab_/
196-
197192
# run test models
198193
- name: Run PEtab test suite
199194
run: |

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ See also our [versioning policy](https://amici.readthedocs.io/en/latest/versioni
5454
* Experimental support for the PEtab data format v2.0.0 (draft, see
5555
https://petab.readthedocs.io/en/latest/v2/documentation_data_format.html)
5656
for SBML- and PySB-based problems (see `amici.petab.petab_importer`).
57+
58+
* Current limitations for PySB-based PEtab problems:
59+
* Only species and `pysb.Parameter` are supported as condition table
60+
targets.
61+
5762
* Many relevant `ReturnData` fields are now available as `xarray.DataArray`
5863
via `ReturnData.xr.{x,y,w,x0,sx,...}`.
5964
`DataArray`s include the identifiers and are often more convenient than the

python/sdist/amici/petab/petab_importer.py

Lines changed: 55 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"ExperimentManager",
4444
"PetabSimulator",
4545
"rdatas_to_measurement_df",
46+
"rdatas_to_simulation_df",
4647
"flatten_timepoint_specific_output_overrides",
4748
"unflatten_simulation_df",
4849
"has_timepoint_specific_overrides",
@@ -65,7 +66,6 @@
6566
# TODO: how to handle SBML vs PySB, jax vs sundials?
6667
# -> separate importers or subclasses?
6768
# TODO: How to handle multi-model-problems?
68-
# TODO: test simulation of up-converted benchmark problems
6969

7070

7171
class PetabImporter:
@@ -74,8 +74,8 @@ class PetabImporter:
7474
7575
This class is used to create an AMICI model from a PEtab problem.
7676
77-
The underlying SBML model will be modified to encode the experiments
78-
defined in the PEtab problem as events.
77+
The underlying SBML or PySB model will be modified to encode the
78+
experiments defined in the PEtab problem as events or initial conditions.
7979
8080
Be careful when using the imported model for anything other than the
8181
PEtab-encoded experiments.
@@ -112,10 +112,10 @@ def __init__(
112112
The output directory where the model files are written to.
113113
:param jax: TODO
114114
"""
115-
# TODO: only copy if needed
116-
self.petab_problem: v2.Problem = copy.deepcopy(
117-
self._upgrade_if_needed(petab_problem)
115+
self.petab_problem: v2.Problem = self._upgrade_or_copy_if_needed(
116+
petab_problem
118117
)
118+
self._debug = False
119119

120120
if len(self.petab_problem.models) > 1:
121121
raise NotImplementedError(
@@ -129,21 +129,21 @@ def __init__(
129129
):
130130
# if self.petab_problem.model.type_id != MODEL_TYPE_SBML:
131131
raise NotImplementedError(
132-
"PEtab v2 importer currently only supports SBML models. "
133-
f"Got {self.petab_problem.model.type_id!r}."
132+
"PEtab v2 importer currently only supports SBML and PySB "
133+
f"models. Got {self.petab_problem.model.type_id!r}."
134134
)
135135
if jax:
136136
raise NotImplementedError(
137137
"PEtab v2 importer currently does not support JAX. "
138138
)
139139

140-
pprint(self.petab_problem.model_dump())
141-
if self.petab_problem.model.type_id == MODEL_TYPE_SBML:
142-
print(self.petab_problem.model.to_antimony())
143-
elif self.petab_problem.model.type_id == MODEL_TYPE_PYSB:
144-
print(self.petab_problem.model.to_str())
145-
146-
self._check_support(self.petab_problem)
140+
if self._debug:
141+
print("PetabImpoter.__init__: petab_problem:")
142+
pprint(self.petab_problem.model_dump())
143+
if self.petab_problem.model.type_id == MODEL_TYPE_SBML:
144+
print(self.petab_problem.model.to_antimony())
145+
elif self.petab_problem.model.type_id == MODEL_TYPE_PYSB:
146+
print(self.petab_problem.model.to_str())
147147

148148
self._compile = compile_
149149
self._sym_model: DEModel | None = None
@@ -176,6 +176,11 @@ def __init__(
176176
def _preprocess_sbml(self):
177177
"""Pre-process the SBML-based PEtab problem to make it
178178
amici-compatible."""
179+
from petab.v2.models.sbml_model import SbmlModel
180+
181+
if not isinstance(self.petab_problem.model, SbmlModel):
182+
raise ValueError("The PEtab problem must contain an SBML model.")
183+
179184
# Convert petab experiments to events, because so far,
180185
# AMICI only supports preequilibration/presimulation/simulation, but
181186
# no arbitrary list of periods.
@@ -188,17 +193,14 @@ def _preprocess_sbml(self):
188193
"AMICI currently does not support more than two periods."
189194
)
190195

191-
# TODO remove dbg
192-
pprint(self.petab_problem.model_dump())
193-
print(self.petab_problem.model.to_antimony())
196+
if self._debug:
197+
print("PetabImpoter._preprocess_sbml: petab_problem:")
198+
pprint(self.petab_problem.model_dump())
199+
print(self.petab_problem.model.to_antimony())
194200

195201
def _preprocess_pysb(self):
196202
"""Pre-process the PySB-based PEtab problem to make it
197203
amici-compatible."""
198-
# TODO: test cases 1--4 7-8 14-15 work
199-
# skipped: 6 (timepoint-specific overrides) 9 (>1 condition) 10,11,13,16,17 (mapping)
200-
# failing: 5 (condition changes / preeq https://github.com/AMICI-dev/AMICI/issues/2975) 12
201-
# update 16: disallowed unnecessary aliasing via mapping table
202204
import pysb
203205
from petab.v2.models.pysb_model import PySBModel
204206

@@ -216,35 +218,21 @@ def _preprocess_pysb(self):
216218
converter = ExperimentsToPySBConverter(self.petab_problem)
217219
self.petab_problem, self._events = converter.convert()
218220

219-
def _upgrade_if_needed(
221+
def _upgrade_or_copy_if_needed(
220222
self, problem: v1.Problem | v2.Problem
221223
) -> v2.Problem:
222-
"""Upgrade the problem to petab v2 if necessary."""
224+
"""Upgrade the problem to petab v2 if necessary.
225+
Otherwise, create a deep copy of the problem."""
223226
if isinstance(problem, v2.Problem):
224-
return problem
227+
return copy.deepcopy(problem)
225228

226229
# TODO: So far, PEtab can only upgrade file-based problems,
227230
# not petab.v1.Problem objects.
228-
raise NotImplementedError("Only petab.v2.Problem is supported.")
229-
230-
@classmethod
231-
def _check_support(cls, petab_problem: v2.Problem):
232-
"""Check if the PEtab problem requires unsupported features."""
233-
...
234-
# # check support for mapping tables
235-
# relevant_mappings = [
236-
# m
237-
# for m in petab_problem.mappings
238-
# # we can ignore annotation-only entries
239-
# if m.model_id is not None
240-
# # we can ignore identity mappings
241-
# and m.petab_id != m.model_id
242-
# ]
243-
# if relevant_mappings:
244-
# # It's partially supported. Remove at your own risk...
245-
# raise NotImplementedError(
246-
# "PEtab v2.0.0 mapping tables are not yet supported."
247-
# )
231+
raise NotImplementedError(
232+
"Only `petab.v2.Problem` is currently supported. "
233+
"For use with PEtab 1.0 problems, please use "
234+
"`petab.v2.Problem.from_yaml(petab_v1_yaml_file)` for upgrading."
235+
)
248236

249237
@property
250238
def model_id(self) -> str:
@@ -285,13 +273,6 @@ def _do_import_sbml(
285273
# TODO split into DEModel creation, code generation and compilation
286274
# allow retrieving DEModel without compilation
287275

288-
from petab.v2.models.sbml_model import SbmlModel
289-
290-
if not isinstance(self.petab_problem.model, SbmlModel):
291-
raise ValueError("The PEtab problem must contain an SBML model.")
292-
293-
# set_log_level(logger, verbose)
294-
295276
logger.info("Importing model ...")
296277

297278
if not self.petab_problem.observables:
@@ -316,13 +297,12 @@ def _do_import_sbml(
316297
logger.info(f"#Observables: {len(observation_model)}")
317298
logger.debug(f"Observables: {observation_model}")
318299

300+
# TODO: to attr
319301
output_parameter_defaults = {}
320302
self._workaround_observable_parameters(
321303
output_parameter_defaults=output_parameter_defaults,
322304
)
323305

324-
sbml_model = self.petab_problem.model.sbml_model
325-
326306
# All indicator variables, i.e., all remaining targets after
327307
# experiments-to-event in the PEtab problem must be converted
328308
# to fixed parameters
@@ -334,14 +314,12 @@ def _do_import_sbml(
334314
for change in self.petab_problem[condition_id].changes
335315
}
336316

337-
# show_model_info(sbml_model)
338-
# TODO spline stuff, to __init__
339-
discard_sbml_annotations = False
317+
from amici.petab.sbml_import import show_model_info
318+
319+
show_model_info(self.petab_problem.model.sbml_model)
340320
sbml_importer = amici.SbmlImporter(
341-
sbml_model,
342-
discard_annotations=discard_sbml_annotations,
321+
self.petab_problem.model.sbml_model,
343322
)
344-
sbml_model = sbml_importer.sbml
345323

346324
self._check_placeholders()
347325

@@ -351,15 +329,8 @@ def _do_import_sbml(
351329
)
352330

353331
fixed_parameters = list(sorted(fixed_parameters))
354-
332+
logger.info(f"Number of fixed parameters: {len(fixed_parameters)}")
355333
logger.debug(f"Fixed parameters are {fixed_parameters}")
356-
logger.info(f"Overall fixed parameters: {len(fixed_parameters)}")
357-
logger.info(
358-
"Variable parameters: "
359-
+ str(
360-
len(sbml_model.getListOfParameters()) - len(fixed_parameters)
361-
)
362-
)
363334

364335
# Create Python module from SBML model
365336
if self._jax:
@@ -381,19 +352,13 @@ def _do_import_sbml(
381352
constant_parameters=fixed_parameters,
382353
allow_reinit_fixpar_initcond=allow_reinit_fixpar_initcond,
383354
verbose=self._verbose,
355+
compile=self._compile,
384356
# FIXME: simplification takes ages for Smith_BMCSystBiol2013
385357
# due to nested piecewises / Heavisides?!
386358
simplify=None,
387359
# **kwargs,
388360
)
389-
# TODO: ensure that all estimated parameters are present as
390-
# (non-constant) parameters in the model
391-
392-
if self._compile:
393-
# check that the model extension was compiled successfully
394-
_ = self.import_module()
395-
# model = model_module.getModel()
396-
# TODO check_model(amici_model=model, petab_problem=petab_problem)
361+
# TODO check_model(amici_model=model, petab_problem=petab_problem)
397362

398363
return sbml_importer
399364

@@ -422,6 +387,7 @@ def _do_import_pysb(
422387
"is currently not supported."
423388
)
424389

390+
# TODO from yaml
425391
if self.model_id is None:
426392
raise ValueError(
427393
"No `model_id` was provided and no model "
@@ -491,13 +457,11 @@ def _do_import_pysb(
491457
constant_parameters=fixed_parameters,
492458
observation_model=observation_model,
493459
pysb_model_has_obs_and_noise=True,
460+
compile=self._compile,
494461
_events=self._events,
495462
# **kwargs,
496463
)
497464

498-
# TODO: ensure that all estimated parameters are present as
499-
# (non-constant) parameters in the model
500-
501465
if self._compile:
502466
# check that the model extension was compiled successfully
503467
_ = self.import_module()
@@ -1092,17 +1056,25 @@ class PetabSimulator:
10921056
:param em: The ExperimentManager to generate the ExpData objects.
10931057
:param solver: The AMICI solver to use for the simulations.
10941058
If not provided, a new solver with default settings will be used.
1059+
:param num_threads: The number of threads to use for parallel
1060+
simulation of experiments. Only relevant if multiple experiments
1061+
are present in the PEtab problem and if AMICI was compiled with
1062+
OpenMP support.
10951063
"""
10961064

10971065
def __init__(
1098-
self, em: ExperimentManager, solver: amici.Solver | None = None
1066+
self,
1067+
em: ExperimentManager,
1068+
solver: amici.Solver | None = None,
1069+
num_threads: int = 1,
10991070
):
11001071
self._petab_problem = em.petab_problem
11011072
self._model = em.model
11021073
self._solver = (
11031074
solver if solver is not None else self._model.create_solver()
11041075
)
11051076
self._exp_man: ExperimentManager = em
1077+
self.num_threads = num_threads
11061078

11071079
def simulate(
11081080
self, problem_parameters: dict[str, float] = None
@@ -1139,7 +1111,9 @@ def simulate(
11391111
edata=edata, problem_parameters=problem_parameters
11401112
)
11411113

1142-
rdatas = amici.run_simulations(self._model, self._solver, edatas)
1114+
rdatas = amici.run_simulations(
1115+
self._model, self._solver, edatas, num_threads=self.num_threads
1116+
)
11431117
from . import EDATAS, LLH, RDATAS, SLLH
11441118

11451119
return {

tests/benchmark_models/test_petab_benchmark.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -595,12 +595,6 @@ def write_debug_output(
595595
df.to_csv(file_name, sep="\t")
596596

597597

598-
# TODO: gradient check for PEtab v2
599-
# problems_for_llh_check = [
600-
# "Boehm_JProteomeRes2014",
601-
# ]
602-
603-
604598
@pytest.mark.filterwarnings(
605599
"ignore:divide by zero encountered in log",
606600
# https://github.com/AMICI-dev/AMICI/issues/18
@@ -611,7 +605,8 @@ def write_debug_output(
611605
)
612606
@pytest.mark.parametrize("problem_id", problems_for_llh_check)
613607
def test_nominal_parameters_llh_v2(problem_id):
614-
"""Test the log-likelihood computation at nominal parameters.
608+
"""Test the log-likelihood computation at nominal parameters
609+
after auto-conversion of PEtab v1 benchmark problems to PEtab v2.
615610
616611
Also check that the simulation time is within the reference range.
617612
"""
@@ -677,6 +672,8 @@ def test_nominal_parameters_llh_v2(problem_id):
677672
ps._solver.set_absolute_tolerance(1e-8)
678673
ps._solver.set_relative_tolerance(1e-8)
679674
ps._solver.set_max_steps(10_000)
675+
ps.num_threads = os.cpu_count()
676+
680677
if problem_id in ("Brannmark_JBC2010", "Isensee_JCB2018"):
681678
ps._model.set_steady_state_sensitivity_mode(
682679
SteadyStateSensitivityMode.integrationOnly
@@ -793,7 +790,6 @@ def test_nominal_parameters_llh_v2(problem_id):
793790
ps,
794791
parameter_ids=parameter_ids,
795792
cache=False,
796-
# TODO: num_threads=os.cpu_count(),
797793
)
798794
np.random.seed(cur_settings.rng_seed)
799795

@@ -914,6 +910,7 @@ def compare_to_reference(problem_id: str, llh: float):
914910
"Reference llh from benchmark collection simulation table:",
915911
ref_llh_bm,
916912
)
913+
# TODO https://github.com/Benchmarking-Initiative/Benchmark-Models-PEtab/issues/278
917914
# assert np.isclose(
918915
# ref_llh, ref_llh_bm
919916
# ), f"Stored Reference llh {ref_llh} differs from the value computed "\

0 commit comments

Comments
 (0)