From 72094f77023de02f3f81cfb4340eb29440f9bbd8 Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Sat, 6 Feb 2021 20:34:12 +0100 Subject: [PATCH 01/13] Add network listener and refactor outer loops Signed-off-by: Geoffroy Jamgotchian --- .../ac/ReactiveLimitsOuterLoop.java | 68 +++---------------- .../ac/equations/AcEquationSystem.java | 45 ++++++++++++ .../openloadflow/network/LfNetwork.java | 13 ++++ .../network/LfNetworkListener.java | 15 ++++ .../network/impl/AbstractLfBus.java | 16 +++-- .../openloadflow/network/impl/LfBusImpl.java | 9 +-- .../network/impl/LfDanglingLineBus.java | 5 +- .../network/impl/LfNetworkLoaderImpl.java | 10 +-- .../openloadflow/network/impl/LfStarBus.java | 5 +- .../powsybl/openloadflow/util/BusState.java | 9 +-- 10 files changed, 111 insertions(+), 84 deletions(-) create mode 100644 src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java diff --git a/src/main/java/com/powsybl/openloadflow/ac/ReactiveLimitsOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/ReactiveLimitsOuterLoop.java index 3c67b35168..58390000d0 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/ReactiveLimitsOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/ReactiveLimitsOuterLoop.java @@ -6,14 +6,9 @@ */ package com.powsybl.openloadflow.ac; -import com.powsybl.openloadflow.ac.equations.AcEquationSystem; import com.powsybl.openloadflow.ac.outerloop.OuterLoop; import com.powsybl.openloadflow.ac.outerloop.OuterLoopContext; import com.powsybl.openloadflow.ac.outerloop.OuterLoopStatus; -import com.powsybl.openloadflow.equations.Equation; -import com.powsybl.openloadflow.equations.EquationSystem; -import com.powsybl.openloadflow.equations.EquationType; -import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBus; import com.powsybl.openloadflow.network.PerUnit; import org.apache.commons.lang3.mutable.MutableInt; @@ -23,7 +18,6 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; -import java.util.stream.Collectors; /** * @author Geoffroy Jamgotchian @@ -51,38 +45,6 @@ public String getType() { return "Reactive limits"; } - public static void switchPvPq(LfBus bus, EquationSystem equationSystem, VariableSet variableSet, double newGenerationTargetQ) { - bus.setGenerationTargetQ(newGenerationTargetQ); - bus.setVoltageControl(false); - - Equation qEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_Q); - qEq.setActive(true); - - LfBus controlledBus = bus.getControlledBus().orElse(null); - if (controlledBus != null) { - updateControlledBus(controlledBus, equationSystem, variableSet); - } else { - Equation vEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V); - vEq.setActive(false); - } - } - - public static void updateControlledBus(LfBus controlledBus, EquationSystem equationSystem, VariableSet variableSet) { - // clean reactive power distribution equations - controlledBus.getControllerBuses().forEach(b -> equationSystem.removeEquation(b.getNum(), EquationType.ZERO_Q)); - - // controlled bus has a voltage equation only if one of the controller bus has voltage control on - List controllerBusesWithVoltageControlOn = controlledBus.getControllerBuses().stream() - .filter(LfBus::hasVoltageControl) - .collect(Collectors.toList()); - equationSystem.createEquation(controlledBus.getNum(), EquationType.BUS_V).setActive(!controllerBusesWithVoltageControlOn.isEmpty()); - - // create reactive power equations on controller buses that have voltage control on - if (!controllerBusesWithVoltageControlOn.isEmpty()) { - AcEquationSystem.createReactivePowerDistributionEquations(equationSystem, variableSet, controllerBusesWithVoltageControlOn); - } - } - private enum ReactiveLimitDirection { MIN, MAX @@ -106,7 +68,7 @@ private PvToPqBus(LfBus bus, double q, double qLimit, ReactiveLimitDirection lim } } - private boolean switchPvPq(List pvToPqBuses, EquationSystem equationSystem, VariableSet variableSet, int remainingPvBusCount) { + private boolean switchPvPq(List pvToPqBuses, int remainingPvBusCount) { boolean done = false; int modifiedRemainingPvBusCount = remainingPvBusCount; @@ -128,7 +90,8 @@ private boolean switchPvPq(List pvToPqBuses, EquationSystem equationS for (PvToPqBus pvToPqBus : pvToPqBuses) { // switch PV -> PQ - switchPvPq(pvToPqBus.bus, equationSystem, variableSet, pvToPqBus.qLimit); + pvToPqBus.bus.setGenerationTargetQ(pvToPqBus.qLimit); + pvToPqBus.bus.setVoltageControl(false); if (LOGGER.isTraceEnabled()) { if (pvToPqBus.limitDirection == ReactiveLimitDirection.MAX) { @@ -147,22 +110,6 @@ private boolean switchPvPq(List pvToPqBuses, EquationSystem equationS return done; } - public static void switchPqPv(LfBus bus, EquationSystem equationSystem, VariableSet variableSet) { - bus.setVoltageControl(true); - bus.setGenerationTargetQ(0); - - Equation qEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_Q); - qEq.setActive(false); - - LfBus controlledBus = bus.getControlledBus().orElse(null); - if (controlledBus != null) { - updateControlledBus(controlledBus, equationSystem, variableSet); - } else { - Equation vEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V); - vEq.setActive(true); - } - } - private static final class PqToPvBus { private final LfBus bus; @@ -175,7 +122,7 @@ private PqToPvBus(LfBus bus, ReactiveLimitDirection limitDirection) { } } - private boolean switchPqPv(List pqToPvBuses, EquationSystem equationSystem, VariableSet variableSet) { + private boolean switchPqPv(List pqToPvBuses) { int pqPvSwitchCount = 0; for (PqToPvBus pqToPvBus : pqToPvBuses) { @@ -185,7 +132,8 @@ private boolean switchPqPv(List pqToPvBuses, EquationSystem equationS LOGGER.trace("Bus '{}' blocked PQ as it has reach its max number of PQ -> PV switch ({})", bus.getId(), bus.getVoltageControlSwitchOffCount()); } else { - switchPqPv(bus, equationSystem, variableSet); + bus.setVoltageControl(true); + bus.setGenerationTargetQ(0); pqPvSwitchCount++; if (LOGGER.isTraceEnabled()) { @@ -256,10 +204,10 @@ public OuterLoopStatus check(OuterLoopContext context) { } } - if (!pvToPqBuses.isEmpty() && switchPvPq(pvToPqBuses, context.getEquationSystem(), context.getVariableSet(), remainingPvBusCount.intValue())) { + if (!pvToPqBuses.isEmpty() && switchPvPq(pvToPqBuses, remainingPvBusCount.intValue())) { status = OuterLoopStatus.UNSTABLE; } - if (!pqToPvBuses.isEmpty() && switchPqPv(pqToPvBuses, context.getEquationSystem(), context.getVariableSet())) { + if (!pqToPvBuses.isEmpty() && switchPqPv(pqToPvBuses)) { status = OuterLoopStatus.UNSTABLE; } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java index fef1d49617..391b99cd20 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java @@ -332,6 +332,22 @@ private static void createBranchEquations(LfNetwork network, VariableSet variabl } } + public static void updateControlledBus(LfBus controlledBus, EquationSystem equationSystem, VariableSet variableSet) { + // clean reactive power distribution equations + controlledBus.getControllerBuses().forEach(b -> equationSystem.removeEquation(b.getNum(), EquationType.ZERO_Q)); + + // controlled bus has a voltage equation only if one of the controller bus has voltage control on + List controllerBusesWithVoltageControlOn = controlledBus.getControllerBuses().stream() + .filter(LfBus::hasVoltageControl) + .collect(Collectors.toList()); + equationSystem.createEquation(controlledBus.getNum(), EquationType.BUS_V).setActive(!controllerBusesWithVoltageControlOn.isEmpty()); + + // create reactive power equations on controller buses that have voltage control on + if (!controllerBusesWithVoltageControlOn.isEmpty()) { + AcEquationSystem.createReactivePowerDistributionEquations(equationSystem, variableSet, controllerBusesWithVoltageControlOn); + } + } + public static EquationSystem create(LfNetwork network) { return create(network, new VariableSet()); } @@ -350,6 +366,35 @@ public static EquationSystem create(LfNetwork network, VariableSet variableSet, createBusEquations(network, variableSet, creationParameters, equationSystem); createBranchEquations(network, variableSet, creationParameters, equationSystem); + network.addListener(new LfNetworkListener() { + @Override + public void onVoltageControlChange(LfBus bus, boolean oldVoltageControl, boolean newVoltageControl) { + if (newVoltageControl) { // switch PQ/PV + Equation qEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_Q); + qEq.setActive(false); + + LfBus controlledBus = bus.getControlledBus().orElse(null); + if (controlledBus != null) { + updateControlledBus(controlledBus, equationSystem, variableSet); + } else { + Equation vEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V); + vEq.setActive(true); + } + } else { // switch PV/PQ + Equation qEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_Q); + qEq.setActive(true); + + LfBus controlledBus = bus.getControlledBus().orElse(null); + if (controlledBus != null) { + updateControlledBus(controlledBus, equationSystem, variableSet); + } else { + Equation vEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V); + vEq.setActive(false); + } + } + } + }); + return equationSystem; } } diff --git a/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java b/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java index fa3fec9784..75b98cd11a 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java @@ -55,6 +55,8 @@ public class LfNetwork { private int shuntCount = 0; + private final List listeners = new ArrayList<>(); + public LfNetwork(int num, SlackBusSelector slackBusSelector) { this.num = num; this.slackBusSelector = Objects.requireNonNull(slackBusSelector); @@ -448,4 +450,15 @@ public static boolean isZeroImpedanceBranch(LfBranch branch) { return piModel.getZ() < LOW_IMPEDANCE_THRESHOLD; } + public void addListener(LfNetworkListener listener) { + listeners.add(listener); + } + + public void removeListener(LfNetworkListener listener) { + listeners.remove(listener); + } + + public List getListeners() { + return listeners; + } } diff --git a/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java b/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java new file mode 100644 index 0000000000..50cc04aacc --- /dev/null +++ b/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java @@ -0,0 +1,15 @@ +/** + * Copyright (c) 2021, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.openloadflow.network; + +/** + * @author Geoffroy Jamgotchian + */ +public interface LfNetworkListener { + + void onVoltageControlChange(LfBus bus, boolean oldVoltageControl, boolean newVoltageControl); +} diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java index 916d28b514..5cabb99a38 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java @@ -29,6 +29,8 @@ public abstract class AbstractLfBus implements LfBus { private static final double Q_DISPATCH_EPSILON = 1e-3; private static final double TARGET_V_EPSILON = 1e-2; + private final LfNetwork network; + private int num = -1; protected boolean slack = false; @@ -83,7 +85,8 @@ public abstract class AbstractLfBus implements LfBus { protected boolean disabled = false; - protected AbstractLfBus(double v, double angle) { + protected AbstractLfBus(LfNetwork network, double v, double angle) { + this.network = Objects.requireNonNull(network); this.v = v; this.angle = angle; } @@ -130,10 +133,15 @@ public boolean hasVoltageControl() { @Override public void setVoltageControl(boolean voltageControl) { - if (this.voltageControl && !voltageControl) { - voltageControlSwitchOffCount++; + if (this.voltageControl != voltageControl) { + if (this.voltageControl) { + voltageControlSwitchOffCount++; + } + this.voltageControl = voltageControl; + for (LfNetworkListener listener : network.getListeners()) { + listener.onVoltageControlChange(this, !voltageControl, voltageControl); + } } - this.voltageControl = voltageControl; } @Override diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfBusImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfBusImpl.java index ebcae26092..b8da3d8d98 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfBusImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfBusImpl.java @@ -8,6 +8,7 @@ import com.powsybl.iidm.network.Bus; import com.powsybl.iidm.network.extensions.SlackTerminal; +import com.powsybl.openloadflow.network.LfNetwork; import java.util.Objects; @@ -24,17 +25,17 @@ public class LfBusImpl extends AbstractLfBus { private final double highVoltageLimit; - protected LfBusImpl(Bus bus, double v, double angle) { - super(v, angle); + protected LfBusImpl(LfNetwork network, Bus bus, double v, double angle) { + super(network, v, angle); this.bus = bus; nominalV = bus.getVoltageLevel().getNominalV(); lowVoltageLimit = bus.getVoltageLevel().getLowVoltageLimit(); highVoltageLimit = bus.getVoltageLevel().getHighVoltageLimit(); } - public static LfBusImpl create(Bus bus) { + public static LfBusImpl create(LfNetwork network, Bus bus) { Objects.requireNonNull(bus); - return new LfBusImpl(bus, bus.getV(), bus.getAngle()); + return new LfBusImpl(network, bus, bus.getV(), bus.getAngle()); } @Override diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfDanglingLineBus.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfDanglingLineBus.java index 1f902589ab..8c918a07e2 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfDanglingLineBus.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfDanglingLineBus.java @@ -7,6 +7,7 @@ package com.powsybl.openloadflow.network.impl; import com.powsybl.iidm.network.DanglingLine; +import com.powsybl.openloadflow.network.LfNetwork; import java.util.Objects; @@ -19,8 +20,8 @@ public class LfDanglingLineBus extends AbstractLfBus { private final double nominalV; - public LfDanglingLineBus(DanglingLine danglingLine) { - super(Networks.getPropertyV(danglingLine), Networks.getPropertyAngle(danglingLine)); + public LfDanglingLineBus(LfNetwork network, DanglingLine danglingLine) { + super(network, Networks.getPropertyV(danglingLine), Networks.getPropertyAngle(danglingLine)); this.danglingLine = Objects.requireNonNull(danglingLine); nominalV = danglingLine.getTerminal().getVoltageLevel().getNominalV(); loadTargetP += danglingLine.getP0(); 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 d12c561a14..8fb0b8aee2 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java @@ -44,7 +44,7 @@ private static void createBuses(List buses, LfNetworkParameters parameters, Map controllerBusToControlledBusId = new LinkedHashMap<>(); for (Bus bus : buses) { - LfBusImpl lfBus = createBus(bus, parameters, loadingContext, report, controllerBusToControlledBusId); + LfBusImpl lfBus = createBus(bus, parameters, lfNetwork, loadingContext, report, controllerBusToControlledBusId); lfNetwork.addBus(lfBus); } @@ -61,9 +61,9 @@ private static Bus getBus(Terminal terminal, boolean breakers) { return breakers ? terminal.getBusBreakerView().getBus() : terminal.getBusView().getBus(); } - private static LfBusImpl createBus(Bus bus, LfNetworkParameters parameters, LoadingContext loadingContext, + private static LfBusImpl createBus(Bus bus, LfNetworkParameters parameters, LfNetwork lfNetwork, LoadingContext loadingContext, LfNetworkLoadingReport report, Map controllerBusToControlledBusId) { - LfBusImpl lfBus = LfBusImpl.create(bus); + LfBusImpl lfBus = LfBusImpl.create(lfNetwork, bus); bus.visitConnectedEquipments(new DefaultTopologyVisitor() { @@ -211,14 +211,14 @@ private static void createBranches(LfNetwork lfNetwork, LoadingContext loadingCo } for (DanglingLine danglingLine : loadingContext.danglingLines) { - LfDanglingLineBus lfBus2 = new LfDanglingLineBus(danglingLine); + LfDanglingLineBus lfBus2 = new LfDanglingLineBus(lfNetwork, danglingLine); lfNetwork.addBus(lfBus2); LfBus lfBus1 = getLfBus(danglingLine.getTerminal(), lfNetwork, breakers); addBranch(lfNetwork, LfDanglingLineBranch.create(danglingLine, lfBus1, lfBus2), report); } for (ThreeWindingsTransformer t3wt : loadingContext.t3wtSet) { - LfStarBus lfBus0 = new LfStarBus(t3wt); + LfStarBus lfBus0 = new LfStarBus(lfNetwork, t3wt); lfNetwork.addBus(lfBus0); LfBus lfBus1 = getLfBus(t3wt.getLeg1().getTerminal(), lfNetwork, breakers); LfBus lfBus2 = getLfBus(t3wt.getLeg2().getTerminal(), lfNetwork, breakers); diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfStarBus.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfStarBus.java index 42a0c2cd62..b897ff9f53 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfStarBus.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfStarBus.java @@ -7,6 +7,7 @@ package com.powsybl.openloadflow.network.impl; import com.powsybl.iidm.network.ThreeWindingsTransformer; +import com.powsybl.openloadflow.network.LfNetwork; /** * @author Geoffroy Jamgotchian @@ -17,8 +18,8 @@ public class LfStarBus extends AbstractLfBus { private final double nominalV; - public LfStarBus(ThreeWindingsTransformer t3wt) { - super(Networks.getPropertyV(t3wt), Networks.getPropertyAngle(t3wt)); + public LfStarBus(LfNetwork network, ThreeWindingsTransformer t3wt) { + super(network, Networks.getPropertyV(t3wt), Networks.getPropertyAngle(t3wt)); this.t3wt = t3wt; nominalV = t3wt.getLeg1().getTerminal().getVoltageLevel().getNominalV(); } diff --git a/src/main/java/com/powsybl/openloadflow/util/BusState.java b/src/main/java/com/powsybl/openloadflow/util/BusState.java index 6bd0ad1eee..73a480df1f 100644 --- a/src/main/java/com/powsybl/openloadflow/util/BusState.java +++ b/src/main/java/com/powsybl/openloadflow/util/BusState.java @@ -6,7 +6,6 @@ */ package com.powsybl.openloadflow.util; -import com.powsybl.openloadflow.ac.ReactiveLimitsOuterLoop; import com.powsybl.openloadflow.ac.outerloop.AcloadFlowEngine; import com.powsybl.openloadflow.network.LfBus; import com.powsybl.openloadflow.network.LfGenerator; @@ -42,12 +41,8 @@ public void restoreBusState(LfBus bus, AcloadFlowEngine engine) { restoreDcBusState(bus); bus.setV(v); bus.setLoadTargetQ(loadTargetQ); - if (hasVoltageControl && !bus.hasVoltageControl()) { // b is now PQ bus. - ReactiveLimitsOuterLoop.switchPqPv(bus, engine.getEquationSystem(), engine.getVariableSet()); - } - if (!hasVoltageControl && bus.hasVoltageControl()) { // b is now PV bus. - ReactiveLimitsOuterLoop.switchPvPq(bus, engine.getEquationSystem(), engine.getVariableSet(), generationTargetQ); - } + bus.setGenerationTargetQ(generationTargetQ); + bus.setVoltageControl(hasVoltageControl); bus.setVoltageControlSwitchOffCount(0); } From 8e2f59f67e4458da03e95a6272710d488ece09f1 Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Sat, 6 Feb 2021 21:11:16 +0100 Subject: [PATCH 02/13] Remove equation system access from outer loops Signed-off-by: Geoffroy Jamgotchian --- .../ac/PhaseControlOuterLoop.java | 30 +++++----------- .../TransformerVoltageControlOuterLoop.java | 26 +++----------- .../ac/equations/AcEquationSystem.java | 34 +++++++++++++++++++ .../ac/outerloop/AcloadFlowEngine.java | 2 +- .../ac/outerloop/OuterLoopContext.java | 21 ++---------- .../network/AbstractLfBranch.java | 10 +++++- .../network/DiscretePhaseControl.java | 13 +++++-- .../network/DiscreteVoltageControl.java | 11 ++++-- .../openloadflow/network/LfBranch.java | 2 ++ .../powsybl/openloadflow/network/LfBus.java | 2 ++ .../network/LfNetworkListener.java | 4 +++ .../network/impl/AbstractLfBus.java | 5 +++ .../network/impl/LfBranchImpl.java | 18 +++++----- .../openloadflow/network/impl/LfBusImpl.java | 6 ++-- .../network/impl/LfDanglingLineBranch.java | 8 ++--- .../network/impl/LfLegBranch.java | 8 ++--- .../network/impl/LfNetworkLoaderImpl.java | 14 ++++---- .../openloadflow/network/impl/LfSwitch.java | 5 +-- 18 files changed, 122 insertions(+), 97 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/ac/PhaseControlOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/PhaseControlOuterLoop.java index 3afed0eb76..237be82281 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/PhaseControlOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/PhaseControlOuterLoop.java @@ -9,12 +9,8 @@ import com.powsybl.openloadflow.ac.outerloop.OuterLoop; import com.powsybl.openloadflow.ac.outerloop.OuterLoopContext; import com.powsybl.openloadflow.ac.outerloop.OuterLoopStatus; -import com.powsybl.openloadflow.equations.Equation; -import com.powsybl.openloadflow.equations.EquationType; -import com.powsybl.openloadflow.equations.Variable; -import com.powsybl.openloadflow.equations.VariableType; -import com.powsybl.openloadflow.network.LfBranch; import com.powsybl.openloadflow.network.DiscretePhaseControl; +import com.powsybl.openloadflow.network.LfBranch; import com.powsybl.openloadflow.network.PiModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,12 +30,12 @@ public String getType() { @Override public OuterLoopStatus check(OuterLoopContext context) { if (context.getIteration() == 0) { - // at first outerloop iteration: + // at first outer loop iteration: // branches with active power control are switched off and taps are rounded // branches with current limiter control will wait for second iteration return firstIteration(context); } else if (context.getIteration() > 0) { - // at second outerloop iteration: + // at second outer loop iteration: // flow of branches with fixed tap are recomputed return nextIteration(context); } @@ -52,8 +48,8 @@ private OuterLoopStatus firstIteration(OuterLoopContext context) { if (branch.isPhaseControlled()) { switch (branch.getDiscretePhaseControl().getMode()) { case CONTROLLER: - // at firall branches with active power control are switched off - desactivateActivePowerControlEquation(context, branch); + // all branches with active power control are switched off + switchOffPhaseControl(branch); // if at least one phase shifter has been switched off we need to continue status = OuterLoopStatus.UNSTABLE; break; @@ -69,7 +65,7 @@ private OuterLoopStatus firstIteration(OuterLoopContext context) { } private OuterLoopStatus nextIteration(OuterLoopContext context) { - // at second outerloop iteration we switch on phase control for branches that are in limiter mode + // at second outer loop iteration we switch on phase control for branches that are in limiter mode // and a current greater than the limit for (LfBranch branch : context.getNetwork().getBranches()) { if (branch.isPhaseControlled()) { @@ -85,20 +81,12 @@ private OuterLoopStatus nextIteration(OuterLoopContext context) { return OuterLoopStatus.STABLE; } - private void desactivateActivePowerControlEquation(OuterLoopContext context, LfBranch branch) { - // switch off phase shifter + private void switchOffPhaseControl(LfBranch branch) { + // switch off phase control branch.getDiscretePhaseControl().setMode(DiscretePhaseControl.Mode.OFF); - // de-activate a1 variable for next outer loop run - LfBranch controllerBranch = branch.getDiscretePhaseControl().getController(); - Variable a1 = context.getVariableSet().getVariable(controllerBranch.getNum(), VariableType.BRANCH_ALPHA1); - a1.setActive(false); - - // de-activate phase control equation - Equation t = context.getEquationSystem().createEquation(branch.getNum(), EquationType.BRANCH_P); - t.setActive(false); - // round the phase shift to the closest tap + LfBranch controllerBranch = branch.getDiscretePhaseControl().getController(); PiModel piModel = controllerBranch.getPiModel(); double a1Value = piModel.getA1(); piModel.roundA1ToClosestTap(); diff --git a/src/main/java/com/powsybl/openloadflow/ac/TransformerVoltageControlOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/TransformerVoltageControlOuterLoop.java index e93426d28b..cef5d4e15a 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/TransformerVoltageControlOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/TransformerVoltageControlOuterLoop.java @@ -6,17 +6,13 @@ */ package com.powsybl.openloadflow.ac; -import com.powsybl.openloadflow.equations.Equation; -import com.powsybl.openloadflow.equations.EquationType; -import com.powsybl.openloadflow.equations.Variable; -import com.powsybl.openloadflow.equations.VariableType; +import com.powsybl.openloadflow.ac.outerloop.OuterLoop; +import com.powsybl.openloadflow.ac.outerloop.OuterLoopContext; +import com.powsybl.openloadflow.ac.outerloop.OuterLoopStatus; import com.powsybl.openloadflow.network.DiscreteVoltageControl; import com.powsybl.openloadflow.network.LfBranch; import com.powsybl.openloadflow.network.LfBus; import com.powsybl.openloadflow.network.PiModel; -import com.powsybl.openloadflow.ac.outerloop.OuterLoop; -import com.powsybl.openloadflow.ac.outerloop.OuterLoopContext; -import com.powsybl.openloadflow.ac.outerloop.OuterLoopStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,19 +35,10 @@ public OuterLoopStatus check(OuterLoopContext context) { if (context.getIteration() == 0) { for (LfBus bus : context.getNetwork().getBuses()) { if (bus.isDiscreteVoltageControlled()) { - // de-activate transformer voltage control equation - Equation t = context.getEquationSystem().createEquation(bus.getNum(), EquationType.BUS_V); - t.setActive(false); + // switch off regulating transformers + bus.getDiscreteVoltageControl().setMode(DiscreteVoltageControl.Mode.OFF); - // at first iteration all branches controlling voltage are switched off for (LfBranch controllerBranch : bus.getDiscreteVoltageControl().getControllers()) { - // de-activate r1 variable for next outer loop run - Variable r1 = context.getVariableSet().getVariable(controllerBranch.getNum(), VariableType.BRANCH_RHO1); - r1.setActive(false); - - // clean transformer distribution equations - context.getEquationSystem().removeEquation(controllerBranch.getNum(), EquationType.ZERO_RHO1); - // round the rho shift to the closest tap PiModel piModel = controllerBranch.getPiModel(); double r1Value = piModel.getR1(); @@ -60,9 +47,6 @@ public OuterLoopStatus check(OuterLoopContext context) { LOGGER.trace("Round voltage shift of '{}': {} -> {}", controllerBranch.getId(), r1Value, roundedR1Value); } - // switch off regulating transformers - bus.getDiscreteVoltageControl().setMode(DiscreteVoltageControl.Mode.OFF); - // if at least one transformer has been switched off wee need to continue status = OuterLoopStatus.UNSTABLE; } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java index 391b99cd20..df5d2aa8ce 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java @@ -393,6 +393,40 @@ public void onVoltageControlChange(LfBus bus, boolean oldVoltageControl, boolean } } } + + @Override + public void onPhaseControlModeChange(DiscretePhaseControl phaseControl, DiscretePhaseControl.Mode oldMode, DiscretePhaseControl.Mode newMode) { + if (newMode == DiscretePhaseControl.Mode.OFF) { + // de-activate a1 variable for next outer loop run + Variable a1 = variableSet.getVariable(phaseControl.getController().getNum(), VariableType.BRANCH_ALPHA1); + a1.setActive(false); + + // de-activate phase control equation + Equation t = equationSystem.createEquation(phaseControl.getControlled().getNum(), EquationType.BRANCH_P); + t.setActive(false); + } + } + + @Override + public void onVoltageControlModeChange(DiscreteVoltageControl voltageControl, DiscreteVoltageControl.Mode oldMode, DiscreteVoltageControl.Mode newMode) { + if (newMode == DiscreteVoltageControl.Mode.OFF) { + LfBus bus = voltageControl.getControlled(); + + // de-activate transformer voltage control equation + Equation t = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V); + t.setActive(false); + + // at first iteration all branches controlling voltage are switched off + for (LfBranch controllerBranch : bus.getDiscreteVoltageControl().getControllers()) { + // de-activate r1 variable + Variable r1 = variableSet.getVariable(controllerBranch.getNum(), VariableType.BRANCH_RHO1); + r1.setActive(false); + + // clean transformer distribution equations + equationSystem.removeEquation(controllerBranch.getNum(), EquationType.ZERO_RHO1); + } + } + } }); return equationSystem; diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java index 335fc8fbc4..d94e8dc727 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java @@ -110,7 +110,7 @@ private void runOuterLoop(OuterLoop outerLoop, LfNetwork network, EquationSystem parameters.getObserver().beforeOuterLoopStatusCheck(outerLoopIteration.getValue(), outerLoop.getType()); // check outer loop status - outerLoopStatus = outerLoop.check(new OuterLoopContext(outerLoopIteration.getValue(), network, equationSystem, variableSet, runningContext.lastNrResult)); + outerLoopStatus = outerLoop.check(new OuterLoopContext(outerLoopIteration.getValue(), network, runningContext.lastNrResult)); parameters.getObserver().afterOuterLoopStatusCheck(outerLoopIteration.getValue(), outerLoop.getType(), outerLoopStatus == OuterLoopStatus.STABLE); diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/OuterLoopContext.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/OuterLoopContext.java index edd803497f..a70f77b2a6 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/OuterLoopContext.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/OuterLoopContext.java @@ -6,10 +6,8 @@ */ package com.powsybl.openloadflow.ac.outerloop; -import com.powsybl.openloadflow.equations.EquationSystem; -import com.powsybl.openloadflow.equations.VariableSet; -import com.powsybl.openloadflow.network.LfNetwork; import com.powsybl.openloadflow.ac.nr.NewtonRaphsonResult; +import com.powsybl.openloadflow.network.LfNetwork; import java.util.Objects; @@ -22,18 +20,11 @@ public class OuterLoopContext { private final LfNetwork network; - private final EquationSystem equationSystem; - - private final VariableSet variableSet; - private final NewtonRaphsonResult lastNewtonRaphsonResult; - OuterLoopContext(int iteration, LfNetwork network, EquationSystem equationSystem, VariableSet variableSet, - NewtonRaphsonResult lastNewtonRaphsonResult) { + OuterLoopContext(int iteration, LfNetwork network, NewtonRaphsonResult lastNewtonRaphsonResult) { this.iteration = iteration; this.network = Objects.requireNonNull(network); - this.equationSystem = Objects.requireNonNull(equationSystem); - this.variableSet = Objects.requireNonNull(variableSet); this.lastNewtonRaphsonResult = Objects.requireNonNull(lastNewtonRaphsonResult); } @@ -45,14 +36,6 @@ public LfNetwork getNetwork() { return network; } - public EquationSystem getEquationSystem() { - return equationSystem; - } - - public VariableSet getVariableSet() { - return variableSet; - } - public NewtonRaphsonResult getLastNewtonRaphsonResult() { return lastNewtonRaphsonResult; } diff --git a/src/main/java/com/powsybl/openloadflow/network/AbstractLfBranch.java b/src/main/java/com/powsybl/openloadflow/network/AbstractLfBranch.java index 0ae2d4b7a9..351ff6437e 100644 --- a/src/main/java/com/powsybl/openloadflow/network/AbstractLfBranch.java +++ b/src/main/java/com/powsybl/openloadflow/network/AbstractLfBranch.java @@ -23,6 +23,8 @@ public abstract class AbstractLfBranch implements LfBranch { private int num = -1; + private final LfNetwork network; + private final LfBus bus1; private final LfBus bus2; @@ -33,7 +35,8 @@ public abstract class AbstractLfBranch implements LfBranch { protected DiscreteVoltageControl discreteVoltageControl; - protected AbstractLfBranch(LfBus bus1, LfBus bus2, PiModel piModel) { + protected AbstractLfBranch(LfNetwork network, LfBus bus1, LfBus bus2, PiModel piModel) { + this.network = Objects.requireNonNull(network); this.bus1 = bus1; this.bus2 = bus2; this.piModel = Objects.requireNonNull(piModel); @@ -49,6 +52,11 @@ public void setNum(int num) { this.num = num; } + @Override + public LfNetwork getNetwork() { + return network; + } + @Override public LfBus getBus1() { return bus1; diff --git a/src/main/java/com/powsybl/openloadflow/network/DiscretePhaseControl.java b/src/main/java/com/powsybl/openloadflow/network/DiscretePhaseControl.java index 7cc97a4cb5..b0871cf8d3 100644 --- a/src/main/java/com/powsybl/openloadflow/network/DiscretePhaseControl.java +++ b/src/main/java/com/powsybl/openloadflow/network/DiscretePhaseControl.java @@ -39,8 +39,8 @@ public enum Unit { public DiscretePhaseControl(LfBranch controller, LfBranch controlled, ControlledSide controlledSide, DiscretePhaseControl.Mode mode, double targetValue, double targetDeadband, Unit unit) { - this.controller = controller; - this.controlled = controlled; + this.controller = Objects.requireNonNull(controller); + this.controlled = Objects.requireNonNull(controlled); this.targetValue = targetValue; this.targetDeadband = targetDeadband; this.controlledSide = Objects.requireNonNull(controlledSide); @@ -73,7 +73,14 @@ public Mode getMode() { } public void setMode(Mode mode) { - this.mode = Objects.requireNonNull(mode); + Objects.requireNonNull(mode); + if (this.mode != mode) { + Mode oldMode = this.mode; + this.mode = mode; + for (LfNetworkListener listener : controller.getNetwork().getListeners()) { + listener.onPhaseControlModeChange(this, oldMode, mode); + } + } } public Unit getUnit() { diff --git a/src/main/java/com/powsybl/openloadflow/network/DiscreteVoltageControl.java b/src/main/java/com/powsybl/openloadflow/network/DiscreteVoltageControl.java index 17d8a83d36..69077b5fd6 100644 --- a/src/main/java/com/powsybl/openloadflow/network/DiscreteVoltageControl.java +++ b/src/main/java/com/powsybl/openloadflow/network/DiscreteVoltageControl.java @@ -30,7 +30,7 @@ public enum Mode { private final double targetValue; public DiscreteVoltageControl(LfBus controlled, DiscreteVoltageControl.Mode mode, double targetValue) { - this.controlled = controlled; + this.controlled = Objects.requireNonNull(controlled); this.targetValue = targetValue; this.mode = Objects.requireNonNull(mode); } @@ -40,7 +40,14 @@ public Mode getMode() { } public void setMode(Mode mode) { - this.mode = Objects.requireNonNull(mode); + Objects.requireNonNull(mode); + if (mode != this.mode) { + Mode oldMode = this.mode; + this.mode = mode; + for (LfNetworkListener listener : controlled.getNetwork().getListeners()) { + listener.onVoltageControlModeChange(this, oldMode, mode); + } + } } public double getTargetValue() { diff --git a/src/main/java/com/powsybl/openloadflow/network/LfBranch.java b/src/main/java/com/powsybl/openloadflow/network/LfBranch.java index 0e885fa00b..4fe29a658b 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfBranch.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfBranch.java @@ -19,6 +19,8 @@ public interface LfBranch { void setNum(int num); + LfNetwork getNetwork(); + LfBus getBus1(); LfBus getBus2(); diff --git a/src/main/java/com/powsybl/openloadflow/network/LfBus.java b/src/main/java/com/powsybl/openloadflow/network/LfBus.java index 4e6de50629..a1cf0c5aec 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfBus.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfBus.java @@ -20,6 +20,8 @@ public interface LfBus { void setNum(int num); + LfNetwork getNetwork(); + String getVoltageLevelId(); boolean isFictitious(); diff --git a/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java b/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java index 50cc04aacc..c748ab1ddd 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java @@ -12,4 +12,8 @@ public interface LfNetworkListener { void onVoltageControlChange(LfBus bus, boolean oldVoltageControl, boolean newVoltageControl); + + void onPhaseControlModeChange(DiscretePhaseControl phaseControl, DiscretePhaseControl.Mode oldMode, DiscretePhaseControl.Mode newMode); + + void onVoltageControlModeChange(DiscreteVoltageControl voltageControl, DiscreteVoltageControl.Mode oldMode, DiscreteVoltageControl.Mode newMode); } diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java index 5cabb99a38..fa4fcfeac3 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java @@ -101,6 +101,11 @@ public void setNum(int num) { this.num = num; } + @Override + public LfNetwork getNetwork() { + return network; + } + @Override public boolean isSlack() { return slack; 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 12683b1333..0f64148a95 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfBranchImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfBranchImpl.java @@ -32,12 +32,12 @@ public class LfBranchImpl extends AbstractLfBranch { private Evaluable q2 = NAN; - protected LfBranchImpl(LfBus bus1, LfBus bus2, PiModel piModel, Branch branch) { - super(bus1, bus2, piModel); + protected LfBranchImpl(LfNetwork network, LfBus bus1, LfBus bus2, PiModel piModel, Branch branch) { + super(network, bus1, bus2, piModel); this.branch = branch; } - private static LfBranchImpl createLine(Line line, LfBus bus1, LfBus bus2, double zb) { + private static LfBranchImpl createLine(Line line, LfNetwork network, LfBus bus1, LfBus bus2, double zb) { PiModel piModel = new SimplePiModel() .setR(line.getR() / zb) .setX(line.getX() / zb) @@ -46,10 +46,10 @@ private static LfBranchImpl createLine(Line line, LfBus bus1, LfBus bus2, double .setB1(line.getB1() * zb) .setB2(line.getB2() * zb); - return new LfBranchImpl(bus1, bus2, piModel, line); + return new LfBranchImpl(network, bus1, bus2, piModel, line); } - private static LfBranchImpl createTransformer(TwoWindingsTransformer twt, LfBus bus1, LfBus bus2, double zb, boolean twtSplitShuntAdmittance) { + private static LfBranchImpl createTransformer(TwoWindingsTransformer twt, LfNetwork network, LfBus bus1, LfBus bus2, double zb, boolean twtSplitShuntAdmittance) { PiModel piModel = null; double baseRatio = Transformers.getRatioPerUnitBase(twt); @@ -93,18 +93,18 @@ private static LfBranchImpl createTransformer(TwoWindingsTransformer twt, LfBus piModel = Transformers.createPiModel(tapCharacteristics, zb, baseRatio, twtSplitShuntAdmittance); } - return new LfBranchImpl(bus1, bus2, piModel, twt); + return new LfBranchImpl(network, bus1, bus2, piModel, twt); } - public static LfBranchImpl create(Branch branch, LfBus bus1, LfBus bus2, boolean twtSplitShuntAdmittance) { + public static LfBranchImpl create(Branch branch, LfNetwork network, LfBus bus1, LfBus bus2, boolean twtSplitShuntAdmittance) { Objects.requireNonNull(branch); double nominalV2 = branch.getTerminal2().getVoltageLevel().getNominalV(); double zb = nominalV2 * nominalV2 / PerUnit.SB; if (branch instanceof Line) { - return createLine((Line) branch, bus1, bus2, zb); + return createLine((Line) branch, network, bus1, bus2, zb); } else if (branch instanceof TwoWindingsTransformer) { TwoWindingsTransformer twt = (TwoWindingsTransformer) branch; - return createTransformer(twt, bus1, bus2, zb, twtSplitShuntAdmittance); + return createTransformer(twt, network, bus1, bus2, zb, twtSplitShuntAdmittance); } 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/LfBusImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfBusImpl.java index b8da3d8d98..cdecbb9e75 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfBusImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfBusImpl.java @@ -25,7 +25,7 @@ public class LfBusImpl extends AbstractLfBus { private final double highVoltageLimit; - protected LfBusImpl(LfNetwork network, Bus bus, double v, double angle) { + protected LfBusImpl(Bus bus, LfNetwork network, double v, double angle) { super(network, v, angle); this.bus = bus; nominalV = bus.getVoltageLevel().getNominalV(); @@ -33,9 +33,9 @@ protected LfBusImpl(LfNetwork network, Bus bus, double v, double angle) { highVoltageLimit = bus.getVoltageLevel().getHighVoltageLimit(); } - public static LfBusImpl create(LfNetwork network, Bus bus) { + public static LfBusImpl create(Bus bus, LfNetwork network) { Objects.requireNonNull(bus); - return new LfBusImpl(network, bus, bus.getV(), bus.getAngle()); + return new LfBusImpl(bus, network, bus.getV(), bus.getAngle()); } @Override diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfDanglingLineBranch.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfDanglingLineBranch.java index 1e4819be24..c712d96688 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfDanglingLineBranch.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfDanglingLineBranch.java @@ -25,12 +25,12 @@ public class LfDanglingLineBranch extends AbstractLfBranch { private Evaluable q = NAN; - protected LfDanglingLineBranch(LfBus bus1, LfBus bus2, PiModel piModel, DanglingLine danglingLine) { - super(bus1, bus2, piModel); + protected LfDanglingLineBranch(LfNetwork network, LfBus bus1, LfBus bus2, PiModel piModel, DanglingLine danglingLine) { + super(network, bus1, bus2, piModel); this.danglingLine = danglingLine; } - public static LfDanglingLineBranch create(DanglingLine danglingLine, LfBus bus1, LfBus bus2) { + public static LfDanglingLineBranch create(DanglingLine danglingLine, LfNetwork network, LfBus bus1, LfBus bus2) { Objects.requireNonNull(danglingLine); Objects.requireNonNull(bus1); Objects.requireNonNull(bus2); @@ -43,7 +43,7 @@ public static LfDanglingLineBranch create(DanglingLine danglingLine, LfBus bus1, .setG2(danglingLine.getG() / 2 * zb) .setB1(danglingLine.getB() / 2 * zb) .setB2(danglingLine.getB() / 2 * zb); - return new LfDanglingLineBranch(bus1, bus2, piModel, danglingLine); + return new LfDanglingLineBranch(network, bus1, bus2, piModel, danglingLine); } @Override 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 89f928f4bf..efb1dd9472 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfLegBranch.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfLegBranch.java @@ -32,13 +32,13 @@ public class LfLegBranch extends AbstractLfBranch { private Evaluable q = NAN; - protected LfLegBranch(LfBus bus1, LfBus bus0, PiModel piModel, ThreeWindingsTransformer twt, ThreeWindingsTransformer.Leg leg) { - super(bus1, bus0, piModel); + protected LfLegBranch(LfNetwork network, LfBus bus1, LfBus bus0, PiModel piModel, ThreeWindingsTransformer twt, ThreeWindingsTransformer.Leg leg) { + super(network, bus1, bus0, piModel); this.twt = twt; this.leg = leg; } - public static LfLegBranch create(LfBus bus1, LfBus bus0, ThreeWindingsTransformer twt, ThreeWindingsTransformer.Leg leg, + public static LfLegBranch create(LfNetwork network, LfBus bus1, LfBus bus0, ThreeWindingsTransformer twt, ThreeWindingsTransformer.Leg leg, boolean twtSplitShuntAdmittance) { Objects.requireNonNull(bus0); Objects.requireNonNull(twt); @@ -88,7 +88,7 @@ public static LfLegBranch create(LfBus bus1, LfBus bus0, ThreeWindingsTransforme piModel = Transformers.createPiModel(tapCharacteristics, zb, baseRatio, twtSplitShuntAdmittance); } - return new LfLegBranch(bus1, bus0, piModel, twt, leg); + return new LfLegBranch(network, bus1, bus0, piModel, twt, leg); } private int getLegNum() { 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 8fb0b8aee2..5c94435365 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java @@ -63,7 +63,7 @@ private static Bus getBus(Terminal terminal, boolean breakers) { private static LfBusImpl createBus(Bus bus, LfNetworkParameters parameters, LfNetwork lfNetwork, LoadingContext loadingContext, LfNetworkLoadingReport report, Map controllerBusToControlledBusId) { - LfBusImpl lfBus = LfBusImpl.create(lfNetwork, bus); + LfBusImpl lfBus = LfBusImpl.create(bus, lfNetwork); bus.visitConnectedEquipments(new DefaultTopologyVisitor() { @@ -196,7 +196,7 @@ private static void createBranches(LfNetwork lfNetwork, LoadingContext loadingCo for (Branch branch : loadingContext.branchSet) { LfBus lfBus1 = getLfBus(branch.getTerminal1(), lfNetwork, breakers); LfBus lfBus2 = getLfBus(branch.getTerminal2(), lfNetwork, breakers); - addBranch(lfNetwork, LfBranchImpl.create(branch, lfBus1, lfBus2, twtSplitShuntAdmittance), report); + addBranch(lfNetwork, LfBranchImpl.create(branch, lfNetwork, lfBus1, lfBus2, twtSplitShuntAdmittance), report); } for (Branch branch : loadingContext.branchSet) { @@ -214,7 +214,7 @@ private static void createBranches(LfNetwork lfNetwork, LoadingContext loadingCo LfDanglingLineBus lfBus2 = new LfDanglingLineBus(lfNetwork, danglingLine); lfNetwork.addBus(lfBus2); LfBus lfBus1 = getLfBus(danglingLine.getTerminal(), lfNetwork, breakers); - addBranch(lfNetwork, LfDanglingLineBranch.create(danglingLine, lfBus1, lfBus2), report); + addBranch(lfNetwork, LfDanglingLineBranch.create(danglingLine, lfNetwork, lfBus1, lfBus2), report); } for (ThreeWindingsTransformer t3wt : loadingContext.t3wtSet) { @@ -223,9 +223,9 @@ private static void createBranches(LfNetwork lfNetwork, LoadingContext loadingCo LfBus lfBus1 = getLfBus(t3wt.getLeg1().getTerminal(), lfNetwork, breakers); LfBus lfBus2 = getLfBus(t3wt.getLeg2().getTerminal(), lfNetwork, breakers); LfBus lfBus3 = getLfBus(t3wt.getLeg3().getTerminal(), lfNetwork, breakers); - addBranch(lfNetwork, LfLegBranch.create(lfBus1, lfBus0, t3wt, t3wt.getLeg1(), twtSplitShuntAdmittance), report); - addBranch(lfNetwork, LfLegBranch.create(lfBus2, lfBus0, t3wt, t3wt.getLeg2(), twtSplitShuntAdmittance), report); - addBranch(lfNetwork, LfLegBranch.create(lfBus3, lfBus0, t3wt, t3wt.getLeg3(), twtSplitShuntAdmittance), report); + addBranch(lfNetwork, LfLegBranch.create(lfNetwork, lfBus1, lfBus0, t3wt, t3wt.getLeg1(), twtSplitShuntAdmittance), report); + addBranch(lfNetwork, LfLegBranch.create(lfNetwork, lfBus2, lfBus0, t3wt, t3wt.getLeg2(), twtSplitShuntAdmittance), report); + addBranch(lfNetwork, LfLegBranch.create(lfNetwork, lfBus3, lfBus0, t3wt, t3wt.getLeg3(), twtSplitShuntAdmittance), report); } for (ThreeWindingsTransformer t3wt : loadingContext.t3wtSet) { @@ -250,7 +250,7 @@ private static void createSwitches(List switches, LfNetwork lfNetwork) { Bus bus2 = vl.getBusBreakerView().getBus2(sw.getId()); LfBus lfBus1 = lfNetwork.getBusById(bus1.getId()); LfBus lfBus2 = lfNetwork.getBusById(bus2.getId()); - lfNetwork.addBranch(new LfSwitch(lfBus1, lfBus2, sw)); + lfNetwork.addBranch(new LfSwitch(lfNetwork, lfBus1, lfBus2, sw)); } } } diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfSwitch.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfSwitch.java index ad3e3a9940..39d515bc26 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfSwitch.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfSwitch.java @@ -9,6 +9,7 @@ import com.powsybl.iidm.network.Switch; import com.powsybl.openloadflow.network.AbstractLfBranch; import com.powsybl.openloadflow.network.LfBus; +import com.powsybl.openloadflow.network.LfNetwork; import com.powsybl.openloadflow.network.SimplePiModel; import com.powsybl.openloadflow.util.Evaluable; @@ -21,8 +22,8 @@ public class LfSwitch extends AbstractLfBranch { private final Switch aSwitch; - public LfSwitch(LfBus bus1, LfBus bus2, Switch aSwitch) { - super(bus1, bus2, new SimplePiModel()); + public LfSwitch(LfNetwork network, LfBus bus1, LfBus bus2, Switch aSwitch) { + super(network, bus1, bus2, new SimplePiModel()); this.aSwitch = Objects.requireNonNull(aSwitch); } From 5b0a534875336ca946b65564ecceb800346cedc0 Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Sat, 6 Feb 2021 21:16:03 +0100 Subject: [PATCH 03/13] Cleanup Signed-off-by: Geoffroy Jamgotchian --- .../powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java index d94e8dc727..9868a8658b 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java @@ -100,7 +100,7 @@ private static class RunningContext { private final Map outerLoopIterationByType = new HashMap<>(); } - private void runOuterLoop(OuterLoop outerLoop, LfNetwork network, EquationSystem equationSystem, VariableSet variableSet, + private void runOuterLoop(OuterLoop outerLoop, LfNetwork network, EquationSystem equationSystem, NewtonRaphson newtonRaphson, NewtonRaphsonParameters nrParameters, RunningContext runningContext) { // for each outer loop re-run Newton-Raphson until stabilization OuterLoopStatus outerLoopStatus; @@ -170,7 +170,7 @@ public AcLoadFlowResult run() { // outer loops are nested: inner most loop first in the list, outer most loop last for (OuterLoop outerLoop : parameters.getOuterLoops()) { - runOuterLoop(outerLoop, network, equationSystem, variableSet, newtonRaphson, nrParameters, runningContext); + runOuterLoop(outerLoop, network, equationSystem, newtonRaphson, nrParameters, runningContext); // continue with next outer loop only if last Newton-Raphson succeed if (runningContext.lastNrResult.getStatus() != NewtonRaphsonStatus.CONVERGED) { From 7aa4e96c7f0dca014ceeb7465ae23776d5bd8dcf Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Sat, 6 Feb 2021 22:02:52 +0100 Subject: [PATCH 04/13] Cleanup Signed-off-by: Geoffroy Jamgotchian --- .../powsybl/openloadflow/ac/equations/AcEquationSystem.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java index df5d2aa8ce..0b73f2a19d 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java @@ -397,7 +397,7 @@ public void onVoltageControlChange(LfBus bus, boolean oldVoltageControl, boolean @Override public void onPhaseControlModeChange(DiscretePhaseControl phaseControl, DiscretePhaseControl.Mode oldMode, DiscretePhaseControl.Mode newMode) { if (newMode == DiscretePhaseControl.Mode.OFF) { - // de-activate a1 variable for next outer loop run + // de-activate a1 variable Variable a1 = variableSet.getVariable(phaseControl.getController().getNum(), VariableType.BRANCH_ALPHA1); a1.setActive(false); @@ -416,7 +416,6 @@ public void onVoltageControlModeChange(DiscreteVoltageControl voltageControl, Di Equation t = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V); t.setActive(false); - // at first iteration all branches controlling voltage are switched off for (LfBranch controllerBranch : bus.getDiscreteVoltageControl().getControllers()) { // de-activate r1 variable Variable r1 = variableSet.getVariable(controllerBranch.getNum(), VariableType.BRANCH_RHO1); From 77f7f9d931ed643c5d0c15c7766895eab7d86a75 Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Sun, 7 Feb 2021 14:23:44 +0100 Subject: [PATCH 05/13] Add checks Signed-off-by: Geoffroy Jamgotchian --- .../powsybl/openloadflow/ac/equations/AcEquationSystem.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java index 0b73f2a19d..175859138f 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java @@ -404,6 +404,8 @@ public void onPhaseControlModeChange(DiscretePhaseControl phaseControl, Discrete // de-activate phase control equation Equation t = equationSystem.createEquation(phaseControl.getControlled().getNum(), EquationType.BRANCH_P); t.setActive(false); + } else { + throw new UnsupportedOperationException("TODO"); } } @@ -424,6 +426,8 @@ public void onVoltageControlModeChange(DiscreteVoltageControl voltageControl, Di // clean transformer distribution equations equationSystem.removeEquation(controllerBranch.getNum(), EquationType.ZERO_RHO1); } + } else { + throw new UnsupportedOperationException("TODO"); } } }); From e95f2567bc88595168775b44d6c531939f3bd0cb Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Sun, 7 Feb 2021 22:36:16 +0100 Subject: [PATCH 06/13] Add AbstractElement Signed-off-by: Geoffroy Jamgotchian --- .../openloadflow/network/AbstractElement.java | 35 +++++++++++++++++++ .../network/AbstractLfBranch.java | 23 ++---------- .../network/impl/AbstractLfBus.java | 25 ++----------- .../network/impl/LfShuntImpl.java | 17 +++------ 4 files changed, 45 insertions(+), 55 deletions(-) create mode 100644 src/main/java/com/powsybl/openloadflow/network/AbstractElement.java diff --git a/src/main/java/com/powsybl/openloadflow/network/AbstractElement.java b/src/main/java/com/powsybl/openloadflow/network/AbstractElement.java new file mode 100644 index 0000000000..d1a10c2865 --- /dev/null +++ b/src/main/java/com/powsybl/openloadflow/network/AbstractElement.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2021, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.openloadflow.network; + +import java.util.Objects; + +/** + * @author Geoffroy Jamgotchian + */ +public abstract class AbstractElement { + + protected final LfNetwork network; + + protected int num = -1; + + protected AbstractElement(LfNetwork network) { + this.network = Objects.requireNonNull(network); + } + + public int getNum() { + return num; + } + + public void setNum(int num) { + this.num = num; + } + + public LfNetwork getNetwork() { + return network; + } +} diff --git a/src/main/java/com/powsybl/openloadflow/network/AbstractLfBranch.java b/src/main/java/com/powsybl/openloadflow/network/AbstractLfBranch.java index 351ff6437e..b782f6d9c8 100644 --- a/src/main/java/com/powsybl/openloadflow/network/AbstractLfBranch.java +++ b/src/main/java/com/powsybl/openloadflow/network/AbstractLfBranch.java @@ -17,14 +17,10 @@ /** * @author Geoffroy Jamgotchian */ -public abstract class AbstractLfBranch implements LfBranch { +public abstract class AbstractLfBranch extends AbstractElement implements LfBranch { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractLfBranch.class); - private int num = -1; - - private final LfNetwork network; - private final LfBus bus1; private final LfBus bus2; @@ -36,27 +32,12 @@ public abstract class AbstractLfBranch implements LfBranch { protected DiscreteVoltageControl discreteVoltageControl; protected AbstractLfBranch(LfNetwork network, LfBus bus1, LfBus bus2, PiModel piModel) { - this.network = Objects.requireNonNull(network); + super(network); this.bus1 = bus1; this.bus2 = bus2; this.piModel = Objects.requireNonNull(piModel); } - @Override - public int getNum() { - return num; - } - - @Override - public void setNum(int num) { - this.num = num; - } - - @Override - public LfNetwork getNetwork() { - return network; - } - @Override public LfBus getBus1() { return bus1; diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java index fa4fcfeac3..70540294ef 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java @@ -21,7 +21,7 @@ /** * @author Geoffroy Jamgotchian */ -public abstract class AbstractLfBus implements LfBus { +public abstract class AbstractLfBus extends AbstractElement implements LfBus { protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractLfBus.class); @@ -29,10 +29,6 @@ public abstract class AbstractLfBus implements LfBus { private static final double Q_DISPATCH_EPSILON = 1e-3; private static final double TARGET_V_EPSILON = 1e-2; - private final LfNetwork network; - - private int num = -1; - protected boolean slack = false; protected double v; @@ -86,26 +82,11 @@ public abstract class AbstractLfBus implements LfBus { protected boolean disabled = false; protected AbstractLfBus(LfNetwork network, double v, double angle) { - this.network = Objects.requireNonNull(network); + super(network); this.v = v; this.angle = angle; } - @Override - public int getNum() { - return num; - } - - @Override - public void setNum(int num) { - this.num = num; - } - - @Override - public LfNetwork getNetwork() { - return network; - } - @Override public boolean isSlack() { return slack; @@ -323,7 +304,7 @@ void addVscConverterStation(VscConverterStation vscCs, LfNetworkLoadingReport re } void addShuntCompensator(ShuntCompensator sc) { - shunts.add(new LfShuntImpl(sc)); + shunts.add(new LfShuntImpl(sc, network)); } @Override diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfShuntImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfShuntImpl.java index 069f7e6d9e..962a4e167f 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfShuntImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfShuntImpl.java @@ -7,6 +7,8 @@ package com.powsybl.openloadflow.network.impl; import com.powsybl.iidm.network.ShuntCompensator; +import com.powsybl.openloadflow.network.AbstractElement; +import com.powsybl.openloadflow.network.LfNetwork; import com.powsybl.openloadflow.network.LfShunt; import com.powsybl.openloadflow.network.PerUnit; import com.powsybl.openloadflow.util.Evaluable; @@ -18,17 +20,16 @@ /** * @author Geoffroy Jamgotchian */ -public class LfShuntImpl implements LfShunt { +public class LfShuntImpl extends AbstractElement implements LfShunt { private final ShuntCompensator shuntCompensator; - private int num = -1; - private final double b; private Evaluable q = NAN; - public LfShuntImpl(ShuntCompensator shuntCompensator) { + public LfShuntImpl(ShuntCompensator shuntCompensator, LfNetwork network) { + super(network); this.shuntCompensator = Objects.requireNonNull(shuntCompensator); double nominalV = shuntCompensator.getTerminal().getVoltageLevel().getNominalV(); double zb = nominalV * nominalV / PerUnit.SB; @@ -40,14 +41,6 @@ public String getId() { return shuntCompensator.getId(); } - public int getNum() { - return num; - } - - public void setNum(int num) { - this.num = num; - } - @Override public double getB() { return b; From 7b42ddbf1b92f59948a6e1b5b445476931978df8 Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Sun, 7 Feb 2021 22:42:47 +0100 Subject: [PATCH 07/13] Fix Sonar issue Signed-off-by: Geoffroy Jamgotchian --- .../com/powsybl/openloadflow/sa/OpenSecurityAnalysis.java | 7 +++---- src/main/java/com/powsybl/openloadflow/util/BusState.java | 3 +-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysis.java index d0f3b03c6a..52b4d1d731 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysis.java @@ -282,7 +282,7 @@ private SecurityAnalysisResult runSimulations(LfNetwork network, List getBusStates(List buses) { /** * Set the bus states based on the given map of states * @param busStates the map containing the bus states, indexed by buses - * @param engine AcLoadFlowEngine to operate the PqPv switching if the bus has lost its voltage control */ - private void restoreBusStates(Map busStates, AcloadFlowEngine engine) { - busStates.forEach((b, state) -> state.restoreBusState(b, engine)); + private void restoreBusStates(Map busStates) { + busStates.forEach((b, state) -> state.restoreBusState(b)); } } diff --git a/src/main/java/com/powsybl/openloadflow/util/BusState.java b/src/main/java/com/powsybl/openloadflow/util/BusState.java index 73a480df1f..d2886b452e 100644 --- a/src/main/java/com/powsybl/openloadflow/util/BusState.java +++ b/src/main/java/com/powsybl/openloadflow/util/BusState.java @@ -6,7 +6,6 @@ */ package com.powsybl.openloadflow.util; -import com.powsybl.openloadflow.ac.outerloop.AcloadFlowEngine; import com.powsybl.openloadflow.network.LfBus; import com.powsybl.openloadflow.network.LfGenerator; @@ -37,7 +36,7 @@ public BusState(LfBus b) { this.generationTargetQ = b.getGenerationTargetQ(); } - public void restoreBusState(LfBus bus, AcloadFlowEngine engine) { + public void restoreBusState(LfBus bus) { restoreDcBusState(bus); bus.setV(v); bus.setLoadTargetQ(loadTargetQ); From f3591392f78bbfb99ccb80ddc9d49c18502dac48 Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Sun, 7 Feb 2021 23:19:30 +0100 Subject: [PATCH 08/13] Refactor phase control equations Signed-off-by: Geoffroy Jamgotchian --- .../ac/equations/AcEquationSystem.java | 31 +++++++++++-------- .../equations/BranchA1EquationTerm.java | 6 +--- 2 files changed, 19 insertions(+), 18 deletions(-) rename src/main/java/com/powsybl/openloadflow/{dc => }/equations/BranchA1EquationTerm.java (71%) diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java index 175859138f..3aea6dfb07 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java @@ -222,14 +222,21 @@ private static void createNonImpedantBranch(VariableSet variableSet, EquationSys } private static void createBranchActivePowerTargetEquation(LfBranch branch, DiscretePhaseControl.ControlledSide controlledSide, - EquationSystem equationSystem, EquationTerm p) { + EquationSystem equationSystem, VariableSet variableSet, EquationTerm p) { if (branch.isPhaseControlled(controlledSide)) { DiscretePhaseControl phaseControl = branch.getDiscretePhaseControl(); if (phaseControl.getMode() == DiscretePhaseControl.Mode.CONTROLLER) { if (phaseControl.getUnit() == DiscretePhaseControl.Unit.A) { throw new PowsyblException("Phase control in A is not yet supported"); } + equationSystem.createEquation(branch.getNum(), EquationType.BRANCH_P).addTerm(p); + + // also create an inactive equation to have a1 variable constant + LfBranch controller = phaseControl.getController(); + equationSystem.createEquation(controller.getNum(), EquationType.BRANCH_ALPHA1) + .addTerm(new BranchA1EquationTerm(controller, variableSet)) + .setActive(false); } } } @@ -285,7 +292,7 @@ private static void createImpedantBranch(LfBranch branch, LfBus bus1, LfBus bus2 equationSystem.createEquation(bus1.getNum(), EquationType.BUS_P).addTerm(p1); branch.setP1(p1); if (creationParameters.isPhaseControl()) { - createBranchActivePowerTargetEquation(branch, DiscretePhaseControl.ControlledSide.ONE, equationSystem, p1); + createBranchActivePowerTargetEquation(branch, DiscretePhaseControl.ControlledSide.ONE, equationSystem, variableSet, p1); } } if (q1 != null) { @@ -296,7 +303,7 @@ private static void createImpedantBranch(LfBranch branch, LfBus bus1, LfBus bus2 equationSystem.createEquation(bus2.getNum(), EquationType.BUS_P).addTerm(p2); branch.setP2(p2); if (creationParameters.isPhaseControl()) { - createBranchActivePowerTargetEquation(branch, DiscretePhaseControl.ControlledSide.TWO, equationSystem, p2); + createBranchActivePowerTargetEquation(branch, DiscretePhaseControl.ControlledSide.TWO, equationSystem, variableSet, p2); } } if (q2 != null) { @@ -396,17 +403,15 @@ public void onVoltageControlChange(LfBus bus, boolean oldVoltageControl, boolean @Override public void onPhaseControlModeChange(DiscretePhaseControl phaseControl, DiscretePhaseControl.Mode oldMode, DiscretePhaseControl.Mode newMode) { - if (newMode == DiscretePhaseControl.Mode.OFF) { - // de-activate a1 variable - Variable a1 = variableSet.getVariable(phaseControl.getController().getNum(), VariableType.BRANCH_ALPHA1); - a1.setActive(false); + boolean on = newMode != DiscretePhaseControl.Mode.OFF; - // de-activate phase control equation - Equation t = equationSystem.createEquation(phaseControl.getControlled().getNum(), EquationType.BRANCH_P); - t.setActive(false); - } else { - throw new UnsupportedOperationException("TODO"); - } + // activate/de-activate phase control equation + equationSystem.createEquation(phaseControl.getControlled().getNum(), EquationType.BRANCH_P) + .setActive(on); + + // de-activate/activate constant phase equation + equationSystem.createEquation(phaseControl.getController().getNum(), EquationType.BRANCH_ALPHA1) + .setActive(!on); } @Override diff --git a/src/main/java/com/powsybl/openloadflow/dc/equations/BranchA1EquationTerm.java b/src/main/java/com/powsybl/openloadflow/equations/BranchA1EquationTerm.java similarity index 71% rename from src/main/java/com/powsybl/openloadflow/dc/equations/BranchA1EquationTerm.java rename to src/main/java/com/powsybl/openloadflow/equations/BranchA1EquationTerm.java index 92a8cb29bb..1bca52ebfe 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/equations/BranchA1EquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/equations/BranchA1EquationTerm.java @@ -4,12 +4,8 @@ * 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.dc.equations; +package com.powsybl.openloadflow.equations; -import com.powsybl.openloadflow.equations.AbstractTargetEquationTerm; -import com.powsybl.openloadflow.equations.SubjectType; -import com.powsybl.openloadflow.equations.VariableSet; -import com.powsybl.openloadflow.equations.VariableType; import com.powsybl.openloadflow.network.LfBranch; import java.util.Objects; From 791e0de1b7d923a4cedfc396cc4f5547c9539a63 Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Mon, 8 Feb 2021 10:53:49 +0100 Subject: [PATCH 09/13] Merge Signed-off-by: Geoffroy Jamgotchian --- .../com/powsybl/openloadflow/sa/OpenSecurityAnalysis.java | 1 + src/main/java/com/powsybl/openloadflow/util/BusState.java | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysis.java index c850a0d293..153ba792fc 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysis.java @@ -35,6 +35,7 @@ import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; diff --git a/src/main/java/com/powsybl/openloadflow/util/BusState.java b/src/main/java/com/powsybl/openloadflow/util/BusState.java index caf8532173..fcbc7414c1 100644 --- a/src/main/java/com/powsybl/openloadflow/util/BusState.java +++ b/src/main/java/com/powsybl/openloadflow/util/BusState.java @@ -68,10 +68,9 @@ public static Map createBusStates(Collection buses) { /** * Set the bus states based on the given map of states * @param busStates the map containing the bus states, indexed by buses - * @param engine AcLoadFlowEngine to operate the PqPv switching if the bus has lost its voltage control */ - public static void restoreBusStates(Map busStates, AcloadFlowEngine engine) { - busStates.forEach((b, state) -> state.restoreBusState(b, engine)); + public static void restoreBusStates(Map busStates) { + busStates.forEach((b, state) -> state.restoreBusState(b)); } /** From 137e285fbeadca8d78c3b89dac8c30426cd755b5 Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Sun, 28 Feb 2021 15:06:09 +0100 Subject: [PATCH 10/13] Merge Signed-off-by: Geoffroy Jamgotchian --- .../ac/equations/AcEquationSystem.java | 1 - .../ac/outerloop/AcloadFlowEngine.java | 2 +- .../openloadflow/sa/OpenSecurityAnalysis.java | 2 +- .../openloadflow/sensi/AcSensitivityAnalysis.java | 4 ++-- .../com/powsybl/openloadflow/util/BusState.java | 15 --------------- 5 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java index bf4c1d301b..21f8c4e08a 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java @@ -7,7 +7,6 @@ package com.powsybl.openloadflow.ac.equations; import com.powsybl.commons.PowsyblException; -import com.powsybl.openloadflow.dc.equations.BranchA1EquationTerm; import com.powsybl.openloadflow.dc.equations.DcEquationSystem; import com.powsybl.openloadflow.equations.*; import com.powsybl.openloadflow.network.*; diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java index 807bdf6eed..dc66c8826b 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java @@ -102,7 +102,7 @@ private void runOuterLoop(OuterLoop outerLoop, LfNetwork network, EquationSystem MutableInt outerLoopIteration = runningContext.outerLoopIterationByType.computeIfAbsent(outerLoop.getType(), k -> new MutableInt()); // check outer loop status - outerLoopStatus = outerLoop.check(new OuterLoopContext(outerLoopIteration.getValue(), network, equationSystem, variableSet, runningContext.lastNrResult)); + outerLoopStatus = outerLoop.check(new OuterLoopContext(outerLoopIteration.getValue(), network, runningContext.lastNrResult)); if (outerLoopStatus == OuterLoopStatus.UNSTABLE) { LOGGER.debug("Start outer loop iteration {} (name='{}')", outerLoopIteration, outerLoop.getType()); diff --git a/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysis.java index 8accba693a..b905784519 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysis.java @@ -240,7 +240,7 @@ private SecurityAnalysisResult runSimulations(LfNetwork network, List, Map>> analyse .forEach(lfFactor -> lfFactor.setPredefinedResult(0d)); contingenciesValues.put(lfContingency.getContingency().getId(), getPostContingencySensitivityValues(lfFactors, lfContingency, lfNetwork, engine, factorGroups, lfParameters, lfParametersExt)); - BusState.restoreBusStates(busStates, engine); + BusState.restoreBusStates(busStates); } // Contingency breaking connectivity @@ -233,7 +233,7 @@ public Pair, Map>> analyse contingenciesValues.put(lfContingency.getContingency().getId(), getPostContingencySensitivityValues(lfFactors, lfContingency, lfNetwork, engine, factorGroups, lfParameters, lfParametersExt)); - BusState.restoreBusStates(busStates, engine); + BusState.restoreBusStates(busStates); connectivity.reset(); } diff --git a/src/main/java/com/powsybl/openloadflow/util/BusState.java b/src/main/java/com/powsybl/openloadflow/util/BusState.java index 79e0bd0772..fcbc7414c1 100644 --- a/src/main/java/com/powsybl/openloadflow/util/BusState.java +++ b/src/main/java/com/powsybl/openloadflow/util/BusState.java @@ -6,10 +6,6 @@ */ package com.powsybl.openloadflow.util; -import com.powsybl.openloadflow.ac.ReactiveLimitsOuterLoop; -import com.powsybl.openloadflow.ac.outerloop.AcloadFlowEngine; -import com.powsybl.openloadflow.equations.EquationSystem; -import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBus; import com.powsybl.openloadflow.network.LfGenerator; @@ -72,17 +68,6 @@ public static Map createBusStates(Collection buses) { /** * Set the bus states based on the given map of states * @param busStates the map containing the bus states, indexed by buses - * @param engine AcLoadFlowEngine to operate the PqPv switching if the bus has lost its voltage control - */ - public static void restoreBusStates(Map busStates) { - restoreBusStates(busStates); - } - - /** - * Set the bus states based on the given map of states - * @param busStates the map containing the bus states, indexed by buses - * @param equationSystem to operate the PqPv switching if the bus has lost its voltage control - * @param variableSet to operate the PqPv switching if the bus has lost its voltage control */ public static void restoreBusStates(Map busStates) { busStates.forEach((b, state) -> state.restoreBusState(b)); From a549324b99130a605bf7e7358ffdf6047e9fd6c1 Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Sun, 28 Feb 2021 15:08:46 +0100 Subject: [PATCH 11/13] Revert phase control refactoring Signed-off-by: Geoffroy Jamgotchian --- .../ac/equations/AcEquationSystem.java | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java index 21f8c4e08a..8f06157201 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java @@ -222,7 +222,7 @@ private static void createNonImpedantBranch(VariableSet variableSet, EquationSys } private static void createBranchActivePowerTargetEquation(LfBranch branch, DiscretePhaseControl.ControlledSide controlledSide, - EquationSystem equationSystem, VariableSet variableSet, EquationTerm p) { + EquationSystem equationSystem, EquationTerm p) { if (branch.isPhaseControlled(controlledSide)) { DiscretePhaseControl phaseControl = branch.getDiscretePhaseControl(); if (phaseControl.getMode() == DiscretePhaseControl.Mode.CONTROLLER) { @@ -231,12 +231,6 @@ private static void createBranchActivePowerTargetEquation(LfBranch branch, Discr } equationSystem.createEquation(branch.getNum(), EquationType.BRANCH_P).addTerm(p); - - // also create an inactive equation to have a1 variable constant - LfBranch controller = phaseControl.getController(); - equationSystem.createEquation(controller.getNum(), EquationType.BRANCH_ALPHA1) - .addTerm(new BranchA1EquationTerm(controller, variableSet)) - .setActive(false); } } } @@ -293,7 +287,7 @@ private static void createImpedantBranch(LfBranch branch, LfBus bus1, LfBus bus2 equationSystem.createEquation(bus1.getNum(), EquationType.BUS_P).addTerm(p1); branch.setP1(p1); if (creationParameters.isPhaseControl()) { - createBranchActivePowerTargetEquation(branch, DiscretePhaseControl.ControlledSide.ONE, equationSystem, variableSet, p1); + createBranchActivePowerTargetEquation(branch, DiscretePhaseControl.ControlledSide.ONE, equationSystem, p1); } } if (q1 != null) { @@ -304,7 +298,7 @@ private static void createImpedantBranch(LfBranch branch, LfBus bus1, LfBus bus2 equationSystem.createEquation(bus2.getNum(), EquationType.BUS_P).addTerm(p2); branch.setP2(p2); if (creationParameters.isPhaseControl()) { - createBranchActivePowerTargetEquation(branch, DiscretePhaseControl.ControlledSide.TWO, equationSystem, variableSet, p2); + createBranchActivePowerTargetEquation(branch, DiscretePhaseControl.ControlledSide.TWO, equationSystem, p2); } } if (q2 != null) { @@ -409,15 +403,17 @@ public void onVoltageControlChange(LfBus bus, boolean oldVoltageControl, boolean @Override public void onPhaseControlModeChange(DiscretePhaseControl phaseControl, DiscretePhaseControl.Mode oldMode, DiscretePhaseControl.Mode newMode) { - boolean on = newMode != DiscretePhaseControl.Mode.OFF; - - // activate/de-activate phase control equation - equationSystem.createEquation(phaseControl.getControlled().getNum(), EquationType.BRANCH_P) - .setActive(on); + if (newMode == DiscretePhaseControl.Mode.OFF) { + // de-activate a1 variable + Variable a1 = variableSet.getVariable(phaseControl.getController().getNum(), VariableType.BRANCH_ALPHA1); + a1.setActive(false); - // de-activate/activate constant phase equation - equationSystem.createEquation(phaseControl.getController().getNum(), EquationType.BRANCH_ALPHA1) - .setActive(!on); + // de-activate phase control equation + Equation t = equationSystem.createEquation(phaseControl.getControlled().getNum(), EquationType.BRANCH_P); + t.setActive(false); + } else { + throw new UnsupportedOperationException("TODO"); + } } @Override From d14ab86eb21d7a98d0c8c6993aaaf4aa9733e16b Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Sun, 28 Feb 2021 15:16:27 +0100 Subject: [PATCH 12/13] Remove oldVoltageControl Signed-off-by: Geoffroy Jamgotchian --- .../powsybl/openloadflow/ac/equations/AcEquationSystem.java | 3 +-- .../com/powsybl/openloadflow/network/LfNetworkListener.java | 2 +- .../com/powsybl/openloadflow/network/impl/AbstractLfBus.java | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java index 8f06157201..a88bdd58cd 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java @@ -229,7 +229,6 @@ private static void createBranchActivePowerTargetEquation(LfBranch branch, Discr if (phaseControl.getUnit() == DiscretePhaseControl.Unit.A) { throw new PowsyblException("Phase control in A is not yet supported"); } - equationSystem.createEquation(branch.getNum(), EquationType.BRANCH_P).addTerm(p); } } @@ -375,7 +374,7 @@ public static EquationSystem create(LfNetwork network, VariableSet variableSet, network.addListener(new LfNetworkListener() { @Override - public void onVoltageControlChange(LfBus bus, boolean oldVoltageControl, boolean newVoltageControl) { + public void onVoltageControlChange(LfBus bus, boolean newVoltageControl) { if (newVoltageControl) { // switch PQ/PV Equation qEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_Q); qEq.setActive(false); diff --git a/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java b/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java index c748ab1ddd..df70442187 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java @@ -11,7 +11,7 @@ */ public interface LfNetworkListener { - void onVoltageControlChange(LfBus bus, boolean oldVoltageControl, boolean newVoltageControl); + void onVoltageControlChange(LfBus bus, boolean newVoltageControl); void onPhaseControlModeChange(DiscretePhaseControl phaseControl, DiscretePhaseControl.Mode oldMode, DiscretePhaseControl.Mode newMode); diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java index 70540294ef..d93cf556c6 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java @@ -125,7 +125,7 @@ public void setVoltageControl(boolean voltageControl) { } this.voltageControl = voltageControl; for (LfNetworkListener listener : network.getListeners()) { - listener.onVoltageControlChange(this, !voltageControl, voltageControl); + listener.onVoltageControlChange(this, voltageControl); } } } From eaff81ee3c51b4e1dd47f3070937ca230bea315a Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Sun, 28 Feb 2021 15:20:11 +0100 Subject: [PATCH 13/13] Add AcEquationSystemUpdater Signed-off-by: Geoffroy Jamgotchian --- .../ac/equations/AcEquationSystem.java | 82 +------------ .../ac/equations/AcEquationSystemUpdater.java | 109 ++++++++++++++++++ 2 files changed, 110 insertions(+), 81 deletions(-) create mode 100644 src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystemUpdater.java diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java index a88bdd58cd..a47279ee0b 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystem.java @@ -338,22 +338,6 @@ private static void createBranchEquations(LfNetwork network, VariableSet variabl } } - public static void updateControlledBus(LfBus controlledBus, EquationSystem equationSystem, VariableSet variableSet) { - // clean reactive power distribution equations - controlledBus.getControllerBuses().forEach(b -> equationSystem.removeEquation(b.getNum(), EquationType.ZERO_Q)); - - // controlled bus has a voltage equation only if one of the controller bus has voltage control on - List controllerBusesWithVoltageControlOn = controlledBus.getControllerBuses().stream() - .filter(LfBus::hasVoltageControl) - .collect(Collectors.toList()); - equationSystem.createEquation(controlledBus.getNum(), EquationType.BUS_V).setActive(!controllerBusesWithVoltageControlOn.isEmpty()); - - // create reactive power equations on controller buses that have voltage control on - if (!controllerBusesWithVoltageControlOn.isEmpty()) { - AcEquationSystem.createReactivePowerDistributionEquations(equationSystem, variableSet, controllerBusesWithVoltageControlOn); - } - } - public static EquationSystem create(LfNetwork network) { return create(network, new VariableSet()); } @@ -372,71 +356,7 @@ public static EquationSystem create(LfNetwork network, VariableSet variableSet, createBusEquations(network, variableSet, creationParameters, equationSystem); createBranchEquations(network, variableSet, creationParameters, equationSystem); - network.addListener(new LfNetworkListener() { - @Override - public void onVoltageControlChange(LfBus bus, boolean newVoltageControl) { - if (newVoltageControl) { // switch PQ/PV - Equation qEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_Q); - qEq.setActive(false); - - LfBus controlledBus = bus.getControlledBus().orElse(null); - if (controlledBus != null) { - updateControlledBus(controlledBus, equationSystem, variableSet); - } else { - Equation vEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V); - vEq.setActive(true); - } - } else { // switch PV/PQ - Equation qEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_Q); - qEq.setActive(true); - - LfBus controlledBus = bus.getControlledBus().orElse(null); - if (controlledBus != null) { - updateControlledBus(controlledBus, equationSystem, variableSet); - } else { - Equation vEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V); - vEq.setActive(false); - } - } - } - - @Override - public void onPhaseControlModeChange(DiscretePhaseControl phaseControl, DiscretePhaseControl.Mode oldMode, DiscretePhaseControl.Mode newMode) { - if (newMode == DiscretePhaseControl.Mode.OFF) { - // de-activate a1 variable - Variable a1 = variableSet.getVariable(phaseControl.getController().getNum(), VariableType.BRANCH_ALPHA1); - a1.setActive(false); - - // de-activate phase control equation - Equation t = equationSystem.createEquation(phaseControl.getControlled().getNum(), EquationType.BRANCH_P); - t.setActive(false); - } else { - throw new UnsupportedOperationException("TODO"); - } - } - - @Override - public void onVoltageControlModeChange(DiscreteVoltageControl voltageControl, DiscreteVoltageControl.Mode oldMode, DiscreteVoltageControl.Mode newMode) { - if (newMode == DiscreteVoltageControl.Mode.OFF) { - LfBus bus = voltageControl.getControlled(); - - // de-activate transformer voltage control equation - Equation t = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V); - t.setActive(false); - - for (LfBranch controllerBranch : bus.getDiscreteVoltageControl().getControllers()) { - // de-activate r1 variable - Variable r1 = variableSet.getVariable(controllerBranch.getNum(), VariableType.BRANCH_RHO1); - r1.setActive(false); - - // clean transformer distribution equations - equationSystem.removeEquation(controllerBranch.getNum(), EquationType.ZERO_RHO1); - } - } else { - throw new UnsupportedOperationException("TODO"); - } - } - }); + network.addListener(new AcEquationSystemUpdater(equationSystem, variableSet)); return equationSystem; } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystemUpdater.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystemUpdater.java new file mode 100644 index 0000000000..137bea6aaf --- /dev/null +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystemUpdater.java @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2021, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.openloadflow.ac.equations; + +import com.powsybl.openloadflow.equations.*; +import com.powsybl.openloadflow.network.*; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * @author Geoffroy Jamgotchian + */ +public class AcEquationSystemUpdater implements LfNetworkListener { + + private final EquationSystem equationSystem; + + private final VariableSet variableSet; + + public AcEquationSystemUpdater(EquationSystem equationSystem, VariableSet variableSet) { + this.equationSystem = Objects.requireNonNull(equationSystem); + this.variableSet = Objects.requireNonNull(variableSet); + } + + private static void updateControlledBus(LfBus controlledBus, EquationSystem equationSystem, VariableSet variableSet) { + // clean reactive power distribution equations + controlledBus.getControllerBuses().forEach(b -> equationSystem.removeEquation(b.getNum(), EquationType.ZERO_Q)); + + // controlled bus has a voltage equation only if one of the controller bus has voltage control on + List controllerBusesWithVoltageControlOn = controlledBus.getControllerBuses().stream() + .filter(LfBus::hasVoltageControl) + .collect(Collectors.toList()); + equationSystem.createEquation(controlledBus.getNum(), EquationType.BUS_V).setActive(!controllerBusesWithVoltageControlOn.isEmpty()); + + // create reactive power equations on controller buses that have voltage control on + if (!controllerBusesWithVoltageControlOn.isEmpty()) { + AcEquationSystem.createReactivePowerDistributionEquations(equationSystem, variableSet, controllerBusesWithVoltageControlOn); + } + } + + @Override + public void onVoltageControlChange(LfBus bus, boolean newVoltageControl) { + if (newVoltageControl) { // switch PQ/PV + Equation qEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_Q); + qEq.setActive(false); + + LfBus controlledBus = bus.getControlledBus().orElse(null); + if (controlledBus != null) { + updateControlledBus(controlledBus, equationSystem, variableSet); + } else { + Equation vEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V); + vEq.setActive(true); + } + } else { // switch PV/PQ + Equation qEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_Q); + qEq.setActive(true); + + LfBus controlledBus = bus.getControlledBus().orElse(null); + if (controlledBus != null) { + updateControlledBus(controlledBus, equationSystem, variableSet); + } else { + Equation vEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V); + vEq.setActive(false); + } + } + } + + @Override + public void onPhaseControlModeChange(DiscretePhaseControl phaseControl, DiscretePhaseControl.Mode oldMode, DiscretePhaseControl.Mode newMode) { + if (newMode == DiscretePhaseControl.Mode.OFF) { + // de-activate a1 variable + Variable a1 = variableSet.getVariable(phaseControl.getController().getNum(), VariableType.BRANCH_ALPHA1); + a1.setActive(false); + + // de-activate phase control equation + Equation t = equationSystem.createEquation(phaseControl.getControlled().getNum(), EquationType.BRANCH_P); + t.setActive(false); + } else { + throw new UnsupportedOperationException("TODO"); + } + } + + @Override + public void onVoltageControlModeChange(DiscreteVoltageControl voltageControl, DiscreteVoltageControl.Mode oldMode, DiscreteVoltageControl.Mode newMode) { + if (newMode == DiscreteVoltageControl.Mode.OFF) { + LfBus bus = voltageControl.getControlled(); + + // de-activate transformer voltage control equation + Equation t = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V); + t.setActive(false); + + for (LfBranch controllerBranch : bus.getDiscreteVoltageControl().getControllers()) { + // de-activate r1 variable + Variable r1 = variableSet.getVariable(controllerBranch.getNum(), VariableType.BRANCH_RHO1); + r1.setActive(false); + + // clean transformer distribution equations + equationSystem.removeEquation(controllerBranch.getNum(), EquationType.ZERO_RHO1); + } + } else { + throw new UnsupportedOperationException("TODO"); + } + } +}