NetworkConnectivityTest.java
/**
* Copyright (c) 2021, 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.openloadflow.graph;
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.Network;
import com.powsybl.openloadflow.network.*;
import com.powsybl.openloadflow.network.impl.Networks;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* @author Ga��l Macherel {@literal <gael.macherel at artelys.com>}
* @author Florian Dupuy {@literal <florian.dupuy at rte-france.com>}
*/
class NetworkConnectivityTest {
private LfNetwork lfNetwork;
@BeforeEach
void setup() {
Network network = ConnectedComponentNetworkFactory.createThreeCcLinkedByASingleBus();
List<LfNetwork> lfNetworks = Networks.load(network, new FirstSlackBusSelector());
lfNetwork = lfNetworks.get(0);
}
@Test
void testConnectivity() {
testConnectivity(new NaiveGraphConnectivity<>(LfBus::getNum));
testConnectivity(new EvenShiloachGraphDecrementalConnectivity<>());
}
@Test
void testReducedMainComponent() {
// Testing the connectivity when the main component is suffering cuts so that it becomes smaller than a newly
// created connected component.
testReducedMainComponent(new NaiveGraphConnectivity<>(LfBus::getNum));
testReducedMainComponent(new EvenShiloachGraphDecrementalConnectivity<>());
}
@Test
void testReadEdge() {
// Testing cutting an edge then adding it back
testReaddEdge(new NaiveGraphConnectivity<>(LfBus::getNum), true);
testReaddEdge(new EvenShiloachGraphDecrementalConnectivity<>(), false);
testReaddEdge(new MinimumSpanningTreeGraphConnectivity<>(), true);
}
@Test
void testNonConnected() {
// Testing with a non-connected graph
GraphConnectivity<LfBus, LfBranch> connectivity = new EvenShiloachGraphDecrementalConnectivity<>();
for (LfBus lfBus : lfNetwork.getBuses()) {
connectivity.addVertex(lfBus);
}
for (LfBranch lfBranch : lfNetwork.getBranches()) {
if (!lfBranch.getId().equals("l48")) {
connectivity.addEdge(lfBranch.getBus1(), lfBranch.getBus2(), lfBranch);
}
}
PowsyblException e = assertThrows(PowsyblException.class, connectivity::startTemporaryChanges);
assertEquals("This implementation does not support saving a graph with several connected components", e.getMessage());
}
@Test
void testNonConnectedComponents() {
testNonConnectedComponents(new NaiveGraphConnectivity<>(LfBus::getNum));
testNonConnectedComponents(new EvenShiloachGraphDecrementalConnectivity<>());
testNonConnectedComponents(new MinimumSpanningTreeGraphConnectivity<>());
}
@Test
void testConnectedComponents() {
testConnectedComponents(new NaiveGraphConnectivity<>(LfBus::getNum));
testConnectedComponents(new EvenShiloachGraphDecrementalConnectivity<>());
testConnectedComponents(new MinimumSpanningTreeGraphConnectivity<>());
}
private void testConnectivity(GraphConnectivity<LfBus, LfBranch> connectivity) {
updateConnectivity(connectivity);
cutBranches(connectivity, "l34", "l48");
assertEquals(1, connectivity.getComponentNumber(lfNetwork.getBusById("b3_vl_0")));
assertEquals(0, connectivity.getComponentNumber(lfNetwork.getBusById("b4_vl_0")));
assertEquals(2, connectivity.getComponentNumber(lfNetwork.getBusById("b8_vl_0")));
assertEquals(3, connectivity.getNbConnectedComponents());
IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> connectivity.getComponentNumber(null));
assertEquals("given vertex null is not in the graph", e.getMessage());
}
private void testReducedMainComponent(GraphConnectivity<LfBus, LfBranch> connectivity) {
updateConnectivity(connectivity);
cutBranches(connectivity, "l34", "l48", "l56", "l57", "l67");
assertEquals(0, connectivity.getComponentNumber(lfNetwork.getBusById("b3_vl_0")));
assertEquals(2, connectivity.getComponentNumber(lfNetwork.getBusById("b4_vl_0")));
assertEquals(1, connectivity.getComponentNumber(lfNetwork.getBusById("b8_vl_0")));
assertEquals(5, connectivity.getNbConnectedComponents());
}
private void testReaddEdge(GraphConnectivity<LfBus, LfBranch> connectivity, boolean supported) {
updateConnectivity(connectivity);
String branchId = "l34";
LfBranch lfBranch = lfNetwork.getBranchById(branchId);
cutBranches(connectivity, branchId);
assertEquals(2, connectivity.getNbConnectedComponents());
assertEquals(1, connectivity.getComponentNumber(lfNetwork.getBusById("b1_vl_0")));
assertEquals(0, connectivity.getComponentNumber(lfNetwork.getBusById("b8_vl_0")));
LfBus bus1 = lfBranch.getBus1();
LfBus bus2 = lfBranch.getBus2();
if (supported) {
connectivity.addEdge(bus1, bus2, lfBranch);
assertEquals(1, connectivity.getNbConnectedComponents());
assertEquals(0, connectivity.getComponentNumber(lfNetwork.getBusById("b1_vl_0")));
assertEquals(0, connectivity.getComponentNumber(lfNetwork.getBusById("b8_vl_0")));
cutBranches(connectivity, "l48");
assertEquals(2, connectivity.getNbConnectedComponents());
assertEquals(0, connectivity.getComponentNumber(lfNetwork.getBusById("b4_vl_0")));
assertEquals(1, connectivity.getComponentNumber(lfNetwork.getBusById("b8_vl_0")));
} else {
PowsyblException e = assertThrows(PowsyblException.class, () -> connectivity.addEdge(bus1, bus2, lfBranch));
assertEquals("This implementation does not support incremental connectivity: edges cannot be added once that connectivity is saved", e.getMessage());
}
}
private void testNonConnectedComponents(AbstractGraphConnectivity<LfBus, LfBranch> connectivity) {
updateConnectivity(connectivity);
cutBranches(connectivity, "l34", "l48");
assertEquals(createVerticesSet("b4_vl_0", "b5_vl_0", "b6_vl_0", "b7_vl_0", "b8_vl_0", "b9_vl_0", "b10_vl_0"),
connectivity.getNonConnectedVertices(lfNetwork.getBusById("b3_vl_0")));
assertEquals(createVerticesSet("b1_vl_0", "b2_vl_0", "b3_vl_0", "b8_vl_0", "b9_vl_0", "b10_vl_0"),
connectivity.getNonConnectedVertices(lfNetwork.getBusById("b6_vl_0")));
assertEquals(createVerticesSet("b4_vl_0", "b5_vl_0", "b6_vl_0", "b7_vl_0", "b1_vl_0", "b2_vl_0", "b3_vl_0"),
connectivity.getNonConnectedVertices(lfNetwork.getBusById("b10_vl_0")));
IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> connectivity.getNonConnectedVertices(null));
assertEquals("given vertex null is not in the graph", e.getMessage());
}
private void testConnectedComponents(GraphConnectivity<LfBus, LfBranch> connectivity) {
updateConnectivity(connectivity);
cutBranches(connectivity, "l34", "l56", "l57");
assertEquals(createVerticesSet("b1_vl_0", "b2_vl_0", "b3_vl_0"),
connectivity.getConnectedComponent(lfNetwork.getBusById("b3_vl_0")));
assertEquals(createVerticesSet("b6_vl_0", "b7_vl_0"),
connectivity.getConnectedComponent(lfNetwork.getBusById("b6_vl_0")));
assertEquals(createVerticesSet("b4_vl_0", "b5_vl_0", "b8_vl_0", "b9_vl_0", "b10_vl_0"),
connectivity.getConnectedComponent(lfNetwork.getBusById("b10_vl_0")));
IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> connectivity.getConnectedComponent(null));
assertEquals("given vertex null is not in the graph", e.getMessage());
}
private void cutBranches(GraphConnectivity<LfBus, LfBranch> connectivity, String... branches) {
connectivity.startTemporaryChanges();
Arrays.stream(branches).map(lfNetwork::getBranchById).forEach(connectivity::removeEdge);
}
private void updateConnectivity(GraphConnectivity<LfBus, LfBranch> connectivity) {
for (LfBus lfBus : lfNetwork.getBuses()) {
connectivity.addVertex(lfBus);
}
for (LfBranch lfBranch : lfNetwork.getBranches()) {
connectivity.addEdge(lfBranch.getBus1(), lfBranch.getBus2(), lfBranch);
}
}
private Set<LfBus> createVerticesSet(String... busIds) {
return Arrays.stream(busIds).map(lfNetwork::getBusById).collect(Collectors.toSet());
}
}