Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 181 additions & 5 deletions src/arcade/core/util/Graph.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ public enum Strategy {
/** Collection of all {@code Edge} objects in a graph. */
private final Bag allEdges;

/** Map of {@code Node} objects, for lookup. */
private final Map<String, Node> nodes;

/** Map of {@code Node} OUT to bag of {@code Edge} objects. */
private final Map<Node, Bag> nodeToOutBag;

Expand All @@ -42,6 +45,7 @@ public Graph() {
allEdges = new Bag();
nodeToOutBag = new HashMap<>();
nodeToInBag = new HashMap<>();
nodes = new HashMap<>();
}

/**
Expand All @@ -53,13 +57,55 @@ public void update(Graph graph) {
allEdges.addAll(graph.allEdges);
nodeToOutBag.putAll(graph.nodeToOutBag);
nodeToInBag.putAll(graph.nodeToInBag);
updateNodes();
}

/** Updates nodes from graph. */
private void updateNodes() {
nodes.clear();
for (Object obj : allEdges) {
Edge edge = (Edge) obj;
Node from = edge.getFrom();
Node to = edge.getTo();

if (!nodes.containsKey(from.toString())) {
nodes.put(from.toString(), from);
}
if (!nodes.containsKey(to.toString())) {
nodes.put(to.toString(), to);
}
}
}

/**
* Replaces this graph with the combined contents of two graphs.
*
* <p>All existing edges are removed and the edges from {@code graph1} and {@code graph2} are
* copied into this graph. This method should be used after node references have been merged or
* reconciled between the two graphs, producing a single graph containing the same edge objects
* of both inputs.
*
* @param graph1 the first graph to combine
* @param graph2 the second graph to combine
*/
public void combine(Graph graph1, Graph graph2) {
clear();
for (Object obj : graph2.getAllEdges()) {
Edge edge = (Edge) obj;
addEdge(edge);
}
for (Object obj : graph1.getAllEdges()) {
Edge edge = (Edge) obj;
addEdge(edge);
}
}

/** Clear edges and nodes from graph. */
public void clear() {
allEdges.clear();
nodeToOutBag.clear();
nodeToInBag.clear();
nodes.clear();
}

/**
Expand Down Expand Up @@ -91,6 +137,28 @@ public boolean contains(Edge edge) {
return checkEdge(edge);
}

/**
* Retrieve the node object for the given coordinates. Returns null if no node exists.
*
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
* @return the node object
*/
public Node lookup(int x, int y, int z) {
return nodes.get("(" + x + "," + y + "," + z + ")");
}

/**
* Retrieve the node object for the given coordinates. Returns null if no node exists.
*
* @param node to lookup an original node
* @return the node object
*/
public Node lookup(Node node) {
return nodes.get(node.toString());
}

/**
* Gets all edges in the graph.
*
Expand Down Expand Up @@ -206,6 +274,7 @@ public void getSubgraph(Graph g, GraphFilter f) {
for (Object obj : allEdges) {
Edge edge = (Edge) obj;
if (f.filter(edge)) {
g.addNodes(edge);
g.allEdges.add(edge);
g.setOutMap(edge.getFrom(), edge);
g.setInMap(edge.getTo(), edge);
Expand Down Expand Up @@ -255,6 +324,8 @@ public void mergeNodes() {
e.setTo(join);
}
}

nodes.put(join.toString(), join);
}
}

Expand All @@ -269,19 +340,56 @@ public void addEdge(Node from, Node to) {
}

/**
* Adds edge to graph.
* Adds edge to graph. Default behavior is to duplicate nodes.
*
* @param edge the edge to add
*/
public void addEdge(Edge edge) {
addNodes(edge);
allEdges.add(edge);
setOutMap(edge.getFrom(), edge);
setInMap(edge.getTo(), edge);
setLinks(edge);
}

/**
* Adds the edge to the bag for the mapping of OUT node to edge.
* Adds edge to graph.
*
* @param edge the edge to add
* @param duplicate {@code true} if desired behavior is to duplicate nodes, {@code false}
* otherwise
*/
public void addEdge(Edge edge, boolean duplicate) {
allEdges.add(edge);
setOutMap(edge.getFrom(), edge, duplicate);
setInMap(edge.getTo(), edge, duplicate);
setLinks(edge);
addNodes(edge);
}

/**
* Helper function to adds the nodes from an edge to a graph.
*
* @param edge the edge to add
*/
private void addNodes(Edge edge) {
Node from = edge.getFrom();
Node to = edge.getTo();
if (!nodes.containsKey(from.toString())) {
nodes.put(from.toString(), from);
} else {
edge.setFrom(nodes.get(from.toString()));
}
if (!nodes.containsKey(to.toString())) {
nodes.put(to.toString(), to);
} else {
edge.setTo(nodes.get(to.toString()));
}
}

/**
* Adds the edge to the bag for the mapping of OUT node to edge. Default behavior is to
* duplicate nodes.
*
* @param node the node hash
* @param edge the edge
Expand All @@ -296,7 +404,27 @@ private void setOutMap(Node node, Edge edge) {
}

/**
* Adds the edge to the bag for the mapping of IN node to edge.
* Adds the edge to the bag for the mapping of OUT node to edge. Used in cases new node object
* is not needed.
*
* @param node the node hash
* @param edge the edge
* @param duplicate {@code true} if desired behavior is to duplicate nodes, {@code false}
* otherwise
*/
private void setOutMap(Node node, Edge edge, boolean duplicate) {
Bag objs = nodeToOutBag.get(node);
if (objs == null) {
objs = new Bag(10);
Node bagNode = duplicate ? node.duplicate() : node;
nodeToOutBag.put(bagNode, objs);
}
objs.add(edge);
}

/**
* Adds the edge to the bag for the mapping of IN node to edge. Default behavior is to duplicate
* nodes.
*
* @param node the node hash
* @param edge the edge
Expand All @@ -310,6 +438,25 @@ private void setInMap(Node node, Edge edge) {
objs.add(edge);
}

/**
* Adds the edge to the bag for the mapping of OUT node to edge. Used in cases new node object
* is not needed.
*
* @param node the node hash
* @param edge the edge
* @param duplicate {@code true} if desired behavior is to duplicate nodes, {@code false}
* otherwise
*/
private void setInMap(Node node, Edge edge, boolean duplicate) {
Bag objs = nodeToInBag.get(node);
if (objs == null) {
objs = new Bag(10);
Node bagNode = duplicate ? node.duplicate() : node;
nodeToInBag.put(bagNode, objs);
}
objs.add(edge);
}

/**
* Adds links between edges in and out of the nodes for a given edge.
*
Expand Down Expand Up @@ -353,6 +500,19 @@ public void removeEdge(Edge edge) {
unsetOutMap(edge.getFrom(), edge);
unsetInMap(edge.getTo(), edge);
unsetLinks(edge);
removeNodeIfDetached(edge.getFrom());
removeNodeIfDetached(edge.getTo());
}

/**
* Remove a node if it is detached from the graph.
*
* @param node the node to check
*/
private void removeNodeIfDetached(Node node) {
if (!nodeToInBag.containsKey(node) && !nodeToOutBag.containsKey(node)) {
nodes.remove(node.toString());
}
}

/**
Expand Down Expand Up @@ -730,7 +890,8 @@ public static class Edge {
private final ArrayList<Edge> edgesOut;

/**
* Creates an {@code Edge} between two {@link Node} objects.
* Creates an {@code Edge} between two {@link Node} objects. Default behavior is to
* duplicate nodes.
*
* @param from the node the edge is from
* @param to the node the edge is to
Expand All @@ -742,6 +903,21 @@ public Edge(Node from, Node to) {
edgesOut = new ArrayList<>();
}

/**
* Creates an {@code Edge} object for graph sites. Used in cases where a new node object is
* not needed.
*
* @param from the node the edge is from
* @param to the node the edge is to
* @param duplicate {@code true} if nodes should be duplicated, {@code false} otherwise
*/
public Edge(Node from, Node to, boolean duplicate) {
this.from = duplicate ? from.duplicate() : from;
this.to = duplicate ? to.duplicate() : to;
edgesIn = new ArrayList<>();
edgesOut = new ArrayList<>();
}

/**
* Gets the node the edge points to based on the calculation strategy (e.g. upstream or
* downstream).
Expand Down Expand Up @@ -822,7 +998,7 @@ public ArrayList<Edge> getEdgesOut() {
*
* @return the reversed edge
*/
Edge reverse() {
public Edge reverse() {
Node tempTo = to;
Node tempFrom = from;
to = tempFrom;
Expand Down
12 changes: 4 additions & 8 deletions src/arcade/patch/env/component/PatchComponentRemodel.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import static arcade.patch.env.component.PatchComponentSitesGraphUtilities.MAXIMUM_WALL_RADIUS_FRACTION;
import static arcade.patch.env.component.PatchComponentSitesGraphUtilities.MINIMUM_CAPILLARY_RADIUS;
import static arcade.patch.env.component.PatchComponentSitesGraphUtilities.MINIMUM_WALL_THICKNESS;
import static arcade.patch.env.component.PatchComponentSitesGraphUtilities.calculateCurrentState;
import static arcade.patch.env.component.PatchComponentSitesGraphUtilities.updateGraph;
import static arcade.patch.util.PatchEnums.Ordering;

/**
Expand Down Expand Up @@ -175,15 +177,9 @@ public void step(SimState state) {
// If any edges are removed, update the graph edges that are ignored.
// Otherwise, recalculate pressure, flow, and stresses.
if (removed) {
PatchComponentSitesGraphUtilities.updateGraph(graph);
updateGraph(graph);
} else {
PatchComponentSitesGraphUtilities.calculatePressures(graph);
boolean reversed = PatchComponentSitesGraphUtilities.reversePressures(graph);
if (reversed) {
PatchComponentSitesGraphUtilities.calculatePressures(graph);
}
PatchComponentSitesGraphUtilities.calculateFlows(graph);
PatchComponentSitesGraphUtilities.calculateStresses(graph);
calculateCurrentState(graph);
}
}

Expand Down
Loading
Loading