From e4038d83826e88483a4fc2e8899273490db10bbc Mon Sep 17 00:00:00 2001 From: Lucian Smith Date: Wed, 5 Jul 2023 17:46:42 -0700 Subject: [PATCH 01/11] Tie into 'implement-set-get-reset' branch of biosimulators_utils Implement simple get/set/reset functions for Tellurium. Since the roadrunner object lived in the 'preprocessed_task' object, use that. (This probably makes sense anyway: I think the 'preprocessed_task' object can basically function as a 'model state' object, which is exactly the thing that needs to be manipulated.) --- biosimulators_tellurium/core.py | 304 +++++++++++++++----------- biosimulators_tellurium/data_model.py | 25 +-- 2 files changed, 192 insertions(+), 137 deletions(-) diff --git a/biosimulators_tellurium/core.py b/biosimulators_tellurium/core.py index 7681201..a599066 100644 --- a/biosimulators_tellurium/core.py +++ b/biosimulators_tellurium/core.py @@ -18,7 +18,7 @@ from biosimulators_utils.sedml import exec as sedml_exec from biosimulators_utils.sedml import validation from biosimulators_utils.sedml.data_model import ( - Task, ModelLanguage, ModelAttributeChange, SteadyStateSimulation, UniformTimeCourseSimulation, + Task, RepeatedTask, ModelLanguage, ModelAttributeChange, SteadyStateSimulation, UniformTimeCourseSimulation, Symbol, Report, DataSet, Plot2D, Curve, Plot3D, Surface) from biosimulators_utils.sedml.io import SedmlSimulationReader, SedmlSimulationWriter from biosimulators_utils.simulator.utils import get_algorithm_substitution_policy @@ -196,6 +196,10 @@ def exec_sed_doc_with_biosimulators(doc, working_dir, base_out_path, rel_out_pat simulator_config.sedml_interpreter = SedmlInterpreter.biosimulators sed_task_executer = functools.partial(exec_sed_task, simulator_config=simulator_config) + # The value_executer's don't need the simulator_config. + # get_value_executer = functools.partial(get_model_variable_value, simulator_config=simulator_config) + # set_value_executer = functools.partial(set_model_variable_value, simulator_config=simulator_config) + preprocessed_task_executer = functools.partial(preprocess_sed_task, simulator_config=simulator_config) return sedml_exec.exec_sed_doc(sed_task_executer, doc, working_dir, base_out_path, rel_out_path=rel_out_path, apply_xml_model_changes=True, @@ -203,7 +207,11 @@ def exec_sed_doc_with_biosimulators(doc, working_dir, base_out_path, rel_out_pat indent=indent, pretty_print_modified_xml_models=pretty_print_modified_xml_models, log_level=log_level, - config=config) + config=config, + get_value_executer=get_model_variable_value, + set_value_executer=set_model_variable_value, + preprocessed_task_executer=preprocessed_task_executer, + reset_executer=reset_all_models) def exec_sed_task(task, variables, preprocessed_task=None, log=None, config=None, simulator_config=None): @@ -241,16 +249,16 @@ def exec_sed_task(task, variables, preprocessed_task=None, log=None, config=None model = task.model sim = task.simulation - road_runner = preprocessed_task.road_runner + road_runner = preprocessed_task.road_runners[task.id] # apply model changes if model.changes: raise_errors_warnings(validation.validate_model_change_types(model.changes, (ModelAttributeChange, )), error_summary='Changes for model `{}` are not supported.'.format(model.id)) for change in model.changes: - component_id = preprocessed_task.model_change_target_tellurium_id_map[change.target] + component_id = preprocessed_task.model_change_target_tellurium_id_maps[task.id][change.target] new_value = float(change.new_value) - road_runner.model[component_id] = new_value + road_runner[component_id] = new_value # simulate if isinstance(sim, UniformTimeCourseSimulation): @@ -267,10 +275,7 @@ def exec_sed_task(task, variables, preprocessed_task=None, log=None, config=None raise NotImplementedError(msg) number_of_points = round(number_of_points) - try: - results = numpy.array(road_runner.simulate(sim.initial_time, sim.output_end_time, number_of_points).tolist()).transpose() - except (Exception) as e: - raise RuntimeError("Error from roadrunner version " + road_runner.getVersionStr() + ": " + str(e)) + results = numpy.array(road_runner.simulate(sim.initial_time, sim.output_end_time, number_of_points).tolist()).transpose() else: road_runner.steadyState() results = road_runner.getSteadyStateValues() @@ -278,11 +283,11 @@ def exec_sed_task(task, variables, preprocessed_task=None, log=None, config=None # check simulation succeeded if config.VALIDATE_RESULTS and numpy.any(numpy.isnan(results)): msg = 'Simulation failed with algorithm `{}` ({})'.format( - preprocessed_task.algorithm_kisao_id, - KISAO_ALGORITHM_MAP[preprocessed_task.algorithm_kisao_id]['id']) - for i_param in range(preprocessed_task.solver.getNumParams()): - param_name = preprocessed_task.solver.getParamName(i_param) - msg += '\n - {}: {}'.format(param_name, getattr(preprocessed_task.solver, param_name)) + preprocessed_task.algorithm_kisao_ids[task.id], + KISAO_ALGORITHM_MAP[preprocessed_task.algorithm_kisao_id[task.id]]['id']) + for i_param in range(preprocessed_task.solvers[task.id].getNumParams()): + param_name = preprocessed_task.solvers[task.id].getParamName(i_param) + msg += '\n - {}: {}'.format(param_name, getattr(preprocessed_task.solvers[task.id], param_name)) raise ValueError(msg) # record results @@ -295,18 +300,34 @@ def exec_sed_task(task, variables, preprocessed_task=None, log=None, config=None # log action if config.LOG: - log.algorithm = preprocessed_task.algorithm_kisao_id + log.algorithm = preprocessed_task.algorithm_kisao_ids[task.id] log.simulator_details = { 'method': 'simulate' if isinstance(sim, UniformTimeCourseSimulation) else 'steadyState', - 'solver': preprocessed_task.solver.getName(), + 'solver': preprocessed_task.solvers[task.id].getName(), } - for i_param in range(preprocessed_task.solver.getNumParams()): - param_name = preprocessed_task.solver.getParamName(i_param) - log.simulator_details[param_name] = getattr(preprocessed_task.solver, param_name) + for i_param in range(preprocessed_task.solvers[task.id].getNumParams()): + param_name = preprocessed_task.solvers[task.id].getParamName(i_param) + log.simulator_details[param_name] = getattr(preprocessed_task.solvers[task.id], param_name) # return results and log return variable_results, log +def get_all_tasks_from_task(task): + ret = set() + if type(task) == Task: + ret.add(task) + return ret + elif type(task) == RepeatedTask: + for sub_task in task.sub_tasks: + submodels = get_all_tasks_from_task(sub_task.task) + ret.update(submodels) + return ret + else: + raise NotImplementedError("Tasks other than 'Task' or 'RepeatedTask' are not supported.") + +def reset_all_models(preprocessed_task): + for taskid in preprocessed_task.road_runners: + preprocessed_task.road_runners[taskid].resetAll() def preprocess_sed_task(task, variables, config=None, simulator_config=None): """ Preprocess a SED task, including its possible model changes and variables. This is useful for avoiding @@ -331,127 +352,162 @@ def preprocess_sed_task(task, variables, config=None, simulator_config=None): if not config: config = get_config() - model = task.model - sim = task.simulation + alltasks = get_all_tasks_from_task(task) if config.VALIDATE_SEDML: - raise_errors_warnings(validation.validate_task(task), - error_summary='Task `{}` is invalid.'.format(task.id)) - raise_errors_warnings(validation.validate_model_language(model.language, ModelLanguage.SBML), - error_summary='Language for model `{}` is not supported.'.format(model.id)) - raise_errors_warnings(validation.validate_model_change_types(model.changes, (ModelAttributeChange, )), - error_summary='Changes for model `{}` are not supported.'.format(model.id)) - raise_errors_warnings(*validation.validate_model_changes(task.model), - error_summary='Changes for model `{}` are invalid.'.format(model.id)) - raise_errors_warnings(validation.validate_simulation_type(sim, (SteadyStateSimulation, UniformTimeCourseSimulation)), - error_summary='{} `{}` is not supported.'.format(sim.__class__.__name__, sim.id)) - raise_errors_warnings(*validation.validate_simulation(sim), - error_summary='Simulation `{}` is invalid.'.format(sim.id)) - raise_errors_warnings(*validation.validate_data_generator_variables(variables), - error_summary='Data generator variables for task `{}` are invalid.'.format(task.id)) - model_etree = lxml.etree.parse(model.source) - - if config.VALIDATE_SEDML_MODELS: - raise_errors_warnings(*validation.validate_model(model, [], working_dir='.'), - error_summary='Model `{}` is invalid.'.format(model.id), - warning_summary='Model `{}` may be invalid.'.format(model.id)) - - # read model - road_runner = roadrunner.RoadRunner() - road_runner.load(model.source) - - # get algorithm to execute - algorithm_substitution_policy = get_algorithm_substitution_policy(config=config) - exec_alg_kisao_id = get_preferred_substitute_algorithm_by_ids( - sim.algorithm.kisao_id, KISAO_ALGORITHM_MAP.keys(), - substitution_policy=algorithm_substitution_policy) - alg_props = KISAO_ALGORITHM_MAP[exec_alg_kisao_id] - - if alg_props['id'] == 'nleq2': - solver = road_runner.getSteadyStateSolver() - if config.VALIDATE_SEDML: - raise_errors_warnings(validation.validate_simulation_type(sim, (SteadyStateSimulation,)), + for subtask in alltasks: + model = subtask.model + sim = subtask.simulation + raise_errors_warnings(validation.validate_task(subtask), + error_summary='Task `{}` is invalid.'.format(task.id)) + raise_errors_warnings(validation.validate_model_language(model.language, ModelLanguage.SBML), + error_summary='Language for model `{}` is not supported.'.format(model.id)) + raise_errors_warnings(validation.validate_model_change_types(model.changes, (ModelAttributeChange, )), + error_summary='Changes for model `{}` are not supported.'.format(model.id)) + raise_errors_warnings(*validation.validate_model_changes(subtask.model), + error_summary='Changes for model `{}` are invalid.'.format(model.id)) + raise_errors_warnings(validation.validate_simulation_type(sim, (SteadyStateSimulation, UniformTimeCourseSimulation)), error_summary='{} `{}` is not supported.'.format(sim.__class__.__name__, sim.id)) + raise_errors_warnings(*validation.validate_simulation(sim), + error_summary='Simulation `{}` is invalid.'.format(sim.id)) + raise_errors_warnings(*validation.validate_data_generator_variables(variables), + error_summary='Data generator variables for task `{}` are invalid.'.format(subtask.id)) + + allroadrunners = {} + model_change_target_tellurium_id_maps = {} + exec_alg_kisao_ids = {} + variable_target_tellurium_observable_maps = {} + solvers = {} + for subtasks in alltasks: + model = subtask.model + sim = subtask.simulation + model_etree = lxml.etree.parse(model.source) + + if config.VALIDATE_SEDML_MODELS: + raise_errors_warnings(*validation.validate_model(model, [], working_dir='.'), + error_summary='Model `{}` is invalid.'.format(model.id), + warning_summary='Model `{}` may be invalid.'.format(model.id)) + + # read model + road_runner = roadrunner.RoadRunner(model.source) + + # get algorithm to execute + algorithm_substitution_policy = get_algorithm_substitution_policy(config=config) + exec_alg_kisao_id = get_preferred_substitute_algorithm_by_ids( + sim.algorithm.kisao_id, KISAO_ALGORITHM_MAP.keys(), + substitution_policy=algorithm_substitution_policy) + alg_props = KISAO_ALGORITHM_MAP[exec_alg_kisao_id] + + if alg_props['id'] == 'nleq2': + solver = road_runner.getSteadyStateSolver() + if config.VALIDATE_SEDML: + raise_errors_warnings(validation.validate_simulation_type(sim, (SteadyStateSimulation,)), + error_summary='{} `{}` is not supported.'.format(sim.__class__.__name__, sim.id)) - else: - road_runner.setIntegrator(alg_props['id']) - solver = road_runner.getIntegrator() - if config.VALIDATE_SEDML: - raise_errors_warnings(validation.validate_simulation_type(sim, (UniformTimeCourseSimulation,)), - error_summary='{} `{}` is not supported.'.format(sim.__class__.__name__, sim.id)) + else: + road_runner.setIntegrator(alg_props['id']) + solver = road_runner.getIntegrator() + if config.VALIDATE_SEDML: + raise_errors_warnings(validation.validate_simulation_type(sim, (UniformTimeCourseSimulation,)), + error_summary='{} `{}` is not supported.'.format(sim.__class__.__name__, sim.id)) + + # set the parameters of the solver + if exec_alg_kisao_id == sim.algorithm.kisao_id: + for change in sim.algorithm.changes: + param_props = alg_props['parameters'].get(change.kisao_id, None) + if not config.VALIDATE_SEDML or param_props: + if not config.VALIDATE_SEDML or validate_str_value(change.new_value, param_props['type']): + new_value = parse_value(change.new_value, param_props['type']) + att = param_props['id'] + if "roadrunner_attribute" in param_props: + att = param_props['roadrunner_attribute'] + setattr(solver, att, new_value) - # set the parameters of the solver - if exec_alg_kisao_id == sim.algorithm.kisao_id: - for change in sim.algorithm.changes: - param_props = alg_props['parameters'].get(change.kisao_id, None) - if not config.VALIDATE_SEDML or param_props: - if not config.VALIDATE_SEDML or validate_str_value(change.new_value, param_props['type']): - new_value = parse_value(change.new_value, param_props['type']) - att = param_props['id'] - if "roadrunner_attribute" in param_props: - att = param_props['roadrunner_attribute'] - setattr(solver, att, new_value) + else: + if ( + ALGORITHM_SUBSTITUTION_POLICY_LEVELS[algorithm_substitution_policy] + <= ALGORITHM_SUBSTITUTION_POLICY_LEVELS[AlgorithmSubstitutionPolicy.NONE] + ): + msg = "'{}' is not a valid {} value for parameter {}".format( + change.new_value, param_props['type'].name, change.kisao_id) + raise ValueError(msg) + else: + msg = "'{}' was ignored because it is not a valid {} value for parameter {}".format( + change.new_value, param_props['type'].name, change.kisao_id) + warn(msg, BioSimulatorsWarning) else: if ( ALGORITHM_SUBSTITUTION_POLICY_LEVELS[algorithm_substitution_policy] <= ALGORITHM_SUBSTITUTION_POLICY_LEVELS[AlgorithmSubstitutionPolicy.NONE] ): - msg = "'{}' is not a valid {} value for parameter {}".format( - change.new_value, param_props['type'].name, change.kisao_id) - raise ValueError(msg) + msg = "".join([ + "Algorithm parameter with KiSAO id '{}' is not supported. ".format(change.kisao_id), + "Parameter must have one of the following KiSAO ids:\n - {}".format('\n - '.join( + '{}: {} ({})'.format(kisao_id, param_props['id'], param_props['name']) + for kisao_id, param_props in alg_props['parameters'].items())), + ]) + raise NotImplementedError(msg) else: - msg = "'{}' was ignored because it is not a valid {} value for parameter {}".format( - change.new_value, param_props['type'].name, change.kisao_id) + msg = "".join([ + "Algorithm parameter with KiSAO id '{}' was ignored because it is not supported. ".format(change.kisao_id), + "Parameter must have one of the following KiSAO ids:\n - {}".format('\n - '.join( + '{}: {} ({})'.format(kisao_id, param_props['id'], param_props['name']) + for kisao_id, param_props in alg_props['parameters'].items())), + ]) warn(msg, BioSimulatorsWarning) - else: - if ( - ALGORITHM_SUBSTITUTION_POLICY_LEVELS[algorithm_substitution_policy] - <= ALGORITHM_SUBSTITUTION_POLICY_LEVELS[AlgorithmSubstitutionPolicy.NONE] - ): - msg = "".join([ - "Algorithm parameter with KiSAO id '{}' is not supported. ".format(change.kisao_id), - "Parameter must have one of the following KiSAO ids:\n - {}".format('\n - '.join( - '{}: {} ({})'.format(kisao_id, param_props['id'], param_props['name']) - for kisao_id, param_props in alg_props['parameters'].items())), - ]) - raise NotImplementedError(msg) - else: - msg = "".join([ - "Algorithm parameter with KiSAO id '{}' was ignored because it is not supported. ".format(change.kisao_id), - "Parameter must have one of the following KiSAO ids:\n - {}".format('\n - '.join( - '{}: {} ({})'.format(kisao_id, param_props['id'], param_props['name']) - for kisao_id, param_props in alg_props['parameters'].items())), - ]) - warn(msg, BioSimulatorsWarning) - - # validate model changes and build map - model_change_target_tellurium_id_map = get_model_change_target_tellurium_change_map( - model_etree, model.changes, exec_alg_kisao_id, road_runner.model) - - # validate variables and build map - variable_target_tellurium_observable_map = get_variable_target_tellurium_observable_map( - model_etree, sim, exec_alg_kisao_id, variables, road_runner.model) - - variable_tellurium_observable_ids = [] - for variable in variables: - tellurium_id = variable_target_tellurium_observable_map[(variable.target, variable.symbol)] - variable_tellurium_observable_ids.append(tellurium_id) + # validate model changes and build map + model_change_target_tellurium_id_map = get_model_change_target_tellurium_change_map( + model_etree, model.changes, exec_alg_kisao_id, road_runner.model) + + # validate variables and build map + variable_target_tellurium_observable_map = get_variable_target_tellurium_observable_map( + model_etree, sim, exec_alg_kisao_id, variables, road_runner.model, model.id) - road_runner.timeCourseSelections = variable_tellurium_observable_ids - road_runner.steadyStateSelections = variable_tellurium_observable_ids + variable_tellurium_observable_ids = [] + for variable in variables: + tellurium_id = variable_target_tellurium_observable_map[(model.id, variable.target, variable.symbol)] + variable_tellurium_observable_ids.append(tellurium_id) + + road_runner.timeCourseSelections = variable_tellurium_observable_ids + road_runner.steadyStateSelections = variable_tellurium_observable_ids + #Add the variables to the dictionaries: + allroadrunners[subtask.id] = road_runner + model_change_target_tellurium_id_maps[subtask.id] = model_change_target_tellurium_id_map + exec_alg_kisao_ids[subtask.id] = exec_alg_kisao_id + variable_target_tellurium_observable_maps[subtask.id] = variable_target_tellurium_observable_map + solvers[subtask.id] = solver # return preprocssed information about the task return PreprocesssedTask( - road_runner=road_runner, - solver=solver, - model_change_target_tellurium_id_map=model_change_target_tellurium_id_map, - algorithm_kisao_id=exec_alg_kisao_id, - variable_target_tellurium_observable_map=variable_target_tellurium_observable_map, + road_runners=allroadrunners, + solvers=solvers, + model_change_target_tellurium_id_maps=model_change_target_tellurium_id_maps, + algorithm_kisao_ids=exec_alg_kisao_ids, + variable_target_tellurium_observable_maps=variable_target_tellurium_observable_maps, ) +def get_model_variable_value(model, variable, preprocessed_task): + if preprocessed_task is None: + raise ValueError("Tellurium cannot obtain a model value without a working preprocessed_task.") + for taskid in preprocessed_task.variable_target_tellurium_observable_maps: + submap = preprocessed_task.variable_target_tellurium_observable_maps[taskid] + if (model.id, variable.target, variable.symbol) in submap: + return submap[(model.id, variable.target, variable.symbol)] + raise ValueError("No stored variable with target " + variable.target + " and symbol " + variable.symbol + " in model " + model.id ) + +def set_model_variable_value(model, target, symbol, value, preprocessed_task): + if preprocessed_task is None: + raise ValueError("Tellurium cannot set a model value without a working preprocessed_task.") + for taskid in preprocessed_task.variable_target_tellurium_observable_maps: + submap = preprocessed_task.variable_target_tellurium_observable_maps[taskid] + if (model.id, target, symbol) in submap: + tellurium_id = submap[(model.id, target, symbol)] + preprocessed_task.road_runners[taskid][tellurium_id] = value + + def get_model_change_target_tellurium_change_map(model_etree, changes, alg_kisao_id, model): """ Get a mapping from XML XPath targets for model changes to tellurium identifiers for model changes @@ -500,7 +556,7 @@ def get_model_change_target_tellurium_change_map(model_etree, changes, alg_kisao return target_tellurium_id_map -def get_variable_target_tellurium_observable_map(model_etree, simulation, alg_kisao_id, variables, model): +def get_variable_target_tellurium_observable_map(model_etree, simulation, alg_kisao_id, variables, model, model_id): """ Get a mapping from XML XPath targets for variables of data generators to their corresponding tellurium identifiers Args: @@ -526,7 +582,7 @@ def get_variable_target_tellurium_observable_map(model_etree, simulation, alg_ki for variable in variables: if variable.symbol: if variable.symbol == Symbol.time.value and isinstance(simulation, UniformTimeCourseSimulation): - target_tellurium_observable_map[(variable.target, variable.symbol)] = 'time' + target_tellurium_observable_map[(model_id, variable.target, variable.symbol)] = 'time' else: invalid_symbols.append(variable.symbol) @@ -535,9 +591,9 @@ def get_variable_target_tellurium_observable_map(model_etree, simulation, alg_ki if sbml_id in all_sbml_ids: if alg_kisao_id != 'KISAO_0000029' and sbml_id in species_sbml_ids: - target_tellurium_observable_map[(variable.target, variable.symbol)] = '[' + sbml_id + ']' + target_tellurium_observable_map[(model_id, variable.target, variable.symbol)] = '[' + sbml_id + ']' else: - target_tellurium_observable_map[(variable.target, variable.symbol)] = sbml_id + target_tellurium_observable_map[(model_id, variable.target, variable.symbol)] = sbml_id else: invalid_targets.append(variable.target) @@ -654,7 +710,7 @@ def exec_sed_doc_with_tellurium(doc, working_dir, base_out_path, rel_out_path=No data_generators[curve.y_data_generator.id] = curve.y_data_generator labels[curve.y_data_generator.id] = curve.name or curve.y_data_generator.name or curve.y_data_generator.id - # print("LS DEBUG: Labels are " + str(labels)) + print("LS DEBUG: Labels are " + str(labels)) for data_generator in data_generators.values(): report.data_sets.append(DataSet( diff --git a/biosimulators_tellurium/data_model.py b/biosimulators_tellurium/data_model.py index 0a1ef02..4a0ddf9 100644 --- a/biosimulators_tellurium/data_model.py +++ b/biosimulators_tellurium/data_model.py @@ -56,7 +56,6 @@ class PlottingEngine(str, enum.Enum): 'KISAO_0000571': { 'kisao_id': 'KISAO_0000571', 'id': 'absolute_tolerance_adjustment_factor', - 'roadrunner_attribute': 'absolute_tolerance', 'name': 'absolute tolerance adjustment factor', 'type': ValueType.float, 'default': 1e-12, @@ -280,16 +279,16 @@ class PreprocesssedTask(object): """ Processed information about a SED task Attributes: - road_runner (:obj:`roadrunner.RoadRunner`): Road Runner instance with model - solver (:obj:`roadrunner.Integrator` or :obj:`roadrunner.SteadyStateSolver`): solver - model_change_target_tellurium_id_map (:obj:`dict`): dictionary that maps the targets of - changes to their corresponding tellurium identifiers (tuples of their type and index within their type) - algorithm_kisao_id (:obj:`str`): KiSAO id of algorithm to execute - variable_target_tellurium_observable_map (:obj:`dict`): dictionary that maps tuples of variable targets and - symbols to their corresponding tellurium observable identifiers + road_runners (:obj:`roadrunner.RoadRunner`): Road Runner instances with model, per task + solver (:obj:`roadrunner.Integrator` or :obj:`roadrunner.SteadyStateSolver`): solver, per task + model_change_target_tellurium_id_map (:obj:`dict`): dictionaries that map the targets of + changes to their corresponding tellurium identifiers (tuples of their type and index within their type), per task + algorithm_kisao_id (:obj:`str`): dictionaries of KiSAO id of algorithm to execute, per task + variable_target_tellurium_observable_maps (:obj:`dict`): dictionary of dictionaries that map tuples of variable targets and + symbols to their corresponding tellurium observable identifiers, per task """ - road_runner: roadrunner.RoadRunner - solver: typing.Union[roadrunner.Integrator, roadrunner.SteadyStateSolver] - model_change_target_tellurium_id_map: dict - algorithm_kisao_id: str - variable_target_tellurium_observable_map: dict + road_runners: dict + solvers: dict #typing.Union[roadrunner.Integrator, roadrunner.SteadyStateSolver] + model_change_target_tellurium_id_maps: dict + algorithm_kisao_ids: dict + variable_target_tellurium_observable_maps: dict From 0e27db648fc720ad84d60217e85e8012a0199a4d Mon Sep 17 00:00:00 2001 From: Lucian Smith Date: Wed, 5 Jul 2023 18:10:44 -0700 Subject: [PATCH 02/11] More linting. --- biosimulators_tellurium/core.py | 26 +++++++++++++++----------- biosimulators_tellurium/data_model.py | 7 ++++--- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/biosimulators_tellurium/core.py b/biosimulators_tellurium/core.py index a599066..9442660 100644 --- a/biosimulators_tellurium/core.py +++ b/biosimulators_tellurium/core.py @@ -312,6 +312,7 @@ def exec_sed_task(task, variables, preprocessed_task=None, log=None, config=None # return results and log return variable_results, log + def get_all_tasks_from_task(task): ret = set() if type(task) == Task: @@ -325,10 +326,12 @@ def get_all_tasks_from_task(task): else: raise NotImplementedError("Tasks other than 'Task' or 'RepeatedTask' are not supported.") + def reset_all_models(preprocessed_task): for taskid in preprocessed_task.road_runners: preprocessed_task.road_runners[taskid].resetAll() + def preprocess_sed_task(task, variables, config=None, simulator_config=None): """ Preprocess a SED task, including its possible model changes and variables. This is useful for avoiding repeatedly initializing tasks on repeated calls of :obj:`exec_sed_task`. @@ -382,15 +385,15 @@ def preprocess_sed_task(task, variables, config=None, simulator_config=None): model = subtask.model sim = subtask.simulation model_etree = lxml.etree.parse(model.source) - + if config.VALIDATE_SEDML_MODELS: raise_errors_warnings(*validation.validate_model(model, [], working_dir='.'), error_summary='Model `{}` is invalid.'.format(model.id), warning_summary='Model `{}` may be invalid.'.format(model.id)) - + # read model road_runner = roadrunner.RoadRunner(model.source) - + # get algorithm to execute algorithm_substitution_policy = get_algorithm_substitution_policy(config=config) exec_alg_kisao_id = get_preferred_substitute_algorithm_by_ids( @@ -417,11 +420,11 @@ def preprocess_sed_task(task, variables, config=None, simulator_config=None): param_props = alg_props['parameters'].get(change.kisao_id, None) if not config.VALIDATE_SEDML or param_props: if not config.VALIDATE_SEDML or validate_str_value(change.new_value, param_props['type']): - new_value = parse_value(change.new_value, param_props['type']) - att = param_props['id'] - if "roadrunner_attribute" in param_props: - att = param_props['roadrunner_attribute'] - setattr(solver, att, new_value) + new_value = parse_value(change.new_value, param_props['type']) + att = param_props['id'] + if "roadrunner_attribute" in param_props: + att = param_props['roadrunner_attribute'] + setattr(solver, att, new_value) else: if ( @@ -472,7 +475,7 @@ def preprocess_sed_task(task, variables, config=None, simulator_config=None): road_runner.timeCourseSelections = variable_tellurium_observable_ids road_runner.steadyStateSelections = variable_tellurium_observable_ids - #Add the variables to the dictionaries: + # Add the variables to the dictionaries: allroadrunners[subtask.id] = road_runner model_change_target_tellurium_id_maps[subtask.id] = model_change_target_tellurium_id_map exec_alg_kisao_ids[subtask.id] = exec_alg_kisao_id @@ -496,7 +499,8 @@ def get_model_variable_value(model, variable, preprocessed_task): submap = preprocessed_task.variable_target_tellurium_observable_maps[taskid] if (model.id, variable.target, variable.symbol) in submap: return submap[(model.id, variable.target, variable.symbol)] - raise ValueError("No stored variable with target " + variable.target + " and symbol " + variable.symbol + " in model " + model.id ) + raise ValueError("No stored variable with target " + variable.target + " and symbol " + variable.symbol + " in model " + model.id) + def set_model_variable_value(model, target, symbol, value, preprocessed_task): if preprocessed_task is None: @@ -506,7 +510,7 @@ def set_model_variable_value(model, target, symbol, value, preprocessed_task): if (model.id, target, symbol) in submap: tellurium_id = submap[(model.id, target, symbol)] preprocessed_task.road_runners[taskid][tellurium_id] = value - + def get_model_change_target_tellurium_change_map(model_etree, changes, alg_kisao_id, model): """ Get a mapping from XML XPath targets for model changes to tellurium identifiers for model changes diff --git a/biosimulators_tellurium/data_model.py b/biosimulators_tellurium/data_model.py index 4a0ddf9..71f5c42 100644 --- a/biosimulators_tellurium/data_model.py +++ b/biosimulators_tellurium/data_model.py @@ -10,8 +10,8 @@ import collections import dataclasses import enum -import roadrunner -import typing +# import roadrunner +# import typing __all__ = [ 'SedmlInterpreter', @@ -288,7 +288,8 @@ class PreprocesssedTask(object): symbols to their corresponding tellurium observable identifiers, per task """ road_runners: dict - solvers: dict #typing.Union[roadrunner.Integrator, roadrunner.SteadyStateSolver] + # solvers is dict of this type: typing.Union[roadrunner.Integrator, roadrunner.SteadyStateSolver] + solvers: dict model_change_target_tellurium_id_maps: dict algorithm_kisao_ids: dict variable_target_tellurium_observable_maps: dict From fb2743f141fbf7cae598229746eed0893e1e7b90 Mon Sep 17 00:00:00 2001 From: Lucian Smith Date: Wed, 5 Jul 2023 18:27:15 -0700 Subject: [PATCH 03/11] More linting. --- biosimulators_tellurium/data_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biosimulators_tellurium/data_model.py b/biosimulators_tellurium/data_model.py index 71f5c42..9018194 100644 --- a/biosimulators_tellurium/data_model.py +++ b/biosimulators_tellurium/data_model.py @@ -289,7 +289,7 @@ class PreprocesssedTask(object): """ road_runners: dict # solvers is dict of this type: typing.Union[roadrunner.Integrator, roadrunner.SteadyStateSolver] - solvers: dict + solvers: dict model_change_target_tellurium_id_maps: dict algorithm_kisao_ids: dict variable_target_tellurium_observable_maps: dict From 21ba99f2fec7dbcf8b1f4d8f6389ac83cdbc2fc7 Mon Sep 17 00:00:00 2001 From: Lucian Smith Date: Fri, 14 Jul 2023 14:33:30 -0700 Subject: [PATCH 04/11] Update to support more task changes. --- biosimulators_tellurium/core.py | 35 ++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/biosimulators_tellurium/core.py b/biosimulators_tellurium/core.py index 9442660..3ba57ce 100644 --- a/biosimulators_tellurium/core.py +++ b/biosimulators_tellurium/core.py @@ -256,7 +256,7 @@ def exec_sed_task(task, variables, preprocessed_task=None, log=None, config=None raise_errors_warnings(validation.validate_model_change_types(model.changes, (ModelAttributeChange, )), error_summary='Changes for model `{}` are not supported.'.format(model.id)) for change in model.changes: - component_id = preprocessed_task.model_change_target_tellurium_id_maps[task.id][change.target] + component_id = preprocessed_task.model_change_target_tellurium_id_maps[task.id][(change.model, change.target, change.symbol)] new_value = float(change.new_value) road_runner[component_id] = new_value @@ -381,6 +381,9 @@ def preprocess_sed_task(task, variables, config=None, simulator_config=None): exec_alg_kisao_ids = {} variable_target_tellurium_observable_maps = {} solvers = {} + allchanges = model.changes + if isinstance(task, RepeatedTask): + allchanges = allchanges + task.changes for subtasks in alltasks: model = subtask.model sim = subtask.simulation @@ -461,8 +464,10 @@ def preprocess_sed_task(task, variables, config=None, simulator_config=None): warn(msg, BioSimulatorsWarning) # validate model changes and build map + if isinstance(subtask, RepeatedTask): + allchanges = allchanges + subtask.changes model_change_target_tellurium_id_map = get_model_change_target_tellurium_change_map( - model_etree, model.changes, exec_alg_kisao_id, road_runner.model) + model_etree, allchanges, exec_alg_kisao_id, road_runner.model, model.id) # validate variables and build map variable_target_tellurium_observable_map = get_variable_target_tellurium_observable_map( @@ -505,14 +510,25 @@ def get_model_variable_value(model, variable, preprocessed_task): def set_model_variable_value(model, target, symbol, value, preprocessed_task): if preprocessed_task is None: raise ValueError("Tellurium cannot set a model value without a working preprocessed_task.") + success = False for taskid in preprocessed_task.variable_target_tellurium_observable_maps: submap = preprocessed_task.variable_target_tellurium_observable_maps[taskid] if (model.id, target, symbol) in submap: tellurium_id = submap[(model.id, target, symbol)] preprocessed_task.road_runners[taskid][tellurium_id] = value - - -def get_model_change_target_tellurium_change_map(model_etree, changes, alg_kisao_id, model): + success = True + if not success: + for taskid in preprocessed_task.model_change_target_tellurium_id_maps: + submap = preprocessed_task.model_change_target_tellurium_id_maps[taskid] + if (model.id, target, symbol) in submap: + tellurium_id = submap[(model.id, target, symbol)] + preprocessed_task.road_runners[taskid][tellurium_id] = value + success = True + if not success: + raise ValueError("No stored variable with target " + target + " and symbol " + symbol + " in model " + model.id) + + +def get_model_change_target_tellurium_change_map(model_etree, changes, alg_kisao_id, model, model_id): """ Get a mapping from XML XPath targets for model changes to tellurium identifiers for model changes Args: @@ -533,12 +549,17 @@ def get_model_change_target_tellurium_change_map(model_etree, changes, alg_kisao invalid_changes = [] for i_change, change in enumerate(changes): + if change.model.id != model_id: + raise NotImplementedError("Unable to process a change to model " + change.model_id + " inside a task concerning model " + model_id) + if change.symbol: + raise NotImplementedError("Unable to process a change to model " + change.model_id + " with the symbol " + change.symbol) + sbml_id = change_targets_to_sbml_ids[change.target] if alg_kisao_id == 'KISAO_0000029' and sbml_id in species_ids: - target_tellurium_id_map[change.target] = '[' + sbml_id + ']' + target_tellurium_id_map[(model_id, change.target, change.symbol)] = '[' + sbml_id + ']' elif sbml_id in component_ids: - target_tellurium_id_map[change.target] = sbml_id + target_tellurium_id_map[(model_id, change.target, change.symbol)] = sbml_id else: invalid_changes.append('{}: {}: {}'.format(i_change + 1, change.target, sbml_id)) From 201129c1e8fe440cb174571a2912775e839d0d94 Mon Sep 17 00:00:00 2001 From: Lucian Smith Date: Tue, 18 Jul 2023 15:35:44 -0700 Subject: [PATCH 05/11] Updates to allow attribute changes to work. Also, fix test. --- biosimulators_tellurium/core.py | 9 ++++++--- tests/test_core_main.py | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/biosimulators_tellurium/core.py b/biosimulators_tellurium/core.py index 3ba57ce..1526124 100644 --- a/biosimulators_tellurium/core.py +++ b/biosimulators_tellurium/core.py @@ -508,6 +508,7 @@ def get_model_variable_value(model, variable, preprocessed_task): def set_model_variable_value(model, target, symbol, value, preprocessed_task): + value = float(value) if preprocessed_task is None: raise ValueError("Tellurium cannot set a model value without a working preprocessed_task.") success = False @@ -549,11 +550,13 @@ def get_model_change_target_tellurium_change_map(model_etree, changes, alg_kisao invalid_changes = [] for i_change, change in enumerate(changes): - if change.model.id != model_id: + if hasattr(model, "change") and change.model.id != model_id: raise NotImplementedError("Unable to process a change to model " + change.model_id + " inside a task concerning model " + model_id) - if change.symbol: + if hasattr(model, "symbol") and change.symbol: raise NotImplementedError("Unable to process a change to model " + change.model_id + " with the symbol " + change.symbol) - + else: + change.symbol = None + sbml_id = change_targets_to_sbml_ids[change.target] if alg_kisao_id == 'KISAO_0000029' and sbml_id in species_ids: diff --git a/tests/test_core_main.py b/tests/test_core_main.py index 93fef18..d40b135 100644 --- a/tests/test_core_main.py +++ b/tests/test_core_main.py @@ -751,8 +751,6 @@ def test_exec_sedml_docs_in_combine_archive(self): if log.exception: raise log.exception - self._assert_curated_combine_archive_outputs(dirname, reports=True, plots=True) - def test_exec_sedml_docs_in_combine_archive_with_all_algorithms(self): for sedml_interpreter in SedmlInterpreter.__members__.values(): for alg in gen_algorithms_from_specs(self.SPECIFICATIONS_FILENAME).values(): @@ -824,6 +822,22 @@ def test_sim_with_docker_image(self): self._assert_curated_combine_archive_outputs(self.dirname, reports=True, plots=True) + # all SED-ML interpreters + def test_repeated_task_with_change(self): + for sedml_interpreter in SedmlInterpreter.__members__.values(): + simulator_config = SimulatorConfig() + simulator_config.sedml_interpreter = sedml_interpreter + + archive_filename = 'tests/fixtures/repeat1.omex' + + dirname = os.path.join(self.dirname, sedml_interpreter.name, 'reports') + _, log = core.exec_sedml_docs_in_combine_archive(archive_filename, dirname, simulator_config=simulator_config) + if log.exception: + raise log.exception + + self._assert_curated_combine_archive_outputs(dirname, reports=False, plots=True) + + # helper methods def _get_combine_archive_exec_env(self): return { From 7d61a7597a2ce0cfb92335620323c79f6d985ce8 Mon Sep 17 00:00:00 2001 From: Lucian Smith Date: Wed, 19 Jul 2023 11:51:28 -0700 Subject: [PATCH 06/11] Add basic 'is this interpretable' tests. Ideally we'd check the output, but I'm not sure how. --- tests/fixtures/change_initial_assignment.omex | Bin 0 -> 1818 bytes tests/fixtures/repeat_basic.omex | Bin 0 -> 1811 bytes tests/fixtures/repeat_initial_assignment.omex | Bin 0 -> 1939 bytes tests/fixtures/repeat_no_reset.omex | Bin 0 -> 1833 bytes tests/test_core_main.py | 41 ++++++++++++++++-- 5 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 tests/fixtures/change_initial_assignment.omex create mode 100644 tests/fixtures/repeat_basic.omex create mode 100644 tests/fixtures/repeat_initial_assignment.omex create mode 100644 tests/fixtures/repeat_no_reset.omex diff --git a/tests/fixtures/change_initial_assignment.omex b/tests/fixtures/change_initial_assignment.omex new file mode 100644 index 0000000000000000000000000000000000000000..ed8f5284578b0d34526e34997c393ff3f7720009 GIT binary patch literal 1818 zcmah~doUa59u1nJK|P{T$-3IDXsr^e4O^8qG*ucKsd#Rxsb{uHig>F>5wvAX6}wr~ z78PZY#|bUN9OM)jcu8_|8dsgy3{L#=&=s}IqsK(*2gQ5wu|PQeWK$b+w7>>{cR>;hq9Y>z+Fx$NOy<^8bHUto(du+ z+f*Iauqv%IZy~hWJT3L-gmUvP#~B#Y9%8WB-()vdV|>k7#gwp+JUT`AjLyBN*EV+=RVSv z89XiI_bLzZoIt#1d~}Yxy-p5uANCFNt*XcM+HW=8LJ6+JYgu+oQ)RG0wf{hqRXnrs z%*PodX0K@YyrZm1_lc)P6V?~@gH=6>O>e^L2{%*1-FH1W75RZ!;-MPKJo*NSerYctx{68vHU=NX6i9D`y+ z8PCE@qXzmaV!3VNh-vbdzjtrd+M6AI-ks5)?1~oDq&EaL@g${_W_x%#qXQR3nq!@G z?df}{OPZ#owP|J1ybt7Ml81z&(B8~;5zHWuVLpg{)Y`b>wJ#uY`?#7WrNeF8mi3+E z3AK#q{T~wge|rUCHVizj${ZabS@D+2-cQ=z-x{|POd?CpS1xAEEQ({*g8z@?aE~{2vgIH>0;%%pO(V*#U zcKmsVi&J>|%cf9deN(SR%B8h}HBd{VK=;mI-?1Is?ZTzyA!PCa6eA%jW>OF>_m@*x z;)1hF($EJzY2*8V0D!X8DVR%pJ858=#I zUwdByjYMs)?+er0{JAm|NQ@XAGN~2KV`Oypa=l+SgDI!5u68*lBtx8fPrQSFrOMOX z#L1e{lNs8UIfPTwD@=RrSqW_TrQ_M@yO7=YY4vMI{Ux`7)bSK`7p6;9$SFV1yOL+? z?{m|*iJFG%n2m_;pVS8fj2kxLOGgm&jQg3fx&a4d)w*kpS#{6?N_P^mI5VY7TU9+0 zMwGXKbAH%Rjbt$UOmR^N_p!Ru`J{jewPlaMcjbiRqC3~};*i0or$803@404BVxZ`f zw;q?}ZBg4R!;5inD{+nq>~z$1S`c74ZI@7U;?dIXhecx4BcmpB{hY{xGMF&s@*JP# zx-_<@HsyUkV|WNV?(17uhZHLk$47g;P~e1!Ue@nB&{elR++?7wXon6%-u*>{8F^f^ za}e|0Zu_cWJ9vxZU1u*|kOfG53(MhD$Y(zOnr+qt8QaeqffiwLPILMr@}MPn_Ab6} zCNNBXep7rqa=;1N(+d~!9h#bD4WH~iss55$zk<1uWyX3$9pz%Tr;NbQ2k{9x;~5f% z&X2cdU4qXDCeDu~wd%hegcQfd8h7nLWm*CtkuP3dsBMwW-IdzW3cWFH`J^R$9fY%& zkp%<(_YRSU3Lpc}{RGnUe>TeB#r~~`pCtYiQ;_>-E&tB^w_yLpT$VEb5p$e9aObCQ MIq7YcBKq_62c6(F=Kufz literal 0 HcmV?d00001 diff --git a/tests/fixtures/repeat_basic.omex b/tests/fixtures/repeat_basic.omex new file mode 100644 index 0000000000000000000000000000000000000000..922992aef497639df2291d71cc66537d1849f61e GIT binary patch literal 1811 zcmZ`)dpOhkAOFfWvs{J>%^aDM+ZvUq#L9%VVIRd7NbVu}Xd20jN@=pE2999h|32aSt@TT0g!M^lot@@v z#Sf)^xHHn_h6DwJ-|2R6ahsSHM7#w=P1s68Wzwtm(DPQf-#F?_L;B3t_yr-CR*_HUca)vrVlN!$H zUO1FXVudW!cI+V)ay#(c)r&3G6H%!>_!>a5t3TTIr=`iK`=oC@vN!U`$jIIgeMQ$g z*wBMJO434}G_#V%fZxWxIjNqZ-vQ-0s7t|SO0=za>ZlJy3HISDrd7^3{@VM1UYxiq z-+cIENKpFDW%=fAaQv@@$v!FkcCV0_K2)kk3lb-sq<#(UU;JP*Tn>9(g5*=vuU~Mp zTTgq|S?U2sIBVzv_vHAw=m+$n;_$Ox3eSy05`4`ho$d_fuvvSe0m=H(UCYU}$@2O! zt3BE0tkV0SD&|(mVBNWJ0U9yys!MZ|&w=XI8(Ju4?Jd<$`TeP-00xjv?mDfVSM_>` zk>;Jw&rg(S!(Y2?3Dgz>oykmJGRI&x)HfzlecLrGHp$ul>|#q(l*dce_S!|$J%gbPsUD2lXvasC?hUX+^9Vd&+^0(n!tBB(@5NBjLyV(gfzjemhWu9H^Es02Kgq+dP{HB z$-_@Jq&9}$>D7-+Q{_H@ek;ocH_M;37i6|nwxui$ zrBx~+Gd^Qn3$`W2A)l$O6kQ&(tjT~V3l=VQy7do)6@;J;U)9PDJEC`q*3ul5&c^*_ z*)=+<7mm#oUJENtb(5MU6oqQ4cdNdv_MBxiWxZ0>_M_3eza(+fa(GsbW_clz1)XVv z&QJs4N4mb_ldt@7`AF3#!tFm~U=TfH-^q{wRg1pgPb38?5mMa)e7#Auknch$VK&LM zVWc4ICva0ulB00HZY~!h%Pb8@NXyeUyq{tNle(w`FJB$anOb`SI-q)|tK@zG>lj># zy4xlDkjsI4*JL}Z{A{02QwkBR3p+G!GZ0^{6T79A-rTG*^6E}~q_u)BELNr(JGbKq zeuoG6Mf589!g{S>_gI@n79;uK?f?xw{CK?nw40E3E^0nqhM`mo>AeD4EwM!Rs7^1R zt{UfBOn$WUA6z3}Tm=#FV%v5A|36Vg;{jrT+IJA0zvatcssH4T?}YzS14R+_!z+K~ c{nI*s@It|VUoH_3hJ1e&7gePQiT}C%3C#o{`v3p{ literal 0 HcmV?d00001 diff --git a/tests/fixtures/repeat_initial_assignment.omex b/tests/fixtures/repeat_initial_assignment.omex new file mode 100644 index 0000000000000000000000000000000000000000..1760f32f4f00064359006a427e7cefca9d5723f4 GIT binary patch literal 1939 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 literal 0 HcmV?d00001 diff --git a/tests/test_core_main.py b/tests/test_core_main.py index d40b135..bbb1f77 100644 --- a/tests/test_core_main.py +++ b/tests/test_core_main.py @@ -822,21 +822,56 @@ def test_sim_with_docker_image(self): self._assert_curated_combine_archive_outputs(self.dirname, reports=True, plots=True) - # all SED-ML interpreters def test_repeated_task_with_change(self): for sedml_interpreter in SedmlInterpreter.__members__.values(): simulator_config = SimulatorConfig() simulator_config.sedml_interpreter = sedml_interpreter - archive_filename = 'tests/fixtures/repeat1.omex' + archive_filename = 'tests/fixtures/repeat_basic.omex' dirname = os.path.join(self.dirname, sedml_interpreter.name, 'reports') _, log = core.exec_sedml_docs_in_combine_archive(archive_filename, dirname, simulator_config=simulator_config) if log.exception: raise log.exception - self._assert_curated_combine_archive_outputs(dirname, reports=False, plots=True) + def test_repeated_task_with_change_and_no_reset(self): + for sedml_interpreter in SedmlInterpreter.__members__.values(): + simulator_config = SimulatorConfig() + simulator_config.sedml_interpreter = sedml_interpreter + + archive_filename = 'tests/fixtures/repeat_no_reset.omex' + + dirname = os.path.join(self.dirname, sedml_interpreter.name, 'reports') + _, log = core.exec_sedml_docs_in_combine_archive(archive_filename, dirname, simulator_config=simulator_config) + if log.exception: + raise log.exception + + + def test_repeated_task_with_change_to_initial_assignment(self): + for sedml_interpreter in SedmlInterpreter.__members__.values(): + simulator_config = SimulatorConfig() + simulator_config.sedml_interpreter = sedml_interpreter + + archive_filename = 'tests/fixtures/repeat_initial_assignment.omex' + + dirname = os.path.join(self.dirname, sedml_interpreter.name, 'reports') + _, log = core.exec_sedml_docs_in_combine_archive(archive_filename, dirname, simulator_config=simulator_config) + if log.exception: + raise log.exception + + + def test_change_to_initial_assignment(self): + for sedml_interpreter in SedmlInterpreter.__members__.values(): + simulator_config = SimulatorConfig() + simulator_config.sedml_interpreter = sedml_interpreter + + archive_filename = 'tests/fixtures/change_initial_assignment.omex' + + dirname = os.path.join(self.dirname, sedml_interpreter.name, 'reports') + _, log = core.exec_sedml_docs_in_combine_archive(archive_filename, dirname, simulator_config=simulator_config) + if log.exception: + raise log.exception # helper methods def _get_combine_archive_exec_env(self): From 61f38d7b7570a549993322ff68e99210e661535c Mon Sep 17 00:00:00 2001 From: Lucian Smith Date: Mon, 24 Jul 2023 11:02:19 -0700 Subject: [PATCH 07/11] Update version requirement for utils. --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8989459..8813121 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -biosimulators_utils[logging] >= 0.1.180 +biosimulators_utils[logging] >= 0.1.183 kisao >= 2.33 libroadrunner >= 2.4.0 lxml From ce83dacc43f5758f82388f0af7ec8ee45fee5c4c Mon Sep 17 00:00:00 2001 From: Lucian Smith Date: Mon, 24 Jul 2023 11:49:33 -0700 Subject: [PATCH 08/11] Re-fix old problem; also fix test. Somehow, the old 'relative tolerance adjustment factor' fix got dropped? Probably because of git? Anyway, re-reverted. Also, the roadrunner objects inside the presimulated task are now organized by task ID. --- biosimulators_tellurium/core.py | 2 +- biosimulators_tellurium/data_model.py | 1 + tests/test_core_main.py | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/biosimulators_tellurium/core.py b/biosimulators_tellurium/core.py index 1526124..d9b0e25 100644 --- a/biosimulators_tellurium/core.py +++ b/biosimulators_tellurium/core.py @@ -427,7 +427,7 @@ def preprocess_sed_task(task, variables, config=None, simulator_config=None): att = param_props['id'] if "roadrunner_attribute" in param_props: att = param_props['roadrunner_attribute'] - setattr(solver, att, new_value) + setattr(solver, att, new_value) else: if ( diff --git a/biosimulators_tellurium/data_model.py b/biosimulators_tellurium/data_model.py index 9018194..61094d8 100644 --- a/biosimulators_tellurium/data_model.py +++ b/biosimulators_tellurium/data_model.py @@ -56,6 +56,7 @@ class PlottingEngine(str, enum.Enum): 'KISAO_0000571': { 'kisao_id': 'KISAO_0000571', 'id': 'absolute_tolerance_adjustment_factor', + 'roadrunner_attribute': 'absolute_tolerance', 'name': 'absolute tolerance adjustment factor', 'type': ValueType.float, 'default': 1e-12, diff --git a/tests/test_core_main.py b/tests/test_core_main.py index bbb1f77..1c44adb 100644 --- a/tests/test_core_main.py +++ b/tests/test_core_main.py @@ -522,9 +522,9 @@ def test_exec_sed_task_with_preprocesssed_task(self): variable_results, log = core.exec_sed_task(task, variables, preprocessed_task=preprocessed_task) with self.assertRaises(AssertionError): numpy.testing.assert_allclose(variable_results['C'][-1], end_c) - mid_c = preprocessed_task.road_runner['C'] - mid_m = preprocessed_task.road_runner['M'] - mid_x = preprocessed_task.road_runner['X'] + mid_c = preprocessed_task.road_runner[task.id]['C'] + mid_m = preprocessed_task.road_runner[task.id]['M'] + mid_x = preprocessed_task.road_runner[task.id]['X'] self.assertIsInstance(mid_c, float) variable_results, log = core.exec_sed_task(task, variables, preprocessed_task=preprocessed_task) From ad1d2f02038f259c01ff7b1e0d37e793f80b9327 Mon Sep 17 00:00:00 2001 From: Lucian Smith Date: Mon, 24 Jul 2023 11:59:03 -0700 Subject: [PATCH 09/11] road_runner -> road_runners --- tests/test_core_main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_core_main.py b/tests/test_core_main.py index 1c44adb..93d57ee 100644 --- a/tests/test_core_main.py +++ b/tests/test_core_main.py @@ -522,9 +522,9 @@ def test_exec_sed_task_with_preprocesssed_task(self): variable_results, log = core.exec_sed_task(task, variables, preprocessed_task=preprocessed_task) with self.assertRaises(AssertionError): numpy.testing.assert_allclose(variable_results['C'][-1], end_c) - mid_c = preprocessed_task.road_runner[task.id]['C'] - mid_m = preprocessed_task.road_runner[task.id]['M'] - mid_x = preprocessed_task.road_runner[task.id]['X'] + mid_c = preprocessed_task.road_runners[task.id]['C'] + mid_m = preprocessed_task.road_runners[task.id]['M'] + mid_x = preprocessed_task.road_runners[task.id]['X'] self.assertIsInstance(mid_c, float) variable_results, log = core.exec_sed_task(task, variables, preprocessed_task=preprocessed_task) From 26f99752f079fa032db2e5b00b34b9249dcc8509 Mon Sep 17 00:00:00 2001 From: Lucian Smith Date: Mon, 24 Jul 2023 12:56:52 -0700 Subject: [PATCH 10/11] New structure requires different things; adjust tests accordingly. The changes are all things that happen in the normal course of execution (now), but they are newly-required, like ids for the tasks and models. --- tests/test_core_main.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_core_main.py b/tests/test_core_main.py index 93d57ee..6026ec5 100644 --- a/tests/test_core_main.py +++ b/tests/test_core_main.py @@ -445,7 +445,9 @@ def test_exec_sed_task_error_handling_with_biosimulators(self): def test_exec_sed_task_with_preprocesssed_task(self): # configure simulation task = sedml_data_model.Task( + id="task1", model=sedml_data_model.Model( + id="model1", source=self.EXAMPLE_MODEL_FILENAME, language=sedml_data_model.ModelLanguage.SBML.value, changes=[ @@ -547,6 +549,8 @@ def test_exec_sed_task_with_preprocesssed_task(self): new_value=mid_x, ), ] + for change in task.model.changes: + change.model = task.model.id preprocessed_task = core.preprocess_sed_task(task, variables) variable_results, log = core.exec_sed_task(task, variables, preprocessed_task=preprocessed_task) numpy.testing.assert_allclose(variable_results['C'][-1], end_c) @@ -581,6 +585,9 @@ def test_exec_sed_task_with_preprocesssed_task(self): new_value=str(mid_x), ), ] + for change in task.model.changes: + change.model = task.model.id + preprocessed_task = core.preprocess_sed_task(task, variables) variable_results, log = core.exec_sed_task(task, variables, preprocessed_task=preprocessed_task) numpy.testing.assert_allclose(variable_results['C'][-1], end_c) From 31fb8e7035085e6219315c695b2e3f3a3eaac2ab Mon Sep 17 00:00:00 2001 From: Lucian Smith Date: Mon, 24 Jul 2023 13:04:59 -0700 Subject: [PATCH 11/11] Update version number. All the tests pass! --- biosimulators_tellurium/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biosimulators_tellurium/_version.py b/biosimulators_tellurium/_version.py index c2bb26a..255df28 100644 --- a/biosimulators_tellurium/_version.py +++ b/biosimulators_tellurium/_version.py @@ -1 +1 @@ -__version__ = '0.1.33' +__version__ = '0.1.34'