LimitViolationUtils.java
/**
* Copyright (c) 2018, 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.iidm.network.util;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.limitmodification.LimitsComputer;
import com.powsybl.iidm.network.limitmodification.result.AbstractDistinctLimitsContainer;
import com.powsybl.iidm.network.limitmodification.result.LimitsContainer;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
/**
*
* Helper methods for checking the occurrence of overloads.
*
* @author Teofil Calin BANC {@literal <teofil-calin.banc at rte-france.com>}
*/
public final class LimitViolationUtils {
public static final String PERMANENT_LIMIT_NAME = "permanent";
private LimitViolationUtils() {
}
public static Overload checkTemporaryLimits(Branch<?> branch, TwoSides side, double limitReductionValue, double i, LimitType type) {
Objects.requireNonNull(branch);
Objects.requireNonNull(side);
return getLimits(branch, side.toThreeSides(), type, LimitsComputer.NO_MODIFICATIONS)
.map(limits -> getOverload(limits.getLimits(), i, limitReductionValue))
.orElse(null);
}
public static Overload checkTemporaryLimits(ThreeWindingsTransformer transformer, ThreeSides side, double limitReductionValue, double i, LimitType type) {
Objects.requireNonNull(transformer);
Objects.requireNonNull(side);
return getLimits(transformer, side, type, LimitsComputer.NO_MODIFICATIONS)
.map(limits -> getOverload(limits.getLimits(), i, limitReductionValue))
.orElse(null);
}
public static Overload checkTemporaryLimits(Branch<?> branch, TwoSides side, LimitsComputer<Identifiable<?>, LoadingLimits> limitsComputer, double i, LimitType type) {
Objects.requireNonNull(branch);
Objects.requireNonNull(side);
return getLimits(branch, side.toThreeSides(), type, limitsComputer)
.map(limits -> getOverload(limits, i))
.orElse(null);
}
public static Overload checkTemporaryLimits(ThreeWindingsTransformer transformer, ThreeSides side, LimitsComputer<Identifiable<?>, LoadingLimits> limitsComputer, double i, LimitType type) {
Objects.requireNonNull(transformer);
Objects.requireNonNull(side);
return getLimits(transformer, side, type, limitsComputer)
.map(limits -> getOverload(limits, i))
.orElse(null);
}
private static OverloadImpl getOverload(LoadingLimits limits, double i, double limitReductionValue) {
double permanentLimit = limits.getPermanentLimit();
if (Double.isNaN(i) || Double.isNaN(permanentLimit)) {
return null;
}
Collection<LoadingLimits.TemporaryLimit> temporaryLimits = limits.getTemporaryLimits();
String previousLimitName = PERMANENT_LIMIT_NAME;
double previousLimit = permanentLimit;
for (LoadingLimits.TemporaryLimit tl : temporaryLimits) { // iterate in ascending order
if (i >= previousLimit * limitReductionValue && i < tl.getValue() * limitReductionValue) {
return new OverloadImpl(tl, previousLimitName, previousLimit);
}
previousLimitName = tl.getName();
previousLimit = tl.getValue();
}
return null;
}
private static Overload getOverload(LimitsContainer<LoadingLimits> limitsContainer, double i) {
double permanentLimit = limitsContainer.getLimits().getPermanentLimit();
if (Double.isNaN(i) || Double.isNaN(permanentLimit)) {
return null;
}
Collection<LoadingLimits.TemporaryLimit> temporaryLimits = limitsContainer.getLimits().getTemporaryLimits();
String previousLimitName = PERMANENT_LIMIT_NAME;
double previousLimit = permanentLimit;
int previousAcceptableDuration = 0; // never mind initialisation it will be overridden with first loop
boolean isFirstTemporaryLimit = true;
for (LoadingLimits.TemporaryLimit tl : temporaryLimits) { // iterate in ascending order
if (i >= previousLimit && i < tl.getValue()) {
double limit = previousLimit;
double reduction = 1;
if (limitsContainer.isDistinct()) {
AbstractDistinctLimitsContainer<?, ?> container = (AbstractDistinctLimitsContainer<?, ?>) limitsContainer;
if (isFirstTemporaryLimit) {
limit = container.getOriginalPermanentLimit();
reduction = container.getPermanentLimitReduction();
} else {
limit = container.getOriginalTemporaryLimit(previousAcceptableDuration);
reduction = container.getTemporaryLimitReduction(previousAcceptableDuration);
}
}
return new OverloadImpl(tl, previousLimitName, limit, reduction);
}
isFirstTemporaryLimit = false;
previousLimitName = tl.getName();
previousLimit = tl.getValue();
previousAcceptableDuration = tl.getAcceptableDuration();
}
return null;
}
private static PermanentLimitCheckResult checkPermanentLimitIfAny(LimitsContainer<LoadingLimits> limitsContainer, double i) {
return checkPermanentLimitIfAny(limitsContainer, i, 1);
}
private static PermanentLimitCheckResult checkPermanentLimitIfAny(LimitsContainer<LoadingLimits> limitsContainer, double i, double limitReductionValue) {
double permanentLimit = limitsContainer.getLimits().getPermanentLimit();
if (Double.isNaN(i) || Double.isNaN(permanentLimit)) {
return new PermanentLimitCheckResult(false, limitReductionValue);
}
if (i >= permanentLimit * limitReductionValue) {
return new PermanentLimitCheckResult(true, limitsContainer.isDistinct() ? ((AbstractDistinctLimitsContainer<?, ?>) limitsContainer).getPermanentLimitReduction() : limitReductionValue);
}
return new PermanentLimitCheckResult(false, limitReductionValue);
}
public static boolean checkPermanentLimit(Branch<?> branch, TwoSides side, double limitReductionValue, double i, LimitType type) {
return getLimits(branch, side.toThreeSides(), type, LimitsComputer.NO_MODIFICATIONS)
.map(l -> checkPermanentLimitIfAny(l, i, limitReductionValue).isOverload())
.orElse(false);
}
public static PermanentLimitCheckResult checkPermanentLimit(Branch<?> branch, TwoSides side, double i, LimitType type, LimitsComputer<Identifiable<?>, LoadingLimits> computer) {
return getLimits(branch, side.toThreeSides(), type, computer)
.map(l -> checkPermanentLimitIfAny(l, i))
.orElse(new PermanentLimitCheckResult(false, 1.0));
}
public static boolean checkPermanentLimit(ThreeWindingsTransformer transformer, ThreeSides side, double limitReductionValue, double i, LimitType type) {
return getLimits(transformer, side, type, LimitsComputer.NO_MODIFICATIONS)
.map(l -> checkPermanentLimitIfAny(l, i, limitReductionValue).isOverload())
.orElse(false);
}
public static PermanentLimitCheckResult checkPermanentLimit(ThreeWindingsTransformer transformer, ThreeSides side, LimitsComputer<Identifiable<?>, LoadingLimits> computer, double i, LimitType type) {
return getLimits(transformer, side, type, computer)
.map(l -> checkPermanentLimitIfAny(l, i))
.orElse(null);
}
public static double getValueForLimit(Terminal t, LimitType type) {
return switch (type) {
case ACTIVE_POWER -> t.getP();
case APPARENT_POWER -> Math.sqrt(t.getP() * t.getP() + t.getQ() * t.getQ());
case CURRENT -> t.getI();
default ->
throw new UnsupportedOperationException(String.format("Getting %s limits is not supported.", type.name()));
};
}
public static boolean checkPermanentLimit(ThreeWindingsTransformer transformer, ThreeSides side, double limitReductionValue, LimitType type) {
return checkPermanentLimit(transformer, side, limitReductionValue, getValueForLimit(transformer.getTerminal(side), type), type);
}
public static PermanentLimitCheckResult checkPermanentLimit(ThreeWindingsTransformer transformer, ThreeSides side, LimitType type, LimitsComputer<Identifiable<?>, LoadingLimits> computer) {
return checkPermanentLimit(transformer, side, computer, getValueForLimit(transformer.getTerminal(side), type), type);
}
public static Overload checkTemporaryLimits(ThreeWindingsTransformer transformer, ThreeSides side, double limitReductionValue, LimitType type) {
return checkTemporaryLimits(transformer, side, limitReductionValue, getValueForLimit(transformer.getTerminal(side), type), type);
}
public static Overload checkTemporaryLimits(ThreeWindingsTransformer transformer, ThreeSides side, LimitType type, LimitsComputer<Identifiable<?>, LoadingLimits> computer) {
return checkTemporaryLimits(transformer, side, computer, getValueForLimit(transformer.getTerminal(side), type), type);
}
public static Optional<? extends LimitsContainer<LoadingLimits>> getLimits(Identifiable<?> transformer, ThreeSides side, LimitType type, LimitsComputer<Identifiable<?>, LoadingLimits> computer) {
return computer.computeLimits(transformer, type, side, false);
}
/**
* @deprecated should use {@link #getLoadingLimits(Identifiable, LimitType, ThreeSides)} instead
*/
@Deprecated(since = "6.4.0")
public static Optional<? extends LoadingLimits> getLimits(Branch<?> branch, TwoSides side, LimitType type) {
return branch.getLimits(type, side);
}
/**
* @deprecated should use {@link #getLoadingLimits(Identifiable, LimitType, ThreeSides)} instead
*/
@Deprecated(since = "6.4.0")
public static Optional<? extends LoadingLimits> getLimits(ThreeWindingsTransformer transformer, ThreeSides side, LimitType type) {
return transformer.getLeg(side).getLimits(type);
}
public static Optional<LoadingLimits> getLoadingLimits(Identifiable<?> identifiable, LimitType limitType, ThreeSides side) {
return switch (identifiable.getType()) {
case LINE -> (Optional<LoadingLimits>) ((Line) identifiable).getLimits(limitType, side.toTwoSides());
case TIE_LINE -> (Optional<LoadingLimits>) ((TieLine) identifiable).getLimits(limitType, side.toTwoSides());
case TWO_WINDINGS_TRANSFORMER ->
(Optional<LoadingLimits>) ((TwoWindingsTransformer) identifiable).getLimits(limitType, side.toTwoSides());
case THREE_WINDINGS_TRANSFORMER ->
(Optional<LoadingLimits>) ((ThreeWindingsTransformer) identifiable).getLeg(side).getLimits(limitType);
default -> Optional.empty();
};
}
}