Browse Source

Merge branch 'testing' into MvK_rules

Yentl Van Tendeloo 8 years ago
parent
commit
9a7fc2330d
51 changed files with 5214 additions and 1213 deletions
  1. 5 0
      .gitignore
  2. 120 27
      bootstrap/core_algorithm.alc
  3. 4 3
      bootstrap/mini_modify.alc
  4. 7 4
      bootstrap/model_management.alc
  5. 11 0
      bootstrap/random.alc
  6. 68 0
      bootstrap/semi_primitives.alc
  7. 44 0
      bootstrap/utils.alc
  8. 2 2
      integration/code/pm_pn_reachability.mvc
  9. 2 2
      integration/test_powerwindow.py
  10. 2 0
      interface/HUTN/hutn_compiler/semantics_visitor.py
  11. 1 1
      interface/HUTN/includes/mini_modify.alh
  12. 1 0
      interface/HUTN/includes/primitives.alh
  13. 1 0
      interface/HUTN/includes/random.alh
  14. 2 0
      interface/HUTN/includes/utils.alh
  15. 9 3
      kernel/modelverse_kernel/main.py
  16. 1 0
      kernel/test/rules/test_rules_break.py
  17. 1 0
      kernel/test/rules/test_rules_continue.py
  18. 125 0
      models/lola.alc
  19. 35 0
      models/paralleldevs_design.mvc
  20. 151 0
      models/pdevs_client.alc
  21. 12 12
      models/pm_req_analyse.mvc
  22. 12 12
      models/pm_req_analyse_debug.mvc
  23. 213 0
      models/produce_consume_PDEVS.mvc
  24. 0 213
      models/render_OD.alc
  25. 0 182
      models/render_SCD.alc
  26. 68 0
      models/upload_models.py
  27. 24 17
      scripts/run_local_modelverse.py
  28. 62 0
      services/DEVS/main.py
  29. 161 0
      services/DEVS/pypdevs/examples/client.py
  30. 36 0
      services/DEVS/pypdevs/examples/experiment.py
  31. 129 0
      services/DEVS/pypdevs/examples/exported_model.py
  32. 29 0
      services/DEVS/pypdevs/examples/helpers.py
  33. 1 0
      services/DEVS/pypdevs/examples/infinity.py
  34. 286 0
      services/DEVS/pypdevs/examples/model.py
  35. 430 0
      services/DEVS/pypdevs/examples/ps_model.py
  36. 536 0
      services/DEVS/pypdevs/src/DEVS.py
  37. 17 0
      services/DEVS/pypdevs/src/devsexception.py
  38. 1 0
      services/DEVS/pypdevs/src/infinity.py
  39. 121 0
      services/DEVS/pypdevs/src/mvk_widget.py
  40. 176 0
      services/DEVS/pypdevs/src/scheduler.py
  41. 1021 0
      services/DEVS/pypdevs/src/simulator.py
  42. 808 0
      services/DEVS/pypdevs/src/simulator.xml
  43. 0 5
      scripts/HUTN_service.py
  44. 0 1
      scripts/JSON_service.py
  45. 1 2
      unit/log_output.py
  46. 1 6
      unit/log_output.xml
  47. 14 3
      unit/test_all.py
  48. 95 81
      wrappers/classes/modelverse.xml
  49. 66 73
      wrappers/modelverse.py
  50. 302 245
      wrappers/modelverse_SCCD.py
  51. 0 319
      wrappers/modelverse_coded.py

+ 5 - 0
.gitignore

