pub use gchemol_lattice::Lattice;
use crate::atom::Vector3f;
use crate::common::*;
use crate::molecule::Molecule;
impl Molecule {
#[cfg(feature = "adhoc")]
pub fn get_lattice(&self) -> Option<&Lattice> {
self.lattice.as_ref()
}
#[cfg(feature = "adhoc")]
pub fn get_lattice_mut(&mut self) -> Option<&mut Lattice> {
self.lattice.as_mut()
}
pub fn set_lattice(&mut self, lat: Lattice) {
self.lattice = Some(lat);
}
pub fn set_lattice_scaled(&mut self, lat: Lattice) {
let fracs: Vec<_> = self.get_scaled_positions().expect("not periodic struct").collect();
self.set_lattice(lat);
self.set_scaled_positions(fracs);
}
pub fn is_periodic(&self) -> bool {
self.lattice.is_some()
}
pub fn unbuild_crystal(&mut self) -> Option<Lattice> {
self.lattice.take()
}
#[deprecated(note = "use get_scaled_positions instead")]
pub fn scaled_positions(&self) -> Option<impl Iterator<Item = [f64; 3]> + '_> {
self.get_scaled_positions()
}
pub fn get_scaled_positions(&self) -> Option<impl Iterator<Item = [f64; 3]> + '_> {
self.lattice.map(|lat| self.positions().map(move |cart| lat.to_frac(cart).into()))
}
pub fn set_scaled_positions<T, P>(&mut self, scaled: T)
where
T: IntoIterator<Item = P>,
P: Into<Vector3f>,
{
let lat = self.lattice.expect("cannot set scaled positions for aperiodic structure");
let positions = scaled.into_iter().map(|frac| lat.to_cart(frac));
self.set_positions(positions);
}
pub fn set_scaled_positions_from<T, P>(&mut self, scaled: T)
where
T: IntoIterator<Item = (usize, P)>,
P: Into<Vector3f>,
{
let lat = self.lattice.expect("cannot set scaled positions for aperiodic structure");
for (i, fi) in scaled {
let pi = lat.to_cart(fi);
self.set_position(i, pi);
}
}
#[cfg(feature = "adhoc")]
pub fn supercell(&self, sa: usize, sb: usize, sc: usize) -> Option<Molecule> {
let lat = self.lattice?;
let (sa, sb, sc) = (sa as isize, sb as isize, sc as isize);
let mut atoms = vec![];
for image in lat.replicate(0..sa, 0..sb, 0..sc) {
let mut m = self.clone();
let t = lat.to_cart(image);
m.translate(t);
for (_, atom) in m.atoms() {
atoms.push(atom.clone());
}
}
let mut mol_new = Molecule::from_atoms(atoms);
let mut vabc = lat.vectors();
let size = [sa, sb, sc];
for v in vabc.iter_mut() {
for i in 0..3 {
v[i] *= size[i] as f64;
}
}
mol_new.name = self.name.to_string();
mol_new.lattice = Some(Lattice::new(vabc));
Some(mol_new)
}
}
impl Molecule {
#[cfg(feature = "adhoc")]
pub fn set_lattice_from_bounding_box(&mut self, padding: f64) {
self.recenter();
let [a, b, c] = self.bounding_box(padding);
let center = [a / 2.0, b / 2.0, c / 2.0];
self.translate(center);
let mat = [[a, 0.0, 0.0], [0.0, b, 0.0], [0.0, 0.0, c]];
let lat = Lattice::new(mat);
self.set_lattice(lat);
}
pub fn bounding_box(&self, padding: f64) -> [f64; 3] {
use vecfx::*;
assert!(padding.is_sign_positive(), "invalid scale factor: {padding}");
let xmax = self.positions().map(|[x, _, _]| x).float_max();
let xmin = self.positions().map(|[x, _, _]| x).float_min();
let ymax = self.positions().map(|[_, y, _]| y).float_max();
let ymin = self.positions().map(|[_, y, _]| y).float_min();
let zmax = self.positions().map(|[_, _, z]| z).float_max();
let zmin = self.positions().map(|[_, _, z]| z).float_min();
let a = xmax - xmin + 2.0 * padding;
let b = ymax - ymin + 2.0 * padding;
let c = zmax - zmin + 2.0 * padding;
[a, b, c]
}
}