Skip to content

Commit 919d177

Browse files
committed
refactor vertex iteration
1 parent 83cb315 commit 919d177

File tree

2 files changed

+44
-36
lines changed

2 files changed

+44
-36
lines changed

src/icoscan.rs

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,34 @@ use std::{f64::consts::PI, path::PathBuf};
2727

2828
pub type Vector3 = nalgebra::Vector3<f64>;
2929
pub type UnitQuaternion = nalgebra::UnitQuaternion<f64>;
30+
use nalgebra::UnitVector3;
31+
32+
/// Orient two reference structures to given 6D point and return the two structures
33+
///
34+
/// Structure A is kept fixed at origin while structure B is rotated and translated
35+
/// to the given 6D point (r, omega, 2 x vertex positions). The given reference structures
36+
/// are assumed to be centered at the origin.
37+
pub fn orient_structures(
38+
r: f64,
39+
omega: f64,
40+
vertex_i: Vector3,
41+
vertex_j: Vector3,
42+
ref_a: &Structure,
43+
ref_b: &Structure,
44+
) -> (Structure, Structure) {
45+
let r_vec = Vector3::new(0.0, 0.0, r);
46+
// Z axis cannot be *exactly* parallel to r_vec; see nalgebra::rotation_between
47+
let zaxis = UnitVector3::new_normalize(Vector3::new(0.0005, 0.0005, 1.0));
48+
let to_neg_zaxis = |p| UnitQuaternion::rotation_between(p, &-zaxis).unwrap();
49+
let around_z = |angle| UnitQuaternion::from_axis_angle(&zaxis, angle);
50+
let q1 = to_neg_zaxis(&vertex_j);
51+
let q2 = around_z(omega);
52+
let q3 = UnitQuaternion::rotation_between(&zaxis, &vertex_i).unwrap();
53+
let mut mol_b = ref_b.clone(); // initially at origin
54+
mol_b.transform(|pos| (q1 * q2).transform_vector(&pos));
55+
mol_b.transform(|pos| q3.transform_vector(&(pos + r_vec)));
56+
(ref_a.clone(), mol_b)
57+
}
3058

3159
#[allow(clippy::too_many_arguments)]
3260
pub fn do_icoscan(
@@ -58,44 +86,20 @@ pub fn do_icoscan(
5886
table.get_heap_size() as f64 / 1e6
5987
);
6088

61-
use nalgebra::UnitVector3;
62-
63-
// Rotation operations via unit quaternions
64-
let zaxis = UnitVector3::new_normalize(Vector3::new(0.0005, 0.0005, 1.0));
65-
let to_neg_zaxis = |p| UnitQuaternion::rotation_between(p, &-zaxis).unwrap();
66-
let around_z = |angle| UnitQuaternion::from_axis_angle(&zaxis, angle);
67-
6889
// Calculate energy of all two-body poses for given mass center separation and dihedral angle
90+
// by looping over remaining 4D angular space. Energies are stored on each vertex of the deepest level
91+
// icospheres.
6992
let calc_energy = |r: f64, omega: f64| {
70-
let r_vec = Vector3::new(0.0, 0.0, r);
71-
let a = table
72-
.get(r)
73-
.expect("invalid r value")
74-
.get(omega)
75-
.expect("invalid omega value");
76-
77-
a.flat_iter().for_each(|(vertex_a, vertex_b)| {
78-
let q1 = to_neg_zaxis(&vertex_b.pos);
79-
let q2 = around_z(omega);
80-
let q3 = UnitQuaternion::rotation_between(&zaxis, &vertex_a.pos).unwrap();
81-
let mut mol_b = ref_b.clone(); // initially at origin
82-
mol_b.transform(|pos| (q1 * q2).transform_vector(&pos));
83-
mol_b.transform(|pos| q3.transform_vector(&(pos + r_vec)));
84-
let energy = pair_matrix.sum_energy(&ref_a, &mol_b);
85-
vertex_b.data.set(energy).unwrap();
86-
});
87-
// for vertex_a in a.vertices.iter() {
88-
// for vertex_b in vertex_a.data.get().unwrap().vertices.iter() {
89-
// let q1 = to_neg_zaxis(&vertex_b.pos);
90-
// let q2 = around_z(omega);
91-
// let q3 = UnitQuaternion::rotation_between(&zaxis, &vertex_a.pos).unwrap();
92-
// let mut mol_b = ref_b.clone(); // initially at origin
93-
// mol_b.transform(|pos| (q1 * q2).transform_vector(&pos));
94-
// mol_b.transform(|pos| q3.transform_vector(&(pos + r_vec)));
95-
// let energy = pair_matrix.sum_energy(&ref_a, &mol_b);
96-
// vertex_b.data.set(energy).unwrap();
97-
// }
98-
// }
93+
table
94+
.get_icospheres(r, omega) // remaining 4D
95+
.expect("invalid (r, omega) value")
96+
.flat_iter()
97+
.for_each(|(vertex_a, vertex_b)| {
98+
let (oriented_a, oriented_b) =
99+
orient_structures(r, omega, vertex_a.pos, vertex_b.pos, &ref_a, &ref_b);
100+
let energy = pair_matrix.sum_energy(&oriented_a, &oriented_b);
101+
vertex_b.data.set(energy).unwrap();
102+
});
99103
};
100104

101105
// Pair all mass center separations (r) and dihedral angles (omega)

src/icotable.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ impl Table6D {
5959
let table3 = PaddedTable::<IcoTableOfSpheres>::new(0.0, 2.0 * PI, angle_resolution, table2); // 𝜔
6060
Ok(Self::new(r_min, r_max, dr, table3)) // R
6161
}
62+
/// Get remaining 4D space (icotables) at (r, omega)
63+
pub fn get_icospheres(&self, r: f64, omega: f64) -> Result<&IcoTableOfSpheres> {
64+
self.get(r)?.get(omega)
65+
}
6266
}
6367

6468
/// Represents indices of a face

0 commit comments

Comments
 (0)