@@ -8,3 +8,8 @@ doc/al_rules/*.pdf
 doc/al_rules/*.eps
 doc/al_rules/*.eps
 *.aux
 *.aux
 *.log
 *.log
+*.dot
+.cache
+*.swp
+*.swo
+.tmp_*

+ 120 - 27
bootstrap/core_algorithm.alc

@@ -13,6 +13,7 @@ include "utils.alh"
 include "conformance_finding.alh"
 include "conformance_finding.alh"
 include "typing.alh"
 include "typing.alh"
 include "compiler.alh"
 include "compiler.alh"
+include "random.alh"
 
 
 String core_model_location = "models/core"
 String core_model_location = "models/core"
 
 
@@ -711,7 +712,20 @@ Element function execute_operation(operation_id : String, input_models : Element
 		result = transform(merged_model, operation)
 		result = transform(merged_model, operation)
 	elif (exact_type == "ManualOperation"):
 	elif (exact_type == "ManualOperation"):
 		output("Please perform manual operation " + cast_value(full_name(operation_id)))
 		output("Please perform manual operation " + cast_value(full_name(operation_id)))
-		modify(merged_model, True)
+		String model_name
+		model_name = ""
+		while (get_entry_id(model_name) != ""):
+			model_name = ".tmp/" + random_string(20)
+		model_create(merged_model, model_name, merged_metamodel_id, "Model")
+		output("Operating on: " + cast_string(model_name))
+		// We want to modify, so modify
+		if (modify(merged_model, True)):
+			// Overwrite the merged model
+			model_overwrite(merged_model, get_entry_id(model_name), merged_metamodel_id)
+		else:
+			// Reload the merged model
+			merged_model = get_full_model(get_entry_id(model_name), merged_metamodel_id)
+		//model_delete(get_entry_id(model_name))
 		result = True
 		result = True
 	elif (exact_type == "ActionLanguage"):
 	elif (exact_type == "ActionLanguage"):
 		Element func
 		Element func
@@ -763,7 +777,7 @@ Element function execute_operation(operation_id : String, input_models : Element
 		log("Negative result of execution")
 		log("Negative result of execution")
 		return read_root()!
 		return read_root()!
 
 
-Boolean function enact_action(pm : Element, element : String, prefix : String):
+Boolean function enact_action(pm : Element, element : String, mapping : Element):
 	Boolean result
 	Boolean result
 	String transformation_id
 	String transformation_id
 	Element lst
 	Element lst
@@ -796,7 +810,7 @@ Boolean function enact_action(pm : Element, element : String, prefix : String):
 	while (set_len(lst) > 0):
 	while (set_len(lst) > 0):
 		consume = set_pop(lst)
 		consume = set_pop(lst)
 		value = read_attribute(pm, readAssociationDestination(pm, consume), "name")
 		value = read_attribute(pm, readAssociationDestination(pm, consume), "name")
-		dict_add(inputs, read_attribute(pm, consume, "name"), prefix + value)
+		dict_add(inputs, read_attribute(pm, consume, "name"), mapping[value])
 
 
 	// Find all output model names and their metamodel
 	// Find all output model names and their metamodel
 	lst = allOutgoingAssociationInstances(pm, element, "Produces")
 	lst = allOutgoingAssociationInstances(pm, element, "Produces")
@@ -806,7 +820,7 @@ Boolean function enact_action(pm : Element, element : String, prefix : String):
 		type_name = read_attribute(pm, elem, "type")
 		type_name = read_attribute(pm, elem, "type")
 		elem_name = read_attribute(pm, elem, "name")
 		elem_name = read_attribute(pm, elem, "name")
 		dict_add(outputs, read_attribute(pm, produce, "name"), type_name)
 		dict_add(outputs, read_attribute(pm, produce, "name"), type_name)
-		dict_add(output_map, read_attribute(pm, produce, "name"), prefix + elem_name)
+		dict_add(output_map, read_attribute(pm, produce, "name"), mapping[elem_name])
 
 
 	if read_type(core, transformation_id) == "ActionLanguage":
 	if read_type(core, transformation_id) == "ActionLanguage":
 		log(string_join("Enacting ActionLanguage: ", read_attribute(pm, element, "name")))
 		log(string_join("Enacting ActionLanguage: ", read_attribute(pm, element, "name")))
@@ -824,7 +838,7 @@ Boolean function enact_action(pm : Element, element : String, prefix : String):
 		// Something went wrong!
 		// Something went wrong!
 		return False!
 		return False!
 	else:
 	else:
-		keys = dict_keys(result)
+		keys = dict_keys(outputs)
 		while (set_len(keys) > 0):
 		while (set_len(keys) > 0):
 			key = set_pop(keys)
 			key = set_pop(keys)
 			if (get_entry_id(output_map[key]) == ""):
 			if (get_entry_id(output_map[key]) == ""):
@@ -834,7 +848,20 @@ Boolean function enact_action(pm : Element, element : String, prefix : String):
 				model_overwrite(result[key], get_entry_id(output_map[key]), get_entry_id(outputs[key]))
 				model_overwrite(result[key], get_entry_id(output_map[key]), get_entry_id(outputs[key]))
 		return True!
 		return True!
 
 
-Void function enact_PM(pm : Element, prefix : String):
+Element function PM_signature(pm : Element):
+	Element all_data
+	Element result
+	String entry
+
+	result = dict_create()
+	all_data = allInstances(pm, "Data")
+	while (set_len(all_data) > 0):
+		entry = set_pop(all_data)
+		dict_add(result, cast_string(read_attribute(pm, entry, "name")), cast_string(read_attribute(pm, entry, "type")))
+
+	return result!
+
+Void function enact_PM(pm : Element, mapping : Element):
 	Element worklist
 	Element worklist
 	String element
 	String element
 	String type
 	String type
@@ -842,9 +869,28 @@ Void function enact_PM(pm : Element, prefix : String):
 	Element tuple
 	Element tuple
 	Element counters
 	Element counters
 	Element join_nodes
 	Element join_nodes
+	Element keys
+	String key
 
 
 	output("Success")
 	output("Success")
 
 
+	// For all entries in the signature, not in the mapping, we add a mock location
+	Element signature
+	String mock_location
+	Element mock_locations
+	mock_locations = set_create()
+	signature = PM_signature(pm)
+	keys = dict_keys(signature)
+	while (set_len(keys) > 0):
+		key = set_pop(keys)
+		if (bool_not(dict_in(mapping, key))):
+			// Add mock location
+			mock_location = ""
+			while (get_entry_id(mock_location) != ""):
+				mock_location = ".tmp/" + random_string(10)
+			dict_add(mapping, key, mock_location)
+			set_add(mock_locations, mock_location)
+
 	// Initialize Join counters
 	// Initialize Join counters
 	counters = dict_create()
 	counters = dict_create()
 	join_nodes = allInstances(pm, "Join")
 	join_nodes = allInstances(pm, "Join")
@@ -897,7 +943,7 @@ Void function enact_PM(pm : Element, prefix : String):
 			// Execute a transformation
 			// Execute a transformation
 			// This the difficult part!
 			// This the difficult part!
 
 
-			result = enact_action(pm, element, prefix)
+			result = enact_action(pm, element, mapping)
 			output("Success")
 			output("Success")
 
 
 		elif (type == "Decision"):
 		elif (type == "Decision"):
@@ -921,6 +967,11 @@ Void function enact_PM(pm : Element, prefix : String):
 			set_add_node(worklist, create_tuple(next, result))
 			set_add_node(worklist, create_tuple(next, result))
 
 
 	// Reached a finish element, so stop
 	// Reached a finish element, so stop
+
+	// Remove all mock locations again
+	while (set_len(mock_locations) > 0):
+		model_delete(get_entry_id(set_pop(mock_locations)))
+
 	return !
 	return !
 
 
 String function cmd_help():
 String function cmd_help():
@@ -1017,7 +1068,7 @@ String function cmd_model_add(type : String, name : String, code : String):
 	else:
 	else:
 		return "Model not found: " + type!
 		return "Model not found: " + type!
 
 
-String function cmd_process_execute(process : String, prefix : String):
+String function cmd_process_execute(process : String, mapping : Element):
 	// Execute a process model until it reaches termination
 	// Execute a process model until it reaches termination
 	String process_id
 	String process_id
 
 
@@ -1029,13 +1080,42 @@ String function cmd_process_execute(process : String, prefix : String):
 			if (element_eq(pm, read_root())):
 			if (element_eq(pm, read_root())):
 				return "Specified model cannot be interpreted as a ProcessModel: " + process!
 				return "Specified model cannot be interpreted as a ProcessModel: " + process!
 
 
-			enact_PM(pm, prefix)
+			enact_PM(pm, mapping)
 			return "Success"!
 			return "Success"!
 		else:
 		else:
 			return "Permission denied to model: " + process!
 			return "Permission denied to model: " + process!
 	else:
 	else:
 		return "Model not found: " + process!
 		return "Model not found: " + process!
 
 
+String function cmd_process_signature(process : String):
+	// Execute a process model until it reaches termination
+	String process_id
+	String result
+	Element signature
+	Element keys
+	String key
+
+	process_id = get_entry_id(process)
+	if (process_id != ""):
+		if (allow_read(current_user_id, process_id)):
+			Element pm
+			pm = get_full_model(process_id, get_entry_id("formalisms/ProcessModel"))
+			if (element_eq(pm, read_root())):
+				return "Specified model cannot be interpreted as a ProcessModel: " + process!
+
+			result = "Success: "
+			signature = PM_signature(pm)
+			keys = dict_keys(signature)
+			while (set_len(keys) > 0):
+				key = set_pop(keys)
+				result = result + key + " : " + cast_string(signature[key]) + "\n"
+
+			return result!
+		else:
+			return "Permission denied to model: " + process!
+	else:
+		return "Model not found: " + process!
+
 String function cmd_transformation_between(source_dict : String, target_dict : String):
 String function cmd_transformation_between(source_dict : String, target_dict : String):
 	Element result
 	Element result
 	Element subresult
 	Element subresult
@@ -1226,13 +1306,6 @@ String function cmd_model_render(model_name : String, mapper_name : String, rend
 	else:
 	else:
 		return "Model not found: " + model_name!
 		return "Model not found: " + model_name!
 
 
-	//trace_links = allOutgoingAssociationInstances(core, operation_id, "tracability")
-	//merged_metamodel_id = ""
-	//while (set_len(trace_links) > 0):
-	//	trace_link_id = set_pop(trace_links)
-	//	if (value_eq(read_attribute(core, trace_link_id, "type"), "operatesOn")):
-	//		merged_metamodel_id = readAssociationDestination(core, trace_link_id)
-
 String function cmd_transformation_execute(transformation_name : String, source_models : Element, target_models : Element, tracability_name : String):
 String function cmd_transformation_execute(transformation_name : String, source_models : Element, target_models : Element, tracability_name : String):
 	// Execute a transformation, whatever type it is
 	// Execute a transformation, whatever type it is
 	// First we detect the type, so we know how to prepare for invocation
 	// First we detect the type, so we know how to prepare for invocation
@@ -1340,14 +1413,19 @@ String function cmd_transformation_execute(transformation_name : String, source_
 					// Something went wrong!
 					// Something went wrong!
 					return "Failure"!
 					return "Failure"!
 				else:
 				else:
-					keys = dict_keys(result)
+					keys = dict_keys(outputs)
 					while (set_len(keys) > 0):
 					while (set_len(keys) > 0):
 						key = set_pop(keys)
 						key = set_pop(keys)
+						log("Writing away model with key " + cast_string(key))
+						log("Output map: " + dict_to_string(output_map))
+						log("Outputs: " + dict_to_string(outputs))
 						
 						
 						if (get_entry_id(outputs[key]) == ""):
 						if (get_entry_id(outputs[key]) == ""):
 							// New model
 							// New model
+							log("New model!")
 							model_create(result[key], outputs[key], get_entry_id(output_map[key]), "Model")
 							model_create(result[key], outputs[key], get_entry_id(output_map[key]), "Model")
 						else:
 						else:
+							log("Existing model!")
 							model_overwrite(result[key], get_entry_id(outputs[key]), get_entry_id(output_map[key]))
 							model_overwrite(result[key], get_entry_id(outputs[key]), get_entry_id(output_map[key]))
 
 
 					return "Success"!
 					return "Success"!
@@ -1609,13 +1687,18 @@ String function transformation_add(source_models : Element, target_models : Elem
 	if (get_entry_id(operation_name) == ""):
 	if (get_entry_id(operation_name) == ""):
 		// Write out a merged metamodel containing all these models: this is the MM for the manual operation
 		// Write out a merged metamodel containing all these models: this is the MM for the manual operation
 		// New location is available, so write
 		// New location is available, so write
-		if (bool_not(bool_and(dict_len(source_models) == 0, dict_len(target_models) == 0))):
+		if (dict_len(source_models) + dict_len(target_models) > 0):
 			merged_formalism = model_fuse(formalism_map)
 			merged_formalism = model_fuse(formalism_map)
 			model_create(merged_formalism, "merged/" + operation_name, get_entry_id("formalisms/SimpleClassDiagrams"), "Model")
 			model_create(merged_formalism, "merged/" + operation_name, get_entry_id("formalisms/SimpleClassDiagrams"), "Model")
-			modify(merged_formalism, True)
-			model_overwrite(merged_formalism, get_entry_id("merged/" + operation_name), get_entry_id("formalisms/SimpleClassDiagrams"))
+			output("Operating on: merged/" + operation_name)
+			if (modify(merged_formalism, True)):
+				model_overwrite(merged_formalism, get_entry_id("merged/" + operation_name), get_entry_id("formalisms/SimpleClassDiagrams"))
+			else:
+				merged_formalism = get_full_model(get_entry_id("merged/" + operation_name), get_entry_id("formalisms/SimpleClassDiagrams"))
 
 
 		if (operation_type == "manual"):
 		if (operation_type == "manual"):
+			if (dict_len(source_models) + dict_len(target_models) == 0):
+				return "Manual activity needs at least one formalism in its input or output signature!"!
 			// Finished with all information, now create the model itself!
 			// Finished with all information, now create the model itself!
 			Element m
 			Element m
 			m = get_full_model(get_entry_id("formalisms/ManualOperation"), get_entry_id("formalisms/SimpleClassDiagrams"))
 			m = get_full_model(get_entry_id("formalisms/ManualOperation"), get_entry_id("formalisms/SimpleClassDiagrams"))
@@ -1637,7 +1720,7 @@ String function transformation_add(source_models : Element, target_models : Elem
 			model_create(import_node("AL/" + operation_name), operation_name, get_entry_id("formalisms/ActionLanguage"), "ActionLanguage")
 			model_create(import_node("AL/" + operation_name), operation_name, get_entry_id("formalisms/ActionLanguage"), "ActionLanguage")
 			model_id = get_entry_id(operation_name)
 			model_id = get_entry_id(operation_name)
 
 
-		if (bool_not(bool_and(dict_len(source_models) == 0, dict_len(target_models) == 0))):
+		if (dict_len(source_models) + dict_len(target_models) > 0):
 			merged_formalism_id = get_entry_id("merged/" + operation_name)
 			merged_formalism_id = get_entry_id("merged/" + operation_name)
 
 
 			// Add tracability links at this level
 			// Add tracability links at this level
@@ -1698,6 +1781,9 @@ String function cmd_transformation_add_MT(source_models : Element, target_models
 	target = dict_create()
 	target = dict_create()
 	to_ramify = set_create()
 	to_ramify = set_create()
 
 
+	if (dict_len(source_models) + dict_len(target_models) == 0):
+		return "Model transformation needs at least one formalism in its input or output signature!"!
+
 	keys = dict_keys(source_models)
 	keys = dict_keys(source_models)
 	while (set_len(keys) > 0):
 	while (set_len(keys) > 0):
 		key = set_pop(keys)
 		key = set_pop(keys)
@@ -1754,7 +1840,11 @@ String function cmd_transformation_add_MT(source_models : Element, target_models
 
 
 	merged_formalism = model_fuse(to_ramify)
 	merged_formalism = model_fuse(to_ramify)
 	model_create(merged_formalism, "merged/" + operation_name, get_entry_id("formalisms/SimpleClassDiagrams"), "Model")
 	model_create(merged_formalism, "merged/" + operation_name, get_entry_id("formalisms/SimpleClassDiagrams"), "Model")
-	modify(merged_formalism, True)
+	output("Operating on: merged/" + operation_name)
+	if (modify(merged_formalism, True)):
+		model_overwrite(merged_formalism, get_entry_id("merged/" + operation_name), get_entry_id("formalisms/SimpleClassDiagrams"))
+	else:
+		merged_formalism = get_full_model(get_entry_id("merged/" + operation_name), get_entry_id("formalisms/SimpleClassDiagrams"))
 	model_overwrite(merged_formalism, get_entry_id("merged/" + operation_name), get_entry_id("formalisms/SimpleClassDiagrams"))
 	model_overwrite(merged_formalism, get_entry_id("merged/" + operation_name), get_entry_id("formalisms/SimpleClassDiagrams"))
 
 
 	ramified_metamodel = ramify(merged_formalism)
 	ramified_metamodel = ramify(merged_formalism)
@@ -2187,7 +2277,9 @@ Void function user_function_skip_init(user_id : String):
 		elif (cmd == "model_add"):
 		elif (cmd == "model_add"):
 			output(cmd_model_add(single_input("Model type?"), single_input("Model name?"), single_input("Model textual representation?")))
 			output(cmd_model_add(single_input("Model type?"), single_input("Model name?"), single_input("Model textual representation?")))
 		elif (cmd == "process_execute"):
 		elif (cmd == "process_execute"):
-			output(cmd_process_execute(single_input("Process to execute?"), single_input("Model prefix to use?")))
+			output(cmd_process_execute(single_input("Process to execute?"), dict_input("Model bindings to use?")))
+		elif (cmd == "process_signature"):
+			output(cmd_process_signature(single_input("Process to execute?")))
 		elif (cmd == "transformation_between"):
 		elif (cmd == "transformation_between"):
 			output(cmd_transformation_between(dict_input("Source signature?"), dict_input("Target signature?")))
 			output(cmd_transformation_between(dict_input("Source signature?"), dict_input("Target signature?")))
 		elif (cmd == "model_render"):
 		elif (cmd == "model_render"):
@@ -2211,11 +2303,11 @@ Void function user_function_skip_init(user_id : String):
 		elif (cmd == "model_list_full"):
 		elif (cmd == "model_list_full"):
 			output(cmd_model_list_full(single_input("Location?")))
 			output(cmd_model_list_full(single_input("Location?")))
 		elif (cmd == "transformation_add_MANUAL"):
 		elif (cmd == "transformation_add_MANUAL"):
-			output(cmd_transformation_add_MANUAL(dict_input("Source model names?"), dict_input("Target model names?"), single_input("Operation name?")))
+			output(cmd_transformation_add_MANUAL(dict_input("Source models?"), dict_input("Target models?"), single_input("Operation name?")))
 		elif (cmd == "transformation_add_AL"):
 		elif (cmd == "transformation_add_AL"):
-			output(cmd_transformation_add_AL(dict_input("Source model names?"), dict_input("Target model names?"), single_input("Operation name?")))
+			output(cmd_transformation_add_AL(dict_input("Source models?"), dict_input("Target models?"), single_input("Operation name?")))
 		elif (cmd == "transformation_add_MT"):
 		elif (cmd == "transformation_add_MT"):
-			output(cmd_transformation_add_MT(dict_input("Source model names?"), dict_input("Target models?"), single_input("Operation name?")))
+			output(cmd_transformation_add_MT(dict_input("Source models?"), dict_input("Target models?"), single_input("Operation name?")))
 		elif (cmd == "permission_modify"):
 		elif (cmd == "permission_modify"):
 			output(cmd_permission_modify(single_input("Model name?"), single_input("Permissions?")))
 			output(cmd_permission_modify(single_input("Model name?"), single_input("Permissions?")))
 		elif (cmd == "permission_owner"):
 		elif (cmd == "permission_owner"):
@@ -2265,8 +2357,9 @@ Void function user_function_skip_init(user_id : String):
 		elif (cmd == "folder_create"):
 		elif (cmd == "folder_create"):
 			output(cmd_folder_create(single_input("Folder name?")))
 			output(cmd_folder_create(single_input("Folder name?")))
 		elif (cmd == "add_conformance"):
 		elif (cmd == "add_conformance"):
-			// TODO
+			log("Adding conformance relation...")
 			output(cmd_conformance_add(single_input("Model name?"), single_input("Metamodel name?")))
 			output(cmd_conformance_add(single_input("Model name?"), single_input("Metamodel name?")))
+			log("Added!")
 		elif (cmd == "remove_conformance"):
 		elif (cmd == "remove_conformance"):
 			// TODO
 			// TODO
 			cmd = "FAIL"
 			cmd = "FAIL"

+ 4 - 3
bootstrap/mini_modify.alc

@@ -497,7 +497,7 @@ String function cmd_all_instances(model : Element, type : String):
 	else:
 	else:
 		return "Element not found: " + type!
 		return "Element not found: " + type!
 
 
-Element function modify(model : Element, write : Boolean):
+Boolean function modify(model : Element, write : Boolean):
 	String cmd
 	String cmd
 
 
 	output("Model loaded, ready for commands!")
 	output("Model loaded, ready for commands!")
@@ -507,7 +507,9 @@ Element function modify(model : Element, write : Boolean):
 		if (cmd == "help"):
 		if (cmd == "help"):
 			output(cmd_help_m(write))
 			output(cmd_help_m(write))
 		elif (cmd == "exit"):
 		elif (cmd == "exit"):
-			return model!
+			return True!
+		elif (cmd == "drop"):
+			return False!
 		elif (cmd == "upload"):
 		elif (cmd == "upload"):
 			output(cmd_upload(write, model))
 			output(cmd_upload(write, model))
 		elif (cmd == "instantiate_node"):
 		elif (cmd == "instantiate_node"):
@@ -565,7 +567,6 @@ Element function modify(model : Element, write : Boolean):
 		else:
 		else:
 			output("Unknown command while modelling: " + cast_value(cmd))
 			output("Unknown command while modelling: " + cast_value(cmd))
 			output("Use command 'help' to get a list of available commands")
 			output("Use command 'help' to get a list of available commands")
-	return model!
 
 
 String function single_input(prompt : String):
 String function single_input(prompt : String):
 	if (verbose):
 	if (verbose):

+ 7 - 4
bootstrap/model_management.alc

@@ -5,6 +5,7 @@ include "constructors.alh"
 include "metamodels.alh"
 include "metamodels.alh"
 include "library.alh"
 include "library.alh"
 include "modelling.alh"
 include "modelling.alh"
+include "utils.alh"
 
 
 Element function model_fuse(models : Element):
 Element function model_fuse(models : Element):
 	Element new_model
 	Element new_model
@@ -192,6 +193,8 @@ Element function model_join(models : Element, metamodel : Element, tracability_m
 
 
 			src_name = read_attribute(tracability_model, readAssociationSource(tracability_model, tracability_link), "name")
 			src_name = read_attribute(tracability_model, readAssociationSource(tracability_model, tracability_link), "name")
 			dst_name = read_attribute(tracability_model, readAssociationDestination(tracability_model, tracability_link), "name")
 			dst_name = read_attribute(tracability_model, readAssociationDestination(tracability_model, tracability_link), "name")
+
+			log("Drawing tracability link from " + src_name + " to " + dst_name)
 			type = read_attribute(tracability_model, tracability_link, "type")
 			type = read_attribute(tracability_model, tracability_link, "type")
 
 
 			// Now try to find all possible combinations
 			// Now try to find all possible combinations
@@ -260,7 +263,7 @@ Element function model_split(merged_model : Element, models : Element, tracabili
 		key = set_pop(keys)
 		key = set_pop(keys)
 		elem = merged_model["model"][key]
 		elem = merged_model["model"][key]
 		type = read_type(merged_model, key)
 		type = read_type(merged_model, key)
-		splitted = string_split(type, "/")
+		splitted = string_split_nr(type, "/", 1)
 
 
 		if (list_len(splitted) == 1):
 		if (list_len(splitted) == 1):
 			// Only one, so no split possible
 			// Only one, so no split possible
@@ -273,8 +276,8 @@ Element function model_split(merged_model : Element, models : Element, tracabili
 				dst = reverse[cast_id(read_edge_dst(elem))]
 				dst = reverse[cast_id(read_edge_dst(elem))]
 
 
 				// All present, so create the link between them
 				// All present, so create the link between them
-				src_name = list_pop_final(string_split(src, "/"))
-				dst_name = list_pop_final(string_split(dst, "/"))
+				src_name = list_pop_final(string_split_nr(src, "/", 1))
+				dst_name = list_pop_final(string_split_nr(dst, "/", 1))
 
 
 				source = instantiate_node(tracability_model, "Reference", "")
 				source = instantiate_node(tracability_model, "Reference", "")
 				target = instantiate_node(tracability_model, "Reference", "")
 				target = instantiate_node(tracability_model, "Reference", "")
@@ -286,7 +289,7 @@ Element function model_split(merged_model : Element, models : Element, tracabili
 		else:
 		else:
 			retyping_key = splitted[0]
 			retyping_key = splitted[0]
 			if (list_len(string_split(key, "/")) > 1):
 			if (list_len(string_split(key, "/")) > 1):
-				new_name = list_read(string_split(key, "/"), 1)
+				new_name = list_read(string_split_nr(key, "/", 1), 1)
 			else:
 			else:
 				new_name = key
 				new_name = key
 
 

+ 11 - 0
bootstrap/random.alc

@@ -1,4 +1,5 @@
 include "primitives.alh"
 include "primitives.alh"
+include "utils.alh"
 
 
 Integer seed = 1
 Integer seed = 1
 
 
@@ -30,3 +31,13 @@ Element function random_choice(list : Element):
 		return read_root()!
 		return read_root()!
 	else:
 	else:
 		return list_read(list, random_interval(0, list_len(list) - 1))!
 		return list_read(list, random_interval(0, list_len(list) - 1))!
+
+String function random_string(length : Integer):
+	String result
+	Element chars
+
+	chars = alphabet()
+	result = ""
+	while (string_len(result) < length):
+		result = string_join(result, cast_string(random_choice(chars)))
+	return result!

+ 68 - 0
bootstrap/semi_primitives.alc

@@ -1,4 +1,6 @@
 include "primitives.alh"
 include "primitives.alh"
+include "utils.alh"
+include "random.alh"
 
 
 // This function must be kept internally, only called through the "sleep" and "interruptable_sleep" functions
 // This function must be kept internally, only called through the "sleep" and "interruptable_sleep" functions
 Float function __sleep(a : Float, b : Boolean) = ?primitives/__sleep
 Float function __sleep(a : Float, b : Boolean) = ?primitives/__sleep
@@ -486,3 +488,69 @@ Element function range(max : Integer):
 		counter = counter + 1
 		counter = counter + 1
 
 
 	return result!
 	return result!
+
+String function spawn(function : Element, arguments : Element):
+	// Define a new task, with all the required stack information
+	// This is taken from the "task_management" code
+	Element task_root
+	Element task_frame
+	Element output_value
+	Element input_value 
+	Element root
+
+	root = read_root()
+	task_root = create_node()
+	task_frame = create_node()
+	output_value = create_node()
+	input_value = create_node()
+
+	dict_add_fast(task_root, "frame", task_frame)
+	dict_add_fast(task_root, "output", output_value)
+	dict_add_fast(task_root, "last_output", output_value)
+	dict_add_fast(task_root, "input", input_value)
+	dict_add_fast(task_root, "last_input", input_value)
+	dict_add_fast(task_frame, "evalstack", create_node())
+	dict_add_fast(task_frame, "returnvalue", create_node())
+	dict_add_fast(task_frame, "phase", "init")
+	dict_add_fast(task_frame, "symbols", create_node())
+
+	// Instead of just spawning, we set a different IP
+	dict_add_fast(task_frame, "IP", function["body"])
+
+	// Additionally, we copy over all globals that we previously had
+	dict_add_fast(task_root, "globals", dict_copy(root[get_taskname()]["globals"]))
+
+	log("Setting IP to " + cast_value(function["body"]))
+	log("Has outputs: " + set_to_string(dict_keys(function)))
+
+	if (dict_in(function, "params")):
+		// And add the arguments to the symbol table
+		Element symbols
+		String arg_names_call
+		Element param_dict
+		Integer arg_i
+		symbols = task_frame["symbols"]
+		arg_names_call = "abcdefghijklmnopqrstuvwxyz"
+		arg_i = 0
+		param_dict = function["params"]
+		
+		arguments = list_copy(arguments)
+		Element t
+		Element entry
+		while (list_len(arguments) > 0):
+			entry = create_node()
+			dict_add(entry, "value", list_pop(arguments, 0))
+			t = create_edge(symbols, entry)
+			create_edge(t, param_dict[string_get(arg_names_call, arg_i)])
+			log("Adding to symbols: " + cast_value(string_get(arg_names_call, arg_i)))
+			arg_i = arg_i + 1
+
+	// Add this only at the end, as otherwise the task will already be detected and executed
+	String taskname
+	taskname = random_string(30)
+
+	while (dict_in(read_root(), taskname)):
+		taskname = random_string(30)
+	dict_add_fast(read_root(), taskname, task_root)
+
+	return taskname!

+ 44 - 0
bootstrap/utils.alc

@@ -90,3 +90,47 @@ Void function list_extend(lst : Element, ext : Element):
 
 
 String function get_taskname():
 String function get_taskname():
 	return reverseKeyLookup(read_root(), read_taskroot())!
 	return reverseKeyLookup(read_root(), read_taskroot())!
+
+Element function string_split_nr(str : String, split : String, count : Integer):
+	Element splitted
+	String new
+
+	splitted = string_split(str, split)
+	count = count + 1
+
+	while (list_len(splitted) > count):
+		new = split + cast_string(list_pop_final(splitted))
+		new = cast_string(list_pop_final(splitted)) + new
+		list_append(splitted, new)
+
+	return splitted!
+
+Element function alphabet():
+	Element chars
+	chars = list_create()
+	list_append(chars, "a")
+	list_append(chars, "b")
+	list_append(chars, "c")
+	list_append(chars, "d")
+	list_append(chars, "e")
+	list_append(chars, "f")
+	list_append(chars, "g")
+	list_append(chars, "h")
+	list_append(chars, "i")
+	list_append(chars, "j")
+	list_append(chars, "k")
+	list_append(chars, "l")
+	list_append(chars, "m")
+	list_append(chars, "n")
+	list_append(chars, "o")
+	list_append(chars, "p")
+	list_append(chars, "q")
+	list_append(chars, "s")
+	list_append(chars, "t")
+	list_append(chars, "u")
+	list_append(chars, "v")
+	list_append(chars, "w")
+	list_append(chars, "x")
+	list_append(chars, "y")
+	list_append(chars, "z")
+	return chars!

+ 2 - 2
integration/code/pm_pn_reachability.mvc

@@ -14,11 +14,11 @@ Exec reachability_print{
 }
 }
 
 
 Data pn {
 Data pn {
-    name = "test/pn"
+    name = "pn"
     type = "test/PetriNet"
     type = "test/PetriNet"
 }
 }
 Data reachability_graph {
 Data reachability_graph {
-    name = "test/reachability"
+    name = "reachability"
     type = "test/ReachabilityGraph"
     type = "test/ReachabilityGraph"
 }
 }
 
 

+ 2 - 2
integration/test_powerwindow.py

@@ -93,7 +93,7 @@ class TestPowerWindow(unittest.TestCase):
             }
             }
 
 
         try:
         try:
-            process_execute("models/pm_powerwindow", "pm_", callbacks)
+            process_execute("models/pm_powerwindow", {}, callbacks)
         except:
         except:
             import traceback
             import traceback
             print(traceback.format_exc())
             print(traceback.format_exc())
@@ -194,7 +194,7 @@ class TestPowerWindow(unittest.TestCase):
                 "models/bfs": (ctrl, "inp", "outp"),
                 "models/bfs": (ctrl, "inp", "outp"),
             }
             }
 
 
-        process_execute("models/pm_powerwindow", "pm_", callbacks)
+        process_execute("models/pm_powerwindow", {}, callbacks)
 
 
         thrd.join()
         thrd.join()
 
 

+ 2 - 0
interface/HUTN/hutn_compiler/semantics_visitor.py

@@ -563,6 +563,7 @@ class SemanticsVisitor(Visitor):
                                        tree.startpos['column'],
                                        tree.startpos['column'],
                                        symbol.signature()))
                                        symbol.signature()))
 
 
+        """
         for i in range(len(expressions)):
         for i in range(len(expressions)):
             arg_type = self.get_type(expressions[i])
             arg_type = self.get_type(expressions[i])
             param_type = symbol.params[i]
             param_type = symbol.params[i]
@@ -580,6 +581,7 @@ class SemanticsVisitor(Visitor):
             if type(arg_type) != type(param_type):
             if type(arg_type) != type(param_type):
                 self.perform_implicit_cast(tree, expressions[i], arg_type,
                 self.perform_implicit_cast(tree, expressions[i], arg_type,
                                            param_type)
                                            param_type)
+        """
 
 
         if symbol.name == "__input":
         if symbol.name == "__input":
             tree.head = "input"
             tree.head = "input"

+ 1 - 1
interface/HUTN/includes/mini_modify.alh

@@ -1,4 +1,4 @@
-Element function modify(model : Element, write : Boolean)
+Boolean function modify(model : Element, write : Boolean)
 String function pretty_print(model : Element)
 String function pretty_print(model : Element)
 String function single_input(prompt : String)
 String function single_input(prompt : String)
 Element function set_input(prompt : String)
 Element function set_input(prompt : String)

+ 1 - 0
interface/HUTN/includes/primitives.alh

@@ -119,3 +119,4 @@ Element function reverseKeyLookupMulti(a: Element, b: Element)
 Element function dict_values(dict : Element)
 Element function dict_values(dict : Element)
 Boolean function is_error(a : Element)
 Boolean function is_error(a : Element)
 Element function range(max : Integer)
 Element function range(max : Integer)
+String function spawn(function : Element, arguments : Element)

+ 1 - 0
interface/HUTN/includes/random.alh

@@ -1,3 +1,4 @@
 Float function random()
 Float function random()
 Integer function random_interval(a : Integer, b : Integer)
 Integer function random_interval(a : Integer, b : Integer)
 Element function random_choice(list : Element)
 Element function random_choice(list : Element)
+String function random_string(length : Integer)

+ 2 - 0
interface/HUTN/includes/utils.alh

@@ -4,3 +4,5 @@ Element function list_splice(lst : Element, start : Integer, end : Integer)
 Void function list_extend(lst : Element, ext : Element)
 Void function list_extend(lst : Element, ext : Element)
 String function get_taskname()
 String function get_taskname()
 Void function sleep(seconds : Float)
 Void function sleep(seconds : Float)
+Element function alphabet()
+Element function string_split_nr(str : String, split : String, count : Integer)

+ 9 - 3
kernel/modelverse_kernel/main.py

@@ -284,14 +284,19 @@ class ModelverseKernel(object):
         old_evalstack_link, old_phase_link, evalstack_roots = \
         old_evalstack_link, old_phase_link, evalstack_roots = \
                             yield [("RDE", [task_frame, "evalstack"]),
                             yield [("RDE", [task_frame, "evalstack"]),
                                    ("RDE", [task_frame, "phase"]),
                                    ("RDE", [task_frame, "phase"]),
-                                   ("RRD", [while_inst, "inst"]),
+                                   ("RRD", [while_inst, self.taskname]),
                                   ]
                                   ]
 
 
         if len(evalstack_roots) == 1:
         if len(evalstack_roots) == 1:
             evalstack_root = evalstack_roots[0]
             evalstack_root = evalstack_roots[0]
         else:
         else:
+            print("Got roots: " + str(evalstack_roots))
             raise Exception("Could not process continue statement!")
             raise Exception("Could not process continue statement!")
 
 
+        # Remove the self.taskname link from the evalstack, as we will repush it
+        lnk, = yield [("RDE", [evalstack_root, self.taskname])]
+        yield [("DE", [lnk])]
+
         prev_evalstack_roots, old_evalstack_phase_link = \
         prev_evalstack_roots, old_evalstack_phase_link = \
                             yield [("RRD", [evalstack_root, "prev"]),
                             yield [("RRD", [evalstack_root, "prev"]),
                                    ("RDE", [evalstack_root, "phase"]),
                                    ("RDE", [evalstack_root, "phase"]),
@@ -327,7 +332,7 @@ class ModelverseKernel(object):
         old_evalstack_link, old_phase_link, evalstack_roots = \
         old_evalstack_link, old_phase_link, evalstack_roots = \
                             yield [("RDE", [task_frame, "evalstack"]),
                             yield [("RDE", [task_frame, "evalstack"]),
                                    ("RDE", [task_frame, "phase"]),
                                    ("RDE", [task_frame, "phase"]),
-                                   ("RRD", [while_inst, "inst"]),
+                                   ("RRD", [while_inst, self.taskname]),
                                   ]
                                   ]
 
 
         if len(evalstack_roots) == 1:
         if len(evalstack_roots) == 1:
@@ -491,12 +496,13 @@ class ModelverseKernel(object):
                                    ("CNV", ["init"]),
                                    ("CNV", ["init"]),
                                    ("CNV", ["init"]),
                                    ("CNV", ["init"]),
                                   ]
                                   ]
-            _, _, _, _, _, _, _, _, _ = \
+            _, _, _, _, _, _, _, _, _, _ = \
                             yield [("CD", [task_frame, "IP", body]),
                             yield [("CD", [task_frame, "IP", body]),
                                    ("CD", [task_frame, "phase", new_phase]),
                                    ("CD", [task_frame, "phase", new_phase]),
                                    ("CD", [task_frame, "evalstack", new_evalstack]),
                                    ("CD", [task_frame, "evalstack", new_evalstack]),
                                    ("CD", [new_evalstack, "prev", evalstack]),
                                    ("CD", [new_evalstack, "prev", evalstack]),
                                    ("CD", [evalstack, "inst", inst]),
                                    ("CD", [evalstack, "inst", inst]),
+                                   ("CD", [evalstack, self.taskname, inst]),
                                    ("CD", [evalstack, "phase", evalstack_phase]),
                                    ("CD", [evalstack, "phase", evalstack_phase]),
                                    ("DE", [evalstack_link]),
                                    ("DE", [evalstack_link]),
                                    ("DE", [ip_link]),
                                    ("DE", [ip_link]),

+ 1 - 0
kernel/test/rules/test_rules_break.py

@@ -23,6 +23,7 @@ class Testbreak(unittest.TestCase):
         self.mvs.execute("CD", [task_frame, "evalstack", evalstack_top])
         self.mvs.execute("CD", [task_frame, "evalstack", evalstack_top])
         self.mvs.execute("CD", [evalstack_top, "prev", evalstack_bottom])
         self.mvs.execute("CD", [evalstack_top, "prev", evalstack_bottom])
         self.mvs.execute("CD", [evalstack_bottom, "inst", while_inst])
         self.mvs.execute("CD", [evalstack_bottom, "inst", while_inst])
+        self.mvs.execute("CD", [evalstack_bottom, "task_1", while_inst])
         self.mvs.execute("CD", [evalstack_bottom, "phase", finish_phase])
         self.mvs.execute("CD", [evalstack_bottom, "phase", finish_phase])
         self.mvs.execute("CD", [root, "task_1", task_root])
         self.mvs.execute("CD", [root, "task_1", task_root])
         self.mvs.execute("CD", [task_root, "frame", task_frame])
         self.mvs.execute("CD", [task_root, "frame", task_frame])

+ 1 - 0
kernel/test/rules/test_rules_continue.py

@@ -23,6 +23,7 @@ class Testcontinue(unittest.TestCase):
         self.mvs.execute("CD", [task_frame, "evalstack", evalstack_top])
         self.mvs.execute("CD", [task_frame, "evalstack", evalstack_top])
         self.mvs.execute("CD", [evalstack_top, "prev", evalstack_bottom])
         self.mvs.execute("CD", [evalstack_top, "prev", evalstack_bottom])
         self.mvs.execute("CD", [evalstack_bottom, "inst", while_inst])
         self.mvs.execute("CD", [evalstack_bottom, "inst", while_inst])
+        self.mvs.execute("CD", [evalstack_bottom, "task_1", while_inst])
         self.mvs.execute("CD", [evalstack_bottom, "phase", init_phase])
         self.mvs.execute("CD", [evalstack_bottom, "phase", init_phase])
         self.mvs.execute("CD", [root, "task_1", task_root])
         self.mvs.execute("CD", [root, "task_1", task_root])
         self.mvs.execute("CD", [task_root, "frame", task_frame])
         self.mvs.execute("CD", [task_root, "frame", task_frame])

+ 125 - 0
models/lola.alc

@@ -0,0 +1,125 @@
+include "primitives.alh"
+include "modelling.alh"
+include "object_operations.alh"
+include "services.alh"
+
+Boolean function lola_format(model : Element):
+	Element all_places
+	String place
+	String name
+	Integer tokens
+	String transition
+	Element all_transitions
+	Element associations
+	Element association
+	String weight
+	String lola_net
+	String query
+	String place_output
+	String marking_output
+	String transition_output
+
+	all_places = allInstances(model, "PN/Place")
+	log("ALL PLACES")
+	log(cast_i2s(list_len(all_places)))
+	place_output = "PLACE "
+	marking_output = "MARKING "
+	while (set_len(all_places) > 0):
+		place = set_pop(all_places)
+		name = read_attribute(model, place, "name")
+		tokens = read_attribute(model, place, "tokens")
+
+		place_output = string_join(place_output, name)
+
+		if tokens > 0:
+			if marking_output != "MARKING ":
+				marking_output = string_join(marking_output, ", ")
+			marking_output = string_join(marking_output, name)
+			marking_output = string_join(marking_output, ": ")
+			marking_output = string_join(marking_output, cast_i2s(tokens))
+	
+		if list_len(all_places) == 0:
+			place_output = string_join(place_output, ";")
+			marking_output = string_join(marking_output, ";")
+		else:
+			place_output = string_join(place_output, ", ")
+
+	lola_net = string_join(place_output, marking_output)
+
+	all_transitions = allInstances(model, "PN/Transition")
+	transition_output = ""
+	while (set_len(all_transitions) > 0):
+		transition = set_pop(all_transitions)
+		name = read_attribute(model, transition, "name")
+
+		transition_output = string_join(transition_output, " TRANSITION ")
+		transition_output = string_join(transition_output, name)
+		transition_output = string_join(transition_output, " CONSUME ")
+
+		associations = allIncomingAssociationInstances(model, transition, "PN/P2T")
+		while (set_len(associations) > 0):
+			association = set_pop(associations)
+			place = readAssociationSource(model, association)
+			weight = read_attribute(model, association, "weight")
+			if cast_s2i(weight) > 0:
+				transition_output = string_join(transition_output, read_attribute(model, place, "name"))
+				transition_output = string_join(transition_output, ": ")
+				transition_output = string_join(transition_output, weight)
+
+			if list_len(associations) == 0:
+				transition_output = string_join(transition_output, ";")
+			else:
+				transition_output = string_join(transition_output, ", ")
+
+		transition_output = string_join(transition_output, " PRODUCE ")
+
+		associations = allOutgoingAssociationInstances(model, transition, "PN/T2P")
+		while (set_len(associations) > 0):
+			association = set_pop(associations)
+			place = readAssociationDestination(model, association)
+			weight = read_attribute(model, association, "weight")
+			if cast_s2i(weight) > 0:
+				transition_output = string_join(transition_output, read_attribute(model, place, "name"))
+				transition_output = string_join(transition_output, ": ")
+				transition_output = string_join(transition_output, weight)
+
+			if list_len(associations) == 0:
+				transition_output = string_join(transition_output, ";")
+			else:
+				transition_output = string_join(transition_output, ", ")
+
+	lola_net = string_join(lola_net, transition_output)
+
+	all_places = allInstances(model, "Query/Place")
+	if set_len(all_places) > 0:
+		place = set_pop(all_places)
+		name = read_attribute(model, place, "name")
+		tokens = read_attribute(model, place, "tokens")
+		query = string_join(name, ' = ')
+		query = string_join(query, cast_i2s(tokens))
+
+	log("PETRINET OUTPUT")
+	log(lola_net)
+	log("\n QUERY OUTPUT")
+	log(query)
+	output = string_join("{\"petrinet\":\"", lola_net)
+	output = string_join(output, "\" , \"query\":\"")
+	output = string_join(output, query)
+	output = string_join(output, "\"}")
+
+	log("\n JSON OUTPUT")
+	log(output)
+
+	String port
+	port = comm_connect("lola")
+	comm_set(port, output)
+
+	String result
+	String path
+	result = comm_get(port)
+	path = comm_get(port)
+	log("\nLola safety query analysis result: " + result)
+	log("\nLola path: "+path)
+	comm_close(port)
+
+	return True!

+ 35 - 0
models/paralleldevs_design.mvc

@@ -0,0 +1,35 @@
+ComplexAttribute ActionCode {}
+SimpleAttribute String {}
+
+Class BaseDEVSBlock {
+    name: String
+}
+
+Class AtomicDEVSBlock: BaseDEVSBlock {
+    timeAdvance: ActionCode
+    outputFnc: ActionCode
+    intTransition: ActionCode
+    extTransition: ActionCode
+    confTransition: ActionCode
+    initialState: ActionCode
+}
+
+Class CoupledDEVSBlock: BaseDEVSBlock {}
+
+Class DEVSInstance {
+    name: String
+    type: String
+}
+
+Association SubModel(CoupledDEVSBlock, DEVSInstance) {}
+
+Class Port {
+    name: String
+}
+
+Class InputPort: Port {}
+Class OutputPort: Port {}
+
+Association DEVSBlockToPort(BaseDEVSBlock, Port) {}
+Association DEVSInstanceToPort(DEVSInstance, Port) {}
+Association Channel (Port, Port) {}

+ 151 - 0
models/pdevs_client.alc

@@ -0,0 +1,151 @@
+include "primitives.alh"
+include "services.alh"
+include "modelling.alh"
+include "object_operations.alh"
+include "utils.alh"
+include "io.alh"
+include "typing.alh"
+
+Boolean function main(model : Element):
+    log("Translating DEVS to string representation!")
+
+    String model_rep
+    Element all_atomics
+    Element curr_atomic
+    Element all_coupleds
+    Element curr_coupled
+    Element string_element
+    Element all_ports
+    Element all_submodels
+    Element curr_port
+    Element curr_submodel
+    Element out_channels
+    Element curr_channel
+    Element possible_parent
+    Element parent
+    String curr_port_name
+    String curr_port_type
+    String curr_submodel_name
+    String curr_submodel_type
+
+    model_rep = "\nfrom DEVS import *\nfrom infinity import INFINITY\n\n"
+
+    all_atomics = allInstances(model, "ParallelDEVS/AtomicDEVSBlock")
+    while (read_nr_out(all_atomics) > 0):
+        curr_atomic = set_pop(all_atomics)
+        model_rep = ((model_rep + "class ") + cast_string(read_attribute(model, curr_atomic, "name"))) + "(AtomicDEVS):\n"
+        model_rep = ((model_rep + "\tdef __init__(self, name=") + cast_value(read_attribute(model, curr_atomic, "name"))) + "):\n"
+        model_rep = model_rep + "\t\tAtomicDEVS.__init__(self, name)\n"
+        model_rep = model_rep + "\t\tself.state = self.initialState()\n"
+        model_rep = model_rep + "\t\tself.my_ports = {"
+        all_ports = allAssociationDestinations(model, curr_atomic, "ParallelDEVS/DEVSBlockToPort")
+        while (read_nr_out(all_ports) > 0):
+            curr_port = set_pop(all_ports)
+            curr_port_name = cast_value(read_attribute(model, curr_port, "name"))
+            curr_port_type = read_type(model, curr_port)
+            if (curr_port_type == "ParallelDEVS/InputPort"):
+                model_rep = (((model_rep + curr_port_name) + ": self.addInPort(") + curr_port_name) + ")"
+            if (curr_port_type == "ParallelDEVS/OutputPort"):
+                model_rep = (((model_rep + curr_port_name) + ": self.addOutPort(") + curr_port_name) + ")"
+            if (read_nr_out(all_ports) > 0):
+                model_rep = model_rep + ", "
+        model_rep = model_rep + "}\n"
+        model_rep = model_rep + "\tdef initialState(self):\n" + cast_string(read_attribute(model, curr_atomic, "initialState")) + "\n"
+        model_rep = ((model_rep + "\tdef timeAdvance(self):\n") + cast_string(read_attribute(model, curr_atomic, "timeAdvance"))) + "\n"
+        model_rep = ((model_rep + "\tdef outputFnc(self):\n") + cast_string(read_attribute(model, curr_atomic, "outputFnc"))) + "\n"
+        model_rep = ((model_rep + "\tdef intTransition(self):\n") + cast_string(read_attribute(model, curr_atomic, "intTransition"))) + "\n"
+        model_rep = ((model_rep + "\tdef extTransition(self, my_inputs):\n") + cast_string(read_attribute(model, curr_atomic, "extTransition"))) + "\n"
+        model_rep = ((model_rep + "\tdef confTransition(self, my_inputs):\n") + cast_string(read_attribute(model, curr_atomic, "confTransition"))) + "\n"
+
+    all_coupleds = allInstances(model, "ParallelDEVS/CoupledDEVSBlock")
+    while (read_nr_out(all_coupleds) > 0):
+        curr_coupled = set_pop(all_coupleds)
+        model_rep = ((model_rep + "class ") + cast_string(read_attribute(model, curr_coupled, "name"))) + "(CoupledDEVS):\n"
+        model_rep = ((model_rep + "\tdef __init__(self, name=") + cast_value(read_attribute(model, curr_coupled, "name"))) + "):\n"
+        model_rep = model_rep + "\t\tCoupledDEVS.__init__(self, name)\n"
+        model_rep = model_rep + "\t\tself.my_ports = {"
+        all_ports = allAssociationDestinations(model, curr_coupled, "ParallelDEVS/DEVSBlockToPort")
+        while (read_nr_out(all_ports) > 0):
+            curr_port = set_pop(all_ports)
+            curr_port_name = cast_value(read_attribute(model, curr_port, "name"))
+            curr_port_type = read_type(model, curr_port)
+            log(curr_port_type)
+            if (curr_port_type == "ParallelDEVS/InputPort"):
+                model_rep = (((model_rep + curr_port_name) + ": self.addInPort(") + curr_port_name) + ")"
+            if (curr_port_type == "ParallelDEVS/OutputPort"):
+                model_rep = (((model_rep + curr_port_name) + ": self.addOutPort(") + curr_port_name) + ")"
+            if (read_nr_out(all_ports) > 0):
+                model_rep = model_rep + ", "
+        model_rep = model_rep + "}\n"
+        model_rep = model_rep + "\t\tself.submodels = {"
+        all_submodels = allAssociationDestinations(model, curr_coupled, "ParallelDEVS/SubModel")
+        while (read_nr_out(all_submodels) > 0):
+            curr_submodel = set_pop(all_submodels)
+            curr_submodel_name = cast_value(read_attribute(model, curr_submodel, "name"))
+            curr_submodel_type = cast_string(read_attribute(model, curr_submodel, "type"))
+            model_rep = ((((((model_rep + curr_submodel_name) + ": self.addSubModel(") + curr_submodel_type) + "(name=") + curr_submodel_name) + ")") + ")"
+            if (read_nr_out(all_submodels) > 0):
+                model_rep = model_rep + ", "
+        model_rep = model_rep + "}\n"
+        all_ports = allAssociationDestinations(model, curr_coupled, "ParallelDEVS/DEVSBlockToPort")
+        while (read_nr_out(all_ports) > 0):
+            curr_port = set_pop(all_ports)
+            out_channels = allAssociationDestinations(model, curr_port, "ParallelDEVS/Channel")
+            while (read_nr_out(out_channels) > 0):
+                curr_channel = set_pop(out_channels)
+                parent = set_pop(allAssociationOrigins(model, curr_channel, "ParallelDEVS/DEVSInstanceToPort"))
+                model_rep = ((((((model_rep + "\t\tself.connectPorts(self.my_ports[") + cast_value(read_attribute(model, curr_port, "name"))) + "], self.submodels[") + cast_value(read_attribute(model, parent, "name"))) + "].my_ports[") + cast_value(read_attribute(model, curr_channel, "name"))) + "])\n"
+        all_submodels = allAssociationDestinations(model, curr_coupled, "ParallelDEVS/SubModel")
+        while (read_nr_out(all_submodels) > 0):
+            curr_submodel = set_pop(all_submodels)
+            curr_submodel_name = cast_value(read_attribute(model, curr_submodel, "name"))
+            log(curr_submodel_name)
+            all_ports = allAssociationDestinations(model, curr_submodel, "ParallelDEVS/DEVSInstanceToPort")
+            while (read_nr_out(all_ports) > 0):
+                curr_port = set_pop(all_ports)
+                out_channels = allAssociationDestinations(model, curr_port, "ParallelDEVS/Channel")
+                log(cast_value(read_nr_out(out_channels)))
+                while (read_nr_out(out_channels) > 0):
+                    curr_channel = set_pop(out_channels)
+                    possible_parent = allAssociationOrigins(model, curr_channel, "ParallelDEVS/DEVSInstanceToPort")
+                    if (read_nr_out(possible_parent) == 0):
+                        model_rep = ((((((model_rep + "\t\tself.connectPorts(self.submodels[") + curr_submodel_name) + "].my_ports[") + cast_value(read_attribute(model, curr_port, "name"))) + "], self.my_ports[") + cast_value(read_attribute(model, curr_channel, "name"))) + "])\n"
+                    else:
+                        parent = set_pop(possible_parent)
+                        model_rep = ((((((((model_rep + "\t\tself.connectPorts(self.submodels[") + curr_submodel_name) + "].my_ports[") + cast_value(read_attribute(model, curr_port, "name"))) + "], self.submodels[") + cast_value(read_attribute(model, parent, "name"))) + "].my_ports[") + cast_value(read_attribute(model, curr_channel, "name"))) + "])\n"
+        model_rep = model_rep + "\n"
+
+    log("Printing model_rep...")
+    log("\n" + model_rep)
+
+	String port
+    String the_input
+    String devs_model
+	port = comm_connect("pypdevs_simulator")
+        
+    log("(PDEVS) task name = " + get_taskname())
+    log("(PDEVS) Sending model...")
+    comm_set(port, model_rep)
+    log("(PDEVS) " + port)
+    
+    while (True):
+        if (comm_hasInput(port)):
+            log(cast_value(has_input()))
+            the_input = comm_get(port)
+            log("(PDEVS) Got input from simulator!")
+            log("(PDEVS) " + the_input)
+            output(the_input)
+
+        if (has_input()):
+            the_input = input()
+            log("(PDEVS) Got input from console/ps simulator!")
+            log("(PDEVS) " + cast_value(the_input))
+            if (is_physical_string(the_input)):
+                comm_set(port, the_input)
+				if (the_input == "[\"exit\"]"):
+					break!
+            else:
+                comm_set(port, cast_value(the_input))
+        sleep(0.05)
+
+	return True!

+ 12 - 12
models/pm_req_analyse.mvc

@@ -68,51 +68,51 @@ Exec bfs {
 Decision found {}
 Decision found {}
 
 
 Data req {
 Data req {
-    name = "models/requirements"
+    name = "requirements"
     type = "formalisms/Requirements"
     type = "formalisms/Requirements"
 }
 }
 Data plant_model {
 Data plant_model {
-    name = "models/plant_model"
+    name = "plant_model"
     type = "formalisms/PW_Plant"
     type = "formalisms/PW_Plant"
 }
 }
 Data environment_model {
 Data environment_model {
-    name = "models/environment_model"
+    name = "environment_model"
     type = "formalisms/PW_Environment"
     type = "formalisms/PW_Environment"
 }
 }
 Data control_model {
 Data control_model {
-    name = "models/control_model"
+    name = "control_model"
     type = "formalisms/PW_Control"
     type = "formalisms/PW_Control"
 }
 }
 Data plant_EPN {
 Data plant_EPN {
-    name = "models/plant_EPN"
+    name = "plant_EPN"
     type = "formalisms/Encapsulated_PetriNet"
     type = "formalisms/Encapsulated_PetriNet"
 }
 }
 Data control_EPN {
 Data control_EPN {
-    name = "models/control_EPN"
+    name = "control_EPN"
     type = "formalisms/Encapsulated_PetriNet"
     type = "formalisms/Encapsulated_PetriNet"
 }
 }
 Data environment_EPN {
 Data environment_EPN {
-    name = "models/environment_EPN"
+    name = "environment_EPN"
     type = "formalisms/Encapsulated_PetriNet"
     type = "formalisms/Encapsulated_PetriNet"
 }
 }
 Data pn {
 Data pn {
-    name = "models/pn"
+    name = "pn"
     type = "formalisms/PetriNet"
     type = "formalisms/PetriNet"
 }
 }
 Data reachability_graph {
 Data reachability_graph {
-    name = "models/reachability"
+    name = "reachability"
     type = "formalisms/ReachabilityGraph"
     type = "formalisms/ReachabilityGraph"
 }
 }
 Data query {
 Data query {
-    name = "models/query"
+    name = "query"
     type = "formalisms/Query"
     type = "formalisms/Query"
 }
 }
 Data architecture {
 Data architecture {
-    name = "models/architecture"
+    name = "architecture"
     type = "formalisms/Architecture"
     type = "formalisms/Architecture"
 }
 }
 Data merged_EPN {
 Data merged_EPN {
-    name = "models/merged_EPN"
+    name = "merged_EPN"
     type = "formalisms/Encapsulated_PetriNet"
     type = "formalisms/Encapsulated_PetriNet"
 }
 }
 
 

+ 12 - 12
models/pm_req_analyse_debug.mvc

@@ -81,51 +81,51 @@ Exec bfs {
 Decision found {}
 Decision found {}
 
 
 Data req {
 Data req {
-    name = "models/requirements"
+    name = "requirements"
     type = "formalisms/Requirements"
     type = "formalisms/Requirements"
 }
 }
 Data plant_model {
 Data plant_model {
-    name = "models/plant_model"
+    name = "plant_model"
     type = "formalisms/PW_Plant"
     type = "formalisms/PW_Plant"
 }
 }
 Data environment_model {
 Data environment_model {
-    name = "models/environment_model"
+    name = "environment_model"
     type = "formalisms/PW_Environment"
     type = "formalisms/PW_Environment"
 }
 }
 Data control_model {
 Data control_model {
-    name = "models/control_model"
+    name = "control_model"
     type = "formalisms/PW_Control"
     type = "formalisms/PW_Control"
 }
 }
 Data plant_EPN {
 Data plant_EPN {
-    name = "models/plant_EPN"
+    name = "plant_EPN"
     type = "formalisms/Encapsulated_PetriNet"
     type = "formalisms/Encapsulated_PetriNet"
 }
 }
 Data control_EPN {
 Data control_EPN {
-    name = "models/control_EPN"
+    name = "control_EPN"
     type = "formalisms/Encapsulated_PetriNet"
     type = "formalisms/Encapsulated_PetriNet"
 }
 }
 Data environment_EPN {
 Data environment_EPN {
-    name = "models/environment_EPN"
+    name = "environment_EPN"
     type = "formalisms/Encapsulated_PetriNet"
     type = "formalisms/Encapsulated_PetriNet"
 }
 }
 Data pn {
 Data pn {
-    name = "models/pn"
+    name = "pn"
     type = "formalisms/PetriNet"
     type = "formalisms/PetriNet"
 }
 }
 Data reachability_graph {
 Data reachability_graph {
-    name = "models/reachability"
+    name = "reachability"
     type = "formalisms/ReachabilityGraph"
     type = "formalisms/ReachabilityGraph"
 }
 }
 Data query {
 Data query {
-    name = "models/query"
+    name = "query"
     type = "formalisms/Query"
     type = "formalisms/Query"
 }
 }
 Data architecture {
 Data architecture {
-    name = "models/architecture"
+    name = "architecture"
     type = "formalisms/Architecture"
     type = "formalisms/Architecture"
 }
 }
 Data merged_EPN {
 Data merged_EPN {
-    name = "models/merged_EPN"
+    name = "merged_EPN"
     type = "formalisms/Encapsulated_PetriNet"
     type = "formalisms/Encapsulated_PetriNet"
 }
 }
 
 

+ 213 - 0
models/produce_consume_PDEVS.mvc

@@ -0,0 +1,213 @@
+include "primitives.alh"
+
+AtomicDEVSBlock Generator {
+    name = "Generator"
+    
+    initialState = """
+        return {'name': 'generating'}
+    """
+    
+    intTransition = """
+        if self.state['name'] == 'generating':
+            new_state = {}
+            new_state['name'] = 'generating'
+            return new_state
+    """
+    
+    timeAdvance = """
+        if self.state['name'] == 'generating':
+            return 1
+    """
+    
+    outputFnc = """
+        if self.state['name'] == 'generating':
+            return {self.my_ports['g_out']: [{'type': 'Job', 'repr': {'duration': 0.3}}]}
+    """
+    
+    extTransition = """
+        inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
+        return AtomicDEVS.extTransition(self, my_inputs)
+    """
+    
+    confTransition = """
+        inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
+        return AtomicDEVS.confTransition(self, my_inputs)
+    """
+}
+
+AtomicDEVSBlock Processor {
+    name = "Processor"
+    
+    initialState = """
+        return {'name': 'idle'}
+    """
+    
+    intTransition = """
+        if self.state['name'] == 'processing':
+            new_state = {}
+            new_state['name'] = 'idle'
+            return new_state
+    """
+    
+    timeAdvance = """
+        if self.state['name'] == 'processing':
+            return self.state['job']['duration']
+        if self.state['name'] == 'idle':
+            return INFINITY
+    """
+    
+    outputFnc = """
+        if self.state['name'] == 'processing':
+            return {self.my_ports['p_out']: [{'type': 'Job', 'repr': self.state['job']}]}
+        if self.state['name'] == 'idle':
+            return {}
+    """
+    
+    extTransition = """
+        inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
+        if self.state['name'] == 'idle':
+            new_state = {}
+            new_state['name'] = 'processing'
+            new_state['job'] = inputs['p_in'][0]['repr']
+            return new_state 
+        else:
+            return AtomicDEVS.extTransition(self, my_inputs)
+    """
+    
+    confTransition = """
+        inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
+        return AtomicDEVS.confTransition(self, my_inputs)
+    """
+}
+
+AtomicDEVSBlock Collector {
+    name = "Collector"
+    
+    initialState = """
+        return {'name': 'waiting', 'nr_of_jobs': 0}
+    """
+    
+    intTransition = """
+        return AtomicDEVS.intTransition(self)
+    """
+    
+    timeAdvance = """
+        if self.state['name'] == 'waiting':
+            return INFINITY
+    """
+    
+    outputFnc = """
+        if self.state['name'] == 'waiting':
+            return {}
+    """
+    
+    extTransition = """
+        inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
+        if self.state['name'] == 'waiting':
+            new_state = {}
+            new_state['name'] = 'waiting'
+            new_state['nr_of_jobs'] = self.state['nr_of_jobs'] + 1
+            return new_state
+        else:
+            return AtomicDEVS.extTransition(self, my_inputs)
+    """
+    
+    confTransition = """
+        inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
+        return AtomicDEVS.confTransition(self, my_inputs)
+    """
+}
+
+OutputPort g_out {name = "g_out"}
+InputPort p_in {name = "p_in"}
+OutputPort p_out {name = "p_out"}
+InputPort c_in {name = "c_in"}
+
+DEVSBlockToPort(Generator, g_out) {}
+DEVSBlockToPort(Processor, p_in) {}
+DEVSBlockToPort(Processor, p_out) {}
+DEVSBlockToPort(Collector, c_in) {}
+
+CoupledDEVSBlock CoupledProcessor {
+    name = "CoupledProcessor"
+}
+
+InputPort cp_in {name = "cp_in"}
+OutputPort cp_out {name = "cp_out"}
+
+DEVSBlockToPort (CoupledProcessor, cp_in) {}
+DEVSBlockToPort (CoupledProcessor, cp_out) {}
+
+DEVSInstance p1 {
+    name = "p1"
+    type = "Processor"
+}
+
+DEVSInstance p2 {
+    name = "p2"
+    type = "Processor"
+}
+
+SubModel (CoupledProcessor, p1) {}
+SubModel (CoupledProcessor, p2) {}
+
+InputPort p1_in {name = "p_in"}
+OutputPort p1_out {name = "p_out"}
+InputPort p2_in {name = "p_in"}
+OutputPort p2_out {name = "p_out"}
+
+DEVSInstanceToPort (p1, p1_in) {}
+DEVSInstanceToPort (p1, p1_out) {}
+DEVSInstanceToPort (p2, p2_in) {}
+DEVSInstanceToPort (p2, p2_out) {}
+
+Channel (cp_in, p1_in) {}
+Channel (p1_out, p2_in) {}
+Channel (p2_out, cp_out) {}
+
+CoupledDEVSBlock Root {
+    name = "Root"
+}
+
+DEVSInstance generator {
+    name = "generator"
+    type = "Generator"
+}
+
+DEVSInstance coupledprocessor {
+    name = "coupledprocessor"
+    type = "CoupledProcessor"
+}
+
+DEVSInstance processor {
+    name = "processor"
+    type = "Processor"
+}
+
+DEVSInstance collector {
+    name = "collector"
+    type = "Collector"
+}
+
+SubModel (Root, generator) {}
+SubModel (Root, coupledprocessor) {}
+SubModel (Root, processor) {}
+SubModel (Root, collector) {}
+
+OutputPort generator_out {name = "g_out"}
+InputPort coupledprocessor_in {name = "cp_in"}
+OutputPort coupledprocessor_out {name = "cp_out"}
+InputPort processor_in {name = "p_in"}
+OutputPort processor_out {name = "p_out"}
+InputPort collector_in {name = "c_in"}
+
+DEVSInstanceToPort (generator, generator_out) {}
+DEVSInstanceToPort (coupledprocessor, coupledprocessor_in) {}
+DEVSInstanceToPort (coupledprocessor, coupledprocessor_out) {}
+DEVSInstanceToPort (processor, processor_in) {}
+DEVSInstanceToPort (processor, processor_out) {}
+DEVSInstanceToPort (collector, collector_in) {}
+
+Channel (generator_out, coupledprocessor_in) {}
+Channel (coupledprocessor_out, processor_in) {}
+Channel (processor_out, collector_in) {}

+ 0 - 213
models/render_OD.alc

@@ -1,213 +0,0 @@
-include "primitives.alh"
-include "modelling.alh"
-include "object_operations.alh"
-
-Boolean function main(model : Element):
-	Element elements
-	String class
-	Element attrs
-	Element attr_keys
-	String attr_key
-	String group
-	String elem
-	Integer loc_x
-	Integer loc_y
-	Integer text_loc
-	loc_x = 10
-	loc_y = 10
-
-	Element to_remove
-	String elem_to_remove
-	Element groups
-	Element class_types
-	Element metamodel
-	metamodel = model["metamodel"]
-	String class_type
-
-	// Construct our own kind of tracability
-	Element cs_to_as
-	Element as_to_cs
-	String asid
-	cs_to_as = dict_create()
-	as_to_cs = dict_create()
-	groups = allInstances(model, "rendered/Group")
-	while (set_len(groups) > 0):
-		group = set_pop(groups)
-		asid = read_attribute(model, group, "__asid")
-		dict_add(cs_to_as, group, "abstract/" + asid)
-		dict_add(as_to_cs, "abstract/" + asid, group)
-
-	// Now render everything
-	groups = dict_create()
-	class_types = allInstances(metamodel, "Class")
-	while (set_len(class_types) > 0):
-		class_type = set_pop(class_types)
-
-		if (string_startswith(class_type, "abstract/")):
-			elements = allInstances(model, class_type)
-
-			while (set_len(elements) > 0):
-				class = set_pop(elements)
-
-				if (is_edge(model["model"][class])):
-					continue!
-				
-				Integer x
-				Integer y
-				x = loc_x
-				y = loc_y
-
-				// Check if there is already an associated element
-				if (dict_in(as_to_cs, class)):
-					// Yes, but is it still clean?
-					Element related_groups
-					group = as_to_cs[class]
-
-					if (bool_not(read_attribute(model, group, "dirty"))):
-						dict_add(groups, class, group)
-						continue!
-					else:
-						group = as_to_cs[class]
-						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)
-						dict_delete(as_to_cs, class)
-
-				if (dict_in(groups, class)):
-					// Already rendered this, so skip
-					continue!
-
-				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(class, "/"), 1))
-				instantiate_attribute(model, group, "layer", 0)
-				dict_add(groups, class, group)
-
-				loc_x = loc_x + 250
-				if (loc_x > 2000):
-					loc_x = 10
-					loc_y = loc_y + 300
-
-				elem = instantiate_node(model, "rendered/Rectangle", "")
-				instantiate_attribute(model, elem, "x", 0)
-				instantiate_attribute(model, elem, "y", 0)
-				instantiate_attribute(model, elem, "height", 40 + set_len(getAttributes(model, class)) * 20)
-				instantiate_attribute(model, elem, "width", 200)
-				instantiate_attribute(model, elem, "lineWidth", 2) 
-				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", 5)
-				instantiate_attribute(model, elem, "y", 3)
-				instantiate_attribute(model, elem, "lineWidth", 1)
-				instantiate_attribute(model, elem, "lineColour", "black")
-				instantiate_attribute(model, elem, "text", string_join(cast_value(list_read(string_split(class, "/"), 1)), " : " + cast_value(list_read(string_split(read_type(model, class), "/"), 1))))
-				instantiate_attribute(model, elem, "layer", 2)
-				instantiate_link(model, "rendered/contains", "", group, elem)
-
-				elem = instantiate_node(model, "rendered/Line", "")
-				instantiate_attribute(model, elem, "x", 0)
-				instantiate_attribute(model, elem, "y", 20)
-				instantiate_attribute(model, elem, "targetX", 200)
-				instantiate_attribute(model, elem, "targetY", 20)
-				instantiate_attribute(model, elem, "lineWidth", 1)
-				instantiate_attribute(model, elem, "lineColour", "black")
-				instantiate_attribute(model, elem, "arrow", False)
-				instantiate_attribute(model, elem, "layer", 2)
-				instantiate_link(model, "rendered/contains", "", group, elem)
-
-				attrs = getAttributes(model, class)
-				attr_keys = dict_keys(attrs)
-				while (dict_len(attr_keys) > 0):
-					attr_key = set_pop(attr_keys)
-					elem = instantiate_node(model, "rendered/Text", "")
-					instantiate_attribute(model, elem, "x", 5)
-					instantiate_attribute(model, elem, "y", text_loc + 20)
-					instantiate_attribute(model, elem, "lineWidth", 1)
-					instantiate_attribute(model, elem, "lineColour", "black")
-					instantiate_attribute(model, elem, "text", (attr_key + " = ") + cast_value(attrs[attr_key]))
-					instantiate_attribute(model, elem, "layer", 2)
-					instantiate_link(model, "rendered/contains", "", group, elem)
-					text_loc = text_loc + 15
-
-	// Flush all associations
-	elements = allInstances(model, "rendered/ConnectingLine")
-	while (set_len(elements) > 0):
-		class = set_pop(elements)
-		model_delete_element(model, class)
-
-	// Rerender associations
-	Element to_render
-	to_render = set_create()
-	class_types = allInstances(metamodel, "Association")
-	while (set_len(class_types) > 0):
-		class_type = set_pop(class_types)
-		log("Checking type " + class_type)
-
-		if (string_startswith(class_type, "abstract/")):
-			elements = allInstances(model, class_type)
-			log("    Checking instance " + class)
-			while (set_len(elements) > 0):
-				class = set_pop(elements)
-				if (is_edge(model["model"][class])):
-					if (bool_not(set_in(to_render, class))):
-						set_add(to_render, class)
-						log("Added!")
-
-	to_render = set_to_list(to_render)
-	Element delayed_elements
-	Integer num_to_render
-	delayed_elements = list_create()
-	while (list_len(to_render) > 0):
-		num_to_render = list_len(to_render)
-		while (list_len(to_render) > 0):
-			class = list_pop_final(to_render)
-			attr_keys = dict_keys(getAttributes(model, class))
-
-			if (bool_not(bool_and(dict_in(groups, readAssociationSource(model, class)), dict_in(groups, readAssociationDestination(model, class))))):
-				list_append(delayed_elements, class)
-				continue!
-
-			elem = instantiate_link(model, "rendered/ConnectingLine", "", groups[readAssociationSource(model, class)], groups[readAssociationDestination(model, class)])
-			dict_add(groups, class, elem)
-			if (is_edge(model["model"][readAssociationSource(model, class)])):
-				instantiate_attribute(model, elem, "offsetSourceX", 0)
-				instantiate_attribute(model, elem, "offsetSourceY", 0)
-			else:
-				instantiate_attribute(model, elem, "offsetSourceX", 100)
-				instantiate_attribute(model, elem, "offsetSourceY", 30)
-			if (is_edge(model["model"][readAssociationDestination(model, class)])):
-				instantiate_attribute(model, elem, "offsetTargetX", 0)
-				instantiate_attribute(model, elem, "offsetTargetY", 0)
-			else:
-				instantiate_attribute(model, elem, "offsetTargetX", 100)
-				instantiate_attribute(model, elem, "offsetTargetY", 30)
-			instantiate_attribute(model, elem, "lineWidth", 3)
-			instantiate_attribute(model, elem, "lineColour", "black")
-			instantiate_attribute(model, elem, "arrow", True)
-			instantiate_attribute(model, elem, "__asid", list_read(string_split(class, "/"), 1))
-			instantiate_attribute(model, elem, "layer", 0)
-			instantiate_link(model, "rendered/contains", "", group, elem)
-
-		if (num_to_render == list_len(delayed_elements)):
-			log("Could not decrease number of rendered elements anymore... Giving up!")
-			return True!
-		else:
-			to_render = delayed_elements
-			delayed_elements = list_create()
-
-	return True!

+ 0 - 182
models/render_SCD.alc

@@ -1,182 +0,0 @@
-include "primitives.alh"
-include "modelling.alh"
-include "object_operations.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/Class")
-	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(class, "/"), 1))
-		instantiate_attribute(model, group, "layer", 0)
-		dict_add(groups, class, group)
-		loc = loc + 200
-
-		elem = instantiate_node(model, "rendered/Rectangle", "")
-		instantiate_attribute(model, elem, "x", 0)
-		instantiate_attribute(model, elem, "y", 0)
-		instantiate_attribute(model, elem, "height", 40 + set_len(getInstantiatableAttributes(model, class, "abstract/AttributeLink")) * 20)
-		instantiate_attribute(model, elem, "width", 150)
-		instantiate_attribute(model, elem, "lineWidth", 2) 
-		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)
-
-		String multiplicities
-		String lower_card
-		String upper_card
-		if (element_eq(read_attribute(model, class, "lower_cardinality"), read_root())):
-			lower_card = "*"
-		else:
-			lower_card = cast_value(read_attribute(model, class, "lower_cardinality"))
-		if (element_eq(read_attribute(model, class, "upper_cardinality"), read_root())):
-			upper_card = "*"
-		else:
-			upper_card = cast_value(read_attribute(model, class, "upper_cardinality"))
-		multiplicities = ((("[" + lower_card) + "..") + upper_card) + "]"
-
-		elem = instantiate_node(model, "rendered/Text", "")
-		instantiate_attribute(model, elem, "x", 5)
-		instantiate_attribute(model, elem, "y", 3)
-		instantiate_attribute(model, elem, "lineWidth", 1)
-		instantiate_attribute(model, elem, "lineColour", "black")
-		if (element_neq(read_attribute(model, class, "name"), read_root())):
-			instantiate_attribute(model, elem, "text", string_join(read_attribute(model, class, "name"), "  " + multiplicities))
-		else:
-			instantiate_attribute(model, elem, "text", "(unnamed) " + multiplicities)
-		instantiate_attribute(model, elem, "layer", 2)
-		instantiate_link(model, "rendered/contains", "", group, elem)
-
-		elem = instantiate_node(model, "rendered/Line", "")
-		instantiate_attribute(model, elem, "x", 0)
-		instantiate_attribute(model, elem, "y", 20)
-		instantiate_attribute(model, elem, "targetX", 150)
-		instantiate_attribute(model, elem, "targetY", 20)
-		instantiate_attribute(model, elem, "lineWidth", 1)
-		instantiate_attribute(model, elem, "lineColour", "black")
-		instantiate_attribute(model, elem, "arrow", False)
-		instantiate_attribute(model, elem, "layer", 2)
-		instantiate_link(model, "rendered/contains", "", group, elem)
-
-		attrs = getInstantiatableAttributes(model, class, "abstract/AttributeLink")
-		attr_keys = dict_keys(attrs)
-		while (dict_len(attr_keys) > 0):
-			attr_key = set_pop(attr_keys)
-			elem = instantiate_node(model, "rendered/Text", "")
-			instantiate_attribute(model, elem, "x", 5)
-			instantiate_attribute(model, elem, "y", text_loc + 20)
-			instantiate_attribute(model, elem, "lineWidth", 1)
-			instantiate_attribute(model, elem, "lineColour", "black")
-			instantiate_attribute(model, elem, "text", (attr_key + " : ") + cast_string(list_read(string_split(attrs[attr_key], "/"), 1)))
-			instantiate_attribute(model, elem, "layer", 2)
-			instantiate_link(model, "rendered/contains", "", group, elem)
-			text_loc = text_loc + 15
-
-		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/Association")
-	while (set_len(elements) > 0):
-		class = set_pop(elements)
-
-		attr_keys = dict_keys(getAttributeList(model, class))
-
-		elem = instantiate_link(model, "rendered/ConnectingLine", "", groups[readAssociationSource(model, class)], groups[readAssociationDestination(model, class)])
-		instantiate_attribute(model, elem, "offsetSourceX", 75)
-		instantiate_attribute(model, elem, "offsetSourceY", 30)
-		instantiate_attribute(model, elem, "offsetTargetX", 75)
-		instantiate_attribute(model, elem, "offsetTargetY", 30)
-		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(class, "/"), 1))
-		instantiate_attribute(model, elem, "layer", 0)
-		log("Found ASID " + cast_value(list_read(string_split(class, "/"), 1)))
-		instantiate_link(model, "rendered/contains", "", group, elem)
-
-	return True!

+ 68 - 0
models/upload_models.py

@@ -0,0 +1,68 @@
+import sys
+sys.path.append("wrappers")
+from modelverse import *
+
+init()
+login("admin", "admin")
+
+model_add("formalisms/ParallelDEVS", "formalisms/SimpleClassDiagrams", open("models/paralleldevs_design.mvc").read())
+model_add("models/produce_consume_pdevs", "formalisms/ParallelDEVS", open("models/produce_consume_PDEVS.mvc").read())
+transformation_add_AL({"ParallelDEVS": "formalisms/ParallelDEVS"}, {}, "models/paralleldevs_simulator", open("models/pdevs_client.alc", "r").read())
+
+"""
+model_add("formalisms/ReachabilityGraph", "formalisms/SimpleClassDiagrams", open("models/reachability_graph.mvc", "r").read())
+model_add("formalisms/PetriNet", "formalisms/SimpleClassDiagrams", open("integration/code/pn_design.mvc", 'r').read())
+model_add("formalisms/Encapsulated_PetriNet", "formalisms/SimpleClassDiagrams", open("models/petrinet_ports.mvc", 'r').read())
+model_add("formalisms/PW_Plant", "formalisms/SimpleClassDiagrams", open("models/plant_PW.mvc", 'r').read())
+model_add("formalisms/PW_Environment", "formalisms/SimpleClassDiagrams", open("models/environment_PW.mvc", 'r').read())
+model_add("formalisms/PW_Control", "formalisms/SimpleClassDiagrams", open("models/control_PW.mvc", 'r').read())
+model_add("formalisms/Requirements", "formalisms/SimpleClassDiagrams", open("models/requirements.mvc", 'r').read())
+model_add("formalisms/Query", "formalisms/SimpleClassDiagrams", open("models/query.mvc", 'r').read())
+model_add("formalisms/Architecture", "formalisms/SimpleClassDiagrams", open("models/architecture.mvc", 'r').read())
+
+model_add("models/pm_powerwindow", "formalisms/ProcessModel", open("models/pm_req_analyse.mvc", 'r').read())
+
+model_add("models/plant", "formalisms/PW_Plant", open("models/plant_model.mvc", 'r').read().replace("PW_Plant/", ""))
+model_add("models/environment", "formalisms/PW_Environment", open("models/environment_model.mvc", 'r').read().replace("PW_Environment/", ""))
+model_add("models/control", "formalisms/PW_Control", open("models/control_model.mvc", 'r').read().replace("PW_Control/", ""))
+model_add("models/control_wrong", "formalisms/PW_Control", open("models/control_model_wrong.mvc", 'r').read().replace("PW_Control/", ""))
+model_add("models/query", "formalisms/Query", open("models/query_model.mvc", 'r').read().replace("Query/", ""))
+model_add("models/architecture", "formalisms/Architecture", open("models/architecture_model.mvc", 'r').read().replace("Architecture/", ""))
+model_add("models/requirements", "formalisms/Requirements", open("models/requirements_model.mvc", 'r').read().replace("Requirements/", ""))
+
+transformation_add_MANUAL({"Requirements": "formalisms/Requirements"}, {"Requirements": "formalisms/Requirements"}, "models/revise_req")
+transformation_add_MANUAL({"Requirements": "formalisms/Requirements", "PW_Environment": "formalisms/PW_Environment"}, {"PW_Environment": "formalisms/PW_Environment"}, "models/revise_environment")
+transformation_add_MANUAL({"Requirements": "formalisms/Requirements", "PW_Plant": "formalisms/PW_Plant"}, {"PW_Plant": "formalisms/PW_Plant"}, "models/revise_plant")
+transformation_add_MANUAL({"Requirements": "formalisms/Requirements", "PW_Control": "formalisms/PW_Control"}, {"PW_Control": "formalisms/PW_Control"}, "models/revise_control")
+transformation_add_MANUAL({"Requirements": "formalisms/Requirements", "Query": "formalisms/Query"}, {"Query": "formalisms/Query"}, "models/revise_query")
+transformation_add_MANUAL({"Requirements": "formalisms/Requirements", "Architecture": "formalisms/Architecture"}, {"Architecture": "formalisms/Architecture"}, "models/revise_architecture")
+
+def tracability_CTRL2EPN(context):
+    instantiate(None, "Association", ("PW_Control/State", "Encapsulated_PetriNet/Place"), ID="CTRL2EPN_link", context=context)
+    instantiate(None, "Association", ("PW_Control/Transition", "Encapsulated_PetriNet/Transition"), ID="CTRL2EPN_tlink", context=context)
+
+def tracability_PLANT2EPN(context):
+    instantiate(None, "Association", ("PW_Plant/State", "Encapsulated_PetriNet/Place"), ID="PLANT2EPN_link", context=context)
+    instantiate(None, "Association", ("PW_Plant/Transition", "Encapsulated_PetriNet/Transition"), ID="PLANT2EPN_tlink", context=context)
+
+def tracability_ENV2EPN(context):
+    instantiate(None, "Association", ("PW_Environment/Event", "Encapsulated_PetriNet/Place"), ID="ENV2EPN_link", context=context)
+
+def tracability_EPN2PN(context):
+    instantiate(None, "Association", ("Encapsulated_PetriNet/Place", "PetriNet/Place"), ID="EPN2PN_transition_link", context=context)
+    instantiate(None, "Association", ("Encapsulated_PetriNet/Transition", "PetriNet/Transition"), ID="EPN2PN_place_link", context=context)
+
+transformation_add_MT({}, {"PW_Plant": "formalisms/PW_Plant", "PW_Environment": "formalisms/PW_Environment", "PW_Control": "formalisms/PW_Control", "Query": "formalisms/Query", "Architecture": "formalisms/Architecture", "Requirements": "formalisms/Requirements"}, "models/make_initial_models", open("models/initialize.mvc", 'r').read())
+transformation_add_MT({"PW_Plant": "formalisms/PW_Plant"}, {"Encapsulated_PetriNet": "formalisms/Encapsulated_PetriNet"}, "models/plant_to_EPN", open("models/plant_to_EPN.mvc", 'r').read(), tracability_PLANT2EPN)
+transformation_add_MT({"PW_Control": "formalisms/PW_Control"}, {"Encapsulated_PetriNet": "formalisms/Encapsulated_PetriNet"}, "models/control_to_EPN", open("models/control_to_EPN.mvc", 'r').read(), tracability_CTRL2EPN)
+transformation_add_MT({"PW_Environment": "formalisms/PW_Environment"}, {"Encapsulated_PetriNet": "formalisms/Encapsulated_PetriNet"}, "models/environment_to_EPN", open("models/environment_to_EPN.mvc", 'r').read(), tracability_ENV2EPN)
+transformation_add_MT({"Encapsulated_PetriNet": "formalisms/Encapsulated_PetriNet", "Architecture": "formalisms/Architecture"}, {"PetriNet": "formalisms/PetriNet"}, "models/combine_EPN", open("models/combine_EPN.mvc", 'r').read(), tracability_EPN2PN)
+transformation_add_MT({"ReachabilityGraph": "formalisms/ReachabilityGraph", "Query": "formalisms/Query"}, {"ReachabilityGraph": "formalisms/ReachabilityGraph"}, "models/match", open("models/matches.mvc", 'r').read())
+
+transformation_add_AL({"PetriNet": "formalisms/PetriNet"}, {"ReachabilityGraph": "formalisms/ReachabilityGraph"}, "models/reachability", open("models/reachability.alc", 'r').read())
+transformation_add_AL({"ReachabilityGraph": "formalisms/ReachabilityGraph"}, {}, "models/bfs", open("models/bfs.alc", 'r').read())
+transformation_add_AL({"EPN_Plant": "formalisms/Encapsulated_PetriNet", "EPN_Control": "formalisms/Encapsulated_PetriNet", "EPN_Environment": "formalisms/Encapsulated_PetriNet"}, {"Encapsulated_PetriNet": "formalisms/Encapsulated_PetriNet"}, "models/merge_EPN", open("models/merge_EPN.alc", 'r').read())
+
+transformation_add_AL({"Encapsulated_PetriNet": "formalisms/Encapsulated_PetriNet"}, {}, "epn_print", open("models/epn_print.alc").read())
+transformation_add_AL({"PetriNet": "formalisms/PetriNet"}, {}, "pn_print", open("models/pn_print.alc").read())
+"""

+ 24 - 17
scripts/run_local_modelverse.py

@@ -8,33 +8,40 @@ if len(sys.argv) < 2:
 else:
 else:
     port = sys.argv[1]
     port = sys.argv[1]
 
 
-# Start up the HUTN compilation service already
 try:
 try:
-    hutn = subprocess.Popen([sys.executable, "scripts/HUTN_service.py", "127.0.0.1:%s" % port])
-    json = subprocess.Popen([sys.executable, "scripts/JSON_service.py", "127.0.0.1:%s" % port])
+    # Compile all SCCD models first
+    os.chdir("wrappers")
+    subprocess.check_call([sys.executable, "-m", "sccd.compiler.sccdc", "-p", "threads", "modelverse_SCCD.xml"])
 
 
-    os.chdir("hybrid_server")
+    os.chdir("../hybrid_server")
     subprocess.check_call([sys.executable, "-m", "sccd.compiler.sccdc", "-p", "threads", "server.xml"])
     subprocess.check_call([sys.executable, "-m", "sccd.compiler.sccdc", "-p", "threads", "server.xml"])
 
 
-    program_to_execute = [sys.executable, "run_mvk_server.py", port]
+    os.chdir("..")
 
 
-    # Alternative execution modes
-    #program_to_execute = [sys.executable, "-m", "cProfile", "-s", "tottime", "run_mvk_server.py", port]
-    #program_to_execute = [sys.executable, "run_mvk_server.py", port, "--kernel=interpreter"]
-    #program_to_execute = [sys.executable, "run_mvk_server.py", port, "--kernel=fast-jit"]
+    # Start up all services with auto-detection
+    import glob
+    service_paths = glob.glob("services/*/main.py")
+    services = []
+    for service_path in service_paths:
+        print("[SERVICE] loaded " + service_path)
+        service = subprocess.Popen([sys.executable, service_path, "127.0.0.1:%s" % port])
+        services.append(service)
 
 
+    os.chdir("hybrid_server")
+    program_to_execute = [sys.executable, "run_mvk_server.py", port]
     server = subprocess.Popen(program_to_execute)
     server = subprocess.Popen(program_to_execute)
