LfNetworkLoaderImplTest.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.network.impl;

import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.ActivePowerControlAdder;
import com.powsybl.iidm.network.test.DanglingLineNetworkFactory;
import com.powsybl.iidm.network.test.EurostagTutorialExample1Factory;
import com.powsybl.iidm.network.test.ThreeWindingsTransformerNetworkFactory;
import com.powsybl.openloadflow.network.*;
import com.powsybl.openloadflow.util.PerUnit;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

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

    private Network network;

    private Generator g;

    @BeforeEach
    void setUp() {
        network = Network.create("test", "code");
        Bus b = createBus(network, "b", 380);
        Bus b2 = createBus(network, "b2", 380);
        createLine(network, b, b2, "l", 1);
        g = createGenerator(b, "g", 10, 400);
        g.newExtension(ActivePowerControlAdder.class)
                .withParticipate(true)
                .withDroop(30)
                .add();
    }

    @Test
    void initialTest() {
        List<LfNetwork> lfNetworks = Networks.load(network, new FirstSlackBusSelector());
        LfNetwork lfNetwork = lfNetworks.get(0);
        LfGenerator lfGenerator = lfNetwork.getBus(0).getGenerators().get(0);
        assertEquals("g", lfGenerator.getId());
        assertTrue(lfGenerator.isParticipating());
    }

    @Test
    void generatorZeroActivePowerTargetTest() {
        // targetP == 0, generator is discarded from active power control
        g.setTargetP(0);
        List<LfNetwork> lfNetworks = Networks.load(network, new FirstSlackBusSelector());
        LfNetwork lfNetwork = lfNetworks.get(0);
        assertFalse(lfNetwork.getBus(0).getGenerators().get(0).isParticipating());
    }

    @Test
    void generatorActivePowerTargetGreaterThanMaxTest() {
        // targetP > maxP, generator is discarded from active power control
        g.setTargetP(10);
        g.setMaxP(5);
        List<LfNetwork> lfNetworks = Networks.load(network, new FirstSlackBusSelector());
        LfNetwork lfNetwork = lfNetworks.get(0);
        assertFalse(lfNetwork.getBus(0).getGenerators().get(0).isParticipating());
    }

    @Test
    void generatorReactiveRangeTooSmallTest() {
        // generators with a too small reactive range cannot control voltage
        g.newReactiveCapabilityCurve()
                .beginPoint()
                .setP(5)
                .setMinQ(6)
                .setMaxQ(6.0000001)
                .endPoint()
                .beginPoint()
                .setP(14)
                .setMinQ(7)
                .setMaxQ(7.00000001)
                .endPoint()
                .add();

        List<LfNetwork> lfNetworks = Networks.load(network, new FirstSlackBusSelector());
        LfNetwork lfNetwork = lfNetworks.get(0);
        assertFalse(lfNetwork.getBus(0).isGeneratorVoltageControlEnabled());
    }

    @Test
    void generatorNotStartedTest() {
        // targetP is zero and minP > 0, meansn generator is not started and cannot control voltage
        g.setTargetP(0);
        g.setMinP(1);
        List<LfNetwork> lfNetworks = Networks.load(network, new FirstSlackBusSelector());
        LfNetwork lfNetwork = lfNetworks.get(0);
        assertFalse(lfNetwork.getBus(0).isGeneratorVoltageControlEnabled());
    }

    @Test
    void networkWithDanglingLineTest() {
        network = DanglingLineNetworkFactory.create();
        List<LfNetwork> lfNetworks = Networks.load(network, new FirstSlackBusSelector());
        assertEquals(1, lfNetworks.size());

        LfNetwork mainNetwork = lfNetworks.get(0);
        LfBus lfDanglingLineBus = mainNetwork.getBusById("DL_BUS");
        assertTrue(lfDanglingLineBus instanceof LfDanglingLineBus);
        assertEquals("VL", lfDanglingLineBus.getVoltageLevelId());
        assertNull(lfDanglingLineBus.getViolationLocation());
    }

    @Test
    void networkWithControlAreasTest() {
        network = EurostagTutorialExample1Factory.createWithTieLinesAndAreas();
        LfNetworkParameters parameters = new LfNetworkParameters();

        List<LfNetwork> lfNetworks = Networks.load(network, parameters);
        assertEquals(1, lfNetworks.size());
        LfNetwork mainNetwork = lfNetworks.get(0);
        assertFalse(mainNetwork.hasArea());

        parameters.setAreaInterchangeControl(true);

        lfNetworks = Networks.load(network, parameters);
        assertEquals(1, lfNetworks.size());
        mainNetwork = lfNetworks.get(0);
        LfArea lfArea = mainNetwork.getAreaById("ControlArea_A");
        // The area is not of 'ControlArea' type, so it is not created
        assertNull(mainNetwork.getAreaById("Region_AB"));
        assertEquals(-602.6 / PerUnit.SB, lfArea.getInterchangeTarget());
        assertEquals(ElementType.AREA, lfArea.getType());
        assertEquals(lfArea.getId(), mainNetwork.getArea(lfArea.getNum()).getId());
        assertEquals(lfArea.getId(), mainNetwork.getElement(ElementType.AREA, lfArea.getNum()).getId());
    }

    @Test
    void networkInvalidAreasTest() {
        // The areas have no boundaries, so they are not created
        network = MultiAreaNetworkFactory.createWithAreaWithoutBoundariesOrTarget();
        LfNetworkParameters parameters = new LfNetworkParameters()
                .setAreaInterchangeControl(true);
        List<LfNetwork> lfNetworks = Networks.load(network, parameters);
        assertEquals(1, lfNetworks.size());
        assertEquals(4, lfNetworks.get(0).getBuses().size());
        LfNetwork mainNetwork = lfNetworks.get(0);
        assertNull(mainNetwork.getAreaById("a1")); // no boundaries
        assertNotNull(mainNetwork.getAreaById("a2")); // ok
        assertNull(mainNetwork.getAreaById("a3")); // no interchange target
        assertNull(mainNetwork.getAreaById("a4")); // no voltage levels
    }

    @Test
    void networkWithInvalidAreasTest2() {
        network = MultiAreaNetworkFactory.createAreaTwoComponentsWithBoundaries();
        LfNetworkParameters parameters = new LfNetworkParameters()
                .setAreaInterchangeControl(true);

        List<LfNetwork> lfNetworks = Networks.load(network, parameters);
        assertEquals(1, lfNetworks.size());

        LfNetwork mainNetwork = lfNetworks.get(0);
        assertNotNull(mainNetwork.getAreaById("a1"));
        assertNull(mainNetwork.getAreaById("a2")); // fragmented area (boundaries in different components)
    }

    @Test
    void networkWith3wtTest() {
        network = ThreeWindingsTransformerNetworkFactory.create();
        ThreeWindingsTransformer transformer = network.getThreeWindingsTransformer("3WT");
        assertNotNull(transformer);
        VoltageLevel voltageLevelLeg1 = transformer.getLeg1().getTerminal().getVoltageLevel();

        List<LfNetwork> lfNetworks = Networks.load(network, new FirstSlackBusSelector());
        assertEquals(1, lfNetworks.size());

        LfNetwork mainNetwork = lfNetworks.get(0);
        LfBus lfStarBus = mainNetwork.getBusById("3WT_BUS0");
        assertTrue(lfStarBus instanceof LfStarBus);
        assertEquals(voltageLevelLeg1.getId(), lfStarBus.getVoltageLevelId());
        assertTrue(lfStarBus.getCountry().isEmpty());
        assertNull(lfStarBus.getViolationLocation());
    }

    @Test
    void defaultMethodsTest() {
        network = EurostagFactory.fix(EurostagTutorialExample1Factory.create());
        List<LfNetwork> lfNetworks = Networks.load(network, new FirstSlackBusSelector());
        assertEquals(1, lfNetworks.size());

        LfNetwork mainNetwork = lfNetworks.get(0);
        LfGenerator generator = mainNetwork.getBusById("VLGEN_0").getGenerators().get(0);
        assertEquals(0, generator.getSlope(), 10E-3);
        generator.setSlope(10);
        assertEquals(0, generator.getSlope(), 10E-3);
    }

    @Test
    void defaultMethodsTest2() {
        network = BoundaryFactory.create();
        List<LfNetwork> lfNetworks = Networks.load(network, new FirstSlackBusSelector());
        assertEquals(1, lfNetworks.size());

        LfNetwork mainNetwork = lfNetworks.get(0);
        LfBus lfDanglingLineBus = mainNetwork.getBusById("dl1_BUS");
        LfGenerator generator = lfDanglingLineBus.getGenerators().get(0);
        assertEquals(0, generator.getDroop(), 10E-3);
        generator.setParticipating(true);
        assertFalse(generator.isParticipating());
    }

    @Test
    void validationLevelTest() {
        network = Network.create("test", "code");
        network.setMinimumAcceptableValidationLevel(ValidationLevel.EQUIPMENT);
        Bus b = createBus(network, "b", 380);
        Bus b2 = createBus(network, "b2", 380);
        createLine(network, b, b2, "l", 1);
        g = createGenerator2(b, "g", 10, 400);
        PowsyblException e = assertThrows(PowsyblException.class, () -> Networks.load(network, new FirstSlackBusSelector()));
        assertEquals("Only STEADY STATE HYPOTHESIS validation level of the network is supported", e.getMessage());
    }

    @Test
    void validationLevelTest2() {
        network = VoltageControlNetworkFactory.createNetworkWithT2wt();
        network.setMinimumAcceptableValidationLevel(ValidationLevel.EQUIPMENT);
        network.getTwoWindingsTransformer("T2wT").getRatioTapChanger().setTargetV(Double.NaN).setRegulating(true);
        PowsyblException e = assertThrows(PowsyblException.class, () -> Networks.load(network, new FirstSlackBusSelector()));
        assertEquals("Only STEADY STATE HYPOTHESIS validation level of the network is supported", e.getMessage());
    }

    @Test
    void validationLevelTest3() {
        network = VoltageControlNetworkFactory.createTransformerBaseNetwork("network");
        network.setMinimumAcceptableValidationLevel(ValidationLevel.EQUIPMENT);
        network.getLoad("LOAD_2").setP0(Double.NaN).setQ0(Double.NaN);
        PowsyblException e = assertThrows(PowsyblException.class, () -> Networks.load(network, new FirstSlackBusSelector()));
        assertEquals("Only STEADY STATE HYPOTHESIS validation level of the network is supported", e.getMessage());
    }

    @Test
    void validationLevelTest4() {
        network = HvdcNetworkFactory.createVsc();
        network.setMinimumAcceptableValidationLevel(ValidationLevel.EQUIPMENT);
        network.getHvdcLine("hvdc23").setConvertersMode(null).setActivePowerSetpoint(Double.NaN);
        PowsyblException e = assertThrows(PowsyblException.class, () -> Networks.load(network, new FirstSlackBusSelector()));
        assertEquals("Only STEADY STATE HYPOTHESIS validation level of the network is supported", e.getMessage());
    }

    @Test
    void validationLevelTest5() {
        network = BoundaryFactory.create();
        network.setMinimumAcceptableValidationLevel(ValidationLevel.EQUIPMENT);
        network.getDanglingLine("dl1").setP0(Double.NaN).setQ0(Double.NaN);
        PowsyblException e = assertThrows(PowsyblException.class, () -> Networks.load(network, new FirstSlackBusSelector()));
        assertEquals("Only STEADY STATE HYPOTHESIS validation level of the network is supported", e.getMessage());
    }

    @Test
    void testMinImpedance() {
        network = EurostagFactory.fix(EurostagTutorialExample1Factory.create());
        network.getLine("NHV1_NHV2_1").setR(0.0).setX(0.0).setB1(0.0).setB2(0.0).setG1(0.0).setG2(0.0);
        List<LfNetwork> lfNetworks = Networks.load(network, new FirstSlackBusSelector());
        LfBranch line = lfNetworks.get(0).getBranchById("NHV1_NHV2_1");
        assertTrue(line.isZeroImpedance(LoadFlowModel.AC));
        assertTrue(line.isZeroImpedance(LoadFlowModel.DC));
        line.setMinZ(10); // for both AC and DC load flow model
        assertFalse(line.isZeroImpedance(LoadFlowModel.AC));
        assertFalse(line.isZeroImpedance(LoadFlowModel.DC));
    }

    @Test
    void testDiscardGeneratorsWithTargetPOutsideActiveLimitsFromVoltageControl() {
        LfNetworkParameters networkParameters = new LfNetworkParameters()
                .setUseActiveLimits(true)
                .setDisableVoltageControlOfGeneratorsOutsideActivePowerLimits(true);

        Network network = Network.create("test", "code");
        Bus b = createBus(network, "b", 380);

        // discarded from voltage control because targetP < minP (50 < 100)
        Generator g1 = createGenerator(b, "g1", 50, 400);
        g1.setMinP(100).setMaxP(200);

        // discarded from voltage control because targetP > maxP (250 > 200)
        Generator g2 = createGenerator(b, "g2", 250, 400);
        g2.setMinP(100).setMaxP(200);

        // kept
        Generator g3 = createGenerator(b, "g3", 150, 400);
        g3.setMinP(100).setMaxP(200);

        List<LfNetwork> lfNetworks = Networks.load(network, networkParameters);
        LfNetwork lfNetwork = lfNetworks.get(0);
        List<LfGenerator> generators = lfNetwork.getBus(0).getGenerators();

        assertEquals(LfGenerator.GeneratorControlType.OFF, generators.get(0).getGeneratorControlType());
        assertEquals(LfGenerator.GeneratorControlType.OFF, generators.get(1).getGeneratorControlType());
        assertEquals(LfGenerator.GeneratorControlType.VOLTAGE, generators.get(2).getGeneratorControlType());
    }
}