From 436c7ae973cfe831ef99021c282b146a3cf23cc0 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Sun, 19 Feb 2023 17:26:04 +0100
Subject: [PATCH 01/30] Current limit automaton simulation

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../openloadflow/DefaultOuterLoopConfig.java  |  4 ++
 .../openloadflow/OpenLoadFlowParameters.java  | 31 +++++++--
 .../ac/outerloop/AutomatonOuterLoop.java      | 29 +++++++++
 .../extensions/CurrentLimitAutomaton.java     | 29 +++++++++
 .../CurrentLimitAutomatonAdder.java           | 21 +++++++
 .../CurrentLimitAutomatonAdderImpl.java       | 63 +++++++++++++++++++
 ...urrentLimitAutomatonAdderImplProvider.java | 40 ++++++++++++
 .../extensions/CurrentLimitAutomatonImpl.java | 46 ++++++++++++++
 .../OpenLoadFlowProviderTest.java             |  2 +-
 src/test/resources/debug-parameters.json      |  3 +-
 10 files changed, 262 insertions(+), 6 deletions(-)
 create mode 100644 src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomatonOuterLoop.java
 create mode 100644 src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomaton.java
 create mode 100644 src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdder.java
 create mode 100644 src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdderImpl.java
 create mode 100644 src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdderImplProvider.java
 create mode 100644 src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonImpl.java

