Skip to content

Commit

Permalink
Fix: does not crash during CGMES export when a terminal is disconnect…
Browse files Browse the repository at this point in the history
…ed (#2050)

* Fix: Connectable buses used for bus bar sections connectivity in CGMES EQ export
* Fix: for switches, if there is no equivalent terminal, we consider the bus of bus view as null => fictitious topological node is created
* Fix: fictitious DC topological nodes are created when a DC converter station is disconnected

Signed-off-by: VEDELAGO MIORA <miora.ralambotiana@rte-france.com>
  • Loading branch information
miovd committed Apr 6, 2022
1 parent 57319f2 commit c16e512
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ private static void addIidmMappingsTerminal(Terminal t, Connectable<?> c) {
boundaryId = CgmesExportUtil.getUniqueId();
c.addAlias(boundaryId, Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + TERMINAL_BOUNDARY);
}
} else if (c instanceof Load && ((Load) c).isFictitious()) {
} else if (c instanceof Load && c.isFictitious()) {
// An fictitious load do not need an alias
} else {
int sequenceNumber = CgmesExportUtil.getTerminalSide(t, c);
Expand Down Expand Up @@ -602,6 +602,11 @@ public Set<CgmesIidmMapping.CgmesTopologicalNode> getTopologicalNodesByBusViewBu
return topologicalNodeByBusViewBusMapping.get(busId);
}

public CgmesExportContext putTopologicalNode(String iidmBusId, String cgmesId) {
topologicalNodeByBusViewBusMapping.computeIfAbsent(iidmBusId, k -> new HashSet<>()).add(new CgmesIidmMapping.CgmesTopologicalNode(cgmesId, cgmesId, Source.IGM));
return this;
}

