SecurityAnalysisResultEquivalence.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 java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import com.google.common.base.Equivalence;
import com.powsybl.security.LimitViolation;
import com.powsybl.security.PostContingencyComputationStatus;
import com.powsybl.security.results.PostContingencyResult;
import com.powsybl.security.SecurityAnalysisResult;
/**
*
* @author Massimo Ferraro {@literal <massimo.ferraro@techrain.eu>}
*/
public class SecurityAnalysisResultEquivalence extends Equivalence<SecurityAnalysisResult> {
private final double threshold;
private SecurityAnalysisResultComparisonWriter comparisonWriter;
public SecurityAnalysisResultEquivalence(double threshold, Writer writer) {
this.threshold = threshold;
this.comparisonWriter = new SecurityAnalysisResultComparisonWriter(writer);
}
@Override
protected boolean doEquivalent(SecurityAnalysisResult result1, SecurityAnalysisResult result2) {
LimitViolationsResultEquivalence violationsResultEquivalence = new LimitViolationsResultEquivalence(threshold, comparisonWriter);
PostContingencyResultComparator postContingencyResultComparator = new PostContingencyResultComparator();
// compare precontingency results
boolean equivalent = result1.getPreContingencyResult().getStatus() == result2.getPreContingencyResult().getStatus();
equivalent &= violationsResultEquivalence.equivalent(result1.getPreContingencyLimitViolationsResult(), result2.getPreContingencyLimitViolationsResult());
// I still carry on the comparison even if equivalent is already false because I need to print the violations of the post contingency results
// compare postcontingency results
List<PostContingencyResult> postContingencyResults1 = new ArrayList<>(result1.getPostContingencyResults());
List<PostContingencyResult> postContingencyResults2 = new ArrayList<>(result2.getPostContingencyResults());
postContingencyResults1.sort(postContingencyResultComparator);
postContingencyResults2.sort(postContingencyResultComparator);
int index1 = 0;
int index2 = 0;
while (index1 < postContingencyResults1.size() && index2 < postContingencyResults2.size()) {
PostContingencyResult postContingencyResult1 = postContingencyResults1.get(index1);
PostContingencyResult postContingencyResult2 = postContingencyResults2.get(index2);
int postContingencyResultComparison = postContingencyResultComparator.compare(postContingencyResult1, postContingencyResult2);
if (postContingencyResultComparison == 0) { // both results for the same contingency
comparisonWriter.setContingency(postContingencyResult1.getContingency().getId());
equivalent &= violationsResultEquivalence.equivalent(postContingencyResult1.getLimitViolationsResult(), postContingencyResult2.getLimitViolationsResult());
index1++;
index2++;
} else if (postContingencyResultComparison < 0) { // contingency only in result1
equivalent &= onlySmallViolations(postContingencyResult1, false);
index1++;
} else { // contingency only in result2
equivalent &= onlySmallViolations(postContingencyResult2, true);
index2++;
}
}
while (index1 < postContingencyResults1.size()) { // possibly remaining post contingency results in result1
PostContingencyResult postContingencyResult1 = postContingencyResults1.get(index1);
equivalent &= onlySmallViolations(postContingencyResult1, false);
index1++;
}
while (index2 < postContingencyResults2.size()) { // possibly remaining post contingency results in result1
PostContingencyResult postContingencyResult2 = postContingencyResults2.get(index2);
equivalent &= onlySmallViolations(postContingencyResult2, true);
index2++;
}
return equivalent;
}
private boolean onlySmallViolations(PostContingencyResult postContingencyResult, boolean missingResult1) {
comparisonWriter.setContingency(postContingencyResult.getContingency().getId());
boolean equivalent = postContingencyResult.getLimitViolationsResult()
.getLimitViolations()
.stream()
.sorted(new LimitViolationComparator())
.map(violation -> isSmallViolation(violation, missingResult1))
.reduce(Boolean::logicalAnd)
.orElse(false);
comparisonWriter = missingResult1 ?
comparisonWriter.write(null, postContingencyResult.getStatus() == PostContingencyComputationStatus.CONVERGED, equivalent) :
comparisonWriter.write(postContingencyResult.getStatus() == PostContingencyComputationStatus.CONVERGED, null, equivalent);
comparisonWriter = missingResult1 ?
comparisonWriter.write(null, postContingencyResult.getLimitViolationsResult().getActionsTaken(), equivalent) :
comparisonWriter.write(postContingencyResult.getLimitViolationsResult().getActionsTaken(), null, equivalent);
return equivalent;
}
private boolean isSmallViolation(LimitViolation violation, boolean missingResult1) {
boolean smallViolation = Math.abs(violation.getValue() - (violation.getLimit() * violation.getLimitReduction())) <= threshold;
comparisonWriter = missingResult1 ? comparisonWriter.write(null, violation, smallViolation) : comparisonWriter.write(violation, null, smallViolation);
return smallViolation;
}
@Override
protected int doHash(SecurityAnalysisResult result) {
return Objects.hashCode(result);
}
}