Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display ground disconnector in single line diagrams #564

Merged
merged 29 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d4acef1
Add ground disconnector component
So-Fras Oct 24, 2023
441aee5
Add new ground disconnector switch type
So-Fras Oct 24, 2023
195f08d
Add test (test reference to be modified)
So-Fras Oct 24, 2023
50bc8e3
Merge branch 'main' into ground_disconnector
So-Fras Jan 15, 2024
1db74e5
Merge branch 'main' into ground_disconnector
So-Fras Jan 22, 2024
3ede434
Add tests for all different configurations (tests are not passing)
So-Fras Jan 22, 2024
a974dcc
Remove ground disconnector kind mentions
So-Fras Jan 24, 2024
18c4f6c
Merge branch 'main' into ground_disconnector
So-Fras Jan 25, 2024
b518cab
Fix svg name
So-Fras Jan 25, 2024
d190d85
Remove switch in Bus/Breaker test networks for ground
So-Fras Jan 26, 2024
0e7bb43
Fix NPE errors due to the misuse of existing network variable
So-Fras Jan 26, 2024
beff695
Add visitGround() method to AbstractGraphBuilder class
So-Fras Jan 26, 2024
04b3551
Create ground FeederNode
So-Fras Jan 26, 2024
6372470
Add GroundDisconnection component and detect it at graph refinement
flo-dup Jan 29, 2024
ee98171
Add disconnector state in GroundDisconnectionNode
flo-dup Jan 29, 2024
5a4d1db
Add ground disconnector component
flo-dup Jan 29, 2024
87b1588
Add css for the ground disconnection
flo-dup Jan 29, 2024
f958319
Keep json order for subcomponents instead of names alphabetical order
flo-dup Jan 29, 2024
1f4f5fa
Fix ground component
flo-dup Jan 30, 2024
915f99d
Update ground unit test references
flo-dup Jan 30, 2024
faff897
Merge branch 'main' into ground_disconnector
So-Fras Jan 30, 2024
d8c17b0
Update other test references
So-Fras Jan 30, 2024
09a474a
Merge branch 'main' into ground_disconnector
So-Fras Jan 30, 2024
0c1311a
Merge branch 'main' into ground_disconnector
So-Fras Jan 30, 2024
aa832fb
Add ground disconnector component in FlatDesignLibrary
So-Fras Jan 31, 2024
ab3729f
Update test references
So-Fras Jan 31, 2024
7e3c3b2
Fix typo in comments
So-Fras Jan 31, 2024
b5d2484
Modifications following review
So-Fras Feb 1, 2024
c672900
Merge branch 'main' into ground_disconnector
So-Fras Feb 1, 2024
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
77 changes: 77 additions & 0 deletions diagram-test/src/main/java/com/powsybl/diagram/test/Networks.java
Original file line number Diff line number Diff line change
Expand Up @@ -2152,6 +2152,65 @@ public static Network createNetworkWithManySubstations() {
return network;
}

public static Network createNetworkGroundDisconnectorOnLineNodeBreaker() {
Network network = Network.create("testCaseGroundDisconnectorOnLineNB", "test");
Substation substation = Networks.createSubstation(network, "s", "s", Country.FR);
VoltageLevel vl = Networks.createVoltageLevel(substation, "vl", "vl", TopologyKind.NODE_BREAKER, 380);
Substation substation2 = Networks.createSubstation(network, "s2", "s2", Country.FR);
VoltageLevel vl2 = Networks.createVoltageLevel(substation2, "vl2", "vl2", TopologyKind.NODE_BREAKER, 380);
Networks.createBusBarSection(vl, "bbs", "bbs", 0, 1, 1);
Networks.createLine(network, "line", "line", 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 2, 4, vl.getId(), vl2.getId(), "fn1", 1, ConnectablePosition.Direction.TOP, "fn2", 0, ConnectablePosition.Direction.TOP);
Networks.createSwitch(vl, "d1", "d1", SwitchKind.DISCONNECTOR, false, false, false, 0, 1);
Networks.createSwitch(vl, "b1", "b1", SwitchKind.BREAKER, false, false, false, 1, 2);
Networks.createSwitch(vl, "gd", "gd", SwitchKind.DISCONNECTOR, false, true, false, 2, 3);
Networks.createGround(vl, "ground", 3);
return network;
}

