1212from biosimulators_utils .log .data_model import CombineArchiveLog , TaskLog , StandardOutputErrorCapturerLevel # noqa: F401
1313from biosimulators_utils .viz .data_model import VizFormat # noqa: F401
1414from biosimulators_utils .report .data_model import ReportFormat , VariableResults , SedDocumentResults # noqa: F401
15- from biosimulators_utils .sedml .data_model import (Task , ModelLanguage , UniformTimeCourseSimulation , # noqa: F401
15+ from biosimulators_utils .sedml .data_model import (Task , ModelLanguage , ModelAttributeChange , UniformTimeCourseSimulation , # noqa: F401
1616 Algorithm , Variable , Symbol )
1717from biosimulators_utils .sedml import validation
1818from biosimulators_utils .sedml .exec import exec_sed_doc as base_exec_sed_doc
19+ from biosimulators_utils .sedml .utils import apply_changes_to_xml_model
1920from biosimulators_utils .simulator .utils import get_algorithm_substitution_policy
2021from biosimulators_utils .utils .core import raise_errors_warnings
2122from biosimulators_utils .warnings import warn , BioSimulatorsWarning
2223from kisao .data_model import AlgorithmSubstitutionPolicy , ALGORITHM_SUBSTITUTION_POLICY_LEVELS
2324from kisao .utils import get_preferred_substitute_algorithm_by_ids
25+ import copy
2426import libsbmlsim
2527import lxml .etree
2628import os
@@ -128,70 +130,44 @@ def exec_sed_task(task, variables, preprocessed_task=None, log=None, config=None
128130 model = task .model
129131 sim = task .simulation
130132
131- if config .VALIDATE_SEDML :
132- raise_errors_warnings (validation .validate_task (task ),
133- error_summary = 'Task `{}` is invalid.' .format (task .id ))
134- raise_errors_warnings (validation .validate_model_language (model .language , ModelLanguage .SBML ),
135- error_summary = 'Language for model `{}` is not supported.' .format (model .id ))
136- raise_errors_warnings (validation .validate_model_change_types (model .changes , ()),
133+ # change model
134+ if model .changes :
135+ raise_errors_warnings (validation .validate_model_change_types (model .changes , (ModelAttributeChange ,)),
137136 error_summary = 'Changes for model `{}` are not supported.' .format (model .id ))
138- raise_errors_warnings (* validation .validate_model_changes (task .model ),
139- error_summary = 'Changes for model `{}` are invalid.' .format (model .id ))
140- raise_errors_warnings (validation .validate_simulation_type (sim , (UniformTimeCourseSimulation , )),
141- error_summary = '{} `{}` is not supported.' .format (sim .__class__ .__name__ , sim .id ))
142- raise_errors_warnings (* validation .validate_simulation (sim ),
143- error_summary = 'Simulation `{}` is invalid.' .format (sim .id ))
144- raise_errors_warnings (* validation .validate_data_generator_variables (variables ),
145- error_summary = 'Data generator variables for task `{}` are invalid.' .format (task .id ))
146137
147- if not os .path .isfile (model .source ):
148- raise FileNotFoundError ('Model source `{}` is not a file.' .format (model .source ))
149- model_etree = lxml .etree .parse (model .source )
150- target_x_paths_to_sbml_ids = validation .validate_target_xpaths (variables , model_etree , attr = 'id' )
138+ model_etree = preprocessed_task ['model' ]['etree' ]
151139
152- if config .VALIDATE_SEDML_MODELS :
153- raise_errors_warnings (* validation .validate_model (model , [], working_dir = '.' ),
154- error_summary = 'Model `{}` is invalid.' .format (model .id ),
155- warning_summary = 'Model `{}` may be invalid.' .format (model .id ))
140+ model = copy .deepcopy (model )
141+ for change in model .changes :
142+ change .new_value = str (change .new_value )
143+
144+ apply_changes_to_xml_model (model , model_etree , sed_doc = None , working_dir = None )
145+
146+ model_file , model_filename = tempfile .mkstemp (suffix = '.xml' )
147+ os .close (model_file )
148+
149+ model_etree .write (model_filename ,
150+ xml_declaration = True ,
151+ encoding = "utf-8" ,
152+ standalone = False ,
153+ pretty_print = False )
154+ else :
155+ model_filename = model .source
156156
157157 # validate time course
158158 if sim .initial_time != 0 :
159159 msg = 'Initial time must be zero, not `{}`.' .format (sim .initial_time )
160- raise NotImplementedError (msg )
161160
162- # determine the simulation algorithm
163- algorithm_substitution_policy = get_algorithm_substitution_policy (config = config )
164- exec_kisao_id = get_preferred_substitute_algorithm_by_ids (
165- sim .algorithm .kisao_id , KISAO_ALGORITHMS_MAP .keys (),
166- substitution_policy = algorithm_substitution_policy )
167- if exec_kisao_id == sim .algorithm .kisao_id :
168- if (
169- ALGORITHM_SUBSTITUTION_POLICY_LEVELS [algorithm_substitution_policy ]
170- > ALGORITHM_SUBSTITUTION_POLICY_LEVELS [AlgorithmSubstitutionPolicy .NONE ]
171- ):
172- changes = []
173- unsupported_changes = []
174- for change in sim .algorithm .changes :
175- if change .kisao_id in ['KISAO_0000594' , 'KISAO_0000483' ]:
176- changes .append (change )
177- else :
178- unsupported_changes .append (change .kisao_id )
179- if unsupported_changes :
180- warn ('{} unsuported algorithm parameters were ignored:\n {}' .format (
181- len (unsupported_changes ), '\n ' .join (sorted (unsupported_changes ))),
182- BioSimulatorsWarning )
183- else :
184- changes = sim .algorithm .changes
185- else :
186- changes = []
187- algorithm = Algorithm (kisao_id = exec_kisao_id , changes = changes )
161+ if model .changes :
162+ os .remove (model_filename )
188163
189- # determine the simulation method and its parameters
190- integrator , time_step = get_integrator (algorithm )
164+ raise NotImplementedError (msg )
165+
166+ # determine the number of simulation steps
167+ time_step = preprocessed_task ['simulation' ]['time_step' ]
191168
192169 if time_step is None :
193170 time_step = (sim .output_end_time - sim .output_start_time ) / sim .number_of_steps / 1e2
194- use_lazy_newton_method = 0
195171
196172 number_of_steps = (sim .output_end_time - sim .initial_time ) / time_step
197173 if abs (number_of_steps - round (number_of_steps )) > 1e-8 :
@@ -210,6 +186,10 @@ def exec_sed_task(task, variables, preprocessed_task=None, log=None, config=None
210186 sim .number_of_steps ,
211187 time_step ,
212188 )
189+
190+ if model .changes :
191+ os .remove (model_filename )
192+
213193 raise ValueError (msg )
214194
215195 print_interval = (sim .output_end_time - sim .output_start_time ) / sim .number_of_steps / time_step
@@ -229,16 +209,24 @@ def exec_sed_task(task, variables, preprocessed_task=None, log=None, config=None
229209 sim .number_of_steps ,
230210 time_step ,
231211 )
212+
213+ if model .changes :
214+ os .remove (model_filename )
215+
232216 raise ValueError (msg )
233217 print_interval = round (print_interval )
234218
235- print_amount = 0
236-
237219 # execute the simulation
238- results = libsbmlsim .simulateSBMLFromFile (model .source ,
239- sim .output_end_time , time_step ,
240- print_interval , print_amount ,
241- integrator , use_lazy_newton_method )
220+ results = libsbmlsim .simulateSBMLFromFile (model_filename ,
221+ sim .output_end_time ,
222+ time_step ,
223+ print_interval ,
224+ preprocessed_task ['simulation' ]['print_amount' ],
225+ preprocessed_task ['simulation' ]['integrator' ],
226+ preprocessed_task ['simulation' ]['use_lazy_newton_method' ])
227+
228+ if model .changes :
229+ os .remove (model_filename )
242230
243231 if results .isError ():
244232 raise ValueError (results .error_message )
@@ -251,9 +239,10 @@ def exec_sed_task(task, variables, preprocessed_task=None, log=None, config=None
251239 os .remove (filename )
252240
253241 # extract results
242+ xpath_sbml_id_map = preprocessed_task ['model' ]['xpath_sbml_id_map' ]
243+ variable_results = VariableResults ()
254244 unsupported_symbols = []
255245 unsupported_targets = []
256- variable_results = VariableResults ()
257246 for variable in variables :
258247 if variable .symbol :
259248 if variable .symbol == Symbol .time .value :
@@ -263,15 +252,15 @@ def exec_sed_task(task, variables, preprocessed_task=None, log=None, config=None
263252 unsupported_symbols .append ((variable .id , variable .symbol ))
264253
265254 else :
266- sbml_id = target_x_paths_to_sbml_ids [variable .target ]
255+ sbml_id = xpath_sbml_id_map [variable .target ]
267256 if sbml_id in results_df :
268257 variable_result = results_df [sbml_id ]
269258 else :
270259 variable_result = None
271260 unsupported_targets .append ((variable .id , variable .target ))
272261
273262 if variable_result is not None :
274- if exec_kisao_id in ['KISAO_0000086' , 'KISAO_0000321' ]:
263+ if preprocessed_task [ 'simulation' ][ 'algorithm_kisao_id' ] in ['KISAO_0000086' , 'KISAO_0000321' ]:
275264 variable_results [variable .id ] = variable_result [- (sim .number_of_steps * print_interval + 1 )::print_interval ].to_numpy ()
276265
277266 else :
@@ -307,16 +296,16 @@ def exec_sed_task(task, variables, preprocessed_task=None, log=None, config=None
307296
308297 # log action
309298 if config .LOG :
310- log .algorithm = exec_kisao_id
299+ log .algorithm = preprocessed_task [ 'simulation' ][ 'algorithm_kisao_id' ],
311300 log .simulator_details = {
312301 'method' : "simulateSBMLFromFile" ,
313302 'arguments' : {
314303 'sim_time' : sim .output_end_time ,
315304 'dt' : time_step ,
316305 'print_interval' : print_interval ,
317- 'print_amount' : print_amount ,
318- 'method' : integrator ,
319- 'use_lazy_method' : use_lazy_newton_method ,
306+ 'print_amount' : preprocessed_task [ 'simulation' ][ ' print_amount' ] ,
307+ 'method' : preprocessed_task [ 'simulation' ][ ' integrator' ] ,
308+ 'use_lazy_method' : preprocessed_task [ 'simulation' ][ ' use_lazy_newton_method' ] ,
320309 },
321310 }
322311
@@ -336,4 +325,81 @@ def preprocess_sed_task(task, variables, config=None):
336325 Returns:
337326 :obj:`object`: preprocessed information about the task
338327 """
339- pass
328+ config = config or get_config ()
329+
330+ model = task .model
331+ sim = task .simulation
332+
333+ # validate model and simulation
334+ if config .VALIDATE_SEDML :
335+ raise_errors_warnings (validation .validate_task (task ),
336+ error_summary = 'Task `{}` is invalid.' .format (task .id ))
337+ raise_errors_warnings (validation .validate_model_language (model .language , ModelLanguage .SBML ),
338+ error_summary = 'Language for model `{}` is not supported.' .format (model .id ))
339+ raise_errors_warnings (validation .validate_model_change_types (model .changes , (ModelAttributeChange ,)),
340+ error_summary = 'Changes for model `{}` are not supported.' .format (model .id ))
341+ raise_errors_warnings (* validation .validate_model_changes (task .model ),
342+ error_summary = 'Changes for model `{}` are invalid.' .format (model .id ))
343+ raise_errors_warnings (validation .validate_simulation_type (sim , (UniformTimeCourseSimulation , )),
344+ error_summary = '{} `{}` is not supported.' .format (sim .__class__ .__name__ , sim .id ))
345+ raise_errors_warnings (* validation .validate_simulation (sim ),
346+ error_summary = 'Simulation `{}` is invalid.' .format (sim .id ))
347+ raise_errors_warnings (* validation .validate_data_generator_variables (variables ),
348+ error_summary = 'Data generator variables for task `{}` are invalid.' .format (task .id ))
349+
350+ if not os .path .isfile (model .source ):
351+ raise FileNotFoundError ('Model source `{}` is not a file.' .format (model .source ))
352+ model_etree = lxml .etree .parse (model .source )
353+ xpath_sbml_id_map = validation .validate_target_xpaths (variables , model_etree , attr = 'id' )
354+
355+ if config .VALIDATE_SEDML_MODELS :
356+ raise_errors_warnings (* validation .validate_model (model , [], working_dir = '.' ),
357+ error_summary = 'Model `{}` is invalid.' .format (model .id ),
358+ warning_summary = 'Model `{}` may be invalid.' .format (model .id ))
359+
360+ # determine the simulation algorithm
361+ algorithm_substitution_policy = get_algorithm_substitution_policy (config = config )
362+ exec_kisao_id = get_preferred_substitute_algorithm_by_ids (
363+ sim .algorithm .kisao_id , KISAO_ALGORITHMS_MAP .keys (),
364+ substitution_policy = algorithm_substitution_policy )
365+ if exec_kisao_id == sim .algorithm .kisao_id :
366+ if (
367+ ALGORITHM_SUBSTITUTION_POLICY_LEVELS [algorithm_substitution_policy ]
368+ > ALGORITHM_SUBSTITUTION_POLICY_LEVELS [AlgorithmSubstitutionPolicy .NONE ]
369+ ):
370+ changes = []
371+ unsupported_changes = []
372+ for change in sim .algorithm .changes :
373+ if change .kisao_id in ['KISAO_0000594' , 'KISAO_0000483' ]:
374+ changes .append (change )
375+ else :
376+ unsupported_changes .append (change .kisao_id )
377+ if unsupported_changes :
378+ warn ('{} unsuported algorithm parameters were ignored:\n {}' .format (
379+ len (unsupported_changes ), '\n ' .join (sorted (unsupported_changes ))),
380+ BioSimulatorsWarning )
381+ else :
382+ changes = sim .algorithm .changes
383+ else :
384+ changes = []
385+ algorithm = Algorithm (kisao_id = exec_kisao_id , changes = changes )
386+
387+ # determine the simulation method and its parameters
388+ integrator , time_step = get_integrator (algorithm )
389+ use_lazy_newton_method = 0
390+ print_amount = 0
391+
392+ # return preprocessed task
393+ return {
394+ 'model' : {
395+ 'etree' : model_etree ,
396+ 'xpath_sbml_id_map' : xpath_sbml_id_map ,
397+ },
398+ 'simulation' : {
399+ 'algorithm_kisao_id' : exec_kisao_id ,
400+ 'integrator' : integrator ,
401+ 'use_lazy_newton_method' : use_lazy_newton_method ,
402+ 'time_step' : time_step ,
403+ 'print_amount' : print_amount ,
404+ },
405+ }
0 commit comments