TieLineConverter.java

/**
 * Copyright (c) 2024, 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.psse.converter;

import com.powsybl.iidm.network.*;
import com.powsybl.psse.model.pf.PsseNonTransformerBranch;
import com.powsybl.psse.model.pf.PssePowerFlowModel;
import com.powsybl.psse.model.pf.PsseRates;
import org.apache.commons.math3.complex.Complex;

import java.util.Collections;
import java.util.Comparator;

import static com.powsybl.psse.converter.AbstractConverter.PsseEquipmentType.PSSE_BRANCH;

/**
 * @author Luma Zamarre��o {@literal <zamarrenolm at aia.es>}
 * @author Jos�� Antonio Marqu��s {@literal <marquesja at aia.es>}
 */
class TieLineConverter extends AbstractConverter {

    TieLineConverter(Network network) {
        super(network);
    }

    static void create(Network network, PssePowerFlowModel psseModel, ContextExport contextExport, PsseExporter.PerUnitContext perUnitContext) {
        network.getTieLines().forEach(tieLine -> psseModel.addNonTransformerBranches(Collections.singletonList(createTieLine(tieLine, contextExport, perUnitContext))));
        psseModel.replaceAllNonTransformerBranches(psseModel.getNonTransformerBranches().stream().sorted(Comparator.comparingInt(PsseNonTransformerBranch::getI).thenComparingInt(PsseNonTransformerBranch::getJ).thenComparing(PsseNonTransformerBranch::getCkt)).toList());
    }

    private static PsseNonTransformerBranch createTieLine(TieLine tieLine, ContextExport contextExport, PsseExporter.PerUnitContext perUnitContext) {
        PsseNonTransformerBranch psseLine = createDefaultNonTransformerBranch();
        int busI = getTerminalBusI(tieLine.getTerminal1(), contextExport);
        int busJ = getTerminalBusI(tieLine.getTerminal2(), contextExport);
        double vNom1 = tieLine.getTerminal1().getVoltageLevel().getNominalV();
        double vNom2 = tieLine.getTerminal2().getVoltageLevel().getNominalV();
        Complex transmissionAdmittance = new Complex(tieLine.getR(), tieLine.getX()).reciprocal();

        psseLine.setI(busI);
        psseLine.setJ(busJ);
        psseLine.setCkt(contextExport.getFullExport().getEquipmentCkt(tieLine.getId(), PSSE_BRANCH.getTextCode(), busI, busJ));
        psseLine.setR(impedanceToPerUnitForLinesWithDifferentNominalVoltageAtEnds(tieLine.getR(), vNom1, vNom2, perUnitContext.sBase()));
        psseLine.setX(impedanceToPerUnitForLinesWithDifferentNominalVoltageAtEnds(tieLine.getX(), vNom1, vNom2, perUnitContext.sBase()));
        psseLine.setName(tieLine.getNameOrId().substring(0, Math.min(40, tieLine.getNameOrId().length())));
        psseLine.setRates(createRates(tieLine, vNom1, vNom2));
        psseLine.setGi(admittanceEnd1ToPerUnitForLinesWithDifferentNominalVoltageAtEnds(transmissionAdmittance.getReal(), tieLine.getG1(), vNom1, vNom2, perUnitContext.sBase()));
        psseLine.setBi(admittanceEnd1ToPerUnitForLinesWithDifferentNominalVoltageAtEnds(transmissionAdmittance.getImaginary(), tieLine.getB1(), vNom1, vNom2, perUnitContext.sBase()));
        psseLine.setGj(admittanceEnd2ToPerUnitForLinesWithDifferentNominalVoltageAtEnds(transmissionAdmittance.getReal(), tieLine.getG2(), vNom1, vNom2, perUnitContext.sBase()));
        psseLine.setBj(admittanceEnd2ToPerUnitForLinesWithDifferentNominalVoltageAtEnds(transmissionAdmittance.getImaginary(), tieLine.getB2(), vNom1, vNom2, perUnitContext.sBase()));
        psseLine.setSt(getStatus(tieLine.getTerminal1(), tieLine.getTerminal2(), contextExport));
        return psseLine;
    }

    private static PsseRates createRates(TieLine tieLine, double vNominal1, double vNominal2) {
        PsseRates windingRates = createDefaultRates();
        tieLine.getApparentPowerLimits1().ifPresent(apparentPowerLimits1 -> setSortedRatesToPsseRates(getSortedRates(apparentPowerLimits1), windingRates));
        if (tieLine.getApparentPowerLimits1().isEmpty()) {
            tieLine.getApparentPowerLimits2().ifPresent(apparentPowerLimits2 -> setSortedRatesToPsseRates(getSortedRates(apparentPowerLimits2), windingRates));
        }
        if (tieLine.getApparentPowerLimits1().isEmpty() && tieLine.getApparentPowerLimits2().isEmpty()) {
            tieLine.getCurrentLimits1().ifPresent(currentLimits1 -> setSortedRatesToPsseRates(getSortedRates(currentLimits1, vNominal1), windingRates));
        }
        if (tieLine.getApparentPowerLimits1().isEmpty() && tieLine.getApparentPowerLimits2().isEmpty() && tieLine.getCurrentLimits1().isEmpty()) {
            tieLine.getCurrentLimits2().ifPresent(currentLimits2 -> setSortedRatesToPsseRates(getSortedRates(currentLimits2, vNominal2), windingRates));
        }
        if (tieLine.getApparentPowerLimits1().isEmpty() && tieLine.getApparentPowerLimits2().isEmpty() && tieLine.getCurrentLimits1().isEmpty()
                && tieLine.getCurrentLimits2().isEmpty()) {
            tieLine.getActivePowerLimits1().ifPresent(activePowerLimits1 -> setSortedRatesToPsseRates(getSortedRates(activePowerLimits1), windingRates));
        }
        if (tieLine.getApparentPowerLimits1().isEmpty() && tieLine.getApparentPowerLimits2().isEmpty() && tieLine.getCurrentLimits1().isEmpty()
                && tieLine.getCurrentLimits2().isEmpty() && tieLine.getActivePowerLimits1().isEmpty()) {
            tieLine.getActivePowerLimits2().ifPresent(activePowerLimits2 -> setSortedRatesToPsseRates(getSortedRates(activePowerLimits2), windingRates));
        }
        return windingRates;
    }
}