AbstractShuntCompensatorTest.java
/**
* Copyright (c) 2017, 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.NoEquipmentNetworkFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
public abstract class AbstractShuntCompensatorTest {
interface FooModel extends ShuntCompensatorModel {
}
private static final String INVALID = "invalid";
private static final String SHUNT = "shunt";
private static final String TEST_MULTI_VARIANT = "testMultiVariant";
private Network network;
private VoltageLevel voltageLevel;
private Terminal terminal;
@BeforeEach
public void setUp() {
network = NoEquipmentNetworkFactory.create();
network.getVoltageLevel("vl2").newLoad()
.setId("load")
.setBus("busB")
.setConnectableBus("busB")
.setP0(0)
.setQ0(0)
.add();
terminal = network.getLoad("load").getTerminal();
voltageLevel = network.getVoltageLevel("vl1");
}
@Test
public void baseLinearShuntTest() {
// adder
ShuntCompensatorAdder adder = createShuntAdder(SHUNT, "shuntName", 6, terminal, true, 200, 10);
adder.newLinearModel()
.setBPerSection(5.0)
.setGPerSection(4.0)
.setMaximumSectionCount(10)
.add();
ShuntCompensator shuntCompensator = adder.add();
assertEquals(IdentifiableType.SHUNT_COMPENSATOR, shuntCompensator.getType());
assertEquals("shuntName", shuntCompensator.getOptionalName().orElse(null));
assertEquals(SHUNT, shuntCompensator.getId());
assertEquals(6, shuntCompensator.getSectionCount());
assertEquals(10, shuntCompensator.getMaximumSectionCount());
assertEquals(30.0, shuntCompensator.getB(), 0.0);
assertEquals(24.0, shuntCompensator.getG(), 0.0);
assertEquals(0.0, shuntCompensator.getB(0), 0.0);
assertEquals(30.0, shuntCompensator.getB(6), 0.0);
assertEquals(0.0, shuntCompensator.getG(0), 0.0);
assertEquals(24.0, shuntCompensator.getG(6), 0.0);
assertSame(terminal, shuntCompensator.getRegulatingTerminal());
assertTrue(shuntCompensator.isVoltageRegulatorOn());
assertEquals(200, shuntCompensator.getTargetV(), 0.0);
assertEquals(10, shuntCompensator.getTargetDeadband(), 0.0);
assertEquals(ShuntCompensatorModelType.LINEAR, shuntCompensator.getModelType());
ShuntCompensatorLinearModel shuntLinearModel = shuntCompensator.getModel(ShuntCompensatorLinearModel.class);
assertEquals(5.0, shuntLinearModel.getBPerSection(), 0.0);
assertEquals(4.0, shuntLinearModel.getGPerSection(), 0.0);
// try get incorrect shunt model
try {
shuntCompensator.getModel(FooModel.class);
fail();
} catch (ValidationException ignored) {
// ignore
}
// currentSectionCount
try {
shuntCompensator.setSectionCount(-1);
fail();
} catch (ValidationException ignored) {
// ignore
}
try {
// max = 10, current could not be 20
shuntCompensator.setSectionCount(20);
fail();
} catch (ValidationException ignored) {
// ignore
}
shuntCompensator.setSectionCount(6);
assertEquals(6, shuntCompensator.getSectionCount());
// b
try {
shuntCompensator.getB(-1);
fail();
} catch (PowsyblException ignored) {
// ignore
}
try {
shuntCompensator.getB(1000);
fail();
} catch (PowsyblException ignored) {
// ignore
}
// g
try {
shuntCompensator.getG(-1);
fail();
} catch (PowsyblException ignored) {
// ignore
}
try {
shuntCompensator.getG(1000);
fail();
} catch (PowsyblException ignored) {
// ignore
}
// for linear model
shuntLinearModel.setBPerSection(-1.0);
assertEquals(-1.0, shuntLinearModel.getBPerSection(), 0.0);
assertEquals(-6.0, shuntCompensator.getB(), 0.0);
// gPerSection
shuntLinearModel.setGPerSection(-2.0);
assertEquals(-2.0, shuntLinearModel.getGPerSection(), 0.0);
assertEquals(-12.0, shuntCompensator.getG(), 0.0);
// maximumSectionCount
try {
shuntLinearModel.setMaximumSectionCount(1);
fail();
} catch (ValidationException ignored) {
// ignore
}
shuntLinearModel.setMaximumSectionCount(20);
assertEquals(20, shuntCompensator.getMaximumSectionCount());
// remove
int count = network.getShuntCompensatorCount();
shuntCompensator.remove();
assertNull(network.getShuntCompensator(SHUNT));
assertNotNull(shuntCompensator);
assertEquals(count - 1L, network.getShuntCompensatorCount());
// Reuse adder tests
// Create second model from same adder
adder.setSectionCount(2)
.newNonLinearModel()
.beginSection()
.setB(5.0)
.setG(2.0)
.endSection()
.beginSection()
.setB(6.0)
.setG(2.0)
.endSection()
.add();
// Create second ShuntCompensator from same adder
ShuntCompensator shuntCompensator2 = adder.setId(SHUNT + "_2").add();
assertNotSame(shuntCompensator.getModel(), shuntCompensator2.getModel());
assertEquals(ShuntCompensatorModelType.NON_LINEAR, shuntCompensator2.getModelType());
}
@Test
public void testDefaultShuntCompensator() {
ShuntCompensatorAdder adder = createShuntAdder(SHUNT, "shuntName", 6, terminal, true, 200, 10);
adder.newLinearModel()
.setBPerSection(5.0)
.setMaximumSectionCount(10)
.add();
ShuntCompensator shuntCompensator = adder.add();
ShuntCompensatorLinearModel shuntLinearModel = shuntCompensator.getModel(ShuntCompensatorLinearModel.class);
assertTrue(Double.isNaN(shuntLinearModel.getGPerSection()));
assertEquals(0.0, shuntCompensator.getG(), 0.0);
shuntCompensator.remove();
adder.setSectionCount(1)
.newNonLinearModel()
.beginSection()
.setB(5.0)
.endSection()
.add();
ShuntCompensator shuntCompensator2 = adder.setId(SHUNT + "_2").add();
assertEquals(0.0, shuntCompensator2.getG(0), 0.0);
}
@Test
public void invalidbPerSection() {
ValidationException e = assertThrows(ValidationException.class, () -> createLinearShunt(INVALID, INVALID, Double.NaN, Double.NaN, 5, 10, null, false, Double.NaN, Double.NaN));
assertTrue(e.getMessage().contains("section susceptance is invalid"));
}
@Test
public void invalidNegativeMaxPerSection() {
ValidationException e = assertThrows(ValidationException.class, () -> createLinearShunt(INVALID, INVALID, 2.0, Double.NaN, 0, -1, null, false, Double.NaN, Double.NaN));
assertTrue(e.getMessage().contains("should be greater than 0"));
}
@Test
public void baseNonLinearShuntTest() {
// adder
ShuntCompensatorAdder adder = voltageLevel.newShuntCompensator()
.setId(SHUNT)
.setName("shuntName")
.setConnectableBus("busA")
.setSectionCount(1)
.setRegulatingTerminal(terminal)
.setVoltageRegulatorOn(true)
.setTargetV(200)
.setTargetDeadband(10);
adder.newNonLinearModel()
.beginSection()
.setB(5.0)
.setG(2.0)
.endSection()
.beginSection()
.setB(6.0)
.setG(2.0)
.endSection()
.add();
ShuntCompensator shuntCompensator = adder.add();
assertEquals(IdentifiableType.SHUNT_COMPENSATOR, shuntCompensator.getType());
assertEquals("shuntName", shuntCompensator.getOptionalName().orElse(null));
assertEquals("shuntName", shuntCompensator.getNameOrId());
assertEquals(SHUNT, shuntCompensator.getId());
assertEquals(1, shuntCompensator.getSectionCount());
assertEquals(2, shuntCompensator.getMaximumSectionCount());
assertEquals(5.0, shuntCompensator.getB(), 0.0);
assertEquals(2.0, shuntCompensator.getG(), 0.0);
assertEquals(0.0, shuntCompensator.getB(0), 0.0);
assertEquals(5.0, shuntCompensator.getB(1), 0.0);
assertEquals(6.0, shuntCompensator.getB(2), 0.0);
assertEquals(0.0, shuntCompensator.getG(0), 0.0);
assertEquals(2.0, shuntCompensator.getG(1), 0.0);
assertEquals(2.0, shuntCompensator.getG(2), 0.0);
assertSame(terminal, shuntCompensator.getRegulatingTerminal());
assertTrue(shuntCompensator.isVoltageRegulatorOn());
assertEquals(200, shuntCompensator.getTargetV(), 0.0);
assertEquals(10, shuntCompensator.getTargetDeadband(), 0.0);
assertEquals(ShuntCompensatorModelType.NON_LINEAR, shuntCompensator.getModelType());
ShuntCompensatorNonLinearModel shuntNonLinearModel = shuntCompensator.getModel(ShuntCompensatorNonLinearModel.class);
assertEquals(2, shuntNonLinearModel.getAllSections().size());
// try get incorrect shunt model
try {
shuntCompensator.getModel(FooModel.class);
fail();
} catch (ValidationException ignored) {
// ignore
}
// currentSectionCount
try {
shuntCompensator.setSectionCount(-1);
fail();
} catch (ValidationException ignored) {
// ignore
}
try {
// exiting = 0, 1, 2, current could not be 20
shuntCompensator.setSectionCount(20);
fail();
} catch (ValidationException ignored) {
// ignore
}
shuntCompensator.setSectionCount(2);
assertEquals(2, shuntCompensator.getSectionCount());
// b
try {
shuntCompensator.getB(-1);
fail();
} catch (PowsyblException ignored) {
// ignore
}
try {
shuntCompensator.getB(1000);
fail();
} catch (PowsyblException ignored) {
// ignore
}
// g
try {
shuntCompensator.getG(-1);
fail();
} catch (PowsyblException ignored) {
// ignore
}
try {
shuntCompensator.getG(1000);
fail();
} catch (PowsyblException ignored) {
// ignore
}
// Reuse adder tests
ShuntCompensator shuntCompensator2 = adder.setId(SHUNT + "_2").add();
assertNotSame(shuntCompensator.getModel(), shuntCompensator2.getModel());
}
@Test
public void invalidEmptyNonLinearModel() {
ShuntCompensatorAdder adder = createShuntAdder(INVALID, INVALID, 6, terminal, true, 200, 10);
ValidationException e = assertThrows(ValidationException.class, () -> adder.newNonLinearModel().add());
assertTrue(e.getMessage().contains("a shunt compensator must have at least one section"));
}
@Test
public void undefinedModel() {
ValidationException e = assertThrows(ValidationException.class, () -> voltageLevel.newShuntCompensator()
.setId(INVALID)
.setName(INVALID)
.setConnectableBus("busA")
.setSectionCount(6)
.setRegulatingTerminal(terminal)
.setVoltageRegulatorOn(false)
.setTargetV(Double.NaN)
.setTargetDeadband(Double.NaN)
.add());
assertTrue(e.getMessage().contains("the shunt compensator model has not been defined"));
}
@Test
public void regulationTest() {
ShuntCompensator shuntCompensator = createLinearShunt(SHUNT, "shuntName", 5.0, 4.0, 6, 10, terminal, true,
200, 10);
// regulating terminal
try {
Network tmp = EurostagTutorialExample1Factory.create();
Terminal tmpTerminal = tmp.getGenerator("GEN").getTerminal();
shuntCompensator.setRegulatingTerminal(tmpTerminal);
fail();
} catch (ValidationException ignored) {
// ignore
}
shuntCompensator.setRegulatingTerminal(null);
assertSame(shuntCompensator.getTerminal(), shuntCompensator.getRegulatingTerminal());
// voltageRegulatorOn
shuntCompensator.setVoltageRegulatorOn(false);
assertFalse(shuntCompensator.isVoltageRegulatorOn());
// targetV
try {
shuntCompensator.setVoltageRegulatorOn(true);
shuntCompensator.setTargetV(Double.NaN);
fail();
} catch (ValidationException ignored) {
// ignore
}
try {
shuntCompensator.setVoltageRegulatorOn(false);
shuntCompensator.setTargetV(Double.NaN);
shuntCompensator.setVoltageRegulatorOn(true);
fail();
} catch (ValidationException ignored) {
// ignore
}
shuntCompensator.setTargetV(400);
assertEquals(400, shuntCompensator.getTargetV(), 0.0);
// targetDeadband
try {
shuntCompensator.setTargetDeadband(-1.0);
fail();
} catch (ValidationException ignored) {
// ignore
}
try {
shuntCompensator.setVoltageRegulatorOn(false);
shuntCompensator.setTargetDeadband(Double.NaN);
shuntCompensator.setVoltageRegulatorOn(true);
fail();
} catch (ValidationException ignored) {
// ignore
}
shuntCompensator.setTargetDeadband(5.0);
assertEquals(5.0, shuntCompensator.getTargetDeadband(), 0.0);
}
@Test
public void invalidRegulatingTerminal() {
Network tmp = EurostagTutorialExample1Factory.create();
Terminal tmpTerminal = tmp.getGenerator("GEN").getTerminal();
ValidationException e = assertThrows(ValidationException.class, () -> createLinearShunt(INVALID, INVALID, 2.0, 1.0, 0, 10, tmpTerminal, false, Double.NaN, Double.NaN));
assertTrue(e.getMessage().contains("regulating terminal is not part of the network"));
}
@Test
public void invalidTargetV() {
ValidationException e = assertThrows(ValidationException.class, () -> createLinearShunt(INVALID, INVALID, 2.0, 1.0, 0, 10, null, true, -10, 0));
assertTrue(e.getMessage().contains("invalid value (-10.0) for voltage setpoint"));
}
@Test
public void invalidNanTargetV() {
ValidationException e = assertThrows(ValidationException.class, () -> createLinearShunt(INVALID, INVALID, 5.0, 1.0, 6, 10, null, true, Double.NaN, 0));
assertTrue(e.getMessage().contains("invalid value (NaN) for voltage setpoint (voltage regulator is on)"));
}
@Test
public void invalidTargetDeadband() {
ValidationException e = assertThrows(ValidationException.class, () -> createLinearShunt(INVALID, INVALID, 2.0, 1.0, 0, 10, null, false, Double.NaN, -10));
assertTrue(e.getMessage().contains("Unexpected value for target deadband of shunt compensator: -10.0"));
}
@Test
public void testSetterGetterInMultiVariants() {
VariantManager variantManager = network.getVariantManager();
createLinearShunt(TEST_MULTI_VARIANT, TEST_MULTI_VARIANT, 2.0, 1.0, 5, 10, terminal, true, 200, 10);
ShuntCompensator shunt = network.getShuntCompensator(TEST_MULTI_VARIANT);
List<String> variantsToAdd = Arrays.asList("s1", "s2", "s3", "s4");
variantManager.cloneVariant(VariantManagerConstants.INITIAL_VARIANT_ID, variantsToAdd);
variantManager.setWorkingVariant("s4");
// check values cloned by extend
assertEquals(5, shunt.getSectionCount());
assertEquals(10.0, shunt.getB(), 0.0); // 2*5
assertEquals(5.0, shunt.getG(), 0.0); // 1*5
// change values in s4
shunt.setSectionCount(4)
.setVoltageRegulatorOn(false)
.setTargetV(220)
.setTargetDeadband(5.0);
// remove s2
variantManager.removeVariant("s2");
variantManager.cloneVariant("s4", "s2b");
variantManager.setWorkingVariant("s2b");
// check values cloned by allocate
assertEquals(4, shunt.getSectionCount());
assertEquals(8.0, shunt.getB(), 0.0); // 2*4
assertEquals(4.0, shunt.getG(), 0.0); // 1*4
assertFalse(shunt.isVoltageRegulatorOn());
assertEquals(220, shunt.getTargetV(), 0.0);
assertEquals(5.0, shunt.getTargetDeadband(), 0.0);
// recheck initial variant value
variantManager.setWorkingVariant(VariantManagerConstants.INITIAL_VARIANT_ID);
assertEquals(5, shunt.getSectionCount());
assertEquals(10.0, shunt.getB(), 0.0); // 2*5
assertEquals(5.0, shunt.getG(), 0.0); // 1*5
assertTrue(shunt.isVoltageRegulatorOn());
assertEquals(200, shunt.getTargetV(), 0.0);
assertEquals(10, shunt.getTargetDeadband(), 0.0);
// remove working variant s4
variantManager.setWorkingVariant("s4");
variantManager.removeVariant("s4");
try {
shunt.getSectionCount();
fail();
} catch (Exception ignored) {
// ignore
}
try {
shunt.isVoltageRegulatorOn();
fail();
} catch (Exception ignored) {
// ignore
}
try {
shunt.getTargetV();
fail();
} catch (Exception ignored) {
// ignore
}
try {
shunt.getTargetDeadband();
fail();
} catch (Exception ignored) {
// ignore
}
// check we delete a single variant's values
variantManager.setWorkingVariant("s3");
assertEquals(5, shunt.getSectionCount());
}
@Test
public void testSetTerminalP() {
// For linear and non-linear shunt compensators:
// Allow setting active power value on a shunt with valid G and
// Allow setting active power value on a shunt created with an invalid G
ShuntCompensator sgb = createLinearShunt("SHUNT_GB", "SHUNT", 2.0, 1.0, 5, 10, terminal, true, 200, 10);
sgb.getTerminal().setP(10);
assertEquals(10, sgb.getTerminal().getP(), 0.0);
ShuntCompensator sb = createLinearShunt("SHUNT_B", "SHUNT", 2.0, Double.NaN, 5, 10, terminal, true, 200, 10);
sb.getTerminal().setP(10);
assertEquals(10, sb.getTerminal().getP(), 0.0);
ShuntCompensator sgbNonLinear = createNonLinearShunt("SHUNT_GB_NL", "SHUNT", terminal, true, 200, 10, 1.0, 2.0);
sgbNonLinear.getTerminal().setP(10);
assertEquals(10, sgbNonLinear.getTerminal().getP(), 0.0);
// Expect an exception when setting active power value on a shunt with invalid G
ShuntCompensator sbNonLinear = createNonLinearShunt("SHUNT_B_NL", "SHUNT", terminal, true, 200, 10, 2.0, Double.NaN);
sbNonLinear.getTerminal().setP(10);
assertEquals(10, sbNonLinear.getTerminal().getP(), 0.0);
}
private ShuntCompensator createLinearShunt(String id, String name, double bPerSection, double gPerSection, int sectionCount, int maxSectionCount, Terminal regulatingTerminal, boolean voltageRegulatorOn, double targetV, double targetDeadband) {
return createShuntAdder(id, name, sectionCount, regulatingTerminal, voltageRegulatorOn, targetV, targetDeadband)
.newLinearModel()
.setBPerSection(bPerSection)
.setGPerSection(gPerSection)
.setMaximumSectionCount(maxSectionCount)
.add()
.add();
}
private ShuntCompensator createNonLinearShunt(String id, String name, Terminal regulatingTerminal, boolean voltageRegulatorOn, double targetV, double targetDeadband, double b0, double g0) {
return createShuntAdder(id, name, 1, regulatingTerminal, voltageRegulatorOn, targetV, targetDeadband)
.newNonLinearModel()
.beginSection()
.setB(b0)
.setG(g0)
.endSection()
.add()
.add();
}
private ShuntCompensatorAdder createShuntAdder(String id, String name, int sectionCount, Terminal regulatingTerminal, boolean voltageRegulatorOn, double targetV, double targetDeadband) {
return voltageLevel.newShuntCompensator()
.setId(id)
.setName(name)
.setConnectableBus("busA")
.setSectionCount(sectionCount)
.setRegulatingTerminal(regulatingTerminal)
.setVoltageRegulatorOn(voltageRegulatorOn)
.setTargetV(targetV)
.setTargetDeadband(targetDeadband);
}
}