+
     server.wait()
     server.wait()
 finally:
 finally:
+    # Stop the server
     try:
     try:
         server.terminate()
         server.terminate()
     except:
     except:
         pass
         pass
-    try:
-        hutn.terminate()
-    except:
-        pass
-    try:
-        json.terminate()
-    except:
-        pass
+
+    # Terminate all services as well
+    for service in services:
+        try:
+            service.terminate()
+        except:
+            pass

+ 62 - 0
services/DEVS/main.py

@@ -0,0 +1,62 @@
+import sys
+sys.path.append("wrappers")
+from modelverse import *
+import random, re, json, uuid
+from pprint import pprint
+from multiprocessing import Process, Pipe, freeze_support
+
+sys.path.append('services/DEVS/pypdevs/src')
+
+from simulator import Controller
+import threading, time
+
+init(sys.argv[1])
+login("pypdevs_service", "my_password")
+
+def pypdevs_service(port):
+    exec service_get(port) in globals()
+    controller = Controller(Root())
+
+    def inputter():
+        print "Waiting for input..."
+        while 1:
+            try:
+                input = service_get(port)
+                print 'raw input = %s' % input
+                params = json.loads(input)
+                print 'json parsed = %s' % params
+                if not isinstance(params, list):
+                    params = [params]
+                print "Sending input to simulator: %s" % params
+                if (len(params) > 1):
+                    controller.addInput(Event(params[0], "request", params[1:]))
+                else:
+                    controller.addInput(Event(params[0], "request", []))
+            except:
+                import traceback
+                traceback.print_exc()
+    input_thread = threading.Thread(target=inputter)
+    input_thread.daemon = True
+    input_thread.start()
+
+    output_listener = controller.addOutputListener(["reply"])
+    def outputter():
+        print "Waiting for output..."
+        while 1:
+            output_val = output_listener.fetch(-1)
+            print "Got output from simulator: %s" % output_val
+            service_set(port, json.dumps({"name": output_val.getName(), "port": output_val.getPort(), "params": output_val.getParameters()}))
+    output_thread = threading.Thread(target=outputter)
+    output_thread.daemon = True
+    output_thread.start()
+
+    controller.start()
+
+service_register("pypdevs_simulator", pypdevs_service)
+
+try:
+    while True:
+        # Stay active, as we shouldn't exit while the service is running!
+        time.sleep(1)
+finally:
+    service_stop()

+ 161 - 0
services/DEVS/pypdevs/examples/client.py

@@ -0,0 +1,161 @@
+print("SCCD PythonPDEVS CLI interface")
+import sys
+import time
+from pprint import pprint
+sys.path.append("../src/")
+from sccd.runtime.statecharts_core import Event
+
+import simulator
+from ps_model import Root
+controller = simulator.Controller(Root())
+reply_port = controller.addOutputListener('reply')
+
+def set_defaults(inp, defaultlist):
+    for i, v in enumerate(defaultlist):
+        if len(inp) == i + 1:
+            inp.append(v)
+
+def get_bool(val):
+    if val.lower() in ["true", "yes", "1"]:
+        return True
+    else:
+        return False
+
+def poll_port(port):
+    while 1:
+        try:
+            event = port.fetch(-1)
+            print("%s" % event.getName())
+            pprint(event.getParameters())
+        except:
+            pass
+
+def generate_input():
+    print("READY for input")
+    print("Type 'help' for information")
+    while 1:
+        inp = raw_input().split(" ")
+        action = inp[0]
+        if inp[0] == "simulate":
+            set_defaults(inp, ['inf'])
+            params = [{"termination_time": float(inp[1])}]
+        elif inp[0] == "big_step":
+            set_defaults(inp, ['inf'])
+            params = [{"termination_time": float(inp[1])}]
+        elif inp[0] == "realtime":
+            set_defaults(inp, ['inf', 1.0])
+            params = [{"termination_time": float(inp[1]), "realtime_scale": float(inp[2])}]
+        elif inp[0] == "small_step":
+            set_defaults(inp, ['inf'])
+            params = [{"termination_time": float(inp[1])}]
+        elif inp[0] == "god_event":
+            if len(inp) != 4:
+                print("God Events require 3 parameters!")
+                continue
+            params = [{"model": inp[1], "attribute": inp[2], "value": inp[3]}]
+        elif inp[0] == "inject":
+            if len(inp) != 4:
+                print("Injects require 3 parameters!")
+                continue
+            params = [{"time": float(inp[1]), "port": inp[2], "event": inp[3]}]
+        elif inp[0] == "trace":
+            set_defaults(inp, [None])
+            params = [inp[1]]
+        elif inp[0] == "pause":
+            params = []
+        elif inp[0] == "exit" or inp[0] == "quit":
+            break
+        elif inp[0] == "add_breakpoint":
+            if len(inp) < 5:
+                print("Breakpoint removal requires 2 parameters!")
+                continue
+            # Merge together the final part again
+            inp = [inp[0], inp[1], " ".join(inp[2:-2]).replace("\\n", "\n"), get_bool(inp[-2]), get_bool(inp[-1])]
+            print("Generated parameters: " + str(inp))
+            params = inp[1:]
+        elif inp[0] == "del_breakpoint":
+            if len(inp) < 2:
+                print("Breakpoint removal requires 1 parameter!")
+                continue
+            params = [inp[1]]
+        elif inp[0] == "enable_breakpoint":
+            action = "toggle_breakpoint"
+            params = [inp[1], True]
+        elif inp[0] == "disable_breakpoint":
+            action = "toggle_breakpoint"
+            params = [inp[1], False]
+        elif inp[0] == "reset":
+            params = []
+        elif inp[0] == "backwards_step":
+            params = []
+        elif inp[0] == "help":
+            print("Supported operations:")
+            print("  simulate [termination_time]")
+            print("   --> Simulate until termination time is reached")
+            print("  big_step [termination_time]")
+            print("   --> Simulate a single step, unless termination time is reached")
+            print("  small_step [termination_time]")
+            print("   --> Simulate a single internal simulation step")
+            print("       Termination time is ONLY checked at the")
+            print("       check_termination phase")
+            print("  backwards_step")
+            print("   --> Step back to the previous time")
+            print("  realtime [termination_time [realtime_scale]]")
+            print("   --> Simulate in realtime until simulation time is reached")
+            print("       realtime_scale can speed up or slow down the pace")
+            print("  god_event model_name attribute_name new_value")
+            print("   --> Modify the internal state of an arbitrary model")
+            print("       model_name should be the fully qualified name")
+            print("       attribute_name is the name of the attribute to alter")
+            print("       new_value is the value to assign")
+            print("       new_value can only be a string due to string-only input")
+            print("  inject time port_name event")
+            print("   --> Put a user-defined event on an input port")
+            print("       port_name should be a fully qualified port name")
+            print("       event should be the event to put on it, string only")
+            print("  trace [filename]")
+            print("   --> Write out trace information to the specified file.")
+            print("       Leave empty to disable tracing.")
+            print("  add_breakpoint id function enabled disable_on_trigger")
+            print("   --> Add a breakpoint that will pause simulation when function returns True")
+            print("       the function should contain a definition of the 'breakpoint' function")
+            print("       and must take 3 parameters: time, model and transitioned")
+            print("       enabled indicates whether or not the breakpoint should be checked")
+            print("       disable_on_trigger determines if the breakpoint should auto-disable")
+            print("       after being triggered")
+            print("  del_breakpoint id")
+            print("   --> Remove a breakpoint")
+            print("  enable_breakpoint id")
+            print("   --> Enable the provided breakpoint")
+            print("  disable_breakpoint id")
+            print("   --> Disable the provided breakpoint")
+            print("  reset")
+            print("   --> Reset the simulation")
+            print("  exit")
+            print("   --> Stop the client")
+            print("  pause")
+            print("   --> Pause the simulation")
+            print("  quit")
+            print("   --> Stop the client")
+            print("")
+            print("Defaults: ")
+            print("  termination_time --> 'inf'")
+            print("  realtime_scale   --> 1.0")
+            continue
+        else:
+            print("Command not understood: " + str(inp))
+            continue
+        controller.addInput(Event(action, "request", params))
+      
+import threading
+poll_thrd = threading.Thread(target=poll_port,args=[reply_port])
+poll_thrd.daemon = True
+poll_thrd.start()
+inp_thrd = threading.Thread(target=generate_input)
+inp_thrd.daemon = True
+inp_thrd.start()
+          
+try:
+    controller.start()
+finally:
+    controller.stop()

+ 36 - 0
services/DEVS/pypdevs/examples/experiment.py

@@ -0,0 +1,36 @@
+import sys
+import time
+sys.path.append("../src/")
+from python_runtime.statecharts_core import Event
+
+import sccd
+from model import TrafficSystem
+controller = sccd.Controller(TrafficSystem(name="MyTrafficSystem"))
+controller.start()
+reply_port = controller.addOutputListener('reply')
+"""
+params = [{"termination_time": 10, "realtime_scale": 3.0}]
+controller.addInput(Event("realtime", "request", params))
+print(reply_port.fetch(-1))
+params = [{"termination_time": 20, "realtime_scale": 0.333}]
+controller.addInput(Event("realtime", "request", params))
+print(reply_port.fetch(-1))
+params = [{"termination_time": 50, "realtime_scale": 1.0}]
+controller.addInput(Event("simulate", "request", params))
+print(reply_port.fetch(-1))
+"""
+params = [{"termination_time": 50}]
+controller.addInput(Event("big_step", "request", params))
+print(reply_port.fetch(-1))
+for _ in range(10):
+    controller.addInput(Event("small_step", "request", params))
+    #print(reply_port.fetch(-1))
+controller.addInput(Event("big_step", "request", params))
+print(reply_port.fetch(-1))
+params = [{"model": "MyTrafficSystem.trafficLight", "attribute": "colour", "value": "green"}]
+controller.addInput(Event("god_event", "request", params))
+print(reply_port.fetch(-1))
+params = [{"termination_time": 5000}]
+controller.addInput(Event("simulate", "request", params))
+print(reply_port.fetch(-1))
+controller.stop()

+ 129 - 0
services/DEVS/pypdevs/examples/exported_model.py

@@ -0,0 +1,129 @@
+from DEVS import *
+from infinity import INFINITY
+
+class Generator(AtomicDEVS):
+        def __init__(self, name="Generator"):
+                AtomicDEVS.__init__(self, name)
+                self.state = {'name': "generating"}
+                self.my_ports = {"g_out": self.addOutPort("g_out")}
+        def timeAdvance(self):
+
+                if self.state['name'] == 'generating':
+                        return 1
+
+        def outputFnc(self):
+
+                if self.state['name'] == 'generating':
+                        return {self.my_ports['g_out']: [{'type': 'Job', 'repr': {'duration': 0.3}}]}
+
+        def intTransition(self):
+
+                if self.state['name'] == 'generating':
+                        new_state = {}
+                        new_state['name'] = 'generating'
+                        return new_state
+
+        def extTransition(self, my_inputs):
+
+                inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
+                return AtomicDEVS.extTransition(self, my_inputs)
+
+        def confTransition(self, my_inputs):
+
+                inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
+                return AtomicDEVS.confTransition(self, my_inputs)
+
+class Processor(AtomicDEVS):
+        def __init__(self, name="Processor"):
+                AtomicDEVS.__init__(self, name)
+                self.state = {'name': "idle"}
+                self.my_ports = {"p_in": self.addInPort("p_in"), "p_out": self.addOutPort("p_out")}
+        def timeAdvance(self):
+
+                if self.state['name'] == 'processing':
+                        return self.state['job']['duration']
+                if self.state['name'] == 'idle':
+                        return INFINITY
+
+        def outputFnc(self):
+
+                if self.state['name'] == 'processing':
+                        return {self.my_ports['p_out']: [{'type': 'Job', 'repr': self.state['job']}]}
+                if self.state['name'] == 'idle':
+                        return {}
+
+        def intTransition(self):
+
+                if self.state['name'] == 'processing':
+                        new_state = {}
+                        new_state['name'] = 'idle'
+                        return new_state
+
+        def extTransition(self, my_inputs):
+
+                inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
+                if self.state['name'] == 'idle':
+                        new_state = {}
+                        new_state['name'] = 'processing'
+                        new_state['job'] = inputs['p_in'][0]['repr']
+                        return new_state
+                else:
+                        return AtomicDEVS.extTransition(self, my_inputs)
+
+        def confTransition(self, my_inputs):
+
+                inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
+                return AtomicDEVS.confTransition(self, my_inputs)
+
+class Collector(AtomicDEVS):
+        def __init__(self, name="Collector"):
+                AtomicDEVS.__init__(self, name)
+                self.state = {'name': "waiting"}
+                self.my_ports = {"c_in": self.addInPort("c_in")}
+        def timeAdvance(self):
+
+                if self.state['name'] == 'waiting':
+                        return INFINITY
+
+        def outputFnc(self):
+
+                if self.state['name'] == 'waiting':
+                        return {}
+
+        def intTransition(self):
+
+                return AtomicDEVS.intTransition(self, my_inputs)
+
+        def extTransition(self, my_inputs):
+
+                inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
+                if self.state['name'] == 'waiting':
+                        new_state = {}
+                        new_state['name'] = 'waiting'
+                        new_state['nr_of_jobs'] = self.state['nr_of_jobs'] + 1
+                        return new_state
+                else:
+                        return AtomicDEVS.extTransition(self, my_inputs)
+
+        def confTransition(self, my_inputs):
+
+                inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
+                return AtomicDEVS.confTransition(self, my_inputs)
+
+class CoupledProcessor(CoupledDEVS):
+        def __init__(self, name="CoupledProcessor"):
+                CoupledDEVS.__init__(self, name)
+                self.my_ports = {"cp_out": self.addOutPort("cp_out"), "cp_in": self.addInPort("cp_in")}
+                self.submodels = {"p1": self.addSubModel(Processor(name="p1")), "p2": self.addSubModel(Processor(name="p2"))}
+                self.connectPorts(self.my_ports["cp_in"], self.submodels["p1"].my_ports["p_in"])
+                self.connectPorts(self.submodels["p1"].my_ports["p_out"], self.submodels["p2"].my_ports["p_in"])
+                self.connectPorts(self.submodels["p2"].my_ports["p_out"], self.my_ports["cp_out"])
+
+class Root(CoupledDEVS):
+        def __init__(self, name="Root"):
+                CoupledDEVS.__init__(self, name)
+                self.my_ports = {}
+                self.submodels = {"generator": self.addSubModel(Generator(name="generator")), "coupledprocessor": self.addSubModel(CoupledProcessor(name="coupledprocessor")), "processor": self.addSubModel(Processor(name="processor")), "collector": self.addSubModel(Collector(name="collector"))}
+                self.connectPorts(self.submodels["coupledprocessor"].my_ports["cp_out"], self.submodels["processor"].my_ports["p_in"])
+                self.connectPorts(self.submodels["generator"].my_ports["g_out"], self.submodels["coupledprocessor"].my_ports["cp_in"])
+                self.connectPorts(self.submodels["processor"].my_ports["p_out"], self.submodels["collector"].my_ports["c_in"])

+ 29 - 0
services/DEVS/pypdevs/examples/helpers.py

@@ -0,0 +1,29 @@
+def canRiotAPC(queue):
+    t_q = [i['type'] for i in queue]
+    return t_q.count('Wheel') >= 4 and t_q.count('Body') >= 1 and t_q.count('WaterCannon') >= 1
+
+def isRiotAPC(queue):
+    if canRiotAPC(queue):
+        toremove = ['Wheel','Wheel','Wheel','Wheel','Body','WaterCannon']
+        while toremove:
+            tofind = toremove.pop()
+            for idx, it in enumerate(queue):
+                if (it['type'] == tofind):
+                    break
+            del queue[idx]
+        return True
+
+def canWarAPC(queue):
+    t_q = [i['type'] for i in queue]
+    return t_q.count('Tracks') >= 2 and t_q.count('Body') >= 1 and t_q.count('MachineGun') >= 1
+        
+def isWarAPC(queue):
+    if canWarAPC(queue):
+        toremove = ['Tracks','Tracks','Body','MachineGun']
+        while toremove:
+            tofind = toremove.pop()
+            for idx, it in enumerate(queue):
+                if (it['type'] == tofind):
+                    break
+            del queue[idx]
+        return True

+ 1 - 0
services/DEVS/pypdevs/examples/infinity.py

@@ -0,0 +1 @@
+INFINITY = float('inf')

+ 286 - 0
services/DEVS/pypdevs/examples/model.py

