Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package org.gridsuite.securityanalysis.server;

import com.powsybl.iidm.network.ThreeSides;
import com.powsybl.loadflow.LoadFlowResult;
import com.powsybl.security.LimitViolationType;
import com.powsybl.security.SecurityAnalysisResult;
import io.swagger.v3.oas.annotations.Operation;
Expand Down Expand Up @@ -158,12 +159,12 @@ public ResponseEntity<byte[]> getNResultZippedCsv(@Parameter(description = "Resu
@Operation(summary = "Get a security analysis result from the database - NMK contingencies result")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The security analysis result"),
@ApiResponse(responseCode = "404", description = "Security analysis result has not been found")})
public ResponseEntity<Page<ContingencyResultDTO>> getNmKContingenciesResult(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid,
@Parameter(description = "network Uuid") @RequestParam(name = "networkUuid", required = false) UUID networkUuid,
@Parameter(description = "variant Id") @RequestParam(name = "variantId", required = false) String variantId,
@Parameter(description = "Filters") @RequestParam(name = "filters", required = false) String stringFilters,
@Parameter(description = "Global Filters") @RequestParam(name = "globalFilters", required = false) String globalFilters,
@Parameter(description = "Pagination parameters") Pageable pageable) {
public ResponseEntity<Page<ContingencyResultDTO>> getPagedNmKContingenciesResult(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid,
@Parameter(description = "network Uuid") @RequestParam(name = "networkUuid", required = false) UUID networkUuid,
@Parameter(description = "variant Id") @RequestParam(name = "variantId", required = false) String variantId,
@Parameter(description = "Filters") @RequestParam(name = "filters", required = false) String stringFilters,
@Parameter(description = "Global Filters") @RequestParam(name = "globalFilters", required = false) String globalFilters,
@Parameter(description = "Pagination parameters") Pageable pageable) {
String decodedStringFilters = stringFilters != null ? URLDecoder.decode(stringFilters, StandardCharsets.UTF_8) : null;
String decodedStringGlobalFilters = globalFilters != null ? URLDecoder.decode(globalFilters, StandardCharsets.UTF_8) : null;
Page<ContingencyResultDTO> result = securityAnalysisResultService.findNmKContingenciesPaged(resultUuid, networkUuid, variantId, decodedStringFilters, decodedStringGlobalFilters, pageable);
Expand All @@ -173,6 +174,18 @@ public ResponseEntity<Page<ContingencyResultDTO>> getNmKContingenciesResult(@Par
: ResponseEntity.notFound().build();
}

@GetMapping(value = "/results/{resultUuid}/nmk-contingencies-result", produces = APPLICATION_JSON_VALUE)
@Operation(summary = "Get a security analysis result from the database - NMK contingencies result")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The security analysis result"),
@ApiResponse(responseCode = "404", description = "Security analysis result has not been found")})
public ResponseEntity<List<ContingencyResultDTO>> getNmKContingenciesResult(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
List<ContingencyResultDTO> result = securityAnalysisResultService.findNmKContingenciesResult(resultUuid);

return result != null
? ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(result)
: ResponseEntity.notFound().build();
}

@PostMapping(value = "/results/{resultUuid}/nmk-contingencies-result/csv", produces = APPLICATION_OCTET_STREAM_VALUE, consumes = APPLICATION_JSON_VALUE)
@Operation(summary = "Get a security analysis result from the database - NMK contingencies result - CSV export")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The security analysis result csv export"),
Expand Down Expand Up @@ -247,6 +260,22 @@ public ResponseEntity<Void> stop(@Parameter(description = "Result UUID") @PathVa
return ResponseEntity.ok().build();
}

@PostMapping(value = "/results/{resultUuid}", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE)
@Operation(summary = "Save security analysis results")
@ApiResponses(value = {@ApiResponse(responseCode = "201", description = "The security analysis results have been saved to database")})
public ResponseEntity<Void> saveResult(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid,
@RequestBody SecurityAnalysisResult result) {
securityAnalysisResultService.insert(
null,
resultUuid,
result,
result.getPreContingencyResult().getStatus() == LoadFlowResult.ComponentResult.Status.CONVERGED
? SecurityAnalysisStatus.CONVERGED
: SecurityAnalysisStatus.DIVERGED
);
return ResponseEntity.ok().build();
}

@GetMapping(value = "/providers", produces = APPLICATION_JSON_VALUE)
@Operation(summary = "Get all security analysis providers")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Security analysis providers have been found")})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.FieldNameConstants;
import org.springframework.lang.Nullable;

