rtx-cfd legacy GPU: kernel outputs were device-buffer CLONES (every write lost) — the buffers are borrowed mutably now; the Poisson kernels keep boundary Dirichlet values; tests: the advection pulse marched 50 steps, the Jacobi budget 20k, the reduction reference in f64
CI / Python Bindings (maturin) (ubuntu-latest) (push) Blocked by required conditions
CI / Build (macos-latest) (push) Waiting to run
CI / Test (macos-latest) (push) Blocked by required conditions
CI / Test (ubuntu-latest) (push) Blocked by required conditions
CI / Python Bindings (maturin) (macos-latest) (push) Blocked by required conditions
CI / WASM Build + Size Check (push) Blocked by required conditions
CI / Distributed Training Tests (push) Blocked by required conditions
CI / CI Success (push) Blocked by required conditions
CI / Build CPU-Only (Explicit) (push) Failing after 5s
Documentation / Build User Guide (push) Successful in 5s
Documentation / Build API Documentation (push) Failing after 5s
CI / Format Check (push) Failing after 10s
CI / Build (ubuntu-latest) (push) Failing after 1m22s
CI / Clippy Check (push) Failing after 1m38s
Performance Benchmarks / Run Benchmarks (push) Successful in 2m50s
CI / Python Bindings (maturin) (ubuntu-latest) (push) Blocked by required conditions
CI / Build (macos-latest) (push) Waiting to run
CI / Test (macos-latest) (push) Blocked by required conditions
CI / Test (ubuntu-latest) (push) Blocked by required conditions
CI / Python Bindings (maturin) (macos-latest) (push) Blocked by required conditions
CI / WASM Build + Size Check (push) Blocked by required conditions
CI / Distributed Training Tests (push) Blocked by required conditions
CI / CI Success (push) Blocked by required conditions
CI / Build CPU-Only (Explicit) (push) Failing after 5s
Documentation / Build User Guide (push) Successful in 5s
Documentation / Build API Documentation (push) Failing after 5s
CI / Format Check (push) Failing after 10s
CI / Build (ubuntu-latest) (push) Failing after 1m22s
CI / Clippy Check (push) Failing after 1m38s
Performance Benchmarks / Run Benchmarks (push) Successful in 2m50s
This commit is contained in:
@@ -25,9 +25,9 @@ extern "C" __global__ void poisson_jacobi_2d(
|
|||||||
|
|
||||||
int idx = j * nx + i;
|
int idx = j * nx + i;
|
||||||
|
|
||||||
// Boundary conditions (Dirichlet - zero on boundaries for now)
|
// Boundary cells keep the Dirichlet values they hold.
|
||||||
if (i == 0 || i == nx - 1 || j == 0 || j == ny - 1) {
|
if (i == 0 || i == nx - 1 || j == 0 || j == ny - 1) {
|
||||||
phi_new[idx] = 0.0f;
|
phi_new[idx] = phi[idx];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +66,6 @@ extern "C" __global__ void poisson_gauss_seidel_2d(
|
|||||||
|
|
||||||
// Boundary conditions
|
// Boundary conditions
|
||||||
if (i == 0 || i == nx - 1 || j == 0 || j == ny - 1) {
|
if (i == 0 || i == nx - 1 || j == 0 || j == ny - 1) {
|
||||||
phi[idx] = 0.0f;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +104,6 @@ extern "C" __global__ void poisson_sor_2d(
|
|||||||
|
|
||||||
// Boundary conditions
|
// Boundary conditions
|
||||||
if (i == 0 || i == nx - 1 || j == 0 || j == ny - 1) {
|
if (i == 0 || i == nx - 1 || j == 0 || j == ny - 1) {
|
||||||
phi[idx] = 0.0f;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ impl PisoGpuSolver {
|
|||||||
fn copy_to_gpu(&self, flow_field: &FlowField) -> CfdResult<()> {
|
fn copy_to_gpu(&self, flow_field: &FlowField) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
// Convert nalgebra matrices to flat vectors
|
// Convert nalgebra matrices to flat vectors
|
||||||
@@ -171,7 +171,7 @@ impl PisoGpuSolver {
|
|||||||
fn copy_from_gpu(&self, flow_field: &mut FlowField) -> CfdResult<()> {
|
fn copy_from_gpu(&self, flow_field: &mut FlowField) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
// Copy from GPU
|
// Copy from GPU
|
||||||
@@ -271,7 +271,7 @@ impl PisoGpuSolver {
|
|||||||
let (nx, ny) = {
|
let (nx, ny) = {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
(buffers.nx, buffers.ny)
|
(buffers.nx, buffers.ny)
|
||||||
};
|
};
|
||||||
@@ -313,7 +313,7 @@ impl PisoGpuSolver {
|
|||||||
let residual_norm = {
|
let residual_norm = {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
self.matrix_ops_kernel.vector_norm(&buffers.mass_source)?
|
self.matrix_ops_kernel.vector_norm(&buffers.mass_source)?
|
||||||
};
|
};
|
||||||
@@ -464,8 +464,8 @@ impl PisoGpuSolver {
|
|||||||
.stream()
|
.stream()
|
||||||
.launch_builder(&func)
|
.launch_builder(&func)
|
||||||
.arg(&buffers.pressure_correction)
|
.arg(&buffers.pressure_correction)
|
||||||
.arg(&mut buffers.u_correction.clone())
|
.arg(&mut buffers.u_correction)
|
||||||
.arg(&mut buffers.v_correction.clone())
|
.arg(&mut buffers.v_correction)
|
||||||
.arg(&correction_factor)
|
.arg(&correction_factor)
|
||||||
.arg(&dx)
|
.arg(&dx)
|
||||||
.arg(&dy)
|
.arg(&dy)
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ impl SimpleGpuSolver {
|
|||||||
fn copy_to_gpu(&self, flow_field: &FlowField) -> CfdResult<()> {
|
fn copy_to_gpu(&self, flow_field: &FlowField) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
// Convert nalgebra matrices to flat vectors
|
// Convert nalgebra matrices to flat vectors
|
||||||
@@ -163,7 +163,7 @@ impl SimpleGpuSolver {
|
|||||||
fn copy_from_gpu(&self, flow_field: &mut FlowField) -> CfdResult<()> {
|
fn copy_from_gpu(&self, flow_field: &mut FlowField) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
// Copy from GPU
|
// Copy from GPU
|
||||||
@@ -300,7 +300,7 @@ impl SimpleGpuSolver {
|
|||||||
async fn gpu_pressure_update(&self, pressure_relaxation: f32) -> CfdResult<()> {
|
async fn gpu_pressure_update(&self, pressure_relaxation: f32) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
// p = p + α_p * p' (pressure update with relaxation)
|
// p = p + α_p * p' (pressure update with relaxation)
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ impl D2Q9GpuSolver {
|
|||||||
fn gpu_collision_step(&self) -> CfdResult<()> {
|
fn gpu_collision_step(&self) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
// First compute equilibrium distributions
|
// First compute equilibrium distributions
|
||||||
@@ -284,7 +284,7 @@ impl D2Q9GpuSolver {
|
|||||||
self.kernel_manager
|
self.kernel_manager
|
||||||
.stream()
|
.stream()
|
||||||
.launch_builder(&func)
|
.launch_builder(&func)
|
||||||
.arg(&mut buffers.f.clone())
|
.arg(&mut buffers.f)
|
||||||
.arg(&buffers.f_eq)
|
.arg(&buffers.f_eq)
|
||||||
.arg(&(self.omega as f32))
|
.arg(&(self.omega as f32))
|
||||||
.arg(&(buffers.nx as i32))
|
.arg(&(buffers.nx as i32))
|
||||||
@@ -303,7 +303,7 @@ impl D2Q9GpuSolver {
|
|||||||
pub fn gpu_streaming_step(&self) -> CfdResult<()> {
|
pub fn gpu_streaming_step(&self) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
let module = self
|
let module = self
|
||||||
@@ -327,7 +327,7 @@ impl D2Q9GpuSolver {
|
|||||||
self.kernel_manager
|
self.kernel_manager
|
||||||
.stream()
|
.stream()
|
||||||
.launch_builder(&func)
|
.launch_builder(&func)
|
||||||
.arg(&mut buffers.f_temp.clone())
|
.arg(&mut buffers.f_temp)
|
||||||
.arg(&buffers.f)
|
.arg(&buffers.f)
|
||||||
.arg(&(buffers.nx as i32))
|
.arg(&(buffers.nx as i32))
|
||||||
.arg(&(buffers.ny as i32))
|
.arg(&(buffers.ny as i32))
|
||||||
@@ -347,7 +347,7 @@ impl D2Q9GpuSolver {
|
|||||||
fn gpu_compute_macroscopic(&self) -> CfdResult<()> {
|
fn gpu_compute_macroscopic(&self) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
let module = self
|
let module = self
|
||||||
@@ -371,9 +371,9 @@ impl D2Q9GpuSolver {
|
|||||||
self.kernel_manager
|
self.kernel_manager
|
||||||
.stream()
|
.stream()
|
||||||
.launch_builder(&func)
|
.launch_builder(&func)
|
||||||
.arg(&mut buffers.density.clone())
|
.arg(&mut buffers.density)
|
||||||
.arg(&mut buffers.velocity_x.clone())
|
.arg(&mut buffers.velocity_x)
|
||||||
.arg(&mut buffers.velocity_y.clone())
|
.arg(&mut buffers.velocity_y)
|
||||||
.arg(&buffers.f)
|
.arg(&buffers.f)
|
||||||
.arg(&(buffers.nx as i32))
|
.arg(&(buffers.nx as i32))
|
||||||
.arg(&(buffers.ny as i32))
|
.arg(&(buffers.ny as i32))
|
||||||
@@ -394,7 +394,7 @@ impl D2Q9GpuSolver {
|
|||||||
fn gpu_compute_equilibrium(&self) -> CfdResult<()> {
|
fn gpu_compute_equilibrium(&self) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
let module = self
|
let module = self
|
||||||
@@ -418,7 +418,7 @@ impl D2Q9GpuSolver {
|
|||||||
self.kernel_manager
|
self.kernel_manager
|
||||||
.stream()
|
.stream()
|
||||||
.launch_builder(&func)
|
.launch_builder(&func)
|
||||||
.arg(&mut buffers.f_eq.clone())
|
.arg(&mut buffers.f_eq)
|
||||||
.arg(&buffers.density)
|
.arg(&buffers.density)
|
||||||
.arg(&buffers.velocity_x)
|
.arg(&buffers.velocity_x)
|
||||||
.arg(&buffers.velocity_y)
|
.arg(&buffers.velocity_y)
|
||||||
@@ -438,7 +438,7 @@ impl D2Q9GpuSolver {
|
|||||||
pub fn gpu_apply_bounce_back_boundaries(&self) -> CfdResult<()> {
|
pub fn gpu_apply_bounce_back_boundaries(&self) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
let module = self
|
let module = self
|
||||||
@@ -462,7 +462,7 @@ impl D2Q9GpuSolver {
|
|||||||
self.kernel_manager
|
self.kernel_manager
|
||||||
.stream()
|
.stream()
|
||||||
.launch_builder(&func)
|
.launch_builder(&func)
|
||||||
.arg(&mut buffers.f.clone())
|
.arg(&mut buffers.f)
|
||||||
.arg(&(buffers.nx as i32))
|
.arg(&(buffers.nx as i32))
|
||||||
.arg(&(buffers.ny as i32))
|
.arg(&(buffers.ny as i32))
|
||||||
.launch(config)
|
.launch(config)
|
||||||
@@ -492,7 +492,7 @@ impl D2Q9GpuSolver {
|
|||||||
) -> CfdResult<()> {
|
) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
let module = self
|
let module = self
|
||||||
@@ -516,10 +516,10 @@ impl D2Q9GpuSolver {
|
|||||||
self.kernel_manager
|
self.kernel_manager
|
||||||
.stream()
|
.stream()
|
||||||
.launch_builder(&func)
|
.launch_builder(&func)
|
||||||
.arg(&mut buffers.f.clone())
|
.arg(&mut buffers.f)
|
||||||
.arg(&mut buffers.density.clone())
|
.arg(&mut buffers.density)
|
||||||
.arg(&mut buffers.velocity_x.clone())
|
.arg(&mut buffers.velocity_x)
|
||||||
.arg(&mut buffers.velocity_y.clone())
|
.arg(&mut buffers.velocity_y)
|
||||||
.arg(&(density as f32))
|
.arg(&(density as f32))
|
||||||
.arg(&(velocity.x as f32))
|
.arg(&(velocity.x as f32))
|
||||||
.arg(&(velocity.y as f32))
|
.arg(&(velocity.y as f32))
|
||||||
@@ -539,7 +539,7 @@ impl D2Q9GpuSolver {
|
|||||||
pub fn get_macroscopic_at(&self, i: usize, j: usize) -> CfdResult<(f64, Vector2<f64>)> {
|
pub fn get_macroscopic_at(&self, i: usize, j: usize) -> CfdResult<(f64, Vector2<f64>)> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
let idx = j * buffers.nx + i;
|
let idx = j * buffers.nx + i;
|
||||||
@@ -585,7 +585,7 @@ impl D2Q9GpuSolver {
|
|||||||
pub fn update_flow_field(&self, flow_field: &mut FlowField) -> CfdResult<()> {
|
pub fn update_flow_field(&self, flow_field: &mut FlowField) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
let (nx, ny, _, _) = flow_field.grid_info();
|
let (nx, ny, _, _) = flow_field.grid_info();
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ __global__ void d3q19_bounce_back_boundaries(
|
|||||||
pub fn gpu_collision_step(&self) -> CfdResult<()> {
|
pub fn gpu_collision_step(&self) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
let omega = 1.0 / self.params.tau;
|
let omega = 1.0 / self.params.tau;
|
||||||
@@ -399,7 +399,7 @@ __global__ void d3q19_bounce_back_boundaries(
|
|||||||
self.kernel_manager
|
self.kernel_manager
|
||||||
.stream()
|
.stream()
|
||||||
.launch_builder(&func)
|
.launch_builder(&func)
|
||||||
.arg(&mut buffers.f.clone())
|
.arg(&mut buffers.f)
|
||||||
.arg(&buffers.f_eq)
|
.arg(&buffers.f_eq)
|
||||||
.arg(&(omega as f32))
|
.arg(&(omega as f32))
|
||||||
.arg(&(buffers.nx as i32))
|
.arg(&(buffers.nx as i32))
|
||||||
@@ -419,7 +419,7 @@ __global__ void d3q19_bounce_back_boundaries(
|
|||||||
pub fn gpu_streaming_step(&self) -> CfdResult<()> {
|
pub fn gpu_streaming_step(&self) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
let module = self
|
let module = self
|
||||||
@@ -444,7 +444,7 @@ __global__ void d3q19_bounce_back_boundaries(
|
|||||||
self.kernel_manager
|
self.kernel_manager
|
||||||
.stream()
|
.stream()
|
||||||
.launch_builder(&func)
|
.launch_builder(&func)
|
||||||
.arg(&mut buffers.f_temp.clone())
|
.arg(&mut buffers.f_temp)
|
||||||
.arg(&buffers.f)
|
.arg(&buffers.f)
|
||||||
.arg(&(buffers.nx as i32))
|
.arg(&(buffers.nx as i32))
|
||||||
.arg(&(buffers.ny as i32))
|
.arg(&(buffers.ny as i32))
|
||||||
@@ -465,7 +465,7 @@ __global__ void d3q19_bounce_back_boundaries(
|
|||||||
fn gpu_extract_macroscopic_variables(&self) -> CfdResult<()> {
|
fn gpu_extract_macroscopic_variables(&self) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
let module = self
|
let module = self
|
||||||
@@ -495,10 +495,10 @@ __global__ void d3q19_bounce_back_boundaries(
|
|||||||
self.kernel_manager
|
self.kernel_manager
|
||||||
.stream()
|
.stream()
|
||||||
.launch_builder(&func)
|
.launch_builder(&func)
|
||||||
.arg(&mut buffers.density.clone())
|
.arg(&mut buffers.density)
|
||||||
.arg(&mut buffers.velocity_x.clone())
|
.arg(&mut buffers.velocity_x)
|
||||||
.arg(&mut buffers.velocity_y.clone())
|
.arg(&mut buffers.velocity_y)
|
||||||
.arg(&mut buffers.velocity_z.clone())
|
.arg(&mut buffers.velocity_z)
|
||||||
.arg(&buffers.f)
|
.arg(&buffers.f)
|
||||||
.arg(&(buffers.nx as i32))
|
.arg(&(buffers.nx as i32))
|
||||||
.arg(&(buffers.ny as i32))
|
.arg(&(buffers.ny as i32))
|
||||||
@@ -520,7 +520,7 @@ __global__ void d3q19_bounce_back_boundaries(
|
|||||||
fn gpu_compute_equilibrium(&self) -> CfdResult<()> {
|
fn gpu_compute_equilibrium(&self) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
let module = self
|
let module = self
|
||||||
@@ -545,7 +545,7 @@ __global__ void d3q19_bounce_back_boundaries(
|
|||||||
self.kernel_manager
|
self.kernel_manager
|
||||||
.stream()
|
.stream()
|
||||||
.launch_builder(&func)
|
.launch_builder(&func)
|
||||||
.arg(&mut buffers.f_eq.clone())
|
.arg(&mut buffers.f_eq)
|
||||||
.arg(&buffers.density)
|
.arg(&buffers.density)
|
||||||
.arg(&buffers.velocity_x)
|
.arg(&buffers.velocity_x)
|
||||||
.arg(&buffers.velocity_y)
|
.arg(&buffers.velocity_y)
|
||||||
@@ -567,7 +567,7 @@ __global__ void d3q19_bounce_back_boundaries(
|
|||||||
pub fn gpu_apply_bounce_back_boundaries(&self) -> CfdResult<()> {
|
pub fn gpu_apply_bounce_back_boundaries(&self) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
let module = self
|
let module = self
|
||||||
@@ -591,7 +591,7 @@ __global__ void d3q19_bounce_back_boundaries(
|
|||||||
self.kernel_manager
|
self.kernel_manager
|
||||||
.stream()
|
.stream()
|
||||||
.launch_builder(&func)
|
.launch_builder(&func)
|
||||||
.arg(&mut buffers.f.clone())
|
.arg(&mut buffers.f)
|
||||||
.arg(&(buffers.nx as i32))
|
.arg(&(buffers.nx as i32))
|
||||||
.arg(&(buffers.ny as i32))
|
.arg(&(buffers.ny as i32))
|
||||||
.arg(&(buffers.nz as i32))
|
.arg(&(buffers.nz as i32))
|
||||||
@@ -621,7 +621,7 @@ __global__ void d3q19_bounce_back_boundaries(
|
|||||||
) -> CfdResult<()> {
|
) -> CfdResult<()> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
let module = self
|
let module = self
|
||||||
@@ -648,7 +648,7 @@ __global__ void d3q19_bounce_back_boundaries(
|
|||||||
self.kernel_manager
|
self.kernel_manager
|
||||||
.stream()
|
.stream()
|
||||||
.launch_builder(&func)
|
.launch_builder(&func)
|
||||||
.arg(&mut buffers.f.clone())
|
.arg(&mut buffers.f)
|
||||||
.arg(&(density as f32))
|
.arg(&(density as f32))
|
||||||
.arg(&(velocity.x as f32))
|
.arg(&(velocity.x as f32))
|
||||||
.arg(&(velocity.y as f32))
|
.arg(&(velocity.y as f32))
|
||||||
@@ -675,7 +675,7 @@ __global__ void d3q19_bounce_back_boundaries(
|
|||||||
) -> CfdResult<MacroscopicVariables3D> {
|
) -> CfdResult<MacroscopicVariables3D> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
// Extract macroscopic variables first
|
// Extract macroscopic variables first
|
||||||
@@ -726,7 +726,7 @@ __global__ void d3q19_bounce_back_boundaries(
|
|||||||
pub fn gpu_total_mass(&self) -> CfdResult<f64> {
|
pub fn gpu_total_mass(&self) -> CfdResult<f64> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
self.gpu_extract_macroscopic_variables()?;
|
self.gpu_extract_macroscopic_variables()?;
|
||||||
@@ -739,7 +739,7 @@ __global__ void d3q19_bounce_back_boundaries(
|
|||||||
pub fn gpu_kinetic_energy(&self) -> CfdResult<f64> {
|
pub fn gpu_kinetic_energy(&self) -> CfdResult<f64> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
self.gpu_extract_macroscopic_variables()?;
|
self.gpu_extract_macroscopic_variables()?;
|
||||||
|
|||||||
@@ -429,7 +429,7 @@ impl KEpsilonGpuModel {
|
|||||||
pub fn get_eddy_viscosity(&self) -> CfdResult<Vec<f32>> {
|
pub fn get_eddy_viscosity(&self) -> CfdResult<Vec<f32>> {
|
||||||
let buffers = self
|
let buffers = self
|
||||||
.gpu_buffers
|
.gpu_buffers
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
.ok_or_else(|| CfdError::gpu_error("GPU buffers not initialized"))?;
|
||||||
|
|
||||||
let n = buffers.nx * buffers.ny * buffers.nz;
|
let n = buffers.nx * buffers.ny * buffers.nz;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ mod gpu_reduction_tests {
|
|||||||
|
|
||||||
// Create test data
|
// Create test data
|
||||||
let test_data: Vec<f32> = (1..=100).map(|i| i as f32).collect();
|
let test_data: Vec<f32> = (1..=100).map(|i| i as f32).collect();
|
||||||
let expected_sum = test_data.iter().sum::<f32>();
|
let expected_sum = test_data.iter().map(|&v| v as f64).sum::<f64>() as f32; // f64 reference: a sequential f32 sum of a million terms carries ~1e-3 of rounding
|
||||||
|
|
||||||
// Copy to GPU
|
// Copy to GPU
|
||||||
let gpu_data = manager.copy_to_device(&test_data)?;
|
let gpu_data = manager.copy_to_device(&test_data)?;
|
||||||
@@ -100,7 +100,7 @@ mod gpu_reduction_tests {
|
|||||||
// Create large test array
|
// Create large test array
|
||||||
let n = 1_000_000;
|
let n = 1_000_000;
|
||||||
let test_data: Vec<f32> = (0..n).map(|i| (i % 100) as f32).collect();
|
let test_data: Vec<f32> = (0..n).map(|i| (i % 100) as f32).collect();
|
||||||
let expected_sum = test_data.iter().sum::<f32>();
|
let expected_sum = test_data.iter().map(|&v| v as f64).sum::<f64>() as f32; // f64 reference: a sequential f32 sum of a million terms carries ~1e-3 of rounding
|
||||||
|
|
||||||
// Copy to GPU
|
// Copy to GPU
|
||||||
let gpu_data = manager.copy_to_device(&test_data)?;
|
let gpu_data = manager.copy_to_device(&test_data)?;
|
||||||
|
|||||||
@@ -46,17 +46,15 @@ mod cuda_tests {
|
|||||||
d_phi = kernel_manager.copy_to_device(&phi)?;
|
d_phi = kernel_manager.copy_to_device(&phi)?;
|
||||||
|
|
||||||
// Run advection kernel
|
// Run advection kernel
|
||||||
advection_kernel.apply(
|
// CFL = v dt / dx ≈ 0.1: march 50 steps so the pulse moves several cells.
|
||||||
&d_phi,
|
for _ in 0..50 {
|
||||||
&mut d_phi_new,
|
advection_kernel.apply(&d_phi, &mut d_phi_new, velocity as f32, dt as f32, dx as f32)?;
|
||||||
velocity as f32,
|
std::mem::swap(&mut d_phi, &mut d_phi_new);
|
||||||
dt as f32,
|
}
|
||||||
dx as f32,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Copy result back
|
// Copy result back
|
||||||
let mut result = vec![0.0f32; nx];
|
let mut result = vec![0.0f32; nx];
|
||||||
result = kernel_manager.copy_from_device(&d_phi_new)?;
|
result = kernel_manager.copy_from_device(&d_phi)?;
|
||||||
|
|
||||||
// Verify that the pulse has moved (mass conservation)
|
// Verify that the pulse has moved (mass conservation)
|
||||||
let initial_mass: f32 = phi.iter().sum();
|
let initial_mass: f32 = phi.iter().sum();
|
||||||
@@ -206,7 +204,7 @@ mod cuda_tests {
|
|||||||
d_source = kernel_manager.copy_to_device(&source)?;
|
d_source = kernel_manager.copy_to_device(&source)?;
|
||||||
|
|
||||||
// Solve Poisson equation
|
// Solve Poisson equation
|
||||||
let max_iterations = 1000;
|
let max_iterations = 20_000; // Jacobi needs O(n²) sweeps on this grid
|
||||||
let tolerance = 1e-6;
|
let tolerance = 1e-6;
|
||||||
let iterations = poisson_kernel.solve_2d(
|
let iterations = poisson_kernel.solve_2d(
|
||||||
&mut d_phi,
|
&mut d_phi,
|
||||||
|
|||||||
Reference in New Issue
Block a user