Browse Source

Move in all DTCBD/CTCBD/FSA models

Yentl Van Tendeloo 7 years ago
parent
commit
5e7ff247a4
28 changed files with 3325 additions and 8 deletions
  1. 0 3
      examples/live_modelling_CBD.py
  2. 2 2
      kernel/modelverse_kernel/main.py
  3. 143 0
      models/CTCBD/PM_live_modelling.mvc
  4. 61 0
      models/CTCBD/metamodels/CTCBD_MM.mvc
  5. 54 0
      models/CTCBD/models/spring.mvc
  6. 180 0
      models/CTCBD/transformations/render.alc
  7. 297 0
      models/CTCBD/transformations/render.mvc
  8. 469 0
      models/CTCBD/transformations/to_partial_runtime.mvc
  9. 143 0
      models/DTCBD/PM_live_modelling.mvc
  10. 53 0
      models/DTCBD/metamodels/DTCBD_MM.mvc
  11. 76 0
      models/DTCBD/metamodels/DTCBD_MM_partial_runtime.mvc
  12. 76 0
      models/DTCBD/metamodels/DTCBD_MM_runtime.mvc
  13. 20 0
      models/DTCBD/models/simple_equation.mvc
  14. 61 0
      models/DTCBD/transformations/merge.alc
  15. 180 0
      models/DTCBD/transformations/render.alc
  16. 297 0
      models/DTCBD/transformations/render.mvc
  17. 612 0
      models/DTCBD/transformations/simulate.alc
  18. 69 0
      models/DTCBD/transformations/to_runtime.alc
  19. 143 0
      models/FiniteStateAutomata/PM_live_modelling.mvc
  20. 15 0
      models/FiniteStateAutomata/metamodels/FSA_MM.mvc
  21. 15 0
      models/FiniteStateAutomata/metamodels/FSA_MM_partial_runtime.mvc
  22. 21 0
      models/FiniteStateAutomata/metamodels/FSA_MM_runtime.mvc
  23. 27 0
      models/FiniteStateAutomata/models/alarm.mvc
  24. 108 0
      models/FiniteStateAutomata/transformations/merge.alc
  25. 62 0
      models/FiniteStateAutomata/transformations/simulate.alc
  26. 60 0
      models/FiniteStateAutomata/transformations/to_runtime.alc
  27. 78 0
      models/old/live_modelling.py
  28. 3 3
      wrappers/modelverse_SCCD.py

+ 0 - 3
examples/live_modelling_CBD.py

