123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403 |
- 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;
-
- public TargetStateAssembler(HolonControlUnit hcu) {
- this.order = null;
- this.hcu = hcu;
- }
-
- public void assembleTargetState(int timeStep) {
- getDesiredPowerUsage(timeStep);
-
- //balance the sub holons
- OptimizationScheme optScheme = this.hcu.getOptimizer().getOptimizationScheme();
- switch(optScheme) {
- case COMFORT:
- assembleTargetStateComfort(timeStep);
- 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);
- }
-
- private void assembleTargetStateComfort(int timeStep) {
- //overall power usage inside this holarchy
- float powerUsage = this.hcu.getStateEstimator().getPowerUsage();
- ArrayList<Float> predictedPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage();
- //check if this holon can run independent from parent without risking stability
- if(this.hcu.matchPowerRange(powerUsage, 0f, predictedPowerUsage, OptimizationManager.POWER_THRESHOLD_COMFORT)
- && this.hcu.getHolon().getLayer() > 1 && this.hcu.getHolon().getParent().canRunIndependent(this.hcu.getHolon())) {
- this.hcu.getHolon().incIndeCounter();
- this.hcu.getHierarchyController().splitSuperHolon(timeStep);
- this.desiredPowerUsage = 0f;
- orderSubholonsPredictedPower(timeStep);
- return;
- }
- //powerUsage already matches desired value, everything as before
- if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage)) {
- orderSubholonsPredictedPower(timeStep);
- return;
- }
- float requiredPower = this.desiredPowerUsage - powerUsage;
-
- //find flexibility which matches required power
- float savedWithFlexibilities = this.hcu.getFlexMan().applyFlexibilities(powerUsage, requiredPower, predictedPowerUsage, timeStep);
- if(savedWithFlexibilities == requiredPower) {
- orderSubholonsPredictedPower(timeStep);
- return;
- }
- requiredPower -= savedWithFlexibilities;
-
- if(this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep)) {
- orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
- return;
- }
-
- //go through merge requests from last iteration
- float savedByMerging = gothroughMergeReq(timeStep, powerUsage, requiredPower, predictedPowerUsage, OptimizationScheme.COMFORT);
- if(savedByMerging == requiredPower) {
- orderSubholonsPredictedPower(timeStep);
- return;
- }
- requiredPower -= savedByMerging;
-
- //look out for another superholon
- if(!this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep)) {
- findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage);
- }
- //tell all holons to use a little more/less energy
- orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
- }
-
- private void assembleTargetStateStability(int timeStep) {
- //overall power usage inside this holarchy
- float powerUsage = this.hcu.getStateEstimator().getPowerUsage();
- ArrayList<Float> predictedPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage();
- //powerUsage already matches desired value, everything as before
- if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage)) {
- orderSubholonsPredictedPower(timeStep);
- return;
- }
- float requiredPower = this.desiredPowerUsage - powerUsage;
-
- //find flexibility which matches required power
- float savedWithFlexibilities = this.hcu.getFlexMan().applyFlexibilities(powerUsage, requiredPower, predictedPowerUsage, timeStep);
- if(savedWithFlexibilities == requiredPower) {
- orderSubholonsPredictedPower(timeStep);
- return;
- }
- requiredPower -= savedWithFlexibilities;
-
- if(this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep)) {
- orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
- return;
- }
-
- //go through merge requests from last iteration
- float savedByMerging = gothroughMergeReq(timeStep, powerUsage, requiredPower, predictedPowerUsage, OptimizationScheme.STABILITY);
- if(savedByMerging == requiredPower) {
- orderSubholonsPredictedPower(timeStep);
- return;
- }
- requiredPower -= savedByMerging;
-
- //look out for another superholon
- if(!this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep)) {
- findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage);
- }
-
- //tell all holons to use a little more/less energy
- orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
- }
-
- private void assembleTargetStateRecovery(int timeStep) {
- //overall power usage inside this holarchy
- float powerUsage = this.hcu.getStateEstimator().getPowerUsage();
- ArrayList<Float> predictedPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage();
- //powerUsage already matches desired value, everything as before
- if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage)) {
- orderSubholonsPredictedPower(timeStep);
- return;
- }
- float requiredPower = this.desiredPowerUsage - powerUsage;
-
- //find flexibility which matches required power
- float savedWithFlexibilities = this.hcu.getFlexMan().applyFlexibilities(powerUsage, requiredPower, predictedPowerUsage, timeStep);
- if(savedWithFlexibilities == requiredPower) {
- orderSubholonsPredictedPower(timeStep);
- return;
- }
- requiredPower -= savedWithFlexibilities;
-
- if(this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep)) {
- orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
- return;
- }
- //go through merge requests from last iteration
- float savedByMerging = gothroughMergeReq(timeStep, powerUsage, requiredPower, predictedPowerUsage, OptimizationScheme.RECOVERY);
- if(savedByMerging == requiredPower) {
- orderSubholonsPredictedPower(timeStep);
- return;
- }
- requiredPower -= savedByMerging;
-
- if(this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep)) {
- orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
- return;
- }
-
- 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[] savings = new Float[predictedPowerUsage.size()+1];
- for(int i=0; i<savings.length; i++)
- savings[i] = 0f;
- for(String s : l) {
- StateMsg state = childStates.get(s);
- savings[0] = savings[0] + state.getPowerUsage();
- for(int i=1; i<savings.length; i++) {
- savings[i] += state.getPredictedPowerUsage().get(i-1);
- }
- }
- if(this.hcu.decreasesPowerUsage(List.of(savings), powerUsage, predictedPowerUsage, this.desiredPowerUsage)) {
- float pu = 0f;
- for(int i=0; i<savings.length; i++)
- pu += savings[i];
- pu = pu/savings.length;
- if(potChild.containsKey(pu) && potChild.get(pu).size() >= l.size())
- continue;
- potChild.put(pu, l);
- }
- }
- //find subset of children with most fitting powerUsage
- float min = Float.MAX_VALUE;
- //the required power usage without any child holons
- float r = this.desiredPowerUsage - this.hcu.getHolon().getHolonObject().getEnergyAtTimeStepFlex(timeStep);
- for(float f : potChild.keySet()) {
- if(Math.abs(r-f) < Math.abs(r-min)) {
- min = f;
- }
- }
- //split all other subholons
- List<String> list = new ArrayList<String>();
- if(potChild.containsKey(min)) {
- list = potChild.get(min);
- List<String> subs = List.copyOf(this.hcu.getHierarchyController().getSubHolons());
- for(String s : subs) {
- if(!list.contains(s)) {
- this.hcu.getHolon().incKickCounter();
- this.hcu.getHierarchyController().splitSubHolon(s, timeStep);
- }
- }
- requiredPower = r - min;
- if(requiredPower == 0) {
- //by removing child holons we have regained stability
- orderSubholonsPredictedPower(timeStep);
- return;
- }
- orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
- return;
- }
- //Split from superholon?
- if(Math.abs(requiredPower) > Math.abs(powerUsage) && this.hcu.getHolon().getLayer() > 1
- && this.hcu.getHolon().getParent().canRunIndependent(this.hcu.getHolon())
- && !this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep)) {
- this.hcu.getHolon().incIndeCounter();
- this.hcu.getHierarchyController().splitSuperHolon(timeStep);
- orderSubholonsRequiredPower(timeStep, powerUsage, 0f-powerUsage);
- return;
- }
-
- //look out for another superholon
- if(!this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep))
- findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage);
-
- //tell all holons to use a little more/less energy
- orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
- }
- /**
- * 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 currentPower, float requiredPower, ArrayList<Float> predictedPower,
- OptimizationScheme optScheme) {
- List<MergeMsg> requests = this.hcu.getHierarchyController().getMergeRequestsForTimeStep(timeStep-1);
- if(requests == null)
- return 0f;
- if(this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep)) {
- 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) {
- 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;
- }
- // ask the requester whether it is still interested in merging
- this.hcu.getHierarchyController().sendMergeAck(timeStep, req);
- }
- poten = this.hcu.getHierarchyController().getReceivedMergeAckII(timeStep);
- //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[] savings = new Float[predictedPower.size()];
- for(int i=0; i<savings.length; i++)
- savings[i] = 0f;
- for(MergeMsg m : l) {
- for(int i=0; i<savings.length; i++) {
- savings[i] = savings[i] + m.getPredictedPowerUsage().get(i);
- }
- }
- if(this.hcu.decreasesPowerUsage(List.of(savings), currentPower, predictedPower, requiredPower)) {
- float s = 0f;
- for(int i=0; i<savings.length; i++)
- s += savings[i];
- s = s/savings.length; //average saving over the next time periods
- if(potSavings.containsKey(s) && potSavings.get(s).size() >= l.size())
- continue;
- potSavings.put(s, l);
- }
- }
- if(potSavings.size() < 1) {
- return 0f;
- }
- float min = Float.MAX_VALUE;
- for(float f : potSavings.keySet()) {
- if(Math.abs(requiredPower-f) < Math.abs(requiredPower-min)) {
- min = f;
- }
- }
- //merge with all holons that are part of the subset with the max saving
- if(potSavings.containsKey(min)) {
- for(MergeMsg req : potSavings.get(min)) {
- this.hcu.getHierarchyController().merge(req, timeStep);
- }
- //remove merge requests so they don't get propagated to super holon
- requests.removeAll(potSavings.get(min));
- this.hcu.getHierarchyController().resetPaths();
- return min;
- }
- return 0f;
- }
-
- private void findNewSuperHolon(int timeStep, float powerUsage, ArrayList<Float> predictedPowerUsage) {
- if(!this.hcu.getHolon().getParent().canRunIndependent(this.hcu.getHolon())) {
- return;
- }
- for(String physicalNeighbor : this.hcu.getHierarchyController().getPhysicalNeighborsFromOtherHolarchy()) {
- this.hcu.getHierarchyController().sendMergeReq(powerUsage, predictedPowerUsage, timeStep, physicalNeighbor);
- }
- }
-
- private void orderSubholonsPredictedPower(int timeStep) {
- HashMap<String, StateMsg> childStates = this.hcu.getStateEstimator().getChildStates();
- Gson gson = this.hcu.getCommunicator().getGson();
- for(String s : childStates.keySet()) {
- OrderMsg o = new OrderMsg(childStates.get(s).getPredictedPowerUsage().size() > 0 ?childStates.get(s).getPredictedPowerUsage().get(0) : 0, timeStep);
- this.hcu.getCommunicator().sendMsg(s, Message.Type.ORDER, gson.toJson(o));
- }
- }
-
- /**
- * 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) {
- Gson gson = this.hcu.getCommunicator().getGson();
- float opt = - requiredPower/this.hcu.getHierarchyController().getSubHolons().size();
- this.hcu.getStateEstimator().calculateNetThroughput(timeStep);
- for(String s : this.hcu.getHierarchyController().getSubHolons()) {
- //order for subholon
- OrderMsg o = new OrderMsg(opt, timeStep);
- //send order to subholon
- this.hcu.getCommunicator().sendMsg(s, Message.Type.ORDER, gson.toJson(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(int timeStep) {
- if(timeStep <= 0) {
- //for init
- this.desiredPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage().get(0);
- } else if(this.order == null || this.order.getTimeStep() < timeStep-1) {
- this.desiredPowerUsage = 0f;
- } else {
- this.desiredPowerUsage = this.order.getDesiredPowerUsage();
- }
- return this.desiredPowerUsage;
- }
- public void setOrder(OrderMsg order, String sender) {
- if(sender.equals(this.hcu.getHierarchyController().getSuperHolon())) {
- this.order = order;
- }
- }
-
- }
|