Skip to content

Commit

Permalink
Add optimization tests for OpenReac indicators and bounds (#88)
Browse files Browse the repository at this point in the history
* Add indicators test for OpenReac
* Add tests for bounds
* Add TUs on Q bounds
* Update resources

---------

Signed-off-by: p-arvy <[email protected]>
  • Loading branch information
p-arvy authored Jan 8, 2025
1 parent af69780 commit 178f1f7
Show file tree
Hide file tree
Showing 22 changed files with 1,894 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.io.InputStream;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ForkJoinPool;
Expand Down Expand Up @@ -82,29 +83,56 @@ protected void testAllModifAndLoadFlow(Network network, String subFolder, OpenRe

/**
* Runs OpenReac and apply the results on the network.
* The application of the voltage plan calculated by optimization is optional.
*/
protected void runAndApplyAllModifications(Network network, String subFolder, OpenReacParameters parameters,
boolean updateNetworkWithVoltages, ReportNode reportNode) throws IOException {
boolean updateNetworkWithVoltages, ReportNode reportNode) throws IOException {
OpenReacResult openReacResult = runOpenReac(network, subFolder, parameters, false, reportNode);
assertEquals(OpenReacStatus.OK, openReacResult.getStatus());
openReacResult.setUpdateNetworkWithVoltages(updateNetworkWithVoltages);
openReacResult.applyAllModifications(network);
}

/**
* Runs OpenReac and returns associated result.
*/
protected OpenReacResult runOpenReac(Network network, String subFolder, boolean onlyIndicators) throws IOException {
return runOpenReac(network, subFolder, new OpenReacParameters(), onlyIndicators);
}

/**
* Runs OpenReac and returns associated result.
*/
protected OpenReacResult runOpenReac(Network network, String subFolder, OpenReacParameters parameters, boolean onlyIndicators) throws IOException {
return runOpenReac(network, subFolder, parameters, onlyIndicators, ReportNode.NO_OP);
}

/**
* Runs OpenReac and returns associated result.
* Note that OpenReac is not really executed by default. If the execution line is not uncommented,
* the results are retrieved and stored in an {@link OpenReacResult} object.
*/
protected OpenReacResult runOpenReac(Network network, String subFolder, OpenReacParameters parameters,
boolean onlyIndicators, ReportNode reportNode) throws IOException {
// set default voltage limits to every voltage levels of the network
setDefaultVoltageLimits(network);
LocalCommandExecutor localCommandExecutor = new TestLocalCommandExecutor(
List.of(subFolder + "/reactiveopf_results_generators.csv",
subFolder + "/reactiveopf_results_indic.txt",
subFolder + "/reactiveopf_results_rtc.csv",
subFolder + "/reactiveopf_results_shunts.csv",
subFolder + "/reactiveopf_results_static_var_compensators.csv",
subFolder + "/reactiveopf_results_vsc_converter_stations.csv",
subFolder + "/reactiveopf_results_voltages.csv"));
List<String> outputFileNames = new ArrayList<>(List.of(subFolder + "/reactiveopf_results_indic.txt"));
if (!onlyIndicators) {
outputFileNames.addAll(List.of(
subFolder + "/reactiveopf_results_rtc.csv",
subFolder + "/reactiveopf_results_shunts.csv",
subFolder + "/reactiveopf_results_static_var_compensators.csv",
subFolder + "/reactiveopf_results_vsc_converter_stations.csv",
subFolder + "/reactiveopf_results_voltages.csv"
));
}
LocalCommandExecutor localCommandExecutor = new TestLocalCommandExecutor(outputFileNames);
// To really run open reac, use the commentede line below. Be sure that open-reac/src/test/resources/com/powsybl/config/test/config.yml contains your ampl path
// try (ComputationManager computationManager = new LocalComputationManager()) {
try (ComputationManager computationManager = new LocalComputationManager(new LocalComputationConfig(tmpDir),
localCommandExecutor, ForkJoinPool.commonPool())) {
OpenReacResult openReacResult = OpenReacRunner.run(network,
network.getVariantManager().getWorkingVariantId(), parameters,
return OpenReacRunner.run(network, network.getVariantManager().getWorkingVariantId(), parameters,
new OpenReacConfig(true), computationManager, reportNode, null);
assertEquals(OpenReacStatus.OK, openReacResult.getStatus());
openReacResult.setUpdateNetworkWithVoltages(updateNetworkWithVoltages);
openReacResult.applyAllModifications(network);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/**
* Copyright (c) 2024, 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/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.openreac.optimization;

import com.powsybl.iidm.network.Network;
import com.powsybl.openreac.network.VoltageControlNetworkFactory;
import com.powsybl.openreac.parameters.input.OpenReacParameters;
import com.powsybl.openreac.parameters.output.OpenReacResult;
import com.powsybl.openreac.parameters.output.OpenReacStatus;
import org.junit.jupiter.api.Test;

import java.io.IOException;

import static org.junit.jupiter.api.Assertions.*;

/**
* Test the generator bounds in OpenReac optimization.
*
* @author Pierre ARVY {@literal <pierre.arvy at artelys.com>}
*/
class OpecReacOptimizationBoundsTest extends AbstractOpenReacRunnerTest {

@Test
void testGeneratorsMaxPBounds() throws IOException {
Network network = VoltageControlNetworkFactory.createWithTwoVoltageControls();
// due to the disconnection, the network is now imbalanced
// and max p of generators is not enough to provide balance
network.getLine("l45").disconnect();
OpenReacResult result = runOpenReac(network, "optimization/bounds/generators-pmax-too-small", true);
assertEquals(OpenReacStatus.NOT_OK, result.getStatus());

// increase max p of generators to allow power balance
network.getGenerator("g2").setMaxP(2.5);
network.getGenerator("g3").setMaxP(2.5);
result = runOpenReac(network, "optimization/bounds/generators-pmax", true);
assertEquals(OpenReacStatus.OK, result.getStatus());
}

@Test
void testGeneratorsMinPBounds() throws IOException {
Network network = VoltageControlNetworkFactory.createWithTwoVoltageControls();
// due to the modifications, the network is now imbalanced
// and min p of generators is not small enough to provide balance
network.getLine("l45").disconnect();
network.getLoad("l4").setP0(3);
network.getGenerator("g2").setMinP(2);
network.getGenerator("g3").setMinP(2);
OpenReacResult result = runOpenReac(network, "optimization/bounds/generators-pmin-too-high", true);
assertEquals(OpenReacStatus.NOT_OK, result.getStatus());

// decrease min p of generators to allow power balance
// but targetP will be fixed in optimization, because it is too close of maxP
network.getGenerator("g2").setMinP(1);
network.getGenerator("g3").setMinP(1);
result = runOpenReac(network, "optimization/bounds/generators-target-p-too-close-pmax", true);
assertEquals(OpenReacStatus.NOT_OK, result.getStatus());

// increase max p of generators to allow modification of targetP in optimization
network.getGenerator("g2").setMaxP(2.5);
network.getGenerator("g3").setMaxP(2.5);
result = runOpenReac(network, "optimization/bounds/generators-pmin", true);
assertEquals(OpenReacStatus.OK, result.getStatus());
}

@Test
void testGeneratorRectangularQBounds() throws IOException {
Network network = VoltageControlNetworkFactory.createWithTwoVoltageControls();
network.getLine("l45").disconnect();
network.getLoad("l4").setP0(4).setQ0(2);

// set reactive limits to both generators
network.getGenerator("g2").newReactiveCapabilityCurve()
.beginPoint()
.setP(0)
.setMinQ(-0.25)
.setMaxQ(0.25)
.endPoint()
.beginPoint()
.setP(2)
.setMinQ(-2)
.setMaxQ(2)
.endPoint()
.add();
network.getGenerator("g3").newReactiveCapabilityCurve()
.beginPoint()
.setP(0)
.setMinQ(-0.25)
.setMaxQ(0.25)
.endPoint()
.beginPoint()
.setP(2)
.setMinQ(-2)
.setMaxQ(2)
.endPoint()
.add();

OpenReacResult result = runOpenReac(network, "optimization/bounds/generator-rectangular-bounds", true);
assertEquals(OpenReacStatus.OK, result.getStatus());
// rectangular bounds in ACOPF implies Q bounds are not large enough to remove reactive slacks in optimization
assertTrue(Integer.parseInt(result.getIndicators().get("nb_reactive_slacks")) > 0);
}

@Test
void testGeneratorQmaxPmaxRatioBounds() throws IOException {
Network network = VoltageControlNetworkFactory.createWithTwoVoltageControls();
network.getLine("l45").disconnect();
network.getLoad("l4").setP0(4).setQ0(2);

OpenReacParameters parameters = new OpenReacParameters();
OpenReacResult result = runOpenReac(network, "optimization/bounds/qmax-pmax-default-ratio", parameters, true);
assertEquals(OpenReacStatus.OK, result.getStatus());
// there are slacks as Q bounds are not large enough
assertTrue(Integer.parseInt(result.getIndicators().get("nb_reactive_slacks")) > 0);

parameters.setDefaultQmaxPmaxRatio(1);
result = runOpenReac(network, "optimization/bounds/same-qmax-pmax", parameters, true);
assertEquals(OpenReacStatus.OK, result.getStatus());
// Q bounds are large enough to remove reactive slacks in optimization
assertEquals(0, Integer.parseInt(result.getIndicators().get("nb_reactive_slacks")));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ void testOutputFileParsing() throws IOException {
assertEquals(7, openReacResult.getGeneratorModifications().size());
assertEquals(3, openReacResult.getVoltageProfile().size());
assertEquals(76, openReacResult.getIndicators().size());

assertTrue(openReacResult.getReactiveSlacks().isEmpty());
}
}
Expand Down
Loading

0 comments on commit 178f1f7

Please sign in to comment.