power-grid-model-ds 0.0.1a11709467271__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. power_grid_model_ds/__init__.py +9 -0
  2. power_grid_model_ds/_core/__init__.py +0 -0
  3. power_grid_model_ds/_core/data_source/__init__.py +0 -0
  4. power_grid_model_ds/_core/data_source/generator/__init__.py +0 -0
  5. power_grid_model_ds/_core/data_source/generator/arrays/__init__.py +0 -0
  6. power_grid_model_ds/_core/data_source/generator/arrays/base.py +25 -0
  7. power_grid_model_ds/_core/data_source/generator/arrays/line.py +133 -0
  8. power_grid_model_ds/_core/data_source/generator/arrays/node.py +37 -0
  9. power_grid_model_ds/_core/data_source/generator/arrays/source.py +30 -0
  10. power_grid_model_ds/_core/data_source/generator/arrays/transformer.py +37 -0
  11. power_grid_model_ds/_core/data_source/generator/grid_generators.py +78 -0
  12. power_grid_model_ds/_core/fancypy.py +66 -0
  13. power_grid_model_ds/_core/load_flow.py +140 -0
  14. power_grid_model_ds/_core/model/__init__.py +0 -0
  15. power_grid_model_ds/_core/model/arrays/__init__.py +43 -0
  16. power_grid_model_ds/_core/model/arrays/base/__init__.py +0 -0
  17. power_grid_model_ds/_core/model/arrays/base/_build.py +166 -0
  18. power_grid_model_ds/_core/model/arrays/base/_filters.py +115 -0
  19. power_grid_model_ds/_core/model/arrays/base/_modify.py +64 -0
  20. power_grid_model_ds/_core/model/arrays/base/_optional.py +11 -0
  21. power_grid_model_ds/_core/model/arrays/base/_string.py +94 -0
  22. power_grid_model_ds/_core/model/arrays/base/array.py +325 -0
  23. power_grid_model_ds/_core/model/arrays/base/errors.py +17 -0
  24. power_grid_model_ds/_core/model/arrays/pgm_arrays.py +122 -0
  25. power_grid_model_ds/_core/model/constants.py +27 -0
  26. power_grid_model_ds/_core/model/containers/__init__.py +0 -0
  27. power_grid_model_ds/_core/model/containers/base.py +244 -0
  28. power_grid_model_ds/_core/model/containers/grid_protocol.py +22 -0
  29. power_grid_model_ds/_core/model/dtypes/__init__.py +0 -0
  30. power_grid_model_ds/_core/model/dtypes/appliances.py +39 -0
  31. power_grid_model_ds/_core/model/dtypes/branches.py +117 -0
  32. power_grid_model_ds/_core/model/dtypes/id.py +19 -0
  33. power_grid_model_ds/_core/model/dtypes/nodes.py +27 -0
  34. power_grid_model_ds/_core/model/dtypes/regulators.py +30 -0
  35. power_grid_model_ds/_core/model/dtypes/sensors.py +63 -0
  36. power_grid_model_ds/_core/model/enums/__init__.py +0 -0
  37. power_grid_model_ds/_core/model/enums/nodes.py +16 -0
  38. power_grid_model_ds/_core/model/graphs/__init__.py +0 -0
  39. power_grid_model_ds/_core/model/graphs/container.py +158 -0
  40. power_grid_model_ds/_core/model/graphs/errors.py +19 -0
  41. power_grid_model_ds/_core/model/graphs/models/__init__.py +7 -0
  42. power_grid_model_ds/_core/model/graphs/models/_rustworkx_search.py +63 -0
  43. power_grid_model_ds/_core/model/graphs/models/base.py +326 -0
  44. power_grid_model_ds/_core/model/graphs/models/rustworkx.py +119 -0
  45. power_grid_model_ds/_core/model/grids/__init__.py +0 -0
  46. power_grid_model_ds/_core/model/grids/_text_sources.py +119 -0
  47. power_grid_model_ds/_core/model/grids/base.py +434 -0
  48. power_grid_model_ds/_core/model/grids/helpers.py +122 -0
  49. power_grid_model_ds/_core/utils/__init__.py +0 -0
  50. power_grid_model_ds/_core/utils/misc.py +41 -0
  51. power_grid_model_ds/_core/utils/pickle.py +47 -0
  52. power_grid_model_ds/_core/utils/zip.py +72 -0
  53. power_grid_model_ds/arrays.py +39 -0
  54. power_grid_model_ds/constants.py +7 -0
  55. power_grid_model_ds/enums.py +7 -0
  56. power_grid_model_ds/errors.py +27 -0
  57. power_grid_model_ds/fancypy.py +9 -0
  58. power_grid_model_ds/generators.py +11 -0
  59. power_grid_model_ds/graph_models.py +8 -0
  60. power_grid_model_ds-0.0.1a11709467271.dist-info/LICENSE +292 -0
  61. power_grid_model_ds-0.0.1a11709467271.dist-info/METADATA +80 -0
  62. power_grid_model_ds-0.0.1a11709467271.dist-info/RECORD +64 -0
  63. power_grid_model_ds-0.0.1a11709467271.dist-info/WHEEL +5 -0
  64. power_grid_model_ds-0.0.1a11709467271.dist-info/top_level.txt +1 -0
