Ejemplo n.º 1
0
def preprocess_sed_task(task, variables, 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`.

    Args:
        task (:obj:`Task`): task
        variables (:obj:`list` of :obj:`Variable`): variables that should be recorded
        config (:obj:`Config`, optional): BioSimulators common configuration

    Returns:
        :obj:`dict`: preprocessed information about the task
    """
    config = config or get_config()

    sim = task.simulation

    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(task.model.language,
                                               ModelLanguage.SBML),
            error_summary='Language for model `{}` is not supported.'.format(
                task.model.id))
        raise_errors_warnings(
            validation.validate_model_change_types(task.model.changes,
                                                   (ModelAttributeChange, )),
            error_summary='Changes for model `{}` are not supported.'.format(
                task.model.id))
        raise_errors_warnings(
            *validation.validate_model_changes(task.model),
            error_summary='Changes for model `{}` are invalid.'.format(
                task.model.id))
        raise_errors_warnings(validation.validate_simulation_type(
            sim, (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(task.model.source)
    change_target_sbml_id_map = validation.validate_target_xpaths(
        task.model.changes, model_etree, attr='id')
    variable_target_sbml_id_map = validation.validate_target_xpaths(
        variables, model_etree, attr='id')

    # Read the SBML-encoded model located at `task.model.source`
    model, errors = gillespy2.import_SBML(task.model.source)
    if model is None or errors:
        raise ValueError('Model at {} could not be imported:\n  - {}'.format(
            task.model.source,
            '\n  - '.join(message for message, code in errors)))

    # preprocess model changes
    parameters = model.get_all_parameters()
    species = model.get_all_species()
    change_target_model_obj_map = {}
    invalid_changes = []
    for change in task.model.changes:
        sbml_id = change_target_sbml_id_map[change.target]
        model_obj = parameters.get(sbml_id, species.get(sbml_id, None))
        if model_obj is None:
            invalid_changes.append(change.target)
        else:
            change_target_model_obj_map[change.target] = model_obj

    if invalid_changes:
        raise ValueError(''.join([
            'The following model targets cannot be changed:\n  - {}\n\n'.
            format('\n  - '.join(sorted(invalid_changes)), ),
            'Model change targets must have one of the following SBML ids:\n  - {}'
            .format(
                '\n  - '.join(
                    sorted(list(parameters.keys()) + list(species.keys()))), ),
        ]))

    # Load the algorithm specified by `sim.algorithm`
    algorithm_substitution_policy = get_algorithm_substitution_policy(
        config=config)
    exec_kisao_id = get_preferred_substitute_algorithm_by_ids(
        sim.algorithm.kisao_id,
        KISAO_ALGORITHM_MAP.keys(),
        substitution_policy=algorithm_substitution_policy)
    algorithm = KISAO_ALGORITHM_MAP[exec_kisao_id]

    solver = algorithm.solver
    if solver == gillespy2.SSACSolver and (model.get_all_events() or
                                           model.get_all_assignment_rules()):
        solver = gillespy2.NumPySSASolver

    # Apply the algorithm parameter changes specified by `sim.algorithm.parameter_changes`
    algorithm_params = {}
    if exec_kisao_id == sim.algorithm.kisao_id:
        for change in sim.algorithm.changes:
            parameter = algorithm.parameters.get(change.kisao_id, None)
            if parameter:
                try:
                    parameter.set_value(algorithm_params, change.new_value)
                except (NotImplementedError, ValueError) as exception:
                    if (ALGORITHM_SUBSTITUTION_POLICY_LEVELS[
                            algorithm_substitution_policy] <=
                            ALGORITHM_SUBSTITUTION_POLICY_LEVELS[
                                AlgorithmSubstitutionPolicy.NONE]):
                        raise
                    else:
                        warn(
                            'Unsuported value `{}` for algorithm parameter `{}` was ignored:\n  {}'
                            .format(change.new_value, change.kisao_id,
                                    str(exception).replace('\n', '\n  ')),
                            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, parameter.name)
                            for kisao_id, parameter in
                            algorithm.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, parameter.name)
                            for kisao_id, parameter in
                            algorithm.parameters.items())),
                    ])
                    warn(msg, BioSimulatorsWarning)

    # determine allowed variable targets
    predicted_ids = list(species.keys()) + list(parameters.keys())
    unpredicted_symbols = set()
    unpredicted_targets = set()
    for variable in variables:
        if variable.symbol:
            if variable.symbol != Symbol.time:
                unpredicted_symbols.add(variable.symbol)

        else:
            if variable_target_sbml_id_map[
                    variable.target] not in predicted_ids:
                unpredicted_targets.add(variable.target)

    if unpredicted_symbols:
        raise NotImplementedError("".join([
            "The following variable symbols are not supported:\n  - {}\n\n".
            format('\n  - '.join(sorted(unpredicted_symbols)), ),
            "Symbols must be one of the following:\n  - {}".format(
                Symbol.time),
        ]))

    if unpredicted_targets:
        raise ValueError(''.join([
            'The following variable targets could not be recorded:\n  - {}\n\n'
            .format('\n  - '.join(sorted(unpredicted_targets)), ),
            'Targets must have one of the following SBML ids:\n  - {}'.format(
                '\n  - '.join(sorted(predicted_ids)), ),
        ]))

    # return preprocessed information about the task
    return {
        'model': {
            'model': model,
            'change_target_model_obj_map': change_target_model_obj_map,
            'variable_target_sbml_id_map': variable_target_sbml_id_map,
        },
        'simulation': {
            'algorithm_kisao_id': exec_kisao_id,
            'solver': solver,
            'solver_args': dict(**algorithm.solver_args, **algorithm_params),
        }
    }
Ejemplo n.º 2
0
def preprocess_sed_task(task, variables, 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`.

    Args:
        task (:obj:`Task`): task
        variables (:obj:`list` of :obj:`Variable`): variables that should be recorded
        config (:obj:`Config`, optional): BioSimulators common configuration

    Returns:
        :obj:`dict`: preprocessed information about the task
    """
    config = config or get_config()

    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(task.model.language, ModelLanguage.BNGL),
            error_summary='Language for model `{}` is not supported.'.format(task.model.id))
        raise_errors_warnings(
            validation.validate_model_change_types(task.model.changes, (ModelAttributeChange, )),
            error_summary='Changes for model `{}` are not supported.'.format(task.model.id))
        raise_errors_warnings(
            *validation.validate_model_changes(task.model),
            error_summary='Changes for model `{}` are invalid.'.format(task.model.id))
        raise_errors_warnings(
            validation.validate_simulation_type(task.simulation, (UniformTimeCourseSimulation, )),
            error_summary='{} `{}` is not supported.'.format(
                task.simulation.__class__.__name__,
                task.simulation.id))
        raise_errors_warnings(
            *validation.validate_simulation(task.simulation),
            error_summary='Simulation `{}` is invalid.'.format(task.simulation.id))
        raise_errors_warnings(
            *validation.validate_data_generator_variables(variables),
            error_summary='Data generator variables for task `{}` are invalid.'.format(task.id))

    # read the model from the BNGL file
    bionetgen_task = read_task(task.model.source)
    if bionetgen_task.actions:
        warnings.warn('Actions in the BNGL file were ignored.', IgnoredBnglFileContentWarning)
        bionetgen_task.actions = []

    # validate and apply the model attribute changes to the BioNetGen task
    model_changes = {}
    for change in task.model.changes:
        model_changes[change.target] = preprocess_model_attribute_change(bionetgen_task, change)

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

    # apply the SED algorithm and its parameters to the BioNetGen task
    simulation_actions, alg_kisao_id = create_actions_for_simulation(task.simulation)

    # return the values of the variables and log
    return {
        'bionetgen_task': bionetgen_task,
        'model_changes': model_changes,
        'simulation_actions': simulation_actions,
        'algorithm_kisao_id': alg_kisao_id,
    }
Ejemplo n.º 3
0
def exec_sed_task(sed_task, variables, log=None):
    """ Execute a task and save its results

    Args:
       sed_task (:obj:`Task`): task
       variables (:obj:`list` of :obj:`Variable`): variables that should be recorded
       log (:obj:`TaskLog`, optional): log for the task

    Returns:
        :obj:`tuple`:

            :obj:`VariableResults`: results of variables
            :obj:`TaskLog`: log
    """
    """ Validate task

    * Model is encoded in BNGL
    * Model changes are instances of :obj:`ModelAttributeChange`
    * Simulation is an instance of :obj:`UniformTimeCourseSimulation`

        * Time course is valid
        * initial time <= output start time <= output end time
        * Number of points is an non-negative integer

    Note:

    * Model attribute changes are validated by

        * :obj:`add_model_attribute_change_to_task`
        * BioNetGen

    * Data generator variables are validated by

        * :obj:`add_variables_to_task`
        * BioNetGen
        * :obj:`get_variables_results_from_observable_results`
    """
    log = log or TaskLog()

    raise_errors_warnings(validation.validate_task(sed_task),
                          error_summary='Task `{}` is invalid.'.format(
                              sed_task.id))
    raise_errors_warnings(
        validation.validate_model_language(sed_task.model.language,
                                           ModelLanguage.BNGL),
        error_summary='Language for model `{}` is not supported.'.format(
            sed_task.model.id))
    raise_errors_warnings(
        validation.validate_model_change_types(sed_task.model.changes,
                                               (ModelAttributeChange, )),
        error_summary='Changes for model `{}` are not supported.'.format(
            sed_task.model.id))
    raise_errors_warnings(
        *validation.validate_model_changes(sed_task.model),
        error_summary='Changes for model `{}` are invalid.'.format(
            sed_task.model.id))
    raise_errors_warnings(validation.validate_simulation_type(
        sed_task.simulation, (UniformTimeCourseSimulation, )),
                          error_summary='{} `{}` is not supported.'.format(
                              sed_task.simulation.__class__.__name__,
                              sed_task.simulation.id))
    raise_errors_warnings(validation.validate_simulation(sed_task.simulation),
                          error_summary='Simulation `{}` is invalid.'.format(
                              sed_task.simulation.id))
    raise_errors_warnings(
        *validation.validate_data_generator_variables(variables),
        error_summary='Data generator variables for task `{}` are invalid.'.
        format(sed_task.id))

    # read the model from the BNGL file
    bionetgen_task = read_task(sed_task.model.source)
    if bionetgen_task.actions:
        warnings.warn('Actions in the BNGL file were ignored.',
                      IgnoredBnglFileContentWarning)
        bionetgen_task.actions = []

    # validate and apply the model attribute changes to the BioNetGen task
    for change in sed_task.model.changes:
        add_model_attribute_change_to_task(bionetgen_task, change)

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

    # apply the SED algorithm and its parameters to the BioNetGen task
    add_simulation_to_task(bionetgen_task, sed_task.simulation)

    # execute the task
    observable_results = exec_bionetgen_task(bionetgen_task)

    # get predicted values of the variables
    variable_results = get_variables_results_from_observable_results(
        observable_results, variables)
    for key in variable_results.keys():
        variable_results[key] = variable_results[key][-(
            sed_task.simulation.number_of_points + 1):]

    # log action
    log.algorithm = sed_task.simulation.algorithm.kisao_id
    log.simulator_details = {
        'actions': bionetgen_task.actions,
    }

    # return the values of the variables and log
    return variable_results, log
Ejemplo n.º 4
0
def exec_sed_task(task, variables, log=None):
    ''' Execute a task and save its results

    Args:
       task (:obj:`Task`): task
       variables (:obj:`list` of :obj:`Variable`): variables that should be recorded
       log (:obj:`TaskLog`, optional): log for the task

    Returns:
        :obj:`tuple`:

            :obj:`VariableResults`: results of variables
            :obj:`TaskLog`: log
    '''
    log = log or TaskLog()

    validation.validate_task(task)
    validation.validate_model_language(task.model.language, ModelLanguage.SBML)
    validation.validate_model_change_types(task.model.changes, ())
    validation.validate_model_changes(task.model.changes)
    validation.validate_simulation_type(task.simulation, (UniformTimeCourseSimulation, ))
    validation.validate_uniform_time_course_simulation(task.simulation)
    validation.validate_data_generator_variables(variables)
    target_x_paths_to_sbml_ids = validation.validate_variable_xpaths(variables, task.model.source, attr='id')

    # validate time course
    if task.simulation.initial_time != 0:
        raise NotImplementedError('Initial time must be zero')

    # execute the simulation
    integrator = get_integrator(task.simulation.algorithm)
    args = [task.model,
            task.simulation.output_end_time, task.simulation.output_end_time / task.simulation.number_of_points,
            1, 0, integrator, 0]
    results = libsbmlsim.simulateSBMLFromFile(*args)

    # extract results
    variable_results = VariableResults()
    for variable in variables:
        # TODO: extract results from `results` and convert to numpy array
        # TODO: throw errors in the simulation request an invalid/unsupported output

        if variable.symbol:
            if variable.symbol == Symbol.time:
                i_result = todo_index_of_time_in_results  # index in results for time
            else:
                raise NotImplementedError('Symbol {} is not supported'.format(variable.symbol))

        else:
            sbml_id = target_x_paths_to_sbml_ids[variable.target]
            i_result = todo_index_of_sbml_id_in_results  # index in results for SBML id
            if not i_result:
                raise NotImplementedError('Variable with target {} is not supported'.format(variable.target))

        variable_results[variable.id] = results[i_result][-(task.simulation.number_of_points + 1):]

    # log action
    log.algorithm = task.simulation.algorithm.kisao_id
    log.simulator_details = {
        'method': "simulateSBMLFromFile",
        'arguments': args,
    }

    # return results and log
    return variable_results, log
Ejemplo n.º 5
0
def preprocess_sed_task(task, variables, 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`.

    Args:
        task (:obj:`Task`): task
        variables (:obj:`list` of :obj:`Variable`): variables that should be recorded
        config (:obj:`Config`, optional): BioSimulators common configuration

    Returns:
        :obj:`dict`: preprocessed information about the task
    """
    config = config or get_config()

    sed_model = task.model
    sed_simulation = task.simulation

    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(sed_model.language,
                                               ModelLanguage.Smoldyn),
            error_summary='Language for model `{}` is not supported.'.format(
                sed_model.id))
        raise_errors_warnings(
            validation.validate_model_change_types(sed_model.changes,
                                                   (ModelAttributeChange, )),
            error_summary='Changes for model `{}` are not supported.'.format(
                sed_model.id))
        raise_errors_warnings(
            *validation.validate_model_changes(sed_model),
            error_summary='Changes for model `{}` are invalid.'.format(
                sed_model.id))
        raise_errors_warnings(validation.validate_simulation_type(
            sed_simulation, (UniformTimeCourseSimulation, )),
                              error_summary='{} `{}` is not supported.'.format(
                                  sed_simulation.__class__.__name__,
                                  sed_simulation.id))
        raise_errors_warnings(
            *validation.validate_simulation(sed_simulation),
            error_summary='Simulation `{}` is invalid.'.format(
                sed_simulation.id))
        raise_errors_warnings(
            *validation.validate_data_generator_variables(variables),
            error_summary='Data generator variables for task `{}` are invalid.'
            .format(task.id))

    if sed_simulation.algorithm.kisao_id not in KISAO_ALGORITHMS_MAP:
        msg = 'Algorithm `{}` is not supported. The following algorithms are supported:{}'.format(
            sed_simulation.algorithm.kisao_id,
            ''.join('\n  {}: {}'.format(kisao_id, alg_props['name'])
                    for kisao_id, alg_props in KISAO_ALGORITHMS_MAP.items()))
        raise NotImplementedError(msg)

    # read Smoldyn configuration
    simulation_configuration = read_smoldyn_simulation_configuration(
        sed_model.source)
    normalize_smoldyn_simulation_configuration(simulation_configuration)

    # turn off Smoldyn's graphics
    disable_smoldyn_graphics_in_simulation_configuration(
        simulation_configuration)

    # preprocess model changes
    sed_smoldyn_preprocessing_change_map = {}
    sed_smoldyn_simulation_change_map = {}
    for change in sed_model.changes:
        smoldyn_change = validate_model_change(change)

        if smoldyn_change.execution == SimulationChangeExecution.preprocessing:
            sed_smoldyn_preprocessing_change_map[change] = smoldyn_change
        else:
            sed_smoldyn_simulation_change_map[change.target] = smoldyn_change

    # apply preprocessing-time changes
    for change, smoldyn_change in sed_smoldyn_preprocessing_change_map.items():
        apply_change_to_smoldyn_simulation_configuration(
            simulation_configuration, change, smoldyn_change)

    # write the modified Smoldyn configuration to a temporary file
    fid, smoldyn_configuration_filename = tempfile.mkstemp(suffix='.txt')
    os.close(fid)
    write_smoldyn_simulation_configuration(simulation_configuration,
                                           smoldyn_configuration_filename)

    # initialize a simulation from the Smoldyn file
    smoldyn_simulation = init_smoldyn_simulation_from_configuration_file(
        smoldyn_configuration_filename)

    # clean up temporary file
    os.remove(smoldyn_configuration_filename)

    # apply the SED algorithm parameters to the Smoldyn simulation and to the arguments to its ``run`` method
    smoldyn_simulation_attrs = {}
    smoldyn_simulation_run_alg_param_args = {}
    for sed_algorithm_parameter_change in sed_simulation.algorithm.changes:
        val = get_smoldyn_instance_attr_or_run_algorithm_parameter_arg(
            sed_algorithm_parameter_change)
        if val['type'] == AlgorithmParameterType.run_argument:
            smoldyn_simulation_run_alg_param_args[val['name']] = val['value']
        else:
            smoldyn_simulation_attrs[val['name']] = val['value']

    # apply the SED algorithm parameters to the Smoldyn simulation and to the arguments to its ``run`` method
    for attr_name, value in smoldyn_simulation_attrs.items():
        setter = getattr(smoldyn_simulation, attr_name)
        setter(value)

    # validate SED variables
    variable_output_cmd_map = validate_variables(variables)

    # Setup Smoldyn output files for the SED variables
    smoldyn_configuration_dirname = os.path.dirname(
        smoldyn_configuration_filename)
    smoldyn_output_files = add_smoldyn_output_files_for_sed_variables(
        smoldyn_configuration_dirname, variables, variable_output_cmd_map,
        smoldyn_simulation)

    # return preprocessed information
    return {
        'simulation': smoldyn_simulation,
        'simulation_attrs': smoldyn_simulation_attrs,
        'simulation_run_alg_param_args': smoldyn_simulation_run_alg_param_args,
        'sed_smoldyn_simulation_change_map': sed_smoldyn_simulation_change_map,
        'variable_output_cmd_map': variable_output_cmd_map,
        'output_files': smoldyn_output_files,
    }