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

com.farao_community.farao.flowbased_computation.impl.FlowbasedComputationImpl Maven / Gradle / Ivy

/*
 * Copyright (c) 2019, 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 com.farao_community.farao.flowbased_computation.impl;

import com.farao_community.farao.commons.RandomizedString;
import com.farao_community.farao.commons.Unit;
import com.powsybl.glsk.commons.ZonalData;
import com.farao_community.farao.data.crac_api.Contingency;
import com.farao_community.farao.data.crac_api.Crac;
import com.farao_community.farao.data.crac_api.Instant;
import com.farao_community.farao.data.crac_api.State;
import com.farao_community.farao.data.crac_api.cnec.FlowCnec;
import com.farao_community.farao.data.crac_api.cnec.Side;
import com.farao_community.farao.data.crac_api.network_action.NetworkAction;
import com.farao_community.farao.data.crac_api.range_action.RangeAction;
import com.farao_community.farao.data.crac_api.usage_rule.UsageMethod;
import com.farao_community.farao.data.flowbased_domain.*;
import com.farao_community.farao.data.rao_result_api.RaoResult;
import com.farao_community.farao.flowbased_computation.FlowbasedComputationParameters;
import com.farao_community.farao.flowbased_computation.FlowbasedComputationProvider;
import com.farao_community.farao.flowbased_computation.FlowbasedComputationResult;
import com.farao_community.farao.flowbased_computation.FlowbasedComputationResultImpl;
import com.farao_community.farao.sensitivity_analysis.AppliedRemedialActions;
import com.farao_community.farao.sensitivity_analysis.SystematicSensitivityInterface;
import com.farao_community.farao.sensitivity_analysis.SystematicSensitivityResult;
import com.google.auto.service.AutoService;
import com.powsybl.iidm.network.Network;
import com.powsybl.sensitivity.SensitivityVariableSet;
import com.powsybl.sensitivity.WeightedSensitivityVariable;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import static com.farao_community.farao.commons.logs.FaraoLoggerProvider.BUSINESS_WARNS;
import static com.farao_community.farao.commons.logs.FaraoLoggerProvider.TECHNICAL_LOGS;

/**
 * Flowbased computation implementation
 *
 * @author Sebastien Murgey {@literal }
 */
@AutoService(FlowbasedComputationProvider.class)
public class FlowbasedComputationImpl implements FlowbasedComputationProvider {

    private static final String INITIAL_STATE_WITH_PRA = "InitialStateWithPra";

    @Override
    public String getName() {
        return "SimpleIterativeFlowBased";
    }

    @Override
    public String getVersion() {
        return "1.0.0";
    }

    @Override
    public CompletableFuture run(Network network, Crac crac, RaoResult raoResult, ZonalData glsk, FlowbasedComputationParameters parameters) {
        Objects.requireNonNull(network);
        Objects.requireNonNull(crac);
        Objects.requireNonNull(glsk);
        Objects.requireNonNull(parameters);

        AppliedRemedialActions appliedRemedialActions = new AppliedRemedialActions();

        if (raoResult == null) {
            TECHNICAL_LOGS.debug("RAO result is null: applying all network actions from CRAC.");
            crac.getStates().forEach(state -> {
                if (state.getInstant().equals(Instant.CURATIVE)) {
                    appliedRemedialActions.addAppliedNetworkActions(state, findAllAvailableRemedialActionsForState(crac, state));
                }
            });
        } else {
            TECHNICAL_LOGS.debug("RAO result is not null: applying remedial actions selected by the RAO.");
            crac.getStates().forEach(state -> {
                if (state.getInstant().equals(Instant.CURATIVE)) {
                    appliedRemedialActions.addAppliedNetworkActions(state, findAppliedNetworkActionsForState(raoResult, state, crac.getNetworkActions()));
                    appliedRemedialActions.addAppliedRangeActions(state, findAppliedRangeActionsForState(raoResult, state));
                }
            });
        }

        SystematicSensitivityInterface systematicSensitivityInterface = SystematicSensitivityInterface.builder()
                .withSensitivityProviderName(parameters.getSensitivityProvider())
                .withDefaultParameters(parameters.getSensitivityAnalysisParameters())
                .withPtdfSensitivities(glsk, crac.getFlowCnecs(), Collections.singleton(Unit.MEGAWATT))
                .withAppliedRemedialActions(appliedRemedialActions)
                .build();

        // Preventive perimeter
        String initialNetworkId = network.getVariantManager().getWorkingVariantId();
        network.getVariantManager().cloneVariant(initialNetworkId, INITIAL_STATE_WITH_PRA);
        network.getVariantManager().setWorkingVariant(INITIAL_STATE_WITH_PRA);
        applyPreventiveRemedialActions(raoResult, crac, network);
        SystematicSensitivityResult result = systematicSensitivityInterface.run(network);
        FlowbasedComputationResult flowBasedComputationResult = new FlowbasedComputationResultImpl(FlowbasedComputationResult.Status.SUCCESS, buildFlowbasedDomain(crac, glsk, result));

        // Restore initial variant at the end of the computation
        network.getVariantManager().setWorkingVariant(initialNetworkId);
        network.getVariantManager().removeVariant(INITIAL_STATE_WITH_PRA);

        return CompletableFuture.completedFuture(flowBasedComputationResult);
    }

