diff --git a/pom.xml b/pom.xml index 38af7d349..bad0304b4 100644 --- a/pom.xml +++ b/pom.xml @@ -42,13 +42,11 @@ - 29 + 30 0.0.2 1.18.3 org.gridsuite.study.server 5.3 - - 1.11.1 @@ -84,24 +82,6 @@ - - - com.powsybl - powsybl-network-store-iidm-impl - ${powsybl-network-store.version} - - - - com.powsybl - powsybl-network-store-client - ${powsybl-network-store.version} - - - - com.powsybl - powsybl-network-store-model - ${powsybl-network-store.version} - diff --git a/src/main/java/org/gridsuite/study/server/RestResponseEntityExceptionHandler.java b/src/main/java/org/gridsuite/study/server/RestResponseEntityExceptionHandler.java index aa7bfc3d8..99c0b365e 100644 --- a/src/main/java/org/gridsuite/study/server/RestResponseEntityExceptionHandler.java +++ b/src/main/java/org/gridsuite/study/server/RestResponseEntityExceptionHandler.java @@ -43,7 +43,8 @@ protected ResponseEntity handleStudyException(StudyException exception) VOLTAGE_INIT_PARAMETERS_NOT_FOUND, SECURITY_ANALYSIS_PARAMETERS_NOT_FOUND, LOADFLOW_PARAMETERS_NOT_FOUND, - SENSITIVITY_ANALYSIS_PARAMETERS_NOT_FOUND + SENSITIVITY_ANALYSIS_PARAMETERS_NOT_FOUND, + STATE_ESTIMATION_NOT_FOUND -> ResponseEntity.status(HttpStatus.NOT_FOUND).body(exception.getType()); case CASE_NOT_FOUND -> ResponseEntity.status(HttpStatus.FAILED_DEPENDENCY).body(exception.getMessage()); case STUDY_ALREADY_EXISTS -> ResponseEntity.status(HttpStatus.CONFLICT).body(type); @@ -54,7 +55,8 @@ protected ResponseEntity handleStudyException(StudyException exception) NON_EVACUATED_ENERGY_RUNNING, DYNAMIC_SIMULATION_RUNNING, SHORT_CIRCUIT_ANALYSIS_RUNNING, - VOLTAGE_INIT_RUNNING + VOLTAGE_INIT_RUNNING, + STATE_ESTIMATION_RUNNING -> ResponseEntity.status(HttpStatus.FORBIDDEN).body(type); case NOT_ALLOWED, BAD_NODE_TYPE, diff --git a/src/main/java/org/gridsuite/study/server/StudyConstants.java b/src/main/java/org/gridsuite/study/server/StudyConstants.java index 9cbc9c661..38958b8d0 100644 --- a/src/main/java/org/gridsuite/study/server/StudyConstants.java +++ b/src/main/java/org/gridsuite/study/server/StudyConstants.java @@ -34,6 +34,7 @@ private StudyConstants() { public static final String TIME_SERIES_API_VERSION = "v1"; public static final String DYNAMIC_MAPPING_API_VERSION = ""; // mapping server is now without version, must be v1 in the next time public static final String FILTER_API_VERSION = "v1"; + public static final String STATE_ESTIMATION_API_VERSION = "v1"; public static final String NETWORK_UUID = "networkUuid"; public static final String CASE_UUID = "caseUuid"; diff --git a/src/main/java/org/gridsuite/study/server/StudyController.java b/src/main/java/org/gridsuite/study/server/StudyController.java index 5c07b32cf..97a612fed 100644 --- a/src/main/java/org/gridsuite/study/server/StudyController.java +++ b/src/main/java/org/gridsuite/study/server/StudyController.java @@ -78,6 +78,7 @@ public class StudyController { private final LoadFlowService loadflowService; private final CaseService caseService; private final RemoteServicesInspector remoteServicesInspector; + private final StateEstimationService stateEstimationService; public StudyController(StudyService studyService, NetworkService networkStoreService, @@ -91,7 +92,8 @@ public StudyController(StudyService studyService, VoltageInitService voltageInitService, LoadFlowService loadflowService, CaseService caseService, - RemoteServicesInspector remoteServicesInspector) { + RemoteServicesInspector remoteServicesInspector, + StateEstimationService stateEstimationService) { this.studyService = studyService; this.networkModificationTreeService = networkModificationTreeService; this.networkStoreService = networkStoreService; @@ -105,6 +107,7 @@ public StudyController(StudyService studyService, this.loadflowService = loadflowService; this.caseService = caseService; this.remoteServicesInspector = remoteServicesInspector; + this.stateEstimationService = stateEstimationService; } @InitBinder @@ -449,18 +452,17 @@ public ResponseEntity getSubstationMapData( return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(studyService.getSubstationMapData(studyUuid, nodeUuid, substationId, inUpstreamBuiltParentNode)); } - @GetMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/network/elements") + @PostMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/network/elements") @Operation(summary = "Get network elements infos") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The list of network elements infos")}) public ResponseEntity getNetworkElementsInfos( @PathVariable("studyUuid") UUID studyUuid, @PathVariable("nodeUuid") UUID nodeUuid, - @Parameter(description = "Substations id") @RequestParam(name = "substationsIds", required = false) List substationsIds, - @Parameter(description = "Element type") @RequestParam(name = "elementType") String elementType, + @RequestBody String equipmentInfos, @Parameter(description = "Info type") @RequestParam(name = "infoType") String infoType, @Parameter(description = "Should get in upstream built node ?") @RequestParam(value = "inUpstreamBuiltParentNode", required = false, defaultValue = "false") boolean inUpstreamBuiltParentNode) { - return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(studyService.getNetworkElementsInfos(studyUuid, nodeUuid, substationsIds, elementType, infoType, inUpstreamBuiltParentNode)); + return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(studyService.getNetworkElementsInfos(studyUuid, nodeUuid, equipmentInfos, infoType, inUpstreamBuiltParentNode)); } @GetMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/network/elements/{elementId}") @@ -1902,4 +1904,47 @@ public ResponseEntity exportFilter( @Parameter(description = "Filter uuid to be applied") @PathVariable("filterUuid") UUID filterUuid) { return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(studyService.exportFilter(studyUuid, filterUuid)); } + + @PostMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/state-estimation/run") + @Operation(summary = "run state estimation on study") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The state estimation has started")}) + public ResponseEntity runStateEstimation(@Parameter(description = "studyUuid") @PathVariable("studyUuid") UUID studyUuid, + @Parameter(description = "nodeUuid") @PathVariable("nodeUuid") UUID nodeUuid, + @RequestHeader(HEADER_USER_ID) String userId) { + studyService.assertIsNodeNotReadOnly(nodeUuid); + studyService.runStateEstimation(studyUuid, nodeUuid, userId); + return ResponseEntity.ok().build(); + } + + @GetMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/state-estimation/result") + @Operation(summary = "Get a state estimation result on study") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The state estimation result"), + @ApiResponse(responseCode = "204", description = "No state estimation has been done yet"), + @ApiResponse(responseCode = "404", description = "The state estimation has not been found")}) + public ResponseEntity getStateEstimationResult(@Parameter(description = "study UUID") @PathVariable("studyUuid") UUID studyUuid, + @Parameter(description = "nodeUuid") @PathVariable("nodeUuid") UUID nodeUuid) { + String result = stateEstimationService.getStateEstimationResult(nodeUuid); + return result != null ? ResponseEntity.ok().body(result) : + ResponseEntity.noContent().build(); + } + + @GetMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/state-estimation/status") + @Operation(summary = "Get the state estimation status on study") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The state estimation status"), + @ApiResponse(responseCode = "204", description = "No state estimation has been done yet"), + @ApiResponse(responseCode = "404", description = "The state estimation status has not been found")}) + public ResponseEntity getStateEstimationStatus(@Parameter(description = "Study UUID") @PathVariable("studyUuid") UUID studyUuid, + @Parameter(description = "nodeUuid") @PathVariable("nodeUuid") UUID nodeUuid) { + String status = stateEstimationService.getStateEstimationStatus(nodeUuid); + return status != null ? ResponseEntity.ok().body(status) : ResponseEntity.noContent().build(); + } + + @PutMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/state-estimation/stop") + @Operation(summary = "stop state estimation on study") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The state estimation has been stopped")}) + public ResponseEntity stopStateEstimation(@Parameter(description = "Study uuid") @PathVariable("studyUuid") UUID studyUuid, + @Parameter(description = "nodeUuid") @PathVariable("nodeUuid") UUID nodeUuid) { + stateEstimationService.stopStateEstimation(studyUuid, nodeUuid); + return ResponseEntity.ok().build(); + } } diff --git a/src/main/java/org/gridsuite/study/server/StudyException.java b/src/main/java/org/gridsuite/study/server/StudyException.java index 7de66394c..e0d8bfc9d 100644 --- a/src/main/java/org/gridsuite/study/server/StudyException.java +++ b/src/main/java/org/gridsuite/study/server/StudyException.java @@ -110,6 +110,9 @@ public enum Type { NOT_IMPLEMENTED, EVALUATE_FILTER_FAILED, GET_USER_PROFILE_FAILED, + STATE_ESTIMATION_RUNNING, + STATE_ESTIMATION_NOT_FOUND, + STATE_ESTIMATION_ERROR, } private final Type type; diff --git a/src/main/java/org/gridsuite/study/server/SupervisionController.java b/src/main/java/org/gridsuite/study/server/SupervisionController.java index 454eab482..ba1d0cefe 100644 --- a/src/main/java/org/gridsuite/study/server/SupervisionController.java +++ b/src/main/java/org/gridsuite/study/server/SupervisionController.java @@ -49,7 +49,7 @@ public SupervisionController(SupervisionService supervisionService, StudyService @DeleteMapping(value = "/computation/results") @Operation(summary = "delete all results of a given computation") - @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "all loadflow results have been deleted")}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "all computation results have been deleted")}) public ResponseEntity deleteComputationResults(@Parameter(description = "Computation type") @RequestParam("type") ComputationType computationType, @Parameter(description = "Dry run") @RequestParam("dryRun") boolean dryRun) { return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(supervisionService.deleteComputationResults(computationType, dryRun)); 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 2ad6736ba..840af1476 100644 --- a/src/main/java/org/gridsuite/study/server/dto/ComputationType.java +++ b/src/main/java/org/gridsuite/study/server/dto/ComputationType.java @@ -28,7 +28,10 @@ public enum ComputationType { NotificationService.UPDATE_TYPE_DYNAMIC_SIMULATION_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); + NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_FAILED), + STATE_ESTIMATION("State estimation", "stateEstimationResultUuid", + NotificationService.UPDATE_TYPE_STATE_ESTIMATION_STATUS, NotificationService.UPDATE_TYPE_STATE_ESTIMATION_RESULT, + NotificationService.UPDATE_TYPE_STATE_ESTIMATION_FAILED); private final String label; // used for logs private final String resultUuidLabel; 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 7294f9160..2a3fcac8a 100644 --- a/src/main/java/org/gridsuite/study/server/dto/DeleteNodeInfos.java +++ b/src/main/java/org/gridsuite/study/server/dto/DeleteNodeInfos.java @@ -43,6 +43,8 @@ public class DeleteNodeInfos { private List voltageInitResultUuids = new ArrayList<>(); private List dynamicSimulationResultUuids = new ArrayList<>(); + private List stateEstimationResultUuids = new ArrayList<>(); + public void addModificationGroupUuid(UUID modificationGroupUuid) { modificationGroupUuids.add(modificationGroupUuid); } @@ -86,4 +88,8 @@ public void addOneBusShortCircuitAnalysisResultUuid(UUID oneBusShortCircuitAnaly public void addVoltageInitResultUuid(UUID voltageInitResultUuid) { voltageInitResultUuids.add(voltageInitResultUuid); } + + public void addStateEstimationResultUuid(UUID stateEstimationResultUuid) { + stateEstimationResultUuids.add(stateEstimationResultUuid); + } } 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 cba3ee746..962b7c3c6 100644 --- a/src/main/java/org/gridsuite/study/server/dto/InvalidateNodeInfos.java +++ b/src/main/java/org/gridsuite/study/server/dto/InvalidateNodeInfos.java @@ -46,6 +46,8 @@ public class InvalidateNodeInfos { private List voltageInitResultUuids = new ArrayList<>(); private List dynamicSimulationResultUuids = new ArrayList<>(); + private List stateEstimationResultUuids = new ArrayList<>(); + public void addReportUuid(UUID reportUuid) { reportUuids.add(reportUuid); } @@ -92,4 +94,8 @@ public void addVoltageInitResultUuid(UUID voltageInitResultUuid) { public void addDynamicSimulationResultUuid(UUID dynamicSimulationResultUuid) { dynamicSimulationResultUuids.add(dynamicSimulationResultUuid); } + + public void addStateEstimationResultUuid(UUID stateEstimationResultUuid) { + stateEstimationResultUuids.add(stateEstimationResultUuid); + } } diff --git a/src/main/java/org/gridsuite/study/server/dto/NodeModificationInfos.java b/src/main/java/org/gridsuite/study/server/dto/NodeModificationInfos.java index 6ea77f791..8426984ec 100644 --- a/src/main/java/org/gridsuite/study/server/dto/NodeModificationInfos.java +++ b/src/main/java/org/gridsuite/study/server/dto/NodeModificationInfos.java @@ -40,4 +40,6 @@ public class NodeModificationInfos { private UUID voltageInitUuid; private UUID dynamicSimulationUuid; + + private UUID stateEstimationUuid; } diff --git a/src/main/java/org/gridsuite/study/server/dto/StateEstimationStatus.java b/src/main/java/org/gridsuite/study/server/dto/StateEstimationStatus.java new file mode 100644 index 000000000..3352745c5 --- /dev/null +++ b/src/main/java/org/gridsuite/study/server/dto/StateEstimationStatus.java @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2024, 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; + +/** + * @author Franck Lecuyer + */ +public enum StateEstimationStatus { + NOT_DONE, + RUNNING, + COMPLETED, +} diff --git a/src/main/java/org/gridsuite/study/server/elasticsearch/EquipmentInfosService.java b/src/main/java/org/gridsuite/study/server/elasticsearch/EquipmentInfosService.java index 0cb674227..ef6630d32 100644 --- a/src/main/java/org/gridsuite/study/server/elasticsearch/EquipmentInfosService.java +++ b/src/main/java/org/gridsuite/study/server/elasticsearch/EquipmentInfosService.java @@ -289,14 +289,14 @@ private String buildTombstonedEquipmentSearchQuery(UUID networkUuid, String vari return String.format(NETWORK_UUID + ":(%s) AND " + VARIANT_ID + ":(%s)", networkUuid, variantId); } - private BoolQuery buildSearchEquipmentsQuery(String userInput, EquipmentInfosService.FieldSelector fieldSelector, UUID networkUuid, String initialVariantId, String variantId, String equipmentType) { + private BoolQuery buildSearchEquipmentsQuery(String userInput, EquipmentInfosService.FieldSelector fieldSelector, UUID networkUuid, String variantId, String equipmentType) { // If search requires boolean logic or advanced text analysis, then use queryStringQuery. // Otherwise, use wildcardQuery for simple text search. WildcardQuery equipmentSearchQuery = Queries.wildcardQuery(fieldSelector == EquipmentInfosService.FieldSelector.NAME ? EQUIPMENT_NAME : EQUIPMENT_ID, "*" + escapeLucene(userInput) + "*"); TermQuery networkUuidSearchQuery = Queries.termQuery(NETWORK_UUID, networkUuid.toString()); TermsQuery variantIdSearchQuery = variantId.equals(VariantManagerConstants.INITIAL_VARIANT_ID) ? - new TermsQuery.Builder().field(VARIANT_ID).terms(new TermsQueryField.Builder().value(List.of(FieldValue.of(initialVariantId))).build()).build() : - new TermsQuery.Builder().field(VARIANT_ID).terms(new TermsQueryField.Builder().value(List.of(FieldValue.of(initialVariantId), FieldValue.of(variantId))).build()).build(); + new TermsQuery.Builder().field(VARIANT_ID).terms(new TermsQueryField.Builder().value(List.of(FieldValue.of(VariantManagerConstants.INITIAL_VARIANT_ID))).build()).build() : + new TermsQuery.Builder().field(VARIANT_ID).terms(new TermsQueryField.Builder().value(List.of(FieldValue.of(VariantManagerConstants.INITIAL_VARIANT_ID), FieldValue.of(variantId))).build()).build(); BoolQuery.Builder boolQueryBuilder = new BoolQuery.Builder() .filter( @@ -341,7 +341,9 @@ private List cleanRemovedEquipments(UUID networkUuid, String var return equipmentInfos .stream() - .filter(ei -> !removedEquipmentIdsInVariant.contains(ei.getId())) + .filter(ei -> !removedEquipmentIdsInVariant.contains(ei.getId()) || + // If the equipment has been recreated after the creation of a deletion hypothesis + !ei.getVariantId().equals(VariantManagerConstants.INITIAL_VARIANT_ID)) .collect(Collectors.toList()); } @@ -354,7 +356,7 @@ public List searchEquipments(@lombok.NonNull UUID networkUuid, @ String effectiveVariantId = variantId.isEmpty() ? VariantManagerConstants.INITIAL_VARIANT_ID : variantId; BoolQuery query = buildSearchEquipmentsQuery(userInput, fieldSelector, networkUuid, - VariantManagerConstants.INITIAL_VARIANT_ID, variantId, equipmentType); + variantId, equipmentType); List equipmentInfos = searchEquipments(query); return variantId.equals(VariantManagerConstants.INITIAL_VARIANT_ID) ? equipmentInfos : cleanModifiedAndRemovedEquipments(networkUuid, effectiveVariantId, equipmentInfos); } diff --git a/src/main/java/org/gridsuite/study/server/networkmodificationtree/NetworkModificationNodeInfoRepositoryProxy.java b/src/main/java/org/gridsuite/study/server/networkmodificationtree/NetworkModificationNodeInfoRepositoryProxy.java index 09c4f586c..2331f5a46 100644 --- a/src/main/java/org/gridsuite/study/server/networkmodificationtree/NetworkModificationNodeInfoRepositoryProxy.java +++ b/src/main/java/org/gridsuite/study/server/networkmodificationtree/NetworkModificationNodeInfoRepositoryProxy.java @@ -58,6 +58,7 @@ public NetworkModificationNodeInfoEntity toEntity(AbstractNode node) { modificationNode.getSensitivityAnalysisResultUuid(), modificationNode.getNonEvacuatedEnergyResultUuid(), modificationNode.getDynamicSimulationResultUuid(), + modificationNode.getStateEstimationResultUuid(), modificationNode.getNodeBuildStatus().toEntity()); return completeEntityNodeInfo(node, networkModificationNodeInfoEntity); } @@ -77,6 +78,7 @@ public NetworkModificationNode toDto(NetworkModificationNodeInfoEntity node) { node.getSensitivityAnalysisResultUuid(), node.getNonEvacuatedEnergyResultUuid(), node.getDynamicSimulationResultUuid(), + node.getStateEstimationResultUuid(), node.getNodeBuildStatus().toDto())); } @@ -125,6 +127,7 @@ public void updateComputationResultUuid(AbstractNode node, UUID computationUuid, case SHORT_CIRCUIT_ONE_BUS -> modificationNode.setOneBusShortCircuitAnalysisResultUuid(computationUuid); case VOLTAGE_INITIALIZATION -> modificationNode.setVoltageInitResultUuid(computationUuid); case DYNAMIC_SIMULATION -> modificationNode.setDynamicSimulationResultUuid(computationUuid); + case STATE_ESTIMATION -> modificationNode.setStateEstimationResultUuid(computationUuid); } updateNode(modificationNode, computationType.getResultUuidLabel()); } @@ -140,6 +143,7 @@ public UUID getComputationResultUuid(AbstractNode node, ComputationType computat case SHORT_CIRCUIT_ONE_BUS -> ((NetworkModificationNode) node).getOneBusShortCircuitAnalysisResultUuid(); case VOLTAGE_INITIALIZATION -> ((NetworkModificationNode) node).getVoltageInitResultUuid(); case DYNAMIC_SIMULATION -> ((NetworkModificationNode) node).getDynamicSimulationResultUuid(); + case STATE_ESTIMATION -> ((NetworkModificationNode) node).getStateEstimationResultUuid(); }; } @@ -189,6 +193,7 @@ public NodeModificationInfos getNodeModificationInfos(AbstractNode node) { .oneBusShortCircuitAnalysisUuid(networkModificationNode.getOneBusShortCircuitAnalysisResultUuid()) .voltageInitUuid(networkModificationNode.getVoltageInitResultUuid()) .dynamicSimulationUuid(networkModificationNode.getDynamicSimulationResultUuid()) + .stateEstimationUuid(networkModificationNode.getStateEstimationResultUuid()) .build(); } } 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 752884956..491d4632d 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 @@ -51,6 +51,8 @@ public class NetworkModificationNode extends AbstractNode { private UUID dynamicSimulationResultUuid; + private UUID stateEstimationResultUuid; + private NodeBuildStatus nodeBuildStatus; @Override diff --git a/src/main/java/org/gridsuite/study/server/networkmodificationtree/entities/NetworkModificationNodeInfoEntity.java b/src/main/java/org/gridsuite/study/server/networkmodificationtree/entities/NetworkModificationNodeInfoEntity.java index cf7afdc1e..c7586399a 100644 --- a/src/main/java/org/gridsuite/study/server/networkmodificationtree/entities/NetworkModificationNodeInfoEntity.java +++ b/src/main/java/org/gridsuite/study/server/networkmodificationtree/entities/NetworkModificationNodeInfoEntity.java @@ -62,6 +62,9 @@ public class NetworkModificationNodeInfoEntity extends AbstractNodeInfoEntity { @Column(name = "dynamicSimulationResultUuid") private UUID dynamicSimulationResultUuid; + @Column(name = "stateEstimationResultUuid") + private UUID stateEstimationResultUuid; + @Embedded @AttributeOverrides(value = { @AttributeOverride(name = "localBuildStatus", column = @Column(name = "localBuildStatus", nullable = false)), 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 4c29b6c35..d534bbdbf 100644 --- a/src/main/java/org/gridsuite/study/server/notification/NotificationService.java +++ b/src/main/java/org/gridsuite/study/server/notification/NotificationService.java @@ -76,6 +76,9 @@ public class NotificationService { public static final String UPDATE_TYPE_STUDY = "study"; public static final String UPDATE_TYPE_STUDY_METADATA_UPDATED = "metadata_updated"; public static final String UPDATE_TYPE_INDEXATION_STATUS = "indexation_status_updated"; + public static final String UPDATE_TYPE_STATE_ESTIMATION_FAILED = "stateEstimation_failed"; + public static final String UPDATE_TYPE_STATE_ESTIMATION_RESULT = "stateEstimationResult"; + public static final String UPDATE_TYPE_STATE_ESTIMATION_STATUS = "stateEstimation_status"; public static final String MODIFICATIONS_CREATING_IN_PROGRESS = "creatingInProgress"; public static final String MODIFICATIONS_STASHING_IN_PROGRESS = "stashingInProgress"; diff --git a/src/main/java/org/gridsuite/study/server/repository/networkmodificationtree/NetworkModificationNodeInfoRepository.java b/src/main/java/org/gridsuite/study/server/repository/networkmodificationtree/NetworkModificationNodeInfoRepository.java index ee30629ce..2d5967f28 100644 --- a/src/main/java/org/gridsuite/study/server/repository/networkmodificationtree/NetworkModificationNodeInfoRepository.java +++ b/src/main/java/org/gridsuite/study/server/repository/networkmodificationtree/NetworkModificationNodeInfoRepository.java @@ -36,4 +36,6 @@ public interface NetworkModificationNodeInfoRepository extends NodeInfoRepositor List findAllByNodeStudyId(UUID studyUuid); List findAllByNodeStudyIdAndName(UUID studyUuid, String name); + + List findAllByStateEstimationResultUuidNotNull(); } 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 8f9ffb205..f03e4ee8b 100644 --- a/src/main/java/org/gridsuite/study/server/service/ConsumerService.java +++ b/src/main/java/org/gridsuite/study/server/service/ConsumerService.java @@ -515,4 +515,19 @@ public Consumer> consumeVoltageInitStopped() { public Consumer> consumeVoltageInitFailed() { return message -> consumeCalculationFailed(message, VOLTAGE_INITIALIZATION); } + + @Bean + public Consumer> consumeStateEstimationResult() { + return message -> consumeCalculationResult(message, STATE_ESTIMATION); + } + + @Bean + public Consumer> consumeStateEstimationStopped() { + return message -> consumeCalculationStopped(message, STATE_ESTIMATION); + } + + @Bean + public Consumer> consumeStateEstimationFailed() { + return message -> consumeCalculationFailed(message, STATE_ESTIMATION); + } } diff --git a/src/main/java/org/gridsuite/study/server/service/NetworkMapService.java b/src/main/java/org/gridsuite/study/server/service/NetworkMapService.java index 2f4f47537..689f82a95 100644 --- a/src/main/java/org/gridsuite/study/server/service/NetworkMapService.java +++ b/src/main/java/org/gridsuite/study/server/service/NetworkMapService.java @@ -54,16 +54,14 @@ public NetworkMapService(RemoteServicesProperties remoteServicesProperties, Rest this.restTemplate = restTemplate; } - public String getElementsInfos(UUID networkUuid, String variantId, List substationsIds, String elementType, String infoType, double dcPowerFactor) { + public String getElementsInfos(UUID networkUuid, String variantId, String equipmentInfos, String infoType, double dcPowerFactor) { String path = DELIMITER + NETWORK_MAP_API_VERSION + "/networks/{networkUuid}/elements"; UriComponentsBuilder builder = UriComponentsBuilder.fromPath(path); - if (substationsIds != null) { - builder = builder.queryParam(QUERY_PARAM_SUBSTATIONS_IDS, substationsIds); - } + if (!StringUtils.isBlank(variantId)) { builder = builder.queryParam(QUERY_PARAM_VARIANT_ID, variantId); } - builder = builder.queryParam(QUERY_PARAM_ELEMENT_TYPE, elementType); + builder = builder.queryParam(QUERY_PARAM_INFO_TYPE, infoType); InfoTypeParameters infoTypeParameters = InfoTypeParameters.builder() @@ -71,7 +69,11 @@ public String getElementsInfos(UUID networkUuid, String variantId, List .build(); queryParamInfoTypeParameters(infoTypeParameters, builder); String url = builder.buildAndExpand(networkUuid).toUriString(); - return restTemplate.getForObject(networkMapServerBaseUri + url, String.class); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity httpEntity = new HttpEntity<>(equipmentInfos, headers); + return restTemplate.postForObject(networkMapServerBaseUri + url, httpEntity, String.class); } public String getElementInfos(UUID networkUuid, String variantId, String elementType, String infoType, String operation, double dcPowerFactor, String elementId) { diff --git a/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java b/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java index 936c009b5..6d9296bcd 100644 --- a/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java +++ b/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java @@ -40,6 +40,7 @@ import static org.gridsuite.study.server.dto.ComputationType.SHORT_CIRCUIT; import static org.gridsuite.study.server.dto.ComputationType.SHORT_CIRCUIT_ONE_BUS; import static org.gridsuite.study.server.dto.ComputationType.VOLTAGE_INITIALIZATION; +import static org.gridsuite.study.server.dto.ComputationType.STATE_ESTIMATION; /** * @author Jacques Borsenberger node.setParentNode(nodeToDelete.getParentNode())); } else { @@ -454,6 +461,7 @@ public void cloneStudyTree(AbstractNode nodeToDuplicate, UUID nodeParentId, Stud model.setShortCircuitAnalysisResultUuid(null); model.setOneBusShortCircuitAnalysisResultUuid(null); model.setVoltageInitResultUuid(null); + model.setStateEstimationResultUuid(null); nextParentId = self.createNode(study.getId(), referenceParentNodeId, model, InsertMode.CHILD, null).getId(); networkModificationService.createModifications(modificationGroupToDuplicateId, newModificationGroupId); @@ -804,6 +812,12 @@ private void fillInvalidateNodeInfos(NodeEntity node, InvalidateNodeInfos invali } } + UUID stateEstimationResultUuid = repositories.get(node.getType()).getComputationResultUuid(node.getIdNode(), STATE_ESTIMATION); + if (stateEstimationResultUuid != null) { + invalidateNodeInfos.addStateEstimationResultUuid(stateEstimationResultUuid); + reportTypes.add(StudyService.ReportType.STATE_ESTIMATION); + } + invalidateNodeInfos.addReportTypes(reportUuid, reportTypes); } @@ -863,6 +877,7 @@ private void invalidateNodeProper(NodeEntity child, InvalidateNodeInfos invalida if (deleteVoltageInitResults) { nodeRepository.updateComputationResultUuid(childUuid, null, VOLTAGE_INITIALIZATION); } + nodeRepository.updateComputationResultUuid(childUuid, null, STATE_ESTIMATION); } } diff --git a/src/main/java/org/gridsuite/study/server/service/StateEstimationService.java b/src/main/java/org/gridsuite/study/server/service/StateEstimationService.java new file mode 100644 index 000000000..9ec9ddfd6 --- /dev/null +++ b/src/main/java/org/gridsuite/study/server/service/StateEstimationService.java @@ -0,0 +1,191 @@ +/** + * Copyright (c) 2024, 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; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; +import org.gridsuite.study.server.RemoteServicesProperties; +import org.gridsuite.study.server.StudyException; +import org.gridsuite.study.server.dto.ComputationType; +import org.gridsuite.study.server.dto.NodeReceiver; +import org.gridsuite.study.server.dto.ReportInfos; +import org.gridsuite.study.server.dto.StateEstimationStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpStatusCodeException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.io.UncheckedIOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +import static org.gridsuite.study.server.StudyConstants.DELIMITER; +import static org.gridsuite.study.server.StudyConstants.HEADER_USER_ID; +import static org.gridsuite.study.server.StudyConstants.QUERY_PARAM_RECEIVER; +import static org.gridsuite.study.server.StudyConstants.QUERY_PARAM_VARIANT_ID; +import static org.gridsuite.study.server.StudyConstants.STATE_ESTIMATION_API_VERSION; +import static org.gridsuite.study.server.StudyException.Type.DELETE_COMPUTATION_RESULTS_FAILED; +import static org.gridsuite.study.server.StudyException.Type.STATE_ESTIMATION_NOT_FOUND; +import static org.gridsuite.study.server.StudyException.Type.STATE_ESTIMATION_RUNNING; +import static org.gridsuite.study.server.utils.StudyUtils.handleHttpError; + +/** + * @author Franck Lecuyer + */ +@Service +public class StateEstimationService { + + static final String RESULT_UUID = "resultUuid"; + + private final RestTemplate restTemplate; + + private final ObjectMapper objectMapper; + + @Setter + private String stateEstimationServerServerBaseUri; + + private final NetworkModificationTreeService networkModificationTreeService; + + @Autowired + public StateEstimationService(RemoteServicesProperties remoteServicesProperties, + NetworkModificationTreeService networkModificationTreeService, + ObjectMapper objectMapper, RestTemplate restTemplate) { + this.stateEstimationServerServerBaseUri = remoteServicesProperties.getServiceUri("state-estimation-server"); + this.networkModificationTreeService = networkModificationTreeService; + this.objectMapper = objectMapper; + this.restTemplate = restTemplate; + } + + public String getStateEstimationResult(UUID nodeUuid) { + String result; + Optional resultUuidOpt = networkModificationTreeService.getComputationResultUuid(nodeUuid, ComputationType.STATE_ESTIMATION); + + if (resultUuidOpt.isEmpty()) { + return null; + } + + UriComponentsBuilder pathBuilder = UriComponentsBuilder.fromPath(DELIMITER + STATE_ESTIMATION_API_VERSION + "/results/{resultUuid}"); + String path = pathBuilder.buildAndExpand(resultUuidOpt.get()).toUriString(); + + try { + result = restTemplate.getForObject(stateEstimationServerServerBaseUri + path, String.class); + } catch (HttpStatusCodeException e) { + if (HttpStatus.NOT_FOUND.equals(e.getStatusCode())) { + throw new StudyException(STATE_ESTIMATION_NOT_FOUND); + } else { + throw e; + } + } + + return result; + } + + public UUID runStateEstimation(UUID networkUuid, String variantId, ReportInfos reportInfos, String receiver, String userId) { + var uriComponentsBuilder = UriComponentsBuilder + .fromPath(DELIMITER + STATE_ESTIMATION_API_VERSION + "/networks/{networkUuid}/run-and-save") + .queryParam("reportUuid", reportInfos.reportUuid().toString()) + .queryParam("reporterId", reportInfos.reporterId()) + .queryParam("reportType", StudyService.ReportType.STATE_ESTIMATION.reportKey); + if (!StringUtils.isBlank(variantId)) { + uriComponentsBuilder.queryParam(QUERY_PARAM_VARIANT_ID, variantId); + } + var path = uriComponentsBuilder.queryParam(QUERY_PARAM_RECEIVER, receiver).buildAndExpand(networkUuid).toUriString(); + + HttpHeaders headers = new HttpHeaders(); + headers.set(HEADER_USER_ID, userId); + headers.setContentType(MediaType.APPLICATION_JSON); + + HttpEntity httpEntity = new HttpEntity<>(null, headers); + + return restTemplate.exchange(stateEstimationServerServerBaseUri + path, HttpMethod.POST, httpEntity, UUID.class).getBody(); + } + + public void stopStateEstimation(UUID studyUuid, UUID nodeUuid) { + Objects.requireNonNull(studyUuid); + Objects.requireNonNull(nodeUuid); + + Optional resultUuidOpt = networkModificationTreeService.getComputationResultUuid(nodeUuid, ComputationType.STATE_ESTIMATION); + + if (resultUuidOpt.isEmpty()) { + return; + } + + String receiver; + try { + receiver = URLEncoder.encode(objectMapper.writeValueAsString(new NodeReceiver(nodeUuid)), StandardCharsets.UTF_8); + } catch (JsonProcessingException e) { + throw new UncheckedIOException(e); + } + + String path = UriComponentsBuilder + .fromPath(DELIMITER + STATE_ESTIMATION_API_VERSION + "/results/{resultUuid}/stop") + .queryParam(QUERY_PARAM_RECEIVER, receiver).buildAndExpand(resultUuidOpt.get()).toUriString(); + + restTemplate.put(stateEstimationServerServerBaseUri + path, Void.class); + } + + public String getStateEstimationStatus(UUID nodeUuid) { + Optional resultUuidOpt = networkModificationTreeService.getComputationResultUuid(nodeUuid, ComputationType.STATE_ESTIMATION); + if (resultUuidOpt.isEmpty()) { + return null; + } + String status; + try { + String path = UriComponentsBuilder + .fromPath(DELIMITER + STATE_ESTIMATION_API_VERSION + "/results/{resultUuid}/status") + .buildAndExpand(resultUuidOpt.get()).toUriString(); + status = restTemplate.getForObject(stateEstimationServerServerBaseUri + path, String.class); + } catch (HttpStatusCodeException e) { + if (HttpStatus.NOT_FOUND.equals(e.getStatusCode())) { + throw new StudyException(STATE_ESTIMATION_NOT_FOUND); + } + throw e; + } + return status; + } + + public void deleteStateEstimationResult(UUID uuid) { + String path = UriComponentsBuilder.fromPath(DELIMITER + STATE_ESTIMATION_API_VERSION + "/results/{resultUuid}") + .buildAndExpand(uuid) + .toUriString(); + + restTemplate.delete(stateEstimationServerServerBaseUri + path); + } + + public void deleteStateEstimationResults() { + try { + String path = UriComponentsBuilder.fromPath(DELIMITER + STATE_ESTIMATION_API_VERSION + "/results").toUriString(); + restTemplate.delete(stateEstimationServerServerBaseUri + path); + } catch (HttpStatusCodeException e) { + throw handleHttpError(e, DELETE_COMPUTATION_RESULTS_FAILED); + } + } + + public Integer getStateEstimationResultsCount() { + String path = UriComponentsBuilder + .fromPath(DELIMITER + STATE_ESTIMATION_API_VERSION + "/supervision/results-count").toUriString(); + return restTemplate.getForObject(stateEstimationServerServerBaseUri + path, Integer.class); + } + + public void assertStateEstimationNotRunning(UUID nodeUuid) { + String status = getStateEstimationStatus(nodeUuid); + if (StateEstimationStatus.RUNNING.name().equals(status)) { + throw new StudyException(STATE_ESTIMATION_RUNNING); + } + } +} 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 9414c7454..70a69cdaa 100644 --- a/src/main/java/org/gridsuite/study/server/service/StudyService.java +++ b/src/main/java/org/gridsuite/study/server/service/StudyService.java @@ -121,6 +121,7 @@ public class StudyService { private final FilterService filterService; private final ActionsService actionsService; private final CaseService caseService; + private final StateEstimationService stateEstimationService; private final ObjectMapper objectMapper; @@ -137,7 +138,8 @@ public enum ReportType { SENSITIVITY_ANALYSIS("SensitivityAnalysis"), DYNAMIC_SIMULATION("DynamicSimulation"), NON_EVACUATED_ENERGY_ANALYSIS("NonEvacuatedEnergyAnalysis"), - VOLTAGE_INITIALIZATION("VoltageInit"); + VOLTAGE_INITIALIZATION("VoltageInit"), + STATE_ESTIMATION("StateEstimation"); public final String reportKey; @@ -179,6 +181,7 @@ public StudyService( VoltageInitService voltageInitService, DynamicSimulationEventService dynamicSimulationEventService, FilterService filterService, + StateEstimationService stateEstimationService, @Lazy StudyService studyService) { this.defaultNonEvacuatedEnergyProvider = defaultNonEvacuatedEnergyProvider; this.defaultDynamicSimulationProvider = defaultDynamicSimulationProvider; @@ -209,6 +212,7 @@ public StudyService( this.voltageInitService = voltageInitService; this.dynamicSimulationEventService = dynamicSimulationEventService; this.filterService = filterService; + this.stateEstimationService = stateEstimationService; this.self = studyService; } @@ -447,6 +451,8 @@ public void deleteStudyIfNotCreationInProgress(UUID studyUuid, String userId) { .map(NodeModificationInfos::getVoltageInitUuid).filter(Objects::nonNull).forEach(voltageInitService::deleteVoltageInitResult)), // TODO delete all with one request only studyServerExecutionService.runAsync(() -> deleteStudyInfos.getNodesModificationInfos().stream() .map(NodeModificationInfos::getDynamicSimulationUuid).filter(Objects::nonNull).forEach(dynamicSimulationService::deleteResult)), // TODO delete all with one request only + studyServerExecutionService.runAsync(() -> deleteStudyInfos.getNodesModificationInfos().stream() + .map(NodeModificationInfos::getStateEstimationUuid).filter(Objects::nonNull).forEach(stateEstimationService::deleteStateEstimationResult)), // TODO delete all with one request only studyServerExecutionService.runAsync(() -> deleteStudyInfos.getNodesModificationInfos().stream().map(NodeModificationInfos::getModificationGroupUuid).filter(Objects::nonNull).forEach(networkModificationService::deleteModifications)), // TODO delete all with one request only studyServerExecutionService.runAsync(() -> deleteStudyInfos.getNodesModificationInfos().stream().map(NodeModificationInfos::getReportUuid).filter(Objects::nonNull).forEach(reportService::deleteReport)), // TODO delete all with one request only studyServerExecutionService.runAsync(() -> deleteEquipmentIndexes(deleteStudyInfos.getNetworkUuid())), @@ -636,12 +642,12 @@ public String getSubstationMapData(UUID studyUuid, UUID nodeUuid, String substat "substations", substationId); } - public String getNetworkElementsInfos(UUID studyUuid, UUID nodeUuid, List substationsIds, String elementType, String infoType, boolean inUpstreamBuiltParentNode) { + public String getNetworkElementsInfos(UUID studyUuid, UUID nodeUuid, String equipmentInfos, String infoType, boolean inUpstreamBuiltParentNode) { UUID nodeUuidToSearchIn = getNodeUuidToSearchIn(nodeUuid, inUpstreamBuiltParentNode); StudyEntity studyEntity = studyRepository.findById(studyUuid).orElseThrow(() -> new StudyException(STUDY_NOT_FOUND)); LoadFlowParameters loadFlowParameters = getLoadFlowParameters(studyEntity); return networkMapService.getElementsInfos(networkStoreService.getNetworkUuid(studyUuid), networkModificationTreeService.getVariantId(nodeUuidToSearchIn), - substationsIds, elementType, infoType, loadFlowParameters.getDcPowerFactor()); + equipmentInfos, infoType, loadFlowParameters.getDcPowerFactor()); } public String getNetworkElementInfos(UUID studyUuid, UUID nodeUuid, String elementType, InfoTypeParameters infoTypeParameters, String elementId, boolean inUpstreamBuiltParentNode) { @@ -716,6 +722,7 @@ private void assertComputationNotRunning(UUID nodeUuid) { nonEvacuatedEnergyService.assertNonEvacuatedEnergyNotRunning(nodeUuid); shortCircuitService.assertShortCircuitAnalysisNotRunning(nodeUuid); voltageInitService.assertVoltageInitNotRunning(nodeUuid); + stateEstimationService.assertStateEstimationNotRunning(nodeUuid); } public void assertIsNodeNotReadOnly(UUID nodeUuid) { @@ -1336,6 +1343,7 @@ public void invalidateBuild(UUID studyUuid, UUID nodeUuid, boolean invalidateOnl studyServerExecutionService.runAsync(() -> invalidateNodeInfos.getOneBusShortCircuitAnalysisResultUuids().forEach(shortCircuitService::deleteShortCircuitAnalysisResult)), studyServerExecutionService.runAsync(() -> invalidateNodeInfos.getVoltageInitResultUuids().forEach(voltageInitService::deleteVoltageInitResult)), studyServerExecutionService.runAsync(() -> invalidateNodeInfos.getDynamicSimulationResultUuids().forEach(dynamicSimulationService::deleteResult)), + studyServerExecutionService.runAsync(() -> invalidateNodeInfos.getStateEstimationResultUuids().forEach(stateEstimationService::deleteStateEstimationResult)), studyServerExecutionService.runAsync(() -> networkStoreService.deleteVariants(invalidateNodeInfos.getNetworkUuid(), invalidateNodeInfos.getVariantIds())) ); try { @@ -1460,6 +1468,7 @@ public void deleteNodes(UUID studyUuid, List nodeIds, boolean deleteChildr studyServerExecutionService.runAsync(() -> deleteNodeInfos.getOneBusShortCircuitAnalysisResultUuids().forEach(shortCircuitService::deleteShortCircuitAnalysisResult)), studyServerExecutionService.runAsync(() -> deleteNodeInfos.getVoltageInitResultUuids().forEach(voltageInitService::deleteVoltageInitResult)), studyServerExecutionService.runAsync(() -> deleteNodeInfos.getDynamicSimulationResultUuids().forEach(dynamicSimulationService::deleteResult)), + studyServerExecutionService.runAsync(() -> deleteNodeInfos.getStateEstimationResultUuids().forEach(stateEstimationService::deleteStateEstimationResult)), studyServerExecutionService.runAsync(() -> networkStoreService.deleteVariants(deleteNodeInfos.getNetworkUuid(), deleteNodeInfos.getVariantIds())), studyServerExecutionService.runAsync(() -> removedNodes.forEach(dynamicSimulationEventService::deleteEventsByNodeId)) ); @@ -2110,6 +2119,7 @@ private void emitAllComputationStatusChanged(UUID studyUuid, UUID nodeUuid) { notificationService.emitStudyChanged(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_STATUS); notificationService.emitStudyChanged(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_VOLTAGE_INIT_STATUS); notificationService.emitStudyChanged(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_DYNAMIC_SIMULATION_STATUS); + notificationService.emitStudyChanged(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_STATE_ESTIMATION_STATUS); } public String evaluateFilter(UUID studyUuid, UUID nodeUuid, boolean inUpstreamBuiltParentNode, String filter) { @@ -2121,4 +2131,32 @@ public String exportFilter(UUID studyUuid, UUID filterUuid) { // will use root node network of the study return filterService.exportFilter(networkStoreService.getNetworkUuid(studyUuid), filterUuid); } + + @Transactional + public UUID runStateEstimation(UUID studyUuid, UUID nodeUuid, String userId) { + Objects.requireNonNull(studyUuid); + Objects.requireNonNull(nodeUuid); + if (studyRepository.findById(studyUuid).isEmpty()) { + throw new StudyException(STUDY_NOT_FOUND); + } + + UUID networkUuid = networkStoreService.getNetworkUuid(studyUuid); + String variantId = networkModificationTreeService.getVariantId(nodeUuid); + UUID reportUuid = networkModificationTreeService.getReportUuid(nodeUuid); + String receiver; + try { + receiver = URLEncoder.encode(objectMapper.writeValueAsString(new NodeReceiver(nodeUuid)), StandardCharsets.UTF_8); + } catch (JsonProcessingException e) { + throw new UncheckedIOException(e); + } + + Optional prevResultUuidOpt = networkModificationTreeService.getComputationResultUuid(nodeUuid, STATE_ESTIMATION); + prevResultUuidOpt.ifPresent(stateEstimationService::deleteStateEstimationResult); + + UUID result = stateEstimationService.runStateEstimation(networkUuid, variantId, new ReportInfos(reportUuid, nodeUuid.toString()), receiver, userId); + updateComputationResultUuid(nodeUuid, result, STATE_ESTIMATION); + notificationService.emitStudyChanged(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_STATE_ESTIMATION_STATUS); + return result; + } + } 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 349a918cf..d4cea359a 100644 --- a/src/main/java/org/gridsuite/study/server/service/SupervisionService.java +++ b/src/main/java/org/gridsuite/study/server/service/SupervisionService.java @@ -66,7 +66,22 @@ public class SupervisionService { private final NetworkModificationNodeInfoRepository networkModificationNodeInfoRepository; - public SupervisionService(StudyService studyService, NetworkModificationTreeService networkModificationTreeService, NetworkService networkStoreService, NetworkModificationNodeInfoRepository networkModificationNodeInfoRepository, ReportService reportService, LoadFlowService loadFlowService, DynamicSimulationService dynamicSimulationService, SecurityAnalysisService securityAnalysisService, SensitivityAnalysisService sensitivityAnalysisService, NonEvacuatedEnergyService nonEvacuatedEnergyService, ShortCircuitService shortCircuitService, VoltageInitService voltageInitService, EquipmentInfosService equipmentInfosService) { + private final StateEstimationService stateEstimationService; + + public SupervisionService(StudyService studyService, + NetworkModificationTreeService networkModificationTreeService, + NetworkService networkStoreService, + NetworkModificationNodeInfoRepository networkModificationNodeInfoRepository, + ReportService reportService, + LoadFlowService loadFlowService, + DynamicSimulationService dynamicSimulationService, + SecurityAnalysisService securityAnalysisService, + SensitivityAnalysisService sensitivityAnalysisService, + NonEvacuatedEnergyService nonEvacuatedEnergyService, + ShortCircuitService shortCircuitService, + VoltageInitService voltageInitService, + EquipmentInfosService equipmentInfosService, + StateEstimationService stateEstimationService) { this.networkStoreService = networkStoreService; this.studyService = studyService; this.networkModificationTreeService = networkModificationTreeService; @@ -80,6 +95,7 @@ public SupervisionService(StudyService studyService, NetworkModificationTreeServ this.shortCircuitService = shortCircuitService; this.voltageInitService = voltageInitService; this.equipmentInfosService = equipmentInfosService; + this.stateEstimationService = stateEstimationService; } @Transactional @@ -98,6 +114,8 @@ public Integer deleteComputationResults(ComputationType computationType, boolean dryRun ? shortCircuitService.getShortCircuitResultsCount() : deleteShortcircuitResults(); case VOLTAGE_INITIALIZATION -> dryRun ? voltageInitService.getVoltageInitResultsCount() : deleteVoltageInitResults(); + case STATE_ESTIMATION -> + dryRun ? stateEstimationService.getStateEstimationResultsCount() : deleteStateEstimationResults(); default -> throw new StudyException(ELEMENT_NOT_FOUND); }; } @@ -239,6 +257,18 @@ private Map formatSubreportMap(String subReporterKey, List startTime = new AtomicReference<>(); + startTime.set(System.nanoTime()); + List nodes = networkModificationNodeInfoRepository.findAllByStateEstimationResultUuidNotNull(); + nodes.forEach(node -> node.setStateEstimationResultUuid(null)); + Map subreportToDelete = formatSubreportMap(StudyService.ReportType.STATE_ESTIMATION.reportKey, nodes); + reportService.deleteTreeReports(subreportToDelete); + stateEstimationService.deleteStateEstimationResults(); + LOGGER.trace(DELETION_LOG_MESSAGE, ComputationType.STATE_ESTIMATION, TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime.get())); + return nodes.size(); + } + @Transactional public void invalidateAllNodesBuilds(UUID studyUuid) { AtomicReference startTime = new AtomicReference<>(); diff --git a/src/main/java/org/gridsuite/study/server/service/client/RemoteServiceName.java b/src/main/java/org/gridsuite/study/server/service/client/RemoteServiceName.java index 95f0d3295..90cd745e4 100644 --- a/src/main/java/org/gridsuite/study/server/service/client/RemoteServiceName.java +++ b/src/main/java/org/gridsuite/study/server/service/client/RemoteServiceName.java @@ -52,7 +52,8 @@ public enum RemoteServiceName { STUDY_SERVER, TIMESERIES_SERVER, USER_ADMIN_SERVER, - VOLTAGE_INIT_SERVER; + VOLTAGE_INIT_SERVER, + STATE_ESTIMATION_SERVER; /** * Service name in the format found in {@link RemoteServicesProperties.Service#getName() Service.name} diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index d495abc60..ff6e9ce81 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -73,3 +73,6 @@ gridsuite: - name: user-admin-server base-uri: http://localhost:5033 + - + name: state-estimation-server + base-uri: http://localhost:5040 diff --git a/src/main/resources/config/application.yaml b/src/main/resources/config/application.yaml index 3824672e7..d3198d26a 100644 --- a/src/main/resources/config/application.yaml +++ b/src/main/resources/config/application.yaml @@ -14,7 +14,8 @@ spring: consumeShortCircuitAnalysisResult;consumeShortCircuitAnalysisStopped;consumeShortCircuitAnalysisFailed;\ consumeVoltageInitResult;consumeVoltageInitStopped;consumeVoltageInitFailed;\ consumeLoadFlowResult;consumeLoadFlowStopped;consumeLoadFlowFailed;\ - consumeNonEvacuatedEnergyResult;consumeNonEvacuatedEnergyStopped;consumeNonEvacuatedEnergyFailed" + consumeNonEvacuatedEnergyResult;consumeNonEvacuatedEnergyStopped;consumeNonEvacuatedEnergyFailed;\ + consumeStateEstimationResult;consumeStateEstimationStopped;consumeStateEstimationFailed" stream: bindings: publishStudyUpdate-out-0: @@ -93,6 +94,15 @@ spring: consumeVoltageInitFailed-in-0: destination: ${powsybl-ws.rabbitmq.destination.prefix:}voltageinit.failed group: studyVoltageInitFailedGroup + consumeStateEstimationResult-in-0: + destination: ${powsybl-ws.rabbitmq.destination.prefix:}stateestimation.result + group: studyStateEstimationResultGroup + consumeStateEstimationStopped-in-0: + destination: ${powsybl-ws.rabbitmq.destination.prefix:}stateestimation.stopped + group: studyStateEstimationStoppedGroup + consumeStateEstimationFailed-in-0: + destination: ${powsybl-ws.rabbitmq.destination.prefix:}stateestimation.failed + group: studyStateEstimationFailedGroup consumeCaseImportSucceeded-in-0: destination: ${powsybl-ws.rabbitmq.destination.prefix:}case.import.succeeded group: studyCaseImportSucceededGroup @@ -163,3 +173,6 @@ gridsuite: - name: filter-server base-uri: http://filter-server/ + - + name: state-estimation-server + base-uri: http://state-estimation-server/ diff --git a/src/main/resources/db/changelog/changesets/changelog_20240530T113417Z.xml b/src/main/resources/db/changelog/changesets/changelog_20240530T113417Z.xml new file mode 100644 index 000000000..d42c6c8f5 --- /dev/null +++ b/src/main/resources/db/changelog/changesets/changelog_20240530T113417Z.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index d9d286565..6ef3b9a96 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -232,6 +232,10 @@ databaseChangeLog: - include: file: changesets/changelog_20240522T150750Z.xml relativeToChangelogFile: true + - include: + file: changesets/changelog_20240530T113417Z.xml + relativeToChangelogFile: true - include: file: changesets/changelog_20240510T112233Z.xml relativeToChangelogFile: true + diff --git a/src/test/java/org/gridsuite/study/server/EquipmentInfosServiceTests.java b/src/test/java/org/gridsuite/study/server/EquipmentInfosServiceTests.java index 4740a1a42..5f6c0fda6 100644 --- a/src/test/java/org/gridsuite/study/server/EquipmentInfosServiceTests.java +++ b/src/test/java/org/gridsuite/study/server/EquipmentInfosServiceTests.java @@ -37,10 +37,7 @@ import org.springframework.data.elasticsearch.client.elc.Queries; import org.springframework.test.context.junit4.SpringRunner; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.stream.Stream; import static org.hamcrest.core.Is.is; @@ -65,6 +62,8 @@ public class EquipmentInfosServiceTests { private static final String EQUIPMENT_NAME_FIELD = "equipmentName"; private static final String NETWORK_UUID_FIELD = "networkUuid.keyword"; + private static final String VARIANT_ID = "variant_1"; + private static final UUID NETWORK_UUID = UUID.fromString("db240961-a7b6-4b76-bfe8-19749026c1cb"); private static final UUID NETWORK_UUID_2 = UUID.fromString("8c73b846-5dbe-4ac8-a9c9-8422fda261bb"); @@ -430,4 +429,17 @@ public void testSearchSpecialChars() { hits = new HashSet<>(equipmentInfosService.searchEquipments(query)); pbsc.checkThat(hits.size(), is(1)); } + + @Test + public void cleanRemovedEquipmentsInSerachTest() { + UUID equipmentUuid = UUID.randomUUID(); + EquipmentInfos equipmentInfos = EquipmentInfos.builder().id(equipmentUuid.toString()).name("test").networkUuid(NETWORK_UUID).type("LOAD").variantId(VARIANT_ID).build(); + TombstonedEquipmentInfos tombstonedEquipmentInfos = TombstonedEquipmentInfos.builder().id(equipmentUuid.toString()).networkUuid(NETWORK_UUID).variantId(VARIANT_ID).build(); + // following the creation of a hypothesis for equipment deletion + equipmentInfosService.addTombstonedEquipmentInfos(tombstonedEquipmentInfos); + // following the creation of a hypothesis for previously deleted equipment creation + equipmentInfosService.addEquipmentInfos(equipmentInfos); + List result = equipmentInfosService.searchEquipments(NETWORK_UUID, VARIANT_ID, "test", EquipmentInfosService.FieldSelector.NAME, "LOAD"); + assertEquals(equipmentInfos, result.get(0)); + } } diff --git a/src/test/java/org/gridsuite/study/server/NetworkMapTest.java b/src/test/java/org/gridsuite/study/server/NetworkMapTest.java index fa50c0e46..39909f6e9 100644 --- a/src/test/java/org/gridsuite/study/server/NetworkMapTest.java +++ b/src/test/java/org/gridsuite/study/server/NetworkMapTest.java @@ -340,7 +340,7 @@ public void testGetVoltageLevelsTopology() throws Exception { UUID rootNodeUuid = getRootNode(studyNameUserIdUuid).getId(); //get the voltage levels and its equipments - getNetworkElementsInfos(studyNameUserIdUuid, rootNodeUuid, "VOLTAGE_LEVEL", "LIST", List.of(), "[{\"id\":\"MTAUBP3\",\"nominalVoltage\":0.0,\"topologyKind\":\"NODE_BREAKER\"}]"); + getNetworkElementsInfos(studyNameUserIdUuid, rootNodeUuid, "LIST", mapper.writeValueAsString(createRequestBody("VOLTAGE_LEVEL", List.of())), "[{\"id\":\"MTAUBP3\",\"nominalVoltage\":0.0,\"topologyKind\":\"NODE_BREAKER\"}]"); assertTrue(TestUtils.getRequestsDone(1, server).stream().anyMatch(r -> r.matches("/v1/parameters/" + LOADFLOW_PARAMETERS_UUID_STRING))); } @@ -372,7 +372,7 @@ public void testGetMapSubstations() throws Exception { //get the substations with it's voltage levels String substationDataAsString = mapper.writeValueAsString(List.of(IdentifiableInfos.builder().id(SUBSTATION_ID_1).name("SUBSTATION_NAME_1").build())); - getNetworkElementsInfos(studyNameUserIdUuid, rootNodeUuid, "SUBSTATION", "MAP", List.of(), substationDataAsString); + getNetworkElementsInfos(studyNameUserIdUuid, rootNodeUuid, "MAP", mapper.writeValueAsString(createRequestBody("SUBSTATION", List.of())), substationDataAsString); assertTrue(TestUtils.getRequestsDone(1, server).stream().anyMatch(r -> r.matches("/v1/parameters/" + LOADFLOW_PARAMETERS_UUID_STRING))); } @@ -387,8 +387,8 @@ public void testGetMapLines() throws Exception { //get the lines String lineDataAsString = mapper.writeValueAsString(List.of(IdentifiableInfos.builder().id(LINE_ID_1).name("LINE_NAME_1").build())); - getNetworkElementsInfos(studyNameUserIdUuid, rootNodeUuid, "LINE", "MAP", List.of(), lineDataAsString); - getNetworkElementsInfos(studyNameUserIdUuid, rootNodeUuid, "LINE", "MAP", List.of("S1"), lineDataAsString); + getNetworkElementsInfos(studyNameUserIdUuid, rootNodeUuid, "MAP", mapper.writeValueAsString(createRequestBody("LINE", List.of())), lineDataAsString); + getNetworkElementsInfos(studyNameUserIdUuid, rootNodeUuid, "MAP", mapper.writeValueAsString(createRequestBody("LINE", List.of("S1"))), lineDataAsString); assertTrue(TestUtils.getRequestsDone(2, server).stream().anyMatch(r -> r.matches("/v1/parameters/" + LOADFLOW_PARAMETERS_UUID_STRING))); } @@ -403,7 +403,7 @@ public void testGetMapHvdcLines() throws Exception { //get the lines String hvdcLineDataAsString = mapper.writeValueAsString(IdentifiableInfos.builder().id(HVDC_LINE_ID_1).name("HVDC_LINE_NAME_1").build()); - getNetworkElementsInfos(studyNameUserIdUuid, rootNodeUuid, "HVDC_LINE", "MAP", List.of(), hvdcLineDataAsString); + getNetworkElementsInfos(studyNameUserIdUuid, rootNodeUuid, "MAP", mapper.writeValueAsString(createRequestBody("HVDC_LINE", List.of())), hvdcLineDataAsString); assertTrue(TestUtils.getRequestsDone(1, server).stream().anyMatch(r -> r.matches("/v1/parameters/" + LOADFLOW_PARAMETERS_UUID_STRING))); } @@ -528,19 +528,18 @@ private MvcResult getNetworkElementsIds(UUID studyUuid, UUID rootNodeUuid, Strin } @SneakyThrows - private MvcResult getNetworkElementsInfos(UUID studyUuid, UUID rootNodeUuid, String elementType, String infoType, List substationsIds, String responseBody) { - UUID stubUuid = wireMockUtils.stubNetworkElementsInfosGet(NETWORK_UUID_STRING, elementType, infoType, responseBody); - MockHttpServletRequestBuilder mockHttpServletRequestBuilder = get("/v1/studies/{studyUuid}/nodes/{nodeUuid}/network/elements", studyUuid, rootNodeUuid) - .queryParam(QUERY_PARAM_ELEMENT_TYPE, elementType) + private MvcResult getNetworkElementsInfos(UUID studyUuid, UUID rootNodeUuid, String infoType, String responseBody, String requestBody) { + UUID stubUuid = wireMockUtils.stubNetworkElementsInfosPost(NETWORK_UUID_STRING, infoType, responseBody); + + MockHttpServletRequestBuilder mockHttpServletRequestBuilder = post("/v1/studies/{studyUuid}/nodes/{nodeUuid}/network/elements", studyUuid, rootNodeUuid) .queryParam(QUERY_PARAM_INFO_TYPE, infoType) - .queryParam(String.format(QUERY_FORMAT_OPTIONAL_PARAMS, QUERY_PARAM_DC_POWERFACTOR), Double.toString(LoadFlowParameters.DEFAULT_DC_POWER_FACTOR)); - if (!substationsIds.isEmpty()) { - mockHttpServletRequestBuilder.queryParam(QUERY_PARAM_SUBSTATIONS_IDS, substationsIds.stream().toArray(String[]::new)); - } + .queryParam(String.format(QUERY_FORMAT_OPTIONAL_PARAMS, QUERY_PARAM_DC_POWERFACTOR), Double.toString(LoadFlowParameters.DEFAULT_DC_POWER_FACTOR)) + .content(requestBody); + MvcResult mvcResult = mockMvc.perform(mockHttpServletRequestBuilder) .andExpect(status().isOk()) .andReturn(); - wireMockUtils.verifyNetworkElementsInfosGet(stubUuid, NETWORK_UUID_STRING, elementType, infoType); + wireMockUtils.verifyNetworkElementsInfosPost(stubUuid, NETWORK_UUID_STRING, infoType, requestBody); return mvcResult; } diff --git a/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java b/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java index b77eac8a6..bb09afe9a 100644 --- a/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java +++ b/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java @@ -124,6 +124,9 @@ public class NetworkModificationTest { private static final String VOLTAGE_INIT_STATUS_JSON = "{\"status\":\"COMPLETED\"}"; + private static final String STATE_ESTIMATION_RESULT_UUID = "d3a85e9b-9894-4255-8ec7-07ea965d24eb"; + private static final String STATE_ESTIMATION_STATUS_JSON = "\"COMPLETED\""; + private static final String MODIFICATION_UUID = "796719f5-bd31-48be-be46-ef7b96951e32"; private static final ReportNode REPORT_TEST = ReportNode.newRootReportNode().withMessageTemplate("test", "test").build(); @@ -186,6 +189,9 @@ public class NetworkModificationTest { @Autowired private VoltageInitService voltageInitService; + @Autowired + private StateEstimationService stateEstimationService; + @MockBean private NetworkStoreService networkStoreService; @@ -230,6 +236,8 @@ public void setup() throws IOException { nonEvacuatedEnergyService.setSensitivityAnalysisServerBaseUri(baseUrl); shortCircuitService.setShortCircuitServerBaseUri(baseUrl); voltageInitService.setVoltageInitServerBaseUri(baseUrl); + stateEstimationService.setStateEstimationServerServerBaseUri(baseUrl); + String baseUrlWireMock = wireMockServer.baseUrl(); networkModificationService.setNetworkModificationServerBaseUri(baseUrlWireMock); @@ -345,6 +353,18 @@ public MockResponse dispatch(RecordedRequest request) { .addHeader("Content-Type", "application/json; charset=utf-8"); } return new MockResponse().setResponseCode(500); + } else if (("/v1/results/invalidate-status?resultUuid=" + STATE_ESTIMATION_RESULT_UUID).equals(path)) { + return new MockResponse().setResponseCode(200).addHeader("Content-Type", + "application/json; charset=utf-8"); + } else if (("/v1/results/" + STATE_ESTIMATION_RESULT_UUID + "/status").equals(path)) { + return new MockResponse().setResponseCode(200).setBody(STATE_ESTIMATION_STATUS_JSON) + .addHeader("Content-Type", "application/json; charset=utf-8"); + } else if (("/v1/results/" + STATE_ESTIMATION_RESULT_UUID).equals(path)) { + if (request.getMethod().equals("DELETE")) { + return new MockResponse().setResponseCode(200).setBody(STATE_ESTIMATION_STATUS_JSON) + .addHeader("Content-Type", "application/json; charset=utf-8"); + } + return new MockResponse().setResponseCode(500); } else { LOGGER.error("Unhandled method+path: " + request.getMethod() + " " + request.getPath()); return new MockResponse().setResponseCode(418).setBody("Unhandled method+path: " + request.getMethod() + " " + request.getPath()); @@ -2330,6 +2350,8 @@ public void testNodesInvalidation() throws Exception { modificationNode1.setShortCircuitAnalysisResultUuid(UUID.fromString(SHORTCIRCUIT_ANALYSIS_RESULT_UUID)); modificationNode1.setOneBusShortCircuitAnalysisResultUuid(UUID.fromString(ONE_BUS_SHORTCIRCUIT_ANALYSIS_RESULT_UUID)); modificationNode1.setVoltageInitResultUuid(UUID.fromString(VOLTAGE_INIT_RESULT_UUID)); + modificationNode1.setStateEstimationResultUuid(UUID.fromString(STATE_ESTIMATION_RESULT_UUID)); + modificationNode2.setReportUuid(UUID.randomUUID()); modificationNode3.setReportUuid(UUID.randomUUID()); @@ -2354,7 +2376,7 @@ public void testNodesInvalidation() throws Exception { checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); wireMockUtils.verifyNetworkModificationPut(stubUuid, MODIFICATION_UUID, generatorAttributesUpdated); - var requests = TestUtils.getRequestsWithBodyDone(15, server); + var requests = TestUtils.getRequestsWithBodyDone(17, server); assertEquals(3, requests.stream().filter(r -> r.getPath().matches("/v1/reports/.*")).count()); assertTrue(requests.stream().anyMatch(r -> r.getPath().matches("/v1/results/" + SECURITY_ANALYSIS_RESULT_UUID))); assertTrue(requests.stream().anyMatch(r -> r.getPath().matches("/v1/results/" + SENSITIVITY_ANALYSIS_RESULT_UUID))); @@ -2362,6 +2384,7 @@ public void testNodesInvalidation() throws Exception { assertTrue(requests.stream().anyMatch(r -> r.getPath().matches("/v1/results/" + SHORTCIRCUIT_ANALYSIS_RESULT_UUID))); assertTrue(requests.stream().anyMatch(r -> r.getPath().matches("/v1/results/" + ONE_BUS_SHORTCIRCUIT_ANALYSIS_RESULT_UUID))); assertTrue(requests.stream().anyMatch(r -> r.getPath().matches("/v1/results/" + VOLTAGE_INIT_RESULT_UUID))); + assertTrue(requests.stream().anyMatch(r -> r.getPath().matches("/v1/results/" + STATE_ESTIMATION_RESULT_UUID))); // Mark the node 3 status as built modificationNode3.setNodeBuildStatus(NodeBuildStatus.from(BuildStatus.BUILT)); @@ -2407,6 +2430,8 @@ public void testRemoveLoadFlowComputationReport() throws Exception { modificationNode1.setShortCircuitAnalysisResultUuid(UUID.fromString(SHORTCIRCUIT_ANALYSIS_RESULT_UUID)); modificationNode1.setOneBusShortCircuitAnalysisResultUuid(UUID.fromString(ONE_BUS_SHORTCIRCUIT_ANALYSIS_RESULT_UUID)); modificationNode1.setVoltageInitResultUuid(UUID.fromString(VOLTAGE_INIT_RESULT_UUID)); + modificationNode1.setStateEstimationResultUuid(UUID.fromString(STATE_ESTIMATION_RESULT_UUID)); + networkModificationTreeService.updateNode(studyNameUserIdUuid, modificationNode1, userId); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); output.receive(TIMEOUT, studyUpdateDestination); @@ -2434,14 +2459,14 @@ public void testRemoveLoadFlowComputationReport() throws Exception { checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); wireMockUtils.verifyNetworkModificationPostWithVariant(stubId, bodyJson, NETWORK_UUID_STRING, VARIANT_ID); - var requests = TestUtils.getRequestsDone(21, server); // 3 x 7 computations + var requests = TestUtils.getRequestsDone(24, server); // 3 x 8 computations List.of(LOADFLOW_RESULT_UUID, SECURITY_ANALYSIS_RESULT_UUID, SENSITIVITY_ANALYSIS_RESULT_UUID, SENSITIVITY_ANALYSIS_NON_EVACUATED_ENERGY_RESULT_UUID, - SHORTCIRCUIT_ANALYSIS_RESULT_UUID, ONE_BUS_SHORTCIRCUIT_ANALYSIS_RESULT_UUID, VOLTAGE_INIT_RESULT_UUID).forEach(uuid -> { + SHORTCIRCUIT_ANALYSIS_RESULT_UUID, ONE_BUS_SHORTCIRCUIT_ANALYSIS_RESULT_UUID, VOLTAGE_INIT_RESULT_UUID, STATE_ESTIMATION_RESULT_UUID).forEach(uuid -> { assertTrue(requests.stream().anyMatch(r -> r.equals("/v1/results/" + uuid))); assertTrue(requests.stream().anyMatch(r -> r.equals("/v1/results/" + uuid + "/status"))); }); // requests for computation sub-report deletion - List.of("LoadFlow", "SecurityAnalysis", "SensitivityAnalysis", "NonEvacuatedEnergyAnalysis", "AllBusesShortCircuitAnalysis", "OneBusShortCircuitAnalysis", "VoltageInit").forEach(reportType -> { + List.of("LoadFlow", "SecurityAnalysis", "SensitivityAnalysis", "NonEvacuatedEnergyAnalysis", "AllBusesShortCircuitAnalysis", "OneBusShortCircuitAnalysis", "VoltageInit", "StateEstimation").forEach(reportType -> { assertTrue(requests.stream().anyMatch(r -> r.equals("/v1/reports/" + reportUuid + "?errorOnReportNotFound=false&reportTypeFilter=" + reportType))); }); } @@ -2666,6 +2691,7 @@ private void checkUpdateModelsStatusMessagesReceived(UUID studyUuid, UUID nodeUu 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_STATE_ESTIMATION_STATUS); } private void checkNodesBuildStatusUpdatedMessageReceived(UUID studyUuid, List nodesUuids) { diff --git a/src/test/java/org/gridsuite/study/server/NetworkModificationTreeTest.java b/src/test/java/org/gridsuite/study/server/NetworkModificationTreeTest.java index 7fa6df94e..4c2d077e0 100644 --- a/src/test/java/org/gridsuite/study/server/NetworkModificationTreeTest.java +++ b/src/test/java/org/gridsuite/study/server/NetworkModificationTreeTest.java @@ -148,6 +148,9 @@ public class NetworkModificationTreeTest { @Autowired private ShortCircuitService shortCircuitService; + @Autowired + private StateEstimationService stateEstimationService; + @Autowired private SingleLineDiagramService singleLineDiagramService; @@ -252,6 +255,7 @@ public Set