OutageReader.java

/*
 * Copyright (c) 2022, 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.openrao.data.crac.io.fbconstraint;

import com.powsybl.contingency.ContingencyElement;
import com.powsybl.contingency.ContingencyElementType;
import com.powsybl.openrao.data.crac.api.ContingencyAdder;
import com.powsybl.openrao.data.crac.api.Crac;
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.OutageType;
import com.powsybl.openrao.data.crac.io.commons.ucte.UcteContingencyElementHelper;
import com.powsybl.openrao.data.crac.io.commons.ucte.UcteNetworkAnalyzer;
import com.powsybl.iidm.network.DanglingLine;
import com.powsybl.iidm.network.Network;

import java.util.*;

/**
 * @author Baptiste Seguinot{@literal <baptiste.seguinot at rte-france.com>}
 */
class OutageReader {

    private final OutageType outage;

    private boolean isOutageValid = true;
    private String invalidOutageReason = "";

    private Map<String, ContingencyElementType> outageElementIdsAndContingencyType;

    OutageType getOutage() {
        return outage;
    }

    boolean isOutageValid() {
        return isOutageValid;
    }

    String getInvalidOutageReason() {
        return invalidOutageReason;
    }

    void addContingency(Crac crac) {
        ContingencyAdder contingencyAdder = crac.newContingency()
            .withId(outage.getId())
            .withName(outage.getName());
        outageElementIdsAndContingencyType.forEach(contingencyAdder::withContingencyElement);
        contingencyAdder.add();
    }

    OutageReader(OutageType outage, UcteNetworkAnalyzer ucteNetworkHelper) {
        this.outage = outage;
        interpretWithNetwork(ucteNetworkHelper);
    }

    private void interpretWithNetwork(UcteNetworkAnalyzer ucteNetworkHelper) {

        if (outage.getHvdcVH().isEmpty() && outage.getBranch().isEmpty()) {
            this.isOutageValid = false;
            this.invalidOutageReason = String.format("outage %s is not valid as it contains neither 'Branch' nor 'HvdcVH' fields", outage.getId());
            return;
        }

        outageElementIdsAndContingencyType = new HashMap<>();

        if (!outage.getBranch().isEmpty()) {

            List<UcteContingencyElementHelper> outageElementsReader = outage.getBranch().stream()
                .map(branch -> new UcteContingencyElementHelper(branch.getFrom(), branch.getTo(), branch.getOrder(), branch.getElementName(), ucteNetworkHelper))
                .toList();

            Optional<UcteContingencyElementHelper> invalidBranch = outageElementsReader.stream().filter(br -> !br.isValid()).findAny();

            if (invalidBranch.isPresent()) {
                this.isOutageValid = false;
                this.invalidOutageReason = String.format("outage %s is not valid: %s", outage.getId(), invalidBranch.get().getInvalidReason());
                return;
            } else {
                outageElementsReader.forEach(br -> outageElementIdsAndContingencyType.put(br.getIdInNetwork(), br.getContingencyTypeInNetwork()));
            }
        }

        if (!outage.getHvdcVH().isEmpty()) {
            outage.getHvdcVH().forEach(hvdcVH -> {
                DanglingLine dl1 = findDanglingLineWithXnode(hvdcVH.getFrom(), ucteNetworkHelper.getNetwork());
                DanglingLine dl2 = findDanglingLineWithXnode(hvdcVH.getTo(), ucteNetworkHelper.getNetwork());

                if (Objects.isNull(dl1) || Objects.isNull(dl2)) {
                    this.isOutageValid = false;
                    this.invalidOutageReason = String.format("one of the two Xnodes of outage %s was not found in the network: %s, %s", outage.getId(), hvdcVH.getFrom(), hvdcVH.getTo());
                } else {
                    outageElementIdsAndContingencyType.put(dl1.getId(), ContingencyElement.of(dl1).getType());
                    outageElementIdsAndContingencyType.put(dl2.getId(), ContingencyElement.of(dl2).getType());
                }
            });
        }
    }

    private DanglingLine findDanglingLineWithXnode(String xNodeId, Network network) {
        return network.getDanglingLineStream().filter(danglingLine -> danglingLine.getPairingKey().equals(xNodeId)).findFirst().orElse(null);
    }
}