use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SupportLevel {
Unsupported,
Experimental,
Supported,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct EhtSupport {
pub level: SupportLevel,
pub has_transition_metals: bool,
pub supported_elements: Vec<u8>,
pub provisional_elements: Vec<u8>,
pub unsupported_elements: Vec<u8>,
pub warnings: Vec<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct OrbitalDef {
pub n: u8,
pub l: u8,
pub label: &'static str,
pub vsip: f64,
pub zeta: f64,
}
#[derive(Debug, Clone, Serialize)]
pub struct EhtParams {
pub z: u8,
pub symbol: &'static str,
pub orbitals: &'static [OrbitalDef],
}
pub const DEFAULT_K: f64 = 1.75;
pub fn is_transition_metal(z: u8) -> bool {
matches!(z, 21..=30 | 39..=48 | 72..=80)
}
pub fn support_level_for_element(z: u8) -> SupportLevel {
if get_params(z).is_none() {
SupportLevel::Unsupported
} else if is_transition_metal(z) {
SupportLevel::Experimental
} else {
SupportLevel::Supported
}
}
pub fn analyze_eht_support(elements: &[u8]) -> EhtSupport {
let mut supported_elements = Vec::new();
let mut provisional_elements = Vec::new();
let mut unsupported_elements = Vec::new();
for &z in elements {
match support_level_for_element(z) {
SupportLevel::Supported => {
if !supported_elements.contains(&z) {
supported_elements.push(z);
}
}
SupportLevel::Experimental => {
if !provisional_elements.contains(&z) {
provisional_elements.push(z);
}
}
SupportLevel::Unsupported => {
if !unsupported_elements.contains(&z) {
unsupported_elements.push(z);
}
}
}
}
supported_elements.sort_unstable();
provisional_elements.sort_unstable();
unsupported_elements.sort_unstable();
let mut warnings = Vec::new();
if !provisional_elements.is_empty() {
warnings.push(format!(
"Transition-metal EHT parameters are provisional for elements {:?}; results should be treated as experimental until benchmark calibration is completed.",
provisional_elements
));
}
if !unsupported_elements.is_empty() {
warnings.push(format!(
"No EHT parameters are available for elements {:?}.",
unsupported_elements
));
}
let level = if !unsupported_elements.is_empty() {
SupportLevel::Unsupported
} else if !provisional_elements.is_empty() {
SupportLevel::Experimental
} else {
SupportLevel::Supported
};
EhtSupport {
level,
has_transition_metals: !provisional_elements.is_empty(),
supported_elements,
provisional_elements,
unsupported_elements,
warnings,
}
}
static H_ORBITALS: [OrbitalDef; 1] = [OrbitalDef {
n: 1,
l: 0,
label: "1s",
vsip: -13.6,
zeta: 1.3,
}];
static C_ORBITALS: [OrbitalDef; 2] = [
OrbitalDef {
n: 2,
l: 0,
label: "2s",
vsip: -21.4,
zeta: 1.625,
},
OrbitalDef {
n: 2,
l: 1,
label: "2p",
vsip: -11.4,
zeta: 1.625,
},
];
static N_ORBITALS: [OrbitalDef; 2] = [
OrbitalDef {
n: 2,
l: 0,
label: "2s",
vsip: -26.0,
zeta: 1.950,
},
OrbitalDef {
n: 2,
l: 1,
label: "2p",
vsip: -13.4,
zeta: 1.950,
},
];
static O_ORBITALS: [OrbitalDef; 2] = [
OrbitalDef {
n: 2,
l: 0,
label: "2s",
vsip: -32.3,
zeta: 2.275,
},
OrbitalDef {
n: 2,
l: 1,
label: "2p",
vsip: -14.8,
zeta: 2.275,
},
];
static F_ORBITALS: [OrbitalDef; 2] = [
OrbitalDef {
n: 2,
l: 0,
label: "2s",
vsip: -40.0,
zeta: 2.425,
},
OrbitalDef {
n: 2,
l: 1,
label: "2p",
vsip: -18.1,
zeta: 2.425,
},
];
static CL_ORBITALS: [OrbitalDef; 2] = [
OrbitalDef {
n: 3,
l: 0,
label: "3s",
vsip: -26.3,
zeta: 2.183,
},
OrbitalDef {
n: 3,
l: 1,
label: "3p",
vsip: -14.2,
zeta: 1.733,
},
];
static BR_ORBITALS: [OrbitalDef; 2] = [
OrbitalDef {
n: 4,
l: 0,
label: "4s",
vsip: -22.07,
zeta: 2.588,
},
OrbitalDef {
n: 4,
l: 1,
label: "4p",
vsip: -13.1,
zeta: 2.131,
},
];
static I_ORBITALS: [OrbitalDef; 2] = [
OrbitalDef {
n: 5,
l: 0,
label: "5s",
vsip: -18.0,
zeta: 2.679,
},
OrbitalDef {
n: 5,
l: 1,
label: "5p",
vsip: -12.7,
zeta: 2.322,
},
];
static S_ORBITALS: [OrbitalDef; 2] = [
OrbitalDef {
n: 3,
l: 0,
label: "3s",
vsip: -20.0,
zeta: 1.817,
},
OrbitalDef {
n: 3,
l: 1,
label: "3p",
vsip: -11.0,
zeta: 1.817,
},
];
static P_ORBITALS: [OrbitalDef; 2] = [
OrbitalDef {
n: 3,
l: 0,
label: "3s",
vsip: -18.6,
zeta: 1.600,
},
OrbitalDef {
n: 3,
l: 1,
label: "3p",
vsip: -14.0,
zeta: 1.600,
},
];
static SI_ORBITALS: [OrbitalDef; 2] = [
OrbitalDef {
n: 3,
l: 0,
label: "3s",
vsip: -17.3,
zeta: 1.383,
},
OrbitalDef {
n: 3,
l: 1,
label: "3p",
vsip: -9.2,
zeta: 1.383,
},
];
static B_ORBITALS: [OrbitalDef; 2] = [
OrbitalDef {
n: 2,
l: 0,
label: "2s",
vsip: -15.2,
zeta: 1.300,
},
OrbitalDef {
n: 2,
l: 1,
label: "2p",
vsip: -8.5,
zeta: 1.300,
},
];
static SC_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 4,
l: 0,
label: "4s",
vsip: -8.87,
zeta: 1.300,
},
OrbitalDef {
n: 4,
l: 1,
label: "4p",
vsip: -2.75,
zeta: 1.300,
},
OrbitalDef {
n: 3,
l: 2,
label: "3d",
vsip: -8.51,
zeta: 4.350,
},
];
static TI_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 4,
l: 0,
label: "4s",
vsip: -8.97,
zeta: 1.075,
},
OrbitalDef {
n: 4,
l: 1,
label: "4p",
vsip: -5.44,
zeta: 1.075,
},
OrbitalDef {
n: 3,
l: 2,
label: "3d",
vsip: -10.81,
zeta: 4.550,
},
];
static V_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 4,
l: 0,
label: "4s",
vsip: -8.81,
zeta: 1.300,
},
OrbitalDef {
n: 4,
l: 1,
label: "4p",
vsip: -5.52,
zeta: 1.300,
},
OrbitalDef {
n: 3,
l: 2,
label: "3d",
vsip: -11.00,
zeta: 4.750,
},
];
static CR_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 4,
l: 0,
label: "4s",
vsip: -8.66,
zeta: 1.700,
},
OrbitalDef {
n: 4,
l: 1,
label: "4p",
vsip: -5.24,
zeta: 1.700,
},
OrbitalDef {
n: 3,
l: 2,
label: "3d",
vsip: -11.22,
zeta: 4.950,
},
];
static MN_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 4,
l: 0,
label: "4s",
vsip: -9.75,
zeta: 1.800,
},
OrbitalDef {
n: 4,
l: 1,
label: "4p",
vsip: -5.89,
zeta: 1.800,
},
OrbitalDef {
n: 3,
l: 2,
label: "3d",
vsip: -11.67,
zeta: 5.150,
},
];
static FE_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 4,
l: 0,
label: "4s",
vsip: -9.10,
zeta: 1.900,
},
OrbitalDef {
n: 4,
l: 1,
label: "4p",
vsip: -5.32,
zeta: 1.900,
},
OrbitalDef {
n: 3,
l: 2,
label: "3d",
vsip: -12.60,
zeta: 5.350,
},
];
static CO_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 4,
l: 0,
label: "4s",
vsip: -9.21,
zeta: 2.000,
},
OrbitalDef {
n: 4,
l: 1,
label: "4p",
vsip: -5.29,
zeta: 2.000,
},
OrbitalDef {
n: 3,
l: 2,
label: "3d",
vsip: -13.18,
zeta: 5.550,
},
];
static NI_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 4,
l: 0,
label: "4s",
vsip: -10.95,
zeta: 2.100,
},
OrbitalDef {
n: 4,
l: 1,
label: "4p",
vsip: -6.27,
zeta: 2.100,
},
OrbitalDef {
n: 3,
l: 2,
label: "3d",
vsip: -13.49,
zeta: 5.750,
},
];
static CU_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 4,
l: 0,
label: "4s",
vsip: -11.40,
zeta: 2.200,
},
OrbitalDef {
n: 4,
l: 1,
label: "4p",
vsip: -6.06,
zeta: 2.200,
},
OrbitalDef {
n: 3,
l: 2,
label: "3d",
vsip: -14.00,
zeta: 5.950,
},
];
static ZN_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 4,
l: 0,
label: "4s",
vsip: -12.41,
zeta: 2.010,
},
OrbitalDef {
n: 4,
l: 1,
label: "4p",
vsip: -6.53,
zeta: 2.010,
},
OrbitalDef {
n: 3,
l: 2,
label: "3d",
vsip: -17.10,
zeta: 6.150,
},
];
static Y_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 5,
l: 0,
label: "5s",
vsip: -7.29,
zeta: 1.390,
},
OrbitalDef {
n: 5,
l: 1,
label: "5p",
vsip: -4.37,
zeta: 1.390,
},
OrbitalDef {
n: 4,
l: 2,
label: "4d",
vsip: -8.46,
zeta: 3.310,
},
];
static ZR_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 5,
l: 0,
label: "5s",
vsip: -8.12,
zeta: 1.520,
},
OrbitalDef {
n: 5,
l: 1,
label: "5p",
vsip: -5.12,
zeta: 1.520,
},
OrbitalDef {
n: 4,
l: 2,
label: "4d",
vsip: -10.14,
zeta: 3.840,
},
];
static NB_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 5,
l: 0,
label: "5s",
vsip: -10.10,
zeta: 1.640,
},
OrbitalDef {
n: 5,
l: 1,
label: "5p",
vsip: -6.86,
zeta: 1.640,
},
OrbitalDef {
n: 4,
l: 2,
label: "4d",
vsip: -12.10,
zeta: 4.080,
},
];
static MO_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 5,
l: 0,
label: "5s",
vsip: -8.34,
zeta: 1.730,
},
OrbitalDef {
n: 5,
l: 1,
label: "5p",
vsip: -5.24,
zeta: 1.730,
},
OrbitalDef {
n: 4,
l: 2,
label: "4d",
vsip: -10.50,
zeta: 4.540,
},
];
static TC_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 5,
l: 0,
label: "5s",
vsip: -9.00,
zeta: 1.820,
},
OrbitalDef {
n: 5,
l: 1,
label: "5p",
vsip: -5.60,
zeta: 1.820,
},
OrbitalDef {
n: 4,
l: 2,
label: "4d",
vsip: -11.20,
zeta: 4.900,
},
];
static RU_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 5,
l: 0,
label: "5s",
vsip: -10.40,
zeta: 1.900,
},
OrbitalDef {
n: 5,
l: 1,
label: "5p",
vsip: -6.87,
zeta: 1.900,
},
OrbitalDef {
n: 4,
l: 2,
label: "4d",
vsip: -14.90,
zeta: 5.380,
},
];
static RH_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 5,
l: 0,
label: "5s",
vsip: -8.09,
zeta: 2.135,
},
OrbitalDef {
n: 5,
l: 1,
label: "5p",
vsip: -4.57,
zeta: 2.135,
},
OrbitalDef {
n: 4,
l: 2,
label: "4d",
vsip: -12.50,
zeta: 4.290,
},
];
static PD_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 5,
l: 0,
label: "5s",
vsip: -7.32,
zeta: 2.190,
},
OrbitalDef {
n: 5,
l: 1,
label: "5p",
vsip: -3.75,
zeta: 2.190,
},
OrbitalDef {
n: 4,
l: 2,
label: "4d",
vsip: -12.02,
zeta: 5.983,
},
];
static AG_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 5,
l: 0,
label: "5s",
vsip: -6.27,
zeta: 2.242,
},
OrbitalDef {
n: 5,
l: 1,
label: "5p",
vsip: -3.97,
zeta: 2.242,
},
OrbitalDef {
n: 4,
l: 2,
label: "4d",
vsip: -14.58,
zeta: 6.070,
},
];
static CD_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 5,
l: 0,
label: "5s",
vsip: -11.79,
zeta: 2.300,
},
OrbitalDef {
n: 5,
l: 1,
label: "5p",
vsip: -6.10,
zeta: 2.300,
},
OrbitalDef {
n: 4,
l: 2,
label: "4d",
vsip: -17.84,
zeta: 6.330,
},
];
static HF_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 6,
l: 0,
label: "6s",
vsip: -8.20,
zeta: 1.720,
},
OrbitalDef {
n: 6,
l: 1,
label: "6p",
vsip: -4.65,
zeta: 1.720,
},
OrbitalDef {
n: 5,
l: 2,
label: "5d",
vsip: -11.18,
zeta: 4.360,
},
];
static TA_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 6,
l: 0,
label: "6s",
vsip: -10.79,
zeta: 1.830,
},
OrbitalDef {
n: 6,
l: 1,
label: "6p",
vsip: -6.86,
zeta: 1.830,
},
OrbitalDef {
n: 5,
l: 2,
label: "5d",
vsip: -12.10,
zeta: 4.762,
},
];
static W_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 6,
l: 0,
label: "6s",
vsip: -8.26,
zeta: 1.890,
},
OrbitalDef {
n: 6,
l: 1,
label: "6p",
vsip: -5.17,
zeta: 1.890,
},
OrbitalDef {
n: 5,
l: 2,
label: "5d",
vsip: -10.37,
zeta: 4.982,
},
];
static RE_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 6,
l: 0,
label: "6s",
vsip: -9.36,
zeta: 1.980,
},
OrbitalDef {
n: 6,
l: 1,
label: "6p",
vsip: -5.96,
zeta: 1.980,
},
OrbitalDef {
n: 5,
l: 2,
label: "5d",
vsip: -12.66,
zeta: 5.343,
},
];
static OS_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 6,
l: 0,
label: "6s",
vsip: -8.17,
zeta: 2.070,
},
OrbitalDef {
n: 6,
l: 1,
label: "6p",
vsip: -4.81,
zeta: 2.070,
},
OrbitalDef {
n: 5,
l: 2,
label: "5d",
vsip: -11.84,
zeta: 5.571,
},
];
static IR_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 6,
l: 0,
label: "6s",
vsip: -11.36,
zeta: 2.200,
},
OrbitalDef {
n: 6,
l: 1,
label: "6p",
vsip: -4.50,
zeta: 2.200,
},
OrbitalDef {
n: 5,
l: 2,
label: "5d",
vsip: -12.17,
zeta: 5.796,
},
];
static PT_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 6,
l: 0,
label: "6s",
vsip: -9.077,
zeta: 2.554,
},
OrbitalDef {
n: 6,
l: 1,
label: "6p",
vsip: -5.475,
zeta: 2.554,
},
OrbitalDef {
n: 5,
l: 2,
label: "5d",
vsip: -12.59,
zeta: 6.013,
},
];
static AU_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 6,
l: 0,
label: "6s",
vsip: -10.92,
zeta: 2.602,
},
OrbitalDef {
n: 6,
l: 1,
label: "6p",
vsip: -5.55,
zeta: 2.602,
},
OrbitalDef {
n: 5,
l: 2,
label: "5d",
vsip: -15.07,
zeta: 6.163,
},
];
static HG_ORBITALS: [OrbitalDef; 3] = [
OrbitalDef {
n: 6,
l: 0,
label: "6s",
vsip: -13.68,
zeta: 2.649,
},
OrbitalDef {
n: 6,
l: 1,
label: "6p",
vsip: -8.47,
zeta: 2.649,
},
OrbitalDef {
n: 5,
l: 2,
label: "5d",
vsip: -17.50,
zeta: 6.350,
},
];
static ALL_PARAMS: &[EhtParams] = &[
EhtParams {
z: 1,
symbol: "H",
orbitals: &H_ORBITALS,
},
EhtParams {
z: 5,
symbol: "B",
orbitals: &B_ORBITALS,
},
EhtParams {
z: 6,
symbol: "C",
orbitals: &C_ORBITALS,
},
EhtParams {
z: 7,
symbol: "N",
orbitals: &N_ORBITALS,
},
EhtParams {
z: 8,
symbol: "O",
orbitals: &O_ORBITALS,
},
EhtParams {
z: 9,
symbol: "F",
orbitals: &F_ORBITALS,
},
EhtParams {
z: 14,
symbol: "Si",
orbitals: &SI_ORBITALS,
},
EhtParams {
z: 15,
symbol: "P",
orbitals: &P_ORBITALS,
},
EhtParams {
z: 16,
symbol: "S",
orbitals: &S_ORBITALS,
},
EhtParams {
z: 17,
symbol: "Cl",
orbitals: &CL_ORBITALS,
},
EhtParams {
z: 21,
symbol: "Sc",
orbitals: &SC_ORBITALS,
},
EhtParams {
z: 22,
symbol: "Ti",
orbitals: &TI_ORBITALS,
},
EhtParams {
z: 23,
symbol: "V",
orbitals: &V_ORBITALS,
},
EhtParams {
z: 24,
symbol: "Cr",
orbitals: &CR_ORBITALS,
},
EhtParams {
z: 25,
symbol: "Mn",
orbitals: &MN_ORBITALS,
},
EhtParams {
z: 26,
symbol: "Fe",
orbitals: &FE_ORBITALS,
},
EhtParams {
z: 27,
symbol: "Co",
orbitals: &CO_ORBITALS,
},
EhtParams {
z: 28,
symbol: "Ni",
orbitals: &NI_ORBITALS,
},
EhtParams {
z: 29,
symbol: "Cu",
orbitals: &CU_ORBITALS,
},
EhtParams {
z: 30,
symbol: "Zn",
orbitals: &ZN_ORBITALS,
},
EhtParams {
z: 35,
symbol: "Br",
orbitals: &BR_ORBITALS,
},
EhtParams {
z: 39,
symbol: "Y",
orbitals: &Y_ORBITALS,
},
EhtParams {
z: 40,
symbol: "Zr",
orbitals: &ZR_ORBITALS,
},
EhtParams {
z: 41,
symbol: "Nb",
orbitals: &NB_ORBITALS,
},
EhtParams {
z: 42,
symbol: "Mo",
orbitals: &MO_ORBITALS,
},
EhtParams {
z: 43,
symbol: "Tc",
orbitals: &TC_ORBITALS,
},
EhtParams {
z: 44,
symbol: "Ru",
orbitals: &RU_ORBITALS,
},
EhtParams {
z: 45,
symbol: "Rh",
orbitals: &RH_ORBITALS,
},
EhtParams {
z: 46,
symbol: "Pd",
orbitals: &PD_ORBITALS,
},
EhtParams {
z: 47,
symbol: "Ag",
orbitals: &AG_ORBITALS,
},
EhtParams {
z: 48,
symbol: "Cd",
orbitals: &CD_ORBITALS,
},
EhtParams {
z: 53,
symbol: "I",
orbitals: &I_ORBITALS,
},
EhtParams {
z: 72,
symbol: "Hf",
orbitals: &HF_ORBITALS,
},
EhtParams {
z: 73,
symbol: "Ta",
orbitals: &TA_ORBITALS,
},
EhtParams {
z: 74,
symbol: "W",
orbitals: &W_ORBITALS,
},
EhtParams {
z: 75,
symbol: "Re",
orbitals: &RE_ORBITALS,
},
EhtParams {
z: 76,
symbol: "Os",
orbitals: &OS_ORBITALS,
},
EhtParams {
z: 77,
symbol: "Ir",
orbitals: &IR_ORBITALS,
},
EhtParams {
z: 78,
symbol: "Pt",
orbitals: &PT_ORBITALS,
},
EhtParams {
z: 79,
symbol: "Au",
orbitals: &AU_ORBITALS,
},
EhtParams {
z: 80,
symbol: "Hg",
orbitals: &HG_ORBITALS,
},
];
pub fn get_params(z: u8) -> Option<&'static EhtParams> {
ALL_PARAMS.iter().find(|p| p.z == z)
}
pub fn num_basis_functions(z: u8) -> usize {
match get_params(z) {
Some(p) => p
.orbitals
.iter()
.map(|o| match o.l {
0 => 1,
1 => 3,
2 => 5,
_ => 0,
})
.sum(),
None => 0,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hydrogen_params() {
let p = get_params(1).expect("H params");
assert_eq!(p.symbol, "H");
assert_eq!(p.orbitals.len(), 1);
assert!((p.orbitals[0].vsip - (-13.6)).abs() < 1e-10);
assert!((p.orbitals[0].zeta - 1.3).abs() < 1e-10);
}
#[test]
fn test_carbon_params() {
let p = get_params(6).expect("C params");
assert_eq!(p.symbol, "C");
assert_eq!(p.orbitals.len(), 2);
assert_eq!(num_basis_functions(6), 4);
}
#[test]
fn test_oxygen_params() {
let p = get_params(8).expect("O params");
assert_eq!(p.symbol, "O");
assert!((p.orbitals[0].vsip - (-32.3)).abs() < 1e-10);
assert!((p.orbitals[1].vsip - (-14.8)).abs() < 1e-10);
}
#[test]
fn test_all_elements_have_params() {
for z in [1, 5, 6, 7, 8, 9, 14, 15, 16, 17, 35, 53] {
assert!(get_params(z).is_some(), "Missing params for Z={}", z);
}
}
#[test]
fn test_unknown_element_returns_none() {
assert!(get_params(118).is_none());
}
#[test]
fn test_basis_function_count() {
assert_eq!(num_basis_functions(1), 1); assert_eq!(num_basis_functions(6), 4); assert_eq!(num_basis_functions(8), 4); }
#[test]
fn test_transition_metals_are_experimental() {
assert_eq!(support_level_for_element(26), SupportLevel::Experimental);
assert!(is_transition_metal(26));
}
#[test]
fn test_support_summary_collects_warnings() {
let support = analyze_eht_support(&[8, 26, 118]);
assert_eq!(support.level, SupportLevel::Unsupported);
assert!(support.has_transition_metals);
assert_eq!(support.supported_elements, vec![8]);
assert_eq!(support.provisional_elements, vec![26]);
assert_eq!(support.unsupported_elements, vec![118]);
assert_eq!(support.warnings.len(), 2);
}
}