From 2352f3ac509dc5992f11d731fe03aefd0c87358c Mon Sep 17 00:00:00 2001 From: lisrte Date: Fri, 15 Nov 2024 16:42:28 +0100 Subject: [PATCH] Build PreContingencyResult from aggregated results and constraints files for DSA Signed-off-by: lisrte --- .../DynaFlowSecurityAnalysisHandler.java | 10 +--- .../dynaflow/SecurityAnalysisConstants.java | 2 + .../results/ContingencyResultsUtils.java | 58 +++++++++++++------ .../powsybl/dynaflow/results/ResultsUtil.java | 17 ++++-- .../dynaflow/xml/ConstraintsReader.java | 4 +- .../convergence/results.json | 4 +- .../divergence/results.json | 6 +- .../failed-criteria/results.json | 6 +- .../DynawoSecurityAnalysisHandler.java | 11 +--- .../dynawo/security/xml/MultipleJobsXml.java | 3 +- 10 files changed, 70 insertions(+), 51 deletions(-) diff --git a/dynaflow/src/main/java/com/powsybl/dynaflow/DynaFlowSecurityAnalysisHandler.java b/dynaflow/src/main/java/com/powsybl/dynaflow/DynaFlowSecurityAnalysisHandler.java index a857fef1d..8bb3a2d25 100644 --- a/dynaflow/src/main/java/com/powsybl/dynaflow/DynaFlowSecurityAnalysisHandler.java +++ b/dynaflow/src/main/java/com/powsybl/dynaflow/DynaFlowSecurityAnalysisHandler.java @@ -26,18 +26,17 @@ import com.powsybl.security.LimitViolationFilter; import com.powsybl.security.SecurityAnalysisParameters; import com.powsybl.security.SecurityAnalysisReport; -import com.powsybl.security.SecurityAnalysisResult; import com.powsybl.security.interceptors.SecurityAnalysisInterceptor; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Collections; import java.util.List; import static com.powsybl.dynaflow.DynaFlowConstants.CONFIG_FILENAME; import static com.powsybl.dynaflow.SecurityAnalysisConstants.CONTINGENCIES_FILENAME; +import static com.powsybl.dynaflow.results.ContingencyResultsUtils.createSecurityAnalysisResult; import static com.powsybl.dynawo.commons.DynawoConstants.NETWORK_FILENAME; import static com.powsybl.dynawo.commons.DynawoConstants.TIMELINE_FOLDER; import static com.powsybl.dynawo.commons.DynawoUtil.getCommandExecutions; @@ -85,12 +84,7 @@ public SecurityAnalysisReport after(Path workingDir, ExecutionReport report) thr super.after(workingDir, report); network.getVariantManager().setWorkingVariant(workingVariantId); ContingencyResultsUtils.reportContingenciesTimelines(contingencies, workingDir.resolve(TIMELINE_FOLDER), reportNode); - return new SecurityAnalysisReport( - new SecurityAnalysisResult( - ContingencyResultsUtils.getPreContingencyResult(network, violationFilter), - ContingencyResultsUtils.getPostContingencyResults(network, violationFilter, workingDir, contingencies), - Collections.emptyList()) - ); + return new SecurityAnalysisReport(createSecurityAnalysisResult(network, violationFilter, workingDir, contingencies)); } private static void writeContingencies(List contingencies, Path workingDir) throws IOException { diff --git a/dynaflow/src/main/java/com/powsybl/dynaflow/SecurityAnalysisConstants.java b/dynaflow/src/main/java/com/powsybl/dynaflow/SecurityAnalysisConstants.java index e50d9b274..60ebdcfb0 100644 --- a/dynaflow/src/main/java/com/powsybl/dynaflow/SecurityAnalysisConstants.java +++ b/dynaflow/src/main/java/com/powsybl/dynaflow/SecurityAnalysisConstants.java @@ -16,6 +16,8 @@ public final class SecurityAnalysisConstants { public static final String CONTINGENCIES_FILENAME = "contingencies.json"; + public static final String BASE_SCENARIO_NAME = "Base"; + private SecurityAnalysisConstants() { } diff --git a/dynaflow/src/main/java/com/powsybl/dynaflow/results/ContingencyResultsUtils.java b/dynaflow/src/main/java/com/powsybl/dynaflow/results/ContingencyResultsUtils.java index 1de95b7eb..ee19a8cc3 100644 --- a/dynaflow/src/main/java/com/powsybl/dynaflow/results/ContingencyResultsUtils.java +++ b/dynaflow/src/main/java/com/powsybl/dynaflow/results/ContingencyResultsUtils.java @@ -16,10 +16,7 @@ import com.powsybl.dynawo.commons.timeline.XmlTimeLineParser; import com.powsybl.iidm.network.Network; import com.powsybl.loadflow.LoadFlowResult; -import com.powsybl.security.LimitViolation; -import com.powsybl.security.LimitViolationFilter; -import com.powsybl.security.LimitViolationsResult; -import com.powsybl.security.Security; +import com.powsybl.security.*; import com.powsybl.security.results.NetworkResult; import com.powsybl.security.results.PostContingencyResult; import com.powsybl.security.results.PreContingencyResult; @@ -31,6 +28,7 @@ import java.util.List; import java.util.Map; +import static com.powsybl.dynaflow.SecurityAnalysisConstants.BASE_SCENARIO_NAME; import static com.powsybl.dynaflow.SecurityAnalysisConstants.CONSTRAINTS_FOLDER; import static com.powsybl.dynawo.commons.DynawoConstants.AGGREGATED_RESULTS; @@ -42,37 +40,59 @@ public final class ContingencyResultsUtils { private ContingencyResultsUtils() { } + public static SecurityAnalysisResult createSecurityAnalysisResult(Network network, LimitViolationFilter violationFilter, + Path workingDir, List contingencies) { + Map aggregatedResults = getAggregatedResults(workingDir); + Path constraintsDir = workingDir.resolve(CONSTRAINTS_FOLDER); + return new SecurityAnalysisResult( + ContingencyResultsUtils.getPreContingencyResult(network, violationFilter, constraintsDir, aggregatedResults), + ContingencyResultsUtils.getPostContingencyResults(network, violationFilter, constraintsDir, aggregatedResults, contingencies), + Collections.emptyList()); + } + /** - * Build the pre-contingency results from the input network + * Build the pre-contingency results from the constraints file written by dynawo or directly form the network if the results are not found */ - public static PreContingencyResult getPreContingencyResult(Network network, LimitViolationFilter violationFilter) { - List limitViolations = Security.checkLimits(network); - List filteredViolations = violationFilter.apply(limitViolations, network); + private static PreContingencyResult getPreContingencyResult(Network network, LimitViolationFilter violationFilter, + Path constraintsDir, Map scenarioResults) { NetworkResult networkResult = new NetworkResult(Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); - return new PreContingencyResult(LoadFlowResult.ComponentResult.Status.CONVERGED, new LimitViolationsResult(filteredViolations), networkResult); + if (scenarioResults.containsKey(BASE_SCENARIO_NAME)) { + return new PreContingencyResult(ResultsUtil.convertToPreStatus(scenarioResults.get(BASE_SCENARIO_NAME)), + getLimitViolationsResult(network, violationFilter, constraintsDir, BASE_SCENARIO_NAME), + networkResult); + } else { + //Dynaflow SA case (see issue #174) + List limitViolations = Security.checkLimits(network); + List filteredViolations = violationFilter.apply(limitViolations, network); + return new PreContingencyResult(LoadFlowResult.ComponentResult.Status.CONVERGED, new LimitViolationsResult(filteredViolations), networkResult); + } } /** * Build the post-contingency results from the constraints files written by dynawo */ - public static List getPostContingencyResults(Network network, LimitViolationFilter violationFilter, - Path workingDir, List contingencies) { - Path constraintsDir = workingDir.resolve(CONSTRAINTS_FOLDER); + private static List getPostContingencyResults(Network network, LimitViolationFilter violationFilter, + Path constraintsDir, Map scenarioResults, + List contingencies) { + return contingencies.stream() + .map(c -> new PostContingencyResult(c, + ResultsUtil.convertToPostStatus(scenarioResults.getOrDefault(c.getId(), Status.EXECUTION_PROBLEM)), + getLimitViolationsResult(network, violationFilter, constraintsDir, c.getId()))) + .toList(); + } + + private static Map getAggregatedResults(Path workingDir) { Path results = workingDir.resolve(AGGREGATED_RESULTS); Map scenarioResults = new HashMap<>(); if (Files.exists(results)) { new XmlScenarioResultParser().parse(results, s -> scenarioResults.put(s.id(), s.status())); } - return contingencies.stream() - .map(c -> new PostContingencyResult(c, - ResultsUtil.convertStatus(scenarioResults.getOrDefault(c.getId(), Status.EXECUTION_PROBLEM)), - getLimitViolationsResult(network, violationFilter, constraintsDir, c))) - .toList(); + return scenarioResults; } private static LimitViolationsResult getLimitViolationsResult(Network network, LimitViolationFilter violationFilter, - Path constraintsDir, Contingency contingency) { - Path constraintsFile = constraintsDir.resolve("constraints_" + contingency.getId() + ".xml"); + Path constraintsDir, String contingencyName) { + Path constraintsFile = constraintsDir.resolve("constraints_" + contingencyName + ".xml"); if (Files.exists(constraintsFile)) { List limitViolationsRead = ConstraintsReader.read(network, constraintsFile); List limitViolationsFiltered = violationFilter.apply(limitViolationsRead, network); diff --git a/dynaflow/src/main/java/com/powsybl/dynaflow/results/ResultsUtil.java b/dynaflow/src/main/java/com/powsybl/dynaflow/results/ResultsUtil.java index 5cb8fe3b5..1f06878b0 100644 --- a/dynaflow/src/main/java/com/powsybl/dynaflow/results/ResultsUtil.java +++ b/dynaflow/src/main/java/com/powsybl/dynaflow/results/ResultsUtil.java @@ -7,6 +7,7 @@ */ package com.powsybl.dynaflow.results; +import com.powsybl.loadflow.LoadFlowResult; import com.powsybl.security.PostContingencyComputationStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,7 +17,6 @@ import static com.powsybl.dynaflow.results.Status.CONVERGENCE; import static com.powsybl.dynaflow.results.Status.CRITERIA_NON_RESPECTED; -import static com.powsybl.security.PostContingencyComputationStatus.*; /** * @author Laurent Issertial {@literal } @@ -28,11 +28,18 @@ private ResultsUtil() { private static final Logger LOGGER = LoggerFactory.getLogger(ResultsUtil.class); - public static PostContingencyComputationStatus convertStatus(Status status) { + public static PostContingencyComputationStatus convertToPostStatus(Status status) { return switch (status) { - case CONVERGENCE -> CONVERGED; - case DIVERGENCE -> SOLVER_FAILED; - case EXECUTION_PROBLEM, CRITERIA_NON_RESPECTED -> FAILED; + case CONVERGENCE -> PostContingencyComputationStatus.CONVERGED; + case DIVERGENCE -> PostContingencyComputationStatus.SOLVER_FAILED; + case EXECUTION_PROBLEM, CRITERIA_NON_RESPECTED -> PostContingencyComputationStatus.FAILED; + }; + } + + public static LoadFlowResult.ComponentResult.Status convertToPreStatus(Status status) { + return switch (status) { + case CONVERGENCE -> LoadFlowResult.ComponentResult.Status.CONVERGED; + case DIVERGENCE, EXECUTION_PROBLEM, CRITERIA_NON_RESPECTED -> LoadFlowResult.ComponentResult.Status.FAILED; }; } diff --git a/dynaflow/src/main/java/com/powsybl/dynaflow/xml/ConstraintsReader.java b/dynaflow/src/main/java/com/powsybl/dynaflow/xml/ConstraintsReader.java index e666dde9c..c7fb3dee0 100644 --- a/dynaflow/src/main/java/com/powsybl/dynaflow/xml/ConstraintsReader.java +++ b/dynaflow/src/main/java/com/powsybl/dynaflow/xml/ConstraintsReader.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Optional; import java.util.function.Supplier; +import java.util.regex.Pattern; /** * @author Marcos de Miguel {@literal } @@ -53,6 +54,7 @@ public final class ConstraintsReader { private static final Supplier XML_INPUT_FACTORY_SUPPLIER = Suppliers.memoize(XMLInputFactory::newInstance); public static final String DYN_CALCULATED_BUS_PREFIX = "calculatedBus_"; + public static final Pattern DYN_CALCULATED_BUS_PATTERN = Pattern.compile("calculatedBus_" + ".*_\\d*"); public static List read(Network network, Path xmlFile) { try (InputStream is = Files.newInputStream(xmlFile)) { @@ -130,7 +132,7 @@ private static Optional getLimitViolation(Network network, Strin } private static Optional> getLimitViolationIdentifiable(Network network, String name) { - if (name.matches(DYN_CALCULATED_BUS_PREFIX + ".*_\\d*")) { + if (DYN_CALCULATED_BUS_PATTERN.matcher(name).matches()) { // FIXME: the voltage level information should be directly referenced // The naming corresponds to buses which are calculated in dynawo: https://github.com/dynawo/dynawo/blob/8f1e20e43db7ec4d2e4982deac8307dfa8d0dbec/dynawo/sources/Modeler/DataInterface/PowSyblIIDM/DYNVoltageLevelInterfaceIIDM.cpp#L290 String vlId = name.substring(DYN_CALCULATED_BUS_PREFIX.length(), name.lastIndexOf("_")); diff --git a/dynawo-integration-tests/src/test/resources/ieee14/dynamic-security-analysis/convergence/results.json b/dynawo-integration-tests/src/test/resources/ieee14/dynamic-security-analysis/convergence/results.json index 90ddb1f93..55ea04f14 100644 --- a/dynawo-integration-tests/src/test/resources/ieee14/dynamic-security-analysis/convergence/results.json +++ b/dynawo-integration-tests/src/test/resources/ieee14/dynamic-security-analysis/convergence/results.json @@ -7,10 +7,10 @@ "subjectId" : "_BUS____1-BUS____2-1_AC", "subjectName" : "BUS 1-BUS 2-1", "limitType" : "CURRENT", - "limitName" : "permanent", + "limitName" : "PATL", "limit" : 836.74, "limitReduction" : 1.0, - "value" : 1248.0773003764798, + "value" : 1248.100487597837, "side" : "ONE" } ], "actionsTaken" : [ ] diff --git a/dynawo-integration-tests/src/test/resources/ieee14/dynamic-security-analysis/divergence/results.json b/dynawo-integration-tests/src/test/resources/ieee14/dynamic-security-analysis/divergence/results.json index 973d7cc56..2c3b56212 100644 --- a/dynawo-integration-tests/src/test/resources/ieee14/dynamic-security-analysis/divergence/results.json +++ b/dynawo-integration-tests/src/test/resources/ieee14/dynamic-security-analysis/divergence/results.json @@ -1,16 +1,16 @@ { "version" : "1.7", "preContingencyResult" : { - "status" : "CONVERGED", + "status" : "FAILED", "limitViolationsResult" : { "limitViolations" : [ { "subjectId" : "_BUS____1-BUS____2-1_AC", "subjectName" : "BUS 1-BUS 2-1", "limitType" : "CURRENT", - "limitName" : "permanent", + "limitName" : "PATL", "limit" : 836.74, "limitReduction" : 1.0, - "value" : 1248.0773003764798, + "value" : 1248.100487597837, "side" : "ONE" } ], "actionsTaken" : [ ] diff --git a/dynawo-integration-tests/src/test/resources/ieee14/dynamic-security-analysis/failed-criteria/results.json b/dynawo-integration-tests/src/test/resources/ieee14/dynamic-security-analysis/failed-criteria/results.json index c591e4cca..309a291b2 100644 --- a/dynawo-integration-tests/src/test/resources/ieee14/dynamic-security-analysis/failed-criteria/results.json +++ b/dynawo-integration-tests/src/test/resources/ieee14/dynamic-security-analysis/failed-criteria/results.json @@ -1,16 +1,16 @@ { "version" : "1.7", "preContingencyResult" : { - "status" : "CONVERGED", + "status" : "FAILED", "limitViolationsResult" : { "limitViolations" : [ { "subjectId" : "_BUS____1-BUS____2-1_AC", "subjectName" : "BUS 1-BUS 2-1", "limitType" : "CURRENT", - "limitName" : "permanent", + "limitName" : "PATL", "limit" : 836.74, "limitReduction" : 1.0, - "value" : 1248.0773003764798, + "value" : 1248.100487597837, "side" : "ONE" } ], "actionsTaken" : [ ] diff --git a/dynawo-security-analysis/src/main/java/com/powsybl/dynawo/security/DynawoSecurityAnalysisHandler.java b/dynawo-security-analysis/src/main/java/com/powsybl/dynawo/security/DynawoSecurityAnalysisHandler.java index 7675f2577..af8568ef0 100644 --- a/dynawo-security-analysis/src/main/java/com/powsybl/dynawo/security/DynawoSecurityAnalysisHandler.java +++ b/dynawo-security-analysis/src/main/java/com/powsybl/dynawo/security/DynawoSecurityAnalysisHandler.java @@ -24,7 +24,6 @@ import com.powsybl.iidm.serde.NetworkSerDe; import com.powsybl.security.LimitViolationFilter; import com.powsybl.security.SecurityAnalysisReport; -import com.powsybl.security.SecurityAnalysisResult; import com.powsybl.security.interceptors.SecurityAnalysisInterceptor; import javax.xml.stream.XMLStreamException; @@ -32,9 +31,9 @@ import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Collections; import java.util.List; +import static com.powsybl.dynaflow.results.ContingencyResultsUtils.createSecurityAnalysisResult; import static com.powsybl.dynawo.DynawoFilesUtils.deleteExistingFile; import static com.powsybl.dynawo.commons.DynawoConstants.*; import static com.powsybl.dynawo.commons.DynawoUtil.getCommandExecutions; @@ -79,13 +78,7 @@ public SecurityAnalysisReport after(Path workingDir, ExecutionReport report) thr NetworkResultsUpdater.update(context.getNetwork(), NetworkSerDe.read(outputNetworkFile), context.getDynawoSimulationParameters().isMergeLoads()); } ContingencyResultsUtils.reportContingenciesTimelines(context.getContingencies(), workingDir.resolve(TIMELINE_FOLDER), reportNode); - - return new SecurityAnalysisReport( - new SecurityAnalysisResult( - ContingencyResultsUtils.getPreContingencyResult(network, violationFilter), - ContingencyResultsUtils.getPostContingencyResults(network, violationFilter, workingDir, context.getContingencies()), - Collections.emptyList()) - ); + return new SecurityAnalysisReport(createSecurityAnalysisResult(network, violationFilter, workingDir, context.getContingencies())); } private void writeInputFiles(Path workingDir) { diff --git a/dynawo-security-analysis/src/main/java/com/powsybl/dynawo/security/xml/MultipleJobsXml.java b/dynawo-security-analysis/src/main/java/com/powsybl/dynawo/security/xml/MultipleJobsXml.java index e98a507c5..4494ce0d0 100644 --- a/dynawo-security-analysis/src/main/java/com/powsybl/dynawo/security/xml/MultipleJobsXml.java +++ b/dynawo-security-analysis/src/main/java/com/powsybl/dynawo/security/xml/MultipleJobsXml.java @@ -16,6 +16,7 @@ import java.nio.file.Path; import java.util.Objects; +import static com.powsybl.dynaflow.SecurityAnalysisConstants.BASE_SCENARIO_NAME; import static com.powsybl.dynawo.DynawoSimulationConstants.JOBS_FILENAME; import static com.powsybl.dynawo.DynawoSimulationConstants.MULTIPLE_JOBS_FILENAME; @@ -52,6 +53,6 @@ private static void writeScenario(XMLStreamWriter writer, String id) throws XMLS private static void writeBaseScenario(XMLStreamWriter writer) throws XMLStreamException { writer.writeEmptyElement("scenario"); - writer.writeAttribute("id", "Base"); + writer.writeAttribute("id", BASE_SCENARIO_NAME); } }