diff --git a/src/main/java/com/powsybl/openloadflow/DefaultOuterLoopConfig.java b/src/main/java/com/powsybl/openloadflow/DefaultOuterLoopConfig.java
index 7a2184192b..a042dbfd6d 100644
--- a/src/main/java/com/powsybl/openloadflow/DefaultOuterLoopConfig.java
+++ b/src/main/java/com/powsybl/openloadflow/DefaultOuterLoopConfig.java
@@ -74,6 +74,10 @@ public List<OuterLoop> configure(LoadFlowParameters parameters, OpenLoadFlowPara
         if (parameters.isShuntCompensatorVoltageControlOn()) {
             outerLoops.add(createShuntVoltageControlOuterLoop(parametersExt));
         }
+        // automatons
+        if (parametersExt.isSimulateAutomatons()) {
+            outerLoops.add(new AutomatonOuterLoop());
+        }
         // secondary voltage control
         if (parametersExt.isSecondaryVoltageControl()) {
             outerLoops.add(new SecondaryVoltageControlOuterLoop());
diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
index c3b1469108..c515d2f39e 100644
--- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
+++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
@@ -90,6 +90,8 @@ public class OpenLoadFlowParameters extends AbstractExtension<LoadFlowParameters
 
     public static final ShuntVoltageControlMode SHUNT_VOLTAGE_CONTROL_MODE_DEFAULT_VALUE = ShuntVoltageControlMode.WITH_GENERATOR_VOLTAGE_CONTROL;
 
+    public static final boolean SIMULATE_AUTOMATONS_DEFAULT_VALUE = false;
+
     public static final String SLACK_BUS_SELECTION_MODE_PARAM_NAME = "slackBusSelectionMode";
 
     public static final String SLACK_BUSES_IDS_PARAM_NAME = "slackBusesIds";
@@ -164,6 +166,8 @@ public class OpenLoadFlowParameters extends AbstractExtension<LoadFlowParameters
 
     public static final String REACTIVE_LIMITS_MAX_SWITCH_PQ_PV_PARAM_NAME = "ReactiveLimitsMaxPqPvSwitch";
 
+    public static final String SIMULATE_AUTOMATONS_PARAM_NAME = "simulateAutomaton";
+
     private static <E extends Enum<E>> List<Object> getEnumPossibleValues(Class<E> enumClass) {
         return EnumSet.allOf(enumClass).stream().map(Enum::name).collect(Collectors.toList());
     }
@@ -205,7 +209,8 @@ private static <E extends Enum<E>> List<Object> getEnumPossibleValues(Class<E> e
         new Parameter(MAX_VOLTAGE_MISMATCH_PARAM_NAME, ParameterType.DOUBLE, "Maximum voltage for per equation stopping criteria", MAX_VOLTAGE_MISMATCH_DEFAULT_VALUE),
         new Parameter(MAX_ANGLE_MISMATCH_PARAM_NAME, ParameterType.DOUBLE, "Maximum angle for per equation stopping criteria", MAX_ANGLE_MISMATCH_DEFAULT_VALUE),
         new Parameter(MAX_RATIO_MISMATCH_PARAM_NAME, ParameterType.DOUBLE, "Maximum ratio for per equation stopping criteria", MAX_RATIO_MISMATCH_DEFAULT_VALUE),
-        new Parameter(MAX_SUSCEPTANCE_MISMATCH_PARAM_NAME, ParameterType.DOUBLE, "Maximum susceptance for per equation stopping criteria", MAX_SUSCEPTANCE_MISMATCH_DEFAULT_VALUE)
+        new Parameter(MAX_SUSCEPTANCE_MISMATCH_PARAM_NAME, ParameterType.DOUBLE, "Maximum susceptance for per equation stopping criteria", MAX_SUSCEPTANCE_MISMATCH_DEFAULT_VALUE),
+        new Parameter(SIMULATE_AUTOMATONS_PARAM_NAME, ParameterType.BOOLEAN, "Automatons simulation", SIMULATE_AUTOMATONS_DEFAULT_VALUE)
     );
 
     public enum VoltageInitModeOverride {
@@ -310,6 +315,8 @@ public enum ReactiveRangeCheckMode {
 
     private int reactiveLimitsMaxPqPvSwitch = ReactiveLimitsOuterLoop.MAX_SWITCH_PQ_PV;
 
+    private boolean simulateAutomatons = SIMULATE_AUTOMATONS_DEFAULT_VALUE;
+
     @Override
     public String getName() {
         return "open-load-flow-parameters";
@@ -683,6 +690,15 @@ public OpenLoadFlowParameters setReactiveLimitsMaxPqPvSwitch(int reactiveLimitsM
         return this;
     }
 
+    public boolean isSimulateAutomatons() {
+        return simulateAutomatons;
+    }
+
+    public OpenLoadFlowParameters setSimulateAutomatons(boolean simulateAutomatons) {
+        this.simulateAutomatons = simulateAutomatons;
+        return this;
+    }
+
     public static OpenLoadFlowParameters load() {
         return load(PlatformConfig.defaultConfig());
     }
@@ -730,7 +746,8 @@ public static OpenLoadFlowParameters load(PlatformConfig platformConfig) {
                 .setDebugDir(config.getStringProperty(DEBUG_DIR_PARAM_NAME, LfNetworkParameters.DEBUG_DIR_DEFAULT_VALUE))
                 .setIncrementalTransformerVoltageControlOuterLoopMaxTapShift(config.getIntProperty(INCREMENTAL_TRANSFORMER_VOLTAGE_CONTROL_OUTER_LOOP_MAX_TAP_SHIFT_PARAM_NAME, IncrementalTransformerVoltageControlOuterLoop.DEFAULT_MAX_TAP_SHIFT))
                 .setSecondaryVoltageControl(config.getBooleanProperty(SECONDARY_VOLTAGE_CONTROL_PARAM_NAME, LfNetworkParameters.SECONDARY_VOLTAGE_CONTROL_DEFAULT_VALUE))
-                .setReactiveLimitsMaxPqPvSwitch(config.getIntProperty(REACTIVE_LIMITS_MAX_SWITCH_PQ_PV_PARAM_NAME, ReactiveLimitsOuterLoop.MAX_SWITCH_PQ_PV)));
+                .setReactiveLimitsMaxPqPvSwitch(config.getIntProperty(REACTIVE_LIMITS_MAX_SWITCH_PQ_PV_PARAM_NAME, ReactiveLimitsOuterLoop.MAX_SWITCH_PQ_PV))
+                .setSimulateAutomatons(config.getBooleanProperty(SIMULATE_AUTOMATONS_PARAM_NAME, SIMULATE_AUTOMATONS_DEFAULT_VALUE)));
         return parameters;
     }
 
@@ -813,6 +830,8 @@ public OpenLoadFlowParameters update(Map<String, String> properties) {
                 .ifPresent(prop -> this.setSecondaryVoltageControl(Boolean.parseBoolean(prop)));
         Optional.ofNullable(properties.get(REACTIVE_LIMITS_MAX_SWITCH_PQ_PV_PARAM_NAME))
                 .ifPresent(prop -> this.setReactiveLimitsMaxPqPvSwitch(Integer.parseInt(prop)));
+        Optional.ofNullable(properties.get(SIMULATE_AUTOMATONS_PARAM_NAME))
+                .ifPresent(prop -> this.setSimulateAutomatons(Boolean.parseBoolean(prop)));
         return this;
     }
 
@@ -856,6 +875,7 @@ public String toString() {
                 ", incrementalTransformerVoltageControlOuterLoopMaxTapShift=" + incrementalTransformerVoltageControlOuterLoopMaxTapShift +
                 ", secondaryVoltageControl=" + secondaryVoltageControl +
                 ", reactiveLimitsMaxPqPvSwitch=" + reactiveLimitsMaxPqPvSwitch +
+                ", simulateAutomaton=" + simulateAutomatons +
                 ')';
     }
 
@@ -930,6 +950,7 @@ public static void logAc(LoadFlowParameters parameters, OpenLoadFlowParameters p
         LOGGER.info("Incremental transformer voltage control outer loop max tap shift: {}", parametersExt.getIncrementalTransformerVoltageControlOuterLoopMaxTapShift());
         LOGGER.info("Secondary voltage control: {}", parametersExt.isSecondaryVoltageControl());
         LOGGER.info("Reactive limits maximum Pq Pv switch: {}", parametersExt.getReactiveLimitsMaxPqPvSwitch());
+        LOGGER.info("Simulate automaton: {}", parametersExt.isSimulateAutomatons());
     }
 
     static VoltageInitializer getVoltageInitializer(LoadFlowParameters parameters, LfNetworkParameters networkParameters, MatrixFactory matrixFactory) {
@@ -1174,7 +1195,8 @@ public static boolean equals(LoadFlowParameters parameters1, LoadFlowParameters
                 Objects.equals(extension1.getDebugDir(), extension2.getDebugDir()) &&
                 extension1.getIncrementalTransformerVoltageControlOuterLoopMaxTapShift() == extension2.getIncrementalTransformerVoltageControlOuterLoopMaxTapShift() &&
                 extension1.isSecondaryVoltageControl() == extension2.isSecondaryVoltageControl() &&
-                extension1.getReactiveLimitsMaxPqPvSwitch() == extension2.getReactiveLimitsMaxPqPvSwitch();
+                extension1.getReactiveLimitsMaxPqPvSwitch() == extension2.getReactiveLimitsMaxPqPvSwitch() &&
+                extension1.isSimulateAutomatons() == extension2.isSimulateAutomatons();
     }
 
     public static LoadFlowParameters clone(LoadFlowParameters parameters) {
@@ -1227,7 +1249,8 @@ public static LoadFlowParameters clone(LoadFlowParameters parameters) {
                     .setDebugDir(extension.getDebugDir())
                     .setIncrementalTransformerVoltageControlOuterLoopMaxTapShift(extension.getIncrementalTransformerVoltageControlOuterLoopMaxTapShift())
                     .setSecondaryVoltageControl(extension.isSecondaryVoltageControl())
-                    .setReactiveLimitsMaxPqPvSwitch(extension.getReactiveLimitsMaxPqPvSwitch());
+                    .setReactiveLimitsMaxPqPvSwitch(extension.getReactiveLimitsMaxPqPvSwitch())
+                    .setSimulateAutomatons(extension.isSimulateAutomatons());
             if (extension2 != null) {
                 parameters2.addExtension(OpenLoadFlowParameters.class, extension2);
             }
diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomatonOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomatonOuterLoop.java
new file mode 100644
index 0000000000..720d6bf71a
--- /dev/null
+++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomatonOuterLoop.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.ac.outerloop;
+
+import com.powsybl.commons.reporter.Reporter;
+import com.powsybl.openloadflow.ac.OuterLoop;
+import com.powsybl.openloadflow.ac.OuterLoopContext;
+import com.powsybl.openloadflow.ac.OuterLoopStatus;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+public class AutomatonOuterLoop implements OuterLoop {
+
+    @Override
+    public String getType() {
+        return "Automaton";
+    }
+
+    @Override
+    public OuterLoopStatus check(OuterLoopContext context, Reporter reporter) {
+        // TODO
+        return OuterLoopStatus.STABLE;
+    }
+}
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomaton.java b/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomaton.java
new file mode 100644
index 0000000000..7da9eb0947
--- /dev/null
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomaton.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.network.extensions;
+
+import com.powsybl.commons.extensions.Extension;
+import com.powsybl.iidm.network.Line;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+public interface CurrentLimitAutomaton extends Extension<Line> {
+
+    String NAME = "CurrentLimitAutomaton";
+
+    @Override
+    default String getName() {
+        return NAME;
+    }
+
+    double getThreshold();
+
+    String getSwitchId();
+
+    boolean isSwitchOpen();
+}
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdder.java b/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdder.java
new file mode 100644
index 0000000000..09a92a46e5
--- /dev/null
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdder.java
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.network.extensions;
+
+import com.powsybl.commons.extensions.ExtensionAdder;
+import com.powsybl.iidm.network.Line;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+public interface CurrentLimitAutomatonAdder extends ExtensionAdder<Line, CurrentLimitAutomaton> {
+    CurrentLimitAutomatonAdderImpl withThreshold(double threshold);
+
+    CurrentLimitAutomatonAdderImpl withSwitchId(String switchId);
+
+    CurrentLimitAutomatonAdderImpl withSwitchOpen(boolean open);
+}
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdderImpl.java b/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdderImpl.java
new file mode 100644
index 0000000000..ef57bb3ca0
--- /dev/null
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdderImpl.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.network.extensions;
+
+import com.powsybl.commons.PowsyblException;
+import com.powsybl.commons.extensions.AbstractExtensionAdder;
+import com.powsybl.iidm.network.Line;
+
+import java.util.Objects;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+public class CurrentLimitAutomatonAdderImpl extends AbstractExtensionAdder<Line, CurrentLimitAutomaton> implements CurrentLimitAutomatonAdder {
+
+    private double threshold = Double.NaN;
+
+    private String switchId;
+
+    private boolean switchOpen = true;
+
+    public CurrentLimitAutomatonAdderImpl(Line line) {
+        super(line);
+    }
+
+    @Override
+    public Class<? super CurrentLimitAutomaton> getExtensionClass() {
+        return CurrentLimitAutomaton.class;
+    }
+
+    @Override
+    public CurrentLimitAutomatonAdderImpl withThreshold(double threshold) {
+        this.threshold = threshold;
+        return this;
+    }
+
+    @Override
+    public CurrentLimitAutomatonAdderImpl withSwitchId(String switchId) {
+        this.switchId = Objects.requireNonNull(switchId);
+        return this;
+    }
+
+    @Override
+    public CurrentLimitAutomatonAdderImpl withSwitchOpen(boolean open) {
+        this.switchOpen = open;
+        return this;
+    }
+
+    @Override
+    protected CurrentLimitAutomaton createExtension(Line line) {
+        if (Double.isNaN(threshold)) {
+            throw new PowsyblException("Threshold is not set");
+        }
+        if (switchId == null) {
+            throw new PowsyblException("Switch ID is not set");
+        }
+        return new CurrentLimitAutomatonImpl(line, threshold, switchId, switchOpen);
+    }
+}
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdderImplProvider.java b/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdderImplProvider.java
new file mode 100644
index 0000000000..4b15eec60a
--- /dev/null
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdderImplProvider.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.network.extensions;
+
+import com.google.auto.service.AutoService;
+import com.powsybl.commons.extensions.ExtensionAdderProvider;
+import com.powsybl.iidm.network.Line;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+@AutoService(ExtensionAdderProvider.class)
+public class CurrentLimitAutomatonAdderImplProvider implements
+        ExtensionAdderProvider<Line, CurrentLimitAutomaton, CurrentLimitAutomatonAdder> {
+
+    @Override
+    public String getImplementationName() {
+        return "Default";
+    }
+
+    @Override
+    public String getExtensionName() {
+        return CurrentLimitAutomaton.NAME;
+    }
+
+    @Override
+    public Class<CurrentLimitAutomatonAdder> getAdderClass() {
+        return CurrentLimitAutomatonAdder.class;
+    }
+
+    @Override
+    public CurrentLimitAutomatonAdder newAdder(Line line) {
+        return new CurrentLimitAutomatonAdderImpl(line);
+    }
+}
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonImpl.java b/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonImpl.java
new file mode 100644
index 0000000000..7f68425139
--- /dev/null
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonImpl.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.network.extensions;
+
+import com.powsybl.commons.extensions.AbstractExtension;
+import com.powsybl.iidm.network.Line;
+
+import java.util.Objects;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+public class CurrentLimitAutomatonImpl extends AbstractExtension<Line> implements CurrentLimitAutomaton {
+
+    private final double threshold;
+
+    private final String switchId;
+
+    private final boolean switchOpen;
+
+    public CurrentLimitAutomatonImpl(Line line, double threshold, String switchId, boolean switchOpen) {
+        super(line);
+        this.threshold = threshold;
+        this.switchId = Objects.requireNonNull(switchId);
+        this.switchOpen = switchOpen;
+    }
+
+    @Override
+    public double getThreshold() {
+        return threshold;
+    }
+
+    @Override
+    public String getSwitchId() {
+        return switchId;
+    }
+
+    @Override
+    public boolean isSwitchOpen() {
+        return switchOpen;
+    }
+}
diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
index dcf4d784dc..47c1fc010c 100644
--- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
+++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
@@ -85,7 +85,7 @@ void testGetExtendedVoltageInitializer() {
     @Test
     void specificParametersTest() {
         OpenLoadFlowProvider provider = new OpenLoadFlowProvider();
-        assertEquals(37, provider.getSpecificParameters().size());
+        assertEquals(38, provider.getSpecificParameters().size());
         LoadFlowParameters parameters = new LoadFlowParameters();
 
         provider.loadSpecificParameters(Collections.emptyMap())
diff --git a/src/test/resources/debug-parameters.json b/src/test/resources/debug-parameters.json
index 129bc8fb3c..49541b0682 100644
--- a/src/test/resources/debug-parameters.json
+++ b/src/test/resources/debug-parameters.json
@@ -53,7 +53,8 @@
         "debugDir" : null,
         "incrementalTransformerVoltageControlOuterLoopMaxTapShift" : 3,
         "secondaryVoltageControl" : false,
-        "reactiveLimitsMaxPqPvSwitch" : 3
+        "reactiveLimitsMaxPqPvSwitch" : 3,
+        "simulateAutomatons" : false
       }
     }
   },

From c9ab21c1e22472ca7f9306abf846a63151c9f400 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Sun, 19 Feb 2023 17:44:47 +0100
Subject: [PATCH 02/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../openloadflow/OpenLoadFlowParameters.java  |  8 ++---
 .../openloadflow/network/LfBranch.java        |  2 ++
 .../network/LfCurrentLimitAutomaton.java      | 34 +++++++++++++++++++
 .../network/LfNetworkParameters.java          | 14 ++++++++
 .../network/impl/AbstractLfBranch.java        |  7 ++++
 .../network/impl/LfNetworkLoaderImpl.java     | 20 +++++++++++
 .../OpenLoadFlowProviderTest.java             |  4 +--
 7 files changed, 82 insertions(+), 7 deletions(-)
 create mode 100644 src/main/java/com/powsybl/openloadflow/network/LfCurrentLimitAutomaton.java

diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
index c515d2f39e..e7468fc9bf 100644
--- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
+++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
@@ -90,8 +90,6 @@ public class OpenLoadFlowParameters extends AbstractExtension<LoadFlowParameters
 
     public static final ShuntVoltageControlMode SHUNT_VOLTAGE_CONTROL_MODE_DEFAULT_VALUE = ShuntVoltageControlMode.WITH_GENERATOR_VOLTAGE_CONTROL;
 
-    public static final boolean SIMULATE_AUTOMATONS_DEFAULT_VALUE = false;
-
     public static final String SLACK_BUS_SELECTION_MODE_PARAM_NAME = "slackBusSelectionMode";
 
     public static final String SLACK_BUSES_IDS_PARAM_NAME = "slackBusesIds";
@@ -210,7 +208,7 @@ private static <E extends Enum<E>> List<Object> getEnumPossibleValues(Class<E> e
         new Parameter(MAX_ANGLE_MISMATCH_PARAM_NAME, ParameterType.DOUBLE, "Maximum angle for per equation stopping criteria", MAX_ANGLE_MISMATCH_DEFAULT_VALUE),
         new Parameter(MAX_RATIO_MISMATCH_PARAM_NAME, ParameterType.DOUBLE, "Maximum ratio for per equation stopping criteria", MAX_RATIO_MISMATCH_DEFAULT_VALUE),
         new Parameter(MAX_SUSCEPTANCE_MISMATCH_PARAM_NAME, ParameterType.DOUBLE, "Maximum susceptance for per equation stopping criteria", MAX_SUSCEPTANCE_MISMATCH_DEFAULT_VALUE),
-        new Parameter(SIMULATE_AUTOMATONS_PARAM_NAME, ParameterType.BOOLEAN, "Automatons simulation", SIMULATE_AUTOMATONS_DEFAULT_VALUE)
+        new Parameter(SIMULATE_AUTOMATONS_PARAM_NAME, ParameterType.BOOLEAN, "Automatons simulation", LfNetworkParameters.SIMULATE_AUTOMATONS_DEFAULT_VALUE)
     );
 
     public enum VoltageInitModeOverride {
@@ -315,7 +313,7 @@ public enum ReactiveRangeCheckMode {
 
     private int reactiveLimitsMaxPqPvSwitch = ReactiveLimitsOuterLoop.MAX_SWITCH_PQ_PV;
 
-    private boolean simulateAutomatons = SIMULATE_AUTOMATONS_DEFAULT_VALUE;
+    private boolean simulateAutomatons = LfNetworkParameters.SIMULATE_AUTOMATONS_DEFAULT_VALUE;
 
     @Override
     public String getName() {
@@ -747,7 +745,7 @@ public static OpenLoadFlowParameters load(PlatformConfig platformConfig) {
                 .setIncrementalTransformerVoltageControlOuterLoopMaxTapShift(config.getIntProperty(INCREMENTAL_TRANSFORMER_VOLTAGE_CONTROL_OUTER_LOOP_MAX_TAP_SHIFT_PARAM_NAME, IncrementalTransformerVoltageControlOuterLoop.DEFAULT_MAX_TAP_SHIFT))
                 .setSecondaryVoltageControl(config.getBooleanProperty(SECONDARY_VOLTAGE_CONTROL_PARAM_NAME, LfNetworkParameters.SECONDARY_VOLTAGE_CONTROL_DEFAULT_VALUE))
                 .setReactiveLimitsMaxPqPvSwitch(config.getIntProperty(REACTIVE_LIMITS_MAX_SWITCH_PQ_PV_PARAM_NAME, ReactiveLimitsOuterLoop.MAX_SWITCH_PQ_PV))
-                .setSimulateAutomatons(config.getBooleanProperty(SIMULATE_AUTOMATONS_PARAM_NAME, SIMULATE_AUTOMATONS_DEFAULT_VALUE)));
+                .setSimulateAutomatons(config.getBooleanProperty(SIMULATE_AUTOMATONS_PARAM_NAME, LfNetworkParameters.SIMULATE_AUTOMATONS_DEFAULT_VALUE)));
         return parameters;
     }
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/LfBranch.java b/src/main/java/com/powsybl/openloadflow/network/LfBranch.java
index c40d8fc8a8..b172f0c8c7 100644
--- a/src/main/java/com/powsybl/openloadflow/network/LfBranch.java
+++ b/src/main/java/com/powsybl/openloadflow/network/LfBranch.java
@@ -171,4 +171,6 @@ static double getDiscretePhaseControlTarget(LfBranch branch, DiscretePhaseContro
     boolean isConnectedAtBothSides();
 
     void setMinZ(double lowImpedanceThreshold);
+
+    List<LfCurrentLimitAutomaton> getCurrentLimitAutomata();
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/LfCurrentLimitAutomaton.java b/src/main/java/com/powsybl/openloadflow/network/LfCurrentLimitAutomaton.java
new file mode 100644
index 0000000000..0e3728375f
--- /dev/null
+++ b/src/main/java/com/powsybl/openloadflow/network/LfCurrentLimitAutomaton.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.network;
+
+import com.powsybl.openloadflow.network.impl.LfSwitch;
+
+import java.util.Objects;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+public class LfCurrentLimitAutomaton {
+
+    private final LfSwitch switchToOperate;
+
+    private final boolean switchOpen;
+
+    public LfCurrentLimitAutomaton(LfSwitch switchToOperate, boolean switchOpen) {
+        this.switchToOperate = Objects.requireNonNull(switchToOperate);
+        this.switchOpen = switchOpen;
+    }
+
+    public LfSwitch getSwitchToOperate() {
+        return switchToOperate;
+    }
+
+    public boolean isSwitchOpen() {
+        return switchOpen;
+    }
+}
diff --git a/src/main/java/com/powsybl/openloadflow/network/LfNetworkParameters.java b/src/main/java/com/powsybl/openloadflow/network/LfNetworkParameters.java
index b882f336cb..6a1a2a3725 100644
--- a/src/main/java/com/powsybl/openloadflow/network/LfNetworkParameters.java
+++ b/src/main/java/com/powsybl/openloadflow/network/LfNetworkParameters.java
@@ -42,6 +42,8 @@ public class LfNetworkParameters {
 
     public static final boolean CACHE_ENABLED_DEFAULT_VALUE = false;
 
+    public static final boolean SIMULATE_AUTOMATONS_DEFAULT_VALUE = false;
+
     private SlackBusSelector slackBusSelector = new FirstSlackBusSelector();
 
     private GraphConnectivityFactory<LfBus, LfBranch> connectivityFactory = new EvenShiloachGraphDecrementalConnectivityFactory<>();
@@ -98,6 +100,8 @@ public class LfNetworkParameters {
 
     private boolean cacheEnabled = CACHE_ENABLED_DEFAULT_VALUE;
 
+    private boolean simulateAutomatons = SIMULATE_AUTOMATONS_DEFAULT_VALUE;
+
     public SlackBusSelector getSlackBusSelector() {
         return slackBusSelector;
     }
@@ -360,6 +364,15 @@ public LfNetworkParameters setCacheEnabled(boolean cacheEnabled) {
         return this;
     }
 
+    public boolean isSimulateAutomatons() {
+        return simulateAutomatons;
+    }
+
+    public LfNetworkParameters setSimulateAutomatons(boolean simulateAutomatons) {
+        this.simulateAutomatons = simulateAutomatons;
+        return this;
+    }
+
     @Override
     public String toString() {
         return "LfNetworkParameters(" +
@@ -390,6 +403,7 @@ public String toString() {
                 ", debugDir=" + debugDir +
                 ", secondaryVoltageControl=" + secondaryVoltageControl +
                 ", cacheEnabled=" + cacheEnabled +
+                ", simulateAutomatons=" + simulateAutomatons +
                 ')';
     }
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBranch.java b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBranch.java
index 5bc42ec432..cfe2b36526 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBranch.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBranch.java
@@ -53,6 +53,8 @@ public abstract class AbstractLfBranch extends AbstractElement implements LfBran
 
     protected boolean acZeroImpedance = false;
 
+    protected final List<LfCurrentLimitAutomaton> currentLimitAutomata = new ArrayList<>();
+
     protected AbstractLfBranch(LfNetwork network, LfBus bus1, LfBus bus2, PiModel piModel, LfNetworkParameters parameters) {
         super(network);
         this.bus1 = bus1;
@@ -305,4 +307,9 @@ private static boolean isZeroImpedanceBranch(PiModel piModel, boolean dc, double
             return piModel.getZ() < lowImpedanceThreshold;
         }
     }
+
+    @Override
+    public List<LfCurrentLimitAutomaton> getCurrentLimitAutomata() {
+        return currentLimitAutomata;
+    }
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
index 0266b504ae..4927f24f12 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
@@ -15,6 +15,7 @@
 import com.powsybl.iidm.network.extensions.SecondaryVoltageControl.ControlZone;
 import com.powsybl.iidm.network.extensions.SecondaryVoltageControl.PilotPoint;
 import com.powsybl.openloadflow.network.*;
+import com.powsybl.openloadflow.network.extensions.CurrentLimitAutomaton;
 import com.powsybl.openloadflow.util.DebugUtil;
 import com.powsybl.openloadflow.util.PerUnit;
 import com.powsybl.openloadflow.util.Reports;
@@ -793,6 +794,10 @@ private LfNetwork create(int numCC, int numSC, Network network, List<Bus> buses,
         // secondary voltage controls
         createSecondaryVoltageControls(network, parameters, lfNetwork);
 
+        if (parameters.isSimulateAutomatons()) {
+            createAutomata(network, lfNetwork);
+        }
+
         if (report.generatorsDiscardedFromVoltageControlBecauseNotStarted > 0) {
             Reports.reportGeneratorsDiscardedFromVoltageControlBecauseNotStarted(reporter, report.generatorsDiscardedFromVoltageControlBecauseNotStarted);
             LOGGER.warn("Network {}: {} generators have been discarded from voltage control because not started",
@@ -896,6 +901,21 @@ private static Optional<Bus> findPilotBus(Network network, boolean breaker, List
         return Optional.empty();
     }
 
+    private void createAutomata(Network network, LfNetwork lfNetwork) {
+        for (Line line : network.getLines()) {
+            LfBranch lfLine = lfNetwork.getBranchById(line.getId());
+            if (lfLine != null) {
+                CurrentLimitAutomaton cla = line.getExtension(CurrentLimitAutomaton.class);
+                if (cla != null) {
+                    LfSwitch lfSwitch = (LfSwitch) lfNetwork.getBranchById(cla.getSwitchId());
+                    if (lfSwitch != null) {
+                        lfLine.getCurrentLimitAutomata().add(new LfCurrentLimitAutomaton(lfSwitch, cla.isSwitchOpen()));
+                    }
+                }
+            }
+        }
+    }
+
     @Override
     public List<LfNetwork> load(Network network, LfNetworkParameters parameters, Reporter reporter) {
         Objects.requireNonNull(network);
diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
index 47c1fc010c..ac6f2684e1 100644
--- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
+++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
@@ -49,7 +49,7 @@ void test() {
     void testDcParameters() {
         Network network = Mockito.mock(Network.class);
         DcLoadFlowParameters dcParameters = OpenLoadFlowParameters.createDcParameters(network, new LoadFlowParameters().setReadSlackBus(true), new OpenLoadFlowParameters(), new DenseMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), true);
-        assertEquals("DcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=false, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, dc=true, reactiveLimits=false, hvdcAcEmulation=false, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=false, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false), equationSystemCreationParameters=DcEquationSystemCreationParameters(updateFlows=true, forcePhaseControlOffAndAddAngle1Var=true, useTransformerRatio=true), matrixFactory=DenseMatrixFactory, distributedSlack=true, balanceType=PROPORTIONAL_TO_GENERATION_P_MAX, setVToNan=true)",
+        assertEquals("DcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=false, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, dc=true, reactiveLimits=false, hvdcAcEmulation=false, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=false, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, simulateAutomatons=false), equationSystemCreationParameters=DcEquationSystemCreationParameters(updateFlows=true, forcePhaseControlOffAndAddAngle1Var=true, useTransformerRatio=true), matrixFactory=DenseMatrixFactory, distributedSlack=true, balanceType=PROPORTIONAL_TO_GENERATION_P_MAX, setVToNan=true)",
                      dcParameters.toString());
     }
 
@@ -57,7 +57,7 @@ void testDcParameters() {
     void testAcParameters() {
         Network network = Mockito.mock(Network.class);
         AcLoadFlowParameters acParameters = OpenLoadFlowParameters.createAcParameters(network, new LoadFlowParameters().setReadSlackBus(true), new OpenLoadFlowParameters(), new DenseMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), false, false);
-        assertEquals("AcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=true, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, dc=false, reactiveLimits=true, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=true, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false), equationSystemCreationParameters=AcEquationSystemCreationParameters(forceA1Var=false), newtonRaphsonParameters=NewtonRaphsonParameters(maxIteration=30, minRealisticVoltage=0.5, maxRealisticVoltage=1.5, stoppingCriteria=DefaultNewtonRaphsonStoppingCriteria, stateVectorScalingMode=NONE), outerLoops=[DistributedSlackOuterLoop, MonitoringVoltageOuterLoop, ReactiveLimitsOuterLoop], matrixFactory=DenseMatrixFactory, voltageInitializer=UniformValueVoltageInitializer)",
+        assertEquals("AcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=true, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, dc=false, reactiveLimits=true, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=true, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, simulateAutomatons=false), equationSystemCreationParameters=AcEquationSystemCreationParameters(forceA1Var=false), newtonRaphsonParameters=NewtonRaphsonParameters(maxIteration=30, minRealisticVoltage=0.5, maxRealisticVoltage=1.5, stoppingCriteria=DefaultNewtonRaphsonStoppingCriteria, stateVectorScalingMode=NONE), outerLoops=[DistributedSlackOuterLoop, MonitoringVoltageOuterLoop, ReactiveLimitsOuterLoop], matrixFactory=DenseMatrixFactory, voltageInitializer=UniformValueVoltageInitializer)",
                      acParameters.toString());
     }
 

From 9a8f3cf4469541e52af02edd53b9bcfa9c796098 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Sun, 19 Feb 2023 21:15:40 +0100
Subject: [PATCH 03/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../openloadflow/OpenLoadFlowParameters.java  |  3 +-
 .../openloadflow/OpenLoadFlowProvider.java    |  8 +++-
 .../openloadflow/ac/AcloadFlowEngine.java     |  8 ++--
 .../ac/outerloop/AutomatonOuterLoop.java      | 36 ++++++++++++++-
 .../openloadflow/network/impl/Networks.java   | 44 ++++++++++++++-----
 5 files changed, 78 insertions(+), 21 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
index e7468fc9bf..2662ab6641 100644
--- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
+++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
@@ -1016,7 +1016,8 @@ static LfNetworkParameters getNetworkParameters(LoadFlowParameters parameters, O
                 .setMaxSlackBusCount(parametersExt.getMaxSlackBusCount())
                 .setDebugDir(parametersExt.getDebugDir())
                 .setSecondaryVoltageControl(parametersExt.isSecondaryVoltageControl())
-                .setCacheEnabled(parametersExt.isNetworkCacheEnabled());
+                .setCacheEnabled(parametersExt.isNetworkCacheEnabled())
+                .setSimulateAutomatons(parametersExt.isSimulateAutomatons());
     }
 
     public static AcLoadFlowParameters createAcParameters(Network network, LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt,
diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
index dc32013eef..67daab7eaa 100644
--- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
+++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
@@ -22,11 +22,11 @@
 import com.powsybl.loadflow.LoadFlowResultImpl;
 import com.powsybl.math.matrix.MatrixFactory;
 import com.powsybl.math.matrix.SparseMatrixFactory;
-import com.powsybl.openloadflow.ac.nr.NewtonRaphsonStatus;
 import com.powsybl.openloadflow.ac.AcLoadFlowParameters;
 import com.powsybl.openloadflow.ac.AcLoadFlowResult;
 import com.powsybl.openloadflow.ac.AcloadFlowEngine;
 import com.powsybl.openloadflow.ac.OuterLoop;
+import com.powsybl.openloadflow.ac.nr.NewtonRaphsonStatus;
 import com.powsybl.openloadflow.dc.DcLoadFlowEngine;
 import com.powsybl.openloadflow.dc.DcLoadFlowResult;
 import com.powsybl.openloadflow.graph.EvenShiloachGraphDecrementalConnectivityFactory;
@@ -35,6 +35,7 @@
 import com.powsybl.openloadflow.network.LfBus;
 import com.powsybl.openloadflow.network.LfNetwork;
 import com.powsybl.openloadflow.network.LfNetworkStateUpdateParameters;
+import com.powsybl.openloadflow.network.impl.LfNetworkList;
 import com.powsybl.openloadflow.network.impl.LfNetworkLoaderImpl;
 import com.powsybl.openloadflow.network.impl.Networks;
 import com.powsybl.openloadflow.network.util.ZeroImpedanceFlows;
@@ -106,7 +107,10 @@ private LoadFlowResult runAc(Network network, LoadFlowParameters parameters, Rep
             results = new AcLoadFlowFromCache(network, parameters, acParameters, reporter)
                     .run();
         } else {
-            results = AcloadFlowEngine.run(network, new LfNetworkLoaderImpl(), acParameters, reporter);
+            try (LfNetworkList lfNetworkList = Networks.load(network, acParameters.getNetworkParameters(), Collections.emptySet(),
+                                                             Collections.emptySet(), reporter)) {
+                results = AcloadFlowEngine.run(lfNetworkList.getList(), acParameters);
+            }
         }
 
         Networks.resetState(network);
diff --git a/src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java b/src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java
index cf55bf92b1..0efaf2942e 100644
--- a/src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java
+++ b/src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java
@@ -9,14 +9,13 @@
 import com.google.common.collect.Lists;
 import com.powsybl.commons.reporter.Reporter;
 import com.powsybl.commons.reporter.TypedValue;
-import com.powsybl.openloadflow.lf.LoadFlowEngine;
 import com.powsybl.openloadflow.ac.equations.AcEquationType;
 import com.powsybl.openloadflow.ac.equations.AcVariableType;
 import com.powsybl.openloadflow.ac.nr.NewtonRaphson;
 import com.powsybl.openloadflow.ac.nr.NewtonRaphsonResult;
 import com.powsybl.openloadflow.ac.nr.NewtonRaphsonStatus;
+import com.powsybl.openloadflow.lf.LoadFlowEngine;
 import com.powsybl.openloadflow.network.LfNetwork;
-import com.powsybl.openloadflow.network.LfNetworkLoader;
 import com.powsybl.openloadflow.network.util.PreviousValueVoltageInitializer;
 import com.powsybl.openloadflow.network.util.VoltageInitializer;
 import com.powsybl.openloadflow.util.Reports;
@@ -166,9 +165,8 @@ public AcLoadFlowResult run() {
         return result;
     }
 
-    public static <T> List<AcLoadFlowResult> run(T network, LfNetworkLoader<T> networkLoader, AcLoadFlowParameters parameters, Reporter reporter) {
-        return LfNetwork.load(network, networkLoader, parameters.getNetworkParameters(), reporter)
-                .stream()
+    public static List<AcLoadFlowResult> run(List<LfNetwork> lfNetworks, AcLoadFlowParameters parameters) {
+        return lfNetworks.stream()
                 .map(n -> {
                     if (n.isValid()) {
                         try (AcLoadFlowContext context = new AcLoadFlowContext(n, parameters)) {
diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomatonOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomatonOuterLoop.java
index 720d6bf71a..3c730ed9c2 100644
--- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomatonOuterLoop.java
+++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomatonOuterLoop.java
@@ -7,15 +7,25 @@
 package com.powsybl.openloadflow.ac.outerloop;
 
 import com.powsybl.commons.reporter.Reporter;
+import com.powsybl.iidm.network.LimitType;
 import com.powsybl.openloadflow.ac.OuterLoop;
 import com.powsybl.openloadflow.ac.OuterLoopContext;
 import com.powsybl.openloadflow.ac.OuterLoopStatus;
+import com.powsybl.openloadflow.network.LfBranch;
+import com.powsybl.openloadflow.network.LfCurrentLimitAutomaton;
+import com.powsybl.openloadflow.util.PerUnit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
 
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
 public class AutomatonOuterLoop implements OuterLoop {
 
+    private static final Logger LOGGER = LoggerFactory.getLogger(AutomatonOuterLoop.class);
+
     @Override
     public String getType() {
         return "Automaton";
@@ -23,7 +33,29 @@ public String getType() {
 
     @Override
     public OuterLoopStatus check(OuterLoopContext context, Reporter reporter) {
-        // TODO
-        return OuterLoopStatus.STABLE;
+        OuterLoopStatus status = OuterLoopStatus.STABLE;
+        for (LfBranch branch : context.getNetwork().getBranches()) {
+            if (branch.getBus1() != null && branch.getBus2() != null) {
+                List<LfCurrentLimitAutomaton> currentLimitAutomata = branch.getCurrentLimitAutomata();
+                if (!currentLimitAutomata.isEmpty()) {
+                    double i1 = branch.getI1().eval();
+                    double limit = branch.getLimits1(LimitType.CURRENT).stream()
+                            .map(LfBranch.LfLimit::getValue)
+                            .min(Double::compare)
+                            .orElse(Double.MAX_VALUE);
+                    if (i1 > limit) {
+                        double ib = PerUnit.ib(branch.getBus1().getNominalV());
+                        for (LfCurrentLimitAutomaton cla : currentLimitAutomata) {
+                            LOGGER.debug("Current limit automaton of line '{}' activated ({} > {}), {} switch '{}'",
+                                    branch.getId(), i1 * ib, limit * ib, cla.isSwitchOpen() ? "open" : "close",
+                                    cla.getSwitchToOperate().getId());
+                            cla.getSwitchToOperate().setDisabled(cla.isSwitchOpen());
+                            status = OuterLoopStatus.UNSTABLE;
+                        }
+                    }
+                }
+            }
+        }
+        return status;
     }
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
index f0b8325df6..b68658dd4b 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
@@ -6,10 +6,10 @@
  */
 package com.powsybl.openloadflow.network.impl;
 
-import com.powsybl.commons.PowsyblException;
 import com.powsybl.commons.reporter.Reporter;
 import com.powsybl.iidm.network.*;
 import com.powsybl.openloadflow.network.*;
+import com.powsybl.openloadflow.network.extensions.CurrentLimitAutomaton;
 
 import java.util.*;
 
@@ -125,7 +125,9 @@ private static void restoreInitialTopology(LfNetwork network, Set<Switch> allSwi
         connectivity.startTemporaryChanges();
         allSwitchesToClose.stream().map(Identifiable::getId).forEach(id -> {
             LfBranch branch = network.getBranchById(id);
-            connectivity.removeEdge(branch);
+            if (branch != null) {
+                connectivity.removeEdge(branch);
+            }
         });
         Set<LfBus> removedBuses = connectivity.getVerticesRemovedFromMainComponent();
         removedBuses.forEach(bus -> bus.setDisabled(true));
@@ -137,14 +139,32 @@ private static void restoreInitialTopology(LfNetwork network, Set<Switch> allSwi
         removedBranches.forEach(branch -> branch.setDisabled(true));
     }
 
+    private static void addSwitchesOperatedByAutomata(Network network, LfNetworkParameters networkParameters,
+                                                      Set<Switch> allSwitchesToOpen, Set<Switch> allSwitchesToClose) {
+        if (networkParameters.isSimulateAutomatons()) {
+            for (Line line : network.getLines()) {
+                CurrentLimitAutomaton cla = line.getExtension(CurrentLimitAutomaton.class);
+                if (cla != null) {
+                    Switch aSwitch = network.getSwitch(cla.getSwitchId());
+                    if (aSwitch != null) {
+                        if (cla.isSwitchOpen()) {
+                            allSwitchesToOpen.add(aSwitch);
+                        } else {
+                            allSwitchesToClose.add(aSwitch);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     public static LfNetworkList load(Network network, LfNetworkParameters networkParameters,
                                      Set<Switch> switchesToOpen, Set<Switch> switchesToClose, Reporter reporter) {
-        if (switchesToOpen.isEmpty() && switchesToClose.isEmpty()) {
-            return new LfNetworkList(load(network, networkParameters, reporter));
-        } else {
-            if (!networkParameters.isBreakers()) {
-                throw new PowsyblException("LF networks have to be built from bus/breaker view");
-            }
+        Set<Switch> allSwitchesToOpen = new HashSet<>(switchesToOpen);
+        Set<Switch> allSwitchesToClose = new HashSet<>(switchesToClose);
+        addSwitchesOperatedByAutomata(network, networkParameters, allSwitchesToOpen, allSwitchesToClose);
+        networkParameters.setBreakers(!allSwitchesToOpen.isEmpty() || !allSwitchesToClose.isEmpty());
+        if (networkParameters.isBreakers()) {
             // create a temporary working variant to build LF networks
             String tmpVariantId = "olf-tmp-" + UUID.randomUUID();
             String workingVariantId = network.getVariantManager().getWorkingVariantId();
@@ -153,18 +173,20 @@ public static LfNetworkList load(Network network, LfNetworkParameters networkPar
 
             // retain in topology all switches that could be open or close
             // and close switches that could be closed during the simulation
-            retainAndCloseNecessarySwitches(network, switchesToOpen, switchesToClose);
+            retainAndCloseNecessarySwitches(network, allSwitchesToOpen, allSwitchesToClose);
 
             List<LfNetwork> lfNetworks = load(network, networkParameters, reporter);
 
-            if (!switchesToClose.isEmpty()) {
+            if (!allSwitchesToClose.isEmpty()) {
                 for (LfNetwork lfNetwork : lfNetworks) {
                     // disable all buses and branches not connected to main component (because of switch to close)
-                    restoreInitialTopology(lfNetwork, switchesToClose);
+                    restoreInitialTopology(lfNetwork, allSwitchesToClose);
                 }
             }
 
             return new LfNetworkList(lfNetworks, new LfNetworkList.VariantCleaner(network, workingVariantId, tmpVariantId));
+        } else {
+            return new LfNetworkList(load(network, networkParameters, reporter));
         }
     }
 

From 34c92a0a5dbdbd9f0146a6ec0263821df96afbcf Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Mon, 15 May 2023 21:22:42 +0200
Subject: [PATCH 04/30] Fix merge

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../com/powsybl/openloadflow/OpenLoadFlowProvider.java   | 9 ---------
 .../com/powsybl/openloadflow/network/impl/Networks.java  | 3 +++
 .../powsybl/openloadflow/OpenLoadFlowParametersTest.java | 2 +-
 .../powsybl/openloadflow/OpenLoadFlowProviderTest.java   | 6 +++---
 4 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
index cfb07425fd..6066ee4f3e 100644
--- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
+++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
@@ -24,20 +24,11 @@
 import com.powsybl.math.matrix.SparseMatrixFactory;
 import com.powsybl.openloadflow.ac.*;
 import com.powsybl.openloadflow.ac.nr.NewtonRaphsonStatus;
-import com.powsybl.openloadflow.ac.AcLoadFlowParameters;
-import com.powsybl.openloadflow.ac.AcLoadFlowResult;
-import com.powsybl.openloadflow.ac.AcloadFlowEngine;
-import com.powsybl.openloadflow.ac.OuterLoop;
-import com.powsybl.openloadflow.ac.nr.NewtonRaphsonStatus;
 import com.powsybl.openloadflow.dc.DcLoadFlowEngine;
 import com.powsybl.openloadflow.dc.DcLoadFlowResult;
 import com.powsybl.openloadflow.graph.EvenShiloachGraphDecrementalConnectivityFactory;
 import com.powsybl.openloadflow.graph.GraphConnectivityFactory;
 import com.powsybl.openloadflow.network.*;
-import com.powsybl.openloadflow.network.LfBranch;
-import com.powsybl.openloadflow.network.LfBus;
-import com.powsybl.openloadflow.network.LfNetwork;
-import com.powsybl.openloadflow.network.LfNetworkStateUpdateParameters;
 import com.powsybl.openloadflow.network.impl.LfNetworkList;
 import com.powsybl.openloadflow.network.impl.LfNetworkLoaderImpl;
 import com.powsybl.openloadflow.network.impl.Networks;
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
index 7dda2ff6ec..6c94179647 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
@@ -6,6 +6,7 @@
  */
 package com.powsybl.openloadflow.network.impl;
 
+import com.powsybl.commons.PowsyblException;
 import com.powsybl.commons.reporter.Reporter;
 import com.powsybl.iidm.network.*;
 import com.powsybl.openloadflow.network.*;
@@ -173,6 +174,8 @@ public static LfNetworkList load(Network network, LfNetworkParameters networkPar
                 throw new PowsyblException("LF networks have to be built from bus/breaker view");
             }
 
+            Set<Switch> allSwitchesToOpen = new LinkedHashSet<>(switchesToOpen);
+            Set<Switch> allSwitchesToClose = new LinkedHashSet<>(switchesToClose);
             addSwitchesOperatedByAutomata(network, networkParameters, allSwitchesToOpen, allSwitchesToClose);
 
             // create a temporary working variant to build LF networks
diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java
index bffdbdd641..bf2d60cedf 100644
--- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java
+++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java
@@ -316,7 +316,7 @@ void testCloneParameters() {
     @Test
     void testToString() {
         OpenLoadFlowParameters parameters = new OpenLoadFlowParameters();
-        assertEquals("OpenLoadFlowParameters(slackBusSelectionMode=MOST_MESHED, slackBusesIds=[], throwsExceptionInCaseOfSlackDistributionFailure=false, voltageRemoteControl=true, lowImpedanceBranchMode=REPLACE_BY_ZERO_IMPEDANCE_LINE, loadPowerFactorConstant=false, plausibleActivePowerLimit=5000.0, newtonRaphsonStoppingCriteriaType=UNIFORM_CRITERIA, slackBusPMaxMismatch=1.0, maxActivePowerMismatch=0.01, maxReactivePowerMismatch=0.01, maxVoltageMismatch=1.0E-4, maxAngleMismatch=1.0E-5, maxRatioMismatch=1.0E-5, maxSusceptanceMismatch=1.0E-4, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, maxNewtonRaphsonIterations=15, maxOuterLoopIterations=20, newtonRaphsonConvEpsPerEq=1.0E-4, voltageInitModeOverride=NONE, transformerVoltageControlMode=WITH_GENERATOR_VOLTAGE_CONTROL, shuntVoltageControlMode=WITH_GENERATOR_VOLTAGE_CONTROL, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, networkCacheEnabled=false, svcVoltageMonitoring=true, stateVectorScalingMode=NONE, maxSlackBusCount=1, debugDir=null, incrementalTransformerVoltageControlOuterLoopMaxTapShift=3, secondaryVoltageControl=false, reactiveLimitsMaxPqPvSwitch=3, phaseShifterControlMode=CONTINUOUS_WITH_DISCRETISATION, alwaysUpdateNetwork=false, mostMeshedSlackBusSelectorMaxNominalVoltagePercentile=95.0, reportedFeatures=[], slackBusCountryFilter=[], actionableSwitchesIds=[])",
+        assertEquals("OpenLoadFlowParameters(slackBusSelectionMode=MOST_MESHED, slackBusesIds=[], throwsExceptionInCaseOfSlackDistributionFailure=false, voltageRemoteControl=true, lowImpedanceBranchMode=REPLACE_BY_ZERO_IMPEDANCE_LINE, loadPowerFactorConstant=false, plausibleActivePowerLimit=5000.0, newtonRaphsonStoppingCriteriaType=UNIFORM_CRITERIA, slackBusPMaxMismatch=1.0, maxActivePowerMismatch=0.01, maxReactivePowerMismatch=0.01, maxVoltageMismatch=1.0E-4, maxAngleMismatch=1.0E-5, maxRatioMismatch=1.0E-5, maxSusceptanceMismatch=1.0E-4, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, maxNewtonRaphsonIterations=15, maxOuterLoopIterations=20, newtonRaphsonConvEpsPerEq=1.0E-4, voltageInitModeOverride=NONE, transformerVoltageControlMode=WITH_GENERATOR_VOLTAGE_CONTROL, shuntVoltageControlMode=WITH_GENERATOR_VOLTAGE_CONTROL, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, networkCacheEnabled=false, svcVoltageMonitoring=true, stateVectorScalingMode=NONE, maxSlackBusCount=1, debugDir=null, incrementalTransformerVoltageControlOuterLoopMaxTapShift=3, secondaryVoltageControl=false, reactiveLimitsMaxPqPvSwitch=3, phaseShifterControlMode=CONTINUOUS_WITH_DISCRETISATION, alwaysUpdateNetwork=false, mostMeshedSlackBusSelectorMaxNominalVoltagePercentile=95.0, reportedFeatures=[], slackBusCountryFilter=[], actionableSwitchesIds=[], simulateAutomaton=false)",
                      parameters.toString());
     }
 }
diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
index 7f0b43737f..44215b999c 100644
--- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
+++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
@@ -49,7 +49,7 @@ void test() {
     void testDcParameters() {
         Network network = Mockito.mock(Network.class);
         DcLoadFlowParameters dcParameters = OpenLoadFlowParameters.createDcParameters(network, new LoadFlowParameters().setReadSlackBus(true), new OpenLoadFlowParameters(), new DenseMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), true);
-        assertEquals("DcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=false, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=DC, reactiveLimits=false, hvdcAcEmulation=false, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=false, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false), equationSystemCreationParameters=DcEquationSystemCreationParameters(updateFlows=true, forcePhaseControlOffAndAddAngle1Var=true, useTransformerRatio=true), matrixFactory=DenseMatrixFactory, distributedSlack=true, balanceType=PROPORTIONAL_TO_GENERATION_P_MAX, setVToNan=true)",
+        assertEquals("DcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=false, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=DC, reactiveLimits=false, hvdcAcEmulation=false, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=false, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, simulateAutomatons=false), equationSystemCreationParameters=DcEquationSystemCreationParameters(updateFlows=true, forcePhaseControlOffAndAddAngle1Var=true, useTransformerRatio=true), matrixFactory=DenseMatrixFactory, distributedSlack=true, balanceType=PROPORTIONAL_TO_GENERATION_P_MAX, setVToNan=true)",
                      dcParameters.toString());
     }
 
@@ -57,7 +57,7 @@ void testDcParameters() {
     void testAcParameters() {
         Network network = Mockito.mock(Network.class);
         AcLoadFlowParameters acParameters = OpenLoadFlowParameters.createAcParameters(network, new LoadFlowParameters().setReadSlackBus(true), new OpenLoadFlowParameters(), new DenseMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), false, false);
-        assertEquals("AcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=true, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=AC, reactiveLimits=true, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=true, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false), equationSystemCreationParameters=AcEquationSystemCreationParameters(forceA1Var=false), newtonRaphsonParameters=NewtonRaphsonParameters(maxIterations=15, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, stoppingCriteria=DefaultNewtonRaphsonStoppingCriteria, stateVectorScalingMode=NONE, alwaysUpdateNetwork=false, detailedNrReport=false), outerLoops=[DistributedSlackOuterLoop, MonitoringVoltageOuterLoop, ReactiveLimitsOuterLoop], maxOuterLoopIterations=20, matrixFactory=DenseMatrixFactory, voltageInitializer=UniformValueVoltageInitializer)",
+        assertEquals("AcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=true, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=AC, reactiveLimits=true, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=true, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, simulateAutomatons=false), equationSystemCreationParameters=AcEquationSystemCreationParameters(forceA1Var=false), newtonRaphsonParameters=NewtonRaphsonParameters(maxIterations=15, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, stoppingCriteria=DefaultNewtonRaphsonStoppingCriteria, stateVectorScalingMode=NONE, alwaysUpdateNetwork=false, detailedNrReport=false), outerLoops=[DistributedSlackOuterLoop, MonitoringVoltageOuterLoop, ReactiveLimitsOuterLoop], maxOuterLoopIterations=20, matrixFactory=DenseMatrixFactory, voltageInitializer=UniformValueVoltageInitializer)",
                      acParameters.toString());
     }
 
@@ -85,7 +85,7 @@ void testGetExtendedVoltageInitializer() {
     @Test
     void specificParametersTest() {
         OpenLoadFlowProvider provider = new OpenLoadFlowProvider();
-        assertEquals(43, provider.getSpecificParameters().size());
+        assertEquals(45, provider.getSpecificParameters().size());
         LoadFlowParameters parameters = new LoadFlowParameters();
 
         provider.loadSpecificParameters(Collections.emptyMap())

From b72f94b6966f2661d8098ce13067b56539cccd68 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Sat, 20 May 2023 17:02:52 +0200
Subject: [PATCH 05/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../openloadflow/DefaultOuterLoopConfig.java  |  4 +-
 .../AutomationFunctionOuterLoop.java          | 55 ++++++++++++++
 .../ac/outerloop/AutomatonOuterLoop.java      | 61 ---------------
 .../openloadflow/network/LfBranch.java        |  2 -
 .../openloadflow/network/LfNetwork.java       | 10 +++
 ...java => LfOverloadManagementFunction.java} | 11 ++-
 .../CurrentLimitAutomatonAdderImpl.java       | 63 ----------------
 ...n.java => OverloadManagementFunction.java} | 12 +--
 .../OverloadManagementFunctionAdder.java      | 23 ++++++
 .../OverloadManagementFunctionAdderImpl.java  | 75 +++++++++++++++++++
 ...va => OverloadManagementFunctionImpl.java} | 16 ++--
 .../SubstationAutomationFunctions.java        | 29 +++++++
 ...> SubstationAutomationFunctionsAdder.java} |  9 +--
 ...ubstationAutomationFunctionsAdderImpl.java | 40 ++++++++++
 ...AutomationFunctionsAdderImplProvider.java} | 16 ++--
 .../SubstationAutomationFunctionsImpl.java    | 37 +++++++++
 .../network/impl/AbstractLfBranch.java        |  7 --
 .../network/impl/LfNetworkLoaderImpl.java     |  6 +-
 .../openloadflow/network/impl/Networks.java   |  4 +-
 19 files changed, 308 insertions(+), 172 deletions(-)
 create mode 100644 src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationFunctionOuterLoop.java
 delete mode 100644 src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomatonOuterLoop.java
 rename src/main/java/com/powsybl/openloadflow/network/{LfCurrentLimitAutomaton.java => LfOverloadManagementFunction.java} (69%)
 delete mode 100644 src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdderImpl.java
 rename src/main/java/com/powsybl/openloadflow/network/extensions/{CurrentLimitAutomaton.java => OverloadManagementFunction.java} (64%)
 create mode 100644 src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdder.java
 create mode 100644 src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdderImpl.java
 rename src/main/java/com/powsybl/openloadflow/network/extensions/{CurrentLimitAutomatonImpl.java => OverloadManagementFunctionImpl.java} (71%)
 create mode 100644 src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctions.java
 rename src/main/java/com/powsybl/openloadflow/network/extensions/{CurrentLimitAutomatonAdder.java => SubstationAutomationFunctionsAdder.java} (57%)
 create mode 100644 src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdderImpl.java
 rename src/main/java/com/powsybl/openloadflow/network/extensions/{CurrentLimitAutomatonAdderImplProvider.java => SubstationAutomationFunctionsAdderImplProvider.java} (57%)
 create mode 100644 src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsImpl.java

diff --git a/src/main/java/com/powsybl/openloadflow/DefaultOuterLoopConfig.java b/src/main/java/com/powsybl/openloadflow/DefaultOuterLoopConfig.java
index 568d479889..edbc4a9d92 100644
--- a/src/main/java/com/powsybl/openloadflow/DefaultOuterLoopConfig.java
+++ b/src/main/java/com/powsybl/openloadflow/DefaultOuterLoopConfig.java
@@ -85,9 +85,9 @@ public List<OuterLoop> configure(LoadFlowParameters parameters, OpenLoadFlowPara
         if (parameters.isShuntCompensatorVoltageControlOn()) {
             outerLoops.add(createShuntVoltageControlOuterLoop(parametersExt));
         }
-        // automatons
+        // automation functions
         if (parametersExt.isSimulateAutomatons()) {
-            outerLoops.add(new AutomatonOuterLoop());
+            outerLoops.add(new AutomationFunctionOuterLoop());
         }
         // secondary voltage control
         if (parametersExt.isSecondaryVoltageControl()) {
diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationFunctionOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationFunctionOuterLoop.java
new file mode 100644
index 0000000000..e90dd5ec18
--- /dev/null
+++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationFunctionOuterLoop.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.ac.outerloop;
+
+import com.powsybl.commons.reporter.Reporter;
+import com.powsybl.iidm.network.LimitType;
+import com.powsybl.openloadflow.ac.OuterLoop;
+import com.powsybl.openloadflow.ac.OuterLoopContext;
+import com.powsybl.openloadflow.ac.OuterLoopStatus;
+import com.powsybl.openloadflow.network.LfBranch;
+import com.powsybl.openloadflow.network.LfOverloadManagementFunction;
+import com.powsybl.openloadflow.util.PerUnit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+public class AutomationFunctionOuterLoop implements OuterLoop {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(AutomationFunctionOuterLoop.class);
+
+    @Override
+    public String getType() {
+        return "AutomationFunction";
+    }
+
+    @Override
+    public OuterLoopStatus check(OuterLoopContext context, Reporter reporter) {
+        OuterLoopStatus status = OuterLoopStatus.STABLE;
+        for (LfOverloadManagementFunction function : context.getNetwork().getOverloadManagementFunctions()) {
+            LfBranch branch = function.getBranchToMonitor();
+            if (branch.isConnectedAtBothSides()) {
+                double i1 = branch.getI1().eval();
+                double limit = branch.getLimits1(LimitType.CURRENT).stream()
+                        .map(LfBranch.LfLimit::getValue)
+                        .min(Double::compare)
+                        .orElse(Double.MAX_VALUE);
+                if (i1 > limit) {
+                    double ib = PerUnit.ib(branch.getBus1().getNominalV());
+                    LOGGER.debug("Line '{}' is overloaded ({} > {}), {} switch '{}'",
+                            branch.getId(), i1 * ib, limit * ib, function.isSwitchOpen() ? "open" : "close",
+                            function.getSwitchToOperate().getId());
+                    function.getSwitchToOperate().setDisabled(function.isSwitchOpen());
+                    status = OuterLoopStatus.UNSTABLE;
+                }
+            }
+        }
+        return status;
+    }
+}
diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomatonOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomatonOuterLoop.java
deleted file mode 100644
index 3c730ed9c2..0000000000
--- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomatonOuterLoop.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * Copyright (c) 2023, 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.openloadflow.ac.outerloop;
-
-import com.powsybl.commons.reporter.Reporter;
-import com.powsybl.iidm.network.LimitType;
-import com.powsybl.openloadflow.ac.OuterLoop;
-import com.powsybl.openloadflow.ac.OuterLoopContext;
-import com.powsybl.openloadflow.ac.OuterLoopStatus;
-import com.powsybl.openloadflow.network.LfBranch;
-import com.powsybl.openloadflow.network.LfCurrentLimitAutomaton;
-import com.powsybl.openloadflow.util.PerUnit;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
-
-/**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
- */
-public class AutomatonOuterLoop implements OuterLoop {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(AutomatonOuterLoop.class);
-
-    @Override
-    public String getType() {
-        return "Automaton";
-    }
-
-    @Override
-    public OuterLoopStatus check(OuterLoopContext context, Reporter reporter) {
-        OuterLoopStatus status = OuterLoopStatus.STABLE;
-        for (LfBranch branch : context.getNetwork().getBranches()) {
-            if (branch.getBus1() != null && branch.getBus2() != null) {
-                List<LfCurrentLimitAutomaton> currentLimitAutomata = branch.getCurrentLimitAutomata();
-                if (!currentLimitAutomata.isEmpty()) {
-                    double i1 = branch.getI1().eval();
-                    double limit = branch.getLimits1(LimitType.CURRENT).stream()
-                            .map(LfBranch.LfLimit::getValue)
-                            .min(Double::compare)
-                            .orElse(Double.MAX_VALUE);
-                    if (i1 > limit) {
-                        double ib = PerUnit.ib(branch.getBus1().getNominalV());
-                        for (LfCurrentLimitAutomaton cla : currentLimitAutomata) {
-                            LOGGER.debug("Current limit automaton of line '{}' activated ({} > {}), {} switch '{}'",
-                                    branch.getId(), i1 * ib, limit * ib, cla.isSwitchOpen() ? "open" : "close",
-                                    cla.getSwitchToOperate().getId());
-                            cla.getSwitchToOperate().setDisabled(cla.isSwitchOpen());
-                            status = OuterLoopStatus.UNSTABLE;
-                        }
-                    }
-                }
-            }
-        }
-        return status;
-    }
-}
diff --git a/src/main/java/com/powsybl/openloadflow/network/LfBranch.java b/src/main/java/com/powsybl/openloadflow/network/LfBranch.java
index b9cb8f9c2b..f1e951c66a 100644
--- a/src/main/java/com/powsybl/openloadflow/network/LfBranch.java
+++ b/src/main/java/com/powsybl/openloadflow/network/LfBranch.java
@@ -191,6 +191,4 @@ static double getDiscretePhaseControlTarget(LfBranch branch, TransformerPhaseCon
     boolean isConnectedAtBothSides();
 
     void setMinZ(double lowImpedanceThreshold);
-
-    List<LfCurrentLimitAutomaton> getCurrentLimitAutomata();
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java b/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java
index 8a00f8d4be..a849be150e 100644
--- a/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java
+++ b/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java
@@ -81,6 +81,8 @@ public class LfNetwork extends AbstractPropertyBag implements PropertyBag {
 
     private final List<LfSecondaryVoltageControl> secondaryVoltageControls = new ArrayList<>();
 
+    protected final List<LfOverloadManagementFunction> overloadManagementFunctions = new ArrayList<>();
+
     public LfNetwork(int numCC, int numSC, SlackBusSelector slackBusSelector, int maxSlackBusCount,
                      GraphConnectivityFactory<LfBus, LfBranch> connectivityFactory, Reporter reporter) {
         this.numCC = numCC;
@@ -654,6 +656,14 @@ public List<LfSecondaryVoltageControl> getSecondaryVoltageControls() {
         return secondaryVoltageControls;
     }
 
+    public void addOverloadManagementFunction(LfOverloadManagementFunction overloadManagementFunction) {
+        overloadManagementFunctions.add(Objects.requireNonNull(overloadManagementFunction));
+    }
+
+    public List<LfOverloadManagementFunction> getOverloadManagementFunctions() {
+        return overloadManagementFunctions;
+    }
+
     @Override
     public String toString() {
         return getId();
diff --git a/src/main/java/com/powsybl/openloadflow/network/LfCurrentLimitAutomaton.java b/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementFunction.java
similarity index 69%
rename from src/main/java/com/powsybl/openloadflow/network/LfCurrentLimitAutomaton.java
rename to src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementFunction.java
index 0e3728375f..173a41e026 100644
--- a/src/main/java/com/powsybl/openloadflow/network/LfCurrentLimitAutomaton.java
+++ b/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementFunction.java
@@ -13,17 +13,24 @@
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
-public class LfCurrentLimitAutomaton {
+public class LfOverloadManagementFunction {
+
+    private final LfBranch branchToMonitor;
 
     private final LfSwitch switchToOperate;
 
     private final boolean switchOpen;
 
-    public LfCurrentLimitAutomaton(LfSwitch switchToOperate, boolean switchOpen) {
+    public LfOverloadManagementFunction(LfBranch branchToMonitor, LfSwitch switchToOperate, boolean switchOpen) {
+        this.branchToMonitor = Objects.requireNonNull(branchToMonitor);
         this.switchToOperate = Objects.requireNonNull(switchToOperate);
         this.switchOpen = switchOpen;
     }
 
+    public LfBranch getBranchToMonitor() {
+        return branchToMonitor;
+    }
+
     public LfSwitch getSwitchToOperate() {
         return switchToOperate;
     }
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdderImpl.java b/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdderImpl.java
deleted file mode 100644
index ef57bb3ca0..0000000000
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdderImpl.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * Copyright (c) 2023, 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.openloadflow.network.extensions;
-
-import com.powsybl.commons.PowsyblException;
-import com.powsybl.commons.extensions.AbstractExtensionAdder;
-import com.powsybl.iidm.network.Line;
-
-import java.util.Objects;
-
-/**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
- */
-public class CurrentLimitAutomatonAdderImpl extends AbstractExtensionAdder<Line, CurrentLimitAutomaton> implements CurrentLimitAutomatonAdder {
-
-    private double threshold = Double.NaN;
-
-    private String switchId;
-
-    private boolean switchOpen = true;
-
-    public CurrentLimitAutomatonAdderImpl(Line line) {
-        super(line);
-    }
-
-    @Override
-    public Class<? super CurrentLimitAutomaton> getExtensionClass() {
-        return CurrentLimitAutomaton.class;
-    }
-
-    @Override
-    public CurrentLimitAutomatonAdderImpl withThreshold(double threshold) {
-        this.threshold = threshold;
-        return this;
-    }
-
-    @Override
-    public CurrentLimitAutomatonAdderImpl withSwitchId(String switchId) {
-        this.switchId = Objects.requireNonNull(switchId);
-        return this;
-    }
-
-    @Override
-    public CurrentLimitAutomatonAdderImpl withSwitchOpen(boolean open) {
-        this.switchOpen = open;
-        return this;
-    }
-
-    @Override
-    protected CurrentLimitAutomaton createExtension(Line line) {
-        if (Double.isNaN(threshold)) {
-            throw new PowsyblException("Threshold is not set");
-        }
-        if (switchId == null) {
-            throw new PowsyblException("Switch ID is not set");
-        }
-        return new CurrentLimitAutomatonImpl(line, threshold, switchId, switchOpen);
-    }
-}
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomaton.java b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunction.java
similarity index 64%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomaton.java
rename to src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunction.java
index 7da9eb0947..889f4a6572 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomaton.java
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunction.java
@@ -6,20 +6,12 @@
  */
 package com.powsybl.openloadflow.network.extensions;
 
-import com.powsybl.commons.extensions.Extension;
-import com.powsybl.iidm.network.Line;
-
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
-public interface CurrentLimitAutomaton extends Extension<Line> {
-
-    String NAME = "CurrentLimitAutomaton";
+public interface OverloadManagementFunction {
 
-    @Override
-    default String getName() {
-        return NAME;
-    }
+    String getLineId();
 
     double getThreshold();
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdder.java b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdder.java
new file mode 100644
index 0000000000..416f67212a
--- /dev/null
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdder.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.network.extensions;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+public interface OverloadManagementFunctionAdder<T> {
+
+    OverloadManagementFunctionAdder withLineId(String lineId);
+
+    OverloadManagementFunctionAdder withThreshold(double threshold);
+
+    OverloadManagementFunctionAdder withSwitchId(String switchId);
+
+    OverloadManagementFunctionAdder withSwitchOpen(boolean open);
+
+    T add();
+}
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdderImpl.java b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdderImpl.java
new file mode 100644
index 0000000000..ce6b89e34f
--- /dev/null
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdderImpl.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.network.extensions;
+
+import com.powsybl.commons.PowsyblException;
+
+import java.util.Objects;
+import java.util.function.Consumer;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+public class OverloadManagementFunctionAdderImpl<T> implements OverloadManagementFunctionAdder<T> {
+
+    private final T parent;
+
+    private final Consumer<OverloadManagementFunctionImpl> parentAdder;
+
+    public OverloadManagementFunctionAdderImpl(T parent, Consumer<OverloadManagementFunctionImpl> parentAdder) {
+        this.parent = Objects.requireNonNull(parent);
+        this.parentAdder = Objects.requireNonNull(parentAdder);
+    }
+
+    private String lineId;
+
+    private double threshold = Double.NaN;
+
+    private String switchId;
+
+    private boolean switchOpen = true;
+
+    @Override
+    public OverloadManagementFunctionAdderImpl<T> withLineId(String lineId) {
+        this.lineId = Objects.requireNonNull(lineId);
+        return this;
+    }
+
+    @Override
+    public OverloadManagementFunctionAdderImpl<T> withThreshold(double threshold) {
+        this.threshold = threshold;
+        return this;
+    }
+
+    @Override
+    public OverloadManagementFunctionAdderImpl<T> withSwitchId(String switchId) {
+        this.switchId = Objects.requireNonNull(switchId);
+        return this;
+    }
+
+    @Override
+    public OverloadManagementFunctionAdderImpl<T> withSwitchOpen(boolean open) {
+        this.switchOpen = open;
+        return this;
+    }
+
+    @Override
+    public T add() {
+        if (lineId == null) {
+            throw new PowsyblException("Line ID is not set");
+        }
+        if (Double.isNaN(threshold)) {
+            throw new PowsyblException("Threshold is not set");
+        }
+        if (switchId == null) {
+            throw new PowsyblException("Switch ID is not set");
+        }
+        OverloadManagementFunctionImpl function = new OverloadManagementFunctionImpl(lineId, threshold, switchId, switchOpen);
+        parentAdder.accept(function);
+        return parent;
+    }
+}
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonImpl.java b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionImpl.java
similarity index 71%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonImpl.java
rename to src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionImpl.java
index 7f68425139..5e5c8bcdbc 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionImpl.java
@@ -6,15 +6,14 @@
  */
 package com.powsybl.openloadflow.network.extensions;
 
-import com.powsybl.commons.extensions.AbstractExtension;
-import com.powsybl.iidm.network.Line;
-
 import java.util.Objects;
 
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
-public class CurrentLimitAutomatonImpl extends AbstractExtension<Line> implements CurrentLimitAutomaton {
+public class OverloadManagementFunctionImpl implements OverloadManagementFunction {
+
+    private final String lineId;
 
     private final double threshold;
 
@@ -22,13 +21,18 @@ public class CurrentLimitAutomatonImpl extends AbstractExtension<Line> implement
 
     private final boolean switchOpen;
 
-    public CurrentLimitAutomatonImpl(Line line, double threshold, String switchId, boolean switchOpen) {
-        super(line);
+    public OverloadManagementFunctionImpl(String lineId, double threshold, String switchId, boolean switchOpen) {
+        this.lineId = Objects.requireNonNull(lineId);
         this.threshold = threshold;
         this.switchId = Objects.requireNonNull(switchId);
         this.switchOpen = switchOpen;
     }
 
+    @Override
+    public String getLineId() {
+        return lineId;
+    }
+
     @Override
     public double getThreshold() {
         return threshold;
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctions.java b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctions.java
new file mode 100644
index 0000000000..59df278f49
--- /dev/null
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctions.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.network.extensions;
+
+import com.powsybl.commons.extensions.Extension;
+import com.powsybl.iidm.network.Substation;
+
+import java.util.List;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+public interface SubstationAutomationFunctions extends Extension<Substation> {
+
+    String NAME = "SubstationAutomationFunctions";
+
+    @Override
+    default String getName() {
+        return NAME;
+    }
+
+    List<OverloadManagementFunction> getOverloadManagementFunctions();
+
+    OverloadManagementFunctionAdder<SubstationAutomationFunctions> newOverloadManagementFunction();
+}
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdder.java b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdder.java
similarity index 57%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdder.java
rename to src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdder.java
index 09a92a46e5..d271a1b270 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdder.java
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdder.java
@@ -7,15 +7,12 @@
 package com.powsybl.openloadflow.network.extensions;
 
 import com.powsybl.commons.extensions.ExtensionAdder;
-import com.powsybl.iidm.network.Line;
+import com.powsybl.iidm.network.Substation;
 
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
-public interface CurrentLimitAutomatonAdder extends ExtensionAdder<Line, CurrentLimitAutomaton> {
-    CurrentLimitAutomatonAdderImpl withThreshold(double threshold);
+public interface SubstationAutomationFunctionsAdder extends ExtensionAdder<Substation, SubstationAutomationFunctions> {
 
-    CurrentLimitAutomatonAdderImpl withSwitchId(String switchId);
-
-    CurrentLimitAutomatonAdderImpl withSwitchOpen(boolean open);
+    OverloadManagementFunctionAdder<SubstationAutomationFunctionsAdder> newOverloadManagementFunction();
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdderImpl.java b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdderImpl.java
new file mode 100644
index 0000000000..cb3e99f27c
--- /dev/null
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdderImpl.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.network.extensions;
+
+import com.powsybl.commons.extensions.AbstractExtensionAdder;
+import com.powsybl.iidm.network.Substation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+public class SubstationAutomationFunctionsAdderImpl extends AbstractExtensionAdder<Substation, SubstationAutomationFunctions> implements SubstationAutomationFunctionsAdder {
+
+    private final List<OverloadManagementFunction> overloadManagementFunctions = new ArrayList<>();
+
+    public SubstationAutomationFunctionsAdderImpl(Substation substation) {
+        super(substation);
+    }
+
+    @Override
+    public Class<? super SubstationAutomationFunctions> getExtensionClass() {
+        return SubstationAutomationFunctions.class;
+    }
+
+    @Override
+    public OverloadManagementFunctionAdder<SubstationAutomationFunctionsAdder> newOverloadManagementFunction() {
+        return new OverloadManagementFunctionAdderImpl<>(this, overloadManagementFunctions::add);
+    }
+
+    @Override
+    protected SubstationAutomationFunctions createExtension(Substation substation) {
+        return new SubstationAutomationFunctionsImpl(substation, overloadManagementFunctions);
+    }
+}
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdderImplProvider.java b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdderImplProvider.java
similarity index 57%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdderImplProvider.java
rename to src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdderImplProvider.java
index 4b15eec60a..cc885857d2 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/CurrentLimitAutomatonAdderImplProvider.java
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdderImplProvider.java
@@ -9,14 +9,14 @@
 
 import com.google.auto.service.AutoService;
 import com.powsybl.commons.extensions.ExtensionAdderProvider;
-import com.powsybl.iidm.network.Line;
+import com.powsybl.iidm.network.Substation;
 
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
 @AutoService(ExtensionAdderProvider.class)
-public class CurrentLimitAutomatonAdderImplProvider implements
-        ExtensionAdderProvider<Line, CurrentLimitAutomaton, CurrentLimitAutomatonAdder> {
+public class SubstationAutomationFunctionsAdderImplProvider implements
+        ExtensionAdderProvider<Substation, SubstationAutomationFunctions, SubstationAutomationFunctionsAdder> {
 
     @Override
     public String getImplementationName() {
@@ -25,16 +25,16 @@ public String getImplementationName() {
 
     @Override
     public String getExtensionName() {
-        return CurrentLimitAutomaton.NAME;
+        return SubstationAutomationFunctions.NAME;
     }
 
     @Override
-    public Class<CurrentLimitAutomatonAdder> getAdderClass() {
-        return CurrentLimitAutomatonAdder.class;
+    public Class<SubstationAutomationFunctionsAdder> getAdderClass() {
+        return SubstationAutomationFunctionsAdder.class;
     }
 
     @Override
-    public CurrentLimitAutomatonAdder newAdder(Line line) {
-        return new CurrentLimitAutomatonAdderImpl(line);
+    public SubstationAutomationFunctionsAdder newAdder(Substation substation) {
+        return new SubstationAutomationFunctionsAdderImpl(substation);
     }
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsImpl.java b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsImpl.java
new file mode 100644
index 0000000000..95452149d1
--- /dev/null
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsImpl.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.network.extensions;
+
+import com.powsybl.commons.extensions.AbstractExtension;
+import com.powsybl.iidm.network.Substation;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+public class SubstationAutomationFunctionsImpl extends AbstractExtension<Substation> implements SubstationAutomationFunctions {
+
+    private final List<OverloadManagementFunction> overloadManagementFunctions;
+
+    public SubstationAutomationFunctionsImpl(Substation substation, List<OverloadManagementFunction> overloadManagementFunctions) {
+        super(substation);
+        this.overloadManagementFunctions = Objects.requireNonNull(overloadManagementFunctions);
+    }
+
+    @Override
+    public List<OverloadManagementFunction> getOverloadManagementFunctions() {
+        return Collections.unmodifiableList(overloadManagementFunctions);
+    }
+
+    @Override
+    public OverloadManagementFunctionAdder<SubstationAutomationFunctions> newOverloadManagementFunction() {
+        return new OverloadManagementFunctionAdderImpl<>(this, overloadManagementFunctions::add);
+    }
+}
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBranch.java b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBranch.java
index 26869aaae6..56eaa4b4ab 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBranch.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBranch.java
@@ -57,8 +57,6 @@ static class ZeroImpedanceContext {
 
     private ReactivePowerControl reactivePowerControl;
 
-    protected final List<LfCurrentLimitAutomaton> currentLimitAutomata = new ArrayList<>();
-
     protected AbstractLfBranch(LfNetwork network, LfBus bus1, LfBus bus2, PiModel piModel, LfNetworkParameters parameters) {
         super(network);
         this.bus1 = bus1;
@@ -330,9 +328,4 @@ public void setDisabled(boolean disabled) {
             }
         }
     }
-
-    @Override
-    public List<LfCurrentLimitAutomaton> getCurrentLimitAutomata() {
-        return currentLimitAutomata;
-    }
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
index d58d05c442..33a8b9a836 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
@@ -15,7 +15,7 @@
 import com.powsybl.iidm.network.extensions.SecondaryVoltageControl.ControlZone;
 import com.powsybl.iidm.network.extensions.SecondaryVoltageControl.PilotPoint;
 import com.powsybl.openloadflow.network.*;
-import com.powsybl.openloadflow.network.extensions.CurrentLimitAutomaton;
+import com.powsybl.openloadflow.network.extensions.OverloadManagementFunction;
 import com.powsybl.openloadflow.util.DebugUtil;
 import com.powsybl.openloadflow.util.PerUnit;
 import com.powsybl.openloadflow.util.Reports;
@@ -777,11 +777,11 @@ private void createAutomata(Network network, LfNetwork lfNetwork) {
         for (Line line : network.getLines()) {
             LfBranch lfLine = lfNetwork.getBranchById(line.getId());
             if (lfLine != null) {
-                CurrentLimitAutomaton cla = line.getExtension(CurrentLimitAutomaton.class);
+                OverloadManagementFunction cla = line.getExtension(OverloadManagementFunction.class);
                 if (cla != null) {
                     LfSwitch lfSwitch = (LfSwitch) lfNetwork.getBranchById(cla.getSwitchId());
                     if (lfSwitch != null) {
-                        lfLine.getCurrentLimitAutomata().add(new LfCurrentLimitAutomaton(lfSwitch, cla.isSwitchOpen()));
+                        lfNetwork.addOverloadManagementFunction(new LfOverloadManagementFunction(lfLine, lfSwitch, cla.isSwitchOpen()));
                     }
                 }
             }
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
index 6c94179647..a2ee351fc3 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
@@ -10,7 +10,7 @@
 import com.powsybl.commons.reporter.Reporter;
 import com.powsybl.iidm.network.*;
 import com.powsybl.openloadflow.network.*;
-import com.powsybl.openloadflow.network.extensions.CurrentLimitAutomaton;
+import com.powsybl.openloadflow.network.extensions.OverloadManagementFunction;
 
 import java.util.*;
 
@@ -144,7 +144,7 @@ private static void addSwitchesOperatedByAutomata(Network network, LfNetworkPara
                                                       Set<Switch> allSwitchesToOpen, Set<Switch> allSwitchesToClose) {
         if (networkParameters.isSimulateAutomatons()) {
             for (Line line : network.getLines()) {
-                CurrentLimitAutomaton cla = line.getExtension(CurrentLimitAutomaton.class);
+                OverloadManagementFunction cla = line.getExtension(OverloadManagementFunction.class);
                 if (cla != null) {
                     Switch aSwitch = network.getSwitch(cla.getSwitchId());
                     if (aSwitch != null) {

From ea20d1a2541d1ba4cdc083cdba89ea9df1ceb86e Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Sat, 20 May 2023 17:08:25 +0200
Subject: [PATCH 06/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../network/impl/LfNetworkLoaderImpl.java     | 23 +++++++++++--------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
index 33a8b9a836..f5edb3fcbd 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
@@ -16,6 +16,7 @@
 import com.powsybl.iidm.network.extensions.SecondaryVoltageControl.PilotPoint;
 import com.powsybl.openloadflow.network.*;
 import com.powsybl.openloadflow.network.extensions.OverloadManagementFunction;
+import com.powsybl.openloadflow.network.extensions.SubstationAutomationFunctions;
 import com.powsybl.openloadflow.util.DebugUtil;
 import com.powsybl.openloadflow.util.PerUnit;
 import com.powsybl.openloadflow.util.Reports;
@@ -667,7 +668,7 @@ private LfNetwork create(int numCC, int numSC, Network network, List<Bus> buses,
         createSecondaryVoltageControls(network, parameters, lfNetwork);
 
         if (parameters.isSimulateAutomatons()) {
-            createAutomata(network, lfNetwork);
+            createAutomationFunctions(network, lfNetwork);
         }
 
         if (report.generatorsDiscardedFromVoltageControlBecauseNotStarted > 0) {
@@ -773,15 +774,17 @@ private static Optional<Bus> findPilotBus(Network network, boolean breaker, List
         return Optional.empty();
     }
 
-    private void createAutomata(Network network, LfNetwork lfNetwork) {
-        for (Line line : network.getLines()) {
-            LfBranch lfLine = lfNetwork.getBranchById(line.getId());
-            if (lfLine != null) {
-                OverloadManagementFunction cla = line.getExtension(OverloadManagementFunction.class);
-                if (cla != null) {
-                    LfSwitch lfSwitch = (LfSwitch) lfNetwork.getBranchById(cla.getSwitchId());
-                    if (lfSwitch != null) {
-                        lfNetwork.addOverloadManagementFunction(new LfOverloadManagementFunction(lfLine, lfSwitch, cla.isSwitchOpen()));
+    private void createAutomationFunctions(Network network, LfNetwork lfNetwork) {
+        for (Substation substation : network.getSubstations()) {
+            SubstationAutomationFunctions functions = substation.getExtension(SubstationAutomationFunctions.class);
+            if (functions != null) {
+                for (OverloadManagementFunction function : functions.getOverloadManagementFunctions()) {
+                    LfBranch lfLine = lfNetwork.getBranchById(function.getLineId());
+                    if (lfLine != null) {
+                        LfSwitch lfSwitch = (LfSwitch) lfNetwork.getBranchById(function.getSwitchId());
+                        if (lfSwitch != null) {
+                            lfNetwork.addOverloadManagementFunction(new LfOverloadManagementFunction(lfLine, lfSwitch, function.isSwitchOpen()));
+                        }
                     }
                 }
             }

From 8a4289afeda7abdc55d4a50aa9447211f7956f83 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Sat, 20 May 2023 17:38:17 +0200
Subject: [PATCH 07/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../extensions/OverloadManagementFunctionAdder.java       | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdder.java b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdder.java
index 416f67212a..b9ed82b01f 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdder.java
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdder.java
@@ -11,13 +11,13 @@
  */
 public interface OverloadManagementFunctionAdder<T> {
 
-    OverloadManagementFunctionAdder withLineId(String lineId);
+    OverloadManagementFunctionAdder<T> withLineId(String lineId);
 
-    OverloadManagementFunctionAdder withThreshold(double threshold);
+    OverloadManagementFunctionAdder<T> withThreshold(double threshold);
 
-    OverloadManagementFunctionAdder withSwitchId(String switchId);
+    OverloadManagementFunctionAdder<T> withSwitchId(String switchId);
 
-    OverloadManagementFunctionAdder withSwitchOpen(boolean open);
+    OverloadManagementFunctionAdder<T> withSwitchOpen(boolean open);
 
     T add();
 }

From 47e6c63b95ab4eb233c4ebb92a9ac2cec3abf08f Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Sat, 20 May 2023 21:00:21 +0200
Subject: [PATCH 08/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../openloadflow/DefaultOuterLoopConfig.java  |  2 +-
 ...op.java => AutomationSystemOuterLoop.java} |  8 ++--
 .../openloadflow/network/LfNetwork.java       | 10 ++---
 ...n.java => LfOverloadManagementSystem.java} |  4 +-
 ...ion.java => OverloadManagementSystem.java} |  2 +-
 ...ava => OverloadManagementSystemAdder.java} | 10 ++---
 ...=> OverloadManagementSystemAdderImpl.java} | 18 ++++----
 ...java => OverloadManagementSystemImpl.java} |  4 +-
 ...ubstationAutomationFunctionsAdderImpl.java | 40 -----------------
 .../SubstationAutomationFunctionsImpl.java    | 37 ----------------
 ....java => SubstationAutomationSystems.java} |  8 ++--
 ... => SubstationAutomationSystemsAdder.java} |  4 +-
 .../SubstationAutomationSystemsAdderImpl.java | 40 +++++++++++++++++
 ...onAutomationSystemsAdderImplProvider.java} | 14 +++---
 .../SubstationAutomationSystemsImpl.java      | 37 ++++++++++++++++
 .../network/impl/LfNetworkLoaderImpl.java     | 10 ++---
 .../openloadflow/network/impl/Networks.java   |  4 +-
 .../openloadflow/ac/AutomationSystemTest.java | 43 +++++++++++++++++++
 18 files changed, 169 insertions(+), 126 deletions(-)
 rename src/main/java/com/powsybl/openloadflow/ac/outerloop/{AutomationFunctionOuterLoop.java => AutomationSystemOuterLoop.java} (88%)
 rename src/main/java/com/powsybl/openloadflow/network/{LfOverloadManagementFunction.java => LfOverloadManagementSystem.java} (86%)
 rename src/main/java/com/powsybl/openloadflow/network/extensions/{OverloadManagementFunction.java => OverloadManagementSystem.java} (91%)
 rename src/main/java/com/powsybl/openloadflow/network/extensions/{OverloadManagementFunctionAdder.java => OverloadManagementSystemAdder.java} (55%)
 rename src/main/java/com/powsybl/openloadflow/network/extensions/{OverloadManagementFunctionAdderImpl.java => OverloadManagementSystemAdderImpl.java} (66%)
 rename src/main/java/com/powsybl/openloadflow/network/extensions/{OverloadManagementFunctionImpl.java => OverloadManagementSystemImpl.java} (84%)
 delete mode 100644 src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdderImpl.java
 delete mode 100644 src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsImpl.java
 rename src/main/java/com/powsybl/openloadflow/network/extensions/{SubstationAutomationFunctions.java => SubstationAutomationSystems.java} (66%)
 rename src/main/java/com/powsybl/openloadflow/network/extensions/{SubstationAutomationFunctionsAdder.java => SubstationAutomationSystemsAdder.java} (69%)
 create mode 100644 src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdderImpl.java
 rename src/main/java/com/powsybl/openloadflow/network/extensions/{SubstationAutomationFunctionsAdderImplProvider.java => SubstationAutomationSystemsAdderImplProvider.java} (60%)
 create mode 100644 src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsImpl.java
 create mode 100644 src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java

diff --git a/src/main/java/com/powsybl/openloadflow/DefaultOuterLoopConfig.java b/src/main/java/com/powsybl/openloadflow/DefaultOuterLoopConfig.java
index edbc4a9d92..c6200fdb9b 100644
--- a/src/main/java/com/powsybl/openloadflow/DefaultOuterLoopConfig.java
+++ b/src/main/java/com/powsybl/openloadflow/DefaultOuterLoopConfig.java
@@ -87,7 +87,7 @@ public List<OuterLoop> configure(LoadFlowParameters parameters, OpenLoadFlowPara
         }
         // automation functions
         if (parametersExt.isSimulateAutomatons()) {
-            outerLoops.add(new AutomationFunctionOuterLoop());
+            outerLoops.add(new AutomationSystemOuterLoop());
         }
         // secondary voltage control
         if (parametersExt.isSecondaryVoltageControl()) {
diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationFunctionOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
similarity index 88%
rename from src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationFunctionOuterLoop.java
rename to src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
index e90dd5ec18..8965ef510a 100644
--- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationFunctionOuterLoop.java
+++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
@@ -12,7 +12,7 @@
 import com.powsybl.openloadflow.ac.OuterLoopContext;
 import com.powsybl.openloadflow.ac.OuterLoopStatus;
 import com.powsybl.openloadflow.network.LfBranch;
-import com.powsybl.openloadflow.network.LfOverloadManagementFunction;
+import com.powsybl.openloadflow.network.LfOverloadManagementSystem;
 import com.powsybl.openloadflow.util.PerUnit;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -20,9 +20,9 @@
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
-public class AutomationFunctionOuterLoop implements OuterLoop {
+public class AutomationSystemOuterLoop implements OuterLoop {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(AutomationFunctionOuterLoop.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(AutomationSystemOuterLoop.class);
 
     @Override
     public String getType() {
@@ -32,7 +32,7 @@ public String getType() {
     @Override
     public OuterLoopStatus check(OuterLoopContext context, Reporter reporter) {
         OuterLoopStatus status = OuterLoopStatus.STABLE;
-        for (LfOverloadManagementFunction function : context.getNetwork().getOverloadManagementFunctions()) {
+        for (LfOverloadManagementSystem function : context.getNetwork().getOverloadManagementSystems()) {
             LfBranch branch = function.getBranchToMonitor();
             if (branch.isConnectedAtBothSides()) {
                 double i1 = branch.getI1().eval();
diff --git a/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java b/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java
index a849be150e..8596a009a2 100644
--- a/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java
+++ b/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java
@@ -81,7 +81,7 @@ public class LfNetwork extends AbstractPropertyBag implements PropertyBag {
 
     private final List<LfSecondaryVoltageControl> secondaryVoltageControls = new ArrayList<>();
 
-    protected final List<LfOverloadManagementFunction> overloadManagementFunctions = new ArrayList<>();
+    protected final List<LfOverloadManagementSystem> overloadManagementSystems = new ArrayList<>();
 
     public LfNetwork(int numCC, int numSC, SlackBusSelector slackBusSelector, int maxSlackBusCount,
                      GraphConnectivityFactory<LfBus, LfBranch> connectivityFactory, Reporter reporter) {
@@ -656,12 +656,12 @@ public List<LfSecondaryVoltageControl> getSecondaryVoltageControls() {
         return secondaryVoltageControls;
     }
 
-    public void addOverloadManagementFunction(LfOverloadManagementFunction overloadManagementFunction) {
-        overloadManagementFunctions.add(Objects.requireNonNull(overloadManagementFunction));
+    public void addOverloadManagementSystem(LfOverloadManagementSystem overloadManagementSystem) {
+        overloadManagementSystems.add(Objects.requireNonNull(overloadManagementSystem));
     }
 
-    public List<LfOverloadManagementFunction> getOverloadManagementFunctions() {
-        return overloadManagementFunctions;
+    public List<LfOverloadManagementSystem> getOverloadManagementSystems() {
+        return overloadManagementSystems;
     }
 
     @Override
diff --git a/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementFunction.java b/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementSystem.java
similarity index 86%
rename from src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementFunction.java
rename to src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementSystem.java
index 173a41e026..66161e83c9 100644
--- a/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementFunction.java
+++ b/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementSystem.java
@@ -13,7 +13,7 @@
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
-public class LfOverloadManagementFunction {
+public class LfOverloadManagementSystem {
 
     private final LfBranch branchToMonitor;
 
@@ -21,7 +21,7 @@ public class LfOverloadManagementFunction {
 
     private final boolean switchOpen;
 
-    public LfOverloadManagementFunction(LfBranch branchToMonitor, LfSwitch switchToOperate, boolean switchOpen) {
+    public LfOverloadManagementSystem(LfBranch branchToMonitor, LfSwitch switchToOperate, boolean switchOpen) {
         this.branchToMonitor = Objects.requireNonNull(branchToMonitor);
         this.switchToOperate = Objects.requireNonNull(switchToOperate);
         this.switchOpen = switchOpen;
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunction.java b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystem.java
similarity index 91%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunction.java
rename to src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystem.java
index 889f4a6572..060dd7d896 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunction.java
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystem.java
@@ -9,7 +9,7 @@
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
-public interface OverloadManagementFunction {
+public interface OverloadManagementSystem {
 
     String getLineId();
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdder.java b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdder.java
similarity index 55%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdder.java
rename to src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdder.java
index b9ed82b01f..abf101e644 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdder.java
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdder.java
@@ -9,15 +9,15 @@
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
-public interface OverloadManagementFunctionAdder<T> {
+public interface OverloadManagementSystemAdder<T> {
 
-    OverloadManagementFunctionAdder<T> withLineId(String lineId);
+    OverloadManagementSystemAdder<T> withLineId(String lineId);
 
-    OverloadManagementFunctionAdder<T> withThreshold(double threshold);
+    OverloadManagementSystemAdder<T> withThreshold(double threshold);
 
-    OverloadManagementFunctionAdder<T> withSwitchId(String switchId);
+    OverloadManagementSystemAdder<T> withSwitchId(String switchId);
 
-    OverloadManagementFunctionAdder<T> withSwitchOpen(boolean open);
+    OverloadManagementSystemAdder<T> withSwitchOpen(boolean open);
 
     T add();
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdderImpl.java b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdderImpl.java
similarity index 66%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdderImpl.java
rename to src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdderImpl.java
index ce6b89e34f..0f022b70b1 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionAdderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdderImpl.java
@@ -14,13 +14,13 @@
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
-public class OverloadManagementFunctionAdderImpl<T> implements OverloadManagementFunctionAdder<T> {
+public class OverloadManagementSystemAdderImpl<T> implements OverloadManagementSystemAdder<T> {
 
     private final T parent;
 
-    private final Consumer<OverloadManagementFunctionImpl> parentAdder;
+    private final Consumer<OverloadManagementSystemImpl> parentAdder;
 
-    public OverloadManagementFunctionAdderImpl(T parent, Consumer<OverloadManagementFunctionImpl> parentAdder) {
+    public OverloadManagementSystemAdderImpl(T parent, Consumer<OverloadManagementSystemImpl> parentAdder) {
         this.parent = Objects.requireNonNull(parent);
         this.parentAdder = Objects.requireNonNull(parentAdder);
     }
@@ -34,25 +34,25 @@ public OverloadManagementFunctionAdderImpl(T parent, Consumer<OverloadManagement
     private boolean switchOpen = true;
 
     @Override
-    public OverloadManagementFunctionAdderImpl<T> withLineId(String lineId) {
+    public OverloadManagementSystemAdderImpl<T> withLineId(String lineId) {
         this.lineId = Objects.requireNonNull(lineId);
         return this;
     }
 
     @Override
-    public OverloadManagementFunctionAdderImpl<T> withThreshold(double threshold) {
+    public OverloadManagementSystemAdderImpl<T> withThreshold(double threshold) {
         this.threshold = threshold;
         return this;
     }
 
     @Override
-    public OverloadManagementFunctionAdderImpl<T> withSwitchId(String switchId) {
+    public OverloadManagementSystemAdderImpl<T> withSwitchId(String switchId) {
         this.switchId = Objects.requireNonNull(switchId);
         return this;
     }
 
     @Override
-    public OverloadManagementFunctionAdderImpl<T> withSwitchOpen(boolean open) {
+    public OverloadManagementSystemAdderImpl<T> withSwitchOpen(boolean open) {
         this.switchOpen = open;
         return this;
     }
@@ -68,8 +68,8 @@ public T add() {
         if (switchId == null) {
             throw new PowsyblException("Switch ID is not set");
         }
-        OverloadManagementFunctionImpl function = new OverloadManagementFunctionImpl(lineId, threshold, switchId, switchOpen);
-        parentAdder.accept(function);
+        OverloadManagementSystemImpl system = new OverloadManagementSystemImpl(lineId, threshold, switchId, switchOpen);
+        parentAdder.accept(system);
         return parent;
     }
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionImpl.java b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemImpl.java
similarity index 84%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionImpl.java
rename to src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemImpl.java
index 5e5c8bcdbc..407f8d1820 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementFunctionImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemImpl.java
@@ -11,7 +11,7 @@
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
-public class OverloadManagementFunctionImpl implements OverloadManagementFunction {
+public class OverloadManagementSystemImpl implements OverloadManagementSystem {
 
     private final String lineId;
 
@@ -21,7 +21,7 @@ public class OverloadManagementFunctionImpl implements OverloadManagementFunctio
 
     private final boolean switchOpen;
 
-    public OverloadManagementFunctionImpl(String lineId, double threshold, String switchId, boolean switchOpen) {
+    public OverloadManagementSystemImpl(String lineId, double threshold, String switchId, boolean switchOpen) {
         this.lineId = Objects.requireNonNull(lineId);
         this.threshold = threshold;
         this.switchId = Objects.requireNonNull(switchId);
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdderImpl.java b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdderImpl.java
deleted file mode 100644
index cb3e99f27c..0000000000
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdderImpl.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * Copyright (c) 2023, 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.openloadflow.network.extensions;
-
-import com.powsybl.commons.extensions.AbstractExtensionAdder;
-import com.powsybl.iidm.network.Substation;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
- */
-public class SubstationAutomationFunctionsAdderImpl extends AbstractExtensionAdder<Substation, SubstationAutomationFunctions> implements SubstationAutomationFunctionsAdder {
-
-    private final List<OverloadManagementFunction> overloadManagementFunctions = new ArrayList<>();
-
-    public SubstationAutomationFunctionsAdderImpl(Substation substation) {
-        super(substation);
-    }
-
-    @Override
-    public Class<? super SubstationAutomationFunctions> getExtensionClass() {
-        return SubstationAutomationFunctions.class;
-    }
-
-    @Override
-    public OverloadManagementFunctionAdder<SubstationAutomationFunctionsAdder> newOverloadManagementFunction() {
-        return new OverloadManagementFunctionAdderImpl<>(this, overloadManagementFunctions::add);
-    }
-
-    @Override
-    protected SubstationAutomationFunctions createExtension(Substation substation) {
-        return new SubstationAutomationFunctionsImpl(substation, overloadManagementFunctions);
-    }
-}
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsImpl.java b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsImpl.java
deleted file mode 100644
index 95452149d1..0000000000
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsImpl.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Copyright (c) 2023, 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.openloadflow.network.extensions;
-
-import com.powsybl.commons.extensions.AbstractExtension;
-import com.powsybl.iidm.network.Substation;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
- */
-public class SubstationAutomationFunctionsImpl extends AbstractExtension<Substation> implements SubstationAutomationFunctions {
-
-    private final List<OverloadManagementFunction> overloadManagementFunctions;
-
-    public SubstationAutomationFunctionsImpl(Substation substation, List<OverloadManagementFunction> overloadManagementFunctions) {
-        super(substation);
-        this.overloadManagementFunctions = Objects.requireNonNull(overloadManagementFunctions);
-    }
-
-    @Override
-    public List<OverloadManagementFunction> getOverloadManagementFunctions() {
-        return Collections.unmodifiableList(overloadManagementFunctions);
-    }
-
-    @Override
-    public OverloadManagementFunctionAdder<SubstationAutomationFunctions> newOverloadManagementFunction() {
-        return new OverloadManagementFunctionAdderImpl<>(this, overloadManagementFunctions::add);
-    }
-}
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctions.java b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystems.java
similarity index 66%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctions.java
rename to src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystems.java
index 59df278f49..cd3e1df239 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctions.java
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystems.java
@@ -14,16 +14,16 @@
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
-public interface SubstationAutomationFunctions extends Extension<Substation> {
+public interface SubstationAutomationSystems extends Extension<Substation> {
 
-    String NAME = "SubstationAutomationFunctions";
+    String NAME = "SubstationAutomationSystems";
 
     @Override
     default String getName() {
         return NAME;
     }
 
-    List<OverloadManagementFunction> getOverloadManagementFunctions();
+    List<OverloadManagementSystem> getOverloadManagementSystems();
 
-    OverloadManagementFunctionAdder<SubstationAutomationFunctions> newOverloadManagementFunction();
+    OverloadManagementSystemAdder<SubstationAutomationSystems> newOverloadManagementSystem();
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdder.java b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdder.java
similarity index 69%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdder.java
rename to src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdder.java
index d271a1b270..8a487d2fbf 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdder.java
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdder.java
@@ -12,7 +12,7 @@
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
-public interface SubstationAutomationFunctionsAdder extends ExtensionAdder<Substation, SubstationAutomationFunctions> {
+public interface SubstationAutomationSystemsAdder extends ExtensionAdder<Substation, SubstationAutomationSystems> {
 
-    OverloadManagementFunctionAdder<SubstationAutomationFunctionsAdder> newOverloadManagementFunction();
+    OverloadManagementSystemAdder<SubstationAutomationSystemsAdder> newOverloadManagementSystem();
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdderImpl.java b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdderImpl.java
new file mode 100644
index 0000000000..742d117e74
--- /dev/null
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdderImpl.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.network.extensions;
+
+import com.powsybl.commons.extensions.AbstractExtensionAdder;
+import com.powsybl.iidm.network.Substation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+public class SubstationAutomationSystemsAdderImpl extends AbstractExtensionAdder<Substation, SubstationAutomationSystems> implements SubstationAutomationSystemsAdder {
+
+    private final List<OverloadManagementSystem> overloadManagementSystems = new ArrayList<>();
+
+    public SubstationAutomationSystemsAdderImpl(Substation substation) {
+        super(substation);
+    }
+
+    @Override
+    public Class<? super SubstationAutomationSystems> getExtensionClass() {
+        return SubstationAutomationSystems.class;
+    }
+
+    @Override
+    public OverloadManagementSystemAdder<SubstationAutomationSystemsAdder> newOverloadManagementSystem() {
+        return new OverloadManagementSystemAdderImpl<>(this, overloadManagementSystems::add);
+    }
+
+    @Override
+    protected SubstationAutomationSystems createExtension(Substation substation) {
+        return new SubstationAutomationSystemsImpl(substation, overloadManagementSystems);
+    }
+}
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdderImplProvider.java b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdderImplProvider.java
similarity index 60%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdderImplProvider.java
rename to src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdderImplProvider.java
index cc885857d2..b6aeba37f4 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationFunctionsAdderImplProvider.java
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdderImplProvider.java
@@ -15,8 +15,8 @@
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
 @AutoService(ExtensionAdderProvider.class)
-public class SubstationAutomationFunctionsAdderImplProvider implements
-        ExtensionAdderProvider<Substation, SubstationAutomationFunctions, SubstationAutomationFunctionsAdder> {
+public class SubstationAutomationSystemsAdderImplProvider implements
+        ExtensionAdderProvider<Substation, SubstationAutomationSystems, SubstationAutomationSystemsAdder> {
 
     @Override
     public String getImplementationName() {
@@ -25,16 +25,16 @@ public String getImplementationName() {
 
     @Override
     public String getExtensionName() {
-        return SubstationAutomationFunctions.NAME;
+        return SubstationAutomationSystems.NAME;
     }
 
     @Override
-    public Class<SubstationAutomationFunctionsAdder> getAdderClass() {
-        return SubstationAutomationFunctionsAdder.class;
+    public Class<SubstationAutomationSystemsAdder> getAdderClass() {
+        return SubstationAutomationSystemsAdder.class;
     }
 
     @Override
-    public SubstationAutomationFunctionsAdder newAdder(Substation substation) {
-        return new SubstationAutomationFunctionsAdderImpl(substation);
+    public SubstationAutomationSystemsAdder newAdder(Substation substation) {
+        return new SubstationAutomationSystemsAdderImpl(substation);
     }
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsImpl.java b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsImpl.java
new file mode 100644
index 0000000000..a377d9566d
--- /dev/null
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsImpl.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.network.extensions;
+
+import com.powsybl.commons.extensions.AbstractExtension;
+import com.powsybl.iidm.network.Substation;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+public class SubstationAutomationSystemsImpl extends AbstractExtension<Substation> implements SubstationAutomationSystems {
+
+    private final List<OverloadManagementSystem> overloadManagementSystems;
+
+    public SubstationAutomationSystemsImpl(Substation substation, List<OverloadManagementSystem> overloadManagementSystems) {
+        super(substation);
+        this.overloadManagementSystems = Objects.requireNonNull(overloadManagementSystems);
+    }
+
+    @Override
+    public List<OverloadManagementSystem> getOverloadManagementSystems() {
+        return Collections.unmodifiableList(overloadManagementSystems);
+    }
+
+    @Override
+    public OverloadManagementSystemAdder<SubstationAutomationSystems> newOverloadManagementSystem() {
+        return new OverloadManagementSystemAdderImpl<>(this, overloadManagementSystems::add);
+    }
+}
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
index f5edb3fcbd..b3f8045652 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
@@ -15,8 +15,8 @@
 import com.powsybl.iidm.network.extensions.SecondaryVoltageControl.ControlZone;
 import com.powsybl.iidm.network.extensions.SecondaryVoltageControl.PilotPoint;
 import com.powsybl.openloadflow.network.*;
-import com.powsybl.openloadflow.network.extensions.OverloadManagementFunction;
-import com.powsybl.openloadflow.network.extensions.SubstationAutomationFunctions;
+import com.powsybl.openloadflow.network.extensions.OverloadManagementSystem;
+import com.powsybl.openloadflow.network.extensions.SubstationAutomationSystems;
 import com.powsybl.openloadflow.util.DebugUtil;
 import com.powsybl.openloadflow.util.PerUnit;
 import com.powsybl.openloadflow.util.Reports;
@@ -776,14 +776,14 @@ private static Optional<Bus> findPilotBus(Network network, boolean breaker, List
 
     private void createAutomationFunctions(Network network, LfNetwork lfNetwork) {
         for (Substation substation : network.getSubstations()) {
-            SubstationAutomationFunctions functions = substation.getExtension(SubstationAutomationFunctions.class);
+            SubstationAutomationSystems functions = substation.getExtension(SubstationAutomationSystems.class);
             if (functions != null) {
-                for (OverloadManagementFunction function : functions.getOverloadManagementFunctions()) {
+                for (OverloadManagementSystem function : functions.getOverloadManagementSystems()) {
                     LfBranch lfLine = lfNetwork.getBranchById(function.getLineId());
                     if (lfLine != null) {
                         LfSwitch lfSwitch = (LfSwitch) lfNetwork.getBranchById(function.getSwitchId());
                         if (lfSwitch != null) {
-                            lfNetwork.addOverloadManagementFunction(new LfOverloadManagementFunction(lfLine, lfSwitch, function.isSwitchOpen()));
+                            lfNetwork.addOverloadManagementSystem(new LfOverloadManagementSystem(lfLine, lfSwitch, function.isSwitchOpen()));
                         }
                     }
                 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
index a2ee351fc3..832497502f 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
@@ -10,7 +10,7 @@
 import com.powsybl.commons.reporter.Reporter;
 import com.powsybl.iidm.network.*;
 import com.powsybl.openloadflow.network.*;
-import com.powsybl.openloadflow.network.extensions.OverloadManagementFunction;
+import com.powsybl.openloadflow.network.extensions.OverloadManagementSystem;
 
 import java.util.*;
 
@@ -144,7 +144,7 @@ private static void addSwitchesOperatedByAutomata(Network network, LfNetworkPara
                                                       Set<Switch> allSwitchesToOpen, Set<Switch> allSwitchesToClose) {
         if (networkParameters.isSimulateAutomatons()) {
             for (Line line : network.getLines()) {
-                OverloadManagementFunction cla = line.getExtension(OverloadManagementFunction.class);
+                OverloadManagementSystem cla = line.getExtension(OverloadManagementSystem.class);
                 if (cla != null) {
                     Switch aSwitch = network.getSwitch(cla.getSwitchId());
                     if (aSwitch != null) {
diff --git a/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java b/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
new file mode 100644
index 0000000000..e69311716c
--- /dev/null
+++ b/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.ac;
+
+import com.powsybl.ieeecdf.converter.IeeeCdfNetworkFactory;
+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.math.matrix.DenseMatrixFactory;
+import com.powsybl.openloadflow.OpenLoadFlowParameters;
+import com.powsybl.openloadflow.OpenLoadFlowProvider;
+import com.powsybl.openloadflow.network.extensions.SubstationAutomationSystemsAdder;
+import org.junit.jupiter.api.Test;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+class AutomationSystemTest {
+
+    @Test
+    void test() {
+        Network network = IeeeCdfNetworkFactory.create14();
+        LoadFlow.Runner loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(new DenseMatrixFactory()));
+        LoadFlowParameters parameters = new LoadFlowParameters();
+        OpenLoadFlowParameters.create(parameters)
+                .setSimulateAutomatons(true);
+        Substation s1 = network.getSubstation("S1");
+        s1.newExtension(SubstationAutomationSystemsAdder.class)
+                .newOverloadManagementSystem()
+                    .withLineId("")
+                    .withThreshold(100)
+                    .withSwitchId("")
+                    .withSwitchOpen(true)
+                .add()
+            .add();
+        loadFlowRunner.run(network, parameters);
+    }
+}

From 6ac754294160c0390312f3ad739dbef81b966a3f Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Sat, 20 May 2023 21:05:29 +0200
Subject: [PATCH 09/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../extensions/OverloadManagementSystem.java  |  4 ++--
 .../OverloadManagementSystemAdder.java        |  4 ++--
 .../OverloadManagementSystemAdderImpl.java    | 22 +++++++++----------
 .../OverloadManagementSystemImpl.java         | 18 +++++++--------
 .../network/impl/LfNetworkLoaderImpl.java     |  4 ++--
 .../openloadflow/network/impl/Networks.java   |  2 +-
 .../openloadflow/ac/AutomationSystemTest.java |  4 ++--
 7 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystem.java b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystem.java
index 060dd7d896..fa937bc42f 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystem.java
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystem.java
@@ -11,11 +11,11 @@
  */
 public interface OverloadManagementSystem {
 
-    String getLineId();
+    String getLineIdToMonitor();
 
     double getThreshold();
 
-    String getSwitchId();
+    String getSwitchIdToOperate();
 
     boolean isSwitchOpen();
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdder.java b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdder.java
index abf101e644..5133c303e6 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdder.java
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdder.java
@@ -11,11 +11,11 @@
  */
 public interface OverloadManagementSystemAdder<T> {
 
-    OverloadManagementSystemAdder<T> withLineId(String lineId);
+    OverloadManagementSystemAdder<T> withLineIdToMonitor(String lineId);
 
     OverloadManagementSystemAdder<T> withThreshold(double threshold);
 
-    OverloadManagementSystemAdder<T> withSwitchId(String switchId);
+    OverloadManagementSystemAdder<T> withSwitchIdToOperate(String switchId);
 
     OverloadManagementSystemAdder<T> withSwitchOpen(boolean open);
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdderImpl.java b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdderImpl.java
index 0f022b70b1..0ba096569e 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdderImpl.java
@@ -25,17 +25,17 @@ public OverloadManagementSystemAdderImpl(T parent, Consumer<OverloadManagementSy
         this.parentAdder = Objects.requireNonNull(parentAdder);
     }
 
-    private String lineId;
+    private String lineIdToMonitor;
 
     private double threshold = Double.NaN;
 
-    private String switchId;
+    private String switchIdToOperate;
 
     private boolean switchOpen = true;
 
     @Override
-    public OverloadManagementSystemAdderImpl<T> withLineId(String lineId) {
-        this.lineId = Objects.requireNonNull(lineId);
+    public OverloadManagementSystemAdderImpl<T> withLineIdToMonitor(String lineIdToMonitor) {
+        this.lineIdToMonitor = Objects.requireNonNull(lineIdToMonitor);
         return this;
     }
 
@@ -46,8 +46,8 @@ public OverloadManagementSystemAdderImpl<T> withThreshold(double threshold) {
     }
 
     @Override
-    public OverloadManagementSystemAdderImpl<T> withSwitchId(String switchId) {
-        this.switchId = Objects.requireNonNull(switchId);
+    public OverloadManagementSystemAdderImpl<T> withSwitchIdToOperate(String switchIdToOperate) {
+        this.switchIdToOperate = Objects.requireNonNull(switchIdToOperate);
         return this;
     }
 
@@ -59,16 +59,16 @@ public OverloadManagementSystemAdderImpl<T> withSwitchOpen(boolean open) {
 
     @Override
     public T add() {
-        if (lineId == null) {
-            throw new PowsyblException("Line ID is not set");
+        if (lineIdToMonitor == null) {
+            throw new PowsyblException("Line ID to monitor is not set");
         }
         if (Double.isNaN(threshold)) {
             throw new PowsyblException("Threshold is not set");
         }
-        if (switchId == null) {
-            throw new PowsyblException("Switch ID is not set");
+        if (switchIdToOperate == null) {
+            throw new PowsyblException("Switch ID to operate is not set");
         }
-        OverloadManagementSystemImpl system = new OverloadManagementSystemImpl(lineId, threshold, switchId, switchOpen);
+        OverloadManagementSystemImpl system = new OverloadManagementSystemImpl(lineIdToMonitor, threshold, switchIdToOperate, switchOpen);
         parentAdder.accept(system);
         return parent;
     }
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemImpl.java b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemImpl.java
index 407f8d1820..b3cbc4aaac 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemImpl.java
@@ -13,24 +13,24 @@
  */
 public class OverloadManagementSystemImpl implements OverloadManagementSystem {
 
-    private final String lineId;
+    private final String lineIdToMonitor;
 
     private final double threshold;
 
-    private final String switchId;
+    private final String switchIdToOperate;
 
     private final boolean switchOpen;
 
-    public OverloadManagementSystemImpl(String lineId, double threshold, String switchId, boolean switchOpen) {
-        this.lineId = Objects.requireNonNull(lineId);
+    public OverloadManagementSystemImpl(String lineIdToMonitor, double threshold, String switchIdToOperate, boolean switchOpen) {
+        this.lineIdToMonitor = Objects.requireNonNull(lineIdToMonitor);
         this.threshold = threshold;
-        this.switchId = Objects.requireNonNull(switchId);
+        this.switchIdToOperate = Objects.requireNonNull(switchIdToOperate);
         this.switchOpen = switchOpen;
     }
 
     @Override
-    public String getLineId() {
-        return lineId;
+    public String getLineIdToMonitor() {
+        return lineIdToMonitor;
     }
 
     @Override
@@ -39,8 +39,8 @@ public double getThreshold() {
     }
 
     @Override
-    public String getSwitchId() {
-        return switchId;
+    public String getSwitchIdToOperate() {
+        return switchIdToOperate;
     }
 
     @Override
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
index b3f8045652..c04ef62c91 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
@@ -779,9 +779,9 @@ private void createAutomationFunctions(Network network, LfNetwork lfNetwork) {
             SubstationAutomationSystems functions = substation.getExtension(SubstationAutomationSystems.class);
             if (functions != null) {
                 for (OverloadManagementSystem function : functions.getOverloadManagementSystems()) {
-                    LfBranch lfLine = lfNetwork.getBranchById(function.getLineId());
+                    LfBranch lfLine = lfNetwork.getBranchById(function.getLineIdToMonitor());
                     if (lfLine != null) {
-                        LfSwitch lfSwitch = (LfSwitch) lfNetwork.getBranchById(function.getSwitchId());
+                        LfSwitch lfSwitch = (LfSwitch) lfNetwork.getBranchById(function.getSwitchIdToOperate());
                         if (lfSwitch != null) {
                             lfNetwork.addOverloadManagementSystem(new LfOverloadManagementSystem(lfLine, lfSwitch, function.isSwitchOpen()));
                         }
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
index 832497502f..5c920dcb1b 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
@@ -146,7 +146,7 @@ private static void addSwitchesOperatedByAutomata(Network network, LfNetworkPara
             for (Line line : network.getLines()) {
                 OverloadManagementSystem cla = line.getExtension(OverloadManagementSystem.class);
                 if (cla != null) {
-                    Switch aSwitch = network.getSwitch(cla.getSwitchId());
+                    Switch aSwitch = network.getSwitch(cla.getSwitchIdToOperate());
                     if (aSwitch != null) {
                         if (cla.isSwitchOpen()) {
                             allSwitchesToOpen.add(aSwitch);
diff --git a/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java b/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
index e69311716c..64c4ee4e2d 100644
--- a/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
+++ b/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
@@ -32,9 +32,9 @@ void test() {
         Substation s1 = network.getSubstation("S1");
         s1.newExtension(SubstationAutomationSystemsAdder.class)
                 .newOverloadManagementSystem()
-                    .withLineId("")
+                    .withLineIdToMonitor("")
                     .withThreshold(100)
-                    .withSwitchId("")
+                    .withSwitchIdToOperate("")
                     .withSwitchOpen(true)
                 .add()
             .add();

From 2f143e9c03b8f9feddfb1bf66203f77ad3921fad Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Sat, 20 May 2023 21:10:58 +0200
Subject: [PATCH 10/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../network/impl/LfNetworkLoaderImpl.java     | 23 ++++++++++---------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
index c04ef62c91..ba188eee35 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
@@ -668,7 +668,7 @@ private LfNetwork create(int numCC, int numSC, Network network, List<Bus> buses,
         createSecondaryVoltageControls(network, parameters, lfNetwork);
 
         if (parameters.isSimulateAutomatons()) {
-            createAutomationFunctions(network, lfNetwork);
+            createAutomationSystems(network, lfNetwork);
         }
 
         if (report.generatorsDiscardedFromVoltageControlBecauseNotStarted > 0) {
@@ -774,17 +774,18 @@ private static Optional<Bus> findPilotBus(Network network, boolean breaker, List
         return Optional.empty();
     }
 
-    private void createAutomationFunctions(Network network, LfNetwork lfNetwork) {
+    private void createAutomationSystems(Network network, LfNetwork lfNetwork) {
         for (Substation substation : network.getSubstations()) {
-            SubstationAutomationSystems functions = substation.getExtension(SubstationAutomationSystems.class);
-            if (functions != null) {
-                for (OverloadManagementSystem function : functions.getOverloadManagementSystems()) {
-                    LfBranch lfLine = lfNetwork.getBranchById(function.getLineIdToMonitor());
-                    if (lfLine != null) {
-                        LfSwitch lfSwitch = (LfSwitch) lfNetwork.getBranchById(function.getSwitchIdToOperate());
-                        if (lfSwitch != null) {
-                            lfNetwork.addOverloadManagementSystem(new LfOverloadManagementSystem(lfLine, lfSwitch, function.isSwitchOpen()));
-                        }
+            SubstationAutomationSystems systems = substation.getExtension(SubstationAutomationSystems.class);
+            if (systems != null) {
+                for (OverloadManagementSystem system : systems.getOverloadManagementSystems()) {
+                    LfBranch lfLineToMonitor = lfNetwork.getBranchById(system.getLineIdToMonitor());
+                    LfSwitch lfSwitchToOperate = (LfSwitch) lfNetwork.getBranchById(system.getSwitchIdToOperate());
+                    if (lfLineToMonitor != null && lfSwitchToOperate != null) {
+                        lfNetwork.addOverloadManagementSystem(new LfOverloadManagementSystem(lfLineToMonitor, lfSwitchToOperate, system.isSwitchOpen()));
+                    } else {
+                        LOGGER.warn("Invalid overload management system: line to monitor is '{}', switch to operate is '{}'",
+                                system.getLineIdToMonitor(), system.getSwitchIdToOperate());
                     }
                 }
             }

From a414875b58875b73d54a67b535fe881ce3b3a6e7 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Sun, 21 May 2023 13:52:36 +0200
Subject: [PATCH 11/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../outerloop/AutomationSystemOuterLoop.java  | 20 +++---
 .../network/LfOverloadManagementSystem.java   |  9 ++-
 .../network/impl/LfNetworkLoaderImpl.java     |  4 +-
 .../openloadflow/network/impl/Networks.java   | 32 ++++++---
 .../openloadflow/ac/AutomationSystemTest.java | 68 ++++++++++++++++---
 .../AbstractLoadFlowNetworkFactory.java       | 16 +++--
 6 files changed, 112 insertions(+), 37 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
index 8965ef510a..30526c1193 100644
--- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
+++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
@@ -7,7 +7,6 @@
 package com.powsybl.openloadflow.ac.outerloop;
 
 import com.powsybl.commons.reporter.Reporter;
-import com.powsybl.iidm.network.LimitType;
 import com.powsybl.openloadflow.ac.OuterLoop;
 import com.powsybl.openloadflow.ac.OuterLoopContext;
 import com.powsybl.openloadflow.ac.OuterLoopStatus;
@@ -32,20 +31,17 @@ public String getType() {
     @Override
     public OuterLoopStatus check(OuterLoopContext context, Reporter reporter) {
         OuterLoopStatus status = OuterLoopStatus.STABLE;
-        for (LfOverloadManagementSystem function : context.getNetwork().getOverloadManagementSystems()) {
-            LfBranch branch = function.getBranchToMonitor();
+        for (LfOverloadManagementSystem system : context.getNetwork().getOverloadManagementSystems()) {
+            LfBranch branch = system.getBranchToMonitor();
             if (branch.isConnectedAtBothSides()) {
                 double i1 = branch.getI1().eval();
-                double limit = branch.getLimits1(LimitType.CURRENT).stream()
-                        .map(LfBranch.LfLimit::getValue)
-                        .min(Double::compare)
-                        .orElse(Double.MAX_VALUE);
-                if (i1 > limit) {
+                double threshold = system.getThreshold();
+                if (i1 > threshold) {
                     double ib = PerUnit.ib(branch.getBus1().getNominalV());
-                    LOGGER.debug("Line '{}' is overloaded ({} > {}), {} switch '{}'",
-                            branch.getId(), i1 * ib, limit * ib, function.isSwitchOpen() ? "open" : "close",
-                            function.getSwitchToOperate().getId());
-                    function.getSwitchToOperate().setDisabled(function.isSwitchOpen());
+                    LOGGER.debug("Line '{}' is overloaded ({} A > {} A), {} switch '{}'",
+                            branch.getId(), i1 * ib, threshold * ib, system.isSwitchOpen() ? "open" : "close",
+                            system.getSwitchToOperate().getId());
+                    system.getSwitchToOperate().setDisabled(system.isSwitchOpen());
                     status = OuterLoopStatus.UNSTABLE;
                 }
             }
diff --git a/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementSystem.java b/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementSystem.java
index 66161e83c9..736a108abc 100644
--- a/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementSystem.java
+++ b/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementSystem.java
@@ -17,12 +17,15 @@ public class LfOverloadManagementSystem {
 
     private final LfBranch branchToMonitor;
 
+    private final double threshold;
+
     private final LfSwitch switchToOperate;
 
     private final boolean switchOpen;
 
-    public LfOverloadManagementSystem(LfBranch branchToMonitor, LfSwitch switchToOperate, boolean switchOpen) {
+    public LfOverloadManagementSystem(LfBranch branchToMonitor, double threshold, LfSwitch switchToOperate, boolean switchOpen) {
         this.branchToMonitor = Objects.requireNonNull(branchToMonitor);
+        this.threshold = threshold;
         this.switchToOperate = Objects.requireNonNull(switchToOperate);
         this.switchOpen = switchOpen;
     }
@@ -31,6 +34,10 @@ public LfBranch getBranchToMonitor() {
         return branchToMonitor;
     }
 
+    public double getThreshold() {
+        return threshold;
+    }
+
     public LfSwitch getSwitchToOperate() {
         return switchToOperate;
     }
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
index ba188eee35..8a00b79d27 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
@@ -782,7 +782,9 @@ private void createAutomationSystems(Network network, LfNetwork lfNetwork) {
                     LfBranch lfLineToMonitor = lfNetwork.getBranchById(system.getLineIdToMonitor());
                     LfSwitch lfSwitchToOperate = (LfSwitch) lfNetwork.getBranchById(system.getSwitchIdToOperate());
                     if (lfLineToMonitor != null && lfSwitchToOperate != null) {
-                        lfNetwork.addOverloadManagementSystem(new LfOverloadManagementSystem(lfLineToMonitor, lfSwitchToOperate, system.isSwitchOpen()));
+                        LfBus bus = lfLineToMonitor.getBus1() != null ? lfLineToMonitor.getBus1() : lfLineToMonitor.getBus2(); // FIXME
+                        double threshold = system.getThreshold() / PerUnit.ib(bus.getNominalV());
+                        lfNetwork.addOverloadManagementSystem(new LfOverloadManagementSystem(lfLineToMonitor, threshold, lfSwitchToOperate, system.isSwitchOpen()));
                     } else {
                         LOGGER.warn("Invalid overload management system: line to monitor is '{}', switch to operate is '{}'",
                                 system.getLineIdToMonitor(), system.getSwitchIdToOperate());
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
index 5c920dcb1b..1b1d4dfb04 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
@@ -11,6 +11,7 @@
 import com.powsybl.iidm.network.*;
 import com.powsybl.openloadflow.network.*;
 import com.powsybl.openloadflow.network.extensions.OverloadManagementSystem;
+import com.powsybl.openloadflow.network.extensions.SubstationAutomationSystems;
 
 import java.util.*;
 
@@ -142,13 +143,13 @@ private static void restoreInitialTopology(LfNetwork network, Set<Switch> allSwi
 
     private static void addSwitchesOperatedByAutomata(Network network, LfNetworkParameters networkParameters,
                                                       Set<Switch> allSwitchesToOpen, Set<Switch> allSwitchesToClose) {
-        if (networkParameters.isSimulateAutomatons()) {
-            for (Line line : network.getLines()) {
-                OverloadManagementSystem cla = line.getExtension(OverloadManagementSystem.class);
-                if (cla != null) {
-                    Switch aSwitch = network.getSwitch(cla.getSwitchIdToOperate());
+        for (Substation substation : network.getSubstations()) {
+            SubstationAutomationSystems systems = substation.getExtension(SubstationAutomationSystems.class);
+            if (systems != null) {
+                for (OverloadManagementSystem system : systems.getOverloadManagementSystems()) {
+                    Switch aSwitch = network.getSwitch(system.getSwitchIdToOperate());
                     if (aSwitch != null) {
-                        if (cla.isSwitchOpen()) {
+                        if (system.isSwitchOpen()) {
                             allSwitchesToOpen.add(aSwitch);
                         } else {
                             allSwitchesToClose.add(aSwitch);
@@ -167,17 +168,26 @@ public static LfNetworkList load(Network network, LfNetworkParameters networkPar
     public static LfNetworkList load(Network network, LfNetworkParameters networkParameters,
                                      Set<Switch> switchesToOpen, Set<Switch> switchesToClose,
                                      LfNetworkList.VariantCleanerFactory variantCleanerFactory, Reporter reporter) {
-        if (switchesToOpen.isEmpty() && switchesToClose.isEmpty()) {
+        Set<Switch> allSwitchesToOpen;
+        Set<Switch> allSwitchesToClose;
+        if (networkParameters.isSimulateAutomatons()) {
+            allSwitchesToOpen = new LinkedHashSet<>(switchesToOpen);
+            allSwitchesToClose = new LinkedHashSet<>(switchesToClose);
+            addSwitchesOperatedByAutomata(network, networkParameters, allSwitchesToOpen, allSwitchesToClose);
+            if (allSwitchesToOpen.size() + allSwitchesToClose.size() > 0) {
+                networkParameters.setBreakers(true);
+            }
+        } else {
+            allSwitchesToOpen = switchesToOpen;
+            allSwitchesToClose = switchesToClose;
+        }
+        if (allSwitchesToOpen.isEmpty() && allSwitchesToClose.isEmpty()) {
             return new LfNetworkList(load(network, networkParameters, reporter));
         } else {
             if (!networkParameters.isBreakers()) {
                 throw new PowsyblException("LF networks have to be built from bus/breaker view");
             }
 
-            Set<Switch> allSwitchesToOpen = new LinkedHashSet<>(switchesToOpen);
-            Set<Switch> allSwitchesToClose = new LinkedHashSet<>(switchesToClose);
-            addSwitchesOperatedByAutomata(network, networkParameters, allSwitchesToOpen, allSwitchesToClose);
-
             // create a temporary working variant to build LF networks
             String tmpVariantId = "olf-tmp-" + UUID.randomUUID();
             String workingVariantId = network.getVariantManager().getWorkingVariantId();
diff --git a/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java b/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
index 64c4ee4e2d..726d3e8c32 100644
--- a/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
+++ b/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
@@ -6,38 +6,90 @@
  */
 package com.powsybl.openloadflow.ac;
 
-import com.powsybl.ieeecdf.converter.IeeeCdfNetworkFactory;
+import com.powsybl.iidm.network.Bus;
+import com.powsybl.iidm.network.Line;
 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;
 import com.powsybl.math.matrix.DenseMatrixFactory;
 import com.powsybl.openloadflow.OpenLoadFlowParameters;
 import com.powsybl.openloadflow.OpenLoadFlowProvider;
+import com.powsybl.openloadflow.network.AbstractLoadFlowNetworkFactory;
 import com.powsybl.openloadflow.network.extensions.SubstationAutomationSystemsAdder;
 import org.junit.jupiter.api.Test;
 
+import static com.powsybl.openloadflow.util.LoadFlowAssert.assertCurrentEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
+
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
-class AutomationSystemTest {
+class AutomationSystemTest extends AbstractLoadFlowNetworkFactory {
+
+    /**
+     * b1 and b2 are the HV network
+     * b3 and b4 are the LV network
+     * when breaker br1 is closed, the network is operated "coupled" and the LV line l34 have a very high intensity
+     * opening the breaker br1 allow reducing the intensity of line l34 (even if network is in that case less robust
+     * to any contingency)
+     *      g1
+     *      |      l12
+     * b1 ====-------------==== b2
+     *      |                |
+     *      8 tr1            8 tr2
+     *      |   b3p  l34    |
+     * b3 ====*====--------==== b4
+     *      br1 |        |
+     *         ld3      ld4
+     */
+    private static Network createNetwork() {
+        Network network = Network.create("OverloadManagementSystemTestCase", "code");
+        Bus b1 = createBus(network, "s1", "b1", 225);
+        Bus b2 = createBus(network, "s2", "b2", 225);
+        Bus b3 = createBus(network, "s1", "b3", 63);
+        Bus b3p = b3.getVoltageLevel().getBusBreakerView().newBus()
+                .setId("b3p")
+                .add();
+        Bus b4 = createBus(network, "s2", "b4", 63);
+        createGenerator(b1, "g1", 100, 230);
+        createLoad(b3p, "ld3", 3, 2);
+        createLoad(b4, "ld4", 90, 60);
+        createLine(network, b1, b2, "l12", 0.1, 3);
+        createLine(network, b3p, b4, "l34", 0.05, 3.2);
+        b3.getVoltageLevel().getBusBreakerView().newSwitch()
+                .setId("br1")
+                .setBus1("b3")
+                .setBus2("b3p")
+                .setOpen(false)
+                .add();
+        createTransformer(network, "s1", b1, b3, "tr1", 0.2, 2, 1);
+        createTransformer(network, "s2", b2, b4, "tr2", 0.3, 3, 1);
+        return network;
+    }
 
     @Test
     void test() {
-        Network network = IeeeCdfNetworkFactory.create14();
+        Network network = createNetwork();
         LoadFlow.Runner loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(new DenseMatrixFactory()));
         LoadFlowParameters parameters = new LoadFlowParameters();
         OpenLoadFlowParameters.create(parameters)
                 .setSimulateAutomatons(true);
-        Substation s1 = network.getSubstation("S1");
+        Substation s1 = network.getSubstation("s1");
         s1.newExtension(SubstationAutomationSystemsAdder.class)
                 .newOverloadManagementSystem()
-                    .withLineIdToMonitor("")
-                    .withThreshold(100)
-                    .withSwitchIdToOperate("")
+                    .withLineIdToMonitor("l34")
+                    .withThreshold(300)
+                    .withSwitchIdToOperate("br1")
                     .withSwitchOpen(true)
                 .add()
             .add();
-        loadFlowRunner.run(network, parameters);
+        LoadFlowResult result = loadFlowRunner.run(network, parameters);
+        assertSame(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus());
+        Line l12 = network.getLine("l12");
+        Line l34 = network.getLine("l34");
+        assertCurrentEquals(298.953, l12.getTerminal1());
+        assertCurrentEquals(34.333, l34.getTerminal1()); // no more loop in LV network
     }
 }
diff --git a/src/test/java/com/powsybl/openloadflow/network/AbstractLoadFlowNetworkFactory.java b/src/test/java/com/powsybl/openloadflow/network/AbstractLoadFlowNetworkFactory.java
index 3688ec9e95..3183c99ce9 100644
--- a/src/test/java/com/powsybl/openloadflow/network/AbstractLoadFlowNetworkFactory.java
+++ b/src/test/java/com/powsybl/openloadflow/network/AbstractLoadFlowNetworkFactory.java
@@ -101,13 +101,17 @@ protected static Load createLoad(Bus b, String id, double p, double q) {
     }
 
     protected static Line createLine(Network network, Bus b1, Bus b2, String id, double x) {
+        return createLine(network, b1, b2, id, 0, x);
+    }
+
+    protected static Line createLine(Network network, Bus b1, Bus b2, String id, double r, double x) {
         return network.newLine()
                 .setId(id)
                 .setBus1(b1.getId())
                 .setConnectableBus1(b1.getId())
                 .setBus2(b2.getId())
                 .setConnectableBus2(b2.getId())
-                .setR(0)
+                .setR(r)
                 .setX(x)
                 .add();
     }
@@ -122,15 +126,19 @@ protected static Switch createSwitch(Network network, Bus b1, Bus b2, String id)
     }
 
     protected static TwoWindingsTransformer createTransformer(Network network, String substationId, Bus b1, Bus b2, String id, double x, double rho) {
+        return createTransformer(network, substationId, b1, b2, id, 0, x, rho);
+    }
+
+    protected static TwoWindingsTransformer createTransformer(Network network, String substationId, Bus b1, Bus b2, String id, double r, double x, double rho) {
         return network.getSubstation(substationId).newTwoWindingsTransformer()
                 .setId(id)
                 .setBus1(b1.getId())
                 .setConnectableBus1(b1.getId())
                 .setBus2(b2.getId())
                 .setConnectableBus2(b2.getId())
-                .setRatedU1(1)
-                .setRatedU2(rho)
-                .setR(0)
+                .setRatedU1(b1.getVoltageLevel().getNominalV())
+                .setRatedU2(b2.getVoltageLevel().getNominalV() * rho)
+                .setR(r)
                 .setX(x)
                 .add();
     }

From 77134c9ce9dae4678ef103a4b7fde074a2bc48a9 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@rte-france.com>
Date: Mon, 3 Jul 2023 11:05:02 +0200
Subject: [PATCH 12/30] Fix

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@rte-france.com>
---
 .../ac/outerloop/AutomationSystemOuterLoop.java       | 11 +++++------
 .../openloadflow/OpenLoadFlowParametersTest.java      |  2 +-
 .../openloadflow/OpenLoadFlowProviderTest.java        |  6 +++---
 3 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
index 30526c1193..8a65c0ef62 100644
--- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
+++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
@@ -7,9 +7,8 @@
 package com.powsybl.openloadflow.ac.outerloop;
 
 import com.powsybl.commons.reporter.Reporter;
-import com.powsybl.openloadflow.ac.OuterLoop;
-import com.powsybl.openloadflow.ac.OuterLoopContext;
-import com.powsybl.openloadflow.ac.OuterLoopStatus;
+import com.powsybl.openloadflow.ac.AcOuterLoopContext;
+import com.powsybl.openloadflow.lf.outerloop.OuterLoopStatus;
 import com.powsybl.openloadflow.network.LfBranch;
 import com.powsybl.openloadflow.network.LfOverloadManagementSystem;
 import com.powsybl.openloadflow.util.PerUnit;
@@ -19,17 +18,17 @@
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
-public class AutomationSystemOuterLoop implements OuterLoop {
+public class AutomationSystemOuterLoop implements AcOuterLoop {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationSystemOuterLoop.class);
 
     @Override
     public String getType() {
-        return "AutomationFunction";
+        return "AutomationSystem";
     }
 
     @Override
-    public OuterLoopStatus check(OuterLoopContext context, Reporter reporter) {
+    public OuterLoopStatus check(AcOuterLoopContext context, Reporter reporter) {
         OuterLoopStatus status = OuterLoopStatus.STABLE;
         for (LfOverloadManagementSystem system : context.getNetwork().getOverloadManagementSystems()) {
             LfBranch branch = system.getBranchToMonitor();
diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java
index 03563b3937..70340be0d0 100644
--- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java
+++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java
@@ -316,7 +316,7 @@ void testCloneParameters() {
     @Test
     void testToString() {
         OpenLoadFlowParameters parameters = new OpenLoadFlowParameters();
-        assertEquals("OpenLoadFlowParameters(slackBusSelectionMode=MOST_MESHED, slackBusesIds=[], throwsExceptionInCaseOfSlackDistributionFailure=false, voltageRemoteControl=true, lowImpedanceBranchMode=REPLACE_BY_ZERO_IMPEDANCE_LINE, loadPowerFactorConstant=false, plausibleActivePowerLimit=5000.0, newtonRaphsonStoppingCriteriaType=UNIFORM_CRITERIA, slackBusPMaxMismatch=1.0, maxActivePowerMismatch=0.01, maxReactivePowerMismatch=0.01, maxVoltageMismatch=1.0E-4, maxAngleMismatch=1.0E-5, maxRatioMismatch=1.0E-5, maxSusceptanceMismatch=1.0E-4, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, maxNewtonRaphsonIterations=15, maxOuterLoopIterations=20, newtonRaphsonConvEpsPerEq=1.0E-4, voltageInitModeOverride=NONE, transformerVoltageControlMode=WITH_GENERATOR_VOLTAGE_CONTROL, shuntVoltageControlMode=WITH_GENERATOR_VOLTAGE_CONTROL, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, networkCacheEnabled=false, svcVoltageMonitoring=true, stateVectorScalingMode=NONE, maxSlackBusCount=1, debugDir=null, incrementalTransformerVoltageControlOuterLoopMaxTapShift=3, secondaryVoltageControl=false, controllerToPilotPointVoltageSensiEpsilon=0.01, reactiveLimitsMaxPqPvSwitch=3, phaseShifterControlMode=CONTINUOUS_WITH_DISCRETISATION, alwaysUpdateNetwork=false, mostMeshedSlackBusSelectorMaxNominalVoltagePercentile=95.0, reportedFeatures=[], slackBusCountryFilter=[], actionableSwitchesIds=[], asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0)",
+        assertEquals("OpenLoadFlowParameters(slackBusSelectionMode=MOST_MESHED, slackBusesIds=[], throwsExceptionInCaseOfSlackDistributionFailure=false, voltageRemoteControl=true, lowImpedanceBranchMode=REPLACE_BY_ZERO_IMPEDANCE_LINE, loadPowerFactorConstant=false, plausibleActivePowerLimit=5000.0, newtonRaphsonStoppingCriteriaType=UNIFORM_CRITERIA, slackBusPMaxMismatch=1.0, maxActivePowerMismatch=0.01, maxReactivePowerMismatch=0.01, maxVoltageMismatch=1.0E-4, maxAngleMismatch=1.0E-5, maxRatioMismatch=1.0E-5, maxSusceptanceMismatch=1.0E-4, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, maxNewtonRaphsonIterations=15, maxOuterLoopIterations=20, newtonRaphsonConvEpsPerEq=1.0E-4, voltageInitModeOverride=NONE, transformerVoltageControlMode=WITH_GENERATOR_VOLTAGE_CONTROL, shuntVoltageControlMode=WITH_GENERATOR_VOLTAGE_CONTROL, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, networkCacheEnabled=false, svcVoltageMonitoring=true, stateVectorScalingMode=NONE, maxSlackBusCount=1, debugDir=null, incrementalTransformerVoltageControlOuterLoopMaxTapShift=3, secondaryVoltageControl=false, controllerToPilotPointVoltageSensiEpsilon=0.01, reactiveLimitsMaxPqPvSwitch=3, phaseShifterControlMode=CONTINUOUS_WITH_DISCRETISATION, alwaysUpdateNetwork=false, mostMeshedSlackBusSelectorMaxNominalVoltagePercentile=95.0, reportedFeatures=[], slackBusCountryFilter=[], actionableSwitchesIds=[], asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, simulateAutomaton=false)",
                      parameters.toString());
     }
 }
diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
index 311d0fc044..85b046a590 100644
--- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
+++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
@@ -49,7 +49,7 @@ void test() {
     void testDcParameters() {
         Network network = Mockito.mock(Network.class);
         DcLoadFlowParameters dcParameters = OpenLoadFlowParameters.createDcParameters(network, new LoadFlowParameters().setReadSlackBus(true), new OpenLoadFlowParameters(), new DenseMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), true);
-        assertEquals("DcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=false, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=DC, reactiveLimits=false, hvdcAcEmulation=false, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=false, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0), equationSystemCreationParameters=DcEquationSystemCreationParameters(updateFlows=true, forcePhaseControlOffAndAddAngle1Var=true, useTransformerRatio=true), matrixFactory=DenseMatrixFactory, distributedSlack=true, balanceType=PROPORTIONAL_TO_GENERATION_P_MAX, setVToNan=true)",
+        assertEquals("DcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=false, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=DC, reactiveLimits=false, hvdcAcEmulation=false, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=false, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, simulateAutomatons=false), equationSystemCreationParameters=DcEquationSystemCreationParameters(updateFlows=true, forcePhaseControlOffAndAddAngle1Var=true, useTransformerRatio=true), matrixFactory=DenseMatrixFactory, distributedSlack=true, balanceType=PROPORTIONAL_TO_GENERATION_P_MAX, setVToNan=true)",
                      dcParameters.toString());
     }
 
@@ -57,7 +57,7 @@ void testDcParameters() {
     void testAcParameters() {
         Network network = Mockito.mock(Network.class);
         AcLoadFlowParameters acParameters = OpenLoadFlowParameters.createAcParameters(network, new LoadFlowParameters().setReadSlackBus(true), new OpenLoadFlowParameters(), new DenseMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), false, false);
-        assertEquals("AcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=true, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=AC, reactiveLimits=true, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=true, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0), equationSystemCreationParameters=AcEquationSystemCreationParameters(forceA1Var=false), newtonRaphsonParameters=NewtonRaphsonParameters(maxIterations=15, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, stoppingCriteria=DefaultNewtonRaphsonStoppingCriteria, stateVectorScalingMode=NONE, alwaysUpdateNetwork=false, detailedNrReport=false), outerLoops=[DistributedSlackOuterLoop, MonitoringVoltageOuterLoop, ReactiveLimitsOuterLoop], maxOuterLoopIterations=20, matrixFactory=DenseMatrixFactory, voltageInitializer=UniformValueVoltageInitializer, asymmetrical=false)",
+        assertEquals("AcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=true, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=AC, reactiveLimits=true, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=true, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, simulateAutomatons=false), equationSystemCreationParameters=AcEquationSystemCreationParameters(forceA1Var=false), newtonRaphsonParameters=NewtonRaphsonParameters(maxIterations=15, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, stoppingCriteria=DefaultNewtonRaphsonStoppingCriteria, stateVectorScalingMode=NONE, alwaysUpdateNetwork=false, detailedNrReport=false), outerLoops=[DistributedSlackOuterLoop, MonitoringVoltageOuterLoop, ReactiveLimitsOuterLoop], maxOuterLoopIterations=20, matrixFactory=DenseMatrixFactory, voltageInitializer=UniformValueVoltageInitializer, asymmetrical=false)",
                      acParameters.toString());
     }
 
@@ -85,7 +85,7 @@ void testGetExtendedVoltageInitializer() {
     @Test
     void specificParametersTest() {
         OpenLoadFlowProvider provider = new OpenLoadFlowProvider();
-        assertEquals(46, provider.getSpecificParameters().size());
+        assertEquals(47, provider.getSpecificParameters().size());
         LoadFlowParameters parameters = new LoadFlowParameters();
 
         provider.loadSpecificParameters(Collections.emptyMap())

From 7331cdf257d309bdb1442662f871d0cc86cb9aa6 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Mon, 16 Oct 2023 10:12:21 +0200
Subject: [PATCH 13/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../AbstractAcOuterLoopConfig.java            |  7 +++++
 .../DefaultAcOuterLoopConfig.java             |  2 ++
 .../ExplicitAcOuterLoopConfig.java            |  4 ++-
 .../openloadflow/OpenLoadFlowProvider.java    |  4 +--
 .../outerloop/AutomationSystemOuterLoop.java  |  6 ++--
 .../network/impl/LfTopoConfig.java            | 20 +++++++++++--
 .../openloadflow/network/impl/Networks.java   | 28 ++++++++-----------
 .../OpenLoadFlowParametersTest.java           |  4 +--
 .../OpenLoadFlowProviderTest.java             |  4 +--
 9 files changed, 51 insertions(+), 28 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java b/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java
index 1609c36ddc..0d5253595f 100644
--- a/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java
+++ b/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java
@@ -102,4 +102,11 @@ protected static Optional<AcOuterLoop> createPhaseControlOuterLoop(LoadFlowParam
     protected static Optional<AcOuterLoop> createPhaseControlOuterLoop(LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt) {
         return createPhaseControlOuterLoop(parameters, parametersExt.getPhaseShifterControlMode());
     }
+
+    protected static Optional<AcOuterLoop> createAutomationSystemOuterLoop(OpenLoadFlowParameters parametersExt) {
+        if (parametersExt.isSimulateAutomatons()) {
+            return Optional.of(new AutomationSystemOuterLoop());
+        }
+        return Optional.empty();
+    }
 }
diff --git a/src/main/java/com/powsybl/openloadflow/DefaultAcOuterLoopConfig.java b/src/main/java/com/powsybl/openloadflow/DefaultAcOuterLoopConfig.java
index 4c27e4fd39..fd3c690977 100644
--- a/src/main/java/com/powsybl/openloadflow/DefaultAcOuterLoopConfig.java
+++ b/src/main/java/com/powsybl/openloadflow/DefaultAcOuterLoopConfig.java
@@ -33,6 +33,8 @@ public List<AcOuterLoop> configure(LoadFlowParameters parameters, OpenLoadFlowPa
         createTransformerVoltageControlOuterLoop(parameters, parametersExt).ifPresent(outerLoops::add);
         // shunt compensator voltage control
         createShuntVoltageControlOuterLoop(parameters, parametersExt).ifPresent(outerLoops::add);
+        // automation system
+        createAutomationSystemOuterLoop(parametersExt).ifPresent(outerLoops::add);
         return outerLoops;
     }
 }
diff --git a/src/main/java/com/powsybl/openloadflow/ExplicitAcOuterLoopConfig.java b/src/main/java/com/powsybl/openloadflow/ExplicitAcOuterLoopConfig.java
index b0ebed61c7..f6bb16ecd9 100644
--- a/src/main/java/com/powsybl/openloadflow/ExplicitAcOuterLoopConfig.java
+++ b/src/main/java/com/powsybl/openloadflow/ExplicitAcOuterLoopConfig.java
@@ -32,7 +32,8 @@ public class ExplicitAcOuterLoopConfig extends AbstractAcOuterLoopConfig {
                                                      SecondaryVoltageControlOuterLoop.NAME,
                                                      ShuntVoltageControlOuterLoop.NAME,
                                                      SimpleTransformerVoltageControlOuterLoop.NAME,
-                                                     TransformerVoltageControlOuterLoop.NAME);
+                                                     TransformerVoltageControlOuterLoop.NAME,
+                                                     AutomationSystemOuterLoop.NAME);
 
     private static Optional<AcOuterLoop> createOuterLoop(String name, LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt) {
         return switch (name) {
@@ -57,6 +58,7 @@ private static Optional<AcOuterLoop> createOuterLoop(String name, LoadFlowParame
             case TransformerVoltageControlOuterLoop.NAME -> createTransformerVoltageControlOuterLoop(parameters,
                                                                                                      OpenLoadFlowParameters.TransformerVoltageControlMode.AFTER_GENERATOR_VOLTAGE_CONTROL,
                                                                                                      parametersExt.getIncrementalTransformerVoltageControlOuterLoopMaxTapShift());
+            case AutomationSystemOuterLoop.NAME -> createAutomationSystemOuterLoop(parametersExt);
             default -> throw new PowsyblException("Unknown outer loop '" + name + "'");
         };
     }
diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
index 05fdb3fd0a..293ec169f3 100644
--- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
+++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
@@ -35,6 +35,7 @@
 import com.powsybl.openloadflow.network.*;
 import com.powsybl.openloadflow.network.impl.LfNetworkList;
 import com.powsybl.openloadflow.network.impl.LfNetworkLoaderImpl;
+import com.powsybl.openloadflow.network.impl.LfTopoConfig;
 import com.powsybl.openloadflow.network.impl.Networks;
 import com.powsybl.openloadflow.network.util.ZeroImpedanceFlows;
 import com.powsybl.openloadflow.util.*;
@@ -154,8 +155,7 @@ private LoadFlowResult runAc(Network network, LoadFlowParameters parameters, Ope
             results = new AcLoadFlowFromCache(network, parameters, parametersExt, acParameters, reporter)
                     .run();
         } else {
-            try (LfNetworkList lfNetworkList = Networks.load(network, acParameters.getNetworkParameters(), Collections.emptySet(),
-                                                             Collections.emptySet(), reporter)) {
+            try (LfNetworkList lfNetworkList = Networks.load(network, acParameters.getNetworkParameters(), new LfTopoConfig(), reporter)) {
                 results = AcloadFlowEngine.run(lfNetworkList.getList(), acParameters);
             }
         }
diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
index 8a65c0ef62..2bd37378b2 100644
--- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
+++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
@@ -22,9 +22,11 @@ public class AutomationSystemOuterLoop implements AcOuterLoop {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationSystemOuterLoop.class);
 
+    public static final String NAME = "AutomationSystem";
+
     @Override
-    public String getType() {
-        return "AutomationSystem";
+    public String getName() {
+        return NAME;
     }
 
     @Override
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfTopoConfig.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfTopoConfig.java
index d77733c781..e59d20033f 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/LfTopoConfig.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfTopoConfig.java
@@ -9,6 +9,7 @@
 import com.powsybl.iidm.network.Switch;
 
 import java.util.HashSet;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -16,11 +17,24 @@
  */
 public class LfTopoConfig {
 
-    private final Set<Switch> switchesToOpen = new HashSet<>();
+    private final Set<Switch> switchesToOpen;
 
-    private final Set<Switch> switchesToClose = new HashSet<>();
+    private final Set<Switch> switchesToClose;
 
-    private final Set<String> busIdsToLose = new HashSet<>();
+    private final Set<String> busIdsToLose;
+
+    public LfTopoConfig() {
+        switchesToOpen = new HashSet<>();
+        switchesToClose = new HashSet<>();
+        busIdsToLose = new HashSet<>();
+    }
+
+    public LfTopoConfig(LfTopoConfig other) {
+        Objects.requireNonNull(other);
+        this.switchesToOpen = new HashSet<>(other.switchesToOpen);
+        this.switchesToClose = new HashSet<>(other.switchesToClose);
+        this.busIdsToLose = new HashSet<>(other.busIdsToLose);
+    }
 
     public Set<Switch> getSwitchesToOpen() {
         return switchesToOpen;
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
index 11b976a220..0e4749ac14 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
@@ -141,8 +141,7 @@ private static void restoreInitialTopology(LfNetwork network, Set<Switch> allSwi
         removedBranches.forEach(branch -> branch.setDisabled(true));
     }
 
-    private static void addSwitchesOperatedByAutomata(Network network, LfNetworkParameters networkParameters,
-                                                      Set<Switch> allSwitchesToOpen, Set<Switch> allSwitchesToClose) {
+    private static void addSwitchesOperatedByAutomata(Network network, LfTopoConfig topoConfig) {
         for (Substation substation : network.getSubstations()) {
             SubstationAutomationSystems systems = substation.getExtension(SubstationAutomationSystems.class);
             if (systems != null) {
@@ -150,9 +149,9 @@ private static void addSwitchesOperatedByAutomata(Network network, LfNetworkPara
                     Switch aSwitch = network.getSwitch(system.getSwitchIdToOperate());
                     if (aSwitch != null) {
                         if (system.isSwitchOpen()) {
-                            allSwitchesToOpen.add(aSwitch);
+                            topoConfig.getSwitchesToOpen().add(aSwitch);
                         } else {
-                            allSwitchesToClose.add(aSwitch);
+                            topoConfig.getSwitchesToClose().add(aSwitch);
                         }
                     }
                 }
@@ -167,20 +166,17 @@ public static LfNetworkList load(Network network, LfNetworkParameters networkPar
 
     public static LfNetworkList load(Network network, LfNetworkParameters networkParameters, LfTopoConfig topoConfig,
                                      LfNetworkList.VariantCleanerFactory variantCleanerFactory, Reporter reporter) {
-        Set<Switch> allSwitchesToOpen;
-        Set<Switch> allSwitchesToClose;
+        LfTopoConfig modifiedTopoConfig;
         if (networkParameters.isSimulateAutomatons()) {
-            allSwitchesToOpen = new LinkedHashSet<>(switchesToOpen);
-            allSwitchesToClose = new LinkedHashSet<>(switchesToClose);
-            addSwitchesOperatedByAutomata(network, networkParameters, allSwitchesToOpen, allSwitchesToClose);
-            if (allSwitchesToOpen.size() + allSwitchesToClose.size() > 0) {
+            modifiedTopoConfig = new LfTopoConfig(topoConfig);
+            addSwitchesOperatedByAutomata(network, modifiedTopoConfig);
+            if (modifiedTopoConfig.isBreaker()) {
                 networkParameters.setBreakers(true);
             }
         } else {
-            allSwitchesToOpen = switchesToOpen;
-            allSwitchesToClose = switchesToClose;
+            modifiedTopoConfig = topoConfig;
         }
-        if (!topoConfig.isBreaker()) {
+        if (!modifiedTopoConfig.isBreaker()) {
             return new LfNetworkList(load(network, networkParameters, reporter));
         } else {
             if (!networkParameters.isBreakers()) {
@@ -195,14 +191,14 @@ public static LfNetworkList load(Network network, LfNetworkParameters networkPar
 
             // retain in topology all switches that could be open or close
             // and close switches that could be closed during the simulation
-            retainAndCloseNecessarySwitches(network, topoConfig);
+            retainAndCloseNecessarySwitches(network, modifiedTopoConfig);
 
             List<LfNetwork> lfNetworks = load(network, networkParameters, reporter);
 
-            if (!topoConfig.getSwitchesToClose().isEmpty()) {
+            if (!modifiedTopoConfig.getSwitchesToClose().isEmpty()) {
                 for (LfNetwork lfNetwork : lfNetworks) {
                     // disable all buses and branches not connected to main component (because of switch to close)
-                    restoreInitialTopology(lfNetwork, topoConfig.getSwitchesToClose());
+                    restoreInitialTopology(lfNetwork, modifiedTopoConfig.getSwitchesToClose());
                 }
             }
 
diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java
index 37b74b943a..68d90a06aa 100644
--- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java
+++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java
@@ -344,7 +344,7 @@ void testExplicitOuterLoopsParameter() {
         e = assertThrows(PowsyblException.class, () -> OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt));
         assertEquals("Unknown outer loop 'Foo'", e.getMessage());
 
-        assertEquals("Ordered explicit list of outer loop names, supported outer loops are IncrementalPhaseControl, DistributedSlack, IncrementalShuntVoltageControl, IncrementalTransformerVoltageControl, VoltageMonitoring, PhaseControl, ReactiveLimits, SecondaryVoltageControl, ShuntVoltageControl, SimpleTransformerVoltageControl, TransformerVoltageControl",
-                OpenLoadFlowParameters.SPECIFIC_PARAMETERS.stream().filter(p -> p.getName().equals(OpenLoadFlowParameters.OUTER_LOOP_NAMES_PARAM_NAME)).findFirst().orElseThrow().getDescription());
+        assertEquals("Ordered explicit list of outer loop names, supported outer loops are IncrementalPhaseControl, DistributedSlack, IncrementalShuntVoltageControl, IncrementalTransformerVoltageControl, VoltageMonitoring, PhaseControl, ReactiveLimits, SecondaryVoltageControl, ShuntVoltageControl, SimpleTransformerVoltageControl, TransformerVoltageControl, AutomationSystem",
+                     OpenLoadFlowParameters.SPECIFIC_PARAMETERS.stream().filter(p -> p.getName().equals(OpenLoadFlowParameters.OUTER_LOOP_NAMES_PARAM_NAME)).findFirst().orElseThrow().getDescription());
     }
 }
diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
index 3c39e8f154..e9265b7f62 100644
--- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
+++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
@@ -49,7 +49,7 @@ void test() {
     void testDcParameters() {
         Network network = Mockito.mock(Network.class);
         DcLoadFlowParameters dcParameters = OpenLoadFlowParameters.createDcParameters(network, new LoadFlowParameters().setReadSlackBus(true), new OpenLoadFlowParameters(), new DenseMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), true);
-        assertEquals("DcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=false, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=DC, reactiveLimits=false, hvdcAcEmulation=false, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=false, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE), equationSystemCreationParameters=DcEquationSystemCreationParameters(updateFlows=true, forcePhaseControlOffAndAddAngle1Var=true, useTransformerRatio=true), matrixFactory=DenseMatrixFactory, distributedSlack=true, balanceType=PROPORTIONAL_TO_GENERATION_P_MAX, setVToNan=true, maxOuterLoopIterations=20)",
+        assertEquals("DcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=false, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=DC, reactiveLimits=false, hvdcAcEmulation=false, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=false, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE, simulateAutomatons=false), equationSystemCreationParameters=DcEquationSystemCreationParameters(updateFlows=true, forcePhaseControlOffAndAddAngle1Var=true, useTransformerRatio=true), matrixFactory=DenseMatrixFactory, distributedSlack=true, balanceType=PROPORTIONAL_TO_GENERATION_P_MAX, setVToNan=true, maxOuterLoopIterations=20)",
                      dcParameters.toString());
     }
 
@@ -57,7 +57,7 @@ void testDcParameters() {
     void testAcParameters() {
         Network network = Mockito.mock(Network.class);
         AcLoadFlowParameters acParameters = OpenLoadFlowParameters.createAcParameters(network, new LoadFlowParameters().setReadSlackBus(true), new OpenLoadFlowParameters(), new DenseMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), false, false);
-        assertEquals("AcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=true, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=AC, reactiveLimits=true, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=true, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE), equationSystemCreationParameters=AcEquationSystemCreationParameters(forceA1Var=false), newtonRaphsonParameters=NewtonRaphsonParameters(maxIterations=15, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, stoppingCriteria=DefaultNewtonRaphsonStoppingCriteria, stateVectorScalingMode=NONE, alwaysUpdateNetwork=false, detailedNrReport=false, lineSearchStateVectorScalingMaxIteration=10, lineSearchStateVectorScalingStepFold=1.3333333333333333, maxVoltageChangeStateVectorScalingMaxDv=0.1, maxVoltageChangeStateVectorScalingMaxDphi=0.17453292519943295), outerLoops=[DistributedSlackOuterLoop, MonitoringVoltageOuterLoop, ReactiveLimitsOuterLoop], maxOuterLoopIterations=20, matrixFactory=DenseMatrixFactory, voltageInitializer=UniformValueVoltageInitializer, asymmetrical=false)",
+        assertEquals("AcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=true, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=AC, reactiveLimits=true, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=true, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE, simulateAutomatons=false), equationSystemCreationParameters=AcEquationSystemCreationParameters(forceA1Var=false), newtonRaphsonParameters=NewtonRaphsonParameters(maxIterations=15, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, stoppingCriteria=DefaultNewtonRaphsonStoppingCriteria, stateVectorScalingMode=NONE, alwaysUpdateNetwork=false, detailedNrReport=false, lineSearchStateVectorScalingMaxIteration=10, lineSearchStateVectorScalingStepFold=1.3333333333333333, maxVoltageChangeStateVectorScalingMaxDv=0.1, maxVoltageChangeStateVectorScalingMaxDphi=0.17453292519943295), outerLoops=[DistributedSlackOuterLoop, MonitoringVoltageOuterLoop, ReactiveLimitsOuterLoop], maxOuterLoopIterations=20, matrixFactory=DenseMatrixFactory, voltageInitializer=UniformValueVoltageInitializer, asymmetrical=false)",
                      acParameters.toString());
     }
 

From db356e29ad7f508c3f3254b72f35acff840071fb Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Mon, 16 Oct 2023 15:16:01 +0200
Subject: [PATCH 14/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../AbstractAcOuterLoopConfig.java            |  2 +-
 .../openloadflow/OpenLoadFlowParameters.java  | 26 +++++++++----------
 .../network/LfNetworkParameters.java          | 16 ++++++------
 .../network/impl/LfNetworkLoaderImpl.java     |  2 +-
 .../openloadflow/network/impl/Networks.java   |  2 +-
 .../OpenLoadFlowParametersTest.java           |  2 +-
 .../OpenLoadFlowProviderTest.java             |  4 +--
 .../openloadflow/ac/AutomationSystemTest.java |  2 +-
 src/test/resources/debug-parameters.json      |  2 +-
 9 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java b/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java
index 0d5253595f..a213a285e9 100644
--- a/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java
+++ b/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java
@@ -104,7 +104,7 @@ protected static Optional<AcOuterLoop> createPhaseControlOuterLoop(LoadFlowParam
     }
 
     protected static Optional<AcOuterLoop> createAutomationSystemOuterLoop(OpenLoadFlowParameters parametersExt) {
-        if (parametersExt.isSimulateAutomatons()) {
+        if (parametersExt.isSimulateAutomationSystems()) {
             return Optional.of(new AutomationSystemOuterLoop());
         }
         return Optional.empty();
diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
index 352e0ffcc1..3df315361f 100644
--- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
+++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
@@ -209,7 +209,7 @@ public class OpenLoadFlowParameters extends AbstractExtension<LoadFlowParameters
 
     private static final String USE_LOAD_MODEL_PARAM_NAME = "useLoadModel";
 
-    public static final String SIMULATE_AUTOMATONS_PARAM_NAME = "simulateAutomaton";
+    public static final String SIMULATE_AUTOMATION_SYSTEMS_PARAM_NAME = "simulateAutomationSystems";
 
     private static <E extends Enum<E>> List<Object> getEnumPossibleValues(Class<E> enumClass) {
         return EnumSet.allOf(enumClass).stream().map(Enum::name).collect(Collectors.toList());
@@ -270,7 +270,7 @@ private static <E extends Enum<E>> List<Object> getEnumPossibleValues(Class<E> e
         new Parameter(MAX_VOLTAGE_CHANGE_STATE_VECTOR_SCALING_MAX_DPHI_PARAM_NAME, ParameterType.DOUBLE, "Max voltage angle change for the max voltage change state vector scaling", MaxVoltageChangeStateVectorScaling.DEFAULT_MAX_DPHI),
         new Parameter(LINE_PER_UNIT_MODE_PARAM_NAME, ParameterType.STRING, "Line per unit mode", LinePerUnitMode.IMPEDANCE.name(), getEnumPossibleValues(LinePerUnitMode.class)),
         new Parameter(USE_LOAD_MODEL_PARAM_NAME, ParameterType.BOOLEAN, "Use load model (with voltage dependency) for simulation", LfNetworkParameters.USE_LOAD_MODE_DEFAULT_VALUE),
-        new Parameter(SIMULATE_AUTOMATONS_PARAM_NAME, ParameterType.BOOLEAN, "Automatons simulation", LfNetworkParameters.SIMULATE_AUTOMATONS_DEFAULT_VALUE)
+        new Parameter(SIMULATE_AUTOMATION_SYSTEMS_PARAM_NAME, ParameterType.BOOLEAN, "Automatons simulation", LfNetworkParameters.SIMULATE_AUTOMATION_SYSTEMS_DEFAULT_VALUE)
     );
 
     public enum VoltageInitModeOverride {
@@ -420,7 +420,7 @@ public enum ReactiveRangeCheckMode {
 
     private boolean useLoadModel = LfNetworkParameters.USE_LOAD_MODE_DEFAULT_VALUE;
 
-    private boolean simulateAutomatons = LfNetworkParameters.SIMULATE_AUTOMATONS_DEFAULT_VALUE;
+    private boolean simulateAutomationSystems = LfNetworkParameters.SIMULATE_AUTOMATION_SYSTEMS_DEFAULT_VALUE;
 
     @Override
     public String getName() {
@@ -955,12 +955,12 @@ public OpenLoadFlowParameters setUseLoadModel(boolean useLoadModel) {
         return this;
     }
 
-    public boolean isSimulateAutomatons() {
-        return simulateAutomatons;
+    public boolean isSimulateAutomationSystems() {
+        return simulateAutomationSystems;
     }
 
-    public OpenLoadFlowParameters setSimulateAutomatons(boolean simulateAutomatons) {
-        this.simulateAutomatons = simulateAutomatons;
+    public OpenLoadFlowParameters setSimulateAutomationSystems(boolean simulateAutomationSystems) {
+        this.simulateAutomationSystems = simulateAutomationSystems;
         return this;
     }
 
@@ -1029,7 +1029,7 @@ public static OpenLoadFlowParameters load(PlatformConfig platformConfig) {
                 .setMaxVoltageChangeStateVectorScalingMaxDphi(config.getDoubleProperty(MAX_VOLTAGE_CHANGE_STATE_VECTOR_SCALING_MAX_DPHI_PARAM_NAME, MaxVoltageChangeStateVectorScaling.DEFAULT_MAX_DPHI))
                 .setLinePerUnitMode(config.getEnumProperty(LINE_PER_UNIT_MODE_PARAM_NAME, LinePerUnitMode.class, LfNetworkParameters.LINE_PER_UNIT_MODE_DEFAULT_VALUE))
                 .setUseLoadModel(config.getBooleanProperty(USE_LOAD_MODEL_PARAM_NAME, LfNetworkParameters.USE_LOAD_MODE_DEFAULT_VALUE))
-                .setSimulateAutomatons(config.getBooleanProperty(SIMULATE_AUTOMATONS_PARAM_NAME, LfNetworkParameters.SIMULATE_AUTOMATONS_DEFAULT_VALUE)));
+                .setSimulateAutomationSystems(config.getBooleanProperty(SIMULATE_AUTOMATION_SYSTEMS_PARAM_NAME, LfNetworkParameters.SIMULATE_AUTOMATION_SYSTEMS_DEFAULT_VALUE)));
         return parameters;
     }
 
@@ -1153,8 +1153,8 @@ public OpenLoadFlowParameters update(Map<String, String> properties) {
                 .ifPresent(prop -> this.setLinePerUnitMode(LinePerUnitMode.valueOf(prop)));
         Optional.ofNullable(properties.get(USE_LOAD_MODEL_PARAM_NAME))
                 .ifPresent(prop -> this.setUseLoadModel(Boolean.parseBoolean(prop)));
-        Optional.ofNullable(properties.get(SIMULATE_AUTOMATONS_PARAM_NAME))
-                .ifPresent(prop -> this.setSimulateAutomatons(Boolean.parseBoolean(prop)));
+        Optional.ofNullable(properties.get(SIMULATE_AUTOMATION_SYSTEMS_PARAM_NAME))
+                .ifPresent(prop -> this.setSimulateAutomationSystems(Boolean.parseBoolean(prop)));
         return this;
     }
 
@@ -1214,7 +1214,7 @@ public Map<String, Object> toMap() {
         map.put(MAX_VOLTAGE_CHANGE_STATE_VECTOR_SCALING_MAX_DPHI_PARAM_NAME, maxVoltageChangeStateVectorScalingMaxDphi);
         map.put(LINE_PER_UNIT_MODE_PARAM_NAME, linePerUnitMode);
         map.put(USE_LOAD_MODEL_PARAM_NAME, useLoadModel);
-        map.put(SIMULATE_AUTOMATONS_PARAM_NAME, simulateAutomatons);
+        map.put(SIMULATE_AUTOMATION_SYSTEMS_PARAM_NAME, simulateAutomationSystems);
         return map;
     }
 
@@ -1337,7 +1337,7 @@ static LfNetworkParameters getNetworkParameters(LoadFlowParameters parameters, O
                 .setMinNominalVoltageTargetVoltageCheck(parametersExt.getMinNominalVoltageTargetVoltageCheck())
                 .setLinePerUnitMode(parametersExt.getLinePerUnitMode())
                 .setUseLoadModel(parametersExt.isUseLoadModel())
-                .setSimulateAutomatons(parametersExt.isSimulateAutomatons());
+                .setSimulateAutomationSystems(parametersExt.isSimulateAutomationSystems());
     }
 
     public static AcLoadFlowParameters createAcParameters(Network network, LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt,
@@ -1550,7 +1550,7 @@ public static boolean equals(LoadFlowParameters parameters1, LoadFlowParameters
                 extension1.getMaxVoltageChangeStateVectorScalingMaxDphi() == extension2.getMaxVoltageChangeStateVectorScalingMaxDphi() &&
                 extension1.getLinePerUnitMode() == extension2.getLinePerUnitMode() &&
                 extension1.isUseLoadModel() == extension2.isUseLoadModel() &&
-                extension1.isSimulateAutomatons() == extension2.isSimulateAutomatons();
+                extension1.isSimulateAutomationSystems() == extension2.isSimulateAutomationSystems();
     }
 
     public static LoadFlowParameters clone(LoadFlowParameters parameters) {
diff --git a/src/main/java/com/powsybl/openloadflow/network/LfNetworkParameters.java b/src/main/java/com/powsybl/openloadflow/network/LfNetworkParameters.java
index 86a7bac36a..bab4c6a00d 100644
--- a/src/main/java/com/powsybl/openloadflow/network/LfNetworkParameters.java
+++ b/src/main/java/com/powsybl/openloadflow/network/LfNetworkParameters.java
@@ -53,7 +53,7 @@ public class LfNetworkParameters {
 
     public static final Set<Country> SLACK_BUS_COUNTRY_FILTER_DEFAULT_VALUE = Collections.emptySet();
 
-    public static final boolean SIMULATE_AUTOMATONS_DEFAULT_VALUE = false;
+    public static final boolean SIMULATE_AUTOMATION_SYSTEMS_DEFAULT_VALUE = false;
 
     private SlackBusSelector slackBusSelector = new FirstSlackBusSelector(SLACK_BUS_COUNTRY_FILTER_DEFAULT_VALUE);
 
@@ -123,7 +123,7 @@ public class LfNetworkParameters {
 
     private boolean useLoadModel = USE_LOAD_MODE_DEFAULT_VALUE;
 
-    private boolean simulateAutomatons = SIMULATE_AUTOMATONS_DEFAULT_VALUE;
+    private boolean simulateAutomationSystems = SIMULATE_AUTOMATION_SYSTEMS_DEFAULT_VALUE;
 
     public LfNetworkParameters() {
     }
@@ -162,7 +162,7 @@ public LfNetworkParameters(LfNetworkParameters other) {
         this.asymmetrical = other.asymmetrical;
         this.linePerUnitMode = other.linePerUnitMode;
         this.useLoadModel = other.useLoadModel;
-        this.simulateAutomatons = other.simulateAutomatons;
+        this.simulateAutomationSystems = other.simulateAutomationSystems;
     }
 
     public SlackBusSelector getSlackBusSelector() {
@@ -472,12 +472,12 @@ public LfNetworkParameters setUseLoadModel(boolean useLoadModel) {
         return this;
     }
 
-    public boolean isSimulateAutomatons() {
-        return simulateAutomatons;
+    public boolean isSimulateAutomationSystems() {
+        return simulateAutomationSystems;
     }
 
-    public LfNetworkParameters setSimulateAutomatons(boolean simulateAutomatons) {
-        this.simulateAutomatons = simulateAutomatons;
+    public LfNetworkParameters setSimulateAutomationSystems(boolean simulateAutomationSystems) {
+        this.simulateAutomationSystems = simulateAutomationSystems;
         return this;
     }
 
@@ -515,7 +515,7 @@ public String toString() {
                 ", minNominalVoltageTargetVoltageCheck=" + minNominalVoltageTargetVoltageCheck +
                 ", linePerUnitMode=" + linePerUnitMode +
                 ", useLoadModel=" + useLoadModel +
-                ", simulateAutomatons=" + simulateAutomatons +
+                ", simulateAutomationSystems=" + simulateAutomationSystems +
                 ')';
     }
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
index c576163db5..88c33e176a 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
@@ -691,7 +691,7 @@ private LfNetwork create(int numCC, int numSC, Network network, List<Bus> buses,
         // voltage angle limits
         createVoltageAngleLimits(network, lfNetwork, parameters);
 
-        if (parameters.isSimulateAutomatons()) {
+        if (parameters.isSimulateAutomationSystems()) {
             createAutomationSystems(network, lfNetwork);
         }
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
index 0e4749ac14..9eb9dcdea0 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
@@ -167,7 +167,7 @@ public static LfNetworkList load(Network network, LfNetworkParameters networkPar
     public static LfNetworkList load(Network network, LfNetworkParameters networkParameters, LfTopoConfig topoConfig,
                                      LfNetworkList.VariantCleanerFactory variantCleanerFactory, Reporter reporter) {
         LfTopoConfig modifiedTopoConfig;
-        if (networkParameters.isSimulateAutomatons()) {
+        if (networkParameters.isSimulateAutomationSystems()) {
             modifiedTopoConfig = new LfTopoConfig(topoConfig);
             addSwitchesOperatedByAutomata(network, modifiedTopoConfig);
             if (modifiedTopoConfig.isBreaker()) {
diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java
index c0ed68b94c..546f6c2115 100644
--- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java
+++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java
@@ -320,7 +320,7 @@ void testCloneParameters() {
     @Test
     void testToString() {
         OpenLoadFlowParameters parameters = new OpenLoadFlowParameters();
-        assertEquals("OpenLoadFlowParameters(slackBusSelectionMode=MOST_MESHED, slackBusesIds=[], throwsExceptionInCaseOfSlackDistributionFailure=false, voltageRemoteControl=true, lowImpedanceBranchMode=REPLACE_BY_ZERO_IMPEDANCE_LINE, loadPowerFactorConstant=false, plausibleActivePowerLimit=5000.0, newtonRaphsonStoppingCriteriaType=UNIFORM_CRITERIA, slackBusPMaxMismatch=1.0, maxActivePowerMismatch=0.01, maxReactivePowerMismatch=0.01, maxVoltageMismatch=1.0E-4, maxAngleMismatch=1.0E-5, maxRatioMismatch=1.0E-5, maxSusceptanceMismatch=1.0E-4, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, maxNewtonRaphsonIterations=15, maxOuterLoopIterations=20, newtonRaphsonConvEpsPerEq=1.0E-4, voltageInitModeOverride=NONE, transformerVoltageControlMode=WITH_GENERATOR_VOLTAGE_CONTROL, shuntVoltageControlMode=WITH_GENERATOR_VOLTAGE_CONTROL, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, networkCacheEnabled=false, svcVoltageMonitoring=true, stateVectorScalingMode=NONE, maxSlackBusCount=1, debugDir=null, incrementalTransformerVoltageControlOuterLoopMaxTapShift=3, secondaryVoltageControl=false, reactiveLimitsMaxPqPvSwitch=3, phaseShifterControlMode=CONTINUOUS_WITH_DISCRETISATION, alwaysUpdateNetwork=false, mostMeshedSlackBusSelectorMaxNominalVoltagePercentile=95.0, reportedFeatures=[], slackBusCountryFilter=[], actionableSwitchesIds=[], asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, reactivePowerDispatchMode=Q_EQUAL_PROPORTION, outerLoopNames=null, useActiveLimits=true, lineSearchStateVectorScalingMaxIteration=10, lineSearchStateVectorScalingStepFold=1.3333333333333333, maxVoltageChangeStateVectorScalingMaxDv=0.1, maxVoltageChangeStateVectorScalingMaxDphi=0.17453292519943295, linePerUnitMode=IMPEDANCE, useLoadModel=false, simulateAutomaton=false)",
+        assertEquals("OpenLoadFlowParameters(slackBusSelectionMode=MOST_MESHED, slackBusesIds=[], throwsExceptionInCaseOfSlackDistributionFailure=false, voltageRemoteControl=true, lowImpedanceBranchMode=REPLACE_BY_ZERO_IMPEDANCE_LINE, loadPowerFactorConstant=false, plausibleActivePowerLimit=5000.0, newtonRaphsonStoppingCriteriaType=UNIFORM_CRITERIA, slackBusPMaxMismatch=1.0, maxActivePowerMismatch=0.01, maxReactivePowerMismatch=0.01, maxVoltageMismatch=1.0E-4, maxAngleMismatch=1.0E-5, maxRatioMismatch=1.0E-5, maxSusceptanceMismatch=1.0E-4, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, maxNewtonRaphsonIterations=15, maxOuterLoopIterations=20, newtonRaphsonConvEpsPerEq=1.0E-4, voltageInitModeOverride=NONE, transformerVoltageControlMode=WITH_GENERATOR_VOLTAGE_CONTROL, shuntVoltageControlMode=WITH_GENERATOR_VOLTAGE_CONTROL, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, networkCacheEnabled=false, svcVoltageMonitoring=true, stateVectorScalingMode=NONE, maxSlackBusCount=1, debugDir=null, incrementalTransformerVoltageControlOuterLoopMaxTapShift=3, secondaryVoltageControl=false, reactiveLimitsMaxPqPvSwitch=3, phaseShifterControlMode=CONTINUOUS_WITH_DISCRETISATION, alwaysUpdateNetwork=false, mostMeshedSlackBusSelectorMaxNominalVoltagePercentile=95.0, reportedFeatures=[], slackBusCountryFilter=[], actionableSwitchesIds=[], asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, reactivePowerDispatchMode=Q_EQUAL_PROPORTION, outerLoopNames=null, useActiveLimits=true, lineSearchStateVectorScalingMaxIteration=10, lineSearchStateVectorScalingStepFold=1.3333333333333333, maxVoltageChangeStateVectorScalingMaxDv=0.1, maxVoltageChangeStateVectorScalingMaxDphi=0.17453292519943295, linePerUnitMode=IMPEDANCE, useLoadModel=false, simulateAutomationSystems=false)",
                      parameters.toString());
     }
 
diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
index ece7f8901b..851ff5b381 100644
--- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
+++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
@@ -49,7 +49,7 @@ void test() {
     void testDcParameters() {
         Network network = Mockito.mock(Network.class);
         DcLoadFlowParameters dcParameters = OpenLoadFlowParameters.createDcParameters(network, new LoadFlowParameters().setReadSlackBus(true), new OpenLoadFlowParameters(), new DenseMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), true);
-        assertEquals("DcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=false, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=DC, reactiveLimits=false, hvdcAcEmulation=false, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=false, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE, useLoadModel=false, simulateAutomatons=false), equationSystemCreationParameters=DcEquationSystemCreationParameters(updateFlows=true, forcePhaseControlOffAndAddAngle1Var=true, useTransformerRatio=true), matrixFactory=DenseMatrixFactory, distributedSlack=true, balanceType=PROPORTIONAL_TO_GENERATION_P_MAX, setVToNan=true, maxOuterLoopIterations=20)",
+        assertEquals("DcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=false, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=DC, reactiveLimits=false, hvdcAcEmulation=false, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=false, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE, useLoadModel=false, simulateAutomationSystems=false), equationSystemCreationParameters=DcEquationSystemCreationParameters(updateFlows=true, forcePhaseControlOffAndAddAngle1Var=true, useTransformerRatio=true), matrixFactory=DenseMatrixFactory, distributedSlack=true, balanceType=PROPORTIONAL_TO_GENERATION_P_MAX, setVToNan=true, maxOuterLoopIterations=20)",
                      dcParameters.toString());
     }
 
@@ -57,7 +57,7 @@ void testDcParameters() {
     void testAcParameters() {
         Network network = Mockito.mock(Network.class);
         AcLoadFlowParameters acParameters = OpenLoadFlowParameters.createAcParameters(network, new LoadFlowParameters().setReadSlackBus(true), new OpenLoadFlowParameters(), new DenseMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), false, false);
-        assertEquals("AcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=true, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=AC, reactiveLimits=true, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=true, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE, useLoadModel=false, simulateAutomatons=false), equationSystemCreationParameters=AcEquationSystemCreationParameters(forceA1Var=false), newtonRaphsonParameters=NewtonRaphsonParameters(maxIterations=15, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, stoppingCriteria=DefaultNewtonRaphsonStoppingCriteria, stateVectorScalingMode=NONE, alwaysUpdateNetwork=false, detailedNrReport=false, lineSearchStateVectorScalingMaxIteration=10, lineSearchStateVectorScalingStepFold=1.3333333333333333, maxVoltageChangeStateVectorScalingMaxDv=0.1, maxVoltageChangeStateVectorScalingMaxDphi=0.17453292519943295), outerLoops=[DistributedSlackOuterLoop, MonitoringVoltageOuterLoop, ReactiveLimitsOuterLoop], maxOuterLoopIterations=20, matrixFactory=DenseMatrixFactory, voltageInitializer=UniformValueVoltageInitializer, asymmetrical=false)",
+        assertEquals("AcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=true, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=AC, reactiveLimits=true, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=true, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE, useLoadModel=false, simulateAutomationSystems=false), equationSystemCreationParameters=AcEquationSystemCreationParameters(forceA1Var=false), newtonRaphsonParameters=NewtonRaphsonParameters(maxIterations=15, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, stoppingCriteria=DefaultNewtonRaphsonStoppingCriteria, stateVectorScalingMode=NONE, alwaysUpdateNetwork=false, detailedNrReport=false, lineSearchStateVectorScalingMaxIteration=10, lineSearchStateVectorScalingStepFold=1.3333333333333333, maxVoltageChangeStateVectorScalingMaxDv=0.1, maxVoltageChangeStateVectorScalingMaxDphi=0.17453292519943295), outerLoops=[DistributedSlackOuterLoop, MonitoringVoltageOuterLoop, ReactiveLimitsOuterLoop], maxOuterLoopIterations=20, matrixFactory=DenseMatrixFactory, voltageInitializer=UniformValueVoltageInitializer, asymmetrical=false)",
                      acParameters.toString());
     }
 
diff --git a/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java b/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
index 726d3e8c32..8156b1500d 100644
--- a/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
+++ b/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
@@ -75,7 +75,7 @@ void test() {
         LoadFlow.Runner loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(new DenseMatrixFactory()));
         LoadFlowParameters parameters = new LoadFlowParameters();
         OpenLoadFlowParameters.create(parameters)
-                .setSimulateAutomatons(true);
+                .setSimulateAutomationSystems(true);
         Substation s1 = network.getSubstation("s1");
         s1.newExtension(SubstationAutomationSystemsAdder.class)
                 .newOverloadManagementSystem()
diff --git a/src/test/resources/debug-parameters.json b/src/test/resources/debug-parameters.json
index ddd90f9132..f74039b41d 100644
--- a/src/test/resources/debug-parameters.json
+++ b/src/test/resources/debug-parameters.json
@@ -72,7 +72,7 @@
         "maxVoltageChangeStateVectorScalingMaxDphi" : 0.17453292519943295,
         "linePerUnitMode" : "IMPEDANCE",
         "useLoadModel" : false,
-        "simulateAutomatons" : false
+        "simulateAutomationSystems" : false
       }
     }
   },

From 211eaa584f011c8d696b0308371cf0e91d3086fe Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Mon, 16 Oct 2023 15:36:37 +0200
Subject: [PATCH 15/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../outerloop/AutomationSystemOuterLoop.java  | 46 ++++++++++++++-----
 1 file changed, 34 insertions(+), 12 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
index 2bd37378b2..ae8498f494 100644
--- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
+++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
@@ -8,13 +8,17 @@
 
 import com.powsybl.commons.reporter.Reporter;
 import com.powsybl.openloadflow.ac.AcOuterLoopContext;
+import com.powsybl.openloadflow.graph.GraphConnectivity;
 import com.powsybl.openloadflow.lf.outerloop.OuterLoopStatus;
-import com.powsybl.openloadflow.network.LfBranch;
-import com.powsybl.openloadflow.network.LfOverloadManagementSystem;
+import com.powsybl.openloadflow.network.*;
+import com.powsybl.openloadflow.network.impl.LfSwitch;
 import com.powsybl.openloadflow.util.PerUnit;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.HashSet;
+import java.util.Set;
+
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
@@ -32,21 +36,39 @@ public String getName() {
     @Override
     public OuterLoopStatus check(AcOuterLoopContext context, Reporter reporter) {
         OuterLoopStatus status = OuterLoopStatus.STABLE;
-        for (LfOverloadManagementSystem system : context.getNetwork().getOverloadManagementSystems()) {
-            LfBranch branch = system.getBranchToMonitor();
-            if (branch.isConnectedAtBothSides()) {
-                double i1 = branch.getI1().eval();
+        LfNetwork network = context.getNetwork();
+        Set<LfBranch> branchesToOpen = new HashSet<>();
+        Set<LfBranch> branchesToClose = new HashSet<>();
+        for (LfOverloadManagementSystem system : network.getOverloadManagementSystems()) {
+            LfBranch branchToMonitor = system.getBranchToMonitor();
+            if (branchToMonitor.isConnectedAtBothSides()) {
+                double i1 = branchToMonitor.getI1().eval();
                 double threshold = system.getThreshold();
                 if (i1 > threshold) {
-                    double ib = PerUnit.ib(branch.getBus1().getNominalV());
-                    LOGGER.debug("Line '{}' is overloaded ({} A > {} A), {} switch '{}'",
-                            branch.getId(), i1 * ib, threshold * ib, system.isSwitchOpen() ? "open" : "close",
-                            system.getSwitchToOperate().getId());
-                    system.getSwitchToOperate().setDisabled(system.isSwitchOpen());
-                    status = OuterLoopStatus.UNSTABLE;
+                    double ib = PerUnit.ib(branchToMonitor.getBus1().getNominalV());
+                    LfSwitch switchToOperate = system.getSwitchToOperate();
+                    if (system.isSwitchOpen() && switchToOperate.isConnectedAtBothSides()) {
+                        LOGGER.debug("Line '{}' is overloaded ({} A > {} A), open switch '{}'",
+                                branchToMonitor.getId(), i1 * ib, threshold * ib, switchToOperate.getId());
+                        branchesToOpen.add(switchToOperate);
+                    } else if (!system.isSwitchOpen() && !switchToOperate.isConnectedAtBothSides()) {
+                        LOGGER.debug("Line '{}' is overloaded ({} A > {} A), close switch '{}'",
+                                branchToMonitor.getId(), i1 * ib, threshold * ib, switchToOperate.getId());
+                        branchesToClose.add(switchToOperate);
+                    }
                 }
             }
         }
+
+        if (branchesToOpen.size() + branchesToClose.size() > 0) {
+            GraphConnectivity<LfBus, LfBranch> connectivity = network.getConnectivity();
+            connectivity.startTemporaryChanges();
+            branchesToOpen.forEach(connectivity::removeEdge);
+            branchesToClose.forEach(branch -> connectivity.addEdge(branch.getBus1(), branch.getBus2(), branch));
+            LfAction.updateBusesAndBranchStatus(connectivity);
+            status = OuterLoopStatus.UNSTABLE;
+        }
+
         return status;
     }
 }

From 4f1fea394ef07d8b33238529869bc029e3ac2896 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Mon, 16 Oct 2023 15:37:44 +0200
Subject: [PATCH 16/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../openloadflow/network/impl/LfNetworkLoaderImpl.java        | 4 ++--
 .../java/com/powsybl/openloadflow/network/impl/Networks.java  | 4 ++--
 .../{ => impl}/extensions/OverloadManagementSystem.java       | 2 +-
 .../{ => impl}/extensions/OverloadManagementSystemAdder.java  | 2 +-
 .../extensions/OverloadManagementSystemAdderImpl.java         | 2 +-
 .../{ => impl}/extensions/OverloadManagementSystemImpl.java   | 2 +-
 .../{ => impl}/extensions/SubstationAutomationSystems.java    | 2 +-
 .../extensions/SubstationAutomationSystemsAdder.java          | 2 +-
 .../extensions/SubstationAutomationSystemsAdderImpl.java      | 2 +-
 .../SubstationAutomationSystemsAdderImplProvider.java         | 2 +-
 .../extensions/SubstationAutomationSystemsImpl.java           | 2 +-
 .../com/powsybl/openloadflow/ac/AutomationSystemTest.java     | 2 +-
 12 files changed, 14 insertions(+), 14 deletions(-)
 rename src/main/java/com/powsybl/openloadflow/network/{ => impl}/extensions/OverloadManagementSystem.java (89%)
 rename src/main/java/com/powsybl/openloadflow/network/{ => impl}/extensions/OverloadManagementSystemAdder.java (92%)
 rename src/main/java/com/powsybl/openloadflow/network/{ => impl}/extensions/OverloadManagementSystemAdderImpl.java (97%)
 rename src/main/java/com/powsybl/openloadflow/network/{ => impl}/extensions/OverloadManagementSystemImpl.java (95%)
 rename src/main/java/com/powsybl/openloadflow/network/{ => impl}/extensions/SubstationAutomationSystems.java (93%)
 rename src/main/java/com/powsybl/openloadflow/network/{ => impl}/extensions/SubstationAutomationSystemsAdder.java (91%)
 rename src/main/java/com/powsybl/openloadflow/network/{ => impl}/extensions/SubstationAutomationSystemsAdderImpl.java (96%)
 rename src/main/java/com/powsybl/openloadflow/network/{ => impl}/extensions/SubstationAutomationSystemsAdderImplProvider.java (95%)
 rename src/main/java/com/powsybl/openloadflow/network/{ => impl}/extensions/SubstationAutomationSystemsImpl.java (95%)

diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
index 88c33e176a..6aaa22d93c 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
@@ -15,8 +15,8 @@
 import com.powsybl.iidm.network.extensions.SecondaryVoltageControl.ControlZone;
 import com.powsybl.iidm.network.extensions.SecondaryVoltageControl.PilotPoint;
 import com.powsybl.openloadflow.network.*;
-import com.powsybl.openloadflow.network.extensions.OverloadManagementSystem;
-import com.powsybl.openloadflow.network.extensions.SubstationAutomationSystems;
+import com.powsybl.openloadflow.network.impl.extensions.OverloadManagementSystem;
+import com.powsybl.openloadflow.network.impl.extensions.SubstationAutomationSystems;
 import com.powsybl.openloadflow.util.DebugUtil;
 import com.powsybl.openloadflow.util.PerUnit;
 import com.powsybl.openloadflow.util.Reports;
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
index 9eb9dcdea0..08f58e4f23 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
@@ -10,8 +10,8 @@
 import com.powsybl.commons.reporter.Reporter;
 import com.powsybl.iidm.network.*;
 import com.powsybl.openloadflow.network.*;
-import com.powsybl.openloadflow.network.extensions.OverloadManagementSystem;
-import com.powsybl.openloadflow.network.extensions.SubstationAutomationSystems;
+import com.powsybl.openloadflow.network.impl.extensions.OverloadManagementSystem;
+import com.powsybl.openloadflow.network.impl.extensions.SubstationAutomationSystems;
 
 import java.util.*;
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystem.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystem.java
similarity index 89%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystem.java
rename to src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystem.java
index fa937bc42f..7c3153d1bf 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystem.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystem.java
@@ -4,7 +4,7 @@
  * 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.openloadflow.network.extensions;
+package com.powsybl.openloadflow.network.impl.extensions;
 
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdder.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdder.java
similarity index 92%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdder.java
rename to src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdder.java
index 5133c303e6..38ab904cbe 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdder.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdder.java
@@ -4,7 +4,7 @@
  * 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.openloadflow.network.extensions;
+package com.powsybl.openloadflow.network.impl.extensions;
 
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdderImpl.java
similarity index 97%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdderImpl.java
rename to src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdderImpl.java
index 0ba096569e..b9af83471b 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemAdderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdderImpl.java
@@ -4,7 +4,7 @@
  * 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.openloadflow.network.extensions;
+package com.powsybl.openloadflow.network.impl.extensions;
 
 import com.powsybl.commons.PowsyblException;
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemImpl.java
similarity index 95%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemImpl.java
rename to src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemImpl.java
index b3cbc4aaac..11f4c17dc8 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/OverloadManagementSystemImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemImpl.java
@@ -4,7 +4,7 @@
  * 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.openloadflow.network.extensions;
+package com.powsybl.openloadflow.network.impl.extensions;
 
 import java.util.Objects;
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystems.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystems.java
similarity index 93%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystems.java
rename to src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystems.java
index cd3e1df239..4cddb70eb8 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystems.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystems.java
@@ -4,7 +4,7 @@
  * 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.openloadflow.network.extensions;
+package com.powsybl.openloadflow.network.impl.extensions;
 
 import com.powsybl.commons.extensions.Extension;
 import com.powsybl.iidm.network.Substation;
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdder.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdder.java
similarity index 91%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdder.java
rename to src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdder.java
index 8a487d2fbf..bcb5543073 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdder.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdder.java
@@ -4,7 +4,7 @@
  * 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.openloadflow.network.extensions;
+package com.powsybl.openloadflow.network.impl.extensions;
 
 import com.powsybl.commons.extensions.ExtensionAdder;
 import com.powsybl.iidm.network.Substation;
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImpl.java
similarity index 96%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdderImpl.java
rename to src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImpl.java
index 742d117e74..b3035cd54c 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImpl.java
@@ -4,7 +4,7 @@
  * 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.openloadflow.network.extensions;
+package com.powsybl.openloadflow.network.impl.extensions;
 
 import com.powsybl.commons.extensions.AbstractExtensionAdder;
 import com.powsybl.iidm.network.Substation;
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdderImplProvider.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImplProvider.java
similarity index 95%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdderImplProvider.java
rename to src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImplProvider.java
index b6aeba37f4..53cc25714f 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsAdderImplProvider.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImplProvider.java
@@ -5,7 +5,7 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-package com.powsybl.openloadflow.network.extensions;
+package com.powsybl.openloadflow.network.impl.extensions;
 
 import com.google.auto.service.AutoService;
 import com.powsybl.commons.extensions.ExtensionAdderProvider;
diff --git a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsImpl.java
similarity index 95%
rename from src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsImpl.java
rename to src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsImpl.java
index a377d9566d..8ff7721b7d 100644
--- a/src/main/java/com/powsybl/openloadflow/network/extensions/SubstationAutomationSystemsImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsImpl.java
@@ -4,7 +4,7 @@
  * 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.openloadflow.network.extensions;
+package com.powsybl.openloadflow.network.impl.extensions;
 
 import com.powsybl.commons.extensions.AbstractExtension;
 import com.powsybl.iidm.network.Substation;
diff --git a/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java b/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
index 8156b1500d..11b29f0aef 100644
--- a/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
+++ b/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
@@ -17,7 +17,7 @@
 import com.powsybl.openloadflow.OpenLoadFlowParameters;
 import com.powsybl.openloadflow.OpenLoadFlowProvider;
 import com.powsybl.openloadflow.network.AbstractLoadFlowNetworkFactory;
-import com.powsybl.openloadflow.network.extensions.SubstationAutomationSystemsAdder;
+import com.powsybl.openloadflow.network.impl.extensions.SubstationAutomationSystemsAdder;
 import org.junit.jupiter.api.Test;
 
 import static com.powsybl.openloadflow.util.LoadFlowAssert.assertCurrentEquals;

From bd6f307fb9caf13c7c6fec7c92d272e20af3338a Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Mon, 16 Oct 2023 16:38:14 +0200
Subject: [PATCH 17/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../SubstationAutomationSystemsAdderImpl.java |  2 +-
 ...ionAutomationSystemsAdderImplProvider.java |  3 +-
 ...stationAutomationSystemsXmlSerializer.java | 59 +++++++++++++++++++
 3 files changed, 61 insertions(+), 3 deletions(-)
 create mode 100644 src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java

diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImpl.java
index b3035cd54c..6e0026c084 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImpl.java
@@ -34,7 +34,7 @@ public OverloadManagementSystemAdder<SubstationAutomationSystemsAdder> newOverlo
     }
 
     @Override
-    protected SubstationAutomationSystems createExtension(Substation substation) {
+    protected SubstationAutomationSystemsImpl createExtension(Substation substation) {
         return new SubstationAutomationSystemsImpl(substation, overloadManagementSystems);
     }
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImplProvider.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImplProvider.java
index 53cc25714f..1601bbdb8e 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImplProvider.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImplProvider.java
@@ -4,7 +4,6 @@
  * 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.openloadflow.network.impl.extensions;
 
 import com.google.auto.service.AutoService;
@@ -34,7 +33,7 @@ public Class<SubstationAutomationSystemsAdder> getAdderClass() {
     }
 
     @Override
-    public SubstationAutomationSystemsAdder newAdder(Substation substation) {
+    public SubstationAutomationSystemsAdderImpl newAdder(Substation substation) {
         return new SubstationAutomationSystemsAdderImpl(substation);
     }
 }
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java
new file mode 100644
index 0000000000..687b7bb2f9
--- /dev/null
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.network.impl.extensions;
+
+import com.google.auto.service.AutoService;
+import com.powsybl.commons.extensions.AbstractExtensionXmlSerializer;
+import com.powsybl.commons.extensions.ExtensionXmlSerializer;
+import com.powsybl.commons.xml.XmlReaderContext;
+import com.powsybl.commons.xml.XmlUtil;
+import com.powsybl.commons.xml.XmlWriterContext;
+import com.powsybl.iidm.network.Substation;
+
+import javax.xml.stream.XMLStreamException;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+@AutoService(ExtensionXmlSerializer.class)
+public class SubstationAutomationSystemsXmlSerializer extends AbstractExtensionXmlSerializer<Substation, SubstationAutomationSystems> {
+
+    public SubstationAutomationSystemsXmlSerializer() {
+        super(SubstationAutomationSystems.NAME, "network", SubstationAutomationSystems.class, true, "substationAutomationSystems.xsd",
+                "http://www.powsybl.org/schema/iidm/ext/substation_automation_systems/1_0", "sas");
+    }
+
+    @Override
+    public void write(SubstationAutomationSystems systems, XmlWriterContext context) throws XMLStreamException {
+        for (var oms : systems.getOverloadManagementSystems()) {
+            context.getWriter().writeStartElement(getNamespaceUri(), "overloadManagementSystem");
+            context.getWriter().writeAttribute("lineIdToMonitor", oms.getLineIdToMonitor());
+            XmlUtil.writeDouble("threshold", oms.getThreshold(), context.getWriter());
+            context.getWriter().writeAttribute("switchIdToOperate", oms.getSwitchIdToOperate());
+            context.getWriter().writeAttribute("switchOpen", Boolean.toString(oms.isSwitchOpen()));
+            context.getWriter().writeEndElement();
+        }
+    }
+
+    @Override
+    public SubstationAutomationSystems read(Substation substation, XmlReaderContext context) throws XMLStreamException {
+        SubstationAutomationSystemsAdder adder = substation.newExtension(SubstationAutomationSystemsAdder.class);
+        XmlUtil.readUntilEndElement(getExtensionName(), context.getReader(), () -> {
+            String lineIdToMonitor = context.getReader().getAttributeValue(null, "lineIdToMonitor");
+            double threshold = XmlUtil.readDoubleAttribute(context.getReader(), "threshold");
+            String switchIdToOperate = context.getReader().getAttributeValue(null, "switchIdToOperate");
+            boolean switchOpen = XmlUtil.readBoolAttribute(context.getReader(), "switchOpen");
+            adder.newOverloadManagementSystem()
+                    .withLineIdToMonitor(lineIdToMonitor)
+                    .withThreshold(threshold)
+                    .withSwitchIdToOperate(switchIdToOperate)
+                    .withSwitchOpen(switchOpen)
+                    .add();
+        });
+        return adder.add();
+    }
+}

From b201e491b0c5b42f389b15fe0e0b49796ff41357 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Mon, 16 Oct 2023 21:09:35 +0200
Subject: [PATCH 18/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../SubstationAutomationSystems.java          |  2 +-
 ...stationAutomationSystemsXmlSerializer.java |  3 +-
 .../openloadflow/ac/AutomationSystemTest.java | 59 +--------------
 .../AutomationSystemNetworkFactory.java       | 73 +++++++++++++++++++
 .../SubstationAutomationSystemsTest.java      | 38 ++++++++++
 .../substationAutomationSystemsRef.xml        | 43 +++++++++++
 .../xsd/substationAutomationSystems.xsd       | 27 +++++++
 7 files changed, 186 insertions(+), 59 deletions(-)
 create mode 100644 src/test/java/com/powsybl/openloadflow/network/AutomationSystemNetworkFactory.java
 create mode 100644 src/test/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsTest.java
 create mode 100644 src/test/resources/substationAutomationSystemsRef.xml
 create mode 100644 src/test/resources/xsd/substationAutomationSystems.xsd

diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystems.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystems.java
index 4cddb70eb8..823ce22432 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystems.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystems.java
@@ -16,7 +16,7 @@
  */
 public interface SubstationAutomationSystems extends Extension<Substation> {
 
-    String NAME = "SubstationAutomationSystems";
+    String NAME = "substationAutomationSystems";
 
     @Override
     default String getName() {
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java
index 687b7bb2f9..de9dc8864c 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java
@@ -30,12 +30,11 @@ public SubstationAutomationSystemsXmlSerializer() {
     @Override
     public void write(SubstationAutomationSystems systems, XmlWriterContext context) throws XMLStreamException {
         for (var oms : systems.getOverloadManagementSystems()) {
-            context.getWriter().writeStartElement(getNamespaceUri(), "overloadManagementSystem");
+            context.getWriter().writeEmptyElement(getNamespaceUri(), "overloadManagementSystem");
             context.getWriter().writeAttribute("lineIdToMonitor", oms.getLineIdToMonitor());
             XmlUtil.writeDouble("threshold", oms.getThreshold(), context.getWriter());
             context.getWriter().writeAttribute("switchIdToOperate", oms.getSwitchIdToOperate());
             context.getWriter().writeAttribute("switchOpen", Boolean.toString(oms.isSwitchOpen()));
-            context.getWriter().writeEndElement();
         }
     }
 
diff --git a/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java b/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
index 11b29f0aef..a22c9f146d 100644
--- a/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
+++ b/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
@@ -6,18 +6,15 @@
  */
 package com.powsybl.openloadflow.ac;
 
-import com.powsybl.iidm.network.Bus;
 import com.powsybl.iidm.network.Line;
 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;
 import com.powsybl.math.matrix.DenseMatrixFactory;
 import com.powsybl.openloadflow.OpenLoadFlowParameters;
 import com.powsybl.openloadflow.OpenLoadFlowProvider;
-import com.powsybl.openloadflow.network.AbstractLoadFlowNetworkFactory;
-import com.powsybl.openloadflow.network.impl.extensions.SubstationAutomationSystemsAdder;
+import com.powsybl.openloadflow.network.AutomationSystemNetworkFactory;
 import org.junit.jupiter.api.Test;
 
 import static com.powsybl.openloadflow.util.LoadFlowAssert.assertCurrentEquals;
@@ -26,65 +23,15 @@
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
-class AutomationSystemTest extends AbstractLoadFlowNetworkFactory {
-
-    /**
-     * b1 and b2 are the HV network
-     * b3 and b4 are the LV network
-     * when breaker br1 is closed, the network is operated "coupled" and the LV line l34 have a very high intensity
-     * opening the breaker br1 allow reducing the intensity of line l34 (even if network is in that case less robust
-     * to any contingency)
-     *      g1
-     *      |      l12
-     * b1 ====-------------==== b2
-     *      |                |
-     *      8 tr1            8 tr2
-     *      |   b3p  l34    |
-     * b3 ====*====--------==== b4
-     *      br1 |        |
-     *         ld3      ld4
-     */
-    private static Network createNetwork() {
-        Network network = Network.create("OverloadManagementSystemTestCase", "code");
-        Bus b1 = createBus(network, "s1", "b1", 225);
-        Bus b2 = createBus(network, "s2", "b2", 225);
-        Bus b3 = createBus(network, "s1", "b3", 63);
-        Bus b3p = b3.getVoltageLevel().getBusBreakerView().newBus()
-                .setId("b3p")
-                .add();
-        Bus b4 = createBus(network, "s2", "b4", 63);
-        createGenerator(b1, "g1", 100, 230);
-        createLoad(b3p, "ld3", 3, 2);
-        createLoad(b4, "ld4", 90, 60);
-        createLine(network, b1, b2, "l12", 0.1, 3);
-        createLine(network, b3p, b4, "l34", 0.05, 3.2);
-        b3.getVoltageLevel().getBusBreakerView().newSwitch()
-                .setId("br1")
-                .setBus1("b3")
-                .setBus2("b3p")
-                .setOpen(false)
-                .add();
-        createTransformer(network, "s1", b1, b3, "tr1", 0.2, 2, 1);
-        createTransformer(network, "s2", b2, b4, "tr2", 0.3, 3, 1);
-        return network;
-    }
+class AutomationSystemTest {
 
     @Test
     void test() {
-        Network network = createNetwork();
+        Network network = AutomationSystemNetworkFactory.create();
         LoadFlow.Runner loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(new DenseMatrixFactory()));
         LoadFlowParameters parameters = new LoadFlowParameters();
         OpenLoadFlowParameters.create(parameters)
                 .setSimulateAutomationSystems(true);
-        Substation s1 = network.getSubstation("s1");
-        s1.newExtension(SubstationAutomationSystemsAdder.class)
-                .newOverloadManagementSystem()
-                    .withLineIdToMonitor("l34")
-                    .withThreshold(300)
-                    .withSwitchIdToOperate("br1")
-                    .withSwitchOpen(true)
-                .add()
-            .add();
         LoadFlowResult result = loadFlowRunner.run(network, parameters);
         assertSame(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus());
         Line l12 = network.getLine("l12");
diff --git a/src/test/java/com/powsybl/openloadflow/network/AutomationSystemNetworkFactory.java b/src/test/java/com/powsybl/openloadflow/network/AutomationSystemNetworkFactory.java
new file mode 100644
index 0000000000..9a3fbda396
--- /dev/null
+++ b/src/test/java/com/powsybl/openloadflow/network/AutomationSystemNetworkFactory.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.network;
+
+import com.powsybl.iidm.network.Bus;
+import com.powsybl.iidm.network.Network;
+import com.powsybl.iidm.network.Substation;
+import com.powsybl.openloadflow.network.impl.extensions.SubstationAutomationSystemsAdder;
+import org.joda.time.DateTime;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+public final class AutomationSystemNetworkFactory extends AbstractLoadFlowNetworkFactory {
+
+    private AutomationSystemNetworkFactory() {
+    }
+
+    /**
+     * b1 and b2 are the HV network
+     * b3 and b4 are the LV network
+     * when breaker br1 is closed, the network is operated "coupled" and the LV line l34 have a very high intensity
+     * opening the breaker br1 allow reducing the intensity of line l34 (even if network is in that case less robust
+     * to any contingency)
+     * g1
+     * |      l12
+     * b1 ====-------------==== b2
+     * |                |
+     * 8 tr1            8 tr2
+     * |   b3p  l34    |
+     * b3 ====*====--------==== b4
+     * br1 |        |
+     * ld3      ld4
+     */
+    public static Network create() {
+        Network network = Network.create("OverloadManagementSystemTestCase", "code");
+        network.setCaseDate(DateTime.parse("2020-04-05T14:11:00.000+01:00"));
+        Bus b1 = createBus(network, "s1", "b1", 225);
+        Bus b2 = createBus(network, "s2", "b2", 225);
+        Bus b3 = createBus(network, "s1", "b3", 63);
+        Bus b3p = b3.getVoltageLevel().getBusBreakerView().newBus()
+                .setId("b3p")
+                .add();
+        Bus b4 = createBus(network, "s2", "b4", 63);
+        createGenerator(b1, "g1", 100, 230);
+        createLoad(b3p, "ld3", 3, 2);
+        createLoad(b4, "ld4", 90, 60);
+        createLine(network, b1, b2, "l12", 0.1, 3);
+        createLine(network, b3p, b4, "l34", 0.05, 3.2);
+        b3.getVoltageLevel().getBusBreakerView().newSwitch()
+                .setId("br1")
+                .setBus1("b3")
+                .setBus2("b3p")
+                .setOpen(false)
+                .add();
+        createTransformer(network, "s1", b1, b3, "tr1", 0.2, 2, 1);
+        createTransformer(network, "s2", b2, b4, "tr2", 0.3, 3, 1);
+        Substation s1 = network.getSubstation("s1");
+        s1.newExtension(SubstationAutomationSystemsAdder.class)
+            .newOverloadManagementSystem()
+                .withLineIdToMonitor("l34")
+                .withThreshold(300)
+                .withSwitchIdToOperate("br1")
+                .withSwitchOpen(true)
+            .add()
+            .add();
+        return network;
+    }
+}
diff --git a/src/test/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsTest.java b/src/test/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsTest.java
new file mode 100644
index 0000000000..6326b3f18d
--- /dev/null
+++ b/src/test/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsTest.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2023, 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.openloadflow.network.impl.extensions;
+
+import com.powsybl.commons.test.AbstractConverterTest;
+import com.powsybl.iidm.network.Network;
+import com.powsybl.iidm.xml.NetworkXml;
+import com.powsybl.openloadflow.network.AutomationSystemNetworkFactory;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+/**
+ * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ */
+class SubstationAutomationSystemsTest extends AbstractConverterTest {
+
+    @Test
+    void xmlRoundTripTest() throws IOException {
+        Network network = AutomationSystemNetworkFactory.create();
+
+        Network network2 = roundTripXmlTest(network,
+                NetworkXml::writeAndValidate,
+                NetworkXml::read,
+                "/substationAutomationSystemsRef.xml");
+
+        SubstationAutomationSystems substationAutomationSystems = network2.getSubstation("s1").getExtension(SubstationAutomationSystems.class);
+        assertNotNull(substationAutomationSystems);
+        assertEquals(1, substationAutomationSystems.getOverloadManagementSystems().size());
+    }
+}
diff --git a/src/test/resources/substationAutomationSystemsRef.xml b/src/test/resources/substationAutomationSystemsRef.xml
new file mode 100644
index 0000000000..52a64a4880
--- /dev/null
+++ b/src/test/resources/substationAutomationSystemsRef.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<iidm:network xmlns:iidm="http://www.powsybl.org/schema/iidm/1_11" xmlns:sas="http://www.powsybl.org/schema/iidm/ext/substation_automation_systems/1_0" id="OverloadManagementSystemTestCase" caseDate="2020-04-05T14:11:00.000+01:00" forecastDistance="0" sourceFormat="code" minimumValidationLevel="STEADY_STATE_HYPOTHESIS">
+    <iidm:substation id="s1" country="FR">
+        <iidm:voltageLevel id="b1_vl" nominalV="225.0" topologyKind="BUS_BREAKER">
+            <iidm:busBreakerTopology>
+                <iidm:bus id="b1"/>
+            </iidm:busBreakerTopology>
+            <iidm:generator id="g1" energySource="OTHER" minP="0.0" maxP="100.0" voltageRegulatorOn="true" targetP="100.0" targetV="230.0" bus="b1" connectableBus="b1" p="-100.0" q="0.0">
+                <iidm:minMaxReactiveLimits minQ="-1.7976931348623157E308" maxQ="1.7976931348623157E308"/>
+            </iidm:generator>
+        </iidm:voltageLevel>
+        <iidm:voltageLevel id="b3_vl" nominalV="63.0" topologyKind="BUS_BREAKER">
+            <iidm:busBreakerTopology>
+                <iidm:bus id="b3"/>
+                <iidm:bus id="b3p"/>
+                <iidm:switch id="br1" kind="BREAKER" retained="true" open="false" bus1="b3" bus2="b3p"/>
+            </iidm:busBreakerTopology>
+            <iidm:load id="ld3" loadType="UNDEFINED" p0="3.0" q0="2.0" bus="b3p" connectableBus="b3p" p="3.0" q="2.0"/>
+        </iidm:voltageLevel>
+        <iidm:twoWindingsTransformer id="tr1" r="0.2" x="2.0" g="0.0" b="0.0" ratedU1="225.0" ratedU2="63.0" bus1="b1" connectableBus1="b1" voltageLevelId1="b1_vl" bus2="b3" connectableBus2="b3" voltageLevelId2="b3_vl"/>
+    </iidm:substation>
+    <iidm:substation id="s2" country="FR">
+        <iidm:voltageLevel id="b2_vl" nominalV="225.0" topologyKind="BUS_BREAKER">
+            <iidm:busBreakerTopology>
+                <iidm:bus id="b2"/>
+            </iidm:busBreakerTopology>
+        </iidm:voltageLevel>
+        <iidm:voltageLevel id="b4_vl" nominalV="63.0" topologyKind="BUS_BREAKER">
+            <iidm:busBreakerTopology>
+                <iidm:bus id="b4"/>
+            </iidm:busBreakerTopology>
+            <iidm:load id="ld4" loadType="UNDEFINED" p0="90.0" q0="60.0" bus="b4" connectableBus="b4" p="90.0" q="60.0"/>
+        </iidm:voltageLevel>
+        <iidm:twoWindingsTransformer id="tr2" r="0.3" x="3.0" g="0.0" b="0.0" ratedU1="225.0" ratedU2="63.0" bus1="b2" connectableBus1="b2" voltageLevelId1="b2_vl" bus2="b4" connectableBus2="b4" voltageLevelId2="b4_vl"/>
+    </iidm:substation>
+    <iidm:line id="l12" r="0.1" x="3.0" g1="0.0" b1="0.0" g2="0.0" b2="0.0" bus1="b1" connectableBus1="b1" voltageLevelId1="b1_vl" bus2="b2" connectableBus2="b2" voltageLevelId2="b2_vl"/>
+    <iidm:line id="l34" r="0.05" x="3.2" g1="0.0" b1="0.0" g2="0.0" b2="0.0" bus1="b3p" connectableBus1="b3p" voltageLevelId1="b3_vl" bus2="b4" connectableBus2="b4" voltageLevelId2="b4_vl"/>
+    <iidm:extension id="s1">
+        <sas:substationAutomationSystems>
+            <sas:overloadManagementSystem lineIdToMonitor="l34" threshold="300.0" switchIdToOperate="br1" switchOpen="true"/>
+        </sas:substationAutomationSystems>
+    </iidm:extension>
+</iidm:network>
\ No newline at end of file
diff --git a/src/test/resources/xsd/substationAutomationSystems.xsd b/src/test/resources/xsd/substationAutomationSystems.xsd
new file mode 100644
index 0000000000..9f67ab879a
--- /dev/null
+++ b/src/test/resources/xsd/substationAutomationSystems.xsd
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Copyright (c) 2023, 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/.
+
+-->
+<xs:schema version="1.0"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema"
+           xmlns:sas="http://www.powsybl.org/schema/iidm/ext/substation_automation_systems/1_0"
+           targetNamespace="http://www.powsybl.org/schema/iidm/ext/substation_automation_systems/1_0"
+           elementFormDefault="qualified">
+    <xs:complexType name="OverloadManagementSystem">
+        <xs:attribute name="lineIdToMonitor" use="required" type="xs:string"/>
+        <xs:attribute name="threshold" use="required" type="xs:double"/>
+        <xs:attribute name="switchIdToOperate" use="required" type="xs:string"/>
+        <xs:attribute name="switchOpen" use="required" type="xs:boolean"/>
+    </xs:complexType>
+    <xs:element name="substationAutomationSystems">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="overloadManagementSystem" type="sas:OverloadManagementSystem" minOccurs="0" maxOccurs="unbounded"/>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+</xs:schema>

From 7518849bf1f5a2e233459e0dd01a01c65d8d69ac Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Mon, 16 Oct 2023 21:54:39 +0200
Subject: [PATCH 19/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../SubstationAutomationSystemsTest.java      | 21 +++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/src/test/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsTest.java b/src/test/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsTest.java
index 6326b3f18d..d0a720153f 100644
--- a/src/test/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsTest.java
+++ b/src/test/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsTest.java
@@ -6,6 +6,7 @@
  */
 package com.powsybl.openloadflow.network.impl.extensions;
 
+import com.powsybl.commons.PowsyblException;
 import com.powsybl.commons.test.AbstractConverterTest;
 import com.powsybl.iidm.network.Network;
 import com.powsybl.iidm.xml.NetworkXml;
@@ -14,14 +15,30 @@
 
 import java.io.IOException;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.*;
 
 /**
  * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
  */
 class SubstationAutomationSystemsTest extends AbstractConverterTest {
 
+    @Test
+    void errorTest() {
+        Network network = AutomationSystemNetworkFactory.create();
+        var s2 = network.getSubstation("s2");
+
+        var adder = s2.newExtension(SubstationAutomationSystemsAdder.class)
+                .newOverloadManagementSystem();
+        var e = assertThrows(PowsyblException.class, adder::add);
+        assertEquals("Line ID to monitor is not set", e.getMessage());
+        adder.withLineIdToMonitor("x");
+        e = assertThrows(PowsyblException.class, adder::add);
+        assertEquals("Threshold is not set", e.getMessage());
+        adder.withThreshold(1000);
+        e = assertThrows(PowsyblException.class, adder::add);
+        assertEquals("Switch ID to operate is not set", e.getMessage());
+    }
+
     @Test
     void xmlRoundTripTest() throws IOException {
         Network network = AutomationSystemNetworkFactory.create();

From c7f61adb7615b03fa1c8fcd7739fb08c6bd0d1e2 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Mon, 16 Oct 2023 22:00:50 +0200
Subject: [PATCH 20/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../network/impl/LfNetworkLoaderImpl.java     | 24 +++++++++++--------
 .../openloadflow/network/impl/Networks.java   | 24 +++++++++++--------
 2 files changed, 28 insertions(+), 20 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
index 6aaa22d93c..6df81f9561 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
@@ -850,21 +850,25 @@ private static void createVoltageAngleLimits(Network network, LfNetwork lfNetwor
         });
     }
 
+    private static void createOverloadManagementSystem(LfNetwork lfNetwork, OverloadManagementSystem system) {
+        LfBranch lfLineToMonitor = lfNetwork.getBranchById(system.getLineIdToMonitor());
+        LfSwitch lfSwitchToOperate = (LfSwitch) lfNetwork.getBranchById(system.getSwitchIdToOperate());
+        if (lfLineToMonitor != null && lfSwitchToOperate != null) {
+            LfBus bus = lfLineToMonitor.getBus1() != null ? lfLineToMonitor.getBus1() : lfLineToMonitor.getBus2();
+            double threshold = system.getThreshold() / PerUnit.ib(bus.getNominalV());
+            lfNetwork.addOverloadManagementSystem(new LfOverloadManagementSystem(lfLineToMonitor, threshold, lfSwitchToOperate, system.isSwitchOpen()));
+        } else {
+            LOGGER.warn("Invalid overload management system: line to monitor is '{}', switch to operate is '{}'",
+                    system.getLineIdToMonitor(), system.getSwitchIdToOperate());
+        }
+    }
+
     private void createAutomationSystems(Network network, LfNetwork lfNetwork) {
         for (Substation substation : network.getSubstations()) {
             SubstationAutomationSystems systems = substation.getExtension(SubstationAutomationSystems.class);
             if (systems != null) {
                 for (OverloadManagementSystem system : systems.getOverloadManagementSystems()) {
-                    LfBranch lfLineToMonitor = lfNetwork.getBranchById(system.getLineIdToMonitor());
-                    LfSwitch lfSwitchToOperate = (LfSwitch) lfNetwork.getBranchById(system.getSwitchIdToOperate());
-                    if (lfLineToMonitor != null && lfSwitchToOperate != null) {
-                        LfBus bus = lfLineToMonitor.getBus1() != null ? lfLineToMonitor.getBus1() : lfLineToMonitor.getBus2(); // FIXME
-                        double threshold = system.getThreshold() / PerUnit.ib(bus.getNominalV());
-                        lfNetwork.addOverloadManagementSystem(new LfOverloadManagementSystem(lfLineToMonitor, threshold, lfSwitchToOperate, system.isSwitchOpen()));
-                    } else {
-                        LOGGER.warn("Invalid overload management system: line to monitor is '{}', switch to operate is '{}'",
-                                system.getLineIdToMonitor(), system.getSwitchIdToOperate());
-                    }
+                    createOverloadManagementSystem(lfNetwork, system);
                 }
             }
         }
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
index 08f58e4f23..5cb59f5f4b 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
@@ -141,19 +141,23 @@ private static void restoreInitialTopology(LfNetwork network, Set<Switch> allSwi
         removedBranches.forEach(branch -> branch.setDisabled(true));
     }
 
-    private static void addSwitchesOperatedByAutomata(Network network, LfTopoConfig topoConfig) {
+    private static void addSwitchesOperatedByAutomationSystem(Network network, LfTopoConfig topoConfig, OverloadManagementSystem system) {
+        Switch aSwitch = network.getSwitch(system.getSwitchIdToOperate());
+        if (aSwitch != null) {
+            if (system.isSwitchOpen()) {
+                topoConfig.getSwitchesToOpen().add(aSwitch);
+            } else {
+                topoConfig.getSwitchesToClose().add(aSwitch);
+            }
+        }
+    }
+
+    private static void addSwitchesOperatedByAutomationSystem(Network network, LfTopoConfig topoConfig) {
         for (Substation substation : network.getSubstations()) {
             SubstationAutomationSystems systems = substation.getExtension(SubstationAutomationSystems.class);
             if (systems != null) {
                 for (OverloadManagementSystem system : systems.getOverloadManagementSystems()) {
-                    Switch aSwitch = network.getSwitch(system.getSwitchIdToOperate());
-                    if (aSwitch != null) {
-                        if (system.isSwitchOpen()) {
-                            topoConfig.getSwitchesToOpen().add(aSwitch);
-                        } else {
-                            topoConfig.getSwitchesToClose().add(aSwitch);
-                        }
-                    }
+                    addSwitchesOperatedByAutomationSystem(network, topoConfig, system);
                 }
             }
         }
@@ -169,7 +173,7 @@ public static LfNetworkList load(Network network, LfNetworkParameters networkPar
         LfTopoConfig modifiedTopoConfig;
         if (networkParameters.isSimulateAutomationSystems()) {
             modifiedTopoConfig = new LfTopoConfig(topoConfig);
-            addSwitchesOperatedByAutomata(network, modifiedTopoConfig);
+            addSwitchesOperatedByAutomationSystem(network, modifiedTopoConfig);
             if (modifiedTopoConfig.isBreaker()) {
                 networkParameters.setBreakers(true);
             }

From 83faddf066974696fef8b3901c7457c885c6c875 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Mon, 16 Oct 2023 22:15:08 +0200
Subject: [PATCH 21/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../java/com/powsybl/openloadflow/network/impl/Networks.java  | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
index 5cb59f5f4b..63de31d653 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/Networks.java
@@ -127,9 +127,7 @@ private static void restoreInitialTopology(LfNetwork network, Set<Switch> allSwi
         connectivity.startTemporaryChanges();
         allSwitchesToClose.stream().map(Identifiable::getId).forEach(id -> {
             LfBranch branch = network.getBranchById(id);
-            if (branch != null) {
-                connectivity.removeEdge(branch);
-            }
+            connectivity.removeEdge(branch);
         });
         Set<LfBus> removedBuses = connectivity.getVerticesRemovedFromMainComponent();
         removedBuses.forEach(bus -> bus.setDisabled(true));

From f8e1be14a145c66187cea485949d86a88b80df00 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Tue, 17 Oct 2023 12:43:26 +0200
Subject: [PATCH 22/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../network/impl/LfNetworkLoaderImpl.java     | 20 ++++++++++---------
 .../extensions/OverloadManagementSystem.java  |  4 ++++
 .../OverloadManagementSystemAdder.java        |  2 ++
 .../OverloadManagementSystemAdderImpl.java    | 10 +++++++++-
 .../OverloadManagementSystemImpl.java         | 15 +++++++++++++-
 ...stationAutomationSystemsXmlSerializer.java |  3 +++
 .../substationAutomationSystemsRef.xml        |  2 +-
 .../xsd/substationAutomationSystems.xsd       |  1 +
 8 files changed, 45 insertions(+), 12 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
index 6df81f9561..a3d1edd353 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
@@ -851,15 +851,17 @@ private static void createVoltageAngleLimits(Network network, LfNetwork lfNetwor
     }
 
     private static void createOverloadManagementSystem(LfNetwork lfNetwork, OverloadManagementSystem system) {
-        LfBranch lfLineToMonitor = lfNetwork.getBranchById(system.getLineIdToMonitor());
-        LfSwitch lfSwitchToOperate = (LfSwitch) lfNetwork.getBranchById(system.getSwitchIdToOperate());
-        if (lfLineToMonitor != null && lfSwitchToOperate != null) {
-            LfBus bus = lfLineToMonitor.getBus1() != null ? lfLineToMonitor.getBus1() : lfLineToMonitor.getBus2();
-            double threshold = system.getThreshold() / PerUnit.ib(bus.getNominalV());
-            lfNetwork.addOverloadManagementSystem(new LfOverloadManagementSystem(lfLineToMonitor, threshold, lfSwitchToOperate, system.isSwitchOpen()));
-        } else {
-            LOGGER.warn("Invalid overload management system: line to monitor is '{}', switch to operate is '{}'",
-                    system.getLineIdToMonitor(), system.getSwitchIdToOperate());
+        if (system.isEnabled()) {
+            LfBranch lfLineToMonitor = lfNetwork.getBranchById(system.getLineIdToMonitor());
+            LfSwitch lfSwitchToOperate = (LfSwitch) lfNetwork.getBranchById(system.getSwitchIdToOperate());
+            if (lfLineToMonitor != null && lfSwitchToOperate != null) {
+                LfBus bus = lfLineToMonitor.getBus1() != null ? lfLineToMonitor.getBus1() : lfLineToMonitor.getBus2();
+                double threshold = system.getThreshold() / PerUnit.ib(bus.getNominalV());
+                lfNetwork.addOverloadManagementSystem(new LfOverloadManagementSystem(lfLineToMonitor, threshold, lfSwitchToOperate, system.isSwitchOpen()));
+            } else {
+                LOGGER.warn("Invalid overload management system: line to monitor is '{}', switch to operate is '{}'",
+                        system.getLineIdToMonitor(), system.getSwitchIdToOperate());
+            }
         }
     }
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystem.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystem.java
index 7c3153d1bf..409a712d85 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystem.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystem.java
@@ -11,6 +11,10 @@
  */
 public interface OverloadManagementSystem {
 
+    boolean isEnabled();
+
+    void setEnabled(boolean enabled);
+
     String getLineIdToMonitor();
 
     double getThreshold();
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdder.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdder.java
index 38ab904cbe..7cfeebb863 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdder.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdder.java
@@ -11,6 +11,8 @@
  */
 public interface OverloadManagementSystemAdder<T> {
 
+    OverloadManagementSystemAdder<T> withEnabled(boolean enabled);
+
     OverloadManagementSystemAdder<T> withLineIdToMonitor(String lineId);
 
     OverloadManagementSystemAdder<T> withThreshold(double threshold);
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdderImpl.java
index b9af83471b..30e3957eca 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdderImpl.java
@@ -25,6 +25,8 @@ public OverloadManagementSystemAdderImpl(T parent, Consumer<OverloadManagementSy
         this.parentAdder = Objects.requireNonNull(parentAdder);
     }
 
+    private boolean enabled = true;
+
     private String lineIdToMonitor;
 
     private double threshold = Double.NaN;
@@ -33,6 +35,12 @@ public OverloadManagementSystemAdderImpl(T parent, Consumer<OverloadManagementSy
 
     private boolean switchOpen = true;
 
+    @Override
+    public OverloadManagementSystemAdder<T> withEnabled(boolean enabled) {
+        this.enabled = enabled;
+        return this;
+    }
+
     @Override
     public OverloadManagementSystemAdderImpl<T> withLineIdToMonitor(String lineIdToMonitor) {
         this.lineIdToMonitor = Objects.requireNonNull(lineIdToMonitor);
@@ -68,7 +76,7 @@ public T add() {
         if (switchIdToOperate == null) {
             throw new PowsyblException("Switch ID to operate is not set");
         }
-        OverloadManagementSystemImpl system = new OverloadManagementSystemImpl(lineIdToMonitor, threshold, switchIdToOperate, switchOpen);
+        OverloadManagementSystemImpl system = new OverloadManagementSystemImpl(enabled, lineIdToMonitor, threshold, switchIdToOperate, switchOpen);
         parentAdder.accept(system);
         return parent;
     }
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemImpl.java
index 11f4c17dc8..66eb624840 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemImpl.java
@@ -13,6 +13,8 @@
  */
 public class OverloadManagementSystemImpl implements OverloadManagementSystem {
 
+    private boolean enabled;
+
     private final String lineIdToMonitor;
 
     private final double threshold;
@@ -21,13 +23,24 @@ public class OverloadManagementSystemImpl implements OverloadManagementSystem {
 
     private final boolean switchOpen;
 
-    public OverloadManagementSystemImpl(String lineIdToMonitor, double threshold, String switchIdToOperate, boolean switchOpen) {
+    public OverloadManagementSystemImpl(boolean enabled, String lineIdToMonitor, double threshold, String switchIdToOperate, boolean switchOpen) {
+        this.enabled = enabled;
         this.lineIdToMonitor = Objects.requireNonNull(lineIdToMonitor);
         this.threshold = threshold;
         this.switchIdToOperate = Objects.requireNonNull(switchIdToOperate);
         this.switchOpen = switchOpen;
     }
 
+    @Override
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
     @Override
     public String getLineIdToMonitor() {
         return lineIdToMonitor;
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java
index de9dc8864c..63840a83a5 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java
@@ -31,6 +31,7 @@ public SubstationAutomationSystemsXmlSerializer() {
     public void write(SubstationAutomationSystems systems, XmlWriterContext context) throws XMLStreamException {
         for (var oms : systems.getOverloadManagementSystems()) {
             context.getWriter().writeEmptyElement(getNamespaceUri(), "overloadManagementSystem");
+            context.getWriter().writeAttribute("enabled", Boolean.toString(oms.isEnabled()));
             context.getWriter().writeAttribute("lineIdToMonitor", oms.getLineIdToMonitor());
             XmlUtil.writeDouble("threshold", oms.getThreshold(), context.getWriter());
             context.getWriter().writeAttribute("switchIdToOperate", oms.getSwitchIdToOperate());
@@ -42,11 +43,13 @@ public void write(SubstationAutomationSystems systems, XmlWriterContext context)
     public SubstationAutomationSystems read(Substation substation, XmlReaderContext context) throws XMLStreamException {
         SubstationAutomationSystemsAdder adder = substation.newExtension(SubstationAutomationSystemsAdder.class);
         XmlUtil.readUntilEndElement(getExtensionName(), context.getReader(), () -> {
+            boolean enabled = XmlUtil.readBoolAttribute(context.getReader(), "enabled");
             String lineIdToMonitor = context.getReader().getAttributeValue(null, "lineIdToMonitor");
             double threshold = XmlUtil.readDoubleAttribute(context.getReader(), "threshold");
             String switchIdToOperate = context.getReader().getAttributeValue(null, "switchIdToOperate");
             boolean switchOpen = XmlUtil.readBoolAttribute(context.getReader(), "switchOpen");
             adder.newOverloadManagementSystem()
+                    .withEnabled(enabled)
                     .withLineIdToMonitor(lineIdToMonitor)
                     .withThreshold(threshold)
                     .withSwitchIdToOperate(switchIdToOperate)
diff --git a/src/test/resources/substationAutomationSystemsRef.xml b/src/test/resources/substationAutomationSystemsRef.xml
index 52a64a4880..690d9c3832 100644
--- a/src/test/resources/substationAutomationSystemsRef.xml
+++ b/src/test/resources/substationAutomationSystemsRef.xml
@@ -37,7 +37,7 @@
     <iidm:line id="l34" r="0.05" x="3.2" g1="0.0" b1="0.0" g2="0.0" b2="0.0" bus1="b3p" connectableBus1="b3p" voltageLevelId1="b3_vl" bus2="b4" connectableBus2="b4" voltageLevelId2="b4_vl"/>
     <iidm:extension id="s1">
         <sas:substationAutomationSystems>
-            <sas:overloadManagementSystem lineIdToMonitor="l34" threshold="300.0" switchIdToOperate="br1" switchOpen="true"/>
+            <sas:overloadManagementSystem enabled="true" lineIdToMonitor="l34" threshold="300.0" switchIdToOperate="br1" switchOpen="true"/>
         </sas:substationAutomationSystems>
     </iidm:extension>
 </iidm:network>
\ No newline at end of file
diff --git a/src/test/resources/xsd/substationAutomationSystems.xsd b/src/test/resources/xsd/substationAutomationSystems.xsd
index 9f67ab879a..630b8970be 100644
--- a/src/test/resources/xsd/substationAutomationSystems.xsd
+++ b/src/test/resources/xsd/substationAutomationSystems.xsd
@@ -12,6 +12,7 @@
            targetNamespace="http://www.powsybl.org/schema/iidm/ext/substation_automation_systems/1_0"
            elementFormDefault="qualified">
     <xs:complexType name="OverloadManagementSystem">
+        <xs:attribute name="enabled" use="required" type="xs:boolean"/>
         <xs:attribute name="lineIdToMonitor" use="required" type="xs:string"/>
         <xs:attribute name="threshold" use="required" type="xs:double"/>
         <xs:attribute name="switchIdToOperate" use="required" type="xs:string"/>

From eee52a553b57ff2a8fefa44fffb03ed65af157c3 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Tue, 17 Oct 2023 12:45:52 +0200
Subject: [PATCH 23/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
index 293ec169f3..f3d0a54b8d 100644
--- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
+++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
@@ -35,7 +35,6 @@
 import com.powsybl.openloadflow.network.*;
 import com.powsybl.openloadflow.network.impl.LfNetworkList;
 import com.powsybl.openloadflow.network.impl.LfNetworkLoaderImpl;
-import com.powsybl.openloadflow.network.impl.LfTopoConfig;
 import com.powsybl.openloadflow.network.impl.Networks;
 import com.powsybl.openloadflow.network.util.ZeroImpedanceFlows;
 import com.powsybl.openloadflow.util.*;

From dc4f77e6a050bd78dc740647cb501102a860d101 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Fri, 20 Oct 2023 13:03:34 +0200
Subject: [PATCH 24/30] Fix

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../ac/outerloop/AutomationSystemOuterLoop.java      | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
index ae8498f494..f5d6342e60 100644
--- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
+++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
@@ -63,10 +63,14 @@ public OuterLoopStatus check(AcOuterLoopContext context, Reporter reporter) {
         if (branchesToOpen.size() + branchesToClose.size() > 0) {
             GraphConnectivity<LfBus, LfBranch> connectivity = network.getConnectivity();
             connectivity.startTemporaryChanges();
-            branchesToOpen.forEach(connectivity::removeEdge);
-            branchesToClose.forEach(branch -> connectivity.addEdge(branch.getBus1(), branch.getBus2(), branch));
-            LfAction.updateBusesAndBranchStatus(connectivity);
-            status = OuterLoopStatus.UNSTABLE;
+            try {
+                branchesToOpen.forEach(connectivity::removeEdge);
+                branchesToClose.forEach(branch -> connectivity.addEdge(branch.getBus1(), branch.getBus2(), branch));
+                LfAction.updateBusesAndBranchStatus(connectivity);
+                status = OuterLoopStatus.UNSTABLE;
+            } finally {
+                connectivity.undoTemporaryChanges();
+            }
         }
 
         return status;

From a1dc2b85bf0dc967194c39d753aea33bc348417d Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Fri, 20 Oct 2023 17:04:02 +0200
Subject: [PATCH 25/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../ac/outerloop/AutomationSystemOuterLoop.java        |  2 +-
 .../network/LfOverloadManagementSystem.java            | 10 +++++-----
 .../openloadflow/network/impl/LfNetworkLoaderImpl.java |  4 ++--
 .../impl/extensions/OverloadManagementSystem.java      |  2 +-
 .../impl/extensions/OverloadManagementSystemAdder.java |  2 +-
 .../extensions/OverloadManagementSystemAdderImpl.java  | 10 +++++-----
 .../impl/extensions/OverloadManagementSystemImpl.java  | 10 +++++-----
 .../SubstationAutomationSystemsXmlSerializer.java      |  6 +++---
 .../network/AutomationSystemNetworkFactory.java        |  2 +-
 .../extensions/SubstationAutomationSystemsTest.java    |  2 +-
 src/test/resources/substationAutomationSystemsRef.xml  |  2 +-
 src/test/resources/xsd/substationAutomationSystems.xsd |  2 +-
 12 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
index f5d6342e60..090054a165 100644
--- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
+++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
@@ -40,7 +40,7 @@ public OuterLoopStatus check(AcOuterLoopContext context, Reporter reporter) {
         Set<LfBranch> branchesToOpen = new HashSet<>();
         Set<LfBranch> branchesToClose = new HashSet<>();
         for (LfOverloadManagementSystem system : network.getOverloadManagementSystems()) {
-            LfBranch branchToMonitor = system.getBranchToMonitor();
+            LfBranch branchToMonitor = system.getMonitoredBranch();
             if (branchToMonitor.isConnectedAtBothSides()) {
                 double i1 = branchToMonitor.getI1().eval();
                 double threshold = system.getThreshold();
diff --git a/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementSystem.java b/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementSystem.java
index 736a108abc..27e15ef64a 100644
--- a/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementSystem.java
+++ b/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementSystem.java
@@ -15,7 +15,7 @@
  */
 public class LfOverloadManagementSystem {
 
-    private final LfBranch branchToMonitor;
+    private final LfBranch monitoredBranch;
 
     private final double threshold;
 
@@ -23,15 +23,15 @@ public class LfOverloadManagementSystem {
 
     private final boolean switchOpen;
 
-    public LfOverloadManagementSystem(LfBranch branchToMonitor, double threshold, LfSwitch switchToOperate, boolean switchOpen) {
-        this.branchToMonitor = Objects.requireNonNull(branchToMonitor);
+    public LfOverloadManagementSystem(LfBranch monitoredBranch, double threshold, LfSwitch switchToOperate, boolean switchOpen) {
+        this.monitoredBranch = Objects.requireNonNull(monitoredBranch);
         this.threshold = threshold;
         this.switchToOperate = Objects.requireNonNull(switchToOperate);
         this.switchOpen = switchOpen;
     }
 
-    public LfBranch getBranchToMonitor() {
-        return branchToMonitor;
+    public LfBranch getMonitoredBranch() {
+        return monitoredBranch;
     }
 
     public double getThreshold() {
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
index 756a6fd596..0f09e53f95 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java
@@ -851,7 +851,7 @@ private static void createVoltageAngleLimits(Network network, LfNetwork lfNetwor
 
     private static void createOverloadManagementSystem(LfNetwork lfNetwork, OverloadManagementSystem system) {
         if (system.isEnabled()) {
-            LfBranch lfLineToMonitor = lfNetwork.getBranchById(system.getLineIdToMonitor());
+            LfBranch lfLineToMonitor = lfNetwork.getBranchById(system.getMonitoredLineId());
             LfSwitch lfSwitchToOperate = (LfSwitch) lfNetwork.getBranchById(system.getSwitchIdToOperate());
             if (lfLineToMonitor != null && lfSwitchToOperate != null) {
                 LfBus bus = lfLineToMonitor.getBus1() != null ? lfLineToMonitor.getBus1() : lfLineToMonitor.getBus2();
@@ -859,7 +859,7 @@ private static void createOverloadManagementSystem(LfNetwork lfNetwork, Overload
                 lfNetwork.addOverloadManagementSystem(new LfOverloadManagementSystem(lfLineToMonitor, threshold, lfSwitchToOperate, system.isSwitchOpen()));
             } else {
                 LOGGER.warn("Invalid overload management system: line to monitor is '{}', switch to operate is '{}'",
-                        system.getLineIdToMonitor(), system.getSwitchIdToOperate());
+                        system.getMonitoredLineId(), system.getSwitchIdToOperate());
             }
         }
     }
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystem.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystem.java
index 409a712d85..ba19ad8532 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystem.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystem.java
@@ -15,7 +15,7 @@ public interface OverloadManagementSystem {
 
     void setEnabled(boolean enabled);
 
-    String getLineIdToMonitor();
+    String getMonitoredLineId();
 
     double getThreshold();
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdder.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdder.java
index 7cfeebb863..d84007c2e7 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdder.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdder.java
@@ -13,7 +13,7 @@ public interface OverloadManagementSystemAdder<T> {
 
     OverloadManagementSystemAdder<T> withEnabled(boolean enabled);
 
-    OverloadManagementSystemAdder<T> withLineIdToMonitor(String lineId);
+    OverloadManagementSystemAdder<T> withMonitoredLineId(String lineId);
 
     OverloadManagementSystemAdder<T> withThreshold(double threshold);
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdderImpl.java
index 30e3957eca..16a34ca007 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdderImpl.java
@@ -27,7 +27,7 @@ public OverloadManagementSystemAdderImpl(T parent, Consumer<OverloadManagementSy
 
     private boolean enabled = true;
 
-    private String lineIdToMonitor;
+    private String monitoredLineId;
 
     private double threshold = Double.NaN;
 
@@ -42,8 +42,8 @@ public OverloadManagementSystemAdder<T> withEnabled(boolean enabled) {
     }
 
     @Override
-    public OverloadManagementSystemAdderImpl<T> withLineIdToMonitor(String lineIdToMonitor) {
-        this.lineIdToMonitor = Objects.requireNonNull(lineIdToMonitor);
+    public OverloadManagementSystemAdderImpl<T> withMonitoredLineId(String monitoredLineId) {
+        this.monitoredLineId = Objects.requireNonNull(monitoredLineId);
         return this;
     }
 
@@ -67,7 +67,7 @@ public OverloadManagementSystemAdderImpl<T> withSwitchOpen(boolean open) {
 
     @Override
     public T add() {
-        if (lineIdToMonitor == null) {
+        if (monitoredLineId == null) {
             throw new PowsyblException("Line ID to monitor is not set");
         }
         if (Double.isNaN(threshold)) {
@@ -76,7 +76,7 @@ public T add() {
         if (switchIdToOperate == null) {
             throw new PowsyblException("Switch ID to operate is not set");
         }
-        OverloadManagementSystemImpl system = new OverloadManagementSystemImpl(enabled, lineIdToMonitor, threshold, switchIdToOperate, switchOpen);
+        OverloadManagementSystemImpl system = new OverloadManagementSystemImpl(enabled, monitoredLineId, threshold, switchIdToOperate, switchOpen);
         parentAdder.accept(system);
         return parent;
     }
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemImpl.java
index 66eb624840..145e53cf09 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemImpl.java
@@ -15,7 +15,7 @@ public class OverloadManagementSystemImpl implements OverloadManagementSystem {
 
     private boolean enabled;
 
-    private final String lineIdToMonitor;
+    private final String monitoredLineId;
 
     private final double threshold;
 
@@ -23,9 +23,9 @@ public class OverloadManagementSystemImpl implements OverloadManagementSystem {
 
     private final boolean switchOpen;
 
-    public OverloadManagementSystemImpl(boolean enabled, String lineIdToMonitor, double threshold, String switchIdToOperate, boolean switchOpen) {
+    public OverloadManagementSystemImpl(boolean enabled, String monitoredLineId, double threshold, String switchIdToOperate, boolean switchOpen) {
         this.enabled = enabled;
-        this.lineIdToMonitor = Objects.requireNonNull(lineIdToMonitor);
+        this.monitoredLineId = Objects.requireNonNull(monitoredLineId);
         this.threshold = threshold;
         this.switchIdToOperate = Objects.requireNonNull(switchIdToOperate);
         this.switchOpen = switchOpen;
@@ -42,8 +42,8 @@ public void setEnabled(boolean enabled) {
     }
 
     @Override
-    public String getLineIdToMonitor() {
-        return lineIdToMonitor;
+    public String getMonitoredLineId() {
+        return monitoredLineId;
     }
 
     @Override
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java
index 63840a83a5..3adc097806 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java
@@ -32,7 +32,7 @@ public void write(SubstationAutomationSystems systems, XmlWriterContext context)
         for (var oms : systems.getOverloadManagementSystems()) {
             context.getWriter().writeEmptyElement(getNamespaceUri(), "overloadManagementSystem");
             context.getWriter().writeAttribute("enabled", Boolean.toString(oms.isEnabled()));
-            context.getWriter().writeAttribute("lineIdToMonitor", oms.getLineIdToMonitor());
+            context.getWriter().writeAttribute("monitoredLineId", oms.getMonitoredLineId());
             XmlUtil.writeDouble("threshold", oms.getThreshold(), context.getWriter());
             context.getWriter().writeAttribute("switchIdToOperate", oms.getSwitchIdToOperate());
             context.getWriter().writeAttribute("switchOpen", Boolean.toString(oms.isSwitchOpen()));
@@ -44,13 +44,13 @@ public SubstationAutomationSystems read(Substation substation, XmlReaderContext
         SubstationAutomationSystemsAdder adder = substation.newExtension(SubstationAutomationSystemsAdder.class);
         XmlUtil.readUntilEndElement(getExtensionName(), context.getReader(), () -> {
             boolean enabled = XmlUtil.readBoolAttribute(context.getReader(), "enabled");
-            String lineIdToMonitor = context.getReader().getAttributeValue(null, "lineIdToMonitor");
+            String monitoredLineId = context.getReader().getAttributeValue(null, "monitoredLineId");
             double threshold = XmlUtil.readDoubleAttribute(context.getReader(), "threshold");
             String switchIdToOperate = context.getReader().getAttributeValue(null, "switchIdToOperate");
             boolean switchOpen = XmlUtil.readBoolAttribute(context.getReader(), "switchOpen");
             adder.newOverloadManagementSystem()
                     .withEnabled(enabled)
-                    .withLineIdToMonitor(lineIdToMonitor)
+                    .withMonitoredLineId(monitoredLineId)
                     .withThreshold(threshold)
                     .withSwitchIdToOperate(switchIdToOperate)
                     .withSwitchOpen(switchOpen)
diff --git a/src/test/java/com/powsybl/openloadflow/network/AutomationSystemNetworkFactory.java b/src/test/java/com/powsybl/openloadflow/network/AutomationSystemNetworkFactory.java
index 9a3fbda396..fad98c665f 100644
--- a/src/test/java/com/powsybl/openloadflow/network/AutomationSystemNetworkFactory.java
+++ b/src/test/java/com/powsybl/openloadflow/network/AutomationSystemNetworkFactory.java
@@ -62,7 +62,7 @@ public static Network create() {
         Substation s1 = network.getSubstation("s1");
         s1.newExtension(SubstationAutomationSystemsAdder.class)
             .newOverloadManagementSystem()
-                .withLineIdToMonitor("l34")
+                .withMonitoredLineId("l34")
                 .withThreshold(300)
                 .withSwitchIdToOperate("br1")
                 .withSwitchOpen(true)
diff --git a/src/test/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsTest.java b/src/test/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsTest.java
index d0a720153f..8044dbe59f 100644
--- a/src/test/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsTest.java
+++ b/src/test/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsTest.java
@@ -31,7 +31,7 @@ void errorTest() {
                 .newOverloadManagementSystem();
         var e = assertThrows(PowsyblException.class, adder::add);
         assertEquals("Line ID to monitor is not set", e.getMessage());
-        adder.withLineIdToMonitor("x");
+        adder.withMonitoredLineId("x");
         e = assertThrows(PowsyblException.class, adder::add);
         assertEquals("Threshold is not set", e.getMessage());
         adder.withThreshold(1000);
diff --git a/src/test/resources/substationAutomationSystemsRef.xml b/src/test/resources/substationAutomationSystemsRef.xml
index 690d9c3832..28068d6754 100644
--- a/src/test/resources/substationAutomationSystemsRef.xml
+++ b/src/test/resources/substationAutomationSystemsRef.xml
@@ -37,7 +37,7 @@
     <iidm:line id="l34" r="0.05" x="3.2" g1="0.0" b1="0.0" g2="0.0" b2="0.0" bus1="b3p" connectableBus1="b3p" voltageLevelId1="b3_vl" bus2="b4" connectableBus2="b4" voltageLevelId2="b4_vl"/>
     <iidm:extension id="s1">
         <sas:substationAutomationSystems>
-            <sas:overloadManagementSystem enabled="true" lineIdToMonitor="l34" threshold="300.0" switchIdToOperate="br1" switchOpen="true"/>
+            <sas:overloadManagementSystem enabled="true" monitoredLineId="l34" threshold="300.0" switchIdToOperate="br1" switchOpen="true"/>
         </sas:substationAutomationSystems>
     </iidm:extension>
 </iidm:network>
\ No newline at end of file
diff --git a/src/test/resources/xsd/substationAutomationSystems.xsd b/src/test/resources/xsd/substationAutomationSystems.xsd
index 630b8970be..04fb6a6af9 100644
--- a/src/test/resources/xsd/substationAutomationSystems.xsd
+++ b/src/test/resources/xsd/substationAutomationSystems.xsd
@@ -13,7 +13,7 @@
            elementFormDefault="qualified">
     <xs:complexType name="OverloadManagementSystem">
         <xs:attribute name="enabled" use="required" type="xs:boolean"/>
-        <xs:attribute name="lineIdToMonitor" use="required" type="xs:string"/>
+        <xs:attribute name="monitoredLineId" use="required" type="xs:string"/>
         <xs:attribute name="threshold" use="required" type="xs:double"/>
         <xs:attribute name="switchIdToOperate" use="required" type="xs:string"/>
         <xs:attribute name="switchOpen" use="required" type="xs:boolean"/>

From 9018a6e1631e8f924ad3ccff3b2fc9753bea55fd Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Mon, 30 Oct 2023 15:13:39 +0100
Subject: [PATCH 26/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../com/powsybl/openloadflow/OpenLoadFlowProviderTest.java    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
index 107dd840db..e09ad21ad0 100644
--- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
+++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java
@@ -49,7 +49,7 @@ void test() {
     void testDcParameters() {
         Network network = Mockito.mock(Network.class);
         DcLoadFlowParameters dcParameters = OpenLoadFlowParameters.createDcParameters(network, new LoadFlowParameters().setReadSlackBus(true), new OpenLoadFlowParameters(), new DenseMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), true);
-        assertEquals("DcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=false, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=DC, reactiveLimits=false, hvdcAcEmulation=false, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=false, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE, useLoadModel=false), equationSystemCreationParameters=DcEquationSystemCreationParameters(updateFlows=true, forcePhaseControlOffAndAddAngle1Var=true, useTransformerRatio=true, dcApproximationType=IGNORE_R), matrixFactory=DenseMatrixFactory, distributedSlack=true, balanceType=PROPORTIONAL_TO_GENERATION_P_MAX, setVToNan=true, maxOuterLoopIterations=20)",
+        assertEquals("DcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=false, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, reactivePowerRemoteControl=false, loadFlowModel=DC, reactiveLimits=false, hvdcAcEmulation=false, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=false, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE, useLoadModel=false, simulateAutomationSystems=false), equationSystemCreationParameters=DcEquationSystemCreationParameters(updateFlows=true, forcePhaseControlOffAndAddAngle1Var=true, useTransformerRatio=true, dcApproximationType=IGNORE_R), matrixFactory=DenseMatrixFactory, distributedSlack=true, balanceType=PROPORTIONAL_TO_GENERATION_P_MAX, setVToNan=true, maxOuterLoopIterations=20)",
                      dcParameters.toString());
     }
 
@@ -85,7 +85,7 @@ void testGetExtendedVoltageInitializer() {
     @Test
     void specificParametersTest() {
         OpenLoadFlowProvider provider = new OpenLoadFlowProvider();
-        assertEquals(55, provider.getSpecificParameters().size());
+        assertEquals(56, provider.getSpecificParameters().size());
         LoadFlowParameters parameters = new LoadFlowParameters();
 
         provider.loadSpecificParameters(Collections.emptyMap())

From b96d523361faf49cd3c123cf5e00f15255f66663 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Mon, 30 Oct 2023 15:14:30 +0100
Subject: [PATCH 27/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../ac/outerloop/AutomationSystemOuterLoop.java     | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
index 090054a165..cc46b2783e 100644
--- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
+++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
@@ -62,15 +62,10 @@ public OuterLoopStatus check(AcOuterLoopContext context, Reporter reporter) {
 
         if (branchesToOpen.size() + branchesToClose.size() > 0) {
             GraphConnectivity<LfBus, LfBranch> connectivity = network.getConnectivity();
-            connectivity.startTemporaryChanges();
-            try {
-                branchesToOpen.forEach(connectivity::removeEdge);
-                branchesToClose.forEach(branch -> connectivity.addEdge(branch.getBus1(), branch.getBus2(), branch));
-                LfAction.updateBusesAndBranchStatus(connectivity);
-                status = OuterLoopStatus.UNSTABLE;
-            } finally {
-                connectivity.undoTemporaryChanges();
-            }
+            branchesToOpen.forEach(connectivity::removeEdge);
+            branchesToClose.forEach(branch -> connectivity.addEdge(branch.getBus1(), branch.getBus2(), branch));
+            LfAction.updateBusesAndBranchStatus(connectivity);
+            status = OuterLoopStatus.UNSTABLE;
         }
 
         return status;

From f77f136c3b003c8cf6fc415d0637f44adf999e5c Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Mon, 30 Oct 2023 18:28:55 +0100
Subject: [PATCH 28/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../powsybl/openloadflow/OpenLoadFlowProvider.java    |  1 +
 .../EvenShiloachGraphDecrementalConnectivity.java     |  5 +++++
 .../powsybl/openloadflow/graph/GraphConnectivity.java |  2 ++
 .../graph/MinimumSpanningTreeGraphConnectivity.java   |  5 +++++
 .../openloadflow/graph/NaiveGraphConnectivity.java    |  5 +++++
 .../com/powsybl/openloadflow/network/LfNetwork.java   |  6 ++++++
 .../openloadflow/sa/OpenSecurityAnalysisProvider.java | 11 ++++++++---
 .../openloadflow/sensi/AcSensitivityAnalysis.java     |  3 ++-
 8 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
index f3d0a54b8d..4cfa295e6d 100644
--- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
+++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
@@ -107,6 +107,7 @@ private static LoadFlowResult.ComponentResult.Status convertStatus(AcLoadFlowRes
 
     private GraphConnectivityFactory<LfBus, LfBranch> getConnectivityFactory(OpenLoadFlowParameters parametersExt) {
         return parametersExt.isNetworkCacheEnabled() && !parametersExt.getActionableSwitchesIds().isEmpty()
+                || parametersExt.isSimulateAutomationSystems()
                 ? new NaiveGraphConnectivityFactory<>(LfBus::getNum)
                 : connectivityFactory;
     }
diff --git a/src/main/java/com/powsybl/openloadflow/graph/EvenShiloachGraphDecrementalConnectivity.java b/src/main/java/com/powsybl/openloadflow/graph/EvenShiloachGraphDecrementalConnectivity.java
index d333e75285..283d1af226 100644
--- a/src/main/java/com/powsybl/openloadflow/graph/EvenShiloachGraphDecrementalConnectivity.java
+++ b/src/main/java/com/powsybl/openloadflow/graph/EvenShiloachGraphDecrementalConnectivity.java
@@ -80,6 +80,11 @@ protected void updateComponents() {
         computeConnectivity();
     }
 
+    @Override
+    public boolean supportTemporaryChangesNesting() {
+        return false;
+    }
+
     @Override
     public void startTemporaryChanges() {
         if (!getModificationsContexts().isEmpty()) {
diff --git a/src/main/java/com/powsybl/openloadflow/graph/GraphConnectivity.java b/src/main/java/com/powsybl/openloadflow/graph/GraphConnectivity.java
index 1fac34f587..b2c0b9846d 100644
--- a/src/main/java/com/powsybl/openloadflow/graph/GraphConnectivity.java
+++ b/src/main/java/com/powsybl/openloadflow/graph/GraphConnectivity.java
@@ -42,6 +42,8 @@ public interface GraphConnectivity<V, E> {
 
     void removeEdge(E edge);
 
+    boolean supportTemporaryChangesNesting();
+
     /**
      * Start recording topological changes to undo them later by a {@link #undoTemporaryChanges} call.
      */
diff --git a/src/main/java/com/powsybl/openloadflow/graph/MinimumSpanningTreeGraphConnectivity.java b/src/main/java/com/powsybl/openloadflow/graph/MinimumSpanningTreeGraphConnectivity.java
index 6dee681ab1..9924b883c4 100644
--- a/src/main/java/com/powsybl/openloadflow/graph/MinimumSpanningTreeGraphConnectivity.java
+++ b/src/main/java/com/powsybl/openloadflow/graph/MinimumSpanningTreeGraphConnectivity.java
@@ -45,6 +45,11 @@ protected void updateConnectivity(EdgeRemove<V, E> edgeRemove) {
         }
     }
 
+    @Override
+    public boolean supportTemporaryChangesNesting() {
+        return true;
+    }
+
     @Override
     public void startTemporaryChanges() {
         super.startTemporaryChanges();
diff --git a/src/main/java/com/powsybl/openloadflow/graph/NaiveGraphConnectivity.java b/src/main/java/com/powsybl/openloadflow/graph/NaiveGraphConnectivity.java
index 5102772c00..d4d12df65d 100644
--- a/src/main/java/com/powsybl/openloadflow/graph/NaiveGraphConnectivity.java
+++ b/src/main/java/com/powsybl/openloadflow/graph/NaiveGraphConnectivity.java
@@ -28,6 +28,11 @@ public NaiveGraphConnectivity(ToIntFunction<V> numGetter) {
         this.numGetter = Objects.requireNonNull(numGetter);
     }
 
+    @Override
+    public boolean supportTemporaryChangesNesting() {
+        return true;
+    }
+
     protected void updateComponents() {
         if (components == null) {
             components = new int[getGraph().vertexSet().size()];
diff --git a/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java b/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java
index 4b15ed1104..e7f56319d5 100644
--- a/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java
+++ b/src/main/java/com/powsybl/openloadflow/network/LfNetwork.java
@@ -603,6 +603,12 @@ public GraphConnectivity<LfBus, LfBranch> getConnectivity() {
                     .filter(b -> b.getBus1() != null && b.getBus2() != null)
                     .forEach(b -> connectivity.addEdge(b.getBus1(), b.getBus2(), b));
             connectivity.setMainComponentVertex(getSlackBus());
+            // this is necessary to create a first temporary changes level in order to allow
+            // some outer loop to change permanently the connectivity (with automation systems for instance)
+            // this one will never be reverted
+            if (connectivity.supportTemporaryChangesNesting()) {
+                connectivity.startTemporaryChanges();
+            }
         }
         return connectivity;
     }
diff --git a/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisProvider.java b/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisProvider.java
index fbfe14e81c..963e9cdfa8 100644
--- a/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisProvider.java
+++ b/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisProvider.java
@@ -14,8 +14,10 @@
 import com.powsybl.computation.ComputationManager;
 import com.powsybl.contingency.ContingenciesProvider;
 import com.powsybl.iidm.network.Network;
+import com.powsybl.loadflow.LoadFlowParameters;
 import com.powsybl.math.matrix.MatrixFactory;
 import com.powsybl.math.matrix.SparseMatrixFactory;
+import com.powsybl.openloadflow.OpenLoadFlowParameters;
 import com.powsybl.openloadflow.graph.EvenShiloachGraphDecrementalConnectivityFactory;
 import com.powsybl.openloadflow.graph.GraphConnectivityFactory;
 import com.powsybl.openloadflow.graph.NaiveGraphConnectivityFactory;
@@ -73,17 +75,20 @@ public CompletableFuture<SecurityAnalysisReport> run(Network network, String wor
         Objects.requireNonNull(stateMonitors);
         Objects.requireNonNull(reporter);
 
+        LoadFlowParameters loadFlowParameters = securityAnalysisParameters.getLoadFlowParameters();
+        OpenLoadFlowParameters loadFlowParametersExt = OpenLoadFlowParameters.get(loadFlowParameters);
+
         // FIXME implement a fast incremental connectivity algorithm
         GraphConnectivityFactory<LfBus, LfBranch> selectedConnectivityFactory;
-        if (operatorStrategies.isEmpty()) {
+        if (operatorStrategies.isEmpty() && !loadFlowParametersExt.isSimulateAutomationSystems()) {
             selectedConnectivityFactory = connectivityFactory;
         } else {
             LOGGER.warn("Naive (and slow!!!) connectivity algorithm has been selected because at least one operator strategy is configured");
             selectedConnectivityFactory = new NaiveGraphConnectivityFactory<>(LfBus::getNum);
         }
 
-        AbstractSecurityAnalysis securityAnalysis;
-        if (securityAnalysisParameters.getLoadFlowParameters().isDc()) {
+        AbstractSecurityAnalysis<?, ?, ?, ?> securityAnalysis;
+        if (loadFlowParameters.isDc()) {
             securityAnalysis = new DcSecurityAnalysis(network, matrixFactory, selectedConnectivityFactory, stateMonitors, reporter);
         } else {
             securityAnalysis = new AcSecurityAnalysis(network, matrixFactory, selectedConnectivityFactory, stateMonitors, reporter);
diff --git a/src/main/java/com/powsybl/openloadflow/sensi/AcSensitivityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sensi/AcSensitivityAnalysis.java
index 0779033395..33210fc851 100644
--- a/src/main/java/com/powsybl/openloadflow/sensi/AcSensitivityAnalysis.java
+++ b/src/main/java/com/powsybl/openloadflow/sensi/AcSensitivityAnalysis.java
@@ -219,7 +219,8 @@ public void analyse(Network network, List<PropagatedContingency> contingencies,
                 .setMinPlausibleTargetVoltage(lfParametersExt.getMinPlausibleTargetVoltage())
                 .setMaxPlausibleTargetVoltage(lfParametersExt.getMaxPlausibleTargetVoltage())
                 .setMinNominalVoltageTargetVoltageCheck(lfParametersExt.getMinNominalVoltageTargetVoltageCheck())
-                .setCacheEnabled(false); // force not caching as not supported in sensi analysis
+                .setCacheEnabled(false) // force not caching as not supported in sensi analysis
+                .setSimulateAutomationSystems(false);
 
         // create networks including all necessary switches
         try (LfNetworkList lfNetworks = Networks.load(network, lfNetworkParameters, topoConfig, reporter)) {

From 090c210833ee555874504e192c2b7000f35f6b49 Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Tue, 31 Oct 2023 13:06:58 +0100
Subject: [PATCH 29/30] Wip

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../openloadflow/ac/outerloop/AutomationSystemOuterLoop.java    | 2 +-
 .../openloadflow/network/LfOverloadManagementSystem.java        | 2 +-
 .../network/impl/extensions/OverloadManagementSystem.java       | 2 +-
 .../network/impl/extensions/OverloadManagementSystemAdder.java  | 2 +-
 .../impl/extensions/OverloadManagementSystemAdderImpl.java      | 2 +-
 .../network/impl/extensions/OverloadManagementSystemImpl.java   | 2 +-
 .../network/impl/extensions/SubstationAutomationSystems.java    | 2 +-
 .../impl/extensions/SubstationAutomationSystemsAdder.java       | 2 +-
 .../impl/extensions/SubstationAutomationSystemsAdderImpl.java   | 2 +-
 .../SubstationAutomationSystemsAdderImplProvider.java           | 2 +-
 .../impl/extensions/SubstationAutomationSystemsImpl.java        | 2 +-
 .../extensions/SubstationAutomationSystemsXmlSerializer.java    | 2 +-
 .../java/com/powsybl/openloadflow/ac/AutomationSystemTest.java  | 2 +-
 .../openloadflow/network/AutomationSystemNetworkFactory.java    | 2 +-
 .../impl/extensions/SubstationAutomationSystemsTest.java        | 2 +-
 15 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
index cc46b2783e..30cd63875f 100644
--- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
+++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AutomationSystemOuterLoop.java
@@ -20,7 +20,7 @@
 import java.util.Set;
 
 /**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
  */
 public class AutomationSystemOuterLoop implements AcOuterLoop {
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementSystem.java b/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementSystem.java
index 27e15ef64a..cc979fb177 100644
--- a/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementSystem.java
+++ b/src/main/java/com/powsybl/openloadflow/network/LfOverloadManagementSystem.java
@@ -11,7 +11,7 @@
 import java.util.Objects;
 
 /**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
  */
 public class LfOverloadManagementSystem {
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystem.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystem.java
index ba19ad8532..41bf57ffbc 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystem.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystem.java
@@ -7,7 +7,7 @@
 package com.powsybl.openloadflow.network.impl.extensions;
 
 /**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
  */
 public interface OverloadManagementSystem {
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdder.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdder.java
index d84007c2e7..7151ed1450 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdder.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdder.java
@@ -7,7 +7,7 @@
 package com.powsybl.openloadflow.network.impl.extensions;
 
 /**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
  */
 public interface OverloadManagementSystemAdder<T> {
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdderImpl.java
index 16a34ca007..71add93c74 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemAdderImpl.java
@@ -12,7 +12,7 @@
 import java.util.function.Consumer;
 
 /**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
  */
 public class OverloadManagementSystemAdderImpl<T> implements OverloadManagementSystemAdder<T> {
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemImpl.java
index 145e53cf09..23584e1fe0 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/OverloadManagementSystemImpl.java
@@ -9,7 +9,7 @@
 import java.util.Objects;
 
 /**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
  */
 public class OverloadManagementSystemImpl implements OverloadManagementSystem {
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystems.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystems.java
index 823ce22432..36877d024e 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystems.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystems.java
@@ -12,7 +12,7 @@
 import java.util.List;
 
 /**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
  */
 public interface SubstationAutomationSystems extends Extension<Substation> {
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdder.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdder.java
index bcb5543073..f859597a25 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdder.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdder.java
@@ -10,7 +10,7 @@
 import com.powsybl.iidm.network.Substation;
 
 /**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
  */
 public interface SubstationAutomationSystemsAdder extends ExtensionAdder<Substation, SubstationAutomationSystems> {
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImpl.java
index 6e0026c084..1d40155fce 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImpl.java
@@ -13,7 +13,7 @@
 import java.util.List;
 
 /**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
  */
 public class SubstationAutomationSystemsAdderImpl extends AbstractExtensionAdder<Substation, SubstationAutomationSystems> implements SubstationAutomationSystemsAdder {
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImplProvider.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImplProvider.java
index 1601bbdb8e..0ec43937d1 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImplProvider.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsAdderImplProvider.java
@@ -11,7 +11,7 @@
 import com.powsybl.iidm.network.Substation;
 
 /**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
  */
 @AutoService(ExtensionAdderProvider.class)
 public class SubstationAutomationSystemsAdderImplProvider implements
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsImpl.java
index 8ff7721b7d..fcfb971602 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsImpl.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsImpl.java
@@ -14,7 +14,7 @@
 import java.util.Objects;
 
 /**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
  */
 public class SubstationAutomationSystemsImpl extends AbstractExtension<Substation> implements SubstationAutomationSystems {
 
diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java
index 3adc097806..620931cba9 100644
--- a/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java
+++ b/src/main/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsXmlSerializer.java
@@ -17,7 +17,7 @@
 import javax.xml.stream.XMLStreamException;
 
 /**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
  */
 @AutoService(ExtensionXmlSerializer.class)
 public class SubstationAutomationSystemsXmlSerializer extends AbstractExtensionXmlSerializer<Substation, SubstationAutomationSystems> {
diff --git a/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java b/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
index a22c9f146d..bef49ca743 100644
--- a/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
+++ b/src/test/java/com/powsybl/openloadflow/ac/AutomationSystemTest.java
@@ -21,7 +21,7 @@
 import static org.junit.jupiter.api.Assertions.assertSame;
 
 /**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
  */
 class AutomationSystemTest {
 
diff --git a/src/test/java/com/powsybl/openloadflow/network/AutomationSystemNetworkFactory.java b/src/test/java/com/powsybl/openloadflow/network/AutomationSystemNetworkFactory.java
index fad98c665f..229eac6901 100644
--- a/src/test/java/com/powsybl/openloadflow/network/AutomationSystemNetworkFactory.java
+++ b/src/test/java/com/powsybl/openloadflow/network/AutomationSystemNetworkFactory.java
@@ -13,7 +13,7 @@
 import org.joda.time.DateTime;
 
 /**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
  */
 public final class AutomationSystemNetworkFactory extends AbstractLoadFlowNetworkFactory {
 
diff --git a/src/test/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsTest.java b/src/test/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsTest.java
index 8044dbe59f..d585ab3801 100644
--- a/src/test/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsTest.java
+++ b/src/test/java/com/powsybl/openloadflow/network/impl/extensions/SubstationAutomationSystemsTest.java
@@ -18,7 +18,7 @@
 import static org.junit.jupiter.api.Assertions.*;
 
 /**
- * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
+ * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
  */
 class SubstationAutomationSystemsTest extends AbstractConverterTest {
 

From fa6f75cd830aac71bac788a52152008d8e83d47d Mon Sep 17 00:00:00 2001
From: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Date: Fri, 3 Nov 2023 15:47:18 +0100
Subject: [PATCH 30/30] Fix

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
---
 .../java/com/powsybl/openloadflow/OpenLoadFlowParameters.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
index 3f7ff9caef..7a9c4f2c16 100644
--- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
+++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
@@ -274,7 +274,7 @@ private static <E extends Enum<E>> List<Object> getEnumPossibleValues(Class<E> e
         new Parameter(LINE_PER_UNIT_MODE_PARAM_NAME, ParameterType.STRING, "Line per unit mode", LinePerUnitMode.IMPEDANCE.name(), getEnumPossibleValues(LinePerUnitMode.class)),
         new Parameter(USE_LOAD_MODEL_PARAM_NAME, ParameterType.BOOLEAN, "Use load model (with voltage dependency) for simulation", LfNetworkParameters.USE_LOAD_MODE_DEFAULT_VALUE),
         new Parameter(DC_APPROXIMATION_TYPE_PARAM_NAME, ParameterType.STRING, "DC approximation type", DcEquationSystemCreationParameters.DC_APPROXIMATION_TYPE_DEFAULT_VALUE.name(), getEnumPossibleValues(DcApproximationType.class)),
-        new Parameter(SIMULATE_AUTOMATION_SYSTEMS_PARAM_NAME, ParameterType.BOOLEAN, "Automatons simulation", LfNetworkParameters.SIMULATE_AUTOMATION_SYSTEMS_DEFAULT_VALUE)
+        new Parameter(SIMULATE_AUTOMATION_SYSTEMS_PARAM_NAME, ParameterType.BOOLEAN, "Automation systems simulation", LfNetworkParameters.SIMULATE_AUTOMATION_SYSTEMS_DEFAULT_VALUE)
     );
 
     public enum VoltageInitModeOverride {