From f01f3ccfc1dfe7cd2dcfdc198869c0d1f99a0aca Mon Sep 17 00:00:00 2001 From: Nitish Bharambe Date: Fri, 16 Dec 2022 20:51:59 +0100 Subject: [PATCH 01/14] fix i0 and wind turbine Signed-off-by: Nitish Bharambe --- .../config/excel/vision_en.yaml | 2 +- .../functions/phase_to_phase.py | 8 ++++++-- tests/unit/functions/test_phase_to_phase.py | 20 +++++++++---------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/power_grid_model_io/config/excel/vision_en.yaml b/src/power_grid_model_io/config/excel/vision_en.yaml index f99a0b23..5c461e9e 100644 --- a/src/power_grid_model_io/config/excel/vision_en.yaml +++ b/src/power_grid_model_io/config/excel/vision_en.yaml @@ -428,7 +428,7 @@ grid: key: Number: Node.Number status: Switch state - type: 1 + type: 0 p_specified: power_grid_model_io.functions.value_or_default: value: Pref 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 ebe194f7..6b15c9b3 100644 --- a/src/power_grid_model_io/functions/phase_to_phase.py +++ b/src/power_grid_model_io/functions/phase_to_phase.py @@ -20,7 +20,7 @@ def relative_no_load_current(i_0: float, p_0: float, s_nom: float, u_nom: float) """ Calculate the relative no load current. """ - i_rel = max(i_0 / (s_nom / (u_nom / math.sqrt(3))), p_0 / s_nom) + i_rel = max(i_0 / (s_nom / (u_nom * math.sqrt(3))), p_0 / s_nom) if i_rel > 1.0: raise ValueError(f"Relative current can't be more than 100% (got {i_rel * 100.0:.2f}%)") return i_rel @@ -35,11 +35,12 @@ def reactive_power(p: float, cos_phi: float) -> float: def power_wind_speed( # pylint: disable=too-many-arguments p_nom: float, - wind_speed: float, + wind_speed_10: float, cut_in_wind_speed: float = 3.0, nominal_wind_speed: float = 14.0, cutting_out_wind_speed: float = 25.0, cut_out_wind_speed: float = 30.0, + axis_height: float = 30.0, ) -> float: """ Estimate p_ref based on p_nom and wind_speed. @@ -47,6 +48,9 @@ def power_wind_speed( # pylint: disable=too-many-arguments See section "Wind turbine" in https://phasetophase.nl/pdf/VisionEN.pdf """ + # Calculate wind speed at the axis height + wind_speed = wind_speed_10 * (axis_height / 10) ** 0.143 + # At a wind speed below cut-in, the power is zero. if wind_speed < cut_in_wind_speed: return 0.0 diff --git a/tests/unit/functions/test_phase_to_phase.py b/tests/unit/functions/test_phase_to_phase.py index 51db92af..279a101e 100644 --- a/tests/unit/functions/test_phase_to_phase.py +++ b/tests/unit/functions/test_phase_to_phase.py @@ -20,8 +20,8 @@ ("i_0", "p_0", "s_nom", "u_nom", "expected"), [ (float("nan"), float("nan"), float("nan"), float("nan"), float("nan")), - (5.0, 1000.0, 100000.0, 400.0, 0.011547005383792516), - (5.0, 2000.0, 100000.0, 400.0, 0.02), + (5.0, 1000.0, 100000.0, 400.0, 0.0346410161513775), + (5.0, 4000.0, 100000.0, 400.0, 0.04), ], ) def test_relative_no_load_current(i_0: float, p_0: float, s_nom: float, u_nom: float, expected: float): @@ -51,14 +51,14 @@ def test_reactive_power(p: float, cos_phi: float, expected: float): [ (0.0, 0.0), (1.5, 0.0), - (3.0, 0.0), # cut-in - (8.5, 125000.0), - (14.0, 1000000.0), # nominal - (19.5, 1000000.0), - (25.0, 1000000.0), # cutting-out - (27.5, 500000.0), - (30.0, 0.0), # cut-out - (100.0, 0.0), + (2.56385179, 0.0), # cut-in + (7.26424673, 125000.0), + (11.96464167, 1000000.0), # nominal + (16.23772797, 1000000.0), + (21.36543155, 1000000.0), # cutting-out + (23.5019747, 500000.0), + (25.63851786, 0.0), # cut-out + (85.46172618, 0.0), ], ) def test_power_wind_speed(wind_speed, expected): From c95cf63a40b6d84740606fa6fb23728e64e34d0b Mon Sep 17 00:00:00 2001 From: Nitish Bharambe Date: Fri, 16 Dec 2022 20:53:14 +0100 Subject: [PATCH 02/14] add deviation doc Signed-off-by: Nitish Bharambe --- docs/converters/vision_converter.md | 23 +++++++++++++++++++++++ docs/index.md | 1 + 2 files changed, 24 insertions(+) create mode 100644 docs/converters/vision_converter.md diff --git a/docs/converters/vision_converter.md b/docs/converters/vision_converter.md new file mode 100644 index 00000000..f9551874 --- /dev/null +++ b/docs/converters/vision_converter.md @@ -0,0 +1,23 @@ + + +# Vision converter + +The vision converter converts the excel exports of vision to PGM data. As mentioned in [Converters](converters/converter.md), vision converter is an implementation of the tabular converter. +The mapping of all attributes is stored in the `vision_en.yaml` and `vision_nl.yaml` files in [config](https://github.com/alliander-opensource/power-grid-model-io/tree/main/src/power_grid_model_io/config) directory. + +## Load rate of elements + +Certain `elements` in vision, ie. appliances like transformer loads and induction motor have a result parameter of load rate. +In vision the load rate is calculated without considering the simultaneity factor of the connected node. +So we may observe a variation in power inflow/outflow result (ie. P,Q and S) due to different simultaneity factors. But the load rate always corresponds to `simultaneity of loads=1`. + +When we make conversion to PGM, the input data attributes of PGM for loads like `p_specified` and `q_specified` are modified as per simultaneity. The resulting loading then takes simultaneity into account. +**Hence, the loading of such elements may not correspond to the load rate obtained in vision** + +## Unsupported attributes + +- power-grid-model currently does not support PV bus and related corresponding features. Currently, the efficiency type of PVs(Photovoltaics) element is also unsupported for all types except the `100%` type. +- The conversions for load behaviors of `industry`, `residential`, `business` are not yet modelled \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 6527c0f4..b7eade27 100644 --- a/docs/index.md +++ b/docs/index.md @@ -33,6 +33,7 @@ quickstart.md :maxdepth: 2 converters/converter.md converters/tabular_converter.md +converters/vision_converter.md ``` ```{toctree} From 7e9608c728e6edf3f5dd6e4fcf424ef2ee3db11a Mon Sep 17 00:00:00 2001 From: Nitish Bharambe Date: Mon, 19 Dec 2022 09:31:14 +0100 Subject: [PATCH 03/14] change test Signed-off-by: Nitish Bharambe --- tests/unit/functions/test_phase_to_phase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/functions/test_phase_to_phase.py b/tests/unit/functions/test_phase_to_phase.py index 279a101e..aafb6b32 100644 --- a/tests/unit/functions/test_phase_to_phase.py +++ b/tests/unit/functions/test_phase_to_phase.py @@ -30,7 +30,7 @@ def test_relative_no_load_current(i_0: float, p_0: float, s_nom: float, u_nom: f def test_relative_no_load_current__exception(): - with raises(ValueError, match="can't be more than 100% .* 115.47%"): + with raises(ValueError, match="can't be more than 100% .* 346.41%"): relative_no_load_current(500.0, 1000.0, 100000.0, 400.0) From 9f47c9a031c9b95f6fb2c238d8529c384ceaf8ea Mon Sep 17 00:00:00 2001 From: Nitish Bharambe Date: Mon, 19 Dec 2022 09:36:48 +0100 Subject: [PATCH 04/14] add source doc content Signed-off-by: Nitish Bharambe --- docs/converters/vision_converter.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/converters/vision_converter.md b/docs/converters/vision_converter.md index f9551874..bc688fc1 100644 --- a/docs/converters/vision_converter.md +++ b/docs/converters/vision_converter.md @@ -17,7 +17,10 @@ So we may observe a variation in power inflow/outflow result (ie. P,Q and S) due When we make conversion to PGM, the input data attributes of PGM for loads like `p_specified` and `q_specified` are modified as per simultaneity. The resulting loading then takes simultaneity into account. **Hence, the loading of such elements may not correspond to the load rate obtained in vision** -## Unsupported attributes +## Modelling differences or unsupported attributes + +Some components are yet to be modelled for conversions because they might not have a straightforward mapping in power-grid-model. - power-grid-model currently does not support PV bus and related corresponding features. Currently, the efficiency type of PVs(Photovoltaics) element is also unsupported for all types except the `100%` type. -- The conversions for load behaviors of `industry`, `residential`, `business` are not yet modelled \ No newline at end of file +- The conversions for load behaviors of `industry`, `residential`, `business` are not yet modelled +- The source bus in PGM is mapped with a source impedance. `Sk"nom`, `R/X` and `Z0/Z1` are the attributes used in modelling source impedance. In vision, these attributes are used only for short circuit calculations \ No newline at end of file From a345f2dc7b824c6c6977bdf1a9f44f4b4d68fc95 Mon Sep 17 00:00:00 2001 From: Nitish Bharambe Date: Mon, 19 Dec 2022 10:38:07 +0100 Subject: [PATCH 05/14] rename variable Signed-off-by: Nitish Bharambe --- .../functions/phase_to_phase.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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 6b15c9b3..09070e6d 100644 --- a/src/power_grid_model_io/functions/phase_to_phase.py +++ b/src/power_grid_model_io/functions/phase_to_phase.py @@ -35,7 +35,7 @@ def reactive_power(p: float, cos_phi: float) -> float: def power_wind_speed( # pylint: disable=too-many-arguments p_nom: float, - wind_speed_10: float, + wind_speed: float, cut_in_wind_speed: float = 3.0, nominal_wind_speed: float = 14.0, cutting_out_wind_speed: float = 25.0, @@ -49,25 +49,25 @@ def power_wind_speed( # pylint: disable=too-many-arguments """ # Calculate wind speed at the axis height - wind_speed = wind_speed_10 * (axis_height / 10) ** 0.143 + wind_speed_height = wind_speed * (axis_height / 10) ** 0.143 # At a wind speed below cut-in, the power is zero. - if wind_speed < cut_in_wind_speed: + if wind_speed_height < cut_in_wind_speed: return 0.0 # At a wind speed between cut-in and nominal, the power is a third power function of the wind speed. - if wind_speed < nominal_wind_speed: - factor = wind_speed - cut_in_wind_speed + if wind_speed_height < nominal_wind_speed: + factor = wind_speed_height - cut_in_wind_speed max_factor = nominal_wind_speed - cut_in_wind_speed return ((factor / max_factor) ** 3) * p_nom # At a wind speed between nominal and cutting-out, the power is the nominal power. - if wind_speed < cutting_out_wind_speed: + if wind_speed_height < cutting_out_wind_speed: return p_nom # At a wind speed between cutting-out and cut-out, the power decreases from nominal to zero. - if wind_speed < cut_out_wind_speed: - factor = wind_speed - cutting_out_wind_speed + if wind_speed_height < cut_out_wind_speed: + factor = wind_speed_height - cutting_out_wind_speed max_factor = cut_out_wind_speed - cutting_out_wind_speed return (1.0 - factor / max_factor) * p_nom From 0a2eb3f3aab1acd31c2868b94df96150010c3a7b Mon Sep 17 00:00:00 2001 From: Bram Stoeller Date: Tue, 20 Dec 2022 14:59:01 +0100 Subject: [PATCH 06/14] Extend unit test for test_power_wind_speed() Signed-off-by: Bram Stoeller --- tests/unit/functions/test_phase_to_phase.py | 33 ++++++++++++--------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/tests/unit/functions/test_phase_to_phase.py b/tests/unit/functions/test_phase_to_phase.py index aafb6b32..f89a5b0f 100644 --- a/tests/unit/functions/test_phase_to_phase.py +++ b/tests/unit/functions/test_phase_to_phase.py @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MPL-2.0 import numpy as np from power_grid_model.enum import WindingType -from pytest import approx, mark, raises +from pytest import approx, mark, param, raises from power_grid_model_io.functions.phase_to_phase import ( get_clock, @@ -47,22 +47,27 @@ def test_reactive_power(p: float, cos_phi: float, expected: float): @mark.parametrize( - ("wind_speed", "expected"), + ("kwargs", "expected"), [ - (0.0, 0.0), - (1.5, 0.0), - (2.56385179, 0.0), # cut-in - (7.26424673, 125000.0), - (11.96464167, 1000000.0), # nominal - (16.23772797, 1000000.0), - (21.36543155, 1000000.0), # cutting-out - (23.5019747, 500000.0), - (25.63851786, 0.0), # cut-out - (85.46172618, 0.0), + param({"wind_speed": 0.0, "axis_height": 10.0}, 0.0, id="no-wind"), + param({"wind_speed": 1.5, "axis_height": 10.0}, 0.0, id="half-way-cut-in"), + param({"wind_speed": 3.0, "axis_height": 10.0}, 0.0, id="cut-in"), + param({"wind_speed": 8.5, "axis_height": 10.0}, 125000.0, id="cut-in-to-nominal"), + param({"wind_speed": 14.0, "axis_height": 10.0}, 1000000.0, id="nominal"), # nominal + param({"wind_speed": 19.5, "axis_height": 10.0}, 1000000.0, id="nominal-to-cutting-out"), + param({"wind_speed": 25.0, "axis_height": 10.0}, 1000000.0, id="cutting-out"), + param({"wind_speed": 27.5, "axis_height": 10.0}, 500000.0, id="cutting-out-to-cut-out"), + param({"wind_speed": 30.0, "axis_height": 10.0}, 0.0, id="cut-out"), + param({"wind_speed": 50.0, "axis_height": 10.0}, 0.0, id="more-than-cut-out"), + # 30 meters high + param({"wind_speed": 3.0, "axis_height": 30.0}, 99.86406950142123, id="cut-in-at-30m"), + param({"wind_speed": 20.0, "axis_height": 30.0}, 1000000.0, id="nominal-at-30m"), + param({"wind_speed": 25.0, "axis_height": 30.0}, 149427.79246831674, id="cutting-out-at-30m"), + param({"wind_speed": 25.63851786, "axis_height": 30.0}, 0.0, id="cut-out-at-30m"), ], ) -def test_power_wind_speed(wind_speed, expected): - assert power_wind_speed(1e6, wind_speed) == approx(expected) +def test_power_wind_speed(kwargs, expected): + assert power_wind_speed(p_nom=1e6, **kwargs) == approx(expected) @mark.parametrize( From a0b31f2a7f72bb11211120e57512f55a2e0bb63c Mon Sep 17 00:00:00 2001 From: Nitish Bharambe <78108900+nitbharambe@users.noreply.github.com> Date: Wed, 21 Dec 2022 13:26:39 +0100 Subject: [PATCH 07/14] Update vision_converter.md Signed-off-by: Nitish Bharambe <78108900+nitbharambe@users.noreply.github.com> --- docs/converters/vision_converter.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/converters/vision_converter.md b/docs/converters/vision_converter.md index bc688fc1..810645ef 100644 --- a/docs/converters/vision_converter.md +++ b/docs/converters/vision_converter.md @@ -17,10 +17,16 @@ So we may observe a variation in power inflow/outflow result (ie. P,Q and S) due When we make conversion to PGM, the input data attributes of PGM for loads like `p_specified` and `q_specified` are modified as per simultaneity. The resulting loading then takes simultaneity into account. **Hence, the loading of such elements may not correspond to the load rate obtained in vision** +## Voltage angle of buses in symmetric power-flow + +Note that vision does not include clock angles of transformer for symmetrical calculations in the result of voltage angles. power-grid-model however does consider them so a direct comparison of results cannot be made in such case. + ## Modelling differences or unsupported attributes -Some components are yet to be modelled for conversions because they might not have a straightforward mapping in power-grid-model. +Some components are yet to be modelled for conversions because they might not have a straightforward mapping in power-grid-model. Those are listed here. -- power-grid-model currently does not support PV bus and related corresponding features. Currently, the efficiency type of PVs(Photovoltaics) element is also unsupported for all types except the `100%` type. +- power-grid-model currently does not support PV(Active Power-Voltage) bus and related corresponding features. +- Currently, the efficiency type of PVs(Photovoltaics) element is also unsupported for all types except the `100%` type. - The conversions for load behaviors of `industry`, `residential`, `business` are not yet modelled -- The source bus in PGM is mapped with a source impedance. `Sk"nom`, `R/X` and `Z0/Z1` are the attributes used in modelling source impedance. In vision, these attributes are used only for short circuit calculations \ No newline at end of file +- The source bus in PGM is mapped with a source impedance. `Sk"nom`, `R/X` and `Z0/Z1` are the attributes used in modelling source impedance. In vision, these attributes are used only for short circuit calculations +- A minor difference in results is expected since Vision uses a power mismatch in p.u. as convergence criteria whereas power-grid-model uses voltage mismatch. From b8dea4aa3ce24e90ced3be0b86118992e91c68ef Mon Sep 17 00:00:00 2001 From: Nitish Bharambe <78108900+nitbharambe@users.noreply.github.com> Date: Wed, 21 Dec 2022 13:29:28 +0100 Subject: [PATCH 08/14] update for wind_speed comment Signed-off-by: Nitish Bharambe <78108900+nitbharambe@users.noreply.github.com> --- .../functions/phase_to_phase.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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 09070e6d..0cb01eca 100644 --- a/src/power_grid_model_io/functions/phase_to_phase.py +++ b/src/power_grid_model_io/functions/phase_to_phase.py @@ -49,25 +49,25 @@ def power_wind_speed( # pylint: disable=too-many-arguments """ # Calculate wind speed at the axis height - wind_speed_height = wind_speed * (axis_height / 10) ** 0.143 + wind_speed *= (axis_height / 10) ** 0.143 # At a wind speed below cut-in, the power is zero. - if wind_speed_height < cut_in_wind_speed: + if wind_speed < cut_in_wind_speed: return 0.0 # At a wind speed between cut-in and nominal, the power is a third power function of the wind speed. - if wind_speed_height < nominal_wind_speed: - factor = wind_speed_height - cut_in_wind_speed + if wind_speed < nominal_wind_speed: + factor = wind_speed - cut_in_wind_speed max_factor = nominal_wind_speed - cut_in_wind_speed return ((factor / max_factor) ** 3) * p_nom # At a wind speed between nominal and cutting-out, the power is the nominal power. - if wind_speed_height < cutting_out_wind_speed: + if wind_speed < cutting_out_wind_speed: return p_nom # At a wind speed between cutting-out and cut-out, the power decreases from nominal to zero. - if wind_speed_height < cut_out_wind_speed: - factor = wind_speed_height - cutting_out_wind_speed + if wind_speed < cut_out_wind_speed: + factor = wind_speed - cutting_out_wind_speed max_factor = cut_out_wind_speed - cutting_out_wind_speed return (1.0 - factor / max_factor) * p_nom From dbe8f3dd9e875abffc3a3372d8c485dc421f673a Mon Sep 17 00:00:00 2001 From: Nitish Bharambe <78108900+nitbharambe@users.noreply.github.com> Date: Wed, 21 Dec 2022 13:39:22 +0100 Subject: [PATCH 09/14] mention change to PQ type load Signed-off-by: Nitish Bharambe <78108900+nitbharambe@users.noreply.github.com> --- docs/converters/vision_converter.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/converters/vision_converter.md b/docs/converters/vision_converter.md index 810645ef..c06ed151 100644 --- a/docs/converters/vision_converter.md +++ b/docs/converters/vision_converter.md @@ -27,6 +27,6 @@ Some components are yet to be modelled for conversions because they might not ha - power-grid-model currently does not support PV(Active Power-Voltage) bus and related corresponding features. - Currently, the efficiency type of PVs(Photovoltaics) element is also unsupported for all types except the `100%` type. -- The conversions for load behaviors of `industry`, `residential`, `business` are not yet modelled +- The conversions for load behaviors of `industry`, `residential`, `business` are not yet modelled. The load behaviors usually do not create a significant difference in power-flow results for most grids when the voltage at bus is close to 1 p.u. Hence, the conversion of the mentioned load behaviors is approximated to be of `Constant Power` type for now. - The source bus in PGM is mapped with a source impedance. `Sk"nom`, `R/X` and `Z0/Z1` are the attributes used in modelling source impedance. In vision, these attributes are used only for short circuit calculations - A minor difference in results is expected since Vision uses a power mismatch in p.u. as convergence criteria whereas power-grid-model uses voltage mismatch. From 239b3cd3c0d5ba633498d83531e5b8bfbac8accb Mon Sep 17 00:00:00 2001 From: Nitish Bharambe <78108900+nitbharambe@users.noreply.github.com> Date: Wed, 21 Dec 2022 13:43:43 +0100 Subject: [PATCH 10/14] Update vision_converter.md Signed-off-by: Nitish Bharambe <78108900+nitbharambe@users.noreply.github.com> --- docs/converters/vision_converter.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/converters/vision_converter.md b/docs/converters/vision_converter.md index c06ed151..a386b1f5 100644 --- a/docs/converters/vision_converter.md +++ b/docs/converters/vision_converter.md @@ -19,7 +19,7 @@ When we make conversion to PGM, the input data attributes of PGM for loads like ## Voltage angle of buses in symmetric power-flow -Note that vision does not include clock angles of transformer for symmetrical calculations in the result of voltage angles. power-grid-model however does consider them so a direct comparison of results cannot be made in such case. +Note that vision does not include clock angles of transformer for symmetrical calculations in the result of voltage angles. power-grid-model however does consider them so a direct comparison of angle results needs to be done with this knowledge. ## Modelling differences or unsupported attributes From 690291dcea5c73ea0846a687c723d49e2115eeaa Mon Sep 17 00:00:00 2001 From: Bram Stoeller Date: Thu, 5 Jan 2023 10:15:45 +0100 Subject: [PATCH 11/14] Move regular expressions to utils Signed-off-by: Bram Stoeller --- .../functions/phase_to_phase.py | 6 +-- src/power_grid_model_io/utils/regex.py | 42 ++++++++++++++++ tests/unit/utils/test_regex.py | 50 +++++++++++++++++++ 3 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 src/power_grid_model_io/utils/regex.py create mode 100644 tests/unit/utils/test_regex.py 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 0cb01eca..602bb276 100644 --- a/src/power_grid_model_io/functions/phase_to_phase.py +++ b/src/power_grid_model_io/functions/phase_to_phase.py @@ -6,14 +6,12 @@ """ import math -import re from typing import Tuple from power_grid_model import WindingType from power_grid_model_io.functions import get_winding - -CONNECTION_PATTERN = re.compile(r"(Y|YN|D|Z|ZN)(y|yn|d|z|zn)(\d|1[0-2])") +from power_grid_model_io.utils.regex import TRAFO_CONNECTION_RE def relative_no_load_current(i_0: float, p_0: float, s_nom: float, u_nom: float) -> float: @@ -113,7 +111,7 @@ def _split_connection_string(conn_str: str) -> Tuple[str, str, int]: * winding_to * clock """ - match = CONNECTION_PATTERN.fullmatch(conn_str) + match = TRAFO_CONNECTION_RE.fullmatch(conn_str) if not match: raise ValueError(f"Invalid transformer connection string: '{conn_str}'") return match.group(1), match.group(2), int(match.group(3)) diff --git a/src/power_grid_model_io/utils/regex.py b/src/power_grid_model_io/utils/regex.py new file mode 100644 index 00000000..423daef4 --- /dev/null +++ b/src/power_grid_model_io/utils/regex.py @@ -0,0 +1,42 @@ +# SPDX-FileCopyrightText: 2022 Contributors to the Power Grid Model project +# +# SPDX-License-Identifier: MPL-2.0 +""" +General regular expressions +""" + +import re + +TRAFO_CONNECTION_RE = re.compile(r"^(Y|YN|D|Z|ZN)(y|yn|d|z|zn)(\d|1[0-2])?$") +r""" +Regular expressions to the winding_from and winding_to codes and optionally the clock number: +^ Start of the string +(Y|YN|D|Z|ZN) From winding type +(y|yn|d|z|zn) To winding type +(\d|1[0-2])? Optional clock number (0-12) +$ End of the string +""" + +TRAFO3_CONNECTION_RE = re.compile(r"^(Y|YN|D|Z|ZN)(y|yn|d|z|zn)(y|yn|d|z|zn)(\d|1[0-2])?$") +r""" +Regular expressions to the winding_1, winding_2 and winding_3 codes and optionally the clock number: +^ Start of the string +(Y|YN|D|Z|ZN) First winding type +(y|yn|d|z|zn) Second winding type +(y|yn|d|z|zn) Third winding type +(\d|1[0-2])? Optional clock number (0-12) +$ End of the string +""" + +NODE_REF_RE = re.compile(r"^(.+_)?node(_.+)?$") +r""" +Regular expressions to match the word node with an optional prefix or suffix, e.g.: + - node + - from_node + - node_1 +^ Start of the string +(.+_)? Optional prefix, ending with an underscore +node The word 'node' +(_.+)? Optional suffix, starting with in an underscore +$ End of the string +""" diff --git a/tests/unit/utils/test_regex.py b/tests/unit/utils/test_regex.py new file mode 100644 index 00000000..b4930b2e --- /dev/null +++ b/tests/unit/utils/test_regex.py @@ -0,0 +1,50 @@ +# SPDX-FileCopyrightText: 2022 Contributors to the Power Grid Model project +# +# SPDX-License-Identifier: MPL-2.0 + +import pytest + +from power_grid_model_io.utils.regex import NODE_REF_RE, TRAFO3_CONNECTION_RE, TRAFO_CONNECTION_RE + + +def test_trafo_connection__pos(): + assert TRAFO_CONNECTION_RE.fullmatch("Dyn").groups() == ("D", "yn", None) + assert TRAFO_CONNECTION_RE.fullmatch("Yyn").groups() == ("Y", "yn", None) + assert TRAFO_CONNECTION_RE.fullmatch("Yzn").groups() == ("Y", "zn", None) + assert TRAFO_CONNECTION_RE.fullmatch("YNy").groups() == ("YN", "y", None) + assert TRAFO_CONNECTION_RE.fullmatch("Dy5").groups() == ("D", "y", "5") + assert TRAFO_CONNECTION_RE.fullmatch("Dy11").groups() == ("D", "y", "11") + + +def test_trafo_connection__neg(): + assert not TRAFO_CONNECTION_RE.fullmatch("Xyn") + assert not TRAFO_CONNECTION_RE.fullmatch("yyn") + assert not TRAFO_CONNECTION_RE.fullmatch("YZN") + assert not TRAFO_CONNECTION_RE.fullmatch("YNx") + assert not TRAFO_CONNECTION_RE.fullmatch("Dy13") + assert not TRAFO_CONNECTION_RE.fullmatch("Dy-1") + + +@pytest.mark.skip("Test not implemented") +def test_trafo3_connection__pos(): + assert TRAFO3_CONNECTION_RE.fullmatch(...).groups() == (..., ..., ..., ...) + + +@pytest.mark.skip("Test not implemented") +def test_trafo3_connection__neg(): + assert not TRAFO3_CONNECTION_RE.fullmatch(...) + + +def test_node_ref__pos(): + assert NODE_REF_RE.fullmatch("node") + assert NODE_REF_RE.fullmatch("from_node") + assert NODE_REF_RE.fullmatch("to_node") + assert NODE_REF_RE.fullmatch("node_1") + assert NODE_REF_RE.fullmatch("node_2") + assert NODE_REF_RE.fullmatch("node_3") + + +def test_node_ref__neg(): + assert not NODE_REF_RE.fullmatch("nodes") + assert not NODE_REF_RE.fullmatch("anode") + assert not NODE_REF_RE.fullmatch("immunodeficient") From 1591e8ae7ce9cfddde31d481320fcf349e3d68f1 Mon Sep 17 00:00:00 2001 From: Nitish Bharambe Date: Thu, 5 Jan 2023 16:30:25 +0100 Subject: [PATCH 12/14] failed test Signed-off-by: Nitish Bharambe --- tests/unit/utils/test_regex.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/unit/utils/test_regex.py b/tests/unit/utils/test_regex.py index b4930b2e..152319a9 100644 --- a/tests/unit/utils/test_regex.py +++ b/tests/unit/utils/test_regex.py @@ -25,14 +25,23 @@ def test_trafo_connection__neg(): assert not TRAFO_CONNECTION_RE.fullmatch("Dy-1") -@pytest.mark.skip("Test not implemented") def test_trafo3_connection__pos(): - assert TRAFO3_CONNECTION_RE.fullmatch(...).groups() == (..., ..., ..., ...) + assert TRAFO3_CONNECTION_RE.fullmatch("Dynyn").groups() == ("D", "yn", "yn", None) + assert TRAFO3_CONNECTION_RE.fullmatch("Yynd").groups() == ("Y", "yn", "d", None) + assert TRAFO3_CONNECTION_RE.fullmatch("Yzny").groups() == ("Y", "zn", "y", None) + assert TRAFO3_CONNECTION_RE.fullmatch("YNdz").groups() == ("YN", "d", "z", None) + assert TRAFO3_CONNECTION_RE.fullmatch("Dyy5").groups() == ("D", "y", "y", "5") + assert TRAFO3_CONNECTION_RE.fullmatch("Dyd11").groups() == ("D", "y", "d" "11") -@pytest.mark.skip("Test not implemented") def test_trafo3_connection__neg(): - assert not TRAFO3_CONNECTION_RE.fullmatch(...) + assert not TRAFO3_CONNECTION_RE.fullmatch("Xynd") + assert not TRAFO3_CONNECTION_RE.fullmatch("ydyn") + assert not TRAFO3_CONNECTION_RE.fullmatch("DYZN") + assert not TRAFO3_CONNECTION_RE.fullmatch("YNxd") + assert not TRAFO3_CONNECTION_RE.fullmatch("Dyd13") + assert not TRAFO3_CONNECTION_RE.fullmatch("DyD13") + assert not TRAFO3_CONNECTION_RE.fullmatch("Dynd-1") def test_node_ref__pos(): From b7142f3729ef9cf880a67bc80767d18c3c980ed0 Mon Sep 17 00:00:00 2001 From: Nitish Bharambe Date: Thu, 5 Jan 2023 16:31:26 +0100 Subject: [PATCH 13/14] fixed test Signed-off-by: Nitish Bharambe --- tests/unit/utils/test_regex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/utils/test_regex.py b/tests/unit/utils/test_regex.py index 152319a9..0033d756 100644 --- a/tests/unit/utils/test_regex.py +++ b/tests/unit/utils/test_regex.py @@ -31,7 +31,7 @@ def test_trafo3_connection__pos(): assert TRAFO3_CONNECTION_RE.fullmatch("Yzny").groups() == ("Y", "zn", "y", None) assert TRAFO3_CONNECTION_RE.fullmatch("YNdz").groups() == ("YN", "d", "z", None) assert TRAFO3_CONNECTION_RE.fullmatch("Dyy5").groups() == ("D", "y", "y", "5") - assert TRAFO3_CONNECTION_RE.fullmatch("Dyd11").groups() == ("D", "y", "d" "11") + assert TRAFO3_CONNECTION_RE.fullmatch("Dyd11").groups() == ("D", "y", "d", "11") def test_trafo3_connection__neg(): From 88409f94551e4f1ac46c3885e88652fd976c61c7 Mon Sep 17 00:00:00 2001 From: Nitish Bharambe Date: Thu, 12 Jan 2023 10:03:41 +0100 Subject: [PATCH 14/14] add deviation doc Signed-off-by: Nitish Bharambe --- docs/converters/vision_converter.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/converters/vision_converter.md b/docs/converters/vision_converter.md index a386b1f5..1adb9ed3 100644 --- a/docs/converters/vision_converter.md +++ b/docs/converters/vision_converter.md @@ -17,6 +17,19 @@ So we may observe a variation in power inflow/outflow result (ie. P,Q and S) due When we make conversion to PGM, the input data attributes of PGM for loads like `p_specified` and `q_specified` are modified as per simultaneity. The resulting loading then takes simultaneity into account. **Hence, the loading of such elements may not correspond to the load rate obtained in vision** +## Transformer load modelling + +power-grid-model-io converts the transformer load into a individual transformer and a load for usage in power-grid-model. +In vision, the modelling of a transformer load seems to be different from an individual transformer and load. +There is a minor difference in both in the reactive power consumed/generated. +This can correspond to a minor voltage deviation too in the results. + +```{tip} +It is recommended to split the transformer load into a individual components in vision beforehand to avoid this issue. +This can be done by first selecting the transformer loads: (Start | Select | Object -> Element -> Check Transformer load, Ok) +Then split it into individual components: (Start | Edit | Topological | Split) +``` + ## Voltage angle of buses in symmetric power-flow Note that vision does not include clock angles of transformer for symmetrical calculations in the result of voltage angles. power-grid-model however does consider them so a direct comparison of angle results needs to be done with this knowledge.