AcEquationSystemUpdater.java

/**
 * Copyright (c) 2021, 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.ac.equations;

import com.powsybl.iidm.network.TwoSides;
import com.powsybl.openloadflow.equations.EquationSystem;
import com.powsybl.openloadflow.lf.AbstractEquationSystemUpdater;
import com.powsybl.openloadflow.network.*;
import com.powsybl.openloadflow.util.EvaluableConstants;

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

/**
 * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
 */
public class AcEquationSystemUpdater extends AbstractEquationSystemUpdater<AcVariableType, AcEquationType> {

    private final AcEquationSystemCreationParameters parameters;

    public AcEquationSystemUpdater(EquationSystem<AcVariableType, AcEquationType> equationSystem,
                                   AcEquationSystemCreationParameters parameters) {
        super(equationSystem, LoadFlowModel.AC);
        this.parameters = Objects.requireNonNull(parameters);
    }

    private void updateVoltageControls(LfBus bus) {
        LfZeroImpedanceNetwork zn = bus.getZeroImpedanceNetwork(loadFlowModel);
        if (zn == null) {
            bus.getGeneratorVoltageControl().ifPresent(voltageControl -> AcEquationSystemCreator.updateGeneratorVoltageControl(voltageControl.getMainVoltageControl(), equationSystem));
            bus.getTransformerVoltageControl().ifPresent(voltageControl -> AcEquationSystemCreator.updateTransformerVoltageControlEquations(voltageControl.getMainVoltageControl(), equationSystem));
            bus.getShuntVoltageControl().ifPresent(voltageControl -> AcEquationSystemCreator.updateShuntVoltageControlEquations(voltageControl.getMainVoltageControl(), equationSystem));
        } else {
            for (LfBus zb : zn.getGraph().vertexSet()) {
                zb.getGeneratorVoltageControl().ifPresent(voltageControl -> AcEquationSystemCreator.updateGeneratorVoltageControl(voltageControl.getMainVoltageControl(), equationSystem));
                zb.getTransformerVoltageControl().ifPresent(voltageControl -> AcEquationSystemCreator.updateTransformerVoltageControlEquations(voltageControl.getMainVoltageControl(), equationSystem));
                zb.getShuntVoltageControl().ifPresent(voltageControl -> AcEquationSystemCreator.updateShuntVoltageControlEquations(voltageControl.getMainVoltageControl(), equationSystem));
            }
        }
    }

    @Override
    public void onGeneratorVoltageControlChange(LfBus controllerBus, boolean newVoltageControllerEnabled) {
        updateVoltageControls(controllerBus.getGeneratorVoltageControl().orElseThrow().getControlledBus());
    }

    @Override
    public void onTransformerPhaseControlChange(LfBranch controllerBranch, boolean newPhaseControlEnabled) {
        AcEquationSystemCreator.updateTransformerPhaseControlEquations(controllerBranch.getPhaseControl().orElseThrow(), equationSystem);
    }

    @Override
    public void onGeneratorReactivePowerControlChange(LfBus controllerBus, boolean newReactiveControllerEnabled) {
        controllerBus.getGeneratorReactivePowerControl().ifPresent(generatorReactivePowerControl -> AcEquationSystemCreator.updateGeneratorReactivePowerControlBranchEquations(generatorReactivePowerControl, equationSystem));
    }

    @Override
    public void onTransformerVoltageControlChange(LfBranch controllerBranch, boolean newVoltageControllerEnabled) {
        updateVoltageControls(controllerBranch.getVoltageControl().orElseThrow().getControlledBus());
    }

    @Override
    public void onShuntVoltageControlChange(LfShunt controllerShunt, boolean newVoltageControllerEnabled) {
        updateVoltageControls(controllerShunt.getVoltageControl().orElseThrow().getControlledBus());
    }

    @Override
    protected void updateNonImpedantBranchEquations(LfBranch branch, boolean enable) {
        // depending on the switch status, we activate either v1 = v2, ph1 = ph2 equations
        // or equations that set dummy p and q variable to zero
        equationSystem.getEquation(branch.getNum(), AcEquationType.ZERO_PHI)
                .orElseThrow()
                .setActive(enable);
        equationSystem.getEquation(branch.getNum(), AcEquationType.DUMMY_TARGET_P)
                .orElseThrow()
                .setActive(!enable);

        equationSystem.getEquation(branch.getNum(), AcEquationType.ZERO_V)
                .orElseThrow()
                .setActive(enable);
        equationSystem.getEquation(branch.getNum(), AcEquationType.DUMMY_TARGET_Q)
                .orElseThrow()
                .setActive(!enable);
    }

