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

Choose which components are on busbars #407

Merged
merged 15 commits into from
Jul 22, 2022
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,28 @@
*/
package com.powsybl.sld.layout;

import com.powsybl.sld.layout.positionbyclustering.PositionByClustering;
import com.powsybl.sld.layout.positionfromextension.PositionFromExtension;
import com.powsybl.commons.PowsyblException;
import com.powsybl.sld.model.blocks.FeederPrimaryBlock;
import com.powsybl.sld.model.blocks.LegPrimaryBlock;
import com.powsybl.sld.model.cells.*;
import com.powsybl.sld.model.cells.BusCell;
import com.powsybl.sld.model.cells.Cell;
import com.powsybl.sld.model.cells.ExternCell;
import com.powsybl.sld.model.cells.InternCell;
import com.powsybl.sld.model.coordinate.Side;
import com.powsybl.sld.model.graphs.VoltageLevelGraph;
import com.powsybl.sld.model.nodes.BusConnection;
import com.powsybl.sld.model.nodes.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static com.powsybl.sld.model.blocks.Block.Extremity.END;
import static com.powsybl.sld.model.blocks.Block.Extremity.START;
import static com.powsybl.sld.model.cells.Cell.CellType.*;
import static com.powsybl.sld.model.cells.Cell.CellType.INTERN;
import static com.powsybl.sld.model.nodes.Node.NodeType.*;

