1use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(rename_all = "snake_case")]
10pub enum SupportLevel {
11 Unsupported,
12 Experimental,
13 Supported,
14}
15
16#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
18pub struct EhtSupport {
19 pub level: SupportLevel,
21 pub has_transition_metals: bool,
23 pub supported_elements: Vec<u8>,
25 pub provisional_elements: Vec<u8>,
27 pub unsupported_elements: Vec<u8>,
29 pub warnings: Vec<String>,
31}
32
33#[derive(Debug, Clone, Serialize)]
35pub struct OrbitalDef {
36 pub n: u8,
38 pub l: u8,
40 pub label: &'static str,
42 pub vsip: f64,
44 pub zeta: f64,
46}
47
48#[derive(Debug, Clone, Serialize)]
50pub struct EhtParams {
51 pub z: u8,
53 pub symbol: &'static str,
55 pub orbitals: &'static [OrbitalDef],
57}
58
59pub const DEFAULT_K: f64 = 1.75;
61
62pub fn is_transition_metal(z: u8) -> bool {
64 matches!(z, 21..=30 | 39..=48 | 72..=80)
65}
66
67pub fn support_level_for_element(z: u8) -> SupportLevel {
69 if get_params(z).is_none() {
70 SupportLevel::Unsupported
71 } else if is_transition_metal(z) {
72 SupportLevel::Experimental
74 } else {
75 SupportLevel::Supported
76 }
77}
78
79pub fn analyze_eht_support(elements: &[u8]) -> EhtSupport {
81 let mut supported_elements = Vec::new();
82 let mut provisional_elements = Vec::new();
83 let mut unsupported_elements = Vec::new();
84
85 for &z in elements {
86 match support_level_for_element(z) {
87 SupportLevel::Supported => {
88 if !supported_elements.contains(&z) {
89 supported_elements.push(z);
90 }
91 }
92 SupportLevel::Experimental => {
93 if !provisional_elements.contains(&z) {
94 provisional_elements.push(z);
95 }
96 }
97 SupportLevel::Unsupported => {
98 if !unsupported_elements.contains(&z) {
99 unsupported_elements.push(z);
100 }
101 }
102 }
103 }
104
105 supported_elements.sort_unstable();
106 provisional_elements.sort_unstable();
107 unsupported_elements.sort_unstable();
108
109 let mut warnings = Vec::new();
110 if !provisional_elements.is_empty() {
111 warnings.push(format!(
112 "Transition-metal EHT parameters are provisional for elements {:?}; results should be treated as experimental until benchmark calibration is completed.",
113 provisional_elements
114 ));
115 }
116 if !unsupported_elements.is_empty() {
117 warnings.push(format!(
118 "No EHT parameters are available for elements {:?}.",
119 unsupported_elements
120 ));
121 }
122
123 let level = if !unsupported_elements.is_empty() {
124 SupportLevel::Unsupported
125 } else if !provisional_elements.is_empty() {
126 SupportLevel::Experimental
127 } else {
128 SupportLevel::Supported
129 };
130
131 EhtSupport {
132 level,
133 has_transition_metals: !provisional_elements.is_empty(),
134 supported_elements,
135 provisional_elements,
136 unsupported_elements,
137 warnings,
138 }
139}
140
141static H_ORBITALS: [OrbitalDef; 1] = [OrbitalDef {
144 n: 1,
145 l: 0,
146 label: "1s",
147 vsip: -13.6,
148 zeta: 1.3,
149}];
150
151static C_ORBITALS: [OrbitalDef; 2] = [
152 OrbitalDef {
153 n: 2,
154 l: 0,
155 label: "2s",
156 vsip: -21.4,
157 zeta: 1.625,
158 },
159 OrbitalDef {
160 n: 2,
161 l: 1,
162 label: "2p",
163 vsip: -11.4,
164 zeta: 1.625,
165 },
166];
167
168static N_ORBITALS: [OrbitalDef; 2] = [
169 OrbitalDef {
170 n: 2,
171 l: 0,
172 label: "2s",
173 vsip: -26.0,
174 zeta: 1.950,
175 },
176 OrbitalDef {
177 n: 2,
178 l: 1,
179 label: "2p",
180 vsip: -13.4,
181 zeta: 1.950,
182 },
183];
184
185static O_ORBITALS: [OrbitalDef; 2] = [
186 OrbitalDef {
187 n: 2,
188 l: 0,
189 label: "2s",
190 vsip: -32.3,
191 zeta: 2.275,
192 },
193 OrbitalDef {
194 n: 2,
195 l: 1,
196 label: "2p",
197 vsip: -14.8,
198 zeta: 2.275,
199 },
200];
201
202static F_ORBITALS: [OrbitalDef; 2] = [
203 OrbitalDef {
204 n: 2,
205 l: 0,
206 label: "2s",
207 vsip: -40.0,
208 zeta: 2.425,
209 },
210 OrbitalDef {
211 n: 2,
212 l: 1,
213 label: "2p",
214 vsip: -18.1,
215 zeta: 2.425,
216 },
217];
218
219static CL_ORBITALS: [OrbitalDef; 2] = [
220 OrbitalDef {
221 n: 3,
222 l: 0,
223 label: "3s",
224 vsip: -26.3,
225 zeta: 2.183,
226 },
227 OrbitalDef {
228 n: 3,
229 l: 1,
230 label: "3p",
231 vsip: -14.2,
232 zeta: 1.733,
233 },
234];
235
236static BR_ORBITALS: [OrbitalDef; 2] = [
237 OrbitalDef {
238 n: 4,
239 l: 0,
240 label: "4s",
241 vsip: -22.07,
242 zeta: 2.588,
243 },
244 OrbitalDef {
245 n: 4,
246 l: 1,
247 label: "4p",
248 vsip: -13.1,
249 zeta: 2.131,
250 },
251];
252
253static I_ORBITALS: [OrbitalDef; 2] = [
254 OrbitalDef {
255 n: 5,
256 l: 0,
257 label: "5s",
258 vsip: -18.0,
259 zeta: 2.679,
260 },
261 OrbitalDef {
262 n: 5,
263 l: 1,
264 label: "5p",
265 vsip: -12.7,
266 zeta: 2.322,
267 },
268];
269
270static S_ORBITALS: [OrbitalDef; 2] = [
271 OrbitalDef {
272 n: 3,
273 l: 0,
274 label: "3s",
275 vsip: -20.0,
276 zeta: 1.817,
277 },
278 OrbitalDef {
279 n: 3,
280 l: 1,
281 label: "3p",
282 vsip: -11.0,
283 zeta: 1.817,
284 },
285];
286
287static P_ORBITALS: [OrbitalDef; 2] = [
288 OrbitalDef {
289 n: 3,
290 l: 0,
291 label: "3s",
292 vsip: -18.6,
293 zeta: 1.600,
294 },
295 OrbitalDef {
296 n: 3,
297 l: 1,
298 label: "3p",
299 vsip: -14.0,
300 zeta: 1.600,
301 },
302];
303
304static SI_ORBITALS: [OrbitalDef; 2] = [
305 OrbitalDef {
306 n: 3,
307 l: 0,
308 label: "3s",
309 vsip: -17.3,
310 zeta: 1.383,
311 },
312 OrbitalDef {
313 n: 3,
314 l: 1,
315 label: "3p",
316 vsip: -9.2,
317 zeta: 1.383,
318 },
319];
320
321static B_ORBITALS: [OrbitalDef; 2] = [
322 OrbitalDef {
323 n: 2,
324 l: 0,
325 label: "2s",
326 vsip: -15.2,
327 zeta: 1.300,
328 },
329 OrbitalDef {
330 n: 2,
331 l: 1,
332 label: "2p",
333 vsip: -8.5,
334 zeta: 1.300,
335 },
336];
337
338static SC_ORBITALS: [OrbitalDef; 3] = [
349 OrbitalDef {
350 n: 4,
351 l: 0,
352 label: "4s",
353 vsip: -8.87,
354 zeta: 1.300,
355 },
356 OrbitalDef {
357 n: 4,
358 l: 1,
359 label: "4p",
360 vsip: -2.75,
361 zeta: 1.300,
362 },
363 OrbitalDef {
364 n: 3,
365 l: 2,
366 label: "3d",
367 vsip: -8.51,
368 zeta: 4.350,
369 },
370];
371static TI_ORBITALS: [OrbitalDef; 3] = [
372 OrbitalDef {
373 n: 4,
374 l: 0,
375 label: "4s",
376 vsip: -8.97,
377 zeta: 1.075,
378 },
379 OrbitalDef {
380 n: 4,
381 l: 1,
382 label: "4p",
383 vsip: -5.44,
384 zeta: 1.075,
385 },
386 OrbitalDef {
387 n: 3,
388 l: 2,
389 label: "3d",
390 vsip: -10.81,
391 zeta: 4.550,
392 },
393];
394static V_ORBITALS: [OrbitalDef; 3] = [
395 OrbitalDef {
396 n: 4,
397 l: 0,
398 label: "4s",
399 vsip: -8.81,
400 zeta: 1.300,
401 },
402 OrbitalDef {
403 n: 4,
404 l: 1,
405 label: "4p",
406 vsip: -5.52,
407 zeta: 1.300,
408 },
409 OrbitalDef {
410 n: 3,
411 l: 2,
412 label: "3d",
413 vsip: -11.00,
414 zeta: 4.750,
415 },
416];
417static CR_ORBITALS: [OrbitalDef; 3] = [
418 OrbitalDef {
419 n: 4,
420 l: 0,
421 label: "4s",
422 vsip: -8.66,
423 zeta: 1.700,
424 },
425 OrbitalDef {
426 n: 4,
427 l: 1,
428 label: "4p",
429 vsip: -5.24,
430 zeta: 1.700,
431 },
432 OrbitalDef {
433 n: 3,
434 l: 2,
435 label: "3d",
436 vsip: -11.22,
437 zeta: 4.950,
438 },
439];
440static MN_ORBITALS: [OrbitalDef; 3] = [
441 OrbitalDef {
442 n: 4,
443 l: 0,
444 label: "4s",
445 vsip: -9.75,
446 zeta: 1.800,
447 },
448 OrbitalDef {
449 n: 4,
450 l: 1,
451 label: "4p",
452 vsip: -5.89,
453 zeta: 1.800,
454 },
455 OrbitalDef {
456 n: 3,
457 l: 2,
458 label: "3d",
459 vsip: -11.67,
460 zeta: 5.150,
461 },
462];
463static FE_ORBITALS: [OrbitalDef; 3] = [
464 OrbitalDef {
465 n: 4,
466 l: 0,
467 label: "4s",
468 vsip: -9.10,
469 zeta: 1.900,
470 },
471 OrbitalDef {
472 n: 4,
473 l: 1,
474 label: "4p",
475 vsip: -5.32,
476 zeta: 1.900,
477 },
478 OrbitalDef {
479 n: 3,
480 l: 2,
481 label: "3d",
482 vsip: -12.60,
483 zeta: 5.350,
484 },
485];
486static CO_ORBITALS: [OrbitalDef; 3] = [
487 OrbitalDef {
488 n: 4,
489 l: 0,
490 label: "4s",
491 vsip: -9.21,
492 zeta: 2.000,
493 },
494 OrbitalDef {
495 n: 4,
496 l: 1,
497 label: "4p",
498 vsip: -5.29,
499 zeta: 2.000,
500 },
501 OrbitalDef {
502 n: 3,
503 l: 2,
504 label: "3d",
505 vsip: -13.18,
506 zeta: 5.550,
507 },
508];
509static NI_ORBITALS: [OrbitalDef; 3] = [
510 OrbitalDef {
511 n: 4,
512 l: 0,
513 label: "4s",
514 vsip: -10.95,
515 zeta: 2.100,
516 },
517 OrbitalDef {
518 n: 4,
519 l: 1,
520 label: "4p",
521 vsip: -6.27,
522 zeta: 2.100,
523 },
524 OrbitalDef {
525 n: 3,
526 l: 2,
527 label: "3d",
528 vsip: -13.49,
529 zeta: 5.750,
530 },
531];
532static CU_ORBITALS: [OrbitalDef; 3] = [
533 OrbitalDef {
534 n: 4,
535 l: 0,
536 label: "4s",
537 vsip: -11.40,
538 zeta: 2.200,
539 },
540 OrbitalDef {
541 n: 4,
542 l: 1,
543 label: "4p",
544 vsip: -6.06,
545 zeta: 2.200,
546 },
547 OrbitalDef {
548 n: 3,
549 l: 2,
550 label: "3d",
551 vsip: -14.00,
552 zeta: 5.950,
553 },
554];
555static ZN_ORBITALS: [OrbitalDef; 3] = [
556 OrbitalDef {
557 n: 4,
558 l: 0,
559 label: "4s",
560 vsip: -12.41,
561 zeta: 2.010,
562 },
563 OrbitalDef {
564 n: 4,
565 l: 1,
566 label: "4p",
567 vsip: -6.53,
568 zeta: 2.010,
569 },
570 OrbitalDef {
571 n: 3,
572 l: 2,
573 label: "3d",
574 vsip: -17.10,
575 zeta: 6.150,
576 },
577];
578
579static Y_ORBITALS: [OrbitalDef; 3] = [
583 OrbitalDef {
584 n: 5,
585 l: 0,
586 label: "5s",
587 vsip: -7.29,
588 zeta: 1.390,
589 },
590 OrbitalDef {
591 n: 5,
592 l: 1,
593 label: "5p",
594 vsip: -4.37,
595 zeta: 1.390,
596 },
597 OrbitalDef {
598 n: 4,
599 l: 2,
600 label: "4d",
601 vsip: -8.46,
602 zeta: 3.310,
603 },
604];
605static ZR_ORBITALS: [OrbitalDef; 3] = [
606 OrbitalDef {
607 n: 5,
608 l: 0,
609 label: "5s",
610 vsip: -8.12,
611 zeta: 1.520,
612 },
613 OrbitalDef {
614 n: 5,
615 l: 1,
616 label: "5p",
617 vsip: -5.12,
618 zeta: 1.520,
619 },
620 OrbitalDef {
621 n: 4,
622 l: 2,
623 label: "4d",
624 vsip: -10.14,
625 zeta: 3.840,
626 },
627];
628static NB_ORBITALS: [OrbitalDef; 3] = [
629 OrbitalDef {
630 n: 5,
631 l: 0,
632 label: "5s",
633 vsip: -10.10,
634 zeta: 1.640,
635 },
636 OrbitalDef {
637 n: 5,
638 l: 1,
639 label: "5p",
640 vsip: -6.86,
641 zeta: 1.640,
642 },
643 OrbitalDef {
644 n: 4,
645 l: 2,
646 label: "4d",
647 vsip: -12.10,
648 zeta: 4.080,
649 },
650];
651static MO_ORBITALS: [OrbitalDef; 3] = [
652 OrbitalDef {
653 n: 5,
654 l: 0,
655 label: "5s",
656 vsip: -8.34,
657 zeta: 1.730,
658 },
659 OrbitalDef {
660 n: 5,
661 l: 1,
662 label: "5p",
663 vsip: -5.24,
664 zeta: 1.730,
665 },
666 OrbitalDef {
667 n: 4,
668 l: 2,
669 label: "4d",
670 vsip: -10.50,
671 zeta: 4.540,
672 },
673];
674static TC_ORBITALS: [OrbitalDef; 3] = [
675 OrbitalDef {
676 n: 5,
677 l: 0,
678 label: "5s",
679 vsip: -9.00,
680 zeta: 1.820,
681 },
682 OrbitalDef {
683 n: 5,
684 l: 1,
685 label: "5p",
686 vsip: -5.60,
687 zeta: 1.820,
688 },
689 OrbitalDef {
690 n: 4,
691 l: 2,
692 label: "4d",
693 vsip: -11.20,
694 zeta: 4.900,
695 },
696];
697static RU_ORBITALS: [OrbitalDef; 3] = [
698 OrbitalDef {
699 n: 5,
700 l: 0,
701 label: "5s",
702 vsip: -10.40,
703 zeta: 1.900,
704 },
705 OrbitalDef {
706 n: 5,
707 l: 1,
708 label: "5p",
709 vsip: -6.87,
710 zeta: 1.900,
711 },
712 OrbitalDef {
713 n: 4,
714 l: 2,
715 label: "4d",
716 vsip: -14.90,
717 zeta: 5.380,
718 },
719];
720static RH_ORBITALS: [OrbitalDef; 3] = [
721 OrbitalDef {
722 n: 5,
723 l: 0,
724 label: "5s",
725 vsip: -8.09,
726 zeta: 2.135,
727 },
728 OrbitalDef {
729 n: 5,
730 l: 1,
731 label: "5p",
732 vsip: -4.57,
733 zeta: 2.135,
734 },
735 OrbitalDef {
736 n: 4,
737 l: 2,
738 label: "4d",
739 vsip: -12.50,
740 zeta: 4.290,
741 },
742];
743static PD_ORBITALS: [OrbitalDef; 3] = [
744 OrbitalDef {
745 n: 5,
746 l: 0,
747 label: "5s",
748 vsip: -7.32,
749 zeta: 2.190,
750 },
751 OrbitalDef {
752 n: 5,
753 l: 1,
754 label: "5p",
755 vsip: -3.75,
756 zeta: 2.190,
757 },
758 OrbitalDef {
759 n: 4,
760 l: 2,
761 label: "4d",
762 vsip: -12.02,
763 zeta: 5.983,
764 },
765];
766static AG_ORBITALS: [OrbitalDef; 3] = [
767 OrbitalDef {
768 n: 5,
769 l: 0,
770 label: "5s",
771 vsip: -6.27,
772 zeta: 2.242,
773 },
774 OrbitalDef {
775 n: 5,
776 l: 1,
777 label: "5p",
778 vsip: -3.97,
779 zeta: 2.242,
780 },
781 OrbitalDef {
782 n: 4,
783 l: 2,
784 label: "4d",
785 vsip: -14.58,
786 zeta: 6.070,
787 },
788];
789static CD_ORBITALS: [OrbitalDef; 3] = [
790 OrbitalDef {
791 n: 5,
792 l: 0,
793 label: "5s",
794 vsip: -11.79,
795 zeta: 2.300,
796 },
797 OrbitalDef {
798 n: 5,
799 l: 1,
800 label: "5p",
801 vsip: -6.10,
802 zeta: 2.300,
803 },
804 OrbitalDef {
805 n: 4,
806 l: 2,
807 label: "4d",
808 vsip: -17.84,
809 zeta: 6.330,
810 },
811];
812
813static HF_ORBITALS: [OrbitalDef; 3] = [
818 OrbitalDef {
819 n: 6,
820 l: 0,
821 label: "6s",
822 vsip: -8.20,
823 zeta: 1.720,
824 },
825 OrbitalDef {
826 n: 6,
827 l: 1,
828 label: "6p",
829 vsip: -4.65,
830 zeta: 1.720,
831 },
832 OrbitalDef {
833 n: 5,
834 l: 2,
835 label: "5d",
836 vsip: -11.18,
837 zeta: 4.360,
838 },
839];
840static TA_ORBITALS: [OrbitalDef; 3] = [
841 OrbitalDef {
842 n: 6,
843 l: 0,
844 label: "6s",
845 vsip: -10.79,
846 zeta: 1.830,
847 },
848 OrbitalDef {
849 n: 6,
850 l: 1,
851 label: "6p",
852 vsip: -6.86,
853 zeta: 1.830,
854 },
855 OrbitalDef {
856 n: 5,
857 l: 2,
858 label: "5d",
859 vsip: -12.10,
860 zeta: 4.762,
861 },
862];
863static W_ORBITALS: [OrbitalDef; 3] = [
864 OrbitalDef {
865 n: 6,
866 l: 0,
867 label: "6s",
868 vsip: -8.26,
869 zeta: 1.890,
870 },
871 OrbitalDef {
872 n: 6,
873 l: 1,
874 label: "6p",
875 vsip: -5.17,
876 zeta: 1.890,
877 },
878 OrbitalDef {
879 n: 5,
880 l: 2,
881 label: "5d",
882 vsip: -10.37,
883 zeta: 4.982,
884 },
885];
886static RE_ORBITALS: [OrbitalDef; 3] = [
887 OrbitalDef {
888 n: 6,
889 l: 0,
890 label: "6s",
891 vsip: -9.36,
892 zeta: 1.980,
893 },
894 OrbitalDef {
895 n: 6,
896 l: 1,
897 label: "6p",
898 vsip: -5.96,
899 zeta: 1.980,
900 },
901 OrbitalDef {
902 n: 5,
903 l: 2,
904 label: "5d",
905 vsip: -12.66,
906 zeta: 5.343,
907 },
908];
909static OS_ORBITALS: [OrbitalDef; 3] = [
910 OrbitalDef {
911 n: 6,
912 l: 0,
913 label: "6s",
914 vsip: -8.17,
915 zeta: 2.070,
916 },
917 OrbitalDef {
918 n: 6,
919 l: 1,
920 label: "6p",
921 vsip: -4.81,
922 zeta: 2.070,
923 },
924 OrbitalDef {
925 n: 5,
926 l: 2,
927 label: "5d",
928 vsip: -11.84,
929 zeta: 5.571,
930 },
931];
932static IR_ORBITALS: [OrbitalDef; 3] = [
933 OrbitalDef {
934 n: 6,
935 l: 0,
936 label: "6s",
937 vsip: -11.36,
938 zeta: 2.200,
939 },
940 OrbitalDef {
941 n: 6,
942 l: 1,
943 label: "6p",
944 vsip: -4.50,
945 zeta: 2.200,
946 },
947 OrbitalDef {
948 n: 5,
949 l: 2,
950 label: "5d",
951 vsip: -12.17,
952 zeta: 5.796,
953 },
954];
955static PT_ORBITALS: [OrbitalDef; 3] = [
956 OrbitalDef {
957 n: 6,
958 l: 0,
959 label: "6s",
960 vsip: -9.077,
961 zeta: 2.554,
962 },
963 OrbitalDef {
964 n: 6,
965 l: 1,
966 label: "6p",
967 vsip: -5.475,
968 zeta: 2.554,
969 },
970 OrbitalDef {
971 n: 5,
972 l: 2,
973 label: "5d",
974 vsip: -12.59,
975 zeta: 6.013,
976 },
977];
978static AU_ORBITALS: [OrbitalDef; 3] = [
979 OrbitalDef {
980 n: 6,
981 l: 0,
982 label: "6s",
983 vsip: -10.92,
984 zeta: 2.602,
985 },
986 OrbitalDef {
987 n: 6,
988 l: 1,
989 label: "6p",
990 vsip: -5.55,
991 zeta: 2.602,
992 },
993 OrbitalDef {
994 n: 5,
995 l: 2,
996 label: "5d",
997 vsip: -15.07,
998 zeta: 6.163,
999 },
1000];
1001static HG_ORBITALS: [OrbitalDef; 3] = [
1002 OrbitalDef {
1003 n: 6,
1004 l: 0,
1005 label: "6s",
1006 vsip: -13.68,
1007 zeta: 2.649,
1008 },
1009 OrbitalDef {
1010 n: 6,
1011 l: 1,
1012 label: "6p",
1013 vsip: -8.47,
1014 zeta: 2.649,
1015 },
1016 OrbitalDef {
1017 n: 5,
1018 l: 2,
1019 label: "5d",
1020 vsip: -17.50,
1021 zeta: 6.350,
1022 },
1023];
1024
1025static ALL_PARAMS: &[EhtParams] = &[
1027 EhtParams {
1028 z: 1,
1029 symbol: "H",
1030 orbitals: &H_ORBITALS,
1031 },
1032 EhtParams {
1033 z: 5,
1034 symbol: "B",
1035 orbitals: &B_ORBITALS,
1036 },
1037 EhtParams {
1038 z: 6,
1039 symbol: "C",
1040 orbitals: &C_ORBITALS,
1041 },
1042 EhtParams {
1043 z: 7,
1044 symbol: "N",
1045 orbitals: &N_ORBITALS,
1046 },
1047 EhtParams {
1048 z: 8,
1049 symbol: "O",
1050 orbitals: &O_ORBITALS,
1051 },
1052 EhtParams {
1053 z: 9,
1054 symbol: "F",
1055 orbitals: &F_ORBITALS,
1056 },
1057 EhtParams {
1058 z: 14,
1059 symbol: "Si",
1060 orbitals: &SI_ORBITALS,
1061 },
1062 EhtParams {
1063 z: 15,
1064 symbol: "P",
1065 orbitals: &P_ORBITALS,
1066 },
1067 EhtParams {
1068 z: 16,
1069 symbol: "S",
1070 orbitals: &S_ORBITALS,
1071 },
1072 EhtParams {
1073 z: 17,
1074 symbol: "Cl",
1075 orbitals: &CL_ORBITALS,
1076 },
1077 EhtParams {
1078 z: 21,
1079 symbol: "Sc",
1080 orbitals: &SC_ORBITALS,
1081 },
1082 EhtParams {
1083 z: 22,
1084 symbol: "Ti",
1085 orbitals: &TI_ORBITALS,
1086 },
1087 EhtParams {
1088 z: 23,
1089 symbol: "V",
1090 orbitals: &V_ORBITALS,
1091 },
1092 EhtParams {
1093 z: 24,
1094 symbol: "Cr",
1095 orbitals: &CR_ORBITALS,
1096 },
1097 EhtParams {
1098 z: 25,
1099 symbol: "Mn",
1100 orbitals: &MN_ORBITALS,
1101 },
1102 EhtParams {
1103 z: 26,
1104 symbol: "Fe",
1105 orbitals: &FE_ORBITALS,
1106 },
1107 EhtParams {
1108 z: 27,
1109 symbol: "Co",
1110 orbitals: &CO_ORBITALS,
1111 },
1112 EhtParams {
1113 z: 28,
1114 symbol: "Ni",
1115 orbitals: &NI_ORBITALS,
1116 },
1117 EhtParams {
1118 z: 29,
1119 symbol: "Cu",
1120 orbitals: &CU_ORBITALS,
1121 },
1122 EhtParams {
1123 z: 30,
1124 symbol: "Zn",
1125 orbitals: &ZN_ORBITALS,
1126 },
1127 EhtParams {
1128 z: 35,
1129 symbol: "Br",
1130 orbitals: &BR_ORBITALS,
1131 },
1132 EhtParams {
1133 z: 39,
1134 symbol: "Y",
1135 orbitals: &Y_ORBITALS,
1136 },
1137 EhtParams {
1138 z: 40,
1139 symbol: "Zr",
1140 orbitals: &ZR_ORBITALS,
1141 },
1142 EhtParams {
1143 z: 41,
1144 symbol: "Nb",
1145 orbitals: &NB_ORBITALS,
1146 },
1147 EhtParams {
1148 z: 42,
1149 symbol: "Mo",
1150 orbitals: &MO_ORBITALS,
1151 },
1152 EhtParams {
1153 z: 43,
1154 symbol: "Tc",
1155 orbitals: &TC_ORBITALS,
1156 },
1157 EhtParams {
1158 z: 44,
1159 symbol: "Ru",
1160 orbitals: &RU_ORBITALS,
1161 },
1162 EhtParams {
1163 z: 45,
1164 symbol: "Rh",
1165 orbitals: &RH_ORBITALS,
1166 },
1167 EhtParams {
1168 z: 46,
1169 symbol: "Pd",
1170 orbitals: &PD_ORBITALS,
1171 },
1172 EhtParams {
1173 z: 47,
1174 symbol: "Ag",
1175 orbitals: &AG_ORBITALS,
1176 },
1177 EhtParams {
1178 z: 48,
1179 symbol: "Cd",
1180 orbitals: &CD_ORBITALS,
1181 },
1182 EhtParams {
1183 z: 53,
1184 symbol: "I",
1185 orbitals: &I_ORBITALS,
1186 },
1187 EhtParams {
1188 z: 72,
1189 symbol: "Hf",
1190 orbitals: &HF_ORBITALS,
1191 },
1192 EhtParams {
1193 z: 73,
1194 symbol: "Ta",
1195 orbitals: &TA_ORBITALS,
1196 },
1197 EhtParams {
1198 z: 74,
1199 symbol: "W",
1200 orbitals: &W_ORBITALS,
1201 },
1202 EhtParams {
1203 z: 75,
1204 symbol: "Re",
1205 orbitals: &RE_ORBITALS,
1206 },
1207 EhtParams {
1208 z: 76,
1209 symbol: "Os",
1210 orbitals: &OS_ORBITALS,
1211 },
1212 EhtParams {
1213 z: 77,
1214 symbol: "Ir",
1215 orbitals: &IR_ORBITALS,
1216 },
1217 EhtParams {
1218 z: 78,
1219 symbol: "Pt",
1220 orbitals: &PT_ORBITALS,
1221 },
1222 EhtParams {
1223 z: 79,
1224 symbol: "Au",
1225 orbitals: &AU_ORBITALS,
1226 },
1227 EhtParams {
1228 z: 80,
1229 symbol: "Hg",
1230 orbitals: &HG_ORBITALS,
1231 },
1232];
1233
1234pub fn get_params(z: u8) -> Option<&'static EhtParams> {
1236 ALL_PARAMS.iter().find(|p| p.z == z)
1237}
1238
1239pub fn num_basis_functions(z: u8) -> usize {
1242 match get_params(z) {
1243 Some(p) => p
1244 .orbitals
1245 .iter()
1246 .map(|o| match o.l {
1247 0 => 1,
1248 1 => 3,
1249 2 => 5,
1250 _ => 0,
1251 })
1252 .sum(),
1253 None => 0,
1254 }
1255}
1256
1257#[cfg(test)]
1258mod tests {
1259 use super::*;
1260
1261 #[test]
1262 fn test_hydrogen_params() {
1263 let p = get_params(1).expect("H params");
1264 assert_eq!(p.symbol, "H");
1265 assert_eq!(p.orbitals.len(), 1);
1266 assert!((p.orbitals[0].vsip - (-13.6)).abs() < 1e-10);
1267 assert!((p.orbitals[0].zeta - 1.3).abs() < 1e-10);
1268 }
1269
1270 #[test]
1271 fn test_carbon_params() {
1272 let p = get_params(6).expect("C params");
1273 assert_eq!(p.symbol, "C");
1274 assert_eq!(p.orbitals.len(), 2);
1275 assert_eq!(num_basis_functions(6), 4);
1277 }
1278
1279 #[test]
1280 fn test_oxygen_params() {
1281 let p = get_params(8).expect("O params");
1282 assert_eq!(p.symbol, "O");
1283 assert!((p.orbitals[0].vsip - (-32.3)).abs() < 1e-10);
1284 assert!((p.orbitals[1].vsip - (-14.8)).abs() < 1e-10);
1285 }
1286
1287 #[test]
1288 fn test_all_elements_have_params() {
1289 for z in [1, 5, 6, 7, 8, 9, 14, 15, 16, 17, 35, 53] {
1290 assert!(get_params(z).is_some(), "Missing params for Z={}", z);
1291 }
1292 }
1293
1294 #[test]
1295 fn test_unknown_element_returns_none() {
1296 assert!(get_params(118).is_none());
1297 }
1298
1299 #[test]
1300 fn test_basis_function_count() {
1301 assert_eq!(num_basis_functions(1), 1); assert_eq!(num_basis_functions(6), 4); assert_eq!(num_basis_functions(8), 4); }
1305
1306 #[test]
1307 fn test_transition_metals_are_experimental() {
1308 assert_eq!(support_level_for_element(26), SupportLevel::Experimental);
1309 assert!(is_transition_metal(26));
1310 }
1311
1312 #[test]
1313 fn test_support_summary_collects_warnings() {
1314 let support = analyze_eht_support(&[8, 26, 118]);
1315 assert_eq!(support.level, SupportLevel::Unsupported);
1316 assert!(support.has_transition_metals);
1317 assert_eq!(support.supported_elements, vec![8]);
1318 assert_eq!(support.provisional_elements, vec![26]);
1319 assert_eq!(support.unsupported_elements, vec![118]);
1320 assert_eq!(support.warnings.len(), 2);
1321 }
1322}