AbstractNodeBreakerInternalConnectionsTest.java
/**
* Copyright (c) 2020, 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/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.iidm.network.tck;
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.*;
import com.powsybl.math.graph.TraverseResult;
import org.junit.jupiter.api.Test;
import java.util.HashSet;
import java.util.List;
import static com.powsybl.iidm.network.VoltageLevel.NodeBreakerView.InternalConnection;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Luma Zamarre��o {@literal <zamarrenolm at aia.es>}
*/
public abstract class AbstractNodeBreakerInternalConnectionsTest {
private static final String S5_10K_V = "S5 10kV";
@Test
public void testTraversalInternalConnections() {
Network network = Network.create("testTraversalInternalConnections", "test");
InternalConnections all = new InternalConnections();
createNetwork(network, all);
VoltageLevel vl = network.getVoltageLevel(S5_10K_V);
assertEquals(10, vl.getNodeBreakerView().getInternalConnectionCount());
List<InternalConnection> internalConnections = vl.getNodeBreakerView().getInternalConnectionStream().toList();
int[][] expectedIcNodes = new int[][]{{7, 0}, {6, 3}, {4, 3}, {5, 2}, {9, 2}, {8, 1}, {1, 10}, {3, 11}, {2, 12}, {2, 13}};
for (int i = 0; i < 10; i++) {
assertEquals(expectedIcNodes[i][0], internalConnections.get(i).getNode1());
assertEquals(expectedIcNodes[i][1], internalConnections.get(i).getNode2());
}
assertEquals(List.of(0), vl.getNodeBreakerView().getNodesInternalConnectedTo(7));
assertEquals(List.of(5, 9, 12, 13), vl.getNodeBreakerView().getNodesInternalConnectedTo(2));
assertEquals(List.of(6, 4, 11), vl.getNodeBreakerView().getNodeInternalConnectedToStream(3).boxed().toList());
assertEquals(new InternalConnections().add(0, 7), findFirstInternalConnections(vl));
// Find the internal connections encountered before encountering a terminal, starting from every node
// Only internal connections connecting two nodes having both a terminal are expected to be missing
InternalConnections icConnectedToAtMostOneTerminal = findInternalConnectionsTraverseStoppingAtTerminals(vl);
InternalConnections expected = new InternalConnections();
expected.add(7, 0).add(6, 3).add(4, 3).add(5, 2).add(9, 2).add(8, 1);
assertEquals(expected, icConnectedToAtMostOneTerminal);
assertEquals(all, findInternalConnections(vl));
}
@Test
public void testRemoveInternalConnections() {
Network network = Network.create("testTraversalInternalConnections", "test");
createNetwork(network, new InternalConnections());
VoltageLevel vl = network.getVoltageLevel(S5_10K_V);
// remove an existing internal connection
assertTrue(vl.getNodeBreakerView().getInternalConnectionStream().anyMatch(ic -> ic.getNode1() == 7 && ic.getNode2() == 0));
vl.getNodeBreakerView().removeInternalConnections(7, 0);
assertTrue(vl.getNodeBreakerView().getInternalConnectionStream().noneMatch(ic -> ic.getNode1() == 7 && ic.getNode2() == 0));
// remove a non-existing internal connection
boolean thrownException = false;
try {
vl.getNodeBreakerView().removeInternalConnections(6, 0);
} catch (PowsyblException e) {
assertEquals("Internal connection not found between 6 and 0", e.getMessage());
thrownException = true;
}
assertTrue(thrownException);
// remove multiple internal connections
vl.getNodeBreakerView().newInternalConnection()
.setNode1(6)
.setNode2(3)
.add();
assertEquals(2, vl.getNodeBreakerView().getInternalConnectionStream().filter(ic -> ic.getNode1() == 6 && ic.getNode2() == 3).count());
vl.getNodeBreakerView().removeInternalConnections(6, 3);
assertTrue(vl.getNodeBreakerView().getInternalConnectionStream().noneMatch(ic -> ic.getNode1() == 6 && ic.getNode2() == 3));
}
@Test
public void testRemoveVoltageLevelWithInternalConnectionsIssue() {
Network network = Network.create("testRemoveVoltageLevelWithInternalConnectionsIssue", "test");
InternalConnections all = new InternalConnections();
createNetwork(network, all);
network.getLine("L6").remove(); // needed to be allowed to remove the voltage level
// should not throw a null pointer exception anymore
network.getVoltageLevel(S5_10K_V).remove();
assertNull(network.getVoltageLevel(S5_10K_V));
}
private void createNetwork(Network network, InternalConnections internalConnections) {
Substation s = network.newSubstation()
.setId("S5")
.setCountry(Country.FR)
.add();
VoltageLevel vl = s.newVoltageLevel()
.setId(S5_10K_V)
.setNominalV(10.0)
.setTopologyKind(TopologyKind.NODE_BREAKER)
.add();
vl.getNodeBreakerView().newBusbarSection()
.setId("NODE13")
.setNode(0)
.add();
vl.getNodeBreakerView().newBusbarSection()
.setId("NODE14")
.setNode(3)
.add();
vl.getNodeBreakerView().newBusbarSection()
.setId("NODE15")
.setNode(2)
.add();
vl.getNodeBreakerView().newBusbarSection()
.setId("NODE16")
.setNode(1)
.add();
vl.getNodeBreakerView().newSwitch()
.setId("BREAKER4")
.setNode1(4)
.setNode2(5)
.setKind(SwitchKind.BREAKER)
.add();
vl.getNodeBreakerView().newSwitch()
.setId("DISCONNECTOR7")
.setNode1(6)
.setNode2(7)
.setKind(SwitchKind.DISCONNECTOR)
.add();
vl.getNodeBreakerView().newSwitch()
.setId("DISCONNECTOR8")
.setNode1(8)
.setNode2(9)
.setKind(SwitchKind.DISCONNECTOR)
.add();
vl.newLoad()
.setId("M3")
.setNode(11)
.setP0(5)
.setQ0(3)
.add();
vl.newLoad()
.setId("M2a")
.setNode(12)
.setP0(2)
.setQ0(1)
.add();
vl.newLoad()
.setId("M2b")
.setNode(13)
.setP0(2)
.setQ0(1)
.add();
VoltageLevel.NodeBreakerView topo = vl.getNodeBreakerView();
addInternalConnection(topo, internalConnections, 7, 0);
addInternalConnection(topo, internalConnections, 6, 3);
addInternalConnection(topo, internalConnections, 4, 3);
addInternalConnection(topo, internalConnections, 5, 2);
addInternalConnection(topo, internalConnections, 9, 2);
addInternalConnection(topo, internalConnections, 8, 1);
addInternalConnection(topo, internalConnections, 1, 10);
addInternalConnection(topo, internalConnections, 3, 11);
addInternalConnection(topo, internalConnections, 2, 12);
addInternalConnection(topo, internalConnections, 2, 13);
Substation s4 = network.newSubstation()
.setId("S4")
.setCountry(Country.FR)
.add();
VoltageLevel vl2 = s4.newVoltageLevel()
.setId("S4 10kV")
.setNominalV(10.0)
.setTopologyKind(TopologyKind.NODE_BREAKER)
.add();
vl2.getNodeBreakerView().newBusbarSection()
.setId("NODE40")
.setNode(1)
.add();
network.newLine()
.setId("L6")
.setVoltageLevel1("S4 10kV")
.setNode1(0)
.setVoltageLevel2(S5_10K_V)
.setNode2(10)
.setR(0.082)
.setX(0.086)
.setG1(0)
.setB1(0)
.setG2(0)
.setB2(0)
.add();
vl2.getNodeBreakerView().newSwitch()
.setId("DISCONNECTOR1")
.setNode1(0)
.setNode2(1)
.setKind(SwitchKind.DISCONNECTOR)
.add();
}
private void addInternalConnection(
VoltageLevel.NodeBreakerView topo,
InternalConnections internalConnections,
int node1,
int node2) {
topo.newInternalConnection()
.setNode1(node1)
.setNode2(node2)
.add();
internalConnections.add(node1, node2);
}
static class InternalConnections extends HashSet<String> {
InternalConnections add(int node1, int node2) {
add(node1 + "-" + node2);
add(node2 + "-" + node1);
return this;
}
}
private InternalConnections findInternalConnectionsTraverseStoppingAtTerminals(VoltageLevel vl) {
InternalConnections cs = new InternalConnections();
VoltageLevel.NodeBreakerView topo = vl.getNodeBreakerView();
topo.traverse(topo.getNodes(), (n1, sw, n2) -> {
if (topo.getTerminal(n2) == null) {
if (sw == null) {
cs.add(n1, n2);
}
return TraverseResult.CONTINUE;
} else {
return TraverseResult.TERMINATE_PATH;
}
});
return cs;
}
private InternalConnections findInternalConnections(VoltageLevel vl) {
VoltageLevel.NodeBreakerView topo = vl.getNodeBreakerView();
InternalConnections cs = new InternalConnections();
topo.traverse(topo.getNodes(), (n1, sw, n2) -> {
if (sw == null) {
cs.add(n1, n2);
}
return TraverseResult.CONTINUE;
});
return cs;
}
private InternalConnections findFirstInternalConnections(VoltageLevel vl) {
VoltageLevel.NodeBreakerView topo = vl.getNodeBreakerView();
InternalConnections cs = new InternalConnections();
topo.traverse(topo.getNodes(), (n1, sw, n2) -> {
if (sw == null) {
cs.add(n1, n2);
return TraverseResult.TERMINATE_TRAVERSER;
}
return TraverseResult.CONTINUE;
});
return cs;
}
}