77import argparse
88import importlib
99import logging
10+ import math
1011import os
1112import re
1213import shutil
2425from _collections import OrderedDict
2526from amici .logging import get_logger , log_execution_time , set_log_level
2627from petab .C import *
28+ from petab .models import MODEL_TYPE_PYSB , MODEL_TYPE_SBML
2729from petab .parameters import get_valid_parameters_for_parameter_table
2830from sympy .abc import _clash
2931
32+ from .petab_util import PREEQ_INDICATOR_ID , get_states_in_condition_table
33+
3034try :
31- from amici .petab_import_pysb import PysbPetabProblem , import_model_pysb
35+ from amici .petab_import_pysb import import_model_pysb
3236except ModuleNotFoundError :
3337 # pysb not available
34- PysbPetabProblem = None
3538 import_model_pysb = None
3639
3740logger = get_logger (__name__ , logging .WARNING )
3841
39- # ID of model parameter that is to be added to SBML model to indicate
40- # preequilibration
41- PREEQ_INDICATOR_ID = "preequilibration_indicator"
42-
4342
4443def _add_global_parameter (
4544 sbml_model : libsbml .Model ,
@@ -97,25 +96,26 @@ def get_fixed_parameters(
9796 :return:
9897 List of IDs of parameters which are to be considered constant.
9998 """
100- # initial concentrations for species or initial compartment sizes in
101- # condition table will need to be turned into fixed parameters
102-
103- # if there is no initial assignment for that species, we'd need
104- # to create one. to avoid any naming collision right away, we don't
105- # allow that for now
106-
107- # we can't handle them yet
108- compartments = [
109- col
110- for col in petab_problem .condition_df
111- if petab_problem .sbml_model .getCompartment (col ) is not None
112- ]
113- if compartments :
114- raise NotImplementedError (
115- "Can't handle initial compartment sizes "
116- "at the moment. Consider creating an "
117- f"initial assignment for { compartments } "
118- )
99+ if petab_problem .model .type_id == MODEL_TYPE_SBML :
100+ # initial concentrations for species or initial compartment sizes in
101+ # condition table will need to be turned into fixed parameters
102+
103+ # if there is no initial assignment for that species, we'd need
104+ # to create one. to avoid any naming collision right away, we don't
105+ # allow that for now
106+
107+ # we can't handle them yet
108+ compartments = [
109+ col
110+ for col in petab_problem .condition_df
111+ if petab_problem .model .sbml_model .getCompartment (col ) is not None
112+ ]
113+ if compartments :
114+ raise NotImplementedError (
115+ "Can't handle initial compartment sizes "
116+ "at the moment. Consider creating an "
117+ f"initial assignment for { compartments } "
118+ )
119119
120120 # if we have a parameter table, all parameters that are allowed to be
121121 # listed in the parameter table, but are not marked as estimated, can be
@@ -142,16 +142,14 @@ def get_fixed_parameters(
142142 estimated_parameters = petab_problem .parameter_df .index .values
143143 fixed_parameters = set (all_parameters ) - set (estimated_parameters )
144144
145- sbml_model = petab_problem .sbml_model
146- condition_df = petab_problem .condition_df
147-
148145 # Column names are model parameter IDs, compartment IDs or species IDs.
149146 # Thereof, all parameters except for any overridden ones should be made
150147 # constant.
151148 # (Could potentially still be made constant, but leaving them might
152149 # increase model reusability)
153150
154151 # handle parameters in condition table
152+ condition_df = petab_problem .condition_df
155153 if condition_df is not None :
156154 logger .debug (f"Condition table: { condition_df .shape } " )
157155
@@ -167,30 +165,31 @@ def get_fixed_parameters(
167165 # of overriding
168166 if condition_df [p ].dtype != "O"
169167 # p is a parameter
170- and sbml_model .getParameter (p ) is not None
171- # but not a rule target
172- and sbml_model .getRuleByVariable (p ) is None
168+ and not petab_problem .model .is_state_variable (p )
173169 )
174170
175171 # Ensure mentioned parameters exist in the model. Remove additional ones
176172 # from list
177173 for fixed_parameter in fixed_parameters .copy ():
178174 # check global parameters
179- if not sbml_model .getParameter (fixed_parameter ):
175+ if not petab_problem .model .has_entity_with_id (fixed_parameter ):
176+ # TODO: could still exist as an output parameter?
180177 logger .warning (
181- f"Parameter or species '{ fixed_parameter } '"
182- " provided in condition table but not present in "
183- " model . Ignoring."
178+ f"Column '{ fixed_parameter } ' used in condition "
179+ "table but not entity with the corresponding ID "
180+ "exists . Ignoring."
184181 )
185182 fixed_parameters .remove (fixed_parameter )
186183
187- # exclude targets of rules or initial assignments
188- for fixed_parameter in fixed_parameters .copy ():
189- # check global parameters
190- if sbml_model .getInitialAssignmentBySymbol (
191- fixed_parameter
192- ) or sbml_model .getRuleByVariable (fixed_parameter ):
193- fixed_parameters .remove (fixed_parameter )
184+ if petab_problem .model .type_id == MODEL_TYPE_SBML :
185+ # exclude targets of rules or initial assignments
186+ sbml_model = petab_problem .model .sbml_model
187+ for fixed_parameter in fixed_parameters .copy ():
188+ # check global parameters
189+ if sbml_model .getInitialAssignmentBySymbol (
190+ fixed_parameter
191+ ) or sbml_model .getRuleByVariable (fixed_parameter ):
192+ fixed_parameters .remove (fixed_parameter )
194193
195194 return list (sorted (fixed_parameters ))
196195
@@ -300,17 +299,25 @@ def import_petab_problem(
300299 :return:
301300 The imported model.
302301 """
303- # extract model name from pysb
304- if (
305- PysbPetabProblem
306- and isinstance (petab_problem , PysbPetabProblem )
307- and model_name is None
308- ):
302+ if petab_problem .model .type_id not in (MODEL_TYPE_SBML , MODEL_TYPE_PYSB ):
303+ raise NotImplementedError (
304+ "Unsupported model type " + petab_problem .model .type_id
305+ )
306+
307+ if petab_problem .mapping_df is not None :
308+ # It's partially supported. Remove at your own risk...
309+ raise NotImplementedError ("PEtab v2.0.0 mapping tables are not yet supported." )
310+
311+ model_name = model_name or petab_problem .model .model_id
312+
313+ if petab_problem .model .type_id == MODEL_TYPE_PYSB and model_name is None :
309314 model_name = petab_problem .pysb_model .name
315+ elif model_name is None and model_output_dir :
316+ model_name = _create_model_name (model_output_dir )
310317
311318 # generate folder and model name if necessary
312319 if model_output_dir is None :
313- if PysbPetabProblem and isinstance ( petab_problem , PysbPetabProblem ) :
320+ if petab_problem . model . type_id == MODEL_TYPE_PYSB :
314321 raise ValueError ("Parameter `model_output_dir` is required." )
315322
316323 model_output_dir = _create_model_output_dir_name (
@@ -319,9 +326,6 @@ def import_petab_problem(
319326 else :
320327 model_output_dir = os .path .abspath (model_output_dir )
321328
322- if model_name is None :
323- model_name = _create_model_name (model_output_dir )
324-
325329 # create folder
326330 if not os .path .exists (model_output_dir ):
327331 os .makedirs (model_output_dir )
@@ -341,7 +345,7 @@ def import_petab_problem(
341345
342346 logger .info (f"Compiling model { model_name } to { model_output_dir } ." )
343347 # compile the model
344- if PysbPetabProblem and isinstance ( petab_problem , PysbPetabProblem ) :
348+ if petab_problem . model . type_id == MODEL_TYPE_PYSB :
345349 import_model_pysb (
346350 petab_problem ,
347351 model_name = model_name ,
@@ -664,13 +668,11 @@ def import_model_sbml(
664668
665669 # TODO: to parameterize initial states or compartment sizes, we currently
666670 # need initial assignments. if they occur in the condition table, we
667- # create a new parameter initial_${startOrCompartmentID }.
671+ # create a new parameter initial_${speciesOrCompartmentID }.
668672 # feels dirty and should be changed (see also #924)
669673 # <BeginWorkAround>
670674
671- initial_states = [
672- col for col in petab_problem .condition_df if element_is_state (sbml_model , col )
673- ]
675+ initial_states = get_states_in_condition_table (petab_problem )
674676 fixed_parameters = []
675677 if initial_states :
676678 # add preequilibration indicator variable
@@ -691,7 +693,7 @@ def import_model_sbml(
691693 logger .debug (
692694 "Adding preequilibration indicator " f"constant { PREEQ_INDICATOR_ID } "
693695 )
694- logger .debug (f"Adding initial assignments for { initial_states } " )
696+ logger .debug (f"Adding initial assignments for { initial_states . keys () } " )
695697 for assignee_id in initial_states :
696698 init_par_id_preeq = f"initial_{ assignee_id } _preeq"
697699 init_par_id_sim = f"initial_{ assignee_id } _sim"
@@ -782,7 +784,6 @@ def get_observation_model(
782784 :return:
783785 Tuple of dicts with observables, noise distributions, and sigmas.
784786 """
785-
786787 if observable_df is None :
787788 return {}, {}, {}
788789
@@ -871,28 +872,13 @@ def show_model_info(sbml_model: "libsbml.Model"):
871872 logger .info (f"Reactions: { len (sbml_model .getListOfReactions ())} " )
872873
873874
874- def element_is_state (sbml_model : libsbml .Model , sbml_id : str ) -> bool :
875- """Does the element with ID `sbml_id` correspond to a state variable?"""
876- if sbml_model .getCompartment (sbml_id ) is not None :
877- return True
878- if sbml_model .getSpecies (sbml_id ) is not None :
879- return True
880- if (
881- rule := sbml_model .getRuleByVariable (sbml_id )
882- ) is not None and rule .getTypeCode () == libsbml .SBML_RATE_RULE :
883- return True
884-
885- return False
886-
887-
888875def _parse_cli_args ():
889876 """
890877 Parse command line arguments
891878
892879 :return:
893880 Parsed CLI arguments from :mod:`argparse`.
894881 """
895-
896882 parser = argparse .ArgumentParser (
897883 description = "Import PEtab-format model into AMICI."
898884 )
0 commit comments