diff --git a/cpp/src/bindings.cpp b/cpp/src/bindings.cpp index 6b83c94b84..e8eec3e87a 100644 --- a/cpp/src/bindings.cpp +++ b/cpp/src/bindings.cpp @@ -234,6 +234,7 @@ PYBIND11_MODULE(_pypowsybl, m) { py::enum_(m, "ElementType") .value("BUS", element_type::BUS) + .value("BUS_FROM_BUS_BREAKER_VIEW", element_type::BUS_FROM_BUS_BREAKER_VIEW) .value("LINE", element_type::LINE) .value("TWO_WINDINGS_TRANSFORMER", element_type::TWO_WINDINGS_TRANSFORMER) .value("THREE_WINDINGS_TRANSFORMER", element_type::THREE_WINDINGS_TRANSFORMER) diff --git a/cpp/src/pypowsybl-api.h b/cpp/src/pypowsybl-api.h index a23a820fb1..41ed4da826 100644 --- a/cpp/src/pypowsybl-api.h +++ b/cpp/src/pypowsybl-api.h @@ -134,6 +134,7 @@ typedef struct operator_strategy_result_struct { typedef enum { BUS = 0, + BUS_FROM_BUS_BREAKER_VIEW, LINE, TWO_WINDINGS_TRANSFORMER, THREE_WINDINGS_TRANSFORMER, diff --git a/docs/user_guide/network.rst b/docs/user_guide/network.rst index fa8e13ddd3..e66548b64c 100644 --- a/docs/user_guide/network.rst +++ b/docs/user_guide/network.rst @@ -100,7 +100,8 @@ Reading network elements data All network elements data can be read as :class:`DataFrames `. Supported elements are: - - buses + - buses (from bus view) + - buses from bus/breaker view - lines - 2 windings transformers - 3 windings transformers diff --git a/java/src/main/java/com/powsybl/dataframe/DataframeElementType.java b/java/src/main/java/com/powsybl/dataframe/DataframeElementType.java index 0477c8c2e2..a524349987 100644 --- a/java/src/main/java/com/powsybl/dataframe/DataframeElementType.java +++ b/java/src/main/java/com/powsybl/dataframe/DataframeElementType.java @@ -11,6 +11,7 @@ */ public enum DataframeElementType { BUS, + BUS_FROM_BUS_BREAKER_VIEW, LINE, TWO_WINDINGS_TRANSFORMER, THREE_WINDINGS_TRANSFORMER, diff --git a/java/src/main/java/com/powsybl/dataframe/network/NetworkDataframes.java b/java/src/main/java/com/powsybl/dataframe/network/NetworkDataframes.java index 13a263d770..08b06078f2 100644 --- a/java/src/main/java/com/powsybl/dataframe/network/NetworkDataframes.java +++ b/java/src/main/java/com/powsybl/dataframe/network/NetworkDataframes.java @@ -51,7 +51,8 @@ public static NetworkDataframeMapper getDataframeMapper(DataframeElementType typ private static Map createMappers() { Map mappers = new EnumMap<>(DataframeElementType.class); mappers.put(DataframeElementType.SUB_NETWORK, subNetworks()); - mappers.put(DataframeElementType.BUS, buses()); + mappers.put(DataframeElementType.BUS, buses(false)); + mappers.put(DataframeElementType.BUS_FROM_BUS_BREAKER_VIEW, buses(true)); mappers.put(DataframeElementType.LINE, lines()); mappers.put(DataframeElementType.TWO_WINDINGS_TRANSFORMER, twoWindingTransformers()); mappers.put(DataframeElementType.THREE_WINDINGS_TRANSFORMER, threeWindingTransformers()); @@ -299,8 +300,8 @@ private static NetworkDataframeMapper subNetworks() { .build(); } - static NetworkDataframeMapper buses() { - return NetworkDataframeMapperBuilder.ofStream(n -> n.getBusView().getBusStream(), + static NetworkDataframeMapper buses(boolean busBreakerView) { + return NetworkDataframeMapperBuilder.ofStream(n -> busBreakerView ? n.getBusBreakerView().getBusStream() : n.getBusView().getBusStream(), getOrThrow((b, id) -> b.getBusView().getBus(id), "Bus")) .stringsIndex("id", Bus::getId) .strings("name", b -> b.getOptionalName().orElse("")) 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 e428da15a2..fec8ecbe79 100644 --- a/java/src/main/java/com/powsybl/python/commons/PyPowsyblApiHeader.java +++ b/java/src/main/java/com/powsybl/python/commons/PyPowsyblApiHeader.java @@ -585,6 +585,7 @@ public interface OperatorStrategyResultPointer extends PointerBase { @CEnum("element_type") public enum ElementType { BUS, + BUS_FROM_BUS_BREAKER_VIEW, LINE, TWO_WINDINGS_TRANSFORMER, THREE_WINDINGS_TRANSFORMER, diff --git a/java/src/main/java/com/powsybl/python/commons/Util.java b/java/src/main/java/com/powsybl/python/commons/Util.java index 5e4ba8ea1f..9c49536028 100644 --- a/java/src/main/java/com/powsybl/python/commons/Util.java +++ b/java/src/main/java/com/powsybl/python/commons/Util.java @@ -178,6 +178,7 @@ public static int convert(SeriesDataType type) { public static PyPowsyblApiHeader.ElementType convert(DataframeElementType type) { return switch (type) { case BUS -> PyPowsyblApiHeader.ElementType.BUS; + case BUS_FROM_BUS_BREAKER_VIEW -> PyPowsyblApiHeader.ElementType.BUS_FROM_BUS_BREAKER_VIEW; case LINE -> PyPowsyblApiHeader.ElementType.LINE; case TWO_WINDINGS_TRANSFORMER -> PyPowsyblApiHeader.ElementType.TWO_WINDINGS_TRANSFORMER; case THREE_WINDINGS_TRANSFORMER -> PyPowsyblApiHeader.ElementType.THREE_WINDINGS_TRANSFORMER; @@ -217,6 +218,7 @@ public static PyPowsyblApiHeader.ElementType convert(DataframeElementType type) public static DataframeElementType convert(PyPowsyblApiHeader.ElementType type) { return switch (type) { case BUS -> DataframeElementType.BUS; + case BUS_FROM_BUS_BREAKER_VIEW -> DataframeElementType.BUS_FROM_BUS_BREAKER_VIEW; case LINE -> DataframeElementType.LINE; case TWO_WINDINGS_TRANSFORMER -> DataframeElementType.TWO_WINDINGS_TRANSFORMER; case THREE_WINDINGS_TRANSFORMER -> DataframeElementType.THREE_WINDINGS_TRANSFORMER; diff --git a/pypowsybl/_pypowsybl.pyi b/pypowsybl/_pypowsybl.pyi index cd0e277976..6986e60ff2 100644 --- a/pypowsybl/_pypowsybl.pyi +++ b/pypowsybl/_pypowsybl.pyi @@ -140,6 +140,7 @@ class ElementType: BATTERY: ClassVar[ElementType] = ... BRANCH: ClassVar[ElementType] = ... BUS: ClassVar[ElementType] = ... + BUS_FROM_BUS_BREAKER_VIEW: ClassVar[ElementType] = ... BUSBAR_SECTION: ClassVar[ElementType] = ... DANGLING_LINE: ClassVar[ElementType] = ... TIE_LINE: ClassVar[ElementType] = ... diff --git a/pypowsybl/network/impl/network.py b/pypowsybl/network/impl/network.py index 244bd86e8c..875d340abd 100644 --- a/pypowsybl/network/impl/network.py +++ b/pypowsybl/network/impl/network.py @@ -486,7 +486,7 @@ def detach(self) -> None: def get_buses(self, all_attributes: bool = False, attributes: List[str] = None, **kwargs: ArrayLike) -> DataFrame: r""" - Get a dataframe of buses. + Get a dataframe of buses from the bus view. Args: all_attributes: flag for including all attributes in the dataframe, default is false @@ -495,7 +495,7 @@ def get_buses(self, all_attributes: bool = False, attributes: List[str] = None, kwargs: the data to be selected, as named arguments. Returns: - A dataframe of buses. + A dataframe of buses from the bus view Notes: The resulting dataframe, depending on the parameters, will include the following columns: @@ -566,6 +566,14 @@ def get_buses(self, all_attributes: bool = False, attributes: List[str] = None, """ return self.get_elements(ElementType.BUS, all_attributes, attributes, **kwargs) + def get_bus_breaker_view_buses(self, all_attributes: bool = False, attributes: List[str] = None, + **kwargs: ArrayLike) -> DataFrame: + r""" + Get a dataframe of buses from the bus/breaker view. + See :meth:`get_buses` for documentation as attributes are the same. + """ + return self.get_elements(ElementType.BUS_FROM_BUS_BREAKER_VIEW, all_attributes, attributes, **kwargs) + def get_generators(self, all_attributes: bool = False, attributes: List[str] = None, **kwargs: ArrayLike) -> DataFrame: r""" diff --git a/tests/test_network.py b/tests/test_network.py index 508a731488..97b23a678b 100644 --- a/tests/test_network.py +++ b/tests/test_network.py @@ -1383,6 +1383,20 @@ def test_bus_breaker_view(): pd.testing.assert_frame_equal(expected_elements, elements, check_dtype=False) +def test_bus_breaker_view_buses(): + n = pp.network.create_eurostag_tutorial_example1_network() + buses = n.get_bus_breaker_view_buses() + expected_buses = pd.DataFrame( + index=pd.Series(name='id', data=['NGEN', 'NHV1', 'NHV2', 'NLOAD']), + columns=['name', 'v_mag', 'v_angle', 'connected_component', 'synchronous_component', + 'voltage_level_id'], + data=[['', NaN, NaN, 0, 0, 'VLGEN'], + ['', 380, NaN, 0, 0, 'VLHV1'], + ['', 380, NaN, 0, 0, 'VLHV2'], + ['', NaN, NaN, 0, 0, 'VLLOAD']]) + pd.testing.assert_frame_equal(expected_buses, buses, check_dtype=False) + + def test_bb_topology_with_no_bus_view_bus_does_not_throw(): n = pp.network.create_empty() n.create_substations(id='S')