implement a CpuBackend for running the "spirv" simulations
UNTESTED
This commit is contained in:
187
crates/coremem/src/sim/spirv/cpu.rs
Normal file
187
crates/coremem/src/sim/spirv/cpu.rs
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
use coremem_types::mat::Material;
|
||||||
|
use coremem_types::real::Real;
|
||||||
|
use coremem_types::step::{SimMeta, StepEContext, StepHContext, VolumeSampleNeg, VolumeSamplePos};
|
||||||
|
use coremem_types::vec::{Vec3, Vec3u};
|
||||||
|
|
||||||
|
use super::SimBackend;
|
||||||
|
|
||||||
|
struct CpuBackend;
|
||||||
|
|
||||||
|
impl<R: Real, M: Material<R>> SimBackend<R, M> for CpuBackend {
|
||||||
|
fn new(_volume: u64) -> Self {
|
||||||
|
CpuBackend
|
||||||
|
}
|
||||||
|
fn step_n(
|
||||||
|
&self,
|
||||||
|
num_steps: u32,
|
||||||
|
meta: SimMeta<R>,
|
||||||
|
stim_e: &[Vec3<f32>],
|
||||||
|
stim_h: &[Vec3<f32>],
|
||||||
|
mat: &[M],
|
||||||
|
e: &mut [Vec3<R>],
|
||||||
|
h: &mut [Vec3<R>],
|
||||||
|
m: &mut [Vec3<R>],
|
||||||
|
) {
|
||||||
|
for _ in 0..num_steps {
|
||||||
|
step_e(meta, stim_e, mat, e, h, m);
|
||||||
|
step_h(meta, stim_h, mat, e, h, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn step_e<R: Real, M: Material<R>>(
|
||||||
|
meta: SimMeta<R>,
|
||||||
|
stim_e: &[Vec3<f32>],
|
||||||
|
mat: &[M],
|
||||||
|
e: &mut [Vec3<R>],
|
||||||
|
h: &[Vec3<R>],
|
||||||
|
m: &[Vec3<R>],
|
||||||
|
) {
|
||||||
|
apply_all_cells(meta.dim, |idx| {
|
||||||
|
step_e_cell(idx, meta, stim_e, mat, e, h, m);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fn step_h<R: Real, M: Material<R>>(
|
||||||
|
meta: SimMeta<R>,
|
||||||
|
stim_h: &[Vec3<f32>],
|
||||||
|
mat: &[M],
|
||||||
|
e: &[Vec3<R>],
|
||||||
|
h: &mut [Vec3<R>],
|
||||||
|
m: &mut [Vec3<R>],
|
||||||
|
) {
|
||||||
|
apply_all_cells(meta.dim, |idx| {
|
||||||
|
step_h_cell(idx, meta, stim_h, mat, e, h, m);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn step_e_cell<R: Real, M: Material<R>>(
|
||||||
|
idx: Vec3u,
|
||||||
|
meta: SimMeta<R>,
|
||||||
|
stim_e: &[Vec3<f32>],
|
||||||
|
mat: &[M],
|
||||||
|
e: &mut [Vec3<R>],
|
||||||
|
h: &[Vec3<R>],
|
||||||
|
m: &[Vec3<R>],
|
||||||
|
) {
|
||||||
|
let flat_idx = flat_idx(meta.dim, idx);
|
||||||
|
let step_e_context = StepEContext {
|
||||||
|
inv_feature_size: meta.inv_feature_size(),
|
||||||
|
time_step: meta.time_step(),
|
||||||
|
stim_e: stim_e[flat_idx].cast(),
|
||||||
|
mat: &mat[flat_idx],
|
||||||
|
in_h: sample_neg(h, meta.dim(), idx),
|
||||||
|
in_e: e[flat_idx],
|
||||||
|
};
|
||||||
|
let new_e = step_e_context.step_e();
|
||||||
|
e[flat_idx] = new_e;
|
||||||
|
}
|
||||||
|
fn step_h_cell<R: Real, M: Material<R>>(
|
||||||
|
idx: Vec3u,
|
||||||
|
meta: SimMeta<R>,
|
||||||
|
stim_h: &[Vec3<f32>],
|
||||||
|
mat: &[M],
|
||||||
|
e: &[Vec3<R>],
|
||||||
|
h: &mut [Vec3<R>],
|
||||||
|
m: &mut [Vec3<R>],
|
||||||
|
) {
|
||||||
|
let flat_idx = flat_idx(meta.dim, idx);
|
||||||
|
let step_h_context = StepHContext {
|
||||||
|
inv_feature_size: meta.inv_feature_size(),
|
||||||
|
time_step: meta.time_step(),
|
||||||
|
stim_h: stim_h[flat_idx].cast(),
|
||||||
|
mat: &mat[flat_idx],
|
||||||
|
in_e: sample_pos(e, meta.dim(), idx),
|
||||||
|
in_h: h[flat_idx],
|
||||||
|
in_m: m[flat_idx],
|
||||||
|
};
|
||||||
|
let (new_h, new_m) = step_h_context.step_h();
|
||||||
|
h[flat_idx] = new_h;
|
||||||
|
m[flat_idx] = new_m;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_all_cells<F: FnMut(Vec3u)>(dim: Vec3u, mut f: F) {
|
||||||
|
for z in 0..dim.z() {
|
||||||
|
for y in 0..dim.y() {
|
||||||
|
for x in 0..dim.x() {
|
||||||
|
f(Vec3u::new(x, y, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flat_idx(dim: Vec3u, idx: Vec3u) -> usize {
|
||||||
|
let dx = dim.x() as usize;
|
||||||
|
let dy = dim.y() as usize;
|
||||||
|
// let dz = dim.z() as usize;
|
||||||
|
let ix = idx.x() as usize;
|
||||||
|
let iy = idx.y() as usize;
|
||||||
|
let iz = idx.z() as usize;
|
||||||
|
let effective_y = iz * dy + iy;
|
||||||
|
let effective_x = effective_y * dx + ix;
|
||||||
|
effective_x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prev_x(idx: Vec3u) -> Option<Vec3u> {
|
||||||
|
match idx.into() {
|
||||||
|
(0, _, _) => None,
|
||||||
|
(x, y, z) => Some(Vec3u::new(x-1, y, z)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn prev_y(idx: Vec3u) -> Option<Vec3u> {
|
||||||
|
match idx.into() {
|
||||||
|
(_, 0, _) => None,
|
||||||
|
(x, y, z) => Some(Vec3u::new(x, y-1, z)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn prev_z(idx: Vec3u) -> Option<Vec3u> {
|
||||||
|
match idx.into() {
|
||||||
|
(_, _, 0) => None,
|
||||||
|
(x, y, z) => Some(Vec3u::new(x, y, z-1)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_x(dim: Vec3u, idx: Vec3u) -> Option<Vec3u> {
|
||||||
|
match idx.into() {
|
||||||
|
(x, y, z) if x + 1 < dim.x() => Some(Vec3u::new(x+1, y, z)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn next_y(dim: Vec3u, idx: Vec3u) -> Option<Vec3u> {
|
||||||
|
match idx.into() {
|
||||||
|
(x, y, z) if y + 1 < dim.y() => Some(Vec3u::new(x, y+1, z)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn next_z(dim: Vec3u, idx: Vec3u) -> Option<Vec3u> {
|
||||||
|
match idx.into() {
|
||||||
|
(x, y, z) if z + 1 < dim.z() => Some(Vec3u::new(x, y, z+1)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sample_pos<R: Copy + Default>(arr: &[Vec3<R>], dim: Vec3u, idx: Vec3u) -> VolumeSamplePos<R> {
|
||||||
|
VolumeSamplePos {
|
||||||
|
mid: arr[flat_idx(dim, idx)],
|
||||||
|
xp1: next_x(dim, idx).map(|i| arr[flat_idx(dim, i)]).into(),
|
||||||
|
yp1: next_y(dim, idx).map(|i| arr[flat_idx(dim, i)]).into(),
|
||||||
|
zp1: next_z(dim, idx).map(|i| arr[flat_idx(dim, i)]).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sample_neg<R: Copy + Default>(arr: &[Vec3<R>], dim: Vec3u, idx: Vec3u) -> VolumeSampleNeg<R> {
|
||||||
|
VolumeSampleNeg {
|
||||||
|
mid: arr[flat_idx(dim, idx)],
|
||||||
|
xm1: prev_x(idx).map(|i| arr[flat_idx(dim, i)]).into(),
|
||||||
|
ym1: prev_y(idx).map(|i| arr[flat_idx(dim, i)]).into(),
|
||||||
|
zm1: prev_z(idx).map(|i| arr[flat_idx(dim, i)]).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
#[test]
|
||||||
|
fn flat_idx_() {
|
||||||
|
// TODO: test all these helper methods!
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
@@ -11,6 +11,7 @@ use crate::types::vec::Vec3;
|
|||||||
use coremem_types::mat::{FullyGenericMaterial, Material};
|
use coremem_types::mat::{FullyGenericMaterial, Material};
|
||||||
use coremem_types::step::SimMeta;
|
use coremem_types::step::SimMeta;
|
||||||
|
|
||||||
|
mod cpu;
|
||||||
mod gpu;
|
mod gpu;
|
||||||
use gpu::WgpuBackend;
|
use gpu::WgpuBackend;
|
||||||
|
|
||||||
|
@@ -84,6 +84,11 @@ impl<T0: Default, T1: Default> Optional<(T0, T1)> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// these impls below are not valid when compiled to spirv.
|
||||||
|
// but because they're generics, they're only compiled lazily,
|
||||||
|
// so we don't need to feature-gate them: just don't use them in spirv code.
|
||||||
|
|
||||||
impl<T> Into<Option<T>> for Optional<T> {
|
impl<T> Into<Option<T>> for Optional<T> {
|
||||||
fn into(self) -> Option<T> {
|
fn into(self) -> Option<T> {
|
||||||
if self.present != 0 {
|
if self.present != 0 {
|
||||||
@@ -94,3 +99,11 @@ impl<T> Into<Option<T>> for Optional<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Default> From<Option<T>> for Optional<T> {
|
||||||
|
fn from(o: Option<T>) -> Self {
|
||||||
|
match o {
|
||||||
|
None => Self::none(),
|
||||||
|
Some(x) => Optional::some(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -16,6 +16,21 @@ pub struct SimMeta<R> {
|
|||||||
pub feature_size: R,
|
pub feature_size: R,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<R: Copy> SimMeta<R> {
|
||||||
|
pub fn dim(&self) -> Vec3u {
|
||||||
|
self.dim
|
||||||
|
}
|
||||||
|
pub fn inv_feature_size(&self) -> R {
|
||||||
|
self.inv_feature_size
|
||||||
|
}
|
||||||
|
pub fn time_step(&self) -> R {
|
||||||
|
self.time_step
|
||||||
|
}
|
||||||
|
pub fn feature_size(&self) -> R {
|
||||||
|
self.feature_size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Package the field vectors adjacent to some particular location.
|
/// Package the field vectors adjacent to some particular location.
|
||||||
/// Particular those at negative offsets from the midpoint.
|
/// Particular those at negative offsets from the midpoint.
|
||||||
/// This is used in step_e when looking at the H field deltas.
|
/// This is used in step_e when looking at the H field deltas.
|
||||||
|
@@ -59,6 +59,12 @@ impl From<(u32, u32, u32)> for Vec3u {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Into<(u32, u32, u32)> for Vec3u {
|
||||||
|
fn into(self) -> (u32, u32, u32) {
|
||||||
|
(self.x, self.y, self.z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<R: Real> From<Vec3<R>> for Vec3u {
|
impl<R: Real> From<Vec3<R>> for Vec3u {
|
||||||
fn from(v: Vec3<R>) -> Self {
|
fn from(v: Vec3<R>) -> Self {
|
||||||
Self::new(v.x().to_f64() as _, v.y().to_f64() as _, v.z().to_f64() as _)
|
Self::new(v.x().to_f64() as _, v.y().to_f64() as _, v.z().to_f64() as _)
|
||||||
|
Reference in New Issue
Block a user