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.
- power_grid_model/__init__.py +54 -29
- power_grid_model/_core/__init__.py +3 -3
- power_grid_model/_core/buffer_handling.py +507 -478
- power_grid_model/_core/data_handling.py +195 -141
- power_grid_model/_core/data_types.py +142 -0
- power_grid_model/_core/dataset_definitions.py +109 -109
- power_grid_model/_core/enum.py +226 -0
- power_grid_model/_core/error_handling.py +215 -198
- power_grid_model/_core/errors.py +134 -0
- power_grid_model/_core/index_integer.py +17 -17
- power_grid_model/_core/options.py +71 -69
- power_grid_model/_core/power_grid_core.py +577 -562
- power_grid_model/_core/power_grid_dataset.py +545 -490
- power_grid_model/_core/power_grid_meta.py +262 -244
- power_grid_model/_core/power_grid_model.py +1025 -687
- power_grid_model/_core/power_grid_model_c/__init__.py +3 -0
- 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 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/basics.h +251 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/buffer.h +108 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/dataset.h +332 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/dataset_definitions.h +1060 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/handle.h +111 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/meta_data.h +189 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/model.h +130 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/options.h +142 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c/serialization.h +118 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_c.h +36 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/basics.hpp +65 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/buffer.hpp +61 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/dataset.hpp +224 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/handle.hpp +108 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/meta_data.hpp +84 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/model.hpp +63 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/options.hpp +52 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/serialization.hpp +124 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp/utils.hpp +81 -0
- power_grid_model/_core/power_grid_model_c/include/power_grid_model_cpp.hpp +19 -0
- power_grid_model/_core/power_grid_model_c/lib/cmake/power_grid_model/power_grid_modelConfig.cmake +37 -0
- power_grid_model/_core/power_grid_model_c/lib/cmake/power_grid_model/power_grid_modelConfigVersion.cmake +65 -0
- power_grid_model/_core/power_grid_model_c/lib/cmake/power_grid_model/power_grid_modelTargets-release.cmake +19 -0
- power_grid_model/_core/power_grid_model_c/lib/cmake/power_grid_model/power_grid_modelTargets.cmake +144 -0
- power_grid_model/_core/power_grid_model_c/lib/power_grid_model_c.lib +0 -0
- power_grid_model/_core/power_grid_model_c/share/LICENSE +292 -0
- power_grid_model/_core/power_grid_model_c/share/README.md +15 -0
- power_grid_model/_core/serialization.py +319 -317
- power_grid_model/_core/typing.py +20 -0
- power_grid_model/{_utils.py → _core/utils.py} +798 -783
- power_grid_model/data_types.py +321 -319
- power_grid_model/enum.py +27 -214
- power_grid_model/errors.py +37 -119
- power_grid_model/typing.py +43 -48
- power_grid_model/utils.py +529 -400
- power_grid_model/validation/__init__.py +25 -10
- power_grid_model/validation/{rules.py → _rules.py} +1167 -962
- power_grid_model/validation/{validation.py → _validation.py} +1172 -1015
- power_grid_model/validation/assertions.py +93 -92
- power_grid_model/validation/errors.py +602 -524
- power_grid_model/validation/utils.py +313 -318
- {power_grid_model-1.10.17.dist-info → power_grid_model-1.12.119.dist-info}/METADATA +162 -165
- power_grid_model-1.12.119.dist-info/RECORD +65 -0
- {power_grid_model-1.10.17.dist-info → power_grid_model-1.12.119.dist-info}/WHEEL +1 -1
- power_grid_model-1.12.119.dist-info/entry_points.txt +3 -0
- power_grid_model/_core/_power_grid_core.dll +0 -0
- power_grid_model-1.10.17.dist-info/RECORD +0 -32
- power_grid_model-1.10.17.dist-info/top_level.txt +0 -1
- {power_grid_model-1.10.17.dist-info → power_grid_model-1.12.119.dist-info/licenses}/LICENSE +0 -0
|
@@ -1,1015 +1,1172 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
|
|
2
|
-
#
|
|
3
|
-
# SPDX-License-Identifier: MPL-2.0
|
|
4
|
-
|
|
5
|
-
"""
|
|
6
|
-
Power Grid Model Validation Functions.
|
|
7
|
-
|
|
8
|
-
Although all functions are 'public', you probably only need validate_input_data() and validate_batch_data().
|
|
9
|
-
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import
|
|
15
|
-
from
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
import
|
|
20
|
-
|
|
21
|
-
from power_grid_model import
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
from power_grid_model.
|
|
27
|
-
|
|
28
|
-
Branch3Side,
|
|
29
|
-
BranchSide,
|
|
30
|
-
CalculationType,
|
|
31
|
-
FaultPhase,
|
|
32
|
-
FaultType,
|
|
33
|
-
LoadGenType,
|
|
34
|
-
MeasuredTerminalType,
|
|
35
|
-
WindingType,
|
|
36
|
-
)
|
|
37
|
-
from power_grid_model.validation.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
"""
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
"
|
|
313
|
-
"
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
"
|
|
319
|
-
"
|
|
320
|
-
"
|
|
321
|
-
"
|
|
322
|
-
"
|
|
323
|
-
"
|
|
324
|
-
"
|
|
325
|
-
"
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
"
|
|
331
|
-
"
|
|
332
|
-
"
|
|
333
|
-
"
|
|
334
|
-
"
|
|
335
|
-
"
|
|
336
|
-
"
|
|
337
|
-
"
|
|
338
|
-
"
|
|
339
|
-
"
|
|
340
|
-
"
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
"
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
required["
|
|
367
|
-
required["
|
|
368
|
-
if calculation_type is None or calculation_type == CalculationType.
|
|
369
|
-
required["
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
required[
|
|
373
|
-
required[
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
required[
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
"""
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
errors
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
errors
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
errors
|
|
551
|
-
errors +=
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
errors
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
errors
|
|
561
|
-
errors +=
|
|
562
|
-
errors +=
|
|
563
|
-
errors +=
|
|
564
|
-
errors
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
errors
|
|
569
|
-
errors +=
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
errors +=
|
|
581
|
-
data,
|
|
582
|
-
)
|
|
583
|
-
errors +=
|
|
584
|
-
errors +=
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
errors
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
errors
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
errors
|
|
599
|
-
errors +=
|
|
600
|
-
errors +=
|
|
601
|
-
errors +=
|
|
602
|
-
errors +=
|
|
603
|
-
errors +=
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
errors
|
|
610
|
-
errors +=
|
|
611
|
-
errors +=
|
|
612
|
-
errors +=
|
|
613
|
-
errors +=
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
errors +=
|
|
617
|
-
errors +=
|
|
618
|
-
errors += _all_greater_or_equal(
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
errors +=
|
|
622
|
-
errors +=
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
errors +=
|
|
626
|
-
errors += _all_greater_than_or_equal_to_zero(
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
errors +=
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
errors
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
errors
|
|
637
|
-
errors +=
|
|
638
|
-
errors +=
|
|
639
|
-
errors +=
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
errors
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
)
|
|
657
|
-
errors += _all_greater_or_equal(
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
)
|
|
664
|
-
errors +=
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
)
|
|
671
|
-
errors +=
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
)
|
|
678
|
-
errors +=
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
data,
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
"
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
"
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
data
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
ComponentType.three_winding_transformer,
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
data,
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
data,
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
data,
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
ComponentType.three_winding_transformer,
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
data
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
"
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
"
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
"
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
"
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
data
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
ComponentType.three_winding_transformer,
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
data,
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
data
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
ComponentType.three_winding_transformer,
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
"
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
data,
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
data
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
errors +=
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
errors
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
errors
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
)
|
|
892
|
-
errors += _all_valid_ids(
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
)
|
|
899
|
-
errors +=
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
errors +=
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
"
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
)
|
|
992
|
-
errors +=
|
|
993
|
-
data,
|
|
994
|
-
|
|
995
|
-
"
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
)
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
errors
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
)
|
|
1008
|
-
errors +=
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1
|
+
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Power Grid Model Validation Functions.
|
|
7
|
+
|
|
8
|
+
Although all functions are 'public', you probably only need validate_input_data() and validate_batch_data().
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import copy
|
|
13
|
+
from collections.abc import Sized as ABCSized
|
|
14
|
+
from itertools import chain
|
|
15
|
+
from typing import Literal
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
|
|
19
|
+
from power_grid_model._core.dataset_definitions import ComponentType, DatasetType, _map_to_component_types
|
|
20
|
+
from power_grid_model._core.power_grid_meta import power_grid_meta_data
|
|
21
|
+
from power_grid_model._core.utils import (
|
|
22
|
+
compatibility_convert_row_columnar_dataset as _compatibility_convert_row_columnar_dataset,
|
|
23
|
+
convert_batch_dataset_to_batch_list as _convert_batch_dataset_to_batch_list,
|
|
24
|
+
)
|
|
25
|
+
from power_grid_model.data_types import BatchDataset, Dataset, SingleDataset
|
|
26
|
+
from power_grid_model.enum import (
|
|
27
|
+
AngleMeasurementType,
|
|
28
|
+
Branch3Side,
|
|
29
|
+
BranchSide,
|
|
30
|
+
CalculationType,
|
|
31
|
+
FaultPhase,
|
|
32
|
+
FaultType,
|
|
33
|
+
LoadGenType,
|
|
34
|
+
MeasuredTerminalType,
|
|
35
|
+
WindingType,
|
|
36
|
+
)
|
|
37
|
+
from power_grid_model.validation._rules import (
|
|
38
|
+
all_between as _all_between,
|
|
39
|
+
all_between_or_at as _all_between_or_at,
|
|
40
|
+
all_boolean as _all_boolean,
|
|
41
|
+
all_cross_unique as _all_cross_unique,
|
|
42
|
+
all_enabled_identical as _all_enabled_identical,
|
|
43
|
+
all_finite as _all_finite,
|
|
44
|
+
all_greater_or_equal as _all_greater_or_equal,
|
|
45
|
+
all_greater_than_or_equal_to_zero as _all_greater_than_or_equal_to_zero,
|
|
46
|
+
all_greater_than_zero as _all_greater_than_zero,
|
|
47
|
+
all_in_valid_values as _all_in_valid_values,
|
|
48
|
+
all_less_than as _all_less_than,
|
|
49
|
+
all_not_two_values_equal as _all_not_two_values_equal,
|
|
50
|
+
all_not_two_values_zero as _all_not_two_values_zero,
|
|
51
|
+
all_same_current_angle_measurement_type_on_terminal as _all_same_current_angle_measurement_type_on_terminal,
|
|
52
|
+
all_same_sensor_type_on_same_terminal as _all_same_sensor_type_on_same_terminal,
|
|
53
|
+
all_unique as _all_unique,
|
|
54
|
+
all_valid_associated_enum_values as _all_valid_associated_enum_values,
|
|
55
|
+
all_valid_clocks as _all_valid_clocks,
|
|
56
|
+
all_valid_enum_values as _all_valid_enum_values,
|
|
57
|
+
all_valid_fault_phases as _all_valid_fault_phases,
|
|
58
|
+
all_valid_ids as _all_valid_ids,
|
|
59
|
+
any_voltage_angle_measurement_if_global_current_measurement as _any_voltage_angle_measurement_if_global_current_measurement, # noqa: E501
|
|
60
|
+
ids_valid_in_update_data_set as _ids_valid_in_update_data_set,
|
|
61
|
+
no_strict_subset_missing as _no_strict_subset_missing,
|
|
62
|
+
none_missing as _none_missing,
|
|
63
|
+
not_all_missing as _not_all_missing,
|
|
64
|
+
valid_p_q_sigma as _valid_p_q_sigma,
|
|
65
|
+
)
|
|
66
|
+
from power_grid_model.validation.errors import (
|
|
67
|
+
IdNotInDatasetError,
|
|
68
|
+
InvalidIdError,
|
|
69
|
+
MissingValueError,
|
|
70
|
+
MultiComponentNotUniqueError,
|
|
71
|
+
ValidationError,
|
|
72
|
+
)
|
|
73
|
+
from power_grid_model.validation.utils import _update_input_data
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def validate_input_data(
|
|
77
|
+
input_data: SingleDataset, calculation_type: CalculationType | None = None, symmetric: bool = True
|
|
78
|
+
) -> list[ValidationError] | None:
|
|
79
|
+
"""
|
|
80
|
+
Validates the entire input dataset:
|
|
81
|
+
|
|
82
|
+
1. Is the data structure correct? (checking data types and numpy array shapes)
|
|
83
|
+
2. Are all required values provided? (checking NaNs)
|
|
84
|
+
3. Are all ID's unique? (checking object identifiers across all components)
|
|
85
|
+
4. Are the supplied values valid? (checking limits and other logic as described in "Graph Data Model")
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
input_data: A power-grid-model input dataset
|
|
89
|
+
calculation_type: Supply a calculation method, to allow missing values for unused fields
|
|
90
|
+
symmetric: A boolean to state whether input data will be used for a symmetric or asymmetric calculation
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
None if the data is valid, or a list containing all validation errors.
|
|
94
|
+
|
|
95
|
+
Raises:
|
|
96
|
+
Error: KeyError | TypeError | ValueError: if the data structure is invalid.
|
|
97
|
+
"""
|
|
98
|
+
input_data = _map_to_component_types(input_data)
|
|
99
|
+
|
|
100
|
+
# Convert to row based if in columnar or mixed format format
|
|
101
|
+
row_input_data = _compatibility_convert_row_columnar_dataset(input_data, None, DatasetType.input)
|
|
102
|
+
|
|
103
|
+
# A deep copy is made of the input data, since default values will be added in the validation process
|
|
104
|
+
input_data_copy = copy.deepcopy(row_input_data)
|
|
105
|
+
|
|
106
|
+
assert_valid_data_structure(input_data_copy, DatasetType.input)
|
|
107
|
+
|
|
108
|
+
errors: list[ValidationError] = []
|
|
109
|
+
errors += validate_required_values(input_data_copy, calculation_type, symmetric)
|
|
110
|
+
errors += validate_unique_ids_across_components(input_data_copy)
|
|
111
|
+
errors += validate_values(input_data_copy, calculation_type)
|
|
112
|
+
return errors if errors else None
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def validate_batch_data(
|
|
116
|
+
input_data: SingleDataset,
|
|
117
|
+
update_data: BatchDataset,
|
|
118
|
+
calculation_type: CalculationType | None = None,
|
|
119
|
+
symmetric: bool = True,
|
|
120
|
+
) -> dict[int, list[ValidationError]] | None:
|
|
121
|
+
"""
|
|
122
|
+
The input dataset is validated:
|
|
123
|
+
|
|
124
|
+
1. Is the data structure correct? (checking data types and numpy array shapes)
|
|
125
|
+
2. Are all input data ID's unique? (checking object identifiers across all components)
|
|
126
|
+
|
|
127
|
+
For each batch the update data is validated:
|
|
128
|
+
3. Is the update data structure correct? (checking data types and numpy array shapes)
|
|
129
|
+
4. Are all update ID's valid? (checking object identifiers across update and input data)
|
|
130
|
+
|
|
131
|
+
Then (for each batch independently) the input dataset is updated with the batch's update data and validated:
|
|
132
|
+
5. Are all required values provided? (checking NaNs)
|
|
133
|
+
6. Are the supplied values valid? (checking limits and other logic as described in "Graph Data Model")
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
input_data: A power-grid-model input dataset
|
|
137
|
+
update_data: A power-grid-model update dataset (one or more batches)
|
|
138
|
+
calculation_type: Supply a calculation method, to allow missing values for unused fields
|
|
139
|
+
symmetric: A boolean to state whether input data will be used for a symmetric or asymmetric calculation
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
None if the data is valid, or a dictionary containing all validation errors,
|
|
143
|
+
where the key is the batch number (0-indexed).
|
|
144
|
+
|
|
145
|
+
Raises:
|
|
146
|
+
Error: KeyError | TypeError | ValueError: if the data structure is invalid.
|
|
147
|
+
"""
|
|
148
|
+
input_data = _map_to_component_types(input_data)
|
|
149
|
+
update_data = _map_to_component_types(update_data)
|
|
150
|
+
|
|
151
|
+
# Convert to row based if in columnar or mixed format
|
|
152
|
+
row_input_data = _compatibility_convert_row_columnar_dataset(input_data, None, DatasetType.input)
|
|
153
|
+
|
|
154
|
+
# A deep copy is made of the input data, since default values will be added in the validation process
|
|
155
|
+
input_data_copy = copy.deepcopy(row_input_data)
|
|
156
|
+
assert_valid_data_structure(input_data_copy, DatasetType.input)
|
|
157
|
+
|
|
158
|
+
input_errors: list[ValidationError] = list(validate_unique_ids_across_components(input_data_copy))
|
|
159
|
+
|
|
160
|
+
batch_data = _convert_batch_dataset_to_batch_list(update_data, DatasetType.update)
|
|
161
|
+
|
|
162
|
+
errors = {}
|
|
163
|
+
for batch, batch_update_data in enumerate(batch_data):
|
|
164
|
+
row_update_data = _compatibility_convert_row_columnar_dataset(batch_update_data, None, DatasetType.update)
|
|
165
|
+
assert_valid_data_structure(row_update_data, DatasetType.update)
|
|
166
|
+
id_errors: list[IdNotInDatasetError | InvalidIdError] = validate_ids(row_update_data, input_data_copy)
|
|
167
|
+
|
|
168
|
+
batch_errors = input_errors + id_errors
|
|
169
|
+
|
|
170
|
+
if not id_errors:
|
|
171
|
+
merged_data = _update_input_data(input_data_copy, row_update_data)
|
|
172
|
+
batch_errors += validate_required_values(merged_data, calculation_type, symmetric)
|
|
173
|
+
batch_errors += validate_values(merged_data, calculation_type)
|
|
174
|
+
|
|
175
|
+
if batch_errors:
|
|
176
|
+
errors[batch] = batch_errors
|
|
177
|
+
|
|
178
|
+
return errors if errors else None
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def assert_valid_data_structure(data: Dataset, data_type: DatasetType) -> None:
|
|
182
|
+
"""
|
|
183
|
+
Checks if all component names are valid and if the data inside the component matches the required Numpy
|
|
184
|
+
structured array as defined in the Power Grid Model meta data.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
data: A power-grid-model input/update dataset
|
|
188
|
+
data_type: 'input' or 'update'
|
|
189
|
+
|
|
190
|
+
Raises:
|
|
191
|
+
Error: KeyError, TypeError
|
|
192
|
+
|
|
193
|
+
"""
|
|
194
|
+
if data_type not in {DatasetType.input, DatasetType.update}:
|
|
195
|
+
raise KeyError(f"Unexpected data type '{data_type}' (should be 'input' or 'update')")
|
|
196
|
+
|
|
197
|
+
component_dtype = {component: meta.dtype for component, meta in power_grid_meta_data[data_type].items()}
|
|
198
|
+
for component, array in data.items():
|
|
199
|
+
# Check if component name is valid
|
|
200
|
+
if component not in component_dtype:
|
|
201
|
+
raise KeyError(f"Unknown component '{component}' in {data_type} data.")
|
|
202
|
+
|
|
203
|
+
# Check if component definition is as expected
|
|
204
|
+
dtype = component_dtype[component]
|
|
205
|
+
if isinstance(array, np.ndarray):
|
|
206
|
+
if array.dtype != dtype:
|
|
207
|
+
if not hasattr(array.dtype, "names") or not array.dtype.names:
|
|
208
|
+
raise TypeError(
|
|
209
|
+
f"Unexpected Numpy array ({array.dtype}) for '{component}' {data_type} data "
|
|
210
|
+
"(should be a Numpy structured array)."
|
|
211
|
+
)
|
|
212
|
+
raise TypeError(
|
|
213
|
+
f"Unexpected Numpy structured array; (expected = {dtype}, actual = {array.dtype}). "
|
|
214
|
+
f"For component '{component}'."
|
|
215
|
+
)
|
|
216
|
+
else:
|
|
217
|
+
raise TypeError(
|
|
218
|
+
f"Unexpected data type {type(array).__name__} for '{component}' {data_type} data "
|
|
219
|
+
"(should be a Numpy structured array)."
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def validate_unique_ids_across_components(data: SingleDataset) -> list[MultiComponentNotUniqueError]:
|
|
224
|
+
"""
|
|
225
|
+
Checks if all ids in the input dataset are unique
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
data: A power-grid-model input dataset
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
An empty list if all ids are unique, or a list of MultiComponentNotUniqueErrors for all components that
|
|
232
|
+
have non-unique ids
|
|
233
|
+
"""
|
|
234
|
+
return _all_cross_unique(data, [(component, "id") for component in data])
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def validate_ids(update_data: SingleDataset, input_data: SingleDataset) -> list[IdNotInDatasetError | InvalidIdError]:
|
|
238
|
+
"""
|
|
239
|
+
Checks if all ids of the components in the update data:
|
|
240
|
+
- exist and match those in the input data
|
|
241
|
+
- are not present but qualifies for optional id
|
|
242
|
+
|
|
243
|
+
This function should be called for every update dataset in a batch set
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
update_data: A single update dataset
|
|
247
|
+
input_data: Input dataset
|
|
248
|
+
|
|
249
|
+
Returns:
|
|
250
|
+
An empty list if all update data ids are valid, or a list of IdNotInDatasetErrors or InvalidIdError for
|
|
251
|
+
all update components that have invalid ids
|
|
252
|
+
|
|
253
|
+
"""
|
|
254
|
+
errors = (
|
|
255
|
+
_ids_valid_in_update_data_set(update_data, input_data, component, DatasetType.update)
|
|
256
|
+
for component in update_data
|
|
257
|
+
)
|
|
258
|
+
return list(chain(*errors))
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def validate_required_values( # noqa: PLR0915
|
|
262
|
+
data: SingleDataset, calculation_type: CalculationType | None = None, symmetric: bool = True
|
|
263
|
+
) -> list[MissingValueError]:
|
|
264
|
+
"""
|
|
265
|
+
Checks if all required data is available.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
data: A power-grid-model input dataset
|
|
269
|
+
calculation_type: Supply a calculation method, to allow missing values for unused fields
|
|
270
|
+
symmetric: A boolean to state whether input data will be used for a symmetric or asymmetric calculation
|
|
271
|
+
|
|
272
|
+
Returns:
|
|
273
|
+
An empty list if all required data is available, or a list of MissingValueErrors.
|
|
274
|
+
"""
|
|
275
|
+
# Base
|
|
276
|
+
required: dict[ComponentType | str, list[str]] = {"base": ["id"]}
|
|
277
|
+
|
|
278
|
+
# Nodes
|
|
279
|
+
required[ComponentType.node] = required["base"] + ["u_rated"]
|
|
280
|
+
|
|
281
|
+
# Branches
|
|
282
|
+
required["branch"] = required["base"] + ["from_node", "to_node", "from_status", "to_status"]
|
|
283
|
+
required[ComponentType.link] = required["branch"].copy()
|
|
284
|
+
required[ComponentType.line] = required["branch"] + ["r1", "x1", "c1", "tan1"]
|
|
285
|
+
required[ComponentType.asym_line] = required["branch"] + [
|
|
286
|
+
"r_aa",
|
|
287
|
+
"r_ba",
|
|
288
|
+
"r_bb",
|
|
289
|
+
"r_ca",
|
|
290
|
+
"r_cb",
|
|
291
|
+
"r_cc",
|
|
292
|
+
"x_aa",
|
|
293
|
+
"x_ba",
|
|
294
|
+
"x_bb",
|
|
295
|
+
"x_ca",
|
|
296
|
+
"x_cb",
|
|
297
|
+
"x_cc",
|
|
298
|
+
]
|
|
299
|
+
required[ComponentType.transformer] = required["branch"] + [
|
|
300
|
+
"u1",
|
|
301
|
+
"u2",
|
|
302
|
+
"sn",
|
|
303
|
+
"uk",
|
|
304
|
+
"pk",
|
|
305
|
+
"i0",
|
|
306
|
+
"p0",
|
|
307
|
+
"winding_from",
|
|
308
|
+
"winding_to",
|
|
309
|
+
"clock",
|
|
310
|
+
"tap_side",
|
|
311
|
+
"tap_min",
|
|
312
|
+
"tap_max",
|
|
313
|
+
"tap_size",
|
|
314
|
+
]
|
|
315
|
+
# Branch3
|
|
316
|
+
required["branch3"] = required["base"] + ["node_1", "node_2", "node_3", "status_1", "status_2", "status_3"]
|
|
317
|
+
required[ComponentType.three_winding_transformer] = required["branch3"] + [
|
|
318
|
+
"u1",
|
|
319
|
+
"u2",
|
|
320
|
+
"u3",
|
|
321
|
+
"sn_1",
|
|
322
|
+
"sn_2",
|
|
323
|
+
"sn_3",
|
|
324
|
+
"uk_12",
|
|
325
|
+
"uk_13",
|
|
326
|
+
"uk_23",
|
|
327
|
+
"pk_12",
|
|
328
|
+
"pk_13",
|
|
329
|
+
"pk_23",
|
|
330
|
+
"i0",
|
|
331
|
+
"p0",
|
|
332
|
+
"winding_1",
|
|
333
|
+
"winding_2",
|
|
334
|
+
"winding_3",
|
|
335
|
+
"clock_12",
|
|
336
|
+
"clock_13",
|
|
337
|
+
"tap_side",
|
|
338
|
+
"tap_min",
|
|
339
|
+
"tap_max",
|
|
340
|
+
"tap_size",
|
|
341
|
+
]
|
|
342
|
+
|
|
343
|
+
# Regulators
|
|
344
|
+
required["regulator"] = required["base"] + ["regulated_object", "status"]
|
|
345
|
+
required[ComponentType.transformer_tap_regulator] = required["regulator"]
|
|
346
|
+
if calculation_type is None or calculation_type == CalculationType.power_flow:
|
|
347
|
+
required[ComponentType.transformer_tap_regulator] += ["control_side", "u_set", "u_band"]
|
|
348
|
+
|
|
349
|
+
# Appliances
|
|
350
|
+
required["appliance"] = required["base"] + ["node", "status"]
|
|
351
|
+
required[ComponentType.source] = required["appliance"].copy()
|
|
352
|
+
if calculation_type is None or calculation_type == CalculationType.power_flow:
|
|
353
|
+
required[ComponentType.source] += ["u_ref"]
|
|
354
|
+
required[ComponentType.shunt] = required["appliance"] + ["g1", "b1"]
|
|
355
|
+
required["generic_load_gen"] = required["appliance"] + ["type"]
|
|
356
|
+
if calculation_type is None or calculation_type == CalculationType.power_flow:
|
|
357
|
+
required["generic_load_gen"] += ["p_specified", "q_specified"]
|
|
358
|
+
required[ComponentType.sym_load] = required["generic_load_gen"].copy()
|
|
359
|
+
required[ComponentType.asym_load] = required["generic_load_gen"].copy()
|
|
360
|
+
required[ComponentType.sym_gen] = required["generic_load_gen"].copy()
|
|
361
|
+
required[ComponentType.asym_gen] = required["generic_load_gen"].copy()
|
|
362
|
+
|
|
363
|
+
# Sensors
|
|
364
|
+
required["sensor"] = required["base"] + ["measured_object"]
|
|
365
|
+
required["voltage_sensor"] = required["sensor"].copy()
|
|
366
|
+
required["power_sensor"] = required["sensor"] + ["measured_terminal_type"]
|
|
367
|
+
required["current_sensor"] = required["sensor"] + ["measured_terminal_type", "angle_measurement_type"]
|
|
368
|
+
if calculation_type is None or calculation_type == CalculationType.state_estimation:
|
|
369
|
+
required["voltage_sensor"] += ["u_sigma", "u_measured"]
|
|
370
|
+
required["power_sensor"] += ["p_measured", "q_measured"] # power_sigma, p_sigma and q_sigma are checked later
|
|
371
|
+
required["current_sensor"] += ["i_sigma", "i_angle_sigma", "i_measured", "i_angle_measured"]
|
|
372
|
+
required[ComponentType.sym_voltage_sensor] = required["voltage_sensor"].copy()
|
|
373
|
+
required[ComponentType.asym_voltage_sensor] = required["voltage_sensor"].copy()
|
|
374
|
+
required[ComponentType.sym_current_sensor] = required["current_sensor"].copy()
|
|
375
|
+
required[ComponentType.asym_current_sensor] = required["current_sensor"].copy()
|
|
376
|
+
|
|
377
|
+
# Different requirements for individual sensors. Avoid shallow copy.
|
|
378
|
+
for sensor_type in (ComponentType.sym_power_sensor, ComponentType.asym_power_sensor):
|
|
379
|
+
required[sensor_type] = required["power_sensor"].copy()
|
|
380
|
+
|
|
381
|
+
# Faults
|
|
382
|
+
required[ComponentType.fault] = required["base"] + ["fault_object"]
|
|
383
|
+
asym_sc = False
|
|
384
|
+
if calculation_type is None or calculation_type == CalculationType.short_circuit:
|
|
385
|
+
required[ComponentType.fault] += ["status", "fault_type"]
|
|
386
|
+
if ComponentType.fault in data:
|
|
387
|
+
for elem in data[ComponentType.fault]["fault_type"]:
|
|
388
|
+
if elem not in (FaultType.three_phase, FaultType.nan):
|
|
389
|
+
asym_sc = True
|
|
390
|
+
break
|
|
391
|
+
|
|
392
|
+
if not symmetric or asym_sc:
|
|
393
|
+
required[ComponentType.line] += ["r0", "x0", "c0", "tan0"]
|
|
394
|
+
required[ComponentType.shunt] += ["g0", "b0"]
|
|
395
|
+
|
|
396
|
+
errors = _validate_required_in_data(data, required)
|
|
397
|
+
|
|
398
|
+
if calculation_type is None or calculation_type == CalculationType.state_estimation:
|
|
399
|
+
errors += _validate_required_power_sigma_or_p_q_sigma(data, ComponentType.sym_power_sensor)
|
|
400
|
+
errors += _validate_required_power_sigma_or_p_q_sigma(data, ComponentType.asym_power_sensor)
|
|
401
|
+
|
|
402
|
+
return errors
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
def _validate_required_in_data(data: SingleDataset, required: dict[ComponentType | str, list[str]]):
|
|
406
|
+
"""
|
|
407
|
+
Checks if all required data is available.
|
|
408
|
+
|
|
409
|
+
Args:
|
|
410
|
+
data: A power-grid-model input dataset
|
|
411
|
+
required: a list of required fields (a list of str), per component when applicaple (a list of str or str lists)
|
|
412
|
+
|
|
413
|
+
Returns:
|
|
414
|
+
An empty list if all required data is available, or a list of MissingValueErrors.
|
|
415
|
+
"""
|
|
416
|
+
|
|
417
|
+
def is_valid_component(data, component):
|
|
418
|
+
return (
|
|
419
|
+
not (isinstance(data[component], np.ndarray) and data[component].size == 0)
|
|
420
|
+
and data[component] is not None
|
|
421
|
+
and isinstance(data[component], ABCSized)
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
results: list[MissingValueError] = []
|
|
425
|
+
|
|
426
|
+
for component in data:
|
|
427
|
+
if is_valid_component(data, component):
|
|
428
|
+
items = required.get(component, [])
|
|
429
|
+
results += _none_missing(data, component, items)
|
|
430
|
+
|
|
431
|
+
return results
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def _validate_required_power_sigma_or_p_q_sigma(
|
|
435
|
+
data: SingleDataset,
|
|
436
|
+
power_sensor: Literal[ComponentType.sym_power_sensor, ComponentType.asym_power_sensor],
|
|
437
|
+
) -> list[MissingValueError]:
|
|
438
|
+
"""
|
|
439
|
+
Check that either `p_sigma` and `q_sigma` are all provided, or that `power_sigma` is provided.
|
|
440
|
+
|
|
441
|
+
Args:
|
|
442
|
+
data: SingleDataset, pgm data
|
|
443
|
+
sensor: the power sensor type, either ComponentType.sym_power_sensor or ComponentType.asym_power_sensor
|
|
444
|
+
"""
|
|
445
|
+
result: list[MissingValueError] = []
|
|
446
|
+
|
|
447
|
+
if power_sensor in data:
|
|
448
|
+
sensor_data = data[power_sensor]
|
|
449
|
+
p_sigma = sensor_data["p_sigma"]
|
|
450
|
+
q_sigma = sensor_data["q_sigma"]
|
|
451
|
+
|
|
452
|
+
asym_axes = tuple(range(sensor_data.ndim, p_sigma.ndim))
|
|
453
|
+
all_pq_sigma_missing_mask = np.all(np.isnan(p_sigma), axis=asym_axes) & np.all(
|
|
454
|
+
np.isnan(q_sigma), axis=asym_axes
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
result += _validate_required_in_data(
|
|
458
|
+
{power_sensor: sensor_data[all_pq_sigma_missing_mask]}, required={power_sensor: ["power_sigma"]}
|
|
459
|
+
)
|
|
460
|
+
result += _validate_required_in_data(
|
|
461
|
+
{power_sensor: sensor_data[~all_pq_sigma_missing_mask]}, required={power_sensor: ["p_sigma", "q_sigma"]}
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
return result
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
def validate_values(data: SingleDataset, calculation_type: CalculationType | None = None) -> list[ValidationError]:
|
|
468
|
+
"""
|
|
469
|
+
For each component supplied in the data, call the appropriate validation function
|
|
470
|
+
|
|
471
|
+
Args:
|
|
472
|
+
data: A power-grid-model input dataset
|
|
473
|
+
calculation_type: Supply a calculation method, to allow missing values for unused fields
|
|
474
|
+
|
|
475
|
+
Returns:
|
|
476
|
+
An empty list if all required data is valid, or a list of ValidationErrors.
|
|
477
|
+
|
|
478
|
+
"""
|
|
479
|
+
errors: list[ValidationError] = list(
|
|
480
|
+
_all_finite(
|
|
481
|
+
data=data,
|
|
482
|
+
exceptions={
|
|
483
|
+
ComponentType.sym_power_sensor: ["power_sigma", "p_sigma", "q_sigma"],
|
|
484
|
+
ComponentType.asym_power_sensor: ["power_sigma", "p_sigma", "q_sigma"],
|
|
485
|
+
ComponentType.sym_voltage_sensor: ["u_sigma"],
|
|
486
|
+
ComponentType.asym_voltage_sensor: ["u_sigma"],
|
|
487
|
+
ComponentType.sym_current_sensor: ["i_sigma", "i_angle_sigma"],
|
|
488
|
+
ComponentType.asym_current_sensor: ["i_sigma", "i_angle_sigma"],
|
|
489
|
+
},
|
|
490
|
+
)
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
component_validators = {
|
|
494
|
+
ComponentType.node: validate_node,
|
|
495
|
+
ComponentType.line: validate_line,
|
|
496
|
+
ComponentType.asym_line: validate_asym_line,
|
|
497
|
+
ComponentType.link: lambda d: validate_branch(d, ComponentType.link),
|
|
498
|
+
ComponentType.generic_branch: validate_generic_branch,
|
|
499
|
+
ComponentType.transformer: validate_transformer,
|
|
500
|
+
ComponentType.three_winding_transformer: validate_three_winding_transformer,
|
|
501
|
+
ComponentType.source: validate_source,
|
|
502
|
+
ComponentType.sym_load: lambda d: validate_generic_load_gen(d, ComponentType.sym_load),
|
|
503
|
+
ComponentType.sym_gen: lambda d: validate_generic_load_gen(d, ComponentType.sym_gen),
|
|
504
|
+
ComponentType.asym_load: lambda d: validate_generic_load_gen(d, ComponentType.asym_load),
|
|
505
|
+
ComponentType.asym_gen: lambda d: validate_generic_load_gen(d, ComponentType.asym_gen),
|
|
506
|
+
ComponentType.shunt: validate_shunt,
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
for component, validator in component_validators.items():
|
|
510
|
+
if component in data:
|
|
511
|
+
errors += validator(data)
|
|
512
|
+
|
|
513
|
+
if calculation_type in (None, CalculationType.state_estimation):
|
|
514
|
+
if ComponentType.sym_voltage_sensor in data:
|
|
515
|
+
errors += validate_generic_voltage_sensor(data, ComponentType.sym_voltage_sensor)
|
|
516
|
+
if ComponentType.asym_voltage_sensor in data:
|
|
517
|
+
errors += validate_generic_voltage_sensor(data, ComponentType.asym_voltage_sensor)
|
|
518
|
+
if ComponentType.sym_power_sensor in data:
|
|
519
|
+
errors += validate_generic_power_sensor(data, ComponentType.sym_power_sensor)
|
|
520
|
+
if ComponentType.asym_power_sensor in data:
|
|
521
|
+
errors += validate_generic_power_sensor(data, ComponentType.asym_power_sensor)
|
|
522
|
+
if ComponentType.sym_current_sensor in data:
|
|
523
|
+
errors += validate_generic_current_sensor(data, ComponentType.sym_current_sensor)
|
|
524
|
+
if ComponentType.asym_current_sensor in data:
|
|
525
|
+
errors += validate_generic_current_sensor(data, ComponentType.asym_current_sensor)
|
|
526
|
+
|
|
527
|
+
errors += validate_no_mixed_sensors_on_same_terminal(data)
|
|
528
|
+
|
|
529
|
+
if calculation_type in (None, CalculationType.short_circuit) and ComponentType.fault in data:
|
|
530
|
+
errors += validate_fault(data)
|
|
531
|
+
|
|
532
|
+
if calculation_type in (None, CalculationType.power_flow) and ComponentType.transformer_tap_regulator in data:
|
|
533
|
+
errors += validate_transformer_tap_regulator(data)
|
|
534
|
+
|
|
535
|
+
return errors
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def validate_base(data: SingleDataset, component: ComponentType) -> list[ValidationError]:
|
|
539
|
+
errors: list[ValidationError] = list(_all_unique(data, component, "id"))
|
|
540
|
+
return errors
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
def validate_node(data: SingleDataset) -> list[ValidationError]:
|
|
544
|
+
errors = validate_base(data, ComponentType.node)
|
|
545
|
+
errors += _all_greater_than_zero(data, ComponentType.node, "u_rated")
|
|
546
|
+
return errors
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
def validate_branch(data: SingleDataset, component: ComponentType) -> list[ValidationError]:
|
|
550
|
+
errors = validate_base(data, component)
|
|
551
|
+
errors += _all_valid_ids(data, component, "from_node", ComponentType.node)
|
|
552
|
+
errors += _all_valid_ids(data, component, "to_node", ComponentType.node)
|
|
553
|
+
errors += _all_not_two_values_equal(data, component, "to_node", "from_node")
|
|
554
|
+
errors += _all_boolean(data, component, "from_status")
|
|
555
|
+
errors += _all_boolean(data, component, "to_status")
|
|
556
|
+
return errors
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
def validate_line(data: SingleDataset) -> list[ValidationError]:
|
|
560
|
+
errors = validate_branch(data, ComponentType.line)
|
|
561
|
+
errors += _all_not_two_values_zero(data, ComponentType.line, "r1", "x1")
|
|
562
|
+
errors += _all_not_two_values_zero(data, ComponentType.line, "r0", "x0")
|
|
563
|
+
errors += _all_greater_than_zero(data, ComponentType.line, "i_n")
|
|
564
|
+
return errors
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
def validate_asym_line(data: SingleDataset) -> list[ValidationError]:
|
|
568
|
+
errors = validate_branch(data, ComponentType.asym_line)
|
|
569
|
+
errors += _all_greater_than_zero(data, ComponentType.asym_line, "i_n")
|
|
570
|
+
required_fields = ["r_aa", "r_ba", "r_bb", "r_ca", "r_cb", "r_cc", "x_aa", "x_ba", "x_bb", "x_ca", "x_cb", "x_cc"]
|
|
571
|
+
optional_r_matrix_fields = ["r_na", "r_nb", "r_nc", "r_nn"]
|
|
572
|
+
optional_x_matrix_fields = ["x_na", "x_nb", "x_nc", "x_nn"]
|
|
573
|
+
required_c_matrix_fields = ["c_aa", "c_ba", "c_bb", "c_ca", "c_cb", "c_cc"]
|
|
574
|
+
c_fields = ["c0", "c1"]
|
|
575
|
+
for field in (
|
|
576
|
+
required_fields + optional_r_matrix_fields + optional_x_matrix_fields + required_c_matrix_fields + c_fields
|
|
577
|
+
):
|
|
578
|
+
errors += _all_greater_than_zero(data, ComponentType.asym_line, field)
|
|
579
|
+
|
|
580
|
+
errors += _no_strict_subset_missing(
|
|
581
|
+
data, optional_r_matrix_fields + optional_x_matrix_fields, ComponentType.asym_line
|
|
582
|
+
)
|
|
583
|
+
errors += _no_strict_subset_missing(data, required_c_matrix_fields, ComponentType.asym_line)
|
|
584
|
+
errors += _no_strict_subset_missing(data, c_fields, ComponentType.asym_line)
|
|
585
|
+
errors += _not_all_missing(data, required_c_matrix_fields + c_fields, ComponentType.asym_line)
|
|
586
|
+
|
|
587
|
+
return errors
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
def validate_generic_branch(data: SingleDataset) -> list[ValidationError]:
|
|
591
|
+
errors = validate_branch(data, ComponentType.generic_branch)
|
|
592
|
+
errors += _all_greater_than_zero(data, ComponentType.generic_branch, "k")
|
|
593
|
+
errors += _all_greater_than_or_equal_to_zero(data, ComponentType.generic_branch, "sn")
|
|
594
|
+
return errors
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
def validate_transformer(data: SingleDataset) -> list[ValidationError]:
|
|
598
|
+
errors = validate_branch(data, ComponentType.transformer)
|
|
599
|
+
errors += _all_greater_than_zero(data, ComponentType.transformer, "u1")
|
|
600
|
+
errors += _all_greater_than_zero(data, ComponentType.transformer, "u2")
|
|
601
|
+
errors += _all_greater_than_zero(data, ComponentType.transformer, "sn")
|
|
602
|
+
errors += _all_greater_or_equal(data, ComponentType.transformer, "uk", "pk/sn")
|
|
603
|
+
errors += _all_between(data, ComponentType.transformer, "uk", 0, 1)
|
|
604
|
+
errors += _all_greater_than_or_equal_to_zero(data, ComponentType.transformer, "pk")
|
|
605
|
+
errors += _all_greater_or_equal(data, ComponentType.transformer, "i0", "p0/sn")
|
|
606
|
+
errors += _all_less_than(data, ComponentType.transformer, "i0", 1)
|
|
607
|
+
errors += _all_greater_than_or_equal_to_zero(data, ComponentType.transformer, "p0")
|
|
608
|
+
errors += _all_valid_enum_values(data, ComponentType.transformer, "winding_from", WindingType)
|
|
609
|
+
errors += _all_valid_enum_values(data, ComponentType.transformer, "winding_to", WindingType)
|
|
610
|
+
errors += _all_between_or_at(data, ComponentType.transformer, "clock", -12, 12)
|
|
611
|
+
errors += _all_valid_clocks(data, ComponentType.transformer, "clock", "winding_from", "winding_to")
|
|
612
|
+
errors += _all_valid_enum_values(data, ComponentType.transformer, "tap_side", BranchSide)
|
|
613
|
+
errors += _all_between_or_at(
|
|
614
|
+
data, ComponentType.transformer, "tap_pos", "tap_min", "tap_max", data[ComponentType.transformer]["tap_nom"], 0
|
|
615
|
+
)
|
|
616
|
+
errors += _all_between_or_at(data, ComponentType.transformer, "tap_nom", "tap_min", "tap_max", 0)
|
|
617
|
+
errors += _all_greater_than_or_equal_to_zero(data, ComponentType.transformer, "tap_size")
|
|
618
|
+
errors += _all_greater_or_equal(
|
|
619
|
+
data, ComponentType.transformer, "uk_min", "pk_min/sn", data[ComponentType.transformer]["uk"]
|
|
620
|
+
)
|
|
621
|
+
errors += _all_between(data, ComponentType.transformer, "uk_min", 0, 1, data[ComponentType.transformer]["uk"])
|
|
622
|
+
errors += _all_greater_or_equal(
|
|
623
|
+
data, ComponentType.transformer, "uk_max", "pk_max/sn", data[ComponentType.transformer]["uk"]
|
|
624
|
+
)
|
|
625
|
+
errors += _all_between(data, ComponentType.transformer, "uk_max", 0, 1, data[ComponentType.transformer]["uk"])
|
|
626
|
+
errors += _all_greater_than_or_equal_to_zero(
|
|
627
|
+
data, ComponentType.transformer, "pk_min", data[ComponentType.transformer]["pk"]
|
|
628
|
+
)
|
|
629
|
+
errors += _all_greater_than_or_equal_to_zero(
|
|
630
|
+
data, ComponentType.transformer, "pk_max", data[ComponentType.transformer]["pk"]
|
|
631
|
+
)
|
|
632
|
+
return errors
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
def validate_branch3(data: SingleDataset, component: ComponentType) -> list[ValidationError]:
|
|
636
|
+
errors = validate_base(data, component)
|
|
637
|
+
errors += _all_valid_ids(data, component, "node_1", ComponentType.node)
|
|
638
|
+
errors += _all_valid_ids(data, component, "node_2", ComponentType.node)
|
|
639
|
+
errors += _all_valid_ids(data, component, "node_3", ComponentType.node)
|
|
640
|
+
errors += _all_not_two_values_equal(data, component, "node_1", "node_2")
|
|
641
|
+
errors += _all_not_two_values_equal(data, component, "node_1", "node_3")
|
|
642
|
+
errors += _all_not_two_values_equal(data, component, "node_2", "node_3")
|
|
643
|
+
errors += _all_boolean(data, component, "status_1")
|
|
644
|
+
errors += _all_boolean(data, component, "status_2")
|
|
645
|
+
errors += _all_boolean(data, component, "status_3")
|
|
646
|
+
return errors
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
def validate_three_winding_transformer(data: SingleDataset) -> list[ValidationError]: # noqa: PLR0915
|
|
650
|
+
errors = validate_branch3(data, ComponentType.three_winding_transformer)
|
|
651
|
+
errors += _all_greater_than_zero(data, ComponentType.three_winding_transformer, "u1")
|
|
652
|
+
errors += _all_greater_than_zero(data, ComponentType.three_winding_transformer, "u2")
|
|
653
|
+
errors += _all_greater_than_zero(data, ComponentType.three_winding_transformer, "u3")
|
|
654
|
+
errors += _all_greater_than_zero(data, ComponentType.three_winding_transformer, "sn_1")
|
|
655
|
+
errors += _all_greater_than_zero(data, ComponentType.three_winding_transformer, "sn_2")
|
|
656
|
+
errors += _all_greater_than_zero(data, ComponentType.three_winding_transformer, "sn_3")
|
|
657
|
+
errors += _all_greater_or_equal(data, ComponentType.three_winding_transformer, "uk_12", "pk_12/sn_1")
|
|
658
|
+
errors += _all_greater_or_equal(data, ComponentType.three_winding_transformer, "uk_12", "pk_12/sn_2")
|
|
659
|
+
errors += _all_greater_or_equal(data, ComponentType.three_winding_transformer, "uk_13", "pk_13/sn_1")
|
|
660
|
+
errors += _all_greater_or_equal(data, ComponentType.three_winding_transformer, "uk_13", "pk_13/sn_3")
|
|
661
|
+
errors += _all_greater_or_equal(data, ComponentType.three_winding_transformer, "uk_23", "pk_23/sn_2")
|
|
662
|
+
errors += _all_greater_or_equal(data, ComponentType.three_winding_transformer, "uk_23", "pk_23/sn_3")
|
|
663
|
+
errors += _all_between(data, ComponentType.three_winding_transformer, "uk_12", 0, 1)
|
|
664
|
+
errors += _all_between(data, ComponentType.three_winding_transformer, "uk_13", 0, 1)
|
|
665
|
+
errors += _all_between(data, ComponentType.three_winding_transformer, "uk_23", 0, 1)
|
|
666
|
+
errors += _all_greater_than_or_equal_to_zero(data, ComponentType.three_winding_transformer, "pk_12")
|
|
667
|
+
errors += _all_greater_than_or_equal_to_zero(data, ComponentType.three_winding_transformer, "pk_13")
|
|
668
|
+
errors += _all_greater_than_or_equal_to_zero(data, ComponentType.three_winding_transformer, "pk_23")
|
|
669
|
+
errors += _all_greater_or_equal(data, ComponentType.three_winding_transformer, "i0", "p0/sn_1")
|
|
670
|
+
errors += _all_less_than(data, ComponentType.three_winding_transformer, "i0", 1)
|
|
671
|
+
errors += _all_greater_than_or_equal_to_zero(data, ComponentType.three_winding_transformer, "p0")
|
|
672
|
+
errors += _all_valid_enum_values(data, ComponentType.three_winding_transformer, "winding_1", WindingType)
|
|
673
|
+
errors += _all_valid_enum_values(data, ComponentType.three_winding_transformer, "winding_2", WindingType)
|
|
674
|
+
errors += _all_valid_enum_values(data, ComponentType.three_winding_transformer, "winding_3", WindingType)
|
|
675
|
+
errors += _all_between_or_at(data, ComponentType.three_winding_transformer, "clock_12", -12, 12)
|
|
676
|
+
errors += _all_between_or_at(data, ComponentType.three_winding_transformer, "clock_13", -12, 12)
|
|
677
|
+
errors += _all_valid_clocks(data, ComponentType.three_winding_transformer, "clock_12", "winding_1", "winding_2")
|
|
678
|
+
errors += _all_valid_clocks(data, ComponentType.three_winding_transformer, "clock_13", "winding_1", "winding_3")
|
|
679
|
+
errors += _all_valid_enum_values(data, ComponentType.three_winding_transformer, "tap_side", Branch3Side)
|
|
680
|
+
errors += _all_between_or_at(
|
|
681
|
+
data,
|
|
682
|
+
ComponentType.three_winding_transformer,
|
|
683
|
+
"tap_pos",
|
|
684
|
+
"tap_min",
|
|
685
|
+
"tap_max",
|
|
686
|
+
data[ComponentType.three_winding_transformer]["tap_nom"],
|
|
687
|
+
0,
|
|
688
|
+
)
|
|
689
|
+
errors += _all_between_or_at(data, ComponentType.three_winding_transformer, "tap_nom", "tap_min", "tap_max", 0)
|
|
690
|
+
errors += _all_greater_than_or_equal_to_zero(data, ComponentType.three_winding_transformer, "tap_size")
|
|
691
|
+
errors += _all_greater_or_equal(
|
|
692
|
+
data,
|
|
693
|
+
ComponentType.three_winding_transformer,
|
|
694
|
+
"uk_12_min",
|
|
695
|
+
"pk_12_min/sn_1",
|
|
696
|
+
data[ComponentType.three_winding_transformer]["uk_12"],
|
|
697
|
+
)
|
|
698
|
+
errors += _all_greater_or_equal(
|
|
699
|
+
data,
|
|
700
|
+
ComponentType.three_winding_transformer,
|
|
701
|
+
"uk_12_min",
|
|
702
|
+
"pk_12_min/sn_2",
|
|
703
|
+
data[ComponentType.three_winding_transformer]["uk_12"],
|
|
704
|
+
)
|
|
705
|
+
errors += _all_greater_or_equal(
|
|
706
|
+
data,
|
|
707
|
+
ComponentType.three_winding_transformer,
|
|
708
|
+
"uk_13_min",
|
|
709
|
+
"pk_13_min/sn_1",
|
|
710
|
+
data[ComponentType.three_winding_transformer]["uk_13"],
|
|
711
|
+
)
|
|
712
|
+
errors += _all_greater_or_equal(
|
|
713
|
+
data,
|
|
714
|
+
ComponentType.three_winding_transformer,
|
|
715
|
+
"uk_13_min",
|
|
716
|
+
"pk_13_min/sn_3",
|
|
717
|
+
data[ComponentType.three_winding_transformer]["uk_13"],
|
|
718
|
+
)
|
|
719
|
+
errors += _all_greater_or_equal(
|
|
720
|
+
data,
|
|
721
|
+
ComponentType.three_winding_transformer,
|
|
722
|
+
"uk_23_min",
|
|
723
|
+
"pk_23_min/sn_2",
|
|
724
|
+
data[ComponentType.three_winding_transformer]["uk_23"],
|
|
725
|
+
)
|
|
726
|
+
errors += _all_greater_or_equal(
|
|
727
|
+
data,
|
|
728
|
+
ComponentType.three_winding_transformer,
|
|
729
|
+
"uk_23_min",
|
|
730
|
+
"pk_23_min/sn_3",
|
|
731
|
+
data[ComponentType.three_winding_transformer]["uk_23"],
|
|
732
|
+
)
|
|
733
|
+
errors += _all_between(
|
|
734
|
+
data,
|
|
735
|
+
ComponentType.three_winding_transformer,
|
|
736
|
+
"uk_12_min",
|
|
737
|
+
0,
|
|
738
|
+
1,
|
|
739
|
+
data[ComponentType.three_winding_transformer]["uk_12"],
|
|
740
|
+
)
|
|
741
|
+
errors += _all_between(
|
|
742
|
+
data,
|
|
743
|
+
ComponentType.three_winding_transformer,
|
|
744
|
+
"uk_13_min",
|
|
745
|
+
0,
|
|
746
|
+
1,
|
|
747
|
+
data[ComponentType.three_winding_transformer]["uk_13"],
|
|
748
|
+
)
|
|
749
|
+
errors += _all_between(
|
|
750
|
+
data,
|
|
751
|
+
ComponentType.three_winding_transformer,
|
|
752
|
+
"uk_23_min",
|
|
753
|
+
0,
|
|
754
|
+
1,
|
|
755
|
+
data[ComponentType.three_winding_transformer]["uk_23"],
|
|
756
|
+
)
|
|
757
|
+
errors += _all_greater_or_equal(
|
|
758
|
+
data,
|
|
759
|
+
ComponentType.three_winding_transformer,
|
|
760
|
+
"uk_12_max",
|
|
761
|
+
"pk_12_max/sn_1",
|
|
762
|
+
data[ComponentType.three_winding_transformer]["uk_12"],
|
|
763
|
+
)
|
|
764
|
+
errors += _all_greater_or_equal(
|
|
765
|
+
data,
|
|
766
|
+
ComponentType.three_winding_transformer,
|
|
767
|
+
"uk_12_max",
|
|
768
|
+
"pk_12_max/sn_2",
|
|
769
|
+
data[ComponentType.three_winding_transformer]["uk_12"],
|
|
770
|
+
)
|
|
771
|
+
errors += _all_greater_or_equal(
|
|
772
|
+
data,
|
|
773
|
+
ComponentType.three_winding_transformer,
|
|
774
|
+
"uk_13_max",
|
|
775
|
+
"pk_13_max/sn_1",
|
|
776
|
+
data[ComponentType.three_winding_transformer]["uk_13"],
|
|
777
|
+
)
|
|
778
|
+
errors += _all_greater_or_equal(
|
|
779
|
+
data,
|
|
780
|
+
ComponentType.three_winding_transformer,
|
|
781
|
+
"uk_13_max",
|
|
782
|
+
"pk_13_max/sn_3",
|
|
783
|
+
data[ComponentType.three_winding_transformer]["uk_13"],
|
|
784
|
+
)
|
|
785
|
+
errors += _all_greater_or_equal(
|
|
786
|
+
data,
|
|
787
|
+
ComponentType.three_winding_transformer,
|
|
788
|
+
"uk_23_max",
|
|
789
|
+
"pk_23_max/sn_2",
|
|
790
|
+
data[ComponentType.three_winding_transformer]["uk_23"],
|
|
791
|
+
)
|
|
792
|
+
errors += _all_greater_or_equal(
|
|
793
|
+
data,
|
|
794
|
+
ComponentType.three_winding_transformer,
|
|
795
|
+
"uk_23_max",
|
|
796
|
+
"pk_23_max/sn_3",
|
|
797
|
+
data[ComponentType.three_winding_transformer]["uk_23"],
|
|
798
|
+
)
|
|
799
|
+
errors += _all_between(
|
|
800
|
+
data,
|
|
801
|
+
ComponentType.three_winding_transformer,
|
|
802
|
+
"uk_12_max",
|
|
803
|
+
0,
|
|
804
|
+
1,
|
|
805
|
+
data[ComponentType.three_winding_transformer]["uk_12"],
|
|
806
|
+
)
|
|
807
|
+
errors += _all_between(
|
|
808
|
+
data,
|
|
809
|
+
ComponentType.three_winding_transformer,
|
|
810
|
+
"uk_13_max",
|
|
811
|
+
0,
|
|
812
|
+
1,
|
|
813
|
+
data[ComponentType.three_winding_transformer]["uk_13"],
|
|
814
|
+
)
|
|
815
|
+
errors += _all_between(
|
|
816
|
+
data,
|
|
817
|
+
ComponentType.three_winding_transformer,
|
|
818
|
+
"uk_23_max",
|
|
819
|
+
0,
|
|
820
|
+
1,
|
|
821
|
+
data[ComponentType.three_winding_transformer]["uk_23"],
|
|
822
|
+
)
|
|
823
|
+
errors += _all_greater_than_or_equal_to_zero(
|
|
824
|
+
data,
|
|
825
|
+
ComponentType.three_winding_transformer,
|
|
826
|
+
"pk_12_min",
|
|
827
|
+
data[ComponentType.three_winding_transformer]["pk_12"],
|
|
828
|
+
)
|
|
829
|
+
errors += _all_greater_than_or_equal_to_zero(
|
|
830
|
+
data,
|
|
831
|
+
ComponentType.three_winding_transformer,
|
|
832
|
+
"pk_13_min",
|
|
833
|
+
data[ComponentType.three_winding_transformer]["pk_13"],
|
|
834
|
+
)
|
|
835
|
+
errors += _all_greater_than_or_equal_to_zero(
|
|
836
|
+
data,
|
|
837
|
+
ComponentType.three_winding_transformer,
|
|
838
|
+
"pk_23_min",
|
|
839
|
+
data[ComponentType.three_winding_transformer]["pk_23"],
|
|
840
|
+
)
|
|
841
|
+
errors += _all_greater_than_or_equal_to_zero(
|
|
842
|
+
data,
|
|
843
|
+
ComponentType.three_winding_transformer,
|
|
844
|
+
"pk_12_max",
|
|
845
|
+
data[ComponentType.three_winding_transformer]["pk_12"],
|
|
846
|
+
)
|
|
847
|
+
errors += _all_greater_than_or_equal_to_zero(
|
|
848
|
+
data,
|
|
849
|
+
ComponentType.three_winding_transformer,
|
|
850
|
+
"pk_13_max",
|
|
851
|
+
data[ComponentType.three_winding_transformer]["pk_13"],
|
|
852
|
+
)
|
|
853
|
+
errors += _all_greater_than_or_equal_to_zero(
|
|
854
|
+
data,
|
|
855
|
+
ComponentType.three_winding_transformer,
|
|
856
|
+
"pk_23_max",
|
|
857
|
+
data[ComponentType.three_winding_transformer]["pk_23"],
|
|
858
|
+
)
|
|
859
|
+
return errors
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
def validate_appliance(data: SingleDataset, component: ComponentType) -> list[ValidationError]:
|
|
863
|
+
errors = validate_base(data, component)
|
|
864
|
+
errors += _all_boolean(data, component, "status")
|
|
865
|
+
errors += _all_valid_ids(data, component, "node", ComponentType.node)
|
|
866
|
+
return errors
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
def validate_source(data: SingleDataset) -> list[ValidationError]:
|
|
870
|
+
errors = validate_appliance(data, ComponentType.source)
|
|
871
|
+
errors += _all_greater_than_zero(data, ComponentType.source, "u_ref")
|
|
872
|
+
errors += _all_greater_than_zero(data, ComponentType.source, "sk")
|
|
873
|
+
errors += _all_greater_than_or_equal_to_zero(data, ComponentType.source, "rx_ratio")
|
|
874
|
+
errors += _all_greater_than_zero(data, ComponentType.source, "z01_ratio")
|
|
875
|
+
return errors
|
|
876
|
+
|
|
877
|
+
|
|
878
|
+
def validate_generic_load_gen(data: SingleDataset, component: ComponentType) -> list[ValidationError]:
|
|
879
|
+
errors = validate_appliance(data, component)
|
|
880
|
+
errors += _all_valid_enum_values(data, component, "type", LoadGenType)
|
|
881
|
+
return errors
|
|
882
|
+
|
|
883
|
+
|
|
884
|
+
def validate_shunt(data: SingleDataset) -> list[ValidationError]:
|
|
885
|
+
return validate_appliance(data, ComponentType.shunt)
|
|
886
|
+
|
|
887
|
+
|
|
888
|
+
def validate_generic_voltage_sensor(data: SingleDataset, component: ComponentType) -> list[ValidationError]:
|
|
889
|
+
errors = validate_base(data, component)
|
|
890
|
+
errors += _all_greater_than_zero(data, component, "u_sigma")
|
|
891
|
+
errors += _all_greater_than_zero(data, component, "u_measured")
|
|
892
|
+
errors += _all_valid_ids(data, component, "measured_object", ComponentType.node)
|
|
893
|
+
return errors
|
|
894
|
+
|
|
895
|
+
|
|
896
|
+
def validate_generic_power_sensor(data: SingleDataset, component: ComponentType) -> list[ValidationError]:
|
|
897
|
+
errors = validate_base(data, component)
|
|
898
|
+
errors += _all_greater_than_zero(data, component, "power_sigma")
|
|
899
|
+
errors += _all_valid_enum_values(data, component, "measured_terminal_type", MeasuredTerminalType)
|
|
900
|
+
errors += _all_valid_ids(
|
|
901
|
+
data,
|
|
902
|
+
component,
|
|
903
|
+
field="measured_object",
|
|
904
|
+
ref_components=[
|
|
905
|
+
ComponentType.node,
|
|
906
|
+
ComponentType.line,
|
|
907
|
+
ComponentType.asym_line,
|
|
908
|
+
ComponentType.generic_branch,
|
|
909
|
+
ComponentType.transformer,
|
|
910
|
+
ComponentType.three_winding_transformer,
|
|
911
|
+
ComponentType.source,
|
|
912
|
+
ComponentType.shunt,
|
|
913
|
+
ComponentType.sym_load,
|
|
914
|
+
ComponentType.asym_load,
|
|
915
|
+
ComponentType.sym_gen,
|
|
916
|
+
ComponentType.asym_gen,
|
|
917
|
+
],
|
|
918
|
+
)
|
|
919
|
+
errors += _all_valid_ids(
|
|
920
|
+
data,
|
|
921
|
+
component,
|
|
922
|
+
field="measured_object",
|
|
923
|
+
ref_components=[
|
|
924
|
+
ComponentType.line,
|
|
925
|
+
ComponentType.asym_line,
|
|
926
|
+
ComponentType.generic_branch,
|
|
927
|
+
ComponentType.transformer,
|
|
928
|
+
],
|
|
929
|
+
measured_terminal_type=MeasuredTerminalType.branch_from,
|
|
930
|
+
)
|
|
931
|
+
errors += _all_valid_ids(
|
|
932
|
+
data,
|
|
933
|
+
component,
|
|
934
|
+
field="measured_object",
|
|
935
|
+
ref_components=[
|
|
936
|
+
ComponentType.line,
|
|
937
|
+
ComponentType.asym_line,
|
|
938
|
+
ComponentType.generic_branch,
|
|
939
|
+
ComponentType.transformer,
|
|
940
|
+
],
|
|
941
|
+
measured_terminal_type=MeasuredTerminalType.branch_to,
|
|
942
|
+
)
|
|
943
|
+
errors += _all_valid_ids(
|
|
944
|
+
data,
|
|
945
|
+
component,
|
|
946
|
+
field="measured_object",
|
|
947
|
+
ref_components=ComponentType.source,
|
|
948
|
+
measured_terminal_type=MeasuredTerminalType.source,
|
|
949
|
+
)
|
|
950
|
+
errors += _all_valid_ids(
|
|
951
|
+
data,
|
|
952
|
+
component,
|
|
953
|
+
field="measured_object",
|
|
954
|
+
ref_components=ComponentType.shunt,
|
|
955
|
+
measured_terminal_type=MeasuredTerminalType.shunt,
|
|
956
|
+
)
|
|
957
|
+
errors += _all_valid_ids(
|
|
958
|
+
data,
|
|
959
|
+
component,
|
|
960
|
+
field="measured_object",
|
|
961
|
+
ref_components=[ComponentType.sym_load, ComponentType.asym_load],
|
|
962
|
+
measured_terminal_type=MeasuredTerminalType.load,
|
|
963
|
+
)
|
|
964
|
+
errors += _all_valid_ids(
|
|
965
|
+
data,
|
|
966
|
+
component,
|
|
967
|
+
field="measured_object",
|
|
968
|
+
ref_components=[ComponentType.sym_gen, ComponentType.asym_gen],
|
|
969
|
+
measured_terminal_type=MeasuredTerminalType.generator,
|
|
970
|
+
)
|
|
971
|
+
errors += _all_valid_ids(
|
|
972
|
+
data,
|
|
973
|
+
component,
|
|
974
|
+
field="measured_object",
|
|
975
|
+
ref_components=ComponentType.three_winding_transformer,
|
|
976
|
+
measured_terminal_type=MeasuredTerminalType.branch3_1,
|
|
977
|
+
)
|
|
978
|
+
errors += _all_valid_ids(
|
|
979
|
+
data,
|
|
980
|
+
component,
|
|
981
|
+
field="measured_object",
|
|
982
|
+
ref_components=ComponentType.three_winding_transformer,
|
|
983
|
+
measured_terminal_type=MeasuredTerminalType.branch3_2,
|
|
984
|
+
)
|
|
985
|
+
errors += _all_valid_ids(
|
|
986
|
+
data,
|
|
987
|
+
component,
|
|
988
|
+
field="measured_object",
|
|
989
|
+
ref_components=ComponentType.three_winding_transformer,
|
|
990
|
+
measured_terminal_type=MeasuredTerminalType.branch3_3,
|
|
991
|
+
)
|
|
992
|
+
errors += _all_valid_ids(
|
|
993
|
+
data,
|
|
994
|
+
component,
|
|
995
|
+
field="measured_object",
|
|
996
|
+
ref_components=ComponentType.node,
|
|
997
|
+
measured_terminal_type=MeasuredTerminalType.node,
|
|
998
|
+
)
|
|
999
|
+
if component in (ComponentType.sym_power_sensor, ComponentType.asym_power_sensor):
|
|
1000
|
+
errors += _valid_p_q_sigma(data, component)
|
|
1001
|
+
|
|
1002
|
+
return errors
|
|
1003
|
+
|
|
1004
|
+
|
|
1005
|
+
def validate_generic_current_sensor(data: SingleDataset, component: ComponentType) -> list[ValidationError]:
|
|
1006
|
+
errors = validate_base(data, component)
|
|
1007
|
+
errors += _all_greater_than_zero(data, component, "i_sigma")
|
|
1008
|
+
errors += _all_greater_than_zero(data, component, "i_angle_sigma")
|
|
1009
|
+
errors += _all_valid_enum_values(data, component, "measured_terminal_type", MeasuredTerminalType)
|
|
1010
|
+
errors += _all_valid_enum_values(data, component, "angle_measurement_type", AngleMeasurementType)
|
|
1011
|
+
errors += _all_in_valid_values(
|
|
1012
|
+
data,
|
|
1013
|
+
component,
|
|
1014
|
+
"measured_terminal_type",
|
|
1015
|
+
[
|
|
1016
|
+
MeasuredTerminalType.branch_from,
|
|
1017
|
+
MeasuredTerminalType.branch_to,
|
|
1018
|
+
MeasuredTerminalType.branch3_1,
|
|
1019
|
+
MeasuredTerminalType.branch3_2,
|
|
1020
|
+
MeasuredTerminalType.branch3_3,
|
|
1021
|
+
],
|
|
1022
|
+
)
|
|
1023
|
+
errors += _all_valid_ids(
|
|
1024
|
+
data,
|
|
1025
|
+
component,
|
|
1026
|
+
field="measured_object",
|
|
1027
|
+
ref_components=[
|
|
1028
|
+
ComponentType.line,
|
|
1029
|
+
ComponentType.asym_line,
|
|
1030
|
+
ComponentType.generic_branch,
|
|
1031
|
+
ComponentType.transformer,
|
|
1032
|
+
ComponentType.three_winding_transformer,
|
|
1033
|
+
],
|
|
1034
|
+
)
|
|
1035
|
+
errors += _all_valid_ids(
|
|
1036
|
+
data,
|
|
1037
|
+
component,
|
|
1038
|
+
field="measured_object",
|
|
1039
|
+
ref_components=[
|
|
1040
|
+
ComponentType.line,
|
|
1041
|
+
ComponentType.asym_line,
|
|
1042
|
+
ComponentType.generic_branch,
|
|
1043
|
+
ComponentType.transformer,
|
|
1044
|
+
],
|
|
1045
|
+
measured_terminal_type=MeasuredTerminalType.branch_from,
|
|
1046
|
+
)
|
|
1047
|
+
errors += _all_valid_ids(
|
|
1048
|
+
data,
|
|
1049
|
+
component,
|
|
1050
|
+
field="measured_object",
|
|
1051
|
+
ref_components=[
|
|
1052
|
+
ComponentType.line,
|
|
1053
|
+
ComponentType.asym_line,
|
|
1054
|
+
ComponentType.generic_branch,
|
|
1055
|
+
ComponentType.transformer,
|
|
1056
|
+
],
|
|
1057
|
+
measured_terminal_type=MeasuredTerminalType.branch_to,
|
|
1058
|
+
)
|
|
1059
|
+
errors += _all_valid_ids(
|
|
1060
|
+
data,
|
|
1061
|
+
component,
|
|
1062
|
+
field="measured_object",
|
|
1063
|
+
ref_components=ComponentType.three_winding_transformer,
|
|
1064
|
+
measured_terminal_type=MeasuredTerminalType.branch3_1,
|
|
1065
|
+
)
|
|
1066
|
+
errors += _all_valid_ids(
|
|
1067
|
+
data,
|
|
1068
|
+
component,
|
|
1069
|
+
field="measured_object",
|
|
1070
|
+
ref_components=ComponentType.three_winding_transformer,
|
|
1071
|
+
measured_terminal_type=MeasuredTerminalType.branch3_2,
|
|
1072
|
+
)
|
|
1073
|
+
errors += _all_valid_ids(
|
|
1074
|
+
data,
|
|
1075
|
+
component,
|
|
1076
|
+
field="measured_object",
|
|
1077
|
+
ref_components=ComponentType.three_winding_transformer,
|
|
1078
|
+
measured_terminal_type=MeasuredTerminalType.branch3_3,
|
|
1079
|
+
)
|
|
1080
|
+
errors += _all_same_current_angle_measurement_type_on_terminal(
|
|
1081
|
+
data,
|
|
1082
|
+
component,
|
|
1083
|
+
measured_object_field="measured_object",
|
|
1084
|
+
measured_terminal_type_field="measured_terminal_type",
|
|
1085
|
+
angle_measurement_type_field="angle_measurement_type",
|
|
1086
|
+
)
|
|
1087
|
+
errors += _any_voltage_angle_measurement_if_global_current_measurement(
|
|
1088
|
+
data,
|
|
1089
|
+
component,
|
|
1090
|
+
angle_measurement_type_filter=("angle_measurement_type", AngleMeasurementType.global_angle),
|
|
1091
|
+
voltage_sensor_u_angle_measured={
|
|
1092
|
+
ComponentType.sym_voltage_sensor: "u_angle_measured",
|
|
1093
|
+
ComponentType.asym_voltage_sensor: "u_angle_measured",
|
|
1094
|
+
},
|
|
1095
|
+
)
|
|
1096
|
+
|
|
1097
|
+
return errors
|
|
1098
|
+
|
|
1099
|
+
|
|
1100
|
+
def validate_fault(data: SingleDataset) -> list[ValidationError]:
|
|
1101
|
+
errors = validate_base(data, ComponentType.fault)
|
|
1102
|
+
errors += _all_boolean(data, ComponentType.fault, "status")
|
|
1103
|
+
errors += _all_valid_enum_values(data, ComponentType.fault, "fault_type", FaultType)
|
|
1104
|
+
errors += _all_valid_enum_values(data, ComponentType.fault, "fault_phase", FaultPhase)
|
|
1105
|
+
errors += _all_valid_fault_phases(data, ComponentType.fault, "fault_type", "fault_phase")
|
|
1106
|
+
errors += _all_valid_ids(data, ComponentType.fault, field="fault_object", ref_components=ComponentType.node)
|
|
1107
|
+
errors += _all_greater_than_or_equal_to_zero(data, ComponentType.fault, "r_f")
|
|
1108
|
+
errors += _all_enabled_identical(data, ComponentType.fault, "fault_type", "status")
|
|
1109
|
+
errors += _all_enabled_identical(data, ComponentType.fault, "fault_phase", "status")
|
|
1110
|
+
return errors
|
|
1111
|
+
|
|
1112
|
+
|
|
1113
|
+
def validate_regulator(data: SingleDataset, component: ComponentType) -> list[ValidationError]:
|
|
1114
|
+
errors = validate_base(data, component)
|
|
1115
|
+
errors += _all_valid_ids(
|
|
1116
|
+
data,
|
|
1117
|
+
component,
|
|
1118
|
+
field="regulated_object",
|
|
1119
|
+
ref_components=[ComponentType.transformer, ComponentType.three_winding_transformer],
|
|
1120
|
+
)
|
|
1121
|
+
return errors
|
|
1122
|
+
|
|
1123
|
+
|
|
1124
|
+
def validate_transformer_tap_regulator(data: SingleDataset) -> list[ValidationError]:
|
|
1125
|
+
errors = validate_regulator(data, ComponentType.transformer_tap_regulator)
|
|
1126
|
+
errors += _all_boolean(data, ComponentType.transformer_tap_regulator, "status")
|
|
1127
|
+
errors += _all_unique(data, ComponentType.transformer_tap_regulator, "regulated_object")
|
|
1128
|
+
errors += _all_valid_enum_values(
|
|
1129
|
+
data, ComponentType.transformer_tap_regulator, "control_side", [BranchSide, Branch3Side]
|
|
1130
|
+
)
|
|
1131
|
+
errors += _all_valid_associated_enum_values(
|
|
1132
|
+
data,
|
|
1133
|
+
ComponentType.transformer_tap_regulator,
|
|
1134
|
+
"control_side",
|
|
1135
|
+
"regulated_object",
|
|
1136
|
+
[ComponentType.transformer],
|
|
1137
|
+
[BranchSide],
|
|
1138
|
+
)
|
|
1139
|
+
errors += _all_valid_associated_enum_values(
|
|
1140
|
+
data,
|
|
1141
|
+
ComponentType.transformer_tap_regulator,
|
|
1142
|
+
"control_side",
|
|
1143
|
+
"regulated_object",
|
|
1144
|
+
[ComponentType.three_winding_transformer],
|
|
1145
|
+
[Branch3Side],
|
|
1146
|
+
)
|
|
1147
|
+
errors += _all_greater_than_or_equal_to_zero(data, ComponentType.transformer_tap_regulator, "u_set")
|
|
1148
|
+
errors += _all_greater_than_zero(data, ComponentType.transformer_tap_regulator, "u_band")
|
|
1149
|
+
errors += _all_greater_than_or_equal_to_zero(
|
|
1150
|
+
data, ComponentType.transformer_tap_regulator, "line_drop_compensation_r", 0.0
|
|
1151
|
+
)
|
|
1152
|
+
errors += _all_greater_than_or_equal_to_zero(
|
|
1153
|
+
data, ComponentType.transformer_tap_regulator, "line_drop_compensation_x", 0.0
|
|
1154
|
+
)
|
|
1155
|
+
return errors
|
|
1156
|
+
|
|
1157
|
+
|
|
1158
|
+
def validate_no_mixed_sensors_on_same_terminal(data: SingleDataset) -> list[ValidationError]:
|
|
1159
|
+
errors: list[ValidationError] = []
|
|
1160
|
+
|
|
1161
|
+
for power_sensor in [ComponentType.sym_power_sensor, ComponentType.asym_power_sensor]:
|
|
1162
|
+
for current_sensor in [ComponentType.sym_current_sensor, ComponentType.asym_current_sensor]:
|
|
1163
|
+
if power_sensor in data and current_sensor in data:
|
|
1164
|
+
errors += _all_same_sensor_type_on_same_terminal(
|
|
1165
|
+
data,
|
|
1166
|
+
power_sensor_type=power_sensor,
|
|
1167
|
+
current_sensor_type=current_sensor,
|
|
1168
|
+
measured_object_field="measured_object",
|
|
1169
|
+
measured_terminal_type_field="measured_terminal_type",
|
|
1170
|
+
)
|
|
1171
|
+
|
|
1172
|
+
return errors
|