11'''Provides comparisons between multiple simulations.'''
22
3+ """
4+ This module provides a class for comparing multiple models with common variables
5+ for the same time course. The class allows for the simulation of a collection of models
6+ with the same variables and generates plots and reports for the comparisons.
7+ The class is designed to be used with the PhraSED-ML format and provides methods
8+ for creating simulation directives, task directives, report directives, and plot directives.
9+
10+ The generation of PhraSED-ML strings is done through the `getPhrasedml` method,
11+ which constructs the string by adding the necessary directives based on the provided
12+ model references, simulation parameters, and display variables. This "late generation" approach
13+ allows for flexibility in model definitions since the definitions in the constructor
14+ can reference other model definitions that occur later on.
15+ """
16+
317import constants as cn # type: ignore
418from simple_sedml_base import SimpleSEDMLBase # type:ignore
519from typing import Optional , List
1024class MultipleModelTimeCourse (SimpleSEDMLBase ):
1125 """Provides comparisons between multiple simulations."""
1226
13- def __init__ (self , start :float = cn .D_START , end :float = cn .D_END , num_step :int = cn .D_NUM_STEP ,
14- num_point :int = cn .D_NUM_POINT , algorithm :str = cn .D_ALGORITHM ,
15- model_refs :Optional [List [str ]]= None ,
16- compare_variables :Optional [List [str ]]= None ,
27+ def __init__ (self ,
28+ model_refs :List [str ],
29+ start :float = cn .D_START ,
30+ end :float = cn .D_END ,
31+ num_step :Optional [int ]= None ,
32+ num_point :Optional [int ]= None ,
33+ algorithm :str = cn .D_ALGORITHM ,
34+ time_course_id :Optional [str ]= None ,
35+ display_variables :Optional [List [str ]]= None ,
36+ ** parameter_dct ,
1737 ):
1838 """Simulates a collection of models with common variables for the same time course.
1939 All models have the compared_variables. The outputs are:
@@ -29,6 +49,7 @@ def __init__(self, start:float=cn.D_START, end:float=cn.D_END, num_step:int=cn.D
2949 models (Optional[List[str]], optional): List of model references. Defaults to None.
3050 variables (Optional[List[str]], optional): List of variables to be compared. Defaults to None.
3151 if not provided, all variables in the model are used.
52+ parameters (Optional[dict], optional): Dictionary of parameters whose values are changed
3253
3354 Example 1: Compare two models with the same variables
3455 mmtc = MultipleModelTimeCourse(start=0, end=10, num_step=100,
@@ -44,22 +65,39 @@ def __init__(self, start:float=cn.D_START, end:float=cn.D_END, num_step:int=cn.D
4465 mmtc.addModel(model1_str, k1=0.2, k2=0.4)
4566 sedml_str = mmtc.getSEDMLString()
4667 """
68+ # Error checks
69+ if len (model_refs ) == 0 :
70+ raise ValueError ("No models have been added to the simulation." )
71+ #
72+ super ().__init__ ()
73+ #
4774 self .start = start
4875 self .end = end
4976 self .num_step = num_step
5077 self .num_point = num_point
5178 self .algorithm = algorithm
52- if model_refs is not None :
53- for model_ref in model_refs :
54- self .addModel (model_ref )
5579 self .model_refs = model_refs
56- if compare_variables is None :
57- compare_variables = []
58- self .compared_variables = compare_variables
59-
80+ self .time_course_id = time_course_id
81+ if display_variables is None :
82+ display_variables = []
83+ self .display_variables = display_variables
84+ self .parameter_dct = parameter_dct
85+
6086 def _makeSimulationDirective (self ):
6187 self .addSimulation (SIM_ID , "uniform" , start = self .start , end = self .end , num_step = self .num_step ,
6288 num_point = self .num_point , algorithm = self .algorithm )
89+
90+ @staticmethod
91+ def _makeTaskID (model_id :str )-> str :
92+ """Make a task ID from the model ID and simulation ID.
93+
94+ Args:
95+ model_id (str): model ID
96+
97+ Returns:
98+ str: task ID
99+ """
100+ return f"t{ model_id } "
63101
64102 def _makeTaskDirectives (self ):
65103 """Make the task directives for the compared variables.
@@ -70,79 +108,82 @@ def _makeTaskDirectives(self):
70108 if len (self .model_dct ) == 0 :
71109 raise ValueError ("No models have been added to the simulation." )
72110 #
73- for model_id in self .model_dct . keys () :
111+ for model_id in self .model_refs :
74112 task_id = self ._makeTaskID (model_id )
75113 self .addTask (task_id , model_id , SIM_ID )
76114
77- def _makeReportDirective (self ):
78- """Make the report directive for the compared variables.
115+ def _makeScopePrefix (self , model_id :str )-> str :
116+ """Makes the scoping prefix for the compared variables.
117+
118+ Args:
119+ model_id (str): model ID
79120
80121 Returns:
81- str: report directives
122+ str: task name
82123 """
83- if self .compared_variables is None :
84- first_model_id = list (self .model_dct .keys ())[0 ]
85- self .compared_variables = list (self .model_dct [first_model_id ].getInformation ().floating_species_dct .keys ())
86- #
87- report_variables = []
88- for model_id in self .model_dct .keys ():
89- task_prefix = self ._makeTaskID (model_id ) + "."
90- new_report_variable = [task_prefix + v for v in self .compared_variables ]
91- report_variables .extend (new_report_variable )
92- self .addReport (* report_variables )
93-
124+ return self ._makeTaskID (model_id ) + "."
125+
94126 def _makeVariables (self ):
95127 # Creates variables if it's None
96- if self .compared_variables is None :
128+ if self .display_variables is None :
97129 first_model_id = list (self .model_dct .keys ())[0 ]
98- self .compared_variables = list (self .model_dct [first_model_id ].getInformation ().floating_species_dct .keys ())
130+ self .display_variables = list (self .model_dct [first_model_id ].getInformation ().floating_species_dct .keys ())
99131
100- def _makePlotDirectives (self ):
101- """Make the plot directives for the compared variables.
132+ def _makeReportDirective (self , task_ids :List [str ]):
133+ """Make the report directive for the compared variables.
134+
135+ Args:
136+ task_ids: list of task ids
102137
103138 Returns:
104- str: plot directives
139+ str: report directives
105140 """
106- #
141+ # Calculate the task ids to consider
142+ # Handle the case where no variables are provided
107143 self ._makeVariables ()
108- for variable in self . compared_variables :
109- plot_variables = []
110- for model_id in self .model_dct . keys () :
111- task_prefix = self ._makeTaskID ( model_id ) + "."
112- plot_variables . append ( task_prefix + variable )
113- self .addPlot ( * plot_variables , title = variable )
144+ #
145+ report_variables = []
146+ for variable in self .display_variables :
147+ new_report_variables = [ self ._makeScopePrefix ( m ) + variable for m in task_ids ]
148+ report_variables . extend ( new_report_variables )
149+ self .addReport ( * report_variables )
114150
115- @ staticmethod
116- def _makeTaskID ( model_id : str ) -> str :
117- """Make a task ID from the model ID and simulation ID .
151+ def _makePlotDirective ( self , task_ids : List [ str ]):
152+ """Make the report directive for the compared variables.
153+ There is one plot for each variable that plots comparisons of the models .
118154
119155 Args:
120- model_id (str): model ID
156+ task_ids: list of task ids
121157
122158 Returns:
123- str: task ID
159+ str: report directives
124160 """
125- return f"t{ model_id } "
161+ #
162+ self ._makeVariables ()
163+ for variable in self .display_variables :
164+ plot_variables = [self ._makeScopePrefix (m ) + variable for m in task_ids ]
165+ self .addPlot (* plot_variables , title = variable )
126166
127- def getPhrasedml (self )-> str :
167+ def getPhraSEDML (self )-> str :
128168 """Construct the PhraSED-ML string. This requires:
129169 1. Create simulation and task directives
130170 2. Changing the model and report
131171
132172 Returns:
133- str: _description_
173+ str: Phrased-ML string
134174 """
135- ##
136- # Add the simulation directive
137- self .addSimulation (SIM_ID , "uniform" , start = self .start , end = self .end , num_step = self .num_step ,
138- num_point = self .num_point , algorithm = self .algorithm )
139- # Add a task directive for each model
140- for model_id in self .model_dct .keys ():
141- task_id = self ._makeTaskID (model_id )
142- self .addTask (task_id , model_id , SIM_ID )
143- for plot in self .plot_dct .values ():
144- plot .changeVariableScope (model_id , task_id )
145- # FIXME: do variable change for report
175+ # Add the models specified in the constructors
176+ exclude_ids = list (self .model_dct .keys ())
177+ for idx , model_ref in enumerate (self .model_refs ):
178+ model_id = f"model{ idx } "
179+ self .addModel (model_id , model_ref , is_overwrite = True , ** self .parameter_dct )
180+ # Calculate the task ids to consider
181+ task_ids = list (set (self .model_dct .keys ()) - set (exclude_ids ))
182+ # Add the other directives
183+ self ._makeSimulationDirective ()
184+ self ._makeTaskDirectives ()
185+ self ._makeReportDirective (task_ids )
186+ self ._makePlotDirectives (task_ids )
146187 #
147188 return self .self .super ().getPhrasedml ()
148189
@@ -152,4 +193,4 @@ def __str__(self)->str:
152193 Returns:
153194 str:
154195 """
155- return self .getPhrasedml ()
196+ return self .getPhraSEDML ()
0 commit comments