Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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 @@ -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 @@ -51,8 +50,6 @@ abstract class AbstractCreateConnectableFeederBays extends AbstractNetworkModifi

protected abstract ConnectablePosition.Direction getDirection(int side);

protected abstract int getNode(int side, Connectable<?> connectable);

protected abstract ConnectablePositionAdder.FeederAdder<?> getFeederAdder(int side, ConnectablePositionAdder<?> connectablePositionAdder);

protected AbstractCreateConnectableFeederBays(int... sides) {
Expand Down Expand Up @@ -238,38 +235,10 @@ private void createExtensionAndTopology(Connectable<?> connectable, Network netw
noConnectablePositionExtension(reportNode, voltageLevel, connectableId);
}
// create switches and a breaker linking the connectable to the busbar sections.
createTopology(side, network, voltageLevel, connectable, namingStrategy, reportNode);
createTopology(side, busOrBusbarSectionId, network, voltageLevel, 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
Expand Up @@ -136,18 +136,6 @@ protected ConnectablePosition.Direction getDirection(int side) {
throw createSideIllegalStateException(side);
}

@Override
protected int getNode(int side, Connectable<?> connectable) {
Branch<?> branch = (Branch<?>) connectable;
if (side == 1) {
return branch.getTerminal1().getNodeBreakerView().getNode();
}
if (side == 2) {
return branch.getTerminal2().getNodeBreakerView().getNode();
}
throw createSideIllegalStateException(side);
}

@Override
protected ConnectablePositionAdder.FeederAdder<?> getFeederAdder(int side, ConnectablePositionAdder<?> connectablePositionAdder) {
if (side == 1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,6 @@ protected ConnectablePosition.Direction getDirection(int side) {
return injectionDirection;
}

@Override
protected int getNode(int side, Connectable<?> connectable) {
return ((Injection<?>) connectable).getTerminal().getNodeBreakerView().getNode();
}

@Override
protected ConnectablePositionAdder.FeederAdder<?> getFeederAdder(int side, ConnectablePositionAdder<?> connectablePositionAdder) {
return connectablePositionAdder.newFeeder();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/**
* 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.HashMap;
import java.util.Map;
import java.util.Objects;

import static com.powsybl.iidm.modification.topology.TopologyModificationUtils.cleanNodeBreakerTopology;
import static com.powsybl.iidm.modification.topology.TopologyModificationUtils.createTopology;
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;

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

@Override
public void apply(Network network, NamingStrategy namingStrategy, boolean throwException, ComputationManager computationManager, ReportNode reportNode) {
Connectable<?> connectable = network.getConnectable(connectableId);
if (!checkConnectable(throwException, reportNode, connectable)) {
return;
}
VoltageLevel voltageLevel = network.getVoltageLevel(targetVoltageLevelId);
if (voltageLevel.getTopologyKind() == TopologyKind.NODE_BREAKER) {
cleanNodeBreakerTopology(network, connectableId, reportNode);
createTopology(getSideFromTerminal(terminal, connectable), targetBusOrBusbarSectionId, network, voltageLevel, connectable, namingStrategy, reportNode);
Map<VoltageLevel, Integer> firstAvailableNodes = new HashMap<>();
int connectableNode = firstAvailableNodes.compute(voltageLevel, this::getNextAvailableNode);
terminal.getNodeBreakerView().moveConnectable(connectableNode, voltageLevel.getId());
} else {
terminal.getBusBreakerView().moveConnectable(targetBusOrBusbarSectionId, terminal.isConnected());
}
}

private int getSideFromTerminal(Terminal terminal, Connectable<?> connectable) {
if (connectable instanceof Injection<?>) {
return 0;
} else if (connectable instanceof Branch<?>) {
return terminal.getSide().getNum();
}
throw new IllegalStateException("Unexpected connectable: " + connectable);
}

private int getNextAvailableNode(VoltageLevel vl, Integer node) {
return node == null ? vl.getNodeBreakerView().getMaximumNodeIndex() + 1 : node + 1;
}

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

@Override
public NetworkModificationImpact hasImpactOnNetwork(Network network) {
NetworkModificationImpact impact = DEFAULT_IMPACT;

// Check connectable and target busbar section exists
Connectable<?> connectable = network.getConnectable(connectableId);
BusbarSection targetBusbarSection = network.getBusbarSection(targetBusOrBusbarSectionId);
if (connectable == null || connectable instanceof BusbarSection || targetBusbarSection == null) {
impact = NetworkModificationImpact.CANNOT_BE_APPLIED;
return impact;
}

// Check that at least one terminal is in the same voltage level as the target busbar section
VoltageLevel targetVoltageLevel = targetBusbarSection.getTerminal().getVoltageLevel();
boolean hasTerminalInTargetVoltageLevel = false;

for (Terminal terminal : connectable.getTerminals()) {
if (terminal.getVoltageLevel().getId().equals(targetVoltageLevel.getId())) {
hasTerminalInTargetVoltageLevel = true;
break;
}
}

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

return impact;
}

private boolean checkConnectable(boolean throwException, ReportNode reportNode, Connectable<?> connectable) {
if (connectable instanceof BusbarSection) {
moveFeederBayBusbarSectionReport(reportNode, connectableId);
logOrThrow(throwException, "BusbarSection connectables are not allowed as MoveFeederBay input: " + connectableId);
return false;
}
if (connectable == null) {
notFoundConnectableReport(reportNode, connectableId);
logOrThrow(throwException, "Connectable not found: " + 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 withBusOrBusbarSectionId(String busOrBbs) {
this.targetBusOrBusbarSectionId = busOrBbs;
return this;
}

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

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

Loading