#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ShellType {
S,
P,
}
#[derive(Debug, Clone)]
pub struct Shell {
pub center_idx: usize,
pub center: [f64; 3],
pub shell_type: ShellType,
pub exponents: Vec<f64>,
pub coefficients: Vec<f64>,
}
impl Shell {
pub fn n_functions(&self) -> usize {
match self.shell_type {
ShellType::S => 1,
ShellType::P => 3,
}
}
pub fn normalize(&mut self) {
for (i, &alpha) in self.exponents.iter().enumerate() {
let n_prim = match self.shell_type {
ShellType::S => (2.0 * alpha / std::f64::consts::PI).powf(0.75),
ShellType::P => (128.0 * alpha.powi(5) / std::f64::consts::PI.powi(3)).powf(0.25),
};
self.coefficients[i] *= n_prim;
}
let mut sum_s = 0.0;
for (i, &a) in self.exponents.iter().enumerate() {
for (j, &b) in self.exponents.iter().enumerate() {
let gamma = a + b;
let overlap = match self.shell_type {
ShellType::S => (std::f64::consts::PI / gamma).powf(1.5),
ShellType::P => {
let pre = (std::f64::consts::PI / gamma).powf(1.5);
pre * (1.0 / (2.0 * gamma)) }
};
sum_s += self.coefficients[i] * self.coefficients[j] * overlap;
}
}
let norm_factor = 1.0 / sum_s.sqrt();
for c in &mut self.coefficients {
*c *= norm_factor;
}
}
}
#[derive(Debug, Clone)]
pub struct BasisSet {
pub shells: Vec<Shell>,
}
impl BasisSet {
pub fn n_basis(&self) -> usize {
self.shells.iter().map(|s| s.n_functions()).sum()
}
}
pub fn ao_to_atom_map(basis: &BasisSet) -> Vec<usize> {
let mut map = Vec::with_capacity(basis.n_basis());
for shell in &basis.shells {
for _ in 0..shell.n_functions() {
map.push(shell.center_idx);
}
}
map
}
pub const ANG_TO_BOHR: f64 = 1.8897259886;
pub fn build_sto3g_basis(elements: &[u8], positions: &[[f64; 3]]) -> BasisSet {
let mut shells = Vec::new();
for (idx, (&z, pos)) in elements.iter().zip(positions.iter()).enumerate() {
let center = [
pos[0] * ANG_TO_BOHR,
pos[1] * ANG_TO_BOHR,
pos[2] * ANG_TO_BOHR,
];
let atom_shells = sto3g_shells(z, idx, center);
shells.extend(atom_shells);
}
BasisSet { shells }
}
fn sto3g_shells(z: u8, center_idx: usize, center: [f64; 3]) -> Vec<Shell> {
let mut shells = match z {
1 => vec![Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![3.42525091, 0.62391373, 0.16885540],
coefficients: vec![0.15432897, 0.53532814, 0.44463454],
}],
6 => vec![
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![71.6168370, 13.0450960, 3.5305122],
coefficients: vec![0.15432897, 0.53532814, 0.44463454],
},
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![2.9412494, 0.6834831, 0.2222899],
coefficients: vec![-0.09996723, 0.39951283, 0.70011547],
},
Shell {
center_idx,
center,
shell_type: ShellType::P,
exponents: vec![2.9412494, 0.6834831, 0.2222899],
coefficients: vec![0.15591627, 0.60768372, 0.39195739],
},
],
7 => vec![
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![99.1061690, 18.0523120, 4.8856602],
coefficients: vec![0.15432897, 0.53532814, 0.44463454],
},
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![3.7804559, 0.8784966, 0.2857144],
coefficients: vec![-0.09996723, 0.39951283, 0.70011547],
},
Shell {
center_idx,
center,
shell_type: ShellType::P,
exponents: vec![3.7804559, 0.8784966, 0.2857144],
coefficients: vec![0.15591627, 0.60768372, 0.39195739],
},
],
8 => vec![
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![130.7093200, 23.8088610, 6.4436083],
coefficients: vec![0.15432897, 0.53532814, 0.44463454],
},
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![5.0331513, 1.1695961, 0.3803890],
coefficients: vec![-0.09996723, 0.39951283, 0.70011547],
},
Shell {
center_idx,
center,
shell_type: ShellType::P,
exponents: vec![5.0331513, 1.1695961, 0.3803890],
coefficients: vec![0.15591627, 0.60768372, 0.39195739],
},
],
9 => vec![
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![166.6791300, 30.3608120, 8.2168207],
coefficients: vec![0.15432897, 0.53532814, 0.44463454],
},
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![6.4648032, 1.5022812, 0.4885885],
coefficients: vec![-0.09996723, 0.39951283, 0.70011547],
},
Shell {
center_idx,
center,
shell_type: ShellType::P,
exponents: vec![6.4648032, 1.5022812, 0.4885885],
coefficients: vec![0.15591627, 0.60768372, 0.39195739],
},
],
15 => vec![
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![508.291310, 92.5891370, 25.0571730],
coefficients: vec![0.15432897, 0.53532814, 0.44463454],
},
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![18.5172490, 4.30422160, 1.39999670],
coefficients: vec![-0.09996723, 0.39951283, 0.70011547],
},
Shell {
center_idx,
center,
shell_type: ShellType::P,
exponents: vec![18.5172490, 4.30422160, 1.39999670],
coefficients: vec![0.15591627, 0.60768372, 0.39195739],
},
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![1.56367880, 0.36368650, 0.11828520],
coefficients: vec![-0.09996723, 0.39951283, 0.70011547],
},
Shell {
center_idx,
center,
shell_type: ShellType::P,
exponents: vec![1.56367880, 0.36368650, 0.11828520],
coefficients: vec![0.15591627, 0.60768372, 0.39195739],
},
],
16 => vec![
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![598.642680, 109.046680, 29.5121090],
coefficients: vec![0.15432897, 0.53532814, 0.44463454],
},
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![22.1564680, 5.14855900, 1.67441430],
coefficients: vec![-0.09996723, 0.39951283, 0.70011547],
},
Shell {
center_idx,
center,
shell_type: ShellType::P,
exponents: vec![22.1564680, 5.14855900, 1.67441430],
coefficients: vec![0.15591627, 0.60768372, 0.39195739],
},
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![1.80579080, 0.41988400, 0.13655330],
coefficients: vec![-0.09996723, 0.39951283, 0.70011547],
},
Shell {
center_idx,
center,
shell_type: ShellType::P,
exponents: vec![1.80579080, 0.41988400, 0.13655330],
coefficients: vec![0.15591627, 0.60768372, 0.39195739],
},
],
17 => vec![
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![696.408520, 126.888800, 34.3399080],
coefficients: vec![0.15432897, 0.53532814, 0.44463454],
},
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![25.9670530, 6.03406090, 1.96235810],
coefficients: vec![-0.09996723, 0.39951283, 0.70011547],
},
Shell {
center_idx,
center,
shell_type: ShellType::P,
exponents: vec![25.9670530, 6.03406090, 1.96235810],
coefficients: vec![0.15591627, 0.60768372, 0.39195739],
},
Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![2.14407210, 0.49841410, 0.16208590],
coefficients: vec![-0.09996723, 0.39951283, 0.70011547],
},
Shell {
center_idx,
center,
shell_type: ShellType::P,
exponents: vec![2.14407210, 0.49841410, 0.16208590],
coefficients: vec![0.15591627, 0.60768372, 0.39195739],
},
],
_ => {
vec![Shell {
center_idx,
center,
shell_type: ShellType::S,
exponents: vec![
3.42525091 * (z as f64 / 1.0).powi(2),
0.62391373 * (z as f64 / 1.0).powi(2),
0.16885540 * (z as f64 / 1.0).powi(2),
],
coefficients: vec![0.15432897, 0.53532814, 0.44463454],
}]
}
};
for shell in &mut shells {
shell.normalize();
}
shells
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_h2_basis() {
let basis = build_sto3g_basis(&[1, 1], &[[0.0, 0.0, 0.0], [0.0, 0.0, 0.74]]);
assert_eq!(basis.n_basis(), 2); assert_eq!(basis.shells.len(), 2);
}
#[test]
fn test_water_basis() {
let elements = [8u8, 1, 1];
let positions = [
[0.0, 0.0, 0.117],
[0.0, 0.757, -0.469],
[0.0, -0.757, -0.469],
];
let basis = build_sto3g_basis(&elements, &positions);
assert_eq!(basis.n_basis(), 7);
}
}