Browse Source

Implement asynchronous solving of the power flow, which adds additional thread safety to many places in the code

Henrik Kunzelmann 3 years ago
parent
commit
3825e84c03

+ 27 - 25
src/algorithm/binary/BaseLine.java

@@ -309,31 +309,33 @@ public class BaseLine implements AddOn {
 		control.calculateStateAndVisualForCurrentTimeStep();
 		DecoratedState actualstate = control.getSimManager().getActualDecorState();	
 		for(DecoratedNetwork net : actualstate.getNetworkList()) {
-			float production = net.getSupplierList().stream().map(supplier -> supplier.getEnergyToSupplyNetwork()).reduce(0.0f, (a, b) -> a + b);
-			float consumption = net.getConsumerList().stream().map(con -> con.getEnergyNeededFromNetwork()).reduce(0.0f, (a, b) -> a + b);
-			float difference = Math.abs(production - consumption);
-			println("production:" + production + "  consumption:" + consumption);
-			if(!(production < consumption))continue;
-			if(net.getConsumerList().isEmpty() && net.getConsumerSelfSuppliedList().isEmpty())continue;
-			//Stream.concat(net.getConsumerList().stream(), net.getConsumerSelfSuppliedList().stream());
-			int consumerWihtMaxNumberElements = Stream.concat(net.getConsumerList().stream(), net.getConsumerSelfSuppliedList().stream()).map(con -> con.getModel().getNumberOfElements()).max((lhs,rhs) ->Integer.compare(lhs, rhs)).orElse(0);
-			println("consumerWihtMaxNumberElements:" + consumerWihtMaxNumberElements);
-			for(int inAktiveCount = 0;inAktiveCount <= consumerWihtMaxNumberElements; inAktiveCount++) {
-				println("inAktiveCount:" + inAktiveCount);
-				final int inAktiveCountFinal = inAktiveCount;
-				List<HolonObject> conList = Stream.concat(net.getConsumerList().stream(), net.getConsumerSelfSuppliedList().stream()).map(con -> con.getModel()).filter(object -> objectList.contains(object)).filter(object -> (object.getNumberOfInActiveElements() == inAktiveCountFinal)).collect(Collectors.toList());
-				conList.sort((a,b) -> Float.compare(a.getMaximumConsumingElementEnergy(actualIteration), b.getMaximumConsumingElementEnergy(actualIteration)));
-				consumer:
-				for(HolonObject con: conList) {
-					//println("Consumer" + con);
-					List<HolonElement> sortedElementList = con.getElements().stream().filter(ele -> ele.isActive() && ele.isConsumer()).sorted((a,b) -> -Float.compare(-a.getEnergyAtTimeStep(actualIteration), -b.getEnergyAtTimeStep(actualIteration))).collect(Collectors.toList());
-					for(HolonElement element: sortedElementList) {
-						float elementConsumption = -element.getEnergyAtTimeStep(actualIteration);
-						if(elementConsumption <= difference) {
-							println("elementConsumption:" + elementConsumption);
-							difference -= elementConsumption;
-							element.setActive(false);
-							continue consumer;
+			synchronized (net.getLockObject()) {
+				float production = net.getSupplierList().stream().map(supplier -> supplier.getEnergyToSupplyNetwork()).reduce(0.0f, (a, b) -> a + b);
+				float consumption = net.getConsumerList().stream().map(con -> con.getEnergyNeededFromNetwork()).reduce(0.0f, (a, b) -> a + b);
+				float difference = Math.abs(production - consumption);
+				println("production:" + production + "  consumption:" + consumption);
+				if (!(production < consumption)) continue;
+				if (net.getConsumerList().isEmpty() && net.getConsumerSelfSuppliedList().isEmpty()) continue;
+				//Stream.concat(net.getConsumerList().stream(), net.getConsumerSelfSuppliedList().stream());
+				int consumerWihtMaxNumberElements = Stream.concat(net.getConsumerList().stream(), net.getConsumerSelfSuppliedList().stream()).map(con -> con.getModel().getNumberOfElements()).max((lhs, rhs) -> Integer.compare(lhs, rhs)).orElse(0);
+				println("consumerWihtMaxNumberElements:" + consumerWihtMaxNumberElements);
+				for (int inAktiveCount = 0; inAktiveCount <= consumerWihtMaxNumberElements; inAktiveCount++) {
+					println("inAktiveCount:" + inAktiveCount);
+					final int inAktiveCountFinal = inAktiveCount;
+					List<HolonObject> conList = Stream.concat(net.getConsumerList().stream(), net.getConsumerSelfSuppliedList().stream()).map(con -> con.getModel()).filter(object -> objectList.contains(object)).filter(object -> (object.getNumberOfInActiveElements() == inAktiveCountFinal)).collect(Collectors.toList());
+					conList.sort((a, b) -> Float.compare(a.getMaximumConsumingElementEnergy(actualIteration), b.getMaximumConsumingElementEnergy(actualIteration)));
+					consumer:
+					for (HolonObject con : conList) {
+						//println("Consumer" + con);
+						List<HolonElement> sortedElementList = con.getElements().stream().filter(ele -> ele.isActive() && ele.isConsumer()).sorted((a, b) -> -Float.compare(-a.getEnergyAtTimeStep(actualIteration), -b.getEnergyAtTimeStep(actualIteration))).collect(Collectors.toList());
+						for (HolonElement element : sortedElementList) {
+							float elementConsumption = -element.getEnergyAtTimeStep(actualIteration);
+							if (elementConsumption <= difference) {
+								println("elementConsumption:" + elementConsumption);
+								difference -= elementConsumption;
+								element.setActive(false);
+								continue consumer;
+							}
 						}
 					}
 				}

+ 48 - 44
src/algorithm/example/FlexExample.java

@@ -361,49 +361,51 @@ public class FlexExample implements AddOn {
 			List<Priority> priorityListASC = createPriorityListASC();
 			DecoratedState actualstate = control.getSimManager().getActualDecorState();	
 			for(DecoratedNetwork net : actualstate.getNetworkList()) {
-				float production = net.getSupplierList().stream().map(supplier -> supplier.getEnergyToSupplyNetwork()).reduce(0.0f, (a, b) -> a + b);
-				float consumption = net.getConsumerList().stream().map(con -> con.getEnergyNeededFromNetwork()).reduce(0.0f, (a, b) -> a + b);
-				float difference = Math.abs(production - consumption);
-				println("production: " + production);
-				println("consumption: " + consumption);
-				println("difference: " + difference);
-				if(production > consumption) continue;
-				if(difference == 0)continue;
-				Set<HolonElement> allHolonElemntsInThisNetwork = createListOfAllHolonElemnts(net);
-				FlexManager flexManager = control.getSimManager().getActualFlexManager();
-				
-				List<FlexWrapper> allOfferedFlex = flexManager.getAllFlexWrapperWithState(FlexState.OFFERED).stream().filter(flexWrapper -> allHolonElemntsInThisNetwork.contains(flexWrapper.getFlex().getElement())).collect(Collectors.toList());
-				List<FlexWrapper> allFlexThatGetMeEnergy = allOfferedFlex.stream().filter(flexWrapper -> (flexWrapper.getFlex().bringtmir() > 0)).collect(Collectors.toList());
-				float amountOfAllEnergyOffered = sumEnergyAvailable(allFlexThatGetMeEnergy);
-				println("amountOfAllFlexEnergyOffered:" + amountOfAllEnergyOffered);
-				//ShuddownPriorities
-				for(Priority emergencyShutDownPriority: priorityListASC) {
-					if(amountOfAllEnergyOffered >= difference) break; 
-					println("ShutDown: " + emergencyShutDownPriority);
-					difference -= shutDownAllConsumerElementsWithPriority(flexManager, allHolonElemntsInThisNetwork, emergencyShutDownPriority, result);
-				}
-				
-				//SortFlexes
-				allFlexThatGetMeEnergy.sort((flex1, flex2) -> Float.compare(flex1.getFlex().cost / flex1.getFlex().bringtmir(), flex2.getFlex().cost / flex2.getFlex().bringtmir()));
-				//OrderFlexes
-				float costForThisTimeStep = 0f;
-				int amountflexActivated = 0;
-				for(FlexWrapper flexWrapper : allFlexThatGetMeEnergy) {
-					if(!flexWrapper.canOrder()) continue;
-					float energy = flexWrapper.getFlex().bringtmir();
-					if(energy <= difference) {
-						println("energyGained:" + energy);
-						difference -= energy;
-						costForThisTimeStep += flexWrapper.getFlex().cost;
-						flexWrapper.order();
-						amountflexActivated++;
-						continue;
+				synchronized (net.getLockObject()) {
+					float production = net.getSupplierList().stream().map(supplier -> supplier.getEnergyToSupplyNetwork()).reduce(0.0f, (a, b) -> a + b);
+					float consumption = net.getConsumerList().stream().map(con -> con.getEnergyNeededFromNetwork()).reduce(0.0f, (a, b) -> a + b);
+					float difference = Math.abs(production - consumption);
+					println("production: " + production);
+					println("consumption: " + consumption);
+					println("difference: " + difference);
+					if (production > consumption) continue;
+					if (difference == 0) continue;
+					Set<HolonElement> allHolonElemntsInThisNetwork = createListOfAllHolonElemnts(net);
+					FlexManager flexManager = control.getSimManager().getActualFlexManager();
+
+					List<FlexWrapper> allOfferedFlex = flexManager.getAllFlexWrapperWithState(FlexState.OFFERED).stream().filter(flexWrapper -> allHolonElemntsInThisNetwork.contains(flexWrapper.getFlex().getElement())).collect(Collectors.toList());
+					List<FlexWrapper> allFlexThatGetMeEnergy = allOfferedFlex.stream().filter(flexWrapper -> (flexWrapper.getFlex().bringtmir() > 0)).collect(Collectors.toList());
+					float amountOfAllEnergyOffered = sumEnergyAvailable(allFlexThatGetMeEnergy);
+					println("amountOfAllFlexEnergyOffered:" + amountOfAllEnergyOffered);
+					//ShuddownPriorities
+					for (Priority emergencyShutDownPriority : priorityListASC) {
+						if (amountOfAllEnergyOffered >= difference) break;
+						println("ShutDown: " + emergencyShutDownPriority);
+						difference -= shutDownAllConsumerElementsWithPriority(flexManager, allHolonElemntsInThisNetwork, emergencyShutDownPriority, result);
 					}
+
+					//SortFlexes
+					allFlexThatGetMeEnergy.sort((flex1, flex2) -> Float.compare(flex1.getFlex().cost / flex1.getFlex().bringtmir(), flex2.getFlex().cost / flex2.getFlex().bringtmir()));
+					//OrderFlexes
+					float costForThisTimeStep = 0f;
+					int amountflexActivated = 0;
+					for (FlexWrapper flexWrapper : allFlexThatGetMeEnergy) {
+						if (!flexWrapper.canOrder()) continue;
+						float energy = flexWrapper.getFlex().bringtmir();
+						if (energy <= difference) {
+							println("energyGained:" + energy);
+							difference -= energy;
+							costForThisTimeStep += flexWrapper.getFlex().cost;
+							flexWrapper.order();
+							amountflexActivated++;
+							continue;
+						}
+					}
+					result.activatedFlex += amountflexActivated;
+
+					println("Activated FlexThisTimeStep: " + amountflexActivated + "   CostForThisTimeStep:" + costForThisTimeStep);
+					result.totalCost += costForThisTimeStep;
 				}
-				result.activatedFlex += 	amountflexActivated;
-				
-				println("Activated FlexThisTimeStep: "+ amountflexActivated+"   CostForThisTimeStep:" + costForThisTimeStep);
-				result.totalCost += costForThisTimeStep;
 			}
 			calculateStateResult(result);
 		}
@@ -456,9 +458,11 @@ public class FlexExample implements AddOn {
 		}
 		private Set<HolonElement> createListOfAllHolonElemnts(DecoratedNetwork net) {
 			Set<HolonElement> allHolonElemntsInThisNetwork = new HashSet<HolonElement>();
-			allHolonElemntsInThisNetwork.addAll(net.getConsumerList().stream().flatMap(con -> con.getModel().getElements().stream()).collect(Collectors.toList()));
-			allHolonElemntsInThisNetwork.addAll(net.getConsumerSelfSuppliedList().stream().flatMap(con -> con.getModel().getElements().stream()).collect(Collectors.toList()));
-			allHolonElemntsInThisNetwork.addAll(net.getSupplierList().stream().flatMap(con -> con.getModel().getElements().stream()).collect(Collectors.toList()));
+			synchronized (net.getLockObject()) {
+				allHolonElemntsInThisNetwork.addAll(net.getConsumerList().stream().flatMap(con -> con.getModel().getElements().stream()).collect(Collectors.toList()));
+				allHolonElemntsInThisNetwork.addAll(net.getConsumerSelfSuppliedList().stream().flatMap(con -> con.getModel().getElements().stream()).collect(Collectors.toList()));
+				allHolonElemntsInThisNetwork.addAll(net.getSupplierList().stream().flatMap(con -> con.getModel().getElements().stream()).collect(Collectors.toList()));
+			}
 			return allHolonElemntsInThisNetwork;
 		}
 

+ 12 - 10
src/algorithm/objectiveFunction/Evaluation.java

@@ -26,20 +26,22 @@ public class Evaluation {
 		
 		// calculate network_fitness
 		for(DecoratedNetwork net : state.getNetworkList()) {
-			float production = net.getSupplierList().stream().map(supplier -> supplier.getEnergyToSupplyNetwork()).reduce(0.0f, (a, b) -> a + b);
-			float consumption = net.getConsumerList().stream().map(con -> con.getEnergyNeededFromNetwork()).reduce(0.0f, (a, b) -> a + b);
-			nw_fitness += Math.abs((production - consumption)/100); //Energy is now everywhere positive
+			synchronized (net.getLockObject()) {
+				float production = net.getSupplierList().stream().map(supplier -> supplier.getEnergyToSupplyNetwork()).reduce(0.0f, (a, b) -> a + b);
+				float consumption = net.getConsumerList().stream().map(con -> con.getEnergyNeededFromNetwork()).reduce(0.0f, (a, b) -> a + b);
+				nw_fitness += Math.abs((production - consumption) / 100); //Energy is now everywhere positive
+			}
 		}
 		
 		// calculate object_fitness
 		for(DecoratedNetwork net : state.getNetworkList()) {
-
-			object_fitness += net.getConsumerList().stream().map(con -> holonObjectSupplyPenaltyFunction(con.getSupplyBarPercentage()) /*+ inactiveHolonElementPenalty(con.getModel())*/).reduce(0.0, (a, b) -> (a + b));
-			object_fitness += net.getConsumerList().stream().map(con -> StateToDouble(con.getState())).reduce(0.0, (a,b) -> (a+b));
-			//object_fitness += net.getPassivNoEnergyList().stream().map(sup -> inactiveHolonElementPenalty(sup.getModel())).reduce(0.0, (a, b) -> (a + b));
-			//object_fitness += net.getSupplierList().stream().map(sup -> inactiveHolonElementPenalty(sup.getModel())).reduce(0.0, (a, b) -> (a + b));
-			//object_fitness += net.getConsumerSelfSuppliedList().stream().map(con -> inactiveHolonElementPenalty(con.getModel())).reduce(0.0, (a, b) -> (a + b));
-
+			synchronized (net.getLockObject()) {
+				object_fitness += net.getConsumerList().stream().map(con -> holonObjectSupplyPenaltyFunction(con.getSupplyBarPercentage()) /*+ inactiveHolonElementPenalty(con.getModel())*/).reduce(0.0, (a, b) -> (a + b));
+				object_fitness += net.getConsumerList().stream().map(con -> StateToDouble(con.getState())).reduce(0.0, (a, b) -> (a + b));
+				//object_fitness += net.getPassivNoEnergyList().stream().map(sup -> inactiveHolonElementPenalty(sup.getModel())).reduce(0.0, (a, b) -> (a + b));
+				//object_fitness += net.getSupplierList().stream().map(sup -> inactiveHolonElementPenalty(sup.getModel())).reduce(0.0, (a, b) -> (a + b));
+				//object_fitness += net.getConsumerSelfSuppliedList().stream().map(con -> inactiveHolonElementPenalty(con.getModel())).reduce(0.0, (a, b) -> (a + b));
+			}
 		}
 		// calculate flexibility fitness old cost flex
 		/*for(FlexWrapper flexWrapper :state.getFlexManager().getAllFlexWrapperWithState(FlexState.IN_USE)) {

+ 81 - 81
src/algorithm/objectiveFunction/GraphMetrics.java

@@ -62,94 +62,94 @@ public class GraphMetrics {
 	 * @return a equivalent Graph to the DecoratedNetwork
 	 */
 	public static Graph convertDecoratedNetworkToGraph(DecoratedNetwork net) {
-		Graph G = new Graph();
-		HashMap<AbstractCanvasObject, Integer> objectToId = new HashMap<>();
-		List<Integer> sourcesList = new ArrayList<Integer>();
-		int count = 0;
-		for(Consumer con: net.getConsumerList()) {
-			objectToId.put(con.getModel(), count);
-			sourcesList.add(count);
-			count++;
-		}
-		for(Consumer con: net.getConsumerSelfSuppliedList()) {
-			objectToId.put(con.getModel(), count);
-			sourcesList.add(count);
-			count++;
-		}
-		for(Passiv pas: net.getPassivNoEnergyList()) {
-			objectToId.put(pas.getModel(), count);
-			sourcesList.add(count);
-			count++;
-		}
-		for(Supplier sup: net.getSupplierList()) {
-			objectToId.put(sup.getModel(), count);
-			sourcesList.add(count);
-			count++;
-		}
-		
-		
-		
-		//Generate EdgeList 
-		List<Edge> edgeList = new ArrayList<Edge>();
-		for(DecoratedCable cable : net.getDecoratedCableList()){
-			
-			AbstractCanvasObject objectA = cable.getModel().getA();
-			AbstractCanvasObject objectB = cable.getModel().getB();
-			if(objectA == null) {
-				System.out.println("Edge: " + cable + "objectA == null");
-				continue;
+		synchronized (net.getLockObject()) {
+			Graph G = new Graph();
+			HashMap<AbstractCanvasObject, Integer> objectToId = new HashMap<>();
+			List<Integer> sourcesList = new ArrayList<Integer>();
+			int count = 0;
+			for (Consumer con : net.getConsumerList()) {
+				objectToId.put(con.getModel(), count);
+				sourcesList.add(count);
+				count++;
 			}
-			if(objectB == null) {
-				System.out.println("Edge: " + cable + "objectB == null");
-				continue;
+			for (Consumer con : net.getConsumerSelfSuppliedList()) {
+				objectToId.put(con.getModel(), count);
+				sourcesList.add(count);
+				count++;
 			}
-			
-			//SpecialCase for open switches
-			if(objectA instanceof HolonSwitch && !((HolonSwitch)objectA).getManualState()) {
-				continue;
+			for (Passiv pas : net.getPassivNoEnergyList()) {
+				objectToId.put(pas.getModel(), count);
+				sourcesList.add(count);
+				count++;
 			}
-			if(objectB instanceof HolonSwitch && !((HolonSwitch)objectB).getManualState()) {
-				continue;
+			for (Supplier sup : net.getSupplierList()) {
+				objectToId.put(sup.getModel(), count);
+				sourcesList.add(count);
+				count++;
 			}
-			
-			int idA = -1;
-			if(objectToId.containsKey(objectA)) {
-				idA = objectToId.get(objectA);
-			}else {
-				idA = count;
-				objectToId.put(objectA, count++);
+
+
+			//Generate EdgeList
+			List<Edge> edgeList = new ArrayList<Edge>();
+			for (DecoratedCable cable : net.getDecoratedCableList()) {
+
+				AbstractCanvasObject objectA = cable.getModel().getA();
+				AbstractCanvasObject objectB = cable.getModel().getB();
+				if (objectA == null) {
+					System.out.println("Edge: " + cable + "objectA == null");
+					continue;
+				}
+				if (objectB == null) {
+					System.out.println("Edge: " + cable + "objectB == null");
+					continue;
+				}
+
+				//SpecialCase for open switches
+				if (objectA instanceof HolonSwitch && !((HolonSwitch) objectA).getManualState()) {
+					continue;
+				}
+				if (objectB instanceof HolonSwitch && !((HolonSwitch) objectB).getManualState()) {
+					continue;
+				}
+
+				int idA = -1;
+				if (objectToId.containsKey(objectA)) {
+					idA = objectToId.get(objectA);
+				} else {
+					idA = count;
+					objectToId.put(objectA, count++);
+				}
+				int idB = -1;
+				if (objectToId.containsKey(objectB)) {
+					idB = objectToId.get(objectB);
+				} else {
+					idB = count;
+					objectToId.put(objectB, count++);
+				}
+				double length = cable.getModel().getLength();
+				edgeList.add(new Edge(idA, idB, length));
 			}
-			int idB = -1;
-			if(objectToId.containsKey(objectB)) {
-				idB = objectToId.get(objectB);
-			}else {
-				idB = count;
-				objectToId.put(objectB, count++);
+			//Generate EdgeArray
+			G.E = new Edge[edgeList.size()];
+			for (int i = 0; i < edgeList.size(); i++) {
+				G.E[i] = edgeList.get(i);
 			}
-			double length = cable.getModel().getLength();
-			edgeList.add(new Edge(idA, idB, length));
-		}
-		//Generate EdgeArray
-		G.E = new Edge[edgeList.size()];
-		for(int i=0;i<edgeList.size();i++)
-	    {
-				G.E[i] =  edgeList.get(i);
-	    }
-		//Generate VertexArray
-		G.V = new Vertex[objectToId.size()];
-		int entryCount = 0;
-		for(Entry<AbstractCanvasObject, Integer> entry : objectToId.entrySet()) {
-			G.V[entryCount] =  new Vertex(entry.getValue());
-			entryCount++;
-		}
-		//Generate Sources Array
-		int sourceCount = 0;
-		G.S = new Vertex[sourcesList.size()];
-		for(int source : sourcesList) {
-			G.S[sourceCount] = new Vertex(source);
-			sourceCount++;
+			//Generate VertexArray
+			G.V = new Vertex[objectToId.size()];
+			int entryCount = 0;
+			for (Entry<AbstractCanvasObject, Integer> entry : objectToId.entrySet()) {
+				G.V[entryCount] = new Vertex(entry.getValue());
+				entryCount++;
+			}
+			//Generate Sources Array
+			int sourceCount = 0;
+			G.S = new Vertex[sourcesList.size()];
+			for (int source : sourcesList) {
+				G.S[sourceCount] = new Vertex(source);
+				sourceCount++;
+			}
+			return G;
 		}
-		return G;
 	}
 	
 	

+ 8 - 6
src/algorithm/objectiveFunction/ObjectiveFunctionByCarlos.java

@@ -97,12 +97,14 @@ public class ObjectiveFunctionByCarlos {
 		double f_eb = 0;
 		//sum over all objects
 		for(DecoratedNetwork net : state.getNetworkList()) {
-			double netEnergyDifference = 0;
-			netEnergyDifference += net.getConsumerList().stream().map(con -> con.getEnergySelfSupplied() - con.getEnergyFromConsumingElemnets()).reduce(0.f, Float::sum);
-			netEnergyDifference += net.getConsumerSelfSuppliedList().stream().map(con -> con.getEnergySelfSupplied() - con.getEnergyFromConsumingElemnets()).reduce(0.f, Float::sum);
-			netEnergyDifference += net.getSupplierList().stream().map(sup -> sup.getEnergyProducing() - sup.getEnergySelfConsuming()).reduce(0.f, Float::sum);
-			//abs
-			f_eb += Math.abs(netEnergyDifference);
+			synchronized (net.getLockObject()) {
+				double netEnergyDifference = 0;
+				netEnergyDifference += net.getConsumerList().stream().map(con -> con.getEnergySelfSupplied() - con.getEnergyFromConsumingElemnets()).reduce(0.f, Float::sum);
+				netEnergyDifference += net.getConsumerSelfSuppliedList().stream().map(con -> con.getEnergySelfSupplied() - con.getEnergyFromConsumingElemnets()).reduce(0.f, Float::sum);
+				netEnergyDifference += net.getSupplierList().stream().map(sup -> sup.getEnergyProducing() - sup.getEnergySelfConsuming()).reduce(0.f, Float::sum);
+				//abs
+				f_eb += Math.abs(netEnergyDifference);
+			}
 		}
 		
 		//Calculate f_state the penalty function for the supply state

+ 13 - 11
src/api/AlgorithmFrameworkFlex.java

@@ -795,17 +795,19 @@ public abstract class AlgorithmFrameworkFlex implements AddOn{
 		int activeElements = 0, amountOfelements = 0;
 		int totalConsumption = 0, totalProduction = 0;
 		for(DecoratedNetwork net : state.getNetworkList()) {
-			amountOfConsumer += net.getAmountOfConsumer();
-			amountOfSupplier += net.getAmountOfSupplier();
-			amountOfPassiv += net.getAmountOfPassiv();
-			unSuppliedConsumer += net.getAmountOfConsumerWithState(HolonObjectState.NOT_SUPPLIED);
-			partiallySuppliedConsumer += net.getAmountOfConsumerWithState(HolonObjectState.PARTIALLY_SUPPLIED);
-			suppliedConsumer += net.getAmountOfConsumerWithState(HolonObjectState.SUPPLIED);
-			overSuppliedConsumer += net.getAmountOfConsumerWithState(HolonObjectState.OVER_SUPPLIED);
-			amountOfelements += net.getAmountOfElements();
-			activeElements += net.getAmountOfActiveElements();
-			totalConsumption += net.getTotalConsumption();
-			totalProduction += net.getTotalProduction();
+			synchronized (net.getLockObject()) {
+				amountOfConsumer += net.getAmountOfConsumer();
+				amountOfSupplier += net.getAmountOfSupplier();
+				amountOfPassiv += net.getAmountOfPassiv();
+				unSuppliedConsumer += net.getAmountOfConsumerWithState(HolonObjectState.NOT_SUPPLIED);
+				partiallySuppliedConsumer += net.getAmountOfConsumerWithState(HolonObjectState.PARTIALLY_SUPPLIED);
+				suppliedConsumer += net.getAmountOfConsumerWithState(HolonObjectState.SUPPLIED);
+				overSuppliedConsumer += net.getAmountOfConsumerWithState(HolonObjectState.OVER_SUPPLIED);
+				amountOfelements += net.getAmountOfElements();
+				activeElements += net.getAmountOfActiveElements();
+				totalConsumption += net.getTotalConsumption();
+				totalProduction += net.getTotalProduction();
+			}
 		}
 		int amountOfObjects = amountOfSupplier + amountOfConsumer + amountOfPassiv;
 		int difference = Math.abs(totalProduction - totalConsumption);

+ 1 - 1
src/holeg/GridSolverResult.java

@@ -1,5 +1,5 @@
 package holeg;
 
 public enum GridSolverResult {
-    Error, PartialFailure, Solved
+    Error, PartialFailure, Solved, Interrupted
 }

+ 68 - 27
src/holeg/HolegGateway.java

@@ -11,6 +11,7 @@ import holeg.simple_grid.SimpleGridNode;
 import holeg.ui.PowerFlowAnalysisMenu;
 import holeg.ui.SolveResultMessageBox;
 import ui.controller.FlexManager;
+import ui.controller.SingletonControl;
 import ui.model.*;
 
 import java.util.HashMap;
@@ -39,6 +40,7 @@ public class HolegGateway {
         for (AbstractCanvasObject object : network.getNodeAndSwitches()) {
             SimpleGridNode node = gridBuilder.addHouse(new ComplexNumber(0, 0));
             node.tag = object;
+            node.typeByDesign = NodeType.Bus;
             canvasToGrid.put(object, node);
         }
         for (IntermediateCableWithState cable : network.getEdgeList()) {
@@ -55,23 +57,27 @@ public class HolegGateway {
     }
 
     private static void decorateNetwork(MinimumNetwork network, int iteration, FlexManager flexManager, DecoratedNetwork decoratedNetwork, Grid grid) {
-        for (GridNode node : grid.getNodes()) {
-            SimpleGridNode simpleNode = (SimpleGridNode) node;
-            if (node.getPowerGeneration().lenSquared() > 0)
-                decoratedNetwork.getSupplierList().add(new Supplier((HolonObject) simpleNode.tag, (float) node.getPowerGeneration().real, 0, simpleNode.voltage, simpleNode.phaseDegrees, simpleNode.typeSolved == NodeType.Slack));
-            else if (node.getPowerConsumption().lenSquared() > 0)
-                decoratedNetwork.getConsumerList().add(new Consumer((HolonObject) simpleNode.tag, (float) node.getPowerConsumption().real, simpleNode.voltage, simpleNode.phaseDegrees, Math.cos(simpleNode.getPowerConsumption().angle()), simpleNode.typeSolved == NodeType.Slack));
-            else if (simpleNode.tag instanceof HolonObject)
-                decoratedNetwork.getPassivNoEnergyList().add(new Passiv((HolonObject) simpleNode.tag));
-        }
-        for (GridEdge edge : grid.getEdges()) {
-            SimpleGridEdge simpleGridEdge = (SimpleGridEdge) edge;
-            decoratedNetwork.getDecoratedCableList().add(
-                    new DecoratedCable(
-                            ((IntermediateCableWithState)simpleGridEdge.tag).getModel(),
-                            DecoratedCable.CableState.Working,
-                            (float)simpleGridEdge.power.real,
-                            (float)simpleGridEdge.loss.real));
+        synchronized (decoratedNetwork.getLockObject()) {
+            decoratedNetwork.clear();
+            for (GridNode node : grid.getNodes()) {
+                SimpleGridNode simpleNode = (SimpleGridNode) node;
+                if (node.getPowerGeneration().lenSquared() > 0)
+                    decoratedNetwork.getSupplierList().add(new Supplier((HolonObject) simpleNode.tag, (float) node.getPowerGeneration().real, 0, simpleNode.voltage, simpleNode.phaseDegrees, simpleNode.typeSolved == NodeType.Slack));
+                else if (node.getPowerConsumption().lenSquared() > 0)
+                    decoratedNetwork.getConsumerList().add(new Consumer((HolonObject) simpleNode.tag, (float) node.getPowerConsumption().real, simpleNode.voltage, simpleNode.phaseDegrees, Math.cos(simpleNode.getPowerConsumption().angle()), simpleNode.typeSolved == NodeType.Slack));
+                else if (simpleNode.tag instanceof HolonObject)
+                    decoratedNetwork.getPassivNoEnergyList().add(new Passiv((HolonObject) simpleNode.tag));
+            }
+            for (GridEdge edge : grid.getEdges()) {
+                SimpleGridEdge simpleGridEdge = (SimpleGridEdge) edge;
+                decoratedNetwork.getDecoratedCableList().add(
+                        new DecoratedCable(
+                                ((IntermediateCableWithState) simpleGridEdge.tag).getModel(),
+                                DecoratedCable.CableState.Working,
+                                (float) simpleGridEdge.power.real,
+                                (float) simpleGridEdge.loss.real));
+            }
+            decoratedNetwork.calculateStates();
         }
     }
 
@@ -99,18 +105,53 @@ public class HolegGateway {
             }
         }
 
-        // Start solver
-        GridSolverResult result = null;
-        if (solve) {
-            HolegPowerFlow powerFlow = new HolegPowerFlow();
-            result = powerFlow.solve(grid, PowerFlowSettings.getDefault());
+        // Stop old solver
+        if (context != null && context.solverJob != null) {
+            try {
+                context.solverJob.interrupt();
+                context.solverJob.join(200);
+            }
+            catch(InterruptedException ignored) {
+
+            }
+            context.solverJob = null;
         }
 
-        // Decorate network
-        decorateNetwork(minimumNetwork, iteration, flexManager, network, grid);
+        // Create solver job
+        Thread solverJob = new Thread(() -> {
+            long start = System.nanoTime();
+            GridSolverResult result = null;
+            if (solve) {
+                HolegPowerFlow powerFlow = new HolegPowerFlow();
+                result = powerFlow.solve(grid, PowerFlowSettings.getDefault());
+            }
 
-        // Show result
-        if (result != null && PowerFlowAnalysisMenu.getInstance().shouldShowResult())
-            SolveResultMessageBox.show(result);
+            // Decorate network
+            decorateNetwork(minimumNetwork, iteration, flexManager, network, grid);
+            if (context != null)
+                context.solverTimeMilliseconds = (System.nanoTime() - start) / 1e6f;
+            SingletonControl.getInstance().getControl().calculateVisual();
+
+            // Show result
+            if (result != null && PowerFlowAnalysisMenu.getInstance().shouldShowResult())
+                SolveResultMessageBox.show(result);
+        });
+
+
+        // Wait or save solver job
+        try {
+            if (context == null || context.settings.waitForSolverJob) {
+                solverJob.start();
+                solverJob.join();
+            }
+            else {
+                decorateNetwork(minimumNetwork, iteration, flexManager, network, grid);
+                context.solverJob = solverJob;
+                solverJob.start();
+            }
+        }
+        catch(InterruptedException e) {
+            e.printStackTrace();
+        }
     }
 }

+ 16 - 0
src/holeg/HolegPowerFlow.java

@@ -31,6 +31,10 @@ public class HolegPowerFlow {
 
         // Try to solve each island
         for (Grid island : islands) {
+            // Check if we should stop
+            if (Thread.interrupted())
+                return GridSolverResult.Interrupted;
+
             boolean solved = false;
 
             // Calculate number of calculation tries
@@ -49,6 +53,10 @@ public class HolegPowerFlow {
             SolverResult bestResult = null;
 
             for (int i = 0; i < solveTryCount; i++) {
+                // Check if we should stop
+                if (Thread.interrupted())
+                    return GridSolverResult.Interrupted;
+
                 // Build problem and solve it
                 PowerFlowProblem problem = buildProblem(island, i, settings);
 
@@ -65,6 +73,10 @@ public class HolegPowerFlow {
                 Solver solver = new NewtonRaphsonSolver();
                 SolverResult result = solver.solve(problem, settings.solverSettings);
 
+                // Solver was interrupted
+                if (result.error == SolverError.Interrupted)
+                    return GridSolverResult.Interrupted;
+
                 // Debug message
                 if (PowerFlowAnalysisMenu.getInstance().shouldShowDebug() && (result.solved || i == solveTryCount - 1))
                     debugShowResultAsMessageBox(problem, result);
@@ -113,6 +125,10 @@ public class HolegPowerFlow {
                 sumResult = GridSolverResult.Error;
         }
 
+        // Check if we should have stopped
+        if (Thread.interrupted())
+            return GridSolverResult.Interrupted;
+
         // Check if some islands failed, but not all
         if (anySolved && sumResult == GridSolverResult.Error)
             return GridSolverResult.PartialFailure;

+ 6 - 0
src/holeg/HolegPowerFlowContext.java

@@ -8,8 +8,14 @@ import java.util.List;
 public class HolegPowerFlowContext {
     public PowerFlowSettings settings = PowerFlowSettings.getDefault();
     public List<Grid> lastSolvedGrids = new ArrayList<>();
+    public Thread solverJob;
+    public float solverTimeMilliseconds;
 
     public void clearCache() {
         lastSolvedGrids.clear();
     }
+
+    public boolean isSolving() {
+        return solverJob != null && solverJob.isAlive();
+    }
 }

+ 2 - 0
src/holeg/PowerFlowSettings.java

@@ -5,6 +5,7 @@ import holeg.power_flow.SolverSettings;
 public class PowerFlowSettings {
     public SolverSettings solverSettings;
     public boolean onlyUpdateGridWhenChanged;
+    public boolean waitForSolverJob;
     public boolean skipGridsWithNoProducers;
     public boolean replaceNodeWithSlackNode;
     public SlackNodePlacementStrategy slackNodePlacementStrategy;
@@ -14,6 +15,7 @@ public class PowerFlowSettings {
     public PowerFlowSettings() {
         solverSettings = new SolverSettings(); // use default
         onlyUpdateGridWhenChanged = true;
+        waitForSolverJob = false;
         skipGridsWithNoProducers = true;
         replaceNodeWithSlackNode = true;
         slackNodePlacementStrategy = SlackNodePlacementStrategy.MinimizeSlack;

+ 5 - 0
src/holeg/power_flow/NewtonRaphsonSolver.java

@@ -2,6 +2,7 @@ package holeg.power_flow;
 
 import Jama.LUDecomposition;
 import Jama.Matrix;
+import holeg.GridSolverResult;
 
 import java.util.Arrays;
 
@@ -54,6 +55,10 @@ public class NewtonRaphsonSolver implements Solver {
             int jacobianRecalculation = 0;
 
             for (int iter = 1; iter <= settings.maxIterations; iter++) {
+                // Check if we should stop
+                if (Thread.interrupted())
+                    return SolverResult.error(SolverError.Interrupted);
+
                 // Calculate current P/Q values
                 double[] P = new double[busCount];
                 double[] Q = new double[busCount];

+ 2 - 1
src/holeg/power_flow/SolverError.java

@@ -4,5 +4,6 @@ public enum SolverError {
     None,
     Internal,
     InvalidData,
-    ConvergenceError
+    ConvergenceError,
+    Interrupted
 }

+ 3 - 0
src/holeg/ui/SolveResultMessageBox.java

@@ -16,6 +16,9 @@ public class SolveResultMessageBox {
             case Solved:
                 JOptionPane.showMessageDialog(null,"Successfully solved!","Success", JOptionPane.INFORMATION_MESSAGE);
                 break;
+            case Interrupted:
+                JOptionPane.showMessageDialog(null,"Solver interrupted!","Interrupted while solving.", JOptionPane.WARNING_MESSAGE);
+                break;
         }
     }
 }

+ 5 - 1
src/ui/controller/Control.java

@@ -564,9 +564,13 @@ public class Control {
      */
     public void calculateStateAndVisualForTimeStep(int x) {
         simulationManager.calculateStateForTimeStep(x, true);
+        calculateVisual();
+    }
+
+    public void calculateVisual() {
         updateOutliner();
         updateFlexWindow();
-        this.updateCanvas();
+        updateCanvas();
     }
 
     /**

+ 14 - 2
src/ui/model/DecoratedNetwork.java

@@ -20,6 +20,8 @@ public class DecoratedNetwork {
 	private ArrayList<DecoratedCable> decoratedCableList = new ArrayList<DecoratedCable>();
 	private int timestep;
 
+	private Object lockObject = new Object();
+
 	public DecoratedNetwork(HolegPowerFlowContext context, MinimumNetwork minimumNetwork, int Iteration, FairnessModel actualFairnessModel, FlexManager flexManager){
 		this.timestep = Iteration;
 		switch(actualFairnessModel) {
@@ -31,13 +33,23 @@ public class DecoratedNetwork {
 			break;
 		case PowerFlowAnalysis:
 			HolegGateway.solve(context, minimumNetwork, Iteration, flexManager, this);
-			calculateStates();
 			break;
 		}
 	}
 
+	public void clear() {
+		supplierList.clear();
+		consumerList.clear();
+		consumerSelfSuppliedList.clear();
+		passivNoEnergyList.clear();
+		decoratedCableList.clear();
+	}
 
 	//Getter:
+	public Object getLockObject() {
+		return lockObject;
+	}
+
 	public ArrayList<Supplier> getSupplierList() {
 		return supplierList;
 	}
@@ -218,7 +230,7 @@ public class DecoratedNetwork {
 		calculateStates();
 	}
 
-	private void calculateStates() {
+	public void calculateStates() {
 		//CalculateStates:
 		supplierList.forEach(sup -> sup.setState(HolonObjectState.PRODUCER));
 		passivNoEnergyList.forEach(sup -> sup.setState(HolonObjectState.NO_ENERGY));

+ 24 - 22
src/ui/model/VisualRepresentationalState.java

@@ -72,32 +72,34 @@ public class VisualRepresentationalState {
 		}
 		//unrolling Networks
 		for(DecoratedNetwork net : stateFromThisTimestep.getNetworkList()) {
-			for(Consumer con : net.getConsumerList()) {
-				DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, con.getModel(), consumerList, con, createdGroupNodes);
-				if(groupNodeFromObject != null) {
-					addToGroupNode(con, groupNodeFromObject.getConsumerList());
+			synchronized (net.getLockObject()) {
+				for (Consumer con : net.getConsumerList()) {
+					DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, con.getModel(), consumerList, con, createdGroupNodes);
+					if (groupNodeFromObject != null) {
+						addToGroupNode(con, groupNodeFromObject.getConsumerList());
+					}
 				}
-			}
-			for(Consumer con : net.getConsumerSelfSuppliedList()) {
-				DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, con.getModel(), consumerList, con, createdGroupNodes);
-				if(groupNodeFromObject != null) {
-					addToGroupNode(con, groupNodeFromObject.getConsumerList());
+				for (Consumer con : net.getConsumerSelfSuppliedList()) {
+					DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, con.getModel(), consumerList, con, createdGroupNodes);
+					if (groupNodeFromObject != null) {
+						addToGroupNode(con, groupNodeFromObject.getConsumerList());
+					}
 				}
-			}
-			for(Supplier sup : net.getSupplierList()) {
-				DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, sup.getModel(), supplierList, sup, createdGroupNodes);
-				if(groupNodeFromObject != null) {
-					addToGroupNode(sup, groupNodeFromObject.getSupplierList());
+				for (Supplier sup : net.getSupplierList()) {
+					DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, sup.getModel(), supplierList, sup, createdGroupNodes);
+					if (groupNodeFromObject != null) {
+						addToGroupNode(sup, groupNodeFromObject.getSupplierList());
+					}
 				}
-			}
-			for(Passiv pas : net.getPassivNoEnergyList()) {
-				DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, pas.getModel(), passivList, pas, createdGroupNodes);
-				if(groupNodeFromObject != null) {
-					addToGroupNode(pas, groupNodeFromObject.getPassivList());
+				for (Passiv pas : net.getPassivNoEnergyList()) {
+					DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, pas.getModel(), passivList, pas, createdGroupNodes);
+					if (groupNodeFromObject != null) {
+						addToGroupNode(pas, groupNodeFromObject.getPassivList());
+					}
+				}
+				for (DecoratedCable cable : net.getDecoratedCableList()) {
+					addCable(cable, inGroupEdges, inGroupObjects, createdGroupNodes, exitCables);
 				}
-			}
-			for(DecoratedCable cable : net.getDecoratedCableList()) {
-				addCable(cable, inGroupEdges, inGroupObjects,createdGroupNodes, exitCables);
 			}
 		}
 		for(DecoratedCable cable : stateFromThisTimestep.getLeftOverEdges()) {

+ 14 - 2
src/ui/view/MyCanvas.java

@@ -4,7 +4,9 @@ import classes.*;
 
 import com.google.gson.JsonParseException;
 
+import holeg.HolegPowerFlowContext;
 import ui.controller.Control;
+import ui.controller.SingletonControl;
 import ui.controller.UpdateController;
 import ui.model.IntermediateCableWithState;
 import ui.model.Consumer;
@@ -373,9 +375,9 @@ public class MyCanvas extends AbstractCanvas implements MouseListener,
 		// Only show voltage when given
 		if (voltage > 0) {
 			if (powerFactor >= 0)
-				g.drawString(String.format("%.0f V (%.1f °) PF: %d%%", voltage, phaseDegrees, Math.round(powerFactor * 100)), posOfCanvasObject.x - controller.getScaleDiv2(), posOfCanvasObject.y - controller.getScaleDiv2() - 14);
+				g.drawString(String.format("%.0f V (%.1f deg) PF: %d%%", voltage, phaseDegrees, Math.round(powerFactor * 100)), posOfCanvasObject.x - controller.getScaleDiv2(), posOfCanvasObject.y - controller.getScaleDiv2() - 14);
 			else
-				g.drawString(String.format("%.0f V (%.1f °)", voltage, phaseDegrees), posOfCanvasObject.x - controller.getScaleDiv2(), posOfCanvasObject.y - controller.getScaleDiv2() - 14);
+				g.drawString(String.format("%.0f V (%.1f deg)", voltage, phaseDegrees), posOfCanvasObject.x - controller.getScaleDiv2(), posOfCanvasObject.y - controller.getScaleDiv2() - 14);
 		}
 		if (isSlack)
 			g.drawString("SLACK", posOfCanvasObject.x - controller.getScaleDiv2(), posOfCanvasObject.y - controller.getScaleDiv2() - 28);
@@ -670,6 +672,16 @@ public class MyCanvas extends AbstractCanvas implements MouseListener,
 					controller.getScaleDiv2(), controller.getScaleDiv2(), null);
 		}
 		//<-- OldCode
+
+		// Draw solver job
+		HolegPowerFlowContext context = SingletonControl.getInstance().getControl().getSimManager().getHolegPowerFlowContext();
+		if (context != null) {
+			g2d.setColor(Color.BLACK);
+			if (context.isSolving())
+				g2d.drawString("Solver running...", 4, 14);
+			else
+				g2d.drawString(String.format("Solver finished in %.2f ms", context.solverTimeMilliseconds), 4, 14);
+		}
 	}
 
 	@Override

+ 28 - 26
src/ui/view/Outliner.java

@@ -89,35 +89,37 @@ public class Outliner extends JFrame {
 		}*/
 		
 		for(DecoratedNetwork dNet: decoratedState.getNetworkList()) {
-			DefaultMutableTreeNode network = new DefaultMutableTreeNode("Network");
-			if(!dNet.getConsumerList().isEmpty() || !dNet.getConsumerSelfSuppliedList().isEmpty()) {
-				DefaultMutableTreeNode consumer = new DefaultMutableTreeNode("ConsumerList");
-				for (Consumer con : dNet.getConsumerList()) {
-					DefaultMutableTreeNode consumerNode = new ColoredTreeNode(con.toString(),con.getState().toString(), getStateColor(con.getState()) );
-					consumer.add(consumerNode);
-					objects.add(new DefaultMutableTreeNode(con.getModel().getName()));
+			synchronized (dNet.getLockObject()) {
+				DefaultMutableTreeNode network = new DefaultMutableTreeNode("Network");
+				if (!dNet.getConsumerList().isEmpty() || !dNet.getConsumerSelfSuppliedList().isEmpty()) {
+					DefaultMutableTreeNode consumer = new DefaultMutableTreeNode("ConsumerList");
+					for (Consumer con : dNet.getConsumerList()) {
+						DefaultMutableTreeNode consumerNode = new ColoredTreeNode(con.toString(), con.getState().toString(), getStateColor(con.getState()));
+						consumer.add(consumerNode);
+						objects.add(new DefaultMutableTreeNode(con.getModel().getName()));
+					}
+					for (Consumer con : dNet.getConsumerSelfSuppliedList()) {
+						DefaultMutableTreeNode consumerNode = new DefaultMutableTreeNode(con.toString() + con.getState());
+						consumer.add(consumerNode);
+						objects.add(new DefaultMutableTreeNode(con.getModel().getName()));
+					}
+					network.add(consumer);
 				}
-				for (Consumer con : dNet.getConsumerSelfSuppliedList()) {
-					DefaultMutableTreeNode consumerNode = new DefaultMutableTreeNode(con.toString() + con.getState());
-					consumer.add(consumerNode);
-					objects.add(new DefaultMutableTreeNode(con.getModel().getName()));
+				if (!dNet.getSupplierList().isEmpty()) {
+					DefaultMutableTreeNode supplier = new DefaultMutableTreeNode("SupplierList");
+					for (Supplier sup : dNet.getSupplierList()) {
+						supplier.add(new DefaultMutableTreeNode(sup.toString()));
+						objects.add(new DefaultMutableTreeNode(sup.getModel().getName()));
+					}
+					network.add(supplier);
 				}
-				network.add(consumer);
-			}
-			if(!dNet.getSupplierList().isEmpty()) {
-				DefaultMutableTreeNode supplier = new DefaultMutableTreeNode("SupplierList");
-				for (Supplier sup : dNet.getSupplierList()) {
-					supplier.add(new DefaultMutableTreeNode(sup.toString()));
-					objects.add(new DefaultMutableTreeNode(sup.getModel().getName()));
+				for (Passiv pas : dNet.getPassivNoEnergyList()) {
+					objects.add(new DefaultMutableTreeNode(pas.getModel().getName()));
+				}
+				topStatePanel.add(network);
+				for (DecoratedCable cable : dNet.getDecoratedCableList()) {
+					cables.add(new DefaultMutableTreeNode(cable.getModel().toString()));
 				}
-				network.add(supplier);
-			}
-			for(Passiv pas: dNet.getPassivNoEnergyList()) {
-				objects.add(new DefaultMutableTreeNode(pas.getModel().getName()));
-			}
-			topStatePanel.add(network);
-			for(DecoratedCable cable : dNet.getDecoratedCableList()) {
-				cables.add(new DefaultMutableTreeNode(cable.getModel().toString()));
 			}
 		}