@@ -0,0 +1,286 @@
+# Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+# McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# Import code for DEVS model representation:
+from DEVS import *
+from infinity import INFINITY
+
+class TrafficLightMode:
+    """
+    Encapsulates the system's state
+    """
+
+    def __init__(self, current="red"):
+        """
+        Constructor (parameterizable).
+        """
+        self.set(current)
+
+    def set(self, value="red"):
+        self.__colour=value
+
+    def get(self):
+        return self.__colour
+
+    def __str__(self):
+        return self.get()
+
+class TrafficLight(AtomicDEVS):
+    """
+    A traffic light 
+    """
+  
+    def __init__(self, name=None):
+        """
+        Constructor (parameterizable).
+        """
+        # Always call parent class' constructor FIRST:
+        AtomicDEVS.__init__(self, name)
+    
+        # STATE:
+        #  Define 'state' attribute (initial sate):
+        self.state = TrafficLightMode("red") 
+
+        # ELAPSED TIME:
+        #  Initialize 'elapsed time' attribute if required
+        #  (by default, value is 0.0):
+        self.elapsed = 1.5 
+        # with elapsed time initially 1.5 and initially in 
+        # state "red", which has a time advance of 60,
+        # there are 60-1.5 = 58.5time-units  remaining until the first 
+        # internal transition 
+    
+        # PORTS:
+        #  Declare as many input and output ports as desired
+        #  (usually store returned references in local variables):
+        self.INTERRUPT = self.addInPort(name="INTERRUPT")
+        self.OBSERVED = self.addOutPort(name="OBSERVED")
+
+    def extTransition(self, inputs):
+        """
+        External Transition Function.
+        """
+        # Compute the new state 'Snew' based (typically) on current
+        # State, Elapsed time parameters and calls to 'self.peek(self.IN)'.
+        input = inputs.get(self.INTERRUPT)[0]
+
+        state = self.state.get()
+
+        if input == "toManual":
+            if state == "manual":
+                # staying in manual mode
+                return TrafficLightMode("manual")
+            elif state in ("red", "green", "yellow"):
+                return TrafficLightMode("manual")
+        elif input == "toAutonomous":
+            if state == "manual":
+                return TrafficLightMode("red")
+            elif state in ("red", "green", "yellow"):
+                # If toAutonomous is given while still autonomous, just stay in this state
+                return self.state
+        raise DEVSException(\
+            "unknown state <%s> in TrafficLight external transition function"\
+            % state) 
+
+    def intTransition(self):
+        """
+        Internal Transition Function.
+        """
+
+        state = self.state.get()
+
+        if state == "red":
+            return TrafficLightMode("green")
+        elif state == "green":
+            return TrafficLightMode("yellow")
+        elif state == "yellow":
+            return TrafficLightMode("red")
+        else:
+            raise DEVSException(\
+                "unknown state <%s> in TrafficLight internal transition function"\
+                % state)
+  
+    def outputFnc(self):
+        """
+        Output Funtion.
+        """
+   
+        # A colourblind observer sees "grey" instead of "red" or "green".
+ 
+        # BEWARE: ouput is based on the OLD state
+        # and is produced BEFORE making the transition.
+        # We'll encode an "observation" of the state the
+        # system will transition to !
+
+        # Send messages (events) to a subset of the atomic-DEVS' 
+        # output ports by means of the 'poke' method, i.e.:
+        # The content of the messages is based (typically) on current State.
+ 
+        state = self.state.get()
+
+        if state == "red":
+            return {self.OBSERVED: ["grey"]}
+        elif state == "green":
+            return {self.OBSERVED: ["yellow"]}
+        elif state == "yellow":
+            return {self.OBSERVED: ["grey"]}
+        else:
+            raise DEVSException(\
+                "unknown state <%s> in TrafficLight external transition function"\
+                % state)
+    
+    def timeAdvance(self):
+        """
+        Time-Advance Function.
+        """
+        # Compute 'ta', the time to the next scheduled internal transition,
+        # based (typically) on current State.
+        state = self.state.get()
+        if state == "red":
+            return 60 
+        elif state == "green":
+            return 50 
+        elif state == "yellow":
+            return 10 
+        elif state == "manual":
+            return INFINITY 
+        else:
+            raise DEVSException(\
+                "unknown state <%s> in TrafficLight time advance transition function"\
+                % state)
+
+class PolicemanMode:
+    """
+    Encapsulates the Policeman's state
+    """
+    def __init__(self, current="idle"):
+        """
+        Constructor (parameterizable).
+        """
+        self.set(current)
+
+    def set(self, value="idle"):
+        self.__mode=value
+
+    def get(self):
+        return self.__mode
+
+    def __str__(self):
+        return self.get()
+
+class Policeman(AtomicDEVS):
+    """
+    A policeman producing "toManual" and "toAutonomous" events:
+    "toManual" when going from "idle" to "working" mode
+    "toAutonomous" when going from "working" to "idle" mode
+    """
+    def __init__(self, name=None):
+        """
+        Constructor (parameterizable).
+        """
+    
+        # Always call parent class' constructor FIRST:
+        AtomicDEVS.__init__(self, name)
+    
+        # STATE:
+        #  Define 'state' attribute (initial sate):
+        self.state = PolicemanMode("idle") 
+
+        # ELAPSED TIME:
+        #  Initialize 'elapsed time' attribute if required
+        #  (by default, value is 0.0):
+        self.elapsed = 0 
+    
+        # PORTS:
+        #  Declare as many input and output ports as desired
+        #  (usually store returned references in local variables):
+        self.OUT = self.addOutPort(name="OUT")
+
+    def intTransition(self):
+        """
+        Internal Transition Function.
+        The policeman works forever, so only one mode. 
+        """
+  
+        state = self.state.get()
+
+        if state == "idle":
+            return PolicemanMode("working")
+        elif state == "working":
+            return PolicemanMode("idle")
+        else:
+            raise DEVSException(\
+                "unknown state <%s> in Policeman internal transition function"\
+                % state)
+    
+    def outputFnc(self):
+        """
+        Output Funtion.
+        """
+        # Send messages (events) to a subset of the atomic-DEVS' 
+        # output ports by means of the 'poke' method, i.e.:
+        # The content of the messages is based (typically) on current State.
+        state = self.state.get()
+        if state == "idle":
+            return {self.OUT: ["toManual"]}
+        elif state == "working":
+            return {self.OUT: ["toAutonomous"]}
+        else:
+            raise DEVSException(\
+                "unknown state <%s> in Policeman output function"\
+                % state)
+    
+    def timeAdvance(self):
+        """
+        Time-Advance Function.
+        """
+        # Compute 'ta', the time to the next scheduled internal transition,
+        # based (typically) on current State.
+    
+        state = self.state.get()
+
+        if state == "idle":
+            return 200 
+        elif state == "working":
+            return 100 
+        else:
+            raise DEVSException(\
+                "unknown state <%s> in Policeman time advance function"\
+                % state)
+
+class Root(CoupledDEVS):
+    def __init__(self, name="Root"):
+        """
+        A simple traffic system consisting of a Policeman and a TrafficLight.
+        """
+        # Always call parent class' constructor FIRST:
+        CoupledDEVS.__init__(self, name)
+
+        # Declare the coupled model's output ports:
+        # Autonomous, so no output ports
+
+        # Declare the coupled model's sub-models:
+
+        # The Policeman generating interrupts 
+        self.policeman = self.addSubModel(Policeman(name="policeman"))
+
+        # The TrafficLight 
+        self.trafficLight = self.addSubModel(TrafficLight(name="trafficLight"))
+
+        # Only connect ...
+        self.connectPorts(self.policeman.OUT, self.trafficLight.INTERRUPT)
+

File diff suppressed because it is too large
+ 430 - 0
services/DEVS/pypdevs/examples/ps_model.py


+ 536 - 0
services/DEVS/pypdevs/src/DEVS.py

@@ -0,0 +1,536 @@
+# -*- coding: Latin-1 -*-
+"""
+Classes and tools for DEVS model specification
+"""
+
+from devsexception import DEVSException
+
+class BaseDEVS(object):
+    """
+    Abstract base class for AtomicDEVS and CoupledDEVS classes.
+  
+    This class provides basic DEVS attributes and query/set methods.
+    """
+    def __init__(self, name):
+        """
+        Constructor
+
+        :param name: the name of the DEVS model
+        """
+    
+        # Prevent any attempt to instantiate this abstract class
+        if self.__class__ == BaseDEVS:
+            raise DEVSException ("Cannot instantiate abstract class '%s' ... " 
+                                 % (self.__class__.__name__))
+
+        # The parent of the current model
+        self.parent = None
+        # The local name of the model
+        self.name = name
+        self.IPorts  = []  
+        self.OPorts   = []
+        self.ports = []
+
+        # Initialise the times
+        self.timeLast = (0.0, 0)
+        self.timeNext = (0.0, 1)
+
+        self.location = None
+    
+        # Variables used for optimisations
+        self.myInput = {}  
+        self.myOutput = {}
+
+        # The state queue, used for time warp
+        self.oldStates = []
+        # List of all memoized states, only useful in distributed simulation 
+        #   with memoization enabled
+        self.memo = []
+
+    def modelTransition(self, state):
+        """
+        DEFAULT function for Dynamic Structure DEVS, always returning False (thus indicating that no structural change is needed)
+
+        :param state: a dict that can be used to save some kind of state, this object is maintained by the kernel and will be passed each time
+        :returns: bool -- whether or not a structural change is necessary
+        """
+        return False
+
+    def addPort(self, name, isInput):
+        """
+        Utility function to create a new port and add it everywhere where it is necessary
+
+        :param name: the name of the port
+        :param isInput: whether or not this is an input port
+        """
+        name = name if name is not None else "port%s" % len(self.ports)
+        port = Port(isInput=isInput, name=name) 
+        if isInput:
+            self.IPorts.append(port)
+        else:
+            self.OPorts.append(port)
+        port.port_id = len(self.ports)
+        self.ports.append(port)
+        port.hostDEVS = self
+        return port
+      
+    def addInPort(self, name=None):
+        """
+        Add an input port to the DEVS model.
+        
+        addInPort is the only proper way to add input ports to a DEVS model. 
+        As for the CoupledDEVS.addSubModel method, calls
+        to addInPort and addOutPort can appear in any DEVS'
+        descriptive class constructor, or the methods can be used with an
+        instantiated object.
+    
+        The methods add a reference to the new port in the DEVS' IPorts 
+        attributes and set the port's hostDEVS attribute. The modeler
+        should typically save the returned reference somewhere.
+
+        :param name: the name of the port. A unique ID will be generated in case None is passed
+        :returns: port -- the generated port
+        """
+        return self.addPort(name, True)
+      
+    def addOutPort(self, name=None):
+        """Add an output port to the DEVS model.
+
+        addOutPort is the only proper way to
+        add output ports to DEVS. As for the CoupledDEVS.addSubModel method, calls
+        to addInPort and addOutPort can appear in any DEVS'
+        descriptive class constructor, or the methods can be used with an
+        instantiated object.
+    
+        The methods add a reference to the new port in the DEVS'
+        OPorts attributes and set the port's hostDEVS attribute. The modeler
+        should typically save the returned reference somewhere.
+
+        :param name: the name of the port. A unique ID will be generated in case None is passed
+        :returns: port -- the generated port
+        """
+        return self.addPort(name, False)
+    
+    def getModelName(self):
+        """
+        Get the local model name
+
+        :returns: string -- the name of the model
+        """
+        return str(self.name)
+
+    def getModelFullName(self):
+        """
+        Get the full model name, including the path from the root
+
+        :returns: string -- the fully qualified name of the model
+        """
+        return self.fullName
+
+class AtomicDEVS(BaseDEVS):
+    """
+    Abstract base class for all atomic-DEVS descriptive classes.
+    """
+  
+    def __init__(self, name=None):
+        """
+        Constructor for an AtomicDEVS model
+
+        :param name: name of the model, can be None to have an automatically generated name
+        """
+        # Prevent any attempt to instantiate this abstract class
+        if self.__class__ == AtomicDEVS:
+            raise DEVSException("Cannot instantiate abstract class '%s' ... " 
+                                % (self.__class__.__name__))
+
+        # The minimal constructor shall first call the superclass
+        # (i.e., BaseDEVS) constructor.
+        BaseDEVS.__init__(self, name)
+    
+        self.elapsed = 0.0 
+        self.state = None
+
+    def extTransition(self, inputs):
+        """
+        DEFAULT External Transition Function.
+  
+        Accesses state and elapsed attributes, as well as inputs
+        through the passed dictionary. Returns the new state.
+
+        .. note:: Should only write to the *state* attribute.
+
+        :param inputs: dictionary containing all ports and their corresponding outputs
+        :returns: state -- the new state of the model
+        """
+        return self.state
+    
+    def intTransition(self):
+        """
+        DEFAULT Internal Transition Function.
+ 
+        .. note:: Should only write to the *state* attribute.
+
+        :returns: state -- the new state of the model
+
+        .. versionchanged:: 2.1 The *elapsed* attribute is no longer guaranteed to be correct as this isn't required by the DEVS formalism.
+
+        """
+        return self.state
+
+    def confTransition(self, inputs):
+        """
+        DEFAULT Confluent Transition Function.
+  
+        Accesses state and elapsed attributes, as well as inputs
+        through the passed dictionary. Returns the new state.
+
+        .. note:: Should only write to the *state* attribute.
+
+        :param inputs: dictionary containing all ports and their corresponding outputs
+        :returns: state -- the new state of the model
+        """
+        self.state = self.intTransition()
+        self.state = self.extTransition(inputs)
+        return self.state
+  
+    def outputFnc(self):
+        """
+        DEFAULT Output Function.
+  
+        Accesses only state attribute. Returns the output on the different ports as a dictionary.
+
+        .. note:: Should **not** write to any attribute.
+
+        :returns: dictionary containing output ports as keys and lists of output on that port as value
+
+        .. versionchanged:: 2.1 The *elapsed* attribute is no longer guaranteed to be correct as this isn't required by the DEVS formalism.
+
+        """
+        return {}
+  
+    def timeAdvance(self):
+        """
+        DEFAULT Time Advance Function.
+    
+        .. note:: Should ideally be deterministic, though this is not mandatory for simulation.
+
+        :returns: the time advance of the model
+
+        .. versionchanged:: 2.1 The *elapsed* attribute is no longer guaranteed to be correct as this isn't required by the DEVS formalism.
+
+        """
+        # By default, return infinity 
+        return float('inf')
+
+    def finalize(self, name, model_counter, model_ids, locations, selectHierarchy):
+        """
+        Finalize the model hierarchy by doing all pre-simulation configuration
+
+        .. note:: Parameters *model_ids* and *locations* are updated by reference.
+
+        :param name: the name of the hierarchy above
+        :param model_counter: the model ID counter
+        :param model_ids: a list with all model_ids and their model
+        :param locations: dictionary of locations and where every model runs
+        :param selectHierarchy: hierarchy to perform selections in Classic DEVS
+
+        :returns: int -- the new model ID counter
+        """
+        # Give a name
+        self.fullName = name + str(self.getModelName())
+
+        # Give a unique ID to the model itself
+        self.model_id = model_counter
+        self.selectHierarchy = selectHierarchy + [self]
+
+        # Add the element to its designated place in the model_ids list
+        model_ids.append(self)
+
+        # Do a quick check, since this is vital to correct operation
+        if model_ids[self.model_id] != self:
+            raise DEVSException("Something went wrong while initializing models: IDs don't match")
+
+        locations[self.location].append(self.model_id)
+
+        # Return the unique ID counter, incremented so it stays unique
+        return model_counter + 1
+
+class CoupledDEVS(BaseDEVS):
+    """
+    Abstract base class for all coupled-DEVS descriptive classes.
+    """
+  
+    def __init__(self, name=None):
+        """
+        Constructor.
+
+        :param name: the name of the coupled model, can be None for an automatically generated name
+        """
+        # Prevent any attempt to instantiate this abstract class
+        if self.__class__ == CoupledDEVS:
+            raise DEVSException("Cannot instantiate abstract class '%s' ... " 
+                                % (self.__class__.__name__))
+        # The minimal constructor shall first call the superclass
+        # (i.e., BaseDEVS) constructor.
+        BaseDEVS.__init__(self, name)
+    
+        # All components of this coupled model (the submodels)
+        self.componentSet = []
+
+    def finalize(self, name, model_counter, model_ids, locations, selectHierarchy):
+        """
+        Finalize the model hierarchy by doing all pre-simulation configuration
+
+        .. note:: Parameters *model_ids* and *locations* are updated by reference.
+
+        :param name: the name of the hierarchy above
+        :param model_counter: the model ID counter
+        :param model_ids: a list with all model_ids and their model
+        :param locations: dictionary of locations and where every model runs
+        :param selectHierarchy: hierarchy to perform selections in Classic DEVS
+
+        :returns: int -- the new model ID counter
+        """
+        # Set name, even though it will never be requested
+        self.fullName = name + str(self.getModelName())
+        for i in self.componentSet:
+            model_counter = i.finalize(self.fullName + ".", model_counter, 
+                    model_ids, locations, selectHierarchy + [self])
+        return model_counter
+
+    def addSubModel(self, model, location = None):
+        """
+        Adds a specified model to the current coupled model as its child. This
+        is the function that must be used to make distributed simulation
+        possible.
+
+        :param model: the model to be added as a child
+        :param location: the location at which the child must run
+        :returns: model -- the model that was created as a child
+
+        .. versionchanged:: 2.1.3
+           model can no longer be a string, this was previously a lot more efficient in partial distribution, though this functionality was removed together with the partial distribution functionality.
+        """
+        model.parent = self
+        if location is not None:
+            location = int(location)
+        model.location = location if location is not None else self.location
+        if model.location is not None and isinstance(model, CoupledDEVS):
+            # Set the location of all children
+            for i in model.componentSet:
+                i.setLocation(model.location)
+        self.componentSet.append(model)        
+        if hasattr(self, "fullName"):
+            # Full Name is only created when starting the simulation, so we are currently in a running simulation
+            # Dynamic Structure change
+            self.server.getSelfProxy().dsScheduleModel(model)
+        return model
+
+    def connectPorts(self, p1, p2, z = None):
+        """
+        Connects two ports together. The coupling is to begin at p1 and
+        to end at p2.
+
+        :param p1: the port at the start of the new connection
+        :param p2: the port at the end of the new connection
+        :param z: the translation function for the events
+                  either input-to-input, output-to-input or output-to-output.
+        """
+        # For a coupling to be valid, two requirements must be met:
+        # 1- at least one of the DEVS the ports belong to is a child of the
+        #    coupled-DEVS (i.e., self), while the other is either the
+        #    coupled-DEVS itself or another of its children. The DEVS'
+        #    'parenthood relationship' uniquely determine the type of coupling;
+        # 2- the types of the ports are consistent with the 'parenthood' of the
+        #    associated DEVS. This validates the coupling determined above.
+
+        # Internal Coupling:
+        if ((p1.hostDEVS.parent == self and p2.hostDEVS.parent == self) and
+                (p1.type() == 'OUTPORT' and p2.type() == 'INPORT')):
+            if p1.hostDEVS is p2.hostDEVS:
+                raise DEVSException(("In coupled model '%s', connecting ports" +
+                                    " '%s' and '%s' belong to the same model" +
+                                    " '%s'. " +
+                                    " Direct feedback coupling not allowed") % (
+                                    self.getModelFullName(),
+                                    p1.getPortFullName(),
+                                    p2.getPortFullName(),
+                                    p1.hostDEVS.getModelFullName()))
+            else:
+                p1.outLine.append(p2)
+                p2.inLine.append(p1)
+        
+        # External input couplings:
+        elif ((p1.hostDEVS == self and p2.hostDEVS.parent == self) and
+              (p1.type() == p2.type() == 'INPORT')):
+            p1.outLine.append(p2)
+            p2.inLine.append(p1)
+   
+        # Eternal output couplings:
+        elif ((p1.hostDEVS.parent == self and p2.hostDEVS == self) and
+              (p1.type() == p2.type() == 'OUTPORT')):
+            p1.outLine.append(p2)
+            p2.inLine.append(p1)
+
+        # Other cases (illegal coupling):
+        else:
+            raise DEVSException(("Illegal coupling in coupled model '%s' " +
+                                "between ports '%s' and '%s'") % (
+                                self.getModelName(), p1.getPortName(), 
+                                p2.getPortName()))
+
+        p1.zFunctions[p2] = z
+        if hasattr(self, "server"):
+            self.server.getSelfProxy().dsUndoDirectConnect()
+
+class RootDEVS(BaseDEVS):
+    """
+    The artificial RootDEVS model is the only 'coupled' model in the simulation after direct connection is performed.
+    """
+    def __init__(self, components, models, schedulerType):
+        """
+        Basic constructor.
+
+        :param components: the atomic DEVS models that are the cildren, only those that are ran locally should be mentioned
+        :param models: all models that have to be passed to the scheduler, thus all models, even non-local ones
+        :param schedulerType: type of scheduler to use (string representation)
+        """
+        BaseDEVS.__init__(self, "ROOT model")
+        self.componentSet = components
+        self.timeNext = (float('inf'), 1)
+        self.local_model_ids = set()
+        for i in self.componentSet:
+            self.local_model_ids.add(i.model_id)
+        self.models = models
+        self.schedulerType = schedulerType
+        self.directConnected = True
+
+    def directConnect(self):
+        """
+        Perform direct connection on the models again
+        """
+        directConnect(self.models, True)
+
+    def setTimeNext(self):
+        """
+        Reset the timeNext
+        """
+        try:
+            self.timeNext = self.scheduler.readFirst()
+        except IndexError:
+            # No element found in the scheduler, so put it to INFINITY
+            self.timeNext = (float('inf'), 1)
+
+class Port(object):
+    """
+    Class for DEVS model ports (both input and output). This class provides basic port attributes and query methods.
+    """
+    def __init__(self, isInput, name=None):
+        """
+        Constructor. Creates an input port if isInput evaluates to True, and
+        an output port otherwise.
+
+        :param isInput: whether or not this is an input port
+        :param name: the name of the port. If None is provided, a unique ID is generated
+        """
+        self.inLine = [] 
+        self.outLine = []
+        self.hostDEVS = None 
+        self.msgcount = 0
+   
+        # The name of the port
+        self.name = name
+        self.isInput = isInput
+        self.zFunctions = {}
+
+    def getPortName(self):
+        """
+        Returns the name of the port
+
+        :returns: local name of the port
+        """
+        return self.name
+
+    def getPortFullName(self):
+        """
+        Returns the complete name of the port
+
+        :returns: fully qualified name of the port
+        """
+        return "%s.%s" % (self.hostDEVS.getModelFullName(), self.getPortName())
+
+    def type(self):
+        """
+        Returns the 'type' of the object
+
+        :returns: either 'INPORT' or 'OUTPORT'
+        """
+        if self.isInput:
+            return 'INPORT'
+        else:
+            return 'OUTPORT'
+
+def appendZ(first_z, new_z):
+    if first_z is None:
+        return new_z
+    elif new_z is None:
+        return first_z
+    else:
+        return lambda x: new_z(first_z(x))
+
+def directConnect(componentSet, local):
+    """
+    Perform direct connection on this CoupledDEVS model
+
+    :param componentSet: the iterable to direct connect
+    :param local: whether or not simulation is local; if it is, dynamic structure code will be prepared
+    :returns: the direct connected componentSet
+    """
+    newlist = []
+    for i in componentSet:
+        if isinstance(i, CoupledDEVS):
+            componentSet.extend(i.componentSet)
+        else:
+            # Found an atomic model
+            newlist.append(i)
+    componentSet = newlist
+
+    # All and only all atomic models are now direct children of this model
+    for i in componentSet:
+        # Remap the output ports
+        for outport in i.OPorts:
+            # The new contents of the line
+            outport.routingOutLine = []
+            worklist = [(p, outport.zFunctions.get(p, None)) for p in outport.outLine]
+            for outline, z in worklist:
+                # If it is a coupled model, we must expand this model
+                if isinstance(outline.hostDEVS, CoupledDEVS):
+                    for inline in outline.outLine:
+                        # Add it to the current iterating list, so we can just continue
+                        worklist.append((inline, appendZ(z, outline.zFunctions[inline])))
+                        # If it is a Coupled model, we should just continue 
+                        # expanding it and not add it to the finished line
+                        if not isinstance(inline.hostDEVS, CoupledDEVS):
+                            outport.routingOutLine.append((inline, appendZ(z, outline.zFunctions[inline])))
+                else:
+                    for ol, z in outport.routingOutLine:
+                        if ol == outline:
+                            break
+                    else:
+                        # Add to the new line if it isn't already there
+                        # Note that it isn't really mandatory to check for this, 
+                        # it is a lot cleaner to do so.
+                        # This will greatly increase the complexity of the connector though
+                        outport.routingOutLine.append((outline, z))
+        # Remap the input ports: identical to the output ports, only in the reverse direction
+        for inport in i.IPorts:
+            inport.routingInLine = []
+            for inline in inport.inLine:
+                if isinstance(inline.hostDEVS, CoupledDEVS):
+                    for outline in inline.inLine:
+                        inport.inLine.append(outline)
+                        if not isinstance(outline.hostDEVS, CoupledDEVS):
+                            inport.routingInLine.append(outline)
+                elif inline not in inport.routingInLine:
+                    inport.routingInLine.append(inline)
+    return componentSet

+ 17 - 0
services/DEVS/pypdevs/src/devsexception.py

@@ -0,0 +1,17 @@
+class DEVSException(Exception):
+    """
+    DEVS specific exceptions
+    """
+    def __init__(self, message="not specified in source"):
+        """
+        Constructor
+
+        :param message: error message to print
+        """
+        Exception.__init__(self, message)
+
+    def __str__(self):
+        """
+        String representation of the exception
+        """
+        return "DEVS Exception: " + str(self.message)

+ 1 - 0
services/DEVS/pypdevs/src/infinity.py

@@ -0,0 +1 @@
+INFINITY = float('inf')

+ 121 - 0
services/DEVS/pypdevs/src/mvk_widget.py

@@ -0,0 +1,121 @@
+'''
+Created on 27-jul.-2014
+
+@author: Simon
+'''
+import Tkinter as tk
+from python_runtime.statecharts_core import Event
+
+class MvKWidget:
+	controller = None
+
+	def __init__(self, configure_later=False):
+		if not configure_later:
+			self.set_bindable_and_tagorid(None, None)
+
+	def set_bindable_and_tagorid(self, bindable=None, tagorid=None):
+		if bindable is None:
+			bindable = self
+		self.bindable = bindable
+		self.mytagorid = tagorid
+		if isinstance(self, tk.Toplevel):
+			self.protocol("WM_DELETE_WINDOW", self.window_close)
+		if tagorid is not None:
+			if not isinstance(tagorid, list):
+				tagorid = [tagorid]
+			for t in tagorid:
+				self.bindable.tag_bind(t, "<Button>", self.on_click)
+				self.bindable.tag_bind(t, "<ButtonRelease>", self.on_release)
+				self.bindable.tag_bind(t, "<Motion>", self.on_motion)
+				self.bindable.tag_bind(t, "<Enter>", self.on_enter)
+				self.bindable.tag_bind(t, "<Leave>", self.on_leave)
+				self.bindable.tag_bind(t, "<Key>", self.on_key)
+				self.bindable.tag_bind(t, "<KeyRelease>", self.on_key_release)
+		else:
+			self.bindable.bind("<Button>", self.on_click)
+			self.bindable.bind("<ButtonRelease>", self.on_release)
+			self.bindable.bind("<Motion>", self.on_motion)
+			self.bindable.bind("<Enter>", self.on_enter)
+			self.bindable.bind("<Leave>", self.on_leave)
+			self.bindable.bind("<Key>", self.on_key)
+			self.bindable.bind("<KeyRelease>", self.on_key_release)
+		self.last_x = 50
+		self.last_y = 50
+
+	def on_click(self, event):
+		event_name = None
+
+		if event.num == 1:
+			event_name = "left-click"
+		elif event.num == 2:
+			event_name = "middle-click"
+		elif event.num == 3:
+			event_name = "right-click"
+
+		if event_name:
+			self.last_x = event.x
+			self.last_y = event.y
+			MvKWidget.controller.addInput(Event(event_name, "input", [id(self)]))
+
+	def on_release(self, event):
+		event_name = None
+
+		if event.num == 1:
+			event_name = "left-release"
+		elif event.num == 2:
+			event_name = "middle-release"
+		elif event.num == 3:
+			event_name = "right-release"
+
+		if event_name:
+			self.last_x = event.x
+			self.last_y = event.y
+			MvKWidget.controller.addInput(Event(event_name, "input", [id(self)]))
+
+	def on_motion(self, event):
+		self.last_x = event.x
+		self.last_y = event.y
+		MvKWidget.controller.addInput(Event("motion", "input", [id(self)]))
+
+	def on_enter(self, event):
+		MvKWidget.controller.addInput(Event("enter", "input", [id(self)]))
+
+	def on_leave(self, event):
+		MvKWidget.controller.addInput(Event("leave", "input", [id(self)]))
+
+	def on_key(self, event):
+		event_name = None
+
+		if event.keysym == 'Escape':
+			event_name = "escape"
+		elif event.keysym == 'Return':
+			event_name = "return"
+		elif event.keysym == 'Delete':
+			event_name = "delete"
+		elif event.keysym == 'Shift_L':
+			event_name = "shift"
+		elif event.keysym == 'Control_L':
+			event_name = "control"
+
+		if event_name:
+			MvKWidget.controller.addInput(Event(event_name, "input", [id(self)]))
+
+	def on_key_release(self, event):
+		event_name = None
+
+		if event.keysym == 'Escape':
+			event_name = "escape-release"
+		elif event.keysym == 'Return':
+			event_name = "return-release"
+		elif event.keysym == 'Delete':
+			event_name = "delete-release"
+		elif event.keysym == 'Shift_L':
+			event_name = "shift-release"
+		elif event.keysym == 'Control_L':
+			event_name = "control-release"
+
+		if event_name:
+			MvKWidget.controller.addInput(Event(event_name, "input", [id(self)]))
+
+	def window_close(self):
+		MvKWidget.controller.addInput(Event("window-close", "input", [id(self)]))

+ 176 - 0
services/DEVS/pypdevs/src/scheduler.py

