pub mod conservation;
pub mod fem_sph;
pub mod md_continuum_adapter;
#[derive(Debug, Clone, Copy)]
pub struct InterfaceSite {
pub id: u64,
pub position: [f64; 3],
}
#[derive(Debug, Clone, Copy)]
pub struct InterfaceState {
pub id: u64,
pub position: [f64; 3],
pub velocity: [f64; 3],
}
#[derive(Debug, Clone, Copy)]
pub struct InterfaceForce {
pub id: u64,
pub force: [f64; 3],
}
#[derive(Debug, Clone)]
pub struct InterfaceStateVec {
pub states: Vec<InterfaceState>,
}
#[derive(Debug, Clone)]
pub struct InterfaceForceVec {
pub forces: Vec<InterfaceForce>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DomainKind {
Fem,
Sph,
Lbm,
Md,
Custom(String),
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CouplingReport {
pub site_count: usize,
pub momentum_a_to_b: [f64; 3],
pub momentum_b_to_a: [f64; 3],
pub rms_position_error: f64,
}
impl CouplingReport {
pub fn zero() -> Self {
Self {
site_count: 0,
momentum_a_to_b: [0.0; 3],
momentum_b_to_a: [0.0; 3],
rms_position_error: 0.0,
}
}
}
pub trait CouplingDomain: Send + Sync {
fn kind(&self) -> DomainKind;
fn sample_interface(&self, sites: &[InterfaceSite]) -> InterfaceStateVec;
fn apply_interface_force(&mut self, forces: &InterfaceForceVec);
}
pub trait DomainCoupler: Send + Sync {
fn step(
&mut self,
dt: f64,
state_a: &InterfaceStateVec,
state_b: &InterfaceStateVec,
) -> (InterfaceForceVec, InterfaceForceVec, CouplingReport);
}
pub struct CouplingRuntime {
domains: Vec<Box<dyn CouplingDomain>>,
couplers: Vec<Box<dyn DomainCoupler>>,
schedule: Vec<(usize, usize, usize)>,
}
impl CouplingRuntime {
pub fn new() -> Self {
Self {
domains: Vec::new(),
couplers: Vec::new(),
schedule: Vec::new(),
}
}
pub fn add_domain(&mut self, domain: Box<dyn CouplingDomain>) -> usize {
let idx = self.domains.len();
self.domains.push(domain);
idx
}
pub fn add_coupler(&mut self, coupler: Box<dyn DomainCoupler>) -> usize {
let idx = self.couplers.len();
self.couplers.push(coupler);
idx
}
pub fn schedule_pair(&mut self, coupler_idx: usize, domain_a_idx: usize, domain_b_idx: usize) {
debug_assert!(
coupler_idx < self.couplers.len(),
"coupler index out of bounds"
);
debug_assert!(
domain_a_idx < self.domains.len(),
"domain_a index out of bounds"
);
debug_assert!(
domain_b_idx < self.domains.len(),
"domain_b index out of bounds"
);
self.schedule
.push((coupler_idx, domain_a_idx, domain_b_idx));
}
pub fn step(&mut self, dt: f64) -> Vec<CouplingReport> {
let schedule: Vec<(usize, usize, usize)> = self.schedule.clone();
let mut reports = Vec::with_capacity(schedule.len());
for (coupler_idx, idx_a, idx_b) in schedule {
let (state_a, state_b) = if idx_a == idx_b {
let s = self.domains[idx_a].sample_interface(&[]);
(
InterfaceStateVec {
states: s.states.clone(),
},
InterfaceStateVec { states: s.states },
)
} else {
let sa = self.domains[idx_a].sample_interface(&[]);
let sb = self.domains[idx_b].sample_interface(&[]);
(sa, sb)
};
let (forces_a, forces_b, report) =
self.couplers[coupler_idx].step(dt, &state_a, &state_b);
if idx_a == idx_b {
self.domains[idx_a].apply_interface_force(&forces_a);
} else if idx_a < idx_b {
let (left, right) = self.domains.split_at_mut(idx_b);
left[idx_a].apply_interface_force(&forces_a);
right[0].apply_interface_force(&forces_b);
} else {
let (left, right) = self.domains.split_at_mut(idx_a);
left[idx_b].apply_interface_force(&forces_b);
right[0].apply_interface_force(&forces_a);
}
reports.push(report);
}
reports
}
pub fn domain_count(&self) -> usize {
self.domains.len()
}
pub fn coupler_count(&self) -> usize {
self.couplers.len()
}
pub fn schedule_len(&self) -> usize {
self.schedule.len()
}
}
impl Default for CouplingRuntime {
fn default() -> Self {
Self::new()
}
}