Skip to content
Open
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 @@ -198,6 +198,7 @@
@Parameter(description = "variant Id") @RequestParam(name = "variantId", required = false) String variantId,
@Parameter(description = "Filters") @RequestParam(name = "filters", required = false) String filters,
@Parameter(description = "Global Filters") @RequestParam(name = "globalFilters", required = false) String globalFilters,
@Parameter(description = "Power cut-off") @RequestParam(name = "isPowerCutOffView", required = false) boolean isPowerCutOffView,

Check failure on line 201 in src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisController.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Convert this optional parameter to an Object type.

See more on https://sonarcloud.io/project/issues?id=org.gridsuite%3Asecurity-analysis-server&issues=AZ5AT9-oPWCvOppt3cr7&open=AZ5AT9-oPWCvOppt3cr7&pullRequest=245
@Parameter(description = "Translation properties") @RequestBody CsvTranslationDTO csvTranslations,
@Parameter(description = "Sort parameters") Sort sort) {
return ResponseEntity.ok()
Expand All @@ -208,6 +209,7 @@
variantId,
filters,
globalFilters,
isPowerCutOffView,
sort,
csvTranslations
));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Copyright (c) 2026, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.gridsuite.securityanalysis.server.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.gridsuite.securityanalysis.server.entities.ConnectivityResultEmbeddable;

