Claudio Gomes 6 éve
szülő
commit
10aff5cf1f

+ 1 - 0
HintCO.edit/plugin.properties

@@ -112,3 +112,4 @@ _UI_UnitInstance_ports_feature = Ports
 _UI_Scenario_type = Scenario
 _UI_HierarchicalCosimUnit_type = Hierarchical Cosim Unit
 _UI_Scenario_cosimunits_feature = Cosimunits
+_UI_PowerBondAdaptation_pIn_feature = PIn

+ 127 - 7
HintCO.edit/src/ua/ansymo/hintco/provider/HierarchicalCosimUnitItemProvider.java

@@ -11,6 +11,7 @@ import org.eclipse.emf.common.notify.Notification;
 
 import org.eclipse.emf.ecore.EStructuralFeature;
 
+import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
 import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
 import org.eclipse.emf.edit.provider.ViewerNotification;
 
@@ -24,7 +25,7 @@ import ua.ansymo.hintco.HintcoPackage;
  * <!-- end-user-doc -->
  * @generated
  */
-public class HierarchicalCosimUnitItemProvider extends UnitInstanceItemProvider {
+public class HierarchicalCosimUnitItemProvider extends ScenarioItemProvider {
 	/**
 	 * This constructs an instance from a factory and a notifier.
 	 * <!-- begin-user-doc -->
@@ -46,10 +47,102 @@ public class HierarchicalCosimUnitItemProvider extends UnitInstanceItemProvider
 		if (itemPropertyDescriptors == null) {
 			super.getPropertyDescriptors(object);
 
+			addPrecedesPropertyDescriptor(object);
+			addSucceedsPropertyDescriptor(object);
+			addBeforePropertyDescriptor(object);
+			addAfterPropertyDescriptor(object);
 		}
 		return itemPropertyDescriptors;
 	}
 
+	/**
+	 * This adds a property descriptor for the Precedes feature.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	protected void addPrecedesPropertyDescriptor(Object object) {
+		itemPropertyDescriptors.add
+			(createItemPropertyDescriptor
+				(((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+				 getResourceLocator(),
+				 getString("_UI_PrecendenceNode_precedes_feature"),
+				 getString("_UI_PropertyDescriptor_description", "_UI_PrecendenceNode_precedes_feature", "_UI_PrecendenceNode_type"),
+				 HintcoPackage.Literals.PRECENDENCE_NODE__PRECEDES,
+				 true,
+				 false,
+				 true,
+				 null,
+				 null,
+				 null));
+	}
+
+	/**
+	 * This adds a property descriptor for the Succeeds feature.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	protected void addSucceedsPropertyDescriptor(Object object) {
+		itemPropertyDescriptors.add
+			(createItemPropertyDescriptor
+				(((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+				 getResourceLocator(),
+				 getString("_UI_PrecendenceNode_succeeds_feature"),
+				 getString("_UI_PropertyDescriptor_description", "_UI_PrecendenceNode_succeeds_feature", "_UI_PrecendenceNode_type"),
+				 HintcoPackage.Literals.PRECENDENCE_NODE__SUCCEEDS,
+				 true,
+				 false,
+				 true,
+				 null,
+				 null,
+				 null));
+	}
+
+	/**
+	 * This adds a property descriptor for the Before feature.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	protected void addBeforePropertyDescriptor(Object object) {
+		itemPropertyDescriptors.add
+			(createItemPropertyDescriptor
+				(((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+				 getResourceLocator(),
+				 getString("_UI_PrecendenceNode_before_feature"),
+				 getString("_UI_PropertyDescriptor_description", "_UI_PrecendenceNode_before_feature", "_UI_PrecendenceNode_type"),
+				 HintcoPackage.Literals.PRECENDENCE_NODE__BEFORE,
+				 true,
+				 false,
+				 true,
+				 null,
+				 null,
+				 null));
+	}
+
+	/**
+	 * This adds a property descriptor for the After feature.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	protected void addAfterPropertyDescriptor(Object object) {
+		itemPropertyDescriptors.add
+			(createItemPropertyDescriptor
+				(((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+				 getResourceLocator(),
+				 getString("_UI_PrecendenceNode_after_feature"),
+				 getString("_UI_PropertyDescriptor_description", "_UI_PrecendenceNode_after_feature", "_UI_PrecendenceNode_type"),
+				 HintcoPackage.Literals.PRECENDENCE_NODE__AFTER,
+				 true,
+				 false,
+				 true,
+				 null,
+				 null,
+				 null));
+	}
+
 	/**
 	 * This specifies how to implement {@link #getChildren} and is used to deduce an appropriate feature for an
 	 * {@link org.eclipse.emf.edit.command.AddCommand}, {@link org.eclipse.emf.edit.command.RemoveCommand} or
@@ -62,7 +155,8 @@ public class HierarchicalCosimUnitItemProvider extends UnitInstanceItemProvider
 	public Collection<? extends EStructuralFeature> getChildrenFeatures(Object object) {
 		if (childrenFeatures == null) {
 			super.getChildrenFeatures(object);
-			childrenFeatures.add(HintcoPackage.Literals.SCENARIO__COSIMUNITS);
+			childrenFeatures.add(HintcoPackage.Literals.UNIT_INSTANCE__ADAPTATION);
+			childrenFeatures.add(HintcoPackage.Literals.UNIT_INSTANCE__PORTS);
 		}
 		return childrenFeatures;
 	}
@@ -118,7 +212,8 @@ public class HierarchicalCosimUnitItemProvider extends UnitInstanceItemProvider
 		updateChildren(notification);
 
 		switch (notification.getFeatureID(HierarchicalCosimUnit.class)) {
-			case HintcoPackage.HIERARCHICAL_COSIM_UNIT__COSIMUNITS:
+			case HintcoPackage.HIERARCHICAL_COSIM_UNIT__ADAPTATION:
+			case HintcoPackage.HIERARCHICAL_COSIM_UNIT__PORTS:
 				fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false));
 				return;
 		}
@@ -138,13 +233,38 @@ public class HierarchicalCosimUnitItemProvider extends UnitInstanceItemProvider
 
 		newChildDescriptors.add
 			(createChildParameter
-				(HintcoPackage.Literals.SCENARIO__COSIMUNITS,
-				 HintcoFactory.eINSTANCE.createHierarchicalCosimUnit()));
+				(HintcoPackage.Literals.UNIT_INSTANCE__ADAPTATION,
+				 HintcoFactory.eINSTANCE.createXorUnitAdaptation()));
+
+		newChildDescriptors.add
+			(createChildParameter
+				(HintcoPackage.Literals.UNIT_INSTANCE__ADAPTATION,
+				 HintcoFactory.eINSTANCE.createCombineAdaptation()));
+
+		newChildDescriptors.add
+			(createChildParameter
+				(HintcoPackage.Literals.UNIT_INSTANCE__ADAPTATION,
+				 HintcoFactory.eINSTANCE.createMultiRateAdaptation()));
+
+		newChildDescriptors.add
+			(createChildParameter
+				(HintcoPackage.Literals.UNIT_INSTANCE__ADAPTATION,
+				 HintcoFactory.eINSTANCE.createPowerBondAdaptation()));
+
+		newChildDescriptors.add
+			(createChildParameter
+				(HintcoPackage.Literals.UNIT_INSTANCE__PORTS,
+				 HintcoFactory.eINSTANCE.createInputPortInstance()));
+
+		newChildDescriptors.add
+			(createChildParameter
+				(HintcoPackage.Literals.UNIT_INSTANCE__PORTS,
+				 HintcoFactory.eINSTANCE.createHierarchicalUnitPort()));
 
 		newChildDescriptors.add
 			(createChildParameter
-				(HintcoPackage.Literals.SCENARIO__COSIMUNITS,
-				 HintcoFactory.eINSTANCE.createCosimUnitInstance()));
+				(HintcoPackage.Literals.UNIT_INSTANCE__PORTS,
+				 HintcoFactory.eINSTANCE.createOutputPortInstance()));
 	}
 
 }

+ 23 - 0
HintCO.edit/src/ua/ansymo/hintco/provider/PowerBondAdaptationItemProvider.java

@@ -48,6 +48,7 @@ public class PowerBondAdaptationItemProvider extends UnitAdaptationItemProvider
 			addEffortPropertyDescriptor(object);
 			addFlowPropertyDescriptor(object);
 			addPOutPropertyDescriptor(object);
+			addPInPropertyDescriptor(object);
 			addNamePropertyDescriptor(object);
 		}
 		return itemPropertyDescriptors;
@@ -119,6 +120,28 @@ public class PowerBondAdaptationItemProvider extends UnitAdaptationItemProvider
 				 null));
 	}
 
+	/**
+	 * This adds a property descriptor for the PIn feature.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	protected void addPInPropertyDescriptor(Object object) {
+		itemPropertyDescriptors.add
+			(createItemPropertyDescriptor
+				(((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+				 getResourceLocator(),
+				 getString("_UI_PowerBondAdaptation_pIn_feature"),
+				 getString("_UI_PropertyDescriptor_description", "_UI_PowerBondAdaptation_pIn_feature", "_UI_PowerBondAdaptation_type"),
+				 HintcoPackage.Literals.POWER_BOND_ADAPTATION__PIN,
+				 true,
+				 false,
+				 true,
+				 null,
+				 null,
+				 null));
+	}
+
 	/**
 	 * This adds a property descriptor for the Name feature.
 	 * <!-- begin-user-doc -->

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 24 - 2
HintCO/model/Candidates.genmodel


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 62 - 2
HintCO/model/hintco.ecore


+ 81 - 19
HintCO/src/ua/ansymo/hintco/AdaptedFMUInstance.xtend

@@ -18,8 +18,8 @@ enum MODE {
 class AdaptedFMUInstance extends FmuInstance {
 	
 	var int innerRate = 1
-	val Map<String, List<IAdaptedInputPort>> adaptedInPorts = newHashMap()
-	val Map<String, IAdaptedOutputPort> adaptedOutPorts = newHashMap()
+	Map<String, List<IAdaptedInputPort>> adaptedInPorts = newHashMap()
+	Map<String, IAdaptedOutputPort> adaptedOutPorts = newHashMap()
 	
 	Logger logger = LoggerFactory.getLogger(typeof(CosimRunner))
 	
@@ -29,19 +29,19 @@ class AdaptedFMUInstance extends FmuInstance {
 	
 	List<OutputPortInstance> outputPorts
 	
-	new(IFmiComponent f, UnitInstance u) {
+	new(UnitInstance u, IFmiComponent f,  Map<Scenario, List<PrecendenceNode>> scenarioNodesMap) {
 		super(f)
 		unit = u
-		instantiateAdaptations(unit)
+		instantiateAdaptations(unit, scenarioNodesMap)
 		currentMode = MODE.NOT_INIT
 		outputPorts = unit.outputPorts
 	}
 	
-	new(UnitInstance unit) {
-		this(null, unit)
+	new(UnitInstance unit, Map<Scenario, List<PrecendenceNode>> scenarioNodesMap) {
+		this(unit, null, scenarioNodesMap)
 	}
 	
-	def instantiateAdaptations(UnitInstance unit) {
+	def instantiateAdaptations(UnitInstance unit, Map<Scenario, List<PrecendenceNode>> scenarioNodesMap) {
 		val unitAdaptations = unit.selectedAdaptations
 		
 		if (!unitAdaptations.empty){
@@ -53,22 +53,16 @@ class AdaptedFMUInstance extends FmuInstance {
 			
 			// Check if there is a power bond adaptation
 			if (adaptation instanceof PowerBondAdaptation) {
-				var FeedThroughAdaptedPort powerTermStorage
+				
+				val siblings = scenarioNodesMap.get(unit.scenario)
+				val dualAdaptation = adaptation.dual
 				// Create Store input for the input port that goes in the power calculation
+				//  if this unit has to extrapolate one of the power inputs, then it is the one that is going to make the correction.
 				if (adaptation.effort instanceof InputPortInstance){
-					powerTermStorage = new FeedThroughAdaptedPort(adaptation.effort.identifier, this)
-					addInAdaptation(adaptation.effort.identifier, powerTermStorage)
+					addPowerPortAdaptations(adaptation, adaptation.effort, dualAdaptation.effort, siblings)
 				} else {
-					powerTermStorage = new FeedThroughAdaptedPort(adaptation.flow.identifier, this)
-					addInAdaptation(adaptation.flow.identifier, powerTermStorage)
+					addPowerPortAdaptations(adaptation, adaptation.flow, dualAdaptation.flow, siblings)
 				}
-				
-				// Create new adapted output for the pOut port
-				adaptedOutPorts.put(adaptation.POut.identifier, new PowerOutAdaptedPort(adaptation, powerTermStorage, this))
-				
-				// Create adapted input for the pIn port.
-				addInAdaptation(adaptation.PIn.identifier, new StoreAdaptedPort())
-				
 			}
 		}
 		
@@ -87,11 +81,59 @@ class AdaptedFMUInstance extends FmuInstance {
 						addInAdaptation(p.identifier, new ExtrapolationAdaptedPort(portAdaptation, this))
 					}
 				}
+				
+				// Check for incompatibilities
+				if (adaptedInPorts.containsKey(p.identifier)){
+					// Port approximations are not compatible with power input corrections.
+					// We need a better way to coordinate which port adaptations gets to propagate its value to the internal fmu.
+					val noApps = adaptedInPorts.get(p.identifier).filter(ApproximationAdaptation).empty
+					val noPCs = adaptedInPorts.get(p.identifier).filter(PowerCorrectionPort).empty
+					Assert.isTrue((!noApps && noPCs) 
+									|| (noApps && !noPCs)
+									|| (noApps && noPCs))
+				}
 			}
 		}
 		
 	}
 	
+	def private addPowerPortAdaptations(PowerBondAdaptation adaptation, PortInstance inputPowerTerm, PortInstance dualPowerTerm, List<PrecendenceNode> siblings) {
+
+		var StoreAdaptedPort powerTermStorage
+		
+		var PowerOutAdaptedPort powerOutAdaptor
+		
+		val powerInStorage = new StoreAdaptedPort()
+		
+		if (executesBefore(dualPowerTerm, dualPowerTerm.unit, siblings)){
+			powerTermStorage = new StoreAdaptedPort()
+			powerOutAdaptor = new PowerOutAdaptedPort(adaptation, powerTermStorage, this)
+			val powerCorrectionPort = new PowerCorrectionPort(inputPowerTerm.identifier, powerOutAdaptor, powerInStorage, this)
+			
+			addInAdaptation(inputPowerTerm.identifier, powerCorrectionPort)
+		} else {
+			powerTermStorage = new FeedThroughAdaptedPort(inputPowerTerm.identifier, this)
+			powerOutAdaptor = new PowerOutAdaptedPort(adaptation, powerTermStorage, this)
+		}
+		
+		// Create new adapted output for the pOut port
+		adaptedOutPorts.put(adaptation.POut.identifier, powerOutAdaptor)
+		
+		// Add storage to input power term.
+		addInAdaptation(inputPowerTerm.identifier, powerTermStorage)
+		
+		// Create adapted input for the pIn port.
+		addInAdaptation(adaptation.PIn.identifier, powerInStorage)
+		
+		
+		
+		return powerTermStorage
+	}
+	
+	def private executesBefore(PortInstance port, UnitInstance unit, List<PrecendenceNode> nodes) {
+		nodes.indexOf(port) < nodes.indexOf(unit)
+	}
+	
 	override enterInitializationMode() throws FmuInvocationException {
 		currentMode = MODE.INITING
 		super.enterInitializationMode()
@@ -211,4 +253,24 @@ class AdaptedFMUInstance extends FmuInstance {
 		adaptedInPorts.get(id).add(port)
 	}
 	
+	override startCosimStep(double time, double stepSize) {
+		// inform port adaptations
+		for (ap : adaptedInPorts.values.flatten){
+			ap.startCosimStep(time, stepSize)
+		}
+		for (ap : adaptedOutPorts.values){
+			ap.startCosimStep(time, stepSize)
+		}
+	}
+	
+	override endCosimStep(double time, double stepSize) {
+		// inform port adaptations
+		for (ap : adaptedInPorts.values.flatten){
+			ap.endCosimStep(time, stepSize)
+		}
+		for (ap : adaptedOutPorts.values){
+			ap.endCosimStep(time, stepSize)
+		}
+	}
+	
 }

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

@@ -30,4 +30,7 @@ abstract class ApproximationAdaptedPort implements IAdaptedInputPort {
 		this.previous_val = current_val
 	}
 	
+	override startCosimStep(double time, double stepSize) {}
+	
+	override endCosimStep(double time, double stepSize) {}
 }

+ 47 - 15
HintCO/src/ua/ansymo/hintco/CandidatesGenerator.xtend

@@ -6,6 +6,8 @@ import java.util.HashMap
 import java.util.List
 import java.util.Set
 import org.eclipse.core.runtime.Assert
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
 
 class CandidatesGenerator {
 	
@@ -13,6 +15,8 @@ class CandidatesGenerator {
 	IVariantValidator variantValidator
 	IVariantProcessor processor
 	
+	Logger logger = LoggerFactory.getLogger(typeof(CandidatesGenerator))
+	
 	new (IConstraintChecker c, IVariantValidator v, IVariantProcessor p){
 		constraintChecker = c
 		variantValidator = v
@@ -31,7 +35,8 @@ class CandidatesGenerator {
 		// Assumes that there is a variant diagram created.
 		Assert.isTrue(cs.root !== null)
 		
-		recGenerateVariants(newLinkedList(cs.root), cs, new ConstraintsStack(), maxVariants)
+		val genVariants = recGenerateVariants(newLinkedList(cs.root), cs, new ConstraintsStack(), maxVariants)
+		return genVariants
 	}
 	
 	def generateVariants(Candidates cs){
@@ -81,6 +86,7 @@ class CandidatesGenerator {
 				pbAdaptation.POut.valueTo.add(pbAdaptation.dual.PIn)
 			}
 		}
+		
 	}
 	
 	def createVariantTree(Candidates cs){
@@ -128,16 +134,20 @@ class CandidatesGenerator {
 		val n = ns.peek() // Head of the queue is the current element being visited.
 		
 		try {
-			switch n.alternative {
+			val alternative = n.alternative
+			switch alternative {
 				RootCandidateScenario: {
 					/*
 					 * Recursively create I/O and DoStep constraints.
 					 */
-					val scenario = (n.alternative as RootCandidateScenario)
+					val scenario = (alternative as RootCandidateScenario)
+					logger.debug("Processing Alternative RootCandidateScenario {}", scenario.identifier)
 					// Outports/HierarchicalPorts -> InPorts/HierarchicalPorts
 					for (outP : scenario.eAllContents.filter(OutputPortInstance).toIterable) {
 						for (inP : outP.valueTo) {
-							addConstraint(outP, inP, constraints, n, cs)
+							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)
 						}
 					}
 					
@@ -148,13 +158,17 @@ class CandidatesGenerator {
 																//Otherwise it is not an input port.
 													
 					) {
-						addConstraint(inP, inP.unit, constraints, n, cs)
+						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("Success: {}", success)
 					}
 					
 					// The DoStep of each unit can only happen after the doStep of the parent unit.
 					for (parentUnit : scenario.eAllContents.filter(HierarchicalCosimUnit).toIterable){
 						for (childUnit : parentUnit.cosimunits){
-							addConstraint(parentUnit, childUnit, constraints, n, cs)
+							logger.debug("Attempting to add constraint {}->{}.", parentUnit.identifier, childUnit.identifier)
+							val success = addConstraint(parentUnit, childUnit, constraints, n, cs)
+							logger.debug("Success: {}", success)
 						}
 					}
 					
@@ -162,8 +176,9 @@ class CandidatesGenerator {
 				ExtrapolationAdaptation: {
 					// Add precedence constraints to the ports that provide value to this port.
 					// and ensure the doStep ordering.
-					val adaptation = n.alternative as ExtrapolationAdaptation
+					val adaptation = alternative as ExtrapolationAdaptation
 					val adapted = adaptation.adapted()
+					logger.debug("Processing Alternative ExtrapolationAdaptation of {}", adapted.identifier)
 					Assert.isNotNull(adapted)
 					Assert.isTrue(adapted instanceof InputPortInstance)
 					val adaptedPort = adapted as InputPortInstance
@@ -185,11 +200,14 @@ class CandidatesGenerator {
 					}
 					Assert.isTrue(siblingAdaptedPort !== null)
 					
-					addConstraint(siblingAdaptedPort, ancestorSrcUnit, constraints, n, cs)
+					logger.debug("Attempting to add constraint {}.{}->{}.", siblingAdaptedPort.unit.identifier, siblingAdaptedPort.identifier, ancestorSrcUnit.identifier)
+					val success = addConstraint(siblingAdaptedPort, ancestorSrcUnit, constraints, n, cs)
+					logger.debug("Success: {}", success)
 				}
 				InterpolationAdaptation: {
-					val adaptation = n.alternative as InterpolationAdaptation
+					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
@@ -202,7 +220,11 @@ class CandidatesGenerator {
 						ancestorSrcPort = ancestorSrcUnit.ports.findFirst[p | adaptedPort.getsValueFrom(p)]
 					}
 					
-					addConstraint(ancestorSrcUnit, ancestorSrcPort, constraints, n, cs)
+					
+					
+					logger.debug("Attempting to add constraint {}->{}.{}.", ancestorSrcUnit.identifier, ancestorSrcPort.unit.identifier, ancestorSrcPort.identifier)
+					val success = addConstraint(ancestorSrcUnit, ancestorSrcPort, constraints, n, cs)
+					logger.debug("Success: {}", success)
 					
 					// Redundant, as the srcPort is connected to the adaptedPort
 					// addConstraint(srcPort, adaptedPort, constraints, n, cs)
@@ -217,14 +239,23 @@ class CandidatesGenerator {
 					// Nothing to do.
 				}
 				PowerBondAdaptation: {
-					// Nothing to do.
-					// TODO: Add constraints to make sure the values of the power output port is compute after its dependencies have been set.
+					// TODO Clean up
+//					val adaptation = alternative as PowerBondAdaptation
+//					val adapted = adaptation.adapted()
+//					logger.debug("Processing Alternative PowerBondAdaptation of {}", adapted.identifier)
+//					Assert.isNotNull(adapted)
+//					Assert.isTrue(adapted instanceof UnitInstance)
+//					val unit = adapted as UnitInstance
+//					
+//					logger.debug("Attempting to add constraint {}->{}.{}.", unit.identifier, adaptation.POut.unit.identifier, adaptation.POut.identifier)
+//					val success = addConstraint(unit, adaptation.POut, constraints, n, cs)
+//					logger.debug("Success: {}", success)
 				}
 				MultiRateAdaptation: {
 					// Nothing to do
 				}
 				default:
-					if (n.alternative !== null){
+					if (alternative !== null){
 						throw new UnsupportedOperationException()
 					}
 			}
@@ -256,8 +287,9 @@ class CandidatesGenerator {
 					}
 				}
 			}
-		} catch (InterruptedException e) {
+		} catch (InfeasibleConstraintException e) {
 			// Do nothing.
+			logger.debug("The last added constraint is infeasible. Trying other alternatives.")
 		}
 		
 		// Revert changes in model
