SynchronousMachineConversion.java

/**
 * Copyright (c) 2017-2018, 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.cgmes.conversion.elements;

import com.powsybl.cgmes.conversion.Context;
import com.powsybl.cgmes.conversion.Conversion;
import com.powsybl.cgmes.conversion.RegulatingControlMappingForGenerators;
import com.powsybl.cgmes.model.CgmesNames;
import com.powsybl.cgmes.model.PowerFlow;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.ActivePowerControlAdder;
import com.powsybl.iidm.network.extensions.ReferencePriority;

import com.powsybl.triplestore.api.PropertyBag;
import java.util.Arrays;

/**
 * @author Luma Zamarre��o {@literal <zamarrenolm at aia.es>}
 */
public class SynchronousMachineConversion extends AbstractReactiveLimitsOwnerConversion {

    private final boolean isCondenser;

    public SynchronousMachineConversion(PropertyBag sm, Context context) {
        super(CgmesNames.SYNCHRONOUS_MACHINE, sm, context);
        String type = p.getLocal("type");
        isCondenser = "SynchronousMachineKind.condenser".equals(type);
    }

    @Override
    public void convert() {
        // If it is a generator, default values for minP and maxP give unlimited range
        // If it is a condenser, default values for minP and maxP are 0
        double minP = p.asDouble("minP", isCondenser ? 0 : -Double.MAX_VALUE);
        double maxP = p.asDouble("maxP", isCondenser ? 0 : Double.MAX_VALUE);
        double ratedS = p.asDouble("ratedS");
        ratedS = ratedS > 0 ? ratedS : Double.NaN;
        PowerFlow f = powerFlow();

        // Default targetP from initial P defined in EQ GeneratingUnit. Removed since CGMES 3.0
        double targetP = p.asDouble("initialP", 0);
        double targetQ = 0;
        // Flow values may come from Terminal or Equipment (SSH RotatingMachine)
        if (f.defined()) {
            targetP = -f.p();
            targetQ = -f.q();
        }

        GeneratorAdder adder = voltageLevel().newGenerator();
        RegulatingControlMappingForGenerators.initialize(adder);
        setMinPMaxP(adder, minP, maxP);
        adder.setTargetP(targetP)
                .setTargetQ(targetQ)
                .setEnergySource(energySourceFromGeneratingUnitType())
                .setRatedS(ratedS);
        identify(adder);
        connect(adder);
        adder.setCondenser(isCondenser);
        Generator g = adder.add();
        addAliasesAndProperties(g);
        convertedTerminals(g.getTerminal());
        convertReactiveLimits(g);
        int referencePriority = p.asInt("referencePriority", 0);
        if (referencePriority > 0) {
            ReferencePriority.set(g, referencePriority);
        }
        if (!isCondenser) {
            convertGenerator(g);
        }

        context.regulatingControlMapping().forGenerators().add(g.getId(), p);
        addSpecificProperties(g, p);
    }

    private static void addSpecificProperties(Generator generator, PropertyBag p) {
        generator.setProperty(Conversion.PROPERTY_CGMES_ORIGINAL_CLASS, CgmesNames.SYNCHRONOUS_MACHINE);
        String type = p.getLocal("type");
        if (type != null) {
            generator.setProperty(Conversion.PROPERTY_CGMES_SYNCHRONOUS_MACHINE_TYPE, type.replace("SynchronousMachineKind.", ""));
        }
        String operatingMode = p.getLocal("operatingMode");
        if (operatingMode != null) {
            generator.setProperty(Conversion.PROPERTY_CGMES_SYNCHRONOUS_MACHINE_OPERATING_MODE, operatingMode.replace("SynchronousMachineOperatingMode.", ""));
        }
    }

    private void convertGenerator(Generator g) {
        double normalPF = p.asDouble("normalPF");
        if (!Double.isNaN(normalPF)) {
            if (context.config().createActivePowerControlExtension()) {
                g.newExtension(ActivePowerControlAdder.class)
                        .withParticipate(true)
                        .withParticipationFactor(normalPF)
                        .add();
            } else {
                g.setProperty(Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + "normalPF", String.valueOf(normalPF));
            }
        }
        String generatingUnit = p.getId("GeneratingUnit");
        if (generatingUnit != null) {
            g.setProperty(Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + "GeneratingUnit", generatingUnit);
        }

        addSpecificGeneratingUnitProperties(g, p);
    }

    private static void addSpecificGeneratingUnitProperties(Generator generator, PropertyBag p) {
        String hydroPlantStorageType = p.getLocal("hydroPlantStorageType");
        if (hydroPlantStorageType != null) {
            generator.setProperty(Conversion.PROPERTY_HYDRO_PLANT_STORAGE_TYPE, hydroPlantStorageType.replace("HydroPlantStorageKind.", ""));
        }
        String fossilFuelType = String.join(";",
                Arrays.stream(p.getLocals("fossilFuelTypeList", ";"))
                        .map(ff -> ff.replace("FuelType.", ""))
                        .toList());
        if (!fossilFuelType.isEmpty()) {
            generator.setProperty(Conversion.PROPERTY_FOSSIL_FUEL_TYPE, fossilFuelType);
        }
        String windGenUnitType = p.getLocal("windGenUnitType");
        if (windGenUnitType != null) {
            generator.setProperty(Conversion.PROPERTY_WIND_GEN_UNIT_TYPE, windGenUnitType.replace("WindGenUnitKind.", ""));
        }
    }

    private EnergySource energySourceFromGeneratingUnitType() {
        String gut = p.getLocal("generatingUnitType");
        EnergySource es = EnergySource.OTHER;
        if (gut != null) {
            if (gut.contains("HydroGeneratingUnit")) {
                es = EnergySource.HYDRO;
            } else if (gut.contains("NuclearGeneratingUnit")) {
                es = EnergySource.NUCLEAR;
            } else if (gut.contains("ThermalGeneratingUnit")) {
                es = EnergySource.THERMAL;
            } else if (gut.contains("WindGeneratingUnit")) {
                es = EnergySource.WIND;
            } else if (gut.contains("SolarGeneratingUnit")) {
                es = EnergySource.SOLAR;
            }
        }
        return es;
    }
}