diff --git a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/FlowDecompositionComputer.java b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/FlowDecompositionComputer.java index 933b6221..33f1555a 100644 --- a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/FlowDecompositionComputer.java +++ b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/FlowDecompositionComputer.java @@ -6,6 +6,7 @@ */ package com.powsybl.flow_decomposition; +import com.powsybl.flow_decomposition.glsk_provider.AutoGlskProvider; import com.powsybl.iidm.network.Branch; import com.powsybl.iidm.network.Country; import com.powsybl.iidm.network.Identifiable; @@ -58,28 +59,32 @@ public FlowDecompositionComputer(FlowDecompositionParameters flowDecompositionPa } public FlowDecompositionResults run(XnecProvider xnecProvider, Network network) { + return run(xnecProvider, new AutoGlskProvider(), network); + } + + public FlowDecompositionResults run(XnecProvider xnecProvider, GlskProvider glskProvider, Network network) { NetworkStateManager networkStateManager = new NetworkStateManager(network, xnecProvider); LoadFlowRunningService.Result loadFlowServiceAcResult = runAcLoadFlow(network); - Map> glsks = getGlsks(network); + Map> glsks = glskProvider.getGlsk(network); Map netPositions = getZonesNetPosition(network); FlowDecompositionResults flowDecompositionResults = new FlowDecompositionResults(network); decomposeFlowForNState(network, - flowDecompositionResults, - xnecProvider.getNetworkElements(network), - netPositions, - glsks, - loadFlowServiceAcResult); - xnecProvider.getNetworkElementsPerContingency(network) - .forEach((contingencyId, xnecList) -> decomposeFlowForContingencyState(network, flowDecompositionResults, - networkStateManager, - contingencyId, - xnecList, + xnecProvider.getNetworkElements(network), netPositions, - glsks)); + glsks, + loadFlowServiceAcResult); + xnecProvider.getNetworkElementsPerContingency(network) + .forEach((contingencyId, xnecList) -> decomposeFlowForContingencyState(network, + flowDecompositionResults, + networkStateManager, + contingencyId, + xnecList, + netPositions, + glsks)); networkStateManager.deleteAllContingencyVariants(); return flowDecompositionResults; } @@ -155,11 +160,6 @@ private void saveAcReferenceFlow(FlowDecompositionResults.PerStateBuilder flowDe flowDecompositionResultBuilder.saveAcReferenceFlow(acReferenceFlows); } - private Map> getGlsks(Network network) { - GlskComputer glskComputer = new GlskComputer(); - return glskComputer.run(network); - } - private Map getZonesNetPosition(Network network) { NetPositionComputer netPositionComputer = new NetPositionComputer(); return netPositionComputer.run(network); diff --git a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/GlskProvider.java b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/GlskProvider.java new file mode 100644 index 00000000..ddc5824b --- /dev/null +++ b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/GlskProvider.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023, 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.flow_decomposition; + +import com.powsybl.iidm.network.Country; +import com.powsybl.iidm.network.Network; + +import java.util.Map; + +/** + * @author Sebastien Murgey {@literal } + */ +public interface GlskProvider { + Map> getGlsk(Network network); +} diff --git a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/NetworkUtil.java b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/NetworkUtil.java index 5d7529e8..2f5a2641 100644 --- a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/NetworkUtil.java +++ b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/NetworkUtil.java @@ -46,10 +46,6 @@ public static Country getTerminalCountry(Terminal terminal) { return optionalCountry.get(); } - static Country getInjectionCountry(Injection injection) { - return getTerminalCountry(injection.getTerminal()); - } - static String getLoopFlowIdFromCountry(Network network, String identifiableId) { Identifiable identifiable = network.getIdentifiable(identifiableId); if (identifiable instanceof Injection) { @@ -67,6 +63,10 @@ static Map getIndex(List idList) { )); } + public static Country getInjectionCountry(Injection injection) { + return getTerminalCountry(injection.getTerminal()); + } + public static List getAllValidBranches(Network network) { return network.getBranchStream() .filter(NetworkUtil::isConnected) diff --git a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/GlskComputer.java b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/glsk_provider/AutoGlskProvider.java similarity index 81% rename from flow-decomposition/src/main/java/com/powsybl/flow_decomposition/GlskComputer.java rename to flow-decomposition/src/main/java/com/powsybl/flow_decomposition/glsk_provider/AutoGlskProvider.java index 4a121427..87d980d6 100644 --- a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/GlskComputer.java +++ b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/glsk_provider/AutoGlskProvider.java @@ -4,8 +4,10 @@ * 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.flow_decomposition; +package com.powsybl.flow_decomposition.glsk_provider; +import com.powsybl.flow_decomposition.GlskProvider; +import com.powsybl.flow_decomposition.NetworkUtil; import com.powsybl.iidm.network.Country; import com.powsybl.iidm.network.Network; @@ -18,8 +20,9 @@ * @author Hugo Schindler {@literal } * @author Sebastien Murgey {@literal } */ -public class GlskComputer { - public Map> run(Network network) { +public class AutoGlskProvider implements GlskProvider { + @Override + public Map> getGlsk(Network network) { Map> glsks = network.getCountries().stream().collect(Collectors.toMap( Function.identity(), country -> new HashMap<>())); diff --git a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/xnec_provider/XnecProvider5percPtdf.java b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/xnec_provider/XnecProvider5percPtdf.java index 1f1afb2b..ef88047a 100644 --- a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/xnec_provider/XnecProvider5percPtdf.java +++ b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/xnec_provider/XnecProvider5percPtdf.java @@ -7,10 +7,8 @@ package com.powsybl.flow_decomposition.xnec_provider; import com.powsybl.contingency.Contingency; -import com.powsybl.flow_decomposition.GlskComputer; -import com.powsybl.flow_decomposition.NetworkUtil; -import com.powsybl.flow_decomposition.XnecProvider; -import com.powsybl.flow_decomposition.ZonalSensitivityAnalyser; +import com.powsybl.flow_decomposition.*; +import com.powsybl.flow_decomposition.glsk_provider.AutoGlskProvider; import com.powsybl.iidm.network.Branch; import com.powsybl.iidm.network.Country; import com.powsybl.iidm.network.Network; @@ -32,6 +30,11 @@ */ public class XnecProvider5percPtdf implements XnecProvider { public static final double MAX_ZONE_TO_ZONE_PTDF_THRESHOLD = 0.05; + private final GlskProvider glskProvider; + + public XnecProvider5percPtdf() { + this.glskProvider = new AutoGlskProvider(); + } private static boolean isAXnec(Branch branch, Map> zonalPtdf) { return XnecProviderInterconnection.isAnInterconnection(branch) || hasMoreThan5PercentPtdf(getZonalPtdf(branch, zonalPtdf)); @@ -46,9 +49,8 @@ private static boolean hasMoreThan5PercentPtdf(Collection countryPtdfLis && (Collections.max(countryPtdfList) - Collections.min(countryPtdfList)) >= MAX_ZONE_TO_ZONE_PTDF_THRESHOLD; } - public static Set getBranches(Network network) { - GlskComputer glskComputer = new GlskComputer(); - Map> glsks = glskComputer.run(network); + public Set getBranches(Network network) { + Map> glsks = glskProvider.getGlsk(network); ZonalSensitivityAnalyser zonalSensitivityAnalyser = new ZonalSensitivityAnalyser(LoadFlowParameters.load(), SensitivityAnalysis.find()); Map> zonalPtdf = zonalSensitivityAnalyser.run(network, glsks, SensitivityVariableType.INJECTION_ACTIVE_POWER); return NetworkUtil.getAllValidBranches(network) diff --git a/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/CustomGlskProviderTests.java b/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/CustomGlskProviderTests.java new file mode 100644 index 00000000..cbf6ec0d --- /dev/null +++ b/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/CustomGlskProviderTests.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023, 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.flow_decomposition; + +import com.powsybl.flow_decomposition.glsk_provider.AutoGlskProvider; +import com.powsybl.flow_decomposition.xnec_provider.XnecProviderByIds; +import com.powsybl.iidm.network.Country; +import com.powsybl.iidm.network.Network; +import org.junit.jupiter.api.Test; + +import java.util.Map; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Sebastien Murgey {@literal } + */ +class CustomGlskProviderTests { + private static final String NETWORK_FILE_FOR_CUSTOM_GLSK_TEST = "customGlskProviderTestNetwork.uct"; + private static final String NETWORK_ELEMENT_DECOMPOSED = "FGEN2 11 FINTER11 1"; + private static final double EPSILON = 1e-3; + + @Test + void checkThatDefaultGlskProviderIsAutoCountryGlsk() { + FlowDecompositionComputer computer = new FlowDecompositionComputer(); + XnecProvider xnecProvider = XnecProviderByIds.builder() + .addNetworkElementsOnBasecase(Set.of(NETWORK_ELEMENT_DECOMPOSED)) + .build(); + Network network = TestUtils.importNetwork(NETWORK_FILE_FOR_CUSTOM_GLSK_TEST); + FlowDecompositionResults results = computer.run(xnecProvider, network); + assertEquals(0., results.getDecomposedFlowMap().get(NETWORK_ELEMENT_DECOMPOSED).getAllocatedFlow(), EPSILON); + } + + @Test + void checkThatDefaultGlskProviderCanBeProvided() { + FlowDecompositionComputer computer = new FlowDecompositionComputer(); + XnecProvider xnecProvider = XnecProviderByIds.builder() + .addNetworkElementsOnBasecase(Set.of(NETWORK_ELEMENT_DECOMPOSED)) + .build(); + GlskProvider glskProvider = new AutoGlskProvider(); + Network network = TestUtils.importNetwork(NETWORK_FILE_FOR_CUSTOM_GLSK_TEST); + FlowDecompositionResults results = computer.run(xnecProvider, glskProvider, network); + assertEquals(0., results.getDecomposedFlowMap().get(NETWORK_ELEMENT_DECOMPOSED).getAllocatedFlow(), EPSILON); + } + + @Test + void checkThatOtherGlskProviderGivesOtherCorrectResults() { + FlowDecompositionComputer computer = new FlowDecompositionComputer(); + XnecProvider xnecProvider = XnecProviderByIds.builder() + .addNetworkElementsOnBasecase(Set.of(NETWORK_ELEMENT_DECOMPOSED)) + .build(); + GlskProvider glskProvider = network -> Map.of(Country.FR, Map.of("FGEN2 11_generator", 1.0), + Country.BE, Map.of("BGEN 11_generator", 1.0)); + Network network = TestUtils.importNetwork(NETWORK_FILE_FOR_CUSTOM_GLSK_TEST); + FlowDecompositionResults results = computer.run(xnecProvider, glskProvider, network); + assertEquals(-100., results.getDecomposedFlowMap().get(NETWORK_ELEMENT_DECOMPOSED).getAllocatedFlow(), EPSILON); + } + + @Test + void checkThatLskInGlskProviderGivesOtherCorrectResults() { + FlowDecompositionComputer computer = new FlowDecompositionComputer(); + XnecProvider xnecProvider = XnecProviderByIds.builder() + .addNetworkElementsOnBasecase(Set.of(NETWORK_ELEMENT_DECOMPOSED)) + .build(); + GlskProvider glskProvider = network -> Map.of(Country.FR, Map.of("FGEN2 11_load", 1.0), + Country.BE, Map.of("BGEN 11_generator", 1.0)); + Network network = TestUtils.importNetwork(NETWORK_FILE_FOR_CUSTOM_GLSK_TEST); + FlowDecompositionResults results = computer.run(xnecProvider, glskProvider, network); + assertEquals(-100., results.getDecomposedFlowMap().get(NETWORK_ELEMENT_DECOMPOSED).getAllocatedFlow(), EPSILON); + } +} diff --git a/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/NodalInjectionTests.java b/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/NodalInjectionTests.java index ba27e766..eef4bd3a 100644 --- a/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/NodalInjectionTests.java +++ b/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/NodalInjectionTests.java @@ -6,6 +6,7 @@ */ package com.powsybl.flow_decomposition; +import com.powsybl.flow_decomposition.glsk_provider.AutoGlskProvider; import com.powsybl.iidm.network.Branch; import com.powsybl.iidm.network.Country; import com.powsybl.iidm.network.Network; @@ -96,8 +97,8 @@ private static Map> getNodalInjections(String networ if (!loadFlowResult.isOk()) { LoadFlow.run(network, LoadFlowParameters.load().setDc(true)); } - GlskComputer glskComputer = new GlskComputer(); - Map> glsks = glskComputer.run(network); + AutoGlskProvider glskProvider = new AutoGlskProvider(); + Map> glsks = glskProvider.getGlsk(network); Map netPositions = NetPositionComputer.computeNetPositions(network); List xnecList = network.getBranchStream().collect(Collectors.toList()); NetworkMatrixIndexes networkMatrixIndexes = new NetworkMatrixIndexes(network, xnecList); diff --git a/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/SensitivityComputerTests.java b/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/SensitivityComputerTests.java index 09ff3c3d..bc977856 100644 --- a/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/SensitivityComputerTests.java +++ b/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/SensitivityComputerTests.java @@ -6,6 +6,7 @@ */ package com.powsybl.flow_decomposition; +import com.powsybl.flow_decomposition.glsk_provider.AutoGlskProvider; import com.powsybl.iidm.network.Branch; import com.powsybl.iidm.network.Country; import com.powsybl.iidm.network.Network; @@ -70,8 +71,8 @@ void testThatZonalPtdfAreWellComputed() { String line7 = "FGEN 11 FLOAD 11 7"; String line8 = "FGEN 11 FLOAD 11 8"; String line9 = "FGEN 11 FLOAD 11 9"; - GlskComputer glskComputer = new GlskComputer(); - Map> glsks = glskComputer.run(network); + AutoGlskProvider glskProvider = new AutoGlskProvider(); + Map> glsks = glskProvider.getGlsk(network); LoadFlowParameters loadFlowParameters = LoadFlowParameters.load(); SensitivityAnalysis.Runner sensitivityAnalysisRunner = SensitivityAnalysis.find(); ZonalSensitivityAnalyser zonalSensitivityAnalyser = new ZonalSensitivityAnalyser(loadFlowParameters, sensitivityAnalysisRunner); diff --git a/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/GlskTests.java b/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/glsk_provider/AutoGlskProviderTests.java similarity index 84% rename from flow-decomposition/src/test/java/com/powsybl/flow_decomposition/GlskTests.java rename to flow-decomposition/src/test/java/com/powsybl/flow_decomposition/glsk_provider/AutoGlskProviderTests.java index bf9d9242..56732fed 100644 --- a/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/GlskTests.java +++ b/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/glsk_provider/AutoGlskProviderTests.java @@ -4,7 +4,7 @@ * 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.flow_decomposition; +package com.powsybl.flow_decomposition.glsk_provider; import com.powsybl.iidm.network.Country; import com.powsybl.iidm.network.Network; @@ -19,7 +19,7 @@ /** * @author Hugo Schindler {@literal } */ -class GlskTests { +class AutoGlskProviderTests { private static final double EPSILON = 1e-3; @Test @@ -29,8 +29,8 @@ void testThatGlskAreWellComputed() { String loadBe = "BLOAD 11_load"; String genFr = "FGEN1 11_generator"; Network network = importNetwork(networkFileName); - GlskComputer glskComputer = new GlskComputer(); - Map> glsks = glskComputer.run(network); + AutoGlskProvider autoGlskProvider = new AutoGlskProvider(); + Map> glsks = autoGlskProvider.getGlsk(network); assertEquals(1.0, glsks.get(Country.FR).get(genFr), EPSILON); assertEquals(1.0, glsks.get(Country.BE).get(genBe), EPSILON); assertNull(glsks.get(Country.BE).get(loadBe)); diff --git a/flow-decomposition/src/test/resources/com/powsybl/flow_decomposition/customGlskProviderTestNetwork.uct b/flow-decomposition/src/test/resources/com/powsybl/flow_decomposition/customGlskProviderTestNetwork.uct new file mode 100644 index 00000000..6f046324 --- /dev/null +++ b/flow-decomposition/src/test/resources/com/powsybl/flow_decomposition/customGlskProviderTestNetwork.uct @@ -0,0 +1,19 @@ +##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 FGEN1 0 2 400.00 0.00000 0.00000 -200.00 0.00000 1000.00 -1000.0 1000.00 -1000.0 +FINTER11 FINTER11 0 0 400.00 0.00000 0.00000 +FGEN2 11 FGEN2 0 2 400.00 100.000 0.00000 0.00000 0.00000 1000.00 -1000.0 1000.00 -1000.0 +##ZBE +BGEN 11 BGEN1 0 3 400.00 200.000 0.00000 -100.00 0.00000 1000.00 -1000.0 1000.00 -1000.0 +##L +FGEN1 11 BGEN 11 1 0 1.0000 0.0500 0.000000 480 LINE +FGEN2 11 FINTER11 1 0 1.0000 0.0500 0.000000 480 LINE +FINTER11 BGEN 11 1 0 1.0000 0.0500 0.000000 480 LINE