    private void applyPreventiveRemedialActions(RaoResult raoResult, Crac crac, Network network) {
        if (raoResult == null) {
            TECHNICAL_LOGS.debug("RAO result is null: applying all network actions from CRAC.");
            crac.getNetworkActions().forEach(na -> {
                UsageMethod usageMethod = na.getUsageMethod(crac.getPreventiveState());
                if (usageMethod.equals(UsageMethod.AVAILABLE) || usageMethod.equals(UsageMethod.FORCED)) {
                    na.apply(network);
                } else if (usageMethod.equals(UsageMethod.TO_BE_EVALUATED)) {
                    BUSINESS_WARNS.warn("Network action {} with usage method TO_BE_EVALUATED will not be applied, as we don't have access to the flow results.", na.getId());
                    /*
                     * This method is only used in FlowbasedComputation.
                     * We do not assess the availability of such remedial actions: they're not supposed to exist.
                     * If it is needed in the future, we will have to loop around a sensitivity computation, followed by a
                     * re-assessment of additional available RAs and applying them, then re-running sensitivity, etc
                     * until the list of applied remedial actions stops changing
                     */
                }
            });
        } else {
            TECHNICAL_LOGS.debug("RAO result is not null: applying remedial actions selected by the RAO.");
            crac.getNetworkActions().forEach(na -> {
                if (raoResult.isActivated(crac.getPreventiveState(), na)) {
                    na.apply(network);
                }
            });
            raoResult.getOptimizedSetPointsOnState(crac.getPreventiveState()).forEach((ra, setpoint) -> ra.apply(network, setpoint));
        }
    }

    private DataDomain buildFlowbasedDomain(Crac crac, ZonalData glsk, SystematicSensitivityResult result) {
        return DataDomain.builder()
                .id(RandomizedString.getRandomizedString())
                .name("FlowBased results")
                .description("")
                .sourceFormat("code")
                .dataPreContingency(buildDataPreContingency(crac, glsk, result))
                .dataPostContingency(buildDataPostContingencies(crac, glsk, result))
                .glskData(buildDataGlskFactors(glsk))
                .build();
    }

    private List buildDataGlskFactors(ZonalData glsk) {
        List glskFactors = new ArrayList<>();
        glsk.getDataPerZone().forEach((s, linearGlsk) -> glskFactors.add(new DataGlskFactors(s, linearGlsk.getVariables().stream().collect(Collectors.toMap(WeightedSensitivityVariable::getId, variable -> (float) variable.getWeight(), (o1, o2) -> o1)))));
        return glskFactors;
    }

    private List buildDataPostContingencies(Crac crac, ZonalData glsk, SystematicSensitivityResult result) {
        List postContingencyList = new ArrayList<>();
        crac.getContingencies().forEach(contingency -> postContingencyList.add(buildDataPostContingency(crac, contingency, glsk, result)));
        return postContingencyList;
    }

    private DataPostContingency buildDataPostContingency(Crac crac, Contingency contingency, ZonalData glsk, SystematicSensitivityResult result) {
        return DataPostContingency.builder()
                .contingencyId(contingency.getId())
                .dataMonitoredBranches(buildDataMonitoredBranches(crac, crac.getStates(contingency), glsk, result))
                .build();
    }