@@ -28,15 +28,12 @@ transformation_add_AL({}, {}, "models/CBD/restartSim", open("models/generic/rest
 model_add("models/live_modelling_CBD", "formalisms/ProcessModel", open("models/CBD/PM_live_modelling.mvc", 'r').read())
 model_add("models/live_modelling_CBD", "formalisms/ProcessModel", open("models/CBD/PM_live_modelling.mvc", 'r').read())
 
 
 def modify_model(model):
 def modify_model(model):
-    print("Modifying model in edit operation")
-
     if len(all_instances(model, "Design/ProbeBlock")) > 2:
     if len(all_instances(model, "Design/ProbeBlock")) > 2:
         import time
         import time
         print("Sufficient Probeblocks detected, so pausing with edits")
         print("Sufficient Probeblocks detected, so pausing with edits")
         while 1:
         while 1:
             time.sleep(1)
             time.sleep(1)
 
 
-    print("Will modify!")
     new_block = instantiate(model, "Design/ProbeBlock")
     new_block = instantiate(model, "Design/ProbeBlock")
     attr_assign(model, new_block, "name", "MyProbeBlock")
     attr_assign(model, new_block, "name", "MyProbeBlock")
     print("Added new probeblock: " + new_block)
     print("Added new probeblock: " + new_block)

+ 2 - 2
kernel/modelverse_kernel/main.py

@@ -345,8 +345,8 @@ class ModelverseKernel(object):
         #print(func)
         #print(func)
 
 
         # To write out all generated functions
         # To write out all generated functions
-        #with open('/tmp/junk/%s' % suggested_name, 'w') as f:
-        #    f.write(func)
+        with open('/tmp/junk/%s' % suggested_name, 'w') as f:
+            f.write(func)
 
 
         yield [("RETURN", [func])]
         yield [("RETURN", [func])]
 
 

+ 143 - 0
models/CTCBD/PM_live_modelling.mvc

@@ -0,0 +1,143 @@
+Start start {}
+
+Exec toRuntime_0 {
+    name = "models/CTCBD/toRuntime"
+}
+
+Exec merge_0 {
+    name = "models/DTCBD/merge"
+}
+
+Exec edit {
+    name = "models/CTCBD/edit"
+}
+
+Exec toRuntime {
+    name = "models/CTCBD/toRuntime"
+}
+
+Exec restartSim {
+    name = "models/DTCBD/restartSim"
+}
+
+Exec simulate {
+    name = "models/DTCBD/simulate"
+}
+
+Exec merge {
+    name = "models/DTCBD/merge"
+}
+
+Fork fork1 {}
+Fork fork2 {}
+
+Data traceability_D2P {
+    name = "traceability_D2P"
+    type = "formalisms/Tracability"
+}
+Data traceability_P2F {
+    name = "traceability_P2F"
+    type = "formalisms/Tracability"
+}
+
+Data design_model {
+    name = "design_model"
+    type = "formalisms/CTCBD/Design_MM"
+}
+
+Data partial_runtime_model {
+    name = "partial_runtime_model"
+    type = "formalisms/DTCBD/PartialRuntime_MM"
+}
+
+Data full_runtime_model {
+    name = "full_runtime_model"
+    type = "formalisms/DTCBD/FullRuntime_MM"
+}
+
+Next (start, toRuntime_0) {}
+Next (toRuntime_0, merge_0) {}
+Next (merge_0, fork1) {}
+Next (fork1, edit) {}
+Next (fork1, simulate) {}
+Next (edit, toRuntime) {}
+Next (toRuntime, fork2) {}
+Next (fork2, edit) {}
+Next (fork2, restartSim) {}
+Next (simulate, merge) {}
+Next (merge, simulate) {}
+
+Consumes (edit, design_model) {
+    name = "Design"
+}
+Produces (edit, design_model) {
+    name = "Design"
+}
+
+Consumes (toRuntime, design_model) {
+    name = "Design"
+}
+Consumes (toRuntime, partial_runtime_model) {
+    name = "PartialRuntime"
+}
+Consumes (toRuntime, traceability_D2P) {
+    name = "__traceability"
+}
+Produces (toRuntime, traceability_D2P) {
+    name = "__traceability"
+}
+Produces (toRuntime, partial_runtime_model) {
+    name = "PartialRuntime"
+}
+
+Consumes (toRuntime_0, design_model) {
+    name = "Design"
+}
+Consumes (toRuntime_0, traceability_D2P) {
+    name = "__traceability"
+}
+Produces (toRuntime_0, traceability_D2P) {
+    name = "__traceability"
+}
+Produces (toRuntime_0, partial_runtime_model) {
+    name = "PartialRuntime"
+}
+
+Consumes (merge, partial_runtime_model) {
+    name = "PartialRuntime"
+}
+Consumes (merge, full_runtime_model) {
+    name = "FullRuntime"
+}
+Consumes (merge, traceability_P2F) {
+    name = "__traceability"
+}
+Produces (merge, traceability_P2F) {
+    name = "__traceability"
+}
+Produces (merge, full_runtime_model) {
+    name = "NewFullRuntime"
+}
+
+Consumes (merge_0, partial_runtime_model) {
+    name = "PartialRuntime"
+}
+Consumes (merge_0, full_runtime_model) {
+    name = "FullRuntime"
+}
+Consumes (merge_0, traceability_P2F) {
+    name = "__traceability"
+}
+Produces (merge_0, traceability_P2F) {
+    name = "__traceability"
+}
+Produces (merge_0, full_runtime_model) {
+    name = "NewFullRuntime"
+}
+
+Consumes (simulate, full_runtime_model) {
+    name = "FullRuntime"
+}
+Produces (simulate, full_runtime_model) {
+    name = "FullRuntime"
+}

+ 61 - 0
models/CTCBD/metamodels/CTCBD_MM.mvc

@@ -0,0 +1,61 @@
+include "primitives.alh"
+
+SimpleAttribute Float {}
+SimpleAttribute String {}
+
+Class Block{}
+Class ICBlock{}
+
+Class ConstantBlock{
+    name = "Constant"
+    value : Float {
+        target_lower_cardinality = 1
+        target_upper_cardinality = 1
+    }
+}
+
+Class AdditionBlock{
+    name = "Addition"
+}
+Class NegatorBlock{
+    name = "Negator"
+}
+Class MultiplyBlock{
+    name = "Multiply"
+}
+Class InverseBlock{
+    name = "Inverse"
+}
+Class DelayBlock{
+    name = "Delay"
+}
+Class IntegratorBlock{
+    name = "Integrator"
+}
+Class DerivatorBlock{
+    name = "Derivator"
+}
+Class ProbeBlock{
+    name = "Probe"
+    name : String {
+        target_lower_cardinality = 1
+        target_upper_cardinality = 1
+    }
+}
+
+Association Link(Block, Block){}
+Association InitialCondition(Block, ICBlock){
+    source_lower_cardinality = 1
+    source_upper_cardinality = 1
+}
+
+Inheritance (ConstantBlock, Block){}
+Inheritance (AdditionBlock, Block){}
+Inheritance (NegatorBlock, Block){}
+Inheritance (MultiplyBlock, Block){}
+Inheritance (InverseBlock, Block){}
+Inheritance (ProbeBlock, Block){}
+Inheritance (ICBlock, Block){}
+Inheritance (DelayBlock, ICBlock){}
+Inheritance (IntegratorBlock, ICBlock){}
+Inheritance (DerivatorBlock, ICBlock){}

+ 54 - 0
models/CTCBD/models/spring.mvc

@@ -0,0 +1,54 @@
+ConstantBlock cte_k {
+    value = 1
+}
+
+ConstantBlock cte_g {
+    value = 10
+}
+
+ConstantBlock cte_m {
+    value = 1
+}
+
+ConstantBlock cte_v0 {
+    value = 1
+}
+
+ConstantBlock cte_y0 {
+    value = 20
+}
+
+MultiplyBlock m0 {}
+MultiplyBlock m1 {}
+MultiplyBlock m2 {}
+NegatorBlock n0 {}
+InverseBlock i0 {}
+AdditionBlock a0 {}
+IntegratorBlock int0 {}
+IntegratorBlock int1 {}
+
+ProbeBlock pv {
+    name = "velocity"
+}
+ProbeBlock py {
+    name = "displacement"
+}
+
+Link (cte_k, m0) {}
+Link (int1, m0) {}
+Link (cte_g, m1) {}
+Link (cte_m, m1) {}
+Link (cte_m, i0) {}
+Link (m0, n0) {}
+Link (n0, a0) {}
+Link (m1, a0) {}
+Link (i0, m2) {}
+Link (a0, m2) {}
+Link (m2, int0) {}
+Link (int0, int1) {}
+
+InitialCondition (cte_v0, int0) {}
+InitialCondition (cte_y0, int1) {}
+
+Link (int0, pv) {}
+Link (int1, py) {}

+ 180 - 0
models/CTCBD/transformations/render.alc

@@ -0,0 +1,180 @@
+include "primitives.alh"
+include "modelling.alh"
+include "object_operations.alh"
+include "utils.alh"
+
+Boolean function main(model : Element):
+	Element elements
+	String class
+	Element attrs
+	Element attr_keys
+	String attr_key
+	String group
+	String elem
+	Integer loc
+	Integer text_loc
+	Element related_groups
+	loc = 10
+
+	Element groups
+	groups = dict_create()
+
+	elements = allInstances(model, "rendered/Group")
+	while (set_len(elements) > 0):
+		group = set_pop(elements)
+		if (set_len(allIncomingAssociationInstances(model, group, "TracabilityClass")) == 0):
+			Element to_remove
+			String elem_to_remove
+			to_remove = allAssociationDestinations(model, group, "rendered/contains")
+			while (set_len(to_remove) > 0):
+				elem_to_remove = set_pop(to_remove)
+				if (read_type(model, elem_to_remove) == "rendered/Group"):
+					set_add(to_remove, elem_to_remove)
+				else:
+					model_delete_element(model, elem_to_remove)
+			model_delete_element(model, group)
+
+	elements = allInstances(model, "abstract/Block")
+	while (set_len(elements) > 0):
+		class = set_pop(elements)
+		
+		Integer x
+		Integer y
+		x = loc
+		y = 10
+
+		// Check if there is already an associated element
+		if (set_len(allOutgoingAssociationInstances(model, class, "TracabilityClass")) > 0):
+			// Yes, but is it still clean?
+			Boolean dirty
+			dirty = False
+
+			related_groups = allAssociationDestinations(model, class, "TracabilityClass")
+			while (set_len(related_groups) > 0):
+				group = set_pop(related_groups)
+				if (value_eq(read_attribute(model, group, "dirty"), True)):
+					// No, so mark all as dirty
+					dirty = True
+					break!
+				else:
+					// Yes, so just ignore this!
+					continue!
+
+			if (bool_not(dirty)):
+				dict_add(groups, class, group)
+				continue!
+			else:
+				related_groups = allAssociationDestinations(model, class, "TracabilityClass")
+				Element to_remove
+				String elem_to_remove
+				while (set_len(related_groups) > 0):
+					group = set_pop(related_groups)
+					to_remove = allAssociationDestinations(model, group, "rendered/contains")
+					x = create_value(read_attribute(model, group, "x"))
+					y = create_value(read_attribute(model, group, "y"))
+					while (set_len(to_remove) > 0):
+						elem_to_remove = set_pop(to_remove)
+						if (read_type(model, elem_to_remove) == "rendered/Group"):
+							set_add(to_remove, elem_to_remove)
+						else:
+							model_delete_element(model, elem_to_remove)
+					model_delete_element(model, group)
+
+		attr_keys = dict_keys(getAttributeList(model, class))
+		text_loc = 5
+
+		group = instantiate_node(model, "rendered/Group", "")
+		instantiate_attribute(model, group, "x", x)
+		instantiate_attribute(model, group, "y", y)
+		instantiate_attribute(model, group, "__asid", list_read(string_split_nr(class, "/", 1), 1))
+		instantiate_attribute(model, group, "layer", 0)
+		dict_add(groups, class, group)
+		loc = loc + 100
+
+		elem = instantiate_node(model, "rendered/Rectangle", "")
+		instantiate_attribute(model, elem, "x", 0)
+		instantiate_attribute(model, elem, "y", 0)
+		instantiate_attribute(model, elem, "height", 50)
+		instantiate_attribute(model, elem, "width", 50)
+		instantiate_attribute(model, elem, "lineWidth", 4) 
+		instantiate_attribute(model, elem, "lineColour", "black")
+		instantiate_attribute(model, elem, "fillColour", "white")
+		instantiate_attribute(model, elem, "layer", 1)
+		instantiate_link(model, "rendered/contains", "", group, elem)
+
+		elem = instantiate_node(model, "rendered/Text", "")
+		instantiate_attribute(model, elem, "x", 20)
+		instantiate_attribute(model, elem, "y", 20)
+		instantiate_attribute(model, elem, "lineWidth", 1)
+		instantiate_attribute(model, elem, "lineColour", "black")
+		
+		String type
+		type = read_type(model, class)
+		if (type == "abstract/ConstantBlock"):
+			if (element_neq(read_attribute(model, class, "value"), read_root())):
+				instantiate_attribute(model, elem, "text", cast_string(read_attribute(model, class, "value")))
+			else:
+				instantiate_attribute(model, elem, "text", "?")
+		elif (type == "abstract/AdditionBlock"):
+			instantiate_attribute(model, elem, "text", "+")
+		elif (type == "abstract/NegatorBlock"):
+			instantiate_attribute(model, elem, "text", "-")
+		elif (type == "abstract/MultiplyBlock"):
+			instantiate_attribute(model, elem, "text", "X")
+		elif (type == "abstract/InverseBlock"):
+			instantiate_attribute(model, elem, "text", "1/x")
+		elif (type == "abstract/DelayBlock"):
+			instantiate_attribute(model, elem, "text", "DELAY")
+		elif (type == "abstract/IntegratorBlock"):
+			instantiate_attribute(model, elem, "text", "1/s")
+		elif (type == "abstract/DerivatorBlock"):
+			instantiate_attribute(model, elem, "text", "dx")
+		elif (type == "abstract/ProbeBlock"):
+			instantiate_attribute(model, elem, "text", "PROBE")
+
+		instantiate_attribute(model, elem, "layer", 2)
+		instantiate_link(model, "rendered/contains", "", group, elem)
+
+		instantiate_link(model, "TracabilityClass", "", class, group)
+
+	// Flush all associations
+	elements = allInstances(model, "rendered/ConnectingLine")
+	while (set_len(elements) > 0):
+		class = set_pop(elements)
+		model_delete_element(model, class)
+
+	// Rerender associations
+	elements = allInstances(model, "abstract/Link")
+	while (set_len(elements) > 0):
+		class = set_pop(elements)
+
+		elem = instantiate_link(model, "rendered/ConnectingLine", "", groups[readAssociationSource(model, class)], groups[readAssociationDestination(model, class)])
+		instantiate_attribute(model, elem, "offsetSourceX", 25)
+		instantiate_attribute(model, elem, "offsetSourceY", 25)
+		instantiate_attribute(model, elem, "offsetTargetX", 25)
+		instantiate_attribute(model, elem, "offsetTargetY", 25)
+		instantiate_attribute(model, elem, "lineWidth", 1)
+		instantiate_attribute(model, elem, "lineColour", "black")
+		instantiate_attribute(model, elem, "arrow", True)
+		instantiate_attribute(model, elem, "__asid", list_read(string_split_nr(class, "/", 1), 1))
+		instantiate_attribute(model, elem, "layer", 0)
+		instantiate_link(model, "rendered/contains", "", group, elem)
+
+	// Rerender initial conditions
+	elements = allInstances(model, "abstract/InitialCondition")
+	while (set_len(elements) > 0):
+		class = set_pop(elements)
+
+		elem = instantiate_link(model, "rendered/ConnectingLine", "", groups[readAssociationSource(model, class)], groups[readAssociationDestination(model, class)])
+		instantiate_attribute(model, elem, "offsetSourceX", 25)
+		instantiate_attribute(model, elem, "offsetSourceY", 25)
+		instantiate_attribute(model, elem, "offsetTargetX", 25)
+		instantiate_attribute(model, elem, "offsetTargetY", 25)
+		instantiate_attribute(model, elem, "lineWidth", 1)
+		instantiate_attribute(model, elem, "lineColour", "red")
+		instantiate_attribute(model, elem, "arrow", True)
+		instantiate_attribute(model, elem, "__asid", list_read(string_split_nr(class, "/", 1), 1))
+		instantiate_attribute(model, elem, "layer", 0)
+		instantiate_link(model, "rendered/contains", "", group, elem)
+
+	return True!

+ 297 - 0
models/CTCBD/transformations/render.mvc

@@ -0,0 +1,297 @@
+include "primitives.alh"
+include "modelling.alh"
+include "object_operations.alh"
+
+Composite schedule {
+    {Contains} Success success {}
+    {Contains} Failure failure {}
+
+    {Contains} ForAll update_blocks {
+        LHS {
+            Pre_abstract/Block pre_update_0 {
+                label = "0"
+            }
+            Pre_rendered/Group pre_update_1 {
+                label = "1"
+            }
+            Pre_TracabilityLink (pre_update_0, pre_update_1){
+                label = "2"
+            }
+        }
+        RHS {
+            Post_abstract/Block post_update_0 {
+                label = "0"
+            }
+            Post_rendered/Group post_update_1 {
+                label = "1"
+                value___asid = $
+                    String function value(model : Element, name : String, mapping : Element):
+                        // Update the mapping!
+                        if (read_nr_out(string_split(mapping["0"], "/")) > 1):
+                            return list_read(string_split(mapping["0"], "/"), 1)!
+                        else:
+                            return mapping["0"]!
+                    $
+                value_x = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return read_attribute(model, name, "x")!
+                    $
+                value_y = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return read_attribute(model, name, "y")!
+                    $
+            }
+            Post_TracabilityLink (post_update_0, post_update_1){
+                label = "2"
+            }
+        }
+    }
+
+    {Contains} ForAll render_blocks {
+        LHS {
+            Pre_abstract/Block pre_block_0 {
+                label = "0"
+            }
+
+            constraint = $
+                Boolean function constraint(model : Element, mapping : Element):
+                    Element trace_links
+                    trace_links = allOutgoingAssociationInstances(model, mapping["0"], "TracabilityLink")
+                    if (read_nr_out(trace_links) > 0):
+                        log("Block already connected; ignoring!")
+                        return False!
+                    else:
+                        return True!
+                $
+        }
+        RHS {
+            Post_abstract/Block post_block_0 {
+                label = "0"
+            }
+            Post_rendered/Group post_block_1 {
+                label = "1"
+                value___asid = $
+                    String function value(model : Element, name : String, mapping : Element):
+                        if (list_len(string_split(mapping["0"], "/")) > 1):
+                            return list_read(string_split(mapping["0"], "/"), 1)!
+                        else:
+                            return mapping["0"]!
+                    $
+                value_x = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 0!
+                    $
+                value_y = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 0!
+                    $
+            }
+            Post_rendered/Rectangle post_block_2 {
+                label = "2"
+                value_x = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 0!
+                    $
+                value_y = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 0!
+                    $
+                value_width = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 30!
+                    $
+                value_height = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 30!
+                    $
+                value_lineWidth = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 2!
+                    $
+                value_lineColour = $
+                    String function value(model : Element, name : String, mapping : Element):
+                        return "black"!
+                    $
+                value_fillColour = $
+                    String function value(model : Element, name : String, mapping : Element):
+                        return "white"!
+                    $
+            }
+            Post_rendered/Text post_block_3 {
+                label = "3"
+                value_x = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 10!
+                    $
+                value_y = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 10!
+                    $
+                value_lineWidth = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 1!
+                    $
+                value_lineColour = $
+                    String function value(model : Element, name : String, mapping : Element):
+                        return "black"!
+                    $
+                value_text = $
+                    String function value(model : Element, name : String, mapping : Element):
+                        String type
+                        type = read_type(model, mapping["0"])
+                        if (type == "abstract/AdditionBlock"):
+                            return "+"!
+                        elif (type == "abstract/NegatorBlock"):
+                            return "-"!
+                        elif (type == "abstract/ConstantBlock"):
+                            return "c"!
+                        elif (type == "abstract/MultiplyBlock"):
+                            return "*"!
+                        elif (type == "abstract/InverseBlock"):
+                            return "/"!
+                        elif (type == "abstract/DerivatorBlock"):
+                            return "d/dx"!
+                        elif (type == "abstract/IntegratorBlock"):
+                            return "1/s"!
+                        elif (type == "abstract/DelayBlock"):
+                            return "DELAY"!
+                        elif (type == "abstract/ProbeBlock"):
+                            return "PROBE"!
+                        else:
+                            return ("Unknown type: " + type)!
+                    $
+            }
+            Post_rendered/contains (post_block_1, post_block_2) {
+                label = "4"
+            }
+            Post_rendered/contains (post_block_1, post_block_3) {
+                label = "5"
+            }
+
+            Post_TracabilityLink (post_block_0, post_block_1) {
+                label = "6"
+            }
+        }
+    }
+
+    {Contains} ForAll remove_connections {
+        LHS {
+            Pre_rendered/Line {
+                label = "0"
+            }
+        }
+        RHS {
+        }
+    }
+
+    {Contains} ForAll render_connections {
+        LHS {
+            Pre_abstract/Block pre_conn_0 {
+                label = "0"
+            }
+
+            Pre_abstract/Block pre_conn_1 {
+                label = "1"
+            }
+
+            Pre_abstract/Link (pre_conn_0, pre_conn_1){
+                label = "2"
+            }
+
+            Pre_rendered/Group pre_conn_3 {
+                label = "3"
+            }
+
+            Pre_rendered/Group pre_conn_4 {
+                label = "4"
+            }
+
+            Pre_TracabilityLink (pre_conn_0, pre_conn_3) {
+                label = "5"
+            }
+            Pre_TracabilityLink (pre_conn_1, pre_conn_4) {
+                label = "6"
+            }
+        }
+        RHS {
+            Post_abstract/Block post_conn_0 {
+                label = "0"
+            }
+
+            Post_abstract/Block post_conn_1 {
+                label = "1"
+            }
+
+            Post_abstract/Link (post_conn_0, post_conn_1){
+                label = "2"
+            }
+
+            Post_rendered/Group post_conn_3 {
+                label = "3"
+            }
+
+            Post_rendered/Group post_conn_4 {
+                label = "4"
+            }
+
+            Post_TracabilityLink (post_conn_0, post_conn_3) {
+                label = "5"
+            }
+            Post_TracabilityLink (post_conn_1, post_conn_4) {
+                label = "6"
+            }
+
+            Post_rendered/Line {
+                label = "7"
+                value___asid = $
+                    String function value(model : Element, name : String, mapping : Element):
+                        if (list_len(string_split(mapping["2"], "/")) > 1):
+                            return list_read(string_split(mapping["2"], "/"), 1)!
+                        else:
+                            return mapping["2"]!
+                    $
+                value_x = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return read_attribute(model, mapping["3"], "x")!
+                    $
+                value_y = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return read_attribute(model, mapping["3"], "y")!
+                    $
+                value_lineWidth = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 1!
+                    $
+                value_lineColour = $
+                    String function value(model : Element, name : String, mapping : Element):
+                        if (read_type(model, name) == "ICLink"):
+                            return "red"!
+                        else:
+                            return "black"!
+                    $
+                value_targetX = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return read_attribute(model, mapping["4"], "x")!
+                    $
+                value_targetY = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return read_attribute(model, mapping["4"], "y")!
+                    $
+            }
+        }
+    }
+}
+
+Initial (schedule, update_blocks) {}
+
+OnSuccess (update_blocks, render_blocks) {}
+OnFailure (update_blocks, render_blocks) {}
+
+OnSuccess (render_blocks, remove_connections) {}
+OnFailure (render_blocks, remove_connections) {}
+
+OnSuccess (remove_connections, render_connections) {}
+OnFailure (remove_connections, render_connections) {}
+
+OnSuccess (render_connections, success) {}
+OnFailure (render_connections, success) {}

+ 469 - 0
models/CTCBD/transformations/to_partial_runtime.mvc

@@ -0,0 +1,469 @@
+include "primitives.alh"
+include "modelling.alh"
+include "object_operations.alh"
+
+Composite schedule {
+    {Contains} Success success {}
+    {Contains} Atomic expand {
+        LHS {
+            Pre_Design/Block expand_lhs_0 {
+                label = "0"
+            }
+            Pre_Design/IntegratorBlock expand_lhs_1 {
+                label = "1"
+            }
+            Pre_Design/Block expand_lhs_2 {
+                label = "2"
+            }
+            Pre_Design/Block expand_lhs_3 {
+                label = "3"
+            }
+            Pre_Design/InitialCondition (expand_lhs_3, expand_lhs_1) {
+                label = "4"
+            }
+            Pre_Design/Link (expand_lhs_0, expand_lhs_1) {
+                label = "5"
+            }
+            Pre_Design/Link (expand_lhs_1, expand_lhs_2) {
+                label = "6"
+            }
+        }
+        RHS {
+            Post_Design/Block expand_rhs_0 {
+                label = "0"
+            }
+            Post_Design/IntegratorBlock expand_rhs_1 {
+                label = "1"
+            }
+            Post_Design/Block expand_rhs_2 {
+                label = "2"
+            }
+            Post_Design/Block expand_rhs_3 {
+                label = "3"
+            }
+            Post_Design/InitialCondition (expand_rhs_3, expand_rhs_1) {
+                label = "4"
+            }
+            Post_Design/Link (expand_rhs_0, expand_rhs_1) {
+                label = "5"
+            }
+            Post_Design/ConstantBlock expand_rhs_7 {
+                label = "7"
+                value_value = $
+                            Float function value(model : Element, name : String, mapping : Element):
+                                return 0.01!
+                        $
+            }
+            Post_Design/MultiplyBlock expand_rhs_8 {
+                label = "8"
+            }
+            Post_Design/AdditionBlock expand_rhs_9 {
+                label = "9"
+            }
+            Post_Design/DelayBlock expand_rhs_10 {
+                label = "10"
+                __id__ = $
+                            String function new_id(model : Element, mapping : Element):
+                                String result
+                                result = cast_string(list_read(string_split(mapping["1"], "/"), 1)) + "_" + cast_string(list_read(string_split(mapping["2"], "/"), 1)) + "_D1"
+                                log("Generate new delayblock with ID " + result)
+                                return result!
+                         $
+            }
+            Post_Design/DelayBlock expand_rhs_11 {
+                label = "11"
+                __id__ = $
+                            String function new_id(model : Element, mapping : Element):
+                                String result
+                                result = cast_string(list_read(string_split(mapping["1"], "/"), 1)) + "_" + cast_string(list_read(string_split(mapping["2"], "/"), 1)) + "_D2"
+                                log("Generate new delayblock with ID " + result)
+                                return result!
+                         $
+            }
+            Post_Design/ConstantBlock expand_rhs_12 {
+                label = "12"
+                value_value = $
+                            Float function value(model : Element, name : String, mapping : Element):
+                                return 0!
+                        $
+            }
+            Post_Design/Link (expand_rhs_0, expand_rhs_10) {
+                label = "13"
+            }
+            Post_Design/Link (expand_rhs_7, expand_rhs_8) {
+                label = "14"
+            }
+            Post_Design/Link (expand_rhs_10, expand_rhs_8) {
+                label = "15"
+            }
+            Post_Design/Link (expand_rhs_8, expand_rhs_9) {
+                label = "16"
+            }
+            Post_Design/Link (expand_rhs_9, expand_rhs_2) {
+                label = "17"
+            }
+            Post_Design/Link (expand_rhs_9, expand_rhs_11) {
+                label = "18"
+            }
+            Post_Design/Link (expand_rhs_11, expand_rhs_9) {
+                label = "19"
+            }
+            Post_Design/InitialCondition (expand_rhs_12, expand_rhs_10) {
+                label = "20"
+            }
+            Post_Design/InitialCondition (expand_rhs_3, expand_rhs_11) {
+                label = "21"
+            }
+        }
+    }
+
+    {Contains} ForAll optimize_inverse {
+        LHS {
+            Pre_Design/ConstantBlock opt_inv_lhs_0 {
+                label = "0"
+            }
+            Pre_Design/InverseBlock opt_inv_lhs_1 {
+                label = "1"
+            }
+            Pre_Design/Block opt_inv_lhs_2 {
+                label = "2"
+            }
+            Pre_Design/Link (opt_inv_lhs_0, opt_inv_lhs_1) {
+                label = "3"
+            }
+            Pre_Design/Link (opt_inv_lhs_1, opt_inv_lhs_2) {
+                label = "4"
+            }
+        }
+        RHS {
+            Post_Design/ConstantBlock opt_inv_rhs_0 {
+                label = "0"
+            }
+            Post_Design/InverseBlock opt_inv_rhs_1 {
+                label = "1"
+            }
+            Post_Design/Block opt_inv_rhs_2 {
+                label = "2"
+            }
+            Post_Design/Link (opt_inv_rhs_0, opt_inv_rhs_1) {
+                label = "3"
+            }
+            Post_Design/ConstantBlock opt_inv_rhs_5 {
+                label = "5"
+                value_value = $
+                            Float function value(model : Element, name : String, mapping : Element):
+                                return float_division(1, read_attribute(model, mapping["0"], "value"))!
+                        $
+            }
+            Post_Design/Link (opt_inv_rhs_5, opt_inv_rhs_2) {
+                label = "6"
+            }
+        }
+    }
+
+    {Contains} ForAll optimize_negator {
+        LHS {
+            Pre_Design/ConstantBlock opt_neg_lhs_0 {
+                label = "0"
+            }
+            Pre_Design/InverseBlock opt_neg_lhs_1 {
+                label = "1"
+            }
+            Pre_Design/Block opt_neg_lhs_2 {
+                label = "2"
+            }
+            Pre_Design/Link (opt_neg_lhs_0, opt_neg_lhs_1) {
+                label = "3"
+            }
+            Pre_Design/Link (opt_neg_lhs_1, opt_neg_lhs_2) {
+                label = "4"
+            }
+        }
+        RHS {
+            Post_Design/ConstantBlock opt_neg_rhs_0 {
+                label = "0"
+            }
+            Post_Design/InverseBlock opt_neg_rhs_1 {
+                label = "1"
+            }
+            Post_Design/Block opt_neg_rhs_2 {
+                label = "2"
+            }
+            Post_Design/Link (opt_neg_rhs_0, opt_neg_rhs_1) {
+                label = "3"
+            }
+            Post_Design/ConstantBlock opt_neg_rhs_5 {
+                label = "5"
+                value_value = $
+                            Float function value(model : Element, name : String, mapping : Element):
+                                return float_subtraction(0, read_attribute(model, mapping["0"], "value"))!
+                        $
+            }
+            Post_Design/Link (opt_neg_rhs_5, opt_neg_rhs_2) {
+                label = "6"
+            }
+        }
+    }
+
+    {Contains} ForAll remove_blocks {
+        LHS {
+            Pre_Design/Block rem_lhs_0 {
+                label = "0"
+                constraint = $
+                                Boolean function constraint(model : Element, name : String):
+                                    if (set_len(allOutgoingAssociationInstances(model, name, "Design/Link")) > 0):
+                                        return False!
+                                    elif (set_len(allOutgoingAssociationInstances(model, name, "Design/InitialCondition")) > 0):
+                                        return False!
+                                    else:
+                                        return read_type(model, name) != "Design/ProbeBlock"!
+                             $
+            }
+        }
+        RHS {}
+    }
+
+    {Contains} ForAll optimize_adder {
+        LHS {
+            Pre_Design/ConstantBlock opt_add_lhs_0 {
+                label = "0"
+            }
+            Pre_Design/ConstantBlock opt_add_lhs_1 {
+                label = "1"
+            }
+            Pre_Design/AdditionBlock opt_add_lhs_2 {
+                label = "2"
+            }
+            Pre_Design/Block opt_add_lhs_3 {
+                label = "3"
+            }
+            Pre_Design/Link (opt_add_lhs_0, opt_add_lhs_2) {
+                label = "4"
+            }
+            Pre_Design/Link (opt_add_lhs_1, opt_add_lhs_2) {
+                label = "5"
+            }
+            Pre_Design/Link (opt_add_lhs_2, opt_add_lhs_3) {
+                label = "6"
+            }
+        }
+        RHS {
+            Post_Design/ConstantBlock opt_add_rhs_0 {
+                label = "0"
+            }
+            Post_Design/ConstantBlock opt_add_rhs_1 {
+                label = "1"
+            }
+            Post_Design/AdditionBlock opt_add_rhs_2 {
+                label = "2"
+            }
+            Post_Design/Block opt_add_rhs_3 {
+                label = "3"
+            }
+            Post_Design/Link (opt_add_rhs_0, opt_add_rhs_2) {
+                label = "4"
+            }
+            Post_Design/Link (opt_add_rhs_1, opt_add_rhs_2) {
+                label = "5"
+            }
+            Post_Design/ConstantBlock opt_add_rhs_7 {
+                label = "7"
+                value_value = $
+                            Float function value(model : Element, name : String, mapping : Element):
+                                return float_addition(read_attribute(model, mapping["0"], "value"),  read_attribute(model, mapping["1"], "value"))!
+                        $
+            }
+            Post_Design/Link (opt_add_rhs_7, opt_add_rhs_3) {
+                label = "8"
+            }
+        }
+    }
+
+    {Contains} ForAll optimize_multiplier {
+        LHS {
+            Pre_Design/ConstantBlock opt_mult_lhs_0 {
+                label = "0"
+            }
+            Pre_Design/ConstantBlock opt_mult_lhs_1 {
+                label = "1"
+            }
+            Pre_Design/MultiplyBlock opt_mult_lhs_2 {
+                label = "2"
+            }
+            Pre_Design/Block opt_mult_lhs_3 {
+                label = "3"
+            }
+            Pre_Design/Link (opt_mult_lhs_0, opt_mult_lhs_2) {
+                label = "4"
+            }
+            Pre_Design/Link (opt_mult_lhs_1, opt_mult_lhs_2) {
+                label = "5"
+            }
+            Pre_Design/Link (opt_mult_lhs_2, opt_mult_lhs_3) {
+                label = "6"
+            }
+        }
+        RHS {
+            Post_Design/ConstantBlock opt_mult_rhs_0 {
+                label = "0"
+            }
+            Post_Design/ConstantBlock opt_mult_rhs_1 {
+                label = "1"
+            }
+            Post_Design/MultiplyBlock opt_mult_rhs_2 {
+                label = "2"
+            }
+            Post_Design/Block opt_mult_rhs_3 {
+                label = "3"
+            }
+            Post_Design/Link (opt_mult_rhs_0, opt_mult_rhs_2) {
+                label = "4"
+            }
+            Post_Design/Link (opt_mult_rhs_1, opt_mult_rhs_2) {
+                label = "5"
+            }
+            Post_Design/ConstantBlock opt_mult_rhs_7 {
+                label = "7"
+                value_value = $
+                            Float function value(model : Element, name : String, mapping : Element):
+                                return float_multiplication(read_attribute(model, mapping["0"], "value"), read_attribute(model, mapping["1"], "value"))!
+                        $
+            }
+            Post_Design/Link (opt_mult_rhs_7, opt_mult_rhs_3) {
+                label = "8"
+            }
+        }
+    }
+
+    {Contains} ForAll optimize_constant {
+        LHS {
+            Pre_Design/ConstantBlock opt_const_lhs_0 {
+                label = "0"
+            }
+            Pre_Design/Block opt_const_lhs_1 {
+                label = "1"
+            }
+            Pre_Design/ConstantBlock opt_const_lhs_2 {
+                label = "2"
+            }
+            Pre_Design/Block opt_const_lhs_3 {
+                label = "3"
+            }
+            Pre_Design/Link (opt_const_lhs_0, opt_const_lhs_1) {
+                label = "4"
+            }
+            Pre_Design/Link (opt_const_lhs_2, opt_const_lhs_3) {
+                label = "5"
+            }
+
+            constraint = $
+                            Boolean function constraint(model : Element, mapping : Element):
+                                return (cast_integer(cast_id(mapping["0"])) < cast_integer(cast_id(mapping["2"])))!
+                         $
+        }
+        RHS {
+            Post_Design/ConstantBlock opt_const_rhs_0 {
+                label = "0"
+            }
+            Post_Design/Block opt_const_rhs_1 {
+                label = "1"
+            }
+            Post_Design/ConstantBlock opt_const_rhs_2 {
+                label = "2"
+            }
+            Post_Design/Block opt_const_rhs_3 {
+                label = "3"
+            }
+            Post_Design/Link (opt_const_rhs_0, opt_const_rhs_1) {
+                label = "4"
+            }
+            Post_Design/Link (opt_const_rhs_0, opt_const_rhs_3) {
+                label = "6"
+            }
+        }
+    }
+
+    {Contains} Atomic map_to_partial {
+        LHS {}
+        RHS {
+            action = $
+                        Void function action(model : Element, mapping : Element):
+                            Element all_blocks
+                            String element_name
+                            String new_element_name
+                            String mm_type_name
+                            Element all_links
+
+                            all_blocks = allInstances(model, "Design/Block")
+                            while (set_len(all_blocks) > 0):
+                                element_name = set_pop(all_blocks)
+                                mm_type_name = "PartialRuntime/" + cast_string(list_read(string_split(read_type(model, element_name), "/"), 1))
+
+                                if (set_len(allOutgoingAssociationInstances(model, element_name, "D2P_block")) == 0):
+                                    // New design element, so create in partial runtime model as well
+                                    String new_name
+                                    if (mm_type_name == "PartialRuntime/DelayBlock"):
+                                        new_name = "PartialRuntime/" + string_replace(element_name, "/", "_")
+                                    else:
+                                        new_name = ""
+                                    new_element_name = instantiate_node(model, mm_type_name, new_name)
+                                    instantiate_link(model, "D2P_block", "", element_name, new_element_name)
+
+                                // Always update the value of attributes of PartialRuntime
+                                new_element_name = map_D2P(model, element_name)
+                                if (mm_type_name == "PartialRuntime/ConstantBlock"):
+                                    instantiate_attribute(model, new_element_name, "value", read_attribute(model, element_name, "value"))
+                                elif (mm_type_name == "PartialRuntime/ProbeBlock"):
+                                    instantiate_attribute(model, new_element_name, "name", read_attribute(model, element_name, "name"))
+
+                            all_blocks = allInstances(model, "PartialRuntime/Block")
+                            while (set_len(all_blocks) > 0):
+                                element_name = set_pop(all_blocks)
+                                if (set_len(allIncomingAssociationInstances(model, element_name, "D2P_block")) == 0):
+                                    // Old partial runtime element, so remove
+                                    model_delete_element(model, element_name)
+
+                            // Delete all existing links
+                            all_links = allInstances(model, "PartialRuntime/Link")
+                            while (set_len(all_links) > 0):
+                                model_delete_element(model, set_pop(all_links))
+
+                            all_links = allInstances(model, "PartialRuntime/InitialCondition")
+                            while (set_len(all_links) > 0):
+                                model_delete_element(model, set_pop(all_links))
+
+                            // Recreate all of them
+                            all_links = allInstances(model, "Design/Link")
+                            while (set_len(all_links) > 0):
+                                element_name = set_pop(all_links)
+                                instantiate_link(model, "PartialRuntime/Link", "", map_D2P(model, readAssociationSource(model, element_name)), map_D2P(model, readAssociationDestination(model, element_name)))
+
+                            all_links = allInstances(model, "Design/InitialCondition")
+                            while (set_len(all_links) > 0):
+                                element_name = set_pop(all_links)
+                                instantiate_link(model, "PartialRuntime/InitialCondition", "", map_D2P(model, readAssociationSource(model, element_name)), map_D2P(model, readAssociationDestination(model, element_name)))
+
+                            return!
+
+                        String function map_D2P(model : Element, name : String):
+                            Element destinations
+                            String pick
+
+                            destinations = allAssociationDestinations(model, name, "D2P_block")
+
+                            pick = name
+                            while (pick == name):
+                                pick = set_pop(destinations)
+
+                            return pick!
+                     $
+        }
+    }
+}
+
+Initial (schedule, expand) {}
+
+OnSuccess (expand, expand) {}
+OnFailure (expand, remove_blocks) {}
+OnSuccess (remove_blocks, map_to_partial) {}
+OnSuccess (map_to_partial, success) {}

+ 143 - 0
models/DTCBD/PM_live_modelling.mvc

@@ -0,0 +1,143 @@
+Start start {}
+
+Exec toRuntime_0 {
+    name = "models/DTCBD/toRuntime"
+}
+
+Exec merge_0 {
+    name = "models/DTCBD/merge"
+}
+
+Exec edit {
+    name = "models/DTCBD/edit"
+}
+
+Exec toRuntime {
+    name = "models/DTCBD/toRuntime"
+}
+
+Exec restartSim {
+    name = "models/DTCBD/restartSim"
+}
+
+Exec simulate {
+    name = "models/DTCBD/simulate"
+}
+
+Exec merge {
+    name = "models/DTCBD/merge"
+}
+
+Fork fork1 {}
+Fork fork2 {}
+
+Data traceability_D2P {
+    name = "traceability_D2P"
+    type = "formalisms/Tracability"
+}
+Data traceability_P2F {
+    name = "traceability_P2F"
+    type = "formalisms/Tracability"
+}
+
+Data design_model {
+    name = "design_model"
+    type = "formalisms/DTCBD/Design_MM"
+}
+
+Data partial_runtime_model {
+    name = "partial_runtime_model"
+    type = "formalisms/DTCBD/PartialRuntime_MM"
+}
+
+Data full_runtime_model {
+    name = "full_runtime_model"
+    type = "formalisms/DTCBD/FullRuntime_MM"
+}
+
+Next (start, toRuntime_0) {}
+Next (toRuntime_0, merge_0) {}
+Next (merge_0, fork1) {}
+Next (fork1, edit) {}
+Next (fork1, simulate) {}
+Next (edit, toRuntime) {}
+Next (toRuntime, fork2) {}
+Next (fork2, edit) {}
+Next (fork2, restartSim) {}
+Next (simulate, merge) {}
+Next (merge, simulate) {}
+
+Consumes (edit, design_model) {
+    name = "Design"
+}
+Produces (edit, design_model) {
+    name = "Design"
+}
+
+Consumes (toRuntime, design_model) {
+    name = "Design"
+}
+Consumes (toRuntime, partial_runtime_model) {
+    name = "PartialRuntime"
+}
+Consumes (toRuntime, traceability_D2P) {
+    name = "__traceability"
+}
+Produces (toRuntime, traceability_D2P) {
+    name = "__traceability"
+}
+Produces (toRuntime, partial_runtime_model) {
+    name = "PartialRuntime"
+}
+
+Consumes (toRuntime_0, design_model) {
+    name = "Design"
+}
+Consumes (toRuntime_0, traceability_D2P) {
+    name = "__traceability"
+}
+Produces (toRuntime_0, traceability_D2P) {
+    name = "__traceability"
+}
+Produces (toRuntime_0, partial_runtime_model) {
+    name = "PartialRuntime"
+}
+
+Consumes (merge, partial_runtime_model) {
+    name = "PartialRuntime"
+}
+Consumes (merge, full_runtime_model) {
+    name = "FullRuntime"
+}
+Consumes (merge, traceability_P2F) {
+    name = "__traceability"
+}
+Produces (merge, traceability_P2F) {
+    name = "__traceability"
+}
+Produces (merge, full_runtime_model) {
+    name = "NewFullRuntime"
+}
+
+Consumes (merge_0, partial_runtime_model) {
+    name = "PartialRuntime"
+}
+Consumes (merge_0, full_runtime_model) {
+    name = "FullRuntime"
+}
+Consumes (merge_0, traceability_P2F) {
+    name = "__traceability"
+}
+Produces (merge_0, traceability_P2F) {
+    name = "__traceability"
+}
+Produces (merge_0, full_runtime_model) {
+    name = "NewFullRuntime"
+}
+
+Consumes (simulate, full_runtime_model) {
+    name = "FullRuntime"
+}
+Produces (simulate, full_runtime_model) {
+    name = "FullRuntime"
+}

+ 53 - 0
models/DTCBD/metamodels/DTCBD_MM.mvc

@@ -0,0 +1,53 @@
+include "primitives.alh"
+
+SimpleAttribute Float {}
+SimpleAttribute String {}
+
+Class Block{}
+Class ICBlock{}
+
+Class ConstantBlock{
+    name = "Constant"
+    value : Float {
+        target_lower_cardinality = 1
+        target_upper_cardinality = 1
+    }
+}
+
+Class AdditionBlock{
+    name = "Addition"
+}
+Class NegatorBlock{
+    name = "Negator"
+}
+Class MultiplyBlock{
+    name = "Multiply"
+}
+Class InverseBlock{
+    name = "Inverse"
+}
+Class DelayBlock{
+    name = "Delay"
+}
+Class ProbeBlock{
+    name = "Probe"
+    name : String {
+        target_lower_cardinality = 1
+        target_upper_cardinality = 1
+    }
+}
+
+Association Link(Block, Block){}
+Association InitialCondition(Block, ICBlock){
+    source_lower_cardinality = 1
+    source_upper_cardinality = 1
+}
+
+Inheritance (ConstantBlock, Block){}
+Inheritance (AdditionBlock, Block){}
+Inheritance (NegatorBlock, Block){}
+Inheritance (MultiplyBlock, Block){}
+Inheritance (InverseBlock, Block){}
+Inheritance (ProbeBlock, Block){}
+Inheritance (ICBlock, Block){}
+Inheritance (DelayBlock, ICBlock){}

+ 76 - 0
models/DTCBD/metamodels/DTCBD_MM_partial_runtime.mvc

@@ -0,0 +1,76 @@
+include "primitives.alh"
+
+Class Float {}
+Class String {}
+
+Class Block{
+    signal : Float {
+        target_lower_cardinality = 1
+        target_upper_cardinality = 1
+    }
+}
+Class ICBlock{
+    last_in : Float {
+        target_lower_cardinality = 0
+        target_upper_cardinality = 1
+    }
+}
+
+Class ConstantBlock{
+    value : Float {
+        target_lower_cardinality = 1
+        target_upper_cardinality = 1
+    }
+}
+
+Class ProbeBlock{
+    name : String {
+        target_lower_cardinality = 1
+        target_upper_cardinality = 1
+    }
+}
+
+Class AdditionBlock{}
+Class NegatorBlock{}
+Class MultiplyBlock{}
+Class InverseBlock{}
+Class DelayBlock{}
+Class IntegratorBlock{
+    last_out : Float {
+        target_lower_cardinality = 0
+        target_upper_cardinality = 1
+    }
+}
+
+Class DerivatorBlock{}
+Class Time{
+    lower_cardinality = 1
+    upper_cardinality = 1
+
+    start_time : Float {
+        target_lower_cardinality = 1
+        target_upper_cardinality = 1
+    }
+
+    current_time : Float {
+        target_lower_cardinality = 1
+        target_upper_cardinality = 1
+    }
+}
+
+Association Link(Block, Block){}
+Association InitialCondition(Block, ICBlock){
+    source_lower_cardinality = 0
+    source_upper_cardinality = 1
+}
+
+Inheritance (ConstantBlock, Block){}
+Inheritance (AdditionBlock, Block){}
+Inheritance (NegatorBlock, Block){}
+Inheritance (MultiplyBlock, Block){}
+Inheritance (InverseBlock, Block){}
+Inheritance (ICBlock, Block){}
+Inheritance (DelayBlock, ICBlock){}
+Inheritance (DerivatorBlock, ICBlock){}
+Inheritance (IntegratorBlock, ICBlock){}
+Inheritance (ProbeBlock, Block){}

+ 76 - 0
models/DTCBD/metamodels/DTCBD_MM_runtime.mvc

@@ -0,0 +1,76 @@
+include "primitives.alh"
+
+Class Float {}
+Class String {}
+
+Class Block{
+    signal : Float {
+        target_lower_cardinality = 1
+        target_upper_cardinality = 1
+    }
+}
+Class ICBlock{
+    last_in : Float {
+        target_lower_cardinality = 0
+        target_upper_cardinality = 1
+    }
+}
+
+Class ConstantBlock{
+    value : Float {
+        target_lower_cardinality = 1
+        target_upper_cardinality = 1
+    }
+}
+
+Class ProbeBlock{
+    name : String {
+        target_lower_cardinality = 1
+        target_upper_cardinality = 1
+    }
+}
+
+Class AdditionBlock{}
+Class NegatorBlock{}
+Class MultiplyBlock{}
+Class InverseBlock{}
+Class DelayBlock{}
+Class IntegratorBlock{
+    last_out : Float {
+        target_lower_cardinality = 0
+        target_upper_cardinality = 1
+    }
+}
+
+Class DerivatorBlock{}
+Class Time{
+    lower_cardinality = 1
+    upper_cardinality = 1
+
+    start_time : Float {
+        target_lower_cardinality = 1
+        target_upper_cardinality = 1
+    }
+
+    current_time : Float {
+        target_lower_cardinality = 1
+        target_upper_cardinality = 1
+    }
+}
+
+Association Link(Block, Block){}
+Association InitialCondition(Block, ICBlock){
+    source_lower_cardinality = 0
+    source_upper_cardinality = 1
+}
+
+Inheritance (ConstantBlock, Block){}
+Inheritance (AdditionBlock, Block){}
+Inheritance (NegatorBlock, Block){}
+Inheritance (MultiplyBlock, Block){}
+Inheritance (InverseBlock, Block){}
+Inheritance (ICBlock, Block){}
+Inheritance (DelayBlock, ICBlock){}
+Inheritance (DerivatorBlock, ICBlock){}
+Inheritance (IntegratorBlock, ICBlock){}
+Inheritance (ProbeBlock, Block){}

+ 20 - 0
models/DTCBD/models/simple_equation.mvc

@@ -0,0 +1,20 @@
+ConstantBlock cte_x {
+    value = 1
+}
+DelayBlock delay {}
+AdditionBlock adder {}
+NegatorBlock neg {}
+ProbeBlock y {
+    name = "y"
+}
+ProbeBlock z {
+    name = "z"
+}
+
+InitialCondition (cte_x, delay){}
+Link (cte_x, adder) {}
+Link (adder, delay) {}
+Link (adder, y) {}
+Link (adder, neg) {}
+Link (delay, z) {}
+Link (neg, adder) {}

+ 61 - 0
models/DTCBD/transformations/merge.alc

@@ -0,0 +1,61 @@
+include "primitives.alh"
+include "modelling.alh"
+include "object_operations.alh"
+include "conformance_scd.alh"
+include "utils.alh"
+include "typing.alh"
+include "mini_modify.alh"
+
+String function map_P2F(model : Element, name : String):
+	Element destinations
+	String pick
+
+	destinations = allAssociationDestinations(model, name, "P2F_block")
+
+	pick = name
+	while (pick == name):
+		pick = set_pop(destinations)
+
+	return pick!
+
+Boolean function main(model : Element):
+	Element all_blocks
+	String element_name
+	Float current_time
+	String time_block
+
+	log("Merging!")
+	all_blocks = allInstances(model, "PartialRuntime/Block")
+	while (set_len(all_blocks) > 0):
+		element_name = set_pop(all_blocks)
+		if (set_len(allOutgoingAssociationInstances(model, element_name, "P2F_block")) > 0):
+			// Element already exists in full, so copy existing attributes
+            if (is_nominal_instance(model, element_name, "PartialRuntime/ICBlock")):
+                instantiate_attribute(model, element_name, "last_in", read_attribute(model, map_P2F(model, element_name), "last_in"))
+            // instantiate_attribute(model, element_name, "signal", read_attribute(model, map_P2F(model, element_name), "signal"))
+		else:
+			// Element doesn't exist, so initialize with 0.0
+            instantiate_attribute(model, element_name, "signal", 0.0)
+			instantiate_link(model, "P2F_block", "", element_name, element_name)
+
+	if (set_len(allInstances(model, "FullRuntime/Time")) > 0):
+		// Time already exists, so copy the value
+		current_time = read_attribute(model, set_pop(allInstances(model, "FullRuntime/Time")), "current_time")
+	else:
+		// No time yet, so initialize
+		current_time = 0.0
+
+	time_block = instantiate_node(model, "PartialRuntime/Time", "")
+	instantiate_attribute(model, time_block, "start_time", current_time)
+	instantiate_attribute(model, time_block, "current_time", current_time)
+
+	Element all_elements
+	String elem
+	all_elements = dict_keys(model["model"])
+	while (set_len(all_elements) > 0):
+		elem = set_pop(all_elements)
+		if (string_startswith(read_type(model, elem), "PartialRuntime/")):
+			retype(model, elem, "NewFullRuntime/" + cast_string(list_read(string_split_nr(read_type(model, elem), "/", 1), 1)))
+
+	log("Merge OK")
+	return True!

+ 180 - 0
models/DTCBD/transformations/render.alc

@@ -0,0 +1,180 @@
+include "primitives.alh"
+include "modelling.alh"
+include "object_operations.alh"
+include "utils.alh"
+
+Boolean function main(model : Element):
+	Element elements
+	String class
+	Element attrs
+	Element attr_keys
+	String attr_key
+	String group
+	String elem
+	Integer loc
+	Integer text_loc
+	Element related_groups
+	loc = 10
+
+	Element groups
+	groups = dict_create()
+
+	elements = allInstances(model, "rendered/Group")
+	while (set_len(elements) > 0):
+		group = set_pop(elements)
+		if (set_len(allIncomingAssociationInstances(model, group, "TracabilityClass")) == 0):
+			Element to_remove
+			String elem_to_remove
+			to_remove = allAssociationDestinations(model, group, "rendered/contains")
+			while (set_len(to_remove) > 0):
+				elem_to_remove = set_pop(to_remove)
+				if (read_type(model, elem_to_remove) == "rendered/Group"):
+					set_add(to_remove, elem_to_remove)
+				else:
+					model_delete_element(model, elem_to_remove)
+			model_delete_element(model, group)
+
+	elements = allInstances(model, "abstract/Block")
+	while (set_len(elements) > 0):
+		class = set_pop(elements)
+		
+		Integer x
+		Integer y
+		x = loc
+		y = 10
+
+		// Check if there is already an associated element
+		if (set_len(allOutgoingAssociationInstances(model, class, "TracabilityClass")) > 0):
+			// Yes, but is it still clean?
+			Boolean dirty
+			dirty = False
+
+			related_groups = allAssociationDestinations(model, class, "TracabilityClass")
+			while (set_len(related_groups) > 0):
+				group = set_pop(related_groups)
+				if (value_eq(read_attribute(model, group, "dirty"), True)):
+					// No, so mark all as dirty
+					dirty = True
+					break!
+				else:
+					// Yes, so just ignore this!
+					continue!
+
+			if (bool_not(dirty)):
+				dict_add(groups, class, group)
+				continue!
+			else:
+				related_groups = allAssociationDestinations(model, class, "TracabilityClass")
+				Element to_remove
+				String elem_to_remove
+				while (set_len(related_groups) > 0):
+					group = set_pop(related_groups)
+					to_remove = allAssociationDestinations(model, group, "rendered/contains")
+					x = create_value(read_attribute(model, group, "x"))
+					y = create_value(read_attribute(model, group, "y"))
+					while (set_len(to_remove) > 0):
+						elem_to_remove = set_pop(to_remove)
+						if (read_type(model, elem_to_remove) == "rendered/Group"):
+							set_add(to_remove, elem_to_remove)
+						else:
+							model_delete_element(model, elem_to_remove)
+					model_delete_element(model, group)
+
+		attr_keys = dict_keys(getAttributeList(model, class))
+		text_loc = 5
+
+		group = instantiate_node(model, "rendered/Group", "")
+		instantiate_attribute(model, group, "x", x)
+		instantiate_attribute(model, group, "y", y)
+		instantiate_attribute(model, group, "__asid", list_read(string_split_nr(class, "/", 1), 1))
+		instantiate_attribute(model, group, "layer", 0)
+		dict_add(groups, class, group)
+		loc = loc + 100
+
+		elem = instantiate_node(model, "rendered/Rectangle", "")
+		instantiate_attribute(model, elem, "x", 0)
+		instantiate_attribute(model, elem, "y", 0)
+		instantiate_attribute(model, elem, "height", 50)
+		instantiate_attribute(model, elem, "width", 50)
+		instantiate_attribute(model, elem, "lineWidth", 4) 
+		instantiate_attribute(model, elem, "lineColour", "black")
+		instantiate_attribute(model, elem, "fillColour", "white")
+		instantiate_attribute(model, elem, "layer", 1)
+		instantiate_link(model, "rendered/contains", "", group, elem)
+
+		elem = instantiate_node(model, "rendered/Text", "")
+		instantiate_attribute(model, elem, "x", 20)
+		instantiate_attribute(model, elem, "y", 20)
+		instantiate_attribute(model, elem, "lineWidth", 1)
+		instantiate_attribute(model, elem, "lineColour", "black")
+		
+		String type
+		type = read_type(model, class)
+		if (type == "abstract/ConstantBlock"):
+			if (element_neq(read_attribute(model, class, "value"), read_root())):
+				instantiate_attribute(model, elem, "text", cast_string(read_attribute(model, class, "value")))
+			else:
+				instantiate_attribute(model, elem, "text", "?")
+		elif (type == "abstract/AdditionBlock"):
+			instantiate_attribute(model, elem, "text", "+")
+		elif (type == "abstract/NegatorBlock"):
+			instantiate_attribute(model, elem, "text", "-")
+		elif (type == "abstract/MultiplyBlock"):
+			instantiate_attribute(model, elem, "text", "X")
+		elif (type == "abstract/InverseBlock"):
+			instantiate_attribute(model, elem, "text", "1/x")
+		elif (type == "abstract/DelayBlock"):
+			instantiate_attribute(model, elem, "text", "DELAY")
+		elif (type == "abstract/IntegratorBlock"):
+			instantiate_attribute(model, elem, "text", "1/s")
+		elif (type == "abstract/DerivatorBlock"):
+			instantiate_attribute(model, elem, "text", "dx")
+		elif (type == "abstract/ProbeBlock"):
+			instantiate_attribute(model, elem, "text", "PROBE")
+
+		instantiate_attribute(model, elem, "layer", 2)
+		instantiate_link(model, "rendered/contains", "", group, elem)
+
+		instantiate_link(model, "TracabilityClass", "", class, group)
+
+	// Flush all associations
+	elements = allInstances(model, "rendered/ConnectingLine")
+	while (set_len(elements) > 0):
+		class = set_pop(elements)
+		model_delete_element(model, class)
+
+	// Rerender associations
+	elements = allInstances(model, "abstract/Link")
+	while (set_len(elements) > 0):
+		class = set_pop(elements)
+
+		elem = instantiate_link(model, "rendered/ConnectingLine", "", groups[readAssociationSource(model, class)], groups[readAssociationDestination(model, class)])
+		instantiate_attribute(model, elem, "offsetSourceX", 25)
+		instantiate_attribute(model, elem, "offsetSourceY", 25)
+		instantiate_attribute(model, elem, "offsetTargetX", 25)
+		instantiate_attribute(model, elem, "offsetTargetY", 25)
+		instantiate_attribute(model, elem, "lineWidth", 1)
+		instantiate_attribute(model, elem, "lineColour", "black")
+		instantiate_attribute(model, elem, "arrow", True)
+		instantiate_attribute(model, elem, "__asid", list_read(string_split_nr(class, "/", 1), 1))
+		instantiate_attribute(model, elem, "layer", 0)
+		instantiate_link(model, "rendered/contains", "", group, elem)
+
+	// Rerender initial conditions
+	elements = allInstances(model, "abstract/InitialCondition")
+	while (set_len(elements) > 0):
+		class = set_pop(elements)
+
+		elem = instantiate_link(model, "rendered/ConnectingLine", "", groups[readAssociationSource(model, class)], groups[readAssociationDestination(model, class)])
+		instantiate_attribute(model, elem, "offsetSourceX", 25)
+		instantiate_attribute(model, elem, "offsetSourceY", 25)
+		instantiate_attribute(model, elem, "offsetTargetX", 25)
+		instantiate_attribute(model, elem, "offsetTargetY", 25)
+		instantiate_attribute(model, elem, "lineWidth", 1)
+		instantiate_attribute(model, elem, "lineColour", "red")
+		instantiate_attribute(model, elem, "arrow", True)
+		instantiate_attribute(model, elem, "__asid", list_read(string_split_nr(class, "/", 1), 1))
+		instantiate_attribute(model, elem, "layer", 0)
+		instantiate_link(model, "rendered/contains", "", group, elem)
+
+	return True!

+ 297 - 0
models/DTCBD/transformations/render.mvc

@@ -0,0 +1,297 @@
+include "primitives.alh"
+include "modelling.alh"
+include "object_operations.alh"
+
+Composite schedule {
+    {Contains} Success success {}
+    {Contains} Failure failure {}
+
+    {Contains} ForAll update_blocks {
+        LHS {
+            Pre_abstract/Block pre_update_0 {
+                label = "0"
+            }
+            Pre_rendered/Group pre_update_1 {
+                label = "1"
+            }
+            Pre_TracabilityLink (pre_update_0, pre_update_1){
+                label = "2"
+            }
+        }
+        RHS {
+            Post_abstract/Block post_update_0 {
+                label = "0"
+            }
+            Post_rendered/Group post_update_1 {
+                label = "1"
+                value___asid = $
+                    String function value(model : Element, name : String, mapping : Element):
+                        // Update the mapping!
+                        if (read_nr_out(string_split(mapping["0"], "/")) > 1):
+                            return list_read(string_split(mapping["0"], "/"), 1)!
+                        else:
+                            return mapping["0"]!
+                    $
+                value_x = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return read_attribute(model, name, "x")!
+                    $
+                value_y = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return read_attribute(model, name, "y")!
+                    $
+            }
+            Post_TracabilityLink (post_update_0, post_update_1){
+                label = "2"
+            }
+        }
+    }
+
+    {Contains} ForAll render_blocks {
+        LHS {
+            Pre_abstract/Block pre_block_0 {
+                label = "0"
+            }
+
+            constraint = $
+                Boolean function constraint(model : Element, mapping : Element):
+                    Element trace_links
+                    trace_links = allOutgoingAssociationInstances(model, mapping["0"], "TracabilityLink")
+                    if (read_nr_out(trace_links) > 0):
+                        log("Block already connected; ignoring!")
+                        return False!
+                    else:
+                        return True!
+                $
+        }
+        RHS {
+            Post_abstract/Block post_block_0 {
+                label = "0"
+            }
+            Post_rendered/Group post_block_1 {
+                label = "1"
+                value___asid = $
+                    String function value(model : Element, name : String, mapping : Element):
+                        if (list_len(string_split(mapping["0"], "/")) > 1):
+                            return list_read(string_split(mapping["0"], "/"), 1)!
+                        else:
+                            return mapping["0"]!
+                    $
+                value_x = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 0!
+                    $
+                value_y = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 0!
+                    $
+            }
+            Post_rendered/Rectangle post_block_2 {
+                label = "2"
+                value_x = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 0!
+                    $
+                value_y = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 0!
+                    $
+                value_width = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 30!
+                    $
+                value_height = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 30!
+                    $
+                value_lineWidth = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 2!
+                    $
+                value_lineColour = $
+                    String function value(model : Element, name : String, mapping : Element):
+                        return "black"!
+                    $
+                value_fillColour = $
+                    String function value(model : Element, name : String, mapping : Element):
+                        return "white"!
+                    $
+            }
+            Post_rendered/Text post_block_3 {
+                label = "3"
+                value_x = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 10!
+                    $
+                value_y = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 10!
+                    $
+                value_lineWidth = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 1!
+                    $
+                value_lineColour = $
+                    String function value(model : Element, name : String, mapping : Element):
+                        return "black"!
+                    $
+                value_text = $
+                    String function value(model : Element, name : String, mapping : Element):
+                        String type
+                        type = read_type(model, mapping["0"])
+                        if (type == "abstract/AdditionBlock"):
+                            return "+"!
+                        elif (type == "abstract/NegatorBlock"):
+                            return "-"!
+                        elif (type == "abstract/ConstantBlock"):
+                            return "c"!
+                        elif (type == "abstract/MultiplyBlock"):
+                            return "*"!
+                        elif (type == "abstract/InverseBlock"):
+                            return "/"!
+                        elif (type == "abstract/DerivatorBlock"):
+                            return "d/dx"!
+                        elif (type == "abstract/IntegratorBlock"):
+                            return "1/s"!
+                        elif (type == "abstract/DelayBlock"):
+                            return "DELAY"!
+                        elif (type == "abstract/ProbeBlock"):
+                            return "PROBE"!
+                        else:
+                            return ("Unknown type: " + type)!
+                    $
+            }
+            Post_rendered/contains (post_block_1, post_block_2) {
+                label = "4"
+            }
+            Post_rendered/contains (post_block_1, post_block_3) {
+                label = "5"
+            }
+
+            Post_TracabilityLink (post_block_0, post_block_1) {
+                label = "6"
+            }
+        }
+    }
+
+    {Contains} ForAll remove_connections {
+        LHS {
+            Pre_rendered/Line {
+                label = "0"
+            }
+        }
+        RHS {
+        }
+    }
+
+    {Contains} ForAll render_connections {
+        LHS {
+            Pre_abstract/Block pre_conn_0 {
+                label = "0"
+            }
+
+            Pre_abstract/Block pre_conn_1 {
+                label = "1"
+            }
+
+            Pre_abstract/Link (pre_conn_0, pre_conn_1){
+                label = "2"
+            }
+
+            Pre_rendered/Group pre_conn_3 {
+                label = "3"
+            }
+
+            Pre_rendered/Group pre_conn_4 {
+                label = "4"
+            }
+
+            Pre_TracabilityLink (pre_conn_0, pre_conn_3) {
+                label = "5"
+            }
+            Pre_TracabilityLink (pre_conn_1, pre_conn_4) {
+                label = "6"
+            }
+        }
+        RHS {
+            Post_abstract/Block post_conn_0 {
+                label = "0"
+            }
+
+            Post_abstract/Block post_conn_1 {
+                label = "1"
+            }
+
+            Post_abstract/Link (post_conn_0, post_conn_1){
+                label = "2"
+            }
+
+            Post_rendered/Group post_conn_3 {
+                label = "3"
+            }
+
+            Post_rendered/Group post_conn_4 {
+                label = "4"
+            }
+
+            Post_TracabilityLink (post_conn_0, post_conn_3) {
+                label = "5"
+            }
+            Post_TracabilityLink (post_conn_1, post_conn_4) {
+                label = "6"
+            }
+
+            Post_rendered/Line {
+                label = "7"
+                value___asid = $
+                    String function value(model : Element, name : String, mapping : Element):
+                        if (list_len(string_split(mapping["2"], "/")) > 1):
+                            return list_read(string_split(mapping["2"], "/"), 1)!
+                        else:
+                            return mapping["2"]!
+                    $
+                value_x = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return read_attribute(model, mapping["3"], "x")!
+                    $
+                value_y = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return read_attribute(model, mapping["3"], "y")!
+                    $
+                value_lineWidth = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return 1!
+                    $
+                value_lineColour = $
+                    String function value(model : Element, name : String, mapping : Element):
+                        if (read_type(model, name) == "ICLink"):
+                            return "red"!
+                        else:
+                            return "black"!
+                    $
+                value_targetX = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return read_attribute(model, mapping["4"], "x")!
+                    $
+                value_targetY = $
+                    Integer function value(model : Element, name : String, mapping : Element):
+                        return read_attribute(model, mapping["4"], "y")!
+                    $
+            }
+        }
+    }
+}
+
+Initial (schedule, update_blocks) {}
+
+OnSuccess (update_blocks, render_blocks) {}
+OnFailure (update_blocks, render_blocks) {}
+
+OnSuccess (render_blocks, remove_connections) {}
+OnFailure (render_blocks, remove_connections) {}
+
+OnSuccess (remove_connections, render_connections) {}
+OnFailure (remove_connections, render_connections) {}
+
+OnSuccess (render_connections, success) {}
+OnFailure (render_connections, success) {}

+ 612 - 0
models/DTCBD/transformations/simulate.alc

@@ -0,0 +1,612 @@
+include "primitives.alh"
+include "modelling.alh"
+include "object_operations.alh"
+include "conformance_scd.alh"
+include "io.alh"
+include "metamodels.alh"
+include "mini_modify.alh"
+include "utils.alh"
+
+Boolean function main(model : Element):
+	log("Start DTCBD simulation!")
+	String cmd
+	Boolean running
+	Element schedule_init
+	Element schedule_run
+	Element schedule
+	Float current_time
+
+	String time
+	time = set_pop(allInstances(model, "FullRuntime/Time"))
+	current_time = read_attribute(model, time, "current_time")
+	log("Fetching time now: " + cast_value(current_time))
+
+	schedule_init = create_schedule(model)
+	schedule_run = read_root()
+
+	Element nodes
+	Element inputs
+	String node
+	nodes = allInstances(model, "FullRuntime/Block")
+	inputs = dict_create()
+	while (set_len(nodes) > 0):
+		node = set_pop(nodes)
+		dict_add(inputs, node, allAssociationOrigins(model, node, "FullRuntime/Link"))
+
+	while (bool_not(has_input())):
+		if (read_attribute(model, time, "start_time") == read_attribute(model, time, "current_time")):
+			schedule = schedule_init
+		else:
+			if (element_eq(schedule_run, read_root())):
+				schedule_run = create_schedule(model)
+			schedule = schedule_run
+		current_time = step_simulation(model, schedule, current_time, inputs)
+
+	instantiate_attribute(model, time, "current_time", current_time)
+	log("CLOSE")
+	output("CLOSE")
+	return True!
+
+Element function create_schedule(model : Element):
+	// Create nice graph first
+	Element nodes
+	Element successors
+	String element_name
+	Element incoming_links
+	Element all_blocks
+
+	nodes = allInstances(model, "FullRuntime/Block")
+	successors = set_create()
+	while (set_len(nodes) > 0):
+		element_name = set_pop(nodes)
+		log("Block " + element_name + " : " + read_type(model, element_name))
+
+		if (is_nominal_instance(model, element_name, "FullRuntime/ICBlock")):
+			if (bool_not(is_physical_float(read_attribute(model, element_name, "last_in")))):
+				incoming_links = allIncomingAssociationInstances(model, element_name, "FullRuntime/InitialCondition")
+			else:
+				incoming_links = create_node()
+		else:
+			incoming_links = allIncomingAssociationInstances(model, element_name, "FullRuntime/Link")
+
+		while (set_len(incoming_links) > 0):
+			String source
+			source = readAssociationSource(model, set_pop(incoming_links))
+			list_append(successors, create_tuple(source, element_name))
+			log("Found edge: " + source + " --> " + element_name)
+
+	Element values
+	values = create_node()
+	//dict_add(values, "model", model)
+	//dict_add(values, "S", create_node())
+	//dict_add(values, "index", 0)
+	//dict_add(values, "indices", create_node())
+	//dict_add(values, "lowlink", create_node())
+	//dict_add(values, "onStack", create_node())
+	//dict_add(values, "successors", successors)
+	//dict_add(values, "predecessors", predecessors)
+	//dict_add(values, "SCC", create_node())
+
+	dict_add(values, "edges", successors)
+	dict_add(values, "nodes", allInstances(model, "FullRuntime/Block"))
+	dict_add(values, "dfsCounter", 0)
+	dict_add(values, "orderNumber", dict_create())
+	dict_add(values, "visited_topSort", set_create())
+	dict_add(values, "unvisited_strongComp", set_create())
+
+	log("Toposort")
+	//nodes = get_topolist(values)
+	//while (list_len(nodes) > 0):
+	//	log("Strong connect")
+	//	strongconnect(list_pop_final(nodes), values)
+
+	dict_overwrite(values, "SCC", strongComp(values))
+
+	//nodes = allInstances(model, "FullRuntime/Block")
+	//while (set_len(nodes) > 0):
+	//	strongconnect(set_pop(nodes), values)
+
+	log("OK")
+
+	return values["SCC"]!
+
+Void function topSort(values : Element):
+	Element nodes_copy
+	String node
+
+	// for node in graph:
+	//     node.visited = False
+	dict_overwrite(values, "visited_topSort", set_create())
+
+	// for node in graph:
+	//     if not node.visited:
+	//          dfsLabelling(node)
+	nodes_copy = set_copy(values["nodes"])
+	while (set_len(nodes_copy) > 0):
+		node = set_pop(nodes_copy)
+		if (bool_not(set_in(values["visited_topSort"], node))):
+			dfsLabelling(values, node)
+	log("Order: " + dict_to_string(values["orderNumber"]))
+
+	return!
+
+Element function get_successors(values : Element, node : String, key : String):
+	Element edges
+	Element result
+	String edge
+
+	result = set_create()
+	edges = list_copy(values[key])
+	while (list_len(edges) > 0):
+		edge = list_pop_final(edges)
+		if (cast_string(edge[0]) == node):
+			set_add(result, edge[1])
+
+	return result!
+
+Void function dfsLabelling(values : Element, node : String):
+	Element successors
+	String successor
+
+	// if not node.visited
+	if (bool_not(set_in(values["visited_topSort"], node))):
+		// node.visited = True
+		set_add(values["visited_topSort"], node)
+
+		// for neighbour in node.out_neighbours:
+		//     dfsLabelling(neighbour, graph)
+		successors = get_successors(values, node, "edges")
+		while (set_len(successors) > 0):
+			successor = set_pop(successors)
+			dfsLabelling(values, successor)
+
+		// node.orderNumber = dfsCounter
+		dict_overwrite(values["orderNumber"], node, values["dfsCounter"])
+
+		// dfsCounter += 1
+		dict_overwrite(values, "dfsCounter", cast_integer(values["dfsCounter"]) + 1)
+
+	return !
+
+Element function dfsCollect(values : Element, start_node : String):
+	Element result
+	String successor
+	Element successors
+
+	result = set_create()
+
+	// if not node.visited
+	if (set_in(values["unvisited_strongComp"], start_node)):
+		list_append(result, start_node)
+		// node.visited = True
+		set_remove(values["unvisited_strongComp"], start_node)
+
+		// for neighbour in node.out_neighbours:
+		//     dfsLabelling(neighbour, graph)
+		successors = get_successors(values, start_node, "rev_edges")
+		while (set_len(successors) > 0):
+			successor = set_pop(successors)
+			list_extend(result, dfsCollect(values, successor))
+
+	return result!
+
+String function highest_orderNumber(values : Element):
+	Integer max
+	String max_element
+	Element search
+	String elem
+
+	max = -1
+	search = set_copy(values["unvisited_strongComp"])
+	while (set_len(search) > 0):
+		elem = set_pop(search)
+		if (cast_integer(values["orderNumber"][elem]) > max):
+			max = values["orderNumber"][elem]
+			max_element = elem
+		
+	return max_element!
+
+Element function reverse_edges(edges : Element):
+	Element result
+	Element elem
+
+	result = list_create()
+	edges = list_copy(edges)
+	while (list_len(edges) > 0):
+		elem = list_pop_final(edges)
+		list_append(result, create_tuple(elem[1], elem[0]))
+	return result!
+
+Element function strongComp(values : Element):
+	Element graph
+	Element sccs
+	String start_node
+	Element strong_components
+	Element component
+
+	sccs = list_create()
+
+	topSort(values)
+
+	dict_overwrite(values, "unvisited_strongComp", set_copy(values["nodes"]))
+
+	dict_overwrite(values, "rev_edges", reverse_edges(values["edges"]))
+	strong_components = list_create()
+
+	while (set_len(values["unvisited_strongComp"]) > 0):
+		start_node = highest_orderNumber(values)
+
+		component = dfsCollect(values, start_node)
+		list_append(sccs, component)
+		log("Got strong component: " + list_to_string(component))
+
+	return sccs!
+
+Element function get_topolist(values : Element):
+	Element result
+	Element predecessors
+	Element remaining
+	String current_element
+	Element cur_predecessors
+
+	result = list_create()
+	predecessors = dict_copy(values["predecessors"])
+
+	while (dict_len(predecessors) > 0):
+		remaining = dict_keys(predecessors)
+		while (set_len(remaining) > 0):
+			current_element = set_pop(remaining)
+			cur_predecessors = predecessors[current_element]
+			if (set_len(set_overlap(list_to_set(result), cur_predecessors)) == set_len(cur_predecessors)):
+				// All predecessors of this node have already been visited
+				dict_delete(predecessors, current_element)
+				remaining = dict_keys(predecessors)
+				list_append(result, current_element)
+
+	return result!
+
+Integer function min(a : Integer, b : Integer):
+	if (a < b):
+		return a!
+	else:
+		return b!
+
+Void function strongconnect(v : String, values : Element):
+	// if (v.index is undefined) then
+	//    strongconnect(V)
+	if (dict_in(values["indices"], v)):
+		return!
+
+	// v.index := index
+	dict_overwrite(values["indices"], v, values["index"])
+	// v.lowlink := indwx
+	dict_overwrite(values["lowlink"], v, values["index"])
+	// index := index + 1
+	dict_overwrite(values, "index", cast_integer(values["index"]) + 1)
+
+	// S.push(v)
+	list_append(values["S"], v)
+	// v.onStack := true
+	dict_overwrite(values["onStack"], v, True)
+	
+	Element successors
+	String w
+	successors = values["successors"][v]
+	while (set_len(successors) > 0):
+		// for each (v, w) in E do
+		w = set_pop(successors)
+		// if (w.index is undefined) then
+		if (bool_not(dict_in(values["indices"], w))):
+			// strongconnect(w)
+			strongconnect(w, values)
+			// v.lowlink := min(v.lowlink, w.lowlink)
+			dict_overwrite(values["lowlink"], v, min(values["lowlink"][v], values["lowlink"][w]))
+		elif (dict_in(values["onStack"], w)):
+			// else if (w.onStack)
+			if (values["onStack"][w]):
+				// v.lowlink := min(v.lowlink, w.index)
+				dict_overwrite(values["lowlink"], v, min(values["lowlink"][v], values["indices"][w]))
+	
+	// if (v.lowlink == v.index) then
+	if (value_eq(values["lowlink"][v], values["indices"][v])):
+		Element scc
+		// Start a new strongly connected component
+		scc = create_node()
+		// It will always differ now
+		// w := S.pop()
+		w = list_pop_final(values["S"])
+		// w.onStack = false
+		dict_overwrite(values["onStack"], w, False)
+		// add w to current strongly connected component
+		list_append(scc, w)
+		// while w != v
+		while (w != v):
+			// w := S.pop()
+			w = list_pop_final(values["S"])
+			// w.onStack = false
+			dict_overwrite(values["onStack"], w, False)
+			// add w to current strongly connected component
+			list_append(scc, w)
+		// output the current strongly connected component
+		list_insert(values["SCC"], scc, 0)
+		log("Found new SCC: " + list_to_string(scc))
+	return!
+
+Boolean function solve_scc(model : Element, scc : Element):
+	Element m
+	Integer i
+	Integer j
+	String block
+	String blocktype
+	Element incoming
+	String selected
+	Float constant
+	Element t
+
+	// Construct the matrix first, with as many rows as there are variables
+	// Number of columns is 1 higher
+	i = 0
+	m = create_node()
+	while (i < read_nr_out(scc)):
+		j = 0
+		t = create_node()
+		while (j < (read_nr_out(scc) + 1)):
+			list_append(t, 0.0)
+			j = j + 1
+		list_append(m, t)
+		i = i + 1
+
+	// Matrix initialized to 0.0
+	i = 0
+	while (i < read_nr_out(scc)):
+		// First element of scc
+		block = scc[i]
+		blocktype = read_type(model, block)
+
+		// First write 1 in the current block
+		dict_overwrite(m[i], i, 1.0)
+
+		// Now check all blocks that are incoming
+		if (blocktype == "FullRuntime/AdditionBlock"):
+			constant = 0.0
+		elif (blocktype == "FullRuntime/MultiplyBlock"):
+			constant = 1.0
+
+		incoming = allIncomingAssociationInstances(model, block, "FullRuntime/Link")
+
+		Integer index_to_write_constant
+		index_to_write_constant = -1
+		while (read_nr_out(incoming) > 0):
+			selected = readAssociationSource(model, set_pop(incoming))
+
+			if (list_in(scc, selected)):
+				// Part of the loop, so in the index of selected in scc
+				// Five options:
+				if (blocktype == "FullRuntime/AdditionBlock"):
+					// 1) AdditionBlock
+					// Add the negative of this signal, which is as of yet unknown
+					// x = y + z --> x - y - z = 0
+					dict_overwrite(m[i], list_index_of(scc, selected), -1.0)
+				elif (blocktype == "FullRuntime/MultiplyBlock"):
+					// 2) MultiplyBlock
+					if (index_to_write_constant != -1):
+						return False!
+					index_to_write_constant = list_index_of(scc, selected)
+				elif (blocktype == "FullRuntime/NegatorBlock"):
+					// 3) NegatorBlock
+					// Add the positive of the signal, which is as of yet unknown
+					dict_overwrite(m[i], list_index_of(scc, selected), 1.0)
+				elif (blocktype == "FullRuntime/DelayBlock"):
+					// 5) DelayBlock
+					// Just copies a single value
+					dict_overwrite(m[i], list_index_of(scc, selected), -1.0)
+				else:
+					// Block that cannot be handled
+					return False!
+			else:
+				// A constant, which we can assume is already computed and thus usable
+				if (blocktype == "FullRuntime/AdditionBlock"):
+					constant = constant + cast_float(read_attribute(model, selected, "signal"))
+					dict_overwrite(m[i], read_nr_out(scc), constant)
+				elif (blocktype == "FullRuntime/MultiplyBlock"):
+					constant = constant * cast_float(read_attribute(model, selected, "signal"))
+					// Not written to constant part, as multiplies a variable
+
+				// Any other block is impossible:
+				// * Constant would never be part of a SCC
+				// * Delay would never get an incoming constant
+				// * Negation and Inverse only get 1 input, which is a variable in a loop
+				// * Integrator and Derivator never get an incoming constant
+
+		if (index_to_write_constant != -1):
+			dict_overwrite(m[i], index_to_write_constant, -constant)
+
+		i = i + 1
+
+	// Constructed a complete matrix, so we can start!
+	log(matrix2string(m))
+
+	// Solve matrix now
+	eliminateGaussJordan(m)
+
+	// Now go over m and set signals for each element
+	// Assume that everything worked out...
+	i = 0
+	while (i < read_nr_out(m)):
+		block = scc[i]
+		instantiate_attribute(model, block, "signal", m[i][read_nr_out(scc)])
+		log((("Solved " + block) + " to ") + cast_string(m[i][read_nr_out(scc)]))
+		i = i + 1
+
+	return True!
+
+Integer function list_index_of(lst : Element, elem : Element):
+	Integer i
+	i = 0
+	while (i < read_nr_out(lst)):
+		if (value_eq(list_read(lst, i), elem)):
+			return i!
+		else:
+			i = i + 1
+	return -1!
+
+Float function step_simulation(model : Element, schedule : Element, time : Float, inputs : Element):
+	Float signal
+	Element incoming
+	String selected
+	String block
+	String elem
+	String blocktype
+	Element memory_blocks
+	Integer i
+	Float delta_t
+	Element scc
+
+	delta_t = 0.1
+
+	memory_blocks = set_create()
+	i = 0
+	while (i < list_len(schedule)):
+		scc = list_read(schedule, i)
+		i = i + 1
+
+		if (list_len(scc) > 1):
+			if (bool_not(solve_scc(model, scc))):
+				log("ALGEBRAIC_LOOP")
+				output("ALGEBRAIC_LOOP")
+				return time!
+		else:
+			block = list_read(scc, 0)
+
+			// Execute "block"
+			blocktype = read_type(model, block)
+			//log("Execute block " + block + " : " + blocktype)
+			incoming = set_copy(inputs[block])
+			if (blocktype == "FullRuntime/ConstantBlock"):
+				signal = cast_float(read_attribute(model, block, "value"))
+			elif (blocktype == "FullRuntime/AdditionBlock"):
+				signal = 0.0
+				while (set_len(incoming) > 0):
+					selected = set_pop(incoming)
+					signal = signal + cast_float(read_attribute(model, selected, "signal"))
+			elif (blocktype == "FullRuntime/MultiplyBlock"):
+				signal = 1.0
+				while (set_len(incoming) > 0):
+					selected = set_pop(incoming)
+					signal = signal * cast_float(read_attribute(model, selected, "signal"))
+			elif (blocktype == "FullRuntime/NegatorBlock"):
+				signal = 0.0
+				while (set_len(incoming) > 0):
+					selected = set_pop(incoming)
+					signal = float_neg(cast_float(read_attribute(model, selected, "signal")))
+			elif (blocktype == "FullRuntime/InverseBlock"):
+				signal = 0.0
+				while (set_len(incoming) > 0):
+					selected = set_pop(incoming)
+					signal = float_division(1.0, cast_float(read_attribute(model, selected, "signal")))
+			elif (blocktype == "FullRuntime/DelayBlock"):
+				signal = 0.0
+				if (bool_not(is_physical_float(read_attribute(model, block, "last_in")))):
+					// No memory yet, so use initial condition
+					incoming = allAssociationOrigins(model, block, "FullRuntime/InitialCondition")
+					while (set_len(incoming) > 0):
+						selected = set_pop(incoming)
+						signal = cast_float(read_attribute(model, selected, "signal"))
+				else:
+					signal = read_attribute(model, block, "last_in")
+				set_add(memory_blocks, block)
+			elif (blocktype == "FullRuntime/ProbeBlock"):
+				signal = 0.0
+				while (set_len(incoming) > 0):
+					signal = cast_float(read_attribute(model, set_pop(incoming), "signal"))
+					output(cast_string(time) + " " + cast_string(read_attribute(model, block, "name")) + " " + cast_string(signal))
+					log(cast_string(time) + " " + cast_string(read_attribute(model, block, "name")) + " " + cast_string(signal))
+
+			instantiate_attribute(model, block, "signal", signal)
+	
+	while (set_len(memory_blocks) > 0):
+		block = set_pop(memory_blocks)
+		// Update memory
+		incoming = set_copy(inputs[block])
+		while (set_len(incoming) > 0):
+			selected = set_pop(incoming)
+			instantiate_attribute(model, block, "last_in", cast_float(read_attribute(model, selected, "signal")))
+
+	// Increase simulation time
+	return time + delta_t!
+
+Void function eliminateGaussJordan(m : Element):
+	Integer i
+	Integer j
+	Integer f
+	Integer g
+	Boolean searching
+	Element t
+	Float divisor
+
+	i = 0
+	j = 0
+
+	while (i < read_nr_out(m)):
+		// Make sure pivot m[i][j] != 0, swapping if necessary
+		while (cast_float(m[i][j]) == 0.0):
+			// Is zero, so find row which is not zero
+			f = i + 1
+			searching = True
+			while (searching):
+				if (f >= read_nr_out(m)):
+					// No longer any rows left, so just increase column counter
+					searching = False
+					j = j + 1
+				else:
+					if (cast_float(m[f][j]) == 0.0):
+						// Also zero, so continue
+						f = f + 1
+					else:
+						// Found non-zero, so swap row
+						t = cast_float(m[f])
+						dict_overwrite(m, f, cast_float(m[i]))
+						dict_overwrite(m, i, t)
+						searching = False
+			// If we have increased j, we will just start the loop again (possibly), as m[i][j] might be zero again
+
+		// Pivot in m[i][j] guaranteed to not be 0
+		// Now divide complete row by value of m[i][j] to make it equal 1
+		f = j
+		divisor = cast_float(m[i][j])
+		while (f < read_nr_out(m[i])):
+			dict_overwrite(m[i], f, float_division(cast_float(m[i][f]), divisor))
+			f = f + 1
+
+		// Eliminate all rows in the j-th column, except the i-th row
+		f = 0
+		while (f < read_nr_out(m)):
+			if (bool_not(f == i)):
+				g = j
+				divisor = cast_float(m[f][j])
+				while (g < read_nr_out(m[f])):
+					dict_overwrite(m[f], g, cast_float(m[f][g]) - (divisor * cast_float(m[i][g])))
+					g = g + 1
+			f = f + 1
+
+		// Increase row and column
+		i = i + 1
+		j = j + 1
+
+	return !
+
+String function matrix2string(m : Element):
+	Integer i
+	Integer j
+	String result
+
+	result = ""
+	i = 0
+	while (i < read_nr_out(m)):
+		j = 0
+		while (j < read_nr_out(m[i])):
+			result = result + cast_string(m[i][j]) + ", "
+			j = j + 1
+		i = i + 1
+		result = result + "\n"
+	return result!

+ 69 - 0
models/DTCBD/transformations/to_runtime.alc

@@ -0,0 +1,69 @@
+include "primitives.alh"
+include "modelling.alh"
+include "object_operations.alh"
+
+String function map_D2P(model : Element, name : String):
+	Element destinations
+	String pick
+
+	destinations = allAssociationDestinations(model, name, "D2P_block")
+
+	pick = name
+	while (pick == name):
+		pick = set_pop(destinations)
+
+	return pick!
+
+Boolean function main(model : Element):
+	Element all_blocks
+	String element_name
+	String new_element_name
+	String mm_type_name
+	Element all_links
+
+	all_blocks = allInstances(model, "Design/Block")
+	while (set_len(all_blocks) > 0):
+		element_name = set_pop(all_blocks)
+		mm_type_name = "PartialRuntime/" + cast_string(list_read(string_split(read_type(model, element_name), "/"), 1))
+
+		if (set_len(allOutgoingAssociationInstances(model, element_name, "D2P_block")) == 0):
+			// New design element, so create in partial runtime model as well
+			new_element_name = instantiate_node(model, mm_type_name, "")
+			instantiate_link(model, "D2P_block", "", element_name, new_element_name)
+
+		// Always update the value of attributes of PartialRuntime
+		new_element_name = map_D2P(model, element_name)
+		if (mm_type_name == "PartialRuntime/ConstantBlock"):
+            instantiate_attribute(model, new_element_name, "value", read_attribute(model, element_name, "value"))
+		elif (mm_type_name == "PartialRuntime/ProbeBlock"):
+            instantiate_attribute(model, new_element_name, "name", read_attribute(model, element_name, "name"))
+
+	all_blocks = allInstances(model, "PartialRuntime/Block")
+	while (set_len(all_blocks) > 0):
+		element_name = set_pop(all_blocks)
+		if (set_len(allIncomingAssociationInstances(model, element_name, "D2P_block")) == 0):
+			// Old partial runtime element, so remove
+			model_delete_element(model, element_name)
+
+	// Delete all existing links
+	all_links = allInstances(model, "PartialRuntime/Link")
+	while (set_len(all_links) > 0):
+		model_delete_element(model, set_pop(all_links))
+
+	all_links = allInstances(model, "PartialRuntime/InitialCondition")
+	while (set_len(all_links) > 0):
+		model_delete_element(model, set_pop(all_links))
+
+	// Recreate all of them
+    all_links = allInstances(model, "Design/Link")
+    while (set_len(all_links) > 0):
+        element_name = set_pop(all_links)
+        instantiate_link(model, "PartialRuntime/Link", "", map_D2P(model, readAssociationSource(model, element_name)), map_D2P(model, readAssociationDestination(model, element_name)))
+
+    all_links = allInstances(model, "Design/InitialCondition")
+    while (set_len(all_links) > 0):
+        element_name = set_pop(all_links)
+        instantiate_link(model, "PartialRuntime/InitialCondition", "", map_D2P(model, readAssociationSource(model, element_name)), map_D2P(model, readAssociationDestination(model, element_name)))
+
+
+	return True!

+ 143 - 0
models/FiniteStateAutomata/PM_live_modelling.mvc

@@ -0,0 +1,143 @@
+Start start {}
+
+Exec toRuntime_0 {
+    name = "models/FSA/toRuntime"
+}
+
+Exec merge_0 {
+    name = "models/FSA/merge"
+}
+
+Exec edit {
+    name = "models/FSA/edit"
+}
+
+Exec toRuntime {
+    name = "models/FSA/toRuntime"
+}
+
+Exec restartSim {
+    name = "models/FSA/restartSim"
+}
+
+Exec simulate {
+    name = "models/FSA/simulate"
+}
+
+Exec merge {
+    name = "models/FSA/merge"
+}
+
+Fork fork1 {}
+Fork fork2 {}
+
+Data traceability_D2P {
+    name = "traceability_D2P"
+    type = "formalisms/Tracability"
+}
+Data traceability_P2F {
+    name = "traceability_P2F"
+    type = "formalisms/Tracability"
+}
+
+Data design_model {
+    name = "design_model"
+    type = "formalisms/FSA/Design_MM"
+}
+
+Data partial_runtime_model {
+    name = "partial_runtime_model"
+    type = "formalisms/FSA/PartialRuntime_MM"
+}
+
+Data full_runtime_model {
+    name = "full_runtime_model"
+    type = "formalisms/FSA/FullRuntime_MM"
+}
+
+Next (start, toRuntime_0) {}
+Next (toRuntime_0, merge_0) {}
+Next (merge_0, fork1) {}
+Next (fork1, edit) {}
+Next (fork1, simulate) {}
+Next (edit, toRuntime) {}
+Next (toRuntime, fork2) {}
+Next (fork2, edit) {}
+Next (fork2, restartSim) {}
+Next (simulate, merge) {}
+Next (merge, simulate) {}
+
+Consumes (edit, design_model) {
+    name = "Design"
+}
+Produces (edit, design_model) {
+    name = "Design"
+}
+
+Consumes (toRuntime, design_model) {
+    name = "Design"
+}
+Consumes (toRuntime, partial_runtime_model) {
+    name = "PartialRuntime"
+}
+Consumes (toRuntime, traceability_D2P) {
+    name = "__traceability"
+}
+Produces (toRuntime, traceability_D2P) {
+    name = "__traceability"
+}
+Produces (toRuntime, partial_runtime_model) {
+    name = "PartialRuntime"
+}
+
+Consumes (toRuntime_0, design_model) {
+    name = "Design"
+}
+Consumes (toRuntime_0, traceability_D2P) {
+    name = "__traceability"
+}
+Produces (toRuntime_0, traceability_D2P) {
+    name = "__traceability"
+}
+Produces (toRuntime_0, partial_runtime_model) {
+    name = "PartialRuntime"
+}
+
+Consumes (merge, partial_runtime_model) {
+    name = "PartialRuntime"
+}
+Consumes (merge, full_runtime_model) {
+    name = "FullRuntime"
+}
+Consumes (merge, traceability_P2F) {
+    name = "__traceability"
+}
+Produces (merge, traceability_P2F) {
+    name = "__traceability"
+}
+Produces (merge, full_runtime_model) {
+    name = "NewFullRuntime"
+}
+
+Consumes (merge_0, partial_runtime_model) {
+    name = "PartialRuntime"
+}
+Consumes (merge_0, full_runtime_model) {
+    name = "FullRuntime"
+}
+Consumes (merge_0, traceability_P2F) {
+    name = "__traceability"
+}
+Produces (merge_0, traceability_P2F) {
+    name = "__traceability"
+}
+Produces (merge_0, full_runtime_model) {
+    name = "NewFullRuntime"
+}
+
+Consumes (simulate, full_runtime_model) {
+    name = "FullRuntime"
+}
+Produces (simulate, full_runtime_model) {
+    name = "FullRuntime"
+}

+ 15 - 0
models/FiniteStateAutomata/metamodels/FSA_MM.mvc

@@ -0,0 +1,15 @@
+include "primitives.alh"
+
+SimpleAttribute String {}
+SimpleAttribute Boolean {}
+
+Class State {
+    name = "State"
+    name : String
+    initial : Boolean
+}
+
+Association Transition (State, State) {
+    trigger? : String {}
+    raise? : String {}
+}

+ 15 - 0
models/FiniteStateAutomata/metamodels/FSA_MM_partial_runtime.mvc

@@ -0,0 +1,15 @@
+include "primitives.alh"
+
+Class String {}
+Class Boolean {}
+
+Class State {
+    name = "State"
+    name : String
+    initial : Boolean
+}
+
+Association Transition (State, State) {
+    trigger? : String {}
+    raise? : String {}
+}

+ 21 - 0
models/FiniteStateAutomata/metamodels/FSA_MM_runtime.mvc

@@ -0,0 +1,21 @@
+include "primitives.alh"
+
+Class String {}
+Class Boolean {}
+Class Float {}
+
+Class Time {
+    current_time : Float
+}
+
+Class State {
+    name = "State"
+    name : String
+    current : Boolean
+    initial : Boolean
+}
+
+Association Transition (State, State) {
+    trigger? : String {}
+    raise? : String {}
+}

+ 27 - 0
models/FiniteStateAutomata/models/alarm.mvc

@@ -0,0 +1,27 @@
+State idle {
+    name = "idle"
+    initial = True
+}
+State armed {
+    name = "armed"
+    initial = False
+}
+State detected {
+    name = "detected"
+    initial = False
+}
+
+Transition (idle, armed) {
+    trigger = "Arm"
+}
+Transition (armed, idle) {
+    trigger = "Disable"
+}
+Transition (armed, detected) {
+    trigger = "PersonDetected"
+    raise = "SoundAlarm"
+}
+Transition (detected, armed) {
+    trigger = "CorrectCode"
+    raise = "DisableAlarm"
+}

+ 108 - 0
models/FiniteStateAutomata/transformations/merge.alc

@@ -0,0 +1,108 @@
+include "primitives.alh"
+include "modelling.alh"
+include "object_operations.alh"
+include "conformance_scd.alh"
+include "utils.alh"
+include "typing.alh"
+include "mini_modify.alh"
+
+String function map_P2F(model : Element, name : String):
+	Element destinations
+	String pick
+
+	destinations = allAssociationDestinations(model, name, "P2F_state")
+
+	pick = name
+	while (pick == name):
+		pick = set_pop(destinations)
+
+	return pick!
+
+Boolean function main(model : Element):
+	Element all_states
+	String element_name
+	Boolean found_current
+	Boolean flag_initial
+	String new_current
+
+	found_current = False
+	new_current = read_root()
+
+	if (set_len(allInstances(model, "FullRuntime/State")) == 0):
+		// No execution in full runtime, so just flag the initial state
+		flag_initial = True
+		log("Searching for new initial state...")
+
+		// And add a new time
+		element_name = instantiate_node(model, "NewFullRuntime/Time", "")
+		instantiate_attribute(model, element_name, "current_time", 0.0)
+	else:
+		flag_initial = False
+		log("No searching for state!")
+
+		// Copy the time though
+		element_name = instantiate_node(model, "NewFullRuntime/Time", "")
+		instantiate_attribute(model, element_name, "current_time", read_attribute(model, set_pop(allInstances(model, "FullRuntime/Time")), "current_time"))
+		log("Time copied OK")
+
+	log("Reading existing data")
+	all_states = allInstances(model, "PartialRuntime/State")
+	while (set_len(all_states) > 0):
+		element_name = set_pop(all_states)
+		if (set_len(allOutgoingAssociationInstances(model, element_name, "P2F_state")) > 0):
+			// Element already exists in full, so check whether this is the current state
+			log("Found existing state")
+			if (read_attribute(model, map_P2F(model, element_name), "current")):
+				found_current = True
+				new_current = element_name
+		else:
+			// New state, so assume that it is not current
+			log("Read value: " + cast_value(read_attribute(model, element_name, "initial")))
+			if (bool_and(flag_initial, read_attribute(model, element_name, "initial"))):
+				log("FOUND IT!")
+				new_current = element_name
+			instantiate_link(model, "P2F_state", "", element_name, element_name)
+	
+	log("Deleting elements...")
+	all_states = allInstances(model, "NewFullRuntime/State")
+	while (set_len(all_states) > 0):
+		element_name = set_pop(all_states)
+		model_delete_element(model, element_name)
+
+	log("Copying elements...")
+	Element all_elements
+	String elem
+	all_elements = dict_keys(model["model"])
+	while (set_len(all_elements) > 0):
+		elem = set_pop(all_elements)
+		if (string_startswith(read_type(model, elem), "PartialRuntime/")):
+			retype(model, elem, "NewFullRuntime/" + cast_string(list_read(string_split_nr(read_type(model, elem), "/", 1), 1)))
+
+			if (read_type(model, elem) == "NewFullRuntime/State"):
+				instantiate_attribute(model, elem, "current", elem == new_current)
+
+	log("Setting current state...")
+	String new_state
+	if (found_current == False):
+		if (False):
+			// Prompt for new state
+			output("FIX_NEW_STATE")
+			new_state = input()
+			all_states = allInstances(model, "NewFullRuntime/State")
+			while (set_len(all_states) > 0):
+				element_name = set_pop(all_states)
+				if (value_eq(read_attribute(model, element_name, "name"), new_state)):
+					instantiate_attribute(model, element_name, "current", True)
+					break!
+		else:
+			// Reset to initial
+			log("Resetting to initial state!")
+			all_states = allInstances(model, "NewFullRuntime/State")
+			while (set_len(all_states) > 0):
+				element_name = set_pop(all_states)
+				if (value_eq(read_attribute(model, element_name, "initial"), True)):
+					log("Found initial state: " + cast_value(read_attribute(model, element_name, "name")))
+					instantiate_attribute(model, element_name, "current", True)
+					break!
+	log("DONE!")
+	return True!

+ 62 - 0
models/FiniteStateAutomata/transformations/simulate.alc

@@ -0,0 +1,62 @@
+include "primitives.alh"
+include "modelling.alh"
+include "object_operations.alh"
+include "conformance_scd.alh"
+include "io.alh"
+include "metamodels.alh"
+include "mini_modify.alh"
+
+Boolean function main(model : Element):
+	String input_value
+	Float start_time
+	String current_state
+	String old_state
+	Element transitions
+	String transition
+
+	start_time = time() - cast_float(read_attribute(model, set_pop(allInstances(model, "FullRuntime/Time")), "current_time"))
+
+	Element all_states
+	String element_name
+	all_states = allInstances(model, "FullRuntime/State")
+	while (set_len(all_states) > 0):
+		element_name = set_pop(all_states)
+		log("Check " + cast_value(read_attribute(model, element_name, "name")))
+		log("  Current: " + cast_value(read_attribute(model, element_name, "current")))
+		if (value_eq(read_attribute(model, element_name, "current"), True)):
+			log("Found current: " + cast_value(read_attribute(model, element_name, "current")))
+			current_state = element_name
+			old_state = element_name
+			break!
+
+	while (True):
+		if (has_input()):
+			input_value = input()
+
+			if (input_value == "__EXIT__"):
+				break!
+
+			log(cast_value(time() - start_time) + " input " + input_value)
+			output(cast_value(time() - start_time) + " input " + input_value)
+
+			transitions = allOutgoingAssociationInstances(model, current_state, "FullRuntime/Transition")
+			while (set_len(transitions) > 0):
+				transition = set_pop(transitions)
+				if (cast_string(read_attribute(model, transition, "trigger")) == input_value):
+					if (element_neq(read_attribute(model, transition, "raise"), read_root())):
+						log(cast_value(time() - start_time) + " output " + cast_string(read_attribute(model, transition, "raise")))
+						output(cast_value(time() - start_time) + " output " + cast_string(read_attribute(model, transition, "raise")))
+					current_state = readAssociationDestination(model, transition)
+					break!
+
+		log(cast_value(time() - start_time) + " state " + cast_string(read_attribute(model, current_state, "name")))
+		output(cast_value(time() - start_time) + " state " + cast_string(read_attribute(model, current_state, "name")))
+		sleep(0.2)
+
+	log("CLOSE")
+	output("CLOSE")
+	
+	instantiate_attribute(model, current_state, "current", True)
+	instantiate_attribute(model, old_state, "current", True)
+	instantiate_attribute(model, set_pop(allInstances(model, "FullRuntime/Time")), "current_time", time() - start_time)
+	return True!

+ 60 - 0
models/FiniteStateAutomata/transformations/to_runtime.alc

@@ -0,0 +1,60 @@
+include "primitives.alh"
+include "modelling.alh"
+include "object_operations.alh"
+
+String function map_D2P(model : Element, name : String):
+	Element destinations
+	String pick
+
+	destinations = allAssociationDestinations(model, name, "D2P_state")
+
+	pick = name
+	while (pick == name):
+		pick = set_pop(destinations)
+
+	return pick!
+
+Boolean function main(model : Element):
+	Element all_states
+	String element_name
+	String new_element_name
+	String mm_type_name
+	Element all_links
+
+	all_states = allInstances(model, "Design/State")
+	while (set_len(all_states) > 0):
+		element_name = set_pop(all_states)
+		mm_type_name = "PartialRuntime/" + cast_string(list_read(string_split(read_type(model, element_name), "/"), 1))
+
+		if (set_len(allOutgoingAssociationInstances(model, element_name, "D2P_state")) == 0):
+			// New design element, so create in partial runtime model as well
+			new_element_name = instantiate_node(model, mm_type_name, "")
+			instantiate_link(model, "D2P_state", "", element_name, new_element_name)
+
+		// Always update the value of attributes of PartialRuntime
+		new_element_name = map_D2P(model, element_name)
+        instantiate_attribute(model, new_element_name, "name", read_attribute(model, element_name, "name"))
+        instantiate_attribute(model, new_element_name, "initial", read_attribute(model, element_name, "initial"))
+		log("Copied state initial: " + cast_value(new_element_name) + ", initial: " + cast_value(read_attribute(model, element_name, "initial")))
+
+	all_states = allInstances(model, "PartialRuntime/State")
+	while (set_len(all_states) > 0):
+		element_name = set_pop(all_states)
+		if (set_len(allIncomingAssociationInstances(model, element_name, "D2P_state")) == 0):
+			// Old partial runtime element, so remove
+			model_delete_element(model, element_name)
+
+	// Delete all existing transitions
+    all_links = allInstances(model, "PartialRuntime/Transition")
+    while (set_len(all_links) > 0):
+        model_delete_element(model, set_pop(all_links))
+
+	// Recreate all transitions
+    all_links = allInstances(model, "Design/Transition")
+    while (set_len(all_links) > 0):
+        element_name = set_pop(all_links)
+        new_element_name = instantiate_link(model, "PartialRuntime/Transition", "", map_D2P(model, readAssociationSource(model, element_name)), map_D2P(model, readAssociationDestination(model, element_name)))
+		instantiate_attribute(model, new_element_name, "trigger", read_attribute(model, element_name, "trigger"))
+		instantiate_attribute(model, new_element_name, "raise", read_attribute(model, element_name, "raise"))
+
+	return True!

+ 78 - 0
models/old/live_modelling.py

@@ -0,0 +1,78 @@
+import sys
+sys.path.append("wrappers")
+from modelverse import *
+
+init()
+login("admin", "admin")
+
+### live modelling DTCBD
+
+model_add("formalisms/DTCBD/Design_MM", "formalisms/SimpleClassDiagrams", open("models/dtcbd_design.mvc", 'r').read())
+model_add("formalisms/DTCBD/PartialRuntime_MM", "formalisms/SimpleClassDiagrams", open("models/dtcbd_partial_runtime.mvc", 'r').read())
+model_add("formalisms/DTCBD/FullRuntime_MM", "formalisms/SimpleClassDiagrams", open("models/dtcbd_runtime.mvc", 'r').read())
+
+model_add("models/DTCBD_model", "formalisms/DTCBD/Design_MM", open("models/dtcbd_simple.mvc", 'r').read())
+
+transformation_add_MANUAL({"Design": "formalisms/DTCBD/Design_MM"}, {"Design": "formalisms/DTCBD/Design_MM"}, "models/DTCBD/edit")
+
+def trace_D2P(model):
+    instantiate(model, "Association", ("Design/Block", "PartialRuntime/Block"), ID="D2P_block")
+
+transformation_add_AL({"Design": "formalisms/DTCBD/Design_MM", "PartialRuntime": "formalisms/DTCBD/PartialRuntime_MM"}, {"PartialRuntime": "formalisms/DTCBD/PartialRuntime_MM"}, "models/DTCBD/toRuntime", open("models/dtcbd_toRuntime.alc", 'r').read(), trace_D2P)
+
+def trace_P2F(model):
+    instantiate(model, "Association", ("PartialRuntime/Block", "FullRuntime/Block"), ID="P2F_block")
+
+transformation_add_AL({"PartialRuntime": "formalisms/DTCBD/PartialRuntime_MM", "FullRuntime": "formalisms/DTCBD/FullRuntime_MM"}, {"NewFullRuntime": "formalisms/DTCBD/FullRuntime_MM"}, "models/DTCBD/merge", open("models/dtcbd_merge.alc", 'r').read(), trace_P2F)
+transformation_add_AL({"FullRuntime": "formalisms/DTCBD/FullRuntime_MM"}, {"FullRuntime": "formalisms/DTCBD/FullRuntime_MM"}, "models/DTCBD/simulate", open("models/dtcbd_simulate.alc", 'r').read())
+transformation_add_AL({}, {}, "models/DTCBD/restartSim", open("models/cbd_restartSim.alc", 'r').read())
+
+model_add("models/live_modelling_DTCBD", "formalisms/ProcessModel", open("models/pm_live_DTCBD.mvc", 'r').read())
+
+### live modelling CTCBD
+
+model_add("formalisms/CTCBD/Design_MM", "formalisms/SimpleClassDiagrams", open("models/ctcbd_design.mvc", 'r').read())
+#model_add("formalisms/DTCBD/PartialRuntime_MM", "formalisms/SimpleClassDiagrams", open("models/dtcbd_partial_runtime.mvc", 'r').read())
+#model_add("formalisms/DTCBD/FullRuntime_MM", "formalisms/SimpleClassDiagrams", open("models/dtcbd_runtime.mvc", 'r').read())
+
+model_add("models/CTCBD_model", "formalisms/CTCBD/Design_MM", open("models/ctcbd_spring.mvc", 'r').read())
+
+transformation_add_MANUAL({"Design": "formalisms/CTCBD/Design_MM"}, {"Design": "formalisms/CTCBD/Design_MM"}, "models/CTCBD/edit")
+
+def trace_D2P(model):
+    instantiate(model, "Association", ("Design/Block", "PartialRuntime/Block"), ID="D2P_block")
+
+transformation_add_MT({"Design": "formalisms/CTCBD/Design_MM", "PartialRuntime": "formalisms/DTCBD/PartialRuntime_MM"}, {"PartialRuntime": "formalisms/DTCBD/PartialRuntime_MM"}, "models/CTCBD/toRuntime", open("models/ctcbd_toPartialRuntime.mvc", 'r').read(), trace_D2P)
+
+def trace_P2F(model):
+    instantiate(model, "Association", ("PartialRuntime/Block", "FullRuntime/Block"), ID="P2F_block")
+
+#transformation_add_AL({"PartialRuntime": "formalisms/DTCBD/PartialRuntime_MM", "FullRuntime": "formalisms/DTCBD/FullRuntime_MM"}, {"NewFullRuntime": "formalisms/DTCBD/FullRuntime_MM"}, "models/DTCBD/merge", open("models/dtcbd_merge.alc", 'r').read(), trace_P2F)
+#transformation_add_AL({"FullRuntime": "formalisms/DTCBD/FullRuntime_MM"}, {"FullRuntime": "formalisms/DTCBD/FullRuntime_MM"}, "models/DTCBD/simulate", open("models/dtcbd_simulate.alc", 'r').read())
+#transformation_add_AL({}, {}, "models/DTCBD/restartSim", open("models/cbd_restartSim.alc", 'r').read())
+
+model_add("models/live_modelling_CTCBD", "formalisms/ProcessModel", open("models/pm_live_CTCBD.mvc", 'r').read())
+
+### live modelling FSA
+
+model_add("formalisms/FSA/Design_MM", "formalisms/SimpleClassDiagrams", open("models/fsa_design.mvc", 'r').read())
+model_add("formalisms/FSA/PartialRuntime_MM", "formalisms/SimpleClassDiagrams", open("models/fsa_partial_runtime.mvc", 'r').read())
+model_add("formalisms/FSA/FullRuntime_MM", "formalisms/SimpleClassDiagrams", open("models/fsa_full_runtime.mvc", 'r').read())
+
+model_add("models/FSA_model", "formalisms/FSA/Design_MM", open("models/fsa_model.mvc", 'r').read())
+
+transformation_add_MANUAL({"Design": "formalisms/FSA/Design_MM"}, {"Design": "formalisms/FSA/Design_MM"}, "models/FSA/edit")
+
+def trace_D2P(model):
+    instantiate(model, "Association", ("Design/State", "PartialRuntime/State"), ID="D2P_state")
+
+transformation_add_AL({"Design": "formalisms/FSA/Design_MM", "PartialRuntime": "formalisms/FSA/PartialRuntime_MM"}, {"PartialRuntime": "formalisms/FSA/PartialRuntime_MM"}, "models/FSA/toRuntime", open("models/fsa_toRuntime.alc", 'r').read(), trace_D2P)
+
+def trace_P2F(model):
+    instantiate(model, "Association", ("PartialRuntime/State", "FullRuntime/State"), ID="P2F_state")
+
+transformation_add_AL({"PartialRuntime": "formalisms/FSA/PartialRuntime_MM", "FullRuntime": "formalisms/FSA/FullRuntime_MM"}, {"NewFullRuntime": "formalisms/FSA/FullRuntime_MM"}, "models/FSA/merge", open("models/fsa_merge.alc", 'r').read(), trace_P2F)
+transformation_add_AL({"FullRuntime": "formalisms/FSA/FullRuntime_MM"}, {"FullRuntime": "formalisms/FSA/FullRuntime_MM"}, "models/FSA/simulate", open("models/fsa_simulate.alc", 'r').read())
+transformation_add_AL({}, {}, "models/FSA/restartSim", open("models/cbd_restartSim.alc", 'r').read())
+
+model_add("models/live_modelling_FSA", "formalisms/ProcessModel", open("models/pm_live_FSA.mvc", 'r').read())

+ 3 - 3
wrappers/modelverse_SCCD.py

@@ -1,7 +1,7 @@
 """
 """
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
 
 
-Date:   Thu May 17 11:08:54 2018
+Date:   Thu May 17 12:43:48 2018
 
 
 Model author: Yentl Van Tendeloo
 Model author: Yentl Van Tendeloo
 Model name:   MvK Server
 Model name:   MvK Server
@@ -2987,13 +2987,13 @@ class Modelverse(RuntimeClassBase):
         return self.expect_response_partial('Success: ', pop=False)
         return self.expect_response_partial('Success: ', pop=False)
     
     
     def _initialized_behaviour_operations_read_association_source_0_exec(self, parameters):
     def _initialized_behaviour_operations_read_association_source_0_exec(self, parameters):
-        self.raiseInternalEvent(Event("result", None, [self.split_response(self.responses.pop(0))]))
+        self.raiseInternalEvent(Event("result", None, [self.split_response(self.responses.pop(0))[0]]))
     
     
     def _initialized_behaviour_operations_read_association_source_0_guard(self, parameters):
     def _initialized_behaviour_operations_read_association_source_0_guard(self, parameters):
         return self.expect_response_partial('Success: ', pop=False)
         return self.expect_response_partial('Success: ', pop=False)
     
     
     def _initialized_behaviour_operations_read_association_destination_0_exec(self, parameters):
     def _initialized_behaviour_operations_read_association_destination_0_exec(self, parameters):
-        self.raiseInternalEvent(Event("result", None, [self.split_response(self.responses.pop(0))]))
+        self.raiseInternalEvent(Event("result", None, [self.split_response(self.responses.pop(0))[0]]))
     
     
     def _initialized_behaviour_operations_read_association_destination_0_guard(self, parameters):
     def _initialized_behaviour_operations_read_association_destination_0_guard(self, parameters):
         return self.expect_response_partial('Success: ', pop=False)
         return self.expect_response_partial('Success: ', pop=False)