Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ core.iidm.modification.positionOrderAlreadyTaken = PositionOrder ${positionOrder
core.iidm.modification.positionOrderTooHigh = PositionOrder ${positionOrder} too high (>${maxValue}). No position extension created.
core.iidm.modification.positionOrderTooLow = PositionOrder ${positionOrder} too low (<${minValue}). No position extension created.
core.iidm.modification.removeBayBusbarSectionConnectable = Cannot remove feeder bay for connectable ${connectableId}, as it is a busbarSection
core.iidm.modification.moveBayBusbarSectionConnectable = Cannot move feeder bay for connectable ${connectableId}, as it is a busbarSection
core.iidm.modification.removedTieLine = Removed tie line ${tieLineId} with pairing key ${pairingKey}
core.iidm.modification.removedTieLineAndAssociatedDanglingLines = Removed tie line ${tieLineId} and associated dangling lines ${danglingLineId1} and ${danglingLineId2} with pairing key ${pairingKey}
core.iidm.modification.RemoveFeederBayAborted = Remove feeder bay of ${connectableId} cannot go further node ${node}, as it is connected to ${otherConnectableId}
Expand Down
22 changes: 22 additions & 0 deletions docs/grid_features/network_modifications.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,28 @@ connectables are removed. The branches and three-winding transformers are also r
substations.
The builder takes the ID of the substation as input.

### Moving a network element

#### MoveFeederBay
This class is used to move feeder bays of connectables
(except `BusOrBusBarSection` connectables) from one place to another within a network.

This class allows to move a feeder bay from one busbar section to another within the network.
The builder should be used to create any instance of this class. It takes as input:

- The ID of the connectable whose feeder bay will be moved (`connectableId`). Note that `BusOrBusBarSection` connectables are not accepted.
- The ID of the target bus or busbar section (`targetBusOrBusBarSectionId`) to which the feeder bay should be connected.
- The ID of the target voltage level (`targetVoltageLevelId`) where the feeder bay will be moved to.
- The terminal object that specifies which terminal of the connectable should be moved.

When the modification is applied on the network, the system identifies and updates all relevant switches and connections
to move the feeder bay from its current position to the specified target place. This includes disconnecting
from the original busbar section and reconnecting to the target busbar section.
If the target voltage level topology kind is `BUS_BREAKER`, the connectable is connected to the target bus without additional switches.
If the target voltage level topology kind is `NODE_BREAKER`, the appropriate disconnectors and breakers are created to connect
the feeder bay to the target busbar section, maintaining the correct topology.
This modification ensures that the connectivity of the network is preserved while moving the feeder bay to its new position.

### Connect a line on a line or a voltage level on a line

#### ConnectVoltageLevelOnLine
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import com.powsybl.iidm.modification.NetworkModificationImpact;
import com.powsybl.iidm.modification.util.ModificationLogs;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.BusbarSectionPosition;
import com.powsybl.iidm.network.extensions.ConnectablePosition;
import com.powsybl.iidm.network.extensions.ConnectablePositionAdder;
import org.apache.commons.lang3.Range;
Expand Down Expand Up @@ -237,39 +236,12 @@ private void createExtensionAndTopology(Connectable<?> connectable, Network netw
LOGGER.warn("No ConnectablePosition extension found on voltageLevel {}. The ConnectablePosition extension is not created for new feeder {}.", voltageLevel.getId(), connectableId);
noConnectablePositionExtension(reportNode, voltageLevel, connectableId);
}
int connectableNode = getNode(side, connectable);
// create switches and a breaker linking the connectable to the busbar sections.
createTopology(side, network, voltageLevel, connectable, namingStrategy, reportNode);
createTopologyWithConnectableNode(side, busOrBusbarSectionId, network, voltageLevel, connectableNode, connectable, namingStrategy, reportNode);
}
if (createConnectablePosition) {
connectablePositionAdder.add();
}
}

private void createTopology(int side, Network network, VoltageLevel voltageLevel, Connectable<?> connectable, NamingStrategy namingStrategy, ReportNode reportNode) {
// Nodes
int connectableNode = getNode(side, connectable);
int forkNode = voltageLevel.getNodeBreakerView().getMaximumNodeIndex() + 1;

// Information gathering
String baseId = namingStrategy.getSwitchBaseId(connectable, side);
String bbsId = getBusOrBusbarSectionId(side);
BusbarSection bbs = network.getBusbarSection(bbsId);
BusbarSectionPosition position = bbs.getExtension(BusbarSectionPosition.class);

// Topology creation
int parallelBbsNumber = 0;
if (position == null) {
// No position extension is present so only one disconnector is needed
createNodeBreakerSwitchesTopology(voltageLevel, connectableNode, forkNode, namingStrategy, baseId, bbs);
LOGGER.warn("No busbar section position extension found on {}, only one disconnector is created.", bbs.getId());
noBusbarSectionPositionExtensionReport(reportNode, bbs);
} else {
List<BusbarSection> bbsList = getParallelBusbarSections(voltageLevel, position);
parallelBbsNumber = bbsList.size() - 1;
createNodeBreakerSwitchesTopology(voltageLevel, connectableNode, forkNode, namingStrategy, baseId, bbsList, bbs);
}
LOGGER.info("New feeder bay associated to {} of type {} was created and connected to voltage level {} on busbar section {} with a closed disconnector " +
"and on {} parallel busbar sections with an open disconnector.", connectable.getId(), connectable.getType(), voltageLevel.getId(), bbsId, parallelBbsNumber);
createdNodeBreakerFeederBay(reportNode, voltageLevel.getId(), bbsId, connectable, parallelBbsNumber);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/**
* Copyright (c) 2025, 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.modification.topology;

import com.powsybl.commons.report.ReportNode;
import com.powsybl.computation.ComputationManager;
import com.powsybl.iidm.modification.AbstractNetworkModification;
import com.powsybl.iidm.modification.NetworkModificationImpact;
import com.powsybl.iidm.network.*;

import java.util.Objects;

import static com.powsybl.iidm.modification.topology.TopologyModificationUtils.cleanNodeBreakerTopology;
import static com.powsybl.iidm.modification.topology.TopologyModificationUtils.createTopologyAndGetConnectableNode;
import static com.powsybl.iidm.modification.util.ModificationLogs.logOrThrow;
import static com.powsybl.iidm.modification.util.ModificationReports.moveFeederBayBusbarSectionReport;
import static com.powsybl.iidm.modification.util.ModificationReports.notFoundConnectableReport;

/**
* This modification moves a feeder bay from one busBar section to another.
* It identifies and updates the relevant switches and connections to achieve the move operation.
* @author Ghazwa Rehili {@literal <ghazwa.rehili at rte-france.com>}
*/
public class MoveFeederBay extends AbstractNetworkModification {
private final String connectableId;
private final String targetBusOrBusBarSectionId;
private final String targetVoltageLevelId;
private final Terminal terminal;

/**
* @param connectableId non-null id of the connectable whose feeder bay will be moved (BusOrBusBarSection are not accepted)
* @param targetBusOrBusBarId non-null id of the target BusOrBusBar section
* @param targetVoltageLevelId non-null id of the target voltage Level
* @param terminal non-null terminal
*/
MoveFeederBay(String connectableId, String targetBusOrBusBarId, String targetVoltageLevelId, Terminal terminal) {
this.connectableId = Objects.requireNonNull(connectableId);
this.targetBusOrBusBarSectionId = Objects.requireNonNull(targetBusOrBusBarId);
this.targetVoltageLevelId = Objects.requireNonNull(targetVoltageLevelId);
this.terminal = Objects.requireNonNull(terminal);
}

@Override
public void apply(Network network, NamingStrategy namingStrategy, boolean throwException,
ComputationManager computationManager, ReportNode reportNode) {
// Get and validate connectable
Connectable<?> connectable = network.getConnectable(connectableId);
if (!validateConnectable(connectable, throwException, reportNode)) {
return;
}

// Get voltage level and perform move operation based on topology kind
VoltageLevel voltageLevel = network.getVoltageLevel(targetVoltageLevelId);
if (voltageLevel.getTopologyKind() == TopologyKind.NODE_BREAKER) {
moveInNodeBreakerTopology(network, connectable, voltageLevel, namingStrategy, reportNode);
} else {
moveInBusBreakerTopology(terminal);
}
}

/**
* Move the connectable in node-breaker topology
*/
private void moveInNodeBreakerTopology(Network network, Connectable<?> connectable,
VoltageLevel voltageLevel, NamingStrategy namingStrategy,
ReportNode reportNode) {
// Clean existing topology
cleanNodeBreakerTopology(network, connectableId, reportNode);

// Create new topology and Get node information
int side = getSideFromTerminal(terminal, connectable);
int connectableNode = createTopologyAndGetConnectableNode(side, targetBusOrBusBarSectionId, network, voltageLevel, connectable, namingStrategy, reportNode);

// Move the terminal of the connectable to the new node
terminal.getNodeBreakerView().moveConnectable(connectableNode, voltageLevel.getId());
}

/**
* Move the connectable in bus-breaker topology
*/
private void moveInBusBreakerTopology(Terminal terminal) {
terminal.getBusBreakerView().moveConnectable(targetBusOrBusBarSectionId, terminal.isConnected());
}

/**
* Get the side value
*/
private int getSideFromTerminal(Terminal terminal, Connectable<?> connectable) {
if (connectable instanceof Injection<?>) {
return 0;
} else if (connectable instanceof Branch<?> || connectable instanceof ThreeWindingsTransformer) {
return terminal.getSide().getNum();
}
throw new IllegalStateException("Unsupported connectable type: " + connectable.getClass().getSimpleName());
}

@Override
public String getName() {
return "MoveFeederBay";
}

@Override
public NetworkModificationImpact hasImpactOnNetwork(Network network) {
impact = DEFAULT_IMPACT;
Connectable<?> connectable = network.getConnectable(connectableId);
BusbarSection targetBusbarSection = network.getBusbarSection(targetBusOrBusBarSectionId);

// Check preconditions: valid connectable and target busbar section
if (connectable == null || connectable instanceof BusbarSection || targetBusbarSection == null) {
impact = NetworkModificationImpact.CANNOT_BE_APPLIED;
return impact;
}

VoltageLevel targetVoltageLevel = targetBusbarSection.getTerminal().getVoltageLevel();

// Check if any terminal is in the same voltage level
boolean hasTerminalInTargetVoltageLevel = connectable.getTerminals().stream()
.anyMatch(t -> t.getVoltageLevel().getId().equals(targetVoltageLevel.getId()));

if (!hasTerminalInTargetVoltageLevel) {
impact = NetworkModificationImpact.CANNOT_BE_APPLIED;
return impact;
}
return impact;
}

/**
* Check if the connectable is valid for this modification
*/
private boolean validateConnectable(Connectable<?> connectable, boolean throwException, ReportNode reportNode) {
if (connectable == null) {
notFoundConnectableReport(reportNode, connectableId);
logOrThrow(throwException, "Connectable not found: " + connectableId);
return false;
}

if (connectable instanceof BusbarSection) {
moveFeederBayBusbarSectionReport(reportNode, connectableId);
logOrThrow(throwException, "BusbarSection connectables are not allowed as MoveFeederBay input: " + connectableId);
return false;
}

return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Copyright (c) 2025, 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.modification.topology;

import com.powsybl.iidm.network.Terminal;

/**
* @author Ghazwa Rehili {@literal <ghazwa.rehili at rte-france.com>}
*/

public class MoveFeederBayBuilder {
private String connectableId = null;
private String targetBusOrBusBarSectionId = null;
private String targetVoltageLevelId = null;
private Terminal terminal = null;

public MoveFeederBay build() {
return new MoveFeederBay(connectableId, targetBusOrBusBarSectionId, targetVoltageLevelId, terminal);
}

/**
* @param connectableId the non-null ID of the connectable
*/
public MoveFeederBayBuilder withConnectableId(String connectableId) {
this.connectableId = connectableId;
return this;
}

public MoveFeederBayBuilder withTargetBusOrBusBarSectionId(String busOrBbsId) {
this.targetBusOrBusBarSectionId = busOrBbsId;
return this;
}

public MoveFeederBayBuilder withTargetVoltageLevelId(String voltageLevelId) {
this.targetVoltageLevelId = voltageLevelId;
return this;
}

public MoveFeederBayBuilder withTerminal(Terminal terminal) {
this.terminal = terminal;
return this;
}
}

Loading