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

Detect inconsistent busNodes positions #573

Merged
merged 3 commits into from
Dec 22, 2023
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,6 +6,8 @@
*/
package com.powsybl.sld.layout;

import com.powsybl.commons.PowsyblException;
import com.powsybl.sld.model.blocks.UndefinedBlock;
import com.powsybl.sld.model.cells.Cell;
import com.powsybl.sld.model.cells.ExternCell;
import com.powsybl.sld.model.cells.InternCell;
Expand All @@ -18,6 +20,7 @@
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
Expand Down Expand Up @@ -99,14 +102,24 @@ Set<InternCellSide> getInternCellSides() {
return internCellSides;
}

void setExtendedNodeSet(Collection<BusNode> busNodes) {
void addToExtendedNodeSet(Collection<BusNode> busNodes) {
if (busNodes.containsAll(busNodeSet)) {
extendedNodeSet.addAll(busNodes.stream().filter(Objects::nonNull).collect(Collectors.toList()));
// The given busNodes correspond to all vertical bus nodes for a specific index of the horizontalBusLanes:
// those nodes correspond to a slice of busbars.
// There can't be more than one busNode per busbar index, we check this by creating the following map with
// an exception-throwing merge method
Map<Integer, BusNode> indexToBusNode = busNodes.stream().filter(Objects::nonNull)
.collect(Collectors.toMap(BusNode::getBusbarIndex, Function.identity(), this::detectConflictingBusNodes));
extendedNodeSet.addAll(indexToBusNode.values());
} else {
LOGGER.error("ExtendedNodeSet inconsistent with NodeBusSet");
}
}

private BusNode detectConflictingBusNodes(BusNode busNode1, BusNode busNode2) {
throw new PowsyblException("Inconsistent legBusSet: extended node set contains two busNodes with same index");
}

Set<BusNode> getExtendedNodeSet() {
return extendedNodeSet;
}
Expand Down Expand Up @@ -175,7 +188,33 @@ private static boolean crossContains(List<BusNode> busNodes1, List<BusNode> busN
return busNodes1.containsAll(busNodes2) && busNodes2.containsAll(busNodes1);
}

private static boolean checkLbs(LegBusSet legBusSet) {
// FIXME: workaround to detect incoherent LegBusSet without any piece of refactoring
boolean externCellLbs = legBusSet.externCells.size() == 1; // detecting a posteriori a legBusSet created from an ExternCell
if (externCellLbs) {
List<Integer> busbarIndices = legBusSet.busNodeSet.stream().map(BusNode::getBusbarIndex).distinct().toList();
// Detecting incoherent bus positions set from the user (from extension or directly when creating the
// busNode, WHEN PositionFromExtension is used instead of PositionByClustering).
// We rule out PositionByClustering where all busbar indices are set to zero and still are at this point
// (note that zero means no value in the code so far) by dismissing the detection if there is a zero busbar
// index. There cannot be any zero busbar index with PositionFromExtension, they are replaced in the call
// PositionFromExtension::setMissingPositionIndices.
if (busbarIndices.size() < legBusSet.busNodeSet.size() && busbarIndices.get(0) != 0) {
// Corresponding extern cell set as undefined block, leading to a squashed externCell at abscissa 0
ExternCell externCell = legBusSet.externCells.iterator().next();
externCell.setRootBlock(new UndefinedBlock(List.of(externCell.getRootBlock())));
LOGGER.error("ExternCell pattern not handled: attached to several busbar sections with same busbar index");
return false;
}
}
return true;
}

public static void pushLBS(List<LegBusSet> legBusSets, LegBusSet legBusSet) {
if (!checkLbs(legBusSet)) {
return;
}

for (LegBusSet lbs : legBusSets) {
if (lbs.contains(legBusSet)) {
lbs.absorbs(legBusSet);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ static List<Subsection> createSubsections(VoltageLevelGraph graph, LBSCluster lb
subsections.add(currentSubsection);
int i = 0;
for (LegBusSet lbs : lbsCluster.getLbsList()) {
lbs.setExtendedNodeSet(lbsCluster.getVerticalBuseNodes(i));
lbs.addToExtendedNodeSet(lbsCluster.getVerticalBuseNodes(i));
if (!currentSubsection.checkAbsorbability(lbs)) {
currentSubsection = new Subsection(vSize);
subsections.add(currentSubsection);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public Map<BusNode, Integer> indexBusPosition(List<BusNode> busNodes, List<BusCe
.sorted(Comparator.comparing(BusNode::getId))
.collect(Collectors.toList())) {
busToNb.put(n, i);
n.setBusBarIndexSectionIndex(0, 0);
i++;
}
return busToNb;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* Copyright (c) 2023, 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.sld.iidm;

import com.powsybl.diagram.test.Networks;
import com.powsybl.iidm.network.Country;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.SwitchKind;
import com.powsybl.iidm.network.TopologyKind;
import com.powsybl.iidm.network.extensions.ConnectablePosition;
import com.powsybl.sld.builders.NetworkGraphBuilder;
import com.powsybl.sld.model.graphs.VoltageLevelGraph;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* <PRE>
* l
* |
* ___ b ____
* | |
* | |
* --d1-- x --d2--
* bbs1 dc bbs2
* </PRE>
*
* @author Florian Dupuy {@literal <florian.dupuy at rte-france.com>}
*/
class TestCaseExternCellOnTwoSections extends AbstractTestCaseIidm {

@BeforeEach
public void setUp() {
network = Network.create("test", "test");
graphBuilder = new NetworkGraphBuilder(network);
substation = Networks.createSubstation(network, "s", "s", Country.FR);
vl = Networks.createVoltageLevel(substation, "vl", "vl", TopologyKind.NODE_BREAKER, 225);
Networks.createBusBarSection(vl, "bbs1", "bbs1", 0, 1, 1);
Networks.createBusBarSection(vl, "bbs2", "bbs2", 1, 1, 2);
Networks.createLoad(vl, "l", "l", "l", 0, ConnectablePosition.Direction.TOP, 2, 10, 10);
Networks.createSwitch(vl, "d1", "d1", SwitchKind.DISCONNECTOR, false, false, false, 0, 3);
Networks.createSwitch(vl, "d2", "d2", SwitchKind.DISCONNECTOR, false, false, false, 1, 3);
Networks.createSwitch(vl, "dc", "dc", SwitchKind.DISCONNECTOR, false, false, false, 0, 1);
Networks.createSwitch(vl, "b", "b", SwitchKind.BREAKER, false, false, false, 3, 2);
}

@Test
void test() {
VoltageLevelGraph g = graphBuilder.buildVoltageLevelGraph(vl.getId());
voltageLevelGraphLayout(g);
assertEquals(toString("/TestCaseExternCellOnTwoSections.svg"), toSVG(g, "/TestCaseExternCellOnTwoSections.svg"));
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.