1use crate::common::*;
3
4use gchemol::Lattice;
5use vecfx::*;
6fn reorder_atoms_by_zfrac_coords(mol: &Molecule) -> Option<Vec<usize>> {
10 let mut zfrac_coords_numbers: Vec<_> = mol.get_scaled_positions()?.map(|[_, _, fz]| fz).zip(mol.numbers()).collect();
11 zfrac_coords_numbers.sort_by_cached_key(|k| k.0.as_ordered_float());
12 zfrac_coords_numbers.into_iter().map(|(_, i)| i).collect_vec().into()
13}
14
15fn contains_atom(mol: &Molecule, i: usize) -> bool {
17 mol.atoms().find(|(_, a)| a.label() == format!("{i}")).is_some()
18}
19
20#[track_caller]
21fn process_bottom_layer(layers: &mut Vec<Molecule>, bottom_atom: usize) -> Vec<usize> {
23 let i = layers
24 .iter()
25 .position(|mol| contains_atom(mol, bottom_atom))
26 .expect("no layer for bottom atom");
27 let mol = layers.remove(i);
28 mol.atoms().map(|(_, a)| a.label().parse().unwrap()).collect()
29}
30#[track_caller]
34pub fn fragment_atoms_by_layer(mol: &Molecule) -> Result<impl Iterator<Item = Vec<usize>>> {
36 let mut mol = mol.clone();
37 ensure!(mol.is_periodic(), "only works for periodic structure!");
38
39 let reorder_atoms = reorder_atoms_by_zfrac_coords(&mol).unwrap();
41
42 let numbers = mol.numbers().collect_vec();
45 for i in numbers {
46 let a = mol.get_atom_unchecked_mut(i);
47 a.set_label(format!("{i}"));
48 }
49
50 let frac_coords: Vec<_> = mol.get_scaled_positions().unwrap().collect();
52 mol.get_lattice_mut().map(|lat| lat.scale_by_c(2.0));
53 mol.set_scaled_positions(frac_coords);
54 std::env::set_var("GCHEMOL_REBOND_IGNORE_PBC", format!("true"));
56 mol.rebond();
57 let mut layers = mol.fragmented().collect_vec();
58
59 let mut remained = reorder_atoms.clone();
60 let iter = std::iter::from_fn(move || {
61 if remained.is_empty() {
63 None
64 } else {
65 let bottom_atom = remained[0];
66 let bottom_atoms = process_bottom_layer(&mut layers, bottom_atom);
67 remained.retain(|sn| !bottom_atoms.contains(sn));
69 Some(bottom_atoms)
70 }
71 });
72
73 Ok(iter)
74}
75#[test]
79fn test_atom_layer() -> Result<()> {
80 let f = "tests/files/R.xsd";
81 let m = Molecule::from_file(f)?;
82 let layers = fragment_atoms_by_layer(&m)?.collect_vec();
83
84 assert!(layers.len() > 4);
85 assert_eq!(layers[0].len(), 24);
86 assert_eq!(layers[1].len(), 27);
87 assert_eq!(layers[2].len(), 24);
88 assert_eq!(layers[3].len(), 12);
89
90 Ok(())
91}
92