Browse Source

prepared for eval+started eval

DESKTOP-L7IQHES\Jonas 2 years ago
parent
commit
4fc027d79c
34 changed files with 665 additions and 283 deletions
  1. BIN
      exampleNetworks/MyExamples/eval-f.holon
  2. BIN
      exampleNetworks/MyExamples/eval-flex.holon
  3. BIN
      exampleNetworks/MyExamples/eval.holon
  4. BIN
      exampleNetworks/MyExamples/eval02.holon
  5. BIN
      exampleNetworks/MyExamples/eval02h-25.holon
  6. BIN
      exampleNetworks/MyExamples/eval02h-scenario.holon
  7. BIN
      exampleNetworks/MyExamples/eval02h.holon
  8. BIN
      exampleNetworks/MyExamples/merge3-flex.holon
  9. BIN
      exampleNetworks/MyExamples/scenario01-25.holon
  10. BIN
      exampleNetworks/MyExamples/scenario01-25h.holon
  11. BIN
      exampleNetworks/MyExamples/scenario02-25h.holon
  12. 76 18
      src/classes/Holon.java
  13. 9 5
      src/classes/holonControlUnit/CommunicationModule.java
  14. 37 14
      src/classes/holonControlUnit/FlexibilityManager.java
  15. 58 42
      src/classes/holonControlUnit/HierarchyControlUnit.java
  16. 42 21
      src/classes/holonControlUnit/HolonControlUnit.java
  17. 39 11
      src/classes/holonControlUnit/StateEstimator.java
  18. 135 102
      src/classes/holonControlUnit/TargetStateAssembler.java
  19. 10 3
      src/classes/holonControlUnit/messages/MergeMsg.java
  20. 26 0
      src/classes/holonControlUnit/messages/MergeOrderMsg.java
  21. 1 1
      src/classes/holonControlUnit/messages/Message.java
  22. 3 25
      src/classes/holonControlUnit/messages/NeighborhoodMsg.java
  23. 3 8
      src/classes/holonControlUnit/messages/OrderMsg.java
  24. 1 1
      src/ui/controller/LoadController.java
  25. 127 2
      src/ui/controller/SimulationManager.java
  26. 2 2
      src/ui/model/Model.java
  27. 1 1
      src/ui/model/Passiv.java
  28. 2 2
      src/ui/view/GUI.java
  29. 4 4
      src/ui/view/holarchy/HolarchyPanel.java
  30. 1 1
      src/ui/view/holarchy/HolarchyTreePanel.java
  31. 7 7
      src/ui/view/holarchy/HolarchyWindow.java
  32. 11 9
      src/ui/view/holarchy/HolonInfoPanel.java
  33. 4 4
      src/ui/view/outliner/HolonView.java
  34. 66 0
      tests/holon_control_unit_evaluation/Main.java

BIN
exampleNetworks/MyExamples/eval-f.holon


BIN
exampleNetworks/MyExamples/eval-flex.holon


BIN
exampleNetworks/MyExamples/eval.holon


BIN
exampleNetworks/MyExamples/eval02.holon


BIN
exampleNetworks/MyExamples/eval02h-25.holon


BIN
exampleNetworks/MyExamples/eval02h-scenario.holon


BIN
exampleNetworks/MyExamples/eval02h.holon


BIN
exampleNetworks/MyExamples/merge3-flex.holon


BIN
exampleNetworks/MyExamples/scenario01-25.holon


BIN
exampleNetworks/MyExamples/scenario01-25h.holon


BIN
exampleNetworks/MyExamples/scenario02-25h.holon


+ 76 - 18
src/classes/Holon.java

@@ -7,6 +7,8 @@ import java.util.List;
 import java.util.UUID;
 
 import classes.holonControlUnit.HolonControlUnit;
+import classes.holonControlUnit.OptimizationManager;
+import classes.holonControlUnit.StateEstimator.StateIndicator;
 import ui.controller.Control;
 import ui.model.DecoratedNetwork;
 import ui.model.IntermediateCableWithState;
