Browse Source

moved tests to canonical generator project. Now passing.

Cláudio Gomes 3 years ago
parent
commit
c6befc2100
27 changed files with 1282 additions and 47 deletions
  1. 27 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/META-INF/MANIFEST.MF
  2. 5 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/build.properties
  3. 17 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/canonical_generation/sample1.sa
  4. 34 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/canonical_generation/sample2.sa
  5. 71 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/controller.sa
  6. 128 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/controller_sa_allInOne.sa
  7. 80 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/controller_sa_commented.sa
  8. 67 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/lazy.sa
  9. 108 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/lazy_sa_commented.sa
  10. 45 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/loop.sa
  11. 74 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/loop_canonical.sa
  12. 12 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/power.BASE.sa
  13. 36 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/rate.sa
  14. 108 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/window_obstacle_sa_flat.BASE.sa
  15. 17 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/window_sa.BASE.sa
  16. 56 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/window_sa_canonical.BASE.sa
  17. 67 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/window_sa_canonical_commented.BASE.sa
  18. 56 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/window_sa_canonical_types.BASE.sa
  19. 79 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/window_sa_commented.BASE.sa
  20. 17 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/window_sa_comp_units.sa
  21. 68 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/pom.xml
  22. 15 4
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.tests/src/be/uantwerpen/ansymo/semanticadaptation/tests/SemanticAdaptationGeneratorTest.xtend
  23. 5 3
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.chain/META-INF/MANIFEST.MF
  24. 0 1
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.tests/pom.xml
  25. 0 39
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.tests/src/be/uantwerpen/ansymo/semanticadaptation/tests/AbstractSemanticAdaptationGeneratorTest.xtend
  26. 89 0
      DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation/src/be/uantwerpen/ansymo/semanticadaptation/generator/SemanticAdaptationGenerator.xtend
  27. 1 0
      DSL_SemanticAdaptation/pom.xml

+ 27 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/META-INF/MANIFEST.MF

@@ -0,0 +1,27 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests
+Bundle-Vendor: My Company
+Bundle-Version: 1.0.0.qualifier
+Bundle-SymbolicName: be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests; singleton:=true
+Bundle-ActivationPolicy: lazy
+Require-Bundle: org.junit;bundle-version="4.7.0",
+ org.eclipse.xtext.junit4,
+ org.eclipse.xtext.xbase.junit,
+ org.eclipse.xtext.xbase.lib,
+ org.eclipse.jdt.core,
+ org.eclipse.xtext.testing,
+ org.eclipse.xtext.xbase.testing,
+ be.uantwerpen.ansymo.semanticadaptation.cg.canonical;bundle-version="1.0.0",
+ be.uantwerpen.ansymo.semanticadaptation;bundle-version="1.0.0",
+ be.uantwerpen.ansymo.semanticadaptation.tests;bundle-version="1.0.0",
+ be.uantwerpen.ansymo.semanticadaptation.testframework;bundle-version="1.0.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Export-Package: be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests;x-internal=true
+Import-Package: org.hamcrest.core,
+ org.junit;version="4.5.0",
+ org.junit.runners.model;version="4.5.0",
+ org.junit.runner;version="4.5.0",
+ org.junit.runners;version="4.5.0",
+ org.junit.runner.manipulation;version="4.5.0",
+ org.junit.runner.notification;version="4.5.0"

+ 5 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/build.properties

@@ -0,0 +1,5 @@
+source.. = src/,\
+           src-gen/,\
+           xtend-gen/
+bin.includes = .,\
+               META-INF/

+ 17 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/canonical_generation/sample1.sa

@@ -0,0 +1,17 @@
+semantic adaptation reactive mealy OuterFMU outerFMU
+at "./path/to/FMU.fmu"
+
+	for inner fmu InnerFMU innerFMU1
+		at "./path/to/InnerFMU.fmu"
+		with input ports innerFMU1__input_port1(rad), Bool innerFMU1__input_port2, innerFMU1__input_port3 (N.m)
+		with output ports Real innerFMU1__outout_port1, Integer innerFMU1__output_port2
+
+	for inner fmu InnerFMU innerFMU2
+		at "./path/to/InnerFMU.fmu"
+		with input ports innerFMU2__input_port1(rad), Bool innerFMU2__input_port2, innerFMU2__input_port3 (N.m)
+		with output ports innerFMU2__outout_port1, String innerFMU2__output_port2
+	
+	coupled as innerFMU2.innerFMU2__outout_port1 -> innerFMU1.innerFMU1__input_port1
+	
+	input ports Real ext_input_port3 -> innerFMU1.innerFMU1__input_port3
+	output ports ext_output_port2 <- innerFMU1.innerFMU1__output_port2

+ 34 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/canonical_generation/sample2.sa

@@ -0,0 +1,34 @@
+semantic adaptation reactive mealy OuterFMU outerFMU
+at "./path/to/FMU.fmu"
+
+	for inner fmu reactive moore NA n1
+		at "./path/to/NA.fmu"
+		with input ports Real ip(m)
+		with output ports Real op(m)
+	
+	for inner fmu reactive mealy NA n2
+		at "./path/to/NA.fmu"
+		with input ports Real ip(m)
+		with output ports Real op(m)
+	
+	for inner fmu reactive mealy NA n3
+		at "./path/to/NA.fmu"
+		with input ports Real ip(m)
+		with output ports Real op(m)
+	
+	for inner fmu reactive mealy NA n4
+		at "./path/to/NA.fmu"
+		with input ports Real ip(m)
+		with output ports Real op(m)
+	
+	for inner fmu reactive mealy NB n5
+		at "./path/to/NB.fmu"
+		with input ports Real ip1(m), Real ip2(m)
+		with output ports Real op(m)
+	
+	coupled as n1.op -> n2.op, 
+				n2.op -> n3.ip, n2.op -> n4.ip,
+				n3.op -> n5.ip1,
+				n4.op -> n5.ip2,
+				n5.op -> n1.ip
+	

+ 71 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/controller.sa

@@ -0,0 +1,71 @@
+semantic adaptation reactive moore ControllerSA controller_sa
+at "./path/to/ControllerSA.fmu"
+
+	for inner fmu LazySA lazy
+	at "./path/to/LazySA.fmu"
+	with input ports obj_detected, passenger_up, passenger_down, passenger_stop, driver_up, driver_down, driver_stop
+	with output ports up, down, stop
+
+input ports armature_current -> lazy.obj_detected, 
+			passenger_up -> lazy.passenger_up, 
+			passenger_down -> lazy.passenger_down,
+			passenger_stop -> lazy.passenger_stop,
+			driver_up -> lazy.driver_up, 
+			driver_down -> lazy.driver_down,
+			driver_stop -> lazy.driver_stop
+
+output ports	u,
+				d
+
+param	RTOL := 0.0001,
+		ATOL := 1e-8,
+		T := 5.0,
+		INIT_V := 0.0;
+
+control var	c := false,
+			p_v := INIT_V;
+control rules {
+	var step_size := H;
+	var aux_obj_detected := false;
+	var crossedTooFar := false;
+	if ((not is_close(p_v, T, RTOL, ATOL) and p_v < T)
+				and (not is_close(f_v, T, RTOL, ATOL) and f_v > T)) {
+		crossedTooFar := true;
+		var negative_value := p_v - T;
+		var positive_value := f_v - T;
+		step_size := (H * (- negative_value)) / (positive_value - negative_value);
+	} else {
+		if ((not is_close(p_v, T, RTOL, ATOL) and p_v < T)
+					and is_close(f_v, T, RTOL, ATOL )) { 
+			c := true;
+		}
+	}
+	
+	if (not crossedTooFar){
+		step_size := do_step(lazy, t, H);
+	}
+	
+	if (is_close(step_size, H, RTOL, ATOL)) {
+		p_v := f_v;
+	}
+	return step_size;
+}
+
+in var	f_v := INIT_V;
+in rules {
+	true -> {
+		f_v := controller_sa.armature_current;
+	} --> {
+		lazy.obj_detected := c;
+	};
+}
+
+out rules {
+	lazy.up -> { } --> {controller_sa.u := 1.0; };
+	not lazy.up -> { } --> {controller_sa.u := 0.0; };
+	
+	lazy.down -> { } --> {controller_sa.d := 1.0; };
+	not lazy.down -> { } --> {controller_sa.d := 0.0; };
+	
+	lazy.stop -> { } --> {controller_sa.u := 0.0 ; controller_sa.d := 0.0; };
+}

+ 128 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/controller_sa_allInOne.sa

@@ -0,0 +1,128 @@
+module Controller_SA
+
+/*
+ * This file is not used in the case study.
+ * The adaptations it does have been split.
+ */
+
+semantic adaptation reactive moore ControllerSA controller_sa
+at "./path/to/ControllerSA.fmu"
+
+	for inner fmu Controller controller
+	at "./path/to/Controller.fmu"
+	with input ports obj_detected, passenger_up, passenger_down, passenger_stop, driver_up, driver_down, driver_stop
+	with output ports up, down, stop
+
+/*
+At some point in the future, we support for simple wildcars in the input ports.
+According to Casper and Kenneth, some FMUs have thousands of ports...
+*/
+input ports armature_current -> controller.obj_detected, 
+			passenger_up -> controller.passenger_up, // You could write passenger_* here.
+			passenger_down -> controller.passenger_down,
+			passenger_stop -> controller.passenger_stop,
+			driver_up -> controller.driver_up, // You could write driver_* here.
+			driver_down -> controller.driver_down,
+			driver_stop -> controller.driver_stop
+
+output ports	u,
+				d
+
+param	REL_TOL := 0.0001,
+		ABS_TOL := 1e-8,
+		CROSSING := 5.0,
+		INIT_ARMATURE_CURRENT := 0.0,
+		INIT_U := 0.0,
+		INIT_D := 0.0;
+
+control var	aux_obj_detected := 0,
+			get_next_step := true,
+			previous_arm_current := INIT_ARMATURE_CURRENT;
+control rules {
+	var step_size := H;
+	aux_obj_detected := false;
+	if ((not is_close(previous_arm_current, CROSSING, REL_TOL, ABS_TOL) and previous_arm_current < CROSSING)
+				and (not is_close(future_arm_current, CROSSING, REL_TOL, ABS_TOL) and future_arm_current > CROSSING)) { // crossing, but not within tolerance
+		var negative_value := previous_arm_current - CROSSING;
+		var positive_value := future_arm_current - CROSSING;
+		step_size := (H * (- negative_value)) / (positive_value - negative_value);
+	} else {
+		if ((not is_close(previous_arm_current, CROSSING, REL_TOL, ABS_TOL) and previous_arm_current < CROSSING)
+					and is_close(future_arm_current, CROSSING, REL_TOL, ABS_TOL )) { // crossing within tolerance found
+			aux_obj_detected := true;
+		}
+	}
+	
+	if (aux_obj_detected == true or t >= next_time_step) {
+		var aux_h := do_step(controller, t-e, e); // do a step, then decide next internal transition
+		//assert aux_h == e; this must always be the case, otherwise it is better not to use the timed transition adaptation.
+		get_next_step := true; // next time the setValues is called, the internal transition will be set again.
+	} else {
+		get_next_step := false;
+	}
+	if (is_close(step_size, H, REL_TOL, ABS_TOL)) {
+		// Step accepted, so store the known input.
+		// We cannot store the armature current at the in rules because we may not accept the step and because they may be called multiple times. 
+		// If that happens, we want to still have the old value of armature current, to compare it with the new one.
+		previous_arm_current := future_arm_current;
+	}
+	return step_size;
+}
+
+in var	next_time_step := -1.0,
+		future_arm_current := INIT_ARMATURE_CURRENT;
+in rules {
+	get_next_step -> {
+		next_time_step := get_next_time_step(controller) + last_execution_time(controller); 
+		/*
+		The get_next_time_step(controller) function is equivalent to the following snippet:
+		save_state(controller);
+		internal_transition := do_step(controller, last_execution_time(controller), MAX);
+		next_time_step := last_execution_time(controller) + internal_transition;
+		rollback(controller);
+		*/
+	} --> { };
+	
+	true -> {
+		future_arm_current := armature_current;
+	} --> {
+		obj_detected := aux_obj_detected; // Sets this input to the FMU 
+	};
+}
+
+out var stored_up := INIT_U,
+		stored_down := INIT_D;
+out rules {
+	true -> {
+		/*
+		Previously, there was this intruction here:
+		internal_transition := get_next_time_step(controller) + t
+		
+		However, it cannot be here, since there is no guarantee in the control rules block, that the doStep of the controller will be called.
+		*/
+	} --> {};
+	
+	/*
+	What does "otherwise var" mean?
+	Suppose I have the following rules:
+		var1 == true and var2 == false -> ...
+		otherwise var1 -> ...
+	
+	controller.up == true -> { stored_up := 1; } --> { };
+	otherwise up -> { } --> { }; 
+	down == true -> { down := 1; } --> { };
+	otherwise down -> { } --> { };
+	stop == true -> { up := 0; down := 0; } --> { };
+	otherwise stop -> { } --> { };
+	true -> { up := stored_up; stored_up := up; } --> { };
+	true -> { down := stored_down; stored_down := down; } --> { }; 
+	*/
+	controller.up -> {stored_up := 1; } --> {u := stored_up; };
+	not controller.up -> {stored_up := 0; } --> {u := stored_up; };
+	
+	controller.down -> {stored_down := 1; } --> {d := stored_down; };
+	not controller.down -> {stored_down := 0; } --> {d := stored_down; };
+	
+	controller.stop -> {stored_down := 0; stored_up :=0; } --> {u := stored_up ; d := stored_down; };
+	
+}

+ 80 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/controller_sa_commented.sa

@@ -0,0 +1,80 @@
+module Controller_SA
+
+semantic adaptation reactive moore ControllerSA controller_sa
+at "./path/to/ControllerSA.fmu"
+
+	for inner fmu LazySA lazy
+	at "./path/to/LazySA.fmu"
+	with input ports obj_detected, passenger_up, passenger_down, passenger_stop, driver_up, driver_down, driver_stop
+	with output ports up, down, stop
+
+/*
+At some point in the future, we support for simple wildcars in the input ports.
+According to Casper and Kenneth, some FMUs have thousands of ports...
+*/
+input ports armature_current -> lazy.obj_detected, 
+			passenger_up -> lazy.passenger_up, // You could write passenger_* here.
+			passenger_down -> lazy.passenger_down,
+			passenger_stop -> lazy.passenger_stop,
+			driver_up -> lazy.driver_up, // You could write driver_* here.
+			driver_down -> lazy.driver_down,
+			driver_stop -> lazy.driver_stop
+
+output ports	u,
+				d
+
+param	REL_TOL := 0.0001,
+		ABS_TOL := 1e-8,
+		CROSSING := 5.0,
+		INIT_ARMATURE_CURRENT := 0.0;
+
+control var	aux_obj_detected := 0,
+			previous_arm_current := INIT_ARMATURE_CURRENT;
+control rules {
+	var step_size := H;
+	var aux_obj_detected := false;
+	var crossedTooFar := false;
+	if ((not is_close(previous_arm_current, CROSSING, REL_TOL, ABS_TOL) and previous_arm_current < CROSSING)
+				and (not is_close(future_arm_current, CROSSING, REL_TOL, ABS_TOL) and future_arm_current > CROSSING)) { // crossing, but not within tolerance
+		crossedTooFar := true;
+		var negative_value := previous_arm_current - CROSSING;
+		var positive_value := future_arm_current - CROSSING;
+		step_size := (H * (- negative_value)) / (positive_value - negative_value);
+	} else {
+		if ((not is_close(previous_arm_current, CROSSING, REL_TOL, ABS_TOL) and previous_arm_current < CROSSING)
+					and is_close(future_arm_current, CROSSING, REL_TOL, ABS_TOL )) { // crossing within tolerance found
+			aux_obj_detected := true;
+		}
+	}
+	
+	if (not crossedTooFar){
+		step_size := do_step(lazy, t, H);
+	}
+	
+	if (is_close(step_size, H, REL_TOL, ABS_TOL)) {
+		// Step accepted, so store the known input.
+		// We cannot store the armature current at the in rules because we may not accept the step and because they may be called multiple times. 
+		// If that happens, we want to still have the old value of armature current, to compare it with the new one.
+		previous_arm_current := future_arm_current;
+	}
+	return step_size;
+}
+
+in var	future_arm_current := INIT_ARMATURE_CURRENT;
+in rules {
+	true -> {
+		future_arm_current := armature_current;
+	} --> {
+		obj_detected := aux_obj_detected; // Sets this input to the FMU 
+	};
+}
+
+out rules {
+	lazy.up -> { } --> {u := 1.0; };
+	not lazy.up -> { } --> {u := 0.0; };
+	
+	lazy.down -> { } --> {d := 1.0; };
+	not lazy.down -> { } --> {d := 0.0; };
+	
+	lazy.stop -> { } --> {u := 0.0 ; d := 0.0; };
+}

+ 67 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/lazy.sa

@@ -0,0 +1,67 @@
+semantic adaptation reactive moore LazySA lazy_sa
+at "./path/to/LazySA.fmu"
+
+	for inner fmu Controller controller
+	at "./path/to/Controller.fmu"
+	with input ports Bool obj_detected, Bool passenger_up, Bool passenger_down, Bool passenger_stop, Bool driver_up, Bool driver_down, Bool driver_stop
+	with output ports Bool up, Bool down, Bool stop
+
+input ports obj_detected -> controller.obj_detected,
+			passenger_up -> controller.passenger_up,
+			passenger_down -> controller.passenger_down,
+			passenger_stop -> controller.passenger_stop,
+			driver_up -> controller.driver_up,
+			driver_down -> controller.driver_down,
+			driver_stop -> controller.driver_stop
+
+param 	INIT_OBJ_DETECTED := false,
+		INIT_PASSENGER_UP := false,
+		INIT_PASSENGER_DOWN := false,
+		INIT_PASSENGER_STOP := false,
+		INIT_DRIVER_UP := false,
+		INIT_DRIVER_DOWN := false,
+		INIT_DRIVER_STOP := false;
+
+control var	tn := -1.0,
+			tl := -1.0,
+			prev_obj_detected := INIT_OBJ_DETECTED,
+			prev_passenger_up := INIT_PASSENGER_UP,
+			prev_passenger_down := INIT_PASSENGER_DOWN,
+			prev_passenger_stop := INIT_PASSENGER_STOP,
+			prev_driver_up := INIT_DRIVER_UP,
+			prev_driver_down := INIT_DRIVER_DOWN,
+			prev_driver_stop := INIT_DRIVER_STOP;
+
+control rules {
+	if (tl < 0.0){
+		tl := t;
+	}
+	
+	var step_size := min(H, tn - t); 
+	if (lazy_sa.obj_detected != prev_obj_detected or
+		lazy_sa.passenger_up != prev_passenger_up or
+		lazy_sa.passenger_down != prev_passenger_down or
+		lazy_sa.passenger_stop != prev_passenger_stop or
+		lazy_sa.driver_up != prev_driver_up or
+		lazy_sa.driver_down != prev_driver_down or
+		lazy_sa.driver_stop != prev_driver_stop or
+		(t+H) >= tn
+	){
+		var Real step_to_be_done := (t+H-tl);
+		var step_done := do_step(controller, t, step_to_be_done); 
+		tn := tl + step_done + get_next_time_step(controller); 
+		step_size := tl + step_done - t; 
+		tl := tl + step_done; 
+	}
+	
+	prev_obj_detected := lazy_sa.obj_detected;
+	prev_passenger_up := lazy_sa.passenger_up;
+	prev_passenger_down := lazy_sa.passenger_down;
+	prev_passenger_stop := lazy_sa.passenger_stop;
+	prev_driver_up := lazy_sa.driver_up;
+	prev_driver_down := lazy_sa.driver_down;
+	prev_driver_stop := lazy_sa.driver_stop;
+	
+	return step_size;
+}
+

+ 108 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/lazy_sa_commented.sa

@@ -0,0 +1,108 @@
+module Lazy_SA
+
+/*
+ * The purpose of this adaptation is to only run the internal FMU 
+ * 	when any of its inputs changes, or when it requests to be explicitly run.
+ */
+
+semantic adaptation reactive moore LazySA lazy_sa
+at "./path/to/LazySA.fmu"
+
+	for inner fmu Controller controller
+	at "./path/to/Controller.fmu"
+	with input ports obj_detected, passenger_up, passenger_down, passenger_stop, driver_up, driver_down, driver_stop
+	with output ports up, down, stop
+
+/*
+ * In addition, we do not need to do anything about the outputs of the inner FMU, because they are zero order holded by default.
+ */
+input ports obj_detected -> controller.obj_detected,
+			passenger_up -> controller.passenger_up,
+			passenger_down -> controller.passenger_down,
+			passenger_stop -> controller.passenger_stop,
+			driver_up -> controller.driver_up,
+			driver_down -> controller.driver_down,
+			driver_stop -> controller.driver_stop
+
+output ports up, down, stop
+
+param 	INIT_OBJ_DETECTED := false,
+		INIT_PASSENGER_UP := false,
+		INIT_PASSENGER_DOWN := false,
+		INIT_PASSENGER_STOP := false,
+		INIT_DRIVER_UP := false,
+		INIT_DRIVER_DOWN := false,
+		INIT_DRIVER_STOP := false;
+
+control var	tn := -1.0,
+			tl := -1.0,
+			prev_obj_detected := INIT_OBJ_DETECTED,
+			prev_passenger_up := INIT_PASSENGER_UP,
+			prev_passenger_down := INIT_PASSENGER_DOWN,
+			prev_passenger_stop := INIT_PASSENGER_STOP,
+			prev_driver_up := INIT_DRIVER_UP,
+			prev_driver_down := INIT_DRIVER_DOWN,
+			prev_driver_stop := INIT_DRIVER_STOP;
+
+control rules {
+	// This initialisation covers simulations that start at a non-zero time.
+	if (tl < 0.0){
+		tl := t;
+	}
+	
+	var step_size := min(H, tn - t); // In case tn < t, this ensures that the controller will be run at the right time.
+	// Note that the expression lazy_sa.obj_detected gets replaced by the corresponding storage var in the canonical version.
+	if (lazy_sa.obj_detected != prev_obj_detected or
+		lazy_sa.passenger_up != prev_passenger_up or
+		lazy_sa.passenger_down != prev_passenger_down or
+		lazy_sa.passenger_stop != prev_passenger_stop or
+		lazy_sa.driver_up != prev_driver_up or
+		lazy_sa.driver_down != prev_driver_down or
+		lazy_sa.driver_stop != prev_driver_stop or
+		(t+H) >= tn
+	){
+		var step_to_be_done := (t+H-tl);
+		var step_done := do_step(controller, t, step_to_be_done); // calls the mapIn function that will take care of forwarding the values of the input ports to the internal FMU.
+		// We calculate these as if step_done == step_to_be_done. If that is not the case, a rollback will be done anyway.
+		tn := tl + step_done + get_next_time_step(controller); // calculates the next time step that is tolerated by the controller.
+		/*
+			The get_next_time_step(controller) function is equivalent to the following snippet:
+			save_state(controller);
+			internal_transition := do_step(controller, last_execution_time(controller), MAX);
+			next_time_step := last_execution_time(controller) + internal_transition;
+			rollback(controller);
+		 */
+		// This is the actual step size taken, from the outside world:
+		step_size := tl + step_done - t; // assert step_size <= H
+		tl := tl + step_done; // assert tl == t+H
+	}
+	
+	// Store the previous values of the inputs
+	prev_obj_detected := lazy_sa.obj_detected;
+	prev_passenger_up := lazy_sa.passenger_up;
+	prev_passenger_down := lazy_sa.passenger_down;
+	prev_passenger_stop := lazy_sa.passenger_stop;
+	prev_driver_up := lazy_sa.driver_up;
+	prev_driver_down := lazy_sa.driver_down;
+	prev_driver_stop := lazy_sa.driver_stop;
+	
+	return step_size;
+}
+
+/*
+The following code is not needed because the outputs are zero order hold'ed by default:
+out var	stored_up := INIT_UP,
+		stored_down := INIT_DOWN,
+		stored_stop := INIT_STOP;
+out rules{
+	 true -> {
+		stored_up := controller.up;
+		stored_down := controller.down;
+		stored_stop := controller.stop;
+	} --> {
+		lazy_sa.up := stored_up;
+		lazy_sa.down := stored_down;
+		lazy_sa.stop := stored_stop;
+	};
+}
+ */

+ 45 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/loop.sa

@@ -0,0 +1,45 @@
+semantic adaptation reactive moore LoopSA loop_sa
+at "./path/to/LoopSA.fmu"
+
+	for inner fmu WindowSA window_sa
+		at "./path/to/WindowSA.fmu"
+		with input ports displacement (rad), speed (rad/s), reaction_force (N)
+		with output ports disp (m), tau (N.m)
+	
+	for inner fmu Obstacle obstacle
+		at "./path/to/Obstacle.fmu"
+		with input ports disp (m)
+		with output ports reaction_force (m)
+	
+	coupled as	window_sa.disp -> obstacle.disp,
+				obstacle.reaction_force -> window_sa.reaction_force
+
+output ports tau <- window_sa.tau
+
+param 	MAXITER := 10, 
+		REL_TOL := 1e-05, 
+		ABS_TOL := 1e-05;
+
+control var prev_disp := 0.0;
+control rules {
+	var repeat := false;
+	for (var iter in 0 .. MAXITER) {
+		save_state(obstacle);
+		save_state(window_sa);
+		obstacle.disp := prev_disp;
+		do_step(obstacle,t,H);
+		do_step(window_sa,t,H);
+		
+		repeat := is_close(prev_disp, window_sa.disp, REL_TOL, ABS_TOL);
+		prev_disp := window_sa.disp;
+		if (repeat) {
+			break;
+		} else {
+			rollback(obstacle);
+			rollback(window_sa);
+		}
+	}
+	return H;
+}
+
+

+ 74 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/loop_canonical.sa

@@ -0,0 +1,74 @@
+semantic adaptation reactive moore LoopSA loop_sa
+at "./path/to/LoopSA.fmu"
+	
+	for inner fmu WindowSA window_sa
+		at "./path/to/WindowSA.fmu"
+		with input ports displacement (rad), speed (rad/s), reaction_force (N)
+		with output ports disp (m), tau (N.m)
+	
+	for inner fmu Obstacle obstacle
+		at "./path/to/Obstacle.fmu"
+		with input ports disp (m)
+		with output ports reaction_force (m)
+	
+	coupled as window_sa.disp -> obstacle.disp, 
+				obstacle.reaction_force -> window_sa.reaction_force
+
+input ports displacement, speed
+
+output ports tau
+
+param 	MAXITER := 10, REL_TOL := 1e-05, ABS_TOL := 1e-05,
+		INIT_LOOP_SA_DISPLACEMENT := 0.0,
+		INIT_LOOP_SA_SPEED := 0.0,
+		INIT_WINDOW_SA_DISP := 0.0,
+		INIT_WINDOW_SA_TAU := 0.0,
+		INIT_OBSTACLE_REACTION_FORCE := 0.0;
+
+control var prev_disp := 0.0;
+control rules {
+	var repeat := false;
+	for (var iter in 0 .. MAXITER) {
+		save_state(obstacle);
+		save_state(window_sa);
+		obstacle.disp := prev_disp;
+		do_step(obstacle,t,H);
+		window_sa.reaction_force := stored_obstacle_reaction_force;
+		do_step(window_sa,t,H);
+		
+		repeat := is_close(prev_disp, stored_window_sa_disp, REL_TOL, ABS_TOL);
+		prev_disp := stored_window_sa_disp;
+		if (repeat) {
+			break;
+		} else {
+			rollback(obstacle);
+			rollback(window_sa);
+		}
+	}
+	return H;
+}
+
+in var 	stored_loop_sa_displacement := INIT_LOOP_SA_DISPLACEMENT,
+		stored_loop_sa_speed := INIT_LOOP_SA_SPEED;
+in rules {
+	true -> {
+		stored_loop_sa_displacement := loop_sa.displacement;
+		stored_loop_sa_speed := loop_sa.speed;
+	} --> {
+		window_sa.displacement := stored_loop_sa_displacement;
+		window_sa.speed := stored_loop_sa_speed;
+	};
+}
+
+out var	stored_window_sa_disp := INIT_WINDOW_SA_DISP,
+		stored_window_sa_tau := INIT_WINDOW_SA_TAU,
+		stored_obstacle_reaction_force := INIT_OBSTACLE_REACTION_FORCE;
+out rules{
+	true -> {
+		stored_window_sa_disp := window_sa.disp;
+		stored_window_sa_tau := window_sa.tau;
+		stored_obstacle_reaction_force := obstacle.tau;
+	} --> {
+		loop_sa.tau := stored_window_sa_tau;
+	};
+}

+ 12 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/power.BASE.sa

@@ -0,0 +1,12 @@
+semantic adaptation delayed moore PowerSA power_sa
+at "./path/to/PowerSA.fmu"
+
+	for inner fmu Power power
+	at "./path/to/Power.fmu"
+	with input ports u, d, tau (N.m)
+	with output ports armature_current (A), speed (rad/s), displacement (rad)
+
+output ports armature_current <- power.armature_current, 
+			speed <- power.speed,
+			displacement <- power.displacement
+

+ 36 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/rate.sa

@@ -0,0 +1,36 @@
+semantic adaptation reactive moore RateSA rate_sa
+at "./path/to/RateSA.fmu"
+
+	for inner fmu LoopSA loop_sa
+		at "./path/to/LoopSA.fmu"
+		with input ports displacement (rad), speed (rad/s)
+		with output ports tau (N.m)
+	
+input ports speed
+output ports tau <- loop_sa.tau
+
+param 	RATE := 10;
+
+control var previous_speed := 0;
+control rules {
+	var micro_step := H/RATE;
+	var inner_time := t;
+	
+	for (var iter in 0 .. RATE) { 
+		do_step(loop_sa,inner_time,micro_step);
+		inner_time := inner_time + micro_step;	
+	}
+	
+	previous_speed := current_speed;
+	return H;
+}
+
+in var current_speed := 0;
+in rules {
+	true -> {
+		current_speed := speed;
+	} --> {
+		loop_sa.speed := previous_speed + (current_speed - previous_speed)*(dt + h);
+	};
+}
+

+ 108 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/window_obstacle_sa_flat.BASE.sa

@@ -0,0 +1,108 @@
+module WindowObstacleLoop_SA
+
+semantic adaptation reactive mealy WindowObstableLoopSA adaptedFMU
+at "./path/to/WindowObstableLoopSA.fmu"
+
+	for inner fmu WindowSA window_sa
+		at "./path/to/WindowSA.fmu"
+		with input ports displacement (rad), speed (rad/s), reaction_force (N)
+		with output ports disp (m), tau (N.m)
+	
+	for inner fmu Obstacle obstacle
+		at "./path/to/Obstacle.fmu"
+		with input ports disp (m)
+		with output ports reaction_force (m)
+	
+	/*
+	This is the information that was missing before: how the semantic adaptation window_sa, which is an FMU, connects to the obstacle FMU.
+	*/
+	coupled as window_sa.disp -> obstacle.disp,	
+				obstacle.reaction_force -> window_sa.reaction_force
+
+/*
+Declares the external ports of the semantic adaptation
+Notice that window_sa.displacement is a dangling input port, so an extra input port will exist in the adapted FMU.
+*/
+input ports speed
+output ports tau 
+
+param 	RATE := 10, 
+		MAXITER := 10, 
+		REL_TOL := 1e-05, 
+		ABS_TOL := 1e-05;
+
+control var previous_speed := 0, future_speed := 0;
+control rules {
+	var inner_dt := H/RATE;
+	/*
+	The two instructions below need to be made, because previously they were made in the sa_in block, but multiple calls to the sa_in block would make them fail.
+	*/
+	previous_speed := future_speed;
+	future_speed := current_speed; // you cannot access input ports of the adapted FMU here.
+	
+	for (var iter in 0 .. RATE) { // multi-rate loop
+		var prev_disp := window_sa.disp;
+		var inner_time := t;
+		for (var iter in 0 .. MAXITER) {
+			save_state(obstacle);
+			save_state(window_sa);
+			do_step(obstacle,inner_time,inner_dt);
+			do_step(window_sa,inner_time,inner_dt);
+			
+			if (is_close(prev_disp, disp, REL_TOL, ABS_TOL)) {
+				break;
+			} else {
+				prev_disp := disp;
+				rollback(obstacle);
+				rollback(window_sa);
+			}
+			
+			/*
+			The above block of statements is equivalent to the following:
+			var obstacle_state := getState(obstacle)
+			var window_sa_state := getState(window_sa)
+			
+			obstacle.set("height", height)
+			obstacle.doStep(inner_time,h)
+			reaction_force := obstacle.get("reaction_force")
+			window_sa.set("reaction_force", reaction_force)
+			window_sa.doStep(inner_time,h)
+			height := window_sa.get("height")
+			if (is_close(prev_height, height, REL_TOL, ABS_TOL)) {
+				// The commits don't do anything, as far as I see. But they serve an analysis which ensures that states are correctly obtained and restored.
+				break;
+			} else {
+				prev_height := height;
+				obstacle.setState(obstacle_state);
+				window_sa.setState(window_sa_state);
+			}
+			*/
+		}
+		inner_time := t + inner_dt;	
+	}
+	return H;
+}
+
+in var current_speed := 0;
+in rules {
+	true -> {
+		/*
+		These instructions would violate the principle that multiple calls to setValues can be made:
+		previous_speed := future_speed;
+		future_speed := speed;
+		Upon execution, this block must call setValues of the original FMUs (window_sa and obstacle).
+		The correct thing then is to execute the next block and then do the setValues of the original FMUs.
+		*/
+		current_speed := speed;
+	} --> {
+		/*
+		This block will be called whenever any of the input ports that are unconnected in the original FMUs is read, in the control rules block.
+		The following variables are available in this block:
+			dt - In the control rules block, (t + dt) is the time that will be passed to the doStep function of the inner FMU. In the control rules block, this can be computed by doing dt := inner_time - t.
+			h - this is the communication step size that will be sent to the inner FMU.
+		
+		*/
+		window_sa.speed := previous_speed + (future_speed - previous_speed)*dt;
+	};
+}
+

+ 17 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/window_sa.BASE.sa

@@ -0,0 +1,17 @@
+semantic adaptation reactive mealy WindowSA windowSA
+at "./path/to/WindowSA.fmu"
+
+	for inner fmu Window window
+		at "test_input/single_folder_spec/window/Window.fmu"
+		with input ports displacement(rad), speed (rad/s), reaction_force (N)
+		with output ports height (cm), reaction_torque (N.m)
+
+output ports disp (m)  <- window.height, tau (N)
+
+out rules {
+	true -> {} --> {
+		windowSA.tau := -window.reaction_torque;
+	};
+}
+
+

+ 56 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/window_sa_canonical.BASE.sa

@@ -0,0 +1,56 @@
+semantic adaptation reactive mealy WindowSA windowSA
+at "./path/to/WindowSA.fmu"
+
+	for inner fmu Window window
+		at "./path/to/Window.fmu"
+		with input ports displacement (rad), speed (rad/s), reaction_force (N)
+		with output ports height (m), reaction_torque (N.m)
+
+input ports 	reaction_force,
+				displacement,
+				speed
+
+output ports	disp,
+				tau
+
+param 	INIT_WINDOWSA_REACTION_FORCE := 0.0,
+		INIT_WINDOWSA_DISPLACEMENT := 0.0,
+		INIT_WINDOWSA_SPEED := 0.0,
+		INIT_WINDOW_REACTION_TORQUE := 0.0,
+		INIT_WINDOW_REACTION_HEIGHT := 0.0;
+
+control rules {
+	var H_window := do_step(window, t, H);
+	return H_window;
+}
+
+in var 	stored_windowsa_reaction_force := INIT_WINDOWSA_REACTION_FORCE, 
+		stored_windowsa_displacement := INIT_WINDOWSA_DISPLACEMENT, 
+		stored_windowsa_speed := INIT_WINDOWSA_SPEED;
+
+in rules {
+	true -> {
+		stored_windowsa_reaction_force := windowSA.reaction_force;
+		stored_windowsa_displacement := windowSA.displacement;			
+		stored_windowsa_speed := windowSA.speed;
+	} --> {
+		window.reaction_force := stored_windowsa_reaction_force;
+		window.displacement := stored_windowsa_displacement; 
+		window.speed := stored_windowsa_speed;
+	};
+}
+
+out var stored_window_reaction_torque := INIT_WINDOW_REACTION_TORQUE,
+		stored_window_height := INIT_WINDOW_REACTION_HEIGHT;
+
+out rules {
+	true -> {
+		stored_window_reaction_torque := window.reaction_torque;
+		stored_window_height := window.height;
+	} --> {
+		windowSA.disp := stored_window_height / 100;
+	};
+	true -> { } --> {
+		windowSA.tau := -stored_window_reaction_torque;
+	};
+}

+ 67 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/window_sa_canonical_commented.BASE.sa

@@ -0,0 +1,67 @@
+module Window_SA
+
+semantic adaptation reactive mealy WindowSA windowSA
+at "./path/to/WindowSA.fmu"
+
+	for inner fmu Window window
+		at "./path/to/Window.fmu"
+		with input ports displacement (rad), speed (rad/s), reaction_force (N)
+		with output ports height (m), reaction_torque (N.m)
+
+/*
+In the original version, no input ports where declared, so all dangling inputs of the original fmus are bound to the input ports of the adapted FMU.
+In the canonical version, the input and output ports are all declared explicitly, and their bindings are implemented in the in/out rules.
+*/
+
+input ports 	reaction_force,
+				displacement,
+				speed
+
+output ports	disp,
+				tau
+
+
+control rules {
+	do_step(window, t, H); // includes update_in rules and update_out (update-in rules do not update state)
+	return H;
+}
+
+in var 	stored_windowsa_reaction_force := 0.0, 
+		stored_windowsa_displacement := 0.0, 
+		stored_windowsa_speed := 0.0;
+
+in rules {
+	true -> {
+		/*
+		is_set checks whether the input value is given in the setValues call of the adapted FMU.
+		Notice that in the canonical version, all ports are prefixed.
+		*/
+		if (is_set(windowSA.reaction_force)){
+			stored_windowsa_reaction_force := windowSA.reaction_force;
+		}
+		if (is_set(windowSA.displacement)){
+			stored_windowsa_displacement := windowSA.displacement;			
+		}
+		if (is_set(windowSA.speed)){
+			stored_windowsa_speed := windowSA.speed;
+		}
+	} --> {
+		window.reaction_force := stored_windowsa_reaction_force;
+		window.displacement := stored_windowsa_displacement; 
+		window.speed := stored_windowsa_speed;
+	};
+}
+
+out var stored_window_reaction_torque := 0,
+		stored_window_height := 0;
+		
+out rules {
+	true -> {
+		stored_window_reaction_torque := window.reaction_torque;
+		stored_window_height := window.height;
+	} --> {
+		windowSA.tau := - stored_window_reaction_torque;
+		windowSA.disp := stored_window_height / 100;
+	};
+}
+

+ 56 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/window_sa_canonical_types.BASE.sa

@@ -0,0 +1,56 @@
+semantic adaptation reactive mealy WindowSA windowSA
+at "./path/to/WindowSA.fmu"
+
+	for inner fmu Window window
+		at "./path/to/Window.fmu"
+		with input ports Real displacement (rad), Real speed (rad/s), Real reaction_force (N)
+		with output ports Real height (m), Real reaction_torque (N.m)
+
+input ports 	Real reaction_force,
+				Real displacement,
+				Real speed
+
+output ports	Real disp,
+				Real tau
+
+param 	Real INIT_WINDOWSA_REACTION_FORCE := 0.0,
+		Real INIT_WINDOWSA_DISPLACEMENT := 0.0,
+		Real INIT_WINDOWSA_SPEED := 0.0,
+		Real INIT_WINDOW_REACTION_TORQUE := 0.0,
+		Real INIT_WINDOW_REACTION_HEIGHT := 0.0;
+
+control rules {
+	var Real H_window := do_step(window, t, H);
+	return H_window;
+}
+
+in var 	Real stored_windowsa_reaction_force := INIT_WINDOWSA_REACTION_FORCE, 
+		Real stored_windowsa_displacement := INIT_WINDOWSA_DISPLACEMENT, 
+		Real stored_windowsa_speed := INIT_WINDOWSA_SPEED;
+
+in rules {
+	true -> {
+		stored_windowsa_reaction_force := windowSA.reaction_force;
+		stored_windowsa_displacement := windowSA.displacement;			
+		stored_windowsa_speed := windowSA.speed;
+	} --> {
+		window.reaction_force := stored_windowsa_reaction_force;
+		window.displacement := stored_windowsa_displacement; 
+		window.speed := stored_windowsa_speed;
+	};
+}
+
+out var Real stored_window_reaction_torque := INIT_WINDOW_REACTION_TORQUE,
+		Real stored_window_height := INIT_WINDOW_REACTION_HEIGHT;
+
+out rules {
+	true -> {
+		stored_window_reaction_torque := window.reaction_torque;
+		stored_window_height := window.height;
+	} --> {
+		windowSA.disp := stored_window_height / 100;
+	};
+	true -> { } --> {
+		windowSA.tau := -stored_window_reaction_torque;
+	};
+}

+ 79 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/window_sa_commented.BASE.sa

@@ -0,0 +1,79 @@
+module Window_SA
+
+semantic adaptation reactive mealy WindowSA windowSA
+at "./path/to/WindowSA.fmu"
+
+/*
+Reactive means that the unit expects the following treatment:
+Supose the external master is at time t, and that there is an FMU f providing inputs to windowsa.
+Then,
+f.doStep(t, H) // f goes from t->t+H 
+u := f.getValues(...)
+windowsa.setValues(u) // Input provided from the future (t+H)
+windowsa.doStep(t, H) // windowsa goes from t->t+H
+v := windowsa.getValues(...)
+
+Delayed unit means that the unit expects the following treatment:
+Supose the external master is at time t, and that there is an FMU f providing inputs to windowsa.
+Then,
+pu := f.getValues(...)
+f.doStep(t, H) // f goes from t->t+H 
+windowsa.setValues(pu) // Input provided at the time t
+windowsa.doStep(t, H) // windowsa goes from t->t+H and does not need input at time (t+H)
+v := windowsa.getValues(...)
+
+
+Mealy unit means the following:
+windowsa.setValues(v1)  // values set at time t
+o1 = windowsa.getValues() // values set at time t
+assert v2 <> v1 // Assumption
+windowsa.setValues(v2)  // values set at time t
+o2 = windowsa.getValues() // values set at time t
+It is probably the case that o1 <> o2
+
+Moore unit means the following:
+windowsa.setValues(v1)  // values set at time t
+o1 = windowsa.getValues() // values set at time t
+assert v2 <> v1 // Assumption
+windowsa.setValues(v2)  // values set at time t
+o2 = windowsa.getValues() // values set at time t
+It must be the case that o1 == o2
+In other words, the output at time t, only depends on the state at time t.
+*/
+
+	
+	/*
+	The definition for the wrapped FMU is now done here.
+	This is because, for adaptations that wrap multiple FMUs as well as other adaptations, the connection information cannot be fully completed in the senario description (see the window_obstacle.sa example).
+	*/
+	for inner fmu Window window
+		at "./path/to/WindowSA.fmu"
+		with input ports displacement (rad), speed (rad/s), reaction_force (N)
+		with output ports height (cm), reaction_torque (N.m)
+
+/*
+No need to have input ports declared for this model.
+Every input port of the original FMU will be automatically assumed to be an input port of the adapted FMU.
+
+If there is an input port window.p which is dangling, but is not declared here, then an input port windowsa.p will be created in the adapted FMU, and we will have that window.p -> windowsa.p.
+*/
+
+/*
+Declares two output ports, and specified how height is mapped to disp.
+Here, the units need to be specified, so that the conversion can take place.
+The units of disp can be either obtained from the scenario, or specified explicitly here.
+*/
+output ports disp (m)  <- height, tau
+/*
+There are alternative ways that this can be interpreted:
+disp  := arbitrary_function(height) * 100 or arbitrary_function(height * 100) (they are not necessarily equal)
+We pick the first one, so what we have is this:
+aux_var := arbitrary_function(height);
+disp := aux_var*100; // This part never has to be coded.
+*/
+
+out rules {
+	true -> {} --> {
+		tau := -reaction_force;
+	};
+}

+ 17 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/input/power_window_case_study/window_sa_comp_units.sa

@@ -0,0 +1,17 @@
+semantic adaptation reactive mealy WindowSA windowSA
+at "./path/to/WindowSA.fmu"
+
+	for inner fmu Window window
+		at "./path/to/Window.fmu"
+		with input ports displacement(rad), speed (rad/s), reaction_force (N)
+		with output ports height (cm), reaction_torque (N.m)
+
+output ports disp  <- window.height, tau (N)
+
+out rules {
+	true -> {} --> {
+		windowSA.tau := -window.reaction_force;
+	};
+}
+
+

+ 68 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests/pom.xml

@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<relativePath>../pom.xml</relativePath>
+		<groupId>be.uantwerpen.ansymo.semanticadaptation</groupId>
+		<artifactId>parent</artifactId>
+		<version>1.0.0-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests</artifactId>
+	<packaging>eclipse-test-plugin</packaging>
+
+	<name>be.uantwerpen.ansymo.semanticadaptation Code Generation to C++ Tests</name>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-clean-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>gen-clean</id>
+						<phase>clean</phase>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.eclipse.xtend</groupId>
+				<artifactId>xtend-maven-plugin</artifactId>
+			</plugin>
+
+
+			<plugin>
+				<!-- Remember that these tests only run in integration so between package 
+					and install http://www.vogella.com/tutorials/EclipseTycho/article.html -->
+				<groupId>org.eclipse.tycho</groupId>
+				<artifactId>tycho-surefire-plugin</artifactId>
+				<version>${tycho.version}</version>
+				<configuration>
+					<useUIHarness>false</useUIHarness>
+					<useUIThread>false</useUIThread>
+				</configuration>
+			</plugin>
+
+			<!-- plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> 
+				<executions> <execution> <id>copy</id> <phase>pre-integration-test</phase> 
+				<goals> <goal>copy</goal> </goals> <configuration> <artifactItems> <artifactItem> 
+				<groupId>be.uantwerpen.ansymo.semanticadaptation</groupId> <artifactId>be.uantwerpen.ansymo.semanticadaptation.cg.cpp.lib</artifactId> 
+				<type>jar</type> <version>${project.version}</version> <overWrite>true</overWrite> 
+				<destFileName>cppFramework.jar</destFileName> </artifactItem> </artifactItems> 
+				<outputDirectory>${project.basedir}/jars</outputDirectory> <overWriteReleases>false</overWriteReleases> 
+				<overWriteSnapshots>false</overWriteSnapshots> <overWriteIfNewer>true</overWriteIfNewer> 
+				</configuration> </execution> </executions> </plugin -->
+
+				<plugin>
+					<groupId>org.apache.maven.plugins</groupId>
+					<artifactId>maven-surefire-plugin</artifactId>
+					<configuration>
+						<!-- the tests use std out a lot so we dont want that in the console -->
+						<redirectTestOutputToFile>true</redirectTestOutputToFile>
+
+					</configuration>
+				</plugin>
+		</plugins>
+	</build>
+</project>

+ 15 - 4
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.tests/src/be/uantwerpen/ansymo/semanticadaptation/tests/SemanticAdaptationGeneratorTest.xtend

@@ -1,8 +1,9 @@
 /*
  * generated by Xtext 2.10.0
  */
-package be.uantwerpen.ansymo.semanticadaptation.tests
+package be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests
 
+import be.uantwerpen.ansymo.semanticadaptation.cg.canonical.SemanticAdaptationCanonicalGenerator
 import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Adaptation
 import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Assignment
 import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.AtomicUnity
@@ -17,9 +18,14 @@ import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Port
 import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.SemanticAdaptation
 import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.SingleVarDeclaration
 import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Variable
+import be.uantwerpen.ansymo.semanticadaptation.tests.AbstractSemanticAdaptationTest
+import be.uantwerpen.ansymo.semanticadaptation.tests.SemanticAdaptationInjectorProvider
 import com.google.inject.Inject
+import org.eclipse.emf.common.util.URI
+import org.eclipse.xtext.generator.InMemoryFileSystemAccess
 import org.eclipse.xtext.testing.InjectWith
 import org.eclipse.xtext.testing.XtextRunner
+import org.eclipse.xtext.testing.util.ParseHelper
 import org.eclipse.xtext.util.IAcceptor
 import org.eclipse.xtext.xbase.testing.CompilationTestHelper
 import org.eclipse.xtext.xbase.testing.CompilationTestHelper.Result
@@ -31,9 +37,10 @@ import org.junit.runner.RunWith
 @InjectWith(SemanticAdaptationInjectorProvider)
 class SemanticAdaptationGeneratorTest extends AbstractSemanticAdaptationTest{
 	
-	@Inject extension CompilationTestHelper
+	@Inject extension ParseHelper<SemanticAdaptation>
 	
-	@Test def test_inferTypesAndUnits_sample1() { __generate('input/canonical_generation/sample1.sa', new IAcceptor<CompilationTestHelper.Result>(){
+	@Test def test_inferTypesAndUnits_sample1() { 
+		__generate('input/canonical_generation/sample1.sa', new IAcceptor<CompilationTestHelper.Result>(){
 			override accept(Result t) {
 				var Adaptation sa = t.resourceSet.resources.head.allContents.toIterable.filter(SemanticAdaptation).last.elements.filter(Adaptation).head
 				Assert.assertTrue(sa.name == "outerFMU")
@@ -220,7 +227,11 @@ class SemanticAdaptationGeneratorTest extends AbstractSemanticAdaptationTest{
 	def void __generate(String filename, IAcceptor<CompilationTestHelper.Result> acceptor) {
 		//readFile(filename).assertCompilesTo('oracles/power_window_case_study/lazy.BASE.sa')
 		
-		readFile(filename).compile(acceptor)
+		val adaptation = readFile(filename).parse
+		val fileUri = URI.createFileURI(filename)
+		val fsa = new InMemoryFileSystemAccess();
+		val generator = new SemanticAdaptationCanonicalGenerator();
 		
+		generator.doGenerate(adaptation.elements.filter(Adaptation).head, fsa, fileUri);
 	}
 }

+ 5 - 3
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.cg.chain/META-INF/MANIFEST.MF

@@ -6,6 +6,8 @@ Bundle-Version: 1.0.0.qualifier
 Bundle-SymbolicName: be.uantwerpen.ansymo.semanticadaptation.cg.chain;singleton:=true
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: be.uantwerpen.ansymo.semanticadaptation.cg.canonical,
- be.uantwerpen.ansymo.semanticadaptation.log
-Require-Bundle: be.uantwerpen.ansymo.semanticadaptation;bundle-version="1.0.0"
+Import-Package: be.uantwerpen.ansymo.semanticadaptation.log
+Require-Bundle: be.uantwerpen.ansymo.semanticadaptation;bundle-version="1.0.0",
+ be.uantwerpen.ansymo.semanticadaptation.cg.canonical;bundle-version="1.0.0",
+ org.eclipse.xtext.generator;bundle-version="2.11.0",
+ org.eclipse.emf.common.source;bundle-version="2.12.0"

+ 0 - 1
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.tests/pom.xml

@@ -33,7 +33,6 @@
 				<artifactId>xtend-maven-plugin</artifactId>
 			</plugin>
 
-
 			<plugin>
 				<!-- Remember that these tests only run in integration so between package and install http://www.vogella.com/tutorials/EclipseTycho/article.html -->
 				<groupId>org.eclipse.tycho</groupId>

+ 0 - 39
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.tests/src/be/uantwerpen/ansymo/semanticadaptation/tests/AbstractSemanticAdaptationGeneratorTest.xtend

@@ -1,39 +0,0 @@
-/*
- * generated by Xtext 2.10.0
- */
-package be.uantwerpen.ansymo.semanticadaptation.tests
-
-import com.google.inject.Inject
-import org.eclipse.xtext.generator.IGenerator2
-import org.junit.Assert
-import org.eclipse.xtext.generator.InMemoryFileSystemAccess
-import org.eclipse.xtext.generator.IFileSystemAccess
-import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.SemanticAdaptation
-
-abstract class AbstractSemanticAdaptationGeneratorTest extends AbstractSemanticAdaptationParserTest {
-
-	@Inject IGenerator2 generator
-	
-	InMemoryFileSystemAccess fsa = new InMemoryFileSystemAccess()
-	
-	/**
-	 * Generates an output file in the file system using the DSL's code generation
-	 */
-	def void generateOutputFile(SemanticAdaptation root) {
-		//println(root.statements)
-		//println(root.imports)
-		generator.doGenerate(root.eResource, this.fsa, null)
-	}
-	
-	/**
-	 * Compares a given file in memory to the given oracle file
-	 */
-	def void compareFiles(String inmemoryfilename, String oraclefilename) {
-		//println(this.fsa.allFiles)
-		Assert.assertTrue(inmemoryfilename + " not found", this.fsa.allFiles.containsKey(inmemoryfilename))
-		val actualtext = fsa.allFiles.get(inmemoryfilename)
-		val expectedtext = readFile('oracles/'+oraclefilename)
-		Assert.assertEquals(expectedtext, actualtext)
-	}
-
-}

+ 89 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation/src/be/uantwerpen/ansymo/semanticadaptation/generator/SemanticAdaptationGenerator.xtend

@@ -0,0 +1,89 @@
+/*
+ * generated by Xtext 2.10.0
+ */
+package be.uantwerpen.ansymo.semanticadaptation.generator
+
+import be.uantwerpen.ansymo.semanticadaptation.log.Log
+import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Adaptation
+import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.SemanticAdaptation
+import org.eclipse.core.runtime.IExtensionPoint
+import org.eclipse.core.runtime.IExtensionRegistry
+import org.eclipse.core.runtime.Platform
+import org.eclipse.emf.ecore.resource.Resource
+import org.eclipse.xtext.generator.AbstractGenerator
+import org.eclipse.xtext.generator.IFileSystemAccess2
+import org.eclipse.xtext.generator.IGeneratorContext
+
+/**
+ * Generates code from your model files on save.
+ * 
+ * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation
+ */
+class SemanticAdaptationGenerator extends AbstractGenerator {
+
+	override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
+		Log.push("Generating canonical semantic adaptation for file " + resource.URI + "...")
+		
+		Log.println("Resource URI information:")
+		Log.println("\t resource.URI.lastSegment = " + resource.URI.lastSegment())
+		Log.println("\t resource.URI.trimFileExtension = " + resource.URI.trimFileExtension())
+		
+		val chainGenerator = loadSemanticAdaptationCustomGenerator()
+		
+		// Create in memory representation of canonical SA file
+		var adaptations = resource.allContents.toIterable.filter(SemanticAdaptation).last.elements.filter(Adaptation);
+		
+		check(adaptations.size == 1, "Only one semantic adaptation is supported per .sa file")
+		
+		var adaptation = adaptations.head
+		
+		chainGenerator.generate(adaptation, fsa, resource.URI)
+		
+		Log.pop("Generating canonical semantic adaptation for file " + resource.URI + "...")
+	}
+	
+	def SemanticAdaptationCustomGenerator loadSemanticAdaptationCustomGenerator() {
+		Log.push("loadSemanticAdaptationCustomGenerator")
+		
+		val IExtensionRegistry registry = Platform.getExtensionRegistry();
+		val IExtensionPoint point = registry.getExtensionPoint("be.uantwerpen.ansymo.semanticadaptation.generator_extension");
+		if (point === null) {
+			Log.println("Extension point be_uantwerpen_ansymo_semanticadaptation_generator must be provided.")
+			throw new Exception("Extension point be_uantwerpen_ansymo_semanticadaptation_generator must be provided.");
+		}
+		Log.println("Extension point found.")
+		var chainExtension = point.getExtension("be.uantwerpen.ansymo.semanticadaptation.cg.chain.chain_generator_extension")
+		if (chainExtension === null) {
+			throw new Exception("An extension called chain_generator_extension must be provided to Extension Point be.uantwerpen.ansymo.semanticadaptation.generator_extension.");
+		}
+		Log.println("Extension to extension point found.")
+		
+		val configElement = chainExtension.configurationElements.head
+		if (configElement === null) {
+			throw new Exception("Configuration element not found.");
+		}
+		
+		val obj = configElement.createExecutableExtension("class")
+		if (obj === null) {
+			throw new Exception("Class attribute of extension not proper java class.");
+		}
+		if (!(obj instanceof SemanticAdaptationCustomGenerator)) {
+			throw new Exception("Instance of SemanticAdaptationCustomGenerator expected. Found " + obj.class);
+		}
+		
+		Log.println("Instance of SemanticAdaptationCustomGenerator found.")
+		
+		val chainGenerator = obj as SemanticAdaptationCustomGenerator
+		
+		Log.pop("loadSemanticAdaptationCustomGenerator")
+		return chainGenerator
+	}
+	
+	
+	def check(Boolean condition, String msg){
+		if (! condition){
+			throw new Exception("Assertion error: " + msg)
+		}
+	}
+	
+}

+ 1 - 0
DSL_SemanticAdaptation/pom.xml

@@ -23,6 +23,7 @@
 		<module>be.uantwerpen.ansymo.semanticadaptation.cg.cpp</module>
 		<module>be.uantwerpen.ansymo.semanticadaptation.cg.canonical</module>
 	  <module>be.uantwerpen.ansymo.semanticadaptation.cg.cpp.tests</module>
+		<module>be.uantwerpen.ansymo.semanticadaptation.cg.canonical.tests</module>
  <module>features</module>
  <module>repository</module>
 	</modules>