Claudio Gomes 7 лет назад
Родитель
Сommit
19e79041e5

+ 188 - 0
HintCO/instances/model_test.xmi

@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="ASCII"?>
+<hintco:Candidates
+    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="Original">
+    <cosimunits
+        identifier="Scenario"
+        declaration="//@csuDeclarations.0">
+      <ports
+          xsi:type="hintco:OutputPortInstance"
+          identifier="psuvolt"
+          valueTo="//@candidates.0/@cosimunits.2/@ports.1"
+          declaration="//@csuDeclarations.0/@ports.0"/>
+      <ports
+          xsi:type="hintco:OutputPortInstance"
+          identifier="ref"
+          valueTo="//@candidates.0/@cosimunits.1/@ports.2"
+          declaration="//@csuDeclarations.0/@ports.1"/>
+    </cosimunits>
+    <cosimunits
+        identifier="DLoopController_FixedEuler_1Em6"
+        declaration="//@csuDeclarations.1">
+      <adaptation
+          xsi:type="hintco:MultiRateAdaptation"
+          rate="10"/>
+      <ports
+          xsi:type="hintco:InputPortInstance"
+          identifier="VEL_FB@expseu_"
+          declaration="//@csuDeclarations.1/@ports.0"
+          valueFrom="//@candidates.0/@cosimunits.2/@ports.4"/>
+      <ports
+          xsi:type="hintco:InputPortInstance"
+          identifier="POS_FB@expseu_"
+          declaration="//@csuDeclarations.1/@ports.1"
+          valueFrom="//@candidates.0/@cosimunits.3/@ports.1"/>
+      <ports
+          xsi:type="hintco:InputPortInstance"
+          identifier="REFERENCE@expseu_"
+          declaration="//@csuDeclarations.1/@ports.2"
+          valueFrom="//@candidates.0/@cosimunits.0/@ports.1">
+        <adaptation
+            xsi:type="hintco:XorAdaptation"
+            selected="true">
+          <children
+              xsi:type="hintco:ExtrapolationAdaptation"
+              weight="1"
+              selected="true"/>
+          <children
+              xsi:type="hintco:InterpolationAdaptation"
+              weight="5"/>
+        </adaptation>
+      </ports>
+      <ports
+          xsi:type="hintco:OutputPortInstance"
+          identifier="OUTPUT@expseu_"
+          valueTo="//@candidates.0/@cosimunits.2/@ports.0"
+          declaration="//@csuDeclarations.1/@ports.3"/>
+    </cosimunits>
+    <cosimunits
+        identifier="EMAPlantNoLoad_FixedEuler_1Em6"
+        declaration="//@csuDeclarations.2">
+      <adaptation
+          xsi:type="hintco:XorAdaptation"
+          selected="true">
+        <children
+            xsi:type="hintco:MultiRateAdaptation"
+            selected="true"
+            rate="5"/>
+        <children
+            xsi:type="hintco:MultiRateAdaptation"
+            rate="10"/>
+      </adaptation>
+      <ports
+          xsi:type="hintco:InputPortInstance"
+          identifier="torque_input@expseu_"
+          declaration="//@csuDeclarations.2/@ports.0"
+          valueFrom="//@candidates.0/@cosimunits.1/@ports.3">
+        <adaptation
+            xsi:type="hintco:XorAdaptation"
+            selected="true">
+          <children
+              xsi:type="hintco:ExtrapolationAdaptation"
+              weight="3"/>
+          <children
+              xsi:type="hintco:InterpolationAdaptation"
+              weight="7"
+              selected="true"/>
+        </adaptation>
+      </ports>
+      <ports
+          xsi:type="hintco:InputPortInstance"
+          identifier="psu_vol_input_v@expseu_"
+          declaration="//@csuDeclarations.2/@ports.1"
+          valueFrom="//@candidates.0/@cosimunits.0/@ports.0"/>
+      <ports
+          xsi:type="hintco:InputPortInstance"
+          identifier="V_IN@expseu_"
+          declaration="//@csuDeclarations.2/@ports.2"
+          valueFrom="//@candidates.0/@cosimunits.3/@ports.2"/>
+      <ports
+          xsi:type="hintco:InputPortInstance"
+          identifier="X_IN@expseu_"
+          declaration="//@csuDeclarations.2/@ports.3"
+          valueFrom="//@candidates.0/@cosimunits.3/@ports.3"/>
+      <ports
+          xsi:type="hintco:OutputPortInstance"
+          identifier="ang_vel_out_rpm@expseu_"
+          valueTo="//@candidates.0/@cosimunits.1/@ports.0"
+          declaration="//@csuDeclarations.2/@ports.4"/>
+      <ports
+          xsi:type="hintco:OutputPortInstance"
+          identifier="F_OUT@expseu_"
+          valueTo="//@candidates.0/@cosimunits.3/@ports.0"
+          declaration="//@csuDeclarations.2/@ports.5"/>
+    </cosimunits>
+    <cosimunits
+        identifier="LoadNSensor_FixedEuler_1Em6"
+        declaration="//@csuDeclarations.3">
+      <ports
+          xsi:type="hintco:InputPortInstance"
+          identifier="F_INPUT@expseu_"
+          declaration="//@csuDeclarations.3/@ports.0"
+          valueFrom="//@candidates.0/@cosimunits.2/@ports.5"/>
+      <ports
+          xsi:type="hintco:OutputPortInstance"
+          identifier="X_AFTER_LOAD@expseu_"
+          valueTo="//@candidates.0/@cosimunits.1/@ports.1"
+          declaration="//@csuDeclarations.3/@ports.1"/>
+      <ports
+          xsi:type="hintco:OutputPortInstance"
+          identifier="V_OUTPUT@expseu_"
+          valueTo="//@candidates.0/@cosimunits.2/@ports.2"
+          declaration="//@csuDeclarations.3/@ports.2"/>
+      <ports
+          xsi:type="hintco:OutputPortInstance"
+          identifier="X_OUTPUT@expseu_"
+          valueTo="//@candidates.0/@cosimunits.2/@ports.3"
+          declaration="//@csuDeclarations.3/@ports.3"/>
+    </cosimunits>
+  </candidates>
+  <csuDeclarations
+      identifier="Scenario">
+    <ports xsi:type="hintco:OutputPortDeclaration"
+        identifier="psuvolt"/>
+    <ports xsi:type="hintco:OutputPortDeclaration"
+        identifier="ref"/>
+  </csuDeclarations>
+  <csuDeclarations
+      identifier="DLoopController_FixedEuler_1Em6">
+    <ports xsi:type="hintco:InputPortDeclaration"
+        identifier="VEL_FB@expseu_"/>
+    <ports xsi:type="hintco:InputPortDeclaration"
+        identifier="POS_FB@expseu_"/>
+    <ports xsi:type="hintco:InputPortDeclaration"
+        identifier="REFERENCE@expseu_"/>
+    <ports xsi:type="hintco:OutputPortDeclaration"
+        identifier="OUTPUT@expseu_"/>
+  </csuDeclarations>
+  <csuDeclarations
+      identifier="EMAPlantNoLoad_FixedEuler_1Em6">
+    <ports xsi:type="hintco:InputPortDeclaration"
+        identifier="torque_input@expseu_"/>
+    <ports xsi:type="hintco:InputPortDeclaration"
+        identifier="psu_vol_input_v@expseu_"/>
+    <ports xsi:type="hintco:InputPortDeclaration"
+        identifier="V_IN@expseu_"/>
+    <ports xsi:type="hintco:InputPortDeclaration"
+        identifier="X_IN@expseu_"/>
+    <ports xsi:type="hintco:OutputPortDeclaration"
+        identifier="ang_vel_out_rpm@expseu_"/>
+    <ports xsi:type="hintco:OutputPortDeclaration"
+        identifier="F_OUT@expseu_"/>
+  </csuDeclarations>
+  <csuDeclarations
+      identifier="LoadNSensor_FixedEuler_1Em6">
+    <ports xsi:type="hintco:InputPortDeclaration"
+        identifier="F_INPUT@expseu_"/>
+    <ports xsi:type="hintco:OutputPortDeclaration"
+        identifier="X_AFTER_LOAD@expseu_"/>
+    <ports xsi:type="hintco:OutputPortDeclaration"
+        identifier="V_OUTPUT@expseu_"/>
+    <ports xsi:type="hintco:OutputPortDeclaration"
+        identifier="X_OUTPUT@expseu_"/>
+  </csuDeclarations>
+</hintco:Candidates>

