Skip to content
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
c112b6a
enhance BusbarSectionFinderTraverser to handle all cases
ghazwarhili Sep 15, 2025
bd1c1c5
add TU for fork topo
ghazwarhili Sep 22, 2025
dab0cf8
enhance coverage code
ghazwarhili Sep 23, 2025
8ea7a25
Merge branch 'main' into fix-busbar-section-finder-traverser
ghazwarhili Sep 23, 2025
78f18fd
enhance TU
ghazwarhili Sep 23, 2025
efc0ece
breadth-first busbasrsection id search algorithm
ghazwarhili Sep 29, 2025
ca84d42
add TU
ghazwarhili Sep 30, 2025
8ba0040
resolving conflicts
ghazwarhili Sep 30, 2025
b03d915
unused import
ghazwarhili Sep 30, 2025
a1482d3
fix sonar issues
ghazwarhili Sep 30, 2025
6bcd0d2
enhance TU to add bypass topo
ghazwarhili Sep 30, 2025
6b5a7f1
enhance TU with mixed topo kind
ghazwarhili Sep 30, 2025
a48c699
EtienneH code review remarks
ghazwarhili Sep 30, 2025
8bf25d4
add author
ghazwarhili Sep 30, 2025
999f53c
etienneH code review remarks part 2
ghazwarhili Oct 1, 2025
28dc2d2
clean code
ghazwarhili Oct 1, 2025
7cd598c
save
etiennehomer Oct 1, 2025
7a975c9
Save paths throw one traverse
etiennehomer Oct 1, 2025
84b8d9a
fix
etiennehomer Oct 1, 2025
f15399d
fix code and remove shared variables between traverser (fork case)
ghazwarhili Oct 1, 2025
e1c16db
Merge remote-tracking branch 'origin/save_Traverser' into save_Traverser
ghazwarhili Oct 1, 2025
80a51ec
enhacement to use allSwitchesClosed
ghazwarhili Oct 1, 2025
6d77c90
implement and handle NodeState
ghazwarhili Oct 2, 2025
1380c2b
equals in tests
etiennehomer Oct 3, 2025
29f95d1
import
etiennehomer Oct 3, 2025
283864f
fix for NodeState
ghazwarhili Oct 3, 2025
7b2b7d9
Merge remote-tracking branch 'origin/save_Traverser' into save_Traverser
ghazwarhili Oct 3, 2025
ed704f1
add busbarsByNode
ghazwarhili Oct 3, 2025
42031cb
revert to simple version
etiennehomer Oct 6, 2025
542b0ce
enhance TU
ghazwarhili Oct 6, 2025
03c3588
Merge remote-tracking branch 'origin/save_Traverser' into save_Traverser
ghazwarhili Oct 6, 2025
d930afc
Merge branch 'main' into save_Traverser
ghazwarhili Oct 6, 2025
d9f9401
code review remarks
ghazwarhili Oct 6, 2025
d6891e9
Merge remote-tracking branch 'origin/save_Traverser' into save_Traverser
ghazwarhili Oct 6, 2025
d94557e
enhance TU
ghazwarhili Oct 6, 2025
ba4df07
enhance TU part 2
ghazwarhili Oct 6, 2025
a4c892e
clean TU
ghazwarhili Oct 6, 2025
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 @@ -6,42 +6,97 @@
*/
package org.gridsuite.network.map.dto.definition.extension;

import com.powsybl.iidm.network.IdentifiableType;
import com.powsybl.iidm.network.BusbarSection;
import com.powsybl.iidm.network.Switch;
import com.powsybl.iidm.network.Terminal;
import com.powsybl.iidm.network.VoltageLevel;
import com.powsybl.math.graph.TraversalType;
import com.powsybl.math.graph.TraverseResult;

import java.util.*;

/**
* @author Slimane Amar <slimane.amar at rte-france.com>
* @author Ghazwa Rehili <ghazwa.rehili at rte-france.com>
*/
public class BusbarSectionFinderTraverser implements Terminal.TopologyTraverser {
// TODO : code to move to powsybl-core or powsybl-network-store
public final class BusbarSectionFinderTraverser {

private BusbarSectionFinderTraverser() {
throw new UnsupportedOperationException();
}

private final boolean onlyConnectedBbs;
public record SwitchInfo(String id, boolean isOpen) { }

private String firstTraversedBbsId;
public record BusbarSectionResult(String busbarSectionId, int depth, SwitchInfo lastSwitch, boolean allClosedSwitch) { }

public BusbarSectionFinderTraverser(boolean onlyConnectedBbs) {
this.onlyConnectedBbs = onlyConnectedBbs;
public static String findBusbarSectionId(Terminal terminal) {
BusbarSectionResult result = getBusbarSectionResult(terminal);
return result != null ? result.busbarSectionId() : terminal.getVoltageLevel().getNodeBreakerView().getBusbarSections().iterator().next().getId();
}

@Override
public TraverseResult traverse(Terminal terminal, boolean connected) {
if (terminal.getConnectable().getType() == IdentifiableType.BUSBAR_SECTION) {
firstTraversedBbsId = terminal.getConnectable().getId();
return TraverseResult.TERMINATE_TRAVERSER;
public static BusbarSectionResult getBusbarSectionResult(Terminal terminal) {
int startNode = terminal.getNodeBreakerView().getNode();
List<BusbarSectionResult> allResults = searchAllBusbars(terminal.getVoltageLevel(), startNode);
if (allResults.isEmpty()) {
return null;
}
return TraverseResult.CONTINUE;
return selectBestBusbar(allResults);
}

@Override
public TraverseResult traverse(Switch aSwitch) {
if (onlyConnectedBbs && aSwitch.isOpen()) {
return TraverseResult.TERMINATE_PATH;
private static BusbarSectionResult selectBestBusbar(List<BusbarSectionResult> results) {
List<BusbarSectionResult> withAllClosedSwitch = results.stream().filter(r -> r.allClosedSwitch).toList();
if (!withAllClosedSwitch.isEmpty()) {
return withAllClosedSwitch.stream().min(Comparator.comparingInt(BusbarSectionResult::depth)
.thenComparing(BusbarSectionResult::busbarSectionId)).orElse(null);
}
return TraverseResult.CONTINUE;
List<BusbarSectionResult> withClosedSwitch = results.stream().filter(r -> r.lastSwitch() != null && !r.lastSwitch().isOpen()).toList();
if (!withClosedSwitch.isEmpty()) {
return withClosedSwitch.stream().min(Comparator.comparingInt(BusbarSectionResult::depth)
.thenComparing(BusbarSectionResult::busbarSectionId)).orElse(null);
}
List<BusbarSectionResult> withOpenSwitch = results.stream().filter(r -> r.lastSwitch() != null && r.lastSwitch().isOpen()).toList();
if (!withOpenSwitch.isEmpty()) {
return withOpenSwitch.stream().min(Comparator.comparingInt(BusbarSectionResult::depth)
.thenComparing(BusbarSectionResult::busbarSectionId)).orElse(null);
}
return results.getFirst();
}

public String getFirstTraversedBbsId() {
return firstTraversedBbsId;
private static List<BusbarSectionResult> searchAllBusbars(VoltageLevel voltageLevel, int startNode) {
List<BusbarSectionResult> results = new ArrayList<>();
record NodeState(int depth, boolean allClosed) { }
Map<Integer, NodeState> visitedNodes = new HashMap<>();
visitedNodes.put(startNode, new NodeState(0, true));
voltageLevel.getNodeBreakerView().getTerminal(startNode).traverse(new Terminal.TopologyTraverser() {
SwitchInfo lastSwitch = null;
@Override
public TraverseResult traverse(Terminal terminal, boolean connected) {
if (terminal.getVoltageLevel() != voltageLevel) {
return TraverseResult.TERMINATE_PATH;
}
NodeState currentNodeState = visitedNodes.get(terminal.getNodeBreakerView().getNode());
if (terminal.getConnectable() instanceof BusbarSection busbarSection) {
if (currentNodeState != null) {
results.add(new BusbarSectionResult(busbarSection.getId(), currentNodeState.depth, lastSwitch, currentNodeState.allClosed));
}
return TraverseResult.TERMINATE_PATH;
}
return TraverseResult.CONTINUE;
}

@Override
public TraverseResult traverse(Switch aSwitch) {
int node1 = voltageLevel.getNodeBreakerView().getNode1(aSwitch.getId());
int node2 = voltageLevel.getNodeBreakerView().getNode2(aSwitch.getId());
int sourceNode = visitedNodes.containsKey(node1) ? node1 : node2;
int targetNode = visitedNodes.containsKey(node1) ? node2 : node1;
NodeState sourceState = visitedNodes.get(sourceNode);
NodeState newState = new NodeState(sourceState.depth + 1, sourceState.allClosed && !aSwitch.isOpen());
visitedNodes.put(targetNode, newState);
lastSwitch = new SwitchInfo(aSwitch.getId(), aSwitch.isOpen());
return TraverseResult.CONTINUE;
}
}, TraversalType.BREADTH_FIRST);
return results;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.ConnectablePosition;
import com.powsybl.math.graph.TraversalType;
import org.gridsuite.network.map.dto.common.ReactiveCapabilityCurveMapData;
import org.gridsuite.network.map.dto.common.TapChangerData;
import org.gridsuite.network.map.dto.common.TapChangerStepData;
Expand Down Expand Up @@ -92,9 +91,8 @@ public static String getBusOrBusbarSection(Terminal terminal) {
return terminal.getBusBreakerView().getConnectableBus().getId();
}
} else {
final BusbarSectionFinderTraverser connectedBusbarSectionFinder = new BusbarSectionFinderTraverser(terminal.isConnected());
terminal.traverse(connectedBusbarSectionFinder, TraversalType.BREADTH_FIRST);
return connectedBusbarSectionFinder.getFirstTraversedBbsId();
// NODE_BREAKER: explore all paths and choose the busbar with the closed disconnector
return BusbarSectionFinderTraverser.findBusbarSectionId(terminal);
}
}

Expand Down
Loading