From c215a43f19b2727e41a1cdad74d11c0c7d3e30ad Mon Sep 17 00:00:00 2001 From: Zhen Wang Date: Wed, 3 Apr 2024 14:48:17 +0200 Subject: [PATCH 1/6] Add the .yml file and find measured terminal type function. Signed-off-by: Zhen Wang --- .../functions/_functions.py | 36 +++++++++++++++++-- src/power_grid_model_io/utils/auto_id.py | 2 +- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/power_grid_model_io/functions/_functions.py b/src/power_grid_model_io/functions/_functions.py index 765636e8..6ffe4c8a 100644 --- a/src/power_grid_model_io/functions/_functions.py +++ b/src/power_grid_model_io/functions/_functions.py @@ -11,7 +11,7 @@ import numpy as np import structlog from power_grid_model import WindingType - +from power_grid_model import MeasuredTerminalType T = TypeVar("T") _LOG = structlog.get_logger(__file__) @@ -24,13 +24,27 @@ "ZN": WindingType.zigzag_n, } +MEASURED_TERMINAL_TYPE_MAP = { + "transformer_from": MeasuredTerminalType.branch_from, + "transformer_to": MeasuredTerminalType.branch_to, + "cable_from": MeasuredTerminalType.branch_from, + "cable_to": MeasuredTerminalType.branch_to, + "transformer_load_to": MeasuredTerminalType.branch_to, + "load_to": MeasuredTerminalType.branch_to, + "earthing_transformer_to": MeasuredTerminalType.branch_to, + "transformer3_1": MeasuredTerminalType.branch3_1, + "transformer3_2": MeasuredTerminalType.branch3_2, + "transformer3_3": MeasuredTerminalType.branch3_3, +} + + def has_value(value: Any) -> bool: """ Return True if the value is not None, NaN or empty string. """ if value is None: - return False + return False if isinstance(value, float): return not np.isnan(value) return value != "" @@ -104,3 +118,21 @@ def both_zeros_to_nan(value: float, other_value: float) -> float: _LOG.warning("0 replaced to nan") return float("nan") return value + +def find_terminal_type(**kwargs) -> MeasuredTerminalType: + """ + Return 'branch_from' if any argument contains 'from' in its name. + Return 'branch_to' if any argument contains 'to' in its name. + Return the name of the first argument that evaluates to True otherwise. + + Parameters: + - args: Variable number of input values. + + Returns: + - String representation based on the conditions mentioned above. + """ + for key, id in kwargs.items(): + if id is not None: + return MEASURED_TERMINAL_TYPE_MAP[key] + _LOG.warning("No proper measured terminal type is found!") + return float("nan") \ No newline at end of file diff --git a/src/power_grid_model_io/utils/auto_id.py b/src/power_grid_model_io/utils/auto_id.py index 756cb34c..dd20d221 100644 --- a/src/power_grid_model_io/utils/auto_id.py +++ b/src/power_grid_model_io/utils/auto_id.py @@ -119,4 +119,4 @@ def __getitem__(self, idx: int) -> Any: Returns: The original item """ - return self._items[idx] + return getattr(self._items[idx], None) From daa26895e58613a775dcb13af93f35b806da20e3 Mon Sep 17 00:00:00 2001 From: Zhen Wang Date: Wed, 3 Apr 2024 16:04:50 +0200 Subject: [PATCH 2/6] Cover all components for measurement field. Signed-off-by: Zhen Wang --- .../functions/_functions.py | 23 +- tests/data/vision/vision_9_7_en.yaml | 1153 +++++++++++++++++ 2 files changed, 1170 insertions(+), 6 deletions(-) create mode 100644 tests/data/vision/vision_9_7_en.yaml diff --git a/src/power_grid_model_io/functions/_functions.py b/src/power_grid_model_io/functions/_functions.py index 6ffe4c8a..14a4e411 100644 --- a/src/power_grid_model_io/functions/_functions.py +++ b/src/power_grid_model_io/functions/_functions.py @@ -25,16 +25,27 @@ } MEASURED_TERMINAL_TYPE_MAP = { - "transformer_from": MeasuredTerminalType.branch_from, - "transformer_to": MeasuredTerminalType.branch_to, "cable_from": MeasuredTerminalType.branch_from, "cable_to": MeasuredTerminalType.branch_to, - "transformer_load_to": MeasuredTerminalType.branch_to, - "load_to": MeasuredTerminalType.branch_to, - "earthing_transformer_to": MeasuredTerminalType.branch_to, + "line_from": MeasuredTerminalType.branch_from, + "line_to": MeasuredTerminalType.branch_to, + "reactance_coil_from": MeasuredTerminalType.branch_from, + "reactance_coil_to": MeasuredTerminalType.branch_to, + "special_transformer_from": MeasuredTerminalType.branch_from, + "special_transformer_to": MeasuredTerminalType.branch_to, + "transformer_from": MeasuredTerminalType.branch_from, + "transformer_to": MeasuredTerminalType.branch_to, + "transformer_load": MeasuredTerminalType.branch_to, + "earthing_transformer": MeasuredTerminalType.branch_to, "transformer3_1": MeasuredTerminalType.branch3_1, "transformer3_2": MeasuredTerminalType.branch3_2, "transformer3_3": MeasuredTerminalType.branch3_3, + "source": MeasuredTerminalType.source, + "shunt_capacitor": MeasuredTerminalType.shunt, + "shunt_reactor": MeasuredTerminalType.shunt, + "pv": MeasuredTerminalType.generator, + "wind_turbine": MeasuredTerminalType.generator, + "load": MeasuredTerminalType.load, } @@ -134,5 +145,5 @@ def find_terminal_type(**kwargs) -> MeasuredTerminalType: for key, id in kwargs.items(): if id is not None: return MEASURED_TERMINAL_TYPE_MAP[key] - _LOG.warning("No proper measured terminal type is found!") + _LOG.warning("No measured terminal type is found!") return float("nan") \ No newline at end of file diff --git a/tests/data/vision/vision_9_7_en.yaml b/tests/data/vision/vision_9_7_en.yaml new file mode 100644 index 00000000..5da2297a --- /dev/null +++ b/tests/data/vision/vision_9_7_en.yaml @@ -0,0 +1,1153 @@ +# SPDX-FileCopyrightText: Contributors to the Power Grid Model project +# +# SPDX-License-Identifier: MPL-2.0 +--- +id_reference: + nodes_table: Nodes + number: Number + node_number: Node.Number + sub_number: Subnumber +grid: + Nodes: + node: + id: + auto_id: + key: Number + u_rated: Unom + extra: + - ID + - Name + Cables: + line: + id: + auto_id: + key: Number + from_node: + auto_id: + table: Nodes + key: + Number: From.Number + from_status: From.Switch state + to_node: + auto_id: + table: Nodes + key: + Number: To.Number + to_status: To.Switch state + r1: R + x1: X + c1: C + tan1: 0 + r0: + power_grid_model_io.functions.both_zeros_to_nan: + value: R0 + other_value: X0 + x0: + power_grid_model_io.functions.both_zeros_to_nan: + value: X0 + other_value: R0 + c0: C0 + tan0: 0 + i_n: Inom' + extra: + - ID + - Name + Lines: + line: + id: + auto_id: + key: Number + from_node: + auto_id: + table: Nodes + key: + Number: From.Number + from_status: From.Switch state + to_node: + auto_id: + table: Nodes + key: + Number: To.Number + to_status: To.Switch state + r1: R + x1: X + c1: C + tan1: 0 + r0: + power_grid_model_io.functions.both_zeros_to_nan: + value: R0 + other_value: X0 + x0: + power_grid_model_io.functions.both_zeros_to_nan: + value: X0 + other_value: R0 + c0: C0 + tan0: 0 + i_n: Inom' + extra: + - ID + - Name + Links: + link: + id: + auto_id: + key: Number + from_node: + auto_id: + table: Nodes + key: + Number: From.Number + from_status: From.Switch state + to_node: + auto_id: + table: Nodes + key: + Number: To.Number + to_status: To.Switch state + extra: + - ID + - Name + Reactance coils: + line: + id: + auto_id: + key: Number + from_node: + auto_id: + table: Nodes + key: + Number: From.Number + from_status: From.Switch state + to_node: + auto_id: + table: Nodes + key: + Number: To.Number + to_status: To.Switch state + r1: R + x1: X + c1: 0 + tan1: 0 + r0: + power_grid_model_io.functions.both_zeros_to_nan: + value: R0 + other_value: X0 + x0: + power_grid_model_io.functions.both_zeros_to_nan: + value: X0 + other_value: R0 + c0: 0 + tan0: 0 + i_n: Inom + extra: + - ID + - Name + Transformers: + transformer: + id: + auto_id: + key: Number + from_node: + auto_id: + table: Nodes + key: + Number: From.Number + from_status: From.Switch state + to_node: + auto_id: + table: Nodes + key: + Number: To.Number + to_status: To.Switch state + u1: Unom1 + u2: Unom2 + sn: Snom + uk: + max: + - divide: + - Pk + - Snom + - power_grid_model_io.functions.value_or_default: + value: uk + default: 0.001 + - 0.001 + pk: Pk + i0: + power_grid_model_io.functions.phase_to_phase.relative_no_load_current: + i_0: Io + p_0: Po + s_nom: Snom + u_nom: Unom2 + p0: Po + winding_from: + power_grid_model_io.functions.phase_to_phase.get_winding_from: + conn_str: Connection + neutral_grounding: N1 + winding_to: + power_grid_model_io.functions.phase_to_phase.get_winding_to: + conn_str: Connection + neutral_grounding: N2 + clock: + power_grid_model_io.functions.phase_to_phase.get_clock: + conn_str: Connection + tap_side: Tap side + tap_pos: Tap + tap_min: Tap min + tap_max: Tap max + tap_nom: Tap nom + tap_size: Tap size + uk_min: + max: + - divide: + - Pk + - Snom + - power_grid_model_io.functions.value_or_default: + value: uk + default: 0.001 + - 0.001 + uk_max: + max: + - divide: + - Pk + - Snom + - power_grid_model_io.functions.value_or_default: + value: uk + default: 0.001 + - 0.001 + pk_min: Pk + pk_max: Pk + r_grounding_from: Re1 + x_grounding_from: Xe1 + r_grounding_to: Re2 + x_grounding_to: Xe2 + extra: + - ID + - Name + Special transformers: + transformer: + id: + auto_id: + key: Number + from_node: + auto_id: + table: Nodes + key: + Number: From.Number + from_status: From.Switch state + to_node: + auto_id: + table: Nodes + key: + Number: To.Number + to_status: To.Switch state + u1: Unom1 + u2: Unom2 + sn: Snom + uk: + max: + - divide: + - Pknom + - Snom + - power_grid_model_io.functions.value_or_default: + value: uknom + default: 0.001 + - 0.001 + pk: Pknom + i0: + power_grid_model_io.functions.phase_to_phase.relative_no_load_current: + i_0: Io + p_0: Po + s_nom: Snom + u_nom: Unom2 + p0: Po + winding_from: 0 + winding_to: 0 + clock: 0 + tap_side: Tap side + tap_pos: Tap + tap_min: Tap min + tap_max: Tap max + tap_nom: Tap nom + tap_size: Tap size + uk_min: + max: + - divide: + - Pkmin + - Snom + - power_grid_model_io.functions.value_or_default: + value: ukmin + default: 0.001 + - 0.001 + uk_max: + max: + - divide: + - Pkmax + - Snom + - power_grid_model_io.functions.value_or_default: + value: ukmax + default: 0.001 + - 0.001 + pk_min: Pkmin + pk_max: Pkmax + r_grounding_from: 0 + x_grounding_from: 0 + r_grounding_to: 0 + x_grounding_to: 0 + extra: + - ID + - Name + Transformer loads: + transformer: + id: + auto_id: + name: transformer + key: + - Node.Number + - Subnumber + from_node: + auto_id: + table: Nodes + key: + Number: Node.Number + to_node: + auto_id: + name: internal_node + key: + - Node.Number + - Subnumber + from_status: Switch state + to_status: 1 + u1: Unom1 + u2: Unom2 + sn: Snom + uk: + max: + - divide: + - Pk + - Snom + - power_grid_model_io.functions.value_or_default: + value: uk + default: 0.001 + - 0.001 + pk: Pk + p0: Po + i0: + power_grid_model_io.functions.phase_to_phase.relative_no_load_current: + i_0: 0 + p_0: Po + s_nom: Snom + u_nom: Unom2 + winding_from: + power_grid_model_io.functions.phase_to_phase.get_winding_from: + conn_str: Connection + winding_to: + power_grid_model_io.functions.phase_to_phase.get_winding_to: + conn_str: Connection + clock: + power_grid_model_io.functions.phase_to_phase.get_clock: + conn_str: Connection + tap_side: Tap side + tap_pos: Tap + tap_min: Tap min + tap_max: Tap max + tap_nom: Tap nom + tap_size: Tap size + uk_min: + max: + - divide: + - Pk + - Snom + - power_grid_model_io.functions.value_or_default: + value: uk + default: 0.001 + - 0.001 + uk_max: + max: + - divide: + - Pk + - Snom + - power_grid_model_io.functions.value_or_default: + value: uk + default: 0.001 + - 0.001 + pk_min: Pk + pk_max: Pk + r_grounding_from: 0 + x_grounding_from: 0 + r_grounding_to: 0 + x_grounding_to: 0 + extra: + - ID + - Name + node: + id: + auto_id: + name: internal_node + key: + - Node.Number + - Subnumber + u_rated: Unom2 + extra: + - ID + - Name + sym_load: + id: + auto_id: + name: load + key: + - Node.Number + - Subnumber + node: + auto_id: + name: internal_node + key: + - Node.Number + - Subnumber + status: Switch state + type: Behaviour + p_specified: + multiply: + - Load.P + - reference: + query_column: Node.Number + other_table: Nodes + key_column: Number + value_column: Simultaneity + q_specified: + multiply: + - Load.Q + - reference: + query_column: Node.Number + other_table: Nodes + key_column: Number + value_column: Simultaneity + extra: + - ID + - Name + sym_gen: + - id: + auto_id: + name: generation + key: + - Node.Number + - Subnumber + node: + auto_id: + name: internal_node + key: + - Node.Number + - Subnumber + status: Switch state + type: 0 + p_specified: Generation.P + q_specified: Generation.Q + extra: + - ID + - Name + - id: + auto_id: + name: pv_generation + key: + - Node.Number + - Subnumber + node: + auto_id: + name: internal_node + key: + - Node.Number + - Subnumber + status: Switch state + type: 0 + p_specified: PV.Pnom + q_specified: + power_grid_model_io.functions.phase_to_phase.reactive_power: + p: PV.Pnom + cos_phi: 1 + extra: + - ID + - Name + Sources: + source: + id: + auto_id: + key: + - Node.Number + - Subnumber + node: + auto_id: + table: Nodes + key: + Number: Node.Number + status: Switch state + u_ref: Uref + sk: Sk"nom + rx_ratio: R/X + z01_ratio: Z0/Z1 + extra: + - ID + - Name + Synchronous generators: + sym_gen: + id: + auto_id: + key: + - Node.Number + - Subnumber + node: + auto_id: + table: Nodes + key: + Number: Node.Number + status: Switch state + type: 0 + p_specified: Pref + q_specified: + multiply: + - power_grid_model_io.functions.phase_to_phase.reactive_power: + p: Pref + cos_phi: cos phi + - Q + extra: + - ID + - Name + Wind turbines: + sym_gen: + id: + auto_id: + key: + - Node.Number + - Subnumber + node: + auto_id: + table: Nodes + key: + Number: Node.Number + status: Switch state + type: 0 + p_specified: + power_grid_model_io.functions.value_or_default: + value: Pref + default: + power_grid_model_io.functions.phase_to_phase.power_wind_speed: + p_nom: Pnom + wind_speed: Wind speed + q_specified: + power_grid_model_io.functions.phase_to_phase.reactive_power: + p: + power_grid_model_io.functions.value_or_default: + value: Pref + default: + power_grid_model_io.functions.phase_to_phase.power_wind_speed: + p_nom: Pnom + wind_speed: Wind speed + cos_phi: cos phi + extra: + - ID + - Name + Loads: + sym_load: + id: + auto_id: + key: + - Node.Number + - Subnumber + node: + auto_id: + table: Nodes + key: + Number: Node.Number + status: Switch state + type: Behaviour + p_specified: + multiply: + - P + - reference: + query_column: Node.Number + other_table: Nodes + key_column: Number + value_column: Simultaneity + q_specified: + multiply: + - Q + - reference: + query_column: Node.Number + other_table: Nodes + key_column: Number + value_column: Simultaneity + extra: + - ID + - Name + Zigzag transformers: + shunt: + id: + auto_id: + key: + - Node.Number + - Subnumber + node: + auto_id: + table: Nodes + key: + Number: Node.Number + status: Switch state + g1: 0 + b1: 0 + g0: + power_grid_model_io.functions.complex_inverse_real_part: + real: R0 + imag: X0 + b0: + power_grid_model_io.functions.complex_inverse_imaginary_part: + real: R0 + imag: X0 + extra: + - ID + - Name + Capacitors: + shunt: + id: + auto_id: + key: + - Node.Number + - Subnumber + node: + auto_id: + table: Nodes + key: + Number: Node.Number + status: Switch state + g1: 0 + b1: + power_grid_model_io.functions.phase_to_phase.reactive_power_to_susceptance: + q: Q + u_nom: Unom + g0: 0 + b0: 0 + extra: + - ID + - Name + Reactors: + shunt: + id: + auto_id: + key: + - Node.Number + - Subnumber + node: + auto_id: + table: Nodes + key: + Number: Node.Number + status: Switch state + g1: 0 + b1: + multiply: + - power_grid_model_io.functions.phase_to_phase.reactive_power_to_susceptance: + q: Q + u_nom: Unom + - -1 + g0: 0 + b0: 0 + extra: + - ID + - Name + Pvs: + sym_gen: + id: + auto_id: + key: + - Node.Number + - Subnumber + node: + auto_id: + table: Nodes + key: + Number: Node.Number + status: Switch state + type: 0 + p_specified: + power_grid_model_io.functions.phase_to_phase.pvs_power_adjustment: + p: + multiply: + - min: + - Pnom + - Inverter.Pnom | Inverter.Snom + - Scaling + efficiency_type: Inverter.efficiency type + q_specified: + multiply: + - power_grid_model_io.functions.phase_to_phase.reactive_power: + p: + min: + - Pnom + - Inverter.Pnom | Inverter.Snom + cos_phi: Inverter.cos phi + - Scaling + extra: + - ID + - Name + Three winding transformers: + three_winding_transformer: + id: + auto_id: + key: Number + node_1: + auto_id: + table: Nodes + key: + Number: Node1.Number + status_1: Switch state 1 + node_2: + auto_id: + table: Nodes + key: + Number: Node2.Number + status_2: Switch state 2 + node_3: + auto_id: + table: Nodes + key: + Number: Node3.Number + status_3: Switch state 3 + u1: Unom1 + u2: Unom2 + u3: Unom3 + sn_1: Snom1 + sn_2: Snom2 + sn_3: Snom3 + uk_12: + max: + - divide: + - Pk12 + - min: + - Snom1 + - Snom2 + - power_grid_model_io.functions.value_or_default: + value: uk12 + default: 0.001 + - 0.001 + uk_13: + max: + - divide: + - Pk13 + - min: + - Snom1 + - Snom3 + - power_grid_model_io.functions.value_or_default: + value: uk13 + default: 0.001 + - 0.001 + uk_23: + max: + - divide: + - Pk23 + - min: + - Snom2 + - Snom3 + - power_grid_model_io.functions.value_or_default: + value: uk23 + default: 0.001 + - 0.001 + pk_12: Pk12 + pk_13: Pk13 + pk_23: Pk23 + i0: + power_grid_model_io.functions.phase_to_phase.relative_no_load_current: + i_0: Io + p_0: Po + s_nom: Snom3 + u_nom: Unom3 + p0: Po + winding_1: + power_grid_model_io.functions.phase_to_phase.get_winding_1: + conn_str: Connection + neutral_grounding: N1 + winding_2: + power_grid_model_io.functions.phase_to_phase.get_winding_2: + conn_str: Connection + neutral_grounding: N2 + winding_3: + power_grid_model_io.functions.phase_to_phase.get_winding_2: + conn_str: Connection + neutral_grounding: N3 + clock_12: + power_grid_model_io.functions.phase_to_phase.get_clock_12: + conn_str: Connection + clock_13: + power_grid_model_io.functions.phase_to_phase.get_clock_13: + conn_str: Connection + tap_side: Tap side a + tap_pos: Tap a + tap_min: Tap min a + tap_max: Tap max a + tap_nom: Tap nom a + tap_size: Tap size a + r_grounding_1: Re1 + x_grounding_1: Xe1 + r_grounding_2: Re2 + x_grounding_2: Xe2 + r_grounding_3: Re3 + x_grounding_3: Xe3 + extra: + - ID + - Name + Measure fields: + sym_voltage_sensor: + id: + auto_id: + key: Number + measured_object: + auto_id: + table: Nodes + GUID: InObject.Number + u_measured: nan + u_angle_measured: nan + u_sigma: nan + filter: + - power_grid_model_io.functions.filter_if_empty: + - power_1 + - power_grid_model_io.functions.filter_if_link: + - InObject.Sort + extra: + - ID + - Name + sym_power_sensor: + id: + auto_id: + key: Number + measured_object: + auto_id: + table: Nodes + GUID: InObject.Number + measured_terminal_type: + - power_grid_model_io.functions.find_terminal_type: + cable_from: + auto_id: + table: Cables + key: + From.Number: NearToNode.Number + cable_to: + auto_id: + table: Cables + key: + To.Number: NearToNode.Number + line_from: + auto_id: + table: Lines + key: + From.Number: NearToNode.Number + line_to: + auto_id: + table: Lines + key: + To.Number: NearToNode.Number + reactance_coil_from: + auto_id: + table: Reactance coils + key: + From.Number: NearToNode.Number + reactance_coil_to: + auto_id: + table: Reactance coils + key: + To.Number: NearToNode.Number + special_transformer_from: + auto_id: + table: Special transformers + key: + From.Number: NearToNode.Number + special_transformer_to: + auto_id: + table: Special transformers + key: + To.Number: NearToNode.Number + transformer_from: + auto_id: + table: Transformers + key: + From.Number: NearToNode.Number + transformer_to: + auto_id: + table: Transformers + key: + To.Number: NearToNode.Number + transformer_load: + auto_id: + table: Transformer loads + key: + Node.Number: NearToNode.Number + earthing_transformer: + auto_id: + table: Earthing transformers + key: + Node.Number: NearToNode.Number + transformer3_1: + auto_id: + table: Three winding transformers + key: + Node1.Number: NearToNode.Number + transformer3_2: + auto_id: + table: Three winding transformers + key: + Node2.Number: NearToNode.Number + transformer3_3: + auto_id: + table: Three winding transformers + key: + Node3.Number: NearToNode.Number + source: + auto_id: + table: Sources + key: + Node.Number: NearToNode.Number + shunt_capacitor: + auto_id: + table: Shunt capacitors + key: + Node.Number: NearToNode.Number + shunt_reactor: + auto_id: + table: Shunt reactors + key: + Node.Number: NearToNode.Number + pv: + auto_id: + table: Pvs + key: + Node.Number: NearToNode.Number + wind_turbine: + auto_id: + table: Wind turbines + key: + Node.Number: NearToNode.Number + load: + auto_id: + table: Loads + key: + Node.Number: NearToNode.Number + p_measured: nan + q_measured: nan + p_sigma: nan + q_sigma: nan + filter: + - power_grid_model_io.functions.filter_if_empty: + - power_2 + - power_grid_model_io.functions.filter_if_link: + - InObject.Sort + extra: + - ID + - Name + sym_power_sensor: + id: + auto_id: + key: Number + measured_object: + auto_id: + table: Nodes + GUID: InObject.Number + measured_terminal_type: + - power_grid_model_io.functions.find_terminal_type: + cable_from: + auto_id: + table: Cables + key: + From.Number: NearToNode.Number + cable_to: + auto_id: + table: Cables + key: + To.Number: NearToNode.Number + transformer_from: + auto_id: + table: Transformers + key: + From.Number: NearToNode.Number + transformer_to: + auto_id: + table: Transformers + key: + To.Number: NearToNode.Number + transformer_load_to: + auto_id: + table: Transformer loads + key: + Node.Number: NearToNode.Number + load_to: + auto_id: + table: Loads + key: + Node.Number: NearToNode.Number + earthing_transformer_to: + auto_id: + table: Earthing transformers loads + key: + Node.Number: NearToNode.Number + transformer3_1: + auto_id: + table: Three winding transformers + key: + Node1.Number: NearToNode.Number + transformer3_2: + auto_id: + table: Three winding transformers + key: + Node2.Number: NearToNode.Number + transformer3_3: + auto_id: + table: Three winding transformers + key: + Node3.Number: NearToNode.Number + p_measured: nan + q_measured: nan + p_sigma: nan + q_sigma: nan + filter: + - power_grid_model_io.functions.filter_if_empty: + - power_3 + - power_grid_model_io.functions.filter_if_link: + - InObject.Sort + extra: + - ID + - Name + sym_power_sensor: + id: + auto_id: + key: Number + measured_object: + auto_id: + table: Nodes + GUID: InObject.Number + measured_terminal_type: + - power_grid_model_io.functions.find_terminal_type: + cable_from: + auto_id: + table: Cables + key: + From.Number: NearToNode.Number + cable_to: + auto_id: + table: Cables + key: + To.Number: NearToNode.Number + transformer_from: + auto_id: + table: Transformers + key: + From.Number: NearToNode.Number + transformer_to: + auto_id: + table: Transformers + key: + To.Number: NearToNode.Number + transformer_load_to: + auto_id: + table: Transformer loads + key: + Node.Number: NearToNode.Number + load_to: + auto_id: + table: Loads + key: + Node.Number: NearToNode.Number + earthing_transformer_to: + auto_id: + table: Earthing transformers loads + key: + Node.Number: NearToNode.Number + transformer3_1: + auto_id: + table: Three winding transformers + key: + Node1.Number: NearToNode.Number + transformer3_2: + auto_id: + table: Three winding transformers + key: + Node2.Number: NearToNode.Number + transformer3_3: + auto_id: + table: Three winding transformers + key: + Node3.Number: NearToNode.Number + p_measured: nan + q_measured: nan + p_sigma: nan + q_sigma: nan + filter: + - power_grid_model_io.functions.filter_if_empty: + - power_4 + - power_grid_model_io.functions.filter_if_link: + - InObject.Sort + extra: + - ID + - Name + +units: + A: null + F: + µF: 0.000_001 + V: + kV: 1_000.0 + VA: + kVA: 1_000.0 + MVA: 1_000_000.0 + VAR: + kvar: 1_000.0 + Mvar: 1_000_000.0 + W: + kW: 1_000.0 + MW: 1_000_000.0 + Wp: + kWp: 1_000.0 + MWp: 1_000_000.0 + m/s: null + ohm: + Ohm: 1.0 + ohm/m: + ohm/km: 0.001 + one: + pu: 1.0 + "%": 0.01 + "‰": 0.001 + +substitutions: + ".*Switch state": + "off": 0 + "in": 1 + "on": 1 + "Switch state .*": + "off": 0 + "in": 1 + "on": 1 + N1: + 0: false + 1: true + none: false + own: true + N2: + 0: false + 1: true + none: false + own: true + N3: + 0: false + 1: true + none: false + own: true + Behaviour: + Constant admittance: 1 + Constant impedance: 1 + ~Constant current: 2 + Constant power: 0 + Default: 0 + Industry: 0 + Business: 0 + Residential: 0 + Living: 0 + Tap side: + 1: 0 + 2: 1 + Synchronous generators.Q: + absorb: -1 + supply: 1 From 92d9666fd7be239998b879955a7f30d3b9bab3ca Mon Sep 17 00:00:00 2001 From: Zhen Wang Date: Thu, 4 Apr 2024 13:36:36 +0200 Subject: [PATCH 3/6] Minor changes. Signed-off-by: Zhen Wang --- .../functions/_functions.py | 17 +- tests/data/vision/vision_9_7_en.yaml | 158 +++++++++++++++--- 2 files changed, 138 insertions(+), 37 deletions(-) diff --git a/src/power_grid_model_io/functions/_functions.py b/src/power_grid_model_io/functions/_functions.py index 14a4e411..d567cd1c 100644 --- a/src/power_grid_model_io/functions/_functions.py +++ b/src/power_grid_model_io/functions/_functions.py @@ -12,6 +12,7 @@ import structlog from power_grid_model import WindingType from power_grid_model import MeasuredTerminalType + T = TypeVar("T") _LOG = structlog.get_logger(__file__) @@ -36,7 +37,7 @@ "transformer_from": MeasuredTerminalType.branch_from, "transformer_to": MeasuredTerminalType.branch_to, "transformer_load": MeasuredTerminalType.branch_to, - "earthing_transformer": MeasuredTerminalType.branch_to, + "earthing_transformer": MeasuredTerminalType.branch_from, "transformer3_1": MeasuredTerminalType.branch3_1, "transformer3_2": MeasuredTerminalType.branch3_2, "transformer3_3": MeasuredTerminalType.branch3_3, @@ -48,14 +49,12 @@ "load": MeasuredTerminalType.load, } - - def has_value(value: Any) -> bool: """ Return True if the value is not None, NaN or empty string. """ if value is None: - return False + return False if isinstance(value, float): return not np.isnan(value) return value != "" @@ -132,15 +131,7 @@ def both_zeros_to_nan(value: float, other_value: float) -> float: def find_terminal_type(**kwargs) -> MeasuredTerminalType: """ - Return 'branch_from' if any argument contains 'from' in its name. - Return 'branch_to' if any argument contains 'to' in its name. - Return the name of the first argument that evaluates to True otherwise. - - Parameters: - - args: Variable number of input values. - - Returns: - - String representation based on the conditions mentioned above. + Return the measured terminal type, based on the string representation """ for key, id in kwargs.items(): if id is not None: diff --git a/tests/data/vision/vision_9_7_en.yaml b/tests/data/vision/vision_9_7_en.yaml index 5da2297a..e6aac676 100644 --- a/tests/data/vision/vision_9_7_en.yaml +++ b/tests/data/vision/vision_9_7_en.yaml @@ -900,32 +900,32 @@ grid: auto_id: table: Sources key: - Node.Number: NearToNode.Number + Node.Number: NearToNode.Number shunt_capacitor: auto_id: table: Shunt capacitors key: - Node.Number: NearToNode.Number + Node.Number: NearToNode.Number shunt_reactor: auto_id: table: Shunt reactors key: - Node.Number: NearToNode.Number + Node.Number: NearToNode.Number pv: auto_id: table: Pvs key: - Node.Number: NearToNode.Number + Node.Number: NearToNode.Number wind_turbine: auto_id: table: Wind turbines key: - Node.Number: NearToNode.Number + Node.Number: NearToNode.Number load: auto_id: table: Loads key: - Node.Number: NearToNode.Number + Node.Number: NearToNode.Number p_measured: nan q_measured: nan p_sigma: nan @@ -958,6 +958,36 @@ grid: table: Cables key: To.Number: NearToNode.Number + line_from: + auto_id: + table: Lines + key: + From.Number: NearToNode.Number + line_to: + auto_id: + table: Lines + key: + To.Number: NearToNode.Number + reactance_coil_from: + auto_id: + table: Reactance coils + key: + From.Number: NearToNode.Number + reactance_coil_to: + auto_id: + table: Reactance coils + key: + To.Number: NearToNode.Number + special_transformer_from: + auto_id: + table: Special transformers + key: + From.Number: NearToNode.Number + special_transformer_to: + auto_id: + table: Special transformers + key: + To.Number: NearToNode.Number transformer_from: auto_id: table: Transformers @@ -968,19 +998,14 @@ grid: table: Transformers key: To.Number: NearToNode.Number - transformer_load_to: + transformer_load: auto_id: table: Transformer loads key: Node.Number: NearToNode.Number - load_to: - auto_id: - table: Loads - key: - Node.Number: NearToNode.Number - earthing_transformer_to: + earthing_transformer: auto_id: - table: Earthing transformers loads + table: Earthing transformers key: Node.Number: NearToNode.Number transformer3_1: @@ -997,7 +1022,37 @@ grid: auto_id: table: Three winding transformers key: - Node3.Number: NearToNode.Number + Node3.Number: NearToNode.Number + source: + auto_id: + table: Sources + key: + Node.Number: NearToNode.Number + shunt_capacitor: + auto_id: + table: Shunt capacitors + key: + Node.Number: NearToNode.Number + shunt_reactor: + auto_id: + table: Shunt reactors + key: + Node.Number: NearToNode.Number + pv: + auto_id: + table: Pvs + key: + Node.Number: NearToNode.Number + wind_turbine: + auto_id: + table: Wind turbines + key: + Node.Number: NearToNode.Number + load: + auto_id: + table: Loads + key: + Node.Number: NearToNode.Number p_measured: nan q_measured: nan p_sigma: nan @@ -1030,6 +1085,36 @@ grid: table: Cables key: To.Number: NearToNode.Number + line_from: + auto_id: + table: Lines + key: + From.Number: NearToNode.Number + line_to: + auto_id: + table: Lines + key: + To.Number: NearToNode.Number + reactance_coil_from: + auto_id: + table: Reactance coils + key: + From.Number: NearToNode.Number + reactance_coil_to: + auto_id: + table: Reactance coils + key: + To.Number: NearToNode.Number + special_transformer_from: + auto_id: + table: Special transformers + key: + From.Number: NearToNode.Number + special_transformer_to: + auto_id: + table: Special transformers + key: + To.Number: NearToNode.Number transformer_from: auto_id: table: Transformers @@ -1040,19 +1125,14 @@ grid: table: Transformers key: To.Number: NearToNode.Number - transformer_load_to: + transformer_load: auto_id: table: Transformer loads key: Node.Number: NearToNode.Number - load_to: - auto_id: - table: Loads - key: - Node.Number: NearToNode.Number - earthing_transformer_to: + earthing_transformer: auto_id: - table: Earthing transformers loads + table: Earthing transformers key: Node.Number: NearToNode.Number transformer3_1: @@ -1069,7 +1149,37 @@ grid: auto_id: table: Three winding transformers key: - Node3.Number: NearToNode.Number + Node3.Number: NearToNode.Number + source: + auto_id: + table: Sources + key: + Node.Number: NearToNode.Numbe + shunt_capacitor: + auto_id: + table: Shunt capacitors + key: + Node.Number: NearToNode.Number + shunt_reactor: + auto_id: + table: Shunt reactors + key: + Node.Number: NearToNode.Number + pv: + auto_id: + table: Pvs + key: + Node.Number: NearToNode.Number + wind_turbine: + auto_id: + table: Wind turbines + key: + Node.Number: NearToNode.Number + load: + auto_id: + table: Loads + key: + Node.Number: NearToNode.Number p_measured: nan q_measured: nan p_sigma: nan From cca2019cba01a9c7c65e5769b40de0a58e879a0f Mon Sep 17 00:00:00 2001 From: Zhen Wang Date: Fri, 5 Apr 2024 09:31:04 +0200 Subject: [PATCH 4/6] Rewrite the filter to exclude sensor on link in a general way. Signed-off-by: Zhen Wang --- .../converters/tabular_converter.py | 28 +++++++++++++++---- .../functions/_functions.py | 26 +++++++++++++---- src/power_grid_model_io/utils/auto_id.py | 2 +- tests/data/vision/vision_9_7_en.yaml | 28 +++++++++++-------- 4 files changed, 59 insertions(+), 25 deletions(-) diff --git a/src/power_grid_model_io/converters/tabular_converter.py b/src/power_grid_model_io/converters/tabular_converter.py index 29c5871e..7c3919b7 100644 --- a/src/power_grid_model_io/converters/tabular_converter.py +++ b/src/power_grid_model_io/converters/tabular_converter.py @@ -178,7 +178,15 @@ def _convert_table_to_component( if table not in data: return None - n_records = len(data[table]) + table_mask = np.arary(True) * len(data[table]) + if "filter" in attributes: + table_mask = self._parse_filter() + pass + + n_records = np.sum(table_mask) + + if n_records == 0: + return None try: pgm_data = initialize_array(data_type=data_type, component_type=component, shape=n_records) @@ -193,7 +201,7 @@ def _convert_table_to_component( for attr, col_def in sorted_attributes: self._convert_col_def_to_attribute( - data=data, + data=data[table_mask], pgm_data=pgm_data, table=table, component=component, @@ -213,6 +221,7 @@ def _convert_col_def_to_attribute( component: str, attr: str, col_def: Any, + table_mask: np.ndarray, extra_info: Optional[ExtraInfo], ): """This function updates one of the attributes of pgm_data, based on the corresponding table/column in a tabular @@ -242,7 +251,7 @@ def _convert_col_def_to_attribute( """ # To avoid mistakes, the attributes in the mapping should exist. There is one extra attribute called # 'extra' in which extra information can be captured. - if attr not in pgm_data.dtype.names and attr != "extra": + if attr not in pgm_data.dtype.names and attr not in ["extra", "filter"]: attrs = ", ".join(pgm_data.dtype.names) raise KeyError(f"Could not find attribute '{attr}' for '{component}s'. (choose from: {attrs})") @@ -250,18 +259,25 @@ def _convert_col_def_to_attribute( # Extra info must be linked to the object IDs, therefore the uuids should be known before extra info can # be parsed. Before this for loop, it is checked that "id" exists and it is placed at the front. self._handle_extra_info( - data=data, table=table, col_def=col_def, uuids=pgm_data["id"], extra_info=extra_info + data=data[table_mask], table=table, col_def=col_def, uuids=pgm_data["id"], extra_info=extra_info ) # Extra info should not be added to the numpy arrays, so let's continue to the next attribute return - attr_data = self._parse_col_def(data=data, table=table, col_def=col_def, extra_info=extra_info) + attr_data = self._parse_col_def(data=data[table_mask], table=table, col_def=col_def, extra_info=extra_info) if len(attr_data.columns) != 1: raise ValueError(f"DataFrame for {component}.{attr} should contain a single column ({attr_data.columns})") pgm_data[attr] = attr_data.iloc[:, 0] + def _parse_filters() -> pd.Series[bool]: + mask = True * len(data) * 483 + for function, args in mapping["filter"] { + mask &= data.apply(function, arg) + } + return pd.Series() + def _handle_extra_info( self, data: TabularData, @@ -517,7 +533,7 @@ def _parse_auto_id( key_col_def: A column definition which should be unique for each object within the current table Returns: A single column containing numerical ids - + """ # Handle reference table diff --git a/src/power_grid_model_io/functions/_functions.py b/src/power_grid_model_io/functions/_functions.py index d567cd1c..db1ab448 100644 --- a/src/power_grid_model_io/functions/_functions.py +++ b/src/power_grid_model_io/functions/_functions.py @@ -10,8 +10,7 @@ import numpy as np import structlog -from power_grid_model import WindingType -from power_grid_model import MeasuredTerminalType +from power_grid_model import MeasuredTerminalType, WindingType T = TypeVar("T") @@ -29,7 +28,7 @@ "cable_from": MeasuredTerminalType.branch_from, "cable_to": MeasuredTerminalType.branch_to, "line_from": MeasuredTerminalType.branch_from, - "line_to": MeasuredTerminalType.branch_to, + "line_to": MeasuredTerminalType.branch_to, "reactance_coil_from": MeasuredTerminalType.branch_from, "reactance_coil_to": MeasuredTerminalType.branch_to, "special_transformer_from": MeasuredTerminalType.branch_from, @@ -48,7 +47,8 @@ "wind_turbine": MeasuredTerminalType.generator, "load": MeasuredTerminalType.load, } - + + def has_value(value: Any) -> bool: """ Return True if the value is not None, NaN or empty string. @@ -129,12 +129,26 @@ def both_zeros_to_nan(value: float, other_value: float) -> float: return float("nan") return value + def find_terminal_type(**kwargs) -> MeasuredTerminalType: """ Return the measured terminal type, based on the string representation - """ + """ for key, id in kwargs.items(): if id is not None: return MEASURED_TERMINAL_TYPE_MAP[key] _LOG.warning("No measured terminal type is found!") - return float("nan") \ No newline at end of file + return float("nan") + + +def if_not_link(input_string) -> bool: + """ + Check if the measurement field is applied on a link + """ + return input_string != "link" + +def filter_if_object(object_name: str, excl_object: str) -> bool: + """ + Return false if the measured object should be excluded. + """ + return object_name != excl_object diff --git a/src/power_grid_model_io/utils/auto_id.py b/src/power_grid_model_io/utils/auto_id.py index dd20d221..4be89f7e 100644 --- a/src/power_grid_model_io/utils/auto_id.py +++ b/src/power_grid_model_io/utils/auto_id.py @@ -119,4 +119,4 @@ def __getitem__(self, idx: int) -> Any: Returns: The original item """ - return getattr(self._items[idx], None) + return self._items.get(idx) \ No newline at end of file diff --git a/tests/data/vision/vision_9_7_en.yaml b/tests/data/vision/vision_9_7_en.yaml index e6aac676..042ed647 100644 --- a/tests/data/vision/vision_9_7_en.yaml +++ b/tests/data/vision/vision_9_7_en.yaml @@ -804,10 +804,11 @@ grid: u_angle_measured: nan u_sigma: nan filter: - - power_grid_model_io.functions.filter_if_empty: + - power_grid_model_io.functions.has_value: - power_1 - - power_grid_model_io.functions.filter_if_link: - - InObject.Sort + - power_grid_model_io.functions.filter_if_object: + object: InObject.Sort + excl_object: link extra: - ID - Name @@ -931,10 +932,11 @@ grid: p_sigma: nan q_sigma: nan filter: - - power_grid_model_io.functions.filter_if_empty: + - power_grid_model_io.functions.has_value: - power_2 - - power_grid_model_io.functions.filter_if_link: - - InObject.Sort + - power_grid_model_io.functions.filter_if_object: + object: InObject.Sort + excl_object: link extra: - ID - Name @@ -1058,10 +1060,11 @@ grid: p_sigma: nan q_sigma: nan filter: - - power_grid_model_io.functions.filter_if_empty: + - power_grid_model_io.functions.has_value: - power_3 - - power_grid_model_io.functions.filter_if_link: - - InObject.Sort + - power_grid_model_io.functions.filter_if_object: + object: InObject.Sort + excl_object: link extra: - ID - Name @@ -1185,10 +1188,11 @@ grid: p_sigma: nan q_sigma: nan filter: - - power_grid_model_io.functions.filter_if_empty: + - power_grid_model_io.functions.has_value: - power_4 - - power_grid_model_io.functions.filter_if_link: - - InObject.Sort + - power_grid_model_io.functions.filter_if_object: + object: InObject.Sort + excl_object: link extra: - ID - Name From 4f6b60dcc39d07d17c918f12f6ea63409291b1f8 Mon Sep 17 00:00:00 2001 From: Zhen Wang Date: Fri, 5 Apr 2024 10:04:31 +0200 Subject: [PATCH 5/6] commit Signed-off-by: Zhen Wang --- .../converters/tabular_converter.py | 10 +++--- .../functions/_functions.py | 7 ---- .../data/pandapower/pgm_asym_output_data.json | 24 ++++++------- tests/data/pandapower/pgm_output_data.json | 36 +++++++++---------- 4 files changed, 35 insertions(+), 42 deletions(-) diff --git a/src/power_grid_model_io/converters/tabular_converter.py b/src/power_grid_model_io/converters/tabular_converter.py index 7c3919b7..4f798a88 100644 --- a/src/power_grid_model_io/converters/tabular_converter.py +++ b/src/power_grid_model_io/converters/tabular_converter.py @@ -180,7 +180,7 @@ def _convert_table_to_component( table_mask = np.arary(True) * len(data[table]) if "filter" in attributes: - table_mask = self._parse_filter() + table_mask = self._parse_filters() pass n_records = np.sum(table_mask) @@ -271,11 +271,11 @@ def _convert_col_def_to_attribute( pgm_data[attr] = attr_data.iloc[:, 0] - def _parse_filters() -> pd.Series[bool]: - mask = True * len(data) * 483 - for function, args in mapping["filter"] { + def _parse_filters(self) -> pd.Series: + mask = True * pd.DataFrame(True, shape=data.shape) + for function, args in mapping["filter"].items(): mask &= data.apply(function, arg) - } + return pd.Series() def _handle_extra_info( diff --git a/src/power_grid_model_io/functions/_functions.py b/src/power_grid_model_io/functions/_functions.py index db1ab448..cab60bfc 100644 --- a/src/power_grid_model_io/functions/_functions.py +++ b/src/power_grid_model_io/functions/_functions.py @@ -140,13 +140,6 @@ def find_terminal_type(**kwargs) -> MeasuredTerminalType: _LOG.warning("No measured terminal type is found!") return float("nan") - -def if_not_link(input_string) -> bool: - """ - Check if the measurement field is applied on a link - """ - return input_string != "link" - def filter_if_object(object_name: str, excl_object: str) -> bool: """ Return false if the measured object should be excluded. diff --git a/tests/data/pandapower/pgm_asym_output_data.json b/tests/data/pandapower/pgm_asym_output_data.json index dea1427e..2a2bca51 100644 --- a/tests/data/pandapower/pgm_asym_output_data.json +++ b/tests/data/pandapower/pgm_asym_output_data.json @@ -1,43 +1,43 @@ { "node": [ - {"id": 0, "energized": 1, "u_pu": [1.000000000042805, 1.000000000042805, 1.000000000040956], "u": [63508.52961357732, 63508.52961357732, 63508.52961345989], "u_angle": [-2.297462191765614e-10, -2.094395102622942, 2.094395102852041], "p": [765820.7217852274, 765820.7235734381, -1529485.490304183], "q": [-142683.6055350895, -142683.5967414472, -136520.3696246375], "id_reference": {"table": "bus", "index": 101}}, - {"id": 1, "energized": 1, "u_pu": [0.9994132656313264, 0.9994132656313274, 1.002844167287654], "u": [11540.23035887859, 11540.2303588786, 11579.84699877547], "u_angle": [-0.002501623712801432, -2.096896726105997, 2.098735152107258], "p": [5.662039942836705e-08, 4.158749852077411e-07, 5.339208304447429e-08], "q": [-7.588863607722517e-08, -6.631148746093378e-08, 3.610845913546241e-07], "id_reference": {"table": "bus", "index": 102}}, - {"id": 2, "energized": 1, "u_pu": [0.9987870960752929, 0.9987870960752938, 1.004418511811836], "u": [11532.9999756439, 11532.99997564391, 11598.02596347214], "u_angle": [-0.002966986920613948, -2.09736208931381, 2.099116406819713], "p": [-729999.9999998733, -730000.000000165, 1570000.000000135], "q": [189999.9999999996, 190000.0000003468, 189999.9999996292], "id_reference": {"table": "bus", "index": 103}}, - {"id": 3, "energized": 1, "u_pu": [1.000000000042805, 1.000000000042805, 1.000000000040956], "u": [63508.52961357732, 63508.52961357732, 63508.52961345989], "u_angle": [-2.297462191765614e-10, -2.094395102622942, 2.094395102852041], "p": [0, 0, 0], "q": [0, 0, 0], "id_reference": {"table": "bus", "index": 106}} + {"id": 0, "energized": 1, "u_pu": [1.000000000042805, 1.000000000042805, 1.000000000040956], "u": [63508.52961357732, 63508.5296135773, 63508.52961345989], "u_angle": [-2.297462189084376e-10, -2.094395102622942, 2.094395102852041], "p": [765820.7267522812, 765820.7296931006, -1529485.490304183], "q": [-142683.6005680358, -142683.6060100956, -136520.3696246375], "id_reference": {"table": "bus", "index": 101}}, + {"id": 1, "energized": 1, "u_pu": [0.999413265631326, 0.999413265631326, 1.002844167287653], "u": [11540.23035887858, 11540.23035887858, 11579.84699877545], "u_angle": [-0.002501623712802202, -2.096896726105998, 2.098735152107257], "p": [-9.468314851880033e-08, -3.443068010217254e-07, -2.092409301524057e-07], "q": [2.368621036415272e-10, -2.818180961370497e-07, 2.07929736044559e-07], "id_reference": {"table": "bus", "index": 102}}, + {"id": 2, "energized": 1, "u_pu": [0.9987870960752924, 0.9987870960752926, 1.004418511811836], "u": [11532.99997564389, 11532.9999756439, 11598.02596347213], "u_angle": [-0.002966986920614807, -2.097362089313811, 2.099116406819712], "p": [-730000.0000000243, -729999.9999999676, 1570000.000000095], "q": [189999.9999999249, 190000.0000002327, 189999.9999996934], "id_reference": {"table": "bus", "index": 103}}, + {"id": 3, "energized": 1, "u_pu": [1.000000000042805, 1.000000000042805, 1.000000000040956], "u": [63508.52961357732, 63508.5296135773, 63508.52961345989], "u_angle": [-2.29746171205172e-10, -2.094395102622942, 2.094395102852041], "p": [-0.004967053732636329, 0, 0], "q": [-0.004967053730354005, 0, 0], "id_reference": {"table": "bus", "index": 106}} ], "line": [ - {"id": 4, "energized": 1, "loading": 1.265330032238072, "p_from": [-729999.9999998733, -730000.000000165, 1570000.000000135], "q_from": [189999.9999999996, 190000.0000003468, 189999.9999996292], "i_from": [65.40543555178559, 65.40543555181758, 136.3555342275158], "s_from": [754320.8866257217, 754320.8866260914, 1581455.026233842], "p_to": [730552.3008243673, 730552.3008246894, -1567616.527443881], "q_to": [-216633.7469513389, -216633.7469515898, -216173.5239478488], "i_to": [66.02947091323357, 66.02947091326645, 136.6556434817117], "s_to": [761995.3048135885, 761995.3048139686, 1582451.44303743], "id_reference": {"table": "line", "index": 101}, "pgm_input": {"from_node": 2, "to_node": 1, "i_n": 108.0}} + {"id": 4, "energized": 1, "loading": 1.265330032238049, "p_from": [-730000.0000000243, -729999.9999999676, 1570000.000000095], "q_from": [189999.9999999249, 190000.0000002327, 189999.9999996934], "i_from": [65.40543555179667, 65.40543555179862, 136.3555342275132], "s_from": [754320.8866258491, 754320.8866258716, 1581455.026233811], "p_to": [730552.3008245184, 730552.3008244052, -1567616.527443842], "q_to": [-216633.7469513398, -216633.7469517758, -216173.5239479129], "i_to": [66.02947091324616, 66.02947091324751, 136.6556434817092], "s_to": [761995.3048137337, 761995.304813749, 1582451.443037399], "id_reference": {"table": "line", "index": 101}, "pgm_input": {"from_node": 2, "to_node": 1, "i_n": 108.0}} ], "source": [ - {"id": 5, "energized": 1, "p": [765820.730621319, 765820.4766903995, -1529485.219644774], "q": [-142683.6428608279, -142684.1067247107, -136520.4031334404], "i": [12.26605892917178, 12.26605633625489, 24.17889348713215], "s": [778999.36674519, 778999.2020728515, 1535565.973048225], "pf": [0.9830826099654819, 0.9830824918082272, -0.9960400572100595], "id_reference": {"table": "ext_grid", "index": 0}, "pgm_input": {"node": 0}} + {"id": 5, "energized": 1, "p": [765820.729727573, 765820.52627096, -1529485.219644774], "q": [-142683.6428608279, -142683.2806999777, -136520.4031334404], "i": [12.266058915337, 12.26605472142855, 24.17889348713215], "s": [778999.3658665639, 778999.0995176046, 1535565.973048225], "pf": [0.9830826099269916, 0.9830826848775494, -0.9960400572100595], "id_reference": {"table": "ext_grid", "index": 0}, "pgm_input": {"node": 0}} ], "sym_load": [ - {"id": 6, "energized": 1, "p": [833333.3333333333, 833333.3333333333, 833333.3333333333], "q": [79999.99999999999, 79999.99999999999, 79999.99999999999], "i": [72.58861772969922, 72.58861772969915, 72.18163928458914], "s": [837164.5265086454, 837164.5265086454, 837164.5265086454], "pf": [0.9954236078405162, 0.9954236078405162, 0.9954236078405162], "id_reference": {"table": "load", "name": "const_power", "index": 101}, "pgm_input": {"node": 2}}, + {"id": 6, "energized": 1, "p": [833333.3333333333, 833333.3333333333, 833333.3333333333], "q": [79999.99999999999, 79999.99999999999, 79999.99999999999], "i": [72.58861772969925, 72.58861772969924, 72.1816392845892], "s": [837164.5265086454, 837164.5265086454, 837164.5265086454], "pf": [0.9954236078405162, 0.9954236078405162, 0.9954236078405162], "id_reference": {"table": "load", "name": "const_power", "index": 101}, "pgm_input": {"node": 2}}, {"id": 7, "energized": 1, "p": [0, 0, 0], "q": [0, 0, 0], "i": [0, 0, 0], "s": [0, 0, 0], "pf": [0, 0, 0], "id_reference": {"table": "load", "name": "const_impedance", "index": 101}, "pgm_input": {"node": 2}}, {"id": 8, "energized": 1, "p": [0, 0, 0], "q": [0, 0, 0], "i": [0, 0, 0], "s": [0, 0, 0], "pf": [0, 0, 0], "id_reference": {"table": "load", "name": "const_current", "index": 101}, "pgm_input": {"node": 2}} ], "transformer": [ - {"id": 9, "energized": 1, "loading": 0.03883052565830863, "p_from": [765820.724989093, 765820.7249890427, -1529485.491438911], "q_from": [-142683.6001096883, -142683.6001099306, -136520.3668874493], "i_from": [12.26605871869048, 12.2660587186904, 24.17889769909201], "s_from": [778999.3533778327, 778999.3533778277, 1535566.240543602], "p_to": [-730552.3008242727, -730552.300824217, 1567616.527444104], "q_to": [216633.7469512629, 216633.7469515783, 216173.5239482207], "i_to": [66.02947091322386, 66.02947091322693, 136.6556434817352], "s_to": [761995.3048134763, 761995.3048135125, 1582451.443037701], "id_reference": {"table": "trafo", "index": 0}, "pgm_input": {"from_node": 0, "to_node": 1}, "pp_input": {"df": 1.0}} + {"id": 9, "energized": 1, "loading": 0.03883052565831053, "p_from": [765820.7249893394, 765820.7249893607, -1529485.491438516], "q_from": [-142683.6001096883, -142683.6001097204, -136520.3668873747], "i_from": [12.2660587186943, 12.26605871869472, 24.17889769908571], "s_from": [778999.3533780748, 778999.3533781016, 1535566.240543202], "p_to": [-730552.3008245374, -730552.3008245562, 1567616.527443769], "q_to": [216633.746951264, 216633.7469512941, 216173.5239481125], "i_to": [66.02947091324589, 66.0294709132482, 136.6556434817054], "s_to": [761995.3048137303, 761995.304813757, 1582451.443037355], "id_reference": {"table": "trafo", "index": 0}, "pgm_input": {"from_node": 0, "to_node": 1}, "pp_input": {"df": 1.0}} ], "sym_gen": [ - {"id": 10, "energized": 1, "p": [403333.3333333333, 403333.3333333333, 403333.3333333333], "q": [269999.9999999999, 269999.9999999999, 269999.9999999999], "i": [42.08476139753746, 42.08476139753742, 41.84880717644763], "s": [485363.5521727787, 485363.5521727787, 485363.5521727787], "pf": [0.8309922150680065, 0.8309922150680065, 0.8309922150680065], "id_reference": {"table": "sgen", "index": 31}, "pgm_input": {"node": 2}} + {"id": 10, "energized": 1, "p": [403333.3333333333, 403333.3333333333, 403333.3333333333], "q": [269999.9999999999, 269999.9999999999, 269999.9999999999], "i": [42.08476139753748, 42.08476139753747, 41.84880717644766], "s": [485363.5521727787, 485363.5521727787, 485363.5521727787], "pf": [0.8309922150680065, 0.8309922150680065, 0.8309922150680065], "id_reference": {"table": "sgen", "index": 31}, "pgm_input": {"node": 2}} ], "link": [ - {"id": 11, "energized": 1, "loading": 0, "p_from": [0, 0, 0], "q_from": [0, 0, 0], "i_from": [0, 0, 0], "s_from": [0, 0, 0], "p_to": [0, 0, 0], "q_to": [0, 0, 0], "i_to": [0, 0, 0], "s_to": [0, 0, 0], "id_reference": {"table": "switch", "name": "b2b_switches", "index": 3021}, "pgm_input": {"from_node": 0, "to_node": 3}} + {"id": 11, "energized": 1, "loading": 0, "p_from": [0.004967053732636329, 0, 0], "q_from": [0.004967053730354005, 0, 0], "i_from": [1.106067924239048e-07, 0, 0], "s_from": [0.007024474752116355, 0, 0], "p_to": [-0.004967053732636329, 0, 0], "q_to": [-0.004967053730354005, 0, 0], "i_to": [1.106067924239048e-07, 0, 0], "s_to": [0.007024474752116355, 0, 0], "id_reference": {"table": "switch", "name": "b2b_switches", "index": 3021}, "pgm_input": {"from_node": 0, "to_node": 3}} ], "asym_load": [ - {"id": 12, "energized": 1, "p": [399999.9999999999, 500000, 1000000], "q": [10000, 10000, 10000], "i": [34.69392016993495, 43.36252415313805, 86.22588032650638], "s": [400124.980474851, 500099.9900019995, 1000049.998750063], "pf": [0.9996876464081228, 0.999800059980007, 0.9999500037496875], "id_reference": {"table": "asymmetric_load", "index": 33}, "pgm_input": {"node": 2}} + {"id": 12, "energized": 1, "p": [399999.9999999999, 500000, 1000000], "q": [10000, 10000, 10000], "i": [34.69392016993496, 43.3625241531381, 86.22588032650644], "s": [400124.980474851, 500099.9900019995, 1000049.998750063], "pf": [0.9996876464081228, 0.999800059980007, 0.9999500037496875], "id_reference": {"table": "asymmetric_load", "index": 33}, "pgm_input": {"node": 2}} ], "asym_gen": [ - {"id": 13, "energized": 1, "p": [99999.99999999999, 200000, 3000000], "q": [10000, 10000, 10000], "i": [8.71401685801165, 17.3632050956306, 258.6661450895947], "s": [100498.7562112089, 200249.8439450078, 3000016.66662037], "pf": [0.9950371902099889, 0.9987523388778446, 0.9999944444907404], "id_reference": {"table": "asymmetric_sgen", "index": 32}, "pgm_input": {"node": 2}} + {"id": 13, "energized": 1, "p": [99999.99999999999, 200000, 3000000], "q": [10000, 10000, 10000], "i": [8.714016858011654, 17.36320509563062, 258.6661450895949], "s": [100498.7562112089, 200249.8439450078, 3000016.66662037], "pf": [0.9950371902099889, 0.9987523388778446, 0.9999944444907404], "id_reference": {"table": "asymmetric_sgen", "index": 32}, "pgm_input": {"node": 2}} ] } diff --git a/tests/data/pandapower/pgm_output_data.json b/tests/data/pandapower/pgm_output_data.json index 7e62a9bc..dac13088 100644 --- a/tests/data/pandapower/pgm_output_data.json +++ b/tests/data/pandapower/pgm_output_data.json @@ -1,37 +1,37 @@ { "node": [ - {"id": 0, "energized": 1, "u_pu": 0.9999999996523372, "u": 109999.9999617571, "u_angle": -1.798666001063812e-10, "p": 1798665.98546505, "q": 3476628.82353626, "id_reference": {"table": "bus", "index": 101}}, - {"id": 1, "energized": 1, "u_pu": 0.97374599364253, "u": 19474.9198728506, "u_angle": -0.5239008142519944, "p": 1.408570295181389e-07, "q": -3.370807360039286e-07, "id_reference": {"table": "bus", "index": 102}}, - {"id": 2, "energized": 1, "u_pu": 0.9730137872763268, "u": 19460.27574552653, "u_angle": -0.5237223960629773, "p": -2414572.645273485, "q": -231798.9739460695, "id_reference": {"table": "bus", "index": 103}}, - {"id": 3, "energized": 1, "u_pu": 0.9695497239124967, "u": 29183.44668976615, "u_angle": -1.04518706304991, "p": -8.295648914520637e-08, "q": 1.430200360429221e-07, "id_reference": {"table": "bus", "index": 104}}, - {"id": 4, "energized": 1, "u_pu": 0.9719979160849105, "u": 58319.87496509463, "u_angle": -1.044828700708015, "p": 944410.894001629, "q": 581081.3221020879, "id_reference": {"table": "bus", "index": 105}}, - {"id": 5, "energized": 1, "u_pu": 0.9999999996523372, "u": 109999.9999617571, "u_angle": -1.798666001063812e-10, "p": 0, "q": 0, "id_reference": {"table": "bus", "index": 106}} + {"id": 0, "energized": 1, "u_pu": 0.9999999996523371, "u": 109999.9999617571, "u_angle": -1.798665986090047e-10, "p": 1798665.98546505, "q": 3476628.823536259, "id_reference": {"table": "bus", "index": 101}}, + {"id": 1, "energized": 1, "u_pu": 0.9737459936425311, "u": 19474.91987285062, "u_angle": -0.5239008142519922, "p": 5.817752759336667e-07, "q": -1.649724889732842e-08, "id_reference": {"table": "bus", "index": 102}}, + {"id": 2, "energized": 1, "u_pu": 0.973013787276328, "u": 19460.27574552656, "u_angle": -0.523722396062975, "p": -2414572.645272499, "q": -231798.9739461347, "id_reference": {"table": "bus", "index": 103}}, + {"id": 3, "energized": 1, "u_pu": 0.9695497239124969, "u": 29183.44668976616, "u_angle": -1.045187063049907, "p": 2.765216304840227e-08, "q": -4.767334534764063e-08, "id_reference": {"table": "bus", "index": 104}}, + {"id": 4, "energized": 1, "u_pu": 0.9719979160849106, "u": 58319.87496509463, "u_angle": -1.044828700708012, "p": 944410.8940017537, "q": 581081.3221016526, "id_reference": {"table": "bus", "index": 105}}, + {"id": 5, "energized": 1, "u_pu": 0.9999999996523371, "u": 109999.9999617571, "u_angle": -1.798666195975547e-10, "p": 0, "q": 0, "id_reference": {"table": "bus", "index": 106}} ], "line": [ - {"id": 6, "energized": 1, "loading": 0.5930290459172566, "p_from": -1763554.11350539, "q_from": -1245081.686597617, "i_from": 64.0471369590637, "s_from": 2158784.731640131, "p_to": 1765096.677117153, "q_to": 1169229.770073222, "i_to": 62.7670637419498, "s_to": 2117230.39246925, "id_reference": {"table": "line", "index": 101}, "pgm_input": {"from_node": 2, "to_node": 1, "i_n": 108.0}} + {"id": 6, "energized": 1, "loading": 0.5930290459171291, "p_from": -1763554.113504432, "q_from": -1245081.686598176, "i_from": 64.04713695904995, "s_from": 2158784.73163967, "p_to": 1765096.677116415, "q_to": 1169229.770074164, "i_to": 62.76706374194693, "s_to": 2117230.392469156, "id_reference": {"table": "line", "index": 101}, "pgm_input": {"from_node": 2, "to_node": 1, "i_n": 108.0}} ], "source": [ - {"id": 7, "energized": 1, "p": 1798666.000438483, "q": 3476627.872944676, "i": 20.54501257148846, "s": 3914350.616394652, "pf": 0.4595055928063901, "id_reference": {"table": "ext_grid", "index": 1}, "pgm_input": {"node": 0}} + {"id": 7, "energized": 1, "p": 1798665.985464717, "q": 3476628.9831677, "i": 20.54501771091204, "s": 3914351.595586354, "pf": 0.4595054740337613, "id_reference": {"table": "ext_grid", "index": 1}, "pgm_input": {"node": 0}} ], "sym_load": [ - {"id": 8, "energized": 1, "p": 575000, "q": 55200, "i": 17.13761141048308, "s": 577643.5232909652, "pf": 0.9954236078405164, "id_reference": {"table": "load", "name": "const_power", "index": 101}, "pgm_input": {"node": 2}}, - {"id": 9, "energized": 1, "p": 1207113.683543022, "q": 115882.9136201301, "i": 35.97746997710809, "s": 1212663.306390481, "pf": 0.9954236078405161, "id_reference": {"table": "load", "name": "const_impedance", "index": 101}, "pgm_input": {"node": 2}}, - {"id": 10, "energized": 1, "p": 632458.9617296124, "q": 60716.06032604279, "i": 18.85014942469511, "s": 635366.6486790245, "pf": 0.9954236078405163, "id_reference": {"table": "load", "name": "const_current", "index": 101}, "pgm_input": {"node": 2}}, + {"id": 8, "energized": 1, "p": 575000, "q": 55200, "i": 17.13761141048306, "s": 577643.5232909652, "pf": 0.9954236078405164, "id_reference": {"table": "load", "name": "const_power", "index": 101}, "pgm_input": {"node": 2}}, + {"id": 9, "energized": 1, "p": 1207113.683543025, "q": 115882.9136201304, "i": 35.97746997710814, "s": 1212663.306390484, "pf": 0.9954236078405164, "id_reference": {"table": "load", "name": "const_impedance", "index": 101}, "pgm_input": {"node": 2}}, + {"id": 10, "energized": 1, "p": 632458.9617296132, "q": 60716.06032604287, "i": 18.85014942469511, "s": 635366.6486790254, "pf": 0.9954236078405163, "id_reference": {"table": "load", "name": "const_current", "index": 101}, "pgm_input": {"node": 2}}, {"id": 18, "energized": 1, "p": 99999.99999999999, "q": 99999.99999999999, "i": 1.400031432537213, "s": 141421.3562373095, "pf": 0.7071067811865475, "id_reference": {"table": "ward", "name": "ward_const_power_load", "index": 34}, "pgm_input": {"node": 4}}, - {"id": 19, "energized": 1, "p": 94477.99488734086, "q": 94477.99488734086, "i": 1.322721625253674, "s": 133612.0617154934, "pf": 0.7071067811865475, "id_reference": {"table": "ward", "name": "ward_const_impedance_load", "index": 34}, "pgm_input": {"node": 4}}, - {"id": 20, "energized": 1, "p": 71111.11111111111, "q": 34440.68301069173, "i": 0.7821998773897324, "s": 79012.34567901235, "pf": 0.9, "id_reference": {"table": "motor", "name": "motor_load", "index": 12}, "pgm_input": {"node": 4}} + {"id": 19, "energized": 1, "p": 94477.99488734089, "q": 94477.99488734089, "i": 1.322721625253674, "s": 133612.0617154934, "pf": 0.7071067811865476, "id_reference": {"table": "ward", "name": "ward_const_impedance_load", "index": 34}, "pgm_input": {"node": 4}}, + {"id": 20, "energized": 1, "p": 71111.11111111111, "q": 34440.68301069173, "i": 0.7821998773897323, "s": 79012.34567901235, "pf": 0.9, "id_reference": {"table": "motor", "name": "motor_load", "index": 12}, "pgm_input": {"node": 4}} ], "shunt": [ - {"id": 11, "energized": 1, "p": 282008.0001416396, "q": 1551044.000779018, "i": 31.18812237569019, "s": 1576472.646288691, "pf": 0.1788854381999832, "id_reference": {"table": "shunt", "index": 1201}, "pgm_input": {"node": 3}} + {"id": 11, "energized": 1, "p": 282008.0001416397, "q": 1551044.000779018, "i": 31.1881223756902, "s": 1576472.646288692, "pf": 0.1788854381999832, "id_reference": {"table": "shunt", "index": 1201}, "pgm_input": {"node": 3}} ], "transformer": [ - {"id": 12, "energized": 1, "loading": 0.04892939318768632, "p_from": 1798665.9834271, "q_from": 3476628.825951878, "i_from": 20.54501697310328, "s_from": 3914351.455014905, "p_to": -1765096.677117184, "q_to": -1169229.770073524, "i_to": 62.76706374195551, "s_to": 2117230.392469442, "id_reference": {"table": "trafo", "index": 101}, "pgm_input": {"from_node": 0, "to_node": 1}, "pp_input": {"df": 1.0}} + {"id": 12, "energized": 1, "loading": 0.04892939318768137, "p_from": 1798665.98342602, "q_from": 3476628.825951991, "i_from": 20.5450169731012, "s_from": 3914351.455014509, "p_to": -1765096.677116123, "q_to": -1169229.77007363, "i_to": 62.76706374193096, "s_to": 2117230.392468616, "id_reference": {"table": "trafo", "index": 101}, "pgm_input": {"from_node": 0, "to_node": 1}, "pp_input": {"df": 1.0}} ], "sym_gen": [ @@ -39,7 +39,7 @@ ], "three_winding_transformer": [ - {"id": 14, "energized": 1, "loading": 0.03152945292576947, "p_1": -651018.5317680555, "q_1": 1013282.712651781, "i_1": 35.73216058618558, "s_1": 1204394.862353865, "p_2": 944410.894001629, "q_2": 581081.3221020879, "i_2": 10.97738675283968, "s_2": 1108858.62020587, "p_3": -282008.0001417859, "q_3": -1551044.00077877, "i_3": 31.18812237568588, "s_3": 1576472.646288473, "id_reference": {"table": "trafo3w", "index": 102}, "pgm_input": {"node_1": 2, "node_2": 4, "node_3": 3}} + {"id": 14, "energized": 1, "loading": 0.03152945292577451, "p_1": -651018.5317681322, "q_1": 1013282.712652206, "i_1": 35.73216058619739, "s_1": 1204394.862354265, "p_2": 944410.8940017537, "q_2": 581081.3221016526, "i_2": 10.97738675283847, "s_2": 1108858.620205748, "p_3": -282008.0001416156, "q_3": -1551044.000779057, "i_3": 31.18812237569086, "s_3": 1576472.646288725, "id_reference": {"table": "trafo3w", "index": 102}, "pgm_input": {"node_1": 2, "node_2": 4, "node_3": 3}} ], "link": [ @@ -47,10 +47,10 @@ ], "asym_load": [ - {"id": 16, "energized": 1, "p": 3300000, "q": 30000, "i": 32.67041668765106, "s": 3300136.36081905, "pf": 0.9999586802470745, "id_reference": {"table": "asymmetric_load", "index": 33}, "pgm_input": {"node": 4}} + {"id": 16, "energized": 1, "p": 3300000, "q": 30000, "i": 32.67041668765105, "s": 3300136.36081905, "pf": 0.9999586802470745, "id_reference": {"table": "asymmetric_load", "index": 33}, "pgm_input": {"node": 4}} ], "asym_gen": [ - {"id": 17, "energized": 1, "p": 3300000, "q": 30000, "i": 32.67041668765106, "s": 3300136.36081905, "pf": 0.9999586802470745, "id_reference": {"table": "asymmetric_sgen", "index": 32}, "pgm_input": {"node": 4}} + {"id": 17, "energized": 1, "p": 3300000, "q": 30000, "i": 32.67041668765105, "s": 3300136.36081905, "pf": 0.9999586802470745, "id_reference": {"table": "asymmetric_sgen", "index": 32}, "pgm_input": {"node": 4}} ] } From 47c5bacd5161a545a6fde167af51380d1b81ae53 Mon Sep 17 00:00:00 2001 From: Zhen Wang Date: Mon, 8 Apr 2024 15:42:31 +0200 Subject: [PATCH 6/6] Pause this ticket Signed-off-by: Zhen Wang --- .../converters/tabular_converter.py | 71 ++++++++++--------- .../functions/_functions.py | 36 +--------- .../functions/phase_to_phase.py | 36 ++++++++++ tests/data/vision/vision_9_7_en.yaml | 18 ++--- .../unit/converters/test_tabular_converter.py | 4 +- tests/unit/functions/test_phase_to_phase.py | 20 ++++++ 6 files changed, 105 insertions(+), 80 deletions(-) diff --git a/src/power_grid_model_io/converters/tabular_converter.py b/src/power_grid_model_io/converters/tabular_converter.py index 4f798a88..9052d968 100644 --- a/src/power_grid_model_io/converters/tabular_converter.py +++ b/src/power_grid_model_io/converters/tabular_converter.py @@ -117,7 +117,7 @@ def _parse_data(self, data: TabularData, data_type: str, extra_info: Optional[Ex # For each table in the mapping for table in self._mapping.tables(): - if table not in data or len(data[table]) == 0: + if table not in data or len(data[table][table_mask]) == 0: continue # pragma: no cover (bug in python 3.9) for component, attributes in self._mapping.instances(table=table): component_data = self._convert_table_to_component( @@ -178,10 +178,9 @@ def _convert_table_to_component( if table not in data: return None - table_mask = np.arary(True) * len(data[table]) + table_mask = np.full(len(data[table]), True) if "filter" in attributes: - table_mask = self._parse_filters() - pass + table_mask = self._parse_filters(data, table) n_records = np.sum(table_mask) @@ -201,13 +200,14 @@ def _convert_table_to_component( for attr, col_def in sorted_attributes: self._convert_col_def_to_attribute( - data=data[table_mask], + data=data, pgm_data=pgm_data, table=table, component=component, attr=attr, col_def=col_def, extra_info=extra_info, + table_mask=table_mask ) return pgm_data @@ -221,8 +221,8 @@ def _convert_col_def_to_attribute( component: str, attr: str, col_def: Any, - table_mask: np.ndarray, extra_info: Optional[ExtraInfo], + table_mask: np.ndarray ): """This function updates one of the attributes of pgm_data, based on the corresponding table/column in a tabular dataset @@ -259,12 +259,12 @@ def _convert_col_def_to_attribute( # Extra info must be linked to the object IDs, therefore the uuids should be known before extra info can # be parsed. Before this for loop, it is checked that "id" exists and it is placed at the front. self._handle_extra_info( - data=data[table_mask], table=table, col_def=col_def, uuids=pgm_data["id"], extra_info=extra_info + data=data, table=table, col_def=col_def, uuids=pgm_data["id"], extra_info=extra_info, table_mask=table_mask ) # Extra info should not be added to the numpy arrays, so let's continue to the next attribute return - attr_data = self._parse_col_def(data=data[table_mask], table=table, col_def=col_def, extra_info=extra_info) + attr_data = self._parse_col_def(data=data, table=table, col_def=col_def, extra_info=extra_info, table_mask=table_mask) if len(attr_data.columns) != 1: raise ValueError(f"DataFrame for {component}.{attr} should contain a single column ({attr_data.columns})") @@ -275,7 +275,7 @@ def _parse_filters(self) -> pd.Series: mask = True * pd.DataFrame(True, shape=data.shape) for function, args in mapping["filter"].items(): mask &= data.apply(function, arg) - + return pd.Series() def _handle_extra_info( @@ -285,6 +285,7 @@ def _handle_extra_info( col_def: Any, uuids: np.ndarray, extra_info: Optional[ExtraInfo], + table_mask ) -> None: """This function can extract extra info from the tabular data and store it in the extra_info dict @@ -308,7 +309,7 @@ def _handle_extra_info( if extra_info is None: return - extra = self._parse_col_def(data=data, table=table, col_def=col_def, extra_info=None).to_dict(orient="records") + extra = self._parse_col_def(data=data, table=table, col_def=col_def, extra_info=None, table_mask=table_mask).to_dict(orient="records") for i, xtr in zip(uuids, extra): xtr = { k[0] if isinstance(k, tuple) else k: v @@ -355,7 +356,7 @@ def _serialize_data(self, data: Dataset, extra_info: Optional[ExtraInfo]) -> Tab return TabularData(logger=self._log, **data) def _parse_col_def( - self, data: TabularData, table: str, col_def: Any, extra_info: Optional[ExtraInfo] + self, data: TabularData, table: str, col_def: Any, extra_info: Optional[ExtraInfo], table_mask ) -> pd.DataFrame: """Interpret the column definition and extract/convert/create the data as a pandas DataFrame. @@ -369,17 +370,17 @@ def _parse_col_def( """ if isinstance(col_def, (int, float)): - return self._parse_col_def_const(data=data, table=table, col_def=col_def) + return self._parse_col_def_const(data=data, table=table, col_def=col_def, table_mask=table_mask) if isinstance(col_def, str): - return self._parse_col_def_column_name(data=data, table=table, col_def=col_def) + return self._parse_col_def_column_name(data=data, table=table, col_def=col_def, table_mask=table_mask) if isinstance(col_def, dict): - return self._parse_col_def_filter(data=data, table=table, col_def=col_def, extra_info=extra_info) + return self._parse_col_def_filter(data=data, table=table, col_def=col_def, extra_info=extra_info, table_mask=table_mask) if isinstance(col_def, list): - return self._parse_col_def_composite(data=data, table=table, col_def=col_def) + return self._parse_col_def_composite(data=data, table=table, col_def=col_def, table_mask=table_mask) raise TypeError(f"Invalid column definition: {col_def}") @staticmethod - def _parse_col_def_const(data: TabularData, table: str, col_def: Union[int, float]) -> pd.DataFrame: + def _parse_col_def_const(data: TabularData, table: str, col_def: Union[int, float], table_mask) -> pd.DataFrame: """Create a single column pandas DataFrame containing the const value. Args: @@ -392,9 +393,9 @@ def _parse_col_def_const(data: TabularData, table: str, col_def: Union[int, floa """ assert isinstance(col_def, (int, float)) - return pd.DataFrame([col_def] * len(data[table])) + return pd.DataFrame([col_def] * len(data[table][table_mask])) - def _parse_col_def_column_name(self, data: TabularData, table: str, col_def: str) -> pd.DataFrame: + def _parse_col_def_column_name(self, data: TabularData, table: str, col_def: str, table_mask) -> pd.DataFrame: """Extract a column from the data. If the column doesn't exist, check if the col_def is a special float value, like 'inf'. If that's the case, create a single column pandas DataFrame containing the const value. @@ -407,7 +408,7 @@ def _parse_col_def_column_name(self, data: TabularData, table: str, col_def: str """ assert isinstance(col_def, str) - table_data = data[table] + table_data = data[table][table_mask] # If multiple columns are given in col_def, return the first column that exists in the dataset columns = [col_name.strip() for col_name in col_def.split("|")] @@ -437,7 +438,7 @@ def _apply_multiplier(self, table: str, column: str, data: pd.Series) -> pd.Seri return data def _parse_reference( - self, data: TabularData, table: str, other_table: str, query_column: str, key_column: str, value_column: str + self, data: TabularData, table: str, other_table: str, query_column: str, key_column: str, value_column: str, table_mask ) -> pd.DataFrame: """ Find and extract a column from a different table. @@ -453,15 +454,15 @@ def _parse_reference( Returns: """ - queries = self._parse_col_def_column_name(data=data, table=table, col_def=query_column) - keys = self._parse_col_def_column_name(data=data, table=other_table, col_def=key_column) - values = self._parse_col_def_column_name(data=data, table=other_table, col_def=value_column) + queries = self._parse_col_def_column_name(data=data, table=table, col_def=query_column, table_mask=table_mask) + keys = self._parse_col_def_column_name(data=data, table=other_table, col_def=key_column, table_mask=table_mask) + values = self._parse_col_def_column_name(data=data, table=other_table, col_def=value_column, table_mask=table_mask) other = pd.concat([keys, values], axis=1) result = queries.merge(other, how="left", left_on=query_column, right_on=key_column) return result[[value_column]] def _parse_col_def_filter( - self, data: TabularData, table: str, col_def: Dict[str, Any], extra_info: Optional[ExtraInfo] + self, data: TabularData, table: str, col_def: Dict[str, Any], extra_info: Optional[ExtraInfo], table_mask ) -> pd.DataFrame: """ Parse column filters like 'auto_id', 'reference', 'function', etc @@ -484,6 +485,7 @@ def _parse_col_def_filter( ref_name=sub_def.get("name"), key_col_def=sub_def["key"], extra_info=extra_info, + table_mask=table_mask, ) elif name == "reference": # Check that (only) the required keys are in the definition @@ -501,11 +503,12 @@ def _parse_col_def_filter( query_column=sub_def["query_column"], key_column=sub_def["key_column"], value_column=sub_def["value_column"], + table_mask=table_mask ) elif isinstance(sub_def, list): - col_data = self._parse_pandas_function(data=data, table=table, fn_name=name, col_def=sub_def) + col_data = self._parse_pandas_function(data=data, table=table, fn_name=name, col_def=sub_def, table_mask=table_mask) elif isinstance(sub_def, dict): - col_data = self._parse_function(data=data, table=table, function=name, col_def=sub_def) + col_data = self._parse_function(data=data, table=table, function=name, col_def=sub_def, table_mask=table_mask) else: raise TypeError(f"Invalid {name} definition: {sub_def}") data_frames.append(col_data) @@ -519,6 +522,7 @@ def _parse_auto_id( ref_name: Optional[str], key_col_def: Union[str, List[str], Dict[str, str]], extra_info: Optional[ExtraInfo], + table_mask, ) -> pd.DataFrame: """ Create (or retrieve) a unique numerical id for each object (row) in `data[table]`, based on the `name` @@ -551,7 +555,7 @@ def _parse_auto_id( else: raise TypeError(f"Invalid key definition type '{type(key_col_def).__name__}': {key_col_def}") - col_data = self._parse_col_def(data=data, table=table, col_def=key_col_def, extra_info=None) + col_data = self._parse_col_def(data=data, table=table, col_def=key_col_def, extra_info=None, table_mask=table_mask) def auto_id(row: np.ndarray): key = dict(zip(key_names, row)) @@ -574,7 +578,7 @@ def auto_id(row: np.ndarray): return col_data.apply(auto_id, axis=1, raw=True) - def _parse_pandas_function(self, data: TabularData, table: str, fn_name: str, col_def: List[Any]) -> pd.DataFrame: + def _parse_pandas_function(self, data: TabularData, table: str, fn_name: str, col_def: List[Any], table_mask) -> pd.DataFrame: """Special vectorized functions. Args: @@ -592,7 +596,7 @@ def _parse_pandas_function(self, data: TabularData, table: str, fn_name: str, co if fn_name == "multiply": fn_name = "prod" - col_data = self._parse_col_def(data=data, table=table, col_def=col_def, extra_info=None) + col_data = self._parse_col_def(data=data, table=table, col_def=col_def, extra_info=None, table_mask=table_mask) try: fn_ptr = getattr(col_data, fn_name) @@ -615,7 +619,7 @@ def _parse_pandas_function(self, data: TabularData, table: str, fn_name: str, co return pd.DataFrame(fn_ptr(axis=1)) - def _parse_function(self, data: TabularData, table: str, function: str, col_def: Dict[str, Any]) -> pd.DataFrame: + def _parse_function(self, data: TabularData, table: str, function: str, col_def: Dict[str, Any], table_mask) -> pd.DataFrame: """Import the function by name and apply it to each row. Args: @@ -632,15 +636,14 @@ def _parse_function(self, data: TabularData, table: str, function: str, col_def: fn_ptr = get_function(function) key_words = list(col_def.keys()) sub_def = list(col_def.values()) - col_data = self._parse_col_def(data=data, table=table, col_def=sub_def, extra_info=None) + col_data = self._parse_col_def(data=data, table=table, col_def=sub_def, extra_info=None, table_mask=table_mask) if col_data.empty: raise ValueError(f"Cannot apply function {function} to an empty DataFrame") - col_data = col_data.apply(lambda row, fn=fn_ptr: fn(**dict(zip(key_words, row))), axis=1, raw=True) return pd.DataFrame(col_data) - def _parse_col_def_composite(self, data: TabularData, table: str, col_def: list) -> pd.DataFrame: + def _parse_col_def_composite(self, data: TabularData, table: str, col_def: list, table_mask) -> pd.DataFrame: """Select multiple columns (each is created from a column definition) and return them as a new DataFrame. Args: @@ -652,7 +655,7 @@ def _parse_col_def_composite(self, data: TabularData, table: str, col_def: list) """ assert isinstance(col_def, list) - columns = [self._parse_col_def(data=data, table=table, col_def=sub_def, extra_info=None) for sub_def in col_def] + columns = [self._parse_col_def(data=data, table=table, col_def=sub_def, extra_info=None, table_mask=table_mask) for sub_def in col_def] return pd.concat(columns, axis=1) def _get_id(self, table: str, key: Mapping[str, int], name: Optional[str]) -> int: diff --git a/src/power_grid_model_io/functions/_functions.py b/src/power_grid_model_io/functions/_functions.py index cab60bfc..d53a0efb 100644 --- a/src/power_grid_model_io/functions/_functions.py +++ b/src/power_grid_model_io/functions/_functions.py @@ -24,30 +24,6 @@ "ZN": WindingType.zigzag_n, } -MEASURED_TERMINAL_TYPE_MAP = { - "cable_from": MeasuredTerminalType.branch_from, - "cable_to": MeasuredTerminalType.branch_to, - "line_from": MeasuredTerminalType.branch_from, - "line_to": MeasuredTerminalType.branch_to, - "reactance_coil_from": MeasuredTerminalType.branch_from, - "reactance_coil_to": MeasuredTerminalType.branch_to, - "special_transformer_from": MeasuredTerminalType.branch_from, - "special_transformer_to": MeasuredTerminalType.branch_to, - "transformer_from": MeasuredTerminalType.branch_from, - "transformer_to": MeasuredTerminalType.branch_to, - "transformer_load": MeasuredTerminalType.branch_to, - "earthing_transformer": MeasuredTerminalType.branch_from, - "transformer3_1": MeasuredTerminalType.branch3_1, - "transformer3_2": MeasuredTerminalType.branch3_2, - "transformer3_3": MeasuredTerminalType.branch3_3, - "source": MeasuredTerminalType.source, - "shunt_capacitor": MeasuredTerminalType.shunt, - "shunt_reactor": MeasuredTerminalType.shunt, - "pv": MeasuredTerminalType.generator, - "wind_turbine": MeasuredTerminalType.generator, - "load": MeasuredTerminalType.load, -} - def has_value(value: Any) -> bool: """ @@ -129,19 +105,9 @@ def both_zeros_to_nan(value: float, other_value: float) -> float: return float("nan") return value - -def find_terminal_type(**kwargs) -> MeasuredTerminalType: - """ - Return the measured terminal type, based on the string representation - """ - for key, id in kwargs.items(): - if id is not None: - return MEASURED_TERMINAL_TYPE_MAP[key] - _LOG.warning("No measured terminal type is found!") - return float("nan") - def filter_if_object(object_name: str, excl_object: str) -> bool: """ Return false if the measured object should be excluded. """ return object_name != excl_object + diff --git a/src/power_grid_model_io/functions/phase_to_phase.py b/src/power_grid_model_io/functions/phase_to_phase.py index 02110331..61068652 100644 --- a/src/power_grid_model_io/functions/phase_to_phase.py +++ b/src/power_grid_model_io/functions/phase_to_phase.py @@ -12,9 +12,34 @@ from power_grid_model_io.functions import get_winding from power_grid_model_io.utils.parsing import parse_pvs_efficiency_type, parse_trafo3_connection, parse_trafo_connection +from power_grid_model import MeasuredTerminalType _LOG = structlog.get_logger(__file__) +MEASURED_TERMINAL_TYPE_MAP = { + "cable_from": MeasuredTerminalType.branch_from, + "cable_to": MeasuredTerminalType.branch_to, + "line_from": MeasuredTerminalType.branch_from, + "line_to": MeasuredTerminalType.branch_to, + "reactance_coil_from": MeasuredTerminalType.branch_from, + "reactance_coil_to": MeasuredTerminalType.branch_to, + "special_transformer_from": MeasuredTerminalType.branch_from, + "special_transformer_to": MeasuredTerminalType.branch_to, + "transformer_from": MeasuredTerminalType.branch_from, + "transformer_to": MeasuredTerminalType.branch_to, + "transformer_load": MeasuredTerminalType.branch_to, + "earthing_transformer": MeasuredTerminalType.branch_from, + "transformer3_1": MeasuredTerminalType.branch3_1, + "transformer3_2": MeasuredTerminalType.branch3_2, + "transformer3_3": MeasuredTerminalType.branch3_3, + "source": MeasuredTerminalType.source, + "shunt_capacitor": MeasuredTerminalType.shunt, + "shunt_reactor": MeasuredTerminalType.shunt, + "pv": MeasuredTerminalType.generator, + "wind_turbine": MeasuredTerminalType.generator, + "load": MeasuredTerminalType.load, +} + def relative_no_load_current(i_0: float, p_0: float, s_nom: float, u_nom: float) -> float: """ @@ -130,3 +155,14 @@ def pvs_power_adjustment(p: float, efficiency_type: str) -> float: return p * 0.95 return p + +def get_measured_terminal_type(**kwargs) -> MeasuredTerminalType: + """ + Return the measured terminal type, based on the string representation + """ + for key, id in kwargs.items(): + if id is not None: + return MEASURED_TERMINAL_TYPE_MAP[key] + _LOG.warning("No measured terminal type is found!") + return float("nan") + diff --git a/tests/data/vision/vision_9_7_en.yaml b/tests/data/vision/vision_9_7_en.yaml index 042ed647..e217b0a6 100644 --- a/tests/data/vision/vision_9_7_en.yaml +++ b/tests/data/vision/vision_9_7_en.yaml @@ -805,8 +805,8 @@ grid: u_sigma: nan filter: - power_grid_model_io.functions.has_value: - - power_1 - - power_grid_model_io.functions.filter_if_object: + value: power_1 + - power_grid_model_io.phase_to_phase.filter_if_object: object: InObject.Sort excl_object: link extra: @@ -821,7 +821,7 @@ grid: table: Nodes GUID: InObject.Number measured_terminal_type: - - power_grid_model_io.functions.find_terminal_type: + - power_grid_model_io.phase_to_phase.get_measured_terminal_type: cable_from: auto_id: table: Cables @@ -933,7 +933,7 @@ grid: q_sigma: nan filter: - power_grid_model_io.functions.has_value: - - power_2 + value: power_2 - power_grid_model_io.functions.filter_if_object: object: InObject.Sort excl_object: link @@ -949,7 +949,7 @@ grid: table: Nodes GUID: InObject.Number measured_terminal_type: - - power_grid_model_io.functions.find_terminal_type: + - power_grid_model_io.phase_to_phase.get_measured_terminal_type: cable_from: auto_id: table: Cables @@ -1061,7 +1061,7 @@ grid: q_sigma: nan filter: - power_grid_model_io.functions.has_value: - - power_3 + value: power_3 - power_grid_model_io.functions.filter_if_object: object: InObject.Sort excl_object: link @@ -1077,7 +1077,7 @@ grid: table: Nodes GUID: InObject.Number measured_terminal_type: - - power_grid_model_io.functions.find_terminal_type: + - power_grid_model_io.phase_to_phase.get_measured_terminal_type: cable_from: auto_id: table: Cables @@ -1189,9 +1189,9 @@ grid: q_sigma: nan filter: - power_grid_model_io.functions.has_value: - - power_4 + value: power_4 - power_grid_model_io.functions.filter_if_object: - object: InObject.Sort + object_name: InObject.Sort excl_object: link extra: - ID diff --git a/tests/unit/converters/test_tabular_converter.py b/tests/unit/converters/test_tabular_converter.py index 895ffb7b..1836a424 100644 --- a/tests/unit/converters/test_tabular_converter.py +++ b/tests/unit/converters/test_tabular_converter.py @@ -67,14 +67,14 @@ def test_set_mapping_file(converter: TabularConverter): with pytest.raises(ValueError, match="Mapping file should be a .yaml file, .txt provided."): converter.set_mapping_file(mapping_file=Path("dummy/path.txt")) - dummy_path = Path(__file__).parents[2] / "data" / "config" / "dummy_mapping.yaml" + dummy_path = Path(__file__).parents[2] / "data" / "config" / "dummy.yaml" with pytest.raises(KeyError, match="Missing 'grid' mapping in mapping_file"): converter.set_mapping_file(mapping_file=dummy_path) converter.set_mapping_file(mapping_file=MAPPING_FILE) -def test_parse_data(converter: TabularConverter, tabular_data: TabularData): +def test_parse_data(converter: TabularConverter, tabular_data: TabularData, table_mask): data = MagicMock() converter._parse_data(data=data, data_type="dummy", extra_info=None) data.set_unit_multipliers.assert_called_once() diff --git a/tests/unit/functions/test_phase_to_phase.py b/tests/unit/functions/test_phase_to_phase.py index a12e57f1..17605b20 100644 --- a/tests/unit/functions/test_phase_to_phase.py +++ b/tests/unit/functions/test_phase_to_phase.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: MPL-2.0 import numpy as np from power_grid_model.enum import WindingType +from power_grid_model.enum import MeasuredTerminalType from pytest import approx, mark, param, raises from power_grid_model_io.functions.phase_to_phase import ( @@ -19,6 +20,7 @@ reactive_power, reactive_power_to_susceptance, relative_no_load_current, + get_measured_terminal_type, ) @@ -401,3 +403,21 @@ def test_reactive_power_to_susceptance(q_var: float, u_nom: float, expected: flo def test_pvs_power_adjustment(p: float, efficiency_type: str, expected: float): actual = pvs_power_adjustment(p, efficiency_type) assert actual == approx(expected) or (np.isnan(actual) and np.isnan(expected)) + + +@mark.parametrize( + ("code", "measured_terminal_type"), + [ + ("cable_from", MeasuredTerminalType.branch_from), + ("transformer_load", MeasuredTerminalType.branch_to), + ("earthing_transformer", MeasuredTerminalType.branch_from), + ("source", MeasuredTerminalType.source), + ("shunt_capacitor", MeasuredTerminalType.shunt), + ("shunt_reactor", MeasuredTerminalType.shunt), + ("pv", MeasuredTerminalType.generator), + ("wind_turbine", MeasuredTerminalType.generator), + ("load", MeasuredTerminalType.load), + ], +) +def test_get_measured_terminal_type(code: str, measured_terminal_type: MeasuredTerminalType): + assert get_measured_terminal_type(code) == measured_terminal_type \ No newline at end of file