Skip to content
This repository has been archived by the owner on Nov 18, 2022. It is now read-only.

Add voltage level filter to display part of the network #18

Merged
merged 17 commits into from
Dec 3, 2021
Merged
17 changes: 15 additions & 2 deletions src/main/java/com/powsybl/nad/NetworkAreaDiagram.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
package com.powsybl.nad;

import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.VoltageLevel;
import com.powsybl.nad.build.iidm.VoltageLevelFilter;
import com.powsybl.nad.build.iidm.IdProvider;
import com.powsybl.nad.build.iidm.IntIdProvider;
import com.powsybl.nad.build.iidm.NetworkGraphBuilder;
Expand All @@ -22,16 +24,27 @@
import java.io.Writer;
import java.nio.file.Path;
import java.util.Objects;
import java.util.function.Predicate;

/**
* @author Florian Dupuy <florian.dupuy at rte-france.com>
*/
public class NetworkAreaDiagram {

private final Network network;
private final Predicate<VoltageLevel> voltageLevelFilter;

public NetworkAreaDiagram(Network network) {
this(network, VoltageLevelFilter.NO_FILTER);
}

public NetworkAreaDiagram(Network network, String voltageLevelId, int depth) {
this(network, VoltageLevelFilter.createVoltageLevelDepthFilter(network, voltageLevelId, depth));
}

public NetworkAreaDiagram(Network network, Predicate<VoltageLevel> voltageLevelFilter) {
this.network = Objects.requireNonNull(network);
this.voltageLevelFilter = Objects.requireNonNull(voltageLevelFilter);
}

public void draw(Path svgFile) {
Expand Down Expand Up @@ -71,7 +84,7 @@ public void draw(Path svgFile, SvgParameters svgParameters, LayoutParameters lay
Objects.requireNonNull(layoutFactory);
Objects.requireNonNull(idProvider);

Graph graph = new NetworkGraphBuilder(network, idProvider).buildGraph();
Graph graph = new NetworkGraphBuilder(network, voltageLevelFilter, idProvider).buildGraph();
layoutFactory.create().run(graph, layoutParameters);
new SvgWriter(svgParameters, styleProvider, labelProvider).writeSvg(graph, svgFile);
}
Expand Down Expand Up @@ -106,7 +119,7 @@ public void draw(Writer writer, SvgParameters svgParameters, LayoutParameters la
public void draw(Writer writer, SvgParameters svgParameters, LayoutParameters layoutParameters,
StyleProvider styleProvider, LabelProvider labelProvider, LayoutFactory layoutFactory,
IdProvider idProvider) {
Graph graph = new NetworkGraphBuilder(network, idProvider).buildGraph();
Graph graph = new NetworkGraphBuilder(network, voltageLevelFilter, idProvider).buildGraph();
layoutFactory.create().run(graph, layoutParameters);
new SvgWriter(svgParameters, styleProvider, labelProvider).writeSvg(graph, writer);
}
Expand Down
135 changes: 90 additions & 45 deletions src/main/java/com/powsybl/nad/build/iidm/NetworkGraphBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,30 @@
import com.powsybl.nad.build.GraphBuilder;
import com.powsybl.nad.model.*;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;

/**
* @author Florian Dupuy <florian.dupuy at rte-france.com>
*/
public class NetworkGraphBuilder implements GraphBuilder {

private static final String LEG1_SUFFIX = "_leg1";
private static final String LEG2_SUFFIX = "_leg2";
private static final String LEG3_SUFFIX = "_leg3";

private final Network network;
private final IdProvider idProvider;
private final Predicate<VoltageLevel> voltageLevelFilter;

public NetworkGraphBuilder(Network network, IdProvider idProvider) {
public NetworkGraphBuilder(Network network, Predicate<VoltageLevel> voltageLevelFilter, IdProvider idProvider) {
this.network = Objects.requireNonNull(network);
this.voltageLevelFilter = voltageLevelFilter;
this.idProvider = Objects.requireNonNull(idProvider);
}

public NetworkGraphBuilder(Network network, Predicate<VoltageLevel> voltageLevelFilter) {
this(network, voltageLevelFilter, new IntIdProvider());
}

public NetworkGraphBuilder(Network network) {
this(network, new IntIdProvider());
this(network, VoltageLevelFilter.NO_FILTER, new IntIdProvider());
}

@Override
Expand All @@ -46,21 +47,23 @@ public Graph buildGraph() {
}

private void addGraphNodes(Graph graph) {
for (VoltageLevel voltageLevel : network.getVoltageLevels()) {
TextNode textNode = new TextNode(idProvider.createId(voltageLevel), voltageLevel.getNameOrId());
VoltageLevelNode vlNode = new VoltageLevelNode(idProvider.createId(voltageLevel),
voltageLevel.getId(), voltageLevel.getNameOrId(), voltageLevel.getNominalV(), textNode);
network.getVoltageLevelStream().filter(voltageLevelFilter).forEach(vl -> {
VoltageLevelNode vlNode = new VoltageLevelNode(idProvider.createId(vl),
vl.getId(), vl.getNameOrId(), vl.getNominalV());
TextNode textNode = new TextNode(vlNode.getDiagramId() + "_text", vl.getNameOrId());
graph.addNode(vlNode);
voltageLevel.getBusView().getBusStream()
graph.addNode(textNode);
graph.addEdge(vlNode, textNode, new TextEdge(textNode.getDiagramId() + "_edge"));
vl.getBusView().getBusStream()
.map(bus -> new BusInnerNode(idProvider.createId(bus), bus.getId()))
.forEach(vlNode::addBusNode);
}
});
}

private void addGraphEdges(Graph graph) {
for (VoltageLevel voltageLevel : network.getVoltageLevels()) {
voltageLevel.visitEquipments(new VisitorBuilder(graph));
}
network.getVoltageLevelStream()
.filter(voltageLevelFilter)
.forEach(vl -> vl.visitEquipments(new VisitorBuilder(graph)));
}

private class VisitorBuilder extends DefaultTopologyVisitor {
Expand All @@ -76,15 +79,16 @@ public void visitLine(Line line, Branch.Side side) {
if (graph.containsEdge(line.getId())) {
return;
}
Optional<VoltageLevelNode> vlNode1 = graph.getVoltageLevelNode(line.getTerminal1().getVoltageLevel().getId());
Optional<VoltageLevelNode> vlNode2 = graph.getVoltageLevelNode(line.getTerminal2().getVoltageLevel().getId());
if (vlNode1.isEmpty() || vlNode2.isEmpty()) {
throw new PowsyblException("Cannot add line, voltage level unknown");
}
double nominalV = vlNode1.get().getNominalV();
graph.addEdge(vlNode1.get(), vlNode2.get(),
new LineEdge(idProvider.createId(line), line.getId(), line.getNameOrId(),
line.getTerminal1().isConnected(), line.getTerminal2().isConnected(), nominalV));

Branch.Side otherSide = side == Branch.Side.ONE ? Branch.Side.TWO : Branch.Side.ONE;
VoltageLevelNode vlNode = graph.getVoltageLevelNode(line.getTerminal(side).getVoltageLevel().getId())
.orElseThrow(() -> new PowsyblException("Cannot add line, its voltage level is unknown"));
VoltageLevelNode vlOtherNode = getOrCreateVoltageLevelNode(line.getTerminal(otherSide));

double nominalV = vlNode.getNominalV();
LineEdge edge = new LineEdge(idProvider.createId(line), line.getId(), line.getNameOrId(),
line.getTerminal1().isConnected(), line.getTerminal2().isConnected(), nominalV);
graph.addEdge(vlNode, vlOtherNode, edge);
}

@Override
Expand All @@ -93,17 +97,16 @@ public void visitTwoWindingsTransformer(TwoWindingsTransformer twt, Branch.Side
if (graph.containsEdge(twt.getId())) {
return;
}
VoltageLevel vl1 = twt.getTerminal1().getVoltageLevel();
VoltageLevel vl2 = twt.getTerminal2().getVoltageLevel();
Optional<VoltageLevelNode> vlNode1 = graph.getVoltageLevelNode(vl1.getId());
Optional<VoltageLevelNode> vlNode2 = graph.getVoltageLevelNode(vl2.getId());
if (vlNode1.isEmpty() || vlNode2.isEmpty()) {
throw new PowsyblException("Cannot add line, one voltage level unknown");
}

Branch.Side otherSide = side == Branch.Side.ONE ? Branch.Side.TWO : Branch.Side.ONE;
VoltageLevelNode vlNode = graph.getVoltageLevelNode(twt.getTerminal(side).getVoltageLevel().getId())
.orElseThrow(() -> new PowsyblException("Cannot add two-windings transformer, its voltage level is unknown"));
VoltageLevelNode vlOtherNode = getOrCreateVoltageLevelNode(twt.getTerminal(otherSide));

AbstractBranchEdge edge = new TwoWtEdge(idProvider.createId(twt), twt.getId(), twt.getNameOrId(),
twt.getTerminal1().isConnected(), twt.getTerminal2().isConnected(),
vl1.getNominalV(), vl2.getNominalV());
graph.addEdge(vlNode1.get(), vlNode2.get(), edge);
twt.getTerminal(side).isConnected(), twt.getTerminal(otherSide).isConnected(),
twt.getTerminal(side).getVoltageLevel().getNominalV(), twt.getTerminal(otherSide).getVoltageLevel().getNominalV());
graph.addEdge(vlNode, vlOtherNode, edge);
}

@Override
Expand All @@ -112,19 +115,61 @@ public void visitThreeWindingsTransformer(ThreeWindingsTransformer twt, ThreeWin
if (graph.containsNode(twt.getId())) {
return;
}
List<? extends Terminal> terminals = twt.getTerminals();
Optional<VoltageLevelNode> vlNode1 = graph.getVoltageLevelNode(terminals.get(0).getVoltageLevel().getId());
Optional<VoltageLevelNode> vlNode2 = graph.getVoltageLevelNode(terminals.get(1).getVoltageLevel().getId());
Optional<VoltageLevelNode> vlNode3 = graph.getVoltageLevelNode(terminals.get(2).getVoltageLevel().getId());
if (vlNode1.isEmpty() || vlNode2.isEmpty() || vlNode3.isEmpty()) {
throw new PowsyblException("Cannot add three-windings transformer, one voltage level unknown");

VoltageLevelNode vlNode = graph.getVoltageLevelNode(twt.getTerminal(side).getVoltageLevel().getId())
.orElseThrow(() -> new PowsyblException("Cannot add three-windings transformer, its voltage level is unknown"));
ThreeWindingsTransformer.Side otherSide1;
ThreeWindingsTransformer.Side otherSide2;
if (side == ThreeWindingsTransformer.Side.ONE) {
otherSide1 = ThreeWindingsTransformer.Side.TWO;
otherSide2 = ThreeWindingsTransformer.Side.THREE;
} else if (side == ThreeWindingsTransformer.Side.TWO) {
otherSide1 = ThreeWindingsTransformer.Side.ONE;
otherSide2 = ThreeWindingsTransformer.Side.THREE;
} else {
otherSide1 = ThreeWindingsTransformer.Side.ONE;
otherSide2 = ThreeWindingsTransformer.Side.TWO;
}
VoltageLevelNode vlOtherNode1 = getOrCreateVoltageLevelNode(twt.getTerminal(otherSide1));
VoltageLevelNode vlOtherNode2 = getOrCreateVoltageLevelNode(twt.getTerminal(otherSide2));

String twtId = twt.getId();
String twtName = twt.getNameOrId();
TransformerNode tn = new TransformerNode(idProvider.createId(twt), twtId, twtName);
graph.addEdge(vlNode1.get(), tn, new ThreeWtEdge(idProvider.createId(twt.getLeg1()), twtId + LEG1_SUFFIX, twtName, twt.getLeg1().getTerminal().isConnected()));
graph.addEdge(vlNode2.get(), tn, new ThreeWtEdge(idProvider.createId(twt.getLeg2()), twtId + LEG2_SUFFIX, twtName, twt.getLeg2().getTerminal().isConnected()));
graph.addEdge(vlNode3.get(), tn, new ThreeWtEdge(idProvider.createId(twt.getLeg3()), twtId + LEG3_SUFFIX, twtName, twt.getLeg3().getTerminal().isConnected()));
graph.addEdge(tn, vlNode, new ThreeWtEdge(idProvider.createId(get3wtLeg(twt, side)), get3wtEquipmentId(twtId, side), twtName, twt.getTerminal(side).isConnected()));
graph.addEdge(tn, vlOtherNode1, new ThreeWtEdge(idProvider.createId(get3wtLeg(twt, otherSide1)), get3wtEquipmentId(twtId, otherSide1), twtName, twt.getTerminal(otherSide1).isConnected()));
graph.addEdge(tn, vlOtherNode2, new ThreeWtEdge(idProvider.createId(get3wtLeg(twt, otherSide2)), get3wtEquipmentId(twtId, otherSide2), twtName, twt.getTerminal(otherSide2).isConnected()));
}

private ThreeWindingsTransformer.Leg get3wtLeg(ThreeWindingsTransformer twt, ThreeWindingsTransformer.Side side) {
if (side == ThreeWindingsTransformer.Side.ONE) {
return twt.getLeg1();
} else if (side == ThreeWindingsTransformer.Side.TWO) {
return twt.getLeg2();
} else {
return twt.getLeg3();
}
}

private String get3wtEquipmentId(String twtId, ThreeWindingsTransformer.Side side) {
if (side == ThreeWindingsTransformer.Side.ONE) {
return twtId + "_leg1";
} else if (side == ThreeWindingsTransformer.Side.TWO) {
return twtId + "_leg2";
} else {
return twtId + "_leg3";
}
}

private VoltageLevelNode getOrCreateVoltageLevelNode(Terminal terminal) {
VoltageLevel vl = terminal.getVoltageLevel();
return graph.getVoltageLevelNode(vl.getId()).orElseGet(() -> createInvisibleVoltageLevelNode(vl));
}

private VoltageLevelNode createInvisibleVoltageLevelNode(VoltageLevel vl) {
VoltageLevelNode invisibleVlNode = new VoltageLevelNode(idProvider.createId(vl), vl.getId(), vl.getNameOrId(), vl.getNominalV(), false);
graph.addNode(invisibleVlNode);
return invisibleVlNode;
}
}
}
111 changes: 111 additions & 0 deletions src/main/java/com/powsybl/nad/build/iidm/VoltageLevelFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* Copyright (c) 2021, 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/.
*/
package com.powsybl.nad.build.iidm;

import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.*;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;

/**
* @author Florian Dupuy <florian.dupuy at rte-france.com>
*/
public class VoltageLevelFilter implements Predicate<VoltageLevel> {

public static final Predicate<VoltageLevel> NO_FILTER = voltageLevel -> true;

private final Set<VoltageLevel> voltageLevels;

public VoltageLevelFilter(Set<VoltageLevel> voltageLevels) {
this.voltageLevels = voltageLevels;
}

@Override
public boolean test(VoltageLevel voltageLevel) {
return voltageLevels.contains(voltageLevel);
}

public static VoltageLevelFilter createVoltageLevelDepthFilter(Network network, String voltageLevelId, int depth) {
Objects.requireNonNull(network);
Objects.requireNonNull(voltageLevelId);

Set<VoltageLevel> voltageLevels = new HashSet<>();
VoltageLevel vl = network.getVoltageLevel(voltageLevelId);
if (vl == null) {
throw new PowsyblException("Unknown voltage level id '" + voltageLevelId + "'");
}

Set<VoltageLevel> startingSet = new HashSet<>();
startingSet.add(vl);
traverseVoltageLevels(startingSet, depth, voltageLevels);
return new VoltageLevelFilter(voltageLevels);
}

private static void traverseVoltageLevels(Set<VoltageLevel> voltageLevelsDepth, int depth, Set<VoltageLevel> visitedVoltageLevels) {
if (depth < 0) {
return;
}
Set<VoltageLevel> nextDepthVoltageLevels = new HashSet<>();
for (VoltageLevel vl : voltageLevelsDepth) {
if (!visitedVoltageLevels.contains(vl)) {
visitedVoltageLevels.add(vl);
vl.visitEquipments(new VlVisitor(nextDepthVoltageLevels, visitedVoltageLevels));
}
}
traverseVoltageLevels(nextDepthVoltageLevels, depth - 1, visitedVoltageLevels);
}

private static class VlVisitor extends DefaultTopologyVisitor {
private final Set<VoltageLevel> nextDepthVoltageLevels;
private final Set<VoltageLevel> visitedVoltageLevels;

public VlVisitor(Set<VoltageLevel> nextDepthVoltageLevels, Set<VoltageLevel> visitedVoltageLevels) {
this.nextDepthVoltageLevels = nextDepthVoltageLevels;
this.visitedVoltageLevels = visitedVoltageLevels;
}

@Override
public void visitLine(Line line, Branch.Side side) {
visitBranch(line, side);
}

@Override
public void visitTwoWindingsTransformer(TwoWindingsTransformer twt, Branch.Side side) {
visitBranch(twt, side);
}

@Override
public void visitThreeWindingsTransformer(ThreeWindingsTransformer twt, ThreeWindingsTransformer.Side side) {
if (side == ThreeWindingsTransformer.Side.ONE) {
visitTerminal(twt.getTerminal(ThreeWindingsTransformer.Side.TWO));
visitTerminal(twt.getTerminal(ThreeWindingsTransformer.Side.THREE));
} else if (side == ThreeWindingsTransformer.Side.TWO) {
visitTerminal(twt.getTerminal(ThreeWindingsTransformer.Side.ONE));
visitTerminal(twt.getTerminal(ThreeWindingsTransformer.Side.THREE));
} else {
visitTerminal(twt.getTerminal(ThreeWindingsTransformer.Side.ONE));
visitTerminal(twt.getTerminal(ThreeWindingsTransformer.Side.TWO));
}
}

private void visitBranch(Branch<?> branch, Branch.Side side) {
Branch.Side otherSide = side == Branch.Side.ONE ? Branch.Side.TWO : Branch.Side.ONE;
visitTerminal(branch.getTerminal(otherSide));
}

private void visitTerminal(Terminal terminal) {
VoltageLevel voltageLevel = terminal.getVoltageLevel();
if (!visitedVoltageLevels.contains(voltageLevel)) {
nextDepthVoltageLevels.add(voltageLevel);
}
}
}

}
Loading