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

com.powsybl.openloadflow.ac.equations.asym.AsymmetricalAcEquationSystemCreator Maven / Gradle / Ivy

/**
 * Copyright (c) 2023, Jean-Baptiste Heyberger 
 * Copyright (c) 2023, Geoffroy Jamgotchian 
 * 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.asym;

import com.powsybl.iidm.network.TwoSides;
import com.powsybl.openloadflow.ac.equations.*;
import com.powsybl.openloadflow.equations.EquationSystem;
import com.powsybl.openloadflow.equations.EquationTerm;
import com.powsybl.openloadflow.network.*;
import com.powsybl.openloadflow.util.ComplexPart;
import com.powsybl.openloadflow.util.Fortescue.SequenceType;

/**
 * @author Geoffroy Jamgotchian {@literal }
 * @author Jean-Baptiste Heyberger {@literal }
 */
public class AsymmetricalAcEquationSystemCreator extends AcEquationSystemCreator {

    private static final double EPSILON = 0.00001;

    public AsymmetricalAcEquationSystemCreator(LfNetwork network, AcEquationSystemCreationParameters creationParameters) {
        super(network, creationParameters);
    }

    @Override
    protected void createBusEquation(LfBus bus, EquationSystem equationSystem) {
        super.createBusEquation(bus, equationSystem);

        // addition of asymmetric equations, supposing that existing v, theta, p and q are linked to the positive sequence
        LfAsymBus asymBus = bus.getAsym();

        var ixh = equationSystem.createEquation(bus, AcEquationType.BUS_TARGET_IX_ZERO);
        asymBus.setIxZ(ixh);
        var iyh = equationSystem.createEquation(bus, AcEquationType.BUS_TARGET_IY_ZERO);
        asymBus.setIyZ(iyh);

        var ixi = equationSystem.createEquation(bus, AcEquationType.BUS_TARGET_IX_NEGATIVE);
        asymBus.setIxN(ixi);
        var iyi = equationSystem.createEquation(bus, AcEquationType.BUS_TARGET_IY_NEGATIVE);
        asymBus.setIyN(iyi);

        // handle generators at bus for zero and negative
        for (LfGenerator gen : bus.getGenerators()) {
            // if there is at least one generating unit that is voltage controlling we model the equivalent in negative and zero
            // with a large admittance yg = g +jb to model a close connection of the bus to the ground (E_zero = 0 E_negative = 0)
            if (gen.getGeneratorControlType() == LfGenerator.GeneratorControlType.REMOTE_REACTIVE_POWER
                    || gen.getGeneratorControlType() == LfGenerator.GeneratorControlType.MONITORING_VOLTAGE) {
                throw new IllegalStateException("Generator with control type " + gen.getGeneratorControlType()
                        + " not yet supported in asymmetric load flow: " + gen.getId());
            }

            if (gen.getGeneratorControlType() == LfGenerator.GeneratorControlType.VOLTAGE) {
                LfAsymGenerator asymGen = gen.getAsym();
                if (asymGen != null) {
                    asymBus.setBzEquiv(asymBus.getBzEquiv() + asymGen.getBz());
                    asymBus.setGzEquiv(asymBus.getGzEquiv() + asymGen.getGz());
                    asymBus.setBnEquiv(asymBus.getBnEquiv() + asymGen.getBn());
                    asymBus.setGnEquiv(asymBus.getGnEquiv() + asymGen.getGn());
                }
            }
        }

        if (Math.abs(asymBus.getBzEquiv()) > EPSILON || Math.abs(asymBus.getGzEquiv()) > EPSILON) {
            equationSystem.createEquation(bus, AcEquationType.BUS_TARGET_IX_ZERO)
                    .addTerm(new ShuntFortescueIxEquationTerm(bus, equationSystem.getVariableSet(), SequenceType.ZERO));
            equationSystem.createEquation(bus, AcEquationType.BUS_TARGET_IY_ZERO)
                    .addTerm(new ShuntFortescueIyEquationTerm(bus, equationSystem.getVariableSet(), SequenceType.ZERO));
        }

        if (Math.abs(asymBus.getGnEquiv()) > EPSILON || Math.abs(asymBus.getBnEquiv()) > EPSILON) {
            equationSystem.createEquation(bus, AcEquationType.BUS_TARGET_IX_NEGATIVE)
                    .addTerm(new ShuntFortescueIxEquationTerm(bus, equationSystem.getVariableSet(), SequenceType.NEGATIVE));
            equationSystem.createEquation(bus, AcEquationType.BUS_TARGET_IY_NEGATIVE).
                    addTerm(new ShuntFortescueIyEquationTerm(bus, equationSystem.getVariableSet(), SequenceType.NEGATIVE));
        }

        if (Math.abs(bus.getLoadTargetP()) > EPSILON || Math.abs(bus.getLoadTargetQ()) > EPSILON) {
            // load modelled as a constant power load in abc phase representation leading to a model depending on vd, vi, vo in fortescue representation
            equationSystem.createEquation(bus, AcEquationType.BUS_TARGET_IX_ZERO)
                    .addTerm(new LoadFortescuePowerEquationTerm(bus, equationSystem.getVariableSet(), ComplexPart.REAL, SequenceType.ZERO));
            equationSystem.createEquation(bus, AcEquationType.BUS_TARGET_P)
                    .addTerm(new LoadFortescuePowerEquationTerm(bus, equationSystem.getVariableSet(), ComplexPart.REAL, SequenceType.POSITIVE));
            equationSystem.createEquation(bus, AcEquationType.BUS_TARGET_IX_NEGATIVE)
                    .addTerm(new LoadFortescuePowerEquationTerm(bus, equationSystem.getVariableSet(), ComplexPart.REAL, SequenceType.NEGATIVE));
            equationSystem.createEquation(bus, AcEquationType.BUS_TARGET_IY_ZERO)
                    .addTerm(new LoadFortescuePowerEquationTerm(bus, equationSystem.getVariableSet(), ComplexPart.IMAGINARY, SequenceType.ZERO));
            equationSystem.createEquation(bus, AcEquationType.BUS_TARGET_Q)
                    .addTerm(new LoadFortescuePowerEquationTerm(bus, equationSystem.getVariableSet(), ComplexPart.IMAGINARY, SequenceType.POSITIVE));
            equationSystem.createEquation(bus, AcEquationType.BUS_TARGET_IY_NEGATIVE)
                    .addTerm(new LoadFortescuePowerEquationTerm(bus, equationSystem.getVariableSet(), ComplexPart.IMAGINARY, SequenceType.NEGATIVE));
        }
    }

    @Override
    protected void createImpedantBranch(LfBranch branch, LfBus bus1, LfBus bus2, EquationSystem equationSystem) {
        // positive sequence
        EquationTerm p1 = null;
        EquationTerm q1 = null;
        EquationTerm p2 = null;
        EquationTerm q2 = null;
        EquationTerm i1 = null;
        EquationTerm i2 = null;

        // zero sequence
        EquationTerm ixz1 = null;
        EquationTerm iyz1 = null;
        EquationTerm ixz2 = null;
        EquationTerm iyz2 = null;

        // negative sequence
        EquationTerm ixn1 = null;
        EquationTerm iyn1 = null;
        EquationTerm ixn2 = null;
        EquationTerm iyn2 = null;

        boolean deriveA1 = isDeriveA1(branch, creationParameters);
        boolean deriveR1 = isDeriveR1(branch);

        if (bus1 != null && bus2 != null) {
            if (!branch.isAsymmetric()) {
                // no asymmetry is detected with this line, we handle the equations as decoupled
                // positive
                p1 = new ClosedBranchSide1ActiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.POSITIVE);
                q1 = new ClosedBranchSide1ReactiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.POSITIVE);
                p2 = new ClosedBranchSide2ActiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.POSITIVE);
                q2 = new ClosedBranchSide2ReactiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.POSITIVE);
                i1 = new ClosedBranchSide1CurrentMagnitudeEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1);
                i2 = new ClosedBranchSide2CurrentMagnitudeEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1);

                // zero
                ixz1 = new ClosedBranchI1xFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.ZERO);
                iyz1 = new ClosedBranchI1yFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.ZERO);
                ixz2 = new ClosedBranchI2xFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.ZERO);
                iyz2 = new ClosedBranchI2yFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.ZERO);

                // negative
                ixn1 = new ClosedBranchI1xFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.NEGATIVE);
                iyn1 = new ClosedBranchI1yFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.NEGATIVE);
                ixn2 = new ClosedBranchI2xFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.NEGATIVE);
                iyn2 = new ClosedBranchI2yFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.NEGATIVE);
            } else {
                // assymmetry is detected with this line, we handle the equations as coupled between the different sequences
                // positive
                p1 = new AsymmetricalClosedBranchCoupledPowerEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), ComplexPart.REAL, TwoSides.ONE, SequenceType.POSITIVE);
                q1 = new AsymmetricalClosedBranchCoupledPowerEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), ComplexPart.IMAGINARY, TwoSides.ONE, SequenceType.POSITIVE);
                p2 = new AsymmetricalClosedBranchCoupledPowerEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), ComplexPart.REAL, TwoSides.TWO, SequenceType.POSITIVE);
                q2 = new AsymmetricalClosedBranchCoupledPowerEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), ComplexPart.IMAGINARY, TwoSides.TWO, SequenceType.POSITIVE);

                // zero
                ixz1 = new AsymmetricalClosedBranchCoupledCurrentEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), ComplexPart.REAL, TwoSides.ONE, SequenceType.ZERO);
                iyz1 = new AsymmetricalClosedBranchCoupledCurrentEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), ComplexPart.IMAGINARY, TwoSides.ONE, SequenceType.ZERO);
                ixz2 = new AsymmetricalClosedBranchCoupledCurrentEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), ComplexPart.REAL, TwoSides.TWO, SequenceType.ZERO);
                iyz2 = new AsymmetricalClosedBranchCoupledCurrentEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), ComplexPart.IMAGINARY, TwoSides.TWO, SequenceType.ZERO);

                // negative
                ixn1 = new AsymmetricalClosedBranchCoupledCurrentEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), ComplexPart.REAL, TwoSides.ONE, SequenceType.NEGATIVE);
                iyn1 = new AsymmetricalClosedBranchCoupledCurrentEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), ComplexPart.IMAGINARY, TwoSides.ONE, SequenceType.NEGATIVE);
                ixn2 = new AsymmetricalClosedBranchCoupledCurrentEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), ComplexPart.REAL, TwoSides.TWO, SequenceType.NEGATIVE);
                iyn2 = new AsymmetricalClosedBranchCoupledCurrentEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), ComplexPart.IMAGINARY, TwoSides.TWO, SequenceType.NEGATIVE);
            }
        } else if (bus1 != null) {
            throw new IllegalStateException("Line open at one side not yet supported in asymmetric load flow at bus: " + bus1.getId());
        } else if (bus2 != null) {
            throw new IllegalStateException("Line open at one side not yet supported in asymmetric load flow  at bus: " + bus2.getId());
        }

        // positive
        createImpedantBranchEquations(branch, bus1, bus2, equationSystem, p1, q1, i1, p2, q2, i2, p1, q1, i1, p2, q2, i2, null, null, null, null, null, null);

        // zero
        if (ixz1 != null) {
            equationSystem.getEquation(bus1.getNum(), AcEquationType.BUS_TARGET_IX_ZERO)
                    .orElseThrow()
                    .addTerm(ixz1);
        }
        if (iyz1 != null) {
            equationSystem.getEquation(bus1.getNum(), AcEquationType.BUS_TARGET_IY_ZERO)
                    .orElseThrow()
                    .addTerm(iyz1);
        }
        if (ixz2 != null) {
            equationSystem.getEquation(bus2.getNum(), AcEquationType.BUS_TARGET_IX_ZERO)
                    .orElseThrow()
                    .addTerm(ixz2);
        }
        if (iyz2 != null) {
            equationSystem.getEquation(bus2.getNum(), AcEquationType.BUS_TARGET_IY_ZERO)
                    .orElseThrow()
                    .addTerm(iyz2);
        }

        // negative
        if (ixn1 != null) {
            equationSystem.getEquation(bus1.getNum(), AcEquationType.BUS_TARGET_IX_NEGATIVE)
                    .orElseThrow()
                    .addTerm(ixn1);
        }
        if (iyn1 != null) {
            equationSystem.getEquation(bus1.getNum(), AcEquationType.BUS_TARGET_IY_NEGATIVE)
                    .orElseThrow()
                    .addTerm(iyn1);
        }
        if (ixn2 != null) {
            equationSystem.getEquation(bus2.getNum(), AcEquationType.BUS_TARGET_IX_NEGATIVE)
                    .orElseThrow()
                    .addTerm(ixn2);
        }
        if (iyn2 != null) {
            equationSystem.getEquation(bus2.getNum(), AcEquationType.BUS_TARGET_IY_NEGATIVE)
                    .orElseThrow()
                    .addTerm(iyn2);
        }

        createGeneratorReactivePowerControlBranchEquation(branch, bus1, bus2, equationSystem, deriveA1, deriveR1);

        createTransformerPhaseControlEquations(branch, bus1, bus2, equationSystem, deriveA1, deriveR1);

        createTransformerReactivePowerControlEquations(branch, equationSystem);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy