All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.powsybl.python.security.SecurityAnalysisCFunctions Maven / Gradle / Ivy

/**
 * Copyright (c) 2022, 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/.
 * SPDX-License-Identifier: MPL-2.0
 */
package com.powsybl.python.security;

import com.powsybl.action.*;
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.report.ReportNode;
import com.powsybl.contingency.ContingencyContext;
import com.powsybl.iidm.network.Network;
import com.powsybl.python.commons.*;
import com.powsybl.python.commons.PyPowsyblApiHeader.SecurityAnalysisParametersPointer;
import com.powsybl.python.contingency.ContingencyContainer;
import com.powsybl.python.loadflow.LoadFlowCFunctions;
import com.powsybl.python.loadflow.LoadFlowCUtils;
import com.powsybl.python.network.Dataframes;
import com.powsybl.security.*;
import com.powsybl.security.condition.*;
import com.powsybl.security.monitor.StateMonitor;
import com.powsybl.security.results.OperatorStrategyResult;
import com.powsybl.security.results.PostContingencyResult;
import com.powsybl.security.results.PreContingencyResult;
import com.powsybl.security.strategy.OperatorStrategy;
import org.graalvm.nativeimage.IsolateThread;
import org.graalvm.nativeimage.ObjectHandle;
import org.graalvm.nativeimage.ObjectHandles;
import org.graalvm.nativeimage.UnmanagedMemory;
import org.graalvm.nativeimage.c.CContext;
import org.graalvm.nativeimage.c.function.CEntryPoint;
import org.graalvm.nativeimage.c.struct.SizeOf;
import org.graalvm.nativeimage.c.type.CCharPointer;
import org.graalvm.nativeimage.c.type.CCharPointerPointer;
import org.graalvm.nativeimage.c.type.CIntPointer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static com.powsybl.python.commons.CTypeUtil.toStringList;
import static com.powsybl.python.commons.PyPowsyblApiHeader.allocArrayPointer;
import static com.powsybl.python.commons.PyPowsyblApiHeader.freeArrayPointer;
import static com.powsybl.python.commons.Util.*;

/**
 * C functions related to security analysis.
 *
 * @author Sylvain Leclerc {@literal }
 */
@CContext(Directives.class)
public final class SecurityAnalysisCFunctions {

    private SecurityAnalysisCFunctions() {
    }

    private static Logger logger() {
        return LoggerFactory.getLogger(SecurityAnalysisCFunctions.class);
    }

    @CEntryPoint(name = "getSecurityAnalysisProviderNames")
    public static PyPowsyblApiHeader.ArrayPointer getSecurityAnalysisProviderNames(IsolateThread thread, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        return doCatch(exceptionHandlerPtr, () -> createCharPtrArray(SecurityAnalysisProvider.findAll()
                .stream().map(SecurityAnalysisProvider::getName).toList()));
    }

    @CEntryPoint(name = "setDefaultSecurityAnalysisProvider")
    public static void setDefaultSecurityAnalysisProvider(IsolateThread thread, CCharPointer provider, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        doCatch(exceptionHandlerPtr, () ->
            PyPowsyblConfiguration.setDefaultSecurityAnalysisProvider(CTypeUtil.toString(provider)));
    }

    @CEntryPoint(name = "getDefaultSecurityAnalysisProvider")
    public static CCharPointer getDefaultSecurityAnalysisProvider(IsolateThread thread, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        return doCatch(exceptionHandlerPtr, () -> CTypeUtil.toCharPtr(PyPowsyblConfiguration.getDefaultSecurityAnalysisProvider()));
    }

    @CEntryPoint(name = "addMonitoredElements")
    public static void addMonitoredElements(IsolateThread thread, ObjectHandle securityAnalysisContextHandle, PyPowsyblApiHeader.RawContingencyContextType contingencyContextType,
                                            CCharPointerPointer branchIds, int branchIdsCount,
                                            CCharPointerPointer voltageLevelIds, int voltageLevelIdCount,
                                            CCharPointerPointer threeWindingsTransformerIds, int threeWindingsTransformerIdsCount,
                                            CCharPointerPointer contingencyIds, int contingencyIdsCount,
                                            PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisContext analysisContext = ObjectHandles.getGlobal().get(securityAnalysisContextHandle);
            List contingencies = toStringList(contingencyIds, contingencyIdsCount);
            contingencies.forEach(contingency -> analysisContext.addMonitor(new StateMonitor(new ContingencyContext(contingency.isEmpty() ? null : contingency, convert(contingencyContextType)),
                    Set.copyOf(toStringList(branchIds, branchIdsCount)), Set.copyOf(toStringList(voltageLevelIds, voltageLevelIdCount)),
                    Set.copyOf(toStringList(threeWindingsTransformerIds, threeWindingsTransformerIdsCount)))));
        });
    }

    @CEntryPoint(name = "getBranchResults")
    public static PyPowsyblApiHeader.ArrayPointer getBranchResults(IsolateThread thread, ObjectHandle securityAnalysisResult, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        return doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisResult result = ObjectHandles.getGlobal().get(securityAnalysisResult);
            return Dataframes.createCDataframe(Dataframes.branchResultsMapper(), result);
        });
    }

    @CEntryPoint(name = "getBusResults")
    public static PyPowsyblApiHeader.ArrayPointer getBusResults(IsolateThread thread, ObjectHandle securityAnalysisResult, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        return doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisResult result = ObjectHandles.getGlobal().get(securityAnalysisResult);
            return Dataframes.createCDataframe(Dataframes.busResultsMapper(), result);
        });
    }

    @CEntryPoint(name = "getThreeWindingsTransformerResults")
    public static PyPowsyblApiHeader.ArrayPointer getThreeWindingsTransformerResults(IsolateThread thread, ObjectHandle securityAnalysisResult, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        return doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisResult result = ObjectHandles.getGlobal().get(securityAnalysisResult);
            return Dataframes.createCDataframe(Dataframes.threeWindingsTransformerResultsMapper(), result);
        });
    }

    @CEntryPoint(name = "createSecurityAnalysis")
    public static ObjectHandle createSecurityAnalysis(IsolateThread thread, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        return doCatch(exceptionHandlerPtr, () -> ObjectHandles.getGlobal().create(new SecurityAnalysisContext()));
    }

    @CEntryPoint(name = "addContingency")
    public static void addContingency(IsolateThread thread, ObjectHandle contingencyContainerHandle, CCharPointer contingencyIdPtr,
                                      CCharPointerPointer elementIdPtrPtr, int elementCount, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        doCatch(exceptionHandlerPtr, () -> {
            ContingencyContainer contingencyContainer = ObjectHandles.getGlobal().get(contingencyContainerHandle);
            String contingencyId = CTypeUtil.toString(contingencyIdPtr);
            List elementIds = toStringList(elementIdPtrPtr, elementCount);
            contingencyContainer.addContingency(contingencyId, elementIds);
        });
    }

    private static void setPostContingencyResultInSecurityAnalysisResultPointer(PyPowsyblApiHeader.PostContingencyResultPointer contingencyPtr, PostContingencyResult postContingencyResult) {
        contingencyPtr.setContingencyId(CTypeUtil.toCharPtr(postContingencyResult.getContingency().getId()));
        contingencyPtr.setStatus(postContingencyResult.getStatus().ordinal());
        List limitViolations = postContingencyResult.getLimitViolationsResult().getLimitViolations();
        PyPowsyblApiHeader.LimitViolationPointer limitViolationPtr = UnmanagedMemory.calloc(limitViolations.size() * SizeOf.get(PyPowsyblApiHeader.LimitViolationPointer.class));
        createLimitViolationPtr(limitViolationPtr, limitViolations);
        contingencyPtr.limitViolations().setLength(limitViolations.size());
        contingencyPtr.limitViolations().setPtr(limitViolationPtr);
    }

    private static void setOperatorStrategyResultInSecurityAnalysisResultPointer(PyPowsyblApiHeader.OperatorStrategyResultPointer operatorStrategyPtr, OperatorStrategyResult result) {
        operatorStrategyPtr.setOperatorStrategyId(CTypeUtil.toCharPtr(result.getOperatorStrategy().getId()));
        operatorStrategyPtr.setStatus(result.getStatus().ordinal());
        List limitViolations = result.getLimitViolationsResult().getLimitViolations();
        PyPowsyblApiHeader.LimitViolationPointer limitViolationPtr = UnmanagedMemory.calloc(limitViolations.size() * SizeOf.get(PyPowsyblApiHeader.LimitViolationPointer.class));
        createLimitViolationPtr(limitViolationPtr, limitViolations);
        operatorStrategyPtr.limitViolations().setLength(limitViolations.size());
        operatorStrategyPtr.limitViolations().setPtr(limitViolationPtr);
    }

    private static void setPreContingencyResultInSecurityAnalysisResultPointer(PyPowsyblApiHeader.PreContingencyResultPointer contingencyPtr, PreContingencyResult preContingencyResult) {
        contingencyPtr.setStatus(preContingencyResult.getStatus().ordinal());
        List limitViolations = preContingencyResult.getLimitViolationsResult().getLimitViolations();
        PyPowsyblApiHeader.LimitViolationPointer limitViolationPtr = UnmanagedMemory.calloc(limitViolations.size() * SizeOf.get(PyPowsyblApiHeader.LimitViolationPointer.class));
        createLimitViolationPtr(limitViolationPtr, limitViolations);
        contingencyPtr.limitViolations().setLength(limitViolations.size());
        contingencyPtr.limitViolations().setPtr(limitViolationPtr);
    }

    private static void createLimitViolationPtr(PyPowsyblApiHeader.LimitViolationPointer limitViolationPtr, List limitViolations) {
        for (int i = 0; i < limitViolations.size(); i++) {
            LimitViolation limitViolation = limitViolations.get(i);
            PyPowsyblApiHeader.LimitViolationPointer limitViolationPtrPlus = limitViolationPtr.addressOf(i);
            limitViolationPtrPlus.setSubjectId(CTypeUtil.toCharPtr(limitViolation.getSubjectId()));
            limitViolationPtrPlus.setSubjectName(CTypeUtil.toCharPtr(Objects.toString(limitViolation.getSubjectName(), "")));
            limitViolationPtrPlus.setLimitType(limitViolation.getLimitType().ordinal());
            limitViolationPtrPlus.setLimit(limitViolation.getLimit());
            limitViolationPtrPlus.setLimitName(CTypeUtil.toCharPtr(Objects.toString(limitViolation.getLimitName(), "")));
            limitViolationPtrPlus.setAcceptableDuration(limitViolation.getAcceptableDuration());
            limitViolationPtrPlus.setLimitReduction(limitViolation.getLimitReduction());
            limitViolationPtrPlus.setValue(limitViolation.getValue());
            limitViolationPtrPlus.setSide(limitViolation.getSide() != null ? limitViolation.getSide().ordinal() : -1);
        }
    }

    private static PyPowsyblApiHeader.PreContingencyResultPointer createPreContingencyResultArrayPointer(SecurityAnalysisResult result) {
        PyPowsyblApiHeader.PreContingencyResultPointer contingencyPtr = UnmanagedMemory.calloc(SizeOf.get(PyPowsyblApiHeader.PreContingencyResultPointer.class));
        setPreContingencyResultInSecurityAnalysisResultPointer(contingencyPtr, result.getPreContingencyResult());
        return contingencyPtr;
    }

    private static PyPowsyblApiHeader.ArrayPointer createPostContingencyResultArrayPointer(SecurityAnalysisResult result) {
        int resultCount = result.getPostContingencyResults().size(); // + 1 for pre-contingency result
        PyPowsyblApiHeader.PostContingencyResultPointer contingencyPtr = UnmanagedMemory.calloc(resultCount * SizeOf.get(PyPowsyblApiHeader.PostContingencyResultPointer.class));
        for (int i = 0; i < result.getPostContingencyResults().size(); i++) {
            PostContingencyResult postContingencyResult = result.getPostContingencyResults().get(i);
            PyPowsyblApiHeader.PostContingencyResultPointer contingencyPtrPlus = contingencyPtr.addressOf(i);
            setPostContingencyResultInSecurityAnalysisResultPointer(contingencyPtrPlus, postContingencyResult);
        }
        return allocArrayPointer(contingencyPtr, resultCount);
    }

    private static PyPowsyblApiHeader.ArrayPointer createOperatorStrategyResultsArrayPointer(SecurityAnalysisResult result) {
        int resultCount = result.getOperatorStrategyResults().size();
        PyPowsyblApiHeader.OperatorStrategyResultPointer strategyPtr = UnmanagedMemory.calloc(resultCount * SizeOf.get(PyPowsyblApiHeader.OperatorStrategyResultPointer.class));
        for (int i = 0; i < result.getOperatorStrategyResults().size(); i++) {
            OperatorStrategyResult resultOp = result.getOperatorStrategyResults().get(i);
            PyPowsyblApiHeader.OperatorStrategyResultPointer operatorStrategyPlus = strategyPtr.addressOf(i);
            setOperatorStrategyResultInSecurityAnalysisResultPointer(operatorStrategyPlus, resultOp);
        }
        return allocArrayPointer(strategyPtr, resultCount);
    }

    private static SecurityAnalysisProvider getProvider(String name) {
        String actualName = name.isEmpty() ? PyPowsyblConfiguration.getDefaultSecurityAnalysisProvider() : name;
        return SecurityAnalysisProvider.findAll().stream()
                .filter(provider -> provider.getName().equals(actualName))
                .findFirst()
                .orElseThrow(() -> new PowsyblException("No security analysis provider for name '" + actualName + "'"));
    }

    @CEntryPoint(name = "runSecurityAnalysis")
    public static ObjectHandle runSecurityAnalysis(IsolateThread thread, ObjectHandle securityAnalysisContextHandle,
                                                   ObjectHandle networkHandle, SecurityAnalysisParametersPointer securityAnalysisParametersPointer,
                                                   CCharPointer providerName, boolean dc, ObjectHandle reportNodeHandle,
                                                   PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        return doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisContext analysisContext = ObjectHandles.getGlobal().get(securityAnalysisContextHandle);
            Network network = ObjectHandles.getGlobal().get(networkHandle);
            SecurityAnalysisProvider provider = getProvider(CTypeUtil.toString(providerName));
            logger().info("Security analysis provider used for security analysis is : {}", provider.getName());
            SecurityAnalysisParameters securityAnalysisParameters = SecurityAnalysisCUtils.createSecurityAnalysisParameters(dc, securityAnalysisParametersPointer, provider);
            ReportNode reportNode = ObjectHandles.getGlobal().get(reportNodeHandle);
            SecurityAnalysisResult result = analysisContext.run(network, securityAnalysisParameters, provider.getName(), reportNode);
            return ObjectHandles.getGlobal().create(result);
        });
    }

    @CEntryPoint(name = "getPostContingencyResults")
    public static PyPowsyblApiHeader.ArrayPointer getPostContingencyResults(IsolateThread thread, ObjectHandle securityAnalysisResultHandle, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        return doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisResult result = ObjectHandles.getGlobal().get(securityAnalysisResultHandle);
            return createPostContingencyResultArrayPointer(result);
        });
    }

    @CEntryPoint(name = "getOperatorStrategyResults")
    public static PyPowsyblApiHeader.ArrayPointer getOperatorStrategyResults(IsolateThread thread, ObjectHandle securityAnalysisResultHandle, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        return doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisResult result = ObjectHandles.getGlobal().get(securityAnalysisResultHandle);
            return createOperatorStrategyResultsArrayPointer(result);
        });
    }

    @CEntryPoint(name = "getPreContingencyResult")
    public static PyPowsyblApiHeader.PreContingencyResultPointer getPreContingencyResult(IsolateThread thread, ObjectHandle securityAnalysisResultHandle, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        return doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisResult result = ObjectHandles.getGlobal().get(securityAnalysisResultHandle);
            return createPreContingencyResultArrayPointer(result);
        });
    }

    @CEntryPoint(name = "getLimitViolations")
    public static PyPowsyblApiHeader.ArrayPointer getLimitViolations(IsolateThread thread, ObjectHandle securityAnalysisResultHandle, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        return doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisResult result = ObjectHandles.getGlobal().get(securityAnalysisResultHandle);
            return Dataframes.createCDataframe(Dataframes.limitViolationsMapper(), result);
        });
    }

    @CEntryPoint(name = "freeContingencyResultArrayPointer")
    public static void freeContingencyResultArrayPointer(IsolateThread thread, PyPowsyblApiHeader.ArrayPointer contingencyResultArrayPtr,
                                                         PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        doCatch(exceptionHandlerPtr, () -> {
            for (int i = 0; i < contingencyResultArrayPtr.getLength(); i++) {
                PyPowsyblApiHeader.PostContingencyResultPointer contingencyResultPtrPlus = contingencyResultArrayPtr.getPtr().addressOf(i);
                UnmanagedMemory.free(contingencyResultPtrPlus.getContingencyId());
                for (int l = 0; l < contingencyResultPtrPlus.limitViolations().getLength(); l++) {
                    PyPowsyblApiHeader.LimitViolationPointer violation = contingencyResultPtrPlus.limitViolations().getPtr().addressOf(l);
                    UnmanagedMemory.free(violation.getSubjectId());
                    UnmanagedMemory.free(violation.getSubjectName());
                    UnmanagedMemory.free(violation.getLimitName());
                }
                UnmanagedMemory.free(contingencyResultPtrPlus.limitViolations().getPtr());
            }
            freeArrayPointer(contingencyResultArrayPtr);
        });
    }

    @CEntryPoint(name = "freeOperatorStrategyResultArrayPointer")
    public static void freeOperatorStrategyResultArrayPointer(IsolateThread thread, PyPowsyblApiHeader.ArrayPointer operatorStrategyResultArrayPtr,
                                                         PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        doCatch(exceptionHandlerPtr, () -> {
            for (int i = 0; i < operatorStrategyResultArrayPtr.getLength(); i++) {
                PyPowsyblApiHeader.OperatorStrategyResultPointer strategyResultPtrPlus = operatorStrategyResultArrayPtr.getPtr().addressOf(i);
                UnmanagedMemory.free(strategyResultPtrPlus.getOperatorStrategyId());
                for (int l = 0; l < strategyResultPtrPlus.limitViolations().getLength(); l++) {
                    PyPowsyblApiHeader.LimitViolationPointer violation = strategyResultPtrPlus.limitViolations().getPtr().addressOf(l);
                    UnmanagedMemory.free(violation.getSubjectId());
                    UnmanagedMemory.free(violation.getSubjectName());
                    UnmanagedMemory.free(violation.getLimitName());
                }
                UnmanagedMemory.free(strategyResultPtrPlus.limitViolations().getPtr());
            }
            freeArrayPointer(operatorStrategyResultArrayPtr);
        });
    }

    @CEntryPoint(name = "freeSecurityAnalysisParameters")
    public static void freeSecurityAnalysisParameters(IsolateThread thread, SecurityAnalysisParametersPointer parameters,
                                              PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        doCatch(exceptionHandlerPtr, () -> {
            LoadFlowCUtils.freeLoadFlowParametersContent(parameters.getLoadFlowParameters());
            UnmanagedMemory.free(parameters);
        });
    }

    @CEntryPoint(name = "createSecurityAnalysisParameters")
    public static SecurityAnalysisParametersPointer createSecurityAnalysisParameters(IsolateThread thread, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        return doCatch(exceptionHandlerPtr, () -> convertToSecurityAnalysisParametersPointer(SecurityAnalysisCUtils.createSecurityAnalysisParameters()));
    }

    private static SecurityAnalysisParametersPointer convertToSecurityAnalysisParametersPointer(SecurityAnalysisParameters parameters) {
        SecurityAnalysisParametersPointer paramsPtr = UnmanagedMemory.calloc(SizeOf.get(SecurityAnalysisParametersPointer.class));
        LoadFlowCFunctions.copyToCLoadFlowParameters(parameters.getLoadFlowParameters(), paramsPtr.getLoadFlowParameters());
        paramsPtr.setFlowProportionalThreshold(parameters.getIncreasedViolationsParameters().getFlowProportionalThreshold());
        paramsPtr.setHighVoltageAbsoluteThreshold(parameters.getIncreasedViolationsParameters().getHighVoltageAbsoluteThreshold());
        paramsPtr.setHighVoltageProportionalThreshold(parameters.getIncreasedViolationsParameters().getHighVoltageProportionalThreshold());
        paramsPtr.setLowVoltageAbsoluteThreshold(parameters.getIncreasedViolationsParameters().getLowVoltageAbsoluteThreshold());
        paramsPtr.setLowVoltageProportionalThreshold(parameters.getIncreasedViolationsParameters().getLowVoltageProportionalThreshold());
        paramsPtr.setProviderParametersValuesCount(0);
        paramsPtr.setProviderParametersKeysCount(0);
        return paramsPtr;
    }

    @CEntryPoint(name = "getSecurityAnalysisProviderParametersNames")
    public static PyPowsyblApiHeader.ArrayPointer getProviderParametersNames(IsolateThread thread, CCharPointer provider, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        return doCatch(exceptionHandlerPtr, () -> {
            String providerStr = CTypeUtil.toString(provider);
            return Util.createCharPtrArray(SecurityAnalysisCUtils.getSecurityAnalysisProvider(providerStr).getSpecificParametersNames());
        });
    }

    @CEntryPoint(name = "addLoadActivePowerAction")
    public static void addLoadActivePowerAction(IsolateThread thread, ObjectHandle securityAnalysisContextHandle,
                                                CCharPointer actionId, CCharPointer loadId, boolean relativeValue,
                                                double activePowerValue,
                                                PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisContext analysisContext = ObjectHandles.getGlobal().get(securityAnalysisContextHandle);
            String actionIdStr = CTypeUtil.toString(actionId);
            String loadIdStr = CTypeUtil.toString(loadId);
            LoadAction action = new LoadActionBuilder().withId(actionIdStr)
                    .withLoadId(loadIdStr)
                    .withRelativeValue(relativeValue)
                    .withActivePowerValue(activePowerValue)
                    .build();
            analysisContext.addAction(action);
        });
    }

    @CEntryPoint(name = "addLoadReactivePowerAction")
    public static void addLoadReactivePowerAction(IsolateThread thread, ObjectHandle securityAnalysisContextHandle,
                                                CCharPointer actionId, CCharPointer loadId, boolean relativeValue,
                                                double reactivePowerValue,
                                                PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisContext analysisContext = ObjectHandles.getGlobal().get(securityAnalysisContextHandle);
            String actionIdStr = CTypeUtil.toString(actionId);
            String loadIdStr = CTypeUtil.toString(loadId);
            LoadAction action = new LoadActionBuilder().withId(actionIdStr)
                    .withLoadId(loadIdStr)
                    .withRelativeValue(relativeValue)
                    .withReactivePowerValue(reactivePowerValue)
                    .build();
            analysisContext.addAction(action);
        });
    }

    @CEntryPoint(name = "addGeneratorActivePowerAction")
    public static void addGeneratorActivePowerAction(IsolateThread thread, ObjectHandle securityAnalysisContextHandle,
                                          CCharPointer actionId, CCharPointer generatorId, boolean relativeValue, double activePower,
                                          PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisContext analysisContext = ObjectHandles.getGlobal().get(securityAnalysisContextHandle);
            String actionIdStr = CTypeUtil.toString(actionId);
            String generatorIdStr = CTypeUtil.toString(generatorId);
            GeneratorActionBuilder builder = new GeneratorActionBuilder().withId(actionIdStr)
                    .withGeneratorId(generatorIdStr)
                    .withActivePowerRelativeValue(relativeValue)
                    .withActivePowerValue(activePower);
            analysisContext.addAction(builder.build());
        });
    }

    @CEntryPoint(name = "addSwitchAction")
    public static void addSwitchAction(IsolateThread thread, ObjectHandle securityAnalysisContextHandle,
                                         CCharPointer actionId, CCharPointer switchId, boolean open,
                                         PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisContext analysisContext = ObjectHandles.getGlobal().get(securityAnalysisContextHandle);
            String actionIdStr = CTypeUtil.toString(actionId);
            String switchIdStr = CTypeUtil.toString(switchId);
            SwitchAction action = new SwitchAction(actionIdStr, switchIdStr, open);
            analysisContext.addAction(action);
        });
    }

    @CEntryPoint(name = "addPhaseTapChangerPositionAction")
    public static void addPhaseTapChangerPositionAction(IsolateThread thread, ObjectHandle securityAnalysisContextHandle,
                                                        CCharPointer actionId, CCharPointer transformerId, boolean isRelative,
                                                        int tapPosition, PyPowsyblApiHeader.ThreeSideType side, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisContext analysisContext = ObjectHandles.getGlobal().get(securityAnalysisContextHandle);
            String actionIdStr = CTypeUtil.toString(actionId);
            String transformerIdStr = CTypeUtil.toString(transformerId);
            PhaseTapChangerTapPositionAction pstAction = new PhaseTapChangerTapPositionAction(actionIdStr, transformerIdStr, isRelative, tapPosition, Util.convert(side));
            analysisContext.addAction(pstAction);
        });
    }

    @CEntryPoint(name = "addRatioTapChangerPositionAction")
    public static void addRatioTapChangerPositionAction(IsolateThread thread, ObjectHandle securityAnalysisContextHandle,
                                                        CCharPointer actionId, CCharPointer transformerId, boolean isRelative,
                                                        int tapPosition, PyPowsyblApiHeader.ThreeSideType side, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisContext analysisContext = ObjectHandles.getGlobal().get(securityAnalysisContextHandle);
            String actionIdStr = CTypeUtil.toString(actionId);
            String transformerIdStr = CTypeUtil.toString(transformerId);
            RatioTapChangerTapPositionAction ratioTapChangerAction = new RatioTapChangerTapPositionAction(actionIdStr, transformerIdStr, isRelative, tapPosition, Util.convert(side));
            analysisContext.addAction(ratioTapChangerAction);
        });
    }

    @CEntryPoint(name = "addShuntCompensatorPositionAction")
    public static void addShuntCompensatorPositionAction(IsolateThread thread, ObjectHandle securityAnalysisContextHandle,
                                                         CCharPointer actionId, CCharPointer shuntCompensatorId, int sectionCount,
                                                         PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisContext analysisContext = ObjectHandles.getGlobal().get(securityAnalysisContextHandle);
            String actionIdStr = CTypeUtil.toString(actionId);
            String shuntCompensatorIdStr = CTypeUtil.toString(shuntCompensatorId);
            ShuntCompensatorPositionActionBuilder builder = new ShuntCompensatorPositionActionBuilder();
            ShuntCompensatorPositionAction action = builder.withId(actionIdStr)
                    .withShuntCompensatorId(shuntCompensatorIdStr)
                    .withSectionCount(sectionCount)
                    .build();
            analysisContext.addAction(action);
        });
    }

    @CEntryPoint(name = "addOperatorStrategy")
    public static void addOperatorStrategy(IsolateThread thread, ObjectHandle securityAnalysisContextHandle,
                                         CCharPointer operationStrategyId, CCharPointer contingencyId,
                                         CCharPointerPointer actions, int actionCount,
                                         PyPowsyblApiHeader.ConditionType conditionType,
                                         CCharPointerPointer subjectIds, int subjectIdsCount,
                                         CIntPointer violationTypes, int violationTypesCount,
                                         PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
        doCatch(exceptionHandlerPtr, () -> {
            SecurityAnalysisContext analysisContext = ObjectHandles.getGlobal().get(securityAnalysisContextHandle);
            String operationStrategyIdStr = CTypeUtil.toString(operationStrategyId);
            String contingencyIdStr = CTypeUtil.toString(contingencyId);
            List actionsStrList = CTypeUtil.toStringList(actions, actionCount);

            Condition condition = buildCondition(conditionType, subjectIds, subjectIdsCount, violationTypes, violationTypesCount);

            OperatorStrategy op = new OperatorStrategy(operationStrategyIdStr,
                    ContingencyContext.specificContingency(contingencyIdStr), condition, actionsStrList);
            analysisContext.addOperatorStrategy(op);
        });
    }

    private static Condition buildCondition(PyPowsyblApiHeader.ConditionType conditionType,
                                            CCharPointerPointer subjectIds, int subjectIdsCount,
                                            CIntPointer violationTypes, int violationTypesCount) {
        List subjectIdsStrList = CTypeUtil.toStringList(subjectIds, subjectIdsCount);
        Set violationTypesC = CTypeUtil.toEnumSet(
                violationTypes, violationTypesCount, PyPowsyblApiHeader.LimitViolationType::fromCValue);
        Set violationTypesFilter = violationTypesC.stream().map(Util::convert).collect(Collectors.toSet());

        return switch (conditionType) {
            case TRUE_CONDITION -> new TrueCondition();
            case ALL_VIOLATION_CONDITION -> new AllViolationCondition(subjectIdsStrList, violationTypesFilter);
            case ANY_VIOLATION_CONDITION -> new AnyViolationCondition(violationTypesFilter);
            case AT_LEAST_ONE_VIOLATION_CONDITION ->
                new AtLeastOneViolationCondition(subjectIdsStrList, violationTypesFilter);
            default -> throw new PowsyblException("Unsupported condition type " + conditionType);
        };
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy