Skip to content

Commit 7f78eee

Browse files
committed
feat: separated simulation and pre-processing
1 parent b8a5f19 commit 7f78eee

File tree

4 files changed

+115
-56
lines changed

4 files changed

+115
-56
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
FROM python:3.9-slim-buster
2424

25-
ARG VERSION="0.1.12"
25+
ARG VERSION="0.1.13"
2626
ARG SIMULATOR_VERSION=2.6.0
2727

2828
# metadata

biosimulators_bionetgen/_version.py

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

biosimulators_bionetgen/core.py

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"""
99

1010
from .io import read_task
11-
from .utils import (exec_bionetgen_task, add_model_attribute_change_to_task, add_simulation_to_task,
11+
from .utils import (exec_bionetgen_task, preprocess_model_attribute_change, add_model_attribute_change_to_task, add_simulation_to_task,
1212
get_variables_results_from_observable_results, add_variables_to_model)
1313
from .warnings import IgnoredBnglFileContentWarning
1414
from biosimulators_utils.combine.exec import exec_sedml_docs_in_archive
@@ -100,7 +100,7 @@ def exec_sed_task(task, variables, preprocessed_task=None, log=None, config=None
100100
Args:
101101
task (:obj:`Task`): SED task
102102
variables (:obj:`list` of :obj:`Variable`): variables that should be recorded
103-
preprocessed_task (:obj:`object`, optional): preprocessed information about the task, including possible
103+
preprocessed_task (:obj:`dict`, optional): preprocessed information about the task, including possible
104104
model changes and variables. This can be used to avoid repeatedly executing the same initialization
105105
for repeated calls to this method.
106106
log (:obj:`TaskLog`, optional): log for the task
@@ -136,12 +136,56 @@ def exec_sed_task(task, variables, preprocessed_task=None, log=None, config=None
136136
* :obj:`get_variables_results_from_observable_results`
137137
"""
138138
config = config or get_config()
139+
139140
if config.LOG and not log:
140141
log = TaskLog()
141142

142143
if preprocessed_task is None:
143144
preprocessed_task = preprocess_sed_task(task, variables, config=config)
144145

