use chematic_core::{Molecule, AtomIdx};
use crate::coords::Coords3D;
pub fn generate_coords_etkdg(mol: &Molecule) -> Coords3D {
let mut coords = super::dg::generate_coords(mol);
if mol.atom_count() < 4 {
return coords;
}
apply_torsion_preferences(mol, &mut coords);
let constraints = super::constraints::build_constraints(mol);
coords = super::constraints::satisfy_constraints(&coords, mol, &constraints, 3);
coords
}
fn apply_torsion_preferences(mol: &Molecule, coords: &mut Coords3D) {
let n = mol.atom_count();
let mut applied = std::collections::HashSet::new();
for b in 0..n {
for c in 0..n {
if b == c {
continue;
}
let b_idx = AtomIdx(b as u32);
let c_idx = AtomIdx(c as u32);
if mol.bond_between(b_idx, c_idx).is_none() {
continue;
}
let b_neighbors: Vec<usize> = (0..n)
.filter(|&a| a != c && mol.bond_between(b_idx, AtomIdx(a as u32)).is_some())
.collect();
let c_neighbors: Vec<usize> = (0..n)
.filter(|&a| a != b && mol.bond_between(c_idx, AtomIdx(a as u32)).is_some())
.collect();
for &a in &b_neighbors {
for &d in &c_neighbors {
let key = (a.min(d), a.max(d), b.min(c), b.max(c));
if applied.contains(&key) {
continue;
}
let a_idx = AtomIdx(a as u32);
let d_idx = AtomIdx(d as u32);
let current = super::mol_transforms::get_dihedral(
coords,
a_idx,
b_idx,
c_idx,
d_idx,
);
if current.is_none() {
continue;
}
let current_deg = current.unwrap() * 180.0 / std::f64::consts::PI;
let target_deg = 180.0;
if (current_deg - target_deg).abs() > 20.0 {
let target_rad = target_deg * std::f64::consts::PI / 180.0;
*coords = super::mol_transforms::set_dihedral(
&coords,
mol,
a_idx,
b_idx,
c_idx,
d_idx,
target_rad,
);
applied.insert(key);
}
}
}
}
}
}