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 all commits
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 @@ -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, Reports.createParameterIntegrityReporter(reportNode, network.getId()));
}
}
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 createParameterIntegrityReporter(ReportNode reportNode, String networkId) {
return reportNode.newReportNode()
.withMessageTemplate("openReacParameterIntegrity", "Open reac parameter integrity on network '${networkId}'")
.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 @@ -533,13 +535,69 @@ public List<OpenReacAlgoParam> getAllAlgorithmParams() {
return allAlgoParams;
}

private void checkLowAndHighVoltageLimitIntegrity(Network network, boolean integrityVoltageLimitOverrides,
Map<String, Pair<Double, Double>> voltageLevelsWithInconsistentLimits,
ReportNode reportNode) {
Map<String, Pair<Integer, Integer>> voltageLevelsWithMissingLimits = new TreeMap<>();

// Check integrity of low/high voltage limits, taking into account voltage limit overrides
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.");
}
}
}

/**
* 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<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,24 +620,27 @@ 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.");
}
checkLowAndHighVoltageLimitIntegrity(network, integrityVoltageLimitOverrides, voltageLevelsWithInconsistentLimits, reportNode);

boolean integrityAlgorithmParameters = checkAlgorithmParametersIntegrity();
if (!integrityAlgorithmParameters) {
throw new InvalidParametersException("At least one algorithm parameter is inconsistent.");
}
}

/**
* 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 +689,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 +698,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 +718,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 +727,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 @@ -677,12 +742,57 @@ boolean checkHighVoltageLevelLimits(Network network) {
return integrityVoltageLevelLimits;
}

private boolean checkRelativeVoltageLimitOverrides(VoltageLimitOverride voltageLimitOverride, VoltageLevel voltageLevel,
Map<String, Pair<Double, Double>> voltageLevelsLimitsAfterOverride,
Map<String, Pair<Double, Double>> voltageLevelsWithInconsistentLimits) {
boolean integrityVoltageLimitOverrides = true;
double value = voltageLimitOverride.getVoltageLimitType() == VoltageLimitOverride.VoltageLimitType.LOW_VOLTAGE_LIMIT ?
voltageLevel.getLowVoltageLimit() : voltageLevel.getHighVoltageLimit();
if (Double.isNaN(value)) {
LOGGER.warn("Voltage level {} has undefined {}, relative voltage limit override is impossible.",
voltageLevel.getId(), voltageLimitOverride.getVoltageLimitType());
integrityVoltageLimitOverrides = false;
} else {
// verify voltage limit override does not lead to negative limit value
double valueAfter = value + voltageLimitOverride.getLimit();
if (voltageLimitOverride.getVoltageLimitType() == VoltageLimitOverride.VoltageLimitType.LOW_VOLTAGE_LIMIT) {
voltageLevelsLimitsAfterOverride.merge(voltageLevel.getId(), Pair.of(valueAfter, voltageLevel.getHighVoltageLimit()), (old, newValue) -> Pair.of(valueAfter, old.getRight()));
if (valueAfter < 0) {
voltageLevelsWithInconsistentLimits.merge(voltageLevel.getId(), Pair.of(valueAfter, voltageLevel.getHighVoltageLimit()), (old, newValue) -> Pair.of(valueAfter, old.getRight()));
}
} else {
voltageLevelsLimitsAfterOverride.merge(voltageLevel.getId(), Pair.of(voltageLevel.getLowVoltageLimit(), valueAfter), (old, newValue) -> Pair.of(old.getLeft(), valueAfter));
if (valueAfter < 0) {
voltageLevelsWithInconsistentLimits.merge(voltageLevel.getId(), 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 {}.",
voltageLevel.getId(), voltageLimitOverride.getVoltageLimitType());
integrityVoltageLimitOverrides = false;
}
}
return integrityVoltageLimitOverrides;
}

private void checkAbsoluteVoltageLimitOverrides(VoltageLimitOverride voltageLimitOverride, VoltageLevel voltageLevel,
Map<String, Pair<Double, Double>> voltageLevelsLimitsAfterOverride) {
if (voltageLimitOverride.getVoltageLimitType() == VoltageLimitOverride.VoltageLimitType.LOW_VOLTAGE_LIMIT) {
voltageLevelsLimitsAfterOverride.merge(voltageLevel.getId(), Pair.of(voltageLimitOverride.getLimit(), voltageLevel.getHighVoltageLimit()), (old, newValue) -> Pair.of(voltageLimitOverride.getLimit(), old.getRight()));
} else {
voltageLevelsLimitsAfterOverride.merge(voltageLevel.getId(), Pair.of(voltageLevel.getLowVoltageLimit(), voltageLimitOverride.getLimit()), (old, newValue) -> Pair.of(old.getLeft(), voltageLimitOverride.getLimit()));
}
}

/**
* @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 @@ -696,26 +806,28 @@ boolean checkVoltageLimitOverrides(Network network) {
}

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

// 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();
}
}
Loading
Loading