PstRangeActionImplTest.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/.
*/
package com.powsybl.openrao.data.crac.impl;
import com.powsybl.commons.PowsyblException;
import com.powsybl.openrao.commons.OpenRaoException;
import com.powsybl.openrao.data.crac.api.Crac;
import com.powsybl.openrao.data.crac.api.InstantKind;
import com.powsybl.openrao.data.crac.impl.utils.NetworkImportsUtil;
import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction;
import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeActionAdder;
import com.powsybl.openrao.data.crac.api.range.RangeType;
import com.powsybl.openrao.data.crac.api.usagerule.UsageMethod;
import com.powsybl.iidm.network.Country;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.PhaseTapChanger;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Joris Mancini {@literal <joris.mancini at rte-france.com>}
* @author Baptiste Seguinot {@literal <baptiste.seguinot at rte-france.com>}
*/
class PstRangeActionImplTest {
private static final String PREVENTIVE_INSTANT_ID = "preventive";
private static final String OUTAGE_INSTANT_ID = "outage";
private static final String AUTO_INSTANT_ID = "auto";
private static final String CURATIVE_INSTANT_ID = "curative";
private Crac crac;
private PstRangeActionAdder pstRangeActionAdder;
private String networkElementId;
private Network network;
private PhaseTapChanger phaseTapChanger;
private Map<Integer, Double> tapToAngleConversionMap;
@BeforeEach
public void setUp() {
crac = new CracImplFactory().create("cracId")
.newInstant(PREVENTIVE_INSTANT_ID, InstantKind.PREVENTIVE)
.newInstant(OUTAGE_INSTANT_ID, InstantKind.OUTAGE)
.newInstant(AUTO_INSTANT_ID, InstantKind.AUTO)
.newInstant(CURATIVE_INSTANT_ID, InstantKind.CURATIVE);
network = NetworkImportsUtil.import12NodesNetwork();
networkElementId = "BBE2AA1 BBE3AA1 1";
phaseTapChanger = network.getTwoWindingsTransformer(networkElementId).getPhaseTapChanger();
tapToAngleConversionMap = new HashMap<>();
phaseTapChanger.getAllSteps().forEach((stepInt, step) -> tapToAngleConversionMap.put(stepInt, step.getAlpha()));
pstRangeActionAdder = crac.newPstRangeAction()
.withId("pst-range-action-id")
.withName("pst-range-action-name")
.withNetworkElement("BBE2AA1 BBE3AA1 1")
.withOperator("operator")
.newOnInstantUsageRule().withInstant(PREVENTIVE_INSTANT_ID).withUsageMethod(UsageMethod.AVAILABLE).add()
.withTapToAngleConversionMap(tapToAngleConversionMap)
.withInitialTap(0);
}
@Test
void apply() {
PstRangeAction pstRa = pstRangeActionAdder.add();
assertEquals(0, network.getTwoWindingsTransformer(networkElementId).getPhaseTapChanger().getTapPosition());
assertEquals(0, pstRa.getCurrentTapPosition(network));
pstRa.apply(network, network.getTwoWindingsTransformer(networkElementId).getPhaseTapChanger().getStep(12).getAlpha());
assertEquals(12, network.getTwoWindingsTransformer(networkElementId).getPhaseTapChanger().getTapPosition());
assertEquals(12, pstRa.getCurrentTapPosition(network));
}
@Test
void applyOutOfBound() {
PstRangeAction pstRa = pstRangeActionAdder.add();
OpenRaoException exception = assertThrows(OpenRaoException.class, () -> pstRa.apply(network, 50));
assertEquals("Angle value 50.0000 is not in the range of minimum and maximum angle values [-6.2276;6.2276] of the phase tap changer BBE2AA1 BBE3AA1 1 steps",
exception.getMessage());
}
@Test
void applyOnUnknownPst() {
PstRangeAction pstRa = pstRangeActionAdder.withNetworkElement("unknownNetworkElement").add();
PowsyblException exception = assertThrows(PowsyblException.class, () -> pstRa.apply(network, 5));
assertEquals("No matching transformer found with ID:unknownNetworkElement", exception.getMessage());
}
@Test
void applyOnTransformerWithNoPhaseShifter() {
Network networkNoPst = Network.read("TestCase12Nodes_no_pst.uct", getClass().getResourceAsStream("/TestCase12Nodes_no_pst.uct"));
PstRangeAction pstRa = pstRangeActionAdder.add();
PowsyblException exception = assertThrows(PowsyblException.class, () -> pstRa.apply(networkNoPst, 5));
assertEquals("Transformer 'BBE2AA1 BBE3AA1 1' does not have a PhaseTapChanger", exception.getMessage());
}
@Test
void pstWithoutSpecificRange() {
PstRangeAction pstRa = pstRangeActionAdder.add();
double minAngleInNetwork = phaseTapChanger.getStep(phaseTapChanger.getLowTapPosition()).getAlpha();
double maxAngleInNetwork = phaseTapChanger.getStep(phaseTapChanger.getHighTapPosition()).getAlpha();
assertEquals(0.3885, pstRa.getSmallestAngleStep(), 1e-3);
assertEquals(minAngleInNetwork, pstRa.getMinAdmissibleSetpoint(0), 1e-3);
assertEquals(maxAngleInNetwork, pstRa.getMaxAdmissibleSetpoint(0), 1e-3);
}
@Test
void pstWithAbsoluteCenteredZeroRange() {
PstRangeAction pstRa = pstRangeActionAdder
.newTapRange().withMinTap(-3).withMaxTap(3).withRangeType(RangeType.ABSOLUTE).add()
.add();
int neutralTap = (phaseTapChanger.getHighTapPosition() + phaseTapChanger.getLowTapPosition()) / 2;
assertEquals(phaseTapChanger.getStep(neutralTap - 3).getAlpha(), pstRa.getMinAdmissibleSetpoint(0), 0);
assertEquals(phaseTapChanger.getStep(neutralTap + 3).getAlpha(), pstRa.getMaxAdmissibleSetpoint(0), 0);
assertEquals(phaseTapChanger.getStep(neutralTap - 3).getAlpha(), pstRa.getMinAdmissibleSetpoint(5), 0);
assertEquals(phaseTapChanger.getStep(neutralTap + 3).getAlpha(), pstRa.getMaxAdmissibleSetpoint(5), 0);
}
@Test
void pstWithRelativeToPreviousInstantRange() {
PstRangeAction pstRa = pstRangeActionAdder
.newOnInstantUsageRule().withInstant(CURATIVE_INSTANT_ID).withUsageMethod(UsageMethod.AVAILABLE).add()
.newTapRange().withMinTap(-3).withMaxTap(3).withRangeType(RangeType.RELATIVE_TO_PREVIOUS_INSTANT).add()
.add();
int initialTapPosition = phaseTapChanger.getTapPosition();
double initialAngle = phaseTapChanger.getCurrentStep().getAlpha();
assertEquals(phaseTapChanger.getStep(initialTapPosition - 3).getAlpha(), pstRa.getMinAdmissibleSetpoint(initialAngle), 0);
assertEquals(phaseTapChanger.getStep(initialTapPosition + 3).getAlpha(), pstRa.getMaxAdmissibleSetpoint(initialAngle), 0);
int newTapPosition = initialTapPosition + 5;
phaseTapChanger.setTapPosition(5);
double newAngle = phaseTapChanger.getCurrentStep().getAlpha();
assertEquals(phaseTapChanger.getStep(newTapPosition - 3).getAlpha(), pstRa.getMinAdmissibleSetpoint(newAngle), 0);
assertEquals(phaseTapChanger.getStep(newTapPosition + 3).getAlpha(), pstRa.getMaxAdmissibleSetpoint(newAngle), 0);
}
@Test
void pstWithRelativeToInitialNetworkRange() {
PstRangeAction pstRa = pstRangeActionAdder
.newTapRange().withMinTap(-3).withMaxTap(3).withRangeType(RangeType.RELATIVE_TO_INITIAL_NETWORK).add()
.add();
int initialTapPosition = phaseTapChanger.getTapPosition();
assertEquals(phaseTapChanger.getStep(initialTapPosition - 3).getAlpha(), pstRa.getMinAdmissibleSetpoint(0), 0);
assertEquals(phaseTapChanger.getStep(initialTapPosition + 3).getAlpha(), pstRa.getMaxAdmissibleSetpoint(0), 0);
assertEquals(phaseTapChanger.getStep(initialTapPosition - 3).getAlpha(), pstRa.getMinAdmissibleSetpoint(5), 0);
assertEquals(phaseTapChanger.getStep(initialTapPosition + 3).getAlpha(), pstRa.getMaxAdmissibleSetpoint(5), 0);
}
@Test
void computeCurrentValue() {
PstRangeAction pstRa = pstRangeActionAdder.add();
pstRa.apply(network, 0.0); // tap 0 (CENTERED_ON_ZERO)
assertEquals(0, pstRa.getCurrentTapPosition(network), 0);
pstRa.apply(network, 3.8946); // tap 10 (CENTERED_ON_ZERO)
assertEquals(10, pstRa.getCurrentTapPosition(network), 0);
}
@Test
void getCurrentSetpointTest() {
PstRangeAction pstRa = pstRangeActionAdder.add();
assertEquals(0, pstRa.getCurrentSetpoint(network), 1e-3);
pstRa.apply(network, 3.8946); // tap 10 (CENTERED_ON_ZERO)
assertEquals(3.8946, pstRa.getCurrentSetpoint(network), 1e-3);
}
@Test
void handleDecreasingAnglesMinMax() {
// First test case where deltaU is negative
PstRangeAction pstRa1 = pstRangeActionAdder
.newTapRange().withMinTap(-10).withMaxTap(10).withRangeType(RangeType.ABSOLUTE).add()
.add();
assertTrue(pstRa1.getMinAdmissibleSetpoint(0) <= pstRa1.getMaxAdmissibleSetpoint(0));
// Then load a new case with a positive delta U and test min and max values
Network network2 = Network.read("utils/TestCase12NodesWithPositiveDeltaUPST.uct", NetworkImportsUtil.class.getResourceAsStream("/utils/TestCase12NodesWithPositiveDeltaUPST.uct"));
Map<Integer, Double> tapToAngleConversionMap2 = new HashMap<>();
network2.getTwoWindingsTransformer(networkElementId).getPhaseTapChanger().getAllSteps().forEach((stepInt, step) -> tapToAngleConversionMap2.put(stepInt, step.getAlpha()));
PstRangeAction pstRa2 = crac.newPstRangeAction()
.withId("pst-range-action-id-2")
.withName("pst-range-action-name-2")
.withNetworkElement("BBE2AA1 BBE3AA1 1")
.withOperator("operator")
.newOnInstantUsageRule().withInstant(PREVENTIVE_INSTANT_ID).withUsageMethod(UsageMethod.AVAILABLE).add()
.newTapRange().withMinTap(-10).withMaxTap(10).withRangeType(RangeType.ABSOLUTE).add()
.withTapToAngleConversionMap(tapToAngleConversionMap2)
.withInitialTap(0)
.add();
assertTrue(pstRa2.getMinAdmissibleSetpoint(0) <= pstRa2.getMaxAdmissibleSetpoint(0));
}
@Test
void testGetLocation() {
PstRangeAction pstRa = pstRangeActionAdder.add();
Set<Optional<Country>> countries = pstRa.getLocation(network);
assertEquals(1, countries.size());
assertTrue(countries.contains(Optional.of(Country.BE)));
}
@Test
void pstEquals() {
PstRangeAction pstRa1 = pstRangeActionAdder.withGroupId("g1").add();
PstRangeAction pstRa2 = pstRangeActionAdder.withId("anotherId").withGroupId("g1").add();
assertEquals(pstRa1.hashCode(), pstRa1.hashCode());
assertEquals(pstRa1, pstRa1);
assertNotEquals(pstRa1.hashCode(), pstRa2.hashCode());
assertNotEquals(pstRa1, pstRa2);
}
}