From 66ab1f93f5709cb965cef490bbb6fd0548de81d7 Mon Sep 17 00:00:00 2001 From: Nitish Bharambe Date: Sat, 16 Nov 2024 01:23:47 +0100 Subject: [PATCH 1/6] add helper function Signed-off-by: Nitish Bharambe --- src/power_grid_model/_core/power_grid_meta.py | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/power_grid_model/_core/power_grid_meta.py b/src/power_grid_model/_core/power_grid_meta.py index 0d375601b..179631689 100644 --- a/src/power_grid_model/_core/power_grid_meta.py +++ b/src/power_grid_model/_core/power_grid_meta.py @@ -21,7 +21,7 @@ _str_to_datatype, ) from power_grid_model._core.power_grid_core import AttributePtr, ComponentPtr, DatasetPtr, power_grid_core as pgc -from power_grid_model.data_types import DenseBatchArray, SingleArray +from power_grid_model.data_types import AttributeType, DenseBatchArray, SingleArray # constant enum for ctype @@ -205,3 +205,41 @@ def initialize_array( dtype=power_grid_meta_data[data_type][component_type].dtype, order="C", ) + + +def attribute_dtype( + data_type: DatasetTypeLike, component_type: ComponentTypeLike, attribute: AttributeType +) -> np.dtype: + """Gives out dtype of the attribute to be used in a columnar data format + + Args: + data_type (DatasetTypeLike): The type of dataset (input, update, sym_output, or asym_output) + component_type (ComponentTypeLike): The type of component (e.g., node) + attribute (AttributeType): The attribute whose dtype is required + + Returns: + np.dtype: The dtype of the specified attribute + """ + data_type = _str_to_datatype(data_type) + component_type = _str_to_component_type(component_type) + return power_grid_meta_data[data_type][component_type].dtype[attribute] + + +def attribute_empty_value( + data_type: DatasetTypeLike, component_type: ComponentTypeLike, attribute: AttributeType +) -> np.ndarray: + """ + Returns the empty value for a specific attribute in the Power Grid Model. + + + Args: + data_type (DatasetTypeLike): The type of dataset (input, update, sym_output, or asym_output) + component_type (ComponentTypeLike): The type of component (e.g., node) + attribute (AttributeType): The attribute whose empty value is required + + Returns: + np.ndarray: The empty value for the specified attribute + """ + data_type = _str_to_datatype(data_type) + component_type = _str_to_component_type(component_type) + return power_grid_meta_data[data_type][component_type].nan_scalar[attribute] From f1844f3c0cd9a759623e805d478c1e7faabfe5de Mon Sep 17 00:00:00 2001 From: Nitish Bharambe Date: Sat, 16 Nov 2024 01:24:00 +0100 Subject: [PATCH 2/6] add tests Signed-off-by: Nitish Bharambe --- src/power_grid_model/__init__.py | 7 ++++- tests/unit/test_meta_data.py | 54 +++++++++++++++++++++++--------- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/power_grid_model/__init__.py b/src/power_grid_model/__init__.py index c22dbdb35..78bb8f278 100644 --- a/src/power_grid_model/__init__.py +++ b/src/power_grid_model/__init__.py @@ -5,7 +5,12 @@ """Power Grid Model""" from power_grid_model._core.dataset_definitions import ComponentType, DatasetType -from power_grid_model._core.power_grid_meta import initialize_array, power_grid_meta_data +from power_grid_model._core.power_grid_meta import ( + attribute_dtype, + attribute_empty_value, + initialize_array, + power_grid_meta_data, +) from power_grid_model._core.power_grid_model import PowerGridModel from power_grid_model.enum import ( Branch3Side, diff --git a/tests/unit/test_meta_data.py b/tests/unit/test_meta_data.py index 6c1f06237..2c4d67873 100644 --- a/tests/unit/test_meta_data.py +++ b/tests/unit/test_meta_data.py @@ -4,33 +4,56 @@ import numpy as np -from power_grid_model import initialize_array, power_grid_meta_data +from power_grid_model import ( + attribute_dtype, + attribute_empty_value, + initialize_array, + power_grid_meta_data, + DatasetType, + ComponentType, +) def test_nan_scalar(): - assert np.isnan(power_grid_meta_data["input"]["node"].nan_scalar["u_rated"]) + assert np.isnan(power_grid_meta_data[DatasetType.input][ComponentType.node].nan_scalar["u_rated"]) def test_initialize_array(): - arr = initialize_array("input", "node", 3) + arr = initialize_array(DatasetType.input, ComponentType.node, 3) assert arr.shape == (3,) assert np.all(np.isnan(arr["u_rated"])) - arr_2d = initialize_array("input", "node", (2, 3)) + arr_2d = initialize_array(DatasetType.input, ComponentType.node, (2, 3)) assert arr_2d.shape == (2, 3) assert np.all(np.isnan(arr_2d["u_rated"])) +def test_attribute_dtype(): + assert attribute_dtype(DatasetType.input, ComponentType.node, "u_rated") == np.float64 + assert attribute_dtype(DatasetType.input, ComponentType.node, "id") == np.int32 + + +def test_attribute_empty_value(): + empty_value = attribute_empty_value(DatasetType.input, ComponentType.node, "u_rated") + assert np.isnan(empty_value) + empty_value = attribute_empty_value(DatasetType.input, ComponentType.node, "id") + assert empty_value == np.iinfo(np.int32).min + + def test_sensor_meta_data(): - sensors = ["sym_voltage_sensor", "asym_voltage_sensor", "sym_power_sensor", "asym_power_sensor"] + sensors = [ + ComponentType.sym_voltage_sensor, + ComponentType.asym_voltage_sensor, + ComponentType.sym_power_sensor, + ComponentType.asym_power_sensor, + ] input_voltage = ["u_measured", "u_angle_measured", "u_sigma"] output_voltage = ["u_residual", "u_angle_residual"] input_power = ["p_measured", "q_measured", "power_sigma"] output_power = ["p_residual", "q_residual"] for sensor in sensors: - for meta_type in ["input", "update", "sym_output", "asym_output"]: + for meta_type in [DatasetType.input, DatasetType.update, DatasetType.sym_output, DatasetType.asym_output]: meta_data = power_grid_meta_data[meta_type] - # comp_names = list(meta_data.keys()) - # assert sensor in comp_names + assert sensor in meta_data meta_data_sensor = meta_data[sensor] attr_names = meta_data_sensor.dtype_dict["names"] assert "id" in attr_names @@ -51,14 +74,17 @@ def test_sensor_meta_data(): def test_dict_like_access(): - assert power_grid_meta_data["input"]["node"].dtype == power_grid_meta_data["input"]["node"]["dtype"] + assert ( + power_grid_meta_data[DatasetType.input][ComponentType.node].dtype + == power_grid_meta_data[DatasetType.input][ComponentType.node]["dtype"] + ) def test_all_datasets(): assert set(power_grid_meta_data.keys()) == { - "input", - "update", - "sym_output", - "asym_output", - "sc_output", + DatasetType.input, + DatasetType.update, + DatasetType.sym_output, + DatasetType.asym_output, + DatasetType.sc_output, } From 6678b596e4d641127a9a934429323c8daa91210a Mon Sep 17 00:00:00 2001 From: Nitish Bharambe Date: Sat, 16 Nov 2024 01:24:39 +0100 Subject: [PATCH 3/6] add docs example Signed-off-by: Nitish Bharambe --- docs/api_reference/python-api-reference.md | 2 + docs/examples/Power Flow Example.ipynb | 49 +++++++++++----------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/docs/api_reference/python-api-reference.md b/docs/api_reference/python-api-reference.md index 00909a7af..2078dda58 100644 --- a/docs/api_reference/python-api-reference.md +++ b/docs/api_reference/python-api-reference.md @@ -14,6 +14,8 @@ This is the Python API reference for the `power-grid-model` library .. autoclass:: PowerGridModel :show-inheritance: .. autofunction:: initialize_array +.. autofunction:: attribute_dtype +.. autofunction:: attribute_empty_value .. py:data:: power_grid_meta_data :type: typing.PowerGridMetaData diff --git a/docs/examples/Power Flow Example.ipynb b/docs/examples/Power Flow Example.ipynb index ab33b40e4..cd62b32d1 100644 --- a/docs/examples/Power Flow Example.ipynb +++ b/docs/examples/Power Flow Example.ipynb @@ -49,7 +49,7 @@ "\n", "from power_grid_model import LoadGenType, ComponentType, DatasetType, ComponentAttributeFilterOptions\n", "from power_grid_model import PowerGridModel, CalculationMethod, CalculationType\n", - "from power_grid_model import initialize_array, power_grid_meta_data" + "from power_grid_model import initialize_array, attribute_dtype" ] }, { @@ -127,7 +127,7 @@ "\n", "A columnar data format better integrates with most databases. In addition, it may bring memory and, in some cases, even computational performance improvements, because unused attribute columns can be omitted.\n", "\n", - "Make sure to provide the correct `dtype` to the numpy arrays, exposed for each dataset type, component and attribute via the `power_grid_meta_data` object." + "Make sure to provide the correct `dtype` to the numpy arrays, exposed for each dataset type, component and attribute via the helper function `attribute_dtype` function." ] }, { @@ -137,12 +137,11 @@ "metadata": {}, "outputs": [], "source": [ - "source_attribute_dtypes = power_grid_meta_data[DatasetType.input][ComponentType.source].dtype\n", "source_columns = {\n", - " \"id\": np.array([10], dtype=source_attribute_dtypes[\"id\"]),\n", - " \"node\": np.array([1], dtype=source_attribute_dtypes[\"node\"]),\n", - " \"status\": np.array([1], dtype=source_attribute_dtypes[\"status\"]),\n", - " \"u_ref\": np.array([1.0], dtype=source_attribute_dtypes[\"u_ref\"]),\n", + " \"id\": np.array([10], dtype=attribute_dtype(DatasetType.input, ComponentType.source, \"id\")),\n", + " \"node\": np.array([1], dtype=attribute_dtype(DatasetType.input, ComponentType.source, \"node\")),\n", + " \"status\": np.array([1], dtype=attribute_dtype(DatasetType.input, ComponentType.source, \"status\")),\n", + " \"u_ref\": np.array([1.0], dtype=attribute_dtype(DatasetType.input, ComponentType.source, \"u_ref\")),\n", " # We're not creating columns for u_ref_angle, sk, ... Instead, the default values are used. This saves us memory.\n", "}\n", "\n", @@ -403,7 +402,7 @@ "List of attribute types in line result\n", "['id', 'p_from']\n", "------line result------\n", - "{'id': array([3, 5, 8], dtype=int32), 'p_from': array([17360100.20222374, -3365613.74450156, 13854413.52498137])}\n" + "{'id': array([3, 5, 8]), 'p_from': array([17360100.20222374, -3365613.74450156, 13854413.52498137])}\n" ] } ], @@ -674,10 +673,11 @@ "metadata": {}, "outputs": [], "source": [ - "line_update_dtype = power_grid_meta_data[DatasetType.update][ComponentType.line].dtype\n", "columnar_update_line = {\n", - " \"id\": np.array([3], dtype=line_update_dtype[\"id\"]), # change line ID 3\n", - " \"from_status\": np.array([0], dtype=line_update_dtype[\"from_status\"]), # switch off at from side\n", + " \"id\": np.array([3], dtype=attribute_dtype(DatasetType.update, ComponentType.line, \"id\")), # change line ID 3\n", + " \"from_status\": np.array(\n", + " [0], dtype=attribute_dtype(DatasetType.update, ComponentType.line, \"from_status\")\n", + " ), # switch off at from side\n", "}\n", "# leave to-side swiching status the same, no need to specify\n", "\n", @@ -699,11 +699,10 @@ "metadata": {}, "outputs": [], "source": [ - "line_update_dtype = power_grid_meta_data[DatasetType.update][ComponentType.line].dtype\n", "columnar_no_ID_update_line = {\n", " # Update IDs are not specified\n", " \"from_status\": np.array(\n", - " [0, 1, 1], dtype=line_update_dtype[\"from_status\"]\n", + " [0, 1, 1], dtype=attribute_dtype(DatasetType.update, ComponentType.line, \"from_status\")\n", " ), # The update for the whole column needs to be specified\n", "}\n", "# leave to-side swiching status the same, no need to specify\n", @@ -1404,16 +1403,16 @@ "output_type": "stream", "text": [ "Node data with invalid results\n", - "[[0.99940117 0.99268579 0.99452137]\n", - " [0.99934769 0.98622639 0.98935286]\n", - " [0.99928838 0.97965401 0.98409554]\n", - " [0. 0. 0. ]\n", - " [0.99915138 0.96614948 0.97329879]\n", - " [0.99907317 0.95920586 0.96775071]\n", - " [0.9989881 0.95212621 0.96209647]\n", - " [0. 0. 0. ]\n", - " [0.99879613 0.93753005 0.95044796]\n", - " [0.9986885 0.92999747 0.94444167]]\n", + "[[9.99401170e-001 9.92685785e-001 9.94521366e-001]\n", + " [9.99347687e-001 9.86226389e-001 9.89352855e-001]\n", + " [9.99288384e-001 9.79654011e-001 9.84095542e-001]\n", + " [6.95296562e-310 8.59448882e-312 6.95296562e-310]\n", + " [9.99151380e-001 9.66149483e-001 9.73298790e-001]\n", + " [9.99073166e-001 9.59205860e-001 9.67750710e-001]\n", + " [9.98988099e-001 9.52126208e-001 9.62096474e-001]\n", + " [8.59448882e-312 8.59448882e-312 6.95296562e-310]\n", + " [9.98796126e-001 9.37530046e-001 9.50447962e-001]\n", + " [9.98688504e-001 9.29997471e-001 9.44441670e-001]]\n", "Node data with only valid results\n", "[[0.99940117 0.99268579 0.99452137]\n", " [0.99934769 0.98622639 0.98935286]\n", @@ -1456,7 +1455,7 @@ ], "metadata": { "kernelspec": { - "display_name": "venv", + "display_name": ".venv", "language": "python", "name": "python3" }, @@ -1470,7 +1469,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.13.0" + "version": "3.12.7" } }, "nbformat": 4, From d2faa4bcf0fa1e9a04ef0a0e9342430b66fc44fb Mon Sep 17 00:00:00 2001 From: Nitish Bharambe Date: Mon, 18 Nov 2024 08:39:37 +0100 Subject: [PATCH 4/6] change import order Signed-off-by: Nitish Bharambe --- tests/unit/test_meta_data.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_meta_data.py b/tests/unit/test_meta_data.py index 2c4d67873..ceba03ac8 100644 --- a/tests/unit/test_meta_data.py +++ b/tests/unit/test_meta_data.py @@ -5,12 +5,12 @@ import numpy as np from power_grid_model import ( + ComponentType, + DatasetType, attribute_dtype, attribute_empty_value, initialize_array, power_grid_meta_data, - DatasetType, - ComponentType, ) From daf58846f8eb1778ceb46ed271c79f5990ca88d0 Mon Sep 17 00:00:00 2001 From: Nitish Bharambe <78108900+nitbharambe@users.noreply.github.com> Date: Mon, 18 Nov 2024 08:41:15 +0100 Subject: [PATCH 5/6] Update src/power_grid_model/_core/power_grid_meta.py Signed-off-by: Nitish Bharambe <78108900+nitbharambe@users.noreply.github.com> --- src/power_grid_model/_core/power_grid_meta.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/power_grid_model/_core/power_grid_meta.py b/src/power_grid_model/_core/power_grid_meta.py index 179631689..ae65e0dd8 100644 --- a/src/power_grid_model/_core/power_grid_meta.py +++ b/src/power_grid_model/_core/power_grid_meta.py @@ -231,7 +231,6 @@ def attribute_empty_value( """ Returns the empty value for a specific attribute in the Power Grid Model. - Args: data_type (DatasetTypeLike): The type of dataset (input, update, sym_output, or asym_output) component_type (ComponentTypeLike): The type of component (e.g., node) From bc0d14917f0edf1f43e056c7b50de8ea350fdf9e Mon Sep 17 00:00:00 2001 From: Nitish Bharambe Date: Mon, 18 Nov 2024 12:11:42 +0100 Subject: [PATCH 6/6] address comments Signed-off-by: Nitish Bharambe --- docs/examples/Power Flow Example.ipynb | 8 ++++---- tests/unit/test_meta_data.py | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/examples/Power Flow Example.ipynb b/docs/examples/Power Flow Example.ipynb index cd62b32d1..123701619 100644 --- a/docs/examples/Power Flow Example.ipynb +++ b/docs/examples/Power Flow Example.ipynb @@ -402,7 +402,7 @@ "List of attribute types in line result\n", "['id', 'p_from']\n", "------line result------\n", - "{'id': array([3, 5, 8]), 'p_from': array([17360100.20222374, -3365613.74450156, 13854413.52498137])}\n" + "{'id': array([3, 5, 8], dtype=int32), 'p_from': array([17360100.20222374, -3365613.74450156, 13854413.52498137])}\n" ] } ], @@ -1406,11 +1406,11 @@ "[[9.99401170e-001 9.92685785e-001 9.94521366e-001]\n", " [9.99347687e-001 9.86226389e-001 9.89352855e-001]\n", " [9.99288384e-001 9.79654011e-001 9.84095542e-001]\n", - " [6.95296562e-310 8.59448882e-312 6.95296562e-310]\n", + " [3.94357132e+180 2.87518198e+161 2.04418455e+214]\n", " [9.99151380e-001 9.66149483e-001 9.73298790e-001]\n", " [9.99073166e-001 9.59205860e-001 9.67750710e-001]\n", " [9.98988099e-001 9.52126208e-001 9.62096474e-001]\n", - " [8.59448882e-312 8.59448882e-312 6.95296562e-310]\n", + " [0.00000000e+000 0.00000000e+000 0.00000000e+000]\n", " [9.98796126e-001 9.37530046e-001 9.50447962e-001]\n", " [9.98688504e-001 9.29997471e-001 9.44441670e-001]]\n", "Node data with only valid results\n", @@ -1469,7 +1469,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.7" + "version": "3.13.0" } }, "nbformat": 4, diff --git a/tests/unit/test_meta_data.py b/tests/unit/test_meta_data.py index ceba03ac8..ea066e8dd 100644 --- a/tests/unit/test_meta_data.py +++ b/tests/unit/test_meta_data.py @@ -82,6 +82,11 @@ def test_dict_like_access(): def test_all_datasets(): assert set(power_grid_meta_data.keys()) == { + "input", + "update", + "sym_output", + "asym_output", + "sc_output", DatasetType.input, DatasetType.update, DatasetType.sym_output,