Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Network listener #215

Merged
merged 15 commits into from
Mar 1, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,8 @@
import com.powsybl.openloadflow.ac.outerloop.OuterLoop;
import com.powsybl.openloadflow.ac.outerloop.OuterLoopContext;
import com.powsybl.openloadflow.ac.outerloop.OuterLoopStatus;
import com.powsybl.openloadflow.equations.Equation;
import com.powsybl.openloadflow.equations.EquationType;
import com.powsybl.openloadflow.equations.Variable;
import com.powsybl.openloadflow.equations.VariableType;
import com.powsybl.openloadflow.network.LfBranch;
import com.powsybl.openloadflow.network.DiscretePhaseControl;
import com.powsybl.openloadflow.network.LfBranch;
import com.powsybl.openloadflow.network.PiModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -34,12 +30,12 @@ public String getType() {
@Override
public OuterLoopStatus check(OuterLoopContext context) {
if (context.getIteration() == 0) {
// at first outerloop iteration:
// at first outer loop iteration:
// branches with active power control are switched off and taps are rounded
// branches with current limiter control will wait for second iteration
return firstIteration(context);
} else if (context.getIteration() > 0) {
// at second outerloop iteration:
// at second outer loop iteration:
// flow of branches with fixed tap are recomputed
return nextIteration(context);
}
Expand All @@ -52,8 +48,8 @@ private OuterLoopStatus firstIteration(OuterLoopContext context) {
if (branch.isPhaseControlled()) {
switch (branch.getDiscretePhaseControl().getMode()) {
case CONTROLLER:
// at firall branches with active power control are switched off
desactivateActivePowerControlEquation(context, branch);
// all branches with active power control are switched off
switchOffPhaseControl(branch);
// if at least one phase shifter has been switched off we need to continue
status = OuterLoopStatus.UNSTABLE;
break;
Expand All @@ -69,7 +65,7 @@ private OuterLoopStatus firstIteration(OuterLoopContext context) {
}

private OuterLoopStatus nextIteration(OuterLoopContext context) {
// at second outerloop iteration we switch on phase control for branches that are in limiter mode
// at second outer loop iteration we switch on phase control for branches that are in limiter mode
// and a current greater than the limit
for (LfBranch branch : context.getNetwork().getBranches()) {
if (branch.isPhaseControlled()) {
Expand All @@ -85,20 +81,12 @@ private OuterLoopStatus nextIteration(OuterLoopContext context) {
return OuterLoopStatus.STABLE;
}

private void desactivateActivePowerControlEquation(OuterLoopContext context, LfBranch branch) {
// switch off phase shifter
private void switchOffPhaseControl(LfBranch branch) {
// switch off phase control
branch.getDiscretePhaseControl().setMode(DiscretePhaseControl.Mode.OFF);

// de-activate a1 variable for next outer loop run
LfBranch controllerBranch = branch.getDiscretePhaseControl().getController();
Variable a1 = context.getVariableSet().getVariable(controllerBranch.getNum(), VariableType.BRANCH_ALPHA1);
a1.setActive(false);

// de-activate phase control equation
Equation t = context.getEquationSystem().createEquation(branch.getNum(), EquationType.BRANCH_P);
t.setActive(false);

// round the phase shift to the closest tap
LfBranch controllerBranch = branch.getDiscretePhaseControl().getController();
PiModel piModel = controllerBranch.getPiModel();
double a1Value = piModel.getA1();
piModel.roundA1ToClosestTap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,9 @@
*/
package com.powsybl.openloadflow.ac;

import com.powsybl.openloadflow.ac.equations.AcEquationSystem;
import com.powsybl.openloadflow.ac.outerloop.OuterLoop;
import com.powsybl.openloadflow.ac.outerloop.OuterLoopContext;
import com.powsybl.openloadflow.ac.outerloop.OuterLoopStatus;
import com.powsybl.openloadflow.equations.Equation;
import com.powsybl.openloadflow.equations.EquationSystem;
import com.powsybl.openloadflow.equations.EquationType;
import com.powsybl.openloadflow.equations.VariableSet;
import com.powsybl.openloadflow.network.LfBus;
import com.powsybl.openloadflow.network.PerUnit;
import org.apache.commons.lang3.mutable.MutableInt;
Expand All @@ -23,7 +18,6 @@
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
* @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
Expand Down Expand Up @@ -51,38 +45,6 @@ public String getType() {
return "Reactive limits";
}

public static void switchPvPq(LfBus bus, EquationSystem equationSystem, VariableSet variableSet, double newGenerationTargetQ) {
bus.setGenerationTargetQ(newGenerationTargetQ);
bus.setVoltageControl(false);

Equation qEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_Q);
qEq.setActive(true);

LfBus controlledBus = bus.getControlledBus().orElse(null);
if (controlledBus != null) {
updateControlledBus(controlledBus, equationSystem, variableSet);
} else {
Equation vEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V);
vEq.setActive(false);
}
}

public static void updateControlledBus(LfBus controlledBus, EquationSystem equationSystem, VariableSet variableSet) {
// clean reactive power distribution equations
controlledBus.getControllerBuses().forEach(b -> equationSystem.removeEquation(b.getNum(), EquationType.ZERO_Q));

// controlled bus has a voltage equation only if one of the controller bus has voltage control on
List<LfBus> controllerBusesWithVoltageControlOn = controlledBus.getControllerBuses().stream()
.filter(LfBus::hasVoltageControl)
.collect(Collectors.toList());
equationSystem.createEquation(controlledBus.getNum(), EquationType.BUS_V).setActive(!controllerBusesWithVoltageControlOn.isEmpty());

// create reactive power equations on controller buses that have voltage control on
if (!controllerBusesWithVoltageControlOn.isEmpty()) {
AcEquationSystem.createReactivePowerDistributionEquations(equationSystem, variableSet, controllerBusesWithVoltageControlOn);
}
}

private enum ReactiveLimitDirection {
MIN,
MAX
Expand All @@ -106,7 +68,7 @@ private PvToPqBus(LfBus bus, double q, double qLimit, ReactiveLimitDirection lim
}
}

private boolean switchPvPq(List<PvToPqBus> pvToPqBuses, EquationSystem equationSystem, VariableSet variableSet, int remainingPvBusCount) {
private boolean switchPvPq(List<PvToPqBus> pvToPqBuses, int remainingPvBusCount) {
boolean done = false;

int modifiedRemainingPvBusCount = remainingPvBusCount;
Expand All @@ -128,7 +90,8 @@ private boolean switchPvPq(List<PvToPqBus> pvToPqBuses, EquationSystem equationS

for (PvToPqBus pvToPqBus : pvToPqBuses) {
// switch PV -> PQ
switchPvPq(pvToPqBus.bus, equationSystem, variableSet, pvToPqBus.qLimit);
pvToPqBus.bus.setGenerationTargetQ(pvToPqBus.qLimit);
pvToPqBus.bus.setVoltageControl(false);

if (LOGGER.isTraceEnabled()) {
if (pvToPqBus.limitDirection == ReactiveLimitDirection.MAX) {
Expand All @@ -147,22 +110,6 @@ private boolean switchPvPq(List<PvToPqBus> pvToPqBuses, EquationSystem equationS
return done;
}

public static void switchPqPv(LfBus bus, EquationSystem equationSystem, VariableSet variableSet) {
bus.setVoltageControl(true);
bus.setGenerationTargetQ(0);

Equation qEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_Q);
qEq.setActive(false);

LfBus controlledBus = bus.getControlledBus().orElse(null);
if (controlledBus != null) {
updateControlledBus(controlledBus, equationSystem, variableSet);
} else {
Equation vEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V);
vEq.setActive(true);
}
}

private static final class PqToPvBus {

private final LfBus bus;
Expand All @@ -175,7 +122,7 @@ private PqToPvBus(LfBus bus, ReactiveLimitDirection limitDirection) {
}
}

private boolean switchPqPv(List<PqToPvBus> pqToPvBuses, EquationSystem equationSystem, VariableSet variableSet) {
private boolean switchPqPv(List<PqToPvBus> pqToPvBuses) {
int pqPvSwitchCount = 0;

for (PqToPvBus pqToPvBus : pqToPvBuses) {
Expand All @@ -185,7 +132,8 @@ private boolean switchPqPv(List<PqToPvBus> pqToPvBuses, EquationSystem equationS
LOGGER.trace("Bus '{}' blocked PQ as it has reach its max number of PQ -> PV switch ({})",
bus.getId(), bus.getVoltageControlSwitchOffCount());
} else {
switchPqPv(bus, equationSystem, variableSet);
bus.setVoltageControl(true);
bus.setGenerationTargetQ(0);
pqPvSwitchCount++;

if (LOGGER.isTraceEnabled()) {
Expand Down Expand Up @@ -256,10 +204,10 @@ public OuterLoopStatus check(OuterLoopContext context) {
}
}

if (!pvToPqBuses.isEmpty() && switchPvPq(pvToPqBuses, context.getEquationSystem(), context.getVariableSet(), remainingPvBusCount.intValue())) {
if (!pvToPqBuses.isEmpty() && switchPvPq(pvToPqBuses, remainingPvBusCount.intValue())) {
status = OuterLoopStatus.UNSTABLE;
}
if (!pqToPvBuses.isEmpty() && switchPqPv(pqToPvBuses, context.getEquationSystem(), context.getVariableSet())) {
if (!pqToPvBuses.isEmpty() && switchPqPv(pqToPvBuses)) {
status = OuterLoopStatus.UNSTABLE;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,13 @@
*/
package com.powsybl.openloadflow.ac;

import com.powsybl.openloadflow.equations.Equation;
import com.powsybl.openloadflow.equations.EquationType;
import com.powsybl.openloadflow.equations.Variable;
import com.powsybl.openloadflow.equations.VariableType;
import com.powsybl.openloadflow.ac.outerloop.OuterLoop;
import com.powsybl.openloadflow.ac.outerloop.OuterLoopContext;
import com.powsybl.openloadflow.ac.outerloop.OuterLoopStatus;
import com.powsybl.openloadflow.network.DiscreteVoltageControl;
import com.powsybl.openloadflow.network.LfBranch;
import com.powsybl.openloadflow.network.LfBus;
import com.powsybl.openloadflow.network.PiModel;
import com.powsybl.openloadflow.ac.outerloop.OuterLoop;
import com.powsybl.openloadflow.ac.outerloop.OuterLoopContext;
import com.powsybl.openloadflow.ac.outerloop.OuterLoopStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -39,19 +35,10 @@ public OuterLoopStatus check(OuterLoopContext context) {
if (context.getIteration() == 0) {
for (LfBus bus : context.getNetwork().getBuses()) {
if (bus.isDiscreteVoltageControlled()) {
// de-activate transformer voltage control equation
Equation t = context.getEquationSystem().createEquation(bus.getNum(), EquationType.BUS_V);
t.setActive(false);
// switch off regulating transformers
bus.getDiscreteVoltageControl().setMode(DiscreteVoltageControl.Mode.OFF);

// at first iteration all branches controlling voltage are switched off
for (LfBranch controllerBranch : bus.getDiscreteVoltageControl().getControllers()) {
// de-activate r1 variable for next outer loop run
Variable r1 = context.getVariableSet().getVariable(controllerBranch.getNum(), VariableType.BRANCH_RHO1);
r1.setActive(false);

// clean transformer distribution equations
context.getEquationSystem().removeEquation(controllerBranch.getNum(), EquationType.ZERO_RHO1);

// round the rho shift to the closest tap
PiModel piModel = controllerBranch.getPiModel();
double r1Value = piModel.getR1();
Expand All @@ -60,9 +47,6 @@ public OuterLoopStatus check(OuterLoopContext context) {
LOGGER.trace("Round voltage shift of '{}': {} -> {}", controllerBranch.getId(), r1Value, roundedR1Value);
}

// switch off regulating transformers
bus.getDiscreteVoltageControl().setMode(DiscreteVoltageControl.Mode.OFF);

// if at least one transformer has been switched off wee need to continue
status = OuterLoopStatus.UNSTABLE;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
package com.powsybl.openloadflow.ac.equations;

import com.powsybl.commons.PowsyblException;
import com.powsybl.openloadflow.dc.equations.BranchA1EquationTerm;
import com.powsybl.openloadflow.dc.equations.DcEquationSystem;
import com.powsybl.openloadflow.equations.*;
import com.powsybl.openloadflow.network.*;
Expand Down Expand Up @@ -357,6 +356,8 @@ public static EquationSystem create(LfNetwork network, VariableSet variableSet,
createBusEquations(network, variableSet, creationParameters, equationSystem);
createBranchEquations(network, variableSet, creationParameters, equationSystem);

network.addListener(new AcEquationSystemUpdater(equationSystem, variableSet));

return equationSystem;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* Copyright (c) 2021, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.powsybl.openloadflow.ac.equations;

import com.powsybl.openloadflow.equations.*;
import com.powsybl.openloadflow.network.*;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
* @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
*/
public class AcEquationSystemUpdater implements LfNetworkListener {

private final EquationSystem equationSystem;

private final VariableSet variableSet;

public AcEquationSystemUpdater(EquationSystem equationSystem, VariableSet variableSet) {
this.equationSystem = Objects.requireNonNull(equationSystem);
this.variableSet = Objects.requireNonNull(variableSet);
}

private static void updateControlledBus(LfBus controlledBus, EquationSystem equationSystem, VariableSet variableSet) {
// clean reactive power distribution equations
controlledBus.getControllerBuses().forEach(b -> equationSystem.removeEquation(b.getNum(), EquationType.ZERO_Q));

// controlled bus has a voltage equation only if one of the controller bus has voltage control on
List<LfBus> controllerBusesWithVoltageControlOn = controlledBus.getControllerBuses().stream()
.filter(LfBus::hasVoltageControl)
.collect(Collectors.toList());
equationSystem.createEquation(controlledBus.getNum(), EquationType.BUS_V).setActive(!controllerBusesWithVoltageControlOn.isEmpty());

// create reactive power equations on controller buses that have voltage control on
if (!controllerBusesWithVoltageControlOn.isEmpty()) {
AcEquationSystem.createReactivePowerDistributionEquations(equationSystem, variableSet, controllerBusesWithVoltageControlOn);
}
}

@Override
public void onVoltageControlChange(LfBus bus, boolean newVoltageControl) {
if (newVoltageControl) { // switch PQ/PV
Equation qEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_Q);
qEq.setActive(false);

LfBus controlledBus = bus.getControlledBus().orElse(null);
if (controlledBus != null) {
updateControlledBus(controlledBus, equationSystem, variableSet);
} else {
Equation vEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V);
vEq.setActive(true);
}
} else { // switch PV/PQ
Equation qEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_Q);
qEq.setActive(true);

LfBus controlledBus = bus.getControlledBus().orElse(null);
if (controlledBus != null) {
updateControlledBus(controlledBus, equationSystem, variableSet);
} else {
Equation vEq = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V);
vEq.setActive(false);
}
}
}

@Override
public void onPhaseControlModeChange(DiscretePhaseControl phaseControl, DiscretePhaseControl.Mode oldMode, DiscretePhaseControl.Mode newMode) {
if (newMode == DiscretePhaseControl.Mode.OFF) {
// de-activate a1 variable
Variable a1 = variableSet.getVariable(phaseControl.getController().getNum(), VariableType.BRANCH_ALPHA1);
a1.setActive(false);

// de-activate phase control equation
Equation t = equationSystem.createEquation(phaseControl.getControlled().getNum(), EquationType.BRANCH_P);
t.setActive(false);
} else {
throw new UnsupportedOperationException("TODO");
}
}

@Override
public void onVoltageControlModeChange(DiscreteVoltageControl voltageControl, DiscreteVoltageControl.Mode oldMode, DiscreteVoltageControl.Mode newMode) {
if (newMode == DiscreteVoltageControl.Mode.OFF) {
LfBus bus = voltageControl.getControlled();

// de-activate transformer voltage control equation
Equation t = equationSystem.createEquation(bus.getNum(), EquationType.BUS_V);
t.setActive(false);

for (LfBranch controllerBranch : bus.getDiscreteVoltageControl().getControllers()) {
// de-activate r1 variable
Variable r1 = variableSet.getVariable(controllerBranch.getNum(), VariableType.BRANCH_RHO1);
r1.setActive(false);

// clean transformer distribution equations
equationSystem.removeEquation(controllerBranch.getNum(), EquationType.ZERO_RHO1);
}
} else {
throw new UnsupportedOperationException("TODO");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ private void runOuterLoop(OuterLoop outerLoop, LfNetwork network, EquationSystem
MutableInt outerLoopIteration = runningContext.outerLoopIterationByType.computeIfAbsent(outerLoop.getType(), k -> new MutableInt());

// check outer loop status
outerLoopStatus = outerLoop.check(new OuterLoopContext(outerLoopIteration.getValue(), network, equationSystem, variableSet, runningContext.lastNrResult));
outerLoopStatus = outerLoop.check(new OuterLoopContext(outerLoopIteration.getValue(), network, runningContext.lastNrResult));

if (outerLoopStatus == OuterLoopStatus.UNSTABLE) {
LOGGER.debug("Start outer loop iteration {} (name='{}')", outerLoopIteration, outerLoop.getType());
Expand Down
Loading