AbstractTieLineTest.java

/**
 * Copyright (c) 2023, 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.tck;

import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.test.EurostagTutorialExample1Factory;
import com.powsybl.iidm.network.test.FourSubstationsNodeBreakerFactory;
import com.powsybl.iidm.network.test.NoEquipmentNetworkFactory;
import com.powsybl.iidm.network.util.SV;
import com.powsybl.iidm.network.util.SwitchPredicates;
import com.powsybl.iidm.network.util.TieLineUtil;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.Optional;

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

/**
 * @author Florian Dupuy {@literal <florian.dupuy at rte-france.com>}
 */
public abstract class AbstractTieLineTest {

    private static final String DANGLING1_NAME = "dl1_name";

    private static final String INVALID = "invalid";

    private static final String TO_REMOVE = "toRemove";

    private static final String DUPLICATE = "duplicate";

    private Network network;
    private VoltageLevel voltageLevelA;
    private VoltageLevel voltageLevelB;

    @BeforeEach
    public void setUp() {
        network = NoEquipmentNetworkFactory.create();
        voltageLevelA = network.getVoltageLevel("vl1");
        voltageLevelB = network.getVoltageLevel("vl2");
    }

    @Test
    public void testTieLineAdder() {
        double tol = 0.0000001;

        double r = 10.0;
        double r2 = 1.0;
        double x = 20.0;
        double x2 = 2.0;
        double hl1g1 = 0.03;
        double hl1g2 = 0.035;
        double hl1b1 = 0.04;
        double hl1b2 = 0.045;
        double hl2g1 = 0.013;
        double hl2g2 = 0.0135;
        double hl2b1 = 0.014;
        double hl2b2 = 0.0145;

        // adder
        DanglingLine dl1 = voltageLevelA.newDanglingLine()
                .setBus("busA")
                .setId("hl1")
                .setEnsureIdUnicity(true)
                .setName(DANGLING1_NAME)
                .setP0(0.0)
                .setQ0(0.0)
                .setR(r)
                .setX(x)
                .setB(hl1b1 + hl1b2)
                .setG(hl1g1 + hl1g2)
                .setPairingKey("ucte")
                .add();
        DanglingLine dl2 = voltageLevelB.newDanglingLine()
                .setBus("busB")
                .setId("hl2")
                .setEnsureIdUnicity(true)
                .setP0(0.0)
                .setQ0(0.0)
                .setR(r2)
                .setX(x2)
                .setB(hl2b1 + hl2b2)
                .setG(hl2g1 + hl2g2)
                .add();

        assertEquals(List.of(dl1, dl2), network.getDanglingLines(DanglingLineFilter.UNPAIRED));
        assertFalse(network.getDanglingLines(DanglingLineFilter.PAIRED).iterator().hasNext());
        assertEquals(List.of(dl1, dl2), network.getDanglingLines());

        // test paired dangling line retrieval - For unpaired dangling lines
        assertFalse(TieLineUtil.getPairedDanglingLine(dl1).isPresent());
        assertFalse(TieLineUtil.getPairedDanglingLine(dl2).isPresent());

        TieLineAdder adder = network.newTieLine().setId("testTie")
                .setName("testNameTie")
                .setDanglingLine1(dl1.getId())
                .setDanglingLine2(dl2.getId());
        TieLine tieLine = adder.add();

        assertEquals(List.of(dl1, dl2), network.getDanglingLines(DanglingLineFilter.PAIRED));
        assertFalse(network.getDanglingLines(DanglingLineFilter.UNPAIRED).iterator().hasNext());

        assertEquals(IdentifiableType.TIE_LINE, tieLine.getType());
        assertEquals("ucte", tieLine.getPairingKey());
        assertEquals("hl1", tieLine.getDanglingLine1().getId());
        assertEquals(DANGLING1_NAME, tieLine.getDanglingLine1().getOptionalName().orElse(null));
        assertEquals("hl2", tieLine.getDanglingLine2().getId());
        assertEquals("hl1", tieLine.getDanglingLine(voltageLevelA.getId()).getId());
        assertEquals("hl2", tieLine.getDanglingLine(voltageLevelB.getId()).getId());
        assertNull(tieLine.getDanglingLine("UnknownVoltageLevelId"));
        assertEquals(11.0, tieLine.getR(), tol);
        assertEquals(22.0, tieLine.getX(), tol);
        assertEquals(0.065, tieLine.getG1(), tol);
        assertEquals(0.02649999999, tieLine.getG2(), tol);
        assertEquals(0.08499999999, tieLine.getB1(), tol);
        assertEquals(0.0285, tieLine.getB2(), tol);

        DanglingLine danglingLine1 = tieLine.getDanglingLine1();
        DanglingLine danglingLine2 = tieLine.getDanglingLine2();

        // Check notification on DanglingLine changes
        NetworkListener mockedListener = mock(DefaultNetworkListener.class);
        // Add observer changes to current network
        network.addListener(mockedListener);
        // Apply changes on dangling lines
        danglingLine1.setR(r + 1);
        danglingLine1.setX(x + 1);
        danglingLine1.setG(hl1g1 + hl1g2 + 2);
        danglingLine1.setB(hl1b1 + hl1b2 + 2);
        danglingLine2.setR(r + 1);
        danglingLine2.setX(x + 1);
        danglingLine2.setG(hl2g1 + hl1g2 + 2);
        danglingLine2.setB(hl2b1 + hl2b2 + 2);
        verify(mockedListener, times(8)).onUpdate(any(DanglingLine.class), anyString(), nullable(String.class), any(), any());
        // Remove observer
        network.removeListener(mockedListener);
        // Cancel changes on dangling lines
        danglingLine1.setR(r);
        danglingLine1.setX(x);
        danglingLine1.setG(hl1g1 + hl1g2);
        danglingLine1.setB(hl1b1 + hl1b2);
        danglingLine2.setR(r);
        danglingLine2.setX(x);
        danglingLine2.setG(hl2g1 + hl2g2);
        danglingLine2.setB(hl2b1 + hl2b2);
        // Check no notification
        verifyNoMoreInteractions(mockedListener);

        // Reuse adder
        adder.setId("testTie2");
        ValidationException e = assertThrows(ValidationException.class, adder::add);
        assertTrue(e.getMessage().contains("already has a tie line"));

        // Update power flows, voltages and angles
        double p1 = -605.0;
        double q1 = -302.5;
        double p2 = 600.0;
        double q2 = 300.0;
        double v1 = 420.0;
        double v2 = 380.0;
        double angle1 = -1e-4;
        double angle2 = -1.7e-3;
        danglingLine1.getTerminal().setP(p1).setQ(q1).getBusView().getBus().setV(v1).setAngle(angle1);
        danglingLine2.getTerminal().setP(p2).setQ(q2).getBusView().getBus().setV(v2).setAngle(angle2);

        // test boundaries values
        SV expectedSV1 = new SV(p1, q1, v1, angle1, TwoSides.ONE);
        SV expectedSV2 = new SV(p2, q2, v2, angle2, TwoSides.ONE);
        assertEquals(expectedSV1.otherSideP(danglingLine1, false), danglingLine1.getBoundary().getP(), 0.0d);
        assertEquals(expectedSV1.otherSideQ(danglingLine1, false), danglingLine1.getBoundary().getQ(), 0.0d);
        assertEquals(expectedSV2.otherSideP(danglingLine2, false), danglingLine2.getBoundary().getP(), 0.0d);
        assertEquals(expectedSV2.otherSideQ(danglingLine2, false), danglingLine2.getBoundary().getQ(), 0.0d);
        assertEquals(expectedSV1.otherSideU(danglingLine1, false), danglingLine1.getBoundary().getV(), 0.0d);
        assertEquals(expectedSV1.otherSideA(danglingLine1, false), danglingLine1.getBoundary().getAngle(), 0.0d);
        assertEquals(expectedSV2.otherSideU(danglingLine2, false), danglingLine2.getBoundary().getV(), 0.0d);
        assertEquals(expectedSV2.otherSideA(danglingLine2, false), danglingLine2.getBoundary().getAngle(), 0.0d);

        // test paired dangling line retrieval - For paired dangling lines
        Optional<DanglingLine> otherSide1 = TieLineUtil.getPairedDanglingLine(danglingLine1);
        assertTrue(otherSide1.isPresent());
        assertEquals(danglingLine2, otherSide1.orElseThrow());
        Optional<DanglingLine> otherSide2 = TieLineUtil.getPairedDanglingLine(danglingLine2);
        assertTrue(otherSide2.isPresent());
        assertEquals(danglingLine1, otherSide2.orElseThrow());

        // try to change pairing key, but not allowed.
        assertThrows(ValidationException.class, () -> danglingLine1.setPairingKey("new_code"),
                "Dangling line 'hl1': pairing key cannot be set if dangling line is paired.");
    }