@@ -28,6 +30,9 @@ public class Holon {
 	/** stores whether the part between this holon and the child is occupied by the superholon */
 	private HashMap<Holon, ArrayList<Edge>> pathsToChildren;
 	
+	private int mergeCounter = 0, splitCounter = 0;
+	private int[] stateCounter = {0, 0, 0};
+	
 	public Holon(String name, Model model) {
 		this.name = name;
 		this.holonObject = null;
@@ -147,7 +152,7 @@ public class Holon {
 
 	public void reassignAllChildren(Holon other) {
 		for(Holon child: this.childHolons) {
-			other.merge(child);
+			other.merge(child, true);
 		}
 		childHolons.clear();
 	}
@@ -229,7 +234,7 @@ public class Holon {
 		}
 		//Remove holons
 		for(Holon holon : removeList) {
-			holon.split(stateHolon);
+			holon.split(null, true);
 		}
 		
 	}
@@ -278,14 +283,14 @@ public class Holon {
 	 * merge this holon as a child with the holon specified by the id
 	 * @param id
 	 */
-	public void merge(String id) {
+	public void merge(String id, boolean allowOccupiedPath) {
 		if(id.equals("State Holon")) {
-			this.split(this.model.getStateHolon());
+			this.split(this.model.getStateHolon(), allowOccupiedPath);
 			return;
 		}
 		Holon h = this.model.getHolonsByID().get(id);
 		if(h != null) {
-			h.split(this);
+			h.split(this, allowOccupiedPath);
 		}
 	}
 	
@@ -293,7 +298,7 @@ public class Holon {
 	 * merge this holon with the specified child holon
 	 * @param child
 	 */
-	public void merge(Holon child) {
+	public void merge(Holon child, boolean allowOccupiedPath) {
 		if(!this.model.getHolonsByID().containsKey(child.getUniqueID())) {
 			System.err.println("could not find: "+child.getHolonObject());
 			return;
@@ -307,7 +312,8 @@ public class Holon {
 			this.addChild(child);
 			return;
 		}
-		
+		this.mergeCounter++;
+//		System.out.println(this.uniqueID+" merge with "+child.getUniqueID());
 		HashMap<Float, ArrayList<Edge>> paths = this.model.getShortestPathToHolarchy(this.minModel, child.getMinimumModel());
 		HashMap<Float, ArrayList<Edge>> free_paths = new HashMap<Float, ArrayList<Edge>>();
 		HashMap<Float, ArrayList<Edge>> occ_paths = new HashMap<Float, ArrayList<Edge>>();
@@ -326,13 +332,15 @@ public class Holon {
 			}
 		}
 		
+//		System.out.println("free: "+free_paths+"\noccupied: "+occ_paths);
+		
 		if(free_paths.size() > 0) {
 			//there is a free path, take it and add child directly to sub holons
 			ArrayList<Edge> path = free_paths.get(getShortestPath(free_paths));
 			Holon holder = this.containsPath(path, this);
 			if(holder != null && !holder.equals(this)) {
 				//the path already used by a child holon
-				holder.merge(child);
+				holder.merge(child, true);
 				return;
 			}
 			this.addChild(child);
@@ -350,8 +358,9 @@ public class Holon {
 		//take the shortest path occupied by another holon
 		ArrayList<Edge> path = shortestPaths.get(0);
 		Holon holder = occ_by.get(path);
-		if(holder != null && holder.getParent() != null) {
-			this.split(holder);
+		if(holder != null && holder.getParent() != null && allowOccupiedPath) {
+//			System.out.println("occupied by "+holder.getUniqueID());
+			this.split(holder, true);
 			this.addChild(child);
 			this.addChildToMinModel(child, path);
 			this.pathsToChildren.put(child, path);
@@ -406,25 +415,35 @@ public class Holon {
 	/**
 	 * removes this holon from current superholon and merge with new superholon
 	 */
-	public void split(Holon newParent) {
+	public void split(Holon newParent, boolean allowOccupiedPath) {
 		//ensure that this holarchy can run independent(path is not occupied by superholon) from the superholon
-		if(!this.parent.canRunIndependent(this)) {
+		if(this.parent == null || !this.parent.canRunIndependent(this)) {
 			return;
 		}
+		if(this.parent.parent != null) {
+			//we actually split from a super holon and not from the state holon
+			this.splitCounter++;
+		}
 		
 		if(newParent == null) {
 			newParent = this.model.getStateHolon();
+			allowOccupiedPath = true;
+		} else {
+			//next step is merge with new parent
+			this.mergeCounter++;
 		}
+
+		this.parent.incSplitCounter();
+		this.parent.removeChildHolon(this);
 		
-		if(this.parent != null) {
-			this.parent.removeChildHolon(this);
-		}
 		this.holonControlUnit.getHierarchyController().resetVirtualNeighbors();
-		newParent.merge(this);
+		newParent.merge(this, allowOccupiedPath);
 	}
 	
 	public void splitById(String id) {
-		this.model.getHolonsByID().get(id).split(null);
+		Holon child = this.model.getHolonsByID().get(id);
+		if(child.parent == this)
+			child.split(null, false);
 	}
 	
 	/**
@@ -504,7 +523,7 @@ public class Holon {
 		for(int i=0; i< this.childHolons.size(); i++) {
 			Holon child = this.childHolons.remove(0);
 			if(this.model.checkHolonObjectsAreConnected(this, child, this.holonControlUnit.getStateEstimator().getNetThroughput())) {
-				this.merge(child);
+				this.merge(child, true);
 			}
 		}
 		
@@ -593,4 +612,43 @@ public class Holon {
 	public boolean isASuperiorHolon(String holon) {
 		return this.parent != null ? (this.parent.getUniqueID().equals(holon) || this.parent.isASuperiorHolon(holon)) : false;
 	}
+
+	public int getMergeCounter() {
+		return mergeCounter;
+	}
+
+	public int getSplitCounter() {
+		return splitCounter;
+	}
+	
+	public void incSplitCounter() {
+		this.splitCounter++;
+	}
+	
+	public int[] getStateCounter() {
+		return this.stateCounter;
+	}
+	
+	public void countState(float dev) {
+		if(Math.abs(dev) <= 1-OptimizationManager.POWER_THRESHOLD_COMFORT) {
+			this.stateCounter[0]++;
+		} else if(Math.abs(dev) <= 1-OptimizationManager.POWER_THRESHOLD_STABILITY) {
+			this.stateCounter[1]++;
+		} else {
+			this.stateCounter[2]++;
+		}
+//		switch (this.holonControlUnit.getStateEstimator().getStateIndicator()) {
+//		case DESIRED: 
+//			this.stateCounter[0]++;
+//			break;
+//		case ENDANGERED:
+//			this.stateCounter[1]++;
+//			break;
+//		case DYSFUNCTIONAL:
+//			this.stateCounter[2]++;
+//			break;
+//		default:
+//			throw new IllegalArgumentException("Unexpected value: " + this.holonControlUnit.getStateEstimator().getStateIndicator());
+//		}
+	}
 }

+ 9 - 5
src/classes/holonControlUnit/CommunicationModule.java

@@ -8,6 +8,7 @@ import classes.holonControlUnit.messages.OrderMsg;
 import classes.holonControlUnit.messages.SplitMsg;
 import classes.holonControlUnit.messages.StateMsg;
 import classes.holonControlUnit.messages.StateRequestMsg;
+import classes.holonControlUnit.messages.MergeOrderMsg;
 
 import java.util.ArrayList;
 
@@ -54,7 +55,7 @@ public class CommunicationModule {
 				receiveNeighborhoodMsg(msg);
 				break;
 			case STATE_REQUEST:
-				this.hcu.receiveStateRequest(msg.getSender(), this.gson.fromJson(msg.getBody(), StateRequestMsg.class));
+				this.hcu.getStateEstimator().receiveStateRequest(msg.getSender(), this.gson.fromJson(msg.getBody(), StateRequestMsg.class));
 				break;
 			case STATE:
 				this.hcu.getStateEstimator().receiveState(msg.getSender(), this.gson.fromJson(msg.getBody(), StateMsg.class));
@@ -65,6 +66,9 @@ public class CommunicationModule {
 			case SPLIT:
 				receiveSplitMsg(msg);
 				break;
+			case MERGE_ORDER:
+				this.hcu.getHierarchyController().receiveMergeOrder(this.gson.fromJson(msg.getBody(), MergeOrderMsg.class), msg.getSender());
+				break;
 			default:
 				throw new RuntimeException("Unknown message type:\n"+message);
 		}
@@ -80,10 +84,10 @@ public class CommunicationModule {
 			case REMOVE_VIRTUAL_NEIGHBOR:
 				this.hcu.getHierarchyController().removeVirtualNeighbors(neighbors);
 				break;
-			case NEW_PHYSICAL_NEIGHBOR:
-				break;
-			case REMOVE_PHYSICAL_NEIGHBOR:
-				break;
+//			case NEW_PHYSICAL_NEIGHBOR:
+//				break;
+//			case REMOVE_PHYSICAL_NEIGHBOR:
+//				break;
 			default:
 				System.err.println("Unknown neighborhood type:\n"+msg);
 		}

+ 37 - 14
src/classes/holonControlUnit/FlexibilityManager.java

@@ -13,13 +13,15 @@ public class FlexibilityManager {
 
 	private HolonControlUnit hcu;
 	private HashMap<Integer, FlexManager> savesFlexManager;
+	private int appliedFlexCounter;
 	
 	public FlexibilityManager(HolonControlUnit hcu) {
 		this.hcu = hcu;
 		this.savesFlexManager = new HashMap<>();
+		this.appliedFlexCounter = 0;
 	}
 	
-	public float applyFlexibilities(float requiredPower, ArrayList<Float> predictedPowerUsage, int timeStep) {
+	public float applyFlexibilities(float currentPower, float requiredPower, ArrayList<Float> predictedPowerUsage, int timeStep) {
 		FlexManager fm = getFlexManager(timeStep);
 		
 		List<Flexibility> offeredFlexes = fm.getAllFlexWrapperWithState(FlexState.OFFERED).stream().map(fw -> fw.getFlex()).collect(Collectors.toList());
@@ -28,28 +30,46 @@ public class FlexibilityManager {
 		for(List<Flexibility> l : offeredPerm) {
 			float pu = 0f;
 //			ArrayList<Float> pus = new ArrayList<>();
+			Float[] savings = new Float[predictedPowerUsage.size()];
+			for(int i=0; i<savings.length; i++)
+				savings[i] = 0f;
 			for(Flexibility f : l) {
 				pu += f.fulfillsConstrains() ? f.getElement().getEnergyPerElement() : 0f;
 				if(Math.abs(pu) > Math.abs(requiredPower))
 					break;
+
+				for(int i=0; i<Math.min(savings.length, f.getDuration()); i++) {
+					savings[i] = savings[i] + f.bringtmir();
+//					savings[i] = savings[i] + (f.fulfillsConstrains() ? f.getElement().getEnergyPerElement() : 0f);
+				}
+//				if(!this.hcu.decreasesPowerUsage(List.of(savings), currentPower, predictedPowerUsage, requiredPower))
+//					break;
+			}
+			if(this.hcu.decreasesPowerUsage(List.of(savings), currentPower, predictedPowerUsage, requiredPower)) {
+				float s = 0f;
+				for(int i=0; i<savings.length; i++)
+					s += savings[i];
+				s = s/savings.length; //average saving over the next time periods
+				if(map.containsKey(s) && map.get(s).size() >= l.size())
+					continue;
+				map.put(s, l);
 			}
-			if(Math.abs(pu) <= Math.abs(requiredPower))
-				map.put(pu, l);
 		}
 
-		float max = 0f;
+		float min = Float.MAX_VALUE;
 		for(float f : map.keySet()) {
-			if(Math.abs(f) > Math.abs(max)) {
-//				System.out.println("cand "+f);
-				max = f;
+			if(Math.abs(requiredPower-f) < Math.abs(requiredPower-min)) {
+				min = f;
 			}
 		}
-		if(map.containsKey(max)) {
-			fm.orderFlexFromList(map.get(max));
-			System.out.println(this.hcu.getHolon().getUniqueID()+" ordered flexes "+map.get(max));
+		if(map.containsKey(min)) {
+			fm.orderFlexFromList(map.get(min));
+//			System.out.println(this.hcu.getHolon().getUniqueID()+" ordered flexes "+map.get(min));
+			this.appliedFlexCounter += map.get(min).size();
+			return min;
 		}
 		
-		return max;
+		return 0f;
 	}
 	
 	public FlexManager getFlexManager(int timeStep) {
@@ -70,7 +90,7 @@ public class FlexibilityManager {
 	}
 	
 	public void orderFlex(Flexibility flex, int timeStep) {
-		System.out.println(this.hcu.getHolon().getUniqueID()+" ordered flex "+flex);
+//		System.out.println(this.hcu.getHolon().getUniqueID()+" ordered flex "+flex);
 		getFlexManager(timeStep).orderFlex(flex);
 	}
 	
@@ -82,10 +102,13 @@ public class FlexibilityManager {
 				List<T> l = new ArrayList<T>();
 				l.addAll(set.subList(i, j+1));
 				out.add(l);
-//				System.out.println("\tsubset "+l);
 			}
-//			out.add(List.of(set.get(i)));
 		}
 		return out;
 	}
+
+	public int getAppliedFlexCounter() {
+		return appliedFlexCounter;
+	}
+	
 }

+ 58 - 42
src/classes/holonControlUnit/HierarchyControlUnit.java

@@ -12,10 +12,12 @@ import classes.HolonObject;
 import classes.HolonSwitch;
 import classes.Node;
 import classes.holonControlUnit.messages.NeighborhoodMsg;
+import classes.holonControlUnit.messages.OrderMsg;
 import classes.holonControlUnit.messages.SplitMsg;
 import classes.holonControlUnit.messages.SplitMsg.SenderRealtion;
 import classes.holonControlUnit.messages.StateMsg;
 import classes.holonControlUnit.messages.MergeMsg;
+import classes.holonControlUnit.messages.MergeOrderMsg;
 import classes.holonControlUnit.messages.Message;
 
 public class HierarchyControlUnit {
@@ -193,13 +195,13 @@ public class HierarchyControlUnit {
 		Holon h = this.hcu.getHolon();
 		if(h.getLayer() > 1 && h.getParent().getPathsToChildren().get(h).contains(e)) {
 			//path to superholon is affected
-			h.merge("State Holon");
+			h.merge("State Holon", true);
 		}
 		Map<Holon, ArrayList<Edge>> set = Map.copyOf(h.getPathsToChildren());
 		for(Holon c : set.keySet()) {
 			if(set.get(c).contains(e)) {
 				//path to subholon c is affected
-				c.merge("State Holon");
+				c.merge("State Holon", true);
 			}
 		}
 	}
@@ -218,57 +220,55 @@ public class HierarchyControlUnit {
 			}
 			if(this.receivedMergeRequests.get(timeStep) == null) 
 				this.receivedMergeRequests.add(new ArrayList<MergeMsg>());
-			ArrayList<MergeMsg> list = this.receivedMergeRequests.get(timeStep);
-			for(MergeMsg m : list) {
-				if(m.getPower() == msg.getPower() && m.getRequester() == msg.getRequester() && m.getTimeStep() == msg.getTimeStep()) {
-					boolean b = true;
-					for(int i=0; i<m.getPredictedPowerUsage().size(); i++) {
-						if(m.getPredictedPowerUsage().get(i) != msg.getPredictedPowerUsage().get(i)) {
-							b = false;
-							break;
-						}
+			for(MergeMsg m : this.receivedMergeRequests.get(timeStep)) {
+				if(m.getPower() == msg.getPower() && m.getRequester() == msg.getRequester() 
+						&& m.getPredictedPowerUsage() == msg.getPredictedPowerUsage() && m.getNetThroughput() == msg.getNetThroughput()) {
+					if (m.getTimeStep() < msg.getTimeStep()) {
+						m = msg;
 					}
-					//the request is a duplicate
-					if(b)
-						return;
+					System.err.println("duplicate");
+					return;
 				}
 			}
-			list.add(msg);
+			this.receivedMergeRequests.get(timeStep).add(msg);
 		}
 	}
 	
 	public void receiveMergeAck(MergeMsg msg, String sender) {
+//		float requiredPower = this.hcu.getStateAssembler().getDesiredPowerUsage() - this.hcu.getStateEstimator().getPowerUsage();
 		if(this.superHolon.equals(sender) || this.subHolons.contains(sender) || !canMerge(msg.getRequester(), msg.getPower())) {
+//				|| !this.hcu.decreasesPowerUsage(msg.getPredictedPowerUsage(), this.hcu.getStateEstimator().getPowerUsage(), 
+//						this.hcu.getStateEstimator().getPredictedPowerUsage(), requiredPower)) {
 			return;
 		}
 		
-		HashMap<String, MergeMsg> map = this.sendMergeRequests.get(msg.getTimeStep()-1);
-		if(map.containsKey(sender) && this.hcu.matchPowerRange(map.get(sender).getPower(), msg.getPower(), 
-				map.get(sender).getPredictedPowerUsage(), this.hcu.getOptimizer().getCurrentPowerThreshold())) {
-			//tell sender that we are still interested in merging
-			map.clear(); //delete all merge request for this timestep so we dont merge with two holons at a time
-			StateMsg state = new StateMsg(this.hcu.getStateEstimator().getPowerUsage(), this.hcu.getStateEstimator().getNetThroughput(), 
-						this.hcu.getStateEstimator().getPredictedPowerUsage(), this.hcu.getStateEstimator().getStateIndicator());
-			MergeMsg m = new MergeMsg(MergeMsg.Type.ACK_II, msg.getPower(), this.hcu.getStateEstimator().getNetThroughput(), 
-					msg.getPredictedPowerUsage(), this.hcu.getHolon().getUniqueID(), msg.getTimeStep(), state, msg.getRedirectedBy());
-			String body = this.hcu.getCommunicator().getGson().toJson(m, MergeMsg.class);
-			this.hcu.getCommunicator().sendMsg(sender, Message.Type.MERGE, body);
-			return;
-		}
+//		HashMap<String, MergeMsg> map = this.sendMergeRequests.get(msg.getTimeStep()-1);
+//		if(map.containsKey(sender) && this.hcu.matchPowerRange(map.get(sender).getPower(), msg.getPower())
+//				&& true) {
+//			//tell sender that we are still interested in merging
+//			map.clear(); //delete all merge request for this timestep so we dont merge with two holons at a time
+//			StateMsg state = new StateMsg(this.hcu.getStateEstimator().getPowerUsage(), this.hcu.getStateEstimator().getNetThroughput(), 
+//						this.hcu.getStateEstimator().getPredictedPowerUsage(), this.hcu.getStateEstimator().getStateIndicator());
+//			MergeMsg m = new MergeMsg(MergeMsg.Type.ACK_II, msg.getPower(), this.hcu.getStateEstimator().getNetThroughput(), 
+//					msg.getPredictedPowerUsage(), this.hcu.getHolon().getUniqueID(), msg.getTimeStep(), state, msg.getRedirectedBy());
+//			String body = this.hcu.getCommunicator().getGson().toJson(m, MergeMsg.class);
+//			this.hcu.getCommunicator().sendMsg(sender, Message.Type.MERGE, body);
+//			return;
+//		}
 		int i = msg.getRedirectedBy().size();
 		if(msg.getTimeStep() < 1 || msg.getTimeStep()-1-i < 0)
 			return;
 		
-		String red = i > 0 ? msg.getRedirectedBy().get(0) : null;
-		map = this.sendMergeRequests.get(msg.getTimeStep()-1-i);
-		if(red != null && map.containsKey(red) && this.hcu.matchPowerRange(map.get(red).getPower(), msg.getPower(), 
-				map.get(red).getPredictedPowerUsage(), this.hcu.getOptimizer().getCurrentPowerThreshold())) {
+		String red = i > 0 ? msg.getRedirectedBy().get(0) : sender;
+		HashMap<String, MergeMsg> map = this.sendMergeRequests.get(msg.getTimeStep()-1-i);
+		if(red != null && map.containsKey(red) && this.hcu.matchPowerRange(map.get(red).getPower(), msg.getPower())) {
 			//tell sender that we are still interested in merging
 			map.clear(); //delete all merge request for this timestep so we dont merge with two holons at a time
 			StateMsg state = new StateMsg(this.hcu.getStateEstimator().getPowerUsage(), this.hcu.getStateEstimator().getNetThroughput(), 
 						this.hcu.getStateEstimator().getPredictedPowerUsage(), this.hcu.getStateEstimator().getStateIndicator());
 			MergeMsg m = new MergeMsg(MergeMsg.Type.ACK_II, msg.getPower(), this.hcu.getStateEstimator().getNetThroughput(), 
-					msg.getPredictedPowerUsage(), this.hcu.getHolon().getUniqueID(), msg.getTimeStep(), state, msg.getRedirectedBy());
+					msg.getPredictedPowerUsage(), this.hcu.getHolon().getUniqueID(), msg.getTimeStep(), state, msg.getRedirectedBy(), 
+					msg.isAllowOccupiedPath());
 			String body = this.hcu.getCommunicator().getGson().toJson(m, MergeMsg.class);
 			this.hcu.getCommunicator().sendMsg(sender, Message.Type.MERGE, body);
 		}
@@ -278,15 +278,30 @@ public class HierarchyControlUnit {
 		if(!canMerge(msg.getRequester(), msg.getPower())) {
 			return;
 		}
-		this.hcu.getHolon().merge(sender);
 		if(msg.getRedirectedBy() == null || msg.getRedirectedBy().size() == 0) {
+			this.hcu.getHolon().merge(sender, msg.isAllowOccupiedPath());
 			this.hcu.getStateEstimator().receiveState(sender, msg.getState());
+		} else {
+			MergeOrderMsg m = new MergeOrderMsg(msg, this.hcu.getHolon().getUniqueID());
+			String body = this.hcu.getCommunicator().getGson().toJson(m, MergeOrderMsg.class);
+			this.hcu.getCommunicator().sendMsg(msg.getRedirectedBy().get(0), Message.Type.MERGE_ORDER, body);
 		}
 	}
 	
+	public void receiveMergeOrder(MergeOrderMsg msg, String sender) {
+		MergeMsg merge = msg.getOrginalMergeMsg();
+//		System.out.println(this.hcu.getHolon().getUniqueID()+" I have to merge :( "+merge.getRedirectedBy());
+		if(!this.hcu.getHolon().isASuperiorHolon(sender) || !canMerge(merge.getRequester(),merge.getPower()))
+			return;
+		this.hcu.getHolon().merge(merge.getRequester(), merge.isAllowOccupiedPath());
+		this.hcu.getStateEstimator().receiveState(merge.getRequester(), merge.getState());
+		OrderMsg order = new OrderMsg(merge.getPower(), this.hcu.getHolon().model.getCurIteration());
+		this.hcu.getCommunicator().sendMsg(merge.getRequester(), Message.Type.ORDER, this.hcu.getCommunicator().getGson().toJson(order));
+	}
+	
 	public void sendMergeReq(float powerUsage, ArrayList<Float> predictedPowerUsage, int timeStep, String physicalNeighbor) {
 		MergeMsg msg = new MergeMsg(MergeMsg.Type.REQ, powerUsage, this.hcu.getStateEstimator().getNetThroughput(), 
-				predictedPowerUsage, this.hcu.getHolon().getUniqueID(), timeStep, null, new ArrayList<>());
+				predictedPowerUsage, this.hcu.getHolon().getUniqueID(), timeStep, null, new ArrayList<>(), true);
 		if(this.sendMergeRequests.size() <= timeStep) {
 			for(int i=this.sendMergeRequests.size(); i<=timeStep; i++) {
 				this.sendMergeRequests.add(new HashMap<>());
@@ -297,9 +312,9 @@ public class HierarchyControlUnit {
 		this.hcu.getCommunicator().sendMsg(physicalNeighbor, Message.Type.MERGE, body);
 	}
 	
-	public void sendMergeAck(int timeStep, MergeMsg req) {
+	public void sendMergeAck(int timeStep, MergeMsg req, boolean allowOccupiedPath) {
 		MergeMsg msg = new MergeMsg(MergeMsg.Type.ACK, req.getPower(), this.hcu.getStateEstimator().getNetThroughput(), req.getPredictedPowerUsage(), 
-				this.hcu.getHolon().getUniqueID(), timeStep, req.getState(), req.getRedirectedBy());
+				this.hcu.getHolon().getUniqueID(), timeStep, req.getState(), req.getRedirectedBy(), allowOccupiedPath);
 		String body = this.hcu.getCommunicator().getGson().toJson(msg, MergeMsg.class);
 		this.hcu.getCommunicator().sendMsg(req.getRequester(), Message.Type.MERGE, body);
 	}
@@ -309,7 +324,8 @@ public class HierarchyControlUnit {
 				|| this.hcu.getHolon().getLayer() <= 1)
 			return;
 		for(MergeMsg req : this.receivedMergeRequests.get(timeStep)) {
-			if(req.getRequester().equals(this.hcu.getHolon().getUniqueID()) || req.getRequester().equals(this.superHolon))
+			if(req.getRequester().equals(this.hcu.getHolon().getUniqueID()) || req.getRequester().equals(this.superHolon)
+					|| req.getRedirectedBy().contains(this.hcu.getHolon().getUniqueID()) || req.getRedirectedBy().contains(this.superHolon))
 				continue;
 			req.getRedirectedBy().add(this.hcu.getHolon().getUniqueID());
 			String body = this.hcu.getCommunicator().getGson().toJson(req, MergeMsg.class);
@@ -330,7 +346,7 @@ public class HierarchyControlUnit {
 		SplitMsg msg = new SplitMsg(SenderRealtion.SUBHOLON, timeStep);
 		String body = this.hcu.getCommunicator().getGson().toJson(msg, SplitMsg.class);
 		this.hcu.getCommunicator().sendMsg(this.superHolon, Message.Type.SPLIT, body);
-		this.hcu.getHolon().split(null);
+		this.hcu.getHolon().split(null, true);
 	}
 	
 	public void receiveSplitMsg(SplitMsg msg, String sender) {
@@ -377,9 +393,9 @@ public class HierarchyControlUnit {
 		if(other.equals(thisHolon.getUniqueID()) || !thisHolon.model.checkHolonObjectsAreConnected(thisHolon, otherHolon, addedThroughput) 
 				|| thisHolon.isASuperiorHolon(other) || otherHolon.isASuperiorHolon(this.hcu.getHolon().getUniqueID())) {
 			// this holon and the other holon can not merge because:
-			// a) this holon and other holon are the same
-			// b) other holon is not connected to this holon or the new throughput would burn a cable
-			// c) other holon is a superior holon of this holon
+			// a) this holon and other holon are the same or
+			// b) other holon is not connected to this holon or the new throughput would burn a cable or
+			// c) other holon is a superior holon of this holon or
 			// d) this holon is a superior holon of other holon
 			return false;
 		}

+ 42 - 21
src/classes/holonControlUnit/HolonControlUnit.java

@@ -18,7 +18,6 @@ public class HolonControlUnit {
 	private StateEstimator stateEstimator;
 	private TargetStateAssembler stateAssembler;
 	private CommunicationModule communicator;
-	private ArrayList<StateMsg> states;
 	
 	public HolonControlUnit(Holon h) {
 		this.holon = h;
@@ -29,7 +28,6 @@ public class HolonControlUnit {
 		this.stateEstimator = new StateEstimator(this);
 		this.stateAssembler = new TargetStateAssembler(this);
 		this.communicator = new CommunicationModule(this);
-		this.states = new ArrayList<StateMsg>();
 	}
 
 	public ArrayList<Holon> getSubHolon() {
@@ -88,25 +86,6 @@ public class HolonControlUnit {
 		//evaluate optimization scheme
 		this.optimizer.evaluateOptimizationScheme(timeStep);
 	}
-	
-	public void receiveStateRequest(String sender, StateRequestMsg req) {
-		int timeStep = req.getTimeStep();
-		if(!sender.equals(this.hierarchyController.getSuperHolon()) || timeStep < 0)
-			return;
-		
-		if(this.states.size() > timeStep) {
-			String body = this.communicator.getGson().toJson(this.states.get(timeStep));
-			this.communicator.sendMsg(sender, Message.Type.STATE, body);
-		} else {
-			computeState(timeStep);
-			StateMsg stateMsg = new StateMsg(this.stateEstimator.getPowerUsage(), this.stateEstimator.getNetThroughput(), 
-					this.stateEstimator.getPredictedPowerUsage(), this.stateEstimator.getStateIndicator());
-			//send current state to sender (super holon)
-			String body = this.communicator.getGson().toJson(stateMsg);
-			this.communicator.sendMsg(sender, Message.Type.STATE, body);
-			this.states.add(stateMsg);
-		}
-	}
 
 	public boolean matchPowerRange(float power, float des, ArrayList<Float> prePower, float threshold) {
 		float diff =  Math.abs(des -  threshold * des);
@@ -119,7 +98,26 @@ public class HolonControlUnit {
 		}
 		return true;
 	}
+
+	public boolean matchPowerRange(float power, float des, float threshold) {
+		float diff =  Math.abs(des -  threshold * des);
+		float tres = Math.max(10-threshold*10, diff);	//otherwise the range could be 0
+		if(power > des + tres || power < des - tres)
+			return false;
+		
+		return true;
+	}
+
+	public boolean matchPowerRange(float power, float des) {
+		float threshold = this.optimizer.getCurrentPowerThreshold();
+		float diff =  Math.abs(des -  threshold * des);
+		float tres = Math.max(10-threshold*10, diff);	//otherwise the range could be 0
+		if(power > des + tres || power < des - tres)
+			return false;
+		return true;
+	}
 	
+	@Deprecated
 	public boolean decreasesPowerUsage(float requiredPower, float powerUsage, List<Float> predictedPowerUsage) {
 		if(Math.abs(powerUsage) > Math.abs(requiredPower))
 			return false;
@@ -130,4 +128,27 @@ public class HolonControlUnit {
 		}
 		return true;
 	}
+	
+	/**
+	 * checks whether addedPower + currentPower decreases the absolute value of the power usage
+	 * @param addedPower
+	 * @param currentPower
+	 * @param predictedPower
+	 * @param desiredPower
+	 * @return
+	 */
+	public boolean decreasesPowerUsage(List<Float> addedPower, float currentPower, List<Float> predictedPower, float desiredPower) {
+//		float threshold = this.optimizer.getCurrentPowerThreshold();
+//		float diff =  Math.abs(desiredPower -  threshold * desiredPower);
+//		float thres =  Math.abs(desiredPower) + Math.max(10-threshold*10, diff);	//otherwise the range could be 0
+		
+		if(Math.abs(currentPower + addedPower.get(0)) > Math.abs(currentPower - desiredPower))
+			return false;
+		for(int i=1; i<addedPower.size(); i++){
+			if(Math.abs(predictedPower.get(i-1) + addedPower.get(i) - desiredPower) > Math.abs(predictedPower.get(i-1) - desiredPower))
+				return false;
+		}
+		
+		return true;
+	}
 }

+ 39 - 11
src/classes/holonControlUnit/StateEstimator.java

@@ -36,13 +36,15 @@ public class StateEstimator {
 	private float netThroughput;
 	private HashMap<String, StateMsg> childStates;
 	private ArrayList<Float> predictedPowerUsage;
-	private HashMap<String, Float> powerUsagesInsideHolarchy;
+	private ArrayList<StateMsg> states;
+//	private HashMap<String, Float> powerUsagesInsideHolarchy;
 	
 	public StateEstimator(HolonControlUnit hcu) {
 		this.hcu = hcu;
 		this.stateInd = StateIndicator.DESIRED;
-		this.powerUsagesInsideHolarchy = new HashMap<String, Float>();
+//		this.powerUsagesInsideHolarchy = new HashMap<String, Float>();
 		this.childStates = new HashMap<String, StateMsg>();
+		this.states = new ArrayList<StateMsg>();
 	}
 
 	public StateIndicator getStateIndicator() {
@@ -71,7 +73,16 @@ public class StateEstimator {
 		
 		boolean b = this.hcu.matchPowerRange(powerUsage, this.hcu.getStateAssembler().getDesiredPowerUsage(), this.predictedPowerUsage, 
 				this.hcu.getOptimizer().getCurrentPowerThreshold());
-		if(b && this.hcu.getOptimizer().getOptimizationScheme() != OptimizationScheme.RECOVERY) {
+		boolean c = this.hcu.getOptimizer().getOptimizationScheme() != OptimizationScheme.RECOVERY;
+		if(c) {
+			for(StateMsg state : this.childStates.values()) {
+				if(state.getStateInd() != StateIndicator.DESIRED) {
+					c = false;
+					break;
+				}
+			}
+		}
+		if(b && c) {
 			this.stateInd = StateIndicator.DESIRED;
 		} else if (b){
 			this.stateInd = StateIndicator.ENDANGERED;
@@ -86,22 +97,21 @@ public class StateEstimator {
 		for(String s : this.childStates.keySet()) {
 			float p = this.childStates.get(s).getPowerUsage();
 			this.powerUsage += p;
-			this.powerUsagesInsideHolarchy.put(s, p);
+//			this.powerUsagesInsideHolarchy.put(s, p);
 		}
 		//add state from holon elements
 		Holon holon = this.hcu.getHolon();
 		if(holon.isPhysical) {
-			float p = holon.getHolonObject().getEnergyAtTimeStepWithFlex(timeStep, this.hcu.getFlexMan().getFlexManager(timeStep));
+			float p = holon.getHolonObject().getEnergyAtTimeStepFlex(timeStep);
 			this.powerUsage += p;
-			this.powerUsagesInsideHolarchy.put(this.hcu.getHolon().getUniqueID(), p);
+//			this.powerUsagesInsideHolarchy.put(this.hcu.getHolon().getUniqueID(), p);
 		}
 	}
 	
 	private void calculateNetThroughput(int timeStep) {
-		FlexManager newFlexManager = this.hcu.getFlexMan().getFlexManager(timeStep);
 		this.netThroughput = this.hcu.getHolon().getAllHolonObjects().stream()
-				.filter(object -> object.getEnergyAtTimeStepWithFlex(timeStep, newFlexManager) > 0.0f)
-				.map(object -> object.getEnergyAtTimeStepWithFlex(timeStep, newFlexManager))
+				.filter(object -> object.getEnergyAtTimeStepFlex(timeStep) > 0.0f)
+				.map(object -> object.getEnergyAtTimeStepFlex(timeStep))
 				.reduce(0.0f, ((a,b) -> a + b));
 	}
 	
@@ -134,15 +144,33 @@ public class StateEstimator {
 			return;
 		this.childStates.put(sender, stateMsg);
 	}
+	
+	public void receiveStateRequest(String sender, StateRequestMsg req) {
+		int timeStep = req.getTimeStep();
+		if(!sender.equals(this.hcu.getHierarchyController().getSuperHolon()) || timeStep < 0)
+			return;
+		
+		if(this.states.size() > timeStep) {
+			String body = this.hcu.getCommunicator().getGson().toJson(this.states.get(timeStep));
+			this.hcu.getCommunicator().sendMsg(sender, Message.Type.STATE, body);
+		} else {
+			computeState(timeStep);
+			StateMsg stateMsg = new StateMsg(this.powerUsage, this.netThroughput, this.predictedPowerUsage, this.stateInd);
+			//send current state to sender (super holon)
+			String body = this.hcu.getCommunicator().getGson().toJson(stateMsg);
+			this.hcu.getCommunicator().sendMsg(sender, Message.Type.STATE, body);
+			this.states.add(stateMsg);
+		}
+	}
 
 	public float getPowerUsage() {
 		return this.powerUsage;
 	}
-
+/**
 	public HashMap<String, Float> getPowerUsagesInsideHolarchy() {
 		return this.powerUsagesInsideHolarchy;
 	}
-
+*/
 	public ArrayList<Float> getPredictedPowerUsage() {
 		return this.predictedPowerUsage;
 	}

+ 135 - 102
src/classes/holonControlUnit/TargetStateAssembler.java

@@ -17,25 +17,26 @@ public class TargetStateAssembler {
 	private HolonControlUnit hcu;
 	private float desiredPowerUsage = 100f;
 	private OrderMsg order;
-	private HashMap<String, OrderMsg> ordersForSubholon;
+//	private HashMap<String, OrderMsg> ordersForSubholon;
 	
 	public TargetStateAssembler(HolonControlUnit hcu) {
 		this.order = null;
 		this.hcu = hcu;
-		this.ordersForSubholon = new HashMap<String, OrderMsg>();
+//		this.ordersForSubholon = new HashMap<String, OrderMsg>();
 	}
 	
 	public void assembleTargetState(int timeStep) {
-		if(this.order == null || this.order.getTimeStep() != timeStep-1) {
+		if(this.order == null || this.order.getTimeStep() >= timeStep-1) {
 			this.desiredPowerUsage =  0f;
 		} else {
 			this.desiredPowerUsage = this.order.getDesiredPowerUsage();
 		}
-		this.ordersForSubholon.clear();
-		System.out.println(this.hcu.getHolon().getUniqueID()+" opt scheme: "+this.hcu.getOptimizer().getOptimizationScheme());
+//		this.ordersForSubholon.clear();
+//		System.out.println(this.hcu.getHolon().getUniqueID()+" opt scheme: "+this.hcu.getOptimizer().getOptimizationScheme());
 
 		//balance the sub holons
-		switch(this.hcu.getOptimizer().getOptimizationScheme()) {
+		OptimizationScheme optScheme = this.hcu.getOptimizer().getOptimizationScheme();
+		switch(optScheme) {
 			case COMFORT:
 				assembleTargetStateComfort(timeStep);
 				break;
@@ -53,12 +54,6 @@ public class TargetStateAssembler {
 				System.err.println("Unknown optimization scheme in "+this.hcu.getHolon().getUniqueID());
 		}
 		this.hcu.getHierarchyController().propagateMergeReqToParent(timeStep-1);
-		//send order to subholons
-		Gson gson = this.hcu.getCommunicator().getGson();
-		for(String s : this.ordersForSubholon.keySet()) {
-			if(this.hcu.getHierarchyController().getSubHolons().contains(s))
-				this.hcu.getCommunicator().sendMsg(s, Message.Type.ORDER, gson.toJson(this.ordersForSubholon.get(s)));
-		}
 	}
 	
 	private void assembleTargetStateComfort(int timeStep) {
@@ -73,34 +68,34 @@ public class TargetStateAssembler {
 		//check if this holon can run independent from parent without risking stability
 		if(this.hcu.matchPowerRange(powerUsage, 0f, predictedPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold()) 
 				&& this.hcu.getHolon().getParent().canRunIndependent(this.hcu.getHolon()) && this.hcu.getHolon().getLayer() > 1) {
-			System.out.println(this.hcu.getHolon().getUniqueID()+" can run independent");
+//			System.out.println(this.hcu.getHolon().getUniqueID()+" can run independent");
 			this.hcu.getHierarchyController().splitSuperHolon(timeStep);
 			this.desiredPowerUsage = 0f;
+			orderSubholonsPredictedPower(timeStep);
+			return;
 		}
 
 		//powerUsage already matches desired value, everything as before
-		if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage, predictedPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold())) {
-			System.out.println(this.hcu.getHolon().getUniqueID()+" power usage as desired "+powerUsage);
-			HashMap<String, StateMsg> childStates = this.hcu.getStateEstimator().getChildStates();
-			for(String s : childStates.keySet()) {
-				OrderMsg o = new OrderMsg(childStates.get(s).getPredictedPowerUsage().get(0), null, OptimizationScheme.STABILITY, timeStep);
-				this.ordersForSubholon.put(s, o);
-			}
+		if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold())) {
+//			System.out.println(this.hcu.getHolon().getUniqueID()+" power usage as desired "+powerUsage);
+			orderSubholonsPredictedPower(timeStep);
 			return;
 		}
-		System.out.println(this.hcu.getHolon().getUniqueID()+" power usage "+powerUsage+" not as desired "+this.desiredPowerUsage);
+//		System.out.println(this.hcu.getHolon().getUniqueID()+" power usage "+powerUsage+" not as desired "+this.desiredPowerUsage);
 		float requiredPower = this.desiredPowerUsage - powerUsage;
 		
 		//find flexibility which matches required power
-		float savedWithFlexibilities = gothroughFlexibilities(timeStep, requiredPower, predictedPowerUsage);
+		float savedWithFlexibilities = this.hcu.getFlexMan().applyFlexibilities(powerUsage, requiredPower, predictedPowerUsage, timeStep);
 		if(savedWithFlexibilities == requiredPower) {
+			orderSubholonsPredictedPower(timeStep);
 			return;
 		}
 		requiredPower -= savedWithFlexibilities;
 		
 		//go through merge requests from last iteration
-		float savedByMerging = gothroughMergeReq(timeStep, requiredPower, predictedPowerUsage, OptimizationScheme.COMFORT);
+		float savedByMerging = gothroughMergeReq(timeStep, powerUsage, requiredPower, predictedPowerUsage, OptimizationScheme.COMFORT);
 		if(savedByMerging == requiredPower) {
+			orderSubholonsPredictedPower(timeStep);
 			return;
 		}
 		requiredPower -= savedByMerging;
@@ -109,7 +104,7 @@ public class TargetStateAssembler {
 		findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage);
 		
 		//tell all holons to use a little more/less energy
-		orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower, OptimizationScheme.COMFORT);
+		orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
 	}
 	
 	private void assembleTargetStateStability(int timeStep) {
@@ -122,28 +117,26 @@ public class TargetStateAssembler {
 		}
 
 		//powerUsage already matches desired value, everything as before
-		if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage, predictedPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold())) {
-			System.out.println(this.hcu.getHolon().getUniqueID()+" power usage as desired "+powerUsage);
-			HashMap<String, StateMsg> childStates = this.hcu.getStateEstimator().getChildStates();
-			for(String s : childStates.keySet()) {
-				OrderMsg o = new OrderMsg(childStates.get(s).getPredictedPowerUsage().get(0), null, OptimizationScheme.STABILITY, timeStep);
-				this.ordersForSubholon.put(s, o);
-			}
+		if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold())) {
+//			System.out.println(this.hcu.getHolon().getUniqueID()+" power usage as desired "+powerUsage);
+			orderSubholonsPredictedPower(timeStep);
 			return;
 		}
-		System.out.println(this.hcu.getHolon().getUniqueID()+" power usage "+powerUsage+" not as desired "+this.desiredPowerUsage);
+//		System.out.println(this.hcu.getHolon().getUniqueID()+" power usage "+powerUsage+" not as desired "+this.desiredPowerUsage);
 		float requiredPower = this.desiredPowerUsage - powerUsage;
 		
 		//find flexibility which matches required power
-		float savedWithFlexibilities = gothroughFlexibilities(timeStep, requiredPower, predictedPowerUsage);
+		float savedWithFlexibilities = this.hcu.getFlexMan().applyFlexibilities(powerUsage, requiredPower, predictedPowerUsage, timeStep);
 		if(savedWithFlexibilities == requiredPower) {
+			orderSubholonsPredictedPower(timeStep);
 			return;
 		}
 		requiredPower -= savedWithFlexibilities;
 		
 		//go through merge requests from last iteration
-		float savedByMerging = gothroughMergeReq(timeStep, requiredPower, predictedPowerUsage, OptimizationScheme.STABILITY);
+		float savedByMerging = gothroughMergeReq(timeStep, powerUsage, requiredPower, predictedPowerUsage, OptimizationScheme.STABILITY);
 		if(savedByMerging == requiredPower) {
+			orderSubholonsPredictedPower(timeStep);
 			return;
 		}
 		requiredPower -= savedByMerging;
@@ -152,7 +145,7 @@ public class TargetStateAssembler {
 		findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage);
 		
 		//tell all holons to use a little more/less energy
-		orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower, OptimizationScheme.STABILITY);
+		orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
 	}
 	
 	private void assembleTargetStateRecovery(int timeStep) {
@@ -165,34 +158,32 @@ public class TargetStateAssembler {
 		}
 
 		//powerUsage already matches desired value, everything as before
-		if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage, predictedPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold())) {
-			System.out.println(this.hcu.getHolon().getUniqueID()+" power usage as desired "+powerUsage);
-			HashMap<String, StateMsg> childStates = this.hcu.getStateEstimator().getChildStates();
-			for(String s : childStates.keySet()) {
-				OrderMsg o = new OrderMsg(childStates.get(s).getPredictedPowerUsage().get(0), null, OptimizationScheme.STABILITY, timeStep);
-				this.ordersForSubholon.put(s, o);
-			}
+		if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold())) {
+//			System.out.println(this.hcu.getHolon().getUniqueID()+" power usage as desired "+powerUsage);
+			orderSubholonsPredictedPower(timeStep);
 			return;
 		}
-		System.out.println(this.hcu.getHolon().getUniqueID()+" power usage "+powerUsage+" not as desired "+this.desiredPowerUsage);
+//		System.out.println(this.hcu.getHolon().getUniqueID()+" power usage "+powerUsage+" not as desired "+this.desiredPowerUsage);
 		float requiredPower = this.desiredPowerUsage - powerUsage;
 		
 		//find flexibility which matches required power
-		float savedWithFlexibilities = gothroughFlexibilities(timeStep, requiredPower, predictedPowerUsage);
+		float savedWithFlexibilities = this.hcu.getFlexMan().applyFlexibilities(powerUsage, requiredPower, predictedPowerUsage, timeStep);
 		if(savedWithFlexibilities == requiredPower) {
+			orderSubholonsPredictedPower(timeStep);
 			return;
 		}
 		requiredPower -= savedWithFlexibilities;
 
 		//go through merge requests from last iteration
-		float savedByMerging = gothroughMergeReq(timeStep, requiredPower, predictedPowerUsage, OptimizationScheme.RECOVERY);
+		float savedByMerging = gothroughMergeReq(timeStep, powerUsage, requiredPower, predictedPowerUsage, OptimizationScheme.RECOVERY);
 		if(savedByMerging == requiredPower) {
+			orderSubholonsPredictedPower(timeStep);
 			return;
 		}
 		requiredPower -= savedByMerging;
 		
-		float p = this.hcu.getHolon().isPhysical ? this.hcu.getHolon().getHolonObject().getEnergyAtTimeStepFlex(timeStep) : 0f;
-		requiredPower = this.desiredPowerUsage - p;
+//		float p = this.hcu.getHolon().isPhysical ? this.hcu.getHolon().getHolonObject().getEnergyAtTimeStepFlex(timeStep) : 0f;
+//		requiredPower = this.desiredPowerUsage - p;
 		
 		//split dysfunctional parts
 		HashMap<String, StateMsg> childStates = this.hcu.getStateEstimator().getChildStates();
@@ -200,44 +191,61 @@ public class TargetStateAssembler {
 		HashMap<Float, List<String>> potChild = new HashMap<Float, List<String>>();
 		for(List<String> l : childPerm) {
 			//check how much power this subset of child would consume
-			float pu = p;
+			Float[] savings = new Float[predictedPowerUsage.size()+1];
+			for(int i=0; i<savings.length; i++)
+				savings[i] = 0f;
 			for(String s : l) {
-				if(Math.abs(pu) > Math.abs(requiredPower))
-					break;
-				pu += childStates.get(s).getPowerUsage();
+				StateMsg state = childStates.get(s);
+//				if(!this.hcu.decreasesPowerUsage(List.of(savings), powerUsage, predictedPowerUsage, this.desiredPowerUsage))
+//					break;
+				savings[0] = savings[0] + state.getPowerUsage();
+				for(int i=1; i<savings.length; i++) {
+					savings[i] += state.getPredictedPowerUsage().get(i-1);
+				}
 			}
-			if(Math.abs(pu) <= Math.abs(requiredPower)) {
+			if(this.hcu.decreasesPowerUsage(List.of(savings), powerUsage, predictedPowerUsage, this.desiredPowerUsage)) {
+				float pu = 0f;
+				for(int i=0; i<savings.length; i++)
+					pu += savings[i];
+				pu = pu/savings.length;
 				if(potChild.containsKey(pu) && potChild.get(pu).size() >= l.size())
 					continue;
 				potChild.put(pu, l);
 			}
 		}
 		//find subset of children with most fitting powerUsage
-		float max = 0f;
+		float min = Float.MAX_VALUE;
+		//the required power usage without any child holons 
+		float r = this.desiredPowerUsage - this.hcu.getHolon().getHolonObject().getEnergyAtTimeStepFlex(timeStep); 
 		for(float f : potChild.keySet()) {
-			if(Math.abs(f) > Math.abs(max)) {
-				max = f;
+			if(Math.abs(f+r) < Math.abs(min+r)) {
+				min = f;
 			}
 		}
 		//split all other subholons
 		List<String> list = new ArrayList<String>();
-		if(potChild.containsKey(max)) {
-			list = potChild.get(max);
+		if(potChild.containsKey(min)) {
+			list = potChild.get(min);
 		}
 		List<String> subs = List.copyOf(this.hcu.getHierarchyController().getSubHolons());
 		for(String s : subs) {
 			if(!list.contains(s)) {
 				this.hcu.getHierarchyController().splitSubHolon(s, timeStep);
+//				requiredPower -= childStates.getOrDefault(s, new StateMsg(0f, 0f, null, null)).getPowerUsage();
 			}
 		}
-		requiredPower -= max;
+		requiredPower = r + min;
 		if(requiredPower == 0) {
+			//by removing child holons we have regained stability
+			orderSubholonsPredictedPower(timeStep);
 			return;
 		}
 
 		//Split from superholon?
-		if(Math.abs(requiredPower) > Math.abs(p) && this.hcu.getHolon().getLayer() > 1) {
+		if(Math.abs(requiredPower) > Math.abs(powerUsage) && this.hcu.getHolon().getLayer() > 1) {
+//			System.out.println("----"+requiredPower+" "+powerUsage);
 			this.hcu.getHierarchyController().splitSuperHolon(timeStep);
+			orderSubholonsRequiredPower(timeStep, powerUsage, 0f-powerUsage);
 			return;
 		}
 		
@@ -245,11 +253,7 @@ public class TargetStateAssembler {
 		findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage);
 		
 		//tell all holons to use a little more/less energy
-		orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower, OptimizationScheme.RECOVERY);
-	}
-	
-	private float gothroughFlexibilities(int timeStep, float requiredPower, ArrayList<Float> predictedPowerUsage) {
-		return this.hcu.getFlexMan().applyFlexibilities(requiredPower, predictedPowerUsage, timeStep);
+		orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
 	}
 
 	/**
@@ -259,7 +263,7 @@ public class TargetStateAssembler {
 	 * @param requiredPower
 	 * @return saved power
 	 */
-	private float gothroughMergeReq(int timeStep, float requiredPower, ArrayList<Float> predictedPowerUsage, 
+	private float gothroughMergeReq(int timeStep, float currentPower, float requiredPower, ArrayList<Float> predictedPower, 
 			OptimizationScheme optScheme) {
 		List<MergeMsg> requests = this.hcu.getHierarchyController().getMergeRequestsForTimeStep(timeStep-1);
 		if(requests == null)
@@ -276,19 +280,21 @@ public class TargetStateAssembler {
 				//cannot merge with the requester
 				continue;
 			}
-			
-			if(this.hcu.matchPowerRange(r, requiredPower, predictedPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold())) {
+//			System.out.println(this.hcu.getHolon().getUniqueID()+" merge req "+req.getPower()+" "
+//					+this.hcu.matchPowerRange(r, requiredPower, predictedPower, this.hcu.getOptimizer().getCurrentPowerThreshold()));
+			if(this.hcu.matchPowerRange(r, requiredPower, predictedPower, this.hcu.getOptimizer().getCurrentPowerThreshold())) {
 				//perfect match
-				this.hcu.getHierarchyController().sendMergeAck(timeStep, req);
-				OrderMsg o = new OrderMsg(r, null, optScheme, timeStep);
-				this.ordersForSubholon.put(requester, o);
+				this.hcu.getHierarchyController().sendMergeAck(timeStep, req, true);
+//				OrderMsg o = new OrderMsg(r, optScheme, timeStep);
+//				this.ordersForSubholon.put(requester, o);
 				requests.remove(req);
 				return r;
-			} else if( ((r < 0 && requiredPower < 0) || (r > 0 && requiredPower > 0))
-					&& this.hcu.decreasesPowerUsage(requiredPower, r, req.getPredictedPowerUsage())) {
+			}
+//			} else if( ((r < 0 && requiredPower < 0) || (r > 0 && requiredPower > 0))
+//					&& this.hcu.decreasesPowerUsage(req.getPredictedPowerUsage(), currentPower, predictedPower, requiredPower)) {
 				//accepting this request would help this holon
 				poten.add(req);
-			}
+//			}
 		}
 		//go through all poten candidates and find most suiting subset
 		//all candidates have either power < 0 or > 0
@@ -298,45 +304,54 @@ public class TargetStateAssembler {
 		HashMap<Float, List<MergeMsg>> potSavings = new HashMap<Float, List<MergeMsg>>();
 		for(List<MergeMsg> l : potPermut) {
 			//check how much power this subset of merges would save
-			float saving = 0f;
-			Float[] savings = new Float[predictedPowerUsage.size()];
+			Float[] savings = new Float[predictedPower.size()];
 			for(int i=0; i<savings.length; i++)
 				savings[i] = 0f;
 			for(MergeMsg m : l) {
-				if(!this.hcu.decreasesPowerUsage(requiredPower, saving, List.of(savings)))
-					break;
-				saving += m.getPredictedPowerUsage().get(0); //since merge req is from timeStep-1
+//				if(!this.hcu.decreasesPowerUsage(List.of(savings), currentPower, predictedPower, requiredPower))
+//					break;
 				for(int i=0; i<savings.length; i++) {
 					savings[i] = savings[i] + m.getPredictedPowerUsage().get(i);
 				}
 			}
-			if(this.hcu.decreasesPowerUsage(requiredPower, saving, List.of(savings))) {
-				if(potSavings.containsKey(saving) && potSavings.get(saving).size() >= l.size())
+//			System.out.println("l "+l+"\nsaving: "+savings[0]);
+			if(this.hcu.decreasesPowerUsage(List.of(savings), currentPower, predictedPower, requiredPower)) {
+				float s = 0f;
+				for(int i=0; i<savings.length; i++)
+					s += savings[i];
+				s = s/savings.length; //average saving over the next time periods
+				if(potSavings.containsKey(s) && potSavings.get(s).size() >= l.size())
 					continue;
-				potSavings.put(saving, l);
+				potSavings.put(s, l);
 			}
 		}
 		if(potSavings.size() < 1) {
 			return 0f;
 		}
-		float max = 0f;
+		float min = Float.MAX_VALUE;
 		for(float f : potSavings.keySet()) {
-			if(Math.abs(f) > Math.abs(max)) {
-				max = f;
+//			System.out.println(requiredPower+" "+currentPower+" "+min+" "+f+" "+Math.abs(requiredPower-f)+" < "+Math.abs(requiredPower-min));
+			if(Math.abs(requiredPower-f) < Math.abs(requiredPower-min)) {
+				min = f;
 			}
 		}
+//		System.out.println("min "+min);
+//		System.out.println(potSavings.keySet());
 		//merge with all holons that are part of the subset with the max saving
-		if(potSavings.containsKey(max)) {
-			for(MergeMsg req : potSavings.get(max)) {
-				float r = req.getPower();
-				String requester = req.getRequester();
-				this.hcu.getHierarchyController().sendMergeAck(timeStep, req);
-				OrderMsg o = new OrderMsg(r, null, optScheme, timeStep);
-				this.ordersForSubholon.put(requester, o);
+		if(potSavings.containsKey(min)) {
+			for(MergeMsg req : potSavings.get(min)) {
+//				System.out.println("I wanna merge");
+//				float r = req.getPower();
+//				String requester = req.getRequester();
+				this.hcu.getHierarchyController().sendMergeAck(timeStep, req, min == requiredPower);
+//				OrderMsg o = new OrderMsg(r, optScheme, timeStep);
+//				this.ordersForSubholon.put(requester, o);
 			}
-			requests.removeAll(potSavings.get(max));
+			//remove merge requests so they don't get propagated to super holon
+			requests.removeAll(potSavings.get(min));
+			return min;
 		}
-		return max;
+		return 0f;
 	}
 	
 	private void findNewSuperHolon(int timeStep, float powerUsage, ArrayList<Float> predictedPowerUsage) {
@@ -345,6 +360,15 @@ public class TargetStateAssembler {
 		}
 	}
 	
+	private void orderSubholonsPredictedPower(int timeStep) {
+		HashMap<String, StateMsg> childStates = this.hcu.getStateEstimator().getChildStates();
+		Gson gson = this.hcu.getCommunicator().getGson();
+		for(String s : childStates.keySet()) {
+			OrderMsg o = new OrderMsg(childStates.get(s).getPredictedPowerUsage().get(0), timeStep);
+//			this.ordersForSubholon.put(s, o);
+			this.hcu.getCommunicator().sendMsg(s, Message.Type.ORDER, gson.toJson(o));
+		}
+	}
 	
 	/**
 	 * compute a new target value for all subholons
@@ -354,18 +378,26 @@ public class TargetStateAssembler {
 	 * @param requiredPower
 	 * @param optScheme
 	 */
-	private void orderSubholonsRequiredPower(int timeStep, float powerUsage, float requiredPower, OptimizationScheme optScheme) {
-		float p = this.hcu.getHolon().isPhysical ? this.hcu.getHolon().getHolonObject().getEnergyAtTimeStep(timeStep) : 0f;
-		requiredPower = this.desiredPowerUsage - p;
-		HashMap<String, StateMsg> childStates = this.hcu.getStateEstimator().getChildStates();
-		float opt = requiredPower/(childStates.size() != 0 ? childStates.size() : 1);
+	private void orderSubholonsRequiredPower(int timeStep, float powerUsage, float requiredPower) {
+//		float p = this.hcu.getHolon().isPhysical ? this.hcu.getHolon().getHolonObject().getEnergyAtTimeStep(timeStep) : 0f;
+//		requiredPower = this.desiredPowerUsage - p;
+//		HashMap<String, StateMsg> childStates = this.hcu.getStateEstimator().getChildStates();
+		Gson gson = this.hcu.getCommunicator().getGson();
+		float opt = - requiredPower/this.hcu.getHierarchyController().getSubHolons().size(); //(childStates.size() - this.ordersForSubholon.size() != 0 ? childStates.size() - this.ordersForSubholon.size() : 1);
 		for(String s : this.hcu.getHierarchyController().getSubHolons()) {
 			//order for subholon
-			if(this.ordersForSubholon.containsKey(s))
-				continue;
-			OrderMsg o = new OrderMsg(opt, null, optScheme, timeStep);
-			this.ordersForSubholon.put(s, o);
+//			if(this.ordersForSubholon.containsKey(s))
+//				continue;
+			OrderMsg o = new OrderMsg(opt, timeStep);
+//			this.ordersForSubholon.put(s, o);
+			//send order to subholon
+			this.hcu.getCommunicator().sendMsg(s, Message.Type.ORDER, gson.toJson(o));
 		}
+		//send order to subholons
+//		for(String s : this.ordersForSubholon.keySet()) {
+//			if(this.hcu.getHierarchyController().getSubHolons().contains(s))
+//				this.hcu.getCommunicator().sendMsg(s, Message.Type.ORDER, gson.toJson(this.ordersForSubholon.get(s)));
+//		}
 	}
 	
 	private <T> List<List<T>> getAllPermutations(List<T> set){
@@ -387,6 +419,7 @@ public class TargetStateAssembler {
 	}
 
 	public void setOrder(OrderMsg order, String sender) {
+//		System.out.println(this.hcu.getHolon().getUniqueID()+" received order "+order);
 		if(sender.equals(this.hcu.getHierarchyController().getSuperHolon())) {
 			this.order = order;
 		}

+ 10 - 3
src/classes/holonControlUnit/messages/MergeMsg.java

@@ -16,9 +16,10 @@ public class MergeMsg {
 	private int timeStep;
 	private StateMsg state;
 	private ArrayList<String> redirectedBy;
+	private boolean allowOccupiedPath;
 
-	public MergeMsg(Type type, float power, float netThroughput, ArrayList<Float> predictedPowerUsage, String requester, 
-			int timeStep, StateMsg state, ArrayList<String> redirectedBy) {
+	public MergeMsg(Type type, float power, float netThroughput, ArrayList<Float> predictedPowerUsage, String requester,
+			int timeStep, StateMsg state, ArrayList<String> redirectedBy, boolean allowOccupiedPath) {
 		super();
 		this.type = type;
 		this.power = power;
@@ -28,13 +29,15 @@ public class MergeMsg {
 		this.timeStep = timeStep;
 		this.state = state;
 		this.redirectedBy = redirectedBy;
+		this.allowOccupiedPath = allowOccupiedPath;
 	}
 
 	@Override
 	public String toString() {
 		return "MergeMsg [type=" + type + ", power=" + power + ", netThroughput=" + netThroughput
 				+ ", predictedPowerUsage=" + predictedPowerUsage + ", requester=" + requester + ", timeStep=" + timeStep
-				+ ", state=" + state + ", redirectedBy=" + redirectedBy + "]";
+				+ ", state=" + state + ", redirectedBy=" + redirectedBy + ", allowOccupiedPath=" + allowOccupiedPath
+				+ "]";
 	}
 
 	public Type getType() {
@@ -68,5 +71,9 @@ public class MergeMsg {
 	public ArrayList<String> getRedirectedBy() {
 		return redirectedBy;
 	}
+
+	public boolean isAllowOccupiedPath() {
+		return allowOccupiedPath;
+	}
 	
 }

+ 26 - 0
src/classes/holonControlUnit/messages/MergeOrderMsg.java

@@ -0,0 +1,26 @@
+package classes.holonControlUnit.messages;
+
+public class MergeOrderMsg {
+	
+	private MergeMsg orginalMergeMsg;
+	private String sender;
+	
+	public MergeOrderMsg(MergeMsg orginalMergeMsg, String sender) {
+		this.orginalMergeMsg = orginalMergeMsg;
+		this.sender = sender;
+	}
+	
+	public MergeMsg getOrginalMergeMsg() {
+		return orginalMergeMsg;
+	}
+
+	public String getSender() {
+		return sender;
+	}
+
+	@Override
+	public String toString() {
+		return "MergeOrderMsg [orginalMergeMsg=" + orginalMergeMsg + ", sender=" + sender + "]";
+	}
+
+}

+ 1 - 1
src/classes/holonControlUnit/messages/Message.java

@@ -5,7 +5,7 @@ import classes.Holon;
 public class Message {
 
 	public enum Type {
-		ORDER, NEIGHBORHOOD, STATE_REQUEST, STATE, MERGE, SPLIT
+		ORDER, NEIGHBORHOOD, STATE_REQUEST, STATE, MERGE, SPLIT, MERGE_ORDER
 	}
 	private String sender;
 	private String receiver;

+ 3 - 25
src/classes/holonControlUnit/messages/NeighborhoodMsg.java

@@ -7,12 +7,10 @@ import classes.Holon;
 public class NeighborhoodMsg {
 
 	public enum Type { 
-		NEW_VIRTUAL_NEIGHBOR, REMOVE_VIRTUAL_NEIGHBOR, 
-		NEW_PHYSICAL_NEIGHBOR, REMOVE_PHYSICAL_NEIGHBOR, SEARCH_PHYSICAL_NEIGHBOR_REQ, SEARCH_PHYSICAL_NEIGHBOR_ANS }
+		NEW_VIRTUAL_NEIGHBOR, REMOVE_VIRTUAL_NEIGHBOR }
+//		NEW_PHYSICAL_NEIGHBOR, REMOVE_PHYSICAL_NEIGHBOR, SEARCH_PHYSICAL_NEIGHBOR_REQ, SEARCH_PHYSICAL_NEIGHBOR_ANS }
 	private Type type;
 	private ArrayList<String> neighbors;
-	private int layer;
-	private String id;
 
 	public NeighborhoodMsg(Type type, ArrayList<String> newVirtualNeighbor) {
 		super();
@@ -20,21 +18,9 @@ public class NeighborhoodMsg {
 		this.neighbors = newVirtualNeighbor;
 	}
 
-	public NeighborhoodMsg(Type type, int layer) {
-		super();
-		this.type = type;
-		this.layer = layer;
-	}
-
-	public NeighborhoodMsg(Type type, String id) {
-		super();
-		this.type = type;
-		this.id = id;
-	}
-
 	@Override
 	public String toString() {
-		return "NeighborhoodMsg [type=" + type + ", neighbors=" + neighbors + ", layer=" + layer + ", id=" + id + "]";
+		return "NeighborhoodMsg [type=" + type + ", neighbors=" + neighbors + "]";
 	}
 
 	public ArrayList<String> getNeighbors() {
@@ -44,13 +30,5 @@ public class NeighborhoodMsg {
 	public Type getType() {
 		return type;
 	}
-
-	public int getLayer() {
-		return layer;
-	}
-
-	public String getId() {
-		return id;
-	}
 	
 }

+ 3 - 8
src/classes/holonControlUnit/messages/OrderMsg.java

@@ -10,19 +10,18 @@ public class OrderMsg {
 
 	private float desiredPowerUsage;
 //	private ArrayList<Flexibility> flexibilitiesToApply;
-	private OptimizationManager.OptimizationScheme optSheme;
+//	private OptimizationManager.OptimizationScheme optSheme;
 	private int timeStep;
 	
-	public OrderMsg(float desiredPowerUsage, ArrayList<Flexibility> flexibilitiesToApply, OptimizationScheme optSheme, int timeStep) {
+	public OrderMsg(float desiredPowerUsage, int timeStep) {
 		super();
 		this.desiredPowerUsage = desiredPowerUsage;
-		this.optSheme = optSheme;
 		this.timeStep = timeStep;
 	}
 
 	@Override
 	public String toString() {
-		return "OrderMsg [desiredPowerUsage=" + desiredPowerUsage + ", optSheme=" + optSheme + ", timeStep=" + timeStep
+		return "OrderMsg [desiredPowerUsage=" + desiredPowerUsage + ", timeStep=" + timeStep
 				+ "]";
 	}
 
@@ -30,10 +29,6 @@ public class OrderMsg {
 		return desiredPowerUsage;
 	}
 
-	public OptimizationManager.OptimizationScheme getOptSheme() {
-		return optSheme;
-	}
-
 	public int getTimeStep() {
 		return timeStep;
 	}

+ 1 - 1
src/ui/controller/LoadController.java

@@ -278,7 +278,7 @@ public class LoadController {
     		System.err.println(jsonObject.get("type").getAsString());
     		return;
     	}
-        
+    	
         temp.setImage(checkOS(temp.getImage()));
         initObjects(temp);
         if (mpC.searchCatObj(mpC.searchCat(temp.getSav()), temp.getObjName()) != null)

+ 127 - 2
src/ui/controller/SimulationManager.java

@@ -2,6 +2,7 @@ package ui.controller;
 
 import classes.*;
 import ui.model.IntermediateCableWithState;
+import ui.model.Consumer;
 import ui.model.DecoratedCable;
 import ui.model.DecoratedCable.CableState;
 import ui.model.DecoratedSwitch.SwitchState;
@@ -12,6 +13,8 @@ import ui.model.MinimumModel;
 import ui.model.MinimumNetwork;
 import ui.model.Model;
 import ui.model.Model.FairnessModel;
+import ui.model.Passiv;
+import ui.model.Supplier;
 import ui.model.VisualRepresentationalState;
 
 import java.util.ArrayList;
@@ -20,6 +23,7 @@ import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
+import java.util.stream.Collectors;
 
 
 /**
@@ -36,6 +40,11 @@ public class SimulationManager {
 	private HashMap<Integer, FlexManager> savesFlexManger = new HashMap<Integer, FlexManager>();
 	
 	private int timeStep;
+	
+	private HashMap<Holon, ArrayList<Float>> averagesPerHolon;
+	private HashMap<Holon, ArrayList<Integer>> mergesPerHolon;
+	private HashMap<Holon, ArrayList<Integer>> splitsPerHolon;
+	private HashMap<Holon, ArrayList<Integer>> flexesPerHolon;
 
 	/**
 	 * Constructor.
@@ -45,6 +54,10 @@ public class SimulationManager {
 	 */
 	public SimulationManager(Model m) {
 		model = m;
+		this.averagesPerHolon = new HashMap<Holon, ArrayList<Float>>();
+		this.mergesPerHolon = new HashMap<Holon, ArrayList<Integer>>();
+		this.splitsPerHolon = new HashMap<Holon, ArrayList<Integer>>();
+		this.flexesPerHolon = new HashMap<Holon, ArrayList<Integer>>();
 	}
 	
 	/**
@@ -55,7 +68,7 @@ public class SimulationManager {
 	 * @param updateVisual TODO
 	 */
 	public void calculateStateForTimeStep(int timeStep, boolean updateVisual) {
-		System.out.println("\n=========================================================================\n");
+//		System.out.println("\n=========================================================================\n");
 		this.timeStep = timeStep;
 		
 		MinimumModel minimumModel = new MinimumModel(model.getObjectsOnCanvas(), model.getEdgesOnCanvas());
@@ -172,12 +185,124 @@ public class SimulationManager {
 		ArrayList<DecoratedSwitch> listOfDecoratedSwitches = decorateSwitches(minimumModel, timeStep);
 		DecoratedState stateFromThisTimestep = new DecoratedState(decorNetworks, leftOverDecoratedCables, listOfDecoratedSwitches, timeStep, holonObjectNetworkTable);
 		saves.put(timeStep, stateFromThisTimestep);
-		if(updateVisual)savesVisual.put(timeStep, new VisualRepresentationalState(stateFromThisTimestep, minimumModel));
+		VisualRepresentationalState visualState = new VisualRepresentationalState(stateFromThisTimestep, minimumModel);
+		if(updateVisual)savesVisual.put(timeStep, visualState);
 		//Check Holarchy and split Holons if no physical connection is present.
 //		List<Holon> holonList = model.getStateHolon().childHolons;
 //		for(int i = 0; i < holonList.size(); i++) {
 //			holonList.get(i).checkRepairHolarchy(holonObjectNetworkTable, model.getStateHolon());
 //		}
+		eval(visualState, independentHolarchies, timeStep >= 99);
+	}
+	
+	private void eval(VisualRepresentationalState visualState, ArrayList<MinimumModel> independentHolarchies, boolean print) {
+		if(print)
+			System.out.println("\n=========================================================================\n");
+		//evaluate power usage in each holon object
+		for(Consumer con : visualState.getConsumerList()) {
+			evalPower(con.getModel().holon, con.getSupplyBarPercentage(), print);
+		}
+		HashMap<MinimumModel, Float> map = new HashMap<>();
+		for(Supplier sup : visualState.getSupplierList()) {
+			//find the holarchy where the sup is
+			MinimumModel holarchy = null;
+			for(MinimumModel mm : independentHolarchies) {
+				if(mm.getHolonObjectList().contains(sup.getModel()))
+					holarchy = mm;
+			}
+			//find out how much energy is produced and consumed in total inside this holarchy
+			//c/p is satisfaction of supplier
+			float sat = 0f;
+			if(holarchy != null) {
+				if(map.containsKey(holarchy)) {
+					sat = map.get(holarchy);
+				} else {
+					float totalProd = 0f;
+					float totalCon = 0f;
+					for(HolonObject ho : holarchy.getHolonObjectList()) {
+						float p = ho.getEnergyAtTimeStepFlex(model.getCurIteration());
+						if(p > 0) {
+							totalProd += p;
+						} else {
+							totalCon -= p;
+						}
+					}
+					sat = totalCon/totalProd;
+					map.put(holarchy, sat);
+				}
+			}
+			evalPower(sup.getModel().holon, sat, print);
+		}
+		for(Passiv pas : visualState.getPassivList()) {
+			evalPower(pas.getModel().holon, pas.getEnergy(), print);
+		}
+
+		List<HolonObject> holonObjects = this.model.getAllHolonObjectsOnCanvas();
+//		int totalMerges = holonObjects.stream().mapToInt(ho -> ho.holon.getMergeCounter()).sum();
+//		int totalSplits = holonObjects.stream().mapToInt(ho -> ho.holon.getSplitCounter()).sum();
+//		if(print) {
+//			System.out.println("Total performed merge: "+totalMerges+"\tavg: "+((float)totalMerges)/((float)holonObjects.size()));
+//			System.out.println("Total performed split: "+totalSplits+"\tavg: "+((float)totalSplits)/((float)holonObjects.size()));
+//		}
+	}
+	
+	private void evalPower(Holon h, float curr, boolean print) {
+		ArrayList<Float> avgList = this.averagesPerHolon.getOrDefault(h, new ArrayList<>());
+		if(timeStep >= avgList.size()) {
+			avgList.add(curr);
+		} else {
+			avgList.remove(timeStep);
+			avgList.add(timeStep, curr);
+		}
+		this.averagesPerHolon.put(h, avgList);
+		
+		ArrayList<Integer> mergeList = this.mergesPerHolon.getOrDefault(h, new ArrayList<>());
+		int merges = h.getMergeCounter();// - ((timeStep-1 >= 0 && mergeList.size() > timeStep-1) ? mergeList.get(timeStep-1) : 0);
+		if(timeStep >= mergeList.size()) {
+			mergeList.add(merges);
+		} else {
+			mergeList.remove(timeStep);
+			mergeList.add(timeStep, merges);
+		}
+		this.mergesPerHolon.put(h, mergeList);
+		
+		ArrayList<Integer> splitList = this.splitsPerHolon.getOrDefault(h, new ArrayList<>());
+		int splits = h.getSplitCounter();// - ((timeStep-1 >= 0 && splitList.size() > timeStep-1) ? splitList.get(timeStep-1) : 0);
+		if(timeStep >= splitList.size()) {
+			splitList.add(splits);
+		} else {
+			splitList.remove(timeStep);
+			splitList.add(timeStep, splits);
+		}
+		this.splitsPerHolon.put(h, splitList);
+		
+		ArrayList<Integer> flexList = this.flexesPerHolon.getOrDefault(h, new ArrayList<>());
+		int flexes = h.holonControlUnit.getFlexMan().getAppliedFlexCounter();// - ((timeStep-1 >= 0 && splitList.size() > timeStep-1) ? splitList.get(timeStep-1) : 0);
+		if(timeStep >= flexList.size()) {
+			flexList.add(flexes);
+		} else {
+			flexList.remove(timeStep);
+			flexList.add(timeStep, flexes);
+		}
+		this.flexesPerHolon.put(h, flexList);
+//		float avg = 0f;
+//		for(float f:list)
+//			avg += f;
+//		avg = avg/list.size();
+		float dev = curr-1f;
+		h.countState(dev);
+		if(print) {
+//			System.out.println("next: "+h.getUniqueID()+"\n\tpower stats: "+curr+"\tavg: "+avg+"\t"+list+"\n\tmerges: "+h.getMergeCounter()
+//					+"\tsplits: "+h.getSplitCounter()+"\n\tDeviation: "+dev+"\t["+h.getStateCounter()[0]+", "+h.getStateCounter()[1]+", "
+//					+h.getStateCounter()[2]+"]\n\tHolarchy: "
+//					+h.getMinimumModel().getHolonObjectList().stream().map(ho -> ho.holon.getUniqueID()).collect(Collectors.toList()));
+			System.out.println("next: "+h.getUniqueID()
+					+"\n\tpower stats: "+avgList
+					+"\n\tmerges: "+mergeList
+					+"\n\tsplits: "+splitList
+					+"\n\tflexes: "+flexList
+					+"\n\tstates: ["+h.getStateCounter()[0]+", "+h.getStateCounter()[1]+", "+h.getStateCounter()[2]+"]");
+		}
 	}
 
 	/** 

+ 2 - 2
src/ui/model/Model.java

@@ -953,7 +953,7 @@ public class Model {
 			if(b.equals(current))
 				break;
 			if(!dist.containsKey(current)) {
-				System.out.println("something is wrong "+current+" "+dist);
+//				System.out.println("something is wrong "+current+" "+dist);
 				return null;
 			}
 			float currDist = dist.get(current);
@@ -1009,7 +1009,7 @@ public class Model {
 	}
 	
 	public boolean checkHolonObjectsAreConnected(Holon a, Holon b, float throughput) {
-		if(a.equals(b)) {
+		if(a == null || b == null || a.equals(b)) {
 			return false;
 		}
 		HashSet<AbstractCanvasObject> visited = new HashSet<AbstractCanvasObject>();

+ 1 - 1
src/ui/model/Passiv.java

@@ -8,7 +8,7 @@ public class Passiv extends DecoratedHolonObject {
 	}
 	
 	@Override
-	float getEnergy() {
+	public float getEnergy() {
 		return 0;
 	}
 

+ 2 - 2
src/ui/view/GUI.java

@@ -310,7 +310,7 @@ public class GUI{
 	 * @param control
 	 *            the Controller
 	 */
-	GUI(Control control) {
+	public GUI(Control control) {
 		this.controller = control;
 		this.informationPanel = new HolonInformationPanel(control);
 		this.model = control.getModel();
@@ -2322,7 +2322,7 @@ public class GUI{
 	 *
 	 * @return the Frame
 	 */
-	JFrame getFrmCyberPhysical() {
+	public JFrame getFrmCyberPhysical() {
 		return holegJFrame;
 	}
 

+ 4 - 4
src/ui/view/holarchy/HolarchyPanel.java

@@ -76,7 +76,7 @@ public class HolarchyPanel extends JPanel {
 		this.sep.setBounds(60, 0, 1, 235);
 		this.add(this.sep);
 		this.sep2 = new JSeparator(SwingConstants.HORIZONTAL);
-		this.sep2.setBounds(0, 235, 60, 1);
+		this.sep2.setBounds(0, 230, 60, 1);
 		this.add(this.sep2);
 		
 		this.ellipses = new ArrayList<Map<Ellipse2D, Holon>>();
@@ -352,17 +352,17 @@ public class HolarchyPanel extends JPanel {
 							//child was clicked
 							child = true;
 							parentFrame.displayHolonInfos(ellipsesChild.get(displayedLayer).get(e).get(e2));
-							break;
+							return;
 						}
 					}
 					if(!child) {
 						//no child was clicked
 						parentFrame.displayHolonInfos(ellipses.get(displayedLayer).get(e));
 					}
-					break;
+					return;
 				}
 			}
-			
+			parentFrame.infoPanel.clearInfos();
 		}
 
 		@Override

+ 1 - 1
src/ui/view/holarchy/HolarchyTreePanel.java

@@ -113,7 +113,7 @@ public class HolarchyTreePanel extends JPanel {
 		}
 		public void AddHolon(Holon holon) {
 			holon.removeFromParent();
-			this.holon.merge(holon);
+			this.holon.merge(holon, true);
 		}
 		@Override
 		public Icon getIcon() {

+ 7 - 7
src/ui/view/holarchy/HolarchyWindow.java

@@ -1,15 +1,10 @@
 package ui.view.holarchy;
 
 import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JSeparator;
-import javax.swing.JSlider;
 import javax.swing.JSplitPane;
 import javax.swing.SwingConstants;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
 
 import classes.Holon;
 import util.ImageImport;
@@ -23,6 +18,7 @@ public class HolarchyWindow extends JFrame {
 	HolarchyTreePanel treePanel;
 	ui.controller.Control  controller;
 	public boolean isClosed = false;
+	JScrollPane scrollPane;
 	
 	public HolarchyWindow(JFrame parentFrame, ui.controller.Control  controller){
 		this.controller = controller;
@@ -50,9 +46,13 @@ public class HolarchyWindow extends JFrame {
 //		this.infoPanel.setBounds(this.getWidth()*4/5+1, 0, this.getWidth()*1/5-1, this.getHeight());
 		
 		this.treePanel = new HolarchyTreePanel(this, controller);
-		
-		JSplitPane infoSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, this.infoPanel, new JScrollPane(this.treePanel));
+
+		scrollPane = new JScrollPane(this.infoPanel);
+		scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+		scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+		JSplitPane infoSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollPane, new JScrollPane(this.treePanel));
 		infoSplit.setDividerLocation(this.getHeight()/2);
+		infoSplit.setEnabled(false);
 		
 		JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, this.holarchyPanel, infoSplit);
 		splitPane.setDividerLocation(this.getWidth()*4/5);

+ 11 - 9
src/ui/view/holarchy/HolonInfoPanel.java

@@ -1,13 +1,13 @@
 package ui.view.holarchy;
 
 import java.awt.Color;
+import java.awt.Dimension;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Set;
 
 import javax.swing.JLabel;
 import javax.swing.JPanel;
-import javax.swing.JScrollPane;
 
 import classes.Holon;
 import ui.controller.Control;
@@ -18,9 +18,8 @@ public class HolonInfoPanel extends JPanel {
 	int offset, offsetLabels = 110;
 	HolarchyWindow parentFrame;
 	Holon h = null;
-	//name, state, parent, children, virtualNeihgbors, physicalNeighbors
 	JPanel[] panels = { new JPanel(), new JPanel(), new JPanel()};
-	JLabel[] labels1 = {new JLabel("Name: "), new JLabel("UUID"), new JLabel("State: "), new JLabel("Optimization Scheme: "), new JLabel("Parent: ")};
+	JLabel[] labels1 = {new JLabel("Name: "), new JLabel("UUID: "), new JLabel("State: "), new JLabel("Optimization Scheme: "), new JLabel("Parent: ")};
 	String[] labels2 = {"Subholons", "Virtual neighbors", "Physical neighbors"};
 	Set<JLabel> toRemove = new HashSet<JLabel>();
 	
@@ -28,8 +27,8 @@ public class HolonInfoPanel extends JPanel {
 		this.control = control;
 		this.parentFrame = parentFrame;
 
-		this.setBounds(0, 0, parentFrame.getWidth()*1/5-1, parentFrame.getHeight());
-		this.setBounds(0, 0, parentFrame.getWidth()*1/5-1, parentFrame.getHeight());
+		this.setBounds(0, 0, parentFrame.getWidth()*1/5-21, (parentFrame.getHeight()-100)/2);
+		this.setPreferredSize(new Dimension(parentFrame.getWidth()*1/5-21, parentFrame.getHeight()/2-20));
 		this.offset = parentFrame.getWidth()*4/5+1;
 		this.setLayout(null);
 		this.setVisible(true);
@@ -73,7 +72,6 @@ public class HolonInfoPanel extends JPanel {
 		offset += 21;
 		ArrayList<String> holons = h.holonControlUnit.getHierarchyController().getVirtualNeighbors();
 		for(String s : holons) {
-//			System.out.println("id: "+s);
 			Holon c = this.control.getModel().getHolonsByID().get(s);
 			JLabel l = new JLabel(c.name+"   "+c.getUniqueID());
 			l.setBounds(5,  offset, this.getWidth(), 20);
@@ -99,18 +97,22 @@ public class HolonInfoPanel extends JPanel {
 			this.toRemove.add(l);
 			offset += 21;
 		}
+		this.setPreferredSize(new Dimension(this.getWidth()*1/5-1, offset+21));
 	}
 	
 	public void clearInfos() {
 		this.labels1[0].setText("Name: ");
-		this.labels1[1].setText("State: ");
-		this.labels1[2].setText("Superholon: ");
+		this.labels1[1].setText("UUID: ");
+		this.labels1[2].setText("State: ");
+		this.labels1[3].setText("Optimization scheme: ");
+		this.labels1[4].setText("Parent holon: ");
 		for(JLabel l : this.toRemove) {
 			this.remove(l);
 		}
-		for(int i=1; i<this.panels.length; i++) {
+		for(int i=0; i<this.panels.length; i++) {
 			this.panels[i].setLocation(5, 89+21*i);
 		}
+		this.setPreferredSize(new Dimension(parentFrame.getWidth()*1/5-21, parentFrame.getHeight()/2-20));
 		this.repaint();
 	}
 	

+ 4 - 4
src/ui/view/outliner/HolonView.java

@@ -173,7 +173,7 @@ public class HolonView extends JPanel{
 			holon.addElement(element);
 		}
 		public void AddHolon(Holon holon) {
-			holon.split(this.holon);
+			holon.split(this.holon, true);
 			control.updateHolarchyWindow();
 		}
 		@Override
@@ -224,8 +224,8 @@ public class HolonView extends JPanel{
      	    	parent.removeChildHolon(info.holon);
      	    	Holon newHolon = new Holon("New Holon", control.getModel());
      	    	control.getModel().getHolonsByID().put(newHolon.getUniqueID(), newHolon);
-     	    	newHolon.merge(info.holon);
-     	    	parent.merge(newHolon);
+     	    	newHolon.merge(info.holon, true);
+     	    	parent.merge(newHolon, true);
      	    	updateTreeStructure();
  	    	});
      	   newHolonAsChildItem.addActionListener(clicked -> {
@@ -233,7 +233,7 @@ public class HolonView extends JPanel{
     	    	HolonInfo info = getInfoFromPath(path);
     	    	if(info == null) return;
     	    	Holon newHolon = new Holon("New Holon", control.getModel());
-    	    	info.holon.merge(newHolon);
+    	    	info.holon.merge(newHolon, true);
      	    	control.getModel().getHolonsByID().put(newHolon.getUniqueID(), newHolon);
     	    	updateTreeStructure();
 	    	});

+ 66 - 0
tests/holon_control_unit_evaluation/Main.java

@@ -0,0 +1,66 @@
+package holon_control_unit_evaluation;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintStream;
+
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+
+import org.apache.commons.compress.archivers.ArchiveException;
+
+import ui.controller.Control;
+import ui.model.Model;
+import ui.view.GUI;
+import ui.view.IndexTranslator;
+
+public class Main {
+	
+	public static void main(String[] args) throws FileNotFoundException {
+		if (!System.getProperty("os.name").startsWith("Linux")) {
+			try {
+				UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+			} catch(ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
+				e.printStackTrace();
+			}
+		}
+		
+//		Model model = new Model();
+//        Control control = new Control(model);
+//        GUI view = new GUI(control);
+//        IndexTranslator.model = model;
+//        view.getFrmCyberPhysical().setVisible(true);
+        
+        String fileName = "C:\\Users\\Jonas\\Dropbox\\Mein PC (DESKTOP-L7IQHES)\\Documents\\Uni\\TUD\\Bachelorarbeit\\Eval\\inputs\\scenario02-25h_"+System.currentTimeMillis();
+		String path = "C:\\Users\\Jonas\\Dropbox\\Mein PC (DESKTOP-L7IQHES)\\Documents\\Uni\\TUD\\Bachelorarbeit\\HOLEG\\exampleNetworks\\MyExamples\\scenario02-25h.holon";
+        PrintStream systemOut = System.out;
+		
+        Model model = new Model();
+        Control control = new Control(model);
+        GUI view = new GUI(control);
+        IndexTranslator.model = model;
+        view.getFrmCyberPhysical().setVisible(true);
+        
+    	File outputFile = new File(fileName+".txt");
+		PrintStream printStream = new PrintStream(outputFile);
+		System.setOut(printStream);
+        
+        for(int i=0; i<50; i++) {
+            try {
+				control.loadFile(path);
+			} catch (IOException | ArchiveException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+				return;
+			}
+            for(int j=0; j<100; j++) {
+            	control.getSimManager().calculateStateForTimeStep(j, true);
+            }
+        }
+
+        printStream.close();
+        System.setOut(systemOut);
+	}
+
+}