    private DataPreContingency buildDataPreContingency(Crac crac, ZonalData glsk, SystematicSensitivityResult result) {
        return DataPreContingency.builder()
                .dataMonitoredBranches(buildDataMonitoredBranches(crac, Set.of(crac.getPreventiveState()), glsk, result))
                .build();
    }

    private List buildDataMonitoredBranches(Crac crac, Set states, ZonalData glsk, SystematicSensitivityResult result) {
        List branchResultList = new ArrayList<>();
        states.forEach(state -> crac.getFlowCnecs(state).forEach(cnec -> branchResultList.add(buildDataMonitoredBranch(cnec, glsk, result))));
        return branchResultList;
    }

    private DataMonitoredBranch buildDataMonitoredBranch(FlowCnec cnec, ZonalData glsk, SystematicSensitivityResult result) {
        double maxThreshold = cnec.getUpperBound(Side.LEFT, Unit.MEGAWATT).orElse(Double.POSITIVE_INFINITY);
        double minThreshold = cnec.getLowerBound(Side.LEFT, Unit.MEGAWATT).orElse(Double.NEGATIVE_INFINITY);
        return new DataMonitoredBranch(
                cnec.getId(),
                cnec.getName(),
                cnec.getState().getInstant().toString(),
                cnec.getNetworkElement().getId(),
                minThreshold,
                maxThreshold,
                zeroIfNaN(result.getReferenceFlow(cnec)),
                buildDataPtdfPerCountry(cnec, glsk, result)
        );
    }

    private List buildDataPtdfPerCountry(FlowCnec cnec, ZonalData glskProvider, SystematicSensitivityResult result) {
        Map glsks = glskProvider.getDataPerZone();
        return glsks.values().stream()
                .map(glsk ->
                        new DataPtdfPerCountry(
                                glsk.getId(),
                                zeroIfNaN(result.getSensitivityOnFlow(glsk.getId(), cnec))
                        )
                ).collect(Collectors.toList());
    }

    /**
     * Find all remedial actions saved in CRAC, on a given network, at a given state.
     *
     * @param crac CRAC that should contain result extension
     * @param state State for which the RAs should be applied
     */
    public static Set findAllAvailableRemedialActionsForState(Crac crac, State state) {
        Set networkActionsAppl = new HashSet<>();

        crac.getNetworkActions().forEach(na -> {
            UsageMethod usageMethod = na.getUsageMethod(state);
            if (usageMethod.equals(UsageMethod.AVAILABLE) || usageMethod.equals(UsageMethod.FORCED)) {
                networkActionsAppl.add(na);
            } else if (usageMethod.equals(UsageMethod.TO_BE_EVALUATED)) {
                BUSINESS_WARNS.warn("Network action {} with usage method TO_BE_EVALUATED will not be applied, as we don't have access to the flow results.", na.getId());
                /*
                 * This method is only used in FlowbasedComputation.
                 * We do not assess the availability of such remedial actions: they're not supposed to exist.
                 * If it is needed in the future, we will have to loop around a sensitivity computation, followed by a
                 * re-assessment of additional available RAs and applying them, then re-running sensitivity, etc
                 * until the list of applied remedial actions stops changing
                 */
            }
        });

        return networkActionsAppl;
    }

    /**
     * Find network actions saved in CRAC result extension on current working variant of given network, at a given state.
     *
     * @param raoResult Result of Rao computation
     * @param state State for which the RAs should be applied
     * @param networkActions All network actions
     */
    public static Set findAppliedNetworkActionsForState(RaoResult raoResult, State state, Set networkActions) {
        Set networkActionsAppl = new HashSet<>();

        networkActions.forEach(na -> {
            if (raoResult.isActivated(state, na)) {
                networkActionsAppl.add(na);
            }
        });
        return networkActionsAppl;
    }

    /**
     * Find range actions saved in CRAC result extension on current working variant of given network, at a given state.
     *
     * @param raoResult Result of Rao computation
     * @param state State for which the RAs should be applied
     */
    public static Map, Double> findAppliedRangeActionsForState(RaoResult raoResult, State state) {
        return new HashMap<>(raoResult.getOptimizedSetPointsOnState(state));
    }

    private double zeroIfNaN(double value) {
        return Double.isNaN(value) ? 0. : value;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy