RaoUtils.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.tests.utils;
import com.powsybl.glsk.commons.ZonalData;
import com.powsybl.iidm.network.*;
import com.powsybl.openrao.commons.Unit;
import com.powsybl.openrao.data.crac.api.Crac;
import com.powsybl.openrao.data.crac.api.InstantKind;
import com.powsybl.openrao.data.crac.api.cnec.FlowCnec;
import com.powsybl.openrao.data.crac.loopflowextension.LoopFlowThresholdAdder;
import com.powsybl.openrao.data.raoresult.api.RaoResult;
import com.powsybl.openrao.data.refprog.referenceprogram.ReferenceProgram;
import com.powsybl.openrao.raoapi.Rao;
import com.powsybl.openrao.raoapi.RaoInput;
import com.powsybl.openrao.raoapi.parameters.RaoParameters;
import com.powsybl.sensitivity.SensitivityVariableSet;
import com.powsybl.openrao.tests.steps.CommonTestData;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Optional;
import java.util.Properties;
import static java.lang.String.format;
public final class RaoUtils {
private RaoUtils() {
// should not be instantiated
}
public static void buildLoopFlowExtensions(Crac crac, Network network, double loopflowAsPmaxPercentage) {
if (loopflowAsPmaxPercentage > 0) {
for (FlowCnec cnec : crac.getFlowCnecs(crac.getPreventiveState())) {
Line cnecLine = network.getLine(cnec.getNetworkElement().getId());
// check if the cnec is cross zonal, if yes, apply loopflowAsPmaxPercentage on it
if (cnecLine != null &&
!getTerminalCountry(cnecLine.getTerminal1()).equals(getTerminalCountry(cnecLine.getTerminal2()))) {
cnec.newExtension(LoopFlowThresholdAdder.class).withUnit(Unit.PERCENT_IMAX).withValue(loopflowAsPmaxPercentage / 100.).add();
}
}
}
}
private static Optional<Country> getTerminalCountry(Terminal terminal) {
Optional<Substation> substation = terminal.getVoltageLevel().getSubstation();
if (substation.isPresent()) {
return substation.get().getCountry();
} else {
return Optional.empty();
}
}
public static RaoResult runRao(String contingencyId, InstantKind instantKind, String raoType, Double loopflowAsPmaxPercentage,
Integer timeLimitInSeconds) throws IOException {
RaoParameters raoParameters = CommonTestData.getRaoParameters();
ZonalData<SensitivityVariableSet> glsks = CommonTestData.getLoopflowGlsks();
// Rao with loop-flows
if (raoParameters.getLoopFlowParameters().isPresent() && glsks != null) {
double effectiveLfPercentage = loopflowAsPmaxPercentage == null ? 0.0 : loopflowAsPmaxPercentage;
buildLoopFlowExtensions(CommonTestData.getCrac(), CommonTestData.getNetwork(), effectiveLfPercentage);
}
return runRaoInMemory(Rao.find(raoType), CommonTestData.getNetwork(), CommonTestData.getCrac(), contingencyId, instantKind, glsks, CommonTestData.getReferenceProgram(), raoParameters, timeLimitInSeconds);
}
private static RaoResult runRaoInMemory(Rao.Runner raoRunner, Network network, Crac crac, String contingencyId, InstantKind instantKind,
ZonalData<SensitivityVariableSet> glsks, ReferenceProgram referenceProgram, RaoParameters config,
Integer timeLimitInSeconds) throws IOException {
RaoInput.RaoInputBuilder raoInputBuilder;
if (contingencyId == null) {
if (instantKind == null) {
// Will optimize all the perimeters
raoInputBuilder = RaoInput.build(network, crac);
} else if (crac.getInstant(instantKind).isPreventive()) {
// Will optimize preventive state only
raoInputBuilder = RaoInput.buildWithPreventiveState(network, crac);
} else {
throw new IllegalArgumentException(format("Contingency ID should not be null with instant being %s - only \"Preventive\" is accepted", instantKind));
}
} else {
// Perform a curative optimization only on the specified state
raoInputBuilder = RaoInput.buildWithState(network, crac, crac.getState(crac.getContingency(contingencyId), crac.getInstant(instantKind)));
}
raoInputBuilder.withGlskProvider(glsks);
raoInputBuilder.withRefProg(referenceProgram);
RaoResult raoResult;
if (timeLimitInSeconds != null) {
raoResult = raoRunner.run(raoInputBuilder.build(), config, java.time.Instant.now().plusSeconds(timeLimitInSeconds.longValue()));
} else {
raoResult = raoRunner.run(raoInputBuilder.build(), config);
}
/*
roundTrip on RaoResult
important to keep that here, as the conversion: SearchTreeRaoResult -> jsonFile -> RaoResultImpl cannot be
properly test - on real data - in the unit tests
*/
return roundTripOnRaoResult(raoResult, crac);
}
private static RaoResult roundTripOnRaoResult(RaoResult raoResult, Crac crac) throws IOException {
// export RaoResult
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Properties properties = new Properties();
properties.setProperty("rao-result.export.json.flows-in-amperes", "true");
properties.setProperty("rao-result.export.json.flows-in-megawatts", "true");
raoResult.write("JSON", crac, properties, outputStream);
// import RaoResult
ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
return RaoResult.read(inputStream, crac);
}
}