diff --git a/src/main/java/com/powsybl/openloadflow/AcLoadFlowFromCache.java b/src/main/java/com/powsybl/openloadflow/AcLoadFlowFromCache.java index a829a78a6a..43038c51f2 100644 --- a/src/main/java/com/powsybl/openloadflow/AcLoadFlowFromCache.java +++ b/src/main/java/com/powsybl/openloadflow/AcLoadFlowFromCache.java @@ -17,7 +17,7 @@ import com.powsybl.openloadflow.ac.nr.NewtonRaphsonStatus; import com.powsybl.openloadflow.lf.outerloop.OuterLoopStatus; import com.powsybl.openloadflow.network.impl.LfNetworkList; -import com.powsybl.openloadflow.network.impl.LfTopoConfig; +import com.powsybl.openloadflow.network.LfTopoConfig; import com.powsybl.openloadflow.network.impl.Networks; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/com/powsybl/openloadflow/network/LfAction.java b/src/main/java/com/powsybl/openloadflow/network/LfAction.java index 9b971bf622..ea0cda0305 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfAction.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfAction.java @@ -126,6 +126,9 @@ public static Optional create(Action action, LfNetwork lfNetwork, Netw case PhaseTapChangerTapPositionAction.NAME: return create((PhaseTapChangerTapPositionAction) action, lfNetwork); + case RatioTapChangerTapPositionAction.NAME: + return create((RatioTapChangerTapPositionAction) action, lfNetwork); + case LoadAction.NAME: return create((LoadAction) action, lfNetwork, network, breakers); @@ -185,12 +188,22 @@ private static Optional create(LoadAction action, LfNetwork lfNetwork, private static Optional create(PhaseTapChangerTapPositionAction action, LfNetwork lfNetwork) { String branchId = action.getSide().map(side -> LfLegBranch.getId(side, action.getTransformerId())).orElseGet(action::getTransformerId); LfBranch branch = lfNetwork.getBranchById(branchId); + return create(branch, action.getId(), action.isRelativeValue(), action.getTapPosition(), lfNetwork); + } + + private static Optional create(RatioTapChangerTapPositionAction action, LfNetwork lfNetwork) { + String branchId = action.getSide().map(side -> LfLegBranch.getId(side, action.getTransformerId())).orElseGet(action::getTransformerId); + LfBranch branch = lfNetwork.getBranchById(branchId); + return create(branch, action.getId(), action.isRelativeValue(), action.getTapPosition(), lfNetwork); + } + + private static Optional create(LfBranch branch, String actionId, boolean isRelative, int tapPosition, LfNetwork lfNetwork) { if (branch != null) { if (branch.getPiModel() instanceof SimplePiModel) { - throw new UnsupportedOperationException("Phase tap changer tap connection action: only one tap in branch " + branch.getId()); + throw new UnsupportedOperationException("Tap position action: only one tap in branch " + branch.getId()); } else { - var tapPositionChange = new TapPositionChange(branch, action.getTapPosition(), action.isRelativeValue()); - return Optional.of(new LfAction(action.getId(), null, null, tapPositionChange, null, null, null)); + var tapPositionChange = new TapPositionChange(branch, tapPosition, isRelative); + return Optional.of(new LfAction(actionId, null, null, tapPositionChange, null, null, null)); } } return Optional.empty(); // could be in another component diff --git a/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java b/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java index 731ac86ad3..9ea6199ea3 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java @@ -561,15 +561,15 @@ public static List load(T network, LfNetworkLoader networkLoad return load(network, networkLoader, parameters, Reporter.NO_OP); } - public static List load(T network, LfNetworkLoader networkLoader, SlackBusSelector slackBusSelector, Reporter reporter) { - return load(network, networkLoader, new LfNetworkParameters().setSlackBusSelector(slackBusSelector), reporter); + public static List load(T network, LfNetworkLoader networkLoader, LfNetworkParameters parameters, Reporter reporter) { + return load(network, networkLoader, new LfTopoConfig(), parameters, reporter); } - public static List load(T network, LfNetworkLoader networkLoader, LfNetworkParameters parameters, Reporter reporter) { + public static List load(T network, LfNetworkLoader networkLoader, LfTopoConfig topoConfig, LfNetworkParameters parameters, Reporter reporter) { Objects.requireNonNull(network); Objects.requireNonNull(networkLoader); Objects.requireNonNull(parameters); - List lfNetworks = networkLoader.load(network, parameters, reporter); + List lfNetworks = networkLoader.load(network, topoConfig, parameters, reporter); for (LfNetwork lfNetwork : lfNetworks) { Reporter reporterNetwork = Reports.createPostLoadingProcessingReporter(lfNetwork.getReporter()); lfNetwork.fix(parameters.isMinImpedance(), parameters.getLowImpedanceThreshold()); diff --git a/src/main/java/com/powsybl/openloadflow/network/LfNetworkLoader.java b/src/main/java/com/powsybl/openloadflow/network/LfNetworkLoader.java index 7617c69792..d2796fb289 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfNetworkLoader.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfNetworkLoader.java @@ -24,5 +24,5 @@ public interface LfNetworkLoader { * components number (hence sorted by descending connected components size then by descending synchronous components * size) */ - List load(T network, LfNetworkParameters parameters, Reporter reporter); + List load(T network, LfTopoConfig topoConfig, LfNetworkParameters parameters, Reporter reporter); } diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfTopoConfig.java b/src/main/java/com/powsybl/openloadflow/network/LfTopoConfig.java similarity index 61% rename from src/main/java/com/powsybl/openloadflow/network/impl/LfTopoConfig.java rename to src/main/java/com/powsybl/openloadflow/network/LfTopoConfig.java index d77733c781..99e9cb99c5 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfTopoConfig.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfTopoConfig.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.openloadflow.network.impl; +package com.powsybl.openloadflow.network; import com.powsybl.iidm.network.Switch; @@ -22,6 +22,10 @@ public class LfTopoConfig { private final Set busIdsToLose = new HashSet<>(); + private final Set branchIdsWithPtcToRetain = new HashSet<>(); + + private final Set branchIdsWithRtcToRetain = new HashSet<>(); + public Set getSwitchesToOpen() { return switchesToOpen; } @@ -34,7 +38,23 @@ public Set getBusIdsToLose() { return busIdsToLose; } + public void addBranchIdsWithPtcToRetain(String branchId) { + branchIdsWithPtcToRetain.add(branchId); + } + + public void addBranchIdsWithRtcToRetain(String branchId) { + branchIdsWithRtcToRetain.add(branchId); + } + public boolean isBreaker() { return !(switchesToOpen.isEmpty() && switchesToClose.isEmpty() && busIdsToLose.isEmpty()); } + + public boolean isRetainedPtc(String branchId) { + return branchIdsWithPtcToRetain.contains(branchId); + } + + public boolean isRetainedRtc(String branchId) { + return branchIdsWithRtcToRetain.contains(branchId); + } } diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfBranchImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfBranchImpl.java index de6e5fdaff..c19acc876b 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfBranchImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfBranchImpl.java @@ -113,7 +113,7 @@ private static LfBranchImpl createLine(Line line, LfNetwork network, LfBus bus1, } private static LfBranchImpl createTransformer(TwoWindingsTransformer twt, LfNetwork network, LfBus bus1, LfBus bus2, - LfNetworkParameters parameters) { + boolean retainPtc, boolean retainRtc, LfNetworkParameters parameters) { PiModel piModel = null; double baseRatio = Transformers.getRatioPerUnitBase(twt); @@ -122,8 +122,8 @@ private static LfBranchImpl createTransformer(TwoWindingsTransformer twt, LfNetw PhaseTapChanger ptc = twt.getPhaseTapChanger(); if (ptc != null - && ptc.isRegulating() - && ptc.getRegulationMode() != PhaseTapChanger.RegulationMode.FIXED_TAP) { + && (ptc.isRegulating() + && ptc.getRegulationMode() != PhaseTapChanger.RegulationMode.FIXED_TAP || retainPtc)) { // we have a phase control, whatever we also have a voltage control or not, we create a pi model array // based on phase taps mixed with voltage current tap Integer rtcPosition = Transformers.getCurrentPosition(twt.getRatioTapChanger()); @@ -136,7 +136,7 @@ private static LfBranchImpl createTransformer(TwoWindingsTransformer twt, LfNetw } RatioTapChanger rtc = twt.getRatioTapChanger(); - if (rtc != null && rtc.isRegulating() && rtc.hasLoadTapChangingCapabilities()) { + if (rtc != null && (rtc.isRegulating() && rtc.hasLoadTapChangingCapabilities() || retainRtc)) { if (piModel == null) { // we have a voltage control, we create a pi model array based on voltage taps mixed with phase current // tap @@ -162,14 +162,16 @@ private static LfBranchImpl createTransformer(TwoWindingsTransformer twt, LfNetw return new LfBranchImpl(network, bus1, bus2, piModel, twt, parameters); } - public static LfBranchImpl create(Branch branch, LfNetwork network, LfBus bus1, LfBus bus2, LfNetworkParameters parameters) { + public static LfBranchImpl create(Branch branch, LfNetwork network, LfBus bus1, LfBus bus2, LfTopoConfig topoConfig, + LfNetworkParameters parameters) { Objects.requireNonNull(branch); Objects.requireNonNull(network); Objects.requireNonNull(parameters); if (branch instanceof Line line) { return createLine(line, network, bus1, bus2, parameters); } else if (branch instanceof TwoWindingsTransformer twt) { - return createTransformer(twt, network, bus1, bus2, parameters); + return createTransformer(twt, network, bus1, bus2, topoConfig.isRetainedPtc(twt.getId()), + topoConfig.isRetainedRtc(twt.getId()), parameters); } else { throw new PowsyblException("Unsupported type of branch for flow equations of branch: " + branch.getId()); } diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfLegBranch.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfLegBranch.java index 0bb5b6102c..c01fc3b255 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfLegBranch.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfLegBranch.java @@ -39,8 +39,8 @@ private ThreeWindingsTransformer.Leg getLeg() { return legRef.get(); } - public static LfLegBranch create(LfNetwork network, LfBus bus1, LfBus bus0, ThreeWindingsTransformer twt, ThreeWindingsTransformer.Leg leg, - LfNetworkParameters parameters) { + public static LfLegBranch create(LfNetwork network, LfBus bus1, LfBus bus0, ThreeWindingsTransformer twt, + ThreeWindingsTransformer.Leg leg, boolean retainPtc, boolean retainRtc, LfNetworkParameters parameters) { Objects.requireNonNull(bus0); Objects.requireNonNull(twt); Objects.requireNonNull(leg); @@ -52,8 +52,8 @@ public static LfLegBranch create(LfNetwork network, LfBus bus1, LfBus bus0, Thre double baseRatio = Transformers.getRatioPerUnitBase(leg, twt); PhaseTapChanger ptc = leg.getPhaseTapChanger(); if (ptc != null - && ptc.isRegulating() - && ptc.getRegulationMode() != PhaseTapChanger.RegulationMode.FIXED_TAP) { + && (ptc.isRegulating() + && ptc.getRegulationMode() != PhaseTapChanger.RegulationMode.FIXED_TAP || retainPtc)) { // we have a phase control, whatever we also have a voltage control or not, we create a pi model array // based on phase taps mixed with voltage current tap Integer rtcPosition = Transformers.getCurrentPosition(leg.getRatioTapChanger()); @@ -66,7 +66,7 @@ public static LfLegBranch create(LfNetwork network, LfBus bus1, LfBus bus0, Thre } RatioTapChanger rtc = leg.getRatioTapChanger(); - if (rtc != null && rtc.isRegulating() && rtc.hasLoadTapChangingCapabilities()) { + if (rtc != null && (rtc.isRegulating() && rtc.hasLoadTapChangingCapabilities() || retainRtc)) { if (piModel == null) { // we have a voltage control, we create a pi model array based on voltage taps mixed with phase current // tap 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 c2882d5467..7b5b214247 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java @@ -360,12 +360,13 @@ private static void addBranch(LfNetwork lfNetwork, LfBranch lfBranch, LfNetworkL } } - private static void createBranches(List lfBuses, LfNetwork lfNetwork, LoadingContext loadingContext, LfNetworkLoadingReport report, - LfNetworkParameters parameters, List postProcessors) { + private static void createBranches(List lfBuses, LfNetwork lfNetwork, LfTopoConfig topoConfig, LoadingContext loadingContext, + LfNetworkLoadingReport report, LfNetworkParameters parameters, + List postProcessors) { for (Branch branch : loadingContext.branchSet) { LfBus lfBus1 = getLfBus(branch.getTerminal1(), lfNetwork, parameters.isBreakers()); LfBus lfBus2 = getLfBus(branch.getTerminal2(), lfNetwork, parameters.isBreakers()); - LfBranchImpl lfBranch = LfBranchImpl.create(branch, lfNetwork, lfBus1, lfBus2, parameters); + LfBranchImpl lfBranch = LfBranchImpl.create(branch, lfNetwork, lfBus1, lfBus2, topoConfig, parameters); addBranch(lfNetwork, lfBranch, report); postProcessors.forEach(pp -> pp.onBranchAdded(branch, lfBranch)); } @@ -393,27 +394,23 @@ private static void createBranches(List lfBuses, LfNetwork lfNetwork, Loa pp.onBusAdded(danglingLine, lfBus2); pp.onBranchAdded(danglingLine, lfBranch); }); - }); + }); } for (ThreeWindingsTransformer t3wt : loadingContext.t3wtSet) { LfStarBus lfBus0 = new LfStarBus(lfNetwork, t3wt, parameters); lfNetwork.addBus(lfBus0); - LfBus lfBus1 = getLfBus(t3wt.getLeg1().getTerminal(), lfNetwork, parameters.isBreakers()); - LfBus lfBus2 = getLfBus(t3wt.getLeg2().getTerminal(), lfNetwork, parameters.isBreakers()); - LfBus lfBus3 = getLfBus(t3wt.getLeg3().getTerminal(), lfNetwork, parameters.isBreakers()); - LfLegBranch lfBranch1 = LfLegBranch.create(lfNetwork, lfBus1, lfBus0, t3wt, t3wt.getLeg1(), parameters); - LfLegBranch lfBranch2 = LfLegBranch.create(lfNetwork, lfBus2, lfBus0, t3wt, t3wt.getLeg2(), parameters); - LfLegBranch lfBranch3 = LfLegBranch.create(lfNetwork, lfBus3, lfBus0, t3wt, t3wt.getLeg3(), parameters); - addBranch(lfNetwork, lfBranch1, report); - addBranch(lfNetwork, lfBranch2, report); - addBranch(lfNetwork, lfBranch3, report); - postProcessors.forEach(pp -> { - pp.onBusAdded(t3wt, lfBus0); - pp.onBranchAdded(t3wt, lfBranch1); - pp.onBranchAdded(t3wt, lfBranch2); - pp.onBranchAdded(t3wt, lfBranch3); - }); + postProcessors.forEach(pp -> pp.onBusAdded(t3wt, lfBus0)); + for (ThreeWindingsTransformer.Side side : ThreeWindingsTransformer.Side.values()) { + ThreeWindingsTransformer.Leg leg = t3wt.getLeg(side); + LfBus lfBus = getLfBus(leg.getTerminal(), lfNetwork, parameters.isBreakers()); + LfLegBranch lfBranch = LfLegBranch.create(lfNetwork, lfBus, lfBus0, t3wt, leg, + topoConfig.isRetainedPtc(LfLegBranch.getId(side, t3wt.getId())), + topoConfig.isRetainedRtc(LfLegBranch.getId(side, t3wt.getId())), + parameters); + addBranch(lfNetwork, lfBranch, report); + postProcessors.forEach(pp -> pp.onBranchAdded(t3wt, lfBranch)); + } } if (parameters.isPhaseControl()) { @@ -648,7 +645,7 @@ private static LfBus getLfBus(Terminal terminal, LfNetwork lfNetwork, boolean br return bus != null ? lfNetwork.getBusById(bus.getId()) : null; } - private LfNetwork create(int numCC, int numSC, Network network, List buses, List switches, LfNetworkParameters parameters, Reporter reporter) { + private LfNetwork create(int numCC, int numSC, Network network, List buses, List switches, LfTopoConfig topoConfig, LfNetworkParameters parameters, Reporter reporter) { LfNetwork lfNetwork = new LfNetwork(numCC, numSC, parameters.getSlackBusSelector(), parameters.getMaxSlackBusCount(), parameters.getConnectivityFactory(), reporter); @@ -661,7 +658,7 @@ private LfNetwork create(int numCC, int numSC, Network network, List buses, List lfBuses = new ArrayList<>(); createBuses(buses, parameters, lfNetwork, lfBuses, loadingContext, report, postProcessors); - createBranches(lfBuses, lfNetwork, loadingContext, report, parameters, postProcessors); + createBranches(lfBuses, lfNetwork, topoConfig, loadingContext, report, parameters, postProcessors); if (parameters.getLoadFlowModel() == LoadFlowModel.AC) { createVoltageControls(lfBuses, parameters); @@ -849,7 +846,7 @@ private static void createVoltageAngleLimits(Network network, LfNetwork lfNetwor } @Override - public List load(Network network, LfNetworkParameters parameters, Reporter reporter) { + public List load(Network network, LfTopoConfig topoConfig, LfNetworkParameters parameters, Reporter reporter) { Objects.requireNonNull(network); Objects.requireNonNull(parameters); @@ -895,8 +892,8 @@ public List load(Network network, LfNetworkParameters parameters, Rep int numCc = networkKey.getLeft(); int numSc = networkKey.getRight(); List lfBuses = e.getValue(); - return create(numCc, numSc, network, lfBuses, switchesByCc.get(networkKey), parameters, - Reports.createLfNetworkReporter(reporter, numCc, numSc)); + return create(numCc, numSc, network, lfBuses, switchesByCc.get(networkKey), topoConfig, + parameters, Reports.createLfNetworkReporter(reporter, numCc, numSc)); }) .collect(Collectors.toList()); diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java index f8b3d3cea7..46d15c1628 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java @@ -106,6 +106,10 @@ public static List load(Network network, LfNetworkParameters paramete return LfNetwork.load(network, new LfNetworkLoaderImpl(), parameters, reporter); } + public static List load(Network network, LfTopoConfig topoConfig, LfNetworkParameters parameters, Reporter reporter) { + return LfNetwork.load(network, new LfNetworkLoaderImpl(), topoConfig, parameters, reporter); + } + private static void retainAndCloseNecessarySwitches(Network network, LfTopoConfig topoConfig) { network.getSwitchStream() .filter(sw -> sw.getVoltageLevel().getTopologyKind() == TopologyKind.NODE_BREAKER) @@ -145,7 +149,7 @@ public static LfNetworkList load(Network network, LfNetworkParameters networkPar public static LfNetworkList load(Network network, LfNetworkParameters networkParameters, LfTopoConfig topoConfig, LfNetworkList.VariantCleanerFactory variantCleanerFactory, Reporter reporter) { if (!topoConfig.isBreaker()) { - return new LfNetworkList(load(network, networkParameters, reporter)); + return new LfNetworkList(load(network, topoConfig, networkParameters, reporter)); } else { if (!networkParameters.isBreakers()) { throw new PowsyblException("LF networks have to be built from bus/breaker view"); @@ -160,7 +164,7 @@ public static LfNetworkList load(Network network, LfNetworkParameters networkPar // and close switches that could be closed during the simulation retainAndCloseNecessarySwitches(network, topoConfig); - List lfNetworks = load(network, networkParameters, reporter); + List lfNetworks = load(network, topoConfig, networkParameters, reporter); if (!topoConfig.getSwitchesToClose().isEmpty()) { for (LfNetwork lfNetwork : lfNetworks) { diff --git a/src/main/java/com/powsybl/openloadflow/sa/AbstractSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/AbstractSecurityAnalysis.java index b6dd4d992e..2d9096a578 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/AbstractSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/AbstractSecurityAnalysis.java @@ -12,8 +12,7 @@ import com.powsybl.computation.CompletableFutureTask; import com.powsybl.computation.ComputationManager; import com.powsybl.contingency.ContingenciesProvider; -import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.Switch; +import com.powsybl.iidm.network.*; import com.powsybl.loadflow.LoadFlowResult; import com.powsybl.math.matrix.MatrixFactory; import com.powsybl.openloadflow.ac.nr.NewtonRaphsonStatus; @@ -22,7 +21,7 @@ import com.powsybl.openloadflow.lf.AbstractLoadFlowParameters; import com.powsybl.openloadflow.lf.LoadFlowContext; import com.powsybl.openloadflow.network.*; -import com.powsybl.openloadflow.network.impl.LfTopoConfig; +import com.powsybl.openloadflow.network.impl.LfLegBranch; import com.powsybl.openloadflow.network.impl.PropagatedContingency; import com.powsybl.security.*; import com.powsybl.security.action.*; @@ -128,11 +127,13 @@ protected static void checkActions(Network network, List actions) { break; } - case PhaseTapChangerTapPositionAction.NAME: { - PhaseTapChangerTapPositionAction phaseTapChangerTapPositionAction = (PhaseTapChangerTapPositionAction) action; - if (network.getTwoWindingsTransformer(phaseTapChangerTapPositionAction.getTransformerId()) == null - && network.getThreeWindingsTransformer(phaseTapChangerTapPositionAction.getTransformerId()) == null) { - throw new PowsyblException("Transformer '" + phaseTapChangerTapPositionAction.getTransformerId() + NOT_FOUND); + case PhaseTapChangerTapPositionAction.NAME, + RatioTapChangerTapPositionAction.NAME: { + String transformerId = action.getType().equals(PhaseTapChangerTapPositionAction.NAME) ? + ((PhaseTapChangerTapPositionAction) action).getTransformerId() : ((RatioTapChangerTapPositionAction) action).getTransformerId(); + if (network.getTwoWindingsTransformer(transformerId) == null + && network.getThreeWindingsTransformer(transformerId) == null) { + throw new PowsyblException("Transformer '" + transformerId + NOT_FOUND); } break; } @@ -268,6 +269,30 @@ protected static void findAllSwitchesToOperate(Network network, List act }); } + protected static void findAllPtcToOperate(List actions, LfTopoConfig topoConfig) { + for (Action action : actions) { + if (PhaseTapChangerTapPositionAction.NAME.equals(action.getType())) { + PhaseTapChangerTapPositionAction ptcAction = (PhaseTapChangerTapPositionAction) action; + ptcAction.getSide().ifPresentOrElse( + side -> topoConfig.addBranchIdsWithPtcToRetain(LfLegBranch.getId(side, ptcAction.getTransformerId())), // T3WT + () -> topoConfig.addBranchIdsWithPtcToRetain(ptcAction.getTransformerId()) // T2WT + ); + } + } + } + + protected static void findAllRtcToOperate(List actions, LfTopoConfig topoConfig) { + for (Action action : actions) { + if (RatioTapChangerTapPositionAction.NAME.equals(action.getType())) { + RatioTapChangerTapPositionAction rtcAction = (RatioTapChangerTapPositionAction) action; + rtcAction.getSide().ifPresentOrElse( + side -> topoConfig.addBranchIdsWithRtcToRetain(LfLegBranch.getId(side, rtcAction.getTransformerId())), // T3WT + () -> topoConfig.addBranchIdsWithRtcToRetain(rtcAction.getTransformerId()) // T2WT + ); + } + } + } + protected OperatorStrategyResult runActionSimulation(LfNetwork network, C context, OperatorStrategy operatorStrategy, List actionsIds, LimitViolationManager preContingencyLimitViolationManager, diff --git a/src/main/java/com/powsybl/openloadflow/sa/AcSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/AcSecurityAnalysis.java index 9f6d3ba4a7..2fcf337a08 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/AcSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/AcSecurityAnalysis.java @@ -26,7 +26,6 @@ import com.powsybl.openloadflow.graph.GraphConnectivityFactory; import com.powsybl.openloadflow.network.*; import com.powsybl.openloadflow.network.impl.LfNetworkList; -import com.powsybl.openloadflow.network.impl.LfTopoConfig; import com.powsybl.openloadflow.network.impl.Networks; import com.powsybl.openloadflow.network.impl.PropagatedContingency; import com.powsybl.openloadflow.network.util.ActivePowerDistribution; @@ -80,6 +79,10 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete LfTopoConfig topoConfig = new LfTopoConfig(); findAllSwitchesToOperate(network, actions, topoConfig); + // try to find all pst and rtc to retain because involved in pst and rtc actions + findAllPtcToOperate(actions, topoConfig); + findAllRtcToOperate(actions, topoConfig); + // load contingencies List contingencies = contingenciesProvider.getContingencies(network); // try to find all switches impacted by at least one contingency and for each contingency the branches impacted @@ -95,7 +98,6 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete // create networks including all necessary switches try (LfNetworkList lfNetworks = Networks.load(network, acParameters.getNetworkParameters(), topoConfig, saReporter)) { - // complete definition of contingencies after network loading PropagatedContingency.completeList(propagatedContingencies, lfParameters.isShuntCompensatorVoltageControlOn(), lfParameters.getBalanceType() == LoadFlowParameters.BalanceType.PROPORTIONAL_TO_CONFORM_LOAD, lfParameters.isHvdcAcEmulation(), breakers); diff --git a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java index b4cd5d7b3f..315749e54e 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java @@ -24,7 +24,6 @@ import com.powsybl.openloadflow.graph.GraphConnectivityFactory; import com.powsybl.openloadflow.network.*; import com.powsybl.openloadflow.network.impl.LfNetworkList; -import com.powsybl.openloadflow.network.impl.LfTopoConfig; import com.powsybl.openloadflow.network.impl.Networks; import com.powsybl.openloadflow.network.impl.PropagatedContingency; import com.powsybl.openloadflow.sensi.OpenSensitivityAnalysisProvider; @@ -236,6 +235,9 @@ private List createOperatorStrategyResults(DcSecurityAna LfTopoConfig topoConfig = new LfTopoConfig(); findAllSwitchesToOperate(network, actions, topoConfig); + // try to find all pst to retain because involved in pst actions + findAllPtcToOperate(actions, topoConfig); + List propagatedContingencies = PropagatedContingency.createList(network, context.getContingencies(), topoConfig, false); Map actionsById = indexActionsById(actions); diff --git a/src/main/java/com/powsybl/openloadflow/sensi/AcSensitivityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sensi/AcSensitivityAnalysis.java index 3de5d183b6..0779033395 100644 --- a/src/main/java/com/powsybl/openloadflow/sensi/AcSensitivityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sensi/AcSensitivityAnalysis.java @@ -24,7 +24,6 @@ import com.powsybl.openloadflow.graph.GraphConnectivityFactory; import com.powsybl.openloadflow.network.*; import com.powsybl.openloadflow.network.impl.LfNetworkList; -import com.powsybl.openloadflow.network.impl.LfTopoConfig; import com.powsybl.openloadflow.network.impl.Networks; import com.powsybl.openloadflow.network.impl.PropagatedContingency; import com.powsybl.openloadflow.network.util.ActivePowerDistribution; diff --git a/src/main/java/com/powsybl/openloadflow/sensi/DcSensitivityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sensi/DcSensitivityAnalysis.java index 8adbf80404..56377ee5c3 100644 --- a/src/main/java/com/powsybl/openloadflow/sensi/DcSensitivityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sensi/DcSensitivityAnalysis.java @@ -30,7 +30,6 @@ import com.powsybl.openloadflow.graph.GraphConnectivityFactory; import com.powsybl.openloadflow.network.*; import com.powsybl.openloadflow.network.impl.LfNetworkList; -import com.powsybl.openloadflow.network.impl.LfTopoConfig; import com.powsybl.openloadflow.network.impl.Networks; import com.powsybl.openloadflow.network.impl.PropagatedContingency; import com.powsybl.openloadflow.network.util.ParticipatingElement; diff --git a/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisProvider.java b/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisProvider.java index 70fc930340..2b8ff24fc8 100644 --- a/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisProvider.java +++ b/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisProvider.java @@ -30,7 +30,7 @@ import com.powsybl.openloadflow.graph.GraphConnectivityFactory; import com.powsybl.openloadflow.network.LfBranch; import com.powsybl.openloadflow.network.LfBus; -import com.powsybl.openloadflow.network.impl.LfTopoConfig; +import com.powsybl.openloadflow.network.LfTopoConfig; import com.powsybl.openloadflow.network.impl.PropagatedContingency; import com.powsybl.openloadflow.util.DebugUtil; import com.powsybl.openloadflow.util.ProviderConstants; diff --git a/src/test/java/com/powsybl/openloadflow/ZeroImpedanceFlowsTest.java b/src/test/java/com/powsybl/openloadflow/ZeroImpedanceFlowsTest.java index 1b53284c1b..b28bc261e3 100644 --- a/src/test/java/com/powsybl/openloadflow/ZeroImpedanceFlowsTest.java +++ b/src/test/java/com/powsybl/openloadflow/ZeroImpedanceFlowsTest.java @@ -18,7 +18,6 @@ import com.powsybl.openloadflow.graph.NaiveGraphConnectivityFactory; import com.powsybl.openloadflow.network.*; import com.powsybl.openloadflow.network.impl.LfNetworkList; -import com.powsybl.openloadflow.network.impl.LfTopoConfig; import com.powsybl.openloadflow.network.impl.Networks; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/src/test/java/com/powsybl/openloadflow/ac/NonImpedantBranchDisablingTest.java b/src/test/java/com/powsybl/openloadflow/ac/NonImpedantBranchDisablingTest.java index 77af8e7800..663b2e1e15 100644 --- a/src/test/java/com/powsybl/openloadflow/ac/NonImpedantBranchDisablingTest.java +++ b/src/test/java/com/powsybl/openloadflow/ac/NonImpedantBranchDisablingTest.java @@ -20,7 +20,6 @@ import com.powsybl.openloadflow.network.*; import com.powsybl.openloadflow.network.impl.LfNetworkList; import com.powsybl.openloadflow.network.impl.LfNetworkLoaderImpl; -import com.powsybl.openloadflow.network.impl.LfTopoConfig; import com.powsybl.openloadflow.network.impl.Networks; import com.powsybl.openloadflow.util.LoadFlowAssert; import com.powsybl.openloadflow.util.PerUnit; diff --git a/src/test/java/com/powsybl/openloadflow/dc/DcLoadFlowTest.java b/src/test/java/com/powsybl/openloadflow/dc/DcLoadFlowTest.java index 2698700d0e..efa0e72f58 100644 --- a/src/test/java/com/powsybl/openloadflow/dc/DcLoadFlowTest.java +++ b/src/test/java/com/powsybl/openloadflow/dc/DcLoadFlowTest.java @@ -19,7 +19,6 @@ import com.powsybl.openloadflow.dc.equations.DcEquationSystemCreationParameters; import com.powsybl.openloadflow.network.*; import com.powsybl.openloadflow.network.impl.LfNetworkList; -import com.powsybl.openloadflow.network.impl.LfTopoConfig; import com.powsybl.openloadflow.network.impl.Networks; import com.powsybl.openloadflow.util.LoadFlowAssert; import com.powsybl.openloadflow.util.PerUnit; diff --git a/src/test/java/com/powsybl/openloadflow/sa/LfActionTest.java b/src/test/java/com/powsybl/openloadflow/sa/LfActionTest.java index af65a92b88..8405b9c374 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/LfActionTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/LfActionTest.java @@ -20,7 +20,6 @@ import com.powsybl.openloadflow.graph.NaiveGraphConnectivityFactory; import com.powsybl.openloadflow.network.*; import com.powsybl.openloadflow.network.impl.LfNetworkList; -import com.powsybl.openloadflow.network.impl.LfTopoConfig; import com.powsybl.openloadflow.network.impl.Networks; import com.powsybl.openloadflow.network.impl.PropagatedContingency; import com.powsybl.openloadflow.util.PerUnit; diff --git a/src/test/java/com/powsybl/openloadflow/sa/LfContingencyTest.java b/src/test/java/com/powsybl/openloadflow/sa/LfContingencyTest.java index c0ebda65dc..63a3c07941 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/LfContingencyTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/LfContingencyTest.java @@ -20,7 +20,6 @@ import com.powsybl.openloadflow.graph.EvenShiloachGraphDecrementalConnectivityFactory; import com.powsybl.openloadflow.graph.GraphConnectivityFactory; import com.powsybl.openloadflow.network.*; -import com.powsybl.openloadflow.network.impl.LfTopoConfig; import com.powsybl.openloadflow.network.impl.Networks; import com.powsybl.openloadflow.network.impl.PropagatedContingency; import org.junit.jupiter.api.AfterEach; diff --git a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisGraphTest.java b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisGraphTest.java index dfada545a8..bedf1c95fe 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisGraphTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisGraphTest.java @@ -17,7 +17,6 @@ import com.powsybl.openloadflow.graph.NaiveGraphConnectivityFactory; import com.powsybl.openloadflow.network.*; import com.powsybl.openloadflow.network.impl.LfNetworkList; -import com.powsybl.openloadflow.network.impl.LfTopoConfig; import com.powsybl.openloadflow.network.impl.Networks; import com.powsybl.openloadflow.network.impl.PropagatedContingency; import org.junit.jupiter.api.BeforeEach; diff --git a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisWithActionsTest.java b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisWithActionsTest.java index cefb9e238c..f6a964f37e 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisWithActionsTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisWithActionsTest.java @@ -9,10 +9,7 @@ import com.powsybl.commons.reporter.Reporter; import com.powsybl.commons.reporter.ReporterModel; import com.powsybl.contingency.*; -import com.powsybl.iidm.network.HvdcLine; -import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.PhaseTapChanger; -import com.powsybl.iidm.network.ThreeWindingsTransformer; +import com.powsybl.iidm.network.*; import com.powsybl.iidm.network.extensions.HvdcAngleDroopActivePowerControlAdder; import com.powsybl.iidm.xml.test.MetrixTutorialSixBusesFactory; import com.powsybl.loadflow.LoadFlowParameters; @@ -39,10 +36,7 @@ import org.junit.jupiter.api.Test; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.concurrent.CompletionException; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -1137,6 +1131,86 @@ void testPhaseTapChangerActionThreeWindingsTransformer() { new TrueCondition(), List.of("pst_leg_1"))); CompletionException exception = assertThrows(CompletionException.class, () -> runSecurityAnalysis(network, contingencies, monitors, securityAnalysisParameters, operatorStrategies1, actions1, Reporter.NO_OP)); - assertEquals("Phase tap changer tap connection action: only one tap in branch PS1_leg_1", exception.getCause().getMessage()); + assertEquals("Tap position action: only one tap in branch PS1_leg_1", exception.getCause().getMessage()); + } + + @Test + void testActionOnRetainedPtc() { + Network network = PhaseControlFactory.createNetworkWithT2wt(); + network.newLine() + .setId("L3") + .setVoltageLevel1("VL1") + .setBus1("B1") + .setVoltageLevel2("VL2") + .setBus2("B2") + .setR(4.0) + .setX(200.0) + .add(); + + List contingencies = List.of(new Contingency("CL3", new BranchContingency("L3"))); + List monitors = createAllBranchesMonitors(network); + List actions = List.of(new PhaseTapChangerTapPositionAction("Aps1", "PS1", false, 2)); + List operatorStrategies = List.of(new OperatorStrategy("strategy1", ContingencyContext.specificContingency("CL3"), new TrueCondition(), List.of("Aps1"))); + SecurityAnalysisResult result = runSecurityAnalysis(network, contingencies, monitors, new SecurityAnalysisParameters(), + operatorStrategies, actions, Reporter.NO_OP); + + network.getLine("L3").getTerminal1().disconnect(); + network.getLine("L3").getTerminal2().disconnect(); + network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setTapPosition(2); + loadFlowRunner.run(network); + + assertEquals(network.getLine("L1").getTerminal1().getP(), getOperatorStrategyResult(result, "strategy1").getNetworkResult().getBranchResult("L1").getP1(), LoadFlowAssert.DELTA_POWER); + assertEquals(network.getLine("L1").getTerminal2().getP(), getOperatorStrategyResult(result, "strategy1").getNetworkResult().getBranchResult("L1").getP2(), LoadFlowAssert.DELTA_POWER); + assertEquals(network.getLine("L2").getTerminal1().getP(), getOperatorStrategyResult(result, "strategy1").getNetworkResult().getBranchResult("L2").getP1(), LoadFlowAssert.DELTA_POWER); + assertEquals(network.getLine("L2").getTerminal2().getP(), getOperatorStrategyResult(result, "strategy1").getNetworkResult().getBranchResult("L2").getP2(), LoadFlowAssert.DELTA_POWER); + } + + @Test + void testActionOnRetainedT3wtPtc() { + Network network = PhaseControlFactory.createNetworkWithT3wt(); + network.newLine() + .setId("L3") + .setVoltageLevel1("VL1") + .setBus1("B1") + .setVoltageLevel2("VL2") + .setBus2("B2") + .setR(4.0) + .setX(200.0) + .add(); + + List contingencies = List.of(new Contingency("CL3", new BranchContingency("L3"))); + List monitors = createAllBranchesMonitors(network); + List actions = List.of(new PhaseTapChangerTapPositionAction("Aps1", "PS1", false, 2, ThreeWindingsTransformer.Side.TWO)); + List operatorStrategies = List.of(new OperatorStrategy("strategy1", ContingencyContext.specificContingency("CL3"), new TrueCondition(), List.of("Aps1"))); + SecurityAnalysisResult result = runSecurityAnalysis(network, contingencies, monitors, new SecurityAnalysisParameters(), + operatorStrategies, actions, Reporter.NO_OP); + + network.getLine("L3").getTerminal1().disconnect(); + network.getLine("L3").getTerminal2().disconnect(); + network.getThreeWindingsTransformer("PS1").getLeg2().getPhaseTapChanger().setTapPosition(2); + loadFlowRunner.run(network); + + assertEquals(network.getLine("L1").getTerminal1().getP(), getOperatorStrategyResult(result, "strategy1").getNetworkResult().getBranchResult("L1").getP1(), LoadFlowAssert.DELTA_POWER); + assertEquals(network.getLine("L1").getTerminal2().getP(), getOperatorStrategyResult(result, "strategy1").getNetworkResult().getBranchResult("L1").getP2(), LoadFlowAssert.DELTA_POWER); + assertEquals(network.getLine("L2").getTerminal1().getP(), getOperatorStrategyResult(result, "strategy1").getNetworkResult().getBranchResult("L2").getP1(), LoadFlowAssert.DELTA_POWER); + assertEquals(network.getLine("L2").getTerminal2().getP(), getOperatorStrategyResult(result, "strategy1").getNetworkResult().getBranchResult("L2").getP2(), LoadFlowAssert.DELTA_POWER); + } + + @Test + void testActionOnRetainedRtc() { + Network network = VoltageControlNetworkFactory.createNetworkWithT2wt(); + List contingencies = List.of(new Contingency("contingency", new LoadContingency("LOAD_2"))); + List monitors = createNetworkMonitors(network); + List actions = List.of(new RatioTapChangerTapPositionAction("action", "T2wT", false, 2)); + List operatorStrategies = List.of(new OperatorStrategy("strategy", ContingencyContext.specificContingency("contingency"), new TrueCondition(), List.of("action"))); + SecurityAnalysisResult result = runSecurityAnalysis(network, contingencies, monitors, new SecurityAnalysisParameters(), + operatorStrategies, actions, Reporter.NO_OP); + + network.getLoad("LOAD_2").getTerminal().disconnect(); + network.getTwoWindingsTransformer("T2wT").getRatioTapChanger().setTapPosition(2); + loadFlowRunner.run(network); + + assertEquals(network.getBusBreakerView().getBus("BUS_2").getV(), + getOperatorStrategyResult(result, "strategy").getNetworkResult().getBusResult("BUS_2").getV(), LoadFlowAssert.DELTA_POWER); } } diff --git a/src/test/java/com/powsybl/openloadflow/sensi/DcSensitivityAnalysisTest.java b/src/test/java/com/powsybl/openloadflow/sensi/DcSensitivityAnalysisTest.java index 63659a7212..879e5accb2 100644 --- a/src/test/java/com/powsybl/openloadflow/sensi/DcSensitivityAnalysisTest.java +++ b/src/test/java/com/powsybl/openloadflow/sensi/DcSensitivityAnalysisTest.java @@ -21,7 +21,6 @@ import com.powsybl.openloadflow.equations.EquationSystem; import com.powsybl.openloadflow.equations.EquationSystemIndex; import com.powsybl.openloadflow.network.*; -import com.powsybl.openloadflow.network.impl.LfTopoConfig; import com.powsybl.openloadflow.network.impl.PropagatedContingency; import com.powsybl.openloadflow.util.LoadFlowAssert; import com.powsybl.sensitivity.*;