@@ -0,0 +1,244 @@
1
+ # SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
2
+ #
3
+ # SPDX-License-Identifier: MPL-2.0
4
+
5
+ """Stores the FancyArrayContainer class"""
6
+
7
+ import dataclasses
8
+ import inspect
9
+ import logging
10
+ from dataclasses import dataclass
11
+ from typing import Type, TypeVar
12
+
13
+ import numpy as np
14
+
15
+ from power_grid_model_ds._core import fancypy as fp
16
+ from power_grid_model_ds._core.model.arrays.base.array import FancyArray
17
+ from power_grid_model_ds._core.model.arrays.base.errors import RecordDoesNotExist
18
+ from power_grid_model_ds._core.model.constants import EMPTY_ID
19
+
20
+ Self = TypeVar("Self", bound="FancyArrayContainer")
21
+
22
+
23
+ @dataclass
24
+ class FancyArrayContainer:
25
+ """
26
+ Base class for ArrayContainers.
27
+ Contains general functionality that is nonspecific to the type of array being stored.
28
+ """
29
+
30
+ _id_counter: int
31
+
32
+ @property
33
+ def id_counter(self):
34
+ """Returns the private _id_counter field (as read-only)"""
35
+ return self._id_counter
36
+
37
+ @classmethod
38
+ def empty(cls: Type[Self]) -> Self:
39
+ """Create an empty grid"""
40
+ empty_fields = cls._get_empty_fields()
41
+ return cls(**empty_fields)
42
+
43
+ def all_arrays(self):
44
+ """Returns all arrays in the container."""
45
+
46
+ for field in dataclasses.fields(self):
47
+ attribute = getattr(self, field.name)
48
+ if isinstance(attribute, FancyArray):
49
+ yield attribute
50
+
51
+ @classmethod
52
+ def find_array_field(cls, array_type: Type[FancyArray]) -> dataclasses.Field:
53
+ """Find the Field that holds an array of type array_type.
54
+
55
+ Args:
56
+ array_type(type[FancyArray]): FancyArray subclass.
57
+
58
+ Raises:
59
+ TypeError: if no field with the given `array_type` is found or if multiple fields are found.
60
+
61
+ Returns:
62
+ a Field instance.
63
+ """
64
+ fields = [
65
+ field
66
+ for field in dataclasses.fields(cls)
67
+ if inspect.isclass(field.type) and issubclass(field.type, array_type)
68
+ ]
69
+ if (nr_fields := len(fields)) != 1:
70
+ raise TypeError(
71
+ f"Expected to find 1 array with type '{array_type.__name__}' in {cls.__name__} ({nr_fields} found)"
72
+ )
73
+ return fields[0]
74
+
75
+ @property
76
+ def max_id(self) -> int:
77
+ """Returns the max id across all arrays within the container."""
78
+ max_per_array = [np.max(array.id) if array.size > 0 else 0 for array in self.all_arrays()]
79
+ return int(max(max_per_array))
80
+
81
+ def check_ids(self, check_between_arrays: bool = True, check_within_arrays: bool = True) -> None:
82
+ """Checks for duplicate id values across all arrays in the container.
83
+
84
+ Args:
85
+ check_between_arrays(bool): whether to check for duplicate ids across arrays
86
+ check_within_arrays(bool): whether to check for duplicate ids within each array
87
+
88
+ Raises:
89
+ ValueError: if duplicates are found.
90
+ """
91
+
92
+ id_arrays = [array for array in self.all_arrays() if hasattr(array, "id")]
93
+ if not id_arrays:
94
+ return # no arrays to check
95
+
96
+ duplicates_between_arrays = self._get_duplicates_between_arrays(
97
+ id_arrays, check=check_between_arrays
98
+ ) # if check_between_arrays else []
99
+ arrays_with_duplicates = self._get_arrays_with_duplicates(id_arrays, check=check_within_arrays)
100
+
101
+ if not any(duplicates_between_arrays) and not any(arrays_with_duplicates):
102
+ return
103
+
104
+ if any(duplicates_between_arrays):
105
+ logging.warning(f"The following ids occur in multiple arrays: {duplicates_between_arrays}!")
106
+ for array_class in arrays_with_duplicates:
107
+ logging.warning(f"{array_class.__name__} contains duplicates!")
108
+
109
+ raise ValueError(f"Duplicates found within {self.__class__.__name__}!")
110
+
111
+ def append(self, array: FancyArray, check_max_id: bool = True) -> None:
112
+ """Append the given asset_array to the corresponding field of ArrayContainer and generate ids.
113
+
114
+ Args:
115
+ array(FancyArray): the asset_array to be appended (e.g. a NodeArray instance).
116
+ check_max_id(bool): whether to check max(array.id) with the id counter
117
+
118
+ Returns:
119
+ None
120
+ """
121
+ self._append(array=array, check_max_id=check_max_id)
122
+
123
+ def attach_ids(self, array: FancyArray) -> FancyArray:
124
+ """Generate and attach ids to the given FancyArray. Also updates _id_counter.
125
+
126
+ Args:
127
+ array(FancyArray): the array of which the id column is set.
128
+
129
+ Returns:
130
+ FancyArray: initial array with updated `id` column.
131
+ """
132
+ if not array.size:
133
+ return array
134
+
135
+ if (id_set := set(array.id)) != {array.get_empty_value("id")}:
136
+ raise ValueError(f"Cannot attach ids to array that contains non-empty ids: {id_set}")
137
+
138
+ start = self._id_counter + 1
139
+ end = start + len(array)
140
+ array.id = np.arange(start, end)
141
+ self._id_counter = max(self._id_counter, end - 1)
142
+
143
+ return array
144
+
145
+ def search_for_id(self, record_id: int) -> list[FancyArray]:
146
+ """Attempts to find a record across all id-arrays within the container.
147
+
148
+ This method is only intended for debugging purposes since it is very inefficient.
149
+ In normal circumstances you should use ``get`` or ``filter`` to find records within a specific array.
150
+
151
+ Args:
152
+ record_id(int): the id of the record to be found.
153
+
154
+ Returns:
155
+ list[FancyArray]:a list of arrays that contain the given record_id.
156
+ Each array within the list contains all records with the given array.
157
+ """
158
+
159
+ logging.warning("Using search_for_id(). Make sure to use only while debugging!")
160
+
161
+ arrays_with_record = []
162
+
163
+ id_arrays = [array for array in self.all_arrays() if "id" in array.dtype.names]
164
+ for id_array in id_arrays:
165
+ matching_records = id_array.filter(id=record_id)
166
+ if matching_records.size:
167
+ arrays_with_record.append(matching_records)
168
+
169
+ if arrays_with_record:
170
+ return arrays_with_record
171
+ raise RecordDoesNotExist(f"record id '{record_id}' not found in {self.__class__.__name__}")
172
+
173
+ def _append(self, array: FancyArray, check_max_id: bool = True) -> None:
174
+ """
175
+ Append the given asset_array to the corresponding field of Grid and generate ids.
176
+ Args:
177
+ array: the asset_array to be appended (e.g. a KabelArray instance).
178
+ check_max_id: whether to check max(array.id) with the id counter
179
+ Returns: None.
180
+ """
181
+ if array.size == 0:
182
+ return
183
+
184
+ array_field = self.find_array_field(array.__class__)
185
+
186
+ if hasattr(array, "id"):
187
+ self._update_id_counter(array, check_max_id)
188
+
189
+ # Add the given asset_array to the corresponding array in the Grid.
190
+ array_attr = getattr(self, array_field.name)
191
+ appended = fp.concatenate(array_attr, array)
192
+ setattr(self, array_field.name, appended)
193
+
194
+ @classmethod
195
+ def _get_empty_fields(cls) -> dict:
196
+ empty_fields = {}
197
+
198
+ empty_fields.update(cls._get_empty_arrays())
199
+ empty_fields.update({"_id_counter": 0})
200
+ return empty_fields
201
+
202
+ @classmethod
203
+ def _get_empty_arrays(cls) -> dict:
204
+ return {
205
+ field.name: field.type()
206
+ for field in dataclasses.fields(cls)
207
+ if inspect.isclass(field.type) and issubclass(field.type, FancyArray)
208
+ }
209
+
210
+ def _update_id_counter(self, array, check_max_id: bool = True):
211
+ if np.all(array.id == EMPTY_ID):
212
+ array = self.attach_ids(array)
213
+ elif np.any(array.id == EMPTY_ID):
214
+ raise ValueError(f"Cannot append: array contains empty [{EMPTY_ID}] and non-empty ids.")
215
+
216
+ new_max_id = np.max(array.id)
217
+ if check_max_id and new_max_id < self._id_counter:
218
+ raise ValueError(f"Cannot append: id {new_max_id} is lower than the id counter")
219
+
220
+ # Update _id_counter
221
+ self._id_counter = max(self._id_counter, new_max_id)
222
+
223
+ @staticmethod
224
+ def _get_duplicates_between_arrays(id_arrays: list[FancyArray], check: bool) -> np.ndarray:
225
+ if not check:
226
+ return np.array([])
227
+ unique_ids_per_array = [np.unique(array.id) for array in id_arrays]
228
+
229
+ all_ids = np.concatenate(unique_ids_per_array)
230
+
231
+ unique_ids, counts = np.unique(all_ids, return_counts=True)
232
+ duplicate_mask = counts > 1
233
+ return unique_ids[duplicate_mask]
234
+
235
+ @staticmethod
236
+ def _get_arrays_with_duplicates(id_arrays: list[FancyArray], check: bool) -> list:
237
+ arrays_with_duplicates: list[Type] = []
238
+ if not check:
239
+ return arrays_with_duplicates
240
+ for id_array in id_arrays:
241
+ duplicates: np.ndarray = id_array.check_ids(return_duplicates=True)
242
+ if duplicates.size > 0:
243
+ arrays_with_duplicates.append(id_arrays.__class__)
244
+ return arrays_with_duplicates
@@ -0,0 +1,22 @@
1
+ # SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
2
+ #
3
+ # SPDX-License-Identifier: MPL-2.0
4
+ """This file contains the Grid protocol defining the minimal arrays contained in a grid"""
5
+
6
+ from typing import Protocol
7
+
8
+ from power_grid_model_ds._core.model.arrays import (
9
+ BranchArray,
10
+ NodeArray,
11
+ ThreeWindingTransformerArray,
12
+ )
13
+
14
+
15
+ class MinimalGridArrays(Protocol):
16
+ """Protocol for the minimal arrays contained in a grid,
17
+ they may be implemented using properties or added as attributes"""
18
+
19
+ node: NodeArray
20
+ three_winding_transformer: ThreeWindingTransformerArray
21
+ branches: BranchArray
22
+ branch_arrays: list[BranchArray]
File without changes
@@ -0,0 +1,39 @@
1
+ # SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
2
+ #
3
+ # SPDX-License-Identifier: MPL-2.0
4
+
5
+ """Appliance data types"""
6
+
7
+ import numpy as np
8
+ from numpy.typing import NDArray
9
+
10
+ from power_grid_model_ds._core.model.dtypes.id import Id
11
+
12
+
13
+ class Appliance(Id):
14
+ """Appliance data type"""
15
+
16
+ node: NDArray[np.int32] # id of the coupled node
17
+ status: NDArray[np.int8] # connection status to the node
18
+
19
+
20
+ class Source(Appliance):
21
+ """Source data type"""
22
+
23
+ u_ref: NDArray[np.float64] # reference voltage
24
+
25
+
26
+ class SymLoad(Appliance):
27
+ """SymLoad data type"""
28
+
29
+ type: NDArray[np.int8] # load type
30
+ p_specified: NDArray[np.float64] # specified active power
31
+ q_specified: NDArray[np.float64] # specified reactive power
32
+
33
+
34
+ class SymGen(Appliance):
35
+ """SymGen data type"""
36
+
37
+ type: NDArray[np.int_] # load type
38
+ p_specified: NDArray[np.float64] # specified active power
39
+ q_specified: NDArray[np.float64] # specified reactive power
@@ -0,0 +1,117 @@
1
+ # SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
2
+ #
3
+ # SPDX-License-Identifier: MPL-2.0
4
+
5
+ """Branch data types"""
6
+
7
+ import numpy as np
8
+ from numpy.typing import NDArray
9
+
10
+ from power_grid_model_ds._core.model.constants import empty
11
+ from power_grid_model_ds._core.model.dtypes.id import Id
12
+
13
+
14
+ class Branch(Id):
15
+ """Branch data type"""
16
+
17
+ from_node: NDArray[np.int32] # node id (from-side)
18
+ to_node: NDArray[np.int32] # node id (to-side)
19
+ from_status: NDArray[np.int8] # 1 = closed, 0 = open
20
+ to_status: NDArray[np.int8] # 1 = closed, 0 = open
21
+ feeder_branch_id: NDArray[np.int32] # branch id of the feeding branch
22
+ feeder_node_id: NDArray[np.int32] # node id of the feeding node
23
+ is_feeder: NDArray[np.bool_] # whether or not this branch is from the substation
24
+
25
+ _defaults = {
26
+ "feeder_branch_id": empty,
27
+ "feeder_node_id": empty,
28
+ "is_feeder": False,
29
+ }
30
+
31
+
32
+ class Link(Branch):
33
+ """Link data type"""
34
+
35
+
36
+ class Line(Branch):
37
+ """Line data type"""
38
+
39
+ r1: NDArray[np.float64] # serial resistance
40
+ x1: NDArray[np.float64] # serial reactance
41
+ c1: NDArray[np.float64] # shunt capacitance
42
+ tan1: NDArray[np.float64] # shunt loss factor
43
+ i_n: NDArray[np.float64] # rated current
44
+
45
+
46
+ class Transformer(Branch):
47
+ """Transformer data type"""
48
+
49
+ u1: NDArray[np.float64] # rated voltage (from-side)
50
+ u2: NDArray[np.float64] # rated voltage (to-side)
51
+ sn: NDArray[np.float64] # rated power
52
+ tap_size: NDArray[np.float64] # size of each tap of the tap changer
53
+ uk: NDArray[np.float64] # relative short circuit voltage
54
+ pk: NDArray[np.float64] # short circuit loss
55
+ i0: NDArray[np.float64] # relative no-load current
56
+ p0: NDArray[np.float64] # no-load loss
57
+ winding_from: NDArray[np.int8] # winding type (from-side)
58
+ winding_to: NDArray[np.int8] # winding type (to-side)
59
+ clock: NDArray[np.int8] # clock number of phase shift
60
+ tap_side: NDArray[np.int8] # side of tap changer
61
+ tap_pos: NDArray[np.int8] # current position of tap changer
62
+ tap_min: NDArray[np.int8] # position of tap changer at minimum voltage
63
+ tap_max: NDArray[np.int8] # position of tap changer at maximum voltage
64
+ tap_nom: NDArray[np.int8] # nominal position of tap changer
65
+
66
+
67
+ class Branch3(Id):
68
+ """Branch3 data type"""
69
+
70
+ node_1: NDArray[np.int32]
71
+ node_2: NDArray[np.int32]
72
+ node_3: NDArray[np.int32]
73
+ status_1: NDArray[np.int8]
74
+ status_2: NDArray[np.int8]
75
+ status_3: NDArray[np.int8]
76
+
77
+
78
+ class ThreeWindingTransformer(Branch3):
79
+ """ThreeWindingTransformer data type"""
80
+
81
+ u1: NDArray[np.float64]
82
+ u2: NDArray[np.float64]
83
+ u3: NDArray[np.float64]
84
+ sn_1: NDArray[np.float64]
85
+ sn_2: NDArray[np.float64]
86
+ sn_3: NDArray[np.float64]
87
+ uk_12: NDArray[np.float64]
88
+ uk_13: NDArray[np.float64]
89
+ uk_23: NDArray[np.float64]
90
+ pk_12: NDArray[np.float64]
91
+ pk_13: NDArray[np.float64]
92
+ pk_23: NDArray[np.float64]
93
+ i0: NDArray[np.float64]
94
+ p0: NDArray[np.float64]
95
+ winding_1: NDArray[np.int8]
96
+ winding_2: NDArray[np.int8]
97
+ winding_3: NDArray[np.int8]
98
+ clock_12: NDArray[np.int8]
99
+ clock_13: NDArray[np.int8]
100
+ tap_side: NDArray[np.int8]
101
+ tap_pos: NDArray[np.int8]
102
+ tap_min: NDArray[np.int8]
103
+ tap_max: NDArray[np.int8]
104
+ tap_nom: NDArray[np.int8]
105
+ tap_size: NDArray[np.float64]
106
+ uk_12_min: NDArray[np.float64]
107
+ uk_13_min: NDArray[np.float64]
108
+ uk_23_min: NDArray[np.float64]
109
+ pk_12_min: NDArray[np.float64]
110
+ pk_13_min: NDArray[np.float64]
111
+ pk_23_min: NDArray[np.float64]
112
+ uk_12_max: NDArray[np.float64]
113
+ uk_13_max: NDArray[np.float64]
114
+ uk_23_max: NDArray[np.float64]
115
+ pk_12_max: NDArray[np.float64]
116
+ pk_13_max: NDArray[np.float64]
117
+ pk_23_max: NDArray[np.float64]
@@ -0,0 +1,19 @@
1
+ # SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
2
+ #
3
+ # SPDX-License-Identifier: MPL-2.0
4
+
5
+ """Base data types"""
6
+
7
+ from typing import Any
8
+
9
+ import numpy as np
10
+ from numpy.typing import NDArray
11
+
12
+ from power_grid_model_ds._core.model.constants import empty
13
+
14
+
15
+ class Id:
16
+ """Base dtype for id arrays"""
17
+
18
+ _defaults: dict[str, Any] = {"id": empty}
19
+ id: NDArray[np.int32]
@@ -0,0 +1,27 @@
1
+ # SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
2
+ #
3
+ # SPDX-License-Identifier: MPL-2.0
4
+
5
+ """Node data types"""
6
+
7
+ import numpy as np
8
+ from numpy.typing import NDArray
9
+
10
+ from power_grid_model_ds._core.model.constants import empty
11
+ from power_grid_model_ds._core.model.dtypes.id import Id
12
+ from power_grid_model_ds._core.model.enums.nodes import NodeType
13
+
14
+
15
+ class Node(Id):
16
+ """Node data type"""
17
+
18
+ u_rated: NDArray[np.float64] # rated line-line voltage
19
+ node_type: NDArray[np.int8]
20
+ feeder_branch_id: NDArray[np.int32] # branch id of the feeder
21
+ feeder_node_id: NDArray[np.int32] # node id of the first substation node
22
+
23
+ _defaults = {
24
+ "node_type": NodeType.UNSPECIFIED.value,
25
+ "feeder_branch_id": empty,
26
+ "feeder_node_id": empty,
27
+ }
@@ -0,0 +1,30 @@
1
+ # SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
2
+ #
3
+ # SPDX-License-Identifier: MPL-2.0
4
+
5
+ import numpy as np
6
+ from numpy.typing import NDArray
7
+
8
+ from power_grid_model_ds._core.model.dtypes.id import Id
9
+
10
+
11
+ class Regulator(Id):
12
+ "Regulator data type"
13
+
14
+ regulated_object: NDArray[np.int32] # a valid regulated object ID
15
+ status: NDArray[np.int8] # connection status of regulated object
16
+
17
+
18
+ class TransformerTapRegulator(Regulator):
19
+ """Transformer tap regulator data type"""
20
+
21
+ control_side: NDArray[np.int8] # the controlled side of the transformer (see BranchSide/Branch3Side of PGM)
22
+ u_set: NDArray[np.float64] # the voltage setpoint
23
+ u_band: NDArray[np.float64] # the width of the voltage band
24
+ line_drop_compensation_r: NDArray[np.float64] # compensation for voltage drop due to resistance during transport
25
+ line_drop_compensation_x: NDArray[np.float64] # compensation for voltage drop due to reactance during transport
26
+
27
+ _defaults = {
28
+ "line_drop_compensation_r": 0,
29
+ "line_drop_compensation_x": 0,
30
+ }
@@ -0,0 +1,63 @@
1
+ # SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
2
+ #
3
+ # SPDX-License-Identifier: MPL-2.0
4
+
5
+ """
6
+ Sensor data types
7
+ Based on the sensors defined in power grid model:
8
+ https://power-grid-model.readthedocs.io/en/v1.9.13/user_manual/components.html#sensor
9
+ """
10
+
11
+ from typing import Annotated, Literal, TypeVar
12
+
13
+ import numpy as np
14
+ from numpy.typing import NDArray
15
+
16
+ from power_grid_model_ds._core.model.dtypes.id import Id
17
+
18
+ # define structural arrays with 3 values for 3-phase variables
19
+ # based on https://stackoverflow.com/a/72585748
20
+ _DT = TypeVar("_DT", bound=np.generic)
21
+ NDArray3 = Annotated[NDArray[_DT], Literal[3]]
22
+
23
+
24
+ class Sensor(Id):
25
+ """Base class for sensor data type"""
26
+
27
+ measured_object: NDArray[np.int32]
28
+
29
+
30
+ class GenericPowerSensor(Sensor):
31
+ """Base class for power sensor data type"""
32
+
33
+ measured_terminal_type: NDArray[np.int32]
34
+ power_sigma: NDArray[np.float64] # std of total power
35
+
36
+
37
+ class SymPowerSensor(GenericPowerSensor):
38
+ """SymPowerSensor data type"""
39
+
40
+ p_measured: NDArray[np.float64] # measured active power
41
+ q_measured: NDArray[np.float64] # measured reactive power
42
+ p_sigma: NDArray[np.float64] # std of active power
43
+ q_sigma: NDArray[np.float64] # std of reactive power
44
+
45
+
46
+ class GenericVoltageSensor(Sensor):
47
+ """Base class for voltage sensor data type"""
48
+
49
+
50
+ class SymVoltageSensor(GenericVoltageSensor):
51
+ """SymVoltageSensor data type"""
52
+
53
+ u_sigma: NDArray[np.float64] # std of voltage
54
+ u_measured: NDArray[np.float64] # measured voltage
55
+ u_angle_measured: NDArray[np.float64] # measured phase
56
+
57
+
58
+ class AsymVoltageSensor(GenericVoltageSensor):
59
+ """AsymVoltageSensor data type"""
60
+
61
+ u_sigma: NDArray3[np.float64] # std of 3 voltages
62
+ u_measured: NDArray3[np.float64] # measured 3 voltages
63
+ u_angle_measured: NDArray3[np.float64] # measured 3 phases
File without changes
@@ -0,0 +1,16 @@
1
+ # SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
2
+ #
3
+ # SPDX-License-Identifier: MPL-2.0
4
+
5
+ """Enums for Nodes"""
6
+
7
+ from enum import IntEnum
8
+
9
+
10
+ class NodeType(IntEnum):
11
+ """Node Types
12
+ Nodes located within a substation, are marked as Substation nodes.
13
+ """
14
+
15
+ UNSPECIFIED = 0
16
+ SUBSTATION_NODE = 1
File without changes