Browse Source

Merge branch 'testing' into MvK_rules

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

+ 5 - 0
.gitignore

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

BIN
bootstrap/bootstrap.m.gz


+ 120 - 27
bootstrap/core_algorithm.alc

@@ -13,6 +13,7 @@ include "utils.alh"
 include "conformance_finding.alh"
 include "typing.alh"
 include "compiler.alh"
+include "random.alh"
 
 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)
 	elif (exact_type == "ManualOperation"):
 		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
 	elif (exact_type == "ActionLanguage"):
 		Element func
@@ -763,7 +777,7 @@ Element function execute_operation(operation_id : String, input_models : Element
 		log("Negative result of execution")
 		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
 	String transformation_id
 	Element lst
@@ -796,7 +810,7 @@ Boolean function enact_action(pm : Element, element : String, prefix : String):
 	while (set_len(lst) > 0):
 		consume = set_pop(lst)
 		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
 	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")
 		elem_name = read_attribute(pm, elem, "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":
 		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!
 		return False!
 	else:
-		keys = dict_keys(result)
+		keys = dict_keys(outputs)
 		while (set_len(keys) > 0):
 			key = set_pop(keys)
 			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]))
 		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
 	String element
 	String type
@@ -842,9 +869,28 @@ Void function enact_PM(pm : Element, prefix : String):
 	Element tuple
 	Element counters
 	Element join_nodes
+	Element keys
+	String key
 
 	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
 	counters = dict_create()
 	join_nodes = allInstances(pm, "Join")
@@ -897,7 +943,7 @@ Void function enact_PM(pm : Element, prefix : String):
 			// Execute a transformation
 			// This the difficult part!
 
-			result = enact_action(pm, element, prefix)
+			result = enact_action(pm, element, mapping)
 			output("Success")
 
 		elif (type == "Decision"):
@@ -921,6 +967,11 @@ Void function enact_PM(pm : Element, prefix : String):
 			set_add_node(worklist, create_tuple(next, result))
 
 	// 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 !
 
 String function cmd_help():
@@ -1017,7 +1068,7 @@ String function cmd_model_add(type : String, name : String, code : String):
 	else:
 		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
 	String process_id
 
@@ -1029,13 +1080,42 @@ String function cmd_process_execute(process : String, prefix : String):
 			if (element_eq(pm, read_root())):
 				return "Specified model cannot be interpreted as a ProcessModel: " + process!
 
-			enact_PM(pm, prefix)
+			enact_PM(pm, mapping)
 			return "Success"!
 		else:
 			return "Permission denied to model: " + process!
 	else:
 		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):
 	Element result
 	Element subresult
@@ -1226,13 +1306,6 @@ String function cmd_model_render(model_name : String, mapper_name : String, rend
 	else:
 		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):
 	// Execute a transformation, whatever type it is
 	// 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!
 					return "Failure"!
 				else:
-					keys = dict_keys(result)
+					keys = dict_keys(outputs)
 					while (set_len(keys) > 0):
 						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]) == ""):
 							// New model
+							log("New model!")
 							model_create(result[key], outputs[key], get_entry_id(output_map[key]), "Model")
 						else:
+							log("Existing model!")
 							model_overwrite(result[key], get_entry_id(outputs[key]), get_entry_id(output_map[key]))
 
 					return "Success"!
@@ -1609,13 +1687,18 @@ String function transformation_add(source_models : Element, target_models : Elem
 	if (get_entry_id(operation_name) == ""):
 		// Write out a merged metamodel containing all these models: this is the MM for the manual operation
 		// 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)
 			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 (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!
 			Element m
 			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_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)
 
 			// Add tracability links at this level
@@ -1698,6 +1781,9 @@ String function cmd_transformation_add_MT(source_models : Element, target_models
 	target = dict_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)
 	while (set_len(keys) > 0):
 		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)
 	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"))
 
 	ramified_metamodel = ramify(merged_formalism)
@@ -2187,7 +2277,9 @@ Void function user_function_skip_init(user_id : String):
 		elif (cmd == "model_add"):
 			output(cmd_model_add(single_input("Model type?"), single_input("Model name?"), single_input("Model textual representation?")))
 		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"):
 			output(cmd_transformation_between(dict_input("Source signature?"), dict_input("Target signature?")))
 		elif (cmd == "model_render"):
@@ -2211,11 +2303,11 @@ Void function user_function_skip_init(user_id : String):
 		elif (cmd == "model_list_full"):
 			output(cmd_model_list_full(single_input("Location?")))
 		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"):
