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 SWTCONTROL,
387 "swtcontrol",
388 [
389 "switchedobj",
390 "switchedterm",
391 "action",
392 "lock",
393 "delay",
394 "normal",
395 "state",
396 "reset",
397 "basefreq",
399 "enabled",
400 "like",
401 ]
402);
403
404class!(
405 REGCONTROL,
406 "regcontrol",
407 [
408 "transformer",
409 "winding",
410 "vreg",
411 "band",
412 "ptratio",
413 "ctprim",
414 "r",
415 "x",
416 "bus",
417 "delay",
418 "reversible",
419 "revvreg",
420 "revband",
421 "revr",
422 "revx",
423 "tapdelay",
424 "debugtrace",
425 "maxtapchange",
426 "inversetime",
427 "tapwinding",
428 "vlimit",
429 "ptphase",
430 "revthreshold",
431 "revdelay",
432 "revneutral",
433 "eventlog",
434 "remoteptratio",
435 "tapnum",
436 "reset",
437 "ldc_z",
438 "rev_z",
439 "cogen",
440 "basefreq",
442 "enabled",
443 "like",
444 ]
445);
446
447static CLASSES: &[&DssClass] = &[
450 &LINE,
451 &LINECODE,
452 &LOAD,
453 &TRANSFORMER,
454 &VSOURCE,
455 &CAPACITOR,
456 &REACTOR,
457 &GENERATOR,
458 &SWTCONTROL,
459 ®CONTROL,
460];
461
462pub fn class_by_name(name: &str) -> Option<&'static DssClass> {
465 CLASSES
466 .iter()
467 .find(|c| c.name.eq_ignore_ascii_case(name))
468 .copied()
469}
470
471impl DssClass {
472 pub fn prop_index(&self, query: &str) -> Option<usize> {
475 let q = query.to_ascii_lowercase();
476 self.props
477 .iter()
478 .position(|p| *p == q)
479 .or_else(|| self.props.iter().position(|p| p.starts_with(&q)))
480 }
481}
482
483#[cfg(test)]
484mod tests {
485 use super::*;
486
487 #[test]
488 fn exact_beats_prefix() {
489 assert_eq!(LINE.prop_index("r1"), Some(5));
491 assert_eq!(LINE.prop_index("R1"), Some(5));
492 }
493
494 #[test]
495 fn first_prefix_match_in_definition_order() {
496 assert_eq!(LINE.prop_index("r"), Some(5));
498 assert_eq!(LINE.prop_index("rm"), Some(11));
500 assert_eq!(LINE.prop_index("norm"), Some(30));
502 }
503
504 #[test]
505 fn percent_properties() {
506 assert_eq!(TRANSFORMER.prop_index("%R"), Some(8));
507 assert_eq!(TRANSFORMER.prop_index("%Rs"), Some(36));
508 assert_eq!(TRANSFORMER.prop_index("%loadloss"), Some(25));
509 }
510
511 #[test]
512 fn load_positions_match_the_engine() {
513 assert_eq!(LOAD.prop_index("relweight"), Some(34));
517 assert_eq!(LOAD.prop_index("vlowpu"), Some(35));
518 assert_eq!(LOAD.prop_index("puxharm"), Some(36));
519 assert_eq!(LOAD.prop_index("xrharm"), Some(37));
520 assert_eq!(LOAD.props.len(), 38 + 4); }
522
523 #[test]
524 fn class_lookup() {
525 assert!(class_by_name("Line").is_some());
526 assert!(class_by_name("LINECODE").is_some());
527 assert!(class_by_name("reactor").is_some());
528 assert!(class_by_name("xfmrcode").is_none());
529 }
530
531 #[test]
532 fn reactor_positions_match_the_engine() {
533 assert_eq!(REACTOR.prop_index("bus1"), Some(0));
537 assert_eq!(REACTOR.prop_index("kvar"), Some(3));
538 assert_eq!(REACTOR.prop_index("lmh"), Some(18));
539 assert_eq!(REACTOR.prop_index("normamps"), Some(19));
541 assert_eq!(REACTOR.props.len(), 19 + 8);
542 }
543
544 #[test]
545 fn unknown_property() {
546 assert_eq!(LINE.prop_index("zzz"), None);
547 }
548}