def gen_Entity(obj, name="", parent=None, **kwargs): islogical = issubclass(obj.__class__, Model.LogicalEntity) hide_behaviour = kwargs["interface_only"] or kwargs["no_behaviour"] or \ (islogical and kwargs["logical_interface_only"]) style = "dashed" if islogical else "solid" inputs = "" outputs = "" centre = "" body = "" """ Inputs """ for name_, input_ in Model.get_inputs(obj, as_dict=True).items(): inputs += "\n" + generate(input_, name_, obj, **kwargs) """ Centre """ if not hide_behaviour: for name_, state in Model.get_states(obj, as_dict=True).items(): if not name_ == CURRENT_IDENTIFIER: centre += "\n" + generate(state, name_, obj, **kwargs) if not hide_behaviour: for name_, local in Model.get_locals(obj, as_dict=True).items(): centre += "\n" + generate(local, name_, obj, **kwargs) """ Outputs """ for name_, output in Model.get_outputs(obj, as_dict=True).items(): outputs += "\n" + generate(output, name_, obj, **kwargs) """ Body """ if not hide_behaviour: if kwargs["transitions"]: for name_, trans in Model.get_transitions(obj, as_dict=True).items(): body += "\n" + "\n".join(generate(trans, name_, obj, **kwargs)) if not kwargs["interface_only"] and not (islogical and kwargs["logical_interface_only"]): for name_, entity in Model.get_entities(obj, as_dict=True).items(): if name_ != PARENT_IDENTIFIER: centre += "\n" + generate(entity, name_, obj, **kwargs) if not kwargs["interface_only"] and not (islogical and kwargs["logical_interface_only"]): for name_, influence in Model.get_influences(obj, as_dict=True).items(): body += "\n" + generate(influence, name_, obj, **kwargs) if not hide_behaviour: if kwargs["updates"]: for name_, update in Model.get_updates(obj, as_dict=True).items(): body += "\n" + "\n".join(generate(update, name_, obj, ** kwargs)) if not hide_behaviour: if kwargs["actions"]: for name_, action in Model.get_actions(obj, as_dict=True).items(): body += "\n" + "\n".join(generate(action, name_, obj, ** kwargs)) typename = obj.__class__.__name__ if isinstance( obj, CrestObject) else obj.__name__ return f"""
def gen_Entity(obj, name="", parent=None, **kwargs): parentinfo = "" if parent is None else parent._name logger.debug( f"Adding entity '{name}' of type {type(obj)} with parent (id={id(parent)})" ) typename = obj.__class__.__name__ if isinstance( obj, CrestObject) else obj.__name__ node = { 'id': str(id(obj)), 'label': { 'label': f'{name} | {typename}', 'text': name }, 'children': [], 'ports': [], 'edges': [], 'cresttype': 'entity', 'width': 300, 'height': 200 } """ Inputs """ for name_, input_ in Model.get_inputs(obj, as_dict=True).items(): node["ports"].append(generate(input_, name_, obj, **kwargs)) """ Centre """ for name_, state in Model.get_states(obj, as_dict=True).items(): if not name_ == CURRENT_IDENTIFIER: node["children"].append(generate(state, name_, obj, **kwargs)) for name_, local in Model.get_locals(obj, as_dict=True).items(): node["children"].append(generate(local, name_, obj, **kwargs)) """ Outputs """ for name_, output in Model.get_outputs(obj, as_dict=True).items(): node["ports"].append(generate(output, name_, obj, **kwargs)) for name_, entity in Model.get_entities(obj, as_dict=True).items(): if name_ != PARENT_IDENTIFIER: node["children"].append(generate(entity, name_, obj, **kwargs)) for name_, trans in Model.get_transitions(obj, as_dict=True).items(): node["edges"].extend(generate(trans, name_, obj, **kwargs)) node["children"].append(generate_midpoint(trans, name_, obj, **kwargs)) for name_, influence in Model.get_influences(obj, as_dict=True).items(): node["edges"].extend(generate(influence, name_, obj, **kwargs)) for name_, update in Model.get_updates(obj, as_dict=True).items(): node["edges"].extend(generate(update, name_, obj, **kwargs)) pass for name_, action in Model.get_actions(obj, as_dict=True).items(): node["edges"].extend(generate(action, name_, obj, **kwargs)) return node
def calculate_entity_hook(self, entity): all_dts = [] logger.debug( f"Calculating behaviour change for entity {entity._name} ({entity.__class__.__name__})" ) for influence in get_influences(entity): if self.contains_if_condition(influence): inf_dts = self.get_condition_change_enablers(influence) if inf_dts is not None: all_dts.append(inf_dts) # updates = [up for up in get_updates(self.entity) if up.state == up._parent.current] for update in get_updates(entity): if update.state is update._parent.current: # only the currently active updates if self.contains_if_condition(update): up_dts = self.get_condition_change_enablers(update) if up_dts is not None: all_dts.append(up_dts) # TODO: check for transitions whether they can be done by time only for name, trans in get_transitions(entity, as_dict=True).items(): if entity.current is trans.source: trans_dts = self.get_transition_time(trans) if trans_dts is not None: all_dts.append(trans_dts) if logger.getEffectiveLevel() <= logging.DEBUG: if len(all_dts) == 0: logger.debug( "There were no change times in entity {entity._name} ({entity.__class__.__name__})." ) return [] min_dt_eps = min(all_dts, key=(lambda x: x[0])) # min_dt = get_minimum_dt_of_several(all_dts, self.timeunit) if min_dt_eps is not None: logger.debug( f"Minimum behaviour change time for entity {entity._name} ({entity.__class__.__name__}) is {min_dt_eps}" ) return [min_dt_eps] # return a list # min_dt = get_minimum_dt_of_several(all_dts, self.timeunit) # if min_dt is not None: # logger.debug(f"Minimum behaviour change time for entity {entity._name} ({entity.__class__.__name__}) is {min_dt}") # return [min_dt] # return a list else: # XXX This is the faster one that we run when we're not debugging !! return all_dts
def transition(self, entity, transition=None): logger.debug("transitions in entity %s (%s)", entity._name, entity.__class__.__name__) if transition is None: transition = self.select_transition_to_trigger(entity) if transition is None: # there are no enabled transitions ! (exit early) return False # in case it was passed as parameter assert self._get_transition_guard_value( transition ), "It seems that the transition that was chosen to be fired is not enabled." entity.current = transition.target logger.info( f"Time: {self.global_time} | Firing transition <<{transition._name}>> in {entity._name} ({entity.__class__.__name__}) : {transition.source._name} -> {transition.target._name} | current global time: {self.global_time}" ) transition_updates = [ up for up in get_updates(transition._parent) if up.state is transition ] # FIXME: until we completely switched to only allowing actions... actions = [ a for a in get_actions(transition._parent) if a.transition is transition ] for act in actions + transition_updates: logger.debug( f"Triggering action {act._name} in entity {entity._name} ({entity.__class__.__name__})" ) newval = self._get_action_function_value(act) if newval != act.target.value: logger.info( f"Port value changed: {act.target._name} ({act.target._parent._name}) {act.target.value} -> {newval}" ) act.target.value = newval # return if a transition was fired return (transition is not None)
def transition(self, entity): # logger.debug(f"transitions in entity {entity._name} ({entity.__class__.__name__})") transitions_from_current_state = [ t for t in model.get_transitions(entity) if t.source is entity.current ] enabled_transitions = [ t for t in transitions_from_current_state if self._get_transition_guard_value(t) ] state_before = SystemState(self.system).save() # backup the state states_after = [] for transition in enabled_transitions: state_before.apply() # reset to original state entity.current = transition.target # logger.info(f"Time: {self.global_time} | Firing transition <<{transition._name}>> in {entity._name} ({entity.__class__.__name__}) : {transition.source._name} -> {transition.target._name} | current global time: {self.global_time}") transition_updates = [ up for up in model.get_updates(transition._parent) if up.state is transition ] # FIXME: until we completely switched to only allowing actions... actions = [ a for a in model.get_actions(transition._parent) if a.transition is transition ] for act in actions + transition_updates: newval = self._get_action_function_value(act) if newval != act.target.value: act.target.value = newval state_after = SystemState(self.system).save() states_after.append((state_after, [transition])) # return the new states if there are any (this means that empty list means no transitions were fired) # logger.debug(f"finished transitions in entity {entity._name} ({entity.__class__.__name__}): Created {len(states_after)} new states!") return states_after
def _update(self, entity, time, original_states, original_port_values, first=False): logger.debug( f"entity <<{entity._name}>> ({entity.__class__.__name__}) with dt of {time}" ) # set pre's for port in get_sources(entity): port.pre = original_port_values[port] current_port_values = {t: t.value for t in get_all_ports(entity)} updates_from_current_state = [ up for up in get_updates(entity) if up.state is entity.current ] """ apply updates """ values_to_update = {} for update in updates_from_current_state: logger.debug( f"Executing update <<{update._name}>> (target: {update.target._name}) in entity {entity._name} ({entity.__class__.__name__})" ) update_func_value = self._calculate_update_value( entity, time, original_states, original_port_values, update) if not bool(current_port_values[update.target] == update_func_value): # this means something changed values_to_update[update.target] = update_func_value logger.debug( f"Update <<{update._name}>> in entity {entity._name} ({entity.__class__.__name__}) TEMP changing value of port {update.target._name} (type: {update.target.resource.unit}) to {update_func_value} (from {current_port_values[update.target]}) | global time {self.global_time}" ) self._value_change(values_to_update) self.propagate_influences( entity) # propagate through influences and to children logger.debug(f"executing subentity updates") subentity_changes = [] for subentity in get_entities(entity): # only do it if the inputs values changed, otherwise we'll stay like this... # also do it if it's the first time we execute if first or any(i.value != current_port_values[i] for i in get_inputs(subentity)): logger.debug( f"Applying update to subentity {subentity._name} ({subentity.__class__.__name__})" ) self.reset_subentity( subentity, original_states, original_port_values) # resets all except inputs self.update_system(subentity, time) self.stabilise(subentity) sub_changes = [ o.value != current_port_values[o] for o in get_outputs(subentity) ] logger.debug( f"Applying update to subentity {subentity._name} ({subentity.__class__.__name__}) changed values: {any(sub_changes)}" ) subentity_changes.append(any(sub_changes)) logger.debug( f"Finished update of subentity {subentity._name} ({subentity.__class__.__name__})" ) logger.debug(f"finished executing subentity updates") self.propagate_influences(entity) # forward all influences logger.debug( f"finished entity <<{entity._name}>> ({entity.__class__.__name__}) with dt of {time}" ) # either port values changed or subentity interfaces changed return len(values_to_update) > 0 or any(subentity_changes)
def _replacability_checks(entity, name, obj, existing): # TODO: clean me up ? These are lots of checks, maybe we need to make them look nice if isinstance(obj, crest.Entity): for update in crest.get_updates( entity ): # check if an update already writes to one of the entity's ports if update.target in crest.get_inputs(existing): raise AttributeError( f"Cannot reassign SubEntity '{name}' since one of its Input ports was used as target of Update '{get_name(update)}'." ) for influence in crest.get_influences( entity ): # check if an influence already reads from or writes to the entity's ports if influence.source in crest.get_outputs(existing): raise AttributeError( f"Cannot reassign SubEntity '{name}' since one of its Output ports was used as source of Influence '{get_name(influence)}'." ) if influence.target in crest.get_inputs(existing): raise AttributeError( f"Cannot reassign SubEntity '{name}' since one of its Input ports was used as target of Influence '{get_name(influence)}'." ) for action in crest.get_actions( entity ): # check if an action already writes to the entity's ports if action.target in crest.get_inputs(existing): raise AttributeError( f"Cannot reassign SubEntity '{name}' since one of its Input ports was used as target of Action '{get_name(action)}'." ) elif isinstance(obj, crest.Port): for update in crest.get_updates( entity ): # check if an update already writes to the port that we want to override if update.target == existing: raise AttributeError( f"Cannot reassign {obj.__class__.__name__} port '{name}' after it was used as target of Update '{get_name(update)}'." ) for influence in crest.get_influences( entity ): # check if an influence already reads from or writes to the port that we want to override if influence.source == existing: raise AttributeError( f"Cannot reassign {obj.__class__.__name__} port '{name}' after it was used as source of Influence '{get_name(influence)}'." ) if influence.target == existing: raise AttributeError( f"Cannot reassign {obj.__class__.__name__} port '{name}' after it was used as target of Influence '{get_name(influence)}'." ) for action in crest.get_actions( entity ): # check if an action already writes to the port that we want to override if action.target == existing: raise AttributeError( f"Cannot reassign {obj.__class__.__name__} port '{name}' after it was used as target of Action '{get_name(action)}'." ) elif isinstance(obj, crest.State): for update in crest.get_updates( entity ): # check if an update is already linked to the state that we want to override if update.state == existing: raise AttributeError( f"Cannot reassign {obj.__class__.__name__} '{name}' after it was used in Update '{get_name(update)}'." ) for transition in crest.get_transitions( entity ): # check if a transition already starts from or goes to the state that we want to override if transition.source == existing: raise AttributeError( f"Cannot reassign {obj.__class__.__name__} '{name}' after it was used as source of Transition '{get_name(transition)}'." ) if transition.target == existing: raise AttributeError( f"Cannot reassign {obj.__class__.__name__} '{name}' after it was used as target of Transition '{get_name(transition)}'." ) elif isinstance(obj, crest.Transition): # TODO: check here for any action uses the transition already # this is non-trivial however pass