TopologyCalculation.java
/**
* Copyright (c) 2019, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.powsybl.sld.util;
import com.powsybl.sld.model.graphs.VoltageLevelGraph;
import com.powsybl.sld.model.nodes.Node;
import com.powsybl.sld.model.nodes.SwitchNode;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* Visit the graph to identifies the connected sets of nodes
*
* @author Benoit Jeanson {@literal <benoit.jeanson at rte-france.com>}
*/
public final class TopologyCalculation {
private final Predicate<Node> extremityCriteria;
public TopologyCalculation(Predicate<Node> extremityCriteria) {
this.extremityCriteria = extremityCriteria;
}
public TopologyCalculation() {
this(TopologyCalculation::isOpenSwitchNode);
}
/**
* Analyses the graph to partition it into TopologicallyConnectedNodeSets.
* @param graph the graph to be analysed
* @return a list of TopologicallyConnectedNodeSets
*/
public List<TopologicallyConnectedNodesSet> findConnectedNodeSets(VoltageLevelGraph graph) {
List<TopologicallyConnectedNodesSet> topologicallyConnectedNodesSets = new ArrayList<>();
List<Node> nodesToVisit = graph.getNodes();
Set<Node> visitedNodes = new HashSet<>();
Node node = identifyNonOpenNode(nodesToVisit);
while (node != null) {
List<Node> borderNodes = new ArrayList<>();
Set<Node> connectedNodes = getConnectedNodesWithExtremityNodes(node, borderNodes, visitedNodes);
Set<Node> borderSwitchNodes = getBorderNodes(borderNodes, connectedNodes);
topologicallyConnectedNodesSets.add(new TopologicallyConnectedNodesSet(new HashSet<>(connectedNodes), borderSwitchNodes));
connectedNodes.removeAll(borderSwitchNodes);
visitedNodes.addAll(connectedNodes); //a border switch is part of 2 connectedNodesSets
nodesToVisit.removeAll(connectedNodes);
node = identifyNonOpenNode(nodesToVisit);
}
return topologicallyConnectedNodesSets;
}
/**
* Analyses the graph to find the TopologicallyConnectedNodesSet corresponding to given predicate.
* @param graph the graph to be analysed
* @param filter the filter applied to the all TopologicallyConnectedNodesSet of the given graph
* @return a list of TopologicallyConnectedNodeSets
*/
public List<TopologicallyConnectedNodesSet> findConnectedNodeSets(VoltageLevelGraph graph, Predicate<TopologicallyConnectedNodesSet> filter) {
return findConnectedNodeSets(graph).stream().filter(filter).collect(Collectors.toList());
}
private Set<Node> getBorderNodes(List<Node> borderNodes, Set<Node> connectedNodes) {
return borderNodes.stream()
.filter(n -> isBorderNode(n, connectedNodes))
.collect(Collectors.toSet());
}
private Set<Node> getConnectedNodesWithExtremityNodes(Node node, List<Node> borderNodes, Set<Node> visitedNodes) {
return GraphTraversal
.run(node, n -> {
boolean isExtremity = extremityCriteria.test(n);
if (isExtremity) {
borderNodes.add(n);
}
return isExtremity;
}, visitedNodes);
}
private static Node identifyNonOpenNode(List<Node> remainingNodes) {
return remainingNodes.stream().filter(n -> !isOpenSwitchNode(n)).findFirst().orElse(null);
}
private static boolean isBorderNode(Node borderNode, Set<Node> connectedNodes) {
return !connectedNodes.containsAll(borderNode.getAdjacentNodes());
}
private static boolean isOpenSwitchNode(Node node) {
return node.getType() == Node.NodeType.SWITCH && ((SwitchNode) node).isOpen();
}
}