def _init_arguments(self, comp, default_arguments=None):

        check_arg(comp, CodeComponent)
        params = self.params.code
        default_arguments = default_arguments or params.default_arguments

        # Check if comp defines used_states if not use the root components
        # full_states attribute
        # FIXME: No need for full_states here...
        states = [state.name for state in comp.root.full_states]
        parameters = comp.root.parameters
        used_parameters = comp.used_parameters

        num_states = comp.root.num_full_states
        num_parameters = comp.root.num_parameters

        # Start building body
        body_lines = []
        body_lines.append("time = time if time else Constant(0.0)")
        body_lines.append("")
        body_lines.append("# Assign states")
        if self.V_name != "v":
            body_lines.append("{0} = v".format(self.V_name))

        state_names = [state for state in states if state != self.V_name]
        if len(states) == 1:
            if states[0] != "s":
                body_lines.append("{0} = s".format(states[0]))
        else:
            body_lines.append("assert(len(s) == {0})".format(num_states - 1))
            body_lines.append(", ".join(state_names) + " = s")
        body_lines.append("")

        body_lines.append("# Assign parameters")
        for param in used_parameters:
            body_lines.append("{0} = self._parameters["\
                              "\"{1}\"]".format(param.name, param.name))

        # If initilizing results
        if comp.results:
            body_lines.append("")
            body_lines.append("# Init return args")

        for result_name in comp.results:
            shape = comp.shapes[result_name]
            if len(shape) > 1:
                error("expected only result expression with rank 1")

            body_lines.append("{0} = [ufl.zero()]*{1}".format(\
                result_name, shape[0]))

        return body_lines
Beispiel #2
0
    def function_code(self, comp, indent=0, default_arguments=None, \
                      include_signature=True):

        default_arguments = default_arguments or \
                            self.params.code.default_arguments

        check_arg(comp, CodeComponent)
        check_kwarg(default_arguments, "default_arguments", str)
        check_kwarg(indent, "indent", int)

        body_lines = self._init_arguments(comp, default_arguments)

        # Iterate over any body needed to define the dy
        for expr in comp.body_expressions:
            if isinstance(expr, Comment):
                body_lines.append("")
                body_lines.append("# " + str(expr))
            else:
                body_lines.append(self.to_code(expr.expr, expr.name))

        if comp.results:
            body_lines.append("")
            body_lines.append("# Return results")
            body_lines.append("return {0}".format(", ".join(\
                ("{0}[0]" if comp.shapes[result_name][0] == 1 \
                 else "dolfin.as_vector({0})").format(result_name) \
                 for result_name in comp.results)))

        if include_signature:

            # Add function prototype
            body_lines = self.wrap_body_with_function_prototype(\
                body_lines, comp.function_name, \
                self.args(default_arguments), \
                comp.description, self.decorators())

        return "\n".join(self.indent_and_split_lines(body_lines,
                                                     indent=indent))
    def __init__(self, ode, membrane_potential):

        # Init base class
        super(CellModelGenerator, self).__init__()

        check_arg(ode, ODE, 0)
        check_arg(membrane_potential, str, 1)

        assert (not ode.is_dae)

        # Capitalize first letter of name
        name = ode.name
        self.name = name if name[0].isupper() else name[0].upper() + \
                    (name[1:] if len(name) > 1 else "")

        # Set cbcbeat compatible gotran code generation parameters
        generation_params = gotran_parameters.generation.copy()
        generation_params.code.default_arguments = "stp"
        generation_params.code.time.name = "time"

        generation_params.code.array.index_format = "[]"
        generation_params.code.array.index_offset = 0

        generation_params.code.parameters.representation = "named"
        generation_params.code.parameters.array_name = "parameters"
        generation_params.code.states.representation = "named"
        generation_params.code.states.array_name = "states"
        generation_params.code.body.representation = "named"
        generation_params.code.body.use_cse = False

        if ode.num_full_states < 2:
            gotran_error("expected the ODE to have at least more than 1 state")

        # Check that ode model has the membrane potential state name
        if membrane_potential not in ode.present_ode_objects:
            gotran_error("Cannot find the membrane potential. ODE does not "\
                         "contain a state with name '{0}'".format(\
                             membrane_potential))

        state = ode.present_ode_objects[membrane_potential]
        if not isinstance(state, gotran.model.State):
            gotran_error("Cannot find the membrane potential. ODE does not "\
                         "contain a state with name '{0}'".format(\
                             membrane_potential))

        # The name of the membrane potential
        self.V_name = state.name

        # Get the I and F expressions
        I_ind = [ind for ind, expr in enumerate(ode.state_expressions) \
                 if expr.state.name == self.V_name][0]

        # Create gotran code component for I(s,t) (dV/dt)
        I_comp = componentwise_derivative(ode, I_ind, \
                                          generation_params.code,
                                          result_name="current")

        # Create gotran code component for F(s,t) (dS/dt)
        F_inds = list(range(ode.num_full_states))
        F_inds.remove(I_ind)
        F_comp = componentwise_derivative(ode, F_inds, \
                                          generation_params.code, \
                                          result_name="F_expressions")

        # Create the class form and start fill it
        self._class_form = _class_form.copy()
        self._class_form["I_body"] = self.function_code(
            I_comp, indent=2, include_signature=False)
        self._class_form["F_body"] = self.function_code(
            F_comp, indent=2, include_signature=False)
        self._class_form["num_states"] = ode.num_full_states - 1
        self._class_form["ModelName"] = self.name
        self._class_form["default_parameters"] = self.default_parameters_body(
            ode)
        self._class_form["initial_conditions"] = self.initial_conditions_body(
            ode)
