LinkData.java

/**
 * Copyright (c) 2020, 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.iidm.network.util;

import com.powsybl.iidm.network.TwoSides;
import org.apache.commons.math3.complex.Complex;
import org.apache.commons.math3.complex.ComplexUtils;

/**
 * @author Jos�� Antonio Marqu��s {@literal <marquesja at aia.es>}
 * @author Marcos de Miguel {@literal <demiguelm at aia.es>}
 */

public final class LinkData {

    private LinkData() {
    }

    static double getFixedX(double x, double epsilonX, boolean applyReactanceCorrection) {
        return Math.abs(x) < epsilonX && applyReactanceCorrection ? epsilonX : x;
    }

    public static BranchAdmittanceMatrix calculateBranchAdmittance(double r, double x, double ratio1, double angle1,
        double ratio2, double angle2, Complex ysh1, Complex ysh2) {

        Complex a1 = ComplexUtils.polar2Complex(ratio1, angle1);
        Complex a2 = ComplexUtils.polar2Complex(ratio2, angle2);

        Complex ytr;
        if (r == 0.0 && x == 0.0) {
            ytr = Complex.ZERO;
        } else {
            ytr = new Complex(r, x).reciprocal();
        }

        BranchAdmittanceMatrix branchAdmittance = new BranchAdmittanceMatrix();

        branchAdmittance.y11 = ytr.add(ysh1).divide(a1.conjugate().multiply(a1));
        branchAdmittance.y12 = ytr.negate().divide(a1.conjugate().multiply(a2));
        branchAdmittance.y21 = ytr.negate().divide(a2.conjugate().multiply(a1));
        branchAdmittance.y22 = ytr.add(ysh2).divide(a2.conjugate().multiply(a2));

        return branchAdmittance;
    }

    public static BranchAdmittanceMatrix kronChain(BranchAdmittanceMatrix firstAdm, TwoSides firstChainNodeSide,
        BranchAdmittanceMatrix secondAdm, TwoSides secondChainNodeSide) {
        BranchAdmittanceMatrix admittance = new BranchAdmittanceMatrix();

        Complex yFirst11;
        Complex yFirst1C;
        Complex yFirstC1;
        Complex yFirstCC;
        if (firstChainNodeSide == TwoSides.TWO) {
            yFirst11 = firstAdm.y11();
            yFirst1C = firstAdm.y12();
            yFirstC1 = firstAdm.y21();
            yFirstCC = firstAdm.y22();
        } else {
            yFirst11 = firstAdm.y22();
            yFirst1C = firstAdm.y21();
            yFirstC1 = firstAdm.y12();
            yFirstCC = firstAdm.y11();
        }

        Complex ySecond22;
        Complex ySecond2C;
        Complex ySecondC2;
        Complex ySecondCC;
        if (secondChainNodeSide == TwoSides.TWO) {
            ySecond22 = secondAdm.y11();
            ySecond2C = secondAdm.y12();
            ySecondC2 = secondAdm.y21();
            ySecondCC = secondAdm.y22();
        } else {
            ySecond22 = secondAdm.y22();
            ySecond2C = secondAdm.y21();
            ySecondC2 = secondAdm.y12();
            ySecondCC = secondAdm.y11();
        }

        admittance.y11 = yFirst11.subtract(yFirst1C.multiply(yFirstC1).divide(yFirstCC.add(ySecondCC)));
        admittance.y12 = yFirst1C.multiply(ySecondC2).divide(yFirstCC.add(ySecondCC)).negate();
        admittance.y21 = ySecond2C.multiply(yFirstC1).divide(yFirstCC.add(ySecondCC)).negate();
        admittance.y22 = ySecond22.subtract(ySecond2C.multiply(ySecondC2).divide(yFirstCC.add(ySecondCC)));

        return admittance;
    }

    static Complex kronAntenna(Complex y11, Complex y12, Complex y21, Complex y22, boolean isOpenFrom) {
        Complex ysh = Complex.ZERO;

        if (isOpenFrom) {
            if (!y11.equals(Complex.ZERO)) {
                ysh = y22.subtract(y21.multiply(y12).divide(y11));
            }
        } else {
            if (!y22.equals(Complex.ZERO)) {
                ysh = y11.subtract(y12.multiply(y21).divide(y22));
            }
        }
        return ysh;
    }

    static Complex flowYshunt(Complex ysh, double u, double theta) {

        Complex v = ComplexUtils.polar2Complex(u, theta);

        return ysh.conjugate().multiply(v.conjugate().multiply(v));
    }

    static Flow flowBothEnds(Complex y11, Complex y12, Complex y21, Complex y22,
        double u1, double theta1, double u2, double theta2) {

        Complex v1 = ComplexUtils.polar2Complex(u1, theta1);
        Complex v2 = ComplexUtils.polar2Complex(u2, theta2);

        return flowBothEnds(y11, y12, y21, y22, v1, v2);
    }

    static Flow flowBothEnds(Complex y11, Complex y12, Complex y21, Complex y22,
        Complex v1, Complex v2) {

        Flow flow = new Flow();
        Complex ift = y12.multiply(v2).add(y11.multiply(v1));
        flow.fromTo = ift.conjugate().multiply(v1);

        Complex itf = y21.multiply(v1).add(y22.multiply(v2));
        flow.toFrom = itf.conjugate().multiply(v2);

        return flow;
    }

    static double getPhaseAngleClockDegrees(int phaseAngleClock) {
        double phaseAngleClockDegree = Math.IEEEremainder(phaseAngleClock * 30.0, 360.0);
        if (phaseAngleClockDegree > 180.0) {
            phaseAngleClockDegree -= 360.0;
        }
        return phaseAngleClockDegree;
    }

    public static class BranchAdmittanceMatrix {
        private Complex y11;
        private Complex y12;
        private Complex y21;
        private Complex y22;

        public BranchAdmittanceMatrix() {
            y11 = Complex.ZERO;
            y12 = Complex.ZERO;
            y21 = Complex.ZERO;
            y22 = Complex.ZERO;
        }

        public BranchAdmittanceMatrix(Complex y11, Complex y12, Complex y21, Complex y22) {
            this.y11 = y11;
            this.y12 = y12;
            this.y21 = y21;
            this.y22 = y22;
        }

        public Complex y11() {
            return y11;
        }

        public Complex y12() {
            return y12;
        }

        public Complex y21() {
            return y21;
        }

        public Complex y22() {
            return y22;
        }
    }

    static class Flow {
        Complex fromTo = Complex.ZERO;
        Complex toFrom = Complex.ZERO;
    }
}