SecurityAnalysisResultComparisonWriter.java

/**
 * Copyright (c) 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.security.comparator;

import com.powsybl.commons.io.table.Column;
import com.powsybl.commons.io.table.CsvTableFormatterFactory;
import com.powsybl.commons.io.table.TableFormatter;
import com.powsybl.commons.io.table.TableFormatterConfig;
import com.powsybl.iidm.network.ThreeSides;
import com.powsybl.security.LimitViolation;
import com.powsybl.security.LimitViolationType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.Writer;
import java.util.List;
import java.util.Objects;

/**
 *
 * @author Massimo Ferraro {@literal <massimo.ferraro@techrain.eu>}
 */
public class SecurityAnalysisResultComparisonWriter implements AutoCloseable {

    private static final String RESULT = "Result";
    private static final String EQUIVALENT = "equivalent";
    private static final String DIFFERENT = "different";
    private static final Logger LOGGER = LoggerFactory.getLogger(SecurityAnalysisResultComparisonWriter.class);

    private TableFormatter formatter;
    private String contingency;

    public SecurityAnalysisResultComparisonWriter(Writer writer) {
        Objects.requireNonNull(writer);
        formatter = new CsvTableFormatterFactory().create(writer, "Security Analysis Results Comparison", TableFormatterConfig.load(), getColumns());
    }

    private Column[] getColumns() {
        return new Column[] {
            new Column("Contingency"),
            new Column("Status" + RESULT + "1"),
            new Column("Status" + RESULT + "2"),
            new Column("Equipment"),
            new Column("End"),
            new Column("ViolationType"),
            new Column("ViolationName" + RESULT + "1"),
            new Column("Value" + RESULT + "1"),
            new Column("Limit" + RESULT + "1"),
            new Column("ViolationName" + RESULT + "2"),
            new Column("Value" + RESULT + "2"),
            new Column("Limit" + RESULT + "2"),
            new Column("Actions" + RESULT + "1"),
            new Column("Actions" + RESULT + "2"),
            new Column("Comparison")
        };
    }

    public void setContingency(String contingency) {
        this.contingency = contingency;
    }

    private <T> void checkInput(T value1, T value2) {
        if (value1 == null && value2 == null) {
            throw new IllegalArgumentException("At least one of the input values must be not null");
        }
    }

    public SecurityAnalysisResultComparisonWriter write(Boolean computationOk1, Boolean computationOk2, boolean equivalent) {
        checkInput(computationOk1, computationOk2);
        try {
            formatter = contingency == null ? formatter.writeEmptyCell() : formatter.writeCell(contingency);
            formatter = computationOk1 == null ? formatter.writeEmptyCells(1) : formatter.writeCell(getStatus(computationOk1));
            formatter = computationOk2 == null ? formatter.writeEmptyCells(1) : formatter.writeCell(getStatus(computationOk2));
            formatter.writeEmptyCells(11);
            formatter.writeCell(getComparison(equivalent));
        } catch (IOException e) {
            LOGGER.error("Error writing security analysis results computation status comparison: {}", e.getMessage());
        }
        return this;
    }

    private String getStatus(boolean computationOk) {
        return computationOk ? "converge" : "diverge";
    }

    public SecurityAnalysisResultComparisonWriter write(LimitViolation violation1, LimitViolation violation2, boolean equivalent) {
        checkInput(violation1, violation2);
        try {
            formatter = contingency == null ? formatter.writeEmptyCell() : formatter.writeCell(contingency);
            formatter.writeEmptyCells(2);
            formatter.writeCell(getEquipment(violation1, violation2));
            formatter = getEnd(violation1, violation2) == null ? formatter.writeEmptyCell() : formatter.writeCell(getEnd(violation1, violation2).name());
            formatter.writeCell(getViolationType(violation1, violation2).name());
            writeViolation(violation1);
            writeViolation(violation2);
            formatter.writeEmptyCells(2);
            formatter.writeCell(getComparison(equivalent));
        } catch (IOException e) {
            LOGGER.error("Error writing security analysis results violations comparison: {}", e.getMessage());
        }
        return this;
    }

    private String getEquipment(LimitViolation violation1, LimitViolation violation2) {
        return violation1 == null ? violation2.getSubjectId() : violation1.getSubjectId();
    }

    private ThreeSides getEnd(LimitViolation violation1, LimitViolation violation2) {
        return violation1 == null ? violation2.getSide() : violation1.getSide();
    }

    private LimitViolationType getViolationType(LimitViolation violation1, LimitViolation violation2) {
        return violation1 == null ? violation2.getLimitType() : violation1.getLimitType();
    }

    private void writeViolation(LimitViolation violation) throws IOException {
        if (violation == null) {
            formatter.writeEmptyCells(3);
        } else {
            formatter = violation.getLimitName() == null ? formatter.writeEmptyCell() : formatter.writeCell(violation.getLimitName());
            formatter.writeCell(violation.getValue())
                     .writeCell(getViolationLimit(violation));
        }
    }

    private double getViolationLimit(LimitViolation violation) {
        return violation.getLimit() * violation.getLimitReduction();
    }

    public SecurityAnalysisResultComparisonWriter write(List<String> actions1, List<String> actions2, boolean equivalent) {
        checkInput(actions1, actions2);
        if (noActions(actions1, actions2)) {
            return this; // skip actions line in cvs file if there are no actions
        }
        try {
            formatter = contingency == null ? formatter.writeEmptyCell() : formatter.writeCell(contingency);
            formatter.writeEmptyCells(11);
            formatter = actions1 == null ? formatter.writeEmptyCell() : formatter.writeCell(actions1.toString());
            formatter = actions2 == null ? formatter.writeEmptyCell() : formatter.writeCell(actions2.toString());
            formatter.writeCell(getComparison(equivalent));
        } catch (IOException e) {
            LOGGER.error("Error writing security analysis results actions comparison: {}", e.getMessage());
        }
        return this;
    }

    private boolean noActions(List<String> actions1, List<String> actions2) {
        return (actions1 == null || actions1.isEmpty())
               && (actions2 == null || actions2.isEmpty());
    }

    private String getComparison(boolean equivalent) {
        return equivalent ? EQUIVALENT : DIFFERENT;
    }

    @Override
    public void close() throws IOException {
        formatter.close();
    }

}