use serde::{Deserialize, Serialize};
use super::UnivariateEnergy;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct OverlapPenalty {
pub k: f64,
pub maximum_allowed_overlap: f64,
pub epsilon_shoulder: f64,
}
impl Default for OverlapPenalty {
#[inline]
fn default() -> Self {
Self {
k: 10_000.0,
maximum_allowed_overlap: 0.2,
epsilon_shoulder: 100.0,
}
}
}
impl OverlapPenalty {
#[must_use]
#[inline]
pub fn scaled_default(diameter: f64) -> Self {
let mut overlap_penalty = Self::default();
overlap_penalty.maximum_allowed_overlap *= diameter;
overlap_penalty
}
}
impl UnivariateEnergy for OverlapPenalty {
#[inline]
fn energy(&self, r: f64) -> f64 {
match r {
x if x < -self.maximum_allowed_overlap => f64::INFINITY,
x if x < 0.0 => 0.5 * self.k * r.powi(2) + self.epsilon_shoulder,
_ => 0.0,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn shoulder() {
let k = 0.0;
let epsilon_shoulder = 15.0;
let maximum_allowed_overlap = 1.0;
let overlap_penalty = OverlapPenalty {
k,
maximum_allowed_overlap,
epsilon_shoulder,
};
assert_eq!(overlap_penalty.energy(1.0), 0.0);
assert_eq!(overlap_penalty.energy(0.0), 0.0);
assert_eq!(
overlap_penalty.energy(0.0_f64.next_down()),
epsilon_shoulder
);
assert_eq!(overlap_penalty.energy(-0.5), epsilon_shoulder);
}
#[test]
fn core() {
let k = 0.0;
let epsilon_shoulder = 0.0;
let maximum_allowed_overlap = 0.5;
let overlap_penalty = OverlapPenalty {
k,
maximum_allowed_overlap,
epsilon_shoulder,
};
assert_eq!(overlap_penalty.energy(1.0), 0.0);
assert_eq!(overlap_penalty.energy(0.0), 0.0);
assert_eq!(overlap_penalty.energy(0.0_f64.next_down()), 0.0);
assert_eq!(overlap_penalty.energy(-0.5), 0.0);
assert_eq!(
overlap_penalty.energy((-0.5_f64).next_down()),
f64::INFINITY
);
assert_eq!(overlap_penalty.energy(-1.0), f64::INFINITY);
}
#[test]
fn harmonic() {
let k = 6.0;
let epsilon_shoulder = 0.0;
let maximum_allowed_overlap = 10.0;
let overlap_penalty = OverlapPenalty {
k,
maximum_allowed_overlap,
epsilon_shoulder,
};
assert_eq!(overlap_penalty.energy(1.0), 0.0);
assert_eq!(overlap_penalty.energy(0.0), 0.0);
assert_eq!(overlap_penalty.energy(-0.125), 0.5 * k * 0.125_f64.powi(2));
}
}