    @Override
    public void onDisableChange(LfElement element, boolean disabled) {
        updateElementEquations(element, !disabled);
        switch (element.getType()) {
            case BUS:
                LfBus bus = (LfBus) element;
                checkSlackBus(bus, disabled);
                equationSystem.getEquation(bus.getNum(), AcEquationType.BUS_TARGET_PHI)
                        .ifPresent(eq -> eq.setActive(!bus.isDisabled() && bus.isReference()));
                equationSystem.getEquation(bus.getNum(), AcEquationType.BUS_TARGET_P)
                        .ifPresent(eq -> eq.setActive(!bus.isDisabled() && !bus.isSlack()));
                // set voltage target equation inactive, various voltage control will set next to the correct value
                equationSystem.getEquation(bus.getNum(), AcEquationType.BUS_TARGET_V)
                        .orElseThrow()
                        .setActive(false);
                bus.getGeneratorVoltageControl().ifPresent(vc -> updateVoltageControls(vc.getControlledBus()));
                bus.getTransformerVoltageControl().ifPresent(vc -> updateVoltageControls(vc.getControlledBus()));
                bus.getShuntVoltageControl().ifPresent(vc -> updateVoltageControls(vc.getControlledBus()));
                bus.getGeneratorReactivePowerControl().ifPresent(reactivePowerControl -> AcEquationSystemCreator.updateGeneratorReactivePowerControlBranchEquations(reactivePowerControl, equationSystem));
                break;
            case BRANCH:
                LfBranch branch = (LfBranch) element;
                AcEquationSystemCreator.updateBranchEquations(branch);
                branch.getVoltageControl().ifPresent(vc -> updateVoltageControls(vc.getControlledBus()));
                branch.getPhaseControl().ifPresent(phaseControl -> AcEquationSystemCreator.updateTransformerPhaseControlEquations(phaseControl, equationSystem));
                branch.getGeneratorReactivePowerControl().ifPresent(reactivePowerControl -> AcEquationSystemCreator.updateGeneratorReactivePowerControlBranchEquations(reactivePowerControl, equationSystem));
                break;
            case SHUNT_COMPENSATOR:
                LfShunt shunt = (LfShunt) element;
                shunt.getVoltageControl().ifPresent(vc -> updateVoltageControls(vc.getControlledBus()));
                break;
            case HVDC:
                // nothing to do
                break;
            default:
                throw new IllegalStateException("Unknown element type: " + element.getType());
        }
    }

    private void recreateDistributionEquations(LfZeroImpedanceNetwork network) {
        for (LfBus bus : network.getGraph().vertexSet()) {
            bus.getGeneratorVoltageControl()
                    .filter(voltageControl -> voltageControl.getMergeStatus() == VoltageControl.MergeStatus.MAIN)
                    .ifPresent(voltageControl -> AcEquationSystemCreator.recreateReactivePowerDistributionEquations(bus.getNetwork(), voltageControl, equationSystem, parameters));
            bus.getTransformerVoltageControl()
                    .filter(voltageControl -> voltageControl.getMergeStatus() == VoltageControl.MergeStatus.MAIN)
                    .ifPresent(voltageControl -> AcEquationSystemCreator.recreateR1DistributionEquations(bus.getNetwork(), voltageControl, equationSystem));
            bus.getShuntVoltageControl()
                    .filter(voltageControl -> voltageControl.getMergeStatus() == VoltageControl.MergeStatus.MAIN)
                    .ifPresent(voltageControl -> AcEquationSystemCreator.recreateShuntSusceptanceDistributionEquations(bus.getNetwork(), voltageControl, equationSystem));
        }
    }

    @Override
    public void onZeroImpedanceNetworkSplit(LfZeroImpedanceNetwork initialNetwork, List<LfZeroImpedanceNetwork> splitNetworks, LoadFlowModel loadFlowModel) {
        if (loadFlowModel == LoadFlowModel.AC) {
            // TODO
            // only recreate distribution equations if controllers buses are redistributed on the different
            // split networks (should be a rare case) and not only ate the end on only one of the split network
            for (LfZeroImpedanceNetwork splitNetwork : splitNetworks) {
                recreateDistributionEquations(splitNetwork);
            }
        }
    }

    @Override
    public void onZeroImpedanceNetworkMerge(LfZeroImpedanceNetwork network1, LfZeroImpedanceNetwork network2, LfZeroImpedanceNetwork mergedNetwork, LoadFlowModel loadFlowModel) {
        if (loadFlowModel == LoadFlowModel.AC) {
            // TODO
            // only recreate distribution equations if controllers buses are merged (should be a rare case)
            // so we have to check here that controllers were spread over network1 and network2 and were not
            // already only on network1 or network2
            recreateDistributionEquations(mergedNetwork);
        }
    }

    @Override
    public void onBranchConnectionStatusChange(LfBranch branch, TwoSides side, boolean connected) {
        AcEquationSystemCreator.updateBranchEquations(branch);
        if (branch.isConnectedSide1() && branch.isConnectedSide2()) {
            branch.setP1(branch.getClosedP1());
            branch.setQ1(branch.getClosedQ1());
            branch.setI1(branch.getClosedI1());
            branch.setP2(branch.getClosedP2());
            branch.setQ2(branch.getClosedQ2());
            branch.setI2(branch.getClosedI2());
        } else if (!branch.isConnectedSide1() && branch.isConnectedSide2()) {
            branch.setP1(EvaluableConstants.ZERO);
            branch.setQ1(EvaluableConstants.ZERO);
            branch.setI1(EvaluableConstants.ZERO);
            branch.setP2(branch.getOpenP2());
            branch.setQ2(branch.getOpenQ2());
            branch.setI2(branch.getOpenI2());
        } else if (branch.isConnectedSide1() && !branch.isConnectedSide2()) {
            branch.setP1(branch.getOpenP1());
            branch.setQ1(branch.getOpenQ1());
            branch.setI1(branch.getOpenI1());
            branch.setP2(EvaluableConstants.ZERO);
            branch.setQ2(EvaluableConstants.ZERO);
            branch.setI2(EvaluableConstants.ZERO);
        } else {
            branch.setP1(EvaluableConstants.NAN);
            branch.setQ1(EvaluableConstants.NAN);
            branch.setI1(EvaluableConstants.NAN);
            branch.setP2(EvaluableConstants.NAN);
            branch.setQ2(EvaluableConstants.NAN);
            branch.setI2(EvaluableConstants.NAN);
        }
    }

    @Override
    protected AcEquationType getTypeBusTargetP() {
        return AcEquationType.BUS_TARGET_P;
    }

    @Override
    protected AcEquationType getTypeBusTargetPhi() {
        return AcEquationType.BUS_TARGET_PHI;
    }

    @Override
    protected AcVariableType getTypeBusPhi() {
        return AcVariableType.BUS_PHI;
    }
}