All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.powsybl.openloadflow.network.impl.LfShuntImpl Maven / Gradle / Ivy

The newest version!
/**
 * 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.impl;

import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.ShuntCompensator;
import com.powsybl.iidm.network.ShuntCompensatorLinearModel;
import com.powsybl.iidm.network.ShuntCompensatorModel;
import com.powsybl.iidm.network.ShuntCompensatorNonLinearModel;
import com.powsybl.openloadflow.network.*;
import com.powsybl.openloadflow.util.PerUnit;

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

/**
 * @author Geoffroy Jamgotchian {@literal }
 * @author Anne Tilloy {@literal }
 */
public class LfShuntImpl extends AbstractLfShunt {

    private final class ControllerImpl extends Controller {

        private final Ref shuntCompensatorRef;

        private ControllerImpl(Ref shuntCompensatorRef, List sectionsB, List sectionsG, int position) {
            super(shuntCompensatorRef.get().getId(), sectionsB, sectionsG, position);
            this.shuntCompensatorRef = shuntCompensatorRef;
        }

        private Ref getShuntCompensatorRef() {
            return shuntCompensatorRef;
        }

        @Override
        public Optional updateSectionB(double deltaB, int maxSectionShift, AllowedDirection allowedDirection) {
            Optional direction = super.updateSectionB(deltaB, maxSectionShift, allowedDirection);
            if (direction.isPresent()) { // it means position has changed
                setG(controllers.stream().mapToDouble(Controller::getG).sum());
                setB(controllers.stream().mapToDouble(Controller::getB).sum());
            }
            return direction;
        }

        @Override
        public void updateSectionB(int newPosition) {
            super.updateSectionB(newPosition);
            setG(controllers.stream().mapToDouble(Controller::getG).sum());
            setB(controllers.stream().mapToDouble(Controller::getB).sum());
        }
    }

    private final List> shuntCompensatorsRefs;

    private final LfBus bus;

    private ShuntVoltageControl voltageControl;

    private boolean voltageControlCapability;

    private boolean voltageControlEnabled = false;

    private final List controllers = new ArrayList<>();

    private double b;

    private final double zb;

    private double g;

    public LfShuntImpl(List shuntCompensators, LfNetwork network, LfBus bus, boolean voltageControlCapability,
                       LfNetworkParameters parameters, LfTopoConfig topoConfig) {
        // if withVoltageControl equals to true, all shunt compensators that are listed must control voltage.
        // if withVoltageControl equals to false, all shunt compensators that are listed will be treated as fixed shunt
        // compensators.
        super(network);
        shuntCompensatorsRefs = Objects.requireNonNull(shuntCompensators).stream()
                .map(sc -> Ref.create(sc, parameters.isCacheEnabled()))
                .collect(Collectors.toList());
        if (shuntCompensators.isEmpty()) {
            throw new IllegalArgumentException("Empty shunt compensator list");
        }
        this.bus = Objects.requireNonNull(bus);
        this.voltageControlCapability = voltageControlCapability;
        double nominalV = shuntCompensators.get(0).getTerminal().getVoltageLevel().getNominalV(); // has to be the same for all shunts
        zb = PerUnit.zb(nominalV);
        b = computeB(shuntCompensators, zb);
        g = computeG(shuntCompensators, zb);

        boolean keepSections = shuntCompensators.stream().map(ShuntCompensator::getId).anyMatch(id -> topoConfig.isOperatedShunt(id));

        if (voltageControlCapability || keepSections) {
            shuntCompensatorsRefs.forEach(shuntCompensatorRef -> {
                var shuntCompensator = shuntCompensatorRef.get();
                List sectionsB = new ArrayList<>(1);
                List sectionsG = new ArrayList<>(1);
                sectionsB.add(0.0);
                sectionsG.add(0.0);
                ShuntCompensatorModel model = shuntCompensator.getModel();
                switch (shuntCompensator.getModelType()) {
                    case LINEAR:
                        ShuntCompensatorLinearModel linearModel = (ShuntCompensatorLinearModel) model;
                        for (int section = 1; section <= shuntCompensator.getMaximumSectionCount(); section++) {
                            sectionsB.add(linearModel.getBPerSection() * section * zb);
                            sectionsG.add(linearModel.getGPerSection() * section * zb);
                        }
                        break;
                    case NON_LINEAR:
                        ShuntCompensatorNonLinearModel nonLinearModel = (ShuntCompensatorNonLinearModel) model;
                        for (int section = 0; section < shuntCompensator.getMaximumSectionCount(); section++) {
                            sectionsB.add(nonLinearModel.getAllSections().get(section).getB() * zb);
                            sectionsG.add(nonLinearModel.getAllSections().get(section).getG() * zb);
                        }
                        break;
                }
                controllers.add(new ControllerImpl(shuntCompensatorRef, sectionsB, sectionsG, shuntCompensator.getSectionCount()));
            });
            // Controllers are always enabled, a contingency with shunt compensator with voltage control on is not supported yet.
            controllers.sort(Comparator.comparingDouble(Controller::getBMagnitude).reversed());
        }
    }

