Skip to content

Commit

Permalink
Merge branch 'main' into convergence_control_parameters_as_olf_parame…
Browse files Browse the repository at this point in the history
…ters
  • Loading branch information
geofjamg authored Oct 5, 2023
2 parents 30886d1 + 7eeb980 commit db9310e
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 16 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<parent>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-parent</artifactId>
<version>15</version>
<version>16</version>
<relativePath/>
</parent>

Expand Down
20 changes: 11 additions & 9 deletions src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
import com.powsybl.openloadflow.ac.nr.NewtonRaphsonResult;
import com.powsybl.openloadflow.ac.nr.NewtonRaphsonStatus;
import com.powsybl.openloadflow.ac.outerloop.AcOuterLoop;
import com.powsybl.openloadflow.ac.outerloop.DistributedSlackOuterLoop;
import com.powsybl.openloadflow.lf.LoadFlowEngine;
import com.powsybl.openloadflow.lf.outerloop.DistributedSlackContextData;
import com.powsybl.openloadflow.lf.outerloop.OuterLoopStatus;
import com.powsybl.openloadflow.network.LfNetwork;
import com.powsybl.openloadflow.network.LfNetworkLoader;
Expand All @@ -27,11 +29,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.*;

/**
* @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
Expand Down Expand Up @@ -121,7 +119,7 @@ public AcLoadFlowResult run() {
List<AcOuterLoop> outerLoops = context.getParameters().getOuterLoops();
List<Pair<AcOuterLoop, AcOuterLoopContext>> outerLoopsAndContexts = outerLoops.stream()
.map(outerLoop -> Pair.of(outerLoop, new AcOuterLoopContext(context.getNetwork())))
.collect(Collectors.toList());
.toList();

// outer loops initialization
for (var outerLoopAndContext : outerLoopsAndContexts) {
Expand All @@ -138,7 +136,6 @@ public AcLoadFlowResult run() {
}
// run initial Newton-Raphson
runningContext.lastNrResult = newtonRaphson.run(voltageInitializer, nrReporter);
double initialSlackBusActivePowerMismatch = runningContext.lastNrResult.getSlackBusActivePowerMismatch();

runningContext.nrTotalIterations.add(runningContext.lastNrResult.getIterations());

Expand Down Expand Up @@ -166,10 +163,14 @@ public AcLoadFlowResult run() {
&& runningContext.outerLoopTotalIterations < context.getParameters().getMaxOuterLoopIterations());
}

double distributedActivePower = 0.0;
// outer loops finalization (in reverse order to allow correct cleanup)
for (var outerLoopAndContext : Lists.reverse(outerLoopsAndContexts)) {
var outerLoop = outerLoopAndContext.getLeft();
var outerLoopContext = outerLoopAndContext.getRight();
if (outerLoop instanceof DistributedSlackOuterLoop) {
distributedActivePower = ((DistributedSlackContextData) outerLoopContext.getData()).getDistributedActivePower();
}
outerLoop.cleanup(outerLoopContext);
}

Expand All @@ -182,7 +183,8 @@ public AcLoadFlowResult run() {
runningContext.lastNrResult.getStatus(),
outerLoopFinalStatus,
runningContext.lastNrResult.getSlackBusActivePowerMismatch(),
initialSlackBusActivePowerMismatch - runningContext.lastNrResult.getSlackBusActivePowerMismatch());
distributedActivePower
);

LOGGER.info("Ac loadflow complete on network {} (result={})", context.getNetwork(), result);

Expand All @@ -206,6 +208,6 @@ public static <T> List<AcLoadFlowResult> run(T network, LfNetworkLoader<T> netwo
}
return AcLoadFlowResult.createNoCalculationResult(n);
})
.collect(Collectors.toList());
.toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.reporter.Reporter;
import com.powsybl.openloadflow.ac.AcOuterLoopContext;
import com.powsybl.openloadflow.lf.outerloop.DistributedSlackContextData;
import com.powsybl.openloadflow.lf.outerloop.OuterLoopStatus;
import com.powsybl.openloadflow.network.util.ActivePowerDistribution;
import com.powsybl.openloadflow.util.PerUnit;
Expand Down Expand Up @@ -44,22 +45,30 @@ public String getName() {
return NAME;
}

@Override
public void initialize(AcOuterLoopContext context) {
var contextData = new DistributedSlackContextData();
context.setData(contextData);
}

@Override
public OuterLoopStatus check(AcOuterLoopContext context, Reporter reporter) {
double slackBusActivePowerMismatch = context.getLastNewtonRaphsonResult().getSlackBusActivePowerMismatch();
if (Math.abs(slackBusActivePowerMismatch) > slackBusPMaxMismatch / PerUnit.SB) {

ActivePowerDistribution.Result result = activePowerDistribution.run(context.getNetwork(), slackBusActivePowerMismatch);

if (Math.abs(result.getRemainingMismatch()) > ActivePowerDistribution.P_RESIDUE_EPS) {
Reports.reportMismatchDistributionFailure(reporter, context.getIteration(), result.getRemainingMismatch() * PerUnit.SB);
double remainingMismatch = result.getRemainingMismatch();
double distributedActivePower = slackBusActivePowerMismatch - remainingMismatch;
DistributedSlackContextData contextData = (DistributedSlackContextData) context.getData();
contextData.addDistributedActivePower(distributedActivePower);
if (Math.abs(remainingMismatch) > ActivePowerDistribution.P_RESIDUE_EPS) {
Reports.reportMismatchDistributionFailure(reporter, context.getIteration(), remainingMismatch * PerUnit.SB);

if (throwsExceptionInCaseOfFailure) {
throw new PowsyblException("Failed to distribute slack bus active power mismatch, "
+ result.getRemainingMismatch() * PerUnit.SB + " MW remains");
+ remainingMismatch * PerUnit.SB + " MW remains");
}

LOGGER.error("Failed to distribute slack bus active power mismatch, {} MW remains", result.getRemainingMismatch() * PerUnit.SB);
LOGGER.error("Failed to distribute slack bus active power mismatch, {} MW remains", remainingMismatch * PerUnit.SB);

return OuterLoopStatus.STABLE;
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Copyright (c) 2023, 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.lf.outerloop;

/**
* Keeps track of distributed active power
*
* @author Damien Jeandemange <damien.jeandemange at artelys.com>
*/
public class DistributedSlackContextData {
private double distributedActivePower = 0.0;

public double getDistributedActivePower() {
return distributedActivePower;
}

public void addDistributedActivePower(double addedDistributedActivePower) {
distributedActivePower += addedDistributedActivePower;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -413,4 +413,34 @@ void batteryTestProportionalToParticipationFactor() {
assertActivePowerEquals(-2, bat1.getTerminal());
assertActivePowerEquals(0, bat2.getTerminal());
}

@Test
void testDistributedActivePower() {
parameters.setUseReactiveLimits(true).getExtension(OpenLoadFlowParameters.class).setSlackBusPMaxMismatch(0.0001);
Network network = DistributedSlackNetworkFactory.createWithLossesAndPvPqTypeSwitch();
Generator g1 = network.getGenerator("g1");
Generator g2 = network.getGenerator("g2");
Generator g3 = network.getGenerator("g3");
Generator g4 = network.getGenerator("g4");
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isOk());
// we were getting 132.47279 when computing distributedActivePower as initial NR slack - final NR slack, while difference targetP - P was only 120.1961
var expectedDistributedActivePower = -network.getGeneratorStream().mapToDouble(g -> g.getTargetP() + g.getTerminal().getP()).sum();
assertEquals(120.1961, expectedDistributedActivePower, LoadFlowAssert.DELTA_POWER);
assertEquals(expectedDistributedActivePower, result.getComponentResults().get(0).getDistributedActivePower(), LoadFlowAssert.DELTA_POWER);
assertActivePowerEquals(-115.024, g1.getTerminal());
assertActivePowerEquals(-245.073, g2.getTerminal());
assertActivePowerEquals(-105.024, g3.getTerminal());
assertActivePowerEquals(-135.073, g4.getTerminal());
}

@Test
void testDistributedActivePowerSlackDistributionDisabled() {
parameters.setUseReactiveLimits(true).setDistributedSlack(false);
Network network = DistributedSlackNetworkFactory.createWithLossesAndPvPqTypeSwitch();
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isOk());
// we were getting 12.307 when computing distributedActivePower as initial NR slack - final NR slack, expecting zero here
assertEquals(0.0, result.getComponentResults().get(0).getDistributedActivePower(), LoadFlowAssert.DELTA_POWER);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,18 @@ public static Network create() {
return network;
}

public static Network createWithLossesAndPvPqTypeSwitch() {
// A lossy network with losses changing significantly between first NR and last NR due to PV->PQ switching.
// First NR has huge losses due to huge reactive flows when g2 is PV.
Network network = create();
network.getLineStream().forEach(l -> l.setR(0.1));
// g2 can only reach 400.18kV with 300MVAr
network.getGenerator("g2")
.setTargetV(402.0).setVoltageRegulatorOn(true)
.newMinMaxReactiveLimits().setMinQ(-300).setMaxQ(300).add();
return network;
}

public static Network createNetworkWithLoads() {
Network network = Network.create("distributed-load-slack-bus", "code");
Bus b1 = createBus(network, "b1", 400);
Expand Down

0 comments on commit db9310e

Please sign in to comment.