import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -64,7 +65,7 @@ private void setContingencyLimitViolations(List<ContingencyLimitViolationEntity>
}
}

public static ContingencyEntity toEntity(Network network, PostContingencyResult postContingencyResult, Map<String, SubjectLimitViolationEntity> subjectLimitViolationsBySubjectId) {
public static ContingencyEntity toEntity(@Nullable Network network, PostContingencyResult postContingencyResult, Map<String, SubjectLimitViolationEntity> subjectLimitViolationsBySubjectId) {
List<ContingencyElementEmbeddable> contingencyElements = postContingencyResult.getContingency().getElements().stream().map(contingencyElement -> ContingencyElementEmbeddable.toEntity(contingencyElement)).collect(Collectors.toList());

List<ContingencyLimitViolationEntity> contingencyLimitViolations = postContingencyResult.getLimitViolationsResult().getLimitViolations().stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import lombok.*;
import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.springframework.lang.Nullable;

/**
* @author Kevin Le Saulnier <kevin.lesaulnier at rte-france.com>
Expand All @@ -30,28 +31,36 @@ public class ContingencyLimitViolationEntity extends AbstractLimitViolationEntit
@Setter
private ContingencyEntity contingency;

public static ContingencyLimitViolationEntity toEntity(Network network, LimitViolation limitViolation, SubjectLimitViolationEntity subjectLimitViolation) {
Double patlLimit = getPatlLimit(limitViolation, network);

ContingencyLimitViolationEntity contingencyLimitViolationEntity = ContingencyLimitViolationEntity.builder()
public static ContingencyLimitViolationEntity toEntity(@Nullable Network network, LimitViolation limitViolation, SubjectLimitViolationEntity subjectLimitViolation) {
ContingencyLimitViolationEntityBuilder<?, ?> contingencyLimitViolationEntityBuilder = ContingencyLimitViolationEntity.builder()
.limit(limitViolation.getLimit())
.limitName(limitViolation.getLimitName())
.limitType(limitViolation.getLimitType())
.limitReduction(limitViolation.getLimitReduction())
.value(limitViolation.getValue())
.side(limitViolation.getSide())
.loading(computeLoading(limitViolation, limitViolation.getLimit()))
.locationId(ComputationResultUtils.getViolationLocationId(limitViolation, network))
.subjectLimitViolation(subjectLimitViolation)
.patlLimit(patlLimit)
.patlLoading(computeLoading(limitViolation, patlLimit))
.nextLimitName(getNextLimitName(limitViolation, network))
.acceptableDuration(calculateActualOverloadDuration(limitViolation, network))
.upcomingAcceptableDuration(calculateUpcomingOverloadDuration(limitViolation))
.build();
.upcomingAcceptableDuration(calculateUpcomingOverloadDuration(limitViolation));

if (network != null) {
enrichBuilderWithNetworkData(contingencyLimitViolationEntityBuilder, network, limitViolation);
}

ContingencyLimitViolationEntity contingencyLimitViolationEntity = contingencyLimitViolationEntityBuilder.build();

subjectLimitViolation.addContingencyLimitViolation(contingencyLimitViolationEntity);

return contingencyLimitViolationEntity;
}

private static void enrichBuilderWithNetworkData(ContingencyLimitViolationEntityBuilder<?, ?> contingencyLimitViolationEntityBuilder, Network network, LimitViolation limitViolation) {
Double patlLimit = getPatlLimit(limitViolation, network);
contingencyLimitViolationEntityBuilder
.patlLimit(patlLimit)
.patlLoading(computeLoading(limitViolation, patlLimit))
.nextLimitName(getNextLimitName(limitViolation, network))
.locationId(ComputationResultUtils.getViolationLocationId(limitViolation, network))
.acceptableDuration(calculateActualOverloadDuration(limitViolation, network));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import jakarta.persistence.*;
import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.springframework.lang.Nullable;

import java.util.List;
import java.util.Map;
Expand All @@ -35,27 +36,37 @@ public class PreContingencyLimitViolationEntity extends AbstractLimitViolationEn
@Setter
SecurityAnalysisResultEntity result;

public static List<PreContingencyLimitViolationEntity> toEntityList(Network network, PreContingencyResult preContingencyResult, Map<String, SubjectLimitViolationEntity> subjectLimitViolationsBySubjectId) {
public static List<PreContingencyLimitViolationEntity> toEntityList(@Nullable Network network, PreContingencyResult preContingencyResult, Map<String, SubjectLimitViolationEntity> subjectLimitViolationsBySubjectId) {
return preContingencyResult.getLimitViolationsResult().getLimitViolations().stream().map(limitViolation -> toEntity(network, limitViolation, subjectLimitViolationsBySubjectId.get(limitViolation.getSubjectId()))).collect(Collectors.toList());
}

public static PreContingencyLimitViolationEntity toEntity(Network network, LimitViolation limitViolation, SubjectLimitViolationEntity subjectLimitViolation) {
Double patlLimit = getPatlLimit(limitViolation, network);
return PreContingencyLimitViolationEntity.builder()
public static PreContingencyLimitViolationEntity toEntity(@Nullable Network network, LimitViolation limitViolation, SubjectLimitViolationEntity subjectLimitViolation) {
PreContingencyLimitViolationEntityBuilder<?, ?> preContingencyLimitViolationEntityBuilder = PreContingencyLimitViolationEntity.builder()
.subjectLimitViolation(subjectLimitViolation)
.limit(limitViolation.getLimit())
.limitName(limitViolation.getLimitName())
.limitType(limitViolation.getLimitType())
.acceptableDuration(calculateActualOverloadDuration(limitViolation, network))
.upcomingAcceptableDuration(calculateUpcomingOverloadDuration(limitViolation))
.limitReduction(limitViolation.getLimitReduction())
.value(limitViolation.getValue())
.side(limitViolation.getSide())
.loading(computeLoading(limitViolation, limitViolation.getLimit()));

if (network != null) {
enrichBuilderWithNetworkData(preContingencyLimitViolationEntityBuilder, network, limitViolation);
}

return preContingencyLimitViolationEntityBuilder.build();
}

private static void enrichBuilderWithNetworkData(PreContingencyLimitViolationEntity.PreContingencyLimitViolationEntityBuilder<?, ?> preContingencyLimitViolationEntityBuilder, Network network, LimitViolation limitViolation) {
Double patlLimit = getPatlLimit(limitViolation, network);

preContingencyLimitViolationEntityBuilder
.acceptableDuration(calculateActualOverloadDuration(limitViolation, network))
.patlLimit(patlLimit)
.loading(computeLoading(limitViolation, limitViolation.getLimit()))
.patlLoading(computeLoading(limitViolation, patlLimit))
.locationId(ComputationResultUtils.getViolationLocationId(limitViolation, network))
.nextLimitName(getNextLimitName(limitViolation, network))
.build();
.nextLimitName(getNextLimitName(limitViolation, network));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import lombok.experimental.FieldNameConstants;
import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisStatus;
import org.jgrapht.alg.util.Pair;
import org.springframework.lang.Nullable;

import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -53,7 +54,7 @@ public SecurityAnalysisResultEntity(UUID id) {
this.id = id;
}

public static SecurityAnalysisResultEntity toEntity(Network network, UUID resultUuid, SecurityAnalysisResult securityAnalysisResult, SecurityAnalysisStatus securityAnalysisStatus) {
public static SecurityAnalysisResultEntity toEntity(@Nullable Network network, UUID resultUuid, SecurityAnalysisResult securityAnalysisResult, SecurityAnalysisStatus securityAnalysisStatus) {
Map<String, SubjectLimitViolationEntity> subjectLimitViolationsBySubjectId = getUniqueSubjectLimitViolationsFromResult(securityAnalysisResult)
.stream().collect(Collectors.toMap(
SubjectLimitViolationEntity::getSubjectId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -238,7 +239,7 @@ public void assertResultExists(UUID resultUuid) {
}

@Transactional
public void insert(Network network, UUID resultUuid, SecurityAnalysisResult result, SecurityAnalysisStatus status) {
public void insert(@Nullable Network network, UUID resultUuid, SecurityAnalysisResult result, SecurityAnalysisStatus status) {
Objects.requireNonNull(resultUuid);
Objects.requireNonNull(result);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet author="lesaulnierkev (generated)" id="1768561622788-1">
<dropNotNullConstraint columnDataType="int" columnName="acceptable_duration" tableName="contingency_limit_violation"/>
</changeSet>
<changeSet author="lesaulnierkev (generated)" id="1768561622788-2">
<dropNotNullConstraint columnDataType="int" columnName="acceptable_duration" tableName="pre_contingency_limit_violation"/>
</changeSet>
</databaseChangeLog>
3 changes: 3 additions & 0 deletions src/main/resources/db/changelog/db.changelog-master.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,6 @@ databaseChangeLog:
- include:
file: changesets/changelog_20250908T143920Z.xml
relativeToChangelogFile: true
- include:
file: changesets/changelog_20260116T110615Z.xml
relativeToChangelogFile: true
Loading
Loading