/**
* @author Ghazwa Rehili <ghazwa.rehili at rte-france.com>
*/

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ConnectivityResultDTO {
private Double disconnectedLoadActivePower;
private Double disconnectedGenerationActivePower;

public static ConnectivityResultDTO toDto(ConnectivityResultEmbeddable connectivityResult) {
if (connectivityResult == null) {
return ConnectivityResultDTO.builder()
.disconnectedLoadActivePower(null)
.disconnectedGenerationActivePower(null)
.build();
}
return ConnectivityResultDTO.builder()
.disconnectedLoadActivePower(connectivityResult.getDisconnectedLoadActivePower())
.disconnectedGenerationActivePower(connectivityResult.getDisconnectedGenerationActivePower())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ public class ContingencyDTO {
private String contingencyId;
private String status;
private List<ContingencyElementDTO> elements;
private ConnectivityResultDTO connectivityResult;

public static ContingencyDTO toDto(ContingencyEntity contingency) {
return ContingencyDTO.builder()
.contingencyId(contingency.getContingencyId())
.status(contingency.getStatus())
.elements(contingency.getContingencyElements().stream().map(ContingencyElementDTO::toDto).collect(Collectors.toList()))
.connectivityResult(ConnectivityResultDTO.toDto(contingency.getConnectivityResult()))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,19 @@ public static ContingencyResultDTO toDto(ContingencyEntity contingency) {
}

// each contingencyResultDto will return multiple line (one for each limitViolation)
public List<List<String>> toCsvRows(Map<String, String> translations, String language) {
public List<List<String>> toCsvRows(Map<String, String> translations, String language, boolean isPowerCutOffView) {
return this.getSubjectLimitViolations().stream().map(lm -> {
List<String> csvRow = new ArrayList<>();
csvRow.add(this.getContingency().getContingencyId());
csvRow.add(CsvExportUtils.translate(this.getContingency().getStatus(), translations));
if (isPowerCutOffView && this.getContingency().getConnectivityResult().getDisconnectedLoadActivePower() != null
&& this.getContingency().getConnectivityResult().getDisconnectedGenerationActivePower() != null) {
csvRow.add(CsvExportUtils.convertDoubleToLocale(this.getContingency().getConnectivityResult().getDisconnectedLoadActivePower(), language));
csvRow.add(CsvExportUtils.convertDoubleToLocale(this.getContingency().getConnectivityResult().getDisconnectedGenerationActivePower(), language));
return csvRow;
}
csvRow.add(lm.getSubjectId());

csvRow.addAll(lm.getLimitViolation().toCsvRow(translations, language));

return csvRow;
}).toList();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
import org.gridsuite.securityanalysis.server.entities.AbstractLimitViolationEntity;
import org.gridsuite.securityanalysis.server.util.CsvExportUtils;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import static org.gridsuite.securityanalysis.server.util.CsvExportUtils.convertDoubleToLocale;

@AllArgsConstructor
@NoArgsConstructor
@Builder
Expand Down Expand Up @@ -54,12 +54,6 @@ public static LimitViolationDTO toDto(AbstractLimitViolationEntity limitViolatio
.build();
}

private static String convertDoubleToLocale(Double value, String language) {
NumberFormat nf = NumberFormat.getInstance(language != null && language.equals("fr") ? Locale.FRENCH : Locale.US);
nf.setGroupingUsed(false);
return nf.format(value);
}

public List<String> toCsvRow(Map<String, String> translations, String language) {
List<String> csvRow = new ArrayList<>();
csvRow.add(this.getLimitType() != null ? CsvExportUtils.translate(this.getLimitType().name(), translations) : "");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Copyright (c) 2026, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.gridsuite.securityanalysis.server.entities;

import com.powsybl.security.results.ConnectivityResult;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

/**
* @author Ghazwa Rehili <ghazwa.rehili at rte-france.com>
*/

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Embeddable
public class ConnectivityResultEmbeddable {
@Column
private Double disconnectedLoadActivePower;

@Column
private Double disconnectedGenerationActivePower;

public static ConnectivityResultEmbeddable toEntity(ConnectivityResult connectivityResult) {
if (connectivityResult.getDisconnectedLoadActivePower() == 0.0 && connectivityResult.getDisconnectedGenerationActivePower() == 0.0) {
return null;
}
return ConnectivityResultEmbeddable.builder()
.disconnectedGenerationActivePower(connectivityResult.getDisconnectedGenerationActivePower())
.disconnectedLoadActivePower(connectivityResult.getDisconnectedLoadActivePower())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@
@Table(name = "contingency")
public class ContingencyEntity {

public ContingencyEntity(String contingencyId, String status, List<ContingencyElementEmbeddable> contingencyElements, List<ContingencyLimitViolationEntity> contingencyLimitViolations) {
public ContingencyEntity(String contingencyId, String status, List<ContingencyElementEmbeddable> contingencyElements, ConnectivityResultEmbeddable connectivityResult,
List<ContingencyLimitViolationEntity> contingencyLimitViolations) {
this.contingencyId = contingencyId;
this.status = status;
this.contingencyElements = contingencyElements;
this.connectivityResult = connectivityResult;
setContingencyLimitViolations(contingencyLimitViolations);
}

Expand All @@ -54,6 +56,9 @@ public ContingencyEntity(String contingencyId, String status, List<ContingencyEl
@OneToMany(mappedBy = "contingency", cascade = CascadeType.ALL, orphanRemoval = true)
List<ContingencyLimitViolationEntity> contingencyLimitViolations;

@Embedded
private ConnectivityResultEmbeddable connectivityResult;

/**
* We keep a String as it could model LoadFlowResult.ComponentResult.Status or PostContingencyComputationStatus.
*/
Expand All @@ -72,6 +77,7 @@ public static ContingencyEntity toEntity(@Nullable Network network, PostContinge
List<ContingencyLimitViolationEntity> contingencyLimitViolations = postContingencyResult.getLimitViolationsResult().getLimitViolations().stream()
.map(limitViolation -> ContingencyLimitViolationEntity.toEntity(network, limitViolation, subjectLimitViolationsBySubjectId.get(limitViolation.getSubjectId())))
.collect(Collectors.toList());
return new ContingencyEntity(postContingencyResult.getContingency().getId(), postContingencyResult.getStatus().name(), contingencyElements, contingencyLimitViolations);
ConnectivityResultEmbeddable connectivityResult = ConnectivityResultEmbeddable.toEntity(postContingencyResult.getConnectivityResult());
return new ContingencyEntity(postContingencyResult.getContingency().getId(), postContingencyResult.getStatus().name(), contingencyElements, connectivityResult, contingencyLimitViolations);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,9 @@
}

@Transactional(readOnly = true)
public byte[] findNmKContingenciesResultZippedCsv(UUID resultUuid, UUID networkUuid, String variantId, String stringFilters, String stringGlobalFilters, Sort sort, CsvTranslationDTO csvTranslations) {
public byte[] findNmKContingenciesResultZippedCsv(UUID resultUuid, UUID networkUuid, String variantId, String stringFilters, String stringGlobalFilters, boolean isPowerCutOffView, Sort sort, CsvTranslationDTO csvTranslations) {

Check warning on line 180 in src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Method has 8 parameters, which is greater than 7 authorized.

See more on https://sonarcloud.io/project/issues?id=org.gridsuite%3Asecurity-analysis-server&issues=AZ5AT96WPWCvOppt3cr6&open=AZ5AT96WPWCvOppt3cr6&pullRequest=245
List<ContingencyResultDTO> result = self.findNmKContingenciesPaged(resultUuid, networkUuid, variantId, stringFilters, stringGlobalFilters, Pageable.unpaged(sort)).getContent();
return CsvExportUtils.csvRowsToZippedCsv(csvTranslations.headers(), csvTranslations.language(), result.stream().map(r -> r.toCsvRows(csvTranslations.enumValueTranslations(), csvTranslations.language())).flatMap(List::stream).toList());
return CsvExportUtils.csvRowsToZippedCsv(csvTranslations.headers(), csvTranslations.language(), result.stream().map(r -> r.toCsvRows(csvTranslations.enumValueTranslations(), csvTranslations.language(), isPowerCutOffView)).flatMap(List::stream).toList());
}

@Transactional(readOnly = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.text.NumberFormat;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
Expand Down Expand Up @@ -70,4 +72,10 @@ public static String translate(String valueToTranslate, Map<String, String> tran
// if translated value is null, we keep original value (untranslated value)
return translations.getOrDefault(valueToTranslate, valueToTranslate);
}

public static String convertDoubleToLocale(Double value, String language) {
NumberFormat nf = NumberFormat.getInstance(language != null && language.equals("fr") ? Locale.FRENCH : Locale.US);
nf.setGroupingUsed(false);
return nf.format(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?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="rehiligha (generated)" id="1775814367027-1">
<addColumn tableName="contingency">
<column name="disconnected_generation_active_power" type="float(53)"/>
</addColumn>
</changeSet>
<changeSet author="rehiligha (generated)" id="1775814367027-2">
<addColumn tableName="contingency">
<column name="disconnected_load_active_power" type="float(53)"/>
</addColumn>
</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 @@ -69,3 +69,6 @@ databaseChangeLog:
- include:
file: changesets/changelog_20260423T124334Z.xml
relativeToChangelogFile: true
- include:
file: changesets/changelog_20260519T125101Z.xml
relativeToChangelogFile: true
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ public class SecurityAnalysisProviderMock implements SecurityAnalysisProvider {
// CONTINGENCIES_WITHOUT_LIMIT_VIOLATION should not be contained here since it does not contain any LIMIT_VIOLATION
// CONTINGENCIES_NOT_CONVERGED_WITHOUT_LIMIT_VIOLATION is here because status is not "CONVERGED"
static final List<ContingencyResultDTO> RESULT_CONTINGENCIES = Stream.of(
CONTINGENCIES.stream().map(c -> toContingencyResultDTO(c.getContingency(), LoadFlowResult.ComponentResult.Status.CONVERGED.name(), RESULT_LIMIT_VIOLATIONS)),
FAILED_CONTINGENCIES.stream().map(c -> toContingencyResultDTO(c, LoadFlowResult.ComponentResult.Status.FAILED.name(), FAILED_LIMIT_VIOLATIONS)),
CONTINGENCIES_NOT_CONVERGED_WITHOUT_LIMIT_VIOLATION.stream().map(c -> toContingencyResultDTO(c, LoadFlowResult.ComponentResult.Status.FAILED.name(), List.of())))
CONTINGENCIES.stream().map(c -> toContingencyResultDTO(c.getContingency(), LoadFlowResult.ComponentResult.Status.CONVERGED.name(), RESULT_LIMIT_VIOLATIONS, ConnectivityResultDTO.builder().disconnectedLoadActivePower(12.03).disconnectedGenerationActivePower(0.0).build())),
FAILED_CONTINGENCIES.stream().map(c -> toContingencyResultDTO(c, LoadFlowResult.ComponentResult.Status.FAILED.name(), FAILED_LIMIT_VIOLATIONS, ConnectivityResultDTO.builder().disconnectedLoadActivePower(0.0).disconnectedGenerationActivePower(12.03).build())),
CONTINGENCIES_NOT_CONVERGED_WITHOUT_LIMIT_VIOLATION.stream().map(c -> toContingencyResultDTO(c, LoadFlowResult.ComponentResult.Status.FAILED.name(), List.of(), ConnectivityResultDTO.builder().disconnectedLoadActivePower(0.0).disconnectedGenerationActivePower(0.0).build())))
.flatMap(Function.identity()).toList();

static List<ContingencyResultDTO> getResultContingenciesWithNestedFilter(Function<SubjectLimitViolationDTO, Boolean> filterMethod) {
Expand Down Expand Up @@ -150,9 +150,9 @@ static List<ContingencyResultDTO> getResultContingenciesSorted(Comparator<Subjec

static final List<SubjectLimitViolationResultDTO> RESULT_CONSTRAINTS = Stream.concat(
RESULT_LIMIT_VIOLATIONS.stream()
.map(limitViolation -> toSubjectLimitViolationResultDTO(limitViolation, CONTINGENCIES.stream().map(ContingencyInfos::getContingency).collect(Collectors.toList()), LoadFlowResult.ComponentResult.Status.CONVERGED)),
.map(limitViolation -> toSubjectLimitViolationResultDTO(limitViolation, CONTINGENCIES.stream().map(ContingencyInfos::getContingency).collect(Collectors.toList()), LoadFlowResult.ComponentResult.Status.CONVERGED, ConnectivityResultDTO.builder().disconnectedLoadActivePower(0.0).disconnectedGenerationActivePower(-852.36).build())),
FAILED_LIMIT_VIOLATIONS.stream()
.map(limitViolation -> toSubjectLimitViolationResultDTO(limitViolation, FAILED_CONTINGENCIES, LoadFlowResult.ComponentResult.Status.FAILED))
.map(limitViolation -> toSubjectLimitViolationResultDTO(limitViolation, FAILED_CONTINGENCIES, LoadFlowResult.ComponentResult.Status.FAILED, ConnectivityResultDTO.builder().disconnectedLoadActivePower(885.16).disconnectedGenerationActivePower(0.0).build()))
).toList();

static List<SubjectLimitViolationResultDTO> getResultConstraintsWithNestedFilter(Function<ContingencyLimitViolationDTO, Boolean> filterMethod) {
Expand Down Expand Up @@ -251,10 +251,10 @@ private static SubjectLimitViolationDTO toSubjectLimitViolationDTO(LimitViolatio
);
}

private static SubjectLimitViolationResultDTO toSubjectLimitViolationResultDTO(LimitViolation limitViolation, List<Contingency> convergedContingencies, LoadFlowResult.ComponentResult.Status status) {
private static SubjectLimitViolationResultDTO toSubjectLimitViolationResultDTO(LimitViolation limitViolation, List<Contingency> convergedContingencies, LoadFlowResult.ComponentResult.Status status, ConnectivityResultDTO connectivityResult) {
return new SubjectLimitViolationResultDTO(
limitViolation.getSubjectId(),
convergedContingencies.stream().map(c -> toContingencyLimitViolationDTO(c, limitViolation, status.name())).toList());
convergedContingencies.stream().map(c -> toContingencyLimitViolationDTO(c, limitViolation, status.name(), connectivityResult)).toList());
}

private static PreContingencyLimitViolationResultDTO toPreContingencyResultDTO(LimitViolation limitViolation, LoadFlowResult.ComponentResult.Status status) {
Expand All @@ -277,20 +277,20 @@ private static PreContingencyLimitViolationResultDTO toPreContingencyResultDTO(L
.build());
}

private static ContingencyResultDTO toContingencyResultDTO(Contingency contingency, String status, List<LimitViolation> limitViolations) {
private static ContingencyResultDTO toContingencyResultDTO(Contingency contingency, String status, List<LimitViolation> limitViolations, ConnectivityResultDTO connectivityResult) {
return new ContingencyResultDTO(
new ContingencyDTO(
contingency.getId(),
status,
contingency.getElements().stream().map(e -> new ContingencyElementDTO(e.getId(), e.getType())).toList()
contingency.getElements().stream().map(e -> new ContingencyElementDTO(e.getId(), e.getType())).toList(), connectivityResult
),
limitViolations.stream()
.map(SecurityAnalysisProviderMock::toSubjectLimitViolationDTO)
.toList()
);
}

private static ContingencyLimitViolationDTO toContingencyLimitViolationDTO(Contingency contingency, LimitViolation limitViolation, String status) {
private static ContingencyLimitViolationDTO toContingencyLimitViolationDTO(Contingency contingency, LimitViolation limitViolation, String status, ConnectivityResultDTO connectivityResult) {
Double computedLoading = limitViolation.getLimitType().equals(LimitViolationType.CURRENT)
? (100 * limitViolation.getValue()) / (limitViolation.getLimit() * limitViolation.getLimitReduction())
: null;
Expand All @@ -299,7 +299,7 @@ private static ContingencyLimitViolationDTO toContingencyLimitViolationDTO(Conti
new ContingencyDTO(
contingency.getId(),
status,
contingency.getElements().stream().map(e -> new ContingencyElementDTO(e.getId(), e.getType())).toList()
contingency.getElements().stream().map(e -> new ContingencyElementDTO(e.getId(), e.getType())).toList(), connectivityResult
),
LimitViolationDTO.builder()
.limitType(limitViolation.getLimitType())
Expand Down
Loading