AMICI-dev/AMICI

PEtab SBML import fails when setting an event-assigned parameter via the condition table

Closed this issue · 0 comments

PEtab SBML import fails when setting the initial value of an event-assigned parameter via the condition table.

Fails in a rather cryptic manner:

AttributeError                            Traceback (most recent call last)
File python3.11/site-packages/sympy/core/numbers.py:1175, in Float.__new__(cls, num, dps, precision)
   1174 try:
-> 1175     _mpf_ = num._as_mpf_val(precision)
   1176 except (NotImplementedError, AttributeError):

AttributeError: 'Add' object has no attribute '_as_mpf_val'

During handling of the above exception, another exception occurred:

TypeError                                 Traceback (most recent call last)
File python3.11/site-packages/amici/petab_import.py:356, in import_petab_problem(petab_problem, model_output_dir, model_name, force_compile, non_estimated_parameters_as_constants, **kwargs)
    349         import_model_pysb(
    350             petab_problem,
    351             model_name=model_name,
    352             model_output_dir=model_output_dir,
    353             **kwargs,
    354         )
    355     else:
--> 356         import_model_sbml(
    357             petab_problem=petab_problem,
    358             model_name=model_name,
    359             model_output_dir=model_output_dir,
    360             non_estimated_parameters_as_constants=non_estimated_parameters_as_constants,
    361             **kwargs,
    362         )
    364 # import model
    365 model_module = amici.import_model_module(model_name, model_output_dir)

File python3.11/site-packages/amici/logging.py:209, in log_execution_time.<locals>.decorator_timer.<locals>.wrapper_timer(*args, **kwargs)
    206     level_length = len("DEBUG")
    208 tstart = time.perf_counter()
--> 209 rval = func(*args, **kwargs)
    210 tend = time.perf_counter()
    211 spacers = " " * max(
    212     59
    213     - len(description)
   (...)
    217     0,
    218 )

File python3.11/site-packages/amici/petab_import.py:746, in import_model_sbml(sbml_model, condition_table, observable_table, measurement_table, petab_problem, model_name, model_output_dir, verbose, allow_reinit_fixpar_initcond, validate, non_estimated_parameters_as_constants, output_parameter_defaults, discard_sbml_annotations, **kwargs)
    740 logger.info(
    741     "Variable parameters: "
    742     + str(len(sbml_model.getListOfParameters()) - len(fixed_parameters))
    743 )
    745 # Create Python module from SBML model
--> 746 sbml_importer.sbml2amici(
    747     model_name=model_name,
    748     output_dir=model_output_dir,
    749     observables=observables,
    750     constant_parameters=fixed_parameters,
    751     sigmas=sigmas,
    752     allow_reinit_fixpar_initcond=allow_reinit_fixpar_initcond,
    753     noise_distributions=noise_distrs,
    754     verbose=verbose,
    755     **kwargs,
    756 )
    758 if kwargs.get(
    759     "compile", amici._get_default_argument(sbml_importer.sbml2amici, "compile")
    760 ):
    761     # check that the model extension was compiled successfully
    762     model_module = amici.import_model_module(model_name, model_output_dir)

File python3.11/site-packages/amici/sbml_import.py:391, in SbmlImporter.sbml2amici(self, model_name, output_dir, observables, event_observables, constant_parameters, sigmas, event_sigmas, noise_distributions, event_noise_distributions, verbose, assume_pow_positivity, compiler, allow_reinit_fixpar_initcond, compile, compute_conservation_laws, simplify, cache_simplify, log_as_log10, generate_sensitivity_code)
    285 """
    286 Generate and compile AMICI C++ files for the model provided to the
    287 constructor.
   (...)
    387     not be generated
    388 """
    389 set_log_level(logger, verbose)
--> 391 ode_model = self._build_ode_model(
    392     observables=observables,
    393     event_observables=event_observables,
    394     constant_parameters=constant_parameters,
    395     sigmas=sigmas,
    396     event_sigmas=event_sigmas,
    397     noise_distributions=noise_distributions,
    398     event_noise_distributions=event_noise_distributions,
    399     verbose=verbose,
    400     compute_conservation_laws=compute_conservation_laws,
    401     simplify=simplify,
    402     cache_simplify=cache_simplify,
    403     log_as_log10=log_as_log10,
    404 )
    406 exporter = DEExporter(
    407     ode_model,
    408     model_name=model_name,
   (...)
    414     generate_sensitivity_code=generate_sensitivity_code,
    415 )
    416 exporter.generate_model_code()

File python3.11/site-packages/amici/sbml_import.py:463, in SbmlImporter._build_ode_model(self, observables, event_observables, constant_parameters, sigmas, event_sigmas, noise_distributions, event_noise_distributions, verbose, compute_conservation_laws, simplify, cache_simplify, log_as_log10)
    459 self._reset_symbols()
    460 self.sbml_parser_settings.setParseLog(
    461     sbml.L3P_PARSE_LOG_AS_LOG10 if log_as_log10 else sbml.L3P_PARSE_LOG_AS_LN
    462 )
--> 463 self._process_sbml(constant_parameters)
    465 if (
    466     self.symbols.get(SymbolId.EVENT, False)
    467     or any(
   (...)
    471     or self.flux_vector.has(sp.Heaviside, sp.Piecewise)
    472 ):
    473     if compute_conservation_laws:

File python3.11/site-packages/amici/logging.py:209, in log_execution_time.<locals>.decorator_timer.<locals>.wrapper_timer(*args, **kwargs)
    206     level_length = len("DEBUG")
    208 tstart = time.perf_counter()
--> 209 rval = func(*args, **kwargs)
    210 tend = time.perf_counter()
    211 spacers = " " * max(
    212     59
    213     - len(description)
   (...)
    217     0,
    218 )

File python3.11/site-packages/amici/sbml_import.py:512, in SbmlImporter._process_sbml(self, constant_parameters)
    510 self._process_parameters(constant_parameters)
    511 self._process_compartments()
--> 512 self._process_species()
    513 self._process_reactions()
    514 self._process_rules()

File python3.11/site-packages/amici/logging.py:209, in log_execution_time.<locals>.decorator_timer.<locals>.wrapper_timer(*args, **kwargs)
    206     level_length = len("DEBUG")
    208 tstart = time.perf_counter()
--> 209 rval = func(*args, **kwargs)
    210 tend = time.perf_counter()
    211 spacers = " " * max(
    212     59
    213     - len(description)
   (...)
    217     0,
    218 )

File python3.11/site-packages/amici/sbml_import.py:782, in SbmlImporter._process_species(self)
    770         continue
    771     self.symbols[SymbolId.SPECIES][_get_identifier_symbol(s)] = {
    772         "name": s.getName() if s.isSetName() else s.getId(),
    773         "compartment": _get_species_compartment_symbol(s),
   (...)
    779         "index": len(self.symbols[SymbolId.SPECIES]),
    780     }
--> 782 self._convert_event_assignment_parameter_targets_to_species()
    783 self._process_species_initial()
    784 self._process_rate_rules()

File python3.11/site-packages/amici/sbml_import.py:1306, in SbmlImporter._convert_event_assignment_parameter_targets_to_species(self)
   1298     parameter_def = {
   1299         "name": par.getName() if par.isSetName() else par.getId(),
   1300         "value": par.getValue() if ia_init is None else ia_init,
   1301     }
   1302 # Fixed parameters are added as species such that they can be
   1303 # targets of events.
   1304 self.symbols[SymbolId.SPECIES][parameter_target] = {
   1305     "name": parameter_def["name"],
-> 1306     "init": sp.Float(parameter_def["value"]),
   1307     # 'compartment': None,  # can ignore for amounts
   1308     "constant": False,
   1309     "amount": True,
   1310     # 'conversion_factor': 1.0,  # can be ignored
   1311     "index": len(self.symbols[SymbolId.SPECIES]),
   1312     "dt": sp.Float(0),
   1313 }

File python3.11/site-packages/sympy/core/numbers.py:1177, in Float.__new__(cls, num, dps, precision)
   1175         _mpf_ = num._as_mpf_val(precision)
   1176     except (NotImplementedError, AttributeError):
-> 1177         _mpf_ = mpmath.mpf(num, prec=precision)._mpf_
   1179 return cls._new(_mpf_, precision, zero=False)

File python3.11/site-packages/mpmath/ctx_mp_python.py:79, in _mpf.__new__(cls, val, **kwargs)
     77 else:
     78     v = new(cls)
---> 79     v._mpf_ = mpf_pos(cls.mpf_convert_arg(val, prec, rounding), prec, rounding)
     80     return v

File python3.11/site-packages/mpmath/ctx_mp_python.py:98, in _mpf.mpf_convert_arg(cls, x, prec, rounding)
     96         return a
     97     raise ValueError("can only create mpf from zero-width interval")
---> 98 raise TypeError("cannot create mpf from " + repr(x))

TypeError: cannot create mpf from initial_eventAssignedParameter_preeq*preequilibration_indicator + initial_eventAssignedParameter_sim*(1 - preequilibration_indicator)

Plain SBML import (without PEtab) works. The problem is

  1. the current way of handling initial values for use with preequilibration (even though in this example, no preequilibration was used)
    in combination with
  2. -> 1306 "init": sp.Float(parameter_def["value"]),, which does not handle expressions properly (which isn't necessary for regular SBML import)