Browse Source

added flexibility control + new optimization schemes

DESKTOP-L7IQHES\Jonas 2 years ago
parent
commit
ba1ea75f5d
58 changed files with 1959 additions and 273 deletions
  1. BIN
      exampleNetworks/MyExamples/example02.holon
  2. BIN
      exampleNetworks/MyExamples/example03.holon
  3. BIN
      exampleNetworks/MyExamples/flex1.holon
  4. BIN
      exampleNetworks/MyExamples/group1.holon
  5. BIN
      exampleNetworks/MyExamples/merge03h.holon
  6. BIN
      exampleNetworks/MyExamples/merge04.holon
  7. BIN
      exampleNetworks/MyExamples/merge04h.holon
  8. BIN
      exampleNetworks/MyExamples/merge05.holon
  9. BIN
      exampleNetworks/MyExamples/merge06.holon
  10. BIN
      exampleNetworks/MyExamples/merge07.holon
  11. BIN
      exampleNetworks/MyExamples/merge1.holon
  12. BIN
      exampleNetworks/MyExamples/merge1b.holon
  13. BIN
      exampleNetworks/MyExamples/merge2.holon
  14. BIN
      exampleNetworks/MyExamples/merge3.holon
  15. BIN
      exampleNetworks/MyExamples/showKlein.holon
  16. BIN
      exampleNetworks/MyExamples/showMittel-h.holon
  17. BIN
      exampleNetworks/MyExamples/showMittel.holon
  18. BIN
      exampleNetworks/MyExamples/t11.holon
  19. 12 10
      src/classes/AbstractCanvasObject.java
  20. 21 0
      src/classes/Edge.java
  21. 63 0
      src/classes/GroupNode.java
  22. 171 56
      src/classes/Holon.java
  23. 9 2
      src/classes/HolonElement.java
  24. 26 0
      src/classes/HolonObject.java
  25. 17 11
      src/classes/HolonSwitch.java
  26. 46 0
      src/classes/Node.java
  27. 34 5
      src/classes/holonControlUnit/CommunicationModule.java
  28. 86 0
      src/classes/holonControlUnit/FlexibilityManager.java
  29. 42 0
      src/classes/holonControlUnit/ForecastComputationUnit.java
  30. 248 17
      src/classes/holonControlUnit/HierarchyControlUnit.java
  31. 59 7
      src/classes/holonControlUnit/HolonControlUnit.java
  32. 38 2
      src/classes/holonControlUnit/OptimizationManager.java
  33. 91 32
      src/classes/holonControlUnit/StateEstimator.java
  34. 385 1
      src/classes/holonControlUnit/TargetStateAssembler.java
  35. 72 0
      src/classes/holonControlUnit/messages/MergeMsg.java
  36. 1 1
      src/classes/holonControlUnit/messages/Message.java
  37. 26 2
      src/classes/holonControlUnit/messages/NeighborhoodMsg.java
  38. 40 0
      src/classes/holonControlUnit/messages/OrderMsg.java
  39. 30 0
      src/classes/holonControlUnit/messages/SplitMsg.java
  40. 25 2
      src/classes/holonControlUnit/messages/StateMsg.java
  41. 23 1
      src/ui/controller/FlexManager.java
  42. 3 2
      src/ui/controller/LoadController.java
  43. 56 38
      src/ui/controller/SimulationManager.java
  44. 7 3
      src/ui/controller/UpdateController.java
  45. 188 0
      src/ui/model/DecoratedNetwork.java
  46. 7 0
      src/ui/model/DecoratedState.java
  47. 24 8
      src/ui/model/IntermediateCableWithState.java
  48. 49 53
      src/ui/model/Model.java
  49. 15 4
      src/ui/view/FlexWindow.java
  50. 1 3
      src/ui/view/GUI.java
  51. 8 0
      src/ui/view/GroupNodeCanvas.java
  52. 10 4
      src/ui/view/HolonInformationPanel.java
  53. 5 1
      src/ui/view/MyCanvas.java
  54. 10 3
      src/ui/view/holarchy/HolarchyPanel.java
  55. 5 0
      src/ui/view/holarchy/HolarchyTreePanel.java
  56. 1 1
      src/ui/view/holarchy/HolarchyWindow.java
  57. 2 2
      src/ui/view/holarchy/HolonInfoPanel.java
  58. 3 2
      src/ui/view/outliner/HolonView.java

BIN
exampleNetworks/MyExamples/example02.holon


BIN
exampleNetworks/MyExamples/example03.holon


BIN
exampleNetworks/MyExamples/flex1.holon


BIN
exampleNetworks/MyExamples/group1.holon


BIN
exampleNetworks/MyExamples/merge03h.holon


BIN
exampleNetworks/MyExamples/merge04.holon


BIN
exampleNetworks/MyExamples/merge04h.holon


BIN
exampleNetworks/MyExamples/merge05.holon


BIN
exampleNetworks/MyExamples/merge06.holon


BIN
exampleNetworks/MyExamples/merge07.holon


BIN
exampleNetworks/MyExamples/merge1.holon


BIN
exampleNetworks/MyExamples/merge1b.holon


BIN
exampleNetworks/MyExamples/merge2.holon


BIN
exampleNetworks/MyExamples/merge3.holon


BIN
exampleNetworks/MyExamples/showKlein.holon


BIN
exampleNetworks/MyExamples/showMittel-h.holon


BIN
exampleNetworks/MyExamples/showMittel.holon


BIN
exampleNetworks/MyExamples/t11.holon


+ 12 - 10
src/classes/AbstractCanvasObject.java

@@ -175,16 +175,20 @@ public abstract class AbstractCanvasObject {
 		return connections;
 	}
 	
-	public ArrayList<AbstractCanvasObject> getConnectedObjects(){
+	public ArrayList<AbstractCanvasObject> getConnectedObjects(float throughput){
 		ArrayList<AbstractCanvasObject> connected = new ArrayList<AbstractCanvasObject>();
-		
+//		addedThroughput = 0f;
 		for(Edge e : this.connections) {
+//			System.out.println(e+" "+e.getThroughput()+"/"+e.getCapacity()+" "+(e.getThroughput()+Math.abs(addedThroughput))+"/"+e.getCapacity());
 			AbstractCanvasObject a = e.getA();
 			AbstractCanvasObject b = e.getB();
-			if(a.equals(this)) {
-				connected.add(b);
-			} else {
-				connected.add(a);
+			if(!e.isBurned() && throughput <= e.getCapacity()) {
+				//added power would not burn edge
+				if(a.equals(this)) {
+					connected.add(b);
+				} else {
+					connected.add(a);
+				}
 			}
 		}
 		
@@ -213,10 +217,10 @@ public abstract class AbstractCanvasObject {
 		AbstractCanvasObject a = edge.getA();
 		AbstractCanvasObject b = edge.getB();
 		if(a instanceof HolonObject) {
-			((HolonObject) a).holon.holonControlUnit.getHierarchyController().removeEdgeTo(b);
+			((HolonObject) a).holon.holonControlUnit.getHierarchyController().removeEdge(edge);
 		}
 		if(b instanceof HolonObject) {
-			((HolonObject) b).holon.holonControlUnit.getHierarchyController().removeEdgeTo(a);
+			((HolonObject) b).holon.holonControlUnit.getHierarchyController().removeEdge(edge);
 		}
 		connections.remove(edge);
 	}
@@ -269,6 +273,4 @@ public abstract class AbstractCanvasObject {
 	public void setSav(String sav) {
 		this.sav = sav;
 	}
-
-
 }

+ 21 - 0
src/classes/Edge.java

@@ -17,6 +17,7 @@ public class Edge {
     // Working would be false
     @Expose
     private float maxCapacity;
+    private float throughput;
     ArrayList<Integer> tags;
     // for internal use --> flow of electricity (simulation state)
     ArrayList<Integer> pseudoTags;
@@ -43,6 +44,7 @@ public class Edge {
     private boolean breakedManuel = false;
     @Expose
     private boolean unlimitedCapacity = false;
+    private boolean burned = false;
     
     
     /**
@@ -62,6 +64,7 @@ public class Edge {
         }
         this.maxCapacity = 100;
         pseudoTags = new ArrayList<>();
+        this.throughput = 0f;
     }
 
     /**
@@ -76,6 +79,7 @@ public class Edge {
         setB(b);
         this.maxCapacity = maxCap;
         pseudoTags = new ArrayList<>();
+        this.throughput = 0f;
     }
 
     /**
@@ -245,4 +249,21 @@ public class Edge {
 		this.unlimitedCapacity = unlimitedCapacity;
 	}
 
+	public float getThroughput() {
+		return throughput;
+	}
+
+	public void setThroughput(float throughput) {
+//		System.out.println(this+" "+throughput);
+		this.throughput = throughput;
+	}
+
+	public boolean isBurned() {
+		return burned;
+	}
+
+	public void setBurned(boolean burned) {
+		this.burned = burned;
+	}
+
 }

+ 63 - 0
src/classes/GroupNode.java

@@ -4,11 +4,15 @@ import com.google.gson.annotations.Expose;
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
 
 public class GroupNode extends AbstractCanvasObject {
 
 	private ArrayList<AbstractCanvasObject> nodes;
 	private HashMap<Integer, Integer> nodesIdx;
+	private String uniqueID;
 	
 	@Expose
 	private int leftBorder; //TODO Delete leftBorder, jet is just set to 0
@@ -29,6 +33,7 @@ public class GroupNode extends AbstractCanvasObject {
 		this.setId(IdCounter.nextId());
 		this.setNodes(new ArrayList<>());
 		this.setNodesIdx(new HashMap<>());
+		this.uniqueID = "Group Node " + UUID.randomUUID().toString();
 	}
 
 	/**
@@ -197,5 +202,63 @@ public class GroupNode extends AbstractCanvasObject {
 		return this;
 	}
 
+	public String getUniqueID() {
+		if(this.uniqueID == null)
+			this.uniqueID = "Group Node "+UUID.randomUUID().toString();
+		return uniqueID;
+	}
 
+	public ArrayList<String> getAllConnectedHolons(ArrayList<AbstractCanvasObject> visited) {
+		ArrayList<String> conns = new ArrayList<String>();
+		
+		visited.add(this);
+		for(Edge e : this.connections) {
+			AbstractCanvasObject a = e.getA();
+			AbstractCanvasObject b = e.getB();
+			if(b.equals(this) && !visited.contains(a)) {
+				if(a instanceof HolonObject) {
+					conns.add(((HolonObject) a).holon.getUniqueID());
+				} else if(a instanceof HolonSwitch) {
+					conns.addAll(((HolonSwitch)a).getAllConnectedHolons(visited));
+				} else if(a instanceof Node) {
+					conns.addAll(((Node) a).getAllConnectedHolons(visited));
+				} else if(a instanceof GroupNode) {
+					conns.addAll(((GroupNode) a).getAllConnectedHolons(visited));
+				}
+				visited.add(a);
+			} else if(a.equals(this) && !visited.contains(b)) {
+				if(b instanceof HolonObject) {
+					conns.add(((HolonObject) b).holon.getUniqueID());
+				} else if(b instanceof HolonSwitch) {
+					conns.addAll(((HolonSwitch)b).getAllConnectedHolons(visited));
+				} else if(b instanceof Node) {
+					conns.addAll(((Node) b).getAllConnectedHolons(visited));
+				} else if(b instanceof GroupNode) {
+					conns.addAll(((GroupNode) b).getAllConnectedHolons(visited));
+				}
+				visited.add(b);
+			}
+		}
+		for(AbstractCanvasObject a : this.nodes) {
+			if(a instanceof HolonObject) {
+				conns.add(((HolonObject) a).holon.getUniqueID());
+			} else if(a instanceof HolonSwitch) {
+				conns.addAll(((HolonSwitch)a).getAllConnectedHolons(visited));
+			} else if(a instanceof Node) {
+				conns.addAll(((Node) a).getAllConnectedHolons(visited));
+			} else if(a instanceof GroupNode) {
+				conns.addAll(((GroupNode) a).getAllConnectedHolons(visited));
+			}
+			visited.add(a);
+		}
+		
+		return conns;
+	}
+	
+	public List<AbstractCanvasObject> getAllObjectsInside(){
+		return this.nodes.stream()
+				.map(aco -> aco instanceof GroupNode ? ((GroupNode) aco).getAllObjectsInside() : List.of(aco))
+				.flatMap(List::stream)
+				.collect(Collectors.toList());
+	}
 }

+ 171 - 56
src/classes/Holon.java

@@ -26,24 +26,22 @@ public class Holon {
 	public Model model;
 	private MinimumModel minModel;
 	/** stores whether the part between this holon and the child is occupied by the superholon */
-	private boolean canRunIndependentFromParent;
+	private HashMap<Holon, ArrayList<Edge>> pathsToChildren;
 	
 	public Holon(String name, Model model) {
 		this.name = name;
-		this.parent = parent;
 		this.holonObject = null;
 		isPhysical = false;
 		this.uniqueID = UUID.randomUUID().toString();
 		this.model = model;
 		this.holonControlUnit = new HolonControlUnit(this);
 		this.minModel = new MinimumModel(new ArrayList<AbstractCanvasObject>(), new ArrayList<Edge>());
-		this.canRunIndependentFromParent = true;
+		this.pathsToChildren = new HashMap<Holon, ArrayList<Edge>>();
 	}
 	
 	public Holon(HolonObject object, Model model) {
 		holonObject = object;
 		object.holon = this;
-		this.parent = parent;
 		name = object.getName();
 		elements.addAll(object.getElements());
 		for(HolonElement ele : elements) {
@@ -56,7 +54,7 @@ public class Holon {
 		ArrayList<AbstractCanvasObject> list = new ArrayList<AbstractCanvasObject>();
 		list.add(object);
 		this.minModel = new MinimumModel(list, new ArrayList<Edge>());
-		this.canRunIndependentFromParent = true;
+		this.pathsToChildren = new HashMap<Holon, ArrayList<Edge>>();
 	}
 	
 	
@@ -73,25 +71,35 @@ public class Holon {
 	}
 	
 	public void addChild(Holon child) {
+		if(child.equals(this)) {
+			System.err.println(this.uniqueID+" wants to merge itself");
+		}
 		if(!this.childHolons.contains(child)) {
-			child.parent = this;
+			child.setParent(this);
 			this.childHolons.add(child);
 		}
-		this.holonControlUnit.addSubHolon(child);
+		if(this.parent != null) {
+			this.holonControlUnit.addSubHolon(child);
+		}
 	}
 	
 	public void addChildHolon(Holon child, int index) {
 		if(!this.childHolons.contains(child)) {
-			child.parent = this;
+			child.setParent(this);
 			childHolons.add(index, child);
 		}
-		this.holonControlUnit.addSubHolon(child);
+		if(this.parent != null) {
+			this.holonControlUnit.addSubHolon(child);
+		}
 	}
 	
 	public void removeChildHolon(Holon child) {
-		child.parent = null;
+		child.setParent(null);
 		childHolons.remove(child);
+		if(this.parent == null)
+			return;
 		this.holonControlUnit.getHierarchyController().removeSubHolon(child.getUniqueID());
+		this.pathsToChildren.remove(child);
 		revalidateMinModel();
 	}
 	
@@ -99,7 +107,7 @@ public class Holon {
 		if(parent != null) {
 			parent.removeChildHolon(this);
 		}
-		parent = model.getStateHolon();
+		this.setParent(model.getStateHolon());
 	}
 	
 	
@@ -113,7 +121,9 @@ public class Holon {
 	
 	public void setParent(Holon parent) {
 		this.parent = parent;
-		this.holonControlUnit.getHierarchyController().setSuperHolon(parent.getUniqueID());
+		if(parent != null) {
+			this.holonControlUnit.getHierarchyController().setSuperHolon(parent.getUniqueID());
+		}
 	}
 	
 	public HolonObject getHolonObject() {
@@ -144,7 +154,7 @@ public class Holon {
 	
 	
 	public void removeAllRefrences() {
-		parent = null;
+		this.setParent(null);
 		this.childHolons.clear();
 		this.elements.clear();
 	}
@@ -152,6 +162,11 @@ public class Holon {
 	
 	
 	public int getLayer() {
+		if(this.parent == null)
+			return 0;
+		if(this.parent.equals(this)) {
+			return 0;
+		}
 		return parent != null ? parent.getLayer() +  1 : 0;
 	}
 	
@@ -186,7 +201,7 @@ public class Holon {
 		return null;
 	}
 	
-	
+	@Deprecated
 	public void checkRepairHolarchy(HashMap<HolonObject, DecoratedNetwork> table, Holon stateHolon) {
 		if(childHolons.isEmpty()) {
 			return;
@@ -207,7 +222,7 @@ public class Holon {
 			if(isPureAbstract) {
 				continue;
 			}
-			boolean isPhysicalConnected = model.checkHolonObjectsAreConnected(this, other);
+			boolean isPhysicalConnected = model.checkHolonObjectsAreConnected(this, other, 0f);
 			if(!isPhysicalConnected) {
 				removeList.add(other);
 			}
@@ -240,49 +255,90 @@ public class Holon {
 		return list;
 	}
 	
+	public ArrayList<AbstractCanvasObject> getAllObjects(){
+		ArrayList<AbstractCanvasObject> list = new ArrayList<AbstractCanvasObject>();
+		
+		list.addAll(this.minModel.getHolonObjectList());
+		list.addAll(this.minModel.getNodeList());
+		list.addAll(this.minModel.getSwitchList());
+		list.addAll(this.minModel.getUppderNodeList());
+		
+		return list;
+	}
+	
 	public MinimumModel getMinimumModel() {
 		return this.minModel;
 	}
 	
+	public HashMap<Holon, ArrayList<Edge>> getPathsToChildren() {
+		return pathsToChildren;
+	}
+
+	/**
+	 * merge this holon as a child with the holon specified by the id
+	 * @param id
+	 */
+	public void merge(String id) {
+		if(id.equals("State Holon")) {
+			this.split(this.model.getStateHolon());
+			return;
+		}
+		Holon h = this.model.getHolonsByID().get(id);
+		if(h != null) {
+			h.split(this);
+		}
+	}
+	
+	/**
+	 * merge this holon with the specified child holon
+	 * @param child
+	 */
 	public void merge(Holon child) {
 		if(!this.model.getHolonsByID().containsKey(child.getUniqueID())) {
 			System.err.println("could not find: "+child.getHolonObject());
 			return;
 		}
-		
+
 		if(this.childHolons.contains(child)) {
 			return;
 		}
-		
-		if(this.getLayer() == 0) {
+
+		if(this.parent == null) {
 			this.addChild(child);
 			return;
 		}
 		
-		//check if path between this holon and child holon is already occupied
-		ArrayList<HolonObject> holarchy = getAllHolonObjects();
-		holarchy.addAll(child.getAllHolonObjects());
-		HashMap<Float, ArrayList<Edge>> paths = this.model.getShortestPathToHolarchy(this.minModel, child.getMinimumModel(), holarchy);
+		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>>();
 		HashMap<ArrayList<Edge>, Holon> occ_by = new HashMap<ArrayList<Edge>, Holon>();
-		
+
 		for(Float f : paths.keySet()) {
 			ArrayList<Edge> path = paths.get(f);
 			Holon holder = isPathOccupied(path);
-			if(holder == null || holder.getLayer() == 0 || holder.equals(this.parent)) {
+			if(holder == null || holder.getParent() == null || holder.equals(this) || holder.equals(this.parent)) {
+				//path between this holon and child holon is free
 				free_paths.put(f, path);
 			} else {
+				//path between this holon and child holon is already occupied
 				occ_paths.put(f, path);
 				occ_by.put(path, holder);
 			}
 		}
 		
 		if(free_paths.size() > 0) {
-			//there is a free path, take it and add child directly
+			//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);
+				return;
+			}
 			this.addChild(child);
-			this.addChildToMinModel(child, free_paths.get(getShortestPath(free_paths)));
-			if(this.getLayer() > 1) {
+			this.addChildToMinModel(child, path);
+			this.pathsToChildren.put(child, path);
+			if(this.parent != null && this.parent.getParent() != null) {
 				this.parent.recalculateMinModel();
 			}
 			return;
@@ -291,21 +347,17 @@ public class Holon {
 			System.err.println("something went wrong when looking for shortest path while merging "+this.uniqueID+" and "+child.getUniqueID());
 		}
 		ArrayList<ArrayList<Edge>> shortestPaths = sortPaths(occ_paths);
-		for(int i=0; i< shortestPaths.size(); i++) {
-			//check if holon should merge with holder of this path
-			ArrayList<Edge> path = shortestPaths.get(i);
-			Holon holder = occ_by.get(path);
-			//if true try to merge with holon which is using the path
-			if(holder != null && holder.getLayer() > 0) {
-				this.split(holder);
-				this.addChild(child);
-				this.addChildToMinModel(child, path);
-				if(this.parent != null && this.getLayer() > 1) {
-					this.parent.recalculateMinModel();
-				}
-				this.canRunIndependentFromParent = false;
+		//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);
+			this.addChild(child);
+			this.addChildToMinModel(child, path);
+			this.pathsToChildren.put(child, path);
+			if(this.parent != null && this.parent.getParent() != null) {
+				this.parent.recalculateMinModel();
 			}
-			break;
 		}
 	}
 	
@@ -355,23 +407,26 @@ public class Holon {
 	 * removes this holon from current superholon and merge with new superholon
 	 */
 	public void split(Holon newParent) {
-		if(newParent == null) {
-			System.err.println("can not split without new super holon");
+		//ensure that this holarchy can run independent(path is not occupied by superholon) from the superholon
+		if(!this.parent.canRunIndependent(this)) {
 			return;
 		}
 		
-		//ensure that this holarchy can run independent(path is not occupied by superholon) from the superholon
-		if(!this.canRunIndependentFromParent) {
-			return;
+		if(newParent == null) {
+			newParent = this.model.getStateHolon();
 		}
 		
 		if(this.parent != null) {
 			this.parent.removeChildHolon(this);
 		}
-		
+		this.holonControlUnit.getHierarchyController().resetVirtualNeighbors();
 		newParent.merge(this);
 	}
 	
+	public void splitById(String id) {
+		this.model.getHolonsByID().get(id).split(null);
+	}
+	
 	/**
 	 * recalculates the min model after a holon was added to a subholon
 	 * does NOT recalculate the shortest paths between its subholons
@@ -394,11 +449,10 @@ public class Holon {
 				edges.add(icws.getModel());
 			}
 		}
-		
 		this.minModel = new MinimumModel(objects, edges);
 		
 		//notify superholon to recalculate its minModel
-		if(this.parent != null && this.getLayer() > 0) {
+		if(this.parent != null && this.parent.getParent() != null && this.parent != this) {
 			this.parent.recalculateMinModel();
 		}
 	}
@@ -408,7 +462,7 @@ public class Holon {
 	 * @param child
 	 */
 	private void addChildToMinModel(Holon child, ArrayList<Edge> path) {
-		if(this.minModel.getHolonObjectList().contains(child.getHolonObject()) || getLayer() == 0)
+		if(this.minModel.getHolonObjectList().contains(child.getHolonObject()) || this.parent == null)
 			return;
 		
 		ArrayList<Edge> edgeList = new ArrayList<Edge>();
@@ -434,7 +488,6 @@ public class Holon {
 				objects.add(b);
 			}
 		}
-		
 		this.minModel = new MinimumModel(objects, edgeList);
 	}
 	
@@ -442,16 +495,17 @@ public class Holon {
 	 * revalidate this min model after a subholon was removed
 	 */
 	public void revalidateMinModel() {
-		if(getLayer() == 0)
+		if(this.parent == null)
 			return;
 
-		this.canRunIndependentFromParent = true;
 		ArrayList<AbstractCanvasObject> list = new ArrayList<AbstractCanvasObject>();
 		list.add(this.holonObject);
 		this.minModel = new MinimumModel(list, new ArrayList<Edge>());
 		for(int i=0; i< this.childHolons.size(); i++) {
 			Holon child = this.childHolons.remove(0);
-			this.merge(child);
+			if(this.model.checkHolonObjectsAreConnected(this, child, this.holonControlUnit.getStateEstimator().getNetThroughput())) {
+				this.merge(child);
+			}
 		}
 		
 		if(this.parent != null) {
@@ -459,11 +513,22 @@ public class Holon {
 		}
 	}
 	
+	public void revalidateMinModelAfterLoad() {
+		if(this.childHolons.size() == 0) {
+			this.revalidateMinModel();
+		} else {
+			List<Holon> list = List.copyOf(this.childHolons);
+			for(Holon child : list) {
+				child.revalidateMinModelAfterLoad();
+			}
+		}
+	}
+	
 	/**
 	 * returns the holon which uses the specified path if it is included in min model, otherwise null
 	 */
 	public Holon containsPath(ArrayList<Edge> path, Holon requester) {
-		if(this.minModel.containsPath(path) || this.getLayer() == 0) {
+		if(this.minModel.containsPath(path) || this.parent == null) {
 			for(Holon child : this.childHolons) {
 				if(child.equals(requester))
 					continue;
@@ -475,7 +540,57 @@ public class Holon {
 			
 			return this;
 		}
-		
+		for(Edge e : path) {
+			AbstractCanvasObject a = e.getA();
+			AbstractCanvasObject b = e.getB();
+			if(a instanceof HolonObject &&  this.childHolons.contains(((HolonObject) a).holon))
+				return ((HolonObject) a).holon;
+			if(b instanceof HolonObject &&  this.childHolons.contains(((HolonObject) b).holon))
+				return ((HolonObject) b).holon;
+			if(this.getAllObjects().contains(a) || this.getAllObjects().contains(b))
+				return this;
+		}
+
 		return null;
 	}
+	
+	/**
+	 * checks whether the requester can run without this holon (none of the paths inside the requesters model is occupied by this model)
+	 * @param requester
+	 * @return
+	 */
+	public boolean canRunIndependent(Holon requester) {
+		if(this.parent == null || this.parent.getParent() == null)
+			return true;
+		
+		ArrayList<AbstractCanvasObject> objects = new ArrayList<AbstractCanvasObject>();
+		objects.addAll(requester.getMinimumModel().getHolonObjectList());
+		objects.addAll(requester.getMinimumModel().getNodeList());
+		objects.addAll(requester.getMinimumModel().getSwitchList());
+		
+		for(Holon child : this.childHolons) {
+			if(child.equals(requester))
+				continue;
+			ArrayList<Edge> path = this.pathsToChildren.get(child);
+			ArrayList<AbstractCanvasObject> pathObjects = new ArrayList<AbstractCanvasObject>();
+			for(Edge e : path) {
+				AbstractCanvasObject a = e.getA();
+				AbstractCanvasObject b = e.getB();
+				if(!pathObjects.contains(a))
+					pathObjects.add(a);
+				if(!pathObjects.contains(b))
+					pathObjects.add(b);
+			}
+			for(AbstractCanvasObject aco : pathObjects) {
+				if(objects.contains(aco))
+					return false;
+			}
+		}
+		
+		return true;
+	}
+	
+	public boolean isASuperiorHolon(String holon) {
+		return this.parent != null ? (this.parent.getUniqueID().equals(holon) || this.parent.isASuperiorHolon(holon)) : false;
+	}
 }

+ 9 - 2
src/classes/HolonElement.java

@@ -109,6 +109,7 @@ public class HolonElement implements LocalMode, GraphEditable{
         sampleGraph();
         setId(id);
         this.priority = Priority.Low;
+        this.holon = parentObject.holon;
     }
 
     /**
@@ -117,7 +118,6 @@ public class HolonElement implements LocalMode, GraphEditable{
      * @param element element to copy
      */
     public HolonElement(HolonElement element) {
-    	this.parentObject = element.parentObject;
     	this.priority = element.getPriority();
     	setLocalPeriod(element.getLocalPeriod());
     	setUseLocalPeriod(element.isUsingLocalPeriod());
@@ -133,7 +133,6 @@ public class HolonElement implements LocalMode, GraphEditable{
         sampleGraph();
         setSaving(null);
         setId(IdCounterElem.nextId());
-
     }
 
 	public String getObjName() {
@@ -477,4 +476,12 @@ public class HolonElement implements LocalMode, GraphEditable{
 		this.isUsingLocalPeriod=state;
 	}
 	
+	public void orderFlex(Flexibility flex, int timeStep) {
+		if(this.holon != null) {
+			this.holon.holonControlUnit.getFlexMan().orderFlex(flex, timeStep);
+		} else if(this.parentObject != null && this.parentObject.holon != null) {
+			this.parentObject.holon.holonControlUnit.getFlexMan().orderFlex(flex, timeStep);
+		}
+	}
+	
 }

+ 26 - 0
src/classes/HolonObject.java

@@ -178,6 +178,14 @@ public class HolonObject extends AbstractCanvasObject {
     public float getMinimumConsumingElementEnergyWithFlex(int timestep, FlexManager flexManager){
     	return getElements().stream().filter(element -> element.isOn(flexManager) && (element.getEnergyAtTimeStep(timestep) < 0) ).map(element -> -element.getEnergyAtTimeStep(timestep)).min((lhs,rhs) ->Float.compare(lhs, rhs)).orElse(0.0f);
     }
+    public float getMinimumConsumingElementEnergyFlex(int timeStep) {
+    	return getElements().stream()
+    			.filter(element -> element.isOn(this.holon.holonControlUnit.getFlexMan().getFlexManager(timeStep)) 
+    					&& (element.getEnergyAtTimeStep(timeStep) < 0))
+    			.map(element -> -element.getEnergyAtTimeStep(timeStep))
+    			.min((lhs,rhs) ->Float.compare(lhs, rhs))
+    			.orElse(0.0f);
+    }
     /**
      * This Method returns the biggest consuming HolonElement'Energy that is ACTIVE.
      * If the HolonObject has no Consumer its return 0. 
@@ -205,6 +213,12 @@ public class HolonObject extends AbstractCanvasObject {
     	return getElements().stream().filter(element -> element.isOn(flexManager)).map(element -> element.getEnergyAtTimeStep(timestep)).reduce(0.0f, (a, b) -> a + b);
     }
     
+    public float getEnergyAtTimeStepFlex(int timeStep) {
+    	return getElements().stream()
+    			.filter(element -> element.isOn(this.holon.holonControlUnit.getFlexMan().getFlexManager(timeStep)))
+    			.map(element -> element.getEnergyAtTimeStep(timeStep))
+    			.reduce(0.0f, (a, b) -> a + b);    	
+    }
     
     public float getMaximumProductionPossible(int timestep) {
     	return elements.stream().filter(element -> element.getEnergyAtTimeStep(timestep) > 0).map(element -> element.getEnergyAtTimeStep(timestep)).reduce(0.0f, Float::sum);
@@ -229,6 +243,12 @@ public class HolonObject extends AbstractCanvasObject {
     public float getEnergySelfProducingFromProducingElementsWithFlex(int timestep, FlexManager flexManager) {
     	return getElements().stream().filter(element -> element.isOn(flexManager) && (element.getEnergyAtTimeStep(timestep) > 0)).map(element -> element.getEnergyAtTimeStep(timestep)).reduce(0.0f, (a, b) -> a + b);
     }
+    public float getEnergySelfProducingFromProducingElementsFlex(int timestep) {
+    	return getElements().stream()
+    			.filter(element -> element.isOn(this.holon.holonControlUnit.getFlexMan().getFlexManager(timestep)) 
+    					&& (element.getEnergyAtTimeStep(timestep) > 0)).map(element -> element.getEnergyAtTimeStep(timestep))
+    			.reduce(0.0f, (a, b) -> a + b);
+    }
     /** 
      * This Method returns the Energy of all HolonElements from the HolonObject that are consuming. Its sums all Energies from the HolonElements of the HolonObject that are ACTIVE and are Consumer.
      * If the HolonObject have no HolonElement its return 0;
@@ -241,6 +261,12 @@ public class HolonObject extends AbstractCanvasObject {
     public float getEnergyNeededFromConsumingElementsWithFlex(int timestep, FlexManager flexManager) {
     	return getElements().stream().filter(element -> element.isOn(flexManager) && (element.getEnergyAtTimeStep(timestep) < 0)).map(element -> -element.getEnergyAtTimeStep(timestep)).reduce(0.0f, (a, b) -> a + b);
     }
+    public float getEnergyNeededFromConsumingElementsFlex(int timestep) {
+    	return getElements().stream()
+    			.filter(element -> element.isOn(this.holon.holonControlUnit.getFlexMan().getFlexManager(timestep)) 
+    					&& (element.getEnergyAtTimeStep(timestep) < 0)).map(element -> -element.getEnergyAtTimeStep(timestep))
+    			.reduce(0.0f, (a, b) -> a + b);
+    }
     /**
      * This Method calculate the amount of HolonElements that are consuming Energy and are ACTIVE.
      * @param timestep is the TimeStep to compare the HolonElements.

+ 17 - 11
src/classes/HolonSwitch.java

@@ -325,33 +325,39 @@ public class HolonSwitch extends AbstractCanvasObject implements LocalMode, Grap
 		
 	}
 	
-	public ArrayList<String> getAllConnectedHolons() {
-		ArrayList<String> conns = new ArrayList();
+	public ArrayList<String> getAllConnectedHolons(ArrayList<AbstractCanvasObject> visited) {
+		ArrayList<String> conns = new ArrayList<String>();
 		
 		//switch is open therefore it does not connect objects
 		if(!this.isClosed())
 			return conns;
 		
+		visited.add(this);
 		for(Edge e : this.connections) {
 			AbstractCanvasObject a = e.getA();
 			AbstractCanvasObject b = e.getB();
-			System.out.println("This: "+this.id+" A: "+e.getA().id+" B: "+e.getB().id);
-			if(b.equals(this)) {
+			if(b.equals(this) && !visited.contains(a)) {
 				if(a instanceof HolonObject) {
 					conns.add(((HolonObject) a).holon.getUniqueID());
 				} else if(a instanceof HolonSwitch) {
-					conns.addAll(((HolonSwitch)a).getAllConnectedHolons());
-				} else {
-					
+					conns.addAll(((HolonSwitch)a).getAllConnectedHolons(visited));
+				} else if(a instanceof Node) {
+					conns.addAll(((Node) a).getAllConnectedHolons(visited));
+				} else if(a instanceof GroupNode) {
+					conns.addAll(((GroupNode) a).getAllConnectedHolons(visited));
 				}
-			} else {
+				visited.add(a);
+			} else if(a.equals(this) && !visited.contains(b)) {
 				if(b instanceof HolonObject) {
 					conns.add(((HolonObject) b).holon.getUniqueID());
 				} else if(b instanceof HolonSwitch) {
-					conns.addAll(((HolonSwitch)b).getAllConnectedHolons());
-				} else {
-					
+					conns.addAll(((HolonSwitch)b).getAllConnectedHolons(visited));
+				} else if(b instanceof Node) {
+					conns.addAll(((Node) b).getAllConnectedHolons(visited));
+				} else if(b instanceof GroupNode) {
+					conns.addAll(((GroupNode) b).getAllConnectedHolons(visited));
 				}
+				visited.add(b);
 			}
 		}
 		

+ 46 - 0
src/classes/Node.java

@@ -1,6 +1,7 @@
 package classes;
 
 import java.util.ArrayList;
+import java.util.UUID;
 
 /**
  * The class "CpsNode" represents empty Objects in the system. They are just
@@ -11,6 +12,8 @@ import java.util.ArrayList;
  */
 public class Node extends AbstractCanvasObject {
 	
+	private String uniqueID;
+	
 	/**
 	 * Create a new node in the system with an user-defined name.
 	 * 
@@ -23,10 +26,12 @@ public class Node extends AbstractCanvasObject {
 		this.setImage("/Images/node.png");
 		this.setSav("CVS");
 		this.setId(IdCounter.nextId());
+		this.uniqueID = "Node " + UUID.randomUUID();
 	}
 	
 	public Node(Node node){
 		super(node);
+		this.uniqueID = "Node " + UUID.randomUUID();
 	}
 	
 	public String toString(){
@@ -37,4 +42,45 @@ public class Node extends AbstractCanvasObject {
 	public AbstractCanvasObject makeCopy() {
 		return new Node(this);
 	}
+	
+	public String getUniqueID() {
+		if(this.uniqueID == null)
+			this.uniqueID = "Node "+UUID.randomUUID().toString();
+		return uniqueID;
+	}
+
+	public ArrayList<String> getAllConnectedHolons(ArrayList<AbstractCanvasObject> visited) {
+		ArrayList<String> conns = new ArrayList<String>();
+		
+		visited.add(this);
+		for(Edge e : this.connections) {
+			AbstractCanvasObject a = e.getA();
+			AbstractCanvasObject b = e.getB();
+			if(b.equals(this) && !visited.contains(a)) {
+				if(a instanceof HolonObject) {
+					conns.add(((HolonObject) a).holon.getUniqueID());
+				} else if(a instanceof HolonSwitch) {
+					conns.addAll(((HolonSwitch)a).getAllConnectedHolons(visited));
+				} else if(a instanceof Node) {
+					conns.addAll(((Node) a).getAllConnectedHolons(visited));
+				} else if(a instanceof GroupNode) {
+					conns.addAll(((GroupNode) a).getAllConnectedHolons(visited));
+				}
+				visited.add(a);
+			} else if(a.equals(this) && !visited.contains(b)) {
+				if(b instanceof HolonObject) {
+					conns.add(((HolonObject) b).holon.getUniqueID());
+				} else if(b instanceof HolonSwitch) {
+					conns.addAll(((HolonSwitch)b).getAllConnectedHolons(visited));
+				} else if(b instanceof Node) {
+					conns.addAll(((Node) b).getAllConnectedHolons(visited));
+				} else if(b instanceof GroupNode) {
+					conns.addAll(((GroupNode) b).getAllConnectedHolons(visited));
+				}
+				visited.add(b);
+			}
+		}
+		
+		return conns;
+	}
 }

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

@@ -1,14 +1,15 @@
 package classes.holonControlUnit;
 
 import classes.Holon;
+import classes.holonControlUnit.messages.MergeMsg;
 import classes.holonControlUnit.messages.Message;
 import classes.holonControlUnit.messages.NeighborhoodMsg;
+import classes.holonControlUnit.messages.OrderMsg;
+import classes.holonControlUnit.messages.SplitMsg;
 import classes.holonControlUnit.messages.StateMsg;
 import classes.holonControlUnit.messages.StateRequestMsg;
 
 import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
 
 import com.google.gson.Gson;
 
@@ -47,17 +48,23 @@ public class CommunicationModule {
 		
 		switch (msg.getType()) {
 			case ORDER:
-				
+				this.hcu.getStateAssembler().setOrder(this.gson.fromJson(msg.getBody(), OrderMsg.class), msg.getSender());
 				break;
 			case NEIGHBORHOOD:
 				receiveNeighborhoodMsg(msg);
 				break;
 			case STATE_REQUEST:
-				this.hcu.getStateEstimator().receiveStateRequest(msg.getSender(), this.gson.fromJson(msg.getBody(), StateRequestMsg.class));
+				this.hcu.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));
 				break;
+			case MERGE:
+				receiveMergeMsg(msg);
+				break;
+			case SPLIT:
+				receiveSplitMsg(msg);
+				break;
 			default:
 				throw new RuntimeException("Unknown message type:\n"+message);
 		}
@@ -78,10 +85,32 @@ public class CommunicationModule {
 			case REMOVE_PHYSICAL_NEIGHBOR:
 				break;
 			default:
-				throw new RuntimeException("Unknown neighborhood type:\n"+msg);
+				System.err.println("Unknown neighborhood type:\n"+msg);
 		}
 	}
 	
+	private void receiveMergeMsg(Message msg) {
+		MergeMsg mMsg = this.gson.fromJson(msg.getBody(), MergeMsg.class);
+		switch(mMsg.getType()) {
+			case REQ:
+				this.hcu.getHierarchyController().receiveMergeReq(mMsg, msg.getSender());
+				break;
+			case ACK:
+				this.hcu.getHierarchyController().receiveMergeAck(mMsg, msg.getSender());
+				break;
+			case ACK_II:
+				this.hcu.getHierarchyController().receiveMergeAckII(mMsg, msg.getSender());
+				break;
+			default:
+				System.err.println("Unknown neighborhood type:\n"+msg);
+		}
+	}
+	
+	private void receiveSplitMsg(Message msg) {
+		SplitMsg split = this.gson.fromJson(msg.getBody(), SplitMsg.class);
+		this.hcu.getHierarchyController().receiveSplitMsg(split, msg.getSender());
+	}
+	
 	public Gson getGson() {
 		return this.gson;
 	}

+ 86 - 0
src/classes/holonControlUnit/FlexibilityManager.java

@@ -1,5 +1,91 @@
 package classes.holonControlUnit;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import classes.Flexibility;
+import ui.controller.FlexManager;
+import ui.controller.FlexManager.FlexState;
+
 public class FlexibilityManager {
 
+	private HolonControlUnit hcu;
+	private HashMap<Integer, FlexManager> savesFlexManager;
+	
+	public FlexibilityManager(HolonControlUnit hcu) {
+		this.hcu = hcu;
+		this.savesFlexManager = new HashMap<>();
+	}
+	
+	public float applyFlexibilities(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());
+		List<List<Flexibility>> offeredPerm = getAllPermutations(offeredFlexes);
+		HashMap<Float, List<Flexibility>> map = new HashMap<>();
+		for(List<Flexibility> l : offeredPerm) {
+			float pu = 0f;
+//			ArrayList<Float> pus = new ArrayList<>();
+			for(Flexibility f : l) {
+				pu += f.fulfillsConstrains() ? f.getElement().getEnergyPerElement() : 0f;
+				if(Math.abs(pu) > Math.abs(requiredPower))
+					break;
+			}
+			if(Math.abs(pu) <= Math.abs(requiredPower))
+				map.put(pu, l);
+		}
+
+		float max = 0f;
+		for(float f : map.keySet()) {
+			if(Math.abs(f) > Math.abs(max)) {
+//				System.out.println("cand "+f);
+				max = f;
+			}
+		}
+		if(map.containsKey(max)) {
+			fm.orderFlexFromList(map.get(max));
+			System.out.println(this.hcu.getHolon().getUniqueID()+" ordered flexes "+map.get(max));
+		}
+		
+		return max;
+	}
+	
+	public FlexManager getFlexManager(int timeStep) {
+		boolean doesFlexManagerExist = savesFlexManager.containsKey(timeStep);
+		boolean createNew = !doesFlexManagerExist;
+		FlexManager newFlexManager;
+		if(createNew) {
+			newFlexManager = new FlexManager(List.of(this.hcu.getHolon().getHolonObject()), timeStep, savesFlexManager.get(timeStep-1));
+			if(doesFlexManagerExist) newFlexManager.orderFlexFromList(savesFlexManager.get(timeStep).getAllFlexesOrderedThisTimeStep());
+			savesFlexManager.put(timeStep, newFlexManager);
+		}else {
+			newFlexManager = savesFlexManager.get(timeStep);
+		}
+//		System.out.println("+++++++++");
+//		newFlexManager.getAllFlexWrapper().stream().forEach(fw -> System.out.print(fw.getFlex().name+" "+fw.getState()+", "));
+//		System.out.println("\n+++++++++");
+		return newFlexManager;
+	}
+	
+	public void orderFlex(Flexibility flex, int timeStep) {
+		System.out.println(this.hcu.getHolon().getUniqueID()+" ordered flex "+flex);
+		getFlexManager(timeStep).orderFlex(flex);
+	}
+	
+	private <T> List<List<T>> getAllPermutations(List<T> set){
+		List<List<T>> out = new ArrayList<List<T>>();
+		
+		for(int i=0; i<set.size(); i++) {
+			for(int j=i; j<set.size(); j++) {
+				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;
+	}
 }

+ 42 - 0
src/classes/holonControlUnit/ForecastComputationUnit.java

@@ -1,5 +1,47 @@
 package classes.holonControlUnit;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import classes.Holon;
+import classes.holonControlUnit.messages.StateMsg;
+
+/**
+ * here we "try" to predict the future power usage inside the holon
+ * as predicted values we use the real power usage values for future timestamps
+ * @author Jonas
+ *
+ */
 public class ForecastComputationUnit {
 
+	public final int N_TIMESTEPS = 5;
+	
+	private HolonControlUnit hcu;
+	
+	public ForecastComputationUnit(HolonControlUnit hcu) {
+		this.hcu = hcu;
+	}
+	
+	public ArrayList<Float> computeForecast(HashMap<String, StateMsg> childStates, int timeStep){
+		ArrayList<Float> forecast = new ArrayList<Float>();
+		
+		Holon holon = this.hcu.getHolon();
+		for(int i=0; i<this.N_TIMESTEPS; i++) {
+			//compute power usage for timestamp+i
+			int t = timeStep+i+1;
+			if(t >= holon.model.getIterations())
+				break;
+			float powerUsage = 0f;
+			for(String s : childStates.keySet()) {
+				powerUsage += childStates.get(s).getPredictedPowerUsage().get(i);
+			}
+			if(holon.isPhysical) {
+				powerUsage += holon.getHolonObject().getEnergyAtTimeStep(t);
+			}
+			forecast.add(powerUsage);
+		}
+//		System.out.println("Forecast for "+holon.getHolonObject()+"\n\t"+forecast);
+		return forecast;
+	}
+	
 }

+ 248 - 17
src/classes/holonControlUnit/HierarchyControlUnit.java

@@ -2,10 +2,7 @@ package classes.holonControlUnit;
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
 
 import classes.AbstractCanvasObject;
 import classes.Edge;
@@ -13,7 +10,12 @@ import classes.GroupNode;
 import classes.Holon;
 import classes.HolonObject;
 import classes.HolonSwitch;
+import classes.Node;
 import classes.holonControlUnit.messages.NeighborhoodMsg;
+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.Message;
 
 public class HierarchyControlUnit {
@@ -23,15 +25,16 @@ public class HierarchyControlUnit {
 	private ArrayList<String> subHolons;
 	private ArrayList<String> physicalNeighbors;
 	private ArrayList<String> virtualNeighbors;
-	private Map<String, HolonSwitch> switches;
+	private ArrayList<ArrayList<MergeMsg>> receivedMergeRequests;	//store merge requests for each timestep
+	private ArrayList<HashMap<String, MergeMsg>> sendMergeRequests;
 	
 	public HierarchyControlUnit(HolonControlUnit hcu) {
 		this.hcu = hcu;
-		this.subHolons = new ArrayList();
-		this.physicalNeighbors = new ArrayList();
-		
-		this.virtualNeighbors = new ArrayList();
-		this.switches = new HashMap();
+		this.subHolons = new ArrayList<>();
+		this.physicalNeighbors = new ArrayList<>();
+		this.virtualNeighbors = new ArrayList<>();
+		this.receivedMergeRequests = new ArrayList<ArrayList<MergeMsg>>();
+		this.sendMergeRequests = new ArrayList<HashMap<String, MergeMsg>>();
 	}
 	
 	public ArrayList<String> getPhysicalNeighbors() {
@@ -56,6 +59,10 @@ public class HierarchyControlUnit {
 		this.virtualNeighbors = virtualNeighbors;
 	}
 	
+	public void resetVirtualNeighbors() {
+		this.virtualNeighbors.clear();
+	}
+	
 	public void addSubHolon(String subHolon) {
 		if(this.subHolons.contains(subHolon))
 			return;
@@ -75,10 +82,10 @@ public class HierarchyControlUnit {
 	
 	public void removeSubHolon(String subHolon) {
 		if(!this.subHolons.remove(subHolon)) {
-			System.err.println("Could not remove sub holon "+subHolon);
+			System.err.println(this.hcu.getHolon().getUniqueID()+" could not remove sub holon "+subHolon+"\n\t"+subHolons);
 			return;
 		}
-		ArrayList<String> list = new ArrayList();
+		ArrayList<String> list = new ArrayList<String>();
 		list.add(subHolon);
 		String body = this.hcu.getCommunicator().getGson().toJson(new NeighborhoodMsg(NeighborhoodMsg.Type.REMOVE_VIRTUAL_NEIGHBOR, list));
 		for(String sub : this.subHolons) {
@@ -98,6 +105,17 @@ public class HierarchyControlUnit {
 		return this.subHolons;
 	}
 	
+	public ArrayList<ArrayList<MergeMsg>> getMergeRequests() {
+		return receivedMergeRequests;
+	}
+	
+	public ArrayList<MergeMsg> getMergeRequestsForTimeStep(int timeStep){
+		if(timeStep >= 0 && timeStep < this.receivedMergeRequests.size()) {
+			return this.receivedMergeRequests.get(timeStep);
+		}
+		return new ArrayList<MergeMsg>();
+	}
+
 	public void addVirtualNeighbor(String virtualNeighbor) {
 		if(!this.virtualNeighbors.contains(virtualNeighbor)) {
 			this.virtualNeighbors.add(virtualNeighbor);
@@ -132,27 +150,240 @@ public class HierarchyControlUnit {
 			HolonSwitch hs = (HolonSwitch) b;
 			if(!this.physicalNeighbors.contains(hs.getUniqueID())) {
 				this.physicalNeighbors.add(hs.getUniqueID());
-				this.switches.put(hs.getUniqueID(), hs);
 			}
+		} else if(b instanceof Node) {
+			Node n = (Node) b;
+			if(!this.physicalNeighbors.contains(n.getUniqueID()))
+				this.physicalNeighbors.add(n.getUniqueID());
 		} else if (b instanceof GroupNode) {
-			//go inside groupnode and find the endpoint
-			
+			GroupNode n = (GroupNode) b;
+			if(!this.physicalNeighbors.contains(n.getUniqueID()))
+				this.physicalNeighbors.add(n.getUniqueID());
 		}
 	}
 	
 	public void removeEdgeTo(AbstractCanvasObject b) {
 		if(b instanceof HolonObject) {
-			//add holon of b as physical neighbor
+			//remove holon of b as physical neighbor
 			Holon ho = ((HolonObject) b).holon;
 			this.physicalNeighbors.remove(ho.getUniqueID());
 		} else if(b instanceof HolonSwitch) {
 			//get edges of b and add them if switch is open
 			HolonSwitch hs = (HolonSwitch) b;
 			this.physicalNeighbors.remove(hs.getUniqueID());
-			this.switches.remove(hs.getUniqueID());
+		} else if(b instanceof Node) {
+			Node n = (Node) b;
+			this.physicalNeighbors.remove(n.getUniqueID());
 		} else if (b instanceof GroupNode) {
-			//go inside groupnode and find the endpoint
+			GroupNode n = (GroupNode) b;
+			this.physicalNeighbors.remove(n.getUniqueID());
+			
+		}
+	}
+	
+	public void removeEdge(Edge e) {
+		AbstractCanvasObject a = e.getA();
+		AbstractCanvasObject b = e.getB();
+		if(a.equals(this.hcu.getHolon().getHolonObject())) {
+			removeEdgeTo(b);
+		} else {
+			removeEdgeTo(a);
+		}
+		//check if connection to super or subholon is affected
+		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");
+		}
+		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");
+			}
+		}
+	}
+	
+	public void receiveMergeReq(MergeMsg msg, String sender) {
+		if(!canMerge(msg.getRequester(), msg.getPower())) {
+			return;
+		}
 			
+		int timeStep = msg.getTimeStep();
+		if(timeStep >= 0) {
+			if(timeStep >= this.receivedMergeRequests.size() && timeStep <= this.hcu.getHolon().model.getIterations()) {
+				for(int i=this.receivedMergeRequests.size(); i<=timeStep; i++) {
+					this.receivedMergeRequests.add(new ArrayList<MergeMsg>());
+				}
+			}
+			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;
+						}
+					}
+					//the request is a duplicate
+					if(b)
+						return;
+				}
+			}
+			list.add(msg);
+		}
+	}
+	
+	public void receiveMergeAck(MergeMsg msg, String sender) {
+		if(this.superHolon.equals(sender) || this.subHolons.contains(sender) || !canMerge(msg.getRequester(), msg.getPower())) {
+			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;
+		}
+		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())) {
+			//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);
+		}
+	}
+	
+	public void receiveMergeAckII(MergeMsg msg, String sender) {
+		if(!canMerge(msg.getRequester(), msg.getPower())) {
+			return;
+		}
+		this.hcu.getHolon().merge(sender);
+		if(msg.getRedirectedBy() == null || msg.getRedirectedBy().size() == 0) {
+			this.hcu.getStateEstimator().receiveState(sender, msg.getState());
+		}
+	}
+	
+	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<>());
+		if(this.sendMergeRequests.size() <= timeStep) {
+			for(int i=this.sendMergeRequests.size(); i<=timeStep; i++) {
+				this.sendMergeRequests.add(new HashMap<>());
+			}
+		}
+		this.sendMergeRequests.get(timeStep).put(physicalNeighbor, msg);
+		String body = this.hcu.getCommunicator().getGson().toJson(msg, MergeMsg.class);
+		this.hcu.getCommunicator().sendMsg(physicalNeighbor, Message.Type.MERGE, body);
+	}
+	
+	public void sendMergeAck(int timeStep, MergeMsg req) {
+		MergeMsg msg = new MergeMsg(MergeMsg.Type.ACK, req.getPower(), this.hcu.getStateEstimator().getNetThroughput(), req.getPredictedPowerUsage(), 
+				this.hcu.getHolon().getUniqueID(), timeStep, req.getState(), req.getRedirectedBy());
+		String body = this.hcu.getCommunicator().getGson().toJson(msg, MergeMsg.class);
+		this.hcu.getCommunicator().sendMsg(req.getRequester(), Message.Type.MERGE, body);
+	}
+	
+	public void propagateMergeReqToParent(int timeStep) {
+		if(timeStep < 0 || timeStep >= this.hcu.getHolon().model.getIterations() || timeStep >= this.receivedMergeRequests.size() 
+				|| 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))
+				continue;
+			req.getRedirectedBy().add(this.hcu.getHolon().getUniqueID());
+			String body = this.hcu.getCommunicator().getGson().toJson(req, MergeMsg.class);
+			this.hcu.getCommunicator().sendMsg(this.superHolon, Message.Type.MERGE, body);
+		}
+	}
+	
+	public void splitSubHolon(String id, int timeStep) {
+		if(!this.subHolons.contains(id))
+			return;
+		SplitMsg msg = new SplitMsg(SenderRealtion.SUPERHOLON, timeStep);
+		String body = this.hcu.getCommunicator().getGson().toJson(msg, SplitMsg.class);
+		this.hcu.getCommunicator().sendMsg(id, Message.Type.SPLIT, body);
+		this.hcu.getHolon().splitById(id);
+	}
+	
+	public void splitSuperHolon(int timeStep) {
+		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);
+	}
+	
+	public void receiveSplitMsg(SplitMsg msg, String sender) {
+		if(msg.getType() == SenderRealtion.SUPERHOLON && this.superHolon.equals(sender)) {
+//			System.out.println(this.hcu.getHolon().getUniqueID()+" my super holon kicked me out :(");
+		} else if (msg.getType() == SenderRealtion.SUBHOLON && this.subHolons.contains(sender)) {
+//			System.out.println(this.hcu.getHolon().getUniqueID()+" my child holon abandoned me :(");
 		}
 	}
+	
+	/**
+	 * get all physical neighbors that are not subholons (or a subholon of a subholon) and not virtual neighbors
+	 * @return
+	 */
+	public ArrayList<String> getPhysicalNeighborsFromOtherHolarchy(){
+		ArrayList<String> neighbors = new ArrayList<String>();
+		
+		for(String s : this.physicalNeighbors) {
+			if(!s.contains("Switch") && !s.contains("Node") && !s.contains("Group Node") && !s.equals(this.superHolon) 
+					&& !this.subHolons.contains(s) && !this.virtualNeighbors.contains(s)) {
+				neighbors.add(s);
+			} else if(s.contains("Switch") || s.contains("Node") || s.contains("Group Node")) {
+				ArrayList<String> potNeighbors = this.hcu.getHolon().model.getAllConnectionsFromObject(s, this.hcu.getHolon().getUniqueID());
+				for(String s2 : potNeighbors) {
+					if(!s2.equals(this.superHolon) && !this.subHolons.contains(s2) && !this.virtualNeighbors.contains(s2)) {
+						neighbors.add(s2);
+					}
+				}
+			}
+		}
+		
+		return neighbors;
+	}
+	
+	/**
+	 * checks if the other holon is a subholon (or subholon of subholon), this superholon or if the added throughput would burn any edges
+	 * @param other
+	 * @param addedThroughput
+	 * @return
+	 */
+	public boolean canMerge(String other, float addedThroughput) {
+		Holon thisHolon = this.hcu.getHolon();
+		Holon otherHolon = thisHolon.model.getHolonsByID().get(other);
+		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
+			// d) this holon is a superior holon of other holon
+			return false;
+		}
+		
+		return true;
+	}
 }

+ 59 - 7
src/classes/holonControlUnit/HolonControlUnit.java

@@ -1,12 +1,12 @@
 package classes.holonControlUnit;
 
 import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.List;
 
 import classes.Holon;
 import classes.holonControlUnit.messages.Message;
-import classes.holonControlUnit.messages.NeighborhoodMsg;
+import classes.holonControlUnit.messages.StateMsg;
+import classes.holonControlUnit.messages.StateRequestMsg;
 
 public class HolonControlUnit {
 	
@@ -18,16 +18,18 @@ public class HolonControlUnit {
 	private StateEstimator stateEstimator;
 	private TargetStateAssembler stateAssembler;
 	private CommunicationModule communicator;
+	private ArrayList<StateMsg> states;
 	
 	public HolonControlUnit(Holon h) {
 		this.holon = h;
 		this.hierarchyController = new HierarchyControlUnit(this);
-		this.flexMan = new FlexibilityManager();
-		this.forecaster = new ForecastComputationUnit();
-		this.optimizer = new OptimizationManager();
+		this.flexMan = new FlexibilityManager(this);
+		this.forecaster = new ForecastComputationUnit(this);
+		this.optimizer = new OptimizationManager(this);
 		this.stateEstimator = new StateEstimator(this);
-		this.stateAssembler = new TargetStateAssembler();
+		this.stateAssembler = new TargetStateAssembler(this);
 		this.communicator = new CommunicationModule(this);
+		this.states = new ArrayList<StateMsg>();
 	}
 
 	public ArrayList<Holon> getSubHolon() {
@@ -77,5 +79,55 @@ public class HolonControlUnit {
 	public CommunicationModule getCommunicator() {
 		return communicator;
 	}
+	
+	public void computeState(int timeStep) {
+		//compute current state
+		this.stateEstimator.computeState(timeStep);
+		//compute target state
+		this.stateAssembler.assembleTargetState(timeStep);
+		//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);
+		float tres = Math.max(10-threshold*10, diff);	//otherwise the range could be 0
+		if(power > des + tres || power < des - tres)
+			return false;
+		for(int i=0; i<prePower.size(); i++) {
+			if(prePower.get(i) > des + tres || prePower.get(i) < des - tres)
+				return false;
+		}
+		return true;
+	}
+	
+	public boolean decreasesPowerUsage(float requiredPower, float powerUsage, List<Float> predictedPowerUsage) {
+		if(Math.abs(powerUsage) > Math.abs(requiredPower))
+			return false;
+		
+		for(int i=0; i<predictedPowerUsage.size(); i++) {
+			if(Math.abs(predictedPowerUsage.get(i)) > Math.abs(requiredPower))
+				return false;
+		}
+		return true;
+	}
 }

+ 38 - 2
src/classes/holonControlUnit/OptimizationManager.java

@@ -1,16 +1,36 @@
 package classes.holonControlUnit;
 
+import java.util.ArrayList;
+
 public class OptimizationManager {
 
 	public enum OptimizationScheme {
 		COMFORT, MIN_COST, ENERGY_CONSUMPTION, STABILITY, RECOVERY
 	}
+	public static final float POWER_THRESHOLD_COMFORT = 0.99f;
+	public static final float POWER_THRESHOLD_STABILITY = 0.9f;
+	public static final float POWER_THRESHOLD_RECOVERY = 0f;
 	
+	private HolonControlUnit hcu;
 	private OptimizationScheme optimizationScheme;
 	
-	public OptimizationManager() {
+	public OptimizationManager(HolonControlUnit hcu) {
+		this.hcu = hcu;
 		this.optimizationScheme = OptimizationScheme.COMFORT;
 	}
+	
+	public void evaluateOptimizationScheme(int timeStep) {
+		float power = this.hcu.getStateEstimator().getPowerUsage();
+		float des = this.hcu.getStateAssembler().getDesiredPowerUsage();
+		ArrayList<Float> prePower = this.hcu.getStateEstimator().getPredictedPowerUsage();
+		if(this.hcu.matchPowerRange(power, des, prePower, POWER_THRESHOLD_COMFORT)) {
+			this.optimizationScheme = OptimizationScheme.COMFORT;
+		} else if(this.hcu.matchPowerRange(power, des, prePower, POWER_THRESHOLD_STABILITY)) {
+			this.optimizationScheme = OptimizationScheme.STABILITY;
+		} else {
+			this.optimizationScheme = OptimizationScheme.RECOVERY;
+		}
+	}
 
 	public OptimizationScheme getOptimizationScheme() {
 		return optimizationScheme;
@@ -20,5 +40,21 @@ public class OptimizationManager {
 		this.optimizationScheme = optimizationScheme;
 	}
 	
-	
+	public float getCurrentPowerThreshold() {
+		switch(this.optimizationScheme) {
+			case COMFORT:
+				return POWER_THRESHOLD_COMFORT;
+			case MIN_COST:
+				return POWER_THRESHOLD_COMFORT;
+			case ENERGY_CONSUMPTION:
+				return POWER_THRESHOLD_COMFORT;
+			case STABILITY:
+				return POWER_THRESHOLD_STABILITY;
+			case RECOVERY:
+				return POWER_THRESHOLD_RECOVERY;
+			default:
+				System.err.println("Unknown optimizaion scheme "+this.optimizationScheme);
+		}
+		return 0f;
+	}
 }

+ 91 - 32
src/classes/holonControlUnit/StateEstimator.java

@@ -2,12 +2,16 @@ package classes.holonControlUnit;
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 
 import classes.Holon;
-import classes.HolonElement;
+import classes.holonControlUnit.OptimizationManager.OptimizationScheme;
 import classes.holonControlUnit.messages.Message;
 import classes.holonControlUnit.messages.StateMsg;
 import classes.holonControlUnit.messages.StateRequestMsg;
+import ui.controller.FlexManager;
+import ui.model.DecoratedCable.CableState;
+import ui.model.IntermediateCableWithState;
 
 /**
  * aggregates all states from sub holons and forwards the resulting own state to the state assembler
@@ -25,16 +29,20 @@ public class StateEstimator {
 		/* stability/functionality of holon is not guaranteed */
 		DYSFUNCTIONAL
 	}
-	private final float POWER_TRESHOLD = 0.95f;
 	
 	private HolonControlUnit hcu;
 	private StateIndicator stateInd;
 	private float powerUsage;
+	private float netThroughput;
 	private HashMap<String, StateMsg> childStates;
+	private ArrayList<Float> predictedPowerUsage;
+	private HashMap<String, Float> powerUsagesInsideHolarchy;
 	
 	public StateEstimator(HolonControlUnit hcu) {
 		this.hcu = hcu;
 		this.stateInd = StateIndicator.DESIRED;
+		this.powerUsagesInsideHolarchy = new HashMap<String, Float>();
+		this.childStates = new HashMap<String, StateMsg>();
 	}
 
 	public StateIndicator getStateIndicator() {
@@ -43,57 +51,108 @@ public class StateEstimator {
 	
 	/**
 	 * Depth-first computation
-	 * aggregates childrens state first, then computes own state
+	 * aggregate childrens state first, then compute own state
 	 */
 	public void computeState(int timeStep) {
-		//request childrens state
-		this.childStates = new HashMap<String, StateMsg>();
-		ArrayList<String> children = this.hcu.getHierarchyController().getSubHolons();
-		for(String child : children) {
-			//send request to child
-			this.hcu.getCommunicator().sendMsg(child, Message.Type.STATE_REQUEST, 
-					this.hcu.getCommunicator().getGson().toJson(new StateRequestMsg(timeStep)));
+		//check if any edge is burned
+		for(IntermediateCableWithState icws : this.hcu.getHolon().getMinimumModel().getEdgeList()) {
+			if(icws.getState() == CableState.Burned || icws.getModel().isBurned()) {
+//				System.out.println(icws.getModel()+" burned");
+				this.hcu.getHierarchyController().removeEdge(icws.getModel());
+			}
 		}
-		//wait for sub holons to compute state and send it
-		if(this.childStates.size() < children.size()) {
-			System.err.println("Something went wrong while computing state of "+this.hcu.getHolon().getUniqueID());
-			System.err.println("\tchildStates "+childStates);
-			System.err.println("\tchildren "+children);
-			return;
+		//request childrens state
+		this.childStates.clear();
+		requestChildStates(timeStep);
+		calculatePowerUsage(timeStep);
+		calculateNetThroughput(timeStep);
+		//compute forecast
+		this.predictedPowerUsage = this.hcu.getForecaster().computeForecast(this.childStates, timeStep);
+		
+		boolean b = this.hcu.matchPowerRange(powerUsage, this.hcu.getStateAssembler().getDesiredPowerUsage(), this.predictedPowerUsage, 
+				this.hcu.getOptimizer().getCurrentPowerThreshold());
+		if(b && this.hcu.getOptimizer().getOptimizationScheme() != OptimizationScheme.RECOVERY) {
+			this.stateInd = StateIndicator.DESIRED;
+		} else if (b){
+			this.stateInd = StateIndicator.ENDANGERED;
+		} else {
+			this.stateInd = StateIndicator.DYSFUNCTIONAL;
 		}
-		//aggregate cub holons state
+	}
+	
+	private void calculatePowerUsage(int timeStep) {
+		//aggregate sub holon state
 		this.powerUsage = 0;
 		for(String s : this.childStates.keySet()) {
-			this.powerUsage += this.childStates.get(s).getPowerUsage();
+			float p = this.childStates.get(s).getPowerUsage();
+			this.powerUsage += p;
+			this.powerUsagesInsideHolarchy.put(s, p);
 		}
 		//add state from holon elements
 		Holon holon = this.hcu.getHolon();
 		if(holon.isPhysical) {
-			this.powerUsage += holon.getHolonObject().getEnergyAtTimeStep(timeStep);
+			float p = holon.getHolonObject().getEnergyAtTimeStepWithFlex(timeStep, this.hcu.getFlexMan().getFlexManager(timeStep));
+			this.powerUsage += p;
+			this.powerUsagesInsideHolarchy.put(this.hcu.getHolon().getUniqueID(), p);
 		}
-		if(this.powerUsage < this.POWER_TRESHOLD * this.hcu.getStateAssembler().getDesiredPowerUsage()) {
-			this.stateInd = StateIndicator.DESIRED;
-		} else {
-			this.stateInd = StateIndicator.ENDANGERED;
+	}
+	
+	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))
+				.reduce(0.0f, ((a,b) -> a + b));
+	}
+	
+	public void requestChildStates(int timeStep) {
+		List<String> children = List.copyOf(this.hcu.getHierarchyController().getSubHolons());
+		if(this.childStates.size() == children.size())
+			return;
+		for(String child : children) {
+			//send request to child
+			if(!this.childStates.containsKey(child)) {
+				this.hcu.getCommunicator().sendMsg(child, Message.Type.STATE_REQUEST, 
+						this.hcu.getCommunicator().getGson().toJson(new StateRequestMsg(timeStep)));
+			}
+		}
+		//wait for sub holons to compute state and send it
+		if(this.childStates.size() < children.size()) {
+			//a subholon has disappeared, remove it from child holon
+			for(String s : children) {
+				if(!this.childStates.containsKey(s)) {
+					this.hcu.getHierarchyController().splitSubHolon(s, timeStep);
+//					System.err.println(this.hcu.getHolon().getUniqueID()+" holon "+s+" has disappeared "
+//								+this.hcu.getHierarchyController().canMerge(s, 0f));
+				}
+			}
 		}
 	}
 	
 	public void receiveState(String sender, StateMsg stateMsg) {
-		if(this.childStates == null)
+		if(this.childStates == null || stateMsg == null)
 			return;
 		this.childStates.put(sender, stateMsg);
 	}
-	
-	public void receiveStateRequest(String sender, StateRequestMsg req) {
-		computeState(req.getTimeStep());
-		//send current state to sender/super holon
-		StateMsg stateMsg = new StateMsg(this.powerUsage);
-		String body = this.hcu.getCommunicator().getGson().toJson(stateMsg);
-		this.hcu.getCommunicator().sendMsg(sender, Message.Type.STATE, body);
-	}
 
 	public float getPowerUsage() {
 		return this.powerUsage;
 	}
+
+	public HashMap<String, Float> getPowerUsagesInsideHolarchy() {
+		return this.powerUsagesInsideHolarchy;
+	}
+
+	public ArrayList<Float> getPredictedPowerUsage() {
+		return this.predictedPowerUsage;
+	}
+
+	public HashMap<String, StateMsg> getChildStates() {
+		return this.childStates;
+	}
+
+	public float getNetThroughput() {
+		return netThroughput;
+	}
 	
 }

+ 385 - 1
src/classes/holonControlUnit/TargetStateAssembler.java

@@ -1,11 +1,395 @@
 package classes.holonControlUnit;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import com.google.gson.Gson;
+
+import classes.holonControlUnit.OptimizationManager.OptimizationScheme;
+import classes.holonControlUnit.messages.MergeMsg;
+import classes.holonControlUnit.messages.Message;
+import classes.holonControlUnit.messages.OrderMsg;
+import classes.holonControlUnit.messages.StateMsg;
+
 public class TargetStateAssembler {
 	
+	private HolonControlUnit hcu;
 	private float desiredPowerUsage = 100f;
+	private OrderMsg order;
+	private HashMap<String, OrderMsg> ordersForSubholon;
+	
+	public TargetStateAssembler(HolonControlUnit hcu) {
+		this.order = null;
+		this.hcu = hcu;
+		this.ordersForSubholon = new HashMap<String, OrderMsg>();
+	}
+	
+	public void assembleTargetState(int timeStep) {
+		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());
+
+		//balance the sub holons
+		switch(this.hcu.getOptimizer().getOptimizationScheme()) {
+			case COMFORT:
+				assembleTargetStateComfort(timeStep);
+				break;
+			case MIN_COST:
+				break;
+			case ENERGY_CONSUMPTION:
+				break;
+			case STABILITY:
+				assembleTargetStateStability(timeStep);
+				break;
+			case RECOVERY:
+				assembleTargetStateRecovery(timeStep);
+				break;
+			default:
+				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) {
+		//overall power usage inside this holarchy
+		float powerUsage = this.hcu.getStateEstimator().getPowerUsage();
+		ArrayList<Float> predictedPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage();
+		if(predictedPowerUsage.size() < 1) {
+			//no more iterations inside simulator
+			return;
+		}
+
+		//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");
+			this.hcu.getHierarchyController().splitSuperHolon(timeStep);
+			this.desiredPowerUsage = 0f;
+		}
+
+		//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);
+			}
+			return;
+		}
+		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);
+		if(savedWithFlexibilities == requiredPower) {
+			return;
+		}
+		requiredPower -= savedWithFlexibilities;
+		
+		//go through merge requests from last iteration
+		float savedByMerging = gothroughMergeReq(timeStep, requiredPower, predictedPowerUsage, OptimizationScheme.COMFORT);
+		if(savedByMerging == requiredPower) {
+			return;
+		}
+		requiredPower -= savedByMerging;
+		
+		//look out for another superholon
+		findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage);
+		
+		//tell all holons to use a little more/less energy
+		orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower, OptimizationScheme.COMFORT);
+	}
+	
+	private void assembleTargetStateStability(int timeStep) {
+		//overall power usage inside this holarchy
+		float powerUsage = this.hcu.getStateEstimator().getPowerUsage();
+		ArrayList<Float> predictedPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage();
+		if(predictedPowerUsage.size() < 1) {
+			//no more iterations inside simulator
+			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);
+			}
+			return;
+		}
+		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);
+		if(savedWithFlexibilities == requiredPower) {
+			return;
+		}
+		requiredPower -= savedWithFlexibilities;
+		
+		//go through merge requests from last iteration
+		float savedByMerging = gothroughMergeReq(timeStep, requiredPower, predictedPowerUsage, OptimizationScheme.STABILITY);
+		if(savedByMerging == requiredPower) {
+			return;
+		}
+		requiredPower -= savedByMerging;
+		
+		//look out for another superholon
+		findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage);
+		
+		//tell all holons to use a little more/less energy
+		orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower, OptimizationScheme.STABILITY);
+	}
+	
+	private void assembleTargetStateRecovery(int timeStep) {
+		//overall power usage inside this holarchy
+		float powerUsage = this.hcu.getStateEstimator().getPowerUsage();
+		ArrayList<Float> predictedPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage();
+		if(predictedPowerUsage.size() < 1) {
+			//no more iterations inside simulator
+			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);
+			}
+			return;
+		}
+		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);
+		if(savedWithFlexibilities == requiredPower) {
+			return;
+		}
+		requiredPower -= savedWithFlexibilities;
 
+		//go through merge requests from last iteration
+		float savedByMerging = gothroughMergeReq(timeStep, requiredPower, predictedPowerUsage, OptimizationScheme.RECOVERY);
+		if(savedByMerging == requiredPower) {
+			return;
+		}
+		requiredPower -= savedByMerging;
+		
+		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();
+		List<List<String>> childPerm = getAllPermutations(List.copyOf(childStates.keySet()));
+		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;
+			for(String s : l) {
+				if(Math.abs(pu) > Math.abs(requiredPower))
+					break;
+				pu += childStates.get(s).getPowerUsage();
+			}
+			if(Math.abs(pu) <= Math.abs(requiredPower)) {
+				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;
+		for(float f : potChild.keySet()) {
+			if(Math.abs(f) > Math.abs(max)) {
+				max = f;
+			}
+		}
+		//split all other subholons
+		List<String> list = new ArrayList<String>();
+		if(potChild.containsKey(max)) {
+			list = potChild.get(max);
+		}
+		List<String> subs = List.copyOf(this.hcu.getHierarchyController().getSubHolons());
+		for(String s : subs) {
+			if(!list.contains(s)) {
+				this.hcu.getHierarchyController().splitSubHolon(s, timeStep);
+			}
+		}
+		requiredPower -= max;
+		if(requiredPower == 0) {
+			return;
+		}
+
+		//Split from superholon?
+		if(Math.abs(requiredPower) > Math.abs(p) && this.hcu.getHolon().getLayer() > 1) {
+			this.hcu.getHierarchyController().splitSuperHolon(timeStep);
+			return;
+		}
+		
+		//look out for another superholon
+		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);
+	}
+
+	/**
+	 * go through all previously received merge requests from other holons
+	 * if there is a fitting one merge
+	 * @param timeStep
+	 * @param requiredPower
+	 * @return saved power
+	 */
+	private float gothroughMergeReq(int timeStep, float requiredPower, ArrayList<Float> predictedPowerUsage, 
+			OptimizationScheme optScheme) {
+		List<MergeMsg> requests = this.hcu.getHierarchyController().getMergeRequestsForTimeStep(timeStep-1);
+		if(requests == null)
+			return 0f;
+		//store holon which would help decrease |requiredPower|
+		ArrayList<MergeMsg> poten = new ArrayList<MergeMsg>();
+		//find a perfect match or holon which would help decrease |requiredPower|
+		for(MergeMsg req : requests) {
+			float r = req.getPredictedPowerUsage().get(0); //since merge req is from timeStep-1
+			String requester = req.getRequester();
+			float newThroughput = req.getNetThroughput() + this.hcu.getStateEstimator().getNetThroughput();
+			
+			if(!this.hcu.getHierarchyController().canMerge(requester, newThroughput)) {
+				//cannot merge with the requester
+				continue;
+			}
+			
+			if(this.hcu.matchPowerRange(r, requiredPower, predictedPowerUsage, 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);
+				requests.remove(req);
+				return r;
+			} else if( ((r < 0 && requiredPower < 0) || (r > 0 && requiredPower > 0))
+					&& this.hcu.decreasesPowerUsage(requiredPower, r, req.getPredictedPowerUsage())) {
+				//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
+		if(poten.size() < 1)
+			return 0f;
+		List<List<MergeMsg>> potPermut = getAllPermutations(poten);
+		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()];
+			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
+				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())
+					continue;
+				potSavings.put(saving, l);
+			}
+		}
+		if(potSavings.size() < 1) {
+			return 0f;
+		}
+		float max = 0f;
+		for(float f : potSavings.keySet()) {
+			if(Math.abs(f) > Math.abs(max)) {
+				max = f;
+			}
+		}
+		//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);
+			}
+			requests.removeAll(potSavings.get(max));
+		}
+		return max;
+	}
+	
+	private void findNewSuperHolon(int timeStep, float powerUsage, ArrayList<Float> predictedPowerUsage) {
+		for(String physicalNeighbor : this.hcu.getHierarchyController().getPhysicalNeighborsFromOtherHolarchy()) {
+			this.hcu.getHierarchyController().sendMergeReq(powerUsage, predictedPowerUsage, timeStep, physicalNeighbor);
+		}
+	}
+	
+	
+	/**
+	 * compute a new target value for all subholons
+	 * "fairness": all subholons get same target value
+	 * @param timeStep
+	 * @param powerUsage
+	 * @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);
+		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);
+		}
+	}
+	
+	private <T> List<List<T>> getAllPermutations(List<T> set){
+		List<List<T>> out = new ArrayList<List<T>>();
+		
+		for(int i=0; i<set.size(); i++) {
+			for(int j=i; j<set.size(); j++) {
+				List<T> l = new ArrayList<T>();
+				l.addAll(set.subList(i, j+1));
+				out.add(l);
+			}
+		}
+		
+		return out;
+	}
+	
 	public float getDesiredPowerUsage() {
-		return desiredPowerUsage;
+		return this.desiredPowerUsage;
 	}
 
+	public void setOrder(OrderMsg order, String sender) {
+		if(sender.equals(this.hcu.getHierarchyController().getSuperHolon())) {
+			this.order = order;
+		}
+	}
+	
 }

+ 72 - 0
src/classes/holonControlUnit/messages/MergeMsg.java

@@ -0,0 +1,72 @@
+package classes.holonControlUnit.messages;
+
+import java.util.ArrayList;
+
+public class MergeMsg {
+	
+	public enum Type {
+		REQ, ACK, ACK_II
+	}
+
+	private Type type;
+	private float power;
+	private float netThroughput;
+	private ArrayList<Float> predictedPowerUsage;
+	private String requester;
+	private int timeStep;
+	private StateMsg state;
+	private ArrayList<String> redirectedBy;
+
+	public MergeMsg(Type type, float power, float netThroughput, ArrayList<Float> predictedPowerUsage, String requester, 
+			int timeStep, StateMsg state, ArrayList<String> redirectedBy) {
+		super();
+		this.type = type;
+		this.power = power;
+		this.netThroughput = netThroughput;
+		this.predictedPowerUsage = predictedPowerUsage;
+		this.requester = requester;
+		this.timeStep = timeStep;
+		this.state = state;
+		this.redirectedBy = redirectedBy;
+	}
+
+	@Override
+	public String toString() {
+		return "MergeMsg [type=" + type + ", power=" + power + ", netThroughput=" + netThroughput
+				+ ", predictedPowerUsage=" + predictedPowerUsage + ", requester=" + requester + ", timeStep=" + timeStep
+				+ ", state=" + state + ", redirectedBy=" + redirectedBy + "]";
+	}
+
+	public Type getType() {
+		return type;
+	}
+	
+	public float getPower() {
+		return power;
+	}
+	
+	public ArrayList<Float> getPredictedPowerUsage() {
+		return predictedPowerUsage;
+	}
+
+	public String getRequester() {
+		return requester;
+	}
+
+	public int getTimeStep() {
+		return timeStep;
+	}
+
+	public float getNetThroughput() {
+		return netThroughput;
+	}
+
+	public StateMsg getState() {
+		return state;
+	}
+
+	public ArrayList<String> getRedirectedBy() {
+		return redirectedBy;
+	}
+	
+}

+ 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
+		ORDER, NEIGHBORHOOD, STATE_REQUEST, STATE, MERGE, SPLIT
 	}
 	private String sender;
 	private String receiver;

+ 26 - 2
src/classes/holonControlUnit/messages/NeighborhoodMsg.java

@@ -6,9 +6,13 @@ import classes.Holon;
 
 public class NeighborhoodMsg {
 
-	public enum Type { NEW_VIRTUAL_NEIGHBOR, REMOVE_VIRTUAL_NEIGHBOR, NEW_PHYSICAL_NEIGHBOR, REMOVE_PHYSICAL_NEIGHBOR }
+	public enum Type { 
+		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();
@@ -16,9 +20,21 @@ 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 + ", newVirtualNeighbor=" + neighbors + "]";
+		return "NeighborhoodMsg [type=" + type + ", neighbors=" + neighbors + ", layer=" + layer + ", id=" + id + "]";
 	}
 
 	public ArrayList<String> getNeighbors() {
@@ -28,5 +44,13 @@ public class NeighborhoodMsg {
 	public Type getType() {
 		return type;
 	}
+
+	public int getLayer() {
+		return layer;
+	}
+
+	public String getId() {
+		return id;
+	}
 	
 }

+ 40 - 0
src/classes/holonControlUnit/messages/OrderMsg.java

@@ -0,0 +1,40 @@
+package classes.holonControlUnit.messages;
+
+import java.util.ArrayList;
+
+import classes.Flexibility;
+import classes.holonControlUnit.OptimizationManager;
+import classes.holonControlUnit.OptimizationManager.OptimizationScheme;
+
+public class OrderMsg {
+
+	private float desiredPowerUsage;
+//	private ArrayList<Flexibility> flexibilitiesToApply;
+	private OptimizationManager.OptimizationScheme optSheme;
+	private int timeStep;
+	
+	public OrderMsg(float desiredPowerUsage, ArrayList<Flexibility> flexibilitiesToApply, OptimizationScheme optSheme, int timeStep) {
+		super();
+		this.desiredPowerUsage = desiredPowerUsage;
+		this.optSheme = optSheme;
+		this.timeStep = timeStep;
+	}
+
+	@Override
+	public String toString() {
+		return "OrderMsg [desiredPowerUsage=" + desiredPowerUsage + ", optSheme=" + optSheme + ", timeStep=" + timeStep
+				+ "]";
+	}
+
+	public float getDesiredPowerUsage() {
+		return desiredPowerUsage;
+	}
+
+	public OptimizationManager.OptimizationScheme getOptSheme() {
+		return optSheme;
+	}
+
+	public int getTimeStep() {
+		return timeStep;
+	}
+}

+ 30 - 0
src/classes/holonControlUnit/messages/SplitMsg.java

@@ -0,0 +1,30 @@
+package classes.holonControlUnit.messages;
+
+public class SplitMsg {
+	
+	public enum SenderRealtion {
+		SUPERHOLON, SUBHOLON
+	}
+
+	private SenderRealtion type;
+	private int timeStep;
+	
+	public SplitMsg(SenderRealtion type, int timeStep) {
+		super();
+		this.type = type;
+		this.timeStep = timeStep;
+	}
+
+	public SenderRealtion getType() {
+		return type;
+	}
+
+	public int getTimeStep() {
+		return timeStep;
+	}
+
+	@Override
+	public String toString() {
+		return "SplitMsg [type=" + type + ", timeStep=" + timeStep + "]";
+	}
+}

+ 25 - 2
src/classes/holonControlUnit/messages/StateMsg.java

@@ -1,21 +1,44 @@
 package classes.holonControlUnit.messages;
 
+import java.util.ArrayList;
+
+import classes.holonControlUnit.StateEstimator.StateIndicator;
+
 public class StateMsg {
 
 	private float powerUsage;
+	private float netThroughput;
+	private ArrayList<Float> predictedPowerUsage;
+	private StateIndicator stateInd;
 
-	public StateMsg(float powerUsage) {
+	public StateMsg(float powerUsage, float netThroughput, ArrayList<Float> predictedPowerUsage, StateIndicator stateInd) {
 		super();
 		this.powerUsage = powerUsage;
+		this.netThroughput = netThroughput;
+		this.predictedPowerUsage = predictedPowerUsage;
+		this.stateInd = stateInd;
 	}
 
 	public float getPowerUsage() {
 		return powerUsage;
 	}
 
+	public ArrayList<Float> getPredictedPowerUsage() {
+		return predictedPowerUsage;
+	}
+
+	public float getNetThroughput() {
+		return netThroughput;
+	}
+
+	public StateIndicator getStateInd() {
+		return stateInd;
+	}
+
 	@Override
 	public String toString() {
-		return "StateMsg [powerUsage=" + powerUsage + "]";
+		return "StateMsg [powerUsage=" + powerUsage + ", netThroughput=" + netThroughput + ", predictedPowerUsage="
+				+ predictedPowerUsage + ", stateInd=" + stateInd + "]";
 	}
 	
 }

+ 23 - 1
src/ui/controller/FlexManager.java

@@ -44,7 +44,29 @@ public class FlexManager {
 		accessFlexMap.values().stream().forEach(flexWrapper -> flexWrapper.revalidateState());
 	}
 
-	
+
+	public FlexManager(List<HolonObject> objects, int timeStep, FlexManager timestepBefore){
+		//Thread.dumpStack();
+		this.timeStep = timeStep;
+		allFlexModels = objects.stream()
+				.flatMap(hObject -> hObject.getElements().stream())
+				.flatMap(hElement -> hElement.flexList.stream())
+				.collect(Collectors.toList());
+		//fill accessFlexMap
+		allFlexModels.stream().map(flex -> new FlexWrapper(flex, timeStep, (timestepBefore != null)?timestepBefore.getFlexWrapper(flex):null)).forEach(flexWrapper -> {
+			accessFlexMap.put(flexWrapper.getFlex(), flexWrapper);
+			HolonElement ele = flexWrapper.getFlex().getElement();
+			if(accessOtherFlex.containsKey(ele)) {
+				accessOtherFlex.get(ele).add(flexWrapper);
+			}else {
+				ArrayList<FlexWrapper> toAdd = new ArrayList<FlexWrapper>();
+				toAdd.add(flexWrapper);
+				accessOtherFlex.put(ele, new ArrayList<FlexWrapper>(toAdd));
+			}
+			});
+		//because when added not all flexes can see others
+		accessFlexMap.values().stream().forEach(flexWrapper -> flexWrapper.revalidateState());
+	}
 	
 	
 	

+ 3 - 2
src/ui/controller/LoadController.java

@@ -117,6 +117,8 @@ public class LoadController {
         forwardObjects(keys, json, objDispatch, eleDispatch);
         forwardEdges(edges, json, objDispatch);
 
+        //reconstruct the holarchies
+		model.getStateHolon().revalidateMinModelAfterLoad();
     }
 
     /**
@@ -195,7 +197,6 @@ public class LoadController {
 		for(JsonElement ele : array) {
 			deserializeHolon(model.getStateHolon(), ele.getAsJsonObject() , objDispatch);
 		}
-		
 	}
 
     
@@ -218,7 +219,7 @@ public class LoadController {
 		for(JsonElement ele : array) {
 			deserializeHolon(created, ele.getAsJsonObject() , objDispatch);
 		}
-		parent.merge(created);
+		parent.addChild(created);
 	}
 
 	/**

+ 56 - 38
src/ui/controller/SimulationManager.java

@@ -14,11 +14,9 @@ import ui.model.Model;
 import ui.model.Model.FairnessModel;
 import ui.model.VisualRepresentationalState;
 
-import java.lang.ModuleLayer.Controller;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
@@ -57,36 +55,54 @@ public class SimulationManager {
 	 * @param updateVisual TODO
 	 */
 	public void calculateStateForTimeStep(int timeStep, boolean updateVisual) {
+		System.out.println("\n=========================================================================\n");
 		this.timeStep = timeStep;
-		//compute state of each holon
-		this.model.getStateHolon().holonControlUnit.getStateEstimator().computeState(timeStep);
 		
-		boolean doesFlexManagerExist = savesFlexManger.containsKey(timeStep);
-		boolean createNew = updateVisual || !doesFlexManagerExist;
-		FlexManager newFlexManager;
-		if(createNew) {
-			newFlexManager = new FlexManager(model, timeStep, savesFlexManger.get(timeStep-1));
-			if(doesFlexManagerExist) newFlexManager.orderFlexFromList(savesFlexManger.get(timeStep).getAllFlexesOrderedThisTimeStep());
-			savesFlexManger.put(timeStep, newFlexManager);
-		}else {
-			newFlexManager = savesFlexManger.get(timeStep);
-		}
+		MinimumModel minimumModel = new MinimumModel(model.getObjectsOnCanvas(), model.getEdgesOnCanvas());
+//		HashMap<Edge, CableState> map = new HashMap<Edge, CableState>();
+//		if(timeStep > 0 && saves.containsKey(timeStep-1)) //if the state before exist
+//		{
+////			System.out.println("---------------------------------------");
+//			//make cable hastmap
+//			DecoratedState theStateBefore = saves.get(timeStep-1);
+//			//edges without HolonObjects or burned
+//			for(DecoratedCable edge : theStateBefore.getLeftOverEdges())
+//			{
+//				map.put(edge.getModel(), edge.getState());
+//			}
+//		}
 		
-		HashMap<Edge, CableState> map = new HashMap<Edge, CableState>();
-		if(timeStep > 0 && saves.containsKey(timeStep-1)) //if the state before exist
-		{
-			//make cable hastmap
-			DecoratedState theStateBefore = saves.get(timeStep-1);
-			//edges without HolonObjects or burned
-			for(DecoratedCable edge : theStateBefore.getLeftOverEdges())
-			{
-				map.put(edge.getModel(), edge.getState());
+		//set all the state before:
+		for(IntermediateCableWithState cable : minimumModel.getEdgeList()) {
+//			if(map.containsKey(cable.getModel()) && map.get(cable.getModel()) == CableState.Burned) {
+//				cable.setState(CableState.Burned);
+////				System.out.println(cable.getModel()+" burnnnnnnn");
+//				cable.getModel().setBurned(true);
+//			}
+			if(cable.getModel().isBurned()) {
+				cable.setState(CableState.Burned);
 			}
 		}
 		
+		
+		//compute state of each holon
+		List<Holon> l = List.copyOf(this.model.getStateHolon().childHolons);
+		for(Holon h : l) {
+			h.holonControlUnit.computeState(timeStep);
+		}
+		
+//		boolean doesFlexManagerExist = savesFlexManger.containsKey(timeStep);
+//		boolean createNew = updateVisual || !doesFlexManagerExist;
+//		FlexManager newFlexManager;
+//		if(createNew) {
+//			newFlexManager = new FlexManager(model, timeStep, savesFlexManger.get(timeStep-1));
+//			if(doesFlexManagerExist) newFlexManager.orderFlexFromList(savesFlexManger.get(timeStep).getAllFlexesOrderedThisTimeStep());
+//			savesFlexManger.put(timeStep, newFlexManager);
+//		}else {
+//			newFlexManager = savesFlexManger.get(timeStep);
+//		}
+		
 		ArrayList<MinimumNetwork> list =  new ArrayList<MinimumNetwork>();
-
-		MinimumModel minimumModel = new MinimumModel(model.getObjectsOnCanvas(), model.getEdgesOnCanvas());
 		
 		//for each holarchy get minimum model
 		ArrayList<MinimumModel> independentHolarchies = new ArrayList<MinimumModel>();
@@ -109,13 +125,9 @@ public class SimulationManager {
 		
 		//set all BreakedManuel Cable Burned:
 		for(IntermediateCableWithState cable : minimumModel.getEdgeList()) {
-			if(cable.getModel().isBreakedManuel()) cable.setState(CableState.Burned);
+			if(cable.getModel().isBreakedManuel() || cable.getModel().isBurned()) cable.setState(CableState.Burned);
 		}
 		
-		//set all the state before:
-		for(IntermediateCableWithState cable : minimumModel.getEdgeList()) {
-			if(map.containsKey(cable.getModel())) cable.setState(map.get(cable.getModel()));
-		}
 		ArrayList<IntermediateCableWithState> leftOver = new ArrayList<IntermediateCableWithState>();
 		
 		boolean doAnotherLoop = true;
@@ -123,13 +135,18 @@ public class SimulationManager {
 			doAnotherLoop = false;
 			list = calculateNetworks(minimumModel, timeStep, leftOver);
 			for(MinimumNetwork net : list) {
+				float energyOnCables = net.getHolonObjectList().stream().filter(object -> object.getEnergyAtTimeStepFlex(timeStep) > 0.0f).map(object -> object.getEnergyAtTimeStepFlex(timeStep)).reduce(0.0f, ((a,b) -> a + b));
 //				float energyOnCables = net.getHolonObjectList().stream().filter(object -> object.getEnergyAtTimeStepWithFlex(timeStep, newFlexManager) > 0.0f).map(object -> object.getEnergyAtTimeStepWithFlex(timeStep, newFlexManager)).reduce(0.0f, ((a,b) -> a + b));
-				float energyOnCables = net.getHolonObjectList().stream().filter(object -> object.holon.holonControlUnit.getStateEstimator().getPowerUsage() > 0.0f).map(object -> object.getEnergyAtTimeStepWithFlex(timeStep, newFlexManager)).reduce(0.0f, ((a,b) -> a + b));
+//				float energyOnCables = net.getHolonObjectList().stream().filter(object -> object.getEnergyAtTimeStepFlex(timeStep) > 0.0f).map(object -> object.getEnergyAtTimeStepFlex(timeStep)).reduce(0.0f, ((a,b) -> a + b));
+//				float energyOnCables = net.getHolonObjectList().stream().filter(object -> object.holon.holonControlUnit.getStateEstimator().getPowerUsage() > 0.0f).map(object -> object.getEnergyAtTimeStepWithFlex(timeStep, newFlexManager)).reduce(0.0f, ((a,b) -> a + b));
 				//find the cable with the energy supplied from his two connected objects are the biggest, from all cables that the network give more energy than the cablecapacity. 
-				IntermediateCableWithState cable = net.getEdgeList().stream().filter(aCable -> energyOnCables > aCable.getModel().getCapacity() && !aCable.getModel().isUnlimitedCapacity()).max((lhs,rhs) -> Float.compare(lhs.getEnergyFromConnetedAtTimestep(timeStep, newFlexManager), rhs.getEnergyFromConnetedAtTimestep(timeStep, newFlexManager))).orElse(null);
+				IntermediateCableWithState cable = net.getEdgeList().stream().filter(aCable -> energyOnCables > aCable.getModel().getCapacity() && !aCable.getModel().isUnlimitedCapacity()).max((lhs,rhs) -> Float.compare(lhs.getEnergyFromConnetedAtTimestep(timeStep), rhs.getEnergyFromConnetedAtTimestep(timeStep))).orElse(null);
 				if(cable != null) {
 					cable.setState(CableState.Burned);
+					cable.getModel().setBurned(true);
 					doAnotherLoop = true;
+				} else {
+					net.getEdgeList().stream().forEach(c -> c.getModel().setThroughput(energyOnCables));
 				}
 			}
 		}
@@ -139,7 +156,8 @@ public class SimulationManager {
 		ArrayList<DecoratedNetwork> decorNetworks = new ArrayList<DecoratedNetwork>();
 		FairnessModel actualFairnessModel = model.getFairnessModel();
 		for (MinimumNetwork net : list) {
-			DecoratedNetwork decNetwork = new DecoratedNetwork(net, timeStep, actualFairnessModel, newFlexManager);
+//			DecoratedNetwork decNetwork = new DecoratedNetwork(net, timeStep, actualFairnessModel, newFlexManager);
+			DecoratedNetwork decNetwork = new DecoratedNetwork(net, timeStep, actualFairnessModel);
 			decorNetworks.add(decNetwork);
 			for(HolonObject obj : net.getHolonObjectList()) {
 				holonObjectNetworkTable.put(obj, decNetwork);
@@ -152,14 +170,14 @@ public class SimulationManager {
 			leftOverDecoratedCables.add(new DecoratedCable(cable.getModel(), cable.getState(), 0.0f));
 		}
 		ArrayList<DecoratedSwitch> listOfDecoratedSwitches = decorateSwitches(minimumModel, timeStep);
-		DecoratedState stateFromThisTimestep = new DecoratedState(decorNetworks, leftOverDecoratedCables, listOfDecoratedSwitches, newFlexManager, timeStep, holonObjectNetworkTable);
+		DecoratedState stateFromThisTimestep = new DecoratedState(decorNetworks, leftOverDecoratedCables, listOfDecoratedSwitches, timeStep, holonObjectNetworkTable);
 		saves.put(timeStep, stateFromThisTimestep);
 		if(updateVisual)savesVisual.put(timeStep, new VisualRepresentationalState(stateFromThisTimestep, minimumModel));
 		//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());
-		}
+//		List<Holon> holonList = model.getStateHolon().childHolons;
+//		for(int i = 0; i < holonList.size(); i++) {
+//			holonList.get(i).checkRepairHolarchy(holonObjectNetworkTable, model.getStateHolon());
+//		}
 	}
 
 	/** 

+ 7 - 3
src/ui/controller/UpdateController.java

@@ -75,7 +75,9 @@ public class UpdateController {
 			}
 			for (HolonElement e1 : elemList) {
 				Object[] temp2 = { e1.getObjName(), e1.getId(), e1.getName(), e1.getEnergyPerElement(),
-						controller.getSimManager().getActualFlexManager().isAFlexInUseOfHolonElement(e1), e1.getAmount(), e1.isActive()};
+						e1.holon.holonControlUnit.getFlexMan().getFlexManager(controller.getModel().getCurIteration()).isAFlexInUseOfHolonElement(e1),
+//						controller.getSimManager().getActualFlexManager().isAFlexInUseOfHolonElement(e1), 
+						e1.getAmount(), e1.isActive()};
 				table.addRow(temp2);
 			}
 
@@ -88,8 +90,10 @@ public class UpdateController {
 				}
 				
 				for (HolonElement e1 : elemList) {
-					Object[] temp2 = { e1.getId(), e1.getName(), e1.getEnergyPerElement(),
-							controller.getSimManager().getActualFlexManager().isAFlexInUseOfHolonElement(e1), e1.getAmount(), e1.isActive()};
+					Object[] temp2 = { e1.getId(), e1.getName(), e1.getEnergyPerElement(), 
+							e1.holon.holonControlUnit.getFlexMan().getFlexManager(controller.getModel().getCurIteration()).isAFlexInUseOfHolonElement(e1),
+//							controller.getSimManager().getActualFlexManager().isAFlexInUseOfHolonElement(e1), 
+							e1.getAmount(), e1.isActive()};
 					table.addRow(temp2);
 				}
 			}

+ 188 - 0
src/ui/model/DecoratedNetwork.java

@@ -32,6 +32,19 @@ public class DecoratedNetwork {
 			break;		
 		}
 	}
+	public DecoratedNetwork(MinimumNetwork minimumNetwork, int Iteration, FairnessModel actualFairnessModel){	
+		
+		this.timestep = Iteration;
+		switch(actualFairnessModel) {
+		case AllEqual:
+			calculateAllEqualNetwork(minimumNetwork, Iteration);
+			break;
+		case MininumDemandFirst:
+		default:
+			calculateMinimumDemandFirstNetwork(minimumNetwork, Iteration);
+			break;		
+		}
+	}
 
 
 	//Getter:
@@ -174,6 +187,121 @@ public class DecoratedNetwork {
 		
 		calculateStates();
 	}
+	private void calculateMinimumDemandFirstNetwork(MinimumNetwork minimumNetwork, int Iteration) {
+		categorize(minimumNetwork, Iteration);
+		//Sort SupplierList according to the EnergyToSupplyNetwork maximum first.
+		//Sort ConsumerList according to the MinimumConsumingElementEnergy minimum first.
+		supplierList.sort((Supplier lhs,Supplier rhs) -> -Float.compare(lhs.getEnergyToSupplyNetwork(), rhs.getEnergyToSupplyNetwork()));
+		consumerList.sort((Consumer lhs,Consumer rhs) -> Float.compare(lhs.getMinimumConsumingElementEnergy()  , rhs.getMinimumConsumingElementEnergy()));
+		//consumerList.forEach((con) -> System.out.println(con.getMinimumConsumingElementEnergy()));
+		//consumerList.forEach((con) -> System.out.println("AfterSorting" + con));
+		float energyToSupplyInTheNetwork = supplierList.stream().map(supplier -> supplier.getEnergyToSupplyNetwork() - supplier.getEnergySupplied()).reduce( 0.0f, (a, b) -> a + b);
+		decorateCable(minimumNetwork, energyToSupplyInTheNetwork);
+		
+		outerLoop:
+			for(Consumer con : consumerList)
+			{
+				//gehe Supplier list durch wer ihn supplien kann.
+				for(Supplier sup : supplierList) {
+					float  energyRdyToSupply = sup.getEnergyToSupplyNetwork() - sup.getEnergySupplied();
+					if(energyRdyToSupply == 0.0f) continue;
+					float energyNeededForMinimumConsumingElement=con.getMinimumConsumingElementEnergy()-con.getEnergyFromNetwork();
+					if(energyNeededForMinimumConsumingElement>energyToSupplyInTheNetwork) {
+						//Dont supply a minimumElement when you cant supply it fully
+						break outerLoop;
+					}
+					if(energyRdyToSupply>=energyNeededForMinimumConsumingElement) {
+						energyToSupplyInTheNetwork -= energyNeededForMinimumConsumingElement;
+						supply(con, sup, energyNeededForMinimumConsumingElement);
+						continue outerLoop;
+					}else
+					{
+						energyToSupplyInTheNetwork -= energyRdyToSupply;
+						supply(con, sup, energyRdyToSupply);
+					}
+				}
+				//No more Energy in the network
+				break;
+			}
+		//consumerList.forEach((con) -> System.out.println("AfterSuppliing MinimumDemand " + con));
+		
+		//Sort ConsumerList according to the EnergyNeeded to supply fully after minimum Demand First.
+		consumerList.sort((Consumer lhs,Consumer rhs) -> Float.compare(lhs.getEnergyNeededFromNetwork()-lhs.getEnergyFromNetwork() , rhs.getEnergyNeededFromNetwork()-rhs.getEnergyFromNetwork() ));
+		//Supply consumer fully 
+		outerLoop:
+			for(Consumer con : consumerList)
+			{
+				//gehe Supplier list durch wer ihn supplien kann.
+				for(Supplier sup : supplierList) {
+					float  energyRdyToSupply = sup.getEnergyToSupplyNetwork() - sup.getEnergySupplied();
+					if(energyRdyToSupply == 0.0f) continue;
+					float energyNeededForFullySupply = con.getEnergyNeededFromNetwork() - con.getEnergyFromNetwork();
+					if(energyNeededForFullySupply == 0.0f) continue outerLoop;
+					if(energyRdyToSupply>=energyNeededForFullySupply) {
+						supply(con, sup, energyNeededForFullySupply);
+						continue outerLoop;
+					}else
+					{
+						supply(con, sup, energyRdyToSupply);
+					}
+				}
+				//No more Energy in the network
+				break;
+			}
+		//consumerList.forEach((con) -> System.out.println("AfterFullySuplieing" + con));
+		//If Energy Left Supply all equal
+		//Count EnergyLeft
+		float energyLeft = supplierList.stream().map(supplier -> supplier.getEnergyToSupplyNetwork() - supplier.getEnergySupplied()).reduce( 0.0f, (a, b) -> a + b);
+		//System.out.println("EnergyLeft: " +  energyLeft);
+		if(energyLeft > 0.0f && (consumerList.size() + consumerSelfSuppliedList.size() != 0))
+		{
+			float equalAmountOfEnergyToSupply = energyLeft / ((float)(consumerList.size() + consumerSelfSuppliedList.size()));
+			outerLoop:
+				for(Consumer con : consumerList)
+				{
+					//gehe Supplier list durch wer ihn supplien kann.
+					for(Supplier sup : supplierList) {
+						float  energyRdyToSupply = sup.getEnergyToSupplyNetwork() - sup.getEnergySupplied();
+						if(energyRdyToSupply == 0.0f) continue;
+						float energyNeededToSupplyConsumerTheEqualAmount = equalAmountOfEnergyToSupply +con.getEnergyNeededFromNetwork()- con.getEnergyFromNetwork();
+						if(energyRdyToSupply>=energyNeededToSupplyConsumerTheEqualAmount) {
+							supply(con, sup, energyNeededToSupplyConsumerTheEqualAmount);
+							continue outerLoop;
+						}else
+						{
+							supply(con, sup, energyRdyToSupply);
+						}
+					}
+					//No more Energy in the network
+					break;
+				}
+			outerLoop:
+				for(Consumer con : consumerSelfSuppliedList)
+				{
+					//gehe Supplier list durch wer ihn supplien kann.
+					for(Supplier sup : supplierList) {
+						float  energyRdyToSupply = sup.getEnergyToSupplyNetwork() - sup.getEnergySupplied();
+						if(energyRdyToSupply == 0.0f) continue;
+						float energyNeededToSupplyConsumerTheEqualAmount = equalAmountOfEnergyToSupply +con.getEnergyNeededFromNetwork()- con.getEnergyFromNetwork();
+						if(energyRdyToSupply>=energyNeededToSupplyConsumerTheEqualAmount) {
+							supply(con, sup, energyNeededToSupplyConsumerTheEqualAmount);
+							continue outerLoop;
+						}else
+						{
+							supply(con, sup, energyRdyToSupply);
+						}
+						
+					}
+					//No more Energy in the network
+					break;
+				}
+		}
+		//consumerList.forEach((con) -> System.out.println("AfterOverSuppleiing" + con));
+		
+		//consumerSelfSuppliedList.forEach((con) -> System.out.println("AfterOverSuppleiing" + con));
+		
+		calculateStates();
+	}
 
 
 	private void decorateCable(MinimumNetwork minimumNetwork, float energyToSupplyInTheNetwork) {
@@ -214,6 +342,34 @@ public class DecoratedNetwork {
 		}
 		calculateStates();
 	}
+	private void calculateAllEqualNetwork(MinimumNetwork minimumNetwork, int Iteration) {
+		categorize(minimumNetwork, Iteration);
+		float energyToSupplyInTheNetwork = supplierList.stream().map(supplier -> supplier.getEnergyToSupplyNetwork() - supplier.getEnergySupplied()).reduce( 0.0f, (a, b) -> a + b);
+		float energyForEachConsumer = (consumerList.size() != 0) ? energyToSupplyInTheNetwork / consumerList.size() : 0.0f;
+		decorateCable(minimumNetwork, energyToSupplyInTheNetwork);
+		//Supply consumer equal 
+		outerLoop:
+		for(Consumer con : consumerList)
+		{
+			//gehe Supplier list durch wer ihn supplien kann.
+			float energyNeededForEqualSupply = energyForEachConsumer;
+			for(Supplier sup : supplierList) {
+				float  energyRdyToSupply = sup.getEnergyToSupplyNetwork() - sup.getEnergySupplied();
+				if(energyRdyToSupply == 0.0f) continue;
+				if(energyRdyToSupply>=energyNeededForEqualSupply) {
+					supply(con, sup, energyNeededForEqualSupply);
+					continue outerLoop;
+				}else
+				{
+					supply(con, sup, energyRdyToSupply);
+					energyNeededForEqualSupply -= energyRdyToSupply;
+				}
+			}
+			//No more Energy in the network
+			break;
+		}
+		calculateStates();
+	}
 
 	private void calculateStates() {
 		//CalculateStates:
@@ -260,6 +416,38 @@ public class DecoratedNetwork {
 			}
 		}
 	}
+	private void categorize(MinimumNetwork minimumNetwork, int Iteration) {
+		//Categorize
+		for(HolonObject hObject: minimumNetwork.getHolonObjectList()) {
+			float energyNeeded = hObject.getEnergyNeededFromConsumingElementsFlex(Iteration);
+			float energySelfProducing = hObject.getEnergySelfProducingFromProducingElementsFlex(Iteration);
+			if(energyNeeded < energySelfProducing) {
+				Supplier sup = new Supplier(hObject, energySelfProducing - energyNeeded, energyNeeded);
+				supplierList.add(sup);
+			} else if (energyNeeded > energySelfProducing) {
+				Consumer con = new Consumer(hObject);
+				con.setEnergyNeededFromNetwork(energyNeeded - energySelfProducing);
+				con.setMinimumConsumingElementEnergy(hObject.getMinimumConsumingElementEnergyFlex(Iteration));
+				con.setEnergyFromConsumingElemnets(hObject.getEnergyNeededFromConsumingElementsFlex(Iteration));
+				con.setEnergySelfSupplied(hObject.getEnergySelfProducingFromProducingElementsFlex(Iteration));
+				consumerList.add(con);
+			}else if(energyNeeded == energySelfProducing) {
+				
+				if (energySelfProducing == 0.0f) {
+					Passiv pas = new Passiv(hObject);
+					passivNoEnergyList.add(pas);
+				} else {
+					Consumer con = new Consumer(hObject);
+					con.setEnergyNeededFromNetwork(0.0f);
+					con.setMinimumConsumingElementEnergy(hObject.getMinimumConsumingElementEnergyFlex(Iteration));
+					con.setEnergyFromConsumingElemnets(hObject.getEnergyNeededFromConsumingElementsFlex(Iteration));
+					con.setEnergySelfSupplied(hObject.getEnergySelfProducingFromProducingElementsFlex(Iteration));
+					consumerSelfSuppliedList.add(con);
+				}
+				
+			}
+		}
+	}
 	
 	
 	private void setConsumerState(Consumer con) {

+ 7 - 0
src/ui/model/DecoratedState.java

@@ -22,6 +22,13 @@ public class DecoratedState {
 		this.flexManager = flexManager;
 		this.holonObjectNetworkTable = holonObjectNetworkTable;
 	}
+	public DecoratedState(ArrayList<DecoratedNetwork> networkList, ArrayList<DecoratedCable> leftOverEdges, ArrayList<DecoratedSwitch> decoratedSwitches, int timestepOfState, HashMap<HolonObject, DecoratedNetwork> holonObjectNetworkTable){
+		this.networkList = networkList;
+		this.leftOverEdges = leftOverEdges;
+		this.decoratedSwitches = decoratedSwitches;
+		this.timestepOfState = timestepOfState;
+		this.holonObjectNetworkTable = holonObjectNetworkTable;
+	}
 	public HashMap<HolonObject, DecoratedNetwork> getHolonObjectNetworkTable() {
 		return holonObjectNetworkTable;
 	}

+ 24 - 8
src/ui/model/IntermediateCableWithState.java

@@ -30,15 +30,31 @@ public class IntermediateCableWithState {
 	//ugly
 	public float getEnergyFromConnetedAtTimestep(int iteration, FlexManager flexManager) {
 		float energy = 0.0f;
-//		if(model.getA() instanceof HolonObject && ((HolonObject) model.getA()).getEnergyAtTimeStepWithFlex(iteration, flexManager) > 0) energy += ((HolonObject) model.getA()).getEnergyAtTimeStepWithFlex(iteration, flexManager);
-//		if(model.getB() instanceof HolonObject && ((HolonObject) model.getB()).getEnergyAtTimeStepWithFlex(iteration, flexManager) > 0) energy += ((HolonObject) model.getB()).getEnergyAtTimeStepWithFlex(iteration, flexManager);
+		if(model.getA() instanceof HolonObject && ((HolonObject) model.getA()).getEnergyAtTimeStepWithFlex(iteration, flexManager) > 0) energy += ((HolonObject) model.getA()).getEnergyAtTimeStepWithFlex(iteration, flexManager);
+		if(model.getB() instanceof HolonObject && ((HolonObject) model.getB()).getEnergyAtTimeStepWithFlex(iteration, flexManager) > 0) energy += ((HolonObject) model.getB()).getEnergyAtTimeStepWithFlex(iteration, flexManager);
 		
-		if(model.getA() instanceof HolonObject && ((HolonObject)model.getA()).holon.holonControlUnit.getStateEstimator().getPowerUsage() > 0) {
-			energy += ((HolonObject)model.getA()).holon.holonControlUnit.getStateEstimator().getPowerUsage();
-		}
-		if(model.getB() instanceof HolonObject && ((HolonObject)model.getB()).holon.holonControlUnit.getStateEstimator().getPowerUsage() > 0) {
-			energy += ((HolonObject)model.getB()).holon.holonControlUnit.getStateEstimator().getPowerUsage();
-		}
+//		if(model.getA() instanceof HolonObject && ((HolonObject)model.getA()).holon.holonControlUnit.getStateEstimator().getPowerUsage() > 0) {
+//			energy += ((HolonObject)model.getA()).holon.holonControlUnit.getStateEstimator().getPowerUsage();
+//		}
+//		if(model.getB() instanceof HolonObject && ((HolonObject)model.getB()).holon.holonControlUnit.getStateEstimator().getPowerUsage() > 0) {
+//			energy += ((HolonObject)model.getB()).holon.holonControlUnit.getStateEstimator().getPowerUsage();
+//		}
+		
+		return energy;
+	}
+	public float getEnergyFromConnetedAtTimestep(int iteration) {
+		float energy = 0.0f;
+		if(model.getA() instanceof HolonObject && ((HolonObject) model.getA()).getEnergyAtTimeStepFlex(iteration) > 0) 
+			energy += ((HolonObject) model.getA()).getEnergyAtTimeStepFlex(iteration);
+		if(model.getB() instanceof HolonObject && ((HolonObject) model.getB()).getEnergyAtTimeStepFlex(iteration) > 0) 
+			energy += ((HolonObject) model.getB()).getEnergyAtTimeStepFlex(iteration);
+		
+//		if(model.getA() instanceof HolonObject && ((HolonObject)model.getA()).holon.holonControlUnit.getStateEstimator().getPowerUsage() > 0) {
+//			energy += ((HolonObject)model.getA()).holon.holonControlUnit.getStateEstimator().getPowerUsage();
+//		}
+//		if(model.getB() instanceof HolonObject && ((HolonObject)model.getB()).holon.holonControlUnit.getStateEstimator().getPowerUsage() > 0) {
+//			energy += ((HolonObject)model.getB()).holon.holonControlUnit.getStateEstimator().getPowerUsage();
+//		}
 		
 		return energy;
 	}

+ 49 - 53
src/ui/model/Model.java

@@ -890,53 +890,14 @@ public class Model {
 	}
 	
 	/**
-	 * get all edges that connect objects inside the holarchy
-	 * requires that all objects are connected
-	 * energy always takes the shortest path between two objects -> all shortest paths are included
-	 * all traversed objects are whether a switch or holon that is part of the holarchy
-	 * group nodes not supported
-	 * @param from
-	 * @param to
+	 * get a list of paths between the two holarchies/minModels
+	 * list contains shortest path between each pair of objects (o1, o2) in (minModel x minModel2)
+	 * @param minModel
+	 * @param minModel2
+	 * @param holarchy
 	 * @return
 	 */
-	public ArrayList<Edge> getAllEdgesInHolarchy(ArrayList<HolonObject> holarchy){
-		if(holarchy.size() < 2) {
-			return new ArrayList<Edge>();
-		}
-		//construct subgraph that contains all objects of the holarchy and all switches from the canvas
-		ArrayList<AbstractCanvasObject> vertices = new ArrayList<AbstractCanvasObject>();
-		for(AbstractCanvasObject aco : this.objectsOnCanvas) {
-			if(aco instanceof HolonSwitch || aco instanceof Node
-					|| (aco instanceof HolonObject && holarchy.contains(aco)) ) {
-				vertices.add(aco);
-			}
-		}
-		ArrayList<Edge> edges = new ArrayList<Edge>();
-		for(Edge e : this.edgesOnCanvas) {
-			AbstractCanvasObject a = e.getA();
-			AbstractCanvasObject b = e.getB();
-			if(vertices.contains(a) && vertices.contains(b)) {
-				edges.add(e);
-			}
-		}
-		
-		//find shortest paths between the objects
-		ArrayList<Edge> es = new ArrayList<Edge>();
-		if(holarchy.size() < 2) {
-			return es;
-		}
-		
-		for(int i=0; i<holarchy.size(); i++) {
-			HolonObject a = holarchy.get(i);
-			for(int j=i+1; j<holarchy.size(); j++) {
-				es.addAll(dijkstra(a, holarchy.get(j), holarchy, vertices, edges));
-			}
-		}
-		
-		return es;
-	}
-	
-	public HashMap<Float, ArrayList<Edge>> getShortestPathToHolarchy(MinimumModel minModel, MinimumModel minModel2, ArrayList<HolonObject> holarchy){
+	public HashMap<Float, ArrayList<Edge>> getShortestPathToHolarchy(MinimumModel minModel, MinimumModel minModel2){
 		ArrayList<AbstractCanvasObject> objects = new ArrayList<AbstractCanvasObject>();
 		objects.addAll(minModel.getHolonObjectList());
 		objects.addAll(minModel.getNodeList());
@@ -947,10 +908,19 @@ public class Model {
 		objects2.addAll(minModel2.getNodeList());
 		objects2.addAll(minModel2.getSwitchList());
 		
+		List<AbstractCanvasObject> vertices = this.objectsOnCanvas.stream()
+				.map(aco -> aco instanceof GroupNode ? ((GroupNode) aco).getAllObjectsInside() : List.of(aco))
+				.flatMap(List::stream)
+				.collect(Collectors.toList());
+		
 		HashMap<Float, ArrayList<Edge>> map = new HashMap<Float, ArrayList<Edge>>();
 		for(AbstractCanvasObject aco : objects) {
 			for(AbstractCanvasObject aco2 : objects2) {
-				ArrayList<Edge> edges = dijkstra(aco, aco2, holarchy, this.objectsOnCanvas, this.edgesOnCanvas);
+				if(aco.equals(aco2))
+					continue;
+				ArrayList<Edge> edges = dijkstra(aco, aco2, minModel2.getHolonObjectList(), vertices, this.edgesOnCanvas);
+				if(edges == null)
+					continue;
 				float dist = 0;
 				for(Edge e : edges) {
 					dist += e.getLength();
@@ -962,7 +932,8 @@ public class Model {
 		return map;
 	}
 	
-	public ArrayList<Edge> dijkstra(AbstractCanvasObject a, AbstractCanvasObject b, ArrayList<HolonObject> holarchy, ArrayList<AbstractCanvasObject> vertices, ArrayList<Edge> edges) {
+	public ArrayList<Edge> dijkstra(AbstractCanvasObject a, AbstractCanvasObject b, ArrayList<HolonObject> holarchy, 
+			List<AbstractCanvasObject> vertices, ArrayList<Edge> edges) {
 		ArrayList<Edge> es = new ArrayList<Edge>();
 		
 		HashSet<AbstractCanvasObject> visited = new HashSet<AbstractCanvasObject>();
@@ -981,8 +952,12 @@ public class Model {
 		while(!unvisited.isEmpty()) {
 			if(b.equals(current))
 				break;
+			if(!dist.containsKey(current)) {
+				System.out.println("something is wrong "+current+" "+dist);
+				return null;
+			}
 			float currDist = dist.get(current);
-			for(AbstractCanvasObject aco : current.getConnectedObjects()) {
+			for(AbstractCanvasObject aco : current.getConnectedObjects(0f)) {
 				if(visited.contains(aco) || (aco instanceof HolonObject && !holarchy.contains(aco))) {
 					continue;
 				}
@@ -1000,12 +975,11 @@ public class Model {
 		
 		//trace back path
 		current = b;
-		while(!current.equals(a)) {
+		while(!a.equals(current)) {
 			AbstractCanvasObject next = pre.get(current);
 			es.add(getEdgeBetweenObjects(current, next, edges));
 			current = next;
 		}
-		
 		return es;
 	}
 	
@@ -1015,7 +989,6 @@ public class Model {
 		
 		for(AbstractCanvasObject aco : map.keySet()) {
 			if(unvisited.contains(aco) && map.get(aco) < m) {
-//				System.out.println("new min "+min);
 				m = map.get(aco);
 				min = aco;
 			}
@@ -1035,7 +1008,7 @@ public class Model {
 		return null;
 	}
 	
-	public boolean checkHolonObjectsAreConnected(Holon a, Holon b) {
+	public boolean checkHolonObjectsAreConnected(Holon a, Holon b, float throughput) {
 		if(a.equals(b)) {
 			return false;
 		}
@@ -1048,7 +1021,7 @@ public class Model {
 		toVisit.add(a.getHolonObject());
 		while(!toVisit.isEmpty()) {
 			AbstractCanvasObject aco = toVisit.remove(0);
-			for(AbstractCanvasObject aco2 : aco.getConnectedObjects()) {
+			for(AbstractCanvasObject aco2 : aco.getConnectedObjects(throughput)) {
 				if(visited.contains(aco2) || (aco2 instanceof HolonSwitch && !((HolonSwitch)aco2).isClosed()) ) {
 					continue;
 				}
@@ -1065,4 +1038,27 @@ public class Model {
 		return false;
 	}
 	
+	public ArrayList<String> getAllConnectionsFromObject(String objectID, String requester){
+		ArrayList<String> connections = new ArrayList<String>();
+		List<AbstractCanvasObject> objects = this.objectsOnCanvas.stream()
+				.map(aco -> aco instanceof GroupNode ? ((GroupNode) aco).getAllObjectsInside() : List.of(aco))
+				.flatMap(List::stream)
+				.collect(Collectors.toList());
+		
+		for(AbstractCanvasObject aco : objects) {
+			if(aco instanceof HolonSwitch && ((HolonSwitch) aco).getUniqueID().equals(objectID)) {
+				connections.addAll(((HolonSwitch) aco).getAllConnectedHolons(new ArrayList<AbstractCanvasObject>()));
+				break;
+			} else if (aco instanceof Node && ((Node) aco).getUniqueID().equals(objectID)) {
+				connections.addAll(((Node) aco).getAllConnectedHolons(new ArrayList<AbstractCanvasObject>()));
+				break;
+			} else if(aco instanceof GroupNode && ((GroupNode) aco).getUniqueID().equals(objectID)) {
+				connections.addAll(((GroupNode) aco).getAllConnectedHolons(new ArrayList<>()));
+				break;
+			}
+		}
+		connections.remove(requester);
+		
+		return connections;
+	}
 }

+ 15 - 4
src/ui/view/FlexWindow.java

@@ -157,7 +157,7 @@ public class FlexWindow extends JFrame {
 
 	
 	private void createUsageViewPanel() {
-		flexmanager = controller.getSimManager().getActualFlexManager();
+//		flexmanager = controller.getSimManager().getActualFlexManager();
 		//GridBagApprouch
 		JPanel gridbagPanel =  new JPanel(new GridBagLayout());
 		usageViewPanel = new JScrollPane(gridbagPanel);
@@ -172,7 +172,15 @@ public class FlexWindow extends JFrame {
 			
 			
 			
-			List<FlexWrapper> listOfFlexWithState = flexmanager.getAllFlexWrapperWithState(titles[i]);
+//			List<FlexWrapper> listOfFlexWithState = flexmanager.getAllFlexWrapperWithState(titles[i]);
+			FlexState state = titles[i];
+			List<FlexWrapper> listOfFlexWithState = controller.getModel().getHolonsByID().values().stream()
+					.map(h -> h.getParent() != null ? 
+							h.holonControlUnit.getFlexMan().getFlexManager(controller.getModel().getCurIteration()).getAllFlexWrapperWithState(state) : 
+								new ArrayList<FlexWrapper>())
+					.flatMap(List::stream)
+					.collect(Collectors.toList());
+			
 			JLabel label = new JLabel(titles[i].toString() + "[" + listOfFlexWithState.size()+ "]");									
 			GridBagConstraints labelC = new GridBagConstraints();
 			labelC.gridx = 1;
@@ -251,7 +259,8 @@ public class FlexWindow extends JFrame {
 			labelButton.setBorder(BorderFactory.createLineBorder(Color.black));
 			listPanel.add(labelButton, c);
 			labelButton.addActionListener(clicked ->{
-				actual.order();
+//				actual.order();
+				actual.getFlex().getElement().orderFlex(actual.getFlex(), this.controller.getModel().getCurIteration());
 				controller.calculateStateAndVisualForCurrentTimeStep();
 				controller.updateCanvas();
 			});
@@ -447,7 +456,9 @@ public class FlexWindow extends JFrame {
 	}
 	private void expandTreeFlex(HolonElement hElement, DefaultMutableTreeNode root) {
 		for(Flexibility flex: hElement.flexList) {
-			FlexWrapper flexWrapper = this.flexmanager.getFlexWrapperFromFlexibility(flex);
+//			FlexWrapper flexWrapper = this.flexmanager.getFlexWrapperFromFlexibility(flex);
+			FlexWrapper flexWrapper = hElement.holon.holonControlUnit.getFlexMan()
+					.getFlexManager(controller.getModel().getCurIteration()).getFlexWrapperFromFlexibility(flex);
 			String flexState = "";
 			if(flexWrapper != null) {
 				Color color = this.FlexStateToColor(flexWrapper.getState());

+ 1 - 3
src/ui/view/GUI.java

@@ -1579,8 +1579,6 @@ public class GUI{
 								((HolonObject) h).holon = new Holon((HolonObject) h, controller.getModel());
 								model.getHolonsByID().put(((HolonObject) h).holon.getUniqueID(), ((HolonObject) h).holon);
 								model.getStateHolon().addChild(((HolonObject)h).holon);
-//								System.out.println("all holon "+model.getStateHolon().getUniqueID());
-//								System.out.println("added holon to canvas "+((HolonObject)h).holon.getUniqueID());
 							}
 							if (tempCps instanceof HolonSwitch) {
 								h = new HolonSwitch(tempCps);
@@ -2216,7 +2214,7 @@ public class GUI{
 	}
 	
 	public void updateHolarchyWindows() {
-		//remove closed Outliner
+		//remove closed Holarchy windows
 		ListIterator<HolarchyWindow> iter = holarchyList.listIterator();
 		while(iter.hasNext())
 		{

+ 8 - 0
src/ui/view/GroupNodeCanvas.java

@@ -349,6 +349,10 @@ public class GroupNodeCanvas extends AbstractCanvas implements MouseListener, Mo
 			g.setColor(new Color(13, 175, 28));
 			g.setStroke(new BasicStroke(unlimited?2f:(currentEnergy / capacity * 2f) + 1));
 			break;
+		case Unused:
+			g.setColor(Color.blue);
+			g.setStroke(new BasicStroke(2));
+			break;
 		}
 		if(isSelected){
 			g.setColor(Color.lightGray);
@@ -436,6 +440,10 @@ public class GroupNodeCanvas extends AbstractCanvas implements MouseListener, Mo
 			g.setColor(new Color(13, 175, 28));
 			g.setStroke(new BasicStroke(unlimited?2f:(currentEnergy / capacity * 2f) + 1));
 			break;
+		case Unused:
+			g.setColor(Color.blue);
+			g.setStroke(new BasicStroke(2));
+			break;
 		}
 		switch(eCable.getState()) {
 		case DOWN:

+ 10 - 4
src/ui/view/HolonInformationPanel.java

@@ -152,10 +152,16 @@ public class HolonInformationPanel extends JPanel {
 		int onCooldown = 0;
 		int notOffered = 0;
 		int unavailable = 0;
-		FlexManager manager = control.getSimManager().getActualFlexManager();
-		Stream<FlexWrapper> flexWrapperStream = decoratedGroupNode.getFlexibilitiesStream()
-				.map(flex -> manager.getFlexWrapperFromFlexibility(flex));
-		List<FlexWrapper> wrapperList = flexWrapperStream.collect(Collectors.toList());
+//		FlexManager manager = control.getSimManager().getActualFlexManager();
+//		Stream<FlexWrapper> flexWrapperStream = decoratedGroupNode.getFlexibilitiesStream()
+//				.map(flex -> manager.getFlexWrapperFromFlexibility(flex));
+//		List<FlexWrapper> wrapperList = flexWrapperStream.collect(Collectors.toList());
+		List<FlexWrapper> wrapperList = control.getModel().getHolonsByID().values().stream()
+				.map(h -> h.getParent() != null ? 
+						h.holonControlUnit.getFlexMan().getFlexManager(control.getModel().getCurIteration()).getAllFlexWrapper() : 
+							new ArrayList<FlexWrapper>())
+				.flatMap(List::stream)
+				.collect(Collectors.toList());
 		for (FlexWrapper wrapper : wrapperList) {
 			switch (wrapper.getState()) {
 			case IN_USE:

+ 5 - 1
src/ui/view/MyCanvas.java

@@ -373,7 +373,7 @@ public class MyCanvas extends AbstractCanvas implements MouseListener,
 			break;
 		case Unused:
 			g.setColor(Color.blue);
-			g.setStroke(new BasicStroke(unlimited?2f:(currentEnergy / capacity * 2f) + 1));
+			g.setStroke(new BasicStroke(2));
 			break;
 		}
 		if(isSelected){
@@ -406,6 +406,10 @@ public class MyCanvas extends AbstractCanvas implements MouseListener,
 			g.setColor(new Color(13, 175, 28));
 			g.setStroke(new BasicStroke(unlimited?2f:(currentEnergy / capacity * 2f) + 1));
 			break;
+		case Unused:
+			g.setColor(Color.blue);
+			g.setStroke(new BasicStroke(2));
+			break;
 		}
 		g.drawLine(start.x, start.y, end.x, end.y);
 		Position middle = new Position((start.x + end.x) / 2, (start.y + end.y) / 2);

+ 10 - 3
src/ui/view/holarchy/HolarchyPanel.java

@@ -35,7 +35,8 @@ public class HolarchyPanel extends JPanel {
 	JSlider slider;
 	JSeparator sep, sep2;
 	int displayedLayer;
-	int minRadius = 24;
+	final int minRadius = 24;
+	int radius = minRadius;
 	Holon root;
 	ArrayList<Map<Ellipse2D, Map<Ellipse2D, Holon>>> ellipsesChild;
 	ArrayList<Map<Ellipse2D, Holon>> ellipses;
@@ -147,8 +148,10 @@ public class HolarchyPanel extends JPanel {
 	
 	public void createAllLayers() {
 		for(int layer=0; layer<this.layeredHolons.size(); layer++) {
+//			System.out.println("layer "+layer);
 			this.ellipsesChild.add(layer, new HashMap<Ellipse2D, Map<Ellipse2D, Holon>>());
 			//estimate the required area, center if it is smaller than the panels size
+			this.radius = this.minRadius;
 			Ellipse2D surrounding = estimateSurrounding(60, 0, layer, this.minRadius);
 			double newX = surrounding.getX(), newY = surrounding.getY();
 			if(surrounding.getWidth() <= this.getWidth()) {
@@ -191,9 +194,10 @@ public class HolarchyPanel extends JPanel {
 		
 		while(shapes.size() < holons.size() && abord < 1000) {
 			Holon h = holons.get(i);
-			int radius = this.minRadius;
+			int radius = this.radius;
 			if(drawChildren)
-				radius = this.minRadius * (h.getChildCount()+1) + 10;
+				radius = this.radius * (h.getChildCount()+1) + 10;
+//			System.out.println("drawing holon with radius "+radius);
 			
 			//randomly place an ellipse for the holon
 			double x = startX + (width * Math.random());
@@ -201,6 +205,7 @@ public class HolarchyPanel extends JPanel {
 			//check if ellipse is inside the surrounding
 			boolean overlap = !surrounding.contains(x, y, radius*2, radius*2);
 			if(overlap) {
+				abord++;
 				continue;
 			}
 			Ellipse2D e = new Ellipse2D.Double(x-5, y-5, radius*2+10, radius*2+10);
@@ -239,8 +244,10 @@ public class HolarchyPanel extends JPanel {
 			int div = radius / (w/(this.getHeight()-50));
 			if(div == radius)
 				div--;
+			this.radius = div;
 			return estimateSurrounding(x, y, layer, div );
 		}
+		this.radius = radius;
 		
 		return new Ellipse2D.Double(x, y, w, w);
 	}

+ 5 - 0
src/ui/view/holarchy/HolarchyTreePanel.java

@@ -52,6 +52,11 @@ public class HolarchyTreePanel extends JPanel {
         holonTree.setEditable(true);
 		this.add(TreeUtils.makePanelFromTree(holonTree));
 	}
+	
+	public void update() {
+		this.removeAll();
+		this.initilizePanel();
+	}
 
 	private JTree generateTree() {
 		root = generateFromHolon(control.getModel().getStateHolon());

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

@@ -78,7 +78,7 @@ public class HolarchyWindow extends JFrame {
 		if(this.infoPanel != null)
 			this.infoPanel.update();
 		if(this.treePanel != null)
-			this.treePanel.initilizePanel();
+			this.treePanel.update();
 	}
 	
 }

+ 2 - 2
src/ui/view/holarchy/HolonInfoPanel.java

@@ -22,7 +22,7 @@ public class HolonInfoPanel extends JPanel {
 	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: ")};
 	String[] labels2 = {"Subholons", "Virtual neighbors", "Physical neighbors"};
-	Set<JLabel> toRemove = new HashSet();
+	Set<JLabel> toRemove = new HashSet<JLabel>();
 	
 	public HolonInfoPanel(HolarchyWindow parentFrame, Control control) {
 		this.control = control;
@@ -88,7 +88,7 @@ public class HolonInfoPanel extends JPanel {
 		holons = h.holonControlUnit.getHierarchyController().getPhysicalNeighbors();
 		for(String s : holons) {
 			JLabel l;
-			if(s.contains("Switch")) {
+			if(s.contains("Switch") || s.contains("Node")) {
 				l = new JLabel(s);
 			} else {
 				Holon c = this.control.getModel().getHolonsByID().get(s);

+ 3 - 2
src/ui/view/outliner/HolonView.java

@@ -174,6 +174,7 @@ public class HolonView extends JPanel{
 		}
 		public void AddHolon(Holon holon) {
 			holon.split(this.holon);
+			control.updateHolarchyWindow();
 		}
 		@Override
 		public Transferable getTransferable(HolonTransferHandler handler) {
@@ -345,8 +346,8 @@ public class HolonView extends JPanel{
 		        try {
 		        	Holon dropHolon = ((HolonInfo) node.getUserObject()).holon;
 					Holon dragHolon = (Holon) support.getTransferable().getTransferData(holonFlavor);
-					boolean physicalConnected = control.getModel().checkHolonObjectsAreConnected(dragHolon, dropHolon);
-					boolean isAllStateHolon = dropHolon.getLayer() == 0;
+					boolean physicalConnected = control.getModel().checkHolonObjectsAreConnected(dragHolon, dropHolon, 0f);
+					boolean isAllStateHolon = dropHolon.getParent() == null;
 					return  physicalConnected || isAllStateHolon;
 				} catch (UnsupportedFlavorException | IOException e) {
 					e.printStackTrace();