@@ -292,7 +324,7 @@ class CandidatesGenerator {
 				src.precedes.add(trg)
 				return true
 			} else {
-				throw new InterruptedException() 
+				throw new InfeasibleConstraintException() 
 			}
 		} else {
 			return false

+ 13 - 1
HintCO/src/ua/ansymo/hintco/CosimRunUtils.xtend

@@ -108,8 +108,14 @@ class CosimRunUtils {
 		return outVals
 	}
 	
-	def static executeStep(double time, double stepSize, List<PrecendenceNode> nodes, Set<InputPortInstance> inPorts, Map<UnitInstance, IFmuInstance> fmuInstanceMap) {
+	def static executeStep(double time, double stepSize, List<PrecendenceNode> nodes, List<UnitInstance> units, Set<InputPortInstance> inPorts, Map<UnitInstance, IFmuInstance> fmuInstanceMap) {
 		logger.debug("Co-simulation step start at time {} -> {}.", time, time + stepSize)
+		
+		// Let units know that a cosim step is starting.
+		for (u : units){
+			fmuInstanceMap.get(u).startCosimStep(time, stepSize)
+		}
+		
 		for (n : nodes) {
 			switch (n) {
 				UnitInstance: {
@@ -133,6 +139,12 @@ class CosimRunUtils {
 				}
 			}
 		}
+		
+		// Let units know that a cosim step has finished.
+		for (u : units){
+			fmuInstanceMap.get(u).endCosimStep(time, stepSize)
+		}
+		
 		logger.debug("Co-simulation step end at time {} -> {}.", time, time + stepSize)
 	}
 }

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

@@ -69,7 +69,7 @@ class CosimRunner implements ICosimRunner, Closeable {
 		var i = 0
 		while (time < stopTime || MathUtils.isApproximatelyEqual(time, stopTime, stepSize*1e-3)){
 			
-			executeStep(time, stepSize, nodes, childInputPorts, fmuInstanceMap)
+			executeStep(time, stepSize, nodes, units, childInputPorts, fmuInstanceMap)
 			
 			// Advance time
 			logger.debug("Time advance: {} -> {}", time, time + stepSize)

+ 1 - 1
HintCO/src/ua/ansymo/hintco/FmuLoader.xtend

@@ -47,7 +47,7 @@ class FmuLoader implements IFmuLoader {
 								}
 								override stepFinished(Fmi2Status status) {}
 							})
-				fmuInstance = new AdaptedFMUInstance(internalFmuComponent, instance)
+				fmuInstance = new AdaptedFMUInstance(instance, internalFmuComponent, scenarioNodesMap)
 			}
 			default: {
 				Assert.isTrue(false)

+ 2 - 3
HintCO/src/ua/ansymo/hintco/HierarchicalInstance.xtend

@@ -11,7 +11,6 @@ import org.slf4j.LoggerFactory
 import static ua.ansymo.hintco.CosimRunUtils.*
 import java.util.Set
 
-// TODO Possible reuse mechanism: extends CosimRunner
 class HierarchicalInstance extends AdaptedFMUInstance {
 	
 	FmuLoader loader
@@ -28,7 +27,7 @@ class HierarchicalInstance extends AdaptedFMUInstance {
 	Set<InputPortInstance> inPorts
 	
 	new(HierarchicalCosimUnit u, Map<Scenario, List<PrecendenceNode>> scenarioNodesMap, FmuLoader l) {
-		super(u)
+		super(u, scenarioNodesMap)
 		loader = l
 		unit = u
 		Assert.isTrue(scenarioNodesMap.containsKey(unit))
@@ -114,7 +113,7 @@ class HierarchicalInstance extends AdaptedFMUInstance {
 		 * The input values have been propagated.
 		 * All we have to do now is step the inner units, and propagate their values in order.
 		 */
-		 executeStep(inner_time, micro_step, nodes, inPorts, fmuInstanceMap)
+		 executeStep(inner_time, micro_step, nodes, units, inPorts, fmuInstanceMap)
 		 return Fmi2Status.OK
 	}
 	

+ 4 - 0
HintCO/src/ua/ansymo/hintco/IAdaptedPort.xtend

@@ -4,4 +4,8 @@ interface IAdaptedPort {
 	def void startStep()
 	
 	def void endStep()
+	
+	def void startCosimStep(double time, double stepSize)
+	
+	def void endCosimStep(double time, double stepSize)
 }

+ 3 - 0
HintCO/src/ua/ansymo/hintco/IFmuInstance.xtend

@@ -13,4 +13,7 @@ interface IFmuInstance {
 	def void setReal(String varName, double v)
 	def void free()	
 	def void outputSnapshot(Map<OutputPortInstance, Double> outVals)
+	def void startCosimStep(double time, double stepSize)
+	def void endCosimStep(double time, double stepSize)
+	
 }

+ 5 - 0
HintCO/src/ua/ansymo/hintco/InfeasibleConstraintException.xtend

@@ -0,0 +1,5 @@
+package ua.ansymo.hintco
+
+class InfeasibleConstraintException extends RuntimeException {
+	
+}

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

@@ -10,4 +10,5 @@ class InterpolationAdaptedPort extends ApproximationAdaptedPort {
 		val o = previous_val + ((current_val - previous_val)/H)*(dt+h)
 		fmu.setInnerReal(portId, o)
 	}
+	
 }

+ 43 - 0
HintCO/src/ua/ansymo/hintco/PowerCorrectionPort.xtend

@@ -0,0 +1,43 @@
+package ua.ansymo.hintco
+
+class PowerCorrectionPort extends StoreAdaptedPort {
+	
+	var AdaptedFMUInstance fmu
+	
+	var String portId
+	
+	var double accumulatedDeficit = 0.0
+	var double energyDeficit = 0.0
+	
+	var Kp = 0.9
+	var Ki = 0.2
+	
+	PowerOutAdaptedPort pOut
+	StoreAdaptedPort pIn
+	
+	new(String pId, PowerOutAdaptedPort po, StoreAdaptedPort pi, AdaptedFMUInstance f) {
+		fmu = f
+		portId = pId
+		pOut = po
+		pIn = pi
+	}
+	
+	override startStep() {}
+	
+	override endStep() {}
+	
+	override endCosimStep(double time, double stepSize) {
+		val powerIn = pIn.storedVal
+		val powerOut = pOut.real
+		energyDeficit = (powerIn - powerOut)/stepSize
+		// Positive residual means this fmu has a deficit of energy.
+		accumulatedDeficit = accumulatedDeficit + energyDeficit
+	}
+	
+	override computeReal(double t, double dt, double h, double H) {
+		val givenInput = storedVal
+		val piControlOut = Kp*energyDeficit + Ki*accumulatedDeficit
+		val actualInput = givenInput + piControlOut
+		fmu.setInnerReal(portId, actualInput)
+	}
+}

+ 6 - 2
HintCO/src/ua/ansymo/hintco/PowerOutAdaptedPort.xtend

@@ -34,11 +34,15 @@ class PowerOutAdaptedPort implements IAdaptedOutputPort {
 	}
 	
 	override startStep() {
-		
 	}
 	
 	override endStep() {
-		
+	}
+	
+	override startCosimStep(double time, double stepSize) {
+	}
+	
+	override endCosimStep(double time, double stepSize) {
 	}
 	
 }

+ 6 - 0
HintCO/src/ua/ansymo/hintco/StoreAdaptedPort.xtend

@@ -16,4 +16,10 @@ class StoreAdaptedPort implements IAdaptedInputPort {
 	
 	override computeReal(double t, double dt, double h, double H) {}
 	
+	override startCosimStep(double time, double stepSize) {
+	}
+	
+	override endCosimStep(double time, double stepSize) {
+	}
+	
 }

+ 12 - 12
HintCO/test/ua/ansymo/hintco/test/AdaptedFMUTest.xtend

@@ -55,15 +55,15 @@ class AdaptedFMUTest {
 			override instantiate(UnitInstance u, Map<Scenario, List<PrecendenceNode>> scenarioNodesMap) {
 				assertTrue(u===source || u===sink)
 				if (u===source){
-					return new AdaptedFMUInstance(new MockSourceFmuInstance[t, H | 
+					return new AdaptedFMUInstance(u, new MockSourceFmuInstance[t, H | 
 						t+H
-					], u)
+					], null)
 				}
 				if (u===sink){
-					return new AdaptedFMUInstance(new MockSinkFmuInstance[t, H, in | 
+					return new AdaptedFMUInstance(u, new MockSinkFmuInstance[t, H, in | 
 						numInnerSteps.add(t)
 						assertTrue(MathUtils.isApproximatelyEqual(in, t+H, 1e-6))
-					], u)
+					], null)
 				}
 				return null
 			}
@@ -101,15 +101,15 @@ class AdaptedFMUTest {
 			override instantiate(UnitInstance u, Map<Scenario, List<PrecendenceNode>> scenarioNodesMap) {
 				assertTrue(u===source || u===sink)
 				if (u===source){
-					return new AdaptedFMUInstance(new MockSourceFmuInstance[t, H | 
+					return new AdaptedFMUInstance(u, new MockSourceFmuInstance[t, H | 
 						t+H
-					], u)
+					], null)
 				}
 				if (u===sink){
-					return new AdaptedFMUInstance(new MockSinkFmuInstance[t, H, in | 
+					return new AdaptedFMUInstance(u, new MockSinkFmuInstance[t, H, in | 
 						numInnerSteps.add(t)
 						assertTrue(MathUtils.isApproximatelyEqual(in, t+H, 1e-6))
-					], u)
+					], null)
 				}
 				return null
 			}
@@ -148,17 +148,17 @@ class AdaptedFMUTest {
 			override instantiate(UnitInstance u, Map<Scenario, List<PrecendenceNode>> scenarioNodesMap) {
 				assertTrue(u===source || u===sink)
 				if (u===source){
-					return new AdaptedFMUInstance(new MockSourceFmuInstance[t, H | 
+					return new AdaptedFMUInstance(u, new MockSourceFmuInstance[t, H | 
 						t+H
-					], u)
+					], null)
 				}
 				if (u===sink){
-					return new AdaptedFMUInstance(new MockSinkFmuInstance[t, H, in | 
+					return new AdaptedFMUInstance(u, new MockSinkFmuInstance[t, H, in | 
 						numInnerSteps.add(t)
 						if (t > 2.0) {
 							assertTrue(MathUtils.isApproximatelyEqual(in, t+H, 1e-6))
 						}
-					], u)
+					], null)
 				}
 				return null
 			}

+ 10 - 9
HintCO/test/ua/ansymo/hintco/test/CosimRunnerTest.xtend

@@ -1,6 +1,8 @@
 package ua.ansymo.hintco.test
 
 import java.io.File
+import java.util.Map
+import org.apache.commons.io.FileUtils
 import org.intocps.fmi.Fmi2Status
 import org.intocps.fmi.IFmuCallback
 import org.intocps.fmi.jnifmuapi.Factory
@@ -11,17 +13,15 @@ import ua.ansymo.hintco.CandidatesGenerator
 import ua.ansymo.hintco.ConstraintChecker
 import ua.ansymo.hintco.CosimRunner
 import ua.ansymo.hintco.FmuLoader
+import ua.ansymo.hintco.IOutputProcessor
 import ua.ansymo.hintco.ModelStorage
+import ua.ansymo.hintco.OutputPortInstance
 import ua.ansymo.hintco.OutputProcessor
+import ua.ansymo.hintco.RootCandidateScenario
 import ua.ansymo.hintco.VariantProcessor
 import ua.ansymo.hintco.VariantValidator
 
 import static org.junit.Assert.*
-import org.apache.commons.io.FileUtils
-import ua.ansymo.hintco.IOutputProcessor
-import ua.ansymo.hintco.RootCandidateScenario
-import java.util.Map
-import ua.ansymo.hintco.OutputPortInstance
 import static ua.ansymo.hintco.ModelQuery.*
 
 class CosimRunnerTest {
@@ -228,17 +228,18 @@ class CosimRunnerTest {
 	@Test
 	@Ignore // Because it only works on windows.
 	def void executeCosimulationTestDoubleLoopPowerBond(){
-		//System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug")
-		//System.setProperty("org.slf4j.simpleLogger.logFile", "powerbond.log")
+		System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug")
+		System.setProperty("org.slf4j.simpleLogger.logFile", "powerbond.log")
 		val resultsDirPath = "results-gen/cosimTestDLoopPBond"
 		val loader = new ModelStorage()
+		val src = loader.loadCandidates("instances/case_study_double_loop_pbond.hintco")
 		val runner = new CosimRunner(new OutputProcessor(resultsDirPath), new FmuLoader)
 		val generator = new CandidatesGenerator(new ConstraintChecker,new VariantValidator, new VariantProcessor(runner))
-		val src = loader.loadCandidates("instances/case_study_double_loop_pbond.hintco")
 		generator.processAdaptations(src)
 		generator.createVariantTree(src)
-		generator.generateVariants(src, 1)
+		val numVariants = generator.generateVariants(src, 1)
 		runner.close()
+		assertEquals(1, numVariants)
 	}
 	
 	@Test