GlskQualityCheck.java

/*
 * Copyright (c) 2020, 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.glsk.ucte.quality_check;

import com.powsybl.commons.report.ReportNode;
import com.powsybl.glsk.api.GlskPoint;
import com.powsybl.glsk.api.GlskRegisteredResource;
import com.powsybl.glsk.ucte.UcteGlskPoint;
import com.powsybl.iidm.network.Injection;
import com.powsybl.iidm.network.LoadType;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.VoltageLevel;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.powsybl.commons.report.TypedValue.WARN_SEVERITY;

/**
 * @author Marc Erkol {@literal <marc.erkol at rte-france.com>}
 */
class GlskQualityCheck {

    private static final String GENERATOR = "A04";

    private static final String LOAD = "A05";

    public static final String NODE_ID_KEY = "NodeId";

    public static final String TYPE_KEY = "Type";

    public static final String TSO_KEY = "TSO";

    public static void gskQualityCheck(GlskQualityCheckInput input, ReportNode reportNode) {
        new GlskQualityCheck().generateReport(input, reportNode);
    }

    private void generateReport(GlskQualityCheckInput input, ReportNode reportNode) {
        Map<String, UcteGlskPoint> glskPointMap = input.getUcteGlskDocument().getGlskPointsForInstant(input.getInstant());
        glskPointMap.forEach((country, glskPoint) -> checkGlskPoint(glskPoint, input.getNetwork(), country, reportNode));
    }

    private void checkGlskPoint(GlskPoint glskPoint, Network network, String tso, ReportNode reportNode) {
        List<String> manualGskGenerators = glskPoint.getGlskShiftKeys().stream()
                .filter(gskShiftKey -> gskShiftKey.getPsrType().equals(GENERATOR) && gskShiftKey.getBusinessType().equals("B43"))
                .flatMap(gskShiftKey -> gskShiftKey.getRegisteredResourceArrayList().stream())
                .map(GlskRegisteredResource::getGeneratorId).collect(Collectors.toList());
        List<String> manualGskLoads = glskPoint.getGlskShiftKeys().stream()
                .filter(gskShiftKey -> gskShiftKey.getPsrType().equals(LOAD) && gskShiftKey.getBusinessType().equals("B43"))
                .flatMap(gskShiftKey -> gskShiftKey.getRegisteredResourceArrayList().stream())
                .map(GlskRegisteredResource::getLoadId).collect(Collectors.toList());

        network.getVoltageLevelStream().forEach(voltageLevel -> voltageLevel.getBusBreakerView().getBuses().forEach(bus -> {
            if (manualGskGenerators.contains(bus.getId() + "_generator")) {
                createMissingGenerator(network, voltageLevel, bus.getId());
            }
            if (manualGskLoads.contains(bus.getId() + "_load")) {
                createMissingLoad(network, voltageLevel, bus.getId());
            }
        }));

        glskPoint.getGlskShiftKeys().forEach(glskShiftKey -> {
            if (glskShiftKey.getPsrType().equals(GENERATOR)) {
                glskShiftKey.getRegisteredResourceArrayList()
                        .forEach(resource -> checkResource(resource, network.getGenerator(resource.getGeneratorId()), "Generator", network, tso, reportNode));
            } else if (glskShiftKey.getPsrType().equals(LOAD)) {
                glskShiftKey.getRegisteredResourceArrayList()
                        .forEach(resource -> checkResource(resource, network.getLoad(resource.getLoadId()), "Load", network, tso, reportNode));
            }
        });
    }

    private void createMissingGenerator(Network network, VoltageLevel voltageLevel, String busId) {
        String generatorId = busId + "_generator";
        if (network.getGenerator(generatorId) == null) {
            voltageLevel.newGenerator()
                    .setBus(busId)
                    .setEnsureIdUnicity(true)
                    .setId(generatorId)
                    .setMaxP(9999)
                    .setMinP(0)
                    .setTargetP(0)
                    .setTargetQ(0)
                    .setTargetV(voltageLevel.getNominalV())
                    .setVoltageRegulatorOn(false)
                    .setFictitious(true)
                    .add()
                    .newMinMaxReactiveLimits().setMaxQ(99999).setMinQ(99999).add();
        }
    }

    private void createMissingLoad(Network network, VoltageLevel voltageLevel, String busId) {
        String loadId = busId + "_load";
        if (network.getLoad(loadId) == null) {
            voltageLevel.newLoad()
                    .setBus(busId)
                    .setEnsureIdUnicity(true)
                    .setId(loadId)
                    .setP0(0)
                    .setQ0(0)
                    .setLoadType(LoadType.FICTITIOUS)
                    .add();
        }
    }

    private void checkResource(GlskRegisteredResource registeredResource, Injection<?> injection, String type, Network network, String tso, ReportNode reportNode) {
        if (injection == null) {

            if (network.getBusBreakerView().getBus(registeredResource.getmRID()) == null) {
                reportNode.newReportNode().withMessageTemplate("1", "GLSK node is not found in CGM")
                    .withTypedValue(NODE_ID_KEY, registeredResource.getmRID(), "")
                    .withTypedValue(TYPE_KEY, type, "")
                    .withTypedValue(TSO_KEY, tso, "")
                    .withSeverity(WARN_SEVERITY)
                    .add();
            } else {
                reportNode.newReportNode().withMessageTemplate("2", "GLSK node is present but has no running Generator or Load")
                    .withTypedValue(NODE_ID_KEY, registeredResource.getmRID(), "")
                    .withTypedValue(TYPE_KEY, type, "")
                    .withTypedValue(TSO_KEY, tso, "")
                    .withSeverity(WARN_SEVERITY)
                    .add();
            }
        } else {
            if (!injection.getTerminal().isConnected()
                    || !injection.getTerminal().getBusBreakerView().getBus().isInMainSynchronousComponent()) {
                reportNode.newReportNode().withMessageTemplate("3", "GLSK node is connected to an island")
                    .withTypedValue(NODE_ID_KEY, registeredResource.getmRID(), "")
                    .withTypedValue(TYPE_KEY, type, "")
                    .withTypedValue(TSO_KEY, tso, "")
                    .withSeverity(WARN_SEVERITY)
                    .add();
            }
        }
    }
}