DanglingLineBoundaryImpl.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.*;

import java.util.Objects;

import static com.powsybl.iidm.network.util.DanglingLineData.zeroImpedance;

/**
 * @author Miora Ralambotiana {@literal <miora.ralambotiana at rte-france.com>}
 */
public class DanglingLineBoundaryImpl implements Boundary {
    // Notes about SV utility class usage here:
    // - side represents the network side, which is always Side.ONE for a dangling line.
    // - DanglingLine model has shunt admittance on network side only, hence splitShuntAdmittance argument in SV methods must be set to false.

    private final DanglingLine parent;

    public DanglingLineBoundaryImpl(DanglingLine parent) {
        this.parent = Objects.requireNonNull(parent);
    }

    @Override
    public double getV() {
        if (useHypothesis(parent)) {
            DanglingLineData danglingLineData = new DanglingLineData(parent);
            return danglingLineData.getBoundaryBusU();
        }

        Terminal t = parent.getTerminal();
        Bus b = t.getBusView().getBus();
        if (zeroImpedance(parent)) {
            return getV(b);
        } else {
            return new SV(t.getP(), t.getQ(), getV(b), getAngle(b), TwoSides.ONE).otherSideU(parent, false);
        }
    }

    @Override
    public double getAngle() {
        if (useHypothesis(parent)) {
            DanglingLineData danglingLineData = new DanglingLineData(parent);
            return Math.toDegrees(danglingLineData.getBoundaryBusTheta());
        }
        Terminal t = parent.getTerminal();
        Bus b = t.getBusView().getBus();
        if (zeroImpedance(parent)) {
            return getAngle(b);
        } else {
            return new SV(t.getP(), t.getQ(), getV(b), getAngle(b), TwoSides.ONE).otherSideA(parent, false);
        }
    }

    @Override
    public double getP() {
        if (useHypothesis(parent)) {
            return -parent.getP0();
        }
        Terminal t = parent.getTerminal();
        Bus b = t.getBusView().getBus();
        if (zeroImpedance(parent)) {
            return -t.getP();
        } else {
            return new SV(t.getP(), t.getQ(), getV(b), getAngle(b), TwoSides.ONE).otherSideP(parent, false);
        }
    }

    @Override
    public double getQ() {
        if (useHypothesis(parent)) {
            return -parent.getQ0();
        }
        Terminal t = parent.getTerminal();
        Bus b = t.getBusView().getBus();
        if (zeroImpedance(parent)) {
            return -t.getQ();
        } else {
            return new SV(t.getP(), t.getQ(), getV(b), getAngle(b), TwoSides.ONE).otherSideQ(parent, false);
        }
    }

    @Override
    public double getI() {
        if (useHypothesis(parent)) {
            return Math.hypot(getP(), getQ()) / (Math.sqrt(3.) * getV() / 1000);
        }
        Terminal t = parent.getTerminal();
        Bus b = t.getBusView().getBus();
        if (zeroImpedance(parent)) {
            return t.getI();
        } else {
            return new SV(t.getP(), t.getQ(), getV(b), getAngle(b), TwoSides.ONE).otherSideI(parent, false);
        }
    }

    @Override
    public DanglingLine getDanglingLine() {
        return parent;
    }

    @Override
    public VoltageLevel getNetworkSideVoltageLevel() {
        return parent.getTerminal().getVoltageLevel();
    }

    private static double getV(Bus b) {
        return b == null ? Double.NaN : b.getV();
    }

    private static double getAngle(Bus b) {
        return b == null ? Double.NaN : b.getAngle();
    }

    private static boolean valid(double p0, double q0) {
        return !Double.isNaN(p0) && !Double.isNaN(q0);
    }

    private static boolean useHypothesis(DanglingLine parent) {
        // We prefer to use P0 and Q0 if the dangling line is not paired and P0 and Q0 are valid, but we cannot retrieve
        // P, Q, angle and voltage at boundary if the dangling line has a generation part: a previous global load flow
        // run is needed, especially if the generation is regulating voltage.
        // This could be improved later.
        return !parent.isPaired() && valid(parent.getP0(), parent.getQ0()) && parent.getGeneration() == null;
    }
}