moldyn_core/forces/
custom.rs1use crate::{Force, Particle};
5use meval::Expr;
6
7pub struct CustomForce {
8 func: Box<dyn Fn(&Particle, &Particle) -> f64>,
9}
10
11impl Force for CustomForce {
12 fn system_name(&self) -> &str {
13 "custom-potential"
14 }
15
16 fn potential(&self, particle: &Particle, other: &Particle) -> f64 {
17 (self.func)(particle, other)
18 }
19}
20
21impl CustomForce {
22 pub fn new(func: Box<dyn Fn(&Particle, &Particle) -> f64>) -> Self {
23 Self { func }
24 }
25
26 #[allow(dead_code)]
29 #[cfg(test)]
30 pub fn from_expr(expr: &str) -> Self {
31 expr.parse::<Expr>()
32 .expect("failed to parse expression")
33 .try_into()
34 .expect("failed to convert expression to custom force")
35 }
36}
37
38impl TryFrom<Expr> for CustomForce {
39 type Error = meval::Error;
40
41 fn try_from(value: Expr) -> Result<Self, Self::Error> {
42 let func = value.bind2("r", "M")?;
43
44 let wrap = move |p1: &Particle, p2: &Particle| {
45 let distance = Particle::distance(p1, p2);
46 let mul_mass = Particle::mass_product(p1, p2);
47
48 if distance == 0.0 {
49 0.0
50 } else {
51 -func(distance, mul_mass)
52 }
53 };
54
55 Ok(CustomForce::new(Box::new(wrap)))
56 }
57}