LfShunt.java

/**
 * Copyright (c) 2019, 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.openloadflow.network;

import com.powsybl.openloadflow.util.Evaluable;
import org.apache.commons.lang3.Range;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
 */
public interface LfShunt extends LfElement {

    Logger LOGGER = LoggerFactory.getLogger(LfShunt.class);

    class Controller {

        private final String id;

        private final List<Double> sectionsB;

        private final List<Double> sectionsG;

        private int position;

        private final double bMagnitude;

        public Controller(String id, List<Double> sectionsB, List<Double> sectionsG, int position) {
            this.id = Objects.requireNonNull(id);
            this.sectionsB = Objects.requireNonNull(sectionsB);
            this.sectionsG = Objects.requireNonNull(sectionsG);
            this.position = position;
            double bMin = Math.min(sectionsB.get(0), sectionsB.get(sectionsB.size() - 1));
            double bMax = Math.max(sectionsB.get(0), sectionsB.get(sectionsB.size() - 1));
            this.bMagnitude = Math.abs(bMax - bMin);
        }

        public String getId() {
            return id;
        }

        public List<Double> getSectionsB() {
            return sectionsB;
        }

        public int getPosition() {
            return position;
        }

        public void setPosition(int position) {
            this.position = position;
        }

        public double getB() {
            return sectionsB.get(this.position);
        }

        public double getG() {
            return sectionsG.get(this.position);
        }

        public double getBMagnitude() {
            return bMagnitude;
        }

        private Range<Integer> getAllowedPositionRange(AllowedDirection allowedDirection) {
            return switch (allowedDirection) {
                case INCREASE -> Range.of(position, sectionsB.size() - 1);
                case DECREASE -> Range.of(0, position);
                case BOTH -> Range.of(0, sectionsB.size() - 1);
            };
        }

        public Optional<Direction> updateSectionB(double deltaB, int maxSectionShift, AllowedDirection allowedDirection) {
            // an increase allowed direction means that the section could increase.
            // a decrease allowed direction means that the section could decrease.
            double newB = getB() + deltaB;
            Range<Integer> positionRange = getAllowedPositionRange(allowedDirection);

            int oldSection = position;
            // find section with the closest b value without exceeding the maximum of sections to switch.
            double smallestDistance = Math.abs(deltaB);
            for (int p = positionRange.getMinimum(); p <= positionRange.getMaximum(); p++) {
                if (Math.abs(p - oldSection) > maxSectionShift) {
                    // we are not allowed in one outer loop run to go further than maxSectionShift sections
                    continue;
                }
                double distance = Math.abs(newB - sectionsB.get(p));
                if (distance < smallestDistance) {
                    position = p;
                    smallestDistance = distance;
                }
            }

            boolean hasChanged = position != oldSection;
            if (hasChanged) {
                LOGGER.debug("Controller '{}' change section from {} to {}", id, oldSection, position);
                return Optional.of(position - oldSection > 0 ? Direction.INCREASE : Direction.DECREASE);
            }
            return Optional.empty();
        }

        public void updateSectionB(int newPosition) {
            position = newPosition;
        }
    }

    double getB();

    default double getBMagnitude() {
        return Math.abs(getB());
    }

    void setB(double b);

    double dispatchB();

    double getG();

    void setG(double g);

    void updateState(LfNetworkStateUpdateParameters parameters);

    boolean hasVoltageControlCapability();

    void setVoltageControlCapability(boolean voltageControlCapability);

    boolean isVoltageControlEnabled();

    void setVoltageControlEnabled(boolean voltageControlEnabled);

    Optional<ShuntVoltageControl> getVoltageControl();

    void setVoltageControl(ShuntVoltageControl voltageControl);

    void reInit();

    List<Controller> getControllers();

    Evaluable getP();

    void setP(Evaluable evaluable);

    Evaluable getQ();

    void setQ(Evaluable evaluable);
}