AcLoadFlowBoundaryTest.java

/**
 * 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.ac;

import com.powsybl.iidm.network.*;
import com.powsybl.loadflow.LoadFlow;
import com.powsybl.loadflow.LoadFlowParameters;
import com.powsybl.loadflow.LoadFlowResult;
import com.powsybl.math.matrix.DenseMatrixFactory;
import com.powsybl.openloadflow.OpenLoadFlowParameters;
import com.powsybl.openloadflow.OpenLoadFlowProvider;
import com.powsybl.openloadflow.network.BoundaryFactory;
import com.powsybl.openloadflow.network.SlackBusSelectionMode;
import com.powsybl.openloadflow.network.VoltageControlNetworkFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static com.powsybl.openloadflow.util.LoadFlowAssert.*;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
 * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
 */
class AcLoadFlowBoundaryTest {

    private Network network;
    private Bus bus1;
    private Bus bus2;
    private DanglingLine dl1;
    private Generator g1;

    private LoadFlow.Runner loadFlowRunner;

    private LoadFlowParameters parameters;

    private OpenLoadFlowParameters parametersExt;

    @BeforeEach
    void setUp() {
        network = BoundaryFactory.create();
        bus1 = network.getBusBreakerView().getBus("b1");
        bus2 = network.getBusBreakerView().getBus("b2");
        dl1 = network.getDanglingLine("dl1");
        g1 = network.getGenerator("g1");
        loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(new DenseMatrixFactory()));
        parameters = new LoadFlowParameters()
                .setUseReactiveLimits(false)
                .setDistributedSlack(false);
        parametersExt = OpenLoadFlowParameters.create(parameters)
                .setSlackBusSelectionMode(SlackBusSelectionMode.MOST_MESHED);
    }

    @Test
    void test() {
        LoadFlowResult result = loadFlowRunner.run(network, parameters);
        assertTrue(result.isFullyConverged());

        assertVoltageEquals(390, bus1);
        assertAngleEquals(0.058104, bus1);
        assertVoltageEquals(388.582864, bus2);
        assertAngleEquals(0, bus2);
        assertActivePowerEquals(101.302, dl1.getTerminal());
        assertReactivePowerEquals(149.764, dl1.getTerminal());
    }

    @Test
    void testWithVoltageRegulationOn() {
        g1.setTargetQ(0);
        g1.setVoltageRegulatorOn(false);
        dl1.getGeneration().setVoltageRegulationOn(true);
        dl1.getGeneration().setMinP(0);
        dl1.getGeneration().setMaxP(10);
        dl1.getGeneration().newMinMaxReactiveLimits()
                .setMinQ(-100)
                .setMaxQ(100)
                .add();
        LoadFlowResult result = loadFlowRunner.run(network, parameters);
        assertTrue(result.isFullyConverged());

        assertVoltageEquals(390.440, bus1);
        assertAngleEquals(0.114371, bus1);
        assertVoltageEquals(390.181, bus2);
        assertAngleEquals(0, bus2);
        assertActivePowerEquals(101.2, dl1.getTerminal());
        assertReactivePowerEquals(-0.202, dl1.getTerminal());

        parameters.setDistributedSlack(true)
                  .setUseReactiveLimits(true);
        LoadFlowResult result2 = loadFlowRunner.run(network, parameters);
        assertTrue(result2.isFullyConverged());

        assertVoltageEquals(390.440, bus1);
        assertAngleEquals(0.114371, bus1);
        assertVoltageEquals(390.181, bus2);
        assertAngleEquals(0, bus2);
        assertActivePowerEquals(101.2, dl1.getTerminal());
        assertReactivePowerEquals(-0.202, dl1.getTerminal());
    }

    @Test
    void testWithXnodeDistributedSlack() {
        parameters.setUseReactiveLimits(true);
        parameters.setDistributedSlack(true);
        testWithXnode();
    }

    @Test
    void testWithXnodeAreaInterchangeControl() {
        parameters.setUseReactiveLimits(true);
        parametersExt.setAreaInterchangeControl(true);
        testWithXnode();
    }

    void testWithXnode() {
        network = BoundaryFactory.createWithXnode();

        LoadFlowResult result = loadFlowRunner.run(network, parameters);
        assertTrue(result.isFullyConverged());

        assertVoltageEquals(400.000, network.getBusBreakerView().getBus("b1"));
        assertVoltageEquals(399.999, network.getBusBreakerView().getBus("xnode"));
        assertVoltageEquals(399.999, network.getBusBreakerView().getBus("b3"));
        assertVoltageEquals(400.000, network.getBusBreakerView().getBus("b4"));
    }

    @Test
    void testWithTieLineDistributedSlack() {
        parameters.setUseReactiveLimits(true);
        parameters.setDistributedSlack(true);
        testWithTieLine();
    }

    @Test
    void testWithTieLineAreaInterchangeControl() {
        parameters.setUseReactiveLimits(true);
        parametersExt.setAreaInterchangeControl(true);
        testWithTieLine();
    }

    void testWithTieLine() {
        network = BoundaryFactory.createWithTieLine();
        LoadFlowResult result = loadFlowRunner.run(network, parameters);
        assertTrue(result.isFullyConverged());

        assertVoltageEquals(400.000, network.getBusBreakerView().getBus("b1"));
        assertVoltageEquals(399.999, network.getBusBreakerView().getBus("b3"));
        assertVoltageEquals(400.000, network.getBusBreakerView().getBus("b4"));
        assertReactivePowerEquals(0.0044, network.getLine("l34").getTerminal2());

        TieLine line = network.getTieLine("t12");
        line.getDanglingLine1().getTerminal().disconnect();
        line.getDanglingLine1().getTerminal().disconnect();
        loadFlowRunner.run(network, parameters);
        assertVoltageEquals(400.0, network.getBusBreakerView().getBus("b3"));
        assertReactivePowerEquals(-0.00125, network.getLine("l34").getTerminal2());
    }

    @Test
    void testEquivalentBranch() {
        network = VoltageControlNetworkFactory.createNetworkWithT2wt();
        network.newLine()
                .setId("LINE_23")
                .setBus1("BUS_2")
                .setBus2("BUS_3")
                .setR(0.0)
                .setX(100)
                .add();

        LoadFlowResult result = loadFlowRunner.run(network, parameters);
        assertTrue(result.isFullyConverged());
        assertVoltageEquals(135.0, network.getBusBreakerView().getBus("BUS_1"));
        assertVoltageEquals(127.198, network.getBusBreakerView().getBus("BUS_2"));
        assertVoltageEquals(40.19, network.getBusBreakerView().getBus("BUS_3"));
    }

    @Test
    void testWithNonImpedantDanglingLine() {
        dl1.setR(0.0).setX(0.0);
        LoadFlowResult result = loadFlowRunner.run(network, parameters);
        assertTrue(result.isFullyConverged());
        assertActivePowerEquals(101.0, dl1.getTerminal());
        assertReactivePowerEquals(150.0, dl1.getTerminal());

        dl1.getGeneration().setVoltageRegulationOn(true);
        dl1.getGeneration().setTargetV(390.0);
        dl1.getGeneration().setMinP(0);
        dl1.getGeneration().setMaxP(10);
        dl1.getGeneration().newMinMaxReactiveLimits()
                .setMinQ(-100)
                .setMaxQ(100)
                .add();
        LoadFlowResult result2 = loadFlowRunner.run(network, parameters);
        assertTrue(result2.isFullyConverged());
        assertActivePowerEquals(101.0, dl1.getTerminal());
        assertReactivePowerEquals(-33.888, dl1.getTerminal());

        parameters.setDc(true);
        LoadFlowResult result3 = loadFlowRunner.run(network, parameters);
        assertTrue(result3.isFullyConverged());
        assertActivePowerEquals(101.0, dl1.getTerminal());
        assertReactivePowerEquals(Double.NaN, dl1.getTerminal());
    }

    @Test
    void testDanglingLineShuntAdmittance() {
        // verify dangling line shunt admittance is correctly accounted to be completely on network side (and not split with boundary side)

        // setup zero flows flow at dangling line boundary side
        dl1.setP0(0.0).setQ0(0.0).getGeneration().setTargetP(0.0).setTargetQ(0.0).setVoltageRegulationOn(false);

        // set higher B and G shunt values, and also much higher series impedance, so we would get very different results if the shunt admittance were split
        dl1.setB(1e-3).setG(1e-4).setR(3.).setX(30.);

        // set g1 to regulate dl1 terminal at 400.0 kV
        g1.setRegulatingTerminal(dl1.getTerminal()).setTargetV(400.0);

        LoadFlowResult result = loadFlowRunner.run(network, parameters);

        assertTrue(result.isFullyConverged());
        assertVoltageEquals(400.0, bus2);
        assertActivePowerEquals(16., dl1.getTerminal()); // v^2 * B_shunt
        assertReactivePowerEquals(-160., dl1.getTerminal()); // - v^2 * G_shunt
    }
}