public static Network createNetworkGroundDisconnectorOnBusBarNodeBreaker() {
Network network = Network.create("testCaseGroundDisconnectorOnBusBarNB", "test");
Substation substation = Networks.createSubstation(network, "s", "s", Country.FR);
VoltageLevel vl = Networks.createVoltageLevel(substation, "vl", "vl", TopologyKind.NODE_BREAKER, 380);
Networks.createBusBarSection(vl, "bbs", "bbs", 0, 1, 1);
Networks.createSwitch(vl, "gd", "gd", SwitchKind.DISCONNECTOR, false, true, false, 0, 1);
Networks.createGround(vl, "ground", 1);
return network;
}

public static Network createNetworkGroundDisconnectorOnLineBusBreaker() {
Network network = Network.create("testCaseGroundDisconnectorOnLineBB", "test");
Substation substation = Networks.createSubstation(network, "s1", "s1", Country.FR);
VoltageLevel vl = Networks.createVoltageLevel(substation, "vl", "vl", TopologyKind.BUS_BREAKER, 380);
olperr1 marked this conversation as resolved.
Show resolved Hide resolved
Substation substation2 = Networks.createSubstation(network, "s2", "s2", Country.FR);
Networks.createVoltageLevel(substation2, "vl2", "vl2", TopologyKind.BUS_BREAKER, 380);
Bus b1 = vl.getBusBreakerView().newBus()
.setId("b1")
.add();
Bus b2 = network.getVoltageLevel("vl2").getBusBreakerView().newBus()
.setId("b2")
.add();
Bus b1g = vl.getBusBreakerView().newBus()
.setId("b1g")
.add();
Networks.createLine(b1, b2);
Networks.createGround(b1g);
return network;
}

public static Network createNetworkGroundDisconnectorOnBusBarBusBreaker() {
Network network = Network.create("testCaseGroundDisconnectorOnBusBarBB", "test");
Substation substation = Networks.createSubstation(network, "s", "s", Country.FR);
VoltageLevel vl = Networks.createVoltageLevel(substation, "vl", "vl", TopologyKind.BUS_BREAKER, 380);
olperr1 marked this conversation as resolved.
Show resolved Hide resolved
vl.getBusBreakerView().newBus()
.setId("b1")
.add();
Bus b1g = vl.getBusBreakerView().newBus()
.setId("b1g")
.add();
Networks.createGround(b1g);
return network;
}

public static void createLine(Bus bus1, Bus bus2) {
String id = String.format("%s - %s",
bus1.getVoltageLevel().getSubstation().orElseThrow().getId(),
Expand Down Expand Up @@ -2212,4 +2271,22 @@ public static void createTransformer(Bus bus1, Bus bus2) {
.setBus2(bus2.getId())
.add();
}

public static void createGround(VoltageLevel vl, String id, int node) {
vl.newGround()
.setId(id)
.setNode(node)
.setEnsureIdUnicity(true)
.add();
}

public static void createGround(Bus bus) {
VoltageLevel voltageLevel = bus.getVoltageLevel();
String id = String.format("%s %s", voltageLevel.getId(), bus.getId());
voltageLevel.newGround()
.setId(id)
.setBus(bus.getId())
.setEnsureIdUnicity(true)
.add();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,11 @@ public void visitThreeWindingsTransformer(ThreeWindingsTransformer transformer,
ThreeSides side) {
addFeeder3wtNode(graph, transformer, side);
}

@Override
public void visitGround(Ground ground) {
addTerminalNode(NodeFactory.createGround(graph, ground.getId(), ground.getNameOrId()), ground.getTerminal());
}
}

public static class NodeBreakerGraphBuilder extends AbstractGraphBuilder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ void run(VoltageLevelGraph graph, LayoutParameters layoutParameters) {
graph.insertBusConnections(nodesOnBus);
graph.insertHookNodesAtBuses();
graph.insertHookNodesAtFeeders();

graph.substituteNodesMirroringGroundDisconnectionComponent();
}

private Predicate<Node> getNodesOnBusPredicate(VoltageLevelGraph graph, List<String> componentsOnBusbars) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
* @author Benoit Jeanson {@literal <benoit.jeanson at rte-france.com>}
Expand All @@ -31,22 +30,16 @@ private GraphTraversal() {
* @return true if no unsuccessfulCriteria reached or node outside
**/

static boolean run(Node node,
Predicate<Node> extremityCriteria,
Predicate<Node> unsuccessfulCriteria,
Set<Node> nodesResult,
Set<Node> outsideNodes) {
public static boolean run(Node node, Predicate<Node> extremityCriteria, Predicate<Node> unsuccessfulCriteria,
Set<Node> nodesResult, Set<Node> outsideNodes) {

if (outsideNodes.contains(node)) {
return false;
}
nodesResult.add(node);
List<Node> nodesToVisit = node.getAdjacentNodes().stream()
.filter(n -> !outsideNodes.contains(n) && !nodesResult.contains(n))
.collect(Collectors.toList());
if (nodesToVisit.isEmpty()) {
return true;
}
.toList();
for (Node n : nodesToVisit) {
if (unsuccessfulCriteria.test(n)) {
return false;
Expand All @@ -59,12 +52,9 @@ static boolean run(Node node,
return true;
}

static Set<Node> run(Node node,
Predicate<Node> extremityCriteria,
Set<Node> outsideNodes) {
static Set<Node> run(Node node, Predicate<Node> extremityCriteria, Set<Node> outsideNodes) {
Set<Node> nodesResult = new LinkedHashSet<>();
run(node, extremityCriteria, n -> false, nodesResult, outsideNodes);
return nodesResult;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public final class ComponentTypeName {
public static final String BUSBAR_SECTION = "BUSBAR_SECTION";
public static final String BREAKER = "BREAKER";
public static final String DISCONNECTOR = "DISCONNECTOR";
public static final String GROUND = "GROUND";
public static final String GROUND_DISCONNECTION = "GROUND_DISCONNECTION";
public static final String BATTERY = "BATTERY";
public static final String BUS_CONNECTION = "BUS_CONNECTION";
public static final String GENERATOR = "GENERATOR";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ private void loadLibrary(String directory) {
LOGGER.debug("Reading subComponent {}", resourceName);
try {
Document doc = db.parse(getClass().getResourceAsStream(resourceName));
svgDocuments.computeIfAbsent(componentType, k -> new TreeMap<>()).put(s.getName(), getElements(doc));
svgDocuments.computeIfAbsent(componentType, k -> new LinkedHashMap<>()).put(s.getName(), getElements(doc));
} catch (SAXException e) {
throw new UncheckedSaxException(e);
} catch (IOException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ public static FeederNode createDanglingLine(VoltageLevelGraph graph, String id,
return createFeederInjectionNode(graph, id, name, ComponentTypeName.DANGLING_LINE);
}

public static FeederNode createGround(VoltageLevelGraph graph, String id, String name) {
return createFeederNode(graph, id, name, id, ComponentTypeName.GROUND, false, new BaseFeeder(FeederType.GROUND), null);
}

public static Node createGroundDisconnectionNode(VoltageLevelGraph graph, SwitchNode disconnector, FeederNode ground) {
String name = "Ground disconnection (ground " + ground.getId() + ", disconnector " + disconnector.getId() + ")";
GroundDisconnectionNode gdNode = new GroundDisconnectionNode(disconnector.getEquipmentId(), name, disconnector.isOpen(), ComponentTypeName.GROUND_DISCONNECTION);
graph.addNode(gdNode);
return gdNode;
}

public static FeederNode createVscConverterStation(VoltageLevelGraph graph, String id, String name, String equipmentId, NodeSide side, VoltageLevelInfos otherSideVoltageLevelInfos) {
FeederWithSides feeder = new FeederWithSides(FeederType.HVDC, side, graph.getVoltageLevelInfos(), otherSideVoltageLevelInfos);
return createFeederNode(graph, id, name, equipmentId, ComponentTypeName.VSC_CONVERTER_STATION, feeder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import com.fasterxml.jackson.core.JsonGenerator;
import com.powsybl.commons.PowsyblException;
import com.powsybl.sld.layout.GraphTraversal;
import com.powsybl.sld.library.ComponentTypeName;
import com.powsybl.sld.model.cells.*;
import com.powsybl.sld.model.coordinate.Direction;
Expand All @@ -21,6 +22,7 @@

import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand Down Expand Up @@ -485,10 +487,13 @@ public List<BusNode> getNodeBuses() {
}

public List<FeederNode> getFeederNodes() {
return nodesByType.computeIfAbsent(Node.NodeType.FEEDER, nodeType -> new ArrayList<>())
return getFeederNodeStream().collect(Collectors.toList());
}

private Stream<FeederNode> getFeederNodeStream() {
return nodesByType.computeIfAbsent(NodeType.FEEDER, nodeType -> new ArrayList<>())
.stream()
.map(FeederNode.class::cast)
.collect(Collectors.toList());
.map(FeederNode.class::cast);
}

public List<Node> getNodes() {
Expand Down Expand Up @@ -654,4 +659,34 @@ public double getLastBusY(double verticalSpaceBus) {
public double getInnerHeight(double verticalSpaceBus) {
return getExternCellHeight(Direction.TOP) + verticalSpaceBus * getMaxV() + getExternCellHeight(Direction.BOTTOM);
}

public void substituteNodesMirroringGroundDisconnectionComponent() {
List<GroundDisconnection> groundDisconnections = getFeederNodeStream().filter(feederNode -> feederNode.getFeeder().getFeederType() == FeederType.GROUND)
.map(this::getGroundDisconnection)
.filter(Objects::nonNull)
.toList();
for (GroundDisconnection gd : groundDisconnections) {
gd.nodes().forEach(this::removeNode);
substituteNode(gd.forkNode(), NodeFactory.createGroundDisconnectionNode(this, gd.disconnector(), gd.ground()));
}
}

private GroundDisconnection getGroundDisconnection(FeederNode groundFeederNode) {
Set<Node> setFromGround = new LinkedHashSet<>();
AtomicReference<SwitchNode> aSwitch = new AtomicReference<>();
boolean groundDisconnectionSetIdentified = GraphTraversal.run(groundFeederNode,
node -> node.getAdjacentEdges().size() > 2, // traversal ends successfully when encountering a fork node, which will be replaced by the ground disconnection component
node -> node.getType() == NodeType.BUS || node.getType() == NodeType.FEEDER // traversal fails and stops when encountering a bus, a feeder, or more than one switch
|| node.getType() == NodeType.SWITCH && aSwitch.getAndSet((SwitchNode) node) != null,
setFromGround,
Collections.emptySet());
if (groundDisconnectionSetIdentified && aSwitch.get() != null && aSwitch.get().getKind() == SwitchNode.SwitchKind.DISCONNECTOR) {
List<Node> list = setFromGround.stream().toList(); // the list contains the fork node which should not be removed but substituted
return new GroundDisconnection(list.subList(0, list.size() - 1), groundFeederNode, aSwitch.get(), list.get(list.size() - 1));
}
return null;
}

private record GroundDisconnection(List<Node> nodes, FeederNode ground, SwitchNode disconnector, Node forkNode) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ public enum FeederType {
TWO_WINDINGS_TRANSFORMER_LEG,
THREE_WINDINGS_TRANSFORMER_LEG,
HVDC,
GROUND,
FICTITIOUS
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Copyright (c) 2024, 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.sld.model.nodes;

/**
* @author Florian Dupuy {@literal <florian.dupuy at rte-france.com>}
*/
public class GroundDisconnectionNode extends EquipmentNode {
private final boolean isDisconnectorOpen;

public GroundDisconnectionNode(String id, String name, boolean isDisconnectorOpen, String componentTypeName) {
super(NodeType.INTERNAL, id, name, id, componentTypeName, false);
this.isDisconnectorOpen = isDisconnectorOpen;
}

public boolean isDisconnectorOpen() {
return isDisconnectorOpen;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public class SwitchNode extends EquipmentNode {
public enum SwitchKind {
BREAKER,
DISCONNECTOR,
LOAD_BREAK_SWITCH;
LOAD_BREAK_SWITCH,
GROUND_DISCONNECTOR
}

private boolean open = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@
import com.powsybl.sld.model.cells.ShuntCell;
import com.powsybl.sld.model.coordinate.Direction;
import com.powsybl.sld.model.graphs.VoltageLevelGraph;
import com.powsybl.sld.model.nodes.BranchEdge;
import com.powsybl.sld.model.nodes.FeederNode;
import com.powsybl.sld.model.nodes.Node;
import com.powsybl.sld.model.nodes.SwitchNode;
import com.powsybl.sld.model.nodes.*;
import com.powsybl.sld.svg.LabelProvider;
import com.powsybl.sld.svg.DirectionalFeederInfo;
import com.powsybl.sld.svg.FeederInfo;
Expand Down Expand Up @@ -50,6 +47,9 @@ public List<String> getNodeStyles(VoltageLevelGraph graph, Node node, ComponentL
if (node.getType() == Node.NodeType.SWITCH) {
styles.add(((SwitchNode) node).isOpen() ? StyleClassConstants.OPEN_SWITCH_STYLE_CLASS : StyleClassConstants.CLOSED_SWITCH_STYLE_CLASS);
}
if (node instanceof GroundDisconnectionNode gdn) {
styles.add(gdn.isDisconnectorOpen() ? StyleClassConstants.OPEN_SWITCH_STYLE_CLASS : StyleClassConstants.CLOSED_SWITCH_STYLE_CLASS);
}
if (node.isFictitious()) {
styles.add(StyleClassConstants.FICTITIOUS_NODE_STYLE_CLASS);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
.sld-svc {stroke: var(--sld-vl-color, blue); fill: none}
.sld-vsc {stroke: var(--sld-vl-color, blue); font-size: 7.43px; fill: none}
.sld-lcc {stroke: var(--sld-vl-color, blue); font-size: 7.43px; fill: none}
.sld-ground {stroke: var(--sld-vl-color, blue); fill: none}
/* Stroke none & fill: --sld-vl-color */
.sld-node-infos {stroke: none; fill: var(--sld-vl-color, black)}
/* Stroke none & fill: black */
Expand All @@ -47,3 +48,9 @@
.sld-disconnector.sld-fictitious {stroke: maroon}
.sld-load-break-switch.sld-fictitious {stroke: maroon}
.sld-busbar-section.sld-fictitious {stroke: var(--sld-vl-color, #c80000); stroke-width: 1}
/* ground disconnector specific */
.sld-ground-disconnection-attach {stroke: var(--sld-vl-color, #c80000); fill: none}
.sld-open .sld-ground-disconnection-ground {stroke: black; fill: none}
.sld-closed .sld-ground-disconnection-ground {stroke: var(--sld-vl-color, #c80000); fill: none}
.sld-ground-disconnection .sld-sw-open {stroke: black; fill: none}
.sld-ground-disconnection .sld-sw-closed {stroke: black; fill: none}
Loading