power-grid-model 1.10.17__py3-none-win_amd64.whl → 1.12.119__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.

Files changed (67) hide show
  1. power_grid_model/__init__.py +54 -29
  2. power_grid_model/_core/__init__.py +3 -3
  3. power_grid_model/_core/buffer_handling.py +507 -478
  4. power_grid_model/_core/data_handling.py +195 -141
  5. power_grid_model/_core/data_types.py +142 -0
  6. power_grid_model/_core/dataset_definitions.py +109 -109
  7. power_grid_model/_core/enum.py +226 -0
  8. power_grid_model/_core/error_handling.py +215 -198
  9. power_grid_model/_core/errors.py +134 -0
  10. power_grid_model/_core/index_integer.py +17 -17
  11. power_grid_model/_core/options.py +71 -69
  12. power_grid_model/_core/power_grid_core.py +577 -562
  13. power_grid_model/_core/power_grid_dataset.py +545 -490
  14. power_grid_model/_core/power_grid_meta.py +262 -244
  15. power_grid_model/_core/power_grid_model.py +1025 -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 +251 -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 +332 -0
  22. power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/dataset_definitions.h +1060 -0
  23. power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/handle.h +111 -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 +130 -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 +224 -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 +319 -317
  47. power_grid_model/_core/typing.py +20 -0
  48. power_grid_model/{_utils.py → _core/utils.py} +798 -783
  49. power_grid_model/data_types.py +321 -319
  50. power_grid_model/enum.py +27 -214
  51. power_grid_model/errors.py +37 -119
  52. power_grid_model/typing.py +43 -48
  53. power_grid_model/utils.py +529 -400
  54. power_grid_model/validation/__init__.py +25 -10
  55. power_grid_model/validation/{rules.py → _rules.py} +1167 -962
  56. power_grid_model/validation/{validation.py → _validation.py} +1172 -1015
  57. power_grid_model/validation/assertions.py +93 -92
  58. power_grid_model/validation/errors.py +602 -524
  59. power_grid_model/validation/utils.py +313 -318
  60. {power_grid_model-1.10.17.dist-info → power_grid_model-1.12.119.dist-info}/METADATA +162 -165
  61. power_grid_model-1.12.119.dist-info/RECORD +65 -0
  62. {power_grid_model-1.10.17.dist-info → power_grid_model-1.12.119.dist-info}/WHEEL +1 -1
  63. power_grid_model-1.12.119.dist-info/entry_points.txt +3 -0
  64. power_grid_model/_core/_power_grid_core.dll +0 -0
  65. power_grid_model-1.10.17.dist-info/RECORD +0 -32
  66. power_grid_model-1.10.17.dist-info/top_level.txt +0 -1
  67. {power_grid_model-1.10.17.dist-info → power_grid_model-1.12.119.dist-info/licenses}/LICENSE +0 -0
