Source code for gillespy2.stochss.StochSSexport

# GillesPy2 is a modeling toolkit for biochemical simulation.
# Copyright (C) 2019-2024 GillesPy2 developers.

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
''' Module for exporting GillesPy2 model as StochSS Live! models. '''
import ast
import json

from gillespy2.core.jsonify import ComplexJsonCoder

def __add_events(model, events):
    for name, event in events.items():
        s_event = {"compID":model['defaultID'],
                   "name": name,
                   "annotation": "",
                   "delay": event.delay,
                   "priority": event.priority,
                   "triggerExpression": event.trigger.expression,
                   "initialValue": event.trigger.value,
                   "persistent": event.trigger.persistent,
                   "useValuesFromTriggerTime": event.use_values_from_trigger_time,
                   "eventAssignments": []}

        __add_event_assignments(model=model, event=s_event, assignments=event.assignments)

        model['eventsCollection'].append(s_event)
        model['defaultID'] += 1


def __add_event_assignments(model, event, assignments):
    for assignment in assignments:
        name = assignment.variable.name
        try:
            variable = __get_species(species=model['species'], name=name)
        except IndexError:
            variable = __get_parameter(parameters=model['parameters'], name=name)

        s_assignment = {"variable": variable,
                        "expression": assignment.expression}
        event['eventAssignments'].append(s_assignment)


def __add_function_definitions(model, function_definitions):
    for name, function_definition in function_definitions.items():
        variables = function_definition.get_arg_string()
        expression = function_definition.function_string
        function = f"lambda({variables}, {expression})"
        signature = f"{name}({variables})"

        s_function_definition = {"compID":model['defaultID'],
                                 "name":name,
                                 "function":function,
                                 "expression":expression,
                                 "variables":variables,
                                 "signature":signature,
                                 "annotation": ""}
        model['functionDefinitions'].append(s_function_definition)
        model['defaultID'] += 1


def __add_parameters(model, parameters):
    for name, parameter in parameters.items():
        try:
            expression = ast.literal_eval(parameter.expression)
        except Exception: # pylint: disable=broad-except
            expression = parameter.expression
        s_parameter = {"compID":model['defaultID'],
                       "name":name,
                       "expression":str(expression),
                       "annotation": ""}
        model['parameters'].append(s_parameter)
        model['defaultID'] += 1


def __add_reactions(model, reactions):
    for name, reaction in reactions.items():
        s_reaction = {"compID":model['defaultID'],
                      "name":name,
                      "reactionType": "custom-propensity",
                      "massaction": False,
                      "propensity": reaction.propensity_function,
                      "annotation": "",
                      "rate": {},
                      "types": [],
                      "reactants": [],
                      "products": []}

        for key in ['reactants', 'products']:
            __add_stoich_species(s_reaction=s_reaction, reaction=reaction,
                                                key=key, species=model['species'])
        __add_summary(reaction=s_reaction)

        model['reactions'].append(s_reaction)
        model['defaultID'] += 1


def __add_rules(model, r_type, rules):
    for name, rule in rules.items():
        try:
            variable = __get_species(species=model['species'], name=rule.variable.name)
        except IndexError:
            variable = __get_parameter(parameters=model['parameters'], name=rule.variable.name)

        s_rule = {"compID":model['defaultID'],
                  "name":name,
                  "expression":rule.formula,
                  "type":r_type,
                  "variable":variable,
                  "annotation": ""}
        model['rules'].append(s_rule)
        model['defaultID'] += 1


def __add_species(model, species):
    modes = []

    for name, specie in species.items():
        if specie.mode is not None and specie.mode not in modes:
            modes.append(specie.mode)
        s_species = {"compID":model['defaultID'],
                     "name":name,
                     "value":specie.initial_value,
                     "mode":specie.mode,
                     "switchTol": specie.switch_tol,
                     "switchMin": specie.switch_min,
                     "isSwitchTol": specie.switch_min == 0,
                     "annotation": "",
                     "diffusionConst":0,
                     "types": []}
        model['species'].append(s_species)
        model['defaultID'] += 1

    if not modes:
        model['defaultMode'] = ""
    elif len(modes) > 1:
        model['defaultMode'] = "dynamic"
    else:
        model['defaultMode'] = modes[0]


def __add_stoich_species(s_reaction, reaction, key, species):
    source = reaction.reactants if key == "reactants" else reaction.products
    for specie, ratio in source.items():
        stoich_species = {"ratio":ratio,
                          "specie":__get_species(species=species, name=specie.name)}
        s_reaction[key].append(stoich_species)


def __add_summary(reaction):
    r_summary = __build_element(reaction['reactants'])
    p_summary = __build_element(reaction['products'])
    reaction['summary'] = f"{r_summary} \\rightarrow {p_summary}"


def __build_element(stoich_species):
    if not stoich_species:
        return "\\emptyset"

    elements = []
    for species in stoich_species:
        name = species['specie']['name']
        ratio = species['ratio']
        element = f"{ratio}{name}" if ratio > 1 else name
        elements.append(element)
    return '+'.join(elements)


def __get_parameter(parameters, name):
    return list(filter(lambda parameter: parameter['name'] == name, parameters))[0]


def __get_species(species, name):
    return list(filter(lambda specie: specie['name'] == name, species))[0]


def __write_to_file(model, path):
    with open(path, "w", encoding="utf-8") as model_file:
        json.dump(model, model_file, indent=4, sort_keys=True, cls=ComplexJsonCoder)


[docs]def export(model, path=None, return_stochss_model=False): """ GillesPy model to StochSS converter :param model: GillesPy model to be converted to StochSS :type model: gillespy.Model :param path: Path to the StochSS file for conversion :type path: str """ model.compile_prep() if path is None: path = f"{model.name}.mdl" if model.tspan is None: model_settings = {"endSim": 20, "timeStep": 0.05} elif type(model.tspan).__name__ == "TimeSpan": model_settings = { "endSim": model.tspan.items[-1], "timeStep": model.tspan.items[1] - model.tspan.items[0] } else: model_settings = { "endSim": model.tspan[-1], "timeStep": model.tspan[1] - model.tspan[0] } s_model = { "is_spatial": False, "defaultID": 1, "annotation": "", "volume": model.volume, "modelSettings": model_settings, "species": [], "initialConditions": [], "parameters": [], "reactions": [], "rules": [], "eventsCollection": [], "functionDefinitions": [] } __add_species(model=s_model, species=model.get_all_species()) __add_parameters(model=s_model, parameters=model.get_all_parameters()) __add_reactions(model=s_model, reactions=model.get_all_reactions()) __add_events(model=s_model, events=model.get_all_events()) __add_rules(model=s_model, r_type='Rate Rule', rules=model.get_all_rate_rules()) __add_rules(model=s_model, r_type='Assignment Rule', rules=model.get_all_assignment_rules()) __add_function_definitions(model=s_model, function_definitions=model.get_all_function_definitions()) if return_stochss_model: return s_model __write_to_file(model=s_model, path=path) return path