power-grid-model 1.11.23__py3-none-win_amd64.whl → 1.12.70__py3-none-win_amd64.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 (67) hide show
  1. power_grid_model/__init__.py +54 -52
  2. power_grid_model/_core/__init__.py +3 -3
  3. power_grid_model/_core/buffer_handling.py +493 -478
  4. power_grid_model/_core/data_handling.py +195 -141
  5. power_grid_model/_core/data_types.py +143 -132
  6. power_grid_model/_core/dataset_definitions.py +109 -108
  7. power_grid_model/_core/enum.py +226 -226
  8. power_grid_model/_core/error_handling.py +206 -205
  9. power_grid_model/_core/errors.py +130 -126
  10. power_grid_model/_core/index_integer.py +17 -17
  11. power_grid_model/_core/options.py +71 -70
  12. power_grid_model/_core/power_grid_core.py +563 -581
  13. power_grid_model/_core/power_grid_dataset.py +535 -534
  14. power_grid_model/_core/power_grid_meta.py +257 -243
  15. power_grid_model/_core/power_grid_model.py +969 -687
  16. power_grid_model/_core/power_grid_model_c/__init__.py +3 -0
  17. power_grid_model/_core/power_grid_model_c/bin/power_grid_model_c.dll +0 -0
  18. power_grid_model/_core/power_grid_model_c/get_pgm_dll_path.py +63 -0
  19. power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/basics.h +255 -0
  20. power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/buffer.h +108 -0
  21. power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/dataset.h +316 -0
  22. power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/dataset_definitions.h +1052 -0
  23. power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/handle.h +99 -0
  24. power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/meta_data.h +189 -0
  25. power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/model.h +125 -0
  26. power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/options.h +142 -0
  27. power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/serialization.h +118 -0
  28. power_grid_model/_core/power_grid_model_c/include/power_grid_model_c.h +36 -0
  29. power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/basics.hpp +65 -0
  30. power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/buffer.hpp +61 -0
  31. power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/dataset.hpp +220 -0
  32. power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/handle.hpp +108 -0
  33. power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/meta_data.hpp +84 -0
  34. power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/model.hpp +63 -0
  35. power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/options.hpp +52 -0
  36. power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/serialization.hpp +124 -0
  37. power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/utils.hpp +81 -0
  38. power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp.hpp +19 -0
  39. power_grid_model/_core/power_grid_model_c/lib/cmake/power_grid_model/power_grid_modelConfig.cmake +37 -0
  40. power_grid_model/_core/power_grid_model_c/lib/cmake/power_grid_model/power_grid_modelConfigVersion.cmake +65 -0
  41. power_grid_model/_core/power_grid_model_c/lib/cmake/power_grid_model/power_grid_modelTargets-release.cmake +19 -0
  42. power_grid_model/_core/power_grid_model_c/lib/cmake/power_grid_model/power_grid_modelTargets.cmake +144 -0
  43. power_grid_model/_core/power_grid_model_c/lib/power_grid_model_c.lib +0 -0
  44. power_grid_model/_core/power_grid_model_c/share/LICENSE +292 -0
  45. power_grid_model/_core/power_grid_model_c/share/README.md +15 -0
  46. power_grid_model/_core/serialization.py +317 -317
  47. power_grid_model/_core/typing.py +20 -20
  48. power_grid_model/_core/utils.py +798 -789
  49. power_grid_model/data_types.py +321 -307
  50. power_grid_model/enum.py +27 -27
  51. power_grid_model/errors.py +37 -37
  52. power_grid_model/typing.py +43 -43
  53. power_grid_model/utils.py +473 -465
  54. power_grid_model/validation/__init__.py +25 -25
  55. power_grid_model/validation/_rules.py +1171 -1175
  56. power_grid_model/validation/_validation.py +1172 -1158
  57. power_grid_model/validation/assertions.py +93 -93
  58. power_grid_model/validation/errors.py +602 -588
  59. power_grid_model/validation/utils.py +313 -321
  60. {power_grid_model-1.11.23.dist-info → power_grid_model-1.12.70.dist-info}/METADATA +178 -180
  61. power_grid_model-1.12.70.dist-info/RECORD +65 -0
  62. {power_grid_model-1.11.23.dist-info → power_grid_model-1.12.70.dist-info}/WHEEL +1 -1
  63. power_grid_model-1.12.70.dist-info/entry_points.txt +3 -0
  64. power_grid_model/_core/_power_grid_core.dll +0 -0
  65. power_grid_model-1.11.23.dist-info/RECORD +0 -36
  66. power_grid_model-1.11.23.dist-info/top_level.txt +0 -1
  67. {power_grid_model-1.11.23.dist-info → power_grid_model-1.12.70.dist-info}/licenses/LICENSE +0 -0
@@ -1,205 +1,206 @@
1
- # SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
2
- #
3
- # SPDX-License-Identifier: MPL-2.0
4
-
5
- """
6
- Error handling
7
- """
8
-
9
- import re
10
-
11
- import numpy as np
12
-
13
- from power_grid_model._core.errors import (
14
- AutomaticTapCalculationError,
15
- AutomaticTapInputError,
16
- ConflictID,
17
- ConflictingAngleMeasurementType,
18
- ConflictVoltage,
19
- IDNotFound,
20
- IDWrongType,
21
- InvalidArguments,
22
- InvalidBranch,
23
- InvalidBranch3,
24
- InvalidCalculationMethod,
25
- InvalidMeasuredObject,
26
- InvalidRegulatedObject,
27
- InvalidShortCircuitPhaseOrType,
28
- InvalidTransformerClock,
29
- IterationDiverge,
30
- MaxIterationReached,
31
- MissingCaseForEnumError,
32
- NotObservableError,
33
- PowerGridBatchError,
34
- PowerGridDatasetError,
35
- PowerGridError,
36
- PowerGridNotImplementedError,
37
- PowerGridSerializationError,
38
- PowerGridUnreachableHitError,
39
- SparseMatrixError,
40
- )
41
- from power_grid_model._core.index_integer import IdxNp
42
- from power_grid_model._core.power_grid_core import power_grid_core as pgc
43
-
44
- VALIDATOR_MSG = "\nTry validate_input_data() or validate_batch_data() to validate your data.\n"
45
- # error codes
46
- PGM_NO_ERROR = 0
47
- PGM_REGULAR_ERROR = 1
48
- PGM_BATCH_ERROR = 2
49
- PGM_SERIALIZATION_ERROR = 3
50
-
51
- _MISSING_CASE_FOR_ENUM_RE = re.compile(r" is not implemented for (.+) #(-?\d+)!\n")
52
- _INVALID_ARGUMENTS_RE = re.compile(r" is not implemented for ") # multiple different flavors
53
- _CONFLICT_VOLTAGE_RE = re.compile(
54
- r"Conflicting voltage for line (-?\d+)\n voltage at from node (-?\d+) is (.*)\n"
55
- r" voltage at to node (-?\d+) is (.*)\n"
56
- )
57
- _INVALID_BRANCH_RE = re.compile(r"Branch (-?\d+) has the same from- and to-node (-?\d+),\n This is not allowed!\n")
58
- _INVALID_BRANCH3_RE = re.compile(
59
- r"Branch3 (-?\d+) is connected to the same node at least twice. Node 1\/2\/3: (-?\d+)\/(-?\d+)\/(-?\d+),\n"
60
- r" This is not allowed!\n"
61
- )
62
- _INVALID_TRANSFORMER_CLOCK_RE = re.compile(r"Invalid clock for transformer (-?\d+), clock (-?\d+)\n")
63
- _SPARSE_MATRIX_ERROR_RE = re.compile(r"Sparse matrix error") # multiple different flavors
64
- _NOT_OBSERVABLE_ERROR_RE = re.compile(r"Not enough measurements available for state estimation.\n")
65
- _ITERATION_DIVERGE_RE = re.compile(r"Iteration failed to converge") # potentially multiple different flavors
66
- _MAX_ITERATION_REACHED_RE = re.compile(r"Maximum number of iterations reached")
67
- _CONFLICT_ID_RE = re.compile(r"Conflicting id detected: (-?\d+)\n")
68
- _ID_NOT_FOUND_RE = re.compile(r"The id cannot be found: (-?\d+)\n")
69
- _INVALID_MEASURED_OBJECT_RE = re.compile(r"(\w+) measurement is not supported for object of type (\w+)")
70
- _INVALID_REGULATED_OBJECT_RE = re.compile(
71
- r"(\w+) regulator is not supported for object "
72
- ) # potentially multiple different flavors
73
- _AUTOMATIC_TAP_CALCULATION_ERROR_RE = re.compile(
74
- r"Automatic tap changing regulator with tap_side at LV side is not supported. Found at id (-?\d+)\n"
75
- )
76
- _AUTOMATIC_TAP_INPUT_ERROR_RE = re.compile(r"Automatic tap changer has invalid configuration")
77
-
78
- _ID_WRONG_TYPE_RE = re.compile(r"Wrong type for object with id (-?\d+)\n")
79
- _CONFLICTING_ANGLE_MEASUREMENT_TYPE_RE = re.compile(r"Conflicting angle measurement type")
80
- _INVALID_CALCULATION_METHOD_RE = re.compile(r"The calculation method is invalid for this calculation!")
81
- _INVALID_SHORT_CIRCUIT_PHASE_OR_TYPE_RE = re.compile(r"short circuit type") # multiple different flavors
82
- _POWER_GRID_DATASET_ERROR_RE = re.compile(r"Dataset error: ") # multiple different flavors
83
- _POWER_GRID_UNREACHABLE_HIT_RE = re.compile(r"Unreachable code hit when executing ") # multiple different flavors
84
- _POWER_GRID_SEARCH_OPT_INCMPT_RE = re.compile(r"Search method is incompatible with optimization strategy: ")
85
- _POWER_GRID_NOT_IMPLEMENTED_ERROR_RE = re.compile(r"The functionality is either not supported or not yet implemented!")
86
-
87
- _ERROR_MESSAGE_PATTERNS = {
88
- _MISSING_CASE_FOR_ENUM_RE: MissingCaseForEnumError,
89
- _INVALID_ARGUMENTS_RE: InvalidArguments,
90
- _CONFLICT_VOLTAGE_RE: ConflictVoltage,
91
- _INVALID_BRANCH_RE: InvalidBranch,
92
- _INVALID_BRANCH3_RE: InvalidBranch3,
93
- _INVALID_TRANSFORMER_CLOCK_RE: InvalidTransformerClock,
94
- _SPARSE_MATRIX_ERROR_RE: SparseMatrixError,
95
- _NOT_OBSERVABLE_ERROR_RE: NotObservableError,
96
- _ITERATION_DIVERGE_RE: IterationDiverge,
97
- _MAX_ITERATION_REACHED_RE: MaxIterationReached,
98
- _CONFLICT_ID_RE: ConflictID,
99
- _ID_NOT_FOUND_RE: IDNotFound,
100
- _INVALID_MEASURED_OBJECT_RE: InvalidMeasuredObject,
101
- _INVALID_REGULATED_OBJECT_RE: InvalidRegulatedObject,
102
- _AUTOMATIC_TAP_CALCULATION_ERROR_RE: AutomaticTapCalculationError,
103
- _AUTOMATIC_TAP_INPUT_ERROR_RE: AutomaticTapInputError,
104
- _ID_WRONG_TYPE_RE: IDWrongType,
105
- _CONFLICTING_ANGLE_MEASUREMENT_TYPE_RE: ConflictingAngleMeasurementType,
106
- _INVALID_CALCULATION_METHOD_RE: InvalidCalculationMethod,
107
- _INVALID_SHORT_CIRCUIT_PHASE_OR_TYPE_RE: InvalidShortCircuitPhaseOrType,
108
- _POWER_GRID_DATASET_ERROR_RE: PowerGridDatasetError,
109
- _POWER_GRID_UNREACHABLE_HIT_RE: PowerGridUnreachableHitError,
110
- _POWER_GRID_SEARCH_OPT_INCMPT_RE: PowerGridUnreachableHitError,
111
- _POWER_GRID_NOT_IMPLEMENTED_ERROR_RE: PowerGridNotImplementedError,
112
- }
113
-
114
-
115
- def _interpret_error(message: str, decode_error: bool = True) -> PowerGridError:
116
- if decode_error:
117
- for pattern, type_ in _ERROR_MESSAGE_PATTERNS.items():
118
- if pattern.search(message) is not None:
119
- return type_(message)
120
-
121
- return PowerGridError(message)
122
-
123
-
124
- def find_error(batch_size: int = 1, decode_error: bool = True) -> RuntimeError | None:
125
- """
126
- Check if there is an error and return it
127
-
128
- Args:
129
- batch_size: (int, optional): Size of batch. Defaults to 1.
130
- decode_error (bool, optional): Decode the error message(s) to derived error classes. Defaults to True
131
-
132
- Returns: error object, can be none
133
-
134
- """
135
- error_code: int = pgc.error_code()
136
- if error_code == PGM_NO_ERROR:
137
- return None
138
- if error_code == PGM_REGULAR_ERROR:
139
- error_message = pgc.error_message()
140
- error_message += VALIDATOR_MSG
141
- return _interpret_error(error_message, decode_error=decode_error)
142
- if error_code == PGM_BATCH_ERROR:
143
- error_message = "There are errors in the batch calculation." + VALIDATOR_MSG
144
- error = PowerGridBatchError(error_message)
145
- n_fails = pgc.n_failed_scenarios()
146
- failed_idxptr = pgc.failed_scenarios()
147
- failed_msgptr = pgc.batch_errors()
148
- error.failed_scenarios = np.ctypeslib.as_array(failed_idxptr, shape=(n_fails,)).copy()
149
- error.error_messages = [failed_msgptr[i].decode() for i in range(n_fails)] # type: ignore
150
- error.errors = [_interpret_error(message, decode_error=decode_error) for message in error.error_messages]
151
- all_scenarios = np.arange(batch_size, dtype=IdxNp)
152
- mask = np.ones(batch_size, dtype=np.bool_)
153
- mask[error.failed_scenarios] = False
154
- error.succeeded_scenarios = all_scenarios[mask]
155
- return error
156
- if error_code == PGM_SERIALIZATION_ERROR:
157
- return PowerGridSerializationError(pgc.error_message())
158
- return RuntimeError("Unknown error!")
159
-
160
-
161
- def assert_no_error(batch_size: int = 1, decode_error: bool = True):
162
- """
163
- Assert there is no error in the last operation
164
- If there is an error, raise it
165
-
166
- Args:
167
- batch_size (int, optional): Size of batch. Defaults to 1.
168
- decode_error (bool, optional): Decode the error message(s) to derived error classes. Defaults to True
169
-
170
- Returns:
171
-
172
- """
173
- error = find_error(batch_size=batch_size, decode_error=decode_error)
174
- if error is not None:
175
- raise error
176
-
177
-
178
- def handle_errors(
179
- continue_on_batch_error: bool, batch_size: int = 1, decode_error: bool = True
180
- ) -> PowerGridBatchError | None:
181
- """
182
- Handle any errors in the way that is specified.
183
-
184
- Args:
185
- continue_on_batch_error (bool): Return the error when the error type is a batch error instead of reraising it.
186
- batch_size (int, optional): Size of batch. Defaults to 1.
187
- decode_error (bool, optional): Decode the error message(s) to derived error classes. Defaults to True
188
-
189
- Raises:
190
- error: Any errors previously encountered, unless it was a batch error and continue_on_batch_error was True.
191
-
192
- Returns:
193
- PowerGridBatchError | None: None if there were no errors, or the previously encountered
194
- error if it was a batch error and continue_on_batch_error was True.
195
- """
196
- error: RuntimeError | None = find_error(batch_size=batch_size, decode_error=decode_error)
197
- if error is None:
198
- return None
199
-
200
- if continue_on_batch_error and isinstance(error, PowerGridBatchError):
201
- # continue on batch error
202
- return error
203
-
204
- # raise normal error
205
- raise error
1
+ # SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
2
+ #
3
+ # SPDX-License-Identifier: MPL-2.0
4
+
5
+ """
6
+ Error handling
7
+ """
8
+
9
+ import re
10
+
11
+ import numpy as np
12
+
13
+ from power_grid_model._core.errors import (
14
+ AutomaticTapCalculationError,
15
+ AutomaticTapInputError,
16
+ ConflictID,
17
+ ConflictingAngleMeasurementType,
18
+ ConflictVoltage,
19
+ IDNotFound,
20
+ IDWrongType,
21
+ InvalidArguments,
22
+ InvalidBranch,
23
+ InvalidBranch3,
24
+ InvalidCalculationMethod,
25
+ InvalidMeasuredObject,
26
+ InvalidRegulatedObject,
27
+ InvalidShortCircuitPhaseOrType,
28
+ InvalidTransformerClock,
29
+ IterationDiverge,
30
+ MaxIterationReached,
31
+ MissingCaseForEnumError,
32
+ NotObservableError,
33
+ PowerGridBatchError,
34
+ PowerGridDatasetError,
35
+ PowerGridError,
36
+ PowerGridNotImplementedError,
37
+ PowerGridSerializationError,
38
+ PowerGridUnreachableHitError,
39
+ SparseMatrixError,
40
+ TapSearchStrategyIncompatibleError,
41
+ )
42
+ from power_grid_model._core.index_integer import IdxNp
43
+ from power_grid_model._core.power_grid_core import power_grid_core as pgc
44
+
45
+ VALIDATOR_MSG = "\nTry validate_input_data() or validate_batch_data() to validate your data.\n"
46
+ # error codes
47
+ PGM_NO_ERROR = 0
48
+ PGM_REGULAR_ERROR = 1
49
+ PGM_BATCH_ERROR = 2
50
+ PGM_SERIALIZATION_ERROR = 3
51
+
52
+ _MISSING_CASE_FOR_ENUM_RE = re.compile(r" is not implemented for (.+) #(-?\d+)!\n")
53
+ _INVALID_ARGUMENTS_RE = re.compile(r" is not implemented for ") # multiple different flavors
54
+ _CONFLICT_VOLTAGE_RE = re.compile(
55
+ r"Conflicting voltage for line (-?\d+)\n voltage at from node (-?\d+) is (.*)\n"
56
+ r" voltage at to node (-?\d+) is (.*)\n"
57
+ )
58
+ _INVALID_BRANCH_RE = re.compile(r"Branch (-?\d+) has the same from- and to-node (-?\d+),\n This is not allowed!\n")
59
+ _INVALID_BRANCH3_RE = re.compile(
60
+ r"Branch3 (-?\d+) is connected to the same node at least twice. Node 1\/2\/3: (-?\d+)\/(-?\d+)\/(-?\d+),\n"
61
+ r" This is not allowed!\n"
62
+ )
63
+ _INVALID_TRANSFORMER_CLOCK_RE = re.compile(r"Invalid clock for transformer (-?\d+), clock (-?\d+)\n")
64
+ _SPARSE_MATRIX_ERROR_RE = re.compile(r"Sparse matrix error") # multiple different flavors
65
+ _NOT_OBSERVABLE_ERROR_RE = re.compile(r"Not enough measurements available for state estimation.\n")
66
+ _ITERATION_DIVERGE_RE = re.compile(r"Iteration failed to converge") # potentially multiple different flavors
67
+ _MAX_ITERATION_REACHED_RE = re.compile(r"Maximum number of iterations reached")
68
+ _CONFLICT_ID_RE = re.compile(r"Conflicting id detected: (-?\d+)\n")
69
+ _ID_NOT_FOUND_RE = re.compile(r"The id cannot be found: (-?\d+)\n")
70
+ _INVALID_MEASURED_OBJECT_RE = re.compile(r"(\w+) measurement is not supported for object of type (\w+)")
71
+ _INVALID_REGULATED_OBJECT_RE = re.compile(
72
+ r"(\w+) regulator is not supported for object "
73
+ ) # potentially multiple different flavors
74
+ _AUTOMATIC_TAP_CALCULATION_ERROR_RE = re.compile(
75
+ r"Automatic tap changing regulator with tap_side at LV side is not supported. Found at id (-?\d+)\n"
76
+ )
77
+ _AUTOMATIC_TAP_INPUT_ERROR_RE = re.compile(r"Automatic tap changer has invalid configuration")
78
+
79
+ _ID_WRONG_TYPE_RE = re.compile(r"Wrong type for object with id (-?\d+)\n")
80
+ _CONFLICTING_ANGLE_MEASUREMENT_TYPE_RE = re.compile(r"Conflicting angle measurement type")
81
+ _INVALID_CALCULATION_METHOD_RE = re.compile(r"The calculation method is invalid for this calculation!")
82
+ _INVALID_SHORT_CIRCUIT_PHASE_OR_TYPE_RE = re.compile(r"short circuit type") # multiple different flavors
83
+ _TAP_STRATEGY_SEARCH_OPT_INCMPT_RE = re.compile(r"Search method is incompatible with optimization strategy: ")
84
+ _POWER_GRID_DATASET_ERROR_RE = re.compile(r"Dataset error: ") # multiple different flavors
85
+ _POWER_GRID_UNREACHABLE_HIT_RE = re.compile(r"Unreachable code hit when executing ") # multiple different flavors
86
+ _POWER_GRID_NOT_IMPLEMENTED_ERROR_RE = re.compile(r"The functionality is either not supported or not yet implemented!")
87
+
88
+ _ERROR_MESSAGE_PATTERNS = {
89
+ _MISSING_CASE_FOR_ENUM_RE: MissingCaseForEnumError,
90
+ _INVALID_ARGUMENTS_RE: InvalidArguments,
91
+ _CONFLICT_VOLTAGE_RE: ConflictVoltage,
92
+ _INVALID_BRANCH_RE: InvalidBranch,
93
+ _INVALID_BRANCH3_RE: InvalidBranch3,
94
+ _INVALID_TRANSFORMER_CLOCK_RE: InvalidTransformerClock,
95
+ _SPARSE_MATRIX_ERROR_RE: SparseMatrixError,
96
+ _NOT_OBSERVABLE_ERROR_RE: NotObservableError,
97
+ _ITERATION_DIVERGE_RE: IterationDiverge,
98
+ _MAX_ITERATION_REACHED_RE: MaxIterationReached,
99
+ _CONFLICT_ID_RE: ConflictID,
100
+ _ID_NOT_FOUND_RE: IDNotFound,
101
+ _INVALID_MEASURED_OBJECT_RE: InvalidMeasuredObject,
102
+ _INVALID_REGULATED_OBJECT_RE: InvalidRegulatedObject,
103
+ _AUTOMATIC_TAP_CALCULATION_ERROR_RE: AutomaticTapCalculationError,
104
+ _AUTOMATIC_TAP_INPUT_ERROR_RE: AutomaticTapInputError,
105
+ _ID_WRONG_TYPE_RE: IDWrongType,
106
+ _CONFLICTING_ANGLE_MEASUREMENT_TYPE_RE: ConflictingAngleMeasurementType,
107
+ _INVALID_CALCULATION_METHOD_RE: InvalidCalculationMethod,
108
+ _INVALID_SHORT_CIRCUIT_PHASE_OR_TYPE_RE: InvalidShortCircuitPhaseOrType,
109
+ _TAP_STRATEGY_SEARCH_OPT_INCMPT_RE: TapSearchStrategyIncompatibleError,
110
+ _POWER_GRID_DATASET_ERROR_RE: PowerGridDatasetError,
111
+ _POWER_GRID_UNREACHABLE_HIT_RE: PowerGridUnreachableHitError,
112
+ _POWER_GRID_NOT_IMPLEMENTED_ERROR_RE: PowerGridNotImplementedError,
113
+ }
114
+
115
+
116
+ def _interpret_error(message: str, decode_error: bool = True) -> PowerGridError:
117
+ if decode_error:
118
+ for pattern, type_ in _ERROR_MESSAGE_PATTERNS.items():
119
+ if pattern.search(message) is not None:
120
+ return type_(message)
121
+
122
+ return PowerGridError(message)
123
+
124
+
125
+ def find_error(batch_size: int = 1, decode_error: bool = True) -> RuntimeError | None:
126
+ """
127
+ Check if there is an error and return it
128
+
129
+ Args:
130
+ batch_size: (int, optional): Size of batch. Defaults to 1.
131
+ decode_error (bool, optional): Decode the error message(s) to derived error classes. Defaults to True
132
+
133
+ Returns: error object, can be none
134
+
135
+ """
136
+ error_code: int = pgc.error_code()
137
+ if error_code == PGM_NO_ERROR:
138
+ return None
139
+ if error_code == PGM_REGULAR_ERROR:
140
+ error_message = pgc.error_message()
141
+ error_message += VALIDATOR_MSG
142
+ return _interpret_error(error_message, decode_error=decode_error)
143
+ if error_code == PGM_BATCH_ERROR:
144
+ error_message = "There are errors in the batch calculation." + VALIDATOR_MSG
145
+ error = PowerGridBatchError(error_message)
146
+ n_fails = pgc.n_failed_scenarios()
147
+ failed_idxptr = pgc.failed_scenarios()
148
+ failed_msgptr = pgc.batch_errors()
149
+ error.failed_scenarios = np.ctypeslib.as_array(failed_idxptr, shape=(n_fails,)).copy()
150
+ error.error_messages = [failed_msgptr[i].decode() for i in range(n_fails)] # type: ignore
151
+ error.errors = [_interpret_error(message, decode_error=decode_error) for message in error.error_messages]
152
+ all_scenarios = np.arange(batch_size, dtype=IdxNp)
153
+ mask = np.ones(batch_size, dtype=np.bool_)
154
+ mask[error.failed_scenarios] = False
155
+ error.succeeded_scenarios = all_scenarios[mask]
156
+ return error
157
+ if error_code == PGM_SERIALIZATION_ERROR:
158
+ return PowerGridSerializationError(pgc.error_message())
159
+ return RuntimeError("Unknown error!")
160
+
161
+
162
+ def assert_no_error(batch_size: int = 1, decode_error: bool = True):
163
+ """
164
+ Assert there is no error in the last operation
165
+ If there is an error, raise it
166
+
167
+ Args:
168
+ batch_size (int, optional): Size of batch. Defaults to 1.
169
+ decode_error (bool, optional): Decode the error message(s) to derived error classes. Defaults to True
170
+
171
+ Returns:
172
+
173
+ """
174
+ error = find_error(batch_size=batch_size, decode_error=decode_error)
175
+ if error is not None:
176
+ raise error
177
+
178
+
179
+ def handle_errors(
180
+ continue_on_batch_error: bool, batch_size: int = 1, decode_error: bool = True
181
+ ) -> PowerGridBatchError | None:
182
+ """
183
+ Handle any errors in the way that is specified.
184
+
185
+ Args:
186
+ continue_on_batch_error (bool): Return the error when the error type is a batch error instead of reraising it.
187
+ batch_size (int, optional): Size of batch. Defaults to 1.
188
+ decode_error (bool, optional): Decode the error message(s) to derived error classes. Defaults to True
189
+
190
+ Raises:
191
+ error: Any errors previously encountered, unless it was a batch error and continue_on_batch_error was True.
192
+
193
+ Returns:
194
+ PowerGridBatchError | None: None if there were no errors, or the previously encountered
195
+ error if it was a batch error and continue_on_batch_error was True.
196
+ """
197
+ error: RuntimeError | None = find_error(batch_size=batch_size, decode_error=decode_error)
198
+ if error is None:
199
+ return None
200
+
201
+ if continue_on_batch_error and isinstance(error, PowerGridBatchError):
202
+ # continue on batch error
203
+ return error
204
+
205
+ # raise normal error
206
+ raise error