Forráskód Böngészése

algebraic loop optimization support implementaion. Missing release and example documentation.

Claudio Gomes 5 éve
szülő
commit
c8f6f57b57

+ 25 - 0
HintCOEngine/examples/case_study_msd_algloop.hintco

@@ -0,0 +1,25 @@
+<?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="Original" stopTime="10.0" stepSize="0.01" outputStepSize="0.01">
+    <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="msd1" declaration="//@csuDeclarations.0">
+      <ports xsi:type="hintco:OutputPortInstance" identifier="x1" valueTo="//@candidates.0/@cosimunits.1/@ports.0"/>
+      <ports xsi:type="hintco:OutputPortInstance" identifier="v1" valueTo="//@candidates.0/@cosimunits.1/@ports.1"/>
+      <ports xsi:type="hintco:InputPortInstance" identifier="fk" extrapolationCost="10.0" valueFrom="//@candidates.0/@cosimunits.1/@ports.2">
+        <adaptation xsi:type="hintco:InterpolationAdaptation"/>
+      </ports>
+    </cosimunits>
+    <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="msd2" declaration="//@csuDeclarations.1">
+      <ports xsi:type="hintco:InputPortInstance" identifier="x1" valueFrom="//@candidates.0/@cosimunits.0/@ports.0">
+        <adaptation xsi:type="hintco:InterpolationAdaptation"/>
+      </ports>
+      <ports xsi:type="hintco:InputPortInstance" identifier="v1" valueFrom="//@candidates.0/@cosimunits.0/@ports.1">
+        <adaptation xsi:type="hintco:InterpolationAdaptation"/>
+      </ports>
+      <ports xsi:type="hintco:OutputPortInstance" identifier="fk" valueTo="//@candidates.0/@cosimunits.0/@ports.2"/>
+      <ports xsi:type="hintco:OutputPortInstance" identifier="x2"/>
+      <ports xsi:type="hintco:OutputPortInstance" identifier="v2"/>
+    </cosimunits>
+  </candidates>
+  <csuDeclarations identifier="MassSpringDamper1" path="resources/msd/MassSpringDamper1.fmu" guid="{b9a6f0c4-d497-4270-82bd-b3082ab8b5ed}"/>
+  <csuDeclarations identifier="MassSpringDamper2" path="resources/msd/MassSpringDamper2.fmu" guid="{ae52e3f4-d126-465f-b9d8-691742b11bda}"/>
+</hintco:HintConfiguration>

+ 1 - 1
HintCOEngine/instances/algebraic_loop_opt_test.hintco

@@ -1,6 +1,6 @@
 <?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="Scenario" stopTime="10.0" stepSize="1.0" outputStepSize="1.0">
+  <candidates identifier="Scenario" stopTime="20.0" stepSize="0.01" outputStepSize="0.01">
     <cosimunits xsi:type="hintco:CosimUnitInstance" identifier="A" declaration="//@csuDeclarations.0">
       <ports xsi:type="hintco:InputPortInstance" identifier="3fromB" extrapolationCost="3.0" valueFrom="//@candidates.0/@cosimunits.1/@ports.1">
         <adaptation xsi:type="hintco:InterpolationAdaptation"/>

+ 44 - 1
HintCOEngine/src/ua/ansymo/hintco/AlgebraicLoopVariantProcessor.xtend

@@ -1,13 +1,17 @@
 package ua.ansymo.hintco
 
 import java.util.Deque
+import java.util.List
+import java.util.Map
 import org.eclipse.core.runtime.Assert
+import org.jgrapht.GraphPath
 import org.jgrapht.alg.connectivity.GabowStrongConnectivityInspector
 import org.jgrapht.alg.interfaces.AStarAdmissibleHeuristic
 import org.jgrapht.alg.shortestpath.AStarShortestPath
 import org.jgrapht.graph.DefaultWeightedEdge
 import org.jgrapht.graph.DirectedMultigraph
 import org.jgrapht.util.SupplierUtil
+import java.util.LinkedList
 
 class AlgebraicLoopVariantProcessor implements IVariantProcessor {
 	
@@ -77,6 +81,7 @@ class AlgebraicLoopVariantProcessor implements IVariantProcessor {
 	def findOptimalTriggerSequence(DirectedMultigraph<CosimUnitInstance, DefaultWeightedEdge> graph) {
 		val strongComponents = new GabowStrongConnectivityInspector(graph).stronglyConnectedSets()
 		Assert.isTrue(strongComponents.size==1, "Non strongly connected scenarios are not yet supported.")
+		
 		// TODO: when multiple strong components exists, take each strong component and build a graph of it.
 		// Then put it through findOptimalTriggerSequenceStrongComponent
 		val searchGraphAndTriggerSeq = findOptimalTriggerSequenceStrongComponent(graph)
@@ -99,12 +104,50 @@ class AlgebraicLoopVariantProcessor implements IVariantProcessor {
 		scenario.eAllContents.filter(InterpolationAdaptation).forEach[adapt | Assert.isTrue(adapt.order == 0, "Only constant interpolations supported in algebraic loop optimizer. Adaptation " + adapt + " is not a constant interpolation.")]
 		Assert.isTrue(scenario.eAllContents.filter(PowerBondAdaptation).empty, "Powerbond adaptations cannot be used with algebraic loop optimizer, as the optimal trigger sequence may override these.")
 		
+		if (runner !== null) {
+			val graph = transformToCosimUnitGraph(scenario)
+			val triggerSeq = findOptimalTriggerSequence(graph).value
+			
+			// TODO: Turn extrapolation adaptations into interpolations adaptations. 
+			// Since for now we're restricted to zero order approximations, there's no point in doing this. 
+			// Once we support 1st order approximations, then we have to do it.
+			
+			val precedenceNodeOrder = createOperationsOrder(triggerSeq)
+			val Map<Scenario, List<PrecedenceNode>> order = newHashMap()
+			order.put(scenario, precedenceNodeOrder)
+			runner.run(scenario, order, variantID)
+		}
 	}
 	
+	/*
+	 * Convert a trigger sequence into a list of precedence nodes, 
+	 * which can be either cosim units (for doStep operations) or output ports 
+	 * (which translate to getOut and setIn operations).
+	 * The trigger sequence is just a list of cosim units, so we need to come up with the order of output port operations.
+	 * This is done as follows:
+	 * 1. For each cosim unit in the i-th position of the trigger sequence:
+	 * 1.1. any output port is position right after the unit.
+	 */
+	def createOperationsOrder(GraphPath<LazySearchNode, DefaultWeightedEdge> triggerSeq) {
+		val LinkedList<PrecedenceNode> resultList = newLinkedList()
+		val vertexList = triggerSeq.vertexList
+		for (vertexUnit : vertexList) {
+			if (vertexUnit instanceof PartialTriggerSequence) {
+				val IthUnit = vertexUnit.unit
+				// Add cosim unit
+				resultList.addLast(IthUnit)
+				for (outputPort: IthUnit.outputPorts) { // Add output ports.
+					resultList.addLast(outputPort)
+				}
+				
+			} // Ignore the other kinds of trigger sequence.
+		}
+		resultList
+	}
 }
 
 class BasicHeuristic implements AStarAdmissibleHeuristic<LazySearchNode> {
 	override getCostEstimate(LazySearchNode sourceVertex, LazySearchNode targetVertex) {
-		0.0 // TODO Better heuristics might be to get the min weight of possible edges
+		0.0 // TODO Better heuristics might be to get the min weight of possible edges (if there's an algebraic loop)
 	}
 }

+ 55 - 6
HintCOEngine/test/ua/ansymo/hintco/test/AlgebraicLoopProcessingTests.xtend

@@ -1,20 +1,28 @@
 package ua.ansymo.hintco.test
 
+import java.util.Map
+import org.jgrapht.alg.connectivity.GabowStrongConnectivityInspector
 import org.junit.Test
 import ua.ansymo.hintco.AlgebraicLoopVariantProcessor
 import ua.ansymo.hintco.CandidatesGenerator
+import ua.ansymo.hintco.CompleteTriggerSequence
 import ua.ansymo.hintco.ConstraintChecker
 import ua.ansymo.hintco.CosimUnitInstance
+import ua.ansymo.hintco.EmptyTriggerSequence
+import ua.ansymo.hintco.FmuLoader
+import ua.ansymo.hintco.IDed
+import ua.ansymo.hintco.IOutputProcessor
 import ua.ansymo.hintco.ModelQuery
 import ua.ansymo.hintco.ModelStorage
+import ua.ansymo.hintco.OutputPortInstance
+import ua.ansymo.hintco.PartialTriggerSequence
+import ua.ansymo.hintco.RootCandidateScenario
+import ua.ansymo.hintco.SingleCosimRunner
+import ua.ansymo.hintco.VariantProcessor
+import ua.ansymo.hintco.VariantValidator
 
 import static org.junit.Assert.*
-import org.jgrapht.alg.connectivity.GabowStrongConnectivityInspector
-import ua.ansymo.hintco.RootCandidateScenario
-import org.jgrapht.graph.DefaultWeightedEdge
-import ua.ansymo.hintco.EmptyTriggerSequence
-import ua.ansymo.hintco.CompleteTriggerSequence
-import ua.ansymo.hintco.PartialTriggerSequence
+import ua.ansymo.hintco.OutputProcessor
 
 class AlgebraicLoopProcessingTests {
 	
@@ -110,4 +118,45 @@ class AlgebraicLoopProcessingTests {
 		])
 	}
 	
+	@Test
+	def void createOperationsOrderTest(){
+		loadAndRunAlgLoopsSample([ scenario |
+			val algLoopProcessor = new AlgebraicLoopVariantProcessor(null)
+			val graph = algLoopProcessor.transformToCosimUnitGraph(scenario)
+			val searchGraphAndTriggerSeq = algLoopProcessor.findOptimalTriggerSequence(graph)
+			val searchGraph = searchGraphAndTriggerSeq.key
+			val triggerSeq = searchGraphAndTriggerSeq.value
+			
+			val precedenceNodeOrder = algLoopProcessor.createOperationsOrder(triggerSeq)
+			
+			val getIdIdx = [Integer i | (precedenceNodeOrder.get(i) as IDed).identifier]
+			
+			assertEquals("B", getIdIdx.apply(0))
+			assertEquals("3toA", getIdIdx.apply(1))
+			assertEquals("3toC", getIdIdx.apply(2))
+			assertEquals("A", getIdIdx.apply(precedenceNodeOrder.length-3))
+			assertEquals("4toB", getIdIdx.apply(precedenceNodeOrder.length-2))
+			assertEquals("3toC", getIdIdx.apply(precedenceNodeOrder.length-1))
+		])
+	}
+	
+	
+	@Test
+	def void executeMSDCaseStudyTest(){
+		val resultsDirPath = "results-gen/msdalglooptest"
+		val loader = new ModelStorage()
+		val src = loader.loadCandidates("examples/case_study_msd_algloop.hintco")
+		
+//		val runner = new SingleCosimRunner(new IOutputProcessor{
+//			override initialize(RootCandidateScenario scenario, String variantID) {}
+//			override terminate() {}
+//			override setOutputs(int step, double time, Map<OutputPortInstance, Double> outVals) {}
+//		}, new FmuLoader)
+		val runner = new SingleCosimRunner(new OutputProcessor(resultsDirPath), new FmuLoader)
+		val generator = new CandidatesGenerator(new ConstraintChecker,new VariantValidator, new AlgebraicLoopVariantProcessor(runner))
+		generator.createVariantTree(src)
+		generator.generateVariants(src, 1, true)
+		runner.close()
+	}
+	
 }