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

com.powsybl.iidm.modification.LoadFlowBasedPhaseShifterOptimizer Maven / Gradle / Ivy

/**
 * Copyright (c) 2017, 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.iidm.modification;

import com.powsybl.commons.PowsyblException;
import com.powsybl.computation.ComputationManager;
import com.powsybl.iidm.network.LoadingLimits;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.TwoWindingsTransformer;
import com.powsybl.loadflow.LoadFlow;
import com.powsybl.loadflow.LoadFlowParameters;
import com.powsybl.loadflow.LoadFlowResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;
import java.util.UUID;

/**
 * @author Geoffroy Jamgotchian {@literal }
 */
public class LoadFlowBasedPhaseShifterOptimizer implements PhaseShifterOptimizer {

    private static final Logger LOGGER = LoggerFactory.getLogger(LoadFlowBasedPhaseShifterOptimizer.class);

    private final ComputationManager computationManager;

    private final LoadFlowBasedPhaseShifterOptimizerConfig config;

    public LoadFlowBasedPhaseShifterOptimizer(ComputationManager computationManager, LoadFlowBasedPhaseShifterOptimizerConfig config) {
        this.computationManager = Objects.requireNonNull(computationManager);
        this.config = Objects.requireNonNull(config);
    }

    public LoadFlowBasedPhaseShifterOptimizer(ComputationManager computationManager) {
        this(computationManager, LoadFlowBasedPhaseShifterOptimizerConfig.load());
    }

    private void runLoadFlow(Network network, String workingStateId) {
        try {
            String loadFlowName = config.getLoadFlowName().orElse(null);
            LoadFlowResult result = LoadFlow.find(loadFlowName)
                                            .run(network, workingStateId, computationManager, LoadFlowParameters.load());
            if (!result.isOk()) {
                throw new PowsyblException("Load flow diverged during phase shifter optimization");
            }
        } catch (Exception e) {
            throw new PowsyblException(e);
        }
    }

    private static double getI(TwoWindingsTransformer phaseShifter) {
        return phaseShifter.getTerminal1().getI();
    }

    private static double getLimit(TwoWindingsTransformer phaseShifter) {
        return phaseShifter.getCurrentLimits1().map(LoadingLimits::getPermanentLimit).orElseThrow(PowsyblException::new);
    }

    @Override
    public void findMaximalFlowTap(Network network, String phaseShifterId) {
        TwoWindingsTransformer phaseShifter = network.getTwoWindingsTransformer(phaseShifterId);
        if (phaseShifter == null) {
            throw new PowsyblException("Phase shifter '" + phaseShifterId + "' not found");
        }
        if (!phaseShifter.hasPhaseTapChanger()) {
            throw new PowsyblException("Transformer '" + phaseShifterId + "' is not a phase shifter");
        }

        int optimalTap;

        // fromNode a temporary state that will be used to move the phase shifter tap without changing the current state
        String stateId = network.getVariantManager().getWorkingVariantId();
        String tmpStateId = "phase-shifter-optim-" + UUID.randomUUID();
        network.getVariantManager().cloneVariant(stateId, tmpStateId);
        try {
            network.getVariantManager().setWorkingVariant(tmpStateId);
            runLoadFlow(network, tmpStateId);
            if (phaseShifter.getTerminal1().getI() >= phaseShifter.getCurrentLimits1().map(LoadingLimits::getPermanentLimit).orElseThrow(PowsyblException::new)) {
                throw new PowsyblException("Phase shifter already overloaded");
            }
            int tapPosInc = 1; // start by incrementing tap +1
            double i;
            double limit = getLimit(phaseShifter);
            int tapPos = phaseShifter.getPhaseTapChanger().getTapPosition();
            int maxTap = phaseShifter.getPhaseTapChanger().getHighTapPosition();

            // increment tap until going above permanent limit
            while ((i = getI(phaseShifter)) < limit && tapPos < maxTap) {
                // increment tap
                tapPos += tapPosInc;
                phaseShifter.getPhaseTapChanger().setTapPosition(tapPos);

                // run load flow
                runLoadFlow(network, tmpStateId);

                // wrong direction, negate the increment
                if (getI(phaseShifter) < i) {
                    // we don't go in the right direction
                    tapPosInc *= -1;
                }
            }

            if (i < limit) {
                // we reached the maximal (ou minimal) tap and phase shifter is not overloaded
                optimalTap = phaseShifter.getPhaseTapChanger().getTapPosition();
            } else {
                // with the last tap, phase shifter is overloaded, in that case we take the previous tap as the optimmal one
                optimalTap = phaseShifter.getPhaseTapChanger().getTapPosition() - tapPosInc;
                phaseShifter.getPhaseTapChanger().setTapPosition(optimalTap);

                // just to be sure, check that with the previous tap, phase shifter is not overloaded...
                runLoadFlow(network, tmpStateId);
                // check there phase shifter is not overloaded
                if (getI(phaseShifter) >= limit) {
                    throw new IllegalStateException("Phase shifter should not be overload");
                }
            }
        } finally {
            // don't forget to remove the temporary state!
            network.getVariantManager().removeVariant(tmpStateId);
            network.getVariantManager().setWorkingVariant(stateId);
        }

        LOGGER.debug("Optimal phase shifter '{}' tap is {} (from {})",
                phaseShifter, optimalTap, phaseShifter.getPhaseTapChanger().getTapPosition());

        // set the best optimal tap on the current state
        phaseShifter.getPhaseTapChanger().setTapPosition(optimalTap);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy