From b30c9dad99102044692fee8162e16a467c4369a3 Mon Sep 17 00:00:00 2001 From: Kannan Date: Mon, 10 Aug 2026 18:08:29 +0200 Subject: [PATCH 1/2] Fix PowerFactory controller connection metadata --- .../to_gdf/power_factory_extractor.py | 23 +++++++++++++++---- tests/power_factory/pf_converter_test.py | 17 ++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/epowcore/power_factory/to_gdf/power_factory_extractor.py b/epowcore/power_factory/to_gdf/power_factory_extractor.py index fc1fac4..6ddb978 100644 --- a/epowcore/power_factory/to_gdf/power_factory_extractor.py +++ b/epowcore/power_factory/to_gdf/power_factory_extractor.py @@ -281,7 +281,7 @@ def extract_switches(self) -> None: self.uid += 1 self._component_dict[pf_switch] = switch self.graph.add_node(pf_switch) - + def extract_fuses(self) -> None: """Extract the PowerFactory fuses to the data format. Currently represented as a switch for the gdf""" pf_fuses = self.app.GetCalcRelevantObjects("RelFuse") @@ -322,7 +322,12 @@ def select_pss_type(self, generator: Any) -> None: self._component_dict[pss] = generic_pss self.graph.add_node(pss) # Create edge with the appropriate generator - self.graph.add_edge(pss, generator) + self.graph.edges[pss, generator].update( + { + generic_pss.uid: generic_pss.connector_names.copy(), + self._component_dict[generator].uid: [], + } + ) def select_avr_type(self, generator: Any) -> None: """Selects one of the currently supported Exciter to extract""" @@ -347,7 +352,12 @@ def select_avr_type(self, generator: Any) -> None: self._component_dict[avr] = generic_avr self.graph.add_node(avr) # Create edge with the appropriate generator - self.graph.add_edge(avr, generator) + self.graph.edges[avr, generator].update( + { + generic_avr.uid: generic_avr.connector_names.copy(), + self._component_dict[generator].uid: [], + } + ) def select_gov_type(self, generator: Any) -> None: """Selects one of the currently supported Governor to extract""" @@ -381,7 +391,12 @@ def select_gov_type(self, generator: Any) -> None: self._component_dict[gov] = generic_gov self.graph.add_node(gov) # Create edge with the appropriate generator - self.graph.add_edge(gov, generator) + self.graph.edges[gov, generator].update( + { + generic_gov.uid: generic_gov.connector_names.copy(), + self._component_dict[generator].uid: [], + } + ) def set_core_model_graph(self) -> None: """This creates the graph for the GenericCoreModel""" diff --git a/tests/power_factory/pf_converter_test.py b/tests/power_factory/pf_converter_test.py index ad52eaf..b856a7d 100644 --- a/tests/power_factory/pf_converter_test.py +++ b/tests/power_factory/pf_converter_test.py @@ -1,4 +1,8 @@ import unittest + +from epowcore.gdf.exciters.exciter import Exciter +from epowcore.gdf.governors.governor import Governor +from epowcore.gdf.power_system_stabilizers.power_system_stabilizer import PowerSystemStabilizer from epowcore.gdf.transformers.two_winding_transformer import TwoWindingTransformer from epowcore.power_factory.power_factory_converter import PFModel, PowerFactoryConverter @@ -10,15 +14,19 @@ def test_minimal_conversion_no_errors(self) -> None: """Test if the CoreModel extraction from the Minimal PF model throws errors.""" converter = PowerFactoryConverter() core_model = converter.to_gdf(PFModel("Minimal", "Base", 50.0)) + self.assertEqual(len(core_model.graph.nodes), 8) self.assertEqual(len(core_model.graph.edges), 7) + two_winding_id = core_model.type_list(TwoWindingTransformer)[0].uid + self.assertTrue( any( two_winding_id in x[2] and x[2][two_winding_id] == ["HV"] for x in core_model.graph.edges.data() ) ) + self.assertTrue( any( two_winding_id in x[2] and x[2][two_winding_id] == ["LV"] @@ -26,6 +34,15 @@ def test_minimal_conversion_no_errors(self) -> None: ) ) + for controller_type in (Exciter, Governor, PowerSystemStabilizer): + controller = core_model.type_list(controller_type)[0] + self.assertTrue( + any( + controller.uid in edge_data and edge_data[controller.uid] == ["In", "Out"] + for _, _, edge_data in core_model.graph.edges.data() + ) + ) + if __name__ == "__main__": unittest.main() From 88da1a0f6088ba3d9219f7bd6b84e33ce11b4efa Mon Sep 17 00:00:00 2001 From: Kannan Date: Fri, 14 Aug 2026 13:13:58 +0200 Subject: [PATCH 2/2] Fix missing PowerFactory controller graph edges --- epowcore/power_factory/to_gdf/power_factory_extractor.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/epowcore/power_factory/to_gdf/power_factory_extractor.py b/epowcore/power_factory/to_gdf/power_factory_extractor.py index 6ddb978..241fd0d 100644 --- a/epowcore/power_factory/to_gdf/power_factory_extractor.py +++ b/epowcore/power_factory/to_gdf/power_factory_extractor.py @@ -322,6 +322,7 @@ def select_pss_type(self, generator: Any) -> None: self._component_dict[pss] = generic_pss self.graph.add_node(pss) # Create edge with the appropriate generator + self.graph.add_edge(pss, generator) self.graph.edges[pss, generator].update( { generic_pss.uid: generic_pss.connector_names.copy(), @@ -352,6 +353,7 @@ def select_avr_type(self, generator: Any) -> None: self._component_dict[avr] = generic_avr self.graph.add_node(avr) # Create edge with the appropriate generator + self.graph.add_edge(avr, generator) self.graph.edges[avr, generator].update( { generic_avr.uid: generic_avr.connector_names.copy(), @@ -391,6 +393,7 @@ def select_gov_type(self, generator: Any) -> None: self._component_dict[gov] = generic_gov self.graph.add_node(gov) # Create edge with the appropriate generator + self.graph.add_edge(gov, generator) self.graph.edges[gov, generator].update( { generic_gov.uid: generic_gov.connector_names.copy(),