Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add concise and detailed logs for missing or inconsistent voltage levels limits. #68

Merged
merged 3 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public static OpenReacResult run(Network network, String variantId, OpenReacPara
* @return All information about the run and possible modifications to apply.
*/
public static OpenReacResult run(Network network, String variantId, OpenReacParameters parameters, OpenReacConfig config, ComputationManager manager, ReportNode reportNode, AmplExportConfig amplExportConfig) {
checkParameters(network, variantId, parameters, config, manager, reportNode);
checkParameters(network, variantId, parameters, config, manager, Reports.createParametersIntegrityReporter(reportNode, network.getId()));
FranckLecuyer marked this conversation as resolved.
Show resolved Hide resolved
AmplModel reactiveOpf = OpenReacModel.buildModel();
OpenReacAmplIOFiles amplIoInterface = new OpenReacAmplIOFiles(parameters, amplExportConfig, network, config.isDebug(), Reports.createOpenReacReporter(reportNode, network.getId(), parameters.getObjective()));
AmplResults run = AmplModelRunner.run(network, variantId, reactiveOpf, manager, amplIoInterface);
Expand Down Expand Up @@ -118,6 +118,6 @@ private static void checkParameters(Network network, String variantId, OpenReacP
Objects.requireNonNull(config);
Objects.requireNonNull(manager);
Objects.requireNonNull(reportNode);
parameters.checkIntegrity(network);
parameters.checkIntegrity(network, reportNode);
FranckLecuyer marked this conversation as resolved.
Show resolved Hide resolved
}
}
8 changes: 8 additions & 0 deletions open-reac/src/main/java/com/powsybl/openreac/Reports.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,12 @@ public static void reportVariableShuntCompensatorsSize(ReportNode reportNode, in
.withUntypedValue("size", variableShuntCompensatorsSize)
.add();
}

public static ReportNode createParametersIntegrityReporter(ReportNode reportNode, String networkId) {
FranckLecuyer marked this conversation as resolved.
Show resolved Hide resolved
return reportNode.newReportNode()
.withMessageTemplate("openReacParametersIntegrity", "Open reac parameters integrity on network '${networkId}'")
FranckLecuyer marked this conversation as resolved.
Show resolved Hide resolved
.withUntypedValue("networkId", networkId)
.add();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@
*/
package com.powsybl.openreac.parameters.input;

import com.powsybl.commons.report.ReportNode;
import com.powsybl.commons.report.TypedValue;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.VoltageLevel;
import com.powsybl.openreac.exceptions.InvalidParametersException;
import com.powsybl.openreac.parameters.input.algo.*;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.stream.Collectors;

/**
* This class stores all inputs parameters specific to the OpenReac optimizer.
Expand Down Expand Up @@ -536,10 +538,14 @@ public List<OpenReacAlgoParam> getAllAlgorithmParams() {
/**
* Do some checks on the parameters given, such as provided IDs must correspond to the given network element
*
* @param network Network on which ID are going to be infered
* @param network Network on which ID are going to be infered
* @param reportNode aggregates functional logging
* @throws InvalidParametersException if the parameters contain some incoherences.
*/
public void checkIntegrity(Network network) throws InvalidParametersException {
public void checkIntegrity(Network network, ReportNode reportNode) throws InvalidParametersException {
Map<String, Pair<Integer, Integer>> voltageLevelsWithMissingLimits = new TreeMap<>();
Map<String, Pair<Double, Double>> voltageLevelsWithInconsistentLimits = new TreeMap<>();

for (String shuntId : getVariableShuntCompensators()) {
if (network.getShuntCompensator(shuntId) == null) {
throw new InvalidParametersException("Shunt " + shuntId + " not found in the network.");
Expand All @@ -562,16 +568,53 @@ public void checkIntegrity(Network network) throws InvalidParametersException {
}

// Check integrity of voltage overrides
boolean integrityVoltageLimitOverrides = checkVoltageLimitOverrides(network);
if (!integrityVoltageLimitOverrides) {
throw new InvalidParametersException("At least one voltage limit override is inconsistent.");
}
boolean integrityVoltageLimitOverrides = checkVoltageLimitOverrides(network, voltageLevelsWithInconsistentLimits);

// Check integrity of low/high voltage limits, taking into account voltage limit overrides
boolean integrityVoltageLevelLimits = checkLowVoltageLevelLimits(network);
integrityVoltageLevelLimits &= checkHighVoltageLevelLimits(network);
if (!integrityVoltageLevelLimits) {
throw new InvalidParametersException("At least one voltage level has an undefined or incorrect voltage limit.");
boolean integrityVoltageLevelLimits = checkLowVoltageLevelLimits(network, voltageLevelsWithMissingLimits);
integrityVoltageLevelLimits &= checkHighVoltageLevelLimits(network, voltageLevelsWithMissingLimits);

if (!integrityVoltageLevelLimits || !integrityVoltageLimitOverrides) {
if (!voltageLevelsWithMissingLimits.isEmpty()) {
reportNode.newReportNode()
.withMessageTemplate("nbVoltageLevelsWithMissingLimits", "${size} voltage level(s) have undefined low and/or high voltage limits")
.withSeverity(TypedValue.INFO_SEVERITY)
.withUntypedValue("size", voltageLevelsWithMissingLimits.size())
.add();
voltageLevelsWithMissingLimits.forEach((key, value) -> {
String messageSuffix = "has undefined low and high voltage limits";
if (value.getLeft() == 0) {
messageSuffix = "has undefined high voltage limit";
} else if (value.getRight() == 0) {
messageSuffix = "has undefined low voltage limit";
}
reportNode.newReportNode()
.withMessageTemplate("voltageLevelWithMissingLimits", "${vlId} " + messageSuffix)
.withSeverity(TypedValue.TRACE_SEVERITY)
.withUntypedValue("vlId", key)
.add();
});
}
if (!voltageLevelsWithInconsistentLimits.isEmpty()) {
reportNode.newReportNode()
.withMessageTemplate("nbVoltageLevelsWithInconsistentLimits", "${size} voltage level(s) have inconsistent low and/or high voltage limits")
.withSeverity(TypedValue.INFO_SEVERITY)
.withUntypedValue("size", voltageLevelsWithInconsistentLimits.size())
.add();
voltageLevelsWithInconsistentLimits.forEach((key, value) -> reportNode.newReportNode()
.withMessageTemplate("voltageLevelWithInconsistentLimits", "${vlId} has one or two inconsistent voltage limits (low voltage limit = ${low}, high voltage limit = ${high})")
.withSeverity(TypedValue.TRACE_SEVERITY)
.withUntypedValue("vlId", key)
.withUntypedValue("low", value.getLeft())
.withUntypedValue("high", value.getRight())
.add());
}

if (!integrityVoltageLevelLimits) {
throw new InvalidParametersException("At least one voltage level has an undefined or incorrect voltage limit.");
} else {
throw new InvalidParametersException("At least one voltage limit override is inconsistent.");
}
}

boolean integrityAlgorithmParameters = checkAlgorithmParametersIntegrity();
Expand All @@ -580,6 +623,16 @@ public void checkIntegrity(Network network) throws InvalidParametersException {
}
}

/**
* Do some checks on the parameters given, such as provided IDs must correspond to the given network element
*
* @param network Network on which ID are going to be infered
* @throws InvalidParametersException if the parameters contain some incoherences.
*/
public void checkIntegrity(Network network) throws InvalidParametersException {
checkIntegrity(network, ReportNode.NO_OP);
}

/**
* @return true if the algorithm parameters are consistent, false otherwise.
*/
Expand Down Expand Up @@ -628,7 +681,7 @@ public boolean checkAlgorithmParametersIntegrity() {
* @return true if the low voltage level limits are correct taking into account low voltage limit overrides,
* false otherwise.
*/
boolean checkLowVoltageLevelLimits(Network network) {
boolean checkLowVoltageLevelLimits(Network network, Map<String, Pair<Integer, Integer>> voltageLevelsWithMissingLimits) {
boolean integrityVoltageLevelLimits = true;

for (VoltageLevel vl : network.getVoltageLevels()) {
Expand All @@ -637,9 +690,11 @@ boolean checkLowVoltageLevelLimits(Network network) {
if (Double.isNaN(lowLimit)) {
List<VoltageLimitOverride> overrides = getSpecificVoltageLimits(vl.getId(), VoltageLimitOverride.VoltageLimitType.LOW_VOLTAGE_LIMIT);
if (overrides.size() != 1) {
voltageLevelsWithMissingLimits.merge(vl.getId(), Pair.of(1, 0), (old, value) -> Pair.of(old.getLeft() + 1, old.getRight()));
LOGGER.warn("Voltage level {} has no low voltage limit defined. Please add one or use a voltage limit override.", vl.getId());
integrityVoltageLevelLimits = false;
} else if (overrides.get(0).isRelative()) { // we have one and just one
voltageLevelsWithMissingLimits.merge(vl.getId(), Pair.of(1, 0), (old, value) -> Pair.of(old.getLeft() + 1, old.getRight()));
LOGGER.warn("Relative voltage override impossible on undefined low voltage limit for voltage level {}.", vl.getId());
integrityVoltageLevelLimits = false;
}
Expand All @@ -655,7 +710,7 @@ boolean checkLowVoltageLevelLimits(Network network) {
* @return true if the high voltage level limits are correct taking into account high voltage limit overrides,
* false otherwise.
*/
boolean checkHighVoltageLevelLimits(Network network) {
boolean checkHighVoltageLevelLimits(Network network, Map<String, Pair<Integer, Integer>> voltageLevelsWithMissingLimits) {
boolean integrityVoltageLevelLimits = true;

for (VoltageLevel vl : network.getVoltageLevels()) {
Expand All @@ -664,9 +719,11 @@ boolean checkHighVoltageLevelLimits(Network network) {
if (Double.isNaN(highLimit)) {
List<VoltageLimitOverride> overrides = getSpecificVoltageLimits(vl.getId(), VoltageLimitOverride.VoltageLimitType.HIGH_VOLTAGE_LIMIT);
if (overrides.size() != 1) {
voltageLevelsWithMissingLimits.merge(vl.getId(), Pair.of(0, 1), (old, value) -> Pair.of(old.getLeft(), old.getRight() + 1));
LOGGER.warn("Voltage level {} has no high voltage limit defined. Please add one or use a voltage limit override.", vl.getId());
integrityVoltageLevelLimits = false;
} else if (overrides.get(0).isRelative()) {
voltageLevelsWithMissingLimits.merge(vl.getId(), Pair.of(0, 1), (old, value) -> Pair.of(old.getLeft(), old.getRight() + 1));
LOGGER.warn("Relative voltage override impossible on undefined high voltage limit for voltage level {}.", vl.getId());
integrityVoltageLevelLimits = false;
}
Expand All @@ -681,8 +738,11 @@ boolean checkHighVoltageLevelLimits(Network network) {
* @param network the network on which are applied voltage limit overrides.
* @return true if the integrity of voltage limit overrides is verified, false otherwise.
*/
boolean checkVoltageLimitOverrides(Network network) {
boolean checkVoltageLimitOverrides(Network network,
Map<String, Pair<Double, Double>> voltageLevelsWithInconsistentLimits) {
// Check integrity of voltage overrides
Map<String, Pair<Double, Double>> voltageLevelsLimitsAfterOverride = new HashMap<>();

boolean integrityVoltageLimitOverrides = true;
for (VoltageLimitOverride voltageLimitOverride : getSpecificVoltageLimits()) {
String voltageLevelId = voltageLimitOverride.getVoltageLevelId();
Expand All @@ -697,25 +757,56 @@ boolean checkVoltageLimitOverrides(Network network) {

if (voltageLimitOverride.isRelative()) {
double value = voltageLimitOverride.getVoltageLimitType() == VoltageLimitOverride.VoltageLimitType.LOW_VOLTAGE_LIMIT ?
voltageLevel.getLowVoltageLimit() : voltageLevel.getHighVoltageLimit();
voltageLevel.getLowVoltageLimit() : voltageLevel.getHighVoltageLimit();
if (Double.isNaN(value)) {
LOGGER.warn("Voltage level {} has undefined {}, relative voltage limit override is impossible.",
voltageLevelId, voltageLimitOverride.getVoltageLimitType());
voltageLevelId, voltageLimitOverride.getVoltageLimitType());
integrityVoltageLimitOverrides = false;
continue;
}
// verify voltage limit override does not lead to negative limit value
if (value + voltageLimitOverride.getLimit() < 0) {
double valueAfter = value + voltageLimitOverride.getLimit();
if (voltageLimitOverride.getVoltageLimitType() == VoltageLimitOverride.VoltageLimitType.LOW_VOLTAGE_LIMIT) {
voltageLevelsLimitsAfterOverride.merge(voltageLevelId, Pair.of(valueAfter, voltageLevel.getHighVoltageLimit()), (old, newValue) -> Pair.of(valueAfter, old.getRight()));
if (valueAfter < 0) {
voltageLevelsWithInconsistentLimits.merge(voltageLevelId, Pair.of(valueAfter, voltageLevel.getHighVoltageLimit()), (old, newValue) -> Pair.of(valueAfter, old.getRight()));
}
} else {
voltageLevelsLimitsAfterOverride.merge(voltageLevelId, Pair.of(voltageLevel.getLowVoltageLimit(), valueAfter), (old, newValue) -> Pair.of(old.getLeft(), valueAfter));
if (valueAfter < 0) {
voltageLevelsWithInconsistentLimits.merge(voltageLevelId, Pair.of(voltageLevel.getLowVoltageLimit(), valueAfter), (old, newValue) -> Pair.of(old.getLeft(), valueAfter));
}
}
if (valueAfter < 0) {
LOGGER.warn("Voltage level {} relative override leads to a negative {}.",
voltageLevelId, voltageLimitOverride.getVoltageLimitType());
voltageLevelId, voltageLimitOverride.getVoltageLimitType());
integrityVoltageLimitOverrides = false;
}
} else {
if (voltageLimitOverride.getVoltageLimitType() == VoltageLimitOverride.VoltageLimitType.LOW_VOLTAGE_LIMIT) {
voltageLevelsLimitsAfterOverride.merge(voltageLevelId, Pair.of(voltageLimitOverride.getLimit(), voltageLevel.getHighVoltageLimit()), (old, newValue) -> Pair.of(voltageLimitOverride.getLimit(), old.getRight()));
} else {
voltageLevelsLimitsAfterOverride.merge(voltageLevelId, Pair.of(voltageLevel.getLowVoltageLimit(), voltageLimitOverride.getLimit()), (old, newValue) -> Pair.of(old.getLeft(), voltageLimitOverride.getLimit()));
}
}
}

// check low limit is lower than high limit after overrides
if (integrityVoltageLimitOverrides) {
for (Map.Entry<String, Pair<Double, Double>> entry : voltageLevelsLimitsAfterOverride.entrySet()) {
String vlId = entry.getKey();
if (entry.getValue().getLeft() > entry.getValue().getRight()) {
voltageLevelsWithInconsistentLimits.merge(vlId, Pair.of(entry.getValue().getLeft(), entry.getValue().getRight()), (old, newValue) -> Pair.of(entry.getValue().getLeft(), entry.getValue().getRight()));
integrityVoltageLimitOverrides = false;
}
}
}

return integrityVoltageLimitOverrides;
}

private List<VoltageLimitOverride> getSpecificVoltageLimits(String voltageLevelId, VoltageLimitOverride.VoltageLimitType type) {
return specificVoltageLimits.stream()
.filter(limit -> limit.getVoltageLevelId().equals(voltageLevelId) && limit.getVoltageLimitType() == type).collect(Collectors.toList());
.filter(limit -> limit.getVoltageLevelId().equals(voltageLevelId) && limit.getVoltageLimitType() == type).toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.powsybl.iidm.network.*;
import com.powsybl.openreac.exceptions.InvalidParametersException;
import com.powsybl.openreac.parameters.input.OpenReacParameters;
import com.powsybl.openreac.parameters.input.VoltageLimitOverride;
import com.powsybl.openreac.parameters.input.algo.OpenReacAlgoParam;
import com.powsybl.openreac.parameters.input.algo.OpenReacAmplLogLevel;
import com.powsybl.openreac.parameters.input.algo.OpenReacOptimisationObjective;
Expand All @@ -26,7 +27,7 @@
* @author Nicolas PIERRE {@literal <nicolas.pierre at artelys.com>}
* @author Pierre ARVY {@literal <pierre.arvy at artelys.com>}
*/
public class OpenReacParametersTest {
class OpenReacParametersTest {

@Test
void testObjectiveIntegrity() {
Expand Down Expand Up @@ -412,6 +413,33 @@ void testListsOfParametersIntegrity() {
testBusesWithReactiveSlacksParametersIntegrity(network, wrongId);
}

@Test
void testMissingVoltageLevelsLimitsIntegrity() {
Network network = IeeeCdfNetworkFactory.create57();
OpenReacParameters parameters = new OpenReacParameters();
InvalidParametersException e = assertThrows(InvalidParametersException.class, () -> parameters.checkIntegrity(network));
assertEquals("At least one voltage level has an undefined or incorrect voltage limit.", e.getMessage());
}

@Test
void testInconsistentVoltageLevelsLimitsIntegrity() {
Network network = IeeeCdfNetworkFactory.create57();
setDefaultVoltageLimits(network); // set default voltage limits to every voltage levels of the network
VoltageLevel vl = network.getVoltageLevels().iterator().next();
OpenReacParameters parameters = new OpenReacParameters();

// if low relative voltage override leads to low limit < 0, throws exception
parameters.addSpecificVoltageLimits(List.of(new VoltageLimitOverride(vl.getId(), VoltageLimitOverride.VoltageLimitType.LOW_VOLTAGE_LIMIT, true, -2.)));
InvalidParametersException e = assertThrows(InvalidParametersException.class, () -> parameters.checkIntegrity(network));
assertEquals("At least one voltage limit override is inconsistent.", e.getMessage());

// if high relative voltage override leads to high limit lower than low limit, throws exception
parameters.getSpecificVoltageLimits().clear();
parameters.addSpecificVoltageLimits(List.of(new VoltageLimitOverride(vl.getId(), VoltageLimitOverride.VoltageLimitType.HIGH_VOLTAGE_LIMIT, true, -0.5)));
InvalidParametersException e1 = assertThrows(InvalidParametersException.class, () -> parameters.checkIntegrity(network));
assertEquals("At least one voltage limit override is inconsistent.", e1.getMessage());
}

void testTwoWindingsTransformersParametersIntegrity(Network network, String wrongId) {
OpenReacParameters parameters = new OpenReacParameters();
parameters.addVariableTwoWindingsTransformers(network.getTwoWindingsTransformerStream().map(TwoWindingsTransformer::getId).collect(Collectors.toList()));
Expand Down
Loading
Loading