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
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)
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
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