@@ -1,198 +1,215 @@
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.index_integer import IdxNp
14
- from power_grid_model._core.power_grid_core import power_grid_core as pgc
15
- from power_grid_model.errors import (
16
- AutomaticTapCalculationError,
17
- ConflictID,
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
-
42
- VALIDATOR_MSG = "\nTry validate_input_data() or validate_batch_data() to validate your data.\n"
43
- # error codes
44
- PGM_NO_ERROR = 0
45
- PGM_REGULAR_ERROR = 1
46
- PGM_BATCH_ERROR = 2
47
- PGM_SERIALIZATION_ERROR = 3
48
-
49
- _MISSING_CASE_FOR_ENUM_RE = re.compile(r" is not implemented for (.+) #(-?\d+)!\n")
50
- _INVALID_ARGUMENTS_RE = re.compile(r" is not implemented for ") # multiple different flavors
51
- _CONFLICT_VOLTAGE_RE = re.compile(
52
- r"Conflicting voltage for line (-?\d+)\n voltage at from node (-?\d+) is (.*)\n"
53
- r" voltage at to node (-?\d+) is (.*)\n"
54
- )
55
- _INVALID_BRANCH_RE = re.compile(r"Branch (-?\d+) has the same from- and to-node (-?\d+),\n This is not allowed!\n")
56
- _INVALID_BRANCH3_RE = re.compile(
57
- r"Branch3 (-?\d+) is connected to the same node at least twice. Node 1\/2\/3: (-?\d+)\/(-?\d+)\/(-?\d+),\n"
58
- r" This is not allowed!\n"
59
- )
60
- _INVALID_TRANSFORMER_CLOCK_RE = re.compile(r"Invalid clock for transformer (-?\d+), clock (-?\d+)\n")
61
- _SPARSE_MATRIX_ERROR_RE = re.compile(r"Sparse matrix error") # multiple different flavors
62
- _NOT_OBSERVABLE_ERROR_RE = re.compile(r"Not enough measurements available for state estimation.\n")
63
- _ITERATION_DIVERGE_RE = re.compile(r"Iteration failed to converge") # potentially multiple different flavors
64
- _MAX_ITERATION_REACHED_RE = re.compile(r"Maximum number of iterations reached")
65
- _CONFLICT_ID_RE = re.compile(r"Conflicting id detected: (-?\d+)\n")
66
- _ID_NOT_FOUND_RE = re.compile(r"The id cannot be found: (-?\d+)\n")
67
- _INVALID_MEASURED_OBJECT_RE = re.compile(r"(\w+) measurement is not supported for object of type (\w+)")
68
- _INVALID_REGULATED_OBJECT_RE = re.compile(
69
- r"(\w+) regulator is not supported for object "
70
- ) # potentially multiple different flavors
71
- _AUTOMATIC_TAP_CALCULATION_ERROR_RE = re.compile(
72
- r"Automatic tap changing regulator with tap_side at LV side is not supported. Found at id (-?\d+)\n"
73
- )
74
- _ID_WRONG_TYPE_RE = re.compile(r"Wrong type for object with id (-?\d+)\n")
75
- _INVALID_CALCULATION_METHOD_RE = re.compile(r"The calculation method is invalid for this calculation!")
76
- _INVALID_SHORT_CIRCUIT_PHASE_OR_TYPE_RE = re.compile(r"short circuit type") # multiple different flavors
77
- _POWER_GRID_DATASET_ERROR_RE = re.compile(r"Dataset error: ") # multiple different flavors
78
- _POWER_GRID_UNREACHABLE_HIT_RE = re.compile(r"Unreachable code hit when executing ") # multiple different flavors
79
- _POWER_GRID_SEARCH_OPT_INCMPT_RE = re.compile(r"Search method is incompatible with optimization strategy: ")
80
- _POWER_GRID_NOT_IMPLEMENTED_ERROR_RE = re.compile(r"The functionality is either not supported or not yet implemented!")
81
-
82
- _ERROR_MESSAGE_PATTERNS = {
83
- _MISSING_CASE_FOR_ENUM_RE: MissingCaseForEnumError,
84
- _INVALID_ARGUMENTS_RE: InvalidArguments,
85
- _CONFLICT_VOLTAGE_RE: ConflictVoltage,
86
- _INVALID_BRANCH_RE: InvalidBranch,
87
- _INVALID_BRANCH3_RE: InvalidBranch3,
88
- _INVALID_TRANSFORMER_CLOCK_RE: InvalidTransformerClock,
89
- _SPARSE_MATRIX_ERROR_RE: SparseMatrixError,
90
- _NOT_OBSERVABLE_ERROR_RE: NotObservableError,
91
- _ITERATION_DIVERGE_RE: IterationDiverge,
92
- _MAX_ITERATION_REACHED_RE: MaxIterationReached,
93
- _CONFLICT_ID_RE: ConflictID,
94
- _ID_NOT_FOUND_RE: IDNotFound,
95
- _INVALID_MEASURED_OBJECT_RE: InvalidMeasuredObject,
96
- _INVALID_REGULATED_OBJECT_RE: InvalidRegulatedObject,
97
- _AUTOMATIC_TAP_CALCULATION_ERROR_RE: AutomaticTapCalculationError,
98
- _ID_WRONG_TYPE_RE: IDWrongType,
99
- _INVALID_CALCULATION_METHOD_RE: InvalidCalculationMethod,
100
- _INVALID_SHORT_CIRCUIT_PHASE_OR_TYPE_RE: InvalidShortCircuitPhaseOrType,
101
- _POWER_GRID_DATASET_ERROR_RE: PowerGridDatasetError,
102
- _POWER_GRID_UNREACHABLE_HIT_RE: PowerGridUnreachableHitError,
103
- _POWER_GRID_SEARCH_OPT_INCMPT_RE: PowerGridUnreachableHitError,
104
- _POWER_GRID_NOT_IMPLEMENTED_ERROR_RE: PowerGridNotImplementedError,
105
- }
106
-
107
-
108
- def _interpret_error(message: str, decode_error: bool = True) -> PowerGridError:
109
- if decode_error:
110
- for pattern, type_ in _ERROR_MESSAGE_PATTERNS.items():
111
- if pattern.search(message) is not None:
112
- return type_(message)
113
-
114
- return PowerGridError(message)
115
-
116
-
117
- def find_error(batch_size: int = 1, decode_error: bool = True) -> RuntimeError | None:
118
- """
119
- Check if there is an error and return it
120
-
121
- Args:
122
- batch_size: (int, optional): Size of batch. Defaults to 1.
123
- decode_error (bool, optional): Decode the error message(s) to derived error classes. Defaults to True
124
-
125
- Returns: error object, can be none
126
-
127
- """
128
- error_code: int = pgc.error_code()
129
- if error_code == PGM_NO_ERROR:
130
- return None
131
- if error_code == PGM_REGULAR_ERROR:
132
- error_message = pgc.error_message()
133
- error_message += VALIDATOR_MSG
134
- return _interpret_error(error_message, decode_error=decode_error)
135
- if error_code == PGM_BATCH_ERROR:
136
- error_message = "There are errors in the batch calculation." + VALIDATOR_MSG
137
- error = PowerGridBatchError(error_message)
138
- n_fails = pgc.n_failed_scenarios()
139
- failed_idxptr = pgc.failed_scenarios()
140
- failed_msgptr = pgc.batch_errors()
141
- error.failed_scenarios = np.ctypeslib.as_array(failed_idxptr, shape=(n_fails,)).copy()
142
- error.error_messages = [failed_msgptr[i].decode() for i in range(n_fails)] # type: ignore
143
- error.errors = [_interpret_error(message, decode_error=decode_error) for message in error.error_messages]
144
- all_scenarios = np.arange(batch_size, dtype=IdxNp)
145
- mask = np.ones(batch_size, dtype=np.bool_)
146
- mask[error.failed_scenarios] = False
147
- error.succeeded_scenarios = all_scenarios[mask]
148
- return error
149
- if error_code == PGM_SERIALIZATION_ERROR:
150
- return PowerGridSerializationError(pgc.error_message())
151
- return RuntimeError("Unknown error!")
152
-
153
-
154
- def assert_no_error(batch_size: int = 1, decode_error: bool = True):
155
- """
156
- Assert there is no error in the last operation
157
- If there is an error, raise it
158
-
159
- Args:
160
- batch_size (int, optional): Size of batch. Defaults to 1.
161
- decode_error (bool, optional): Decode the error message(s) to derived error classes. Defaults to True
162
-
163
- Returns:
164
-
165
- """
166
- error = find_error(batch_size=batch_size, decode_error=decode_error)
167
- if error is not None:
168
- raise error
169
-
170
-
171
- def handle_errors(
172
- continue_on_batch_error: bool, batch_size: int = 1, decode_error: bool = True
173
- ) -> PowerGridBatchError | None:
174
- """
175
- Handle any errors in the way that is specified.
176
-
177
- Args:
178
- continue_on_batch_error (bool): Return the error when the error type is a batch error instead of reraising it.
179
- batch_size (int, optional): Size of batch. Defaults to 1.
180
- decode_error (bool, optional): Decode the error message(s) to derived error classes. Defaults to True
181
-
182
- Raises:
183
- error: Any errors previously encountered, unless it was a batch error and continue_on_batch_error was True.
184
-
185
- Returns:
186
- PowerGridBatchError | None: None if there were no errors, or the previously encountered
187
- error if it was a batch error and continue_on_batch_error was True.
188
- """
189
- error: RuntimeError | None = find_error(batch_size=batch_size, decode_error=decode_error)
190
- if error is None:
191
- return None
192
-
193
- if continue_on_batch_error and isinstance(error, PowerGridBatchError):
194
- # continue on batch error
195
- return error
196
-
197
- # raise normal error
198
- 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
+ from enum import IntEnum
11
+
12
+ import numpy as np
13
+
14
+ from power_grid_model._core.errors import (
15
+ AutomaticTapCalculationError,
16
+ AutomaticTapInputError,
17
+ ConflictID,
18
+ ConflictingAngleMeasurementType,
19
+ ConflictVoltage,
20
+ IDNotFound,
21
+ IDWrongType,
22
+ InvalidArguments,
23
+ InvalidBranch,
24
+ InvalidBranch3,
25
+ InvalidCalculationMethod,
26
+ InvalidMeasuredObject,
27
+ InvalidRegulatedObject,
28
+ InvalidShortCircuitPhaseOrType,
29
+ InvalidTransformerClock,
30
+ IterationDiverge,
31
+ MaxIterationReached,
32
+ MissingCaseForEnumError,
33
+ NotObservableError,
34
+ PowerGridBatchError,
35
+ PowerGridDatasetError,
36
+ PowerGridError,
37
+ PowerGridIllegalOperationError,
38
+ PowerGridNotImplementedError,
39
+ PowerGridSerializationError,
40
+ PowerGridUnreachableHitError,
41
+ SparseMatrixError,
42
+ TapSearchStrategyIncompatibleError,
43
+ )
44
+ from power_grid_model._core.index_integer import IdxNp
45
+ from power_grid_model._core.power_grid_core import get_power_grid_core as get_pgc
46
+
47
+ VALIDATOR_MSG = "\nTry validate_input_data() or validate_batch_data() to validate your data.\n"
48
+
49
+
50
+ class _PgmCErrorCode(IntEnum):
51
+ NO_ERROR = 0
52
+ REGULAR_ERROR = 1
53
+ BATCH_ERROR = 2
54
+ SERIALIZATION_ERROR = 3
55
+
56
+
57
+ _MISSING_CASE_FOR_ENUM_RE = re.compile(r" is not implemented for (.+) #(-?\d+)!\n")
58
+ _INVALID_ARGUMENTS_RE = re.compile(r" is not implemented for ") # multiple different flavors
59
+ _CONFLICT_VOLTAGE_RE = re.compile(
60
+ r"Conflicting voltage for line (-?\d+)\n voltage at from node (-?\d+) is (.*)\n"
61
+ r" voltage at to node (-?\d+) is (.*)\n"
62
+ )
63
+ _INVALID_BRANCH_RE = re.compile(r"Branch (-?\d+) has the same from- and to-node (-?\d+),\n This is not allowed!\n")
64
+ _INVALID_BRANCH3_RE = re.compile(
65
+ r"Branch3 (-?\d+) is connected to the same node at least twice. Node 1\/2\/3: (-?\d+)\/(-?\d+)\/(-?\d+),\n"
66
+ r" This is not allowed!\n"
67
+ )
68
+ _INVALID_TRANSFORMER_CLOCK_RE = re.compile(r"Invalid clock for transformer (-?\d+), clock (-?\d+)\n")
69
+ _SPARSE_MATRIX_ERROR_RE = re.compile(r"Sparse matrix error") # multiple different flavors
70
+ _NOT_OBSERVABLE_ERROR_RE = re.compile(r"Not enough measurements available for state estimation.\n")
71
+ _ITERATION_DIVERGE_RE = re.compile(r"Iteration failed to converge") # potentially multiple different flavors
72
+ _MAX_ITERATION_REACHED_RE = re.compile(r"Maximum number of iterations reached")
73
+ _CONFLICT_ID_RE = re.compile(r"Conflicting id detected: (-?\d+)\n")
74
+ _ID_NOT_FOUND_RE = re.compile(r"The id cannot be found: (-?\d+)\n")
75
+ _INVALID_MEASURED_OBJECT_RE = re.compile(r"(\w+) measurement is not supported for object of type (\w+)")
76
+ _INVALID_REGULATED_OBJECT_RE = re.compile(
77
+ r"(\w+) regulator is not supported for object "
78
+ ) # potentially multiple different flavors
79
+ _AUTOMATIC_TAP_CALCULATION_ERROR_RE = re.compile(
80
+ r"Automatic tap changing regulator with tap_side at LV side is not supported. Found at id (-?\d+)\n"
81
+ )
82
+ _AUTOMATIC_TAP_INPUT_ERROR_RE = re.compile(r"Automatic tap changer has invalid configuration")
83
+
84
+ _ID_WRONG_TYPE_RE = re.compile(r"Wrong type for object with id (-?\d+)\n")
85
+ _CONFLICTING_ANGLE_MEASUREMENT_TYPE_RE = re.compile(r"Conflicting angle measurement type")
86
+ _INVALID_CALCULATION_METHOD_RE = re.compile(r"The calculation method is invalid for this calculation!")
87
+ _INVALID_SHORT_CIRCUIT_PHASE_OR_TYPE_RE = re.compile(r"short circuit type") # multiple different flavors
88
+ _TAP_STRATEGY_SEARCH_OPT_INCMPT_RE = re.compile(r"Search method is incompatible with optimization strategy: ")
89
+ _POWER_GRID_DATASET_ERROR_RE = re.compile(r"Dataset error: ") # multiple different flavors
90
+ _POWER_GRID_ILLEGAL_OPERATION_ERROR_RE = re.compile(r"Illegal operation: ") # multiple different flavors
91
+ _POWER_GRID_UNREACHABLE_HIT_RE = re.compile(r"Unreachable code hit when executing ") # multiple different flavors
92
+ _POWER_GRID_NOT_IMPLEMENTED_ERROR_RE = re.compile(r"The functionality is either not supported or not yet implemented!")
93
+
94
+ _ERROR_MESSAGE_PATTERNS = {
95
+ _MISSING_CASE_FOR_ENUM_RE: MissingCaseForEnumError,
96
+ _INVALID_ARGUMENTS_RE: InvalidArguments,
97
+ _CONFLICT_VOLTAGE_RE: ConflictVoltage,
98
+ _INVALID_BRANCH_RE: InvalidBranch,
99
+ _INVALID_BRANCH3_RE: InvalidBranch3,
100
+ _INVALID_TRANSFORMER_CLOCK_RE: InvalidTransformerClock,
101
+ _SPARSE_MATRIX_ERROR_RE: SparseMatrixError,
102
+ _NOT_OBSERVABLE_ERROR_RE: NotObservableError,
103
+ _ITERATION_DIVERGE_RE: IterationDiverge,
104
+ _MAX_ITERATION_REACHED_RE: MaxIterationReached,
105
+ _CONFLICT_ID_RE: ConflictID,
106
+ _ID_NOT_FOUND_RE: IDNotFound,
107
+ _INVALID_MEASURED_OBJECT_RE: InvalidMeasuredObject,
108
+ _INVALID_REGULATED_OBJECT_RE: InvalidRegulatedObject,
109
+ _AUTOMATIC_TAP_CALCULATION_ERROR_RE: AutomaticTapCalculationError,
110
+ _AUTOMATIC_TAP_INPUT_ERROR_RE: AutomaticTapInputError,
111
+ _ID_WRONG_TYPE_RE: IDWrongType,
112
+ _CONFLICTING_ANGLE_MEASUREMENT_TYPE_RE: ConflictingAngleMeasurementType,
113
+ _INVALID_CALCULATION_METHOD_RE: InvalidCalculationMethod,
114
+ _INVALID_SHORT_CIRCUIT_PHASE_OR_TYPE_RE: InvalidShortCircuitPhaseOrType,
115
+ _TAP_STRATEGY_SEARCH_OPT_INCMPT_RE: TapSearchStrategyIncompatibleError,
116
+ _POWER_GRID_DATASET_ERROR_RE: PowerGridDatasetError,
117
+ _POWER_GRID_ILLEGAL_OPERATION_ERROR_RE: PowerGridIllegalOperationError,
118
+ _POWER_GRID_UNREACHABLE_HIT_RE: PowerGridUnreachableHitError,
119
+ _POWER_GRID_NOT_IMPLEMENTED_ERROR_RE: PowerGridNotImplementedError,
120
+ }
121
+
122
+
123
+ def _interpret_error(message: str, decode_error: bool = True) -> PowerGridError:
124
+ if decode_error:
125
+ for pattern, type_ in _ERROR_MESSAGE_PATTERNS.items():
126
+ if pattern.search(message) is not None:
127
+ return type_(message)
128
+
129
+ return PowerGridError(message)
130
+
131
+
132
+ def find_error(batch_size: int = 1, decode_error: bool = True) -> RuntimeError | None:
133
+ """
134
+ Check if there is an error and return it
135
+
136
+ Args:
137
+ batch_size: (int, optional): Size of batch. Defaults to 1.
138
+ decode_error (bool, optional): Decode the error message(s) to derived error classes. Defaults to True
139
+
140
+ Returns: error object, can be none
141
+
142
+ """
143
+ error_code: int = get_pgc().error_code()
144
+ match error_code:
145
+ case _PgmCErrorCode.NO_ERROR:
146
+ return None
147
+ case _PgmCErrorCode.REGULAR_ERROR:
148
+ error_message = get_pgc().error_message()
149
+ error_message += VALIDATOR_MSG
150
+ return _interpret_error(error_message, decode_error=decode_error)
151
+ case _PgmCErrorCode.BATCH_ERROR:
152
+ error_message = "There are errors in the batch calculation." + VALIDATOR_MSG
153
+ error = PowerGridBatchError(error_message)
154
+ n_fails = get_pgc().n_failed_scenarios()
155
+ failed_idxptr = get_pgc().failed_scenarios()
156
+ failed_msgptr = get_pgc().batch_errors()
157
+ error.failed_scenarios = np.ctypeslib.as_array(failed_idxptr, shape=(n_fails,)).copy()
158
+ error.error_messages = [failed_msgptr[i].decode() for i in range(n_fails)] # type: ignore
159
+ error.errors = [_interpret_error(message, decode_error=decode_error) for message in error.error_messages]
160
+ all_scenarios = np.arange(batch_size, dtype=IdxNp)
161
+ mask = np.ones(batch_size, dtype=np.bool_)
162
+ mask[error.failed_scenarios] = False
163
+ error.succeeded_scenarios = all_scenarios[mask]
164
+ return error
165
+ case _PgmCErrorCode.SERIALIZATION_ERROR:
166
+ return PowerGridSerializationError(get_pgc().error_message())
167
+ case _:
168
+ return RuntimeError("Unknown error!")
169
+
170
+
171
+ def assert_no_error(batch_size: int = 1, decode_error: bool = True):
172
+ """
173
+ Assert there is no error in the last operation
174
+ If there is an error, raise it
175
+
176
+ Args:
177
+ batch_size (int, optional): Size of batch. Defaults to 1.
178
+ decode_error (bool, optional): Decode the error message(s) to derived error classes. Defaults to True
179
+
180
+ Returns:
181
+
182
+ """
183
+ error = find_error(batch_size=batch_size, decode_error=decode_error)
184
+ if error is not None:
185
+ raise error
186
+
187
+
188
+ def handle_errors(
189
+ continue_on_batch_error: bool, batch_size: int = 1, decode_error: bool = True
190
+ ) -> PowerGridBatchError | None:
191
+ """
192
+ Handle any errors in the way that is specified.
193
+
194
+ Args:
195
+ continue_on_batch_error (bool): Return the error when the error type is a batch error instead of reraising it.
196
+ batch_size (int, optional): Size of batch. Defaults to 1.
197
+ decode_error (bool, optional): Decode the error message(s) to derived error classes. Defaults to True
198
+
199
+ Raises:
200
+ error: Any errors previously encountered, unless it was a batch error and continue_on_batch_error was True.
201
+
202
+ Returns:
203
+ PowerGridBatchError | None: None if there were no errors, or the previously encountered
204
+ error if it was a batch error and continue_on_batch_error was True.
205
+ """
206
+ error: RuntimeError | None = find_error(batch_size=batch_size, decode_error=decode_error)
207
+ if error is None:
208
+ return None
209
+
210
+ if continue_on_batch_error and isinstance(error, PowerGridBatchError):
211
+ # continue on batch error
212
+ return error
213
+
214
+ # raise normal error
215
+ raise error
@@ -0,0 +1,134 @@
1
+ # SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
2
+ #
3
+ # SPDX-License-Identifier: MPL-2.0
4
+
5
+ """
6
+ This file contains error classes for library-internal use.
7
+ """
8
+
9
+ import numpy as np
10
+
11
+
12
+ class PowerGridError(RuntimeError):
13
+ """Generic power grid error."""
14
+
15
+
16
+ class PowerGridBatchError(PowerGridError):
17
+ """Error occurs in batch calculation."""
18
+
19
+ failed_scenarios: np.ndarray
20
+ succeeded_scenarios: np.ndarray
21
+ error_messages: list[str]
22
+ errors: list[PowerGridError]
23
+
24
+
25
+ class InvalidArguments(PowerGridError):
26
+ """A (combination of) input arguments is not valid."""
27
+
28
+
29
+ class MissingCaseForEnumError(InvalidArguments):
30
+ """An enum value is not covered in a for loop.
31
+
32
+ This usually happens when an invalid combination of (enum) settings is provided."""
33
+
34
+
35
+ class ConflictVoltage(PowerGridError):
36
+ """There is a confliciting voltage"""
37
+
38
+
39
+ class InvalidBranch(PowerGridError):
40
+ """A branch is invalid."""
41
+
42
+
43
+ class InvalidBranch3(PowerGridError):
44
+ """A branch3 is invalid."""
45
+
46
+
47
+ class InvalidTransformerClock(PowerGridError):
48
+ """Invalid transformer clock found."""
49
+
50
+
51
+ class SparseMatrixError(PowerGridError):
52
+ """Attempting to invert a non-invertible matrix."""
53
+
54
+
55
+ class NotObservableError(SparseMatrixError):
56
+ """Attempting to solve a non-observable system."""
57
+
58
+
59
+ class IterationDiverge(PowerGridError):
60
+ """Unable to iteratively converge to an optimum within the set number of iterations and precision."""
61
+
62
+
63
+ class MaxIterationReached(IterationDiverge):
64
+ """Maximum number of iterations reached."""
65
+
66
+
67
+ class InvalidID(PowerGridError):
68
+ """An ID is invalid."""
69
+
70
+
71
+ class IDNotFound(InvalidID):
72
+ """A reference to a non-existent ID was provided."""
73
+
74
+
75
+ class InvalidMeasuredObject(InvalidID):
76
+ """A provided measured object is invalid."""
77
+
78
+
79
+ class InvalidRegulatedObject(InvalidID):
80
+ """A provided regulated object is invalid."""
81
+
82
+
83
+ class IDWrongType(InvalidID):
84
+ """A referenced ID points to a component that cannot be referenced here."""
85
+
86
+
87
+ class ConflictID(InvalidID):
88
+ """Conflicting IDs found."""
89
+
90
+
91
+ class InvalidCalculationMethod(PowerGridError):
92
+ """Invalid calculation method provided."""
93
+
94
+
95
+ class AutomaticTapCalculationError(PowerGridError):
96
+ """Automatic tap changer with tap at LV side is unsupported for automatic tap changing calculation."""
97
+
98
+
99
+ class AutomaticTapInputError(PowerGridError):
100
+ """Automatic tap changer has invalid configuration."""
101
+
102
+
103
+ class ConflictingAngleMeasurementType(PowerGridError):
104
+ """Conflicting angle measurement types found."""
105
+
106
+
107
+ class InvalidShortCircuitPhaseOrType(PowerGridError):
108
+ """Invalid (combination of) short circuit types and phase(s) provided."""
109
+
110
+
111
+ class TapSearchStrategyIncompatibleError(InvalidArguments):
112
+ """Search method is incompatible with optimization strategy."""
113
+
114
+
115
+ class PowerGridSerializationError(PowerGridError):
116
+ """Error occurs during (de-)serialization."""
117
+
118
+
119
+ class PowerGridDatasetError(PowerGridError):
120
+ """Error occurs during dataset handling."""
121
+
122
+
123
+ class PowerGridNotImplementedError(PowerGridError):
124
+ """The functionality is either not supported or not yet implemented."""
125
+
126
+
127
+ class PowerGridIllegalOperationError(PowerGridError):
128
+ """An illegal operation was attempted to the C API, such as accessing a null pointer."""
129
+
130
+
131
+ class PowerGridUnreachableHitError(PowerGridError):
132
+ """Supposedly unreachable code was hit.
133
+
134
+ This usually means a failed assumption and may be caused by a bug in the PGM library."""
@@ -1,17 +1,17 @@
1
- # SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
2
- #
3
- # SPDX-License-Identifier: MPL-2.0
4
-
5
- """
6
- Definition of integers used by the calculation core
7
- """
8
-
9
- # define internal index integer
10
- from ctypes import c_int32, c_int64
11
-
12
- import numpy as np
13
-
14
- IdxC = c_int64
15
- IdxNp = np.int64
16
- IdC = c_int32
17
- IdNp = np.int32
1
+ # SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
2
+ #
3
+ # SPDX-License-Identifier: MPL-2.0
4
+
5
+ """
6
+ Definition of integers used by the calculation core
7
+ """
8
+
9
+ # define internal index integer
10
+ from ctypes import c_int32, c_int64
11
+
12
+ import numpy as np
13
+
14
+ IdxC = c_int64
15
+ IdxNp = np.int64
16
+ IdC = c_int32
17
+ IdNp = np.int32