use cartan_core::Manifold;
use cartan_dec::Operators;
use volterra_core::ActiveNematicParams;
use volterra_dec::{molecular_field_dec, QFieldDec};
#[derive(Debug, Clone)]
pub struct SnapStatsDec {
pub time: f64,
pub mean_s: f64,
pub n_vertices: usize,
}
fn beris_edwards_rhs_dec<M: Manifold>(
q: &QFieldDec,
params: &ActiveNematicParams,
ops: &Operators<M, 3, 2>,
curvature_correction: Option<&dyn Fn(usize) -> [[f64; 3]; 3]>,
) -> QFieldDec {
let h = molecular_field_dec(q, params, ops, curvature_correction);
h.scale(params.gamma_r)
}
fn rk4_step<M: Manifold>(
q: &QFieldDec,
dt: f64,
params: &ActiveNematicParams,
ops: &Operators<M, 3, 2>,
curvature_correction: Option<&dyn Fn(usize) -> [[f64; 3]; 3]>,
) -> QFieldDec {
let k1 = beris_edwards_rhs_dec(q, params, ops, curvature_correction);
let q2 = q.add(&k1.scale(0.5 * dt));
let k2 = beris_edwards_rhs_dec(&q2, params, ops, curvature_correction);
let q3 = q.add(&k2.scale(0.5 * dt));
let k3 = beris_edwards_rhs_dec(&q3, params, ops, curvature_correction);
let q4 = q.add(&k3.scale(dt));
let k4 = beris_edwards_rhs_dec(&q4, params, ops, curvature_correction);
let rhs = k1
.add(&k2.scale(2.0))
.add(&k3.scale(2.0))
.add(&k4);
q.add(&rhs.scale(dt / 6.0))
}
pub fn run_dry_active_nematic_dec<M: Manifold>(
q_init: &QFieldDec,
params: &ActiveNematicParams,
ops: &Operators<M, 3, 2>,
curvature_correction: Option<&dyn Fn(usize) -> [[f64; 3]; 3]>,
n_steps: usize,
snap_every: usize,
) -> (QFieldDec, Vec<SnapStatsDec>) {
let mut q = q_init.clone();
let mut stats = Vec::new();
for step in 0..=n_steps {
if step % snap_every == 0 {
stats.push(SnapStatsDec {
time: step as f64 * params.dt,
mean_s: q.mean_order_param(),
n_vertices: q.n_vertices,
});
}
if step < n_steps {
q = rk4_step(&q, params.dt, params, ops, curvature_correction);
}
}
(q, stats)
}