Skip to content

Commit

Permalink
Consider dangling lines (#454)
Browse files Browse the repository at this point in the history
* consider dangling lines
* dangling line info at network side
* update test resources
* boundary nodes as semicircles

Signed-off-by: Luma <zamarrenolm@aia.es>
  • Loading branch information
zamarrenolm authored Dec 20, 2022
1 parent d2c1fd2 commit bf51785
Show file tree
Hide file tree
Showing 49 changed files with 820 additions and 329 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,4 @@ public interface IdProvider {
String createId(Identifiable<?> identifiable);

String createId(ThreeWindingsTransformer.Leg leg);

}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ private void addGraphEdges(VoltageLevel vl, Graph graph) {
vl.getLineStream().forEach(l -> visitLine(vl, l, graph));
vl.getTwoWindingsTransformerStream().forEach(twt -> visitTwoWindingsTransformer(vl, twt, graph));
vl.getThreeWindingsTransformerStream().forEach(thwt -> visitThreeWindingsTransformer(vl, thwt, graph));
vl.getDanglingLineStream().forEach(dl -> visitDanglingLine(dl, graph));
vl.getConnectableStream(HvdcConverterStation.class).forEach(hvdc -> visitHvdcConverterStation(hvdc, graph));
}

Expand Down Expand Up @@ -104,6 +105,14 @@ private void visitThreeWindingsTransformer(VoltageLevel vl, ThreeWindingsTransfo
}
}

private void visitDanglingLine(DanglingLine dl, Graph graph) {
BoundaryNode boundaryNode = new BoundaryNode(idProvider.createId(dl), dl.getId(), dl.getNameOrId());
BusNode boundaryBusNode = new BoundaryBusNode(idProvider.createId(dl), dl.getId());
boundaryNode.addBusNode(boundaryBusNode);
graph.addNode(boundaryNode);
addEdge(graph, dl, boundaryNode, boundaryBusNode);
}

