Skip to content

Commit ea116e0

Browse files
committed
feat: refactored task preprocessing
1 parent f111670 commit ea116e0

File tree

5 files changed

+192
-86
lines changed

5 files changed

+192
-86
lines changed

biosimulators/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Base OS
22
FROM python:3.9-slim-buster
33

4-
ARG VERSION=0.0.3
4+
ARG VERSION=0.0.4
55
ARG SIMULATOR_VERSION=1.4.0
66
ARG LIBSBML_VERSION=5.19.0
77

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '0.0.3'
1+
__version__ = '0.0.4'

biosimulators/biosimulators_libsbmlsim/core.py

Lines changed: 133 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,17 @@
1212
from biosimulators_utils.log.data_model import CombineArchiveLog, TaskLog, StandardOutputErrorCapturerLevel # noqa: F401
1313
from biosimulators_utils.viz.data_model import VizFormat # noqa: F401
1414
from 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)
1717
from biosimulators_utils.sedml import validation
1818
from 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
1920
from biosimulators_utils.simulator.utils import get_algorithm_substitution_policy
2021
from biosimulators_utils.utils.core import raise_errors_warnings
2122
from biosimulators_utils.warnings import warn, BioSimulatorsWarning
2223
from kisao.data_model import AlgorithmSubstitutionPolicy, ALGORITHM_SUBSTITUTION_POLICY_LEVELS
2324
from kisao.utils import get_preferred_substitute_algorithm_by_ids
25+
import copy
2426
import libsbmlsim
2527
import lxml.etree
2628
import 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+
}

biosimulators/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
biosimulators_utils[sbml,logging] >= 0.1.116
1+
biosimulators_utils[sbml,logging] >= 0.1.118
22
# libsbmlsim
33
lxml
44
kisao

0 commit comments

Comments
 (0)