Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2026, 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.data.raoresult.api.extension;

import com.powsybl.commons.extensions.AbstractExtension;
import com.powsybl.openrao.data.raoresult.api.RaoResult;

import java.time.OffsetDateTime;
import java.util.Optional;

/**
* @author Thomas Bouquet {@literal <thomas.bouquet at rte-france.com>}
*/
public abstract class AbstractMetadata extends AbstractExtension<RaoResult> implements RaoMetadata {
protected OffsetDateTime computationStart;
protected OffsetDateTime computationEnd;
protected String executionDetails;

protected AbstractMetadata() {
}

public Optional<OffsetDateTime> getComputationStart() {
return Optional.ofNullable(computationStart);
}

public void setComputationStart(OffsetDateTime computationStart) {
this.computationStart = computationStart;
}

public Optional<OffsetDateTime> getComputationEnd() {
return Optional.ofNullable(computationEnd);
}

public void setComputationEnd(OffsetDateTime computationEnd) {
this.computationEnd = computationEnd;
}

public String getExecutionDetails() {
return executionDetails;
}

public void setExecutionDetails(String executionDetails) {
this.executionDetails = executionDetails;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2026, 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.data.raoresult.api.extension;

import com.powsybl.commons.extensions.Extension;
import com.powsybl.openrao.data.raoresult.api.RaoResult;

import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.Optional;

/**
* @author Thomas Bouquet {@literal <thomas.bouquet at rte-france.com>}
*/
public interface RaoMetadata extends Extension<RaoResult> {
Optional<OffsetDateTime> getComputationStart();

void setComputationStart(OffsetDateTime computationStart);

Optional<OffsetDateTime> getComputationEnd();

void setComputationEnd(OffsetDateTime computationEnd);

default Optional<Duration> getComputationDuration() {
Optional<OffsetDateTime> start = getComputationStart();
Optional<OffsetDateTime> end = getComputationEnd();
if (start.isPresent() && end.isPresent()) {
return Optional.of(Duration.between(start.orElseThrow(), end.orElseThrow()));
}
return Optional.empty();
}

String getExecutionDetails();

void setExecutionDetails(String executionDetails);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2026, 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.data.raoresult.api;

import org.junit.jupiter.api.Test;

import java.time.Duration;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* @author Thomas Bouquet {@literal <thomas.bouquet at rte-france.com>}
*/
public class MetadataTest {
@Test
public void testMetadataExtension() {
RaoResult raoResult = new MockRaoResult();
MockMetadata metadata = new MockMetadata();
raoResult.addExtension(MockMetadata.class, metadata);

assertNotNull(raoResult.getExtension(MockMetadata.class));
assertTrue(raoResult.getExtension(MockMetadata.class).getComputationStart().isEmpty());
assertTrue(raoResult.getExtension(MockMetadata.class).getComputationEnd().isEmpty());
assertTrue(raoResult.getExtension(MockMetadata.class).getComputationDuration().isEmpty());
assertEquals(ComputationStatus.DEFAULT, metadata.getComputationStatus());

metadata.setComputationStart(OffsetDateTime.of(2026, 3, 2, 10, 19, 0, 0, ZoneOffset.UTC));
metadata.setComputationEnd(OffsetDateTime.of(2026, 3, 2, 10, 20, 30, 0, ZoneOffset.UTC));
metadata.setExecutionDetails(ComputationStatus.FAILURE);

assertTrue(raoResult.getExtension(MockMetadata.class).getComputationStart().isPresent());
assertTrue(raoResult.getExtension(MockMetadata.class).getComputationEnd().isPresent());
assertTrue(raoResult.getExtension(MockMetadata.class).getComputationDuration().isPresent());

assertEquals(OffsetDateTime.of(2026, 3, 2, 10, 19, 0, 0, ZoneOffset.UTC), raoResult.getExtension(MockMetadata.class).getComputationStart().get());
assertEquals(OffsetDateTime.of(2026, 3, 2, 10, 20, 30, 0, ZoneOffset.UTC), raoResult.getExtension(MockMetadata.class).getComputationEnd().get());
assertEquals(Duration.of(90, ChronoUnit.SECONDS), raoResult.getExtension(MockMetadata.class).getComputationDuration().get());
assertEquals(ComputationStatus.FAILURE, raoResult.getExtension(MockMetadata.class).getComputationStatus());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2026, 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.data.raoresult.api;

import com.powsybl.openrao.data.raoresult.api.extension.AbstractMetadata;

/**
* @author Thomas Bouquet {@literal <thomas.bouquet at rte-france.com>}
*/
public class MockMetadata extends AbstractMetadata {
@Override
public String getName() {
return "mock-metadata";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2026, 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.data.raoresult.io.json.extension;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.powsybl.openrao.data.raoresult.api.extension.RaoMetadata;
import com.powsybl.openrao.data.raoresult.io.json.RaoResultJsonUtils;

import java.io.IOException;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Optional;

/**
* @author Thomas Bouquet {@literal <thomas.bouquet at rte-france.com>}
*/
public abstract class AbstractJsonMetadata<E extends RaoMetadata> implements RaoResultJsonUtils.ExtensionSerializer<E> {
protected static final String EXECUTION_DETAILS = "executionDetails";
protected static final String COMPUTATION_START = "computationStart";
protected static final String COMPUTATION_END = "computationEnd";
protected static final String COMPUTATION_DURATION = "computationDuration";
protected static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");

@Override
public void serialize(E metadata, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField(EXECUTION_DETAILS, metadata.getExecutionDetails());
Optional<OffsetDateTime> computationStart = metadata.getComputationStart();
if (computationStart.isPresent()) {
jsonGenerator.writeStringField(COMPUTATION_START, computationStart.get().format(FORMATTER));
}
Optional<OffsetDateTime> computationEnd = metadata.getComputationEnd();
if (computationEnd.isPresent()) {
jsonGenerator.writeStringField(COMPUTATION_END, computationEnd.get().format(FORMATTER));
}
Optional<Duration> duration = metadata.getComputationDuration();
if (duration.isPresent()) {
jsonGenerator.writeStringField(COMPUTATION_DURATION, duration.get().toString());
}
serializeImplementationSpecificMetadata(metadata, jsonGenerator, serializerProvider);
jsonGenerator.writeEndObject();
}

protected abstract void serializeImplementationSpecificMetadata(E metadata, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
import java.util.Set;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;

/**
* @author Thomas Bouquet {@literal <thomas.bouquet at rte-france.com>}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import java.util.Properties;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* @author Philippe Edwards {@literal <philippe.edwards at rte-france.com>}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@
import com.powsybl.openrao.data.crac.api.cnec.FlowCnec;
import com.powsybl.openrao.data.crac.api.networkaction.NetworkAction;
import com.powsybl.openrao.data.crac.api.rangeaction.RangeAction;
import com.powsybl.openrao.data.raoresult.api.TimeCoupledRaoResult;
import com.powsybl.openrao.data.raoresult.api.RaoResult;
import com.powsybl.openrao.raoapi.*;
import com.powsybl.openrao.data.raoresult.api.TimeCoupledRaoResult;
import com.powsybl.openrao.raoapi.RaoInput;
import com.powsybl.openrao.raoapi.RaoInputWithNetworkPaths;
import com.powsybl.openrao.raoapi.TimeCoupledRaoInput;
import com.powsybl.openrao.raoapi.TimeCoupledRaoInputWithNetworkPaths;
import com.powsybl.openrao.raoapi.TimeCoupledRaoProvider;
import com.powsybl.openrao.raoapi.parameters.RaoParameters;
import com.powsybl.openrao.raoapi.parameters.extensions.OpenRaoSearchTreeParameters;
import com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoCostlyMinMarginParameters;
Expand All @@ -36,23 +40,39 @@
import com.powsybl.openrao.searchtreerao.marmot.results.GlobalFlowResult;
import com.powsybl.openrao.searchtreerao.marmot.results.GlobalLinearOptimizationResult;
import com.powsybl.openrao.searchtreerao.marmot.results.TimeCoupledRaoResultImpl;
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.PrePerimeterResult;
import com.powsybl.openrao.searchtreerao.result.impl.*;
import com.powsybl.openrao.searchtreerao.result.api.RangeActionActivationResult;
import com.powsybl.openrao.searchtreerao.result.api.RangeActionSetpointResult;
import com.powsybl.openrao.searchtreerao.result.impl.FastRaoResultImpl;
import com.powsybl.openrao.searchtreerao.result.impl.LightFastRaoResultImpl;
import com.powsybl.openrao.searchtreerao.result.impl.NetworkActionsResultImpl;
import com.powsybl.openrao.searchtreerao.result.impl.RangeActionActivationResultImpl;
import com.powsybl.openrao.searchtreerao.result.impl.RangeActionSetpointResultImpl;
import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions;

import java.time.OffsetDateTime;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;

import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.TECHNICAL_LOGS;
import static com.powsybl.openrao.searchtreerao.commons.RaoLogger.logCost;
import static com.powsybl.openrao.searchtreerao.commons.RaoUtil.getFlowUnit;
import static com.powsybl.openrao.searchtreerao.marmot.MarmotUtils.*;
import static com.powsybl.openrao.searchtreerao.marmot.MarmotUtils.getPostOptimizationResults;
import static com.powsybl.openrao.searchtreerao.marmot.MarmotUtils.runInitialPrePerimeterSensitivityAnalysisWithoutRangeActions;
import static com.powsybl.openrao.searchtreerao.marmot.MarmotUtils.runSensitivityAnalysisBasedOnInitialResult;

/**
* @author Thomas Bouquet {@literal <thomas.bouquet at rte-france.com>}
Expand All @@ -70,6 +90,8 @@ public class Marmot implements TimeCoupledRaoProvider {

@Override
public CompletableFuture<TimeCoupledRaoResult> run(TimeCoupledRaoInputWithNetworkPaths timeCoupledRaoInputWithNetworkPaths, RaoParameters raoParameters) {
OffsetDateTime computationStart = OffsetDateTime.now();

// 1. Run independent RAOs to compute optimal preventive topological remedial actions
TECHNICAL_LOGS.info("[MARMOT] ----- Topological optimization [start]");
TemporalData<Set<FlowCnec>> consideredCnecs = new TemporalDataImpl<>();
Expand Down Expand Up @@ -116,6 +138,7 @@ public CompletableFuture<TimeCoupledRaoResult> run(TimeCoupledRaoInputWithNetwor
// Get the curative ations applied in the individual results to be able to apply them during sensitivity computations
TemporalData<AppliedRemedialActions> curativeRemedialActions = MarmotUtils.getAppliedRemedialActionsInCurative(timeCoupledRaoInput.getRaoInputs(), topologicalOptimizationResults);

OffsetDateTime globalLinearOptimizationStart = OffsetDateTime.now();
TECHNICAL_LOGS.info("[MARMOT] ----- Global range actions optimization [start]");
// make fast rao result lighter by keeping only initial flow result and filtered rao result for actions
replaceFastRaoResultsWithLightVersions(topologicalOptimizationResults);
Expand Down Expand Up @@ -166,6 +189,9 @@ public CompletableFuture<TimeCoupledRaoResult> run(TimeCoupledRaoInputWithNetwor
logCost("[MARMOT] Before global linear optimization: ", postTopologicalOptimizationResult, raoParameters, 10);
logCost("[MARMOT] After global linear optimization: ", fullResults, raoParameters, 10);

OffsetDateTime computationEnd = OffsetDateTime.now();
addMetadataExtension(timeCoupledRaoResult, computationStart, globalLinearOptimizationStart, computationEnd);

return CompletableFuture.completedFuture(timeCoupledRaoResult);
}

Expand Down Expand Up @@ -539,6 +565,15 @@ private static TemporalData<NetworkActionsResult> getNetworkActionActivationResu
return new TemporalDataImpl<>(networkActionsResults);
}

private static void addMetadataExtension(TimeCoupledRaoResult timeCoupledRaoResult, OffsetDateTime computationStart, OffsetDateTime globalLinearOptimizationStart, OffsetDateTime computationEnd) {
MarmotMetadata metadata = new MarmotMetadata();
metadata.setExecutionDetails(timeCoupledRaoResult.getExecutionDetails());
metadata.setComputationStart(computationStart);
metadata.setComputationEnd(computationEnd);
metadata.setGlobalLinearOptimizationStart(globalLinearOptimizationStart);
timeCoupledRaoResult.addExtension(MarmotMetadata.class, metadata);
}

@Override
public String getName() {
return TIME_COUPLED_RAO;
Expand Down
Loading
Loading