diff --git a/.gitignore b/.gitignore index fd71e9331b..d3b06d84e5 100755 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ -# ignore Intellij files + + tests/src/test/resources/files/raoresults/*.zip + +# ignore Intellij files .idea *.iml diff --git a/checkstyle.xml b/checkstyle.xml index 2166b2aaa3..2b286f7054 100755 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -1,27 +1,13 @@ + "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN" + "https://checkstyle.org/dtds/configuration_1_3.dtd"> - - - - - - - - - - - - + - - - - - + + @@ -31,11 +17,10 @@ - - + @@ -47,7 +32,7 @@ - + @@ -55,17 +40,13 @@ - - - - - + @@ -76,10 +57,6 @@ - - - - @@ -90,6 +67,10 @@ - + + + + - + + \ No newline at end of file diff --git a/commons/pom.xml b/commons/pom.xml index 82c90937b6..2c681df311 100755 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -74,6 +74,36 @@ slf4j-api + + + io.opentelemetry + opentelemetry-sdk + + + io.opentelemetry + opentelemetry-sdk-logs + + + io.opentelemetry + opentelemetry-sdk-metrics + + + io.opentelemetry + opentelemetry-api + + + io.opentelemetry + opentelemetry-exporter-otlp + + + io.opentelemetry + opentelemetry-exporter-logging + + + io.opentelemetry.instrumentation + opentelemetry-instrumentation-annotations + + ch.qos.logback diff --git a/commons/src/main/java/com/powsybl/openrao/commons/logs/AbstractOpenRaoLogger.java b/commons/src/main/java/com/powsybl/openrao/commons/logs/AbstractOpenRaoLogger.java index 8139fce6b0..f425a6ee57 100644 --- a/commons/src/main/java/com/powsybl/openrao/commons/logs/AbstractOpenRaoLogger.java +++ b/commons/src/main/java/com/powsybl/openrao/commons/logs/AbstractOpenRaoLogger.java @@ -7,6 +7,7 @@ package com.powsybl.openrao.commons.logs; +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,27 +19,27 @@ public abstract class AbstractOpenRaoLogger implements OpenRaoLogger { @Override public void trace(String format, Object... arguments) { - logger.trace(format, arguments); + OpenTelemetryReporter.trace(logger, format, arguments); } @Override public void info(String format, Object... arguments) { - logger.info(format, arguments); + OpenTelemetryReporter.info(logger, format, arguments); } @Override public void warn(String format, Object... arguments) { - logger.warn(format, arguments); + OpenTelemetryReporter.warn(logger, format, arguments); } @Override public void error(String format, Object... arguments) { - logger.error(format, arguments); + OpenTelemetryReporter.error(logger, format, arguments); } @Override public void debug(String format, Object... arguments) { - logger.debug(format, arguments); + OpenTelemetryReporter.debug(logger, format, arguments); } @Override diff --git a/commons/src/main/java/com/powsybl/openrao/commons/opentelemetry/OpenTelemetryContext.java b/commons/src/main/java/com/powsybl/openrao/commons/opentelemetry/OpenTelemetryContext.java new file mode 100644 index 0000000000..4b455be308 --- /dev/null +++ b/commons/src/main/java/com/powsybl/openrao/commons/opentelemetry/OpenTelemetryContext.java @@ -0,0 +1,63 @@ +/* + * 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/. + */ + +package com.powsybl.openrao.commons.opentelemetry; + +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import java.util.Optional; +import javax.annotation.Nullable; + +/** + * @author Fabrice Buscaylet {@literal } + */ +public class OpenTelemetryContext { + + private final Optional span; + private final Optional context; + + public OpenTelemetryContext(Tracer tracer, String spanName) { + var hasTracer = tracer != null; + if (hasTracer) { + var newSpan = tracer.spanBuilder(spanName).startSpan(); + this.context = Optional.of(newSpan.storeInContext(Context.current())); + this.span = Optional.of(newSpan); + } else { + this.span = Optional.empty(); + this.context = Optional.empty(); + } + } + + @Nullable + public Scope makeCurrent() { + return context.map(Context::makeCurrent).orElse(null); + } + + public void addEvent(String name) { + span.ifPresent(s -> s.addEvent(name)); + } + + public void setStatus(StatusCode statusCode) { + span.ifPresent(s -> s.setStatus(statusCode)); + } + + public void setStatus(StatusCode statusCode, String description) { + span.ifPresent(s -> s.setStatus(statusCode, description)); + } + + public void end() { + span.ifPresent(Span::end); + } + + public void recordException(Exception e) { + span.ifPresent(s -> s.recordException(e)); + } + +} diff --git a/commons/src/main/java/com/powsybl/openrao/commons/opentelemetry/OpenTelemetryReporter.java b/commons/src/main/java/com/powsybl/openrao/commons/opentelemetry/OpenTelemetryReporter.java new file mode 100644 index 0000000000..e01c292a74 --- /dev/null +++ b/commons/src/main/java/com/powsybl/openrao/commons/opentelemetry/OpenTelemetryReporter.java @@ -0,0 +1,236 @@ +/* + * 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/. + */ + +package com.powsybl.openrao.commons.opentelemetry; + +import com.powsybl.openrao.commons.OpenRaoException; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import java.util.Collection; +import java.util.concurrent.Callable; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.helpers.MessageFormatter; + +/** + * @author Fabrice Buscaylet {@literal } + */ +public final class OpenTelemetryReporter { + + protected static final String OPEN_RAO = "open-rao"; + protected static final String VERSION = "1.0.0"; + + /** + * The open telemetry tracer + */ + private static Tracer TRACER; + private static boolean TRACE_ALL_LOGS = false; + + /** + * Logger for the spans creation + */ + private static final Logger LOGGER = LoggerFactory.getLogger(OpenTelemetryReporter.class); + + /** + * Private constructor + */ + private OpenTelemetryReporter() { + } + + /** + * Initializes the OpenTelemetry SDK with a simple logging exporter. In a production + * environment, you would use an exporter like OTLP to send data to a backend (e.g., Jaeger, + * Prometheus, etc.). + * + * @param endPoint the Open Telemetry trace collector (ex: '...') + * @param service the service name for traces + * @param version the version of the service for traces + */ + public static void initOpenTelemetry(String endPoint, String service, String version) { + + OtlpGrpcSpanExporter otlpGrpcSpanExporter = OtlpGrpcSpanExporter.builder() + .setEndpoint(endPoint).build(); + + SdkTracerProvider tracerProvider = SdkTracerProvider.builder() + .addSpanProcessor(BatchSpanProcessor.builder(otlpGrpcSpanExporter).build()) + .setResource(Resource.getDefault().merge( + Resource.builder() + .put("service.name", service != null ? service : OPEN_RAO) + .put("service.version", version != null ? version : VERSION).build() + )).build(); + OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).buildAndRegisterGlobal(); + TRACER = tracerProvider.get(OPEN_RAO); + } + + /** + * Set the open telemetry tracer used to trace open-rao + * + * @param tracerProvider + */ + public static void setOpenTelemetryTracer(SdkTracerProvider tracerProvider, + boolean traceAllLogs) { + TRACE_ALL_LOGS = traceAllLogs; + var hasProvider = tracerProvider != null; + TRACER = + hasProvider ? tracerProvider.get(OPEN_RAO) : GlobalOpenTelemetry.getTracer(OPEN_RAO); + } + + @SuppressWarnings("unused") + private static SpanExporter getStdIoSpanExporter() { + return new SpanExporter() { + @Override + public CompletableResultCode export(Collection collection) { + for (SpanData spanData : collection) { + LOGGER.info("[{}] >> {}\t{}\t{}\t{} ms", spanData.getParentSpanId(), + spanData.getSpanId(), spanData.getName(), spanData.getStatus(), Math.ceil( + (double) (spanData.getEndEpochNanos() - spanData.getStartEpochNanos()) + / 1000000)); + } + return null; + } + + @Override + public CompletableResultCode flush() { + return null; + } + + @Override + public CompletableResultCode shutdown() { + return null; + } + }; + } + + @FunctionalInterface + public interface ThrowingFunction { + + R apply(T t) throws Exception; + } + + @FunctionalInterface + public interface ThrowingConsumer { + + void accept(T t) throws Exception; + } + + /** + * A generic utility method to wrap a method call with a span. This method handles span + * creation, context management, and error handling. + * + * @param spanName The name of the span to create. + * @param runnable The operation to execute, wrapped in a Callable. + * @param The return type of the Callable. + * @return The result of the Callable. + * @throws Exception if the Callable throws an exception. + */ + public static T withSpan(String spanName, + ThrowingFunction runnable) { + return doWithSpan(spanName, runnable); + } + + /** + * An overloaded utility method for methods that return void. + * + * @param spanName The name of the span to create. + * @param runnable The operation to execute, wrapped in a Runnable. + */ + public static void withSpan(String spanName, ThrowingConsumer runnable) { + doWithSpan(spanName, ctx -> { + runnable.accept(ctx); + return null; + }); + } + + protected static T doWithSpan(String spanName, + ThrowingFunction callable) { + var ctx = new OpenTelemetryContext(TRACER, spanName); + try { + ctx.addEvent("Executing operation: " + spanName); + T result = callable.apply(ctx); + ctx.setStatus(StatusCode.OK); + return result; + } catch (Exception e) { + ctx.setStatus(StatusCode.ERROR, "Operation failed: " + e); + ctx.recordException(e); + throw new OpenRaoException(e.getMessage()); + } finally { + ctx.end(); + } + } + + /** + * Runs the given task in an existing Open Telemetry Context, i.e. withSpan() has been called + * before This is necessary when running tasks in different Threads (e.g. using ForkJoinTask) + * + * @param cx + * @param task + */ + public static T inContext(OpenTelemetryContext cx, Callable task) + throws Exception { + try (var scope = cx.makeCurrent()) { + return task.call(); + } + } + + public static void inContext(OpenTelemetryContext cx, Runnable task) { + try (var scope = cx.makeCurrent()) { + task.run(); + } + } + + public static void trace(Logger logger, String format, Object... arguments) { + doLog(logger.isTraceEnabled(), logger::trace, format, arguments); + } + + public static void info(Logger logger, String format, Object... arguments) { + doLog(logger.isInfoEnabled(), logger::info, format, arguments); + } + + public static void warn(Logger logger, String format, Object... arguments) { + doLog(logger.isWarnEnabled(), logger::warn, format, arguments); + } + + public static void error(Logger logger, String format, Object... arguments) { + doLog(logger.isErrorEnabled(), logger::error, format, arguments); + } + + public static void debug(Logger logger, String format, Object... arguments) { + doLog(logger.isDebugEnabled(), logger::debug, format, arguments); + } + + private static void doLog(boolean loggerEnabled, Consumer logWriter, String format, + Object... arguments) { + if (!loggerEnabled) { + return; + } + var msg = format(format, arguments); + if (TRACE_ALL_LOGS) { + OpenTelemetryReporter.withSpan(msg, cx -> { + logWriter.accept(msg); + }); + } else { + logWriter.accept(msg); + } + } + + private static String format(String pattern, Object[] args) { + // Use the SLF4J MessageFormatter's arrayFormat method + return MessageFormatter.arrayFormat(pattern, args).getMessage(); + } + +} diff --git a/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/crac/io/json/JsonExport.java b/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/crac/io/json/JsonExport.java index a38af124f2..29c86d2e07 100644 --- a/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/crac/io/json/JsonExport.java +++ b/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/crac/io/json/JsonExport.java @@ -7,21 +7,21 @@ package com.powsybl.openrao.data.crac.io.json; -import com.powsybl.openrao.data.crac.io.json.serializers.CracJsonSerializerModule; -import com.powsybl.openrao.data.crac.api.Crac; -import com.powsybl.openrao.data.crac.api.io.Exporter; +import static com.powsybl.commons.json.JsonUtil.createObjectMapper; + import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.module.SimpleModule; import com.google.auto.service.AutoService; - +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; +import com.powsybl.openrao.data.crac.api.Crac; +import com.powsybl.openrao.data.crac.api.io.Exporter; +import com.powsybl.openrao.data.crac.io.json.serializers.CracJsonSerializerModule; import java.io.IOException; import java.io.OutputStream; import java.io.UncheckedIOException; -import static com.powsybl.commons.json.JsonUtil.createObjectMapper; - /** * CRAC object export in json format * @@ -39,15 +39,18 @@ public String getFormat() { @Override public void exportData(Crac crac, OutputStream outputStream) { - try { - ObjectMapper objectMapper = createObjectMapper(); - objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - SimpleModule module = new CracJsonSerializerModule(); - objectMapper.registerModule(module); - ObjectWriter writer = objectMapper.writerWithDefaultPrettyPrinter(); - writer.writeValue(outputStream, crac); - } catch (IOException e) { - throw new UncheckedIOException(e); - } + OpenTelemetryReporter.withSpan("rao.exportJsonCrac", cx -> { + try { + ObjectMapper objectMapper = createObjectMapper(); + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + SimpleModule module = new CracJsonSerializerModule(); + objectMapper.registerModule(module); + ObjectWriter writer = objectMapper.writerWithDefaultPrettyPrinter(); + writer.writeValue(outputStream, crac); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); } } + diff --git a/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/crac/io/json/JsonImport.java b/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/crac/io/json/JsonImport.java index 7cdbfe0c61..6834e31d0a 100644 --- a/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/crac/io/json/JsonImport.java +++ b/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/crac/io/json/JsonImport.java @@ -7,18 +7,24 @@ package com.powsybl.openrao.data.crac.io.json; +import static com.powsybl.commons.json.JsonUtil.createObjectMapper; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.TECHNICAL_LOGS; +import static com.powsybl.openrao.data.crac.io.json.JsonSchemaProvider.getSchema; +import static com.powsybl.openrao.data.crac.io.json.JsonSchemaProvider.getValidationErrors; +import static com.powsybl.openrao.data.crac.io.json.JsonSchemaProvider.isCracFile; + import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.google.auto.service.AutoService; import com.networknt.schema.JsonSchema; import com.powsybl.iidm.network.Network; import com.powsybl.openrao.commons.OpenRaoException; +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; import com.powsybl.openrao.data.crac.api.Crac; import com.powsybl.openrao.data.crac.api.CracCreationContext; import com.powsybl.openrao.data.crac.api.io.Importer; import com.powsybl.openrao.data.crac.api.parameters.CracCreationParameters; import com.powsybl.openrao.data.crac.io.json.deserializers.CracDeserializer; - import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -28,18 +34,13 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import static com.powsybl.commons.json.JsonUtil.createObjectMapper; -import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.TECHNICAL_LOGS; -import static com.powsybl.openrao.data.crac.io.json.JsonSchemaProvider.getSchema; -import static com.powsybl.openrao.data.crac.io.json.JsonSchemaProvider.getValidationErrors; -import static com.powsybl.openrao.data.crac.io.json.JsonSchemaProvider.isCracFile; - /** * @author Viktor Terrier {@literal } * @author Peter Mitri {@literal } */ @AutoService(Importer.class) public class JsonImport implements Importer { + @Override public String getFormat() { return "JSON"; @@ -51,52 +52,67 @@ public boolean exists(String filename, InputStream inputStream) { return false; } try { - ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(inputStream.readAllBytes()); + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + inputStream.readAllBytes()); if (isCracFile(byteArrayInputStream)) { byteArrayInputStream.reset(); Version cracVersion = readVersion(byteArrayInputStream); JsonSchema jsonSchema = getSchema(cracVersion); - List validationError = getValidationErrors(jsonSchema, byteArrayInputStream); + List validationError = getValidationErrors(jsonSchema, + byteArrayInputStream); if (validationError.isEmpty()) { return true; } - throw new OpenRaoException("JSON file is not a valid CRAC v%s.%s. Reasons: %s".formatted(cracVersion.majorVersion(), cracVersion.minorVersion(), String.join("; ", validationError))); + throw new OpenRaoException( + "JSON file is not a valid CRAC v%s.%s. Reasons: %s".formatted( + cracVersion.majorVersion(), cracVersion.minorVersion(), + String.join("; ", validationError))); } return false; } catch (IOException e) { - TECHNICAL_LOGS.debug("JSON file could not be processed as CRAC. Reason: {}", e.getMessage()); + TECHNICAL_LOGS.debug("JSON file could not be processed as CRAC. Reason: {}", + e.getMessage()); return false; } } @Override - public CracCreationContext importData(InputStream inputStream, CracCreationParameters cracCreationParameters, Network network) { - if (network == null) { - throw new OpenRaoException("Network object is null but it is needed to map contingency's elements"); - } - try { - ObjectMapper objectMapper = createObjectMapper(); - SimpleModule module = new SimpleModule(); - module.addDeserializer(Crac.class, new CracDeserializer(cracCreationParameters.getCracFactory(), network)); - objectMapper.registerModule(module); - Crac crac = objectMapper.readValue(inputStream, Crac.class); - CracCreationContext cracCreationContext = new JsonCracCreationContext(true, crac, network.getNameOrId()); - return cracCreationContext; - } catch (IOException e) { - throw new UncheckedIOException(e); - } catch (OpenRaoException e) { - CracCreationContext cracCreationContext = new JsonCracCreationContext(false, null, network.getNameOrId()); - cracCreationContext.getCreationReport().error(e.getMessage()); - return cracCreationContext; - } + public CracCreationContext importData(InputStream inputStream, + CracCreationParameters cracCreationParameters, Network network) { + return OpenTelemetryReporter.withSpan("rao.importJsonCrac", cx -> { + if (network == null) { + throw new OpenRaoException( + "Network object is null but it is needed to map contingency's elements"); + } + try { + ObjectMapper objectMapper = createObjectMapper(); + SimpleModule module = new SimpleModule(); + module.addDeserializer(Crac.class, + new CracDeserializer(cracCreationParameters.getCracFactory(), network)); + objectMapper.registerModule(module); + Crac crac = objectMapper.readValue(inputStream, Crac.class); + CracCreationContext cracCreationContext = new JsonCracCreationContext(true, crac, + network.getNameOrId()); + return cracCreationContext; + } catch (IOException e) { + throw new UncheckedIOException(e); + } catch (OpenRaoException e) { + CracCreationContext cracCreationContext = new JsonCracCreationContext(false, null, + network.getNameOrId()); + cracCreationContext.getCreationReport().error(e.getMessage()); + return cracCreationContext; + } + }); } private static Version readVersion(ByteArrayInputStream cracByteArrayInputStream) { - String cracContent = new String(cracByteArrayInputStream.readAllBytes(), StandardCharsets.UTF_8); + String cracContent = new String(cracByteArrayInputStream.readAllBytes(), + StandardCharsets.UTF_8); cracByteArrayInputStream.reset(); Pattern versionPattern = Pattern.compile("\"version\"\\s?:\\s?\"([1-9]\\d*)\\.(\\d+)\""); Matcher versionMatcher = versionPattern.matcher(cracContent); versionMatcher.find(); - return new Version(Integer.parseInt(versionMatcher.group(1)), Integer.parseInt(versionMatcher.group(2))); + return new Version(Integer.parseInt(versionMatcher.group(1)), + Integer.parseInt(versionMatcher.group(2))); } } diff --git a/data/rao-result/rao-result-io/rao-result-json/src/main/java/com/powsybl/openrao/data/raoresult/io/json/RaoResultJsonExporter.java b/data/rao-result/rao-result-io/rao-result-json/src/main/java/com/powsybl/openrao/data/raoresult/io/json/RaoResultJsonExporter.java index 6cad6fcbaa..a5cff473c8 100644 --- a/data/rao-result/rao-result-io/rao-result-json/src/main/java/com/powsybl/openrao/data/raoresult/io/json/RaoResultJsonExporter.java +++ b/data/rao-result/rao-result-io/rao-result-json/src/main/java/com/powsybl/openrao/data/raoresult/io/json/RaoResultJsonExporter.java @@ -7,20 +7,20 @@ package com.powsybl.openrao.data.raoresult.io.json; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.module.SimpleModule; import com.google.auto.service.AutoService; +import com.powsybl.commons.json.JsonUtil; import com.powsybl.openrao.commons.OpenRaoException; import com.powsybl.openrao.commons.Unit; +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; import com.powsybl.openrao.data.crac.api.Crac; import com.powsybl.openrao.data.crac.api.CracCreationContext; import com.powsybl.openrao.data.crac.io.json.JsonCracCreationContext; -import com.powsybl.openrao.data.raoresult.api.io.Exporter; import com.powsybl.openrao.data.raoresult.api.RaoResult; +import com.powsybl.openrao.data.raoresult.api.io.Exporter; import com.powsybl.openrao.data.raoresult.io.json.serializers.RaoResultJsonSerializerModule; -import com.powsybl.commons.json.JsonUtil; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectWriter; -import com.fasterxml.jackson.databind.module.SimpleModule; - import java.io.IOException; import java.io.OutputStream; import java.io.UncheckedIOException; @@ -45,6 +45,7 @@ */ @AutoService(Exporter.class) public class RaoResultJsonExporter implements Exporter { + private static final String JSON_EXPORT_PROPERTIES_PREFIX = "rao-result.export.json."; private static final String FLOWS_IN_AMPERES = "flows-in-amperes"; private static final String FLOWS_IN_MEGAWATTS = "flows-in-megawatts"; @@ -65,33 +66,43 @@ public Class getCracCreationContextClass() { } @Override - public void exportData(RaoResult raoResult, CracCreationContext cracCreationContext, Properties properties, OutputStream outputStream) { + public void exportData(RaoResult raoResult, CracCreationContext cracCreationContext, + Properties properties, OutputStream outputStream) { validateDataToExport(cracCreationContext, properties); exportData(raoResult, cracCreationContext.getCrac(), properties, outputStream); } @Override - public void exportData(RaoResult raoResult, Crac crac, Properties properties, OutputStream outputStream) { - boolean flowsInAmperes = Boolean.parseBoolean(properties.getProperty(JSON_EXPORT_PROPERTIES_PREFIX + FLOWS_IN_AMPERES, "false")); - boolean flowsInMegawatts = Boolean.parseBoolean(properties.getProperty(JSON_EXPORT_PROPERTIES_PREFIX + FLOWS_IN_MEGAWATTS, "false")); - if (!flowsInAmperes && !flowsInMegawatts) { - throw new OpenRaoException("At least one flow unit should be used. Please provide %s and/or %s in the properties.".formatted(JSON_EXPORT_PROPERTIES_PREFIX + FLOWS_IN_AMPERES, JSON_EXPORT_PROPERTIES_PREFIX + FLOWS_IN_MEGAWATTS)); - } - Set flowUnits = new HashSet<>(); - if (flowsInAmperes) { - flowUnits.add(Unit.AMPERE); - } - if (flowsInMegawatts) { - flowUnits.add(Unit.MEGAWATT); - } - try { - ObjectMapper objectMapper = JsonUtil.createObjectMapper(); - SimpleModule module = new RaoResultJsonSerializerModule(crac, flowUnits); - objectMapper.registerModule(module); - ObjectWriter writer = objectMapper.writerWithDefaultPrettyPrinter(); - writer.writeValue(outputStream, raoResult); - } catch (IOException e) { - throw new UncheckedIOException(e); - } + public void exportData(RaoResult raoResult, Crac crac, Properties properties, + OutputStream outputStream) { + OpenTelemetryReporter.withSpan("rao.exportJsonCrac", cx -> { + boolean flowsInAmperes = Boolean.parseBoolean( + properties.getProperty(JSON_EXPORT_PROPERTIES_PREFIX + FLOWS_IN_AMPERES, "false")); + boolean flowsInMegawatts = Boolean.parseBoolean( + properties.getProperty(JSON_EXPORT_PROPERTIES_PREFIX + FLOWS_IN_MEGAWATTS, + "false")); + if (!flowsInAmperes && !flowsInMegawatts) { + throw new OpenRaoException( + "At least one flow unit should be used. Please provide %s and/or %s in the properties.".formatted( + JSON_EXPORT_PROPERTIES_PREFIX + FLOWS_IN_AMPERES, + JSON_EXPORT_PROPERTIES_PREFIX + FLOWS_IN_MEGAWATTS)); + } + Set flowUnits = new HashSet<>(); + if (flowsInAmperes) { + flowUnits.add(Unit.AMPERE); + } + if (flowsInMegawatts) { + flowUnits.add(Unit.MEGAWATT); + } + try { + ObjectMapper objectMapper = JsonUtil.createObjectMapper(); + SimpleModule module = new RaoResultJsonSerializerModule(crac, flowUnits); + objectMapper.registerModule(module); + ObjectWriter writer = objectMapper.writerWithDefaultPrettyPrinter(); + writer.writeValue(outputStream, raoResult); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); } } diff --git a/data/rao-result/rao-result-io/rao-result-json/src/main/java/com/powsybl/openrao/data/raoresult/io/json/RaoResultJsonImporter.java b/data/rao-result/rao-result-io/rao-result-json/src/main/java/com/powsybl/openrao/data/raoresult/io/json/RaoResultJsonImporter.java index d8da354b81..3964069d0e 100644 --- a/data/rao-result/rao-result-io/rao-result-json/src/main/java/com/powsybl/openrao/data/raoresult/io/json/RaoResultJsonImporter.java +++ b/data/rao-result/rao-result-io/rao-result-json/src/main/java/com/powsybl/openrao/data/raoresult/io/json/RaoResultJsonImporter.java @@ -7,26 +7,27 @@ package com.powsybl.openrao.data.raoresult.io.json; +import static com.powsybl.commons.json.JsonUtil.createObjectMapper; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; import com.google.auto.service.AutoService; import com.powsybl.openrao.commons.OpenRaoException; +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; import com.powsybl.openrao.data.crac.api.Crac; -import com.powsybl.openrao.data.raoresult.api.io.Importer; import com.powsybl.openrao.data.raoresult.api.RaoResult; +import com.powsybl.openrao.data.raoresult.api.io.Importer; import com.powsybl.openrao.data.raoresult.io.json.deserializers.RaoResultDeserializer; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; - import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; -import static com.powsybl.commons.json.JsonUtil.createObjectMapper; - /** * @author Baptiste Seguinot {@literal } */ @AutoService(Importer.class) public class RaoResultJsonImporter implements Importer { + @Override public String getFormat() { return "JSON"; @@ -49,14 +50,16 @@ public boolean exists(InputStream inputStream) { @Override public RaoResult importData(InputStream inputStream, Crac crac) { - try { - ObjectMapper objectMapper = createObjectMapper(); - SimpleModule module = new SimpleModule(); - module.addDeserializer(RaoResult.class, new RaoResultDeserializer(crac)); - objectMapper.registerModule(module); - return objectMapper.readValue(inputStream, RaoResult.class); - } catch (IOException e) { - throw new UncheckedIOException(e); - } + return OpenTelemetryReporter.withSpan("rao.importJsonRaoResult", cx -> { + try { + ObjectMapper objectMapper = createObjectMapper(); + SimpleModule module = new SimpleModule(); + module.addDeserializer(RaoResult.class, new RaoResultDeserializer(crac)); + objectMapper.registerModule(module); + return objectMapper.readValue(inputStream, RaoResult.class); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); } } diff --git a/monitoring/src/main/java/com/powsybl/openrao/monitoring/Monitoring.java b/monitoring/src/main/java/com/powsybl/openrao/monitoring/Monitoring.java index ec287bb64e..a546b1e8f6 100644 --- a/monitoring/src/main/java/com/powsybl/openrao/monitoring/Monitoring.java +++ b/monitoring/src/main/java/com/powsybl/openrao/monitoring/Monitoring.java @@ -7,13 +7,28 @@ package com.powsybl.openrao.monitoring; -import com.powsybl.action.*; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_LOGS; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_WARNS; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.TECHNICAL_LOGS; + +import com.powsybl.action.Action; +import com.powsybl.action.DanglingLineAction; +import com.powsybl.action.GeneratorAction; +import com.powsybl.action.LoadAction; +import com.powsybl.action.ShuntCompensatorPositionAction; import com.powsybl.computation.ComputationManager; import com.powsybl.contingency.Contingency; import com.powsybl.glsk.commons.CountryEICode; import com.powsybl.glsk.commons.ZonalData; import com.powsybl.iidm.modification.scalable.Scalable; -import com.powsybl.iidm.network.*; +import com.powsybl.iidm.network.Country; +import com.powsybl.iidm.network.Generator; +import com.powsybl.iidm.network.Identifiable; +import com.powsybl.iidm.network.IdentifiableType; +import com.powsybl.iidm.network.Injection; +import com.powsybl.iidm.network.Load; +import com.powsybl.iidm.network.Network; +import com.powsybl.iidm.network.Substation; import com.powsybl.loadflow.LoadFlow; import com.powsybl.loadflow.LoadFlowParameters; import com.powsybl.loadflow.LoadFlowResult; @@ -21,6 +36,7 @@ import com.powsybl.openrao.commons.OpenRaoException; import com.powsybl.openrao.commons.PhysicalParameter; import com.powsybl.openrao.commons.Unit; +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; import com.powsybl.openrao.data.crac.api.Crac; import com.powsybl.openrao.data.crac.api.RemedialAction; import com.powsybl.openrao.data.crac.api.State; @@ -32,18 +48,28 @@ import com.powsybl.openrao.data.crac.impl.VoltageCnecValue; import com.powsybl.openrao.data.raoresult.api.RaoResult; import com.powsybl.openrao.monitoring.redispatching.RedispatchAction; -import com.powsybl.openrao.monitoring.results.*; +import com.powsybl.openrao.monitoring.results.CnecResult; +import com.powsybl.openrao.monitoring.results.MonitoringResult; +import com.powsybl.openrao.monitoring.results.RaoResultWithAngleMonitoring; +import com.powsybl.openrao.monitoring.results.RaoResultWithVoltageMonitoring; import com.powsybl.openrao.util.AbstractNetworkPool; - -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.ExecutionException; import java.util.concurrent.ForkJoinTask; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.*; -import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.TECHNICAL_LOGS; - /** * @author Godelaine de Montmorillon {@literal } * @author Peter Mitri {@literal } @@ -63,10 +89,12 @@ public Monitoring(String loadFlowProvider, LoadFlowParameters loadFlowParameters } /** - * The computation manager can be used by the caller to execute actions before and/or after running the loadflow. - * In particular, GridCapa relies on it to inject task-id in the MDC in order to bind logs with tasks. + * The computation manager can be used by the caller to execute actions before and/or after + * running the loadflow. In particular, GridCapa relies on it to inject task-id in the MDC in + * order to bind logs with tasks. */ - public Monitoring(String loadFlowProvider, LoadFlowParameters loadFlowParameters, ComputationManager computationManager) { + public Monitoring(String loadFlowProvider, LoadFlowParameters loadFlowParameters, + ComputationManager computationManager) { this(loadFlowProvider, loadFlowParameters); this.loadFlowRunParameters.setComputationManager(computationManager); } @@ -75,145 +103,191 @@ public Monitoring(String loadFlowProvider, LoadFlowParameters loadFlowParameters * Main function : runs AngleMonitoring computation on all AngleCnecs defined in the CRAC. * Returns an RaoResult enhanced with AngleMonitoringResult */ - public static RaoResult runAngleAndUpdateRaoResult(String loadFlowProvider, LoadFlowParameters loadFlowParameters, int numberOfLoadFlowsInParallel, MonitoringInput monitoringInput) throws OpenRaoException { - final MonitoringResult angleMonitoringResult = new Monitoring(loadFlowProvider, loadFlowParameters).runMonitoring(monitoringInput, numberOfLoadFlowsInParallel); - return new RaoResultWithAngleMonitoring(monitoringInput.getRaoResult(), angleMonitoringResult); + public static RaoResult runAngleAndUpdateRaoResult(String loadFlowProvider, + LoadFlowParameters loadFlowParameters, int numberOfLoadFlowsInParallel, + MonitoringInput monitoringInput) throws OpenRaoException { + final MonitoringResult angleMonitoringResult = new Monitoring(loadFlowProvider, + loadFlowParameters).runMonitoring(monitoringInput, numberOfLoadFlowsInParallel); + return new RaoResultWithAngleMonitoring(monitoringInput.getRaoResult(), + angleMonitoringResult); } /** - * The computation manager can be used by the caller to execute actions before and/or after running the loadflow. - * In particular, GridCapa relies on it to inject task-id in the MDC in order to bind logs with tasks. + * The computation manager can be used by the caller to execute actions before and/or after + * running the loadflow. In particular, GridCapa relies on it to inject task-id in the MDC in + * order to bind logs with tasks. */ - public static RaoResult runAngleAndUpdateRaoResult(String loadFlowProvider, LoadFlowParameters loadFlowParameters, ComputationManager computationManager, int numberOfLoadFlowsInParallel, MonitoringInput monitoringInput) throws OpenRaoException { - final MonitoringResult angleMonitoringResult = new Monitoring(loadFlowProvider, loadFlowParameters, computationManager).runMonitoring(monitoringInput, numberOfLoadFlowsInParallel); - return new RaoResultWithAngleMonitoring(monitoringInput.getRaoResult(), angleMonitoringResult); + public static RaoResult runAngleAndUpdateRaoResult(String loadFlowProvider, + LoadFlowParameters loadFlowParameters, ComputationManager computationManager, + int numberOfLoadFlowsInParallel, MonitoringInput monitoringInput) throws OpenRaoException { + final MonitoringResult angleMonitoringResult = new Monitoring(loadFlowProvider, + loadFlowParameters, computationManager).runMonitoring(monitoringInput, + numberOfLoadFlowsInParallel); + return new RaoResultWithAngleMonitoring(monitoringInput.getRaoResult(), + angleMonitoringResult); } /** * Main function : runs VoltageMonitoring computation on all VoltageCnecs defined in the CRAC. * Returns an RaoResult enhanced with VoltageMonitoringResult */ - public static RaoResult runVoltageAndUpdateRaoResult(String loadFlowProvider, LoadFlowParameters loadFlowParameters, int numberOfLoadFlowsInParallel, MonitoringInput monitoringInput) { - final MonitoringResult voltageMonitoringResult = new Monitoring(loadFlowProvider, loadFlowParameters).runMonitoring(monitoringInput, numberOfLoadFlowsInParallel); - return new RaoResultWithVoltageMonitoring(monitoringInput.getRaoResult(), voltageMonitoringResult); + public static RaoResult runVoltageAndUpdateRaoResult(String loadFlowProvider, + LoadFlowParameters loadFlowParameters, int numberOfLoadFlowsInParallel, + MonitoringInput monitoringInput) { + final MonitoringResult voltageMonitoringResult = new Monitoring(loadFlowProvider, + loadFlowParameters).runMonitoring(monitoringInput, numberOfLoadFlowsInParallel); + return new RaoResultWithVoltageMonitoring(monitoringInput.getRaoResult(), + voltageMonitoringResult); } /** - * The computation manager can be used by the caller to execute actions before and/or after running the loadflow. - * In particular, GridCapa relies on it to inject task-id in the MDC in order to bind logs with tasks. + * The computation manager can be used by the caller to execute actions before and/or after + * running the loadflow. In particular, GridCapa relies on it to inject task-id in the MDC in + * order to bind logs with tasks. */ - public static RaoResult runVoltageAndUpdateRaoResult(String loadFlowProvider, LoadFlowParameters loadFlowParameters, ComputationManager computationManager, int numberOfLoadFlowsInParallel, MonitoringInput monitoringInput) { - final MonitoringResult voltageMonitoringResult = new Monitoring(loadFlowProvider, loadFlowParameters, computationManager).runMonitoring(monitoringInput, numberOfLoadFlowsInParallel); - return new RaoResultWithVoltageMonitoring(monitoringInput.getRaoResult(), voltageMonitoringResult); + public static RaoResult runVoltageAndUpdateRaoResult(String loadFlowProvider, + LoadFlowParameters loadFlowParameters, ComputationManager computationManager, + int numberOfLoadFlowsInParallel, MonitoringInput monitoringInput) { + final MonitoringResult voltageMonitoringResult = new Monitoring(loadFlowProvider, + loadFlowParameters, computationManager).runMonitoring(monitoringInput, + numberOfLoadFlowsInParallel); + return new RaoResultWithVoltageMonitoring(monitoringInput.getRaoResult(), + voltageMonitoringResult); } - public MonitoringResult runMonitoring(MonitoringInput monitoringInput, int numberOfLoadFlowsInParallel) { - PhysicalParameter physicalParameter = monitoringInput.getPhysicalParameter(); - Network inputNetwork = monitoringInput.getNetwork(); - Crac crac = monitoringInput.getCrac(); - RaoResult raoResult = monitoringInput.getRaoResult(); - - MonitoringResult monitoringResult = new MonitoringResult(physicalParameter, Collections.emptySet(), Collections.emptyMap(), Cnec.SecurityStatus.SECURE); - - BUSINESS_LOGS.info("----- {} monitoring [start]", physicalParameter); - Set cnecs = crac.getCnecs(physicalParameter); - if (cnecs.isEmpty()) { - BUSINESS_WARNS.warn("No Cnecs of type '{}' defined.", physicalParameter); - BUSINESS_LOGS.info("----- {} monitoring [end]", physicalParameter); - return monitoringResult; - } - - // I) Preventive state - State preventiveState = crac.getPreventiveState(); - if (Objects.nonNull(preventiveState)) { - applyOptimalRemedialActions(preventiveState, inputNetwork, raoResult); - Set preventiveStateCnecs = crac.getCnecs(physicalParameter, preventiveState); - MonitoringResult preventiveStateMonitoringResult = monitorCnecs(preventiveState, preventiveStateCnecs, inputNetwork, monitoringInput); - preventiveStateMonitoringResult.printConstraints().forEach(BUSINESS_LOGS::info); - monitoringResult.combine(preventiveStateMonitoringResult); - } + public MonitoringResult runMonitoring(MonitoringInput monitoringInput, + int numberOfLoadFlowsInParallel) { + return OpenTelemetryReporter.withSpan("rao.runMonitoring", cx -> { + PhysicalParameter physicalParameter = monitoringInput.getPhysicalParameter(); + Network inputNetwork = monitoringInput.getNetwork(); + Crac crac = monitoringInput.getCrac(); + RaoResult raoResult = monitoringInput.getRaoResult(); + + MonitoringResult monitoringResult = new MonitoringResult(physicalParameter, + Collections.emptySet(), Collections.emptyMap(), Cnec.SecurityStatus.SECURE); + + BUSINESS_LOGS.info("----- {} monitoring [start]", physicalParameter); + Set cnecs = crac.getCnecs(physicalParameter); + if (cnecs.isEmpty()) { + BUSINESS_WARNS.warn("No Cnecs of type '{}' defined.", physicalParameter); + BUSINESS_LOGS.info("----- {} monitoring [end]", physicalParameter); + return monitoringResult; + } - // II) Curative states - Set contingencyStates = crac.getCnecs(physicalParameter).stream().map(Cnec::getState).filter(state -> !state.isPreventive()).collect(Collectors.toSet()); - if (contingencyStates.isEmpty()) { - BUSINESS_LOGS.info("----- {} monitoring [end]", physicalParameter); - return monitoringResult; - } + // I) Preventive state + State preventiveState = crac.getPreventiveState(); + if (Objects.nonNull(preventiveState)) { + applyOptimalRemedialActions(preventiveState, inputNetwork, raoResult); + Set preventiveStateCnecs = crac.getCnecs(physicalParameter, preventiveState); + MonitoringResult preventiveStateMonitoringResult = monitorCnecs(preventiveState, + preventiveStateCnecs, inputNetwork, monitoringInput); + preventiveStateMonitoringResult.printConstraints().forEach(BUSINESS_LOGS::info); + monitoringResult.combine(preventiveStateMonitoringResult); + } - try (AbstractNetworkPool networkPool = AbstractNetworkPool.create(inputNetwork, inputNetwork.getVariantManager().getWorkingVariantId(), Math.min(numberOfLoadFlowsInParallel, contingencyStates.size()), true)) { - List> tasks = contingencyStates.stream().map(state -> - networkPool.submit(() -> { - Network networkClone = networkPool.getAvailableNetwork(); + // II) Curative states + Set contingencyStates = crac.getCnecs(physicalParameter).stream() + .map(Cnec::getState) + .filter(state -> !state.isPreventive()).collect(Collectors.toSet()); + if (contingencyStates.isEmpty()) { + BUSINESS_LOGS.info("----- {} monitoring [end]", physicalParameter); + return monitoringResult; + } - Contingency contingency = state.getContingency().orElseThrow(); - if (!contingency.isValid(networkClone)) { - monitoringResult.combine(makeFailedMonitoringResultForStateWithNaNCnecRsults(monitoringInput, physicalParameter, state, "Unable to apply contingency " + contingency.getId())); + try (AbstractNetworkPool networkPool = AbstractNetworkPool.create(inputNetwork, + inputNetwork.getVariantManager().getWorkingVariantId(), + Math.min(numberOfLoadFlowsInParallel, contingencyStates.size()), true)) { + List> tasks = contingencyStates.stream().map(state -> + networkPool.submit(() -> { + Network networkClone = networkPool.getAvailableNetwork(); + + Contingency contingency = state.getContingency().orElseThrow(); + if (!contingency.isValid(networkClone)) { + monitoringResult.combine( + makeFailedMonitoringResultForStateWithNaNCnecRsults(monitoringInput, + physicalParameter, state, + "Unable to apply contingency " + contingency.getId())); + networkPool.releaseUsedNetwork(networkClone); + return null; + } + contingency.toModification().apply(networkClone, (ComputationManager) null); + applyOptimalRemedialActionsOnContingencyState(state, networkClone, crac, + raoResult); + Set currentStateCnecs = crac.getCnecs(physicalParameter, state); + MonitoringResult currentStateMonitoringResult = monitorCnecs(state, + currentStateCnecs, networkClone, monitoringInput); + currentStateMonitoringResult.printConstraints() + .forEach(BUSINESS_LOGS::info); + monitoringResult.combine(currentStateMonitoringResult); networkPool.releaseUsedNetwork(networkClone); return null; + })).toList(); + + for (ForkJoinTask task : tasks) { + try { + task.get(); + } catch (ExecutionException e) { + throw new OpenRaoException(e); } - contingency.toModification().apply(networkClone, (ComputationManager) null); - applyOptimalRemedialActionsOnContingencyState(state, networkClone, crac, raoResult); - Set currentStateCnecs = crac.getCnecs(physicalParameter, state); - MonitoringResult currentStateMonitoringResult = monitorCnecs(state, currentStateCnecs, networkClone, monitoringInput); - currentStateMonitoringResult.printConstraints().forEach(BUSINESS_LOGS::info); - monitoringResult.combine(currentStateMonitoringResult); - networkPool.releaseUsedNetwork(networkClone); - return null; - })).toList(); - - for (ForkJoinTask task : tasks) { - try { - task.get(); - } catch (ExecutionException e) { - throw new OpenRaoException(e); } + networkPool.shutdownAndAwaitTermination(24, TimeUnit.HOURS); + } catch (Exception e) { + Thread.currentThread().interrupt(); + monitoringResult.setStatusToFailure(); } - networkPool.shutdownAndAwaitTermination(24, TimeUnit.HOURS); - } catch (Exception e) { - Thread.currentThread().interrupt(); - monitoringResult.setStatusToFailure(); - } - BUSINESS_LOGS.info("----- {} monitoring [end]", physicalParameter); - monitoringResult.printConstraints().forEach(BUSINESS_LOGS::info); - return monitoringResult; + BUSINESS_LOGS.info("----- {} monitoring [end]", physicalParameter); + monitoringResult.printConstraints().forEach(BUSINESS_LOGS::info); + return monitoringResult; + }); } - private MonitoringResult monitorCnecs(State state, Set cnecs, Network network, MonitoringInput monitoringInput) { + private MonitoringResult monitorCnecs(State state, Set cnecs, Network network, + MonitoringInput monitoringInput) { PhysicalParameter physicalParameter = monitoringInput.getPhysicalParameter(); Unit unit = parameterToUnitMap.get(physicalParameter); Set cnecResults = new HashSet<>(); BUSINESS_LOGS.info("-- '{}' Monitoring at state '{}' [start]", physicalParameter, state); boolean lfSuccess = computeLoadFlow(network); if (!lfSuccess) { - String failureReason = String.format("Load-flow computation failed at state %s. Skipping this state.", state); - return makeFailedMonitoringResultForStateWithNaNCnecRsults(monitoringInput, physicalParameter, state, failureReason); + String failureReason = String.format( + "Load-flow computation failed at state %s. Skipping this state.", state); + return makeFailedMonitoringResultForStateWithNaNCnecRsults(monitoringInput, + physicalParameter, state, failureReason); } List appliedNetworkActionsResultList = new ArrayList<>(); cnecs.forEach(cnec -> { if (cnec.computeMargin(network, unit) < 0) { // For Cnecs with overshoot, get associated remedial actions - Set availableNetworkActions = getNetworkActionsAssociatedToCnec(state, monitoringInput.getCrac(), cnec, physicalParameter); + Set availableNetworkActions = getNetworkActionsAssociatedToCnec( + state, monitoringInput.getCrac(), cnec, physicalParameter); // if there is any RA(s) available apply it/them if (!availableNetworkActions.isEmpty()) { - AppliedNetworkActionsResult appliedNetworkActionsResult = applyNetworkActions(network, availableNetworkActions, cnec.getId(), monitoringInput); + AppliedNetworkActionsResult appliedNetworkActionsResult = applyNetworkActions( + network, availableNetworkActions, cnec.getId(), monitoringInput); if (!appliedNetworkActionsResult.getAppliedNetworkActions().isEmpty()) { appliedNetworkActionsResultList.add(appliedNetworkActionsResult); } } } - CnecResult cnecResult = new CnecResult(cnec, unit, cnec.computeValue(network, unit), cnec.computeMargin(network, unit), cnec.computeSecurityStatus(network, unit)); + CnecResult cnecResult = new CnecResult(cnec, unit, cnec.computeValue(network, unit), + cnec.computeMargin(network, unit), cnec.computeSecurityStatus(network, unit)); cnecResults.add(cnecResult); }); - redispatchNetworkActions(network, appliedNetworkActionsResultList, monitoringInput.getScalableZonalData()); + redispatchNetworkActions(network, appliedNetworkActionsResultList, + monitoringInput.getScalableZonalData()); // If some action were applied, recompute a loadflow - if (appliedNetworkActionsResultList.stream().map(AppliedNetworkActionsResult::getAppliedNetworkActions).findAny().isPresent()) { + if (appliedNetworkActionsResultList.stream() + .map(AppliedNetworkActionsResult::getAppliedNetworkActions).findAny().isPresent()) { lfSuccess = computeLoadFlow(network); if (!lfSuccess) { - String failureReason = String.format("Load-flow computation failed at state %s after applying RAs. Skipping this state.", state); - return makeFailedMonitoringResultForState(physicalParameter, state, failureReason, cnecResults); + String failureReason = String.format( + "Load-flow computation failed at state %s after applying RAs. Skipping this state.", + state); + return makeFailedMonitoringResultForState(physicalParameter, state, failureReason, + cnecResults); } // Re-compute all voltage/angle values cnecResults.clear(); @@ -238,30 +312,40 @@ private MonitoringResult monitorCnecs(State state, Set cnecs, Network netw BUSINESS_LOGS.info("-- '{}' Monitoring at state '{}' [end]", physicalParameter, state); return new MonitoringResult(physicalParameter, cnecResults, - Map.of(state, appliedNetworkActionsResultList.stream().flatMap(r -> r.getAppliedNetworkActions().stream()).collect(Collectors.toSet())), + Map.of(state, appliedNetworkActionsResultList.stream() + .flatMap(r -> r.getAppliedNetworkActions().stream()).collect(Collectors.toSet())), monitoringResultStatus); } - private void redispatchNetworkActions(Network network, List appliedNetworkActionsResults, ZonalData scalableZonalData) { + private void redispatchNetworkActions(Network network, + List appliedNetworkActionsResults, + ZonalData scalableZonalData) { // Apply one redispatch action per country appliedNetworkActionsResults.forEach(appliedNetworkActionsResult -> appliedNetworkActionsResult.getPowerToBeRedispatched().forEach((key, value) -> { BUSINESS_LOGS.info("Redispatching {} MW in {} [start]", value, key); - List countryScalables = scalableZonalData.getDataPerZone().entrySet().stream().filter(entry -> key.equals(new CountryEICode(entry.getKey()).getCountry())) + List countryScalables = scalableZonalData.getDataPerZone().entrySet() + .stream() + .filter(entry -> key.equals(new CountryEICode(entry.getKey()).getCountry())) .map(Map.Entry::getValue).toList(); if (countryScalables.size() > 1) { - throw new OpenRaoException(String.format("> 1 (%s) glskPoints defined for country %s", countryScalables.size(), key.getName())); + throw new OpenRaoException( + String.format("> 1 (%s) glskPoints defined for country %s", + countryScalables.size(), key.getName())); } - new RedispatchAction(value, appliedNetworkActionsResult.getNetworkElementsToBeExcluded(), countryScalables.get(0)).apply(network); + new RedispatchAction(value, + appliedNetworkActionsResult.getNetworkElementsToBeExcluded(), + countryScalables.get(0)).apply(network); BUSINESS_LOGS.info("Redispatching {} MW in {} [end]", value, key); })); } /** - * Gathers optimal remedial actions retrieved from raoResult for a given state on network. - * For curative states, consider auto (when they exist) and curative states. + * Gathers optimal remedial actions retrieved from raoResult for a given state on network. For + * curative states, consider auto (when they exist) and curative states. */ - private void applyOptimalRemedialActionsOnContingencyState(State state, Network network, Crac crac, RaoResult raoResult) { + private void applyOptimalRemedialActionsOnContingencyState(State state, Network network, + Crac crac, RaoResult raoResult) { if (state.getInstant().isCurative()) { Optional contingency = state.getContingency(); crac.getStates(contingency.orElseThrow()).forEach(contingencyState -> @@ -282,8 +366,7 @@ private void applyOptimalRemedialActions(State state, Network network, RaoResult } /** - * Runs a LoadFlow computation - * Returns false if loadFlow has not converged. + * Runs a LoadFlow computation Returns false if loadFlow has not converged. */ private boolean computeLoadFlow(Network network) { TECHNICAL_LOGS.info("Load-flow computation [start]"); @@ -296,7 +379,8 @@ private boolean computeLoadFlow(Network network) { return loadFlowResult.isFullyConverged(); } - private Set getNetworkActionsAssociatedToCnec(State state, Crac crac, Cnec cnec, PhysicalParameter physicalParameter) { + private Set getNetworkActionsAssociatedToCnec(State state, Crac crac, Cnec cnec, + PhysicalParameter physicalParameter) { Set> availableRemedialActions = crac.getRemedialActions().stream() .filter(remedialAction -> @@ -305,11 +389,15 @@ private Set getNetworkActionsAssociatedToCnec(State state, Crac c .anyMatch(onConstraint -> onConstraint.getCnec().equals(cnec))) .collect(Collectors.toSet()); if (availableRemedialActions.isEmpty()) { - BUSINESS_WARNS.warn("{} Cnec {} in state {} has no associated RA. {} constraint cannot be secured.", physicalParameter, cnec.getId(), state.getId(), physicalParameter); + BUSINESS_WARNS.warn( + "{} Cnec {} in state {} has no associated RA. {} constraint cannot be secured.", + physicalParameter, cnec.getId(), state.getId(), physicalParameter); return Collections.emptySet(); } if (state.isPreventive()) { - BUSINESS_WARNS.warn("{} Cnec {} is constrained in preventive state, it cannot be secured.", physicalParameter, cnec.getId()); + BUSINESS_WARNS.warn( + "{} Cnec {} is constrained in preventive state, it cannot be secured.", + physicalParameter, cnec.getId()); return Collections.emptySet(); } // Convert remedial actions to network actions @@ -317,30 +405,40 @@ private Set getNetworkActionsAssociatedToCnec(State state, Crac c if (remedialAction instanceof NetworkAction) { return true; } else { - BUSINESS_WARNS.warn("Remedial action {} of Cnec {} in state {} is ignored : it's not a network action.", remedialAction.getId(), cnec.getId(), state.getId()); + BUSINESS_WARNS.warn( + "Remedial action {} of Cnec {} in state {} is ignored : it's not a network action.", + remedialAction.getId(), cnec.getId(), state.getId()); return false; } }).map(NetworkAction.class::cast).collect(Collectors.toSet()); } - private AppliedNetworkActionsResult applyNetworkActions(Network network, Set availableNetworkActions, String cnecId, MonitoringInput monitoringInput) { + private AppliedNetworkActionsResult applyNetworkActions(Network network, + Set availableNetworkActions, String cnecId, + MonitoringInput monitoringInput) { AppliedNetworkActionsResult appliedNetworkActionsResult; - Set appliedNetworkActions = new TreeSet<>(Comparator.comparing(RemedialAction::getId)); + Set appliedNetworkActions = new TreeSet<>( + Comparator.comparing(RemedialAction::getId)); if (monitoringInput.getPhysicalParameter().equals(PhysicalParameter.VOLTAGE)) { for (NetworkAction na : availableNetworkActions) { na.apply(network); appliedNetworkActions.add(na); } - appliedNetworkActionsResult = new AppliedNetworkActionsResult.AppliedNetworkActionsResultBuilder().withAppliedNetworkActions(appliedNetworkActions) - .withNetworkElementsToBeExcluded(new HashSet<>()).withPowerToBeRedispatched(new EnumMap<>(Country.class)).build(); + appliedNetworkActionsResult = new AppliedNetworkActionsResult.AppliedNetworkActionsResultBuilder().withAppliedNetworkActions( + appliedNetworkActions) + .withNetworkElementsToBeExcluded(new HashSet<>()) + .withPowerToBeRedispatched(new EnumMap<>(Country.class)).build(); } else { boolean networkActionOk = false; EnumMap powerToBeRedispatched = new EnumMap<>(Country.class); Set networkElementsToBeExcluded = new HashSet<>(); for (NetworkAction na : availableNetworkActions) { - EnumMap tempPowerToBeRedispatched = new EnumMap<>(powerToBeRedispatched); + EnumMap tempPowerToBeRedispatched = new EnumMap<>( + powerToBeRedispatched); for (Action ea : na.getElementaryActions()) { - networkActionOk = checkElementaryActionAndStoreInjection(ea, network, cnecId, na.getId(), networkElementsToBeExcluded, tempPowerToBeRedispatched, monitoringInput.getScalableZonalData()); + networkActionOk = checkElementaryActionAndStoreInjection(ea, network, cnecId, + na.getId(), networkElementsToBeExcluded, tempPowerToBeRedispatched, + monitoringInput.getScalableZonalData()); if (!networkActionOk) { break; } @@ -351,48 +449,70 @@ private AppliedNetworkActionsResult applyNetworkActions(Network network, Set networkElementsToBeExcluded, Map powerToBeRedispatched, ZonalData scalableZonalData) { + private boolean checkElementaryActionAndStoreInjection(Action ea, Network network, + String angleCnecId, String naId, Set networkElementsToBeExcluded, + Map powerToBeRedispatched, ZonalData scalableZonalData) { if (!(ea instanceof LoadAction) && !(ea instanceof GeneratorAction)) { - BUSINESS_WARNS.warn("Remedial action {} of AngleCnec {} is ignored : it has an elementary action that's not an injection setpoint.", naId, angleCnecId); + BUSINESS_WARNS.warn( + "Remedial action {} of AngleCnec {} is ignored : it has an elementary action that's not an injection setpoint.", + naId, angleCnecId); return false; } Identifiable ne = getInjectionSetpointIdentifiable(ea, network); if (ne == null) { - BUSINESS_WARNS.warn("Remedial action {} of AngleCnec {} is ignored : it has no elementary actions.", naId, angleCnecId); + BUSINESS_WARNS.warn( + "Remedial action {} of AngleCnec {} is ignored : it has no elementary actions.", + naId, angleCnecId); return false; } - Optional substation = ((Injection) ne).getTerminal().getVoltageLevel().getSubstation(); + Optional substation = ((Injection) ne).getTerminal().getVoltageLevel() + .getSubstation(); if (substation.isEmpty()) { - BUSINESS_WARNS.warn("Remedial action {} of AngleCnec {} is ignored : it has an elementary action that doesn't have a substation.", naId, angleCnecId); + BUSINESS_WARNS.warn( + "Remedial action {} of AngleCnec {} is ignored : it has an elementary action that doesn't have a substation.", + naId, angleCnecId); return false; } else { Optional country = substation.get().getCountry(); if (country.isEmpty()) { - BUSINESS_WARNS.warn("Remedial action {} of AngleCnec {} is ignored : it has an elementary action that doesn't have a country.", naId, angleCnecId); + BUSINESS_WARNS.warn( + "Remedial action {} of AngleCnec {} is ignored : it has an elementary action that doesn't have a country.", + naId, angleCnecId); return false; } else { checkGlsks(country.get(), naId, angleCnecId, scalableZonalData); if (ne.getType().equals(IdentifiableType.GENERATOR)) { - powerToBeRedispatched.merge(country.get(), ((Generator) ne).getTargetP() - ((GeneratorAction) ea).getActivePowerValue().getAsDouble(), Double::sum); + powerToBeRedispatched.merge(country.get(), + ((Generator) ne).getTargetP() - ((GeneratorAction) ea).getActivePowerValue() + .getAsDouble(), Double::sum); } else if (ne.getType().equals(IdentifiableType.LOAD)) { - powerToBeRedispatched.merge(country.get(), -((Load) ne).getP0() + ((LoadAction) ea).getActivePowerValue().getAsDouble(), Double::sum); + powerToBeRedispatched.merge(country.get(), + -((Load) ne).getP0() + ((LoadAction) ea).getActivePowerValue() + .getAsDouble(), Double::sum); } else { - BUSINESS_WARNS.warn("Remedial action {} of AngleCnec {} is ignored : it has an injection setpoint that's neither a generator nor a load.", naId, angleCnecId); + BUSINESS_WARNS.warn( + "Remedial action {} of AngleCnec {} is ignored : it has an injection setpoint that's neither a generator nor a load.", + naId, angleCnecId); return false; } networkElementsToBeExcluded.add(ne.getId()); @@ -420,7 +540,8 @@ private Identifiable getInjectionSetpointIdentifiable(Action ea, Network netw /** * Checks glsks are correctly defined on country */ - private void checkGlsks(Country country, String naId, String angleCnecId, ZonalData scalableZonalData) { + private void checkGlsks(Country country, String naId, String angleCnecId, + ZonalData scalableZonalData) { Set glskCountries = new TreeSet<>(Comparator.comparing(Country::getName)); if (Objects.isNull(scalableZonalData)) { String error = "ScalableZonalData undefined (no GLSK given)"; @@ -431,19 +552,31 @@ private void checkGlsks(Country country, String naId, String angleCnecId, ZonalD glskCountries.add(new CountryEICode(zone).getCountry()); } if (!glskCountries.contains(country)) { - throw new OpenRaoException(String.format("INFEASIBLE Angle Monitoring : Glsks were not defined for country %s. Remedial action %s of AngleCnec %s is ignored.", country.getName(), naId, angleCnecId)); + throw new OpenRaoException(String.format( + "INFEASIBLE Angle Monitoring : Glsks were not defined for country %s. Remedial action %s of AngleCnec %s is ignored.", + country.getName(), naId, angleCnecId)); } } - private MonitoringResult makeFailedMonitoringResultForStateWithNaNCnecRsults(MonitoringInput monitoringInput, PhysicalParameter physicalParameter, State state, String failureReason) { + private MonitoringResult makeFailedMonitoringResultForStateWithNaNCnecRsults( + MonitoringInput monitoringInput, PhysicalParameter physicalParameter, State state, + String failureReason) { Set cnecResults = new HashSet<>(); - CnecValue cnecValue = physicalParameter.equals(PhysicalParameter.ANGLE) ? new AngleCnecValue(Double.NaN) : new VoltageCnecValue(Double.NaN, Double.NaN); - monitoringInput.getCrac().getCnecs(state).forEach(cnec -> cnecResults.add(new CnecResult(cnec, parameterToUnitMap.get(physicalParameter), cnecValue, Double.NaN, Cnec.SecurityStatus.FAILURE))); - return makeFailedMonitoringResultForState(physicalParameter, state, failureReason, cnecResults); + CnecValue cnecValue = + physicalParameter.equals(PhysicalParameter.ANGLE) ? new AngleCnecValue(Double.NaN) + : new VoltageCnecValue(Double.NaN, Double.NaN); + monitoringInput.getCrac().getCnecs(state).forEach(cnec -> cnecResults.add( + new CnecResult(cnec, parameterToUnitMap.get(physicalParameter), cnecValue, Double.NaN, + Cnec.SecurityStatus.FAILURE))); + return makeFailedMonitoringResultForState(physicalParameter, state, failureReason, + cnecResults); } - private MonitoringResult makeFailedMonitoringResultForState(PhysicalParameter physicalParameter, State state, String failureReason, Set cnecResults) { + private MonitoringResult makeFailedMonitoringResultForState(PhysicalParameter physicalParameter, + State state, String failureReason, Set cnecResults) { BUSINESS_WARNS.warn(failureReason); - return new MonitoringResult(physicalParameter, cnecResults, Map.of(state, Collections.emptySet()), Cnec.SecurityStatus.FAILURE); + return new MonitoringResult(physicalParameter, cnecResults, + Map.of(state, Collections.emptySet()), Cnec.SecurityStatus.FAILURE); } } + diff --git a/pom.xml b/pom.xml index c1c669fba4..979facf3d2 100644 --- a/pom.xml +++ b/pom.xml @@ -114,6 +114,8 @@ 2.10.0 1.5.3 3.27.7 + 1.53.0 + 2.7.0 @@ -611,6 +613,43 @@ runtime + + + io.opentelemetry + opentelemetry-sdk + ${opentelemetry.version} + + + io.opentelemetry + opentelemetry-sdk-logs + ${opentelemetry.version} + + + io.opentelemetry + opentelemetry-sdk-metrics + ${opentelemetry.version} + + + io.opentelemetry + opentelemetry-api + ${opentelemetry.version} + + + io.opentelemetry + opentelemetry-exporter-otlp + ${opentelemetry.version} + + + io.opentelemetry + opentelemetry-exporter-logging + ${opentelemetry.version} + + + io.opentelemetry.instrumentation + opentelemetry-instrumentation-annotations + ${opentelemetry-instrumentation.version} + + io.cucumber diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java index e3e80a3db5..2741f26500 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java @@ -7,6 +7,16 @@ package com.powsybl.openrao.searchtreerao.castor.algorithm; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_LOGS; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.TECHNICAL_LOGS; +import static com.powsybl.openrao.searchtreerao.commons.HvdcUtils.getHvdcRangeActionsOnHvdcLineInAcEmulation; +import static com.powsybl.openrao.searchtreerao.commons.RaoLogger.formatDoubleBasedOnMargin; +import static com.powsybl.openrao.searchtreerao.commons.RaoLogger.getVirtualCostDetailed; +import static com.powsybl.openrao.searchtreerao.commons.RaoUtil.applyRemedialActions; +import static com.powsybl.openrao.searchtreerao.commons.RaoUtil.getFlowUnit; + +import com.powsybl.iidm.network.Network; +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; import com.powsybl.openrao.data.crac.api.Crac; import com.powsybl.openrao.data.crac.api.Instant; import com.powsybl.openrao.data.crac.api.State; @@ -28,30 +38,35 @@ import com.powsybl.openrao.searchtreerao.commons.RaoUtil; import com.powsybl.openrao.searchtreerao.commons.ToolProvider; import com.powsybl.openrao.searchtreerao.commons.objectivefunction.ObjectiveFunction; -import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.*; +import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.PreventiveOptimizationPerimeter; import com.powsybl.openrao.searchtreerao.commons.parameters.TreeParameters; import com.powsybl.openrao.searchtreerao.commons.parameters.UnoptimizedCnecParameters; -import com.powsybl.openrao.searchtreerao.result.api.*; -import com.powsybl.openrao.searchtreerao.result.impl.*; +import com.powsybl.openrao.searchtreerao.result.api.FlowResult; +import com.powsybl.openrao.searchtreerao.result.api.OptimizationResult; +import com.powsybl.openrao.searchtreerao.result.api.PrePerimeterResult; +import com.powsybl.openrao.searchtreerao.result.impl.FailedRaoResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.NetworkActionsResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.OneStateOnlyRaoResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.OptimizationResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.PostPerimeterResult; +import com.powsybl.openrao.searchtreerao.result.impl.PreventiveAndCurativesRaoResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.RangeActionActivationResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.RemedialActionActivationResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.UnoptimizedRaoResultImpl; import com.powsybl.openrao.searchtreerao.searchtree.algorithms.SearchTree; import com.powsybl.openrao.searchtreerao.searchtree.inputs.SearchTreeInput; import com.powsybl.openrao.searchtreerao.searchtree.parameters.SearchTreeParameters; import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions; -import com.powsybl.iidm.network.Network; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.apache.commons.lang3.tuple.Pair; - import java.time.temporal.ChronoUnit; -import java.util.*; -import java.util.concurrent.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; - -import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.*; -import static com.powsybl.openrao.searchtreerao.commons.HvdcUtils.getHvdcRangeActionsOnHvdcLineInAcEmulation; -import static com.powsybl.openrao.searchtreerao.commons.RaoLogger.formatDoubleBasedOnMargin; -import static com.powsybl.openrao.searchtreerao.commons.RaoLogger.getVirtualCostDetailed; -import static com.powsybl.openrao.searchtreerao.commons.RaoUtil.applyRemedialActions; -import static com.powsybl.openrao.searchtreerao.commons.RaoUtil.getFlowUnit; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.apache.commons.lang3.tuple.Pair; /** * @author Joris Mancini {@literal } @@ -62,6 +77,7 @@ * @author Thomas Bouquet {@literal } */ public class CastorFullOptimization { + private static final String INITIAL_SCENARIO = "InitialScenario"; private static final String PREVENTIVE_SCENARIO = "PreventiveScenario"; private static final String SECOND_PREVENTIVE_SCENARIO_BEFORE_OPT = "SecondPreventiveScenario"; @@ -76,7 +92,8 @@ public class CastorFullOptimization { private final RaoParameters raoParameters; private final java.time.Instant targetEndInstant; - public CastorFullOptimization(RaoInput raoInput, RaoParameters raoParameters, java.time.Instant targetEndInstant) { + public CastorFullOptimization(RaoInput raoInput, RaoParameters raoParameters, + java.time.Instant targetEndInstant) { this.raoInput = raoInput; this.crac = raoInput.getCrac(); this.network = raoInput.getNetwork(); @@ -89,10 +106,14 @@ public CompletableFuture run() { try { RaoUtil.initData(raoInput, raoParameters); - ToolProvider toolProvider = ToolProvider.buildFromRaoInputAndParameters(raoInput, raoParameters); + ToolProvider toolProvider = ToolProvider.buildFromRaoInputAndParameters(raoInput, + raoParameters); if (crac.getFlowCnecs().isEmpty()) { - PrePerimeterResult initialResult = new PrePerimeterSensitivityAnalysis(crac, crac.getFlowCnecs(), crac.getRangeActions(), raoParameters, toolProvider, true).runInitialSensitivityAnalysis(network); - return CompletableFuture.completedFuture(new UnoptimizedRaoResultImpl(initialResult)); + PrePerimeterResult initialResult = new PrePerimeterSensitivityAnalysis(crac, + crac.getFlowCnecs(), crac.getRangeActions(), raoParameters, toolProvider, + true).runInitialSensitivityAnalysis(network); + return CompletableFuture.completedFuture( + new UnoptimizedRaoResultImpl(initialResult)); } StateTree stateTree = new StateTree(crac); @@ -112,7 +133,8 @@ public CompletableFuture run() { initialOutput = prePerimeterSensitivityAnalysis.runInitialSensitivityAnalysis(network); if (initialOutput.getSensitivityStatus() == ComputationStatus.FAILURE) { BUSINESS_LOGS.error("Initial sensitivity analysis failed"); - return CompletableFuture.completedFuture(new FailedRaoResultImpl("Initial sensitivity analysis failed")); + return CompletableFuture.completedFuture( + new FailedRaoResultImpl("Initial sensitivity analysis failed")); } RaoLogger.logSensitivityAnalysisResults("Initial sensitivity analysis: ", prePerimeterSensitivityAnalysis.getObjectiveFunction(), @@ -127,44 +149,63 @@ public CompletableFuture run() { java.time.Instant preventiveRaoStartInstant = java.time.Instant.now(); BUSINESS_LOGS.info("----- Preventive perimeter optimization [start]"); - network.getVariantManager().cloneVariant(network.getVariantManager().getWorkingVariantId(), INITIAL_SCENARIO); - network.getVariantManager().cloneVariant(network.getVariantManager().getWorkingVariantId(), PREVENTIVE_SCENARIO); - network.getVariantManager().cloneVariant(network.getVariantManager().getWorkingVariantId(), SECOND_PREVENTIVE_SCENARIO_BEFORE_OPT); + network.getVariantManager() + .cloneVariant(network.getVariantManager().getWorkingVariantId(), INITIAL_SCENARIO); + network.getVariantManager() + .cloneVariant(network.getVariantManager().getWorkingVariantId(), + PREVENTIVE_SCENARIO); + network.getVariantManager() + .cloneVariant(network.getVariantManager().getWorkingVariantId(), + SECOND_PREVENTIVE_SCENARIO_BEFORE_OPT); network.getVariantManager().setWorkingVariant(PREVENTIVE_SCENARIO); if (stateTree.getContingencyScenarios().isEmpty()) { - Pair> preventiveResultsAndOptimizedCnecs = optimizePreventivePerimeter(stateTree, toolProvider, initialOutput); + Pair> preventiveResultsAndOptimizedCnecs = optimizePreventivePerimeter( + stateTree, toolProvider, initialOutput); OptimizationResult preventiveResult = preventiveResultsAndOptimizedCnecs.getLeft(); Set optimizedFlowCnecs = preventiveResultsAndOptimizedCnecs.getRight(); BUSINESS_LOGS.info("----- Preventive perimeter optimization [end]"); // log final result - RaoLogger.logMostLimitingElementsResults(TECHNICAL_LOGS, preventiveResult, raoParameters.getObjectiveFunctionParameters().getType(), getFlowUnit(raoParameters), 10); + RaoLogger.logMostLimitingElementsResults(TECHNICAL_LOGS, preventiveResult, + raoParameters.getObjectiveFunctionParameters().getType(), + getFlowUnit(raoParameters), 10); RaoLogger.checkIfMostLimitingElementIsFictional(BUSINESS_LOGS, preventiveResult); - RaoResult raoResult = new OneStateOnlyRaoResultImpl(crac.getPreventiveState(), initialOutput, preventiveResult, optimizedFlowCnecs); - return postCheckResults(raoResult, initialOutput, raoParameters.getObjectiveFunctionParameters(), true); + RaoResult raoResult = new OneStateOnlyRaoResultImpl(crac.getPreventiveState(), + initialOutput, preventiveResult, optimizedFlowCnecs); + return postCheckResults(raoResult, initialOutput, + raoParameters.getObjectiveFunctionParameters(), true); } - OptimizationResult preventiveResult = optimizePreventivePerimeter(stateTree, toolProvider, initialOutput).getLeft(); + OptimizationResult preventiveResult = optimizePreventivePerimeter(stateTree, + toolProvider, initialOutput).getLeft(); BUSINESS_LOGS.info("----- Preventive perimeter optimization [end]"); java.time.Instant preventiveRaoEndInstant = java.time.Instant.now(); - long preventiveRaoTime = ChronoUnit.SECONDS.between(preventiveRaoStartInstant, preventiveRaoEndInstant); + long preventiveRaoTime = ChronoUnit.SECONDS.between(preventiveRaoStartInstant, + preventiveRaoEndInstant); // ----- SENSI POST-PRA ----- currentStep = "post-PRA sensitivity analysis"; // mutualise the pre-perimeter sensi analysis for all contingency scenario + get after-PRA result over all CNECs network.getVariantManager().setWorkingVariant(INITIAL_SCENARIO); - network.getVariantManager().cloneVariant(network.getVariantManager().getWorkingVariantId(), PREVENTIVE_SCENARIO, true); + network.getVariantManager() + .cloneVariant(network.getVariantManager().getWorkingVariantId(), + PREVENTIVE_SCENARIO, true); network.getVariantManager().setWorkingVariant(PREVENTIVE_SCENARIO); applyRemedialActions(network, preventiveResult, crac.getPreventiveState()); - PostPerimeterResult postPreventiveResult = computePostPreventiveResult(toolProvider, initialOutput, preventiveResult); + PostPerimeterResult postPreventiveResult = computePostPreventiveResult(toolProvider, + initialOutput, preventiveResult); PrePerimeterResult preCurativeSensitivityAnalysisOutput = postPreventiveResult.prePerimeterResultForAllFollowingStates(); - if (preCurativeSensitivityAnalysisOutput.getSensitivityStatus() == ComputationStatus.FAILURE) { - BUSINESS_LOGS.error("Systematic sensitivity analysis after preventive remedial actions failed"); - return CompletableFuture.completedFuture(new FailedRaoResultImpl("Systematic sensitivity analysis after preventive remedial actions failed")); + if (preCurativeSensitivityAnalysisOutput.getSensitivityStatus() + == ComputationStatus.FAILURE) { + BUSINESS_LOGS.error( + "Systematic sensitivity analysis after preventive remedial actions failed"); + return CompletableFuture.completedFuture(new FailedRaoResultImpl( + "Systematic sensitivity analysis after preventive remedial actions failed")); } - RaoLogger.logSensitivityAnalysisResults("Systematic sensitivity analysis after preventive remedial actions: ", + RaoLogger.logSensitivityAnalysisResults( + "Systematic sensitivity analysis after preventive remedial actions: ", prePerimeterSensitivityAnalysis.getObjectiveFunction(), new RemedialActionActivationResultImpl(preventiveResult, preventiveResult), preCurativeSensitivityAnalysisOutput, @@ -181,41 +222,61 @@ public CompletableFuture run() { // (however RAO could continue depending on parameter enforce-curative-if-basecase-unsecure) double preventiveOptimalCost = preventiveResult.getCost(); if (shouldStopOptimisationIfPreventiveUnsecure(preventiveOptimalCost)) { - BUSINESS_LOGS.info("Preventive perimeter could not be secured; there is no point in optimizing post-contingency perimeters. The RAO will be interrupted here."); - mergedRaoResults = new PreventiveAndCurativesRaoResultImpl(stateTree, initialOutput, postPreventiveResult, crac, raoParameters); + BUSINESS_LOGS.info( + "Preventive perimeter could not be secured; there is no point in optimizing post-contingency perimeters. The RAO will be interrupted here."); + mergedRaoResults = new PreventiveAndCurativesRaoResultImpl(stateTree, initialOutput, + postPreventiveResult, crac, raoParameters); // log results - RaoLogger.logMostLimitingElementsResults(BUSINESS_LOGS, preCurativeSensitivityAnalysisOutput, raoParameters.getObjectiveFunctionParameters().getType(), getFlowUnit(raoParameters), NUMBER_LOGGED_ELEMENTS_END_RAO); - RaoLogger.checkIfMostLimitingElementIsFictional(BUSINESS_LOGS, preCurativeSensitivityAnalysisOutput); - return postCheckResults(mergedRaoResults, initialOutput, raoParameters.getObjectiveFunctionParameters(), true); + RaoLogger.logMostLimitingElementsResults(BUSINESS_LOGS, + preCurativeSensitivityAnalysisOutput, + raoParameters.getObjectiveFunctionParameters().getType(), + getFlowUnit(raoParameters), NUMBER_LOGGED_ELEMENTS_END_RAO); + RaoLogger.checkIfMostLimitingElementIsFictional(BUSINESS_LOGS, + preCurativeSensitivityAnalysisOutput); + return postCheckResults(mergedRaoResults, initialOutput, + raoParameters.getObjectiveFunctionParameters(), true); } BUSINESS_LOGS.info("----- Post-contingency perimeters optimization [start]"); - TreeParameters curativeTreeParameters = TreeParameters.buildForCurativePerimeter(raoParameters, preventiveOptimalCost); - CastorContingencyScenarios castorContingencyScenarios = new CastorContingencyScenarios(crac, raoParameters, toolProvider, stateTree, curativeTreeParameters, initialOutput); - Map postContingencyResults = castorContingencyScenarios.optimizeContingencyScenarios(network, preCurativeSensitivityAnalysisOutput, false); + TreeParameters curativeTreeParameters = TreeParameters.buildForCurativePerimeter( + raoParameters, preventiveOptimalCost); + CastorContingencyScenarios castorContingencyScenarios = new CastorContingencyScenarios( + crac, raoParameters, toolProvider, stateTree, curativeTreeParameters, + initialOutput); + Map postContingencyResults = castorContingencyScenarios.optimizeContingencyScenarios( + network, preCurativeSensitivityAnalysisOutput, false); BUSINESS_LOGS.info("----- Post-contingency perimeters optimization [end]"); // ----- SECOND PREVENTIVE PERIMETER OPTIMIZATION ----- currentStep = "second preventive optimization"; - mergedRaoResults = new PreventiveAndCurativesRaoResultImpl(stateTree, initialOutput, postPreventiveResult, postContingencyResults, crac, raoParameters); + mergedRaoResults = new PreventiveAndCurativesRaoResultImpl(stateTree, initialOutput, + postPreventiveResult, postContingencyResults, crac, raoParameters); boolean logFinalResultsOutsideOfSecondPreventive = true; // Run second preventive when necessary - CastorSecondPreventive castorSecondPreventive = new CastorSecondPreventive(crac, raoParameters, network, stateTree, toolProvider, targetEndInstant); + CastorSecondPreventive castorSecondPreventive = new CastorSecondPreventive(crac, + raoParameters, network, stateTree, toolProvider, targetEndInstant); // define variables to set with second preventive results only if it improves first PostPerimeterResult finalSecondPreventiveResult = postPreventiveResult; PostPerimeterResult intermediateSecondPreventiveResult = postPreventiveResult; - Map finalPostContingencyResults = new HashMap<>(postContingencyResults); - - if (castorSecondPreventive.shouldRunSecondPreventiveRao(preventiveResult, postContingencyResults.values(), mergedRaoResults, preventiveRaoTime)) { - CastorSecondPreventive.SecondPreventiveRaoResultsHolder secondPreventiveRaoResultsHolder = castorSecondPreventive.runSecondPreventiveAndAutoRao(castorContingencyScenarios, prePerimeterSensitivityAnalysis, initialOutput, postPreventiveResult, postContingencyResults); + Map finalPostContingencyResults = new HashMap<>( + postContingencyResults); + + if (castorSecondPreventive.shouldRunSecondPreventiveRao(preventiveResult, + postContingencyResults.values(), mergedRaoResults, preventiveRaoTime)) { + CastorSecondPreventive.SecondPreventiveRaoResultsHolder secondPreventiveRaoResultsHolder = castorSecondPreventive.runSecondPreventiveAndAutoRao( + castorContingencyScenarios, prePerimeterSensitivityAnalysis, initialOutput, + postPreventiveResult, postContingencyResults); RaoResult secondPreventiveRaoResults; if (secondPreventiveRaoResultsHolder.hasFailed()) { - secondPreventiveRaoResults = new FailedRaoResultImpl(secondPreventiveRaoResultsHolder.errorMessage()); + secondPreventiveRaoResults = new FailedRaoResultImpl( + secondPreventiveRaoResultsHolder.errorMessage()); } else { intermediateSecondPreventiveResult = new PostPerimeterResult( - secondPreventiveRaoResultsHolder.secondPreventiveRaoResult().perimeterResult(), - secondPreventiveRaoResultsHolder.secondPreventiveRaoResult().postPraSensitivityAnalysisOutput() + secondPreventiveRaoResultsHolder.secondPreventiveRaoResult() + .perimeterResult(), + secondPreventiveRaoResultsHolder.secondPreventiveRaoResult() + .postPraSensitivityAnalysisOutput() ); secondPreventiveRaoResults = new PreventiveAndCurativesRaoResultImpl( stateTree, @@ -228,31 +289,50 @@ public CompletableFuture run() { } if (secondPreventiveImprovesResults(secondPreventiveRaoResults, mergedRaoResults)) { finalSecondPreventiveResult = intermediateSecondPreventiveResult; - finalPostContingencyResults = new HashMap<>(secondPreventiveRaoResultsHolder.postContingencyResults()); + finalPostContingencyResults = new HashMap<>( + secondPreventiveRaoResultsHolder.postContingencyResults()); mergedRaoResults = secondPreventiveRaoResults; - mergedRaoResults.setExecutionDetails(OptimizationStepsExecuted.SECOND_PREVENTIVE_IMPROVED_FIRST); + mergedRaoResults.setExecutionDetails( + OptimizationStepsExecuted.SECOND_PREVENTIVE_IMPROVED_FIRST); logFinalResultsOutsideOfSecondPreventive = false; } else { - mergedRaoResults.setExecutionDetails(OptimizationStepsExecuted.SECOND_PREVENTIVE_FELLBACK_TO_FIRST_PREVENTIVE_SITUATION); + mergedRaoResults.setExecutionDetails( + OptimizationStepsExecuted.SECOND_PREVENTIVE_FELLBACK_TO_FIRST_PREVENTIVE_SITUATION); } } // Log final results if (logFinalResultsOutsideOfSecondPreventive) { BUSINESS_LOGS.info("Merging preventive and post-contingency RAO results:"); - RaoLogger.logMostLimitingElementsResults(BUSINESS_LOGS, stateTree.getBasecaseScenario(), finalSecondPreventiveResult.optimizationResult(), stateTree.getContingencyScenarios(), finalPostContingencyResults, raoParameters.getObjectiveFunctionParameters().getType(), getFlowUnit(raoParameters), NUMBER_LOGGED_ELEMENTS_END_RAO); - RaoLogger.checkIfMostLimitingElementIsFictional(BUSINESS_LOGS, stateTree.getBasecaseScenario(), finalSecondPreventiveResult.optimizationResult(), stateTree.getContingencyScenarios(), finalPostContingencyResults, raoParameters.getObjectiveFunctionParameters().getType(), getFlowUnit(raoParameters)); + RaoLogger.logMostLimitingElementsResults(BUSINESS_LOGS, + stateTree.getBasecaseScenario(), + finalSecondPreventiveResult.optimizationResult(), + stateTree.getContingencyScenarios(), finalPostContingencyResults, + raoParameters.getObjectiveFunctionParameters().getType(), + getFlowUnit(raoParameters), NUMBER_LOGGED_ELEMENTS_END_RAO); + RaoLogger.checkIfMostLimitingElementIsFictional(BUSINESS_LOGS, + stateTree.getBasecaseScenario(), + finalSecondPreventiveResult.optimizationResult(), + stateTree.getContingencyScenarios(), finalPostContingencyResults, + raoParameters.getObjectiveFunctionParameters().getType(), + getFlowUnit(raoParameters)); } - CompletableFuture raoResult = postCheckResults(mergedRaoResults, initialOutput, raoParameters.getObjectiveFunctionParameters(), true); + CompletableFuture raoResult = postCheckResults(mergedRaoResults, + initialOutput, raoParameters.getObjectiveFunctionParameters(), true); // PST regulation - Map pstsToRegulate = SearchTreeRaoPstRegulationParameters.getPstsToRegulate(raoParameters); + Map pstsToRegulate = SearchTreeRaoPstRegulationParameters.getPstsToRegulate( + raoParameters); if (!pstsToRegulate.isEmpty()) { BUSINESS_LOGS.info("----- PST regulation [start]"); network.getVariantManager().cloneVariant(INITIAL_SCENARIO, PST_REGULATION); network.getVariantManager().setWorkingVariant(PST_REGULATION); - Set pstRegulationResults = CastorPstRegulation.regulatePsts(pstsToRegulate, finalPostContingencyResults, network, crac, raoParameters, mergedRaoResults); - Map postRegulationResults = mergeRaoAndPstRegulationResults(pstRegulationResults, finalSecondPreventiveResult, finalPostContingencyResults, prePerimeterSensitivityAnalysis, initialOutput, toolProvider); + Set pstRegulationResults = CastorPstRegulation.regulatePsts( + pstsToRegulate, finalPostContingencyResults, network, crac, raoParameters, + mergedRaoResults); + Map postRegulationResults = mergeRaoAndPstRegulationResults( + pstRegulationResults, finalSecondPreventiveResult, finalPostContingencyResults, + prePerimeterSensitivityAnalysis, initialOutput, toolProvider); RaoResult raoResultWithRegulation = new PreventiveAndCurativesRaoResultImpl( stateTree, initialOutput, @@ -264,27 +344,46 @@ public CompletableFuture run() { raoResultWithRegulation.setExecutionDetails(mergedRaoResults.getExecutionDetails()); BUSINESS_LOGS.info("----- PST regulation [end]"); BUSINESS_LOGS.info("Merging RAO and PST regulation results:"); - RaoLogger.logMostLimitingElementsResults(BUSINESS_LOGS, stateTree.getBasecaseScenario(), finalSecondPreventiveResult.optimizationResult(), stateTree.getContingencyScenarios(), postRegulationResults, raoParameters.getObjectiveFunctionParameters().getType(), getFlowUnit(raoParameters), NUMBER_LOGGED_ELEMENTS_END_RAO); - RaoLogger.checkIfMostLimitingElementIsFictional(BUSINESS_LOGS, stateTree.getBasecaseScenario(), finalSecondPreventiveResult.optimizationResult(), stateTree.getContingencyScenarios(), postRegulationResults, raoParameters.getObjectiveFunctionParameters().getType(), getFlowUnit(raoParameters)); - return postCheckResults(raoResultWithRegulation, initialOutput, raoParameters.getObjectiveFunctionParameters(), false); + RaoLogger.logMostLimitingElementsResults(BUSINESS_LOGS, + stateTree.getBasecaseScenario(), + finalSecondPreventiveResult.optimizationResult(), + stateTree.getContingencyScenarios(), postRegulationResults, + raoParameters.getObjectiveFunctionParameters().getType(), + getFlowUnit(raoParameters), NUMBER_LOGGED_ELEMENTS_END_RAO); + RaoLogger.checkIfMostLimitingElementIsFictional(BUSINESS_LOGS, + stateTree.getBasecaseScenario(), + finalSecondPreventiveResult.optimizationResult(), + stateTree.getContingencyScenarios(), postRegulationResults, + raoParameters.getObjectiveFunctionParameters().getType(), + getFlowUnit(raoParameters)); + return postCheckResults(raoResultWithRegulation, initialOutput, + raoParameters.getObjectiveFunctionParameters(), false); } return raoResult; } catch (RuntimeException e) { BUSINESS_LOGS.error("{} \n {}", e.getMessage(), ExceptionUtils.getStackTrace(e)); - return CompletableFuture.completedFuture(new FailedRaoResultImpl(String.format("RAO failed during %s : %s", currentStep, e.getMessage()))); + return CompletableFuture.completedFuture(new FailedRaoResultImpl( + String.format("RAO failed during %s : %s", currentStep, e.getMessage()))); } } - private PostPerimeterResult computePostPreventiveResult(ToolProvider toolProvider, PrePerimeterResult initialOutput, OptimizationResult preventiveResult) { - PostPerimeterResult postPreventiveResult; - postPreventiveResult = new PostPerimeterSensitivityAnalysis(crac, crac.getFlowCnecs(), crac.getRangeActions(), raoParameters, toolProvider, true) - .runBasedOnInitialPreviousAndOptimizationResults(network, initialOutput, initialOutput, Collections.emptySet(), preventiveResult, null); - return postPreventiveResult; + private PostPerimeterResult computePostPreventiveResult(ToolProvider toolProvider, + PrePerimeterResult initialOutput, OptimizationResult preventiveResult) { + return OpenTelemetryReporter.withSpan("rao.postPreventiveEvaluation", cx -> { + PostPerimeterResult postPreventiveResult; + postPreventiveResult = new PostPerimeterSensitivityAnalysis(crac, crac.getFlowCnecs(), + crac.getRangeActions(), raoParameters, toolProvider, true) + .runBasedOnInitialPreviousAndOptimizationResults(network, initialOutput, + initialOutput, + Collections.emptySet(), preventiveResult, null); + return postPreventiveResult; + }); } private boolean shouldStopOptimisationIfPreventiveUnsecure(double preventiveOptimalCost) { - return raoParameters.getObjectiveFunctionParameters().getType().equals(ObjectiveFunctionParameters.ObjectiveFunctionType.SECURE_FLOW) + return raoParameters.getObjectiveFunctionParameters().getType() + .equals(ObjectiveFunctionParameters.ObjectiveFunctionType.SECURE_FLOW) && preventiveOptimalCost > 0 && !raoParameters.getObjectiveFunctionParameters().getEnforceCurativeSecurity(); } @@ -292,22 +391,35 @@ private boolean shouldStopOptimisationIfPreventiveUnsecure(double preventiveOpti /** * Return true if 2P has decreased cost */ - private boolean secondPreventiveImprovesResults(RaoResult secondPreventiveRaoResults, RaoResult mergedRaoResults) { + private boolean secondPreventiveImprovesResults(RaoResult secondPreventiveRaoResults, + RaoResult mergedRaoResults) { if (secondPreventiveRaoResults instanceof FailedRaoResultImpl) { BUSINESS_LOGS.info("Second preventive failed. Falling back to previous solution:"); return false; } - if (mergedRaoResults.getComputationStatus() == ComputationStatus.FAILURE && secondPreventiveRaoResults.getComputationStatus() != ComputationStatus.FAILURE) { - BUSINESS_LOGS.info("RAO has succeeded thanks to second preventive step when first preventive step had failed"); + if (mergedRaoResults.getComputationStatus() == ComputationStatus.FAILURE + && secondPreventiveRaoResults.getComputationStatus() != ComputationStatus.FAILURE) { + BUSINESS_LOGS.info( + "RAO has succeeded thanks to second preventive step when first preventive step had failed"); return true; } Instant curativeInstant = crac.getLastInstant(); double firstPreventiveCost = mergedRaoResults.getCost(curativeInstant); double secondPreventiveCost = secondPreventiveRaoResults.getCost(curativeInstant); if (secondPreventiveCost > firstPreventiveCost) { - BUSINESS_LOGS.info("Second preventive step has increased the overall cost from {} (functional: {}, virtual: {}) to {} (functional: {}, virtual: {}). Falling back to previous solution:", - formatDoubleBasedOnMargin(firstPreventiveCost, -firstPreventiveCost), formatDoubleBasedOnMargin(mergedRaoResults.getFunctionalCost(curativeInstant), -firstPreventiveCost), formatDoubleBasedOnMargin(mergedRaoResults.getVirtualCost(curativeInstant), -firstPreventiveCost), - formatDoubleBasedOnMargin(secondPreventiveCost, -secondPreventiveCost), formatDoubleBasedOnMargin(secondPreventiveRaoResults.getFunctionalCost(curativeInstant), -secondPreventiveCost), formatDoubleBasedOnMargin(secondPreventiveRaoResults.getVirtualCost(curativeInstant), -secondPreventiveCost)); + BUSINESS_LOGS.info( + "Second preventive step has increased the overall cost from {} (functional: {}, virtual: {}) to {} (functional: {}, virtual: {}). Falling back to previous solution:", + formatDoubleBasedOnMargin(firstPreventiveCost, -firstPreventiveCost), + formatDoubleBasedOnMargin(mergedRaoResults.getFunctionalCost(curativeInstant), + -firstPreventiveCost), + formatDoubleBasedOnMargin(mergedRaoResults.getVirtualCost(curativeInstant), + -firstPreventiveCost), + formatDoubleBasedOnMargin(secondPreventiveCost, -secondPreventiveCost), + formatDoubleBasedOnMargin( + secondPreventiveRaoResults.getFunctionalCost(curativeInstant), + -secondPreventiveCost), formatDoubleBasedOnMargin( + secondPreventiveRaoResults.getVirtualCost(curativeInstant), + -secondPreventiveCost)); return false; } return true; @@ -316,7 +428,9 @@ private boolean secondPreventiveImprovesResults(RaoResult secondPreventiveRaoRes /** * Return initial result if RAO has increased cost and handleCostIncrease is set to true */ - private CompletableFuture postCheckResults(RaoResult raoResult, PrePerimeterResult initialResult, ObjectiveFunctionParameters objectiveFunctionParameters, boolean handleCostIncrease) { + private CompletableFuture postCheckResults(RaoResult raoResult, + PrePerimeterResult initialResult, ObjectiveFunctionParameters objectiveFunctionParameters, + boolean handleCostIncrease) { RaoResult finalRaoResult = raoResult; double initialCost = initialResult.getCost(); @@ -328,74 +442,106 @@ private CompletableFuture postCheckResults(RaoResult raoResult, PrePe double finalVirtualCost = finalRaoResult.getVirtualCost(lastInstant); if (handleCostIncrease && finalCost > initialCost + EPSILON) { - BUSINESS_LOGS.info("RAO has increased the overall cost from {} (functional: {}, virtual: {}) to {} (functional: {}, virtual: {}). Falling back to initial solution:", - formatDoubleBasedOnMargin(initialCost, -initialCost), formatDoubleBasedOnMargin(initialFunctionalCost, -initialCost), formatDoubleBasedOnMargin(initialVirtualCost, -initialCost), - formatDoubleBasedOnMargin(finalCost, -finalCost), formatDoubleBasedOnMargin(finalFunctionalCost, -finalCost), formatDoubleBasedOnMargin(finalVirtualCost, -finalCost)); + BUSINESS_LOGS.info( + "RAO has increased the overall cost from {} (functional: {}, virtual: {}) to {} (functional: {}, virtual: {}). Falling back to initial solution:", + formatDoubleBasedOnMargin(initialCost, -initialCost), + formatDoubleBasedOnMargin(initialFunctionalCost, -initialCost), + formatDoubleBasedOnMargin(initialVirtualCost, -initialCost), + formatDoubleBasedOnMargin(finalCost, -finalCost), + formatDoubleBasedOnMargin(finalFunctionalCost, -finalCost), + formatDoubleBasedOnMargin(finalVirtualCost, -finalCost)); // log results - RaoLogger.logMostLimitingElementsResults(BUSINESS_LOGS, initialResult, objectiveFunctionParameters.getType(), getFlowUnit(raoParameters), NUMBER_LOGGED_ELEMENTS_END_RAO); + RaoLogger.logMostLimitingElementsResults(BUSINESS_LOGS, initialResult, + objectiveFunctionParameters.getType(), getFlowUnit(raoParameters), + NUMBER_LOGGED_ELEMENTS_END_RAO); finalRaoResult = new UnoptimizedRaoResultImpl(initialResult); finalCost = initialCost; finalFunctionalCost = initialFunctionalCost; finalVirtualCost = initialVirtualCost; - if (raoResult.getExecutionDetails().equals(OptimizationStepsExecuted.FIRST_PREVENTIVE_ONLY)) { - finalRaoResult.setExecutionDetails(OptimizationStepsExecuted.FIRST_PREVENTIVE_FELLBACK_TO_INITIAL_SITUATION); + if (raoResult.getExecutionDetails() + .equals(OptimizationStepsExecuted.FIRST_PREVENTIVE_ONLY)) { + finalRaoResult.setExecutionDetails( + OptimizationStepsExecuted.FIRST_PREVENTIVE_FELLBACK_TO_INITIAL_SITUATION); } else { - finalRaoResult.setExecutionDetails(OptimizationStepsExecuted.SECOND_PREVENTIVE_FELLBACK_TO_INITIAL_SITUATION); + finalRaoResult.setExecutionDetails( + OptimizationStepsExecuted.SECOND_PREVENTIVE_FELLBACK_TO_INITIAL_SITUATION); } } Map initialVirtualCostDetailed = getVirtualCostDetailed(initialResult); - Map finalVirtualCostDetailed = getVirtualCostDetailed(finalRaoResult, crac.getLastInstant()); + Map finalVirtualCostDetailed = getVirtualCostDetailed(finalRaoResult, + crac.getLastInstant()); // Log costs before and after RAO - BUSINESS_LOGS.info("Cost before RAO = {} (functional: {}, virtual: {}{}), cost after RAO = {} (functional: {}, virtual: {}{})", - formatDoubleBasedOnMargin(initialCost, -initialCost), formatDoubleBasedOnMargin(initialFunctionalCost, -initialCost), formatDoubleBasedOnMargin(initialVirtualCost, -initialCost), + BUSINESS_LOGS.info( + "Cost before RAO = {} (functional: {}, virtual: {}{}), cost after RAO = {} (functional: {}, virtual: {}{})", + formatDoubleBasedOnMargin(initialCost, -initialCost), + formatDoubleBasedOnMargin(initialFunctionalCost, -initialCost), + formatDoubleBasedOnMargin(initialVirtualCost, -initialCost), initialVirtualCostDetailed.isEmpty() ? "" : " " + initialVirtualCostDetailed, - formatDoubleBasedOnMargin(finalCost, -finalCost), formatDoubleBasedOnMargin(finalFunctionalCost, -finalCost), formatDoubleBasedOnMargin(finalVirtualCost, -finalCost), + formatDoubleBasedOnMargin(finalCost, -finalCost), + formatDoubleBasedOnMargin(finalFunctionalCost, -finalCost), + formatDoubleBasedOnMargin(finalVirtualCost, -finalCost), finalVirtualCostDetailed.isEmpty() ? "" : " " + finalVirtualCostDetailed); return CompletableFuture.completedFuture(finalRaoResult); } - private Pair> optimizePreventivePerimeter(StateTree stateTree, ToolProvider toolProvider, PrePerimeterResult initialResult) { - - PreventiveOptimizationPerimeter optPerimeter = PreventiveOptimizationPerimeter.buildFromBasecaseScenario(stateTree.getBasecaseScenario(), crac, network, raoParameters, initialResult); - - SearchTreeParameters.SearchTreeParametersBuilder searchTreeParametersBuilder = SearchTreeParameters.create() - .withConstantParametersOverAllRao(raoParameters, crac) - .withTreeParameters(TreeParameters.buildForPreventivePerimeter(raoParameters)) - .withUnoptimizedCnecParameters(UnoptimizedCnecParameters.build(raoParameters.getNotOptimizedCnecsParameters(), stateTree.getOperatorsNotSharingCras())); - - if (!getHvdcRangeActionsOnHvdcLineInAcEmulation(crac.getHvdcRangeActions(), network).isEmpty()) { - LoadFlowAndSensitivityParameters loadFlowAndSensitivityParameters = - raoParameters.hasExtension(OpenRaoSearchTreeParameters.class) - ? raoParameters.getExtension(OpenRaoSearchTreeParameters.class).getLoadFlowAndSensitivityParameters() - : new LoadFlowAndSensitivityParameters(); - searchTreeParametersBuilder.withLoadFlowAndSensitivityParameters(loadFlowAndSensitivityParameters); - } + private Pair> optimizePreventivePerimeter(StateTree stateTree, + ToolProvider toolProvider, PrePerimeterResult initialResult) { + return OpenTelemetryReporter.withSpan("rao.optimizePreventivePerimeter", cx -> { + PreventiveOptimizationPerimeter optPerimeter = PreventiveOptimizationPerimeter.buildFromBasecaseScenario( + stateTree.getBasecaseScenario(), crac, network, raoParameters, initialResult); + + SearchTreeParameters.SearchTreeParametersBuilder searchTreeParametersBuilder = SearchTreeParameters.create() + .withConstantParametersOverAllRao(raoParameters, crac) + .withTreeParameters(TreeParameters.buildForPreventivePerimeter(raoParameters)) + .withUnoptimizedCnecParameters( + UnoptimizedCnecParameters.build(raoParameters.getNotOptimizedCnecsParameters(), + stateTree.getOperatorsNotSharingCras())); + + if (!getHvdcRangeActionsOnHvdcLineInAcEmulation(crac.getHvdcRangeActions(), + network).isEmpty()) { + LoadFlowAndSensitivityParameters loadFlowAndSensitivityParameters = + raoParameters.hasExtension(OpenRaoSearchTreeParameters.class) + ? raoParameters.getExtension(OpenRaoSearchTreeParameters.class) + .getLoadFlowAndSensitivityParameters() + : new LoadFlowAndSensitivityParameters(); + searchTreeParametersBuilder.withLoadFlowAndSensitivityParameters( + loadFlowAndSensitivityParameters); + } - SearchTreeParameters searchTreeParameters = searchTreeParametersBuilder.build(); - - Set statesToOptimize = new HashSet<>(optPerimeter.getMonitoredStates()); - statesToOptimize.add(optPerimeter.getMainOptimizationState()); - - SearchTreeInput searchTreeInput = SearchTreeInput.create() - .withNetwork(network) - .withOptimizationPerimeter(optPerimeter) - .withInitialFlowResult(initialResult) - .withPrePerimeterResult(initialResult) - .withPreOptimizationAppliedNetworkActions(new AppliedRemedialActions()) //no remedial Action applied - .withObjectiveFunction(ObjectiveFunction.build(optPerimeter.getFlowCnecs(), optPerimeter.getLoopFlowCnecs(), initialResult, initialResult, Collections.emptySet(), raoParameters, statesToOptimize)) - .withToolProvider(toolProvider) - .withOutageInstant(crac.getOutageInstant()) - .build(); - - OptimizationResult optResult = new SearchTree(searchTreeInput, searchTreeParameters, true).run().join(); - applyRemedialActions(network, optResult, crac.getPreventiveState()); - return Pair.of(optResult, optPerimeter.getFlowCnecs()); + SearchTreeParameters searchTreeParameters = searchTreeParametersBuilder.build(); + + Set statesToOptimize = new HashSet<>(optPerimeter.getMonitoredStates()); + statesToOptimize.add(optPerimeter.getMainOptimizationState()); + + SearchTreeInput searchTreeInput = SearchTreeInput.create() + .withNetwork(network) + .withOptimizationPerimeter(optPerimeter) + .withInitialFlowResult(initialResult) + .withPrePerimeterResult(initialResult) + .withPreOptimizationAppliedNetworkActions( + new AppliedRemedialActions()) //no remedial Action applied + .withObjectiveFunction(ObjectiveFunction.build(optPerimeter.getFlowCnecs(), + optPerimeter.getLoopFlowCnecs(), initialResult, initialResult, + Collections.emptySet(), raoParameters, statesToOptimize)) + .withToolProvider(toolProvider) + .withOutageInstant(crac.getOutageInstant()) + .build(); + + OptimizationResult optResult = new SearchTree(searchTreeInput, searchTreeParameters, + true).run().join(); + applyRemedialActions(network, optResult, crac.getPreventiveState()); + return Pair.of(optResult, optPerimeter.getFlowCnecs()); + }); } - private Map mergeRaoAndPstRegulationResults(Set pstRegulationResults, PostPerimeterResult postPraResult, Map postContingencyResults, PrePerimeterSensitivityAnalysis prePerimeterSensitivityAnalysis, FlowResult initialFlowResult, ToolProvider toolProvider) { + private Map mergeRaoAndPstRegulationResults( + Set pstRegulationResults, PostPerimeterResult postPraResult, + Map postContingencyResults, + PrePerimeterSensitivityAnalysis prePerimeterSensitivityAnalysis, + FlowResult initialFlowResult, ToolProvider toolProvider) { // create a new network variant from initial variant for performing the results merging String variantName = "PSTRegulationResultsMerging"; network.getVariantManager().setWorkingVariant(INITIAL_SCENARIO); @@ -403,31 +549,49 @@ private Map mergeRaoAndPstRegulationResults(Set regulatedStates = pstRegulationResults.stream().map(pstRegulationResult -> crac.getState(pstRegulationResult.contingency().getId(), crac.getLastInstant())).collect(Collectors.toSet()); + Set regulatedStates = pstRegulationResults.stream().map( + pstRegulationResult -> crac.getState(pstRegulationResult.contingency().getId(), + crac.getLastInstant())).collect(Collectors.toSet()); Map> appliedNetworkActions = new HashMap<>(); // gather all applied ARAs and CRAs AppliedRemedialActions appliedRemedialActions = new AppliedRemedialActions(); postContingencyResults.forEach((state, postPerimeterResult) -> { - appliedNetworkActions.put(state, postPerimeterResult.optimizationResult().getActivatedNetworkActions()); - appliedRemedialActions.addAppliedNetworkActions(state, postPerimeterResult.optimizationResult().getActivatedNetworkActions()); - appliedRemedialActions.addAppliedRangeActions(state, getAppliedRangeActionsAndSetPoint(state, postPraResult.optimizationResult())); - appliedRemedialActions.addAppliedRangeActions(state, getAppliedRangeActionsAndSetPoint(state, postPerimeterResult.optimizationResult())); + appliedNetworkActions.put(state, + postPerimeterResult.optimizationResult().getActivatedNetworkActions()); + appliedRemedialActions.addAppliedNetworkActions(state, + postPerimeterResult.optimizationResult().getActivatedNetworkActions()); + appliedRemedialActions.addAppliedRangeActions(state, + getAppliedRangeActionsAndSetPoint(state, postPraResult.optimizationResult())); + appliedRemedialActions.addAppliedRangeActions(state, + getAppliedRangeActionsAndSetPoint(state, postPerimeterResult.optimizationResult())); }); // overwrite PST range action results for regulated PSTs - pstRegulationResults.forEach(pstRegulationResult -> pstRegulationResult.regulatedTapPerPst().forEach((pstRangeAction, regulatedTap) -> appliedRemedialActions.addAppliedRangeAction(crac.getState(pstRegulationResult.contingency().getId(), crac.getLastInstant()), pstRangeAction, pstRangeAction.convertTapToAngle(regulatedTap)))); + pstRegulationResults.forEach(pstRegulationResult -> pstRegulationResult.regulatedTapPerPst() + .forEach((pstRangeAction, regulatedTap) -> appliedRemedialActions.addAppliedRangeAction( + crac.getState(pstRegulationResult.contingency().getId(), crac.getLastInstant()), + pstRangeAction, pstRangeAction.convertTapToAngle(regulatedTap)))); - PrePerimeterResult postCraSensitivityAnalysisOutput = prePerimeterSensitivityAnalysis.runBasedOnInitialResults(network, initialFlowResult, Collections.emptySet(), appliedRemedialActions); + PrePerimeterResult postCraSensitivityAnalysisOutput = prePerimeterSensitivityAnalysis.runBasedOnInitialResults( + network, initialFlowResult, Collections.emptySet(), appliedRemedialActions); Map postRegulationPostContingencyResults = new HashMap<>(); // override optimization result - RangeActionActivationResultImpl postRegulationRangeActionActivationResult = new RangeActionActivationResultImpl(postCraSensitivityAnalysisOutput); - postContingencyResults.keySet().forEach(state -> appliedRemedialActions.getAppliedRangeActions(state).forEach((rangeAction, setPoint) -> postRegulationRangeActionActivationResult.putResult(rangeAction, state, setPoint))); - OptimizationResult newOptimizationResult = new OptimizationResultImpl(postCraSensitivityAnalysisOutput, postCraSensitivityAnalysisOutput, postCraSensitivityAnalysisOutput, new NetworkActionsResultImpl(appliedNetworkActions), postRegulationRangeActionActivationResult); + RangeActionActivationResultImpl postRegulationRangeActionActivationResult = new RangeActionActivationResultImpl( + postCraSensitivityAnalysisOutput); + postContingencyResults.keySet().forEach( + state -> appliedRemedialActions.getAppliedRangeActions(state).forEach( + (rangeAction, setPoint) -> postRegulationRangeActionActivationResult.putResult( + rangeAction, state, setPoint))); + OptimizationResult newOptimizationResult = new OptimizationResultImpl( + postCraSensitivityAnalysisOutput, postCraSensitivityAnalysisOutput, + postCraSensitivityAnalysisOutput, new NetworkActionsResultImpl(appliedNetworkActions), + postRegulationRangeActionActivationResult); for (State state : postContingencyResults.keySet()) { // For instants before pst regulation instant, keep previous results @@ -436,7 +600,8 @@ private Map mergeRaoAndPstRegulationResults(Set mergeRaoAndPstRegulationResults(Set, Double> getAppliedRangeActionsAndSetPoint(State state, OptimizationResult optimizationResult) { + private static Map, Double> getAppliedRangeActionsAndSetPoint(State state, + OptimizationResult optimizationResult) { Map, Double> optimizedRangeActions = new HashMap<>(); - optimizationResult.getActivatedRangeActions(state).forEach(rangeAction -> optimizedRangeActions.put(rangeAction, optimizationResult.getOptimizedSetpoint(rangeAction, state))); + optimizationResult.getActivatedRangeActions(state).forEach( + rangeAction -> optimizedRangeActions.put(rangeAction, + optimizationResult.getOptimizedSetpoint(rangeAction, state))); return optimizedRangeActions; } } diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/PostPerimeterSensitivityAnalysis.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/PostPerimeterSensitivityAnalysis.java index 016b4a4584..71fb278d09 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/PostPerimeterSensitivityAnalysis.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/PostPerimeterSensitivityAnalysis.java @@ -7,8 +7,11 @@ package com.powsybl.openrao.searchtreerao.castor.algorithm; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.TECHNICAL_LOGS; + import com.powsybl.iidm.network.Network; import com.powsybl.openrao.commons.OpenRaoException; +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; import com.powsybl.openrao.data.crac.api.Crac; import com.powsybl.openrao.data.crac.api.State; import com.powsybl.openrao.data.crac.api.cnec.FlowCnec; @@ -18,39 +21,47 @@ import com.powsybl.openrao.searchtreerao.commons.SensitivityComputer; import com.powsybl.openrao.searchtreerao.commons.ToolProvider; import com.powsybl.openrao.searchtreerao.commons.objectivefunction.ObjectiveFunction; -import com.powsybl.openrao.searchtreerao.result.api.*; -import com.powsybl.openrao.searchtreerao.result.impl.*; +import com.powsybl.openrao.searchtreerao.result.api.FlowResult; +import com.powsybl.openrao.searchtreerao.result.api.ObjectiveFunctionResult; +import com.powsybl.openrao.searchtreerao.result.api.OptimizationResult; +import com.powsybl.openrao.searchtreerao.result.api.PrePerimeterResult; +import com.powsybl.openrao.searchtreerao.result.api.RemedialActionActivationResult; +import com.powsybl.openrao.searchtreerao.result.api.SensitivityResult; +import com.powsybl.openrao.searchtreerao.result.impl.OptimizationResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.PostPerimeterResult; +import com.powsybl.openrao.searchtreerao.result.impl.PrePerimeterSensitivityResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.RangeActionSetpointResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.RemedialActionActivationResultImpl; import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions; - import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; -import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.TECHNICAL_LOGS; - /** - * This class aims at performing the sensitivity analysis after the optimization of a perimeter. The result can be used as a - * starting point for the next perimeter, but it is also needed for the costs, margins and flows of elements after an optimization instant. + * This class aims at performing the sensitivity analysis after the optimization of a perimeter. The + * result can be used as a starting point for the next perimeter, but it is also needed for the + * costs, margins and flows of elements after an optimization instant. * * @author Philippe Edwards {@literal } */ public class PostPerimeterSensitivityAnalysis extends AbstractMultiPerimeterSensitivityAnalysis { public PostPerimeterSensitivityAnalysis(Crac crac, - Set flowCnecs, - Set> rangeActions, - RaoParameters raoParameters, - ToolProvider toolProvider, - boolean multiThreadedSensitivities) { - super(crac, flowCnecs, rangeActions, raoParameters, toolProvider, multiThreadedSensitivities); + Set flowCnecs, + Set> rangeActions, + RaoParameters raoParameters, + ToolProvider toolProvider, + boolean multiThreadedSensitivities) { + super(crac, flowCnecs, rangeActions, raoParameters, toolProvider, + multiThreadedSensitivities); } public PostPerimeterSensitivityAnalysis(Crac crac, - Set states, - RaoParameters raoParameters, - ToolProvider toolProvider, - boolean multiThreadedSensitivities) { + Set states, + RaoParameters raoParameters, + ToolProvider toolProvider, + boolean multiThreadedSensitivities) { super(crac, states, raoParameters, toolProvider, multiThreadedSensitivities); } @@ -63,81 +74,97 @@ public PostPerimeterSensitivityAnalysis(Crac crac, * */ public PostPerimeterResult runBasedOnInitialPreviousAndOptimizationResults(Network network, - FlowResult initialFlowResult, - PrePerimeterResult previousResultsFuture, - Set operatorsNotSharingCras, - OptimizationResult optimizationResult, - AppliedRemedialActions appliedCurativeRemedialActions) { - - AtomicReference flowResult = new AtomicReference<>(); - AtomicReference sensitivityResult = new AtomicReference<>(); - boolean actionWasTaken = actionWasTaken(optimizationResult.getActivatedNetworkActions(), optimizationResult.getActivatedRangeActionsPerState()); - if (actionWasTaken) { - SensitivityComputer sensitivityComputer = buildSensitivityComputer(initialFlowResult, appliedCurativeRemedialActions); - - int oldThreadCount = setNewThreadCountAndGetOldValue(); - sensitivityComputer.compute(network); - resetThreadCount(oldThreadCount); - flowResult.set(sensitivityComputer.getBranchResult(network)); - sensitivityResult.set(sensitivityComputer.getSensitivityResult()); - } else { - flowResult.set(previousResultsFuture); - sensitivityResult.set(previousResultsFuture); - } + FlowResult initialFlowResult, + PrePerimeterResult previousResultsFuture, + Set operatorsNotSharingCras, + OptimizationResult optimizationResult, + AppliedRemedialActions appliedCurativeRemedialActions) { + return OpenTelemetryReporter.withSpan("rao.runBasedOnInitialPreviousAndOptimizationResults", + cx -> { + AtomicReference flowResult = new AtomicReference<>(); + AtomicReference sensitivityResult = new AtomicReference<>(); + boolean actionWasTaken = actionWasTaken( + optimizationResult.getActivatedNetworkActions(), + optimizationResult.getActivatedRangeActionsPerState()); + if (actionWasTaken) { + SensitivityComputer sensitivityComputer = buildSensitivityComputer( + initialFlowResult, + appliedCurativeRemedialActions); + + int oldThreadCount = setNewThreadCountAndGetOldValue(); + sensitivityComputer.compute(network); + resetThreadCount(oldThreadCount); + flowResult.set(sensitivityComputer.getBranchResult(network)); + sensitivityResult.set(sensitivityComputer.getSensitivityResult()); + } else { + flowResult.set(previousResultsFuture); + sensitivityResult.set(previousResultsFuture); + } + + ObjectiveFunction objectiveFunction = ObjectiveFunction.build( + flowCnecs, + toolProvider.getLoopFlowCnecs(flowCnecs), + initialFlowResult, + previousResultsFuture, + operatorsNotSharingCras, + raoParameters, + optimizationResult.getActivatedRangeActionsPerState().keySet() + ); + + ObjectiveFunctionResult objectiveFunctionResult = objectiveFunction.evaluate( + flowResult.get(), + new RemedialActionActivationResultImpl(optimizationResult, optimizationResult) + ); - ObjectiveFunction objectiveFunction = ObjectiveFunction.build( - flowCnecs, - toolProvider.getLoopFlowCnecs(flowCnecs), - initialFlowResult, - previousResultsFuture, - operatorsNotSharingCras, - raoParameters, - optimizationResult.getActivatedRangeActionsPerState().keySet() - ); - - ObjectiveFunctionResult objectiveFunctionResult = objectiveFunction.evaluate( - flowResult.get(), - new RemedialActionActivationResultImpl(optimizationResult, optimizationResult) - ); - - return new PostPerimeterResult(optimizationResult, new PrePerimeterSensitivityResultImpl( - flowResult.get(), - sensitivityResult.get(), - RangeActionSetpointResultImpl.buildWithSetpointsFromNetwork(network, rangeActions), - objectiveFunctionResult - )); + return new PostPerimeterResult(optimizationResult, + new PrePerimeterSensitivityResultImpl( + flowResult.get(), + sensitivityResult.get(), + RangeActionSetpointResultImpl.buildWithSetpointsFromNetwork(network, + rangeActions), + objectiveFunctionResult + )); + }); } /** *