/**
* @author Benoit Jeanson <benoit.jeanson at rte-france.com>
Expand All @@ -43,30 +48,6 @@ public class BlockOrganizer {

private final Map<String, Side> busInfoMap;

public BlockOrganizer() {
this(new PositionFromExtension(), true);
}

public BlockOrganizer(boolean stack) {
this(new PositionByClustering(), stack);
}

public BlockOrganizer(PositionFinder positionFinder) {
this(positionFinder, true);
}

public BlockOrganizer(PositionFinder positionFinder, boolean stack) {
this(positionFinder, stack, false);
}

public BlockOrganizer(PositionFinder positionFinder, boolean stack, boolean exceptionIfPatternNotHandled) {
this(positionFinder, stack, exceptionIfPatternNotHandled, false, Collections.emptyMap());
}

public BlockOrganizer(PositionFinder positionFinder, boolean stack, boolean exceptionIfPatternNotHandled, boolean handleShunt) {
this(positionFinder, stack, exceptionIfPatternNotHandled, handleShunt, Collections.emptyMap());
}

public BlockOrganizer(PositionFinder positionFinder, boolean stack, boolean exceptionIfPatternNotHandled, boolean handleShunt, Map<String, Side> busInfoMap) {
this.positionFinder = Objects.requireNonNull(positionFinder);
this.stack = stack;
Expand All @@ -78,10 +59,11 @@ public BlockOrganizer(PositionFinder positionFinder, boolean stack, boolean exce
/**
* Organize cells into blocks and call the layout resolvers
*/
public void organize(VoltageLevelGraph graph) {
public void organize(VoltageLevelGraph graph, LayoutParameters layoutParameters) {
LOGGER.info("Organizing graph cells into blocks");
graph.getBusCellStream().forEach(cell -> {
CellBlockDecomposer.determineComplexCell(graph, cell, exceptionIfPatternNotHandled);
checkBlocks(cell, layoutParameters);
if (cell.getType() == INTERN) {
((InternCell) cell).organizeBlocks();
}
Expand All @@ -102,6 +84,31 @@ public void organize(VoltageLevelGraph graph) {
new BlockPositionner().determineBlockPositions(graph, subsections, busInfoMap);
}

private void checkBlocks(BusCell cell, LayoutParameters layoutParameters) {
cell.getLegPrimaryBlocks().forEach(lpb -> checkLegPrimaryBlockConsistency(lpb, layoutParameters.getComponentsOnBusbars()));
cell.getFeederPrimaryBlocks().forEach(this::checkFeederPrimaryBlockConsistency);
}

private void checkLegPrimaryBlockConsistency(LegPrimaryBlock legPrimaryBlock, List<String> componentsOnBus) {
List<Node> nodes = legPrimaryBlock.getNodes();
boolean consistent = nodes.size() == 3
&& nodes.get(0).getType() == Node.NodeType.BUS
&& nodes.get(1) instanceof BusConnection || componentsOnBus.contains(nodes.get(1).getComponentType())
&& (nodes.get(2).getType() == Node.NodeType.FICTITIOUS || nodes.get(2).getType() == Node.NodeType.SHUNT);
if (!consistent) {
throw new PowsyblException("LegPrimaryBlock not consistent");
}
}

private void checkFeederPrimaryBlockConsistency(FeederPrimaryBlock lpb) {
List<Node> nodes = lpb.getNodes();
boolean consistent = nodes.size() == 2 && nodes.get(1).getType() == FEEDER
&& (nodes.get(0).getType() == FICTITIOUS || nodes.get(0).getType() == SHUNT);
if (!consistent) {
throw new PowsyblException("FeederPrimaryBlock not consistent");
}
}

/**
* Determines blocks connected to busbar that are stackable
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,8 @@ private static List<Block> createPrimaryBlock(BusCell busCell) {
}

private static void mergeBlocks(VoltageLevelGraph vlGraph, BusCell busCell, List<Block> blocks, boolean exceptionIfPatternNotHandled) {
// Search all blocks connected to a busbar inside the primary blocks list
List<LegPrimaryBlock> primaryLegBlocks = blocks.stream()
.filter(b -> b instanceof LegPrimaryBlock)
.map(LegPrimaryBlock.class::cast)
.collect(Collectors.toList());
List<LegPrimaryBlock> legPrimaryBlocks = blocks.stream().filter(LegPrimaryBlock.class::isInstance).map(LegPrimaryBlock.class::cast).collect(Collectors.toList());
List<FeederPrimaryBlock> feederPrimaryBlocks = blocks.stream().filter(FeederPrimaryBlock.class::isInstance).map(FeederPrimaryBlock.class::cast).collect(Collectors.toList());

// Merge blocks to obtain a hierarchy of blocks
while (blocks.size() != 1) {
Expand All @@ -84,7 +81,7 @@ private static void mergeBlocks(VoltageLevelGraph vlGraph, BusCell busCell, List
}
}
}
busCell.blocksSetting(blocks.get(0), primaryLegBlocks);
busCell.blocksSetting(blocks.get(0), legPrimaryBlocks, feederPrimaryBlocks);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* 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/.
*/
package com.powsybl.sld.layout;

import com.powsybl.sld.model.graphs.VoltageLevelGraph;
import com.powsybl.sld.model.nodes.*;

import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
* Refines the graph so that it becomes consistent with the diagram layout.
* In particular for cell detection: it inserts the {@link BusConnection} nodes and {@link InternalNode} hook nodes needed for it.
*
* @author Florian Dupuy <florian.dupuy at rte-france.com>
*/
public class GraphRefiner {
private final boolean removeUnnecessaryFictitiousNodes;
private final boolean substituteSingularFictitiousByFeederNode;

public GraphRefiner(boolean removeUnnecessaryFictitiousNodes, boolean substituteSingularFictitiousByFeederNode) {
this.removeUnnecessaryFictitiousNodes = removeUnnecessaryFictitiousNodes;
this.substituteSingularFictitiousByFeederNode = substituteSingularFictitiousByFeederNode;
}

void run(VoltageLevelGraph graph, LayoutParameters layoutParameters) {
graph.substituteFictitiousNodesMirroringBusNodes();
if (removeUnnecessaryFictitiousNodes) {
graph.removeUnnecessaryFictitiousNodes();
}
if (substituteSingularFictitiousByFeederNode) {
graph.substituteSingularFictitiousByFeederNode();
}

graph.extendBusesConnectedToBuses();

Predicate<Node> nodesOnBus = getNodesOnBusPredicate(graph, layoutParameters.getComponentsOnBusbars());
graph.insertBusConnections(nodesOnBus);
graph.insertHookNodesAtBuses();
graph.insertHookNodesAtFeeders();
}

private Predicate<Node> getNodesOnBusPredicate(VoltageLevelGraph graph, List<String> componentsOnBusbars) {
Set<Node> nodesOnBusBetweenBuses = getNodesOnBusBetweenBuses(graph, componentsOnBusbars);
return node -> componentsOnBusbars.contains(node.getComponentType()) && !nodesOnBusBetweenBuses.contains(node);
}

private Set<Node> getNodesOnBusBetweenBuses(VoltageLevelGraph graph, List<String> componentsOnBusbars) {
return graph.getNodeBuses().stream()
.flatMap(nodeBus -> nodeBus.getAdjacentNodes().stream())
.filter(nodeConnectedToBus -> componentsOnBusbars.contains(nodeConnectedToBus.getComponentType()))
.filter(n -> n.getAdjacentNodes().stream().allMatch(BusNode.class::isInstance))
.collect(Collectors.toSet());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,12 @@
public class ImplicitCellDetector implements CellDetector {

private static final Logger LOGGER = LoggerFactory.getLogger(ImplicitCellDetector.class);
private boolean removeUnnecessaryFictitiousNodes;
private boolean substituteSingularFictitiousByFeederNode;
private boolean exceptionIfPatternNotHandled;
private final boolean exceptionIfPatternNotHandled;

public ImplicitCellDetector(boolean removeUnnecessaryFictitiousNodes, boolean substituteSingularFictitiousByFeederNode, boolean exceptionIfPatternNotHandled) {
this.removeUnnecessaryFictitiousNodes = removeUnnecessaryFictitiousNodes;
this.substituteSingularFictitiousByFeederNode = substituteSingularFictitiousByFeederNode;
public ImplicitCellDetector(boolean exceptionIfPatternNotHandled) {
this.exceptionIfPatternNotHandled = exceptionIfPatternNotHandled;
}

public ImplicitCellDetector() {
this(true, true, false);
}


/**
* internCell detection : an internal cell is composed of nodes connecting BUSes without connecting Feeder.
* detectCell is used to detect cells exploring the graph and scanning exclusionTypes and stopTypes
Expand All @@ -56,8 +47,6 @@ public ImplicitCellDetector() {
*/
@Override
public void detectCells(VoltageLevelGraph graph) {
cleaning(graph);

LOGGER.info("Detecting cells...");

List<Node> allocatedNodes = new ArrayList<>();
Expand Down Expand Up @@ -97,22 +86,6 @@ private void createExternAndShuntCells(VoltageLevelGraph graph, Set<Node> nodes,
}
}

private void cleaning(VoltageLevelGraph graph) {
graph.substituteFictitiousNodesMirroringBusNodes();
if (removeUnnecessaryFictitiousNodes) {
graph.removeUnnecessaryFictitiousNodes();
}
if (substituteSingularFictitiousByFeederNode) {
graph.substituteSingularFictitiousByFeederNode();
}
graph.insertFictitiousNodesAtFeeders();
graph.extendNodeConnectedToBus(node -> node instanceof SwitchNode && ((SwitchNode) node).getKind() != SwitchNode.SwitchKind.DISCONNECTOR);
graph.extendNodeConnectedToBus(Middle3WTNode.class::isInstance);
graph.extendSwitchBetweenBuses();
graph.extendFirstOutsideNode();
graph.extendBusConnectedToBus();
}

/**
* @param graph is the voltage level graph
* @param typeStops is the types of node that stops the exploration
Expand Down Expand Up @@ -282,9 +255,9 @@ private boolean isIsolatedBusOrShunt(Set<Node> remainingNodes, Node rn) {

private ShuntCell createShuntCell(VoltageLevelGraph vlGraph, List<Node> shuntNodes) {
int cellNumber = vlGraph.getNextCellNumber();
InternalNode iNode1 = vlGraph.insertInternalNode(shuntNodes.get(0), shuntNodes.get(1),
InternalNode iNode1 = vlGraph.insertHookNodesAtBuses(shuntNodes.get(0), shuntNodes.get(1),
"Shunt " + cellNumber + ".1");
InternalNode iNode2 = vlGraph.insertInternalNode(shuntNodes.get(shuntNodes.size() - 1),
InternalNode iNode2 = vlGraph.insertHookNodesAtBuses(shuntNodes.get(shuntNodes.size() - 1),
shuntNodes.get(shuntNodes.size() - 2), "Shunt " + cellNumber + ".2");
shuntNodes.add(1, iNode1);
shuntNodes.add(shuntNodes.size() - 1, iNode2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.powsybl.sld.library.ComponentSize;
import com.powsybl.sld.library.ComponentTypeName;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

Expand Down Expand Up @@ -88,6 +91,9 @@ public class LayoutParameters {

private int feederInfoPrecision = 0;

/** Components which are displayed on busbars */
private List<String> componentsOnBusbars = List.of(ComponentTypeName.DISCONNECTOR);

@JsonIgnore
private Map<String, ComponentSize> componentsSize;

Expand Down Expand Up @@ -131,7 +137,8 @@ public LayoutParameters(@JsonProperty("voltageLevelPadding") Padding voltageLeve
@JsonProperty("feederInfosIntraMargin") double feederInfosIntraMargin,
@JsonProperty("busInfoMargin") double busInfoMargin,
@JsonProperty("busbarsAlignment") Alignment busbarsAlignment,
@JsonProperty("feederInfoPrecision") int feederInfoPrecision) {
@JsonProperty("feederInfoPrecision") int feederInfoPrecision,
@JsonProperty("componentsOnBusbars") List<String> componentsOnBusbars) {
this.diagramPadding = diagramPadding;
this.voltageLevelPadding = voltageLevelPadding;
this.verticalSpaceBus = verticalSpaceBus;
Expand Down Expand Up @@ -168,6 +175,7 @@ public LayoutParameters(@JsonProperty("voltageLevelPadding") Padding voltageLeve
this.busInfoMargin = busInfoMargin;
this.busbarsAlignment = busbarsAlignment;
this.feederInfoPrecision = feederInfoPrecision;
this.componentsOnBusbars = new ArrayList<>(componentsOnBusbars);
}

public LayoutParameters(LayoutParameters other) {
Expand Down Expand Up @@ -209,6 +217,7 @@ public LayoutParameters(LayoutParameters other) {
busInfoMargin = other.busInfoMargin;
busbarsAlignment = other.busbarsAlignment;
feederInfoPrecision = other.feederInfoPrecision;
componentsOnBusbars = new ArrayList<>(other.componentsOnBusbars);
}

public double getVerticalSpaceBus() {
Expand Down Expand Up @@ -548,6 +557,15 @@ public LayoutParameters setFeederInfoPrecision(int feederInfoPrecision) {
return this;
}

public List<String> getComponentsOnBusbars() {
return componentsOnBusbars;
}

public LayoutParameters setComponentsOnBusbars(List<String> componentsOnBusbars) {
this.componentsOnBusbars = componentsOnBusbars;
return this;
}

public enum Alignment {
FIRST, LAST, MIDDLE, NONE;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,32 @@
public class PositionVoltageLevelLayout extends AbstractVoltageLevelLayout {

private static final Logger LOGGER = LoggerFactory.getLogger(PositionVoltageLevelLayout.class);
private final CellDetector cellDetector;
private final BlockOrganizer blockOrganizer;
private final GraphRefiner graphAdapter;

public PositionVoltageLevelLayout(VoltageLevelGraph graph) {
public PositionVoltageLevelLayout(VoltageLevelGraph graph, GraphRefiner graphRefiner, CellDetector cellDetector, BlockOrganizer blockOrganizer) {
super(graph);
this.graphAdapter = graphRefiner;
this.cellDetector = cellDetector;
this.blockOrganizer = blockOrganizer;
}

/**
* Calculate real coordinate of busNode and blocks connected to busbar
* Layout the nodes:
* - adapt the graph to have the expected patterns
* - detect the cells (intern / extern / shunt)
* - organize the cells into blocks
* - calculate real coordinate of busNode and blocks connected to busbar
*/
@Override
public void run(LayoutParameters layoutParam) {
LOGGER.info("Running voltage level layout");

graphAdapter.run(getGraph(), layoutParam);
cellDetector.detectCells(getGraph());
blockOrganizer.organize(getGraph(), layoutParam);

calculateMaxCellHeight(layoutParam);
calculateBusNodeCoord(getGraph(), layoutParam);
calculateCellCoord(getGraph(), layoutParam);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,15 @@ public PositionVoltageLevelLayoutFactory setBusInfoMap(Map<String, Side> busInfo

@Override
public Layout create(VoltageLevelGraph graph) {
// detect cells
new ImplicitCellDetector(removeUnnecessaryFictitiousNodes, substituteSingularFictitiousByFeederNode, exceptionIfPatternNotHandled)
.detectCells(graph);
// For adapting the graph to the diagram layout
GraphRefiner graphRefiner = new GraphRefiner(removeUnnecessaryFictitiousNodes, substituteSingularFictitiousByFeederNode);

// build blocks from cells
new BlockOrganizer(positionFinder, feederStacked, exceptionIfPatternNotHandled, handleShunts, busInfoMap).organize(graph);
// For cell detection
ImplicitCellDetector cellDetector = new ImplicitCellDetector(exceptionIfPatternNotHandled);

return new PositionVoltageLevelLayout(graph);
// For building blocks from cells
BlockOrganizer blockOrganizer = new BlockOrganizer(positionFinder, feederStacked, exceptionIfPatternNotHandled, handleShunts, busInfoMap);

return new PositionVoltageLevelLayout(graph, graphRefiner, cellDetector, blockOrganizer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

/**
* Represents a connected set of nodes if considering the borderNodes as disconnected:
* for any couple of nodes in <code>nodess</code> there is at least one path connecting them together WITHOUT passing
* for any couple of nodes in <code>nodes</code> there is at least one path connecting them together WITHOUT passing
* through any nodes of <code>borderNodes</code>.
* The <code>nodes</code> holds the connected set of nodes.
* The <code>borderNodes</code> holds the nodes that are at the border of this set, that is for which 1 adjacent node
Expand Down
Loading