ApplyActionToNetworkTest.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.action;
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.report.ReportNode;
import com.powsybl.computation.ComputationManager;
import com.powsybl.computation.local.LocalComputationManager;
import com.powsybl.iidm.modification.NetworkModification;
import com.powsybl.iidm.modification.topology.DefaultNamingStrategy;
import com.powsybl.iidm.modification.topology.NamingStrategy;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.HvdcAngleDroopActivePowerControl;
import com.powsybl.iidm.network.extensions.HvdcAngleDroopActivePowerControlAdder;
import com.powsybl.iidm.network.test.*;
import org.junit.jupiter.api.Test;
import static com.powsybl.action.PercentChangeLoadAction.QModificationStrategy.CONSTANT_PQ_RATIO;
import static com.powsybl.action.PercentChangeLoadAction.QModificationStrategy.CONSTANT_Q;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Pauline JEAN-MARIE {@literal <pauline.jean-marie at artelys.com>}
*/
class ApplyActionToNetworkTest {
@Test
void switchAction() {
Network network = TwoVoltageLevelNetworkFactory.create();
Switch sw = network.getSwitch("BR_LOAD");
assertFalse(sw.isOpen());
SwitchAction action = new SwitchAction("id", "BR_LOAD", true);
action.toModification().apply(network);
assertTrue(sw.isOpen());
assertTrue(sw.isOpen());
SwitchAction action2 = new SwitchAction("id", "BR_LOAD", false);
action2.toModification().apply(network);
assertFalse(sw.isOpen());
}
@Test
void terminalConnectionAction() {
Network network = EurostagTutorialExample1Factory.create();
Connectable<?> connectable = network.getConnectable("NHV1_NHV2_2");
assertTrue(connectable.getTerminals().stream().allMatch(Terminal::isConnected));
TerminalsConnectionAction action = new TerminalsConnectionAction("id", "NHV1_NHV2_2", true);
action.toModification().apply(network);
assertTrue(connectable.getTerminals().stream().noneMatch(Terminal::isConnected));
Branch<?> branch = network.getBranch("NHV1_NHV2_2");
assertFalse(branch.getTerminal(TwoSides.TWO).isConnected());
assertFalse(branch.getTerminal(TwoSides.ONE).isConnected());
TerminalsConnectionAction action2 = new TerminalsConnectionAction("id", "NHV1_NHV2_2", ThreeSides.TWO, false);
action2.toModification().apply(network);
assertTrue(branch.getTerminal(TwoSides.TWO).isConnected());
assertFalse(branch.getTerminal(TwoSides.ONE).isConnected());
}
@Test
void terminalConnectionActionOnTieLine() {
Network network = EurostagTutorialExample1Factory.createWithTieLine();
TieLine tieLine = network.getTieLine("NHV1_NHV2_1");
// Disconnection
TerminalsConnectionAction disconnectionAction = new TerminalsConnectionAction("id", "NHV1_NHV2_1", true);
NetworkModification disconnection = disconnectionAction.toModification();
NamingStrategy namingStrategy = new DefaultNamingStrategy();
ComputationManager computationManager = LocalComputationManager.getDefault();
assertTrue(tieLine.getDanglingLine1().getTerminal().isConnected());
assertTrue(tieLine.getDanglingLine2().getTerminal().isConnected());
disconnection.apply(network, namingStrategy, true, computationManager, ReportNode.NO_OP);
assertFalse(tieLine.getDanglingLine1().getTerminal().isConnected());
assertFalse(tieLine.getDanglingLine2().getTerminal().isConnected());
// Connection
TerminalsConnectionAction connectionAction = new TerminalsConnectionAction("id", "NHV1_NHV2_1", false);
NetworkModification connection = connectionAction.toModification();
connection.apply(network, namingStrategy, true, computationManager, ReportNode.NO_OP);
assertTrue(tieLine.getDanglingLine1().getTerminal().isConnected());
assertTrue(tieLine.getDanglingLine2().getTerminal().isConnected());
}
@Test
void dangingLineAction() {
Network network = EurostagTutorialExample1Factory.createWithTieLine();
DanglingLine danglingLine = network.getDanglingLine("NHV1_XNODE1");
danglingLine.setP0(10.0);
danglingLine.setQ0(4.0);
assertEquals(10.0, danglingLine.getP0());
DanglingLineAction action = new DanglingLineActionBuilder().withId("id")
.withDanglingLineId("NHV1_XNODE1")
.withRelativeValue(false)
.withActivePowerValue(5.0)
.build();
action.toModification().apply(network);
assertEquals(5.0, danglingLine.getP0());
assertEquals(4.0, danglingLine.getQ0());
DanglingLineAction action2 = new DanglingLineActionBuilder().withId("id")
.withDanglingLineId("NHV1_XNODE1")
.withRelativeValue(true)
.withReactivePowerValue(2.0)
.build();
action2.toModification().apply(network);
assertEquals(6.0, danglingLine.getQ0());
}
@Test
void loadAction() {
Network network = EurostagTutorialExample1Factory.create();
Load load = network.getLoad("LOAD");
assertEquals(200.0, load.getQ0());
LoadAction action = new LoadActionBuilder().withId("id")
.withLoadId("LOAD")
.withRelativeValue(false)
.withReactivePowerValue(100.0)
.build();
action.toModification().apply(network);
assertEquals(100.0, load.getQ0());
assertEquals(600.0, load.getP0());
LoadAction action2 = new LoadActionBuilder().withId("id")
.withLoadId("LOAD")
.withRelativeValue(true)
.withActivePowerValue(-20.0)
.build();
action2.toModification().apply(network);
assertEquals(580.0, load.getP0());
}
@Test
void pctLoadActionShouldNotModifyQ0WhenConstantQ() {
Network network = EurostagTutorialExample1Factory.create();
Load load = network.getLoad("LOAD");
assertEquals(600.0, load.getP0());
assertEquals(200.0, load.getQ0());
PercentChangeLoadAction action = (PercentChangeLoadAction) new PercentChangeLoadActionBuilder()
.withId("id").withLoadId("LOAD").withP0PercentChange(-10d).withQModificationStrategy(CONSTANT_Q).build();
action.toModification().apply(network);
assertEquals(540.0, load.getP0());
assertEquals(200.0, load.getQ0());
}
@Test
void pctLoadActionShouldPreservePQRatioWhenConstantPQRatio() {
Network network = EurostagTutorialExample1Factory.create();
Load load = network.getLoad("LOAD");
assertEquals(600.0, load.getP0());
assertEquals(200.0, load.getQ0());
PercentChangeLoadAction action = (PercentChangeLoadAction) new PercentChangeLoadActionBuilder()
.withId("id").withLoadId("LOAD").withP0PercentChange(-10d).withQModificationStrategy(CONSTANT_PQ_RATIO).build();
action.toModification().apply(network);
assertEquals(540.0, load.getP0());
assertEquals(180.0, load.getQ0());
}
@Test
void shuntCompensatorAction() {
Network network = EurostagTutorialExample1Factory.createWithMultipleConnectedComponents();
ShuntCompensator shuntCompensator = network.getShuntCompensator("SHUNT");
assertEquals(1, shuntCompensator.getSectionCount());
ShuntCompensatorPositionAction action = new ShuntCompensatorPositionActionBuilder().withId("id")
.withShuntCompensatorId("SHUNT")
.withSectionCount(0)
.build();
action.toModification().apply(network);
assertEquals(0, shuntCompensator.getSectionCount());
assertEquals(0, shuntCompensator.getSectionCount());
assertEquals(1, shuntCompensator.getMaximumSectionCount());
ShuntCompensatorPositionAction action2 = new ShuntCompensatorPositionActionBuilder().withId("id")
.withShuntCompensatorId("SHUNT")
.withSectionCount(2)
.build();
NetworkModification modif = action2.toModification();
PowsyblException e = assertThrows(PowsyblException.class, () -> modif.apply(network, true, ReportNode.NO_OP));
assertEquals("Shunt compensator 'SHUNT': the current number (2) of section should be lesser than the maximum number of section (1)", e.getMessage());
assertDoesNotThrow(() -> modif.apply(network));
}
@Test
void phaseTapChangerTapPositionAction() {
Network network = PhaseShifterTestCaseFactory.create();
TwoWindingsTransformer twoWT = network.getTwoWindingsTransformer("PS1");
assertEquals(1, twoWT.getPhaseTapChanger().getTapPosition());
PhaseTapChangerTapPositionAction action = new PhaseTapChangerTapPositionAction("id", "PS1", false, 2);
action.toModification().apply(network);
assertEquals(2, twoWT.getPhaseTapChanger().getTapPosition());
assertEquals(2, twoWT.getPhaseTapChanger().getTapPosition());
PhaseTapChangerTapPositionAction action2 = new PhaseTapChangerTapPositionAction("id", "PS1", false, 3);
NetworkModification modif = action2.toModification();
PowsyblException e = assertThrows(PowsyblException.class, () -> modif.apply(network, true, ReportNode.NO_OP));
assertEquals("2 windings transformer 'PS1': incorrect tap position 3 [0, 2]", e.getMessage());
Network network2 = ThreeWindingsTransformerNetworkFactory.create();
ThreeWindingsTransformer.Leg threeWTLeg = network2.getThreeWindingsTransformer("3WT").getLeg(ThreeSides.THREE);
addPhaseTapChanger(threeWTLeg);
assertEquals(0, threeWTLeg.getPhaseTapChanger().getTapPosition());
PhaseTapChangerTapPositionAction action3 = new PhaseTapChangerTapPositionAction("id", "3WT", false, 1, ThreeSides.THREE);
action3.toModification().apply(network2);
assertEquals(1, threeWTLeg.getPhaseTapChanger().getTapPosition());
}
private static void addPhaseTapChanger(ThreeWindingsTransformer.Leg threeWTLeg) {
threeWTLeg.newPhaseTapChanger()
.setLowTapPosition(0)
.setTapPosition(0)
.beginStep()
.setR(0.01)
.setX(0.0001)
.setB(0)
.setG(0)
.setRho(1.1)
.setAlpha(1)
.endStep()
.beginStep()
.setR(0.02)
.setX(0.0002)
.setB(0)
.setG(0)
.setRho(1.2)
.setAlpha(1.1)
.endStep()
.add();
}
@Test
void generatorAction() {
Network network = EurostagTutorialExample1Factory.create();
Generator generator = network.getGenerator("GEN");
assertEquals(607.0, generator.getTargetP());
GeneratorAction action = new GeneratorActionBuilder()
.withId("id")
.withGeneratorId("GEN")
.withActivePowerRelativeValue(false)
.withActivePowerValue(503.0)
.build();
action.toModification().apply(network);
assertEquals(503.0, generator.getTargetP());
assertEquals(503.0, generator.getTargetP());
GeneratorAction action2 = new GeneratorActionBuilder()
.withId("id")
.withGeneratorId("GEN")
.withActivePowerRelativeValue(true)
.withActivePowerValue(-10)
.build();
action2.toModification().apply(network);
assertEquals(493.0, generator.getTargetP());
}
@Test
void hvdcAction() {
Network network = HvdcTestNetwork.createLcc();
HvdcLine hvdcLine = network.getHvdcLine("L");
hvdcLine.newExtension(HvdcAngleDroopActivePowerControlAdder.class)
.withP0(200.0f)
.withDroop(0.9f)
.withEnabled(true)
.add();
assertEquals(280.0, hvdcLine.getActivePowerSetpoint());
HvdcAction action = new HvdcActionBuilder()
.withId("id")
.withHvdcId("L")
.withActivePowerSetpoint(200.0)
.build();
action.toModification().apply(network);
assertEquals(200.0, hvdcLine.getActivePowerSetpoint());
assertEquals(HvdcLine.ConvertersMode.SIDE_1_INVERTER_SIDE_2_RECTIFIER, hvdcLine.getConvertersMode());
HvdcAction action2 = new HvdcActionBuilder()
.withId("id")
.withHvdcId("L")
.withActivePowerSetpoint(-20.0)
.withRelativeValue(true)
.withConverterMode(HvdcLine.ConvertersMode.SIDE_1_RECTIFIER_SIDE_2_INVERTER)
.build();
action2.toModification().apply(network);
assertEquals(180.0, hvdcLine.getActivePowerSetpoint());
assertEquals(HvdcLine.ConvertersMode.SIDE_1_RECTIFIER_SIDE_2_INVERTER, hvdcLine.getConvertersMode());
HvdcAngleDroopActivePowerControl hvdcLineExt = hvdcLine.getExtension(HvdcAngleDroopActivePowerControl.class);
assertEquals(200.0f, hvdcLineExt.getP0());
assertEquals(0.9f, hvdcLineExt.getDroop());
HvdcAction action3 = new HvdcActionBuilder()
.withId("id")
.withHvdcId("L")
.withP0(100.0)
.withDroop(1.0)
.build();
action3.toModification().apply(network);
assertEquals(100.0f, hvdcLineExt.getP0());
assertEquals(1.0f, hvdcLineExt.getDroop());
assertTrue(hvdcLineExt.isEnabled());
HvdcAction action4 = new HvdcActionBuilder()
.withId("id")
.withHvdcId("L")
.withActivePowerSetpoint(220.0)
.withAcEmulationEnabled(false)
.build();
action4.toModification().apply(network);
assertEquals(220.0, hvdcLine.getActivePowerSetpoint());
assertFalse(hvdcLineExt.isEnabled());
}
}