Skip to content

Commit

Permalink
Dynamic simulation results (#916)
Browse files Browse the repository at this point in the history
Signed-off-by: lisrte <[email protected]>
  • Loading branch information
Lisrte authored Dec 18, 2024
1 parent 2a2a49d commit 0d4c02a
Show file tree
Hide file tree
Showing 15 changed files with 191 additions and 50 deletions.
16 changes: 12 additions & 4 deletions cpp/powsybl-cpp/powsybl-cpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1337,8 +1337,8 @@ JavaHandle createEventMapping() {
return PowsyblCaller::get()->callJava<JavaHandle>(::createEventMapping);
}

JavaHandle runDynamicModel(JavaHandle dynamicModelContext, JavaHandle network, JavaHandle dynamicMapping, JavaHandle eventMapping, JavaHandle timeSeriesMapping, int start, int stop, JavaHandle reportNode) {
return PowsyblCaller::get()->callJava<JavaHandle>(::runDynamicModel, dynamicModelContext, network, dynamicMapping, eventMapping, timeSeriesMapping, start, stop, reportNode);
JavaHandle runDynamicModel(JavaHandle dynamicModelContext, JavaHandle network, JavaHandle dynamicMapping, JavaHandle eventMapping, JavaHandle timeSeriesMapping, int start, int stop, JavaHandle *reportNode) {
return PowsyblCaller::get()->callJava<JavaHandle>(::runDynamicModel, dynamicModelContext, network, dynamicMapping, eventMapping, timeSeriesMapping, start, stop, (reportNode == nullptr) ? nullptr : *reportNode);
}

void addDynamicMappings(JavaHandle dynamicMappingHandle, DynamicMappingType mappingType, dataframe_array* dataframes) {
Expand All @@ -1354,8 +1354,12 @@ void addOutputVariables(JavaHandle outputVariablesHandle, std::string dynamicId,
PowsyblCaller::get()->callJava<>(::addOutputVariables, outputVariablesHandle, (char*) dynamicId.c_str(), variablesPtr.get(), variables.size(), isDynamic, variableType);
}

std::string getDynamicSimulationResultsStatus(JavaHandle dynamicSimulationResultsHandle) {
return PowsyblCaller::get()->callJava<std::string>(::getDynamicSimulationResultsStatus, dynamicSimulationResultsHandle);
DynamicSimulationStatus getDynamicSimulationResultsStatus(JavaHandle resultsHandle) {
return PowsyblCaller::get()->callJava<DynamicSimulationStatus>(::getDynamicSimulationResultsStatus, resultsHandle);
}

std::string getDynamicSimulationResultsStatusText(JavaHandle resultsHandle) {
return PowsyblCaller::get()->callJava<std::string>(::getDynamicSimulationResultsStatusText, resultsHandle);
}

SeriesArray* getDynamicCurve(JavaHandle resultHandle, std::string curveName) {
Expand All @@ -1371,6 +1375,10 @@ SeriesArray* getFinalStateValues(JavaHandle resultHandle) {
return new SeriesArray(PowsyblCaller::get()->callJava<array*>(::getFinalStateValues, resultHandle));
}

SeriesArray* getTimeline(JavaHandle resultHandle) {
return new SeriesArray(PowsyblCaller::get()->callJava<array*>(::getTimeline, resultHandle));
}

std::vector<std::string> getSupportedModels(DynamicMappingType mappingType) {
ToStringVector vector(PowsyblCaller::get()->callJava<array*>(::getSupportedModels, mappingType));
return vector.get();
Expand Down
6 changes: 4 additions & 2 deletions cpp/powsybl-cpp/powsybl-cpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ JavaHandle createDynamicModelMapping();
JavaHandle createTimeseriesMapping();
JavaHandle createEventMapping();

JavaHandle runDynamicModel(JavaHandle dynamicModelContext, JavaHandle network, JavaHandle dynamicMapping, JavaHandle eventMapping, JavaHandle timeSeriesMapping, int start, int stop, JavaHandle reportNode);
JavaHandle runDynamicModel(JavaHandle dynamicModelContext, JavaHandle network, JavaHandle dynamicMapping, JavaHandle eventMapping, JavaHandle timeSeriesMapping, int start, int stop, JavaHandle* reportNode);

// timeseries mapping
void addOutputVariables(JavaHandle outputVariablesHandle, std::string dynamicId, std::vector<std::string>& variables, bool isDynamic, OutputVariableType variableType);
Expand All @@ -781,10 +781,12 @@ std::vector<std::vector<SeriesMetadata>> getDynamicMappingsMetaData(DynamicMappi
std::vector<std::string> getSupportedModels(DynamicMappingType mappingType);

// results
std::string getDynamicSimulationResultsStatus(JavaHandle dynamicSimulationResultsHandle);
DynamicSimulationStatus getDynamicSimulationResultsStatus(JavaHandle resultsHandle);
std::string getDynamicSimulationResultsStatusText(JavaHandle resultsHandle);
SeriesArray* getDynamicCurve(JavaHandle resultHandle, std::string curveName);
std::vector<std::string> getAllDynamicCurvesIds(JavaHandle resultHandle);
SeriesArray* getFinalStateValues(JavaHandle resultHandle);
SeriesArray* getTimeline(JavaHandle resultHandle);

//=======END OF dynamic modeling for dynawo package==========

Expand Down
12 changes: 9 additions & 3 deletions cpp/pypowsybl-cpp/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,13 @@ void dynamicSimulationBindings(py::module_& m) {
.value("NODE_FAULT", EventMappingType::NODE_FAULT)
.value("ACTIVE_POWER_VARIATION", EventMappingType::ACTIVE_POWER_VARIATION);

py::enum_<OutputVariableType>(m, "OutputVariableType")
.value("CURVE", OutputVariableType::CURVE)
.value("FINAL_STATE", OutputVariableType::FINAL_STATE);
py::enum_<OutputVariableType>(m, "OutputVariableType")
.value("CURVE", OutputVariableType::CURVE)
.value("FINAL_STATE", OutputVariableType::FINAL_STATE);

py::enum_<DynamicSimulationStatus>(m, "DynamicSimulationStatus")
.value("SUCCESS", DynamicSimulationStatus::DYNAMIC_SIMULATION_SUCCESS)
.value("FAILURE", DynamicSimulationStatus::DYNAMIC_SIMULATION_FAILURE);

//entrypoints for constructors
m.def("create_dynamic_simulation_context", &pypowsybl::createDynamicSimulationContext);
Expand All @@ -216,9 +220,11 @@ void dynamicSimulationBindings(py::module_& m) {

// Simulation results
m.def("get_dynamic_simulation_results_status", &pypowsybl::getDynamicSimulationResultsStatus, py::arg("result_handle"));
m.def("get_dynamic_simulation_results_status_text", &pypowsybl::getDynamicSimulationResultsStatusText, py::arg("result_handle"));
m.def("get_dynamic_curve", &pypowsybl::getDynamicCurve, py::arg("report_handle"), py::arg("curve_name"));
m.def("get_all_dynamic_curves_ids", &pypowsybl::getAllDynamicCurvesIds, py::arg("report_handle"));
m.def("get_final_state_values", &pypowsybl::getFinalStateValues, py::arg("result_handle"));
m.def("get_timeline", &pypowsybl::getTimeline, py::arg("result_handle"));
}

void voltageInitializerBinding(py::module_& m) {
Expand Down
5 changes: 5 additions & 0 deletions cpp/pypowsybl-java/powsybl-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,11 @@ typedef enum {
FINAL_STATE,
} OutputVariableType;

typedef enum {
DYNAMIC_SIMULATION_SUCCESS = 0,
DYNAMIC_SIMULATION_FAILURE,
} DynamicSimulationStatus;

typedef enum {
UNDEFINED = -1,
ONE,
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/dynamic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,7 @@ Results

SimulationResult
SimulationResult.status
SimulationResult.status_text
SimulationResult.curves
SimulationResult.final_state_values
SimulationResult.timeline
4 changes: 3 additions & 1 deletion docs/user_guide/dynamic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,7 @@ To run a Dynawo simulation:
results = sim.run(network, model_mapping, event_mapping, variables_mapping, start_time, end_time)
# getting the results
results.status()
results.status_text() # error description if the simulation fails
results.curves() # dataframe containing the mapped curves
results.final_state_values() # dataframe containing the mapped final state values
results.final_state_values() # dataframe containing the mapped final state values
results.timeline() # dataframe containing the simulation timeline
7 changes: 5 additions & 2 deletions integration_tests/test_dynawo.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import pypowsybl as pp
import pypowsybl.dynamic as dyn
import pypowsybl.report as rp
from pypowsybl._pypowsybl import DynamicSimulationStatus
import pandas as pd

def test_simulation():
Expand Down Expand Up @@ -44,8 +45,10 @@ def test_simulation():
res = sim.run(network, model_mapping, event_mapping, variables_mapping, 0, 100, report_node)

assert report_node
assert 'Ok' == res.status()
assert DynamicSimulationStatus.SUCCESS == res.status()
assert "" == res.status_text()
assert 'BBM_GEN6_generator_PGen' in res.curves()
assert 'BBM_GEN6_generator_QGen' in res.curves()
assert 'BBM_GEN6_generator_UStatorPu' in res.curves()
assert res.final_state_values().loc['NETWORK_B3_Upu_value'].empty == False
assert False == res.final_state_values().loc['NETWORK_B3_Upu_value'].empty
assert False == res.timeline().empty
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2024, RTE (http://www.rte-france.com)
* Copyright (c) 2020-2022, 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/.
Expand All @@ -9,18 +9,22 @@

import com.powsybl.dataframe.DataframeMapper;
import com.powsybl.dataframe.DataframeMapperBuilder;
import com.powsybl.dynamicsimulation.TimelineEvent;
import com.powsybl.timeseries.DoublePoint;
import com.powsybl.timeseries.DoubleTimeSeries;
import com.powsybl.timeseries.TimeSeries;

import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;

/**
* @author Laurent Issertial {@literal <laurent.issertial at rte-france.com>}
* @author Nicolas Pierre {@literal <nicolas.pierre@artelys.com>}
*/
public final class OutputVariablesSeries {
public final class DynamicSimulationDataframeMappersUtils {

private OutputVariablesSeries() {
private DynamicSimulationDataframeMappersUtils() {
}

public static DataframeMapper<DoubleTimeSeries, Void> curvesDataFrameMapper(String colName) {
Expand All @@ -38,4 +42,15 @@ public static DataframeMapper<Map<String, Double>, Void> fsvDataFrameMapper() {
.doubles("values", Map.Entry::getValue)
.build();
}

public static DataframeMapper<List<TimelineEvent>, Void> timelineEventDataFrameMapper() {
AtomicInteger index = new AtomicInteger();
return new DataframeMapperBuilder<List<TimelineEvent>, TimelineEvent, Void>()
.itemsProvider(Function.identity())
.intsIndex("index", e -> index.getAndIncrement())
.doubles("time", TimelineEvent::time)
.strings("model", TimelineEvent::modelName)
.strings("message", TimelineEvent::message)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1245,6 +1245,18 @@ public enum OutputVariableType {
public static native OutputVariableType fromCValue(int value);
}

@CEnum("DynamicSimulationStatus")
public enum DynamicSimulationStatus {
DYNAMIC_SIMULATION_SUCCESS,
DYNAMIC_SIMULATION_FAILURE;

@CEnumValue
public native int getCValue();

@CEnumLookup
public static native DynamicSimulationStatus fromCValue(int value);
}

@CEnum("ThreeSide")
public enum ThreeSideType {
UNDEFINED,
Expand Down
9 changes: 9 additions & 0 deletions java/src/main/java/com/powsybl/python/commons/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.powsybl.dataframe.DataframeElementType;
import com.powsybl.dataframe.SeriesDataType;
import com.powsybl.dataframe.network.modifications.DataframeNetworkModificationType;
import com.powsybl.dynamicsimulation.DynamicSimulationResult;
import com.powsybl.dynamicsimulation.OutputVariable;
import com.powsybl.iidm.network.ThreeSides;
import com.powsybl.iidm.network.ValidationLevel;
Expand All @@ -21,6 +22,7 @@
import com.powsybl.openreac.parameters.input.algo.ReactiveSlackBusesMode;
import com.powsybl.openreac.parameters.output.OpenReacStatus;
import com.powsybl.python.commons.PyPowsyblApiHeader.ArrayPointer;
import com.powsybl.python.commons.PyPowsyblApiHeader.DynamicSimulationStatus;
import com.powsybl.python.commons.PyPowsyblApiHeader.VoltageInitializerObjective;
import com.powsybl.python.commons.PyPowsyblApiHeader.VoltageInitializerStatus;
import com.powsybl.python.commons.PyPowsyblApiHeader.VoltageInitializerLogLevelAmpl;
Expand Down Expand Up @@ -385,6 +387,13 @@ public static ReactiveSlackBusesMode convert(VoltageInitializerReactiveSlackBuse
};
}

public static DynamicSimulationStatus convert(DynamicSimulationResult.Status obj) {
return switch (obj) {
case SUCCESS -> DynamicSimulationStatus.DYNAMIC_SIMULATION_SUCCESS;
case FAILURE -> DynamicSimulationStatus.DYNAMIC_SIMULATION_FAILURE;
};
}

public static byte[] binaryBufferToBytes(ByteBuffer buffer) {
if (buffer.hasArray()) {
return buffer.array();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package com.powsybl.python.dynamic;

import static com.powsybl.python.commons.CTypeUtil.toStringList;
import static com.powsybl.python.commons.Util.convert;
import static com.powsybl.python.commons.Util.doCatch;
import static com.powsybl.python.network.NetworkCFunctions.createDataframe;

Expand All @@ -16,7 +17,7 @@

import com.powsybl.commons.report.ReportNode;
import com.powsybl.dataframe.SeriesMetadata;
import com.powsybl.dataframe.dynamic.OutputVariablesSeries;
import com.powsybl.dataframe.dynamic.DynamicSimulationDataframeMappersUtils;
import com.powsybl.python.network.Dataframes;
import com.powsybl.python.report.ReportCUtils;
import com.powsybl.timeseries.DoubleTimeSeries;
Expand Down Expand Up @@ -107,6 +108,9 @@ public static ObjectHandle runDynamicModel(IsolateThread thread,
EventModelsSupplier eventModelsSupplier = ObjectHandles.getGlobal().get(eventModelsSupplierHandle);
OutputVariablesSupplier outputVariablesSupplier = ObjectHandles.getGlobal().get(outputVariablesSupplierHandle);
ReportNode reportNode = ReportCUtils.getReportNode(reportNodeHandle);
if (reportNode == null) {
reportNode = ReportNode.NO_OP;
}
DynamicSimulationParameters dynamicSimulationParameters = new DynamicSimulationParameters(startTime,
stopTime);
DynamicSimulationResult result = dynamicContext.run(network,
Expand Down Expand Up @@ -193,17 +197,27 @@ public static void addOutputVariables(IsolateThread thread,
String dynamicId = CTypeUtil.toString(dynamicIdPtr);
List<String> variables = toStringList(variablesPtrPtr, variableCount);
PythonOutputVariablesSupplier outputVariablesSupplier = ObjectHandles.getGlobal().get(outputVariablesHandle);
outputVariablesSupplier.addOutputVariables(dynamicId, variables, isDynamic, Util.convert(variableType));
outputVariablesSupplier.addOutputVariables(dynamicId, variables, isDynamic, convert(variableType));
});
}

@CEntryPoint(name = "getDynamicSimulationResultsStatus")
public static CCharPointer getDynamicSimulationResultsStatus(IsolateThread thread,
ObjectHandle dynamicSimulationResultsHandle,
public static DynamicSimulationStatus getDynamicSimulationResultsStatus(IsolateThread thread,
ObjectHandle resultsHandle,
ExceptionHandlerPointer exceptionHandlerPtr) {
return doCatch(exceptionHandlerPtr, () -> {
DynamicSimulationResult simulationResult = ObjectHandles.getGlobal().get(dynamicSimulationResultsHandle);
return CTypeUtil.toCharPtr(simulationResult.isOk() ? "Ok" : "Not OK");
DynamicSimulationResult simulationResult = ObjectHandles.getGlobal().get(resultsHandle);
return convert(simulationResult.getStatus());
});
}

@CEntryPoint(name = "getDynamicSimulationResultsStatusText")
public static CCharPointer getDynamicSimulationResultsStatusText(IsolateThread thread,
ObjectHandle resultsHandle,
ExceptionHandlerPointer exceptionHandlerPtr) {
return doCatch(exceptionHandlerPtr, () -> {
DynamicSimulationResult simulationResult = ObjectHandles.getGlobal().get(resultsHandle);
return CTypeUtil.toCharPtr(simulationResult.getStatusText());
});
}

Expand All @@ -216,7 +230,7 @@ public static ArrayPointer<SeriesPointer> getDynamicCurve(IsolateThread thread,
DynamicSimulationResult result = ObjectHandles.getGlobal().get(resultHandle);
String curveName = CTypeUtil.toString(curveNamePtr);
DoubleTimeSeries curve = result.getCurve(curveName);
return Dataframes.createCDataframe(OutputVariablesSeries.curvesDataFrameMapper(curveName), curve);
return Dataframes.createCDataframe(DynamicSimulationDataframeMappersUtils.curvesDataFrameMapper(curveName), curve);
});
}

Expand All @@ -234,6 +248,16 @@ public static ArrayPointer<CCharPointerPointer> getAllDynamicCurvesIds(IsolateTh
public static ArrayPointer<SeriesPointer> getFinalStateValues(IsolateThread thread, ObjectHandle resultHandle,
ExceptionHandlerPointer exceptionHandlerPtr) {
DynamicSimulationResult result = ObjectHandles.getGlobal().get(resultHandle);
return Dataframes.createCDataframe(OutputVariablesSeries.fsvDataFrameMapper(), result.getFinalStateValues());
return Dataframes.createCDataframe(DynamicSimulationDataframeMappersUtils.fsvDataFrameMapper(), result.getFinalStateValues());
}

@CEntryPoint(name = "getTimeline")
public static ArrayPointer<SeriesPointer> getTimeline(IsolateThread thread,
ObjectHandle resultsHandle,
ExceptionHandlerPointer exceptionHandlerPtr) {
return doCatch(exceptionHandlerPtr, () -> {
DynamicSimulationResult simulationResult = ObjectHandles.getGlobal().get(resultsHandle);
return Dataframes.createCDataframe(DynamicSimulationDataframeMappersUtils.timelineEventDataFrameMapper(), simulationResult.getTimeLine());
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* Copyright (c) 2024, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.dataframe.dynamic;

import com.powsybl.dataframe.impl.Series;
import com.powsybl.dynamicsimulation.TimelineEvent;
import org.junit.jupiter.api.Test;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static com.powsybl.dataframe.dynamic.DynamicSimulationDataframeMappersUtils.fsvDataFrameMapper;
import static com.powsybl.dataframe.dynamic.DynamicSimulationDataframeMappersUtils.timelineEventDataFrameMapper;
import static com.powsybl.python.network.Dataframes.createSeries;
import static org.assertj.core.api.Assertions.assertThat;

/**
* @author Laurent Issertial {@literal <laurent.issertial at rte-france.com>}
*/
class DynamicSimulationDataframeMappersTest {

@Test
void testFsvDataframesMapper() {
Map<String, Double> fsv = new LinkedHashMap<>();
fsv.put("GEN_Upu_value", 45.8);
fsv.put("LOAD_load_PPu", 22.1);
List<Series> series = createSeries(fsvDataFrameMapper(), fsv);
assertThat(series)
.extracting(Series::getName)
.containsExactly("variables", "values");
assertThat(series).satisfiesExactly(
col1 -> assertThat(col1.getStrings()).containsExactly("GEN_Upu_value", "LOAD_load_PPu"),
col2 -> assertThat(col2.getDoubles()).containsExactly(45.8, 22.1));
}

@Test
void testTimelineDataframesMapper() {
List<TimelineEvent> timelineEvents = List.of(
new TimelineEvent(0.0, "BBM_GEN6", "PMIN : activation"),
new TimelineEvent(0.0, "BBM_GEN8", "PMIN : activation"),
new TimelineEvent(2.2, "BBM_GEN6", "PMIN : deactivation"));
List<Series> series = createSeries(timelineEventDataFrameMapper(), timelineEvents);
assertThat(series)
.extracting(Series::getName)
.containsExactly("index", "time", "model", "message");
assertThat(series).satisfiesExactly(
index -> assertThat(index.getInts()).containsExactly(0, 1, 2),
col1 -> assertThat(col1.getDoubles()).containsExactly(0.0, 0.0, 2.2),
col2 -> assertThat(col2.getStrings()).containsExactly("BBM_GEN6", "BBM_GEN8", "BBM_GEN6"),
col3 -> assertThat(col3.getStrings()).containsExactly("PMIN : activation", "PMIN : activation", "PMIN : deactivation"));
}
}
Loading

0 comments on commit 0d4c02a

Please sign in to comment.