diff --git a/src/main/java/org/gridsuite/study/server/StudyConstants.java b/src/main/java/org/gridsuite/study/server/StudyConstants.java index d0789a28d5..d48c545fb4 100644 --- a/src/main/java/org/gridsuite/study/server/StudyConstants.java +++ b/src/main/java/org/gridsuite/study/server/StudyConstants.java @@ -26,6 +26,7 @@ private StudyConstants() { public static final String SECURITY_ANALYSIS_API_VERSION = "v1"; public static final String DYNAMIC_SIMULATION_API_VERSION = "v1"; public static final String DYNAMIC_SECURITY_ANALYSIS_API_VERSION = "v1"; + public static final String DYNAMIC_MARGIN_CALCULATION_API_VERSION = "v1"; public static final String SENSITIVITY_ANALYSIS_API_VERSION = "v1"; public static final String ACTIONS_API_VERSION = "v1"; public static final String NETWORK_MAP_API_VERSION = "v1"; diff --git a/src/main/java/org/gridsuite/study/server/controller/StudyController.java b/src/main/java/org/gridsuite/study/server/controller/StudyController.java index c4e15f9e46..ca2191b190 100644 --- a/src/main/java/org/gridsuite/study/server/controller/StudyController.java +++ b/src/main/java/org/gridsuite/study/server/controller/StudyController.java @@ -6,6 +6,7 @@ */ package org.gridsuite.study.server.controller; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.powsybl.iidm.network.ThreeSides; import com.powsybl.timeseries.DoubleTimeSeries; @@ -18,16 +19,12 @@ import org.apache.commons.lang3.StringUtils; import org.gridsuite.filter.globalfilter.GlobalFilter; import org.gridsuite.filter.utils.EquipmentType; -import org.gridsuite.study.server.service.RebuildNodeService; import org.gridsuite.study.server.StudyApi; -import org.gridsuite.study.server.StudyConstants.ModificationsActionType; -import org.gridsuite.study.server.dto.modification.NetworkModificationMetadata; -import org.gridsuite.study.server.error.StudyException; -import org.gridsuite.study.server.dto.networkexport.NodeExportInfos; import org.gridsuite.study.server.dto.*; import org.gridsuite.study.server.dto.computation.LoadFlowComputationInfos; import org.gridsuite.study.server.dto.dynamicmapping.MappingInfos; import org.gridsuite.study.server.dto.dynamicmapping.ModelInfos; +import org.gridsuite.study.server.dto.dynamicmargincalculation.DynamicMarginCalculationStatus; import org.gridsuite.study.server.dto.dynamicsecurityanalysis.DynamicSecurityAnalysisStatus; import org.gridsuite.study.server.dto.dynamicsimulation.DynamicSimulationParametersInfos; import org.gridsuite.study.server.dto.dynamicsimulation.DynamicSimulationStatus; @@ -35,13 +32,16 @@ import org.gridsuite.study.server.dto.elasticsearch.EquipmentInfos; import org.gridsuite.study.server.dto.modification.ModificationType; import org.gridsuite.study.server.dto.modification.ModificationsSearchResultByNode; +import org.gridsuite.study.server.dto.modification.NetworkModificationMetadata; import org.gridsuite.study.server.dto.networkexport.ExportNetworkStatus; +import org.gridsuite.study.server.dto.networkexport.NodeExportInfos; import org.gridsuite.study.server.dto.sensianalysis.SensitivityAnalysisCsvFileInfos; import org.gridsuite.study.server.dto.sequence.NodeSequenceType; import org.gridsuite.study.server.dto.timeseries.TimeSeriesMetadataInfos; import org.gridsuite.study.server.dto.timeseries.TimelineEventInfos; import org.gridsuite.study.server.dto.voltageinit.parameters.StudyVoltageInitParameters; import org.gridsuite.study.server.elasticsearch.EquipmentInfosService; +import org.gridsuite.study.server.error.StudyException; import org.gridsuite.study.server.exception.PartialResultException; import org.gridsuite.study.server.networkmodificationtree.dto.*; import org.gridsuite.study.server.service.*; @@ -66,9 +66,9 @@ import java.beans.PropertyEditorSupport; import java.util.*; -import static org.gridsuite.study.server.error.StudyBusinessErrorCode.MOVE_NETWORK_MODIFICATION_FORBIDDEN; import static org.gridsuite.study.server.StudyConstants.*; import static org.gridsuite.study.server.dto.ComputationType.LOAD_FLOW; +import static org.gridsuite.study.server.error.StudyBusinessErrorCode.MOVE_NETWORK_MODIFICATION_FORBIDDEN; /** * @author Abdelsalem Hedhili @@ -1176,6 +1176,23 @@ public ResponseEntity getDynamicSecurityAnalysisProvider(@PathVariable(" return ResponseEntity.ok().body(studyService.getDynamicSecurityAnalysisProvider(studyUuid)); } + @PostMapping(value = "/studies/{studyUuid}/dynamic-margin-calculation/provider") + @Operation(summary = "Set dynamic margin calculation provider for the specified study, no body means reset to default provider") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The dynamic margin calculation provider is set")}) + public ResponseEntity setDynamicMarginCalculationProvider(@PathVariable("studyUuid") UUID studyUuid, + @RequestBody(required = false) String provider, + @RequestHeader(HEADER_USER_ID) String userId) { + studyService.updateDynamicMarginCalculationProvider(studyUuid, provider, userId); + return ResponseEntity.ok().build(); + } + + @GetMapping(value = "/studies/{studyUuid}/dynamic-margin-calculation/provider") + @Operation(summary = "Get dynamic margin calculation provider for a specified study") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The dynamic margin calculation provider is returned")}) + public ResponseEntity getDynamicMarginCalculationProvider(@PathVariable("studyUuid") UUID studyUuid) { + return ResponseEntity.ok().body(studyService.getDynamicMarginCalculationProvider(studyUuid)); + } + @PostMapping(value = "/studies/{studyUuid}/short-circuit-analysis/parameters", consumes = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "set short-circuit analysis parameters on study, reset to default ones if empty body") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The short-circuit analysis parameters are set"), @@ -1740,6 +1757,13 @@ public ResponseEntity getDefaultDynamicSecurityAnalysisProvider(@Request return ResponseEntity.ok().body(studyService.getDefaultDynamicSecurityAnalysisProvider(userId)); } + @GetMapping(value = "/dynamic-margin-calculation-default-provider") + @Operation(summary = "Get dynamic margin calculation default provider") + @ApiResponses(@ApiResponse(responseCode = "200", description = "The dynamic margin calculation default provider has been found")) + public ResponseEntity getDefaultDynamicMarginCalculationProvider(@RequestHeader(HEADER_USER_ID) String userId) { + return ResponseEntity.ok().body(studyService.getDefaultDynamicMarginCalculationProvider(userId)); + } + @PostMapping(value = "/studies/{studyUuid}/root-networks/{rootNetworkUuid}/reindex-all") @Operation(summary = "reindex root network") @ApiResponse(responseCode = "200", description = "Root network reindexed") @@ -2082,6 +2106,59 @@ public ResponseEntity getDynamicSecurityAnalysisStatus(@Parameter(descri // --- Dynamic Security Analysis Endpoints END --- // + // --- Dynamic Margin Calculation Endpoints BEGIN --- // + + @PostMapping(value = "/studies/{studyUuid}/dynamic-margin-calculation/parameters") + @Operation(summary = "Set dynamic margin calculation parameters on study, reset to default one if empty body") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The dynamic margin calculation parameters are set")}) + public ResponseEntity setDynamicMarginCalculationParameters( + @PathVariable("studyUuid") UUID studyUuid, + @RequestBody(required = false) String dmcParameter, + @RequestHeader(HEADER_USER_ID) String userId) { + return studyService.setDynamicMarginCalculationParameters(studyUuid, dmcParameter, userId) ? + ResponseEntity.noContent().build() : + ResponseEntity.ok().build(); + } + + @GetMapping(value = "/studies/{studyUuid}/dynamic-margin-calculation/parameters") + @Operation(summary = "Get dynamic margin calculation parameters on study") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The dynamic margin calculation parameters")}) + public ResponseEntity getDynamicMarginCalculationParameters( + @PathVariable("studyUuid") UUID studyUuid, + @RequestHeader(HEADER_USER_ID) String userId + ) { + return ResponseEntity.ok().body(studyService.getDynamicMarginCalculationParameters(studyUuid, userId)); + } + + @PostMapping(value = "/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/dynamic-margin-calculation/run") + @Operation(summary = "run dynamic margin calculation on study") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The dynamic margin calculation has started")}) + public ResponseEntity runDynamicMarginCalculation(@Parameter(description = "studyUuid") @PathVariable("studyUuid") UUID studyUuid, + @Parameter(description = "root network id") @PathVariable("rootNetworkUuid") UUID rootNetworkUuid, + @Parameter(description = "nodeUuid") @PathVariable("nodeUuid") UUID nodeUuid, + @Parameter(description = "debug") @RequestParam(name = "debug", required = false, defaultValue = "false") boolean debug, + @RequestHeader(HEADER_USER_ID) String userId) throws JsonProcessingException { + studyService.assertIsNodeNotReadOnly(nodeUuid); + studyService.assertCanRunOnConstructionNode(studyUuid, nodeUuid, List.of(DYNAWO_PROVIDER), studyService::getDynamicMarginCalculationProvider); + studyService.runDynamicMarginCalculation(studyUuid, nodeUuid, rootNetworkUuid, userId, debug); + return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).build(); + } + + @GetMapping(value = "/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/dynamic-margin-calculation/status") + @Operation(summary = "Get the status of dynamic margin calculation result on study") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The status of dynamic margin calculation result"), + @ApiResponse(responseCode = "204", description = "No dynamic margin calculation status"), + @ApiResponse(responseCode = "404", description = "The dynamic margin calculation has not been found")}) + public ResponseEntity getDynamicMarginCalculationStatus(@Parameter(description = "study UUID") @PathVariable("studyUuid") UUID studyUuid, + @Parameter(description = "root network id") @PathVariable("rootNetworkUuid") UUID rootNetworkUuid, + @Parameter(description = "nodeUuid") @PathVariable("nodeUuid") UUID nodeUuid) { + DynamicMarginCalculationStatus result = rootNetworkNodeInfoService.getDynamicMarginCalculationStatus(nodeUuid, rootNetworkUuid); + return result != null ? ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(result.name()) : + ResponseEntity.noContent().build(); + } + + // --- Dynamic Margin Calculation Endpoints END --- // + @GetMapping(value = "/studies/{studyUuid}/security-analysis/parameters") @Operation(summary = "Get security analysis parameters on study") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The security analysis parameters")}) diff --git a/src/main/java/org/gridsuite/study/server/dto/ComputationType.java b/src/main/java/org/gridsuite/study/server/dto/ComputationType.java index d39169792c..8cf8562ad7 100644 --- a/src/main/java/org/gridsuite/study/server/dto/ComputationType.java +++ b/src/main/java/org/gridsuite/study/server/dto/ComputationType.java @@ -17,6 +17,9 @@ public enum ComputationType { SHORT_CIRCUIT("Short circuit analysis", "shortCircuitAnalysisResultUuid", NotificationService.UPDATE_TYPE_SHORT_CIRCUIT_STATUS, NotificationService.UPDATE_TYPE_SHORT_CIRCUIT_RESULT, NotificationService.UPDATE_TYPE_SHORT_CIRCUIT_FAILED), + SHORT_CIRCUIT_ONE_BUS("One bus Short circuit analysis", "oneBusShortCircuitAnalysisResultUuid", + NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_STATUS, NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_RESULT, + NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_FAILED), VOLTAGE_INITIALIZATION("Voltage init", "voltageInitResultUuid", NotificationService.UPDATE_TYPE_VOLTAGE_INIT_STATUS, NotificationService.UPDATE_TYPE_VOLTAGE_INIT_RESULT, NotificationService.UPDATE_TYPE_VOLTAGE_INIT_FAILED), @@ -26,9 +29,9 @@ public enum ComputationType { DYNAMIC_SECURITY_ANALYSIS("Dynamic security analysis", "dynamicSecurityAnalysisResultUuid", NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS, NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_RESULT, NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_FAILED), - SHORT_CIRCUIT_ONE_BUS("One bus Short circuit analysis", "oneBusShortCircuitAnalysisResultUuid", - NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_STATUS, NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_RESULT, - NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_FAILED), + DYNAMIC_MARGIN_CALCULATION("Dynamic margin calculation", "dynamicMarginCalculationResultUuid", + NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_STATUS, NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_RESULT, + NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_FAILED), STATE_ESTIMATION("State estimation", "stateEstimationResultUuid", NotificationService.UPDATE_TYPE_STATE_ESTIMATION_STATUS, NotificationService.UPDATE_TYPE_STATE_ESTIMATION_RESULT, NotificationService.UPDATE_TYPE_STATE_ESTIMATION_FAILED), diff --git a/src/main/java/org/gridsuite/study/server/dto/DeleteNodeInfos.java b/src/main/java/org/gridsuite/study/server/dto/DeleteNodeInfos.java index 0a0368a77a..d9a46ca7fa 100644 --- a/src/main/java/org/gridsuite/study/server/dto/DeleteNodeInfos.java +++ b/src/main/java/org/gridsuite/study/server/dto/DeleteNodeInfos.java @@ -44,6 +44,8 @@ public class DeleteNodeInfos { private List dynamicSecurityAnalysisResultUuids = new ArrayList<>(); + private List dynamicMarginCalculationResultUuids = new ArrayList<>(); + private List stateEstimationResultUuids = new ArrayList<>(); private List pccMinResultUuids = new ArrayList<>(); @@ -80,6 +82,10 @@ public void addDynamicSecurityAnalysisResultUuid(UUID dynamicSecurityAnalysisRes dynamicSecurityAnalysisResultUuids.add(dynamicSecurityAnalysisResultUuid); } + public void addDynamicMarginCalculationResultUuid(UUID dynamicMarginCalculationResultUuid) { + dynamicMarginCalculationResultUuids.add(dynamicMarginCalculationResultUuid); + } + public void addSensitivityAnalysisResultUuid(UUID sensitivityAnalysisResultUuid) { sensitivityAnalysisResultUuids.add(sensitivityAnalysisResultUuid); } diff --git a/src/main/java/org/gridsuite/study/server/dto/InvalidateNodeInfos.java b/src/main/java/org/gridsuite/study/server/dto/InvalidateNodeInfos.java index d959ea16d8..ae3c24f609 100644 --- a/src/main/java/org/gridsuite/study/server/dto/InvalidateNodeInfos.java +++ b/src/main/java/org/gridsuite/study/server/dto/InvalidateNodeInfos.java @@ -40,6 +40,7 @@ public class InvalidateNodeInfos { private Set pccMinResultUuids = new HashSet<>(); private Set dynamicSimulationResultUuids = new HashSet<>(); private Set dynamicSecurityAnalysisResultUuids = new HashSet<>(); + private Set dynamicMarginCalculationResultUuids = new HashSet<>(); public List getNodeUuids() { return nodeUuids.stream().toList(); @@ -97,6 +98,10 @@ public List getDynamicSecurityAnalysisResultUuids() { return dynamicSecurityAnalysisResultUuids.stream().toList(); } + public List getDynamicMarginCalculationResultUuids() { + return dynamicMarginCalculationResultUuids.stream().toList(); + } + public void addReportUuid(UUID reportUuid) { reportUuids.add(reportUuid); } @@ -137,6 +142,10 @@ public void addDynamicSecurityAnalysisResultUuid(UUID dynamicSecurityAnalysisRes dynamicSecurityAnalysisResultUuids.add(dynamicSecurityAnalysisResultUuid); } + public void addDynamicMarginCalculationResultUuid(UUID dynamicMarginCalculationResultUuid) { + dynamicMarginCalculationResultUuids.add(dynamicMarginCalculationResultUuid); + } + public void addStateEstimationResultUuid(UUID stateEstimationResultUuid) { stateEstimationResultUuids.add(stateEstimationResultUuid); } @@ -170,5 +179,6 @@ public void add(InvalidateNodeInfos invalidateNodeInfos) { pccMinResultUuids.addAll(invalidateNodeInfos.getPccMinResultUuids()); dynamicSimulationResultUuids.addAll(invalidateNodeInfos.getDynamicSimulationResultUuids()); dynamicSecurityAnalysisResultUuids.addAll(invalidateNodeInfos.getDynamicSecurityAnalysisResultUuids()); + dynamicMarginCalculationResultUuids.addAll(invalidateNodeInfos.getDynamicMarginCalculationResultUuids()); } } diff --git a/src/main/java/org/gridsuite/study/server/dto/RootNetworkNodeInfo.java b/src/main/java/org/gridsuite/study/server/dto/RootNetworkNodeInfo.java index 11896cbd05..b166b231d8 100644 --- a/src/main/java/org/gridsuite/study/server/dto/RootNetworkNodeInfo.java +++ b/src/main/java/org/gridsuite/study/server/dto/RootNetworkNodeInfo.java @@ -50,6 +50,8 @@ public class RootNetworkNodeInfo { private UUID dynamicSecurityAnalysisResultUuid; + private UUID dynamicMarginCalculationResultUuid; + private UUID stateEstimationResultUuid; private UUID pccMinResultUuid; @@ -73,6 +75,7 @@ public RootNetworkNodeInfoEntity toEntity() { .sensitivityAnalysisResultUuid(sensitivityAnalysisResultUuid) .dynamicSimulationResultUuid(dynamicSimulationResultUuid) .dynamicSecurityAnalysisResultUuid(dynamicSecurityAnalysisResultUuid) + .dynamicMarginCalculationResultUuid(dynamicMarginCalculationResultUuid) .stateEstimationResultUuid(stateEstimationResultUuid) .pccMinResultUuid(pccMinResultUuid) .nodeBuildStatus(nodeBuildStatus.toEntity()) diff --git a/src/main/java/org/gridsuite/study/server/dto/UserProfileInfos.java b/src/main/java/org/gridsuite/study/server/dto/UserProfileInfos.java index 29832cacae..a0cd4592d7 100644 --- a/src/main/java/org/gridsuite/study/server/dto/UserProfileInfos.java +++ b/src/main/java/org/gridsuite/study/server/dto/UserProfileInfos.java @@ -37,6 +37,9 @@ public class UserProfileInfos { // note: this parameter is not managed by user-admin-server yet private UUID dynamicSecurityAnalysisParameterId; + // note: this parameter is not managed by user-admin-server yet + private UUID dynamicMarginCalculationParameterId; + private UUID voltageInitParameterId; Integer maxAllowedBuilds; diff --git a/src/main/java/org/gridsuite/study/server/dto/dynamicmargincalculation/DynamicMarginCalculationStatus.java b/src/main/java/org/gridsuite/study/server/dto/dynamicmargincalculation/DynamicMarginCalculationStatus.java new file mode 100644 index 0000000000..64bdd9c694 --- /dev/null +++ b/src/main/java/org/gridsuite/study/server/dto/dynamicmargincalculation/DynamicMarginCalculationStatus.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2026, 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.study.server.dto.dynamicmargincalculation; + +/** + * @author Thang PHAM + */ +public enum DynamicMarginCalculationStatus { + NOT_DONE, + RUNNING, + SUCCEED, + FAILED +} diff --git a/src/main/java/org/gridsuite/study/server/dto/dynamicsecurityanalysis/DynamicSecurityAnalysisParametersInfos.java b/src/main/java/org/gridsuite/study/server/dto/dynamicsecurityanalysis/DynamicSecurityAnalysisParametersInfos.java deleted file mode 100644 index 5fb3a2e34b..0000000000 --- a/src/main/java/org/gridsuite/study/server/dto/dynamicsecurityanalysis/DynamicSecurityAnalysisParametersInfos.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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.study.server.dto.dynamicsecurityanalysis; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import lombok.*; - -import java.util.List; -import java.util.UUID; - -/** - * @author Thang PHAM - */ -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Setter -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class DynamicSecurityAnalysisParametersInfos { - private UUID id; - - private String provider; - - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private Double scenarioDuration; - - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private Double contingenciesStartTime; - - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private List contingencyListIds; - -} diff --git a/src/main/java/org/gridsuite/study/server/networkmodificationtree/dto/NetworkModificationNode.java b/src/main/java/org/gridsuite/study/server/networkmodificationtree/dto/NetworkModificationNode.java index 71209cfa50..6eb494ae15 100644 --- a/src/main/java/org/gridsuite/study/server/networkmodificationtree/dto/NetworkModificationNode.java +++ b/src/main/java/org/gridsuite/study/server/networkmodificationtree/dto/NetworkModificationNode.java @@ -52,6 +52,8 @@ public class NetworkModificationNode extends AbstractNode { private UUID dynamicSecurityAnalysisResultUuid; + private UUID dynamicMarginCalculationResultUuid; + private UUID stateEstimationResultUuid; private UUID pccMinResultUuid; @@ -72,6 +74,7 @@ public void completeDtoFromRootNetworkNodeInfo(RootNetworkNodeInfoEntity rootNet this.setSensitivityAnalysisResultUuid(rootNetworkNodeInfoEntity.getSensitivityAnalysisResultUuid()); this.setDynamicSimulationResultUuid(rootNetworkNodeInfoEntity.getDynamicSimulationResultUuid()); this.setDynamicSecurityAnalysisResultUuid(rootNetworkNodeInfoEntity.getDynamicSecurityAnalysisResultUuid()); + this.setDynamicMarginCalculationResultUuid(rootNetworkNodeInfoEntity.getDynamicMarginCalculationResultUuid()); this.setStateEstimationResultUuid(rootNetworkNodeInfoEntity.getStateEstimationResultUuid()); this.setPccMinResultUuid(rootNetworkNodeInfoEntity.getPccMinResultUuid()); this.setNodeBuildStatus(rootNetworkNodeInfoEntity.getNodeBuildStatus().toDto()); diff --git a/src/main/java/org/gridsuite/study/server/networkmodificationtree/entities/RootNetworkNodeInfoEntity.java b/src/main/java/org/gridsuite/study/server/networkmodificationtree/entities/RootNetworkNodeInfoEntity.java index 92062ad5a0..9a02f100c5 100644 --- a/src/main/java/org/gridsuite/study/server/networkmodificationtree/entities/RootNetworkNodeInfoEntity.java +++ b/src/main/java/org/gridsuite/study/server/networkmodificationtree/entities/RootNetworkNodeInfoEntity.java @@ -96,6 +96,9 @@ public class RootNetworkNodeInfoEntity { @Column(name = "dynamicSecurityAnalysisResultUuid") private UUID dynamicSecurityAnalysisResultUuid; + @Column(name = "dynamicMarginCalculationResultUuid") + private UUID dynamicMarginCalculationResultUuid; + @Column(name = "stateEstimationResultUuid") private UUID stateEstimationResultUuid; @@ -126,6 +129,7 @@ public RootNetworkNodeInfo toDto() { .modificationReports(modificationReports) .dynamicSimulationResultUuid(dynamicSimulationResultUuid) .dynamicSecurityAnalysisResultUuid(dynamicSecurityAnalysisResultUuid) + .dynamicMarginCalculationResultUuid(dynamicMarginCalculationResultUuid) .loadFlowResultUuid(loadFlowResultUuid) .loadFlowWithRatioTapChangers(loadFlowWithRatioTapChangers) .nodeBuildStatus(nodeBuildStatus.toDto()) diff --git a/src/main/java/org/gridsuite/study/server/notification/NotificationService.java b/src/main/java/org/gridsuite/study/server/notification/NotificationService.java index 183c0af937..4e32c7abd1 100644 --- a/src/main/java/org/gridsuite/study/server/notification/NotificationService.java +++ b/src/main/java/org/gridsuite/study/server/notification/NotificationService.java @@ -80,6 +80,9 @@ public class NotificationService { public static final String UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_FAILED = "dynamicSecurityAnalysis_failed"; public static final String UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_RESULT = "dynamicSecurityAnalysisResult"; public static final String UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS = "dynamicSecurityAnalysis_status"; + public static final String UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_FAILED = "dynamicMarginCalculation_failed"; + public static final String UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_RESULT = "dynamicMarginCalculationResult"; + public static final String UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_STATUS = "dynamicMarginCalculation_status"; public static final String UPDATE_TYPE_VOLTAGE_INIT_RESULT = "voltageInitResult"; public static final String UPDATE_TYPE_VOLTAGE_INIT_STATUS = "voltageInit_status"; public static final String UPDATE_TYPE_VOLTAGE_INIT_FAILED = "voltageInit_failed"; diff --git a/src/main/java/org/gridsuite/study/server/repository/StudyEntity.java b/src/main/java/org/gridsuite/study/server/repository/StudyEntity.java index 357326ba4f..3e5a40c1b4 100644 --- a/src/main/java/org/gridsuite/study/server/repository/StudyEntity.java +++ b/src/main/java/org/gridsuite/study/server/repository/StudyEntity.java @@ -83,6 +83,9 @@ public class StudyEntity extends AbstractManuallyAssignedIdentifierEntity @Column(name = "dynamicSecurityAnalysisParametersUuid") private UUID dynamicSecurityAnalysisParametersUuid; + @Column(name = "dynamicMarginCalculationParametersUuid") + private UUID dynamicMarginCalculationParametersUuid; + @Column(name = "voltageInitParametersUuid") private UUID voltageInitParametersUuid; diff --git a/src/main/java/org/gridsuite/study/server/repository/rootnetwork/RootNetworkNodeInfoRepository.java b/src/main/java/org/gridsuite/study/server/repository/rootnetwork/RootNetworkNodeInfoRepository.java index 61919ef07b..3a03c19b5c 100644 --- a/src/main/java/org/gridsuite/study/server/repository/rootnetwork/RootNetworkNodeInfoRepository.java +++ b/src/main/java/org/gridsuite/study/server/repository/rootnetwork/RootNetworkNodeInfoRepository.java @@ -28,6 +28,8 @@ public interface RootNetworkNodeInfoRepository extends JpaRepository findAllByDynamicSecurityAnalysisResultUuidNotNull(); + List findAllByDynamicMarginCalculationResultUuidNotNull(); + List findAllBySecurityAnalysisResultUuidNotNull(); List findAllBySensitivityAnalysisResultUuidNotNull(); diff --git a/src/main/java/org/gridsuite/study/server/service/ConsumerService.java b/src/main/java/org/gridsuite/study/server/service/ConsumerService.java index 197b1ec851..17260c0078 100644 --- a/src/main/java/org/gridsuite/study/server/service/ConsumerService.java +++ b/src/main/java/org/gridsuite/study/server/service/ConsumerService.java @@ -25,6 +25,7 @@ import org.gridsuite.study.server.networkmodificationtree.dto.NodeBuildStatus; import org.gridsuite.study.server.dto.networkexport.NodeExportInfos; import org.gridsuite.study.server.notification.NotificationService; +import org.gridsuite.study.server.service.dynamicmargincalculation.DynamicMarginCalculationService; import org.gridsuite.study.server.service.dynamicsecurityanalysis.DynamicSecurityAnalysisService; import org.gridsuite.study.server.service.dynamicsimulation.DynamicSimulationService; import org.gridsuite.study.server.service.shortcircuit.ShortCircuitService; @@ -74,6 +75,7 @@ public class ConsumerService { private final RootNetworkNodeInfoService rootNetworkNodeInfoService; private final VoltageInitService voltageInitService; private final DynamicSecurityAnalysisService dynamicSecurityAnalysisService; + private final DynamicMarginCalculationService dynamicMarginCalculationService; private final StateEstimationService stateEstimationService; private final PccMinService pccMinService; private final DirectoryService directoryService; @@ -91,7 +93,9 @@ public ConsumerService(ObjectMapper objectMapper, RootNetworkNodeInfoService rootNetworkNodeInfoService, VoltageInitService voltageInitService, DynamicSecurityAnalysisService dynamicSecurityAnalysisService, - StateEstimationService stateEstimationService, PccMinService pccMinService, + DynamicMarginCalculationService dynamicMarginCalculationService, + StateEstimationService stateEstimationService, + PccMinService pccMinService, DirectoryService directoryService) { this.objectMapper = objectMapper; this.notificationService = notificationService; @@ -106,6 +110,7 @@ public ConsumerService(ObjectMapper objectMapper, this.rootNetworkNodeInfoService = rootNetworkNodeInfoService; this.voltageInitService = voltageInitService; this.dynamicSecurityAnalysisService = dynamicSecurityAnalysisService; + this.dynamicMarginCalculationService = dynamicMarginCalculationService; this.stateEstimationService = stateEstimationService; this.pccMinService = pccMinService; this.directoryService = directoryService; @@ -296,6 +301,7 @@ private void insertStudy(UUID studyUuid, String userId, NetworkInfos networkInfo UUID networkVisualizationParametersUuid = createDefaultNetworkVisualizationParameters(userId, userProfileInfos); UUID voltageInitParametersUuid = createDefaultVoltageInitParameters(userId, userProfileInfos); UUID dynamicSecurityAnalysisParametersUuid = createDefaultDynamicSecurityAnalysisParameters(userId, userProfileInfos); + UUID dynamicMarginCalculationParametersUuid = createDefaultDynamicMarginCalculationParameters(userId, userProfileInfos); UUID stateEstimationParametersUuid = createDefaultStateEstimationParameters(); UUID pccMinParametersUuid = createDefaultPccMinParameters(userId, userProfileInfos); UUID spreadsheetConfigCollectionUuid = createDefaultSpreadsheetConfigCollection(userId, userProfileInfos); @@ -304,7 +310,8 @@ private void insertStudy(UUID studyUuid, String userId, NetworkInfos networkInfo studyService.insertStudy(studyUuid, userId, networkInfos, caseInfos, loadFlowParametersUuid, shortCircuitParametersUuid, DynamicSimulationService.toEntity(dynamicSimulationParameters, objectMapper), voltageInitParametersUuid, securityAnalysisParametersUuid, sensitivityAnalysisParametersUuid, - networkVisualizationParametersUuid, dynamicSecurityAnalysisParametersUuid, stateEstimationParametersUuid, pccMinParametersUuid, spreadsheetConfigCollectionUuid, workspacesConfigUuid, + networkVisualizationParametersUuid, dynamicSecurityAnalysisParametersUuid, dynamicMarginCalculationParametersUuid, + stateEstimationParametersUuid, pccMinParametersUuid, spreadsheetConfigCollectionUuid, workspacesConfigUuid, importParameters, importReportUuid); } @@ -448,6 +455,26 @@ private UUID createDefaultDynamicSecurityAnalysisParameters(String userId, UserP } } + private UUID createDefaultDynamicMarginCalculationParameters(String userId, UserProfileInfos userProfileInfos) { + if (userProfileInfos != null && userProfileInfos.getDynamicMarginCalculationParameterId() != null) { + // try to access/duplicate the user profile Dynamic Margin Calculation parameters + try { + return dynamicMarginCalculationService.duplicateParameters(userProfileInfos.getDynamicMarginCalculationParameterId()); + } catch (Exception e) { + // TODO try to report a log in Root subreporter ? + LOGGER.error(String.format("Could not duplicate dynamic margin calculation parameters with id '%s' from user/profile '%s/%s'. Using default parameters", + userProfileInfos.getDynamicMarginCalculationParameterId(), userId, userProfileInfos.getName()), e); + } + } + // no profile, or no/bad dynamic margin calculation parameters in profile => use default values + try { + return dynamicMarginCalculationService.createDefaultParameters(); + } catch (final Exception e) { + LOGGER.error("Error while creating default parameters for dynamic margin calculation", e); + return null; + } + } + private UUID createDefaultStateEstimationParameters() { try { return stateEstimationService.createDefaultStateEstimationParameters(); @@ -554,12 +581,9 @@ public void consumeCalculationFailed(Message msg, ComputationType comput String userId = msg.getHeaders().get(HEADER_USER_ID, String.class); UUID resultUuid = null; - var computationsToReset = List.of(DYNAMIC_SIMULATION, DYNAMIC_SECURITY_ANALYSIS); - if (!computationsToReset.contains(computationType)) { - String resultId = msg.getHeaders().get(RESULT_UUID, String.class); - if (resultId != null) { - resultUuid = UUID.fromString(resultId); - } + String resultId = msg.getHeaders().get(RESULT_UUID, String.class); + if (resultId != null) { + resultUuid = UUID.fromString(resultId); } if (!Strings.isBlank(receiver)) { NodeReceiver receiverObj = null; @@ -754,6 +778,26 @@ public Consumer> consumeDsaFailed() { return message -> consumeCalculationFailed(message, DYNAMIC_SECURITY_ANALYSIS); } + @Bean + public Consumer> consumeDmcDebug() { + return message -> consumeCalculationDebug(message, DYNAMIC_MARGIN_CALCULATION); + } + + @Bean + public Consumer> consumeDmcResult() { + return message -> consumeCalculationResult(message, DYNAMIC_MARGIN_CALCULATION); + } + + @Bean + public Consumer> consumeDmcStopped() { + return message -> consumeCalculationStopped(message, DYNAMIC_MARGIN_CALCULATION); + } + + @Bean + public Consumer> consumeDmcFailed() { + return message -> consumeCalculationFailed(message, DYNAMIC_MARGIN_CALCULATION); + } + @Bean public Consumer> consumeSaResult() { return message -> consumeCalculationResult(message, SECURITY_ANALYSIS); diff --git a/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java b/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java index ab4397dd38..43d1927015 100644 --- a/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java +++ b/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java @@ -11,6 +11,7 @@ import org.apache.commons.lang3.StringUtils; import org.gridsuite.study.server.dto.*; import org.gridsuite.study.server.dto.computation.LoadFlowComputationInfos; +import org.gridsuite.study.server.dto.dynamicmargincalculation.DynamicMarginCalculationStatus; import org.gridsuite.study.server.dto.dynamicsecurityanalysis.DynamicSecurityAnalysisStatus; import org.gridsuite.study.server.dto.dynamicsimulation.DynamicSimulationStatus; import org.gridsuite.study.server.dto.modification.ModificationApplicationContext; @@ -27,6 +28,7 @@ import org.gridsuite.study.server.repository.networkmodificationtree.NetworkModificationNodeInfoRepository; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkEntity; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkNodeInfoRepository; +import org.gridsuite.study.server.service.dynamicmargincalculation.DynamicMarginCalculationService; import org.gridsuite.study.server.service.dynamicsecurityanalysis.DynamicSecurityAnalysisService; import org.gridsuite.study.server.service.dynamicsimulation.DynamicSimulationService; import org.gridsuite.study.server.service.securityanalysis.SecurityAnalysisResultType; @@ -64,6 +66,7 @@ public class RootNetworkNodeInfoService { private final VoltageInitService voltageInitService; private final DynamicSimulationService dynamicSimulationService; private final DynamicSecurityAnalysisService dynamicSecurityAnalysisService; + private final DynamicMarginCalculationService dynamicMarginCalculationService; private final StateEstimationService stateEstimationService; private final PccMinService pccMinService; private final ReportService reportService; @@ -78,6 +81,7 @@ public RootNetworkNodeInfoService(RootNetworkNodeInfoRepository rootNetworkNodeI VoltageInitService voltageInitService, DynamicSimulationService dynamicSimulationService, DynamicSecurityAnalysisService dynamicSecurityAnalysisService, + DynamicMarginCalculationService dynamicMarginCalculationService, StateEstimationService stateEstimationService, PccMinService pccMinService, ReportService reportService) { @@ -91,6 +95,7 @@ public RootNetworkNodeInfoService(RootNetworkNodeInfoRepository rootNetworkNodeI this.voltageInitService = voltageInitService; this.dynamicSimulationService = dynamicSimulationService; this.dynamicSecurityAnalysisService = dynamicSecurityAnalysisService; + this.dynamicMarginCalculationService = dynamicMarginCalculationService; this.stateEstimationService = stateEstimationService; this.pccMinService = pccMinService; this.reportService = reportService; @@ -160,6 +165,7 @@ public void updateComputationResultUuid(UUID nodeUuid, UUID rootNetworkUuid, UUI case VOLTAGE_INITIALIZATION -> rootNetworkNodeInfoEntity.setVoltageInitResultUuid(computationResultUuid); case DYNAMIC_SIMULATION -> rootNetworkNodeInfoEntity.setDynamicSimulationResultUuid(computationResultUuid); case DYNAMIC_SECURITY_ANALYSIS -> rootNetworkNodeInfoEntity.setDynamicSecurityAnalysisResultUuid(computationResultUuid); + case DYNAMIC_MARGIN_CALCULATION -> rootNetworkNodeInfoEntity.setDynamicMarginCalculationResultUuid(computationResultUuid); case STATE_ESTIMATION -> rootNetworkNodeInfoEntity.setStateEstimationResultUuid(computationResultUuid); case PCC_MIN -> rootNetworkNodeInfoEntity.setPccMinResultUuid(computationResultUuid); } @@ -170,7 +176,7 @@ public List getAllWithRootNetworkByNodeInfoId(UUID no } public void fillDeleteNodeInfo(UUID nodeUuid, DeleteNodeInfos deleteNodeInfos) { - //get all rootnetworknodeinfo info linked to node + //get all rootNetworkNodeInfo info linked to node List rootNetworkNodeInfoEntities = rootNetworkNodeInfoRepository.findAllWithRootNetworkByNodeInfoId(nodeUuid); rootNetworkNodeInfoEntities.forEach(rootNetworkNodeInfoEntity -> { rootNetworkNodeInfoEntity.getModificationReports().forEach((key, value) -> deleteNodeInfos.addReportUuid(value)); @@ -222,6 +228,11 @@ public void fillDeleteNodeInfo(UUID nodeUuid, DeleteNodeInfos deleteNodeInfos) { deleteNodeInfos.addDynamicSecurityAnalysisResultUuid(dynamicSecurityAnalysisResultUuid); } + UUID dynamicMarginCalculationResultUuid = getComputationResultUuid(rootNetworkNodeInfoEntity, DYNAMIC_MARGIN_CALCULATION); + if (dynamicMarginCalculationResultUuid != null) { + deleteNodeInfos.addDynamicMarginCalculationResultUuid(dynamicMarginCalculationResultUuid); + } + UUID stateEstimationResultUuid = getComputationResultUuid(rootNetworkNodeInfoEntity, STATE_ESTIMATION); if (stateEstimationResultUuid != null) { deleteNodeInfos.addStateEstimationResultUuid(stateEstimationResultUuid); @@ -337,7 +348,7 @@ private Set filterForExclusivelyOwnedReports( .collect(Collectors.toSet()); } - private static void invalidateBuildStatus(RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity, InvalidateNodeInfos invalidateNodeInfos) { + private void invalidateBuildStatus(RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity, InvalidateNodeInfos invalidateNodeInfos) { rootNetworkNodeInfoEntity.setNodeBuildStatus(NodeBuildStatusEmbeddable.from(BuildStatus.NOT_BUILT)); rootNetworkNodeInfoEntity.setVariantId(UUID.randomUUID().toString()); rootNetworkNodeInfoEntity.setModificationReports(new HashMap<>()); @@ -345,7 +356,7 @@ private static void invalidateBuildStatus(RootNetworkNodeInfoEntity rootNetworkN invalidateNodeInfos.addNodeUuid(rootNetworkNodeInfoEntity.getNodeInfo().getIdNode()); } - private static void invalidateComputationResults(RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity, ComputationsInvalidationMode computationsInvalidationMode) { + private void invalidateComputationResults(RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity, ComputationsInvalidationMode computationsInvalidationMode) { if (!ComputationsInvalidationMode.isPreserveLoadFlowResults(computationsInvalidationMode)) { rootNetworkNodeInfoEntity.setLoadFlowResultUuid(null); rootNetworkNodeInfoEntity.setLoadFlowWithRatioTapChangers(null); @@ -356,6 +367,7 @@ private static void invalidateComputationResults(RootNetworkNodeInfoEntity rootN rootNetworkNodeInfoEntity.setOneBusShortCircuitAnalysisResultUuid(null); rootNetworkNodeInfoEntity.setDynamicSimulationResultUuid(null); rootNetworkNodeInfoEntity.setDynamicSecurityAnalysisResultUuid(null); + rootNetworkNodeInfoEntity.setDynamicMarginCalculationResultUuid(null); if (!ComputationsInvalidationMode.isPreserveVoltageInitResults(computationsInvalidationMode)) { rootNetworkNodeInfoEntity.setVoltageInitResultUuid(null); } @@ -412,6 +424,8 @@ private void fillComputationResultUuids(RootNetworkNodeInfoEntity rootNetworkNod .ifPresent(invalidateNodeInfos::addDynamicSimulationResultUuid); Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfoEntity, DYNAMIC_SECURITY_ANALYSIS)) .ifPresent(invalidateNodeInfos::addDynamicSecurityAnalysisResultUuid); + Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfoEntity, DYNAMIC_MARGIN_CALCULATION)) + .ifPresent(invalidateNodeInfos::addDynamicMarginCalculationResultUuid); Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfoEntity, STATE_ESTIMATION)) .ifPresent(invalidateNodeInfos::addStateEstimationResultUuid); Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfoEntity, PCC_MIN)) @@ -433,6 +447,7 @@ private static UUID getComputationResultUuid(RootNetworkNodeInfoEntity rootNetwo case VOLTAGE_INITIALIZATION -> rootNetworkNodeInfoEntity.getVoltageInitResultUuid(); case DYNAMIC_SIMULATION -> rootNetworkNodeInfoEntity.getDynamicSimulationResultUuid(); case DYNAMIC_SECURITY_ANALYSIS -> rootNetworkNodeInfoEntity.getDynamicSecurityAnalysisResultUuid(); + case DYNAMIC_MARGIN_CALCULATION -> rootNetworkNodeInfoEntity.getDynamicMarginCalculationResultUuid(); case STATE_ESTIMATION -> rootNetworkNodeInfoEntity.getStateEstimationResultUuid(); case PCC_MIN -> rootNetworkNodeInfoEntity.getPccMinResultUuid(); }; @@ -555,6 +570,9 @@ public void updateRootNetworkNode(UUID nodeUuid, UUID rootNetworkUuid, RootNetwo if (rootNetworkNodeInfo.getDynamicSecurityAnalysisResultUuid() != null) { rootNetworkNodeInfoEntity.setDynamicSecurityAnalysisResultUuid(rootNetworkNodeInfo.getDynamicSecurityAnalysisResultUuid()); } + if (rootNetworkNodeInfo.getDynamicMarginCalculationResultUuid() != null) { + rootNetworkNodeInfoEntity.setDynamicMarginCalculationResultUuid(rootNetworkNodeInfo.getDynamicMarginCalculationResultUuid()); + } if (rootNetworkNodeInfo.getVoltageInitResultUuid() != null) { rootNetworkNodeInfoEntity.setVoltageInitResultUuid(rootNetworkNodeInfo.getVoltageInitResultUuid()); } @@ -575,6 +593,7 @@ public void deleteRootNetworkNodeRemoteInfos(List rootNetwo studyServerExecutionService.runAsync(() -> voltageInitService.deleteVoltageInitResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getVoltageInitResultUuid).filter(Objects::nonNull).toList())), studyServerExecutionService.runAsync(() -> dynamicSimulationService.deleteResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getDynamicSimulationResultUuid).filter(Objects::nonNull).toList())), studyServerExecutionService.runAsync(() -> dynamicSecurityAnalysisService.deleteResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getDynamicSecurityAnalysisResultUuid).filter(Objects::nonNull).toList())), + studyServerExecutionService.runAsync(() -> dynamicMarginCalculationService.deleteResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getDynamicMarginCalculationResultUuid).filter(Objects::nonNull).toList())), studyServerExecutionService.runAsync(() -> stateEstimationService.deleteStateEstimationResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getStateEstimationResultUuid).filter(Objects::nonNull).toList())), studyServerExecutionService.runAsync(() -> pccMinService.deletePccMinResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getPccMinResultUuid).filter(Objects::nonNull).toList())) ); @@ -601,6 +620,7 @@ public void assertComputationNotRunning(UUID nodeUuid, UUID rootNetworkUuid) { securityAnalysisService.assertSecurityAnalysisNotRunning(getComputationResultUuid(nodeUuid, rootNetworkUuid, SECURITY_ANALYSIS)); dynamicSimulationService.assertDynamicSimulationNotRunning(getComputationResultUuid(nodeUuid, rootNetworkUuid, DYNAMIC_SIMULATION)); dynamicSecurityAnalysisService.assertDynamicSecurityAnalysisNotRunning(getComputationResultUuid(nodeUuid, rootNetworkUuid, DYNAMIC_SECURITY_ANALYSIS)); + dynamicMarginCalculationService.assertDynamicMarginCalculationNotRunning(getComputationResultUuid(nodeUuid, rootNetworkUuid, DYNAMIC_MARGIN_CALCULATION)); sensitivityAnalysisService.assertSensitivityAnalysisNotRunning(getComputationResultUuid(nodeUuid, rootNetworkUuid, SENSITIVITY_ANALYSIS)); shortCircuitService.assertShortCircuitAnalysisNotRunning(getComputationResultUuid(nodeUuid, rootNetworkUuid, SHORT_CIRCUIT), getComputationResultUuid(nodeUuid, rootNetworkUuid, SHORT_CIRCUIT_ONE_BUS)); voltageInitService.assertVoltageInitNotRunning(getComputationResultUuid(nodeUuid, rootNetworkUuid, VOLTAGE_INITIALIZATION)); @@ -790,6 +810,12 @@ public DynamicSecurityAnalysisStatus getDynamicSecurityAnalysisStatus(UUID nodeU return dynamicSecurityAnalysisService.getStatus(resultUuid); } + @Transactional(readOnly = true) + public DynamicMarginCalculationStatus getDynamicMarginCalculationStatus(UUID nodeUuid, UUID rootNetworkUuid) { + UUID resultUuid = getComputationResultUuid(nodeUuid, rootNetworkUuid, DYNAMIC_MARGIN_CALCULATION); + return dynamicMarginCalculationService.getStatus(resultUuid); + } + public String getSensitivityAnalysisStatus(UUID nodeUuid, UUID rootNetworkUuid) { UUID resultUuid = getComputationResultUuid(nodeUuid, rootNetworkUuid, SENSITIVITY_ANALYSIS); return sensitivityAnalysisService.getSensitivityAnalysisStatus(resultUuid); diff --git a/src/main/java/org/gridsuite/study/server/service/StudyService.java b/src/main/java/org/gridsuite/study/server/service/StudyService.java index 6e254dfb6f..5f150189fb 100644 --- a/src/main/java/org/gridsuite/study/server/service/StudyService.java +++ b/src/main/java/org/gridsuite/study/server/service/StudyService.java @@ -41,13 +41,17 @@ import org.gridsuite.study.server.elasticsearch.StudyInfosService; import org.gridsuite.study.server.error.StudyException; import org.gridsuite.study.server.networkmodificationtree.dto.*; -import org.gridsuite.study.server.networkmodificationtree.entities.*; +import org.gridsuite.study.server.networkmodificationtree.entities.NetworkModificationNodeInfoEntity; +import org.gridsuite.study.server.networkmodificationtree.entities.NodeEntity; +import org.gridsuite.study.server.networkmodificationtree.entities.NodeType; +import org.gridsuite.study.server.networkmodificationtree.entities.RootNetworkNodeInfoEntity; import org.gridsuite.study.server.notification.NotificationService; import org.gridsuite.study.server.notification.dto.NetworkImpactsInfos; import org.gridsuite.study.server.repository.*; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkEntity; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkRequestEntity; import org.gridsuite.study.server.repository.voltageinit.StudyVoltageInitParametersEntity; +import org.gridsuite.study.server.service.dynamicmargincalculation.DynamicMarginCalculationService; import org.gridsuite.study.server.service.dynamicsecurityanalysis.DynamicSecurityAnalysisService; import org.gridsuite.study.server.service.dynamicsimulation.DynamicSimulationEventService; import org.gridsuite.study.server.service.dynamicsimulation.DynamicSimulationService; @@ -123,6 +127,7 @@ public class StudyService { private final SecurityAnalysisService securityAnalysisService; private final DynamicSimulationService dynamicSimulationService; private final DynamicSecurityAnalysisService dynamicSecurityAnalysisService; + private final DynamicMarginCalculationService dynamicMarginCalculationService; private final SensitivityAnalysisService sensitivityAnalysisService; private final DynamicSimulationEventService dynamicSimulationEventService; private final StudyConfigService studyConfigService; @@ -147,6 +152,7 @@ public enum ReportType { SENSITIVITY_ANALYSIS("SensitivityAnalysis"), DYNAMIC_SIMULATION("DynamicSimulation"), DYNAMIC_SECURITY_ANALYSIS("DynamicSecurityAnalysis"), + DYNAMIC_MARGIN_CALCULATION("DynamicMarginCalculation"), VOLTAGE_INITIALIZATION("VoltageInit"), STATE_ESTIMATION("StateEstimation"), PCC_MIN("PccMin"); @@ -187,6 +193,7 @@ public StudyService( SensitivityAnalysisService sensitivityAnalysisService, DynamicSimulationService dynamicSimulationService, DynamicSecurityAnalysisService dynamicSecurityAnalysisService, + DynamicMarginCalculationService dynamicMarginCalculationService, VoltageInitService voltageInitService, DynamicSimulationEventService dynamicSimulationEventService, StudyConfigService studyConfigService, @@ -223,6 +230,7 @@ public StudyService( this.caseService = caseService; this.dynamicSimulationService = dynamicSimulationService; this.dynamicSecurityAnalysisService = dynamicSecurityAnalysisService; + this.dynamicMarginCalculationService = dynamicMarginCalculationService; this.voltageInitService = voltageInitService; this.dynamicSimulationEventService = dynamicSimulationEventService; this.studyConfigService = studyConfigService; @@ -538,6 +546,7 @@ private Optional doDeleteStudyIfNotCreationInProgress(UUID stu removeVoltageInitParameters(s.getVoltageInitParametersUuid()); removeSensitivityAnalysisParameters(s.getSensitivityAnalysisParametersUuid()); removeDynamicSecurityAnalysisParameters(s.getDynamicSecurityAnalysisParametersUuid()); + removeDynamicMarginCalculationParameters(s.getDynamicMarginCalculationParametersUuid()); removeNetworkVisualizationParameters(s.getNetworkVisualizationParametersUuid()); removeStateEstimationParameters(s.getStateEstimationParametersUuid()); removePccMinParameters(s.getPccMinParametersUuid()); @@ -610,7 +619,8 @@ public void deleteStudyIfNotCreationInProgress(UUID studyUuid) { public CreatedStudyBasicInfos insertStudy(UUID studyUuid, String userId, NetworkInfos networkInfos, CaseInfos caseInfos, UUID loadFlowParametersUuid, UUID shortCircuitParametersUuid, DynamicSimulationParametersEntity dynamicSimulationParametersEntity, UUID voltageInitParametersUuid, UUID securityAnalysisParametersUuid, UUID sensitivityAnalysisParametersUuid, - UUID networkVisualizationParametersUuid, UUID dynamicSecurityAnalysisParametersUuid, UUID stateEstimationParametersUuid, UUID pccMinParametersUuid, + UUID networkVisualizationParametersUuid, UUID dynamicSecurityAnalysisParametersUuid, UUID dynamicMarginCalculationParametersUuid, + UUID stateEstimationParametersUuid, UUID pccMinParametersUuid, UUID spreadsheetConfigCollectionUuid, UUID workspacesConfigUuid, Map importParameters, UUID importReportUuid) { Objects.requireNonNull(studyUuid); Objects.requireNonNull(userId); @@ -624,7 +634,7 @@ public CreatedStudyBasicInfos insertStudy(UUID studyUuid, String userId, Network caseInfos, loadFlowParametersUuid, shortCircuitParametersUuid, dynamicSimulationParametersEntity, voltageInitParametersUuid, securityAnalysisParametersUuid, - sensitivityAnalysisParametersUuid, networkVisualizationParametersUuid, dynamicSecurityAnalysisParametersUuid, + sensitivityAnalysisParametersUuid, networkVisualizationParametersUuid, dynamicSecurityAnalysisParametersUuid, dynamicMarginCalculationParametersUuid, stateEstimationParametersUuid, pccMinParametersUuid, spreadsheetConfigCollectionUuid, workspacesConfigUuid, importParameters, importReportUuid); // Need to deal with the study creation (with a default root network ?) @@ -1223,11 +1233,13 @@ public boolean setLoadFlowParameters(UUID studyUuid, String parameters, String u invalidateSensitivityAnalysisStatusOnAllNodes(studyUuid); invalidateDynamicSimulationStatusOnAllNodes(studyUuid); invalidateDynamicSecurityAnalysisStatusOnAllNodes(studyUuid); + invalidateDynamicMarginCalculationStatusOnAllNodes(studyUuid); notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_SECURITY_ANALYSIS_STATUS); notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_SENSITIVITY_ANALYSIS_STATUS); notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_DYNAMIC_SIMULATION_STATUS); notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS); + notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_STATUS); notificationService.emitElementUpdated(studyUuid, userId); notificationService.emitComputationParamsChanged(studyUuid, LOAD_FLOW); return userProfileIssue; @@ -1310,7 +1322,7 @@ public String getDefaultDynamicSecurityAnalysisProvider(String userId) { return dynamicSecurityAnalysisService.getProvider(userProfileInfos.getDynamicSecurityAnalysisParameterId()); } catch (Exception e) { LOGGER.error(String.format("Could not get dynamic security analysis provider with id '%s' from user/profile '%s/%s'. Using default provider", - userProfileInfos.getLoadFlowParameterId(), userId, userProfileInfos.getName()), e); + userProfileInfos.getDynamicSecurityAnalysisParameterId(), userId, userProfileInfos.getName()), e); // in case of read error (ex: wrong/dangling uuid in the profile), move on with default provider below } } @@ -1333,6 +1345,37 @@ public void updateDynamicSecurityAnalysisProvider(UUID studyUuid, String provide }); } + public String getDefaultDynamicMarginCalculationProvider(String userId) { + if (userId != null) { + UserProfileInfos userProfileInfos = userAdminService.getUserProfile(userId); + if (userProfileInfos.getDynamicMarginCalculationParameterId() != null) { + try { + return dynamicMarginCalculationService.getProvider(userProfileInfos.getDynamicMarginCalculationParameterId()); + } catch (Exception e) { + LOGGER.error(String.format("Could not get dynamic margin calculation provider with id '%s' from user/profile '%s/%s'. Using default provider", + userProfileInfos.getDynamicMarginCalculationParameterId(), userId, userProfileInfos.getName()), e); + // in case of read error (ex: wrong/dangling uuid in the profile), move on with default provider below + } + } + } + return dynamicMarginCalculationService.getDefaultProvider(); + } + + public String getDynamicMarginCalculationProvider(UUID studyUuid) { + StudyEntity studyEntity = getStudy(studyUuid); + return dynamicMarginCalculationService.getProvider(studyEntity.getDynamicMarginCalculationParametersUuid()); + } + + public void updateDynamicMarginCalculationProvider(UUID studyUuid, String provider, String userId) { + updateProvider(studyUuid, userId, studyEntity -> { + dynamicMarginCalculationService.updateProvider(studyEntity.getDynamicMarginCalculationParametersUuid(), provider); + invalidateDynamicMarginCalculationStatusOnAllNodes(studyUuid); + notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_STATUS); + notificationService.emitComputationParamsChanged(studyUuid, DYNAMIC_MARGIN_CALCULATION); + + }); + } + @Transactional public String getShortCircuitParametersInfo(UUID studyUuid) { StudyEntity studyEntity = getStudy(studyUuid); @@ -1528,6 +1571,10 @@ public void invalidateDynamicSecurityAnalysisStatusOnAllNodes(UUID studyUuid) { dynamicSecurityAnalysisService.invalidateStatus(rootNetworkNodeInfoService.getComputationResultUuids(studyUuid, DYNAMIC_SECURITY_ANALYSIS)); } + public void invalidateDynamicMarginCalculationStatusOnAllNodes(UUID studyUuid) { + dynamicMarginCalculationService.invalidateStatus(rootNetworkNodeInfoService.getComputationResultUuids(studyUuid, DYNAMIC_MARGIN_CALCULATION)); + } + public void invalidateAllStudyLoadFlowStatus(UUID studyUuid) { invalidateSecurityNodeTreeWithLoadFlowResults(studyUuid); invalidateLoadFlowStatusOnAllNodes(studyUuid); @@ -1583,7 +1630,8 @@ private StudyEntity saveStudyThenCreateBasicTree(UUID studyUuid, NetworkInfos ne CaseInfos caseInfos, UUID loadFlowParametersUuid, UUID shortCircuitParametersUuid, DynamicSimulationParametersEntity dynamicSimulationParametersEntity, UUID voltageInitParametersUuid, UUID securityAnalysisParametersUuid, UUID sensitivityAnalysisParametersUuid, - UUID networkVisualizationParametersUuid, UUID dynamicSecurityAnalysisParametersUuid, UUID stateEstimationParametersUuid, UUID pccMinParametersUuid, + UUID networkVisualizationParametersUuid, UUID dynamicSecurityAnalysisParametersUuid, UUID dynamicMarginCalculationParametersUuid, + UUID stateEstimationParametersUuid, UUID pccMinParametersUuid, UUID spreadsheetConfigCollectionUuid, UUID workspacesConfigUuid, Map importParameters, UUID importReportUuid) { StudyEntity studyEntity = StudyEntity.builder() @@ -1598,6 +1646,7 @@ private StudyEntity saveStudyThenCreateBasicTree(UUID studyUuid, NetworkInfos ne .voltageInitParameters(new StudyVoltageInitParametersEntity()) .networkVisualizationParametersUuid(networkVisualizationParametersUuid) .dynamicSecurityAnalysisParametersUuid(dynamicSecurityAnalysisParametersUuid) + .dynamicMarginCalculationParametersUuid(dynamicMarginCalculationParametersUuid) .stateEstimationParametersUuid(stateEstimationParametersUuid) .pccMinParametersUuid(pccMinParametersUuid) .spreadsheetConfigCollectionUuid(spreadsheetConfigCollectionUuid) @@ -2310,6 +2359,7 @@ private CompletableFuture deleteInvalidationInfos(InvalidateNodeInfos inva studyServerExecutionService.runAsync(() -> voltageInitService.deleteVoltageInitResults(invalidateNodeInfos.getVoltageInitResultUuids())), studyServerExecutionService.runAsync(() -> dynamicSimulationService.deleteResults(invalidateNodeInfos.getDynamicSimulationResultUuids())), studyServerExecutionService.runAsync(() -> dynamicSecurityAnalysisService.deleteResults(invalidateNodeInfos.getDynamicSecurityAnalysisResultUuids())), + studyServerExecutionService.runAsync(() -> dynamicMarginCalculationService.deleteResults(invalidateNodeInfos.getDynamicMarginCalculationResultUuids())), studyServerExecutionService.runAsync(() -> stateEstimationService.deleteStateEstimationResults(invalidateNodeInfos.getStateEstimationResultUuids())), studyServerExecutionService.runAsync(() -> pccMinService.deletePccMinResults(invalidateNodeInfos.getPccMinResultUuids())) ); @@ -2330,6 +2380,7 @@ private void deleteNodesInfos(DeleteNodeInfos deleteNodeInfos) { studyServerExecutionService.runAsync(() -> voltageInitService.deleteVoltageInitResults(deleteNodeInfos.getVoltageInitResultUuids())), studyServerExecutionService.runAsync(() -> dynamicSimulationService.deleteResults(deleteNodeInfos.getDynamicSimulationResultUuids())), studyServerExecutionService.runAsync(() -> dynamicSecurityAnalysisService.deleteResults(deleteNodeInfos.getDynamicSecurityAnalysisResultUuids())), + studyServerExecutionService.runAsync(() -> dynamicMarginCalculationService.deleteResults(deleteNodeInfos.getDynamicMarginCalculationResultUuids())), studyServerExecutionService.runAsync(() -> stateEstimationService.deleteStateEstimationResults(deleteNodeInfos.getStateEstimationResultUuids())), studyServerExecutionService.runAsync(() -> pccMinService.deletePccMinResults(deleteNodeInfos.getPccMinResultUuids())) ); @@ -2926,7 +2977,7 @@ public List getDynamicSimulationModels(UUID studyUuid) { public void setDynamicSimulationParameters(UUID studyUuid, DynamicSimulationParametersInfos dsParameter, String userId) { updateDynamicSimulationParameters(studyUuid, DynamicSimulationService.toEntity(dsParameter != null ? dsParameter : DynamicSimulationService.getDefaultDynamicSimulationParameters(), objectMapper)); - // Dynamic security analysis depend on dynamic simulation => must invalidate + // Dynamic security analysis depends on dynamic simulation => must invalidate invalidateDynamicSecurityAnalysisStatusOnAllNodes(studyUuid); notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS); @@ -3166,6 +3217,119 @@ private UUID handleDynamicSecurityAnalysisRequest(StudyEntity studyEntity, UUID // --- Dynamic Security Analysis service methods END --- // + // --- Dynamic Margin Calculation service methods BEGIN --- // + + public UUID getDynamicMarginCalculationParametersUuid(UUID studyUuid) { + StudyEntity studyEntity = getStudy(studyUuid); + return studyEntity.getDynamicMarginCalculationParametersUuid(); + } + + @Transactional + public String getDynamicMarginCalculationParameters(UUID studyUuid, String userId) { + StudyEntity studyEntity = getStudy(studyUuid); + return dynamicMarginCalculationService.getParameters( + dynamicMarginCalculationService.getDynamicMarginCalculationParametersUuidOrElseCreateDefault(studyEntity), userId); + } + + @Transactional + public boolean setDynamicMarginCalculationParameters(UUID studyUuid, String dsaParameter, String userId) { + StudyEntity studyEntity = getStudy(studyUuid); + boolean userProfileIssue = createOrUpdateDynamicMarginCalculationParameters(studyEntity, dsaParameter, userId); + invalidateDynamicMarginCalculationStatusOnAllNodes(studyUuid); + notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_STATUS); + notificationService.emitElementUpdated(studyUuid, userId); + notificationService.emitComputationParamsChanged(studyUuid, DYNAMIC_MARGIN_CALCULATION); + return userProfileIssue; + } + + public boolean createOrUpdateDynamicMarginCalculationParameters(StudyEntity studyEntity, String parameters, String userId) { + boolean userProfileIssue = false; + UUID existingDynamicMarginCalculationParametersUuid = studyEntity.getDynamicMarginCalculationParametersUuid(); + UserProfileInfos userProfileInfos = parameters == null ? userAdminService.getUserProfile(userId) : null; + if (parameters == null && userProfileInfos.getDynamicMarginCalculationParameterId() != null) { + // reset case, with existing profile, having default dynamic margin calculation params + try { + UUID dynamicMarginCalculationParametersFromProfileUuid = dynamicMarginCalculationService.duplicateParameters(userProfileInfos.getDynamicMarginCalculationParameterId()); + studyEntity.setDynamicMarginCalculationParametersUuid(dynamicMarginCalculationParametersFromProfileUuid); + removeDynamicMarginCalculationParameters(existingDynamicMarginCalculationParametersUuid); + return userProfileIssue; + } catch (Exception e) { + userProfileIssue = true; + LOGGER.error(String.format("Could not duplicate dynamic margin calculation parameters with id '%s' from user/profile '%s/%s'. Using default parameters", + userProfileInfos.getDynamicMarginCalculationParameterId(), userId, userProfileInfos.getName()), e); + // in case of duplication error (ex: wrong/dangling uuid in the profile), move on with default params below + } + } + + if (existingDynamicMarginCalculationParametersUuid == null) { + UUID newDynamicMarginCalculationParametersUuid = dynamicMarginCalculationService.createParameters(parameters); + studyEntity.setDynamicMarginCalculationParametersUuid(newDynamicMarginCalculationParametersUuid); + } else { + dynamicMarginCalculationService.updateParameters(existingDynamicMarginCalculationParametersUuid, parameters); + } + + return userProfileIssue; + } + + private void removeDynamicMarginCalculationParameters(@Nullable UUID dynamicMarginCalculationParametersUuid) { + if (dynamicMarginCalculationParametersUuid != null) { + try { + dynamicMarginCalculationService.deleteParameters(dynamicMarginCalculationParametersUuid); + } catch (Exception e) { + LOGGER.error("Could not remove dynamic margin calculation parameters with uuid:" + dynamicMarginCalculationParametersUuid, e); + } + } + } + + @Transactional + public UUID runDynamicMarginCalculation(@NonNull UUID studyUuid, @NonNull UUID nodeUuid, @NonNull UUID rootNetworkUuid, String userId, boolean debug) throws JsonProcessingException { + StudyEntity studyEntity = getStudy(studyUuid); + networkModificationTreeService.blockNode(rootNetworkUuid, nodeUuid); + + return handleDynamicMarginCalculationRequest(studyEntity, nodeUuid, rootNetworkUuid, debug, userId); + } + + private UUID handleDynamicMarginCalculationRequest(StudyEntity studyEntity, UUID nodeUuid, UUID rootNetworkUuid, boolean debug, String userId) throws JsonProcessingException { + + // pre-condition check + if (!rootNetworkNodeInfoService.isLoadflowConverged(nodeUuid, rootNetworkUuid)) { + throw new StudyException(NOT_ALLOWED, "Load flow must run successfully before running dynamic margin calculation"); + } + + // clean previous result if exist + UUID prevResultUuid = rootNetworkNodeInfoService.getComputationResultUuid(nodeUuid, rootNetworkUuid, DYNAMIC_MARGIN_CALCULATION); + if (prevResultUuid != null) { + dynamicMarginCalculationService.deleteResults(List.of(prevResultUuid)); + } + + // get dynamic simulation parameters entity + DynamicSimulationParametersInfos dynamicSimulationParametersInfos = getDynamicSimulationParameters(studyEntity); + String dynamicSimulationParametersInfosJson = objectMapper.writeValueAsString(dynamicSimulationParametersInfos); + + // get dynamic security analysis parameters uuid + UUID dynamicSecurityAnalysisParametersUuid = getDynamicSecurityAnalysisParametersUuid(studyEntity.getId()); + + // get dynamic margin calculation parameters uuid + UUID dynamicMarginCalculationParametersUuid = getDynamicMarginCalculationParametersUuid(studyEntity.getId()); + + UUID reportUuid = networkModificationTreeService.getComputationReports(nodeUuid, rootNetworkUuid).getOrDefault(DYNAMIC_MARGIN_CALCULATION.name(), UUID.randomUUID()); + networkModificationTreeService.updateComputationReportUuid(nodeUuid, rootNetworkUuid, DYNAMIC_MARGIN_CALCULATION, reportUuid); + + // launch dynamic margin calculation + UUID networkUuid = rootNetworkService.getNetworkUuid(rootNetworkUuid); + String variantId = networkModificationTreeService.getVariantId(nodeUuid, rootNetworkUuid); + UUID dynamicMarginCalculationResultUuid = dynamicMarginCalculationService.runDynamicMarginCalculation(studyEntity.getDynamicSimulationProvider(), + nodeUuid, rootNetworkUuid, networkUuid, variantId, reportUuid, dynamicSecurityAnalysisParametersUuid, dynamicMarginCalculationParametersUuid, dynamicSimulationParametersInfosJson, userId, debug); + + // update result uuid and notification + updateComputationResultUuid(nodeUuid, rootNetworkUuid, dynamicMarginCalculationResultUuid, DYNAMIC_MARGIN_CALCULATION); + notificationService.emitStudyChanged(studyEntity.getId(), nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_STATUS); + + return dynamicMarginCalculationResultUuid; + } + + // --- Dynamic Margin Calculation service methods END --- // + public String getNetworkElementsIds(UUID nodeUuid, UUID rootNetworkUuid, List substationsIds, boolean inUpstreamBuiltParentNode, String equipmentType, List nominalVoltages) { UUID nodeUuidToSearchIn = getNodeUuidToSearchIn(nodeUuid, rootNetworkUuid, inUpstreamBuiltParentNode); return networkMapService.getElementsIds(rootNetworkService.getNetworkUuid(rootNetworkUuid), networkModificationTreeService.getVariantId(nodeUuidToSearchIn, rootNetworkUuid), @@ -3316,6 +3480,7 @@ private void emitAllComputationStatusChanged(UUID studyUuid, UUID nodeUuid, UUID notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_VOLTAGE_INIT_STATUS); notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_DYNAMIC_SIMULATION_STATUS); notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS); + notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_STATUS); notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_STATE_ESTIMATION_STATUS); notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_PCC_MIN_STATUS); } diff --git a/src/main/java/org/gridsuite/study/server/service/SupervisionService.java b/src/main/java/org/gridsuite/study/server/service/SupervisionService.java index b2e814dd21..2871a5a5f6 100644 --- a/src/main/java/org/gridsuite/study/server/service/SupervisionService.java +++ b/src/main/java/org/gridsuite/study/server/service/SupervisionService.java @@ -17,6 +17,7 @@ import org.gridsuite.study.server.repository.StudyRepository; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkEntity; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkNodeInfoRepository; +import org.gridsuite.study.server.service.dynamicmargincalculation.DynamicMarginCalculationService; import org.gridsuite.study.server.service.dynamicsecurityanalysis.DynamicSecurityAnalysisService; import org.gridsuite.study.server.service.dynamicsimulation.DynamicSimulationService; import org.gridsuite.study.server.service.shortcircuit.ShortCircuitService; @@ -59,6 +60,8 @@ public class SupervisionService { private final DynamicSecurityAnalysisService dynamicSecurityAnalysisService; + private final DynamicMarginCalculationService dynamicMarginCalculationService; + private final SecurityAnalysisService securityAnalysisService; private final SensitivityAnalysisService sensitivityAnalysisService; @@ -88,6 +91,7 @@ public SupervisionService(StudyService studyService, LoadFlowService loadFlowService, DynamicSimulationService dynamicSimulationService, DynamicSecurityAnalysisService dynamicSecurityAnalysisService, + DynamicMarginCalculationService dynamicMarginCalculationService, SecurityAnalysisService securityAnalysisService, SensitivityAnalysisService sensitivityAnalysisService, ShortCircuitService shortCircuitService, @@ -106,6 +110,7 @@ public SupervisionService(StudyService studyService, this.loadFlowService = loadFlowService; this.dynamicSimulationService = dynamicSimulationService; this.dynamicSecurityAnalysisService = dynamicSecurityAnalysisService; + this.dynamicMarginCalculationService = dynamicMarginCalculationService; this.securityAnalysisService = securityAnalysisService; this.sensitivityAnalysisService = sensitivityAnalysisService; this.shortCircuitService = shortCircuitService; @@ -127,6 +132,8 @@ public Integer deleteComputationResults(ComputationType computationType, boolean dryRun ? dynamicSimulationService.getResultsCount() : deleteDynamicSimulationResults(); case DYNAMIC_SECURITY_ANALYSIS -> dryRun ? dynamicSecurityAnalysisService.getResultsCount() : deleteDynamicSecurityAnalysisResults(); + case DYNAMIC_MARGIN_CALCULATION -> + dryRun ? dynamicMarginCalculationService.getResultsCount() : deleteDynamicMarginCalculationResults(); case SECURITY_ANALYSIS -> dryRun ? securityAnalysisService.getSecurityAnalysisResultsCount() : deleteSecurityAnalysisResults(); case SENSITIVITY_ANALYSIS -> @@ -218,6 +225,16 @@ private Integer deleteDynamicSecurityAnalysisResults() { return rootNetworkNodeStatusEntities.size(); } + private Integer deleteDynamicMarginCalculationResults() { + AtomicReference startTime = new AtomicReference<>(); + startTime.set(System.nanoTime()); + List rootNetworkNodeStatusEntities = rootNetworkNodeInfoRepository.findAllByDynamicMarginCalculationResultUuidNotNull(); + rootNetworkNodeStatusEntities.forEach(rootNetworkNodeStatus -> rootNetworkNodeStatus.setDynamicMarginCalculationResultUuid(null)); + dynamicMarginCalculationService.deleteAllResults(); + LOGGER.trace(DELETION_LOG_MESSAGE, ComputationType.DYNAMIC_MARGIN_CALCULATION, TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime.get())); + return rootNetworkNodeStatusEntities.size(); + } + private Integer deleteSecurityAnalysisResults() { AtomicReference startTime = new AtomicReference<>(); startTime.set(System.nanoTime()); diff --git a/src/main/java/org/gridsuite/study/server/service/client/dynamicmargincalculation/DynamicMarginCalculationClient.java b/src/main/java/org/gridsuite/study/server/service/client/dynamicmargincalculation/DynamicMarginCalculationClient.java new file mode 100644 index 0000000000..198d284bbe --- /dev/null +++ b/src/main/java/org/gridsuite/study/server/service/client/dynamicmargincalculation/DynamicMarginCalculationClient.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2026, 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.study.server.service.client.dynamicmargincalculation; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.gridsuite.study.server.RemoteServicesProperties; +import org.gridsuite.study.server.dto.ReportInfos; +import org.gridsuite.study.server.dto.dynamicmargincalculation.DynamicMarginCalculationStatus; +import org.gridsuite.study.server.service.StudyService; +import org.gridsuite.study.server.service.client.AbstractRestClient; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.lang.NonNull; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +import static org.gridsuite.study.server.StudyConstants.*; +import static org.gridsuite.study.server.notification.NotificationService.HEADER_USER_ID; +import static org.gridsuite.study.server.service.client.util.UrlUtil.buildEndPointUrl; + +/** + * @author Thang PHAM + */ +@Service +public class DynamicMarginCalculationClient extends AbstractRestClient { + public static final String API_VERSION = DYNAMIC_MARGIN_CALCULATION_API_VERSION; + public static final String DYNAMIC_MARGIN_CALCULATION_END_POINT_PARAMETER = "parameters"; + public static final String DYNAMIC_MARGIN_CALCULATION_END_POINT_RUN = "networks"; + public static final String DYNAMIC_MARGIN_CALCULATION_END_POINT_RESULT = "results"; + + protected DynamicMarginCalculationClient(RemoteServicesProperties remoteServicesProperties, + RestTemplate restTemplate) { + super(remoteServicesProperties.getServiceUri("dynamic-margin-calculation-server"), restTemplate); + } + + private String getParametersWithUuidUrl(UUID parametersUuid) { + String parametersBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_PARAMETER); + + return UriComponentsBuilder + .fromUriString(parametersBaseUrl + "/{uuid}") + .buildAndExpand(parametersUuid) + .toUriString(); + } + + // --- Related parameters methods --- // + + public String getDefaultProvider() { + String rootBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, null); + + String url = UriComponentsBuilder + .fromUriString(rootBaseUrl + "/default-provider") + .toUriString(); + + return getRestTemplate().getForObject(url, String.class); + } + + public String getProvider(@NonNull UUID parametersUuid) { + Objects.requireNonNull(parametersUuid); + String parametersBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_PARAMETER); + + String url = UriComponentsBuilder + .fromUriString(parametersBaseUrl + "/{uuid}/provider") + .buildAndExpand(parametersUuid) + .toUriString(); + + return getRestTemplate().getForObject(url, String.class); + } + + public void updateProvider(@NonNull UUID parametersUuid, @NonNull String provider) { + Objects.requireNonNull(parametersUuid); + Objects.requireNonNull(provider); + + String parametersBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_PARAMETER); + + String url = UriComponentsBuilder + .fromUriString(parametersBaseUrl + "/{uuid}/provider") + .buildAndExpand(parametersUuid) + .toUriString(); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + HttpEntity httpEntity = new HttpEntity<>(provider, headers); + + // call dynamic-margin-calculation REST API + getRestTemplate().put(url, httpEntity); + } + + public String getParameters(@NonNull UUID parametersUuid, String userId) { + Objects.requireNonNull(parametersUuid); + + String url = getParametersWithUuidUrl(parametersUuid); + + HttpHeaders headers = new HttpHeaders(); + if (StringUtils.isNotBlank(userId)) { + headers.set(HEADER_USER_ID, userId); + } + + return getRestTemplate() + .exchange(url, HttpMethod.GET, new HttpEntity<>(headers), String.class).getBody(); + } + + public UUID createParameters(@NonNull String parametersInfos) { + Objects.requireNonNull(parametersInfos); + + String parametersBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_PARAMETER); + + String url = UriComponentsBuilder + .fromUriString(parametersBaseUrl) + .buildAndExpand() + .toUriString(); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + HttpEntity httpEntity = new HttpEntity<>(parametersInfos, headers); + + return getRestTemplate().postForObject(url, httpEntity, UUID.class); + } + + public void updateParameters(@NonNull UUID parametersUuid, @NonNull String parametersInfos) { + Objects.requireNonNull(parametersUuid); + Objects.requireNonNull(parametersInfos); + + String url = getParametersWithUuidUrl(parametersUuid); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + HttpEntity httpEntity = new HttpEntity<>(parametersInfos, headers); + + getRestTemplate().put(url, httpEntity); + } + + public UUID duplicateParameters(@NonNull UUID sourceParametersUuid) { + Objects.requireNonNull(sourceParametersUuid); + + String parametersBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_PARAMETER); + + String url = UriComponentsBuilder + .fromUriString(parametersBaseUrl) + .queryParam("duplicateFrom", sourceParametersUuid) + .buildAndExpand() + .toUriString(); + + return getRestTemplate().postForObject(url, null, UUID.class); + } + + public void deleteParameters(@NonNull UUID parametersUuid) { + Objects.requireNonNull(parametersUuid); + + String url = getParametersWithUuidUrl(parametersUuid); + + // call dynamic-margin-calculation REST API + getRestTemplate().delete(url); + } + + public UUID createDefaultParameters() { + String parametersBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_PARAMETER); + + String url = UriComponentsBuilder + .fromUriString(parametersBaseUrl + "/default") + .buildAndExpand() + .toUriString(); + + return getRestTemplate().postForObject(url, null, UUID.class); + } + + // --- Related run computation methods --- // + + public UUID run(String provider, @NonNull String receiver, @NonNull UUID networkUuid, String variantId, + @NonNull ReportInfos reportInfos, @NonNull UUID dynamicSecurityAnalysisParametersUuid, + @NonNull UUID parametersUuid, @NonNull String dynamicSimulationParametersJson, String userId, boolean debug) { + Objects.requireNonNull(receiver); + Objects.requireNonNull(networkUuid); + Objects.requireNonNull(reportInfos); + Objects.requireNonNull(dynamicSecurityAnalysisParametersUuid); + Objects.requireNonNull(parametersUuid); + + String runBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_RUN); + + UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(runBaseUrl + "/{networkUuid}/run"); + if (StringUtils.isNotBlank(variantId)) { + uriComponentsBuilder.queryParam(QUERY_PARAM_VARIANT_ID, variantId); + } + if (StringUtils.isNotBlank(provider)) { + uriComponentsBuilder.queryParam("provider", provider); + } + if (debug) { + uriComponentsBuilder.queryParam(QUERY_PARAM_DEBUG, true); + } + uriComponentsBuilder + .queryParam("dynamicSecurityAnalysisParametersUuid", dynamicSecurityAnalysisParametersUuid) + .queryParam("parametersUuid", parametersUuid) + .queryParam(QUERY_PARAM_RECEIVER, receiver) + .queryParam(QUERY_PARAM_REPORT_UUID, reportInfos.reportUuid()) + .queryParam(QUERY_PARAM_REPORTER_ID, reportInfos.nodeUuid()) + .queryParam(QUERY_PARAM_REPORT_TYPE, StudyService.ReportType.DYNAMIC_SECURITY_ANALYSIS.reportKey); + String url = uriComponentsBuilder + .buildAndExpand(networkUuid) + .toUriString(); + + HttpHeaders headers = new HttpHeaders(); + headers.set(HEADER_USER_ID, userId); + headers.setContentType(MediaType.APPLICATION_JSON); + + // call dynamic-margin-calculation REST API + HttpEntity httpEntity = new HttpEntity<>(dynamicSimulationParametersJson, headers); + + return getRestTemplate().postForObject(url, httpEntity, UUID.class); + } + + // --- Related result methods --- // + + public DynamicMarginCalculationStatus getStatus(@NonNull UUID resultUuid) { + Objects.requireNonNull(resultUuid); + + String resultBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_RESULT); + + String url = UriComponentsBuilder + .fromUriString(resultBaseUrl + "/{resultUuid}/status") + .buildAndExpand(resultUuid) + .toUriString(); + + // call dynamic-margin-calculation REST API + return getRestTemplate().getForObject(url, DynamicMarginCalculationStatus.class); + } + + public void invalidateStatus(@NonNull List resultUuids) { + if (CollectionUtils.isEmpty(resultUuids)) { + return; + } + + String resultBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_RESULT); + + String url = UriComponentsBuilder + .fromUriString(resultBaseUrl + "/invalidate-status") + .queryParam("resultUuid", resultUuids) + .build() + .toUriString(); + + getRestTemplate().exchange(url, HttpMethod.PUT, null, new ParameterizedTypeReference>() { }); + } + + public void deleteResults(List resultUuids) { + if (CollectionUtils.isEmpty(resultUuids)) { + return; + } + String resultBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_RESULT); + String url = UriComponentsBuilder + .fromUriString(resultBaseUrl) + .queryParam(QUERY_PARAM_RESULTS_UUIDS, resultUuids) + .build() + .toUriString(); + // call dynamic-margin-calculation REST API + getRestTemplate().delete(url); + } + + public Integer getResultsCount() { + String resultBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_RESULT); + String url = UriComponentsBuilder + .fromUriString(resultBaseUrl) + .toUriString(); + + // call dynamic-margin-calculation REST API + return getRestTemplate().getForObject(url, Integer.class); + } +} diff --git a/src/main/java/org/gridsuite/study/server/service/dynamicmargincalculation/DynamicMarginCalculationService.java b/src/main/java/org/gridsuite/study/server/service/dynamicmargincalculation/DynamicMarginCalculationService.java new file mode 100644 index 0000000000..fb231db3ba --- /dev/null +++ b/src/main/java/org/gridsuite/study/server/service/dynamicmargincalculation/DynamicMarginCalculationService.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2026, 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.study.server.service.dynamicmargincalculation; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.collections4.CollectionUtils; +import org.gridsuite.study.server.dto.NodeReceiver; +import org.gridsuite.study.server.dto.ReportInfos; +import org.gridsuite.study.server.dto.dynamicmargincalculation.DynamicMarginCalculationStatus; +import org.gridsuite.study.server.error.StudyException; +import org.gridsuite.study.server.repository.StudyEntity; +import org.gridsuite.study.server.service.client.dynamicmargincalculation.DynamicMarginCalculationClient; +import org.springframework.stereotype.Service; + +import java.io.UncheckedIOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.UUID; + +import static org.gridsuite.study.server.error.StudyBusinessErrorCode.COMPUTATION_RUNNING; + +/** + * @author Thang PHAM + */ +@Service +public class DynamicMarginCalculationService { + + private final ObjectMapper objectMapper; + + private final DynamicMarginCalculationClient dynamicMarginCalculationClient; + + public DynamicMarginCalculationService(ObjectMapper objectMapper, + DynamicMarginCalculationClient dynamicMarginCalculationClient) { + this.objectMapper = objectMapper; + this.dynamicMarginCalculationClient = dynamicMarginCalculationClient; + } + + public String getParameters(UUID parametersUuid, String userId) { + return dynamicMarginCalculationClient.getParameters(parametersUuid, userId); + } + + public UUID createParameters(String parameters) { + return dynamicMarginCalculationClient.createParameters(parameters); + } + + public UUID createDefaultParameters() { + return dynamicMarginCalculationClient.createDefaultParameters(); + } + + public void updateParameters(UUID parametersUuid, String parametersInfos) { + dynamicMarginCalculationClient.updateParameters(parametersUuid, parametersInfos); + } + + public UUID duplicateParameters(UUID sourceParameterId) { + return dynamicMarginCalculationClient.duplicateParameters(sourceParameterId); + } + + public void deleteParameters(UUID parametersUuid) { + dynamicMarginCalculationClient.deleteParameters(parametersUuid); + } + + public UUID runDynamicMarginCalculation(String provider, UUID nodeUuid, UUID rootNetworkUuid, UUID networkUuid, + String variantId, UUID reportUuid, UUID dynamicSecurityAnalysisParametersUuid, UUID parametersUuid, String dynamicSimulationParametersJson, String userId, boolean debug) { + + // create receiver for getting back the notification in rabbitmq + String receiver; + + try { + receiver = URLEncoder.encode(objectMapper.writeValueAsString(new NodeReceiver(nodeUuid, rootNetworkUuid)), + StandardCharsets.UTF_8); + } catch (JsonProcessingException e) { + throw new UncheckedIOException(e); + } + + return dynamicMarginCalculationClient.run(provider, receiver, networkUuid, variantId, new ReportInfos(reportUuid, nodeUuid), dynamicSecurityAnalysisParametersUuid, parametersUuid, dynamicSimulationParametersJson, userId, debug); + } + + public DynamicMarginCalculationStatus getStatus(UUID resultUuid) { + return resultUuid == null ? null : dynamicMarginCalculationClient.getStatus(resultUuid); + } + + public void invalidateStatus(List resultUuids) { + if (CollectionUtils.isNotEmpty(resultUuids)) { + dynamicMarginCalculationClient.invalidateStatus(resultUuids); + } + } + + public void deleteResults(List resultUuids) { + dynamicMarginCalculationClient.deleteResults(resultUuids); + } + + public void deleteAllResults() { + deleteResults(null); + } + + public Integer getResultsCount() { + return dynamicMarginCalculationClient.getResultsCount(); + } + + public void assertDynamicMarginCalculationNotRunning(UUID resultUuid) { + DynamicMarginCalculationStatus status = getStatus(resultUuid); + if (DynamicMarginCalculationStatus.RUNNING == status) { + throw new StudyException(COMPUTATION_RUNNING); + } + } + + public UUID getDynamicMarginCalculationParametersUuidOrElseCreateDefault(StudyEntity studyEntity) { + if (studyEntity.getDynamicMarginCalculationParametersUuid() == null) { + // not supposed to happen because we create it as the study creation + studyEntity.setDynamicMarginCalculationParametersUuid(dynamicMarginCalculationClient.createDefaultParameters()); + } + return studyEntity.getDynamicMarginCalculationParametersUuid(); + } + + public void updateProvider(UUID parametersUuid, String provider) { + dynamicMarginCalculationClient.updateProvider(parametersUuid, provider); + } + + public String getDefaultProvider() { + return dynamicMarginCalculationClient.getDefaultProvider(); + } + + public String getProvider(UUID parametersUuid) { + return dynamicMarginCalculationClient.getProvider(parametersUuid); + } +} diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 237f8990cb..a38d05375d 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -61,6 +61,9 @@ gridsuite: - name: dynamic-security-analysis-server base-uri: http://localhost:5040 + - + name: dynamic-margin-calculation-server + base-uri: http://localhost:5041 - name: timeseries-server base-uri: http://localhost:5037 diff --git a/src/main/resources/config/application.yaml b/src/main/resources/config/application.yaml index fd28d3a7bc..2e12cf7541 100644 --- a/src/main/resources/config/application.yaml +++ b/src/main/resources/config/application.yaml @@ -8,6 +8,7 @@ spring: definition: "consumeSaResult;consumeSaStopped;consumeSaFailed;consumeSaCancelFailed;\ consumeDsDebug;consumeDsResult;consumeDsStopped;consumeDsFailed;consumeDsCancelFailed;\ consumeDsaDebug;consumeDsaResult;consumeDsaStopped;consumeDsaFailed;consumeDsaCancelFailed;\ + consumeDmcDebug;consumeDmcResult;consumeDmcStopped;consumeDmcFailed;consumeDmcCancelFailed;\ consumeBuildResult;consumeBuildStopped;consumeBuildFailed;\ consumeCaseImportSucceeded;consumeCaseImportFailed;\ consumeSensitivityAnalysisResult;consumeSensitivityAnalysisStopped;consumeSensitivityAnalysisFailed;consumeSensitivityAnalysisCancelFailed;\ @@ -65,6 +66,21 @@ spring: consumeDsaFailed-in-0: destination: ${powsybl-ws.rabbitmq.destination.prefix:}dsa.run.dlx group: dlq + consumeDmcDebug-in-0: + destination: ${powsybl-ws.rabbitmq.destination.prefix:}dmc.debug + group: studyDsaDebugGroup + consumeDmcResult-in-0: + destination: ${powsybl-ws.rabbitmq.destination.prefix:}dmc.result + group: studyDsaResultGroup + consumeDmcStopped-in-0: + destination: ${powsybl-ws.rabbitmq.destination.prefix:}dmc.stopped + group: studyDsaStoppedGroup + consumeDmcCancelFailed-in-0: + destination: ${powsybl-ws.rabbitmq.destination.prefix:}dmc.cancelfailed + group: studyDsaCancelFailedGroup + consumeDmcFailed-in-0: + destination: ${powsybl-ws.rabbitmq.destination.prefix:}dmc.run.dlx + group: dlq consumeBuildResult-in-0: destination: ${powsybl-ws.rabbitmq.destination.prefix:}build.result group: studyBuildResultGroup @@ -207,6 +223,9 @@ gridsuite: - name: dynamic-security-analysis-server base-uri: http://dynamic-security-analysis-server/ + - + name: dynamic-margin-calculation-server + base-uri: http://dynamic-margin-calculation-server/ - name: timeseries-server base-uri: http://timeseries-server/ diff --git a/src/main/resources/db/changelog/changesets/changelog_20260106T162321Z.xml b/src/main/resources/db/changelog/changesets/changelog_20260106T162321Z.xml new file mode 100644 index 0000000000..a5d5ac3652 --- /dev/null +++ b/src/main/resources/db/changelog/changesets/changelog_20260106T162321Z.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index 99c05491a1..edfb6847aa 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -365,3 +365,6 @@ databaseChangeLog: - include: file: changesets/changelog_20260123T095727Z.xml relativeToChangelogFile: true + - include: + file: changesets/changelog_20260106T162321Z.xml + relativeToChangelogFile: true diff --git a/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java b/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java index 8bf3a65a1c..c22dd8a966 100644 --- a/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java +++ b/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java @@ -24,6 +24,7 @@ import com.powsybl.network.store.iidm.impl.NetworkFactoryImpl; import com.powsybl.ws.commons.error.PowsyblWsProblemDetail; import org.gridsuite.study.server.dto.*; +import org.gridsuite.study.server.dto.dynamicmargincalculation.DynamicMarginCalculationStatus; import org.gridsuite.study.server.dto.dynamicsecurityanalysis.DynamicSecurityAnalysisStatus; import org.gridsuite.study.server.dto.dynamicsimulation.DynamicSimulationStatus; import org.gridsuite.study.server.dto.impacts.SimpleElementImpact.SimpleImpactType; @@ -39,6 +40,7 @@ import org.gridsuite.study.server.repository.StudyRepository; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkNodeInfoRepository; import org.gridsuite.study.server.service.*; +import org.gridsuite.study.server.service.client.dynamicmargincalculation.DynamicMarginCalculationClient; import org.gridsuite.study.server.service.client.dynamicsecurityanalysis.DynamicSecurityAnalysisClient; import org.gridsuite.study.server.service.client.dynamicsimulation.DynamicSimulationClient; import org.gridsuite.study.server.service.shortcircuit.ShortCircuitService; @@ -74,6 +76,7 @@ import org.springframework.test.web.servlet.MvcResult; import java.util.*; +import java.util.stream.Collectors; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; import static org.gridsuite.study.server.StudyConstants.HEADER_ERROR_MESSAGE; @@ -84,6 +87,7 @@ import static org.gridsuite.study.server.utils.JsonUtils.getModificationContextJsonString; import static org.gridsuite.study.server.utils.MatcherCreatedStudyBasicInfos.createMatcherCreatedStudyBasicInfos; import static org.gridsuite.study.server.utils.SendInput.POST_ACTION_SEND_INPUT; +import static org.gridsuite.study.server.utils.TestUtils.checkUpdateStatusMessagesReceived; import static org.gridsuite.study.server.utils.TestUtils.synchronizeStudyServerExecutionService; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.*; @@ -123,6 +127,7 @@ class NetworkModificationTest { private static final String LOADFLOW_RESULT_UUID = "0c8de3c9-6f4d-4b3e-9c4a-8f7e5a9b1d2e"; private static final String DYNAMIC_SIMULATION_RESULT_UUID = "1d9ef4d0-7f5e-5c4f-0d5b-9f8f6b0c2e3f"; private static final String DYNAMIC_SECURITY_ANALYSIS_RESULT_UUID = "2e0f05e1-8a6f-6d50-1e6c-0a9071d3f40a"; + private static final String DYNAMIC_MARGIN_CALCULATION_RESULT_UUID = "52b88cb8-d3ce-4263-bd4d-8b27849d88bc"; private static final String SECURITY_ANALYSIS_RESULT_UUID = "f3a85c9b-9594-4e55-8ec7-07ea965d24eb"; private static final String SECURITY_ANALYSIS_STATUS_JSON = "\"CONVERGED\""; @@ -222,6 +227,9 @@ class NetworkModificationTest { @MockitoSpyBean DynamicSecurityAnalysisClient dynamicSecurityAnalysisClient; + @MockitoSpyBean + DynamicMarginCalculationClient dynamicMarginCalculationClient; + @MockitoSpyBean private RootNetworkNodeInfoRepository rootNetworkNodeInfoRepository; @@ -289,6 +297,7 @@ void setup() { doReturn(baseUrl).when(dynamicSimulationClient).getBaseUri(); doReturn(baseUrl).when(dynamicSecurityAnalysisClient).getBaseUri(); + doReturn(baseUrl).when(dynamicMarginCalculationClient).getBaseUri(); networkModificationService.setNetworkModificationServerBaseUri(baseUrl); userAdminService.setUserAdminServerBaseUri(baseUrl); @@ -519,7 +528,7 @@ void testLocalBuildValue() throws Exception { .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); wireMockStubs.verifyNetworkModificationDeleteIndex(deleteModificationIndexStub); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); checkNodesBuildStatusUpdatedMessageReceived(studyNameUserIdUuid, List.of(modificationNodeUuid)); @@ -537,7 +546,7 @@ void testLocalBuildValue() throws Exception { .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); checkNodesBuildStatusUpdatedMessageReceived(studyNameUserIdUuid, List.of(modificationNode2Uuid)); @@ -592,7 +601,7 @@ void testNetworkModificationSwitch() throws Exception { .content(bodyJson).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -613,7 +622,7 @@ void testNetworkModificationSwitch() throws Exception { .content(bodyJson).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -640,7 +649,7 @@ void testNetworkModificationSwitch() throws Exception { Set substationsSet = ImmutableSet.of("s3", "s1", "s2"); NetworkImpactsInfos expectedPayload = NetworkImpactsInfos.builder().impactedSubstationsIds(substationsSet).build(); checkNodesBuildStatusUpdatedMessageReceived(studyNameUserIdUuid, List.of(modificationNode2Uuid)); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); checkEquipmentMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, expectedPayload); @@ -691,7 +700,7 @@ void testNetworkModificationEquipment() throws Exception { .content(bodyJson).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); Pair> modificationBody = Pair.of(bodyJson, List.of(rootNetworkNodeInfoService.getNetworkModificationApplicationContext(firstRootNetworkUuid, modificationNodeUuid, NETWORK_UUID))); @@ -711,7 +720,7 @@ void testNetworkModificationEquipment() throws Exception { .content(bodyJson).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -761,7 +770,7 @@ void testCreateGenerator() throws Exception { .content(bodyJsonCreate).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -773,7 +782,7 @@ void testCreateGenerator() throws Exception { .content(bodyJsonCreate).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -837,7 +846,7 @@ void testCreateShuntsCompensator() throws Exception { .content(createShuntCompensatorAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -901,7 +910,7 @@ void testCreateLine() throws Exception { .content(createLineAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -913,7 +922,7 @@ void testCreateLine() throws Exception { .content(createLineAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); modificationBody = Pair.of(createLineAttributes, List.of(rootNetworkNodeInfoService.getNetworkModificationApplicationContext(firstRootNetworkUuid, modificationNode2Uuid, NETWORK_UUID))); @@ -984,7 +993,7 @@ void testCreateTwoWindingsTransformer() throws Exception { .content(createTwoWindingsTransformerAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -996,7 +1005,7 @@ void testCreateTwoWindingsTransformer() throws Exception { .content(createTwoWindingsTransformerAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1106,7 +1115,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate1).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1121,7 +1130,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate2).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isInternalServerError()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); wireMockStubs.verifyNetworkModificationPost(modificationBodyJson); @@ -1135,7 +1144,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate3).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1150,7 +1159,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate4).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isInternalServerError()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); wireMockStubs.verifyNetworkModificationPost(modificationBodyJson); @@ -1164,7 +1173,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate5).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1179,7 +1188,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate6).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isInternalServerError()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); wireMockStubs.verifyNetworkModificationPost(modificationBodyJson); @@ -1193,7 +1202,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate7).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1208,7 +1217,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate8).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isInternalServerError()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); wireMockStubs.verifyNetworkModificationPost(modificationBodyJson); @@ -1220,7 +1229,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate9).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1259,7 +1268,7 @@ void testCreateLoad() throws Exception { .content(createLoadAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1271,7 +1280,7 @@ void testCreateLoad() throws Exception { .content(createLoadAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1332,7 +1341,7 @@ void testModifyLoad() throws Exception { .content(loadModificationAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1344,7 +1353,7 @@ void testModifyLoad() throws Exception { .content(loadModificationAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1390,7 +1399,7 @@ void testModifyEquipment() throws Exception { .content(equipmentModificationAttribute).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1402,7 +1411,7 @@ void testModifyEquipment() throws Exception { .content(equipmentModificationAttribute).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1451,7 +1460,7 @@ void testCreateSubstation() throws Exception { .content(createSubstationAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1463,7 +1472,7 @@ void testCreateSubstation() throws Exception { .content(createSubstationAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1523,7 +1532,7 @@ void testCreateVoltageLevel() throws Exception { .content(createVoltageLevelAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1535,7 +1544,7 @@ void testCreateVoltageLevel() throws Exception { .content(createVoltageLevelAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1597,7 +1606,7 @@ void testLineSplitWithVoltageLevel() throws Exception { .content(lineSplitWoVLasJSON).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1623,7 +1632,7 @@ void testLineSplitWithVoltageLevel() throws Exception { .content(badBody).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isBadRequest()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); mockMvc.perform(put(URI_NETWORK_MODIF_WITH_ID, studyNameUserIdUuid, modificationNodeUuid, MODIFICATION_UUID) @@ -1657,7 +1666,7 @@ void testLineAttachToVoltageLevel() throws Exception { .content(createLineAttachToVoltageLevelAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1692,7 +1701,7 @@ void testLinesAttachToSplitLines() throws Exception { .content(createLinesAttachToSplitLinesAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1718,7 +1727,7 @@ void testLinesAttachToSplitLines() throws Exception { .content(badBody).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isBadRequest()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); mockMvc.perform(put(URI_NETWORK_MODIF_WITH_ID, studyNameUserIdUuid, modificationNodeUuid, MODIFICATION_UUID) @@ -1750,7 +1759,7 @@ void testScaling(ModificationType scalingType) throws Exception { .content(requestBody).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1775,7 +1784,7 @@ void testScaling(ModificationType scalingType) throws Exception { .content(requestBody).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().is4xxClientError()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); wireMockStubs.verifyNetworkModificationPost(modificationBodyJson); @@ -1806,7 +1815,7 @@ void testDeleteVoltageLevelOnline() throws Exception { .content(createDeleteVoltageLevelOnlineAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); Pair> modificationBody = Pair.of(createDeleteVoltageLevelOnlineAttributes, List.of(rootNetworkNodeInfoService.getNetworkModificationApplicationContext(firstRootNetworkUuid, modificationNodeUuid, NETWORK_UUID))); @@ -1829,7 +1838,7 @@ void testDeleteVoltageLevelOnline() throws Exception { mockMvc.perform(post(URI_NETWORK_MODIF, studyNameUserIdUuid, modificationNodeUuid).header(USER_ID_HEADER, userId) .content(badBody).contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isBadRequest()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); wireMockStubs.verifyNetworkModificationPost(modificationBodyJson); @@ -1859,7 +1868,7 @@ void testDeleteAttachingline() throws Exception { .content(createDeleteAttachingLineAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); Pair> modificationBody = Pair.of(createDeleteAttachingLineAttributes, List.of(rootNetworkNodeInfoService.getNetworkModificationApplicationContext(firstRootNetworkUuid, modificationNodeUuid, NETWORK_UUID))); @@ -1883,7 +1892,7 @@ void testDeleteAttachingline() throws Exception { .content(badBody).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isBadRequest()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); wireMockStubs.verifyNetworkModificationPost(modificationBodyJson); @@ -1921,7 +1930,7 @@ void testReorderModification() throws Exception { mockMvc.perform(put("/v1/studies/{studyUuid}/nodes/{nodeUuid}/network-modification/{modificationID}", studyNameUserIdUuid, modificationNodeUuid, modification1).header(USER_ID_HEADER, "userId")) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentUpdatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1939,7 +1948,7 @@ void testReorderModification() throws Exception { mockMvc.perform(put("/v1/studies/{studyUuid}/nodes/{nodeUuid}/network-modification/{modificationID}?beforeUuid={modificationID2}", studyNameUserIdUuid, modificationNodeUuid, modification1, modification2).header(USER_ID_HEADER, "userId")) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentUpdatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -2003,7 +2012,7 @@ void testDuplicateModification() throws Exception { .content(modificationUuidListBody) .header(USER_ID_HEADER, "userId")) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyUuid, nodeUuid1); + checkUpdateStatusMessagesReceived(studyUuid, nodeUuid1, output); checkEquipmentUpdatingMessagesReceived(studyUuid, nodeUuid1); checkEquipmentUpdatingFinishedMessagesReceived(studyUuid, nodeUuid1); checkElementUpdatedMessageSent(studyUuid, userId); @@ -2036,7 +2045,7 @@ void testDuplicateModification() throws Exception { .andExpect(status().isOk()); NetworkImpactsInfos expectedPayload = NetworkImpactsInfos.builder().build(); - checkUpdateModelsStatusMessagesReceived(studyUuid, nodeUuid1); + checkUpdateStatusMessagesReceived(studyUuid, nodeUuid1, output); checkEquipmentUpdatingMessagesReceived(studyUuid, nodeUuid1); checkElementUpdatedMessageSent(studyUuid, userId); checkEquipmentMessagesReceived(studyUuid, List.of(nodeUuid1), expectedPayload); @@ -2075,7 +2084,7 @@ void testDuplicateModificationBetweenStudies() throws Exception { .content(modificationUuidListBody) .header(USER_ID_HEADER, "userId")) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyEntity1.getId(), node1.getId()); + checkUpdateStatusMessagesReceived(studyEntity1.getId(), node1.getId(), output); checkEquipmentUpdatingMessagesReceived(studyEntity1.getId(), node1.getId()); checkEquipmentUpdatingFinishedMessagesReceived(studyEntity1.getId(), node1.getId()); checkElementUpdatedMessageSent(studyEntity1.getId(), userId); @@ -2156,7 +2165,7 @@ void testCutAndPasteModification() throws Exception { .content(modificationUuidListBody) .header(USER_ID_HEADER, "userId")) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyUuid, nodeUuid1); + checkUpdateStatusMessagesReceived(studyUuid, nodeUuid1, output); checkEquipmentUpdatingMessagesReceived(studyUuid, nodeUuid1); checkEquipmentUpdatingFinishedMessagesReceived(studyUuid, nodeUuid1); @@ -2176,8 +2185,8 @@ void testCutAndPasteModification() throws Exception { .content(modificationUuidListBody) .header(USER_ID_HEADER, "userId")) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyUuid, nodeUuid1); - checkUpdateModelsStatusMessagesReceived(studyUuid, nodeUuid2); + checkUpdateStatusMessagesReceived(studyUuid, nodeUuid1, output); + checkUpdateStatusMessagesReceived(studyUuid, nodeUuid2, output); checkEquipmentUpdatingMessagesReceived(studyUuid, nodeUuid2); checkEquipmentUpdatingMessagesReceived(studyUuid, nodeUuid1); checkEquipmentUpdatingFinishedMessagesReceived(studyUuid, nodeUuid2); @@ -2265,7 +2274,7 @@ void testDeleteEquipment() throws Exception { .content(bodyJson).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -2277,7 +2286,7 @@ void testDeleteEquipment() throws Exception { .content(bodyJson).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -2342,7 +2351,7 @@ void testNodesInvalidation() throws Exception { wireMockStubs.verifyNetworkModificationDeleteIndex(deleteModificationIndexStub); checkEquipmentUpdatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkNodesInvalidationMessagesReceived(studyNameUserIdUuid, List.of(modificationNode1Uuid, modificationNode2Uuid, modificationNode3Uuid)); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -2380,7 +2389,7 @@ void testNodesInvalidation() throws Exception { .andExpect(status().isOk()); wireMockStubs.verifyNetworkModificationDeleteIndex(deleteModificationIndexStub); checkNodesInvalidationMessagesReceived(studyNameUserIdUuid, List.of(modificationNode2Uuid, modificationNode3Uuid)); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -2401,28 +2410,22 @@ void testRemoveLoadFlowComputationReport() throws Exception { UUID rootNodeUuid = getRootNode(studyNameUserIdUuid).getId(); NetworkModificationNode modificationNode1 = createNetworkModificationNode(studyNameUserIdUuid, rootNodeUuid, UUID.randomUUID(), VARIANT_ID, "node 1", NetworkModificationNodeType.SECURITY, BuildStatus.BUILT, userId); UUID modificationNode1Uuid = modificationNode1.getId(); - // In this node, let's say we have all computations results + // In this node, let's say we have all computation results RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity = rootNetworkNodeInfoRepository.findByNodeInfoIdAndRootNetworkId(modificationNode1Uuid, studyTestUtils.getOneRootNetworkUuid(studyNameUserIdUuid)).orElseThrow(() -> new StudyException(NOT_FOUND, "Root network not found")); rootNetworkNodeInfoEntity.setLoadFlowResultUuid(UUID.fromString(LOADFLOW_RESULT_UUID)); rootNetworkNodeInfoEntity.setSecurityAnalysisResultUuid(UUID.fromString(SECURITY_ANALYSIS_RESULT_UUID)); rootNetworkNodeInfoEntity.setDynamicSimulationResultUuid(UUID.fromString(DYNAMIC_SIMULATION_RESULT_UUID)); rootNetworkNodeInfoEntity.setDynamicSecurityAnalysisResultUuid(UUID.fromString(DYNAMIC_SECURITY_ANALYSIS_RESULT_UUID)); + rootNetworkNodeInfoEntity.setDynamicMarginCalculationResultUuid(UUID.fromString(DYNAMIC_MARGIN_CALCULATION_RESULT_UUID)); rootNetworkNodeInfoEntity.setSensitivityAnalysisResultUuid(UUID.fromString(SENSITIVITY_ANALYSIS_RESULT_UUID)); rootNetworkNodeInfoEntity.setShortCircuitAnalysisResultUuid(UUID.fromString(SHORTCIRCUIT_ANALYSIS_RESULT_UUID)); rootNetworkNodeInfoEntity.setOneBusShortCircuitAnalysisResultUuid(UUID.fromString(ONE_BUS_SHORTCIRCUIT_ANALYSIS_RESULT_UUID)); rootNetworkNodeInfoEntity.setVoltageInitResultUuid(UUID.fromString(VOLTAGE_INIT_RESULT_UUID)); rootNetworkNodeInfoEntity.setStateEstimationResultUuid(UUID.fromString(STATE_ESTIMATION_RESULT_UUID)); - rootNetworkNodeInfoEntity.setComputationReports(Map.of( - ComputationType.LOAD_FLOW.name(), UUID.randomUUID(), - ComputationType.SECURITY_ANALYSIS.name(), UUID.randomUUID(), - ComputationType.DYNAMIC_SIMULATION.name(), UUID.randomUUID(), - ComputationType.DYNAMIC_SECURITY_ANALYSIS.name(), UUID.randomUUID(), - ComputationType.SENSITIVITY_ANALYSIS.name(), UUID.randomUUID(), - ComputationType.SHORT_CIRCUIT.name(), UUID.randomUUID(), - ComputationType.SHORT_CIRCUIT_ONE_BUS.name(), UUID.randomUUID(), - ComputationType.VOLTAGE_INITIALIZATION.name(), UUID.randomUUID(), - ComputationType.STATE_ESTIMATION.name(), UUID.randomUUID() - )); + rootNetworkNodeInfoEntity.setPccMinResultUuid(UUID.fromString(PCC_MIN_RESULT_UUID)); + Map computationReportsMap = Arrays.stream(ComputationType.values()) + .collect(Collectors.toMap(ComputationType::name, computationType -> UUID.randomUUID())); + rootNetworkNodeInfoEntity.setComputationReports(computationReportsMap); rootNetworkNodeInfoRepository.save(rootNetworkNodeInfoEntity); // A modification body @@ -2443,7 +2446,7 @@ void testRemoveLoadFlowComputationReport() throws Exception { .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); checkNodesBuildStatusUpdatedMessageReceived(studyNameUserIdUuid, List.of(modificationNode1Uuid)); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -2451,18 +2454,20 @@ void testRemoveLoadFlowComputationReport() throws Exception { wireMockStubs.verifyNetworkModificationPostWithVariant(getModificationContextJsonString(mapper, modificationBody)); wireMockStubs.verifyNetworkModificationDeleteIndex(deleteModificationIndexStub); - // 1 status LF + 2 x 9 computations + 1 report + // 1 status LF + 2 x 10 computations + 1 report computationServerStubs.verifyDeleteResult(LOADFLOW_RESULT_UUID); computationServerStubs.verifyGetResultStatus(LOADFLOW_RESULT_UUID, 2); List.of( SECURITY_ANALYSIS_RESULT_UUID, DYNAMIC_SIMULATION_RESULT_UUID, DYNAMIC_SECURITY_ANALYSIS_RESULT_UUID, + DYNAMIC_MARGIN_CALCULATION_RESULT_UUID, SENSITIVITY_ANALYSIS_RESULT_UUID, SHORTCIRCUIT_ANALYSIS_RESULT_UUID, ONE_BUS_SHORTCIRCUIT_ANALYSIS_RESULT_UUID, VOLTAGE_INIT_RESULT_UUID, - STATE_ESTIMATION_RESULT_UUID + STATE_ESTIMATION_RESULT_UUID, + PCC_MIN_RESULT_UUID ).forEach(resultUuid -> { computationServerStubs.verifyDeleteResult(resultUuid); computationServerStubs.verifyGetResultStatus(resultUuid); @@ -2491,7 +2496,7 @@ void testUpdateOfBuildStatus() throws Exception { .content(jsonCreateLoadInfos).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -2513,7 +2518,7 @@ void testUpdateOfBuildStatus() throws Exception { .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); NetworkImpactsInfos expectedPayload = NetworkImpactsInfos.builder().impactedSubstationsIds(ImmutableSet.of("s1")).deletedEquipments(ImmutableSet.of()).build(); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); checkEquipmentMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, expectedPayload); @@ -2529,7 +2534,7 @@ void testUpdateOfBuildStatus() throws Exception { .content(jsonCreateLoadInfos).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); checkNodesBuildStatusUpdatedMessageReceived(studyNameUserIdUuid, List.of(modificationNodeUuid)); @@ -2546,7 +2551,7 @@ void testUpdateOfBuildStatus() throws Exception { .content(jsonCreateLoadInfos).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); checkNodesBuildStatusUpdatedMessageReceived(studyNameUserIdUuid, List.of(modificationNodeUuid)); @@ -2708,6 +2713,7 @@ private ComputationResultStubIds stubAllComputationResults() throws JsonProcessi getStatusStubIds.put(SECURITY_ANALYSIS_RESULT_UUID, computationServerStubs.stubGetResultStatus(SECURITY_ANALYSIS_RESULT_UUID, SECURITY_ANALYSIS_STATUS_JSON)); getStatusStubIds.put(DYNAMIC_SIMULATION_RESULT_UUID, computationServerStubs.stubGetResultStatus(DYNAMIC_SIMULATION_RESULT_UUID, objectMapper.writeValueAsString(DynamicSimulationStatus.CONVERGED))); getStatusStubIds.put(DYNAMIC_SECURITY_ANALYSIS_RESULT_UUID, computationServerStubs.stubGetResultStatus(DYNAMIC_SECURITY_ANALYSIS_RESULT_UUID, objectMapper.writeValueAsString(DynamicSecurityAnalysisStatus.SUCCEED))); + getStatusStubIds.put(DYNAMIC_MARGIN_CALCULATION_RESULT_UUID, computationServerStubs.stubGetResultStatus(DYNAMIC_MARGIN_CALCULATION_RESULT_UUID, objectMapper.writeValueAsString(DynamicMarginCalculationStatus.SUCCEED))); getStatusStubIds.put(SENSITIVITY_ANALYSIS_RESULT_UUID, computationServerStubs.stubGetResultStatus(SENSITIVITY_ANALYSIS_RESULT_UUID, SENSITIVITY_ANALYSIS_STATUS_JSON)); getStatusStubIds.put(SHORTCIRCUIT_ANALYSIS_RESULT_UUID, computationServerStubs.stubGetResultStatus(SHORTCIRCUIT_ANALYSIS_RESULT_UUID, SHORTCIRCUIT_ANALYSIS_STATUS_JSON)); getStatusStubIds.put(ONE_BUS_SHORTCIRCUIT_ANALYSIS_RESULT_UUID, computationServerStubs.stubGetResultStatus(ONE_BUS_SHORTCIRCUIT_ANALYSIS_RESULT_UUID, ONE_BUS_SHORTCIRCUIT_ANALYSIS_STATUS_JSON)); @@ -2727,31 +2733,6 @@ private void checkEquipmentCreatingMessagesReceived(UUID studyNameUserIdUuid, UU assertEquals(NotificationService.MODIFICATIONS_CREATING_IN_PROGRESS, headersStudyUpdate.get(NotificationService.HEADER_UPDATE_TYPE)); } - private void checkUpdateModelStatusMessagesReceived(UUID studyUuid, UUID nodeUuid, String updateType) { - // assert that the broker message has been sent for updating model status - Message messageStatus = output.receive(TIMEOUT, STUDY_UPDATE_DESTINATION); - assertEquals("", new String(messageStatus.getPayload())); - MessageHeaders headersStatus = messageStatus.getHeaders(); - assertEquals(studyUuid, headersStatus.get(NotificationService.HEADER_STUDY_UUID)); - if (nodeUuid != null) { - assertEquals(nodeUuid, headersStatus.get(NotificationService.HEADER_NODE)); - } - assertEquals(updateType, headersStatus.get(NotificationService.HEADER_UPDATE_TYPE)); - } - - private void checkUpdateModelsStatusMessagesReceived(UUID studyUuid, UUID nodeUuid) { - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_SECURITY_ANALYSIS_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_SENSITIVITY_ANALYSIS_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_SHORT_CIRCUIT_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_VOLTAGE_INIT_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_DYNAMIC_SIMULATION_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_STATE_ESTIMATION_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_PCC_MIN_STATUS); - } - private void checkNodesBuildStatusUpdatedMessageReceived(UUID studyUuid, List nodesUuids) { Message messageStatus = output.receive(TIMEOUT, STUDY_UPDATE_DESTINATION); assertEquals("", new String(messageStatus.getPayload())); @@ -2762,7 +2743,7 @@ private void checkNodesBuildStatusUpdatedMessageReceived(UUID studyUuid, List messageStudyUpdate = output.receive(TIMEOUT, STUDY_UPDATE_DESTINATION); - NetworkImpactsInfos actualPayload = mapper.readValue(new String(messageStudyUpdate.getPayload()), new TypeReference() { }); - assertThat(expectedPayload, new MatcherJson<>(mapper, actualPayload)); - MessageHeaders headersStudyUpdate = messageStudyUpdate.getHeaders(); - assertEquals(studyNameUserIdUuid, headersStudyUpdate.get(NotificationService.HEADER_STUDY_UUID)); - assertEquals(nodeUuid, headersStudyUpdate.get(NotificationService.HEADER_NODE)); - assertEquals(NotificationService.UPDATE_TYPE_STUDY, headersStudyUpdate.get(NotificationService.HEADER_UPDATE_TYPE)); - - checkNodesBuildStatusUpdatedMessageReceived(studyNameUserIdUuid, List.of(nodeUuid)); - - // assert that the broker message has been sent for updating load flow status - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, nodeUuid); - } - private void checkNodesInvalidationMessagesReceived(UUID studyNameUserIdUuid, List invalidatedNodes) { checkNodesBuildStatusUpdatedMessageReceived(studyNameUserIdUuid, invalidatedNodes); } @@ -2929,7 +2894,7 @@ void testCreateModificationWithErrors() throws Exception { .content(jsonCreateLoadInfos).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -2944,7 +2909,7 @@ void testCreateModificationWithErrors() throws Exception { .header(USER_ID_HEADER, userId)) .andExpect(status().isInternalServerError()) .andReturn(); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); wireMockStubs.verifyNetworkModificationPost(modificationBodyJson); @@ -2955,7 +2920,7 @@ void testCreateModificationWithErrors() throws Exception { .content(jsonCreateLoadInfos).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isInternalServerError()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); wireMockStubs.verifyNetworkModificationPost(modificationBodyJson); @@ -2967,7 +2932,7 @@ void testCreateModificationWithErrors() throws Exception { .content(jsonCreateLoadInfos).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isInternalServerError()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); wireMockStubs.verifyNetworkModificationPost(modificationBodyJson); diff --git a/src/test/java/org/gridsuite/study/server/NetworkModificationTreeTest.java b/src/test/java/org/gridsuite/study/server/NetworkModificationTreeTest.java index a295d7d5da..487348ab1e 100644 --- a/src/test/java/org/gridsuite/study/server/NetworkModificationTreeTest.java +++ b/src/test/java/org/gridsuite/study/server/NetworkModificationTreeTest.java @@ -28,6 +28,7 @@ import mockwebserver3.junit5.internal.MockWebServerExtension; import okhttp3.Headers; import okhttp3.HttpUrl; +import org.gridsuite.study.server.dto.ComputationType; import org.gridsuite.study.server.dto.RootNetworkNodeInfo; import org.gridsuite.study.server.dto.modification.NetworkModificationResult; import org.gridsuite.study.server.error.StudyException; @@ -43,9 +44,9 @@ import org.gridsuite.study.server.repository.rootnetwork.RootNetworkNodeInfoRepository; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkRepository; import org.gridsuite.study.server.service.*; +import org.gridsuite.study.server.service.client.dynamicmargincalculation.DynamicMarginCalculationClient; import org.gridsuite.study.server.service.client.dynamicsecurityanalysis.DynamicSecurityAnalysisClient; import org.gridsuite.study.server.service.client.dynamicsimulation.DynamicSimulationClient; -import org.gridsuite.study.server.service.LoadFlowService; import org.gridsuite.study.server.service.shortcircuit.ShortCircuitService; import org.gridsuite.study.server.utils.TestUtils; import org.gridsuite.study.server.utils.elasticsearch.DisableElasticsearch; @@ -75,12 +76,16 @@ import java.util.*; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; -import static org.gridsuite.study.server.error.StudyBusinessErrorCode.*; +import static org.gridsuite.study.server.error.StudyBusinessErrorCode.NOT_FOUND; import static org.gridsuite.study.server.notification.NotificationService.*; import static org.gridsuite.study.server.service.NetworkModificationTreeService.ROOT_NODE_NAME; +import static org.gridsuite.study.server.utils.TestUtils.checkUpdateStatusMessagesReceived; +import static org.gridsuite.study.server.utils.TestUtils.checkUpdateTypeMessageReceived; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.ArgumentMatchers.eq; @@ -176,6 +181,9 @@ class NetworkModificationTreeTest { @MockitoSpyBean DynamicSecurityAnalysisClient dynamicSecurityAnalysisClient; + @MockitoSpyBean + DynamicMarginCalculationClient dynamicMarginCalculationClient; + @MockitoBean private NetworkStoreService networkStoreService; @@ -269,6 +277,7 @@ public Set