    private static double computeG(List shuntCompensators, double zb) {
        return zb * shuntCompensators.stream()
                .mapToDouble(ShuntCompensator::getG)
                .sum();
    }

    private static double computeB(List shuntCompensators, double zb) {
        return zb * shuntCompensators.stream()
                .mapToDouble(ShuntCompensator::getB)
                .sum();
    }

    @Override
    public ElementType getType() {
        return ElementType.SHUNT_COMPENSATOR;
    }

    @Override
    public String getId() {
        return controllers.isEmpty() ? bus.getId() + "_shunt_compensators" : bus.getId() + "_controller_shunt_compensators";
    }

    @Override
    public List getOriginalIds() {
        return shuntCompensatorsRefs.stream().map(scRef -> scRef.get().getId()).collect(Collectors.toList());
    }

    @Override
    public double getB() {
        return b;
    }

    @Override
    public void setB(double b) {
        if (b != this.b) {
            this.b = b;
            for (LfNetworkListener listener : getNetwork().getListeners()) {
                listener.onShuntSusceptanceChange(this, b);
            }
        }
    }

    @Override
    public double getG() {
        return g;
    }

    @Override
    public void setG(double g) {
        this.g = g;
    }

    @Override
    public boolean hasVoltageControlCapability() {
        return voltageControlCapability;
    }

    @Override
    public void setVoltageControlCapability(boolean voltageControlCapability) {
        this.voltageControlCapability = voltageControlCapability;
    }

    @Override
    public boolean isVoltageControlEnabled() {
        return voltageControlEnabled;
    }

    @Override
    public void setVoltageControlEnabled(boolean voltageControlEnabled) {
        if (this.voltageControlEnabled != voltageControlEnabled) {
            this.voltageControlEnabled = voltageControlEnabled;
            for (LfNetworkListener listener : network.getListeners()) {
                listener.onShuntVoltageControlChange(this, voltageControlEnabled);
            }
        }
    }

    @Override
    public Optional getVoltageControl() {
        return Optional.ofNullable(voltageControl);
    }

    @Override
    public void setVoltageControl(ShuntVoltageControl voltageControl) {
        this.voltageControl = voltageControl;
    }

    public List getControllers() {
        return controllers;
    }

    private void roundBToClosestSection(double b, Controller controller) {
        List sections = controller.getSectionsB();
        // find tap position with the closest b value
        double smallestDistance = Math.abs(b - sections.get(controller.getPosition()));
        for (int s = 0; s < sections.size(); s++) {
            double distance = Math.abs(b - sections.get(s));
            if (distance < smallestDistance) {
                controller.setPosition(s);
                smallestDistance = distance;
            }
        }
        LOGGER.trace("Round B shift of shunt '{}': {} -> {}", controller.getId(), b * zb, controller.getB() * zb);
    }

    @Override
    public double dispatchB() {
        double residueB = b;
        int remainingControllers = controllers.size();
        for (Controller controller : controllers) {
            double bToDispatchByController = residueB / remainingControllers--;
            roundBToClosestSection(bToDispatchByController, controller);
            residueB -= controller.getB();
        }
        b = controllers.stream().mapToDouble(Controller::getB).sum();
        return residueB;
    }

    @Override
    public void updateState(LfNetworkStateUpdateParameters parameters) {
        if (parameters.isDc()) {
            for (var scRef : shuntCompensatorsRefs) {
                var sc = scRef.get();
                sc.getTerminal().setP(0);
            }
        } else {
            double vSquare = bus.getV() * bus.getV() * bus.getNominalV() * bus.getNominalV();
            if (!voltageControlCapability) {
                for (var scRef : shuntCompensatorsRefs) {
                    var sc = scRef.get();
                    sc.getTerminal().setP(sc.getG() * vSquare);
                    sc.getTerminal().setQ(-sc.getB() * vSquare);
                }
            } else {
                for (Controller controller : controllers) {
                    ShuntCompensator sc = ((ControllerImpl) controller).getShuntCompensatorRef().get();
                    sc.getTerminal().setP(controller.getG() * vSquare / zb);
                    sc.getTerminal().setQ(-controller.getB() * vSquare / zb);
                    sc.setSectionCount(controller.getPosition());
                }
            }
        }
    }

    @Override
    public void reInit() {
        if (voltageControlCapability) {
            throw new PowsyblException("Cannot re-init a shunt compensator with voltage control capabilities");
        }
        List shuntCompensators = shuntCompensatorsRefs.stream().map(Ref::get).collect(Collectors.toList());
        setB(computeB(shuntCompensators, zb));
        setG(computeG(shuntCompensators, zb));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy