LoadFlowResultImpl.java
/**
* Copyright (c) 2016, RTE (http://www.rte-france.com)
* Copyright (c) 2023, Coreso SA (https://www.coreso.eu/) and TSCNET Services GmbH (https://www.tscnet.eu/)
* 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.loadflow;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* @author Christian Biasuzzi {@literal <christian.biasuzzi@techrain.eu>}
* @author Damien Jeandemange {@literal <damien.jeandemange at artelys.com>}
*/
public class LoadFlowResultImpl implements LoadFlowResult {
public static class SlackBusResultImpl implements SlackBusResult {
private final String id;
private final double activePowerMismatch;
public SlackBusResultImpl(String id, double activePowerMismatch) {
this.id = Objects.requireNonNull(id);
this.activePowerMismatch = activePowerMismatch;
}
@Override
public String getId() {
return id;
}
@Override
public double getActivePowerMismatch() {
return activePowerMismatch;
}
}
public static class ComponentResultImpl implements ComponentResult {
private final int connectedComponentNum;
private final int synchronousComponentNum;
private final Status status;
private final String statusText;
private final Map<String, String> metrics;
private final int iterationCount;
private final String referenceBusId;
private final List<SlackBusResult> slackBusResults;
private final double distributedActivePower;
public ComponentResultImpl(int connectedComponentNum, int synchronousComponentNum, Status status, int iterationCount,
String slackBusId, double slackBusActivePowerMismatch, double distributedActivePower) {
this.connectedComponentNum = checkComponentNum(connectedComponentNum);
this.synchronousComponentNum = checkComponentNum(synchronousComponentNum);
this.status = Objects.requireNonNull(status);
this.statusText = status.name();
this.metrics = Collections.emptyMap();
this.iterationCount = checkIterationCount(iterationCount);
this.referenceBusId = slackBusId;
this.slackBusResults = Collections.singletonList(new SlackBusResultImpl(slackBusId, slackBusActivePowerMismatch));
this.distributedActivePower = distributedActivePower;
}
public ComponentResultImpl(int connectedComponentNum, int synchronousComponentNum, Status status,
String statusText, Map<String, String> metrics, int iterationCount,
String referenceBusId, List<SlackBusResult> slackBusResults,
double distributedActivePower) {
this.connectedComponentNum = checkComponentNum(connectedComponentNum);
this.synchronousComponentNum = checkComponentNum(synchronousComponentNum);
this.status = Objects.requireNonNull(status);
this.statusText = Objects.requireNonNullElse(statusText, status.name());
this.metrics = Objects.requireNonNull(metrics);
this.iterationCount = checkIterationCount(iterationCount);
this.referenceBusId = referenceBusId; // allowed to be null
this.slackBusResults = Objects.requireNonNull(slackBusResults);
this.distributedActivePower = distributedActivePower;
}
private static int checkComponentNum(int componentNum) {
if (componentNum < 0) {
throw new IllegalArgumentException("Invalid component number: " + componentNum);
}
return componentNum;
}
private static int checkIterationCount(int iterationCount) {
if (iterationCount < 0) { // 0 is ok if not relevant for a particular implementation
throw new IllegalArgumentException("Invalid iteration count: " + iterationCount);
}
return iterationCount;
}
@Override
public int getConnectedComponentNum() {
return connectedComponentNum;
}
@Override
public int getSynchronousComponentNum() {
return synchronousComponentNum;
}
@Override
public Status getStatus() {
return status;
}
@Override
public String getStatusText() {
return statusText;
}
@Override
public Map<String, String> getMetrics() {
return metrics;
}
@Override
public int getIterationCount() {
return iterationCount;
}
@Override
public String getReferenceBusId() {
return referenceBusId;
}
@Override
public List<SlackBusResult> getSlackBusResults() {
return Collections.unmodifiableList(slackBusResults);
}
@Override
public String getSlackBusId() {
if (slackBusResults.isEmpty()) {
return "";
} else if (slackBusResults.size() == 1) {
return slackBusResults.get(0).getId();
} else {
throw new IllegalStateException("Deprecated method: cannot return a value in the case of multiple slack results. Please migrate to new API.");
}
}
@Override
public double getSlackBusActivePowerMismatch() {
if (slackBusResults.isEmpty()) {
return 0;
} else if (slackBusResults.size() == 1) {
return slackBusResults.get(0).getActivePowerMismatch();
} else {
throw new IllegalStateException("Deprecated method: cannot return a value in the case of multiple slack results. Please migrate to new API.");
}
}
@Override
public double getDistributedActivePower() {
return distributedActivePower;
}
}
private final boolean ok;
private final Status status;
private final Map<String, String> metrics;
private final String logs;
private final List<ComponentResult> componentResults;
public LoadFlowResultImpl(boolean ok, Map<String, String> metrics, String logs) {
this(ok, metrics, logs, Collections.emptyList());
}
public LoadFlowResultImpl(boolean ok, Map<String, String> metrics, String logs, List<ComponentResult> componentResults) {
this.ok = ok;
this.metrics = Objects.requireNonNull(metrics);
this.logs = logs;
this.componentResults = Objects.requireNonNull(componentResults);
this.status = computeStatus(componentResults);
}
private Status computeStatus(List<ComponentResult> componentResults) {
int convergedCount = 0;
int maxIterOrFailedCount = 0;
for (ComponentResult componentResult : componentResults) {
ComponentResult.Status componentResultStatus = Objects.requireNonNull(componentResult.getStatus());
if (componentResultStatus == ComponentResult.Status.CONVERGED) {
convergedCount++;
} else if (componentResultStatus == ComponentResult.Status.MAX_ITERATION_REACHED || componentResultStatus == ComponentResult.Status.FAILED) {
maxIterOrFailedCount++;
}
}
if (convergedCount == 0) {
return Status.FAILED;
} else if (maxIterOrFailedCount > 0) {
return Status.PARTIALLY_CONVERGED;
} else {
return Status.FULLY_CONVERGED;
}
}
@Override
public boolean isOk() {
return ok;
}
@Override
public Status getStatus() {
return status;
}
@Override
public Map<String, String> getMetrics() {
return metrics;
}
@Override
public String getLogs() {
return logs;
}
@Override
public List<ComponentResult> getComponentResults() {
return Collections.unmodifiableList(componentResults);
}
}