def build_event_connections(self, component, runnable, structure): """ Adds event connections to a runnable component based on the structure specifications in the component model. @param component: Component model containing structure specifications. @type component: lems.model.component.FatComponent @param runnable: Runnable component to which structure is to be added. @type runnable: lems.sim.runnable.Runnable @param structure: The structure object to be used to add structure code in the runnable component. @type structure: lems.model.structure.Structure """ if self.debug: print("\n++++++++ Calling build_event_connections of %s with runnable %s, parent %s"%(component.id, runnable.id, runnable.parent)) # Process event connections for ec in structure.event_connections: if self.debug: print(ec.toxml()) source = runnable.parent.resolve_path(ec.from_) target = runnable.parent.resolve_path(ec.to) if ec.receiver: receiver_template = self.build_runnable(ec.receiver, target) #receiver = copy.deepcopy(receiver_template) receiver = receiver_template.copy() receiver.id = "{0}__{1}__".format(component.id, receiver_template.id) if ec.receiver_container: target.add_attachment(receiver, ec.receiver_container) target.add_child(receiver_template.id, receiver) target = receiver else: source = runnable.resolve_path(ec.from_) target = runnable.resolve_path(ec.to) source_port = ec.source_port target_port = ec.target_port if not source_port: if len(source.event_out_ports) == 1: source_port = source.event_out_ports[0] else: raise SimBuildError(("No source event port " "uniquely identifiable" " in '{0}'").format(source.id)) if not target_port: if len(target.event_in_ports) == 1: target_port = target.event_in_ports[0] else: raise SimBuildError(("No destination event port " "uniquely identifiable " "in '{0}'").format(target)) if self.debug: print("register_event_out_callback\n Source: %s, %s (port: %s) \n -> %s, %s (port: %s)"%(source, id(source), source_port, target, id(target), target_port)) source.register_event_out_callback(\ source_port, lambda: target.inc_event_in(target_port))
def build_foreach(self, component, runnable, foreach, name_mappings = {}): """ Iterate over ForEach constructs and process nested elements. @param component: Component model containing structure specifications. @type component: lems.model.component.FatComponent @param runnable: Runnable component to which structure is to be added. @type runnable: lems.sim.runnable.Runnable @param foreach: The ForEach structure object to be used to add structure code in the runnable component. @type foreach: lems.model.structure.ForEach """ if self.debug: print("\n++++++++ Calling build_foreach of %s with runnable %s, parent %s, name_mappings: %s"%(component.id, runnable.id, runnable.parent, name_mappings)) target_array = runnable.resolve_path(foreach.instances) for target_runnable in target_array: if self.debug: print("Applying contents of for_each to %s, as %s"%(target_runnable.id, foreach.as_)) name_mappings[foreach.as_] = target_runnable # Process foreach statements for fe2 in foreach.for_eachs: #print fe2.toxml() target_array2 = runnable.resolve_path(fe2.instances) for target_runnable2 in target_array2: name_mappings[fe2.as_] = target_runnable2 self.build_foreach(component, runnable, fe2, name_mappings) # Process event connections for ec in foreach.event_connections: source = name_mappings[ec.from_] target = name_mappings[ec.to] source_port = ec.source_port target_port = ec.target_port if not source_port: if len(source.event_out_ports) == 1: source_port = source.event_out_ports[0] else: raise SimBuildError(("No source event port " "uniquely identifiable" " in '{0}'").format(source.id)) if not target_port: if len(target.event_in_ports) == 1: target_port = target.event_in_ports[0] else: raise SimBuildError(("No destination event port " "uniquely identifiable " "in '{0}'").format(target)) if self.debug: print("register_event_out_callback\n Source: %s, %s (port: %s) \n -> %s, %s (port: %s)"%(source, id(source), source_port, target, id(target), target_port)) source.register_event_out_callback(\ source_port, lambda: target.inc_event_in(target_port))
def add_variable_recorder2(self, data_output, recorder, path, full_path): if path[0] == '/': self.parent.add_variable_recorder2(data_output, recorder, path, full_path) elif path.find('../') == 0: self.parent.add_variable_recorder2(data_output, recorder, path[3:], full_path) elif path.find('/') >= 1: (child, new_path) = path.split('/', 1) if ':' in child: syn_parts = child.split(":") if syn_parts[0] == 'synapses' and syn_parts[2] == '0': child = syn_parts[1] else: raise SimBuildError( 'Cannot determine what to do with (synapse?) path: %s (full path: %s)' % (child, full_path)) idxbegin = child.find('[') idxend = child.find(']') if idxbegin != 0 and idxend > idxbegin: idx = int(child[idxbegin + 1:idxend]) child = child[:idxbegin] else: idx = -1 if child in self.children: childobj = self.children[child] if idx == -1: childobj.add_variable_recorder2(data_output, recorder, new_path, full_path) else: childobj.array[idx].add_variable_recorder2( data_output, recorder, new_path, full_path) elif child in self.component.children: cdef = self.component.children[child] childobj = None for cid in self.children: c = self.children[cid] if cdef.type in c.component.types: childobj = c if childobj: childobj.add_variable_recorder2(data_output, recorder, new_path) else: raise SimBuildError('Unable to find the child \'{0}\' in ' '\'{1}\''.format(child, self.id)) else: raise SimBuildError('Unable to find a child \'{0}\' in ' '\'{1}\''.format(child, self.id)) else: self.recorded_variables.append( Recording(path, full_path, data_output, recorder))
def get_numeric_value(self, value_str, dimension=None): """ Get the numeric value for a parameter value specification. @param value_str: Value string @type value_str: str @param dimension: Dimension of the value @type dimension: str """ n = None i = len(value_str) while n is None: try: part = value_str[0:i] nn = float(part) n = nn s = value_str[i:] except ValueError: i = i - 1 number = n sym = s numeric_value = None if sym == '': numeric_value = number else: if sym in self.units: unit = self.units[sym] if dimension: if dimension != unit.dimension and dimension != '*': raise SimBuildError( "Unit symbol '{0}' cannot " "be used for dimension '{1}'", sym, dimension) else: dimension = unit.dimension numeric_value = (number * (10**unit.power) * unit.scale) + unit.offset else: raise SimBuildError("Unknown unit symbol '{0}'. Known: {1}", sym, self.units) #print("Have converted %s to value: %s, dimension %s"%(value_str, numeric_value, dimension)) return numeric_value
def add_recording_behavior(self, component, runnable, behavior_profile): """ Adds recording-related behavior to a runnable component based on the behavior specifications in the component model. @param component: Component model containing behavior specifications. @type component: lems.model.component.Component @param runnable: Runnable component to which behavior is to be added. @type runnable: lems.sim.runnable.Runnable @param behavior_profile: The behavior profile to be used to generate behavior code in the runnable component. @type behavior_profile: lems.model.behavior.Behavior @raise SimBuildError: Raised when a target for recording could not be found. """ context = component.context regime = behavior_profile.default_regime for rn in regime.records: rec = regime.records[rn] if self.current_record_target == None: raise SimBuildError('No target available for ' 'recording variables') self.current_record_target.add_variable_recorder(rec.quantity)
def add_variable_recorder(self, path): if path[0] == '/': self.parent.add_variable_recorder(path) elif path.find('../') == 0: self.parent.add_variable_recorder(path[3:]) elif path.find('/') >= 1: (child, new_path) = path.split('/', 1) idxbegin = child.find('[') idxend = child.find(']') if idxbegin != 0 and idxend > idxbegin: idx = int(child[idxbegin + 1:idxend]) child = child[:idxbegin] else: idx = -1 if child in self.children: childobj = self.children[child] if idx == -1: childobj.add_variable_recorder(new_path) else: childobj.array[idx].add_variable_recorder(new_path) else: raise SimBuildError('Unable to find child \'{0}\' in ' '\'{1}\''.format(child, self.id)) else: self.recorded_variables[path] = []
def add_variable_recorder2(self, data_output, recorder, path, full_path): if path[0] == '/': self.parent.add_variable_recorder2(data_output, recorder, path, full_path) elif path.find('../') == 0: self.parent.add_variable_recorder2(data_output, recorder, path[3:], full_path) elif path.find('/') >= 1: (child, new_path) = path.split('/', 1) idxbegin = child.find('[') idxend = child.find(']') if idxbegin != 0 and idxend > idxbegin: idx = int(child[idxbegin + 1:idxend]) child = child[:idxbegin] else: idx = -1 if child in self.children: childobj = self.children[child] if idx == -1: childobj.add_variable_recorder2(data_output, recorder, new_path, full_path) else: childobj.array[idx].add_variable_recorder2( data_output, recorder, new_path, full_path) elif child in self.component.children: cdef = self.component.children[child] childobj = None for cid in self.children: c = self.children[cid] if cdef.type in c.component.types: childobj = c if childobj: childobj.add_variable_recorder2(data_output, recorder, new_path) else: raise SimBuildError('Unable to find child \'{0}\' in ' '\'{1}\''.format(child, self.id)) else: raise SimBuildError('Unable to find child \'{0}\' in ' '\'{1}\''.format(child, self.id)) else: self.recorded_variables.append( Recording(path, full_path, data_output, recorder))
def add_event_connection(self, runnable, from_component, from_port, to_component, to_port): if from_component in runnable.children: from_ = runnable.children[from_component] else: raise SimBuildError('Unable to find component \'{0}\' ' 'under \'{1}\''.format(\ from_component, runnable.id)) if to_component in runnable.children: to = runnable.children[to_component] else: raise SimBuildError('Unable to find component \'{0}\' ' 'under \'{1}\''.format(\ to_component, runnable.id)) from_.register_event_out_callback(\ from_port, lambda: to.inc_event_in(to_port))
def register_event_out_callback(self, port, callback): if self.debug: print("register_event_out_callback on %s, port: %s, callback: %s" % (self.id, port, callback)) if port in self.event_out_callbacks: self.event_out_callbacks[port].append(callback) else: raise SimBuildError('No event out port \'{0}\' in ' 'component \'{1}\''.format(port, self.id)) if self.debug: print("EOC: " + str(self.event_out_callbacks))
def add_attachment(self, runnable, container=None): for ctype in runnable.component.types: if ctype in self.attachments: name = self.attachments[ctype] if container is not None and container != name: continue if name not in self.__dict__: raise SimBuildError( 'Cannot attach {0} to {1} in {2}'.format( runnable.id, name, self.id)) runnable.id = runnable.id + str(len(self.__dict__[name])) self.__dict__[name].append(runnable) runnable.parent = self return raise SimBuildError( 'Unable to find appropriate attachment for {0} in {1}', runnable.id, self.id)
def order_derived_parameters(component): """ Finds ordering of derived_parameters. @param component: Component containing derived parameters. @type component: lems.model.component.Component @return: Returns ordered list of derived parameters. @rtype: list(string) @raise SimBuildError: Raised when a proper ordering of derived parameters could not be found. """ if len(component.derived_parameters) == 0: return [] ordering = [] dps = [] for dp in component.derived_parameters: dps.append(dp.name) maxcount = 5 count = maxcount while count > 0 and dps != []: count = count - 1 for dp1 in dps: #exp_tree = regime.derived_variables[dv1].expression_tree value = component.derived_parameters[dp1].value found = False for dp2 in dps: if dp1 != dp2 and dp2 in value: found = True if not found: ordering.append(dp1) del dps[dps.index(dp1)] count = maxcount break if count == 0: raise SimBuildError(("Unable to find ordering for derived " "parameter in component '{0}'").format(component)) #return ordering + dvsnoexp return ordering
def build(self): """ Build the simulation components from the model. @return: A runnable simulation object @rtype: lems.sim.sim.Simulation """ self.sim = Simulation() for component_id in self.model.targets: if component_id not in self.model.components: raise SimBuildError("Unable to find target component '{0}'", component_id) component = self.model.fat_components[component_id] runnable = self.build_runnable(component) self.sim.add_runnable(runnable) return self.sim
def build(self): """ Build the simulation components from the model. @return: A runnable simulation object @rtype: lems.sim.sim.Simulation """ self.sim = Simulation() for component_id in self.model.default_runs: if component_id not in self.model.context.components: raise SimBuildError('Unable to find component \'{0}\' to run'\ .format(component_id)) component = self.model.context.components[component_id] runnable = self.build_runnable(component) self.sim.add_runnable(component.id, runnable) return self.sim
def build_expression_from_tree(self, runnable, regime, tree_node): """ Recursively builds a Python expression from a parsed expression tree. @param runnable: Runnable object to which this expression would be added. @type runnable: lems.sim.runnable.Runnable @param regime: Dynamics regime being built. @type regime: lems.model.dynamics.Regime @param tree_node: Root node for the tree from which the expression is to be built. @type tree_node: lems.parser.expr.ExprNode @return: Generated Python expression. @rtype: string """ component_type = self.model.component_types[runnable.component.type] dynamics = component_type.dynamics if tree_node.type == ExprNode.VALUE: if tree_node.value[0].isalpha(): if tree_node.value == 't': return 'self.time_completed' elif tree_node.value in component_type.requirements: var_prefix = 'self' v = tree_node.value r = runnable while (v not in r.instance_variables and v not in r.derived_variables): var_prefix = '{0}.{1}'.format(var_prefix, 'parent') r = r.parent if r == None: raise SimBuildError("Unable to resolve required " "variable '{0}'".format(v)) return '{0}.{1}'.format(var_prefix, v) elif (tree_node.value in dynamics.derived_variables or (regime is not None and tree_node.value in regime.derived_variables)): return 'self.{0}'.format(tree_node.value) else: return 'self.{0}_shadow'.format(tree_node.value) else: return tree_node.value elif tree_node.type == ExprNode.FUNC1: pattern = '({0}({1}))' func = self.convert_func(tree_node.func) if 'random.uniform' in func: pattern = '({0}(0,{1}))' return pattern.format(\ func, self.build_expression_from_tree(runnable, regime, tree_node.param)) else: return '({0}) {1} ({2})'.format(\ self.build_expression_from_tree(runnable, regime, tree_node.left), self.convert_op(tree_node.op), self.build_expression_from_tree(runnable, regime, tree_node.right))
def add_dynamics_2(self, component, runnable, regime, dynamics): """ Adds dynamics to a runnable component based on the dynamics specifications in the component model. This method builds dynamics dependent on child components. @param component: Component model containing dynamics specifications. @type component: lems.model.component.FatComponent @param runnable: Runnable component to which dynamics is to be added. @type runnable: lems.sim.runnable.Runnable @param regime: The dynamics regime to be used to generate dynamics code in the runnable component. @type regime: lems.model.dynamics.Regime @param dynamics: Shared dynamics specifications. @type dynamics: lems.model.dynamics.Regime @raise SimBuildError: Raised when a time derivative expression refers to an undefined variable. @raise SimBuildError: Raised when there are invalid time specifications for the <Run> statement. @raise SimBuildError: Raised when the component reference for <Run> cannot be resolved. """ if isinstance(regime, Dynamics) or regime.name == '': suffix = '' else: suffix = '_regime_' + regime.name # Process kinetic schemes ks_code = [] for ks in regime.kinetic_schemes: raise NotImplementedError("KineticScheme element is not stable in PyLEMS yet, see https://github.com/LEMS/pylems/issues/15") try: ###nodes = {node.id:node for node in runnable.__dict__[ks.nodes]} nodes = {} for node in runnable.__dict__[ks.nodes]: nodes[node.id] = node edges = runnable.__dict__[ks.edges] for edge in edges: from_ = edge.__dict__[ks.edge_source] to = edge.__dict__[ks.edge_target] ks_code += [('self.{0}.{2} += dt * (-self.{3}.{4} * self.{0}.{2}_shadow' ' + self.{3}.{5} * self.{1}.{2}_shadow)').format( from_, to, ks.state_variable, edge.id, ks.forward_rate, ks.reverse_rate)] ks_code += [('self.{1}.{2} += dt * (self.{3}.{4} * self.{0}.{2}_shadow' ' - self.{3}.{5} * self.{1}.{2}_shadow)').format( from_, to, ks.state_variable, edge.id, ks.forward_rate, ks.reverse_rate)] ks_code += ['sum = 0'] for node in nodes: nodes[node].__dict__[ks.state_variable] = 1.0 / len(nodes) nodes[node].__dict__[ks.state_variable + '_shadow'] = 1.0 / len(nodes) ks_code += ['sum += self.{0}.{1}'.format(node, ks.state_variable)] for node in nodes: ks_code += ['self.{0}.{1} /= sum'.format(node, ks.state_variable)] for node in nodes: ks_code += [('self.{0}.{1}_shadow = ' 'self.{0}.{1}').format(node, ks.state_variable)] except Exception as e: raise SimBuildError(("Unable to construct kinetic scheme '{0}' " "for component '{1}' - {2}").format(ks.name, component.id, str(e))) runnable.add_method('update_kinetic_scheme' + suffix, ['self', 'dt'], ks_code)
def register_event_out_callback(self, port, callback): if port in self.event_out_callbacks: self.event_out_callbacks[port].append(callback) else: raise SimBuildError('No event out port \'{0}\' in ' 'component \'{1}\''.format(port, self.name))
found = True else: for case in dv.cases: for dv2 in dvs: if dv1 != dv2 and (is_var_in_exp_tree(dv2, case.condition_expression_tree) or is_var_in_exp_tree(dv2, case.value_expression_tree)): found = True if not found: ordering.append(dv1) del dvs[dvs.index(dv1)] count = maxcount break if count == 0: raise SimBuildError(("Unable to find ordering for derived " "variables in regime '{0}'").format(regime.name)) #return ordering + dvsnoexp return dvsnoexp + ordering def is_var_in_exp_tree(var, exp_tree): node = exp_tree if node.type == ExprNode.VALUE: if node.value == var: return True else: return False elif node.type == ExprNode.OP: if is_var_in_exp_tree(var, node.left): return True
def add_runnable_behavior(self, component, runnable, behavior_profile): """ Adds behavior to a runnable component based on the behavior specifications in the component model. @param component: Component model containing behavior specifications. @type component: lems.model.component.Component @param runnable: Runnable component to which behavior is to be added. @type runnable: lems.sim.runnable.Runnable @param behavior_profile: The behavior profile to be used to generate behavior code in the runnable component. @type behavior_profile: lems.model.behavior.Behavior @raise SimBuildError: Raised when a time derivative expression refers to an undefined variable. @raise SimBuildError: Raised when there are invalid time specifications for the <Run> statement. @raise SimBuildError: Raised when the component reference for <Run> cannot be resolved. """ context = component.context regime = behavior_profile.default_regime for svn in regime.state_variables: sv = regime.state_variables[svn] runnable.add_instance_variable(sv.name, 0) time_step_code = [] for tdn in regime.time_derivatives: if tdn not in regime.state_variables: raise SimBuildError(('Time derivative for undefined state ' 'variable {0}').format(tdn)) td = regime.time_derivatives[tdn] time_step_code += ['self.{0} += dt * ({1})'.format(td.variable, self.build_expression_from_tree(\ td.expression_tree))] runnable.add_method('update_state_variables', ['self', 'dt'], time_step_code) pre_event_handler_code = [] post_event_handler_code = [] for eh in regime.event_handlers: if eh.type == EventHandler.ON_CONDITION: post_event_handler_code += self.build_event_handler(eh) else: pre_event_handler_code += self.build_event_handler(eh) runnable.add_method('run_preprocessing_event_handlers', ['self'], pre_event_handler_code) runnable.add_method('run_postprocessing_event_handlers', ['self'], post_event_handler_code) for rn in regime.runs: run = regime.runs[rn] c = context.lookup_component_ref(run.component) if c != None: target = self.build_runnable(c, self) self.sim.add_runnable(c.id, target) self.current_record_target = target time_step = context.lookup_parameter(run.increment) time_total = context.lookup_parameter(run.total) if time_step != None and time_total != None: target.configure_time(time_step.numeric_value, time_total.numeric_value) else: raise SimBuildError(('Invalid component reference {0} in ' '<Run>').format(c.id))
def resolve_path(self, path): if self.debug: print("Resolving path: %s in %s" % (path, self)) if path == '': return self if path == 'this': return self if path[0] == '/': return self.parent.resolve_path(path) elif path.find('../') == 0: return self.parent.resolve_path(path[3:]) elif path.find('..') == 0: return self.parent elif path == 'parent': return self.parent else: if path.find('/') >= 1: (child, new_path) = path.split('/', 1) else: child = path new_path = '' idxbegin = child.find('[') idxend = child.find(']') if idxbegin != 0 and idxend > idxbegin: idx = int(child[idxbegin + 1:idxend]) child = child[:idxbegin] else: idx = -1 if child in self.children: childobj = self.children[child] if idx != -1: childobj = childobj.array[idx] elif child in self.component.parameters: ctx = self.component p = ctx.parameters[child] return self.resolve_path('../' + p.value) elif child in self.__dict__.keys(): child_resolved = self.__dict__[child] #print("Think it's a link from %s to %s"%(child, child_resolved)) return self.resolve_path('../' + child_resolved) else: if self.debug: keys = list(self.__dict__.keys()) keys.sort() prefix = "--- " print('{0} Keys for {1}'.format(prefix, self.id)) for k in keys: key_str = str(self.__dict__[k]) if len( key_str ) > 0 and not key_str == "[]" and not key_str == "{}": print('{0} {1} -> {2}'.format( prefix, k, key_str)) raise SimBuildError('Unable to find child \'{0}\' in ' '\'{1}\''.format(child, self.id)) if new_path == '': return childobj else: return childobj.resolve_path(new_path)
def copy(self): """ Make a copy of this runnable. @return: Copy of this runnable. @rtype: lems.sim.runnable.Runnable """ if self.debug: print("Coping....." + self.id) r = Runnable(self.id, self.component, self.parent) copies = dict() # Copy simulation time parameters r.time_step = self.time_step r.time_completed = self.time_completed r.time_total = self.time_total # Plasticity and state stack (?) r.plastic = self.plastic r.state_stack = Stack() # Copy variables (GG - Faster using the add_* methods?) for v in self.instance_variables: r.instance_variables.append(v) r.__dict__[v] = self.__dict__[v] r.__dict__[v + '_shadow'] = self.__dict__[v + '_shadow'] for v in self.derived_variables: r.derived_variables.append(v) r.__dict__[v] = self.__dict__[v] r.__dict__[v + '_shadow'] = self.__dict__[v + '_shadow'] # Copy array elements for child in self.array: child_copy = child.copy() child_copy.parent = r r.array.append(child_copy) copies[child.uid] = child_copy # Copy attachment def for att in self.attachments: atn = self.attachments[att] r.attachments[att] = atn r.__dict__[atn] = [] # Copy children for uid in self.uchildren: child = self.uchildren[uid] child_copy = child.copy() child_copy.parent = r copies[child.uid] = child_copy r.add_child(child_copy.id, child_copy) # For typerefs try: idx = [k for k in self.__dict__ if self.__dict__[k] == child][0] r.__dict__[idx] = child_copy except: pass # For groups and attachments: try: idx = [k for k in self.__dict__ if child in self.__dict__[k]][0] if idx not in r.__dict__: r.__dict__[idx] = [] r.__dict__[idx].append(child_copy) except: pass # Copy event ports for port in self.event_in_ports: r.event_in_ports.append(port) r.event_in_counters[port] = 0 for port in self.event_out_ports: r.event_out_ports.append(port) r.event_out_callbacks[port] = self.event_out_callbacks[port] for ec in r.component.structure.event_connections: if self.debug: print("--- Fixing event_connection: %s in %s" % (ec.toxml(), id(r))) source = r.parent.resolve_path(ec.from_) target = r.parent.resolve_path(ec.to) if ec.receiver: # Will throw error... receiver_template = self.build_runnable(ec.receiver, target) #receiver = copy.deepcopy(receiver_template) receiver = receiver_template.copy() receiver.id = "{0}__{1}__".format(component.id, receiver_template.id) if ec.receiver_container: target.add_attachment(receiver, ec.receiver_container) target.add_child(receiver_template.id, receiver) target = receiver else: source = r.resolve_path(ec.from_) target = r.resolve_path(ec.to) source_port = ec.source_port target_port = ec.target_port if not source_port: if len(source.event_out_ports) == 1: source_port = source.event_out_ports[0] else: raise SimBuildError(("No source event port " "uniquely identifiable" " in '{0}'").format(source.id)) if not target_port: if len(target.event_in_ports) == 1: target_port = target.event_in_ports[0] else: raise SimBuildError(("No destination event port " "uniquely identifiable " "in '{0}'").format(target)) if self.debug: print( "register_event_out_callback\n Source: %s, %s (port: %s) \n -> %s, %s (port: %s)" % (source, id(source), source_port, target, id(target), target_port)) source.register_event_out_callback(\ source_port, lambda: target.inc_event_in(target_port)) # Copy methods if getattr(self, "update_kinetic_scheme", None): r.update_kinetic_scheme = self.update_kinetic_scheme if getattr(self, "run_startup_event_handlers", None): r.run_startup_event_handlers = self.run_startup_event_handlers if getattr(self, "run_preprocessing_event_handlers", None): r.run_preprocessing_event_handlers = self.run_preprocessing_event_handlers if getattr(self, "run_postprocessing_event_handlers", None): r.run_postprocessing_event_handlers = self.run_postprocessing_event_handlers if getattr(self, "update_state_variables", None): r.update_state_variables = self.update_state_variables if getattr(self, "update_derived_variables", None): r.update_derived_variables = self.update_derived_variables #r.update_shadow_variables = self.update_shadow_variables if getattr(self, "update_derived_parameters", None): r.update_derived_parameters = self.update_derived_parameters for rn in self.regimes: r.add_regime(self.regimes[rn]) r.current_regime = self.current_regime # Copy groups for gn in self.groups: g = self.__dict__[gn] for c in g: if c.uid in copies: r.add_child_to_group(gn, copies[c.uid]) else: c2 = c.copy() c2.parent = r copies[c.uid] = c2 r.add_child_to_group(gn, c2) # Copy remaining runnable references. for k in self.__dict__: if k == 'parent': continue c = self.__dict__[k] if isinstance(c, Runnable): if c.uid in copies: r.__dict__[k] = copies[c.uid] else: c2 = c.copy() c2.parent = r copies[c.uid] = c2 r.__dict__[k] = c2 # Copy text fields for k in self.__dict__: if not k in r.__dict__: c = self.__dict__[k] if self.debug: print("Adding remaining field: %s = %s" % (k, c)) r.__dict__[k] = c if self.debug: print('########################################') keys = list(self.__dict__.keys()) keys.sort() print(len(keys)) for k in keys: print(k, self.__dict__[k]) print('----------------------------------------') keys = list(r.__dict__.keys()) keys.sort() print(len(keys)) for k in keys: print(k, r.__dict__[k]) print('########################################') print('') print('') print('') print('') if self.debug: print("Finished coping..." + self.id) return r
def add_dynamics_1(self, component, runnable, regime, dynamics): """ Adds dynamics to a runnable component based on the dynamics specifications in the component model. This method builds dynamics necessary for building child components. @param component: Component model containing dynamics specifications. @type component: lems.model.component.FatComponent @param runnable: Runnable component to which dynamics is to be added. @type runnable: lems.sim.runnable.Runnable @param regime: The dynamics regime to be used to generate dynamics code in the runnable component. @type regime: lems.model.dynamics.Regime @param dynamics: Shared dynamics specifications. @type dynamics: lems.model.dynamics.Regime @raise SimBuildError: Raised when a time derivative expression refers to an undefined variable. @raise SimBuildError: Raised when there are invalid time specifications for the <Run> statement. @raise SimBuildError: Raised when the component reference for <Run> cannot be resolved. """ if isinstance(regime, Dynamics) or regime.name == '': suffix = '' else: suffix = '_regime_' + regime.name if isinstance(regime, Regime) and regime.initial: runnable.new_regime = regime.name # Process state variables for sv in regime.state_variables: runnable.add_instance_variable(sv.name, 0) # Process time derivatives time_step_code = [] for td in regime.time_derivatives: if td.variable not in regime.state_variables and td.variable not in dynamics.state_variables: raise SimBuildError(('Time derivative for undefined state ' 'variable {0} in component {1}').format(td.variable, component.id)) exp = self.build_expression_from_tree(runnable, regime, td.expression_tree) time_step_code += ['self.{0} += dt * ({1})'.format(td.variable, exp)] runnable.add_method('update_state_variables' + suffix, ['self', 'dt'], time_step_code) # Process derived variables derived_variable_code = [] derived_variables_ordering = order_derived_variables(regime) for dvn in derived_variables_ordering: #regime.derived_variables: if dvn in dynamics.derived_variables: dv = dynamics.derived_variables[dvn] runnable.add_derived_variable(dv.name) if dv.value: derived_variable_code += ['self.{0} = ({1})'.format( dv.name, self.build_expression_from_tree(runnable, regime, dv.expression_tree))] elif dv.select: if dv.reduce: derived_variable_code += self.build_reduce_code(dv.name, dv.select, dv.reduce) else: derived_variable_code += ['self.{0} = (self.{1})'.format( dv.name, dv.select.replace('/', '.'))] else: raise SimBuildError(('Inconsistent derived variable settings' 'for {0}').format(dvn)) elif dvn in dynamics.conditional_derived_variables: dv = dynamics.conditional_derived_variables[dvn] runnable.add_derived_variable(dv.name) derived_variable_code += self.build_conditional_derived_var_code(runnable, regime, dv) else: raise SimBuildError("Unknown derived variable '{0}' in '{1}'", dvn, runnable.id) runnable.add_method('update_derived_variables' + suffix, ['self'], derived_variable_code) # Process event handlers pre_event_handler_code = [] post_event_handler_code = [] startup_event_handler_code = [] on_entry_added = False for eh in regime.event_handlers: if isinstance(eh, OnStart): startup_event_handler_code += self.build_event_handler(runnable, regime, eh) elif isinstance(eh, OnCondition): post_event_handler_code += self.build_event_handler(runnable, regime, eh) else: if isinstance(eh, OnEntry): on_entry_added = True pre_event_handler_code += self.build_event_handler(runnable, regime, eh) if isinstance(regime, Regime) and not on_entry_added: pre_event_handler_code += self.build_event_handler(runnable, regime, OnEntry()) runnable.add_method('run_startup_event_handlers' + suffix, ['self'], startup_event_handler_code) runnable.add_method('run_preprocessing_event_handlers' + suffix, ['self'], pre_event_handler_code) runnable.add_method('run_postprocessing_event_handlers' + suffix, ['self'], post_event_handler_code)