@@ -0,0 +1,176 @@
+# -*- coding: Latin-1 -*-
+"""
+The Activity Heap is based on a heap, though allows for reschedules. 
+
+To allow reschedules to happen, a model is accompagnied by a flag to 
+indicate whether or not it is still valid. 
+As soon as a model is rescheduled, the flag of the previously scheduled 
+time is set and another entry is added. This causes the heap to become *dirty*, 
+requiring a check for the flag as soon as the first element is requested.
+
+Due to the possibility for a dirty heap, the heap will be cleaned up as 
+soon as the number of invalid elements becomes too high. 
+This cleanup method has O(n) complexity and is therefore only 
+ran when the heap becomes way too dirty.
+
+Another problem is that it might consume more memory than other schedulers, 
+due to invalid elements being kept in memory. 
+However, the actual model and states are not duplicated as they are references. 
+The additional memory requirement should not be a problem in most situations.
+
+The 'activity' part from the name stems from the fact that only models where 
+the *timeNext* attribute is smaller than infinity will be scheduled. 
+Since these elements are not added to the heap, they aren't taken into account 
+in the complexity. This allows for severe optimisations in situations where 
+a lot of models can be scheduled for infinity.
+
+Of all provided schedulers, this one is the most mature due to it being the 
+oldest and also the default scheduler. It is also applicable in every situation 
+and it offers sufficient performance in most cases.
+
+This scheduler is ideal in situations where (nearly) no reschedules happen 
+and where most models transition at a different time.
+
+It results in slow behaviour in situations requiring lots of rescheduling, 
+and thus lots of dirty elements.
+
+This method is also applied in the VLE simulator and is the common approach 
+to heap schedulers that require invalidation. It varies from the scheduler in 
+ADEVS due to the heap from the heapq library being used, which doesn't offer 
+functions to restructure the heap. 
+Reimplementing these methods in pure Python would be unnecessarily slow.
+"""
+from heapq import heappush, heappop, heapify
+
+class Scheduler(object):
+    """
+    Scheduler class itself
+    """
+    def __init__(self, models, epsilon, totalModels):
+        """
+        Constructor
+
+        :param models: all models in the simulation
+        """
+        self.heap = []
+        self.id_fetch = [None] * totalModels
+        for model in models:
+            if model.timeNext[0] != float('inf'):
+                self.id_fetch[model.model_id] = [model.timeNext, model.model_id, True, model]
+                heappush(self.heap, self.id_fetch[model.model_id])
+            else:
+                self.id_fetch[model.model_id] = [model.timeNext, model.model_id, False, model]
+        
+        self.invalids = 0
+        self.maxInvalids = len(models)*2
+        self.epsilon = epsilon
+
+    def schedule(self, model):
+        """
+        Schedule a model
+
+        :param model: the model to schedule
+        """
+        # Create the entry, as we have accepted the model
+        elem = [model.timeNext, model.model_id, False, model]
+        try:
+            self.id_fetch[model.model_id] = elem
+        except IndexError:
+            # A completely new model
+            self.id_fetch.append(elem)
+            self.maxInvalids += 2
+        # Check if it requires to be scheduled
+        if model.timeNext[0] != float('inf'):
+            self.id_fetch[model.model_id][2] = True
+            heappush(self.heap, self.id_fetch[model.model_id])
+
+    def unschedule(self, model):
+        """
+        Unschedule a model
+
+        :param model: model to unschedule
+        """
+        if model.timeNext != float('inf'):
+            self.invalids += 1
+        # Update the referece still in the heap
+        self.id_fetch[model.model_id][2] = False
+        # Remove the reference in our id_fetch
+        self.id_fetch[model.model_id] = None
+        self.maxInvalids -= 2
+
+    def massReschedule(self, reschedule_set):
+        """
+        Reschedule all models provided. 
+        Equivalent to calling unschedule(model); schedule(model) on every element in the iterable.
+
+        :param reschedule_set: iterable containing all models to reschedule
+        """
+        #NOTE rather dirty, though a lot faster for huge models
+        inf = float('inf')
+        for model in reschedule_set:
+            event = self.id_fetch[model.model_id]
+            if event[2]:
+                if model.timeNext == event[0]:
+                    continue
+                elif event[0][0] != inf:
+                    self.invalids += 1
+                event[2] = False
+            if model.timeNext[0] != inf:
+                self.id_fetch[model.model_id] = [model.timeNext, model.model_id, True, model]
+                heappush(self.heap, self.id_fetch[model.model_id])
+        if self.invalids >= self.maxInvalids:
+            self.heap = [i for i in self.heap if i[2] and (i[0][0] != inf)]
+            heapify(self.heap)
+            self.invalids = 0
+
+    def readFirst(self):
+        """
+        Returns the time of the first model that has to transition
+
+        :returns: timestamp of the first model
+        """
+        self.cleanFirst()
+        return self.heap[0][0]
+
+    def cleanFirst(self):
+        """
+        Clean up the invalid elements in front of the list
+        """
+        try:
+            while not self.heap[0][2]:
+                heappop(self.heap)
+                self.invalids -= 1
+        except IndexError:
+            # Nothing left, so it as clean as can be
+            pass
+
+    def getImminent(self, time):
+        """
+        Returns a list of all models that transition at the provided time, with a specified epsilon deviation allowed.
+
+        :param time: timestamp to check for models
+
+        .. warning:: For efficiency, this method only checks the **first** elements, so trying to invoke this function with a timestamp higher than the value provided with the *readFirst* method, will **always** return an empty set.
+        """
+        immChildren = []
+        t, age = time
+        try:
+            # Age must be exactly the same
+            first = self.heap[0]
+            while (first[0][0] <= t) and (first[0][1] == age):
+                # Check if the found event is actually still active
+                if(first[2]):
+                    # Active, so event is imminent
+                    immChildren.append(first[3])
+                    first[2] = False
+                else:
+                    # Wasn't active, but we will have to pop this to get the next
+                    # So we can lower the number of invalids
+                    self.invalids -= 1
+
+                # Advance the while loop
+                heappop(self.heap)
+                first = self.heap[0]
+        except IndexError:
+            pass
+        return immChildren

File diff suppressed because it is too large
+ 1021 - 0
services/DEVS/pypdevs/src/simulator.py


+ 808 - 0
services/DEVS/pypdevs/src/simulator.xml

@@ -0,0 +1,808 @@
+<?xml version="1.0" ?>
+<diagram author="Yentl Van Tendeloo" name="DEVS simulator">
+    <description>
+        A restricted PythonPDEVS simulator modelled in SCCD
+    </description>
+    <top>
+        import cPickle as pickle
+        import time
+
+        # We basically just interface with the basesimulator
+        from scheduler import Scheduler
+        from DEVS import directConnect, CoupledDEVS, AtomicDEVS, RootDEVS
+
+        class Breakpoint(object):
+            def __init__(self, breakpoint_id, function, enabled, disable_on_trigger):
+                self.id = breakpoint_id
+                self.function = function
+                self.enabled = enabled
+                self.disable_on_trigger = disable_on_trigger
+    </top>
+    <inport name="request"/>
+    <outport name="reply"/>
+    <class name="SCCDSimulator" default="true">
+        <!-- Define the constructor, taking the model to simulate as a parameter -->
+        <constructor>
+            <parameter name="model"/>
+            <body>
+                <![CDATA[
+                # Simulation variables
+                self.termination_time = None
+                self.termination_condition = None
+                self.simulation_time = (0.0, 0)
+                self.model = model
+                self.root_model = model
+                self.realtime_scale = 1.0
+
+                # Values to be set during simulation
+                self.realtime_starttime = None
+                self.inject_queue = []
+
+                # Model initialization
+                self.model_ids = []
+                self.model.finalize(name="", model_counter=0, model_ids=self.model_ids, locations={None: []}, selectHierarchy=[])
+
+                # Direct connection
+                if isinstance(self.model, CoupledDEVS):
+                    self.model.componentSet = directConnect(self.model.componentSet, True)
+                    self.model = RootDEVS(self.model.componentSet, self.model.componentSet, None)
+                    for m in self.model.componentSet:
+                        m.timeLast = (-m.elapsed, 1)
+                        ta = m.timeAdvance()
+                        m.timeNext = (m.timeLast[0] + ta, 1)
+                        m.old_states = [(m.timeLast, pickle.dumps(m.state))]
+                elif isinstance(self.model, AtomicDEVS):
+                    for p in self.model.IPorts:
+                        p.routingInLine = []
+                        p.routingOutLine = []
+                    for p in self.model.OPorts:
+                        p.routingInLine = []
+                        p.routingOutLine = []
+                    self.model = RootDEVS([self.model], [self.model], None)
+                    self.model.timeLast = (-self.model.elapsed, 1)
+                    ta = self.model.timeAdvance()
+                    self.model.timeNext = (self.model.timeLast[0] + ta, 1)
+
+                # Fixed configuration options
+                self.model.scheduler = Scheduler(self.model.componentSet, 1e-6, len(self.model.models))
+                self.timeNext = self.model.scheduler.readFirst()
+
+                # Cached values
+                self.imminents = None
+                self.outbags = None
+                self.inbags = None
+                self.transitioning = None
+                self.new_states = None
+                self.new_tn = None
+
+                # Verbose trace file
+                self.trace_file = None
+
+                # Breakpoint management
+                self.breakpoints = []
+
+                # For a reset
+                self.save_model = {model: (model.elapsed, pickle.dumps(model.state, pickle.HIGHEST_PROTOCOL)) for model in self.model.componentSet}
+                self.transition_times = []
+
+                ]]>
+            </body>
+        </constructor>
+        <!-- Serialize the output values in something human-readable instead of internal objects.
+             Note that this doesn't alter the internal structure, as that is still used for simulation. -->
+        <method name="serialize">
+            <parameter name="type"/>
+            <parameter name="object"/>
+            <body>
+                <![CDATA[
+                if type == "imminents":
+                    return [m.getModelFullName() for m in object]
+                elif type == "inbags" or type == "outbags":
+                    return {m.getPortFullName(): object[m] for m in object}
+                elif type == "new_tn" or type == "new_states":
+                    return {m.getModelFullName(): object[m] for m in object}
+                elif type == "transitioning":
+                    return {m.getModelFullName(): {1: "INTERNAL", 2: "EXTERNAL", 3: "CONFLUENT"}[object[m]] for m in object}
+                ]]>
+            </body>
+        </method>
+        <!-- Find a port based on a fully qualified name. -->
+        <method name="find_port_with_name">
+            <parameter name="name"/>
+            <body>
+                <![CDATA[
+                for model in self.model.componentSet:
+                    if name.startswith(model.getModelFullName()):
+                        # Found a potential model
+                        # We can't simply check for equality, as portnames might contain dots too
+                        for port in model.IPorts:
+                            if port.getPortFullName() == name:
+                                # Now everything matches
+                                return port
+                # Nothing found
+                return None
+                ]]>
+            </body>
+        </method>
+        <!-- Find a model based on a fully qualified name. -->
+        <method name="find_model_with_name">
+            <parameter name="name"/>
+            <body>
+                <![CDATA[
+                for model in self.model.componentSet:
+                    if name == model.getModelFullName():
+                        # Found exact match
+                        return model
+                return None
+                ]]>
+            </body>
+        </method>
+        <!-- Calculate the time to wait before triggering the next transition.
+             This method is also called in non-realtime simulation, so make sure that it returns infinity in that case. -->
+        <method name="calculate_after">
+            <body>
+                <![CDATA[
+                try:
+                    # Process in parts of 100 milliseconds to repeatedly check the termination condition
+                    nexttime = (self.timeNext[0] - (time.time() - self.realtime_starttime) / self.realtime_scale) * self.realtime_scale
+                    x =  min(0.1, nexttime)
+                    return x
+                except TypeError, AttributeError:
+                    # We are probably not simulating in realtime...
+                    return float('inf')
+                ]]>
+            </body>
+        </method>
+        <!-- Parse a list of options that can be passed together with the request -->
+        <method name="parse_options">
+            <parameter name="configuration"/>
+            <body>
+                <![CDATA[
+                self.termination_condition = None if "termination_condition" not in configuration else configuration["termination_condition"]
+                self.termination_time = None if "termination_time" not in configuration else configuration["termination_time"]
+                self.realtime_scale = 1.0 if "realtime_scale" not in configuration else 1.0/configuration["realtime_scale"]
+                # Subtract the current simulation time to allow for pausing
+                self.realtime_starttime = (time.time() - self.simulation_time[0]*self.realtime_scale)
+                # Reset the time used in the waiting, as it might not get recomputed
+                self.the_time = 0.00001
+                ]]>
+            </body>
+        </method>
+        <!-- Utility function to determine whether or not simulation is finished. -->
+        <method name="should_terminate">
+            <parameter name="realtime"/>
+            <body>
+                <![CDATA[
+                # Now that it includes breakpoints, results are to be interpretted as follows:
+                # -2 --> continue simulation
+                # -1 --> termination condition
+                # else --> breakpoint
+
+                if realtime:
+                    check_time = self.simulation_time
+                else:
+                    self.compute_timeNext()
+                    check_time = self.timeNext
+
+                # Just access the 'transitioned' dictionary
+                # Kind of dirty though...
+                if self.transitioning is None:
+                    transitioned = set()
+                else:
+                    transitioned = set(self.transitioning.keys())
+
+                if check_time[0] == float('inf'):
+                    # Always terminate if we have reached infinity
+                    terminate = True
+                elif self.termination_condition is not None:
+                    terminate = self.termination_condition(check_time, self.root_model, transitioned)
+                else:
+                    terminate = self.termination_time < check_time[0]
+
+                if terminate:
+                    # Always terminate, so don't check breakpoints
+                    return -1
+                else:
+                    # Have to check breakpoints for termination
+                    for bp in self.breakpoints:
+                        if not bp.enabled:
+                            continue
+                        # Include the function in the scope
+                        exec(bp.function)
+                        # And execute it, note that the breakpoint thus has to start with "def breakpoint("
+                        if breakpoint(check_time, self.root_model, transitioned):
+                            # Triggered!
+                            return bp.id
+                        else:
+                            # Not triggered, so continue
+                            continue
+                    return -2
+                ]]>
+            </body>
+        </method>
+        <!-- Compute all models of which the internal transition function has to be triggered. -->
+        <method name="find_internal_imminents">
+            <body>
+                <![CDATA[
+                self.imminents = self.model.scheduler.getImminent(self.simulation_time)
+                self.transition_times.append(self.simulation_time)
+                ]]>
+            </body>
+        </method>
+        <!-- Trigger all output functions of imminent models. -->
+        <method name="compute_outputfunction">
+            <body>
+                <![CDATA[
+                self.outbags = {}
+                for model in self.imminents:
+                    self.outbags.update(model.outputFnc())
+                ]]>
+            </body>
+        </method>
+        <!-- Route all messages and apply the required transfer functions. -->
+        <method name="route_messages">
+            <body>
+                <![CDATA[
+                self.inbags = {}
+                for outport in self.outbags:
+                    payload = self.outbags[outport]
+                    for inport, z in outport.routingOutLine:
+                        if z is not None:
+                            payload = [z(pickle.loads(pickle.dumps(m))) for m in payload]
+                        self.inbags.setdefault(inport, []).extend(payload)
+                ]]>
+            </body>
+        </method>
+        <!-- Process the injects on the inject_queue. -->
+        <method name="process_injects">
+            <body>
+                <![CDATA[
+                while self.inject_queue:
+                    if self.inject_queue[0]["time"] > self.simulation_time:
+                        break
+                    config = self.inject_queue.pop(0)
+                    portname = config["port"]
+                    event = config["event"]
+                    port = self.find_port_with_name(portname)
+                    self.inbags.setdefault(port, []).append(event)
+                ]]>
+            </body>
+        </method>
+        <!-- Combine the information from the routed messages to determine the external, internal and confluent transition functions to trigger. -->
+        <method name="find_all_imminents">
+            <body>
+                <![CDATA[
+                # Internal codes:
+                #   1 --> internal transition
+                #   2 --> external transition
+                #   3 --> confluent transition
+                # These codes are a legacy of efficient PyPDEVS, but is kept here for consistency
+                self.transitioning = {model: 1 for model in self.imminents}
+                for inport in self.inbags:
+                    aDEVS = inport.hostDEVS
+                    aDEVS.myInput[inport] = self.inbags[inport]
+                    if aDEVS in self.transitioning:
+                        self.transitioning[aDEVS] = 3
+                    else:
+                        self.transitioning[aDEVS] = 2
+                ]]>
+            </body>
+        </method>
+        <!-- Trigger all transition functions. -->
+        <method name="compute_transitions">
+            <body>
+                <![CDATA[
+                self.new_states = {}
+                for aDEVS in self.transitioning:
+                    aDEVS.myInput = {key: pickle.loads(pickle.dumps(aDEVS.myInput[key], pickle.HIGHEST_PROTOCOL)) for key in aDEVS.myInput}
+                    if self.transitioning[aDEVS] == 1:
+                        aDEVS.state = aDEVS.intTransition()
+                    elif self.transitioning[aDEVS] == 2:
+                        aDEVS.elapsed = self.simulation_time[0] - aDEVS.timeLast[0]
+                        aDEVS.state = aDEVS.extTransition(aDEVS.myInput)
+                    elif self.transitioning[aDEVS] == 3:
+                        aDEVS.elapsed = 0.
+                        aDEVS.state = aDEVS.confTransition(aDEVS.myInput)
+                    aDEVS.old_states.append((self.simulation_time, pickle.dumps(aDEVS.state)))
+                    aDEVS.myInput = {}
+                    self.new_states[aDEVS] = aDEVS.state
+                ]]>
+            </body>
+        </method>
+        <!-- Trigger all timeAdvance functions. -->
+        <method name="compute_ta">
+            <body>
+                <![CDATA[
+                self.new_tn = {}
+                t, age = self.simulation_time
+                for aDEVS in self.transitioning:
+                    ta = aDEVS.timeAdvance()
+                    aDEVS.timeLast = self.simulation_time
+                    aDEVS.timeNext = (t + ta, 1 if ta else (age + 1))
+                    self.new_tn[aDEVS] = aDEVS.timeNext
+                    self.trace(self.transitioning[aDEVS], aDEVS)
+                self.model.scheduler.massReschedule(self.transitioning)
+                self.timeNext = self.model.scheduler.readFirst()
+                ]]>
+            </body>
+        </method>
+        <!-- Verbose tracing. -->
+        <method name="trace">
+            <parameter name="type"/>
+            <parameter name="model"/>
+            <body>
+                <![CDATA[
+                type_map = {1: "INTERNAL", 2: "EXTERNAL", 3: "CONFLUENT"}
+                type = type_map[type]
+                if self.trace_file is not None:
+                    self.trace_file.write("%s TRANSITION in <%s> @ %s\n" % (type, model.getModelFullName(), model.timeLast[0]))
+                    self.trace_file.write("  NEW STATE <%s>\n" % (model.state))
+                    if type != "EXTERNAL":
+                        self.trace_file.write("  OUTPUTFNC returned %s\n" % model.myOutput)
+                    elif type != "INTERNAL":
+                        self.trace_file.write("  inputs were %s\n" % model.myInput)
+                    self.trace_file.write("  timeNext: %s (ta: %s)\n" % (model.timeNext[0], model.timeNext[0] - model.timeLast[0]))
+                ]]>
+            </body>
+        </method>
+        <method name="flush_file">
+            <body>
+                <![CDATA[
+                if self.trace_file is not None:
+                    self.trace_file.flush()
+                ]]>
+            </body>
+        </method>
+        <method name="process_breakpoints">
+            <parameter name="realtime"/>
+            <body>
+                <![CDATA[
+                breakpoint_id = self.should_terminate(realtime)
+                for breakpoint in self.breakpoints:
+                    if breakpoint.id == breakpoint_id:
+                        if breakpoint.disable_on_trigger:
+                            breakpoint.enabled = False
+                        return breakpoint_id
+                ]]>
+            </body>
+        </method>
+        <method name="compute_timeNext">
+            <body>
+                <![CDATA[
+                model_timeNext = self.model.scheduler.readFirst()
+                if len(self.inject_queue) > 0:
+                    self.timeNext = min(model_timeNext, self.inject_queue[0]["time"])
+                else:
+                    self.timeNext = model_timeNext
+                ]]>
+            </body>
+        </method>
+        <method name="rollback_step">
+            <body>
+                <![CDATA[
+                    if len(self.transition_times) == 0:
+                        return
+                    new_time = self.transition_times.pop()
+                    for model in self.model.componentSet:
+                        if model.old_states[-1][0] == new_time:
+                            # Remove the current state
+                            del model.old_states[-1]
+                            # Set the new (old...) state
+                            new_state = model.old_states[-1]
+                            model.state = pickle.loads(new_state[1])
+                            model.timeLast = new_state[0]
+                            ta = model.timeAdvance()
+                            model.timeNext = (model.timeLast[0] + ta, model.timeLast[1] + 1 if ta == 0 else 0)
+                            self.model.scheduler.massReschedule([model])
+                    self.simulation_time = self.transition_times[-1] if len(self.transition_times) > 0 else (0.0, 0)
+                ]]>
+            </body>
+        </method>
+        <scxml initial="main">
+            <!-- Parallel states: one of them controls the simulation flow, the other the type of simulation being performed. -->
+            <parallel id="main">
+                <!-- When an injection is received, just append it to the list of pending injections.
+                     These will be processed as soon as the current simulation step is finished.
+                     Afterwards, return to the previous state, as there was no change of state. -->
+                <state id="injection_monitor">
+                    <state id="inject">
+                        <transition port="request" event="inject" target=".">
+                            <parameter name="configuration"/>
+                            <script>
+                                configuration["time"] = (configuration["time"], 1)
+                                self.inject_queue.append(configuration)
+                                self.inject_queue.sort(key=lambda i: i["time"])
+                            </script>
+                            <raise scope="output" port="reply" event="inject_ok"/>
+                        </transition>
+                    </state>
+                </state>
+                <state id="tracer_monitor">
+                    <state id="trace">
+                        <transition port="request" event="trace" target=".">
+                            <parameter name="filename"/>
+                            <script>
+                                if filename is not None:
+                                    self.trace_file = open(filename, 'w')
+                                else:
+                                    self.trace_file = None
+                            </script>
+                            <raise scope="output" port="reply" event="trace_config_ok"/>
+                        </transition>
+                    </state>
+                </state>
+                <!-- The main parallel component: the simulation flow. -->
+                <state id="simulation_flow" initial="initialize">
+                    <state id="initialize">
+                        <transition target="../check_termination">
+                            <raise scope="output" port="reply" event="all_states">
+                                <parameter expr="self.simulation_time"/>
+                                <parameter expr="{m.getModelFullName(): (m.timeNext, m.state) for m in self.model.componentSet}"/>
+                            </raise>
+                        </transition>
+                    </state>
+                    <state id="check_termination" initial="workaround">
+                        <onexit>
+                            <script>
+                                self.simulation_time = self.timeNext
+                            </script>
+                        </onexit>
+
+                        <state id="workaround">
+                            <transition after="0" target="../check_termination"/>
+                        </state>
+
+                        <state id="wait">
+                            <onexit>
+                                <script>
+                                    diff = time.time() - self.realtime_starttime
+                                    self.simulation_time = (diff / self.realtime_scale, 1)
+                                </script>
+                            </onexit>
+                            <transition after="self.calculate_after()" target="../check_termination"/>
+                            <transition cond="INSTATE('../../../simulation_state/paused')" target="../check_termination"/>
+                        </state>
+
+                        <state id="small_step_check">
+                            <transition cond="self.should_terminate(False) == -2" target="../../do_simulation"/>
+                            <transition cond="self.should_terminate(False) == -1" target="../check_termination">
+                                <raise event="termination_condition"/>
+                            </transition>
+                            <transition cond="self.should_terminate(False) &gt; -1" target="../check_termination">
+                                <script>
+                                    breakpoint_id = self.process_breakpoints(False)
+                                </script>
+                                <raise scope="output" port="reply" event="breakpoint_triggered">
+                                    <parameter expr="breakpoint_id"/>
+                                </raise>
+                                <raise event="termination_condition"/>
+                            </transition>
+                        </state>
+
+                        <state id="check_termination">
+                            <onentry>
+                                <script>
+                                    self.compute_timeNext()
+                                    self.the_time = self.calculate_after()
+                                </script>
+                            </onentry>
+                            <!-- Continue simulation -->
+                            <transition cond="INSTATE('../../../simulation_state/continuous') and (self.should_terminate(False) == -2)" target="../../do_simulation"/>
+                            <transition cond="INSTATE('../../../simulation_state/big_step') and (self.should_terminate(False) == -2)" target="../../do_simulation"/>
+
+                            <!-- Realtime and didn't reach the required timeNext yet -->
+                            <transition cond="INSTATE('../../../simulation_state/realtime') and (self.should_terminate(True) == -2) and (self.the_time &gt; 0.0)" target="../wait"/>
+
+                            <transition cond="INSTATE('../../../simulation_state/realtime') and (self.should_terminate(True) == -2) and (self.the_time &lt;= 0.0)" target="../../do_simulation"/>
+
+                            <transition port="request" event="small_step" target="../small_step_check">
+                                <parameter name="configuration" type="dict" default="{}"/>
+                                <script>
+                                    self.parse_options(configuration)
+                                </script>
+                            </transition>
+
+                            <!-- Pause simulation -->
+                            <transition cond="(not INSTATE('../../../simulation_state/paused') and INSTATE('../../../simulation_state/realtime') and (self.should_terminate(True) == -1))" target="../workaround">
+                                <raise event="termination_condition"/>
+                            </transition>
+                            <transition cond="(not INSTATE('../../../simulation_state/paused') and not INSTATE('../../../simulation_state/realtime') and (self.should_terminate(False) == -1))" target="../workaround">
+                                <raise event="termination_condition"/>
+                            </transition>
+                            <transition cond="(not INSTATE('../../../simulation_state/paused')) and INSTATE('../../../simulation_state/realtime') and (self.should_terminate(True) &gt; -1)" target="../workaround">
+                                <script>
+                                    breakpoint_id = self.process_breakpoints(True)
+                                </script>
+                                <raise scope="output" port="reply" event="breakpoint_triggered">
+                                    <parameter expr="breakpoint_id"/>
+                                </raise>
+                                <raise event="termination_condition"/>
+                            </transition>
+                            <transition cond="(not INSTATE('../../../simulation_state/paused')) and not INSTATE('../../../simulation_state/realtime') and (self.should_terminate(False) &gt; -1)" target="../workaround">
+                                <script>
+                                    breakpoint_id = self.process_breakpoints(False)
+                                </script>
+                                <raise scope="output" port="reply" event="breakpoint_triggered">
+                                    <parameter expr="breakpoint_id"/>
+                                </raise>
+                                <raise event="termination_condition"/>
+                            </transition>
+
+                            <!-- Process god event -->
+                            <transition cond="INSTATE('../../../simulation_state/paused')" port="request" event="god_event" target="../workaround">
+                                <parameter name="configuration"/>
+                                <script>
+                                    modelname = configuration["model"]
+                                    state_attribute = configuration["attribute"]
+                                    new_value = configuration["value"]
+                                    model = self.find_model_with_name(modelname)
+                                    setattr(model.state, state_attribute, new_value)
+                                    # Call the timeadvance method again and compute new ta
+                                    ta = model.timeAdvance()
+                                    model.timeNext = (model.timeLast[0] + ta, 1 if ta else (model.timeLast[1] + 1))
+                                    self.model.scheduler.massReschedule([model])
+                                    # self.simulation_time = self.model.scheduler.readFirst()
+                                </script>
+                                <raise scope="output" port="reply" event="god_event_ok">
+                                    <parameter expr="{model.getModelFullName(): str(model.state)}"/>
+                                </raise>
+                                <raise scope="output" port="reply" event="new_tn">
+									<parameter expr="self.simulation_time"/>
+                                    <parameter expr="{model.getModelFullName(): model.timeNext}"/>
+                                </raise>
+                            </transition>
+
+                            <!-- Omniscient debugging -->
+                            <transition cond="INSTATE('../../../simulation_state/paused')" port="request" event="backwards_step" target="../workaround">
+                                <script>
+                                    self.rollback_step()
+                                </script>
+                                <raise scope="output" port="reply" event="all_states">
+                                    <parameter expr="self.simulation_time"/>
+                                    <parameter expr="{m.getModelFullName(): (m.timeNext, m.state) for m in self.model.componentSet}"/>
+                                </raise>
+                            </transition>
+
+                        </state>
+                    </state>
+
+                    <state id="do_simulation" initial="init">
+                    <state id="init">
+                        <onexit>
+                            <script>
+                                self.find_internal_imminents()
+                            </script>
+                        </onexit>
+                        <transition cond="not INSTATE('../../../simulation_state/paused')" target="../found_internal_imminents"/>
+                        <!-- Always output this if paused, as we only got here because a small step was fired previously -->
+                        <transition cond="INSTATE('../../../simulation_state/paused')" target="../found_internal_imminents">
+                            <raise scope="output" port="reply" event="imminents">
+                                <parameter expr="self.simulation_time"/>
+                                <parameter expr="self.serialize('imminents', self.imminents)"/>
+                            </raise>
+                        </transition>
+                    </state>
+
+                    <state id="found_internal_imminents">
+                        <onexit>
+                            <script>
+                                self.compute_outputfunction()
+                            </script>
+                        </onexit>
+                        <transition cond="not INSTATE('../../../simulation_state/paused')" target="../computed_outputfunction"/>
+                        <transition port="request" event="small_step" target="../computed_outputfunction">
+                            <raise scope="output" port="reply" event="outbags">
+                                <parameter expr="self.simulation_time"/>
+                                <parameter expr="self.serialize('outbags', self.outbags)"/>
+                            </raise>
+                        </transition>
+                    </state>
+
+                    <state id="computed_outputfunction">
+                        <onexit>
+                            <script>
+                                self.route_messages()
+                                self.process_injects()
+                            </script>
+                        </onexit>
+                        <transition cond="not INSTATE('../../../simulation_state/paused')" target="../routed_messages">
+                        </transition>
+                        <transition port="request" event="small_step" target="../routed_messages">
+                            <raise scope="output" port="reply" event="inbags">
+                                <parameter expr="self.simulation_time"/>
+                                <parameter expr="self.serialize('inbags', self.inbags)"/>
+                            </raise>
+                        </transition>
+                    </state>
+
+                    <state id="routed_messages">
+                        <onexit>
+                            <script>
+                                self.find_all_imminents()
+                            </script>
+                        </onexit>
+                        <transition cond="not INSTATE('../../../simulation_state/paused')" target="../found_all_imminents">
+                        </transition>
+                        <transition port="request" event="small_step" target="../found_all_imminents">
+                            <raise scope="output" port="reply" event="transitioning">
+                                <parameter expr="self.simulation_time"/>
+                                <parameter expr="self.serialize('transitioning', self.transitioning)"/>
+                            </raise>
+                        </transition>
+                    </state>
+
+                    <state id="found_all_imminents">
+                        <onexit>
+                            <script>
+                                self.compute_transitions()
+                            </script>
+                        </onexit>
+                        <transition cond="not INSTATE('../../../simulation_state/paused')" target="../computed_transitions"/>
+                        <transition port="request" event="small_step" target="../computed_transitions">
+                            <raise scope="output" port="reply" event="new_states">
+                                <parameter expr="self.simulation_time"/>
+                                <parameter expr="self.serialize('new_states', self.new_states)"/>
+                            </raise>
+                        </transition>
+                    </state>
+
+                    <state id="computed_transitions">
+                        <onexit>
+                            <script>
+                                self.compute_ta()
+                            </script>
+                        </onexit>
+                        <transition cond="INSTATE('../../../simulation_state/continuous')" target="../../check_termination"/>
+                        <transition port="request" event="small_step" target="../../check_termination">
+                            <raise scope="output" port="reply" event="new_tn">
+                                <parameter expr="self.simulation_time"/>
+                                <parameter expr="self.serialize('new_tn', self.new_tn)"/>
+                            </raise>
+                        </transition>
+                        <transition cond="INSTATE('../../../simulation_state/realtime') or INSTATE('../../../simulation_state/big_step')" target="../../check_termination">
+                            <raise event="big_step_done"/>
+                            <raise scope="output" port="reply" event="new_states">
+                                <parameter expr="self.simulation_time"/>
+                                <parameter expr="self.serialize('new_states', self.new_states)"/>
+                            </raise>
+                            <raise scope="output" port="reply" event="new_tn">
+                                <parameter expr="self.simulation_time"/>
+                                <parameter expr="self.serialize('new_tn', self.new_tn)"/>
+                            </raise>
+                        </transition>
+                    </state>
+                    </state>
+                </state>
+
+                <state id="simulation_state" initial="paused">
+                    <state id="paused">
+                        <transition port="request" event="simulate" target="../continuous">
+                            <parameter name="configuration" type="dict" default="{}"/>
+                            <script>
+                                self.parse_options(configuration)
+                            </script>
+                        </transition>
+                        <transition port="request" event="realtime" target="../realtime">
+                            <parameter name="configuration" type="dict" default="{}"/>
+                            <script>
+                                self.parse_options(configuration)
+                            </script>
+                        </transition>
+                        <transition port="request" event="big_step" target="../big_step">
+                            <parameter name="configuration" type="dict" default="{}"/>
+                            <script>
+                                self.parse_options(configuration)
+                            </script>
+                        </transition>
+                    </state>
+                    <state id="continuous">
+                            <transition port="request" event="pause" target=".">
+                                <script>
+                                    # Just override termination condition
+                                    self.termination_condition = lambda i, j, k : True
+                                    self.termination_time = None
+                                </script>
+                            </transition>
+                            <transition event="termination_condition" target="../paused">
+                                <raise port="reply" event="terminate">
+                                    <parameter expr="self.simulation_time"/>
+                                </raise>
+                                <script>
+                                    self.flush_file()
+                                </script>
+                                <raise scope="output" port="reply" event="all_states">
+                                    <parameter expr="self.simulation_time"/>
+                                    <parameter expr="{m.getModelFullName(): (m.timeNext, m.state) for m in self.model.componentSet}"/>
+                                </raise>
+                            </transition>
+                    </state>
+                    <state id="realtime">
+                            <transition port="request" event="pause" target=".">
+                                <script>
+                                    # Just override termination condition
+                                    self.termination_condition = lambda i, j, k : True
+                                    self.termination_time = None
+
+                                    # Don't forget to correctly set the simulation time
+                                    diff = time.time() - self.realtime_starttime
+                                    self.simulation_time = (diff / self.realtime_scale, 1)
+                                </script>
+                            </transition>
+                            <transition event="termination_condition" target="../paused">
+                                <raise port="reply" event="terminate">
+                                    <parameter expr="self.simulation_time"/>
+                                </raise>
+                                <script>
+                                    self.flush_file()
+                                </script>
+                            </transition>
+                    </state>
+                    <state id="big_step">
+                            <transition event="big_step_done" target="../paused"/>
+                            <transition event="termination_condition" target="../paused">
+                                <raise port="reply" event="terminate">
+                                    <parameter expr="self.simulation_time"/>
+                                </raise>
+                                <script>
+                                    self.flush_file()
+                                </script>
+                            </transition>
+                    </state>
+                </state>
+                <state id="breakpoint_manager">
+                    <state id="breakpoint_manage">
+                        <transition port="request" event="add_breakpoint" target=".">
+                            <parameter name="breakpoint_id"/>
+                            <parameter name="function"/>
+                            <parameter name="enabled"/>
+                            <parameter name="disable_on_trigger"/>
+                            <script>
+                                self.breakpoints.append(Breakpoint(breakpoint_id, function, enabled, disable_on_trigger))
+                            </script>
+                        </transition>
+                        <transition port="request" event="del_breakpoint" target=".">
+                            <parameter name="del_breakpoint_id"/>
+                            <script>
+                                self.breakpoints = [breakpoint for breakpoint in self.breakpoints if breakpoint.id != del_breakpoint_id]
+                            </script>
+                        </transition>
+                        <transition port="request" event="toggle_breakpoint" target=".">
+                            <parameter name="breakpoint_id"/>
+                            <parameter name="enabled"/>
+                            <script>
+                                for breakpoint in self.breakpoints:
+                                    if breakpoint.id == breakpoint_id:
+                                        breakpoint.enabled = enabled
+                                        break
+                            </script>
+                        </transition>
+                    </state>
+                </state>
+                <state id="reset">
+                    <state id="reset">
+                        <transition port="request" event="reset" target=".">
+                            <script>
+                                for model in self.model.componentSet:
+                                    model.state = pickle.loads(self.save_model[model][1])
+                                    model.elapsed = self.save_model[model][0]
+                                    model.timeLast = (-model.elapsed, 1)
+                                    ta = model.timeAdvance()
+                                    model.timeNext = (model.timeLast[0] + ta, 1)
+                                self.simulation_time = (0.0, 0)
+                                self.model.scheduler.massReschedule(self.model.componentSet)
+
+                                # Reset trace file
+                                if self.trace_file is not None:
+                                    self.trace_file = open(self.trace_file.name, 'w')
+                            </script>
+                            <raise scope="output" port="reply" event="all_states">
+                                <parameter expr="(0.0, 0)"/>
+                                <parameter expr="{m.getModelFullName(): (m.timeNext, m.state) for m in self.model.componentSet}"/>
+                            </raise>
+                        </transition>
+                    </state>
+                </state>
+            </parallel>
+        </scxml>
+    </class>
+</diagram>

+ 0 - 5
scripts/HUTN_service.py

@@ -26,7 +26,6 @@ def clean_code(code):
     return code
     return code
 
 
 def compile_service(port):
 def compile_service(port):
-    print("Start with port " + str(port))
     start = time.time()
     start = time.time()
     temp_file = ".tmp_%s" % port
     temp_file = ".tmp_%s" % port
 
 
@@ -60,7 +59,6 @@ def compile_service(port):
 
 
     mode = service_get(port)
     mode = service_get(port)
     code = service_get(port)
     code = service_get(port)
-    print("Service set: " + str(port))
 
 
     try:
     try:
         if mode == "code":
         if mode == "code":
@@ -76,11 +74,8 @@ def compile_service(port):
     except Exception as e:
     except Exception as e:
         service_set(port, str(e))
         service_set(port, str(e))
         raise
         raise
-    print("Compile took %ss" % (time.time() - start))
 
 
-print("Start service")
 service_register("compiler", compile_service)
 service_register("compiler", compile_service)
-print("Service OK")
 
 
 try:
 try:
     while raw_input() != "STOP":
     while raw_input() != "STOP":

+ 0 - 1
scripts/JSON_service.py

@@ -74,7 +74,6 @@ def json_service(port):
     except Exception as e:
     except Exception as e:
         service_set(port, str(e))
         service_set(port, str(e))
         raise
         raise
-    print("JSON took %ss" % (time.time() - start))
 
 
 service_register("JSON", json_service)
 service_register("JSON", json_service)
 
 

+ 1 - 2
unit/log_output.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:   Mon Aug 28 10:53:51 2017
+Date:   Fri Nov 10 08:52:06 2017
 
 
 Model author: Yentl Van Tendeloo
 Model author: Yentl Van Tendeloo
 Model name:   Logging
 Model name:   Logging
@@ -77,7 +77,6 @@ class Logging(RuntimeClassBase):
     def _init_0_exec(self, parameters):
     def _init_0_exec(self, parameters):
         value = parameters[0]
         value = parameters[0]
         self.log.append(value)
         self.log.append(value)
-        print("Got value: " + str(value))
     
     
     def initializeStatechart(self):
     def initializeStatechart(self):
         # enter default state
         # enter default state

+ 1 - 6
unit/log_output.xml

@@ -20,7 +20,6 @@
                     <parameter name="value"/>
                     <parameter name="value"/>
                     <script>
                     <script>
                         self.log.append(value)
                         self.log.append(value)
-                        print("Got value: " + str(value))
                     </script>
                     </script>
                 </transition>
                 </transition>
 
 
@@ -29,11 +28,7 @@
                 <transition event="terminate" port="inp" target="../finished"/>
                 <transition event="terminate" port="inp" target="../finished"/>
             </state>
             </state>
 
 
-            <state id="finished">
-                <script>
-                    print("FINISHED")
-                </script>
-            </state>
+            <state id="finished"/>
         </scxml>
         </scxml>
     </class>
     </class>
 </diagram>
 </diagram>

+ 14 - 3
unit/test_all.py

@@ -218,15 +218,20 @@ class TestModelverse(unittest.TestCase):
         thrd.daemon = True
         thrd.daemon = True
         thrd.start()
         thrd.start()
 
 
-        assert transformation_execute_MT("test/print_pn", {"PetriNet": "test/my_pn"}, {}, (ctrl, "inp", "outp")) == True
+        assert transformation_execute_MT("test/print_pn", {"PetriNet": "test/my_pn"}, {}, (ctrl, "inp", "outp")) == None
+        print("Joining")
         thrd.join()
         thrd.join()
+        print("Joined")
         assert set(log) == set(['"p1" --> 1',
         assert set(log) == set(['"p1" --> 1',
                                 '"p2" --> 2',
                                 '"p2" --> 2',
                                 '"p3" --> 3'])
                                 '"p3" --> 3'])
 
 
+        print("MAN")
         assert transformation_execute_MANUAL("test/pn_design_to_runtime", {"PetriNet": "test/my_pn"}, {"PetriNet_Runtime": "test/my_pn_RT"}, manual_callback) == True
         assert transformation_execute_MANUAL("test/pn_design_to_runtime", {"PetriNet": "test/my_pn"}, {"PetriNet_Runtime": "test/my_pn_RT"}, manual_callback) == True
+        print("OK")
         assert transformation_execute_AL("test/pn_simulate", {"PetriNet_Runtime": "test/my_pn_RT"}, {"PetriNet_Runtime": "test/my_pn_RT"}) == True
         assert transformation_execute_AL("test/pn_simulate", {"PetriNet_Runtime": "test/my_pn_RT"}, {"PetriNet_Runtime": "test/my_pn_RT"}) == True
         assert transformation_execute_MT("test/pn_runtime_to_design", {"PetriNet_Runtime": "test/my_pn_RT"}, {"PetriNet": "test/my_pn"}) == True
         assert transformation_execute_MT("test/pn_runtime_to_design", {"PetriNet_Runtime": "test/my_pn_RT"}, {"PetriNet": "test/my_pn"}) == True
+        print("MT OK")
 
 
         log = []
         log = []
         ctrl = log_output.Controller(log, keep_running=False)
         ctrl = log_output.Controller(log, keep_running=False)
@@ -234,7 +239,7 @@ class TestModelverse(unittest.TestCase):
         thrd.daemon = True
         thrd.daemon = True
         thrd.start()
         thrd.start()
 
 
