use crate::traits::{get_valence_electrons, AtomTrait, BondTrait};
#[derive(Debug, Clone, Copy)]
pub enum Geometry {
Linear, TrigonalPlanar, Tetrahedral, TrigonalBipyramidal, Octahedral, PentagonalBipyramidal, }
impl Geometry {
pub fn from_steric_number(sn: usize) -> Self {
match sn {
0..=2 => Geometry::Linear,
3 => Geometry::TrigonalPlanar,
4 => Geometry::Tetrahedral,
5 => Geometry::TrigonalBipyramidal,
6 => Geometry::Octahedral,
_ => Geometry::PentagonalBipyramidal,
}
}
pub fn ideal_angle(&self) -> f64 {
match self {
Geometry::Linear => std::f64::consts::PI,
Geometry::TrigonalPlanar => 2.0 * std::f64::consts::PI / 3.0,
Geometry::Tetrahedral => (109.4712_f64).to_radians(),
Geometry::TrigonalBipyramidal => (90.0_f64).to_radians(),
Geometry::Octahedral => std::f64::consts::PI / 2.0,
Geometry::PentagonalBipyramidal => (72.0_f64).to_radians(),
}
}
}
pub fn calculate_steric_number<A: AtomTrait, B: BondTrait>(
atom_idx: usize,
atoms: &[A],
bonds: &[B],
) -> usize {
let atom = &atoms[atom_idx];
let valence_electrons = get_valence_electrons(atom.atomic_number());
let charge = atom.formal_charge();
let mut bonded_atoms_count = 0;
let mut electron_sum = 0.0;
for bond in bonds {
let (i, j) = bond.get_atom_indices();
if i == atom_idx || j == atom_idx {
bonded_atoms_count += 1;
electron_sum += bond.get_bond_order() as f64;
}
}
let lone_pairs = ((valence_electrons as i32 - charge) as f64 - electron_sum).max(0.0) / 2.0;
bonded_atoms_count + (lone_pairs.round() as usize)
}