DefaultLimitViolationDetector.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.security.detectors;

import com.powsybl.iidm.network.*;
import com.powsybl.security.*;

import java.util.*;
import java.util.function.Consumer;

import static com.powsybl.security.LimitViolationDetection.createViolationLocation;

/**
 * Implements the default behaviour for limit violation detection.
 *
 * @author Sylvain Leclerc {@literal <sylvain.leclerc at rte-france.com>}
 */
public class DefaultLimitViolationDetector extends AbstractContingencyBlindDetector {

    private final double limitReductionValue;
    private final Set<LoadingLimitType> currentLimitTypes;

    public DefaultLimitViolationDetector(double limitReductionValue, Collection<LoadingLimitType> currentLimitTypes) {
        if (limitReductionValue <= 0) {
            throw new IllegalArgumentException("Bad limit reduction " + limitReductionValue);
        }
        this.limitReductionValue = limitReductionValue;
        this.currentLimitTypes = EnumSet.copyOf(Objects.requireNonNull(currentLimitTypes));
    }

    public DefaultLimitViolationDetector(Collection<LoadingLimitType> currentLimitTypes) {
        this(1.0f, currentLimitTypes);
    }

    public DefaultLimitViolationDetector() {
        this(EnumSet.allOf(LoadingLimitType.class));
    }

    @Override
    public void checkCurrent(Branch branch, TwoSides side, double value, Consumer<LimitViolation> consumer) {

        checkLimitViolation(branch, side, value, consumer, LimitType.CURRENT);
    }

    @Override
    public void checkCurrent(ThreeWindingsTransformer transformer, ThreeSides side, double value, Consumer<LimitViolation> consumer) {

        checkLimitViolation(transformer, side, value, consumer, LimitType.CURRENT);
    }

    @Override
    public void checkActivePower(Branch branch, TwoSides side, double value, Consumer<LimitViolation> consumer) {

        checkLimitViolation(branch, side, value, consumer, LimitType.ACTIVE_POWER);
    }

    @Override
    public void checkActivePower(ThreeWindingsTransformer transformer, ThreeSides side, double value, Consumer<LimitViolation> consumer) {
        checkLimitViolation(transformer, side, value, consumer, LimitType.ACTIVE_POWER);
    }

    @Override
    public void checkApparentPower(Branch branch, TwoSides side, double value, Consumer<LimitViolation> consumer) {

        checkLimitViolation(branch, side, value, consumer, LimitType.APPARENT_POWER);
    }

    @Override
    public void checkApparentPower(ThreeWindingsTransformer transformer, ThreeSides side, double value, Consumer<LimitViolation> consumer) {
        checkLimitViolation(transformer, side, value, consumer, LimitType.APPARENT_POWER);
    }

    @Override
    public void checkVoltage(Bus bus, double value, Consumer<LimitViolation> consumer) {
        VoltageLevel vl = bus.getVoltageLevel();
        if (!Double.isNaN(vl.getLowVoltageLimit()) && value <= vl.getLowVoltageLimit()) {
            consumer.accept(new LimitViolation(vl.getId(), vl.getOptionalName().orElse(null), LimitViolationType.LOW_VOLTAGE,
                    vl.getLowVoltageLimit(), limitReductionValue, value, createViolationLocation(bus)));
        }

        if (!Double.isNaN(vl.getHighVoltageLimit()) && value >= vl.getHighVoltageLimit()) {
            consumer.accept(new LimitViolation(vl.getId(), vl.getOptionalName().orElse(null), LimitViolationType.HIGH_VOLTAGE,
                    vl.getHighVoltageLimit(), limitReductionValue, value, createViolationLocation(bus)));
        }
    }

    @Override
    public void checkVoltageAngle(VoltageAngleLimit voltageAngleLimit, double value, Consumer<LimitViolation> consumer) {
        if (Double.isNaN(value)) {
            return;
        }
        voltageAngleLimit.getLowLimit().ifPresent(
            lowLimit -> {
                if (value <= lowLimit) {
                    consumer.accept(new LimitViolation(voltageAngleLimit.getId(), LimitViolationType.LOW_VOLTAGE_ANGLE, lowLimit,
                            limitReductionValue, value));
                }
            });
        voltageAngleLimit.getHighLimit().ifPresent(
            highLimit -> {
                if (value >= highLimit) {
                    consumer.accept(new LimitViolation(voltageAngleLimit.getId(), LimitViolationType.HIGH_VOLTAGE_ANGLE, highLimit,
                            limitReductionValue, value));
                }
            });
    }

    public void checkLimitViolation(Branch branch, TwoSides side, double value, Consumer<LimitViolation> consumer, LimitType type) {
        boolean noOverloadOnTemporary = true;
        if (currentLimitTypes.contains(LoadingLimitType.TATL)) {
            noOverloadOnTemporary = checkTemporary(branch, side, limitReductionValue, value, consumer, type);
        }
        if (noOverloadOnTemporary && currentLimitTypes.contains(LoadingLimitType.PATL)) {
            checkPermanentLimit(branch, side, limitReductionValue, value, consumer, type);
        }
    }

    public void checkLimitViolation(ThreeWindingsTransformer transformer, ThreeSides side, double value, Consumer<LimitViolation> consumer, LimitType type) {
        boolean noOverloadOnTemporary = true;
        if (currentLimitTypes.contains(LoadingLimitType.TATL)) {
            noOverloadOnTemporary = checkTemporary(transformer, side, limitReductionValue, value, consumer, type);
        }
        if (noOverloadOnTemporary && currentLimitTypes.contains(LoadingLimitType.PATL)) {
            checkPermanentLimit(transformer, side, limitReductionValue, value, consumer, type);
        }
    }
}