From a1ee8a6f023c4e047fdd07e46eb26b49149e7530 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Fri, 21 Nov 2025 16:40:38 +0100 Subject: [PATCH 01/22] first refacto Signed-off-by: Mathieu DEHARBE --- .../byfilter/equipmentfield/LineField.java | 5 +- .../TwoWindingsTransformerField.java | 5 +- .../AbstractBranchModification.java | 739 +----------------- .../modifications/olg/OlgModification.java | 461 +++++++++++ .../modifications/olg/OlgsModification.java | 201 +++++ .../modification/utils/OlgUtils.java | 166 ++++ 6 files changed, 842 insertions(+), 735 deletions(-) create mode 100644 src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java create mode 100644 src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java create mode 100644 src/main/java/org/gridsuite/modification/utils/OlgUtils.java diff --git a/src/main/java/org/gridsuite/modification/dto/byfilter/equipmentfield/LineField.java b/src/main/java/org/gridsuite/modification/dto/byfilter/equipmentfield/LineField.java index c62f8d9d..41fa06e2 100644 --- a/src/main/java/org/gridsuite/modification/dto/byfilter/equipmentfield/LineField.java +++ b/src/main/java/org/gridsuite/modification/dto/byfilter/equipmentfield/LineField.java @@ -12,6 +12,7 @@ import groovyjarjarantlr4.v4.runtime.misc.NotNull; import org.gridsuite.modification.dto.AttributeModification; import org.gridsuite.modification.dto.OperationType; +import org.gridsuite.modification.utils.OlgUtils; import org.gridsuite.modification.utils.ModificationUtils; import static org.gridsuite.modification.NetworkModificationException.Type.MODIFY_LINE_ERROR; @@ -86,7 +87,7 @@ private static void setNewStringValue(Line line, LineField field, String newValu .stream() .map(OperationalLimitsGroup::getId) .toList(), 1); - modifySelectedOperationalLimitsGroup(line, attributeModification, TwoSides.ONE, null); + OlgUtils.modifySelectedOperationalLimitsGroup(line, attributeModification, TwoSides.ONE, null); } case SELECTED_OPERATIONAL_LIMITS_GROUP_2 -> { ModificationUtils.checkLimitsGroupExist(errorMessage, newValue, MODIFY_LINE_ERROR, @@ -94,7 +95,7 @@ private static void setNewStringValue(Line line, LineField field, String newValu .stream() .map(OperationalLimitsGroup::getId) .toList(), 2); - modifySelectedOperationalLimitsGroup(line, attributeModification, TwoSides.TWO, null); + OlgUtils.modifySelectedOperationalLimitsGroup(line, attributeModification, TwoSides.TWO, null); } default -> throw new IllegalArgumentException(String.format("field %s is not a string modification", field)); } diff --git a/src/main/java/org/gridsuite/modification/dto/byfilter/equipmentfield/TwoWindingsTransformerField.java b/src/main/java/org/gridsuite/modification/dto/byfilter/equipmentfield/TwoWindingsTransformerField.java index 6d3757ca..b09215ad 100644 --- a/src/main/java/org/gridsuite/modification/dto/byfilter/equipmentfield/TwoWindingsTransformerField.java +++ b/src/main/java/org/gridsuite/modification/dto/byfilter/equipmentfield/TwoWindingsTransformerField.java @@ -13,6 +13,7 @@ import jakarta.validation.constraints.NotNull; import org.gridsuite.modification.dto.AttributeModification; import org.gridsuite.modification.dto.OperationType; +import org.gridsuite.modification.utils.OlgUtils; import org.gridsuite.modification.utils.ModificationUtils; import java.util.List; @@ -193,7 +194,7 @@ private static void setNewStringValue(TwoWindingsTransformer transformer, TwoWin .stream() .map(OperationalLimitsGroup::getId) .toList(), 1); - modifySelectedOperationalLimitsGroup(transformer, attributeModification, TwoSides.ONE, null); + OlgUtils.modifySelectedOperationalLimitsGroup(transformer, attributeModification, TwoSides.ONE, null); } case SELECTED_OPERATIONAL_LIMITS_GROUP_2 -> { ModificationUtils.checkLimitsGroupExist(errorMessage, newValue, MODIFY_LINE_ERROR, @@ -201,7 +202,7 @@ private static void setNewStringValue(TwoWindingsTransformer transformer, TwoWin .stream() .map(OperationalLimitsGroup::getId) .toList(), 2); - modifySelectedOperationalLimitsGroup(transformer, attributeModification, TwoSides.TWO, null); + OlgUtils.modifySelectedOperationalLimitsGroup(transformer, attributeModification, TwoSides.TWO, null); } default -> throw new IllegalArgumentException(String.format("field %s is not a string modification", field)); } diff --git a/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java b/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java index 4617d7b2..1fad7ced 100644 --- a/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java @@ -6,25 +6,20 @@ */ package org.gridsuite.modification.modifications; -import com.powsybl.commons.PowsyblException; import com.powsybl.commons.report.ReportNode; import com.powsybl.commons.report.TypedValue; import com.powsybl.iidm.network.*; import com.powsybl.iidm.network.extensions.*; -import jakarta.validation.constraints.NotNull; import org.gridsuite.modification.NetworkModificationException; import org.gridsuite.modification.dto.*; +import org.gridsuite.modification.modifications.olg.OlgsModification; +import org.gridsuite.modification.utils.OlgUtils; import org.gridsuite.modification.utils.ModificationUtils; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; import java.util.*; -import java.util.function.Function; import java.util.stream.Collectors; 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; /** @@ -32,14 +27,9 @@ */ public abstract class AbstractBranchModification extends AbstractModification { - private static final String DURATION = "duration"; public static final String NAME = "name"; public static final String VALUE = "value"; private static final String VALIDITY = "validity"; - private static final String LIMIT_ACCEPTABLE_DURATION = "limitAcceptableDuration"; - public static final String OPERATIONAL_LIMITS_GROUP_NAME = "operationalLimitsGroupName"; - private static final String SIDE = "side"; - private static final String APPLICABILITY = "applicability"; protected final BranchModificationInfos modificationInfos; @@ -72,14 +62,14 @@ protected void modifyBranch(Branch branch, BranchModificationInfos branchModi boolean modifyOLG = branchModificationInfos.getEnableOLGModification() == null || branchModificationInfos.getEnableOLGModification(); - if (modifyOLG && !CollectionUtils.isEmpty(branchModificationInfos.getOperationalLimitsGroups())) { + if (modifyOLG) { limitsReportNode = subReportNode.newReportNode().withMessageTemplate("network.modification.limits").add(); ReportNode limitSetsReportNode = limitsReportNode.newReportNode().withMessageTemplate("network.modification.limitsSets").add(); - modifyOperationalLimitsGroups( + new OlgsModification( branch, - branchModificationInfos.getOperationalLimitsGroupsModificationType(), branchModificationInfos.getOperationalLimitsGroups(), - limitSetsReportNode); + limitSetsReportNode + ).modifyOperationalLimitsGroups(branchModificationInfos.getOperationalLimitsGroupsModificationType()); } applySelectedOLGs(branch, activeOLGReports); @@ -93,188 +83,9 @@ protected void modifyBranch(Branch branch, BranchModificationInfos branchModi updateConnections(branch, branchModificationInfos); } - private void copyOperationalLimitsGroup(CurrentLimitsAdder limitsAdder, OperationalLimitsGroup opLimitGroupToCopy) { - // Copy all limits of the other side - opLimitGroupToCopy.getCurrentLimits().ifPresent(currentLimits -> { - limitsAdder.setPermanentLimit(currentLimits.getPermanentLimit()); - - for (LoadingLimits.TemporaryLimit tempLimit : currentLimits.getTemporaryLimits()) { - addTemporaryLimit(limitsAdder, tempLimit.getName(), tempLimit.getValue(), tempLimit.getAcceptableDuration()); - } - limitsAdder.add(); - }); - } - - private void moveLimitSetToTheOtherSide(Branch branch, List modificationInfos, - OperationalLimitsGroup limitsGroupToCopy, String modifiedLimitSet, - boolean isSide1, List olgReports) { - // if we have only one limit set with the same name but applicability is not good - // we should copy existing limit set on the right side and removed it from the other side - if (modificationInfos.stream().filter(limitSet -> limitSet.getId().equals(modifiedLimitSet)).toList().size() == 1) { - // Copy operational limits group to the other side - OperationalLimitsGroup limitsGroup = isSide1 ? branch.newOperationalLimitsGroup1(limitsGroupToCopy.getId()) - : branch.newOperationalLimitsGroup2(limitsGroupToCopy.getId()); - copyOperationalLimitsGroup(limitsGroup.newCurrentLimits(), limitsGroupToCopy); - - olgReports.add(ReportNode.newRootReportNode().withMessageTemplate("network.modification.applicabilityChanged") - .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, limitsGroupToCopy.getId()) - .withUntypedValue(APPLICABILITY, isSide1 ? SIDE1.toString() : SIDE2.toString()) - .withSeverity(TypedValue.INFO_SEVERITY) - .build()); - // Remove copied operational limits group - if (isSide1) { - branch.removeOperationalLimitsGroup2(modifiedLimitSet); - } else { - branch.removeOperationalLimitsGroup1(modifiedLimitSet); - } - } - } - - private boolean shouldDeletedOtherSide(Branch branch, List modificationInfos, - OperationalLimitsGroupModificationInfos limitsModifInfos) { - boolean hasModificationOnSideOne = !modificationInfos.stream().filter(opLimitModifInfo -> - opLimitModifInfo.getId().equals(limitsModifInfos.getId()) && opLimitModifInfo.getApplicability().equals(SIDE1)) - .toList().isEmpty(); - - boolean hasModificationOnSideTwo = !modificationInfos.stream().filter(opLimitModifInfo -> - opLimitModifInfo.getId().equals(limitsModifInfos.getId()) && opLimitModifInfo.getApplicability().equals(SIDE2)) - .toList().isEmpty(); - - switch (limitsModifInfos.getApplicability()) { - case SIDE1 -> { - return !hasModificationOnSideTwo && branch.getOperationalLimitsGroup2(limitsModifInfos.getId()).isPresent(); - } - case SIDE2 -> { - return !hasModificationOnSideOne && branch.getOperationalLimitsGroup1(limitsModifInfos.getId()).isPresent(); - } - default -> { - return false; - } - } - } - - // If we are changing applicability we may not find operational limits group where we should so check both sides - private void detectApplicabilityChange(Branch branch, List modificationInfos, - OperationalLimitsGroupModificationInfos modifiedLimitSetInfos, List olgReports) { - - OperationalLimitsGroup limitsGroup1 = branch.getOperationalLimitsGroup1(modifiedLimitSetInfos.getId()).orElse(null); - OperationalLimitsGroup limitsGroup2 = branch.getOperationalLimitsGroup2(modifiedLimitSetInfos.getId()).orElse(null); - if (limitsGroup1 == null && modifiedLimitSetInfos.getApplicability().equals(SIDE2) - || limitsGroup2 == null && modifiedLimitSetInfos.getApplicability().equals(SIDE1)) { - return; - } else if (limitsGroup1 != null && limitsGroup2 != null && !modifiedLimitSetInfos.getApplicability().equals(EQUIPMENT)) { - // applicability change from EQUIPMENT to one side - if (shouldDeletedOtherSide(branch, modificationInfos, modifiedLimitSetInfos)) { - if (modifiedLimitSetInfos.getApplicability().equals(SIDE1)) { - branch.removeOperationalLimitsGroup2(modifiedLimitSetInfos.getId()); - logApplicabilityChange(olgReports, limitsGroup1.getId(), SIDE1); - } else if (modifiedLimitSetInfos.getApplicability().equals(SIDE2)) { - branch.removeOperationalLimitsGroup1(modifiedLimitSetInfos.getId()); - logApplicabilityChange(olgReports, limitsGroup2.getId(), SIDE2); - } - } - return; - } - - switch (modifiedLimitSetInfos.getApplicability()) { - case SIDE1 -> moveLimitSetToTheOtherSide(branch, modificationInfos, limitsGroup2, modifiedLimitSetInfos.getId(), true, olgReports); - case SIDE2 -> moveLimitSetToTheOtherSide(branch, modificationInfos, limitsGroup1, modifiedLimitSetInfos.getId(), false, olgReports); - case EQUIPMENT -> { - boolean applicabilityChanged = false; - if (limitsGroup1 == null && limitsGroup2 != null) { - limitsGroup1 = branch.newOperationalLimitsGroup1(limitsGroup2.getId()); - copyOperationalLimitsGroup(limitsGroup1.newCurrentLimits(), limitsGroup2); - applicabilityChanged = true; - } - if (limitsGroup2 == null && limitsGroup1 != null) { - limitsGroup2 = branch.newOperationalLimitsGroup2(limitsGroup1.getId()); - copyOperationalLimitsGroup(limitsGroup2.newCurrentLimits(), limitsGroup1); - applicabilityChanged = true; - } - if (applicabilityChanged) { - logApplicabilityChange(olgReports, limitsGroup1.getId(), EQUIPMENT); - } - } - } - } - - private void logApplicabilityChange(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, - OperationalLimitsGroupsModificationType operationalLimitsGroupsModificationType, - List operationalLimitsInfos, - ReportNode limitSetsReportNode) { - - if (operationalLimitsGroupsModificationType == OperationalLimitsGroupsModificationType.REPLACE) { - // because we are replacing all the limit sets we remove all the limit sets that are not specified in the network modification - // the others may be modified instead of recreated so it is better to not delete them in order to have more precise logs - deleteOlgsUnspecifiedInTheModification(branch, operationalLimitsInfos, branch.getOperationalLimitsGroups1(), SIDE1, limitSetsReportNode); - deleteOlgsUnspecifiedInTheModification(branch, operationalLimitsInfos, branch.getOperationalLimitsGroups2(), SIDE2, limitSetsReportNode); - } - - for (OperationalLimitsGroupModificationInfos opLGModifInfos : operationalLimitsInfos) { - if (opLGModifInfos.getModificationType() == null) { - continue; - } - - ArrayList olgSetReports = new ArrayList<>(); - - OperationalLimitsGroupInfos.Applicability applicability = opLGModifInfos.getApplicability(); - // 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) - - if (!opLGModifInfos.getModificationType().equals(DELETE)) { - detectApplicabilityChange(branch, operationalLimitsInfos, opLGModifInfos, olgSetReports); - } - - if (applicability == SIDE1 - || applicability == EQUIPMENT) { - OperationalLimitsGroup operationalLimitsGroup1 = branch.getOperationalLimitsGroup1(opLGModifInfos.getId()).orElse(null); - applyModificationToOperationalLimitsGroup(branch, branch::newOperationalLimitsGroup1, opLGModifInfos, operationalLimitsGroup1, SIDE1, limitSetsReportNode); - } - if (applicability == SIDE2 - || applicability == EQUIPMENT) { - OperationalLimitsGroup operationalLimitsGroup2 = branch.getOperationalLimitsGroup2(opLGModifInfos.getId()).orElse(null); - applyModificationToOperationalLimitsGroup(branch, branch::newOperationalLimitsGroup2, opLGModifInfos, operationalLimitsGroup2, SIDE2, limitSetsReportNode); - } - } - } - - private void deleteOlgsUnspecifiedInTheModification( - Branch branch, - List operationalLimitsInfos, - Collection operationalLimitsGroups, - OperationalLimitsGroupInfos.Applicability applicability, - ReportNode limitSetsReportNode) { - List olgToBeDeleted = new ArrayList<>(); - operationalLimitsGroups.stream().filter( - operationalLimitsGroup -> - operationalLimitsInfos.stream().noneMatch( - operationalLimitsGroupModificationInfos -> - // we don't want to remove the limit sets specified in the network modification (operationalLimitsGroups) : - Objects.equals(operationalLimitsGroupModificationInfos.getId(), operationalLimitsGroup.getId()) - && (operationalLimitsGroupModificationInfos.getApplicability() == applicability - || operationalLimitsGroupModificationInfos.getApplicability() == EQUIPMENT) - ) - ).forEach(operationalLimitsGroup -> olgToBeDeleted.add(operationalLimitsGroup.getId())); - - Iterator i = olgToBeDeleted.iterator(); - while (i.hasNext()) { - String s = i.next(); - removeOlg(branch, s, applicability, limitSetsReportNode); - } - } - private void applySelectedOLGs(Branch branch, List activeOLGReports) { if (modificationInfos.getSelectedOperationalLimitsGroup1() != null) { - modifySelectedOperationalLimitsGroup( + OlgUtils.modifySelectedOperationalLimitsGroup( branch, modificationInfos.getSelectedOperationalLimitsGroup1(), TwoSides.ONE, @@ -282,7 +93,7 @@ private void applySelectedOLGs(Branch branch, List activeOLGRepor ); } if (modificationInfos.getSelectedOperationalLimitsGroup2() != null) { - modifySelectedOperationalLimitsGroup( + OlgUtils.modifySelectedOperationalLimitsGroup( branch, modificationInfos.getSelectedOperationalLimitsGroup2(), TwoSides.TWO, @@ -290,66 +101,6 @@ private void applySelectedOLGs(Branch branch, List activeOLGRepor } } - private static void applySelectedOLGOnSide1(Branch branch, AttributeModification modifOperationalLimitsGroup, List reportNode, String newSelectedOLG) { - if (!StringUtils.hasText(newSelectedOLG) || modifOperationalLimitsGroup.getOp() == OperationType.UNSET) { - branch.cancelSelectedOperationalLimitsGroup1(); - if (reportNode != null) { - reportNode.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.noLimitSetSelectedOnSide1") - .withSeverity(TypedValue.INFO_SEVERITY) - .build()); - } - } else { - if (StringUtils.hasText(newSelectedOLG) && branch.getOperationalLimitsGroup1(newSelectedOLG).isEmpty() && reportNode != null) { - reportNode.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.limitSetAbsentOnSide1") - .withUntypedValue("selectedOperationalLimitsGroup", newSelectedOLG) - .withSeverity(TypedValue.WARN_SEVERITY) - .build()); - - } else { - branch.setSelectedOperationalLimitsGroup1(newSelectedOLG); - if (reportNode != null) { - reportNode.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.limitSetSelectedOnSide1") - .withUntypedValue("selectedOperationalLimitsGroup1", newSelectedOLG) - .withSeverity(TypedValue.INFO_SEVERITY) - .build()); - } - } - } - } - - private static void applySelectedOLGOnSide2(Branch branch, AttributeModification modifOperationalLimitsGroup, List reportNode, String newSelectedOLG) { - if (!StringUtils.hasText(newSelectedOLG) || modifOperationalLimitsGroup.getOp() == OperationType.UNSET) { - branch.cancelSelectedOperationalLimitsGroup2(); - if (reportNode != null) { - reportNode.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.noLimitSetSelectedOnSide2") - .withSeverity(TypedValue.INFO_SEVERITY) - .build()); - } - } else { - if (StringUtils.hasText(newSelectedOLG) && branch.getOperationalLimitsGroup2(newSelectedOLG).isEmpty() && reportNode != null) { - reportNode.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.limitSetAbsentOnSide2") - .withUntypedValue("selectedOperationalLimitsGroup", newSelectedOLG) - .withSeverity(TypedValue.WARN_SEVERITY) - .build()); - - } else { - branch.setSelectedOperationalLimitsGroup2(newSelectedOLG); - if (reportNode != null) { - reportNode.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.limitSetSelectedOnSide2") - .withUntypedValue("selectedOperationalLimitsGroup2", newSelectedOLG) - .withSeverity(TypedValue.INFO_SEVERITY) - .build()); - } - } - } - } - public ReportNode updateMeasurements(Branch branch, BranchModificationInfos branchModificationInfos, ReportNode subReportNode) { Double p1Value = branchModificationInfos.getP1MeasurementValue() != null ? branchModificationInfos.getP1MeasurementValue().getValue() : null; Double q1Value = branchModificationInfos.getQ1MeasurementValue() != null ? branchModificationInfos.getQ1MeasurementValue().getValue() : null; @@ -461,465 +212,6 @@ private boolean updateConnection(Branch branch, TwoSides side, Boolean connec return done; } - /** - * only apply the modification to a singular operational limits group on a given side (like in iidm) - * therefore applicability is SIDE1 or SIDE2, not EQUIPMENT - */ - protected void applyModificationToOperationalLimitsGroup( - Branch branch, - Function groupFactory, - OperationalLimitsGroupModificationInfos opLGModificationInfos, - OperationalLimitsGroup modifiedOperationalLimitsGroup, - OperationalLimitsGroupInfos.Applicability applicability, - ReportNode limitsSetsReportNode - ) { - switch (opLGModificationInfos.getModificationType()) { - case OperationalLimitsGroupModificationType.MODIFY_OR_ADD: { - if (modifiedOperationalLimitsGroup == null) { - addOpLG(groupFactory, opLGModificationInfos, modifiedOperationalLimitsGroup, applicability, limitsSetsReportNode); - } else { - modifyOLG(opLGModificationInfos, modifiedOperationalLimitsGroup, applicability, limitsSetsReportNode); - } - } break; - case OperationalLimitsGroupModificationType.MODIFY: { - if (modifiedOperationalLimitsGroup == null) { - throw new PowsyblException("Cannot modify operational limit group " + opLGModificationInfos.getId() + " which has not been found in equipment given side"); - } - modifyOLG(opLGModificationInfos, modifiedOperationalLimitsGroup, applicability, limitsSetsReportNode); - } break; - case OperationalLimitsGroupModificationType.ADD: { - addOpLG(groupFactory, opLGModificationInfos, modifiedOperationalLimitsGroup, applicability, limitsSetsReportNode); - } break; - case OperationalLimitsGroupModificationType.REPLACE: { - replaceOpLG(groupFactory, opLGModificationInfos, modifiedOperationalLimitsGroup, applicability, limitsSetsReportNode); - } break; - case DELETE: { - removeOlg(branch, opLGModificationInfos.getId(), applicability, limitsSetsReportNode); - } - } - } - - private void removeOlg( - Branch branch, - String olgId, - OperationalLimitsGroupInfos.Applicability applicability, - ReportNode limitsSetsReportNode) { - if (applicability == SIDE1 && branch.getOperationalLimitsGroup1(olgId).isEmpty() || - applicability == SIDE2 && branch.getOperationalLimitsGroup2(olgId).isEmpty()) { - throw new PowsyblException("Cannot delete operational limit group " + olgId + " which has not been found in equipment on side " + applicability); - } - if (applicability == SIDE1) { - branch.removeOperationalLimitsGroup1(olgId); - } else if (applicability == SIDE2) { - branch.removeOperationalLimitsGroup2(olgId); - } - limitsSetsReportNode.newReportNode() - .withMessageTemplate("network.modification.operationalLimitsGroupDeleted") - .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, olgId) - .withUntypedValue(SIDE, applicability.toString()) - .withSeverity(TypedValue.INFO_SEVERITY) - .add(); - } - - private void replaceOpLG(Function groupFactory, - OperationalLimitsGroupModificationInfos opLGModificationInfos, - OperationalLimitsGroup modifiedOperationalLimitsGroup, - OperationalLimitsGroupInfos.Applicability applicability, - ReportNode limitsSetsReportNode) { - - List limitSetReports = new ArrayList<>(); - if (modifiedOperationalLimitsGroup != null) { - modifiedOperationalLimitsGroup.removeCurrentLimits(); - removeAllProperties(modifiedOperationalLimitsGroup, limitSetReports); - } - - OperationalLimitsGroup newOperationalLimitsGroup = groupFactory.apply(opLGModificationInfos.getId()); - modifyCurrentLimits(opLGModificationInfos, newOperationalLimitsGroup.newCurrentLimits(), null, limitSetReports); - addProperties(newOperationalLimitsGroup, opLGModificationInfos, limitSetReports); - - if (!CollectionUtils.isEmpty(limitSetReports)) { - ReportNode reportNode = limitsSetsReportNode.newReportNode() - .withMessageTemplate("network.modification.operationalLimitsGroupReplaced") - .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, opLGModificationInfos.getId()) - .withUntypedValue(SIDE, applicability.toString()) - .withSeverity(TypedValue.INFO_SEVERITY) - .add(); - ModificationUtils.getInstance().reportModifications(reportNode, limitSetReports); - } - } - - private void addProperties(OperationalLimitsGroup limitsGroup, OperationalLimitsGroupModificationInfos operationalLimitsGroupInfos, List limitSetsReports) { - if (limitsGroup == null || CollectionUtils.isEmpty(operationalLimitsGroupInfos.getLimitsProperties())) { - return; - } - - operationalLimitsGroupInfos.getLimitsProperties().forEach((LimitsPropertyInfos property) -> { - limitSetsReports.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.propertyAdded") - .withUntypedValue(NAME, property.name()) - .withUntypedValue(VALUE, property.value()) - .withSeverity(TypedValue.DETAIL_SEVERITY) - .build()); - limitsGroup.setProperty(property.name(), property.value()); - }); - } - - private void removeAllProperties(OperationalLimitsGroup limitsGroup, List limitSetsReports) { - - if (limitsGroup == null) { - return; - } - - Iterator propertiesIt = limitsGroup.getPropertyNames().iterator(); - while (propertiesIt.hasNext()) { - String propertyName = propertiesIt.next(); - limitsGroup.removeProperty(propertyName); - limitSetsReports.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.propertyDeleted") - .withUntypedValue(NAME, propertyName) - .withSeverity(TypedValue.DETAIL_SEVERITY).build()); - } - } - - private void modifyProperties(OperationalLimitsGroup limitsGroup, - OperationalLimitsGroupModificationInfos operationalLimitsGroupInfos, - List limitSetsReports) { - if (limitsGroup == null || operationalLimitsGroupInfos == null) { - return; - } - - Set currentProperties = limitsGroup.getPropertyNames(); - - List propertiesToModify = new ArrayList<>(); - List propertiesToAdd = new ArrayList<>(); - List propertiesToRemove; - - if (!CollectionUtils.isEmpty(operationalLimitsGroupInfos.getLimitsProperties())) { - for (LimitsPropertyInfos propertyInfos : operationalLimitsGroupInfos.getLimitsProperties()) { - if (currentProperties.contains(propertyInfos.name())) { - propertiesToModify.add(propertyInfos); - } else { - propertiesToAdd.add(propertyInfos); - } - } - - propertiesToRemove = currentProperties.stream().filter( - (String propertyName) -> propertiesToModify.stream().filter(propertyInfos -> - propertyInfos.name().equals(propertyName)).toList().isEmpty()).toList(); - } else { - propertiesToRemove = new ArrayList<>(currentProperties); - } - - propertiesToRemove.forEach((String propertyName) -> { - limitsGroup.removeProperty(propertyName); - limitSetsReports.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.propertyDeleted") - .withUntypedValue(NAME, propertyName) - .withSeverity(TypedValue.DETAIL_SEVERITY).build()); - }); - - propertiesToModify.forEach((LimitsPropertyInfos property) -> { - // Skip changes when value does not change - if (limitsGroup.getProperty(property.name()).equals(property.value())) { - return; - } - limitSetsReports.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.propertyChanged") - .withUntypedValue(NAME, property.name()) - .withUntypedValue("to", property.value()) - .withUntypedValue("from", limitsGroup.getProperty(property.name())) - .withSeverity(TypedValue.DETAIL_SEVERITY).build()); - limitsGroup.setProperty(property.name(), property.value()); - }); - - propertiesToAdd.forEach((LimitsPropertyInfos property) -> { - limitSetsReports.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.propertyAdded") - .withUntypedValue(NAME, property.name()) - .withUntypedValue(VALUE, property.value()) - .withSeverity(TypedValue.DETAIL_SEVERITY) - .build()); - limitsGroup.setProperty(property.name(), property.value()); - }); - } - - private void modifyOLG( - OperationalLimitsGroupModificationInfos operationalLimitsGroupInfos, - OperationalLimitsGroup modifiedOperationalLimitsGroup, - OperationalLimitsGroupInfos.Applicability applicability, - ReportNode limitsSetsReportNode) { - - List limitSetsReports = new ArrayList<>(); - - modifiedOperationalLimitsGroup.getCurrentLimits().ifPresent(currentLimits -> { - modifyCurrentLimits(operationalLimitsGroupInfos, modifiedOperationalLimitsGroup.newCurrentLimits(), currentLimits, limitSetsReports); - modifyProperties(modifiedOperationalLimitsGroup, operationalLimitsGroupInfos, limitSetsReports); - - if (!limitSetsReports.isEmpty()) { - ReportNode limitSetReport = limitsSetsReportNode.newReportNode() - .withMessageTemplate("network.modification.operationalLimitsGroupModified") - .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, operationalLimitsGroupInfos.getId()) - .withUntypedValue(SIDE, applicability.toString()) - .withSeverity(TypedValue.INFO_SEVERITY).add(); - ModificationUtils.getInstance().reportModifications(limitSetReport, limitSetsReports); - } - }); - } - - private void addOpLG(Function groupFactory, OperationalLimitsGroupModificationInfos operationalLimitsGroupInfos, - OperationalLimitsGroup modifiedOperationalLimitsGroup, - OperationalLimitsGroupInfos.Applicability applicability, ReportNode limitsSetsReportNode) { - - List limitSetReports = new ArrayList<>(); - if (modifiedOperationalLimitsGroup != null) { - throw new PowsyblException("Cannot add " + modifiedOperationalLimitsGroup.getId() + " operational limit group, one with the given name already exists"); - } - OperationalLimitsGroup newOperationalLimitsGroup = groupFactory.apply(operationalLimitsGroupInfos.getId()); - modifyCurrentLimits(operationalLimitsGroupInfos, newOperationalLimitsGroup.newCurrentLimits(), - newOperationalLimitsGroup.getCurrentLimits().orElse(null), limitSetReports); - addProperties(newOperationalLimitsGroup, operationalLimitsGroupInfos, limitSetReports); - - if (!CollectionUtils.isEmpty(limitSetReports)) { - ReportNode limitSetNode = limitsSetsReportNode.newReportNode() - .withMessageTemplate("network.modification.operationalLimitsGroupAdded") - .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, operationalLimitsGroupInfos.getId()) - .withUntypedValue(SIDE, applicability.toString()) - .withSeverity(TypedValue.INFO_SEVERITY) - .add(); - ModificationUtils.getInstance().reportModifications(limitSetNode, limitSetReports); - } - } - - protected void modifyCurrentLimits( - OperationalLimitsGroupModificationInfos operationalLimitsGroupModificationInfos, - CurrentLimitsAdder limitsAdder, - CurrentLimits currentLimits, - List limitsReports) { - CurrentLimitsModificationInfos currentLimitsInfos = operationalLimitsGroupModificationInfos.getCurrentLimits(); - boolean hasPermanent = currentLimitsInfos.getPermanentLimit() != null; - if (hasPermanent) { - if (!(currentLimits != null && currentLimits.getPermanentLimit() == currentLimitsInfos.getPermanentLimit())) { - limitsReports.add(ModificationUtils.getInstance().buildModificationReport(currentLimits != null ? currentLimits.getPermanentLimit() : Double.NaN, - currentLimitsInfos.getPermanentLimit(), "PATL")); - } - limitsAdder.setPermanentLimit(currentLimitsInfos.getPermanentLimit()); - } else { - if (currentLimits != null) { - limitsAdder.setPermanentLimit(currentLimits.getPermanentLimit()); - } - } - modifyTemporaryLimits(operationalLimitsGroupModificationInfos, limitsAdder, currentLimits, limitsReports); - limitsAdder.add(); - } - - /** - * is the limit identified by acceptableDuration deleted in temporaryLimitsModification ? - */ - public boolean isThisLimitDeleted(List temporaryLimitsModification, int acceptableDuration) { - return temporaryLimitsModification.stream() - .filter(temporaryLimit -> temporaryLimit.getAcceptableDuration() != null) - .anyMatch(temporaryLimit -> temporaryLimit.getAcceptableDuration() == acceptableDuration && temporaryLimit.getModificationType() == TemporaryLimitModificationType.DELETE); - } - - /** - * This function removes all the temporary limits of the 'currentLimits' concerned and recreates them (except in case of deletion) - */ - protected void modifyTemporaryLimits(@NotNull OperationalLimitsGroupModificationInfos operationalLimitsGroupModificationInfos, - CurrentLimitsAdder limitsAdder, - CurrentLimits currentLimits, - List limitsReports) { - CurrentLimitsModificationInfos currentLimitsInfos = operationalLimitsGroupModificationInfos.getCurrentLimits(); - - // we create a mutable list of temporary limits to be able to remove the limits that are modified in this current modification - // those left at the end of the network modification are those that have not been modified (or deleted) - List unmodifiedTemporaryLimits = new ArrayList<>(); - boolean areLimitsReplaced = TemporaryLimitModificationType.REPLACE.equals(operationalLimitsGroupModificationInfos.getTemporaryLimitsModificationType()); - if (currentLimits != null) { - unmodifiedTemporaryLimits.addAll(currentLimits.getTemporaryLimits()); - } - List temporaryLimitsReports = new ArrayList<>(); - - if (currentLimitsInfos != null && currentLimitsInfos.getTemporaryLimits() != null) { - for (CurrentTemporaryLimitModificationInfos limit : currentLimitsInfos.getTemporaryLimits()) { - applyTemporaryLimitModification( - operationalLimitsGroupModificationInfos, - limitsAdder, - currentLimits, - limit, - unmodifiedTemporaryLimits, - temporaryLimitsReports - ); - } - } - - if (!unmodifiedTemporaryLimits.isEmpty()) { - if (areLimitsReplaced) { - // this needs to be logged only if there are unmodifiedTemporaryLimits left. - // which means that they are going to be removed by the REPLACE mode - temporaryLimitsReports.addFirst(ReportNode.newRootReportNode() - .withAllResourceBundlesFromClasspath() - .withMessageTemplate("network.modification.temporaryLimitsReplaced") - .withSeverity(TypedValue.INFO_SEVERITY) - .build()); - } else { - // we add (back) the temporary limits that have not been modified - for (LoadingLimits.TemporaryLimit limit : unmodifiedTemporaryLimits) { - addTemporaryLimit(limitsAdder, limit.getName(), limit.getValue(), limit.getAcceptableDuration()); - } - } - } - if (!temporaryLimitsReports.isEmpty()) { - temporaryLimitsReports.addFirst(ReportNode.newRootReportNode() - .withAllResourceBundlesFromClasspath() - .withMessageTemplate("network.modification.temporaryLimitsModification") - .withSeverity(TypedValue.INFO_SEVERITY) - .build()); - limitsReports.addAll(temporaryLimitsReports); - } - } - - private static boolean mayCreateALimit(TemporaryLimitModificationType modificationType) { - return modificationType == TemporaryLimitModificationType.ADD - || modificationType == TemporaryLimitModificationType.REPLACE - || modificationType == TemporaryLimitModificationType.MODIFY_OR_ADD; - } - - /** - * modify a specific limit - * @param operationalLimitsGroupModificationInfos part of the network modification containing the operational limits groups data - * @param limitsAdder adder which receives all the "validated" limits to be added at the end - * @param networkCurrentLimits limits of the branch which is currently modified by the network modification - * @param limit modification to be applied to the limit - * @param unmodifiedTemporaryLimits list of all the unmodified limits that will be added at the end of the network modification - * @param temporaryLimitsReports log report - */ - private void applyTemporaryLimitModification( - OperationalLimitsGroupModificationInfos operationalLimitsGroupModificationInfos, - CurrentLimitsAdder limitsAdder, - CurrentLimits networkCurrentLimits, - CurrentTemporaryLimitModificationInfos limit, - List unmodifiedTemporaryLimits, - List temporaryLimitsReports) { - CurrentLimitsModificationInfos currentLimitsInfos = operationalLimitsGroupModificationInfos.getCurrentLimits(); - int limitAcceptableDuration = limit.getAcceptableDuration() == null ? Integer.MAX_VALUE : limit.getAcceptableDuration(); - double limitValue = limit.getValue() == null ? Double.MAX_VALUE : limit.getValue(); - String limitDurationToReport = limitAcceptableDuration == Integer.MAX_VALUE ? " " : String.valueOf(limitAcceptableDuration); - String limitValueToReport = limitValue == Double.MAX_VALUE ? "no value" : String.valueOf(limitValue); - LoadingLimits.TemporaryLimit limitToModify = null; - if (networkCurrentLimits != null) { - limitToModify = getTemporaryLimitToModify(networkCurrentLimits, limit, currentLimitsInfos, operationalLimitsGroupModificationInfos.getTemporaryLimitsModificationType()); - // this limit is modified by the network modification so we remove it from the list of unmodified temporary limits - unmodifiedTemporaryLimits.removeIf(temporaryLimit -> temporaryLimit.getAcceptableDuration() == limitAcceptableDuration); - } - if (limitToModify == null && mayCreateALimit(limit.getModificationType())) { - createTemporaryLimit(limitsAdder, limit, temporaryLimitsReports, limitDurationToReport, limitValueToReport, limitValue, limitAcceptableDuration); - } else if (limitToModify != null) { - // the limit already exists - if (limit.getModificationType() == TemporaryLimitModificationType.DELETE) { - // the limit has been removed previously - temporaryLimitsReports.add(ReportNode.newRootReportNode() - .withAllResourceBundlesFromClasspath() - .withMessageTemplate("network.modification.temporaryLimitDeleted.name") - .withUntypedValue(NAME, limit.getName()) - .withUntypedValue(DURATION, limitDurationToReport) - .withSeverity(TypedValue.INFO_SEVERITY) - .build()); - } else { - modifyTemporaryLimit(limitsAdder, limit, temporaryLimitsReports, limitToModify, limitValue, limitDurationToReport, limitValueToReport, limitAcceptableDuration); - } - } else if (limit.getModificationType() == TemporaryLimitModificationType.MODIFY || limit.getModificationType() == TemporaryLimitModificationType.MODIFY_OR_ADD) { - // invalid modification - temporaryLimitsReports.add(ReportNode.newRootReportNode() - .withAllResourceBundlesFromClasspath() - .withMessageTemplate("network.modification.temporaryLimitsNoMatch") - .withUntypedValue(LIMIT_ACCEPTABLE_DURATION, limitAcceptableDuration) - .withSeverity(TypedValue.WARN_SEVERITY) - .build()); - } - } - - private static void modifyTemporaryLimit( - CurrentLimitsAdder limitsAdder, - CurrentTemporaryLimitModificationInfos limitModificationInfos, - List temporaryLimitsReports, - LoadingLimits.TemporaryLimit limitToModify, - double limitValue, - String limitDurationToReport, - String limitValueToReport, - int limitAcceptableDuration) { - if (Double.compare(limitToModify.getValue(), limitValue) != 0 && limitModificationInfos.getModificationType() != null) { - temporaryLimitsReports.add(ReportNode.newRootReportNode() - .withAllResourceBundlesFromClasspath() - .withMessageTemplate("network.modification.temporaryLimitModified.name") - .withUntypedValue(NAME, limitModificationInfos.getName()) - .withUntypedValue(DURATION, limitDurationToReport) - .withUntypedValue(VALUE, limitValueToReport) - .withUntypedValue("oldValue", - limitToModify.getValue() == Double.MAX_VALUE ? "no value" - : String.valueOf(limitToModify.getValue())) - .withSeverity(TypedValue.INFO_SEVERITY) - .build()); - addTemporaryLimit(limitsAdder, limitModificationInfos.getName(), limitValue, limitAcceptableDuration); - } else { - // no real modification - addTemporaryLimit(limitsAdder, limitModificationInfos.getName(), limitToModify.getValue(), limitAcceptableDuration); - } - } - - private static void createTemporaryLimit( - CurrentLimitsAdder limitsAdder, - CurrentTemporaryLimitModificationInfos limit, - List temporaryLimitsReports, - String limitDurationToReport, - String limitValueToReport, - double limitValue, - int limitAcceptableDuration) { - temporaryLimitsReports.add(ReportNode.newRootReportNode() - .withAllResourceBundlesFromClasspath() - .withMessageTemplate("network.modification.temporaryLimitAdded.name") - .withUntypedValue(NAME, limit.getName()) - .withUntypedValue(DURATION, limitDurationToReport) - .withUntypedValue(VALUE, limitValueToReport) - .withSeverity(TypedValue.INFO_SEVERITY) - .build()); - addTemporaryLimit(limitsAdder, limit.getName(), limitValue, limitAcceptableDuration); - } - - private static void addTemporaryLimit(CurrentLimitsAdder limitsAdder, String limit, double limitValue, int limitAcceptableDuration) { - limitsAdder - .beginTemporaryLimit() - .setName(limit) - .setValue(limitValue) - .setAcceptableDuration(limitAcceptableDuration) - .endTemporaryLimit(); - } - - private LoadingLimits.TemporaryLimit getTemporaryLimitToModify( - CurrentLimits networkCurrentLimits, - CurrentTemporaryLimitModificationInfos limit, - CurrentLimitsModificationInfos currentLimitsInfos, - TemporaryLimitModificationType temporaryLimitsModificationType) { - int limitAcceptableDuration = limit.getAcceptableDuration() == null ? Integer.MAX_VALUE : limit.getAcceptableDuration(); - LoadingLimits.TemporaryLimit limitToModify; - limitToModify = networkCurrentLimits.getTemporaryLimit(limitAcceptableDuration); - if (limitToModify != null && !limitToModify.getName().equals(limit.getName())) { - boolean isThisLimitDeleted = isThisLimitDeleted(currentLimitsInfos.getTemporaryLimits(), limitAcceptableDuration); - if (isThisLimitDeleted) { - limitToModify = null; - } else if (TemporaryLimitModificationType.ADD.equals(limit.getModificationType())) { - throw new PowsyblException("2 temporary limits have the same duration " + limitAcceptableDuration); - } - } - - //Additional check for limit sets tabular modifications - if (TemporaryLimitModificationType.ADD.equals(temporaryLimitsModificationType)) { - networkCurrentLimits.getTemporaryLimits().stream().filter(temporaryLimit -> temporaryLimit.getName().equals(limit.getName())).findFirst().ifPresent(temporaryLimit -> { - throw new PowsyblException("2 temporary limits have the same name " + limit.getName()); - }); - } - return limitToModify; - } - protected boolean characteristicsModified(BranchModificationInfos branchModificationInfos) { return branchModificationInfos.getX() != null && branchModificationInfos.getX().getValue() != null @@ -957,19 +249,4 @@ private void modifyBranchVoltageLevelBusOrBusBarSectionAttributesSide2(BranchMod ); } - public static void modifySelectedOperationalLimitsGroup( - Branch branch, - AttributeModification modifOperationalLimitsGroup, - TwoSides side, - List reportNode) { - Objects.requireNonNull(side); - if (modifOperationalLimitsGroup != null) { - String newSelectedOLG = modifOperationalLimitsGroup.getValue(); - if (side == TwoSides.ONE) { - applySelectedOLGOnSide1(branch, modifOperationalLimitsGroup, reportNode, newSelectedOLG); - } else if (side == TwoSides.TWO) { - applySelectedOLGOnSide2(branch, modifOperationalLimitsGroup, reportNode, newSelectedOLG); - } - } - } } diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java new file mode 100644 index 00000000..450db7e8 --- /dev/null +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -0,0 +1,461 @@ +package org.gridsuite.modification.modifications.olg; + +import com.powsybl.commons.PowsyblException; +import com.powsybl.commons.report.ReportNode; +import com.powsybl.commons.report.TypedValue; +import com.powsybl.iidm.network.*; +import org.gridsuite.modification.dto.*; +import org.gridsuite.modification.utils.ModificationUtils; +import org.gridsuite.modification.utils.OlgUtils; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.function.Function; + +import static org.gridsuite.modification.dto.OperationalLimitsGroupInfos.Applicability.*; +import static org.gridsuite.modification.modifications.AbstractBranchModification.NAME; +import static org.gridsuite.modification.modifications.AbstractBranchModification.VALUE; + +/** + * handles the modification of a single operational limits group from AbstractBranchModification + * it may affect both sides of an operational limits group + */ +public class OlgModification { + private final Branch modifiedBranch; // branch modified by the network modification + private final OperationalLimitsGroupModificationInfos olgModifInfos; + private final ReportNode olgsReportNode; + + public OlgModification( + Branch modifiedBranch, + OperationalLimitsGroupModificationInfos olgModifInfos, + ReportNode limitSetsReportNode) { + this.modifiedBranch = modifiedBranch; + this.olgModifInfos = olgModifInfos; + olgsReportNode = limitSetsReportNode; + } + + private OperationalLimitsGroup modifiedOperationalLimitsGroup1() { + return modifiedBranch.getOperationalLimitsGroup1(olgModifInfos.getId()).orElse(null); + } + + private OperationalLimitsGroup modifiedOperationalLimitsGroup2() { + return modifiedBranch.getOperationalLimitsGroup2(olgModifInfos.getId()).orElse(null); + } + + protected void applyModificationToOperationalLimitsGroup(Function groupFactory) { + switch (olgModifInfos.getModificationType()) { + case OperationalLimitsGroupModificationType.MODIFY_OR_ADD: { + switch (olgModifInfos.getApplicability()) { + case EQUIPMENT : + if (modifiedOperationalLimitsGroup1() == null && modifiedOperationalLimitsGroup2() == null) { + // TODO : attention quand un est valide et l'autre non + addOpLG(groupFactory, olgModifInfos.getApplicability()); + } else { + modifyOLG(); + } + break; + case SIDE1 : + if (modifiedOperationalLimitsGroup1() == null) { + addOpLG(groupFactory, olgModifInfos.getApplicability()); + } else { + modifyOLG(); + } + break; + case SIDE2 : + if (modifiedOperationalLimitsGroup2() == null) { + addOpLG(groupFactory, olgModifInfos.getApplicability()); + } else { + modifyOLG(); + } + break; + } + } break; + case OperationalLimitsGroupModificationType.MODIFY: { + if (modifySide1() && modifiedOperationalLimitsGroup1() == null) { + throw new PowsyblException("Cannot modify operational limit group " + olgModifInfos.getId() + " which has not been found in equipment side 1"); + } + if (modifySide2() && modifiedOperationalLimitsGroup2() == null) { + throw new PowsyblException("Cannot modify operational limit group " + olgModifInfos.getId() + " which has not been found in equipment side 2"); + } + modifyOLG(); + } break; + case OperationalLimitsGroupModificationType.ADD: { + addOpLG(groupFactory, olgModifInfos.getApplicability()); + } break; + case OperationalLimitsGroupModificationType.REPLACE: { + replaceOpLG(groupFactory); + } break; + case DELETE: { + removeOlg(); + } + } + } + + private boolean modifySide1() { + return olgModifInfos.getApplicability() == SIDE1 || olgModifInfos.getApplicability() == EQUIPMENT; + } + + private boolean modifySide2() { + return olgModifInfos.getApplicability() == SIDE2 || olgModifInfos.getApplicability() == EQUIPMENT; + } + + private void modifyOLG() { + + List limitSetsReports = new ArrayList<>(); + + if (modifySide1()) { + modifiedOperationalLimitsGroup1().getCurrentLimits().ifPresent(currentLimits -> { + modifyCurrentLimits(modifiedOperationalLimitsGroup1().newCurrentLimits(), currentLimits, limitSetsReports); + modifyProperties(modifiedOperationalLimitsGroup1(), limitSetsReports); + }); + } + if (modifySide2()) { + modifiedOperationalLimitsGroup2().getCurrentLimits().ifPresent(currentLimits -> { + modifyCurrentLimits(modifiedOperationalLimitsGroup2().newCurrentLimits(), currentLimits, limitSetsReports); + modifyProperties(modifiedOperationalLimitsGroup2(), limitSetsReports); + }); + } + + if (!limitSetsReports.isEmpty()) { + ReportNode limitSetReport = olgsReportNode.newReportNode() + .withMessageTemplate("network.modification.operationalLimitsGroupModified") + .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) + .withUntypedValue(OlgUtils.SIDE, olgModifInfos.getApplicability().toString()) + .withSeverity(TypedValue.INFO_SEVERITY).add(); + ModificationUtils.getInstance().reportModifications(limitSetReport, limitSetsReports); + } + } + + private void modifyProperties(OperationalLimitsGroup limitsGroup, + List limitSetsReports) { + if (limitsGroup == null || olgModifInfos == null) { + return; + } + + Set currentProperties = limitsGroup.getPropertyNames(); + + List propertiesToModify = new ArrayList<>(); + List propertiesToAdd = new ArrayList<>(); + List propertiesToRemove; + + if (!CollectionUtils.isEmpty(olgModifInfos.getLimitsProperties())) { + for (LimitsPropertyInfos propertyInfos : olgModifInfos.getLimitsProperties()) { + if (currentProperties.contains(propertyInfos.name())) { + propertiesToModify.add(propertyInfos); + } else { + propertiesToAdd.add(propertyInfos); + } + } + + propertiesToRemove = currentProperties.stream().filter( + (String propertyName) -> propertiesToModify.stream().filter(propertyInfos -> + propertyInfos.name().equals(propertyName)).toList().isEmpty()).toList(); + } else { + propertiesToRemove = new ArrayList<>(currentProperties); + } + + propertiesToRemove.forEach((String propertyName) -> { + limitsGroup.removeProperty(propertyName); + limitSetsReports.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.propertyDeleted") + .withUntypedValue(NAME, propertyName) + .withSeverity(TypedValue.DETAIL_SEVERITY).build()); + }); + + propertiesToModify.forEach((LimitsPropertyInfos property) -> { + // Skip changes when value does not change + if (limitsGroup.getProperty(property.name()).equals(property.value())) { + return; + } + limitSetsReports.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.propertyChanged") + .withUntypedValue(NAME, property.name()) + .withUntypedValue("to", property.value()) + .withUntypedValue("from", limitsGroup.getProperty(property.name())) + .withSeverity(TypedValue.DETAIL_SEVERITY).build()); + limitsGroup.setProperty(property.name(), property.value()); + }); + + propertiesToAdd.forEach((LimitsPropertyInfos property) -> { + limitSetsReports.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.propertyAdded") + .withUntypedValue(NAME, property.name()) + .withUntypedValue(VALUE, property.value()) + .withSeverity(TypedValue.DETAIL_SEVERITY) + .build()); + limitsGroup.setProperty(property.name(), property.value()); + }); + } + + protected void modifyCurrentLimits( + CurrentLimitsAdder limitsAdder, + CurrentLimits currentLimits, + List limitsReports) { + CurrentLimitsModificationInfos currentLimitsInfos = olgModifInfos.getCurrentLimits(); + boolean hasPermanent = currentLimitsInfos.getPermanentLimit() != null; + if (hasPermanent) { + if (!(currentLimits != null && currentLimits.getPermanentLimit() == currentLimitsInfos.getPermanentLimit())) { + limitsReports.add(ModificationUtils.getInstance().buildModificationReport(currentLimits != null ? currentLimits.getPermanentLimit() : Double.NaN, + currentLimitsInfos.getPermanentLimit(), "PATL")); + } + limitsAdder.setPermanentLimit(currentLimitsInfos.getPermanentLimit()); + } else { + if (currentLimits != null) { + limitsAdder.setPermanentLimit(currentLimits.getPermanentLimit()); + } + } + modifyTemporaryLimits(limitsAdder, currentLimits, limitsReports); + limitsAdder.add(); + } + + private void addOpLG(Function groupFactory, OperationalLimitsGroupInfos.Applicability applicability) { + + List limitSetReports = new ArrayList<>(); + if ((applicability == EQUIPMENT || applicability == SIDE1) && modifiedOperationalLimitsGroup1() != null) { + throw new PowsyblException("Cannot add " + modifiedOperationalLimitsGroup1().getId() + " operational limit group, one with the given name already exists"); + } + if ((applicability == EQUIPMENT || applicability == SIDE2) && modifiedOperationalLimitsGroup2() != null) { + throw new PowsyblException("Cannot add " + modifiedOperationalLimitsGroup2().getId() + " operational limit group, one with the given name already exists"); + } + OperationalLimitsGroup newOperationalLimitsGroup = groupFactory.apply(olgModifInfos.getId()); + modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), + newOperationalLimitsGroup.getCurrentLimits().orElse(null), limitSetReports); + addProperties(newOperationalLimitsGroup, limitSetReports); + + if (!CollectionUtils.isEmpty(limitSetReports)) { + ReportNode limitSetNode = olgsReportNode.newReportNode() + .withMessageTemplate("network.modification.operationalLimitsGroupAdded") + .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) + .withUntypedValue(OlgUtils.SIDE, applicability.toString()) + .withSeverity(TypedValue.INFO_SEVERITY) + .add(); + ModificationUtils.getInstance().reportModifications(limitSetNode, limitSetReports); + } + } + + private void replaceOpLG(Function groupFactory) { + List limitSetReports = new ArrayList<>(); + if (modifySide1() && modifiedOperationalLimitsGroup1() != null) { + modifiedOperationalLimitsGroup1().removeCurrentLimits(); + removeAllProperties(modifiedOperationalLimitsGroup1(), limitSetReports); + } + if (modifySide2() && modifiedOperationalLimitsGroup2() != null) { + modifiedOperationalLimitsGroup2().removeCurrentLimits(); + removeAllProperties(modifiedOperationalLimitsGroup2(), limitSetReports); + } + + OperationalLimitsGroup newOperationalLimitsGroup = groupFactory.apply(olgModifInfos.getId()); + modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), null, limitSetReports); + addProperties(newOperationalLimitsGroup, limitSetReports); + + if (!CollectionUtils.isEmpty(limitSetReports)) { + ReportNode reportNode = olgsReportNode.newReportNode() + .withMessageTemplate("network.modification.operationalLimitsGroupReplaced") + .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) + .withUntypedValue(OlgUtils.SIDE, olgModifInfos.getApplicability().toString()) + .withSeverity(TypedValue.INFO_SEVERITY) + .add(); + ModificationUtils.getInstance().reportModifications(reportNode, limitSetReports); + } + } + + private void addProperties(OperationalLimitsGroup limitsGroup, List limitSetsReports) { + if (limitsGroup == null || CollectionUtils.isEmpty(olgModifInfos.getLimitsProperties())) { + return; + } + + olgModifInfos.getLimitsProperties().forEach((LimitsPropertyInfos property) -> { + limitSetsReports.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.propertyAdded") + .withUntypedValue(NAME, property.name()) + .withUntypedValue(VALUE, property.value()) + .withSeverity(TypedValue.DETAIL_SEVERITY) + .build()); + limitsGroup.setProperty(property.name(), property.value()); + }); + } + + public void removeOlg() { + String olgId = olgModifInfos.getId(); + if (modifySide1() && modifiedBranch.getOperationalLimitsGroup1(olgId).isEmpty() || + modifySide2() && modifiedBranch.getOperationalLimitsGroup2(olgId).isEmpty()) { + throw new PowsyblException("Cannot delete operational limit group " + olgId + " which has not been found in equipment on side " + olgModifInfos.getApplicability().toString()); + } + if (modifySide1()) { + modifiedBranch.removeOperationalLimitsGroup1(olgId); + } + if (modifySide2()) { + modifiedBranch.removeOperationalLimitsGroup2(olgId); + } + olgsReportNode.newReportNode() + .withMessageTemplate("network.modification.operationalLimitsGroupDeleted") + .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgId) + .withUntypedValue(OlgUtils.SIDE, olgModifInfos.getApplicability().toString()) + .withSeverity(TypedValue.INFO_SEVERITY) + .add(); + } + + private void removeAllProperties(OperationalLimitsGroup limitsGroup, List limitSetsReports) { + + if (limitsGroup == null) { + return; + } + + Iterator propertiesIt = limitsGroup.getPropertyNames().iterator(); + while (propertiesIt.hasNext()) { + String propertyName = propertiesIt.next(); + limitsGroup.removeProperty(propertyName); + limitSetsReports.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.propertyDeleted") + .withUntypedValue(NAME, propertyName) + .withSeverity(TypedValue.DETAIL_SEVERITY).build()); + } + } + + /** + * This function removes all the temporary limits of the 'currentLimits' concerned and recreates them (except in case of deletion) + */ + protected void modifyTemporaryLimits(CurrentLimitsAdder limitsAdder, + CurrentLimits currentLimits, + List limitsReports) { + CurrentLimitsModificationInfos currentLimitsInfos = olgModifInfos.getCurrentLimits(); + + // we create a mutable list of temporary limits to be able to remove the limits that are modified in this current modification + // those left at the end of the network modification are those that have not been modified (or deleted) + List unmodifiedTemporaryLimits = new ArrayList<>(); + boolean areLimitsReplaced = TemporaryLimitModificationType.REPLACE.equals(olgModifInfos.getTemporaryLimitsModificationType()); + if (currentLimits != null) { + unmodifiedTemporaryLimits.addAll(currentLimits.getTemporaryLimits()); + } + List temporaryLimitsReports = new ArrayList<>(); + + if (currentLimitsInfos != null && currentLimitsInfos.getTemporaryLimits() != null) { + for (CurrentTemporaryLimitModificationInfos limit : currentLimitsInfos.getTemporaryLimits()) { + applyTemporaryLimitModification( + limitsAdder, + currentLimits, + limit, + unmodifiedTemporaryLimits, + temporaryLimitsReports + ); + } + } + + if (!unmodifiedTemporaryLimits.isEmpty()) { + if (areLimitsReplaced) { + // this needs to be logged only if there are unmodifiedTemporaryLimits left. + // which means that they are going to be removed by the REPLACE mode + temporaryLimitsReports.addFirst(ReportNode.newRootReportNode() + .withAllResourceBundlesFromClasspath() + .withMessageTemplate("network.modification.temporaryLimitsReplaced") + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + } else { + // we add (back) the temporary limits that have not been modified + for (LoadingLimits.TemporaryLimit limit : unmodifiedTemporaryLimits) { + OlgUtils.addTemporaryLimit(limitsAdder, limit.getName(), limit.getValue(), limit.getAcceptableDuration()); + } + } + } + if (!temporaryLimitsReports.isEmpty()) { + temporaryLimitsReports.addFirst(ReportNode.newRootReportNode() + .withAllResourceBundlesFromClasspath() + .withMessageTemplate("network.modification.temporaryLimitsModification") + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + limitsReports.addAll(temporaryLimitsReports); + } + } + + /** + * modify a specific limit + * @param limitsAdder adder which receives all the "validated" limits to be added at the end + * @param networkCurrentLimits limits of the branch which is currently modified by the network modification + * @param limit modification to be applied to the limit + * @param unmodifiedTemporaryLimits list of all the unmodified limits that will be added at the end of the network modification + * @param temporaryLimitsReports log report + */ + private void applyTemporaryLimitModification( + CurrentLimitsAdder limitsAdder, + CurrentLimits networkCurrentLimits, + CurrentTemporaryLimitModificationInfos limit, + List unmodifiedTemporaryLimits, + List temporaryLimitsReports) { + CurrentLimitsModificationInfos currentLimitsInfos = olgModifInfos.getCurrentLimits(); + int limitAcceptableDuration = limit.getAcceptableDuration() == null ? Integer.MAX_VALUE : limit.getAcceptableDuration(); + double limitValue = limit.getValue() == null ? Double.MAX_VALUE : limit.getValue(); + String limitDurationToReport = limitAcceptableDuration == Integer.MAX_VALUE ? " " : String.valueOf(limitAcceptableDuration); + String limitValueToReport = limitValue == Double.MAX_VALUE ? "no value" : String.valueOf(limitValue); + LoadingLimits.TemporaryLimit limitToModify = null; + if (networkCurrentLimits != null) { + limitToModify = getTemporaryLimitToModify(networkCurrentLimits, limit, currentLimitsInfos, olgModifInfos.getTemporaryLimitsModificationType()); + // this limit is modified by the network modification so we remove it from the list of unmodified temporary limits + unmodifiedTemporaryLimits.removeIf(temporaryLimit -> temporaryLimit.getAcceptableDuration() == limitAcceptableDuration); + } + if (limitToModify == null && OlgUtils.mayCreateALimit(limit.getModificationType())) { + OlgUtils.createTemporaryLimit(limitsAdder, limit, temporaryLimitsReports, limitDurationToReport, limitValueToReport, limitValue, limitAcceptableDuration); + } else if (limitToModify != null) { + // the limit already exists + if (limit.getModificationType() == TemporaryLimitModificationType.DELETE) { + // the limit has been removed previously + temporaryLimitsReports.add(ReportNode.newRootReportNode() + .withAllResourceBundlesFromClasspath() + .withMessageTemplate("network.modification.temporaryLimitDeleted.name") + .withUntypedValue(NAME, limit.getName()) + .withUntypedValue(OlgUtils.DURATION, limitDurationToReport) + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + } else { + OlgUtils.modifyTemporaryLimit(limitsAdder, limit, temporaryLimitsReports, limitToModify, limitValue, limitDurationToReport, limitValueToReport, limitAcceptableDuration); + } + } else if (limit.getModificationType() == TemporaryLimitModificationType.MODIFY || limit.getModificationType() == TemporaryLimitModificationType.MODIFY_OR_ADD) { + // invalid modification + temporaryLimitsReports.add(ReportNode.newRootReportNode() + .withAllResourceBundlesFromClasspath() + .withMessageTemplate("network.modification.temporaryLimitsNoMatch") + .withUntypedValue(OlgUtils.LIMIT_ACCEPTABLE_DURATION, limitAcceptableDuration) + .withSeverity(TypedValue.WARN_SEVERITY) + .build()); + } + } + + /** + * is the limit identified by acceptableDuration deleted in temporaryLimitsModification ? + */ + public boolean isThisLimitDeleted(List temporaryLimitsModification, int acceptableDuration) { + return temporaryLimitsModification.stream() + .filter(temporaryLimit -> temporaryLimit.getAcceptableDuration() != null) + .anyMatch(temporaryLimit -> + temporaryLimit.getAcceptableDuration() == acceptableDuration && temporaryLimit.getModificationType() == TemporaryLimitModificationType.DELETE + ); + } + + private LoadingLimits.TemporaryLimit getTemporaryLimitToModify( + CurrentLimits networkCurrentLimits, + CurrentTemporaryLimitModificationInfos limit, + CurrentLimitsModificationInfos currentLimitsInfos, + TemporaryLimitModificationType temporaryLimitsModificationType) { + int limitAcceptableDuration = limit.getAcceptableDuration() == null ? Integer.MAX_VALUE : limit.getAcceptableDuration(); + LoadingLimits.TemporaryLimit limitToModify; + limitToModify = networkCurrentLimits.getTemporaryLimit(limitAcceptableDuration); + if (limitToModify != null && !limitToModify.getName().equals(limit.getName())) { + boolean isThisLimitDeleted = isThisLimitDeleted(currentLimitsInfos.getTemporaryLimits(), limitAcceptableDuration); + if (isThisLimitDeleted) { + limitToModify = null; + } else if (TemporaryLimitModificationType.ADD.equals(limit.getModificationType())) { + throw new PowsyblException("2 temporary limits have the same duration " + limitAcceptableDuration); + } + } + + //Additional check for limit sets tabular modifications + if (TemporaryLimitModificationType.ADD.equals(temporaryLimitsModificationType)) { + networkCurrentLimits.getTemporaryLimits().stream().filter(temporaryLimit -> temporaryLimit.getName().equals(limit.getName())).findFirst().ifPresent(temporaryLimit -> { + throw new PowsyblException("2 temporary limits have the same name " + limit.getName()); + }); + } + return limitToModify; + } +} diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java new file mode 100644 index 00000000..59ef93fe --- /dev/null +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java @@ -0,0 +1,201 @@ +package org.gridsuite.modification.modifications.olg; + +import com.powsybl.commons.report.ReportNode; +import com.powsybl.commons.report.TypedValue; +import com.powsybl.iidm.network.*; +import org.gridsuite.modification.dto.*; +import org.gridsuite.modification.utils.OlgUtils; + +import java.util.*; + +import static org.gridsuite.modification.dto.OperationalLimitsGroupInfos.Applicability.*; +import static org.gridsuite.modification.dto.OperationalLimitsGroupInfos.Applicability.EQUIPMENT; +import static org.gridsuite.modification.dto.OperationalLimitsGroupModificationType.DELETE; + +/** + * handles the modification of a list of operational limits groups from AbstractBranchModification + */ +public class OlgsModification { + private final Branch modifiedBranch; // branch modified by the network modification + private final List olgModificationInfos; + private final ReportNode olgsReportNode; + + public OlgsModification( + Branch branch, + List operationalLimitsInfos, + ReportNode limitSetsReportNode) { + modifiedBranch = branch; + olgModificationInfos = operationalLimitsInfos != null ? operationalLimitsInfos : new ArrayList<>(); + olgsReportNode = limitSetsReportNode; + } + + public void modifyOperationalLimitsGroups(OperationalLimitsGroupsModificationType operationalLimitsGroupsModificationType) { + + if (operationalLimitsGroupsModificationType == OperationalLimitsGroupsModificationType.REPLACE) { + // because we are replacing all the limit sets we remove all the limit sets that are not specified in the network modification + // the others may be modified instead of recreated so it is better to not delete them in order to have more precise logs + deleteOlgsUnspecifiedInTheModification(SIDE1); + deleteOlgsUnspecifiedInTheModification(SIDE2); + } + + for (OperationalLimitsGroupModificationInfos opLGModifInfos : olgModificationInfos) { + if (opLGModifInfos.getModificationType() == null) { + continue; + } + + ArrayList olgSetReports = new ArrayList<>(); + + if (!opLGModifInfos.getModificationType().equals(DELETE)) { + detectApplicabilityChange(opLGModifInfos, olgSetReports); + } + + new OlgModification( + modifiedBranch, + opLGModifInfos, + olgsReportNode + ).applyModificationToOperationalLimitsGroup(modifiedBranch::newOperationalLimitsGroup1); + } + } + + private void deleteOlgsUnspecifiedInTheModification(OperationalLimitsGroupInfos.Applicability applicability) { + List olgToBeDeleted = new ArrayList<>(); + Collection operationalLimitsGroups = applicability == SIDE1 ? + modifiedBranch.getOperationalLimitsGroups1() : + modifiedBranch.getOperationalLimitsGroups2(); + operationalLimitsGroups.stream().filter( + operationalLimitsGroup -> + olgModificationInfos.stream().noneMatch( + operationalLimitsGroupModificationInfos -> + // we don't want to remove the limit sets specified in the network modification (operationalLimitsGroups) : + Objects.equals(operationalLimitsGroupModificationInfos.getId(), operationalLimitsGroup.getId()) + && (operationalLimitsGroupModificationInfos.getApplicability() == applicability + || operationalLimitsGroupModificationInfos.getApplicability() == EQUIPMENT) + ) + ).forEach(operationalLimitsGroup -> olgToBeDeleted.add(operationalLimitsGroup.getId())); + + Iterator i = olgToBeDeleted.iterator(); + while (i.hasNext()) { + String s = i.next(); + new OlgModification( + modifiedBranch, + OperationalLimitsGroupModificationInfos.builder() + .id(s) + .applicability(applicability) + .build(), + olgsReportNode + ).removeOlg(); + } + } + + private void logApplicabilityChange(List olgReports, String groupId, OperationalLimitsGroupInfos.Applicability applicability) { + olgReports.add(ReportNode.newRootReportNode().withMessageTemplate("network.modification.applicabilityChanged") + .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, groupId) + .withUntypedValue(OlgUtils.APPLICABILITY, applicability.toString()) + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + } + + private boolean shouldDeletedOtherSide(Branch branch, OperationalLimitsGroupModificationInfos limitsModifInfos) { + boolean hasModificationOnSideOne = !olgModificationInfos.stream().filter(opLimitModifInfo -> + opLimitModifInfo.getId().equals(limitsModifInfos.getId()) && opLimitModifInfo.getApplicability().equals(SIDE1)) + .toList().isEmpty(); + + boolean hasModificationOnSideTwo = !olgModificationInfos.stream().filter(opLimitModifInfo -> + opLimitModifInfo.getId().equals(limitsModifInfos.getId()) && opLimitModifInfo.getApplicability().equals(SIDE2)) + .toList().isEmpty(); + + switch (limitsModifInfos.getApplicability()) { + case SIDE1 -> { + return !hasModificationOnSideTwo && branch.getOperationalLimitsGroup2(limitsModifInfos.getId()).isPresent(); + } + case SIDE2 -> { + return !hasModificationOnSideOne && branch.getOperationalLimitsGroup1(limitsModifInfos.getId()).isPresent(); + } + default -> { + return false; + } + } + } + + // If we are changing applicability we may not find operational limits group where we should so check both sides + private void detectApplicabilityChange(OperationalLimitsGroupModificationInfos modifiedLimitSetInfos, List olgReports) { + + OperationalLimitsGroup limitsGroup1 = modifiedBranch.getOperationalLimitsGroup1(modifiedLimitSetInfos.getId()).orElse(null); + OperationalLimitsGroup limitsGroup2 = modifiedBranch.getOperationalLimitsGroup2(modifiedLimitSetInfos.getId()).orElse(null); + if (limitsGroup1 == null && modifiedLimitSetInfos.getApplicability().equals(SIDE2) + || limitsGroup2 == null && modifiedLimitSetInfos.getApplicability().equals(SIDE1)) { + return; + } else if (limitsGroup1 != null && limitsGroup2 != null && !modifiedLimitSetInfos.getApplicability().equals(EQUIPMENT)) { + // applicability change from EQUIPMENT to one side + if (shouldDeletedOtherSide(modifiedBranch, modifiedLimitSetInfos)) { + if (modifiedLimitSetInfos.getApplicability().equals(SIDE1)) { + modifiedBranch.removeOperationalLimitsGroup2(modifiedLimitSetInfos.getId()); + logApplicabilityChange(olgReports, limitsGroup1.getId(), SIDE1); + } else if (modifiedLimitSetInfos.getApplicability().equals(SIDE2)) { + modifiedBranch.removeOperationalLimitsGroup1(modifiedLimitSetInfos.getId()); + logApplicabilityChange(olgReports, limitsGroup2.getId(), SIDE2); + } + } + return; + } + + switch (modifiedLimitSetInfos.getApplicability()) { + case SIDE1 -> moveLimitSetToTheOtherSide(modifiedBranch, limitsGroup2, modifiedLimitSetInfos.getId(), true, olgReports); + case SIDE2 -> moveLimitSetToTheOtherSide(modifiedBranch, limitsGroup1, modifiedLimitSetInfos.getId(), false, olgReports); + case EQUIPMENT -> { + boolean applicabilityChanged = false; + if (limitsGroup1 == null && limitsGroup2 != null) { + limitsGroup1 = modifiedBranch.newOperationalLimitsGroup1(limitsGroup2.getId()); + copyOperationalLimitsGroup(limitsGroup1.newCurrentLimits(), limitsGroup2); + applicabilityChanged = true; + } + if (limitsGroup2 == null && limitsGroup1 != null) { + limitsGroup2 = modifiedBranch.newOperationalLimitsGroup2(limitsGroup1.getId()); + copyOperationalLimitsGroup(limitsGroup2.newCurrentLimits(), limitsGroup1); + applicabilityChanged = true; + } + if (applicabilityChanged) { + logApplicabilityChange(olgReports, limitsGroup1.getId(), EQUIPMENT); + } + } + } + } + + private void moveLimitSetToTheOtherSide(Branch branch, + OperationalLimitsGroup limitsGroupToCopy, String modifiedLimitSet, + boolean isSide1, + List olgReports) { + // if we have only one limit set with the same name but applicability is not good + // we should copy existing limit set on the right side and removed it from the other side + if (olgModificationInfos.stream().filter(limitSet -> limitSet.getId().equals(modifiedLimitSet)).toList().size() == 1) { + // Copy operational limits group to the other side + OperationalLimitsGroup limitsGroup = isSide1 ? branch.newOperationalLimitsGroup1(limitsGroupToCopy.getId()) + : branch.newOperationalLimitsGroup2(limitsGroupToCopy.getId()); + copyOperationalLimitsGroup(limitsGroup.newCurrentLimits(), limitsGroupToCopy); + + olgReports.add(ReportNode.newRootReportNode().withMessageTemplate("network.modification.applicabilityChanged") + .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, limitsGroupToCopy.getId()) + .withUntypedValue(OlgUtils.APPLICABILITY, isSide1 ? SIDE1.toString() : SIDE2.toString()) + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + // Remove copied operational limits group + if (isSide1) { + branch.removeOperationalLimitsGroup2(modifiedLimitSet); + } else { + branch.removeOperationalLimitsGroup1(modifiedLimitSet); + } + } + } + + private void copyOperationalLimitsGroup(CurrentLimitsAdder limitsAdder, OperationalLimitsGroup opLimitGroupToCopy) { + // Copy all limits of the other side + opLimitGroupToCopy.getCurrentLimits().ifPresent(currentLimits -> { + limitsAdder.setPermanentLimit(currentLimits.getPermanentLimit()); + + for (LoadingLimits.TemporaryLimit tempLimit : currentLimits.getTemporaryLimits()) { + OlgUtils.addTemporaryLimit(limitsAdder, tempLimit.getName(), tempLimit.getValue(), tempLimit.getAcceptableDuration()); + } + limitsAdder.add(); + }); + } +} diff --git a/src/main/java/org/gridsuite/modification/utils/OlgUtils.java b/src/main/java/org/gridsuite/modification/utils/OlgUtils.java new file mode 100644 index 00000000..1946346f --- /dev/null +++ b/src/main/java/org/gridsuite/modification/utils/OlgUtils.java @@ -0,0 +1,166 @@ +package org.gridsuite.modification.utils; + +import com.powsybl.commons.report.ReportNode; +import com.powsybl.commons.report.TypedValue; +import com.powsybl.iidm.network.Branch; +import com.powsybl.iidm.network.CurrentLimitsAdder; +import com.powsybl.iidm.network.LoadingLimits; +import com.powsybl.iidm.network.TwoSides; +import org.gridsuite.modification.dto.AttributeModification; +import org.gridsuite.modification.dto.CurrentTemporaryLimitModificationInfos; +import org.gridsuite.modification.dto.OperationType; +import org.gridsuite.modification.dto.TemporaryLimitModificationType; +import org.gridsuite.modification.modifications.AbstractBranchModification; +import org.springframework.util.StringUtils; + +import java.util.List; +import java.util.Objects; + +public final class OlgUtils { + public static final String DURATION = "duration"; + public static final String LIMIT_ACCEPTABLE_DURATION = "limitAcceptableDuration"; + public static final String OPERATIONAL_LIMITS_GROUP_NAME = "operationalLimitsGroupName"; + public static final String SIDE = "side"; + public static final String APPLICABILITY = "applicability"; + + private OlgUtils() { + } + + private static void applySelectedOLGOnSide1(Branch branch, AttributeModification modifOperationalLimitsGroup, List reportNode, String newSelectedOLG) { + if (!StringUtils.hasText(newSelectedOLG) || modifOperationalLimitsGroup.getOp() == OperationType.UNSET) { + branch.cancelSelectedOperationalLimitsGroup1(); + if (reportNode != null) { + reportNode.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.noLimitSetSelectedOnSide1") + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + } + } else { + if (StringUtils.hasText(newSelectedOLG) && branch.getOperationalLimitsGroup1(newSelectedOLG).isEmpty() && reportNode != null) { + reportNode.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.limitSetAbsentOnSide1") + .withUntypedValue("selectedOperationalLimitsGroup", newSelectedOLG) + .withSeverity(TypedValue.WARN_SEVERITY) + .build()); + + } else { + branch.setSelectedOperationalLimitsGroup1(newSelectedOLG); + if (reportNode != null) { + reportNode.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.limitSetSelectedOnSide1") + .withUntypedValue("selectedOperationalLimitsGroup1", newSelectedOLG) + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + } + } + } + } + + private static void applySelectedOLGOnSide2(Branch branch, AttributeModification modifOperationalLimitsGroup, List reportNode, String newSelectedOLG) { + if (!StringUtils.hasText(newSelectedOLG) || modifOperationalLimitsGroup.getOp() == OperationType.UNSET) { + branch.cancelSelectedOperationalLimitsGroup2(); + if (reportNode != null) { + reportNode.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.noLimitSetSelectedOnSide2") + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + } + } else { + if (StringUtils.hasText(newSelectedOLG) && branch.getOperationalLimitsGroup2(newSelectedOLG).isEmpty() && reportNode != null) { + reportNode.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.limitSetAbsentOnSide2") + .withUntypedValue("selectedOperationalLimitsGroup", newSelectedOLG) + .withSeverity(TypedValue.WARN_SEVERITY) + .build()); + + } else { + branch.setSelectedOperationalLimitsGroup2(newSelectedOLG); + if (reportNode != null) { + reportNode.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.limitSetSelectedOnSide2") + .withUntypedValue("selectedOperationalLimitsGroup2", newSelectedOLG) + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + } + } + } + } + + public static boolean mayCreateALimit(TemporaryLimitModificationType modificationType) { + return modificationType == TemporaryLimitModificationType.ADD + || modificationType == TemporaryLimitModificationType.REPLACE + || modificationType == TemporaryLimitModificationType.MODIFY_OR_ADD; + } + + public static void modifyTemporaryLimit( + CurrentLimitsAdder limitsAdder, + CurrentTemporaryLimitModificationInfos limitModificationInfos, + List temporaryLimitsReports, + LoadingLimits.TemporaryLimit limitToModify, + double limitValue, + String limitDurationToReport, + String limitValueToReport, + int limitAcceptableDuration) { + if (Double.compare(limitToModify.getValue(), limitValue) != 0 && limitModificationInfos.getModificationType() != null) { + temporaryLimitsReports.add(ReportNode.newRootReportNode() + .withAllResourceBundlesFromClasspath() + .withMessageTemplate("network.modification.temporaryLimitModified.name") + .withUntypedValue(AbstractBranchModification.NAME, limitModificationInfos.getName()) + .withUntypedValue(DURATION, limitDurationToReport) + .withUntypedValue(AbstractBranchModification.VALUE, limitValueToReport) + .withUntypedValue("oldValue", + limitToModify.getValue() == Double.MAX_VALUE ? "no value" + : String.valueOf(limitToModify.getValue())) + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + addTemporaryLimit(limitsAdder, limitModificationInfos.getName(), limitValue, limitAcceptableDuration); + } else { + // no real modification + addTemporaryLimit(limitsAdder, limitModificationInfos.getName(), limitToModify.getValue(), limitAcceptableDuration); + } + } + + public static void createTemporaryLimit( + CurrentLimitsAdder limitsAdder, + CurrentTemporaryLimitModificationInfos limit, + List temporaryLimitsReports, + String limitDurationToReport, + String limitValueToReport, + double limitValue, + int limitAcceptableDuration) { + temporaryLimitsReports.add(ReportNode.newRootReportNode() + .withAllResourceBundlesFromClasspath() + .withMessageTemplate("network.modification.temporaryLimitAdded.name") + .withUntypedValue(AbstractBranchModification.NAME, limit.getName()) + .withUntypedValue(DURATION, limitDurationToReport) + .withUntypedValue(AbstractBranchModification.VALUE, limitValueToReport) + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + addTemporaryLimit(limitsAdder, limit.getName(), limitValue, limitAcceptableDuration); + } + + public static void addTemporaryLimit(CurrentLimitsAdder limitsAdder, String limit, double limitValue, int limitAcceptableDuration) { + limitsAdder + .beginTemporaryLimit() + .setName(limit) + .setValue(limitValue) + .setAcceptableDuration(limitAcceptableDuration) + .endTemporaryLimit(); + } + + public static void modifySelectedOperationalLimitsGroup( + Branch branch, + AttributeModification modifOperationalLimitsGroup, + TwoSides side, + List reportNode) { + Objects.requireNonNull(side); + if (modifOperationalLimitsGroup != null) { + String newSelectedOLG = modifOperationalLimitsGroup.getValue(); + if (side == TwoSides.ONE) { + applySelectedOLGOnSide1(branch, modifOperationalLimitsGroup, reportNode, newSelectedOLG); + } else if (side == TwoSides.TWO) { + applySelectedOLGOnSide2(branch, modifOperationalLimitsGroup, reportNode, newSelectedOLG); + } + } + } +} From f31fdc239974cb3fa13a6ee773003c28d330a0ed Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Mon, 24 Nov 2025 11:32:16 +0100 Subject: [PATCH 02/22] corrects TU Signed-off-by: Mathieu DEHARBE --- .../modifications/olg/OlgModification.java | 73 +++++++++++-------- .../modifications/olg/OlgsModification.java | 2 +- 2 files changed, 45 insertions(+), 30 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index 450db7e8..89c36245 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -13,7 +13,6 @@ import java.util.Iterator; import java.util.List; import java.util.Set; -import java.util.function.Function; import static org.gridsuite.modification.dto.OperationalLimitsGroupInfos.Applicability.*; import static org.gridsuite.modification.modifications.AbstractBranchModification.NAME; @@ -45,28 +44,28 @@ private OperationalLimitsGroup modifiedOperationalLimitsGroup2() { return modifiedBranch.getOperationalLimitsGroup2(olgModifInfos.getId()).orElse(null); } - protected void applyModificationToOperationalLimitsGroup(Function groupFactory) { + protected void applyModificationToOperationalLimitsGroup() { switch (olgModifInfos.getModificationType()) { case OperationalLimitsGroupModificationType.MODIFY_OR_ADD: { switch (olgModifInfos.getApplicability()) { case EQUIPMENT : if (modifiedOperationalLimitsGroup1() == null && modifiedOperationalLimitsGroup2() == null) { // TODO : attention quand un est valide et l'autre non - addOpLG(groupFactory, olgModifInfos.getApplicability()); + addOlg(); } else { modifyOLG(); } break; case SIDE1 : if (modifiedOperationalLimitsGroup1() == null) { - addOpLG(groupFactory, olgModifInfos.getApplicability()); + addOlg(); } else { modifyOLG(); } break; case SIDE2 : if (modifiedOperationalLimitsGroup2() == null) { - addOpLG(groupFactory, olgModifInfos.getApplicability()); + addOlg(); } else { modifyOLG(); } @@ -83,10 +82,10 @@ protected void applyModificationToOperationalLimitsGroup(Function groupFactory, OperationalLimitsGroupInfos.Applicability applicability) { + private void addOlg() { List limitSetReports = new ArrayList<>(); - if ((applicability == EQUIPMENT || applicability == SIDE1) && modifiedOperationalLimitsGroup1() != null) { - throw new PowsyblException("Cannot add " + modifiedOperationalLimitsGroup1().getId() + " operational limit group, one with the given name already exists"); + if (olgModifInfos.getApplicability() == EQUIPMENT || olgModifInfos.getApplicability() == SIDE1) { + if (modifiedOperationalLimitsGroup1() != null) { + throw new PowsyblException("Cannot add " + modifiedOperationalLimitsGroup1().getId() + " operational limit group, one with the given name already exists"); + } + addOlgOnASide(modifiedBranch.newOperationalLimitsGroup1(olgModifInfos.getId()), limitSetReports); } - if ((applicability == EQUIPMENT || applicability == SIDE2) && modifiedOperationalLimitsGroup2() != null) { - throw new PowsyblException("Cannot add " + modifiedOperationalLimitsGroup2().getId() + " operational limit group, one with the given name already exists"); + if (olgModifInfos.getApplicability() == EQUIPMENT || olgModifInfos.getApplicability() == SIDE2) { + if (modifiedOperationalLimitsGroup2() != null) { + throw new PowsyblException("Cannot add " + modifiedOperationalLimitsGroup2().getId() + " operational limit group, one with the given name already exists"); + } + addOlgOnASide(modifiedBranch.newOperationalLimitsGroup2(olgModifInfos.getId()), limitSetReports); } - OperationalLimitsGroup newOperationalLimitsGroup = groupFactory.apply(olgModifInfos.getId()); - modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), - newOperationalLimitsGroup.getCurrentLimits().orElse(null), limitSetReports); - addProperties(newOperationalLimitsGroup, limitSetReports); if (!CollectionUtils.isEmpty(limitSetReports)) { ReportNode limitSetNode = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupAdded") .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) - .withUntypedValue(OlgUtils.SIDE, applicability.toString()) - .withSeverity(TypedValue.INFO_SEVERITY) + .withUntypedValue(OlgUtils.SIDE, olgModifInfos.getApplicability().toString()) + .withSeverity(TypedValue.DETAIL_SEVERITY) .add(); ModificationUtils.getInstance().reportModifications(limitSetNode, limitSetReports); } } - private void replaceOpLG(Function groupFactory) { + private void addOlgOnASide(OperationalLimitsGroup newOperationalLimitsGroup, List limitSetReports) { + modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), + newOperationalLimitsGroup.getCurrentLimits().orElse(null), limitSetReports); + addProperties(newOperationalLimitsGroup, limitSetReports); + } + + private void replaceOpLG() { List limitSetReports = new ArrayList<>(); - if (modifySide1() && modifiedOperationalLimitsGroup1() != null) { - modifiedOperationalLimitsGroup1().removeCurrentLimits(); - removeAllProperties(modifiedOperationalLimitsGroup1(), limitSetReports); + if (modifySide1()) { + OperationalLimitsGroup modifiedOlg = modifiedOperationalLimitsGroup1(); + if (modifiedOlg != null) { + modifiedOlg.removeCurrentLimits(); + removeAllProperties(modifiedOlg, limitSetReports); + } + OperationalLimitsGroup newOperationalLimitsGroup = modifiedBranch.newOperationalLimitsGroup1(olgModifInfos.getId()); + modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), null, limitSetReports); + addProperties(newOperationalLimitsGroup, limitSetReports); } - if (modifySide2() && modifiedOperationalLimitsGroup2() != null) { - modifiedOperationalLimitsGroup2().removeCurrentLimits(); - removeAllProperties(modifiedOperationalLimitsGroup2(), limitSetReports); + if (modifySide2()) { + OperationalLimitsGroup modifiedOlg = modifiedOperationalLimitsGroup2(); + if (modifiedOlg != null) { + modifiedOlg.removeCurrentLimits(); + removeAllProperties(modifiedOlg, limitSetReports); + } + OperationalLimitsGroup newOperationalLimitsGroup = modifiedBranch.newOperationalLimitsGroup2(olgModifInfos.getId()); + modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), null, limitSetReports); + addProperties(newOperationalLimitsGroup, limitSetReports); } - OperationalLimitsGroup newOperationalLimitsGroup = groupFactory.apply(olgModifInfos.getId()); - modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), null, limitSetReports); - addProperties(newOperationalLimitsGroup, limitSetReports); - if (!CollectionUtils.isEmpty(limitSetReports)) { ReportNode reportNode = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupReplaced") diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java index 59ef93fe..3aefa613 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java @@ -53,7 +53,7 @@ public void modifyOperationalLimitsGroups(OperationalLimitsGroupsModificationTyp modifiedBranch, opLGModifInfos, olgsReportNode - ).applyModificationToOperationalLimitsGroup(modifiedBranch::newOperationalLimitsGroup1); + ).applyModificationToOperationalLimitsGroup(); } } From 47b4492145770e62d69a0954df82fdb02d889144 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Mon, 24 Nov 2025 13:32:05 +0100 Subject: [PATCH 03/22] permanent limit Signed-off-by: Mathieu DEHARBE --- .../modifications/olg/OlgModification.java | 40 ++++++++++--------- .../modification/utils/OlgUtils.java | 4 +- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index 89c36245..edbc360f 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -73,10 +73,10 @@ protected void applyModificationToOperationalLimitsGroup() { } } break; case OperationalLimitsGroupModificationType.MODIFY: { - if (modifySide1() && modifiedOperationalLimitsGroup1() == null) { + if (applicableOnSide1() && modifiedOperationalLimitsGroup1() == null) { throw new PowsyblException("Cannot modify operational limit group " + olgModifInfos.getId() + " which has not been found in equipment side 1"); } - if (modifySide2() && modifiedOperationalLimitsGroup2() == null) { + if (applicableOnSide2() && modifiedOperationalLimitsGroup2() == null) { throw new PowsyblException("Cannot modify operational limit group " + olgModifInfos.getId() + " which has not been found in equipment side 2"); } modifyOLG(); @@ -93,11 +93,11 @@ protected void applyModificationToOperationalLimitsGroup() { } } - private boolean modifySide1() { + private boolean applicableOnSide1() { return olgModifInfos.getApplicability() == SIDE1 || olgModifInfos.getApplicability() == EQUIPMENT; } - private boolean modifySide2() { + private boolean applicableOnSide2() { return olgModifInfos.getApplicability() == SIDE2 || olgModifInfos.getApplicability() == EQUIPMENT; } @@ -105,13 +105,13 @@ private void modifyOLG() { List limitSetsReports = new ArrayList<>(); - if (modifySide1()) { + if (applicableOnSide1()) { modifiedOperationalLimitsGroup1().getCurrentLimits().ifPresent(currentLimits -> { modifyCurrentLimits(modifiedOperationalLimitsGroup1().newCurrentLimits(), currentLimits, limitSetsReports); modifyProperties(modifiedOperationalLimitsGroup1(), limitSetsReports); }); } - if (modifySide2()) { + if (applicableOnSide2()) { modifiedOperationalLimitsGroup2().getCurrentLimits().ifPresent(currentLimits -> { modifyCurrentLimits(modifiedOperationalLimitsGroup2().newCurrentLimits(), currentLimits, limitSetsReports); modifyProperties(modifiedOperationalLimitsGroup2(), limitSetsReports); @@ -197,8 +197,12 @@ protected void modifyCurrentLimits( boolean hasPermanent = currentLimitsInfos.getPermanentLimit() != null; if (hasPermanent) { if (!(currentLimits != null && currentLimits.getPermanentLimit() == currentLimitsInfos.getPermanentLimit())) { - limitsReports.add(ModificationUtils.getInstance().buildModificationReport(currentLimits != null ? currentLimits.getPermanentLimit() : Double.NaN, - currentLimitsInfos.getPermanentLimit(), "PATL")); + limitsReports.add( + ModificationUtils.buildModificationReport( + currentLimits != null ? currentLimits.getPermanentLimit() : Double.NaN, currentLimitsInfos.getPermanentLimit(), + "Permanent limit", + TypedValue.DETAIL_SEVERITY + )); } limitsAdder.setPermanentLimit(currentLimitsInfos.getPermanentLimit()); } else { @@ -231,7 +235,7 @@ private void addOlg() { .withMessageTemplate("network.modification.operationalLimitsGroupAdded") .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) .withUntypedValue(OlgUtils.SIDE, olgModifInfos.getApplicability().toString()) - .withSeverity(TypedValue.DETAIL_SEVERITY) + .withSeverity(TypedValue.INFO_SEVERITY) .add(); ModificationUtils.getInstance().reportModifications(limitSetNode, limitSetReports); } @@ -245,7 +249,7 @@ private void addOlgOnASide(OperationalLimitsGroup newOperationalLimitsGroup, Lis private void replaceOpLG() { List limitSetReports = new ArrayList<>(); - if (modifySide1()) { + if (applicableOnSide1()) { OperationalLimitsGroup modifiedOlg = modifiedOperationalLimitsGroup1(); if (modifiedOlg != null) { modifiedOlg.removeCurrentLimits(); @@ -255,7 +259,7 @@ private void replaceOpLG() { modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), null, limitSetReports); addProperties(newOperationalLimitsGroup, limitSetReports); } - if (modifySide2()) { + if (applicableOnSide2()) { OperationalLimitsGroup modifiedOlg = modifiedOperationalLimitsGroup2(); if (modifiedOlg != null) { modifiedOlg.removeCurrentLimits(); @@ -295,14 +299,14 @@ private void addProperties(OperationalLimitsGroup limitsGroup, List public void removeOlg() { String olgId = olgModifInfos.getId(); - if (modifySide1() && modifiedBranch.getOperationalLimitsGroup1(olgId).isEmpty() || - modifySide2() && modifiedBranch.getOperationalLimitsGroup2(olgId).isEmpty()) { + if (applicableOnSide1() && modifiedBranch.getOperationalLimitsGroup1(olgId).isEmpty() || + applicableOnSide2() && modifiedBranch.getOperationalLimitsGroup2(olgId).isEmpty()) { throw new PowsyblException("Cannot delete operational limit group " + olgId + " which has not been found in equipment on side " + olgModifInfos.getApplicability().toString()); } - if (modifySide1()) { + if (applicableOnSide1()) { modifiedBranch.removeOperationalLimitsGroup1(olgId); } - if (modifySide2()) { + if (applicableOnSide2()) { modifiedBranch.removeOperationalLimitsGroup2(olgId); } olgsReportNode.newReportNode() @@ -366,7 +370,7 @@ protected void modifyTemporaryLimits(CurrentLimitsAdder limitsAdder, temporaryLimitsReports.addFirst(ReportNode.newRootReportNode() .withAllResourceBundlesFromClasspath() .withMessageTemplate("network.modification.temporaryLimitsReplaced") - .withSeverity(TypedValue.INFO_SEVERITY) + .withSeverity(TypedValue.DETAIL_SEVERITY) .build()); } else { // we add (back) the temporary limits that have not been modified @@ -379,7 +383,7 @@ protected void modifyTemporaryLimits(CurrentLimitsAdder limitsAdder, temporaryLimitsReports.addFirst(ReportNode.newRootReportNode() .withAllResourceBundlesFromClasspath() .withMessageTemplate("network.modification.temporaryLimitsModification") - .withSeverity(TypedValue.INFO_SEVERITY) + .withSeverity(TypedValue.DETAIL_SEVERITY) .build()); limitsReports.addAll(temporaryLimitsReports); } @@ -421,7 +425,7 @@ private void applyTemporaryLimitModification( .withMessageTemplate("network.modification.temporaryLimitDeleted.name") .withUntypedValue(NAME, limit.getName()) .withUntypedValue(OlgUtils.DURATION, limitDurationToReport) - .withSeverity(TypedValue.INFO_SEVERITY) + .withSeverity(TypedValue.DETAIL_SEVERITY) .build()); } else { OlgUtils.modifyTemporaryLimit(limitsAdder, limit, temporaryLimitsReports, limitToModify, limitValue, limitDurationToReport, limitValueToReport, limitAcceptableDuration); diff --git a/src/main/java/org/gridsuite/modification/utils/OlgUtils.java b/src/main/java/org/gridsuite/modification/utils/OlgUtils.java index 1946346f..b969fe3e 100644 --- a/src/main/java/org/gridsuite/modification/utils/OlgUtils.java +++ b/src/main/java/org/gridsuite/modification/utils/OlgUtils.java @@ -111,7 +111,7 @@ public static void modifyTemporaryLimit( .withUntypedValue("oldValue", limitToModify.getValue() == Double.MAX_VALUE ? "no value" : String.valueOf(limitToModify.getValue())) - .withSeverity(TypedValue.INFO_SEVERITY) + .withSeverity(TypedValue.DETAIL_SEVERITY) .build()); addTemporaryLimit(limitsAdder, limitModificationInfos.getName(), limitValue, limitAcceptableDuration); } else { @@ -134,7 +134,7 @@ public static void createTemporaryLimit( .withUntypedValue(AbstractBranchModification.NAME, limit.getName()) .withUntypedValue(DURATION, limitDurationToReport) .withUntypedValue(AbstractBranchModification.VALUE, limitValueToReport) - .withSeverity(TypedValue.INFO_SEVERITY) + .withSeverity(TypedValue.DETAIL_SEVERITY) .build()); addTemporaryLimit(limitsAdder, limit.getName(), limitValue, limitAcceptableDuration); } From 8d6e732a4594c8380bd522a5f48fa0ba19f8927c Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Mon, 24 Nov 2025 13:42:11 +0100 Subject: [PATCH 04/22] applicabilityToString Signed-off-by: Mathieu DEHARBE --- .../modifications/olg/OlgModification.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index edbc360f..d49e8a5a 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -122,7 +122,7 @@ private void modifyOLG() { ReportNode limitSetReport = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupModified") .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) - .withUntypedValue(OlgUtils.SIDE, olgModifInfos.getApplicability().toString()) + .withUntypedValue(OlgUtils.SIDE, applicabilityToString(olgModifInfos.getApplicability())) .withSeverity(TypedValue.INFO_SEVERITY).add(); ModificationUtils.getInstance().reportModifications(limitSetReport, limitSetsReports); } @@ -234,13 +234,21 @@ private void addOlg() { ReportNode limitSetNode = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupAdded") .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) - .withUntypedValue(OlgUtils.SIDE, olgModifInfos.getApplicability().toString()) + .withUntypedValue(OlgUtils.SIDE, applicabilityToString(olgModifInfos.getApplicability())) .withSeverity(TypedValue.INFO_SEVERITY) .add(); ModificationUtils.getInstance().reportModifications(limitSetNode, limitSetReports); } } + private String applicabilityToString(OperationalLimitsGroupInfos.Applicability applicability) { + return switch (applicability) { + case EQUIPMENT -> "sides 1 & 2"; + case SIDE1 -> "side 1"; + case SIDE2 -> "side 2"; + }; + } + private void addOlgOnASide(OperationalLimitsGroup newOperationalLimitsGroup, List limitSetReports) { modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), newOperationalLimitsGroup.getCurrentLimits().orElse(null), limitSetReports); @@ -274,7 +282,7 @@ private void replaceOpLG() { ReportNode reportNode = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupReplaced") .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) - .withUntypedValue(OlgUtils.SIDE, olgModifInfos.getApplicability().toString()) + .withUntypedValue(OlgUtils.SIDE, applicabilityToString(olgModifInfos.getApplicability())) .withSeverity(TypedValue.INFO_SEVERITY) .add(); ModificationUtils.getInstance().reportModifications(reportNode, limitSetReports); @@ -301,7 +309,8 @@ public void removeOlg() { String olgId = olgModifInfos.getId(); if (applicableOnSide1() && modifiedBranch.getOperationalLimitsGroup1(olgId).isEmpty() || applicableOnSide2() && modifiedBranch.getOperationalLimitsGroup2(olgId).isEmpty()) { - throw new PowsyblException("Cannot delete operational limit group " + olgId + " which has not been found in equipment on side " + olgModifInfos.getApplicability().toString()); + throw new PowsyblException( + "Cannot delete operational limit group " + olgId + " which has not been found in equipment on " + applicabilityToString(olgModifInfos.getApplicability())); } if (applicableOnSide1()) { modifiedBranch.removeOperationalLimitsGroup1(olgId); @@ -312,7 +321,7 @@ public void removeOlg() { olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupDeleted") .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgId) - .withUntypedValue(OlgUtils.SIDE, olgModifInfos.getApplicability().toString()) + .withUntypedValue(OlgUtils.SIDE, applicabilityToString(olgModifInfos.getApplicability())) .withSeverity(TypedValue.INFO_SEVERITY) .add(); } From 2f4df9d81522b3755e3779d67665091c16176674 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Mon, 24 Nov 2025 13:51:23 +0100 Subject: [PATCH 05/22] applicabilityToString in the UTs Signed-off-by: Mathieu DEHARBE --- .../modification/modifications/LineModificationTest.java | 2 +- .../tabularmodifications/LimitSetModificationsTest.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/gridsuite/modification/modifications/LineModificationTest.java b/src/test/java/org/gridsuite/modification/modifications/LineModificationTest.java index c890a802..c4d2d65d 100644 --- a/src/test/java/org/gridsuite/modification/modifications/LineModificationTest.java +++ b/src/test/java/org/gridsuite/modification/modifications/LineModificationTest.java @@ -407,7 +407,7 @@ void testDelete() { 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); + assertEquals("Cannot delete operational limit group doesNotExist which has not been found in equipment on side 2", errorMessage); } private void changeLineConnectionState(Line existingEquipment, boolean expectedState) { diff --git a/src/test/java/org/gridsuite/modification/modifications/tabularmodifications/LimitSetModificationsTest.java b/src/test/java/org/gridsuite/modification/modifications/tabularmodifications/LimitSetModificationsTest.java index de9c0ef1..24a3286c 100644 --- a/src/test/java/org/gridsuite/modification/modifications/tabularmodifications/LimitSetModificationsTest.java +++ b/src/test/java/org/gridsuite/modification/modifications/tabularmodifications/LimitSetModificationsTest.java @@ -238,13 +238,13 @@ protected void assertAfterNetworkModificationApplication() { private void assertAfterNetworkModificationApplication(ReportNode reportNode) { assertAfterNetworkModificationApplication(); - assertLogMessageWithoutRank("Limit set DEFAULT has been modified on SIDE1", "network.modification.operationalLimitsGroupModified", reportNode); + assertLogMessageWithoutRank("Limit set DEFAULT has been modified on side 1", "network.modification.operationalLimitsGroupModified", reportNode); assertLogMessageWithoutRank("Previous temporary limits were removed", "network.modification.temporaryLimitsReplaced", reportNode); assertLogMessageWithoutRank("Cannot add DEFAULT operational limit group, one with the given name already exists", "network.modification.tabular.modification.exception", reportNode); assertLogMessageWithoutRank("No existing temporary limit found with acceptableDuration = 3 matching is based on acceptableDuration if that helps", "network.modification.temporaryLimitsNoMatch", reportNode); assertLogMessageWithoutRank("limit set selected on side 2 : group0", "network.modification.limitSetSelectedOnSide2", reportNode); - assertLogMessageWithoutRank("Limit set group0 has been replaced on SIDE2", "network.modification.operationalLimitsGroupReplaced", reportNode); - assertLogMessageWithoutRank("Limit set DEFAULT added on SIDE1", "network.modification.operationalLimitsGroupAdded", reportNode); + assertLogMessageWithoutRank("Limit set group0 has been replaced on side 2", "network.modification.operationalLimitsGroupReplaced", reportNode); + assertLogMessageWithoutRank("Limit set DEFAULT added on side 1", "network.modification.operationalLimitsGroupAdded", reportNode); } From fc9d514ffd81f2c504e10e24ea476d0e0c38de94 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Mon, 24 Nov 2025 14:08:14 +0100 Subject: [PATCH 06/22] correct handling of ambiguous ADD or MODIFY Signed-off-by: Mathieu DEHARBE --- .../modifications/olg/OlgModification.java | 68 ++++++++++++------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index d49e8a5a..5da8ac05 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -50,24 +50,36 @@ protected void applyModificationToOperationalLimitsGroup() { switch (olgModifInfos.getApplicability()) { case EQUIPMENT : if (modifiedOperationalLimitsGroup1() == null && modifiedOperationalLimitsGroup2() == null) { - // TODO : attention quand un est valide et l'autre non - addOlg(); + addOlg(EQUIPMENT); + } + else if (modifiedOperationalLimitsGroup1() == null && modifiedOperationalLimitsGroup2() != null) { + modifyOLG(EQUIPMENT); } else { - modifyOLG(); + // one side already existed (modification), the other was empty so this is a creation + if (modifiedOperationalLimitsGroup1() == null) { + addOlg(SIDE1); + } else { + modifyOLG(SIDE1); + } + if (modifiedOperationalLimitsGroup2() == null) { + addOlg(SIDE2); + } else { + modifyOLG(SIDE2); + } } break; case SIDE1 : if (modifiedOperationalLimitsGroup1() == null) { - addOlg(); + addOlg(olgModifInfos.getApplicability()); } else { - modifyOLG(); + modifyOLG(olgModifInfos.getApplicability()); } break; case SIDE2 : if (modifiedOperationalLimitsGroup2() == null) { - addOlg(); + addOlg(olgModifInfos.getApplicability()); } else { - modifyOLG(); + modifyOLG(olgModifInfos.getApplicability()); } break; } @@ -79,10 +91,10 @@ protected void applyModificationToOperationalLimitsGroup() { if (applicableOnSide2() && modifiedOperationalLimitsGroup2() == null) { throw new PowsyblException("Cannot modify operational limit group " + olgModifInfos.getId() + " which has not been found in equipment side 2"); } - modifyOLG(); + modifyOLG(olgModifInfos.getApplicability()); } break; case OperationalLimitsGroupModificationType.ADD: { - addOlg(); + addOlg(olgModifInfos.getApplicability()); } break; case OperationalLimitsGroupModificationType.REPLACE: { replaceOpLG(); @@ -101,28 +113,34 @@ private boolean applicableOnSide2() { return olgModifInfos.getApplicability() == SIDE2 || olgModifInfos.getApplicability() == EQUIPMENT; } - private void modifyOLG() { + private void modifyOLG(OperationalLimitsGroupInfos.Applicability applicability) { List limitSetsReports = new ArrayList<>(); - if (applicableOnSide1()) { - modifiedOperationalLimitsGroup1().getCurrentLimits().ifPresent(currentLimits -> { - modifyCurrentLimits(modifiedOperationalLimitsGroup1().newCurrentLimits(), currentLimits, limitSetsReports); - modifyProperties(modifiedOperationalLimitsGroup1(), limitSetsReports); - }); + if (applicability == SIDE1 || applicability == EQUIPMENT) { + OperationalLimitsGroup modifiedOlg = modifiedOperationalLimitsGroup1(); + if (modifiedOlg != null) { + modifiedOlg.getCurrentLimits().ifPresent(currentLimits -> { + modifyCurrentLimits(modifiedOlg.newCurrentLimits(), currentLimits, limitSetsReports); + modifyProperties(modifiedOlg, limitSetsReports); + }); + } } - if (applicableOnSide2()) { - modifiedOperationalLimitsGroup2().getCurrentLimits().ifPresent(currentLimits -> { - modifyCurrentLimits(modifiedOperationalLimitsGroup2().newCurrentLimits(), currentLimits, limitSetsReports); - modifyProperties(modifiedOperationalLimitsGroup2(), limitSetsReports); - }); + if (applicability == SIDE2 || applicability == EQUIPMENT) { + OperationalLimitsGroup modifiedOlg = modifiedOperationalLimitsGroup2(); + if (modifiedOlg != null) { + modifiedOlg.getCurrentLimits().ifPresent(currentLimits -> { + modifyCurrentLimits(modifiedOlg.newCurrentLimits(), currentLimits, limitSetsReports); + modifyProperties(modifiedOlg, limitSetsReports); + }); + } } if (!limitSetsReports.isEmpty()) { ReportNode limitSetReport = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupModified") .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) - .withUntypedValue(OlgUtils.SIDE, applicabilityToString(olgModifInfos.getApplicability())) + .withUntypedValue(OlgUtils.SIDE, applicabilityToString(applicability)) .withSeverity(TypedValue.INFO_SEVERITY).add(); ModificationUtils.getInstance().reportModifications(limitSetReport, limitSetsReports); } @@ -214,16 +232,16 @@ protected void modifyCurrentLimits( limitsAdder.add(); } - private void addOlg() { + private void addOlg(OperationalLimitsGroupInfos.Applicability applicability) { List limitSetReports = new ArrayList<>(); - if (olgModifInfos.getApplicability() == EQUIPMENT || olgModifInfos.getApplicability() == SIDE1) { + if (applicability == EQUIPMENT || applicability == SIDE1) { if (modifiedOperationalLimitsGroup1() != null) { throw new PowsyblException("Cannot add " + modifiedOperationalLimitsGroup1().getId() + " operational limit group, one with the given name already exists"); } addOlgOnASide(modifiedBranch.newOperationalLimitsGroup1(olgModifInfos.getId()), limitSetReports); } - if (olgModifInfos.getApplicability() == EQUIPMENT || olgModifInfos.getApplicability() == SIDE2) { + if (applicability == EQUIPMENT || applicability == SIDE2) { if (modifiedOperationalLimitsGroup2() != null) { throw new PowsyblException("Cannot add " + modifiedOperationalLimitsGroup2().getId() + " operational limit group, one with the given name already exists"); } @@ -234,7 +252,7 @@ private void addOlg() { ReportNode limitSetNode = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupAdded") .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) - .withUntypedValue(OlgUtils.SIDE, applicabilityToString(olgModifInfos.getApplicability())) + .withUntypedValue(OlgUtils.SIDE, applicabilityToString(applicability)) .withSeverity(TypedValue.INFO_SEVERITY) .add(); ModificationUtils.getInstance().reportModifications(limitSetNode, limitSetReports); From 6ce5c99f31c8f1a19829e4c3354d892c7b7bc840 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Mon, 24 Nov 2025 14:15:04 +0100 Subject: [PATCH 07/22] code style Signed-off-by: Mathieu DEHARBE --- .../modification/modifications/olg/OlgModification.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index 5da8ac05..d50bf6b5 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -51,8 +51,7 @@ protected void applyModificationToOperationalLimitsGroup() { case EQUIPMENT : if (modifiedOperationalLimitsGroup1() == null && modifiedOperationalLimitsGroup2() == null) { addOlg(EQUIPMENT); - } - else if (modifiedOperationalLimitsGroup1() == null && modifiedOperationalLimitsGroup2() != null) { + } else if (modifiedOperationalLimitsGroup1() != null && modifiedOperationalLimitsGroup2() != null) { modifyOLG(EQUIPMENT); } else { // one side already existed (modification), the other was empty so this is a creation From 6bc3cc7ec810d449df643bf844667c5c41d63435 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Mon, 24 Nov 2025 17:26:56 +0100 Subject: [PATCH 08/22] sub report node for each side Signed-off-by: Mathieu DEHARBE --- .../modifications/olg/OlgModification.java | 243 ++++++++++++------ .../modifications/olg/OlgsModification.java | 8 + .../modification/utils/OlgUtils.java | 50 ---- .../gridsuite/modification/reports.properties | 6 +- 4 files changed, 180 insertions(+), 127 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index d50bf6b5..c0117df6 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -1,3 +1,9 @@ +/** + * Copyright (c) 2025, 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 org.gridsuite.modification.modifications.olg; import com.powsybl.commons.PowsyblException; @@ -5,6 +11,7 @@ import com.powsybl.commons.report.TypedValue; import com.powsybl.iidm.network.*; import org.gridsuite.modification.dto.*; +import org.gridsuite.modification.modifications.AbstractBranchModification; import org.gridsuite.modification.utils.ModificationUtils; import org.gridsuite.modification.utils.OlgUtils; import org.springframework.util.CollectionUtils; @@ -17,15 +24,20 @@ import static org.gridsuite.modification.dto.OperationalLimitsGroupInfos.Applicability.*; import static org.gridsuite.modification.modifications.AbstractBranchModification.NAME; import static org.gridsuite.modification.modifications.AbstractBranchModification.VALUE; +import static org.gridsuite.modification.utils.OlgUtils.DURATION; /** * handles the modification of a single operational limits group from AbstractBranchModification * it may affect both sides of an operational limits group + * + * @author Mathieu DEHARBE */ public class OlgModification { private final Branch modifiedBranch; // branch modified by the network modification private final OperationalLimitsGroupModificationInfos olgModifInfos; private final ReportNode olgsReportNode; + List limitsReportsSide1; + List limitsReportsSide2; public OlgModification( Branch modifiedBranch, @@ -34,6 +46,17 @@ public OlgModification( this.modifiedBranch = modifiedBranch; this.olgModifInfos = olgModifInfos; olgsReportNode = limitSetsReportNode; + limitsReportsSide1 = new ArrayList<>(); + limitsReportsSide2 = new ArrayList<>(); + } + + private void logOnSide(ReportNode reportNode, OperationalLimitsGroupInfos.Applicability applicability) { + if (applicability == EQUIPMENT || applicability == SIDE1) { + limitsReportsSide1.add(reportNode); + } + if (applicability == EQUIPMENT || applicability == SIDE2) { + limitsReportsSide2.add(reportNode); + } } private OperationalLimitsGroup modifiedOperationalLimitsGroup1() { @@ -113,15 +136,12 @@ private boolean applicableOnSide2() { } private void modifyOLG(OperationalLimitsGroupInfos.Applicability applicability) { - - List limitSetsReports = new ArrayList<>(); - if (applicability == SIDE1 || applicability == EQUIPMENT) { OperationalLimitsGroup modifiedOlg = modifiedOperationalLimitsGroup1(); if (modifiedOlg != null) { modifiedOlg.getCurrentLimits().ifPresent(currentLimits -> { - modifyCurrentLimits(modifiedOlg.newCurrentLimits(), currentLimits, limitSetsReports); - modifyProperties(modifiedOlg, limitSetsReports); + modifyCurrentLimits(modifiedOlg.newCurrentLimits(), currentLimits, SIDE1); + modifyProperties(modifiedOlg, SIDE1); }); } } @@ -129,24 +149,37 @@ private void modifyOLG(OperationalLimitsGroupInfos.Applicability applicability) OperationalLimitsGroup modifiedOlg = modifiedOperationalLimitsGroup2(); if (modifiedOlg != null) { modifiedOlg.getCurrentLimits().ifPresent(currentLimits -> { - modifyCurrentLimits(modifiedOlg.newCurrentLimits(), currentLimits, limitSetsReports); - modifyProperties(modifiedOlg, limitSetsReports); + modifyCurrentLimits(modifiedOlg.newCurrentLimits(), currentLimits, SIDE2); + modifyProperties(modifiedOlg, SIDE2); }); } } - if (!limitSetsReports.isEmpty()) { + if (!limitsReportsSide1.isEmpty() || !limitsReportsSide2.isEmpty()) { ReportNode limitSetReport = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupModified") .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) .withUntypedValue(OlgUtils.SIDE, applicabilityToString(applicability)) .withSeverity(TypedValue.INFO_SEVERITY).add(); - ModificationUtils.getInstance().reportModifications(limitSetReport, limitSetsReports); + logSideNode(limitSetReport, "network.modification.operationalLimitsGroupModified.detail", limitsReportsSide1); + logSideNode(limitSetReport, "network.modification.operationalLimitsGroupModified.detail", limitsReportsSide2); + } + } + + /** + * cerates a log node specific for each side + */ + private void logSideNode(ReportNode limitSetReport, String messageTemplate, List limitsReports) { + if (!limitsReports.isEmpty()) { + ReportNode limitSetReport1 = limitSetReport.newReportNode() + .withMessageTemplate(messageTemplate) + .withUntypedValue(OlgUtils.SIDE, applicabilityToString(SIDE1)) + .withSeverity(TypedValue.DETAIL_SEVERITY).add(); + ModificationUtils.getInstance().reportModifications(limitSetReport1, limitsReports); } } - private void modifyProperties(OperationalLimitsGroup limitsGroup, - List limitSetsReports) { + private void modifyProperties(OperationalLimitsGroup limitsGroup, OperationalLimitsGroupInfos.Applicability applicability) { if (limitsGroup == null || olgModifInfos == null) { return; } @@ -175,10 +208,11 @@ private void modifyProperties(OperationalLimitsGroup limitsGroup, propertiesToRemove.forEach((String propertyName) -> { limitsGroup.removeProperty(propertyName); - limitSetsReports.add(ReportNode.newRootReportNode() + logOnSide(ReportNode.newRootReportNode() .withMessageTemplate("network.modification.propertyDeleted") .withUntypedValue(NAME, propertyName) - .withSeverity(TypedValue.DETAIL_SEVERITY).build()); + .withSeverity(TypedValue.DETAIL_SEVERITY).build(), + applicability); }); propertiesToModify.forEach((LimitsPropertyInfos property) -> { @@ -186,22 +220,24 @@ private void modifyProperties(OperationalLimitsGroup limitsGroup, if (limitsGroup.getProperty(property.name()).equals(property.value())) { return; } - limitSetsReports.add(ReportNode.newRootReportNode() + logOnSide(ReportNode.newRootReportNode() .withMessageTemplate("network.modification.propertyChanged") .withUntypedValue(NAME, property.name()) .withUntypedValue("to", property.value()) .withUntypedValue("from", limitsGroup.getProperty(property.name())) - .withSeverity(TypedValue.DETAIL_SEVERITY).build()); + .withSeverity(TypedValue.DETAIL_SEVERITY).build(), + applicability); limitsGroup.setProperty(property.name(), property.value()); }); propertiesToAdd.forEach((LimitsPropertyInfos property) -> { - limitSetsReports.add(ReportNode.newRootReportNode() + logOnSide(ReportNode.newRootReportNode() .withMessageTemplate("network.modification.propertyAdded") .withUntypedValue(NAME, property.name()) .withUntypedValue(VALUE, property.value()) .withSeverity(TypedValue.DETAIL_SEVERITY) - .build()); + .build(), + applicability); limitsGroup.setProperty(property.name(), property.value()); }); } @@ -209,17 +245,17 @@ private void modifyProperties(OperationalLimitsGroup limitsGroup, protected void modifyCurrentLimits( CurrentLimitsAdder limitsAdder, CurrentLimits currentLimits, - List limitsReports) { + OperationalLimitsGroupInfos.Applicability applicability) { CurrentLimitsModificationInfos currentLimitsInfos = olgModifInfos.getCurrentLimits(); boolean hasPermanent = currentLimitsInfos.getPermanentLimit() != null; if (hasPermanent) { if (!(currentLimits != null && currentLimits.getPermanentLimit() == currentLimitsInfos.getPermanentLimit())) { - limitsReports.add( - ModificationUtils.buildModificationReport( - currentLimits != null ? currentLimits.getPermanentLimit() : Double.NaN, currentLimitsInfos.getPermanentLimit(), + logOnSide(ModificationUtils.buildModificationReport( + currentLimits != null ? currentLimits.getPermanentLimit() : Double.NaN, currentLimitsInfos.getPermanentLimit(), "Permanent limit", TypedValue.DETAIL_SEVERITY - )); + ), + applicability); } limitsAdder.setPermanentLimit(currentLimitsInfos.getPermanentLimit()); } else { @@ -227,34 +263,33 @@ protected void modifyCurrentLimits( limitsAdder.setPermanentLimit(currentLimits.getPermanentLimit()); } } - modifyTemporaryLimits(limitsAdder, currentLimits, limitsReports); + modifyTemporaryLimits(limitsAdder, currentLimits, applicability); limitsAdder.add(); } private void addOlg(OperationalLimitsGroupInfos.Applicability applicability) { - - List limitSetReports = new ArrayList<>(); if (applicability == EQUIPMENT || applicability == SIDE1) { if (modifiedOperationalLimitsGroup1() != null) { throw new PowsyblException("Cannot add " + modifiedOperationalLimitsGroup1().getId() + " operational limit group, one with the given name already exists"); } - addOlgOnASide(modifiedBranch.newOperationalLimitsGroup1(olgModifInfos.getId()), limitSetReports); + addOlgOnASide(modifiedBranch.newOperationalLimitsGroup1(olgModifInfos.getId()), SIDE1); } if (applicability == EQUIPMENT || applicability == SIDE2) { if (modifiedOperationalLimitsGroup2() != null) { throw new PowsyblException("Cannot add " + modifiedOperationalLimitsGroup2().getId() + " operational limit group, one with the given name already exists"); } - addOlgOnASide(modifiedBranch.newOperationalLimitsGroup2(olgModifInfos.getId()), limitSetReports); + addOlgOnASide(modifiedBranch.newOperationalLimitsGroup2(olgModifInfos.getId()), SIDE2); } - if (!CollectionUtils.isEmpty(limitSetReports)) { - ReportNode limitSetNode = olgsReportNode.newReportNode() + if (!CollectionUtils.isEmpty(limitsReportsSide1) || !CollectionUtils.isEmpty(limitsReportsSide2)) { + ReportNode limitSetReport = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupAdded") .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) .withUntypedValue(OlgUtils.SIDE, applicabilityToString(applicability)) .withSeverity(TypedValue.INFO_SEVERITY) .add(); - ModificationUtils.getInstance().reportModifications(limitSetNode, limitSetReports); + logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", limitsReportsSide1); + logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", limitsReportsSide2); } } @@ -266,58 +301,58 @@ private String applicabilityToString(OperationalLimitsGroupInfos.Applicability a }; } - private void addOlgOnASide(OperationalLimitsGroup newOperationalLimitsGroup, List limitSetReports) { - modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), - newOperationalLimitsGroup.getCurrentLimits().orElse(null), limitSetReports); - addProperties(newOperationalLimitsGroup, limitSetReports); + private void addOlgOnASide(OperationalLimitsGroup newOperationalLimitsGroup, OperationalLimitsGroupInfos.Applicability applicability) { + modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), newOperationalLimitsGroup.getCurrentLimits().orElse(null), applicability); + addProperties(newOperationalLimitsGroup, applicability); } private void replaceOpLG() { - List limitSetReports = new ArrayList<>(); if (applicableOnSide1()) { OperationalLimitsGroup modifiedOlg = modifiedOperationalLimitsGroup1(); if (modifiedOlg != null) { modifiedOlg.removeCurrentLimits(); - removeAllProperties(modifiedOlg, limitSetReports); + removeAllProperties(modifiedOlg); } OperationalLimitsGroup newOperationalLimitsGroup = modifiedBranch.newOperationalLimitsGroup1(olgModifInfos.getId()); - modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), null, limitSetReports); - addProperties(newOperationalLimitsGroup, limitSetReports); + modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), null, SIDE1); + addProperties(newOperationalLimitsGroup, SIDE1); } if (applicableOnSide2()) { OperationalLimitsGroup modifiedOlg = modifiedOperationalLimitsGroup2(); if (modifiedOlg != null) { modifiedOlg.removeCurrentLimits(); - removeAllProperties(modifiedOlg, limitSetReports); + removeAllProperties(modifiedOlg); } OperationalLimitsGroup newOperationalLimitsGroup = modifiedBranch.newOperationalLimitsGroup2(olgModifInfos.getId()); - modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), null, limitSetReports); - addProperties(newOperationalLimitsGroup, limitSetReports); + modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), null, SIDE2); + addProperties(newOperationalLimitsGroup, SIDE2); } - if (!CollectionUtils.isEmpty(limitSetReports)) { - ReportNode reportNode = olgsReportNode.newReportNode() + if (!CollectionUtils.isEmpty(limitsReportsSide1) || !CollectionUtils.isEmpty(limitsReportsSide2)) { + ReportNode limitSetReport = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupReplaced") .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) .withUntypedValue(OlgUtils.SIDE, applicabilityToString(olgModifInfos.getApplicability())) .withSeverity(TypedValue.INFO_SEVERITY) .add(); - ModificationUtils.getInstance().reportModifications(reportNode, limitSetReports); + logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", limitsReportsSide1); + logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", limitsReportsSide2); } } - private void addProperties(OperationalLimitsGroup limitsGroup, List limitSetsReports) { + private void addProperties(OperationalLimitsGroup limitsGroup, OperationalLimitsGroupInfos.Applicability applicability) { if (limitsGroup == null || CollectionUtils.isEmpty(olgModifInfos.getLimitsProperties())) { return; } olgModifInfos.getLimitsProperties().forEach((LimitsPropertyInfos property) -> { - limitSetsReports.add(ReportNode.newRootReportNode() + logOnSide(ReportNode.newRootReportNode() .withMessageTemplate("network.modification.propertyAdded") .withUntypedValue(NAME, property.name()) .withUntypedValue(VALUE, property.value()) .withSeverity(TypedValue.DETAIL_SEVERITY) - .build()); + .build(), + applicability); limitsGroup.setProperty(property.name(), property.value()); }); } @@ -343,7 +378,7 @@ public void removeOlg() { .add(); } - private void removeAllProperties(OperationalLimitsGroup limitsGroup, List limitSetsReports) { + private void removeAllProperties(OperationalLimitsGroup limitsGroup) { if (limitsGroup == null) { return; @@ -353,19 +388,18 @@ private void removeAllProperties(OperationalLimitsGroup limitsGroup, List limitsReports) { + protected void modifyTemporaryLimits(CurrentLimitsAdder limitsAdder, CurrentLimits currentLimits, OperationalLimitsGroupInfos.Applicability applicability) { CurrentLimitsModificationInfos currentLimitsInfos = olgModifInfos.getCurrentLimits(); // we create a mutable list of temporary limits to be able to remove the limits that are modified in this current modification @@ -375,7 +409,6 @@ protected void modifyTemporaryLimits(CurrentLimitsAdder limitsAdder, if (currentLimits != null) { unmodifiedTemporaryLimits.addAll(currentLimits.getTemporaryLimits()); } - List temporaryLimitsReports = new ArrayList<>(); if (currentLimitsInfos != null && currentLimitsInfos.getTemporaryLimits() != null) { for (CurrentTemporaryLimitModificationInfos limit : currentLimitsInfos.getTemporaryLimits()) { @@ -384,7 +417,7 @@ protected void modifyTemporaryLimits(CurrentLimitsAdder limitsAdder, currentLimits, limit, unmodifiedTemporaryLimits, - temporaryLimitsReports + applicability ); } } @@ -393,26 +426,19 @@ protected void modifyTemporaryLimits(CurrentLimitsAdder limitsAdder, if (areLimitsReplaced) { // this needs to be logged only if there are unmodifiedTemporaryLimits left. // which means that they are going to be removed by the REPLACE mode - temporaryLimitsReports.addFirst(ReportNode.newRootReportNode() + logOnSide(ReportNode.newRootReportNode() .withAllResourceBundlesFromClasspath() .withMessageTemplate("network.modification.temporaryLimitsReplaced") .withSeverity(TypedValue.DETAIL_SEVERITY) - .build()); + .build(), + applicability); } else { // we add (back) the temporary limits that have not been modified for (LoadingLimits.TemporaryLimit limit : unmodifiedTemporaryLimits) { - OlgUtils.addTemporaryLimit(limitsAdder, limit.getName(), limit.getValue(), limit.getAcceptableDuration()); + addTemporaryLimit(limitsAdder, limit.getName(), limit.getValue(), limit.getAcceptableDuration(), applicability); } } } - if (!temporaryLimitsReports.isEmpty()) { - temporaryLimitsReports.addFirst(ReportNode.newRootReportNode() - .withAllResourceBundlesFromClasspath() - .withMessageTemplate("network.modification.temporaryLimitsModification") - .withSeverity(TypedValue.DETAIL_SEVERITY) - .build()); - limitsReports.addAll(temporaryLimitsReports); - } } /** @@ -421,14 +447,13 @@ protected void modifyTemporaryLimits(CurrentLimitsAdder limitsAdder, * @param networkCurrentLimits limits of the branch which is currently modified by the network modification * @param limit modification to be applied to the limit * @param unmodifiedTemporaryLimits list of all the unmodified limits that will be added at the end of the network modification - * @param temporaryLimitsReports log report */ private void applyTemporaryLimitModification( CurrentLimitsAdder limitsAdder, CurrentLimits networkCurrentLimits, CurrentTemporaryLimitModificationInfos limit, List unmodifiedTemporaryLimits, - List temporaryLimitsReports) { + OperationalLimitsGroupInfos.Applicability applicability) { CurrentLimitsModificationInfos currentLimitsInfos = olgModifInfos.getCurrentLimits(); int limitAcceptableDuration = limit.getAcceptableDuration() == null ? Integer.MAX_VALUE : limit.getAcceptableDuration(); double limitValue = limit.getValue() == null ? Double.MAX_VALUE : limit.getValue(); @@ -441,29 +466,31 @@ private void applyTemporaryLimitModification( unmodifiedTemporaryLimits.removeIf(temporaryLimit -> temporaryLimit.getAcceptableDuration() == limitAcceptableDuration); } if (limitToModify == null && OlgUtils.mayCreateALimit(limit.getModificationType())) { - OlgUtils.createTemporaryLimit(limitsAdder, limit, temporaryLimitsReports, limitDurationToReport, limitValueToReport, limitValue, limitAcceptableDuration); + createTemporaryLimit(limitsAdder, limit, limitDurationToReport, limitValueToReport, limitValue, limitAcceptableDuration, applicability); } else if (limitToModify != null) { // the limit already exists if (limit.getModificationType() == TemporaryLimitModificationType.DELETE) { // the limit has been removed previously - temporaryLimitsReports.add(ReportNode.newRootReportNode() + logOnSide(ReportNode.newRootReportNode() .withAllResourceBundlesFromClasspath() .withMessageTemplate("network.modification.temporaryLimitDeleted.name") .withUntypedValue(NAME, limit.getName()) - .withUntypedValue(OlgUtils.DURATION, limitDurationToReport) + .withUntypedValue(DURATION, limitDurationToReport) .withSeverity(TypedValue.DETAIL_SEVERITY) - .build()); + .build(), + applicability); } else { - OlgUtils.modifyTemporaryLimit(limitsAdder, limit, temporaryLimitsReports, limitToModify, limitValue, limitDurationToReport, limitValueToReport, limitAcceptableDuration); + modifyTemporaryLimit(limitsAdder, limit, limitToModify, limitValue, limitDurationToReport, limitValueToReport, limitAcceptableDuration, applicability); } } else if (limit.getModificationType() == TemporaryLimitModificationType.MODIFY || limit.getModificationType() == TemporaryLimitModificationType.MODIFY_OR_ADD) { // invalid modification - temporaryLimitsReports.add(ReportNode.newRootReportNode() + logOnSide(ReportNode.newRootReportNode() .withAllResourceBundlesFromClasspath() .withMessageTemplate("network.modification.temporaryLimitsNoMatch") .withUntypedValue(OlgUtils.LIMIT_ACCEPTABLE_DURATION, limitAcceptableDuration) .withSeverity(TypedValue.WARN_SEVERITY) - .build()); + .build(), + applicability); } } @@ -503,4 +530,70 @@ private LoadingLimits.TemporaryLimit getTemporaryLimitToModify( } return limitToModify; } + + public void modifyTemporaryLimit( + CurrentLimitsAdder limitsAdder, + CurrentTemporaryLimitModificationInfos limitModificationInfos, + LoadingLimits.TemporaryLimit limitToModify, + double limitValue, + String limitDurationToReport, + String limitValueToReport, + int limitAcceptableDuration, + OperationalLimitsGroupInfos.Applicability applicability) { + if (Double.compare(limitToModify.getValue(), limitValue) != 0 && limitModificationInfos.getModificationType() != null) { + // value change + logOnSide(ReportNode.newRootReportNode() + .withAllResourceBundlesFromClasspath() + .withMessageTemplate("network.modification.temporaryLimitValueModified.name") + .withUntypedValue(AbstractBranchModification.NAME, limitModificationInfos.getName()) + .withUntypedValue(DURATION, limitDurationToReport) + .withUntypedValue(AbstractBranchModification.VALUE, limitValueToReport) + .withUntypedValue("oldValue", + limitToModify.getValue() == Double.MAX_VALUE ? "no value" + : String.valueOf(limitToModify.getValue())) + .withSeverity(TypedValue.DETAIL_SEVERITY) + .build(), + applicability); + addTemporaryLimit(limitsAdder, limitModificationInfos.getName(), limitValue, limitAcceptableDuration, applicability); + } else { + addTemporaryLimit(limitsAdder, limitModificationInfos.getName(), limitToModify.getValue(), limitAcceptableDuration, applicability); + } + } + + public void addTemporaryLimit(CurrentLimitsAdder limitsAdder, + String limit, + double limitValue, + int limitAcceptableDuration, + OperationalLimitsGroupInfos.Applicability applicability) { + OlgUtils.addTemporaryLimit(limitsAdder, limit, limitValue, limitAcceptableDuration); + logOnSide(ReportNode.newRootReportNode() + .withAllResourceBundlesFromClasspath() + .withMessageTemplate("network.modification.temporaryLimitModified.name") + .withUntypedValue(AbstractBranchModification.NAME, limit) + .withUntypedValue(AbstractBranchModification.VALUE, limitValue) + .withUntypedValue(DURATION, limitAcceptableDuration) + .withSeverity(TypedValue.DETAIL_SEVERITY) + .build(), + applicability); + } + + public void createTemporaryLimit( + CurrentLimitsAdder limitsAdder, + CurrentTemporaryLimitModificationInfos limit, + String limitDurationToReport, + String limitValueToReport, + double limitValue, + int limitAcceptableDuration, + OperationalLimitsGroupInfos.Applicability applicability) { + logOnSide(ReportNode.newRootReportNode() + .withAllResourceBundlesFromClasspath() + .withMessageTemplate("network.modification.temporaryLimitAdded.name") + .withUntypedValue(AbstractBranchModification.NAME, limit.getName()) + .withUntypedValue(DURATION, limitDurationToReport) + .withUntypedValue(AbstractBranchModification.VALUE, limitValueToReport) + .withSeverity(TypedValue.DETAIL_SEVERITY) + .build(), + olgModifInfos.getApplicability()); + addTemporaryLimit(limitsAdder, limit.getName(), limitValue, limitAcceptableDuration, applicability); + } } diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java index 3aefa613..890d9a7d 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java @@ -1,3 +1,9 @@ +/** + * Copyright (c) 2025, 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 org.gridsuite.modification.modifications.olg; import com.powsybl.commons.report.ReportNode; @@ -14,6 +20,8 @@ /** * handles the modification of a list of operational limits groups from AbstractBranchModification + * + * @author Mathieu DEHARBE */ public class OlgsModification { private final Branch modifiedBranch; // branch modified by the network modification diff --git a/src/main/java/org/gridsuite/modification/utils/OlgUtils.java b/src/main/java/org/gridsuite/modification/utils/OlgUtils.java index b969fe3e..8cc7c642 100644 --- a/src/main/java/org/gridsuite/modification/utils/OlgUtils.java +++ b/src/main/java/org/gridsuite/modification/utils/OlgUtils.java @@ -4,13 +4,10 @@ import com.powsybl.commons.report.TypedValue; import com.powsybl.iidm.network.Branch; import com.powsybl.iidm.network.CurrentLimitsAdder; -import com.powsybl.iidm.network.LoadingLimits; import com.powsybl.iidm.network.TwoSides; import org.gridsuite.modification.dto.AttributeModification; -import org.gridsuite.modification.dto.CurrentTemporaryLimitModificationInfos; import org.gridsuite.modification.dto.OperationType; import org.gridsuite.modification.dto.TemporaryLimitModificationType; -import org.gridsuite.modification.modifications.AbstractBranchModification; import org.springframework.util.StringUtils; import java.util.List; @@ -92,53 +89,6 @@ public static boolean mayCreateALimit(TemporaryLimitModificationType modificatio || modificationType == TemporaryLimitModificationType.MODIFY_OR_ADD; } - public static void modifyTemporaryLimit( - CurrentLimitsAdder limitsAdder, - CurrentTemporaryLimitModificationInfos limitModificationInfos, - List temporaryLimitsReports, - LoadingLimits.TemporaryLimit limitToModify, - double limitValue, - String limitDurationToReport, - String limitValueToReport, - int limitAcceptableDuration) { - if (Double.compare(limitToModify.getValue(), limitValue) != 0 && limitModificationInfos.getModificationType() != null) { - temporaryLimitsReports.add(ReportNode.newRootReportNode() - .withAllResourceBundlesFromClasspath() - .withMessageTemplate("network.modification.temporaryLimitModified.name") - .withUntypedValue(AbstractBranchModification.NAME, limitModificationInfos.getName()) - .withUntypedValue(DURATION, limitDurationToReport) - .withUntypedValue(AbstractBranchModification.VALUE, limitValueToReport) - .withUntypedValue("oldValue", - limitToModify.getValue() == Double.MAX_VALUE ? "no value" - : String.valueOf(limitToModify.getValue())) - .withSeverity(TypedValue.DETAIL_SEVERITY) - .build()); - addTemporaryLimit(limitsAdder, limitModificationInfos.getName(), limitValue, limitAcceptableDuration); - } else { - // no real modification - addTemporaryLimit(limitsAdder, limitModificationInfos.getName(), limitToModify.getValue(), limitAcceptableDuration); - } - } - - public static void createTemporaryLimit( - CurrentLimitsAdder limitsAdder, - CurrentTemporaryLimitModificationInfos limit, - List temporaryLimitsReports, - String limitDurationToReport, - String limitValueToReport, - double limitValue, - int limitAcceptableDuration) { - temporaryLimitsReports.add(ReportNode.newRootReportNode() - .withAllResourceBundlesFromClasspath() - .withMessageTemplate("network.modification.temporaryLimitAdded.name") - .withUntypedValue(AbstractBranchModification.NAME, limit.getName()) - .withUntypedValue(DURATION, limitDurationToReport) - .withUntypedValue(AbstractBranchModification.VALUE, limitValueToReport) - .withSeverity(TypedValue.DETAIL_SEVERITY) - .build()); - addTemporaryLimit(limitsAdder, limit.getName(), limitValue, limitAcceptableDuration); - } - public static void addTemporaryLimit(CurrentLimitsAdder limitsAdder, String limit, double limitValue, int limitAcceptableDuration) { limitsAdder .beginTemporaryLimit() diff --git a/src/main/resources/org/gridsuite/modification/reports.properties b/src/main/resources/org/gridsuite/modification/reports.properties index 972c25f6..3f4138dd 100644 --- a/src/main/resources/org/gridsuite/modification/reports.properties +++ b/src/main/resources/org/gridsuite/modification/reports.properties @@ -178,8 +178,10 @@ 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.operationalLimitsGroupAdded.detail = Added to operational limits group on ${side} network.modification.operationalLimitsGroupReplaced = Limit set ${operationalLimitsGroupName} has been replaced on ${side} network.modification.operationalLimitsGroupModified = Limit set ${operationalLimitsGroupName} has been modified on ${side} +network.modification.operationalLimitsGroupModified.detail = Modified in operational limits group on ${side} network.modification.limitSetSelectedOnSide1 = limit set selected on side 1 : ${selectedOperationalLimitsGroup1} network.modification.limitSetSelectedOnSide2 = limit set selected on side 2 : ${selectedOperationalLimitsGroup2} network.modification.noLimitSetSelectedOnSide1 = No limit set selected on side 1 @@ -298,8 +300,8 @@ network.modification.tapChangerStepsModification = Taps were replaced by new one network.modification.tapsModification = Taps network.modification.temporaryLimitAdded.name = ${name} (${duration}) added with ${value} network.modification.temporaryLimitDeleted.name = ${name} (${duration}) deleted -network.modification.temporaryLimitModified.name = ${name} (${duration}) : ${oldValue} -> ${value} -network.modification.temporaryLimitsModification = Temporary current limits : +network.modification.temporaryLimitValueModified.name = Temporary limit ${name} (${duration}) : ${oldValue} -> ${value} +network.modification.temporaryLimitModified.name = Temporary limit ${name}; value: ${value}; acceptable duration: ${duration} network.modification.temporaryLimitsReplaced = Previous temporary limits were removed network.modification.temporaryLimitsNoMatch = No existing temporary limit found with acceptableDuration = ${limitAcceptableDuration} matching is based on acceptableDuration if that helps network.modification.terminal1Disconnected = Equipment with id=${id} disconnected on side 1 From 05eab30fac3b1a72f0b387623cd8e5394d445729 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Mon, 24 Nov 2025 17:41:39 +0100 Subject: [PATCH 09/22] remove olgUtils Signed-off-by: Mathieu DEHARBE --- .../byfilter/equipmentfield/LineField.java | 5 +- .../TwoWindingsTransformerField.java | 5 +- .../AbstractBranchModification.java | 102 ++++++++++++++- .../modifications/olg/OlgModification.java | 33 +++-- .../modifications/olg/OlgsModification.java | 12 +- .../modification/utils/OlgUtils.java | 116 ------------------ 6 files changed, 124 insertions(+), 149 deletions(-) delete mode 100644 src/main/java/org/gridsuite/modification/utils/OlgUtils.java diff --git a/src/main/java/org/gridsuite/modification/dto/byfilter/equipmentfield/LineField.java b/src/main/java/org/gridsuite/modification/dto/byfilter/equipmentfield/LineField.java index 41fa06e2..c62f8d9d 100644 --- a/src/main/java/org/gridsuite/modification/dto/byfilter/equipmentfield/LineField.java +++ b/src/main/java/org/gridsuite/modification/dto/byfilter/equipmentfield/LineField.java @@ -12,7 +12,6 @@ import groovyjarjarantlr4.v4.runtime.misc.NotNull; import org.gridsuite.modification.dto.AttributeModification; import org.gridsuite.modification.dto.OperationType; -import org.gridsuite.modification.utils.OlgUtils; import org.gridsuite.modification.utils.ModificationUtils; import static org.gridsuite.modification.NetworkModificationException.Type.MODIFY_LINE_ERROR; @@ -87,7 +86,7 @@ private static void setNewStringValue(Line line, LineField field, String newValu .stream() .map(OperationalLimitsGroup::getId) .toList(), 1); - OlgUtils.modifySelectedOperationalLimitsGroup(line, attributeModification, TwoSides.ONE, null); + modifySelectedOperationalLimitsGroup(line, attributeModification, TwoSides.ONE, null); } case SELECTED_OPERATIONAL_LIMITS_GROUP_2 -> { ModificationUtils.checkLimitsGroupExist(errorMessage, newValue, MODIFY_LINE_ERROR, @@ -95,7 +94,7 @@ private static void setNewStringValue(Line line, LineField field, String newValu .stream() .map(OperationalLimitsGroup::getId) .toList(), 2); - OlgUtils.modifySelectedOperationalLimitsGroup(line, attributeModification, TwoSides.TWO, null); + modifySelectedOperationalLimitsGroup(line, attributeModification, TwoSides.TWO, null); } default -> throw new IllegalArgumentException(String.format("field %s is not a string modification", field)); } diff --git a/src/main/java/org/gridsuite/modification/dto/byfilter/equipmentfield/TwoWindingsTransformerField.java b/src/main/java/org/gridsuite/modification/dto/byfilter/equipmentfield/TwoWindingsTransformerField.java index b09215ad..6d3757ca 100644 --- a/src/main/java/org/gridsuite/modification/dto/byfilter/equipmentfield/TwoWindingsTransformerField.java +++ b/src/main/java/org/gridsuite/modification/dto/byfilter/equipmentfield/TwoWindingsTransformerField.java @@ -13,7 +13,6 @@ import jakarta.validation.constraints.NotNull; import org.gridsuite.modification.dto.AttributeModification; import org.gridsuite.modification.dto.OperationType; -import org.gridsuite.modification.utils.OlgUtils; import org.gridsuite.modification.utils.ModificationUtils; import java.util.List; @@ -194,7 +193,7 @@ private static void setNewStringValue(TwoWindingsTransformer transformer, TwoWin .stream() .map(OperationalLimitsGroup::getId) .toList(), 1); - OlgUtils.modifySelectedOperationalLimitsGroup(transformer, attributeModification, TwoSides.ONE, null); + modifySelectedOperationalLimitsGroup(transformer, attributeModification, TwoSides.ONE, null); } case SELECTED_OPERATIONAL_LIMITS_GROUP_2 -> { ModificationUtils.checkLimitsGroupExist(errorMessage, newValue, MODIFY_LINE_ERROR, @@ -202,7 +201,7 @@ private static void setNewStringValue(TwoWindingsTransformer transformer, TwoWin .stream() .map(OperationalLimitsGroup::getId) .toList(), 2); - OlgUtils.modifySelectedOperationalLimitsGroup(transformer, attributeModification, TwoSides.TWO, null); + modifySelectedOperationalLimitsGroup(transformer, attributeModification, TwoSides.TWO, null); } default -> throw new IllegalArgumentException(String.format("field %s is not a string modification", field)); } diff --git a/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java b/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java index 1fad7ced..729244f0 100644 --- a/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java @@ -13,8 +13,8 @@ import org.gridsuite.modification.NetworkModificationException; import org.gridsuite.modification.dto.*; import org.gridsuite.modification.modifications.olg.OlgsModification; -import org.gridsuite.modification.utils.OlgUtils; import org.gridsuite.modification.utils.ModificationUtils; +import org.springframework.util.StringUtils; import java.util.*; import java.util.stream.Collectors; @@ -27,9 +27,14 @@ */ public abstract class AbstractBranchModification extends AbstractModification { + public static final String DURATION = "duration"; public static final String NAME = "name"; public static final String VALUE = "value"; private static final String VALIDITY = "validity"; + public static final String LIMIT_ACCEPTABLE_DURATION = "limitAcceptableDuration"; + public static final String OPERATIONAL_LIMITS_GROUP_NAME = "operationalLimitsGroupName"; + public static final String SIDE = "side"; + public static final String APPLICABILITY = "applicability"; protected final BranchModificationInfos modificationInfos; @@ -85,7 +90,7 @@ protected void modifyBranch(Branch branch, BranchModificationInfos branchModi private void applySelectedOLGs(Branch branch, List activeOLGReports) { if (modificationInfos.getSelectedOperationalLimitsGroup1() != null) { - OlgUtils.modifySelectedOperationalLimitsGroup( + modifySelectedOperationalLimitsGroup( branch, modificationInfos.getSelectedOperationalLimitsGroup1(), TwoSides.ONE, @@ -93,7 +98,7 @@ private void applySelectedOLGs(Branch branch, List activeOLGRepor ); } if (modificationInfos.getSelectedOperationalLimitsGroup2() != null) { - OlgUtils.modifySelectedOperationalLimitsGroup( + modifySelectedOperationalLimitsGroup( branch, modificationInfos.getSelectedOperationalLimitsGroup2(), TwoSides.TWO, @@ -101,6 +106,81 @@ private void applySelectedOLGs(Branch branch, List activeOLGRepor } } + private static void applySelectedOLGOnSide1(Branch branch, AttributeModification modifOperationalLimitsGroup, List reportNode, String newSelectedOLG) { + if (!StringUtils.hasText(newSelectedOLG) || modifOperationalLimitsGroup.getOp() == OperationType.UNSET) { + branch.cancelSelectedOperationalLimitsGroup1(); + if (reportNode != null) { + reportNode.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.noLimitSetSelectedOnSide1") + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + } + } else { + if (StringUtils.hasText(newSelectedOLG) && branch.getOperationalLimitsGroup1(newSelectedOLG).isEmpty() && reportNode != null) { + reportNode.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.limitSetAbsentOnSide1") + .withUntypedValue("selectedOperationalLimitsGroup", newSelectedOLG) + .withSeverity(TypedValue.WARN_SEVERITY) + .build()); + + } else { + branch.setSelectedOperationalLimitsGroup1(newSelectedOLG); + if (reportNode != null) { + reportNode.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.limitSetSelectedOnSide1") + .withUntypedValue("selectedOperationalLimitsGroup1", newSelectedOLG) + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + } + } + } + } + + private static void applySelectedOLGOnSide2(Branch branch, AttributeModification modifOperationalLimitsGroup, List reportNode, String newSelectedOLG) { + if (!StringUtils.hasText(newSelectedOLG) || modifOperationalLimitsGroup.getOp() == OperationType.UNSET) { + branch.cancelSelectedOperationalLimitsGroup2(); + if (reportNode != null) { + reportNode.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.noLimitSetSelectedOnSide2") + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + } + } else { + if (StringUtils.hasText(newSelectedOLG) && branch.getOperationalLimitsGroup2(newSelectedOLG).isEmpty() && reportNode != null) { + reportNode.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.limitSetAbsentOnSide2") + .withUntypedValue("selectedOperationalLimitsGroup", newSelectedOLG) + .withSeverity(TypedValue.WARN_SEVERITY) + .build()); + + } else { + branch.setSelectedOperationalLimitsGroup2(newSelectedOLG); + if (reportNode != null) { + reportNode.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.limitSetSelectedOnSide2") + .withUntypedValue("selectedOperationalLimitsGroup2", newSelectedOLG) + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + } + } + } + } + + public static boolean mayCreateALimit(TemporaryLimitModificationType modificationType) { + return modificationType == TemporaryLimitModificationType.ADD + || modificationType == TemporaryLimitModificationType.REPLACE + || modificationType == TemporaryLimitModificationType.MODIFY_OR_ADD; + } + + public static void addTemporaryLimit(CurrentLimitsAdder limitsAdder, String limit, double limitValue, int limitAcceptableDuration) { + limitsAdder + .beginTemporaryLimit() + .setName(limit) + .setValue(limitValue) + .setAcceptableDuration(limitAcceptableDuration) + .endTemporaryLimit(); + } + public ReportNode updateMeasurements(Branch branch, BranchModificationInfos branchModificationInfos, ReportNode subReportNode) { Double p1Value = branchModificationInfos.getP1MeasurementValue() != null ? branchModificationInfos.getP1MeasurementValue().getValue() : null; Double q1Value = branchModificationInfos.getQ1MeasurementValue() != null ? branchModificationInfos.getQ1MeasurementValue().getValue() : null; @@ -249,4 +329,20 @@ private void modifyBranchVoltageLevelBusOrBusBarSectionAttributesSide2(BranchMod ); } + public static void modifySelectedOperationalLimitsGroup( + Branch branch, + AttributeModification modifOperationalLimitsGroup, + TwoSides side, + List reportNode) { + Objects.requireNonNull(side); + if (modifOperationalLimitsGroup != null) { + String newSelectedOLG = modifOperationalLimitsGroup.getValue(); + if (side == TwoSides.ONE) { + applySelectedOLGOnSide1(branch, modifOperationalLimitsGroup, reportNode, newSelectedOLG); + } else if (side == TwoSides.TWO) { + applySelectedOLGOnSide2(branch, modifOperationalLimitsGroup, reportNode, newSelectedOLG); + } + } + } + } diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index c0117df6..d9cb162e 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -13,7 +13,6 @@ import org.gridsuite.modification.dto.*; import org.gridsuite.modification.modifications.AbstractBranchModification; import org.gridsuite.modification.utils.ModificationUtils; -import org.gridsuite.modification.utils.OlgUtils; import org.springframework.util.CollectionUtils; import java.util.ArrayList; @@ -22,9 +21,7 @@ import java.util.Set; import static org.gridsuite.modification.dto.OperationalLimitsGroupInfos.Applicability.*; -import static org.gridsuite.modification.modifications.AbstractBranchModification.NAME; -import static org.gridsuite.modification.modifications.AbstractBranchModification.VALUE; -import static org.gridsuite.modification.utils.OlgUtils.DURATION; +import static org.gridsuite.modification.modifications.AbstractBranchModification.*; /** * handles the modification of a single operational limits group from AbstractBranchModification @@ -158,8 +155,8 @@ private void modifyOLG(OperationalLimitsGroupInfos.Applicability applicability) if (!limitsReportsSide1.isEmpty() || !limitsReportsSide2.isEmpty()) { ReportNode limitSetReport = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupModified") - .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) - .withUntypedValue(OlgUtils.SIDE, applicabilityToString(applicability)) + .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) + .withUntypedValue(SIDE, applicabilityToString(applicability)) .withSeverity(TypedValue.INFO_SEVERITY).add(); logSideNode(limitSetReport, "network.modification.operationalLimitsGroupModified.detail", limitsReportsSide1); logSideNode(limitSetReport, "network.modification.operationalLimitsGroupModified.detail", limitsReportsSide2); @@ -173,7 +170,7 @@ private void logSideNode(ReportNode limitSetReport, String messageTemplate, List if (!limitsReports.isEmpty()) { ReportNode limitSetReport1 = limitSetReport.newReportNode() .withMessageTemplate(messageTemplate) - .withUntypedValue(OlgUtils.SIDE, applicabilityToString(SIDE1)) + .withUntypedValue(SIDE, applicabilityToString(SIDE1)) .withSeverity(TypedValue.DETAIL_SEVERITY).add(); ModificationUtils.getInstance().reportModifications(limitSetReport1, limitsReports); } @@ -284,8 +281,8 @@ private void addOlg(OperationalLimitsGroupInfos.Applicability applicability) { if (!CollectionUtils.isEmpty(limitsReportsSide1) || !CollectionUtils.isEmpty(limitsReportsSide2)) { ReportNode limitSetReport = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupAdded") - .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) - .withUntypedValue(OlgUtils.SIDE, applicabilityToString(applicability)) + .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) + .withUntypedValue(SIDE, applicabilityToString(applicability)) .withSeverity(TypedValue.INFO_SEVERITY) .add(); logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", limitsReportsSide1); @@ -331,8 +328,8 @@ private void replaceOpLG() { if (!CollectionUtils.isEmpty(limitsReportsSide1) || !CollectionUtils.isEmpty(limitsReportsSide2)) { ReportNode limitSetReport = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupReplaced") - .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) - .withUntypedValue(OlgUtils.SIDE, applicabilityToString(olgModifInfos.getApplicability())) + .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) + .withUntypedValue(SIDE, applicabilityToString(olgModifInfos.getApplicability())) .withSeverity(TypedValue.INFO_SEVERITY) .add(); logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", limitsReportsSide1); @@ -372,8 +369,8 @@ public void removeOlg() { } olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupDeleted") - .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, olgId) - .withUntypedValue(OlgUtils.SIDE, applicabilityToString(olgModifInfos.getApplicability())) + .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, olgId) + .withUntypedValue(SIDE, applicabilityToString(olgModifInfos.getApplicability())) .withSeverity(TypedValue.INFO_SEVERITY) .add(); } @@ -465,7 +462,7 @@ private void applyTemporaryLimitModification( // this limit is modified by the network modification so we remove it from the list of unmodified temporary limits unmodifiedTemporaryLimits.removeIf(temporaryLimit -> temporaryLimit.getAcceptableDuration() == limitAcceptableDuration); } - if (limitToModify == null && OlgUtils.mayCreateALimit(limit.getModificationType())) { + if (limitToModify == null && mayCreateALimit(limit.getModificationType())) { createTemporaryLimit(limitsAdder, limit, limitDurationToReport, limitValueToReport, limitValue, limitAcceptableDuration, applicability); } else if (limitToModify != null) { // the limit already exists @@ -487,7 +484,7 @@ private void applyTemporaryLimitModification( logOnSide(ReportNode.newRootReportNode() .withAllResourceBundlesFromClasspath() .withMessageTemplate("network.modification.temporaryLimitsNoMatch") - .withUntypedValue(OlgUtils.LIMIT_ACCEPTABLE_DURATION, limitAcceptableDuration) + .withUntypedValue(LIMIT_ACCEPTABLE_DURATION, limitAcceptableDuration) .withSeverity(TypedValue.WARN_SEVERITY) .build(), applicability); @@ -565,12 +562,12 @@ public void addTemporaryLimit(CurrentLimitsAdder limitsAdder, double limitValue, int limitAcceptableDuration, OperationalLimitsGroupInfos.Applicability applicability) { - OlgUtils.addTemporaryLimit(limitsAdder, limit, limitValue, limitAcceptableDuration); + AbstractBranchModification.addTemporaryLimit(limitsAdder, limit, limitValue, limitAcceptableDuration); logOnSide(ReportNode.newRootReportNode() .withAllResourceBundlesFromClasspath() .withMessageTemplate("network.modification.temporaryLimitModified.name") - .withUntypedValue(AbstractBranchModification.NAME, limit) - .withUntypedValue(AbstractBranchModification.VALUE, limitValue) + .withUntypedValue(NAME, limit) + .withUntypedValue(VALUE, limitValue) .withUntypedValue(DURATION, limitAcceptableDuration) .withSeverity(TypedValue.DETAIL_SEVERITY) .build(), diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java index 890d9a7d..c23ec826 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java @@ -10,13 +10,13 @@ import com.powsybl.commons.report.TypedValue; import com.powsybl.iidm.network.*; import org.gridsuite.modification.dto.*; -import org.gridsuite.modification.utils.OlgUtils; import java.util.*; import static org.gridsuite.modification.dto.OperationalLimitsGroupInfos.Applicability.*; import static org.gridsuite.modification.dto.OperationalLimitsGroupInfos.Applicability.EQUIPMENT; import static org.gridsuite.modification.dto.OperationalLimitsGroupModificationType.DELETE; +import static org.gridsuite.modification.modifications.AbstractBranchModification.*; /** * handles the modification of a list of operational limits groups from AbstractBranchModification @@ -97,8 +97,8 @@ private void deleteOlgsUnspecifiedInTheModification(OperationalLimitsGroupInfos. private void logApplicabilityChange(List olgReports, String groupId, OperationalLimitsGroupInfos.Applicability applicability) { olgReports.add(ReportNode.newRootReportNode().withMessageTemplate("network.modification.applicabilityChanged") - .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, groupId) - .withUntypedValue(OlgUtils.APPLICABILITY, applicability.toString()) + .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, groupId) + .withUntypedValue(APPLICABILITY, applicability.toString()) .withSeverity(TypedValue.INFO_SEVERITY) .build()); } @@ -182,8 +182,8 @@ private void moveLimitSetToTheOtherSide(Branch branch, copyOperationalLimitsGroup(limitsGroup.newCurrentLimits(), limitsGroupToCopy); olgReports.add(ReportNode.newRootReportNode().withMessageTemplate("network.modification.applicabilityChanged") - .withUntypedValue(OlgUtils.OPERATIONAL_LIMITS_GROUP_NAME, limitsGroupToCopy.getId()) - .withUntypedValue(OlgUtils.APPLICABILITY, isSide1 ? SIDE1.toString() : SIDE2.toString()) + .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, limitsGroupToCopy.getId()) + .withUntypedValue(APPLICABILITY, isSide1 ? SIDE1.toString() : SIDE2.toString()) .withSeverity(TypedValue.INFO_SEVERITY) .build()); // Remove copied operational limits group @@ -201,7 +201,7 @@ private void copyOperationalLimitsGroup(CurrentLimitsAdder limitsAdder, Operatio limitsAdder.setPermanentLimit(currentLimits.getPermanentLimit()); for (LoadingLimits.TemporaryLimit tempLimit : currentLimits.getTemporaryLimits()) { - OlgUtils.addTemporaryLimit(limitsAdder, tempLimit.getName(), tempLimit.getValue(), tempLimit.getAcceptableDuration()); + addTemporaryLimit(limitsAdder, tempLimit.getName(), tempLimit.getValue(), tempLimit.getAcceptableDuration()); } limitsAdder.add(); }); diff --git a/src/main/java/org/gridsuite/modification/utils/OlgUtils.java b/src/main/java/org/gridsuite/modification/utils/OlgUtils.java deleted file mode 100644 index 8cc7c642..00000000 --- a/src/main/java/org/gridsuite/modification/utils/OlgUtils.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.gridsuite.modification.utils; - -import com.powsybl.commons.report.ReportNode; -import com.powsybl.commons.report.TypedValue; -import com.powsybl.iidm.network.Branch; -import com.powsybl.iidm.network.CurrentLimitsAdder; -import com.powsybl.iidm.network.TwoSides; -import org.gridsuite.modification.dto.AttributeModification; -import org.gridsuite.modification.dto.OperationType; -import org.gridsuite.modification.dto.TemporaryLimitModificationType; -import org.springframework.util.StringUtils; - -import java.util.List; -import java.util.Objects; - -public final class OlgUtils { - public static final String DURATION = "duration"; - public static final String LIMIT_ACCEPTABLE_DURATION = "limitAcceptableDuration"; - public static final String OPERATIONAL_LIMITS_GROUP_NAME = "operationalLimitsGroupName"; - public static final String SIDE = "side"; - public static final String APPLICABILITY = "applicability"; - - private OlgUtils() { - } - - private static void applySelectedOLGOnSide1(Branch branch, AttributeModification modifOperationalLimitsGroup, List reportNode, String newSelectedOLG) { - if (!StringUtils.hasText(newSelectedOLG) || modifOperationalLimitsGroup.getOp() == OperationType.UNSET) { - branch.cancelSelectedOperationalLimitsGroup1(); - if (reportNode != null) { - reportNode.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.noLimitSetSelectedOnSide1") - .withSeverity(TypedValue.INFO_SEVERITY) - .build()); - } - } else { - if (StringUtils.hasText(newSelectedOLG) && branch.getOperationalLimitsGroup1(newSelectedOLG).isEmpty() && reportNode != null) { - reportNode.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.limitSetAbsentOnSide1") - .withUntypedValue("selectedOperationalLimitsGroup", newSelectedOLG) - .withSeverity(TypedValue.WARN_SEVERITY) - .build()); - - } else { - branch.setSelectedOperationalLimitsGroup1(newSelectedOLG); - if (reportNode != null) { - reportNode.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.limitSetSelectedOnSide1") - .withUntypedValue("selectedOperationalLimitsGroup1", newSelectedOLG) - .withSeverity(TypedValue.INFO_SEVERITY) - .build()); - } - } - } - } - - private static void applySelectedOLGOnSide2(Branch branch, AttributeModification modifOperationalLimitsGroup, List reportNode, String newSelectedOLG) { - if (!StringUtils.hasText(newSelectedOLG) || modifOperationalLimitsGroup.getOp() == OperationType.UNSET) { - branch.cancelSelectedOperationalLimitsGroup2(); - if (reportNode != null) { - reportNode.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.noLimitSetSelectedOnSide2") - .withSeverity(TypedValue.INFO_SEVERITY) - .build()); - } - } else { - if (StringUtils.hasText(newSelectedOLG) && branch.getOperationalLimitsGroup2(newSelectedOLG).isEmpty() && reportNode != null) { - reportNode.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.limitSetAbsentOnSide2") - .withUntypedValue("selectedOperationalLimitsGroup", newSelectedOLG) - .withSeverity(TypedValue.WARN_SEVERITY) - .build()); - - } else { - branch.setSelectedOperationalLimitsGroup2(newSelectedOLG); - if (reportNode != null) { - reportNode.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.limitSetSelectedOnSide2") - .withUntypedValue("selectedOperationalLimitsGroup2", newSelectedOLG) - .withSeverity(TypedValue.INFO_SEVERITY) - .build()); - } - } - } - } - - public static boolean mayCreateALimit(TemporaryLimitModificationType modificationType) { - return modificationType == TemporaryLimitModificationType.ADD - || modificationType == TemporaryLimitModificationType.REPLACE - || modificationType == TemporaryLimitModificationType.MODIFY_OR_ADD; - } - - public static void addTemporaryLimit(CurrentLimitsAdder limitsAdder, String limit, double limitValue, int limitAcceptableDuration) { - limitsAdder - .beginTemporaryLimit() - .setName(limit) - .setValue(limitValue) - .setAcceptableDuration(limitAcceptableDuration) - .endTemporaryLimit(); - } - - public static void modifySelectedOperationalLimitsGroup( - Branch branch, - AttributeModification modifOperationalLimitsGroup, - TwoSides side, - List reportNode) { - Objects.requireNonNull(side); - if (modifOperationalLimitsGroup != null) { - String newSelectedOLG = modifOperationalLimitsGroup.getValue(); - if (side == TwoSides.ONE) { - applySelectedOLGOnSide1(branch, modifOperationalLimitsGroup, reportNode, newSelectedOLG); - } else if (side == TwoSides.TWO) { - applySelectedOLGOnSide2(branch, modifOperationalLimitsGroup, reportNode, newSelectedOLG); - } - } - } -} From 617b04cda47b1c25700cac84f5aceba1d3ea90d4 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Mon, 24 Nov 2025 17:58:11 +0100 Subject: [PATCH 10/22] corrects logSideNode Signed-off-by: Mathieu DEHARBE --- .../AbstractBranchModification.java | 31 ++++++------ .../modifications/olg/OlgModification.java | 48 +++++++++++-------- 2 files changed, 42 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java b/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java index 729244f0..a1e444d8 100644 --- a/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java @@ -166,21 +166,6 @@ private static void applySelectedOLGOnSide2(Branch branch, AttributeModificat } } - public static boolean mayCreateALimit(TemporaryLimitModificationType modificationType) { - return modificationType == TemporaryLimitModificationType.ADD - || modificationType == TemporaryLimitModificationType.REPLACE - || modificationType == TemporaryLimitModificationType.MODIFY_OR_ADD; - } - - public static void addTemporaryLimit(CurrentLimitsAdder limitsAdder, String limit, double limitValue, int limitAcceptableDuration) { - limitsAdder - .beginTemporaryLimit() - .setName(limit) - .setValue(limitValue) - .setAcceptableDuration(limitAcceptableDuration) - .endTemporaryLimit(); - } - public ReportNode updateMeasurements(Branch branch, BranchModificationInfos branchModificationInfos, ReportNode subReportNode) { Double p1Value = branchModificationInfos.getP1MeasurementValue() != null ? branchModificationInfos.getP1MeasurementValue().getValue() : null; Double q1Value = branchModificationInfos.getQ1MeasurementValue() != null ? branchModificationInfos.getQ1MeasurementValue().getValue() : null; @@ -292,6 +277,21 @@ private boolean updateConnection(Branch branch, TwoSides side, Boolean connec return done; } + public static boolean mayCreateALimit(TemporaryLimitModificationType modificationType) { + return modificationType == TemporaryLimitModificationType.ADD + || modificationType == TemporaryLimitModificationType.REPLACE + || modificationType == TemporaryLimitModificationType.MODIFY_OR_ADD; + } + + public static void addTemporaryLimit(CurrentLimitsAdder limitsAdder, String limit, double limitValue, int limitAcceptableDuration) { + limitsAdder + .beginTemporaryLimit() + .setName(limit) + .setValue(limitValue) + .setAcceptableDuration(limitAcceptableDuration) + .endTemporaryLimit(); + } + protected boolean characteristicsModified(BranchModificationInfos branchModificationInfos) { return branchModificationInfos.getX() != null && branchModificationInfos.getX().getValue() != null @@ -344,5 +344,4 @@ public static void modifySelectedOperationalLimitsGroup( } } } - } diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index d9cb162e..2f221c14 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -47,7 +47,7 @@ public OlgModification( limitsReportsSide2 = new ArrayList<>(); } - private void logOnSide(ReportNode reportNode, OperationalLimitsGroupInfos.Applicability applicability) { + private void addToLogsOnSide(ReportNode reportNode, OperationalLimitsGroupInfos.Applicability applicability) { if (applicability == EQUIPMENT || applicability == SIDE1) { limitsReportsSide1.add(reportNode); } @@ -158,15 +158,21 @@ private void modifyOLG(OperationalLimitsGroupInfos.Applicability applicability) .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) .withUntypedValue(SIDE, applicabilityToString(applicability)) .withSeverity(TypedValue.INFO_SEVERITY).add(); - logSideNode(limitSetReport, "network.modification.operationalLimitsGroupModified.detail", limitsReportsSide1); - logSideNode(limitSetReport, "network.modification.operationalLimitsGroupModified.detail", limitsReportsSide2); + logSideNode(limitSetReport, "network.modification.operationalLimitsGroupModified.detail", SIDE1); + logSideNode(limitSetReport, "network.modification.operationalLimitsGroupModified.detail", SIDE2); } } /** - * cerates a log node specific for each side + * creates a log node specific for each side */ - private void logSideNode(ReportNode limitSetReport, String messageTemplate, List limitsReports) { + private void logSideNode(ReportNode limitSetReport, String messageTemplate, OperationalLimitsGroupInfos.Applicability applicability) { + List limitsReports; + if (applicability == SIDE1) { + limitsReports = limitsReportsSide1; + } else { + limitsReports = limitsReportsSide2; + } if (!limitsReports.isEmpty()) { ReportNode limitSetReport1 = limitSetReport.newReportNode() .withMessageTemplate(messageTemplate) @@ -205,7 +211,7 @@ private void modifyProperties(OperationalLimitsGroup limitsGroup, OperationalLim propertiesToRemove.forEach((String propertyName) -> { limitsGroup.removeProperty(propertyName); - logOnSide(ReportNode.newRootReportNode() + addToLogsOnSide(ReportNode.newRootReportNode() .withMessageTemplate("network.modification.propertyDeleted") .withUntypedValue(NAME, propertyName) .withSeverity(TypedValue.DETAIL_SEVERITY).build(), @@ -217,7 +223,7 @@ private void modifyProperties(OperationalLimitsGroup limitsGroup, OperationalLim if (limitsGroup.getProperty(property.name()).equals(property.value())) { return; } - logOnSide(ReportNode.newRootReportNode() + addToLogsOnSide(ReportNode.newRootReportNode() .withMessageTemplate("network.modification.propertyChanged") .withUntypedValue(NAME, property.name()) .withUntypedValue("to", property.value()) @@ -228,7 +234,7 @@ private void modifyProperties(OperationalLimitsGroup limitsGroup, OperationalLim }); propertiesToAdd.forEach((LimitsPropertyInfos property) -> { - logOnSide(ReportNode.newRootReportNode() + addToLogsOnSide(ReportNode.newRootReportNode() .withMessageTemplate("network.modification.propertyAdded") .withUntypedValue(NAME, property.name()) .withUntypedValue(VALUE, property.value()) @@ -247,7 +253,7 @@ protected void modifyCurrentLimits( boolean hasPermanent = currentLimitsInfos.getPermanentLimit() != null; if (hasPermanent) { if (!(currentLimits != null && currentLimits.getPermanentLimit() == currentLimitsInfos.getPermanentLimit())) { - logOnSide(ModificationUtils.buildModificationReport( + addToLogsOnSide(ModificationUtils.buildModificationReport( currentLimits != null ? currentLimits.getPermanentLimit() : Double.NaN, currentLimitsInfos.getPermanentLimit(), "Permanent limit", TypedValue.DETAIL_SEVERITY @@ -285,8 +291,8 @@ private void addOlg(OperationalLimitsGroupInfos.Applicability applicability) { .withUntypedValue(SIDE, applicabilityToString(applicability)) .withSeverity(TypedValue.INFO_SEVERITY) .add(); - logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", limitsReportsSide1); - logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", limitsReportsSide2); + logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", SIDE1); + logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", SIDE2); } } @@ -332,8 +338,8 @@ private void replaceOpLG() { .withUntypedValue(SIDE, applicabilityToString(olgModifInfos.getApplicability())) .withSeverity(TypedValue.INFO_SEVERITY) .add(); - logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", limitsReportsSide1); - logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", limitsReportsSide2); + logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", SIDE1); + logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", SIDE2); } } @@ -343,7 +349,7 @@ private void addProperties(OperationalLimitsGroup limitsGroup, OperationalLimits } olgModifInfos.getLimitsProperties().forEach((LimitsPropertyInfos property) -> { - logOnSide(ReportNode.newRootReportNode() + addToLogsOnSide(ReportNode.newRootReportNode() .withMessageTemplate("network.modification.propertyAdded") .withUntypedValue(NAME, property.name()) .withUntypedValue(VALUE, property.value()) @@ -385,7 +391,7 @@ private void removeAllProperties(OperationalLimitsGroup limitsGroup) { while (propertiesIt.hasNext()) { String propertyName = propertiesIt.next(); limitsGroup.removeProperty(propertyName); - logOnSide(ReportNode.newRootReportNode() + addToLogsOnSide(ReportNode.newRootReportNode() .withMessageTemplate("network.modification.propertyDeleted") .withUntypedValue(NAME, propertyName) .withSeverity(TypedValue.DETAIL_SEVERITY).build(), @@ -423,7 +429,7 @@ protected void modifyTemporaryLimits(CurrentLimitsAdder limitsAdder, CurrentLimi if (areLimitsReplaced) { // this needs to be logged only if there are unmodifiedTemporaryLimits left. // which means that they are going to be removed by the REPLACE mode - logOnSide(ReportNode.newRootReportNode() + addToLogsOnSide(ReportNode.newRootReportNode() .withAllResourceBundlesFromClasspath() .withMessageTemplate("network.modification.temporaryLimitsReplaced") .withSeverity(TypedValue.DETAIL_SEVERITY) @@ -468,7 +474,7 @@ private void applyTemporaryLimitModification( // the limit already exists if (limit.getModificationType() == TemporaryLimitModificationType.DELETE) { // the limit has been removed previously - logOnSide(ReportNode.newRootReportNode() + addToLogsOnSide(ReportNode.newRootReportNode() .withAllResourceBundlesFromClasspath() .withMessageTemplate("network.modification.temporaryLimitDeleted.name") .withUntypedValue(NAME, limit.getName()) @@ -481,7 +487,7 @@ private void applyTemporaryLimitModification( } } else if (limit.getModificationType() == TemporaryLimitModificationType.MODIFY || limit.getModificationType() == TemporaryLimitModificationType.MODIFY_OR_ADD) { // invalid modification - logOnSide(ReportNode.newRootReportNode() + addToLogsOnSide(ReportNode.newRootReportNode() .withAllResourceBundlesFromClasspath() .withMessageTemplate("network.modification.temporaryLimitsNoMatch") .withUntypedValue(LIMIT_ACCEPTABLE_DURATION, limitAcceptableDuration) @@ -539,7 +545,7 @@ public void modifyTemporaryLimit( OperationalLimitsGroupInfos.Applicability applicability) { if (Double.compare(limitToModify.getValue(), limitValue) != 0 && limitModificationInfos.getModificationType() != null) { // value change - logOnSide(ReportNode.newRootReportNode() + addToLogsOnSide(ReportNode.newRootReportNode() .withAllResourceBundlesFromClasspath() .withMessageTemplate("network.modification.temporaryLimitValueModified.name") .withUntypedValue(AbstractBranchModification.NAME, limitModificationInfos.getName()) @@ -563,7 +569,7 @@ public void addTemporaryLimit(CurrentLimitsAdder limitsAdder, int limitAcceptableDuration, OperationalLimitsGroupInfos.Applicability applicability) { AbstractBranchModification.addTemporaryLimit(limitsAdder, limit, limitValue, limitAcceptableDuration); - logOnSide(ReportNode.newRootReportNode() + addToLogsOnSide(ReportNode.newRootReportNode() .withAllResourceBundlesFromClasspath() .withMessageTemplate("network.modification.temporaryLimitModified.name") .withUntypedValue(NAME, limit) @@ -582,7 +588,7 @@ public void createTemporaryLimit( double limitValue, int limitAcceptableDuration, OperationalLimitsGroupInfos.Applicability applicability) { - logOnSide(ReportNode.newRootReportNode() + addToLogsOnSide(ReportNode.newRootReportNode() .withAllResourceBundlesFromClasspath() .withMessageTemplate("network.modification.temporaryLimitAdded.name") .withUntypedValue(AbstractBranchModification.NAME, limit.getName()) From dda8e3dcba3019fa06eae0b1ed5e26cf25edee43 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Mon, 24 Nov 2025 18:42:55 +0100 Subject: [PATCH 11/22] corrects logSideNode Signed-off-by: Mathieu DEHARBE --- .../modification/modifications/olg/OlgModification.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index 2f221c14..4ccd8cbf 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -174,11 +174,11 @@ private void logSideNode(ReportNode limitSetReport, String messageTemplate, Oper limitsReports = limitsReportsSide2; } if (!limitsReports.isEmpty()) { - ReportNode limitSetReport1 = limitSetReport.newReportNode() + ReportNode limitSetReportDetail = limitSetReport.newReportNode() .withMessageTemplate(messageTemplate) - .withUntypedValue(SIDE, applicabilityToString(SIDE1)) + .withUntypedValue(SIDE, applicabilityToString(applicability)) .withSeverity(TypedValue.DETAIL_SEVERITY).add(); - ModificationUtils.getInstance().reportModifications(limitSetReport1, limitsReports); + ModificationUtils.getInstance().reportModifications(limitSetReportDetail, limitsReports); } } From c0e89d2a08ccbef8a425eee54b698eb4321d8b51 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Tue, 25 Nov 2025 10:53:27 +0100 Subject: [PATCH 12/22] log limits only if there is at least one actual modification Signed-off-by: Mathieu DEHARBE --- .../modifications/olg/OlgModification.java | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index 4ccd8cbf..977abbc0 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -438,7 +438,7 @@ protected void modifyTemporaryLimits(CurrentLimitsAdder limitsAdder, CurrentLimi } else { // we add (back) the temporary limits that have not been modified for (LoadingLimits.TemporaryLimit limit : unmodifiedTemporaryLimits) { - addTemporaryLimit(limitsAdder, limit.getName(), limit.getValue(), limit.getAcceptableDuration(), applicability); + addTemporaryLimit(limitsAdder, limit.getName(), limit.getValue(), limit.getAcceptableDuration()); } } } @@ -557,29 +557,25 @@ public void modifyTemporaryLimit( .withSeverity(TypedValue.DETAIL_SEVERITY) .build(), applicability); - addTemporaryLimit(limitsAdder, limitModificationInfos.getName(), limitValue, limitAcceptableDuration, applicability); + addTemporaryLimit(limitsAdder, limitModificationInfos.getName(), limitValue, limitAcceptableDuration); } else { - addTemporaryLimit(limitsAdder, limitModificationInfos.getName(), limitToModify.getValue(), limitAcceptableDuration, applicability); + addTemporaryLimit(limitsAdder, limitModificationInfos.getName(), limitToModify.getValue(), limitAcceptableDuration); + // log only if there is at least one actual modification + if (Double.compare(limitToModify.getValue(), limitValue) != 0 || + !limitToModify.getName().equals(limitModificationInfos.getName())) { + addToLogsOnSide(ReportNode.newRootReportNode() + .withAllResourceBundlesFromClasspath() + .withMessageTemplate("network.modification.temporaryLimitModified.name") + .withUntypedValue(NAME, limitModificationInfos.getName()) + .withUntypedValue(VALUE, limitToModify.getValue()) + .withUntypedValue(DURATION, limitAcceptableDuration) + .withSeverity(TypedValue.DETAIL_SEVERITY) + .build(), + applicability); + } } } - public void addTemporaryLimit(CurrentLimitsAdder limitsAdder, - String limit, - double limitValue, - int limitAcceptableDuration, - OperationalLimitsGroupInfos.Applicability applicability) { - AbstractBranchModification.addTemporaryLimit(limitsAdder, limit, limitValue, limitAcceptableDuration); - addToLogsOnSide(ReportNode.newRootReportNode() - .withAllResourceBundlesFromClasspath() - .withMessageTemplate("network.modification.temporaryLimitModified.name") - .withUntypedValue(NAME, limit) - .withUntypedValue(VALUE, limitValue) - .withUntypedValue(DURATION, limitAcceptableDuration) - .withSeverity(TypedValue.DETAIL_SEVERITY) - .build(), - applicability); - } - public void createTemporaryLimit( CurrentLimitsAdder limitsAdder, CurrentTemporaryLimitModificationInfos limit, @@ -596,7 +592,7 @@ public void createTemporaryLimit( .withUntypedValue(AbstractBranchModification.VALUE, limitValueToReport) .withSeverity(TypedValue.DETAIL_SEVERITY) .build(), - olgModifInfos.getApplicability()); - addTemporaryLimit(limitsAdder, limit.getName(), limitValue, limitAcceptableDuration, applicability); + applicability); + addTemporaryLimit(limitsAdder, limit.getName(), limitValue, limitAcceptableDuration); } } From cc3401c8002da44a444c723375c60409047a050b Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Tue, 25 Nov 2025 11:26:54 +0100 Subject: [PATCH 13/22] corrections post merge conflicts Signed-off-by: Mathieu DEHARBE --- .../AbstractBranchModification.java | 3 +- .../modifications/olg/OlgModification.java | 34 +++++++++---------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java b/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java index 6e4911e1..cc604f7b 100644 --- a/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java @@ -13,7 +13,6 @@ import org.gridsuite.modification.NetworkModificationException; import org.gridsuite.modification.dto.*; import org.gridsuite.modification.modifications.olg.OlgsModification; -import org.gridsuite.modification.report.NetworkModificationReportResourceBundle; import org.gridsuite.modification.utils.ModificationUtils; import org.springframework.util.StringUtils; @@ -278,7 +277,7 @@ private boolean updateConnection(Branch branch, TwoSides side, Boolean connec return done; } - public static boolean mayCreateALimit(TemporaryLimitModificationType modificationType) { + public static boolean mayCreateLimit(TemporaryLimitModificationType modificationType) { return modificationType == TemporaryLimitModificationType.ADD || modificationType == TemporaryLimitModificationType.REPLACE || modificationType == TemporaryLimitModificationType.MODIFY_OR_ADD; diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index 977abbc0..b12ead74 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -12,6 +12,7 @@ import com.powsybl.iidm.network.*; import org.gridsuite.modification.dto.*; import org.gridsuite.modification.modifications.AbstractBranchModification; +import org.gridsuite.modification.report.NetworkModificationReportResourceBundle; import org.gridsuite.modification.utils.ModificationUtils; import org.springframework.util.CollectionUtils; @@ -66,7 +67,7 @@ private OperationalLimitsGroup modifiedOperationalLimitsGroup2() { protected void applyModificationToOperationalLimitsGroup() { switch (olgModifInfos.getModificationType()) { - case OperationalLimitsGroupModificationType.MODIFY_OR_ADD: { + case OperationalLimitsGroupModificationType.MODIFY_OR_ADD: switch (olgModifInfos.getApplicability()) { case EQUIPMENT : if (modifiedOperationalLimitsGroup1() == null && modifiedOperationalLimitsGroup2() == null) { @@ -102,8 +103,8 @@ protected void applyModificationToOperationalLimitsGroup() { } break; } - } break; - case OperationalLimitsGroupModificationType.MODIFY: { + break; + case OperationalLimitsGroupModificationType.MODIFY: if (applicableOnSide1() && modifiedOperationalLimitsGroup1() == null) { throw new PowsyblException("Cannot modify operational limit group " + olgModifInfos.getId() + " which has not been found in equipment side 1"); } @@ -111,16 +112,15 @@ protected void applyModificationToOperationalLimitsGroup() { throw new PowsyblException("Cannot modify operational limit group " + olgModifInfos.getId() + " which has not been found in equipment side 2"); } modifyOLG(olgModifInfos.getApplicability()); - } break; - case OperationalLimitsGroupModificationType.ADD: { + break; + case OperationalLimitsGroupModificationType.ADD: addOlg(olgModifInfos.getApplicability()); - } break; - case OperationalLimitsGroupModificationType.REPLACE: { + break; + case OperationalLimitsGroupModificationType.REPLACE: replaceOpLG(); - } break; - case DELETE: { + break; + case DELETE: removeOlg(); - } } } @@ -430,7 +430,7 @@ protected void modifyTemporaryLimits(CurrentLimitsAdder limitsAdder, CurrentLimi // this needs to be logged only if there are unmodifiedTemporaryLimits left. // which means that they are going to be removed by the REPLACE mode addToLogsOnSide(ReportNode.newRootReportNode() - .withAllResourceBundlesFromClasspath() + .withResourceBundles(NetworkModificationReportResourceBundle.BASE_NAME) .withMessageTemplate("network.modification.temporaryLimitsReplaced") .withSeverity(TypedValue.DETAIL_SEVERITY) .build(), @@ -468,14 +468,14 @@ private void applyTemporaryLimitModification( // this limit is modified by the network modification so we remove it from the list of unmodified temporary limits unmodifiedTemporaryLimits.removeIf(temporaryLimit -> temporaryLimit.getAcceptableDuration() == limitAcceptableDuration); } - if (limitToModify == null && mayCreateALimit(limit.getModificationType())) { + if (limitToModify == null && mayCreateLimit(limit.getModificationType())) { createTemporaryLimit(limitsAdder, limit, limitDurationToReport, limitValueToReport, limitValue, limitAcceptableDuration, applicability); } else if (limitToModify != null) { // the limit already exists if (limit.getModificationType() == TemporaryLimitModificationType.DELETE) { // the limit has been removed previously addToLogsOnSide(ReportNode.newRootReportNode() - .withAllResourceBundlesFromClasspath() + .withResourceBundles(NetworkModificationReportResourceBundle.BASE_NAME) .withMessageTemplate("network.modification.temporaryLimitDeleted.name") .withUntypedValue(NAME, limit.getName()) .withUntypedValue(DURATION, limitDurationToReport) @@ -488,7 +488,7 @@ private void applyTemporaryLimitModification( } else if (limit.getModificationType() == TemporaryLimitModificationType.MODIFY || limit.getModificationType() == TemporaryLimitModificationType.MODIFY_OR_ADD) { // invalid modification addToLogsOnSide(ReportNode.newRootReportNode() - .withAllResourceBundlesFromClasspath() + .withResourceBundles(NetworkModificationReportResourceBundle.BASE_NAME) .withMessageTemplate("network.modification.temporaryLimitsNoMatch") .withUntypedValue(LIMIT_ACCEPTABLE_DURATION, limitAcceptableDuration) .withSeverity(TypedValue.WARN_SEVERITY) @@ -546,7 +546,7 @@ public void modifyTemporaryLimit( if (Double.compare(limitToModify.getValue(), limitValue) != 0 && limitModificationInfos.getModificationType() != null) { // value change addToLogsOnSide(ReportNode.newRootReportNode() - .withAllResourceBundlesFromClasspath() + .withResourceBundles(NetworkModificationReportResourceBundle.BASE_NAME) .withMessageTemplate("network.modification.temporaryLimitValueModified.name") .withUntypedValue(AbstractBranchModification.NAME, limitModificationInfos.getName()) .withUntypedValue(DURATION, limitDurationToReport) @@ -564,7 +564,7 @@ public void modifyTemporaryLimit( if (Double.compare(limitToModify.getValue(), limitValue) != 0 || !limitToModify.getName().equals(limitModificationInfos.getName())) { addToLogsOnSide(ReportNode.newRootReportNode() - .withAllResourceBundlesFromClasspath() + .withResourceBundles(NetworkModificationReportResourceBundle.BASE_NAME) .withMessageTemplate("network.modification.temporaryLimitModified.name") .withUntypedValue(NAME, limitModificationInfos.getName()) .withUntypedValue(VALUE, limitToModify.getValue()) @@ -585,7 +585,7 @@ public void createTemporaryLimit( int limitAcceptableDuration, OperationalLimitsGroupInfos.Applicability applicability) { addToLogsOnSide(ReportNode.newRootReportNode() - .withAllResourceBundlesFromClasspath() + .withResourceBundles(NetworkModificationReportResourceBundle.BASE_NAME) .withMessageTemplate("network.modification.temporaryLimitAdded.name") .withUntypedValue(AbstractBranchModification.NAME, limit.getName()) .withUntypedValue(DURATION, limitDurationToReport) From 9df943ce7b68a85ada00db819fcad7c46aa8999a Mon Sep 17 00:00:00 2001 From: Mathieu Deharbe <148252167+Mathieu-Deharbe@users.noreply.github.com> Date: Tue, 25 Nov 2025 11:37:36 +0100 Subject: [PATCH 14/22] if (!limitsReportsSide1.isEmpty() || !limitsReportsSide2.isEmpty()) { Co-authored-by: EtienneLt --- .../modification/modifications/olg/OlgModification.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index b12ead74..01074eac 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -284,7 +284,7 @@ private void addOlg(OperationalLimitsGroupInfos.Applicability applicability) { addOlgOnASide(modifiedBranch.newOperationalLimitsGroup2(olgModifInfos.getId()), SIDE2); } - if (!CollectionUtils.isEmpty(limitsReportsSide1) || !CollectionUtils.isEmpty(limitsReportsSide2)) { + if (!limitsReportsSide1.isEmpty() || !limitsReportsSide2.isEmpty()) { ReportNode limitSetReport = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupAdded") .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) From 0d9870d5b78ddf03eddb9db4ee031be99b0f4893 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Tue, 25 Nov 2025 11:39:38 +0100 Subject: [PATCH 15/22] createLogNodeForSide Signed-off-by: Mathieu DEHARBE --- .../modifications/olg/OlgModification.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index b12ead74..1ee1e2ba 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -158,15 +158,12 @@ private void modifyOLG(OperationalLimitsGroupInfos.Applicability applicability) .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) .withUntypedValue(SIDE, applicabilityToString(applicability)) .withSeverity(TypedValue.INFO_SEVERITY).add(); - logSideNode(limitSetReport, "network.modification.operationalLimitsGroupModified.detail", SIDE1); - logSideNode(limitSetReport, "network.modification.operationalLimitsGroupModified.detail", SIDE2); + createLogNodeForSide(limitSetReport, "network.modification.operationalLimitsGroupModified.detail", SIDE1); + createLogNodeForSide(limitSetReport, "network.modification.operationalLimitsGroupModified.detail", SIDE2); } } - /** - * creates a log node specific for each side - */ - private void logSideNode(ReportNode limitSetReport, String messageTemplate, OperationalLimitsGroupInfos.Applicability applicability) { + private void createLogNodeForSide(ReportNode limitSetReport, String messageTemplate, OperationalLimitsGroupInfos.Applicability applicability) { List limitsReports; if (applicability == SIDE1) { limitsReports = limitsReportsSide1; @@ -291,8 +288,8 @@ private void addOlg(OperationalLimitsGroupInfos.Applicability applicability) { .withUntypedValue(SIDE, applicabilityToString(applicability)) .withSeverity(TypedValue.INFO_SEVERITY) .add(); - logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", SIDE1); - logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", SIDE2); + createLogNodeForSide(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", SIDE1); + createLogNodeForSide(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", SIDE2); } } @@ -338,8 +335,8 @@ private void replaceOpLG() { .withUntypedValue(SIDE, applicabilityToString(olgModifInfos.getApplicability())) .withSeverity(TypedValue.INFO_SEVERITY) .add(); - logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", SIDE1); - logSideNode(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", SIDE2); + createLogNodeForSide(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", SIDE1); + createLogNodeForSide(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", SIDE2); } } From 777057f0c3e5f213c8b4423c54f85a038c5cbb85 Mon Sep 17 00:00:00 2001 From: Mathieu Deharbe <148252167+Mathieu-Deharbe@users.noreply.github.com> Date: Tue, 25 Nov 2025 11:51:55 +0100 Subject: [PATCH 16/22] if (!limitsReportsSide1.isEmpty() || !limitsReportsSide2.isEmpty()) { Co-authored-by: EtienneLt --- .../modification/modifications/olg/OlgModification.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index 8412c2a5..e2fe3bba 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -328,7 +328,7 @@ private void replaceOpLG() { addProperties(newOperationalLimitsGroup, SIDE2); } - if (!CollectionUtils.isEmpty(limitsReportsSide1) || !CollectionUtils.isEmpty(limitsReportsSide2)) { + if (!limitsReportsSide1.isEmpty() || !limitsReportsSide2.isEmpty()) { ReportNode limitSetReport = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupReplaced") .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) From 803482c2772572699e3e1f2cb6f0e7ee25fcf149 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Tue, 25 Nov 2025 12:07:17 +0100 Subject: [PATCH 17/22] check on createLogNodeForSide parameter Signed-off-by: Mathieu DEHARBE --- .../modification/modifications/olg/OlgModification.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index e2fe3bba..184b15ef 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -164,12 +164,10 @@ private void modifyOLG(OperationalLimitsGroupInfos.Applicability applicability) } private void createLogNodeForSide(ReportNode limitSetReport, String messageTemplate, OperationalLimitsGroupInfos.Applicability applicability) { - List limitsReports; - if (applicability == SIDE1) { - limitsReports = limitsReportsSide1; - } else { - limitsReports = limitsReportsSide2; + if (applicability == EQUIPMENT) { + throw new IllegalArgumentException("createLogNodeForSide cannot be called on an EQUIPMENT applicability"); } + List limitsReports = applicability == SIDE1 ? limitsReportsSide1 : limitsReportsSide2; if (!limitsReports.isEmpty()) { ReportNode limitSetReportDetail = limitSetReport.newReportNode() .withMessageTemplate(messageTemplate) From a3df970933c09de55f0f292ea1df10ca374e9b5a Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Tue, 25 Nov 2025 14:17:46 +0100 Subject: [PATCH 18/22] corrections post review Signed-off-by: Mathieu DEHARBE --- .../modifications/olg/OlgModification.java | 23 +++++++++---------- .../gridsuite/modification/reports.properties | 2 +- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index 184b15ef..0cbf4188 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -31,6 +31,7 @@ * @author Mathieu DEHARBE */ public class OlgModification { + public static final String OPERATIONAL_LIMITS_GROUP_ADDED_LOG_DETAIL = "network.modification.operationalLimitsGroupAdded.detail"; private final Branch modifiedBranch; // branch modified by the network modification private final OperationalLimitsGroupModificationInfos olgModifInfos; private final ReportNode olgsReportNode; @@ -117,7 +118,7 @@ protected void applyModificationToOperationalLimitsGroup() { addOlg(olgModifInfos.getApplicability()); break; case OperationalLimitsGroupModificationType.REPLACE: - replaceOpLG(); + replaceOlg(); break; case DELETE: removeOlg(); @@ -270,13 +271,13 @@ private void addOlg(OperationalLimitsGroupInfos.Applicability applicability) { if (modifiedOperationalLimitsGroup1() != null) { throw new PowsyblException("Cannot add " + modifiedOperationalLimitsGroup1().getId() + " operational limit group, one with the given name already exists"); } - addOlgOnASide(modifiedBranch.newOperationalLimitsGroup1(olgModifInfos.getId()), SIDE1); + addOlgOnSide(modifiedBranch.newOperationalLimitsGroup1(olgModifInfos.getId()), SIDE1); } if (applicability == EQUIPMENT || applicability == SIDE2) { if (modifiedOperationalLimitsGroup2() != null) { throw new PowsyblException("Cannot add " + modifiedOperationalLimitsGroup2().getId() + " operational limit group, one with the given name already exists"); } - addOlgOnASide(modifiedBranch.newOperationalLimitsGroup2(olgModifInfos.getId()), SIDE2); + addOlgOnSide(modifiedBranch.newOperationalLimitsGroup2(olgModifInfos.getId()), SIDE2); } if (!limitsReportsSide1.isEmpty() || !limitsReportsSide2.isEmpty()) { @@ -286,8 +287,8 @@ private void addOlg(OperationalLimitsGroupInfos.Applicability applicability) { .withUntypedValue(SIDE, applicabilityToString(applicability)) .withSeverity(TypedValue.INFO_SEVERITY) .add(); - createLogNodeForSide(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", SIDE1); - createLogNodeForSide(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", SIDE2); + createLogNodeForSide(limitSetReport, OPERATIONAL_LIMITS_GROUP_ADDED_LOG_DETAIL, SIDE1); + createLogNodeForSide(limitSetReport, OPERATIONAL_LIMITS_GROUP_ADDED_LOG_DETAIL, SIDE2); } } @@ -299,12 +300,12 @@ private String applicabilityToString(OperationalLimitsGroupInfos.Applicability a }; } - private void addOlgOnASide(OperationalLimitsGroup newOperationalLimitsGroup, OperationalLimitsGroupInfos.Applicability applicability) { + private void addOlgOnSide(OperationalLimitsGroup newOperationalLimitsGroup, OperationalLimitsGroupInfos.Applicability applicability) { modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), newOperationalLimitsGroup.getCurrentLimits().orElse(null), applicability); addProperties(newOperationalLimitsGroup, applicability); } - private void replaceOpLG() { + private void replaceOlg() { if (applicableOnSide1()) { OperationalLimitsGroup modifiedOlg = modifiedOperationalLimitsGroup1(); if (modifiedOlg != null) { @@ -333,8 +334,8 @@ private void replaceOpLG() { .withUntypedValue(SIDE, applicabilityToString(olgModifInfos.getApplicability())) .withSeverity(TypedValue.INFO_SEVERITY) .add(); - createLogNodeForSide(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", SIDE1); - createLogNodeForSide(limitSetReport, "network.modification.operationalLimitsGroupAdded.detail", SIDE2); + createLogNodeForSide(limitSetReport, OPERATIONAL_LIMITS_GROUP_ADDED_LOG_DETAIL, SIDE1); + createLogNodeForSide(limitSetReport, OPERATIONAL_LIMITS_GROUP_ADDED_LOG_DETAIL, SIDE2); } } @@ -497,7 +498,6 @@ private void applyTemporaryLimitModification( */ public boolean isThisLimitDeleted(List temporaryLimitsModification, int acceptableDuration) { return temporaryLimitsModification.stream() - .filter(temporaryLimit -> temporaryLimit.getAcceptableDuration() != null) .anyMatch(temporaryLimit -> temporaryLimit.getAcceptableDuration() == acceptableDuration && temporaryLimit.getModificationType() == TemporaryLimitModificationType.DELETE ); @@ -512,8 +512,7 @@ private LoadingLimits.TemporaryLimit getTemporaryLimitToModify( LoadingLimits.TemporaryLimit limitToModify; limitToModify = networkCurrentLimits.getTemporaryLimit(limitAcceptableDuration); if (limitToModify != null && !limitToModify.getName().equals(limit.getName())) { - boolean isThisLimitDeleted = isThisLimitDeleted(currentLimitsInfos.getTemporaryLimits(), limitAcceptableDuration); - if (isThisLimitDeleted) { + if (isThisLimitDeleted(currentLimitsInfos.getTemporaryLimits(), limitAcceptableDuration)) { limitToModify = null; } else if (TemporaryLimitModificationType.ADD.equals(limit.getModificationType())) { throw new PowsyblException("2 temporary limits have the same duration " + limitAcceptableDuration); diff --git a/src/main/resources/org/gridsuite/modification/reports.properties b/src/main/resources/org/gridsuite/modification/reports.properties index 3f4138dd..98678379 100644 --- a/src/main/resources/org/gridsuite/modification/reports.properties +++ b/src/main/resources/org/gridsuite/modification/reports.properties @@ -300,7 +300,7 @@ network.modification.tapChangerStepsModification = Taps were replaced by new one network.modification.tapsModification = Taps network.modification.temporaryLimitAdded.name = ${name} (${duration}) added with ${value} network.modification.temporaryLimitDeleted.name = ${name} (${duration}) deleted -network.modification.temporaryLimitValueModified.name = Temporary limit ${name} (${duration}) : ${oldValue} -> ${value} +network.modification.temporaryLimitValueModified.name = Temporary limit ${name} (duration: ${duration}) : ${oldValue} -> ${value} network.modification.temporaryLimitModified.name = Temporary limit ${name}; value: ${value}; acceptable duration: ${duration} network.modification.temporaryLimitsReplaced = Previous temporary limits were removed network.modification.temporaryLimitsNoMatch = No existing temporary limit found with acceptableDuration = ${limitAcceptableDuration} matching is based on acceptableDuration if that helps From 7b57038015c197f4a2639848e47ffa440a845132 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Wed, 26 Nov 2025 12:08:18 +0100 Subject: [PATCH 19/22] corrects name modification Signed-off-by: Mathieu DEHARBE --- .../modifications/AbstractBranchModification.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java b/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java index cc604f7b..bb6616ea 100644 --- a/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java @@ -20,7 +20,7 @@ import java.util.stream.Collectors; import static org.gridsuite.modification.NetworkModificationException.Type.BRANCH_MODIFICATION_ERROR; -import static org.gridsuite.modification.utils.ModificationUtils.insertReportNode; +import static org.gridsuite.modification.utils.ModificationUtils.NO_VALUE; /** * @author Florent MILLOT @@ -48,9 +48,14 @@ protected void modifyBranch(Branch branch, BranchModificationInfos branchModi .withUntypedValue("id", branchModificationInfos.getEquipmentId()) .withSeverity(TypedValue.INFO_SEVERITY) .add(); - if (branchModificationInfos.getEquipmentName() != null) { - insertReportNode(subReportNode, ModificationUtils.getInstance().buildModificationReport(Optional.of(branch.getOptionalName()).orElse(null), branchModificationInfos.getEquipmentName().getValue(), "Name")); - branch.setName(branchModificationInfos.getEquipmentName().getValue()); + if (branchModificationInfos.getEquipmentName() != null && modificationInfos.getEquipmentName().getValue() != null) { + ModificationUtils.getInstance().applyElementaryModifications( + branch::setName, + () -> branch.getOptionalName().orElse(NO_VALUE), + modificationInfos.getEquipmentName(), + subReportNode, + "Name" + ); } modifyBranchVoltageLevelBusOrBusBarSectionAttributesSide1(modificationInfos, branch, subReportNode); From 77930deb5b703fee5319c61306ed8c6140316272 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Wed, 26 Nov 2025 13:31:29 +0100 Subject: [PATCH 20/22] logs in case of line ceration and transfo creation Signed-off-by: Mathieu DEHARBE --- .../modifications/LineCreation.java | 23 ++- .../TwoWindingsTransformerCreation.java | 95 ++++++++----- .../modifications/olg/OlgModification.java | 31 ++-- .../modification/utils/ModificationUtils.java | 134 ++++++++++-------- .../gridsuite/modification/reports.properties | 4 +- 5 files changed, 162 insertions(+), 125 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/modifications/LineCreation.java b/src/main/java/org/gridsuite/modification/modifications/LineCreation.java index d65617f8..b7f8636a 100644 --- a/src/main/java/org/gridsuite/modification/modifications/LineCreation.java +++ b/src/main/java/org/gridsuite/modification/modifications/LineCreation.java @@ -80,16 +80,25 @@ public void apply(Network network, ReportNode subReportNode) { List opLimitsGroupSide1 = ModificationUtils.getOperationalLimitsGroupsOnSide(modificationInfos.getOperationalLimitsGroups(), Applicability.SIDE1); List opLimitsGroupSide2 = ModificationUtils.getOperationalLimitsGroupsOnSide(modificationInfos.getOperationalLimitsGroups(), Applicability.SIDE2); ReportNode reportNode = null; - if (!CollectionUtils.isEmpty(opLimitsGroupSide1)) { + if (!CollectionUtils.isEmpty(modificationInfos.getOperationalLimitsGroups())) { reportNode = addLimitSetReportNode(limitsReporter); - ModificationUtils.getInstance().setCurrentLimitsOnASide(reportNode, opLimitsGroupSide1, line, ONE); - } - if (!CollectionUtils.isEmpty(opLimitsGroupSide2)) { - if (reportNode == null) { - reportNode = addLimitSetReportNode(limitsReporter); + + for (OperationalLimitsGroupInfos olgInfos : modificationInfos.getOperationalLimitsGroups()) { + ReportNode limitSetNode = reportNode.newReportNode() + .withMessageTemplate("network.modification.limitSetAdded") + .withUntypedValue("name", olgInfos.getId()) + .withSeverity(TypedValue.INFO_SEVERITY) + .add(); + + if (olgInfos.getApplicability() == Applicability.SIDE1 || olgInfos.getApplicability() == Applicability.EQUIPMENT) { + ModificationUtils.getInstance().setCurrentLimitsOnASide(limitSetNode, olgInfos, line, ONE); + } + if (olgInfos.getApplicability() == Applicability.SIDE2 || olgInfos.getApplicability() == Applicability.EQUIPMENT) { + ModificationUtils.getInstance().setCurrentLimitsOnASide(limitSetNode, olgInfos, line, TWO); + } } - ModificationUtils.getInstance().setCurrentLimitsOnASide(reportNode, opLimitsGroupSide2, line, TWO); } + List limitSetsOnSideReportNodes = new ArrayList<>(); if (modificationInfos.getSelectedOperationalLimitsGroup1() != null) { if (!ModificationUtils.hasLimitSet(opLimitsGroupSide1, modificationInfos.getSelectedOperationalLimitsGroup1())) { diff --git a/src/main/java/org/gridsuite/modification/modifications/TwoWindingsTransformerCreation.java b/src/main/java/org/gridsuite/modification/modifications/TwoWindingsTransformerCreation.java index 885d3274..e8fc9b8d 100644 --- a/src/main/java/org/gridsuite/modification/modifications/TwoWindingsTransformerCreation.java +++ b/src/main/java/org/gridsuite/modification/modifications/TwoWindingsTransformerCreation.java @@ -20,6 +20,8 @@ import java.util.List; import java.util.Optional; +import static com.powsybl.iidm.network.TwoSides.ONE; +import static com.powsybl.iidm.network.TwoSides.TWO; import static org.gridsuite.modification.NetworkModificationException.Type.*; import static org.gridsuite.modification.dto.OperationalLimitsGroupInfos.Applicability.SIDE1; import static org.gridsuite.modification.dto.OperationalLimitsGroupInfos.Applicability.SIDE2; @@ -239,38 +241,6 @@ private void create2WTInOtherBreaker(Network network, VoltageLevel voltageLevel1 completeTwoWindingsTransformerCreation(network, twoWindingsTransformer, modificationInfos, subReportNode); } - private void setCurrentLimitsForSide(ReportNode reportNode, List operationalLimitsGroups, String selectedGroup, TwoWindingsTransformer transformer, TwoSides side, - List limitSetsOnSideReportNodes) { - if (!CollectionUtils.isEmpty(operationalLimitsGroups)) { - getInstance().setCurrentLimitsOnASide(reportNode, operationalLimitsGroups, transformer, side); - } - if (selectedGroup != null) { - if (!ModificationUtils.hasLimitSet(operationalLimitsGroups, selectedGroup)) { - limitSetsOnSideReportNodes.add(ReportNode.newRootReportNode() - .withMessageTemplate("network.modification.limitSetAbsentOnSide" + side.getNum()) - .withUntypedValue("selectedOperationalLimitsGroup", selectedGroup) - .withSeverity(TypedValue.WARN_SEVERITY) - .build()); - return; - } - - if (side == TwoSides.ONE) { - transformer.setSelectedOperationalLimitsGroup1(selectedGroup); - limitSetsOnSideReportNodes.add(ReportNode.newRootReportNode().withMessageTemplate("network.modification.limitSetSelectedOnSide1") - .withUntypedValue("selectedOperationalLimitsGroup1", modificationInfos.getSelectedOperationalLimitsGroup1()) - .withSeverity(TypedValue.INFO_SEVERITY) - .build()); - } - if (side == TwoSides.TWO) { - transformer.setSelectedOperationalLimitsGroup2(selectedGroup); - limitSetsOnSideReportNodes.add(ReportNode.newRootReportNode().withMessageTemplate("network.modification.limitSetSelectedOnSide2") - .withUntypedValue("selectedOperationalLimitsGroup2", modificationInfos.getSelectedOperationalLimitsGroup2()) - .withSeverity(TypedValue.INFO_SEVERITY) - .build()); - } - } - } - private void completeTwoWindingsTransformerCreation(Network network, TwoWindingsTransformer twoWindingsTransformer, TwoWindingsTransformerCreationInfos modificationInfos, @@ -290,12 +260,61 @@ private void completeTwoWindingsTransformerCreation(Network network, List operationalLimitsGroups2 = ModificationUtils.getOperationalLimitsGroupsOnSide(modificationInfos.getOperationalLimitsGroups(), SIDE2); List limitSetsOnSideReportNodes = new ArrayList<>(); - ReportNode reportNode = limitsReporter.newReportNode() - .withSeverity(TypedValue.INFO_SEVERITY) - .withMessageTemplate("network.modification.LimitSets") - .add(); - setCurrentLimitsForSide(reportNode, operationalLimitsGroups1, modificationInfos.getSelectedOperationalLimitsGroup1(), twoWindingsTransformer, TwoSides.ONE, limitSetsOnSideReportNodes); - setCurrentLimitsForSide(reportNode, operationalLimitsGroups2, modificationInfos.getSelectedOperationalLimitsGroup2(), twoWindingsTransformer, TwoSides.TWO, limitSetsOnSideReportNodes); + if (!CollectionUtils.isEmpty(modificationInfos.getOperationalLimitsGroups())) { + ReportNode reportNode = limitsReporter.newReportNode() + .withSeverity(TypedValue.INFO_SEVERITY) + .withMessageTemplate("network.modification.LimitSets") + .add(); + + for (OperationalLimitsGroupInfos olgInfos : modificationInfos.getOperationalLimitsGroups()) { + ReportNode limitSetNode = reportNode.newReportNode() + .withMessageTemplate("network.modification.limitSetAdded") + .withUntypedValue("name", olgInfos.getId()) + .withSeverity(TypedValue.INFO_SEVERITY) + .add(); + + if (olgInfos.getApplicability() == OperationalLimitsGroupInfos.Applicability.SIDE1 || olgInfos.getApplicability() == OperationalLimitsGroupInfos.Applicability.EQUIPMENT) { + ModificationUtils.getInstance().setCurrentLimitsOnASide(limitSetNode, olgInfos, twoWindingsTransformer, ONE); + } + if (olgInfos.getApplicability() == OperationalLimitsGroupInfos.Applicability.SIDE2 || olgInfos.getApplicability() == OperationalLimitsGroupInfos.Applicability.EQUIPMENT) { + ModificationUtils.getInstance().setCurrentLimitsOnASide(limitSetNode, olgInfos, twoWindingsTransformer, TWO); + } + } + } + + if (modificationInfos.getSelectedOperationalLimitsGroup1() != null) { + if (!ModificationUtils.hasLimitSet(operationalLimitsGroups1, modificationInfos.getSelectedOperationalLimitsGroup1())) { + limitSetsOnSideReportNodes.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.limitSetAbsentOnSide1") + .withUntypedValue("selectedOperationalLimitsGroup", modificationInfos.getSelectedOperationalLimitsGroup1()) + .withSeverity(TypedValue.WARN_SEVERITY) + .build()); + } else { + twoWindingsTransformer.setSelectedOperationalLimitsGroup1(modificationInfos.getSelectedOperationalLimitsGroup1()); + limitSetsOnSideReportNodes.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.limitSetSelectedOnSide1") + .withUntypedValue("selectedOperationalLimitsGroup1", modificationInfos.getSelectedOperationalLimitsGroup1()) + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + } + } + if (modificationInfos.getSelectedOperationalLimitsGroup2() != null) { + if (!ModificationUtils.hasLimitSet(operationalLimitsGroups2, modificationInfos.getSelectedOperationalLimitsGroup2())) { + limitSetsOnSideReportNodes.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.limitSetAbsentOnSide2") + .withUntypedValue("selectedOperationalLimitsGroup", modificationInfos.getSelectedOperationalLimitsGroup2()) + .withSeverity(TypedValue.WARN_SEVERITY) + .build()); + } else { + twoWindingsTransformer.setSelectedOperationalLimitsGroup2(modificationInfos.getSelectedOperationalLimitsGroup2()); + limitSetsOnSideReportNodes.add(ReportNode.newRootReportNode() + .withMessageTemplate("network.modification.limitSetSelectedOnSide2") + .withUntypedValue("selectedOperationalLimitsGroup2", modificationInfos.getSelectedOperationalLimitsGroup2()) + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + } + } + if (!limitSetsOnSideReportNodes.isEmpty()) { ModificationUtils.getInstance().reportModifications(limitsReporter, limitSetsOnSideReportNodes, "network.modification.ActiveLimitSets"); diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java index 0cbf4188..b193f5e5 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java @@ -31,7 +31,6 @@ * @author Mathieu DEHARBE */ public class OlgModification { - public static final String OPERATIONAL_LIMITS_GROUP_ADDED_LOG_DETAIL = "network.modification.operationalLimitsGroupAdded.detail"; private final Branch modifiedBranch; // branch modified by the network modification private final OperationalLimitsGroupModificationInfos olgModifInfos; private final ReportNode olgsReportNode; @@ -157,7 +156,7 @@ private void modifyOLG(OperationalLimitsGroupInfos.Applicability applicability) ReportNode limitSetReport = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupModified") .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) - .withUntypedValue(SIDE, applicabilityToString(applicability)) + .withUntypedValue(SIDE, ModificationUtils.applicabilityToString(applicability)) .withSeverity(TypedValue.INFO_SEVERITY).add(); createLogNodeForSide(limitSetReport, "network.modification.operationalLimitsGroupModified.detail", SIDE1); createLogNodeForSide(limitSetReport, "network.modification.operationalLimitsGroupModified.detail", SIDE2); @@ -172,7 +171,7 @@ private void createLogNodeForSide(ReportNode limitSetReport, String messageTempl if (!limitsReports.isEmpty()) { ReportNode limitSetReportDetail = limitSetReport.newReportNode() .withMessageTemplate(messageTemplate) - .withUntypedValue(SIDE, applicabilityToString(applicability)) + .withUntypedValue(SIDE, ModificationUtils.applicabilityToString(applicability)) .withSeverity(TypedValue.DETAIL_SEVERITY).add(); ModificationUtils.getInstance().reportModifications(limitSetReportDetail, limitsReports); } @@ -284,22 +283,14 @@ private void addOlg(OperationalLimitsGroupInfos.Applicability applicability) { ReportNode limitSetReport = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupAdded") .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) - .withUntypedValue(SIDE, applicabilityToString(applicability)) + .withUntypedValue(SIDE, ModificationUtils.applicabilityToString(applicability)) .withSeverity(TypedValue.INFO_SEVERITY) .add(); - createLogNodeForSide(limitSetReport, OPERATIONAL_LIMITS_GROUP_ADDED_LOG_DETAIL, SIDE1); - createLogNodeForSide(limitSetReport, OPERATIONAL_LIMITS_GROUP_ADDED_LOG_DETAIL, SIDE2); + createLogNodeForSide(limitSetReport, ModificationUtils.OPERATIONAL_LIMITS_GROUP_ADDED_LOG_DETAIL, SIDE1); + createLogNodeForSide(limitSetReport, ModificationUtils.OPERATIONAL_LIMITS_GROUP_ADDED_LOG_DETAIL, SIDE2); } } - private String applicabilityToString(OperationalLimitsGroupInfos.Applicability applicability) { - return switch (applicability) { - case EQUIPMENT -> "sides 1 & 2"; - case SIDE1 -> "side 1"; - case SIDE2 -> "side 2"; - }; - } - private void addOlgOnSide(OperationalLimitsGroup newOperationalLimitsGroup, OperationalLimitsGroupInfos.Applicability applicability) { modifyCurrentLimits(newOperationalLimitsGroup.newCurrentLimits(), newOperationalLimitsGroup.getCurrentLimits().orElse(null), applicability); addProperties(newOperationalLimitsGroup, applicability); @@ -331,11 +322,11 @@ private void replaceOlg() { ReportNode limitSetReport = olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupReplaced") .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, olgModifInfos.getId()) - .withUntypedValue(SIDE, applicabilityToString(olgModifInfos.getApplicability())) + .withUntypedValue(SIDE, ModificationUtils.applicabilityToString(olgModifInfos.getApplicability())) .withSeverity(TypedValue.INFO_SEVERITY) .add(); - createLogNodeForSide(limitSetReport, OPERATIONAL_LIMITS_GROUP_ADDED_LOG_DETAIL, SIDE1); - createLogNodeForSide(limitSetReport, OPERATIONAL_LIMITS_GROUP_ADDED_LOG_DETAIL, SIDE2); + createLogNodeForSide(limitSetReport, ModificationUtils.OPERATIONAL_LIMITS_GROUP_ADDED_LOG_DETAIL, SIDE1); + createLogNodeForSide(limitSetReport, ModificationUtils.OPERATIONAL_LIMITS_GROUP_ADDED_LOG_DETAIL, SIDE2); } } @@ -361,7 +352,7 @@ public void removeOlg() { if (applicableOnSide1() && modifiedBranch.getOperationalLimitsGroup1(olgId).isEmpty() || applicableOnSide2() && modifiedBranch.getOperationalLimitsGroup2(olgId).isEmpty()) { throw new PowsyblException( - "Cannot delete operational limit group " + olgId + " which has not been found in equipment on " + applicabilityToString(olgModifInfos.getApplicability())); + "Cannot delete operational limit group " + olgId + " which has not been found in equipment on " + ModificationUtils.applicabilityToString(olgModifInfos.getApplicability())); } if (applicableOnSide1()) { modifiedBranch.removeOperationalLimitsGroup1(olgId); @@ -372,7 +363,7 @@ public void removeOlg() { olgsReportNode.newReportNode() .withMessageTemplate("network.modification.operationalLimitsGroupDeleted") .withUntypedValue(OPERATIONAL_LIMITS_GROUP_NAME, olgId) - .withUntypedValue(SIDE, applicabilityToString(olgModifInfos.getApplicability())) + .withUntypedValue(SIDE, ModificationUtils.applicabilityToString(olgModifInfos.getApplicability())) .withSeverity(TypedValue.INFO_SEVERITY) .add(); } @@ -580,7 +571,7 @@ public void createTemporaryLimit( OperationalLimitsGroupInfos.Applicability applicability) { addToLogsOnSide(ReportNode.newRootReportNode() .withResourceBundles(NetworkModificationReportResourceBundle.BASE_NAME) - .withMessageTemplate("network.modification.temporaryLimitAdded.name") + .withMessageTemplate("network.modification.temporaryLimitModified.name") .withUntypedValue(AbstractBranchModification.NAME, limit.getName()) .withUntypedValue(DURATION, limitDurationToReport) .withUntypedValue(AbstractBranchModification.VALUE, limitValueToReport) diff --git a/src/main/java/org/gridsuite/modification/utils/ModificationUtils.java b/src/main/java/org/gridsuite/modification/utils/ModificationUtils.java index 5e1bb3c5..d7e1f01a 100644 --- a/src/main/java/org/gridsuite/modification/utils/ModificationUtils.java +++ b/src/main/java/org/gridsuite/modification/utils/ModificationUtils.java @@ -16,6 +16,7 @@ import org.gridsuite.modification.IFilterService; import org.gridsuite.modification.NetworkModificationException; import org.gridsuite.modification.dto.*; +import org.gridsuite.modification.modifications.AbstractBranchModification; import org.gridsuite.modification.modifications.BusbarSectionFinderTraverser; import org.gridsuite.modification.report.NetworkModificationReportResourceBundle; import org.springframework.util.CollectionUtils; @@ -34,6 +35,8 @@ import static com.powsybl.iidm.network.TwoSides.ONE; import static org.gridsuite.modification.NetworkModificationException.Type.*; +import static org.gridsuite.modification.dto.OperationalLimitsGroupInfos.Applicability.SIDE1; +import static org.gridsuite.modification.dto.OperationalLimitsGroupInfos.Applicability.SIDE2; import static org.gridsuite.modification.modifications.AbstractBranchModification.*; /** @@ -52,6 +55,7 @@ public final class ModificationUtils { public static final String NO_VALUE = "No value"; public static final String LIMITS = "network.modification.limits"; public static final String REACTIVE_LIMITS = "network.modification.ReactiveLimits"; + public static final String OPERATIONAL_LIMITS_GROUP_ADDED_LOG_DETAIL = "network.modification.operationalLimitsGroupAdded.detail"; private static final String SETPOINTS = "network.modification.Setpoints"; private static final String MIN_REACTIVE_POWER_FIELDNAME = "Minimum reactive power"; private static final String MAX_REACTIVE_POWER_FIELDNAME = "Maximum reactive power"; @@ -67,6 +71,14 @@ public final class ModificationUtils { public static final String CONNECT = "connect"; public static final String DISCONNECT = "disconnect"; + public static String applicabilityToString(OperationalLimitsGroupInfos.Applicability applicability) { + return switch (applicability) { + case EQUIPMENT -> "sides 1 & 2"; + case SIDE1 -> "side 1"; + case SIDE2 -> "side 2"; + }; + } + public enum FeederSide { INJECTION_SINGLE_SIDE, BRANCH_SIDE_ONE, @@ -1079,70 +1091,76 @@ public Identifiable getEquipmentByIdentifiableType(Network network, Identifia } /** - * @param reportNode Limit sets report node - * @param opLimitGroups added current limits + * @param reportNode Limit set report node + * @param opLimitsGroup added current limits * @param branch branch to which limits are going to be added * @param side which side of the branch receives the limits */ - public void setCurrentLimitsOnASide(ReportNode reportNode, List opLimitGroups, Branch branch, TwoSides side) { + public void setCurrentLimitsOnASide(ReportNode reportNode, OperationalLimitsGroupInfos opLimitsGroup, Branch branch, TwoSides side) { - if (CollectionUtils.isEmpty(opLimitGroups)) { + boolean hasPermanent = opLimitsGroup.getCurrentLimits().getPermanentLimit() != null; + boolean hasTemporary = !CollectionUtils.isEmpty(opLimitsGroup.getCurrentLimits().getTemporaryLimits()); + boolean hasLimits = hasPermanent || hasTemporary; + + if (!hasPermanent && !hasLimits || opLimitsGroup.getId() == null) { return; } - - for (OperationalLimitsGroupInfos opLimitsGroup : opLimitGroups) { - boolean hasPermanent = opLimitsGroup.getCurrentLimits().getPermanentLimit() != null; - boolean hasTemporary = !CollectionUtils.isEmpty(opLimitsGroup.getCurrentLimits().getTemporaryLimits()); - boolean hasLimits = hasPermanent || hasTemporary; - - if (!hasLimits || opLimitsGroup.getId() == null) { - continue; - } - - OperationalLimitsGroup opGroup = side == ONE - ? branch.newOperationalLimitsGroup1(opLimitsGroup.getId()) - : branch.newOperationalLimitsGroup2(opLimitsGroup.getId()); - - ReportNode limitSetNode = reportNode.newReportNode() - .withMessageTemplate("network.modification.limitSetAdded") - .withUntypedValue("name", opLimitsGroup.getId()) - .withSeverity(TypedValue.INFO_SEVERITY) - .add(); - - CurrentLimitsAdder limitsAdder = opGroup.newCurrentLimits(); - if (hasPermanent) { - limitsAdder.setPermanentLimit(opLimitsGroup.getCurrentLimits().getPermanentLimit()); - } - if (hasTemporary) { - opLimitsGroup.getCurrentLimits().getTemporaryLimits().forEach(limit -> { - double value = limit.getValue() != null ? limit.getValue() : Double.MAX_VALUE; - int duration = limit.getAcceptableDuration() != null ? limit.getAcceptableDuration() : Integer.MAX_VALUE; - - limitsAdder.beginTemporaryLimit() - .setName(limit.getName()) - .setValue(value) - .setAcceptableDuration(duration) - .endTemporaryLimit(); - }); - } - limitsAdder.add(); - - //add properties - List detailsOnLimitSet = new ArrayList<>(); - if (!CollectionUtils.isEmpty(opLimitsGroup.getLimitsProperties()) && - checkPropertiesUnicity(opLimitsGroup.getLimitsProperties(), detailsOnLimitSet)) { - opLimitsGroup.getLimitsProperties().forEach(property -> { - detailsOnLimitSet.add( - ReportNode.newRootReportNode().withSeverity(TypedValue.DETAIL_SEVERITY) - .withMessageTemplate("network.modification.propertyAdded") - .withUntypedValue(NAME, property.name()) - .withUntypedValue(VALUE, property.value()).build()); - opGroup.setProperty(property.name(), property.value()); - }); - if (!detailsOnLimitSet.isEmpty()) { - ModificationUtils.getInstance().reportModifications(limitSetNode, detailsOnLimitSet); - } - } + ReportNode limitSetReportDetail = reportNode.newReportNode() + .withMessageTemplate(OPERATIONAL_LIMITS_GROUP_ADDED_LOG_DETAIL) + .withUntypedValue(SIDE, applicabilityToString(side == ONE ? SIDE1 : SIDE2)) + .withSeverity(TypedValue.DETAIL_SEVERITY).add(); + + OperationalLimitsGroup opGroup = side == ONE + ? branch.newOperationalLimitsGroup1(opLimitsGroup.getId()) + : branch.newOperationalLimitsGroup2(opLimitsGroup.getId()); + List detailsOnLimitSet = new ArrayList<>(); + + CurrentLimitsAdder limitsAdder = opGroup.newCurrentLimits(); + if (hasPermanent) { + limitsAdder.setPermanentLimit(opLimitsGroup.getCurrentLimits().getPermanentLimit()); + detailsOnLimitSet.add(ReportNode.newRootReportNode() + .withResourceBundles(NetworkModificationReportResourceBundle.BASE_NAME) + .withMessageTemplate("network.modification.permanentLimit") + .withUntypedValue(VALUE, opLimitsGroup.getCurrentLimits().getPermanentLimit()) + .withSeverity(TypedValue.DETAIL_SEVERITY) + .build()); + } + if (hasTemporary) { + opLimitsGroup.getCurrentLimits().getTemporaryLimits().forEach(limit -> { + double value = limit.getValue() != null ? limit.getValue() : Double.MAX_VALUE; + int duration = limit.getAcceptableDuration() != null ? limit.getAcceptableDuration() : Integer.MAX_VALUE; + detailsOnLimitSet.add(ReportNode.newRootReportNode() + .withResourceBundles(NetworkModificationReportResourceBundle.BASE_NAME) + .withMessageTemplate("network.modification.temporaryLimitModified.name") + .withUntypedValue(AbstractBranchModification.NAME, limit.getName()) + .withUntypedValue(DURATION, duration) + .withUntypedValue(AbstractBranchModification.VALUE, value) + .withSeverity(TypedValue.DETAIL_SEVERITY) + .build()); + + limitsAdder.beginTemporaryLimit() + .setName(limit.getName()) + .setValue(value) + .setAcceptableDuration(duration) + .endTemporaryLimit(); + }); + } + limitsAdder.add(); + + //add properties + if (!CollectionUtils.isEmpty(opLimitsGroup.getLimitsProperties()) && + checkPropertiesUnicity(opLimitsGroup.getLimitsProperties(), detailsOnLimitSet)) { + opLimitsGroup.getLimitsProperties().forEach(property -> { + detailsOnLimitSet.add( + ReportNode.newRootReportNode().withSeverity(TypedValue.DETAIL_SEVERITY) + .withMessageTemplate("network.modification.propertyAdded") + .withUntypedValue(NAME, property.name()) + .withUntypedValue(VALUE, property.value()).build()); + opGroup.setProperty(property.name(), property.value()); + }); + } + if (!detailsOnLimitSet.isEmpty()) { + ModificationUtils.getInstance().reportModifications(limitSetReportDetail, detailsOnLimitSet); } } diff --git a/src/main/resources/org/gridsuite/modification/reports.properties b/src/main/resources/org/gridsuite/modification/reports.properties index 98678379..fb15a042 100644 --- a/src/main/resources/org/gridsuite/modification/reports.properties +++ b/src/main/resources/org/gridsuite/modification/reports.properties @@ -175,7 +175,7 @@ network.modification.invalidFilters = ${errorType}: There is no valid equipment 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.limitSetAdded = ${name} added network.modification.operationalLimitsGroupDeleted = Limit set ${operationalLimitsGroupName} has been deleted on ${side} network.modification.operationalLimitsGroupAdded = Limit set ${operationalLimitsGroupName} added on ${side} network.modification.operationalLimitsGroupAdded.detail = Added to operational limits group on ${side} @@ -298,7 +298,7 @@ network.modification.tabularCreation = Tabular creation (${creationType}) network.modification.tabularModification = Tabular modification (${modificationType}) network.modification.tapChangerStepsModification = Taps were replaced by new ones below network.modification.tapsModification = Taps -network.modification.temporaryLimitAdded.name = ${name} (${duration}) added with ${value} +network.modification.permanentLimit = Permanent limit value: ${value} network.modification.temporaryLimitDeleted.name = ${name} (${duration}) deleted network.modification.temporaryLimitValueModified.name = Temporary limit ${name} (duration: ${duration}) : ${oldValue} -> ${value} network.modification.temporaryLimitModified.name = Temporary limit ${name}; value: ${value}; acceptable duration: ${duration} From 188eed4dda4154be46592dd2d3994719f28e5b7d Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Wed, 26 Nov 2025 15:29:03 +0100 Subject: [PATCH 21/22] rename classes Signed-off-by: Mathieu DEHARBE --- .../modifications/AbstractBranchModification.java | 4 ++-- ...ation.java => OperationalLimitsGroupModification.java} | 4 ++-- ...tion.java => OperationalLimitsGroupsModification.java} | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) rename src/main/java/org/gridsuite/modification/modifications/olg/{OlgModification.java => OperationalLimitsGroupModification.java} (99%) rename src/main/java/org/gridsuite/modification/modifications/olg/{OlgsModification.java => OperationalLimitsGroupsModification.java} (98%) diff --git a/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java b/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java index bb6616ea..3a865388 100644 --- a/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/AbstractBranchModification.java @@ -12,7 +12,7 @@ import com.powsybl.iidm.network.extensions.*; import org.gridsuite.modification.NetworkModificationException; import org.gridsuite.modification.dto.*; -import org.gridsuite.modification.modifications.olg.OlgsModification; +import org.gridsuite.modification.modifications.olg.OperationalLimitsGroupsModification; import org.gridsuite.modification.utils.ModificationUtils; import org.springframework.util.StringUtils; @@ -75,7 +75,7 @@ protected void modifyBranch(Branch branch, BranchModificationInfos branchModi if (modifyOLG) { limitsReportNode = subReportNode.newReportNode().withMessageTemplate("network.modification.limits").add(); ReportNode limitSetsReportNode = limitsReportNode.newReportNode().withMessageTemplate("network.modification.limitsSets").add(); - new OlgsModification( + new OperationalLimitsGroupsModification( branch, branchModificationInfos.getOperationalLimitsGroups(), limitSetsReportNode diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OperationalLimitsGroupModification.java similarity index 99% rename from src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java rename to src/main/java/org/gridsuite/modification/modifications/olg/OperationalLimitsGroupModification.java index b193f5e5..5b70c52d 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OperationalLimitsGroupModification.java @@ -30,14 +30,14 @@ * * @author Mathieu DEHARBE */ -public class OlgModification { +public class OperationalLimitsGroupModification { private final Branch modifiedBranch; // branch modified by the network modification private final OperationalLimitsGroupModificationInfos olgModifInfos; private final ReportNode olgsReportNode; List limitsReportsSide1; List limitsReportsSide2; - public OlgModification( + public OperationalLimitsGroupModification( Branch modifiedBranch, OperationalLimitsGroupModificationInfos olgModifInfos, ReportNode limitSetsReportNode) { diff --git a/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java b/src/main/java/org/gridsuite/modification/modifications/olg/OperationalLimitsGroupsModification.java similarity index 98% rename from src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java rename to src/main/java/org/gridsuite/modification/modifications/olg/OperationalLimitsGroupsModification.java index c23ec826..f861f72c 100644 --- a/src/main/java/org/gridsuite/modification/modifications/olg/OlgsModification.java +++ b/src/main/java/org/gridsuite/modification/modifications/olg/OperationalLimitsGroupsModification.java @@ -23,12 +23,12 @@ * * @author Mathieu DEHARBE */ -public class OlgsModification { +public class OperationalLimitsGroupsModification { private final Branch modifiedBranch; // branch modified by the network modification private final List olgModificationInfos; private final ReportNode olgsReportNode; - public OlgsModification( + public OperationalLimitsGroupsModification( Branch branch, List operationalLimitsInfos, ReportNode limitSetsReportNode) { @@ -57,7 +57,7 @@ public void modifyOperationalLimitsGroups(OperationalLimitsGroupsModificationTyp detectApplicabilityChange(opLGModifInfos, olgSetReports); } - new OlgModification( + new OperationalLimitsGroupModification( modifiedBranch, opLGModifInfos, olgsReportNode @@ -84,7 +84,7 @@ private void deleteOlgsUnspecifiedInTheModification(OperationalLimitsGroupInfos. Iterator i = olgToBeDeleted.iterator(); while (i.hasNext()) { String s = i.next(); - new OlgModification( + new OperationalLimitsGroupModification( modifiedBranch, OperationalLimitsGroupModificationInfos.builder() .id(s) From 6155133d31d187e16325b4ef92438418a42aa083 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Wed, 26 Nov 2025 16:08:09 +0100 Subject: [PATCH 22/22] TU testRename Signed-off-by: Mathieu DEHARBE --- .../modifications/LineModificationTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/test/java/org/gridsuite/modification/modifications/LineModificationTest.java b/src/test/java/org/gridsuite/modification/modifications/LineModificationTest.java index c4d2d65d..109f7d65 100644 --- a/src/test/java/org/gridsuite/modification/modifications/LineModificationTest.java +++ b/src/test/java/org/gridsuite/modification/modifications/LineModificationTest.java @@ -8,6 +8,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.powsybl.commons.PowsyblException; +import com.powsybl.commons.report.ReportNode; import com.powsybl.iidm.network.*; import com.powsybl.iidm.network.extensions.ConnectablePosition; import com.powsybl.iidm.network.extensions.Measurement; @@ -16,6 +17,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.gridsuite.modification.NetworkModificationException; import org.gridsuite.modification.dto.*; +import org.gridsuite.modification.report.NetworkModificationReportResourceBundle; import org.gridsuite.modification.utils.NetworkCreation; import org.junit.jupiter.api.Test; @@ -27,6 +29,7 @@ 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.gridsuite.modification.utils.TestUtils.assertLogMessageWithoutRank; import static org.junit.jupiter.api.Assertions.*; /** @@ -337,6 +340,24 @@ void testConnectWhenNoSwitchesOpened() { assertEquals("BRANCH_MODIFICATION_ERROR : Could not connect equipment 'line1' on side 1 & 2", exception.getMessage()); } + @Test + void testRename() { + Line line = getNetwork().getLine("line1"); + line.setName(null); + + LineModificationInfos modificationInfos = LineModificationInfos.builder() + .equipmentName(AttributeModification.toAttributeModification("newName", OperationType.SET)) + .equipmentId("line1") + .build(); + ReportNode reportNode = modificationInfos.createSubReportNode(ReportNode.newRootReportNode() + .withResourceBundles(NetworkModificationReportResourceBundle.BASE_NAME) + .withMessageTemplate("test").build()); + modificationInfos.toModification().apply(getNetwork(), reportNode); + + assertEquals("newName", line.getOptionalName().orElseThrow()); + assertLogMessageWithoutRank("Name : No value → newName", "network.modification.fieldModification", reportNode); + } + @Test void testDelete() { Line line = getNetwork().getLine("line1");