StateMonitor.java

/**
 * Copyright (c) 2021, 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.monitor;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import com.powsybl.commons.json.JsonUtil;
import com.powsybl.contingency.ContingencyContext;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;

/**
 *  A state monitor allows to output in security analysis results some state variables related to branches, buses and three
 *  windings transformers. The supported state variables are active power, reactive power and current at both side for branches
 *  (see {@link com.powsybl.security.results.BranchResult}), active power, reactive power and current at voltage level side for
 *  three windings transformers (see {@link com.powsybl.security.results.ThreeWindingsTransformerResult}) and voltage angle and voltage
 *  magnitude for buses (see {@link com.powsybl.security.results.BusResult}).
 *  <p>
 *  A state monitor is defined for some contingencies through a {@link ContingencyContext}.
 *  A {@link com.powsybl.contingency.ContingencyContextType#NONE} or {@link com.powsybl.contingency.ContingencyContextType#ALL}
 *  (because it includes the base case) contingency context will output monitoring results in
 *  {@link com.powsybl.security.results.PreContingencyResult}.
 *  If a contingency has a state monitor declared (through a {@link com.powsybl.contingency.ContingencyContextType#ALL},
 *  a {@link com.powsybl.contingency.ContingencyContextType#ONLY_CONTINGENCIES} or a {@link com.powsybl.contingency.ContingencyContextType#SPECIFIC}),
 *  monitoring results are output in the dedicated {@link com.powsybl.security.results.PostContingencyResult}.
 *
 * @author Etienne Lesot {@literal <etienne.lesot at rte-france.com>}
 */
public class StateMonitor {

    /**
     * define on which situation information are needed
     */
    private final ContingencyContext contingencyContext;

    /**
     * branchs ids on which information will be collected
     */
    private final Set<String> branchIds = new LinkedHashSet<>();

    /**
     * voltageLevels ids on which information will be collected
     */
    private final Set<String> voltageLevelIds = new LinkedHashSet<>();

    /**
     * voltageLevels ids on which information will be collected
     */
    private final Set<String> threeWindingsTransformerIds = new LinkedHashSet<>();

    public ContingencyContext getContingencyContext() {
        return contingencyContext;
    }

    public Set<String> getBranchIds() {
        return branchIds;
    }

    public Set<String> getVoltageLevelIds() {
        return voltageLevelIds;
    }

    public Set<String> getThreeWindingsTransformerIds() {
        return threeWindingsTransformerIds;
    }

    public StateMonitor(@JsonProperty("contingencyContext") ContingencyContext contingencyContext,
                        @JsonProperty("branchIds") Set<String> branchIds, @JsonProperty("voltageLevelIds") Set<String> voltageLevelIds,
                        @JsonProperty("threeWindingsTransformerIds") Set<String> threeWindingsTransformerIds) {
        this.contingencyContext = Objects.requireNonNull(contingencyContext);
        this.branchIds.addAll(Objects.requireNonNull(branchIds));
        this.voltageLevelIds.addAll(Objects.requireNonNull(voltageLevelIds));
        this.threeWindingsTransformerIds.addAll(Objects.requireNonNull(threeWindingsTransformerIds));
    }

    public StateMonitor merge(StateMonitor monitorTobeMerged) {
        this.branchIds.addAll(monitorTobeMerged.getBranchIds());
        this.voltageLevelIds.addAll(monitorTobeMerged.getVoltageLevelIds());
        this.threeWindingsTransformerIds.addAll(monitorTobeMerged.getThreeWindingsTransformerIds());
        return this;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        StateMonitor that = (StateMonitor) o;
        return Objects.equals(contingencyContext, that.contingencyContext) &&
            Objects.equals(branchIds, that.branchIds) &&
            Objects.equals(voltageLevelIds, that.voltageLevelIds) &&
            Objects.equals(threeWindingsTransformerIds, that.threeWindingsTransformerIds);
    }

    @Override
    public int hashCode() {
        return Objects.hash(contingencyContext, branchIds, voltageLevelIds, threeWindingsTransformerIds);
    }

    @Override
    public String toString() {
        return "StateMonitor{" +
            "contingencyContext=" + contingencyContext +
            ", branchIds=" + branchIds +
            ", voltageLevelIds=" + voltageLevelIds +
            ", threeWindingsTransformerIds=" + threeWindingsTransformerIds +
            '}';
    }

    public static void write(List<StateMonitor> monitors, Path jsonFile) {
        try {
            OutputStream out = Files.newOutputStream(jsonFile);
            JsonUtil.createObjectMapper().writer().writeValue(out, monitors);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    public static List<StateMonitor> read(Path jsonFile) {
        try {
            return JsonUtil.createObjectMapper().readerFor(new TypeReference<List<StateMonitor>>() {
            }).readValue(Files.newInputStream(jsonFile));
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }
}