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" ,
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
7171class 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 {
0 commit comments