use std::sync::{PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard};
use crate::axis::Axis;
pub(crate) type Block = [Vec<f32>; 3];
pub(crate) fn read<T>(l: &RwLock<T>) -> RwLockReadGuard<'_, T> {
l.read().unwrap_or_else(PoisonError::into_inner)
}
pub(crate) fn write<T>(l: &RwLock<T>) -> RwLockWriteGuard<'_, T> {
l.write().unwrap_or_else(PoisonError::into_inner)
}
#[derive(Debug, Clone)]
pub(crate) struct Layout {
pub(crate) n: [usize; 3],
pub(crate) plane: usize,
pub(crate) slab_start: Vec<usize>,
plane_slab: Vec<usize>,
}
impl Layout {
pub(crate) fn new(n: [usize; 3], slabs: usize) -> Self {
let slabs = slabs.clamp(1, n[0]);
let (q, r) = (n[0] / slabs, n[0] % slabs);
let mut slab_start = Vec::with_capacity(slabs + 1);
let mut p = 0;
for s in 0..slabs {
slab_start.push(p);
p += q + usize::from(s < r);
}
slab_start.push(n[0]);
let mut plane_slab = vec![0; n[0]];
for s in 0..slabs {
plane_slab[slab_start[s]..slab_start[s + 1]].fill(s);
}
Self {
n,
plane: n[1] * n[2],
slab_start,
plane_slab,
}
}
pub(crate) fn slabs(&self) -> usize {
self.slab_start.len() - 1
}
pub(crate) fn planes(&self, s: usize) -> (usize, usize) {
(self.slab_start[s], self.slab_start[s + 1])
}
#[inline]
pub(crate) fn locate(&self, [i, j, k]: [usize; 3]) -> (usize, usize) {
assert!(
i < self.n[0] && j < self.n[1] && k < self.n[2],
"node [{i}, {j}, {k}] out of range {:?}",
self.n
);
let s = self.plane_slab[i];
(
s,
((i - self.slab_start[s]) * self.n[1] + j) * self.n[2] + k,
)
}
}
#[derive(Debug)]
pub(crate) struct FieldStore {
pub(crate) layout: Layout,
pub(crate) u: Vec<RwLock<Block>>,
pub(crate) i: Vec<RwLock<Block>>,
}
impl FieldStore {
pub(crate) fn new(layout: Layout) -> Self {
let mk = |s: usize| {
let (a, b) = layout.planes(s);
let len = (b - a) * layout.plane;
RwLock::new([vec![0.0; len], vec![0.0; len], vec![0.0; len]])
};
let u = (0..layout.slabs()).map(mk).collect();
let i = (0..layout.slabs()).map(mk).collect();
Self { layout, u, i }
}
pub(crate) fn lock(&self) -> Fields<'_> {
Fields {
u: FieldArrays {
layout: &self.layout,
blocks: self.u.iter().map(write).collect(),
},
i: FieldArrays {
layout: &self.layout,
blocks: self.i.iter().map(write).collect(),
},
}
}
}
#[derive(Debug)]
pub struct FieldArrays<'a> {
layout: &'a Layout,
blocks: Vec<RwLockWriteGuard<'a, Block>>,
}
impl FieldArrays<'_> {
pub fn nodes(&self) -> [usize; 3] {
self.layout.n
}
#[inline]
pub fn get(&self, axis: Axis, node: [usize; 3]) -> f32 {
let (s, o) = self.layout.locate(node);
self.blocks[s][axis.index()][o]
}
#[inline]
pub fn get_mut(&mut self, axis: Axis, node: [usize; 3]) -> &mut f32 {
let (s, o) = self.layout.locate(node);
&mut self.blocks[s][axis.index()][o]
}
#[inline]
pub fn set(&mut self, axis: Axis, node: [usize; 3], v: f32) {
*self.get_mut(axis, node) = v;
}
pub fn plane(&self, axis: Axis, i: usize) -> &[f32] {
let (s, o) = self.layout.locate([i, 0, 0]);
&self.blocks[s][axis.index()][o..o + self.layout.plane]
}
pub fn plane_mut(&mut self, axis: Axis, i: usize) -> &mut [f32] {
let (s, o) = self.layout.locate([i, 0, 0]);
&mut self.blocks[s][axis.index()][o..o + self.layout.plane]
}
pub fn to_vec(&self, axis: Axis) -> Vec<f32> {
let mut v = Vec::with_capacity(self.layout.n[0] * self.layout.plane);
for b in &self.blocks {
v.extend_from_slice(&b[axis.index()]);
}
v
}
pub fn clear(&mut self) {
for b in &mut self.blocks {
for c in b.iter_mut() {
c.fill(0.0);
}
}
}
}
#[derive(Debug)]
pub struct Fields<'a> {
pub u: FieldArrays<'a>,
pub i: FieldArrays<'a>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn partition() {
let l = Layout::new([10, 3, 4], 4);
assert_eq!(l.slab_start, vec![0, 3, 6, 8, 10]);
assert_eq!(l.locate([7, 1, 2]), (2, 18));
let l = Layout::new([3, 2, 2], 8);
assert_eq!(l.slabs(), 3);
let store = FieldStore::new(Layout::new([5, 2, 3], 2));
let mut f = store.lock();
f.u.set(Axis::Y, [4, 1, 2], 3.0);
f.i.set(Axis::X, [0, 0, 1], 2.0);
assert_eq!(f.u.get(Axis::Y, [4, 1, 2]), 3.0);
let v = f.u.to_vec(Axis::Y);
assert_eq!(v[(4 * 2 + 1) * 3 + 2], 3.0);
assert_eq!(f.i.plane(Axis::X, 0)[1], 2.0);
}
}