Пример #1
0
def gotran2latex(filename, params):
    """
    Create LaTeX code from a gotran model
    """

    if not params.sympy_contraction:
        # A hack to avoid sympy contractions
        # import gotran.codegeneration.avoidsympycontractions
        pass

    # Load Gotran model
    ode = load_ode(filename)

    # Check for completeness
    # TODO: Should raise a more descriptive exception?
    if not ode.is_complete:
        raise Exception("Incomplete ODE")

    params.output = (
        params.output or Path(filename).with_name(f"{ode.name}.tex").as_posix()
    )

    # Create a gotran -> LaTeX document generator
    gen = LatexCodeGenerator(ode, params)

    info("")
    info(f"Generating LaTeX files for the {ode.name} ode...")
    with open(gen.output_file, "w") as f:
        f.write(gen.generate())
    info("  done.")
def gotran2dolfin(filename, params):
    """
    Create ufl code from a gotran model
    """

    # Load Gotran model
    ode = load_ode(filename)

    # Create a ufl based model code generator
    code_gen = DOLFINCodeGenerator(params)

    output = params.output

    if output:
        if not output.endswith(".py"):
            output += ".py"
    else:
        output = filename.replace(".ode", "") + ".py"

    f = open(output, "w")
    f.write("from __future__ import division\n\n")
    f.write(code_gen.init_states_code(ode) + "\n\n")
    f.write(code_gen.init_parameters_code(ode) + "\n\n")
    f.write(
        code_gen.function_code(
            rhs_expressions(ode, params=code_gen.params.code)) + "\n", )
def gotran2matlab(filename, params):
    """
    Create a matlab code from a gotran model
    """

    timer = Timer(f"Generate Matlab code from {filename}")  # noqa: F841

    # Load Gotran model
    ode = load_ode(filename)

    gen = MatlabCodeGenerator(params)

    info("")
    info(f"Generating Matlab files for the {ode.name} ode...")

    # Collect monitored
    if params.functions.monitored.generate:
        monitored = [expr.name for expr in ode.intermediates + ode.state_expressions]
    else:
        monitored = None

    for function_name, code in list(gen.code_dict(ode, monitored).items()):
        open(f"{ode.name}_{function_name}.m", "w").write(code)

    info("  done.")
Пример #4
0
def gotran2cuda(filename, params):
    """
    Create a CUDA file from a gotran model
    """

    # Load Gotran model
    ode = load_ode(filename)

    # Create a C code generator
    gen = CUDACodeGenerator(params)

    output = params.output

    if output:
        if not output.endswith(".cu"):
            output += ".cu"
    else:
        output = filename.replace(".ode", "") + ".cu"

    info("")
    info(f"Generating CUDA code for the {ode.name} ode...")
    code = gen.module_code(ode)
    info("  done.")
    with open(output, "w") as f:
        if params.system_headers:
            f.write("#include <math.h>\n")
            f.write("#include <string.h>\n")

        f.write(code)

    if params.list_timings:
        list_timings()
Пример #5
0
def gotranprobe(filename, params):

    set_log_level(WARNING)
    ode = load_ode(filename)
    set_log_level(INFO)

    if params.flat_view:
        print()
        print(f"  Components({len(ode.components)}):")
        print(join_indent_and_split([comp.name for comp in ode.components]))
        print()
        print(f"  States({len(ode.full_states)}):")
        print(join_indent_and_split([state.name for state in ode.full_states]))
        if len(ode.parameters) > 0:
            print()
            print(f"  Parameters({len(ode.parameters)}):")
        print(join_indent_and_split([param.name for param in ode.parameters]))
        print()
        print(f"  Intermediates({len(ode.intermediates)}): ")
        print(
            join_indent_and_split(
                [interm.name for interm in ode.intermediates]))
    else:
        for comp in ode.components:
            if comp.states or comp.parameters or comp.intermediates:
                print(f"\n  {comp.name}:")
                if comp.full_states:
                    print(
                        "    States:        ",
                        ", ".join(state.name for state in comp.full_states),
                    )
                if comp.parameters:
                    print(
                        "    Parameters:    ",
                        ", ".join(param.name for param in comp.parameters),
                    )
                if comp.intermediates:
                    print(
                        "    Intermediates: ",
                        ", ".join(interm.name
                                  for interm in comp.intermediates),
                    )
                    print(
                        "    Dependencies:  ",
                        ", ".join(
                            set(dep.name for interm in comp.intermediates
                                for dep in ode.expression_dependencies[interm]
                                if not isinstance(dep, Comment) and dep not in
                                comp.full_states + comp.parameters), ),
                    )
Пример #6
0
def gotran2py(filename, params):
    """
    Create a c header file from a gotran model
    """
    timer = Timer(f"Generate Python code from {filename}")

    # Load Gotran model
    ode = load_ode(filename)

    # Collect monitored
    if params.functions.monitored.generate:
        monitored = [
            expr.name for expr in ode.intermediates + ode.state_expressions
        ]
    else:
        monitored = None

    # Create a Python code generator
    gen = PythonCodeGenerator(
        params,
        ns=params.namespace,
        import_inside_functions=params.import_inside_functions,
    )

    output = params.output

    if output:
        if not output.endswith(".py"):
            output += ".py"
    else:
        output = filename.replace(".ode", "") + ".py"

    info("")
    info(f"Generating Python code for the {ode.name} ode...")
    if params.class_code:
        code = gen.class_code(ode, monitored=monitored)
    else:
        code = gen.module_code(ode, monitored=monitored)
    info("  done.")
    with open(output, "w") as f:
        f.write(code)

    del timer

    if params.list_timings:
        list_timings()
def gotranexport(filename, params):

    if len(params.components) == 1 and params.components[0] == "":
        error("Expected at least 1 component.")

    if params.name == "":
        error("Expected a name of the exported ODE.")

    if params.name in params.components:
        error(
            "Expected the name of the ODE to be different from the components."
        )

    sub_ode = ODE(params.name)
    sub_ode.import_ode(load_ode(filename), components=params.components)
    sub_ode.finalize()
    sub_ode.save()
Пример #8
0
def gotran2md(filename):

    filename = Path(filename)
    ode = load_ode(filename)

    parameters = make_table(
        [[f"${format_expr(p.name)}$", f"{p._repr_latex_()}"] for p in ode.parameters],
        header_names=["Name", "Value"],
    )
    states = make_table(
        [[f"${format_expr(p.name)}$", f"{p._repr_latex_()}"] for p in ode.states],
        header_names=["Name", "Value"],
    )

    expr = "\n\n".join(
        [
            f"$$\n{p._repr_latex_name()} = {p._repr_latex_expr()}\n$$"
            for p in ode.intermediates
        ],
    )

    state_expr = "\n\n".join(
        [
            f"$$\n{p._repr_latex_name()} = {p._repr_latex_expr()}\n$$"
            for p in ode.state_expressions
        ],
    )

    mdname = filename.with_suffix(".md")
    with open(mdname, "w") as f:

        f.write(
            _template.format(
                name=ode.name,
                parameters=parameters,
                states=states,
                expr=expr,
                state_expr=state_expr,
            ),
        )

    print(f"Saved to {mdname}")
Пример #9
0
def gotran2cpp(filename, params):
    """
    Create a C++ header file from a gotran model
    """

    timer = Timer(f"Generate C++ code from {filename}")

    # Load Gotran model
    ode = load_ode(filename)

    # Create a C code generator
    gen = CppCodeGenerator(params)

    output = params.output

    if output:
        if not (output.endswith(".cpp") or output.endswith(".h")):
            output += ".h"
    else:
        output = filename.replace(".ode", "") + ".h"

    info("")
    info(f"Generating C++ code for the {ode.name} ode...")
    if params.class_code:
        code = gen.class_code(ode)
    else:
        code = gen.module_code(ode)
    info("  done.")

    with open(output, "w") as f:
        if params.system_headers:
            f.write("#include <cmath>\n")
            f.write("#include <cstring>\n")
            f.write("#include <stdexcept>\n")

        f.write(code)

    del timer

    if params.list_timings:
        list_timings()
Пример #10
0
def gotran2julia(filename, params):
    """
    Create a c header file from a gotran model
    """
    timer = Timer(f"Generate Julia code from {filename}")

    # Load Gotran model
    ode = load_ode(filename)

    # Collect monitored
    if params.functions.monitored.generate:
        monitored = [
            expr.name for expr in ode.intermediates + ode.state_expressions
        ]
    else:
        monitored = None

    # Create a C code generator
    gen = JuliaCodeGenerator(params)

    output = params.output

    if output:
        if not output.endswith(".jl"):
            output += ".jl"
    else:
        output = filename.replace(".ode", "") + ".jl"

    info("")
    info(f"Generating Julia code for the {ode.name} ode...")
    code = gen.module_code(ode, monitored=monitored)
    info("  done.")
    with open(output, "w") as f:
        f.write(code)

    del timer

    if params.list_timings:
        list_timings()
Пример #11
0
def create_module(ode, path="../ode/"):
    """
    Compile a gotran ode and return the module and 
    corresponding forward method.
    """
    generation = parameters.generation.copy()

    for what_not in [
            "componentwise_rhs_evaluation", "forward_backward_subst",
            "linearized_rhs_evaluation", "lu_factorization", "jacobian"
    ]:
        generation.functions[what_not].generate = False

    solver = "rush_larsen"
    generation.solvers[solver].generate = True

    if isinstance(ode, str):
        ode = load_ode(path + ode)

    module = compile_module(ode, "c", [], generation)
    forward = getattr(module, "forward_" + solver)

    return module, forward
Пример #12
0
extract_equations = []
change_state_names = []

# params = CellMLParser.default_parameters()
# parser = CellMLParser(model, params=params)
# open(parser.name+".ode", "w").write(parser.to_gotran())
# ode = load_ode(parser.name+".ode")

for f in glob.glob("*.cellml"):
    # print
    # print f
    params = CellMLParser.default_parameters()
    parser = CellMLParser(f, params=params)
    open(parser.name + ".ode", "w").write(parser.to_gotran())
    try:
        ode = load_ode(parser.name + ".ode")
    except Exception as e:
        print("***Error: Could not load gotran model", parser.name, e)
        print()
    list_timings()
    clear_timings()
    print()

mathmlparser = parser.mathmlparser
parsed_components = parser.components
cellml = parser.cellml

cellml_namespace = cellml.tag.split("}")[0] + "}"

# Grab encapsulation grouping
encapsulations = {}
Пример #13
0
def gotranrun(filename, params):

    # Copy of default parameters
    generation = parameters.generation.copy()

    # Set body parameters
    generation.code.body.representation = params.code.body_repr
    generation.code.body.use_cse = params.code.use_cse
    generation.code.body.optimize_exprs = params.code.optimize_exprs

    # Set what code we are going to generate and not
    for what_not in [
        "componentwise_rhs_evaluation",
        "forward_backward_subst",
        "linearized_rhs_evaluation",
        "lu_factorization",
        "jacobian",
    ]:
        generation.functions[what_not].generate = False

    # Always generate code for monitored expressions
    generation.functions.monitored.generate = True

    # If scipy is used to solve we generate RHS and potentially a jacobian
    if params.solver == "scipy":
        generation.functions.rhs.generate = True
        generation.functions.jacobian.generate = params.code.generate_jacobian
    else:
        generation.solvers[params.solver].generate = True

    # Compile executeable code from gotran ode
    model_arguments = params.model_arguments
    if len(model_arguments) == 1 and model_arguments[0] == "":
        model_arguments = []

    if len(model_arguments) % 2 != 0:
        error("Expected an even number of values for 'model_arguments'")

    arguments = dict()
    for arg_name, arg_value in [
        (model_arguments[i * 2], model_arguments[i * 2 + 1])
        for i in range(int(len(model_arguments) / 2))
    ]:

        arguments[arg_name] = arg_value

    ode = load_ode(filename, **arguments)

    # Check for DAE
    if ode.is_dae:
        error(
            "Can only integrate pure ODEs. {0} includes algebraic states "
            "and is hence a DAE.".format(ode.name),
        )

    # Get monitored and plot states
    plot_states = params.plot_y

    # Get x_values
    x_name = params.plot_x

    state_names = [state.name for state in ode.full_states]
    monitored_plot = [
        plot_states.pop(plot_states.index(name))
        for name in plot_states[:]
        if name not in state_names
    ]

    monitored = []
    all_monitored_names = []
    for expr in sorted(ode.intermediates + ode.state_expressions):
        if expr.name not in monitored:
            monitored.append(expr.name)
        all_monitored_names.append(expr.name)

    # Check valid monitored plot
    for mp in monitored_plot:
        if mp not in monitored:
            error(f"{mp} is not a state or intermediate in this ODE")

    # Check x_name
    if x_name not in ["time"] + monitored + state_names:
        error(
            "Expected plot_x to be either 'time' or one of the plotable "
            "variables, got {}".format(x_name),
        )

    # Logic if x_name is not 'time' as we then need to add the name to
    # either plot_states or monitored_plot
    if x_name != "time":
        if x_name in state_names:
            plot_states.append(x_name)
        else:
            monitored_plot.append(x_name)

    module = compile_module(ode, params.code.language, monitored, generation)

    parameter_values = params.parameters
    init_conditions = params.init_conditions

    if len(parameter_values) == 1 and parameter_values[0] == "":
        parameter_values = []

    if len(init_conditions) == 1 and init_conditions[0] == "":
        init_conditions = []

    if len(parameter_values) % 2 != 0:
        error("Expected an even number of values for 'parameters'")

    if len(init_conditions) % 2 != 0:
        error("Expected an even number of values for 'initial_conditions'")

    user_params = dict()
    for param_name, param_value in [
        (parameter_values[i * 2], parameter_values[i * 2 + 1])
        for i in range(int(len(parameter_values) / 2))
    ]:

        user_params[param_name] = float(param_value)

    user_ic = dict()
    for state_name, state_value in [
        (init_conditions[i * 2], init_conditions[i * 2 + 1])
        for i in range(int(len(init_conditions) / 2))
    ]:

        user_ic[state_name] = float(state_value)

    # Use scipy to integrate model
    t0 = 0.0
    t1 = params.tstop
    dt = params.dt

    rhs = module.rhs
    jac = module.compute_jacobian if params.code.generate_jacobian else None
    y0 = module.init_state_values(**user_ic)
    model_params = module.init_parameter_values(**user_params)

    # Check for steady state solve
    if params.steady_state.solve and root:
        result = root(
            rhs,
            y0,
            args=(0.0, model_params),
            jac=jac,
            method=params.steady_state.method,
            tol=params.steady_state.tol,
        )

        if result.success:
            y0 = result.x
            print(
                "Found stead state:",
                ", ".join(
                    f"{state.name}: {value:e}"
                    for value, state in zip(y0, ode.full_states)
                ),
            )
        else:
            warning(result.message)

    tsteps = np.linspace(t0, t1, int(t1 / dt) + 1)

    # What solver should we use
    if params.solver == "scipy":
        try:
            from scipy.integrate import odeint
        except Exception as e:
            error(f"Problem importing scipy.integrate.odeint. {e}")
        results = odeint(rhs, y0, tsteps, Dfun=jac, args=(model_params,))

    else:

        # Get generated forward method
        forward = getattr(module, "forward_" + params.solver)

        results = [y0]
        states = y0.copy()

        # Integrate solution using generated forward method
        for ind, t in enumerate(tsteps[:-1]):

            # Step solver
            forward(states, t, dt, model_params)
            results.append(states.copy())

    # Plot results
    if not (plot_states or monitored or params.save_results):
        return

    # allocate memory for saving results
    if params.save_results:
        save_results = np.zeros(
            (len(results), 1 + len(state_names) + len(all_monitored_names)),
        )
        all_monitor_inds = np.array(
            [monitored.index(monitor) for monitor in all_monitored_names],
            dtype=int,
        )
        all_results_header = ", ".join(["time"] + state_names + all_monitored_names)

    plot_inds = [module.state_indices(state) for state in plot_states]

    monitor_inds = np.array(
        [monitored.index(monitor) for monitor in monitored_plot],
        dtype=int,
    )
    monitored_get_values = np.zeros(len(monitored), dtype=np.float_)

    # Allocate memory
    plot_values = np.zeros((len(plot_states) + len(monitored_plot), len(results)))

    for ind, (time, res) in enumerate(zip(tsteps, results)):

        if plot_states:
            plot_values[: len(plot_states), ind] = res[plot_inds]
        if monitored_plot or params.save_results:
            module.monitor(res, time, model_params, monitored_get_values)
        if monitored_plot:
            plot_values[len(plot_states) :, ind] = monitored_get_values[monitor_inds]
        if params.save_results:
            save_results[ind, 0] = time
            save_results[ind, 1 : len(state_names) + 1] = res
            save_results[ind, len(state_names) + 1 :] = monitored_get_values[
                all_monitor_inds
            ]

    # Save data
    if params.save_results:
        np.savetxt(
            f"{params.basename}.csv",
            save_results,
            header=all_results_header,
            delimiter=", ",
        )

    # Plot data

    if not (plot_states + monitored_plot):
        return

    # Fixes for derivatives
    monitored_plot_updated = []
    for monitor in monitored_plot:
        expr, what = special_expression(monitor, ode)
        if what == DERIVATIVE_EXPRESSION:
            var, dep = expr.groups()
            if var in ode.present_ode_objects and dep in ode.present_ode_objects:
                monitored_plot_updated.append(f"d{var}/d{dep}")
            else:
                monitored_plot_updated.append(monitor)
        else:
            monitored_plot_updated.append(monitor)

    plot_items = plot_states + monitored_plot
    if x_name != "time":
        x_values = plot_values[plot_items.index(x_name)]
    else:
        x_values = tsteps

    plt.rcParams["lines.linewidth"] = 2
    # line_styles = cycle([c+s for s in ["-", "--", "-.", ":"]
    # for c in plt.rcParams["axes.color_cycle"]])
    line_styles = cycle(
        [
            c + s
            for s in ["-", "--", "-.", ":"]
            for c in ["b", "g", "r", "c", "m", "y", "k"]
        ],
    )

    plotted_items = 0
    for what, values in zip(plot_items, plot_values):
        if what == x_name:
            continue
        plotted_items += 1

        plt.plot(x_values, values, next(line_styles))

    if plotted_items > 1:
        plt.legend([f"$\\mathrm{{{latex(value)}}}$" for value in plot_items])
    elif plot_items:
        plt.ylabel(f"$\\mathrm{{{latex(plot_items[0])}}}$")

    plt.xlabel(f"$\\mathrm{{{latex(x_name)}}}$")
    plt.title(ode.name.replace("_", "\\_"))
    plt.show()
Пример #14
0
    def import_ode(self, ode, prefix="", components=None, **arguments):
        """
        Import a Model into the present Model

        Arguments
        ---------
        ode : str, gotran.ODE
            The ode which should be added. If ode is a str an
            ODE stored in that file will be loaded. If it is an ODE it will be
            added directly to the present ODE.
        prefix : str (optional)
            A prefix which all state, parameters and intermediates are
            prefixed with.
        components : list, tuple of str (optional)
            A list of components which will either be extracted or excluded
            from the imported model. If not given the whole ODE will be imported.
        arguments : dict (optional)
            Optional arguments which can control loading of model
        """

        timer = Timer("Import ode")  # noqa: F841

        components = components or []
        check_arg(ode, (str, Path, ODE), 0, context=ODE.import_ode)
        check_arg(prefix, str, 1, context=ODE.import_ode)
        check_arg(components, list, 2, context=ODE.import_ode, itemtypes=str)

        # If ode is given directly
        if isinstance(ode, (str, Path)):
            # If not load external ODE
            from gotran.model.loadmodel import load_ode

            ode = load_ode(ode, **arguments)

        # Postfix prefix with "_" if prefix is not ""
        if prefix and prefix[-1] != "_":
            prefix += "_"

        # If extracting only a certain components
        if components:
            ode = ode.extract_components(ode.name, *components)

        # Subs for expressions
        subs = {}
        old_new_map = {ode: self}

        def add_comp_and_children(added, comp):
            "Help function to recursively add components to ode"

            # Add states and parameters
            for obj in comp.ode_objects:

                # Check if obj already excists as a ODE parameter
                old_obj = self.present_ode_objects.get(str(obj))

                if old_obj and self.object_component[old_obj] == self:
                    new_name = obj.name
                else:
                    new_name = prefix + obj.name

                if isinstance(obj, State):
                    subs[obj.sym] = added.add_state(new_name, obj.param)

                elif isinstance(obj, Parameter):

                    # If adding an ODE parameter
                    if comp == ode:

                        # And parameter name already excists in the present ODE
                        if str(obj) in self.present_ode_objects:

                            # Skip it and add the registered symbol for
                            # substitution
                            subs[obj.sym] = self.present_ode_objects[str(
                                obj)].sym

                        else:

                            # If not already present just add unprefixed name
                            subs[obj.sym] = added.add_parameter(
                                obj.name, obj.param)

                    else:

                        subs[obj.sym] = added.add_parameter(
                            new_name, obj.param)

            # Add child components
            for child in list(comp.children.values()):
                added_child = added.add_component(child.name)

                # Get corresponding component in present ODE
                old_new_map[child] = added_child

                add_comp_and_children(added_child, child)

        # Recursively add states and parameters
        add_comp_and_children(self, ode)

        # Iterate over all components to add expressions
        for comp_name in ode.all_expr_components_ordered:

            comp = ode.all_components[comp_name]

            comp_comment = f"Expressions for the {comp.name} component"

            # Get corresponding component in new ODE
            added = old_new_map[comp]

            # Iterate over all objects of the component and save only expressions
            # and comments
            for obj in comp.ode_objects:

                # If saving an expression
                if isinstance(obj, Expression):

                    # The new sympy expression
                    new_expr = obj.expr.xreplace(subs)

                    # If the component is a Markov model
                    if comp.rates:

                        # Do not save State derivatives
                        if isinstance(obj, StateDerivative):
                            continue

                        # Save rate expressions slightly different
                        elif isinstance(obj, RateExpression):

                            states = obj.states
                            added._add_single_rate(
                                subs[states[0].sym],
                                subs[states[1].sym],
                                new_expr,
                            )
                            continue

                    # If no prefix we just add the expression by using setattr
                    # magic
                    if prefix == "":
                        setattr(added, str(obj), new_expr)
                        subs[obj.sym] = added.ode_objects.get(obj.name).sym

                    elif isinstance(obj, (StateExpression, StateSolution)):

                        state = subs[obj.state.sym]

                        if isinstance(obj, AlgebraicExpression):
                            subs[obj.sym] = added.add_algebraic(
                                state, new_expr)

                        elif isinstance(obj, StateDerivative):
                            subs[obj.sym] = added.add_derivative(
                                state,
                                added.t,
                                new_expr,
                            )

                        elif isinstance(obj, StateSolution):
                            subs[obj.sym] = added.add_state_solution(
                                state, new_expr)
                            print(repr(obj), obj.sym)
                        else:
                            error("Should not reach here...")

                    # Derivatives are tricky. Here the der expr and dep var
                    # need to be registered in the ODE already. But they can
                    # be registered with and without prefix, so we need to
                    # check that.
                    elif isinstance(obj, Derivatives):

                        # Get der_expr
                        der_expr = self.root.present_ode_objects.get(
                            obj.der_expr.name)

                        if der_expr is None:

                            # If not found try prefixed version
                            der_expr = self.root.present_ode_objects.get(
                                prefix + obj.der_expr.name, )

                            if der_expr is None:
                                if prefix:
                                    error(
                                        "Could not find expression: "
                                        "({0}){1} while adding "
                                        "derivative".format(
                                            prefix, obj.der_expr), )
                                else:
                                    error(
                                        "Could not find expression: "
                                        "{0} while adding derivative".format(
                                            obj.der_expr, ), )

                        dep_var = self.root.present_ode_objects.get(
                            obj.dep_var.name)

                        if isinstance(dep_var, Time):
                            dep_var = self._time

                        elif dep_var is None:

                            # If not found try prefixed version
                            dep_var = self.root.present_ode_objects.get(
                                prefix + obj.dep_var.name, )

                            if dep_var is None:
                                if prefix:
                                    error(
                                        "Could not find expression: "
                                        "({0}){1} while adding "
                                        "derivative".format(
                                            prefix, obj.dep_var), )
                                else:
                                    error(
                                        "Could not find expression: "
                                        "{0} while adding derivative".format(
                                            obj.dep_var, ), )

                        subs[obj.sym] = added.add_derivative(
                            der_expr,
                            dep_var,
                            new_expr,
                        )

                    elif isinstance(obj, Intermediate):

                        subs[obj.sym] = added.add_intermediate(
                            prefix + obj.name,
                            new_expr,
                        )

                    else:
                        error("Should not reach here!")

                # If saving a comment
                elif isinstance(obj, Comment) and str(obj) != comp_comment:
                    added.add_comment(str(obj))