diff --git a/src/context.rs b/src/context.rs index 94252bd..8fdf89c 100644 --- a/src/context.rs +++ b/src/context.rs @@ -10,11 +10,11 @@ pub struct Context { pub platform: Box, } impl Context { - pub fn set_positions(&mut self, positions: Vec>) { + pub fn set_positions(&mut self, _positions: Vec>) { unimplemented!() } - pub fn get_state(&self, state_type: StateType) -> State { + pub fn get_state(&self, _state_type: StateType) -> State { unimplemented!() } } diff --git a/src/force/harmonic_angle_force.rs b/src/force/harmonic_angle_force.rs index f27bf74..1eeb650 100644 --- a/src/force/harmonic_angle_force.rs +++ b/src/force/harmonic_angle_force.rs @@ -3,20 +3,177 @@ use crate::force::Force; #[derive(Debug, Clone, PartialEq)] pub struct HarmonicAngleForce {} -impl Force for HarmonicAngleForce { - fn add_bond(&mut self, particle1: usize, particle2: usize, length: f64, k: f64) { +impl HarmonicAngleForce { + pub fn new() -> Self { + Self {} + } + + pub fn add_angle( + &mut self, + _particle1: usize, + _particle2: usize, + _particle3: usize, + _angle: f64, + _k: f64, + ) { unimplemented!() } - fn set_bond_parameters(&mut self, particle1: usize, particle2: usize, length: f64, k: f64) { - unimplemented!() - } - - fn update_parameters_in_context(&mut self, context: &mut Context) { - unimplemented!() - } - - fn set_uses_periodic_boundary_conditions(&mut self, status: bool) { + pub fn set_angle_parameters( + &mut self, + _angle_id: usize, + _particle1: usize, + _particle2: usize, + _particle3: usize, + _angle: f64, + _k: f64, + ) { + unimplemented!() + } +} + +impl Force for HarmonicAngleForce { + fn update_parameters_in_context(&mut self, _context: &mut Context) { + unimplemented!() + } + + fn set_periodic_boundary_conditions(&mut self, _status: bool) { + unimplemented!() + } + + fn use_periodic_boundary_conditions(&self) -> bool { + unimplemented!() + } +} + +impl Default for HarmonicAngleForce { + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +mod tests { + use super::HarmonicAngleForce; + use crate::context::Context; + use crate::force::Force; + use crate::integrator::VerletIntegrator; + use crate::platform::CPU; + use crate::state::StateType; + use crate::system::System; + use approx::assert_relative_eq; + use nalgebra::Vector3; + use std::f64::consts::PI; + + #[ignore] + #[test] + fn test_harmonic_angle_force() { + let mut system = System::new(); + system.add_particle(1.0); + system.add_particle(1.0); + system.add_particle(1.0); + system.add_particle(1.0); + let integrator = VerletIntegrator { dt: 0.01 }; + + let mut forcefield = HarmonicAngleForce::new(); + forcefield.add_angle(0, 1, 2, PI / 3.0, 1.1); + forcefield.add_angle(1, 2, 3, PI / 2.0, 1.2); + + system.add_force(Box::new(forcefield.clone())); + assert_eq!(forcefield.use_periodic_boundary_conditions(), false); + assert_eq!(system.use_periodic_boundary_conditions(), false); + + let mut context = Context { + system, + integrator: Box::new(integrator), + platform: Box::new(CPU), + }; + + let mut positions = vec![Vector3::zeros(); 4]; + positions[0] = Vector3::new(0.0, 2.0, 0.0); + positions[1] = Vector3::new(0.0, 0.0, 0.0); + positions[2] = Vector3::new(1.0, 0.0, 0.0); + positions[3] = Vector3::new(2.0, 1.0, 0.0); + + context.set_positions(positions); + let state = context.get_state(StateType::Either); + let forces = state.get_forces(); + let torque1 = 1.1 * PI / 6.0; + let torque2 = 1.2 * PI / 4.0; + assert_relative_eq!(forces[0], Vector3::new(torque1, 0.0, 0.0)); + assert_relative_eq!(forces[3], Vector3::new(-0.5 * torque2, 0.5 * torque2, 0.0)); + assert_relative_eq!(forces[1], -forces[0] - forces[2]); + assert_relative_eq!( + state.get_potential_energy(), + 0.5 * 1.1 * PI / 6.0 * PI / 6.0 + 0.5 * 1.2 * PI / 4.0 * PI / 4.0 + ); + + forcefield.set_angle_parameters(0, 0, 1, 2, PI / 3.1, 1.3); + forcefield.set_angle_parameters(1, 1, 2, 3, PI / 2.1, 1.4); + forcefield.update_parameters_in_context(&mut context); + + let state = context.get_state(StateType::Either); + let forces = state.get_forces(); + let dtheta1 = (PI / 2.0) - (PI / 3.1); + let dtheta2 = (3.0 * PI / 4.0) - (PI / 2.1); + let torque1 = 1.3 * dtheta1; + let torque2 = 1.4 * dtheta2; + assert_relative_eq!(forces[0], Vector3::new(torque1, 0.0, 0.0)); + assert_relative_eq!(forces[3], Vector3::new(-0.5 * torque2, 0.5 * torque2, 0.0)); + assert_relative_eq!(forces[1], -forces[0] - forces[2]); + assert_relative_eq!( + state.get_potential_energy(), + 0.5 * 1.3 * dtheta1 * dtheta1 + 0.5 * 1.4 * dtheta2 * dtheta2 + ); + } + + #[ignore] + #[test] + fn test_harmonic_angle_force_with_periodic_boundary_conditions() { + let mut system = System {}; + system.add_particle(1.0); + system.add_particle(1.0); + system.add_particle(1.0); + system.set_default_periodic_box_vectors( + Vector3::new(3.0, 0.0, 0.0), + Vector3::new(0.0, 1.5, 0.0), + Vector3::new(0.0, 0.0, 3.0), + ); + + let integrator = VerletIntegrator { dt: 0.01 }; + let mut forcefield = HarmonicAngleForce {}; + forcefield.add_angle(0, 1, 2, PI / 3.0, 1.1); + forcefield.set_periodic_boundary_conditions(true); + + system.add_force(Box::new(forcefield)); + + let mut context = Context { + system, + integrator: Box::new(integrator), + platform: Box::new(CPU), + }; + + let mut positions = vec![Vector3::zeros(); 3]; + positions[0] = Vector3::new(0.0, 1.0, 0.0); + positions[1] = Vector3::new(0.0, 0.0, 0.0); + positions[2] = Vector3::new(1.0, 0.0, 0.0); + context.set_positions(positions); + + let state = context.get_state(StateType::Either); + let forces = state.get_forces(); + + let torque = 1.1 * PI / 6.0; + assert_relative_eq!(forces[0], Vector3::new(2.0 * torque, 0.0, 0.0)); + assert_relative_eq!(forces[2], Vector3::new(0.0, -torque, 0.0)); + + let energy = state.get_potential_energy(); + assert_relative_eq!(energy, 0.5 * 1.1 * (PI / 6.0) * (PI / 6.0)); + } + + #[ignore] + #[test] + fn test_harmonic_angle_force_parallel_computation() { + // TODO: Rust-OpenMM unimplemented!() } } diff --git a/src/force/harmonic_bond_force.rs b/src/force/harmonic_bond_force.rs index 82116a1..db3a364 100644 --- a/src/force/harmonic_bond_force.rs +++ b/src/force/harmonic_bond_force.rs @@ -3,21 +3,42 @@ use crate::force::Force; #[derive(Debug, Clone, PartialEq)] pub struct HarmonicBondForce {} +impl HarmonicBondForce { + pub fn new() -> Self { + Self {} + } + + pub fn add_bond(&mut self, _particle1: usize, _particle2: usize, _length: f64, _k: f64) { + unimplemented!() + } + + pub fn set_bond_parameters( + &mut self, + _particle1: usize, + _particle2: usize, + _length: f64, + _k: f64, + ) { + unimplemented!() + } +} impl Force for HarmonicBondForce { - fn add_bond(&mut self, particle1: usize, particle2: usize, length: f64, k: f64) { + fn update_parameters_in_context(&mut self, _context: &mut Context) { unimplemented!() } - fn set_bond_parameters(&mut self, particle1: usize, particle2: usize, length: f64, k: f64) { + fn set_periodic_boundary_conditions(&mut self, _status: bool) { unimplemented!() } - fn update_parameters_in_context(&mut self, context: &mut Context) { + fn use_periodic_boundary_conditions(&self) -> bool { unimplemented!() } +} - fn set_uses_periodic_boundary_conditions(&mut self, status: bool) { - unimplemented!() +impl Default for HarmonicBondForce { + fn default() -> Self { + Self::new() } } @@ -28,11 +49,12 @@ mod test { use crate::force::Force; use crate::integrator::VerletIntegrator; use crate::platform::CPU; - use crate::state::{State, StateType}; + use crate::state::StateType; use crate::system::System; use approx::assert_relative_eq; use nalgebra::Vector3; + #[ignore] #[test] fn test_harmonic_bond_force() { let mut system = System {}; @@ -58,7 +80,7 @@ mod test { positions[2] = Vector3::new(1.0, 0.0, 0.0); context.set_positions(positions); - let state = context.get_state(StateType::Both); + let state = context.get_state(StateType::Either); let forces = state.get_forces(); assert_relative_eq!(forces[0], Vector3::new(0.0, -0.8 * 0.5, 0.0)); assert_relative_eq!(forces[2], Vector3::new(0.7 * 0.2, 0.0, 0.0)); @@ -81,6 +103,7 @@ mod test { assert_relative_eq!(energy, 0.5 * 0.9 * 0.4 * 0.4 + 0.5 * 0.8 * 0.3 * 0.3); } + #[ignore] #[test] fn test_harmonic_bond_force_with_periodic_boundary_conditions() { let mut system = System {}; @@ -95,7 +118,7 @@ mod test { let integrator = VerletIntegrator { dt: 0.01 }; let mut forcefield = HarmonicBondForce {}; forcefield.add_bond(0, 1, 1.2, 0.8); - forcefield.set_uses_periodic_boundary_conditions(true); + forcefield.set_periodic_boundary_conditions(true); system.add_force(Box::new(forcefield)); @@ -119,6 +142,7 @@ mod test { assert_relative_eq!(energy, 0.5 * 0.8 * 0.2 * 0.2); } + #[ignore] #[test] fn test_harmonic_bond_force_parallel_computation() { // TODO: Rust-OpenMM diff --git a/src/force/mod.rs b/src/force/mod.rs index 9121a1f..be482e4 100644 --- a/src/force/mod.rs +++ b/src/force/mod.rs @@ -3,10 +3,9 @@ use std::fmt::Debug; use crate::context::Context; pub trait Force: Debug { - fn add_bond(&mut self, particle1: usize, particle2: usize, length: f64, k: f64); - fn set_bond_parameters(&mut self, particle1: usize, particle2: usize, length: f64, k: f64); fn update_parameters_in_context(&mut self, context: &mut Context); - fn set_uses_periodic_boundary_conditions(&mut self, status: bool); + fn set_periodic_boundary_conditions(&mut self, status: bool); + fn use_periodic_boundary_conditions(&self) -> bool; } pub mod harmonic_angle_force; diff --git a/src/state.rs b/src/state.rs index 1fc8cca..daa4d30 100644 --- a/src/state.rs +++ b/src/state.rs @@ -2,22 +2,23 @@ use nalgebra::Vector3; pub enum StateType { Both, + Either, Forces, Energy, } pub struct State { pub state_type: StateType, - pub forces: Vec>, - pub energy: f32, + pub forces: Vec>, + pub energy: f64, } impl State { - pub fn get_forces(&self) -> &Vec> { + pub fn get_forces(&self) -> &Vec> { &self.forces } - pub fn get_potential_energy(&self) -> f32 { + pub fn get_potential_energy(&self) -> f64 { self.energy } } diff --git a/src/system.rs b/src/system.rs index 19448b9..01116fc 100644 --- a/src/system.rs +++ b/src/system.rs @@ -3,6 +3,10 @@ use crate::virtual_site::VirtualSite; use nalgebra::Vector3; pub struct System {} impl System { + pub fn new() -> Self { + Self {} + } + pub fn add_particle(&mut self, _mass: f32) { // Todo: Rust-OpenMM unimplemented!() @@ -92,7 +96,19 @@ impl System { // Todo: Rust-OpenMM unimplemented!() } + + pub fn use_periodic_boundary_conditions(&self) -> bool { + // Todo: Rust-OpenMM + unimplemented!() + } } + +impl Default for System { + fn default() -> Self { + Self::new() + } +} + #[cfg(test)] mod test { use crate::force::{HarmonicAngleForce, HarmonicBondForce};