diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/AutomationSystem.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/AutomationSystem.java new file mode 100644 index 00000000000..6cf2ce900d9 --- /dev/null +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/AutomationSystem.java @@ -0,0 +1,26 @@ +/** + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.iidm.network; + +/** + * @author Olivier Perrin {@literal } + */ +public interface AutomationSystem> extends Identifiable { + + /** + * Says if the system is active or not. + * @return true is the automation system is enabled + */ + boolean isEnabled(); + + /** + * Change the state of the automation system + * @param enabled true to enable the automation system + */ + void setEnabled(boolean enabled); +} diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/IdentifiableType.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/IdentifiableType.java index 51075635e07..7f5dcc6168e 100644 --- a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/IdentifiableType.java +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/IdentifiableType.java @@ -28,5 +28,6 @@ public enum IdentifiableType { SHUNT_COMPENSATOR, DANGLING_LINE, STATIC_VAR_COMPENSATOR, - HVDC_CONVERTER_STATION + HVDC_CONVERTER_STATION, + OVERLOAD_MANAGEMENT_SYSTEM } diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/Network.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/Network.java index d46f5714544..65de0bab69f 100644 --- a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/Network.java +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/Network.java @@ -827,6 +827,28 @@ default VoltageLevelAdder newVoltageLevel() { */ ThreeWindingsTransformer getThreeWindingsTransformer(String id); + /** + * Get all overload management systems. + */ + Iterable getOverloadManagementSystems(); + + /** + * Get all overload management systems. + */ + Stream getOverloadManagementSystemStream(); + + /** + * Get the overload management system count. + */ + int getOverloadManagementSystemCount(); + + /** + * Get an overload management system. + * + * @param id the id or an alias of the overload management system + */ + OverloadManagementSystem getOverloadManagementSystem(String id); + /** * Get all generators. */ diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/OverloadManagementSystem.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/OverloadManagementSystem.java new file mode 100644 index 00000000000..4222a202506 --- /dev/null +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/OverloadManagementSystem.java @@ -0,0 +1,145 @@ +/** + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.iidm.network; + +import java.util.List; + +/** + * An overload management system. + * + * @author Olivier Perrin {@literal } + */ +public interface OverloadManagementSystem extends AutomationSystem { + + interface Tripping { + enum Type { + BRANCH_TRIPPING, + THREE_WINDINGS_TRANSFORMER_TRIPPING, + SWITCH_TRIPPING + } + + Type getType(); + + /** + * Get the unique key of the tripping. + *

This key is unique for a single overload management system, but it can be reused + * for another overload management system).

+ * @return the tripping key + */ + String getKey(); + + /** + * Get the name (if available) or the key of the tripping. + *

This method result is used for reporting purposes.

+ * @return the name (if available) or the key of the tripping + */ + String getNameOrKey(); + + /** + * Set the name of the tripping. + *

This name is facultative. It is used only for reporting purposes.

+ * @param name the name of the tripping + * @see #getNameOrKey() + */ + Tripping setName(String name); + + /** + * Return the maximum acceptable current value (in A). + * @return the maximum current value + */ + double getCurrentLimit(); + + Tripping setCurrentLimit(double currentLimit); + + /** + * Tell if the tripping operation consists in opening (true) or closing (false) + * the element (branch, three windings transformer or switch) to operate. + * @return true it the operation consists in opening the element, else false. + */ + boolean isOpenAction(); + + Tripping setOpenAction(boolean open); + } + + interface SwitchTripping extends Tripping { + @Override + default Type getType() { + return Type.SWITCH_TRIPPING; + } + + String getSwitchToOperateId(); + + SwitchTripping setSwitchToOperateId(String switchToOperateId); + } + + interface BranchTripping extends Tripping { + @Override + default Type getType() { + return Type.BRANCH_TRIPPING; + } + + String getBranchToOperateId(); + + BranchTripping setBranchToOperateId(String branch); + + TwoSides getSideToOperate(); + + BranchTripping setSideToOperate(TwoSides side); + } + + interface ThreeWindingsTransformerTripping extends Tripping { + @Override + default Type getType() { + return Type.THREE_WINDINGS_TRANSFORMER_TRIPPING; + } + + String getThreeWindingsTransformerToOperateId(); + + ThreeWindingsTransformerTripping setThreeWindingsTransformerToOperateId(String threeWindingsTransformerId); + + ThreeSides getSideToOperate(); + + ThreeWindingsTransformerTripping setSideToOperate(ThreeSides side); + } + + /** + * Get the parent substation. + * @return the parent substation + */ + Substation getSubstation(); + + /** + * Get the id of the element (branch or three windings transformer) which is monitored + * @return the id of the monitored element + */ + String getMonitoredElementId(); + + /** + * Get the monitored side of the element. + * @return the side + * @see #getMonitoredElementId() + */ + ThreeSides getMonitoredSide(); + + /** + * Add a tripping (operation to perform when the current is out of an acceptable interval) + * @param tripping the tripping to add + */ + void addTripping(Tripping tripping); + + /** + * Return the list of the defined trippings. + * @return the trippings + */ + List getTrippings(); + + @Override + default IdentifiableType getType() { + return IdentifiableType.OVERLOAD_MANAGEMENT_SYSTEM; + } +} diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/OverloadManagementSystemAdder.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/OverloadManagementSystemAdder.java new file mode 100644 index 00000000000..1c30c0aedc4 --- /dev/null +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/OverloadManagementSystemAdder.java @@ -0,0 +1,100 @@ +/** + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.iidm.network; + +/** + * @author Olivier Perrin {@literal } + */ +public interface OverloadManagementSystemAdder extends IdentifiableAdder { + + interface TrippingAdder> { + /** + * Set the unique key of the tripping. + *

This key is unique for a single overload management system, but it can be reused + * for another overload management system).

+ * @param key the tripping key + */ + I setKey(String key); + + /** + * Set the name of the tripping. + *

This name is facultative. It is used only for reporting purposes.

+ * @param name the name of the tripping + */ + I setName(String name); + + /** + * Set the maximum acceptable current value (in A). + * @param currentLimit the maximum current value + */ + I setCurrentLimit(double currentLimit); + + I setOpenAction(boolean open); + + OverloadManagementSystem.Tripping.Type getType(); + + OverloadManagementSystemAdder add(); + } + + interface SwitchTrippingAdder extends TrippingAdder { + @Override + default OverloadManagementSystem.Tripping.Type getType() { + return OverloadManagementSystem.Tripping.Type.SWITCH_TRIPPING; + } + + SwitchTrippingAdder setSwitchToOperateId(String switchId); + } + + interface BranchTrippingAdder extends TrippingAdder { + @Override + default OverloadManagementSystem.Tripping.Type getType() { + return OverloadManagementSystem.Tripping.Type.BRANCH_TRIPPING; + } + + BranchTrippingAdder setBranchToOperateId(String branchId); + + BranchTrippingAdder setSideToOperate(TwoSides side); + } + + interface ThreeWindingsTransformerTrippingAdder extends TrippingAdder { + @Override + default OverloadManagementSystem.Tripping.Type getType() { + return OverloadManagementSystem.Tripping.Type.THREE_WINDINGS_TRANSFORMER_TRIPPING; + } + + ThreeWindingsTransformerTrippingAdder setThreeWindingsTransformerToOperateId(String threeWindingsTransformerId); + + ThreeWindingsTransformerTrippingAdder setSideToOperate(ThreeSides side); + + } + + @Override + OverloadManagementSystem add(); + + OverloadManagementSystemAdder setEnabled(boolean enabled); + + /** + * Set the id of the element (branch or three windings transformer) which is monitored. + * @param monitoredElementId the id of the monitored element + * @return the adder + */ + OverloadManagementSystemAdder setMonitoredElementId(String monitoredElementId); + + /** + * Set the monitored side of the element. + * @param monitoredElementSide the monitored side of the element + * @return the adder + */ + OverloadManagementSystemAdder setMonitoredElementSide(ThreeSides monitoredElementSide); + + SwitchTrippingAdder newSwitchTripping(); + + BranchTrippingAdder newBranchTripping(); + + ThreeWindingsTransformerTrippingAdder newThreeWindingsTransformerTripping(); +} diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/Substation.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/Substation.java index 2919ddbde5a..ad25812c4b1 100644 --- a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/Substation.java +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/Substation.java @@ -162,6 +162,26 @@ public interface Substation extends Container { */ int getThreeWindingsTransformerCount(); + /** + * Get a builder to create a new overload management system in the substation. + */ + OverloadManagementSystemAdder newOverloadManagementSystem(); + + /** + * Get the overload management systems relative to the substation. + */ + Iterable getOverloadManagementSystems(); + + /** + * Get the overload management systems relative to the substation. + */ + Stream getOverloadManagementSystemStream(); + + /** + * Get the overload management systems count + */ + int getOverloadManagementSystemCount(); + /** * Get geographical tags associated to the substation. */ diff --git a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/AbstractAutomationSystem.java b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/AbstractAutomationSystem.java new file mode 100644 index 00000000000..b17d81e90e8 --- /dev/null +++ b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/AbstractAutomationSystem.java @@ -0,0 +1,69 @@ +/** + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.iidm.network.impl; + +import com.powsybl.commons.util.trove.TBooleanArrayList; +import com.powsybl.iidm.network.AutomationSystem; +import com.powsybl.iidm.network.impl.util.Ref; + +import java.util.Objects; + +/** + * @author Olivier Perrin {@literal } + */ +abstract class AbstractAutomationSystem> extends AbstractIdentifiable implements AutomationSystem { + private final TBooleanArrayList enabled; + + AbstractAutomationSystem(Ref networkRef, String id, String name, boolean enabled) { + super(id, name); + Objects.requireNonNull(networkRef); + + int variantArraySize = networkRef.get().getVariantManager().getVariantArraySize(); + this.enabled = new TBooleanArrayList(variantArraySize); + for (int i = 0; i < variantArraySize; i++) { + this.enabled.add(enabled); + } + } + + @Override + public boolean isEnabled() { + return enabled.get(getNetwork().getVariantIndex()); + } + + @Override + public void setEnabled(boolean enabled) { + this.enabled.set(getNetwork().getVariantIndex(), enabled); + } + + @Override + public void extendVariantArraySize(int initVariantArraySize, int number, int sourceIndex) { + super.extendVariantArraySize(initVariantArraySize, number, sourceIndex); + enabled.ensureCapacity(enabled.size() + number); + enabled.fill(initVariantArraySize, initVariantArraySize + number, enabled.get(sourceIndex)); + } + + @Override + public void reduceVariantArraySize(int number) { + super.reduceVariantArraySize(number); + enabled.remove(enabled.size() - number, number); + } + + @Override + public void deleteVariantArrayElement(int index) { + super.deleteVariantArrayElement(index); + // nothing to do + } + + @Override + public void allocateVariantArrayElement(int[] indexes, int sourceIndex) { + super.allocateVariantArrayElement(indexes, sourceIndex); + for (int index : indexes) { + enabled.set(index, enabled.get(sourceIndex)); + } + } +} diff --git a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/NetworkImpl.java b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/NetworkImpl.java index 458ff47e640..ce8f68df56c 100644 --- a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/NetworkImpl.java +++ b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/NetworkImpl.java @@ -442,6 +442,26 @@ public ThreeWindingsTransformer getThreeWindingsTransformer(String id) { return index.get(id, ThreeWindingsTransformerImpl.class); } + @Override + public Iterable getOverloadManagementSystems() { + return Collections.unmodifiableCollection(index.getAll(OverloadManagementSystemImpl.class)); + } + + @Override + public Stream getOverloadManagementSystemStream() { + return index.getAll(OverloadManagementSystemImpl.class).stream().map(Function.identity()); + } + + @Override + public int getOverloadManagementSystemCount() { + return index.getAll(OverloadManagementSystemImpl.class).size(); + } + + @Override + public OverloadManagementSystem getOverloadManagementSystem(String id) { + return index.get(id, OverloadManagementSystemImpl.class); + } + @Override public Iterable getGenerators() { return Collections.unmodifiableCollection(index.getAll(GeneratorImpl.class)); diff --git a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/OverloadManagementSystemAdderImpl.java b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/OverloadManagementSystemAdderImpl.java new file mode 100644 index 00000000000..bae47923ef3 --- /dev/null +++ b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/OverloadManagementSystemAdderImpl.java @@ -0,0 +1,247 @@ +/** + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.iidm.network.impl; + +import com.powsybl.iidm.network.*; + +import java.util.*; +import java.util.function.BiFunction; + +/** + * @author Olivier Perrin {@literal } + */ +class OverloadManagementSystemAdderImpl extends AbstractIdentifiableAdder + implements OverloadManagementSystemAdder { + + abstract class AbstractTrippingAdderImpl> implements Validable, TrippingAdder { + protected String key = null; + protected String name = null; + protected double currentLimit = Double.NaN; + protected boolean openAction = true; + + public I setKey(String key) { + this.key = key; + return (I) this; + } + + public I setName(String name) { + this.name = name; + return (I) this; + } + + public I setCurrentLimit(double currentLimit) { + this.currentLimit = currentLimit; + return (I) this; + } + + public I setOpenAction(boolean open) { + this.openAction = open; + return (I) this; + } + + public OverloadManagementSystemAdder add() { + trippingAdders.add(this); + return OverloadManagementSystemAdderImpl.this; + } + + protected String getTrippingAttribute() { + return String.format("tripping '%s'", key); + } + + @Override + public String getMessageHeader() { + return String.format("Overload management system in substation '%s': - %s:", substation.getId(), getTrippingAttribute()); + } + + protected static String getNotFoundMessage(String type, String id) { + return type + " '" + id + "' not found"; + } + + protected String checkElementId(String elementId, BiFunction getter, String attributeName, String type) { + if (elementId == null) { + throw new ValidationException(this, attributeName + " is not set"); + } + E element = getter.apply(getNetwork(), elementId); + if (element == null) { + throw new ValidationException(this, getNotFoundMessage(type, elementId)); + } + return elementId; + } + } + + class SwitchTrippingAdderImpl extends AbstractTrippingAdderImpl + implements OverloadManagementSystemAdder.SwitchTrippingAdder { + private String switchId; + + @Override + public OverloadManagementSystemAdder.SwitchTrippingAdder setSwitchToOperateId(String switchId) { + this.switchId = switchId; + return this; + } + + protected String checkSwitchId() { + return checkElementId(switchId, Network::getSwitch, "switchId", "switch"); + } + } + + class BranchTrippingAdderImpl extends AbstractTrippingAdderImpl + implements OverloadManagementSystemAdder.BranchTrippingAdder { + private String branchId; + private TwoSides side; + + @Override + public OverloadManagementSystemAdder.BranchTrippingAdder setBranchToOperateId(String branchId) { + this.branchId = branchId; + return this; + } + + @Override + public OverloadManagementSystemAdder.BranchTrippingAdder setSideToOperate(TwoSides side) { + this.side = side; + return this; + } + + protected String checkBranchId() { + return checkElementId(branchId, Network::getBranch, "branchId", "branch"); + } + } + + class ThreeWindingsTransformerTrippingAdderImpl extends AbstractTrippingAdderImpl + implements OverloadManagementSystemAdder.ThreeWindingsTransformerTrippingAdder { + private String threeWindingsTransformerId; + private ThreeSides side; + + @Override + public OverloadManagementSystemAdder.ThreeWindingsTransformerTrippingAdder setThreeWindingsTransformerToOperateId( + String threeWindingsTransformerId) { + this.threeWindingsTransformerId = threeWindingsTransformerId; + return this; + } + + @Override + public OverloadManagementSystemAdder.ThreeWindingsTransformerTrippingAdder setSideToOperate(ThreeSides side) { + this.side = side; + return this; + } + + protected String checkThreeWindingsTransformerId() { + return checkElementId(threeWindingsTransformerId, Network::getThreeWindingsTransformer, + "threeWindingsTransformerId", "three windings transformer"); + } + } + + private final SubstationImpl substation; + private boolean enabled = true; + + private String monitoredElementId; + private ThreeSides monitoredElementSide; + private final List> trippingAdders = new ArrayList<>(); + + OverloadManagementSystemAdderImpl(SubstationImpl substation) { + this.substation = Objects.requireNonNull(substation); + } + + @Override + protected NetworkImpl getNetwork() { + return substation.getNetwork(); + } + + @Override + protected String getTypeDescription() { + return "Overload management system"; + } + + @Override + public OverloadManagementSystemAdder setEnabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + @Override + public OverloadManagementSystemAdder setMonitoredElementId(String monitoredElementId) { + this.monitoredElementId = monitoredElementId; + return this; + } + + @Override + public OverloadManagementSystemAdder setMonitoredElementSide(ThreeSides monitoredElementSide) { + this.monitoredElementSide = monitoredElementSide; + return this; + } + + @Override + public SwitchTrippingAdder newSwitchTripping() { + return new SwitchTrippingAdderImpl(); + } + + @Override + public BranchTrippingAdder newBranchTripping() { + return new BranchTrippingAdderImpl(); + } + + @Override + public OverloadManagementSystemAdder.ThreeWindingsTransformerTrippingAdder newThreeWindingsTransformerTripping() { + return new ThreeWindingsTransformerTrippingAdderImpl(); + } + + @Override + public OverloadManagementSystem add() { + String id = checkAndGetUniqueId(); + + OverloadManagementSystemImpl overloadManagementSystem = new OverloadManagementSystemImpl(id, getName(), substation, + monitoredElementId, monitoredElementSide, enabled); + + // Add the trippings + Set knownTrippingKeys = new HashSet<>(); + for (AbstractTrippingAdderImpl adder : trippingAdders) { + overloadManagementSystem.addTripping(createTripping(adder, id, knownTrippingKeys)); + } + + getNetwork().getIndex().checkAndAdd(overloadManagementSystem); + substation.addOverloadManagementSystem(overloadManagementSystem); + getNetwork().getListeners().notifyCreation(overloadManagementSystem); + return overloadManagementSystem; + } + + private OverloadManagementSystem.Tripping createTripping(AbstractTrippingAdderImpl adder, String overloadManagementSystemId, + Set knownTrippingKeys) { + String key = adder.key; + if (!knownTrippingKeys.add(key)) { + throw new ValidationException(adder, "key \"" + key + + "\" is already used for another tripping in the overload management system."); + } + return switch (adder.getType()) { + case SWITCH_TRIPPING -> createTripping((SwitchTrippingAdderImpl) adder, overloadManagementSystemId); + case BRANCH_TRIPPING -> createTripping((BranchTrippingAdderImpl) adder, overloadManagementSystemId); + case THREE_WINDINGS_TRANSFORMER_TRIPPING -> createTripping((ThreeWindingsTransformerTrippingAdderImpl) adder, + overloadManagementSystemId); + }; + } + + private OverloadManagementSystem.Tripping createTripping(SwitchTrippingAdderImpl adder, String overloadManagementSystemId) { + return new OverloadManagementSystemImpl.SwitchTrippingImpl( + overloadManagementSystemId, adder.key, adder.name, + adder.currentLimit, adder.openAction, + adder.checkSwitchId()); + } + + private OverloadManagementSystem.Tripping createTripping(BranchTrippingAdderImpl adder, String overloadManagementSystemId) { + return new OverloadManagementSystemImpl.BranchTrippingImpl( + overloadManagementSystemId, + adder.key, adder.name, adder.currentLimit, adder.openAction, + adder.checkBranchId(), adder.side); + } + + private OverloadManagementSystem.Tripping createTripping(ThreeWindingsTransformerTrippingAdderImpl adder, + String overloadManagementSystemId) { + return new OverloadManagementSystemImpl.ThreeWindingsTransformerTrippingImpl( + overloadManagementSystemId, + adder.key, adder.name, adder.currentLimit, adder.openAction, + adder.checkThreeWindingsTransformerId(), adder.side); + } +} diff --git a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/OverloadManagementSystemImpl.java b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/OverloadManagementSystemImpl.java new file mode 100644 index 00000000000..e28c0f98765 --- /dev/null +++ b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/OverloadManagementSystemImpl.java @@ -0,0 +1,249 @@ +/** + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.iidm.network.impl; + +import com.powsybl.iidm.network.*; + +import java.util.*; + +/** + * Overload management system implementation. + * + * @author Olivier Perrin {@literal } + */ +class OverloadManagementSystemImpl extends AbstractAutomationSystem implements OverloadManagementSystem { + + abstract static class AbstractTrippingImpl implements Tripping, Validable { + private final String overloadManagementSystemId; + private final String key; + private String name; + private double currentLimit; + private boolean openAction; + + protected AbstractTrippingImpl(String overloadManagementSystemId, String key, String name, + double currentLimit, boolean openAction) { + this.overloadManagementSystemId = overloadManagementSystemId; + this.key = Objects.requireNonNull(key); + setName(name); + setCurrentLimit(currentLimit); + setOpenAction(openAction); + } + + @Override + public String getKey() { + return this.key; + } + + @Override + public String getNameOrKey() { + return name != null ? name : key; + } + + @Override + public Tripping setName(String name) { + this.name = name; + return this; + } + + @Override + public double getCurrentLimit() { + return this.currentLimit; + } + + @Override + public Tripping setCurrentLimit(double currentLimit) { + if (Double.isNaN(currentLimit)) { + throw new ValidationException(this, "Current limit is mandatory."); + } else if (currentLimit < 0) { + throw new ValidationException(this, "Current limit must be positive."); + } + this.currentLimit = currentLimit; + return this; + } + + @Override + public boolean isOpenAction() { + return this.openAction; + } + + @Override + public Tripping setOpenAction(boolean open) { + this.openAction = open; + return this; + } + + protected String getTrippingAttribute() { + return String.format("tripping '%s'", key); + } + + @Override + public String getMessageHeader() { + return String.format("Overload management system '%s' - %s:", overloadManagementSystemId, getTrippingAttribute()); + } + } + + static class SwitchTrippingImpl extends AbstractTrippingImpl implements SwitchTripping { + private String switchToOperateId; + + public SwitchTrippingImpl(String overloadManagementSystemId, String key, String name, + double currentLimit, boolean openAction, + String switchToOperateId) { + super(overloadManagementSystemId, key, name, currentLimit, openAction); + setSwitchToOperateId(switchToOperateId); + } + + @Override + public String getSwitchToOperateId() { + return this.switchToOperateId; + } + + @Override + public SwitchTripping setSwitchToOperateId(String switchToOperateId) { + this.switchToOperateId = Objects.requireNonNull(switchToOperateId); + return this; + } + } + + static class BranchTrippingImpl extends AbstractTrippingImpl implements OverloadManagementSystem.BranchTripping { + private String branchToOperateId; + private TwoSides side; + + protected BranchTrippingImpl(String overloadManagementSystemId, String key, String name, + double currentLimit, boolean openAction, + String branchToOperateId, TwoSides side) { + super(overloadManagementSystemId, key, name, currentLimit, openAction); + setBranchToOperateId(branchToOperateId); + setSideToOperate(side); + } + + @Override + public String getBranchToOperateId() { + return this.branchToOperateId; + } + + @Override + public BranchTripping setBranchToOperateId(String branchId) { + this.branchToOperateId = Objects.requireNonNull(branchId); + return this; + } + + @Override + public TwoSides getSideToOperate() { + return this.side; + } + + @Override + public BranchTripping setSideToOperate(TwoSides side) { + this.side = Objects.requireNonNull(side); + return this; + } + } + + static class ThreeWindingsTransformerTrippingImpl extends AbstractTrippingImpl + implements OverloadManagementSystem.ThreeWindingsTransformerTripping { + + private String threeWindingsTransformerId; + private ThreeSides side; + + protected ThreeWindingsTransformerTrippingImpl(String overloadManagementSystemId, String key, String name, + double currentLimit, boolean openAction, + String threeWindingsTransformerId, ThreeSides side) { + super(overloadManagementSystemId, key, name, currentLimit, openAction); + setThreeWindingsTransformerToOperateId(threeWindingsTransformerId); + setSideToOperate(side); + } + + @Override + public String getThreeWindingsTransformerToOperateId() { + return this.threeWindingsTransformerId; + } + + @Override + public ThreeWindingsTransformerTripping setThreeWindingsTransformerToOperateId(String threeWindingsTransformerId) { + this.threeWindingsTransformerId = Objects.requireNonNull(threeWindingsTransformerId); + return this; + } + + @Override + public ThreeSides getSideToOperate() { + return this.side; + } + + @Override + public ThreeWindingsTransformerTripping setSideToOperate(ThreeSides side) { + this.side = Objects.requireNonNull(side); + return this; + } + } + + private final SubstationImpl substation; + private final String monitoredElementId; + private final ThreeSides monitoredSide; + private final List trippings; + + OverloadManagementSystemImpl(String id, String name, SubstationImpl substation, + String monitoredElementId, ThreeSides monitoredSide, + boolean enabled) { + super(Objects.requireNonNull(substation).getNetworkRef(), id, name, enabled); + this.substation = Objects.requireNonNull(substation); + this.monitoredElementId = checkMonitoredElementId(monitoredElementId); + this.monitoredSide = Objects.requireNonNull(monitoredSide); + this.trippings = new ArrayList<>(); + } + + private String checkMonitoredElementId(String monitoredElementId) { + if (monitoredElementId == null) { + throw new ValidationException(this, "monitoredElementId is not set"); + } + Identifiable element = getNetwork().getIdentifiable(monitoredElementId); + if (element == null) { + throw new ValidationException(this, " '" + monitoredElementId + "' not found"); + } + return monitoredElementId; + } + + @Override + public Substation getSubstation() { + return this.substation; + } + + @Override + public NetworkImpl getNetwork() { + return this.substation.getNetwork(); + } + + @Override + public Network getParentNetwork() { + return this.substation.getParentNetwork(); + } + + @Override + protected String getTypeDescription() { + return "Overload management system"; + } + + @Override + public String getMonitoredElementId() { + return monitoredElementId; + } + + @Override + public ThreeSides getMonitoredSide() { + return monitoredSide; + } + + @Override + public void addTripping(Tripping tripping) { + this.trippings.add(tripping); + } + + @Override + public List getTrippings() { + return Collections.unmodifiableList(trippings); + } +} diff --git a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/SubnetworkImpl.java b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/SubnetworkImpl.java index 14656190df2..c0673bb2994 100644 --- a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/SubnetworkImpl.java +++ b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/SubnetworkImpl.java @@ -320,6 +320,27 @@ public ThreeWindingsTransformer getThreeWindingsTransformer(String id) { return contains(twt) ? twt : null; } + @Override + public Iterable getOverloadManagementSystems() { + return getOverloadManagementSystemStream().toList(); + } + + @Override + public Stream getOverloadManagementSystemStream() { + return getNetwork().getOverloadManagementSystemStream().filter(this::contains); + } + + @Override + public int getOverloadManagementSystemCount() { + return (int) getOverloadManagementSystemStream().count(); + } + + @Override + public OverloadManagementSystem getOverloadManagementSystem(String id) { + OverloadManagementSystem oms = getNetwork().getOverloadManagementSystem(id); + return contains(oms) ? oms : null; + } + @Override public Iterable getGenerators() { return getGeneratorStream().toList(); diff --git a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/SubstationImpl.java b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/SubstationImpl.java index 18efc70629f..e31cffb03ce 100644 --- a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/SubstationImpl.java +++ b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/SubstationImpl.java @@ -34,6 +34,8 @@ class SubstationImpl extends AbstractIdentifiable implements Substat private final Set voltageLevels = new LinkedHashSet<>(); + private final Set overloadManagementSystems = new LinkedHashSet<>(); + private boolean removed = false; SubstationImpl(String id, String name, boolean fictitious, Country country, String tso, Ref networkRef, Ref subnetworkRef) { @@ -166,6 +168,30 @@ public int getThreeWindingsTransformerCount() { .count()); } + void addOverloadManagementSystem(OverloadManagementSystemImpl overloadManagementSystem) { + overloadManagementSystems.add(overloadManagementSystem); + } + + @Override + public OverloadManagementSystemAdderImpl newOverloadManagementSystem() { + return new OverloadManagementSystemAdderImpl(this); + } + + @Override + public Iterable getOverloadManagementSystems() { + return Collections.unmodifiableSet(overloadManagementSystems); + } + + @Override + public Stream getOverloadManagementSystemStream() { + return overloadManagementSystems.stream().map(Function.identity()); + } + + @Override + public int getOverloadManagementSystemCount() { + return Ints.checkedCast(getOverloadManagementSystemStream().count()); + } + @Override public Set getGeographicalTags() { return Collections.unmodifiableSet(geographicalTags); diff --git a/iidm/iidm-impl/src/test/java/com/powsybl/iidm/network/impl/tck/OverloadManagementSystemTest.java b/iidm/iidm-impl/src/test/java/com/powsybl/iidm/network/impl/tck/OverloadManagementSystemTest.java new file mode 100644 index 00000000000..dfabd807cdc --- /dev/null +++ b/iidm/iidm-impl/src/test/java/com/powsybl/iidm/network/impl/tck/OverloadManagementSystemTest.java @@ -0,0 +1,15 @@ +/** + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.iidm.network.impl.tck; + +import com.powsybl.iidm.network.tck.AbstractOverloadManagementSystemTest; + +/** + * @author Olivier Perrin {@literal } + */ +public class OverloadManagementSystemTest extends AbstractOverloadManagementSystemTest { } diff --git a/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractOverloadManagementSystemTest.java b/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractOverloadManagementSystemTest.java new file mode 100644 index 00000000000..474a0c374ce --- /dev/null +++ b/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractOverloadManagementSystemTest.java @@ -0,0 +1,321 @@ +/** + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.iidm.network.tck; + +import com.google.common.collect.ImmutableSet; +import com.powsybl.iidm.network.*; +import com.powsybl.iidm.network.test.SecurityAnalysisTestNetworkFactory; +import com.powsybl.iidm.network.test.ThreeWindingsTransformerNetworkFactory; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.StreamSupport; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author Olivier Perrin {@literal } + */ +public abstract class AbstractOverloadManagementSystemTest { + @Test + public void baseTests() { + Network network = SecurityAnalysisTestNetworkFactory.create(); + Substation substation = network.getSubstation("S1"); + OverloadManagementSystem oms1 = substation.newOverloadManagementSystem() + .setId("OMS1") + .setName("1st OMS") + .setEnabled(true) + .setMonitoredElementId("LINE_S1S2V1_1") + .setMonitoredElementSide(ThreeSides.ONE) + .newSwitchTripping() + .setKey("SwTrip") + .setName("Tripping on switch") + .setCurrentLimit(80.) + .setOpenAction(true) + .setSwitchToOperateId("S1VL2_LINES1S2V1_1_BREAKER") + .add() + .newBranchTripping() + .setKey("LineTrip") + .setCurrentLimit(50) + .setOpenAction(false) + .setBranchToOperateId("LINE_S1S2V1_2") + .setSideToOperate(TwoSides.ONE) + .add() + .add(); + OverloadManagementSystem oms2 = substation.newOverloadManagementSystem() + .setId("OMS2") + .setEnabled(false) + .setMonitoredElementId("LINE_S1S2V1_2") + .setMonitoredElementSide(ThreeSides.TWO) + .newBranchTripping() + .setKey("2wtTrip") + .setName("Tripping on 2 windings transformer") + .setCurrentLimit(100.) + .setOpenAction(true) + .setBranchToOperateId("TWT") + .setSideToOperate(TwoSides.TWO) + .add() + .add(); + + assertNotNull(oms1); + assertNotNull(oms2); + + assertEquals(2, substation.getOverloadManagementSystemCount()); + + Iterable iterable = substation.getOverloadManagementSystems(); + List retreived = StreamSupport.stream(iterable.spliterator(), false).toList(); + assertEquals(2, retreived.size()); + assertTrue(retreived.containsAll(ImmutableSet.of(oms1, oms2))); + + retreived = substation.getOverloadManagementSystemStream().toList(); + assertEquals(2, retreived.size()); + assertTrue(retreived.containsAll(ImmutableSet.of(oms1, oms2))); + + assertEquals("OMS1", oms1.getId()); + assertEquals("OMS2", oms2.getId()); + assertEquals("1st OMS", oms1.getNameOrId()); + assertEquals("OMS2", oms2.getNameOrId()); + assertTrue(oms1.isEnabled()); + assertFalse(oms2.isEnabled()); + assertEquals("LINE_S1S2V1_1", oms1.getMonitoredElementId()); + assertEquals("LINE_S1S2V1_2", oms2.getMonitoredElementId()); + assertEquals(ThreeSides.ONE, oms1.getMonitoredSide()); + assertEquals(ThreeSides.TWO, oms2.getMonitoredSide()); + + List trippings = oms1.getTrippings(); + assertEquals(2, trippings.size()); + + assertEquals(OverloadManagementSystem.Tripping.Type.SWITCH_TRIPPING, trippings.get(0).getType()); + OverloadManagementSystem.SwitchTripping swTripping = (OverloadManagementSystem.SwitchTripping) trippings.get(0); + assertEquals("SwTrip", swTripping.getKey()); + assertEquals("Tripping on switch", swTripping.getNameOrKey()); + assertEquals(80., swTripping.getCurrentLimit()); + assertTrue(swTripping.isOpenAction()); + assertEquals("S1VL2_LINES1S2V1_1_BREAKER", swTripping.getSwitchToOperateId()); + + assertEquals(OverloadManagementSystem.Tripping.Type.BRANCH_TRIPPING, trippings.get(1).getType()); + OverloadManagementSystem.BranchTripping brTripping = (OverloadManagementSystem.BranchTripping) trippings.get(1); + assertEquals("LineTrip", brTripping.getKey()); + assertEquals("LineTrip", brTripping.getNameOrKey()); + assertEquals(50., brTripping.getCurrentLimit()); + assertFalse(brTripping.isOpenAction()); + assertEquals("LINE_S1S2V1_2", brTripping.getBranchToOperateId()); + assertEquals(TwoSides.ONE, brTripping.getSideToOperate()); + + trippings = oms2.getTrippings(); + assertEquals(1, trippings.size()); + assertEquals(OverloadManagementSystem.Tripping.Type.BRANCH_TRIPPING, trippings.get(0).getType()); + brTripping = (OverloadManagementSystem.BranchTripping) trippings.get(0); + assertEquals("2wtTrip", brTripping.getKey()); + assertEquals("Tripping on 2 windings transformer", brTripping.getNameOrKey()); + assertEquals(100., brTripping.getCurrentLimit()); + assertTrue(brTripping.isOpenAction()); + assertEquals("TWT", brTripping.getBranchToOperateId()); + assertEquals(TwoSides.TWO, brTripping.getSideToOperate()); + } + + @Test + public void threeWindingsTransformerTrippingTest() { + Network network = ThreeWindingsTransformerNetworkFactory.create(); + Substation substation = network.getSubstation("SUBSTATION"); + OverloadManagementSystem oms = substation.newOverloadManagementSystem() + .setId("OMS") + .setName("An OMS") + .setEnabled(true) + .setMonitoredElementId("3WT") + .setMonitoredElementSide(ThreeSides.TWO) + .newThreeWindingsTransformerTripping() + .setKey("3wtTrip") + .setName("Tripping on 3 windings transformer") + .setCurrentLimit(60.) + .setOpenAction(true) + .setThreeWindingsTransformerToOperateId("3WT") + .setSideToOperate(ThreeSides.THREE) + .add() + .add(); + assertNotNull(oms); + + List trippings = oms.getTrippings(); + assertEquals(1, trippings.size()); + assertEquals(OverloadManagementSystem.Tripping.Type.THREE_WINDINGS_TRANSFORMER_TRIPPING, trippings.get(0).getType()); + OverloadManagementSystem.ThreeWindingsTransformerTripping twtTripping = + (OverloadManagementSystem.ThreeWindingsTransformerTripping) trippings.get(0); + assertEquals("3wtTrip", twtTripping.getKey()); + assertEquals("Tripping on 3 windings transformer", twtTripping.getNameOrKey()); + assertEquals(60., twtTripping.getCurrentLimit()); + assertTrue(twtTripping.isOpenAction()); + assertEquals("3WT", twtTripping.getThreeWindingsTransformerToOperateId()); + assertEquals(ThreeSides.THREE, twtTripping.getSideToOperate()); + } + + @Test + public void testSetterGetterInMultiVariants() { + Network network = SecurityAnalysisTestNetworkFactory.create(); + Substation substation = network.getSubstation("S1"); + OverloadManagementSystem oms1 = substation.newOverloadManagementSystem() + .setId("OMS1") + .setEnabled(true) + .setMonitoredElementId("LINE_S1S2V1_1") + .setMonitoredElementSide(ThreeSides.ONE) + .newBranchTripping() + .setKey("LineTrip") + .setCurrentLimit(50) + .setOpenAction(false) + .setBranchToOperateId("LINE_S1S2V1_2") + .setSideToOperate(TwoSides.ONE) + .add() + .add(); + VariantManager variantManager = network.getVariantManager(); + List variantsToAdd = Arrays.asList("s1", "s2", "s3", "s4"); + variantManager.cloneVariant(VariantManagerConstants.INITIAL_VARIANT_ID, variantsToAdd); + + variantManager.setWorkingVariant("s4"); + // check value cloned by extend + assertTrue(oms1.isEnabled()); + // change value in s4 + oms1.setEnabled(false); + + // remove s2 + variantManager.removeVariant("s2"); + + variantManager.cloneVariant("s4", "s2b"); + variantManager.setWorkingVariant("s2b"); + // check value cloned by allocate + assertFalse(oms1.isEnabled()); + + // recheck initial variant value + variantManager.setWorkingVariant(VariantManagerConstants.INITIAL_VARIANT_ID); + assertTrue(oms1.isEnabled()); + + // remove working variant s4 + variantManager.setWorkingVariant("s4"); + variantManager.removeVariant("s4"); + assertThrows(Exception.class, oms1::isEnabled); + } + + @Test + public void invalidCurrentLimitsTest() { + Network network = SecurityAnalysisTestNetworkFactory.create(); + Substation substation = network.getSubstation("S1"); + OverloadManagementSystemAdder omsAdder = substation.newOverloadManagementSystem() + .setId("OMS1") + .setMonitoredElementId("LINE_S1S2V1_1") + .setMonitoredElementSide(ThreeSides.ONE); + OverloadManagementSystemAdder.BranchTrippingAdder trippingAdder = omsAdder + .newBranchTripping() + .setKey("LineTrip") + .setOpenAction(false) + .setBranchToOperateId("LINE_S1S2V1_2") + .setSideToOperate(TwoSides.ONE) + .setCurrentLimit(-50); + trippingAdder.add(); + assertThrows(ValidationException.class, omsAdder::add); + + trippingAdder.setCurrentLimit(Double.NaN); + assertThrows(ValidationException.class, omsAdder::add); + } + + @Test + public void duplicateTrippingKeysOnSameOmsTest() { + Network network = SecurityAnalysisTestNetworkFactory.create(); + Substation substation = network.getSubstation("S1"); + String duplicateKey = "duplicate"; + OverloadManagementSystemAdder omsAdder = substation.newOverloadManagementSystem() + .setId("OMS1") + .setMonitoredElementId("LINE_S1S2V1_1") + .setMonitoredElementSide(ThreeSides.ONE) + .newSwitchTripping() + .setKey(duplicateKey) + .setCurrentLimit(80.) + .setOpenAction(true) + .setSwitchToOperateId("S1VL2_LINES1S2V1_1_BREAKER") + .add() + .newBranchTripping() + .setKey(duplicateKey) + .setOpenAction(false) + .setBranchToOperateId("LINE_S1S2V1_2") + .setSideToOperate(TwoSides.ONE) + .setCurrentLimit(-50) + .add(); + // duplicate tripping keys are NOT allowed if they are on the same OverloadManagementSystem + assertThrows(ValidationException.class, omsAdder::add); + } + + @Test + public void duplicateTrippingKeysOnDifferentOmsTest() { + Network network = SecurityAnalysisTestNetworkFactory.create(); + Substation substation = network.getSubstation("S1"); + String duplicateKey = "duplicate"; + substation.newOverloadManagementSystem() + .setId("OMS1") + .setMonitoredElementId("LINE_S1S2V1_1") + .setMonitoredElementSide(ThreeSides.ONE) + .newSwitchTripping() + .setKey(duplicateKey) + .setCurrentLimit(80.) + .setOpenAction(true) + .setSwitchToOperateId("S1VL2_LINES1S2V1_1_BREAKER") + .add() + .add(); + OverloadManagementSystemAdder omsAdder = substation.newOverloadManagementSystem() + .setId("OMS2") + .setMonitoredElementId("LINE_S1S2V1_1") + .setMonitoredElementSide(ThreeSides.TWO) + .newBranchTripping() + .setKey(duplicateKey) + .setOpenAction(false) + .setBranchToOperateId("LINE_S1S2V1_2") + .setSideToOperate(TwoSides.ONE) + .setCurrentLimit(50) + .add(); + // duplicate tripping keys are allowed if they are on distinct OverloadManagementSystems + assertDoesNotThrow(omsAdder::add); + } + + @Test + public void unknownMonitoredElementTest() { + Network network = SecurityAnalysisTestNetworkFactory.create(); + Substation substation = network.getSubstation("S1"); + OverloadManagementSystemAdder omsAdder = substation.newOverloadManagementSystem() + .setId("OMS1") + .setMonitoredElementSide(ThreeSides.ONE) + .newBranchTripping() + .setKey("LineTrip") + .setOpenAction(false) + .setBranchToOperateId("LINE_S1S2V1_2") + .setSideToOperate(TwoSides.ONE) + .setCurrentLimit(50) + .add(); + ValidationException ex = assertThrows(ValidationException.class, omsAdder::add); + assertTrue(ex.getMessage().contains("monitoredElementId is not set")); + + omsAdder.setMonitoredElementId("UNKNOWN"); + ex = assertThrows(ValidationException.class, omsAdder::add); + assertTrue(ex.getMessage().contains("'UNKNOWN' not found")); + } + + @Test + public void unknownTrippingElementTest() { + Network network = SecurityAnalysisTestNetworkFactory.create(); + Substation substation = network.getSubstation("S1"); + OverloadManagementSystemAdder omsAdder = substation.newOverloadManagementSystem() + .setId("OMS1") + .setMonitoredElementId("LINE_S1S2V1_1") + .setMonitoredElementSide(ThreeSides.ONE) + .newBranchTripping() + .setKey("LineTrip") + .setOpenAction(false) + .setBranchToOperateId("UNKNOWN") + .setSideToOperate(TwoSides.ONE) + .setCurrentLimit(50) + .add(); + ValidationException ex = assertThrows(ValidationException.class, omsAdder::add); + assertTrue(ex.getMessage().contains("'UNKNOWN' not found")); + } +} diff --git a/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractSubnetworksExplorationTest.java b/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractSubnetworksExplorationTest.java index fa187ab006c..bc0988e0665 100644 --- a/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractSubnetworksExplorationTest.java +++ b/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractSubnetworksExplorationTest.java @@ -191,8 +191,9 @@ private static Network createNetwork(String networkId, Country otherSubstationCo .setR(0.24 / 1300 * (38 * 38)).setX(Math.sqrt(10 * 10 - 0.24 * 0.24) / 1300 * (38 * 38)) .setG(0.0).setB(0.0) .add(); + String lineId1 = id("line1", networkId); n.newLine() - .setId(id("line1", networkId)) + .setId(lineId1) .setVoltageLevel1(id("voltageLevel1", networkId)) .setNode1(13) .setVoltageLevel2(id("voltageLevel2", networkId)) @@ -220,6 +221,19 @@ private static Network createNetwork(String networkId, Country otherSubstationCo .setR(1.0).setX(0.1).setG(0.0).setB(0.001).setP0(10).setQ0(1) .setPairingKey("mergingKey") // when merging both networks, this key will be used to create a tie line .add(); + substation3.newOverloadManagementSystem() + .setId(id("overloadManagementSystem", networkId)) + .setEnabled(true) + .setMonitoredElementId(lineId1) + .setMonitoredElementSide(ThreeSides.ONE) + .newBranchTripping() + .setKey("branchTripping") + .setCurrentLimit(80.) + .setOpenAction(true) + .setBranchToOperateId(lineId1) + .setSideToOperate(TwoSides.ONE) + .add() + .add(); return n; } @@ -549,6 +563,18 @@ public void testExploreBranches() { Network::getBranch); } + @Test + public void testExploreOverloadManagementSystems() { + var expectedIdsForSubnetwork1 = List.of(id("overloadManagementSystem", ID_1)); + var expectedIdsForSubnetwork2 = List.of(id("overloadManagementSystem", ID_2)); + + testExploreElements(expectedIdsForSubnetwork1, expectedIdsForSubnetwork2, + Network::getOverloadManagementSystems, + Network::getOverloadManagementSystemStream, + Network::getOverloadManagementSystemCount, + Network::getOverloadManagementSystem); + } + @Test public void testExploreConnectables() { var expectedIdsForSubnetwork1 = List.of(id("battery1", ID_1),