diff --git a/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/AbstractSecurityAnalysisRunParameters.java b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/AbstractSecurityAnalysisRunParameters.java index 8ff88690543..4e87631dd4f 100644 --- a/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/AbstractSecurityAnalysisRunParameters.java +++ b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/AbstractSecurityAnalysisRunParameters.java @@ -13,6 +13,7 @@ import com.powsybl.computation.local.LocalComputationManager; import com.powsybl.security.interceptors.SecurityAnalysisInterceptor; import com.powsybl.security.monitor.StateMonitor; +import com.powsybl.security.results.SecurityAnalysisResultHandler; import com.powsybl.security.strategy.OperatorStrategy; import java.util.ArrayList; @@ -34,6 +35,7 @@ public abstract class AbstractSecurityAnalysisRunParameters operatorStrategies = new ArrayList<>(); private List actions = new ArrayList<>(); private List monitors = new ArrayList<>(); + private List handlers = new ArrayList<>(); private ReportNode reportNode = ReportNode.NO_OP; /** @@ -131,6 +133,15 @@ public T setActions(List actions) { return self(); } + /** + * Sets the list of handlers referenced in {@link SecurityAnalysisResultHandler} + */ + public T setResultHandlers(List handlers) { + Objects.requireNonNull(handlers, "Handler list should not be null"); + this.handlers = handlers; + return self(); + } + /** * Sets the reportNode used for functional logs, see {@link ReportNode} */ @@ -164,5 +175,11 @@ public T addAction(Action action) { return self(); } + public T addResultHandler(SecurityAnalysisResultHandler handler) { + Objects.requireNonNull(handlers, "Handler should not be null"); + handlers.add(handler); + return self(); + } + protected abstract T self(); } diff --git a/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/execution/AbstractSecurityAnalysisExecutionInput.java b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/execution/AbstractSecurityAnalysisExecutionInput.java index 65d57dd25b7..f2e1c00480f 100644 --- a/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/execution/AbstractSecurityAnalysisExecutionInput.java +++ b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/execution/AbstractSecurityAnalysisExecutionInput.java @@ -13,6 +13,7 @@ import com.powsybl.security.LimitViolationType; import com.powsybl.security.limitreduction.LimitReduction; import com.powsybl.security.monitor.StateMonitor; +import com.powsybl.security.results.SecurityAnalysisResultHandler; import com.powsybl.security.strategy.OperatorStrategy; import java.util.*; @@ -31,6 +32,7 @@ public abstract class AbstractSecurityAnalysisExecutionInput actions = new ArrayList<>(); private final List monitors = new ArrayList<>(); private final List limitReductions = new ArrayList<>(); + private final List resultHandlers = new ArrayList<>(); public Optional getContingenciesSource() { return Optional.ofNullable(contingenciesSource); @@ -64,6 +66,10 @@ public List getLimitReductions() { return Collections.unmodifiableList(limitReductions); } + public List getResultHandlers() { + return Collections.unmodifiableList(resultHandlers); + } + public boolean isWithLogs() { return withLogs; } @@ -103,6 +109,11 @@ public T addActions(List actions) { return self(); } + public T addHandlers(List handlers) { + this.resultHandlers.addAll(Objects.requireNonNull(handlers)); + return self(); + } + public T setNetworkVariant(Network network, String variantId) { networkVariant = new NetworkVariant(network, variantId); return self(); @@ -136,6 +147,13 @@ public T setLimitReductions(List limitReductions) { return self(); } + public T setResultHandlers(List handlers) { + Objects.requireNonNull(handlers); + this.resultHandlers.clear(); + this.resultHandlers.addAll(handlers); + return self(); + } + public T setWithLogs(boolean withLogs) { this.withLogs = withLogs; return self(); diff --git a/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/results/InMemoryResultHandler.java b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/results/InMemoryResultHandler.java new file mode 100644 index 00000000000..6cffc54dacd --- /dev/null +++ b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/results/InMemoryResultHandler.java @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2025, Coreso SA (https://www.coreso.eu/) and TSCNET Services GmbH (https://www.tscnet.eu/) + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.security.results; + +import com.powsybl.contingency.Contingency; +import com.powsybl.security.strategy.OperatorStrategy; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; + +/** + * @author Bertrand Rix {@literal } + */ +public class InMemoryResultHandler implements SecurityAnalysisResultHandler { + + public static class StateResult { + + private final List branchResultList; + private final List threeWindingsTransformerResultList; + private final List busResultList; + + StateResult() { + branchResultList = new ArrayList<>(); + threeWindingsTransformerResultList = new ArrayList<>(); + busResultList = new ArrayList<>(); + } + + List getBranchResultList() { + return branchResultList; + } + + List getThreeWindingsTransformerResultList() { + return threeWindingsTransformerResultList; + } + + List getBusResultList() { + return busResultList; + } + + void addBranchResult(BranchResult branchResult) { + branchResultList.add(branchResult); + } + + void addThreeWindingsTransformerResult(ThreeWindingsTransformerResult threeWindingsTransformerResult) { + threeWindingsTransformerResultList.add(threeWindingsTransformerResult); + } + + void addBusResult(BusResult busResult) { + busResultList.add(busResult); + } + } + + private final StateResult baseCaseResult; + private final Map postContingencyResults; + private final Map operatorStrategyResults; + + public InMemoryResultHandler() { + baseCaseResult = new StateResult(); + postContingencyResults = new HashMap<>(); + operatorStrategyResults = new HashMap<>(); + } + + @Override + public void writeBranchResult(Contingency contingency, OperatorStrategy operatorStrategy, BranchResult branchResult) { + registerResult(contingency, operatorStrategy, branchResult, StateResult::addBranchResult); + } + + @Override + public void writeThreeWindingsTransformerResult(Contingency contingency, OperatorStrategy operatorStrategy, ThreeWindingsTransformerResult threeWindingsTransformerResult) { + registerResult(contingency, operatorStrategy, threeWindingsTransformerResult, StateResult::addThreeWindingsTransformerResult); + } + + @Override + public void writeBusResult(Contingency contingency, OperatorStrategy operatorStrategy, BusResult busResult) { + registerResult(contingency, operatorStrategy, busResult, StateResult::addBusResult); + } + + StateResult getBaseCaseResult() { + return baseCaseResult; + } + + Map getPostContingencyResults() { + return postContingencyResults; + } + + Map getOperatorStrategyResults() { + return operatorStrategyResults; + } + + void registerResult(Contingency contingency, OperatorStrategy operatorStrategy, T result, BiConsumer resultAdder) { + if (contingency == null) { + resultAdder.accept(baseCaseResult, result); + } else if (operatorStrategy == null) { + resultAdder.accept(postContingencyResults.computeIfAbsent(contingency.getId(), k -> new StateResult()), result); + } else { + resultAdder.accept(operatorStrategyResults.computeIfAbsent(operatorStrategy.getId(), k -> new StateResult()), result); + } + } +} diff --git a/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/results/SecurityAnalysisResultHandler.java b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/results/SecurityAnalysisResultHandler.java new file mode 100644 index 00000000000..374c6347e3c --- /dev/null +++ b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/results/SecurityAnalysisResultHandler.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2025, Coreso SA (https://www.coreso.eu/) and TSCNET Services GmbH (https://www.tscnet.eu/) + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.security.results; + +import com.powsybl.contingency.Contingency; +import com.powsybl.security.strategy.OperatorStrategy; + +/** + * @author Bertrand Rix {@literal } + */ +public interface SecurityAnalysisResultHandler { + + void writeBranchResult(Contingency contingency, OperatorStrategy operatorStrategy, BranchResult branchResult); + + void writeThreeWindingsTransformerResult(Contingency contingency, OperatorStrategy operatorStrategy, ThreeWindingsTransformerResult branchResult); + + void writeBusResult(Contingency contingency, OperatorStrategy operatorStrategy, BusResult busResult); + +}