123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 |
- 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 this.desiredPowerUsage;
- }
- public void setOrder(OrderMsg order, String sender) {
- if(sender.equals(this.hcu.getHierarchyController().getSuperHolon())) {
- this.order = order;
- }
- }
-
- }
|