146+
# read the model from the BNGL file
147+
bionetgen_task = preprocessed_task['bionetgen_task']
148+
149+
# validate and apply the model attribute changes to the BioNetGen task
150+
for change in task.model.changes:
151+
add_model_attribute_change_to_task(bionetgen_task, change, preprocessed_task['model_changes'][change.target])
152+
153+
# apply the SED algorithm and its parameters to the BioNetGen task
154+
alg_kisao_id = preprocessed_task['algorithm_kisao_id']
155+
156+
# execute the task
157+
observable_results = exec_bionetgen_task(bionetgen_task)
158+
159+
# get predicted values of the variables
160+
variable_results = get_variables_results_from_observable_results(observable_results, variables)
161+
for key in variable_results.keys():
162+
variable_results[key] = variable_results[key][-(task.simulation.number_of_points + 1):]
163+
164+
# log action
165+
if config.LOG:
166+
log.algorithm = alg_kisao_id
167+
log.simulator_details = {
168+
'actions': bionetgen_task.actions,
169+
}
170+
171+
# return the values of the variables and log
172+
return variable_results, log
173+
174+
175+
def preprocess_sed_task(task, variables, config=None):
176+
""" Preprocess a SED task, including its possible model changes and variables. This is useful for avoiding
177+
repeatedly initializing tasks on repeated calls of :obj:`exec_sed_task`.
178+
179+
Args:
180+
task (:obj:`Task`): task
181+
variables (:obj:`list` of :obj:`Variable`): variables that should be recorded
182+
config (:obj:`Config`, optional): BioSimulators common configuration
183+
184+
Returns:
185+
:obj:`dict`: preprocessed information about the task
186+
"""
187+
config = config or get_config()
188+
145189
if config.VALIDATE_SEDML:
146190
raise_errors_warnings(
147191
validation.validate_task(task),
@@ -174,47 +218,19 @@ def exec_sed_task(task, variables, preprocessed_task=None, log=None, config=None
174218
bionetgen_task.actions = []
175219

176220
# validate and apply the model attribute changes to the BioNetGen task
221+
model_changes = {}
177222
for change in task.model.changes:
178-
add_model_attribute_change_to_task(bionetgen_task, change)
223+
model_changes[change.target] = preprocess_model_attribute_change(bionetgen_task, change)
179224

180225
# add observables for the variables to the BioNetGen model
181226
add_variables_to_model(bionetgen_task.model, variables)
182227

183228
# apply the SED algorithm and its parameters to the BioNetGen task
184229
alg_kisao_id = add_simulation_to_task(bionetgen_task, task.simulation)
185230

186-
# execute the task
187-
observable_results = exec_bionetgen_task(bionetgen_task)
188-
189-
# get predicted values of the variables
190-
variable_results = get_variables_results_from_observable_results(observable_results, variables)
191-
for key in variable_results.keys():
192-
variable_results[key] = variable_results[key][-(task.simulation.number_of_points + 1):]
193-
194-
# log action
195-
if config.LOG:
196-
log.algorithm = alg_kisao_id
197-
log.simulator_details = {
198-
'actions': bionetgen_task.actions,
199-
}
200-
201231
# return the values of the variables and log
202-
return variable_results, log
203-
204-
205-
def preprocess_sed_task(task, variables, config=None):
206-
""" Preprocess a SED task, including its possible model changes and variables. This is useful for avoiding
207-
repeatedly initializing tasks on repeated calls of :obj:`exec_sed_task`.
208-
209-
Args:
210-
task (:obj:`Task`): task
211-
variables (:obj:`list` of :obj:`Variable`): variables that should be recorded
212-
preprocessed_task (:obj:`PreprocessedTask`, optional): preprocessed information about the task, including possible
213-
model changes and variables. This can be used to avoid repeatedly executing the same initialization for repeated
214-
calls to this method.
215-
config (:obj:`Config`, optional): BioSimulators common configuration
216-
217-
Returns:
218-
:obj:`object`: preprocessed information about the task
219-
"""
220-
pass
232+
return {
233+
'bionetgen_task': bionetgen_task,
234+
'model_changes': model_changes,
235+
'algorithm_kisao_id': alg_kisao_id,
236+
}

biosimulators_bionetgen/utils.py

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import tempfile
2727

2828
__all__ = [
29+
'preprocess_model_attribute_change',
2930
'add_model_attribute_change_to_task',
3031
'add_variables_to_model',
3132
'add_simulation_to_task',
@@ -34,8 +35,8 @@
3435
]
3536

3637

37-
def add_model_attribute_change_to_task(task, change):
38-
""" Encode SED model attribute changes into a BioNetGen task
38+
def preprocess_model_attribute_change(task, change):
39+
""" Process a model change
3940
4041
* Compartment sizes: targets should follow the pattern ``compartments.<compartment_id>.size``
4142
* Function expressions: targets should follow the pattern ``functions.<function_id>.expression``
@@ -46,11 +47,13 @@ def add_model_attribute_change_to_task(task, change):
4647
task (:obj:`Task`): BioNetGen task
4748
change (:obj:`ModelAttributeChange`): model attribute change
4849
50+
Returns:
51+
:obj:`dict`: processed information about the model change
52+
4953
Raises:
5054
:obj:`ValueError`: if a target of a change is not valid
5155
"""
5256
target = change.target
53-
new_value = change.new_value
5457

5558
compartment_size_match = re.match(r'^compartments\.([^\.]+)(\.size)?$', target)
5659
if compartment_size_match:
@@ -62,25 +65,32 @@ def add_model_attribute_change_to_task(task, change):
6265
for i_line, line in enumerate(block):
6366
match = re.match(pattern, line)
6467
if match:
65-
block[i_line] = '{} {} {} {}'.format(obj_id, match.group(1), new_value, (match.group(3) or '').strip()).strip()
6668
comp_changed = True
69+
return {
70+
'type': 'replace_line_in_block',
71+
'block': block,
72+
'i_line': i_line,
73+
'new_line': lambda new_value: '{} {} {} {}'.format(obj_id, match.group(1), new_value, (match.group(3) or '').strip()).strip(),
74+
}
6775

6876
if not comp_changed:
6977
raise ValueError(('The size of compartment `{}` cannot be changed '
7078
'because the model does not have a compartment with this id.').format(obj_id))
7179

72-
return
73-
7480
parameter_values_match = re.match(r'^parameters\.([^\.]+)(\.value)?$', target)
7581
if parameter_values_match:
76-
task.actions.append('setParameter("{}", {})'.format(parameter_values_match.group(1), new_value))
77-
return
82+
return {
83+
'type': 'append_action',
84+
'action': lambda new_value: 'setParameter("{}", {})'.format(parameter_values_match.group(1), new_value),
85+
}
7886

7987
species_counts_match = re.match(r'^species\.([^\.]+)\((.*?)\)(\.initialCount)?$', target)
8088
if species_counts_match:
81-
task.actions.append('setConcentration("{}({})", {})'.format(
82-
species_counts_match.group(1), species_counts_match.group(2), new_value))
83-
return
89+
return {
90+
'type': 'append_action',
91+
'action': lambda new_value: 'setConcentration("{}({})", {})'.format(
92+
species_counts_match.group(1), species_counts_match.group(2), new_value),
93+
}
8494

8595
functions_expression_match = re.match(r'^functions\.([^\.\(\)]+)(\.expression)?$', target)
8696
if functions_expression_match:
@@ -94,14 +104,17 @@ def add_model_attribute_change_to_task(task, change):
94104
match = re.match(pattern, line)
95105
if match:
96106
func_changed = True
97-
block[i_line] = '{}({}) = {}'.format(obj_id, match.group(1), new_value)
107+
return {
108+
'type': 'replace_line_in_block',
109+
'block': block,
110+
'i_line': i_line,
111+
'new_line': lambda new_value: '{}({}) = {}'.format(obj_id, match.group(1), new_value),
112+
}
98113

99114
if not func_changed:
100115
raise ValueError(('The expression of function `{}` cannot be changed '
101116
'because the model does not have a function with this id.').format(obj_id))
102117

103-
return
104-
105118
function_args_expression_match = re.match(r'^functions\.([^\.]+)\((.*?)\)(\.expression)?$', target)
106119
if function_args_expression_match:
107120
obj_id = function_args_expression_match.group(1)
@@ -115,14 +128,17 @@ def add_model_attribute_change_to_task(task, change):
115128
match = re.match(pattern, line)
116129
if match:
117130
func_changed = True
118-
block[i_line] = '{}({}) = {}'.format(obj_id, obj_args, new_value)
131+
return {
132+
'type': 'replace_line_in_block',
133+
'block': block,
134+
'i_line': i_line,
135+
'new_line': lambda new_value: '{}({}) = {}'.format(obj_id, obj_args, new_value),
136+
}
119137

120138
if not func_changed:
121139
raise ValueError(('The expression of function `{}` cannot be changed '
122140
'because the model does not have a function with this id.').format(obj_id))
123141

124-
return
125-
126142
target_patterns = {
127143
'compartment size': compartment_size_match,
128144
'parameter value': parameter_values_match,
@@ -135,6 +151,33 @@ def add_model_attribute_change_to_task(task, change):
135151
raise NotImplementedError(msg)
136152

137153

154+
def add_model_attribute_change_to_task(task, change, preprocessed_change=None):
155+
""" Encode SED model attribute changes into a BioNetGen task
156+
157+
* Compartment sizes: targets should follow the pattern ``compartments.<compartment_id>.size``
158+
* Function expressions: targets should follow the pattern ``functions.<function_id>.expression``
159+
* Initial species counts: targets should follow the pattern ``species.<species_id>.count``
160+
* Parameter values: targets should follow the pattern ``parameters.<parameter_id>.value``
161+
162+
Args:
163+
task (:obj:`Task`): BioNetGen task
164+
change (:obj:`ModelAttributeChange`): model attribute change
165+
preprocessed_change (:obj:`dict`): preprocessed information about the change
166+
167+
Raises:
168+
:obj:`ValueError`: if a target of a change is not valid
169+
"""
170+
if preprocessed_change is None:
171+
preprocessed_change = preprocess_model_attribute_change(task, change)
172+
173+
new_value = change.new_value
174+
175+
if preprocessed_change['type'] == 'replace_line_in_block':
176+
preprocessed_change['block'][preprocessed_change['i_line']] = preprocessed_change['new_line'](new_value)
177+
else:
178+
task.actions.append(preprocessed_change['action'](new_value))
179+
180+
138181
def add_variables_to_model(model, variables):
139182
""" Encode SED variables into observables in a BioNetGen task
140183

0 commit comments

Comments
 (0)