diff --git a/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java b/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java index 54a3814117..ddee9d7ad2 100644 --- a/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java +++ b/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java @@ -9,7 +9,6 @@ import com.powsybl.loadflow.LoadFlowParameters; import com.powsybl.openloadflow.ac.outerloop.*; -import com.powsybl.openloadflow.network.util.ActivePowerDistribution; import com.powsybl.openloadflow.util.PerUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,16 +28,16 @@ protected AbstractAcOuterLoopConfig() { protected static Optional createDistributedSlackOuterLoop(LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt) { if (parameters.isDistributedSlack()) { - ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(parameters.getBalanceType(), parametersExt.isLoadPowerFactorConstant(), parametersExt.isUseActiveLimits()); - return Optional.of(new DistributedSlackOuterLoop(activePowerDistribution, parametersExt.getSlackBusPMaxMismatch())); + return Optional.of(DistributedSlackOuterLoop.create(parameters.getBalanceType(), parametersExt.isLoadPowerFactorConstant(), parametersExt.isUseActiveLimits(), + parametersExt.getSlackBusPMaxMismatch())); } return Optional.empty(); } protected static Optional createAreaInterchangeControlOuterLoop(LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt) { if (parametersExt.isAreaInterchangeControl()) { - ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(parameters.getBalanceType(), parametersExt.isLoadPowerFactorConstant(), parametersExt.isUseActiveLimits()); - return Optional.of(new AcAreaInterchangeControlOuterLoop(activePowerDistribution, parametersExt.getSlackBusPMaxMismatch(), parametersExt.getAreaInterchangePMaxMismatch())); + return Optional.of(AcAreaInterchangeControlOuterLoop.create(parameters.getBalanceType(), parametersExt.isLoadPowerFactorConstant(), parametersExt.isUseActiveLimits(), + parametersExt.getSlackBusPMaxMismatch(), parametersExt.getAreaInterchangePMaxMismatch())); } return Optional.empty(); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcAreaInterchangeControlOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcAreaInterchangeControlOuterLoop.java index 3b466535eb..ba36461787 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcAreaInterchangeControlOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcAreaInterchangeControlOuterLoop.java @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.outerloop; +import com.powsybl.loadflow.LoadFlowParameters; import com.powsybl.openloadflow.ac.AcLoadFlowContext; import com.powsybl.openloadflow.ac.AcLoadFlowParameters; import com.powsybl.openloadflow.ac.AcOuterLoopContext; @@ -32,6 +33,12 @@ public AcAreaInterchangeControlOuterLoop(ActivePowerDistribution activePowerDist super(activePowerDistribution, new DistributedSlackOuterLoop(activePowerDistribution, slackBusPMaxMismatch), slackBusPMaxMismatch, areaInterchangePMaxMismatch, LOGGER); } + public static AcAreaInterchangeControlOuterLoop create(LoadFlowParameters.BalanceType balanceType, boolean loadPowerFactorConstant, boolean useActiveLimits, + double slackBusPMaxMismatch, double areaInterchangePMaxMismatch) { + ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(balanceType, loadPowerFactorConstant, useActiveLimits); + return new AcAreaInterchangeControlOuterLoop(activePowerDistribution, slackBusPMaxMismatch, areaInterchangePMaxMismatch); + } + @Override public String getName() { return NAME; diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/DistributedSlackOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/DistributedSlackOuterLoop.java index 997ef7d3d3..38b3ff9d7d 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/DistributedSlackOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/DistributedSlackOuterLoop.java @@ -8,6 +8,7 @@ package com.powsybl.openloadflow.ac.outerloop; import com.powsybl.commons.report.ReportNode; +import com.powsybl.loadflow.LoadFlowParameters; import com.powsybl.openloadflow.OpenLoadFlowParameters; import com.powsybl.openloadflow.ac.AcLoadFlowContext; import com.powsybl.openloadflow.ac.AcLoadFlowParameters; @@ -48,6 +49,12 @@ public DistributedSlackOuterLoop(ActivePowerDistribution activePowerDistribution this.slackBusPMaxMismatch = slackBusPMaxMismatch; } + public static DistributedSlackOuterLoop create(LoadFlowParameters.BalanceType balanceType, boolean loadPowerFactorConstant, boolean useActiveLimits, + double slackBusPMaxMismatch) { + ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(balanceType, loadPowerFactorConstant, useActiveLimits); + return new DistributedSlackOuterLoop(activePowerDistribution, slackBusPMaxMismatch); + } + @Override public String getName() { return NAME; diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcAreaInterchangeControlOuterLoop.java b/src/main/java/com/powsybl/openloadflow/dc/DcAreaInterchangeControlOuterLoop.java index 46e4b149e6..7783ebf778 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/DcAreaInterchangeControlOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/dc/DcAreaInterchangeControlOuterLoop.java @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.dc; +import com.powsybl.loadflow.LoadFlowParameters; import com.powsybl.openloadflow.dc.equations.DcEquationType; import com.powsybl.openloadflow.dc.equations.DcVariableType; import com.powsybl.openloadflow.lf.outerloop.AbstractAreaInterchangeControlOuterLoop; @@ -28,6 +29,12 @@ public DcAreaInterchangeControlOuterLoop(ActivePowerDistribution activePowerDist super(activePowerDistribution, null, slackBusPMaxMismatch, areaInterchangePMaxMismatch, LOGGER); } + public static DcAreaInterchangeControlOuterLoop create(LoadFlowParameters.BalanceType balanceType, boolean loadPowerFactorConstant, boolean useActiveLimits, + double slackBusPMaxMismatch, double areaInterchangePMaxMismatch) { + ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(balanceType, loadPowerFactorConstant, useActiveLimits); + return new DcAreaInterchangeControlOuterLoop(activePowerDistribution, slackBusPMaxMismatch, areaInterchangePMaxMismatch); + } + @Override public String getName() { return "AreaInterchangeControl"; diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java index 3df28cb263..6f5c3a1753 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java @@ -515,19 +515,17 @@ private static void createBranches(List lfBuses, LfNetwork lfNetwork, LfT } private static void updateArea(Bus bus, LfBus lfBus, LfNetworkParameters parameters, LoadingContext loadingContext) { - if (parameters.isAreaInterchangeControl()) { - // Consider only the area type that should be used for area interchange control - Optional areaOpt = bus.getVoltageLevel().getArea(parameters.getAreaInterchangeControlAreaType()); - areaOpt.ifPresent(area -> - loadingContext.areaBusMap.computeIfAbsent(area, k -> { - area.getAreaBoundaryStream().forEach(boundary -> { - boundary.getTerminal().ifPresent(t -> loadingContext.areaTerminalMap.put(t, area)); - boundary.getBoundary().ifPresent(b -> loadingContext.areaTerminalMap.put(b.getDanglingLine().getTerminal(), area)); - }); - return new HashSet<>(); - }).add(lfBus) - ); - } + // Consider only the area type that should be used for area interchange control + Optional areaOpt = bus.getVoltageLevel().getArea(parameters.getAreaInterchangeControlAreaType()); + areaOpt.ifPresent(area -> + loadingContext.areaBusMap.computeIfAbsent(area, k -> { + area.getAreaBoundaryStream().forEach(boundary -> { + boundary.getTerminal().ifPresent(t -> loadingContext.areaTerminalMap.put(t, area)); + boundary.getBoundary().ifPresent(b -> loadingContext.areaTerminalMap.put(b.getDanglingLine().getTerminal(), area)); + }); + return new HashSet<>(); + }).add(lfBus) + ); } /** @@ -556,36 +554,34 @@ private static void addAreaBoundary(Terminal terminal, LfBranch branch, TwoSides } private static void createAreas(LfNetwork network, LoadingContext loadingContext, List postProcessors, LfNetworkParameters parameters) { - if (parameters.isAreaInterchangeControl()) { - loadingContext.areaBusMap - .entrySet() - .stream() - .filter(e -> { - if (e.getKey().getAreaBoundaryStream().findAny().isEmpty()) { - Reports.reportAreaNoInterchangeControl(network.getReportNode(), e.getKey().getId(), "Area does not have any area boundary"); - LOGGER.warn("Network {}: Area {} does not have any area boundary. The area will not be considered for area interchange control", network, e.getKey().getId()); - return false; - } - return true; - }) - .filter(e -> { - if (e.getKey().getInterchangeTarget().isEmpty()) { - Reports.reportAreaNoInterchangeControl(network.getReportNode(), e.getKey().getId(), "Area does not have an interchange target"); - LOGGER.warn("Network {}: Area {} does not have an interchange target. The area will not be considered for area interchange control", network, e.getKey().getId()); - return false; - } - return true; - }) - .filter(e -> checkBoundariesComponent(network, e.getKey())) - .forEach(e -> { - Area area = e.getKey(); - Set lfBuses = e.getValue(); - Set boundaries = loadingContext.areaBoundaries.getOrDefault(area, new HashSet<>()); - LfArea lfArea = LfAreaImpl.create(area, lfBuses, boundaries, network, parameters); - network.addArea(lfArea); - postProcessors.forEach(pp -> pp.onAreaAdded(area, lfArea)); - }); - } + loadingContext.areaBusMap + .entrySet() + .stream() + .filter(e -> { + if (e.getKey().getAreaBoundaryStream().findAny().isEmpty()) { + Reports.reportAreaNoInterchangeControl(network.getReportNode(), e.getKey().getId(), "Area does not have any area boundary"); + LOGGER.warn("Network {}: Area {} does not have any area boundary. The area will not be considered for area interchange control", network, e.getKey().getId()); + return false; + } + return true; + }) + .filter(e -> { + if (e.getKey().getInterchangeTarget().isEmpty()) { + Reports.reportAreaNoInterchangeControl(network.getReportNode(), e.getKey().getId(), "Area does not have an interchange target"); + LOGGER.warn("Network {}: Area {} does not have an interchange target. The area will not be considered for area interchange control", network, e.getKey().getId()); + return false; + } + return true; + }) + .filter(e -> checkBoundariesComponent(network, e.getKey())) + .forEach(e -> { + Area area = e.getKey(); + Set lfBuses = e.getValue(); + Set boundaries = loadingContext.areaBoundaries.getOrDefault(area, new HashSet<>()); + LfArea lfArea = LfAreaImpl.create(area, lfBuses, boundaries, network, parameters); + network.addArea(lfArea); + postProcessors.forEach(pp -> pp.onAreaAdded(area, lfArea)); + }); } private static boolean checkBoundariesComponent(LfNetwork network, Area area) { diff --git a/src/main/java/com/powsybl/openloadflow/sa/AbstractSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/AbstractSecurityAnalysis.java index 67cdaede23..3708fa905b 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/AbstractSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/AbstractSecurityAnalysis.java @@ -20,6 +20,14 @@ import com.powsybl.loadflow.LoadFlowResult; import com.powsybl.math.matrix.MatrixFactory; import com.powsybl.openloadflow.OpenLoadFlowParameters; +import com.powsybl.openloadflow.ac.AcLoadFlowParameters; +import com.powsybl.openloadflow.ac.outerloop.AcActivePowerDistributionOuterLoop; +import com.powsybl.openloadflow.ac.outerloop.AcAreaInterchangeControlOuterLoop; +import com.powsybl.openloadflow.ac.outerloop.AcOuterLoop; +import com.powsybl.openloadflow.ac.outerloop.DistributedSlackOuterLoop; +import com.powsybl.openloadflow.dc.DcAreaInterchangeControlOuterLoop; +import com.powsybl.openloadflow.dc.DcLoadFlowParameters; +import com.powsybl.openloadflow.dc.DcOuterLoop; import com.powsybl.openloadflow.equations.Quantity; import com.powsybl.openloadflow.graph.GraphConnectivityFactory; import com.powsybl.openloadflow.lf.AbstractLoadFlowParameters; @@ -28,6 +36,7 @@ import com.powsybl.openloadflow.network.*; import com.powsybl.openloadflow.network.impl.*; import com.powsybl.openloadflow.network.util.ActivePowerDistribution; +import com.powsybl.openloadflow.sa.extensions.ContingencyLoadFlowParameters; import com.powsybl.openloadflow.util.Lists2; import com.powsybl.openloadflow.util.PerUnit; import com.powsybl.openloadflow.util.Reports; @@ -49,6 +58,7 @@ import java.util.concurrent.*; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; @@ -605,9 +615,10 @@ protected static void findAllBranchesToClose(Network network, List actio } protected static void distributedMismatch(LfNetwork network, double mismatch, LoadFlowParameters loadFlowParameters, - OpenLoadFlowParameters openLoadFlowParameters) { - if (loadFlowParameters.isDistributedSlack() && Math.abs(mismatch) > 0) { - ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(loadFlowParameters.getBalanceType(), openLoadFlowParameters.isLoadPowerFactorConstant(), openLoadFlowParameters.isUseActiveLimits()); + OpenLoadFlowParameters openLoadFlowParameters, ContingencyLoadFlowParameters contingencyParameters) { + ContingencyLoadFlowParameters parameters = Objects.requireNonNullElse(contingencyParameters, new ContingencyLoadFlowParameters(loadFlowParameters.isDistributedSlack(), openLoadFlowParameters.isAreaInterchangeControl(), loadFlowParameters.getBalanceType())); + if ((parameters.isDistributedSlack() || parameters.isAreaInterchangeControl()) && Math.abs(mismatch) > 0) { + ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(parameters.getBalanceType(), openLoadFlowParameters.isLoadPowerFactorConstant(), openLoadFlowParameters.isUseActiveLimits()); activePowerDistribution.run(network, mismatch); } } @@ -669,9 +680,12 @@ protected SecurityAnalysisResult runSimulations(LfNetwork lfNetwork, List parametersResetter = applyContingencyParameters(context.getParameters(), contingencyLoadFlowParameters, openLoadFlowParameters); + lfContingency.apply(loadFlowParameters.getBalanceType()); - distributedMismatch(lfNetwork, lfContingency.getActivePowerLoss(), loadFlowParameters, openLoadFlowParameters); + distributedMismatch(lfNetwork, lfContingency.getActivePowerLoss(), loadFlowParameters, openLoadFlowParameters, contingencyLoadFlowParameters); var postContingencyResult = runPostContingencySimulation(lfNetwork, context, propagatedContingency.getContingency(), lfContingency, preContingencyLimitViolationManager, @@ -713,7 +727,7 @@ protected SecurityAnalysisResult runSimulations(LfNetwork lfNetwork, List applyContingencyParameters(P parameters, ContingencyLoadFlowParameters contingencyLoadFlowParameters, OpenLoadFlowParameters parametersExt) { + if (contingencyLoadFlowParameters != null) { + if (parameters instanceof DcLoadFlowParameters dcLoadFlowParameters) { + return applyDcContingencyLoadFlowParameters(dcLoadFlowParameters, parametersExt, contingencyLoadFlowParameters); + } else if (parameters instanceof AcLoadFlowParameters acLoadFlowParameters) { + return applyAcContingencyLoadFlowParameters(acLoadFlowParameters, parametersExt, contingencyLoadFlowParameters); + } else { + LOGGER.error("Unsupported load flow parameters type {} to apply contingency parameters", parameters.getClass()); + } + } + return p -> {}; + } + + private Consumer

applyAcContingencyLoadFlowParameters(AcLoadFlowParameters acLoadFlowParameters, OpenLoadFlowParameters parametersExt, ContingencyLoadFlowParameters contingencyLoadFlowParameters) { + List oldOuterLoops = acLoadFlowParameters.getOuterLoops(); + List newOuterLoops = new ArrayList<>(oldOuterLoops.stream().filter(o -> !(o instanceof AcActivePowerDistributionOuterLoop)).toList()); + if (contingencyLoadFlowParameters.isAreaInterchangeControl()) { + AcAreaInterchangeControlOuterLoop outerLoop = AcAreaInterchangeControlOuterLoop.create(contingencyLoadFlowParameters.getBalanceType(), parametersExt.isLoadPowerFactorConstant(), parametersExt.isUseActiveLimits(), + parametersExt.getSlackBusPMaxMismatch(), parametersExt.getAreaInterchangePMaxMismatch()); + newOuterLoops.add(outerLoop); + } else if (contingencyLoadFlowParameters.isDistributedSlack()) { + DistributedSlackOuterLoop outerLoop = DistributedSlackOuterLoop.create(contingencyLoadFlowParameters.getBalanceType(), parametersExt.isLoadPowerFactorConstant(), parametersExt.isUseActiveLimits(), + parametersExt.getSlackBusPMaxMismatch()); + newOuterLoops.add(outerLoop); + } + + acLoadFlowParameters.setOuterLoops(newOuterLoops); + return p -> ((AcLoadFlowParameters) p).setOuterLoops(oldOuterLoops); + } + + private Consumer

applyDcContingencyLoadFlowParameters(DcLoadFlowParameters dcLoadFlowParameters, OpenLoadFlowParameters parametersExt, ContingencyLoadFlowParameters contingencyLoadFlowParameters) { + boolean oldDistributedSlack = dcLoadFlowParameters.isDistributedSlack(); + List oldOuterLoops = dcLoadFlowParameters.getOuterLoops(); + + List newOuterLoops = new ArrayList<>(oldOuterLoops.stream().filter(o -> !(o instanceof DcAreaInterchangeControlOuterLoop)).toList()); + if (contingencyLoadFlowParameters.isAreaInterchangeControl()) { + DcAreaInterchangeControlOuterLoop outerLoop = DcAreaInterchangeControlOuterLoop.create(contingencyLoadFlowParameters.getBalanceType(), parametersExt.isLoadPowerFactorConstant(), parametersExt.isUseActiveLimits(), + parametersExt.getSlackBusPMaxMismatch(), parametersExt.getAreaInterchangePMaxMismatch()); + newOuterLoops.add(outerLoop); + } else if (contingencyLoadFlowParameters.isDistributedSlack()) { + dcLoadFlowParameters.setDistributedSlack(true); + } + dcLoadFlowParameters.setOuterLoops(newOuterLoops); + return p -> { + ((DcLoadFlowParameters) p).setDistributedSlack(oldDistributedSlack); + ((DcLoadFlowParameters) p).setOuterLoops(oldOuterLoops); + }; + } + private Optional runActionSimulation(LfNetwork network, C context, OperatorStrategy operatorStrategy, LimitViolationManager preContingencyLimitViolationManager, SecurityAnalysisParameters.IncreasedViolationsParameters violationsParameters, diff --git a/src/test/java/com/powsybl/openloadflow/network/MultiAreaNetworkFactory.java b/src/test/java/com/powsybl/openloadflow/network/MultiAreaNetworkFactory.java index be949f061d..bcc6872f43 100644 --- a/src/test/java/com/powsybl/openloadflow/network/MultiAreaNetworkFactory.java +++ b/src/test/java/com/powsybl/openloadflow/network/MultiAreaNetworkFactory.java @@ -263,9 +263,9 @@ public static Network createTwoAreasWithDanglingLine() { /** * g1 100 MW gen3 40MW * | | - * b1 ---(l12)--- b2 ---(dlA1)----< >----(dlA2)--- b3 + * b1 ---(l12)--- b2 ---(dlA1)----< >----(dlA2)--- b3 ---(l34)--- b4 --- load4 30MW * | | - * load1 60MW load3 50MW + * load1 60MW load3 20MW * <-------------------------------> <---------------------> * Area 1 Area 2 */ @@ -313,17 +313,22 @@ public static Network createTwoAreasWithTieLine() { .setBoundary(dl2.getBoundary()) .setAc(true) .add(); + Bus b4 = createBus(network, "b4", 400); + network.getArea("a2").addVoltageLevel(b4.getVoltageLevel()); + network.getLoad("load3").setP0(20); + createLoad(b4, "load4", 30); + createLine(network, network.getBusBreakerView().getBus("b3"), b4, "l34", 0.2); return network; } /** * g1 100 MW gen3 40MW * | | - * b1 ---(l12)--- b2 ---(dlA1)----< >----(dlA2)--- b3 + * b1 ---(l12)--- b2 ---(dlA1)----< >----(dlA2)--- b3 ---(l34)--- b4 --- load4 30MW * | | | - * load1 60MW | load3 50MW + * load1 60MW | load3 20MW * | - * + ---(dlA1_1)---< >---(dlA1_2)--- b4 -- gen4 5 MW + * + ---(dlA1_1)---< >---(dlA1_2)--- b5 -- gen5 5 MW * <-------------------------------> <---------------------> * Area 1 Area 2 * The second tie line is not considered in Areas' boundaries. @@ -343,21 +348,12 @@ public static Network createTwoAreasWithUnconsideredTieLine() { .setQ0(0) .setPairingKey("tlA1A2_2") .add(); - Substation s4 = network.newSubstation() - .setId("S4") - .add(); - VoltageLevel vl4 = s4.newVoltageLevel() - .setId("vl4") - .setNominalV(400) - .setTopologyKind(TopologyKind.BUS_BREAKER) - .add(); - vl4.getBusBreakerView().newBus() - .setId("b4") - .add(); - vl4.newGenerator() - .setId("gen4") - .setConnectableBus("b4") - .setBus("b4") + Bus b5 = createBus(network, "S5", "b5", 400); + VoltageLevel vl5 = b5.getVoltageLevel(); + vl5.newGenerator() + .setId("gen5") + .setConnectableBus("b5") + .setBus("b5") .setTargetP(5) .setTargetQ(0) .setTargetV(400) @@ -365,10 +361,10 @@ public static Network createTwoAreasWithUnconsideredTieLine() { .setMaxP(30) .setVoltageRegulatorOn(true) .add(); - vl4.newDanglingLine() + vl5.newDanglingLine() .setId("dlA1_2") - .setConnectableBus("b4") - .setBus("b4") + .setConnectableBus("b5") + .setBus("b5") .setR(0) .setX(1) .setG(0) @@ -384,21 +380,13 @@ public static Network createTwoAreasWithUnconsideredTieLine() { .setDanglingLine2("dlA1_2") .add(); network.getArea("a2") - .addVoltageLevel(vl4); - network.newLine() - .setId("l24") - .setBus1("b2") - .setBus2("b4") - .setR(0) - .setX(1) - .add(); + .addVoltageLevel(vl5); return network; } /** * same as createTwoAreasWithTieLine but with a small dummy island and a2 has a boundary in it. */ - public static Network createAreaTwoComponents() { Network network = createTwoAreasWithTieLine(); // create dummy bus in another island diff --git a/src/test/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImplTest.java b/src/test/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImplTest.java index 92b223a748..e2430f24a1 100644 --- a/src/test/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImplTest.java +++ b/src/test/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImplTest.java @@ -124,13 +124,6 @@ void networkWithControlAreasTest() { List lfNetworks = Networks.load(network, parameters); assertEquals(1, lfNetworks.size()); LfNetwork mainNetwork = lfNetworks.get(0); - assertFalse(mainNetwork.hasArea()); - - parameters.setAreaInterchangeControl(true); - - lfNetworks = Networks.load(network, parameters); - assertEquals(1, lfNetworks.size()); - mainNetwork = lfNetworks.get(0); LfArea lfArea = mainNetwork.getAreaById("ControlArea_A"); // The area is not of 'ControlArea' type, so it is not created assertNull(mainNetwork.getAreaById("Region_AB")); diff --git a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisWithActionsTest.java b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisWithActionsTest.java index f38be37da7..7d1170221e 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisWithActionsTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisWithActionsTest.java @@ -21,6 +21,7 @@ import com.powsybl.openloadflow.graph.GraphConnectivityFactory; import com.powsybl.openloadflow.graph.NaiveGraphConnectivityFactory; import com.powsybl.openloadflow.network.*; +import com.powsybl.openloadflow.sa.extensions.ContingencyLoadFlowParameters; import com.powsybl.openloadflow.util.LoadFlowAssert; import com.powsybl.security.*; import com.powsybl.security.condition.AllViolationCondition; @@ -1667,4 +1668,40 @@ void testOperatorStrategyNoMoreBusVoltageControlled() throws IOException { assertReportEquals("/saReportOperatorStrategyNoVoltageControl.txt", reportNode); } + + @Test + void testContingencyParameters() { + Network network = MultiAreaNetworkFactory.createTwoAreasWithTieLine(); + Contingency contingency1 = new Contingency("load3", new LoadContingency("load3")); + ContingencyLoadFlowParameters contingencyParameters1 = new ContingencyLoadFlowParameters(false, true, LoadFlowParameters.BalanceType.PROPORTIONAL_TO_LOAD); + contingency1.addExtension(ContingencyLoadFlowParameters.class, contingencyParameters1); + Action action1 = new GeneratorActionBuilder().withId("action1").withGeneratorId("gen3").withActivePowerRelativeValue(false).withActivePowerValue(45).build(); + + OperatorStrategy operatorStrategy1 = new OperatorStrategy("strategy1", ContingencyContext.specificContingency("load3"), new TrueCondition(), List.of("action1")); + List monitors = createAllBranchesMonitors(network); + + List contingencies = List.of(contingency1); + List actions = List.of(action1); + List operatorStrategies = List.of(operatorStrategy1); + + LoadFlowParameters parameters = new LoadFlowParameters(); + parameters.setDistributedSlack(true); + parameters.setConnectedComponentMode(LoadFlowParameters.ConnectedComponentMode.ALL); + SecurityAnalysisParameters securityAnalysisParameters = new SecurityAnalysisParameters(); + securityAnalysisParameters.setLoadFlowParameters(parameters); + SecurityAnalysisResult resultAc = runSecurityAnalysis(network, contingencies, monitors, securityAnalysisParameters, + operatorStrategies, actions, ReportNode.NO_OP); + + PreContingencyResult preContingencyResult = resultAc.getPreContingencyResult(); + assertEquals(25, preContingencyResult.getNetworkResult().getBranchResult("tl1").getP1(), LoadFlowAssert.DELTA_POWER); + assertEquals(30, preContingencyResult.getNetworkResult().getBranchResult("l34").getP1(), LoadFlowAssert.DELTA_POWER); + + PostContingencyResult postContingencyResult = getPostContingencyResult(resultAc, "load3"); + assertEquals(50, postContingencyResult.getNetworkResult().getBranchResult("tl1").getP1(), LoadFlowAssert.DELTA_POWER); + assertEquals(75, postContingencyResult.getNetworkResult().getBranchResult("l34").getP1(), LoadFlowAssert.DELTA_POWER); + + OperatorStrategyResult acStrategyResult = getOperatorStrategyResult(resultAc, "strategy1"); + assertEquals(50, acStrategyResult.getNetworkResult().getBranchResult("tl1").getP1(), LoadFlowAssert.DELTA_POWER); + assertEquals(95, acStrategyResult.getNetworkResult().getBranchResult("l34").getP1(), LoadFlowAssert.DELTA_POWER); + } }