include "primitives.alh" include "modelling.alh" include "object_operations.alh" include "library.alh" include "conformance_scd.alh" include "io.alh" include "metamodels.alh" include "compilation_manager.alh" Void function main(): Element model String verify_result while (True): execute_cbd(instantiate_model(import_node("models/CausalBlockDiagrams_Design"))) Element function retype_to_runtime(design_model : Element): Element runtime_model Element all_blocks Element all_links String mm_type_name String element_name String attr_name String attr_value String attribute String src String dst String time Element all_attributes runtime_model = instantiate_model(import_node("models/CausalBlockDiagrams_Runtime")) all_blocks = allInstances(design_model, "Block") while (list_len(all_blocks) > 0): element_name = set_pop(all_blocks) mm_type_name = reverseKeyLookup(design_model["metamodel"]["model"], dict_read_node(design_model["type_mapping"], design_model["model"][element_name])) element_name = instantiate_node(runtime_model, mm_type_name, element_name) if (mm_type_name == "ConstantBlock"): instantiate_attribute(runtime_model, element_name, "value", read_attribute(design_model, element_name, "value")) // Don't merge this together with the block conversion, as the destination block might not exist yet! all_links = allInstances(design_model, "Link") while (read_nr_out(all_links) > 0): element_name = set_pop(all_links) src = reverseKeyLookup(design_model["model"], read_edge_src(design_model["model"][element_name])) dst = reverseKeyLookup(design_model["model"], read_edge_dst(design_model["model"][element_name])) instantiate_link(runtime_model, "Link", element_name, src, dst) all_links = allInstances(design_model, "InitialCondition") while (read_nr_out(all_links) > 0): element_name = set_pop(all_links) src = reverseKeyLookup(design_model["model"], read_edge_src(design_model["model"][element_name])) dst = reverseKeyLookup(design_model["model"], read_edge_dst(design_model["model"][element_name])) instantiate_link(runtime_model, "InitialCondition", element_name, src, dst) return runtime_model! Element function sanitize(new_runtime_model : Element, old_runtime_model : Element): Element all_blocks Element all_links String mm_type_name String element_name String attr_name String attr_value String attribute String time Element all_attributes Integer current_time all_blocks = allInstances(new_runtime_model, "Block") while (list_len(all_blocks) > 0): element_name = set_pop(all_blocks) mm_type_name = reverseKeyLookup(new_runtime_model["metamodel"]["model"], dict_read_node(new_runtime_model["type_mapping"], new_runtime_model["model"][element_name])) if (dict_in(old_runtime_model["model"], element_name)): if (mm_type_name == "DelayBlock"): instantiate_attribute(new_runtime_model, element_name, "memory", read_attribute(old_runtime_model, element_name, "memory")) instantiate_attribute(new_runtime_model, element_name, "signal", read_attribute(old_runtime_model, element_name, "signal")) else: instantiate_attribute(new_runtime_model, element_name, "signal", 0.0) if (dict_in(old_runtime_model["model"], "time")): current_time = read_attribute(old_runtime_model, "time", "current_time") else: current_time = 0 time = instantiate_node(new_runtime_model, "Time", "time") instantiate_attribute(new_runtime_model, time, "start_time", current_time) instantiate_attribute(new_runtime_model, time, "current_time", current_time) return new_runtime_model! Element function create_schedule(model : Element, start_time : Integer): Element all_blocks Element visited Element to_visit Element incoming_links String element_name String link String source String new_schedule Boolean ready Element schedule // TODO add algebraic loop detection (not solution...) schedule = create_node() all_blocks = allInstances(model, "Block") visited = create_node() to_visit = create_node() while (read_nr_out(all_blocks) > 0): element_name = set_pop(all_blocks) if (bool_not(set_in(visited, element_name))): list_append(to_visit, element_name) while (list_len(to_visit) > 0): element_name = list_read(to_visit, list_len(to_visit) - 1) if (reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][element_name])) == "DelayBlock"): if (element_eq(read_attribute(model, element_name, "memory"), read_root())): incoming_links = allIncomingAssociationInstances(model, element_name, "InitialCondition") else: incoming_links = create_node() else: incoming_links = allIncomingAssociationInstances(model, element_name, "Link") ready = True while (list_len(incoming_links) > 0): link = set_pop(incoming_links) source = readAssociationSource(model, link) if (bool_not(set_in(visited, source))): list_append(to_visit, source) ready = False if (ready): list_append(schedule, element_name) list_delete(to_visit, list_len(to_visit) - 1) set_add(visited, element_name) log("Schedule length: " + cast_v2s(read_nr_out(schedule))) return schedule! String function readType(model : Element, name : String): return reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][name]))! Void function step_simulation(model : Element, schedule : Element): String time Float signal Element incoming String selected String block String elem String blocktype Element delay_blocks Integer i time = "time" delay_blocks = create_node() output("SIM_TIME " + cast_v2s(read_attribute(model, time, "current_time"))) i = 0 while (i < read_nr_out(schedule)): block = list_read(schedule, i) i = i + 1 // Execute "block" blocktype = readType(model, block) if (blocktype == "ConstantBlock"): signal = read_attribute(model, block, "value") elif (blocktype == "AdditionBlock"): signal = 0.0 incoming = allIncomingAssociationInstances(model, block, "Link") while (read_nr_out(incoming) > 0): selected = readAssociationSource(model, set_pop(incoming)) signal = signal + cast_s2f(cast_v2s(read_attribute(model, selected, "signal"))) elif (blocktype == "MultiplyBlock"): signal = 1.0 incoming = allIncomingAssociationInstances(model, block, "Link") while (read_nr_out(incoming) > 0): selected = readAssociationSource(model, set_pop(incoming)) signal = signal * cast_s2f(cast_v2s(read_attribute(model, selected, "signal"))) elif (blocktype == "NegatorBlock"): incoming = allIncomingAssociationInstances(model, block, "Link") signal = 0.0 while (read_nr_out(incoming) > 0): selected = readAssociationSource(model, set_pop(incoming)) signal = float_neg(cast_s2f(cast_v2s(read_attribute(model, selected, "signal")))) elif (blocktype == "InverseBlock"): signal = 0.0 incoming = allIncomingAssociationInstances(model, block, "Link") while (read_nr_out(incoming) > 0): selected = readAssociationSource(model, set_pop(incoming)) signal = float_division(1.0, cast_s2f(cast_v2s(read_attribute(model, selected, "signal")))) elif (blocktype == "DelayBlock"): signal = 0.0 if (element_eq(read_attribute(model, block, "memory"), read_root())): // No memory yet, so use initial condition incoming = allIncomingAssociationInstances(model, block, "InitialCondition") while (read_nr_out(incoming) > 0): selected = readAssociationSource(model, set_pop(incoming)) signal = cast_s2f(cast_v2s(read_attribute(model, selected, "signal"))) else: signal = read_attribute(model, block, "memory") unset_attribute(model, block, "memory") set_add(delay_blocks, block) unset_attribute(model, block, "signal") instantiate_attribute(model, block, "signal", signal) output((("SIM_PROBE " + cast_v2s(block)) + " ") + cast_v2s(signal)) output("SIM_END") while (read_nr_out(delay_blocks) > 0): block = set_pop(delay_blocks) // Update memory incoming = allIncomingAssociationInstances(model, block, "Link") while (read_nr_out(incoming) > 0): selected = readAssociationSource(model, set_pop(incoming)) instantiate_attribute(model, block, "memory", cast_s2f(cast_v2s(read_attribute(model, selected, "signal")))) // Increase simulation time Integer new_time new_time = cast_s2i(cast_v2s(read_attribute(model, time, "current_time"))) + 1 unset_attribute(model, time, "current_time") instantiate_attribute(model, time, "current_time", new_time) return ! Void function execute_cbd(design_model : Element): String verify_result Element runtime_model Element old_runtime_model String cmd Boolean running Element schedule_init Element schedule_run Element schedule String conforming old_runtime_model = instantiate_model(import_node("models/CausalBlockDiagrams_Runtime")) runtime_model = retype_to_runtime(design_model) runtime_model = sanitize(runtime_model, old_runtime_model) running = False conforming = conformance_scd(design_model) if (conforming == "OK"): output("CONFORMANCE_OK") else: output("CONFORMANCE_FAIL") schedule_init = create_schedule(runtime_model, read_attribute(runtime_model, "time", "start_time")) schedule_run = create_schedule(runtime_model, -1) while (True): // If we are running, we just don't block for input and automatically do a step if there is no input if (running): if (has_input()): cmd = input() else: cmd = "step" else: cmd = input() // Process input if (cmd == "simulate"): // Simulation should toggle running to True, but only if the model is conforming if (conforming == "OK"): running = True else: output("CONFORMANCE_FAIL " + conforming) elif (cmd == "step"): // Stepping should make a single step, but first need to pick the correct schedule to use if (conforming == "OK"): if (read_attribute(runtime_model, "time", "start_time") == read_attribute(runtime_model, "time", "current_time")): schedule = schedule_init else: schedule = schedule_run step_simulation(runtime_model, schedule) else: output("CONFORMANCE_FAIL " + conforming) elif (cmd == "pause"): // Pausing merely stops a running simulation running = False elif (cmd == "read_available_attributes"): // Returns a list of all available attributes Element attr_list Element attrs Element attr attr_list = getAttributeList(design_model, input()) attrs = dict_keys(attr_list) while (0 < read_nr_out(attrs)): attr = set_pop(attrs) output("AVAILABLE_ATTR_VALUE " + cast_v2s(attr)) output("AVAILABLE_ATTR_TYPE " + cast_v2s(dict_read(attr_list, attr))) output("AVAILABLE_ATTR_END") elif (cmd == "read_attribute"): // Returns the value of an attribute output("ATTR_VALUE " + cast_v2s(read_attribute(design_model, input(), input()))) elif (bool_or(bool_or(cmd == "set_attribute", cmd == "instantiate_node"), cmd == "instantiate_association")): // Modify the structure if (cmd == "set_attribute"): // Setting an attribute String element_name String attribute_name element_name = input() attribute_name = input() // Delete it if it exists already if (bool_not(element_eq(read_attribute(design_model, element_name, attribute_name), read_root()))): unset_attribute(design_model, element_name, attribute_name) // And finally set it instantiate_attribute(design_model, element_name, attribute_name, input()) elif (cmd == "instantiate_node"): // Instantiate a node instantiate_node(design_model, input(), input()) elif (cmd == "instantiate_association"): // Instantiate an association instantiate_link(design_model, input(), input(), input(), input()) // After changes, we check whether or not the design model conforms conforming = conformance_scd(design_model) if (conforming == "OK"): // Conforming, so do the retyping and sanitization step runtime_model = retype_to_runtime(design_model) runtime_model = sanitize(runtime_model, old_runtime_model) schedule_init = create_schedule(runtime_model, read_attribute(runtime_model, "time", "start_time")) schedule_run = create_schedule(runtime_model, -1) old_runtime_model = runtime_model output("CONFORMANCE_OK") else: // Not conforming, so stop simulation and block for input (preferably a modify to make everything consistent again) running = False output("CONFORMANCE_FAIL " + conforming) else: log("Did not understand command: " + cmd)