package ui.controller; import classes.*; import ui.model.Model; import ui.view.FlexiblePane; import ui.view.MyCanvas; import java.util.ArrayList; import java.util.HashMap; /** * Controller for Simulation. * * @author Gruppe14 */ public class SimulationManager { private Model model; private ArrayList objectsToHandle; // private ArrayList allConnections; private ArrayList subNets; private ArrayList brokenEdges; private MyCanvas canvas; private int timeStep; private HashMap tagTable = new HashMap<>(); private FlexiblePane flexPane; /** * Constructor. * * @param m Model */ public SimulationManager(Model m) { canvas = null; model = m; subNets = new ArrayList<>(); brokenEdges = new ArrayList<>(); } /** * calculates the flow of the edges and the supply for objects. * * @param x current Iteration */ public void calculateStateForTimeStep(int x) { reset(); timeStep = x; searchForSubNets(); for (SubNet singleSubNet : subNets) { resetConnections(singleSubNet.getObjects().get(0), new ArrayList<>(), new ArrayList<>()); } for (SubNet singleSubNet : subNets) { float production = calculateEnergy("prod", singleSubNet, timeStep); float consumption = calculateEnergy("cons", singleSubNet, timeStep); float wastedEnergy = production - consumption; float minConsumption = calculateMinimumEnergy(singleSubNet, timeStep); setFlowSimulation(singleSubNet); for (HolonObject hl : singleSubNet.getObjects()) { if (!(hl.getState() == 0) && !(hl.getState() == 3)) { for (int i = 0; i < hl.getConnections().size(); i++) { CpsEdge edge = hl.getConnectedTo().get(i); if (edge.isWorking() && edge.getFlow() > 0 || edge.getCapacity() == CpsEdge.CAPACITY_INFINITE) { // 0 = no energy, 1 = not supplied, 2 = supplied, 3 // = producer, 4 = partially supplied if ((production + consumption) >= 0) { hl.setState(HolonObject.SUPPLIED); } if ((production + consumption) < 0) { if ((production + minConsumption) >= 0) { hl.setState(HolonObject.PARTIALLY_SUPPLIED); } else if (hl.checkIfPartiallySupplied(timeStep)) { hl.setState(HolonObject.PARTIALLY_SUPPLIED); } else { hl.setState(HolonObject.NOT_SUPPLIED); } } break; } hl.setState(HolonObject.NOT_SUPPLIED); } if (hl.checkIfPartiallySupplied(timeStep) && !(hl.getState() == 2)) { hl.setState(HolonObject.PARTIALLY_SUPPLIED); } } } } canvas.repaint(); // printNetToConsole(); flexPane.recalculate(); } /** * Set Flow Simulation. * * @param sN Subnet */ public void setFlowSimulation(SubNet sN) { ArrayList producers = new ArrayList<>(); AbstractCpsObject tmp = null; tagTable = new HashMap<>(); // traverse all objects in this subnet for (HolonObject hl : sN.getObjects()) { float energy = hl.getCurrentEnergyAtTimeStep(timeStep); // if their production is higher than their consumption if (energy > 0) { tagTable.put(hl.getId(), energy); hl.addTag(hl.getId()); for (CpsEdge edge : hl.getConnections()) { if (edge.isWorking()) { // set other end of edge as tmp-object // and add this end to the other end's tag-list AbstractCpsObject a = edge.getA(); AbstractCpsObject b = edge.getB(); if (a.getId() == hl.getId()) { b.addTag(hl.getId()); tmp = b; } if (b.getId() == hl.getId()) { a.addTag(hl.getId()); tmp = a; } edge.setFlow(edge.getFlow() + energy); edge.calculateState(); edge.addTag(hl.getId()); if (edge.isWorking() && !producers.contains(tmp)) { if (tmp instanceof HolonSwitch) { if (((HolonSwitch) tmp).getState(timeStep)) { producers.add(tmp); } } else if (!(tmp instanceof CpsUpperNode)) { producers.add(tmp); } } } } } } setFlowSimRec(producers, 0); } /** * Set Flow Simulation Rec. * * @param nodes the nodes * @param iter the Iteration */ public void setFlowSimRec(ArrayList nodes, int iter) { ArrayList newNodes = new ArrayList<>(); ArrayList changedEdges = new ArrayList<>(); AbstractCpsObject tmp; if (nodes.size() != 0) { for (AbstractCpsObject cps : nodes) { // check whether the cps is in a legit state if it is a switch if (legitState(cps)) { for (CpsEdge edge : cps.getConnections()) { // is edge working // and does the edge's tag-list not (yet) contain all tags of the cps if (edge.isWorking() && (!(edge.containsTags(edge.getTags(), cps.getTag())))) { if (edge.getA().getId() == cps.getId()) { tmp = edge.getB(); } else { tmp = edge.getA(); } for (Integer tag : cps.getTag()) { if (!(edge.getTags().contains(tag)) && !(edge.getPseudoTags().contains(tag))) { edge.setFlow(edge.getFlow() + tagTable.get(tag)); edge.addTag(tag); } } // uppernodes do not spread energy if (!(tmp instanceof CpsUpperNode)) { for (Integer tag : tmp.getTag()) { if (!(edge.getTags().contains(tag)) && tagTable.get(tag) != null && !(edge.getPseudoTags().contains(tag))) { edge.setFlow(edge.getFlow() + tagTable.get(tag)); edge.addPseudoTag(tag); changedEdges.add(edge); } } } edge.calculateState(); if (edge.isWorking() && !(tmp instanceof CpsUpperNode)) { tmp.addAllPseudoTags(cps.getTag()); if (!newNodes.contains(tmp)) { newNodes.add(tmp); } } } } } } setPseudoTags(newNodes, changedEdges); setFlowSimRec(newNodes, iter + 1); } } /** * Set the Pseudo Tags. * * @param nodes Array of AbstractCpsObjects */ public 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<>()); } } // /** // * Print the nodes. // * // * @param nodes // * Array of AbstractCpsObject // */ // public void printNodes(ArrayList nodes) { // for (AbstractCpsObject node : nodes) { // System.out.println(node.getId()); // } // } // /** // * Get String. // * // * @param tags // * the tags // * @return the String // */ // public String getString(ArrayList tags) { // String result = ""; // for (Integer i : tags) { // result = result + ", " + i; // } // return result; // } // /** // * Merge the Lists. // * // * @param a // * first liust // * @param b // * second list // * @return the Result // */ // public ArrayList mergeLists(ArrayList a, ArrayList b) { // ArrayList result = new ArrayList<>(); // for (Integer i : a) { // if (!(result.contains(i))) { // result.add(i); // } // } // for (Integer j : b) { // if (!(result.contains(j))) { // result.add(j); // } // } // return result; // } /** * Reset the Connection. * * @param cps CpsObject * @param visitedObj the visited Objects * @param visitedEdges the visited Edges */ public void resetConnections(AbstractCpsObject cps, ArrayList visitedObj, ArrayList visitedEdges) { visitedObj.add(cps.getId()); cps.resetTags(); for (CpsEdge e : cps.getConnections()) { if (!(visitedEdges.contains(e))) { e.setFlow(0); e.calculateState(); e.setTags(new ArrayList<>()); visitedEdges.add(e); if (!(visitedObj.contains(e.getA().getId()))) { resetConnections(e.getA(), visitedObj, visitedEdges); e.getA().resetTags(); } if (!(visitedObj.contains(e.getB().getId()))) { resetConnections(e.getB(), visitedObj, visitedEdges); e.getB().resetTags(); } } } } /** * calculates the energy of either all producers or consumers. * * @param type Type * @param sN Subnet * @param x Integer * @return The Energy */ public float calculateEnergy(String type, SubNet sN, int x) { float energy = 0; for (HolonObject hl : sN.getObjects()) { if (type.equals("prod")) { if (hl.getCurrentEnergyAtTimeStep(x) > 0) { energy = energy + hl.getCurrentEnergyAtTimeStep(x); hl.setState(HolonObject.PRODUCER); } } if (type.equals("cons")) { if (hl.getCurrentEnergyAtTimeStep(x) < 0) { energy = energy + hl.getCurrentEnergyAtTimeStep(x); hl.setState(HolonObject.NOT_SUPPLIED); } } if (hl.getCurrentEnergyAtTimeStep(x) == 0) { hl.setState(HolonObject.NO_ENERGY); } } return energy; } /** * Calculate the Minimum Energy. * * @param sN Subnet * @param x Integer * @return the Calculated minimum Energy */ public float calculateMinimumEnergy(SubNet sN, int x) { float min = 0; float minElement = 0; for (HolonObject hl : sN.getObjects()) { if (hl.getElements().size() > 0 && hl.getElements().get(0).getTotalEnergyAtTimeStep(x) < 0) { minElement = hl.getElements().get(0).getTotalEnergyAtTimeStep(x); } for (HolonElement he : hl.getElements()) { if (minElement < he.getTotalEnergyAtTimeStep(x) && he.getTotalEnergyAtTimeStep(x) < 0) { minElement = he.getTotalEnergyAtTimeStep(x); } } min = min + minElement; } return min; } /** * generates all subNets from all objectsToHandle. */ public void searchForSubNets() { subNets = new ArrayList<>(); brokenEdges.clear(); boolean end = false; int i = 0; AbstractCpsObject cps; if (objectsToHandle.size() > 0) { while (!end) { cps = objectsToHandle.get(i); SubNet singleSubNet = new SubNet(new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); singleSubNet = buildSubNet(cps, new ArrayList<>(), singleSubNet); if (singleSubNet.getObjects().size() != 0) { subNets.add(singleSubNet); } if (0 == objectsToHandle.size()) { end = true; } } } } /** * recursivly generates a subnet of all objects, that one specific object is * connected to. * * @param cps AbstractCpsObject * @param visited visited Array of Integer * @param sN Subnets * @return Subnet */ public SubNet buildSubNet(AbstractCpsObject cps, ArrayList visited, SubNet sN) { visited.add(cps.getId()); if (cps instanceof HolonObject) { sN.getObjects().add((HolonObject) cps); } if (cps instanceof HolonSwitch) { sN.getSwitches().add((HolonSwitch) cps); } removeFromToHandle(cps.getId()); AbstractCpsObject a; AbstractCpsObject b; for (CpsEdge edge : cps.getConnections()) { if (edge.isWorking()) { a = edge.getA(); b = edge.getB(); if (!(cps instanceof HolonSwitch)) { if (!(sN.getEdges().contains(edge))) { sN.getEdges().add(edge); } } if (cps instanceof HolonSwitch && ((HolonSwitch) cps).getState(timeStep)) { if (!(sN.getEdges().contains(edge))) { sN.getEdges().add(edge); } } if (!visited.contains(a.getId()) && legitState(cps) && !(a instanceof CpsUpperNode)) { sN = buildSubNet(a, visited, sN); } if (!visited.contains(b.getId()) && legitState(cps) && !(b instanceof CpsUpperNode)) { sN = buildSubNet(b, visited, sN); } if (a instanceof CpsUpperNode && a.getId() != cps.getId()) { edge.setConnected(CpsEdge.CON_UPPER_NODE_NOT_INSIDE); checkForConnectedStates(b, (CpsUpperNode) a, edge); } if (b instanceof CpsUpperNode && b.getId() != cps.getId()) { edge.setConnected(CpsEdge.CON_UPPER_NODE_NOT_INSIDE); checkForConnectedStates(a, (CpsUpperNode) b, edge); } } else { brokenEdges.add(edge); } } return sN; } /** * is the Switch in a legitimate State. * * @param current AbstractCpsObject * @return boolean */ public boolean legitState(AbstractCpsObject current) { if (current instanceof HolonSwitch) { return ((HolonSwitch) current).getState(timeStep); } return true; } /** * removes an Object that already has been handled with. * * @param id the Object ID */ public void removeFromToHandle(int id) { for (int i = 0; i < objectsToHandle.size(); i++) { if (objectsToHandle.get(i).getId() == id) { objectsToHandle.remove(i); } } } // /** // * ensures that objectsToHandle only contains HolonObjects. // */ // public void cleanObjectsToHandle() { // for (int i = 0; i < objectsToHandle.size(); i++) { // if (!(objectsToHandle.get(i) instanceof HolonObject)) { // objectsToHandle.remove(i); // } // } // } /** * copies the data of an array of Objects. * * @param toCopy the ArrayList of CpsObjects co Copy */ public void copyObjects(ArrayList toCopy) { for (AbstractCpsObject cps : toCopy) { if (cps instanceof CpsUpperNode) { copyObjects(((CpsUpperNode) cps).getNodes()); } else { objectsToHandle.add(cps); } } } /** * Prints the Components auf all subnets. */ public void printNetToConsole() { for (int i = 0; i < subNets.size(); i++) { System.out.println("SUBNET NR:" + i); System.out.println(" Objects:"); for (int j = 0; j < subNets.get(i).getObjects().size(); j++) { HolonObject hl = subNets.get(i).getObjects().get(j); System.out.println(" " + hl.getName() + " " + hl.getId()); } System.out.println(" Edges:"); for (int j = 0; j < subNets.get(i).getEdges().size(); j++) { CpsEdge edge = subNets.get(i).getEdges().get(j); System.out.println(" " + edge.getA().getName() + " connected To " + edge.getB().getName()); } System.out.println(" Switches:"); for (int j = 0; j < subNets.get(i).getSwitches().size(); j++) { HolonSwitch sw = subNets.get(i).getSwitches().get(j); System.out.println(" " + sw.getName() + " " + sw.getId() + " State:" + sw.getActiveAt()[timeStep]); } } } /** * Set the Canvas. * * @param can the Canvas */ public void setCanvas(MyCanvas can) { canvas = can; } /** * Reset all Data to the current state of the Model. */ public void reset() { objectsToHandle = new ArrayList<>(); copyObjects(model.getObjectsOnCanvas()); } /** * Resets the State of all Edges */ public void resetEdges() { for (CpsEdge e : brokenEdges) { e.setWorkingState(true); } } /** * Resets the State for the whole Simulation Model */ public void resetSimulation() { reset(); resetEdges(); } /** * Get all Subnets. * * @return all Subnets */ public ArrayList getSubNets() { return subNets; } /** * Get broken Edges */ public ArrayList getBrokenEdges() { return brokenEdges; } /** * checks whether a given object is connected to an object inside the upperNode. * if yes, the state for the edge is changed in "connected" or "not connected" * * @param cps * @param cUNode */ public void checkForConnectedStates(AbstractCpsObject cps, CpsUpperNode cUNode, CpsEdge theEdge) { AbstractCpsObject tmp; for (CpsEdge edge : cps.getConnections()) { if (edge.getA().getId() == cps.getId()) { tmp = edge.getB(); } else { tmp = edge.getA(); } if (cUNode.getNodes().contains(tmp)) { if (tmp instanceof CpsUpperNode) { checkForConnectedStates(cps, (CpsUpperNode) tmp, theEdge); } else { theEdge.setConnected(CpsEdge.CON_UPPER_NODE_AND_INSIDE); break; } } } } public FlexiblePane getFlexiblePane() { return flexPane; } public void setFlexiblePane(FlexiblePane fp) { flexPane = fp; } }