diff --git a/src/main/java/com/powsybl/openloadflow/ac/PhaseControlOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/PhaseControlOuterLoop.java index 56b5017a88..f661b36ecc 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/PhaseControlOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/PhaseControlOuterLoop.java @@ -23,7 +23,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; /** @@ -95,16 +94,15 @@ public OuterLoopStatus check(OuterLoopContext context, Reporter reporter) { } private OuterLoopStatus firstIteration(OuterLoopContext context) { - List phaseControlsOn = context.getNetwork().getBranches().stream() - .map(branch -> branch.getDiscretePhaseControl().filter(dpc -> branch.isPhaseControlled())) - .filter(Optional::isPresent) - .map(Optional::get) - .filter(dpc -> dpc.getMode() == DiscretePhaseControl.Mode.CONTROLLER || dpc.getMode() == DiscretePhaseControl.Mode.LIMITER) + .filter(LfBranch::isPhaseControlled) + .flatMap(branch -> branch.getDiscretePhaseControl().stream()) .collect(Collectors.toList()); // all branches with active power control are switched off - phaseControlsOn.stream().filter(dpc -> dpc.getMode() == DiscretePhaseControl.Mode.CONTROLLER).forEach(this::switchOffPhaseControl); + phaseControlsOn.stream() + .filter(dpc -> dpc.getMode() == DiscretePhaseControl.Mode.CONTROLLER) + .forEach(this::switchOffPhaseControl); // if at least one phase shifter has been switched off we need to continue return phaseControlsOn.isEmpty() ? OuterLoopStatus.STABLE : OuterLoopStatus.UNSTABLE; @@ -115,11 +113,10 @@ private OuterLoopStatus nextIteration(OuterLoopContext context) { // and a current greater than the limit // phase control consists in increasing or decreasing tap position to limit the current List unstablePhaseControls = context.getNetwork().getBranches().stream() - .map(branch -> branch.getDiscretePhaseControl().filter(dpc -> branch.isPhaseControlled())) - .filter(Optional::isPresent) - .map(Optional::get) - .filter(dpc -> dpc.getMode() == DiscretePhaseControl.Mode.LIMITER) - .filter(dpc -> changeTapPositions(dpc) == OuterLoopStatus.UNSTABLE) + .filter(LfBranch::isPhaseControlled) + .flatMap(branch -> branch.getDiscretePhaseControl().stream()) + .filter(phaseControl -> phaseControl.getMode() == DiscretePhaseControl.Mode.LIMITER) + .filter(this::changeTapPositions) .collect(Collectors.toList()); return unstablePhaseControls.isEmpty() ? OuterLoopStatus.STABLE : OuterLoopStatus.UNSTABLE; @@ -138,21 +135,19 @@ private void switchOffPhaseControl(DiscretePhaseControl phaseControl) { LOGGER.info("Round phase shift of '{}': {} -> {}", controllerBranch.getId(), a1Value, roundedA1Value); } - private OuterLoopStatus changeTapPositions(DiscretePhaseControl phaseControl) { + private boolean changeTapPositions(DiscretePhaseControl phaseControl) { // only local control supported: controlled branch is controller branch. double currentLimit = phaseControl.getTargetValue(); LfBranch controllerBranch = phaseControl.getController(); PiModel piModel = controllerBranch.getPiModel(); - boolean isSensibilityPositive; - boolean success = false; if (phaseControl.getControlledSide() == DiscretePhaseControl.ControlledSide.ONE && currentLimit < controllerBranch.getI1().eval()) { - isSensibilityPositive = isSensitivityCurrentPerA1Positive(controllerBranch, DiscretePhaseControl.ControlledSide.ONE); - success = isSensibilityPositive ? piModel.updateTapPosition(PiModel.Direction.DECREASE) : piModel.updateTapPosition(PiModel.Direction.INCREASE); + boolean isSensibilityPositive = isSensitivityCurrentPerA1Positive(controllerBranch, DiscretePhaseControl.ControlledSide.ONE); + return isSensibilityPositive ? piModel.updateTapPosition(PiModel.Direction.DECREASE) : piModel.updateTapPosition(PiModel.Direction.INCREASE); } else if (phaseControl.getControlledSide() == DiscretePhaseControl.ControlledSide.TWO && currentLimit < controllerBranch.getI2().eval()) { - isSensibilityPositive = isSensitivityCurrentPerA1Positive(controllerBranch, DiscretePhaseControl.ControlledSide.TWO); - success = isSensibilityPositive ? piModel.updateTapPosition(PiModel.Direction.DECREASE) : piModel.updateTapPosition(PiModel.Direction.INCREASE); + boolean isSensibilityPositive = isSensitivityCurrentPerA1Positive(controllerBranch, DiscretePhaseControl.ControlledSide.TWO); + return isSensibilityPositive ? piModel.updateTapPosition(PiModel.Direction.DECREASE) : piModel.updateTapPosition(PiModel.Direction.INCREASE); } - return success ? OuterLoopStatus.UNSTABLE : OuterLoopStatus.STABLE; + return false; } boolean isSensitivityCurrentPerA1Positive(LfBranch controllerBranch, DiscretePhaseControl.ControlledSide controlledSide) { diff --git a/src/main/java/com/powsybl/openloadflow/network/AbstractPropertyBag.java b/src/main/java/com/powsybl/openloadflow/network/AbstractPropertyBag.java index 67325c1fef..7ea36589e5 100644 --- a/src/main/java/com/powsybl/openloadflow/network/AbstractPropertyBag.java +++ b/src/main/java/com/powsybl/openloadflow/network/AbstractPropertyBag.java @@ -32,4 +32,11 @@ public void setProperty(String name, Object value) { } properties.put(name, value); } + + public void removeProperty(String name) { + Objects.requireNonNull(name); + if (properties != null) { + properties.remove(name); + } + } } diff --git a/src/main/java/com/powsybl/openloadflow/network/PropertyBag.java b/src/main/java/com/powsybl/openloadflow/network/PropertyBag.java index ac9a55b5e2..960e1e0e42 100644 --- a/src/main/java/com/powsybl/openloadflow/network/PropertyBag.java +++ b/src/main/java/com/powsybl/openloadflow/network/PropertyBag.java @@ -14,4 +14,6 @@ public interface PropertyBag { Object getProperty(String name); void setProperty(String name, Object value); + + void removeProperty(String name); } diff --git a/src/test/java/com/powsybl/openloadflow/network/PropertyTest.java b/src/test/java/com/powsybl/openloadflow/network/PropertyTest.java index 5a4e03116c..055f100b3d 100644 --- a/src/test/java/com/powsybl/openloadflow/network/PropertyTest.java +++ b/src/test/java/com/powsybl/openloadflow/network/PropertyTest.java @@ -9,6 +9,7 @@ import com.powsybl.iidm.network.Network; import com.powsybl.iidm.network.test.EurostagTutorialExample1Factory; import com.powsybl.openloadflow.network.impl.Networks; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -20,10 +21,16 @@ */ class PropertyTest { + private LfNetwork lfNetwork; + + @BeforeEach + void setUp() { + Network network = EurostagTutorialExample1Factory.create(); + lfNetwork = Networks.load(network, new FirstSlackBusSelector()).get(0); + } + @Test void test() { - Network network = EurostagTutorialExample1Factory.create(); - LfNetwork lfNetwork = Networks.load(network, new FirstSlackBusSelector()).get(0); assertNull(lfNetwork.getProperty("a")); lfNetwork.setProperty("a", "test"); assertEquals("test", lfNetwork.getProperty("a")); @@ -31,5 +38,17 @@ void test() { assertNull(lfBus.getProperty("b")); lfBus.setProperty("b", "hello"); assertEquals("hello", lfBus.getProperty("b")); + lfBus.removeProperty("b"); + assertNull(lfBus.getProperty("b")); + lfBus.setProperty("c", "hi"); + assertEquals("hi", lfBus.getProperty("c")); + } + + @Test + void testRemoveWithEmptyMap() { + // also try to remove a not defined property + assertNull(lfNetwork.getProperty("x")); + lfNetwork.removeProperty("x"); + assertNull(lfNetwork.getProperty("x")); } }