ShuntCompensatorsValidation.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.loadflow.validation;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.Objects;

import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.powsybl.loadflow.validation.io.ValidationWriter;

/**
 *
 * @author Massimo Ferraro {@literal <massimo.ferraro@techrain.eu>}
 */
public final class ShuntCompensatorsValidation {

    private static final Logger LOGGER = LoggerFactory.getLogger(ShuntCompensatorsValidation.class);

    public static final ShuntCompensatorsValidation INSTANCE = new ShuntCompensatorsValidation();

    private ShuntCompensatorsValidation() {
    }

    public boolean checkShunts(Network network, ValidationConfig config, Path file) throws IOException {
        Objects.requireNonNull(file);
        Objects.requireNonNull(config);
        Objects.requireNonNull(file);
        try (Writer writer = Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
            return checkShunts(network, config, writer);
        }
    }

    public boolean checkShunts(Network network, ValidationConfig config, Writer writer) {
        Objects.requireNonNull(network);
        Objects.requireNonNull(config);
        Objects.requireNonNull(writer);
        try (ValidationWriter shuntsWriter = ValidationUtils.createValidationWriter(network.getId(), config, writer, ValidationType.SHUNTS)) {
            return checkShunts(network, config, shuntsWriter);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    public boolean checkShunts(Network network, ValidationConfig config, ValidationWriter shuntsWriter) {
        Objects.requireNonNull(network);
        Objects.requireNonNull(config);
        Objects.requireNonNull(shuntsWriter);
        LOGGER.info("Checking shunt compensators of network {}", network.getId());
        return network.getShuntCompensatorStream()
                .sorted(Comparator.comparing(ShuntCompensator::getId))
                .map(shunt -> checkShunts(shunt, config, shuntsWriter))
                .reduce(Boolean::logicalAnd)
                .orElse(true);
    }

    public boolean checkShunts(ShuntCompensator shunt, ValidationConfig config, Writer writer) {
        Objects.requireNonNull(shunt);
        Objects.requireNonNull(config);
        Objects.requireNonNull(writer);

        try (ValidationWriter shuntsWriter = ValidationUtils.createValidationWriter(shunt.getId(), config, writer, ValidationType.SHUNTS)) {
            return checkShunts(shunt, config, shuntsWriter);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    public boolean checkShunts(ShuntCompensator shunt, ValidationConfig config, ValidationWriter shuntsWriter) {
        Objects.requireNonNull(shunt);
        Objects.requireNonNull(config);
        Objects.requireNonNull(shuntsWriter);

        if (shunt.getModelType() == ShuntCompensatorModelType.NON_LINEAR) {
            throw new PowsyblException("non linear shunt not supported yet");
        }

        double p = shunt.getTerminal().getP();
        double q = shunt.getTerminal().getQ();
        int currentSectionCount = shunt.getSectionCount();
        int maximumSectionCount = shunt.getMaximumSectionCount();
        double bPerSection = shunt.getModel(ShuntCompensatorLinearModel.class).getBPerSection();
        double nominalV = shunt.getTerminal().getVoltageLevel().getNominalV();
        double qMax = bPerSection * maximumSectionCount * nominalV * nominalV;
        Bus bus = shunt.getTerminal().getBusView().getBus();
        double v = bus != null ? bus.getV() : Double.NaN;
        boolean connected = bus != null;
        Bus connectableBus = shunt.getTerminal().getBusView().getConnectableBus();
        boolean connectableMainComponent = connectableBus != null && connectableBus.isInMainConnectedComponent();
        boolean mainComponent = bus != null ? bus.isInMainConnectedComponent() : connectableMainComponent;
        return checkShunts(shunt.getId(), p, q, currentSectionCount, maximumSectionCount, bPerSection, v, qMax, nominalV, connected, mainComponent, config, shuntsWriter);
    }

    public boolean checkShunts(String id, double p, double q, int currentSectionCount, int maximumSectionCount, double bPerSection,
                               double v, double qMax, double nominalV, boolean connected, boolean mainComponent, ValidationConfig config,
                               Writer writer) {
        Objects.requireNonNull(id);
        Objects.requireNonNull(config);
        Objects.requireNonNull(writer);

        try (ValidationWriter shuntsWriter = ValidationUtils.createValidationWriter(id, config, writer, ValidationType.SHUNTS)) {
            return checkShunts(id, p, q, currentSectionCount, maximumSectionCount, bPerSection, v, qMax, nominalV, connected, mainComponent, config, shuntsWriter);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    public boolean checkShunts(String id, double p, double q, int currentSectionCount, int maximumSectionCount, double bPerSection,
                               double v, double qMax, double nominalV, boolean connected, boolean mainComponent, ValidationConfig config,
                               ValidationWriter shuntsWriter) {
        boolean validated = true;

        if (!connected && !Double.isNaN(q) && q != 0) { // if the shunt is disconnected then either ���q��� is not defined or ���q��� is 0
            LOGGER.warn("{} {}: {}: disconnected shunt Q {}", ValidationType.SHUNTS, ValidationUtils.VALIDATION_ERROR, id, q);
            validated = false;
        }
        // ���q��� = - bPerSection * currentSectionCount * v^2
        double expectedQ = -bPerSection * currentSectionCount * v * v;
        if (connected && ValidationUtils.isMainComponent(config, mainComponent)) {
            // ���p��� is always NaN
            if (!Double.isNaN(p)) {
                LOGGER.warn("{} {}: {}: P={}", ValidationType.SHUNTS, ValidationUtils.VALIDATION_ERROR, id, p);
                validated = false;
            }
            if (ValidationUtils.areNaN(config, q, expectedQ) || Math.abs(q - expectedQ) > config.getThreshold()) {
                LOGGER.warn("{} {}: {}:  Q {} {}", ValidationType.SHUNTS, ValidationUtils.VALIDATION_ERROR, id, q, expectedQ);
                validated = false;
            }
        }
        try {
            shuntsWriter.write(id, q, expectedQ, p, currentSectionCount, maximumSectionCount, bPerSection, v, connected, qMax, nominalV, mainComponent, validated);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
        return validated;
    }
}