+ 39 - 8
HintCO/model/Candidates.xcore

@@ -63,7 +63,24 @@ class HierarchicalCosimUnitDeclaration extends CosimUnitDeclaration {
 	contains CosimUnitInstance[] children
 }
 
-class CosimUnitInstance extends IDed,PrecendenceNode {
+class Adaptable {
+	contains Adaptation adaptation opposite adaptable
+	op Adaptation selectedAdaptation() {
+		if (adaptation === null){
+			return null
+		}
+		if (adaptation.selected){
+			if (adaptation instanceof XorAdaptation){
+				return (adaptation as XorAdaptation).selectedAdaptation()
+			}
+			return adaptation
+		}
+		
+		return null
+	}
+}
+
+class CosimUnitInstance extends IDed,PrecendenceNode, Adaptable {
 	refers CosimUnitDeclaration[1] declaration
 	contains PortInstance[] ports opposite unit
 }
@@ -80,8 +97,7 @@ class OutputPortDeclaration extends PortDeclaration {
 	
 }
 
-abstract class PortInstance extends PrecendenceNode,IDed {
-	contains Adaptation adaptation opposite port
+abstract class PortInstance extends PrecendenceNode,IDed,Adaptable {
 	refers CosimUnitInstance unit opposite ports
 }
 
@@ -98,22 +114,23 @@ class OutputPortInstance extends PortInstance {
 abstract class Alternative
 {
 	int weight
+	boolean selected
 	refers Alternative[] implies
 }
 
 abstract class Adaptation extends Alternative
 {
 	refers DecompositionAdaptation parent opposite children
-	refers PortInstance port opposite adaptation
+	refers Adaptable adaptable opposite adaptation
 	
-	op PortInstance adaptedPort() {
-		if (port !== null){
-			return port
+	op Adaptable adapted() {
+		if (adaptable !== null){
+			return adaptable
 		}
 		if (parent === null){
 			return null
 		}
-		return parent.adaptedPort()
+		return parent.adapted()
 	}
 }
 
@@ -125,12 +142,26 @@ class XorAdaptation extends DecompositionAdaptation {
 	derived String name get {
 		"(w=" + weight + ")"
 	}
+	op Adaptation selectedAdaptation() {
+		val selected = children.findFirst[a | a.selected]
+		if (selected instanceof XorAdaptation){
+			return selected.selectedAdaptation()
+		}
+		return selected
+	}
 }
 
 abstract class ApproximationAdaptation extends Adaptation {
 	int order
 }
 
+class MultiRateAdaptation extends Adaptation {
+	int rate
+	derived String name get {
+		rate + "(w=" + weight + ")"
+	}
+}
+
 class ExtrapolationAdaptation extends ApproximationAdaptation {
 	derived String name get {
 		order + "(w=" + weight + ")"

+ 76 - 0
HintCO/src/ua/ansymo/hintco/AdaptedFMU.xtend

@@ -0,0 +1,76 @@
+package ua.ansymo.hintco
+
+import java.util.Map
+import org.intocps.fmi.Fmi2Status
+import org.intocps.fmi.FmuInvocationException
+import org.intocps.fmi.IFmiComponent
+
+class AdaptedFMU extends Fmu {
+	
+	var int innerRate = 1
+	val Map<String, IAdaptedInputPort> adaptedInPorts = newHashMap()
+	
+	new(IFmiComponent f, CosimUnitInstance unit) {
+		super(f)
+		
+		// Check if unit has a multi-rate adaptation
+		val unitAdaptation = unit.selectedAdaptation
+		if (unitAdaptation !== null && unitAdaptation instanceof MultiRateAdaptation){
+			innerRate = (unit.adaptation as MultiRateAdaptation).rate
+		}
+		
+		// Instantiate each adaptation input port of the unit.
+		for (p : unit.ports.filter(InputPortInstance)){
+			// Check which adaptation is selected for the input port, and instantiate the appropriate class.
+			val portAdaptation = p.selectedAdaptation
+			switch (portAdaptation) {
+				InterpolationAdaptation: {
+					adaptedInPorts.put(p.identifier, new InterpolationAdaptedPort(p, portAdaptation as InterpolationAdaptation))
+				}
+				ExtrapolationAdaptation: {
+					adaptedInPorts.put(p.identifier, new ExtrapolationAdaptedPort(p, portAdaptation as InterpolationAdaptation))
+				}
+			}
+		}
+		
+		// TODO Instantiate each adaptation output port of the unit.
+	}
+	
+	override doStep(double currentCommunicationPoint, double communicationStepSize) throws FmuInvocationException {
+		val micro_step = communicationStepSize/innerRate
+		var inner_time = currentCommunicationPoint
+		var Fmi2Status status;
+		
+		// Prepare input port adaptations for stepping
+		for (p : adaptedInPorts.keySet){
+			adaptedInPorts.get(p).startStep()
+		}
+		
+		for (i : 0 ..< innerRate){
+			// Set adapted inputs before doStep.
+			for (p : adaptedInPorts.keySet){
+				super.setReal(p, adaptedInPorts.get(p).getReal(inner_time, inner_time-currentCommunicationPoint, micro_step, communicationStepSize))
+			}
+			// doStep
+			status = super.doStep(inner_time, micro_step)
+		}
+		
+		// Inform input port adaptations of ending of step
+		for (p : adaptedInPorts.keySet){
+			adaptedInPorts.get(p).endStep()
+		}
+		
+		return status
+	}
+	
+	override setReal(String portName, double v) {
+		val adaptedPort = adaptedInPorts.get(portName)
+		if (adaptedPort !== null){
+			adaptedPort.setReal(v)
+			return true
+		} else {
+			return super.setReal(portName, v)
+		}
+	}
+	
+}

+ 27 - 0
HintCO/src/ua/ansymo/hintco/ApproximationAdaptedPort.xtend

@@ -0,0 +1,27 @@
+package ua.ansymo.hintco
+
+import ua.ansymo.hintco.IAdaptedInputPort
+
+abstract class ApproximationAdaptedPort implements IAdaptedInputPort {
+	
+	var protected double current_val
+	var protected double previous_val
+	var protected boolean initialized = false
+	
+	new(InputPortInstance instance, InterpolationAdaptation adaptation) {}
+	
+	override setReal(double v) {
+		current_val = v
+		if (!initialized){
+			previous_val = v
+			initialized = true
+		}
+	}
+	
+	override startStep() {}
+	
+	override endStep() {
+		this.previous_val = current_val
+	}
+	
+}

+ 12 - 7
HintCO/src/ua/ansymo/hintco/CandidatesGenerator.xtend

@@ -97,11 +97,12 @@ class CandidatesGenerator {
 					// Add precedence constraints to the ports that provide value to this port.
 					// and ensure the doStep ordering.
 					val adaptation = n.alternative as ExtrapolationAdaptation
-					val adaptedPort = adaptation.adaptedPort()
-					Assert.isNotNull(adaptedPort)
-					Assert.isTrue(adaptedPort instanceof InputPortInstance)
+					val adapted = adaptation.adapted()
+					Assert.isNotNull(adapted)
+					Assert.isTrue(adapted instanceof InputPortInstance)
+					val adaptedPort = adapted as InputPortInstance
 					val adaptedUnit = adaptedPort.unit
-					val srcPort = (adaptedPort as InputPortInstance).valueFrom
+					val srcPort = adaptedPort.valueFrom
 					val srcUnit = srcPort.unit
 					
 					addConstraint(srcPort, adaptedPort, constraints, n, cs)
@@ -110,9 +111,10 @@ class CandidatesGenerator {
 				}
 				InterpolationAdaptation: {
 					val adaptation = n.alternative as InterpolationAdaptation
-					val adaptedPort = adaptation.adaptedPort()
-					Assert.isNotNull(adaptedPort)
-					Assert.isTrue(adaptedPort instanceof InputPortInstance)
+					val adapted = adaptation.adapted()
+					Assert.isNotNull(adapted)
+					Assert.isTrue(adapted instanceof InputPortInstance)
+					val adaptedPort = adapted as InputPortInstance
 					val adaptedUnit = adaptedPort.unit
 					val srcPort = (adaptedPort as InputPortInstance).valueFrom
 					val srcUnit = srcPort.unit
@@ -139,7 +141,10 @@ class CandidatesGenerator {
 				// Base case
 				if (numGenVariants < maxVariants){
 					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.
+					ns.forEach[n.alternative.selected = true]
 					processor.process(ns, variantID, constraints, cs)
+					ns.forEach[n.alternative.selected = false]
 					numGenVariants++				
 				}
 			} else {

+ 2 - 2
HintCO/src/ua/ansymo/hintco/CosimRunner.xtend

@@ -25,14 +25,14 @@ class CosimRunner implements ICosimRunner {
 			val fmu = Factory.create(new File(unit.declaration.path))
 			fmu.load()
 			// TODO: Inject the AdaptedFMU object, which is a wrapper to the real FMU, containing the adaptations declared.
-			val fmuInstance = new Fmu(fmu.instantiate(unit.declaration.guid, unit.identifier, true, true, new IFmuCallback() {
+			val fmuInstance = new AdaptedFMU(fmu.instantiate(unit.declaration.guid, unit.identifier, true, true, new IFmuCallback() {
 				override log(String instanceName, Fmi2Status status, String category, String message) {
 					println("log: " + instanceName + " " + status + " " + category + " " + message);
 				}
 
 				override stepFinished(Fmi2Status status) {
 				}
-			}))
+			}), unit)
 			fmuInstance.setupExperiment()
 			
 			// TODO Set the configured parameter values.

+ 14 - 0
HintCO/src/ua/ansymo/hintco/ExtrapolationAdaptedPort.xtend

@@ -0,0 +1,14 @@
+package ua.ansymo.hintco
+
+class ExtrapolationAdaptedPort extends ApproximationAdaptedPort {
+	
+	new(InputPortInstance port, InterpolationAdaptation adaptation) {
+		super(port, adaptation)
+		// TODO: For now we assume only 1st order approximations
+	}
+	
+	override getReal(double t, double dt, double h, double H) {
+		return previous_val + ((current_val - previous_val)/H)*(H + dt + h)
+	}
+	
+}

+ 12 - 0
HintCO/src/ua/ansymo/hintco/IAdaptedInputPort.xtend

@@ -0,0 +1,12 @@
+package ua.ansymo.hintco
+
+interface IAdaptedInputPort {
+	def void setReal(double v)
+	
+	def double getReal(double t, double dt, double h, double H)
+	
+	def void startStep()
+	
+	def void endStep()
+	
+}

+ 14 - 0
HintCO/src/ua/ansymo/hintco/InterpolationAdaptedPort.xtend

@@ -0,0 +1,14 @@
+package ua.ansymo.hintco
+
+class InterpolationAdaptedPort extends ApproximationAdaptedPort {
+	
+	new(InputPortInstance port, InterpolationAdaptation adaptation) {
+		super(port, adaptation)
+		// TODO: For now we assume only 1st order approximations
+	}
+	
+	override getReal(double t, double dt, double h, double H) {
+		return previous_val + ((current_val - previous_val)/H)*(dt+h)
+	}
+	
+}

+ 1 - 1
HintCO/test/ua/ansymo/hintco/test/CandidatesGeneratorTest.xtend

@@ -92,7 +92,7 @@ class CandidatesGeneratorTest {
 			],
 			[ns, vId, constraints, cs |
 				variants.add(vId)
-		])
+			])
 		generator.createVariantTree(src)
 		generator.generateVariants(src, 2)
 		assertEquals(2, variants.size)

+ 28 - 0
HintCO/test/ua/ansymo/hintco/test/ModelTest.xtend

@@ -0,0 +1,28 @@
+package ua.ansymo.hintco.test
+
+import org.junit.Test
+import ua.ansymo.hintco.CosimUnitInstance
+import ua.ansymo.hintco.ModelStorage
+import ua.ansymo.hintco.MultiRateAdaptation
+
+import static org.junit.Assert.*
+import ua.ansymo.hintco.InputPortInstance
+import ua.ansymo.hintco.InterpolationAdaptation
+
+class ModelTest {
+	
+	val loader = new ModelStorage()
+	
+	@Test
+	def void getAdaptedTest(){
+		val src = loader.loadCandidates("instances/model_test.xmi")
+		
+		val plant = src.eAllContents.filter(CosimUnitInstance).findFirst[u | u.identifier == "EMAPlantNoLoad_FixedEuler_1Em6"]
+		assertTrue(plant.selectedAdaptation() instanceof MultiRateAdaptation)
+		assertTrue((plant.selectedAdaptation() as MultiRateAdaptation).rate == 5)
+		
+		val torque = src.eAllContents.filter(InputPortInstance).findFirst[p | p.identifier == "torque_input@expseu_"]
+		assertTrue(torque.selectedAdaptation instanceof InterpolationAdaptation)
+	}
+	
+}