diff --git a/cpp/src/bindings.cpp b/cpp/src/bindings.cpp index 566f08e7e..f644913d0 100644 --- a/cpp/src/bindings.cpp +++ b/cpp/src/bindings.cpp @@ -460,23 +460,23 @@ PYBIND11_MODULE(_pypowsybl, m) { m.def("run_loadflow_validation", &pypowsybl::runLoadFlowValidation, "Run a load flow validation", py::arg("network"), py::arg("validation_type"), py::arg("validation_parameters")); - py::class_(m, "LayoutParameters") - .def(py::init(&pypowsybl::createLayoutParameters)) - .def_readwrite("use_name", &pypowsybl::LayoutParameters::use_name) - .def_readwrite("center_name", &pypowsybl::LayoutParameters::center_name) - .def_readwrite("diagonal_label", &pypowsybl::LayoutParameters::diagonal_label) - .def_readwrite("topological_coloring", &pypowsybl::LayoutParameters::topological_coloring) - .def_readwrite("nodes_infos", &pypowsybl::LayoutParameters::nodes_infos) - .def_readwrite("component_library", &pypowsybl::LayoutParameters::component_library); + py::class_(m, "SldParameters") + .def(py::init(&pypowsybl::createSldParameters)) + .def_readwrite("use_name", &pypowsybl::SldParameters::use_name) + .def_readwrite("center_name", &pypowsybl::SldParameters::center_name) + .def_readwrite("diagonal_label", &pypowsybl::SldParameters::diagonal_label) + .def_readwrite("nodes_infos", &pypowsybl::SldParameters::nodes_infos) + .def_readwrite("topological_coloring", &pypowsybl::SldParameters::topological_coloring) + .def_readwrite("component_library", &pypowsybl::SldParameters::component_library); m.def("write_single_line_diagram_svg", &pypowsybl::writeSingleLineDiagramSvg, "Write single line diagram SVG", - py::arg("network"), py::arg("container_id"), py::arg("svg_file"), py::arg("metadata_file"), py::arg("layout_parameters")); + py::arg("network"), py::arg("container_id"), py::arg("svg_file"), py::arg("metadata_file"), py::arg("sld_parameters")); m.def("get_single_line_diagram_svg", &pypowsybl::getSingleLineDiagramSvg, "Get single line diagram SVG as a string", py::arg("network"), py::arg("container_id")); m.def("get_single_line_diagram_svg_and_metadata", &pypowsybl::getSingleLineDiagramSvgAndMetadata, "Get single line diagram SVG and its metadata as a list of strings", - py::arg("network"), py::arg("container_id"), py::arg("layout_parameters")); + py::arg("network"), py::arg("container_id"), py::arg("sld_parameters")); m.def("get_single_line_diagram_component_library_names", &pypowsybl::getSingleLineDiagramComponentLibraryNames, "Get supported component library providers for single line diagram"); diff --git a/cpp/src/pypowsybl-api.h b/cpp/src/pypowsybl-api.h index 5846e0d0b..4bdd9be06 100644 --- a/cpp/src/pypowsybl-api.h +++ b/cpp/src/pypowsybl-api.h @@ -274,14 +274,14 @@ typedef struct flow_decomposition_parameters_struct { int sensitivity_variable_batch_size; } flow_decomposition_parameters; -typedef struct layout_parameters_struct { +typedef struct sld_parameters_struct { unsigned char use_name; unsigned char center_name; unsigned char diagonal_label; - unsigned char topological_coloring; unsigned char nodes_infos; + unsigned char topological_coloring; char* component_library; -} layout_parameters; +} sld_parameters; typedef enum { ALPHA_BETA_LOAD = 0, diff --git a/cpp/src/pypowsybl.cpp b/cpp/src/pypowsybl.cpp index dcbd18cd3..0106a6958 100644 --- a/cpp/src/pypowsybl.cpp +++ b/cpp/src/pypowsybl.cpp @@ -765,7 +765,7 @@ SeriesArray* runLoadFlowValidation(const JavaHandle& network, validation_type va return new SeriesArray(callJava(::runLoadFlowValidation, network, validationType, c_validation_parameters.get())); } -void writeSingleLineDiagramSvg(const JavaHandle& network, const std::string& containerId, const std::string& svgFile, const std::string& metadataFile, const LayoutParameters& parameters) { +void writeSingleLineDiagramSvg(const JavaHandle& network, const std::string& containerId, const std::string& svgFile, const std::string& metadataFile, const SldParameters& parameters) { auto c_parameters = parameters.to_c_struct(); callJava(::writeSingleLineDiagramSvg, network, (char*) containerId.data(), (char*) svgFile.data(), (char*) metadataFile.data(), c_parameters.get()); } @@ -774,7 +774,7 @@ std::string getSingleLineDiagramSvg(const JavaHandle& network, const std::string return toString(callJava(::getSingleLineDiagramSvg, network, (char*) containerId.data())); } -std::vector getSingleLineDiagramSvgAndMetadata(const JavaHandle& network, const std::string& containerId, const LayoutParameters& parameters) { +std::vector getSingleLineDiagramSvgAndMetadata(const JavaHandle& network, const std::string& containerId, const SldParameters& parameters) { auto c_parameters = parameters.to_c_struct(); auto svgAndMetadataArrayPtr = callJava(::getSingleLineDiagramSvgAndMetadata, network, (char*) containerId.data(), c_parameters.get()); ToStringVector svgAndMetadata(svgAndMetadataArrayPtr); @@ -1240,40 +1240,40 @@ void closePypowsybl() { pypowsybl::callJava(::closePypowsybl); } -LayoutParameters::LayoutParameters(layout_parameters* src) { +SldParameters::SldParameters(sld_parameters* src) { use_name = (bool) src->use_name; center_name = (bool) src->center_name; diagonal_label = (bool) src->diagonal_label; - topological_coloring = (bool) src->topological_coloring; nodes_infos = (bool) src->nodes_infos; + topological_coloring = (bool) src->topological_coloring; component_library = toString(src->component_library); } -void LayoutParameters::layout_to_c_struct(layout_parameters& res) const { +void SldParameters::sld_to_c_struct(sld_parameters& res) const { res.use_name = (unsigned char) use_name; res.center_name = (unsigned char) center_name; res.diagonal_label = (unsigned char) diagonal_label; - res.topological_coloring = (unsigned char) topological_coloring; res.nodes_infos = (unsigned char) nodes_infos; + res.topological_coloring = (unsigned char) topological_coloring; res.component_library = copyStringToCharPtr(component_library); } -std::shared_ptr LayoutParameters::to_c_struct() const { - layout_parameters* res = new layout_parameters(); - layout_to_c_struct(*res); +std::shared_ptr SldParameters::to_c_struct() const { + sld_parameters* res = new sld_parameters(); + sld_to_c_struct(*res); //Memory has been allocated here on C side, we need to clean it up on C side (not java side) - return std::shared_ptr(res, [](layout_parameters* ptr){ + return std::shared_ptr(res, [](sld_parameters* ptr){ delete ptr; }); } -LayoutParameters* createLayoutParameters() { - layout_parameters* parameters_ptr = callJava(::createLayoutParameters); - auto parameters = std::shared_ptr(parameters_ptr, [](layout_parameters* ptr){ +SldParameters* createSldParameters() { + sld_parameters* parameters_ptr = callJava(::createSldParameters); + auto parameters = std::shared_ptr(parameters_ptr, [](sld_parameters* ptr){ //Memory has been allocated on java side, we need to clean it up on java side - callJava(::freeLayoutParameters, ptr); + callJava(::freeSldParameters, ptr); }); - return new LayoutParameters(parameters.get()); + return new SldParameters(parameters.get()); } void removeElementsModification(pypowsybl::JavaHandle network, const std::vector& connectableIds, dataframe* dataframe, remove_modification_type removeModificationType, bool throwException, JavaHandle* reporter) { diff --git a/cpp/src/pypowsybl.h b/cpp/src/pypowsybl.h index 13c077eb6..95967d123 100644 --- a/cpp/src/pypowsybl.h +++ b/cpp/src/pypowsybl.h @@ -263,17 +263,17 @@ class FlowDecompositionParameters { int sensitivity_variable_batch_size; }; -class LayoutParameters { +class SldParameters { public: - LayoutParameters(layout_parameters* src); - std::shared_ptr to_c_struct() const; - void layout_to_c_struct(layout_parameters& params) const; + SldParameters(sld_parameters* src); + std::shared_ptr to_c_struct() const; + void sld_to_c_struct(sld_parameters& params) const; bool use_name; bool center_name; bool diagonal_label; - bool topological_coloring; bool nodes_infos; + bool topological_coloring; std::string component_library; }; @@ -372,11 +372,11 @@ LoadFlowComponentResultArray* runLoadFlow(const JavaHandle& network, bool dc, co SeriesArray* runLoadFlowValidation(const JavaHandle& network, validation_type validationType, const LoadFlowValidationParameters& validationParameters); -void writeSingleLineDiagramSvg(const JavaHandle& network, const std::string& containerId, const std::string& svgFile, const std::string& metadataFile, const LayoutParameters& parameters); +void writeSingleLineDiagramSvg(const JavaHandle& network, const std::string& containerId, const std::string& svgFile, const std::string& metadataFile, const SldParameters& parameters); std::string getSingleLineDiagramSvg(const JavaHandle& network, const std::string& containerId); -std::vector getSingleLineDiagramSvgAndMetadata(const JavaHandle& network, const std::string& containerId, const LayoutParameters& parameters); +std::vector getSingleLineDiagramSvgAndMetadata(const JavaHandle& network, const std::string& containerId, const SldParameters& parameters); std::vector getSingleLineDiagramComponentLibraryNames(); @@ -541,7 +541,7 @@ void closePypowsybl(); void removeElementsModification(pypowsybl::JavaHandle network, const std::vector& connectableIds, dataframe* dataframe, remove_modification_type removeModificationType, bool throwException, JavaHandle* reporter); -LayoutParameters* createLayoutParameters(); +SldParameters* createSldParameters(); //=======dynamic modeling for dynawaltz package========== diff --git a/java/src/main/java/com/powsybl/python/commons/PyPowsyblApiHeader.java b/java/src/main/java/com/powsybl/python/commons/PyPowsyblApiHeader.java index b61eea681..a1d788847 100644 --- a/java/src/main/java/com/powsybl/python/commons/PyPowsyblApiHeader.java +++ b/java/src/main/java/com/powsybl/python/commons/PyPowsyblApiHeader.java @@ -920,8 +920,8 @@ public interface FlowDecompositionParametersPointer extends PointerBase { void setSensitivityVariableBatchSize(int sensitivityVariableBatchSize); } - @CStruct("layout_parameters") - public interface LayoutParametersPointer extends PointerBase { + @CStruct("sld_parameters") + public interface SldParametersPointer extends PointerBase { @CField("use_name") boolean isUseName(); @@ -941,18 +941,18 @@ public interface LayoutParametersPointer extends PointerBase { @CField("diagonal_label") void setDiagonalLabel(boolean diagonalLabel); - @CField("topological_coloring") - boolean isTopologicalColoring(); - - @CField("topological_coloring") - void setTopologicalColoring(boolean topologicalColoring); - @CField("nodes_infos") boolean isAddNodesInfos(); @CField("nodes_infos") void setAddNodesInfos(boolean addNodeInfos); + @CField("topological_coloring") + boolean isTopologicalColoring(); + + @CField("topological_coloring") + void setTopologicalColoring(boolean topologicalColoring); + @CField("component_library") CCharPointer getComponentLibrary(); diff --git a/java/src/main/java/com/powsybl/python/network/NetworkAreaDiagramUtil.java b/java/src/main/java/com/powsybl/python/network/NetworkAreaDiagramUtil.java index e9724427a..375318be7 100644 --- a/java/src/main/java/com/powsybl/python/network/NetworkAreaDiagramUtil.java +++ b/java/src/main/java/com/powsybl/python/network/NetworkAreaDiagramUtil.java @@ -42,11 +42,13 @@ static void writeSvg(Network network, List voltageLevelIds, int depth, W .setFixedWidth(800) .setFixedHeight(600) .setEdgeNameDisplayed(edgeNameDisplayed); + Predicate filter = !voltageLevelIds.isEmpty() ? getNominalVoltageFilter(network, voltageLevelIds, highNominalVoltageBound, lowNominalVoltageBound, depth) : VoltageLevelFilter.NO_FILTER; NadParameters nadParameters = new NadParameters() .setSvgParameters(svgParameters); + NetworkAreaDiagram.draw(network, writer, nadParameters, filter); } diff --git a/java/src/main/java/com/powsybl/python/network/NetworkCFunctions.java b/java/src/main/java/com/powsybl/python/network/NetworkCFunctions.java index 887b6bd12..0c2fafff5 100644 --- a/java/src/main/java/com/powsybl/python/network/NetworkCFunctions.java +++ b/java/src/main/java/com/powsybl/python/network/NetworkCFunctions.java @@ -29,14 +29,20 @@ import com.powsybl.dataframe.update.UpdatingDataframe; import com.powsybl.iidm.network.*; import com.powsybl.iidm.reducer.*; -import com.powsybl.python.commons.*; +import com.powsybl.python.commons.CTypeUtil; +import com.powsybl.python.commons.Directives; +import com.powsybl.python.commons.PyPowsyblApiHeader; +import com.powsybl.python.commons.Util; import com.powsybl.python.dataframe.CDoubleSeries; import com.powsybl.python.dataframe.CIntSeries; import com.powsybl.python.dataframe.CStringSeries; import com.powsybl.python.datasource.InMemoryZipFileDataSource; import com.powsybl.python.report.ReportCUtils; -import com.powsybl.sld.layout.LayoutParameters; -import com.powsybl.sld.svg.SvgParameters; +import com.powsybl.sld.SldParameters; +import com.powsybl.sld.library.ComponentLibrary; +import com.powsybl.sld.library.ConvergenceComponentLibrary; +import com.powsybl.sld.svg.styles.DefaultStyleProviderFactory; +import com.powsybl.sld.svg.styles.NominalVoltageStyleProviderFactory; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.graalvm.nativeimage.IsolateThread; @@ -835,81 +841,62 @@ public static boolean updateConnectableStatus(IsolateThread thread, ObjectHandle }); } - public static class LayoutParametersExt { - public final LayoutParameters layoutParameters; - public final SvgParameters svgParameters; - public final boolean topologicalColoring; - - public final String componentLibrary; - - public LayoutParametersExt() { - this(new LayoutParameters(), new SvgParameters(), true, "Convergence"); - } - - public LayoutParametersExt(LayoutParameters layoutParameters, SvgParameters svgParameters, boolean topologicalColoring, String componentLibrary) { - Objects.requireNonNull(layoutParameters); - this.layoutParameters = layoutParameters; - this.svgParameters = svgParameters; - this.svgParameters.setSvgWidthAndHeightAdded(true); - this.topologicalColoring = topologicalColoring; - this.componentLibrary = componentLibrary; - } - } - - public static void copyToCLayoutParameters(LayoutParametersExt parameters, LayoutParametersPointer cParameters) { - cParameters.setUseName(parameters.svgParameters.isUseName()); - cParameters.setCenterName(parameters.svgParameters.isLabelCentered()); - cParameters.setDiagonalLabel(parameters.svgParameters.isLabelDiagonal()); - cParameters.setTopologicalColoring(parameters.topologicalColoring); - cParameters.setAddNodesInfos(parameters.svgParameters.isAddNodesInfos()); - cParameters.setComponentLibrary(CTypeUtil.toCharPtr(parameters.componentLibrary)); + public static void copyToCSldParameters(SldParameters parameters, SldParametersPointer cParameters) { + cParameters.setUseName(parameters.getSvgParameters().isUseName()); + cParameters.setCenterName(parameters.getSvgParameters().isLabelCentered()); + cParameters.setDiagonalLabel(parameters.getSvgParameters().isLabelDiagonal()); + cParameters.setTopologicalColoring(parameters.getStyleProviderFactory() instanceof DefaultStyleProviderFactory); + cParameters.setAddNodesInfos(parameters.getSvgParameters().isAddNodesInfos()); + cParameters.setComponentLibrary(CTypeUtil.toCharPtr(parameters.getComponentLibrary().getName())); } - public static LayoutParametersPointer convertToLayoutParametersPointer(LayoutParametersExt parameters) { - LayoutParametersPointer paramsPtr = UnmanagedMemory.calloc(SizeOf.get(LayoutParametersPointer.class)); - copyToCLayoutParameters(parameters, paramsPtr); + public static SldParametersPointer convertToSldParametersPointer(SldParameters parameters) { + SldParametersPointer paramsPtr = UnmanagedMemory.calloc(SizeOf.get(SldParametersPointer.class)); + copyToCSldParameters(parameters, paramsPtr); return paramsPtr; } - @CEntryPoint(name = "createLayoutParameters") - public static LayoutParametersPointer createLayoutParameters(IsolateThread thread, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) { - return doCatch(exceptionHandlerPtr, () -> convertToLayoutParametersPointer(new LayoutParametersExt())); + @CEntryPoint(name = "createSldParameters") + public static SldParametersPointer createSldParameters(IsolateThread thread, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) { + return doCatch(exceptionHandlerPtr, () -> convertToSldParametersPointer(SingleLineDiagramUtil.createSldParameters())); } - public static void freeLayoutParametersPointer(LayoutParametersPointer layoutParametersPtr) { - UnmanagedMemory.free(layoutParametersPtr); + public static void freeSldParametersPointer(SldParametersPointer sldParametersPtr) { + UnmanagedMemory.free(sldParametersPtr); } - @CEntryPoint(name = "freeLayoutParameters") - public static void freeLayoutParameters(IsolateThread thread, LayoutParametersPointer layoutParametersPtr, + @CEntryPoint(name = "freeSldParameters") + public static void freeSldParameters(IsolateThread thread, SldParametersPointer sldParametersPtr, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) { doCatch(exceptionHandlerPtr, () -> { - freeLayoutParametersPointer(layoutParametersPtr); + freeSldParametersPointer(sldParametersPtr); }); } - public static LayoutParametersExt convertLayoutParameters(LayoutParametersPointer layoutParametersPtr) { - return new LayoutParametersExt(new LayoutParameters(), - new SvgParameters() - .setUseName(layoutParametersPtr.isUseName()) - .setLabelCentered(layoutParametersPtr.isCenterName()) - .setLabelDiagonal(layoutParametersPtr.isDiagonalLabel()) - .setAddNodesInfos(layoutParametersPtr.isAddNodesInfos()), - layoutParametersPtr.isTopologicalColoring(), - CTypeUtil.toString(layoutParametersPtr.getComponentLibrary())); + public static SldParameters convertSldParameters(SldParametersPointer sldParametersPtr) { + String componentLibraryName = CTypeUtil.toString(sldParametersPtr.getComponentLibrary()); + SldParameters sldParameters = SingleLineDiagramUtil.createSldParameters() + .setStyleProviderFactory(sldParametersPtr.isTopologicalColoring() ? new DefaultStyleProviderFactory() : new NominalVoltageStyleProviderFactory()) + .setComponentLibrary(ComponentLibrary.find(componentLibraryName).orElseGet(ConvergenceComponentLibrary::new)); + sldParameters.getSvgParameters() + .setUseName(sldParametersPtr.isUseName()) + .setLabelCentered(sldParametersPtr.isCenterName()) + .setLabelDiagonal(sldParametersPtr.isDiagonalLabel()) + .setAddNodesInfos(sldParametersPtr.isAddNodesInfos()); + return sldParameters; } @CEntryPoint(name = "writeSingleLineDiagramSvg") public static void writeSingleLineDiagramSvg(IsolateThread thread, ObjectHandle networkHandle, CCharPointer containerId, - CCharPointer svgFile, CCharPointer metadataFile, LayoutParametersPointer layoutParametersPtr, + CCharPointer svgFile, CCharPointer metadataFile, SldParametersPointer sldParametersPtr, ExceptionHandlerPointer exceptionHandlerPtr) { doCatch(exceptionHandlerPtr, () -> { Network network = ObjectHandles.getGlobal().get(networkHandle); String containerIdStr = CTypeUtil.toString(containerId); String svgFileStr = CTypeUtil.toString(svgFile); String metadataFileStr = metadataFile.isNonNull() ? CTypeUtil.toString(metadataFile) : null; - LayoutParametersExt layoutParametersExt = convertLayoutParameters(layoutParametersPtr); - SingleLineDiagramUtil.writeSvg(network, containerIdStr, svgFileStr, metadataFileStr, layoutParametersExt); + SldParameters sldParameters = convertSldParameters(sldParametersPtr); + SingleLineDiagramUtil.writeSvg(network, containerIdStr, svgFileStr, metadataFileStr, sldParameters); }); } @@ -926,12 +913,12 @@ public static CCharPointer getSingleLineDiagramSvg(IsolateThread thread, ObjectH @CEntryPoint(name = "getSingleLineDiagramSvgAndMetadata") public static ArrayPointer getSingleLineDiagramSvgAndMetadata(IsolateThread thread, ObjectHandle networkHandle, CCharPointer containerId, - LayoutParametersPointer layoutParametersPtr, ExceptionHandlerPointer exceptionHandlerPtr) { + SldParametersPointer sldParametersPtr, ExceptionHandlerPointer exceptionHandlerPtr) { return doCatch(exceptionHandlerPtr, () -> { Network network = ObjectHandles.getGlobal().get(networkHandle); String containerIdStr = CTypeUtil.toString(containerId); - LayoutParametersExt layoutParametersExt = convertLayoutParameters(layoutParametersPtr); - List svgAndMeta = SingleLineDiagramUtil.getSvgAndMetadata(network, containerIdStr, layoutParametersExt); + SldParameters sldParameters = convertSldParameters(sldParametersPtr); + List svgAndMeta = SingleLineDiagramUtil.getSvgAndMetadata(network, containerIdStr, sldParameters); return createCharPtrArray(svgAndMeta); }); } diff --git a/java/src/main/java/com/powsybl/python/network/SingleLineDiagramUtil.java b/java/src/main/java/com/powsybl/python/network/SingleLineDiagramUtil.java index 175a227c6..f5b4cd965 100644 --- a/java/src/main/java/com/powsybl/python/network/SingleLineDiagramUtil.java +++ b/java/src/main/java/com/powsybl/python/network/SingleLineDiagramUtil.java @@ -6,14 +6,10 @@ */ package com.powsybl.python.network; -import com.powsybl.commons.PowsyblException; import com.powsybl.iidm.network.Network; import com.powsybl.sld.SingleLineDiagram; import com.powsybl.sld.SldParameters; import com.powsybl.sld.library.ComponentLibrary; -import com.powsybl.sld.svg.styles.DefaultStyleProviderFactory; -import com.powsybl.sld.svg.styles.NominalVoltageStyleProviderFactory; -import com.powsybl.sld.svg.styles.StyleProviderFactory; import java.io.IOException; import java.io.StringWriter; @@ -32,10 +28,10 @@ public final class SingleLineDiagramUtil { private SingleLineDiagramUtil() { } - static void writeSvg(Network network, String containerId, String svgFile, String metadataFile, NetworkCFunctions.LayoutParametersExt layoutParametersExt) { + static void writeSvg(Network network, String containerId, String svgFile, String metadataFile, SldParameters sldParameters) { try (Writer writer = Files.newBufferedWriter(Paths.get(svgFile)); Writer metadataWriter = metadataFile.isEmpty() ? new StringWriter() : Files.newBufferedWriter(Paths.get(metadataFile))) { - writeSvg(network, containerId, writer, metadataWriter, layoutParametersExt); + writeSvg(network, containerId, writer, metadataWriter, sldParameters); } catch (IOException e) { throw new UncheckedIOException(e); } @@ -51,9 +47,9 @@ static String getSvg(Network network, String containerId) { } } - static List getSvgAndMetadata(Network network, String containerId, NetworkCFunctions.LayoutParametersExt layoutParametersExt) { + static List getSvgAndMetadata(Network network, String containerId, SldParameters sldParameters) { try (StringWriter writer = new StringWriter(); StringWriter writerMeta = new StringWriter()) { - writeSvg(network, containerId, writer, writerMeta, layoutParametersExt); + writeSvg(network, containerId, writer, writerMeta, sldParameters); writer.flush(); writerMeta.flush(); return List.of(writer.toString(), writerMeta.toString()); @@ -62,21 +58,17 @@ static List getSvgAndMetadata(Network network, String containerId, Netwo } } + static SldParameters createSldParameters() { + SldParameters sldParameters = new SldParameters(); + sldParameters.getSvgParameters().setSvgWidthAndHeightAdded(true); + return sldParameters; + } + static void writeSvg(Network network, String containerId, Writer writer) { - writeSvg(network, containerId, writer, new StringWriter(), new NetworkCFunctions.LayoutParametersExt()); + writeSvg(network, containerId, writer, new StringWriter(), createSldParameters()); } - static void writeSvg(Network network, String containerId, Writer writer, Writer metadataWriter, NetworkCFunctions.LayoutParametersExt layoutParametersExt) { - ComponentLibrary componentLibrary = ComponentLibrary.find(layoutParametersExt.componentLibrary) - .orElseThrow(() -> new PowsyblException("library with name " + layoutParametersExt.componentLibrary + - " was not found for Single Line Diagram component library")); - StyleProviderFactory styleProviderFactory = layoutParametersExt.topologicalColoring ? new DefaultStyleProviderFactory() - : new NominalVoltageStyleProviderFactory(); - SldParameters sldParameters = new SldParameters() - .setComponentLibrary(componentLibrary) - .setLayoutParameters(layoutParametersExt.layoutParameters) - .setSvgParameters(layoutParametersExt.svgParameters) - .setStyleProviderFactory(styleProviderFactory); + static void writeSvg(Network network, String containerId, Writer writer, Writer metadataWriter, SldParameters sldParameters) { SingleLineDiagram.draw(network, containerId, writer, metadataWriter, sldParameters); } diff --git a/java/src/test/java/com/powsybl/python/network/SingleLineDiagramUtilTest.java b/java/src/test/java/com/powsybl/python/network/SingleLineDiagramUtilTest.java index ade92e371..0ec8420ca 100644 --- a/java/src/test/java/com/powsybl/python/network/SingleLineDiagramUtilTest.java +++ b/java/src/test/java/com/powsybl/python/network/SingleLineDiagramUtilTest.java @@ -10,6 +10,7 @@ import com.powsybl.commons.test.TestUtil; import com.powsybl.iidm.network.Network; import com.powsybl.iidm.network.test.FourSubstationsNodeBreakerFactory; +import com.powsybl.sld.SldParameters; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -17,7 +18,6 @@ import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Objects; -import java.util.regex.Pattern; import static org.junit.jupiter.api.Assertions.*; @@ -26,38 +26,24 @@ */ class SingleLineDiagramUtilTest { - private static final Pattern SVG_FIX_PATTERN = Pattern.compile(">\\s*(<\\!\\[CDATA\\[.*?]]>)\\s* To remove when migrating to Java 17. - * - * See https://stackoverflow.com/questions/55853220/handling-change-in-newlines-by-xml-transformation-for-cdata-from-java-8-to-java - */ - private static String fixSvg(String svg) { - return SVG_FIX_PATTERN.matcher(Objects.requireNonNull(svg)).replaceAll(">$1 svgAndMeta = SingleLineDiagramUtil.getSvgAndMetadata(network, "S1VL1", layoutParametersExt); - assertEquals(TestUtil.normalizeLineSeparator(new String(ByteStreams.toByteArray(Objects.requireNonNull(SingleLineDiagramUtil.class.getResourceAsStream("/sld.svg"))), StandardCharsets.UTF_8)), - fixSvg(TestUtil.normalizeLineSeparator(svgAndMeta.get(0)))); - assertFalse(svgAndMeta.get(1).isEmpty()); - } - } + SldParameters sldParameters = SingleLineDiagramUtil.createSldParameters(); + List svgAndMeta = SingleLineDiagramUtil.getSvgAndMetadata(network, "S1VL1", sldParameters); + assertEquals(TestUtil.normalizeLineSeparator(new String(ByteStreams.toByteArray(Objects.requireNonNull(SingleLineDiagramUtil.class.getResourceAsStream("/sld.svg"))), StandardCharsets.UTF_8)), + TestUtil.normalizeLineSeparator(svgAndMeta.get(0))); + assertFalse(svgAndMeta.get(1).isEmpty()); + } } diff --git a/pypowsybl/_pypowsybl.pyi b/pypowsybl/_pypowsybl.pyi index b6d704772..5d4f564f6 100644 --- a/pypowsybl/_pypowsybl.pyi +++ b/pypowsybl/_pypowsybl.pyi @@ -180,12 +180,12 @@ class JavaHandle: class Dataframe: ... -class LayoutParameters: +class SldParameters: use_name: bool center_name: bool diagonal_label: bool - topological_coloring: bool nodes_infos: bool + topological_coloring: bool component_library: str def __init__(self) -> None: ... @@ -585,7 +585,7 @@ def get_pre_contingency_result(result: JavaHandle) -> PreContingencyResult: ... def get_network_elements_dataframe_metadata(element_type: ElementType) -> List[SeriesMetadata]: ... def get_network_elements_creation_dataframes_metadata(element_type: ElementType) -> List[List[SeriesMetadata]]: ... def get_single_line_diagram_svg(network: JavaHandle, container_id: str) -> str: ... -def get_single_line_diagram_svg_and_metadata(network: JavaHandle, container_id: str, parameters: LayoutParameters ) -> List[str]: ... +def get_single_line_diagram_svg_and_metadata(network: JavaHandle, container_id: str, parameters: SldParameters ) -> List[str]: ... def get_three_windings_transformer_results(result: JavaHandle) -> SeriesArray: ... def get_validation_level(network: JavaHandle) -> ValidationLevel: ... def get_variant_ids(network: JavaHandle) -> List[str]: ... @@ -628,7 +628,7 @@ def update_network_elements_with_series(network: JavaHandle, array: Dataframe, e def update_switch_position(arg0: JavaHandle, arg1: str, arg2: bool) -> bool: ... def validate(network: JavaHandle) -> ValidationLevel: ... def write_network_area_diagram_svg(network: JavaHandle, svg_file: str, voltage_level_ids: Union[str, List[str]], depth: int, high_nominal_voltage_bound: float, low_nominal_voltage_bound: float, edge_name_displayed: bool) -> None: ... -def write_single_line_diagram_svg(network: JavaHandle, container_id: str, svg_file: str, metadata_file: str, parameters: LayoutParameters) -> None: ... +def write_single_line_diagram_svg(network: JavaHandle, container_id: str, svg_file: str, metadata_file: str, parameters: SldParameters) -> None: ... def add_network_element_properties(network: JavaHandle, dataframe: Dataframe) -> None: ... def remove_network_element_properties(network: JavaHandle, ids: List[str], properties: List[str]) -> None: ... def get_network_extensions_dataframe_metadata(name: str, table_name: str) -> List[SeriesMetadata]: ... diff --git a/pypowsybl/network/__init__.py b/pypowsybl/network/__init__.py index 3b6c2f3e3..5dbda0a59 100644 --- a/pypowsybl/network/__init__.py +++ b/pypowsybl/network/__init__.py @@ -13,6 +13,7 @@ from .impl.svg import Svg from .impl.bus_breaker_topology import BusBreakerTopology from .impl.node_breaker_topology import NodeBreakerTopology +from .impl.sld_parameters import SldParameters from .impl.layout_parameters import LayoutParameters from .impl.network_creation_util import ( create_empty, diff --git a/pypowsybl/network/impl/layout_parameters.py b/pypowsybl/network/impl/layout_parameters.py index 389e13944..183a82d42 100644 --- a/pypowsybl/network/impl/layout_parameters.py +++ b/pypowsybl/network/impl/layout_parameters.py @@ -4,58 +4,17 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. # SPDX-License-Identifier: MPL-2.0 # -import pypowsybl._pypowsybl as _pp +import warnings +from .sld_parameters import SldParameters -class LayoutParameters: + +class LayoutParameters(SldParameters): """ - This class represents layout parameters for a single line diagram svg generation.""" + This class is only used for backward compatibility and represents sld parameters for a single line diagram svg + generation.""" def __init__(self, use_name: bool = False, center_name: bool = False, diagonal_label: bool = False, topological_coloring: bool = True, nodes_infos: bool = False, component_library: str = 'Convergence'): - self._use_name = use_name - self._center_name = center_name - self._diagonal_label = diagonal_label - self._topological_coloring = topological_coloring - self._nodes_infos = nodes_infos - self._component_library = component_library - - @property - def use_name(self) -> bool: - """Use names instead of ids in labels.""" - return self._use_name - - @property - def center_name(self) -> bool: - """Center labels.""" - return self._center_name - - @property - def diagonal_label(self) -> bool: - """Display diagonal labels.""" - return self._diagonal_label - - @property - def topological_coloring(self) -> bool: - """When False, coloring is based only on nominal voltage.""" - return self._topological_coloring - - @property - def nodes_infos(self) -> bool: - """When True, add infos about voltage and angle.""" - return self._nodes_infos - - @property - def component_library(self) -> str: - """name of the library used for component""" - return self._component_library - - def _to_c_parameters(self) -> _pp.LayoutParameters: - c_parameters = _pp.LayoutParameters() - c_parameters.use_name = self._use_name - c_parameters.center_name = self._center_name - c_parameters.diagonal_label = self._diagonal_label - c_parameters.topological_coloring = self._topological_coloring - c_parameters.nodes_infos = self._nodes_infos - c_parameters.component_library = self._component_library - return c_parameters + warnings.warn("LayoutParameters is deprecated, use SldParameters instead", DeprecationWarning) + super().__init__(use_name, center_name, diagonal_label, nodes_infos, topological_coloring, component_library) diff --git a/pypowsybl/network/impl/network.py b/pypowsybl/network/impl/network.py index d1e9f4bf1..e86432a35 100644 --- a/pypowsybl/network/impl/network.py +++ b/pypowsybl/network/impl/network.py @@ -39,7 +39,7 @@ from pypowsybl.report import Reporter from .bus_breaker_topology import BusBreakerTopology from .node_breaker_topology import NodeBreakerTopology -from .layout_parameters import LayoutParameters +from .sld_parameters import SldParameters from .svg import Svg from .util import create_data_frame_from_series_array, ParamsDict @@ -178,7 +178,7 @@ def reduce(self, v_min: float = 0, v_max: float = sys.float_info.max, ids: List[ _pp.reduce_network(self._handle, v_min, v_max, ids, vls, depths, with_dangling_lines) def write_single_line_diagram_svg(self, container_id: str, svg_file: PathOrStr, metadata_file: PathOrStr = None, - parameters: LayoutParameters = None) -> None: + parameters: SldParameters = None) -> None: """ Create a single line diagram in SVG format from a voltage level or a substation and write to a file. @@ -186,25 +186,30 @@ def write_single_line_diagram_svg(self, container_id: str, svg_file: PathOrStr, container_id: a voltage level id or a substation id svg_file: a svg file path metadata_file: a json metadata file path - parameters: layout parameters to adjust the rendering of the diagram + parameters: single-line diagram parameters to adjust the rendering of the diagram """ + svg_file = path_to_str(svg_file) - p = parameters._to_c_parameters() if parameters is not None else _pp.LayoutParameters() # pylint: disable=protected-access + + p = parameters._to_c_parameters() if parameters is not None else _pp.SldParameters() # pylint: disable=protected-access + _pp.write_single_line_diagram_svg(self._handle, container_id, svg_file, '' if metadata_file is None else path_to_str(metadata_file), p) - def get_single_line_diagram(self, container_id: str, parameters: LayoutParameters = None) -> Svg: + def get_single_line_diagram(self, container_id: str, parameters: SldParameters = None) -> Svg: """ Create a single line diagram from a voltage level or a substation. Args: container_id: a voltage level id or a substation id - parameters: layout parameters to adjust the rendering of the diagram + parameters: single-line diagram parameters to adjust the rendering of the diagram Returns: the single line diagram """ - p = parameters._to_c_parameters() if parameters is not None else _pp.LayoutParameters() # pylint: disable=protected-access + + p = parameters._to_c_parameters() if parameters is not None else _pp.SldParameters() # pylint: disable=protected-access + svg_and_metadata: List[str] = _pp.get_single_line_diagram_svg_and_metadata(self._handle, container_id, p) return Svg(svg_and_metadata[0], svg_and_metadata[1]) diff --git a/pypowsybl/network/impl/sld_parameters.py b/pypowsybl/network/impl/sld_parameters.py new file mode 100644 index 000000000..adaff9a79 --- /dev/null +++ b/pypowsybl/network/impl/sld_parameters.py @@ -0,0 +1,61 @@ +# 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 +# +import pypowsybl._pypowsybl as _pp + + +class SldParameters: + """ + This class represents sld parameters for a single line diagram svg generation.""" + + def __init__(self, use_name: bool = False, center_name: bool = False, diagonal_label: bool = False, + nodes_infos: bool = False, topological_coloring: bool = True, component_library: str = 'Convergence'): + self._use_name = use_name + self._center_name = center_name + self._diagonal_label = diagonal_label + self._nodes_infos = nodes_infos + self._topological_coloring = topological_coloring + self._component_library = component_library + + @property + def use_name(self) -> bool: + """Use names instead of ids in labels.""" + return self._use_name + + @property + def center_name(self) -> bool: + """Center labels.""" + return self._center_name + + @property + def diagonal_label(self) -> bool: + """Display diagonal labels.""" + return self._diagonal_label + + @property + def nodes_infos(self) -> bool: + """When True, add infos about voltage and angle.""" + return self._nodes_infos + + @property + def topological_coloring(self) -> bool: + """When False, coloring is based only on nominal voltage.""" + return self._topological_coloring + + @property + def component_library(self) -> str: + """name of the library used for component""" + return self._component_library + + def _to_c_parameters(self) -> _pp.SldParameters: + c_parameters = _pp.SldParameters() + c_parameters.use_name = self._use_name + c_parameters.center_name = self._center_name + c_parameters.diagonal_label = self._diagonal_label + c_parameters.topological_coloring = self._topological_coloring + c_parameters.nodes_infos = self._nodes_infos + c_parameters.component_library = self._component_library + return c_parameters diff --git a/tests/test_network.py b/tests/test_network.py index c06a97715..53149c1f6 100644 --- a/tests/test_network.py +++ b/tests/test_network.py @@ -25,7 +25,7 @@ import pypowsybl.report as rp import util from pypowsybl import PyPowsyblError -from pypowsybl.network import ValidationLevel, LayoutParameters +from pypowsybl.network import ValidationLevel, SldParameters, LayoutParameters TEST_DIR = pathlib.Path(__file__).parent DATA_DIR = TEST_DIR.parent / 'data' @@ -46,22 +46,26 @@ def test_load_network_from_string(): n = pp.network.load_from_string('simple-eu.uct', file_content) assert 1 == len(n.get_substations()) + def test_load_cgmes_zipped(): with open(DATA_DIR.joinpath('CGMES_Full.zip'), "rb") as fh: n = pp.network.load_from_binary_buffer(io.BytesIO(fh.read())) assert 3 == len(n.get_substations()) + def test_load_cgmes_two_zip(): with open(DATA_DIR.joinpath('CGMES_Partial.zip'), "rb") as cgmesPartial: with open(DATA_DIR.joinpath('Boundary.zip'), "rb") as boundary: n = pp.network.load_from_binary_buffers([io.BytesIO(cgmesPartial.read()), io.BytesIO(boundary.read())]) assert 3 == len(n.get_substations()) + def test_load_zipped_xiidm(): with open(DATA_DIR.joinpath('battery_xiidm.zip'), "rb") as fh: n = pp.network.load_from_binary_buffer(io.BytesIO(fh.read())) assert 2 == len(n.get_substations()) + def test_dump_to_string(): bat_path = TEST_DIR.joinpath('battery.xiidm') xml = bat_path.read_text() @@ -482,11 +486,14 @@ def test_ratio_tap_changer_steps_data_frame(): assert 0.8505666905244191 == steps.loc['NHV2_NLOAD']['rho'][0] assert 0.8505666905244191 == steps.loc[('NHV2_NLOAD', 0), 'rho'] pd.testing.assert_series_equal(steps.loc[('NHV2_NLOAD', 0)], - pd.Series(data={'rho': 0.850567, 'r': 0, 'x': 0, 'g': 0, 'b': 0}, name=('NHV2_NLOAD', 0)), check_dtype=False) + pd.Series(data={'rho': 0.850567, 'r': 0, 'x': 0, 'g': 0, 'b': 0}, + name=('NHV2_NLOAD', 0)), check_dtype=False) pd.testing.assert_series_equal(steps.loc[('NHV2_NLOAD', 1)], - pd.Series(data={'rho': 1.00067, 'r': 0, 'x': 0, 'g': 0, 'b': 0}, name=('NHV2_NLOAD', 1)), check_dtype=False) + pd.Series(data={'rho': 1.00067, 'r': 0, 'x': 0, 'g': 0, 'b': 0}, + name=('NHV2_NLOAD', 1)), check_dtype=False) pd.testing.assert_series_equal(steps.loc[('NHV2_NLOAD', 2)], - pd.Series(data={'rho': 1.15077, 'r': 0, 'x': 0, 'g': 0, 'b': 0}, name=('NHV2_NLOAD', 2)), check_dtype=False) + pd.Series(data={'rho': 1.15077, 'r': 0, 'x': 0, 'g': 0, 'b': 0}, + name=('NHV2_NLOAD', 2)), check_dtype=False) n.update_ratio_tap_changer_steps(pd.DataFrame( index=pd.MultiIndex.from_tuples([('NHV2_NLOAD', 0), ('NHV2_NLOAD', 1)], names=['id', 'position']), columns=['rho', 'r', 'x', 'g', 'b'], @@ -760,6 +767,22 @@ def test_variant(): assert 1 == len(n.get_variant_ids()) +def test_sld_parameters(): + parameters = SldParameters() + assert not parameters.use_name + assert not parameters.center_name + assert not parameters.diagonal_label + assert not parameters.nodes_infos + assert parameters.topological_coloring + parameters = SldParameters(use_name=True, center_name=True, diagonal_label=True, topological_coloring=False, + nodes_infos=True) + assert parameters.use_name + assert parameters.center_name + assert parameters.diagonal_label + assert parameters.nodes_infos + assert not parameters.topological_coloring + + def test_layout_parameters(): parameters = LayoutParameters() assert not parameters.use_name @@ -781,16 +804,28 @@ def test_sld_svg(): sld = n.get_single_line_diagram('S1VL1') assert re.search('.* 0 - sld1 = n.get_single_line_diagram('S1VL1', LayoutParameters(use_name=True, center_name=True, diagonal_label=True, - topological_coloring=False)) + sld1 = n.get_single_line_diagram('S1VL1', SldParameters(use_name=True, center_name=True, diagonal_label=True, + topological_coloring=False)) assert re.search('.* 0 - sld2 = n.get_single_line_diagram('S1VL1', LayoutParameters(use_name=True, center_name=True, diagonal_label=True, - topological_coloring=True, nodes_infos=True)) + sld2 = n.get_single_line_diagram('S1VL1', SldParameters(use_name=True, center_name=True, diagonal_label=True, + nodes_infos=True, topological_coloring=True)) assert re.search('.* 0 +def test_sld_svg_backward_compatibility(): + n = pp.network.create_four_substations_node_breaker_network() + sld = n.get_single_line_diagram('S1VL1', LayoutParameters(use_name=True, center_name=True, diagonal_label=True, + topological_coloring=False)) + assert re.search('.* 0 + sld1 = n.get_single_line_diagram('S1VL1', LayoutParameters(use_name=True, center_name=True, diagonal_label=True, + topological_coloring=True, nodes_infos=True)) + assert re.search('.* 0 + + def test_sld_nad(): n = pp.network.create_ieee14() sld = n.get_network_area_diagram() @@ -812,7 +847,8 @@ def test_sld_nad(): n.write_network_area_diagram_svg(test_svg, None) n.write_network_area_diagram_svg(test_svg, ['VL1']) n.write_network_area_diagram_svg(test_svg, ['VL1', 'VL2']) - n.write_network_area_diagram_svg(test_svg, high_nominal_voltage_bound=50, low_nominal_voltage_bound=10, depth=10) + n.write_network_area_diagram_svg(test_svg, high_nominal_voltage_bound=50, low_nominal_voltage_bound=10, + depth=10) n.write_network_area_diagram_svg(test_svg, low_nominal_voltage_bound=10, depth=10) n.write_network_area_diagram_svg(test_svg, high_nominal_voltage_bound=50, depth=10)