Skip to content

Create a default NadProfile #991

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
16 changes: 16 additions & 0 deletions cpp/powsybl-cpp/powsybl-cpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,22 @@ std::vector<std::string> getNetworkAreaDiagramDisplayedVoltageLevels(const JavaH
return displayedVoltageLevelIds.get();
}

SeriesArray* getNetworkAreaDiagramDefaultBranchLabels(const JavaHandle& network) {
return new SeriesArray(PowsyblCaller::get()->callJava<array*>(::getNetworkAreaDiagramDefaultBranchLabels, network));
}

SeriesArray* getNetworkAreaDiagramDefaultTwtLabels(const JavaHandle& network) {
return new SeriesArray(PowsyblCaller::get()->callJava<array*>(::getNetworkAreaDiagramDefaultThreeWtLabels, network));
}

SeriesArray* getNetworkAreaDiagramDefaultBusDescriptions(const JavaHandle& network) {
return new SeriesArray(PowsyblCaller::get()->callJava<array*>(::getNetworkAreaDiagramDefaultBusDescriptions, network));
}

SeriesArray* getNetworkAreaDiagramDefaultVoltageLevelDescriptions(const JavaHandle& network) {
return new SeriesArray(PowsyblCaller::get()->callJava<array*>(::getNetworkAreaDiagramDefaultVlDescriptions, network));
}

JavaHandle createSecurityAnalysis() {
return PowsyblCaller::get()->callJava<JavaHandle>(::createSecurityAnalysis);
}
Expand Down
8 changes: 8 additions & 0 deletions cpp/powsybl-cpp/powsybl-cpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,14 @@ std::vector<std::string> getNetworkAreaDiagramSvgAndMetadata(const JavaHandle& n

std::vector<std::string> getNetworkAreaDiagramDisplayedVoltageLevels(const JavaHandle& network, const std::vector<std::string>& voltageLevelIds, int depth);

SeriesArray* getNetworkAreaDiagramDefaultBranchLabels(const JavaHandle& network);

SeriesArray* getNetworkAreaDiagramDefaultTwtLabels(const JavaHandle& network);

SeriesArray* getNetworkAreaDiagramDefaultBusDescriptions(const JavaHandle& network);

SeriesArray* getNetworkAreaDiagramDefaultVoltageLevelDescriptions(const JavaHandle& network);

JavaHandle createSecurityAnalysis();

void addContingency(const JavaHandle& analysisContext, const std::string& contingencyId, const std::vector<std::string>& elementsIds);
Expand Down
12 changes: 12 additions & 0 deletions cpp/pypowsybl-cpp/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,18 @@ PYBIND11_MODULE(_pypowsybl, m) {
m.def("get_network_area_diagram_displayed_voltage_levels", &pypowsybl::getNetworkAreaDiagramDisplayedVoltageLevels, "Get network area diagram displayed voltage level",
py::arg("network"), py::arg("voltage_level_ids"), py::arg("depth"));

m.def("get_default_branch_labels_nad", &pypowsybl::getNetworkAreaDiagramDefaultBranchLabels, "Get network area diagram default branch labels",
py::arg("network"));

m.def("get_default_twt_labels_nad", &pypowsybl::getNetworkAreaDiagramDefaultTwtLabels, "Get network area diagram default twt labels",
py::arg("network"));

m.def("get_default_bus_descriptions_nad", &pypowsybl::getNetworkAreaDiagramDefaultBusDescriptions, "Get network area diagram default bus descriptions",
py::arg("network"));

m.def("get_default_voltage_level_descriptions_nad", &pypowsybl::getNetworkAreaDiagramDefaultVoltageLevelDescriptions, "Get network area diagram default voltage level descriptions",
py::arg("network"));

m.def("create_security_analysis", &pypowsybl::createSecurityAnalysis, "Create a security analysis");

m.def("add_contingency", &pypowsybl::addContingency, "Add a contingency to a security analysis or sensitivity analysis",
Expand Down
8 changes: 8 additions & 0 deletions docs/user_guide/network_visualization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,14 @@ Similarly to the edge_styles, the three_wt_styles parameter can be used to set t

The optional parameter nad_profile can also be set in the write_network_area_diagram function.

We can create a NadProfile, initialized with default content (in terms of branch_labels, vl_descriptions, and bus_descriptions), by using the get_default_nad_profile function:

.. code-block:: python

>>> default_profile = network.get_default_nad_profile()

This is useful for example if we want to update just a few labels and rely on the defaults for the other ones.

Network area diagram using geographical data
--------------------------------------------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,20 @@
*/
package com.powsybl.python.network;

import com.powsybl.dataframe.DataframeMapper;
import com.powsybl.dataframe.DataframeMapperBuilder;
import com.powsybl.iidm.network.*;
import com.powsybl.nad.model.Identifiable;
import com.powsybl.nad.NadParameters;
import com.powsybl.nad.NetworkAreaDiagram;
import com.powsybl.nad.build.iidm.NetworkGraphBuilder;
import com.powsybl.nad.build.iidm.VoltageLevelFilter;
import com.powsybl.nad.model.*;
import com.powsybl.nad.svg.CustomLabelProvider;
import com.powsybl.nad.svg.EdgeInfo;
import com.powsybl.nad.svg.LabelProvider;
import com.powsybl.nad.svg.SvgParameters;
import com.powsybl.nad.svg.iidm.DefaultLabelProvider;

import java.io.IOException;
import java.io.StringWriter;
Expand All @@ -21,7 +30,12 @@
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
Expand Down Expand Up @@ -116,4 +130,229 @@ static VoltageLevelFilter getNominalVoltageFilter(Network network, double nomina
public static List<String> getDisplayedVoltageLevels(Network network, List<String> voltageLevelIds, int depth) {
return NetworkAreaDiagram.getDisplayedVoltageLevels(network, voltageLevelIds, depth);
}

public record CustomLabelData(Map<String, CustomLabelProvider.BranchLabels> branchLabels, Map<String, CustomLabelProvider.ThreeWtLabels> threeWtLabels,
Map<String, String> busDescriptions, Map<String, List<String>> vlDescriptions, Map<String, List<String>> vlDetails) {
}

public static Map<String, CustomLabelProvider.BranchLabels> getBranchLabelsMap(Graph graph, LabelProvider labelProvider) {

return graph.getBranchEdgeStream()
.filter(be -> !(BranchEdge.DANGLING_LINE_EDGE.equals(be.getType())))
.collect(Collectors.toMap(Identifiable::getEquipmentId, branchEdge -> {
EdgeInfo e1 = labelProvider.getEdgeInfo(graph, branchEdge, BranchEdge.Side.ONE).orElse(null);
String side1Label = "";
EdgeInfo.Direction dir1 = null;
if (e1 != null) {
side1Label = e1.getExternalLabel().orElse("");
dir1 = e1.getDirection().orElse(null);

}

EdgeInfo e2 = labelProvider.getEdgeInfo(graph, branchEdge, BranchEdge.Side.TWO).orElse(null);
String side2Label = "";
EdgeInfo.Direction dir2 = null;
if (e2 != null) {
side2Label = e2.getExternalLabel().orElse("");
dir2 = e2.getDirection().orElse(null);
}

String edgeLabel = labelProvider.getLabel(branchEdge);

return new CustomLabelProvider.BranchLabels(side1Label, edgeLabel, side2Label, dir1, dir2);
}));
}

public static Map<String, CustomLabelProvider.BranchLabels> getBranchLabelsMap(Network network, SvgParameters pars) {
LabelProvider labelProvider = new DefaultLabelProvider(network, pars);
Graph graph = new NetworkGraphBuilder(network).buildGraph();
return NetworkAreaDiagramUtil.getBranchLabelsMap(graph, labelProvider);
}

private static CustomLabelProvider.ThreeWtLabels buildThreeWtLabelsRecord(List<ThreeWtEdge> dataList, Graph graph, LabelProvider labelProvider) {
String side1 = null;
String side2 = null;
String side3 = null;
EdgeInfo.Direction direction1 = null;
EdgeInfo.Direction direction2 = null;
EdgeInfo.Direction direction3 = null;

for (ThreeWtEdge edge : dataList) {
ThreeWtEdge.Side side = edge.getSide();
Optional<EdgeInfo> edgeInfo = labelProvider.getEdgeInfo(graph, edge);
if (edgeInfo.isPresent()) {
EdgeInfo.Direction dir = edgeInfo.get().getDirection().orElse(null);
String label = edgeInfo.get().getExternalLabel().orElse("");

switch (side) {
case ONE -> {
side1 = label;
direction1 = dir;
}
case TWO -> {
side2 = label;
direction2 = dir;
}
case THREE -> {
side3 = label;
direction3 = dir;
}
}
}
}
return new CustomLabelProvider.ThreeWtLabels(side1, side2, side3, direction1, direction2, direction3);
}

public static Map<String, CustomLabelProvider.ThreeWtLabels> getThreeWtBranchLabelsMap(Graph graph, LabelProvider labelProvider) {
return graph.getThreeWtEdgesStream().collect(Collectors.groupingBy(
ThreeWtEdge::getEquipmentId,
Collectors.collectingAndThen(
Collectors.toList(),
list -> buildThreeWtLabelsRecord(list, graph, labelProvider)
)
));
}

public static Map<String, CustomLabelProvider.ThreeWtLabels> getThreeWtBranchLabelsMap(Network network, SvgParameters pars) {
LabelProvider labelProvider = new DefaultLabelProvider(network, pars);
Graph graph = new NetworkGraphBuilder(network).buildGraph();
return NetworkAreaDiagramUtil.getThreeWtBranchLabelsMap(graph, labelProvider);
}

public static Map<String, String> getBusDescriptionsMap(Graph graph, LabelProvider labelProvider) {
return graph.getBusNodesStream()
.filter(busNode -> !(busNode instanceof BoundaryBusNode))
.collect(Collectors.toMap(
BusNode::getEquipmentId,
labelProvider::getBusDescription
));
}

public static Map<String, String> getBusDescriptionsMap(Network network, SvgParameters pars) {
LabelProvider labelProvider = new DefaultLabelProvider(network, pars);
Graph graph = new NetworkGraphBuilder(network).buildGraph();
return NetworkAreaDiagramUtil.getBusDescriptionsMap(graph, labelProvider);
}

public static Map<String, List<String>> getVoltageLevelDescriptionsMap(Graph graph, LabelProvider labelProvider) {
return graph.getVoltageLevelNodesStream()
.filter(Objects::nonNull)
.filter(VoltageLevelNode::isVisible)
.filter(vlNode -> !(vlNode instanceof BoundaryNode))
.collect(Collectors.toMap(
VoltageLevelNode::getEquipmentId,
labelProvider::getVoltageLevelDescription
));
}

public static Map<String, List<String>> getVoltageLevelDetailsMap(Graph graph, LabelProvider labelProvider) {
return graph.getVoltageLevelNodesStream()
.filter(Objects::nonNull)
.filter(VoltageLevelNode::isVisible)
.filter(vlNode -> !(vlNode instanceof BoundaryNode))
.collect(Collectors.filtering(
c1 -> {
List<String> details = labelProvider.getVoltageLevelDetails(c1);
return details != null && !details.isEmpty();
},
Collectors.toMap(
VoltageLevelNode::getEquipmentId,
labelProvider::getVoltageLevelDetails
)));
}

private static String getDirectionAsString(EdgeInfo.Direction dir) {
if (dir != null) {
return dir.name();
} else {
return "";
}
}

private static String getBranchArrowAsString(CustomLabelProvider.BranchLabels label, BranchEdge.Side side) {
EdgeInfo.Direction dir = switch (side) {
case ONE -> label.arrow1();
case TWO -> label.arrow2();
};
return getDirectionAsString(dir);
}

private static String getTwtLegArrowAsString(CustomLabelProvider.ThreeWtLabels label, ThreeWtEdge.Side side) {
EdgeInfo.Direction dir = switch (side) {
case ONE -> label.arrow1();
case TWO -> label.arrow2();
case THREE -> label.arrow3();
};
return getDirectionAsString(dir);
}

public static final DataframeMapper<Map<String, CustomLabelProvider.BranchLabels>, Void> BRANCH_LABELS_MAPPER = new DataframeMapperBuilder<Map<String, CustomLabelProvider.BranchLabels>,
Map.Entry<String, CustomLabelProvider.BranchLabels>, Void>()
.itemsProvider(c -> c.entrySet()
.stream()
.map(x -> Map.entry(x.getKey(), x.getValue()))
.toList())
.stringsIndex("id", Map.Entry::getKey)
.strings("side1", ble -> ble.getValue().side1())
.strings("middle", ble -> ble.getValue().middle())
.strings("side2", ble -> ble.getValue().side2())
.strings("arrow1", ble -> getBranchArrowAsString(ble.getValue(), BranchEdge.Side.ONE))
.strings("arrow2", ble -> getBranchArrowAsString(ble.getValue(), BranchEdge.Side.TWO))
.build();

public static final DataframeMapper<Map<String, CustomLabelProvider.ThreeWtLabels>, Void> TWT_LABELS_MAPPER = new DataframeMapperBuilder<Map<String, CustomLabelProvider.ThreeWtLabels>,
Map.Entry<String, CustomLabelProvider.ThreeWtLabels>, Void>()
.itemsProvider(c -> c.entrySet()
.stream()
.map(x -> Map.entry(x.getKey(), x.getValue()))
.toList())
.stringsIndex("id", Map.Entry::getKey)
.strings("side1", ble -> ble.getValue().side1())
.strings("side2", ble -> ble.getValue().side2())
.strings("side3", ble -> ble.getValue().side3())
.strings("arrow1", ble -> getTwtLegArrowAsString(ble.getValue(), ThreeWtEdge.Side.ONE))
.strings("arrow2", ble -> getTwtLegArrowAsString(ble.getValue(), ThreeWtEdge.Side.TWO))
.strings("arrow3", ble -> getTwtLegArrowAsString(ble.getValue(), ThreeWtEdge.Side.THREE))
.build();

public static final DataframeMapper<Map<String, String>, Void> BUS_DESCRIPTIONS_MAPPER = new DataframeMapperBuilder<Map<String, String>, Map.Entry<String, String>, Void>()
.itemsProvider(c -> c.entrySet()
.stream()
.map(x -> Map.entry(x.getKey(), x.getValue()))
.toList())
.stringsIndex("id", Map.Entry::getKey)
.strings("description", Map.Entry::getValue)
.build();

public record VlInfos(String id, String type, String description) {
}

public static List<NetworkAreaDiagramUtil.VlInfos> getVlDescriptionsWithType(Map<String, List<String>> vlDescriptionMap, Map<String, List<String>> vlDetailsMap) {
Objects.requireNonNull(vlDescriptionMap);
Objects.requireNonNull(vlDetailsMap);
return Stream.concat(
vlDescriptionMap.entrySet().stream()
.flatMap(entry -> entry.getValue().stream()
.map(value -> new NetworkAreaDiagramUtil.VlInfos(entry.getKey(), "HEADER", value))),
vlDetailsMap.entrySet().stream()
.flatMap(entry -> entry.getValue().stream()
.map(value -> new NetworkAreaDiagramUtil.VlInfos(entry.getKey(), "FOOTER", value)))
).toList();
}

public static List<NetworkAreaDiagramUtil.VlInfos> getVlDescriptionsWithType(Network network, SvgParameters svgParameters) {
Objects.requireNonNull(network);
Objects.requireNonNull(svgParameters);
LabelProvider labelProvider = new DefaultLabelProvider(network, svgParameters);
Graph graph = new NetworkGraphBuilder(network).buildGraph();
return getVlDescriptionsWithType(NetworkAreaDiagramUtil.getVoltageLevelDescriptionsMap(graph, labelProvider), NetworkAreaDiagramUtil.getVoltageLevelDetailsMap(graph, labelProvider));

}

public static final DataframeMapper<List<VlInfos>, Void> VL_DESCRIPTIONS_MAPPER = new DataframeMapperBuilder<List<VlInfos>, VlInfos, Void>()
.itemsProvider(c -> c)
.stringsIndex("id", x -> x.id)
.strings("type", x -> x.type)
.strings("description", x -> x.description)
.build();
}
Loading
Loading