AcLoadFlowGeneratorTest.java

/**
 * Copyright (c) 2024, 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.iidm.network.extensions.ActivePowerControlAdder;
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.FourBusNetworkFactory;
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.*;

/**
 * @author Anne Tilloy {@literal <anne.tilloy at rte-france.com>}
 */
class AcLoadFlowGeneratorTest {
    private LoadFlow.Runner loadFlowRunner;
    private LoadFlowParameters parameters;
    private OpenLoadFlowParameters parametersExt;

    @BeforeEach
    void setUp() {
        loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(new DenseMatrixFactory()));
        parameters = new LoadFlowParameters();
        parametersExt = OpenLoadFlowParameters.create(parameters);
    }

    @Test
    void testWithCondenser() {
        Network network = FourBusNetworkFactory.createWithCondenser();
        Bus b1 = network.getBusBreakerView().getBus("b1");
        Bus b4 = network.getBusBreakerView().getBus("b4");
        parameters.setBalanceType(LoadFlowParameters.BalanceType.PROPORTIONAL_TO_LOAD);
        LoadFlowResult result = loadFlowRunner.run(network, parameters);
        assertTrue(result.isFullyConverged());
        assertVoltageEquals(1.0, b1);
        assertAngleEquals(0, b1);
        assertVoltageEquals(1.0, b4);
        assertAngleEquals(-2.584977, b4);
    }

    @Test
    void testGeneratorDiscardedFromVoltageControl() {
        Network network = FourBusNetworkFactory.createWith2GeneratorsAtBus1();
        Generator g1Bis = network.getGenerator("g1Bis").setTargetP(0.0).setMinP(1.0).setTargetQ(Double.NaN); // must be discarded from voltage control
        Bus b1 = network.getBusBreakerView().getBus("b1");
        Bus b4 = network.getBusBreakerView().getBus("b4");
        Generator g1 = network.getGenerator("g1");
        parameters.setBalanceType(LoadFlowParameters.BalanceType.PROPORTIONAL_TO_LOAD);
        LoadFlowResult result = loadFlowRunner.run(network, parameters);
        assertTrue(result.isFullyConverged());
        assertVoltageEquals(1.0, b1);
        assertAngleEquals(0, b1);
        assertVoltageEquals(1.0, b4);
        assertAngleEquals(-1.452245, b4);
        assertReactivePowerEquals(0.0, g1Bis.getTerminal());
        assertReactivePowerEquals(-0.570, g1.getTerminal());
    }

    @Test
    void testGeneratorForceTargetQInDiagram() {
        Network network = FourBusNetworkFactory.createBaseNetwork();
        Generator g1 = network.getGenerator("g1");
        Bus b1 = network.getBusBreakerView().getBus("b1");
        Bus b4 = network.getBusBreakerView().getBus("b4");
        g1.newMinMaxReactiveLimits().setMinQ(-1).setMaxQ(1).add();

        // targetQ > diagram
        g1.setTargetQ(2).setVoltageRegulatorOn(false);
        parametersExt.setForceTargetQInReactiveLimits(true);

        LoadFlowResult result = loadFlowRunner.run(network, parameters);
        assertTrue(result.isFullyConverged());
        assertVoltageEquals(1.028108, b1);
        assertAngleEquals(0, b1);
        assertVoltageEquals(1.0, b4);
        assertAngleEquals(-0.337487, b4);
        assertReactivePowerEquals(-1, g1.getTerminal());

        // targetQ < diagram
        g1.setTargetQ(-2);
        result = loadFlowRunner.run(network, parameters);
        assertTrue(result.isFullyConverged());
        assertVoltageEquals(0.884231, b1);
        assertAngleEquals(0, b1);
        assertVoltageEquals(1.0, b4);
        assertAngleEquals(-1.089083, b4);
        assertReactivePowerEquals(1, g1.getTerminal());
    }

    @Test
    void testGeneratorForceTargetQInCurveDiagram() {
        Network network = FourBusNetworkFactory.createBaseNetwork();
        Generator g1 = network.getGenerator("g1");
        assertEquals(2, g1.getTargetP());
        // disable slack generation on g4 so that only g1 moves
        network.getGenerator("g4").newExtension(ActivePowerControlAdder.class).withParticipate(false).add();
        Load d3 = network.getLoad("d3");
        g1.newReactiveCapabilityCurve()
            .beginPoint().setP(0).setMinQ(-2).setMaxQ(2).endPoint()
            .beginPoint().setP(4).setMinQ(-1).setMaxQ(1).endPoint()
            .add();

        g1.setTargetQ(1.5).setVoltageRegulatorOn(false);
        parametersExt.setForceTargetQInReactiveLimits(true).setSlackBusPMaxMismatch(0.001);

        d3.setP0(1.5);
        LoadFlowResult result = loadFlowRunner.run(network, parameters);
        assertTrue(result.isFullyConverged());
        assertActivePowerEquals(-1.5, g1.getTerminal()); // lowered from 2 to 1.5 because slack distribution
        assertReactivePowerEquals(-1.5, g1.getTerminal()); // at targetQ, inside curve

        d3.setP0(2.);
        result = loadFlowRunner.run(network, parameters);
        assertTrue(result.isFullyConverged());
        assertActivePowerEquals(-2.0, g1.getTerminal()); // at targetP, no slack needed
        assertReactivePowerEquals(-1.5, g1.getTerminal()); // at targetQ and at curve limit

        d3.setP0(2.5);
        result = loadFlowRunner.run(network, parameters);
        assertTrue(result.isFullyConverged());
        assertActivePowerEquals(-2.5, g1.getTerminal()); // increased from 2 to 2.5 because slack distribution
        assertReactivePowerEquals(-1.374997, g1.getTerminal()); // not at targetQ because at curve limit
    }
}