* Asynchronously runs a post-perimeter computation - * - * If a remedial action was taken, it performs a sensitivity analysis. - * Otherwise, it waits and retrieves the pre-perimeter results from the {@code previousResultsFuture}. - * After computations, the objective function is evaluated and a {@link PostPerimeterResult} is constructed and returned. + *

+ * If a remedial action was taken, it performs a sensitivity analysis. Otherwise, it waits and + * retrieves the pre-perimeter results from the {@code previousResultsFuture}. After + * computations, the objective function is evaluated and a {@link PostPerimeterResult} is + * constructed and returned. *

* - * @param network the network instance on which computations are performed + * @param network the network instance on which computations are + * performed * @param initialFlowResult the initial flow result - * @param previousResultsFuture a future providing the results of the previous perimeter + * @param previousResultsFuture a future providing the results of the previous + * perimeter * @param operatorsNotSharingCras the set of operators not sharing CRAs - * @param remedialActionActivationResult the set of remedial actions that were activated in the previous perimeter + * @param remedialActionActivationResult the set of remedial actions that were activated in the + * previous perimeter * @param appliedCurativeRemedialActions the applied curative remedial actions for 2P * @return a {@code Future} */ - public CompletableFuture runAsyncBasedOnInitialPreviousAndActivatedRa(Network network, - FlowResult initialFlowResult, - CompletableFuture previousResultsFuture, - Set operatorsNotSharingCras, - RemedialActionActivationResult remedialActionActivationResult, - AppliedRemedialActions appliedCurativeRemedialActions) { + public CompletableFuture runAsyncBasedOnInitialPreviousAndActivatedRa( + Network network, + FlowResult initialFlowResult, + CompletableFuture previousResultsFuture, + Set operatorsNotSharingCras, + RemedialActionActivationResult remedialActionActivationResult, + AppliedRemedialActions appliedCurativeRemedialActions) { return CompletableFuture.supplyAsync(() -> { AtomicReference flowResult = new AtomicReference<>(); AtomicReference sensitivityResult = new AtomicReference<>(); - boolean actionWasTaken = actionWasTaken(remedialActionActivationResult.getActivatedNetworkActions(), remedialActionActivationResult.getActivatedRangeActionsPerState()); + boolean actionWasTaken = actionWasTaken( + remedialActionActivationResult.getActivatedNetworkActions(), + remedialActionActivationResult.getActivatedRangeActionsPerState()); if (actionWasTaken) { - SensitivityComputer sensitivityComputer = buildSensitivityComputer(initialFlowResult, appliedCurativeRemedialActions); + SensitivityComputer sensitivityComputer = buildSensitivityComputer( + initialFlowResult, appliedCurativeRemedialActions); int oldThreadCount = setNewThreadCountAndGetOldValue(); sensitivityComputer.compute(network); @@ -179,18 +206,23 @@ public CompletableFuture runAsyncBasedOnInitialPreviousAndA flowResult.get(), remedialActionActivationResult ); - OptimizationResult optimizationResult = new OptimizationResultImpl(objectiveFunctionResult, flowResult.get(), sensitivityResult.get(), remedialActionActivationResult, remedialActionActivationResult); - - return new PostPerimeterResult(optimizationResult, new PrePerimeterSensitivityResultImpl( - flowResult.get(), - sensitivityResult.get(), - RangeActionSetpointResultImpl.buildWithSetpointsFromNetwork(network, rangeActions), - objectiveFunctionResult - )); + OptimizationResult optimizationResult = new OptimizationResultImpl( + objectiveFunctionResult, flowResult.get(), sensitivityResult.get(), + remedialActionActivationResult, remedialActionActivationResult); + + return new PostPerimeterResult(optimizationResult, + new PrePerimeterSensitivityResultImpl( + flowResult.get(), + sensitivityResult.get(), + RangeActionSetpointResultImpl.buildWithSetpointsFromNetwork(network, + rangeActions), + objectiveFunctionResult + )); }); } - private boolean actionWasTaken(Set activatedNetworkActions, Map>> activatedRangeActionsPerState) { + private boolean actionWasTaken(Set activatedNetworkActions, + Map>> activatedRangeActionsPerState) { if (!activatedNetworkActions.isEmpty()) { return true; } diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/PrePerimeterSensitivityAnalysis.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/PrePerimeterSensitivityAnalysis.java index 6daa29c207..19bcb47597 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/PrePerimeterSensitivityAnalysis.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/PrePerimeterSensitivityAnalysis.java @@ -7,27 +7,31 @@ package com.powsybl.openrao.searchtreerao.castor.algorithm; +import com.powsybl.iidm.network.Network; +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; import com.powsybl.openrao.data.crac.api.Crac; import com.powsybl.openrao.data.crac.api.State; import com.powsybl.openrao.data.crac.api.cnec.FlowCnec; import com.powsybl.openrao.data.crac.api.rangeaction.RangeAction; import com.powsybl.openrao.raoapi.parameters.RaoParameters; -import com.powsybl.openrao.searchtreerao.result.api.*; -import com.powsybl.openrao.searchtreerao.result.impl.PrePerimeterSensitivityResultImpl; import com.powsybl.openrao.searchtreerao.commons.SensitivityComputer; import com.powsybl.openrao.searchtreerao.commons.ToolProvider; import com.powsybl.openrao.searchtreerao.commons.objectivefunction.ObjectiveFunction; +import com.powsybl.openrao.searchtreerao.result.api.FlowResult; +import com.powsybl.openrao.searchtreerao.result.api.ObjectiveFunctionResult; +import com.powsybl.openrao.searchtreerao.result.api.PrePerimeterResult; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionSetpointResult; +import com.powsybl.openrao.searchtreerao.result.api.SensitivityResult; +import com.powsybl.openrao.searchtreerao.result.impl.PrePerimeterSensitivityResultImpl; import com.powsybl.openrao.searchtreerao.result.impl.RangeActionSetpointResultImpl; import com.powsybl.openrao.searchtreerao.result.impl.RemedialActionActivationResultImpl; import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions; -import com.powsybl.iidm.network.Network; - import java.util.Set; /** - * This class aims at performing the sensitivity analysis before the optimization of a perimeter. At these specific - * instants we actually want to compute all the results on the network. They will be useful either for the optimization - * or to fill results in the final output. + * This class aims at performing the sensitivity analysis before the optimization of a perimeter. At + * these specific instants we actually want to compute all the results on the network. They will be + * useful either for the optimization or to fill results in the final output. * * @author Baptiste Seguinot {@literal } */ @@ -38,41 +42,57 @@ public class PrePerimeterSensitivityAnalysis extends AbstractMultiPerimeterSensi private ObjectiveFunction objectiveFunction; public PrePerimeterSensitivityAnalysis(Crac crac, - Set flowCnecs, - Set> rangeActions, - RaoParameters raoParameters, - ToolProvider toolProvider, - boolean multiThreadedSensitivities) { - super(crac, flowCnecs, rangeActions, raoParameters, toolProvider, multiThreadedSensitivities); + Set flowCnecs, + Set> rangeActions, + RaoParameters raoParameters, + ToolProvider toolProvider, + boolean multiThreadedSensitivities) { + super(crac, flowCnecs, rangeActions, raoParameters, toolProvider, + multiThreadedSensitivities); } public PrePerimeterResult runInitialSensitivityAnalysis(Network network) { - return runInitialSensitivityAnalysis(network, Set.of()); + return OpenTelemetryReporter.withSpan("rao.runInitialSensitivityAnalysis", cx -> { + return runInitialSensitivityAnalysis(network, Set.of()); + }); } - public PrePerimeterResult runInitialSensitivityAnalysis(Network network, Set optimizedStates) { - SensitivityComputer.SensitivityComputerBuilder sensitivityComputerBuilder = buildSensiBuilder() - .withOutageInstant(crac.getOutageInstant()); - if (raoParameters.getLoopFlowParameters().isPresent()) { - sensitivityComputerBuilder.withCommercialFlowsResults(toolProvider.getLoopFlowComputation(), toolProvider.getLoopFlowCnecs(flowCnecs)); - } - if (raoParameters.getObjectiveFunctionParameters().getType().relativePositiveMargins()) { - sensitivityComputerBuilder.withPtdfsResults(toolProvider.getAbsolutePtdfSumsComputation(), flowCnecs); - } - - sensitivityComputer = sensitivityComputerBuilder.build(); - objectiveFunction = ObjectiveFunction.buildForInitialSensitivityComputation(flowCnecs, raoParameters, optimizedStates); - - return runAndGetResult(network, objectiveFunction); + public PrePerimeterResult runInitialSensitivityAnalysis(Network network, + Set optimizedStates) { + return OpenTelemetryReporter.withSpan("rao.runSensitivityAnalysisBasedOnInitialResults", + cx -> { + SensitivityComputer.SensitivityComputerBuilder sensitivityComputerBuilder = buildSensiBuilder() + .withOutageInstant(crac.getOutageInstant()); + if (raoParameters.getLoopFlowParameters().isPresent()) { + sensitivityComputerBuilder.withCommercialFlowsResults( + toolProvider.getLoopFlowComputation(), + toolProvider.getLoopFlowCnecs(flowCnecs)); + } + if (raoParameters.getObjectiveFunctionParameters().getType() + .relativePositiveMargins()) { + sensitivityComputerBuilder.withPtdfsResults( + toolProvider.getAbsolutePtdfSumsComputation(), flowCnecs); + } + + sensitivityComputer = sensitivityComputerBuilder.build(); + objectiveFunction = ObjectiveFunction.buildForInitialSensitivityComputation( + flowCnecs, + raoParameters, optimizedStates); + + return runAndGetResult(network, objectiveFunction); + }); } public PrePerimeterResult runBasedOnInitialResults(Network network, - FlowResult initialFlowResult, - Set operatorsNotSharingCras, - AppliedRemedialActions appliedCurativeRemedialActions) { + FlowResult initialFlowResult, + Set operatorsNotSharingCras, + AppliedRemedialActions appliedCurativeRemedialActions) { - sensitivityComputer = buildSensitivityComputer(initialFlowResult, appliedCurativeRemedialActions); - objectiveFunction = ObjectiveFunction.build(flowCnecs, toolProvider.getLoopFlowCnecs(flowCnecs), initialFlowResult, initialFlowResult, operatorsNotSharingCras, raoParameters, Set.of(crac.getPreventiveState())); + sensitivityComputer = buildSensitivityComputer(initialFlowResult, + appliedCurativeRemedialActions); + objectiveFunction = ObjectiveFunction.build(flowCnecs, + toolProvider.getLoopFlowCnecs(flowCnecs), initialFlowResult, initialFlowResult, + operatorsNotSharingCras, raoParameters, Set.of(crac.getPreventiveState())); return runAndGetResult(network, objectiveFunction); } @@ -83,24 +103,27 @@ public ObjectiveFunction getObjectiveFunction() { private SensitivityComputer.SensitivityComputerBuilder buildSensiBuilder() { return SensitivityComputer.create() - .withToolProvider(toolProvider) - .withCnecs(flowCnecs) - .withRangeActions(rangeActions); + .withToolProvider(toolProvider) + .withCnecs(flowCnecs) + .withRangeActions(rangeActions); } - private PrePerimeterResult runAndGetResult(Network network, ObjectiveFunction objectiveFunction) { + private PrePerimeterResult runAndGetResult(Network network, + ObjectiveFunction objectiveFunction) { int oldThreadCount = setNewThreadCountAndGetOldValue(); sensitivityComputer.compute(network); resetThreadCount(oldThreadCount); FlowResult flowResult = sensitivityComputer.getBranchResult(network); SensitivityResult sensitivityResult = sensitivityComputer.getSensitivityResult(); - RangeActionSetpointResult rangeActionSetpointResult = RangeActionSetpointResultImpl.buildWithSetpointsFromNetwork(network, rangeActions); - ObjectiveFunctionResult objectiveFunctionResult = objectiveFunction.evaluate(flowResult, RemedialActionActivationResultImpl.empty(rangeActionSetpointResult)); + RangeActionSetpointResult rangeActionSetpointResult = RangeActionSetpointResultImpl.buildWithSetpointsFromNetwork( + network, rangeActions); + ObjectiveFunctionResult objectiveFunctionResult = objectiveFunction.evaluate(flowResult, + RemedialActionActivationResultImpl.empty(rangeActionSetpointResult)); return new PrePerimeterSensitivityResultImpl( - flowResult, - sensitivityResult, - rangeActionSetpointResult, - objectiveFunctionResult + flowResult, + sensitivityResult, + rangeActionSetpointResult, + objectiveFunctionResult ); } } diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/CastorPstRegulation.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/CastorPstRegulation.java index caf17327d9..7be5fb7e09 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/CastorPstRegulation.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/CastorPstRegulation.java @@ -7,12 +7,18 @@ package com.powsybl.openrao.searchtreerao.castor.algorithm.pstregulation; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_LOGS; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_WARNS; +import static com.powsybl.openrao.raoapi.parameters.extensions.MultithreadingParameters.getAvailableCPUs; +import static com.powsybl.openrao.searchtreerao.commons.RaoUtil.getFlowUnit; + import com.powsybl.contingency.Contingency; import com.powsybl.iidm.network.Network; import com.powsybl.loadflow.LoadFlowParameters; import com.powsybl.openloadflow.OpenLoadFlowParameters; import com.powsybl.openrao.commons.OpenRaoException; import com.powsybl.openrao.commons.Unit; +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; import com.powsybl.openrao.data.crac.api.Crac; import com.powsybl.openrao.data.crac.api.Identifiable; import com.powsybl.openrao.data.crac.api.Instant; @@ -26,7 +32,6 @@ import com.powsybl.openrao.searchtreerao.result.impl.PostPerimeterResult; import com.powsybl.openrao.searchtreerao.result.impl.SkippedOptimizationResultImpl; import com.powsybl.openrao.util.AbstractNetworkPool; - import java.util.ArrayList; import java.util.Comparator; import java.util.HashSet; @@ -40,34 +45,42 @@ import java.util.function.Function; import java.util.stream.Collectors; -import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_LOGS; -import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_WARNS; -import static com.powsybl.openrao.raoapi.parameters.extensions.MultithreadingParameters.getAvailableCPUs; -import static com.powsybl.openrao.searchtreerao.commons.RaoUtil.getFlowUnit; - /** * @author Thomas Bouquet {@literal } */ public final class CastorPstRegulation { + private CastorPstRegulation() { } - public static Set regulatePsts(Map pstsToRegulate, Map postContingencyResults, Network network, Crac crac, RaoParameters raoParameters, RaoResult raoResult) { + public static Set regulatePsts(Map pstsToRegulate, + Map postContingencyResults, Network network, Crac crac, + RaoParameters raoParameters, RaoResult raoResult) { // filter out non-curative PSTs // currently, only PSTs with a usage rule for a given state are regulated - Set rangeActionsToRegulate = getPstRangeActionsForRegulation(pstsToRegulate.keySet(), crac); + Set rangeActionsToRegulate = getPstRangeActionsForRegulation( + pstsToRegulate.keySet(), crac); if (rangeActionsToRegulate.isEmpty()) { return Set.of(); } - Set statesToRegulate = getStatesToRegulate(crac, postContingencyResults, getFlowUnit(raoParameters), rangeActionsToRegulate, SearchTreeRaoPstRegulationParameters.getPstsToRegulate(raoParameters), network); + Set statesToRegulate = getStatesToRegulate(crac, postContingencyResults, + getFlowUnit(raoParameters), rangeActionsToRegulate, + SearchTreeRaoPstRegulationParameters.getPstsToRegulate(raoParameters), network); if (statesToRegulate.isEmpty()) { return Set.of(); } - Set contingencies = statesToRegulate.stream().map(PstRegulationInput::curativeState).map(State::getContingency).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toSet()); - BUSINESS_LOGS.info("{} contingency scenario(s) to regulate: {}", contingencies.size(), String.join(", ", contingencies.stream().map(contingency -> contingency.getName().orElse(contingency.getId())).sorted().toList())); - BUSINESS_LOGS.info("{} PST(s) to regulate: {}", rangeActionsToRegulate.size(), String.join(", ", rangeActionsToRegulate.stream().map(PstRangeAction::getName).sorted().toList())); + Set contingencies = statesToRegulate.stream() + .map(PstRegulationInput::curativeState).map(State::getContingency) + .filter(Optional::isPresent).map(Optional::get).collect(Collectors.toSet()); + BUSINESS_LOGS.info("{} contingency scenario(s) to regulate: {}", contingencies.size(), + String.join(", ", contingencies.stream() + .map(contingency -> contingency.getName().orElse(contingency.getId())).sorted() + .toList())); + BUSINESS_LOGS.info("{} PST(s) to regulate: {}", rangeActionsToRegulate.size(), + String.join(", ", + rangeActionsToRegulate.stream().map(PstRangeAction::getName).sorted().toList())); // update loadflow parameters LoadFlowParameters loadFlowParameters = getLoadFlowParameters(raoParameters); @@ -78,27 +91,36 @@ public static Set regulatePsts(Map pstsToRe applyOptimalRemedialActionsForState(network, raoResult, crac.getPreventiveState()); // regulate PSTs for each curative scenario in parallel - try (AbstractNetworkPool networkPool = AbstractNetworkPool.create(network, network.getVariantManager().getWorkingVariantId(), getNumberOfThreads(crac, raoParameters), true)) { - List> tasks = statesToRegulate.stream().map(pstRegulationInput -> - networkPool.submit(() -> regulatePstsForContingencyScenario(pstRegulationInput, crac, rangeActionsToRegulate, raoResult, loadFlowParameters, networkPool)) - ).toList(); - Set pstRegulationResults = new HashSet<>(); - for (ForkJoinTask task : tasks) { - try { - pstRegulationResults.add(task.get()); - } catch (ExecutionException e) { - throw new OpenRaoException(e); + return OpenTelemetryReporter.withSpan("rao.regulatePstsParallel", cx -> { + try (AbstractNetworkPool networkPool = AbstractNetworkPool.create(network, + network.getVariantManager().getWorkingVariantId(), + getNumberOfThreads(crac, raoParameters), true)) { + List> tasks = statesToRegulate.stream() + .map(pstRegulationInput -> + networkPool.submit( + () -> regulatePstsForContingencyScenario(pstRegulationInput, crac, + rangeActionsToRegulate, raoResult, loadFlowParameters, networkPool)) + ).toList(); + Set pstRegulationResults = new HashSet<>(); + for (ForkJoinTask task : tasks) { + try { + pstRegulationResults.add(task.get()); + } catch (ExecutionException e) { + throw new OpenRaoException(e); + } } + networkPool.shutdownAndAwaitTermination(1000, TimeUnit.SECONDS); + return pstRegulationResults; + } catch (Exception e) { + Thread.currentThread().interrupt(); + BUSINESS_WARNS.warn( + "An error occurred during PST regulation, pre-regulation RAO result will be kept."); + return Set.of(); + } finally { + loadFlowParameters.setPhaseShifterRegulationOn( + initialPhaseShifterRegulationOnValue); } - networkPool.shutdownAndAwaitTermination(1000, TimeUnit.SECONDS); - return pstRegulationResults; - } catch (Exception e) { - Thread.currentThread().interrupt(); - BUSINESS_WARNS.warn("An error occurred during PST regulation, pre-regulation RAO result will be kept."); - return Set.of(); - } finally { - loadFlowParameters.setPhaseShifterRegulationOn(initialPhaseShifterRegulationOnValue); - } + }); } /** @@ -109,37 +131,55 @@ public static Set regulatePsts(Map pstsToRe * * For all such states, the associated PST regulation input is included in a set that is returned. */ - private static Set getStatesToRegulate(Crac crac, Map postContingencyResults, Unit unit, Set rangeActionsToRegulate, Map linesInSeriesWithPst, Network network) { + private static Set getStatesToRegulate(Crac crac, + Map postContingencyResults, Unit unit, + Set rangeActionsToRegulate, Map linesInSeriesWithPst, + Network network) { Instant lastInstant = crac.getLastInstant(); return lastInstant.isCurative() ? crac.getStates(lastInstant).stream() .filter(postContingencyResults::containsKey) - .filter(curativeState -> !(postContingencyResults.get(curativeState).optimizationResult() instanceof SkippedOptimizationResultImpl)) - .map(curativeState -> getPstRegulationInput(curativeState, crac, postContingencyResults.get(curativeState), unit, rangeActionsToRegulate, linesInSeriesWithPst, network)) + .filter(curativeState -> !(postContingencyResults.get(curativeState) + .optimizationResult() instanceof SkippedOptimizationResultImpl)) + .map(curativeState -> getPstRegulationInput(curativeState, crac, + postContingencyResults.get(curativeState), unit, rangeActionsToRegulate, + linesInSeriesWithPst, network)) .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toSet()) : Set.of(); } - private static Optional getPstRegulationInput(State curativeState, Crac crac, PostPerimeterResult postPerimeterResult, Unit unit, Set rangeActionsToRegulate, Map linesInSeriesWithPst, Network network) { - Optional limitingElement = getMostLimitingElementProtectedByPst(curativeState, crac, postPerimeterResult, unit, new HashSet<>(linesInSeriesWithPst.values())); + private static Optional getPstRegulationInput(State curativeState, + Crac crac, PostPerimeterResult postPerimeterResult, Unit unit, + Set rangeActionsToRegulate, Map linesInSeriesWithPst, + Network network) { + Optional limitingElement = getMostLimitingElementProtectedByPst(curativeState, + crac, postPerimeterResult, unit, new HashSet<>(linesInSeriesWithPst.values())); if (limitingElement.isPresent()) { Set elementaryPstRegulationInputs = rangeActionsToRegulate.stream() - .filter(pstRangeAction -> linesInSeriesWithPst.containsKey(pstRangeAction.getNetworkElement().getId())) - .map(pstRangeAction -> ElementaryPstRegulationInput.of(pstRangeAction, linesInSeriesWithPst.get(pstRangeAction.getNetworkElement().getId()), curativeState, crac, network)) + .filter(pstRangeAction -> linesInSeriesWithPst.containsKey( + pstRangeAction.getNetworkElement().getId())) + .map(pstRangeAction -> ElementaryPstRegulationInput.of(pstRangeAction, + linesInSeriesWithPst.get(pstRangeAction.getNetworkElement().getId()), + curativeState, crac, network)) .collect(Collectors.toSet()); - return Optional.of(new PstRegulationInput(curativeState, limitingElement.get(), elementaryPstRegulationInputs)); + return Optional.of(new PstRegulationInput(curativeState, limitingElement.get(), + elementaryPstRegulationInputs)); } return Optional.empty(); } /** - * If the most limiting element of a curative state is overloaded and is in series with a PST, it is returned. - * If not, an empty optional value is returned instead. + * If the most limiting element of a curative state is overloaded and is in series with a PST, + * it is returned. If not, an empty optional value is returned instead. */ - private static Optional getMostLimitingElementProtectedByPst(State curativeState, Crac crac, PostPerimeterResult postPerimeterResult, Unit unit, Set linesInSeriesWithPst) { - Map marginPerCnec = crac.getFlowCnecs(curativeState).stream().collect(Collectors.toMap(Function.identity(), flowCnec -> postPerimeterResult.optimizationResult().getMargin(flowCnec, unit))); + private static Optional getMostLimitingElementProtectedByPst(State curativeState, + Crac crac, PostPerimeterResult postPerimeterResult, Unit unit, + Set linesInSeriesWithPst) { + Map marginPerCnec = crac.getFlowCnecs(curativeState).stream().collect( + Collectors.toMap(Function.identity(), + flowCnec -> postPerimeterResult.optimizationResult().getMargin(flowCnec, unit))); List> sortedNegativeMargins = marginPerCnec.entrySet().stream() .filter(entry -> entry.getValue() < 0) .sorted(Map.Entry.comparingByValue()).toList(); @@ -148,49 +188,67 @@ private static Optional getMostLimitingElementProtectedByPst(State cur } double minMargin = sortedNegativeMargins.get(0).getValue(); Set limitingElements = new HashSet<>(); - sortedNegativeMargins.stream().filter(entry -> entry.getValue() == minMargin).forEach(entry -> limitingElements.add(entry.getKey())); + sortedNegativeMargins.stream().filter(entry -> entry.getValue() == minMargin) + .forEach(entry -> limitingElements.add(entry.getKey())); return limitingElements.stream() .filter(flowCnec -> linesInSeriesWithPst.contains(flowCnec.getNetworkElement().getId())) .min(Comparator.comparing(Identifiable::getId)); } private static LoadFlowParameters getLoadFlowParameters(RaoParameters raoParameters) { - return raoParameters.hasExtension(OpenRaoSearchTreeParameters.class) ? raoParameters.getExtension(OpenRaoSearchTreeParameters.class).getLoadFlowAndSensitivityParameters().getSensitivityWithLoadFlowParameters().getLoadFlowParameters() : new LoadFlowParameters(); + return raoParameters.hasExtension(OpenRaoSearchTreeParameters.class) + ? raoParameters.getExtension(OpenRaoSearchTreeParameters.class) + .getLoadFlowAndSensitivityParameters().getSensitivityWithLoadFlowParameters() + .getLoadFlowParameters() : new LoadFlowParameters(); } - private static void updateLoadFlowParametersForPstRegulation(LoadFlowParameters loadFlowParameters) { + private static void updateLoadFlowParametersForPstRegulation( + LoadFlowParameters loadFlowParameters) { loadFlowParameters.setPhaseShifterRegulationOn(true); if (loadFlowParameters.getExtension(OpenLoadFlowParameters.class) == null) { - loadFlowParameters.addExtension(OpenLoadFlowParameters.class, new OpenLoadFlowParameters()); + loadFlowParameters.addExtension(OpenLoadFlowParameters.class, + new OpenLoadFlowParameters()); } - loadFlowParameters.getExtension(OpenLoadFlowParameters.class).setMaxOuterLoopIterations(1000); + loadFlowParameters.getExtension(OpenLoadFlowParameters.class) + .setMaxOuterLoopIterations(1000); } - private static void applyOptimalRemedialActionsForState(Network networkClone, RaoResult raoResult, State state) { + private static void applyOptimalRemedialActionsForState(Network networkClone, + RaoResult raoResult, State state) { // network actions need to be applied BEFORE range actions because to apply HVDC range actions we need to apply AC emulation deactivation network actions beforehand - raoResult.getActivatedNetworkActionsDuringState(state).forEach(networkAction -> networkAction.apply(networkClone)); - raoResult.getActivatedRangeActionsDuringState(state).forEach(rangeAction -> rangeAction.apply(networkClone, raoResult.getOptimizedSetPointOnState(state, rangeAction))); + raoResult.getActivatedNetworkActionsDuringState(state) + .forEach(networkAction -> networkAction.apply(networkClone)); + raoResult.getActivatedRangeActionsDuringState(state).forEach( + rangeAction -> rangeAction.apply(networkClone, + raoResult.getOptimizedSetPointOnState(state, rangeAction))); } - private static Set getPstRangeActionsForRegulation(Set pstsToRegulate, Crac crac) { + private static Set getPstRangeActionsForRegulation(Set pstsToRegulate, + Crac crac) { Map rangeActionPerPst = getRangeActionPerPst(pstsToRegulate, crac); Set rangeActionsToRegulate = new HashSet<>(); for (String pstId : pstsToRegulate) { if (rangeActionPerPst.containsKey(pstId)) { rangeActionsToRegulate.add(rangeActionPerPst.get(pstId)); } else { - BUSINESS_LOGS.info("PST {} cannot be regulated as no curative PST range action was defined for it.", pstId); + BUSINESS_LOGS.info( + "PST {} cannot be regulated as no curative PST range action was defined for it.", + pstId); } } return rangeActionsToRegulate; } - private static Map getRangeActionPerPst(Set pstsToRegulate, Crac crac) { + private static Map getRangeActionPerPst(Set pstsToRegulate, + Crac crac) { // filter out crac's last instant range actions, as results reporting would be less relevant return crac.getPstRangeActions().stream() - .filter(pstRangeAction -> pstRangeAction.getUsageRules().stream().anyMatch(usageRule -> usageRule.getInstant() == crac.getLastInstant())) - .filter(pstRangeAction -> pstsToRegulate.contains(pstRangeAction.getNetworkElement().getId())) - .collect(Collectors.toMap(pstRangeAction -> pstRangeAction.getNetworkElement().getId(), Function.identity())); + .filter(pstRangeAction -> pstRangeAction.getUsageRules().stream() + .anyMatch(usageRule -> usageRule.getInstant() == crac.getLastInstant())) + .filter(pstRangeAction -> pstsToRegulate.contains( + pstRangeAction.getNetworkElement().getId())) + .collect(Collectors.toMap(pstRangeAction -> pstRangeAction.getNetworkElement().getId(), + Function.identity())); } private static int getNumberOfThreads(Crac crac, RaoParameters raoParameters) { @@ -198,20 +256,29 @@ private static int getNumberOfThreads(Crac crac, RaoParameters raoParameters) { } /** - * Performs PST regulation for a curative state. The taps are changed during the loadflow iterations. + * Performs PST regulation for a curative state. The taps are changed during the loadflow + * iterations. */ - private static PstRegulationResult regulatePstsForContingencyScenario(PstRegulationInput pstRegulationInput, Crac crac, Set rangeActionsToRegulate, RaoResult raoResult, LoadFlowParameters loadFlowParameters, AbstractNetworkPool networkPool) throws InterruptedException { + private static PstRegulationResult regulatePstsForContingencyScenario( + PstRegulationInput pstRegulationInput, Crac crac, + Set rangeActionsToRegulate, RaoResult raoResult, + LoadFlowParameters loadFlowParameters, AbstractNetworkPool networkPool) + throws InterruptedException { Network networkClone = networkPool.getAvailableNetwork(); Contingency contingency = pstRegulationInput.curativeState().getContingency().orElseThrow(); simulateContingencyAndApplyCurativeActions(contingency, networkClone, crac, raoResult); - Map initialTapPerPst = getInitialTapPerPst(rangeActionsToRegulate, networkClone); - Map regulatedTapPerPst = PstRegulator.regulatePsts(pstRegulationInput.elementaryPstRegulationInputs(), networkClone, loadFlowParameters); - logPstRegulationResultsForContingencyScenario(contingency, initialTapPerPst, regulatedTapPerPst, pstRegulationInput.limitingElement()); + Map initialTapPerPst = getInitialTapPerPst(rangeActionsToRegulate, + networkClone); + Map regulatedTapPerPst = PstRegulator.regulatePsts( + pstRegulationInput.elementaryPstRegulationInputs(), networkClone, loadFlowParameters); + logPstRegulationResultsForContingencyScenario(contingency, initialTapPerPst, + regulatedTapPerPst, pstRegulationInput.limitingElement()); networkPool.releaseUsedNetwork(networkClone); return new PstRegulationResult(contingency, regulatedTapPerPst); } - private static void simulateContingencyAndApplyCurativeActions(Contingency contingency, Network networkClone, Crac crac, RaoResult raoResult) { + private static void simulateContingencyAndApplyCurativeActions(Contingency contingency, + Network networkClone, Crac crac, RaoResult raoResult) { // simulate contingency contingency.toModification().apply(networkClone); @@ -221,28 +288,37 @@ private static void simulateContingencyAndApplyCurativeActions(Contingency conti .forEach(state -> applyOptimalRemedialActionsForState(networkClone, raoResult, state)); } - private static Map getInitialTapPerPst(Set rangeActionsToRegulate, Network networkClone) { - return rangeActionsToRegulate.stream().collect(Collectors.toMap(Function.identity(), pstRangeAction -> networkClone.getTwoWindingsTransformer(pstRangeAction.getNetworkElement().getId()).getPhaseTapChanger().getTapPosition())); + private static Map getInitialTapPerPst( + Set rangeActionsToRegulate, Network networkClone) { + return rangeActionsToRegulate.stream().collect(Collectors.toMap(Function.identity(), + pstRangeAction -> networkClone.getTwoWindingsTransformer( + pstRangeAction.getNetworkElement().getId()).getPhaseTapChanger().getTapPosition())); } private static void logPstRegulationResultsForContingencyScenario(Contingency contingency, - Map initialTapPerPst, - Map regulatedTapPerPst, - FlowCnec mostLimitingElement) { - List sortedPstRangeActions = initialTapPerPst.keySet().stream().sorted(Comparator.comparing(PstRangeAction::getId)).toList(); + Map initialTapPerPst, + Map regulatedTapPerPst, + FlowCnec mostLimitingElement) { + List sortedPstRangeActions = initialTapPerPst.keySet().stream() + .sorted(Comparator.comparing(PstRangeAction::getId)).toList(); List shiftDetails = new ArrayList<>(); sortedPstRangeActions.forEach( pstRangeAction -> { int initialTap = initialTapPerPst.get(pstRangeAction); int regulatedTap = regulatedTapPerPst.get(pstRangeAction); if (initialTap != regulatedTap) { - shiftDetails.add("%s (%s -> %s)".formatted(pstRangeAction.getName(), initialTap, regulatedTap)); + shiftDetails.add("%s (%s -> %s)".formatted(pstRangeAction.getName(), initialTap, + regulatedTap)); } } ); - String allShiftedPstsDetails = shiftDetails.isEmpty() ? "no PST shifted" : String.join(", ", shiftDetails); + String allShiftedPstsDetails = + shiftDetails.isEmpty() ? "no PST shifted" : String.join(", ", shiftDetails); if (!shiftDetails.isEmpty()) { - BUSINESS_LOGS.info("FlowCNEC '{}' of contingency scenario '{}' is overloaded and is the most limiting element, PST regulation has been triggered: {}", mostLimitingElement.getId(), contingency.getName().orElse(contingency.getId()), allShiftedPstsDetails); + BUSINESS_LOGS.info( + "FlowCNEC '{}' of contingency scenario '{}' is overloaded and is the most limiting element, PST regulation has been triggered: {}", + mostLimitingElement.getId(), contingency.getName().orElse(contingency.getId()), + allShiftedPstsDetails); } } } diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/RaoUtil.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/RaoUtil.java index 6b350af3be..9d918628b4 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/RaoUtil.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/RaoUtil.java @@ -7,12 +7,20 @@ package com.powsybl.openrao.searchtreerao.commons; +import static com.powsybl.openrao.raoapi.parameters.extensions.LoadFlowAndSensitivityParameters.getLoadFlowProvider; +import static com.powsybl.openrao.raoapi.parameters.extensions.LoadFlowAndSensitivityParameters.getSensitivityWithLoadFlowParameters; +import static com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoRangeActionsOptimizationParameters.getPstModel; +import static com.powsybl.openrao.searchtreerao.commons.HvdcUtils.addNetworkActionAssociatedWithHvdcRangeAction; +import static com.powsybl.openrao.searchtreerao.commons.HvdcUtils.updateHvdcRangeActionInitialSetpoint; +import static java.lang.String.format; + import com.powsybl.iidm.network.Network; import com.powsybl.iidm.network.TwoSides; import com.powsybl.iidm.network.extensions.HvdcAngleDroopActivePowerControl; import com.powsybl.openrao.commons.OpenRaoException; import com.powsybl.openrao.commons.Unit; import com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider; +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; import com.powsybl.openrao.data.crac.api.Crac; import com.powsybl.openrao.data.crac.api.RemedialAction; import com.powsybl.openrao.data.crac.api.State; @@ -32,31 +40,30 @@ import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.OptimizationPerimeter; import com.powsybl.openrao.searchtreerao.result.api.FlowResult; import com.powsybl.openrao.searchtreerao.result.api.OptimizationResult; -import org.apache.commons.lang3.tuple.Pair; - -import java.util.*; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; - -import static com.powsybl.openrao.raoapi.parameters.extensions.LoadFlowAndSensitivityParameters.getLoadFlowProvider; -import static com.powsybl.openrao.raoapi.parameters.extensions.LoadFlowAndSensitivityParameters.getSensitivityWithLoadFlowParameters; -import static com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoRangeActionsOptimizationParameters.getPstModel; -import static com.powsybl.openrao.searchtreerao.commons.HvdcUtils.addNetworkActionAssociatedWithHvdcRangeAction; -import static com.powsybl.openrao.searchtreerao.commons.HvdcUtils.updateHvdcRangeActionInitialSetpoint; -import static java.lang.String.format; +import org.apache.commons.lang3.tuple.Pair; /** * @author Joris Mancini {@literal } */ public final class RaoUtil { + private RaoUtil() { } public static void initData(RaoInput raoInput, RaoParameters raoParameters) { - checkParameters(raoParameters, raoInput); - checkCnecsThresholdsUnit(raoParameters, raoInput); - initNetwork(raoInput.getNetwork(), raoInput.getNetworkVariantId()); - updateHvdcRangeActionInitialSetpoint(raoInput.getCrac(), raoInput.getNetwork(), raoParameters); - addNetworkActionAssociatedWithHvdcRangeAction(raoInput.getCrac(), raoInput.getNetwork()); + OpenTelemetryReporter.withSpan("rao.initData", cx -> { + checkParameters(raoParameters, raoInput); + checkCnecsThresholdsUnit(raoParameters, raoInput); + initNetwork(raoInput.getNetwork(), raoInput.getNetworkVariantId()); + updateHvdcRangeActionInitialSetpoint(raoInput.getCrac(), raoInput.getNetwork(), + raoParameters); + addNetworkActionAssociatedWithHvdcRangeAction(raoInput.getCrac(), + raoInput.getNetwork()); + }); } public static void initNetwork(Network network, String networkVariantId) { @@ -69,21 +76,25 @@ public static void checkParameters(RaoParameters raoParameters, RaoInput raoInpu checkHvdcAcEmulationParameters(raoParameters, raoInput); if (!PstModel.APPROXIMATED_INTEGERS.equals(getPstModel(raoParameters)) - && raoInput.getCrac().getRaUsageLimitsPerInstant().values().stream().anyMatch(raUsageLimits -> !raUsageLimits.getMaxElementaryActionsPerTso().isEmpty())) { + && raoInput.getCrac().getRaUsageLimitsPerInstant().values().stream() + .anyMatch(raUsageLimits -> !raUsageLimits.getMaxElementaryActionsPerTso().isEmpty())) { String msg = "The PSTs must be approximated as integers to use the limitations of elementary actions as a constraint in the RAO."; OpenRaoLoggerProvider.BUSINESS_LOGS.error(msg); throw new OpenRaoException(msg); } } - public static void checkHvdcAcEmulationParameters(RaoParameters raoParameters, RaoInput raoInput) { + public static void checkHvdcAcEmulationParameters(RaoParameters raoParameters, + RaoInput raoInput) { boolean isAnyHvdcInAcEmulation = raoInput.getNetwork().getHvdcLineStream() .anyMatch(hvdcLine -> { - HvdcAngleDroopActivePowerControl extension = hvdcLine.getExtension(HvdcAngleDroopActivePowerControl.class); + HvdcAngleDroopActivePowerControl extension = hvdcLine.getExtension( + HvdcAngleDroopActivePowerControl.class); return extension != null && extension.isEnabled(); }); - if (!getSensitivityWithLoadFlowParameters(raoParameters).getLoadFlowParameters().isHvdcAcEmulation() && isAnyHvdcInAcEmulation) { + if (!getSensitivityWithLoadFlowParameters(raoParameters).getLoadFlowParameters() + .isHvdcAcEmulation() && isAnyHvdcInAcEmulation) { String msg = "hvdcAcEmulation is not enabled but some HVDC lines are in AC emulation mode which will not be coherent."; OpenRaoLoggerProvider.BUSINESS_LOGS.error(msg); throw new OpenRaoException(msg); @@ -94,11 +105,17 @@ private static void checkLoopFlowParameters(RaoParameters raoParameters, RaoInpu if ((raoParameters.getLoopFlowParameters().isPresent() || raoParameters.getObjectiveFunctionParameters().getType().relativePositiveMargins()) && (Objects.isNull(raoInput.getReferenceProgram()))) { - OpenRaoLoggerProvider.BUSINESS_WARNS.warn("No ReferenceProgram provided. A ReferenceProgram will be generated using information in the network file."); - raoInput.setReferenceProgram(ReferenceProgramBuilder.buildReferenceProgram(raoInput.getNetwork(), getLoadFlowProvider(raoParameters), getSensitivityWithLoadFlowParameters(raoParameters).getLoadFlowParameters())); + OpenRaoLoggerProvider.BUSINESS_WARNS.warn( + "No ReferenceProgram provided. A ReferenceProgram will be generated using information in the network file."); + raoInput.setReferenceProgram( + ReferenceProgramBuilder.buildReferenceProgram(raoInput.getNetwork(), + getLoadFlowProvider(raoParameters), + getSensitivityWithLoadFlowParameters(raoParameters).getLoadFlowParameters())); } - if (raoParameters.getLoopFlowParameters().isPresent() && (Objects.isNull(raoInput.getReferenceProgram()) || Objects.isNull(raoInput.getGlskProvider()))) { + if (raoParameters.getLoopFlowParameters().isPresent() && ( + Objects.isNull(raoInput.getReferenceProgram()) || Objects.isNull( + raoInput.getGlskProvider()))) { String msg = format( "Loopflow computation cannot be performed on CRAC %s because it lacks a ReferenceProgram or a GlskProvider", raoInput.getCrac().getId()); @@ -107,21 +124,31 @@ private static void checkLoopFlowParameters(RaoParameters raoParameters, RaoInpu } } - private static void checkObjectiveFunctionParameters(RaoParameters raoParameters, RaoInput raoInput) { + private static void checkObjectiveFunctionParameters(RaoParameters raoParameters, + RaoInput raoInput) { if (raoParameters.getObjectiveFunctionParameters().getType().relativePositiveMargins()) { if (raoInput.getGlskProvider() == null) { - throw new OpenRaoException(format("Objective function %s requires glsks", raoParameters.getObjectiveFunctionParameters().getType())); + throw new OpenRaoException(format("Objective function %s requires glsks", + raoParameters.getObjectiveFunctionParameters().getType())); } - if (raoParameters.getRelativeMarginsParameters().map(relativeMarginsParameters -> relativeMarginsParameters.getPtdfBoundaries().isEmpty()).orElse(true)) { - throw new OpenRaoException(format("Objective function %s requires a config with a non empty boundary set", raoParameters.getObjectiveFunctionParameters().getType())); + if (raoParameters.getRelativeMarginsParameters().map( + relativeMarginsParameters -> relativeMarginsParameters.getPtdfBoundaries() + .isEmpty()).orElse(true)) { + throw new OpenRaoException( + format("Objective function %s requires a config with a non empty boundary set", + raoParameters.getObjectiveFunctionParameters().getType())); } } if (raoParameters.getObjectiveFunctionParameters().getType().costOptimization() && (!raoParameters.hasExtension(OpenRaoSearchTreeParameters.class) || - raoParameters.hasExtension(OpenRaoSearchTreeParameters.class) && raoParameters.getExtension(OpenRaoSearchTreeParameters.class).getMinMarginsParameters().isEmpty())) { - throw new OpenRaoException(format("Objective function type %s requires a config with costly min margin parameters", raoParameters.getObjectiveFunctionParameters().getType())); + raoParameters.hasExtension(OpenRaoSearchTreeParameters.class) + && raoParameters.getExtension(OpenRaoSearchTreeParameters.class) + .getMinMarginsParameters().isEmpty())) { + throw new OpenRaoException(format( + "Objective function type %s requires a config with costly min margin parameters", + raoParameters.getObjectiveFunctionParameters().getType())); } } @@ -129,15 +156,19 @@ public static void checkCnecsThresholdsUnit(RaoParameters raoParameters, RaoInpu Crac crac = raoInput.getCrac(); if (!getSensitivityWithLoadFlowParameters(raoParameters).getLoadFlowParameters().isDc()) { crac.getFlowCnecs().forEach(flowCnec -> { - if (flowCnec.getThresholds().stream().anyMatch(branchThreshold -> branchThreshold.getUnit().equals(Unit.MEGAWATT))) { - String msg = format("A threshold for the flowCnec %s is defined in MW but the loadflow computation is in AC. It will be imprecisely converted by the RAO which could create uncoherent results due to side effects", flowCnec.getId()); + if (flowCnec.getThresholds().stream() + .anyMatch(branchThreshold -> branchThreshold.getUnit().equals(Unit.MEGAWATT))) { + String msg = format( + "A threshold for the flowCnec %s is defined in MW but the loadflow computation is in AC. It will be imprecisely converted by the RAO which could create uncoherent results due to side effects", + flowCnec.getId()); OpenRaoLoggerProvider.BUSINESS_WARNS.warn(msg); } }); } } - public static double getFlowUnitMultiplier(FlowCnec cnec, TwoSides voltageSide, Unit unitFrom, Unit unitTo) { + public static double getFlowUnitMultiplier(FlowCnec cnec, TwoSides voltageSide, Unit unitFrom, + Unit unitTo) { if (unitFrom == unitTo) { return 1; } @@ -152,39 +183,55 @@ public static double getFlowUnitMultiplier(FlowCnec cnec, TwoSides voltageSide, } /** - * Returns true if any flowCnec has a negative margin. - * We need to know the unit of the objective function, because a negative margin in A can be positive in MW - * given different approximations, and vice versa + * Returns true if any flowCnec has a negative margin. We need to know the unit of the objective + * function, because a negative margin in A can be positive in MW given different + * approximations, and vice versa */ - public static boolean isAnyMarginNegative(FlowResult flowResult, Set flowCnecs, Unit marginUnit) { - return flowCnecs.stream().anyMatch(flowCnec -> flowResult.getMargin(flowCnec, marginUnit) <= 0); + public static boolean isAnyMarginNegative(FlowResult flowResult, Set flowCnecs, + Unit marginUnit) { + return flowCnecs.stream() + .anyMatch(flowCnec -> flowResult.getMargin(flowCnec, marginUnit) <= 0); } /** - * Evaluates if a remedial action is available. - * 1) The remedial action has no usage rule: it will not be available. - * 2) It gathers all the remedial action usage rules and filters out the OnFlowConstraint(InCountry) with no negative margins on their associated cnecs. - * If there are remaining usage rules, the remedial action is available. + * Evaluates if a remedial action is available. 1) The remedial action has no usage rule: it + * will not be available. 2) It gathers all the remedial action usage rules and filters out the + * OnFlowConstraint(InCountry) with no negative margins on their associated cnecs. If there are + * remaining usage rules, the remedial action is available. */ - public static boolean canRemedialActionBeUsed(RemedialAction remedialAction, State state, FlowResult flowResult, Set flowCnecs, Network network, RaoParameters raoParameters) { - return remedialAction.getUsageRules().stream().anyMatch(ur -> isUsageRuleActivated(ur, remedialAction, state, flowResult, flowCnecs, network, getFlowUnit(raoParameters))); + public static boolean canRemedialActionBeUsed(RemedialAction remedialAction, State state, + FlowResult flowResult, Set flowCnecs, Network network, + RaoParameters raoParameters) { + return remedialAction.getUsageRules().stream().anyMatch( + ur -> isUsageRuleActivated(ur, remedialAction, state, flowResult, flowCnecs, network, + getFlowUnit(raoParameters))); } - private static boolean isUsageRuleActivated(UsageRule usageRule, RemedialAction remedialAction, State state, FlowResult flowResult, Set flowCnecs, Network network, Unit unit) { + private static boolean isUsageRuleActivated(UsageRule usageRule, + RemedialAction remedialAction, State state, FlowResult flowResult, + Set flowCnecs, Network network, Unit unit) { if (usageRule instanceof OnInstant onInstant) { return onInstant.getInstant().equals(state.getInstant()); } else if (usageRule instanceof OnContingencyState onContingencyState) { return onContingencyState.getState().equals(state); } else if (usageRule instanceof OnFlowConstraintInCountry onFlowConstraintInCountry) { - if (onFlowConstraintInCountry.getContingency().isPresent() && !onFlowConstraintInCountry.getContingency().equals(state.getContingency())) { + if (onFlowConstraintInCountry.getContingency().isPresent() + && !onFlowConstraintInCountry.getContingency().equals(state.getContingency())) { return false; } - return isAnyMarginNegative(flowResult, remedialAction.getFlowCnecsConstrainingForOneUsageRule(onFlowConstraintInCountry, flowCnecs, network), unit) && onFlowConstraintInCountry.getInstant().equals(state.getInstant()); - } else if (usageRule instanceof OnConstraint onConstraint && onConstraint.getCnec() instanceof FlowCnec flowCnec) { - if (!onConstraint.getInstant().isPreventive() && !flowCnec.getState().getContingency().equals(state.getContingency())) { + return isAnyMarginNegative(flowResult, + remedialAction.getFlowCnecsConstrainingForOneUsageRule(onFlowConstraintInCountry, + flowCnecs, network), unit) && onFlowConstraintInCountry.getInstant() + .equals(state.getInstant()); + } else if (usageRule instanceof OnConstraint onConstraint + && onConstraint.getCnec() instanceof FlowCnec flowCnec) { + if (!onConstraint.getInstant().isPreventive() && !flowCnec.getState().getContingency() + .equals(state.getContingency())) { return false; } - return isAnyMarginNegative(flowResult, remedialAction.getFlowCnecsConstrainingForOneUsageRule(onConstraint, flowCnecs, network), unit) && onConstraint.getInstant().equals(state.getInstant()); + return isAnyMarginNegative(flowResult, + remedialAction.getFlowCnecsConstrainingForOneUsageRule(onConstraint, flowCnecs, + network), unit) && onConstraint.getInstant().equals(state.getInstant()); } else { return false; } @@ -194,7 +241,8 @@ private static boolean isUsageRuleActivated(UsageRule usageRule, RemedialAction< * Returns the range action from optimizationContext that is available on the latest state * strictly before the given state, and that acts on the same network element as rangeAction. */ - public static Pair, State> getLastAvailableRangeActionOnSameNetworkElement(OptimizationPerimeter optimizationContext, RangeAction rangeAction, State state) { + public static Pair, State> getLastAvailableRangeActionOnSameNetworkElement( + OptimizationPerimeter optimizationContext, RangeAction rangeAction, State state) { if (state.isPreventive() || state.equals(optimizationContext.getMainOptimizationState())) { // no previous instant @@ -205,8 +253,10 @@ public static Pair, State> getLastAvailableRangeActionOnSameNetwo State previousUsageState = optimizationContext.getMainOptimizationState(); if (previousUsageState.getInstant().comesBefore(state.getInstant())) { - Optional> correspondingRa = optimizationContext.getRangeActionsPerState().get(previousUsageState).stream() - .filter(ra -> ra.getId().equals(rangeAction.getId()) || ra.getNetworkElements().equals(rangeAction.getNetworkElements())) + Optional> correspondingRa = optimizationContext.getRangeActionsPerState() + .get(previousUsageState).stream() + .filter(ra -> ra.getId().equals(rangeAction.getId()) || ra.getNetworkElements() + .equals(rangeAction.getNetworkElements())) .findAny(); if (correspondingRa.isPresent()) { @@ -215,7 +265,8 @@ public static Pair, State> getLastAvailableRangeActionOnSameNetwo } return null; } else { - throw new OpenRaoException("Linear optimization does not handle range actions which are neither PREVENTIVE nor CURATIVE."); + throw new OpenRaoException( + "Linear optimization does not handle range actions which are neither PREVENTIVE nor CURATIVE."); } } @@ -223,14 +274,19 @@ public static double getLargestCnecThreshold(Set flowCnecs, Unit unit) return flowCnecs.stream().filter(Cnec::isOptimized) .map(flowCnec -> flowCnec.getMonitoredSides().stream().map(side -> - Math.max(Math.abs(flowCnec.getUpperBound(side, unit).orElse(0.)), Math.abs(flowCnec.getLowerBound(side, unit).orElse(0.)))).max(Double::compare).orElse(0.)) + Math.max(Math.abs(flowCnec.getUpperBound(side, unit).orElse(0.)), + Math.abs(flowCnec.getLowerBound(side, unit).orElse(0.)))) + .max(Double::compare).orElse(0.)) .max(Double::compare) .orElse(0.); } - public static void applyRemedialActions(Network network, OptimizationResult optResult, State state) { - optResult.getActivatedNetworkActions().forEach(networkAction -> networkAction.apply(network)); - optResult.getActivatedRangeActions(state).forEach(rangeAction -> rangeAction.apply(network, optResult.getOptimizedSetpoint(rangeAction, state))); + public static void applyRemedialActions(Network network, OptimizationResult optResult, + State state) { + optResult.getActivatedNetworkActions() + .forEach(networkAction -> networkAction.apply(network)); + optResult.getActivatedRangeActions(state).forEach(rangeAction -> rangeAction.apply(network, + optResult.getOptimizedSetpoint(rangeAction, state))); } public static Set getDuplicateCnecs(Set flowcnecs) { @@ -242,7 +298,9 @@ public static Set getDuplicateCnecs(Set flowcnecs) { // TODO: find a better place for this function public static Unit getFlowUnit(RaoParameters raoParameters) { - return getSensitivityWithLoadFlowParameters(raoParameters).getLoadFlowParameters().isDc() ? Unit.MEGAWATT : Unit.AMPERE; + return getSensitivityWithLoadFlowParameters(raoParameters).getLoadFlowParameters().isDc() + ? Unit.MEGAWATT : Unit.AMPERE; } } + diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/ToolProvider.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/ToolProvider.java index fede621851..4402178f1a 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/ToolProvider.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/ToolProvider.java @@ -7,8 +7,19 @@ package com.powsybl.openrao.searchtreerao.commons; -import com.powsybl.openrao.commons.*; +import static com.powsybl.openrao.raoapi.parameters.extensions.LoadFlowAndSensitivityParameters.getSensitivityProvider; +import static com.powsybl.openrao.raoapi.parameters.extensions.LoadFlowAndSensitivityParameters.getSensitivityWithLoadFlowParameters; +import static com.powsybl.openrao.searchtreerao.commons.RaoUtil.getFlowUnit; + +import com.powsybl.glsk.commons.ZonalData; +import com.powsybl.glsk.commons.ZonalDataImpl; +import com.powsybl.iidm.network.Country; +import com.powsybl.iidm.network.Network; +import com.powsybl.openrao.commons.EICode; +import com.powsybl.openrao.commons.OpenRaoException; +import com.powsybl.openrao.commons.Unit; import com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider; +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; import com.powsybl.openrao.data.crac.api.Instant; import com.powsybl.openrao.data.crac.api.cnec.Cnec; import com.powsybl.openrao.data.crac.api.cnec.FlowCnec; @@ -18,28 +29,25 @@ import com.powsybl.openrao.loopflowcomputation.LoopFlowComputation; import com.powsybl.openrao.loopflowcomputation.LoopFlowComputationImpl; import com.powsybl.openrao.raoapi.RaoInput; -import com.powsybl.openrao.raoapi.parameters.RaoParameters; import com.powsybl.openrao.raoapi.parameters.LoopFlowParameters; +import com.powsybl.openrao.raoapi.parameters.RaoParameters; import com.powsybl.openrao.raoapi.parameters.RelativeMarginsParameters; import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions; import com.powsybl.openrao.sensitivityanalysis.SystematicSensitivityInterface; -import com.powsybl.glsk.commons.ZonalData; -import com.powsybl.glsk.commons.ZonalDataImpl; -import com.powsybl.iidm.network.Country; -import com.powsybl.iidm.network.Network; import com.powsybl.sensitivity.SensitivityVariableSet; - -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; -import static com.powsybl.openrao.raoapi.parameters.extensions.LoadFlowAndSensitivityParameters.getSensitivityProvider; -import static com.powsybl.openrao.raoapi.parameters.extensions.LoadFlowAndSensitivityParameters.getSensitivityWithLoadFlowParameters; -import static com.powsybl.openrao.searchtreerao.commons.RaoUtil.getFlowUnit; - /** * @author Joris Mancini {@literal } */ public final class ToolProvider { + private Network network; private RaoParameters raoParameters; private ReferenceProgram referenceProgram; @@ -65,9 +73,11 @@ private boolean hasLoopFlowExtension(FlowCnec cnec) { public Set getLoopFlowCnecs(Set allCnecs) { Optional loopFlowParametersOptional = raoParameters.getLoopFlowParameters(); - if (loopFlowParametersOptional.isPresent() && !loopFlowParametersOptional.get().getCountries().isEmpty()) { + if (loopFlowParametersOptional.isPresent() && !loopFlowParametersOptional.get() + .getCountries().isEmpty()) { return allCnecs.stream() - .filter(cnec -> hasLoopFlowExtension(cnec) && cnecIsInCountryList(cnec, network, loopFlowParametersOptional.get().getCountries())) + .filter(cnec -> hasLoopFlowExtension(cnec) && cnecIsInCountryList(cnec, network, + loopFlowParametersOptional.get().getCountries())) .collect(Collectors.toSet()); } else { return allCnecs.stream() @@ -76,23 +86,25 @@ public Set getLoopFlowCnecs(Set allCnecs) { } } - static boolean cnecIsInCountryList(Cnec cnec, Network network, Set loopflowCountries) { + static boolean cnecIsInCountryList(Cnec cnec, Network network, + Set loopflowCountries) { return cnec.getLocation(network).stream().anyMatch(loopflowCountries::contains); } public SystematicSensitivityInterface getSystematicSensitivityInterface(Set cnecs, - Set> rangeActions, - boolean computePtdfs, - boolean computeLoopFlows, Instant outageInstant) { - return getSystematicSensitivityInterface(cnecs, rangeActions, computePtdfs, computeLoopFlows, null, outageInstant); + Set> rangeActions, + boolean computePtdfs, + boolean computeLoopFlows, Instant outageInstant) { + return getSystematicSensitivityInterface(cnecs, rangeActions, computePtdfs, + computeLoopFlows, null, outageInstant); } public SystematicSensitivityInterface getSystematicSensitivityInterface(Set cnecs, - Set> rangeActions, - boolean computePtdfs, - boolean computeLoopFlows, - AppliedRemedialActions appliedRemedialActions, - Instant outageInstant) { + Set> rangeActions, + boolean computePtdfs, + boolean computeLoopFlows, + AppliedRemedialActions appliedRemedialActions, + Instant outageInstant) { Unit flowUnit = getFlowUnit(raoParameters); @@ -100,7 +112,8 @@ public SystematicSensitivityInterface getSystematicSensitivityInterface(Set loopflowCnecs = getLoopFlowCnecs(cnecs); - builder.withPtdfSensitivities(getGlskForEic(getEicForLoopFlows()), loopflowCnecs, computationUnits); + builder.withPtdfSensitivities(getGlskForEic(getEicForLoopFlows()), loopflowCnecs, + computationUnits); } else if (computePtdfs) { - builder.withPtdfSensitivities(getGlskForEic(getEicForObjectiveFunction()), cnecs, computationUnits); + builder.withPtdfSensitivities(getGlskForEic(getEicForObjectiveFunction()), cnecs, + computationUnits); } return builder.build(); @@ -149,7 +164,8 @@ ZonalData getGlskForEic(Set listEicCode) { for (String eiCode : listEicCode) { SensitivityVariableSet linearGlsk = glskProvider.getData(eiCode); if (Objects.isNull(linearGlsk)) { - OpenRaoLoggerProvider.TECHNICAL_LOGS.warn("No GLSK found for CountryEICode {}", eiCode); + OpenRaoLoggerProvider.TECHNICAL_LOGS.warn("No GLSK found for CountryEICode {}", + eiCode); } else { glskBoundaries.put(eiCode, linearGlsk); } @@ -163,6 +179,7 @@ public static ToolProviderBuilder create() { } public static final class ToolProviderBuilder { + private Network network; private RaoParameters raoParameters; private ReferenceProgram referenceProgram; @@ -180,14 +197,18 @@ public ToolProviderBuilder withRaoParameters(RaoParameters raoParameters) { return this; } - public ToolProviderBuilder withLoopFlowComputation(ReferenceProgram referenceProgram, ZonalData glskProvider, LoopFlowComputation loopFlowComputation) { + public ToolProviderBuilder withLoopFlowComputation(ReferenceProgram referenceProgram, + ZonalData glskProvider, + LoopFlowComputation loopFlowComputation) { this.referenceProgram = referenceProgram; this.glskProvider = glskProvider; this.loopFlowComputation = loopFlowComputation; return this; } - public ToolProviderBuilder withAbsolutePtdfSumsComputation(ZonalData glskProvider, AbsolutePtdfSumsComputation absolutePtdfSumsComputation) { + public ToolProviderBuilder withAbsolutePtdfSumsComputation( + ZonalData glskProvider, + AbsolutePtdfSumsComputation absolutePtdfSumsComputation) { this.glskProvider = glskProvider; this.absolutePtdfSumsComputation = absolutePtdfSumsComputation; return this; @@ -207,35 +228,40 @@ public ToolProvider build() { } } - public static ToolProvider buildFromRaoInputAndParameters(RaoInput raoInput, RaoParameters raoParameters) { - - ToolProvider.ToolProviderBuilder toolProviderBuilder = ToolProvider.create() - .withNetwork(raoInput.getNetwork()) - .withRaoParameters(raoParameters); - if (raoInput.getReferenceProgram() != null) { - toolProviderBuilder.withLoopFlowComputation( - raoInput.getReferenceProgram(), - raoInput.getGlskProvider(), - new LoopFlowComputationImpl( - raoInput.getGlskProvider(), + public static ToolProvider buildFromRaoInputAndParameters(RaoInput raoInput, + RaoParameters raoParameters) { + return OpenTelemetryReporter.withSpan("rao.buildToolProvider", cx -> { + ToolProvider.ToolProviderBuilder toolProviderBuilder = ToolProvider.create() + .withNetwork(raoInput.getNetwork()) + .withRaoParameters(raoParameters); + if (raoInput.getReferenceProgram() != null) { + toolProviderBuilder.withLoopFlowComputation( raoInput.getReferenceProgram(), - getFlowUnit(raoParameters) - ) - ); - } - if (raoParameters.getObjectiveFunctionParameters().getType().relativePositiveMargins()) { - Optional optionalRelativeMarginsParameters = raoParameters.getRelativeMarginsParameters(); - if (optionalRelativeMarginsParameters.isEmpty()) { - throw new OpenRaoException("No relative margins parameters were defined with objective function " + raoParameters.getObjectiveFunctionParameters().getType()); + raoInput.getGlskProvider(), + new LoopFlowComputationImpl( + raoInput.getGlskProvider(), + raoInput.getReferenceProgram(), + getFlowUnit(raoParameters) + ) + ); } - toolProviderBuilder.withAbsolutePtdfSumsComputation( - raoInput.getGlskProvider(), - new AbsolutePtdfSumsComputation( + if (raoParameters.getObjectiveFunctionParameters().getType() + .relativePositiveMargins()) { + Optional optionalRelativeMarginsParameters = raoParameters.getRelativeMarginsParameters(); + if (optionalRelativeMarginsParameters.isEmpty()) { + throw new OpenRaoException( + "No relative margins parameters were defined with objective function " + + raoParameters.getObjectiveFunctionParameters().getType()); + } + toolProviderBuilder.withAbsolutePtdfSumsComputation( raoInput.getGlskProvider(), - optionalRelativeMarginsParameters.get().getPtdfBoundaries() - ) - ); - } - return toolProviderBuilder.build(); + new AbsolutePtdfSumsComputation( + raoInput.getGlskProvider(), + optionalRelativeMarginsParameters.get().getPtdfBoundaries() + ) + ); + } + return toolProviderBuilder.build(); + }); } } diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/parameters/TreeParameters.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/parameters/TreeParameters.java index 2dfa0aa967..a3afa58ce9 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/parameters/TreeParameters.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/parameters/TreeParameters.java @@ -7,24 +7,28 @@ package com.powsybl.openrao.searchtreerao.commons.parameters; -import com.powsybl.openrao.raoapi.parameters.ObjectiveFunctionParameters; -import com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoRangeActionsOptimizationParameters; -import com.powsybl.openrao.raoapi.parameters.RaoParameters; - -import static com.powsybl.openrao.raoapi.parameters.extensions.MultithreadingParameters.*; +import static com.powsybl.openrao.raoapi.parameters.extensions.MultithreadingParameters.getAvailableCPUs; import static com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoObjectiveFunctionParameters.getCurativeMinObjImprovement; import static com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoRangeActionsOptimizationParameters.getRaRangeShrinking; -import static com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoTopoOptimizationParameters.*; +import static com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoTopoOptimizationParameters.getMaxCurativeSearchTreeDepth; +import static com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoTopoOptimizationParameters.getMaxPreventiveSearchTreeDepth; + +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; +import com.powsybl.openrao.raoapi.parameters.ObjectiveFunctionParameters; +import com.powsybl.openrao.raoapi.parameters.RaoParameters; +import com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoRangeActionsOptimizationParameters; /** - * This class contains internal Open RAO parameters used in the SearchTree algorithm. - * These parameters are dynamically generated by the SearchTreeRaoProvider depending on the context and on - * the user's RAO parameters, and then used in SearchTree algorithm. - * They should not be visible to the user. + * This class contains internal Open RAO parameters used in the SearchTree algorithm. These + * parameters are dynamically generated by the SearchTreeRaoProvider depending on the context and on + * the user's RAO parameters, and then used in SearchTree algorithm. They should not be visible to + * the user. * * @author Peter Mitri {@literal } */ -public record TreeParameters(StopCriterion stopCriterion, double targetObjectiveValue, int maximumSearchDepth, int leavesInParallel, boolean raRangeShrinking) { +public record TreeParameters(StopCriterion stopCriterion, double targetObjectiveValue, + int maximumSearchDepth, int leavesInParallel, + boolean raRangeShrinking) { public enum StopCriterion { MIN_OBJECTIVE, @@ -32,10 +36,15 @@ public enum StopCriterion { } public static TreeParameters buildForPreventivePerimeter(RaoParameters parameters) { - SearchTreeRaoRangeActionsOptimizationParameters.RaRangeShrinking raRangeShrinking = getRaRangeShrinking(parameters); - boolean shouldShrinkRaRange = raRangeShrinking.equals(SearchTreeRaoRangeActionsOptimizationParameters.RaRangeShrinking.ENABLED_IN_FIRST_PRAO_AND_CRAO) || - raRangeShrinking.equals(SearchTreeRaoRangeActionsOptimizationParameters.RaRangeShrinking.ENABLED); - if (parameters.getObjectiveFunctionParameters().getType() == ObjectiveFunctionParameters.ObjectiveFunctionType.SECURE_FLOW) { + SearchTreeRaoRangeActionsOptimizationParameters.RaRangeShrinking raRangeShrinking = getRaRangeShrinking( + parameters); + boolean shouldShrinkRaRange = raRangeShrinking.equals( + SearchTreeRaoRangeActionsOptimizationParameters.RaRangeShrinking.ENABLED_IN_FIRST_PRAO_AND_CRAO) + || + raRangeShrinking.equals( + SearchTreeRaoRangeActionsOptimizationParameters.RaRangeShrinking.ENABLED); + if (parameters.getObjectiveFunctionParameters().getType() + == ObjectiveFunctionParameters.ObjectiveFunctionType.SECURE_FLOW) { return new TreeParameters(StopCriterion.AT_TARGET_OBJECTIVE_VALUE, 0.0, // secure getMaxPreventiveSearchTreeDepth(parameters), @@ -50,30 +59,41 @@ public static TreeParameters buildForPreventivePerimeter(RaoParameters parameter } } - public static TreeParameters buildForCurativePerimeter(RaoParameters parameters, Double preventiveOptimizedCost) { - StopCriterion stopCriterion = StopCriterion.AT_TARGET_OBJECTIVE_VALUE; - double targetObjectiveValue; - if (parameters.getObjectiveFunctionParameters().getType() == ObjectiveFunctionParameters.ObjectiveFunctionType.SECURE_FLOW) { - targetObjectiveValue = 0.0; - } else { - targetObjectiveValue = preventiveOptimizedCost - getCurativeMinObjImprovement(parameters); - if (parameters.getObjectiveFunctionParameters().getEnforceCurativeSecurity()) { - targetObjectiveValue = Math.min(targetObjectiveValue, 0); + public static TreeParameters buildForCurativePerimeter(RaoParameters parameters, + Double preventiveOptimizedCost) { + return OpenTelemetryReporter.withSpan("rao.buildCurativePerimeter", cx -> { + StopCriterion stopCriterion = StopCriterion.AT_TARGET_OBJECTIVE_VALUE; + double targetObjectiveValue; + if (parameters.getObjectiveFunctionParameters().getType() + == ObjectiveFunctionParameters.ObjectiveFunctionType.SECURE_FLOW) { + targetObjectiveValue = 0.0; + } else { + targetObjectiveValue = + preventiveOptimizedCost - getCurativeMinObjImprovement(parameters); + if (parameters.getObjectiveFunctionParameters().getEnforceCurativeSecurity()) { + targetObjectiveValue = Math.min(targetObjectiveValue, 0); + } } - } - SearchTreeRaoRangeActionsOptimizationParameters.RaRangeShrinking raRangeShrinking = getRaRangeShrinking(parameters); - boolean shouldShrinkRaRange = raRangeShrinking.equals(SearchTreeRaoRangeActionsOptimizationParameters.RaRangeShrinking.ENABLED_IN_FIRST_PRAO_AND_CRAO) || - raRangeShrinking.equals(SearchTreeRaoRangeActionsOptimizationParameters.RaRangeShrinking.ENABLED); - return new TreeParameters(stopCriterion, - targetObjectiveValue, - getMaxCurativeSearchTreeDepth(parameters), - 1, - shouldShrinkRaRange); + SearchTreeRaoRangeActionsOptimizationParameters.RaRangeShrinking raRangeShrinking = getRaRangeShrinking( + parameters); + boolean shouldShrinkRaRange = raRangeShrinking.equals( + SearchTreeRaoRangeActionsOptimizationParameters.RaRangeShrinking.ENABLED_IN_FIRST_PRAO_AND_CRAO) + || + raRangeShrinking.equals( + SearchTreeRaoRangeActionsOptimizationParameters.RaRangeShrinking.ENABLED); + return new TreeParameters(stopCriterion, + targetObjectiveValue, + getMaxCurativeSearchTreeDepth(parameters), + 1, + shouldShrinkRaRange); + }); } public static TreeParameters buildForSecondPreventivePerimeter(RaoParameters parameters) { - boolean raRangeShrinking = getRaRangeShrinking(parameters).equals(SearchTreeRaoRangeActionsOptimizationParameters.RaRangeShrinking.ENABLED); - if (parameters.getObjectiveFunctionParameters().getType().equals(ObjectiveFunctionParameters.ObjectiveFunctionType.SECURE_FLOW)) { + boolean raRangeShrinking = getRaRangeShrinking(parameters).equals( + SearchTreeRaoRangeActionsOptimizationParameters.RaRangeShrinking.ENABLED); + if (parameters.getObjectiveFunctionParameters().getType() + .equals(ObjectiveFunctionParameters.ObjectiveFunctionType.SECURE_FLOW)) { return new TreeParameters(StopCriterion.AT_TARGET_OBJECTIVE_VALUE, 0.0, // secure getMaxPreventiveSearchTreeDepth(parameters), diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/IteratingLinearOptimizer.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/IteratingLinearOptimizer.java index e275acd712..e18ecaf4a8 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/IteratingLinearOptimizer.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/IteratingLinearOptimizer.java @@ -7,6 +7,13 @@ package com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_LOGS; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_WARNS; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.TECHNICAL_LOGS; +import static com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoRangeActionsOptimizationParameters.getPstModel; + +import com.powsybl.iidm.network.Network; +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction; import com.powsybl.openrao.data.raoresult.api.ComputationStatus; import com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoRangeActionsOptimizationParameters.PstModel; @@ -17,19 +24,20 @@ import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.LinearProblem; import com.powsybl.openrao.searchtreerao.linearoptimisation.inputs.IteratingLinearOptimizerInput; import com.powsybl.openrao.searchtreerao.linearoptimisation.parameters.IteratingLinearOptimizerParameters; -import com.powsybl.openrao.searchtreerao.result.api.*; +import com.powsybl.openrao.searchtreerao.result.api.FlowResult; +import com.powsybl.openrao.searchtreerao.result.api.LinearOptimizationResult; +import com.powsybl.openrao.searchtreerao.result.api.LinearProblemStatus; +import com.powsybl.openrao.searchtreerao.result.api.NetworkActionsResult; +import com.powsybl.openrao.searchtreerao.result.api.ObjectiveFunctionResult; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionActivationResult; +import com.powsybl.openrao.searchtreerao.result.api.SensitivityResult; import com.powsybl.openrao.searchtreerao.result.impl.IteratingLinearOptimizationResultImpl; import com.powsybl.openrao.searchtreerao.result.impl.LinearProblemResult; import com.powsybl.openrao.searchtreerao.result.impl.RangeActionActivationResultImpl; import com.powsybl.openrao.searchtreerao.result.impl.RemedialActionActivationResultImpl; import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions; -import com.powsybl.iidm.network.Network; -import org.apache.commons.lang3.tuple.Pair; - import java.util.Locale; - -import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.*; -import static com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoRangeActionsOptimizationParameters.getPstModel; +import org.apache.commons.lang3.tuple.Pair; /** * @author Joris Mancini {@literal } @@ -40,68 +48,83 @@ private IteratingLinearOptimizer() { } - public static LinearOptimizationResult optimize(IteratingLinearOptimizerInput input, IteratingLinearOptimizerParameters parameters) { + public static LinearOptimizationResult optimize(IteratingLinearOptimizerInput input, + IteratingLinearOptimizerParameters parameters) { IteratingLinearOptimizationResultImpl bestResult = createResult( - input.preOptimizationFlowResult(), - input.preOptimizationSensitivityResult(), - input.raActivationFromParentLeaf(), - input.appliedNetworkActionsInPrimaryState(), - 0, - input.objectiveFunction()); + input.preOptimizationFlowResult(), + input.preOptimizationSensitivityResult(), + input.raActivationFromParentLeaf(), + input.appliedNetworkActionsInPrimaryState(), + 0, + input.objectiveFunction()); IteratingLinearOptimizationResultImpl previousResult = bestResult; SensitivityComputer sensitivityComputer = null; LinearProblem linearProblem = LinearProblem.create() - .buildFromInputsAndParameters(input, parameters); + .buildFromInputsAndParameters(input, parameters); - linearProblem.fill(input.preOptimizationFlowResult(), input.preOptimizationSensitivityResult()); + linearProblem.fill(input.preOptimizationFlowResult(), + input.preOptimizationSensitivityResult()); for (int iteration = 1; iteration <= parameters.getMaxNumberOfIterations(); iteration++) { LinearProblemStatus solveStatus = solveLinearProblem(linearProblem, iteration); bestResult.setNbOfIteration(iteration); if (solveStatus == LinearProblemStatus.FEASIBLE) { - TECHNICAL_LOGS.warn("The solver was interrupted. A feasible solution has been produced."); + TECHNICAL_LOGS.warn( + "The solver was interrupted. A feasible solution has been produced."); } else if (solveStatus != LinearProblemStatus.OPTIMAL) { BUSINESS_LOGS.error("Linear optimization failed at iteration {}", iteration); if (iteration == 1) { bestResult.setStatus(solveStatus); - BUSINESS_LOGS.info("Linear problem failed with the following status : {}, initial situation is kept.", solveStatus); + BUSINESS_LOGS.info( + "Linear problem failed with the following status : {}, initial situation is kept.", + solveStatus); return bestResult; } bestResult.setStatus(LinearProblemStatus.FEASIBLE); return bestResult; } - RangeActionActivationResult linearProblemResult = new LinearProblemResult(linearProblem, input.prePerimeterSetpoints(), input.optimizationPerimeter()); - RangeActionActivationResult currentRangeActionActivationResult = roundResult(linearProblemResult, bestResult, input, parameters); - currentRangeActionActivationResult = resolveIfApproximatedPstTaps(bestResult, linearProblem, iteration, currentRangeActionActivationResult, input, parameters); + RangeActionActivationResult linearProblemResult = new LinearProblemResult(linearProblem, + input.prePerimeterSetpoints(), input.optimizationPerimeter()); + RangeActionActivationResult currentRangeActionActivationResult = roundResult( + linearProblemResult, bestResult, input, parameters); + currentRangeActionActivationResult = resolveIfApproximatedPstTaps(bestResult, + linearProblem, iteration, currentRangeActionActivationResult, input, parameters); - if (!hasAnyRangeActionChanged(currentRangeActionActivationResult, previousResult, input.optimizationPerimeter())) { + if (!hasAnyRangeActionChanged(currentRangeActionActivationResult, previousResult, + input.optimizationPerimeter())) { // If the solution has not changed, no need to run a new sensitivity computation and iteration can stop - TECHNICAL_LOGS.info("Iteration {}: same results as previous iterations, optimal solution found", iteration); + TECHNICAL_LOGS.info( + "Iteration {}: same results as previous iterations, optimal solution found", + iteration); return bestResult; } - sensitivityComputer = runSensitivityAnalysis(sensitivityComputer, iteration, currentRangeActionActivationResult, input, parameters); - if (sensitivityComputer.getSensitivityResult().getSensitivityStatus() == ComputationStatus.FAILURE) { + sensitivityComputer = runSensitivityAnalysis(sensitivityComputer, iteration, + currentRangeActionActivationResult, input, parameters); + if (sensitivityComputer.getSensitivityResult().getSensitivityStatus() + == ComputationStatus.FAILURE) { bestResult.setStatus(LinearProblemStatus.SENSITIVITY_COMPUTATION_FAILED); return bestResult; } IteratingLinearOptimizationResultImpl currentResult = createResult( - sensitivityComputer.getBranchResult(input.network()), - sensitivityComputer.getSensitivityResult(), - currentRangeActionActivationResult, - input.appliedNetworkActionsInPrimaryState(), - iteration, - input.objectiveFunction() + sensitivityComputer.getBranchResult(input.network()), + sensitivityComputer.getSensitivityResult(), + currentRangeActionActivationResult, + input.appliedNetworkActionsInPrimaryState(), + iteration, + input.objectiveFunction() ); previousResult = currentResult; - Pair mipShouldStop = updateBestResultAndCheckStopCondition(parameters.getRaRangeShrinking(), linearProblem, input, iteration, currentResult, bestResult); + Pair mipShouldStop = updateBestResultAndCheckStopCondition( + parameters.getRaRangeShrinking(), linearProblem, input, iteration, currentResult, + bestResult); if (Boolean.TRUE.equals(mipShouldStop.getRight())) { return bestResult; } else { @@ -112,25 +135,36 @@ public static LinearOptimizationResult optimize(IteratingLinearOptimizerInput in return bestResult; } - private static SensitivityComputer runSensitivityAnalysis(SensitivityComputer sensitivityComputer, int iteration, RangeActionActivationResult currentRangeActionActivationResult, IteratingLinearOptimizerInput input, IteratingLinearOptimizerParameters parameters) { + private static SensitivityComputer runSensitivityAnalysis( + SensitivityComputer sensitivityComputer, int iteration, + RangeActionActivationResult currentRangeActionActivationResult, + IteratingLinearOptimizerInput input, IteratingLinearOptimizerParameters parameters) { SensitivityComputer tmpSensitivityComputer = sensitivityComputer; if (input.optimizationPerimeter() instanceof GlobalOptimizationPerimeter) { - AppliedRemedialActions appliedRemedialActionsInSecondaryStates = applyRangeActions(currentRangeActionActivationResult, input); - tmpSensitivityComputer = createSensitivityComputer(appliedRemedialActionsInSecondaryStates, input, parameters); + AppliedRemedialActions appliedRemedialActionsInSecondaryStates = applyRangeActions( + currentRangeActionActivationResult, input); + tmpSensitivityComputer = createSensitivityComputer( + appliedRemedialActionsInSecondaryStates, input, parameters); } else { applyRangeActions(currentRangeActionActivationResult, input); - if (tmpSensitivityComputer == null) { // first iteration, do not need to be updated afterwards - tmpSensitivityComputer = createSensitivityComputer(input.preOptimizationAppliedRemedialActions(), input, parameters); + if (tmpSensitivityComputer + == null) { // first iteration, do not need to be updated afterwards + tmpSensitivityComputer = createSensitivityComputer( + input.preOptimizationAppliedRemedialActions(), input, parameters); } } runSensitivityAnalysis(tmpSensitivityComputer, input.network(), iteration); return tmpSensitivityComputer; } - private static RangeActionActivationResult resolveIfApproximatedPstTaps(IteratingLinearOptimizationResultImpl bestResult, LinearProblem linearProblem, int iteration, RangeActionActivationResult currentRangeActionActivationResult, IteratingLinearOptimizerInput input, IteratingLinearOptimizerParameters parameters) { + private static RangeActionActivationResult resolveIfApproximatedPstTaps( + IteratingLinearOptimizationResultImpl bestResult, LinearProblem linearProblem, + int iteration, RangeActionActivationResult currentRangeActionActivationResult, + IteratingLinearOptimizerInput input, IteratingLinearOptimizerParameters parameters) { LinearProblemStatus solveStatus; RangeActionActivationResult rangeActionActivationResult = currentRangeActionActivationResult; - if (getPstModel(parameters.getRangeActionParametersExtension()).equals(PstModel.APPROXIMATED_INTEGERS)) { + if (getPstModel(parameters.getRangeActionParametersExtension()).equals( + PstModel.APPROXIMATED_INTEGERS)) { // if the PST approximation is APPROXIMATED_INTEGERS, we re-solve the optimization problem // but first, we update it, with an adjustment of the PSTs angleToTap conversion factors, to @@ -140,65 +174,93 @@ private static RangeActionActivationResult resolveIfApproximatedPstTaps(Iteratin linearProblem.updateBetweenMipIteration(rangeActionActivationResult); solveStatus = solveLinearProblem(linearProblem, iteration); - if (solveStatus == LinearProblemStatus.OPTIMAL || solveStatus == LinearProblemStatus.FEASIBLE) { - RangeActionActivationResult updatedLinearProblemResult = new LinearProblemResult(linearProblem, input.prePerimeterSetpoints(), input.optimizationPerimeter()); - rangeActionActivationResult = roundResult(updatedLinearProblemResult, bestResult, input, parameters); + if (solveStatus == LinearProblemStatus.OPTIMAL + || solveStatus == LinearProblemStatus.FEASIBLE) { + RangeActionActivationResult updatedLinearProblemResult = new LinearProblemResult( + linearProblem, input.prePerimeterSetpoints(), input.optimizationPerimeter()); + rangeActionActivationResult = roundResult(updatedLinearProblemResult, bestResult, + input, parameters); } } return rangeActionActivationResult; } - private static LinearProblemStatus solveLinearProblem(LinearProblem linearProblem, int iteration) { - TECHNICAL_LOGS.debug("Iteration {}: linear optimization [start]", iteration); - LinearProblemStatus status = linearProblem.solve(); - TECHNICAL_LOGS.debug("Iteration {}: linear optimization [end]", iteration); - return status; + private static LinearProblemStatus solveLinearProblem(LinearProblem linearProblem, + int iteration) { + return OpenTelemetryReporter.withSpan("rao.iteratingLinearSolver.solveLinearProblem", + cx -> { + TECHNICAL_LOGS.debug("Iteration {}: linear optimization [start]", iteration); + LinearProblemStatus status = linearProblem.solve(); + TECHNICAL_LOGS.debug("Iteration {}: linear optimization [end]", iteration); + return status; + }); } - private static boolean hasAnyRangeActionChanged(RangeActionActivationResult newRangeActionActivationResult, RangeActionActivationResult oldRangeActionActivationResult, OptimizationPerimeter optimizationContext) { + private static boolean hasAnyRangeActionChanged( + RangeActionActivationResult newRangeActionActivationResult, + RangeActionActivationResult oldRangeActionActivationResult, + OptimizationPerimeter optimizationContext) { return optimizationContext.getRangeActionsPerState().entrySet().stream() - .anyMatch(e -> e.getValue().stream() - .anyMatch(ra -> Math.abs(newRangeActionActivationResult.getOptimizedSetpoint(ra, e.getKey()) - oldRangeActionActivationResult.getOptimizedSetpoint(ra, e.getKey())) >= 1e-6)); + .anyMatch(e -> e.getValue().stream() + .anyMatch(ra -> Math.abs( + newRangeActionActivationResult.getOptimizedSetpoint(ra, e.getKey()) + - oldRangeActionActivationResult.getOptimizedSetpoint(ra, e.getKey())) + >= 1e-6)); } - public static AppliedRemedialActions applyRangeActions(RangeActionActivationResult rangeActionActivationResult, IteratingLinearOptimizerInput input) { + public static AppliedRemedialActions applyRangeActions( + RangeActionActivationResult rangeActionActivationResult, + IteratingLinearOptimizerInput input) { OptimizationPerimeter optimizationContext = input.optimizationPerimeter(); // apply RangeAction from first optimization state - optimizationContext.getRangeActionsPerState().get(optimizationContext.getMainOptimizationState()) - .forEach(ra -> ra.apply(input.network(), rangeActionActivationResult.getOptimizedSetpoint(ra, optimizationContext.getMainOptimizationState()))); + optimizationContext.getRangeActionsPerState() + .get(optimizationContext.getMainOptimizationState()) + .forEach(ra -> ra.apply(input.network(), + rangeActionActivationResult.getOptimizedSetpoint(ra, + optimizationContext.getMainOptimizationState()))); // add RangeAction activated in the following states if (optimizationContext instanceof GlobalOptimizationPerimeter) { - AppliedRemedialActions appliedRemedialActions = input.preOptimizationAppliedRemedialActions().copyNetworkActionsAndAutomaticRangeActions(); + AppliedRemedialActions appliedRemedialActions = input.preOptimizationAppliedRemedialActions() + .copyNetworkActionsAndAutomaticRangeActions(); optimizationContext.getRangeActionsPerState().entrySet().stream() - .filter(e -> !e.getKey().equals(optimizationContext.getMainOptimizationState())) // remove preventive state - .forEach(e -> e.getValue().forEach(ra -> appliedRemedialActions.addAppliedRangeAction(e.getKey(), ra, rangeActionActivationResult.getOptimizedSetpoint(ra, e.getKey())))); + .filter(e -> !e.getKey().equals( + optimizationContext.getMainOptimizationState())) // remove preventive state + .forEach(e -> e.getValue().forEach( + ra -> appliedRemedialActions.addAppliedRangeAction(e.getKey(), ra, + rangeActionActivationResult.getOptimizedSetpoint(ra, e.getKey())))); return appliedRemedialActions; } else { return null; } } - private static SensitivityComputer createSensitivityComputer(AppliedRemedialActions appliedRemedialActions, IteratingLinearOptimizerInput input, IteratingLinearOptimizerParameters parameters) { + private static SensitivityComputer createSensitivityComputer( + AppliedRemedialActions appliedRemedialActions, IteratingLinearOptimizerInput input, + IteratingLinearOptimizerParameters parameters) { SensitivityComputer.SensitivityComputerBuilder builder = SensitivityComputer.create() - .withCnecs(input.optimizationPerimeter().getFlowCnecs()) - .withRangeActions(input.optimizationPerimeter().getRangeActions()) - .withAppliedRemedialActions(appliedRemedialActions) - .withToolProvider(input.toolProvider()) - .withOutageInstant(input.outageInstant()); - - if (parameters.isRaoWithLoopFlowLimitation() && parameters.getLoopFlowParametersExtension().getPtdfApproximation().shouldUpdatePtdfWithPstChange()) { - builder.withCommercialFlowsResults(input.toolProvider().getLoopFlowComputation(), input.optimizationPerimeter().getLoopFlowCnecs()); + .withCnecs(input.optimizationPerimeter().getFlowCnecs()) + .withRangeActions(input.optimizationPerimeter().getRangeActions()) + .withAppliedRemedialActions(appliedRemedialActions) + .withToolProvider(input.toolProvider()) + .withOutageInstant(input.outageInstant()); + + if (parameters.isRaoWithLoopFlowLimitation() && parameters.getLoopFlowParametersExtension() + .getPtdfApproximation().shouldUpdatePtdfWithPstChange()) { + builder.withCommercialFlowsResults(input.toolProvider().getLoopFlowComputation(), + input.optimizationPerimeter().getLoopFlowCnecs()); } else if (parameters.isRaoWithLoopFlowLimitation()) { builder.withCommercialFlowsResults(input.preOptimizationFlowResult()); } if (parameters.getObjectiveFunction().relativePositiveMargins()) { - if (parameters.getMaxMinRelativeMarginParameters().getPtdfApproximation().shouldUpdatePtdfWithPstChange()) { - builder.withPtdfsResults(input.toolProvider().getAbsolutePtdfSumsComputation(), input.optimizationPerimeter().getFlowCnecs()); + if (parameters.getMaxMinRelativeMarginParameters().getPtdfApproximation() + .shouldUpdatePtdfWithPstChange()) { + builder.withPtdfsResults(input.toolProvider().getAbsolutePtdfSumsComputation(), + input.optimizationPerimeter().getFlowCnecs()); } else { builder.withPtdfsResults(input.preOptimizationFlowResult()); } @@ -207,45 +269,66 @@ private static SensitivityComputer createSensitivityComputer(AppliedRemedialActi return builder.build(); } - private static void runSensitivityAnalysis(SensitivityComputer sensitivityComputer, Network network, int iteration) { + private static void runSensitivityAnalysis(SensitivityComputer sensitivityComputer, + Network network, int iteration) { sensitivityComputer.compute(network); - if (sensitivityComputer.getSensitivityResult().getSensitivityStatus() == ComputationStatus.FAILURE) { - BUSINESS_WARNS.warn("Systematic sensitivity computation failed at iteration {}", iteration); + if (sensitivityComputer.getSensitivityResult().getSensitivityStatus() + == ComputationStatus.FAILURE) { + BUSINESS_WARNS.warn("Systematic sensitivity computation failed at iteration {}", + iteration); } } private static IteratingLinearOptimizationResultImpl createResult(FlowResult flowResult, - SensitivityResult sensitivityResult, - RangeActionActivationResult rangeActionActivation, - NetworkActionsResult networkActionsResult, - int nbOfIterations, - ObjectiveFunction objectiveFunction) { - return new IteratingLinearOptimizationResultImpl(LinearProblemStatus.OPTIMAL, nbOfIterations, rangeActionActivation, flowResult, - objectiveFunction.evaluate(flowResult, new RemedialActionActivationResultImpl(rangeActionActivation, networkActionsResult)), sensitivityResult); + SensitivityResult sensitivityResult, + RangeActionActivationResult rangeActionActivation, + NetworkActionsResult networkActionsResult, + int nbOfIterations, + ObjectiveFunction objectiveFunction) { + return new IteratingLinearOptimizationResultImpl(LinearProblemStatus.OPTIMAL, + nbOfIterations, rangeActionActivation, flowResult, + objectiveFunction.evaluate(flowResult, + new RemedialActionActivationResultImpl(rangeActionActivation, + networkActionsResult)), sensitivityResult); } - private static Pair updateBestResultAndCheckStopCondition(boolean raRangeShrinking, LinearProblem linearProblem, IteratingLinearOptimizerInput input, int iteration, IteratingLinearOptimizationResultImpl currentResult, IteratingLinearOptimizationResultImpl bestResult) { + private static Pair updateBestResultAndCheckStopCondition( + boolean raRangeShrinking, LinearProblem linearProblem, IteratingLinearOptimizerInput input, + int iteration, IteratingLinearOptimizationResultImpl currentResult, + IteratingLinearOptimizationResultImpl bestResult) { if (currentResult.getCost() < bestResult.getCost()) { logBetterResult(iteration, currentResult); - linearProblem.updateBetweenSensiIteration(currentResult.getBranchResult(), currentResult.getSensitivityResult(), currentResult.getRangeActionActivationResult()); + linearProblem.updateBetweenSensiIteration(currentResult.getBranchResult(), + currentResult.getSensitivityResult(), + currentResult.getRangeActionActivationResult()); return Pair.of(currentResult, false); } logWorseResult(iteration, bestResult, currentResult); applyRangeActions(bestResult, input); if (raRangeShrinking) { - linearProblem.updateBetweenSensiIteration(currentResult.getBranchResult(), currentResult.getSensitivityResult(), currentResult.getRangeActionActivationResult()); + linearProblem.updateBetweenSensiIteration(currentResult.getBranchResult(), + currentResult.getSensitivityResult(), + currentResult.getRangeActionActivationResult()); } return Pair.of(bestResult, !raRangeShrinking); } - private static RangeActionActivationResult roundResult(RangeActionActivationResult linearProblemResult, IteratingLinearOptimizationResultImpl previousResult, IteratingLinearOptimizerInput input, IteratingLinearOptimizerParameters parameters) { - RangeActionActivationResultImpl roundedResult = roundPsts(linearProblemResult, previousResult, input, parameters); + private static RangeActionActivationResult roundResult( + RangeActionActivationResult linearProblemResult, + IteratingLinearOptimizationResultImpl previousResult, IteratingLinearOptimizerInput input, + IteratingLinearOptimizerParameters parameters) { + RangeActionActivationResultImpl roundedResult = roundPsts(linearProblemResult, + previousResult, input, parameters); roundOtherRas(linearProblemResult, input.optimizationPerimeter(), roundedResult); return roundedResult; } - private static RangeActionActivationResultImpl roundPsts(RangeActionActivationResult linearProblemResult, IteratingLinearOptimizationResultImpl previousResult, IteratingLinearOptimizerInput input, IteratingLinearOptimizerParameters parameters) { - if (getPstModel(parameters.getRangeActionParametersExtension()).equals(PstModel.CONTINUOUS)) { + private static RangeActionActivationResultImpl roundPsts( + RangeActionActivationResult linearProblemResult, + IteratingLinearOptimizationResultImpl previousResult, IteratingLinearOptimizerInput input, + IteratingLinearOptimizerParameters parameters) { + if (getPstModel(parameters.getRangeActionParametersExtension()).equals( + PstModel.CONTINUOUS)) { return BestTapFinder.round( linearProblemResult, input.network(), @@ -255,23 +338,28 @@ private static RangeActionActivationResultImpl roundPsts(RangeActionActivationRe parameters.getFlowUnit() ); } - RangeActionActivationResultImpl roundedResult = new RangeActionActivationResultImpl(input.prePerimeterSetpoints()); - input.optimizationPerimeter().getRangeActionOptimizationStates().forEach(state -> linearProblemResult.getActivatedRangeActions(state) - .stream().filter(PstRangeAction.class::isInstance).map(PstRangeAction.class::cast) - .forEach(pst -> roundedResult.putResult(pst, state, pst.convertTapToAngle(linearProblemResult.getOptimizedTap(pst, state)))) - ); + RangeActionActivationResultImpl roundedResult = new RangeActionActivationResultImpl( + input.prePerimeterSetpoints()); + input.optimizationPerimeter().getRangeActionOptimizationStates() + .forEach(state -> linearProblemResult.getActivatedRangeActions(state) + .stream().filter(PstRangeAction.class::isInstance).map(PstRangeAction.class::cast) + .forEach(pst -> roundedResult.putResult(pst, state, + pst.convertTapToAngle(linearProblemResult.getOptimizedTap(pst, state))))); return roundedResult; } static void roundOtherRas(RangeActionActivationResult linearProblemResult, - OptimizationPerimeter optimizationContext, - RangeActionActivationResultImpl roundedResult) { - optimizationContext.getRangeActionsPerState().keySet().forEach(state -> linearProblemResult.getActivatedRangeActions(state).stream() - .filter(ra -> !(ra instanceof PstRangeAction)) - .forEach(ra -> roundedResult.putResult(ra, state, Math.round(linearProblemResult.getOptimizedSetpoint(ra, state))))); + OptimizationPerimeter optimizationContext, + RangeActionActivationResultImpl roundedResult) { + optimizationContext.getRangeActionsPerState().keySet() + .forEach(state -> linearProblemResult.getActivatedRangeActions(state).stream() + .filter(ra -> !(ra instanceof PstRangeAction)) + .forEach(ra -> roundedResult.putResult(ra, state, + Math.round(linearProblemResult.getOptimizedSetpoint(ra, state))))); } - private static void logBetterResult(int iteration, ObjectiveFunctionResult currentObjectiveFunctionResult) { + private static void logBetterResult(int iteration, + ObjectiveFunctionResult currentObjectiveFunctionResult) { TECHNICAL_LOGS.info( "Iteration {}: better solution found with a cost of {} (functional: {})", iteration, @@ -286,7 +374,8 @@ private static void logBetterResult(int iteration, ObjectiveFunctionResult curre }); } - private static void logWorseResult(int iteration, ObjectiveFunctionResult bestResult, ObjectiveFunctionResult currentResult) { + private static void logWorseResult(int iteration, ObjectiveFunctionResult bestResult, + ObjectiveFunctionResult currentResult) { TECHNICAL_LOGS.info( "Iteration {}: linear optimization found a worse result than best iteration, with a cost increasing from {} to {} (functional: from {} to {})", iteration, diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/OpenRaoMPSolver.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/OpenRaoMPSolver.java index 8e56cc3e5a..f01d323964 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/OpenRaoMPSolver.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/OpenRaoMPSolver.java @@ -12,9 +12,9 @@ import com.google.ortools.linearsolver.MPSolverParameters; import com.powsybl.openrao.commons.OpenRaoException; import com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider; +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; import com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoRangeActionsOptimizationParameters; import com.powsybl.openrao.searchtreerao.result.api.LinearProblemStatus; - import java.util.Map; import java.util.Objects; import java.util.TreeMap; @@ -26,11 +26,13 @@ * @author Peter Mitri {@literal } */ public class OpenRaoMPSolver { + static { try { Loader.loadNativeLibraries(); } catch (Exception e) { - OpenRaoLoggerProvider.TECHNICAL_LOGS.error("Native library jniortools could not be loaded. You can ignore this message if it is not needed."); + OpenRaoLoggerProvider.TECHNICAL_LOGS.error( + "Native library jniortools could not be loaded. You can ignore this message if it is not needed."); } } @@ -52,7 +54,8 @@ public class OpenRaoMPSolver { OpenRaoMPObjective objective; private boolean objectiveMinimization = true; - public OpenRaoMPSolver(String optProblemName, SearchTreeRaoRangeActionsOptimizationParameters.Solver solver) { + public OpenRaoMPSolver(String optProblemName, + SearchTreeRaoRangeActionsOptimizationParameters.Solver solver) { this.solver = solver; this.optProblemName = optProblemName; solveConfiguration = new MPSolverParameters(); @@ -76,13 +79,15 @@ public SearchTreeRaoRangeActionsOptimizationParameters.Solver getSolver() { return solver; } - private MPSolver.OptimizationProblemType getOrToolsProblemType(SearchTreeRaoRangeActionsOptimizationParameters.Solver solver) { + private MPSolver.OptimizationProblemType getOrToolsProblemType( + SearchTreeRaoRangeActionsOptimizationParameters.Solver solver) { Objects.requireNonNull(solver); return switch (solver) { case CBC -> MPSolver.OptimizationProblemType.CBC_MIXED_INTEGER_PROGRAMMING; case SCIP -> MPSolver.OptimizationProblemType.SCIP_MIXED_INTEGER_PROGRAMMING; case XPRESS -> MPSolver.OptimizationProblemType.XPRESS_MIXED_INTEGER_PROGRAMMING; - default -> throw new OpenRaoException(String.format("unknown solver %s in RAO parameters", solver)); + default -> throw new OpenRaoException( + String.format("unknown solver %s in RAO parameters", solver)); }; } @@ -99,7 +104,8 @@ public OpenRaoMPConstraint getConstraint(String name) { if (hasConstraint(name)) { return constraints.get(name); } else { - throw new OpenRaoException(String.format("Constraint %s has not been created yet", name)); + throw new OpenRaoException( + String.format("Constraint %s has not been created yet", name)); } } @@ -137,7 +143,8 @@ private OpenRaoMPVariable makeVar(double lb, double ub, boolean integer, String } double roundedLb = roundDouble(lb); double roundedUb = roundDouble(ub); - OpenRaoMPVariable variable = new OpenRaoMPVariable(mpSolver.makeVar(roundedLb, roundedUb, integer, name)); + OpenRaoMPVariable variable = new OpenRaoMPVariable( + mpSolver.makeVar(roundedLb, roundedUb, integer, name)); variables.put(name, variable); return variable; } @@ -148,7 +155,8 @@ public OpenRaoMPConstraint makeConstraint(double lb, double ub, String name) { } else { double roundedLb = roundDouble(lb); double roundedUb = roundDouble(ub); - OpenRaoMPConstraint constraint = new OpenRaoMPConstraint(mpSolver.makeConstraint(roundedLb, roundedUb, name)); + OpenRaoMPConstraint constraint = new OpenRaoMPConstraint( + mpSolver.makeConstraint(roundedLb, roundedUb, name)); constraints.put(name, constraint); return constraint; } @@ -168,14 +176,17 @@ public boolean setSolverSpecificParametersAsString(String solverSpecificParamete } public void setRelativeMipGap(double relativeMipGap) { - solveConfiguration.setDoubleParam(MPSolverParameters.DoubleParam.RELATIVE_MIP_GAP, relativeMipGap); + solveConfiguration.setDoubleParam(MPSolverParameters.DoubleParam.RELATIVE_MIP_GAP, + relativeMipGap); } public LinearProblemStatus solve() { - if (OpenRaoLoggerProvider.TECHNICAL_LOGS.isTraceEnabled()) { - mpSolver.enableOutput(); - } - return convertResultStatus(mpSolver.solve(solveConfiguration)); + return OpenTelemetryReporter.withSpan("rao.mpsolver.solve", cx -> { + if (OpenRaoLoggerProvider.TECHNICAL_LOGS.isTraceEnabled()) { + mpSolver.enableOutput(); + } + return convertResultStatus(mpSolver.solve(solveConfiguration)); + }); } static LinearProblemStatus convertResultStatus(MPSolver.ResultStatus status) { @@ -237,7 +248,8 @@ static double roundDouble(double value) { return 0.; } double t = value * (1L << NUMBER_OF_BITS_TO_ROUND_OFF); - if (t != Double.POSITIVE_INFINITY && value != Double.NEGATIVE_INFINITY && !Double.isNaN(t)) { + if (t != Double.POSITIVE_INFINITY && value != Double.NEGATIVE_INFINITY && !Double.isNaN( + t)) { return value - t + t; } return value; diff --git a/sensitivity-analysis/src/main/java/com/powsybl/openrao/sensitivityanalysis/SystematicSensitivityInterface.java b/sensitivity-analysis/src/main/java/com/powsybl/openrao/sensitivityanalysis/SystematicSensitivityInterface.java index e2c54aa81d..0bc732d6b5 100644 --- a/sensitivity-analysis/src/main/java/com/powsybl/openrao/sensitivityanalysis/SystematicSensitivityInterface.java +++ b/sensitivity-analysis/src/main/java/com/powsybl/openrao/sensitivityanalysis/SystematicSensitivityInterface.java @@ -7,21 +7,22 @@ package com.powsybl.openrao.sensitivityanalysis; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_WARNS; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.TECHNICAL_LOGS; + +import com.powsybl.glsk.commons.ZonalData; +import com.powsybl.iidm.network.Network; import com.powsybl.openrao.commons.OpenRaoException; import com.powsybl.openrao.commons.Unit; -import com.powsybl.glsk.commons.ZonalData; +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; import com.powsybl.openrao.data.crac.api.Instant; import com.powsybl.openrao.data.crac.api.cnec.FlowCnec; import com.powsybl.openrao.data.crac.api.rangeaction.RangeAction; -import com.powsybl.iidm.network.Network; import com.powsybl.sensitivity.SensitivityAnalysisParameters; import com.powsybl.sensitivity.SensitivityVariableSet; - import java.util.Objects; import java.util.Set; -import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.*; - /** * An interface with the engine that computes sensitivities and flows needed in the RAO. * @@ -30,6 +31,7 @@ * @author Baptiste Seguinot {@literal } */ public final class SystematicSensitivityInterface { + /** * Name of sensitivity analysis provider */ @@ -55,6 +57,7 @@ public final class SystematicSensitivityInterface { * Builder */ public static final class SystematicSensitivityInterfaceBuilder { + private String sensitivityProvider; private SensitivityAnalysisParameters defaultParameters; private final MultipleSensitivityProvider multipleSensitivityProvider = new MultipleSensitivityProvider(); @@ -66,17 +69,20 @@ private SystematicSensitivityInterfaceBuilder() { } - public SystematicSensitivityInterfaceBuilder withSensitivityProviderName(String sensitivityProvider) { + public SystematicSensitivityInterfaceBuilder withSensitivityProviderName( + String sensitivityProvider) { this.sensitivityProvider = sensitivityProvider; return this; } - public SystematicSensitivityInterfaceBuilder withParameters(SensitivityAnalysisParameters defaultParameters) { + public SystematicSensitivityInterfaceBuilder withParameters( + SensitivityAnalysisParameters defaultParameters) { this.defaultParameters = defaultParameters; return this; } - public SystematicSensitivityInterfaceBuilder withSensitivityProvider(CnecSensitivityProvider cnecSensitivityProvider) { + public SystematicSensitivityInterfaceBuilder withSensitivityProvider( + CnecSensitivityProvider cnecSensitivityProvider) { if (Objects.isNull(cnecSensitivityProvider)) { throw new OpenRaoException("Null sensitivity provider."); } @@ -85,26 +91,32 @@ public SystematicSensitivityInterfaceBuilder withSensitivityProvider(CnecSensiti return this; } - public SystematicSensitivityInterfaceBuilder withPtdfSensitivities(ZonalData glsk, Set cnecs, Set units) { + public SystematicSensitivityInterfaceBuilder withPtdfSensitivities( + ZonalData glsk, Set cnecs, Set units) { return this.withSensitivityProvider(new PtdfSensitivityProvider(glsk, cnecs, units)); } - public SystematicSensitivityInterfaceBuilder withRangeActionSensitivities(Set> rangeActions, Set cnecs, Set units) { - return this.withSensitivityProvider(new RangeActionSensitivityProvider(rangeActions, cnecs, units)); + public SystematicSensitivityInterfaceBuilder withRangeActionSensitivities( + Set> rangeActions, Set cnecs, Set units) { + return this.withSensitivityProvider( + new RangeActionSensitivityProvider(rangeActions, cnecs, units)); } - public SystematicSensitivityInterfaceBuilder withLoadflow(Set cnecs, Set units) { + public SystematicSensitivityInterfaceBuilder withLoadflow(Set cnecs, + Set units) { return this.withSensitivityProvider(new LoadflowProvider(cnecs, units)); } - public SystematicSensitivityInterfaceBuilder withAppliedRemedialActions(AppliedRemedialActions appliedRemedialActions) { + public SystematicSensitivityInterfaceBuilder withAppliedRemedialActions( + AppliedRemedialActions appliedRemedialActions) { this.appliedRemedialActions = appliedRemedialActions; return this; } public SystematicSensitivityInterfaceBuilder withOutageInstant(Instant outageInstant) { if (!outageInstant.isOutage()) { - throw new OpenRaoException("Instant provided in the systematic sensitivity builder has to be an outage"); + throw new OpenRaoException( + "Instant provided in the systematic sensitivity builder has to be an outage"); } this.outageInstant = outageInstant; return this; @@ -112,7 +124,8 @@ public SystematicSensitivityInterfaceBuilder withOutageInstant(Instant outageIns public SystematicSensitivityInterface build() { if (Objects.isNull(sensitivityProvider)) { - throw new OpenRaoException("Please provide a sensitivity provider implementation name when building a SystematicSensitivityInterface"); + throw new OpenRaoException( + "Please provide a sensitivity provider implementation name when building a SystematicSensitivityInterface"); } if (!providerInitialised) { throw new OpenRaoException("Sensitivity provider has not been initialized"); @@ -121,7 +134,8 @@ public SystematicSensitivityInterface build() { defaultParameters = new SensitivityAnalysisParameters(); } if (Objects.isNull(outageInstant)) { - throw new OpenRaoException("Outage instant has not been defined in the systematic sensitivity interface"); + throw new OpenRaoException( + "Outage instant has not been defined in the systematic sensitivity interface"); } SystematicSensitivityInterface systematicSensitivityInterface = new SystematicSensitivityInterface(); systematicSensitivityInterface.sensitivityProvider = sensitivityProvider; @@ -146,11 +160,13 @@ public static SystematicSensitivityInterfaceBuilder builder() { * SystematicSensitivityResult to the given network variant. */ public SystematicSensitivityResult run(Network network) { - SystematicSensitivityResult result = runWithConfig(network); - if (!result.isSuccess()) { - BUSINESS_WARNS.warn("Sensitivity analysis failed."); - } - return result; + return OpenTelemetryReporter.withSpan("rao.systematicSA.run", cx -> { + SystematicSensitivityResult result = runWithConfig(network); + if (!result.isSuccess()) { + BUSINESS_WARNS.warn("Sensitivity analysis failed."); + } + return result; + }); } /** @@ -163,7 +179,8 @@ private SystematicSensitivityResult runWithConfig(Network network) { return new SystematicSensitivityResult(); } SystematicSensitivityResult tempSystematicSensitivityAnalysisResult = SystematicSensitivityAdapter - .runSensitivity(network, cnecSensitivityProvider, appliedRemedialActions, parameters, sensitivityProvider, outageInstant); + .runSensitivity(network, cnecSensitivityProvider, appliedRemedialActions, parameters, + sensitivityProvider, outageInstant); if (!tempSystematicSensitivityAnalysisResult.isSuccess()) { TECHNICAL_LOGS.error("Sensitivity analysis failed: no output data available."); diff --git a/util/src/main/java/com/powsybl/openrao/util/MultipleNetworkPool.java b/util/src/main/java/com/powsybl/openrao/util/MultipleNetworkPool.java index 24b5490194..70598ab890 100644 --- a/util/src/main/java/com/powsybl/openrao/util/MultipleNetworkPool.java +++ b/util/src/main/java/com/powsybl/openrao/util/MultipleNetworkPool.java @@ -7,11 +7,13 @@ package com.powsybl.openrao.util; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.TECHNICAL_LOGS; + import com.powsybl.iidm.network.Network; import com.powsybl.iidm.network.VariantManagerConstants; import com.powsybl.iidm.serde.NetworkSerDe; import com.powsybl.openrao.commons.OpenRaoException; - +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -19,8 +21,6 @@ import java.util.concurrent.ForkJoinTask; import java.util.concurrent.atomic.AtomicInteger; -import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.TECHNICAL_LOGS; - /** * @author Sebastien Murgey {@literal } */ @@ -28,7 +28,8 @@ public class MultipleNetworkPool extends AbstractNetworkPool { private int networkNumberOfClones = 0; - protected MultipleNetworkPool(Network network, String targetVariant, int parallelism, boolean initClones) { + protected MultipleNetworkPool(Network network, String targetVariant, int parallelism, + boolean initClones) { super(network, targetVariant, parallelism); if (initClones) { initClones(parallelism); @@ -41,7 +42,8 @@ protected void cleanVariants(Network networkClone) { .filter(variantId -> !variantId.equals(VariantManagerConstants.INITIAL_VARIANT_ID)) .filter(variantId -> !variantId.equals(stateSaveVariant)) .toList(); - variantsToBeRemoved.forEach(variantId -> networkClone.getVariantManager().removeVariant(variantId)); + variantsToBeRemoved.forEach( + variantId -> networkClone.getVariantManager().removeVariant(variantId)); } @Override @@ -52,41 +54,47 @@ public int getNetworkNumberOfClones() { @Override public void initClones(int desiredNumberOfClones) { - int requiredClones = Math.min(getParallelism(), desiredNumberOfClones); - int clonesToAdd = requiredClones - networkNumberOfClones; + OpenTelemetryReporter.withSpan("rao.multipleNetworkPool.initClones", cx -> { + int requiredClones = Math.min(getParallelism(), desiredNumberOfClones); + int clonesToAdd = requiredClones - networkNumberOfClones; - if (clonesToAdd == 0) { - return; - } + if (clonesToAdd == 0) { + return; + } - TECHNICAL_LOGS.debug("Filling network pool with {} new cop{} of network {} on variant {}", clonesToAdd, clonesToAdd == 1 ? "y" : "ies", network.getId(), targetVariant); + TECHNICAL_LOGS.debug( + "Filling network pool with {} new cop{} of network {} on variant {}", + clonesToAdd, clonesToAdd == 1 ? "y" : "ies", network.getId(), targetVariant); - String initialVariant = network.getVariantManager().getWorkingVariantId(); - network.getVariantManager().setWorkingVariant(targetVariant); + String initialVariant = network.getVariantManager().getWorkingVariantId(); + network.getVariantManager().setWorkingVariant(targetVariant); - AtomicInteger remainingClones = new AtomicInteger(requiredClones); - List> tasks = new ArrayList<>(); - try { - for (int i = networkNumberOfClones; i < requiredClones; i++) { - int finalI = i; - tasks.add(this.submit(() -> createNetworkCopy(finalI, remainingClones))); - } - for (ForkJoinTask task : tasks) { - try { - boolean isSuccess = networksQueue.offer(task.get()); - if (!isSuccess) { - throw new OpenRaoException(String.format("Cannot offer copy n°'%d' in pool. Should not happen", networkNumberOfClones + 1)); - } else { - networkNumberOfClones++; + AtomicInteger remainingClones = new AtomicInteger(requiredClones); + List> tasks = new ArrayList<>(); + try { + for (int i = networkNumberOfClones; i < requiredClones; i++) { + int finalI = i; + tasks.add(this.submit(() -> createNetworkCopy(finalI, remainingClones))); + } + for (ForkJoinTask task : tasks) { + try { + boolean isSuccess = networksQueue.offer(task.get()); + if (!isSuccess) { + throw new OpenRaoException( + String.format("Cannot offer copy n°'%d' in pool. Should not happen", + networkNumberOfClones + 1)); + } else { + networkNumberOfClones++; + } + } catch (ExecutionException e) { + throw new OpenRaoException(e); } - } catch (ExecutionException e) { - throw new OpenRaoException(e); } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - network.getVariantManager().setWorkingVariant(initialVariant); + network.getVariantManager().setWorkingVariant(initialVariant); + }); } private Network createNetworkCopy(int finalI, AtomicInteger remainingClones) { @@ -94,8 +102,10 @@ private Network createNetworkCopy(int finalI, AtomicInteger remainingClones) { Network copy = NetworkSerDe.copy(network); // The initial network working variant is VariantManagerConstants.INITIAL_VARIANT_ID // in cloned network, so we need to copy it again. - copy.getVariantManager().cloneVariant(VariantManagerConstants.INITIAL_VARIANT_ID, Arrays.asList(stateSaveVariant, workingVariant), true); + copy.getVariantManager().cloneVariant(VariantManagerConstants.INITIAL_VARIANT_ID, + Arrays.asList(stateSaveVariant, workingVariant), true); remainingClones.decrementAndGet(); return copy; } } + diff --git a/util/src/test/java/com/powsybl/openrao/util/NetworkPoolTest.java b/util/src/test/java/com/powsybl/openrao/util/NetworkPoolTest.java index dfb182da89..888498e585 100644 --- a/util/src/test/java/com/powsybl/openrao/util/NetworkPoolTest.java +++ b/util/src/test/java/com/powsybl/openrao/util/NetworkPoolTest.java @@ -7,26 +7,31 @@ package com.powsybl.openrao.util; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; import com.powsybl.iidm.network.Network; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; - +import com.powsybl.openrao.commons.opentelemetry.OpenTelemetryReporter; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; /** * @author Sebastien Murgey {@literal } */ class NetworkPoolTest { + private Network network; private String initialVariant; private String otherVariant = "otherVariant"; @@ -40,20 +45,24 @@ public void setUp() { @Test void testCreate() { - assertTrue(AbstractNetworkPool.create(network, otherVariant, 10, true) instanceof MultipleNetworkPool); - assertTrue(AbstractNetworkPool.create(network, otherVariant, 1, true) instanceof SingleNetworkPool); + assertTrue(AbstractNetworkPool.create(network, otherVariant, 10, + true) instanceof MultipleNetworkPool); + assertTrue(AbstractNetworkPool.create(network, otherVariant, 1, + true) instanceof SingleNetworkPool); } @Test void networkPoolUsageTest() { - try (AbstractNetworkPool pool = AbstractNetworkPool.create(network, otherVariant, 10, false)) { + try (AbstractNetworkPool pool = AbstractNetworkPool.create(network, otherVariant, 10, + false)) { pool.initClones(4); Network networkCopy = pool.getAvailableNetwork(); assertNotNull(networkCopy); assertNotEquals(network, networkCopy); - assertTrue(networkCopy.getVariantManager().getWorkingVariantId().startsWith("OpenRaoNetworkPool working variant")); + assertTrue(networkCopy.getVariantManager().getWorkingVariantId() + .startsWith("OpenRaoNetworkPool working variant")); pool.initClones(1); assertNotEquals(network, pool.getAvailableNetwork()); @@ -73,7 +82,8 @@ void singleNetworkPoolUsageTest() throws InterruptedException { assertNotNull(networkCopy); assertEquals(network, networkCopy); assertEquals(4, network.getVariantManager().getVariantIds().size()); - assertTrue(networkCopy.getVariantManager().getWorkingVariantId().startsWith("OpenRaoNetworkPool working variant")); + assertTrue(networkCopy.getVariantManager().getWorkingVariantId() + .startsWith("OpenRaoNetworkPool working variant")); pool.releaseUsedNetwork(networkCopy); @@ -88,19 +98,22 @@ void checkMDCIsCopied() throws InterruptedException { listAppender.start(); logger.addAppender(listAppender); - MDC.put("extrafield", "value from caller"); - AbstractNetworkPool pool = AbstractNetworkPool.create(network, otherVariant, 20, true); - for (int i = 0; i < 20; i++) { - pool.submit(() -> { - LoggerFactory.getLogger("LOGGER").info("Hello from forked thread"); - }); - } - pool.shutdownAndAwaitTermination(1, TimeUnit.SECONDS); + OpenTelemetryReporter.withSpan("checkMDCIsCopied", cx -> { + MDC.put("extrafield", "value from caller"); + AbstractNetworkPool pool = AbstractNetworkPool.create(network, otherVariant, 20, true); + for (int i = 0; i < 20; i++) { + pool.submit(() -> { + LoggerFactory.getLogger("LOGGER").info("Hello from forked thread"); + }); + } + pool.shutdownAndAwaitTermination(1, TimeUnit.SECONDS); + }); List logsList = listAppender.list; for (int i = 0; i < 20; i++) { assertTrue(logsList.get(i).getMDCPropertyMap().containsKey("extrafield")); - assertEquals("value from caller", logsList.get(i).getMDCPropertyMap().get("extrafield")); + assertEquals("value from caller", + logsList.get(i).getMDCPropertyMap().get("extrafield")); } }