Beispiel #4
0
    def __init__(self,
                 ode,
                 field_states=None,
                 field_parameters=None,
                 monitored=None,
                 code_params=None):
        """
        A class for generating a C++ subclass of a goss::ODEParameterized
        
        Arguments:
        ----------
        ode : gotran.ODE
            The gotran ode
        field_states : list
            A list of state names, which should be treated as field states
        field_parameters : list
            A list of parameter names, which should be treated as field parameters
        monitored : list
            A list of names of intermediates of the ODE. Code for monitoring
            the intermediates will be generated.
        code_params : dict
            Parameters controling the code generation
        """

        field_states = field_states or []
        field_parameters = field_parameters or []
        monitored = monitored or []
        code_params = code_params or {}

        check_arg(ode, ODE)
        check_kwarg(field_states, "field_states", list, itemtypes=str)
        check_kwarg(field_parameters, "field_parameters", list, itemtypes=str)
        check_kwarg(monitored, "monitored", list, itemtypes=str)
        check_kwarg(code_params, "code_params", dict)

        state_strs = [state.name for state in ode.full_states]
        for state_str in field_states:
            if not state_str in state_strs:
                error("{0} is not a state in the {1} ODE".format(
                    state_str, ode))

        parameter_strs = [param.name for param in ode.parameters]
        for parameter_str in field_parameters:
            if not parameter_str in parameter_strs:
                error("{0} is not a parameter in the {1} ODE".format(\
                    parameter_str, ode))

        for expr_str in monitored:
            obj = ode.present_ode_objects.get(expr_str)
            if not isinstance(obj, Expression):
                error("{0} is not an expression in the {1} ODE".format(\
                    expr_str, ode))

        params = GossCodeGenerator.default_parameters()
        params.update(code_params)

        # Get a whole set of gotran code parameters and update with goss
        # specific options
        generation_params = parameters.generation.copy()
        generation_params.code.default_arguments = "st"
        generation_params.code.time.name = "time"

        generation_params.code.array.index_format = "[]"
        generation_params.code.array.index_offset = 0
        generation_params.code.array.flatten = True

        generation_params.code.parameters.representation = "named"

        generation_params.code.states.representation = params.state_repr
        generation_params.code.states.array_name = "states"

        generation_params.code.body.array_name = "body"
        generation_params.code.body.representation = params.body_repr
        generation_params.code.body.use_cse = params.use_cse
        generation_params.code.body.optimize_exprs = params.optimize_exprs
        generation_params.functions.jacobian.generate = params.generate_jacobian
        generation_params.functions.lu_factorization.generate = \
                                        params.generate_lu_factorization
        generation_params.functions.forward_backward_subst.generate = \
                                        params.generate_forward_backward_subst

        # Init base class
        super(GossCodeGenerator, self).__init__()

        # Store attributes
        self.params = generation_params
        self.file_form = _file_form.copy()
        self.class_form = _class_form.copy()
        name = ode.name

        self.name = name if name[0].isupper() else name[0].upper() + \
                    (name[1:] if len(name) > 1 else "")

        self.ode = ode
        self.field_states = field_states
        self.field_parameters = field_parameters
        self.monitored = monitored

        # Fill the forms with content
        self.file_form["MODELNAME"] = name.upper()
        self.class_form["ModelName"] = self.name
        self.class_form["num_states"] = ode.num_full_states
        self.class_form["num_parameters"] = ode.num_parameters
        self.class_form["num_field_states"] = len(field_states)
        self.class_form["num_field_parameters"] = len(field_parameters)
        self.class_form["num_monitored"] = len(monitored)
        self.class_form["monitored_evaluation_code"] = \
                    _no_monitored_snippet.format(ode.name.capitalize()) + "\n"
        self._code_generated = False