    @Test
    public void danglingLine1NotSet() {
        // adder
        TieLineAdder tieLineAdder = network.newTieLine()
                .setId("testTie")
                .setName("testNameTie");
        ValidationException e = assertThrows(ValidationException.class, tieLineAdder::add);
        assertTrue(e.getMessage().contains("undefined dangling line"));
    }

    @Test
    public void danglingLine2NotSet() {
        // adder
        DanglingLine dl1 = voltageLevelA.newDanglingLine()
                .setBus("busA")
                .setId("hl1")
                .setName(DANGLING1_NAME)
                .setR(10.0)
                .setX(20.0)
                .setB(80.0)
                .setG(65.0)
                .setP0(0.0)
                .setQ0(0.0)
                .setPairingKey("ucte")
                .add();
        // adder
        TieLineAdder tieLineAdder = network.newTieLine()
                .setId("testTie")
                .setName("testNameTie")
                .setDanglingLine1(dl1.getId());
        ValidationException e = assertThrows(ValidationException.class, tieLineAdder::add);
        assertTrue(e.getMessage().contains("undefined dangling line"));
    }

    @Test
    public void invalidDanglingLineCharacteristicsR() {
        ValidationException e = assertThrows(ValidationException.class, () -> createTieLineWithDanglingline2ByDefault(INVALID, INVALID, INVALID, Double.NaN, 2.0,
                6.5, 8.5, "code"));
        assertTrue(e.getMessage().contains("r is invalid"));
    }

