TargetStateAssembler.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. package classes.holonControlUnit;
  2. import java.util.ArrayList;
  3. import java.util.HashMap;
  4. import java.util.List;
  5. import com.google.gson.Gson;
  6. import classes.holonControlUnit.OptimizationManager.OptimizationScheme;
  7. import classes.holonControlUnit.messages.MergeMsg;
  8. import classes.holonControlUnit.messages.Message;
  9. import classes.holonControlUnit.messages.OrderMsg;
  10. import classes.holonControlUnit.messages.StateMsg;
  11. public class TargetStateAssembler {
  12. private HolonControlUnit hcu;
  13. private float desiredPowerUsage = 100f;
  14. private OrderMsg order;
  15. private HashMap<String, OrderMsg> ordersForSubholon;
  16. public TargetStateAssembler(HolonControlUnit hcu) {
  17. this.order = null;
  18. this.hcu = hcu;
  19. this.ordersForSubholon = new HashMap<String, OrderMsg>();
  20. }
  21. public void assembleTargetState(int timeStep) {
  22. if(this.order == null || this.order.getTimeStep() != timeStep-1) {
  23. this.desiredPowerUsage = 0f;
  24. } else {
  25. this.desiredPowerUsage = this.order.getDesiredPowerUsage();
  26. }
  27. this.ordersForSubholon.clear();
  28. System.out.println(this.hcu.getHolon().getUniqueID()+" opt scheme: "+this.hcu.getOptimizer().getOptimizationScheme());
  29. //balance the sub holons
  30. switch(this.hcu.getOptimizer().getOptimizationScheme()) {
  31. case COMFORT:
  32. assembleTargetStateComfort(timeStep);
  33. break;
  34. case MIN_COST:
  35. break;
  36. case ENERGY_CONSUMPTION:
  37. break;
  38. case STABILITY:
  39. assembleTargetStateStability(timeStep);
  40. break;
  41. case RECOVERY:
  42. assembleTargetStateRecovery(timeStep);
  43. break;
  44. default:
  45. System.err.println("Unknown optimization scheme in "+this.hcu.getHolon().getUniqueID());
  46. }
  47. this.hcu.getHierarchyController().propagateMergeReqToParent(timeStep-1);
  48. //send order to subholons
  49. Gson gson = this.hcu.getCommunicator().getGson();
  50. for(String s : this.ordersForSubholon.keySet()) {
  51. if(this.hcu.getHierarchyController().getSubHolons().contains(s))
  52. this.hcu.getCommunicator().sendMsg(s, Message.Type.ORDER, gson.toJson(this.ordersForSubholon.get(s)));
  53. }
  54. }
  55. private void assembleTargetStateComfort(int timeStep) {
  56. //overall power usage inside this holarchy
  57. float powerUsage = this.hcu.getStateEstimator().getPowerUsage();
  58. ArrayList<Float> predictedPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage();
  59. if(predictedPowerUsage.size() < 1) {
  60. //no more iterations inside simulator
  61. return;
  62. }
  63. //check if this holon can run independent from parent without risking stability
  64. if(this.hcu.matchPowerRange(powerUsage, 0f, predictedPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold())
  65. && this.hcu.getHolon().getParent().canRunIndependent(this.hcu.getHolon()) && this.hcu.getHolon().getLayer() > 1) {
  66. System.out.println(this.hcu.getHolon().getUniqueID()+" can run independent");
  67. this.hcu.getHierarchyController().splitSuperHolon(timeStep);
  68. this.desiredPowerUsage = 0f;
  69. }
  70. //powerUsage already matches desired value, everything as before
  71. if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage, predictedPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold())) {
  72. System.out.println(this.hcu.getHolon().getUniqueID()+" power usage as desired "+powerUsage);
  73. HashMap<String, StateMsg> childStates = this.hcu.getStateEstimator().getChildStates();
  74. for(String s : childStates.keySet()) {
  75. OrderMsg o = new OrderMsg(childStates.get(s).getPredictedPowerUsage().get(0), null, OptimizationScheme.STABILITY, timeStep);
  76. this.ordersForSubholon.put(s, o);
  77. }
  78. return;
  79. }
  80. System.out.println(this.hcu.getHolon().getUniqueID()+" power usage "+powerUsage+" not as desired "+this.desiredPowerUsage);
  81. float requiredPower = this.desiredPowerUsage - powerUsage;
  82. //find flexibility which matches required power
  83. float savedWithFlexibilities = gothroughFlexibilities(timeStep, requiredPower, predictedPowerUsage);
  84. if(savedWithFlexibilities == requiredPower) {
  85. return;
  86. }
  87. requiredPower -= savedWithFlexibilities;
  88. //go through merge requests from last iteration
  89. float savedByMerging = gothroughMergeReq(timeStep, requiredPower, predictedPowerUsage, OptimizationScheme.COMFORT);
  90. if(savedByMerging == requiredPower) {
  91. return;
  92. }
  93. requiredPower -= savedByMerging;
  94. //look out for another superholon
  95. findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage);
  96. //tell all holons to use a little more/less energy
  97. orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower, OptimizationScheme.COMFORT);
  98. }
  99. private void assembleTargetStateStability(int timeStep) {
  100. //overall power usage inside this holarchy
  101. float powerUsage = this.hcu.getStateEstimator().getPowerUsage();
  102. ArrayList<Float> predictedPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage();
  103. if(predictedPowerUsage.size() < 1) {
  104. //no more iterations inside simulator
  105. return;
  106. }
  107. //powerUsage already matches desired value, everything as before
  108. if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage, predictedPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold())) {
  109. System.out.println(this.hcu.getHolon().getUniqueID()+" power usage as desired "+powerUsage);
  110. HashMap<String, StateMsg> childStates = this.hcu.getStateEstimator().getChildStates();
  111. for(String s : childStates.keySet()) {
  112. OrderMsg o = new OrderMsg(childStates.get(s).getPredictedPowerUsage().get(0), null, OptimizationScheme.STABILITY, timeStep);
  113. this.ordersForSubholon.put(s, o);
  114. }
  115. return;
  116. }
  117. System.out.println(this.hcu.getHolon().getUniqueID()+" power usage "+powerUsage+" not as desired "+this.desiredPowerUsage);
  118. float requiredPower = this.desiredPowerUsage - powerUsage;
  119. //find flexibility which matches required power
  120. float savedWithFlexibilities = gothroughFlexibilities(timeStep, requiredPower, predictedPowerUsage);
  121. if(savedWithFlexibilities == requiredPower) {
  122. return;
  123. }
  124. requiredPower -= savedWithFlexibilities;
  125. //go through merge requests from last iteration
  126. float savedByMerging = gothroughMergeReq(timeStep, requiredPower, predictedPowerUsage, OptimizationScheme.STABILITY);
  127. if(savedByMerging == requiredPower) {
  128. return;
  129. }
  130. requiredPower -= savedByMerging;
  131. //look out for another superholon
  132. findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage);
  133. //tell all holons to use a little more/less energy
  134. orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower, OptimizationScheme.STABILITY);
  135. }
  136. private void assembleTargetStateRecovery(int timeStep) {
  137. //overall power usage inside this holarchy
  138. float powerUsage = this.hcu.getStateEstimator().getPowerUsage();
  139. ArrayList<Float> predictedPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage();
  140. if(predictedPowerUsage.size() < 1) {
  141. //no more iterations inside simulator
  142. return;
  143. }
  144. //powerUsage already matches desired value, everything as before
  145. if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage, predictedPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold())) {
  146. System.out.println(this.hcu.getHolon().getUniqueID()+" power usage as desired "+powerUsage);
  147. HashMap<String, StateMsg> childStates = this.hcu.getStateEstimator().getChildStates();
  148. for(String s : childStates.keySet()) {
  149. OrderMsg o = new OrderMsg(childStates.get(s).getPredictedPowerUsage().get(0), null, OptimizationScheme.STABILITY, timeStep);
  150. this.ordersForSubholon.put(s, o);
  151. }
  152. return;
  153. }
  154. System.out.println(this.hcu.getHolon().getUniqueID()+" power usage "+powerUsage+" not as desired "+this.desiredPowerUsage);
  155. float requiredPower = this.desiredPowerUsage - powerUsage;
  156. //find flexibility which matches required power
  157. float savedWithFlexibilities = gothroughFlexibilities(timeStep, requiredPower, predictedPowerUsage);
  158. if(savedWithFlexibilities == requiredPower) {
  159. return;
  160. }
  161. requiredPower -= savedWithFlexibilities;
  162. //go through merge requests from last iteration
  163. float savedByMerging = gothroughMergeReq(timeStep, requiredPower, predictedPowerUsage, OptimizationScheme.RECOVERY);
  164. if(savedByMerging == requiredPower) {
  165. return;
  166. }
  167. requiredPower -= savedByMerging;
  168. float p = this.hcu.getHolon().isPhysical ? this.hcu.getHolon().getHolonObject().getEnergyAtTimeStepFlex(timeStep) : 0f;
  169. requiredPower = this.desiredPowerUsage - p;
  170. //split dysfunctional parts
  171. HashMap<String, StateMsg> childStates = this.hcu.getStateEstimator().getChildStates();
  172. List<List<String>> childPerm = getAllPermutations(List.copyOf(childStates.keySet()));
  173. HashMap<Float, List<String>> potChild = new HashMap<Float, List<String>>();
  174. for(List<String> l : childPerm) {
  175. //check how much power this subset of child would consume
  176. float pu = p;
  177. for(String s : l) {
  178. if(Math.abs(pu) > Math.abs(requiredPower))
  179. break;
  180. pu += childStates.get(s).getPowerUsage();
  181. }
  182. if(Math.abs(pu) <= Math.abs(requiredPower)) {
  183. if(potChild.containsKey(pu) && potChild.get(pu).size() >= l.size())
  184. continue;
  185. potChild.put(pu, l);
  186. }
  187. }
  188. //find subset of children with most fitting powerUsage
  189. float max = 0f;
  190. for(float f : potChild.keySet()) {
  191. if(Math.abs(f) > Math.abs(max)) {
  192. max = f;
  193. }
  194. }
  195. //split all other subholons
  196. List<String> list = new ArrayList<String>();
  197. if(potChild.containsKey(max)) {
  198. list = potChild.get(max);
  199. }
  200. List<String> subs = List.copyOf(this.hcu.getHierarchyController().getSubHolons());
  201. for(String s : subs) {
  202. if(!list.contains(s)) {
  203. this.hcu.getHierarchyController().splitSubHolon(s, timeStep);
  204. }
  205. }
  206. requiredPower -= max;
  207. if(requiredPower == 0) {
  208. return;
  209. }
  210. //Split from superholon?
  211. if(Math.abs(requiredPower) > Math.abs(p) && this.hcu.getHolon().getLayer() > 1) {
  212. this.hcu.getHierarchyController().splitSuperHolon(timeStep);
  213. return;
  214. }
  215. //look out for another superholon
  216. findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage);
  217. //tell all holons to use a little more/less energy
  218. orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower, OptimizationScheme.RECOVERY);
  219. }
  220. private float gothroughFlexibilities(int timeStep, float requiredPower, ArrayList<Float> predictedPowerUsage) {
  221. return this.hcu.getFlexMan().applyFlexibilities(requiredPower, predictedPowerUsage, timeStep);
  222. }
  223. /**
  224. * go through all previously received merge requests from other holons
  225. * if there is a fitting one merge
  226. * @param timeStep
  227. * @param requiredPower
  228. * @return saved power
  229. */
  230. private float gothroughMergeReq(int timeStep, float requiredPower, ArrayList<Float> predictedPowerUsage,
  231. OptimizationScheme optScheme) {
  232. List<MergeMsg> requests = this.hcu.getHierarchyController().getMergeRequestsForTimeStep(timeStep-1);
  233. if(requests == null)
  234. return 0f;
  235. //store holon which would help decrease |requiredPower|
  236. ArrayList<MergeMsg> poten = new ArrayList<MergeMsg>();
  237. //find a perfect match or holon which would help decrease |requiredPower|
  238. for(MergeMsg req : requests) {
  239. float r = req.getPredictedPowerUsage().get(0); //since merge req is from timeStep-1
  240. String requester = req.getRequester();
  241. float newThroughput = req.getNetThroughput() + this.hcu.getStateEstimator().getNetThroughput();
  242. if(!this.hcu.getHierarchyController().canMerge(requester, newThroughput)) {
  243. //cannot merge with the requester
  244. continue;
  245. }
  246. if(this.hcu.matchPowerRange(r, requiredPower, predictedPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold())) {
  247. //perfect match
  248. this.hcu.getHierarchyController().sendMergeAck(timeStep, req);
  249. OrderMsg o = new OrderMsg(r, null, optScheme, timeStep);
  250. this.ordersForSubholon.put(requester, o);
  251. requests.remove(req);
  252. return r;
  253. } else if( ((r < 0 && requiredPower < 0) || (r > 0 && requiredPower > 0))
  254. && this.hcu.decreasesPowerUsage(requiredPower, r, req.getPredictedPowerUsage())) {
  255. //accepting this request would help this holon
  256. poten.add(req);
  257. }
  258. }
  259. //go through all poten candidates and find most suiting subset
  260. //all candidates have either power < 0 or > 0
  261. if(poten.size() < 1)
  262. return 0f;
  263. List<List<MergeMsg>> potPermut = getAllPermutations(poten);
  264. HashMap<Float, List<MergeMsg>> potSavings = new HashMap<Float, List<MergeMsg>>();
  265. for(List<MergeMsg> l : potPermut) {
  266. //check how much power this subset of merges would save
  267. float saving = 0f;
  268. Float[] savings = new Float[predictedPowerUsage.size()];
  269. for(int i=0; i<savings.length; i++)
  270. savings[i] = 0f;
  271. for(MergeMsg m : l) {
  272. if(!this.hcu.decreasesPowerUsage(requiredPower, saving, List.of(savings)))
  273. break;
  274. saving += m.getPredictedPowerUsage().get(0); //since merge req is from timeStep-1
  275. for(int i=0; i<savings.length; i++) {
  276. savings[i] = savings[i] + m.getPredictedPowerUsage().get(i);
  277. }
  278. }
  279. if(this.hcu.decreasesPowerUsage(requiredPower, saving, List.of(savings))) {
  280. if(potSavings.containsKey(saving) && potSavings.get(saving).size() >= l.size())
  281. continue;
  282. potSavings.put(saving, l);
  283. }
  284. }
  285. if(potSavings.size() < 1) {
  286. return 0f;
  287. }
  288. float max = 0f;
  289. for(float f : potSavings.keySet()) {
  290. if(Math.abs(f) > Math.abs(max)) {
  291. max = f;
  292. }
  293. }
  294. //merge with all holons that are part of the subset with the max saving
  295. if(potSavings.containsKey(max)) {
  296. for(MergeMsg req : potSavings.get(max)) {
  297. float r = req.getPower();
  298. String requester = req.getRequester();
  299. this.hcu.getHierarchyController().sendMergeAck(timeStep, req);
  300. OrderMsg o = new OrderMsg(r, null, optScheme, timeStep);
  301. this.ordersForSubholon.put(requester, o);
  302. }
  303. requests.removeAll(potSavings.get(max));
  304. }
  305. return max;
  306. }
  307. private void findNewSuperHolon(int timeStep, float powerUsage, ArrayList<Float> predictedPowerUsage) {
  308. for(String physicalNeighbor : this.hcu.getHierarchyController().getPhysicalNeighborsFromOtherHolarchy()) {
  309. this.hcu.getHierarchyController().sendMergeReq(powerUsage, predictedPowerUsage, timeStep, physicalNeighbor);
  310. }
  311. }
  312. /**
  313. * compute a new target value for all subholons
  314. * "fairness": all subholons get same target value
  315. * @param timeStep
  316. * @param powerUsage
  317. * @param requiredPower
  318. * @param optScheme
  319. */
  320. private void orderSubholonsRequiredPower(int timeStep, float powerUsage, float requiredPower, OptimizationScheme optScheme) {
  321. float p = this.hcu.getHolon().isPhysical ? this.hcu.getHolon().getHolonObject().getEnergyAtTimeStep(timeStep) : 0f;
  322. requiredPower = this.desiredPowerUsage - p;
  323. HashMap<String, StateMsg> childStates = this.hcu.getStateEstimator().getChildStates();
  324. float opt = requiredPower/(childStates.size() != 0 ? childStates.size() : 1);
  325. for(String s : this.hcu.getHierarchyController().getSubHolons()) {
  326. //order for subholon
  327. if(this.ordersForSubholon.containsKey(s))
  328. continue;
  329. OrderMsg o = new OrderMsg(opt, null, optScheme, timeStep);
  330. this.ordersForSubholon.put(s, o);
  331. }
  332. }
  333. private <T> List<List<T>> getAllPermutations(List<T> set){
  334. List<List<T>> out = new ArrayList<List<T>>();
  335. for(int i=0; i<set.size(); i++) {
  336. for(int j=i; j<set.size(); j++) {
  337. List<T> l = new ArrayList<T>();
  338. l.addAll(set.subList(i, j+1));
  339. out.add(l);
  340. }
  341. }
  342. return out;
  343. }
  344. public float getDesiredPowerUsage() {
  345. return this.desiredPowerUsage;
  346. }
  347. public void setOrder(OrderMsg order, String sender) {
  348. if(sender.equals(this.hcu.getHierarchyController().getSuperHolon())) {
  349. this.order = order;
  350. }
  351. }
  352. }