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

Remove dangling lines merge by ID #2677

Merged
merged 1 commit into from
Aug 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 @@ -7,7 +7,6 @@
package com.powsybl.iidm.network.util;

import com.google.common.collect.Sets;
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.reporter.Reporter;
import com.powsybl.iidm.network.DanglingLine;
import com.powsybl.iidm.network.DanglingLineFilter;
Expand Down Expand Up @@ -158,61 +157,40 @@ public static void mergeDifferentAliases(DanglingLine dl1, DanglingLine dl2, Map
/**
* If it exists, find the dangling line in the merging network that should be associated to a candidate dangling line in the network to be merged.
* Two dangling lines in different IGM should be associated if:
* - they have the same ID and at least one has a non-null X-node code
* OR
* - they have the same non-null X-node code and are the only dangling lines to have this X-node code in their respective networks
* OR
* - they have the same non-null X-node code and are the only connected dangling lines to have this X-node code in their respective networks
*
* @param candidateDanglingLine candidate dangling line in the network to be merged
* @param danglingLine dangling line in the merging network with same ID as the candidate dangling line. Can be null.
* @param getDanglingLinesByXnodeCode function to retrieve dangling lines with a given X-node code in the merging network.
* @param associateDanglingLines function associating two dangling lines
*/
public static void findAndAssociateDanglingLines(DanglingLine candidateDanglingLine, DanglingLine danglingLine,
public static void findAndAssociateDanglingLines(DanglingLine candidateDanglingLine,
Function<String, List<DanglingLine>> getDanglingLinesByXnodeCode,
BiConsumer<DanglingLine, DanglingLine> associateDanglingLines) {
Objects.requireNonNull(candidateDanglingLine);
Objects.requireNonNull(getDanglingLinesByXnodeCode);
Objects.requireNonNull(associateDanglingLines);
if (danglingLine == null) { // if dangling line with same ID not present, find dangling line(s) with same X-node code in merging network if present
// mapping by ucte xnode code
if (candidateDanglingLine.getUcteXnodeCode() != null) { // if X-node code null: no associated dangling line
if (candidateDanglingLine.getNetwork().getDanglingLineStream(DanglingLineFilter.UNPAIRED)
.filter(d -> d != candidateDanglingLine)
.filter(d -> candidateDanglingLine.getUcteXnodeCode().equals(d.getUcteXnodeCode()))
.anyMatch(d -> d.getTerminal().isConnected())) { // check that there is no connected dangling line with same X-node code in the network to be merged
return; // in that case, do nothing
// mapping by ucte xnode code
if (candidateDanglingLine.getUcteXnodeCode() != null) { // if X-node code null: no associated dangling line
if (candidateDanglingLine.getNetwork().getDanglingLineStream(DanglingLineFilter.UNPAIRED)
.filter(d -> d != candidateDanglingLine)
.filter(d -> candidateDanglingLine.getUcteXnodeCode().equals(d.getUcteXnodeCode()))
.anyMatch(d -> d.getTerminal().isConnected())) { // check that there is no connected dangling line with same X-node code in the network to be merged
return; // in that case, do nothing
}
List<DanglingLine> dls = getDanglingLinesByXnodeCode.apply(candidateDanglingLine.getUcteXnodeCode());
if (dls != null) {
if (dls.size() == 1) { // if there is exactly one dangling line in the merging network, merge it
associateDanglingLines.accept(dls.get(0), candidateDanglingLine);
}
List<DanglingLine> dls = getDanglingLinesByXnodeCode.apply(candidateDanglingLine.getUcteXnodeCode());
if (dls != null) {
if (dls.size() == 1) { // if there is exactly one dangling line in the merging network, merge it
associateDanglingLines.accept(dls.get(0), candidateDanglingLine);
}
if (dls.size() > 1) { // if more than one dangling line in the merging network, check how many are connected
List<DanglingLine> connectedDls = dls.stream().filter(dl -> dl.getTerminal().isConnected()).toList();
if (connectedDls.size() == 1) { // if there is exactly one connected dangling line in the merging network, merge it. Otherwise, do nothing
associateDanglingLines.accept(connectedDls.get(0), candidateDanglingLine);
}
if (dls.size() > 1) { // if more than one dangling line in the merging network, check how many are connected
List<DanglingLine> connectedDls = dls.stream().filter(dl -> dl.getTerminal().isConnected()).toList();
if (connectedDls.size() == 1) { // if there is exactly one connected dangling line in the merging network, merge it. Otherwise, do nothing
associateDanglingLines.accept(connectedDls.get(0), candidateDanglingLine);
}
}
}
} else {
// if dangling line with same ID present, there is only one: they are associated if the X-node code is identical (if not: throw exception)
boolean nonNullAndDifferent = danglingLine.getUcteXnodeCode() != null && candidateDanglingLine.getUcteXnodeCode() != null
&& !danglingLine.getUcteXnodeCode().equals(candidateDanglingLine.getUcteXnodeCode());
boolean bothNull = danglingLine.getUcteXnodeCode() == null && candidateDanglingLine.getUcteXnodeCode() == null;
if (nonNullAndDifferent || bothNull) {
throw new PowsyblException("Dangling line couple " + danglingLine.getId()
+ " have inconsistent Xnodes (" + danglingLine.getUcteXnodeCode()
+ "!=" + candidateDanglingLine.getUcteXnodeCode() + ")");
}
String code = Optional.ofNullable(danglingLine.getUcteXnodeCode()).orElseGet(candidateDanglingLine::getUcteXnodeCode);
List<DanglingLine> dls = getDanglingLinesByXnodeCode.apply(code);
if (dls != null && dls.size() > 1) {
throw new PowsyblException("Should not have any dangling lines other than " + danglingLine.getId() + " linked to " + code);
}
associateDanglingLines.accept(danglingLine, candidateDanglingLine);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -891,9 +891,6 @@ public void merge(Network other) {
Multimap<Class<? extends Identifiable>, String> intersection = index.intersection(otherNetwork.index);
for (Map.Entry<Class<? extends Identifiable>, Collection<String>> entry : intersection.asMap().entrySet()) {
Class<? extends Identifiable> clazz = entry.getKey();
if (clazz == DanglingLineImpl.class) { // fine for dangling lines
continue;
}
Collection<String> objs = entry.getValue();
if (!objs.isEmpty()) {
throw new PowsyblException("The following object(s) of type "
Expand All @@ -912,7 +909,7 @@ public void merge(Network other) {
}
}
for (DanglingLine dl2 : Lists.newArrayList(other.getDanglingLines(DanglingLineFilter.ALL))) {
findAndAssociateDanglingLines(dl2, getDanglingLine(dl2.getId()), dl1byXnodeCode::get, (dll1, dll2) -> pairDanglingLines(lines, dll1, dll2, dl1byXnodeCode));
findAndAssociateDanglingLines(dl2, dl1byXnodeCode::get, (dll1, dll2) -> pairDanglingLines(lines, dll1, dll2, dl1byXnodeCode));
}

// do not forget to remove the other network from its index!!!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,6 @@ public void failMergeWithSameObj() {
assertTrue(e.getMessage().contains("The following object(s) of type SubstationImpl exist(s) in both networks: [P1]"));
}

@Test
public void xnodeNonCompatible() {
addSubstationAndVoltageLevel();
addDanglingLines("dl", "code", "dl", "deco");
merge.merge(n1);
PowsyblException e = assertThrows(PowsyblException.class, () -> merge.merge(n2));
assertTrue(e.getMessage().contains("Dangling line couple dl have inconsistent Xnodes (code!=deco)"));
}

@Test
public void testMerge() {
addSubstationAndVoltageLevel();
Expand All @@ -64,14 +55,12 @@ public void testMerge() {
}

@Test
public void testMergeSameId() {

public void failMergeDanglingLinesWithSameId() {
addSubstationAndVoltageLevel();
addDanglingLines("dl", null, "dl", "code");
merge.merge(n1, n2);
assertNotNull(merge.getTieLine("dl"));
assertEquals("dl", merge.getTieLine("dl").getId());
assertEquals("dl_name", merge.getTieLine("dl").getOptionalName().orElse(null));
assertEquals("dl_name", merge.getTieLine("dl").getNameOrId());
PowsyblException e = assertThrows(PowsyblException.class, () -> merge.merge(n1, n2));
assertTrue(e.getMessage().contains("The following object(s) of type DanglingLineImpl exist(s) in both networks: [dl]"));
}

private void addSubstation(Network network, String substationId) {
Expand Down