Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/main/java/com/powsybl/openloadflow/NetworkCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ private CacheUpdateResult onGeneratorUpdate(Generator generator, String attribut
} else {
context.getNetwork().getGeneratorById(generator.getId()).setGeneratorControlType(LfGenerator.GeneratorControlType.OFF);
if (lfBus.getGenerators().stream().noneMatch(gen -> gen.getGeneratorControlType() == LfGenerator.GeneratorControlType.VOLTAGE)) {
lfBus.setGeneratorVoltageControlEnabled(false);
lfBus.setGeneratorVoltageControlEnabledAndRecomputeTargetQ(false);
}
}
context.getNetwork().validate(LoadFlowModel.AC, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ private static void switchPqPv(List<PqToPvBus> pqToPvBuses, ReportNode reportNod
for (PqToPvBus pqToPvBus : pqToPvBuses) {
LfBus controllerBus = pqToPvBus.controllerBus;

controllerBus.setGeneratorVoltageControlEnabled(true);
controllerBus.invalidateGenerationTargetQ();
controllerBus.setGeneratorVoltageControlEnabledAndRecomputeTargetQ(true);
double newTargetV;
if (pqToPvBus.voltageLimitDirection == VoltageLimitDirection.MAX
|| pqToPvBus.voltageLimitDirection == VoltageLimitDirection.MIN) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,7 @@ private boolean switchPvPq(List<ControllerBusToPqBus> pvToPqBuses, int remaining
LfBus controllerBus = pvToPqBus.controllerBus;

// switch PV -> PQ
controllerBus.setGeneratorVoltageControlEnabled(false);
controllerBus.freezeGenerationTargetQ(pvToPqBus.qLimit);
controllerBus.freezeGenerationTargetQAndDisableGeneratorVoltageControl(pvToPqBus.qLimit);
controllerBus.setQLimitType(pvToPqBus.limitType);
// increment PV -> PQ switch counter
contextData.incrementPvPqSwitchCount(controllerBus.getId());
Expand Down Expand Up @@ -197,8 +196,7 @@ private static boolean switchPqPv(List<PqToPvBus> pqToPvBuses, ContextData conte
if (pvPqSwitchCount >= maxPqPvSwitch) {
pqPvNodes.add(Reports.createRootReportPvPqSwitchLimit(reportNode, controllerBus, pvPqSwitchCount, log, LOGGER));
} else {
controllerBus.setGeneratorVoltageControlEnabled(true);
controllerBus.invalidateGenerationTargetQ();
controllerBus.setGeneratorVoltageControlEnabledAndRecomputeTargetQ(true);
controllerBus.setQLimitType(null);
pqPvSwitchCount++;

Expand Down Expand Up @@ -321,7 +319,7 @@ private void checkPqBus(LfBus controllerCapableBus, List<PqToPvBus> pqToPvBuses,
pqToPvBuses.add(new PqToPvBus(controllerCapableBus, LfBus.QLimitType.MIN_Q));
} else if (qLimitType == LfBus.QLimitType.MIN_Q && Math.abs(minQ - q) > maxReactivePowerMismatch) {
LOGGER.trace("PQ bus {} with updated Q limits, previous minQ {} new minQ {}", controllerCapableBus.getId(), q, minQ);
controllerCapableBus.freezeGenerationTargetQ(minQ);
controllerCapableBus.freezeGenerationTargetQAndDisableGeneratorVoltageControl(minQ);
busesWithUpdatedQLimits.add(controllerCapableBus);
}
} else if (qLimitType.isMaxLimit()) {
Expand All @@ -330,7 +328,7 @@ private void checkPqBus(LfBus controllerCapableBus, List<PqToPvBus> pqToPvBuses,
pqToPvBuses.add(new PqToPvBus(controllerCapableBus, LfBus.QLimitType.MAX_Q));
} else if (qLimitType == LfBus.QLimitType.MAX_Q && Math.abs(maxQ - q) > maxReactivePowerMismatch) {
LOGGER.trace("PQ bus {} with updated Q limits, previous maxQ {} new maxQ {}", controllerCapableBus.getId(), q, maxQ);
controllerCapableBus.freezeGenerationTargetQ(maxQ);
controllerCapableBus.freezeGenerationTargetQAndDisableGeneratorVoltageControl(maxQ);
busesWithUpdatedQLimits.add(controllerCapableBus);
}
}
Expand All @@ -348,7 +346,7 @@ private boolean switchReactiveControllerBusPq(List<ControllerBusToPqBus> reactiv
LfBus controllerBus = bus.controllerBus;

controllerBus.setGeneratorReactivePowerControlEnabled(false);
controllerBus.freezeGenerationTargetQ(bus.qLimit);
controllerBus.freezeGenerationTargetQAndDisableGeneratorVoltageControl(bus.qLimit);
switchCount++;

switch (bus.limitType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ public void disableGeneratorVoltageControlsUnderMaxControlledNominalVoltage(LfNe
var voltageControl = bus.getGeneratorVoltageControl().orElseThrow();
for (LfBus controllerBus : voltageControl.getMergedControllerElements()) {
if (controllerBus.isGeneratorVoltageControlEnabled() && !hasStepUpTransformers(controllerBus, minNominalVoltageLimit)) {
controllerBus.setGeneratorVoltageControlEnabled(false);
controllerBus.freezeGenerationTargetQ(controllerBus.getQ().eval());
controllerBus.freezeGenerationTargetQAndDisableGeneratorVoltageControl(controllerBus.getQ().eval());
disabledControllerBuses.add(controllerBus);
}
}
Expand All @@ -82,8 +81,7 @@ public void disableGeneratorVoltageControlsUnderMaxControlledNominalVoltage(LfNe
*/
public void enableGeneratorVoltageControlsUnderMaxControlledNominalVoltage() {
for (LfBus controllerBus : disabledControllerBuses) {
controllerBus.setGeneratorVoltageControlEnabled(true);
controllerBus.invalidateGenerationTargetQ();
controllerBus.setGeneratorVoltageControlEnabledAndRecomputeTargetQ(true);
}
}

Expand Down
6 changes: 2 additions & 4 deletions src/main/java/com/powsybl/openloadflow/network/BusState.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,9 @@ public void restore() {
super.restore();
element.setAngle(angle);
element.setV(voltage);
element.setGeneratorVoltageControlEnabled(voltageControlEnabled);
element.setGeneratorVoltageControlEnabledAndRecomputeTargetQ(voltageControlEnabled);
if (isGenerationTargetQFrozen) {
element.freezeGenerationTargetQ(generationTargetQ);
} else {
element.invalidateGenerationTargetQ();
element.freezeGenerationTargetQAndDisableGeneratorVoltageControl(generationTargetQ);
}
element.setGeneratorReactivePowerControlEnabled(reactiveControlEnabled);
if (shuntVoltageControlEnabled != null) {
Expand Down
6 changes: 2 additions & 4 deletions src/main/java/com/powsybl/openloadflow/network/LfBus.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public boolean isMaxLimit() {

boolean isGeneratorVoltageControlEnabled();

void setGeneratorVoltageControlEnabled(boolean generatorVoltageControlEnabled);
void setGeneratorVoltageControlEnabledAndRecomputeTargetQ(boolean generatorVoltageControlEnabled);

// generator reactive power control

Expand Down Expand Up @@ -133,15 +133,13 @@ public boolean isMaxLimit() {

void invalidateGenerationTargetP();

void invalidateGenerationTargetQ();

double getGenerationTargetP();

double getMaxP();

double getGenerationTargetQ();

void freezeGenerationTargetQ(double generationTargetQ);
void freezeGenerationTargetQAndDisableGeneratorVoltageControl(double generationTargetQ);

boolean isGenerationTargetQFrozen();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,6 @@ private void processLostGenerators(boolean updateAcQuantities) {
generator.setGeneratorControlType(LfGenerator.GeneratorControlType.OFF);
bus.getGeneratorVoltageControl().ifPresent(GeneratorVoltageControl::updateReactiveKeys);
bus.getGeneratorReactivePowerControl().ifPresent(GeneratorReactivePowerControl::updateReactiveKeys);
} else {
bus.invalidateGenerationTargetQ();
}
if (generator instanceof LfStaticVarCompensator svc) {
svc.getStandByAutomatonShunt().ifPresent(svcShunt -> {
Expand All @@ -214,7 +212,7 @@ private void processLostGenerators(boolean updateAcQuantities) {
// Only AC quantities
for (LfBus bus : generatorBuses) {
if (bus.getGenerators().stream().noneMatch(gen -> gen.getGeneratorControlType() == LfGenerator.GeneratorControlType.VOLTAGE)) {
bus.setGeneratorVoltageControlEnabled(false);
bus.setGeneratorVoltageControlEnabledAndRecomputeTargetQ(false);
}
if (bus.getGenerators().stream().noneMatch(gen -> gen.getGeneratorControlType() == LfGenerator.GeneratorControlType.REMOTE_REACTIVE_POWER)) {
bus.setGeneratorReactivePowerControlEnabled(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public void tryToReEnableHelpfulControllerBuses() {
// the secondary voltage control to get a reactive power alignment
if (!controllerBusesToLimit.isEmpty() && controllerBusesToLimit.size() < allControllerBuses.size()) {
for (LfBus controllerBus : controllerBusesToLimit) {
controllerBus.setGeneratorVoltageControlEnabled(true);
controllerBus.setGeneratorVoltageControlEnabledAndRecomputeTargetQ(true);
controllerBus.setQLimitType(null);
}
LOGGER.debug("Secondary voltage control of zone '{}': controller buses {} have been re-enabled because might help to reach pilot bus target",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,7 @@ public boolean isGeneratorVoltageControlEnabled() {
return generatorVoltageControlEnabled;
}

@Override
public void setGeneratorVoltageControlEnabled(boolean generatorVoltageControlEnabled) {
private void setGeneratorVoltageControlEnabled(boolean generatorVoltageControlEnabled) {
if (this.generatorVoltageControlEnabled != generatorVoltageControlEnabled) {
this.generatorVoltageControlEnabled = generatorVoltageControlEnabled;
for (LfNetworkListener listener : network.getListeners()) {
Expand All @@ -279,9 +278,15 @@ public void setGeneratorVoltageControlEnabled(boolean generatorVoltageControlEna
}
}

@Override
public void setGeneratorVoltageControlEnabledAndRecomputeTargetQ(boolean generatorVoltageControlEnabled) {
setGeneratorVoltageControlEnabled(generatorVoltageControlEnabled);
invalidateGenerationTargetQ();
}

@Override
public void setVoltageControlEnabled(boolean enabled) {
setGeneratorVoltageControlEnabled(enabled);
setGeneratorVoltageControlEnabledAndRecomputeTargetQ(enabled);
}

private static LfLoadModel createLfLoadModel(LoadModel loadModel, LfNetworkParameters parameters) {
Expand Down Expand Up @@ -405,7 +410,7 @@ public void invalidateGenerationTargetP() {
}
}

public void invalidateGenerationTargetQ() {
private void invalidateGenerationTargetQ() {
// If generationTargetQ was frozen, it is now freed. generationTargetQ is computed according to its definition in getGenerationTargetQ()
invalidatedGenerationTargetQ = true;
isGenerationTargetQFrozen = false;
Expand Down Expand Up @@ -449,14 +454,11 @@ public double getGenerationTargetQ() {
}

@Override
public void freezeGenerationTargetQ(double generationTargetQ) {
// This is only used in case of PV bus switched to PQ bus (Reactive limit outerloop) or in the transformer voltage control algorithm
if (!isGeneratorVoltageControlEnabled()) {
updateGenerationTargetQ(generationTargetQ, this.generationTargetQ);
isGenerationTargetQFrozen = true;
} else {
throw new PowsyblException("Generation targetQ cannot be frozen if generatorVoltageControl is enabled");
}
public void freezeGenerationTargetQAndDisableGeneratorVoltageControl(double generationTargetQ) {
// This is only used in case of PV bus switched to PQ bus
setGeneratorVoltageControlEnabled(false);
updateGenerationTargetQ(generationTargetQ, this.generationTargetQ);
isGenerationTargetQFrozen = true;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ private static void createGeneratorVoltageControl(LfBus controlledBus, LfBus con
voltageControls.add(voltageControl);
}
if (controllerBus.getGenerators().stream().anyMatch(gen -> gen.getGeneratorControlType() == LfGenerator.GeneratorControlType.MONITORING_VOLTAGE)) {
controllerBus.setGeneratorVoltageControlEnabled(false);
controllerBus.setGeneratorVoltageControlEnabledAndRecomputeTargetQ(false);
}
}

Expand All @@ -195,12 +195,11 @@ private static void updateGeneratorVoltageControl(GeneratorVoltageControl voltag
}

private static void discardGeneratorVoltageControl(LfBus controllerBus) {
controllerBus.setGeneratorVoltageControlEnabled(false);
controllerBus.setGeneratorVoltageControlEnabledAndRecomputeTargetQ(false);
controllerBus.getGenerators()
.stream()
.filter(lfGenerator -> lfGenerator.getGeneratorControlType() == LfGenerator.GeneratorControlType.VOLTAGE)
.forEach(lfGenerator -> lfGenerator.setGeneratorControlType(LfGenerator.GeneratorControlType.OFF));
controllerBus.invalidateGenerationTargetQ();
}

private static void checkGeneratorsWithSlope(GeneratorVoltageControl voltageControl) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.report.ReportNode;
import com.powsybl.commons.test.PowsyblTestReportResourceBundle;
import com.powsybl.computation.local.LocalComputationManager;
import com.powsybl.contingency.Contingency;
import com.powsybl.ieeecdf.converter.IeeeCdfNetworkFactory;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.PilotPoint;
Expand All @@ -19,14 +19,19 @@
import com.powsybl.loadflow.LoadFlow;
import com.powsybl.loadflow.LoadFlowParameters;
import com.powsybl.loadflow.LoadFlowResult;
import com.powsybl.loadflow.LoadFlowRunParameters;
import com.powsybl.math.matrix.DenseMatrixFactory;
import com.powsybl.openloadflow.OpenLoadFlowParameters;
import com.powsybl.openloadflow.OpenLoadFlowProvider;
import com.powsybl.openloadflow.graph.EvenShiloachGraphDecrementalConnectivityFactory;
import com.powsybl.openloadflow.network.LfNetwork;
import com.powsybl.openloadflow.network.LfNetworkParameters;
import com.powsybl.openloadflow.network.LfSecondaryVoltageControl;
import com.powsybl.openloadflow.network.impl.LfNetworkLoaderImpl;
import com.powsybl.openloadflow.sa.OpenSecurityAnalysisProvider;
import com.powsybl.openloadflow.util.report.PowsyblOpenLoadFlowReportResourceBundle;
import com.powsybl.security.SecurityAnalysisParameters;
import com.powsybl.security.SecurityAnalysisRunParameters;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -54,6 +59,8 @@ class SecondaryVoltageControlTest {

private LoadFlow.Runner loadFlowRunner;

private LoadFlowRunParameters loadFlowRunParameters;

private LoadFlowParameters parameters;

private OpenLoadFlowParameters parametersExt;
Expand All @@ -78,6 +85,7 @@ void setUp() {
parameters = new LoadFlowParameters();
parametersExt = OpenLoadFlowParameters.create(parameters)
.setMaxPlausibleTargetVoltage(1.6);
loadFlowRunParameters = new LoadFlowRunParameters().setParameters(parameters);
}

private static double qToK(Generator g) {
Expand Down Expand Up @@ -176,8 +184,7 @@ void testReactiveLimits() {
assertReactivePowerEquals(6, g8.getTerminal()); // [-6, 200] => qmin
}

@Test
void testUnblockGeneratorFromLimit() throws IOException {
void modifyNetworkToUnblockGeneratorFromLimit() {
network.newExtension(SecondaryVoltageControlAdder.class)
.newControlZone()
.withName("z1")
Expand All @@ -190,7 +197,11 @@ void testUnblockGeneratorFromLimit() throws IOException {
// to put g6 and g8 at q min
g6.setTargetV(11.8);
g8.setTargetV(19.5);
}

@Test
void testUnblockGeneratorFromLimit() throws IOException {
modifyNetworkToUnblockGeneratorFromLimit();
// This scenario works if the slack distribution fails and an injection is added at the slack bus
parametersExt.setPlausibleActivePowerLimit(5000); // Remove large generators from slack distribution
parametersExt.setSlackDistributionFailureBehavior(OpenLoadFlowParameters.SlackDistributionFailureBehavior.LEAVE_ON_SLACK_BUS);
Expand All @@ -203,7 +214,8 @@ void testUnblockGeneratorFromLimit() throws IOException {
.build();

// try to put g6 and g8 at qmax to see if they are correctly unblock from qmin
var result = loadFlowRunner.run(network, network.getVariantManager().getWorkingVariantId(), LocalComputationManager.getDefault(), parameters, node);
loadFlowRunParameters.setReportNode(node);
var result = loadFlowRunner.run(network, loadFlowRunParameters);
assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus());
assertEquals(14, result.getComponentResults().get(0).getIterationCount());

Expand Down Expand Up @@ -258,19 +270,29 @@ AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STA
}

@Test
void testCannotUnblockGeneratorFromLimit() throws IOException {
network.newExtension(SecondaryVoltageControlAdder.class)
.newControlZone()
.withName("z1")
.newPilotPoint().withTargetV(15).withBusbarSectionsOrBusesIds(List.of("B10")).add()
.newControlUnit().withId("B6-G").add()
.newControlUnit().withId("B8-G").add()
.add()
.add();
void testSecurityAnalysisWithUnblockedGenerator() {
modifyNetworkToUnblockGeneratorFromLimit();

// to put g6 and g8 at q min
g6.setTargetV(11.8);
g8.setTargetV(19.5);
// Pilot point is set to test unblocking of generators without them turning back PQ
network.getExtension(SecondaryVoltageControl.class)
.getControlZone("z1").orElseThrow().getPilotPoint().setTargetV(14.95);

parametersExt.setPlausibleActivePowerLimit(5000); // Remove large generators from slack distribution
parametersExt.setSlackDistributionFailureBehavior(OpenLoadFlowParameters.SlackDistributionFailureBehavior.LEAVE_ON_SLACK_BUS);
parametersExt.setSecondaryVoltageControl(true);

List<Contingency> contingencies = List.of(Contingency.branch("L1-2-1"), Contingency.branch("L1-5-1"));
OpenSecurityAnalysisProvider securityAnalysisProvider = new OpenSecurityAnalysisProvider(new DenseMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>());
assertDoesNotThrow(() -> securityAnalysisProvider.run(network,
network.getVariantManager().getWorkingVariantId(),
n -> contingencies,
new SecurityAnalysisRunParameters().
setSecurityAnalysisParameters(new SecurityAnalysisParameters().setLoadFlowParameters(parameters))).join());
}

@Test
void testCannotUnblockGeneratorFromLimit() throws IOException {
modifyNetworkToUnblockGeneratorFromLimit();

parametersExt.setSecondaryVoltageControl(true);
parametersExt.setReactiveLimitsMaxPqPvSwitch(0); // Will block PQ->PV move
Expand All @@ -281,7 +303,8 @@ void testCannotUnblockGeneratorFromLimit() throws IOException {
.build();

// try to put g6 and g8 at qmax to see if they are correctly unblock from qmin
var result = loadFlowRunner.run(network, network.getVariantManager().getWorkingVariantId(), LocalComputationManager.getDefault(), parameters, node);
loadFlowRunParameters.setReportNode(node);
var result = loadFlowRunner.run(network, loadFlowRunParameters);
assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus());
assertEquals(11, result.getComponentResults().get(0).getIterationCount());

Expand Down
Loading