#![allow(non_upper_case_globals)]
#![allow(unused)]
use std::f64::consts::TAU;
use lin_alg::f64::{Quaternion, Vec3};
pub const LEN_CP_N: f64 = 1.335; pub const LEN_N_CALPHA: f64 = 1.46;
pub const LEN_CALPHA_CP: f64 = 1.409;
pub const LEN_CP_O: f64 = 1.229; pub const LEN_CALPHA_H: f64 = 1.080; pub const LEN_N_H: f64 = 1.010; pub const LEN_C_H: f64 = 1.09; pub const LEN_O_H: f64 = 0.9572; pub const LEN_S_H: f64 = 1.336;
pub const θ_HOH_ANGLE: f64 = 1.82421813;
pub const TETRA_ANGLE: f64 = 1.9106332;
pub const BOND_ANGLE_N_CALPHA_CP: f64 = 122.7 * TAU / 360.;
pub const BOND_ANGLE_CALPHA_CP_R: f64 = 110.6 * TAU / 360.;
pub const BOND_ANGLE_CALPHA_CP_N: f64 = 111.0 * TAU / 360.;
pub const BOND_ANGLE_CALPHA_CP_H: f64 = 109.5 * TAU / 360.; pub const BOND_ANGLE_CALPHA_N_R: f64 = 110.6 * TAU / 360.;
pub const BOND_ANGLE_CP_N_CALPHA: f64 = 117.2 * TAU / 360.;
pub const BOND_ANGLE_CP_N_O: f64 = 122.7 * TAU / 360.;
pub const BOND_ANGLE_CP_CALPHA_O: f64 = 120.1 * TAU / 360.;
pub const ANCHOR_BOND_VEC: Vec3 = Vec3 {
x: 1.,
y: 0.,
z: 0.,
};
pub const CALPHA_CP_BOND: Vec3 = ANCHOR_BOND_VEC;
pub static mut CALPHA_N_BOND: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub static mut CALPHA_R_BOND: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub static mut CALPHA_H_BOND: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub const CP_N_BOND: Vec3 = ANCHOR_BOND_VEC;
pub static mut CP_CALPHA_BOND: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub static mut CP_O_BOND: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub const N_CALPHA_BOND: Vec3 = ANCHOR_BOND_VEC;
pub static mut N_CP_BOND: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub static mut N_H_BOND: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub const O_CP_BOND: Vec3 = ANCHOR_BOND_VEC;
pub const H_CALPHA_BOND: Vec3 = ANCHOR_BOND_VEC;
pub const H_N_BOND: Vec3 = ANCHOR_BOND_VEC;
pub const TETRA_A: Vec3 = ANCHOR_BOND_VEC;
pub static mut TETRA_B: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub static mut TETRA_C: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub static mut TETRA_D: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub const PLANAR3_A: Vec3 = ANCHOR_BOND_VEC;
pub static mut PLANAR3_B: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub static mut PLANAR3_C: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub const RING_BOND_IN: Vec3 = Vec3 {
x: 1.,
y: 0.,
z: 0.,
};
pub const WATER_BOND_H_A: Vec3 = ANCHOR_BOND_VEC;
pub static mut WATER_BOND_H_B: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub static mut WATER_BOND_M: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub static mut RING5_BOND_OUT: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub static mut RING5_BOND_OUT_B: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub static mut RING6_BOND_OUT: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub static mut RING6_BOND_OUT_B: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub const H_BOND_IN: Vec3 = Vec3 {
x: 1.,
y: 0.,
z: 0.,
};
pub const H_BOND_OUT: Vec3 = Vec3 {
x: 1.,
y: 0.,
z: 0.,
};
pub const O_BOND_IN: Vec3 = Vec3 {
x: 1.,
y: 0.,
z: 0.,
};
pub static mut O_BOND_OUT: Vec3 = Vec3 {
x: 0.,
y: 0.,
z: 0.,
};
pub struct Tetrahedral {
pub bond_a: Vec3,
pub bond_b: Vec3,
pub bond_c: Vec3,
pub bond_d: Vec3,
}
impl Default for Tetrahedral {
fn default() -> Self {
let z = Vec3::new(0., 0., 1.);
let r1 = z;
let r2 = Quaternion::from_axis_angle(ANCHOR_BOND_VEC, TAU / 3.).rotate_vec(z);
let r3 = Quaternion::from_axis_angle(ANCHOR_BOND_VEC, TAU * 2. / 3.).rotate_vec(z);
Self {
bond_a: ANCHOR_BOND_VEC,
bond_b: Quaternion::from_axis_angle(r1, TETRA_ANGLE).rotate_vec(ANCHOR_BOND_VEC),
bond_c: Quaternion::from_axis_angle(r2, TETRA_ANGLE).rotate_vec(ANCHOR_BOND_VEC),
bond_d: Quaternion::from_axis_angle(r3, TETRA_ANGLE).rotate_vec(ANCHOR_BOND_VEC),
}
}
}
pub struct Planar3 {
pub bond_a: Vec3,
pub bond_b: Vec3,
pub bond_c: Vec3,
}
impl Default for Planar3 {
fn default() -> Self {
let z = Vec3::new(0., 0., 1.);
Self {
bond_a: ANCHOR_BOND_VEC,
bond_b: Quaternion::from_axis_angle(z, TAU / 3.).rotate_vec(ANCHOR_BOND_VEC),
bond_c: Quaternion::from_axis_angle(z, TAU * 2. / 3.).rotate_vec(ANCHOR_BOND_VEC),
}
}
}
fn rotate_vec(start: Vec3, angle: f64, rot_plane_norm: Vec3) -> Vec3 {
let rotation = Quaternion::from_axis_angle(rot_plane_norm, angle);
rotation.rotate_vec(start)
}
fn find_third_bond_vec(
bond1: Vec3,
bond2: Vec3,
angle_1_3: f64,
angle_2_3: f64,
bond2_rot_plane_norm: Vec3,
) -> Vec3 {
const EPS: f64 = 0.01;
const N_PLANES: usize = 120;
let rot_plane_incr = TAU / N_PLANES as f64;
let mut result = Vec3::new_zero();
for i in 0..N_PLANES {
let iterated_rot_plane_norm =
rotate_vec(bond2_rot_plane_norm, rot_plane_incr * i as f64, bond1);
result = rotate_vec(bond1, angle_1_3, iterated_rot_plane_norm);
let angle_2_3_meas = (bond2.dot(result)).acos();
if (angle_2_3_meas - angle_2_3).abs() < EPS {
break;
}
}
result
}
pub fn init_local_bond_vecs() {
let rot_plane_norm = Vec3::new(0., 0., 1.);
unsafe {
let tetra = Tetrahedral::default();
TETRA_B = tetra.bond_b;
TETRA_C = tetra.bond_c;
TETRA_D = tetra.bond_d;
let planar3 = Planar3::default();
PLANAR3_B = planar3.bond_b;
PLANAR3_C = planar3.bond_c;
let z = Vec3::new(0., 0., 1.);
let bond_angle_ring5 = TAU / 2. - TAU / 5.;
let bond_angle_ring6 = TAU / 2. - TAU / 6.;
let bond_angle_ho = TAU * 0.3;
let bond_angle_water = θ_HOH_ANGLE;
RING5_BOND_OUT =
Quaternion::from_axis_angle(z, bond_angle_ring5).rotate_vec(ANCHOR_BOND_VEC);
RING6_BOND_OUT =
Quaternion::from_axis_angle(z, bond_angle_ring6).rotate_vec(ANCHOR_BOND_VEC);
RING5_BOND_OUT_B =
Quaternion::from_axis_angle(z, -bond_angle_ring5).rotate_vec(ANCHOR_BOND_VEC);
RING6_BOND_OUT_B =
Quaternion::from_axis_angle(z, -bond_angle_ring6).rotate_vec(ANCHOR_BOND_VEC);
O_BOND_OUT = Quaternion::from_axis_angle(z, bond_angle_ho).rotate_vec(ANCHOR_BOND_VEC);
WATER_BOND_H_B =
Quaternion::from_axis_angle(z, bond_angle_water).rotate_vec(ANCHOR_BOND_VEC);
WATER_BOND_M =
Quaternion::from_axis_angle(z, bond_angle_water / 2.).rotate_vec(ANCHOR_BOND_VEC);
CALPHA_N_BOND = rotate_vec(CALPHA_CP_BOND, BOND_ANGLE_CALPHA_CP_N, rot_plane_norm);
CP_CALPHA_BOND = rotate_vec(CP_N_BOND, BOND_ANGLE_CP_N_CALPHA, rot_plane_norm);
N_CP_BOND = rotate_vec(N_CALPHA_BOND, BOND_ANGLE_N_CALPHA_CP, rot_plane_norm);
N_H_BOND = rotate_vec(N_CALPHA_BOND, TAU * 2. / 3., rot_plane_norm);
CALPHA_R_BOND = find_third_bond_vec(
CALPHA_CP_BOND,
CALPHA_N_BOND,
BOND_ANGLE_CALPHA_CP_R,
BOND_ANGLE_CALPHA_N_R,
rot_plane_norm,
);
CALPHA_H_BOND = tetra.bond_d;
CP_O_BOND = find_third_bond_vec(
CP_N_BOND,
CP_CALPHA_BOND,
BOND_ANGLE_CP_N_O,
BOND_ANGLE_CP_CALPHA_O,
rot_plane_norm,
);
}
}
pub fn find_planar_posit(central: Vec3, posit_0: Vec3, posit_1: Vec3) -> Vec3 {
let r = (posit_0 - central).magnitude();
let u0 = (posit_0 - central).to_normalized();
let u1 = (posit_1 - central).to_normalized();
let mut dir = -(u0 + u1);
if dir.magnitude_squared() < 1e-12 {
let a = if u0.x.abs() < 0.9 {
Vec3::new(1.0, 0.0, 0.0)
} else {
Vec3::new(0.0, 1.0, 0.0)
};
dir = (a - u0 * a.dot(u0)).to_normalized();
} else {
dir = dir.to_normalized();
}
central + dir * r
}
pub fn find_tetra_posits(central: Vec3, posit_0: Vec3, posit_1: Vec3) -> (Vec3, Vec3) {
let r = (posit_0 - central).magnitude();
let u0 = (posit_0 - central).to_normalized();
let mut u1p = posit_1 - central;
if u1p.magnitude_squared() < 1e-24 {
let a = if u0.x.abs() < 0.9 {
Vec3::new(1.0, 0.0, 0.0)
} else {
Vec3::new(0.0, 1.0, 0.0)
};
u1p = (a - u0 * a.dot(u0)).to_normalized();
} else {
u1p = (u1p - u0 * u1p.dot(u0)).to_normalized();
}
let u2p = u0.cross(u1p);
let s = (1.0f64 / 3.0).sqrt();
let v0 = Vec3::new(s, s, s);
let v1 = Vec3::new(s, -s, -s);
let v2 = Vec3::new(-s, s, -s);
let v3 = Vec3::new(-s, -s, s);
let asrc = v0.to_normalized();
let bsrc = (v1 - asrc * v1.dot(asrc)).to_normalized();
let csrc = asrc.cross(bsrc);
let adst = u0;
let bdst = u1p;
let cdst = u2p;
let m = |v: Vec3| -> Vec3 {
let x = v.dot(asrc);
let y = v.dot(bsrc);
let z = v.dot(csrc);
adst * x + bdst * y + cdst * z
};
let u2 = m(v2).to_normalized();
let u3 = m(v3).to_normalized();
(central + u2 * r, central + u3 * r)
}
pub fn find_tetra_posit_final(central: Vec3, sat_0: Vec3, sat_1: Vec3, sat_2: Vec3) -> Vec3 {
let r = (sat_0 - central).magnitude();
let u0 = (sat_0 - central).to_normalized();
let mut u1p = sat_1 - central;
if u1p.magnitude_squared() < 1e-24 {
let a = if u0.x.abs() < 0.9 {
Vec3::new(1.0, 0.0, 0.0)
} else {
Vec3::new(0.0, 1.0, 0.0)
};
u1p = (a - u0 * a.dot(u0)).to_normalized();
} else {
u1p = (u1p - u0 * u1p.dot(u0)).to_normalized();
}
let u2p = u0.cross(u1p);
let s = (1.0f64 / 3.0).sqrt();
let v0 = Vec3::new(s, s, s);
let v1 = Vec3::new(s, -s, -s);
let v2 = Vec3::new(-s, s, -s);
let v3 = Vec3::new(-s, -s, s);
let asrc = v0.to_normalized();
let bsrc = (v1 - asrc * v1.dot(asrc)).to_normalized();
let csrc = asrc.cross(bsrc);
let adst = u0;
let bdst = u1p;
let cdst = u2p;
let m = |v: Vec3| -> Vec3 {
let x = v.dot(asrc);
let y = v.dot(bsrc);
let z = v.dot(csrc);
adst * x + bdst * y + cdst * z
};
let cand2 = m(v2).to_normalized();
let cand3 = m(v3).to_normalized();
let dir2 = sat_2 - central;
if dir2.magnitude_squared() < 1e-24 {
return central + cand2 * r;
}
let u_given = dir2.to_normalized();
let choose_cand3 = u_given.dot(cand2) > u_given.dot(cand3);
let u_missing = if choose_cand3 { cand3 } else { cand2 };
central + u_missing * r
}