use super::{MultipoleField, MultipolePotential};
use crate::{Matrix3, NalgebraVector3, Vector3};
pub trait MultipoleEnergy: MultipolePotential + MultipoleField {
fn self_energy(&self, monopoles: &[f64], dipoles: &[f64]) -> f64 {
let mut sum: f64 = 0.0;
let prefactor = self.self_energy_prefactors();
if let Some(c1) = prefactor.monopole {
sum += c1 * monopoles.iter().map(|z| z * z).sum::<f64>() / self.cutoff();
}
if let Some(c2) = prefactor.dipole {
sum += c2 * dipoles.iter().map(|mu| mu * mu).sum::<f64>() / self.cutoff().powi(3);
}
sum
}
fn ion_ion_energy(&self, charge1: f64, charge2: f64, r: f64) -> f64 {
charge2 * self.ion_potential(charge1, r)
}
fn ion_induced_dipole_energy(&self, charge: f64, alpha: f64, r: impl Into<Vector3>) -> f64 {
let r: NalgebraVector3 = r.into().into();
let field: NalgebraVector3 = self.ion_field(charge, r).into();
field.norm_squared() * (-0.5 * alpha)
}
fn ion_dipole_energy(
&self,
charge: f64,
dipole: impl Into<Vector3>,
r: impl Into<Vector3>,
) -> f64 {
let dipole: NalgebraVector3 = dipole.into().into();
let r: NalgebraVector3 = r.into().into();
charge * self.dipole_potential(dipole, -r) }
fn dipole_dipole_energy(
&self,
dipole1: impl Into<Vector3>,
dipole2: impl Into<Vector3>,
r: impl Into<Vector3>,
) -> f64 {
let dipole1: NalgebraVector3 = dipole1.into().into();
let dipole2: NalgebraVector3 = dipole2.into().into();
let field: NalgebraVector3 = self.dipole_field(dipole2, r).into();
-dipole1.dot(&field)
}
fn ion_quadrupole_energy(
&self,
charge: f64,
quad: impl Into<Matrix3>,
r: impl Into<Vector3>,
) -> f64 {
let r: NalgebraVector3 = r.into().into();
charge * self.quadrupole_potential(quad, -r) }
}