-        assert transformation_execute_MT("test/print_pn", {"PetriNet": "test/my_pn"}, {}, (ctrl, "inp", "outp")) == True
+        assert transformation_execute_MT("test/print_pn", {"PetriNet": "test/my_pn"}, {}, (ctrl, "inp", "outp")) == None
         thrd.join()
         thrd.join()
         assert set(log) == set(['"p1" --> 0',
         assert set(log) == set(['"p1" --> 0',
                                 '"p2" --> 1',
                                 '"p2" --> 1',
@@ -242,8 +247,10 @@ class TestModelverse(unittest.TestCase):
 
 
         model_delete("RAMified")
         model_delete("RAMified")
         model_delete("merged")
         model_delete("merged")
+        model_delete(".tmp")
         model_delete("type mappings/RAMified")
         model_delete("type mappings/RAMified")
         model_delete("type mappings/merged")
         model_delete("type mappings/merged")
+        model_delete("type mappings/.tmp")
 
 
     def test_process_model_trivial_pn_subfunction(self):
     def test_process_model_trivial_pn_subfunction(self):
         model_add("test/PetriNet", "formalisms/SimpleClassDiagrams", open("integration/code/pn_design.mvc", "r").read())
         model_add("test/PetriNet", "formalisms/SimpleClassDiagrams", open("integration/code/pn_design.mvc", "r").read())
@@ -272,17 +279,19 @@ class TestModelverse(unittest.TestCase):
         thrd.daemon = True
         thrd.daemon = True
         thrd.start()
         thrd.start()
 
 
-        process_execute("test/pn_reachability", "", {"test/refine_PN": callback_refine_PN, "test/reachability_print": (ctrl, "inp", "outp")})
+        process_execute("test/pn_reachability", {}, {"test/refine_PN": callback_refine_PN, "test/reachability_print": (ctrl, "inp", "outp")})
         thrd.join()
         thrd.join()
 
 
         assert set(log) == set(['"0": {"p1": 1}',
         assert set(log) == set(['"0": {"p1": 1}',
                                 '"1": {"p1": 0}',
                                 '"1": {"p1": 0}',
                                 '"0" --["t1"]--> "1"'])
                                 '"0" --["t1"]--> "1"'])
 
 
+        model_delete(".tmp")
         model_delete("RAMified")
         model_delete("RAMified")
         model_delete("merged")
         model_delete("merged")
         model_delete("type mappings/RAMified")
         model_delete("type mappings/RAMified")
         model_delete("type mappings/merged")
         model_delete("type mappings/merged")
+        model_delete("type mappings/.tmp")
 
 
     def test_render(self):
     def test_render(self):
         model_add("test/CausalBlockDiagrams", "formalisms/SimpleClassDiagrams", open("integration/code/cbd_design.mvc", 'r').read())
         model_add("test/CausalBlockDiagrams", "formalisms/SimpleClassDiagrams", open("integration/code/cbd_design.mvc", 'r').read())
@@ -313,7 +322,9 @@ class TestModelverse(unittest.TestCase):
         transformation_add_AL({"SCCD": "test/SCCD"}, {"trace": "test/SCCD_Trace"}, "test/SCCD_execute_afap", open("models/SCCD_execute.alc", 'r').read().replace("afap = False", "afap = True"))
         transformation_add_AL({"SCCD": "test/SCCD"}, {"trace": "test/SCCD_Trace"}, "test/SCCD_execute_afap", open("models/SCCD_execute.alc", 'r').read().replace("afap = False", "afap = True"))
         transformation_execute_AL("test/SCCD_execute_afap", {"SCCD": "test/my_SCCD"}, {"trace": "test/my_SCCD_trace"})
         transformation_execute_AL("test/SCCD_execute_afap", {"SCCD": "test/my_SCCD"}, {"trace": "test/my_SCCD_trace"})
 
 
+        print("Executed AL")
         alter_context("test/my_SCCD_trace", "test/SCCD_Trace")
         alter_context("test/my_SCCD_trace", "test/SCCD_Trace")
+        print("Altered context")
         lst = element_list_nice("test/my_SCCD_trace")
         lst = element_list_nice("test/my_SCCD_trace")
 
 
         model_delete("merged")
         model_delete("merged")

+ 95 - 81
wrappers/classes/modelverse.xml

@@ -392,10 +392,6 @@
                             <script>
                             <script>
                                 self.registered_metamodel[self.parameters[0]] = self.parameters[1]
                                 self.registered_metamodel[self.parameters[0]] = self.parameters[1]
                             </script>
                             </script>
-
-                            <raise event="result">
-                                <parameter expr="None"/>
-                            </raise>
                         </transition>
                         </transition>
                     </state>
                     </state>
 
 
@@ -560,6 +556,27 @@
                         </transition>
                         </transition>
                     </state>
                     </state>
 
 
+                    <state id="process_signature">
+                        <onentry>
+                            <raise event="request">
+                                <parameter expr="['process_signature', self.parameters[0]]"/>
+                            </raise>
+                        </onentry>
+
+                        <transition cond="self.expect_response_partial('Success: ', pop=False)" target="../../wait_for_action/history">
+                            <script>
+                                results = self.split_response(self.responses.pop(0))
+                                signature = {}
+                                for result in results:
+                                    key, value = result.strip().split(" : ", 1)
+                                    signature[key] = value
+                            </script>
+                            <raise event="result">
+                                <parameter expr="signature"/>
+                            </raise>
+                        </transition>
+                    </state>
+
                     <state id="store_on_scripted" initial="transformation_add_MT">
                     <state id="store_on_scripted" initial="transformation_add_MT">
                         <state id="transformation_add_MT" initial="send_metadata">
                         <state id="transformation_add_MT" initial="send_metadata">
                             <state id="send_metadata">
                             <state id="send_metadata">
@@ -576,16 +593,15 @@
 
 
                                 </onentry>
                                 </onentry>
 
 
-                                <transition target="../edit_metamodel"/>
-
-                            </state>
-
-                            <state id="edit_metamodel">
-                                <transition cond="self.expect_response('Model loaded, ready for commands!')" target="../../../../going_scripted">
+                                <transition cond="self.expect_response_partial('Operating on: ')" target="../edit_metamodel">
                                     <raise event="result">
                                     <raise event="result">
-                                        <parameter expr="self.context"/>
+                                        <parameter expr="[self.context, self.responses.pop(0).split(': ', 1)[1]]"/>
                                     </raise>
                                     </raise>
                                 </transition>
                                 </transition>
+                            </state>
+
+                            <state id="edit_metamodel">
+                                <transition cond="self.expect_response('Model loaded, ready for commands!')" target="../../../../going_scripted"/>
                                 <transition cond="self.expect_response('Waiting for model constructors...')" target="../send_model"/>
                                 <transition cond="self.expect_response('Waiting for model constructors...')" target="../send_model"/>
                             </state>
                             </state>
 
 
@@ -624,19 +640,17 @@
                                     </script>
                                     </script>
                                 </onentry>
                                 </onentry>
 
 
-                                <transition target="../edit_metamodel"/>
-
-                            </state>
-
-                            <state id="edit_metamodel">
-                                <transition cond="self.expect_response('Model loaded, ready for commands!')" target="../../../../going_scripted">
+                                <transition cond="self.expect_response_partial('Operating on: ')" target="../edit_metamodel">
                                     <raise event="result">
                                     <raise event="result">
-                                        <parameter expr="self.context"/>
+                                        <parameter expr="[self.context, self.responses.pop(0).split(': ', 1)[1]]"/>
                                     </raise>
                                     </raise>
                                 </transition>
                                 </transition>
-                                <transition cond="self.expect_response('Waiting for code constructors...')" target="../send_model"/>
                             </state>
                             </state>
 
 
+                            <state id="edit_metamodel">
+                                <transition cond="self.expect_response('Model loaded, ready for commands!')" target="../../../../going_scripted"/>
+                            </state>
+                               
                             <state id="send_model">
                             <state id="send_model">
                                 <onentry>
                                 <onentry>
                                     <raise event="request">
                                     <raise event="request">
@@ -650,6 +664,8 @@
                                     </raise>
                                     </raise>
                                 </transition>
                                 </transition>
                             </state>
                             </state>
+
+                            <transition cond="self.expect_response('Waiting for code constructors...')" target="send_model"/>
                         </state>
                         </state>
 
 
                         <state id="transformation_add_MANUAL" initial="send_metadata">
                         <state id="transformation_add_MANUAL" initial="send_metadata">
@@ -665,16 +681,15 @@
                                     </script>
                                     </script>
                                 </onentry>
                                 </onentry>
 
 
-                                <transition target="../edit_metamodel"/>
-
-                            </state>
-
-                            <state id="edit_metamodel">
-                                <transition cond="self.expect_response('Model loaded, ready for commands!')" target="../../../../going_scripted">
+                                <transition cond="self.expect_response_partial('Operating on: ')" target="../edit_metamodel">
                                     <raise event="result">
                                     <raise event="result">
-                                        <parameter expr="self.context"/>
+                                        <parameter expr="[self.context, self.responses.pop(0).split(': ', 1)[1]]"/>
                                     </raise>
                                     </raise>
                                 </transition>
                                 </transition>
+                            </state>
+
+                            <state id="edit_metamodel">
+                                <transition cond="self.expect_response('Model loaded, ready for commands!')" target="../../../../going_scripted"/>
                                 <transition cond="self.expect_response('Success')" target="../../../../wait_for_action/megamodelling">
                                 <transition cond="self.expect_response('Success')" target="../../../../wait_for_action/megamodelling">
                                     <raise event="result">
                                     <raise event="result">
                                         <parameter expr="None"/>
                                         <parameter expr="None"/>
@@ -690,19 +705,25 @@
                                         <parameter expr="['transformation_execute', self.parameters[0]] + self.dict_to_list(self.parameters[1]) + self.dict_to_list(self.parameters[2]) + [self.parameters[3]]"/>
                                         <parameter expr="['transformation_execute', self.parameters[0]] + self.dict_to_list(self.parameters[1]) + self.dict_to_list(self.parameters[2]) + [self.parameters[3]]"/>
                                     </raise>
                                     </raise>
                                     <script>
                                     <script>
-                                        if self.parameters[4] == False:
+                                        if len(self.parameters) > 4 and self.parameters[4] == False:
                                             self.finish_output_thread = True
                                             self.finish_output_thread = True
+                                        print("Executing transformation " + str(self.parameters[0]))
                                     </script>
                                     </script>
                                 </onentry>
                                 </onentry>
 
 
-                                <transition cond="self.expect_response_partial('Success: ready for ', pop=True)" target="../dialog">
+                                <transition cond="self.expect_response('Success: ready for MANUAL execution', pop=True)" target="../edit_model">
+                                    <script>
+                                        self.context = str(uuid.uuid4())
+                                        self.actions[self.context] = []
+                                    </script>
+                                </transition>
+                                <transition cond="self.expect_response('Success: ready for AL execution', pop=True) or self.expect_response('Success: ready for MT execution', pop=True)" target="../dialog">
                                     <script>
                                     <script>
                                         self.input_context = str(uuid.uuid4())
                                         self.input_context = str(uuid.uuid4())
                                         self.inputs[self.input_context] = []
                                         self.inputs[self.input_context] = []
                                     </script>
                                     </script>
-
                                     <raise event="result">
                                     <raise event="result">
-                                        <parameter expr="self.input_context"/>
+                                        <parameter expr="['SC', self.parameters[0], self.input_context]"/>
                                     </raise>
                                     </raise>
                                 </transition>
                                 </transition>
                             </state>
                             </state>
@@ -726,31 +747,17 @@
                                     </raise>
                                     </raise>
                                 </transition>
                                 </transition>
                             </state>
                             </state>
-                        </state>
-
-                        <state id="transformation_execute_MANUAL" initial="send_metadata">
-                            <state id="send_metadata">
-                                <onentry>
-                                    <raise event="request">
-                                        <parameter expr="['transformation_execute', self.parameters[0]] + self.dict_to_list(self.parameters[1]) + self.dict_to_list(self.parameters[2]) + [self.parameters[3]]"/>
-                                    </raise>
 
 
+                            <state id="edit_model">
+                                <transition cond="self.expect_response_partial('Please perform manual operation ', pop=True)" target="."/>
+                                <transition cond="self.expect_response_partial('Operating on: ', pop=False)" target=".">
                                     <script>
                                     <script>
-                                        self.context = str(uuid.uuid4())
-                                        self.actions[self.context] = []
+                                        model = self.responses.pop(0).split(": ", 1)[1]
                                     </script>
                                     </script>
-
                                     <raise event="result">
                                     <raise event="result">
-                                        <parameter expr="self.context"/>
+                                        <parameter expr="['OP', self.parameters[0], self.context, model]"/>
                                     </raise>
                                     </raise>
-                                </onentry>
-
-                                <transition cond="self.expect_response('Success: ready for MANUAL execution')" target="../edit_model"/>
-
-                            </state>
-
-                            <state id="edit_model">
-                                <transition cond="self.expect_response_partial('Please perform manual operation ', pop=True)" target="."/>
+                                </transition>
                                 <transition cond="self.expect_response('Model loaded, ready for commands!')" target="../../../../going_scripted"/>
                                 <transition cond="self.expect_response('Model loaded, ready for commands!')" target="../../../../going_scripted"/>
                                 <transition cond="self.expect_response('Success')" target="../../../../wait_for_action/megamodelling">
                                 <transition cond="self.expect_response('Success')" target="../../../../wait_for_action/megamodelling">
                                     <raise event="result">
                                     <raise event="result">
@@ -764,7 +771,7 @@
                             <state id="init">
                             <state id="init">
                                 <onentry>
                                 <onentry>
                                     <raise event="request">
                                     <raise event="request">
-                                        <parameter expr="['process_execute', self.parameters[0], self.parameters[1]]"/>
+                                        <parameter expr="['process_execute', self.parameters[0]] + self.dict_to_list(self.parameters[1])"/>
                                     </raise>
                                     </raise>
                                 </onentry>
                                 </onentry>
 
 
@@ -825,24 +832,20 @@
                                     </state>
                                     </state>
                                 </state>
                                 </state>
 
 
-                                <state id="op" initial="init">
-                                    <state id="init">
-                                        <transition target="../processing">
-                                            <script>
-                                                self.context = str(uuid.uuid4())
-                                                self.actions[self.context] = []
-                                            </script>
-
-                                            <raise event="result">
-                                                <parameter expr="['OP', self.op_name, self.context]"/>
-                                            </raise>
-                                        </transition>
-                                    </state>
-
-                                    <state id="processing">
-                                        <transition cond="self.expect_response_partial('Please perform manual operation ', pop=True)" target="."/>
-                                        <transition cond="self.expect_response('Model loaded, ready for commands!')" target="../../../../../../going_scripted"/>
-                                    </state>
+                                <state id="op">
+                                    <transition cond="self.expect_response_partial('Please perform manual operation ', pop=True)" target="."/>
+                                    <transition cond="self.expect_response_partial('Operating on: ', pop=False)" target=".">
+                                        <script>
+                                            model = self.responses.pop(0).split(": ", 1)[1]
+                                            self.context = str(uuid.uuid4())
+                                            self.actions[self.context] = []
+                                        </script>
+
+                                        <raise event="result">
+                                            <parameter expr="['OP', self.op_name, self.context, model]"/>
+                                        </raise>
+                                    </transition>
+                                    <transition cond="self.expect_response('Model loaded, ready for commands!')" target="../../../../../going_scripted"/>
                                 </state>
                                 </state>
 
 
                                 <transition cond="self.expect_response('Success', pop=True)" target="../executing"/>
                                 <transition cond="self.expect_response('Success', pop=True)" target="../executing"/>
@@ -1608,37 +1611,31 @@
                             </script>
                             </script>
                         </transition>
                         </transition>
 
 
-                        <transition cond="self.expect_action(None, 'transformation_add_MT')" target="../../operations/store_on_scripted/transformation_add_MT">
+                        <transition cond="self.expect_action(None, 'process_signature')" target="../../operations/process_signature">
                             <script>
                             <script>
                                 self.load_action(None)
                                 self.load_action(None)
                             </script>
                             </script>
                         </transition>
                         </transition>
 
 
-                        <transition cond="self.expect_action(None, 'transformation_add_AL')" target="../../operations/store_on_scripted/transformation_add_AL">
-                            <script>
-                                self.load_action(None)
-                            </script>
-                        </transition>
-
-                        <transition cond="self.expect_action(None, 'transformation_add_MANUAL')" target="../../operations/store_on_scripted/transformation_add_MANUAL">
+                        <transition cond="self.expect_action(None, 'transformation_add_MT')" target="../../operations/store_on_scripted/transformation_add_MT">
                             <script>
                             <script>
                                 self.load_action(None)
                                 self.load_action(None)
                             </script>
                             </script>
                         </transition>
                         </transition>
 
 
-                        <transition cond="self.expect_action(None, 'transformation_execute_AL')" target="../../operations/store_on_scripted/transformation_execute">
+                        <transition cond="self.expect_action(None, 'transformation_add_AL')" target="../../operations/store_on_scripted/transformation_add_AL">
                             <script>
                             <script>
                                 self.load_action(None)
                                 self.load_action(None)
                             </script>
                             </script>
                         </transition>
                         </transition>
 
 
-                        <transition cond="self.expect_action(None, 'transformation_execute_MT')" target="../../operations/store_on_scripted/transformation_execute">
+                        <transition cond="self.expect_action(None, 'transformation_add_MANUAL')" target="../../operations/store_on_scripted/transformation_add_MANUAL">
                             <script>
                             <script>
                                 self.load_action(None)
                                 self.load_action(None)
                             </script>
                             </script>
                         </transition>
                         </transition>
 
 
-                        <transition cond="self.expect_action(None, 'transformation_execute_MANUAL')" target="../../operations/store_on_scripted/transformation_execute_MANUAL">
+                        <transition cond="self.expect_action(None, 'transformation_execute')" target="../../operations/store_on_scripted/transformation_execute">
                             <script>
                             <script>
                                 self.load_action(None)
                                 self.load_action(None)
                             </script>
                             </script>
@@ -1777,6 +1774,7 @@
                         <state id="recognized" initial="manual">
                         <state id="recognized" initial="manual">
                             <state id="manual">
                             <state id="manual">
                                 <transition cond="self.expect_action(self.context, 'exit')" target="../../../../leaving_manual"/>
                                 <transition cond="self.expect_action(self.context, 'exit')" target="../../../../leaving_manual"/>
+                                <transition cond="self.expect_action(self.context, 'drop')" target="../../../../leaving_manual_drop"/>
 
 
                                 <transition cond="self.actions[self.context] and self.actions[self.context][0]['parameters'][0] != self.current_model" target="../../../../leaving_manual"/>
                                 <transition cond="self.actions[self.context] and self.actions[self.context][0]['parameters'][0] != self.current_model" target="../../../../leaving_manual"/>
                             </state>
                             </state>
@@ -1787,6 +1785,12 @@
                                         <parameter expr="'exit'"/>
                                         <parameter expr="'exit'"/>
                                     </raise>
                                     </raise>
                                 </transition>
                                 </transition>
+
+                                <transition cond="self.expect_action(self.context, 'drop')" target="../../../../operations/store_on_scripted/history">
+                                    <raise event="request">
+                                        <parameter expr="'drop'"/>
+                                    </raise>
+                                </transition>
                             </state>
                             </state>
 
 
                             <transition cond="self.expect_action(self.context, 'element_list')" target="../../../operations/element_list">
                             <transition cond="self.expect_action(self.context, 'element_list')" target="../../../operations/element_list">
@@ -2039,6 +2043,16 @@
 
 
                     <transition cond="self.expect_response('Success', pop=True)" target="../wait_for_action/megamodelling"/>
                     <transition cond="self.expect_response('Success', pop=True)" target="../wait_for_action/megamodelling"/>
                 </state>
                 </state>
+
+                <state id="leaving_manual_drop">
+                    <onentry>
+                        <raise event="request">
+                            <parameter expr="'drop'"/>
+                        </raise>
+                    </onentry>
+
+                    <transition cond="self.expect_response('Success', pop=True)" target="../wait_for_action/megamodelling"/>
+                </state>
             </state>
             </state>
 
 
             <state id="queue">
             <state id="queue">
@@ -2103,7 +2117,7 @@
                         <parameter name="value"/>
                         <parameter name="value"/>
                         <parameter name="context_ID"/>
                         <parameter name="context_ID"/>
                         <script>
                         <script>
-                            self.inputs[context_ID].append(value)
+                            self.inputs[context_ID].append({"name": "data_input", "parameters": value})
                         </script>
                         </script>
                     </transition>
                     </transition>
                 </state>
                 </state>

+ 66 - 73
wrappers/modelverse.py

@@ -52,6 +52,39 @@ def _next_ID():
     ID += 1
     ID += 1
     return ID
     return ID
 
 
+def _process_SC(statechart, port_sc, context):
+    print("Context: " + str(context))
+    while 1:
+        empty = True
+
+        # Fetch output from the MV
+        response = responses.fetch(0)
+        if response is not None:
+            print("Output of MV to SC")
+            if response.name == "data_output":
+                # Got output of MV, so forward to SCCD
+                statechart[0].addInput(Event("input", statechart[1], response.parameters))
+            elif response.name == "result":
+                # Finished execution, so continue and return result
+                statechart[0].addInput(Event("terminate", statechart[1], []))
+                return response.parameters[1]
+            else:
+                raise Exception("Unknown data from MV to SC: " + str(response))
+            empty = False
+
+        # Fetch output from the SC
+        response = port_sc.fetch(0)
+        if response is not None:
+            print("Output of SC to MV")
+            if response.name == "output":
+                controller.addInput(Event("data_input", "action_in", [response.parameters, context]))
+            else:
+                raise Exception("Unknown data from SC to MV: " + str(response))
+            empty = False
+
+        if empty:
+            time.sleep(0.5)
+
 def INPUT(action, context, parameters):
 def INPUT(action, context, parameters):
     controller.addInput(Event("action", "action_in", [action, _next_ID(), context, parameters]))
     controller.addInput(Event("action", "action_in", [action, _next_ID(), context, parameters]))
 
 
@@ -66,6 +99,7 @@ def OUTPUT():
             elif response.parameters[1] == "UnknownMetamodellingHierarchy":
             elif response.parameters[1] == "UnknownMetamodellingHierarchy":
                 raise UnknownMetamodellingHierarchy()
                 raise UnknownMetamodellingHierarchy()
             else:
             else:
+                print("Unknown error: " + str(response.parameters))
                 raise UnknownError()
                 raise UnknownError()
 
 
 def init(address_param="127.0.0.1:8001", timeout=20.0):
 def init(address_param="127.0.0.1:8001", timeout=20.0):
@@ -133,21 +167,21 @@ def model_render(model_name, mapper_name, rendered_name):
     INPUT("model_render", None, [model_name, mapper_name, rendered_name])
     INPUT("model_render", None, [model_name, mapper_name, rendered_name])
     return OUTPUT()
     return OUTPUT()
 
 
-def transformation_between(source, target):
+def transformation_between(sources, targets):
     INPUT("transformation_between", None, [source, target])
     INPUT("transformation_between", None, [source, target])
     return OUTPUT()
     return OUTPUT()
 
 
 def transformation_add_MT(source_metamodels, target_metamodels, operation_name, code, callback=None):
 def transformation_add_MT(source_metamodels, target_metamodels, operation_name, code, callback=None):
-    INPUT("transformation_add_MT", None, [source_metamodels, target_metamodels, operation_name, code])
-    context = OUTPUT()
+    INPUT("transformation_add_MT", None, [source_metamodels, target_metamodels, operation_name, code, True])
+    context, model = OUTPUT()
     if callback is not None:
     if callback is not None:
         callback(context)
         callback(context)
     INPUT("exit", context, [])
     INPUT("exit", context, [])
     return OUTPUT()
     return OUTPUT()
 
 
 def transformation_add_AL(source_metamodels, target_metamodels, operation_name, code, callback=None):
 def transformation_add_AL(source_metamodels, target_metamodels, operation_name, code, callback=None):
-    INPUT("transformation_add_AL", None, [source_metamodels, target_metamodels, operation_name, code])
-    context = OUTPUT()
+    INPUT("transformation_add_AL", None, [source_metamodels, target_metamodels, operation_name, code, True])
+    context, model = OUTPUT()
 
 
     if context is None:
     if context is None:
         # In case the source and target metamodels are empty, the context will be None, indicating that we are finished already (no callbacks allowed)
         # In case the source and target metamodels are empty, the context will be None, indicating that we are finished already (no callbacks allowed)
@@ -159,89 +193,48 @@ def transformation_add_AL(source_metamodels, target_metamodels, operation_name,
     return OUTPUT()
     return OUTPUT()
 
 
 def transformation_add_MANUAL(source_metamodels, target_metamodels, operation_name, callback=None):
 def transformation_add_MANUAL(source_metamodels, target_metamodels, operation_name, callback=None):
-    INPUT("transformation_add_MANUAL", None, [source_metamodels, target_metamodels, operation_name])
-    context = OUTPUT()
+    INPUT("transformation_add_MANUAL", None, [source_metamodels, target_metamodels, operation_name, True])
+    context, model = OUTPUT()
     if callback is not None:
     if callback is not None:
         callback(context)
         callback(context)
     INPUT("exit", context, [])
     INPUT("exit", context, [])
     return OUTPUT()
     return OUTPUT()
 
 
-def transformation_execute_MT(operation_name, input_models_dict, output_models_dict, statechart=None, tracability_model="", fetch_output=True):
+def __transformation_execute(operation_name, input_models_dict, output_models_dict, statechart, tracability_model, fetch_output):
     if statechart is not None:
     if statechart is not None:
         port_sc = statechart[0].addOutputListener(statechart[2])
         port_sc = statechart[0].addOutputListener(statechart[2])
 
 
-    INPUT("transformation_execute_MT", None, [operation_name, input_models_dict, output_models_dict, tracability_model, fetch_output])
-    context = OUTPUT()
+    INPUT("transformation_execute", None, [operation_name, input_models_dict, output_models_dict, tracability_model, fetch_output])
+    op, name, context = OUTPUT()
     if statechart is not None:
     if statechart is not None:
-        while 1:
-            empty = True
-
-            # Fetch output from the MV
-            response = responses.fetch(0)
-            if response is not None:
-                if response.name == "data_output":
-                    # Got output of MV, so forward to SCCD
-                    statechart[0].addInput(Event("input", statechart[1], response.parameters))
-                elif response.name == "result":
-                    # Finished execution, so continue and return result
-                    statechart[0].addInput(Event("terminate", statechart[1], []))
-                    return response.parameters[1]
-                empty = False
-
-            # Fetch output from the SC
-            response = port_sc.fetch(0)
-            if response is not None:
-                if response.name == "output":
-                    controller.addInput(Event("data_input", "action_in", [response.parameters, context]))
-                empty = False
-
-            if empty:
-                time.sleep(0.01)
+        threading.Thread(target=_process_SC, args=[statechart, port_sc, context]).start()
     else:
     else:
-        return OUTPUT()
+        val = OUTPUT()
+        print("Transformation result: " + str(val))
+        return val
 
 
-def transformation_execute_AL(operation_name, input_models_dict, output_models_dict, statechart=None, tracability_model="", fetch_output=True):
-    if statechart is not None:
-        port_sc = statechart[0].addOutputListener(statechart[2])
-    INPUT("transformation_execute_AL", None, [operation_name, input_models_dict, output_models_dict, tracability_model, fetch_output])
+def transformation_execute_MT(operation_name, input_models_dict, output_models_dict, statechart=None, tracability_model="", fetch_output=True):
+    return __transformation_execute(operation_name, input_models_dict, output_models_dict, statechart, tracability_model, fetch_output)
 
 
-    context = OUTPUT()
-    if statechart is not None:
-        while 1:
-            empty = True
-
-            # Fetch output from the MV
-            response = responses.fetch(0)
-            if response is not None:
-                if response.name == "data_output":
-                    # Got output of MV, so forward to SCCD
-                    statechart[0].addInput(Event("input", statechart[1], response.parameters))
-                elif response.name == "result":
-                    # Finished execution, so continue and return result
-                    statechart[0].addInput(Event("terminate", statechart[1], []))
-                    return response.parameters[1]
-                empty = False
-
-            # Fetch output from the SC
-            response = port_sc.fetch(0)
-            if response is not None:
-                if response.name == "output":
-                    controller.addInput(Event("data_input", "action_in", [response.parameters, context]))
-                empty = False
-
-            if empty:
-                time.sleep(0.01)
-    else:
-        return OUTPUT()
+def transformation_execute_AL(operation_name, input_models_dict, output_models_dict, statechart=None, tracability_model="", fetch_output=True):
+    return __transformation_execute(operation_name, input_models_dict, output_models_dict, statechart, tracability_model, fetch_output)
 
 
 def transformation_execute_MANUAL(operation_name, input_models_dict, output_models_dict, callback=None, tracability_model=""):
 def transformation_execute_MANUAL(operation_name, input_models_dict, output_models_dict, callback=None, tracability_model=""):
-    INPUT("transformation_execute_MANUAL", None, [operation_name, input_models_dict, output_models_dict, tracability_model])
-    context = OUTPUT()
+    INPUT("transformation_execute", None, [operation_name, input_models_dict, output_models_dict, tracability_model])
+    op, name, context, model = OUTPUT()
     if callback is not None:
     if callback is not None:
         callback(context)
         callback(context)
     INPUT("exit", context, [])
     INPUT("exit", context, [])
     return OUTPUT()
     return OUTPUT()
 
 
+def transformation_signature(operation_name):
+    INPUT("transformation_signature", None, [operation_name])
+    return OUTPUT()
+
+def process_signature(process_name):
+    INPUT("process_signature", None, [operation_name])
+    return OUTPUT()
+
 def permission_modify(model_name, permissions):
 def permission_modify(model_name, permissions):
     INPUT("permission_modify", None, [model_name, permissions])
     INPUT("permission_modify", None, [model_name, permissions])
     return OUTPUT()
     return OUTPUT()
@@ -308,7 +301,6 @@ def model_types(model_name):
 
 
 def alter_context(model_name, metamodel_name):
 def alter_context(model_name, metamodel_name):
     INPUT("alter_context", None, [model_name, metamodel_name])
     INPUT("alter_context", None, [model_name, metamodel_name])
-    return OUTPUT()
 
 
 def element_list(model_name, context=None):
 def element_list(model_name, context=None):
     INPUT("element_list", context, [model_name])
     INPUT("element_list", context, [model_name])
@@ -396,13 +388,14 @@ def process_execute(process_name, prefix, callbacks=None):
     operation = OUTPUT()
     operation = OUTPUT()
     while 1:
     while 1:
         if isinstance(operation, (list, tuple)):
         if isinstance(operation, (list, tuple)):
-            t, name, context = operation
-            if t == "OP":
+            if operation[0] == "OP":
+                t, name, context, model = operation
                 if name in callbacks:
                 if name in callbacks:
                     callbacks[name](context)
                     callbacks[name](context)
                 INPUT("exit", context, [])
                 INPUT("exit", context, [])
                 operation = OUTPUT()
                 operation = OUTPUT()
-            elif t == "SC":
+            elif operation[0] == "SC":
+                t, name, context = operation
                 if name in callbacks:
                 if name in callbacks:
                     statechart = callbacks[name]
                     statechart = callbacks[name]
                 else:
                 else:

File diff suppressed because it is too large
+ 302 - 245
wrappers/modelverse_SCCD.py


+ 0 - 319
wrappers/modelverse_coded.py

@@ -1,319 +0,0 @@
-import urllib
-import urllib2
-import json
-import random
-from urllib2 import URLError
-import sys
-import time
-import threading
-
-COMPILER_PATH = "interface/HUTN"
-
-MODE_UNCONNECTED = 0
-MODE_UNAUTHORIZED = 1
-MODE_MODELLING = 2
-MODE_SERVICE = 6
-
-# Bind to the compiler (might have to update path manually!)
-sys.path.append(COMPILER_PATH)
-from hutn_compiler.compiler import main as do_compile
-
-# Exceptions
-class ModelverseException(Exception):
-    pass
-
-class UnknownError(ModelverseException):
-    pass
-
-class UnknownIdentifier(ModelverseException):
-    pass
-
-class CompilationError(ModelverseException):
-    pass
-
-class NoSuchAttribute(ModelverseException):
-    pass
-
-class UnknownModel(ModelverseException):
-    pass
-
-class ConnectionError(ModelverseException):
-    pass
-
-class ModelExists(ModelverseException):
-    pass
-
-class PermissionDenied(ModelverseException):
-    pass
-
-class InvalidMode(ModelverseException):
-    pass
-
-class InterfaceMismatch(ModelverseException):
-    pass
-
-class UnknownMetamodellingHierarchy(ModelverseException):
-    pass
-
-# Helper functions and configuration: do not use yourself!
-taskname = None
-address = None
-last_output = None
-mode = MODE_UNCONNECTED
-prev_mode = None
-current_model = None
-registered_metamodels = {}
-
-def _check_type(value):
-    if not isinstance(value, (int, long, float, str, unicode, bool)):
-        raise UnsupportedValue("%s : %s" % (value, str(type(value))))
-
-def _check_type_list(value):
-    if isinstance(value, list):
-        [_check_type(i) for i in value]
-    else:
-        _check_type(value)
-
-def _goto_mode(new_mode, model_name=None):
-    global mode
-
-    if mode == new_mode:
-        return
-    else:
-        # Go to a mode that we have no automatic transfer to: raise exception
-        raise InvalidMode("Required mode: %s, current mode: %s" % (new_mode, mode))
-
-def _input(value, port=None):
-    # Ugly json encoding of primitives
-    if port is None:
-        port = taskname
-    if isinstance(value, type([])):
-        value = json.dumps(value)
-        urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "data": value, "taskname": port}))).read()
-    else:
-        value = json.dumps(value)
-        #print("Set input: " + str(value))
-        urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": value, "taskname": port}))).read()
-
-def _input_raw(value, taskname):
-    # Ugly json encoding of primitives
-    urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": value, "taskname": taskname}))).read()
-
-def _compile_AL(code):
-    # Compile an action language file and send the compiled code
-    code_fragments = code.split("\n")
-    code_fragments = [i for i in code_fragments if i.strip() != ""]
-    code_fragments = [i.replace("    ", "\t") for i in code_fragments]
-    initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
-    code_fragments = [i[initial_tabs:] for i in code_fragments]
-    code_fragments.append("")
-    code = "\n".join(code_fragments)
-
-    with open(".code.alc", "w") as f:
-        f.write(code)
-        f.flush()
-
-    compiled = do_compile(".code.alc", COMPILER_PATH + "/grammars/actionlanguage.g", "CS")
-    return compiled
-
-def _compile_model(code):
-    # Compile a model and send the compiled graph
-    # First change multiple spaces to a tab
-    code_fragments = code.split("\n")
-    code_fragments = [i for i in code_fragments if i.strip() != ""]
-    code_fragments = [i.replace("    ", "\t") for i in code_fragments]
-    initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
-    code_fragments = [i[initial_tabs:] for i in code_fragments]
-    code_fragments.append("")
-    code = "\n".join(code_fragments)
-
-    with open(".model.mvc", "w") as f:
-        f.write(code)
-        f.flush()
-
-    return do_compile(".model.mvc", COMPILER_PATH + "/grammars/modelling.g", "M")
-
-def _output(expected=None,port=None):
-    if port is None:
-        port = taskname
-    try:
-        global last_output
-        last_output = json.loads(urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "taskname": port}))).read())
-        #print("[OUT] %s" % last_output)
-    except:
-        raise UnknownError()
-    if expected is not None and last_output != expected:
-        raise InterfaceMismatch(_last_output(), expected)
-    return last_output
-
-def _last_output():
-    return last_output
-
-# Raise common exceptions
-def _handle_output(requested=None, split=None):
-    value = _output()
-    if value.startswith("Model exists: "):
-        raise ModelExists(value.split(": ", 1)[1])
-    elif value.startswith("Permission denied"):
-        raise PermissionDenied(value.split(": ", 1)[1])
-    elif value.startswith("Model not found: "):
-        raise UnknownModel(value.split(": ", 1)[1])
-    elif value.startswith("Element not found: "):
-        raise UnknownIdentifier(value.split(": ", 1)[1])
-    elif value.startswith("Element exists: "):
-        raise ElementExists(value.split(": ", 1)[1])
-    elif value.startswith("Attribute not found: "):
-        raise NoSuchAttribute(value.split(": ", 1)[1])
-    elif requested is not None and value.startswith(requested):
-        if split is None:
-            return value
-        else:
-            splitted = value.strip().split(split, 1)
-            if len(splitted) == 1:
-                return ""
-            else:
-                return splitted[1].rstrip()
-    else:
-        raise InterfaceMismatch(value)
-    
-def _model_modify(model_name, metamodel_name):
-    """Modify an existing model."""
-    global mode
-    global prev_mode
-
-    if mode == MODE_MANUAL:
-        prev_mode = MODE_MANUAL
-        mode = MODE_MODIFY
-        return None
-
-    _goto_mode(MODE_MODELLING)
-    prev_mode = MODE_MODELLING
-
-    _input(["model_modify", model_name, metamodel_name])
-    _handle_output("Success")
-    global current_model
-    current_model = model_name
-    # Mode has changed
-    mode = MODE_MODIFY
-    _output("Model loaded, ready for commands!")
-
-def _model_exit():
-    """Leave model modify mode."""
-    global mode
-    global prev_mode
-
-    if prev_mode == MODE_MANUAL:
-        mode = MODE_MANUAL
-        return
-
-    if mode != MODE_MODIFY:
-        raise InvalidMode()
-
-    _input("exit")
-    _output("Success")
-    mode = MODE_MODELLING
-
-def alter_context(model_name, metamodel_name):
-    global registered_metamodels
-    registered_metamodels[model_name] = metamodel_name
-
-# Main MvC operations
-def init(address_param="127.0.0.1:8001", timeout=20.0):
-    """Starts up the connection to the Modelverse."""
-    global mode
-    global address
-    global taskname
-    address = "http://%s" % address_param
-    start_time = time.time()
-    taskname = random.random()
-    while 1:
-        try:
-            _input_raw('"%s"' % taskname, "task_manager")
-            mode = MODE_UNAUTHORIZED
-            break
-        except URLError as e:
-            if time.time() - start_time > timeout:
-                raise ConnectionError(e.reason)
-            else:
-                time.sleep(0.1)
-
-def login(username, password):
-    """Log in a user, if user doesn't exist, it is created."""
-    global mode
-    _goto_mode(MODE_UNAUTHORIZED)
-
-    _output("Log on as which user?")
-    _input(username)
-    if _output() == "Password for existing user?":
-        _input(password)
-        if _output() == "Welcome to the Model Management Interface v2.0!":
-            _output("Use the 'help' command for a list of possible commands")
-            _input("quiet")
-            mode = MODE_MODELLING
-        elif _last_output() == "Wrong password!":
-            raise PermissionDenied()
-        else:
-            raise InterfaceMismatch(_last_output())
-    elif _last_output() == "This is a new user: please give password!":
-        _input(password)
-        _output("Please repeat the password")
-        _input(password)
-        if _output() == "Passwords match!":
-            _output("Welcome to the Model Management Interface v2.0!")
-            _output("Use the 'help' command for a list of possible commands")
-            _input("quiet")
-            mode = MODE_MODELLING
-        elif _last_output() == "Not the same password!":
-            # We just sent the same password, so it should be identical, unless the interface changed
-            raise InterfaceMismatch(_last_output())
-        else:
-            raise InterfaceMismatch(_last_output())
-    else:
-        raise InterfaceMismatch(_last_output())
-
-def service_register(name, function):
-    """Register a function as a service with a specific name."""
-
-    def service_process(port):
-        while 1:
-            thrd = threading.Thread(target=function, args=[service_get(port)])
-            thrd.daemon = True
-            thrd.start()
-
-    global mode
-    _goto_mode(MODE_MODELLING)
-
-    _input(["service_register", name])
-
-    # Now we are in service-mode
-    mode = MODE_SERVICE
-    port = _handle_output("Success: ", split=" ")
-
-    # Process events in the background!
-    threading.Thread(target=service_process, args=[port]).start()
-
-def service_stop():
-    """Stop the currently executing process."""
-    _goto_mode(MODE_SERVICE)
-    _input("service_stop")
-    _handle_output("Success")
-
-    global mode
-    mode = MODE_MODELLING
-
-def service_get(port):
-    """Get the values on the specified port."""
-    _goto_mode(MODE_SERVICE)
-
-    return _output(port=port)
-
-def service_set(port, value):
-    """Set a value on a specified port."""
-    _check_type_list(value)
-    _goto_mode(MODE_SERVICE)
-
-    _input(value, port=port)
-
-def service_poll(port):
-    """Checks whether or not the Modelverse side has any input ready to be processed."""
-    raise NotImplementedError()