    @Test
    public void invalidDanglingLineCharacteristicsX() {
        ValidationException e = assertThrows(ValidationException.class, () -> createTieLineWithDanglingline2ByDefault(INVALID, INVALID, INVALID, 1.0, Double.NaN,
                6.5, 8.5, "code"));
        assertTrue(e.getMessage().contains("x is invalid"));
    }

    @Test
    public void invalidDanglingLineCharacteristicsG() {
        ValidationException e = assertThrows(ValidationException.class, () -> createTieLineWithDanglingline2ByDefault(INVALID, INVALID, INVALID, 1.0, 2.0,
                Double.NaN, 8.5, "code"));
        assertTrue(e.getMessage().contains("g is invalid"));
    }

    @Test
    public void invalidDanglingLineCharacteristicsB() {
        ValidationException e = assertThrows(ValidationException.class, () -> createTieLineWithDanglingline2ByDefault(INVALID, INVALID, INVALID, 1.0, 2.0,
                6.5, Double.NaN, "code"));
        assertTrue(e.getMessage().contains("b is invalid"));
    }

    @Test
    public void danglingLineIdNull() {
        PowsyblException e = assertThrows(PowsyblException.class, () -> createTieLineWithDanglingline2ByDefault(INVALID, INVALID, null, 1.0, 2.0,
                6.5, 8.5, "code"));
        assertTrue(e.getMessage().contains("Dangling line id is not set"));
    }

    @Test
    public void danglingLineIdEmpty() {
        PowsyblException e = assertThrows(PowsyblException.class, () -> createTieLineWithDanglingline2ByDefault(INVALID, INVALID, "", 1.0, 2.0,
                6.5, 8.5, "code"));
        assertTrue(e.getMessage().contains("Invalid id ''"));
    }

    @Test
    public void duplicate() {
        createTieLineWithDanglingline2ByDefault(DUPLICATE, DUPLICATE, "id1", 1.0, 2.0,
                6.5, 8.5, DUPLICATE);
        assertThrows(PowsyblException.class, () -> createTieLineWithDanglingline2ByDefault(DUPLICATE, DUPLICATE, "id1", 1.0, 2.0,
                6.5, 8.5, DUPLICATE));
    }

    @Test
    public void testRemove() {
        createTieLineWithDanglingline2ByDefault(TO_REMOVE, TO_REMOVE, "id1", 1.0, 2.0,
                6.5, 8.5, TO_REMOVE);
        TieLine line = network.getTieLine(TO_REMOVE);
        assertNotNull(line);
        int count = network.getTieLineCount();
        line.remove();
        assertNull(network.getLine(TO_REMOVE));
        assertNotNull(line);
        assertEquals(count - 1L, network.getTieLineCount());
    }

    @Test
    public void testRemoveUpdateDanglingLines() {
        Network eurostagNetwork = EurostagTutorialExample1Factory.createWithTieLine();
        TieLine line1 = eurostagNetwork.getTieLine("NHV1_NHV2_1");
        TieLine line2 = eurostagNetwork.getTieLine("NHV1_NHV2_2");
        assertNotNull(line1);
        assertNotNull(line2);
        assertEquals(0.0, line1.getDanglingLine1().getP0());
        assertEquals(0.0, line1.getDanglingLine1().getQ0());
        assertEquals(0.0, line1.getDanglingLine2().getP0());
        assertEquals(0.0, line1.getDanglingLine2().getQ0());
        assertEquals(0.0, line2.getDanglingLine1().getP0());
        assertEquals(0.0, line2.getDanglingLine1().getQ0());
        assertEquals(0.0, line2.getDanglingLine2().getP0());
        assertEquals(0.0, line2.getDanglingLine2().getQ0());
        line1.remove(true);
        line2.remove(true);
        assertEquals(301.278, line1.getDanglingLine1().getP0(), 0.001);
        assertEquals(116.563, line1.getDanglingLine1().getQ0(), 0.001);
        assertEquals(-301.745, line1.getDanglingLine2().getP0(), 0.001);
        assertEquals(-116.566, line1.getDanglingLine2().getQ0(), 0.001);
        assertEquals(301.278, line2.getDanglingLine1().getP0(), 0.001);
        assertEquals(116.563, line2.getDanglingLine1().getQ0(), 0.001);
        assertEquals(-301.745, line2.getDanglingLine2().getP0(), 0.001);
        assertEquals(-116.567, line2.getDanglingLine2().getQ0(), 0.001);
    }

    @Test
    public void testRemoveUpdateDanglingLinesNotCalculated() {
        Network eurostagNetwork = EurostagTutorialExample1Factory.createWithTieLine();
        TieLine line1 = eurostagNetwork.getTieLine("NHV1_NHV2_1");
        TieLine line2 = eurostagNetwork.getTieLine("NHV1_NHV2_2");
        assertNotNull(line1);
        assertNotNull(line2);
        assertEquals(0.0, line1.getDanglingLine1().getP0());
        assertEquals(0.0, line1.getDanglingLine1().getQ0());
        assertEquals(0.0, line1.getDanglingLine2().getP0());
        assertEquals(0.0, line1.getDanglingLine2().getQ0());
        assertEquals(0.0, line2.getDanglingLine1().getP0());
        assertEquals(0.0, line2.getDanglingLine1().getQ0());
        assertEquals(0.0, line2.getDanglingLine2().getP0());
        assertEquals(0.0, line2.getDanglingLine2().getQ0());
        // reset the terminal flows at dangling lines, we simulate we do not have calculated
        line1.getDanglingLine1().getTerminal().setP(Double.NaN);
        line1.getDanglingLine1().getTerminal().setQ(Double.NaN);
        line1.getDanglingLine2().getTerminal().setP(Double.NaN);
        line1.getDanglingLine2().getTerminal().setQ(Double.NaN);
        line2.getDanglingLine1().getTerminal().setP(Double.NaN);
        line2.getDanglingLine1().getTerminal().setQ(Double.NaN);
        line2.getDanglingLine2().getTerminal().setP(Double.NaN);
        line2.getDanglingLine2().getTerminal().setQ(Double.NaN);
        // Set some non-zero p0, q0 values to check that:
        // if we remove the tie line without flows calculated
        // p0, q0 of dangling lines are preserved
        line1.getDanglingLine1().setP0(10);
        line1.getDanglingLine1().setQ0(20);
        line1.getDanglingLine2().setP0(-10);
        line1.getDanglingLine2().setQ0(-20);
        line1.remove(true);
        line2.remove(true);
        assertEquals(10, line1.getDanglingLine1().getP0(), 0.001);
        assertEquals(20, line1.getDanglingLine1().getQ0(), 0.001);
        assertEquals(-10, line1.getDanglingLine2().getP0(), 0.001);
        assertEquals(-20, line1.getDanglingLine2().getQ0(), 0.001);
        assertEquals(0, line2.getDanglingLine1().getP0(), 0.001);
        assertEquals(0, line2.getDanglingLine1().getQ0(), 0.001);
        assertEquals(0, line2.getDanglingLine2().getP0(), 0.001);
        assertEquals(0, line2.getDanglingLine2().getQ0(), 0.001);
    }

