package ui.controller; import classes.*; import classes.comparator.EnergyMinToMaxComparator; import classes.comparator.MinEnergyComparator; import classes.comparator.WeakestBattery; import ui.model.IntermediateCableWithState; import ui.model.DecoratedCable; import ui.model.DecoratedCable.CableState; import ui.model.DecoratedSwitch.SwitchState; import ui.model.DecoratedNetwork; import ui.model.DecoratedState; import ui.model.DecoratedSwitch; import ui.model.MinimumModel; import ui.model.MinimumNetwork; import ui.model.Model; import ui.model.Model.FairnessModel; import ui.model.VisualRepresentationalState; import ui.view.FlexiblePane; import ui.view.GUI; import ui.view.MyCanvas; import ui.view.Outliner; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.ListIterator; import javax.swing.JPanel; /** * Controller for Simulation. * * @author Gruppe14 */ public class SimulationManager { int global = 0; private Model model; private ArrayList objectsToHandle; private ArrayList subNets; private ArrayList brokenEdges; private HashMap saves = new HashMap(); private HashMap savesVisual = new HashMap(); private MyCanvas canvas; private int timeStep; private HashMap tagTable = new HashMap<>(); private FlexiblePane flexPane; private GUI gui; private HashMap flexDevicesTurnedOnThisTurn = new HashMap<>(); /** * Constructor. * * @param m * Model */ SimulationManager(Model m) { canvas = null; model = m; subNets = new ArrayList<>(); brokenEdges = new ArrayList<>(); } /** * calculates the flow of the edges and the supply for objects and consider old timesteps for burned cables. * * @param timestep * current Iteration */ void calculateStateForTimeStep(int timestep) { HashMap map = new HashMap(); if(timestep > 0 && saves.containsKey(timestep-1)) //if the state before exist { //make cable hastmap DecoratedState theStateBefore = saves.get(timestep-1); for(DecoratedCable edge : theStateBefore.getLeftOverEdges()) { map.put(edge.getModel(), edge.getState()); } } timeStep = timestep; ArrayList list = new ArrayList(); MinimumModel minimumModel = new MinimumModel(model.getObjectsOnCanvas(), model.getEdgesOnCanvas()); //set all working: for(IntermediateCableWithState cable : minimumModel.getEdgeList()) { if(map.containsKey(cable.getModel())) cable.setState(map.get(cable.getModel())); } ArrayList leftOver = new ArrayList(); boolean doAnotherLoop = true; while(doAnotherLoop) { doAnotherLoop = false; list = calculateNetworks(minimumModel, timestep, leftOver); for(MinimumNetwork net : list) { float energyOnCables = net.getHolonObjectList().stream().filter(object -> object.getEnergyAtTimeStep(timestep) > 0.0f).map(object -> object.getEnergyAtTimeStep(timestep)).reduce(0.0f, ((a,b) -> a + b)); //find the cable with the energy supplied from his two connected objects are the biggest, from all cables that the network give more energy than the cablecapacity. IntermediateCableWithState cable = net.getEdgeList().stream().filter(aCable -> energyOnCables > aCable.getModel().getCapacity()).max((lhs,rhs) -> Float.compare(lhs.getEnergyFromConnetedAtTimestep(timestep), rhs.getEnergyFromConnetedAtTimestep(timestep))).orElse(null); if(cable != null) { cable.setState(CableState.Burned); doAnotherLoop = true; } } } ArrayList decorNetworks = new ArrayList(); FairnessModel actualFairnessModel = model.getFairnessModel(); for (MinimumNetwork net : list) { decorNetworks.add(new DecoratedNetwork(net, timestep, actualFairnessModel)); } ArrayList leftOverDecoratedCables = new ArrayList(); for(IntermediateCableWithState cable: leftOver) { leftOverDecoratedCables.add(new DecoratedCable(cable.getModel(), cable.getState(), 0.0f)); } ArrayList listOfDecoratedSwitches = decorateSwitches(minimumModel, timestep); DecoratedState stateFromThisTimestep = new DecoratedState(decorNetworks, leftOverDecoratedCables, listOfDecoratedSwitches, timestep); saves.put(timestep, stateFromThisTimestep); savesVisual.put(timestep, new VisualRepresentationalState(stateFromThisTimestep, minimumModel)); canvas.repaint(); gui.updateOutliners(getActualDecorState());//saves.getOrDefault(timestep, null); } /** * Decorate a switch * @param minModel * @param iteration * @return */ public static ArrayList decorateSwitches(MinimumModel minModel, int iteration) { ArrayList aListOfDecoratedSwitches = new ArrayList(); for(HolonSwitch hSwitch: minModel.getSwitchList()) { aListOfDecoratedSwitches.add(new DecoratedSwitch(hSwitch, hSwitch.getState(iteration) ? SwitchState.Closed : SwitchState.Open)); } return aListOfDecoratedSwitches; } /** * SubFunction to calculate the Networks from the model. * @param minModel * @param Iteration * @param leftOver * @return */ ArrayList calculateNetworks(MinimumModel minModel, int Iteration, ArrayList leftOver){ //Copy minModel ObjectList ArrayList holonObjectList = new ArrayList(); for(HolonObject holonObject: minModel.getHolonObjectList()) { holonObjectList.add(holonObject); } //Copy minModelEdgeList ArrayList edgeList = new ArrayList(); for(IntermediateCableWithState cable: minModel.getEdgeList()) { edgeList.add(cable); } ArrayList listOfNetworks = new ArrayList(); while(!holonObjectList.isEmpty()) { //lookAt the first holonObject and find his neighbors HolonObject lookAtObject = holonObjectList.get(0); //delete out of list holonObjectList.remove(0); //create a new Network MinimumNetwork actualNetwork = new MinimumNetwork(new ArrayList(), new ArrayList()); actualNetwork.getHolonObjectList().add(lookAtObject); //create List of neighbors LinkedList neighbors = new LinkedList(); populateListOfNeighbors(edgeList, lookAtObject, actualNetwork, neighbors); while(!neighbors.isEmpty()) { AbstractCpsObject lookAtNeighbor = neighbors.getFirst(); if(lookAtNeighbor instanceof HolonObject) { actualNetwork.getHolonObjectList().add((HolonObject) lookAtNeighbor); holonObjectList.remove(lookAtNeighbor); } //When HolonSwitch Check if closed if(!(lookAtNeighbor instanceof HolonSwitch) || ((HolonSwitch)lookAtNeighbor).getState(Iteration)) { populateListOfNeighbors(edgeList, lookAtNeighbor, actualNetwork, neighbors); } neighbors.removeFirst(); } listOfNetworks.add(actualNetwork); } if(leftOver!= null) { leftOver.clear(); for(IntermediateCableWithState cable: edgeList) { leftOver.add(cable); } } return listOfNetworks; } /** * Adds the neighbors. * @param edgeList * @param lookAtObject * @param actualNetwork * @param neighbors */ void populateListOfNeighbors(ArrayList edgeList, AbstractCpsObject lookAtObject, MinimumNetwork actualNetwork, LinkedList neighbors) { ListIterator iter = edgeList.listIterator(); while(iter.hasNext()) { IntermediateCableWithState lookAtEdge = iter.next(); if(lookAtEdge.getState() == CableState.Working && lookAtEdge.getModel().isConnectedTo(lookAtObject)) { iter.remove(); actualNetwork.getEdgeList().add(lookAtEdge); //Add neighbar AbstractCpsObject edgeNeighbor; if(lookAtEdge.getModel().getA().equals(lookAtObject)) { edgeNeighbor = lookAtEdge.getModel().getB(); }else { edgeNeighbor = lookAtEdge.getModel().getA(); } if(!neighbors.contains(edgeNeighbor)) { neighbors.add(edgeNeighbor); } } } } /** * add all battries.getOut() from a list of battries and return them * @param aL a List of HolonBattries likely from subnet.getBatteries() * @param x TimeStep * @return * */ private float GetOutAllBatteries(ArrayList aL, int x) { float OutEnergy = 0; for(HolonBattery hB : aL) { //System.out.println("Iteration: "+ x +"OutBattery: "+ hB.getOutAtTimeStep(x-1)); OutEnergy += hB.getOutAtTimeStep(x-1); } //System.out.println("Iteration: "+ x +"GetOutAllBatteries: "+ OutEnergy); return OutEnergy; } /** * search for all flexible devices in the network and turn them on, until * energy surplus = 0 or all devices have been examined. * * This code could be compressed (cases inside over- and underproduction are * the same), but we decided that it is better readable this way * * @param subNet * the subnet * @param energySurplus * the current surplus of energy */ private void turnOnFlexibleDevices(SubNet subNet, float energySurplus, int timestep) { for (HolonObject holonOb : subNet.getObjects()) { for (HolonElement holonEl : holonOb.getElements()) { // if this element is flexible and active (can be considered for // calculations) if (holonEl.isFlexible() && holonEl.isActive()) { float energyAvailableSingle = holonEl .getEnergyAtTimeStep(timestep); float energyAvailableMultiple = energyAvailableSingle * holonEl.getAmount(); // ------------- flexible consumer / OVERPRODUCTION // ------------- if (energyAvailableMultiple < 0 && energySurplus > 0) { // if there is more wasted energy than energy that this // device can give, give all energy available if (Math.abs(energyAvailableMultiple) <= Math .abs(energySurplus)) { energySurplus += energyAvailableMultiple; // set the new energy consumption to the maximum holonEl.setEnergyPerElement(energyAvailableSingle); flexDevicesTurnedOnThisTurn.put(holonEl, energyAvailableMultiple); } // else: we just need to turn on part of the flexible // energy available else { float energyNeeded = -energySurplus; energySurplus += energyNeeded; // should give 0, but // was kept this was // for consistency // the energy needed divided through the amount of // elements holonEl.setEnergyPerElement(energyNeeded / holonEl.getAmount()); flexDevicesTurnedOnThisTurn.put(holonEl, energyNeeded); } } // ------------- flexible producer / UNDERPRODUCTION // ------------- else if (energyAvailableMultiple > 0 && energySurplus < 0) { // if there is more energy needed than this device can // give, give all the energy available if (Math.abs(energyAvailableMultiple) <= Math .abs(energySurplus)) { energySurplus += energyAvailableMultiple; // set the new energy consumption to the maximum holonEl.setEnergyPerElement(energyAvailableSingle); flexDevicesTurnedOnThisTurn.put(holonEl, energyAvailableMultiple); } // else: we just need to turn on part of the flexible // energy available else { float energyNeeded = -energySurplus; int i = 0; energySurplus += energyNeeded; // should give 0, but // was kept this was // for consistency // the energy needed divided through the amount of // elements holonEl.setEnergyPerElement(energyNeeded / holonEl.getAmount()); flexDevicesTurnedOnThisTurn.put(holonEl, energyNeeded); } } } if (energySurplus == 0) { break; } } if (energySurplus == 0) { break; } } } /** * Set Flow Simulation. * * @param sN * Subnet */ /** * Set the Pseudo Tags. * * @param nodes * Array of AbstractCpsObjects */ private void setPseudoTags(ArrayList nodes, ArrayList edges) { for (AbstractCpsObject node : nodes) { node.recalculateTags(); node.setPseudoTags(new ArrayList<>()); } for (CpsEdge edge : edges) { edge.recalculateTags(); edge.setPseudoTag(new ArrayList<>()); } } /** * copies the data of an array of Objects. * * @param toCopy * the ArrayList of CpsObjects co Copy */ private void copyObjects(ArrayList toCopy) { for (AbstractCpsObject cps : toCopy) { if (cps instanceof CpsUpperNode) { copyObjects(((CpsUpperNode) cps).getNodes()); } else { objectsToHandle.add(cps); } } } /** * Set the Canvas. * * @param can * the Canvas */ public void setCanvas(MyCanvas can) { canvas = can; } /** * Should be a better way to update the canvas -.- * @param can */ public void updateCanvas() { canvas.repaint(); } /** * Reset all Data to the current state of the Model. */ public void reset() { objectsToHandle = new ArrayList<>(); copyObjects(model.getObjectsOnCanvas()); flexDevicesTurnedOnThisTurn = new HashMap<>(); } /** * Get all Subnets.Not functional. * * @return all Subnets */ @Deprecated public ArrayList getSubNets() { return subNets; } /** * Get broken Edges */ // public ArrayList getBrokenEdges() { // return brokenEdges; // } public FlexiblePane getFlexiblePane() { return flexPane; } void setFlexiblePane(FlexiblePane fp) { flexPane = fp; } public DecoratedState getActualDecorStateWithOffSet(int offSet) { return getDecorState(timeStep + offSet); } public DecoratedState getActualDecorState() { return getDecorState(timeStep); } public VisualRepresentationalState getActualVisualRepresentationalState(){ return savesVisual.getOrDefault(timeStep, null); } public DecoratedState getDecorState(int timestep) { return saves.getOrDefault(timestep, null); } public void setGui(GUI gui) { this.gui = gui; } public HashMap getSavesVisual() { return savesVisual; } }