Beispiel #5
0
    def _init_arguments(self, comp, default_arguments=None):

        check_arg(comp, CodeComponent)
        params = self.params.code
        default_arguments = default_arguments or params.default_arguments

        # Check if comp defines used_states if not use the root components
        # full_states attribute
        # FIXME: No need for full_states here...
        states = comp.root.full_states
        parameters = comp.root.parameters

        num_states = comp.root.num_full_states
        num_parameters = comp.root.num_parameters

        # Start building body
        body_lines = ["# Imports", "import ufl", "import dolfin"]

        if "s" in default_arguments and states:
            
            states_name = params.states.array_name
            body_lines.append("")
            body_lines.append("# Assign states")
            body_lines.append("assert(isinstance({0}, dolfin.Function))"\
                              .format(states_name))
            body_lines.append("assert(states.function_space().depth() == 1)")
            body_lines.append("assert(states.function_space().num_sub_spaces() "\
                              "== {0})".format(num_states))

            # Generate state assign code
            if params.states.representation == "named":
                
                body_lines.append(", ".join(state.name for state in states) + \
                                  " = dolfin.split({0})".format(states_name))
        
        # Add parameters code if not numerals
        if "p" in default_arguments and params.parameters.representation \
               in ["named", "array"]:

            parameters_name = params.parameters.array_name
            body_lines.append("")
            body_lines.append("# Assign parameters")
            body_lines.append("assert(isinstance({0}, (dolfin.Function, "\
                              "dolfin.Constant)))".format(parameters_name))
            body_lines.append("if isinstance({0}, dolfin.Function):".format(\
                parameters_name))
            if_closure = []
            if_closure.append("assert({0}.function_space().depth() == 1)"\
                              .format(parameters_name))
            if_closure.append("assert({0}.function_space().num_sub_spaces() "\
                              "== {1})".format(parameters_name, num_parameters))
            body_lines.append(if_closure)
            body_lines.append("else:")
            body_lines.append(["assert({0}.value_size() == {1})".format(\
                parameters_name, num_parameters)])

            # Generate parameters assign code
            if params.parameters.representation == "named":
                
                body_lines.append(", ".join(param.name for param in \
                parameters) + " = dolfin.split({0})".format(parameters_name))

        # If initilizing results
        if comp.results:
            body_lines.append("")
            body_lines.append("# Init return args")
            
        for result_name in comp.results:
            shape = comp.shapes[result_name]
            if len(shape) > 1:
                error("expected only result expression with rank 1")

            body_lines.append("{0} = [ufl.zero()]*{1}".format(\
                result_name, shape[0]))
            
        return body_lines