Skip to content

Commit

Permalink
Merge branch 'main' into download_readthedocs
Browse files Browse the repository at this point in the history
  • Loading branch information
olperr1 authored Dec 16, 2024
2 parents c5f41be + 868e5e3 commit 5c8cfdf
Show file tree
Hide file tree
Showing 21 changed files with 348 additions and 150 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,12 @@ dependencies to respectively have access to network model, IEEE test networks an
<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-iidm-impl</artifactId>
<version>6.5.1</version>
<version>6.6.0</version>
</dependency>
<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-ieee-cdf-converter</artifactId>
<version>6.5.1</version>
<version>6.6.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
Expand All @@ -117,7 +117,7 @@ After adding a last Maven dependency on Open Load Flow implementation:
<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-open-loadflow</artifactId>
<version>1.13.2</version>
<version>1.14.0</version>
</dependency>
```

Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
</parent>

<artifactId>powsybl-open-loadflow</artifactId>
<version>1.14.0-SNAPSHOT</version>
<version>1.15.0-SNAPSHOT</version>

<name>powsybl open loadflow</name>
<description>An open source loadflow based on PowSyBl</description>
Expand Down Expand Up @@ -54,7 +54,7 @@
<slf4jtoys.version>1.6.3</slf4jtoys.version>
<asciitable.version>0.3.2</asciitable.version>

<powsybl-core.version>6.6.0-RC1</powsybl-core.version>
<powsybl-core.version>6.6.0</powsybl-core.version>
</properties>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
package com.powsybl.openloadflow.ac.outerloop;

import com.powsybl.commons.report.ReportNode;
import com.powsybl.openloadflow.OpenLoadFlowParameters;
import com.powsybl.openloadflow.ac.AcLoadFlowContext;
import com.powsybl.openloadflow.ac.AcLoadFlowParameters;
import com.powsybl.openloadflow.ac.AcOuterLoopContext;
Expand All @@ -18,14 +17,12 @@
import com.powsybl.openloadflow.lf.outerloop.DistributedSlackContextData;
import com.powsybl.openloadflow.lf.outerloop.OuterLoopResult;
import com.powsybl.openloadflow.lf.outerloop.OuterLoopStatus;
import com.powsybl.openloadflow.network.LfGenerator;
import com.powsybl.openloadflow.network.util.ActivePowerDistribution;
import com.powsybl.openloadflow.util.PerUnit;
import com.powsybl.openloadflow.util.Reports;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Locale;
import java.util.Objects;

/**
Expand Down Expand Up @@ -71,25 +68,27 @@ public OuterLoopResult check(AcOuterLoopContext context, ReportNode reportNode)
}
ReportNode iterationReportNode = Reports.createOuterLoopIterationReporter(reportNode, context.getOuterLoopTotalIterations() + 1);
ActivePowerDistribution.Result result = activePowerDistribution.run(context.getNetwork(), slackBusActivePowerMismatch);
double remainingMismatch = result.remainingMismatch();
ActivePowerDistribution.ResultWithFailureBehaviorHandling resultWbh = ActivePowerDistribution.handleDistributionFailureBehavior(
context.getLoadFlowContext().getParameters().getSlackDistributionFailureBehavior(),
context.getNetwork().getReferenceGenerator(),
slackBusActivePowerMismatch,
result,
"Failed to distribute slack bus active power mismatch, %.2f MW remains"
);
double remainingMismatch = resultWbh.remainingMismatch();
double distributedActivePower = slackBusActivePowerMismatch - remainingMismatch;
if (Math.abs(remainingMismatch) > ActivePowerDistribution.P_RESIDUE_EPS) {
Reports.reportMismatchDistributionFailure(iterationReportNode, remainingMismatch * PerUnit.SB);
} else {
ActivePowerDistribution.reportAndLogSuccess(iterationReportNode, slackBusActivePowerMismatch, resultWbh);
}
DistributedSlackContextData contextData = (DistributedSlackContextData) context.getData();
contextData.addDistributedActivePower(distributedActivePower);
if (Math.abs(remainingMismatch) > ActivePowerDistribution.P_RESIDUE_EPS) {
OpenLoadFlowParameters.SlackDistributionFailureBehavior slackDistributionFailureBehavior = getSlackDistributionFailureBehavior(context);
LfGenerator referenceGenerator = context.getNetwork().getReferenceGenerator();
String statusText = String.format(Locale.US, "Failed to distribute slack bus active power mismatch, %.2f MW remains", remainingMismatch * PerUnit.SB);

OuterLoopResult outerLoopResult = handleDistributionFailure(context, contextData, result.movedBuses(), distributedActivePower, remainingMismatch, statusText);

if (slackDistributionFailureBehavior == OpenLoadFlowParameters.SlackDistributionFailureBehavior.DISTRIBUTE_ON_REFERENCE_GENERATOR && referenceGenerator != null) {
LOGGER.debug("{} MW distributed to reference generator '{}'",
remainingMismatch * PerUnit.SB, referenceGenerator.getId());
}
return outerLoopResult;
if (resultWbh.failed()) {
contextData.addDistributedActivePower(-resultWbh.failedDistributedActivePower());
return new OuterLoopResult(this, OuterLoopStatus.FAILED, resultWbh.failedMessage());
} else {
reportAndLogSuccess(iterationReportNode, slackBusActivePowerMismatch, result);
return new OuterLoopResult(this, OuterLoopStatus.UNSTABLE);
return new OuterLoopResult(this, resultWbh.movedBuses() ? OuterLoopStatus.UNSTABLE : OuterLoopStatus.STABLE);
}
}

Expand All @@ -98,20 +97,4 @@ public double getSlackBusActivePowerMismatch(AcOuterLoopContext context) {
return context.getLastSolverResult().getSlackBusActivePowerMismatch();
}

@Override
public OpenLoadFlowParameters.SlackDistributionFailureBehavior getSlackDistributionFailureBehavior(AcOuterLoopContext context) {
OpenLoadFlowParameters.SlackDistributionFailureBehavior slackDistributionFailureBehavior = context.getLoadFlowContext().getParameters().getSlackDistributionFailureBehavior();
if (slackDistributionFailureBehavior == OpenLoadFlowParameters.SlackDistributionFailureBehavior.DISTRIBUTE_ON_REFERENCE_GENERATOR
&& context.getNetwork().getReferenceGenerator() == null) {
slackDistributionFailureBehavior = OpenLoadFlowParameters.SlackDistributionFailureBehavior.FAIL;
}
return slackDistributionFailureBehavior;
}

private static void reportAndLogSuccess(ReportNode reportNode, double slackBusActivePowerMismatch, ActivePowerDistribution.Result result) {
Reports.reportMismatchDistributionSuccess(reportNode, slackBusActivePowerMismatch * PerUnit.SB, result.iteration());

LOGGER.info("Slack bus active power ({} MW) distributed in {} distribution iteration(s)",
slackBusActivePowerMismatch * PerUnit.SB, result.iteration());
}
}
40 changes: 38 additions & 2 deletions src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,21 @@
import com.powsybl.commons.report.ReportNode;
import com.powsybl.loadflow.LoadFlowParameters;
import com.powsybl.math.matrix.MatrixException;
import com.powsybl.openloadflow.OpenLoadFlowParameters;
import com.powsybl.openloadflow.dc.equations.DcEquationType;
import com.powsybl.openloadflow.dc.equations.DcVariableType;
import com.powsybl.openloadflow.equations.*;
import com.powsybl.openloadflow.lf.LoadFlowEngine;
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.LfGenerator;
import com.powsybl.openloadflow.network.LfNetwork;
import com.powsybl.openloadflow.network.LfNetworkLoader;
import com.powsybl.openloadflow.network.util.ActivePowerDistribution;
import com.powsybl.openloadflow.network.util.UniformValueVoltageInitializer;
import com.powsybl.openloadflow.network.util.VoltageInitializer;
import com.powsybl.openloadflow.util.PerUnit;
import com.powsybl.openloadflow.util.Reports;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
Expand Down Expand Up @@ -205,8 +208,41 @@ public DcLoadFlowResult run() {
double initialSlackBusActivePowerMismatch = getActivePowerMismatch(network.getBuses());
double distributedActivePower = 0.0;
if (parameters.isDistributedSlack() || parameters.isAreaInterchangeControl()) {
// FIXME handle distribution failure
distributedActivePower = distributeSlack(network, network.getBuses(), parameters.getBalanceType(), parameters.getNetworkParameters().isUseActiveLimits());
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()) {
// actual behavior will be handled by the outerloop itself, just leave on slack bus here
behavior = OpenLoadFlowParameters.SlackDistributionFailureBehavior.LEAVE_ON_SLACK_BUS;
referenceGenerator = null;
} else {
behavior = parameters.getSlackDistributionFailureBehavior();
referenceGenerator = context.getNetwork().getReferenceGenerator();
}
ActivePowerDistribution.ResultWithFailureBehaviorHandling resultWbh = ActivePowerDistribution.handleDistributionFailureBehavior(
behavior,
referenceGenerator,
initialSlackBusActivePowerMismatch,
result,
"Failed to distribute slack bus active power mismatch, %.2f MW remains"
);
double remainingMismatch = resultWbh.remainingMismatch();
distributedActivePower = initialSlackBusActivePowerMismatch - remainingMismatch;
if (Math.abs(remainingMismatch) > ActivePowerDistribution.P_RESIDUE_EPS) {
Reports.reportMismatchDistributionFailure(reportNode, remainingMismatch * PerUnit.SB);
} else {
ActivePowerDistribution.reportAndLogSuccess(reportNode, initialSlackBusActivePowerMismatch, resultWbh);
}
if (resultWbh.failed()) {
distributedActivePower -= resultWbh.failedDistributedActivePower();
runningContext.lastSolverSuccess = false;
runningContext.lastOuterLoopResult = new OuterLoopResult("DistributedSlack", OuterLoopStatus.FAILED, resultWbh.failedMessage());
Reports.reportDcLfComplete(reportNode, runningContext.lastSolverSuccess, runningContext.lastOuterLoopResult.status().name());
return buildDcLoadFlowResult(network, runningContext, initialSlackBusActivePowerMismatch, distributedActivePower);
}
}

// we need to copy the target array because JacobianMatrix.solveTransposed take as an input the second member
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ public double calculateSensi(DenseMatrix dx, int column) {
double dph1 = dx.get(ph1Var.getRow(), column);
double dph2 = dx.get(ph2Var.getRow(), column);
double da1 = a1Var != null ? dx.get(a1Var.getRow(), column) : 0;
return calculateSensi(dph1, dph2, da1);
// - eval(0,0,0) to have an exact epression and remove the constant term of the affine function (wich is 0 in practe because A2 = 0)
return eval(dph1, dph2, da1) - eval(0, 0, 0);
}

protected double ph1(StateVector sv) {
Expand All @@ -116,16 +117,11 @@ protected double ph2() {
return ph2(sv);
}

protected abstract double calculateSensi(double ph1, double ph2, double a1);
protected abstract double eval(double ph1, double ph2, double a1);

@Override
public double eval() {
return calculateSensi(ph1(), ph2(), a1());
}

@Override
public double eval(StateVector sv) {
return calculateSensi(ph1(sv), ph2(sv), a1(sv));
return eval(ph1(), ph2(), a1());
}

protected double a1(StateVector sv) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public static ClosedBranchSide1DcFlowEquationTerm create(LfBranch branch, LfBus
}

@Override
protected double calculateSensi(double ph1, double ph2, double a1) {
protected double eval(double ph1, double ph2, double a1) {
double deltaPhase = ph2 - ph1 + A2 - a1;
return -getPower() * deltaPhase;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public static ClosedBranchSide2DcFlowEquationTerm create(LfBranch branch, LfBus
}

@Override
protected double calculateSensi(double ph1, double ph2, double a1) {
protected double eval(double ph1, double ph2, double a1) {
double deltaPhase = ph2 - ph1 + A2 - a1;
return getPower() * deltaPhase;
}
Expand Down
13 changes: 10 additions & 3 deletions src/main/java/com/powsybl/openloadflow/equations/Equation.java
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,16 @@ public double eval() {
for (EquationTerm<V, E> term : terms) {
if (term.isActive()) {
value += term.eval();
if (term.hasRhs()) {
value -= term.rhs();
}
}
}
return value;
}

public double evalLhs() {
double value = 0;
for (EquationTerm<V, E> term : terms) {
if (term.isActive()) {
value += term.evalLhs();
}
}
return value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,11 @@ static <V extends Enum<V> & Quantity, E extends Enum<E> & Quantity> EquationTerm
double eval();

/**
* Evaluate the equation term with an alternative state vector.
* Evaluate equation lhs of the equation term
* @return value of the equation term
*/
default double eval(StateVector sv) {
throw new UnsupportedOperationException("Not implemented");
default double evalLhs() {
return eval() - (hasRhs() ? rhs() : 0);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ protected double[] createArray() {
return array;
}

private void eval(double[] array, List<Equation<V, E>> equations) {
private void evalLhs(double[] array, List<Equation<V, E>> equations) {
Arrays.fill(array, 0); // necessary?
for (Equation<V, E> equation : equations) {
array[equation.getColumn()] = equation.eval();
array[equation.getColumn()] = equation.evalLhs();
}
}

Expand All @@ -59,7 +59,7 @@ protected void updateArray(double[] array) {
throw new IllegalArgumentException("Bad equation vector length: " + array.length);
}

eval(array, equations);
evalLhs(array, equations);

LOGGER.debug(PERFORMANCE_MARKER, "Equation vector updated in {} us", stopwatch.elapsed(TimeUnit.MICROSECONDS));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,4 @@ public boolean isActive() {
return getBranchTermStream().anyMatch(EquationTerm::isActive);
}

@Override
public double eval(StateVector sv) {
// The equation is
// rhs = VariableInjectionPart+ branchPart
// with rhs = - (cte injectionPart) (for ex sum of targetQ)
// -branchPart = variableInjectionPart + cteInjectionPart
return -getBranchTermStream().mapToDouble(t -> t.eval(sv)).sum();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,9 @@
*/
package com.powsybl.openloadflow.lf.outerloop;

import com.powsybl.commons.PowsyblException;
import com.powsybl.openloadflow.OpenLoadFlowParameters;
import com.powsybl.openloadflow.equations.Quantity;
import com.powsybl.openloadflow.lf.AbstractLoadFlowParameters;
import com.powsybl.openloadflow.lf.LoadFlowContext;
import com.powsybl.openloadflow.network.LfGenerator;

import java.util.Objects;

/**
* @author Valentin Mouradian {@literal <valentin.mouradian at artelys.com>}
Expand All @@ -35,34 +30,4 @@ public double getDistributedActivePower(O context) {
return Double.NaN;
}

@Override
public OuterLoopResult handleDistributionFailure(O context, DistributedSlackContextData contextData, boolean movedBuses, double totalDistributedActivePower, double remainingMismatch, String errorMessage) {
OpenLoadFlowParameters.SlackDistributionFailureBehavior slackDistributionFailureBehavior = getSlackDistributionFailureBehavior(context);

switch (slackDistributionFailureBehavior) {
case THROW ->
throw new PowsyblException(errorMessage);

case LEAVE_ON_SLACK_BUS -> {
return new OuterLoopResult(this, movedBuses ? OuterLoopStatus.UNSTABLE : OuterLoopStatus.STABLE);
}
case FAIL -> {
// Mismatches reported in LoadFlowResult on slack bus(es) are the mismatches of the last NR run.
// Since we will not be re-running an NR, revert distributedActivePower reporting which would otherwise be misleading.
// Said differently, we report that we didn't distribute anything, and this is indeed consistent with the network state.
contextData.addDistributedActivePower(-totalDistributedActivePower);
return new OuterLoopResult(this, OuterLoopStatus.FAILED, errorMessage);
}
case DISTRIBUTE_ON_REFERENCE_GENERATOR -> {
LfGenerator referenceGenerator = context.getNetwork().getReferenceGenerator();
Objects.requireNonNull(referenceGenerator, () -> "No reference generator in " + context.getNetwork());
// remaining goes to reference generator, without any limit consideration
contextData.addDistributedActivePower(remainingMismatch);
referenceGenerator.setTargetP(referenceGenerator.getTargetP() + remainingMismatch);
return new OuterLoopResult(this, OuterLoopStatus.UNSTABLE);
}
default -> throw new IllegalArgumentException("Unknown slackDistributionFailureBehavior");
}
}

}
Loading

0 comments on commit 5c8cfdf

Please sign in to comment.