diff --git a/distribution/pom.xml b/distribution/pom.xml
index e15e978e2f..9738559d3a 100755
--- a/distribution/pom.xml
+++ b/distribution/pom.xml
@@ -112,6 +112,11 @@
open-rao-search-tree-rao
${project.version}
+
+ ${project.groupId}
+ open-rao-roda
+ ${project.version}
+
${project.groupId}
open-rao-sensitivity-analysis
diff --git a/docs/parameters/implementation-specific-parameters.md b/docs/parameters/implementation-specific-parameters.md
index c3875f8110..41135b602c 100644
--- a/docs/parameters/implementation-specific-parameters.md
+++ b/docs/parameters/implementation-specific-parameters.md
@@ -580,3 +580,51 @@ fast-rao-parameters:
~~~
:::
::::
+
+### RODA parameters
+
+RODA implementation specific parameters ("roda-parameters"). Optional.
+
+#### forced-preventive-actions-list
+
+You can create an optional forced-preventive-actions-list to force some preventive actions before running the RAO.
+While this is equivalent to pre-processing the network file before running the RAO, it can be useful if
+you want to test different preventive actions in an outside loop, without having to pre-process (and
+eventually serialize) the network.
+Note that this is not currently supported in the yaml format.
+Also note that when using lazy networks, this will make all the networks load at the beginning of the RAO. So you may encounter memory issues.
+
+- **Expected value**: a list of PowSyBl Actions. In JSON, this should be represented by a serialized ActionList.
+- **Default value**: empty array
+- **Usage**: these actions will be applied on the network before running the RAO. In the case of time-coupled RAO,
+ the actions will be applied for all timestamps.
+ Actions that cannot be applied (for example if the ID of the element is wrong) will be ignored (the issue will be logged in a warning).
+
+#### Example
+::::{tabs}
+:::{group-tab} JSON
+~~~json
+"roda-parameters": {
+ "forced-preventive-actions-list": {
+ "version": "1.3",
+ "actions": [
+ {
+ "type": "PHASE_TAP_CHANGER_TAP_POSITION",
+ "id": "PRA_PST_BE",
+ "transformerId": "BBE2AA1 BBE3AA1 1",
+ "tapPosition": -16,
+ "relativeValue": false,
+ "side": "TWO"
+ },
+ {
+ "type": "TERMINALS_CONNECTION",
+ "id": "Open FR1 FR2",
+ "elementId": "FFR1AA1 FFR2AA1 1",
+ "open": true
+ }
+ ]
+ }
+}
+~~~
+:::
+::::
\ No newline at end of file
diff --git a/ra-optimisation/roda/pom.xml b/ra-optimisation/roda/pom.xml
index ec520aaeaa..65eff22c81 100644
--- a/ra-optimisation/roda/pom.xml
+++ b/ra-optimisation/roda/pom.xml
@@ -21,6 +21,7 @@
+
${project.groupId}
open-rao-rao-api
@@ -29,6 +30,66 @@
${project.groupId}
open-rao-search-tree-rao
+
+ com.powsybl
+ powsybl-action-api
+
+
+
+
+ ch.qos.logback
+ logback-classic
+ test
+
+
+ ${project.groupId}
+ open-rao-commons
+ ${project.version}
+ test
+ test-jar
+
+
+ ${project.groupId}
+ open-rao-crac-impl
+ ${project.version}
+ test-jar
+ test
+
+
+ ${project.groupId}
+ open-rao-rao-result-impl
+ ${project.version}
+
+
+ ch.qos.logback
+ logback-classic
+ test
+
+
+ com.google.jimfs
+ jimfs
+ test
+
+
+ com.powsybl
+ powsybl-commons-test
+ test
+
+
+ com.powsybl
+ powsybl-config-test
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
\ No newline at end of file
diff --git a/ra-optimisation/roda/src/main/java/com/powsybl/openrao/roda/Roda.java b/ra-optimisation/roda/src/main/java/com/powsybl/openrao/roda/Roda.java
index 521a992da6..ee17bfdf6b 100644
--- a/ra-optimisation/roda/src/main/java/com/powsybl/openrao/roda/Roda.java
+++ b/ra-optimisation/roda/src/main/java/com/powsybl/openrao/roda/Roda.java
@@ -11,6 +11,7 @@
import com.powsybl.openrao.commons.TemporalData;
import com.powsybl.openrao.commons.TemporalDataImpl;
import com.powsybl.openrao.commons.Unit;
+import com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider;
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;
@@ -23,6 +24,7 @@
import com.powsybl.openrao.raoapi.parameters.extensions.OpenRaoSearchTreeParameters;
import com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoCostlyMinMarginParameters;
import com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoRelativeMarginsParameters;
+import com.powsybl.openrao.roda.parameters.RodaParameters;
import com.powsybl.openrao.searchtreerao.commons.ToolProvider;
import com.powsybl.openrao.searchtreerao.commons.objectivefunction.ObjectiveFunction;
import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.OptimizationPerimeter;
@@ -71,6 +73,8 @@ public class Roda implements TimeCoupledRaoProvider {
@Override
public CompletableFuture run(TimeCoupledRaoInput timeCoupledRaoInput, RaoParameters raoParameters) {
+ applyForcedActions(timeCoupledRaoInput.getRaoInputs(), raoParameters.getExtension(RodaParameters.class));
+
if (timeCoupledRaoInput.getRaoInputs().getTimestamps().size() == 1) {
TECHNICAL_LOGS.info("[RODA] Only one time-step in inputs. Calling single time-step RAO directly: {}", DEFAULT_SINGLE_TS_RAO);
return runSingleTsRao(timeCoupledRaoInput, raoParameters);
@@ -212,6 +216,18 @@ public CompletableFuture run(TimeCoupledRaoInput timeCoupl
return CompletableFuture.completedFuture(timeCoupledRaoResult);
}
+ static void applyForcedActions(TemporalData raoInputs, RodaParameters rodaParameters) {
+ if (rodaParameters == null || rodaParameters.getForcedPreventiveActions().isEmpty()) {
+ return;
+ }
+ OpenRaoLoggerProvider.BUSINESS_LOGS.info(String.format("Applying %d forced preventive actions before running RAO.", rodaParameters.getForcedPreventiveActions().size()));
+ raoInputs.getDataPerTimestamp().values().stream().map(RaoInput::getNetwork).forEach(network -> {
+ rodaParameters.getForcedPreventiveActions().stream().filter(action -> !action.toModification().apply(network, true))
+ .forEach(action -> OpenRaoLoggerProvider.BUSINESS_WARNS.warn(String.format("Action '%s' could not be applied.", action.getId())));
+ rodaParameters.getForcedPreventiveActions().forEach(action -> action.toModification().apply(network, false));
+ });
+ }
+
private CompletableFuture runSingleTsRao(TimeCoupledRaoInput raoInputs, RaoParameters raoParameters) {
OffsetDateTime ts = raoInputs.getRaoInputs().getTimestamps().getFirst();
RaoInput raoInput = raoInputs.getRaoInputs().getData(ts).orElseThrow();
diff --git a/ra-optimisation/roda/src/main/java/com/powsybl/openrao/roda/parameters/JsonRodaParameters.java b/ra-optimisation/roda/src/main/java/com/powsybl/openrao/roda/parameters/JsonRodaParameters.java
new file mode 100644
index 0000000000..e44a3c7f76
--- /dev/null
+++ b/ra-optimisation/roda/src/main/java/com/powsybl/openrao/roda/parameters/JsonRodaParameters.java
@@ -0,0 +1,80 @@
+/*
+ * 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.roda.parameters;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.google.auto.service.AutoService;
+import com.powsybl.action.ActionList;
+import com.powsybl.action.json.ActionJsonModule;
+import com.powsybl.commons.json.JsonUtil;
+import com.powsybl.openrao.commons.OpenRaoException;
+import com.powsybl.openrao.raoapi.json.JsonRaoParameters;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * RODA parameters extension json serializer & deserializer.
+ * Depends on PowSyBl's ActionList serializer & deserializer.
+ *
+ * @author Peter Mitri {@literal }
+ */
+@AutoService(JsonRaoParameters.ExtensionSerializer.class)
+public class JsonRodaParameters implements JsonRaoParameters.ExtensionSerializer {
+
+ private static final String PREVENTIVE_ACTION_LIST = "forced-preventive-actions-list";
+
+ @Override
+ public void serialize(RodaParameters rodaParameters, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
+ jsonGenerator.writeStartObject();
+ jsonGenerator.writeFieldName(PREVENTIVE_ACTION_LIST);
+ createObjectMapper().writeValue(jsonGenerator, new ActionList(rodaParameters.getForcedPreventiveActions()));
+ jsonGenerator.writeEndObject();
+ }
+
+ private static ObjectMapper createObjectMapper() {
+ return JsonUtil.createObjectMapper()
+ .registerModule(new ActionJsonModule());
+ }
+
+ @Override
+ public RodaParameters deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
+ ActionList actionList = null;
+ while (!jsonParser.nextToken().isStructEnd()) {
+ if (jsonParser.currentName().equals(PREVENTIVE_ACTION_LIST)) {
+ jsonParser.nextToken();
+ actionList = createObjectMapper().readValue(jsonParser, ActionList.class);
+ } else {
+ throw new OpenRaoException("Unexpected token: " + jsonParser.currentName());
+ }
+ }
+ if (actionList == null) {
+ return new RodaParameters(List.of());
+ }
+ return new RodaParameters(actionList.getActions());
+ }
+
+ @Override
+ public String getExtensionName() {
+ return RodaParameters.EXTENSION_NAME;
+ }
+
+ @Override
+ public String getCategoryName() {
+ return "rao-parameters";
+ }
+
+ @Override
+ public Class super RodaParameters> getExtensionClass() {
+ return RodaParameters.class;
+ }
+}
diff --git a/ra-optimisation/roda/src/main/java/com/powsybl/openrao/roda/parameters/RodaParameters.java b/ra-optimisation/roda/src/main/java/com/powsybl/openrao/roda/parameters/RodaParameters.java
new file mode 100644
index 0000000000..716b5b5fb3
--- /dev/null
+++ b/ra-optimisation/roda/src/main/java/com/powsybl/openrao/roda/parameters/RodaParameters.java
@@ -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.roda.parameters;
+
+import com.powsybl.action.Action;
+import com.powsybl.commons.extensions.AbstractExtension;
+import com.powsybl.openrao.raoapi.parameters.RaoParameters;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * RODA specific RAO parameters.
+ * For now, only allows forcing actions on the network before running RAO.
+ * Could be useful to avoid pre-processing network multiple times (for example when testing topological changes
+ * in an outside loop).
+ *
+ * @author Peter Mitri {@literal }
+ */
+public class RodaParameters extends AbstractExtension {
+ public static final String EXTENSION_NAME = "roda-parameters";
+ private final List forcedPreventiveActions;
+
+ public RodaParameters(List forcedPreventiveActions) {
+ this.forcedPreventiveActions = Collections.unmodifiableList(forcedPreventiveActions);
+ }
+
+ @Override
+ public String getName() {
+ return EXTENSION_NAME;
+ }
+
+ public List getForcedPreventiveActions() {
+ return forcedPreventiveActions;
+ }
+}
diff --git a/ra-optimisation/roda/src/test/java/com/powsybl/openrao/roda/RodaTest.java b/ra-optimisation/roda/src/test/java/com/powsybl/openrao/roda/RodaTest.java
new file mode 100644
index 0000000000..26cbebad31
--- /dev/null
+++ b/ra-optimisation/roda/src/test/java/com/powsybl/openrao/roda/RodaTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.roda;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+import com.powsybl.action.Action;
+import com.powsybl.action.PhaseTapChangerTapPositionAction;
+import com.powsybl.action.TerminalsConnectionAction;
+import com.powsybl.iidm.network.Network;
+import com.powsybl.openrao.commons.TemporalData;
+import com.powsybl.openrao.commons.TemporalDataImpl;
+import com.powsybl.openrao.commons.logs.RaoBusinessWarns;
+import com.powsybl.openrao.data.crac.api.Crac;
+import com.powsybl.openrao.data.crac.impl.utils.CommonCracCreation;
+import com.powsybl.openrao.data.crac.impl.utils.NetworkImportsUtil;
+import com.powsybl.openrao.raoapi.RaoInput;
+import com.powsybl.openrao.roda.parameters.RodaParameters;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.slf4j.LoggerFactory;
+
+import java.time.OffsetDateTime;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * @author Peter Mitri {@literal }
+ */
+class RodaTest {
+ Network network;
+ TemporalData raoInput;
+
+ @BeforeEach
+ void setUp() {
+ network = NetworkImportsUtil.import12NodesNetwork();
+ Crac crac = CommonCracCreation.createWithPreventivePstRange();
+ String variantId = network.getVariantManager().getWorkingVariantId();
+ raoInput = new TemporalDataImpl<>(
+ Map.of(OffsetDateTime.now(), RaoInput.buildWithPreventiveState(network, crac)
+ .withNetworkVariantId(variantId)
+ .build()));
+ }
+
+ @Test
+ void testApplyForcedActions() {
+ ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(RaoBusinessWarns.class);
+ ListAppender listAppender = new ListAppender<>();
+ listAppender.start();
+ logger.addAppender(listAppender);
+ List logsList = listAppender.list;
+
+ Action action1 = new PhaseTapChangerTapPositionAction("action1", "BBE2AA1 BBE3AA1 1", false, -8);
+ Action action2 = new TerminalsConnectionAction("action2", "FFR1AA1 FFR2AA1 1", true);
+ Action action3 = new TerminalsConnectionAction("wrong_action", "wrong_id", true);
+ RodaParameters rodaParameters = new RodaParameters(List.of(action1, action2, action3));
+ Roda.applyForcedActions(raoInput, rodaParameters);
+ assertEquals(-8, network.getTwoWindingsTransformer("BBE2AA1 BBE3AA1 1").getPhaseTapChanger().getTapPosition());
+ assertFalse(network.getLine("FFR1AA1 FFR2AA1 1").getTerminal1().isConnected());
+ assertFalse(network.getLine("FFR1AA1 FFR2AA1 1").getTerminal2().isConnected());
+ assertTrue(logsList.stream().anyMatch(e -> e.getMessage().contains("Action 'wrong_action' could not be applied.")));
+ }
+
+ @Test
+ void testApplyForcedActionsNullOrEmpty() {
+ assertDoesNotThrow(() -> Roda.applyForcedActions(raoInput, null));
+ assertDoesNotThrow(() -> Roda.applyForcedActions(raoInput, new RodaParameters(List.of())));
+ }
+}
diff --git a/ra-optimisation/roda/src/test/java/com/powsybl/openrao/roda/parameters/JsonRodaParametersTest.java b/ra-optimisation/roda/src/test/java/com/powsybl/openrao/roda/parameters/JsonRodaParametersTest.java
new file mode 100644
index 0000000000..bc8b856c68
--- /dev/null
+++ b/ra-optimisation/roda/src/test/java/com/powsybl/openrao/roda/parameters/JsonRodaParametersTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.roda.parameters;
+
+import com.powsybl.action.*;
+import com.powsybl.commons.test.AbstractSerDeTest;
+import com.powsybl.iidm.network.PhaseTapChanger;
+import com.powsybl.iidm.network.StaticVarCompensator;
+import com.powsybl.iidm.network.ThreeSides;
+import com.powsybl.openrao.commons.OpenRaoException;
+import com.powsybl.openrao.raoapi.json.JsonRaoParameters;
+import com.powsybl.openrao.raoapi.parameters.RaoParameters;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.util.*;
+
+import static com.powsybl.action.PercentChangeLoadAction.QModificationStrategy.CONSTANT_Q;
+import static com.powsybl.iidm.network.HvdcLine.ConvertersMode.SIDE_1_RECTIFIER_SIDE_2_INVERTER;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * @author Peter Mitri {@literal }
+ */
+class JsonRodaParametersTest extends AbstractSerDeTest {
+ @Test
+ void testForcedActionsRoundTrip() throws IOException {
+ List actions = new ArrayList<>();
+ actions.add(new SwitchAction("id1", "switchId1", true));
+ actions.add(new MultipleActionsAction("id2", Collections.singletonList(new SwitchAction("id3", "switchId2", true))));
+ actions.add(new TerminalsConnectionAction("id3", "lineId3", true)); // both sides.
+ actions.add(new TerminalsConnectionAction("id4", "lineId4", false)); // both sides.
+ actions.add(new PhaseTapChangerTapPositionAction("id5", "transformerId1", true, 5, ThreeSides.TWO));
+ actions.add(new PhaseTapChangerTapPositionAction("id6", "transformerId2", false, 12));
+ actions.add(new PhaseTapChangerTapPositionAction("id7", "transformerId3", true, -5, ThreeSides.ONE));
+ actions.add(new PhaseTapChangerTapPositionAction("id8", "transformerId3", false, 2, ThreeSides.THREE));
+ actions.add(new GeneratorActionBuilder().withId("id9").withGeneratorId("generatorId1").withActivePowerRelativeValue(true).withActivePowerValue(100.0).build());
+ actions.add(new GeneratorActionBuilder().withId("id10").withGeneratorId("generatorId2").withVoltageRegulatorOn(true).withTargetV(225.0).build());
+ actions.add(new GeneratorActionBuilder().withId("id11").withGeneratorId("generatorId2").withVoltageRegulatorOn(false).withTargetQ(400.0).build());
+ actions.add(new LoadActionBuilder().withId("id12").withLoadId("loadId1").withRelativeValue(false).withActivePowerValue(50.0).build());
+ actions.add(new LoadActionBuilder().withId("id13").withLoadId("loadId1").withRelativeValue(true).withReactivePowerValue(5.0).build());
+ actions.add(new PercentChangeLoadActionBuilder().withId("id26").withLoadId("loadId1").withP0PercentChange(5.0).withQModificationStrategy(CONSTANT_Q).build());
+ actions.add(new BoundaryLineActionBuilder().withId("id17").withBoundaryLineId("dlId1").withRelativeValue(true).withReactivePowerValue(5.0).build());
+ actions.add(new RatioTapChangerTapPositionAction("id14", "transformerId4", false, 2, ThreeSides.THREE));
+ actions.add(new RatioTapChangerTapPositionAction("id15", "transformerId5", true, 1));
+ actions.add(RatioTapChangerRegulationAction.activateRegulation("id16", "transformerId5", ThreeSides.THREE));
+ actions.add(PhaseTapChangerRegulationAction.activateAndChangeRegulationMode("id17", "transformerId5", ThreeSides.ONE,
+ PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL, 10.0));
+ actions.add(PhaseTapChangerRegulationAction.deactivateRegulation("id18",
+ "transformerId6", ThreeSides.ONE));
+ actions.add(PhaseTapChangerRegulationAction.activateAndChangeRegulationMode("id19",
+ "transformerId6", ThreeSides.ONE,
+ PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL, 15.0));
+ actions.add(RatioTapChangerRegulationAction.activateRegulationAndChangeTargetV("id20", "transformerId5", 90.0));
+ actions.add(RatioTapChangerRegulationAction.deactivateRegulation("id21", "transformerId5", ThreeSides.THREE));
+ actions.add(new HvdcActionBuilder()
+ .withId("id22")
+ .withHvdcId("hvdc1")
+ .withAcEmulationEnabled(false)
+ .build());
+ actions.add(new HvdcActionBuilder()
+ .withId("id23")
+ .withHvdcId("hvdc2")
+ .withAcEmulationEnabled(true)
+ .build());
+ actions.add(new HvdcActionBuilder()
+ .withId("id24")
+ .withHvdcId("hvdc2")
+ .withAcEmulationEnabled(true)
+ .withDroop(121.0)
+ .withP0(42.0)
+ .withConverterMode(SIDE_1_RECTIFIER_SIDE_2_INVERTER)
+ .withRelativeValue(false)
+ .build());
+ actions.add(new HvdcActionBuilder()
+ .withId("id25")
+ .withHvdcId("hvdc1")
+ .withAcEmulationEnabled(false)
+ .withActivePowerSetpoint(12.0)
+ .withRelativeValue(true)
+ .build());
+ actions.add(new ShuntCompensatorPositionActionBuilder().withId("id22").withShuntCompensatorId("shuntId1").withSectionCount(5).build());
+ actions.add(new StaticVarCompensatorActionBuilder().withId("id23")
+ .withStaticVarCompensatorId("svc").withRegulationMode(StaticVarCompensator.RegulationMode.VOLTAGE)
+ .withVoltageSetpoint(56.0).build());
+ actions.add(new StaticVarCompensatorActionBuilder().withId("id24")
+ .withStaticVarCompensatorId("svc").withRegulationMode(StaticVarCompensator.RegulationMode.REACTIVE_POWER)
+ .withReactivePowerSetpoint(120.0).build());
+ actions.add(new TerminalsConnectionAction("id4", "transformerId25", ThreeSides.THREE, true)); // only one side.
+ actions.add(new AreaInterchangeTargetAction("id99", "AreaA", 101.0));
+ actions.add(new AreaInterchangeTargetAction("idDisabledTarget", "AreaA", Double.NaN));
+
+ RaoParameters raoParameters = new RaoParameters();
+ RodaParameters forcedActions = new RodaParameters(actions);
+ raoParameters.addExtension(RodaParameters.class, forcedActions);
+
+ roundTripTest(raoParameters, JsonRaoParameters::write, JsonRaoParameters::read, "/RaoParameters_with_ForcedActions.json");
+ }
+
+ @Test
+ void testWrongForcedActions() {
+ try (var stream = getClass().getResourceAsStream("/RaoParameters_with_wrong_ForcedActions.json")) {
+ OpenRaoException exception = assertThrows(OpenRaoException.class, () -> JsonRaoParameters.read(stream));
+ assertEquals("Unexpected token: wrong-key", exception.getMessage());
+ } catch (IOException e) {
+ fail(e);
+ }
+ }
+
+ @Test
+ void testEmptyForcedActions() {
+ RaoParameters raoParameters = JsonRaoParameters.read(getClass().getResourceAsStream("/RaoParameters_with_empty_ForcedActions.json"));
+ RodaParameters forcedActions = raoParameters.getExtension(RodaParameters.class);
+ assertNotNull(forcedActions);
+ assertTrue(forcedActions.getForcedPreventiveActions().isEmpty());
+ }
+}
diff --git a/ra-optimisation/roda/src/test/resources/RaoParameters_with_ForcedActions.json b/ra-optimisation/roda/src/test/resources/RaoParameters_with_ForcedActions.json
new file mode 100644
index 0000000000..66e945deac
--- /dev/null
+++ b/ra-optimisation/roda/src/test/resources/RaoParameters_with_ForcedActions.json
@@ -0,0 +1,231 @@
+{
+ "version" : "3.3",
+ "objective-function" : {
+ "type" : "SECURE_FLOW",
+ "enforce-curative-security" : false
+ },
+ "range-actions-optimization" : {
+ "pst-ra-min-impact-threshold" : 0.01,
+ "hvdc-ra-min-impact-threshold" : 0.001,
+ "injection-ra-min-impact-threshold" : 0.001
+ },
+ "topological-actions-optimization" : {
+ "relative-minimum-impact-threshold" : 0.0,
+ "absolute-minimum-impact-threshold" : 0.0
+ },
+ "not-optimized-cnecs" : {
+ "do-not-optimize-curative-cnecs-for-tsos-without-cras" : false
+ },
+ "extensions" : {
+ "roda-parameters" : {
+ "forced-preventive-actions-list" : {
+ "version" : "1.3",
+ "actions" : [ {
+ "type" : "SWITCH",
+ "id" : "id1",
+ "switchId" : "switchId1",
+ "open" : true
+ }, {
+ "type" : "MULTIPLE_ACTIONS",
+ "id" : "id2",
+ "actions" : [ {
+ "type" : "SWITCH",
+ "id" : "id3",
+ "switchId" : "switchId2",
+ "open" : true
+ } ]
+ }, {
+ "type" : "TERMINALS_CONNECTION",
+ "id" : "id3",
+ "elementId" : "lineId3",
+ "open" : true
+ }, {
+ "type" : "TERMINALS_CONNECTION",
+ "id" : "id4",
+ "elementId" : "lineId4",
+ "open" : false
+ }, {
+ "type" : "PHASE_TAP_CHANGER_TAP_POSITION",
+ "id" : "id5",
+ "transformerId" : "transformerId1",
+ "tapPosition" : 5,
+ "relativeValue" : true,
+ "side" : "TWO"
+ }, {
+ "type" : "PHASE_TAP_CHANGER_TAP_POSITION",
+ "id" : "id6",
+ "transformerId" : "transformerId2",
+ "tapPosition" : 12,
+ "relativeValue" : false
+ }, {
+ "type" : "PHASE_TAP_CHANGER_TAP_POSITION",
+ "id" : "id7",
+ "transformerId" : "transformerId3",
+ "tapPosition" : -5,
+ "relativeValue" : true,
+ "side" : "ONE"
+ }, {
+ "type" : "PHASE_TAP_CHANGER_TAP_POSITION",
+ "id" : "id8",
+ "transformerId" : "transformerId3",
+ "tapPosition" : 2,
+ "relativeValue" : false,
+ "side" : "THREE"
+ }, {
+ "type" : "GENERATOR",
+ "id" : "id9",
+ "generatorId" : "generatorId1",
+ "activePowerRelativeValue" : true,
+ "activePowerValue" : 100.0
+ }, {
+ "type" : "GENERATOR",
+ "id" : "id10",
+ "generatorId" : "generatorId2",
+ "voltageRegulatorOn" : true,
+ "targetV" : 225.0
+ }, {
+ "type" : "GENERATOR",
+ "id" : "id11",
+ "generatorId" : "generatorId2",
+ "voltageRegulatorOn" : false,
+ "targetQ" : 400.0
+ }, {
+ "type" : "LOAD",
+ "id" : "id12",
+ "loadId" : "loadId1",
+ "relativeValue" : false,
+ "activePowerValue" : 50.0
+ }, {
+ "type" : "LOAD",
+ "id" : "id13",
+ "loadId" : "loadId1",
+ "relativeValue" : true,
+ "reactivePowerValue" : 5.0
+ }, {
+ "type" : "PCT_LOAD_CHANGE",
+ "id" : "id26",
+ "loadId" : "loadId1",
+ "p0PercentChange" : 5.0,
+ "qModificationStrategy" : "CONSTANT_Q"
+ }, {
+ "type" : "BOUNDARY_LINE",
+ "id" : "id17",
+ "boundaryLineId" : "dlId1",
+ "relativeValue" : true,
+ "reactivePowerValue" : 5.0
+ }, {
+ "type" : "RATIO_TAP_CHANGER_TAP_POSITION",
+ "id" : "id14",
+ "transformerId" : "transformerId4",
+ "tapPosition" : 2,
+ "relativeValue" : false,
+ "side" : "THREE"
+ }, {
+ "type" : "RATIO_TAP_CHANGER_TAP_POSITION",
+ "id" : "id15",
+ "transformerId" : "transformerId5",
+ "tapPosition" : 1,
+ "relativeValue" : true
+ }, {
+ "type" : "RATIO_TAP_CHANGER_REGULATION",
+ "id" : "id16",
+ "transformerId" : "transformerId5",
+ "regulating" : true,
+ "side" : "THREE"
+ }, {
+ "type" : "PHASE_TAP_CHANGER_REGULATION",
+ "id" : "id17",
+ "transformerId" : "transformerId5",
+ "regulating" : true,
+ "side" : "ONE",
+ "regulationMode" : "ACTIVE_POWER_CONTROL",
+ "regulationValue" : 10.0
+ }, {
+ "type" : "PHASE_TAP_CHANGER_REGULATION",
+ "id" : "id18",
+ "transformerId" : "transformerId6",
+ "regulating" : false,
+ "side" : "ONE"
+ }, {
+ "type" : "PHASE_TAP_CHANGER_REGULATION",
+ "id" : "id19",
+ "transformerId" : "transformerId6",
+ "regulating" : true,
+ "side" : "ONE",
+ "regulationMode" : "ACTIVE_POWER_CONTROL",
+ "regulationValue" : 15.0
+ }, {
+ "type" : "RATIO_TAP_CHANGER_REGULATION",
+ "id" : "id20",
+ "transformerId" : "transformerId5",
+ "regulating" : true,
+ "targetV" : 90.0
+ }, {
+ "type" : "RATIO_TAP_CHANGER_REGULATION",
+ "id" : "id21",
+ "transformerId" : "transformerId5",
+ "regulating" : false,
+ "side" : "THREE"
+ }, {
+ "type" : "HVDC",
+ "id" : "id22",
+ "hvdcId" : "hvdc1",
+ "acEmulationEnabled" : false
+ }, {
+ "type" : "HVDC",
+ "id" : "id23",
+ "hvdcId" : "hvdc2",
+ "acEmulationEnabled" : true
+ }, {
+ "type" : "HVDC",
+ "id" : "id24",
+ "hvdcId" : "hvdc2",
+ "acEmulationEnabled" : true,
+ "converterMode" : "SIDE_1_RECTIFIER_SIDE_2_INVERTER",
+ "droop" : 121.0,
+ "p0" : 42.0,
+ "relativeValue" : false
+ }, {
+ "type" : "HVDC",
+ "id" : "id25",
+ "hvdcId" : "hvdc1",
+ "acEmulationEnabled" : false,
+ "activePowerSetpoint" : 12.0,
+ "relativeValue" : true
+ }, {
+ "type" : "SHUNT_COMPENSATOR_POSITION",
+ "id" : "id22",
+ "shuntCompensatorId" : "shuntId1",
+ "sectionCount" : 5
+ }, {
+ "type" : "STATIC_VAR_COMPENSATOR",
+ "id" : "id23",
+ "staticVarCompensatorId" : "svc",
+ "regulationMode" : "VOLTAGE",
+ "voltageSetpoint" : 56.0
+ }, {
+ "type" : "STATIC_VAR_COMPENSATOR",
+ "id" : "id24",
+ "staticVarCompensatorId" : "svc",
+ "regulationMode" : "REACTIVE_POWER",
+ "reactivePowerSetpoint" : 120.0
+ }, {
+ "type" : "TERMINALS_CONNECTION",
+ "id" : "id4",
+ "elementId" : "transformerId25",
+ "side" : "THREE",
+ "open" : true
+ }, {
+ "type" : "AREA_INTERCHANGE_TARGET_ACTION",
+ "id" : "id99",
+ "areaId" : "AreaA",
+ "interchangeTarget" : 101.0
+ }, {
+ "type" : "AREA_INTERCHANGE_TARGET_ACTION",
+ "id" : "idDisabledTarget",
+ "areaId" : "AreaA"
+ } ]
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ra-optimisation/roda/src/test/resources/RaoParameters_with_empty_ForcedActions.json b/ra-optimisation/roda/src/test/resources/RaoParameters_with_empty_ForcedActions.json
new file mode 100644
index 0000000000..57d1807b1c
--- /dev/null
+++ b/ra-optimisation/roda/src/test/resources/RaoParameters_with_empty_ForcedActions.json
@@ -0,0 +1,23 @@
+{
+ "version" : "3.3",
+ "objective-function" : {
+ "type" : "SECURE_FLOW",
+ "enforce-curative-security" : false
+ },
+ "range-actions-optimization" : {
+ "pst-ra-min-impact-threshold" : 0.01,
+ "hvdc-ra-min-impact-threshold" : 0.001,
+ "injection-ra-min-impact-threshold" : 0.001
+ },
+ "topological-actions-optimization" : {
+ "relative-minimum-impact-threshold" : 0.0,
+ "absolute-minimum-impact-threshold" : 0.0
+ },
+ "not-optimized-cnecs" : {
+ "do-not-optimize-curative-cnecs-for-tsos-without-cras" : false
+ },
+ "extensions" : {
+ "roda-parameters" : {
+ }
+ }
+}
\ No newline at end of file
diff --git a/ra-optimisation/roda/src/test/resources/RaoParameters_with_wrong_ForcedActions.json b/ra-optimisation/roda/src/test/resources/RaoParameters_with_wrong_ForcedActions.json
new file mode 100644
index 0000000000..ad481a2228
--- /dev/null
+++ b/ra-optimisation/roda/src/test/resources/RaoParameters_with_wrong_ForcedActions.json
@@ -0,0 +1,24 @@
+{
+ "version" : "3.3",
+ "objective-function" : {
+ "type" : "SECURE_FLOW",
+ "enforce-curative-security" : false
+ },
+ "range-actions-optimization" : {
+ "pst-ra-min-impact-threshold" : 0.01,
+ "hvdc-ra-min-impact-threshold" : 0.001,
+ "injection-ra-min-impact-threshold" : 0.001
+ },
+ "topological-actions-optimization" : {
+ "relative-minimum-impact-threshold" : 0.0,
+ "absolute-minimum-impact-threshold" : 0.0
+ },
+ "not-optimized-cnecs" : {
+ "do-not-optimize-curative-cnecs-for-tsos-without-cras" : false
+ },
+ "extensions" : {
+ "roda-parameters" : {
+ "wrong-key" : "something"
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/pom.xml b/tests/pom.xml
index a3946eb8bb..12323c4f25 100644
--- a/tests/pom.xml
+++ b/tests/pom.xml
@@ -209,6 +209,12 @@
${project.version}
test
+
+ ${project.groupId}
+ open-rao-roda
+ ${project.version}
+ test
+
${project.groupId}
open-rao-swe-cne-exporter
diff --git a/tests/src/test/java/com/powsybl/openrao/tests/steps/TimeCoupledRaoSteps.java b/tests/src/test/java/com/powsybl/openrao/tests/steps/TimeCoupledRaoSteps.java
index 635954d176..61bc9faa34 100644
--- a/tests/src/test/java/com/powsybl/openrao/tests/steps/TimeCoupledRaoSteps.java
+++ b/tests/src/test/java/com/powsybl/openrao/tests/steps/TimeCoupledRaoSteps.java
@@ -35,10 +35,7 @@
import com.powsybl.openrao.data.refprog.refprogxmlimporter.TimeCoupledRefProg;
import com.powsybl.openrao.data.timecoupledconstraints.TimeCoupledConstraints;
import com.powsybl.openrao.data.timecoupledconstraints.io.JsonTimeCoupledConstraints;
-import com.powsybl.openrao.raoapi.LazyNetwork;
-import com.powsybl.openrao.raoapi.RaoInput;
-import com.powsybl.openrao.raoapi.TimeCoupledRao;
-import com.powsybl.openrao.raoapi.TimeCoupledRaoInput;
+import com.powsybl.openrao.raoapi.*;
import com.powsybl.openrao.tests.utils.CoreCcPreprocessor;
import io.cucumber.datatable.DataTable;
import io.cucumber.java.After;
@@ -270,7 +267,12 @@ public static void loadDataForCoreTimeCoupledRao(DataTable arg1) throws IOExcept
@When("I launch marmot")
public static void iLaunchMarmot() {
- timeCoupledRaoResult = TimeCoupledRao.run(timeCoupledRaoInput, getRaoParameters());
+ timeCoupledRaoResult = TimeCoupledRao.find("TimeCoupledRao").run(timeCoupledRaoInput, getRaoParameters());
+ }
+
+ @When("I launch roda")
+ public static void iLaunchRoda() {
+ timeCoupledRaoResult = TimeCoupledRao.find("Roda").run(timeCoupledRaoInput, getRaoParameters());
}
@When("I export marmot results to {string}")
@@ -526,13 +528,22 @@ private static void applyRedispatchingAction(InjectionRangeAction injectionRange
}
}
+ @Then("the initial margin on {string} for timestamp {string} is {double} MW")
+ public static void theInitialMarginOnCnecForTimestampIsMW(String cnecId, String timestamp, double margin) {
+ checkMarginInMw(cnecId, timestamp, margin, null);
+ }
+
@Then("the optimized margin on {string} for timestamp {string} is {double} MW")
public static void theOptimizedMarginOnCnecForTimestampIsMW(String cnecId, String timestamp, double margin) {
+ Instant afterCra = timeCoupledRaoInput.getRaoInputs().getData(getOffsetDateTimeFromBrusselsTimestamp(timestamp)).orElseThrow().getCrac().getLastInstant();
+ checkMarginInMw(cnecId, timestamp, margin, afterCra);
+ }
+
+ private static void checkMarginInMw(String cnecId, String timestamp, double margin, Instant optimizedInstant) {
OffsetDateTime offsetDateTime = getOffsetDateTimeFromBrusselsTimestamp(timestamp);
FlowCnec flowCnec = timeCoupledRaoInput.getRaoInputs().getData(offsetDateTime).orElseThrow().getCrac().getFlowCnec(cnecId);
- Instant afterCra = timeCoupledRaoInput.getRaoInputs().getData(offsetDateTime).orElseThrow().getCrac().getLastInstant();
assertEquals(margin,
- timeCoupledRaoResult.getIndividualRaoResult(offsetDateTime).getMargin(afterCra, flowCnec, Unit.MEGAWATT),
+ timeCoupledRaoResult.getIndividualRaoResult(offsetDateTime).getMargin(optimizedInstant, flowCnec, Unit.MEGAWATT),
RaoSteps.TOLERANCE_FLOW_IN_MEGAWATT);
}
diff --git a/tests/src/test/resources/com/powsybl/openrao/tests/features/7_roda/forced_actions.feature b/tests/src/test/resources/com/powsybl/openrao/tests/features/7_roda/forced_actions.feature
new file mode 100644
index 0000000000..f05d63a72b
--- /dev/null
+++ b/tests/src/test/resources/com/powsybl/openrao/tests/features/7_roda/forced_actions.feature
@@ -0,0 +1,29 @@
+# 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/.
+
+Feature: Forced actions in RODA
+ @fast @rao @dc @redispatching @forced-actions
+ Scenario: ForcedActions.1: A clone of test 4.1.2, with optimal topological PRA (Close Line NL2 BE3 2) of second TS forced in parameters
+ Given network files are in folder "epic93/TestCases_93_2_2"
+ Given crac file is "epic93/cbcora_93_2_2.xml"
+ Given ics static file is "epic93/static_93_2_1.csv"
+ Given ics series file is "epic93/series_93_2_1.csv"
+ Given configuration file is "roda/conf_force_actions.json"
+ Given time-coupled rao inputs for CORE are:
+ | Timestamp | Network |
+ | 2019-01-08 00:30 | 12Nodes_0030.uct |
+ | 2019-01-08 01:30 | 12Nodes_0130.uct |
+ When I launch roda
+ When I export marmot results to "raoresults/ForcedActions.zip"
+ Then the initial margin on "NNL2AA1 BBE3AA1 1 - preventive" for timestamp "2019-01-08 00:30" is 523.04 MW
+ And the initial margin on "NNL2AA1 BBE3AA1 1 - preventive" for timestamp "2019-01-08 01:30" is 252.8 MW
+ And the optimized margin on "NNL2AA1 BBE3AA1 1 - preventive" for timestamp "2019-01-08 00:30" is 523.04 MW
+ And the optimized margin on "NNL2AA1 BBE3AA1 1 - preventive" for timestamp "2019-01-08 01:30" is 252.8 MW
+ And the functional cost for timestamp "2019-01-08 00:30" is 0
+ And the functional cost for timestamp "2019-01-08 01:30" is 0
+ And the functional cost for all timestamps is 0
+ And the total cost for timestamp "2019-01-08 00:30" is 0
+ And the total cost for timestamp "2019-01-08 01:30" is 0
+ And the total cost for all timestamps is 0
\ No newline at end of file
diff --git a/tests/src/test/resources/files/configurations/roda/conf_force_actions.json b/tests/src/test/resources/files/configurations/roda/conf_force_actions.json
new file mode 100644
index 0000000000..ea0867adf1
--- /dev/null
+++ b/tests/src/test/resources/files/configurations/roda/conf_force_actions.json
@@ -0,0 +1,158 @@
+{
+ "version" : "3.3",
+ "objective-function" : {
+ "type" : "MIN_COST"
+ },
+ "range-actions-optimization" : {
+ "pst-ra-min-impact-threshold" : 0.1,
+ "hvdc-ra-min-impact-threshold" : 0.1,
+ "injection-ra-min-impact-threshold" : 0.1
+ },
+ "topological-actions-optimization" : {
+ "relative-minimum-impact-threshold" : 0.01,
+ "absolute-minimum-impact-threshold" : 100
+ },
+ "not-optimized-cnecs" : {
+ "do-not-optimize-curative-cnecs-for-tsos-without-cras" : false
+ },
+ "extensions" : {
+ "open-rao-search-tree-parameters" : {
+ "objective-function" : {
+ "curative-min-obj-improvement" : 0.0
+ },
+ "range-actions-optimization" : {
+ "max-mip-iterations" : 2,
+ "pst-sensitivity-threshold" : 0.001,
+ "pst-model" : "APPROXIMATED_INTEGERS",
+ "hvdc-sensitivity-threshold" : 0.001,
+ "injection-ra-sensitivity-threshold" : 0.001,
+ "ra-range-shrinking" : "DISABLED",
+ "linear-optimization-solver" : {
+ "solver" : "CBC",
+ "relative-mip-gap" : 0.001,
+ "solver-specific-parameters" : null
+ }
+ },
+ "topological-actions-optimization" : {
+ "max-preventive-search-tree-depth" : 2,
+ "max-curative-search-tree-depth" : 2,
+ "predefined-combinations" : [ ],
+ "skip-actions-far-from-most-limiting-element" : false,
+ "max-number-of-boundaries-for-skipping-actions" : 0
+ },
+ "second-preventive-rao" : {
+ "execution-condition" : "POSSIBLE_CURATIVE_IMPROVEMENT",
+ "hint-from-first-preventive-rao" : false
+ },
+ "load-flow-and-sensitivity-computation" : {
+ "load-flow-provider" : "OpenLoadFlow",
+ "sensitivity-provider" : "OpenLoadFlow",
+ "sensitivity-failure-overcost" : 10000.0,
+ "sensitivity-parameters" : {
+ "version" : "1.0",
+ "load-flow-parameters" : {
+ "version" : "1.10",
+ "voltageInitMode" : "UNIFORM_VALUES",
+ "transformerVoltageControlOn" : false,
+ "phaseShifterRegulationOn" : false,
+ "useReactiveLimits" : true,
+ "twtSplitShuntAdmittance" : true,
+ "shuntCompensatorVoltageControlOn" : false,
+ "readSlackBus" : false,
+ "writeSlackBus" : true,
+ "dc" : true,
+ "distributedSlack" : true,
+ "balanceType" : "PROPORTIONAL_TO_GENERATION_P",
+ "dcUseTransformerRatio" : false,
+ "countriesToBalance" : [ "GR", "BE", "SK", "TR", "CH", "RS", "PL", "UA", "BG", "ES", "ME", "CZ", "HR", "AL", "RO", "HU", "AT", "FR", "PT", "DE", "MK", "BA", "SI", "IT", "NL" ],
+ "componentMode" : "MAIN_CONNECTED",
+ "hvdcAcEmulation" : true,
+ "dcPowerFactor" : 1.0,
+ "extensions" : {
+ "open-load-flow-parameters" : {
+ "slackBusSelectionMode" : "MOST_MESHED",
+ "slackBusesIds" : [ ],
+ "slackDistributionFailureBehavior" : "LEAVE_ON_SLACK_BUS",
+ "lowImpedanceBranchMode" : "REPLACE_BY_ZERO_IMPEDANCE_LINE",
+ "loadPowerFactorConstant" : false,
+ "plausibleActivePowerLimit" : 10000.0,
+ "newtonRaphsonStoppingCriteriaType" : "UNIFORM_CRITERIA",
+ "maxActivePowerMismatch" : 0.01,
+ "maxReactivePowerMismatch" : 0.01,
+ "maxVoltageMismatch" : 1.0E-4,
+ "maxAngleMismatch" : 1.0E-5,
+ "maxRatioMismatch" : 1.0E-5,
+ "maxSusceptanceMismatch" : 1.0E-4,
+ "slackBusPMaxMismatch" : 1.0,
+ "voltagePerReactivePowerControl" : false,
+ "maxNewtonRaphsonIterations" : 30,
+ "maxOuterLoopIterations" : 20,
+ "newtonRaphsonConvEpsPerEq" : 1.0E-4,
+ "voltageInitModeOverride" : "NONE",
+ "transformerVoltageControlMode" : "WITH_GENERATOR_VOLTAGE_CONTROL",
+ "shuntVoltageControlMode" : "WITH_GENERATOR_VOLTAGE_CONTROL",
+ "minPlausibleTargetVoltage" : 0.8,
+ "maxPlausibleTargetVoltage" : 1.2,
+ "minNominalVoltageTargetVoltageCheck" : 20.0,
+ "minRealisticVoltage" : 0.5,
+ "maxRealisticVoltage" : 1.5,
+ "lowImpedanceThreshold" : 1.0E-8,
+ "reactiveRangeCheckMode" : "MAX",
+ "networkCacheEnabled" : false,
+ "svcVoltageMonitoring" : true,
+ "stateVectorScalingMode" : "NONE",
+ "maxSlackBusCount" : 1,
+ "debugDir" : null,
+ "incrementalTransformerRatioTapControlOuterLoopMaxTapShift" : 3,
+ "secondaryVoltageControl" : false,
+ "reactiveLimitsMaxPqPvSwitch" : 3,
+ "phaseShifterControlMode" : "CONTINUOUS_WITH_DISCRETISATION",
+ "alwaysUpdateNetwork" : false,
+ "mostMeshedSlackBusSelectorMaxNominalVoltagePercentile" : 95.0,
+ "reportedFeatures" : [ ],
+ "slackBusCountryFilter" : [ ],
+ "actionableSwitchesIds" : [ ],
+ "asymmetrical" : false,
+ "reactivePowerDispatchMode" : "Q_EQUAL_PROPORTION",
+ "outerLoopNames" : null,
+ "useActiveLimits" : true,
+ "lineSearchStateVectorScalingMaxIteration" : 10,
+ "lineSearchStateVectorScalingStepFold" : 1.3333333333333333,
+ "maxVoltageChangeStateVectorScalingMaxDv" : 0.1,
+ "maxVoltageChangeStateVectorScalingMaxDphi" : 0.17453292519943295,
+ "linePerUnitMode" : "IMPEDANCE",
+ "useLoadModel" : false,
+ "dcApproximationType" : "IGNORE_R",
+ "simulateAutomationSystems" : false
+ }
+ }
+ }
+ }
+ },
+ "multi-threading" : {
+ "available-cpus" : 14
+ },
+ "mnec-parameters" : {
+ "violation-cost" : 100000.0,
+ "constraint-adjustment-coefficient" : 3.0
+ },
+ "costly-min-margin-parameters" : {
+ "shifted-violation-threshold" : 10,
+ "shifted-violation-penalty" : 1000.0
+ }
+ },
+ "roda-parameters": {
+ "forced-preventive-actions-list": {
+ "version": "1.3",
+ "actions": [
+ {
+ "type": "TERMINALS_CONNECTION",
+ "id": "Close Line NL2 BE3 2",
+ "elementId": "NNL2AA1 BBE3AA1 2",
+ "open": false
+ }
+ ]
+ }
+ }
+ }
+}
\ No newline at end of file