CgmesZoneLayoutTest.java

/**
 * Copyright (c) 2019-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.sld.cgmes.layout;

import com.powsybl.iidm.network.*;
import com.powsybl.sld.builders.NetworkGraphBuilder;
import com.powsybl.sld.cgmes.dl.iidm.extensions.*;
import com.powsybl.sld.layout.LayoutParameters;
import com.powsybl.sld.model.coordinate.Orientation;
import com.powsybl.sld.model.coordinate.Point;
import com.powsybl.sld.model.graphs.VoltageLevelGraph;
import com.powsybl.sld.model.graphs.ZoneGraph;
import com.powsybl.sld.model.nodes.BranchEdge;
import com.powsybl.sld.model.nodes.BusNode;
import com.powsybl.sld.model.nodes.Node;
import org.junit.jupiter.api.Test;

import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.List;

import static com.powsybl.sld.library.ComponentTypeName.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
 *
 * @author Massimo Ferraro {@literal <massimo.ferraro@techrain.eu>}
 */
class CgmesZoneLayoutTest {

    private static final String SUBSTATION_1_ID = "Substation1";
    private static final String SUBSTATION_2_ID = "Substation2";
    private static final String VOLTAGE_LEVEL_11_ID = "VoltageLevel11";
    private static final String VOLTAGE_LEVEL_12_ID = "VoltageLevel12";
    private static final String VOLTAGE_LEVEL_21_ID = "VoltageLevel21";
    private static final String BUS_11_ID = "Bus11";
    private static final String BUS_12_ID = "Bus12";
    private static final String BUS_21_ID = "Bus21";
    private static final String LOAD_ID = "Load";
    private static final String LINE_ID = "Line";
    private static final String GENERATOR_ID = "Generator";
    private static final String TRANSFORMER_ID = "Transformer";
    private static final String DIAGRAM_ID = "Diagram";

    private Network createNetwork() {
        Network network = Network.create("Network", "test");
        network.setCaseDate(ZonedDateTime.parse("2018-01-01T00:30:00.000+01:00"));
        Substation substation1 = network.newSubstation()
                .setId(SUBSTATION_1_ID)
                .setCountry(Country.FR)
                .add();
        VoltageLevel voltageLevel11 = substation1.newVoltageLevel()
                .setId(VOLTAGE_LEVEL_11_ID)
                .setNominalV(400)
                .setTopologyKind(TopologyKind.BUS_BREAKER)
                .add();
        voltageLevel11.getBusBreakerView().newBus()
                .setId(BUS_11_ID)
                .add();
        voltageLevel11.newLoad()
                .setId(LOAD_ID)
                .setBus(BUS_11_ID)
                .setConnectableBus(BUS_11_ID)
                .setP0(100)
                .setQ0(50)
                .add();
        VoltageLevel voltageLevel12 = substation1.newVoltageLevel()
                .setId(VOLTAGE_LEVEL_12_ID)
                .setNominalV(280)
                .setTopologyKind(TopologyKind.BUS_BREAKER)
                .add();
        voltageLevel12.getBusBreakerView().newBus()
                .setId(BUS_12_ID)
                .add();
        int zb380 = 380 * 380 / 100;
        substation1.newTwoWindingsTransformer()
                .setId(TRANSFORMER_ID)
                .setVoltageLevel1(voltageLevel11.getId())
                .setBus1(BUS_11_ID)
                .setConnectableBus1(BUS_11_ID)
                .setRatedU1(24.0)
                .setVoltageLevel2(voltageLevel12.getId())
                .setBus2(BUS_12_ID)
                .setConnectableBus2(BUS_12_ID)
                .setRatedU2(400.0)
                .setR(0.24 / 1300 * zb380)
                .setX(Math.sqrt(10 * 10 - 0.24 * 0.24) / 1300 * zb380)
                .setG(0.0)
                .setB(0.0)
                .add();
        Substation substation2 = network.newSubstation()
                .setId(SUBSTATION_2_ID)
                .setCountry(Country.FR)
                .add();
        VoltageLevel voltageLevel21 = substation2.newVoltageLevel()
                .setId(VOLTAGE_LEVEL_21_ID)
                .setNominalV(280)
                .setTopologyKind(TopologyKind.BUS_BREAKER)
                .add();
        voltageLevel21.getBusBreakerView().newBus()
                .setId(BUS_21_ID)
                .add();
        voltageLevel21.newGenerator()
                .setId(GENERATOR_ID)
                .setBus(BUS_21_ID)
                .setConnectableBus(BUS_21_ID)
                .setTargetP(100)
                .setTargetV(380)
                .setVoltageRegulatorOn(true)
                .setMaxP(100)
                .setMinP(0)
                .add();
        network.newLine()
                .setId(LINE_ID)
                .setVoltageLevel1(voltageLevel12.getId())
                .setBus1(BUS_12_ID)
                .setConnectableBus1(BUS_12_ID)
                .setVoltageLevel2(voltageLevel21.getId())
                .setBus2(BUS_21_ID)
                .setConnectableBus2(BUS_21_ID)
                .setR(3.0)
                .setX(33.0)
                .setG1(0.0)
                .setB1(386E-6 / 2)
                .setG2(0.0)
                .setB2(386E-6 / 2)
                .add();
        return network;
    }

