LineConverter.java

/**
 * 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.powerfactory.converter;

import com.powsybl.iidm.network.Network;
import com.powsybl.powerfactory.converter.PowerFactoryImporter.ImportContext;
import com.powsybl.powerfactory.model.DataObject;
import com.powsybl.powerfactory.model.DataObjectRef;
import com.powsybl.powerfactory.model.PowerFactoryException;

import java.util.List;
import java.util.Optional;

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

class LineConverter extends AbstractConverter {

    LineConverter(ImportContext importContext, Network network) {
        super(importContext, network);
    }

    void create(DataObject elmLne) {
        List<NodeRef> nodeRefs = checkNodes(elmLne, 2);
        Optional<LineModel> lineModel = LineModel.createFromElmLne(elmLne);
        if (lineModel.isEmpty()) {
            return;
        }
        NodeRef end1 = nodeRefs.get(0);
        NodeRef end2 = nodeRefs.get(1);

        createLine(end1, end2, elmLne.getLocName(), lineModel.get());
    }

    void createTower(DataObject elmTow) {
        Optional<List<DataObjectRef>> plines = elmTow.findObjectVectorAttributeValue("plines");
        if (plines.isEmpty() || plines.get().isEmpty()) {
            throw new PowerFactoryException("ElmTow without plines '" + elmTow.getLocName() + "'");
        }

        plines.get().forEach(pline -> {
            DataObject elmLne = pline.resolve()
                .orElseThrow(() -> new PowerFactoryException("pline dataObject not found, ElmTow Id: " + elmTow.getId()));
            createFromElmLneFromElmTow(elmTow, elmLne);
        });
    }

    private void createLine(NodeRef end1, NodeRef end2, String id, LineModel lineModel) {
        getNetwork().newLine()
            .setId(id)
            .setEnsureIdUnicity(true)
            .setVoltageLevel1(end1.voltageLevelId)
            .setVoltageLevel2(end2.voltageLevelId)
            .setNode1(end1.node)
            .setNode2(end2.node)
            .setR(lineModel.r)
            .setX(lineModel.x)
            .setG1(lineModel.g1)
            .setB1(lineModel.b1)
            .setG2(lineModel.g2)
            .setB2(lineModel.b2)
            .add();
    }

    private void createFromElmLneFromElmTow(DataObject elmTow, DataObject elmLne) {
        List<NodeRef> nodeRefs = checkNodes(elmLne, 2);
        LineModel lineModel = LineModel.createFromElmTow(elmTow, elmLne);

        NodeRef end1 = nodeRefs.get(0);
        NodeRef end2 = nodeRefs.get(1);
        createLine(end1, end2, elmLne.getLocName(), lineModel);
    }

    private static final class LineModel {
        private final double r;
        private final double x;
        private final double g1;
        private final double b1;
        private final double g2;
        private final double b2;

        private LineModel(double r, double x, double g1, double b1, double g2, double b2) {
            this.r = r;
            this.x = x;
            this.g1 = g1;
            this.b1 = b1;
            this.g2 = g2;
            this.b2 = b2;
        }

        private static Optional<LineModel> createFromElmLne(DataObject elmLne) {
            return elmLne.findObjectAttributeValue(DataAttributeNames.TYP_ID).flatMap(DataObjectRef::resolve).map(typLne -> typeLneModel(elmLne, typLne));
        }

        private static LineModel typeLneModel(DataObject elmLne, DataObject typLne) {
            float dline = elmLne.getFloatAttributeValue("dline");
            float rline = typLne.getFloatAttributeValue("rline");
            float xline = typLne.getFloatAttributeValue("xline");
            double r = rline * dline;
            double x = xline * dline;

            double g = typeLneModelShuntConductance(typLne) * dline;
            double b = typeLneModelShuntSusceptance(typLne) * dline;

            int numberOfParallelLines = elmLne.findIntAttributeValue("nlnum").orElse(1);
            if (numberOfParallelLines > 1) {
                r /= numberOfParallelLines;
                x /= numberOfParallelLines;
                g *= numberOfParallelLines;
                b *= numberOfParallelLines;
            }

            return new LineModel(r, x, g * 0.5, b * 0.5, g * 0.5, b * 0.5);
        }

        private static double typeLneModelShuntConductance(DataObject typLne) {
            Optional<Float> gline = typLne.findFloatAttributeValue("gline");
            if (gline.isPresent()) {
                return microSiemensToSiemens(gline.get());
            }
            Optional<Float> tline = typLne.findFloatAttributeValue("tline");
            Optional<Float> bline = typLne.findFloatAttributeValue("bline");
            if (tline.isPresent() && bline.isPresent()) {
                return microSiemensToSiemens(bline.get() * tline.get());
            }
            return 0.0;
        }

        private static double typeLneModelShuntSusceptance(DataObject typLne) {
            Optional<Float> bline = typLne.findFloatAttributeValue("bline");
            if (bline.isPresent()) {
                return microSiemensToSiemens(bline.get());
            }
            Optional<Float> frnom = typLne.findFloatAttributeValue("frnom");
            Optional<Float> cline = typLne.findFloatAttributeValue("cline");
            if (frnom.isPresent() && cline.isPresent()) {
                return microFaradToSiemens(frnom.get(), cline.get());
            }
            return 0.0;
        }

        private static LineModel createFromElmTow(DataObject elmTow, DataObject elmLne) {
            float dline = elmLne.getFloatAttributeValue("dline");
            DataObject typTow = getTypeTow(elmTow);

            double r = typTow.getDoubleMatrixAttributeValue("R_c1").getEntry(0, 0) * dline;
            double x = typTow.getDoubleMatrixAttributeValue("X_c1").getEntry(0, 0) * dline;
            double g = microSiemensToSiemens(typTow.getDoubleMatrixAttributeValue("G_c1").getEntry(0, 0) * dline);
            double b = microSiemensToSiemens(typTow.getDoubleMatrixAttributeValue("B_c1").getEntry(0, 0) * dline);

            return new LineModel(r, x, g * 0.5, b * 0.5, g * 0.5, b * 0.5);
        }

        private static DataObject getTypeTow(DataObject elmTow) {
            return elmTow.findObjectVectorAttributeValue("pGeo")
                .flatMap(listDataObjectRef -> listDataObjectRef.stream().findFirst()).flatMap(DataObjectRef::resolve)
                .orElseThrow(() -> new PowerFactoryException("Unexpected elmTow configuration '" + elmTow.getLocName() + "'"));
        }
    }
}