Browse Source

feedthrough constraints implemented, and corresponding hierarchical propagation

Claudio Gomes 6 years ago
parent
commit
7562b6c7d8

+ 2 - 1
HintCOEngine/examples/case_study_double_loop_approx_cpint.xmi

@@ -4,7 +4,8 @@
       identifier="Original"
       stopTime="5.0"
       stepSize="1.0E-5"
-      outputStepSize="0.01">
+      outputStepSize="0.01"
+      maxInitIterations="10">
     <cosimunits
         xsi:type="hintco:CosimUnitInstance"
         identifier="Scenario"

+ 12 - 12
HintCOEngine/instances/add_constraints_test.hintco

@@ -1,29 +1,29 @@
 <?xml version="1.0" encoding="ASCII"?>
-<hintco:HintConfiguration xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:hintco="ua.ansymo.hintco">
+<hintco:HintConfiguration xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:hintco="ua.ansymo.hintco">
   <candidates identifier="R" stopTime="2.0" stepSize="0.001" outputStepSize="0.001">
     <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="A">
       <ports xsi:type="hintco:OutputPortInstance" identifier="Aop" valueTo="//@candidates.0/@cosimunits.1/@ports.0"/>
     </cosimunits>
     <cosimunits xsi:type="hintco:HierarchicalCosimUnit" identifier="B">
-      <ports xsi:type="hintco:HierarchicalUnitPort" identifier="Bip" valueFrom="//@candidates.0/@cosimunits.0/@ports.0" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.0"/>
-      <ports xsi:type="hintco:HierarchicalUnitPort" identifier="Bop" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.1/@ports.0" valueTo="//@candidates.0/@cosimunits.2/@ports.0"/>
       <cosimunits xsi:type="hintco:HierarchicalCosimUnit" identifier="B2">
-        <ports xsi:type="hintco:HierarchicalUnitPort" identifier="B2ip1" valueFrom="//@candidates.0/@cosimunits.1/@ports.0" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@cosimunits.0/@ports.0"/>
-        <ports xsi:type="hintco:HierarchicalUnitPort" identifier="B2ip2" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.1/@ports.1" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@cosimunits.0/@ports.1"/>
-        <ports xsi:type="hintco:HierarchicalUnitPort" identifier="B2op" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@cosimunits.0/@ports.2" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.1/@ports.2"/>
         <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="B21">
-          <ports xsi:type="hintco:InputPortInstance" identifier="B21ip1" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.0">
-            <adaptation xsi:type="hintco:ExtrapolationAdaptation"/>
-          </ports>
+          <ports xsi:type="hintco:InputPortInstance" identifier="B21ip1" internalValueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@cosimunits.0/@ports.2" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.0"/>
           <ports xsi:type="hintco:InputPortInstance" identifier="B21ip2" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.1"/>
-          <ports xsi:type="hintco:OutputPortInstance" identifier="B21op" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.2"/>
+          <ports xsi:type="hintco:OutputPortInstance" identifier="B21op" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.2" internalValueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@cosimunits.0/@ports.0"/>
         </cosimunits>
+        <ports xsi:type="hintco:HierarchicalUnitPort" identifier="B2ip1" valueFrom="//@candidates.0/@cosimunits.1/@ports.0" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@cosimunits.0/@ports.0"/>
+        <ports xsi:type="hintco:HierarchicalUnitPort" identifier="B2ip2" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.1/@ports.1" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@cosimunits.0/@ports.1"/>
+        <ports xsi:type="hintco:HierarchicalUnitPort" identifier="B2op" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@cosimunits.0/@ports.2" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.1/@ports.2"/>
       </cosimunits>
       <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="B1">
-        <ports xsi:type="hintco:OutputPortInstance" identifier="B1op1" valueTo="//@candidates.0/@cosimunits.1/@ports.1"/>
+        <ports xsi:type="hintco:OutputPortInstance" identifier="B1op1" valueTo="//@candidates.0/@cosimunits.1/@ports.1" internalValueFrom="//@candidates.0/@cosimunits.1/@cosimunits.1/@ports.2"/>
         <ports xsi:type="hintco:OutputPortInstance" identifier="B1op2" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.1"/>
-        <ports xsi:type="hintco:InputPortInstance" identifier="B1ip" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.2"/>
+        <ports xsi:type="hintco:InputPortInstance" identifier="B1ip" internalValueTo="//@candidates.0/@cosimunits.1/@cosimunits.1/@ports.0" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.2">
+          <adaptation xsi:type="hintco:ExtrapolationAdaptation"/>
+        </ports>
       </cosimunits>
+      <ports xsi:type="hintco:HierarchicalUnitPort" identifier="Bip" valueFrom="//@candidates.0/@cosimunits.0/@ports.0" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.0"/>
+      <ports xsi:type="hintco:HierarchicalUnitPort" identifier="Bop" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.1/@ports.0" valueTo="//@candidates.0/@cosimunits.2/@ports.0"/>
     </cosimunits>
     <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="C">
       <ports xsi:type="hintco:InputPortInstance" identifier="Cip" valueFrom="//@candidates.0/@cosimunits.1/@ports.1">

+ 34 - 0
HintCOEngine/instances/add_constraints_test_inter.hintco

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="ASCII"?>
+<hintco:HintConfiguration xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:hintco="ua.ansymo.hintco">
+  <candidates identifier="R" stopTime="2.0" stepSize="0.001" outputStepSize="0.001">
+    <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="A">
+      <ports xsi:type="hintco:OutputPortInstance" identifier="Aop" valueTo="//@candidates.0/@cosimunits.1/@ports.0"/>
+    </cosimunits>
+    <cosimunits xsi:type="hintco:HierarchicalCosimUnit" identifier="B">
+      <cosimunits xsi:type="hintco:HierarchicalCosimUnit" identifier="B2">
+        <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="B21">
+          <ports xsi:type="hintco:InputPortInstance" identifier="B21ip1" internalValueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@cosimunits.0/@ports.2" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.0"/>
+          <ports xsi:type="hintco:InputPortInstance" identifier="B21ip2" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.1"/>
+          <ports xsi:type="hintco:OutputPortInstance" identifier="B21op" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.2" internalValueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@cosimunits.0/@ports.0"/>
+        </cosimunits>
+        <ports xsi:type="hintco:HierarchicalUnitPort" identifier="B2ip1" valueFrom="//@candidates.0/@cosimunits.1/@ports.0" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@cosimunits.0/@ports.0"/>
+        <ports xsi:type="hintco:HierarchicalUnitPort" identifier="B2ip2" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.1/@ports.1" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@cosimunits.0/@ports.1"/>
+        <ports xsi:type="hintco:HierarchicalUnitPort" identifier="B2op" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@cosimunits.0/@ports.2" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.1/@ports.2"/>
+      </cosimunits>
+      <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="B1">
+        <ports xsi:type="hintco:OutputPortInstance" identifier="B1op1" valueTo="//@candidates.0/@cosimunits.1/@ports.1" internalValueFrom="//@candidates.0/@cosimunits.1/@cosimunits.1/@ports.2"/>
+        <ports xsi:type="hintco:OutputPortInstance" identifier="B1op2" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.1"/>
+        <ports xsi:type="hintco:InputPortInstance" identifier="B1ip" internalValueTo="//@candidates.0/@cosimunits.1/@cosimunits.1/@ports.0" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.2">
+          <adaptation xsi:type="hintco:InterpolationAdaptation"/>
+        </ports>
+      </cosimunits>
+      <ports xsi:type="hintco:HierarchicalUnitPort" identifier="Bip" valueFrom="//@candidates.0/@cosimunits.0/@ports.0" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.0"/>
+      <ports xsi:type="hintco:HierarchicalUnitPort" identifier="Bop" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.1/@ports.0" valueTo="//@candidates.0/@cosimunits.2/@ports.0"/>
+    </cosimunits>
+    <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="C">
+      <ports xsi:type="hintco:InputPortInstance" identifier="Cip" valueFrom="//@candidates.0/@cosimunits.1/@ports.1">
+        <adaptation xsi:type="hintco:ExtrapolationAdaptation"/>
+      </ports>
+    </cosimunits>
+  </candidates>
+</hintco:HintConfiguration>

