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

com.powsybl.openloadflow.dc.equations.DcEquationSystemCreator 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.dc.equations;

import com.powsybl.iidm.network.TwoSides;
import com.powsybl.openloadflow.equations.EquationSystem;
import com.powsybl.openloadflow.equations.EquationSystemPostProcessor;
import com.powsybl.openloadflow.equations.EquationTerm;
import com.powsybl.openloadflow.network.*;
import com.powsybl.openloadflow.util.EvaluableConstants;

import java.util.Objects;

/**
 * @author Geoffroy Jamgotchian {@literal }
 */
public class DcEquationSystemCreator {

    private final LfNetwork network;

    private final DcEquationSystemCreationParameters creationParameters;

    public DcEquationSystemCreator(LfNetwork network) {
        this(network, new DcEquationSystemCreationParameters());
    }

    public DcEquationSystemCreator(LfNetwork network, DcEquationSystemCreationParameters creationParameters) {
        this.network = Objects.requireNonNull(network);
        this.creationParameters = Objects.requireNonNull(creationParameters);
    }

    private void createBuses(EquationSystem equationSystem) {
        for (LfBus bus : network.getBuses()) {
            var p = equationSystem.createEquation(bus, DcEquationType.BUS_TARGET_P);
            bus.setP(p);
            if (bus.isReference()) {
                equationSystem.createEquation(bus, DcEquationType.BUS_TARGET_PHI)
                        .addTerm(equationSystem.getVariable(bus.getNum(), DcVariableType.BUS_PHI).createTerm());
            }
            // The P balance equation is only disabled for the first slack bus. In cas of multi-slack, target vector will be updated for the other slack buses
            if (bus == network.getSlackBus()) {
                p.setActive(false);
            }
        }
    }

    public static void createNonImpedantBranch(EquationSystem equationSystem,
                                               LfBranch branch, LfBus bus1, LfBus bus2, boolean spanningTree) {
        if (bus1 != null && bus2 != null) {
            boolean hasPhi1 = equationSystem.hasEquation(bus1.getNum(), DcEquationType.BUS_TARGET_PHI);
            boolean hasPhi2 = equationSystem.hasEquation(bus2.getNum(), DcEquationType.BUS_TARGET_PHI);
            if (!(hasPhi1 && hasPhi2)) {
                // create voltage angle coupling equation
                // alpha = phi1 - phi2
                equationSystem.createEquation(branch, DcEquationType.ZERO_PHI)
                        .addTerm(equationSystem.getVariable(bus1.getNum(), DcVariableType.BUS_PHI).createTerm())
                        .addTerm(equationSystem.getVariable(bus2.getNum(), DcVariableType.BUS_PHI).createTerm()
                                .minus())
                        .setActive(!branch.isDisabled() && spanningTree);

                // add a dummy active power variable to both sides of the non impedant branch and with an opposite sign
                // to ensure we have the same number of equation and variables
                var dummyP = equationSystem.getVariable(branch.getNum(), DcVariableType.DUMMY_P);
                equationSystem.getEquation(bus1.getNum(), DcEquationType.BUS_TARGET_P)
                        .orElseThrow()
                        .addTerm(dummyP.createTerm());

                equationSystem.getEquation(bus2.getNum(), DcEquationType.BUS_TARGET_P)
                        .orElseThrow()
                        .addTerm(dummyP.createTerm().minus());

                // create an inactive dummy active power target equation set to zero that could be activated
                // on case of switch opening
                equationSystem.createEquation(branch, DcEquationType.DUMMY_TARGET_P)
                        .addTerm(dummyP.createTerm())
                        .setActive(branch.isDisabled() || !spanningTree); // inverted logic
            } else {
                throw new IllegalStateException("Cannot happen because there is only one reference bus per model");
            }
        }
    }

    private static void createImpedantBranch(EquationSystem equationSystem,
                                             DcEquationSystemCreationParameters creationParameters, LfBranch branch,
                                             LfBus bus1, LfBus bus2) {
        if (bus1 != null && bus2 != null) {
            boolean deriveA1 = isDeriveA1(branch, creationParameters);
            ClosedBranchSide1DcFlowEquationTerm p1 = ClosedBranchSide1DcFlowEquationTerm.create(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, creationParameters.isUseTransformerRatio(), creationParameters.getDcApproximationType());
            ClosedBranchSide2DcFlowEquationTerm p2 = ClosedBranchSide2DcFlowEquationTerm.create(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, creationParameters.isUseTransformerRatio(), creationParameters.getDcApproximationType());
            equationSystem.getEquation(bus1.getNum(), DcEquationType.BUS_TARGET_P)
                    .orElseThrow()
                    .addTerm(p1);
            equationSystem.getEquation(bus2.getNum(), DcEquationType.BUS_TARGET_P)
                    .orElseThrow()
                    .addTerm(p2);
            if (deriveA1) {
                EquationTerm a1 = equationSystem.getVariable(branch.getNum(), DcVariableType.BRANCH_ALPHA1)
                        .createTerm();
                branch.setA1(a1);
                equationSystem.createEquation(branch, DcEquationType.BRANCH_TARGET_ALPHA1)
                        .addTerm(a1);
            }
            if (creationParameters.isUpdateFlows()) {
                branch.setP1(p1);
                branch.setClosedP1(p1);
                branch.setP2(p2);
                branch.setClosedP2(p2);
                ClosedBranchDcCurrent i1 = new ClosedBranchDcCurrent(branch, TwoSides.ONE, creationParameters.getDcPowerFactor());
                ClosedBranchDcCurrent i2 = new ClosedBranchDcCurrent(branch, TwoSides.TWO, creationParameters.getDcPowerFactor());
                branch.setI1(i1);
                branch.setI2(i2);
            }
        } else if (bus1 != null && creationParameters.isUpdateFlows()) {
            branch.setP1(EvaluableConstants.ZERO);
        } else if (bus2 != null && creationParameters.isUpdateFlows()) {
            branch.setP2(EvaluableConstants.ZERO);
        }
    }

    protected static boolean isDeriveA1(LfBranch branch, DcEquationSystemCreationParameters creationParameters) {
        return branch.isPhaseController()
                || creationParameters.isForcePhaseControlOffAndAddAngle1Var() && branch.hasPhaseControllerCapability() && branch.isConnectedAtBothSides();
    }

    private void createBranches(EquationSystem equationSystem) {
        for (LfBranch branch : network.getBranches()) {
            LfBus bus1 = branch.getBus1();
            LfBus bus2 = branch.getBus2();
            if (branch.isZeroImpedance(LoadFlowModel.DC)) {
                createNonImpedantBranch(equationSystem, branch, bus1, bus2, branch.isSpanningTreeEdge(LoadFlowModel.DC));
            } else {
                createImpedantBranch(equationSystem, creationParameters, branch, bus1, bus2);
            }
        }
    }

    private void createHvdcs(EquationSystem equationSystem) {
        for (LfHvdc hvdc : network.getHvdcs()) {
            EquationTerm p1 = null;
            EquationTerm p2 = null;
            if (hvdc.getBus1() != null && hvdc.getBus2() != null && hvdc.isAcEmulation()) {
                p1 = new HvdcAcEmulationSide1DCFlowEquationTerm(hvdc, hvdc.getBus1(), hvdc.getBus2(), equationSystem.getVariableSet());
                p2 = new HvdcAcEmulationSide2DCFlowEquationTerm(hvdc, hvdc.getBus1(), hvdc.getBus2(), equationSystem.getVariableSet());
            }

            if (p1 != null) {
                equationSystem.getEquation(hvdc.getBus1().getNum(), DcEquationType.BUS_TARGET_P)
                        .orElseThrow()
                        .addTerm(p1);
                hvdc.setP1(p1);
            }

            if (p2 != null) {
                equationSystem.getEquation(hvdc.getBus2().getNum(), DcEquationType.BUS_TARGET_P)
                        .orElseThrow()
                        .addTerm(p2);
                hvdc.setP2(p2);
            }
        }
    }

    public EquationSystem create(boolean withListener) {
        EquationSystem equationSystem = new EquationSystem<>();

        createBuses(equationSystem);
        createBranches(equationSystem);
        createHvdcs(equationSystem);

        EquationSystemPostProcessor.findAll().forEach(pp -> pp.onCreate(equationSystem));

        if (withListener) {
            network.addListener(LfNetworkListenerTracer.trace(new DcEquationSystemUpdater(equationSystem)));
        }

        return equationSystem;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy