diff --git a/src/main/java/org/gridsuite/modification/dto/OperationalLimitsGroupModificationType.java b/src/main/java/org/gridsuite/modification/dto/OperationalLimitsGroupModificationType.java index 0d669e4c..3ddc9b34 100644 --- a/src/main/java/org/gridsuite/modification/dto/OperationalLimitsGroupModificationType.java +++ b/src/main/java/org/gridsuite/modification/dto/OperationalLimitsGroupModificationType.java @@ -17,4 +17,5 @@ public enum OperationalLimitsGroupModificationType { REPLACE, // Modification type for simple form modifications : MODIFY_OR_ADD, // if the OLG exists it is modified, if not it is created + DELETE, } diff --git a/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java b/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java index 3190f4ea..dbf5b345 100644 --- a/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java @@ -24,6 +24,7 @@ import static org.gridsuite.modification.NetworkModificationException.Type.BRANCH_MODIFICATION_ERROR; import static org.gridsuite.modification.dto.OperationalLimitsGroupInfos.Applicability.*; +import static org.gridsuite.modification.dto.OperationalLimitsGroupModificationType.DELETE; import static org.gridsuite.modification.utils.ModificationUtils.insertReportNode; /** @@ -157,13 +158,15 @@ private void detectApplicabilityChange(Branch branch, List branch, List olgReports, String groupId, OperationalLimitsGroupInfos.Applicability applicability) { + olgReports.add(ReportNode.newRootReportNode().withMessageTemplate("network.modification.applicabilityChanged") + .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, groupId) + .withUntypedValue(APPLICABILITY, applicability.toString()) + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + } + private void modifyOperationalLimitsGroups(Branch branch, List operationalLimitsInfos, ReportNode limitSetsReportNode) { @@ -210,18 +218,19 @@ private void modifyOperationalLimitsGroups(Branch branch, // here the modifications on an applicability EQUIPMENT are separated into two separate applications of both sides // because iidm has two separated sets of opLGs on the network object (and for better logs) - detectApplicabilityChange(branch, operationalLimitsInfos, opLGModifInfos, olgSetReports); + if (!opLGModifInfos.getModificationType().equals(DELETE)) { + detectApplicabilityChange(branch, operationalLimitsInfos, opLGModifInfos, olgReports); + } + if (applicability == SIDE1 || applicability == EQUIPMENT) { OperationalLimitsGroup operationalLimitsGroup1 = branch.getOperationalLimitsGroup1(opLGModifInfos.getId()).orElse(null); - applyModificationToOperationalLimitsGroup(branch::newOperationalLimitsGroup1, opLGModifInfos, operationalLimitsGroup1, - SIDE1, limitSetsReportNode); + applyModificationToOperationalLimitsGroup(branch, branch::newOperationalLimitsGroup1, opLGModifInfos, operationalLimitsGroup1, SIDE1, limitSetsReportNode); } if (applicability == SIDE2 || applicability == EQUIPMENT) { OperationalLimitsGroup operationalLimitsGroup2 = branch.getOperationalLimitsGroup2(opLGModifInfos.getId()).orElse(null); - applyModificationToOperationalLimitsGroup(branch::newOperationalLimitsGroup2, opLGModifInfos, operationalLimitsGroup2, - SIDE2, limitSetsReportNode); + applyModificationToOperationalLimitsGroup(branch, branch::newOperationalLimitsGroup2, opLGModifInfos, operationalLimitsGroup2, SIDE2, limitSetsReportNode); } } } @@ -420,6 +429,7 @@ private boolean updateConnection(Branch branch, TwoSides side, Boolean connec * therefore applicability is SIDE1 or SIDE2, not EQUIPMENT */ protected void applyModificationToOperationalLimitsGroup( + Branch branch, Function groupFactory, OperationalLimitsGroupModificationInfos opLGModificationInfos, OperationalLimitsGroup modifiedOperationalLimitsGroup, @@ -446,8 +456,28 @@ protected void applyModificationToOperationalLimitsGroup( case OperationalLimitsGroupModificationType.REPLACE: { replaceOpLG(groupFactory, opLGModificationInfos, modifiedOperationalLimitsGroup, applicability, limitsSetsReportNode); } break; - default: break; + case DELETE: { + removeOlg(branch, opLGModificationInfos, operationalLimitsGroupReports, applicability); + } + } + } + + private void removeOlg(Branch branch, OperationalLimitsGroupModificationInfos opLGModificationInfos, List operationalLimitsGroupReports, OperationalLimitsGroupInfos.Applicability applicability) { + if (applicability == SIDE1 && branch.getOperationalLimitsGroup1(opLGModificationInfos.getId()).isEmpty() || + applicability == SIDE2 && branch.getOperationalLimitsGroup2(opLGModificationInfos.getId()).isEmpty()) { + throw new PowsyblException("Cannot delete operational limit group " + opLGModificationInfos.getId() + " which has not been found in equipment on side " + applicability); + } + if (applicability == SIDE1) { + branch.removeOperationalLimitsGroup1(opLGModificationInfos.getId()); + } else if (applicability == SIDE2) { + branch.removeOperationalLimitsGroup2(opLGModificationInfos.getId()); } + operationalLimitsGroupReports.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.operationalLimitsGroupDeleted") + .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, opLGModificationInfos.getId()) + .withUntypedValue(SIDE, applicability.toString()) + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); } private void replaceOpLG(Function groupFactory, @@ -627,8 +657,10 @@ protected void modifyCurrentLimits( CurrentLimitsModificationInfos currentLimitsInfos = operationalLimitsGroupModificationInfos.getCurrentLimits(); boolean hasPermanent = currentLimitsInfos.getPermanentLimit() != null; if (hasPermanent) { - limitsReports.add(ModificationUtils.getInstance().buildModificationReport(currentLimits != null ? currentLimits.getPermanentLimit() : Double.NaN, - currentLimitsInfos.getPermanentLimit(), "IST")); + if (!(currentLimits != null && currentLimits.getPermanentLimit() == currentLimitsInfos.getPermanentLimit())) { + limitsReports.add(ModificationUtils.getInstance().buildModificationReport(currentLimits != null ? currentLimits.getPermanentLimit() : Double.NaN, + currentLimitsInfos.getPermanentLimit(), "IST")); + } limitsAdder.setPermanentLimit(currentLimitsInfos.getPermanentLimit()); } else { if (currentLimits != null) { diff --git a/src/main/resources/org/gridsuite/modification/reports.properties b/src/main/resources/org/gridsuite/modification/reports.properties index d41d8964..0875fc80 100644 --- a/src/main/resources/org/gridsuite/modification/reports.properties +++ b/src/main/resources/org/gridsuite/modification/reports.properties @@ -176,6 +176,7 @@ network.modification.lcc.creation = Lcc creation ${lccId} network.modification.lccCharacteristics = Characteristics network.modification.lccCreated = New lcc with id=${id} created network.modification.limitSetAdded = Limit set ${name} added +network.modification.operationalLimitsGroupDeleted = Limit set ${operationalLimitsGroupName} has been deleted on ${side} network.modification.operationalLimitsGroupAdded = Limit set ${operationalLimitsGroupName} added on ${side} network.modification.operationalLimitsGroupReplaced = Limit set ${operationalLimitsGroupName} has been replaced on ${side} network.modification.operationalLimitsGroupModified = Limit set ${operationalLimitsGroupName} has been modified on ${side} diff --git a/src/test/java/org/gridsuite/modification/modifications/LineModificationTest.java b/src/test/java/org/gridsuite/modification/modifications/LineModificationTest.java index 61459109..43cb9919 100644 --- a/src/test/java/org/gridsuite/modification/modifications/LineModificationTest.java +++ b/src/test/java/org/gridsuite/modification/modifications/LineModificationTest.java @@ -7,6 +7,7 @@ package org.gridsuite.modification.modifications; import com.fasterxml.jackson.core.type.TypeReference; +import com.powsybl.commons.PowsyblException; import com.powsybl.iidm.network.*; import com.powsybl.iidm.network.extensions.ConnectablePosition; import com.powsybl.iidm.network.extensions.Measurement; @@ -23,6 +24,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.gridsuite.modification.NetworkModificationException.Type.LINE_NOT_FOUND; import static org.gridsuite.modification.dto.OperationalLimitsGroupInfos.Applicability.*; +import static org.gridsuite.modification.dto.OperationalLimitsGroupModificationType.DELETE; import static org.gridsuite.modification.dto.OperationalLimitsGroupModificationType.MODIFY_OR_ADD; import static org.gridsuite.modification.dto.OperationalLimitsGroupModificationType.REPLACE; import static org.junit.jupiter.api.Assertions.*; @@ -334,6 +336,79 @@ void testConnectWhenNoSwitchesOpened() { assertEquals("BRANCH_MODIFICATION_ERROR : Could not connect equipment 'line1' on side 1 & 2", exception.getMessage()); } + @Test + void testDelete() { + Line line = getNetwork().getLine("line1"); + // side 1 + line.newOperationalLimitsGroup1("NewLimitsGroup1").newCurrentLimits() + .setPermanentLimit(10.0) + .add(); + line.newOperationalLimitsGroup1("NewLimitsGroup2").newCurrentLimits() + .setPermanentLimit(10.0) + .add(); + // side 2 + line.newOperationalLimitsGroup2("NewLimitsGroup1").newCurrentLimits() + .setPermanentLimit(10.0) + .add(); + line.newOperationalLimitsGroup2("NewLimitsGroup3").newCurrentLimits() + .setPermanentLimit(10.0) + .add(); + + // modification 1 remove olg on both side + OperationalLimitsGroupModificationInfos opLimitsGroupInfos1 = OperationalLimitsGroupModificationInfos.builder() + .id("NewLimitsGroup1").applicability(EQUIPMENT).modificationType(DELETE).build(); + LineModificationInfos lineModificationInfos1 = LineModificationInfos.builder() + .enableOLGModification(true) + .equipmentId("line1") + .operationalLimitsGroups(Collections.singletonList(opLimitsGroupInfos1)).build(); + lineModificationInfos1.toModification().apply(getNetwork()); + + assertTrue(line.getOperationalLimitsGroup1("NewLimitsGroup1").isEmpty()); + assertTrue(line.getOperationalLimitsGroup2("NewLimitsGroup1").isEmpty()); + assertTrue(line.getOperationalLimitsGroup1("NewLimitsGroup2").isPresent()); + assertTrue(line.getOperationalLimitsGroup2("NewLimitsGroup3").isPresent()); + + // modification 2 remove olg on side one + OperationalLimitsGroupModificationInfos opLimitsGroupInfos2 = OperationalLimitsGroupModificationInfos.builder() + .id("NewLimitsGroup2").applicability(SIDE1).modificationType(DELETE).build(); + LineModificationInfos lineModificationInfos2 = LineModificationInfos.builder() + .enableOLGModification(true) + .equipmentId("line1") + .operationalLimitsGroups(Collections.singletonList(opLimitsGroupInfos2)).build(); + lineModificationInfos2.toModification().apply(getNetwork()); + + assertTrue(line.getOperationalLimitsGroup1("NewLimitsGroup1").isEmpty()); + assertTrue(line.getOperationalLimitsGroup2("NewLimitsGroup1").isEmpty()); + assertTrue(line.getOperationalLimitsGroup1("NewLimitsGroup2").isEmpty()); + assertTrue(line.getOperationalLimitsGroup2("NewLimitsGroup3").isPresent()); + + // modification 3 remove olg on side two + OperationalLimitsGroupModificationInfos opLimitsGroupInfos3 = OperationalLimitsGroupModificationInfos.builder() + .id("NewLimitsGroup3").applicability(SIDE2).modificationType(DELETE).build(); + LineModificationInfos lineModificationInfos3 = LineModificationInfos.builder() + .enableOLGModification(true) + .equipmentId("line1") + .operationalLimitsGroups(Collections.singletonList(opLimitsGroupInfos3)).build(); + lineModificationInfos3.toModification().apply(getNetwork()); + + assertTrue(line.getOperationalLimitsGroup1("NewLimitsGroup1").isEmpty()); + assertTrue(line.getOperationalLimitsGroup2("NewLimitsGroup1").isEmpty()); + assertTrue(line.getOperationalLimitsGroup1("NewLimitsGroup2").isEmpty()); + assertTrue(line.getOperationalLimitsGroup2("NewLimitsGroup3").isEmpty()); + + // try to remove not existing group + OperationalLimitsGroupModificationInfos opLimitsGroupInfos4 = OperationalLimitsGroupModificationInfos.builder() + .id("doesNotExist").applicability(SIDE2).modificationType(DELETE).build(); + LineModificationInfos lineModificationInfos4 = LineModificationInfos.builder() + .enableOLGModification(true) + .equipmentId("line1") + .operationalLimitsGroups(Collections.singletonList(opLimitsGroupInfos4)).build(); + Network network = getNetwork(); + AbstractModification modification = lineModificationInfos4.toModification(); + String errorMessage = assertThrows(PowsyblException.class, () -> modification.apply(network)).getMessage(); + assertEquals("Cannot delete operational limit group doesNotExist which has not been found in equipment on side SIDE2", errorMessage); + } + private void changeLineConnectionState(Line existingEquipment, boolean expectedState) { LineModificationInfos modificationInfos = (LineModificationInfos) buildModification(); modificationInfos.setTerminal1Connected(new AttributeModification<>(expectedState, OperationType.SET));