power-grid-model 1.12.58__py3-none-win_amd64.whl → 1.12.59__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.
Potentially problematic release.
This version of power-grid-model might be problematic. Click here for more details.
- power_grid_model/__init__.py +54 -54
- power_grid_model/_core/__init__.py +3 -3
- power_grid_model/_core/buffer_handling.py +493 -493
- power_grid_model/_core/data_handling.py +141 -141
- power_grid_model/_core/data_types.py +132 -132
- power_grid_model/_core/dataset_definitions.py +109 -109
- power_grid_model/_core/enum.py +226 -226
- power_grid_model/_core/error_handling.py +206 -206
- power_grid_model/_core/errors.py +130 -130
- power_grid_model/_core/index_integer.py +17 -17
- power_grid_model/_core/options.py +71 -71
- power_grid_model/_core/power_grid_core.py +563 -563
- power_grid_model/_core/power_grid_dataset.py +535 -535
- power_grid_model/_core/power_grid_meta.py +243 -243
- power_grid_model/_core/power_grid_model.py +686 -686
- power_grid_model/_core/power_grid_model_c/__init__.py +3 -3
- power_grid_model/_core/power_grid_model_c/bin/power_grid_model_c.dll +0 -0
- power_grid_model/_core/power_grid_model_c/get_pgm_dll_path.py +63 -63
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/basics.h +255 -255
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/buffer.h +108 -108
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/dataset.h +316 -316
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/dataset_definitions.h +1052 -1052
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/handle.h +99 -99
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/meta_data.h +189 -189
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/model.h +125 -125
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/options.h +142 -142
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/serialization.h +118 -118
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c.h +36 -36
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/basics.hpp +65 -65
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/buffer.hpp +61 -61
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/dataset.hpp +220 -220
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/handle.hpp +108 -108
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/meta_data.hpp +84 -84
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/model.hpp +63 -63
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/options.hpp +52 -52
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/serialization.hpp +124 -124
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/utils.hpp +81 -81
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp.hpp +19 -19
- power_grid_model/_core/power_grid_model_c/lib/cmake/power_grid_model/power_grid_modelConfigVersion.cmake +3 -3
- power_grid_model/_core/serialization.py +317 -317
- power_grid_model/_core/typing.py +20 -20
- power_grid_model/_core/utils.py +798 -798
- power_grid_model/data_types.py +321 -321
- power_grid_model/enum.py +27 -27
- power_grid_model/errors.py +37 -37
- power_grid_model/typing.py +43 -43
- power_grid_model/utils.py +473 -473
- power_grid_model/validation/__init__.py +25 -25
- power_grid_model/validation/_rules.py +1171 -1171
- power_grid_model/validation/_validation.py +1172 -1172
- power_grid_model/validation/assertions.py +93 -93
- power_grid_model/validation/errors.py +602 -602
- power_grid_model/validation/utils.py +313 -313
- {power_grid_model-1.12.58.dist-info → power_grid_model-1.12.59.dist-info}/METADATA +1 -1
- power_grid_model-1.12.59.dist-info/RECORD +65 -0
- power_grid_model-1.12.58.dist-info/RECORD +0 -65
- {power_grid_model-1.12.58.dist-info → power_grid_model-1.12.59.dist-info}/WHEEL +0 -0
- {power_grid_model-1.12.58.dist-info → power_grid_model-1.12.59.dist-info}/entry_points.txt +0 -0
- {power_grid_model-1.12.58.dist-info → power_grid_model-1.12.59.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,206 +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
|
-
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
|
|
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
|