1pub struct DssClass {
13 pub name: &'static str,
14 pub props: &'static [&'static str],
15}
16
17macro_rules! class {
18 ($ident:ident, $name:literal, [$($p:literal),* $(,)?]) => {
19 pub static $ident: DssClass = DssClass { name: $name, props: &[$($p),*] };
20 };
21}
22
23class!(
24 LINE,
25 "line",
26 [
27 "bus1",
28 "bus2",
29 "linecode",
30 "length",
31 "phases",
32 "r1",
33 "x1",
34 "r0",
35 "x0",
36 "c1",
37 "c0",
38 "rmatrix",
39 "xmatrix",
40 "cmatrix",
41 "switch",
42 "rg",
43 "xg",
44 "rho",
45 "geometry",
46 "units",
47 "spacing",
48 "wires",
49 "earthmodel",
50 "cncables",
51 "tscables",
52 "b1",
53 "b0",
54 "seasons",
55 "ratings",
56 "linetype",
57 "normamps",
59 "emergamps",
60 "faultrate",
61 "pctperm",
62 "repair",
63 "basefreq",
64 "enabled",
65 "like",
66 ]
67);
68
69class!(
70 LINECODE,
71 "linecode",
72 [
73 "nphases",
74 "r1",
75 "x1",
76 "r0",
77 "x0",
78 "c1",
79 "c0",
80 "units",
81 "rmatrix",
82 "xmatrix",
83 "cmatrix",
84 "basefreq",
85 "normamps",
86 "emergamps",
87 "faultrate",
88 "pctperm",
89 "repair",
90 "kron",
91 "rg",
92 "xg",
93 "rho",
94 "neutral",
95 "b1",
96 "b0",
97 "seasons",
98 "ratings",
99 "linetype",
100 "like",
102 ]
103);
104
105class!(
106 LOAD,
107 "load",
108 [
109 "phases",
110 "bus1",
111 "kv",
112 "kw",
113 "pf",
114 "model",
115 "yearly",
116 "daily",
117 "duty",
118 "growth",
119 "conn",
120 "kvar",
121 "rneut",
122 "xneut",
123 "status",
124 "class",
125 "vminpu",
126 "vmaxpu",
127 "vminnorm",
128 "vminemerg",
129 "xfkva",
130 "allocationfactor",
131 "kva",
132 "%mean",
133 "%stddev",
134 "cvrwatts",
135 "cvrvars",
136 "kwh",
137 "kwhdays",
138 "cfactor",
139 "cvrcurve",
140 "numcust",
141 "zipv",
142 "%seriesrl",
143 "relweight",
144 "vlowpu",
145 "puxharm",
146 "xrharm",
147 "spectrum",
149 "basefreq",
150 "enabled",
151 "like",
152 ]
153);
154
155class!(
156 TRANSFORMER,
157 "transformer",
158 [
159 "phases",
160 "windings",
161 "wdg",
162 "bus",
163 "conn",
164 "kv",
165 "kva",
166 "tap",
167 "%r",
168 "rneut",
169 "xneut",
170 "buses",
171 "conns",
172 "kvs",
173 "kvas",
174 "taps",
175 "xhl",
176 "xht",
177 "xlt",
178 "xscarray",
179 "thermal",
180 "n",
181 "m",
182 "flrise",
183 "hsrise",
184 "%loadloss",
185 "%noloadloss",
186 "normhkva",
187 "emerghkva",
188 "sub",
189 "maxtap",
190 "mintap",
191 "numtaps",
192 "subname",
193 "%imag",
194 "ppm_antifloat",
195 "%rs",
196 "bank",
197 "xfmrcode",
198 "xrconst",
199 "x12",
200 "x13",
201 "x23",
202 "leadlag",
203 "wdgcurrents",
204 "core",
205 "rdcohms",
206 "seasons",
207 "ratings",
208 "normamps",
210 "emergamps",
211 "faultrate",
212 "pctperm",
213 "repair",
214 "basefreq",
215 "enabled",
216 "like",
217 ]
218);
219
220class!(
221 VSOURCE,
222 "vsource",
223 [
224 "bus1",
225 "basekv",
226 "pu",
227 "angle",
228 "frequency",
229 "phases",
230 "mvasc3",
231 "mvasc1",
232 "x1r1",
233 "x0r0",
234 "isc3",
235 "isc1",
236 "r1",
237 "x1",
238 "r0",
239 "x0",
240 "scantype",
241 "sequence",
242 "bus2",
243 "z1",
244 "z0",
245 "z2",
246 "puz1",
247 "puz0",
248 "puz2",
249 "basemva",
250 "yearly",
251 "daily",
252 "duty",
253 "model",
254 "puzideal",
255 "spectrum",
257 "basefreq",
258 "enabled",
259 "like",
260 ]
261);
262
263class!(
264 CAPACITOR,
265 "capacitor",
266 [
267 "bus1",
268 "bus2",
269 "phases",
270 "kvar",
271 "kv",
272 "conn",
273 "cmatrix",
274 "cuf",
275 "r",
276 "xl",
277 "harm",
278 "numsteps",
279 "states",
280 "normamps",
282 "emergamps",
283 "faultrate",
284 "pctperm",
285 "repair",
286 "basefreq",
287 "enabled",
288 "like",
289 ]
290);
291
292class!(
293 REACTOR,
294 "reactor",
295 [
296 "bus1",
297 "bus2",
298 "phases",
299 "kvar",
300 "kv",
301 "conn",
302 "rmatrix",
303 "xmatrix",
304 "parallel",
305 "r",
306 "x",
307 "rp",
308 "z1",
309 "z2",
310 "z0",
311 "z",
312 "rcurve",
313 "lcurve",
314 "lmh",
315 "normamps",
317 "emergamps",
318 "faultrate",
319 "pctperm",
320 "repair",
321 "basefreq",
322 "enabled",
323 "like",
324 ]
325);
326
327class!(
328 GENERATOR,
329 "generator",
330 [
331 "phases",
332 "bus1",
333 "kv",
334 "kw",
335 "pf",
336 "kvar",
337 "model",
338 "vminpu",
339 "vmaxpu",
340 "yearly",
341 "daily",
342 "duty",
343 "dispmode",
344 "dispvalue",
345 "conn",
346 "rneut",
347 "xneut",
348 "status",
349 "class",
350 "vpu",
351 "maxkvar",
352 "minkvar",
353 "pvfactor",
354 "forceon",
355 "kva",
356 "mva",
357 "xd",
358 "xdp",
359 "xdpp",
360 "h",
361 "d",
362 "usermodel",
363 "userdata",
364 "shaftmodel",
365 "shaftdata",
366 "dutystart",
367 "debugtrace",
368 "balanced",
369 "xrdp",
370 "usefuel",
371 "fuelkwh",
372 "%fuel",
373 "%reserve",
374 "refuel",
375 "dynamiceq",
376 "dynout",
377 "spectrum",
379 "basefreq",
380 "enabled",
381 "like",
382 ]
383);
384
385class!(
386 PVSYSTEM,
387 "pvsystem",
388 [
389 "phases",
390 "bus1",
391 "kv",
392 "irradiance",
393 "pmpp",
394 "%pmpp",
395 "temperature",
396 "pf",
397 "conn",
398 "kvar",
399 "kva",
400 "%cutin",
401 "%cutout",
402 "effcurve",
403 "ptcurve",
404 "daily",
405 "yearly",
406 "duty",
407 "tdaily",
408 "tyearly",
409 "tduty",
410 "class",
411 "user_model",
412 "user_data",
413 "debugtrace",
414 "varfollowinverter",
415 "duty_start",
416 "wattpriority",
417 "pfpriority",
418 "pctpmpp",
419 "pctcutin",
420 "pctcutout",
421 "kvarmax",
422 "kvarmaxabs",
423 "kvarlimit",
424 "kvarlimitneg",
425 "%pminnovars",
426 "%pminkvarmax",
427 "vminpu",
428 "vmaxpu",
429 "spectrum",
431 "basefreq",
432 "enabled",
433 "like",
434 ]
435);
436
437class!(
438 XYCURVE,
439 "xycurve",
440 [
441 "npts", "points", "yarray", "xarray", "csvfile", "sngfile", "dblfile", "x", "y",
442 "like",
444 ]
445);
446
447class!(
448 INVCONTROL,
449 "invcontrol",
450 [
451 "derlist",
452 "mode",
453 "combimode",
454 "vvc_curve1",
455 "hysteresis_offset",
456 "voltage_curvex_ref",
457 "avgwindowlen",
458 "volt_watt_curve",
459 "dbvmin",
460 "dbvmax",
461 "armingtime",
462 "deltaq_factor",
463 "voltagechange_tolerance",
464 "varchange_tolerance",
465 "voltwatt_curve",
466 "voltwattyaxis",
467 "rateofchange_mode",
468 "lpftau",
469 "riseFallLimit",
470 "deltaP_factor",
471 "eventlog",
472 "refreactivepower",
473 "activepchange_tolerance",
474 "monvoltagecalc",
475 "monbus",
476 "monbusesvbase",
477 "basefreq",
479 "enabled",
480 "like",
481 ]
482);
483
484class!(
485 SWTCONTROL,
486 "swtcontrol",
487 [
488 "switchedobj",
489 "switchedterm",
490 "action",
491 "lock",
492 "delay",
493 "normal",
494 "state",
495 "reset",
496 "basefreq",
498 "enabled",
499 "like",
500 ]
501);
502
503class!(
504 REGCONTROL,
505 "regcontrol",
506 [
507 "transformer",
508 "winding",
509 "vreg",
510 "band",
511 "ptratio",
512 "ctprim",
513 "r",
514 "x",
515 "bus",
516 "delay",
517 "reversible",
518 "revvreg",
519 "revband",
520 "revr",
521 "revx",
522 "tapdelay",
523 "debugtrace",
524 "maxtapchange",
525 "inversetime",
526 "tapwinding",
527 "vlimit",
528 "ptphase",
529 "revthreshold",
530 "revdelay",
531 "revneutral",
532 "eventlog",
533 "remoteptratio",
534 "tapnum",
535 "reset",
536 "ldc_z",
537 "rev_z",
538 "cogen",
539 "basefreq",
541 "enabled",
542 "like",
543 ]
544);
545
546static CLASSES: &[&DssClass] = &[
549 &LINE,
550 &LINECODE,
551 &LOAD,
552 &TRANSFORMER,
553 &VSOURCE,
554 &CAPACITOR,
555 &REACTOR,
556 &GENERATOR,
557 &PVSYSTEM,
558 &XYCURVE,
559 &INVCONTROL,
560 &SWTCONTROL,
561 ®CONTROL,
562];
563
564pub fn class_by_name(name: &str) -> Option<&'static DssClass> {
567 CLASSES
568 .iter()
569 .find(|c| c.name.eq_ignore_ascii_case(name))
570 .copied()
571}
572
573impl DssClass {
574 pub fn prop_index(&self, query: &str) -> Option<usize> {
577 let q = query.to_ascii_lowercase();
578 self.props
579 .iter()
580 .position(|p| *p == q)
581 .or_else(|| self.props.iter().position(|p| p.starts_with(&q)))
582 }
583}
584
585#[cfg(test)]
586mod tests {
587 use super::*;
588
589 #[test]
590 fn exact_beats_prefix() {
591 assert_eq!(LINE.prop_index("r1"), Some(5));
593 assert_eq!(LINE.prop_index("R1"), Some(5));
594 }
595
596 #[test]
597 fn first_prefix_match_in_definition_order() {
598 assert_eq!(LINE.prop_index("r"), Some(5));
600 assert_eq!(LINE.prop_index("rm"), Some(11));
602 assert_eq!(LINE.prop_index("norm"), Some(30));
604 }
605
606 #[test]
607 fn percent_properties() {
608 assert_eq!(TRANSFORMER.prop_index("%R"), Some(8));
609 assert_eq!(TRANSFORMER.prop_index("%Rs"), Some(36));
610 assert_eq!(TRANSFORMER.prop_index("%loadloss"), Some(25));
611 }
612
613 #[test]
614 fn load_positions_match_the_engine() {
615 assert_eq!(LOAD.prop_index("relweight"), Some(34));
619 assert_eq!(LOAD.prop_index("vlowpu"), Some(35));
620 assert_eq!(LOAD.prop_index("puxharm"), Some(36));
621 assert_eq!(LOAD.prop_index("xrharm"), Some(37));
622 assert_eq!(LOAD.props.len(), 38 + 4); }
624
625 #[test]
626 fn class_lookup() {
627 assert!(class_by_name("Line").is_some());
628 assert!(class_by_name("LINECODE").is_some());
629 assert!(class_by_name("reactor").is_some());
630 assert!(class_by_name("xfmrcode").is_none());
631 }
632
633 #[test]
634 fn reactor_positions_match_the_engine() {
635 assert_eq!(REACTOR.prop_index("bus1"), Some(0));
639 assert_eq!(REACTOR.prop_index("kvar"), Some(3));
640 assert_eq!(REACTOR.prop_index("lmh"), Some(18));
641 assert_eq!(REACTOR.prop_index("normamps"), Some(19));
643 assert_eq!(REACTOR.props.len(), 19 + 8);
644 }
645
646 #[test]
647 fn unknown_property() {
648 assert_eq!(LINE.prop_index("zzz"), None);
649 }
650}