GeneratorRemoteControlTest.java
/**
* Copyright (c) 2019, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.openloadflow.ac;
import com.powsybl.commons.report.ReportNode;
import com.powsybl.commons.test.PowsyblCoreTestReportResourceBundle;
import com.powsybl.computation.local.LocalComputationManager;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.CoordinatedReactiveControlAdder;
import com.powsybl.iidm.network.extensions.RemoteReactivePowerControl;
import com.powsybl.iidm.network.extensions.RemoteReactivePowerControlAdder;
import com.powsybl.iidm.network.test.EurostagTutorialExample1Factory;
import com.powsybl.loadflow.LoadFlow;
import com.powsybl.loadflow.LoadFlowParameters;
import com.powsybl.loadflow.LoadFlowResult;
import com.powsybl.math.matrix.DenseMatrixFactory;
import com.powsybl.openloadflow.OpenLoadFlowParameters;
import com.powsybl.openloadflow.OpenLoadFlowProvider;
import com.powsybl.openloadflow.ac.solver.NewtonRaphsonStoppingCriteriaType;
import com.powsybl.openloadflow.network.*;
import com.powsybl.openloadflow.network.impl.LfNetworkLoaderImpl;
import com.powsybl.openloadflow.util.LoadFlowAssert;
import com.powsybl.openloadflow.util.report.PowsyblOpenLoadFlowReportResourceBundle;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import static com.powsybl.openloadflow.util.LoadFlowAssert.*;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
*/
class GeneratorRemoteControlTest extends AbstractLoadFlowNetworkFactory {
private Network network;
Substation s;
private Bus b1;
private Bus b2;
private Bus b3;
private Bus b4;
private Generator g1;
private Generator g2;
private Generator g3;
private TwoWindingsTransformer tr1;
private TwoWindingsTransformer tr2;
private TwoWindingsTransformer tr3;
private LoadFlow.Runner loadFlowRunner;
private LoadFlowParameters parameters;
private OpenLoadFlowParameters parametersExt;
@BeforeEach
void setUp() {
network = VoltageControlNetworkFactory.createWithGeneratorRemoteControl();
s = network.getSubstation("s");
b1 = network.getBusBreakerView().getBus("b1");
b2 = network.getBusBreakerView().getBus("b2");
b3 = network.getBusBreakerView().getBus("b3");
b4 = network.getBusBreakerView().getBus("b4");
g1 = network.getGenerator("g1");
g2 = network.getGenerator("g2");
g3 = network.getGenerator("g3");
tr1 = network.getTwoWindingsTransformer("tr1");
tr2 = network.getTwoWindingsTransformer("tr2");
tr3 = network.getTwoWindingsTransformer("tr3");
loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(new DenseMatrixFactory()));
parameters = new LoadFlowParameters().setUseReactiveLimits(false)
.setDistributedSlack(false);
parametersExt = OpenLoadFlowParameters.create(parameters)
.setSlackBusSelectionMode(SlackBusSelectionMode.MOST_MESHED)
.setVoltageRemoteControl(true);
}
@Test
void testWith3Generators() {
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertVoltageEquals(21.506559, b1);
assertVoltageEquals(21.293879, b2);
assertVoltageEquals(22.641227, b3);
assertVoltageEquals(413.4, b4);
assertReactivePowerEquals(-69.925, g1.getTerminal());
assertReactivePowerEquals(-69.925, g2.getTerminal());
assertReactivePowerEquals(-69.925, g3.getTerminal());
}
@Test
void testWith3GeneratorsAndNonImpedantBranch() {
// add a non impedant branch going to a load at generator 3 connection bus.
VoltageLevel vl5 = s.newVoltageLevel()
.setId("vl5")
.setNominalV(20)
.setTopologyKind(TopologyKind.BUS_BREAKER)
.add();
vl5.getBusBreakerView().newBus()
.setId("b5")
.add();
vl5.newLoad()
.setId("ld5")
.setConnectableBus("b5")
.setBus("b5")
.setP0(0)
.setQ0(30)
.add();
network.newLine()
.setId("ln1")
.setConnectableBus1("b3")
.setBus1("b3")
.setConnectableBus2("b5")
.setBus2("b5")
.setR(0)
.setX(0)
.add();
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(-79.892, g1.getTerminal());
assertReactivePowerEquals(-79.892, g2.getTerminal());
assertReactivePowerEquals(-79.892, g3.getTerminal());
}
@Test
void testWithLoadConnectedToGeneratorBus() {
// in that case we expect the generation reactive power to be equals for each of the controller buses
b1.getVoltageLevel().newLoad()
.setId("l")
.setBus(b1.getId())
.setConnectableBus(b1.getId())
.setP0(0)
.setQ0(10)
.add();
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(-73.283, g1.getTerminal());
assertReactivePowerEquals(-73.283, g2.getTerminal());
assertReactivePowerEquals(-73.283, g3.getTerminal());
assertReactivePowerEquals(63.283, tr1.getTerminal1());
assertReactivePowerEquals(73.283, tr2.getTerminal1());
assertReactivePowerEquals(73.283, tr3.getTerminal1());
// same test but with a more complex distribution
g1.newExtension(CoordinatedReactiveControlAdder.class).withQPercent(60).add();
g2.newExtension(CoordinatedReactiveControlAdder.class).withQPercent(30).add();
g3.newExtension(CoordinatedReactiveControlAdder.class).withQPercent(10).add();
result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(-132.094, g1.getTerminal());
assertReactivePowerEquals(-66.047, g2.getTerminal());
assertReactivePowerEquals(-22.015, g3.getTerminal());
assertReactivePowerEquals(122.094, tr1.getTerminal1());
assertReactivePowerEquals(66.047, tr2.getTerminal1());
assertReactivePowerEquals(22.015, tr3.getTerminal1());
}
@Test
void testWithShuntConnectedToGeneratorBus() {
// in that case we expect the generation reactive power to be equals for each of the controller buses
b1.getVoltageLevel().newShuntCompensator()
.setId("l")
.setBus(b1.getId())
.setConnectableBus(b1.getId())
.setSectionCount(1)
.newLinearModel()
.setBPerSection(Math.pow(10, -2))
.setMaximumSectionCount(1)
.add()
.add();
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(-68.372, g1.getTerminal());
assertReactivePowerEquals(-68.372, g2.getTerminal());
assertReactivePowerEquals(-68.372, g3.getTerminal());
assertReactivePowerEquals(73.003, tr1.getTerminal1());
assertReactivePowerEquals(68.372, tr2.getTerminal1());
assertReactivePowerEquals(68.372, tr3.getTerminal1());
}
@Test
void testWith3GeneratorsAndCoordinatedReactiveControlExtensions() {
g1.newExtension(CoordinatedReactiveControlAdder.class).withQPercent(60).add();
g2.newExtension(CoordinatedReactiveControlAdder.class).withQPercent(30).add();
g3.newExtension(CoordinatedReactiveControlAdder.class).withQPercent(10).add();
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertVoltageEquals(21.709276, b1);
assertVoltageEquals(21.264396, b2);
assertVoltageEquals(22.331965, b3);
assertVoltageEquals(413.4, b4);
assertReactivePowerEquals(-126.14, g1.getTerminal());
assertReactivePowerEquals(-63.07, g2.getTerminal());
assertReactivePowerEquals(-21.023, g3.getTerminal());
}
@Test
void testWith3GeneratorsAndReactiveLimits() {
// as there is no CoordinatedReactiveControl extension, reactive limit range will be used to create reactive
// keys
g1.newMinMaxReactiveLimits().setMinQ(0).setMaxQ(60).add();
g2.newMinMaxReactiveLimits().setMinQ(0).setMaxQ(30).add();
g3.newMinMaxReactiveLimits().setMinQ(0).setMaxQ(10).add();
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertVoltageEquals(21.709276, b1);
assertVoltageEquals(21.264396, b2);
assertVoltageEquals(22.331965, b3);
assertVoltageEquals(413.4, b4);
assertReactivePowerEquals(-126.14, g1.getTerminal());
assertReactivePowerEquals(-63.07, g2.getTerminal());
assertReactivePowerEquals(-21.023, g3.getTerminal());
}
@Test
void testErrorWhenDifferentTargetV() {
g3.setTargetV(413.3);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertVoltageEquals(413.4, b4); // check target voltage has been fixed to first controller one
}
@Test
void testWith2Generators() {
g3.setTargetQ(10).setVoltageRegulatorOn(false);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertVoltageEquals(21.616159, b1);
assertVoltageEquals(21.423099, b2);
assertVoltageEquals(22.261066, b3);
assertVoltageEquals(413.4, b4);
assertReactivePowerEquals(-100.189, g1.getTerminal());
assertReactivePowerEquals(-100.189, g2.getTerminal());
assertReactivePowerEquals(-10, g3.getTerminal());
}
@Test
void testWith3GeneratorsAndFirstGeneratorToLimit() {
parameters.setUseReactiveLimits(true);
g1.newMinMaxReactiveLimits()
.setMinQ(-50)
.setMaxQ(50)
.add();
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertVoltageEquals(21.433794, b1);
assertVoltageEquals(21.337233, b2);
assertVoltageEquals(22.704157, b3);
assertVoltageEquals(413.4, b4);
assertReactivePowerEquals(-50, g1.getTerminal()); // generator 1 has been correctly limited to -50 MVar
assertReactivePowerEquals(-80.038, g2.getTerminal());
assertReactivePowerEquals(-80.038, g3.getTerminal());
}
@Test
void testWith3GeneratorsAndAnAdditionalWithLocalRegulation() {
// create a generator on controlled bus to have "mixed" 1 local plus 3 remote generators controlling voltage
// at bus 4
Generator g4 = b4.getVoltageLevel()
.newGenerator()
.setId("g4")
.setBus("b4")
.setConnectableBus("b4")
.setEnergySource(EnergySource.THERMAL)
.setMinP(0)
.setMaxP(200)
.setTargetP(100)
.setTargetV(413.4)
.setVoltageRegulatorOn(true)
.add();
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(-52.103, g1.getTerminal());
assertReactivePowerEquals(-52.103, g2.getTerminal());
assertReactivePowerEquals(-52.103, g3.getTerminal());
assertReactivePowerEquals(-52.103, g4.getTerminal()); // local generator has the same reactive power that remote ones
// check that distribution is correct even with 2 generators connected to local bus
Generator g4bis = b4.getVoltageLevel()
.newGenerator()
.setId("g4bis")
.setBus("b4")
.setConnectableBus("b4")
.setEnergySource(EnergySource.THERMAL)
.setMinP(0)
.setMaxP(200)
.setTargetP(100)
.setTargetV(413.4)
.setVoltageRegulatorOn(true)
.add();
result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(-41.559, g1.getTerminal());
assertReactivePowerEquals(-41.559, g2.getTerminal());
assertReactivePowerEquals(-41.559, g3.getTerminal());
assertReactivePowerEquals(-41.559, g4.getTerminal());
assertReactivePowerEquals(-41.559, g4bis.getTerminal());
// check that of we switch g4 PQ with Q=+-10MVar, generators that still regulate voltage already have a correct
// amount of reactive power
g4.setTargetQ(-10)
.setVoltageRegulatorOn(false);
result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(-54.646, g1.getTerminal());
assertReactivePowerEquals(-54.646, g2.getTerminal());
assertReactivePowerEquals(-54.646, g3.getTerminal());
assertReactivePowerEquals(10, g4.getTerminal());
assertReactivePowerEquals(-54.646, g4bis.getTerminal());
g4.setTargetQ(10);
result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(-49.563, g1.getTerminal());
assertReactivePowerEquals(-49.563, g2.getTerminal());
assertReactivePowerEquals(-49.563, g3.getTerminal());
assertReactivePowerEquals(-10, g4.getTerminal());
assertReactivePowerEquals(-49.563, g4bis.getTerminal());
// same test but with one of the remote generator switched PQ
g4.setVoltageRegulatorOn(true);
g2.setTargetQ(-10)
.setVoltageRegulatorOn(false);
result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(-54.51, g1.getTerminal());
assertReactivePowerEquals(10, g2.getTerminal());
assertReactivePowerEquals(-54.51, g3.getTerminal());
assertReactivePowerEquals(-54.51, g4.getTerminal());
assertReactivePowerEquals(-54.51, g4bis.getTerminal());
g2.setTargetQ(10);
result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(-49.449, g1.getTerminal());
assertReactivePowerEquals(-10, g2.getTerminal());
assertReactivePowerEquals(-49.449, g3.getTerminal());
assertReactivePowerEquals(-49.449, g4.getTerminal());
assertReactivePowerEquals(-49.449, g4bis.getTerminal());
// try to switch off regulation of the 3 remote generators
g1.setTargetQ(10).setVoltageRegulatorOn(false);
g2.setTargetQ(10).setVoltageRegulatorOn(false);
g3.setTargetQ(10).setVoltageRegulatorOn(false);
result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(-10, g1.getTerminal());
assertReactivePowerEquals(-10, g2.getTerminal());
assertReactivePowerEquals(-10, g3.getTerminal());
assertReactivePowerEquals(-88.407, g4.getTerminal());
assertReactivePowerEquals(-88.407, g4bis.getTerminal());
}
@Test
void testGeneratorRemoteReactivePowerControl() {
// create a basic 4-buses network
Network network = FourBusNetworkFactory.createBaseNetwork();
Generator g4 = network.getGenerator("g4");
Line l34 = network.getLine("l34");
Line l12 = network.getLine("l12");
double targetQ = 1.0;
// disable voltage control on g4
g4.setTargetQ(0).setVoltageRegulatorOn(false);
// first test: generator g4 regulates reactive power on line 4->3 (on side of g4)
g4.newExtension(RemoteReactivePowerControlAdder.class)
.withTargetQ(targetQ)
.withRegulatingTerminal(l34.getTerminal(TwoSides.TWO))
.withEnabled(true).add();
parametersExt.setGeneratorReactivePowerRemoteControl(true);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(targetQ, l34.getTerminal(TwoSides.TWO));
// second test: generator g4 regulates reactive power on line 3->4 (on the opposite side of the line)
g4.newExtension(RemoteReactivePowerControlAdder.class)
.withTargetQ(targetQ)
.withRegulatingTerminal(l34.getTerminal(TwoSides.ONE))
.withEnabled(true).add();
result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(targetQ, l34.getTerminal(TwoSides.ONE));
// third test: generator g4 regulates reactive power on line 1->2 (line which is not linked to bus 4)
g4.newExtension(RemoteReactivePowerControlAdder.class)
.withTargetQ(targetQ)
.withRegulatingTerminal(l12.getTerminal(TwoSides.ONE))
.withEnabled(true).add();
result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(targetQ, l12.getTerminal(TwoSides.ONE));
}
@Test
void testGeneratorRemoteReactivePowerControlOnZeroImpedanceBranch() {
// create a basic 4-buses network
Network network = FourBusNetworkFactory.createBaseNetwork();
Generator g4 = network.getGenerator("g4");
Line l34 = network.getLine("l34");
l34.setR(0).setX(0);
double targetQ = 1.0;
// disable voltage control on g4
g4.setTargetQ(0).setVoltageRegulatorOn(false);
// generator g4 regulates reactive power on line 4->3 (on side of g4)
// which is zero impedant
g4.newExtension(RemoteReactivePowerControlAdder.class)
.withTargetQ(targetQ)
.withRegulatingTerminal(l34.getTerminal(TwoSides.TWO))
.withEnabled(true).add();
parametersExt
.setGeneratorReactivePowerRemoteControl(true);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(targetQ, l34.getTerminal(TwoSides.TWO));
}
@Test
void testDiscardedGeneratorRemoteReactivePowerControls() {
// create a basic 4-buses network
Network network = FourBusNetworkFactory.createBaseNetwork();
Generator g4 = network.getGenerator("g4");
Line l34 = network.getLine("l34");
l34.getTerminal1().disconnect();
double targetQ = 1.0;
// disable voltage control on g4
g4.setTargetQ(0).setVoltageRegulatorOn(false);
// first test: generator g4 regulates reactive power on line 4->3 (on side of g4)
g4.newExtension(RemoteReactivePowerControlAdder.class)
.withTargetQ(targetQ)
.withRegulatingTerminal(l34.getTerminal(TwoSides.TWO))
.withEnabled(true).add();
parametersExt.setGeneratorReactivePowerRemoteControl(true);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(0.0, l34.getTerminal(TwoSides.TWO));
l34.getTerminal2().disconnect();
LoadFlowResult result2 = loadFlowRunner.run(network, parameters);
assertTrue(result2.isFullyConverged());
assertReactivePowerEquals(Double.NaN, l34.getTerminal(TwoSides.TWO));
}
@Test
void testSharedGeneratorRemoteReactivePowerControl() throws IOException {
// we create a basic 4-buses network
Network network = FourBusNetworkFactory.createBaseNetwork();
Bus b1 = network.getBusBreakerView().getBus("b1");
Bus b2 = network.getBusBreakerView().getBus("b2");
Bus b4 = network.getBusBreakerView().getBus("b4");
Generator g4 = network.getGenerator("g4");
Generator g1 = network.getGenerator("g1");
Line l34 = network.getLine("l34");
createGenerator(b2, "g2", 0);
double targetQ = 1.0;
// we disable the voltage control of g1 and g4
g1.setTargetQ(0).setVoltageRegulatorOn(false);
g4.setTargetQ(0).setVoltageRegulatorOn(false);
// generators g1 and g4 both regulate reactive power on line 4->3
g1.newExtension(RemoteReactivePowerControlAdder.class)
.withTargetQ(targetQ)
.withRegulatingTerminal(l34.getTerminal(TwoSides.TWO))
.withEnabled(true).add();
g4.newExtension(RemoteReactivePowerControlAdder.class)
.withTargetQ(targetQ)
.withRegulatingTerminal(l34.getTerminal(TwoSides.TWO))
.withEnabled(true).add();
parametersExt.setGeneratorReactivePowerRemoteControl(true);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(1, l34.getTerminal(TwoSides.TWO));
assertEquals(0.0, Math.abs(b1.getConnectedTerminalStream().mapToDouble(Terminal::getQ).sum()), DELTA_POWER);
assertEquals(0.0, Math.abs(b4.getConnectedTerminalStream().mapToDouble(Terminal::getQ).sum()), DELTA_POWER);
// generators g1 and g4 both regulate reactive power on line 4->3
g1.newExtension(RemoteReactivePowerControlAdder.class)
.withTargetQ(targetQ)
.withRegulatingTerminal(l34.getTerminal(TwoSides.TWO))
.withEnabled(true).add();
g4.newExtension(RemoteReactivePowerControlAdder.class)
.withTargetQ(targetQ)
.withRegulatingTerminal(l34.getTerminal(TwoSides.ONE))
.withEnabled(true).add();
parametersExt.setGeneratorReactivePowerRemoteControl(true);
ReportNode reportNode = ReportNode.newRootReportNode()
.withResourceBundles(PowsyblOpenLoadFlowReportResourceBundle.BASE_NAME, PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME)
.withMessageTemplate("testReport")
.build();
LoadFlowResult result2 = loadFlowRunner.run(network, VariantManagerConstants.INITIAL_VARIANT_ID, LocalComputationManager.getDefault(), parameters, reportNode);
assertTrue(result2.isFullyConverged());
assertReactivePowerEquals(1, l34.getTerminal(TwoSides.TWO));
assertEquals(0.0, Math.abs(b1.getConnectedTerminalStream().mapToDouble(Terminal::getQ).sum()), DELTA_POWER);
assertEquals(0.0, Math.abs(b4.getConnectedTerminalStream().mapToDouble(Terminal::getQ).sum()), DELTA_POWER);
LoadFlowAssert.assertReportEquals("/sharedGeneratorRemoteReactivePowerControlReport.txt", reportNode);
}
@Test
void testSharedGeneratorRemoteReactivePowerControl2() {
// generators g1 and g4 both regulate reactive power on line 4->3
// reactive keys are not set -> fallback case: equally distributed
Network network1 = FourBusNetworkFactory.createWithReactiveControl();
Generator g4n1 = network1.getGenerator("g4");
Generator g1n1 = network1.getGenerator("g1");
Line l34n1 = network1.getLine("l34");
parametersExt
.setGeneratorReactivePowerRemoteControl(true)
.setNewtonRaphsonStoppingCriteriaType(NewtonRaphsonStoppingCriteriaType.PER_EQUATION_TYPE_CRITERIA)
.setMaxReactivePowerMismatch(DELTA_POWER); // needed to ensure convergence within a DELTA_POWER
// tolerance in Q for the controlled branch
LoadFlowResult result1 = loadFlowRunner.run(network1, parameters);
assertTrue(result1.isFullyConverged());
assertReactivePowerEquals(2, l34n1.getTerminal(TwoSides.TWO));
// reactive power equally partitioned
assertEquals(Math.abs(g1n1.getTerminal().getQ()), Math.abs(g4n1.getTerminal().getQ()), DELTA_POWER);
// generators g1 and g4 both regulate reactive power on line 4->3
// reactive keys are set -> 75% for g1 and 25% for g4
Network network2 = FourBusNetworkFactory.createWithReactiveControl();
Line l34n2 = network2.getLine("l34");
Generator g4n2 = network2.getGenerator("g4");
Generator g1n2 = network2.getGenerator("g1");
g1n2.newExtension(CoordinatedReactiveControlAdder.class).withQPercent(75).add();
g4n2.newExtension(CoordinatedReactiveControlAdder.class).withQPercent(25).add();
LoadFlowResult result2 = loadFlowRunner.run(network2, parameters);
assertTrue(result2.isFullyConverged());
assertReactivePowerEquals(2, l34n2.getTerminal(TwoSides.TWO));
// reactive power partitioned 1:3
assertEquals(Math.abs(g1n2.getTerminal().getQ()), 3 * Math.abs(g4n2.getTerminal().getQ()), DELTA_POWER);
}
@Test
void testSharedGeneratorRemoteReactivePowerControl3() {
// only generator g1 regulates reactive power on line 4->3
Network network1 = FourBusNetworkFactory.createWithReactiveControl2GeneratorsOnSameBus();
Generator g1n1 = network1.getGenerator("g1");
network1.getGenerator("g1Bis").getExtension(RemoteReactivePowerControl.class).setEnabled(false);
Line l34n1 = network1.getLine("l34");
parametersExt.setGeneratorReactivePowerRemoteControl(true);
LoadFlowResult result1 = loadFlowRunner.run(network1, parameters);
assertTrue(result1.isFullyConverged());
assertReactivePowerEquals(2, l34n1.getTerminal(TwoSides.TWO));
// both generators g1 and g1Bis (same bus) regulate reactive power on line 4->3 equally
Network network2 = FourBusNetworkFactory.createWithReactiveControl2GeneratorsOnSameBus();
Generator g1n2 = network2.getGenerator("g1");
Line l34n2 = network2.getLine("l34");
LoadFlowResult result2 = loadFlowRunner.run(network2, parameters);
assertTrue(result2.isFullyConverged());
assertReactivePowerEquals(2, l34n2.getTerminal(TwoSides.TWO));
// in second run reactive power is divided by 2 due to the presence of the second generator g1Bis
assertEquals(g1n1.getTerminal().getQ(), 2 * g1n2.getTerminal().getQ(), DELTA_POWER);
}
@Test
void testSharedGeneratorRemoteReactivePowerControl4() {
// generators g1, g1Bis and g4 regulate reactive power on line 4->3
Network network = FourBusNetworkFactory.createWithReactiveControl2GeneratorsOnSameBusAnd1Extra();
Generator g1 = network.getGenerator("g1");
Generator g4 = network.getGenerator("g4");
Line l34 = network.getLine("l34");
parametersExt.setGeneratorReactivePowerRemoteControl(true);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(2, l34.getTerminal(TwoSides.TWO));
// reactive power partitioned 2 (bus1 with 2 generators) : 1 (bus4)
assertEquals(Math.abs(g1.getTerminal().getQ()), Math.abs(g4.getTerminal().getQ()), DELTA_POWER);
}
@Test
void testSharedGeneratorRemoteReactivePowerControlReactiveKeys() {
// generator g1 and g1Bis regulate reactive power on line 4->3
// they are on the same bus
Network network = FourBusNetworkFactory.createWithReactiveControl2GeneratorsOnSameBus();
Generator g1 = network.getGenerator("g1");
Generator g1Bis = network.getGenerator("g1Bis");
Line l34 = network.getLine("l34");
// Q should be split 1 : 4 for g1 and g1Bis respectively
g1.newExtension(CoordinatedReactiveControlAdder.class).withQPercent(80).add();
g1Bis.newExtension(CoordinatedReactiveControlAdder.class).withQPercent(20).add();
parametersExt.setGeneratorReactivePowerRemoteControl(true)
.setReactivePowerDispatchMode(ReactivePowerDispatchMode.Q_EQUAL_PROPORTION);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(2, l34.getTerminal(TwoSides.TWO));
assertEquals(g1.getTerminal().getQ(), 4 * g1Bis.getTerminal().getQ(), DELTA_POWER);
assertEquals(5.8386, g1.getTerminal().getQ() + g1Bis.getTerminal().getQ(), DELTA_POWER);
}
@Test
void testSharedGeneratorRemoteReactivePowerControlReactiveKeysFallbackMaxRange() {
// generator g1 and g1Bis regulate reactive power on line 4->3
// they are on the same bus
Network network = FourBusNetworkFactory.createWithReactiveControl2GeneratorsOnSameBus();
Generator g1 = network.getGenerator("g1");
Generator g1Bis = network.getGenerator("g1Bis");
Line l34 = network.getLine("l34");
// no reactive keys set => fallback
// Q should be split 1 : 2 for g1 and g1Bis respectively
g1.newMinMaxReactiveLimits().setMinQ(-20).setMaxQ(20).add();
g1Bis.newMinMaxReactiveLimits().setMinQ(-10).setMaxQ(10).add();
parametersExt.setGeneratorReactivePowerRemoteControl(true)
.setReactivePowerDispatchMode(ReactivePowerDispatchMode.Q_EQUAL_PROPORTION);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(2, l34.getTerminal(TwoSides.TWO));
assertEquals(g1.getTerminal().getQ(), 2 * g1Bis.getTerminal().getQ(), DELTA_POWER);
assertEquals(5.8386, g1.getTerminal().getQ() + g1Bis.getTerminal().getQ(), DELTA_POWER);
}
@Test
void testSharedGeneratorRemoteReactivePowerControlReactiveKeysFallbackEquallyDistributed() {
// generator g1 and g1Bis regulate reactive power on line 4->3
// they are on the same bus
Network network = FourBusNetworkFactory.createWithReactiveControl2GeneratorsOnSameBus();
Generator g1 = network.getGenerator("g1");
Generator g1Bis = network.getGenerator("g1Bis");
Line l34 = network.getLine("l34");
// no reactive keys set => fallback max range
// not valid max ranges => fallback equally distributed
// Q should be equally split between g1 and g1Bis
parametersExt.setGeneratorReactivePowerRemoteControl(true)
.setReactivePowerDispatchMode(ReactivePowerDispatchMode.Q_EQUAL_PROPORTION);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(2, l34.getTerminal(TwoSides.TWO));
assertEquals(g1.getTerminal().getQ(), g1Bis.getTerminal().getQ(), DELTA_POWER);
assertEquals(5.8386, g1.getTerminal().getQ() + g1Bis.getTerminal().getQ(), DELTA_POWER);
}
@Test
void testNotSupportedGeneratorRemoteReactivePowerControl() {
// Create a basic 4-buses network
Network network = FourBusNetworkFactory.createBaseNetwork();
Generator g4 = network.getGenerator("g4");
Line l34 = network.getLine("l34");
double targetQ = 1.0;
// first test: generator g4 regulates reactive power on line 4->3 (on side of g4)
g4.newExtension(RemoteReactivePowerControlAdder.class)
.withTargetQ(targetQ)
.withRegulatingTerminal(l34.getTerminal(TwoSides.TWO))
.withEnabled(true).add();
parametersExt.setGeneratorReactivePowerRemoteControl(true);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(0.274417, l34.getTerminal(TwoSides.TWO));
}
@Test
void testGeneratorUpdateWithReactivePowerControlDisabled() {
// control is off through parameters
Network network2 = FourBusNetworkFactory.createWithReactiveControl2GeneratorsOnSameBus();
Generator g1n1 = network2.getGenerator("g1Bis");
g1n1.setTargetQ(5.0);
Generator g1n2 = network2.getGenerator("g1");
g1n2.setTargetQ(3.0);
Line l34n2 = network2.getLine("l34");
LoadFlowResult result2 = loadFlowRunner.run(network2, parameters);
assertTrue(result2.isFullyConverged());
assertReactivePowerEquals(-0.287, l34n2.getTerminal(TwoSides.TWO));
assertReactivePowerEquals(-5.0, g1n1.getTerminal());
assertReactivePowerEquals(-3.0, g1n2.getTerminal());
}
@Test
void testNotSupportedGeneratorRemoteReactivePowerControl2() {
Network network = FourBusNetworkFactory.createWithTwoGeneratorsAtBus2();
Generator g2 = network.getGenerator("g2");
Line l34 = network.getLine("l34");
double targetQ = 1.0;
// generator g2 regulates reactive power on line 4->3
// generator g5 regulates voltage
// they are both connected to the same bus
g2.setTargetQ(0).setVoltageRegulatorOn(false);
g2.newExtension(RemoteReactivePowerControlAdder.class)
.withTargetQ(targetQ)
.withRegulatingTerminal(l34.getTerminal(TwoSides.TWO))
.withEnabled(true).add();
parametersExt.setGeneratorReactivePowerRemoteControl(true);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(0.162232, l34.getTerminal(TwoSides.TWO));
}
@Test
void testNotSupportedGeneratorRemoteReactivePowerControl3() {
Network network = FourBusNetworkFactory.createBaseNetwork();
Generator g4 = network.getGenerator("g4");
Load l = network.getLoad("d2");
double targetQ = 1.0;
g4.setTargetQ(0).setVoltageRegulatorOn(false);
g4.newExtension(RemoteReactivePowerControlAdder.class)
.withTargetQ(targetQ)
.withRegulatingTerminal(l.getTerminal()) // not supported.
.withEnabled(true).add();
parametersExt.setGeneratorReactivePowerRemoteControl(true);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
}
@Test
void testGeneratorRemoteReactivePowerControl2() {
Network network = EurostagFactory.fix(EurostagTutorialExample1Factory.create());
VoltageLevel vlload = network.getVoltageLevel("VLLOAD");
Bus nload = vlload.getBusBreakerView().getBus("NLOAD");
vlload.newGenerator()
.setId("GEN2")
.setBus(nload.getId())
.setConnectableBus(nload.getId())
.setMinP(-9999.99D)
.setMaxP(9999.99D)
.setVoltageRegulatorOn(true)
.setTargetV(150D)
.setTargetP(0.0D)
.setTargetQ(301.0D)
.add();
Generator generator2 = network.getGenerator("GEN2");
generator2.newReactiveCapabilityCurve()
.beginPoint()
.setP(3.0D)
.setMaxQ(5.0D)
.setMinQ(4.0D)
.endPoint()
.beginPoint()
.setP(0.0D)
.setMaxQ(7.0D)
.setMinQ(6.0D)
.endPoint()
.beginPoint()
.setP(1.0D)
.setMaxQ(5.0D)
.setMinQ(4.0D)
.endPoint()
.add();
Generator gen = network.getGenerator("GEN");
TwoWindingsTransformer twt = network.getTwoWindingsTransformer("NGEN_NHV1");
double targetQ = 1.0;
gen.setTargetQ(0).setVoltageRegulatorOn(false);
gen.newExtension(RemoteReactivePowerControlAdder.class)
.withTargetQ(targetQ)
.withRegulatingTerminal(twt.getTerminal(TwoSides.TWO))
.withEnabled(true).add();
parametersExt.setGeneratorReactivePowerRemoteControl(true);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(targetQ, twt.getTerminal(TwoSides.TWO));
}
/**
* G1 controls reactive power on T3WT leg1.
*<pre>
* G1 LD2 LD3 G3
* | L12 | | /
* | -------- | | /
* B1 B2 B3
* \ /
* leg1 leg2
* \ /
* T3WT
* |
* leg3
* |
* B4
* |
* LD4
*</pre>
*/
@Test
void testGeneratorRemoteReactivePowerControl3wt() {
Network network = VoltageControlNetworkFactory.createNetworkWithT3wt();
var gen1 = network.getGenerator("GEN_1");
var t3wt = network.getThreeWindingsTransformer("T3wT");
VoltageLevel vl3 = network.getVoltageLevel("VL_3");
Bus b3 = vl3.getBusBreakerView().getBus("BUS_3");
vl3.newGenerator()
.setId("GEN_3")
.setBus(b3.getId())
.setConnectableBus(b3.getId())
.setMinP(-100)
.setMaxP(+100)
.setVoltageRegulatorOn(true)
.setTargetV(vl3.getNominalV())
.setTargetP(10.0)
.setTargetQ(0.0)
.add();
double targetQ = -5.0;
gen1.setTargetQ(0.0).setVoltageRegulatorOn(false)
.newExtension(RemoteReactivePowerControlAdder.class)
.withTargetQ(targetQ)
.withRegulatingTerminal(t3wt.getTerminal(ThreeSides.ONE))
.withEnabled(true).add();
parametersExt
.setGeneratorReactivePowerRemoteControl(true)
.setMaxReactivePowerMismatch(DELTA_POWER)
.setNewtonRaphsonStoppingCriteriaType(NewtonRaphsonStoppingCriteriaType.PER_EQUATION_TYPE_CRITERIA);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(targetQ, t3wt.getTerminal(ThreeSides.ONE));
}
@Test
void testReactiveRangeCheckMode() {
parameters.setUseReactiveLimits(true);
Network network = EurostagFactory.fix(EurostagTutorialExample1Factory.create());
VoltageLevel vlload = network.getVoltageLevel("VLLOAD");
Bus nload = vlload.getBusBreakerView().getBus("NLOAD");
vlload.newGenerator()
.setId("GEN2")
.setBus(nload.getId())
.setConnectableBus(nload.getId())
.setMinP(-9999.99D)
.setMaxP(9999.99D)
.setVoltageRegulatorOn(true)
.setTargetV(150D)
.setTargetP(0.0D)
.setTargetQ(301.0D)
.add();
Generator generator2 = network.getGenerator("GEN2");
generator2.newReactiveCapabilityCurve()
.beginPoint()
.setP(3.0D)
.setMaxQ(100)
.setMinQ(-100)
.endPoint()
.beginPoint()
.setP(0.0D)
.setMaxQ(100)
.setMinQ(-100)
.endPoint()
.beginPoint()
.setP(1.0D)
.setMaxQ(5.0D)
.setMinQ(5.0D)
.endPoint()
.add();
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertVoltageEquals(150.0, nload);
generator2.setTargetP(1.0);
parametersExt.setReactiveRangeCheckMode(OpenLoadFlowParameters.ReactiveRangeCheckMode.TARGET_P);
LoadFlowResult result2 = loadFlowRunner.run(network, parameters);
assertTrue(result2.isFullyConverged());
assertVoltageEquals(164.88, nload);
generator2.setTargetP(0.0);
parametersExt.setReactiveRangeCheckMode(OpenLoadFlowParameters.ReactiveRangeCheckMode.MIN_MAX);
LoadFlowResult result3 = loadFlowRunner.run(network, parameters);
assertTrue(result3.isFullyConverged());
assertVoltageEquals(164.88, nload);
}
@Test
void testWithZeroReactiveKey() {
g1.newExtension(CoordinatedReactiveControlAdder.class).withQPercent(0).add();
LfNetwork lfNetwork = LfNetwork.load(network, new LfNetworkLoaderImpl(), new LfNetworkParameters()).get(0);
assertTrue(lfNetwork.getGeneratorById(g1.getId()).getRemoteControlReactiveKey().isEmpty()); // zero is fixed to empty
}
@Test
void testGeneratorRemoteReactivePowerControlInsideReactiveLimits() {
// create a basic 4-buses network
Network network = FourBusNetworkFactory.createBaseNetwork();
Generator g4 = network.getGenerator("g4");
Line l34 = network.getLine("l34");
double targetQ = 4.0;
// disable voltage control on g4
g4.setTargetQ(0.0).setVoltageRegulatorOn(false);
// first test: generator g4 regulates reactive power on line 4->3 (on side of g4)
g4.newExtension(RemoteReactivePowerControlAdder.class)
.withTargetQ(targetQ)
.withRegulatingTerminal(l34.getTerminal(TwoSides.TWO))
.withEnabled(true).add();
g4.newMinMaxReactiveLimits().setMinQ(-15.0).setMaxQ(15.0).add();
parameters.setUseReactiveLimits(true);
parametersExt.setGeneratorReactivePowerRemoteControl(true);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(-10.296, g4.getTerminal());
assertReactivePowerEquals(4.004, l34.getTerminal2());
assertEquals(0.0, Math.abs(network.getBusView().getBus("b4_vl_0").getConnectedTerminalStream().mapToDouble(Terminal::getQ).sum()), 1E-2);
}
@Test
void testGeneratorRemoteReactivePowerControlOutsideReactiveLimits() {
// create a basic 4-buses network
Network network = FourBusNetworkFactory.createBaseNetwork();
Generator g4 = network.getGenerator("g4");
Line l34 = network.getLine("l34");
double targetQ = 4.0;
// disable voltage control on g4
g4.setTargetQ(0.0).setVoltageRegulatorOn(false);
// first test: generator g4 regulates reactive power on line 4->3 (on side of g4)
g4.newExtension(RemoteReactivePowerControlAdder.class)
.withTargetQ(targetQ)
.withRegulatingTerminal(l34.getTerminal(TwoSides.TWO))
.withEnabled(true).add();
g4.newMinMaxReactiveLimits().setMinQ(-5.0).setMaxQ(5.0).add();
parameters.setUseReactiveLimits(true);
parametersExt.setGeneratorReactivePowerRemoteControl(true);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isFullyConverged());
assertReactivePowerEquals(-5.0, g4.getTerminal());
assertReactivePowerEquals(2.031, l34.getTerminal2());
assertEquals(0.0, Math.abs(network.getBusView().getBus("b4_vl_0").getConnectedTerminalStream().mapToDouble(Terminal::getQ).sum()), 1E-2);
}
}