    private void addDiagramData(Network network) {
        Load load = network.getLoad(LOAD_ID);
        InjectionDiagramData<Load> loadDiagramData = new InjectionDiagramData<>(load);
        InjectionDiagramData.InjectionDiagramDetails loadsDiagramDetails = loadDiagramData.new InjectionDiagramDetails(new DiagramPoint(10, 20, 0), 90);
        loadsDiagramDetails.addTerminalPoint(new DiagramPoint(15, 20, 1));
        loadsDiagramDetails.addTerminalPoint(new DiagramPoint(30, 20, 2));
        loadDiagramData.addData(DIAGRAM_ID, loadsDiagramDetails);
        load.addExtension(InjectionDiagramData.class, loadDiagramData);

        Bus bus11 = network.getVoltageLevel(VOLTAGE_LEVEL_11_ID).getBusBreakerView().getBus(BUS_11_ID);
        NodeDiagramData<Bus> busDiagramData11 = new NodeDiagramData<>(bus11);
        NodeDiagramData.NodeDiagramDataDetails diagramDetails11 = busDiagramData11.new NodeDiagramDataDetails();
        diagramDetails11.setPoint1(new DiagramPoint(30, 10, 1));
        diagramDetails11.setPoint2(new DiagramPoint(30, 30, 2));
        busDiagramData11.addData(DIAGRAM_ID, diagramDetails11);
        bus11.addExtension(NodeDiagramData.class, busDiagramData11);

        TwoWindingsTransformer twt = network.getTwoWindingsTransformer(TRANSFORMER_ID);
        CouplingDeviceDiagramData<TwoWindingsTransformer> twtDiagramData = new CouplingDeviceDiagramData<>(twt);
        CouplingDeviceDiagramData.CouplingDeviceDiagramDetails twtDiagramDetails = twtDiagramData.new CouplingDeviceDiagramDetails(new DiagramPoint(50, 20, 0), 90);
        twtDiagramDetails.addTerminalPoint(DiagramTerminal.TERMINAL1, new DiagramPoint(45, 20, 1));
        twtDiagramDetails.addTerminalPoint(DiagramTerminal.TERMINAL1, new DiagramPoint(30, 20, 2));
        twtDiagramDetails.addTerminalPoint(DiagramTerminal.TERMINAL2, new DiagramPoint(55, 20, 1));
        twtDiagramDetails.addTerminalPoint(DiagramTerminal.TERMINAL2, new DiagramPoint(70, 20, 2));
        twtDiagramData.addData(DIAGRAM_ID, twtDiagramDetails);
        twt.addExtension(CouplingDeviceDiagramData.class, twtDiagramData);

        Bus bus12 = network.getVoltageLevel(VOLTAGE_LEVEL_12_ID).getBusBreakerView().getBus(BUS_12_ID);
        NodeDiagramData<Bus> busDiagramData12 = new NodeDiagramData<>(bus12);
        NodeDiagramData.NodeDiagramDataDetails diagramDetails12 = busDiagramData11.new NodeDiagramDataDetails();
        diagramDetails12.setPoint1(new DiagramPoint(70, 10, 1));
        diagramDetails12.setPoint2(new DiagramPoint(70, 30, 2));
        busDiagramData12.addData(DIAGRAM_ID, diagramDetails12);
        bus12.addExtension(NodeDiagramData.class, busDiagramData12);

        Line line = network.getLine(LINE_ID);
        LineDiagramData<Line> lineDiagramData = new LineDiagramData<>(line);
        lineDiagramData.addPoint(DIAGRAM_ID, new DiagramPoint(70, 20, 1));
        lineDiagramData.addPoint(DIAGRAM_ID, new DiagramPoint(100, 20, 2));
        lineDiagramData.addPoint(DIAGRAM_ID, new DiagramPoint(100, 60, 3));
        lineDiagramData.addPoint(DIAGRAM_ID, new DiagramPoint(130, 60, 4));
        line.addExtension(LineDiagramData.class, lineDiagramData);

        Bus bus21 = network.getVoltageLevel(VOLTAGE_LEVEL_21_ID).getBusBreakerView().getBus(BUS_21_ID);
        NodeDiagramData<Bus> busDiagramData21 = new NodeDiagramData<>(bus21);
        NodeDiagramData.NodeDiagramDataDetails diagramDetails21 = busDiagramData21.new NodeDiagramDataDetails();
        diagramDetails21.setPoint1(new DiagramPoint(130, 50, 1));
        diagramDetails21.setPoint2(new DiagramPoint(130, 70, 2));
        busDiagramData21.addData(DIAGRAM_ID, diagramDetails21);
        bus21.addExtension(NodeDiagramData.class, busDiagramData21);

        Generator generator = network.getGenerator(GENERATOR_ID);
        InjectionDiagramData<Generator> generatorDiagramData = new InjectionDiagramData<>(generator);
        InjectionDiagramData.InjectionDiagramDetails diagramDetails = generatorDiagramData.new InjectionDiagramDetails(new DiagramPoint(150, 60, 0), 0);
        diagramDetails.addTerminalPoint(new DiagramPoint(145, 60, 1));
        diagramDetails.addTerminalPoint(new DiagramPoint(130, 60, 2));
        generatorDiagramData.addData(DIAGRAM_ID, diagramDetails);
        generator.addExtension(InjectionDiagramData.class, generatorDiagramData);

        NetworkDiagramData.addDiagramName(network, DIAGRAM_ID, SUBSTATION_1_ID);
        NetworkDiagramData.addDiagramName(network, DIAGRAM_ID, SUBSTATION_2_ID);
    }

