From 7b3b61cc8ab974c065b41c0977eacc05da16c6b5 Mon Sep 17 00:00:00 2001 From: Hadrien Date: Mon, 27 May 2024 15:53:33 +0200 Subject: [PATCH 01/21] AcEmulationControl Signed-off-by: Hadrien --- .../powsybl/openloadflow/network/impl/LfHvdcImpl.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java index ffbe307e63..49fad8d5ed 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java @@ -8,6 +8,7 @@ package com.powsybl.openloadflow.network.impl; import com.powsybl.iidm.network.HvdcLine; +import com.powsybl.iidm.network.TwoSides; import com.powsybl.iidm.network.extensions.HvdcAngleDroopActivePowerControl; import com.powsybl.iidm.network.extensions.HvdcOperatorActivePowerRange; import com.powsybl.openloadflow.network.*; @@ -47,6 +48,15 @@ public class LfHvdcImpl extends AbstractElement implements LfHvdc { private final double pMaxFromCS2toCS1; + public class AcEmulationControl { + private final double droop; + private final double p0; + private final double pMaxFromCS1toCS2; + private final double pMaxFromCS2toCS1; + private boolean activated = true; + private TwoSides feedingSide; + }; + public LfHvdcImpl(String id, LfBus bus1, LfBus bus2, LfNetwork network, HvdcLine hvdcLine, boolean acEmulation) { super(network); this.id = Objects.requireNonNull(id); From 14ea87e1ac518ea35ceba6da1c136c192cd7b5a9 Mon Sep 17 00:00:00 2001 From: Hadrien Date: Mon, 27 May 2024 18:54:16 +0200 Subject: [PATCH 02/21] Continuing AcEmulationControl Signed-off-by: Hadrien --- .../powsybl/openloadflow/network/LfHvdc.java | 8 -- .../openloadflow/network/impl/LfHvdcImpl.java | 84 ++++++++++--------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java b/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java index 4b07bafd52..9eeef7aa0e 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java @@ -28,10 +28,6 @@ public interface LfHvdc extends LfElement { Evaluable getP2(); - double getDroop(); - - double getP0(); - boolean isAcEmulation(); void setAcEmulation(boolean acEmulation); @@ -45,8 +41,4 @@ public interface LfHvdc extends LfElement { void setConverterStation2(LfVscConverterStation converterStation2); void updateState(); - - double getPMaxFromCS1toCS2(); - - double getPMaxFromCS2toCS1(); } diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java index 49fad8d5ed..538bca476c 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java @@ -34,20 +34,12 @@ public class LfHvdcImpl extends AbstractElement implements LfHvdc { private Evaluable p2 = NAN; - private double droop = Double.NaN; - - private double p0 = Double.NaN; - private LfVscConverterStation converterStation1; private LfVscConverterStation converterStation2; private boolean acEmulation; - private final double pMaxFromCS1toCS2; - - private final double pMaxFromCS2toCS1; - public class AcEmulationControl { private final double droop; private final double p0; @@ -55,26 +47,62 @@ public class AcEmulationControl { private final double pMaxFromCS2toCS1; private boolean activated = true; private TwoSides feedingSide; + + public AcEmulationControl(double droop, double p0, double pMaxFromCS1toCS2, double pMaxFromCS2toCS1) { + this.droop = droop; + this.p0 = p0; + this.pMaxFromCS1toCS2 = pMaxFromCS1toCS2; + this.pMaxFromCS2toCS1 = pMaxFromCS2toCS1; + this.feedingSide = (p0 >= 0) ? TwoSides.ONE : TwoSides.TWO; + } + + double getDroop() { + return droop / PerUnit.SB; + } + + double getP0() { + return p0 / PerUnit.SB; + } + + double getPMaxFromCS1toCS2() { + return pMaxFromCS1toCS2 / PerUnit.SB; + } + + double getPMaxFromCS2toCS1() { + return pMaxFromCS2toCS1 / PerUnit.SB; + } + + boolean isActivated() { + return activated; + } + + TwoSides getFeedingSide() { + return feedingSide; + } + + void setActivated(boolean activated) { + this.activated = activated; + } + + void setFeedingSide(TwoSides side) { + feedingSide = side; + } }; + AcEmulationControl acEmulationControl; + public LfHvdcImpl(String id, LfBus bus1, LfBus bus2, LfNetwork network, HvdcLine hvdcLine, boolean acEmulation) { super(network); this.id = Objects.requireNonNull(id); this.bus1 = bus1; this.bus2 = bus2; HvdcAngleDroopActivePowerControl droopControl = hvdcLine.getExtension(HvdcAngleDroopActivePowerControl.class); + HvdcOperatorActivePowerRange powerRange = hvdcLine.getExtension(HvdcOperatorActivePowerRange.class); + double pMaxFromCS1toCS2 = (powerRange != null) ? powerRange.getOprFromCS1toCS2() : hvdcLine.getMaxP(); + double pMaxFromCS2toCS1 = (powerRange != null) ? powerRange.getOprFromCS2toCS1() : hvdcLine.getMaxP(); this.acEmulation = acEmulation && droopControl != null && droopControl.isEnabled(); if (this.acEmulation) { - droop = droopControl.getDroop(); - p0 = droopControl.getP0(); - } - HvdcOperatorActivePowerRange powerRange = hvdcLine.getExtension(HvdcOperatorActivePowerRange.class); - if (powerRange != null) { - pMaxFromCS1toCS2 = powerRange.getOprFromCS1toCS2(); - pMaxFromCS2toCS1 = powerRange.getOprFromCS2toCS1(); - } else { - pMaxFromCS2toCS1 = hvdcLine.getMaxP(); - pMaxFromCS1toCS2 = hvdcLine.getMaxP(); + acEmulationControl = new AcEmulationControl(droopControl.getDroop(), droopControl.getP0(), pMaxFromCS1toCS2, pMaxFromCS2toCS1); } } @@ -133,16 +161,6 @@ public Evaluable getP2() { return this.p2; } - @Override - public double getDroop() { - return droop / PerUnit.SB; - } - - @Override - public double getP0() { - return p0 / PerUnit.SB; - } - @Override public boolean isAcEmulation() { return acEmulation; @@ -182,14 +200,4 @@ public void updateState() { ((LfVscConverterStationImpl) converterStation2).getStation().getTerminal().setP(p2.eval() * PerUnit.SB); } } - - @Override - public double getPMaxFromCS1toCS2() { - return Double.isNaN(pMaxFromCS1toCS2) ? Double.MAX_VALUE : pMaxFromCS1toCS2 / PerUnit.SB; - } - - @Override - public double getPMaxFromCS2toCS1() { - return Double.isNaN(pMaxFromCS1toCS2) ? Double.MAX_VALUE : pMaxFromCS2toCS1 / PerUnit.SB; - } } From 5bee2ba80ad1b2a2f899f579a84b1daf28e92b3a Mon Sep 17 00:00:00 2001 From: Hadrien Date: Mon, 3 Jun 2024 11:31:56 +0200 Subject: [PATCH 03/21] AcEmulationControl end Signed-off-by: Hadrien --- ...stractHvdcAcEmulationFlowEquationTerm.java | 8 +-- ...ractHvdcAcEmulationDcFlowEquationTerm.java | 2 +- ...vdcAcEmulationSide1DCFlowEquationTerm.java | 4 +- ...vdcAcEmulationSide2DCFlowEquationTerm.java | 4 +- .../powsybl/openloadflow/network/LfHvdc.java | 53 ++++++++++++++++++ .../openloadflow/network/impl/LfHvdcImpl.java | 55 ++----------------- .../powsybl/openloadflow/EquationsTest.java | 7 +-- 7 files changed, 70 insertions(+), 63 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractHvdcAcEmulationFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractHvdcAcEmulationFlowEquationTerm.java index 466e293869..ff1e99ca86 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractHvdcAcEmulationFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractHvdcAcEmulationFlowEquationTerm.java @@ -43,12 +43,12 @@ protected AbstractHvdcAcEmulationFlowEquationTerm(LfHvdc hvdc, LfBus bus1, LfBus ph1Var = variableSet.getVariable(bus1.getNum(), AcVariableType.BUS_PHI); ph2Var = variableSet.getVariable(bus2.getNum(), AcVariableType.BUS_PHI); variables = List.of(ph1Var, ph2Var); - k = hvdc.getDroop() * 180 / Math.PI; - p0 = hvdc.getP0(); + k = hvdc.getAcEmulationControl().getDroop() * 180 / Math.PI; + p0 = hvdc.getAcEmulationControl().getP0(); lossFactor1 = hvdc.getConverterStation1().getLossFactor() / 100; lossFactor2 = hvdc.getConverterStation2().getLossFactor() / 100; - pMaxFromCS1toCS2 = hvdc.getPMaxFromCS1toCS2(); - pMaxFromCS2toCS1 = hvdc.getPMaxFromCS2toCS1(); + pMaxFromCS1toCS2 = hvdc.getAcEmulationControl().getPMaxFromCS1toCS2(); + pMaxFromCS2toCS1 = hvdc.getAcEmulationControl().getPMaxFromCS2toCS1(); } protected double rawP(double p0, double k, double ph1, double ph2) { diff --git a/src/main/java/com/powsybl/openloadflow/dc/equations/AbstractHvdcAcEmulationDcFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/dc/equations/AbstractHvdcAcEmulationDcFlowEquationTerm.java index 6626c16c5c..a11a1b4e00 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/equations/AbstractHvdcAcEmulationDcFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/dc/equations/AbstractHvdcAcEmulationDcFlowEquationTerm.java @@ -33,7 +33,7 @@ protected AbstractHvdcAcEmulationDcFlowEquationTerm(LfHvdc hvdc, LfBus bus1, LfB ph2Var = variableSet.getVariable(bus2.getNum(), DcVariableType.BUS_PHI); variables = List.of(ph1Var, ph2Var); this.hvdc = hvdc; - k = this.hvdc.getDroop() * 180 / Math.PI; + k = this.hvdc.getAcEmulationControl().getDroop() * 180 / Math.PI; } @Override diff --git a/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide1DCFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide1DCFlowEquationTerm.java index ef20ed1742..8f8dc175bb 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide1DCFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide1DCFlowEquationTerm.java @@ -28,7 +28,7 @@ protected String getName() { @Override public double eval() { - return k * (ph1() - ph2()) + hvdc.getP0(); + return k * (ph1() - ph2()) + hvdc.getAcEmulationControl().getP0(); } @Override @@ -49,6 +49,6 @@ public boolean hasRhs() { @Override public double rhs() { - return hvdc.getP0(); + return hvdc.getAcEmulationControl().getP0(); } } diff --git a/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide2DCFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide2DCFlowEquationTerm.java index dec88b3517..600be02bd8 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide2DCFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide2DCFlowEquationTerm.java @@ -28,7 +28,7 @@ protected String getName() { @Override public double eval() { - return k * (ph2() - ph1()) - hvdc.getP0(); + return k * (ph2() - ph1()) - hvdc.getAcEmulationControl().getP0(); } @Override @@ -49,6 +49,6 @@ public boolean hasRhs() { @Override public double rhs() { - return -hvdc.getP0(); + return -hvdc.getAcEmulationControl().getP0(); } } diff --git a/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java b/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java index 9eeef7aa0e..bf03a73839 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java @@ -7,13 +7,64 @@ */ package com.powsybl.openloadflow.network; +import com.powsybl.iidm.network.TwoSides; import com.powsybl.openloadflow.util.Evaluable; +import com.powsybl.openloadflow.util.PerUnit; /** * @author Anne Tilloy {@literal } */ public interface LfHvdc extends LfElement { + class AcEmulationControl { + private final double droop; + private final double p0; + private final double pMaxFromCS1toCS2; + private final double pMaxFromCS2toCS1; + private boolean activated = true; + private TwoSides feedingSide; + + public AcEmulationControl(double droop, double p0, double pMaxFromCS1toCS2, double pMaxFromCS2toCS1) { + this.droop = droop; + this.p0 = p0; + this.pMaxFromCS1toCS2 = pMaxFromCS1toCS2; + this.pMaxFromCS2toCS1 = pMaxFromCS2toCS1; + this.feedingSide = (p0 >= 0) ? TwoSides.ONE : TwoSides.TWO; + } + + public double getDroop() { + return droop / PerUnit.SB; + } + + public double getP0() { + return p0 / PerUnit.SB; + } + + public double getPMaxFromCS1toCS2() { + return pMaxFromCS1toCS2 / PerUnit.SB; + } + + public double getPMaxFromCS2toCS1() { + return pMaxFromCS2toCS1 / PerUnit.SB; + } + + public boolean isActivated() { + return activated; + } + + public TwoSides getFeedingSide() { + return feedingSide; + } + + void setActivated(boolean activated) { + this.activated = activated; + } + + void setFeedingSide(TwoSides side) { + feedingSide = side; + } + } + LfBus getBus1(); LfBus getBus2(); @@ -40,5 +91,7 @@ public interface LfHvdc extends LfElement { void setConverterStation2(LfVscConverterStation converterStation2); + AcEmulationControl getAcEmulationControl(); + void updateState(); } diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java index 538bca476c..1f717cdfb9 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java @@ -8,7 +8,6 @@ package com.powsybl.openloadflow.network.impl; import com.powsybl.iidm.network.HvdcLine; -import com.powsybl.iidm.network.TwoSides; import com.powsybl.iidm.network.extensions.HvdcAngleDroopActivePowerControl; import com.powsybl.iidm.network.extensions.HvdcOperatorActivePowerRange; import com.powsybl.openloadflow.network.*; @@ -40,55 +39,6 @@ public class LfHvdcImpl extends AbstractElement implements LfHvdc { private boolean acEmulation; - public class AcEmulationControl { - private final double droop; - private final double p0; - private final double pMaxFromCS1toCS2; - private final double pMaxFromCS2toCS1; - private boolean activated = true; - private TwoSides feedingSide; - - public AcEmulationControl(double droop, double p0, double pMaxFromCS1toCS2, double pMaxFromCS2toCS1) { - this.droop = droop; - this.p0 = p0; - this.pMaxFromCS1toCS2 = pMaxFromCS1toCS2; - this.pMaxFromCS2toCS1 = pMaxFromCS2toCS1; - this.feedingSide = (p0 >= 0) ? TwoSides.ONE : TwoSides.TWO; - } - - double getDroop() { - return droop / PerUnit.SB; - } - - double getP0() { - return p0 / PerUnit.SB; - } - - double getPMaxFromCS1toCS2() { - return pMaxFromCS1toCS2 / PerUnit.SB; - } - - double getPMaxFromCS2toCS1() { - return pMaxFromCS2toCS1 / PerUnit.SB; - } - - boolean isActivated() { - return activated; - } - - TwoSides getFeedingSide() { - return feedingSide; - } - - void setActivated(boolean activated) { - this.activated = activated; - } - - void setFeedingSide(TwoSides side) { - feedingSide = side; - } - }; - AcEmulationControl acEmulationControl; public LfHvdcImpl(String id, LfBus bus1, LfBus bus2, LfNetwork network, HvdcLine hvdcLine, boolean acEmulation) { @@ -193,6 +143,11 @@ public void setConverterStation2(LfVscConverterStation converterStation2) { converterStation2.setHvdc(this); } + @Override + public AcEmulationControl getAcEmulationControl() { + return acEmulationControl; + } + @Override public void updateState() { if (acEmulation) { diff --git a/src/test/java/com/powsybl/openloadflow/EquationsTest.java b/src/test/java/com/powsybl/openloadflow/EquationsTest.java index c0b9d10bec..e39c0808c6 100644 --- a/src/test/java/com/powsybl/openloadflow/EquationsTest.java +++ b/src/test/java/com/powsybl/openloadflow/EquationsTest.java @@ -17,6 +17,7 @@ import com.powsybl.openloadflow.equations.*; import com.powsybl.openloadflow.network.*; import com.powsybl.openloadflow.network.impl.LfVscConverterStationImpl; +import com.powsybl.openloadflow.util.PerUnit; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -63,6 +64,7 @@ public Object answer(InvocationOnMock invocation) { private static final double LOSS_FACTOR_1 = 0.01100000023841858; private static final double LOSS_FACTOR_2 = 0.02400453453002384; private static final double G_SHUNT = 0.0000372472384299244; + private static final LfHvdc.AcEmulationControl AC_EMULATION_CONTROL = new LfHvdc.AcEmulationControl(DROOP * PerUnit.SB, P_0 * PerUnit.SB, Double.MAX_VALUE, Double.MAX_VALUE); private static & Quantity, E extends Enum & Quantity> double[] eval(EquationTerm term, List> variables, StateVector sv) { term.setStateVector(sv); @@ -255,10 +257,7 @@ void hvdcTest() { var hvdc = Mockito.mock(LfHvdc.class, new RuntimeExceptionAnswer()); Mockito.doReturn(0).when(hvdc).getNum(); Mockito.doReturn(false).when(hvdc).isDisabled(); - Mockito.doReturn(DROOP).when(hvdc).getDroop(); - Mockito.doReturn(P_0).when(hvdc).getP0(); - Mockito.doReturn(Double.MAX_VALUE).when(hvdc).getPMaxFromCS1toCS2(); - Mockito.doReturn(Double.MAX_VALUE).when(hvdc).getPMaxFromCS2toCS1(); + Mockito.doReturn(AC_EMULATION_CONTROL).when(hvdc).getAcEmulationControl(); LfVscConverterStationImpl station1 = Mockito.mock(LfVscConverterStationImpl.class, new RuntimeExceptionAnswer()); LfVscConverterStationImpl station2 = Mockito.mock(LfVscConverterStationImpl.class, new RuntimeExceptionAnswer()); Mockito.doReturn(station1).when(hvdc).getConverterStation1(); From 2384e46ab39776c9fbc7b6f053388e29d251b5d6 Mon Sep 17 00:00:00 2001 From: Hadrien Date: Mon, 3 Jun 2024 16:03:31 +0200 Subject: [PATCH 04/21] AcEmulationOuterLoop Signed-off-by: Hadrien --- ...stractHvdcAcEmulationFlowEquationTerm.java | 11 ------- ...cEmulationSide1ActiveFlowEquationTerm.java | 3 +- ...cEmulationSide2ActiveFlowEquationTerm.java | 3 +- .../ac/outerloop/AcEmulationOuterLoop.java | 33 +++++++++++++++++++ 4 files changed, 35 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractHvdcAcEmulationFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractHvdcAcEmulationFlowEquationTerm.java index ff1e99ca86..c680ffaad1 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractHvdcAcEmulationFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractHvdcAcEmulationFlowEquationTerm.java @@ -55,17 +55,6 @@ protected double rawP(double p0, double k, double ph1, double ph2) { return p0 + k * (ph1 - ph2); } - protected double boundedP(double rawP) { - // If there is a maximal active power - // it is applied at the entry of the controller VSC station - // on the AC side of the network. - if (rawP >= 0) { - return Math.min(rawP, pMaxFromCS1toCS2); - } else { - return Math.max(rawP, -pMaxFromCS2toCS1); - } - } - protected double ph1() { return sv.get(ph1Var.getRow()); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide1ActiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide1ActiveFlowEquationTerm.java index 0b58fc63e0..714cd93178 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide1ActiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide1ActiveFlowEquationTerm.java @@ -25,8 +25,7 @@ public HvdcAcEmulationSide1ActiveFlowEquationTerm(LfHvdc hvdc, LfBus bus1, LfBus private double p1(double ph1, double ph2) { double rawP = rawP(p0, k, ph1, ph2); - double boundedP = boundedP(rawP); - return (isController(rawP) ? 1 : getVscLossMultiplier()) * boundedP; + return (isController(rawP) ? 1 : getVscLossMultiplier()) * rawP; } private static boolean isController(double rawP) { diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java index 501f7eca1d..7f6e61e7a5 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java @@ -25,8 +25,7 @@ public HvdcAcEmulationSide2ActiveFlowEquationTerm(LfHvdc hvdc, LfBus bus1, LfBus private double p2(double ph1, double ph2) { double rawP = rawP(p0, k, ph1, ph2); - double boundedP = boundedP(rawP); - return -(isController(rawP) ? 1 : getVscLossMultiplier()) * boundedP; + return -(isController(rawP) ? 1 : getVscLossMultiplier()) * rawP; } private boolean isController(double rawP) { diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java new file mode 100644 index 0000000000..1b497c9e9a --- /dev/null +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2023, Coreso SA (https://www.coreso.eu/) and TSCNET Services GmbH (https://www.tscnet.eu/) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.openloadflow.ac.outerloop; + +import com.powsybl.commons.report.ReportNode; +import com.powsybl.openloadflow.ac.AcOuterLoopContext; +import com.powsybl.openloadflow.lf.outerloop.OuterLoopResult; + +/** + * @author Hadrien Godard {@literal } + */ +public class AcEmulationOuterLoop implements AcOuterLoop { + + public static final String NAME = "AcEmulation"; + + private static final int maxModeSwitch = 2; + private static final int maxFeedingSideSwitch = 2; + + @Override + public String getName() { + return NAME; + } + + @Override + public OuterLoopResult check(AcOuterLoopContext context, ReportNode reportNode) { + return null; + } +} From 4cf7a2030bbe20f7cd1aabecffc385b2866c32e0 Mon Sep 17 00:00:00 2001 From: Hadrien Date: Fri, 7 Jun 2024 09:53:56 +0200 Subject: [PATCH 05/21] HvdcAcEmulationSide1ActiveFlowEquationTerm Signed-off-by: Hadrien --- ...cEmulationSide1ActiveFlowEquationTerm.java | 38 ++++++++++--------- .../powsybl/openloadflow/network/LfHvdc.java | 16 +++++--- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide1ActiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide1ActiveFlowEquationTerm.java index 714cd93178..fbe75cfd74 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide1ActiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide1ActiveFlowEquationTerm.java @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.iidm.network.TwoSides; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBus; @@ -23,30 +24,31 @@ public HvdcAcEmulationSide1ActiveFlowEquationTerm(LfHvdc hvdc, LfBus bus1, LfBus super(hvdc, bus1, bus2, variableSet); } - private double p1(double ph1, double ph2) { - double rawP = rawP(p0, k, ph1, ph2); - return (isController(rawP) ? 1 : getVscLossMultiplier()) * rawP; - } - - private static boolean isController(double rawP) { - return rawP >= 0; + private double getSide1LossMultiplier() { + return element.getAcEmulationControl().getFeedingSide() == TwoSides.ONE ? 1 : getVscLossMultiplier(); } - private boolean isInOperatingRange(double rawP) { - return rawP < pMaxFromCS1toCS2 && rawP > -pMaxFromCS2toCS1; + private double p1(double ph1, double ph2) { + double boundedP = switch (element.getAcEmulationControl().getAcEmulationStatus()) { + case FREE -> rawP(p0, k, ph1, ph2); + case BOUNDED_SIDE_ONE -> pMaxFromCS1toCS2; + case BOUNDED_SIDE_TWO -> -pMaxFromCS2toCS1; + default -> 0; + }; + return getSide1LossMultiplier() * boundedP; } - protected double dp1dph1(double ph1, double ph2) { - double rawP = rawP(p0, k, ph1, ph2); - if (isInOperatingRange(rawP)) { - return (isController(rawP) ? 1 : getVscLossMultiplier()) * k; - } else { + protected double dp1dph1() { + if (element.getAcEmulationControl().getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.FREE) { + return getSide1LossMultiplier() * k; + } + else { return 0; } } - protected double dp1dph2(double ph1, double ph2) { - return -dp1dph1(ph1, ph2); + protected double dp1dph2() { + return -dp1dph1(); } @Override @@ -58,9 +60,9 @@ public double eval() { public double der(Variable variable) { Objects.requireNonNull(variable); if (variable.equals(ph1Var)) { - return dp1dph1(ph1(), ph2()); + return dp1dph1(); } else if (variable.equals(ph2Var)) { - return dp1dph2(ph1(), ph2()); + return dp1dph2(); } else { throw new IllegalStateException("Unknown variable: " + variable); } diff --git a/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java b/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java index bf03a73839..dc14e872ff 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java @@ -17,11 +17,17 @@ public interface LfHvdc extends LfElement { class AcEmulationControl { + public enum AcEmulationStatus { + FREE, + BOUNDED_SIDE_ONE, + BOUNDED_SIDE_TWO, + NULL; + } private final double droop; private final double p0; private final double pMaxFromCS1toCS2; private final double pMaxFromCS2toCS1; - private boolean activated = true; + private AcEmulationStatus acEmulationStatus = AcEmulationStatus.FREE; private TwoSides feedingSide; public AcEmulationControl(double droop, double p0, double pMaxFromCS1toCS2, double pMaxFromCS2toCS1) { @@ -48,16 +54,16 @@ public double getPMaxFromCS2toCS1() { return pMaxFromCS2toCS1 / PerUnit.SB; } - public boolean isActivated() { - return activated; + public AcEmulationStatus getAcEmulationStatus() { + return acEmulationStatus; } public TwoSides getFeedingSide() { return feedingSide; } - void setActivated(boolean activated) { - this.activated = activated; + void setAcEmulationStatus(AcEmulationStatus status) { + acEmulationStatus = status; } void setFeedingSide(TwoSides side) { From 52edfd998d9624bd08e46fd7fc5b286daa9d0520 Mon Sep 17 00:00:00 2001 From: Hadrien Date: Fri, 7 Jun 2024 14:24:44 +0200 Subject: [PATCH 06/21] Continuing outerloop Signed-off-by: Hadrien --- .../AbstractAcOuterLoopConfig.java | 7 ++ .../DefaultAcOuterLoopConfig.java | 2 + .../ExplicitAcOuterLoopConfig.java | 4 +- ...cEmulationSide2ActiveFlowEquationTerm.java | 38 ++++---- .../ac/outerloop/AcEmulationOuterLoop.java | 91 +++++++++++++++++++ .../powsybl/openloadflow/network/LfHvdc.java | 4 +- 6 files changed, 125 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java b/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java index a5fd28de62..ab4d419a45 100644 --- a/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java +++ b/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java @@ -112,6 +112,13 @@ protected static Optional createPhaseControlOuterLoop(LoadFlowParam return createPhaseControlOuterLoop(parameters, parametersExt.getPhaseShifterControlMode()); } + protected static Optional createAcEmulationOuterLoop(LoadFlowParameters parameters) { + if (parameters.isHvdcAcEmulation()) { + return Optional.of(new AcEmulationOuterLoop()); + } + return Optional.empty(); + } + protected static Optional createAutomationSystemOuterLoop(OpenLoadFlowParameters parametersExt) { if (parametersExt.isSimulateAutomationSystems()) { return Optional.of(new AutomationSystemOuterLoop()); diff --git a/src/main/java/com/powsybl/openloadflow/DefaultAcOuterLoopConfig.java b/src/main/java/com/powsybl/openloadflow/DefaultAcOuterLoopConfig.java index d100fe82ec..1ee731f5f1 100644 --- a/src/main/java/com/powsybl/openloadflow/DefaultAcOuterLoopConfig.java +++ b/src/main/java/com/powsybl/openloadflow/DefaultAcOuterLoopConfig.java @@ -36,6 +36,8 @@ public List configure(LoadFlowParameters parameters, OpenLoadFlowPa createTransformerReactivePowerControlOuterLoop(parametersExt).ifPresent(outerLoops::add); // shunt compensator voltage control createShuntVoltageControlOuterLoop(parameters, parametersExt).ifPresent(outerLoops::add); + // AC emulation + createAcEmulationOuterLoop(parameters).ifPresent(outerLoops::add); // automation system createAutomationSystemOuterLoop(parametersExt).ifPresent(outerLoops::add); return outerLoops; diff --git a/src/main/java/com/powsybl/openloadflow/ExplicitAcOuterLoopConfig.java b/src/main/java/com/powsybl/openloadflow/ExplicitAcOuterLoopConfig.java index a770c2c2c6..4e8b53e053 100644 --- a/src/main/java/com/powsybl/openloadflow/ExplicitAcOuterLoopConfig.java +++ b/src/main/java/com/powsybl/openloadflow/ExplicitAcOuterLoopConfig.java @@ -35,7 +35,8 @@ public class ExplicitAcOuterLoopConfig extends AbstractAcOuterLoopConfig { SimpleTransformerVoltageControlOuterLoop.NAME, TransformerVoltageControlOuterLoop.NAME, AutomationSystemOuterLoop.NAME, - IncrementalTransformerReactivePowerControlOuterLoop.NAME); + IncrementalTransformerReactivePowerControlOuterLoop.NAME, + AcEmulationOuterLoop.NAME); private static Optional createOuterLoop(String name, LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt) { return switch (name) { @@ -65,6 +66,7 @@ private static Optional createOuterLoop(String name, LoadFlowParame parametersExt.getGeneratorVoltageControlMinNominalVoltage()); case AutomationSystemOuterLoop.NAME -> createAutomationSystemOuterLoop(parametersExt); case IncrementalTransformerReactivePowerControlOuterLoop.NAME -> createTransformerReactivePowerControlOuterLoop(parametersExt); + case AcEmulationOuterLoop.NAME -> createAcEmulationOuterLoop(parameters); default -> throw new PowsyblException("Unknown outer loop '" + name + "'"); }; } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java index 7f6e61e7a5..a2a147ed51 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.iidm.network.TwoSides; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBus; @@ -23,30 +24,31 @@ public HvdcAcEmulationSide2ActiveFlowEquationTerm(LfHvdc hvdc, LfBus bus1, LfBus super(hvdc, bus1, bus2, variableSet); } - private double p2(double ph1, double ph2) { - double rawP = rawP(p0, k, ph1, ph2); - return -(isController(rawP) ? 1 : getVscLossMultiplier()) * rawP; - } - - private boolean isController(double rawP) { - return rawP < 0; + private double getSide2LossMultiplier() { + return element.getAcEmulationControl().getFeedingSide() == TwoSides.TWO ? 1 : getVscLossMultiplier(); } - private boolean isInOperatingRange(double rawP) { - return rawP < pMaxFromCS2toCS1 && rawP > -pMaxFromCS1toCS2; + private double p2(double ph1, double ph2) { + double boundedP = switch (element.getAcEmulationControl().getAcEmulationStatus()) { + case FREE -> rawP(p0, k, ph2, ph1); + case BOUNDED_SIDE_ONE -> -pMaxFromCS1toCS2; + case BOUNDED_SIDE_TWO -> pMaxFromCS2toCS1; + default -> 0; + }; + return getSide2LossMultiplier() * boundedP; } - private double dp2dph1(double ph1, double ph2) { - double rawP = rawP(p0, k, ph1, ph2); - if (isInOperatingRange(rawP)) { - return -(isController(rawP) ? 1 : getVscLossMultiplier()) * k; - } else { + private double dp2dph1() { + if (element.getAcEmulationControl().getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.FREE) { + return getSide2LossMultiplier() * k; + } + else { return 0; } } - private double dp2dph2(double ph1, double ph2) { - return -dp2dph1(ph1, ph2); + private double dp2dph2() { + return -dp2dph1(); } @Override @@ -58,9 +60,9 @@ public double eval() { public double der(Variable variable) { Objects.requireNonNull(variable); if (variable.equals(ph1Var)) { - return dp2dph1(ph1(), ph2()); + return dp2dph1(); } else if (variable.equals(ph2Var)) { - return dp2dph2(ph1(), ph2()); + return dp2dph2(); } else { throw new IllegalStateException("Unknown variable: " + variable); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java index 1b497c9e9a..b659a7b121 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java @@ -8,26 +8,117 @@ package com.powsybl.openloadflow.ac.outerloop; import com.powsybl.commons.report.ReportNode; +import com.powsybl.iidm.network.TwoSides; import com.powsybl.openloadflow.ac.AcOuterLoopContext; import com.powsybl.openloadflow.lf.outerloop.OuterLoopResult; +import com.powsybl.openloadflow.lf.outerloop.OuterLoopStatus; +import com.powsybl.openloadflow.network.LfHvdc; +import org.apache.commons.lang3.mutable.MutableInt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; /** * @author Hadrien Godard {@literal } */ public class AcEmulationOuterLoop implements AcOuterLoop { + private static final Logger LOGGER = LoggerFactory.getLogger(AcEmulationOuterLoop.class); public static final String NAME = "AcEmulation"; private static final int maxModeSwitch = 2; private static final int maxFeedingSideSwitch = 2; + private static final class ContextData { + private final Map modeSwitchCount = new HashMap<>(); + private final Map feedingSideSwitchCount = new HashMap<>(); + + void incrementModeSwitchCount(String hvdcId) { + modeSwitchCount.computeIfAbsent(hvdcId, k -> new MutableInt(0)) + .increment(); + } + + void incrementFeedingSideSwitchCount(String hvdcId) { + feedingSideSwitchCount.computeIfAbsent(hvdcId, k -> new MutableInt(0)) + .increment(); + } + + int getModeSwitchCount(String hvdcId) { + MutableInt counter = modeSwitchCount.get(hvdcId); + if (counter == null) { + return 0; + } + return counter.getValue(); + } + + int getFeedingSideSwitchCount(String hvdcId) { + MutableInt counter = feedingSideSwitchCount.get(hvdcId); + if (counter == null) { + return 0; + } + return counter.getValue(); + } + } + + @Override + public void initialize(AcOuterLoopContext context) { + context.setData(new AcEmulationOuterLoop.ContextData()); + } + @Override public String getName() { return NAME; } + private void processHvdc(LfHvdc hvdc, ContextData contextData) { + String hvdcId = hvdc.getId(); + if(contextData.getFeedingSideSwitchCount(hvdcId) < maxFeedingSideSwitch && contextData.getModeSwitchCount(hvdcId) < maxModeSwitch) { + LfHvdc.AcEmulationControl acEmulationControl = hvdc.getAcEmulationControl(); + + // Check feeding side + if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { + if (hvdc.getP1().eval() < 0) { + // Switch feeding side + LOGGER.trace("Switching feeding side from One to Two for Hvdc: " + hvdcId); + contextData.incrementFeedingSideSwitchCount(hvdcId); + acEmulationControl.setFeedingSide(TwoSides.TWO); + if (contextData.getFeedingSideSwitchCount(hvdcId) == maxFeedingSideSwitch) { + LOGGER.debug("Two many feeding side switches (flow blocked to 0 MW) for Hvdc: " + hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.NULL); + } + } + } else { + if (hvdc.getP2().eval() < 0) { + // Switch feeding side + LOGGER.trace("Switching feeding side from Two to One for Hvdc: " + hvdcId); + contextData.incrementFeedingSideSwitchCount(hvdcId); + acEmulationControl.setFeedingSide(TwoSides.ONE); + if (contextData.getFeedingSideSwitchCount(hvdcId) == maxFeedingSideSwitch) { + LOGGER.debug("Two many feeding side switches (flow blocked to 0 MW) for Hvdc: " + hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.NULL); + } + } + + } + + // Check Pmax + // TODO HG + if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { + + } else { + + } + } + } + @Override public OuterLoopResult check(AcOuterLoopContext context, ReportNode reportNode) { + OuterLoopStatus status = OuterLoopStatus.STABLE; + ContextData contextData = (ContextData) context.getData(); + + context.getNetwork().getHvdcs().forEach(hvdc -> processHvdc(hvdc, contextData)); return null; } } diff --git a/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java b/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java index dc14e872ff..77fecd4732 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java @@ -62,11 +62,11 @@ public TwoSides getFeedingSide() { return feedingSide; } - void setAcEmulationStatus(AcEmulationStatus status) { + public void setAcEmulationStatus(AcEmulationStatus status) { acEmulationStatus = status; } - void setFeedingSide(TwoSides side) { + public void setFeedingSide(TwoSides side) { feedingSide = side; } } From 2aaba914bbce93bc334acb182d1a24a3241e63b8 Mon Sep 17 00:00:00 2001 From: Hadrien Date: Mon, 10 Jun 2024 17:51:39 +0200 Subject: [PATCH 07/21] End outerloop Signed-off-by: Hadrien --- ...cEmulationSide1ActiveFlowEquationTerm.java | 3 +- ...cEmulationSide2ActiveFlowEquationTerm.java | 3 +- .../ac/outerloop/AcEmulationOuterLoop.java | 112 +++++++++++++----- .../powsybl/openloadflow/network/LfHvdc.java | 3 +- 4 files changed, 87 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide1ActiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide1ActiveFlowEquationTerm.java index fbe75cfd74..8c3158abca 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide1ActiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide1ActiveFlowEquationTerm.java @@ -31,8 +31,7 @@ private double getSide1LossMultiplier() { private double p1(double ph1, double ph2) { double boundedP = switch (element.getAcEmulationControl().getAcEmulationStatus()) { case FREE -> rawP(p0, k, ph1, ph2); - case BOUNDED_SIDE_ONE -> pMaxFromCS1toCS2; - case BOUNDED_SIDE_TWO -> -pMaxFromCS2toCS1; + case BOUNDED -> element.getAcEmulationControl().getFeedingSide() == TwoSides.ONE ? pMaxFromCS1toCS2 : -pMaxFromCS2toCS1; default -> 0; }; return getSide1LossMultiplier() * boundedP; diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java index a2a147ed51..a3a9020d18 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java @@ -31,8 +31,7 @@ private double getSide2LossMultiplier() { private double p2(double ph1, double ph2) { double boundedP = switch (element.getAcEmulationControl().getAcEmulationStatus()) { case FREE -> rawP(p0, k, ph2, ph1); - case BOUNDED_SIDE_ONE -> -pMaxFromCS1toCS2; - case BOUNDED_SIDE_TWO -> pMaxFromCS2toCS1; + case BOUNDED -> element.getAcEmulationControl().getFeedingSide() == TwoSides.TWO ? pMaxFromCS2toCS1 : -pMaxFromCS1toCS2; default -> 0; }; return getSide2LossMultiplier() * boundedP; diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java index b659a7b121..41baec2073 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java @@ -39,7 +39,7 @@ void incrementModeSwitchCount(String hvdcId) { modeSwitchCount.computeIfAbsent(hvdcId, k -> new MutableInt(0)) .increment(); } - + void incrementFeedingSideSwitchCount(String hvdcId) { feedingSideSwitchCount.computeIfAbsent(hvdcId, k -> new MutableInt(0)) .increment(); @@ -72,45 +72,89 @@ public String getName() { return NAME; } - private void processHvdc(LfHvdc hvdc, ContextData contextData) { + private boolean checkFeedingSide(LfHvdc hvdc, ContextData contextData) { String hvdcId = hvdc.getId(); - if(contextData.getFeedingSideSwitchCount(hvdcId) < maxFeedingSideSwitch && contextData.getModeSwitchCount(hvdcId) < maxModeSwitch) { - LfHvdc.AcEmulationControl acEmulationControl = hvdc.getAcEmulationControl(); + LfHvdc.AcEmulationControl acEmulationControl = hvdc.getAcEmulationControl(); + + if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { + if (hvdc.getP1().eval() < 0) { + // Switch feeding side + LOGGER.trace("Switching feeding side from One to Two for Hvdc: " + hvdcId); + contextData.incrementFeedingSideSwitchCount(hvdcId); + acEmulationControl.setFeedingSide(TwoSides.TWO); + if (contextData.getFeedingSideSwitchCount(hvdcId) == maxFeedingSideSwitch) { + LOGGER.debug("Two many feeding side switches (flow blocked to 0 MW) for Hvdc: " + hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.NULL); + } + return true; + } + } else { + if (hvdc.getP2().eval() < 0) { + // Switch feeding side + LOGGER.trace("Switching feeding side from Two to One for Hvdc: " + hvdcId); + contextData.incrementFeedingSideSwitchCount(hvdcId); + acEmulationControl.setFeedingSide(TwoSides.ONE); + if (contextData.getFeedingSideSwitchCount(hvdcId) == maxFeedingSideSwitch) { + LOGGER.debug("Two many feeding side switches (flow blocked to 0 MW) for Hvdc: " + hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.NULL); + } + return true; + } + } + return false; + } + + private boolean checkMode(LfHvdc hvdc, ContextData contextData) { + String hvdcId = hvdc.getId(); + LfHvdc.AcEmulationControl acEmulationControl = hvdc.getAcEmulationControl(); - // Check feeding side + // Check for mode switch between FREE and BOUNDED + if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.FREE) { + // Check Pmax if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { - if (hvdc.getP1().eval() < 0) { - // Switch feeding side - LOGGER.trace("Switching feeding side from One to Two for Hvdc: " + hvdcId); - contextData.incrementFeedingSideSwitchCount(hvdcId); - acEmulationControl.setFeedingSide(TwoSides.TWO); - if (contextData.getFeedingSideSwitchCount(hvdcId) == maxFeedingSideSwitch) { - LOGGER.debug("Two many feeding side switches (flow blocked to 0 MW) for Hvdc: " + hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.NULL); + if (hvdc.getP1().eval() > acEmulationControl.getPMaxFromCS1toCS2()) { + // Switch mode + LOGGER.trace("Bound Hvdc flow to Pmax from CS1 to CS2 for Hvdc: " + hvdcId); + contextData.incrementModeSwitchCount(hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); + if (contextData.getModeSwitchCount(hvdcId) == maxModeSwitch) { + LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS1 to CS2) for Hvdc: " + hvdcId); } + return true; } } else { - if (hvdc.getP2().eval() < 0) { - // Switch feeding side - LOGGER.trace("Switching feeding side from Two to One for Hvdc: " + hvdcId); - contextData.incrementFeedingSideSwitchCount(hvdcId); - acEmulationControl.setFeedingSide(TwoSides.ONE); - if (contextData.getFeedingSideSwitchCount(hvdcId) == maxFeedingSideSwitch) { - LOGGER.debug("Two many feeding side switches (flow blocked to 0 MW) for Hvdc: " + hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.NULL); + if (hvdc.getP2().eval() > acEmulationControl.getPMaxFromCS2toCS1()) { + // Switch mode + LOGGER.trace("Bound Hvdc flow to Pmax from CS2 to CS1 for Hvdc: " + hvdcId); + contextData.incrementModeSwitchCount(hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); + if (contextData.getModeSwitchCount(hvdcId) == maxModeSwitch) { + LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS2 to CS1) for Hvdc: " + hvdcId); } + return true; } - } + } - // Check Pmax - // TODO HG + // Check for mode switch between BOUNDED and FREE + if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED) { if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { - + if (hvdc.getP1().eval() < acEmulationControl.getPMaxFromCS1toCS2()) { + // Switch mode + LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); + return true; + } } else { - + if (hvdc.getP2().eval() < acEmulationControl.getPMaxFromCS2toCS1()) { + // Switch mode + LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); + return true; + } } } + return false; } @Override @@ -118,7 +162,19 @@ public OuterLoopResult check(AcOuterLoopContext context, ReportNode reportNode) OuterLoopStatus status = OuterLoopStatus.STABLE; ContextData contextData = (ContextData) context.getData(); - context.getNetwork().getHvdcs().forEach(hvdc -> processHvdc(hvdc, contextData)); - return null; + for (LfHvdc hvdc : context.getNetwork().getHvdcs()) { + String hvdcId = hvdc.getId(); + if (contextData.getFeedingSideSwitchCount(hvdcId) < maxFeedingSideSwitch && contextData.getModeSwitchCount(hvdcId) < maxModeSwitch) { + // First check the feeding side + if (checkFeedingSide(hvdc, contextData)) + status = OuterLoopStatus.UNSTABLE; + + // Second check for Pmax values + if (checkMode(hvdc, contextData)) + status = OuterLoopStatus.UNSTABLE; + } + } + + return new OuterLoopResult(this, status); } } diff --git a/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java b/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java index 77fecd4732..bde4c39e7f 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java @@ -19,8 +19,7 @@ public interface LfHvdc extends LfElement { class AcEmulationControl { public enum AcEmulationStatus { FREE, - BOUNDED_SIDE_ONE, - BOUNDED_SIDE_TWO, + BOUNDED, NULL; } private final double droop; From 448652af443bcef6135de905683e132bf108d670 Mon Sep 17 00:00:00 2001 From: Hadrien Date: Fri, 14 Jun 2024 09:47:57 +0200 Subject: [PATCH 08/21] Fix typos Signed-off-by: Hadrien --- ...cEmulationSide1ActiveFlowEquationTerm.java | 3 +-- ...cEmulationSide2ActiveFlowEquationTerm.java | 3 +-- .../ac/outerloop/AcEmulationOuterLoop.java | 20 ++++++++++--------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide1ActiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide1ActiveFlowEquationTerm.java index 8c3158abca..6b6399766d 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide1ActiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide1ActiveFlowEquationTerm.java @@ -40,8 +40,7 @@ private double p1(double ph1, double ph2) { protected double dp1dph1() { if (element.getAcEmulationControl().getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.FREE) { return getSide1LossMultiplier() * k; - } - else { + } else { return 0; } } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java index a3a9020d18..ee1186913b 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java @@ -40,8 +40,7 @@ private double p2(double ph1, double ph2) { private double dp2dph1() { if (element.getAcEmulationControl().getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.FREE) { return getSide2LossMultiplier() * k; - } - else { + } else { return 0; } } diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java index 41baec2073..42022590b2 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java @@ -28,8 +28,8 @@ public class AcEmulationOuterLoop implements AcOuterLoop { private static final Logger LOGGER = LoggerFactory.getLogger(AcEmulationOuterLoop.class); public static final String NAME = "AcEmulation"; - private static final int maxModeSwitch = 2; - private static final int maxFeedingSideSwitch = 2; + private static final int MAX_MODE_SWITCH = 2; + private static final int MAX_FEEDING_SIDE_SWITCH = 2; private static final class ContextData { private final Map modeSwitchCount = new HashMap<>(); @@ -82,7 +82,7 @@ private boolean checkFeedingSide(LfHvdc hvdc, ContextData contextData) { LOGGER.trace("Switching feeding side from One to Two for Hvdc: " + hvdcId); contextData.incrementFeedingSideSwitchCount(hvdcId); acEmulationControl.setFeedingSide(TwoSides.TWO); - if (contextData.getFeedingSideSwitchCount(hvdcId) == maxFeedingSideSwitch) { + if (contextData.getFeedingSideSwitchCount(hvdcId) == MAX_FEEDING_SIDE_SWITCH) { LOGGER.debug("Two many feeding side switches (flow blocked to 0 MW) for Hvdc: " + hvdcId); acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.NULL); } @@ -94,7 +94,7 @@ private boolean checkFeedingSide(LfHvdc hvdc, ContextData contextData) { LOGGER.trace("Switching feeding side from Two to One for Hvdc: " + hvdcId); contextData.incrementFeedingSideSwitchCount(hvdcId); acEmulationControl.setFeedingSide(TwoSides.ONE); - if (contextData.getFeedingSideSwitchCount(hvdcId) == maxFeedingSideSwitch) { + if (contextData.getFeedingSideSwitchCount(hvdcId) == MAX_FEEDING_SIDE_SWITCH) { LOGGER.debug("Two many feeding side switches (flow blocked to 0 MW) for Hvdc: " + hvdcId); acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.NULL); } @@ -117,7 +117,7 @@ private boolean checkMode(LfHvdc hvdc, ContextData contextData) { LOGGER.trace("Bound Hvdc flow to Pmax from CS1 to CS2 for Hvdc: " + hvdcId); contextData.incrementModeSwitchCount(hvdcId); acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); - if (contextData.getModeSwitchCount(hvdcId) == maxModeSwitch) { + if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS1 to CS2) for Hvdc: " + hvdcId); } return true; @@ -128,7 +128,7 @@ private boolean checkMode(LfHvdc hvdc, ContextData contextData) { LOGGER.trace("Bound Hvdc flow to Pmax from CS2 to CS1 for Hvdc: " + hvdcId); contextData.incrementModeSwitchCount(hvdcId); acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); - if (contextData.getModeSwitchCount(hvdcId) == maxModeSwitch) { + if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS2 to CS1) for Hvdc: " + hvdcId); } return true; @@ -164,14 +164,16 @@ public OuterLoopResult check(AcOuterLoopContext context, ReportNode reportNode) for (LfHvdc hvdc : context.getNetwork().getHvdcs()) { String hvdcId = hvdc.getId(); - if (contextData.getFeedingSideSwitchCount(hvdcId) < maxFeedingSideSwitch && contextData.getModeSwitchCount(hvdcId) < maxModeSwitch) { + if (contextData.getFeedingSideSwitchCount(hvdcId) < MAX_FEEDING_SIDE_SWITCH && contextData.getModeSwitchCount(hvdcId) < MAX_MODE_SWITCH) { // First check the feeding side - if (checkFeedingSide(hvdc, contextData)) + if (checkFeedingSide(hvdc, contextData)) { status = OuterLoopStatus.UNSTABLE; + } // Second check for Pmax values - if (checkMode(hvdc, contextData)) + if (checkMode(hvdc, contextData)) { status = OuterLoopStatus.UNSTABLE; + } } } From 25ad3a85822604d2d805316d6bc3861f3c67ba60 Mon Sep 17 00:00:00 2001 From: Hadrien Date: Fri, 14 Jun 2024 10:27:24 +0200 Subject: [PATCH 09/21] Fix tests Signed-off-by: Hadrien --- .../HvdcAcEmulationSide2ActiveFlowEquationTerm.java | 4 ++-- .../openloadflow/ac/outerloop/AcEmulationOuterLoop.java | 3 +++ .../sa/OpenSecurityAnalysisWithActionsTest.java | 2 +- src/test/resources/esgTutoReport.txt | 2 ++ src/test/resources/esgTutoReportDetailedNrReportSensi.txt | 1 + src/test/resources/saReportOperatorStrategies.txt | 7 +++++++ 6 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java index ee1186913b..f596c939f1 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/HvdcAcEmulationSide2ActiveFlowEquationTerm.java @@ -30,7 +30,7 @@ private double getSide2LossMultiplier() { private double p2(double ph1, double ph2) { double boundedP = switch (element.getAcEmulationControl().getAcEmulationStatus()) { - case FREE -> rawP(p0, k, ph2, ph1); + case FREE -> -rawP(p0, k, ph1, ph2); case BOUNDED -> element.getAcEmulationControl().getFeedingSide() == TwoSides.TWO ? pMaxFromCS2toCS1 : -pMaxFromCS1toCS2; default -> 0; }; @@ -39,7 +39,7 @@ private double p2(double ph1, double ph2) { private double dp2dph1() { if (element.getAcEmulationControl().getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.FREE) { - return getSide2LossMultiplier() * k; + return -getSide2LossMultiplier() * k; } else { return 0; } diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java index 42022590b2..0f361850b1 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java @@ -163,6 +163,9 @@ public OuterLoopResult check(AcOuterLoopContext context, ReportNode reportNode) ContextData contextData = (ContextData) context.getData(); for (LfHvdc hvdc : context.getNetwork().getHvdcs()) { + if (!hvdc.isAcEmulation() || hvdc.getBus1().isDisabled() || hvdc.getBus2().isDisabled()) { + continue; + } String hvdcId = hvdc.getId(); if (contextData.getFeedingSideSwitchCount(hvdcId) < MAX_FEEDING_SIDE_SWITCH && contextData.getModeSwitchCount(hvdcId) < MAX_MODE_SWITCH) { // First check the feeding side diff --git a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisWithActionsTest.java b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisWithActionsTest.java index e61b270e67..4b9af0e11f 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisWithActionsTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisWithActionsTest.java @@ -1279,7 +1279,7 @@ void testWrongShuntAction() { @Test void testVSCLossAcEmulation() { - // contingency leads to the lost of one converter station. + // contingency leads to the loss of one converter station. // contingency leads to zero active power transmission in the hvdc line. // but other converter station keeps its voltage control capability. // remedial action re-enables the ac emulation of the hvdc line. diff --git a/src/test/resources/esgTutoReport.txt b/src/test/resources/esgTutoReport.txt index 9714db7f95..9edf254676 100644 --- a/src/test/resources/esgTutoReport.txt +++ b/src/test/resources/esgTutoReport.txt @@ -14,6 +14,7 @@ Outer loop DistributedSlack Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) + Sensitivity analysis on network 'sim1' + Network CC0 SC0 @@ -24,4 +25,5 @@ Slack bus: VLLOAD_0 Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) diff --git a/src/test/resources/esgTutoReportDetailedNrReportSensi.txt b/src/test/resources/esgTutoReportDetailedNrReportSensi.txt index 6904bf38c8..20616b5413 100644 --- a/src/test/resources/esgTutoReportDetailedNrReportSensi.txt +++ b/src/test/resources/esgTutoReportDetailedNrReportSensi.txt @@ -66,4 +66,5 @@ Bus injection: 607.0001563589107 MW, 225.40357009583855 MVar Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) diff --git a/src/test/resources/saReportOperatorStrategies.txt b/src/test/resources/saReportOperatorStrategies.txt index c2833fb62e..50c3a3a9aa 100644 --- a/src/test/resources/saReportOperatorStrategies.txt +++ b/src/test/resources/saReportOperatorStrategies.txt @@ -9,28 +9,35 @@ + Pre-contingency simulation Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) + Post-contingency simulation 'L1' Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) + Operator strategy simulation 'strategyL1' Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) + Post-contingency simulation 'L3' Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) + Operator strategy simulation 'strategyL3' Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) + Post-contingency simulation 'L2' Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) + Operator strategy simulation 'strategyL2' Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) From 1c22515003647f26ff0a6c83c0ce5592eb8169ba Mon Sep 17 00:00:00 2001 From: Hadrien Date: Fri, 14 Jun 2024 11:17:05 +0200 Subject: [PATCH 10/21] Fix tests Signed-off-by: Hadrien --- .../openloadflow/ac/outerloop/AcEmulationOuterLoop.java | 2 +- src/test/resources/detailedNrReportSecurityAnalysis.txt | 3 +++ src/test/resources/esgTutoReport.txt | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java index 0f361850b1..2fbce6527f 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java @@ -163,7 +163,7 @@ public OuterLoopResult check(AcOuterLoopContext context, ReportNode reportNode) ContextData contextData = (ContextData) context.getData(); for (LfHvdc hvdc : context.getNetwork().getHvdcs()) { - if (!hvdc.isAcEmulation() || hvdc.getBus1().isDisabled() || hvdc.getBus2().isDisabled()) { + if (!hvdc.isAcEmulation() || hvdc.getBus1().isDisabled() || hvdc.getBus2().isDisabled() || hvdc.isDisabled()) { continue; } String hvdcId = hvdc.getId(); diff --git a/src/test/resources/detailedNrReportSecurityAnalysis.txt b/src/test/resources/detailedNrReportSecurityAnalysis.txt index 8a323d826b..2ff730b158 100644 --- a/src/test/resources/detailedNrReportSecurityAnalysis.txt +++ b/src/test/resources/detailedNrReportSecurityAnalysis.txt @@ -68,6 +68,7 @@ Outer loop DistributedSlack Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) + Post-contingency simulation 'L2' + Newton Raphson on Network CC0 SC0 @@ -163,7 +164,9 @@ Bus injection: 608.3346737740034 MW, 234.0235926831469 MVar Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation Outer loop DistributedSlack Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) diff --git a/src/test/resources/esgTutoReport.txt b/src/test/resources/esgTutoReport.txt index 9edf254676..694e2e0157 100644 --- a/src/test/resources/esgTutoReport.txt +++ b/src/test/resources/esgTutoReport.txt @@ -11,6 +11,7 @@ Slack bus active power (-1.4404045651219555 MW) distributed in 1 distribution iteration(s) Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation Outer loop DistributedSlack Outer loop VoltageMonitoring Outer loop ReactiveLimits From 39bf64a24597ce7adeb1c17c99de7ffa4c32230f Mon Sep 17 00:00:00 2001 From: Hadrien Date: Fri, 14 Jun 2024 12:00:06 +0200 Subject: [PATCH 11/21] Reporter Signed-off-by: Hadrien --- .../controllerShuntAlreadyInVoltageControlReport.txt | 2 ++ src/test/resources/esgTutoReportDetailedNrReportLf.txt | 2 ++ src/test/resources/generatorVoltageControlDiscarded.txt | 1 + ...atorsConnectedToSameBusNotControllingSameBusReport.txt | 1 + .../resources/multipleConnectedComponentsAcReport.txt | 1 + src/test/resources/saReport.txt | 8 ++++++++ .../sharedGeneratorRemoteReactivePowerControlReport.txt | 1 + src/test/resources/shuntVoltageControlDiscarded.txt | 2 ++ src/test/resources/shuntVoltageControlOuterLoopReport.txt | 2 ++ .../transformerReactivePowerControlOuterLoopReport.txt | 4 ++++ src/test/resources/transformerVoltageControlDiscarded.txt | 2 ++ 11 files changed, 26 insertions(+) diff --git a/src/test/resources/controllerShuntAlreadyInVoltageControlReport.txt b/src/test/resources/controllerShuntAlreadyInVoltageControlReport.txt index 98f4429245..2fd95b4038 100644 --- a/src/test/resources/controllerShuntAlreadyInVoltageControlReport.txt +++ b/src/test/resources/controllerShuntAlreadyInVoltageControlReport.txt @@ -11,8 +11,10 @@ Outer loop VoltageMonitoring Outer loop ReactiveLimits Outer loop ShuntVoltageControl + Outer loop AcEmulation Outer loop DistributedSlack Outer loop VoltageMonitoring Outer loop ReactiveLimits Outer loop ShuntVoltageControl + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) diff --git a/src/test/resources/esgTutoReportDetailedNrReportLf.txt b/src/test/resources/esgTutoReportDetailedNrReportLf.txt index b0ddfeed51..c559e1d864 100644 --- a/src/test/resources/esgTutoReportDetailedNrReportLf.txt +++ b/src/test/resources/esgTutoReportDetailedNrReportLf.txt @@ -223,10 +223,12 @@ + Outer loop IncrementalTransformerVoltageControl + Outer loop iteration 2 1 voltage-controlled buses are outside of their target deadbands + Outer loop AcEmulation Outer loop DistributedSlack Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop IncrementalTransformerVoltageControl + Outer loop iteration 2 1 voltage-controlled buses are outside of their target deadbands + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) diff --git a/src/test/resources/generatorVoltageControlDiscarded.txt b/src/test/resources/generatorVoltageControlDiscarded.txt index a42c147f6a..475b5c45d1 100644 --- a/src/test/resources/generatorVoltageControlDiscarded.txt +++ b/src/test/resources/generatorVoltageControlDiscarded.txt @@ -11,4 +11,5 @@ Outer loop VoltageMonitoring Outer loop ReactiveLimits Outer loop SimpleTransformerVoltageControl + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) diff --git a/src/test/resources/generatorsConnectedToSameBusNotControllingSameBusReport.txt b/src/test/resources/generatorsConnectedToSameBusNotControllingSameBusReport.txt index 366ec047f1..6b9ec11043 100644 --- a/src/test/resources/generatorsConnectedToSameBusNotControllingSameBusReport.txt +++ b/src/test/resources/generatorsConnectedToSameBusNotControllingSameBusReport.txt @@ -8,4 +8,5 @@ Angle reference bus: VLGEN_0 Slack bus: VLGEN_0 Outer loop VoltageMonitoring + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) diff --git a/src/test/resources/multipleConnectedComponentsAcReport.txt b/src/test/resources/multipleConnectedComponentsAcReport.txt index a7170efdb2..fd9e9ab489 100644 --- a/src/test/resources/multipleConnectedComponentsAcReport.txt +++ b/src/test/resources/multipleConnectedComponentsAcReport.txt @@ -9,6 +9,7 @@ Outer loop DistributedSlack Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) + Network CC1 SC1 + Network info diff --git a/src/test/resources/saReport.txt b/src/test/resources/saReport.txt index eed341c721..38ca73d533 100644 --- a/src/test/resources/saReport.txt +++ b/src/test/resources/saReport.txt @@ -12,9 +12,11 @@ Slack bus active power (-1.4404045651219555 MW) distributed in 1 distribution iteration(s) Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation Outer loop DistributedSlack Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) + Post-contingency simulation 'NHV1_NHV2_1' + Outer loop DistributedSlack @@ -22,9 +24,11 @@ Slack bus active power (5.803741102800952 MW) distributed in 1 distribution iteration(s) Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation Outer loop DistributedSlack Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) + Post-contingency simulation 'NHV1_NHV2_2' + Outer loop DistributedSlack @@ -32,9 +36,11 @@ Slack bus active power (5.803741102800952 MW) distributed in 1 distribution iteration(s) Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation Outer loop DistributedSlack Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) + Post-contingency simulation 'NGEN_NHV1' 1 buses have a voltage magnitude out of the configured realistic range [0.5, 1.5] p.u.: {VLHV1_0=1.5105659472379578} @@ -45,7 +51,9 @@ Slack bus active power (-5.4942194604343655 MW) distributed in 1 distribution iteration(s) Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation Outer loop DistributedSlack Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) diff --git a/src/test/resources/sharedGeneratorRemoteReactivePowerControlReport.txt b/src/test/resources/sharedGeneratorRemoteReactivePowerControlReport.txt index 9e9e4fd45e..5828d177e5 100644 --- a/src/test/resources/sharedGeneratorRemoteReactivePowerControlReport.txt +++ b/src/test/resources/sharedGeneratorRemoteReactivePowerControlReport.txt @@ -8,4 +8,5 @@ Angle reference bus: b1_vl_0 Slack bus: b1_vl_0 Outer loop VoltageMonitoring + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) diff --git a/src/test/resources/shuntVoltageControlDiscarded.txt b/src/test/resources/shuntVoltageControlDiscarded.txt index 3e3ff71efe..37beb8747d 100644 --- a/src/test/resources/shuntVoltageControlDiscarded.txt +++ b/src/test/resources/shuntVoltageControlDiscarded.txt @@ -11,8 +11,10 @@ Outer loop VoltageMonitoring Outer loop ReactiveLimits Outer loop ShuntVoltageControl + Outer loop AcEmulation Outer loop DistributedSlack Outer loop VoltageMonitoring Outer loop ReactiveLimits Outer loop ShuntVoltageControl + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) diff --git a/src/test/resources/shuntVoltageControlOuterLoopReport.txt b/src/test/resources/shuntVoltageControlOuterLoopReport.txt index 4347afc3f7..8533672d84 100644 --- a/src/test/resources/shuntVoltageControlOuterLoopReport.txt +++ b/src/test/resources/shuntVoltageControlOuterLoopReport.txt @@ -104,8 +104,10 @@ Bus Id: vl1_0 (nominalVoltage=400.0kV) Bus V: 0.975 pu, 0.002014826586019094 rad Bus injection: 101.3664080925296 MW, -2.165165450231683 MVar + Outer loop AcEmulation Outer loop DistributedSlack Outer loop VoltageMonitoring Outer loop ReactiveLimits Outer loop IncrementalShuntVoltageControl + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) diff --git a/src/test/resources/transformerReactivePowerControlOuterLoopReport.txt b/src/test/resources/transformerReactivePowerControlOuterLoopReport.txt index 327991105f..5a02352314 100644 --- a/src/test/resources/transformerReactivePowerControlOuterLoopReport.txt +++ b/src/test/resources/transformerReactivePowerControlOuterLoopReport.txt @@ -211,6 +211,7 @@ Bus Id: VL_1_0 (nominalVoltage=132.0kV) Bus V: 1.0227272727272727 pu, 0.011772577480572114 rad Bus injection: 22.111739596487254 MW, 7.223626593973918 MVar + Outer loop AcEmulation + Outer loop DistributedSlack + Outer loop iteration 4 Slack bus active power (2.379902997164196 MW) distributed in 1 distribution iteration(s) @@ -246,12 +247,15 @@ Bus injection: 24.491420280899572 MW, 7.284141028025306 MVar Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation + Outer loop IncrementalTransformerReactivePowerControl + Outer loop iteration 5 1 reactive power-controlled branches are outside of their target deadbands + Outer loop AcEmulation Outer loop DistributedSlack Outer loop VoltageMonitoring Outer loop ReactiveLimits + Outer loop AcEmulation + Outer loop IncrementalTransformerReactivePowerControl + Outer loop iteration 5 1 reactive power-controlled branches are outside of their target deadbands diff --git a/src/test/resources/transformerVoltageControlDiscarded.txt b/src/test/resources/transformerVoltageControlDiscarded.txt index c3d7024b31..99cde77d2e 100644 --- a/src/test/resources/transformerVoltageControlDiscarded.txt +++ b/src/test/resources/transformerVoltageControlDiscarded.txt @@ -13,8 +13,10 @@ Outer loop VoltageMonitoring Outer loop ReactiveLimits Outer loop SimpleTransformerVoltageControl + Outer loop AcEmulation Outer loop DistributedSlack Outer loop VoltageMonitoring Outer loop ReactiveLimits Outer loop SimpleTransformerVoltageControl + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) From 7e309204bb817a8a2e40770574a3c31083493f5b Mon Sep 17 00:00:00 2001 From: Hadrien Date: Fri, 14 Jun 2024 12:02:27 +0200 Subject: [PATCH 12/21] Reporter test fix Signed-off-by: Hadrien --- .../transformerReactivePowerControlOuterLoopReport.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/transformerReactivePowerControlOuterLoopReport.txt b/src/test/resources/transformerReactivePowerControlOuterLoopReport.txt index 5a02352314..7ddc635800 100644 --- a/src/test/resources/transformerReactivePowerControlOuterLoopReport.txt +++ b/src/test/resources/transformerReactivePowerControlOuterLoopReport.txt @@ -255,8 +255,8 @@ Outer loop DistributedSlack Outer loop VoltageMonitoring Outer loop ReactiveLimits - Outer loop AcEmulation + Outer loop IncrementalTransformerReactivePowerControl + Outer loop iteration 5 1 reactive power-controlled branches are outside of their target deadbands + Outer loop AcEmulation AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE) From 8b596e86f7e6ba957d9029eb45f2045bc882a762 Mon Sep 17 00:00:00 2001 From: Hadrien Date: Fri, 14 Jun 2024 12:04:46 +0200 Subject: [PATCH 13/21] Fix Signed-off-by: Hadrien --- .../resources/transformerReactivePowerControlOuterLoopReport.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/resources/transformerReactivePowerControlOuterLoopReport.txt b/src/test/resources/transformerReactivePowerControlOuterLoopReport.txt index 7ddc635800..ef71733067 100644 --- a/src/test/resources/transformerReactivePowerControlOuterLoopReport.txt +++ b/src/test/resources/transformerReactivePowerControlOuterLoopReport.txt @@ -247,7 +247,6 @@ Bus injection: 24.491420280899572 MW, 7.284141028025306 MVar Outer loop VoltageMonitoring Outer loop ReactiveLimits - Outer loop AcEmulation + Outer loop IncrementalTransformerReactivePowerControl + Outer loop iteration 5 1 reactive power-controlled branches are outside of their target deadbands From 2f44f84876a13fc6abf3e39d4dfd65608443ccf3 Mon Sep 17 00:00:00 2001 From: Hadrien Date: Fri, 14 Jun 2024 12:21:38 +0200 Subject: [PATCH 14/21] Tests ok Signed-off-by: Hadrien --- .../java/com/powsybl/openloadflow/EquationsTest.java | 9 ++++++++- .../powsybl/openloadflow/OpenLoadFlowParametersTest.java | 4 ++-- .../powsybl/openloadflow/OpenLoadFlowProviderTest.java | 2 +- .../openloadflow/sa/OpenSecurityAnalysisTest.java | 8 ++++---- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/test/java/com/powsybl/openloadflow/EquationsTest.java b/src/test/java/com/powsybl/openloadflow/EquationsTest.java index e39c0808c6..39462c84e9 100644 --- a/src/test/java/com/powsybl/openloadflow/EquationsTest.java +++ b/src/test/java/com/powsybl/openloadflow/EquationsTest.java @@ -8,6 +8,7 @@ package com.powsybl.openloadflow; import com.powsybl.commons.PowsyblException; +import com.powsybl.iidm.network.TwoSides; import com.powsybl.math.matrix.DenseMatrix; import com.powsybl.openloadflow.ac.equations.*; import com.powsybl.openloadflow.dc.equations.ClosedBranchSide1DcFlowEquationTerm; @@ -64,7 +65,13 @@ public Object answer(InvocationOnMock invocation) { private static final double LOSS_FACTOR_1 = 0.01100000023841858; private static final double LOSS_FACTOR_2 = 0.02400453453002384; private static final double G_SHUNT = 0.0000372472384299244; - private static final LfHvdc.AcEmulationControl AC_EMULATION_CONTROL = new LfHvdc.AcEmulationControl(DROOP * PerUnit.SB, P_0 * PerUnit.SB, Double.MAX_VALUE, Double.MAX_VALUE); + + private static LfHvdc.AcEmulationControl buildAcEmulationControl() { + LfHvdc.AcEmulationControl acEmulationControl = new LfHvdc.AcEmulationControl(DROOP * PerUnit.SB, P_0 * PerUnit.SB, Double.MAX_VALUE, Double.MAX_VALUE); + acEmulationControl.setFeedingSide(TwoSides.TWO); + return acEmulationControl; + } + private static final LfHvdc.AcEmulationControl AC_EMULATION_CONTROL = buildAcEmulationControl(); private static & Quantity, E extends Enum & Quantity> double[] eval(EquationTerm term, List> variables, StateVector sv) { term.setStateVector(sv); diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java index 166ee44393..15be5033a4 100644 --- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java +++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java @@ -395,7 +395,7 @@ void testExplicitOuterLoopsParameter() { OpenLoadFlowParameters parametersExt = new OpenLoadFlowParameters() .setSecondaryVoltageControl(true); - assertEquals(List.of("DistributedSlack", "SecondaryVoltageControl", "VoltageMonitoring", "ReactiveLimits", "ShuntVoltageControl"), OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); + assertEquals(List.of("DistributedSlack", "SecondaryVoltageControl", "VoltageMonitoring", "ReactiveLimits", "ShuntVoltageControl", "AcEmulation"), OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); parametersExt.setOuterLoopNames(List.of("ReactiveLimits", "SecondaryVoltageControl")); assertEquals(List.of("ReactiveLimits", "SecondaryVoltageControl"), OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); @@ -408,7 +408,7 @@ void testExplicitOuterLoopsParameter() { e = assertThrows(PowsyblException.class, () -> OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt)); assertEquals("Unknown outer loop 'Foo'", e.getMessage()); - assertEquals("Ordered explicit list of outer loop names, supported outer loops are IncrementalPhaseControl, DistributedSlack, IncrementalShuntVoltageControl, IncrementalTransformerVoltageControl, VoltageMonitoring, PhaseControl, ReactiveLimits, SecondaryVoltageControl, ShuntVoltageControl, SimpleTransformerVoltageControl, TransformerVoltageControl, AutomationSystem, IncrementalTransformerReactivePowerControl", + assertEquals("Ordered explicit list of outer loop names, supported outer loops are IncrementalPhaseControl, DistributedSlack, IncrementalShuntVoltageControl, IncrementalTransformerVoltageControl, VoltageMonitoring, PhaseControl, ReactiveLimits, SecondaryVoltageControl, ShuntVoltageControl, SimpleTransformerVoltageControl, TransformerVoltageControl, AutomationSystem, IncrementalTransformerReactivePowerControl, AcEmulation", OpenLoadFlowParameters.SPECIFIC_PARAMETERS.stream().filter(p -> p.getName().equals(OpenLoadFlowParameters.OUTER_LOOP_NAMES_PARAM_NAME)).findFirst().orElseThrow().getDescription()); } diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java index 762f4d34a9..6ae4ea2bc7 100644 --- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java +++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java @@ -59,7 +59,7 @@ void testDcParameters() { void testAcParameters() { Network network = Mockito.mock(Network.class); AcLoadFlowParameters acParameters = OpenLoadFlowParameters.createAcParameters(network, new LoadFlowParameters().setReadSlackBus(true), new OpenLoadFlowParameters(), new DenseMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), false, false); - assertEquals("AcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=true, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, generatorReactivePowerRemoteControl=false, transformerReactivePowerControl=false, loadFlowModel=AC, reactiveLimits=true, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=true, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE, useLoadModel=false, simulateAutomationSystems=false, referenceBusSelector=ReferenceBusFirstSlackSelector, voltageTargetPriorities=[GENERATOR, TRANSFORMER, SHUNT]), equationSystemCreationParameters=AcEquationSystemCreationParameters(forceA1Var=false), newtonRaphsonParameters=NewtonRaphsonParameters(maxIterations=15, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, stoppingCriteria=DefaultNewtonRaphsonStoppingCriteria, stateVectorScalingMode=NONE, alwaysUpdateNetwork=false, lineSearchStateVectorScalingMaxIteration=10, lineSearchStateVectorScalingStepFold=1.3333333333333333, maxVoltageChangeStateVectorScalingMaxDv=0.1, maxVoltageChangeStateVectorScalingMaxDphi=0.17453292519943295), newtonKrylovParameters=NewtonKrylovParameters(maxIterations=100, lineSearch=false), outerLoops=[DistributedSlackOuterLoop, MonitoringVoltageOuterLoop, ReactiveLimitsOuterLoop], maxOuterLoopIterations=20, matrixFactory=DenseMatrixFactory, voltageInitializer=UniformValueVoltageInitializer, asymmetrical=false, slackDistributionFailureBehavior=LEAVE_ON_SLACK_BUS, solverFactory=NewtonRaphsonFactory, detailedReport=false)", + assertEquals("AcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=true, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, generatorReactivePowerRemoteControl=false, transformerReactivePowerControl=false, loadFlowModel=AC, reactiveLimits=true, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=true, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE, useLoadModel=false, simulateAutomationSystems=false, referenceBusSelector=ReferenceBusFirstSlackSelector, voltageTargetPriorities=[GENERATOR, TRANSFORMER, SHUNT]), equationSystemCreationParameters=AcEquationSystemCreationParameters(forceA1Var=false), newtonRaphsonParameters=NewtonRaphsonParameters(maxIterations=15, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, stoppingCriteria=DefaultNewtonRaphsonStoppingCriteria, stateVectorScalingMode=NONE, alwaysUpdateNetwork=false, lineSearchStateVectorScalingMaxIteration=10, lineSearchStateVectorScalingStepFold=1.3333333333333333, maxVoltageChangeStateVectorScalingMaxDv=0.1, maxVoltageChangeStateVectorScalingMaxDphi=0.17453292519943295), newtonKrylovParameters=NewtonKrylovParameters(maxIterations=100, lineSearch=false), outerLoops=[DistributedSlackOuterLoop, MonitoringVoltageOuterLoop, ReactiveLimitsOuterLoop, AcEmulationOuterLoop], maxOuterLoopIterations=20, matrixFactory=DenseMatrixFactory, voltageInitializer=UniformValueVoltageInitializer, asymmetrical=false, slackDistributionFailureBehavior=LEAVE_ON_SLACK_BUS, solverFactory=NewtonRaphsonFactory, detailedReport=false)", acParameters.toString()); } diff --git a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java index e410eaa32c..7ab192cfa9 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java @@ -1302,11 +1302,11 @@ void testHvdcAcEmulation() { SecurityAnalysisResult result = runSecurityAnalysis(network, contingencies, monitors, parameters); PreContingencyResult preContingencyResult = result.getPreContingencyResult(); - assertEquals(-1.768, preContingencyResult.getNetworkResult().getBranchResult("l25").getP1(), LoadFlowAssert.DELTA_POWER); + assertEquals(-1.766, preContingencyResult.getNetworkResult().getBranchResult("l25").getP1(), LoadFlowAssert.DELTA_POWER); // post-contingency tests PostContingencyResult g1ContingencyResult = getPostContingencyResult(result, "g1"); - assertEquals(-2.783, g1ContingencyResult.getNetworkResult().getBranchResult("l25").getP1(), LoadFlowAssert.DELTA_POWER); + assertEquals(-2.780, g1ContingencyResult.getNetworkResult().getBranchResult("l25").getP1(), LoadFlowAssert.DELTA_POWER); List contingencies2 = new ArrayList<>(); contingencies2.add(Contingency.hvdcLine("hvdc34")); @@ -1315,10 +1315,10 @@ void testHvdcAcEmulation() { // post-contingency tests PostContingencyResult hvdcContingencyResult = getPostContingencyResult(result2, "hvdc34"); - assertEquals(-2.000, hvdcContingencyResult.getNetworkResult().getBranchResult("l25").getP1(), LoadFlowAssert.DELTA_POWER); + assertEquals(-1.998, hvdcContingencyResult.getNetworkResult().getBranchResult("l25").getP1(), LoadFlowAssert.DELTA_POWER); PostContingencyResult g1ContingencyResult2 = getPostContingencyResult(result, "g1"); - assertEquals(-2.783, g1ContingencyResult2.getNetworkResult().getBranchResult("l25").getP1(), LoadFlowAssert.DELTA_POWER); + assertEquals(-2.780, g1ContingencyResult2.getNetworkResult().getBranchResult("l25").getP1(), LoadFlowAssert.DELTA_POWER); } @Test From 510192e0764cb9ed0519459ae70c0b45140a496d Mon Sep 17 00:00:00 2001 From: Hadrien Date: Fri, 14 Jun 2024 14:38:39 +0200 Subject: [PATCH 15/21] Fix Signed-off-by: Hadrien --- src/test/java/com/powsybl/openloadflow/EquationsTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/com/powsybl/openloadflow/EquationsTest.java b/src/test/java/com/powsybl/openloadflow/EquationsTest.java index 39462c84e9..225c59da27 100644 --- a/src/test/java/com/powsybl/openloadflow/EquationsTest.java +++ b/src/test/java/com/powsybl/openloadflow/EquationsTest.java @@ -71,6 +71,7 @@ private static LfHvdc.AcEmulationControl buildAcEmulationControl() { acEmulationControl.setFeedingSide(TwoSides.TWO); return acEmulationControl; } + private static final LfHvdc.AcEmulationControl AC_EMULATION_CONTROL = buildAcEmulationControl(); private static & Quantity, E extends Enum & Quantity> double[] eval(EquationTerm term, List> variables, StateVector sv) { From eb703091dc50adf62da3f8ddf6f80d09870d22b1 Mon Sep 17 00:00:00 2001 From: Hadrien Date: Fri, 14 Jun 2024 16:39:25 +0200 Subject: [PATCH 16/21] DcLoadFlow Signed-off-by: Hadrien --- .../dc/DcAcEmulationOuterLoop.java | 134 ++++++++++++++++++ .../openloadflow/dc/DcLoadFlowEngine.java | 105 ++++++++------ .../openloadflow/dc/DcOuterLoopContext.java | 4 + ...ractHvdcAcEmulationDcFlowEquationTerm.java | 10 ++ ...vdcAcEmulationSide1DCFlowEquationTerm.java | 21 ++- ...vdcAcEmulationSide2DCFlowEquationTerm.java | 25 +++- .../multipleConnectedComponentsDcReport.txt | 2 + 7 files changed, 248 insertions(+), 53 deletions(-) create mode 100644 src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java new file mode 100644 index 0000000000..7a43e71e72 --- /dev/null +++ b/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java @@ -0,0 +1,134 @@ +/** + * Copyright (c) 2023, Coreso SA (https://www.coreso.eu/) and TSCNET Services GmbH (https://www.tscnet.eu/) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.openloadflow.dc; + +import com.powsybl.commons.report.ReportNode; +import com.powsybl.iidm.network.TwoSides; +import com.powsybl.openloadflow.dc.equations.DcEquationType; +import com.powsybl.openloadflow.dc.equations.DcVariableType; +import com.powsybl.openloadflow.lf.outerloop.OuterLoop; +import com.powsybl.openloadflow.lf.outerloop.OuterLoopResult; +import com.powsybl.openloadflow.lf.outerloop.OuterLoopStatus; +import com.powsybl.openloadflow.network.LfHvdc; +import org.apache.commons.lang3.mutable.MutableInt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Hadrien Godard {@literal } + */ +public class DcAcEmulationOuterLoop implements OuterLoop { + + private static final Logger LOGGER = LoggerFactory.getLogger(DcAcEmulationOuterLoop.class); + public static final String NAME = "DcAcEmulation"; + + private static final int MAX_MODE_SWITCH = 2; + + private static final class ContextData { + private final Map modeSwitchCount = new HashMap<>(); + + void incrementModeSwitchCount(String hvdcId) { + modeSwitchCount.computeIfAbsent(hvdcId, k -> new MutableInt(0)) + .increment(); + } + + int getModeSwitchCount(String hvdcId) { + MutableInt counter = modeSwitchCount.get(hvdcId); + if (counter == null) { + return 0; + } + return counter.getValue(); + } + } + + public void initialize(DcOuterLoopContext context) { + context.setData(new ContextData()); + } + + @Override + public String getName() { + return NAME; + } + + private boolean checkMode(LfHvdc hvdc, ContextData contextData) { + String hvdcId = hvdc.getId(); + LfHvdc.AcEmulationControl acEmulationControl = hvdc.getAcEmulationControl(); + + // Check for mode switch between FREE and BOUNDED + if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.FREE) { + // Check Pmax + if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { + if (hvdc.getP1().eval() > acEmulationControl.getPMaxFromCS1toCS2()) { + // Switch mode + LOGGER.trace("Bound Hvdc flow to Pmax from CS1 to CS2 for Hvdc: " + hvdcId); + contextData.incrementModeSwitchCount(hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); + if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { + LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS1 to CS2) for Hvdc: " + hvdcId); + } + return true; + } + } else { + if (hvdc.getP2().eval() > acEmulationControl.getPMaxFromCS2toCS1()) { + // Switch mode + LOGGER.trace("Bound Hvdc flow to Pmax from CS2 to CS1 for Hvdc: " + hvdcId); + contextData.incrementModeSwitchCount(hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); + if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { + LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS2 to CS1) for Hvdc: " + hvdcId); + } + return true; + } + } + } + + // Check for mode switch between BOUNDED and FREE + if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED) { + if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { + if (hvdc.getP1().eval() < acEmulationControl.getPMaxFromCS1toCS2()) { + // Switch mode + LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); + return true; + } + } else { + if (hvdc.getP2().eval() < acEmulationControl.getPMaxFromCS2toCS1()) { + // Switch mode + LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); + return true; + } + } + } + return false; + } + + @Override + public OuterLoopResult check(DcOuterLoopContext context, ReportNode reportNode) { + OuterLoopStatus status = OuterLoopStatus.STABLE; + ContextData contextData = (ContextData) context.getData(); + + for (LfHvdc hvdc : context.getNetwork().getHvdcs()) { + if (!hvdc.isAcEmulation() || hvdc.getBus1().isDisabled() || hvdc.getBus2().isDisabled() || hvdc.isDisabled()) { + continue; + } + String hvdcId = hvdc.getId(); + if (contextData.getModeSwitchCount(hvdcId) < MAX_MODE_SWITCH) { + // Check for Pmax values + if (checkMode(hvdc, contextData)) { + status = OuterLoopStatus.UNSTABLE; + } + } + } + + return new OuterLoopResult(this, status); + } +} diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java index 00e0808673..83f5841ce8 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java +++ b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java @@ -21,6 +21,7 @@ import com.powsybl.openloadflow.network.LfBus; import com.powsybl.openloadflow.network.LfNetwork; import com.powsybl.openloadflow.network.LfNetworkLoader; +import com.powsybl.openloadflow.network.LfNetworkParameters; import com.powsybl.openloadflow.network.util.ActivePowerDistribution; import com.powsybl.openloadflow.network.util.UniformValueVoltageInitializer; import com.powsybl.openloadflow.network.util.VoltageInitializer; @@ -69,20 +70,10 @@ public static void initStateVector(LfNetwork network, EquationSystem v : equationSystem.getIndex().getSortedVariablesToFind()) { switch (v.getType()) { - case BUS_PHI: - x[v.getRow()] = initializer.getAngle(network.getBus(v.getElementNum())); - break; - - case BRANCH_ALPHA1: - x[v.getRow()] = network.getBranch(v.getElementNum()).getPiModel().getA1(); - break; - - case DUMMY_P: - x[v.getRow()] = 0; - break; - - default: - throw new IllegalStateException("Unknown variable type " + v.getType()); + case BUS_PHI -> x[v.getRow()] = initializer.getAngle(network.getBus(v.getElementNum())); + case BRANCH_ALPHA1 -> x[v.getRow()] = network.getBranch(v.getElementNum()).getPiModel().getA1(); + case DUMMY_P -> x[v.getRow()] = 0; + default -> throw new IllegalStateException("Unknown variable type " + v.getType()); } } equationSystem.getStateVector().set(x); @@ -110,36 +101,59 @@ public static void updateNetwork(LfNetwork network, EquationSystem targetVector = context.getTargetVector(); - // outer loop initialization + // outer loops initialization DcIncrementalPhaseControlOuterLoop phaseShifterControlOuterLoop = new DcIncrementalPhaseControlOuterLoop(); - DcOuterLoopContext outerLoopContext = new DcOuterLoopContext(network); + DcOuterLoopContext phaseControlOuterLoopContext = new DcOuterLoopContext(network); if (parameters.getNetworkParameters().isPhaseControl()) { - phaseShifterControlOuterLoop.initialize(outerLoopContext); + phaseShifterControlOuterLoop.initialize(phaseControlOuterLoopContext); + } + DcAcEmulationOuterLoop acEmulationOuterLoop = new DcAcEmulationOuterLoop(); + DcOuterLoopContext acEmulationLoopContext = new DcOuterLoopContext(network); + if (parameters.getNetworkParameters().isHvdcAcEmulation()) { + acEmulationOuterLoop.initialize(acEmulationLoopContext); } initStateVector(network, equationSystem, new UniformValueVoltageInitializer()); @@ -188,9 +207,9 @@ public DcLoadFlowResult run() { equationSystem.getStateVector().set(targetVectorArray); updateNetwork(network, equationSystem, targetVectorArray); - // continue with PST active power control outer loop only if first linear system solution has succeeded - if (success && parameters.getNetworkParameters().isPhaseControl()) { - success = runPhaseControlOuterLoop(phaseShifterControlOuterLoop, outerLoopContext); + // continue with outer loops only if first linear system solution has succeeded + if (success) { + success = runOuterLoops(phaseShifterControlOuterLoop, phaseControlOuterLoopContext, acEmulationOuterLoop, acEmulationLoopContext, parameters.getNetworkParameters()); } // set all calculated voltages to NaN diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcOuterLoopContext.java b/src/main/java/com/powsybl/openloadflow/dc/DcOuterLoopContext.java index 6a8e959f90..e5db5f170d 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/DcOuterLoopContext.java +++ b/src/main/java/com/powsybl/openloadflow/dc/DcOuterLoopContext.java @@ -31,4 +31,8 @@ public int getIteration() { public void setIteration(int iteration) { this.iteration = iteration; } + + public void incrementIteration() { + this.iteration = iteration + 1; + } } diff --git a/src/main/java/com/powsybl/openloadflow/dc/equations/AbstractHvdcAcEmulationDcFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/dc/equations/AbstractHvdcAcEmulationDcFlowEquationTerm.java index a11a1b4e00..2307895300 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/equations/AbstractHvdcAcEmulationDcFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/dc/equations/AbstractHvdcAcEmulationDcFlowEquationTerm.java @@ -26,6 +26,9 @@ public abstract class AbstractHvdcAcEmulationDcFlowEquationTerm extends Abstract protected final List> variables; protected final LfHvdc hvdc; protected final double k; + protected final double p0; + protected final double pMaxFromCS1toCS2; + protected final double pMaxFromCS2toCS1; protected AbstractHvdcAcEmulationDcFlowEquationTerm(LfHvdc hvdc, LfBus bus1, LfBus bus2, VariableSet variableSet) { super(hvdc); @@ -34,6 +37,9 @@ protected AbstractHvdcAcEmulationDcFlowEquationTerm(LfHvdc hvdc, LfBus bus1, LfB variables = List.of(ph1Var, ph2Var); this.hvdc = hvdc; k = this.hvdc.getAcEmulationControl().getDroop() * 180 / Math.PI; + p0 = hvdc.getAcEmulationControl().getP0(); + pMaxFromCS1toCS2 = hvdc.getAcEmulationControl().getPMaxFromCS1toCS2(); + pMaxFromCS2toCS1 = hvdc.getAcEmulationControl().getPMaxFromCS2toCS1(); } @Override @@ -41,6 +47,10 @@ public List> getVariables() { return variables; } + protected double rawP(double p0, double k, double ph1, double ph2) { + return p0 + k * (ph1 - ph2); + } + protected double ph1() { return ph1(sv); } diff --git a/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide1DCFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide1DCFlowEquationTerm.java index 8f8dc175bb..5709410da2 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide1DCFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide1DCFlowEquationTerm.java @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.dc.equations; +import com.powsybl.iidm.network.TwoSides; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBus; @@ -28,15 +29,23 @@ protected String getName() { @Override public double eval() { - return k * (ph1() - ph2()) + hvdc.getAcEmulationControl().getP0(); + return switch (element.getAcEmulationControl().getAcEmulationStatus()) { + case FREE -> rawP(p0, k, ph1(), ph2()); + case BOUNDED -> element.getAcEmulationControl().getFeedingSide() == TwoSides.ONE ? pMaxFromCS1toCS2 : -pMaxFromCS2toCS1; + default -> 0; + }; } @Override public double der(Variable variable) { + double der = 0; + if (element.getAcEmulationControl().getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.FREE) { + der = k; + } if (variable.equals(ph1Var)) { - return k; + return der; } else if (variable.equals(ph2Var)) { - return -k; + return -der; } else { throw new IllegalStateException("Unknown variable: " + variable); } @@ -49,6 +58,10 @@ public boolean hasRhs() { @Override public double rhs() { - return hvdc.getAcEmulationControl().getP0(); + return switch (element.getAcEmulationControl().getAcEmulationStatus()) { + case FREE -> p0; + case BOUNDED -> element.getAcEmulationControl().getFeedingSide() == TwoSides.ONE ? pMaxFromCS1toCS2 : -pMaxFromCS2toCS1; + default -> 0; + }; } } diff --git a/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide2DCFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide2DCFlowEquationTerm.java index 600be02bd8..03799bba15 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide2DCFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide2DCFlowEquationTerm.java @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.dc.equations; +import com.powsybl.iidm.network.TwoSides; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBus; @@ -28,15 +29,23 @@ protected String getName() { @Override public double eval() { - return k * (ph2() - ph1()) - hvdc.getAcEmulationControl().getP0(); + return switch (element.getAcEmulationControl().getAcEmulationStatus()) { + case FREE -> -rawP(p0, k, ph1(), ph2()); + case BOUNDED -> element.getAcEmulationControl().getFeedingSide() == TwoSides.TWO ? pMaxFromCS2toCS1 : -pMaxFromCS1toCS2; + default -> 0; + }; } @Override public double der(Variable variable) { - if (variable.equals(ph1Var)) { - return -k; - } else if (variable.equals(ph2Var)) { - return k; + double der = 0; + if (element.getAcEmulationControl().getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.FREE) { + der = k; + } + if (variable.equals(ph2Var)) { + return der; + } else if (variable.equals(ph1Var)) { + return -der; } else { throw new IllegalStateException("Unknown variable: " + variable); } @@ -49,6 +58,10 @@ public boolean hasRhs() { @Override public double rhs() { - return -hvdc.getAcEmulationControl().getP0(); + return switch (element.getAcEmulationControl().getAcEmulationStatus()) { + case FREE -> -p0; + case BOUNDED -> element.getAcEmulationControl().getFeedingSide() == TwoSides.TWO ? pMaxFromCS2toCS1 : -pMaxFromCS1toCS2; + default -> 0; + }; } } diff --git a/src/test/resources/multipleConnectedComponentsDcReport.txt b/src/test/resources/multipleConnectedComponentsDcReport.txt index f25d69cdc5..08f5de9f64 100644 --- a/src/test/resources/multipleConnectedComponentsDcReport.txt +++ b/src/test/resources/multipleConnectedComponentsDcReport.txt @@ -6,6 +6,7 @@ Network balance: active generation=3.0 MW, active load=2.0 MW, reactive generation=0.0 MVar, reactive load=0.0 MVar Angle reference bus: b1_vl_0 Slack bus: b1_vl_0 + Outer loop DcAcEmulation DC load flow completed (status=true) + Network CC1 SC1 + Network info @@ -13,5 +14,6 @@ Network balance: active generation=2.0 MW, active load=4.0 MW, reactive generation=0.0 MVar, reactive load=0.0 MVar Angle reference bus: b5_vl_0 Slack bus: b5_vl_0 + Outer loop DcAcEmulation DC load flow completed (status=true) No calculation will be done on 1 network(s) that have no generators From 58976544629bc839c1b5de6336e203ccd9abc295 Mon Sep 17 00:00:00 2001 From: Hadrien Date: Fri, 14 Jun 2024 17:07:24 +0200 Subject: [PATCH 17/21] Refacto Signed-off-by: Hadrien --- .../ac/outerloop/AcEmulationOuterLoop.java | 107 ++------------- .../dc/DcAcEmulationOuterLoop.java | 87 +------------ .../AbstractAcEmulationOuterLoop.java | 122 ++++++++++++++++++ 3 files changed, 134 insertions(+), 182 deletions(-) create mode 100644 src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAcEmulationOuterLoop.java diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java index 2fbce6527f..d71f87c5de 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java @@ -9,64 +9,28 @@ import com.powsybl.commons.report.ReportNode; import com.powsybl.iidm.network.TwoSides; +import com.powsybl.openloadflow.ac.AcLoadFlowContext; +import com.powsybl.openloadflow.ac.AcLoadFlowParameters; import com.powsybl.openloadflow.ac.AcOuterLoopContext; +import com.powsybl.openloadflow.ac.equations.AcEquationType; +import com.powsybl.openloadflow.ac.equations.AcVariableType; +import com.powsybl.openloadflow.lf.outerloop.AbstractAcEmulationOuterLoop; import com.powsybl.openloadflow.lf.outerloop.OuterLoopResult; import com.powsybl.openloadflow.lf.outerloop.OuterLoopStatus; import com.powsybl.openloadflow.network.LfHvdc; -import org.apache.commons.lang3.mutable.MutableInt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashMap; -import java.util.Map; - /** * @author Hadrien Godard {@literal } */ -public class AcEmulationOuterLoop implements AcOuterLoop { +public class AcEmulationOuterLoop + extends AbstractAcEmulationOuterLoop + implements AcOuterLoop { private static final Logger LOGGER = LoggerFactory.getLogger(AcEmulationOuterLoop.class); public static final String NAME = "AcEmulation"; - private static final int MAX_MODE_SWITCH = 2; - private static final int MAX_FEEDING_SIDE_SWITCH = 2; - - private static final class ContextData { - private final Map modeSwitchCount = new HashMap<>(); - private final Map feedingSideSwitchCount = new HashMap<>(); - - void incrementModeSwitchCount(String hvdcId) { - modeSwitchCount.computeIfAbsent(hvdcId, k -> new MutableInt(0)) - .increment(); - } - - void incrementFeedingSideSwitchCount(String hvdcId) { - feedingSideSwitchCount.computeIfAbsent(hvdcId, k -> new MutableInt(0)) - .increment(); - } - - int getModeSwitchCount(String hvdcId) { - MutableInt counter = modeSwitchCount.get(hvdcId); - if (counter == null) { - return 0; - } - return counter.getValue(); - } - - int getFeedingSideSwitchCount(String hvdcId) { - MutableInt counter = feedingSideSwitchCount.get(hvdcId); - if (counter == null) { - return 0; - } - return counter.getValue(); - } - } - - @Override - public void initialize(AcOuterLoopContext context) { - context.setData(new AcEmulationOuterLoop.ContextData()); - } - @Override public String getName() { return NAME; @@ -104,59 +68,6 @@ private boolean checkFeedingSide(LfHvdc hvdc, ContextData contextData) { return false; } - private boolean checkMode(LfHvdc hvdc, ContextData contextData) { - String hvdcId = hvdc.getId(); - LfHvdc.AcEmulationControl acEmulationControl = hvdc.getAcEmulationControl(); - - // Check for mode switch between FREE and BOUNDED - if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.FREE) { - // Check Pmax - if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { - if (hvdc.getP1().eval() > acEmulationControl.getPMaxFromCS1toCS2()) { - // Switch mode - LOGGER.trace("Bound Hvdc flow to Pmax from CS1 to CS2 for Hvdc: " + hvdcId); - contextData.incrementModeSwitchCount(hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); - if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { - LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS1 to CS2) for Hvdc: " + hvdcId); - } - return true; - } - } else { - if (hvdc.getP2().eval() > acEmulationControl.getPMaxFromCS2toCS1()) { - // Switch mode - LOGGER.trace("Bound Hvdc flow to Pmax from CS2 to CS1 for Hvdc: " + hvdcId); - contextData.incrementModeSwitchCount(hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); - if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { - LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS2 to CS1) for Hvdc: " + hvdcId); - } - return true; - } - } - } - - // Check for mode switch between BOUNDED and FREE - if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED) { - if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { - if (hvdc.getP1().eval() < acEmulationControl.getPMaxFromCS1toCS2()) { - // Switch mode - LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); - return true; - } - } else { - if (hvdc.getP2().eval() < acEmulationControl.getPMaxFromCS2toCS1()) { - // Switch mode - LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); - return true; - } - } - } - return false; - } - @Override public OuterLoopResult check(AcOuterLoopContext context, ReportNode reportNode) { OuterLoopStatus status = OuterLoopStatus.STABLE; @@ -174,7 +85,7 @@ public OuterLoopResult check(AcOuterLoopContext context, ReportNode reportNode) } // Second check for Pmax values - if (checkMode(hvdc, contextData)) { + if (checkMode(hvdc, contextData, LOGGER)) { status = OuterLoopStatus.UNSTABLE; } } diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java index 7a43e71e72..dbefa4d6b7 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java @@ -8,109 +8,28 @@ package com.powsybl.openloadflow.dc; import com.powsybl.commons.report.ReportNode; -import com.powsybl.iidm.network.TwoSides; import com.powsybl.openloadflow.dc.equations.DcEquationType; import com.powsybl.openloadflow.dc.equations.DcVariableType; -import com.powsybl.openloadflow.lf.outerloop.OuterLoop; +import com.powsybl.openloadflow.lf.outerloop.AbstractAcEmulationOuterLoop; import com.powsybl.openloadflow.lf.outerloop.OuterLoopResult; import com.powsybl.openloadflow.lf.outerloop.OuterLoopStatus; import com.powsybl.openloadflow.network.LfHvdc; -import org.apache.commons.lang3.mutable.MutableInt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashMap; -import java.util.Map; - /** * @author Hadrien Godard {@literal } */ -public class DcAcEmulationOuterLoop implements OuterLoop { +public class DcAcEmulationOuterLoop extends AbstractAcEmulationOuterLoop { private static final Logger LOGGER = LoggerFactory.getLogger(DcAcEmulationOuterLoop.class); public static final String NAME = "DcAcEmulation"; - private static final int MAX_MODE_SWITCH = 2; - - private static final class ContextData { - private final Map modeSwitchCount = new HashMap<>(); - - void incrementModeSwitchCount(String hvdcId) { - modeSwitchCount.computeIfAbsent(hvdcId, k -> new MutableInt(0)) - .increment(); - } - - int getModeSwitchCount(String hvdcId) { - MutableInt counter = modeSwitchCount.get(hvdcId); - if (counter == null) { - return 0; - } - return counter.getValue(); - } - } - - public void initialize(DcOuterLoopContext context) { - context.setData(new ContextData()); - } - @Override public String getName() { return NAME; } - private boolean checkMode(LfHvdc hvdc, ContextData contextData) { - String hvdcId = hvdc.getId(); - LfHvdc.AcEmulationControl acEmulationControl = hvdc.getAcEmulationControl(); - - // Check for mode switch between FREE and BOUNDED - if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.FREE) { - // Check Pmax - if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { - if (hvdc.getP1().eval() > acEmulationControl.getPMaxFromCS1toCS2()) { - // Switch mode - LOGGER.trace("Bound Hvdc flow to Pmax from CS1 to CS2 for Hvdc: " + hvdcId); - contextData.incrementModeSwitchCount(hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); - if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { - LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS1 to CS2) for Hvdc: " + hvdcId); - } - return true; - } - } else { - if (hvdc.getP2().eval() > acEmulationControl.getPMaxFromCS2toCS1()) { - // Switch mode - LOGGER.trace("Bound Hvdc flow to Pmax from CS2 to CS1 for Hvdc: " + hvdcId); - contextData.incrementModeSwitchCount(hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); - if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { - LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS2 to CS1) for Hvdc: " + hvdcId); - } - return true; - } - } - } - - // Check for mode switch between BOUNDED and FREE - if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED) { - if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { - if (hvdc.getP1().eval() < acEmulationControl.getPMaxFromCS1toCS2()) { - // Switch mode - LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); - return true; - } - } else { - if (hvdc.getP2().eval() < acEmulationControl.getPMaxFromCS2toCS1()) { - // Switch mode - LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); - return true; - } - } - } - return false; - } - @Override public OuterLoopResult check(DcOuterLoopContext context, ReportNode reportNode) { OuterLoopStatus status = OuterLoopStatus.STABLE; @@ -123,7 +42,7 @@ public OuterLoopResult check(DcOuterLoopContext context, ReportNode reportNode) String hvdcId = hvdc.getId(); if (contextData.getModeSwitchCount(hvdcId) < MAX_MODE_SWITCH) { // Check for Pmax values - if (checkMode(hvdc, contextData)) { + if (checkMode(hvdc, contextData, LOGGER)) { status = OuterLoopStatus.UNSTABLE; } } diff --git a/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAcEmulationOuterLoop.java new file mode 100644 index 0000000000..ea75dd9306 --- /dev/null +++ b/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAcEmulationOuterLoop.java @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2023, Coreso SA (https://www.coreso.eu/) and TSCNET Services GmbH (https://www.tscnet.eu/) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.openloadflow.lf.outerloop; + +/** + * @author Hadrien Godard {@literal } + */ + +import com.powsybl.iidm.network.TwoSides; +import com.powsybl.openloadflow.equations.Quantity; +import com.powsybl.openloadflow.lf.AbstractLoadFlowParameters; +import com.powsybl.openloadflow.lf.LoadFlowContext; +import com.powsybl.openloadflow.network.LfHvdc; +import org.apache.commons.lang3.mutable.MutableInt; +import org.slf4j.Logger; + +import java.util.HashMap; +import java.util.Map; + +public abstract class AbstractAcEmulationOuterLoop & Quantity, + E extends Enum & Quantity, + P extends AbstractLoadFlowParameters, + C extends LoadFlowContext, + O extends OuterLoopContext> implements OuterLoop { + + protected static final int MAX_MODE_SWITCH = 2; + protected static final int MAX_FEEDING_SIDE_SWITCH = 2; + + protected static final class ContextData { + private final Map modeSwitchCount = new HashMap<>(); + private final Map feedingSideSwitchCount = new HashMap<>(); + + public void incrementModeSwitchCount(String hvdcId) { + modeSwitchCount.computeIfAbsent(hvdcId, k -> new MutableInt(0)) + .increment(); + } + + public void incrementFeedingSideSwitchCount(String hvdcId) { + feedingSideSwitchCount.computeIfAbsent(hvdcId, k -> new MutableInt(0)) + .increment(); + } + + public int getModeSwitchCount(String hvdcId) { + MutableInt counter = modeSwitchCount.get(hvdcId); + if (counter == null) { + return 0; + } + return counter.getValue(); + } + + public int getFeedingSideSwitchCount(String hvdcId) { + MutableInt counter = feedingSideSwitchCount.get(hvdcId); + if (counter == null) { + return 0; + } + return counter.getValue(); + } + } + + public void initialize(OuterLoopContext context) { + context.setData(new ContextData()); + } + + protected boolean checkMode(LfHvdc hvdc, ContextData contextData, Logger logger) { + String hvdcId = hvdc.getId(); + LfHvdc.AcEmulationControl acEmulationControl = hvdc.getAcEmulationControl(); + + // Check for mode switch between FREE and BOUNDED + if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.FREE) { + // Check Pmax + if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { + if (hvdc.getP1().eval() > acEmulationControl.getPMaxFromCS1toCS2()) { + // Switch mode + logger.trace("Bound Hvdc flow to Pmax from CS1 to CS2 for Hvdc: " + hvdcId); + contextData.incrementModeSwitchCount(hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); + if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { + logger.debug("Two many mode switches (flow blocked to Pmax from CS1 to CS2) for Hvdc: " + hvdcId); + } + return true; + } + } else { + if (hvdc.getP2().eval() > acEmulationControl.getPMaxFromCS2toCS1()) { + // Switch mode + logger.trace("Bound Hvdc flow to Pmax from CS2 to CS1 for Hvdc: " + hvdcId); + contextData.incrementModeSwitchCount(hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); + if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { + logger.debug("Two many mode switches (flow blocked to Pmax from CS2 to CS1) for Hvdc: " + hvdcId); + } + return true; + } + } + } + + // Check for mode switch between BOUNDED and FREE + if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED) { + if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { + if (hvdc.getP1().eval() < acEmulationControl.getPMaxFromCS1toCS2()) { + // Switch mode + logger.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); + return true; + } + } else { + if (hvdc.getP2().eval() < acEmulationControl.getPMaxFromCS2toCS1()) { + // Switch mode + logger.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); + return true; + } + } + } + return false; + } + +} From 305a6a4844c7e7dec03bc7e92b9c6ee8ed3491df Mon Sep 17 00:00:00 2001 From: Hadrien Date: Fri, 14 Jun 2024 18:56:02 +0200 Subject: [PATCH 18/21] Test Signed-off-by: Hadrien --- .../ac/outerloop/AcEmulationOuterLoop.java | 55 +++++++++++++++- .../dc/DcAcEmulationOuterLoop.java | 46 ++++++++++++- ...vdcAcEmulationSide1DCFlowEquationTerm.java | 20 +++--- ...vdcAcEmulationSide2DCFlowEquationTerm.java | 20 +++--- .../AbstractAcEmulationOuterLoop.java | 65 ++++--------------- .../openloadflow/ac/AcLoadFlowVscTest.java | 2 +- .../openloadflow/dc/DcLoadFlowTest.java | 8 +++ .../network/HvdcNetworkFactory.java | 2 +- 8 files changed, 140 insertions(+), 78 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java index d71f87c5de..1687558604 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java @@ -68,6 +68,59 @@ private boolean checkFeedingSide(LfHvdc hvdc, ContextData contextData) { return false; } + private boolean checkMode(LfHvdc hvdc, ContextData contextData) { + String hvdcId = hvdc.getId(); + LfHvdc.AcEmulationControl acEmulationControl = hvdc.getAcEmulationControl(); + + // Check for mode switch between FREE and BOUNDED + if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.FREE) { + // Check Pmax + if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { + if (hvdc.getP1().eval() > acEmulationControl.getPMaxFromCS1toCS2()) { + // Switch mode + LOGGER.trace("Bound Hvdc flow to Pmax from CS1 to CS2 for Hvdc: " + hvdcId); + contextData.incrementModeSwitchCount(hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); + if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { + LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS1 to CS2) for Hvdc: " + hvdcId); + } + return true; + } + } else { + if (hvdc.getP2().eval() > acEmulationControl.getPMaxFromCS2toCS1()) { + // Switch mode + LOGGER.trace("Bound Hvdc flow to Pmax from CS2 to CS1 for Hvdc: " + hvdcId); + contextData.incrementModeSwitchCount(hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); + if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { + LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS2 to CS1) for Hvdc: " + hvdcId); + } + return true; + } + } + } + + // Check for mode switch between BOUNDED and FREE + if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED) { + if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { + if (computeRawP1(hvdc) < acEmulationControl.getPMaxFromCS1toCS2()) { + // Switch mode + LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); + return true; + } + } else { + if (computeRawP2(hvdc) < acEmulationControl.getPMaxFromCS2toCS1()) { + // Switch mode + LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); + return true; + } + } + } + return false; + } + @Override public OuterLoopResult check(AcOuterLoopContext context, ReportNode reportNode) { OuterLoopStatus status = OuterLoopStatus.STABLE; @@ -85,7 +138,7 @@ public OuterLoopResult check(AcOuterLoopContext context, ReportNode reportNode) } // Second check for Pmax values - if (checkMode(hvdc, contextData, LOGGER)) { + if (checkMode(hvdc, contextData)) { status = OuterLoopStatus.UNSTABLE; } } diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java index dbefa4d6b7..78c97f3d14 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java @@ -8,6 +8,7 @@ package com.powsybl.openloadflow.dc; import com.powsybl.commons.report.ReportNode; +import com.powsybl.iidm.network.TwoSides; import com.powsybl.openloadflow.dc.equations.DcEquationType; import com.powsybl.openloadflow.dc.equations.DcVariableType; import com.powsybl.openloadflow.lf.outerloop.AbstractAcEmulationOuterLoop; @@ -30,6 +31,49 @@ public String getName() { return NAME; } + private boolean checkMode(LfHvdc hvdc, ContextData contextData) { + String hvdcId = hvdc.getId(); + LfHvdc.AcEmulationControl acEmulationControl = hvdc.getAcEmulationControl(); + + // Check for mode switch between FREE and BOUNDED + if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.FREE) { + // Check Pmax + if (hvdc.getP1().eval() > acEmulationControl.getPMaxFromCS1toCS2()) { + acEmulationControl.setFeedingSide(TwoSides.ONE); + // Switch mode + LOGGER.trace("Bound Hvdc flow to Pmax from CS1 to CS2 for Hvdc: " + hvdcId); + contextData.incrementModeSwitchCount(hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); + if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { + LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS1 to CS2) for Hvdc: " + hvdcId); + } + return true; + } + if (hvdc.getP2().eval() > acEmulationControl.getPMaxFromCS2toCS1()) { + acEmulationControl.setFeedingSide(TwoSides.TWO); + // Switch mode + LOGGER.trace("Bound Hvdc flow to Pmax from CS2 to CS1 for Hvdc: " + hvdcId); + contextData.incrementModeSwitchCount(hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); + if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { + LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS2 to CS1) for Hvdc: " + hvdcId); + } + return true; + } + } + + // Check for mode switch between BOUNDED and FREE + if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED) { + if (computeRawP1(hvdc) < acEmulationControl.getPMaxFromCS1toCS2() && computeRawP2(hvdc) < acEmulationControl.getPMaxFromCS2toCS1()) { + // Switch mode + LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); + acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); + return true; + } + } + return false; + } + @Override public OuterLoopResult check(DcOuterLoopContext context, ReportNode reportNode) { OuterLoopStatus status = OuterLoopStatus.STABLE; @@ -42,7 +86,7 @@ public OuterLoopResult check(DcOuterLoopContext context, ReportNode reportNode) String hvdcId = hvdc.getId(); if (contextData.getModeSwitchCount(hvdcId) < MAX_MODE_SWITCH) { // Check for Pmax values - if (checkMode(hvdc, contextData, LOGGER)) { + if (checkMode(hvdc, contextData)) { status = OuterLoopStatus.UNSTABLE; } } diff --git a/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide1DCFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide1DCFlowEquationTerm.java index 5709410da2..6dc88fdd5a 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide1DCFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide1DCFlowEquationTerm.java @@ -29,11 +29,11 @@ protected String getName() { @Override public double eval() { - return switch (element.getAcEmulationControl().getAcEmulationStatus()) { - case FREE -> rawP(p0, k, ph1(), ph2()); - case BOUNDED -> element.getAcEmulationControl().getFeedingSide() == TwoSides.ONE ? pMaxFromCS1toCS2 : -pMaxFromCS2toCS1; - default -> 0; - }; + if (element.getAcEmulationControl().getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED) { + return element.getAcEmulationControl().getFeedingSide() == TwoSides.ONE ? pMaxFromCS1toCS2 : -pMaxFromCS2toCS1; + } else { // free + return rawP(p0, k, ph1(), ph2()); + } } @Override @@ -58,10 +58,10 @@ public boolean hasRhs() { @Override public double rhs() { - return switch (element.getAcEmulationControl().getAcEmulationStatus()) { - case FREE -> p0; - case BOUNDED -> element.getAcEmulationControl().getFeedingSide() == TwoSides.ONE ? pMaxFromCS1toCS2 : -pMaxFromCS2toCS1; - default -> 0; - }; + if (element.getAcEmulationControl().getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED) { + return element.getAcEmulationControl().getFeedingSide() == TwoSides.ONE ? pMaxFromCS1toCS2 : -pMaxFromCS2toCS1; + } else { // free + return p0; + } } } diff --git a/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide2DCFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide2DCFlowEquationTerm.java index 03799bba15..074fd430aa 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide2DCFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/dc/equations/HvdcAcEmulationSide2DCFlowEquationTerm.java @@ -29,11 +29,11 @@ protected String getName() { @Override public double eval() { - return switch (element.getAcEmulationControl().getAcEmulationStatus()) { - case FREE -> -rawP(p0, k, ph1(), ph2()); - case BOUNDED -> element.getAcEmulationControl().getFeedingSide() == TwoSides.TWO ? pMaxFromCS2toCS1 : -pMaxFromCS1toCS2; - default -> 0; - }; + if (element.getAcEmulationControl().getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED) { + return element.getAcEmulationControl().getFeedingSide() == TwoSides.TWO ? pMaxFromCS2toCS1 : -pMaxFromCS1toCS2; + } else { // free + return -rawP(p0, k, ph1(), ph2()); + } } @Override @@ -58,10 +58,10 @@ public boolean hasRhs() { @Override public double rhs() { - return switch (element.getAcEmulationControl().getAcEmulationStatus()) { - case FREE -> -p0; - case BOUNDED -> element.getAcEmulationControl().getFeedingSide() == TwoSides.TWO ? pMaxFromCS2toCS1 : -pMaxFromCS1toCS2; - default -> 0; - }; + if (element.getAcEmulationControl().getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED) { + return element.getAcEmulationControl().getFeedingSide() == TwoSides.TWO ? pMaxFromCS2toCS1 : -pMaxFromCS1toCS2; + } else { // free + return -p0; + } } } diff --git a/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAcEmulationOuterLoop.java index ea75dd9306..55d44eda52 100644 --- a/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAcEmulationOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAcEmulationOuterLoop.java @@ -11,13 +11,11 @@ * @author Hadrien Godard {@literal } */ -import com.powsybl.iidm.network.TwoSides; import com.powsybl.openloadflow.equations.Quantity; import com.powsybl.openloadflow.lf.AbstractLoadFlowParameters; import com.powsybl.openloadflow.lf.LoadFlowContext; import com.powsybl.openloadflow.network.LfHvdc; import org.apache.commons.lang3.mutable.MutableInt; -import org.slf4j.Logger; import java.util.HashMap; import java.util.Map; @@ -62,61 +60,20 @@ public int getFeedingSideSwitchCount(String hvdcId) { } } - public void initialize(OuterLoopContext context) { - context.setData(new ContextData()); + protected double computeRawP1(LfHvdc hvdc) { + double ph1 = hvdc.getBus1().getAngle(); + double ph2 = hvdc.getBus1().getAngle(); + double p0 = hvdc.getAcEmulationControl().getP0(); + double k = hvdc.getAcEmulationControl().getDroop(); + return p0 + k * (ph1 - ph2); } - protected boolean checkMode(LfHvdc hvdc, ContextData contextData, Logger logger) { - String hvdcId = hvdc.getId(); - LfHvdc.AcEmulationControl acEmulationControl = hvdc.getAcEmulationControl(); - - // Check for mode switch between FREE and BOUNDED - if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.FREE) { - // Check Pmax - if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { - if (hvdc.getP1().eval() > acEmulationControl.getPMaxFromCS1toCS2()) { - // Switch mode - logger.trace("Bound Hvdc flow to Pmax from CS1 to CS2 for Hvdc: " + hvdcId); - contextData.incrementModeSwitchCount(hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); - if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { - logger.debug("Two many mode switches (flow blocked to Pmax from CS1 to CS2) for Hvdc: " + hvdcId); - } - return true; - } - } else { - if (hvdc.getP2().eval() > acEmulationControl.getPMaxFromCS2toCS1()) { - // Switch mode - logger.trace("Bound Hvdc flow to Pmax from CS2 to CS1 for Hvdc: " + hvdcId); - contextData.incrementModeSwitchCount(hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); - if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { - logger.debug("Two many mode switches (flow blocked to Pmax from CS2 to CS1) for Hvdc: " + hvdcId); - } - return true; - } - } - } + protected double computeRawP2(LfHvdc hvdc) { + return -computeRawP1(hvdc); + } - // Check for mode switch between BOUNDED and FREE - if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED) { - if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { - if (hvdc.getP1().eval() < acEmulationControl.getPMaxFromCS1toCS2()) { - // Switch mode - logger.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); - return true; - } - } else { - if (hvdc.getP2().eval() < acEmulationControl.getPMaxFromCS2toCS1()) { - // Switch mode - logger.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); - return true; - } - } - } - return false; + public void initialize(OuterLoopContext context) { + context.setData(new ContextData()); } } diff --git a/src/test/java/com/powsybl/openloadflow/ac/AcLoadFlowVscTest.java b/src/test/java/com/powsybl/openloadflow/ac/AcLoadFlowVscTest.java index 2620a9b960..0cc6679a6f 100644 --- a/src/test/java/com/powsybl/openloadflow/ac/AcLoadFlowVscTest.java +++ b/src/test/java/com/powsybl/openloadflow/ac/AcLoadFlowVscTest.java @@ -275,7 +275,7 @@ void testHvdcPowerAcEmulation() { @Test void testHvdcDirectionChangeAcEmulation() { - Network network = HvdcNetworkFactory.createHvdcInAcEmulationInSymetricNetwork(); + Network network = HvdcNetworkFactory.createHvdcInAcEmulationInSymmetricNetwork(); LoadFlow.Runner loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(new DenseMatrixFactory())); LoadFlowResult result = loadFlowRunner.run(network, new LoadFlowParameters()); assertTrue(result.isFullyConverged()); diff --git a/src/test/java/com/powsybl/openloadflow/dc/DcLoadFlowTest.java b/src/test/java/com/powsybl/openloadflow/dc/DcLoadFlowTest.java index bd4a5f586d..b0657cbe0a 100644 --- a/src/test/java/com/powsybl/openloadflow/dc/DcLoadFlowTest.java +++ b/src/test/java/com/powsybl/openloadflow/dc/DcLoadFlowTest.java @@ -391,4 +391,12 @@ void testDcApproxIgnoreG() { assertEquals(307.436, line2.getTerminal1().getP(), 0.01); assertEquals(-307.436, line2.getTerminal2().getP(), 0.01); } + + @Test + void testDcAcEmulation() { + Network network = HvdcNetworkFactory.createHvdcInAcEmulationInSymmetricNetwork(); + network.getHvdcLine("hvdc12").setMaxP(2.); + loadFlowRunner.run(network, parameters); + int a = 0; + } } diff --git a/src/test/java/com/powsybl/openloadflow/network/HvdcNetworkFactory.java b/src/test/java/com/powsybl/openloadflow/network/HvdcNetworkFactory.java index da5f0cae3b..6ee4f715f9 100644 --- a/src/test/java/com/powsybl/openloadflow/network/HvdcNetworkFactory.java +++ b/src/test/java/com/powsybl/openloadflow/network/HvdcNetworkFactory.java @@ -582,7 +582,7 @@ public static Network createWithHvdcInAcEmulation() { * Initially, g1 is on. g2 is off. * @return */ - public static Network createHvdcInAcEmulationInSymetricNetwork() { + public static Network createHvdcInAcEmulationInSymmetricNetwork() { Network network = Network.create("test", "code"); Bus b1 = createBus(network, "b1"); Bus b2 = createBus(network, "b2"); From 5d43d951a7148c56d48e12b89da1f714e50349c2 Mon Sep 17 00:00:00 2001 From: Hadrien Date: Fri, 14 Jun 2024 20:15:49 +0200 Subject: [PATCH 19/21] Listeners Signed-off-by: Hadrien --- .../ac/outerloop/AcEmulationOuterLoop.java | 16 ++++++++-------- .../openloadflow/dc/DcAcEmulationOuterLoop.java | 10 +++++----- .../openloadflow/equations/TargetVector.java | 11 +++++++++++ .../outerloop/AbstractAcEmulationOuterLoop.java | 2 +- .../network/AbstractLfNetworkListener.java | 10 ++++++++++ .../powsybl/openloadflow/network/LfHvdc.java | 4 ++++ .../openloadflow/network/LfNetworkListener.java | 4 ++++ .../network/LfNetworkListenerTracer.java | 12 ++++++++++++ .../openloadflow/network/impl/LfHvdcImpl.java | 17 +++++++++++++++++ .../powsybl/openloadflow/dc/DcLoadFlowTest.java | 3 ++- 10 files changed, 74 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java index 1687558604..a72edb1813 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java @@ -45,10 +45,10 @@ private boolean checkFeedingSide(LfHvdc hvdc, ContextData contextData) { // Switch feeding side LOGGER.trace("Switching feeding side from One to Two for Hvdc: " + hvdcId); contextData.incrementFeedingSideSwitchCount(hvdcId); - acEmulationControl.setFeedingSide(TwoSides.TWO); + hvdc.updateFeedingSide(TwoSides.TWO); if (contextData.getFeedingSideSwitchCount(hvdcId) == MAX_FEEDING_SIDE_SWITCH) { LOGGER.debug("Two many feeding side switches (flow blocked to 0 MW) for Hvdc: " + hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.NULL); + hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.NULL); } return true; } @@ -57,10 +57,10 @@ private boolean checkFeedingSide(LfHvdc hvdc, ContextData contextData) { // Switch feeding side LOGGER.trace("Switching feeding side from Two to One for Hvdc: " + hvdcId); contextData.incrementFeedingSideSwitchCount(hvdcId); - acEmulationControl.setFeedingSide(TwoSides.ONE); + hvdc.updateFeedingSide(TwoSides.ONE); if (contextData.getFeedingSideSwitchCount(hvdcId) == MAX_FEEDING_SIDE_SWITCH) { LOGGER.debug("Two many feeding side switches (flow blocked to 0 MW) for Hvdc: " + hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.NULL); + hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.NULL); } return true; } @@ -80,7 +80,7 @@ private boolean checkMode(LfHvdc hvdc, ContextData contextData) { // Switch mode LOGGER.trace("Bound Hvdc flow to Pmax from CS1 to CS2 for Hvdc: " + hvdcId); contextData.incrementModeSwitchCount(hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); + hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS1 to CS2) for Hvdc: " + hvdcId); } @@ -91,7 +91,7 @@ private boolean checkMode(LfHvdc hvdc, ContextData contextData) { // Switch mode LOGGER.trace("Bound Hvdc flow to Pmax from CS2 to CS1 for Hvdc: " + hvdcId); contextData.incrementModeSwitchCount(hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); + hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS2 to CS1) for Hvdc: " + hvdcId); } @@ -106,14 +106,14 @@ private boolean checkMode(LfHvdc hvdc, ContextData contextData) { if (computeRawP1(hvdc) < acEmulationControl.getPMaxFromCS1toCS2()) { // Switch mode LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); + hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); return true; } } else { if (computeRawP2(hvdc) < acEmulationControl.getPMaxFromCS2toCS1()) { // Switch mode LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); + hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); return true; } } diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java index 78c97f3d14..9f5300ae45 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java @@ -39,22 +39,22 @@ private boolean checkMode(LfHvdc hvdc, ContextData contextData) { if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.FREE) { // Check Pmax if (hvdc.getP1().eval() > acEmulationControl.getPMaxFromCS1toCS2()) { - acEmulationControl.setFeedingSide(TwoSides.ONE); + hvdc.updateFeedingSide(TwoSides.ONE); // Switch mode LOGGER.trace("Bound Hvdc flow to Pmax from CS1 to CS2 for Hvdc: " + hvdcId); contextData.incrementModeSwitchCount(hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); + hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS1 to CS2) for Hvdc: " + hvdcId); } return true; } if (hvdc.getP2().eval() > acEmulationControl.getPMaxFromCS2toCS1()) { - acEmulationControl.setFeedingSide(TwoSides.TWO); + hvdc.updateFeedingSide(TwoSides.TWO); // Switch mode LOGGER.trace("Bound Hvdc flow to Pmax from CS2 to CS1 for Hvdc: " + hvdcId); contextData.incrementModeSwitchCount(hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); + hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS2 to CS1) for Hvdc: " + hvdcId); } @@ -67,7 +67,7 @@ private boolean checkMode(LfHvdc hvdc, ContextData contextData) { if (computeRawP1(hvdc) < acEmulationControl.getPMaxFromCS1toCS2() && computeRawP2(hvdc) < acEmulationControl.getPMaxFromCS2toCS1()) { // Switch mode LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); - acEmulationControl.setAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); + hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); return true; } } diff --git a/src/main/java/com/powsybl/openloadflow/equations/TargetVector.java b/src/main/java/com/powsybl/openloadflow/equations/TargetVector.java index 3632ac3f37..2bb8328fcb 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/TargetVector.java +++ b/src/main/java/com/powsybl/openloadflow/equations/TargetVector.java @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.equations; +import com.powsybl.iidm.network.TwoSides; import com.powsybl.openloadflow.network.*; import java.util.List; @@ -77,6 +78,16 @@ public void onDisableChange(LfElement element, boolean disabled) { } } } + + @Override + public void onAcEmulationStatusChange(LfHvdc hvdc, LfHvdc.AcEmulationControl.AcEmulationStatus acEmulationStatus) { + invalidateValues(); + } + + @Override + public void onAcEmulationFeedingSideChange(LfHvdc hvdc, TwoSides side) { + invalidateValues(); + } }; public TargetVector(LfNetwork network, EquationSystem equationSystem, Initializer initializer) { diff --git a/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAcEmulationOuterLoop.java index 55d44eda52..b9514f5c9f 100644 --- a/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAcEmulationOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAcEmulationOuterLoop.java @@ -62,7 +62,7 @@ public int getFeedingSideSwitchCount(String hvdcId) { protected double computeRawP1(LfHvdc hvdc) { double ph1 = hvdc.getBus1().getAngle(); - double ph2 = hvdc.getBus1().getAngle(); + double ph2 = hvdc.getBus2().getAngle(); double p0 = hvdc.getAcEmulationControl().getP0(); double k = hvdc.getAcEmulationControl().getDroop(); return p0 + k * (ph1 - ph2); diff --git a/src/main/java/com/powsybl/openloadflow/network/AbstractLfNetworkListener.java b/src/main/java/com/powsybl/openloadflow/network/AbstractLfNetworkListener.java index e4aa63bde3..f4ce6da549 100644 --- a/src/main/java/com/powsybl/openloadflow/network/AbstractLfNetworkListener.java +++ b/src/main/java/com/powsybl/openloadflow/network/AbstractLfNetworkListener.java @@ -115,4 +115,14 @@ public void onSlackBusChange(LfBus bus, boolean slack) { public void onReferenceBusChange(LfBus bus, boolean reference) { // empty } + + @Override + public void onAcEmulationStatusChange(LfHvdc hvdc, LfHvdc.AcEmulationControl.AcEmulationStatus acEmulationStatus) { + // empty + } + + @Override + public void onAcEmulationFeedingSideChange(LfHvdc hvdc, TwoSides side) { + // empty + } } diff --git a/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java b/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java index bde4c39e7f..6f6530be6f 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java @@ -98,5 +98,9 @@ public void setFeedingSide(TwoSides side) { AcEmulationControl getAcEmulationControl(); + void updateAcEmulationStatus(AcEmulationControl.AcEmulationStatus acEmulationStatus); + + void updateFeedingSide(TwoSides side); + void updateState(); } diff --git a/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java b/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java index d6faf9a32b..8dcda94a12 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java @@ -55,4 +55,8 @@ public interface LfNetworkListener { void onSlackBusChange(LfBus bus, boolean slack); void onReferenceBusChange(LfBus bus, boolean reference); + + void onAcEmulationStatusChange(LfHvdc hvdc, LfHvdc.AcEmulationControl.AcEmulationStatus acEmulationStatus); + + void onAcEmulationFeedingSideChange(LfHvdc hvdc, TwoSides side); } diff --git a/src/main/java/com/powsybl/openloadflow/network/LfNetworkListenerTracer.java b/src/main/java/com/powsybl/openloadflow/network/LfNetworkListenerTracer.java index ee7eb7d54a..8af09f218e 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfNetworkListenerTracer.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfNetworkListenerTracer.java @@ -167,4 +167,16 @@ public void onReferenceBusChange(LfBus bus, boolean reference) { LOGGER.trace("onReferenceBusChange(bus={}, reference={})", bus, reference); delegate.onReferenceBusChange(bus, reference); } + + @Override + public void onAcEmulationStatusChange(LfHvdc hvdc, LfHvdc.AcEmulationControl.AcEmulationStatus acEmulationStatus) { + LOGGER.trace("onAcEmulationStatusChange(hvdc={}, status={})", hvdc, acEmulationStatus); + delegate.onAcEmulationStatusChange(hvdc, acEmulationStatus); + } + + @Override + public void onAcEmulationFeedingSideChange(LfHvdc hvdc, TwoSides side) { + LOGGER.trace("onAcEmulationFeedingSideChange(hvdc={}, side={})", hvdc, side); + delegate.onAcEmulationFeedingSideChange(hvdc, side); + } } diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java index 1f717cdfb9..81d4e7f997 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java @@ -8,6 +8,7 @@ package com.powsybl.openloadflow.network.impl; import com.powsybl.iidm.network.HvdcLine; +import com.powsybl.iidm.network.TwoSides; import com.powsybl.iidm.network.extensions.HvdcAngleDroopActivePowerControl; import com.powsybl.iidm.network.extensions.HvdcOperatorActivePowerRange; import com.powsybl.openloadflow.network.*; @@ -148,6 +149,22 @@ public AcEmulationControl getAcEmulationControl() { return acEmulationControl; } + @Override + public void updateAcEmulationStatus(AcEmulationControl.AcEmulationStatus acEmulationStatus) { + acEmulationControl.setAcEmulationStatus(acEmulationStatus); + for (LfNetworkListener listener : network.getListeners()) { + listener.onAcEmulationStatusChange(this, acEmulationStatus); + } + } + + @Override + public void updateFeedingSide(TwoSides side) { + acEmulationControl.setFeedingSide(side); + for (LfNetworkListener listener : network.getListeners()) { + listener.onAcEmulationFeedingSideChange(this, side); + } + } + @Override public void updateState() { if (acEmulation) { diff --git a/src/test/java/com/powsybl/openloadflow/dc/DcLoadFlowTest.java b/src/test/java/com/powsybl/openloadflow/dc/DcLoadFlowTest.java index b0657cbe0a..c77ff61062 100644 --- a/src/test/java/com/powsybl/openloadflow/dc/DcLoadFlowTest.java +++ b/src/test/java/com/powsybl/openloadflow/dc/DcLoadFlowTest.java @@ -397,6 +397,7 @@ void testDcAcEmulation() { Network network = HvdcNetworkFactory.createHvdcInAcEmulationInSymmetricNetwork(); network.getHvdcLine("hvdc12").setMaxP(2.); loadFlowRunner.run(network, parameters); - int a = 0; + assertEquals(2.0, network.getHvdcLine("hvdc12").getConverterStation1().getTerminal().getP(), 0.01); + assertEquals(1.0, network.getLine("l12").getTerminal1().getP(), 0.01); } } From d295f9cea69c229ff17264e287653b19457ae260 Mon Sep 17 00:00:00 2001 From: Hadrien Date: Fri, 14 Jun 2024 21:00:34 +0200 Subject: [PATCH 20/21] New test Signed-off-by: Hadrien --- .../ac/outerloop/AcEmulationOuterLoop.java | 20 +++++------ .../dc/DcAcEmulationOuterLoop.java | 10 +++--- .../openloadflow/dc/DcLoadFlowTest.java | 8 ++--- .../network/HvdcNetworkFactory.java | 33 +++++++++++++++++++ 4 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java index a72edb1813..a11dcda3d4 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java @@ -43,11 +43,11 @@ private boolean checkFeedingSide(LfHvdc hvdc, ContextData contextData) { if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { if (hvdc.getP1().eval() < 0) { // Switch feeding side - LOGGER.trace("Switching feeding side from One to Two for Hvdc: " + hvdcId); + LOGGER.trace("Switching feeding side from One to Two for Hvdc: {}", hvdcId); contextData.incrementFeedingSideSwitchCount(hvdcId); hvdc.updateFeedingSide(TwoSides.TWO); if (contextData.getFeedingSideSwitchCount(hvdcId) == MAX_FEEDING_SIDE_SWITCH) { - LOGGER.debug("Two many feeding side switches (flow blocked to 0 MW) for Hvdc: " + hvdcId); + LOGGER.debug("Two many feeding side switches (flow blocked to 0 MW) for Hvdc: {}", hvdcId); hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.NULL); } return true; @@ -55,11 +55,11 @@ private boolean checkFeedingSide(LfHvdc hvdc, ContextData contextData) { } else { if (hvdc.getP2().eval() < 0) { // Switch feeding side - LOGGER.trace("Switching feeding side from Two to One for Hvdc: " + hvdcId); + LOGGER.trace("Switching feeding side from Two to One for Hvdc: {}", hvdcId); contextData.incrementFeedingSideSwitchCount(hvdcId); hvdc.updateFeedingSide(TwoSides.ONE); if (contextData.getFeedingSideSwitchCount(hvdcId) == MAX_FEEDING_SIDE_SWITCH) { - LOGGER.debug("Two many feeding side switches (flow blocked to 0 MW) for Hvdc: " + hvdcId); + LOGGER.debug("Two many feeding side switches (flow blocked to 0 MW) for Hvdc: {}", hvdcId); hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.NULL); } return true; @@ -78,22 +78,22 @@ private boolean checkMode(LfHvdc hvdc, ContextData contextData) { if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { if (hvdc.getP1().eval() > acEmulationControl.getPMaxFromCS1toCS2()) { // Switch mode - LOGGER.trace("Bound Hvdc flow to Pmax from CS1 to CS2 for Hvdc: " + hvdcId); + LOGGER.trace("Bound Hvdc flow to Pmax from CS1 to CS2 for Hvdc: {}", hvdcId); contextData.incrementModeSwitchCount(hvdcId); hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { - LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS1 to CS2) for Hvdc: " + hvdcId); + LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS1 to CS2) for Hvdc: {}", hvdcId); } return true; } } else { if (hvdc.getP2().eval() > acEmulationControl.getPMaxFromCS2toCS1()) { // Switch mode - LOGGER.trace("Bound Hvdc flow to Pmax from CS2 to CS1 for Hvdc: " + hvdcId); + LOGGER.trace("Bound Hvdc flow to Pmax from CS2 to CS1 for Hvdc: {}", hvdcId); contextData.incrementModeSwitchCount(hvdcId); hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { - LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS2 to CS1) for Hvdc: " + hvdcId); + LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS2 to CS1) for Hvdc: {}", hvdcId); } return true; } @@ -105,14 +105,14 @@ private boolean checkMode(LfHvdc hvdc, ContextData contextData) { if (acEmulationControl.getFeedingSide() == TwoSides.ONE) { if (computeRawP1(hvdc) < acEmulationControl.getPMaxFromCS1toCS2()) { // Switch mode - LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); + LOGGER.trace("Set free the Ac Emulation mode for Hvdc: {}", hvdcId); hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); return true; } } else { if (computeRawP2(hvdc) < acEmulationControl.getPMaxFromCS2toCS1()) { // Switch mode - LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); + LOGGER.trace("Set free the Ac Emulation mode for Hvdc: {}", hvdcId); hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); return true; } diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java index 9f5300ae45..e5eca29c60 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java @@ -41,22 +41,22 @@ private boolean checkMode(LfHvdc hvdc, ContextData contextData) { if (hvdc.getP1().eval() > acEmulationControl.getPMaxFromCS1toCS2()) { hvdc.updateFeedingSide(TwoSides.ONE); // Switch mode - LOGGER.trace("Bound Hvdc flow to Pmax from CS1 to CS2 for Hvdc: " + hvdcId); + LOGGER.trace("Bound Hvdc flow to Pmax from CS1 to CS2 for Hvdc: {}", hvdcId); contextData.incrementModeSwitchCount(hvdcId); hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { - LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS1 to CS2) for Hvdc: " + hvdcId); + LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS1 to CS2) for Hvdc: {}", hvdcId); } return true; } if (hvdc.getP2().eval() > acEmulationControl.getPMaxFromCS2toCS1()) { hvdc.updateFeedingSide(TwoSides.TWO); // Switch mode - LOGGER.trace("Bound Hvdc flow to Pmax from CS2 to CS1 for Hvdc: " + hvdcId); + LOGGER.trace("Bound Hvdc flow to Pmax from CS2 to CS1 for Hvdc: {}", hvdcId); contextData.incrementModeSwitchCount(hvdcId); hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED); if (contextData.getModeSwitchCount(hvdcId) == MAX_MODE_SWITCH) { - LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS2 to CS1) for Hvdc: " + hvdcId); + LOGGER.debug("Two many mode switches (flow blocked to Pmax from CS2 to CS1) for Hvdc: {}", hvdcId); } return true; } @@ -66,7 +66,7 @@ private boolean checkMode(LfHvdc hvdc, ContextData contextData) { if (acEmulationControl.getAcEmulationStatus() == LfHvdc.AcEmulationControl.AcEmulationStatus.BOUNDED) { if (computeRawP1(hvdc) < acEmulationControl.getPMaxFromCS1toCS2() && computeRawP2(hvdc) < acEmulationControl.getPMaxFromCS2toCS1()) { // Switch mode - LOGGER.trace("Set free the Ac Emulation mode for Hvdc: " + hvdcId); + LOGGER.trace("Set free the Ac Emulation mode for Hvdc: {}", hvdcId); hvdc.updateAcEmulationStatus(LfHvdc.AcEmulationControl.AcEmulationStatus.FREE); return true; } diff --git a/src/test/java/com/powsybl/openloadflow/dc/DcLoadFlowTest.java b/src/test/java/com/powsybl/openloadflow/dc/DcLoadFlowTest.java index c77ff61062..d39cf4bce8 100644 --- a/src/test/java/com/powsybl/openloadflow/dc/DcLoadFlowTest.java +++ b/src/test/java/com/powsybl/openloadflow/dc/DcLoadFlowTest.java @@ -394,10 +394,10 @@ void testDcApproxIgnoreG() { @Test void testDcAcEmulation() { - Network network = HvdcNetworkFactory.createHvdcInAcEmulationInSymmetricNetwork(); - network.getHvdcLine("hvdc12").setMaxP(2.); + Network network = HvdcNetworkFactory.createHvdcInAcEmulation3BusesNetwork(); + network.getHvdcLine("hvdc23").setMaxP(2.); loadFlowRunner.run(network, parameters); - assertEquals(2.0, network.getHvdcLine("hvdc12").getConverterStation1().getTerminal().getP(), 0.01); - assertEquals(1.0, network.getLine("l12").getTerminal1().getP(), 0.01); + assertEquals(2.0, network.getHvdcLine("hvdc23").getConverterStation1().getTerminal().getP(), 0.01); + assertEquals(1.0, network.getLine("l13").getTerminal1().getP(), 0.01); } } diff --git a/src/test/java/com/powsybl/openloadflow/network/HvdcNetworkFactory.java b/src/test/java/com/powsybl/openloadflow/network/HvdcNetworkFactory.java index 6ee4f715f9..09efe67a8b 100644 --- a/src/test/java/com/powsybl/openloadflow/network/HvdcNetworkFactory.java +++ b/src/test/java/com/powsybl/openloadflow/network/HvdcNetworkFactory.java @@ -603,6 +603,39 @@ public static Network createHvdcInAcEmulationInSymmetricNetwork() { return network; } + /** + * ------------l12--------------- + * | | + * g1--b1--b2---vsc1--hvdc12--vsc2----b3--g3 + * | | + * l1 l3 + * + * Initially, g1 is on. g2 is off. + * @return + */ + public static Network createHvdcInAcEmulation3BusesNetwork() { + Network network = Network.create("test", "code"); + Bus b1 = createBus(network, "b1"); + Bus b2 = createBus(network, "b2"); + Bus b3 = createBus(network, "b3"); + createGenerator(b1, "g1", 5).setMaxP(10); + createGenerator(b3, "g3", 0).setMaxP(10); + createLoad(b1, "l1", 3); + createLoad(b3, "l3", 3); + createLine(network, b1, b2, "l12", 0.001f); + createLine(network, b1, b3, "l13", 0.1f); + + HvdcConverterStation cs1 = createVsc(b2, "cs2", 1.2d, 0d); + HvdcConverterStation cs2 = createVsc(b3, "cs3", 1.2d, 0d); + createHvdcLine(network, "hvdc23", cs1, cs2, 400, 0.1, 2) + .newExtension(HvdcAngleDroopActivePowerControlAdder.class) + .withDroop(1) + .withP0(0) + .withEnabled(true) + .add(); + return network; + } + /** *
      *     g1 - b1 -- l12 -- b2 -- hvdc23 -- b3 -- l34 -- b4 - l4

From 198c4e166659afce2388932823d785e444f021f2 Mon Sep 17 00:00:00 2001
From: Hadrien 
Date: Mon, 24 Jun 2024 15:42:28 +0200
Subject: [PATCH 21/21] Rename

Signed-off-by: Hadrien 
---
 .../openloadflow/AbstractAcOuterLoopConfig.java  |  4 ++--
 .../openloadflow/DefaultAcOuterLoopConfig.java   |  4 ++--
 .../openloadflow/ExplicitAcOuterLoopConfig.java  |  4 ++--
 ...Loop.java => AcHvdcAcEmulationOuterLoop.java} | 10 +++++-----
 ...Loop.java => DcHvdcAcEmulationOuterLoop.java} |  8 ++++----
 .../openloadflow/dc/DcLoadFlowEngine.java        |  4 ++--
 .../openloadflow/equations/TargetVector.java     |  4 ++--
 ...ava => AbstractHvdcAcEmulationOuterLoop.java} |  2 +-
 .../network/AbstractLfNetworkListener.java       |  4 ++--
 .../openloadflow/network/LfNetworkListener.java  |  4 ++--
 .../network/LfNetworkListenerTracer.java         | 12 ++++++------
 .../openloadflow/network/impl/LfHvdcImpl.java    |  4 ++--
 .../openloadflow/OpenLoadFlowParametersTest.java |  4 ++--
 .../openloadflow/OpenLoadFlowProviderTest.java   |  2 +-
 ...trollerShuntAlreadyInVoltageControlReport.txt |  4 ++--
 .../detailedNrReportSecurityAnalysis.txt         |  6 +++---
 src/test/resources/esgTutoReport.txt             |  6 +++---
 .../esgTutoReportDetailedNrReportLf.txt          |  4 ++--
 .../esgTutoReportDetailedNrReportSensi.txt       |  2 +-
 .../generatorVoltageControlDiscarded.txt         |  2 +-
 ...ectedToSameBusNotControllingSameBusReport.txt |  2 +-
 .../multipleConnectedComponentsAcReport.txt      |  2 +-
 .../multipleConnectedComponentsDcReport.txt      |  4 ++--
 src/test/resources/saReport.txt                  | 16 ++++++++--------
 .../resources/saReportOperatorStrategies.txt     | 14 +++++++-------
 ...GeneratorRemoteReactivePowerControlReport.txt |  2 +-
 .../resources/shuntVoltageControlDiscarded.txt   |  4 ++--
 .../shuntVoltageControlOuterLoopReport.txt       |  4 ++--
 ...formerReactivePowerControlOuterLoopReport.txt |  6 +++---
 .../transformerVoltageControlDiscarded.txt       |  4 ++--
 30 files changed, 76 insertions(+), 76 deletions(-)
 rename src/main/java/com/powsybl/openloadflow/ac/outerloop/{AcEmulationOuterLoop.java => AcHvdcAcEmulationOuterLoop.java} (95%)
 rename src/main/java/com/powsybl/openloadflow/dc/{DcAcEmulationOuterLoop.java => DcHvdcAcEmulationOuterLoop.java} (92%)
 rename src/main/java/com/powsybl/openloadflow/lf/outerloop/{AbstractAcEmulationOuterLoop.java => AbstractHvdcAcEmulationOuterLoop.java} (97%)

diff --git a/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java b/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java
index ab4d419a45..27e733e578 100644
--- a/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java
+++ b/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java
@@ -112,9 +112,9 @@ protected static Optional createPhaseControlOuterLoop(LoadFlowParam
         return createPhaseControlOuterLoop(parameters, parametersExt.getPhaseShifterControlMode());
     }
 
-    protected static Optional createAcEmulationOuterLoop(LoadFlowParameters parameters) {
+    protected static Optional createAcHvdcAcEmulationOuterLoop(LoadFlowParameters parameters) {
         if (parameters.isHvdcAcEmulation()) {
-            return Optional.of(new AcEmulationOuterLoop());
+            return Optional.of(new AcHvdcAcEmulationOuterLoop());
         }
         return Optional.empty();
     }
diff --git a/src/main/java/com/powsybl/openloadflow/DefaultAcOuterLoopConfig.java b/src/main/java/com/powsybl/openloadflow/DefaultAcOuterLoopConfig.java
index 1ee731f5f1..7d2b853f31 100644
--- a/src/main/java/com/powsybl/openloadflow/DefaultAcOuterLoopConfig.java
+++ b/src/main/java/com/powsybl/openloadflow/DefaultAcOuterLoopConfig.java
@@ -23,6 +23,8 @@ public List configure(LoadFlowParameters parameters, OpenLoadFlowPa
         List outerLoops = new ArrayList<>(5);
         // primary frequency control
         createDistributedSlackOuterLoop(parameters, parametersExt).ifPresent(outerLoops::add);
+        // AC emulation
+        createAcHvdcAcEmulationOuterLoop(parameters).ifPresent(outerLoops::add);
         // secondary voltage control
         createSecondaryVoltageControlOuterLoop(parametersExt).ifPresent(outerLoops::add);
         // primary voltage control
@@ -36,8 +38,6 @@ public List configure(LoadFlowParameters parameters, OpenLoadFlowPa
         createTransformerReactivePowerControlOuterLoop(parametersExt).ifPresent(outerLoops::add);
         // shunt compensator voltage control
         createShuntVoltageControlOuterLoop(parameters, parametersExt).ifPresent(outerLoops::add);
-        // AC emulation
-        createAcEmulationOuterLoop(parameters).ifPresent(outerLoops::add);
         // automation system
         createAutomationSystemOuterLoop(parametersExt).ifPresent(outerLoops::add);
         return outerLoops;
diff --git a/src/main/java/com/powsybl/openloadflow/ExplicitAcOuterLoopConfig.java b/src/main/java/com/powsybl/openloadflow/ExplicitAcOuterLoopConfig.java
index 4e8b53e053..031175ccce 100644
--- a/src/main/java/com/powsybl/openloadflow/ExplicitAcOuterLoopConfig.java
+++ b/src/main/java/com/powsybl/openloadflow/ExplicitAcOuterLoopConfig.java
@@ -36,7 +36,7 @@ public class ExplicitAcOuterLoopConfig extends AbstractAcOuterLoopConfig {
                                                      TransformerVoltageControlOuterLoop.NAME,
                                                      AutomationSystemOuterLoop.NAME,
                                                      IncrementalTransformerReactivePowerControlOuterLoop.NAME,
-                                                     AcEmulationOuterLoop.NAME);
+                                                     AcHvdcAcEmulationOuterLoop.NAME);
 
     private static Optional createOuterLoop(String name, LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt) {
         return switch (name) {
@@ -66,7 +66,7 @@ private static Optional createOuterLoop(String name, LoadFlowParame
                                                                                                      parametersExt.getGeneratorVoltageControlMinNominalVoltage());
             case AutomationSystemOuterLoop.NAME -> createAutomationSystemOuterLoop(parametersExt);
             case IncrementalTransformerReactivePowerControlOuterLoop.NAME -> createTransformerReactivePowerControlOuterLoop(parametersExt);
-            case AcEmulationOuterLoop.NAME -> createAcEmulationOuterLoop(parameters);
+            case AcHvdcAcEmulationOuterLoop.NAME -> createAcHvdcAcEmulationOuterLoop(parameters);
             default -> throw new PowsyblException("Unknown outer loop '" + name + "'");
         };
     }
diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcHvdcAcEmulationOuterLoop.java
similarity index 95%
rename from src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java
rename to src/main/java/com/powsybl/openloadflow/ac/outerloop/AcHvdcAcEmulationOuterLoop.java
index a11dcda3d4..834d463a71 100644
--- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcEmulationOuterLoop.java
+++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcHvdcAcEmulationOuterLoop.java
@@ -14,7 +14,7 @@
 import com.powsybl.openloadflow.ac.AcOuterLoopContext;
 import com.powsybl.openloadflow.ac.equations.AcEquationType;
 import com.powsybl.openloadflow.ac.equations.AcVariableType;
-import com.powsybl.openloadflow.lf.outerloop.AbstractAcEmulationOuterLoop;
+import com.powsybl.openloadflow.lf.outerloop.AbstractHvdcAcEmulationOuterLoop;
 import com.powsybl.openloadflow.lf.outerloop.OuterLoopResult;
 import com.powsybl.openloadflow.lf.outerloop.OuterLoopStatus;
 import com.powsybl.openloadflow.network.LfHvdc;
@@ -24,12 +24,12 @@
 /**
  * @author Hadrien Godard {@literal }
  */
-public class AcEmulationOuterLoop
-        extends AbstractAcEmulationOuterLoop
+public class AcHvdcAcEmulationOuterLoop
+        extends AbstractHvdcAcEmulationOuterLoop
         implements AcOuterLoop {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(AcEmulationOuterLoop.class);
-    public static final String NAME = "AcEmulation";
+    private static final Logger LOGGER = LoggerFactory.getLogger(AcHvdcAcEmulationOuterLoop.class);
+    public static final String NAME = "AcHvdcAcEmulation";
 
     @Override
     public String getName() {
diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java b/src/main/java/com/powsybl/openloadflow/dc/DcHvdcAcEmulationOuterLoop.java
similarity index 92%
rename from src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java
rename to src/main/java/com/powsybl/openloadflow/dc/DcHvdcAcEmulationOuterLoop.java
index e5eca29c60..db3bb7458c 100644
--- a/src/main/java/com/powsybl/openloadflow/dc/DcAcEmulationOuterLoop.java
+++ b/src/main/java/com/powsybl/openloadflow/dc/DcHvdcAcEmulationOuterLoop.java
@@ -11,7 +11,7 @@
 import com.powsybl.iidm.network.TwoSides;
 import com.powsybl.openloadflow.dc.equations.DcEquationType;
 import com.powsybl.openloadflow.dc.equations.DcVariableType;
-import com.powsybl.openloadflow.lf.outerloop.AbstractAcEmulationOuterLoop;
+import com.powsybl.openloadflow.lf.outerloop.AbstractHvdcAcEmulationOuterLoop;
 import com.powsybl.openloadflow.lf.outerloop.OuterLoopResult;
 import com.powsybl.openloadflow.lf.outerloop.OuterLoopStatus;
 import com.powsybl.openloadflow.network.LfHvdc;
@@ -21,10 +21,10 @@
 /**
  * @author Hadrien Godard {@literal }
  */
-public class DcAcEmulationOuterLoop extends AbstractAcEmulationOuterLoop {
+public class DcHvdcAcEmulationOuterLoop extends AbstractHvdcAcEmulationOuterLoop {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(DcAcEmulationOuterLoop.class);
-    public static final String NAME = "DcAcEmulation";
+    private static final Logger LOGGER = LoggerFactory.getLogger(DcHvdcAcEmulationOuterLoop.class);
+    public static final String NAME = "DcHvdcAcEmulation";
 
     @Override
     public String getName() {
diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java
index 83f5841ce8..3cea650ad3 100644
--- a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java
+++ b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java
@@ -101,7 +101,7 @@ public static void updateNetwork(LfNetwork network, EquationSystem & Quantity,
+public abstract class AbstractHvdcAcEmulationOuterLoop & Quantity,
                                                     E extends Enum & Quantity,
                                                     P extends AbstractLoadFlowParameters,
                                                     C extends LoadFlowContext,
diff --git a/src/main/java/com/powsybl/openloadflow/network/AbstractLfNetworkListener.java b/src/main/java/com/powsybl/openloadflow/network/AbstractLfNetworkListener.java
index f4ce6da549..bd5d55f2b5 100644
--- a/src/main/java/com/powsybl/openloadflow/network/AbstractLfNetworkListener.java
+++ b/src/main/java/com/powsybl/openloadflow/network/AbstractLfNetworkListener.java
@@ -117,12 +117,12 @@ public void onReferenceBusChange(LfBus bus, boolean reference) {
     }
 
     @Override
-    public void onAcEmulationStatusChange(LfHvdc hvdc, LfHvdc.AcEmulationControl.AcEmulationStatus acEmulationStatus) {
+    public void onHvdcAcEmulationStatusChange(LfHvdc hvdc, LfHvdc.AcEmulationControl.AcEmulationStatus acEmulationStatus) {
         // empty
     }
 
     @Override
-    public void onAcEmulationFeedingSideChange(LfHvdc hvdc, TwoSides side) {
+    public void onHvdcAcEmulationFeedingSideChange(LfHvdc hvdc, TwoSides side) {
         // empty
     }
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java b/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java
index 8dcda94a12..a029b7cec7 100644
--- a/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java
+++ b/src/main/java/com/powsybl/openloadflow/network/LfNetworkListener.java
@@ -56,7 +56,7 @@ public interface LfNetworkListener {
 
     void onReferenceBusChange(LfBus bus, boolean reference);
 
-    void onAcEmulationStatusChange(LfHvdc hvdc, LfHvdc.AcEmulationControl.AcEmulationStatus acEmulationStatus);
+    void onHvdcAcEmulationStatusChange(LfHvdc hvdc, LfHvdc.AcEmulationControl.AcEmulationStatus acEmulationStatus);
 
-    void onAcEmulationFeedingSideChange(LfHvdc hvdc, TwoSides side);
+    void onHvdcAcEmulationFeedingSideChange(LfHvdc hvdc, TwoSides side);
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/LfNetworkListenerTracer.java b/src/main/java/com/powsybl/openloadflow/network/LfNetworkListenerTracer.java
index 8af09f218e..8ee2246c5a 100644
--- a/src/main/java/com/powsybl/openloadflow/network/LfNetworkListenerTracer.java
+++ b/src/main/java/com/powsybl/openloadflow/network/LfNetworkListenerTracer.java
@@ -169,14 +169,14 @@ public void onReferenceBusChange(LfBus bus, boolean reference) {
     }
 
     @Override
-    public void onAcEmulationStatusChange(LfHvdc hvdc, LfHvdc.AcEmulationControl.AcEmulationStatus acEmulationStatus) {
-        LOGGER.trace("onAcEmulationStatusChange(hvdc={}, status={})", hvdc, acEmulationStatus);
-        delegate.onAcEmulationStatusChange(hvdc, acEmulationStatus);
+    public void onHvdcAcEmulationStatusChange(LfHvdc hvdc, LfHvdc.AcEmulationControl.AcEmulationStatus acEmulationStatus) {
+        LOGGER.trace("onHvdcAcEmulationStatusChange(hvdc={}, status={})", hvdc, acEmulationStatus);
+        delegate.onHvdcAcEmulationStatusChange(hvdc, acEmulationStatus);
     }
 
     @Override
-    public void onAcEmulationFeedingSideChange(LfHvdc hvdc, TwoSides side) {
-        LOGGER.trace("onAcEmulationFeedingSideChange(hvdc={}, side={})", hvdc, side);
-        delegate.onAcEmulationFeedingSideChange(hvdc, side);
+    public void onHvdcAcEmulationFeedingSideChange(LfHvdc hvdc, TwoSides side) {
+        LOGGER.trace("onHvdcAcEmulationFeedingSideChange(hvdc={}, side={})", hvdc, side);
+        delegate.onHvdcAcEmulationFeedingSideChange(hvdc, side);
     }
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java
index 81d4e7f997..3dfc91cdf9 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java
@@ -153,7 +153,7 @@ public AcEmulationControl getAcEmulationControl() {
     public void updateAcEmulationStatus(AcEmulationControl.AcEmulationStatus acEmulationStatus) {
         acEmulationControl.setAcEmulationStatus(acEmulationStatus);
         for (LfNetworkListener listener : network.getListeners()) {
-            listener.onAcEmulationStatusChange(this, acEmulationStatus);
+            listener.onHvdcAcEmulationStatusChange(this, acEmulationStatus);
         }
     }
 
@@ -161,7 +161,7 @@ public void updateAcEmulationStatus(AcEmulationControl.AcEmulationStatus acEmula
     public void updateFeedingSide(TwoSides side) {
         acEmulationControl.setFeedingSide(side);
         for (LfNetworkListener listener : network.getListeners()) {
-            listener.onAcEmulationFeedingSideChange(this, side);
+            listener.onHvdcAcEmulationFeedingSideChange(this, side);
         }
     }
 
diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java
index 15be5033a4..6d83c27c98 100644
--- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java
+++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java
@@ -395,7 +395,7 @@ void testExplicitOuterLoopsParameter() {
         OpenLoadFlowParameters parametersExt = new OpenLoadFlowParameters()
                 .setSecondaryVoltageControl(true);
 
-        assertEquals(List.of("DistributedSlack", "SecondaryVoltageControl", "VoltageMonitoring", "ReactiveLimits", "ShuntVoltageControl", "AcEmulation"), OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList());
+        assertEquals(List.of("DistributedSlack", "AcHvdcAcEmulation", "SecondaryVoltageControl", "VoltageMonitoring", "ReactiveLimits", "ShuntVoltageControl"), OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList());
 
         parametersExt.setOuterLoopNames(List.of("ReactiveLimits", "SecondaryVoltageControl"));
         assertEquals(List.of("ReactiveLimits", "SecondaryVoltageControl"), OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList());
@@ -408,7 +408,7 @@ void testExplicitOuterLoopsParameter() {
         e = assertThrows(PowsyblException.class, () -> OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt));
         assertEquals("Unknown outer loop 'Foo'", e.getMessage());
 
-        assertEquals("Ordered explicit list of outer loop names, supported outer loops are IncrementalPhaseControl, DistributedSlack, IncrementalShuntVoltageControl, IncrementalTransformerVoltageControl, VoltageMonitoring, PhaseControl, ReactiveLimits, SecondaryVoltageControl, ShuntVoltageControl, SimpleTransformerVoltageControl, TransformerVoltageControl, AutomationSystem, IncrementalTransformerReactivePowerControl, AcEmulation",
+        assertEquals("Ordered explicit list of outer loop names, supported outer loops are IncrementalPhaseControl, DistributedSlack, IncrementalShuntVoltageControl, IncrementalTransformerVoltageControl, VoltageMonitoring, PhaseControl, ReactiveLimits, SecondaryVoltageControl, ShuntVoltageControl, SimpleTransformerVoltageControl, TransformerVoltageControl, AutomationSystem, IncrementalTransformerReactivePowerControl, AcHvdcAcEmulation",
                      OpenLoadFlowParameters.SPECIFIC_PARAMETERS.stream().filter(p -> p.getName().equals(OpenLoadFlowParameters.OUTER_LOOP_NAMES_PARAM_NAME)).findFirst().orElseThrow().getDescription());
     }
 
diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
index 6ae4ea2bc7..5552907371 100644
--- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
+++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
@@ -59,7 +59,7 @@ void testDcParameters() {
     void testAcParameters() {
         Network network = Mockito.mock(Network.class);
         AcLoadFlowParameters acParameters = OpenLoadFlowParameters.createAcParameters(network, new LoadFlowParameters().setReadSlackBus(true), new OpenLoadFlowParameters(), new DenseMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), false, false);
-        assertEquals("AcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=true, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, generatorReactivePowerRemoteControl=false, transformerReactivePowerControl=false, loadFlowModel=AC, reactiveLimits=true, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=true, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE, useLoadModel=false, simulateAutomationSystems=false, referenceBusSelector=ReferenceBusFirstSlackSelector, voltageTargetPriorities=[GENERATOR, TRANSFORMER, SHUNT]), equationSystemCreationParameters=AcEquationSystemCreationParameters(forceA1Var=false), newtonRaphsonParameters=NewtonRaphsonParameters(maxIterations=15, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, stoppingCriteria=DefaultNewtonRaphsonStoppingCriteria, stateVectorScalingMode=NONE, alwaysUpdateNetwork=false, lineSearchStateVectorScalingMaxIteration=10, lineSearchStateVectorScalingStepFold=1.3333333333333333, maxVoltageChangeStateVectorScalingMaxDv=0.1, maxVoltageChangeStateVectorScalingMaxDphi=0.17453292519943295), newtonKrylovParameters=NewtonKrylovParameters(maxIterations=100, lineSearch=false), outerLoops=[DistributedSlackOuterLoop, MonitoringVoltageOuterLoop, ReactiveLimitsOuterLoop, AcEmulationOuterLoop], maxOuterLoopIterations=20, matrixFactory=DenseMatrixFactory, voltageInitializer=UniformValueVoltageInitializer, asymmetrical=false, slackDistributionFailureBehavior=LEAVE_ON_SLACK_BUS, solverFactory=NewtonRaphsonFactory, detailedReport=false)",
+        assertEquals("AcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=true, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, generatorReactivePowerRemoteControl=false, transformerReactivePowerControl=false, loadFlowModel=AC, reactiveLimits=true, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=true, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE, useLoadModel=false, simulateAutomationSystems=false, referenceBusSelector=ReferenceBusFirstSlackSelector, voltageTargetPriorities=[GENERATOR, TRANSFORMER, SHUNT]), equationSystemCreationParameters=AcEquationSystemCreationParameters(forceA1Var=false), newtonRaphsonParameters=NewtonRaphsonParameters(maxIterations=15, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, stoppingCriteria=DefaultNewtonRaphsonStoppingCriteria, stateVectorScalingMode=NONE, alwaysUpdateNetwork=false, lineSearchStateVectorScalingMaxIteration=10, lineSearchStateVectorScalingStepFold=1.3333333333333333, maxVoltageChangeStateVectorScalingMaxDv=0.1, maxVoltageChangeStateVectorScalingMaxDphi=0.17453292519943295), newtonKrylovParameters=NewtonKrylovParameters(maxIterations=100, lineSearch=false), outerLoops=[DistributedSlackOuterLoop, AcHvdcAcEmulationOuterLoop, MonitoringVoltageOuterLoop, ReactiveLimitsOuterLoop], maxOuterLoopIterations=20, matrixFactory=DenseMatrixFactory, voltageInitializer=UniformValueVoltageInitializer, asymmetrical=false, slackDistributionFailureBehavior=LEAVE_ON_SLACK_BUS, solverFactory=NewtonRaphsonFactory, detailedReport=false)",
                      acParameters.toString());
     }
 
diff --git a/src/test/resources/controllerShuntAlreadyInVoltageControlReport.txt b/src/test/resources/controllerShuntAlreadyInVoltageControlReport.txt
index 2fd95b4038..64ac125cc5 100644
--- a/src/test/resources/controllerShuntAlreadyInVoltageControlReport.txt
+++ b/src/test/resources/controllerShuntAlreadyInVoltageControlReport.txt
@@ -8,13 +8,13 @@
             Angle reference bus: vl2_0
             Slack bus: vl2_0
          Outer loop DistributedSlack
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
          Outer loop ShuntVoltageControl
-         Outer loop AcEmulation
          Outer loop DistributedSlack
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
          Outer loop ShuntVoltageControl
-         Outer loop AcEmulation
          AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
diff --git a/src/test/resources/detailedNrReportSecurityAnalysis.txt b/src/test/resources/detailedNrReportSecurityAnalysis.txt
index 2ff730b158..7ef1bba19f 100644
--- a/src/test/resources/detailedNrReportSecurityAnalysis.txt
+++ b/src/test/resources/detailedNrReportSecurityAnalysis.txt
@@ -66,9 +66,9 @@
                      Bus V: 0.995 pu, 8.551939024446748E-22 rad
                      Bus injection: 603.7693866643697 MW, 121.9404027609291 MVar
             Outer loop DistributedSlack
+            Outer loop AcHvdcAcEmulation
             Outer loop VoltageMonitoring
             Outer loop ReactiveLimits
-            Outer loop AcEmulation
             AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
          + Post-contingency simulation 'L2'
             + Newton Raphson on Network CC0 SC0
@@ -162,11 +162,11 @@
                      Bus Id: VL1_0 (nominalVoltage=400.0kV)
                      Bus V: 0.995 pu, 2.3836834369535747E-26 rad
                      Bus injection: 608.3346737740034 MW, 234.0235926831469 MVar
+            Outer loop AcHvdcAcEmulation
             Outer loop VoltageMonitoring
             Outer loop ReactiveLimits
-            Outer loop AcEmulation
             Outer loop DistributedSlack
+            Outer loop AcHvdcAcEmulation
             Outer loop VoltageMonitoring
             Outer loop ReactiveLimits
-            Outer loop AcEmulation
             AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
diff --git a/src/test/resources/esgTutoReport.txt b/src/test/resources/esgTutoReport.txt
index 694e2e0157..bb0817bab5 100644
--- a/src/test/resources/esgTutoReport.txt
+++ b/src/test/resources/esgTutoReport.txt
@@ -9,13 +9,13 @@
          + Outer loop DistributedSlack
             + Outer loop iteration 1
                Slack bus active power (-1.4404045651219555 MW) distributed in 1 distribution iteration(s)
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
-         Outer loop AcEmulation
          Outer loop DistributedSlack
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
-         Outer loop AcEmulation
          AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
    + Sensitivity analysis on network 'sim1'
       + Network CC0 SC0
@@ -24,7 +24,7 @@
             Network balance: active generation=607.0 MW, active load=600.0 MW, reactive generation=0.0 MVar, reactive load=200.0 MVar
             Angle reference bus: VLLOAD_0
             Slack bus: VLLOAD_0
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
-         Outer loop AcEmulation
          AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
diff --git a/src/test/resources/esgTutoReportDetailedNrReportLf.txt b/src/test/resources/esgTutoReportDetailedNrReportLf.txt
index c559e1d864..5987aae5da 100644
--- a/src/test/resources/esgTutoReportDetailedNrReportLf.txt
+++ b/src/test/resources/esgTutoReportDetailedNrReportLf.txt
@@ -218,17 +218,17 @@
                   Bus Id: VLGEN_0 (nominalVoltage=24.0kV)
                   Bus V: 1.0208333333333333 pu, 0.04059595665621846 rad
                   Bus injection: 605.5584900201209 MW, 225.2825348319027 MVar
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
          + Outer loop IncrementalTransformerVoltageControl
             + Outer loop iteration 2
                1 voltage-controlled buses are outside of their target deadbands
-         Outer loop AcEmulation
          Outer loop DistributedSlack
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
          + Outer loop IncrementalTransformerVoltageControl
             + Outer loop iteration 2
                1 voltage-controlled buses are outside of their target deadbands
-         Outer loop AcEmulation
          AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
diff --git a/src/test/resources/esgTutoReportDetailedNrReportSensi.txt b/src/test/resources/esgTutoReportDetailedNrReportSensi.txt
index 20616b5413..5c0658679b 100644
--- a/src/test/resources/esgTutoReportDetailedNrReportSensi.txt
+++ b/src/test/resources/esgTutoReportDetailedNrReportSensi.txt
@@ -64,7 +64,7 @@
                   Bus Id: VLGEN_0 (nominalVoltage=24.0kV)
                   Bus V: 1.0208333333333333 pu, 0.04069359966489529 rad
                   Bus injection: 607.0001563589107 MW, 225.40357009583855 MVar
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
-         Outer loop AcEmulation
          AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
diff --git a/src/test/resources/generatorVoltageControlDiscarded.txt b/src/test/resources/generatorVoltageControlDiscarded.txt
index 475b5c45d1..88d6c0ff2c 100644
--- a/src/test/resources/generatorVoltageControlDiscarded.txt
+++ b/src/test/resources/generatorVoltageControlDiscarded.txt
@@ -8,8 +8,8 @@
             Angle reference bus: b1_vl_0
             Slack bus: b1_vl_0
          Outer loop DistributedSlack
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
          Outer loop SimpleTransformerVoltageControl
-         Outer loop AcEmulation
          AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
diff --git a/src/test/resources/generatorsConnectedToSameBusNotControllingSameBusReport.txt b/src/test/resources/generatorsConnectedToSameBusNotControllingSameBusReport.txt
index 6b9ec11043..c61fea8acd 100644
--- a/src/test/resources/generatorsConnectedToSameBusNotControllingSameBusReport.txt
+++ b/src/test/resources/generatorsConnectedToSameBusNotControllingSameBusReport.txt
@@ -7,6 +7,6 @@
             Network balance: active generation=608.0 MW, active load=600.0 MW, reactive generation=0.0 MVar, reactive load=200.0 MVar
             Angle reference bus: VLGEN_0
             Slack bus: VLGEN_0
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
-         Outer loop AcEmulation
          AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
diff --git a/src/test/resources/multipleConnectedComponentsAcReport.txt b/src/test/resources/multipleConnectedComponentsAcReport.txt
index fd9e9ab489..f014d774bd 100644
--- a/src/test/resources/multipleConnectedComponentsAcReport.txt
+++ b/src/test/resources/multipleConnectedComponentsAcReport.txt
@@ -7,9 +7,9 @@
             Angle reference bus: b1_vl_0
             Slack bus: b1_vl_0
          Outer loop DistributedSlack
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
-         Outer loop AcEmulation
          AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
       + Network CC1 SC1
          + Network info
diff --git a/src/test/resources/multipleConnectedComponentsDcReport.txt b/src/test/resources/multipleConnectedComponentsDcReport.txt
index 08f5de9f64..296bab6ba5 100644
--- a/src/test/resources/multipleConnectedComponentsDcReport.txt
+++ b/src/test/resources/multipleConnectedComponentsDcReport.txt
@@ -6,7 +6,7 @@
             Network balance: active generation=3.0 MW, active load=2.0 MW, reactive generation=0.0 MVar, reactive load=0.0 MVar
             Angle reference bus: b1_vl_0
             Slack bus: b1_vl_0
-         Outer loop DcAcEmulation
+         Outer loop DcHvdcAcEmulation
          DC load flow completed (status=true)
       + Network CC1 SC1
          + Network info
@@ -14,6 +14,6 @@
             Network balance: active generation=2.0 MW, active load=4.0 MW, reactive generation=0.0 MVar, reactive load=0.0 MVar
             Angle reference bus: b5_vl_0
             Slack bus: b5_vl_0
-         Outer loop DcAcEmulation
+         Outer loop DcHvdcAcEmulation
          DC load flow completed (status=true)
       No calculation will be done on 1 network(s) that have no generators
diff --git a/src/test/resources/saReport.txt b/src/test/resources/saReport.txt
index 38ca73d533..7b430696a8 100644
--- a/src/test/resources/saReport.txt
+++ b/src/test/resources/saReport.txt
@@ -10,37 +10,37 @@
             + Outer loop DistributedSlack
                + Outer loop iteration 1
                   Slack bus active power (-1.4404045651219555 MW) distributed in 1 distribution iteration(s)
+            Outer loop AcHvdcAcEmulation
             Outer loop VoltageMonitoring
             Outer loop ReactiveLimits
-            Outer loop AcEmulation
             Outer loop DistributedSlack
+            Outer loop AcHvdcAcEmulation
             Outer loop VoltageMonitoring
             Outer loop ReactiveLimits
-            Outer loop AcEmulation
             AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
          + Post-contingency simulation 'NHV1_NHV2_1'
             + Outer loop DistributedSlack
                + Outer loop iteration 1
                   Slack bus active power (5.803741102800952 MW) distributed in 1 distribution iteration(s)
+            Outer loop AcHvdcAcEmulation
             Outer loop VoltageMonitoring
             Outer loop ReactiveLimits
-            Outer loop AcEmulation
             Outer loop DistributedSlack
+            Outer loop AcHvdcAcEmulation
             Outer loop VoltageMonitoring
             Outer loop ReactiveLimits
-            Outer loop AcEmulation
             AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
          + Post-contingency simulation 'NHV1_NHV2_2'
             + Outer loop DistributedSlack
                + Outer loop iteration 1
                   Slack bus active power (5.803741102800952 MW) distributed in 1 distribution iteration(s)
+            Outer loop AcHvdcAcEmulation
             Outer loop VoltageMonitoring
             Outer loop ReactiveLimits
-            Outer loop AcEmulation
             Outer loop DistributedSlack
+            Outer loop AcHvdcAcEmulation
             Outer loop VoltageMonitoring
             Outer loop ReactiveLimits
-            Outer loop AcEmulation
             AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
          + Post-contingency simulation 'NGEN_NHV1'
             1 buses have a voltage magnitude out of the configured realistic range [0.5, 1.5] p.u.: {VLHV1_0=1.5105659472379578}
@@ -49,11 +49,11 @@
             + Outer loop DistributedSlack
                + Outer loop iteration 1
                   Slack bus active power (-5.4942194604343655 MW) distributed in 1 distribution iteration(s)
+            Outer loop AcHvdcAcEmulation
             Outer loop VoltageMonitoring
             Outer loop ReactiveLimits
-            Outer loop AcEmulation
             Outer loop DistributedSlack
+            Outer loop AcHvdcAcEmulation
             Outer loop VoltageMonitoring
             Outer loop ReactiveLimits
-            Outer loop AcEmulation
             AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
diff --git a/src/test/resources/saReportOperatorStrategies.txt b/src/test/resources/saReportOperatorStrategies.txt
index 50c3a3a9aa..9686039660 100644
--- a/src/test/resources/saReportOperatorStrategies.txt
+++ b/src/test/resources/saReportOperatorStrategies.txt
@@ -7,37 +7,37 @@
             Angle reference bus: VL2_0
             Slack bus: VL2_0
          + Pre-contingency simulation
+            Outer loop AcHvdcAcEmulation
             Outer loop VoltageMonitoring
             Outer loop ReactiveLimits
-            Outer loop AcEmulation
             AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
          + Post-contingency simulation 'L1'
+            Outer loop AcHvdcAcEmulation
             Outer loop VoltageMonitoring
             Outer loop ReactiveLimits
-            Outer loop AcEmulation
             AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
             + Operator strategy simulation 'strategyL1'
+               Outer loop AcHvdcAcEmulation
                Outer loop VoltageMonitoring
                Outer loop ReactiveLimits
-               Outer loop AcEmulation
                AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
          + Post-contingency simulation 'L3'
+            Outer loop AcHvdcAcEmulation
             Outer loop VoltageMonitoring
             Outer loop ReactiveLimits
-            Outer loop AcEmulation
             AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
             + Operator strategy simulation 'strategyL3'
+               Outer loop AcHvdcAcEmulation
                Outer loop VoltageMonitoring
                Outer loop ReactiveLimits
-               Outer loop AcEmulation
                AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
          + Post-contingency simulation 'L2'
+            Outer loop AcHvdcAcEmulation
             Outer loop VoltageMonitoring
             Outer loop ReactiveLimits
-            Outer loop AcEmulation
             AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
             + Operator strategy simulation 'strategyL2'
+               Outer loop AcHvdcAcEmulation
                Outer loop VoltageMonitoring
                Outer loop ReactiveLimits
-               Outer loop AcEmulation
                AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
diff --git a/src/test/resources/sharedGeneratorRemoteReactivePowerControlReport.txt b/src/test/resources/sharedGeneratorRemoteReactivePowerControlReport.txt
index 5828d177e5..893c4bba65 100644
--- a/src/test/resources/sharedGeneratorRemoteReactivePowerControlReport.txt
+++ b/src/test/resources/sharedGeneratorRemoteReactivePowerControlReport.txt
@@ -7,6 +7,6 @@
             Network balance: active generation=3.0 MW, active load=5.0 MW, reactive generation=0.0 MVar, reactive load=0.0 MVar
             Angle reference bus: b1_vl_0
             Slack bus: b1_vl_0
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
-         Outer loop AcEmulation
          AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
diff --git a/src/test/resources/shuntVoltageControlDiscarded.txt b/src/test/resources/shuntVoltageControlDiscarded.txt
index 37beb8747d..0296e2f43b 100644
--- a/src/test/resources/shuntVoltageControlDiscarded.txt
+++ b/src/test/resources/shuntVoltageControlDiscarded.txt
@@ -8,13 +8,13 @@
             Angle reference bus: vl2_0
             Slack bus: vl2_0
          Outer loop DistributedSlack
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
          Outer loop ShuntVoltageControl
-         Outer loop AcEmulation
          Outer loop DistributedSlack
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
          Outer loop ShuntVoltageControl
-         Outer loop AcEmulation
          AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
diff --git a/src/test/resources/shuntVoltageControlOuterLoopReport.txt b/src/test/resources/shuntVoltageControlOuterLoopReport.txt
index 8533672d84..bd8ab5f265 100644
--- a/src/test/resources/shuntVoltageControlOuterLoopReport.txt
+++ b/src/test/resources/shuntVoltageControlOuterLoopReport.txt
@@ -53,6 +53,7 @@
                   Bus V: 0.975 pu, 0.0010125504427887688 rad
                   Bus injection: 101.36618622358611 MW, 150.64984395641986 MVar
          Outer loop DistributedSlack
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
          + Outer loop IncrementalShuntVoltageControl
@@ -104,10 +105,9 @@
                   Bus Id: vl1_0 (nominalVoltage=400.0kV)
                   Bus V: 0.975 pu, 0.002014826586019094 rad
                   Bus injection: 101.3664080925296 MW, -2.165165450231683 MVar
-         Outer loop AcEmulation
          Outer loop DistributedSlack
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
          Outer loop IncrementalShuntVoltageControl
-         Outer loop AcEmulation
          AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
diff --git a/src/test/resources/transformerReactivePowerControlOuterLoopReport.txt b/src/test/resources/transformerReactivePowerControlOuterLoopReport.txt
index ef71733067..844c674434 100644
--- a/src/test/resources/transformerReactivePowerControlOuterLoopReport.txt
+++ b/src/test/resources/transformerReactivePowerControlOuterLoopReport.txt
@@ -97,6 +97,7 @@
                   Bus Id: VL_1_0 (nominalVoltage=132.0kV)
                   Bus V: 1.0227272727272727 pu, 0.011752202697884006 rad
                   Bus injection: 22.111404488893672 MW, 7.616219016989096 MVar
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
          + Outer loop IncrementalTransformerReactivePowerControl
@@ -211,7 +212,6 @@
                   Bus Id: VL_1_0 (nominalVoltage=132.0kV)
                   Bus V: 1.0227272727272727 pu, 0.011772577480572114 rad
                   Bus injection: 22.111739596487254 MW, 7.223626593973918 MVar
-         Outer loop AcEmulation
          + Outer loop DistributedSlack
             + Outer loop iteration 4
                Slack bus active power (2.379902997164196 MW) distributed in 1 distribution iteration(s)
@@ -245,17 +245,17 @@
                   Bus Id: VL_1_0 (nominalVoltage=132.0kV)
                   Bus V: 1.0227272727272727 pu, 0.013083707387261096 rad
                   Bus injection: 24.491420280899572 MW, 7.284141028025306 MVar
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
          + Outer loop IncrementalTransformerReactivePowerControl
             + Outer loop iteration 5
                1 reactive power-controlled branches are outside of their target deadbands
-         Outer loop AcEmulation
          Outer loop DistributedSlack
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
          + Outer loop IncrementalTransformerReactivePowerControl
             + Outer loop iteration 5
                1 reactive power-controlled branches are outside of their target deadbands
-         Outer loop AcEmulation
          AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)
diff --git a/src/test/resources/transformerVoltageControlDiscarded.txt b/src/test/resources/transformerVoltageControlDiscarded.txt
index 99cde77d2e..bb6a8cc51d 100644
--- a/src/test/resources/transformerVoltageControlDiscarded.txt
+++ b/src/test/resources/transformerVoltageControlDiscarded.txt
@@ -10,13 +10,13 @@
          + Outer loop DistributedSlack
             + Outer loop iteration 1
                Slack bus active power (-2.8882610545475753 MW) distributed in 1 distribution iteration(s)
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
          Outer loop SimpleTransformerVoltageControl
-         Outer loop AcEmulation
          Outer loop DistributedSlack
+         Outer loop AcHvdcAcEmulation
          Outer loop VoltageMonitoring
          Outer loop ReactiveLimits
          Outer loop SimpleTransformerVoltageControl
-         Outer loop AcEmulation
          AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)