    @Test
    public void testRemoveUpdateDanglingLinesDcCalculated() {
        Network eurostagNetwork = EurostagTutorialExample1Factory.createWithTieLine();
        TieLine line1 = eurostagNetwork.getTieLine("NHV1_NHV2_1");
        TieLine line2 = eurostagNetwork.getTieLine("NHV1_NHV2_2");
        assertNotNull(line1);
        assertNotNull(line2);
        assertEquals(0.0, line1.getDanglingLine1().getP0());
        assertEquals(0.0, line1.getDanglingLine1().getQ0());
        assertEquals(0.0, line1.getDanglingLine2().getP0());
        assertEquals(0.0, line1.getDanglingLine2().getQ0());
        assertEquals(0.0, line2.getDanglingLine1().getP0());
        assertEquals(0.0, line2.getDanglingLine1().getQ0());
        assertEquals(0.0, line2.getDanglingLine2().getP0());
        assertEquals(0.0, line2.getDanglingLine2().getQ0());
        // reset only the terminal q values (simulate only a dc load flow has been calculated)
        line1.getDanglingLine1().getTerminal().setQ(Double.NaN);
        line1.getDanglingLine2().getTerminal().setQ(Double.NaN);
        line2.getDanglingLine1().getTerminal().setQ(Double.NaN);
        line2.getDanglingLine2().getTerminal().setQ(Double.NaN);
        // Set some non-zero p0, q0 values to check that:
        // if we remove the tie line with only p flows calculated
        // q0 values of dangling lines are preserved
        line1.getDanglingLine1().setP0(10);
        line1.getDanglingLine1().setQ0(20);
        line1.getDanglingLine2().setP0(-10);
        line1.getDanglingLine2().setQ0(-20);
        line1.remove(true);
        line2.remove(true);
        assertEquals(302.444, line1.getDanglingLine1().getP0(), 0.001);
        assertEquals(20, line1.getDanglingLine1().getQ0(), 0.001);
        assertEquals(-300.434, line1.getDanglingLine2().getP0(), 0.001);
        assertEquals(-20, line1.getDanglingLine2().getQ0(), 0.001);
        assertEquals(302.444, line2.getDanglingLine1().getP0(), 0.001);
        assertEquals(0, line2.getDanglingLine1().getQ0(), 0.001);
        assertEquals(-300.434, line2.getDanglingLine2().getP0(), 0.001);
        assertEquals(0, line2.getDanglingLine2().getQ0(), 0.001);
    }

    private void createTieLineWithDanglingline2ByDefault(String id, String name, String danglingLineId, double r, double x,
                                                         double g, double b, String code) {
        DanglingLine dl1 = voltageLevelA.newDanglingLine()
                .setBus("busA")
                .setId(danglingLineId)
                .setName(DANGLING1_NAME)
                .setR(r)
                .setX(x)
                .setB(b)
                .setG(g)
                .setP0(0)
                .setQ0(0)
                .add();
        DanglingLine dl2 = voltageLevelB.newDanglingLine()
                .setBus("busB")
                .setId("hl2")
                .setName("half2_name")
                .setR(1.0)
                .setX(2.0)
                .setB(6.5)
                .setG(8.5)
                .setP0(0)
                .setQ0(0)
                .setPairingKey(code)
                .add();
        network.newTieLine()
                .setId(id)
                .setEnsureIdUnicity(true)
                .setName(name)
                .setDanglingLine1(dl1.getId())
                .setDanglingLine2(dl2.getId())
                .add();
    }

