FlowCnecImplTest.java
/*
* Copyright (c) 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/.
*/
package com.powsybl.openrao.data.crac.impl;
import com.powsybl.iidm.network.*;
import com.powsybl.openrao.commons.OpenRaoException;
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.Cnec;
import com.powsybl.openrao.data.crac.api.cnec.FlowCnec;
import com.powsybl.openrao.data.crac.api.cnec.FlowCnecAdder;
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 static com.powsybl.openrao.commons.Unit.*;
import static com.powsybl.iidm.network.TwoSides.ONE;
import static com.powsybl.iidm.network.TwoSides.TWO;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Baptiste Seguinot {@literal <baptiste.seguinot at rte-france.com>}
*/
class FlowCnecImplTest {
private static final String PREVENTIVE_INSTANT_ID = "preventive";
private static final double DOUBLE_TOLERANCE = 1; // high tolerance for conversion AMPERE <-> MEGAWATT
private Crac crac;
@BeforeEach
public void setUp() {
crac = new CracImplFactory().create("cracId")
.newInstant(PREVENTIVE_INSTANT_ID, InstantKind.PREVENTIVE);
}
private FlowCnecAdder initPreventiveCnecAdder() {
return crac.newFlowCnec().withId("line-cnec").withName("line-cnec-name").withNetworkElement("anyNetworkElement").withOperator("FR").withInstant(PREVENTIVE_INSTANT_ID).withOptimized(true);
}
@Test
void testGetLocation1() {
Network network = NetworkImportsUtil.import12NodesNetwork();
FlowCnec cnec1 = crac.newFlowCnec().withId("cnec-1-id").withNetworkElement("BBE1AA1 BBE2AA1 1").withInstant(PREVENTIVE_INSTANT_ID).newThreshold().withUnit(MEGAWATT).withMax(1000.).withSide(TwoSides.ONE).add().add();
FlowCnec cnec2 = crac.newFlowCnec().withId("cnec-2-id").withNetworkElement("DDE2AA1 NNL3AA1 1").withInstant(PREVENTIVE_INSTANT_ID).newThreshold().withUnit(MEGAWATT).withMax(1000.).withSide(TwoSides.ONE).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() {
Network network = Mockito.mock(Network.class);
Branch branch1 = Mockito.mock(Branch.class);
Terminal terminal11 = Mockito.mock(Terminal.class);
Terminal terminal12 = Mockito.mock(Terminal.class);
Terminal terminal21 = Mockito.mock(Terminal.class);
Mockito.when(network.getBranch("BBE1AA1 BBE2AA1 1")).thenReturn(branch1);
Mockito.when(terminal11.getP()).thenReturn(300.);
Mockito.when(terminal12.getP()).thenReturn(1100.);
Mockito.when(branch1.getTerminal(ONE)).thenReturn(terminal11);
Mockito.when(branch1.getTerminal(TWO)).thenReturn(terminal12);
Branch branch2 = Mockito.mock(Branch.class);
Mockito.when(network.getBranch("DDE2AA1 NNL3AA1 1")).thenReturn(branch2);
Mockito.when(terminal21.getP()).thenReturn(100.);
Mockito.when(branch2.getTerminal(ONE)).thenReturn(terminal21);
FlowCnec cnecWithTwoSides = crac.newFlowCnec().withId("cnec-1-id").withNetworkElement("BBE1AA1 BBE2AA1 1").withInstant(PREVENTIVE_INSTANT_ID)
.newThreshold().withUnit(MEGAWATT).withMin(500.).withMax(1000.).withSide(TwoSides.ONE).add()
.newThreshold().withUnit(MEGAWATT).withMin(2000.).withMax(3000.).withSide(TwoSides.TWO).add()
.add();
assertThrows(OpenRaoException.class, () -> cnecWithTwoSides.computeValue(network, KILOVOLT));
assertEquals(300., ((FlowCnecValue) cnecWithTwoSides.computeValue(network, MEGAWATT)).side1Value());
assertEquals(1100., ((FlowCnecValue) cnecWithTwoSides.computeValue(network, MEGAWATT)).side2Value());
FlowCnec cnecWithOneSide = crac.newFlowCnec().withId("cnec-2-id").withNetworkElement("DDE2AA1 NNL3AA1 1").withInstant(PREVENTIVE_INSTANT_ID).newThreshold().withUnit(MEGAWATT).withMax(1000.).withSide(TwoSides.ONE).add().add();
assertEquals(100., ((FlowCnecValue) cnecWithOneSide.computeValue(network, MEGAWATT)).side1Value());
assertEquals(Double.NaN, ((FlowCnecValue) cnecWithOneSide.computeValue(network, MEGAWATT)).side2Value());
}
@Test
void testComputeValueAmpere() {
Network network = Mockito.mock(Network.class);
Branch branch3 = Mockito.mock(Branch.class);
Terminal terminal31 = Mockito.mock(Terminal.class);
Terminal terminal32 = Mockito.mock(Terminal.class);
Mockito.when(network.getBranch("AAE2AA1 AAE3AA1 1")).thenReturn(branch3);
Mockito.when(terminal31.getP()).thenReturn(-66.);
Mockito.when(terminal31.getI()).thenReturn(55.);
Mockito.when(terminal32.getP()).thenReturn(22.);
Mockito.when(terminal32.getI()).thenReturn(Double.NaN);
Mockito.when(branch3.getTerminal(ONE)).thenReturn(terminal31);
Mockito.when(branch3.getTerminal(TWO)).thenReturn(terminal32);
FlowCnec cnecA = crac.newFlowCnec().withId("cnec-A-id").withNetworkElement("AAE2AA1 AAE3AA1 1").withInstant(PREVENTIVE_INSTANT_ID)
.withNominalVoltage(222.)
.newThreshold().withUnit(AMPERE).withMin(5.).withMax(10.).withSide(TwoSides.ONE).add()
.newThreshold().withUnit(AMPERE).withMin(20.).withMax(300.).withSide(TwoSides.TWO).add()
.add();
assertEquals(-55., ((FlowCnecValue) cnecA.computeValue(network, AMPERE)).side1Value());
assertEquals(57.2, ((FlowCnecValue) cnecA.computeValue(network, AMPERE)).side2Value(), 0.1);
}
@Test
void testComputeWorstMargin() {
Network network = Mockito.mock(Network.class, Mockito.RETURNS_DEEP_STUBS);
Branch branch1 = Mockito.mock(Branch.class, Mockito.RETURNS_DEEP_STUBS);
Mockito.when(network.getBranch("BBE1AA1 BBE2AA1 1")).thenReturn(branch1);
Mockito.when(branch1.getTerminal(ONE).getP()).thenReturn(300.);
Mockito.when(branch1.getTerminal(TWO).getP()).thenReturn(1100.);
Branch branch2 = Mockito.mock(Branch.class, Mockito.RETURNS_DEEP_STUBS);
Mockito.when(network.getBranch("DDE2AA1 NNL3AA1 1")).thenReturn(branch2);
Mockito.when(branch2.getTerminal(ONE).getP()).thenReturn(100.);
FlowCnec cnecWithTwoSides = crac.newFlowCnec().withId("cnec-1-id").withNetworkElement("BBE1AA1 BBE2AA1 1").withInstant(PREVENTIVE_INSTANT_ID)
.newThreshold().withUnit(MEGAWATT).withMin(500.).withMax(1000.).withSide(TwoSides.ONE).add()
.newThreshold().withUnit(MEGAWATT).withMin(2000.).withMax(3000.).withSide(TwoSides.TWO).add()
.add();
assertThrows(OpenRaoException.class, () -> cnecWithTwoSides.computeMargin(network, KILOVOLT));
assertEquals(-900., cnecWithTwoSides.computeMargin(network, MEGAWATT));
FlowCnec cnecWithOneSide = crac.newFlowCnec().withId("cnec-2-id").withNetworkElement("DDE2AA1 NNL3AA1 1").withInstant(PREVENTIVE_INSTANT_ID).newThreshold().withUnit(MEGAWATT).withMax(1000.).withSide(TwoSides.ONE).add().add();
assertEquals(900., cnecWithOneSide.computeMargin(network, MEGAWATT));
}
@Test
void testComputeSecurityStatus() {
Network network = Mockito.mock(Network.class, Mockito.RETURNS_DEEP_STUBS);
Branch branch1 = Mockito.mock(Branch.class, Mockito.RETURNS_DEEP_STUBS);
Mockito.when(network.getBranch("BBE1AA1 BBE2AA1 1")).thenReturn(branch1);
Mockito.when(branch1.getTerminal(ONE).getP()).thenReturn(300.);
Mockito.when(branch1.getTerminal(TWO).getP()).thenReturn(3100.);
Branch branch2 = Mockito.mock(Branch.class, Mockito.RETURNS_DEEP_STUBS);
Mockito.when(network.getBranch("DDE2AA1 NNL3AA1 1")).thenReturn(branch2);
Mockito.when(branch2.getTerminal(ONE).getP()).thenReturn(100.);
FlowCnec cnecWithTwoSides = crac.newFlowCnec().withId("cnec-1-id").withNetworkElement("BBE1AA1 BBE2AA1 1").withInstant(PREVENTIVE_INSTANT_ID)
.newThreshold().withUnit(MEGAWATT).withMin(500.).withMax(1000.).withSide(TwoSides.ONE).add()
.newThreshold().withUnit(MEGAWATT).withMin(2000.).withMax(3000.).withSide(TwoSides.TWO).add()
.add();
assertThrows(OpenRaoException.class, () -> cnecWithTwoSides.computeMargin(network, KILOVOLT));
assertEquals(Cnec.SecurityStatus.HIGH_AND_LOW_CONSTRAINTS, cnecWithTwoSides.computeSecurityStatus(network, MEGAWATT));
FlowCnec cnecWithOneSide = crac.newFlowCnec().withId("cnec-2-id").withNetworkElement("DDE2AA1 NNL3AA1 1").withInstant(PREVENTIVE_INSTANT_ID).newThreshold().withUnit(MEGAWATT).withMax(1000.).withSide(TwoSides.ONE).add().add();
assertEquals(Cnec.SecurityStatus.SECURE, cnecWithOneSide.computeSecurityStatus(network, MEGAWATT));
FlowCnec cnec3 = crac.newFlowCnec().withId("cnec-3-id").withNetworkElement("DDE2AA1 NNL3AA1 1").withInstant(PREVENTIVE_INSTANT_ID).newThreshold().withUnit(MEGAWATT).withMax(10.).withSide(TwoSides.ONE).add().add();
assertEquals(Cnec.SecurityStatus.HIGH_CONSTRAINT, cnec3.computeSecurityStatus(network, MEGAWATT));
}
// test threshold on branches whose nominal voltage is the same on both side
@Test
void testBranchWithOneMaxThresholdOnLeftInMW() {
FlowCnec cnec = initPreventiveCnecAdder().withNominalVoltage(380.).newThreshold().withUnit(MEGAWATT).withMax(500.).withSide(TwoSides.ONE).add().add();
// bounds on ONE side
assertEquals(500., cnec.getUpperBound(ONE, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(500. / (0.38 * Math.sqrt(3)), cnec.getUpperBound(ONE, AMPERE).orElseThrow(), DOUBLE_TOLERANCE); // = 760 A
assertFalse(cnec.getLowerBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(ONE, AMPERE).isPresent());
// bounds on TWO side
assertFalse(cnec.getUpperBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(TWO, AMPERE).isPresent());
assertFalse(cnec.getLowerBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(TWO, AMPERE).isPresent());
// margin
assertEquals(200., cnec.computeMargin(300, ONE, MEGAWATT), DOUBLE_TOLERANCE); // bound: 500 MW
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(300, TWO, MEGAWATT), DOUBLE_TOLERANCE); // bound: 500 MW
assertEquals(460., cnec.computeMargin(300, ONE, AMPERE), DOUBLE_TOLERANCE); // bound: 760 A
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(-300, TWO, AMPERE), DOUBLE_TOLERANCE); // bound: 760 A
}
@Test
void testBranchWithOneMinThresholdOnRightInMW() {
FlowCnec cnec = initPreventiveCnecAdder().withNominalVoltage(380.).newThreshold().withUnit(MEGAWATT).withMin(-500.).withSide(TwoSides.TWO).add().add();
// bounds on ONE side
assertFalse(cnec.getUpperBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(ONE, AMPERE).isPresent());
assertFalse(cnec.getLowerBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(ONE, AMPERE).isPresent());
// bounds on TWO side
assertFalse(cnec.getUpperBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(TWO, AMPERE).isPresent());
assertEquals(-500., cnec.getLowerBound(TWO, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(-500. / (0.38 * Math.sqrt(3)), cnec.getLowerBound(TWO, AMPERE).orElseThrow(), DOUBLE_TOLERANCE); // = -760 A
// margin
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(300, ONE, MEGAWATT), DOUBLE_TOLERANCE); // bound: -500 MW
assertEquals(800., cnec.computeMargin(300, TWO, MEGAWATT), DOUBLE_TOLERANCE); // bound: -500 MW
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(300, ONE, AMPERE), DOUBLE_TOLERANCE); // bound: -760 A
assertEquals(-240., cnec.computeMargin(-1000, TWO, AMPERE), DOUBLE_TOLERANCE); // bound: -760 A
}
@Test
void testBranchWithOneMinThresholdOnLeftInAmpere() {
FlowCnec cnec = initPreventiveCnecAdder().withNominalVoltage(380.).newThreshold().withUnit(AMPERE).withMin(-450.).withSide(TwoSides.ONE).add().add();
// bounds on ONE side
assertFalse(cnec.getUpperBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(ONE, AMPERE).isPresent());
assertEquals(-450., cnec.getLowerBound(ONE, AMPERE).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(-450. * (0.38 * Math.sqrt(3)), cnec.getLowerBound(ONE, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE); // -296 MW
// bounds on TWO side
assertFalse(cnec.getUpperBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(TWO, AMPERE).isPresent());
assertFalse(cnec.getLowerBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(TWO, AMPERE).isPresent());
// margin
assertEquals(750., cnec.computeMargin(300, ONE, AMPERE), DOUBLE_TOLERANCE); // bound: -450 A
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(300, TWO, AMPERE), DOUBLE_TOLERANCE); // bound: -450 A
assertEquals(596., cnec.computeMargin(300, ONE, MEGAWATT), DOUBLE_TOLERANCE); // bound: -296 MW
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(-300, TWO, MEGAWATT), DOUBLE_TOLERANCE); // bound: -296 MW
}
@Test
void testBranchWithOneMaxThresholdOnRightInAmpere() {
FlowCnec cnec = initPreventiveCnecAdder().withNominalVoltage(220.).newThreshold().withUnit(AMPERE).withMax(110.).withSide(TwoSides.TWO).add().add();
// bounds on ONE side
assertFalse(cnec.getUpperBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(ONE, AMPERE).isPresent());
assertFalse(cnec.getLowerBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(ONE, AMPERE).isPresent());
// bounds on TWO side
assertEquals(110., cnec.getUpperBound(TWO, AMPERE).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(110. * (0.22 * Math.sqrt(3)), cnec.getUpperBound(TWO, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE); // 42 MW
assertFalse(cnec.getLowerBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(TWO, AMPERE).isPresent());
// margin
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(300, ONE, AMPERE), DOUBLE_TOLERANCE); // bound: 110 A
assertEquals(-190., cnec.computeMargin(300, TWO, AMPERE), DOUBLE_TOLERANCE); // bound: 110 A
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(300, ONE, MEGAWATT), DOUBLE_TOLERANCE); // bound: 42 MW
assertEquals(342., cnec.computeMargin(-300, TWO, MEGAWATT), DOUBLE_TOLERANCE); // bound: 42 MW
}
@Test
void testBranchWithOneMaxThresholdOnLeftInPercentImax() {
FlowCnec cnec = initPreventiveCnecAdder().withNominalVoltage(380.).withIMax(1000.).newThreshold().withUnit(PERCENT_IMAX).withMax(1.1).withSide(TwoSides.ONE).add() // 1.1 = 110 %
.add();
// bounds on ONE side
assertEquals(1100., cnec.getUpperBound(ONE, AMPERE).orElseThrow(), DOUBLE_TOLERANCE); // 1100 A
assertEquals(1100. * (0.38 * Math.sqrt(3)), cnec.getUpperBound(ONE, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE); // 724 MW
assertFalse(cnec.getLowerBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(ONE, AMPERE).isPresent());
// bounds on TWO side
assertFalse(cnec.getUpperBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(TWO, AMPERE).isPresent());
assertFalse(cnec.getLowerBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(TWO, AMPERE).isPresent());
// margin
assertEquals(-100, cnec.computeMargin(1200, ONE, AMPERE), DOUBLE_TOLERANCE); // bound: 1100 A
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(1200, TWO, AMPERE), DOUBLE_TOLERANCE); // bound: 1100 A
assertEquals(-26., cnec.computeMargin(750, ONE, MEGAWATT), DOUBLE_TOLERANCE); // bound: 724 MW
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(100, TWO, MEGAWATT), DOUBLE_TOLERANCE); // bound: 724 MW
}
@Test
void testBranchWithOneMinThresholdOnRightInPercentImax() {
FlowCnec cnec = initPreventiveCnecAdder().withNominalVoltage(220.).withIMax(1000., TWO).withIMax(0., ONE) // should not be considered as the threshold is on the right side
.newThreshold().withUnit(PERCENT_IMAX).withMin(-0.9).withSide(TwoSides.TWO).add() // 0.9 = 90 %
.add();
assertEquals(Set.of(TWO), cnec.getMonitoredSides());
// bounds on ONE side
assertFalse(cnec.getUpperBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(ONE, AMPERE).isPresent());
assertFalse(cnec.getLowerBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(ONE, AMPERE).isPresent());
// bounds on TWO side
assertFalse(cnec.getUpperBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(TWO, AMPERE).isPresent());
assertEquals(-900., cnec.getLowerBound(TWO, AMPERE).orElseThrow(), DOUBLE_TOLERANCE); // -900 A
assertEquals(-900. * (0.22 * Math.sqrt(3)), cnec.getLowerBound(TWO, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE); // -343 MW
// margin
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(1200, ONE, AMPERE), DOUBLE_TOLERANCE); // bound: -900 A
assertEquals(2100., cnec.computeMargin(1200, TWO, AMPERE), DOUBLE_TOLERANCE); // bound: -900 A
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(-500, ONE, MEGAWATT), DOUBLE_TOLERANCE); // bound: -343 MW
assertEquals(443., cnec.computeMargin(100, TWO, MEGAWATT), DOUBLE_TOLERANCE); // bound: -343 MW
}
// test threshold on transformer whose nominal voltage is NOT the same on both side
/*
- when measured in MEGAWATT, the bounds on both side of a transformer are always equal
- when measured in AMPERE, the bounds on both side of a transformer are different, one is multiply by the voltage ratio
- when computing the margin in MEGAWATT, the returned margin will be same whether the considered flow (in MW) is considered
on the left or right side of the transformer
- when computing the margin in AMPERE, the returned margin will be different whether the flow (in A) is considered on the
left or on the right side of the transformer
*/
@Test
void testTransformerWithOneMaxThresholdOnLeftInMW() {
FlowCnec cnec = initPreventiveCnecAdder().withNominalVoltage(220., ONE).withNominalVoltage(380., TWO).newThreshold().withUnit(MEGAWATT).withMax(500.).withSide(TwoSides.ONE).add().add();
// bounds on ONE side
assertEquals(500., cnec.getUpperBound(ONE, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(500. / (0.22 * Math.sqrt(3)), cnec.getUpperBound(ONE, AMPERE).orElseThrow(), DOUBLE_TOLERANCE); // 1312 A
assertFalse(cnec.getLowerBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(ONE, AMPERE).isPresent());
// bounds on TWO side
assertFalse(cnec.getUpperBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(TWO, AMPERE).isPresent());
assertFalse(cnec.getLowerBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(TWO, AMPERE).isPresent());
// margins
assertEquals(400., cnec.computeMargin(100, ONE, MEGAWATT), DOUBLE_TOLERANCE); // bound: 500 MW
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(1000, TWO, MEGAWATT), DOUBLE_TOLERANCE); // bound: 500 MW
assertEquals(1512., cnec.computeMargin(-200, ONE, AMPERE), DOUBLE_TOLERANCE); // bound: 1312 A
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(2000, TWO, AMPERE), DOUBLE_TOLERANCE); // bound: 759 A
}
@Test
void testTransformerWithOneMinThresholdOnRightInMW() {
FlowCnec cnec = initPreventiveCnecAdder().withNominalVoltage(220., ONE).withNominalVoltage(380., TWO).newThreshold().withUnit(MEGAWATT).withMin(-600.).withSide(TwoSides.TWO).add().add();
// bounds on ONE side
assertFalse(cnec.getUpperBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(ONE, AMPERE).isPresent());
assertFalse(cnec.getLowerBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(ONE, AMPERE).isPresent());
// bounds on TWO side
assertFalse(cnec.getUpperBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(TWO, AMPERE).isPresent());
assertEquals(-600., cnec.getLowerBound(TWO, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(-600. / (0.38 * Math.sqrt(3)), cnec.getLowerBound(TWO, AMPERE).orElseThrow(), DOUBLE_TOLERANCE); // - 912 A
// margin
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(500, ONE, MEGAWATT), DOUBLE_TOLERANCE); // bound: -600 MW
assertEquals(-400., cnec.computeMargin(-1000, TWO, MEGAWATT), DOUBLE_TOLERANCE); // bound: -600 MW
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(-500, ONE, AMPERE), DOUBLE_TOLERANCE); // bound: -1575 A
assertEquals(1012., cnec.computeMargin(100, TWO, AMPERE), DOUBLE_TOLERANCE); // bound: -912 A
}
@Test
void testTransformerWithOneMinThresholdOnLeftInA() {
FlowCnec cnec = initPreventiveCnecAdder().withNominalVoltage(220., ONE).withNominalVoltage(380., TWO).newThreshold().withUnit(AMPERE).withMin(-1000.).withSide(TwoSides.ONE).add().add();
// bounds on ONE side
assertFalse(cnec.getUpperBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(ONE, AMPERE).isPresent());
assertEquals(-1000., cnec.getLowerBound(ONE, AMPERE).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(-1000. * (0.22 * Math.sqrt(3)), cnec.getLowerBound(ONE, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE); // - 381 MW
// bounds on TWO side
assertFalse(cnec.getUpperBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(TWO, AMPERE).isPresent());
assertFalse(cnec.getLowerBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(TWO, AMPERE).isPresent());
// margin
assertEquals(1300., cnec.computeMargin(300, ONE, AMPERE), DOUBLE_TOLERANCE); // bound: -1000 A
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(-800, TWO, AMPERE), DOUBLE_TOLERANCE); // bound: -579 A
assertEquals(-319., cnec.computeMargin(-700, ONE, MEGAWATT), DOUBLE_TOLERANCE); // bound: -381 MW
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(1000, TWO, MEGAWATT), DOUBLE_TOLERANCE); // bound: -381 MW
}
@Test
void testTransformerWithOneMaxThresholdOnRightInA() {
FlowCnec cnec = initPreventiveCnecAdder().withNominalVoltage(220., ONE).withNominalVoltage(380., TWO).newThreshold().withUnit(AMPERE).withMax(500.).withSide(TwoSides.TWO).add().add();
// bounds on ONE side
assertFalse(cnec.getUpperBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(ONE, AMPERE).isPresent());
assertFalse(cnec.getLowerBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(ONE, AMPERE).isPresent());
// bounds on TWO side
assertEquals(500., cnec.getUpperBound(TWO, AMPERE).orElseThrow(), DOUBLE_TOLERANCE); // 500 A
assertEquals(500. * (0.38 * Math.sqrt(3)), cnec.getUpperBound(TWO, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE); // 329 MW
assertFalse(cnec.getLowerBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(TWO, AMPERE).isPresent());
// margin
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(800, ONE, AMPERE), DOUBLE_TOLERANCE); // bound: 864 A
assertEquals(-100., cnec.computeMargin(600, TWO, AMPERE), DOUBLE_TOLERANCE); // bound: 500 A
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(300, ONE, MEGAWATT), DOUBLE_TOLERANCE); // bound: 329 MW
assertEquals(-71., cnec.computeMargin(400, TWO, MEGAWATT), DOUBLE_TOLERANCE); // bound: 329 MW
}
@Test
void testTransformerWithOneMinThresholdOnLeftInPercentImax() {
FlowCnec cnec = initPreventiveCnecAdder().withNominalVoltage(220., ONE).withNominalVoltage(380., TWO).withIMax(2000.).newThreshold().withUnit(PERCENT_IMAX).withMin(-1.).withSide(TwoSides.ONE).add().add();
// bounds on ONE side
assertFalse(cnec.getUpperBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(ONE, AMPERE).isPresent());
assertEquals(-2000., cnec.getLowerBound(ONE, AMPERE).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(-2000. * (0.22 * Math.sqrt(3)), cnec.getLowerBound(ONE, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE); // - 762 MW
// bounds on TWO side
assertFalse(cnec.getUpperBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(TWO, AMPERE).isPresent());
assertFalse(cnec.getLowerBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(TWO, AMPERE).isPresent());
// margin
assertEquals(2300., cnec.computeMargin(300, ONE, AMPERE), DOUBLE_TOLERANCE); // bound: -2000 A
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(-800, TWO, AMPERE), DOUBLE_TOLERANCE); // bound: -1158 A
assertEquals(62., cnec.computeMargin(-700, ONE, MEGAWATT), DOUBLE_TOLERANCE); // bound: -762 MW
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(-1000, TWO, MEGAWATT), DOUBLE_TOLERANCE); // bound: -762 MW
}
@Test
void testTransformerWithOneMaxThresholdOnRightInPercentImax() {
FlowCnec cnec = initPreventiveCnecAdder().withNominalVoltage(220., ONE).withNominalVoltage(380., TWO).withIMax(0., ONE) // shouldn't be used as threshold is defined on right side
.withIMax(2000., TWO).newThreshold().withUnit(PERCENT_IMAX).withMax(0.25).withSide(TwoSides.TWO).add().add();
// bounds on ONE side
assertFalse(cnec.getUpperBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getUpperBound(ONE, AMPERE).isPresent());
assertFalse(cnec.getLowerBound(ONE, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(ONE, AMPERE).isPresent());
// bounds on TWO side
assertEquals(500., cnec.getUpperBound(TWO, AMPERE).orElseThrow(), DOUBLE_TOLERANCE); // 500 A
assertEquals(500. * (0.38 * Math.sqrt(3)), cnec.getUpperBound(TWO, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE); // 329 MW
assertFalse(cnec.getLowerBound(TWO, MEGAWATT).isPresent());
assertFalse(cnec.getLowerBound(TWO, AMPERE).isPresent());
// margin
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(800, ONE, AMPERE), DOUBLE_TOLERANCE); // bound: 864 A
assertEquals(-100., cnec.computeMargin(600, TWO, AMPERE), DOUBLE_TOLERANCE); // bound: 500 A
assertEquals(Double.POSITIVE_INFINITY, cnec.computeMargin(300, ONE, MEGAWATT), DOUBLE_TOLERANCE); // bound: 329 MW
assertEquals(-71., cnec.computeMargin(400, TWO, MEGAWATT), DOUBLE_TOLERANCE); // bound: 329 MW
}
// Tests on concurrency between thresholds
@Test
void testBranchWithSeveralThresholdsWithLimitingOnLeftOrRightSide() {
FlowCnec cnec = initPreventiveCnecAdder().newThreshold().withUnit(MEGAWATT).withMax(100.).withSide(TwoSides.ONE).add().newThreshold().withUnit(MEGAWATT).withMin(-200.).withSide(TwoSides.ONE).add().newThreshold().withUnit(MEGAWATT).withMax(500.).withSide(TwoSides.TWO).add().newThreshold().withUnit(MEGAWATT).withMin(-300.).withSide(TwoSides.TWO).add().add();
assertEquals(100., cnec.getUpperBound(ONE, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(-200., cnec.getLowerBound(ONE, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(-200., cnec.computeMargin(300, ONE, MEGAWATT), DOUBLE_TOLERANCE);
assertEquals(0., cnec.computeMargin(-200, ONE, MEGAWATT), DOUBLE_TOLERANCE);
}
@Test
void testBranchWithSeveralThresholdsWithBoth() {
FlowCnec cnec = initPreventiveCnecAdder().newThreshold().withUnit(MEGAWATT).withMax(100.).withSide(TwoSides.ONE).add().newThreshold().withUnit(MEGAWATT).withMin(-200.).withSide(TwoSides.ONE).add().newThreshold().withUnit(MEGAWATT).withMax(500.).withSide(TwoSides.TWO).add().newThreshold().withUnit(MEGAWATT).withMin(-300.).withSide(TwoSides.TWO).add().newThreshold().withUnit(MEGAWATT).withMin(-50.).withMax(150.).withSide(TwoSides.TWO).add().add();
assertEquals(100., cnec.getUpperBound(ONE, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(-200., cnec.getLowerBound(ONE, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(-200., cnec.computeMargin(300, ONE, MEGAWATT), DOUBLE_TOLERANCE);
assertEquals(0., cnec.computeMargin(-200, ONE, MEGAWATT), DOUBLE_TOLERANCE);
assertEquals(150., cnec.getUpperBound(TWO, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(-50., cnec.getLowerBound(TWO, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(-150, cnec.computeMargin(300, TWO, MEGAWATT), DOUBLE_TOLERANCE);
assertEquals(-150., cnec.computeMargin(-200, TWO, MEGAWATT), DOUBLE_TOLERANCE);
}
@Test
void testComputeMarginOnTransformerWithSeveralThresholdsInAmps() {
FlowCnec cnec = initPreventiveCnecAdder().withNominalVoltage(220., ONE).withNominalVoltage(380., TWO).newThreshold().withUnit(AMPERE).withMax(100.).withSide(TwoSides.ONE).add().newThreshold().withUnit(AMPERE).withMin(-70.).withSide(TwoSides.ONE).add().newThreshold().withUnit(AMPERE).withMin(-50.).withMax(50.).withSide(TwoSides.TWO).add().add();
assertEquals(100, cnec.getUpperBound(ONE, AMPERE).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(-70, cnec.getLowerBound(ONE, AMPERE).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(0., cnec.computeMargin(100, ONE, AMPERE), DOUBLE_TOLERANCE);
assertEquals(-30, cnec.computeMargin(-100, ONE, AMPERE), DOUBLE_TOLERANCE);
}
@Test
void unboundedCnecInOppositeDirection() {
FlowCnec cnec = initPreventiveCnecAdder().newThreshold().withUnit(MEGAWATT).withMax(500.).withSide(TwoSides.ONE).add().newThreshold().withUnit(MEGAWATT).withMax(200.).withSide(TwoSides.ONE).add().add();
assertEquals(200, cnec.getUpperBound(ONE, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(200, cnec.computeMargin(0., ONE, MEGAWATT), DOUBLE_TOLERANCE);
assertFalse(cnec.getLowerBound(ONE, MEGAWATT).isPresent());
}
@Test
void unboundedCnecInDirectDirection() {
FlowCnec cnec = initPreventiveCnecAdder().newThreshold().withUnit(MEGAWATT).withMin(-500.).withSide(TwoSides.ONE).add().newThreshold().withUnit(MEGAWATT).withMin(-200.).withSide(TwoSides.ONE).add().add();
assertEquals(-200, cnec.getLowerBound(ONE, MEGAWATT).orElseThrow(), DOUBLE_TOLERANCE);
assertEquals(200, cnec.computeMargin(0., ONE, MEGAWATT), DOUBLE_TOLERANCE);
assertFalse(cnec.getUpperBound(ONE, MEGAWATT).isPresent());
}
@Test
void marginsWithNegativeAndPositiveLimits() {
FlowCnec cnec = initPreventiveCnecAdder().newThreshold().withUnit(MEGAWATT).withMin(-200.).withMax(500.).withSide(TwoSides.ONE).add().add();
assertEquals(-100, cnec.computeMargin(-300, ONE, MEGAWATT), DOUBLE_TOLERANCE);
assertEquals(200, cnec.computeMargin(0, ONE, MEGAWATT), DOUBLE_TOLERANCE);
assertEquals(100, cnec.computeMargin(400, ONE, MEGAWATT), DOUBLE_TOLERANCE);
assertEquals(-300, cnec.computeMargin(800, ONE, MEGAWATT), DOUBLE_TOLERANCE);
}
// other
@Test
void testEqualsAndHashCode() {
FlowCnec cnec1 = initPreventiveCnecAdder().newThreshold().withUnit(MEGAWATT).withMax(1000.).withSide(TwoSides.ONE).add().add();
FlowCnec cnec2 = initPreventiveCnecAdder().withId("anotherId").newThreshold().withUnit(AMPERE).withMin(-1000.).withSide(TwoSides.ONE).add().withNominalVoltage(220.).add();
assertEquals(cnec1, cnec1);
assertNotEquals(cnec1, cnec2);
assertNotNull(cnec1);
assertNotEquals(1, cnec1);
assertEquals(cnec1.hashCode(), cnec1.hashCode());
assertNotEquals(cnec1.hashCode(), cnec2.hashCode());
}
@Test
void testIsConnected() {
Network network = NetworkImportsUtil.import12NodesNetwork();
NetworkImportsUtil.addDanglingLine(network);
// Branch
FlowCnec cnec1 = crac.newFlowCnec().withId("cnec-1-id").withNetworkElement("BBE1AA1 BBE2AA1 1").withInstant(PREVENTIVE_INSTANT_ID).newThreshold().withUnit(MEGAWATT).withMax(1000.).withSide(ONE).add().add();
assertTrue(cnec1.isConnected(network));
network.getBranch("BBE1AA1 BBE2AA1 1").getTerminal1().disconnect();
assertFalse(cnec1.isConnected(network));
network.getBranch("BBE1AA1 BBE2AA1 1").getTerminal1().connect();
network.getBranch("BBE1AA1 BBE2AA1 1").getTerminal2().disconnect();
assertFalse(cnec1.isConnected(network));
// DanglingLine
FlowCnec cnec2 = crac.newFlowCnec().withId("cnec-2-id").withNetworkElement("DL1").withInstant(PREVENTIVE_INSTANT_ID).newThreshold().withUnit(MEGAWATT).withMax(1000.).withSide(ONE).add().add();
assertTrue(cnec2.isConnected(network));
network.getDanglingLine("DL1").getTerminal().disconnect();
assertFalse(cnec2.isConnected(network));
// Generator
FlowCnec cnec3 = crac.newFlowCnec().withId("cnec-3-id").withNetworkElement("BBE2AA1 _generator").withInstant(PREVENTIVE_INSTANT_ID).newThreshold().withUnit(MEGAWATT).withMax(1000.).withSide(ONE).add().add();
assertTrue(cnec3.isConnected(network));
network.getGenerator("BBE2AA1 _generator").getTerminal().disconnect();
assertFalse(cnec3.isConnected(network));
}
}