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

Import pypowsybl nominal voltage filter into powsybl-diagram #566

Merged
merged 17 commits into from
Dec 11, 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 @@ -9,6 +9,8 @@
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.*;
import com.powsybl.nad.utils.iidm.IidmUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.function.Predicate;
Expand All @@ -19,8 +21,12 @@
*/
public class VoltageLevelFilter implements Predicate<VoltageLevel> {

protected static final Logger LOGGER = LoggerFactory.getLogger(VoltageLevelFilter.class);

public static final Predicate<VoltageLevel> NO_FILTER = voltageLevel -> true;

private static final String UNKNOWN_VOLTAGE_LEVEL = "Unknown voltage level id '";

private final Set<VoltageLevel> voltageLevels;

public VoltageLevelFilter(Set<VoltageLevel> voltageLevels) {
Expand All @@ -40,43 +46,55 @@ public boolean test(VoltageLevel voltageLevel) {
return voltageLevels.contains(voltageLevel);
}

public static VoltageLevelFilter createVoltageLevelsFilter(Network network, List<String> voltageLevelIds) {
return createVoltageLevelsDepthFilter(network, voltageLevelIds, 0);
}

public static VoltageLevelFilter createVoltageLevelDepthFilter(Network network, String voltageLevelId, int depth) {
Objects.requireNonNull(network);
Objects.requireNonNull(voltageLevelId);
return createVoltageLevelsDepthFilter(network, List.of(voltageLevelId), depth);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, indeed, this was also duplicate code!

}

Set<VoltageLevel> voltageLevels = new HashSet<>();
VoltageLevel vl = network.getVoltageLevel(voltageLevelId);
if (vl == null) {
throw new PowsyblException("Unknown voltage level id '" + voltageLevelId + "'");
}
public static VoltageLevelFilter createVoltageLevelsDepthFilter(Network network, List<String> voltageLevelIds, int depth) {
return createVoltageLevelFilterWithPredicate(network, voltageLevelIds, depth, NO_FILTER);
}

Set<VoltageLevel> startingSet = new HashSet<>();
startingSet.add(vl);
traverseVoltageLevels(startingSet, depth, voltageLevels);
return new VoltageLevelFilter(voltageLevels);
public static VoltageLevelFilter createNominalVoltageLowerBoundFilter(Network network, List<String> voltageLevelIds, double nominalVoltageLowerBound, int depth) {
return createNominalVoltageFilter(network, voltageLevelIds, nominalVoltageLowerBound, Double.MAX_VALUE, depth);
}

public static VoltageLevelFilter createVoltageLevelsDepthFilter(Network network, List<String> voltageLevelIds, int depth) {
public static VoltageLevelFilter createNominalVoltageUpperBoundFilter(Network network, List<String> voltageLevelIds, double nominalVoltageUpperBound, int depth) {
return createNominalVoltageFilter(network, voltageLevelIds, 0, nominalVoltageUpperBound, depth);
}

public static VoltageLevelFilter createNominalVoltageFilter(Network network, List<String> voltageLevelIds,
double nominalVoltageLowerBound, double nominalVoltageUpperBound,
int depth) {
checkVoltageBoundValues(nominalVoltageLowerBound, nominalVoltageUpperBound);
Predicate<VoltageLevel> voltageLevelPredicate = voltageLevel -> voltageLevel.getNominalV() >= nominalVoltageLowerBound && voltageLevel.getNominalV() <= nominalVoltageUpperBound;

return createVoltageLevelFilterWithPredicate(network, voltageLevelIds, depth, voltageLevelPredicate);
}

public static VoltageLevelFilter createVoltageLevelFilterWithPredicate(Network network, List<String> voltageLevelIds, int depth, Predicate<VoltageLevel> voltageLevelPredicate) {
Objects.requireNonNull(network);
Objects.requireNonNull(voltageLevelIds);
Set<VoltageLevel> startingSet = new HashSet<>();

for (String voltageLevelId : voltageLevelIds) {
VoltageLevel vl = network.getVoltageLevel(voltageLevelId);
if (vl == null) {
throw new PowsyblException("Unknown voltage level id '" + voltageLevelId + "'");
throw new PowsyblException(UNKNOWN_VOLTAGE_LEVEL + voltageLevelId + "'");
}
if (!voltageLevelPredicate.test(vl)) {
LOGGER.warn("vl '{}' does not comply with the predicate", voltageLevelId);
}
startingSet.add(vl);
}

Set<VoltageLevel> voltageLevels = new HashSet<>();
traverseVoltageLevels(startingSet, depth, voltageLevels);
VoltageLevelFilter.traverseVoltageLevels(startingSet, depth, voltageLevels, voltageLevelPredicate);
return new VoltageLevelFilter(voltageLevels);
}

public static VoltageLevelFilter createVoltageLevelsFilter(Network network, List<String> voltageLevelIds) {
return createVoltageLevelsDepthFilter(network, voltageLevelIds, 0);
}

public static Collection<VoltageLevel> getNextDepthVoltageLevels(Network network, List<VoltageLevel> voltageLevels) {
List<String> voltageLevelIds = voltageLevels.stream().map(VoltageLevel::getId).collect(Collectors.toList());
VoltageLevelFilter voltageLevelFilter = createVoltageLevelsDepthFilter(network, voltageLevelIds, 1);
Expand All @@ -85,27 +103,38 @@ public static Collection<VoltageLevel> getNextDepthVoltageLevels(Network network
return voltageLevelSet;
}

private static void traverseVoltageLevels(Set<VoltageLevel> voltageLevelsDepth, int depth, Set<VoltageLevel> visitedVoltageLevels) {
private static void traverseVoltageLevels(Set<VoltageLevel> voltageLevelsDepth, int depth, Set<VoltageLevel> visitedVoltageLevels, Predicate<VoltageLevel> predicate) {
if (depth < 0) {
return;
}
Set<VoltageLevel> nextDepthVoltageLevels = new HashSet<>();
for (VoltageLevel vl : voltageLevelsDepth) {
if (!visitedVoltageLevels.contains(vl)) {
visitedVoltageLevels.add(vl);
vl.visitEquipments(new VlVisitor(nextDepthVoltageLevels, visitedVoltageLevels));
vl.visitEquipments(new VlVisitor(nextDepthVoltageLevels, visitedVoltageLevels, predicate));
}
}
traverseVoltageLevels(nextDepthVoltageLevels, depth - 1, visitedVoltageLevels);
traverseVoltageLevels(nextDepthVoltageLevels, depth - 1, visitedVoltageLevels, predicate);
}

private static void checkVoltageBoundValues(double nominalVoltageLowerBound, double nominalVoltageUpperBound) {
if (nominalVoltageLowerBound < 0 || nominalVoltageUpperBound < 0) {
throw new PowsyblException("Voltage bounds must be positive");
}
if (nominalVoltageLowerBound > nominalVoltageUpperBound) {
throw new PowsyblException("Low bound must be less than or equal to high bound");
}
}

private static class VlVisitor extends DefaultTopologyVisitor {
private final Set<VoltageLevel> nextDepthVoltageLevels;
private final Set<VoltageLevel> visitedVoltageLevels;
private final Predicate<VoltageLevel> voltageLevelPredicate;

public VlVisitor(Set<VoltageLevel> nextDepthVoltageLevels, Set<VoltageLevel> visitedVoltageLevels) {
public VlVisitor(Set<VoltageLevel> nextDepthVoltageLevels, Set<VoltageLevel> visitedVoltageLevels, Predicate<VoltageLevel> voltageLevelPredicate) {
this.nextDepthVoltageLevels = nextDepthVoltageLevels;
this.visitedVoltageLevels = visitedVoltageLevels;
this.voltageLevelPredicate = voltageLevelPredicate;
}

@Override
Expand Down Expand Up @@ -143,7 +172,7 @@ private void visitBranch(Branch<?> branch, Branch.Side side) {

private void visitTerminal(Terminal terminal) {
VoltageLevel voltageLevel = terminal.getVoltageLevel();
if (!visitedVoltageLevels.contains(voltageLevel)) {
if (!visitedVoltageLevels.contains(voltageLevel) && voltageLevelPredicate.test(voltageLevel)) {
nextDepthVoltageLevels.add(voltageLevel);
}
}
Expand All @@ -155,5 +184,4 @@ public void visitDanglingLine(DanglingLine danglingLine) {
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@
*/
package com.powsybl.nad;

import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.read.ListAppender;
import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
import com.powsybl.commons.PowsyblException;
import com.powsybl.diagram.test.Networks;
import com.powsybl.ieeecdf.converter.IeeeCdfNetworkFactory;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.test.*;
import com.powsybl.iidm.network.test.EurostagTutorialExample1Factory;
import com.powsybl.nad.build.iidm.VoltageLevelFilter;
import com.powsybl.nad.layout.LayoutParameters;
import com.powsybl.nad.svg.LabelProvider;
Expand All @@ -21,12 +26,14 @@
import com.powsybl.nad.svg.iidm.NominalVoltageStyleProvider;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.LoggerFactory;

import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.util.*;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static com.powsybl.nad.build.iidm.VoltageLevelFilter.NO_FILTER;
import static org.junit.jupiter.api.Assertions.*;

/**
* @author Thomas Adam {@literal <tadam at silicom.fr>}
Expand Down Expand Up @@ -62,7 +69,7 @@ void testDrawSvg() {
NadParameters nadParameters = new NadParameters()
.setSvgParameters(getSvgParameters())
.setStyleProviderFactory(this::getStyleProvider);
NetworkAreaDiagram.draw(network, svgFile, nadParameters, VoltageLevelFilter.NO_FILTER);
NetworkAreaDiagram.draw(network, svgFile, nadParameters, NO_FILTER);
assertEquals(toString("/dangling_line_connected.svg"), getContentFile(svgFile));
}

Expand All @@ -75,4 +82,69 @@ void testGetVisibleVoltageLevels() {
ids = NetworkAreaDiagram.getDisplayedVoltageLevels(network, List.of("VLHV1"), 2);
assertEquals("VLGEN, VLHV1, VLHV2, VLLOAD", String.join(", ", ids));
}

@Test
void testVoltageFilteredDiagramTwoBounds() {
Network network = IeeeCdfNetworkFactory.create14();
Path svgFileVoltageFilter = fileSystem.getPath("nad-test-voltage-filter.svg");
NetworkAreaDiagram.draw(network, svgFileVoltageFilter, new NadParameters(), VoltageLevelFilter.createNominalVoltageFilter(network, List.of("VL4"), 120, 180, 2));
assertEquals(toString("/IEEE_14_bus_voltage_filter1.svg"), getContentFile(svgFileVoltageFilter));
}

@Test
void testVoltageFilteredDiagramLowBound() {
Network network = IeeeCdfNetworkFactory.create14();
Path svgFileVoltageFilter = fileSystem.getPath("nad-test-voltage-filter.svg");
NetworkAreaDiagram.draw(network, svgFileVoltageFilter, new NadParameters(), VoltageLevelFilter.createNominalVoltageLowerBoundFilter(network, List.of("VL4"), 120, 2));
assertEquals(toString("/IEEE_14_bus_voltage_filter1.svg"), getContentFile(svgFileVoltageFilter));
}

@Test
void testVoltageFilteredDiagramHighBound() {
Network network = IeeeCdfNetworkFactory.create14();
Path svgFileVoltageFilter = fileSystem.getPath("nad-test-voltage-filter.svg");
NetworkAreaDiagram.draw(network, svgFileVoltageFilter, new NadParameters(), VoltageLevelFilter.createNominalVoltageUpperBoundFilter(network, List.of("VL4"), 180, 2));
assertEquals(toString("/IEEE_14_bus_voltage_filter2.svg"), getContentFile(svgFileVoltageFilter));
}

@Test
void testVoltageFilteredDiagramOutOfBound() {
ListAppender<ILoggingEvent> logWatcher = new ListAppender<>();
logWatcher.start();
((Logger) LoggerFactory.getLogger(VoltageLevelFilter.class)).addAppender(logWatcher);
Network network = IeeeCdfNetworkFactory.create14();
Path svgFileVoltageFilter = fileSystem.getPath("nad-test-voltage-filter.svg");
List<String> voltageLevelList = List.of("VL4");
VoltageLevelFilter voltageLevelFilter = VoltageLevelFilter.createNominalVoltageUpperBoundFilter(network, voltageLevelList, 130, 2);
NetworkAreaDiagram.draw(network, svgFileVoltageFilter, new NadParameters(), voltageLevelFilter);

List<ILoggingEvent> logsList = logWatcher.list;
assertEquals(1, logsList.size());
assertEquals("vl 'VL4' does not comply with the predicate", logsList.get(0).getFormattedMessage());
assertEquals(toString("/IEEE_14_bus_voltage_filter3.svg"), getContentFile(svgFileVoltageFilter));
}

@Test
void testVoltageFilteredDiagramNegativeBound() {
Network network = IeeeCdfNetworkFactory.create14();
List<String> voltageLevelList = List.of("VL4");
PowsyblException e = assertThrows(PowsyblException.class, () -> VoltageLevelFilter.createNominalVoltageFilter(network, voltageLevelList, -100, 180, 2));
assertTrue(e.getMessage().contains("Voltage bounds must be positive"));
}

@Test
void testVoltageFilteredDiagramInconsistentBounds() {
Network network = IeeeCdfNetworkFactory.create14();
List<String> voltageLevelList = List.of("VL4");
PowsyblException e = assertThrows(PowsyblException.class, () -> VoltageLevelFilter.createNominalVoltageFilter(network, voltageLevelList, 180, 90, 2));
assertTrue(e.getMessage().contains("Low bound must be less than or equal to high bound"));
}

@Test
void testVoltageFilteredDiagramUnexistingVoltageLevel() {
Network network = IeeeCdfNetworkFactory.create14();
List<String> voltageLevelList = List.of("VL456");
PowsyblException e = assertThrows(PowsyblException.class, () -> VoltageLevelFilter.createNominalVoltageUpperBoundFilter(network, voltageLevelList, 90, 2));
assertTrue(e.getMessage().contains("Unknown voltage level id 'VL456'"));
}
}
Loading