public Set<CgmesIidmMapping.CgmesTopologicalNode> getUnmappedTopologicalNodes() {
return Collections.unmodifiableSet(unmappedTopologicalNodes);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,7 @@ private static String connectivityNodeId(Map<String, String> exportedNodes, Term
if (terminal.getVoltageLevel().getTopologyKind().equals(TopologyKind.NODE_BREAKER)) {
key = terminal.getVoltageLevel().getId() + terminal.getNodeBreakerView().getNode();
} else {
key = terminal.getBusBreakerView().getBus().getId();
key = terminal.getBusBreakerView().getConnectableBus().getId();
}
return exportedNodes.get(key);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ private static String cgmesTerminalFromAlias(Identifiable<?> i, String aliasType
}

private static String topologicalNodeFromIidmBus(Bus b, CgmesExportContext context) {
return context.getTopologicalNodesByBusViewBus(b.getId()).stream().findFirst().orElseThrow(PowsyblException::new).getCgmesId();
return b != null ? context.getTopologicalNodesByBusViewBus(b.getId()).stream().findFirst().orElseThrow(PowsyblException::new).getCgmesId() : null;
}

private static void writeSwitchesTerminals(Network network, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException {
Expand All @@ -92,8 +92,8 @@ private static void writeSwitchesTerminals(Network network, String cimNamespace,
Bus bus1;
Bus bus2;
if (vl.getTopologyKind() == TopologyKind.NODE_BREAKER) {
bus1 = Networks.getEquivalentTerminal(vl, vl.getNodeBreakerView().getNode1(sw.getId())).getBusView().getBus();
bus2 = Networks.getEquivalentTerminal(vl, vl.getNodeBreakerView().getNode2(sw.getId())).getBusView().getBus();
bus1 = Optional.ofNullable(Networks.getEquivalentTerminal(vl, vl.getNodeBreakerView().getNode1(sw.getId()))).map(t -> t.getBusView().getBus()).orElse(null);
bus2 = Optional.ofNullable(Networks.getEquivalentTerminal(vl, vl.getNodeBreakerView().getNode2(sw.getId()))).map(t -> t.getBusView().getBus()).orElse(null);
} else {
bus1 = vl.getBusView().getMergedBus(vl.getBusBreakerView().getBus1(sw.getId()).getId());
bus2 = vl.getBusView().getMergedBus(vl.getBusBreakerView().getBus2(sw.getId()).getId());
Expand All @@ -102,11 +102,22 @@ private static void writeSwitchesTerminals(Network network, String cimNamespace,
String cgmesTerminal1 = cgmesTerminalFromAlias(sw, CgmesNames.TERMINAL1);
String cgmesTerminal2 = cgmesTerminalFromAlias(sw, CgmesNames.TERMINAL2);

writeTerminal(cgmesTerminal1, topologicalNodeFromIidmBus(bus1, context), cimNamespace, writer);
writeTerminal(cgmesTerminal2, topologicalNodeFromIidmBus(bus2, context), cimNamespace, writer);
writeSwitchTerminal(bus1, sw.getVoltageLevel(), cgmesTerminal1, cimNamespace, writer, context);
writeSwitchTerminal(bus2, sw.getVoltageLevel(), cgmesTerminal2, cimNamespace, writer, context);
}
}

private static void writeSwitchTerminal(Bus bus, VoltageLevel voltageLevel, String cgmesTerminal, String cimNamespace,
XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException {
String tn = topologicalNodeFromIidmBus(bus, context);
if (tn == null) {
tn = CgmesExportUtil.getUniqueId();
writeTopologicalNode(tn, tn, voltageLevel.getId(),
context.getBaseVoltageByNominalVoltage(voltageLevel.getNominalV()).getId(), cimNamespace, writer);
}
writeTerminal(cgmesTerminal, tn, cimNamespace, writer);
}

private static void writeHvdcTerminals(Network network, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException {
for (HvdcLine line : network.getHvdcLines()) {
Bus b1 = line.getConverterStation1().getTerminal().getBusView().getBus();
Expand All @@ -118,7 +129,13 @@ private static void writeHvdcTerminals(Network network, String cimNamespace, XML
}

private static void writeHvdcBusTerminals(HvdcLine line, Bus bus, int side, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException {
for (CgmesIidmMapping.CgmesTopologicalNode topologicalNode : context.getTopologicalNodesByBusViewBus(bus.getId())) {
String iidmId;
if (bus == null) {
iidmId = line.getId() + side;
} else {
iidmId = bus.getId();
}
for (CgmesIidmMapping.CgmesTopologicalNode topologicalNode : context.getTopologicalNodesByBusViewBus(iidmId)) {
String dcTopologicalNode = topologicalNode.getCgmesId() + "DC";
String dcNode = line.getAliasFromType(Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + "DCNode" + side).orElseThrow(PowsyblException::new);
writeDCNode(dcNode, dcTopologicalNode, cimNamespace, writer);
Expand Down Expand Up @@ -208,14 +225,27 @@ private static void writeDanglingLineTopologicalNodes(Network network, String ci
private static void writeHvdcTopologicalNodes(Network network, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException {
for (HvdcLine line : network.getHvdcLines()) {
Bus b1 = line.getConverterStation1().getTerminal().getBusView().getBus();
for (CgmesIidmMapping.CgmesTopologicalNode topologicalNode : context.getTopologicalNodesByBusViewBus(b1.getId())) {
writeDCTopologicalNode(topologicalNode.getCgmesId() + "DC", line.getNameOrId() + 1, cimNamespace, writer);
if (b1 != null) {
for (CgmesIidmMapping.CgmesTopologicalNode topologicalNode : context.getTopologicalNodesByBusViewBus(b1.getId())) {
writeDCTopologicalNode(topologicalNode.getCgmesId() + "DC", line.getNameOrId() + 1, cimNamespace, writer);
}
} else {
String topologicalNode = CgmesExportUtil.getUniqueId();
context.putTopologicalNode(line.getId() + 1, topologicalNode);
writeDCTopologicalNode(topologicalNode + "DC", line.getNameOrId() + 1, cimNamespace, writer);
}

Bus b2 = line.getConverterStation2().getTerminal().getBusView().getBus();
for (CgmesIidmMapping.CgmesTopologicalNode topologicalNode : context.getTopologicalNodesByBusViewBus(b2.getId())) {
writeDCTopologicalNode(topologicalNode.getCgmesId() + "DC", line.getNameOrId() + 2, cimNamespace, writer);
if (b2 != null) {
for (CgmesIidmMapping.CgmesTopologicalNode topologicalNode : context.getTopologicalNodesByBusViewBus(b2.getId())) {
writeDCTopologicalNode(topologicalNode.getCgmesId() + "DC", line.getNameOrId() + 2, cimNamespace, writer);
}
} else {
String topologicalNode = CgmesExportUtil.getUniqueId();
context.putTopologicalNode(line.getId() + 2, topologicalNode);
writeDCTopologicalNode(topologicalNode + "DC", line.getNameOrId() + 2, cimNamespace, writer);
}

}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Copyright (c) 2022, 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.cgmes.conversion.test.export;

import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
import com.powsybl.commons.datasource.GenericReadOnlyDataSource;
import com.powsybl.iidm.export.Exporters;
import com.powsybl.iidm.import_.Importers;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.test.FictitiousSwitchFactory;
import com.powsybl.iidm.network.util.Networks;
import org.junit.Test;

import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;

import static org.junit.Assert.assertNull;

/**
* @author Miora Vedelago <miora.ralambotiana at rte-france.com>
*/
public class CgmesExportTest {

@Test
public void testFromIidm() throws IOException {
// Test from IIDM with configuration that does not exist in CGMES (disconnected node on switch and HVDC line)

Network network = FictitiousSwitchFactory.create();
VoltageLevel vl = network.getVoltageLevel("C");

// Add disconnected node on switch (side 2)
vl.getNodeBreakerView().newSwitch().setId("TEST_SW")
.setKind(SwitchKind.DISCONNECTOR)
.setOpen(true)
.setNode1(0)
.setNode2(6)
.add();

// Add disconnected node on DC converter station (side 2)
vl.newVscConverterStation()
.setId("C1")
.setNode(5)
.setLossFactor(1.1f)
.setVoltageSetpoint(405.0)
.setVoltageRegulatorOn(true)
.add();
vl.getNodeBreakerView().newInternalConnection().setNode1(0).setNode2(5).add();
vl.newVscConverterStation()
.setId("C2")
.setNode(6)
.setLossFactor(1.1f)
.setReactivePowerSetpoint(123)
.setVoltageRegulatorOn(false)
.add();
network.newHvdcLine()
.setId("hvdc_line")
.setR(5.0)
.setConvertersMode(HvdcLine.ConvertersMode.SIDE_1_INVERTER_SIDE_2_RECTIFIER)
.setNominalV(440.0)
.setMaxP(50.0)
.setActivePowerSetpoint(20.0)
.setConverterStationId1("C1")
.setConverterStationId2("C2")
.add();

try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) {
Path tmpDir = Files.createDirectory(fs.getPath("/cgmes"));
Exporters.export("CGMES", network, null, tmpDir.resolve("tmp"));
Network n2 = Importers.loadNetwork(new GenericReadOnlyDataSource(tmpDir, "tmp"));
VoltageLevel c = n2.getVoltageLevel("C");
assertNull(Networks.getEquivalentTerminal(c, c.getNodeBreakerView().getNode2("TEST_SW")));
assertNull(n2.getVscConverterStation("C2").getTerminal().getBusView().getBus());
}
}
}

0 comments on commit c16e512

Please sign in to comment.