use super::MultipoleField;
use crate::{Matrix3, NalgebraVector3, Vector3};
pub trait MultipoleForce: MultipoleField {
fn ion_ion_force(&self, charge1: f64, charge2: f64, r: impl Into<Vector3>) -> Vector3 {
let field: NalgebraVector3 = self.ion_field(charge1, r).into();
(charge2 * field).into()
}
fn ion_dipole_force(
&self,
charge: f64,
dipole: impl Into<Vector3>,
r: impl Into<Vector3>,
) -> Vector3 {
let field: NalgebraVector3 = self.dipole_field(dipole, r).into();
(charge * field).into()
}
fn dipole_dipole_force(
&self,
mu1: impl Into<Vector3>,
mu2: impl Into<Vector3>,
r: impl Into<Vector3>,
) -> Vector3 {
let mu1: NalgebraVector3 = mu1.into().into();
let mu2: NalgebraVector3 = mu2.into().into();
let r: NalgebraVector3 = r.into().into();
let r2 = r.norm_squared();
if r2 >= self.cutoff_squared() {
return NalgebraVector3::zeros().into();
}
let r1 = r.norm();
let rh = r / r1;
let q = r1 / self.cutoff();
let q2 = q * q;
let r4 = r2 * r2;
let mu1_dot_rh = mu1.dot(&rh);
let mu2_dot_rh = mu2.dot(&rh);
let srf0 = self.short_range_f0(q);
let srf1 = self.short_range_f1(q);
let srf2 = self.short_range_f2(q);
let srf3 = self.short_range_f3(q);
let mut force_d = 3.0
* ((5.0 * mu1_dot_rh * mu2_dot_rh - mu1.dot(&mu2)) * rh
- mu2_dot_rh * mu1
- mu1_dot_rh * mu2)
/ r4;
let result = if let Some(kappa) = self.kappa() {
let kr = kappa * r1;
force_d *= srf0 * (1.0 + kr + kr * kr / 3.0) - q * srf1 * (1.0 + 2.0 / 3.0 * kr)
+ q2 / 3.0 * srf2;
let force_i = mu1_dot_rh * mu2_dot_rh * rh / r4
* (srf0 * (1.0 + kr) * kr * kr - q * srf1 * (3.0 * kr + 2.0) * kr
+ srf2 * (1.0 + 3.0 * kr) * q2
- q2 * q * srf3);
(force_d + force_i) * (-kr).exp()
} else {
force_d *= srf0 - q * srf1 + q * q / 3.0 * srf2;
let force_i = mu1_dot_rh * mu2_dot_rh * rh / r4 * (srf2 * (1.0) * q2 - q2 * q * srf3);
force_d + force_i
};
result.into()
}
fn ion_quadrupole_force(
&self,
charge: f64,
quad: impl Into<Matrix3>,
r: impl Into<Vector3>,
) -> Vector3 {
let field: NalgebraVector3 = self.quadrupole_field(quad, r).into();
(charge * field).into()
}
}