AngleCnecImplTest.java
/*
* Copyright (c) 2022, 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.iidm.network.*;
import com.powsybl.openrao.commons.Unit;
import com.powsybl.openrao.data.crac.impl.utils.NetworkImportsUtil;
import com.powsybl.openrao.data.crac.api.Crac;
import com.powsybl.openrao.data.crac.api.InstantKind;
import com.powsybl.openrao.data.crac.api.cnec.AngleCnec;
import com.powsybl.openrao.data.crac.api.cnec.AngleCnecAdder;
import com.powsybl.openrao.data.crac.api.cnec.Cnec;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Philippe Edwards {@literal <philippe.edwards at rte-france.com>}
*/
class AngleCnecImplTest {
private static final double DOUBLE_TOLERANCE = 1e-3;
private static final String PREVENTIVE_INSTANT_ID = "preventive";
private Crac crac;
@BeforeEach
public void setUp() {
crac = new CracImplFactory().create("cracId")
.newInstant(PREVENTIVE_INSTANT_ID, InstantKind.PREVENTIVE);
}
private AngleCnecAdder initPreventiveCnecAdder() {
return crac.newAngleCnec()
.withId("angle-cnec")
.withName("angle-cnec-name")
.withExportingNetworkElement("exportingNetworkElement")
.withImportingNetworkElement("importingNetworkElement")
.withOperator("FR")
.withInstant(PREVENTIVE_INSTANT_ID)
.withOptimized(false);
}
@Test
void testGetLocation1() {
Network network = NetworkImportsUtil.import12NodesNetwork();
AngleCnec cnec1 = crac.newAngleCnec()
.withId("cnec-1-id")
.withExportingNetworkElement("BBE1AA1")
.withImportingNetworkElement("BBE2AA1")
.withInstant(PREVENTIVE_INSTANT_ID)
.newThreshold().withUnit(Unit.DEGREE).withMax(1000.).add()
.add();
AngleCnec cnec2 = crac.newAngleCnec()
.withId("cnec-2-id")
.withExportingNetworkElement("DDE2AA1")
.withImportingNetworkElement("NNL3AA1")
.withInstant(PREVENTIVE_INSTANT_ID)
.newThreshold().withUnit(Unit.DEGREE).withMax(1000.).add()
.add();
Set<Optional<Country>> countries = cnec1.getLocation(network);
assertEquals(1, countries.size());
assertTrue(countries.contains(Optional.of(Country.BE)));
countries = cnec2.getLocation(network);
assertEquals(2, countries.size());
assertTrue(countries.contains(Optional.of(Country.DE)));
assertTrue(countries.contains(Optional.of(Country.NL)));
}
@Test
void testComputeValue() {
AngleCnec cnec = initPreventiveCnecAdder()
.newThreshold().withUnit(Unit.DEGREE).withMax(500.).add()
.add();
Network networkMock1 = mockBusAngleInNetwork("exportingNetworkElement", 0., "importingNetworkElement", 300.);
Network networkMock2 = mockBusAngleInNetwork("exportingNetworkElement", 900., "importingNetworkElement", 100.);
assertEquals(-300., ((AngleCnecValue) cnec.computeValue(networkMock1, Unit.DEGREE)).value(), DOUBLE_TOLERANCE);
assertEquals(800., ((AngleCnecValue) cnec.computeValue(networkMock2, Unit.DEGREE)).value(), DOUBLE_TOLERANCE);
}
@Test
void checkComputeSecurityStatusReturnsSecure() {
AngleCnec cnec = crac.newAngleCnec()
.withId("cnec-1-id")
.withExportingNetworkElement("BBE1AA1")
.withImportingNetworkElement("BBE2AA1")
.withInstant(PREVENTIVE_INSTANT_ID)
.newThreshold().withUnit(Unit.DEGREE).withMax(1000.).add()
.add();
Network networkMock = mockBusAngleInNetwork("BBE1AA1", 0., "BBE2AA1", 300.);
assertEquals(Cnec.SecurityStatus.SECURE, cnec.computeSecurityStatus(networkMock, Unit.DEGREE));
}
@Test
void checkComputeSecurityStatusReturnsHighConstraint() {
AngleCnec cnec = crac.newAngleCnec()
.withId("cnec-1-id")
.withExportingNetworkElement("BBE1AA1")
.withImportingNetworkElement("BBE2AA1")
.withInstant(PREVENTIVE_INSTANT_ID)
.newThreshold().withUnit(Unit.DEGREE).withMax(1000.).add()
.add();
Network networkMock = mockBusAngleInNetwork("BBE1AA1", 1200., "BBE2AA1", 300.);
assertEquals(Cnec.SecurityStatus.SECURE, cnec.computeSecurityStatus(networkMock, Unit.DEGREE));
}
// test threshold on branches whose nominal voltage is the same on both side
@Test
void testAngleCnecWithOneMaxThreshold() {
AngleCnec cnec = initPreventiveCnecAdder()
.newThreshold().withUnit(Unit.DEGREE).withMax(500.).add()
.add();
// bounds
assertEquals(500., cnec.getUpperBound(Unit.DEGREE).orElseThrow(), DOUBLE_TOLERANCE);
assertFalse(cnec.getLowerBound(Unit.DEGREE).isPresent());
// margin
Network networkMock1 = mockBusAngleInNetwork("exportingNetworkElement", 0., "importingNetworkElement", 300.);
assertEquals(800., cnec.computeMargin(networkMock1, Unit.DEGREE), DOUBLE_TOLERANCE);
Network networkMock2 = mockBusAngleInNetwork("exportingNetworkElement", 300., "importingNetworkElement", 0.);
assertEquals(200., cnec.computeMargin(networkMock2, Unit.DEGREE), DOUBLE_TOLERANCE);
}
@Test
void testAngleCnecWithSeveralThresholds() {
AngleCnec cnec = initPreventiveCnecAdder()
.newThreshold().withUnit(Unit.DEGREE).withMax(100.).add()
.newThreshold().withUnit(Unit.DEGREE).withMin(-200.).add()
.newThreshold().withUnit(Unit.DEGREE).withMax(500.).add()
.newThreshold().withUnit(Unit.DEGREE).withMin(-300.).add()
.newThreshold().withUnit(Unit.DEGREE).withMin(-50.).withMax(150.).add()
.add();
assertEquals(100., cnec.getUpperBound(Unit.DEGREE).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(-50., cnec.getLowerBound(Unit.DEGREE).orElseThrow(), DOUBLE_TOLERANCE);
Network networkMock1 = mockBusAngleInNetwork("exportingNetworkElement", 300., "importingNetworkElement", 0.);
assertEquals(-200, cnec.computeMargin(networkMock1, Unit.DEGREE), DOUBLE_TOLERANCE);
Network networkMock2 = mockBusAngleInNetwork("exportingNetworkElement", 0., "importingNetworkElement", 200.);
assertEquals(-150., cnec.computeMargin(networkMock2, Unit.DEGREE), DOUBLE_TOLERANCE);
}
@Test
void marginsWithNegativeAndPositiveLimits() {
AngleCnec cnec = initPreventiveCnecAdder()
.newThreshold().withUnit(Unit.DEGREE).withMin(-200.).withMax(500.).add()
.add();
Network networkMock1 = mockBusAngleInNetwork("exportingNetworkElement", 0., "importingNetworkElement", 300.);
assertEquals(-100, cnec.computeMargin(networkMock1, Unit.DEGREE), DOUBLE_TOLERANCE);
Network networkMock2 = mockBusAngleInNetwork("exportingNetworkElement", 300., "importingNetworkElement", 300.);
assertEquals(200, cnec.computeMargin(networkMock2, Unit.DEGREE), DOUBLE_TOLERANCE);
Network networkMock3 = mockBusAngleInNetwork("exportingNetworkElement", 300., "importingNetworkElement", -100.);
assertEquals(100, cnec.computeMargin(networkMock3, Unit.DEGREE), DOUBLE_TOLERANCE);
Network networkMock4 = mockBusAngleInNetwork("exportingNetworkElement", 300., "importingNetworkElement", -500.);
assertEquals(-300, cnec.computeMargin(networkMock4, Unit.DEGREE), DOUBLE_TOLERANCE);
}
// other
@Test
void testEqualsAndHashCode() {
AngleCnec cnec1 = initPreventiveCnecAdder().newThreshold().withUnit(Unit.DEGREE).withMax(1000.).add().add();
AngleCnec cnec2 = initPreventiveCnecAdder().withId("anotherId").newThreshold().withUnit(Unit.DEGREE).withMin(-1000.).add().add();
assertEquals(cnec1, cnec1);
assertNotEquals(cnec1, cnec2);
assertNotNull(cnec1);
assertNotEquals(1, cnec1);
assertEquals(cnec1.hashCode(), cnec1.hashCode());
assertNotEquals(cnec1.hashCode(), cnec2.hashCode());
}
@Test
void testComputeSecurityStatus() {
AngleCnec cnec = initPreventiveCnecAdder()
.newThreshold().withUnit(Unit.DEGREE).withMin(-200.).withMax(500.).add()
.add();
Network networkMockWithBusAngleWithinThresholds = mockBusAngleInNetwork("exportingNetworkElement", 300., "importingNetworkElement", 0.);
Network networkMockWithBusAngleLowerThanThresholds = mockBusAngleInNetwork("exportingNetworkElement", -300., "importingNetworkElement", 0.);
Network networkMockWithBusAngleHigherThanThresholds = mockBusAngleInNetwork("exportingNetworkElement", 1300., "importingNetworkElement", 0.);
assertEquals(Cnec.SecurityStatus.SECURE, cnec.computeSecurityStatus(networkMockWithBusAngleWithinThresholds, Unit.DEGREE));
assertEquals(Cnec.SecurityStatus.LOW_CONSTRAINT, cnec.computeSecurityStatus(networkMockWithBusAngleLowerThanThresholds, Unit.DEGREE));
assertEquals(Cnec.SecurityStatus.HIGH_CONSTRAINT, cnec.computeSecurityStatus(networkMockWithBusAngleHigherThanThresholds, Unit.DEGREE));
}
private static Network mockBusAngleInNetwork(String exportingElement, double expAngle, String importingElement, double impAngle) {
Network network = Mockito.mock(Network.class);
VoltageLevel exportingVl = Mockito.mock(VoltageLevel.class);
Mockito.when(exportingVl.getId()).thenReturn(exportingElement);
Mockito.when(network.getVoltageLevel(exportingElement)).thenReturn(exportingVl);
VoltageLevel.BusView bv = Mockito.mock(VoltageLevel.BusView.class);
Mockito.when(exportingVl.getBusView()).thenReturn(bv);
Bus bus = Mockito.mock(Bus.class);
Mockito.when(bus.getAngle()).thenReturn(expAngle);
Mockito.when(bv.getBusStream()).thenReturn(Stream.of(bus));
Network.BusBreakerView busBreakerView = Mockito.mock(Network.BusBreakerView.class);
Mockito.when(network.getBusBreakerView()).thenReturn(busBreakerView);
Mockito.when(busBreakerView.getBus(exportingElement)).thenReturn(bus);
Mockito.when(bus.getVoltageLevel()).thenReturn(exportingVl);
// importing vl
VoltageLevel importingVl = Mockito.mock(VoltageLevel.class);
Mockito.when(importingVl.getId()).thenReturn(importingElement);
Mockito.when(network.getVoltageLevel(importingElement)).thenReturn(importingVl);
VoltageLevel.BusView bvI = Mockito.mock(VoltageLevel.BusView.class);
Mockito.when(importingVl.getBusView()).thenReturn(bvI);
Bus busI = Mockito.mock(Bus.class);
Mockito.when(busI.getAngle()).thenReturn(impAngle);
Mockito.when(bvI.getBusStream()).thenReturn(Stream.of(busI));
Network.BusBreakerView busBreakerViewI = Mockito.mock(Network.BusBreakerView.class);
Mockito.when(network.getBusBreakerView()).thenReturn(busBreakerViewI);
Mockito.when(busBreakerViewI.getBus(importingElement)).thenReturn(busI);
Mockito.when(busI.getVoltageLevel()).thenReturn(importingVl);
return network;
}
}