Skip to content

Commit

Permalink
Refactor DC Outer Loops creation (#1158)
Browse files Browse the repository at this point in the history
Signed-off-by: vmouradian <[email protected]>
  • Loading branch information
vmouradian authored Jan 16, 2025
1 parent fbec503 commit b988c72
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 85 deletions.
24 changes: 21 additions & 3 deletions src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@
import com.powsybl.openloadflow.ac.solver.*;
import com.powsybl.openloadflow.ac.outerloop.AcOuterLoop;
import com.powsybl.openloadflow.ac.outerloop.ReactiveLimitsOuterLoop;
import com.powsybl.openloadflow.dc.DcAreaInterchangeControlOuterLoop;
import com.powsybl.openloadflow.dc.DcIncrementalPhaseControlOuterLoop;
import com.powsybl.openloadflow.dc.DcLoadFlowParameters;
import com.powsybl.openloadflow.dc.DcOuterLoop;
import com.powsybl.openloadflow.dc.DcValueVoltageInitializer;
import com.powsybl.openloadflow.dc.equations.DcApproximationType;
import com.powsybl.openloadflow.dc.equations.DcEquationSystemCreationParameters;
import com.powsybl.openloadflow.graph.GraphConnectivityFactory;
import com.powsybl.openloadflow.lf.AbstractLoadFlowParameters;
import com.powsybl.openloadflow.network.*;
import com.powsybl.openloadflow.network.util.ActivePowerDistribution;
import com.powsybl.openloadflow.network.util.PreviousValueVoltageInitializer;
import com.powsybl.openloadflow.network.util.UniformValueVoltageInitializer;
import com.powsybl.openloadflow.network.util.VoltageInitializer;
Expand Down Expand Up @@ -1816,7 +1820,7 @@ public static AcLoadFlowParameters createAcParameters(Network network, LoadFlowP
return acParameters;
}

static List<AcOuterLoop> createOuterLoops(LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt) {
static List<AcOuterLoop> createAcOuterLoops(LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt) {
AcOuterLoopConfig outerLoopConfig = AcOuterLoopConfig.findOuterLoopConfig()
.orElseGet(() -> parametersExt.getOuterLoopNames() != null ? new ExplicitAcOuterLoopConfig()
: new DefaultAcOuterLoopConfig());
Expand All @@ -1835,7 +1839,7 @@ public static AcLoadFlowParameters createAcParameters(LoadFlowParameters paramet

VoltageInitializer voltageInitializer = getExtendedVoltageInitializer(parameters, parametersExt, networkParameters, matrixFactory);

List<AcOuterLoop> outerLoops = createOuterLoops(parameters, parametersExt);
List<AcOuterLoop> outerLoops = createAcOuterLoops(parameters, parametersExt);

AcSolverFactory solverFactory = AcSolverFactory.find(parametersExt.getAcSolverType());

Expand All @@ -1851,6 +1855,20 @@ public static AcLoadFlowParameters createAcParameters(LoadFlowParameters paramet
.setSolverFactory(solverFactory, parameters);
}

static List<DcOuterLoop> createDcOuterLoops(LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt) {
List<DcOuterLoop> outerLoops = new ArrayList<>();
if (parameters.isPhaseShifterRegulationOn()) {
DcIncrementalPhaseControlOuterLoop phaseShifterControlOuterLoop = new DcIncrementalPhaseControlOuterLoop();
outerLoops.add(phaseShifterControlOuterLoop);
}
if (parametersExt.isAreaInterchangeControl()) {
ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(parameters.getBalanceType(), false, parametersExt.isUseActiveLimits());
DcAreaInterchangeControlOuterLoop areaInterchangeControlOuterLoop = new DcAreaInterchangeControlOuterLoop(activePowerDistribution, parametersExt.getSlackBusPMaxMismatch(), parametersExt.getAreaInterchangePMaxMismatch());
outerLoops.add(areaInterchangeControlOuterLoop);
}
return outerLoops;
}

public static DcLoadFlowParameters createDcParameters(Network network, LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt,
MatrixFactory matrixFactory, GraphConnectivityFactory<LfBus, LfBranch> connectivityFactory,
boolean forcePhaseControlOffAndAddAngle1Var) {
Expand Down Expand Up @@ -1911,9 +1929,9 @@ public static DcLoadFlowParameters createDcParameters(LoadFlowParameters paramet
.setSlackDistributionFailureBehavior(parametersExt.getSlackDistributionFailureBehavior())
.setMatrixFactory(matrixFactory)
.setDistributedSlack(parameters.isDistributedSlack())
.setAreaInterchangeControl(parametersExt.isAreaInterchangeControl())
.setBalanceType(parameters.getBalanceType())
.setSetVToNan(true)
.setOuterLoops(createDcOuterLoops(parameters, parametersExt))
.setMaxOuterLoopIterations(parametersExt.getMaxOuterLoopIterations())
.setSlackBusPMaxMismatch(parametersExt.getSlackBusPMaxMismatch())
.setAreaInterchangePMaxMismatch(parametersExt.getAreaInterchangePMaxMismatch());
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Copyright (c) 2024, 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.openloadflow.dc.equations.DcEquationType;
import com.powsybl.openloadflow.dc.equations.DcVariableType;
import com.powsybl.openloadflow.lf.outerloop.AbstractAreaInterchangeControlOuterLoop;
import com.powsybl.openloadflow.lf.outerloop.OuterLoopResult;
import com.powsybl.openloadflow.lf.outerloop.OuterLoopStatus;
import com.powsybl.openloadflow.network.LfBus;
import com.powsybl.openloadflow.network.util.ActivePowerDistribution;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
* @author Valentin Mouradian {@literal <valentin.mouradian at artelys.com>}
*/
public class DcAreaInterchangeControlOuterLoop extends AbstractAreaInterchangeControlOuterLoop<DcVariableType, DcEquationType, DcLoadFlowParameters, DcLoadFlowContext, DcOuterLoopContext> implements DcOuterLoop {

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

public DcAreaInterchangeControlOuterLoop(ActivePowerDistribution activePowerDistribution, double slackBusPMaxMismatch, double areaInterchangePMaxMismatch) {
super(activePowerDistribution, new DcNoAreaOuterLoop(), slackBusPMaxMismatch, areaInterchangePMaxMismatch, LOGGER);
}

@Override
public String getName() {
return "AreaInterchangeControl";
}

@Override
public double getSlackBusActivePowerMismatch(DcOuterLoopContext context) {
List<LfBus> buses = context.getNetwork().getBuses();
return DcLoadFlowEngine.getActivePowerMismatch(buses);
}

/**
* If the network has no area, the area interchange control is replaced by slack distribution.
* In DC mode, the slack distribution is handled directly by the load flow engine, without any outer loop.
* This class will be used as fallback outerloop in case the network has no area, and has no need to do anything.
*/
private static class DcNoAreaOuterLoop implements DcOuterLoop {
@Override
public String getName() {
return "DcNoAreaOuterLoop";
}

@Override
public OuterLoopResult check(DcOuterLoopContext context, ReportNode reportNode) {
return new OuterLoopResult(this, OuterLoopStatus.STABLE);
}
}
}
33 changes: 14 additions & 19 deletions src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -184,37 +183,33 @@ public DcLoadFlowResult run() {
DcLoadFlowParameters parameters = context.getParameters();
TargetVector<DcVariableType, DcEquationType> targetVector = context.getTargetVector();
RunningContext runningContext = new RunningContext();
List<DcOuterLoop> outerLoops = parameters.getOuterLoops();

// outer loop initialization
List<Pair<DcOuterLoop, DcOuterLoopContext>> outerLoopsAndContexts = new ArrayList<>();

if (parameters.getNetworkParameters().isPhaseControl()) {
DcIncrementalPhaseControlOuterLoop phaseShifterControlOuterLoop = new DcIncrementalPhaseControlOuterLoop();
DcOuterLoopContext phaseShifterControlOuterLoopContext = new DcOuterLoopContext(network);
outerLoopsAndContexts.add(Pair.of(phaseShifterControlOuterLoop, phaseShifterControlOuterLoopContext));
phaseShifterControlOuterLoop.initialize(phaseShifterControlOuterLoopContext);
}
List<Pair<DcOuterLoop, DcOuterLoopContext>> outerLoopsAndContexts = outerLoops.stream()
.map(outerLoop -> Pair.of(outerLoop, new DcOuterLoopContext(network)))
.toList();

if (parameters.isAreaInterchangeControl() && network.hasArea()) {
ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(parameters.getBalanceType(), false, parameters.getNetworkParameters().isUseActiveLimits());
DcAreaInterchangeControlControlOuterLoop areaInterchangeControlOuterLoop = new DcAreaInterchangeControlControlOuterLoop(activePowerDistribution, parameters.getSlackBusPMaxMismatch(), parameters.getAreaInterchangePMaxMismatch());
DcOuterLoopContext areaInterchangeControlOuterLoopContext = new DcOuterLoopContext(network);
outerLoopsAndContexts.add(Pair.of(areaInterchangeControlOuterLoop, areaInterchangeControlOuterLoopContext));
areaInterchangeControlOuterLoop.initialize(areaInterchangeControlOuterLoopContext);
// outer loops initialization
for (var outerLoopAndContext : outerLoopsAndContexts) {
var outerLoop = outerLoopAndContext.getLeft();
var outerLoopContext = outerLoopAndContext.getRight();
outerLoop.initialize(outerLoopContext);
}

initStateVector(network, equationSystem, new UniformValueVoltageInitializer());

double initialSlackBusActivePowerMismatch = getActivePowerMismatch(network.getBuses());
double distributedActivePower = 0.0;
if (parameters.isDistributedSlack() || parameters.isAreaInterchangeControl()) {

boolean isAreaInterchangeControl = outerLoops.stream().anyMatch(DcAreaInterchangeControlOuterLoop.class::isInstance);
if (parameters.isDistributedSlack() || isAreaInterchangeControl) {
LoadFlowParameters.BalanceType balanceType = parameters.getBalanceType();
boolean useActiveLimits = parameters.getNetworkParameters().isUseActiveLimits();
ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(balanceType, false, useActiveLimits);
var result = activePowerDistribution.run(network, initialSlackBusActivePowerMismatch);
final LfGenerator referenceGenerator;
final OpenLoadFlowParameters.SlackDistributionFailureBehavior behavior;
if (parameters.isAreaInterchangeControl()) {
if (isAreaInterchangeControl && network.hasArea()) {
// actual behavior will be handled by the outerloop itself, just leave on slack bus here
behavior = OpenLoadFlowParameters.SlackDistributionFailureBehavior.LEAVE_ON_SLACK_BUS;
referenceGenerator = null;
Expand Down Expand Up @@ -284,7 +279,7 @@ public DcLoadFlowResult run() {
for (var outerLoopAndContext : Lists.reverse(outerLoopsAndContexts)) {
var outerLoop = outerLoopAndContext.getLeft();
var outerLoopContext = outerLoopAndContext.getRight();
if (outerLoop instanceof DcAreaInterchangeControlControlOuterLoop activePowerDistributionOuterLoop) {
if (outerLoop instanceof DcAreaInterchangeControlOuterLoop activePowerDistributionOuterLoop) {
distributedActivePower += activePowerDistributionOuterLoop.getDistributedActivePower(outerLoopContext);
}
outerLoop.cleanup(outerLoopContext);
Expand Down
24 changes: 13 additions & 11 deletions src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowParameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import com.powsybl.openloadflow.dc.equations.DcEquationSystemCreationParameters;
import com.powsybl.openloadflow.lf.AbstractLoadFlowParameters;

import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
Expand All @@ -23,12 +25,12 @@ public class DcLoadFlowParameters extends AbstractLoadFlowParameters<DcLoadFlowP

private boolean distributedSlack = LoadFlowParameters.DEFAULT_DISTRIBUTED_SLACK;

private boolean areaInterchangeControl = OpenLoadFlowParameters.AREA_INTERCHANGE_CONTROL_DEFAULT_VALUE;

private LoadFlowParameters.BalanceType balanceType = LoadFlowParameters.DEFAULT_BALANCE_TYPE;

private boolean setVToNan = false;

protected List<DcOuterLoop> outerLoops = Collections.emptyList();

private int maxOuterLoopIterations = DEFAULT_MAX_OUTER_LOOP_ITERATIONS;

private double slackBusPMaxMismatch = OpenLoadFlowParameters.SLACK_BUS_P_MAX_MISMATCH_DEFAULT_VALUE;
Expand Down Expand Up @@ -62,15 +64,6 @@ public DcLoadFlowParameters setDistributedSlack(boolean distributedSlack) {
return this;
}

public boolean isAreaInterchangeControl() {
return areaInterchangeControl;
}

public DcLoadFlowParameters setAreaInterchangeControl(boolean areaInterchangeControl) {
this.areaInterchangeControl = areaInterchangeControl;
return this;
}

public LoadFlowParameters.BalanceType getBalanceType() {
return balanceType;
}
Expand All @@ -89,6 +82,15 @@ public DcLoadFlowParameters setSetVToNan(boolean setVToNan) {
return this;
}

public List<DcOuterLoop> getOuterLoops() {
return outerLoops;
}

public DcLoadFlowParameters setOuterLoops(List<DcOuterLoop> outerLoops) {
this.outerLoops = Objects.requireNonNull(outerLoops);
return this;
}

public double getSlackBusPMaxMismatch() {
return slackBusPMaxMismatch;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ public abstract class AbstractAreaInterchangeControlOuterLoop<
P extends AbstractLoadFlowParameters<P>,
C extends LoadFlowContext<V, E, P>,
O extends AbstractOuterLoopContext<V, E, P, C>>
extends AbstractActivePowerDistributionOuterLoop<V, E, P, C, O>
implements OuterLoop<V, E, P, C, O>, ActivePowerDistributionOuterLoop<V, E, P, C, O> {
extends AbstractActivePowerDistributionOuterLoop<V, E, P, C, O> {

private final Logger logger;

Expand Down
Loading

0 comments on commit b988c72

Please sign in to comment.