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

com.powsybl.cgmes.conversion.elements.AbstractReactiveLimitsOwnerConversion Maven / Gradle / Ivy

There is a newer version: 6.6.0
Show newest version
/**
 * 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/.
 */

package com.powsybl.cgmes.conversion.elements;

import com.google.common.collect.Range;
import com.powsybl.cgmes.conversion.Context;
import com.powsybl.iidm.network.GeneratorAdder;
import com.powsybl.iidm.network.ReactiveCapabilityCurveAdder;
import com.powsybl.iidm.network.ReactiveLimitsHolder;
import com.powsybl.triplestore.api.PropertyBag;
import com.powsybl.triplestore.api.PropertyBags;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

/**
 * @author Luma Zamarreño {@literal }
 */
public abstract class AbstractReactiveLimitsOwnerConversion extends AbstractConductingEquipmentConversion {

    public AbstractReactiveLimitsOwnerConversion(
        String type,
        PropertyBag p,
        Context context) {
        super(type, p, context);
    }

    protected void convertReactiveLimits(ReactiveLimitsHolder g) {
        // IIDM only accepts one definition of limits,
        // either MinMaxReactiveLimits or ReactiveCapabilityCurve.
        // If an element has both definitions we will select the
        // ReactiveCapabilityCurve.
        if (p.containsKey("ReactiveCapabilityCurve")) {
            String curveId = p.getId("ReactiveCapabilityCurve");
            PropertyBags curveData = context.reactiveCapabilityCurveData(curveId);

            Map> qRanges = new HashMap<>();
            curveData.forEach(d -> {
                double p = d.asDouble("xvalue");
                double minQ = d.asDouble("y1value");
                double maxQ = d.asDouble("y2value");

                if (!checkPointValidity(p, minQ, maxQ)) {
                    return;
                }

                Range qRange = fixedMinMaxQ("ReactiveCapabilityCurve Point", minQ, maxQ);

                // check if there is a previous point with same p
                Range prev = qRanges.get(p);
                if (prev != null) {
                    if (prev.isConnected(qRange)) {
                        fixed("reactive capability curve", () -> String.format("point merged with another one with same p (%f)", p));
                        qRanges.put(p, prev.span(qRange));
                    } else {
                        ignored("reactive capability curve point", () -> String.format("another point with same p (%f) and a disconnected reactive range", p));
                    }
                } else {
                    qRanges.put(p, qRange);
                }
            });

            if (qRanges.size() >= 2) {
                // create curve
                ReactiveCapabilityCurveAdder rcca = g.newReactiveCapabilityCurve();
                for (Map.Entry> e : qRanges.entrySet()) {
                    double p = e.getKey();
                    Range qRange = e.getValue();
                    rcca.beginPoint()
                            .setP(p)
                            .setMinQ(qRange.lowerEndpoint())
                            .setMaxQ(qRange.upperEndpoint())
                            .endPoint();
                }
                rcca.add();
            } else if (qRanges.size() == 1) {
                fixed("reactive capability curve", "only one point");
                Map.Entry> e = qRanges.entrySet().iterator().next();
                Range qRange = e.getValue();
                g.newMinMaxReactiveLimits()
                            .setMinQ(qRange.lowerEndpoint())
                            .setMaxQ(qRange.upperEndpoint())
                            .add();
            } else {
                missing("Empty curve");
                convertMinMaxQ(g);
            }
        } else {
            convertMinMaxQ(g);
        }
    }

    private void convertMinMaxQ(ReactiveLimitsHolder g) {
        if (p.containsKey("minQ") && p.containsKey("maxQ")) {
            double minQ = p.asDouble("minQ");
            double maxQ = p.asDouble("maxQ");
            Range qRange = fixedMinMaxQ("Reactive Limits", minQ, maxQ);
            g.newMinMaxReactiveLimits()
                    .setMinQ(qRange.lowerEndpoint())
                    .setMaxQ(qRange.upperEndpoint())
                    .add();
        } else {
            missing("minQ/maxQ are missing, default to unbounded reactive limits");
        }
    }

    private boolean checkPointValidity(double p, double minQ, double maxQ) {
        if (Double.isNaN(p) || Double.isNaN(minQ) || Double.isNaN(maxQ)) {
            Supplier reason = () -> String.format("Incomplete point p, minQ, maxQ = %f, %f, %f", p, minQ, maxQ);
            ignored("ReactiveCapabilityCurvePoint", reason);
            return false;
        }
        return true;
    }

    private Range fixedMinMaxQ(String context, double minQ, double maxQ) {
        if (minQ > maxQ) {
            Supplier reason = () -> String.format("minQ > maxQ (%.4f > %.4f)", minQ, maxQ);
            fixed(context, reason);
            return Range.closed(maxQ, minQ);
        }
        return Range.closed(minQ, maxQ);
    }

    protected void setMinPMaxP(GeneratorAdder adder, double minP, double maxP) {
        if (minP > maxP) {
            context.fixed("Active power limits", String.format("minP (%f) > maxP (%f)", minP, maxP));
            adder.setMinP(maxP).setMaxP(minP);
            return;
        }
        adder.setMinP(minP).setMaxP(maxP);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy