MonitoringResult.java
/*
* Copyright (c) 2024, 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.monitoring.results;
import com.powsybl.openrao.commons.OpenRaoException;
import com.powsybl.openrao.commons.PhysicalParameter;
import com.powsybl.openrao.data.crac.api.RemedialAction;
import com.powsybl.openrao.data.crac.api.State;
import com.powsybl.openrao.data.crac.api.cnec.Cnec.SecurityStatus;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Mohamed Ben Rejeb {@literal <mohamed.ben-rejeb at rte-france.com>}
*/
public class MonitoringResult {
private PhysicalParameter physicalParameter;
private Set<CnecResult> cnecResults;
private Map<State, Set<RemedialAction>> appliedRas;
private SecurityStatus status;
public MonitoringResult(PhysicalParameter physicalParameter, Set<CnecResult> cnecResults, Map<State, Set<RemedialAction>> appliedRas, SecurityStatus status) {
this.physicalParameter = physicalParameter;
this.cnecResults = cnecResults;
this.appliedRas = appliedRas;
this.status = status;
}
public PhysicalParameter getPhysicalParameter() {
return physicalParameter;
}
public Set<CnecResult> getCnecResults() {
return cnecResults;
}
public Map<State, Set<RemedialAction>> getAppliedRas() {
return appliedRas;
}
public Set<RemedialAction> getAppliedRas(State state) {
return appliedRas.getOrDefault(state, Collections.emptySet());
}
public Set<String> getAppliedRas(String stateId) {
Set<State> states = appliedRas.keySet().stream().filter(s -> s.getId().equals(stateId)).collect(Collectors.toSet());
if (states.isEmpty()) {
return Collections.emptySet();
} else if (states.size() > 1) {
throw new OpenRaoException(String.format("%s states share the same id : %s.", states.size(), stateId));
} else {
return appliedRas.get(states.iterator().next()).stream().map(RemedialAction::getId).collect(Collectors.toSet());
}
}
public SecurityStatus getStatus() {
return status;
}
public List<String> printConstraints() {
if (status.equals(SecurityStatus.FAILURE)) {
return List.of(physicalParameter + " monitoring failed due to a load flow divergence or an inconsistency in the crac or in the parameters.");
}
List<String> constraints = new ArrayList<>();
cnecResults.stream()
.filter(cr -> cr.getMargin() < 0)
.sorted(Comparator.comparing(CnecResult::getId))
.forEach(cnecResult -> constraints.add(cnecResult.print()));
if (constraints.isEmpty()) {
return List.of(String.format("All %s Cnecs are secure.", physicalParameter));
} else {
constraints.add(0, String.format("Some %s Cnecs are not secure:", physicalParameter));
}
return constraints;
}
// Add synchronized in the signature to make the function blocking
// Necessary because in the function runMonitoring this function is called in parallel threads -> can cause overwriting conflict.
public synchronized void combine(MonitoringResult monitoringResult) {
Set<CnecResult> thisCnecResults = new HashSet<>(this.getCnecResults());
Set<CnecResult> otherCnecResults = monitoringResult.getCnecResults();
thisCnecResults.addAll(otherCnecResults);
this.cnecResults = thisCnecResults;
Map<State, Set<RemedialAction>> thisAppliedRas = new HashMap<>(this.getAppliedRas());
Map<State, Set<RemedialAction>> otherAppliedRas = monitoringResult.getAppliedRas();
thisAppliedRas.putAll(otherAppliedRas);
this.appliedRas = thisAppliedRas;
this.status = combineStatuses(this.status, monitoringResult.getStatus());
}
public static SecurityStatus combineStatuses(SecurityStatus... statuses) {
boolean atLeastOneFailed = Arrays.asList(statuses).contains(SecurityStatus.FAILURE);
if (atLeastOneFailed) {
return SecurityStatus.FAILURE;
}
boolean atLeastOneHigh = Arrays.asList(statuses).contains(SecurityStatus.HIGH_CONSTRAINT);
boolean atLeastOneLow = Arrays.asList(statuses).contains(SecurityStatus.LOW_CONSTRAINT);
boolean atLeastOneHighAndLow = Arrays.asList(statuses).contains(SecurityStatus.HIGH_AND_LOW_CONSTRAINTS) || atLeastOneHigh && atLeastOneLow;
if (atLeastOneHighAndLow) {
return SecurityStatus.HIGH_AND_LOW_CONSTRAINTS;
}
if (atLeastOneHigh) {
return SecurityStatus.HIGH_CONSTRAINT;
}
if (atLeastOneLow) {
return SecurityStatus.LOW_CONSTRAINT;
}
return SecurityStatus.SECURE;
}
public void setStatusToFailure() {
this.status = SecurityStatus.FAILURE;
}
}