use crate::lattice::D2Q9_C;
use crate::moment::{Moments2d, collide_d2q9, moments_d2q9, reconstruct_d2q9};
#[derive(Debug, Clone)]
pub struct Field2d {
pub nx: usize,
pub ny: usize,
pub viscosity: f64,
pub cells: Vec<Moments2d>,
}
impl Field2d {
pub fn new(nx: usize, ny: usize, viscosity: f64) -> Self {
Self {
nx,
ny,
viscosity,
cells: vec![Moments2d::equilibrium(1.0, [0.0, 0.0]); nx * ny],
}
}
pub fn init<F: FnMut(usize, usize) -> (f64, f64, f64)>(
nx: usize,
ny: usize,
viscosity: f64,
mut f: F,
) -> Self {
let mut cells = Vec::with_capacity(nx * ny);
for y in 0..ny {
for x in 0..nx {
let (rho, ux, uy) = f(x, y);
cells.push(Moments2d::equilibrium(rho, [ux, uy]));
}
}
Self {
nx,
ny,
viscosity,
cells,
}
}
#[inline]
fn idx(&self, x: usize, y: usize) -> usize {
y * self.nx + x
}
pub fn at(&self, x: usize, y: usize) -> Moments2d {
self.cells[self.idx(x, y)]
}
pub fn step(&mut self) {
let mut next = Vec::with_capacity(self.cells.len());
for y in 0..self.ny {
for x in 0..self.nx {
let mut f = [0.0f64; 9];
for (i, c) in D2Q9_C.iter().enumerate() {
let sx = (x as isize - c[0] as isize).rem_euclid(self.nx as isize) as usize;
let sy = (y as isize - c[1] as isize).rem_euclid(self.ny as isize) as usize;
f[i] = reconstruct_d2q9(&self.cells[self.idx(sx, sy)])[i];
}
let post = moments_d2q9(&f);
next.push(collide_d2q9(&post, self.viscosity, [0.0, 0.0]));
}
}
self.cells = next;
}
pub fn mass(&self) -> f64 {
self.cells.iter().map(|c| c.rho).sum()
}
pub fn max_speed(&self) -> f64 {
self.cells
.iter()
.map(|c| (c.u[0] * c.u[0] + c.u[1] * c.u[1]).sqrt())
.fold(0.0, f64::max)
}
pub fn kinetic_energy(&self) -> f64 {
self.cells
.iter()
.map(|c| 0.5 * c.rho * (c.u[0] * c.u[0] + c.u[1] * c.u[1]))
.sum()
}
}
pub fn taylor_green(n: usize, u0: f64, viscosity: f64) -> Field2d {
let k = 2.0 * std::f64::consts::PI / n as f64;
Field2d::init(n, n, viscosity, |x, y| {
let (fx, fy) = (x as f64, y as f64);
(
1.0,
-u0 * (k * fx).cos() * (k * fy).sin(),
u0 * (k * fx).sin() * (k * fy).cos(),
)
})
}
pub fn taylor_green_decay(n: usize, viscosity: f64, steps: usize) -> f64 {
let k = 2.0 * std::f64::consts::PI / n as f64;
(-2.0 * viscosity * k * k * steps as f64).exp()
}