    @Test
    void testConnectDisconnect() {
        Network networkWithTieLine = createNetworkWithTieLine();
        TieLine tieLine = networkWithTieLine.getTieLine("TL");

        // Check that the tie line is connected
        assertTieLineConnection(tieLine, true, true);

        // Connection fails since it's already connected
        assertFalse(tieLine.connectDanglingLines());

        // Disconnection fails if switches cannot be opened (here, only fictional switches could be opened)
        assertFalse(tieLine.disconnectDanglingLines(SwitchPredicates.IS_NONFICTIONAL.negate().and(SwitchPredicates.IS_OPEN.negate())));

        // Disconnection
        assertTrue(tieLine.disconnectDanglingLines());
        assertTieLineConnection(tieLine, false, false);

        // Disconnection fails since it's already disconnected
        assertFalse(tieLine.disconnectDanglingLines());

        // Connection fails if switches cannot be opened (here, only fictional switches could be closed)
        assertFalse(tieLine.connectDanglingLines(SwitchPredicates.IS_NONFICTIONAL.negate()));

        // Connection
        assertTrue(tieLine.connectDanglingLines());
        assertTieLineConnection(tieLine, true, true);

        // Disconnect one side
        assertTrue(tieLine.disconnectDanglingLines(SwitchPredicates.IS_CLOSED_BREAKER, TwoSides.ONE));
        assertTieLineConnection(tieLine, false, true);

        // Connection on the other side fails since it's still connected
        assertFalse(tieLine.connectDanglingLines(SwitchPredicates.IS_NONFICTIONAL_BREAKER, TwoSides.TWO));
    }

    private void assertTieLineConnection(TieLine tieLine, boolean expectedConnectionOnSide1, boolean expectedConnectionOnSide2) {
        assertEquals(expectedConnectionOnSide1, tieLine.getDanglingLine1().getTerminal().isConnected());
        assertEquals(expectedConnectionOnSide2, tieLine.getDanglingLine2().getTerminal().isConnected());
    }

    private Network createNetworkWithTieLine() {
        // Initialize the network
        Network networkWithTieLine = FourSubstationsNodeBreakerFactory.create();

        // Existing voltage levels in Node-breaker view
        VoltageLevel s1vl1 = networkWithTieLine.getVoltageLevel("S1VL1");

        // New voltage levels in bus-breaker view
        VoltageLevel s2vl2 = networkWithTieLine.getSubstation("S2").newVoltageLevel()
            .setId("S2VL2")
            .setNominalV(1.0)
            .setTopologyKind(TopologyKind.BUS_BREAKER)
            .add();

        // New buses
        s2vl2.getBusBreakerView()
            .newBus()
            .setId("bus22")
            .add();

        /*
         * First Tie line on node-breaker
         */
        // Add a dangling line in the first Voltage level
        createSwitch(s1vl1, "S1VL1_DL_DISCONNECTOR", SwitchKind.DISCONNECTOR, false, 0, 20);
        createSwitch(s1vl1, "S1VL1_DL_BREAKER", SwitchKind.BREAKER, false, 20, 21);
        DanglingLine danglingLine1 = s1vl1.newDanglingLine()
            .setId("NHV1_XNODE1")
            .setP0(0.0)
            .setQ0(0.0)
            .setR(1.5)
            .setX(20.0)
            .setG(1E-6)
            .setB(386E-6 / 2)
            .setNode(21)
            .setPairingKey("XNODE1")
            .add();

        // Add a dangling line in the second Voltage level
        DanglingLine danglingLine2 = s2vl2.newDanglingLine()
            .setId("S2VL2_DL")
            .setP0(0.0)
            .setQ0(0.0)
            .setR(1.5)
            .setX(13.0)
            .setG(2E-6)
            .setB(386E-6 / 2)
            .setBus("bus22")
            .setPairingKey("XNODE1")
            .add();
        networkWithTieLine.newTieLine()
            .setId("TL")
            .setDanglingLine1(danglingLine1.getId())
            .setDanglingLine2(danglingLine2.getId())
            .add();

        return networkWithTieLine;
    }

    private static void createSwitch(VoltageLevel vl, String id, SwitchKind kind, boolean open, int node1, int node2) {
        vl.getNodeBreakerView().newSwitch()
            .setId(id)
            .setName(id)
            .setKind(kind)
            .setRetained(kind.equals(SwitchKind.BREAKER))
            .setOpen(open)
            .setFictitious(false)
            .setNode1(node1)
            .setNode2(node2)
            .add();
    }
}