From e8426433575cd2bdcaa919db3be076acf06b723f Mon Sep 17 00:00:00 2001 From: dbraquart <107846716+dbraquart@users.noreply.github.com> Date: Fri, 22 Dec 2023 14:34:53 +0100 Subject: [PATCH] add controls on ipMin/ipMax in voltage level modifications (#404) Signed-off-by: David BRAQUART --- .../modifications/ModificationUtils.java | 10 ++ .../VoltageLevelModification.java | 52 ++++++-- .../VoltageLevelCreationTest.java | 41 ++++++ .../VoltageLevelModificationTest.java | 123 +++++++++++++++++- .../server/utils/NetworkCreation.java | 2 +- .../server/utils/NetworkUtil.java | 8 ++ 6 files changed, 219 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/server/modifications/ModificationUtils.java b/src/main/java/org/gridsuite/modification/server/modifications/ModificationUtils.java index d18520a90..53bdc9410 100644 --- a/src/main/java/org/gridsuite/modification/server/modifications/ModificationUtils.java +++ b/src/main/java/org/gridsuite/modification/server/modifications/ModificationUtils.java @@ -256,9 +256,19 @@ public void controlVoltageLevelCreation(VoltageLevelCreationInfos voltageLevelCr throw new NetworkModificationException(CREATE_VOLTAGE_LEVEL_ERROR, "Coupling between same bus bar section is not allowed"); } + if (Objects.nonNull(voltageLevelCreationInfos.getIpMin()) && voltageLevelCreationInfos.getIpMin() < 0) { + throw new NetworkModificationException(CREATE_VOLTAGE_LEVEL_ERROR, "IpMin must be positive"); + } + if (Objects.nonNull(voltageLevelCreationInfos.getIpMax()) && voltageLevelCreationInfos.getIpMax() < 0) { + throw new NetworkModificationException(CREATE_VOLTAGE_LEVEL_ERROR, "IpMax must be positive"); + } if (Objects.nonNull(voltageLevelCreationInfos.getIpMin()) && Objects.isNull(voltageLevelCreationInfos.getIpMax())) { throw new NetworkModificationException(CREATE_VOLTAGE_LEVEL_ERROR, "IpMax is required"); } + if (Objects.nonNull(voltageLevelCreationInfos.getIpMin()) && Objects.nonNull(voltageLevelCreationInfos.getIpMax()) + && voltageLevelCreationInfos.getIpMin() > voltageLevelCreationInfos.getIpMax()) { + throw new NetworkModificationException(CREATE_VOLTAGE_LEVEL_ERROR, "IpMin cannot be greater than IpMax"); + } } private boolean checkBbs(Network network, String busbarSectionId1, String busbarSectionId2, Reporter subReporter) { diff --git a/src/main/java/org/gridsuite/modification/server/modifications/VoltageLevelModification.java b/src/main/java/org/gridsuite/modification/server/modifications/VoltageLevelModification.java index 1d97f4fbb..b57858021 100644 --- a/src/main/java/org/gridsuite/modification/server/modifications/VoltageLevelModification.java +++ b/src/main/java/org/gridsuite/modification/server/modifications/VoltageLevelModification.java @@ -10,17 +10,16 @@ import com.powsybl.commons.reporter.Report; import com.powsybl.commons.reporter.Reporter; import com.powsybl.commons.reporter.TypedValue; -import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.VoltageLevel; +import com.powsybl.iidm.network.*; import com.powsybl.iidm.network.extensions.IdentifiableShortCircuit; import com.powsybl.iidm.network.extensions.IdentifiableShortCircuitAdder; import org.gridsuite.modification.server.NetworkModificationException; import org.gridsuite.modification.server.dto.VoltageLevelModificationInfos; - import java.util.ArrayList; import java.util.List; +import java.util.Objects; -import static org.gridsuite.modification.server.NetworkModificationException.Type.VOLTAGE_LEVEL_NOT_FOUND; +import static org.gridsuite.modification.server.NetworkModificationException.Type.MODIFY_VOLTAGE_LEVEL_ERROR; /** * @author Seddik Yengui @@ -35,20 +34,49 @@ public VoltageLevelModification(VoltageLevelModificationInfos voltageLevelModifi @Override public void check(Network network) throws NetworkModificationException { - VoltageLevel voltageLevel = network.getVoltageLevel(modificationInfos.getEquipmentId()); - if (voltageLevel == null) { - throw new NetworkModificationException(VOLTAGE_LEVEL_NOT_FOUND, - String.format("Voltage level %s does not exist in network", modificationInfos.getEquipmentId())); + boolean ipMinSet = false; + boolean ipMaxSet = false; + if (Objects.nonNull(modificationInfos.getIpMin())) { + ipMinSet = true; + if (modificationInfos.getIpMin().getValue() < 0) { + throw new NetworkModificationException(MODIFY_VOLTAGE_LEVEL_ERROR, "IpMin must be positive"); + } + } + if (Objects.nonNull(modificationInfos.getIpMax())) { + ipMaxSet = true; + if (modificationInfos.getIpMax().getValue() < 0) { + throw new NetworkModificationException(MODIFY_VOLTAGE_LEVEL_ERROR, "IpMax must be positive"); + } + } + if (ipMinSet && ipMaxSet) { + if (modificationInfos.getIpMin().getValue() > modificationInfos.getIpMax().getValue()) { + throw new NetworkModificationException(MODIFY_VOLTAGE_LEVEL_ERROR, "IpMin cannot be greater than IpMax"); + } + } else if (ipMinSet || ipMaxSet) { + // only one Icc set: check with existing VL attributes + checkIccValuesAgainstEquipmentInNetwork(network, ipMinSet, ipMaxSet); + } + } + + private void checkIccValuesAgainstEquipmentInNetwork(Network network, boolean ipMinSet, boolean ipMaxSet) { + VoltageLevel existingVoltageLevel = ModificationUtils.getInstance().getVoltageLevel(network, modificationInfos.getEquipmentId()); + IdentifiableShortCircuit identifiableShortCircuit = existingVoltageLevel.getExtension(IdentifiableShortCircuit.class); + if (Objects.isNull(identifiableShortCircuit)) { + if (ipMinSet) { + throw new NetworkModificationException(MODIFY_VOLTAGE_LEVEL_ERROR, "IpMax is required"); + } + } else { + if (ipMinSet && modificationInfos.getIpMin().getValue() > identifiableShortCircuit.getIpMax() || + ipMaxSet && identifiableShortCircuit.getIpMin() > modificationInfos.getIpMax().getValue()) { + throw new NetworkModificationException(MODIFY_VOLTAGE_LEVEL_ERROR, "IpMin cannot be greater than IpMax"); + } } } @Override public void apply(Network network, Reporter subReporter) { - VoltageLevel voltageLevel = network.getVoltageLevel(modificationInfos.getEquipmentId()); - modifyVoltageLevel(subReporter, voltageLevel); - } + VoltageLevel voltageLevel = ModificationUtils.getInstance().getVoltageLevel(network, modificationInfos.getEquipmentId()); - private void modifyVoltageLevel(Reporter subReporter, VoltageLevel voltageLevel) { subReporter.report(Report.builder() .withKey("voltageLevelModification") .withDefaultMessage("Voltage level with id=${id} modified :") diff --git a/src/test/java/org/gridsuite/modification/server/modifications/VoltageLevelCreationTest.java b/src/test/java/org/gridsuite/modification/server/modifications/VoltageLevelCreationTest.java index 535e7168d..223f15b0a 100644 --- a/src/test/java/org/gridsuite/modification/server/modifications/VoltageLevelCreationTest.java +++ b/src/test/java/org/gridsuite/modification/server/modifications/VoltageLevelCreationTest.java @@ -156,6 +156,47 @@ public void testCreateWithBbsNotExist() throws Exception { assertNotNull(getNetwork().getVoltageLevel("vl_2")); } + @Test + public void testIpMinEqualsIpMax() throws Exception { + VoltageLevelCreationInfos vli = (VoltageLevelCreationInfos) buildModification(); + vli.setEquipmentId("vl_ok"); + vli.setIpMin(25.0); + vli.setIpMax(25.0); + String vliJsonObject = mapper.writeValueAsString(vli); + mockMvc.perform(post(getNetworkModificationUri()).content(vliJsonObject).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + // VL is created + assertNotNull(getNetwork().getVoltageLevel("vl_ok")); + } + + private void testIccWithError(Double ipMin, Double ipMax, String reportError) throws Exception { + VoltageLevelCreationInfos vli = (VoltageLevelCreationInfos) buildModification(); + vli.setEquipmentId("vl_ko"); + vli.setIpMin(ipMin); + vli.setIpMax(ipMax); + String vliJsonObject = mapper.writeValueAsString(vli); + mockMvc.perform(post(getNetworkModificationUri()).content(vliJsonObject).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + // VL could not have been created + assertNull(getNetwork().getVoltageLevel("vl_ko")); + assertLogMessage(new NetworkModificationException(CREATE_VOLTAGE_LEVEL_ERROR, reportError).getMessage(), vli.getErrorType().name(), reportService); + } + + @Test + public void testIpMinGreaterThanIpMax() throws Exception { + testIccWithError(15.1, 15.0, "IpMin cannot be greater than IpMax"); + } + + @Test + public void testIpMinNegative() throws Exception { + testIccWithError(-25.0, 15.0, "IpMin must be positive"); + } + + @Test + public void testIpMaxNegative() throws Exception { + testIccWithError(25.0, -15.0, "IpMax must be positive"); + } + public void testCreateWithShortCircuitExtension() throws Exception { VoltageLevelCreationInfos vli = (VoltageLevelCreationInfos) buildModification(); vli.setIpMin(null); diff --git a/src/test/java/org/gridsuite/modification/server/modifications/VoltageLevelModificationTest.java b/src/test/java/org/gridsuite/modification/server/modifications/VoltageLevelModificationTest.java index fc4c50338..0cea380aa 100644 --- a/src/test/java/org/gridsuite/modification/server/modifications/VoltageLevelModificationTest.java +++ b/src/test/java/org/gridsuite/modification/server/modifications/VoltageLevelModificationTest.java @@ -11,11 +11,10 @@ import com.powsybl.iidm.network.Network; import com.powsybl.iidm.network.VoltageLevel; import com.powsybl.iidm.network.extensions.IdentifiableShortCircuit; +import com.powsybl.iidm.network.extensions.IdentifiableShortCircuitAdder; import lombok.SneakyThrows; -import org.gridsuite.modification.server.dto.AttributeModification; -import org.gridsuite.modification.server.dto.ModificationInfos; -import org.gridsuite.modification.server.dto.OperationType; -import org.gridsuite.modification.server.dto.VoltageLevelModificationInfos; +import org.gridsuite.modification.server.NetworkModificationException; +import org.gridsuite.modification.server.dto.*; import org.gridsuite.modification.server.utils.NetworkCreation; import org.junit.Test; import org.junit.jupiter.api.Tag; @@ -24,6 +23,8 @@ import java.util.Map; import java.util.UUID; +import static org.gridsuite.modification.server.NetworkModificationException.Type.MODIFY_VOLTAGE_LEVEL_ERROR; +import static org.gridsuite.modification.server.utils.TestUtils.assertLogMessage; import static org.junit.Assert.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -121,6 +122,120 @@ public void testModifyShortCircuitExtension() throws Exception { assertEquals(0.2, identifiableShortCircuit2.getIpMin(), 0); } + private void testIpMinIpMaxNotChanged(Double ipMin, Double ipMax, String reportError) throws Exception { + final String vlWithBothIcc = "v3"; + final double beforeUpdateIpMin = 15.0; // cf NetworkCreation.java + final double beforeUpdateIpMax = 25.0; + + VoltageLevelModificationInfos vli = VoltageLevelModificationInfos.builder() + .stashed(false) + .equipmentId(vlWithBothIcc) + .build(); + if (ipMin != null) { + vli.setIpMin(new AttributeModification<>(ipMin, OperationType.SET)); + } + if (ipMax != null) { + vli.setIpMax(new AttributeModification<>(ipMax, OperationType.SET)); + } + applyModification(vli); + + // check the update has not been made + VoltageLevel voltageLevelUpdated = getNetwork().getVoltageLevel(vlWithBothIcc); + assertNotNull(voltageLevelUpdated); + IdentifiableShortCircuit identifiableShortCircuit1 = voltageLevelUpdated.getExtension(IdentifiableShortCircuit.class); + assertNotNull(identifiableShortCircuit1); + assertEquals(beforeUpdateIpMin, identifiableShortCircuit1.getIpMin(), 0); + assertEquals(beforeUpdateIpMax, identifiableShortCircuit1.getIpMax(), 0); + assertLogMessage(new NetworkModificationException(MODIFY_VOLTAGE_LEVEL_ERROR, reportError).getMessage(), vli.getErrorType().name(), reportService); + } + + @Test + public void testIpMinGreaterThanIpMax() throws Exception { + // check only modification inputs + testIpMinIpMaxNotChanged(30.0, 29.0, "IpMin cannot be greater than IpMax"); + } + + @Test + public void testIpMinNegative() throws Exception { + // check only modification inputs + testIpMinIpMaxNotChanged(-30.0, 0.0, "IpMin must be positive"); + } + + @Test + public void testIpMaxNegative() throws Exception { + // check only modification inputs + testIpMinIpMaxNotChanged(0.0, -12.0, "IpMax must be positive"); + } + + @Test + public void testIpMinGreaterThanEquipmentIpMax() throws Exception { + // check ipMin modification input against equipement ipMax real value (25.0) + testIpMinIpMaxNotChanged(30.0, null, "IpMin cannot be greater than IpMax"); + } + + @Test + public void testEquipmentIpMinGreaterThanIpMax() throws Exception { + // check ipMax modification input against equipement ipMin real value (15.0) + testIpMinIpMaxNotChanged(null, 14.9, "IpMin cannot be greater than IpMax"); + } + + @Test + public void testIpMinEqualsIpMax() throws Exception { + final String vlWithBothIcc = "v3"; + final double iccValue = 29.0; + VoltageLevelModificationInfos vli = (VoltageLevelModificationInfos) buildModification(); + vli.setIpMin(new AttributeModification<>(iccValue, OperationType.SET)); + vli.setIpMax(new AttributeModification<>(iccValue, OperationType.SET)); + vli.setEquipmentId(vlWithBothIcc); + applyModification(vli); + + // check the update has been made + VoltageLevel voltageLevelUpdated = getNetwork().getVoltageLevel(vlWithBothIcc); + assertNotNull(voltageLevelUpdated); + IdentifiableShortCircuit identifiableShortCircuit1 = voltageLevelUpdated.getExtension(IdentifiableShortCircuit.class); + assertNotNull(identifiableShortCircuit1); + assertEquals(iccValue, identifiableShortCircuit1.getIpMin(), 0); + assertEquals(iccValue, identifiableShortCircuit1.getIpMax(), 0); + } + + @Test + public void testSetIpMinOnEquipmentWithoutExtension() throws Exception { + final String vlWithNoIcc = "v2"; + VoltageLevelModificationInfos vli = VoltageLevelModificationInfos.builder() + .stashed(false) + .equipmentId(vlWithNoIcc) + .ipMin(new AttributeModification<>(10.0, OperationType.SET)) + .build(); + applyModification(vli); + // check the update has not been made + VoltageLevel voltageLevelUpdated = getNetwork().getVoltageLevel(vlWithNoIcc); + assertNotNull(voltageLevelUpdated); + assertNull(voltageLevelUpdated.getExtension(IdentifiableShortCircuit.class)); + assertLogMessage(new NetworkModificationException(MODIFY_VOLTAGE_LEVEL_ERROR, "IpMax is required").getMessage(), vli.getErrorType().name(), reportService); + } + + @Test + public void testSetIpMaxOnEquipmentWitOnlyIpMaxExtension() throws Exception { + final String vlName = "v2"; // has no ICC + getNetwork().getVoltageLevel(vlName) + .newExtension(IdentifiableShortCircuitAdder.class).withIpMax(30.0).add(); + + final double targetIpMax = 29.0; + VoltageLevelModificationInfos vli = VoltageLevelModificationInfos.builder() + .stashed(false) + .equipmentId(vlName) + .ipMax(new AttributeModification<>(targetIpMax, OperationType.SET)) + .build(); + applyModification(vli); + // check the update has been made + VoltageLevel voltageLevelUpdated = getNetwork().getVoltageLevel(vlName); + assertNotNull(voltageLevelUpdated); + IdentifiableShortCircuit identifiableShortCircuit1 = voltageLevelUpdated.getExtension(IdentifiableShortCircuit.class); + assertNotNull(identifiableShortCircuit1); + assertEquals(0, identifiableShortCircuit1.getIpMin(), 0); + assertEquals(targetIpMax, identifiableShortCircuit1.getIpMax(), 0); + } + private void applyModification(VoltageLevelModificationInfos infos) throws Exception { mockMvc.perform(post(getNetworkModificationUri()) .content(mapper.writeValueAsString(infos)) diff --git a/src/test/java/org/gridsuite/modification/server/utils/NetworkCreation.java b/src/test/java/org/gridsuite/modification/server/utils/NetworkCreation.java index 9b8f5d4a4..f5ec866c6 100644 --- a/src/test/java/org/gridsuite/modification/server/utils/NetworkCreation.java +++ b/src/test/java/org/gridsuite/modification/server/utils/NetworkCreation.java @@ -89,7 +89,7 @@ public static Network create(UUID uuid, boolean createHvdcLine, NetworkFactory n createStaticVarCompensator(v6, "v6Compensator", "v6Compensator", 5, StaticVarCompensator.RegulationMode.VOLTAGE, 380., 100, 2, 30); Substation s2 = createSubstation(network, "s2", "s2", Country.FR); - VoltageLevel v3 = createVoltageLevel(s2, "v3", "v3", TopologyKind.NODE_BREAKER, 380.0); + VoltageLevel v3 = createVoltageLevel(s2, "v3", "v3", TopologyKind.NODE_BREAKER, 380.0, 15.0, 25.0); createBusBarSection(v3, "3A", "3A", 0); createLoad(v3, "v3load", "v3load", 2, 0., 0., "cn3", 3, ConnectablePosition.Direction.BOTTOM); diff --git a/src/test/java/org/gridsuite/modification/server/utils/NetworkUtil.java b/src/test/java/org/gridsuite/modification/server/utils/NetworkUtil.java index 9ce610632..581376f64 100644 --- a/src/test/java/org/gridsuite/modification/server/utils/NetworkUtil.java +++ b/src/test/java/org/gridsuite/modification/server/utils/NetworkUtil.java @@ -11,6 +11,7 @@ import com.powsybl.iidm.network.extensions.BusbarSectionPositionAdder; import com.powsybl.iidm.network.extensions.ConnectablePosition; import com.powsybl.iidm.network.extensions.ConnectablePositionAdder; +import com.powsybl.iidm.network.extensions.IdentifiableShortCircuitAdder; public final class NetworkUtil { @@ -37,6 +38,13 @@ public static VoltageLevel createVoltageLevel(Substation s, String id, String na .add(); } + public static VoltageLevel createVoltageLevel(Substation s, String id, String name, + TopologyKind topology, double vNom, double ipMin, double ipMax) { + VoltageLevel vl = createVoltageLevel(s, id, name, topology, vNom); + vl.newExtension(IdentifiableShortCircuitAdder.class).withIpMin(ipMin).withIpMax(ipMax).add(); + return vl; + } + public static void createBusBarSection(VoltageLevel vl, String id, String name, int node) { var bbs = vl.getNodeBreakerView().newBusbarSection() .setId(id)