+ 38 - 0
HintCOEngine/instances/complex_order_hierarchical_test_feedthrough.hintco

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="ASCII"?>
+<hintco:HintConfiguration xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:hintco="ua.ansymo.hintco">
+  <candidates identifier="R" stopTime="2.0" stepSize="0.001" outputStepSize="0.001">
+    <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="A">
+      <ports xsi:type="hintco:OutputPortInstance" identifier="Aop" valueTo="//@candidates.0/@cosimunits.1/@ports.0"/>
+    </cosimunits>
+    <cosimunits xsi:type="hintco:HierarchicalCosimUnit" identifier="B">
+      <ports xsi:type="hintco:HierarchicalUnitPort" identifier="Bip" valueFrom="//@candidates.0/@cosimunits.0/@ports.0" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.0"/>
+      <ports xsi:type="hintco:HierarchicalUnitPort" identifier="Bop" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.1/@ports.0" valueTo="//@candidates.0/@cosimunits.2/@ports.0"/>
+      <cosimunits xsi:type="hintco:HierarchicalCosimUnit" identifier="B2">
+        <ports xsi:type="hintco:HierarchicalUnitPort" identifier="B2ip1" valueFrom="//@candidates.0/@cosimunits.1/@ports.0" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@cosimunits.0/@ports.0"/>
+        <ports xsi:type="hintco:HierarchicalUnitPort" identifier="B2ip2" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.1/@ports.1" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@cosimunits.0/@ports.1">
+          <adaptation xsi:type="hintco:InterpolationAdaptation"/>
+        </ports>
+        <ports xsi:type="hintco:HierarchicalUnitPort" identifier="B2op" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@cosimunits.0/@ports.2" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.1/@ports.2"/>
+        <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="B21">
+          <ports xsi:type="hintco:InputPortInstance" identifier="B21ip1" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.0">
+            <adaptation xsi:type="hintco:ExtrapolationAdaptation"/>
+          </ports>
+          <ports xsi:type="hintco:InputPortInstance" identifier="B21ip2" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.1"/>
+          <ports xsi:type="hintco:OutputPortInstance" identifier="B21op" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.2"/>
+        </cosimunits>
+      </cosimunits>
+      <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="B1">
+        <ports xsi:type="hintco:OutputPortInstance" identifier="B1op1" valueTo="//@candidates.0/@cosimunits.1/@ports.1"/>
+        <ports xsi:type="hintco:OutputPortInstance" identifier="B1op2" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.1"/>
+        <ports xsi:type="hintco:InputPortInstance" identifier="B1ip" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.2">
+          <adaptation xsi:type="hintco:ExtrapolationAdaptation"/>
+        </ports>
+      </cosimunits>
+    </cosimunits>
+    <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="C">
+      <ports xsi:type="hintco:InputPortInstance" identifier="Cip" valueFrom="//@candidates.0/@cosimunits.1/@ports.1">
+        <adaptation xsi:type="hintco:InterpolationAdaptation"/>
+      </ports>
+    </cosimunits>
+  </candidates>
+</hintco:HintConfiguration>

+ 18 - 18
HintCOEngine/instances/generated/generate_variants_infeasible_interpolation_test.xmi

@@ -1,36 +1,36 @@
 <?xml version="1.0" encoding="ASCII"?>
 <hintco:HintConfiguration xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:hintco="ua.ansymo.hintco" root="//@nodes.0">
   <candidates identifier="Original" selected="true">
-    <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="Scenario" declaration="//@csuDeclarations.0">
-      <ports xsi:type="hintco:OutputPortInstance" precedes="//@candidates.0/@cosimunits.2/@ports.1" identifier="psuvolt" valueTo="//@candidates.0/@cosimunits.2/@ports.1"/>
-      <ports xsi:type="hintco:OutputPortInstance" precedes="//@candidates.0/@cosimunits.1/@ports.2" identifier="ref" valueTo="//@candidates.0/@cosimunits.1/@ports.2"/>
+    <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="Scenario" precedes="//@candidates.0/@cosimunits.0/@ports.0 //@candidates.0/@cosimunits.0/@ports.1" declaration="//@csuDeclarations.0">
+      <ports xsi:type="hintco:OutputPortInstance" precedes="//@candidates.0/@cosimunits.2/@ports.1" succeeds="//@candidates.0/@cosimunits.0" identifier="psuvolt" valueTo="//@candidates.0/@cosimunits.2/@ports.1"/>
+      <ports xsi:type="hintco:OutputPortInstance" precedes="//@candidates.0/@cosimunits.1/@ports.2" succeeds="//@candidates.0/@cosimunits.0" identifier="ref" valueTo="//@candidates.0/@cosimunits.1/@ports.2"/>
     </cosimunits>
-    <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="DLoopController_FixedEuler_1Em6" succeeds="//@candidates.0/@cosimunits.1/@ports.0 //@candidates.0/@cosimunits.1/@ports.1 //@candidates.0/@cosimunits.1/@ports.2" declaration="//@csuDeclarations.1">
-      <ports xsi:type="hintco:InputPortInstance" precedes="//@candidates.0/@cosimunits.1" succeeds="//@candidates.0/@cosimunits.2/@ports.4" identifier="VEL_FB@expseu_" valueFrom="//@candidates.0/@cosimunits.2/@ports.4"/>
-      <ports xsi:type="hintco:InputPortInstance" precedes="//@candidates.0/@cosimunits.1" succeeds="//@candidates.0/@cosimunits.3/@ports.1" identifier="POS_FB@expseu_" valueFrom="//@candidates.0/@cosimunits.3/@ports.1"/>
-      <ports xsi:type="hintco:InputPortInstance" precedes="//@candidates.0/@cosimunits.1" succeeds="//@candidates.0/@cosimunits.0/@ports.1" identifier="REFERENCE@expseu_" valueFrom="//@candidates.0/@cosimunits.0/@ports.1"/>
-      <ports xsi:type="hintco:OutputPortInstance" precedes="//@candidates.0/@cosimunits.2/@ports.0" identifier="OUTPUT@expseu_" valueTo="//@candidates.0/@cosimunits.2/@ports.0"/>
+    <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="DLoopController_FixedEuler_1Em6" precedes="//@candidates.0/@cosimunits.1/@ports.3" declaration="//@csuDeclarations.1">
+      <ports xsi:type="hintco:InputPortInstance" succeeds="//@candidates.0/@cosimunits.2/@ports.4" identifier="VEL_FB@expseu_" valueFrom="//@candidates.0/@cosimunits.2/@ports.4"/>
+      <ports xsi:type="hintco:InputPortInstance" succeeds="//@candidates.0/@cosimunits.3/@ports.1" identifier="POS_FB@expseu_" valueFrom="//@candidates.0/@cosimunits.3/@ports.1"/>
+      <ports xsi:type="hintco:InputPortInstance" succeeds="//@candidates.0/@cosimunits.0/@ports.1" identifier="REFERENCE@expseu_" valueFrom="//@candidates.0/@cosimunits.0/@ports.1"/>
+      <ports xsi:type="hintco:OutputPortInstance" precedes="//@candidates.0/@cosimunits.2/@ports.0" succeeds="//@candidates.0/@cosimunits.1" identifier="OUTPUT@expseu_" valueTo="//@candidates.0/@cosimunits.2/@ports.0"/>
     </cosimunits>
-    <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="EMAPlantNoLoad_FixedEuler_1Em6" succeeds="//@candidates.0/@cosimunits.2/@ports.0 //@candidates.0/@cosimunits.2/@ports.1 //@candidates.0/@cosimunits.2/@ports.2 //@candidates.0/@cosimunits.2/@ports.3 //@candidates.0/@cosimunits.3/@ports.0" declaration="//@csuDeclarations.2">
-      <ports xsi:type="hintco:InputPortInstance" precedes="//@candidates.0/@cosimunits.2" succeeds="//@candidates.0/@cosimunits.1/@ports.3" identifier="torque_input@expseu_" valueFrom="//@candidates.0/@cosimunits.1/@ports.3"/>
-      <ports xsi:type="hintco:InputPortInstance" precedes="//@candidates.0/@cosimunits.2" succeeds="//@candidates.0/@cosimunits.0/@ports.0" identifier="psu_vol_input_v@expseu_" valueFrom="//@candidates.0/@cosimunits.0/@ports.0"/>
+    <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="EMAPlantNoLoad_FixedEuler_1Em6" precedes="//@candidates.0/@cosimunits.2/@ports.4 //@candidates.0/@cosimunits.2/@ports.5" succeeds="//@candidates.0/@cosimunits.2/@ports.2" declaration="//@csuDeclarations.2">
+      <ports xsi:type="hintco:InputPortInstance" succeeds="//@candidates.0/@cosimunits.1/@ports.3" identifier="torque_input@expseu_" valueFrom="//@candidates.0/@cosimunits.1/@ports.3"/>
+      <ports xsi:type="hintco:InputPortInstance" succeeds="//@candidates.0/@cosimunits.0/@ports.0" identifier="psu_vol_input_v@expseu_" valueFrom="//@candidates.0/@cosimunits.0/@ports.0"/>
       <ports xsi:type="hintco:InputPortInstance" precedes="//@candidates.0/@cosimunits.2" succeeds="//@candidates.0/@cosimunits.3/@ports.2" identifier="V_IN@expseu_" valueFrom="//@candidates.0/@cosimunits.3/@ports.2">
         <adaptation xsi:type="hintco:InterpolationAdaptation" weight="10" selected="true"/>
       </ports>
-      <ports xsi:type="hintco:InputPortInstance" precedes="//@candidates.0/@cosimunits.2" succeeds="//@candidates.0/@cosimunits.3/@ports.3" identifier="X_IN@expseu_" valueFrom="//@candidates.0/@cosimunits.3/@ports.3"/>
-      <ports xsi:type="hintco:OutputPortInstance" precedes="//@candidates.0/@cosimunits.1/@ports.0" identifier="ang_vel_out_rpm@expseu_" valueTo="//@candidates.0/@cosimunits.1/@ports.0"/>
-      <ports xsi:type="hintco:OutputPortInstance" precedes="//@candidates.0/@cosimunits.3/@ports.0" identifier="F_OUT@expseu_" valueTo="//@candidates.0/@cosimunits.3/@ports.0"/>
+      <ports xsi:type="hintco:InputPortInstance" succeeds="//@candidates.0/@cosimunits.3/@ports.3" identifier="X_IN@expseu_" valueFrom="//@candidates.0/@cosimunits.3/@ports.3"/>
+      <ports xsi:type="hintco:OutputPortInstance" precedes="//@candidates.0/@cosimunits.1/@ports.0" succeeds="//@candidates.0/@cosimunits.2" identifier="ang_vel_out_rpm@expseu_" valueTo="//@candidates.0/@cosimunits.1/@ports.0"/>
+      <ports xsi:type="hintco:OutputPortInstance" precedes="//@candidates.0/@cosimunits.3/@ports.0" succeeds="//@candidates.0/@cosimunits.2" identifier="F_OUT@expseu_" valueTo="//@candidates.0/@cosimunits.3/@ports.0"/>
     </cosimunits>
-    <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="LoadNSensor_FixedEuler_1Em6" precedes="//@candidates.0/@cosimunits.3/@ports.2" succeeds="//@candidates.0/@cosimunits.3/@ports.0" declaration="//@csuDeclarations.3">
-      <ports xsi:type="hintco:InputPortInstance" precedes="//@candidates.0/@cosimunits.3 //@candidates.0/@cosimunits.2" succeeds="//@candidates.0/@cosimunits.2/@ports.5" identifier="F_INPUT@expseu_" valueFrom="//@candidates.0/@cosimunits.2/@ports.5">
+    <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="LoadNSensor_FixedEuler_1Em6" precedes="//@candidates.0/@cosimunits.3/@ports.1 //@candidates.0/@cosimunits.3/@ports.2 //@candidates.0/@cosimunits.3/@ports.3 //@candidates.0/@cosimunits.3/@ports.0" declaration="//@csuDeclarations.3">
+      <ports xsi:type="hintco:InputPortInstance" succeeds="//@candidates.0/@cosimunits.2/@ports.5 //@candidates.0/@cosimunits.3" identifier="F_INPUT@expseu_" valueFrom="//@candidates.0/@cosimunits.2/@ports.5">
         <adaptation xsi:type="hintco:XorPortAdaptation" selected="true">
           <children xsi:type="hintco:InterpolationAdaptation"/>
           <children xsi:type="hintco:ExtrapolationAdaptation" selected="true"/>
         </adaptation>
       </ports>
-      <ports xsi:type="hintco:OutputPortInstance" precedes="//@candidates.0/@cosimunits.1/@ports.1" identifier="X_AFTER_LOAD@expseu_" valueTo="//@candidates.0/@cosimunits.1/@ports.1"/>
+      <ports xsi:type="hintco:OutputPortInstance" precedes="//@candidates.0/@cosimunits.1/@ports.1" succeeds="//@candidates.0/@cosimunits.3" identifier="X_AFTER_LOAD@expseu_" valueTo="//@candidates.0/@cosimunits.1/@ports.1"/>
       <ports xsi:type="hintco:OutputPortInstance" precedes="//@candidates.0/@cosimunits.2/@ports.2" succeeds="//@candidates.0/@cosimunits.3" identifier="V_OUTPUT@expseu_" valueTo="//@candidates.0/@cosimunits.2/@ports.2"/>
-      <ports xsi:type="hintco:OutputPortInstance" precedes="//@candidates.0/@cosimunits.2/@ports.3" identifier="X_OUTPUT@expseu_" valueTo="//@candidates.0/@cosimunits.2/@ports.3"/>
+      <ports xsi:type="hintco:OutputPortInstance" precedes="//@candidates.0/@cosimunits.2/@ports.3" succeeds="//@candidates.0/@cosimunits.3" identifier="X_OUTPUT@expseu_" valueTo="//@candidates.0/@cosimunits.2/@ports.3"/>
     </cosimunits>
   </candidates>
   <csuDeclarations identifier="Scenario"/>

+ 14 - 15
HintCOEngine/instances/interpolation_test.xmi

@@ -1,22 +1,26 @@
 <?xml version="1.0" encoding="ASCII"?>
-<hintco:HintConfiguration xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:hintco="ua.ansymo.hintco">
+<hintco:HintConfiguration
+    xmi:version="2.0"
+    xmlns:xmi="http://www.omg.org/XMI"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:hintco="ua.ansymo.hintco">
   <candidates
       identifier="Scenario"
       stopTime="10.0"
       stepSize="1.0"
-      outputStepSize="1.0">
-    <cosimunits
- xsi:type="hintco:CosimUnitInstance"
+      outputStepSize="1.0"
+      maxInitIterations="10">
+    <cosimunits
+        xsi:type="hintco:CosimUnitInstance"
         identifier="Source"
         declaration="//@csuDeclarations.0">
       <ports
           xsi:type="hintco:OutputPortInstance"
           identifier="out"
-          valueTo="//@candidates.0/@cosimunits.1/@ports.0"
-          />
+          valueTo="//@candidates.0/@cosimunits.1/@ports.0"/>
     </cosimunits>
-    <cosimunits
- xsi:type="hintco:CosimUnitInstance"
+    <cosimunits
+        xsi:type="hintco:CosimUnitInstance"
         identifier="Sink"
         declaration="//@csuDeclarations.1">
       <adaptation
@@ -25,7 +29,6 @@
       <ports
           xsi:type="hintco:InputPortInstance"
           identifier="in"
-
           valueFrom="//@candidates.0/@cosimunits.0/@ports.0">
         <adaptation
             xsi:type="hintco:InterpolationAdaptation"
@@ -36,13 +39,9 @@
   <csuDeclarations
       identifier="Source"
       path="resources/Scenario.fmu"
-      guid="{a174734c-d15f-4ef0-838d-06526230b19e}">
-
-  </csuDeclarations>
+      guid="{a174734c-d15f-4ef0-838d-06526230b19e}"/>
   <csuDeclarations
       identifier="Sink"
       path="resources/DLoopController_FixedEuler_1Em6.fmu"
-      guid="2761528305">
-
-  </csuDeclarations>
+      guid="2761528305"/>
 </hintco:HintConfiguration>

+ 18 - 0
HintCOEngine/instances/propagate_constraints_test.hintco

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="ASCII"?>
+<hintco:HintConfiguration xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:hintco="ua.ansymo.hintco">
+  <candidates identifier="R" stopTime="2.0" stepSize="0.001" outputStepSize="0.001">
+    <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="A">
+      <ports xsi:type="hintco:OutputPortInstance" identifier="Aop" valueTo="//@candidates.0/@cosimunits.1/@ports.0"/>
+    </cosimunits>
+    <cosimunits xsi:type="hintco:HierarchicalCosimUnit" identifier="B">
+      <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="b">
+        <ports xsi:type="hintco:InputPortInstance" identifier="bip" internalValueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.1" valueFrom="//@candidates.0/@cosimunits.1/@ports.0">
+          <adaptation xsi:type="hintco:InterpolationAdaptation"/>
+        </ports>
+        <ports xsi:type="hintco:OutputPortInstance" identifier="bop" valueTo="//@candidates.0/@cosimunits.1/@ports.1" internalValueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.0"/>
+      </cosimunits>
+      <ports xsi:type="hintco:HierarchicalUnitPort" identifier="Bip" valueFrom="//@candidates.0/@cosimunits.0/@ports.0" valueTo="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.0"/>
+      <ports xsi:type="hintco:HierarchicalUnitPort" identifier="Bop" valueFrom="//@candidates.0/@cosimunits.1/@cosimunits.0/@ports.1"/>
+    </cosimunits>
+  </candidates>
+</hintco:HintConfiguration>

+ 80 - 71
HintCOEngine/src/ua/ansymo/hintco/CandidatesGenerator.xtend

@@ -8,26 +8,6 @@ import java.util.Set
 import org.eclipse.core.runtime.Assert
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
-import ua.ansymo.hintco.Alternative
-import ua.ansymo.hintco.HintcoFactory
-import ua.ansymo.hintco.CosimUnitInstance
-import ua.ansymo.hintco.DecompositionPortAdaptation
-import ua.ansymo.hintco.DecompositionUnitAdaptation
-import ua.ansymo.hintco.ExtrapolationAdaptation
-import ua.ansymo.hintco.HierarchicalCosimUnit
-import ua.ansymo.hintco.HintConfiguration
-import ua.ansymo.hintco.InputPortInstance
-import ua.ansymo.hintco.InterpolationAdaptation
-import ua.ansymo.hintco.MultiRateAdaptation
-import ua.ansymo.hintco.OutputPortInstance
-import ua.ansymo.hintco.PortAdaptation
-import ua.ansymo.hintco.PortInstance
-import ua.ansymo.hintco.PowerBondAdaptation
-import ua.ansymo.hintco.PrecendenceNode
-import ua.ansymo.hintco.RootCandidateScenario
-import ua.ansymo.hintco.UnitAdaptation
-import ua.ansymo.hintco.UnitInstance
-import ua.ansymo.hintco.VariantDiagram
 
 class CandidatesGenerator {
 	
@@ -48,7 +28,7 @@ class CandidatesGenerator {
 		  * Recursively goes through every path on the variant diagram and creates the necessary precedence constraints, cleaning up after the function call.
 		 Optimizations: check if there is a cycle every time there are a new edge is created. Then abort that function call, as any children of the variant tree will not be valid. Possible paper that addresses this: https://dl.acm.org/citation.cfm?id=1033207
 		 Simple solution is to check if there already is a path connecting those two ports being connected.
-		 Compute transitive closure for quicker reachable computation after adding multiple edges. This result is passed down function calls, and cleaned up as well.
+		 (Not done) Compute transitive closure for quicker reachable computation after adding multiple edges. This result is passed down function calls, and cleaned up as well.
 		 The base case, for now, is to check whether there is a single path passing through all nodes, in a DFS, and return the first such path (mark it on the model, and call semantic adaptation code generation).
 		  */
 		
@@ -139,6 +119,8 @@ class CandidatesGenerator {
 		println()
 	}
 	
+	// TODO: Break this method into multiple methods: generation of contratins, propagation of constraints, etc...
+	// Leave the recursive calls here!
 	def private int recGenerateVariants(Deque<VariantDiagram> ns, 
 										HintConfiguration cs, 
 										ConstraintsStack constraints, int maxVariants) {
@@ -162,40 +144,61 @@ class CandidatesGenerator {
 					 */
 					val scenario = (alternative as RootCandidateScenario)
 					logger.debug("Processing Alternative RootCandidateScenario {}", scenario.identifier)
-					// Outports/HierarchicalPorts -> InPorts/HierarchicalPorts
+					
 					for (outP : scenario.eAllContents.filter(OutputPortInstance).toIterable) {
+						// Create constraints Outports/HierarchicalPorts -> InPorts/HierarchicalPorts
 						for (inP : outP.valueTo) {
 							logger.debug("Attempting to add constraint {}.{}->{}.{}.", outP.unit.identifier, outP.identifier, inP.unit.identifier, inP.identifier)
 							val success = addConstraint(outP, inP, constraints, n, cs)
 							logger.debug("Success: {}", success)
 						}
+						
+						//Create feedthrough constraints:
+						for (inP : outP.internalValueFrom) {
+							logger.debug("Attempting to add constraint {}.{}->{}.{}.", inP.unit.identifier, inP.identifier, outP.unit.identifier, outP.identifier)
+							val success = addConstraint(inP, outP, constraints, n, cs)
+							logger.debug("Success: {}", success)
+						}
 					}
 					
-					// Create I/DoStep constraints: inputs should be set before doStep.
-					for (inP : scenario.eAllContents.filter(InputPortInstance)
-													.filter[it.isInput] // ip can be a hierarchical port, 
-													.toIterable // therefore we need to make sure it is connected to an internal unit. 
-																//Otherwise it is not an input port.
-													
+					// Create constraints between outputs and doStep.
+					// We assume that at the beginning of the cosim step, every input/output is defined. 
+					// Therefore, doStep must be done before getting any output.
+					for (outP : scenario.eAllContents.filter(OutputPortInstance)
+											.filter[! it.isInput] // ip can be a hierarchical port, 
+											.toIterable // therefore we need to make sure it is connected to an internal unit. 
+											//Otherwise it is not an input port.
 					) {
-						logger.debug("Attempting to add constraint {}.{}->{}.", inP.unit.identifier, inP.identifier, inP.unit.identifier)
-						val success = addConstraint(inP, inP.unit, constraints, n, cs)
+						logger.debug("Attempting to add constraint {}->{}.{}.", outP.unit.identifier, outP.unit.identifier, outP.identifier)
+						val success = addConstraint(outP.unit, outP, constraints, n, cs)
 						logger.debug("Success: {}", success)
 					}
 					
-					// The DoStep of each unit can only happen after the doStep of the parent unit.
+					// The DoStep of each child unit must conclude before the doStep of the parent unit concludes
+					// Furthermore, every output operation of a child unit must come before every getout operation of the parent unit.
+					// This, together with the previous set of constraints, ensures that each hierarchical unit's doStep operation is atomic.
 					for (parentUnit : scenario.eAllContents.filter(HierarchicalCosimUnit).toIterable){
+						val parentOutputPorts = parentUnit.outputPorts
 						for (childUnit : parentUnit.cosimunits){
-							logger.debug("Attempting to add constraint {}->{}.", parentUnit.identifier, childUnit.identifier)
-							val success = addConstraint(parentUnit, childUnit, constraints, n, cs)
+							logger.debug("Attempting to add constraint {}->{}.", childUnit.identifier, parentUnit.identifier)
+							val success = addConstraint(childUnit, parentUnit, constraints, n, cs)
 							logger.debug("Success: {}", success)
+							
+							for (childOutP : childUnit.outputPorts){
+								for (parentOutP : parentOutputPorts){
+									// TODO: Use toString method for printing, and move the logging operations to inside a method.
+									logger.debug("Attempting to add constraint {}.{}->{}.{}.", childOutP.unit.identifier, childOutP.identifier, parentOutP.unit.identifier, parentOutP.identifier)
+									val succ = addConstraint(childOutP, parentOutP, constraints, n, cs)
+									logger.debug("Success: {}", succ)
+								}
+							}
 						}
 					}
-					
 				}
 				ExtrapolationAdaptation: {
-					// Add precedence constraints to the ports that provide value to this port.
-					// and ensure the doStep ordering.
+					// In case of an extrapolation on an input, the doStep must be done before setting the input,
+					// because whenever the input is set, it is being set for timestamp t+H.
+
 					val adaptation = alternative as ExtrapolationAdaptation
 					val adapted = adaptation.adapted()
 					logger.debug("Processing Alternative ExtrapolationAdaptation of {}", adapted.identifier)
@@ -203,54 +206,27 @@ class CandidatesGenerator {
 					Assert.isTrue(adapted instanceof InputPortInstance)
 					val adaptedPort = adapted as InputPortInstance
 					Assert.isTrue(adaptedPort.unit instanceof CosimUnitInstance)
-					val srcPort = adaptedPort.realValueFrom
-					
-					val ancestorTriple = ModelQuery.findLeastAncestorScenarioTriple(adaptedPort, srcPort)															
-					val ancestorAdaptedUnit = ancestorTriple.get(1) as UnitInstance
-					val ancestorSrcUnit = ancestorTriple.get(2) as UnitInstance
-					
-					// Redundant, as every port of the unit must be set before do step of the unit.
-					// addConstraint(adaptedPort, adaptedUnit, constraints, n, cs) 
-					// Redundant, as the srcPort is connected to the adaptedPort
-					// addConstraint(srcPort, adaptedPort, constraints, n, cs)
 					
-					var PortInstance siblingAdaptedPort = adaptedPort
-					if (ancestorAdaptedUnit !== adaptedPort.unit) {
-						siblingAdaptedPort = ancestorAdaptedUnit.ports.findFirst[p | adaptedPort.getsValueFrom(p)]						
-					}
-					Assert.isTrue(siblingAdaptedPort !== null)
-					
-					logger.debug("Attempting to add constraint {}.{}->{}.", siblingAdaptedPort.unit.identifier, siblingAdaptedPort.identifier, ancestorSrcUnit.identifier)
-					val success = addConstraint(siblingAdaptedPort, ancestorSrcUnit, constraints, n, cs)
+					logger.debug("Attempting to add constraint {}->{}.{}.", adaptedPort.unit.identifier, adaptedPort.unit.identifier, adaptedPort.identifier)
+					val success = addConstraint(adaptedPort.unit, adaptedPort, constraints, n, cs)
 					logger.debug("Success: {}", success)
+					
 				}
 				InterpolationAdaptation: {
+					// In case of an interpolation on an input, the input must be set before the doStep,
+					// because whenever the input is set, it is being set for timestamp t+H.
+					
 					val adaptation = alternative as InterpolationAdaptation
 					val adapted = adaptation.adapted()
 					logger.debug("Processing Alternative InterpolationAdaptation of {}", adapted.identifier)
 					Assert.isNotNull(adapted)
 					Assert.isTrue(adapted instanceof InputPortInstance)
 					val adaptedPort = adapted as InputPortInstance
-					val srcPort = adaptedPort.realValueFrom
-					val ancestorTriple = ModelQuery.findLeastAncestorScenarioTriple(adaptedPort, srcPort)															
-					val ancestorSrcUnit = ancestorTriple.get(2) as UnitInstance
-					
-					var PortInstance ancestorSrcPort = srcPort
-					if (ancestorSrcUnit !== srcPort.unit) {
-						ancestorSrcPort = ancestorSrcUnit.ports.findFirst[p | adaptedPort.getsValueFrom(p)]
-					}
-					
 					
-					
-					logger.debug("Attempting to add constraint {}->{}.{}.", ancestorSrcUnit.identifier, ancestorSrcPort.unit.identifier, ancestorSrcPort.identifier)
-					val success = addConstraint(ancestorSrcUnit, ancestorSrcPort, constraints, n, cs)
+					logger.debug("Attempting to add constraint {}.{}->{}.{}.", adaptedPort.unit.identifier, adaptedPort.identifier, adaptedPort.unit.identifier)
+					val success = addConstraint(adaptedPort, adaptedPort.unit, constraints, n, cs)
 					logger.debug("Success: {}", success)
 					
-					// Redundant, as the srcPort is connected to the adaptedPort
-					// addConstraint(srcPort, adaptedPort, constraints, n, cs)
-					
-					// Redundant, as every port of the unit must be set before do step of the unit.
-					// addConstraint(adaptedPort, adaptedUnit, constraints, n, cs)
 				}
 				DecompositionPortAdaptation: {
 					// Nothing to do.
@@ -259,6 +235,11 @@ class CandidatesGenerator {
 					// Nothing to do.
 				}
 				PowerBondAdaptation: {
+					// This needs to be rewritten, to accomodate the hierarchical cosim case 
+					//    and the assumption that at the begining of the cosim step, every port is defined.
+					throw new UnsupportedOperationException("Powerbond adaptations need to be re-implemented for hierarchical cosim.")
+					
+					/*
 					val adaptation = alternative as PowerBondAdaptation
 					val adapted = adaptation.adapted()
 					logger.debug("Processing Alternative PowerBondAdaptation of {}", adapted.identifier)
@@ -271,6 +252,7 @@ class CandidatesGenerator {
 					logger.debug("Attempting to add constraint {}.{}->{}.", unit.identifier, adaptation.POut.identifier, unit.identifier)
 					val success = addConstraint(adaptation.POut, unit, constraints, n, cs)
 					logger.debug("Success: {}", success)
+					 */
 				}
 				MultiRateAdaptation: {
 					// Nothing to do
@@ -289,6 +271,11 @@ class CandidatesGenerator {
 			if (n.children.empty){
 				// Base case
 				if (numGenVariants < maxVariants){
+					// Propagate precedence constraints from inner scenarios to their parents.
+					// If two nodes are indirectly (via a path in the children nodes) connected, then they should be connected directly.
+					// This will ensure that the topological sort can safely ignore child nodes.
+					propagateConstraints(n, ns, constraints, cs)
+					
 					val variantID = ns.map[n1 | n1.identifier].reduce[n1, n2| n2 + "_" + n1]
 					// mark alternatives as selected, so the processor knows which alternatives have been selected.
 					// Exclude root because it has no alternative
@@ -323,6 +310,28 @@ class CandidatesGenerator {
 		return numGenVariants
 	}
 	
+	def propagateConstraints(VariantDiagram n, Deque<VariantDiagram> ns, ConstraintsStack constraints, HintConfiguration cs) {
+		val rootScenario = ModelQuery.findRootScenario(ns)
+		val scenarios = rootScenario.eAllContents.filter(HierarchicalCosimUnit).toList
+		
+		for (scenario: scenarios){
+			val List<PrecendenceNode> scenarioNodes = newLinkedList()
+			scenarioNodes.add(scenario as PrecendenceNode)
+			scenarioNodes.addAll(scenario.inputPorts)
+			scenarioNodes.addAll(scenario.outputPorts)
+			
+			for (scenarioNodeSrc : scenarioNodes){
+				for (scenarioNodeTrg : scenarioNodes){
+					if (! scenarioNodeSrc.precedes.contains(scenarioNodeTrg) && 
+							ModelQuery.pathExists(scenarioNodeSrc, scenarioNodeTrg, constraints, cs)
+					){
+						Assert.isTrue(addConstraint(scenarioNodeSrc, scenarioNodeTrg, constraints, n, cs))
+					}
+				}
+			}
+		}
+	}
+	
 	def markSelected(Deque<VariantDiagram> ns, boolean selected) {
 		for (n : ns){
 			if (n.alternative !== null){

+ 1 - 61
HintCOEngine/src/ua/ansymo/hintco/ConstraintChecker.xtend

@@ -1,10 +1,6 @@
 package ua.ansymo.hintco
 
-import java.util.Set
 import org.eclipse.core.runtime.Assert
-import ua.ansymo.hintco.HintConfiguration
-import ua.ansymo.hintco.PrecendenceNode
-import ua.ansymo.hintco.VariantDiagram
 
 class ConstraintChecker implements IConstraintChecker {
 	
@@ -29,65 +25,9 @@ class ConstraintChecker implements IConstraintChecker {
 		/*
 		  * A constraint is not feasible adding it to the precedence graph causes a new cycle to be formed.
 		  */
-		 val found = recPathExists(trg, src, constraints, newHashSet(), cs)
+		 val found = ModelQuery.pathExists(trg, src, constraints, cs)
 		 Assert.isTrue(constraintsConsistent(constraints, cs))
 		 return !found
 	}
 	
-	def private boolean recPathExists(PrecendenceNode src,
-						PrecendenceNode trg, 
-						ConstraintsStack constraints,
-						Set<PrecendenceNode> visited, 
-						HintConfiguration cs){
-		/*
-		 * If src has been visited, return.
-		 * If src has not been visited, mark it as visited, and 
-		 * 		compute reachable nodes for its successors, and 
-		 * 		link src to every node that is reachable from each of its successors
-		 */
-		
-		// Base case: already visited
-		if (visited.contains(src)) {
-			return false
-		}
-		
-		visited.add(src)
-		
-		var found = false
-		
-		// Recursion step
-		try {
-			for (suc : src.precedes) {
-				// This is our goal, so no point continuing recursive execution
-				if (suc === trg){
-					throw new InterruptedException() 
-				}
-				if (recPathExists(suc, trg, constraints, visited, cs)) {
-					throw new InterruptedException() 
-				}
-			}	
-		} catch (InterruptedException e) {
-			// found trg
-			found = true
-		} 
-		
-		// link src to every to every node that is reachable from each of its successors
-		// Use intermediate list to avoid concurrent modification exception
-//		val toAdd = newLinkedList()
-//		for (suc : src.precedes) {
-//			for (sucsuc : suc.precedes) {
-//				// check if constraint already exists.
-//				if (!constraints.stackContains(src, sucsuc) && 
-//				  		!src.precedes.contains(sucsuc)) {
-//				  	toAdd.add(sucsuc)
-//				}
-//			}
-//		}
-//		for (sucsuc : toAdd) {
-//			constraints.safeAdd(src, sucsuc)
-//			src.precedes.add(sucsuc)
-//		}
-		
-		return found
-	}
 }

+ 3 - 1
HintCOEngine/src/ua/ansymo/hintco/HierarchicalInstance.xtend

@@ -44,7 +44,7 @@ class HierarchicalInstance extends AdaptedFMUInstance {
 		
 		inPorts = nodes.filter(InputPortInstance).filter[it.input].toSet
 		
-		// Ignore hierarchyports that are inputs.
+		// Ignore hierarchical ports that are inputs.
 		childOutputPorts = nodes.filter(OutputPortInstance).filter[!it.isInput].toList
 		
 		// Instantiate subunits.
@@ -83,6 +83,8 @@ class HierarchicalInstance extends AdaptedFMUInstance {
 		val hUnitPort = unitPort as HierarchicalUnitPort
 		Assert.isTrue(hUnitPort.input)
 		
+		// TODO: This is wrong. It should only be called when we need to set that input. For now, it should just be stored in a buffer.
+		// Except during the initialization phase.
 		for (trgPort : hUnitPort.valueTo) {
 			val trgUnit = fmuInstanceMap.get(trgPort.unit)
 			trgUnit.setReal(trgPort.identifier, v)

+ 2 - 0
HintCOEngine/src/ua/ansymo/hintco/Main.xtend

@@ -74,6 +74,8 @@ class Main implements IApplication {
 		var outDir = getOptString(outDirOpt, cmd, "output");
 		
 		val loader = new ModelStorage()
+		
+		
 		val src = loader.loadCandidates(scenarioFile)
 		
 		val spaceGenerator = new CandidateSpaceGenerator()

+ 75 - 7
HintCOEngine/src/ua/ansymo/hintco/ModelQuery.xtend

@@ -2,14 +2,9 @@ package ua.ansymo.hintco
 
 import java.util.Deque
 import java.util.List
+import java.util.Set
 import org.eclipse.core.runtime.Assert
-import ua.ansymo.hintco.HierarchicalCosimUnit
-import ua.ansymo.hintco.HintConfiguration
-import ua.ansymo.hintco.IDed
-import ua.ansymo.hintco.PortInstance
-import ua.ansymo.hintco.PrecendenceNode
-import ua.ansymo.hintco.Scenario
-import ua.ansymo.hintco.UnitInstance
+import java.util.HashSet
 
 class ModelQuery {
 	
@@ -21,6 +16,72 @@ class ModelQuery {
 		nSrc.precedes.contains(nTrg)
 	}
 	
+	def static boolean recPathExists(PrecendenceNode src,
+						PrecendenceNode trg, 
+						ConstraintsStack constraints,
+						Set<PrecendenceNode> visited, 
+						HintConfiguration cs){
+		/*
+		 * If src has been visited, return.
+		 * If src has not been visited, mark it as visited, and 
+		 * 		compute reachable nodes for its successors, and 
+		 * 		link src to every node that is reachable from each of its successors
+		 */
+		
+		// Base case: already visited
+		if (visited.contains(src)) {
+			return false
+		}
+		
+		visited.add(src)
+		
+		var found = false
+		
+		// Recursion step
+		try {
+			for (suc : src.precedes) {
+				// This is our goal, so no point continuing recursive execution
+				if (suc === trg){
+					throw new InterruptedException() 
+				}
+				if (recPathExists(suc, trg, constraints, visited, cs)) {
+					throw new InterruptedException() 
+				}
+			}	
+		} catch (InterruptedException e) {
+			// found trg
+			found = true
+		} 
+		
+		// Optimization: store reachability results in the graph. Not done because it clutters the resulting models (bad for debugging).
+		// link src to every to every node that is reachable from each of its successors
+		// Use intermediate list to avoid concurrent modification exception
+//		val toAdd = newLinkedList()
+//		for (suc : src.precedes) {
+//			for (sucsuc : suc.precedes) {
+//				// check if constraint already exists.
+//				if (!constraints.stackContains(src, sucsuc) && 
+//				  		!src.precedes.contains(sucsuc)) {
+//				  	toAdd.add(sucsuc)
+//				}
+//			}
+//		}
+//		for (sucsuc : toAdd) {
+//			constraints.safeAdd(src, sucsuc)
+//			src.precedes.add(sucsuc)
+//		}
+		
+		return found
+	}
+	
+	def static findRootScenario(Deque<VariantDiagram> ns){
+		// Locate scenario where computation order should be generated. Search ns and it's parents for a CandidateScenario alternative.
+		val scenarios = ns.filter[n | n.alternative instanceof RootCandidateScenario]
+		Assert.isTrue(1 == scenarios.size)
+		val scenario = scenarios.head.alternative as RootCandidateScenario
+		return scenario
+	}
+	
 	def static findIded(String id, HintConfiguration cs){
 		var IDed res = null
 		
@@ -80,4 +141,11 @@ class ModelQuery {
 		res
 	}
 	
+	def static pathExists(PrecendenceNode src,
+						PrecendenceNode trg, 
+						ConstraintsStack constraints,
+						HintConfiguration cs) {
+		recPathExists(src, trg, constraints, new HashSet(), cs)
+	}
+	
 }

+ 3 - 0
HintCOEngine/src/ua/ansymo/hintco/ModelStorage.xtend

@@ -24,6 +24,9 @@ class ModelStorage {
 		val resourceSet = new ResourceSetImpl
 		val res = resourceSet.getResource(URI.createURI(uri), true)
 		val candidates = res.contents.get(0) as HintConfiguration
+		
+		ModelValidation.validate(candidates)
+		
 		return candidates
 	}
 	

+ 14 - 0
HintCOEngine/src/ua/ansymo/hintco/ModelValidation.xtend

@@ -0,0 +1,14 @@
+package ua.ansymo.hintco
+
+class ModelValidation {
+	def static validate(HintConfiguration config){
+		emptyHierarchicalUnits(config)
+	}
+	
+	def static emptyHierarchicalUnits(HintConfiguration config) {
+		if (config.eAllContents.filter(HierarchicalCosimUnit).exists[u | u.cosimunits.empty]){
+			throw new RuntimeException("Hierarchical units must have child units.")
+		}
+	}
+		
+}

+ 6 - 22
HintCOEngine/src/ua/ansymo/hintco/VariantProcessor.xtend

@@ -6,12 +6,6 @@ import java.util.List
 import java.util.Map
 import java.util.Set
 import org.eclipse.core.runtime.Assert
-import ua.ansymo.hintco.HierarchicalCosimUnit
-import ua.ansymo.hintco.HintConfiguration
-import ua.ansymo.hintco.PrecendenceNode
-import ua.ansymo.hintco.RootCandidateScenario
-import ua.ansymo.hintco.Scenario
-import ua.ansymo.hintco.VariantDiagram
 
 class VariantProcessor implements IVariantProcessor {
 	
@@ -21,23 +15,12 @@ class VariantProcessor implements IVariantProcessor {
 		runner = r
 	}
 	
-	def findRootScenario(Deque<VariantDiagram> ns){
-		// Locate scenario where computation order should be generated. Search ns and it's parents for a CandidateScenario alternative.
-		val scenarios = ns.filter[n | n.alternative instanceof RootCandidateScenario]
-		Assert.isTrue(1 == scenarios.size)
-		val scenario = scenarios.head.alternative as RootCandidateScenario
-		return scenario
-	}
-	
-	def computeOperationOrder(Deque<VariantDiagram> ns, HintConfiguration cs){
+	def computeOperationOrder(RootCandidateScenario  scenario, Deque<VariantDiagram> ns, HintConfiguration cs){
 		/*
 		 * Computes feasible operation order. 
 		 */
 		 
-		 // Locate scenario where computation order should be generated. Search ns and it's parents for a CandidateScenario alternative.
-		 val RootCandidateScenario rootScenario = findRootScenario(ns)
-		 
-		 val scenarioSortedNodesMap = computeHierarchicalTopologicalSort(rootScenario)
+		 val scenarioSortedNodesMap = computeHierarchicalTopologicalSort(scenario)
 		 
 		 // Set the path in the model.
 		 for (sortedNodes: scenarioSortedNodesMap.values){
@@ -79,7 +62,7 @@ class VariantProcessor implements IVariantProcessor {
 		 unSortedNodes.forEach[n | inSorted.put(n, false)]
 		 val sortedNodes = newLinkedList()
 		 val candidates = newLinkedList()
-		 // TODO: The successors and predecessor sets must be restricted to the current scenario.
+		 // The successors and predecessor sets must be restricted to the current scenario.
 		 unSortedNodes.forEach[n |
 		 	if (n.succeeds.filter[unSortedNodes.contains(it)].empty){
 		 		candidates.push(n)
@@ -112,8 +95,9 @@ class VariantProcessor implements IVariantProcessor {
 	
 	override process(Deque<VariantDiagram> ns, String variantID, ConstraintsStack constraints, HintConfiguration cs) {
 		if (runner !== null) {
-			val order = computeOperationOrder(ns, cs)
-			val scenario = findRootScenario(ns)
+			// Locate scenario where computation order should be generated. Search ns and it's parents for a CandidateScenario alternative.
+			val scenario = ModelQuery.findRootScenario(ns)
+			val order = computeOperationOrder(scenario, ns, cs)
 			runner.run(scenario, order, variantID)
 		}
 	}

+ 73 - 18
HintCOEngine/test/ua/ansymo/hintco/test/CandidatesGeneratorTest.xtend

@@ -1,14 +1,16 @@
 package ua.ansymo.hintco.test
 
+import org.junit.Ignore
 import org.junit.Test
 import ua.ansymo.hintco.CandidatesGenerator
 import ua.ansymo.hintco.ConstraintChecker
-import ua.ansymo.hintco.ModelStorage
-import ua.ansymo.hintco.VariantProcessor
-import ua.ansymo.hintco.VariantValidator
 import ua.ansymo.hintco.CosimUnitInstance
 import ua.ansymo.hintco.ExtrapolationAdaptation
+import ua.ansymo.hintco.ModelQuery
+import ua.ansymo.hintco.ModelStorage
 import ua.ansymo.hintco.PowerBondAdaptation
+import ua.ansymo.hintco.VariantProcessor
+import ua.ansymo.hintco.VariantValidator
 
 import static org.junit.Assert.*
 import static ua.ansymo.hintco.ModelQuery.*
@@ -24,7 +26,8 @@ class CandidatesGeneratorTest {
 				true
 			],
 			[ns, vId, constraints, cs |
-				val orderMap = new VariantProcessor(null).computeOperationOrder(ns, cs)
+				val scenario = ModelQuery.findRootScenario(ns)
+				val orderMap = new VariantProcessor(null).computeOperationOrder(scenario, ns, cs)
 				val order = orderMap.values.head
 				assertTrue(comesBefore("LoadNSensor_FixedEuler_1Em6", "EMAPlantNoLoad_FixedEuler_1Em6", order, cs))
 				assertTrue(comesBefore("F_OUT@expseu_", "F_INPUT@expseu_", order, cs))
@@ -41,7 +44,8 @@ class CandidatesGeneratorTest {
 				true
 			],
 			[ns, vId, constraints, cs |
-				val orderMap = new VariantProcessor(null).computeOperationOrder(ns, cs)
+				val scenario = ModelQuery.findRootScenario(ns)
+				val orderMap = new VariantProcessor(null).computeOperationOrder(scenario, ns, cs)
 				val order = orderMap.values.head
 				assertTrue(comesBefore("LoadNSensor_FixedEuler_1Em6", "EMAPlantNoLoad_FixedEuler_1Em6", order, cs))
 				assertTrue(comesBefore("F_OUT@expseu_", "F_INPUT@expseu_", order, cs))
@@ -57,10 +61,10 @@ class CandidatesGeneratorTest {
 				true
 			],
 			[ns, vId, constraints, cs |
-				val vp = new VariantProcessor(null)
-				val orderMap = vp.computeOperationOrder(ns, cs)
+				val scenario = ModelQuery.findRootScenario(ns)
+				val orderMap = new VariantProcessor(null).computeOperationOrder(scenario, ns, cs)
 				
-				val rootScenario = vp.findRootScenario(ns)
+				val rootScenario = ModelQuery.findRootScenario(ns)
 				val topOrder = orderMap.get(rootScenario)
 				
 				comesBefore("B", "C", topOrder, cs)
@@ -151,21 +155,70 @@ class CandidatesGeneratorTest {
 			[ns, vId, constraints, cs |
 			variants.add(vId)
 			
-			assertTrue(precedes(cs, "B", "B2"))
+			assertTrue(precedes(cs, "B2", "B"))
 			assertTrue(precedes(cs, "Bip", "B2ip1"))
-			assertTrue(precedes(cs, "Bip", "A"))
+			assertTrue(precedes(cs, "Bip", "Bop"))
 			assertTrue(precedes(cs, "Aop", "Bip"))
-			assertTrue(precedes(cs, "Bip", "B"))
-			
-			//loader.storeCandidates("instances/generated/add_constraints_test.hintco", src)
 			
 			assertFalse(precedes(cs, "B", "B")) // no self loop
 			
 			assertTrue(precedes(cs, "Bop", "Cip"))
 			
-			assertTrue(precedes(cs, "B", "Bop"))
+			assertTrue(precedes(cs, "Cip", "C"))
+			
+		])
+		generator.createVariantTree(src)
+		generator.generateVariants(src)
+		assertEquals(1, variants.size)
+	}
+	
+	@Test
+	def void addConstraintsHierInterTest(){
+		val src = loader.loadCandidates("instances/add_constraints_test_inter.hintco")
+		val variants = newLinkedList()
+		val generator = new CandidatesGenerator(new ConstraintChecker(), new VariantValidator(),
+			[ns, vId, constraints, cs |
+			variants.add(vId)
+			
+			assertTrue(precedes(cs, "B2", "B"))
+			assertTrue(precedes(cs, "Bip", "B2ip1"))
+			assertTrue(precedes(cs, "Bip", "Bop"))
+			assertTrue(precedes(cs, "Bip", "B"))
+			assertTrue(precedes(cs, "Aop", "Bip"))
+			
+			assertTrue(precedes(cs, "Bop", "Cip"))
+			
+			assertTrue(precedes(cs, "C", "Cip"))
+			
+		])
+		generator.createVariantTree(src)
+		generator.generateVariants(src)
+		assertEquals(1, variants.size)
+	}
+	
+	@Test
+	def void propagateConstraintsTest(){
+		val src = loader.loadCandidates("instances/propagate_constraints_test.hintco")
+		val variants = newLinkedList()
+		val generator = new CandidatesGenerator(new ConstraintChecker(), new VariantValidator(),
+			[ns, vId, constraints, cs |
+			variants.add(vId)
+			
+			assertTrue(precedes(cs, "A", "Aop"))
+			assertTrue(precedes(cs, "Aop", "Bip"))
+			assertTrue(precedes(cs, "Bip", "bip"))
+			assertTrue(precedes(cs, "bip", "b"))
+			assertTrue(precedes(cs, "b", "bop"))
+			assertTrue(precedes(cs, "bop", "Bop"))
+			assertTrue(precedes(cs, "b", "B"))
+			assertTrue(precedes(cs, "Bip", "B")) // Propagated
+			assertTrue(precedes(cs, "Bip", "Bop")) // Propagated
 			
+			val scenario = ModelQuery.findRootScenario(ns)
+			val orderMap = new VariantProcessor(null).computeOperationOrder(scenario, ns, cs)
+			val order = orderMap.values.head
 			
+			assertTrue(comesBefore("Bip", "Bop", order, cs))
 		])
 		generator.createVariantTree(src)
 		generator.generateVariants(src)
@@ -179,10 +232,11 @@ class CandidatesGeneratorTest {
 		val generator = new CandidatesGenerator(new ConstraintChecker(), new VariantValidator(),
 			[ns, vId, constraints, cs |
 			variants.add(vId)
-			val orderMap = new VariantProcessor(null).computeOperationOrder(ns, cs)
+			val scenario = ModelQuery.findRootScenario(ns)
+			val orderMap = new VariantProcessor(null).computeOperationOrder(scenario, ns, cs)
 			val order = orderMap.values.head
 			
-			assertTrue(comesBefore("u1", "A", order, cs))
+			assertTrue(comesBefore("A", "u1", order, cs))
 		])
 		generator.createVariantTree(src)
 		generator.generateVariants(src)
@@ -218,9 +272,9 @@ class CandidatesGeneratorTest {
 				true
 			],
 			[ns, vId, constraints, cs |
+			assertTrue(precedes(cs, "EMAPlantNoLoad_FixedEuler_1Em6", "ang_vel_out_rpm@expseu_"))
 			assertTrue(precedes(cs, "ang_vel_out_rpm@expseu_", "VEL_FB@expseu_"))
-			assertTrue(precedes(cs, "VEL_FB@expseu_", "DLoopController_FixedEuler_1Em6"))
-			assertTrue(precedes(cs, "VEL_FB@expseu_", "EMAPlantNoLoad_FixedEuler_1Em6"))
+			assertTrue(precedes(cs, "DLoopController_FixedEuler_1Em6", "VEL_FB@expseu_"))
 		])
 		generator.createVariantTree(src)
 		generator.generateVariants(src)
@@ -291,6 +345,7 @@ class CandidatesGeneratorTest {
 	
 	
 	@Test
+	@Ignore // Power Bond adaptations are no longer support. Need to make them consistent with waveform relaxation techniques.
 	def void processBondAdaptationsTest(){
 		val loader = new ModelStorage()
 		val src = loader.loadCandidates("instances/case_study_double_loop_pbond.hintco")

+ 2 - 0
HintCOEngine/test/ua/ansymo/hintco/test/CosimRunnerTest.xtend

@@ -240,6 +240,7 @@ class CosimRunnerTest {
 	}
 	
 	@Test
+	@Ignore // Power Bond adaptations are no longer support. Need to make them consistent with waveform relaxation techniques.
 	def void executeCosimulationTestDoubleLoopPowerBond(){
 		Assume.assumeTrue(SystemUtils.IS_OS_WINDOWS) // Because it only works on windows.
 //		System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug")
@@ -257,6 +258,7 @@ class CosimRunnerTest {
 	}
 	
 	@Test
+	@Ignore // Power Bond adaptations are no longer support. Need to make them consistent with waveform relaxation techniques.
 	def void executeCosimulationTestDoubleLoopPowerBondHier(){
 		Assume.assumeTrue(SystemUtils.IS_OS_WINDOWS) // Because it only works on windows.
 //		System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug")