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 ordersForSubholon; public TargetStateAssembler(HolonControlUnit hcu) { this.order = null; this.hcu = hcu; this.ordersForSubholon = new HashMap(); } 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 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 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 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 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 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 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 childStates = this.hcu.getStateEstimator().getChildStates(); List> childPerm = getAllPermutations(List.copyOf(childStates.keySet())); HashMap> potChild = new HashMap>(); for(List 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 list = new ArrayList(); if(potChild.containsKey(max)) { list = potChild.get(max); } List 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 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 predictedPowerUsage, OptimizationScheme optScheme) { List requests = this.hcu.getHierarchyController().getMergeRequestsForTimeStep(timeStep-1); if(requests == null) return 0f; //store holon which would help decrease |requiredPower| ArrayList poten = new ArrayList(); //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> potPermut = getAllPermutations(poten); HashMap> potSavings = new HashMap>(); for(List 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= 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 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 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 List> getAllPermutations(List set){ List> out = new ArrayList>(); for(int i=0; i l = new ArrayList(); l.addAll(set.subList(i, j+1)); out.add(l); } } return out; } public float getDesiredPowerUsage() { return this.desiredPowerUsage; } public void setOrder(OrderMsg order, String sender) { if(sender.equals(this.hcu.getHierarchyController().getSuperHolon())) { this.order = order; } } }