Skip to content

Commit

Permalink
Transformer voltage control outer loop after generator control mode (#…
Browse files Browse the repository at this point in the history
…439)

Signed-off-by: Anne Tilloy <anne.tilloy@rte-france.com>
Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
  • Loading branch information
annetill authored Feb 4, 2022
1 parent 807b2fc commit 5bbf2be
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 34 deletions.
22 changes: 22 additions & 0 deletions src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ public enum VoltageInitModeOverride {

public static final VoltageInitModeOverride VOLTAGE_INIT_MODE_OVERRIDE_DEFAULT_VALUE = VoltageInitModeOverride.NONE;

public enum TransformerVoltageControlMode {
WITH_GENERATOR_VOLTAGE_CONTROL,
AFTER_GENERATOR_VOLTAGE_CONTROL
}

public static final TransformerVoltageControlMode TRANSFORMER_VOLTAGE_CONTROL_MODE_DEFAULT_VALUE = TransformerVoltageControlMode.WITH_GENERATOR_VOLTAGE_CONTROL;

private SlackBusSelectionMode slackBusSelectionMode = SLACK_BUS_SELECTION_DEFAULT_VALUE;

private List<String> slackBusesIds = Collections.emptyList();
Expand Down Expand Up @@ -109,6 +116,8 @@ public enum LowImpedanceBranchMode {

private VoltageInitModeOverride voltageInitModeOverride = VOLTAGE_INIT_MODE_OVERRIDE_DEFAULT_VALUE;

private TransformerVoltageControlMode transformerVoltageControlMode = TRANSFORMER_VOLTAGE_CONTROL_MODE_DEFAULT_VALUE;

@Override
public String getName() {
return "open-load-flow-parameters";
Expand Down Expand Up @@ -248,6 +257,15 @@ public OpenLoadFlowParameters setVoltageInitModeOverride(VoltageInitModeOverride
return this;
}

public TransformerVoltageControlMode getTransformerVoltageControlMode() {
return transformerVoltageControlMode;
}

public OpenLoadFlowParameters setTransformerVoltageControlMode(TransformerVoltageControlMode transformerVoltageControlMode) {
this.transformerVoltageControlMode = Objects.requireNonNull(transformerVoltageControlMode);
return this;
}

public static OpenLoadFlowParameters load() {
return new OpenLoadFlowConfigLoader().load(PlatformConfig.defaultConfig());
}
Expand All @@ -269,6 +287,7 @@ public String toString() {
", maxIteration=" + maxIteration +
", newtonRaphsonConvEpsPerEq=" + newtonRaphsonConvEpsPerEq +
", voltageInitModeOverride=" + voltageInitModeOverride +
", transformerVoltageControlMode=" + transformerVoltageControlMode +
')';
}

Expand Down Expand Up @@ -303,6 +322,8 @@ public static class OpenLoadFlowConfigLoader implements LoadFlowParameters.Confi

public static final String VOLTAGE_INIT_MODE_OVERRIDE_NAME = "voltageInitModeOverride";

public static final String TRANSFORMER_VOLTAGE_CONTROL_MODE_NAME = "transformerVoltageControlMode";

@Override
public OpenLoadFlowParameters load(PlatformConfig platformConfig) {
OpenLoadFlowParameters parameters = new OpenLoadFlowParameters();
Expand All @@ -325,6 +346,7 @@ public OpenLoadFlowParameters load(PlatformConfig platformConfig) {
.setMaxIteration(config.getIntProperty(MAX_ITERATION_NAME, NewtonRaphsonParameters.DEFAULT_MAX_ITERATION))
.setNewtonRaphsonConvEpsPerEq(config.getDoubleProperty(NEWTON_RAPHSON_CONV_EPS_PER_EQ_NAME, DefaultNewtonRaphsonStoppingCriteria.DEFAULT_CONV_EPS_PER_EQ))
.setVoltageInitModeOverride(config.getEnumProperty(VOLTAGE_INIT_MODE_OVERRIDE_NAME, VoltageInitModeOverride.class, VOLTAGE_INIT_MODE_OVERRIDE_DEFAULT_VALUE))
.setTransformerVoltageControlMode(config.getEnumProperty(TRANSFORMER_VOLTAGE_CONTROL_MODE_NAME, TransformerVoltageControlMode.class, TRANSFORMER_VOLTAGE_CONTROL_MODE_DEFAULT_VALUE))
);
return parameters;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Copyright (c) 2020, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.powsybl.openloadflow.ac;

import com.powsybl.openloadflow.ac.outerloop.OuterLoop;
import com.powsybl.openloadflow.ac.outerloop.OuterLoopStatus;
import com.powsybl.openloadflow.network.LfBranch;
import com.powsybl.openloadflow.network.LfNetwork;
import com.powsybl.openloadflow.network.PiModel;
import com.powsybl.openloadflow.network.TransformerVoltageControl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author Anne Tilloy <anne.tilloy at rte-france.com>
*/
public abstract class AbstractTransformerVoltageControlOuterLoop implements OuterLoop {

private static final Logger LOGGER = LoggerFactory.getLogger(AbstractTransformerVoltageControlOuterLoop.class);

protected OuterLoopStatus roundVoltageRatios(LfNetwork network) {
OuterLoopStatus status = OuterLoopStatus.STABLE;
for (LfBranch branch : network.getBranches()) {
TransformerVoltageControl voltageControl = branch.getVoltageControl().orElse(null);
if (voltageControl != null) {
branch.setVoltageControlEnabled(false);

// round the rho shift to the closest tap
PiModel piModel = branch.getPiModel();
double r1Value = piModel.getR1();
piModel.roundR1ToClosestTap();
double roundedR1Value = piModel.getR1();
LOGGER.trace("Round voltage ratio of '{}': {} -> {}", branch.getId(), r1Value, roundedR1Value);

status = OuterLoopStatus.UNSTABLE;
}
}
return status;
}

@Override
public void cleanup(LfNetwork network) {
for (LfBranch branch : network.getBranches()) {
branch.getVoltageControl().ifPresent(voltageControl -> branch.setVoltageControlEnabled(true));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ public List<OuterLoop> configure(LoadFlowParameters parameters, OpenLoadFlowPara
outerLoops.add(new ReactiveLimitsOuterLoop());
}
if (parameters.isTransformerVoltageControlOn()) {
outerLoops.add(new TransformerVoltageControlOuterLoop());
if (parametersExt.getTransformerVoltageControlMode() == OpenLoadFlowParameters.TransformerVoltageControlMode.WITH_GENERATOR_VOLTAGE_CONTROL) {
outerLoops.add(new SimpleTransformerVoltageControlOuterLoop());
} else if (parametersExt.getTransformerVoltageControlMode() == OpenLoadFlowParameters.TransformerVoltageControlMode.AFTER_GENERATOR_VOLTAGE_CONTROL) {
outerLoops.add(new TransformerVoltageControlOuterLoop());
} else {
throw new IllegalStateException("Unknown transformer voltage control mode: " + parametersExt.getTransformerVoltageControlMode());
}
}
if (parameters.isSimulShunt()) {
outerLoops.add(new ShuntVoltageControlOuterLoop());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Copyright (c) 2020, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.powsybl.openloadflow.ac;

import com.powsybl.commons.reporter.Reporter;
import com.powsybl.openloadflow.ac.outerloop.OuterLoopContext;
import com.powsybl.openloadflow.ac.outerloop.OuterLoopStatus;

/**
* @author Anne Tilloy <anne.tilloy at rte-france.com>
*/
public class SimpleTransformerVoltageControlOuterLoop extends AbstractTransformerVoltageControlOuterLoop {

@Override
public String getType() {
return "Simple transformer voltage control";
}

@Override
public OuterLoopStatus check(OuterLoopContext context, Reporter reporter) {
OuterLoopStatus status = OuterLoopStatus.STABLE;
if (context.getIteration() == 0) {
status = roundVoltageRatios(context.getNetwork());
}
return status;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,30 @@
package com.powsybl.openloadflow.ac;

import com.powsybl.commons.reporter.Reporter;
import com.powsybl.openloadflow.ac.outerloop.OuterLoop;
import com.powsybl.openloadflow.ac.outerloop.OuterLoopContext;
import com.powsybl.openloadflow.ac.outerloop.OuterLoopStatus;
import com.powsybl.openloadflow.network.LfBranch;
import com.powsybl.openloadflow.network.LfBus;
import com.powsybl.openloadflow.network.LfNetwork;
import com.powsybl.openloadflow.network.PiModel;
import com.powsybl.openloadflow.network.TransformerVoltageControl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author Anne Tilloy <anne.tilloy at rte-france.com>
*/
public class TransformerVoltageControlOuterLoop implements OuterLoop {
public class TransformerVoltageControlOuterLoop extends AbstractTransformerVoltageControlOuterLoop {

private static final Logger LOGGER = LoggerFactory.getLogger(TransformerVoltageControlOuterLoop.class);
private double maxControlledNominalVoltage = Double.MIN_VALUE;

@Override
public void initialize(LfNetwork network) {
// All transformer voltage control are disabled for the first equation system resolution.
for (LfBranch branch : network.getBranches()) {
branch.getVoltageControl().ifPresent(voltageControl -> {
branch.setVoltageControlEnabled(false);
maxControlledNominalVoltage = Math.max(maxControlledNominalVoltage, voltageControl.getControlled().getNominalV());
});
}
}

@Override
public String getType() {
Expand All @@ -32,30 +40,44 @@ public String getType() {
@Override
public OuterLoopStatus check(OuterLoopContext context, Reporter reporter) {
OuterLoopStatus status = OuterLoopStatus.STABLE;

// At first outer loop iteration, the voltage control of generators that controlled at nominal voltage of
// the set controlledNominalVoltages are disabled.
// The transformer voltage controls are enabled.
if (context.getIteration() == 0) {
for (LfBus bus : context.getNetwork().getBuses()) {
if (bus.isVoltageControlled() && bus.getNominalV() <= maxControlledNominalVoltage) {
bus.getVoltageControl().ifPresent(voltageControl -> {
voltageControl.getControllerBuses().forEach(controllerBus -> {
controllerBus.setGenerationTargetQ(controllerBus.getQ().eval());
controllerBus.setVoltageControlEnabled(false);
});
});
status = OuterLoopStatus.UNSTABLE;
}
}
for (LfBranch branch : context.getNetwork().getBranches()) {
TransformerVoltageControl voltageControl = branch.getVoltageControl().orElse(null);
if (voltageControl != null) {
branch.setVoltageControlEnabled(false);

// round the rho shift to the closest tap
PiModel piModel = branch.getPiModel();
double r1Value = piModel.getR1();
piModel.roundR1ToClosestTap();
double roundedR1Value = piModel.getR1();
LOGGER.trace("Round voltage ratio of '{}': {} -> {}", branch.getId(), r1Value, roundedR1Value);

branch.setVoltageControlEnabled(true);
status = OuterLoopStatus.UNSTABLE;
}
}
}
return status;
}

@Override
public void cleanup(LfNetwork network) {
for (LfBranch branch : network.getBranches()) {
branch.getVoltageControl().ifPresent(voltageControl -> branch.setVoltageControlEnabled(true));
// At second outer loop iteration, the transformers are rounded. The generator voltage controls that were
// disabled previously are enabled.
if (context.getIteration() == 1) {
status = roundVoltageRatios(context.getNetwork());
for (LfBus bus : context.getNetwork().getBuses()) {
if (bus.hasVoltageControllerCapability() && bus.getNominalV() <= maxControlledNominalVoltage) {
bus.setGenerationTargetQ(0);
bus.setVoltageControlEnabled(true);
status = OuterLoopStatus.UNSTABLE;
}
}
}

return status;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,18 +104,18 @@ public AcLoadFlowResult run(Reporter reporter) {
NewtonRaphson newtonRaphson = new NewtonRaphson(context.getNetwork(), context.getParameters().getNewtonRaphsonParameters(),
context.getEquationSystem(), context.getJacobianMatrix(), context.getTargetVector());

// outer loops initialization
for (OuterLoop outerLoop : context.getParameters().getOuterLoops()) {
outerLoop.initialize(context.getNetwork());
}

// run initial Newton-Raphson
runningContext.lastNrResult = newtonRaphson.run(reporter);

// continue with outer loops only if initial Newton-Raphson succeed
if (runningContext.lastNrResult.getStatus() == NewtonRaphsonStatus.CONVERGED) {
updatePvBusesReactivePower(runningContext.lastNrResult, context.getNetwork(), context.getEquationSystem());

// outer loops initialization
for (OuterLoop outerLoop : context.getParameters().getOuterLoops()) {
outerLoop.initialize(context.getNetwork());
}

// re-run all outer loops until Newton-Raphson failed or no more Newton-Raphson iterations are needed
int oldIterationCount;
do {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,21 @@ class AcLoadFlowTransformerControlTest {
private Bus bus2;
private Bus bus3;
private Bus bus4;
private Line line12;
private Line line24;
private TwoWindingsTransformer t2wt;
private TwoWindingsTransformer t2wt2;
private ThreeWindingsTransformer t3wt;
private Load load3;

private LoadFlow.Runner loadFlowRunner;
private LoadFlowParameters parameters;
private OpenLoadFlowParameters parametersExt;

@BeforeEach
void setUp() {
loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(new DenseMatrixFactory()));
parameters = new LoadFlowParameters();
parameters.setTransformerVoltageControlOn(false);
parameters.setDistributedSlack(false);
OpenLoadFlowParameters.create(parameters)
parametersExt = OpenLoadFlowParameters.create(parameters)
.setSlackBusSelectionMode(SlackBusSelectionMode.FIRST);
}

Expand Down Expand Up @@ -97,6 +95,50 @@ void voltageControlT2wtTest() {
assertEquals(3, t2wt.getRatioTapChanger().getTapPosition());
}

@Test
void voltageControlT2wtTest2() {
selectNetwork(VoltageControlNetworkFactory.createNetworkWithT2wt());

parameters.setTransformerVoltageControlOn(true);
parametersExt.setTransformerVoltageControlMode(OpenLoadFlowParameters.TransformerVoltageControlMode.AFTER_GENERATOR_VOLTAGE_CONTROL);
t2wt.getRatioTapChanger()
.setTargetDeadband(0)
.setRegulating(true)
.setTapPosition(0)
.setRegulationTerminal(t2wt.getTerminal2())
.setTargetV(34.0);

LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isOk());
assertVoltageEquals(134.281, bus2);
assertVoltageEquals(34.433, t2wt.getTerminal2().getBusView().getBus()); //FIXME: should be 34.427
assertEquals(3, t2wt.getRatioTapChanger().getTapPosition());
}

@Test
void voltageControlT2wtTest3() {
selectNetwork(VoltageControlNetworkFactory.createNetworkWithT2wt());

parameters.setTransformerVoltageControlOn(true);
t2wt.getRatioTapChanger()
.setTargetDeadband(0)
.setRegulating(true)
.setTapPosition(0)
.setRegulationTerminal(t2wt.getTerminal1())
.setTargetV(135.0);

LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertFalse(result.isOk());

parametersExt.setTransformerVoltageControlMode(OpenLoadFlowParameters.TransformerVoltageControlMode.AFTER_GENERATOR_VOLTAGE_CONTROL);
LoadFlowResult result2 = loadFlowRunner.run(network, parameters);
assertTrue(result2.isOk());

assertVoltageEquals(134.281, bus2);
assertVoltageEquals(27.0, t2wt.getTerminal2().getBusView().getBus());
assertEquals(0, t2wt.getRatioTapChanger().getTapPosition());
}

@Test
void remoteVoltageControlT2wtTest() {
selectNetwork(VoltageControlNetworkFactory.createNetworkWithT2wt());
Expand Down Expand Up @@ -615,13 +657,12 @@ private Network createNetworkWithSharedControl() {

private void selectNetwork(Network network) {
this.network = network;

bus1 = network.getBusBreakerView().getBus("BUS_1");
bus2 = network.getBusBreakerView().getBus("BUS_2");
bus3 = network.getBusBreakerView().getBus("BUS_3");
bus4 = network.getBusBreakerView().getBus("BUS_4");

line12 = network.getLine("LINE_12");

t2wt = network.getTwoWindingsTransformer("T2wT");
t3wt = network.getThreeWindingsTransformer("T3wT");
}
Expand Down
3 changes: 2 additions & 1 deletion src/test/resources/debug-parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"voltagePerReactivePowerControl" : false,
"maxIteration" : 30,
"newtonRaphsonConvEpsPerEq" : 1.0E-4,
"voltageInitModeOverride" : "NONE"
"voltageInitModeOverride" : "NONE",
"transformerVoltageControlMode" : "WITH_GENERATOR_VOLTAGE_CONTROL"
}
}
},
Expand Down

0 comments on commit 5bbf2be

Please sign in to comment.