private void visitHvdcConverterStation(HvdcConverterStation<?> converterStation, Graph graph) {
// check if the hvdc line was not already added (at the other side of the line)
HvdcLine hvdcLine = converterStation.getHvdcLine();
Expand Down Expand Up @@ -157,6 +166,15 @@ private void addThreeWtEdge(Graph graph, ThreeWindingsTransformer twt, ThreeWtNo
graph.addEdge(vlNode, getBusNode(graph, terminal), tn, edge);
}

private void addEdge(Graph graph, DanglingLine dl, BoundaryNode boundaryVlNode, BusNode boundaryBusNode) {
Terminal terminal = dl.getTerminal();
VoltageLevelNode vlNode = graph.getVoltageLevelNode(terminal.getVoltageLevel().getId())
.orElseThrow(() -> new PowsyblException("Cannot add edge, corresponding voltage level is unknown: '" + terminal.getVoltageLevel().getId() + "'"));
BranchEdge edge = new BranchEdge(idProvider.createId(dl),
dl.getId(), dl.getNameOrId(), BranchEdge.DANGLING_LINE_EDGE);
graph.addEdge(vlNode, getBusNode(graph, terminal), boundaryVlNode, boundaryBusNode, edge);
}

private BusNode getBusNode(Graph graph, Terminal terminal) {
Bus connectableBusA = terminal.getBusView().getConnectableBus();
if (connectableBusA == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Copyright (c) 2022, 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.nad.model;

/**
* @author Luma Zamarreño <zamarrenolm at aia.es>
*/
public class BoundaryBusNode extends BusNode {

public BoundaryBusNode(String diagramId, String equipmentId) {
super(diagramId, equipmentId);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Copyright (c) 2022, 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.nad.model;

/**
* @author Luma Zamarreño <zamarrenolm at aia.es>
*/
public class BoundaryNode extends VoltageLevelNode {

public BoundaryNode(String diagramId, String equipmentId, String nameOrId) {
super(diagramId, equipmentId, nameOrId, false);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public int getNum() {
public static final String PST_EDGE = "PstEdge";
public static final String LINE_EDGE = "LineEdge";
public static final String HVDC_LINE_EDGE = "HvdcLineEdge";
public static final String DANGLING_LINE_EDGE = "DanglingLineEdge";

private List<Point> points1 = Collections.emptyList();
private List<Point> points2 = Collections.emptyList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ protected List<URL> getCssUrls() {

@Override
public List<String> getNodeStyleClasses(Node node) {
return Collections.emptyList();
return node instanceof BoundaryNode ? Collections.singletonList(BOUNDARY_NODE_CLASS) : Collections.emptyList();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,18 @@ public interface StyleProvider {
String VOLTAGE_LEVEL_NODES_CLASS = CLASSES_PREFIX + "vl-nodes";
String TEXT_NODES_CLASS = CLASSES_PREFIX + "text-nodes";
String THREE_WT_NODES_CLASS = CLASSES_PREFIX + "3wt-nodes";
String BOUNDARY_NODE_CLASS = CLASSES_PREFIX + "boundary-node";
String DISCONNECTED_CLASS = CLASSES_PREFIX + "disconnected";
String BRANCH_EDGES_CLASS = CLASSES_PREFIX + "branch-edges";
String HVDC_EDGE_CLASS = CLASSES_PREFIX + "hvdc-edge";
String THREE_WT_EDGES_CLASS = CLASSES_PREFIX + "3wt-edges";
String DANGLING_LINE_EDGE_CLASS = CLASSES_PREFIX + "dangling-line-edge";
String TEXT_EDGES_CLASS = CLASSES_PREFIX + "text-edges";
String EDGE_INFOS_CLASS = CLASSES_PREFIX + "edge-infos";
String ARROW_IN_CLASS = CLASSES_PREFIX + "arrow-in";
String ARROW_OUT_CLASS = CLASSES_PREFIX + "arrow-out";
String HVDC_CLASS = CLASSES_PREFIX + "hvdc";
String UNKNOWN_BUSNODE_CLASS = CLASSES_PREFIX + "unknown-busnode";
String TEXT_BACKGROUND_CLASS = CLASSES_PREFIX + "text-background";
String LINE_OVERLOADED_CLASS = CLASSES_PREFIX + "overload";
String VL_OVERVOLTAGE_CLASS = CLASSES_PREFIX + "overvoltage";
String VL_UNDERVOLTAGE_CLASS = CLASSES_PREFIX + "undervoltage";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ private void drawBranchEdges(Graph graph, XMLStreamWriter writer) throws XMLStre
}

private void drawEdgeCenter(XMLStreamWriter writer, BranchEdge edge) throws XMLStreamException {
if (BranchEdge.LINE_EDGE.equals(edge.getType())) {
if (BranchEdge.LINE_EDGE.equals(edge.getType()) || BranchEdge.DANGLING_LINE_EDGE.equals(edge.getType())) {
return;
}
writer.writeStartElement(GROUP_ELEMENT_NAME);
Expand Down Expand Up @@ -602,22 +602,35 @@ private void drawNode(Graph graph, XMLStreamWriter writer, VoltageLevelNode vlNo
double busInnerRadius = getBusAnnulusInnerRadius(busNode, vlNode, svgParameters);
double busOuterRadius = getBusAnnulusOuterRadius(busNode, vlNode, svgParameters);
if (busInnerRadius == 0) {
writer.writeEmptyElement(CIRCLE_ELEMENT_NAME);
writer.writeAttribute(CIRCLE_RADIUS_ATTRIBUTE, getFormattedValue(busOuterRadius));
if (busNode instanceof BoundaryBusNode) {
// Boundary nodes are always at side two of a dangling line edge, dangling line is its only edge
double edgeStartAngle = getEdgeStartAngle(graph.getBusEdges(busNode).iterator().next(), BranchEdge.Side.TWO);
drawBoundarySemicircle(writer, busOuterRadius, edgeStartAngle);
} else {
writer.writeEmptyElement(CIRCLE_ELEMENT_NAME);
writer.writeAttribute(CIRCLE_RADIUS_ATTRIBUTE, getFormattedValue(busOuterRadius));
}
} else {
writer.writeEmptyElement(PATH_ELEMENT_NAME);
writer.writeAttribute(PATH_D_ATTRIBUTE, getFragmentedAnnulusPath(busInnerRadius, busOuterRadius, traversingBusEdges, graph, vlNode, busNode));
}
writer.writeAttribute(ID_ATTRIBUTE, getPrefixedId(busNode.getDiagramId()));

List<String> nodeStyleClasses = styleProvider.getNodeStyleClasses(busNode);
List<String> nodeStyleClasses = new ArrayList<>(styleProvider.getNodeStyleClasses(busNode));
nodeStyleClasses.add(StyleProvider.BUSNODE_CLASS);
addStylesIfAny(writer, nodeStyleClasses);

traversingBusEdges.addAll(graph.getBusEdges(busNode));
}
}

private void drawBoundarySemicircle(XMLStreamWriter writer, double radius, double edgeStartAngle) throws XMLStreamException {
writer.writeEmptyElement(PATH_ELEMENT_NAME);
double startAngle = -Math.PI / 2 + edgeStartAngle;
String semiCircle = "M" + getCirclePath(radius, startAngle, startAngle + Math.PI, true);
writer.writeAttribute(PATH_D_ATTRIBUTE, semiCircle);
}

private String getFragmentedAnnulusPath(double innerRadius, double outerRadius, List<Edge> traversingBusEdges, Graph graph, VoltageLevelNode vlNode, BusNode busNode) {
if (traversingBusEdges.isEmpty()) {
String path = "M" + getCirclePath(outerRadius, 0, Math.PI, true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@
import com.powsybl.nad.svg.StyleProvider;
import com.powsybl.nad.utils.iidm.IidmUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.*;

/**
* @author Florian Dupuy <florian.dupuy at rte-france.com>
Expand All @@ -40,7 +37,7 @@ protected AbstractVoltageStyleProvider(Network network, BaseVoltagesConfig baseV
@Override
public List<String> getNodeStyleClasses(BusNode busNode) {
if (busNode == BusNode.UNKNOWN) {
return Collections.singletonList(UNKNOWN_BUSNODE_CLASS);
return List.of(UNKNOWN_BUSNODE_CLASS);
}
List<String> styles = new ArrayList<>();
Bus b = network.getBusView().getBus(busNode.getEquipmentId());
Expand All @@ -57,7 +54,7 @@ public List<String> getNodeStyleClasses(BusNode busNode) {
@Override
public List<String> getEdgeStyleClasses(Edge edge) {
List<String> styleClasses = new ArrayList<>(super.getEdgeStyleClasses(edge));
if (edge instanceof BranchEdge && !((BranchEdge) edge).getType().equals(BranchEdge.HVDC_LINE_EDGE)) {
if (IidmUtils.isIidmBranch(edge)) {
Branch<?> branch = network.getBranch(edge.getEquipmentId());
if (branch.isOverloaded()) {
styleClasses.add(StyleProvider.LINE_OVERLOADED_CLASS);
Expand Down Expand Up @@ -89,8 +86,7 @@ protected boolean isDisconnected(Edge edge) {

@Override
protected boolean isDisconnected(BranchEdge edge, BranchEdge.Side side) {
Terminal terminal = IidmUtils.getTerminalFromEdge(network, edge, side);
return terminal == null || !terminal.isConnected();
return IidmUtils.isDisconnected(network, edge, side);
}

@Override
Expand All @@ -106,6 +102,8 @@ protected Optional<String> getBaseVoltageStyle(Edge edge) {
String branchType = ((BranchEdge) edge).getType();
if (branchType.equals(BranchEdge.HVDC_LINE_EDGE)) {
return Optional.of(HVDC_EDGE_CLASS);
} else if (branchType.equals(BranchEdge.DANGLING_LINE_EDGE)) {
return Optional.of(DANGLING_LINE_EDGE_CLASS);
}
} else if (edge instanceof ThreeWtEdge) {
Terminal terminal = network.getThreeWindingsTransformer(edge.getEquipmentId())
Expand All @@ -118,6 +116,10 @@ protected Optional<String> getBaseVoltageStyle(Edge edge) {

@Override
protected Optional<String> getBaseVoltageStyle(BranchEdge edge, BranchEdge.Side side) {
String branchType = edge.getType();
if (branchType.equals(BranchEdge.DANGLING_LINE_EDGE)) {
return getBaseVoltageStyle(network.getDanglingLine(edge.getEquipmentId()).getBoundary().getVoltageLevel().getNominalV());
}
Terminal terminal = IidmUtils.getTerminalFromEdge(network, edge, side);
return getBaseVoltageStyle(terminal);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.powsybl.commons.config.BaseVoltagesConfig;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.Terminal;
import com.powsybl.nad.model.BoundaryNode;
import com.powsybl.nad.model.Node;
import com.powsybl.nad.model.VoltageLevelNode;

Expand Down Expand Up @@ -38,7 +39,11 @@ public List<String> getCssFilenames() {
@Override
public List<String> getNodeStyleClasses(Node node) {
List<String> styles = new ArrayList<>();
if (node instanceof VoltageLevelNode) {
if (node instanceof BoundaryNode) {
styles.add(BOUNDARY_NODE_CLASS);
double nominalV = network.getDanglingLine(node.getEquipmentId()).getBoundary().getVoltageLevel().getNominalV();
getBaseVoltageStyle(nominalV).ifPresent(styles::add);
} else if (node instanceof VoltageLevelNode) {
double nominalV = network.getVoltageLevel(node.getEquipmentId()).getNominalV();
getBaseVoltageStyle(nominalV).ifPresent(styles::add);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
import com.powsybl.iidm.network.Bus;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.Terminal;
import com.powsybl.nad.model.BusNode;
import com.powsybl.nad.model.Node;
import com.powsybl.nad.model.*;

import java.util.ArrayList;
import java.util.Collections;
Expand All @@ -38,23 +37,36 @@ public List<String> getCssFilenames() {
return Collections.singletonList("topologicalStyle.css");
}

@Override
public List<String> getNodeStyleClasses(Node node) {
return Collections.emptyList();
}

@Override
public List<String> getNodeStyleClasses(BusNode busNode) {
List<String> styles = new ArrayList<>(super.getNodeStyleClasses(busNode));
Bus b = network.getBusView().getBus(busNode.getEquipmentId());
if (b != null) {
getBaseVoltageStyle(b.getVoltageLevel().getNominalV())
if (busNode instanceof BoundaryBusNode) {
String dlId = busNode.getEquipmentId();
getBaseVoltageStyle(network.getDanglingLine(dlId).getBoundary().getVoltageLevel().getNominalV())
.map(baseVoltageStyle -> baseVoltageStyle + "-" + busNode.getIndex())
.ifPresent(styles::add);
} else {
Bus b = network.getBusView().getBus(busNode.getEquipmentId());
if (b != null) {
getBaseVoltageStyle(b.getVoltageLevel().getNominalV())
.map(baseVoltageStyle -> baseVoltageStyle + "-" + busNode.getIndex())
.ifPresent(styles::add);
}
}
return styles;
}

@Override
protected Optional<String> getBaseVoltageStyle(BranchEdge edge, BranchEdge.Side side) {
String branchType = edge.getType();
if (branchType.equals(BranchEdge.DANGLING_LINE_EDGE)) {
return getBaseVoltageStyle(network.getDanglingLine(edge.getEquipmentId()).getBoundary().getVoltageLevel().getNominalV())
.map(baseVoltageStyle -> baseVoltageStyle + LINE_STYLE_SUFFIX);
} else {
return super.getBaseVoltageStyle(edge, side);
}
}

@Override
protected Optional<String> getBaseVoltageStyle(Terminal terminal) {
if (terminal == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.powsybl.iidm.network.*;
import com.powsybl.nad.model.BranchEdge;
import com.powsybl.nad.model.Edge;
import com.powsybl.nad.model.ThreeWtEdge;

import java.util.Objects;
Expand All @@ -11,13 +12,26 @@ public final class IidmUtils {
private IidmUtils() {
}

public static boolean isDisconnected(Network network, BranchEdge edge, BranchEdge.Side side) {
if (edge.getType().equals(BranchEdge.DANGLING_LINE_EDGE) && side.equals(BranchEdge.Side.TWO)) {
return false;
}
Terminal terminal = IidmUtils.getTerminalFromEdge(network, edge, side);
return terminal == null || !terminal.isConnected();
}

public static Terminal getTerminalFromEdge(Network network, BranchEdge edge, BranchEdge.Side side) {
if (!edge.getType().equals(BranchEdge.HVDC_LINE_EDGE)) {
Branch<?> branch = network.getBranch(edge.getEquipmentId());
return branch.getTerminal(IidmUtils.getIidmSideFromBranchEdgeSide(side));
} else {
if (edge.getType().equals(BranchEdge.HVDC_LINE_EDGE)) {
HvdcLine line = network.getHvdcLine(edge.getEquipmentId());
return line.getConverterStation(IidmUtils.getIidmHvdcSideFromBranchEdgeSide(side)).getTerminal();
} else if (edge.getType().equals(BranchEdge.DANGLING_LINE_EDGE)) {
if (side.equals(BranchEdge.Side.ONE)) {
return network.getDanglingLine(edge.getEquipmentId()).getTerminal();
}
return null;
} else {
Branch<?> branch = network.getBranch(edge.getEquipmentId());
return branch.getTerminal(IidmUtils.getIidmSideFromBranchEdgeSide(side));
}
}

Expand Down Expand Up @@ -67,4 +81,12 @@ public static ThreeWtEdge.Side getThreeWtEdgeSideFromIidmSide(ThreeWindingsTrans
return null;
}

public static boolean isIidmBranch(Edge edge) {
if (edge instanceof BranchEdge) {
String edgeType = ((BranchEdge) edge).getType();
return !edgeType.equals(BranchEdge.HVDC_LINE_EDGE) &&
!edgeType.equals(BranchEdge.DANGLING_LINE_EDGE);
}
return false;
}
}
1 change: 1 addition & 0 deletions network-area-diagram/src/main/resources/nominalStyle.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
.nad-vl-nodes .nad-busnode {fill: var(--nad-vl-color, lightblue)}
.nad-vl-nodes circle.nad-unknown-busnode {stroke: lightgrey; stroke-width: 5; stroke-dasharray: 5,5; fill: none}
.nad-hvdc-edge polyline.nad-hvdc {stroke: grey; stroke-width: 20}
.nad-dangling-line-edge {fill: var(--nad-vl-color, lighgrey)}
.nad-pst-arrow {stroke: #6a6a6a; stroke-width: 4; stroke-linecap: round; fill: none}
.nad-state-out .nad-arrow-in {visibility: hidden}
.nad-state-in .nad-arrow-out {visibility: hidden}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
.nad-vl-nodes .nad-busnode {fill: var(--nad-vl-color, lightgrey)}
.nad-vl-nodes circle.nad-unknown-busnode {stroke: var(--nad-vl-color, #808080); stroke-width: 5; stroke-dasharray: 5,5; fill: none}
.nad-hvdc-edge polyline.nad-hvdc {stroke: grey; stroke-width: 20}
.nad-dangling-line-edge {stroke: var(--nad-vl-color, lightgrey); stroke-width: 1; fill: none}
.nad-pst-arrow {stroke: #6a6a6a; stroke-width: 4; stroke-linecap: round; fill: none}
.nad-state-out .nad-arrow-in {visibility: hidden}
.nad-state-in .nad-arrow-out {visibility: hidden}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public void testCurrentLimits() {
Network network = NetworkTestFactory.createTwoVoltageLevels();

Map<String, Point> expected = Map.of(
"dl1", new Point(0, 0),
"vl1", new Point(1, 0),
"vl2", new Point(2, 1));
Graph graph = new NetworkGraphBuilder(network, VoltageLevelFilter.NO_FILTER).buildGraph();
Expand Down
1 change: 1 addition & 0 deletions network-area-diagram/src/test/resources/3wt.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit bf51785

Please sign in to comment.