Skip to content

Commit

Permalink
[Flow decomposition] Fix net position computation with dangling lines (
Browse files Browse the repository at this point in the history
…#134)

* Fix net positions in flow decomposition for dangling lines

---------

Signed-off-by: Hugo SCHINDLER <hugo.schindler@rte-france.com>
  • Loading branch information
OpenSuze authored Jan 29, 2024
1 parent 9e9be3c commit 687e835
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,12 @@ Map<Country, Double> run(Network network) {
static Map<Country, Double> computeNetPositions(Network network) {
Map<Country, Double> netPositions = new EnumMap<>(Country.class);

network.getLineStream().forEach(line -> {
Country countrySide1 = NetworkUtil.getTerminalCountry(line.getTerminal1());
Country countrySide2 = NetworkUtil.getTerminalCountry(line.getTerminal2());
if (countrySide1.equals(countrySide2)) {
return;
}
addLeavingFlow(netPositions, line, countrySide1);
addLeavingFlow(netPositions, line, countrySide2);
network.getDanglingLineStream().forEach(danglingLine -> {
Country country = NetworkUtil.getTerminalCountry(danglingLine.getTerminal());
addLeavingFlow(netPositions, danglingLine, country);
});

network.getTieLineStream().forEach(line -> {
network.getLineStream().forEach(line -> {
Country countrySide1 = NetworkUtil.getTerminalCountry(line.getTerminal1());
Country countrySide2 = NetworkUtil.getTerminalCountry(line.getTerminal2());
if (countrySide1.equals(countrySide2)) {
Expand Down Expand Up @@ -65,24 +60,17 @@ private static void addLeavingFlow(Map<Country, Double> netPositions, Line line,
netPositions.put(country, previousValue + getLeavingFlow(line, country));
}

private static void addLeavingFlow(Map<Country, Double> netPositions, TieLine line, Country country) {
double previousValue = getPreviousValue(netPositions, country);
netPositions.put(country, previousValue + getLeavingFlow(line, country));
}

private static void addLeavingFlow(Map<Country, Double> netPositions, HvdcLine hvdcLine, Country country) {
double previousValue = getPreviousValue(netPositions, country);
netPositions.put(country, previousValue + getLeavingFlow(hvdcLine, country));
}

private static double getLeavingFlow(Line line, Country country) {
double flowSide1 = line.getTerminal1().isConnected() && !Double.isNaN(line.getTerminal1().getP()) ? line.getTerminal1().getP() : 0;
double flowSide2 = line.getTerminal2().isConnected() && !Double.isNaN(line.getTerminal2().getP()) ? line.getTerminal2().getP() : 0;
double directFlow = (flowSide1 - flowSide2) / 2;
return country.equals(NetworkUtil.getTerminalCountry(line.getTerminal1())) ? directFlow : -directFlow;
private static void addLeavingFlow(Map<Country, Double> netPositions, DanglingLine danglingLine, Country country) {
double previousValue = getPreviousValue(netPositions, country);
netPositions.put(country, previousValue + getLeavingFlow(danglingLine));
}

private static double getLeavingFlow(TieLine line, Country country) {
private static double getLeavingFlow(Line line, Country country) {
double flowSide1 = line.getTerminal1().isConnected() && !Double.isNaN(line.getTerminal1().getP()) ? line.getTerminal1().getP() : 0;
double flowSide2 = line.getTerminal2().isConnected() && !Double.isNaN(line.getTerminal2().getP()) ? line.getTerminal2().getP() : 0;
double directFlow = (flowSide1 - flowSide2) / 2;
Expand All @@ -95,4 +83,8 @@ private static double getLeavingFlow(HvdcLine hvdcLine, Country country) {
double directFlow = (flowSide1 - flowSide2) / 2;
return country.equals(NetworkUtil.getTerminalCountry(hvdcLine.getConverterStation1().getTerminal())) ? directFlow : -directFlow;
}

private static double getLeavingFlow(DanglingLine danglingLine) {
return danglingLine.getTerminal().isConnected() && !Double.isNaN(danglingLine.getTerminal().getP()) ? danglingLine.getTerminal().getP() : 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ void testSingleN1PostContingencyState() {
TestUtils.assertCoherenceTotalFlow(flowDecompositionParameters.isRescaleEnabled(), flowDecompositionResults);

Map<String, DecomposedFlow> decomposedFlowMap = flowDecompositionResults.getDecomposedFlowMap();
validateFlowDecompositionOnXnec(xnecId, branchId, contingencyId, decomposedFlowMap.get(xnecId), -1269.932, -22.027);
validateFlowDecompositionOnXnec(xnecId, branchId, contingencyId, decomposedFlowMap.get(xnecId), -1269.932, 31.943);
}

@Test
Expand All @@ -69,8 +69,8 @@ void testNStateAndN1PostContingencyState() {
TestUtils.assertCoherenceTotalFlow(flowDecompositionParameters.isRescaleEnabled(), flowDecompositionResults);

Map<String, DecomposedFlow> decomposedFlowMap = flowDecompositionResults.getDecomposedFlowMap();
validateFlowDecompositionOnXnec(xnecId1, branchId, contingencyId1, decomposedFlowMap.get(xnecId1), -300.420, -15.496);
validateFlowDecompositionOnXnec(xnecId2, branchId, contingencyId2, decomposedFlowMap.get(xnecId2), -1269.932, -22.027);
validateFlowDecompositionOnXnec(xnecId1, branchId, contingencyId1, decomposedFlowMap.get(xnecId1), -300.420, 22.472);
validateFlowDecompositionOnXnec(xnecId2, branchId, contingencyId2, decomposedFlowMap.get(xnecId2), -1269.932, 31.943);
}

@Test
Expand All @@ -95,7 +95,7 @@ void testSingleN2PostContingencyState() {
TestUtils.assertCoherenceTotalFlow(flowDecompositionParameters.isRescaleEnabled(), flowDecompositionResults);

Map<String, DecomposedFlow> decomposedFlowMap = flowDecompositionResults.getDecomposedFlowMap();
validateFlowDecompositionOnXnec(xnecId, branchId, contingencyId, decomposedFlowMap.get(xnecId), -406.204, 3.329);
validateFlowDecompositionOnXnec(xnecId, branchId, contingencyId, decomposedFlowMap.get(xnecId), -406.204, 48.362);
}

@Test
Expand Down Expand Up @@ -125,9 +125,9 @@ void testNStateN1AndN2PostContingencyState() {
TestUtils.assertCoherenceTotalFlow(flowDecompositionParameters.isRescaleEnabled(), flowDecompositionResults);

Map<String, DecomposedFlow> decomposedFlowMap = flowDecompositionResults.getDecomposedFlowMap();
validateFlowDecompositionOnXnec(xnecId1, branchId, contingencyId1, decomposedFlowMap.get(xnecId1), -300.420, -15.496);
validateFlowDecompositionOnXnec(xnecId2, branchId, contingencyId2, decomposedFlowMap.get(xnecId2), -1269.932, -22.027);
validateFlowDecompositionOnXnec(xnecId3, branchId, contingencyId3, decomposedFlowMap.get(xnecId3), -406.204, 3.329);
validateFlowDecompositionOnXnec(xnecId1, branchId, contingencyId1, decomposedFlowMap.get(xnecId1), -300.420, 22.472);
validateFlowDecompositionOnXnec(xnecId2, branchId, contingencyId2, decomposedFlowMap.get(xnecId2), -1269.932, 31.943);
validateFlowDecompositionOnXnec(xnecId3, branchId, contingencyId3, decomposedFlowMap.get(xnecId3), -406.204, 48.362);
}

private static void validateFlowDecompositionOnXnec(String xnecId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.powsybl.iidm.network.Country;
import com.powsybl.iidm.network.Network;
import com.powsybl.loadflow.LoadFlow;
import com.powsybl.loadflow.LoadFlowParameters;
import org.junit.jupiter.api.Test;

import java.util.Map;
Expand All @@ -18,43 +19,107 @@
/**
* @author Sebastien Murgey {@literal <sebastien.murgey at rte-france.com>}
* @author Peter Mitri {@literal <peter.mitri at rte-france.com>}
* @author Hugo Schindler{@literal <hugo.schindler@rte-france.com>}
*/
class NetPositionTest {
private static final double DOUBLE_TOLERANCE = 1e-3;

@Test
void testLines() {
Network network = Network.read("testCase.xiidm", getClass().getResourceAsStream("testCase.xiidm"));
private static void assertNetPosition(Network network, double netPositionBe, double netPositionNl, double netPositionDe) {
Map<Country, Double> netPositions = NetPositionComputer.computeNetPositions(network);
assertEquals(1000.0, netPositions.get(Country.FR), DOUBLE_TOLERANCE);
assertEquals(1500.0, netPositions.get(Country.BE), DOUBLE_TOLERANCE);
assertEquals(0.0, netPositions.get(Country.NL), DOUBLE_TOLERANCE);
assertEquals(-2500.0, netPositions.get(Country.DE), DOUBLE_TOLERANCE);
assertEquals(netPositionBe, netPositions.get(Country.BE), DOUBLE_TOLERANCE);
assertEquals(netPositionNl, netPositions.get(Country.NL), DOUBLE_TOLERANCE);
assertEquals(netPositionDe, netPositions.get(Country.DE), DOUBLE_TOLERANCE);
double sumAllNetPositions = netPositions.values().stream().mapToDouble(Double::doubleValue).sum();
assertEquals(0.0, sumAllNetPositions, DOUBLE_TOLERANCE);
}

private static void assertNetPositionForHvdc(Network network, double countryNetPosition) {
Map<Country, Double> netPositions = NetPositionComputer.computeNetPositions(network);
assertEquals(countryNetPosition, netPositions.get(Country.FR), DOUBLE_TOLERANCE);
assertEquals(-countryNetPosition, netPositions.get(Country.DE), DOUBLE_TOLERANCE);
double sumAllNetPositions = netPositions.values().stream().mapToDouble(Double::doubleValue).sum();
assertEquals(0.0, sumAllNetPositions, DOUBLE_TOLERANCE);
}

@Test
void testLines() {
Network network = Network.read("testCase.xiidm", getClass().getResourceAsStream("testCase.xiidm"));
LoadFlow.run(network, new LoadFlowParameters().setDc(true));
assertNetPosition(network, 1500.0, 0.0, -2500.0);
}

@Test
void testLinesDisconnected() {
Network network = Network.read("testCase.xiidm", getClass().getResourceAsStream("testCase.xiidm"));
network.getBranch("NNL2AA1 BBE3AA1 1").getTerminal1().disconnect();
network.getBranch("NNL2AA1 BBE3AA1 1").getTerminal2().disconnect();
LoadFlow.run(network, new LoadFlowParameters().setDc(true));
assertNetPosition(network, 1500.0, 0.0, -2500.0);
}

@Test
void testLinesNaN() {
Network network = Network.read("testCase.xiidm", getClass().getResourceAsStream("testCase.xiidm"));
LoadFlow.run(network, new LoadFlowParameters().setDc(true));
network.getBranch("NNL2AA1 BBE3AA1 1").getTerminal1().setP(Double.NaN);
network.getBranch("NNL2AA1 BBE3AA1 1").getTerminal2().setP(Double.NaN);
assertNetPosition(network, 324.666, 1175.334, -2500.0);
}

@Test
void testDanglingLinesBalanced() {
Network network = Network.read("TestCaseDangling.xiidm", getClass().getResourceAsStream("TestCaseDangling.xiidm"));
LoadFlow.run(network, new LoadFlowParameters().setDc(true));
assertNetPosition(network, 2300.0, -500.0, -2800.0);
}

@Test
void testDanglingLines() {
void testDanglingLinesDisconnected() {
Network network = Network.read("TestCaseDangling.xiidm", getClass().getResourceAsStream("TestCaseDangling.xiidm"));
LoadFlow.run(network);
network.getDanglingLine("BBE2AA1 X_BEFR1 1").getTerminal().disconnect();
LoadFlow.run(network, new LoadFlowParameters().setDc(true));
assertNetPosition(network, 2300.0, -500.0, -2800.0);
}

@Test
void testDanglingLinesNaN() {
Network network = Network.read("TestCaseDangling.xiidm", getClass().getResourceAsStream("TestCaseDangling.xiidm"));
LoadFlow.run(network, new LoadFlowParameters().setDc(true));
network.getDanglingLine("BBE2AA1 X_BEFR1 1").getTerminal().setP(Double.NaN);
assertNetPosition(network, 2300.0, -500.0, -2800.0);
}

@Test
void testDanglingLinesUnbalanced() {
Network network = Network.read("NETWORK_SINGLE_LOAD_TWO_GENERATORS_WITH_UNBOUNDED_XNODE.uct", getClass().getResourceAsStream("NETWORK_SINGLE_LOAD_TWO_GENERATORS_WITH_UNBOUNDED_XNODE.uct"));
LoadFlow.run(network, new LoadFlowParameters().setDc(true));
Map<Country, Double> netPositions = NetPositionComputer.computeNetPositions(network);
assertEquals(1000.0, netPositions.get(Country.FR), DOUBLE_TOLERANCE);
assertEquals(2300.0, netPositions.get(Country.BE), DOUBLE_TOLERANCE);
assertEquals(-500.0, netPositions.get(Country.NL), DOUBLE_TOLERANCE);
assertEquals(-2800.0, netPositions.get(Country.DE), DOUBLE_TOLERANCE);
assertEquals(100, netPositions.get(Country.FR), DOUBLE_TOLERANCE);
assertEquals(0, netPositions.get(Country.BE), DOUBLE_TOLERANCE);
double sumAllNetPositions = netPositions.values().stream().mapToDouble(Double::doubleValue).sum();
assertEquals(0.0, sumAllNetPositions, DOUBLE_TOLERANCE);
assertEquals(100, sumAllNetPositions, DOUBLE_TOLERANCE);
}

@Test
void testHvdcLines() {
Network network = Network.read("TestCaseHvdc.xiidm", getClass().getResourceAsStream("TestCaseHvdc.xiidm"));
Map<Country, Double> netPositions = NetPositionComputer.computeNetPositions(network);
assertEquals(272.0, netPositions.get(Country.FR), DOUBLE_TOLERANCE);
assertEquals(-272.0, netPositions.get(Country.DE), DOUBLE_TOLERANCE);
double sumAllNetPositions = netPositions.values().stream().mapToDouble(Double::doubleValue).sum();
assertEquals(0.0, sumAllNetPositions, DOUBLE_TOLERANCE);
assertNetPositionForHvdc(network, 272.0);
}

@Test
void testHvdcLinesDisconnected() {
Network network = Network.read("TestCaseHvdc.xiidm", getClass().getResourceAsStream("TestCaseHvdc.xiidm"));
network.getHvdcLine("hvdc_line_FR_1_DE").getConverterStation1().getTerminal().disconnect();
network.getHvdcLine("hvdc_line_FR_1_DE").getConverterStation2().getTerminal().disconnect();
assertNetPositionForHvdc(network, 200.0);
}

@Test
void testHvdcLinesNaN() {
Network network = Network.read("TestCaseHvdc.xiidm", getClass().getResourceAsStream("TestCaseHvdc.xiidm"));
network.getHvdcLine("hvdc_line_FR_1_DE").getConverterStation1().getTerminal().setP(Double.NaN);
network.getHvdcLine("hvdc_line_FR_1_DE").getConverterStation2().getTerminal().setP(Double.NaN);
assertNetPositionForHvdc(network, 200.0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
##C 2007.05.01
This is a test network with only two branches.
Each branch is linking a generator with a central load.
Used to validate:
- Basic network importer
- XNEC automatic selection
- GLSK automatic generation
- Zone automatic extraction
##N
##ZFR
FGEN1 11 GEN 0 3 400.00 0.00000 0.00000 -100.00 0.00000 1000.00 -1000.0 1000.00 -1000.0
##ZBE
BGEN2 11 GEN 0 2 400.00 0.00000 0.00000 -100.00 0.00000 1000.00 -1000.0 1000.00 -1000.0
BLOAD 11 LOAD 0 0 100.000 0.00000 0.00000 0.00000
##ZXX
X 11 XNODE 0 0 100.000 0.00000 0.00000 0.00000 1000.00 -1000.0 1000.00 -1000.0
##L
FGEN1 11 BLOAD 11 1 0 1.0000 0.0500 0.000000 480 LINE
BLOAD 11 BGEN2 11 1 0 1.0000 0.0500 0.000000 480 LINE
BLOAD 11 X 11 1 0 1.0000 0.0500 0.000000 480 LINE

0 comments on commit 687e835

Please sign in to comment.