BlockOrganizer.java
/**
* Copyright (c) 2019, 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.commons.PowsyblException;
import com.powsybl.sld.layout.position.BlockPositionner;
import com.powsybl.sld.layout.position.PositionFinder;
import com.powsybl.sld.layout.position.Subsection;
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.coordinate.Side;
import com.powsybl.sld.model.graphs.VoltageLevelGraph;
import com.powsybl.sld.model.nodes.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static com.powsybl.sld.library.ComponentTypeName.BUS_CONNECTION;
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.INTERN;
import static com.powsybl.sld.model.nodes.Node.NodeType.*;
/**
* @author Benoit Jeanson {@literal <benoit.jeanson at rte-france.com>}
* @author Nicolas Duchene
* @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
*/
public class BlockOrganizer {
private static final Logger LOGGER = LoggerFactory.getLogger(BlockOrganizer.class);
private final PositionFinder positionFinder;
private final boolean stack;
private final boolean handleShunt;
private final boolean exceptionIfPatternNotHandled;
private final Map<String, Side> busInfoMap;
public BlockOrganizer(PositionFinder positionFinder, boolean stack, boolean exceptionIfPatternNotHandled, boolean handleShunt, Map<String, Side> busInfoMap) {
this.positionFinder = Objects.requireNonNull(positionFinder);
this.stack = stack;
this.exceptionIfPatternNotHandled = exceptionIfPatternNotHandled;
this.handleShunt = handleShunt;
this.busInfoMap = busInfoMap;
}
/**
* Organize cells into blocks and call the layout resolvers
*/
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(exceptionIfPatternNotHandled);
}
});
graph.getShuntCellStream().forEach(CellBlockDecomposer::determineShuntCellBlocks);
if (stack) {
determineStackableBlocks(graph);
}
List<Subsection> subsections = positionFinder.buildLayout(graph, handleShunt);
graph.getExternCellStream().forEach(ExternCell::organizeBlockDirections);
graph.getArchCellStream().forEach(ArchCell::organizeBlockDirections);
graph.getCellStream().forEach(Cell::blockSizing);
new BlockPositionner().determineBlockPositions(graph, subsections, busInfoMap);
graph.getInternCellStream()
.filter(internCell -> internCell.getShape() == InternCell.Shape.CROSSOVER)
.forEach(InternCell::crossOverBlockSizing);
}
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).getComponentType().equals(BUS_CONNECTION) || componentsOnBus.contains(nodes.get(1).getComponentType())
&& nodes.get(2).getType() == INTERNAL;
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() == INTERNAL;
if (!consistent) {
throw new PowsyblException("FeederPrimaryBlock not consistent");
}
}
/**
* Determines blocks connected to busbar that are stackable
*/
private void determineStackableBlocks(VoltageLevelGraph graph) {
LOGGER.info("Determining stackable Blocks");
graph.getBusCellStream()
.filter(cell -> !cell.getLegPrimaryBlocks().isEmpty())
.forEach(BlockOrganizer::determineStackableBlocks);
}
private static void determineStackableBlocks(BusCell cell) {
List<LegPrimaryBlock> blocks = cell.getLegPrimaryBlocks();
for (int i = 0; i < blocks.size(); i++) {
LegPrimaryBlock block1 = blocks.get(i);
if (block1.getNodes().size() == 3) {
for (int j = i + 1; j < blocks.size(); j++) {
LegPrimaryBlock block2 = blocks.get(j);
if (block2.getNodes().size() == 3
&& block1.getExtremityNode(END).equals(block2.getExtremityNode(END))
&& !block1.getExtremityNode(START).equals(block2.getExtremityNode(START))) {
block1.addStackableBlock(block2);
block2.addStackableBlock(block1);
}
}
}
}
}
}