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

Voltage limit override new version #27

Merged
merged 17 commits into from
Oct 19, 2023
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
10 changes: 7 additions & 3 deletions open-reac/src/main/java/com/powsybl/openreac/OpenReacTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,13 @@ public OpenReacParameters createOpenReacParameters(CommandLine line,
ArrayNode array = (ArrayNode) jsonNode.get(VOLTAGE_OVERRIDE_LIST);
array.forEach(node -> {
String voltageId = node.get("id").asText();
double lowerPercent = node.get("lower").asDouble();
double upperPercent = node.get("upper").asDouble();
openReacParameters.addSpecificVoltageLimits(Map.of(voltageId, new VoltageLimitOverride(lowerPercent, upperPercent)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@geofjamg can we delete the tool now? If yes, I will dot that in a other PR.

double lower = node.get("lower").asDouble();
double upper = node.get("upper").asDouble();

List<VoltageLimitOverride> voltageLimitOverrides = new ArrayList<>();
voltageLimitOverrides.add(new VoltageLimitOverride(voltageId, VoltageLimitOverride.VoltageLimitType.LOW_VOLTAGE_LIMIT, true, lower));
voltageLimitOverrides.add(new VoltageLimitOverride(voltageId, VoltageLimitOverride.VoltageLimitType.HIGH_VOLTAGE_LIMIT, true, upper));
openReacParameters.addSpecificVoltageLimits(voltageLimitOverrides);
});
}
boolean objectiveSet = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/
package com.powsybl.openreac.parameters.input;

import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.VoltageLevel;
import com.powsybl.openreac.exceptions.InvalidParametersException;
Expand All @@ -17,6 +16,7 @@
import org.slf4j.LoggerFactory;

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

/**
* This class stores all inputs parameters specific to the OpenReac optimizer.
Expand All @@ -26,23 +26,31 @@
public class OpenReacParameters {

private static final Logger LOGGER = LoggerFactory.getLogger(OpenReacParameters.class);

private static final String OBJECTIVE_DISTANCE_KEY = "ratio_voltage_target";
private final Map<String, VoltageLimitOverride> specificVoltageLimits = new HashMap<>();

private final List<VoltageLimitOverride> specificVoltageLimits = new ArrayList<>();

private final List<String> variableShuntCompensators = new ArrayList<>();

private final List<String> constantQGenerators = new ArrayList<>();

private final List<String> variableTwoWindingsTransformers = new ArrayList<>();

private final List<OpenReacAlgoParam> algorithmParams = new ArrayList<>();

private OpenReacOptimisationObjective objective = OpenReacOptimisationObjective.MIN_GENERATION;

private Double objectiveDistance;

/**
* Override some voltage level limits in the network. This will NOT modify the network object.
* <p>
* The override is ignored if one or both of the voltage limit are NaN.
* @param specificVoltageLimits keys: a VoltageLevel ID, values: low and high delta limits (kV).
* @param specificVoltageLimits list of voltage limit overrides.
*/
public OpenReacParameters addSpecificVoltageLimits(Map<String, VoltageLimitOverride> specificVoltageLimits) {
this.specificVoltageLimits.putAll(Objects.requireNonNull(specificVoltageLimits));
public OpenReacParameters addSpecificVoltageLimits(List<VoltageLimitOverride> specificVoltageLimits) {
this.specificVoltageLimits.addAll(Objects.requireNonNull(specificVoltageLimits));
return this;
}

Expand Down Expand Up @@ -133,7 +141,7 @@ public List<String> getVariableShuntCompensators() {
return variableShuntCompensators;
}

public Map<String, VoltageLimitOverride> getSpecificVoltageLimits() {
public List<VoltageLimitOverride> getSpecificVoltageLimits() {
return specificVoltageLimits;
}

Expand Down Expand Up @@ -176,41 +184,126 @@ public void checkIntegrity(Network network) throws InvalidParametersException {
}
for (String transformerId : getVariableTwoWindingsTransformers()) {
if (network.getTwoWindingsTransformer(transformerId) == null) {
throw new InvalidParametersException("Two windings transfromer " + transformerId + " not found in the network.");
throw new InvalidParametersException("Two windings transformer " + transformerId + " not found in the network.");
}
}
for (String voltageLevelId : getSpecificVoltageLimits().keySet()) {
VoltageLevel voltageLevel = network.getVoltageLevel(voltageLevelId);
VoltageLimitOverride override = getSpecificVoltageLimits().get(voltageLevelId);
if (voltageLevel == null) {
throw new InvalidParametersException("Voltage level " + voltageLevelId + " not found in the network.");
} else {
if (voltageLevel.getNominalV()
+ override.getDeltaLowVoltageLimit()
< 0) {
throw new InvalidParametersException("Voltage level " + voltageLevelId + " override leads to negative lower voltage level.");

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

// 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.");
}

if (objective.equals(OpenReacOptimisationObjective.BETWEEN_HIGH_AND_LOW_VOLTAGE_LIMIT) && objectiveDistance == null) {
throw new InvalidParametersException("In using " + OpenReacOptimisationObjective.BETWEEN_HIGH_AND_LOW_VOLTAGE_LIMIT +
" as objective, a distance in percent between low and high voltage limits is expected.");
}

}

/**
* @param network the network on which voltage levels are verified.
* @return true if the low voltage level limits are correct taking into account low voltage limit overrides,
* false otherwise.
*/
boolean checkLowVoltageLevelLimits(Network network) {
boolean integrityVoltageLevelLimits = true;

for (VoltageLevel vl : network.getVoltageLevels()) {
double lowLimit = vl.getLowVoltageLimit();

if (lowLimit <= 0) {
List<VoltageLimitOverride> overrides = getSpecificVoltageLimits(vl.getId(), VoltageLimitOverride.VoltageLimitType.LOW_VOLTAGE_LIMIT);
if (overrides.size() != 1) {
LOGGER.warn("Voltage level {} has a negative or null low voltage limit. Please change it or use a voltage limit override.", vl.getId());
integrityVoltageLevelLimits = false;
}
}
if (Double.isNaN(lowLimit)) {
List<VoltageLimitOverride> overrides = getSpecificVoltageLimits(vl.getId(), VoltageLimitOverride.VoltageLimitType.LOW_VOLTAGE_LIMIT);
if (overrides.size() != 1) {
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
LOGGER.warn("Relative voltage override impossible on undefined low voltage limit for voltage level {}.", vl.getId());
integrityVoltageLevelLimits = false;
}
}
}
return integrityVoltageLevelLimits;
}

/**
* @param network the network on which voltage levels are verified.
* @return true if the high voltage level limits are correct taking into account high voltage limit overrides,
* false otherwise.
*/
boolean checkHighVoltageLevelLimits(Network network) {
boolean integrityVoltageLevelLimits = true;

for (VoltageLevel vl : network.getVoltageLevels()) {
double lowLimit = vl.getLowVoltageLimit();
double highLimit = vl.getHighVoltageLimit();
if (lowLimit == 0 && Double.isNaN(highLimit)) {
lowLimit = Double.NaN;
LOGGER.warn("Voltage level '{}' has an unsupported limit [0, NaN], fix to [NaN, NaN]", vl.getId());
}
// xor operator, exactly one limit must be NaN
if (Double.isNaN(highLimit) ^ Double.isNaN(lowLimit)) {
throw new PowsyblException(
"Voltage level '" + vl.getId() + "' has only one voltage limit defined (min:" + lowLimit +
", max:" + highLimit + "). Please define none or both.");

if (Double.isNaN(highLimit)) {
List<VoltageLimitOverride> overrides = getSpecificVoltageLimits(vl.getId(), VoltageLimitOverride.VoltageLimitType.HIGH_VOLTAGE_LIMIT);
if (overrides.size() != 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()) {
LOGGER.warn("Relative voltage override impossible on undefined high voltage limit for voltage level {}.", vl.getId());
integrityVoltageLevelLimits = false;
}
}
}
return integrityVoltageLevelLimits;
}

if (objective.equals(OpenReacOptimisationObjective.BETWEEN_HIGH_AND_LOW_VOLTAGE_LIMIT) && objectiveDistance == null) {
throw new InvalidParametersException("In using " + OpenReacOptimisationObjective.BETWEEN_HIGH_AND_LOW_VOLTAGE_LIMIT +
" as objective, a distance in percent between low and high voltage limits is expected.");
/**
* @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) {
// Check integrity of voltage overrides
boolean integrityVoltageLimitOverrides = true;
for (VoltageLimitOverride voltageLimitOverride : getSpecificVoltageLimits()) {
String voltageLevelId = voltageLimitOverride.getVoltageLevelId();
VoltageLevel voltageLevel = network.getVoltageLevel(voltageLevelId);

// Check existence of voltage level on which is applied voltage limit override
if (voltageLevel == null) {
LOGGER.warn("Voltage level {} not found in the network.", voltageLevelId);
integrityVoltageLimitOverrides = false;
continue;
}

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 or null {}.",
voltageLevelId, voltageLimitOverride.getVoltageLimitType());
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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@
*/
package com.powsybl.openreac.parameters.input;

import com.powsybl.ampl.converter.AmplConstants;
import com.powsybl.ampl.converter.AmplSubset;
import com.powsybl.ampl.executor.AmplInputFile;
import com.powsybl.commons.util.StringToIntMapper;
import com.powsybl.iidm.network.Network;
import com.powsybl.openreac.parameters.AmplIOUtils;
import com.powsybl.openreac.exceptions.InvalidParametersException;
import org.jgrapht.alg.util.Pair;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

Expand All @@ -26,31 +27,45 @@
public class VoltageLevelLimitsOverrideInput implements AmplInputFile {

private static final String FILENAME = "ampl_network_substations_override.txt";
private final Map<String, VoltageLimitOverride> normalizedVoltageLimitsOverride;

public VoltageLevelLimitsOverrideInput(Map<String, VoltageLimitOverride> voltageLimitsOverride, Network network) {
Objects.requireNonNull(voltageLimitsOverride);
private final Map<String, Pair<Double, Double>> normalizedVoltageLimitsOverride;

public VoltageLevelLimitsOverrideInput(List<VoltageLimitOverride> voltageLimitsOverrides, Network network) {
Objects.requireNonNull(voltageLimitsOverrides);
Objects.requireNonNull(network);
this.normalizedVoltageLimitsOverride = new HashMap<>();
transformToNormalizedVoltage(voltageLimitsOverride, network);
transformToNormalizedVoltage(voltageLimitsOverrides, network);
}

/**
* voltageLimitsOverride contains absolute voltage limits.
* This function compute limits in pair-unit quantities.
*/
private void transformToNormalizedVoltage(Map<String, VoltageLimitOverride> voltageLimitsOverride, Network network) {
for (Map.Entry<String, VoltageLimitOverride> entry : voltageLimitsOverride.entrySet()) {
String voltageLevelId = entry.getKey();
VoltageLimitOverride limits = entry.getValue();
double previousLowVoltageLimit = network.getVoltageLevel(voltageLevelId).getLowVoltageLimit();
double previousHighVoltageLimit = network.getVoltageLevel(voltageLevelId).getHighVoltageLimit();
// If one of the limit is not defined, we ignore the override
if (!Double.isNaN(previousLowVoltageLimit) && !Double.isNaN(previousHighVoltageLimit)) {
double nominalV = network.getVoltageLevel(voltageLevelId).getNominalV();
normalizedVoltageLimitsOverride.put(voltageLevelId, new VoltageLimitOverride((previousLowVoltageLimit + limits.getDeltaLowVoltageLimit()) / nominalV,
(previousHighVoltageLimit + limits.getDeltaHighVoltageLimit()) / nominalV));
private void transformToNormalizedVoltage(List<VoltageLimitOverride> voltageLimitsOverrides, Network network) {
for (VoltageLimitOverride voltageLimitOverride : voltageLimitsOverrides) {
// get previous voltage limit values
String voltageLevelId = voltageLimitOverride.getVoltageLevelId();
double nominalV = network.getVoltageLevel(voltageLevelId).getNominalV();
double previousNormalizedLowVoltageLimit = network.getVoltageLevel(voltageLevelId).getLowVoltageLimit() / nominalV;
double previousNormalizedHighVoltageLimit = network.getVoltageLevel(voltageLevelId).getHighVoltageLimit() / nominalV;

// get or create voltage limit override of the voltage level
Pair<Double, Double> newLimits = normalizedVoltageLimitsOverride.containsKey(voltageLevelId) ? normalizedVoltageLimitsOverride.get(voltageLevelId)
: new Pair<>(previousNormalizedLowVoltageLimit, previousNormalizedHighVoltageLimit);
if (voltageLimitOverride.getVoltageLimitType() == VoltageLimitOverride.VoltageLimitType.LOW_VOLTAGE_LIMIT) {
double value = (voltageLimitOverride.isRelative() ? newLimits.getFirst() : 0.0) + voltageLimitOverride.getLimit() / nominalV;
newLimits.setFirst(value);
} else if (voltageLimitOverride.getVoltageLimitType() == VoltageLimitOverride.VoltageLimitType.HIGH_VOLTAGE_LIMIT) {
double value = (voltageLimitOverride.isRelative() ? newLimits.getSecond() : 0.0) + voltageLimitOverride.getLimit() / nominalV;
newLimits.setSecond(value);
} else {
throw new UnsupportedOperationException("Unsupported voltage limit type: " + voltageLimitOverride.getVoltageLimitType());
}

if (newLimits.getFirst() > newLimits.getSecond()) {
throw new InvalidParametersException("Override on voltage level " + voltageLevelId + " leads to low voltage limit > high voltage limit.");
}
normalizedVoltageLimitsOverride.put(voltageLevelId, newLimits);
}
}

Expand All @@ -64,19 +79,20 @@ public InputStream getParameterFileAsStream(StringToIntMapper<AmplSubset> string
StringBuilder dataBuilder = new StringBuilder();
dataBuilder.append("#num minV (pu) maxV (pu) id");
dataBuilder.append(System.lineSeparator());
for (Map.Entry<String, VoltageLimitOverride> entry : normalizedVoltageLimitsOverride.entrySet()) {

for (Map.Entry<String, Pair<Double, Double>> entry : normalizedVoltageLimitsOverride.entrySet()) {
String voltageLevelId = entry.getKey();
VoltageLimitOverride limits = entry.getValue();
if (!Double.isNaN(limits.getDeltaHighVoltageLimit()) || !Double.isNaN(limits.getDeltaLowVoltageLimit())) {
Pair<Double, Double> limits = entry.getValue();

if (!Double.isNaN(limits.getFirst()) || !Double.isNaN(limits.getSecond())) {
int amplId = stringToIntMapper.getInt(AmplSubset.VOLTAGE_LEVEL, voltageLevelId);
double newHighVoltageLimit = Double.isNaN(limits.getDeltaHighVoltageLimit()) ? AmplConstants.INVALID_FLOAT_VALUE : limits.getDeltaHighVoltageLimit();
double newLowVoltageLimit = Double.isNaN(limits.getDeltaLowVoltageLimit()) ? AmplConstants.INVALID_FLOAT_VALUE : limits.getDeltaLowVoltageLimit();
String[] tokens = {Integer.toString(amplId), Double.toString(newLowVoltageLimit), Double.toString(newHighVoltageLimit), AmplIOUtils.addQuotes(voltageLevelId)};
String[] tokens = {Integer.toString(amplId), Double.toString(limits.getFirst()), Double.toString(limits.getSecond()), "\"" + voltageLevelId + "\""};
dataBuilder.append(String.join(" ", tokens));
dataBuilder.append(System.lineSeparator());
}
}
//add new line at the end of the file !

//add new line at the end of the file
dataBuilder.append(System.lineSeparator());
return new ByteArrayInputStream(dataBuilder.toString().getBytes(StandardCharsets.UTF_8));
}
Expand Down
Loading