Skip to content

Commit

Permalink
Allow use of bus-breaker voltage levels (#169)
Browse files Browse the repository at this point in the history
* add exception on Three Windings Transformers and Dangling Lines

Signed-off-by: Nicolas Rol <nicolas.rol@rte-france.com>

* remove dangling lines from branches (already managed as loads) + rewrite addElementToRetainedBreakersList to manage switches from BUS_BREAKER voltage levels + remove exception + add TODO on T3T

Signed-off-by: Nicolas Rol <nicolas.rol@rte-france.com>

* test exception on T3T

Signed-off-by: Nicolas Rol <nicolas.rol@rte-france.com>

* add test on MetrixNetwork

Signed-off-by: Nicolas Rol <nicolas.rol@rte-france.com>

* switch next to dangling lines should be managed as those next to loads

Signed-off-by: Nicolas Rol <nicolas.rol@rte-france.com>

* add more test for coverage

Signed-off-by: Nicolas Rol <nicolas.rol@rte-france.com>

* remove useless comment

Signed-off-by: Nicolas Rol <nicolas.rol@rte-france.com>

* revert fixes on dangling line to do it in another PR

Signed-off-by: Nicolas Rol <nicolas.rol@rte-france.com>

---------

Signed-off-by: Nicolas Rol <nicolas.rol@rte-france.com>
Co-authored-by: jeandemanged <damien.jeandemange@artelys.com>
  • Loading branch information
rolnico and jeandemanged authored Nov 8, 2024
1 parent 0692275 commit edd3f0e
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public class MetrixNetwork {
private final Map<String, String> mappedSwitchMap = new HashMap<>();

protected MetrixNetwork(Network network) {
// TODO: switch T3T for 3xTWT in the network using a network modification
this.network = Objects.requireNonNull(network);
}

Expand Down Expand Up @@ -612,35 +613,66 @@ private void createRetainedBreakersList(Set<String> breakerList) {
private void addElementToRetainedBreakersList(Switch sw) {
String switchId = sw.getId();

VoltageLevel.NodeBreakerView nodeBreakerView = sw.getVoltageLevel().getNodeBreakerView();
Terminal terminal1 = nodeBreakerView.getTerminal1(switchId);
Terminal terminal2 = nodeBreakerView.getTerminal2(switchId);
VoltageLevel voltageLevel = sw.getVoltageLevel();

if (terminal1 == null || terminal1.getConnectable().getType() == IdentifiableType.BUSBAR_SECTION) {
terminal1 = terminal2;
if (voltageLevel.getTopologyKind() == TopologyKind.NODE_BREAKER) {
// Get the terminals on both sides of the switch
VoltageLevel.NodeBreakerView nodeBreakerView = voltageLevel.getNodeBreakerView();
Terminal terminal1 = nodeBreakerView.getTerminal1(switchId);
Terminal terminal2 = nodeBreakerView.getTerminal2(switchId);

// Check on both sides of the switch to find a connectable that is not another switch nor a bus bar section
if (isSwitchNotConnectedToOtherSwitchOrBbs(terminal1)) {
addElementToRetainedBreakersList(sw, terminal1, true);
} else if (isSwitchNotConnectedToOtherSwitchOrBbs(terminal2)) {
addElementToRetainedBreakersList(sw, terminal2, true);
} else {
// Both sides have either a switch or a bus bar section : the switch is registered by itself
addElementToRetainedBreakersList(sw, switchId, true);
}
} else if (voltageLevel.getTopologyKind() == TopologyKind.BUS_BREAKER) {
// Get the terminals on both sides of the switch
VoltageLevel.BusBreakerView busBreakerView = voltageLevel.getBusBreakerView();
List<? extends Terminal> terminalsBus1 = busBreakerView.getBus1(switchId).getConnectedTerminalStream().toList();
List<? extends Terminal> terminalsBus2 = busBreakerView.getBus2(switchId).getConnectedTerminalStream().toList();

// Check on both sides of the switch to check if there is one and only one connectable
if (terminalsBus1.size() == 1) {
addElementToRetainedBreakersList(sw, terminalsBus1.get(0), false);
} else if (terminalsBus2.size() == 1) {
addElementToRetainedBreakersList(sw, terminalsBus2.get(0), false);
} else {
addElementToRetainedBreakersList(sw, switchId, false);
}
}
}

if (terminal1 == null || terminal1.getConnectable().getType() == IdentifiableType.BUSBAR_SECTION) {
sw.setRetained(true);
mappedSwitchMap.put(switchId, switchId);
} else {
switch (terminal1.getConnectable().getType()) {
case LINE, TWO_WINDINGS_TRANSFORMER -> {
sw.setRetained(true);
mappedSwitchMap.put(switchId, terminal1.getConnectable().getId());
}
case LOAD, GENERATOR -> {
sw.setRetained(true);
mappedSwitchMap.put(switchId, switchId);
}
case DANGLING_LINE, HVDC_CONVERTER_STATION, SHUNT_COMPENSATOR, STATIC_VAR_COMPENSATOR, THREE_WINDINGS_TRANSFORMER -> {
if (LOGGER.isWarnEnabled()) {
LOGGER.warn(String.format("Unsupported connectable type (%s) for switch '%s'", terminal1.getConnectable().getType(), switchId));
}
private boolean isSwitchNotConnectedToOtherSwitchOrBbs(Terminal terminal) {
return terminal != null && terminal.getConnectable().getType() != IdentifiableType.BUSBAR_SECTION;
}

private void addElementToRetainedBreakersList(Switch sw, Terminal terminal, boolean setRetained) {
String switchId = sw.getId();
switch (terminal.getConnectable().getType()) {
// Since switches connected to lines and TWT are "replaced" by those connectables, no need to set them retained
case LINE, TWO_WINDINGS_TRANSFORMER -> addElementToRetainedBreakersList(sw, terminal.getConnectable().getId(), false);
case LOAD, GENERATOR -> addElementToRetainedBreakersList(sw, switchId, setRetained);
case DANGLING_LINE, HVDC_CONVERTER_STATION, SHUNT_COMPENSATOR, STATIC_VAR_COMPENSATOR,
THREE_WINDINGS_TRANSFORMER -> {
if (LOGGER.isWarnEnabled()) {
LOGGER.warn("Unsupported connectable type ({}) for switch '{}'", terminal.getConnectable().getType(), switchId);
}
default -> throw new PowsyblException("Unexpected connectable type : " + terminal1.getConnectable().getType());
}
default ->
throw new PowsyblException("Unexpected connectable type : " + terminal.getConnectable().getType());
}
}

private void addElementToRetainedBreakersList(Switch sw, String id, boolean setRetained) {
if (setRetained) {
sw.setRetained(true);
}
mappedSwitchMap.put(sw.getId(), id);
}

private void createOpenedBranchesList(Set<String> openedBranches) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,11 @@ private void createMetrixInputs() {

trnbgrou = metrixNetwork.getGeneratorList().size();

cqnbquad = metrixNetwork.getLineList().size() + metrixNetwork.getTwoWindingsTransformerList().size() + 3 * metrixNetwork.getThreeWindingsTransformerList().size() + metrixNetwork.getDanglingLineList().size() + metrixNetwork.getSwitchList().size();
// Quadripoles are lines, transformers and switches
cqnbquad = metrixNetwork.getLineList().size() + metrixNetwork.getTwoWindingsTransformerList().size() + 3 * metrixNetwork.getThreeWindingsTransformerList().size() + metrixNetwork.getSwitchList().size();
dtnbtrde = metrixNetwork.getPhaseTapChangerList().size();

// Loads are loads and dangling lines
ecnbcons = metrixNetwork.getLoadList().size() + metrixNetwork.getDanglingLineList().size();

dcnblies = metrixNetwork.getHvdcLineList().size();
Expand Down Expand Up @@ -391,7 +393,7 @@ private void writeBranches(boolean constantLossFactor, MetrixDie die) {

// Three Windings Transformers
metrixNetwork.getThreeWindingsTransformerList().forEach(twt -> {
throw new UnsupportedOperationException("TODO");
throw new PowsyblException("Three Windings Transformers are not yet supported in metrix");
});

// Switches
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
import com.google.common.collect.Range;
import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
import com.powsybl.commons.PowsyblException;
import com.powsybl.contingency.*;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.test.ThreeWindingsTransformerNetworkFactory;
import com.powsybl.iidm.serde.NetworkSerDe;
import com.powsybl.metrix.integration.dataGenerator.MetrixInputData;
import com.powsybl.metrix.integration.metrix.MetrixChunkParam;
Expand Down Expand Up @@ -156,6 +158,17 @@ void metrixDefaultInputTest() throws IOException {
new ByteArrayInputStream(actual.getBytes(StandardCharsets.UTF_8))));
}

@Test
void metrixInputDataWithT3TTest() throws IOException {
Network n = ThreeWindingsTransformerNetworkFactory.create();
MetrixInputData metrixInputData = new MetrixInputData(MetrixNetwork.create(n), null, new MetrixParameters());
try (StringWriter writer = new StringWriter()) {
assertThrows(PowsyblException.class,
() -> metrixInputData.writeJson(writer),
"Three Windings Transformers are not yet supported in metrix");
}
}

@Test
void metrixInputTest() throws IOException {
Network n = NetworkSerDe.read(getClass().getResourceAsStream("/simpleNetwork.xml"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import com.powsybl.contingency.Contingency;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.test.FourSubstationsNodeBreakerFactory;
import com.powsybl.iidm.serde.ExportOptions;
import com.powsybl.iidm.serde.NetworkSerDe;
import com.powsybl.metrix.integration.contingency.Probability;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -21,6 +23,8 @@
import java.util.Set;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* @author Nicolas Rol {@literal <nicolas.rol at rte-france.com>}
Expand All @@ -44,8 +48,11 @@ void testNetworkElementsLists() {
Network network = createNetwork();

// Set some switches as retained
Set<String> mappedSwitches = Set.of("S1VL2_GH2_BREAKER", "S3VL1_LINES3S4_BREAKER", "S1VL1_LD1_BREAKER");
List<Switch> switchList = mappedSwitches.stream()
Set<String> mappedSwitches = Set.of("S1VL2_GH2_BREAKER", "S3VL1_LINES3S4_BREAKER", "S1VL1_LD1_BREAKER", "S1VL3_DL_BREAKER", "S1VL2_BBS1_BBS3");

// Expected switch list in MetrixNetwork: switches next to branches (lines, two windings transformers) are not present
List<Switch> switchList = Set.of("S1VL2_GH2_BREAKER", "S1VL1_LD1_BREAKER", "S1VL2_BBS1_BBS3")
.stream()
.map(network::getSwitch).toList();

// Contingencies
Expand Down Expand Up @@ -77,13 +84,79 @@ void testNetworkElementsLists() {
assertThat(metrixNetwork.getHvdcLineList()).containsExactlyInAnyOrderElementsOf(network.getHvdcLines());
assertThat(metrixNetwork.getBusList()).containsExactlyInAnyOrderElementsOf(network.getBusBreakerView().getBuses());
assertThat(metrixNetwork.getContingencyList()).containsExactlyInAnyOrderElementsOf(List.of(a, b));

assertTrue(metrixNetwork.isMapped(network.getIdentifiable("S1VL2_GH2_BREAKER")));
assertTrue(metrixNetwork.isMapped(network.getIdentifiable("DL")));
assertTrue(metrixNetwork.isMapped(network.getIdentifiable("GH2")));
assertTrue(metrixNetwork.isMapped(network.getIdentifiable("HVDC1")));
assertTrue(metrixNetwork.isMapped(network.getIdentifiable("LINE_S2S3")));
assertTrue(metrixNetwork.isMapped(network.getIdentifiable("LD5")));
assertFalse(metrixNetwork.isMapped(network.getIdentifiable("S2VL1_BBS")));
}

@Test
void testNetworkBusBreakerElementsLists() {
// Mapped switches
Set<String> mappedSwitches = Set.of("S1VL2_GH2_BREAKER", "S3VL1_LINES3S4_BREAKER", "S1VL1_LD1_BREAKER",
"S1VL3_DL_BREAKER", "S1VL2_BBS1_BBS3", "S1VL3_3WT_BREAKER");

// Network
Network network = createBusBreakerNetwork(mappedSwitches);

// Expected switch list in MetrixNetwork: switches next to branches (lines, two windings transformers) are not present
List<Switch> switchList = mappedSwitches.stream().map(network::getSwitch).toList();

// Contingencies
Contingency a = new Contingency("a", Collections.singletonList(new BranchContingency("LINE_S2S3")));
Contingency b = new Contingency("b", Arrays.asList(
new BranchContingency("LINE_S2S3"),
new BranchContingency("LINE_S3S4")));

// Create a contingency provider
ContingenciesProvider contingenciesProvider = networkLocal -> {
a.addExtension(Probability.class, new Probability(0.002d, null));
b.addExtension(Probability.class, new Probability(null, "variable_ts1"));
return Arrays.asList(a, b);
};

// Initialize the MetrixNetwork
MetrixNetwork metrixNetwork = MetrixNetwork.create(network, contingenciesProvider, mappedSwitches, new MetrixParameters(), (Path) null);

// Check the lists
assertThat(metrixNetwork.getCountryList()).containsExactlyInAnyOrderElementsOf(Collections.singletonList("Undefined"));
assertThat(metrixNetwork.getLoadList()).containsExactlyInAnyOrderElementsOf(network.getLoads());
assertThat(metrixNetwork.getGeneratorList()).containsExactlyInAnyOrderElementsOf(network.getGenerators());
assertThat(metrixNetwork.getGeneratorTypeList()).containsExactlyInAnyOrderElementsOf(List.of("HYDRO", "THERMAL"));
assertThat(metrixNetwork.getLineList()).containsExactlyInAnyOrderElementsOf(network.getLines());
assertThat(metrixNetwork.getTwoWindingsTransformerList()).containsExactlyInAnyOrderElementsOf(network.getTwoWindingsTransformers());
assertThat(metrixNetwork.getThreeWindingsTransformerList()).containsExactlyInAnyOrderElementsOf(network.getThreeWindingsTransformers());
assertThat(metrixNetwork.getDanglingLineList()).containsExactlyInAnyOrderElementsOf(network.getDanglingLines());
assertThat(metrixNetwork.getSwitchList()).containsExactlyInAnyOrderElementsOf(switchList);
assertThat(metrixNetwork.getHvdcLineList()).containsExactlyInAnyOrderElementsOf(network.getHvdcLines());
assertThat(metrixNetwork.getBusList()).containsExactlyInAnyOrderElementsOf(network.getBusBreakerView().getBuses());
assertThat(metrixNetwork.getContingencyList()).containsExactlyInAnyOrderElementsOf(List.of(a, b));
}

private Network createBusBreakerNetwork(Set<String> mappedSwitches) {
// Initial network
Network network = createNetwork();

// Set some switches as retained
List<Switch> retainedSwitches = mappedSwitches.stream().map(network::getSwitch).toList();
network.getSwitchStream()
.forEach(sw -> sw.setRetained(retainedSwitches.contains(sw)));

// Export the network as BusBreaker
Path exportedFile = fileSystem.getPath("./network.xiidm");
NetworkSerDe.write(network, new ExportOptions().setTopologyLevel(TopologyLevel.BUS_BREAKER), exportedFile);
return NetworkSerDe.read(exportedFile);
}

private Network createNetwork() {
// Initial network
Network network = FourSubstationsNodeBreakerFactory.create();

// We add a substation, a ThreeWindingsTransformer and a DanglingLine
// We add a voltage level, a ThreeWindingsTransformer and a DanglingLine
VoltageLevel s1vl3 = network.getSubstation("S1").newVoltageLevel()
.setId("S1VL3")
.setNominalV(225.0)
Expand Down Expand Up @@ -137,7 +210,7 @@ private Network createNetwork() {

// Dangling line
createSwitch(s1vl3, "S1VL3_BBS_DL_DISCONNECTOR", SwitchKind.DISCONNECTOR, 0, 3);
createSwitch(s1vl3, "S1VL3_DL_BREAKER", SwitchKind.BREAKER, 3, 4);
createSwitch(s1vl3, "S1VL3_DL_BREAKER", SwitchKind.BREAKER, 4, 3);
s1vl3.newDanglingLine()
.setId("DL")
.setR(10.0)
Expand All @@ -149,6 +222,16 @@ private Network createNetwork() {
.setNode(4)
.add();

// We add another bus bar section and link it to the others with a breaker
network.getVoltageLevel("S1VL2").getNodeBreakerView().newBusbarSection()
.setId("S1VL2_BBS3")
.setName("S1VL2_BBS3")
.setNode(90)
.add();
createSwitch(network.getVoltageLevel("S1VL2"), "S1VL2_BBS1_DISCONNECTOR", SwitchKind.DISCONNECTOR, 0, 91);
createSwitch(network.getVoltageLevel("S1VL2"), "S1VL2_BBS3_DISCONNECTOR", SwitchKind.DISCONNECTOR, 92, 90);
createSwitch(network.getVoltageLevel("S1VL2"), "S1VL2_BBS1_BBS3", SwitchKind.BREAKER, 91, 92);

return network;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ class SimpleMappingData extends FilteredData {
// for each filtered equipment, compute the distribution key and add it to the config
if (!filteredEquipments.isEmpty()) {

if (((Switch) filteredEquipments[0]).voltageLevel.topologyKind == TopologyKind.BUS_BREAKER) {
throw new TimeSeriesMappingException("Bus breaker topology not supported for switch mapping")
}

filteredEquipments.forEach({ Identifiable identifiable ->
configLoader.addEquipmentMapping(breakerType, spec.timeSeriesName, identifiable.id, NumberDistributionKey.ONE, EquipmentVariable.OPEN)
})
Expand Down

0 comments on commit edd3f0e

Please sign in to comment.