-			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"):
-			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"):
 			output(cmd_permission_modify(single_input("Model name?"), single_input("Permissions?")))
 		elif (cmd == "permission_owner"):
@@ -2265,8 +2357,9 @@ Void function user_function_skip_init(user_id : String):
 		elif (cmd == "folder_create"):
 			output(cmd_folder_create(single_input("Folder name?")))
 		elif (cmd == "add_conformance"):
-			// TODO
+			log("Adding conformance relation...")
 			output(cmd_conformance_add(single_input("Model name?"), single_input("Metamodel name?")))
+			log("Added!")
 		elif (cmd == "remove_conformance"):
 			// TODO
 			cmd = "FAIL"

+ 4 - 3
bootstrap/mini_modify.alc

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

+ 7 - 4
bootstrap/model_management.alc

@@ -5,6 +5,7 @@ include "constructors.alh"
 include "metamodels.alh"
 include "library.alh"
 include "modelling.alh"
+include "utils.alh"
 
 Element function model_fuse(models : Element):
 	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")
 			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")
 
 			// 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)
 		elem = merged_model["model"][key]
 		type = read_type(merged_model, key)
-		splitted = string_split(type, "/")
+		splitted = string_split_nr(type, "/", 1)
 
 		if (list_len(splitted) == 1):
 			// 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))]
 
 				// 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", "")
 				target = instantiate_node(tracability_model, "Reference", "")
@@ -286,7 +289,7 @@ Element function model_split(merged_model : Element, models : Element, tracabili
 		else:
 			retyping_key = splitted[0]
 			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:
 				new_name = key
 

+ 11 - 0
bootstrap/random.alc

@@ -1,4 +1,5 @@
 include "primitives.alh"
+include "utils.alh"
 
 Integer seed = 1
 
@@ -30,3 +31,13 @@ Element function random_choice(list : Element):
 		return read_root()!
 	else:
 		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 "utils.alh"
+include "random.alh"
 
 // This function must be kept internally, only called through the "sleep" and "interruptable_sleep" functions
 Float function __sleep(a : Float, b : Boolean) = ?primitives/__sleep
@@ -486,3 +488,69 @@ Element function range(max : Integer):
 		counter = counter + 1
 
 	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():
 	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 {
-    name = "test/pn"
+    name = "pn"
     type = "test/PetriNet"
 }
 Data reachability_graph {
-    name = "test/reachability"
+    name = "reachability"
     type = "test/ReachabilityGraph"
 }
 

+ 2 - 2
integration/test_powerwindow.py

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

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

@@ -563,6 +563,7 @@ class SemanticsVisitor(Visitor):
                                        tree.startpos['column'],
                                        symbol.signature()))
 
+        """
         for i in range(len(expressions)):
             arg_type = self.get_type(expressions[i])
             param_type = symbol.params[i]
@@ -580,6 +581,7 @@ class SemanticsVisitor(Visitor):
             if type(arg_type) != type(param_type):
                 self.perform_implicit_cast(tree, expressions[i], arg_type,
                                            param_type)
+        """
 
         if symbol.name == "__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 single_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)
 Boolean function is_error(a : Element)
 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()
 Integer function random_interval(a : Integer, b : Integer)
 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)
 String function get_taskname()
 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 = \
                             yield [("RDE", [task_frame, "evalstack"]),
                                    ("RDE", [task_frame, "phase"]),
-                                   ("RRD", [while_inst, "inst"]),
+                                   ("RRD", [while_inst, self.taskname]),
                                   ]
 
         if len(evalstack_roots) == 1:
             evalstack_root = evalstack_roots[0]
         else:
+            print("Got roots: " + str(evalstack_roots))
             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 = \
                             yield [("RRD", [evalstack_root, "prev"]),
                                    ("RDE", [evalstack_root, "phase"]),
@@ -327,7 +332,7 @@ class ModelverseKernel(object):
         old_evalstack_link, old_phase_link, evalstack_roots = \
                             yield [("RDE", [task_frame, "evalstack"]),
                                    ("RDE", [task_frame, "phase"]),
-                                   ("RRD", [while_inst, "inst"]),
+                                   ("RRD", [while_inst, self.taskname]),
                                   ]
 
         if len(evalstack_roots) == 1:
@@ -491,12 +496,13 @@ class ModelverseKernel(object):
                                    ("CNV", ["init"]),
                                    ("CNV", ["init"]),
                                   ]
-            _, _, _, _, _, _, _, _, _ = \
+            _, _, _, _, _, _, _, _, _, _ = \
                             yield [("CD", [task_frame, "IP", body]),
                                    ("CD", [task_frame, "phase", new_phase]),
                                    ("CD", [task_frame, "evalstack", new_evalstack]),
                                    ("CD", [new_evalstack, "prev", evalstack]),
                                    ("CD", [evalstack, "inst", inst]),
+                                   ("CD", [evalstack, self.taskname, inst]),
                                    ("CD", [evalstack, "phase", evalstack_phase]),
                                    ("DE", [evalstack_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", [evalstack_top, "prev", evalstack_bottom])
         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", [root, "task_1", task_root])
         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", [evalstack_top, "prev", evalstack_bottom])
         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", [root, "task_1", task_root])
         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 {}
 
 Data req {
-    name = "models/requirements"
+    name = "requirements"
     type = "formalisms/Requirements"
 }
 Data plant_model {
-    name = "models/plant_model"
+    name = "plant_model"
     type = "formalisms/PW_Plant"
 }
 Data environment_model {
-    name = "models/environment_model"
+    name = "environment_model"
     type = "formalisms/PW_Environment"
 }
 Data control_model {
-    name = "models/control_model"
+    name = "control_model"
     type = "formalisms/PW_Control"
 }
 Data plant_EPN {
-    name = "models/plant_EPN"
+    name = "plant_EPN"
     type = "formalisms/Encapsulated_PetriNet"
 }
 Data control_EPN {
-    name = "models/control_EPN"
+    name = "control_EPN"
     type = "formalisms/Encapsulated_PetriNet"
 }
 Data environment_EPN {
-    name = "models/environment_EPN"
+    name = "environment_EPN"
     type = "formalisms/Encapsulated_PetriNet"
 }
 Data pn {
-    name = "models/pn"
+    name = "pn"
     type = "formalisms/PetriNet"
 }
 Data reachability_graph {
-    name = "models/reachability"
+    name = "reachability"
     type = "formalisms/ReachabilityGraph"
 }
 Data query {
-    name = "models/query"
+    name = "query"
     type = "formalisms/Query"
 }
 Data architecture {
-    name = "models/architecture"
+    name = "architecture"
     type = "formalisms/Architecture"
 }
 Data merged_EPN {
-    name = "models/merged_EPN"
+    name = "merged_EPN"
     type = "formalisms/Encapsulated_PetriNet"
 }
 

+ 12 - 12
models/pm_req_analyse_debug.mvc

@@ -81,51 +81,51 @@ Exec bfs {
 Decision found {}
 
 Data req {
-    name = "models/requirements"
+    name = "requirements"
     type = "formalisms/Requirements"
 }
 Data plant_model {
-    name = "models/plant_model"
+    name = "plant_model"
     type = "formalisms/PW_Plant"
 }
 Data environment_model {
-    name = "models/environment_model"
+    name = "environment_model"
     type = "formalisms/PW_Environment"
 }
 Data control_model {
-    name = "models/control_model"
+    name = "control_model"
     type = "formalisms/PW_Control"
 }
 Data plant_EPN {
-    name = "models/plant_EPN"
+    name = "plant_EPN"
     type = "formalisms/Encapsulated_PetriNet"
 }
 Data control_EPN {
-    name = "models/control_EPN"
+    name = "control_EPN"
     type = "formalisms/Encapsulated_PetriNet"
 }
 Data environment_EPN {
-    name = "models/environment_EPN"
+    name = "environment_EPN"
     type = "formalisms/Encapsulated_PetriNet"
 }
 Data pn {
-    name = "models/pn"
+    name = "pn"
     type = "formalisms/PetriNet"
 }
 Data reachability_graph {
-    name = "models/reachability"
+    name = "reachability"
     type = "formalisms/ReachabilityGraph"
 }
 Data query {
-    name = "models/query"
+    name = "query"
     type = "formalisms/Query"
 }
 Data architecture {
-    name = "models/architecture"
+    name = "architecture"
     type = "formalisms/Architecture"
 }
 Data merged_EPN {
-    name = "models/merged_EPN"
+    name = "merged_EPN"
     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:
     port = sys.argv[1]
 
-# Start up the HUTN compilation service already
 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"])
 
-    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.wait()
 finally:
+    # Stop the server
     try:
         server.terminate()
     except:
         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
 
 def compile_service(port):
-    print("Start with port " + str(port))
     start = time.time()
     temp_file = ".tmp_%s" % port
 
@@ -60,7 +59,6 @@ def compile_service(port):
 
     mode = service_get(port)
     code = service_get(port)
-    print("Service set: " + str(port))
 
     try:
         if mode == "code":
@@ -76,11 +74,8 @@ def compile_service(port):
     except Exception as e:
         service_set(port, str(e))
         raise
-    print("Compile took %ss" % (time.time() - start))
 
-print("Start service")
 service_register("compiler", compile_service)
-print("Service OK")
 
 try:
     while raw_input() != "STOP":

+ 0 - 1
scripts/JSON_service.py

@@ -74,7 +74,6 @@ def json_service(port):
     except Exception as e:
         service_set(port, str(e))
         raise
-    print("JSON took %ss" % (time.time() - start))
 
 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)
 
-Date:   Mon Aug 28 10:53:51 2017
+Date:   Fri Nov 10 08:52:06 2017
 
 Model author: Yentl Van Tendeloo
 Model name:   Logging
@@ -77,7 +77,6 @@ class Logging(RuntimeClassBase):
     def _init_0_exec(self, parameters):
         value = parameters[0]
         self.log.append(value)
-        print("Got value: " + str(value))
     
     def initializeStatechart(self):
         # enter default state

+ 1 - 6
unit/log_output.xml

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

+ 14 - 3
unit/test_all.py

@@ -218,15 +218,20 @@ class TestModelverse(unittest.TestCase):
         thrd.daemon = True
         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()
+        print("Joined")
         assert set(log) == set(['"p1" --> 1',
                                 '"p2" --> 2',
                                 '"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
+        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_MT("test/pn_runtime_to_design", {"PetriNet_Runtime": "test/my_pn_RT"}, {"PetriNet": "test/my_pn"}) == True
+        print("MT OK")
 
         log = []
         ctrl = log_output.Controller(log, keep_running=False)
@@ -234,7 +239,7 @@ class TestModelverse(unittest.TestCase):
         thrd.daemon = True
         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()
         assert set(log) == set(['"p1" --> 0',
                                 '"p2" --> 1',
@@ -242,8 +247,10 @@ class TestModelverse(unittest.TestCase):
 
         model_delete("RAMified")
         model_delete("merged")
+        model_delete(".tmp")
         model_delete("type mappings/RAMified")
         model_delete("type mappings/merged")
+        model_delete("type mappings/.tmp")
 
     def test_process_model_trivial_pn_subfunction(self):
         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.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()
 
         assert set(log) == set(['"0": {"p1": 1}',
                                 '"1": {"p1": 0}',
                                 '"0" --["t1"]--> "1"'])
 
+        model_delete(".tmp")
         model_delete("RAMified")
         model_delete("merged")
         model_delete("type mappings/RAMified")
         model_delete("type mappings/merged")
+        model_delete("type mappings/.tmp")
 
     def test_render(self):
         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_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")
+        print("Altered context")
         lst = element_list_nice("test/my_SCCD_trace")
 
         model_delete("merged")

+ 95 - 81
wrappers/classes/modelverse.xml

@@ -392,10 +392,6 @@
                             <script>
                                 self.registered_metamodel[self.parameters[0]] = self.parameters[1]
                             </script>
-
-                            <raise event="result">
-                                <parameter expr="None"/>
-                            </raise>
                         </transition>
                     </state>
 
@@ -560,6 +556,27 @@
                         </transition>
                     </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="transformation_add_MT" initial="send_metadata">
                             <state id="send_metadata">
@@ -576,16 +593,15 @@
 
                                 </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">
-                                        <parameter expr="self.context"/>
+                                        <parameter expr="[self.context, self.responses.pop(0).split(': ', 1)[1]]"/>
                                     </raise>
                                 </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"/>
                             </state>
 
@@ -624,19 +640,17 @@
                                     </script>
                                 </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">
-                                        <parameter expr="self.context"/>
+                                        <parameter expr="[self.context, self.responses.pop(0).split(': ', 1)[1]]"/>
                                     </raise>
                                 </transition>
-                                <transition cond="self.expect_response('Waiting for code constructors...')" target="../send_model"/>
                             </state>
 
+                            <state id="edit_metamodel">
+                                <transition cond="self.expect_response('Model loaded, ready for commands!')" target="../../../../going_scripted"/>
+                            </state>
+                               
                             <state id="send_model">
                                 <onentry>
                                     <raise event="request">
@@ -650,6 +664,8 @@
                                     </raise>
                                 </transition>
                             </state>
+
+                            <transition cond="self.expect_response('Waiting for code constructors...')" target="send_model"/>
                         </state>
 
                         <state id="transformation_add_MANUAL" initial="send_metadata">
@@ -665,16 +681,15 @@
                                     </script>
                                 </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">
-                                        <parameter expr="self.context"/>
+                                        <parameter expr="[self.context, self.responses.pop(0).split(': ', 1)[1]]"/>
                                     </raise>
                                 </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">
                                     <raise event="result">
                                         <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]]"/>
                                     </raise>
                                     <script>
-                                        if self.parameters[4] == False:
+                                        if len(self.parameters) > 4 and self.parameters[4] == False:
                                             self.finish_output_thread = True
+                                        print("Executing transformation " + str(self.parameters[0]))
                                     </script>
                                 </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>
                                         self.input_context = str(uuid.uuid4())
                                         self.inputs[self.input_context] = []
                                     </script>
-
                                     <raise event="result">
-                                        <parameter expr="self.input_context"/>
+                                        <parameter expr="['SC', self.parameters[0], self.input_context]"/>
                                     </raise>
                                 </transition>
                             </state>
@@ -726,31 +747,17 @@
                                     </raise>
                                 </transition>
                             </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>
-                                        self.context = str(uuid.uuid4())
-                                        self.actions[self.context] = []
+                                        model = self.responses.pop(0).split(": ", 1)[1]
                                     </script>
-
                                     <raise event="result">
-                                        <parameter expr="self.context"/>
+                                        <parameter expr="['OP', self.parameters[0], self.context, model]"/>
                                     </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('Success')" target="../../../../wait_for_action/megamodelling">
                                     <raise event="result">
@@ -764,7 +771,7 @@
                             <state id="init">
                                 <onentry>
                                     <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>
                                 </onentry>
 
@@ -825,24 +832,20 @@
                                     </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>
 
                                 <transition cond="self.expect_response('Success', pop=True)" target="../executing"/>
@@ -1608,37 +1611,31 @@
                             </script>
                         </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>
                                 self.load_action(None)
                             </script>
                         </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>
                                 self.load_action(None)
                             </script>
                         </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>
                                 self.load_action(None)
                             </script>
                         </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>
                                 self.load_action(None)
                             </script>
                         </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>
                                 self.load_action(None)
                             </script>
@@ -1777,6 +1774,7 @@
                         <state id="recognized" initial="manual">
                             <state id="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"/>
                             </state>
@@ -1787,6 +1785,12 @@
                                         <parameter expr="'exit'"/>
                                     </raise>
                                 </transition>
+
+                                <transition cond="self.expect_action(self.context, 'drop')" target="../../../../operations/store_on_scripted/history">
+                                    <raise event="request">
+                                        <parameter expr="'drop'"/>
+                                    </raise>
+                                </transition>
                             </state>
 
                             <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"/>
                 </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 id="queue">
@@ -2103,7 +2117,7 @@
                         <parameter name="value"/>
                         <parameter name="context_ID"/>
                         <script>
-                            self.inputs[context_ID].append(value)
+                            self.inputs[context_ID].append({"name": "data_input", "parameters": value})
                         </script>
                     </transition>
                 </state>

+ 66 - 73
wrappers/modelverse.py

@@ -52,6 +52,39 @@ def _next_ID():
     ID += 1
     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):
     controller.addInput(Event("action", "action_in", [action, _next_ID(), context, parameters]))
 
@@ -66,6 +99,7 @@ def OUTPUT():
             elif response.parameters[1] == "UnknownMetamodellingHierarchy":
                 raise UnknownMetamodellingHierarchy()
             else:
+                print("Unknown error: " + str(response.parameters))
                 raise UnknownError()
 
 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])
     return OUTPUT()
 
-def transformation_between(source, target):
+def transformation_between(sources, targets):
     INPUT("transformation_between", None, [source, target])
     return OUTPUT()
 
 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:
         callback(context)
     INPUT("exit", context, [])
     return OUTPUT()
 
 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:
         # 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()
 
 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:
         callback(context)
     INPUT("exit", context, [])
     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:
         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:
-        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:
-        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=""):
-    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:
         callback(context)
     INPUT("exit", context, [])
     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):
     INPUT("permission_modify", None, [model_name, permissions])
     return OUTPUT()
@@ -308,7 +301,6 @@ def model_types(model_name):
 
 def alter_context(model_name, metamodel_name):
     INPUT("alter_context", None, [model_name, metamodel_name])
-    return OUTPUT()
 
 def element_list(model_name, context=None):
     INPUT("element_list", context, [model_name])
@@ -396,13 +388,14 @@ def process_execute(process_name, prefix, callbacks=None):
     operation = OUTPUT()
     while 1:
         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:
                     callbacks[name](context)
                 INPUT("exit", context, [])
                 operation = OUTPUT()
-            elif t == "SC":
+            elif operation[0] == "SC":
+                t, name, context = operation
                 if name in callbacks:
                     statechart = callbacks[name]
                 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()