diff --git a/crates/specialized/rtx-cfd/src/kernels/cuda_simple.rs b/crates/specialized/rtx-cfd/src/kernels/cuda_simple.rs index d6869ae..9d6ea5a 100644 --- a/crates/specialized/rtx-cfd/src/kernels/cuda_simple.rs +++ b/crates/specialized/rtx-cfd/src/kernels/cuda_simple.rs @@ -601,6 +601,23 @@ impl PoissonKernel { }) } + /// [`Self::solve_2d`] under its older name. + #[allow(clippy::too_many_arguments)] + pub fn solve_jacobi_2d( + &self, + phi: &mut CudaSlice, + source: &CudaSlice, + nx: usize, + ny: usize, + dx: f32, + dy: f32, + max_iterations: usize, + tolerance: f32, + ) -> CfdResult { + self.solve_2d(phi, source, nx, ny, dx, dy, max_iterations, tolerance) + } + + #[allow(clippy::too_many_arguments)] pub fn solve_2d( &self, phi: &mut CudaSlice, @@ -757,6 +774,39 @@ impl MatrixOpsKernel { Ok(result) } + /// `y = T x` for the tridiagonal matrix with `diagonal` (n) and + /// `off_diagonal` (n − 1) — the `tridiagonal_matvec` kernel. + pub fn tridiagonal_matvec( + &self, + diagonal: &CudaSlice, + off_diagonal: &CudaSlice, + x: &CudaSlice, + y: &mut CudaSlice, + ) -> CfdResult<()> { + let n = x.len(); + let func = self + .module + .load_function("tridiagonal_matvec") + .map_err(|e| CfdError::gpu_error(&format!("Failed to get kernel: {}", e)))?; + let config = LaunchConfig { + grid_dim: ((n as u32 + 255) / 256, 1, 1), + block_dim: (256, 1, 1), + shared_mem_bytes: 0, + }; + unsafe { + self.stream + .launch_builder(&func) + .arg(diagonal) + .arg(off_diagonal) + .arg(x) + .arg(y) + .arg(&(n as i32)) + .launch(config) + .map_err(|e| CfdError::gpu_error(&format!("Kernel launch failed: {}", e)))?; + } + Ok(()) + } + /// Compute L2 norm of vector pub fn vector_norm(&self, x: &CudaSlice) -> CfdResult { let n = x.len(); diff --git a/crates/specialized/rtx-cfd/tests/cuda_kernel_manager_tests.rs b/crates/specialized/rtx-cfd/tests/cuda_kernel_manager_tests.rs index 9cef51e..3c15c78 100644 --- a/crates/specialized/rtx-cfd/tests/cuda_kernel_manager_tests.rs +++ b/crates/specialized/rtx-cfd/tests/cuda_kernel_manager_tests.rs @@ -20,6 +20,7 @@ mod cuda_kernel_manager_tests { viscosity: 0.01, density: 1.0, device_id: 0, + ..CfdConfig::default() } } @@ -31,7 +32,7 @@ mod cuda_kernel_manager_tests { } let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); // Verify manager is created successfully // Context and stream should be valid (non-null references) @@ -49,7 +50,7 @@ mod cuda_kernel_manager_tests { } let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); // Test that required modules are loaded // Getting a module should succeed and return a valid Arc reference @@ -72,7 +73,7 @@ mod cuda_kernel_manager_tests { } let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); // Test that non-existent module returns error let result = manager.get_module("nonexistent_module"); @@ -92,7 +93,7 @@ mod cuda_kernel_manager_tests { } let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); // Test allocating GPU memory let size = 1024; @@ -110,7 +111,7 @@ mod cuda_kernel_manager_tests { } let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); // Test copying data to GPU let host_data: Vec = (0..100).map(|i| i as f32).collect(); @@ -128,7 +129,7 @@ mod cuda_kernel_manager_tests { } let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); // Test round-trip copy: host -> device -> host let original_data: Vec = (0..100).map(|i| i as f32 * 0.1).collect(); @@ -159,7 +160,7 @@ mod cuda_kernel_manager_tests { } let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); // Test that synchronization doesn't error manager.synchronize()?; diff --git a/crates/specialized/rtx-cfd/tests/gpu_kernel_comprehensive_tests.rs b/crates/specialized/rtx-cfd/tests/gpu_kernel_comprehensive_tests.rs index 98226c9..6dd0020 100644 --- a/crates/specialized/rtx-cfd/tests/gpu_kernel_comprehensive_tests.rs +++ b/crates/specialized/rtx-cfd/tests/gpu_kernel_comprehensive_tests.rs @@ -37,9 +37,10 @@ mod gpu_kernel_tests { lz: 0.0, dt: 0.001, ..Default::default() + ..CfdConfig::default() }; - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); // Test all advection schemes let schemes = vec![ @@ -117,9 +118,10 @@ mod gpu_kernel_tests { lz: 0.0, dt: 0.001, ..Default::default() + ..CfdConfig::default() }; - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let kernel = AdvectionKernel::new(&manager, AdvectionScheme::Upwind)?; let nx = 64; @@ -202,9 +204,10 @@ mod gpu_kernel_tests { lz: 0.0, dt: 0.0001, ..Default::default() + ..CfdConfig::default() }; - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); // Test all diffusion schemes let schemes = vec![ @@ -288,9 +291,10 @@ mod gpu_kernel_tests { lz: 0.0, dt: 0.0001, ..Default::default() + ..CfdConfig::default() }; - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let kernel = DiffusionKernel::new(&manager, DiffusionScheme::Explicit)?; let nx = 64; @@ -366,9 +370,10 @@ mod gpu_kernel_tests { lz: 0.0, dt: 0.001, ..Default::default() + ..CfdConfig::default() }; - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let kernel = PoissonKernel::new(&manager)?; let nx = 32; @@ -443,9 +448,10 @@ mod gpu_kernel_tests { lz: 0.0, dt: 0.001, ..Default::default() + ..CfdConfig::default() }; - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); // Test allocation and deallocation of large arrays let sizes = vec![1024, 65536, 262144]; @@ -491,9 +497,10 @@ mod gpu_kernel_tests { lz: 0.0, dt: 0.001, ..Default::default() + ..CfdConfig::default() }; - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let kernel = AdvectionKernel::new(&manager, AdvectionScheme::Upwind)?; let n = 512 * 512; diff --git a/crates/specialized/rtx-cfd/tests/gpu_kernel_tests.rs b/crates/specialized/rtx-cfd/tests/gpu_kernel_tests.rs index 25fab83..46876e2 100644 --- a/crates/specialized/rtx-cfd/tests/gpu_kernel_tests.rs +++ b/crates/specialized/rtx-cfd/tests/gpu_kernel_tests.rs @@ -25,20 +25,21 @@ mod cuda_tests { viscosity: 0.01, density: 1.0, device_id: 0, + ..CfdConfig::default() } } #[test] fn test_cuda_kernel_manager_creation() -> CfdResult<()> { let config = create_test_config(); - let _manager = CudaKernelManager::new(&config)?; + let _manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); Ok(()) } #[test] fn test_memory_operations() -> CfdResult<()> { let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); // Test allocation let size = 1000; @@ -63,7 +64,7 @@ mod cuda_tests { #[test] fn test_advection_kernel_1d() -> CfdResult<()> { let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let kernel = AdvectionKernel::new(&manager, AdvectionScheme::Upwind)?; let n = 100; @@ -99,7 +100,7 @@ mod cuda_tests { #[test] fn test_advection_kernel_2d() -> CfdResult<()> { let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let kernel = AdvectionKernel::new(&manager, AdvectionScheme::Upwind)?; let nx = 32; @@ -147,7 +148,7 @@ mod cuda_tests { #[test] fn test_diffusion_kernel_explicit() -> CfdResult<()> { let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let kernel = DiffusionKernel::new(&manager, DiffusionScheme::Explicit)?; let n = 100; @@ -182,7 +183,7 @@ mod cuda_tests { #[test] fn test_diffusion_kernel_2d() -> CfdResult<()> { let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let kernel = DiffusionKernel::new(&manager, DiffusionScheme::Explicit)?; let nx = 32; @@ -225,7 +226,7 @@ mod cuda_tests { #[test] fn test_poisson_kernel_jacobi() -> CfdResult<()> { let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let kernel = PoissonKernel::new(&manager)?; let nx = 32; @@ -267,7 +268,7 @@ mod cuda_tests { #[test] fn test_matrix_ops_tridiagonal() -> CfdResult<()> { let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let kernel = MatrixOpsKernel::new(&manager)?; let n = 100; @@ -303,7 +304,7 @@ mod cuda_tests { #[test] fn test_matrix_ops_dot_product() -> CfdResult<()> { let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let kernel = MatrixOpsKernel::new(&manager)?; let n = 1000; @@ -325,7 +326,7 @@ mod cuda_tests { #[test] fn test_matrix_ops_vector_norm() -> CfdResult<()> { let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let kernel = MatrixOpsKernel::new(&manager)?; let n = 100; @@ -345,7 +346,7 @@ mod cuda_tests { #[test] fn test_matrix_ops_axpy() -> CfdResult<()> { let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let kernel = MatrixOpsKernel::new(&manager)?; let n = 100; @@ -372,7 +373,7 @@ mod cuda_tests { #[test] fn test_performance_comparison() -> CfdResult<()> { let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let n = 10000; let host_data: Vec = (0..n).map(|i| i as f32 * 0.1).collect(); @@ -394,7 +395,7 @@ mod cuda_tests { #[test] fn test_kernel_error_handling() -> CfdResult<()> { let config = create_test_config(); - let manager = CudaKernelManager::new(&config)?; + let manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); // Test with mismatched array sizes (should not crash) let small_array = manager.allocate_f32(10)?; @@ -434,6 +435,7 @@ mod cpu_fallback_tests { reference_length: 1.0, reference_velocity: 1.0, use_gpu: true, + ..CfdConfig::default() }; let result = CudaKernelManager::new(&config); diff --git a/crates/specialized/rtx-cfd/tests/gpu_reduction_tests.rs b/crates/specialized/rtx-cfd/tests/gpu_reduction_tests.rs index 6203f10..c426fba 100644 --- a/crates/specialized/rtx-cfd/tests/gpu_reduction_tests.rs +++ b/crates/specialized/rtx-cfd/tests/gpu_reduction_tests.rs @@ -21,6 +21,7 @@ mod gpu_reduction_tests { viscosity: 0.01, density: 1.0, device_id: 0, + ..CfdConfig::default() } } diff --git a/crates/specialized/rtx-cfd/tests/kernels_tests.rs b/crates/specialized/rtx-cfd/tests/kernels_tests.rs index 0846c83..a8b8f29 100644 --- a/crates/specialized/rtx-cfd/tests/kernels_tests.rs +++ b/crates/specialized/rtx-cfd/tests/kernels_tests.rs @@ -20,7 +20,7 @@ mod cuda_tests { #[tokio::test] async fn test_advection_kernel_upwind() -> CfdResult<()> { let config = CfdConfig::new().with_gpu(true); - let kernel_manager = CudaKernelManager::new(&config)?; + let kernel_manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let advection_kernel = AdvectionKernel::new(&kernel_manager, AdvectionScheme::Upwind)?; // Test data: 1D advection with known analytical solution @@ -43,14 +43,14 @@ mod cuda_tests { let d_phi_new = kernel_manager.allocate_f32(nx)?; // Copy to GPU - kernel_manager.copy_to_device(&phi, &mut d_phi)?; + d_phi = kernel_manager.copy_to_device(&phi)?; // Run advection kernel advection_kernel.apply(&d_phi, &d_phi_new, velocity as f32, dt as f32, dx as f32)?; // Copy result back let mut result = vec![0.0f32; nx]; - kernel_manager.copy_from_device(&d_phi_new, &mut result)?; + result = kernel_manager.copy_from_device(&d_phi_new)?; // Verify that the pulse has moved (mass conservation) let initial_mass: f32 = phi.iter().sum(); @@ -82,7 +82,7 @@ mod cuda_tests { #[tokio::test] async fn test_advection_kernel_central() -> CfdResult<()> { let config = CfdConfig::new().with_gpu(true); - let kernel_manager = CudaKernelManager::new(&config)?; + let kernel_manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let advection_kernel = AdvectionKernel::new(&kernel_manager, AdvectionScheme::Central)?; // Test data: smooth sinusoidal wave @@ -100,11 +100,11 @@ mod cuda_tests { let mut d_phi = kernel_manager.allocate_f32(nx)?; let d_phi_new = kernel_manager.allocate_f32(nx)?; - kernel_manager.copy_to_device(&phi, &mut d_phi)?; + d_phi = kernel_manager.copy_to_device(&phi)?; advection_kernel.apply(&d_phi, &d_phi_new, velocity as f32, dt as f32, dx as f32)?; let mut result = vec![0.0f32; nx]; - kernel_manager.copy_from_device(&d_phi_new, &mut result)?; + result = kernel_manager.copy_from_device(&d_phi_new)?; // For central scheme, verify mass conservation and smoothness let initial_mass: f32 = phi.iter().sum(); @@ -117,7 +117,7 @@ mod cuda_tests { #[tokio::test] async fn test_diffusion_kernel_explicit() -> CfdResult<()> { let config = CfdConfig::new().with_gpu(true); - let kernel_manager = CudaKernelManager::new(&config)?; + let kernel_manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let diffusion_kernel = DiffusionKernel::new(&kernel_manager, DiffusionScheme::Explicit)?; // Test 1D heat equation with analytical solution @@ -135,11 +135,11 @@ mod cuda_tests { let mut d_temp = kernel_manager.allocate_f32(nx)?; let d_temp_new = kernel_manager.allocate_f32(nx)?; - kernel_manager.copy_to_device(&temperature, &mut d_temp)?; + d_temp = kernel_manager.copy_to_device(&temperature)?; diffusion_kernel.apply(&d_temp, &d_temp_new, alpha as f32, dt as f32, dx as f32)?; let mut result = vec![0.0f32; nx]; - kernel_manager.copy_from_device(&d_temp_new, &mut result)?; + result = kernel_manager.copy_from_device(&d_temp_new)?; // Verify diffusion: edges should be smoother, total heat conserved let initial_total: f32 = temperature.iter().sum(); @@ -160,7 +160,7 @@ mod cuda_tests { #[tokio::test] async fn test_poisson_kernel_2d() -> CfdResult<()> { let config = CfdConfig::new().with_gpu(true); - let kernel_manager = CudaKernelManager::new(&config)?; + let kernel_manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let poisson_kernel = PoissonKernel::new(&kernel_manager)?; // Test 2D Poisson equation: ∇²φ = f @@ -190,8 +190,8 @@ mod cuda_tests { let mut d_phi = kernel_manager.allocate_f32(nx * ny)?; let mut d_source = kernel_manager.allocate_f32(nx * ny)?; - kernel_manager.copy_to_device(&phi, &mut d_phi)?; - kernel_manager.copy_to_device(&source, &mut d_source)?; + d_phi = kernel_manager.copy_to_device(&phi)?; + d_source = kernel_manager.copy_to_device(&source)?; // Solve Poisson equation let max_iterations = 1000; @@ -208,7 +208,7 @@ mod cuda_tests { )?; let mut result = vec![0.0f32; nx * ny]; - kernel_manager.copy_from_device(&d_phi, &mut result)?; + result = kernel_manager.copy_from_device(&d_phi)?; // Verify against analytical solution let mut max_error = 0.0f32; @@ -233,7 +233,7 @@ mod cuda_tests { #[tokio::test] async fn test_matrix_ops_kernel() -> CfdResult<()> { let config = CfdConfig::new().with_gpu(true); - let kernel_manager = CudaKernelManager::new(&config)?; + let kernel_manager = std::sync::Arc::new(CudaKernelManager::new(&config)?); let matrix_ops = MatrixOpsKernel::new(&kernel_manager)?; // Test sparse matrix-vector multiplication (typical in CFD) @@ -246,17 +246,17 @@ mod cuda_tests { let mut d_diag = kernel_manager.allocate_f32(n)?; let mut d_off_diag = kernel_manager.allocate_f32(n - 1)?; let mut d_x = kernel_manager.allocate_f32(n)?; - let d_y = kernel_manager.allocate_f32(n)?; + let mut d_y = kernel_manager.allocate_f32(n)?; - kernel_manager.copy_to_device(&diagonal, &mut d_diag)?; - kernel_manager.copy_to_device(&off_diagonal, &mut d_off_diag)?; - kernel_manager.copy_to_device(&x, &mut d_x)?; + d_diag = kernel_manager.copy_to_device(&diagonal)?; + d_off_diag = kernel_manager.copy_to_device(&off_diagonal)?; + d_x = kernel_manager.copy_to_device(&x)?; // Perform A*x = y operation - matrix_ops.tridiagonal_matvec(&d_diag, &d_off_diag, &d_x, &d_y, n)?; + matrix_ops.tridiagonal_matvec(&d_diag, &d_off_diag, &d_x, &mut d_y)?; let mut result = vec![0.0f32; n]; - kernel_manager.copy_from_device(&d_y, &mut result)?; + result = kernel_manager.copy_from_device(&d_y)?; // Verify result manually for first few elements assert_relative_eq!(result[0], 2.0 * x[0] - x[1], epsilon = 1e-6); @@ -287,7 +287,7 @@ async fn test_kernel_manager_initialization() -> CfdResult<()> { #[cfg(feature = "cuda")] { // Should successfully create kernel manager - let result = rtx_cfd::kernels::CudaKernelManager::new(&config); + let mut result = rtx_cfd::kernels::CudaKernelManager::new(&config); // May fail if no CUDA device available - that's expected in CI match result { Ok(_) => println!("CUDA kernel manager created successfully"),