diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java index 5a87d4a6..50bcbef4 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java @@ -19,6 +19,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityAnalysisInputData; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityAnalysisStatus; +import org.gridsuite.sensitivityanalysis.server.dto.SensitivityResultFilterOptions; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityRunQueryResult; import org.gridsuite.sensitivityanalysis.server.service.SensitivityAnalysisRunContext; import org.gridsuite.sensitivityanalysis.server.service.SensitivityAnalysisService; @@ -54,6 +55,13 @@ private static List getNonNullOtherNetworkUuids(List otherNetworkUui return otherNetworkUuids != null ? otherNetworkUuids : Collections.emptyList(); } + private static ResultsSelector getSelector(String selectorJson) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + return selectorJson == null ? + ResultsSelector.builder().functionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1).isJustBefore(false).build() : + mapper.readValue(selectorJson, ResultsSelector.class); + } + @PostMapping(value = "/networks/{networkUuid}/run", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) @Operation(summary = "Run a sensitivity analysis on a network") @ApiResponses(value = {@ApiResponse(responseCode = "200", @@ -99,21 +107,30 @@ public ResponseEntity getResult(@Parameter(descriptio @PathVariable("resultUuid") UUID resultUuid, @RequestParam(name = "selector", required = false) String selectorJson) { - ObjectMapper mapper = new ObjectMapper(); - ResultsSelector selector; - if (selectorJson == null) { - selector = ResultsSelector.builder().functionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1).isJustBefore(false).build(); - } else { - try { - selector = mapper.readValue(selectorJson, ResultsSelector.class); - } catch (JsonProcessingException e) { - return ResponseEntity.badRequest().build(); - } + try { + ResultsSelector selector = getSelector(selectorJson); + SensitivityRunQueryResult result = service.getRunResult(resultUuid, selector); + return result != null ? ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(result) + : ResponseEntity.notFound().build(); + } catch (JsonProcessingException e) { + return ResponseEntity.badRequest().build(); } + } - SensitivityRunQueryResult result = service.getRunResult(resultUuid, selector); - return result != null ? ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(result) - : ResponseEntity.notFound().build(); + @GetMapping(value = "/results/{resultUuid}/filter-options", produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Get all filter options of sensitivity analysis results") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The sensitivity analysis result filter options"), + @ApiResponse(responseCode = "404", description = "Sensitivity analysis result has not been found")}) + public ResponseEntity getResultFilerOptions(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid, + @RequestParam(name = "selector", required = false) String selectorJson) { + try { + ResultsSelector selector = getSelector(selectorJson); + SensitivityResultFilterOptions result = service.getSensitivityResultOptions(resultUuid, selector); + return result != null ? ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(result) + : ResponseEntity.notFound().build(); + } catch (JsonProcessingException e) { + return ResponseEntity.badRequest().build(); + } } @DeleteMapping(value = "/results/{resultUuid}", produces = APPLICATION_JSON_VALUE) diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityResultFilterOptions.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityResultFilterOptions.java new file mode 100644 index 00000000..21c9b53a --- /dev/null +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityResultFilterOptions.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2023, 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.sensitivityanalysis.server.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author Seddik Yengui + */ + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +public class SensitivityResultFilterOptions { + List allContingencyIds; + List allFunctionIds; + List allVariableIds; +} diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityRunQueryResult.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityRunQueryResult.java index 349c775a..8b4fb28f 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityRunQueryResult.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityRunQueryResult.java @@ -40,8 +40,4 @@ public class SensitivityRunQueryResult { @NonNull List sensitivities; - - List allContingencyIds; - List allFunctionIds; - List allVariableIds; } diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/repositories/SensitivityAnalysisResultRepository.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/repositories/SensitivityAnalysisResultRepository.java index a86319a4..abeba29f 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/repositories/SensitivityAnalysisResultRepository.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/repositories/SensitivityAnalysisResultRepository.java @@ -10,6 +10,7 @@ import com.powsybl.sensitivity.SensitivityValue; import org.gridsuite.sensitivityanalysis.server.ResultsSelector; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityOfTo; +import org.gridsuite.sensitivityanalysis.server.dto.SensitivityResultFilterOptions; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityRunQueryResult; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityWithContingency; import org.gridsuite.sensitivityanalysis.server.entities.AnalysisResultEntity; @@ -28,13 +29,10 @@ import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; -import java.util.TreeSet; import java.util.UUID; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -145,6 +143,28 @@ public String findStatus(UUID resultUuid) { } } + @Transactional(readOnly = true) + public SensitivityResultFilterOptions getSensitivityResultFilterOptions(UUID resultUuid, ResultsSelector selector) { + AnalysisResultEntity sas = analysisResultRepository.findByResultUuid(resultUuid); + if (sas == null) { + return null; + } + + SensitivityResultFilterOptions.SensitivityResultFilterOptionsBuilder sensitivityResultOptionsBuilder = SensitivityResultFilterOptions.builder() + .allFunctionIds(sensitivityRepository.findFunctionByResultResultUuidAndFactorFunctionType(sas.getResultUuid(), selector.getFunctionType())) + .allVariableIds(sensitivityRepository.findVariableByResultResultUuidAndFactorFunctionType(sas.getResultUuid(), selector.getFunctionType())); + + if (!selector.getIsJustBefore()) { + sensitivityResultOptionsBuilder.allContingencyIds(sensitivityRepository.findContingencyByResultResultUuidAndFactorFunctionType(sas.getResultUuid(), selector.getFunctionType()) + .stream() + .filter(Objects::nonNull) + .collect(Collectors.toList())) + .build(); + } + + return sensitivityResultOptionsBuilder.build(); + } + @Transactional(readOnly = true) public SensitivityRunQueryResult getRunResult(UUID resultUuid, ResultsSelector selector) { AnalysisResultEntity sas = analysisResultRepository.findByResultUuid(resultUuid); @@ -213,10 +233,6 @@ private SensitivityRunQueryResult getSensitivityRunQueryResult(ResultsSelector s return retBuilder.build(); } - Set allFunctionIds = new TreeSet<>(); - Set allVariableIds = new TreeSet<>(); - Set allContingencyIds = new TreeSet<>(); - var totalSensitivitiesCountSpec = SensitivityRepository.getSpecification(sas, selector.getFunctionType(), null, @@ -229,8 +245,6 @@ private SensitivityRunQueryResult getSensitivityRunQueryResult(ResultsSelector s List befores = new ArrayList<>(); sensitivityEntities.forEach(sensitivityEntity -> { SensitivityFactorEmbeddable factorEmbeddable = sensitivityEntity.getFactor(); - allFunctionIds.add(factorEmbeddable.getFunctionId()); - allVariableIds.add(factorEmbeddable.getVariableId()); befores.add(SensitivityOfTo.builder() .funcId(factorEmbeddable.getFunctionId()) .varId(factorEmbeddable.getVariableId()) @@ -239,16 +253,11 @@ private SensitivityRunQueryResult getSensitivityRunQueryResult(ResultsSelector s .functionReference(sensitivityEntity.getFunctionReference()) .build()); }); - complete(retBuilder, allFunctionIds, allVariableIds, null, filteredSensitivitiesCount, count, befores); + complete(retBuilder, filteredSensitivitiesCount, count, befores); } else { List after = new ArrayList<>(); sensitivityEntities.forEach(sensitivityEntity -> { SensitivityFactorEmbeddable factorEmbeddable = sensitivityEntity.getFactor(); - allFunctionIds.add(factorEmbeddable.getFunctionId()); - allVariableIds.add(factorEmbeddable.getVariableId()); - if (factorEmbeddable.getContingencyContextId() != null) { - allContingencyIds.add(factorEmbeddable.getContingencyContextId()); - } SensitivityWithContingency r = SensitivityWithContingency.builder() .funcId(factorEmbeddable.getFunctionId()) .varId(factorEmbeddable.getVariableId()) @@ -262,25 +271,17 @@ private SensitivityRunQueryResult getSensitivityRunQueryResult(ResultsSelector s after.add(r); }); - complete(retBuilder, allFunctionIds, allVariableIds, allContingencyIds, filteredSensitivitiesCount, count, after); + complete(retBuilder, filteredSensitivitiesCount, count, after); } return retBuilder.build(); } private void complete(SensitivityRunQueryResult.SensitivityRunQueryResultBuilder retBuilder, - Collection allFunctionIds, - Collection allVariableIds, - Collection allContingencyIds, long filteredSensitivitiesCount, long count, List filtered ) { - retBuilder.allFunctionIds(allFunctionIds.stream().sorted().collect(Collectors.toList())); - retBuilder.allVariableIds(allVariableIds.stream().sorted().collect(Collectors.toList())); - if (allContingencyIds != null) { - retBuilder.allContingencyIds(allContingencyIds.stream().sorted().collect(Collectors.toList())); - } retBuilder.filteredSensitivitiesCount(filteredSensitivitiesCount); retBuilder.sensitivities(filtered); retBuilder.totalSensitivitiesCount(count); diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/repositories/SensitivityRepository.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/repositories/SensitivityRepository.java index b2d9501a..29d756b3 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/repositories/SensitivityRepository.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/repositories/SensitivityRepository.java @@ -15,6 +15,7 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; import org.springframework.util.CollectionUtils; import jakarta.persistence.criteria.CriteriaBuilder; @@ -37,6 +38,15 @@ public interface SensitivityRepository extends JpaRepository findAll(Specification specification, Pageable pageable); + @Query(value = "SELECT distinct s.factor.functionId from SensitivityEntity as s") + List findFunctionByResultResultUuidAndFactorFunctionType(UUID resultUuid, SensitivityFunctionType sensitivityFunctionType); + + @Query(value = "SELECT distinct s.factor.variableId from SensitivityEntity as s") + List findVariableByResultResultUuidAndFactorFunctionType(UUID resultUuid, SensitivityFunctionType sensitivityFunctionType); + + @Query(value = "SELECT distinct s.contingency.contingencyId from SensitivityEntity as s") + List findContingencyByResultResultUuidAndFactorFunctionType(UUID resultUuid, SensitivityFunctionType sensitivityFunctionType); + static Specification getSpecification(AnalysisResultEntity sas, SensitivityFunctionType functionType, Collection functionIds, diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java index 113eab9e..3609d87e 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java @@ -10,6 +10,7 @@ import com.powsybl.sensitivity.SensitivityAnalysisProvider; import org.gridsuite.sensitivityanalysis.server.ResultsSelector; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityAnalysisStatus; +import org.gridsuite.sensitivityanalysis.server.dto.SensitivityResultFilterOptions; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityRunQueryResult; import org.gridsuite.sensitivityanalysis.server.repositories.SensitivityAnalysisResultRepository; import org.springframework.beans.factory.annotation.Autowired; @@ -63,6 +64,10 @@ public SensitivityRunQueryResult getRunResult(UUID resultUuid, ResultsSelector s return resultRepository.getRunResult(resultUuid, selector); } + public SensitivityResultFilterOptions getSensitivityResultOptions(UUID resultUuid, ResultsSelector selector) { + return resultRepository.getSensitivityResultFilterOptions(resultUuid, selector); + } + public void deleteResult(UUID resultUuid) { resultRepository.delete(resultUuid); } diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java index db3461a2..7acfb9c5 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java @@ -81,6 +81,7 @@ import static org.gridsuite.sensitivityanalysis.server.service.NotificationService.FAIL_MESSAGE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.eq; @@ -615,6 +616,30 @@ public void runAndSaveTest() throws Exception { assertEquals(6, (long) resNK.getTotalSensitivitiesCount()); assertEquals(2, resNK.getSensitivities().size()); + ResultsSelector filterOptionsSelector = ResultsSelector.builder().isJustBefore(false) + .functionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1).build(); + result = mockMvc.perform(get("/" + VERSION + "/results/{resultUuid}/filter-options?selector={selector}", RESULT_UUID, + mapper.writeValueAsString(filterOptionsSelector))) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + SensitivityResultFilterOptions filterOptions = mapper.readValue(result.getResponse().getContentAsString(), new TypeReference<>() { }); + assertEquals(3, filterOptions.getAllContingencyIds().size()); + assertEquals(3, filterOptions.getAllFunctionIds().size()); + assertEquals(2, filterOptions.getAllVariableIds().size()); + + ResultsSelector filterOptionsSelector2 = ResultsSelector.builder().isJustBefore(true) + .functionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_2).build(); + result = mockMvc.perform(get("/" + VERSION + "/results/{resultUuid}/filter-options?selector={selector}", RESULT_UUID, + mapper.writeValueAsString(filterOptionsSelector2))) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + SensitivityResultFilterOptions filterOptions2 = mapper.readValue(result.getResponse().getContentAsString(), new TypeReference<>() { }); + assertNull(filterOptions2.getAllContingencyIds()); + assertEquals(3, filterOptions2.getAllFunctionIds().size()); + assertEquals(2, filterOptions2.getAllVariableIds().size()); + // check that a request for not present contingency does not crash and just brings nothing ResultsSelector selectorNKz1 = ResultsSelector.builder().isJustBefore(false) .functionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1).contingencyIds(List.of("unfoundable")).build();