    @Test
    void test() {
        Network network = createNetwork();
        addDiagramData(network);
        List<String> zone = Arrays.asList(SUBSTATION_1_ID, SUBSTATION_2_ID);
        ZoneGraph graph = new NetworkGraphBuilder(network).buildZoneGraph(zone);
        LayoutParameters layoutParameters = new LayoutParameters();
        layoutParameters.setCgmesScaleFactor(2);
        layoutParameters.setCgmesDiagramName(DIAGRAM_ID);
        new CgmesZoneLayout(graph, network).run(layoutParameters);

        assertEquals(2, graph.getSubstations().size());
        assertEquals(2, graph.getSubstationGraph(SUBSTATION_1_ID).getVoltageLevels().size());
        assertEquals(1, graph.getSubstationGraph(SUBSTATION_2_ID).getVoltageLevels().size());
        assertEquals(SUBSTATION_1_ID, graph.getSubstations().get(0).getSubstationId());
        assertEquals(SUBSTATION_2_ID, graph.getSubstations().get(1).getSubstationId());

        VoltageLevelGraph vlGraph11 = graph.getSubstationGraph(SUBSTATION_1_ID).getVoltageLevel(VOLTAGE_LEVEL_11_ID);
        assertEquals(3, vlGraph11.getNodes().size());
        assertEquals(2, vlGraph11.getEdges().size());
        checkNode(vlGraph11.getNodes().get(0), Node.NodeType.BUS, BUS_11_ID, BUSBAR_SECTION, Arrays.asList(LOAD_ID, TRANSFORMER_ID + "_" + TwoSides.ONE), 60, 10, true);
        checkNode(vlGraph11.getNodes().get(1), Node.NodeType.FEEDER, LOAD_ID, LOAD, Arrays.asList(BUS_11_ID), 20, 30, true);
        checkNode(vlGraph11.getNodes().get(2), Node.NodeType.FEEDER, TRANSFORMER_ID + "_" + TwoSides.ONE, TWO_WINDINGS_TRANSFORMER_LEG, Arrays.asList(BUS_11_ID), 100, 30, false);

        VoltageLevelGraph vlGraph12 = graph.getSubstationGraph(SUBSTATION_1_ID).getVoltageLevel(VOLTAGE_LEVEL_12_ID);
        assertEquals(3, vlGraph12.getNodes().size());
        assertEquals(2, vlGraph12.getEdges().size());
        checkNode(vlGraph12.getNodes().get(0), Node.NodeType.BUS, BUS_12_ID, BUSBAR_SECTION, Arrays.asList(LINE_ID + "_" + TwoSides.ONE, TRANSFORMER_ID + "_" + TwoSides.TWO), 140, 10, true);
        checkNode(vlGraph12.getNodes().get(1), Node.NodeType.FEEDER, TRANSFORMER_ID + "_" + TwoSides.TWO, TWO_WINDINGS_TRANSFORMER_LEG, Arrays.asList(BUS_12_ID), 100, 30, false);
        checkNode(vlGraph12.getNodes().get(2), Node.NodeType.FEEDER, LINE_ID + "_" + TwoSides.ONE, LINE, Arrays.asList(BUS_12_ID), 180, 30, true);

        VoltageLevelGraph vlGraph21 = graph.getSubstationGraph(SUBSTATION_2_ID).getVoltageLevel(VOLTAGE_LEVEL_21_ID);
        assertEquals(3, vlGraph21.getNodes().size());
        assertEquals(2, vlGraph21.getEdges().size());
        checkNode(vlGraph21.getNodes().get(0), Node.NodeType.BUS, BUS_21_ID, BUSBAR_SECTION, Arrays.asList(LINE_ID + "_" + TwoSides.TWO, GENERATOR_ID), 260, 90, true);
        checkNode(vlGraph21.getNodes().get(1), Node.NodeType.FEEDER, GENERATOR_ID, GENERATOR, Arrays.asList(BUS_21_ID), 300, 110, false);
        checkNode(vlGraph21.getNodes().get(2), Node.NodeType.FEEDER, LINE_ID + "_" + TwoSides.TWO, LINE, Arrays.asList(BUS_21_ID), 220, 110, true);

        assertEquals(1, graph.getLineEdges().size());
        BranchEdge linEdge = graph.getLineEdges().get(0);
        assertEquals(LINE_ID, linEdge.getId());
        assertEquals(LINE_ID + "_" + TwoSides.ONE, linEdge.getNode1().getId());
        assertEquals(LINE_ID + "_" + TwoSides.TWO, linEdge.getNode2().getId());
        List<Point> points = linEdge.getSnakeLine();
        assertEquals(4, points.size());
        checkLinePointCoordinates(points.get(0), 180, 30);
        checkLinePointCoordinates(points.get(1), 200, 30);
        checkLinePointCoordinates(points.get(2), 200, 110);
        checkLinePointCoordinates(points.get(3), 220, 110);
    }

    private void checkNode(Node node, Node.NodeType type, String id, String componentType,
                           List<String> expectedAdjacentNodes, double x, double y, boolean rotated) {
        assertEquals(type, node.getType());
        assertEquals(id, node.getId());
        assertEquals(componentType, node.getComponentType());
        assertEquals(expectedAdjacentNodes.size(), node.getAdjacentNodes().size());
        checkAdjacentNodes(node, expectedAdjacentNodes);
        checkNodeCoordinates(node, x, y, rotated);
    }

    private void checkAdjacentNodes(Node node, List<String> expectedAdjacentNodes) {
        node.getAdjacentNodes().forEach(adjacentNode -> {
            assertTrue(expectedAdjacentNodes.contains(adjacentNode.getId()));
        });
    }

    private void checkNodeCoordinates(Node node, double x, double y, boolean rotated) {
        assertEquals(x, node.getX(), 0);
        assertEquals(y, node.getY(), 0);
        if (node instanceof BusNode) {
            assertEquals(rotated ? Orientation.UP : Orientation.RIGHT, node.getOrientation());
        } else {
            assertEquals(rotated ? Orientation.RIGHT : Orientation.UP, node.getOrientation());
        }
    }

    private void checkLinePointCoordinates(Point point, int x, int y) {
        assertEquals(x, point.getX(), 0);
        assertEquals(y, point.getY(), 0);
    }

}