Add GPU plain SOR (Block SOR) linear solver, closing last backend gap#197
Merged
Conversation
Plain SOR is sequential (each cell depends on already-updated left/down neighbors), so a naive GPU mapping fails. The GPU variant uses red-black tile coloring: each CUDA thread sweeps an 8x8 interior tile in row-major order (Gauss-Seidel inside the tile), and tiles are colored so no two simultaneously active tiles share a halo boundary. Two kernel launches per iteration (color=0 then color=1) serve as the synchronization barrier, mirroring the existing Red-Black SOR GPU solver. The double-buffered tile design tried first diverged at optimal-omega (~1.85 on 33x33) because Jacobi-coupled tiles with omega>1 are unstable. Red-black tile coloring is a consistent ordering and is provably convergent for 0<omega<2, so auto optimal-omega works correctly. Files changed: - poisson_gpu_primitives.cuh: new lin_gpu_kernel_block_sor_tile_sweep kernel - poisson_solver_sor_gpu.cu: new solver (ctx, init, destroy, solve, factory) - linear_solver_internal.h: factory declaration under #ifdef CFD_HAS_CUDA - linear_solver.c: dispatcher case for POISSON_BACKEND_GPU / POISSON_METHOD_SOR - lib/CMakeLists.txt: add .cu to CFD_CUDA_SOURCES - CMakeLists.txt: test executable, link, and ctest registration - tests/math/test_poisson_sor_gpu.c: new test (manufactured solution, 33x33) - ROADMAP.md, .claude/CLAUDE.md, docs/reference/solvers.md: matrix updated Test result: 440 GPU iters vs 479 CPU iters, max field diff 5.567e-08, L2_gpu = L2_cpu = 2.974e-02.
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a CUDA GPU backend for the plain SOR Poisson solver using an in-place Block SOR tile sweep with red-black tile coloring, closing the remaining backend gap for SOR on GPU and adding a regression test to validate convergence and agreement with CPU SOR.
Changes:
- Introduces a new CUDA Block SOR tile-sweep kernel and a new
sor_gpupoisson_solver_tbackend implementation. - Wires the new GPU SOR backend into the linear solver factory/dispatcher and CUDA build sources.
- Adds a GPU SOR test (with graceful skip when CUDA/device is unavailable) and updates solver/backends documentation and roadmap tables.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
lib/src/solvers/linear/gpu/poisson_gpu_primitives.cuh |
Adds the Block SOR per-thread tile sweep kernel with red-black tile coloring. |
lib/src/solvers/linear/gpu/poisson_solver_sor_gpu.cu |
Implements the GPU plain SOR solver backend (init/destroy/solve + factory). |
lib/src/solvers/linear/linear_solver_internal.h |
Declares create_sor_gpu_solver() behind CFD_HAS_CUDA. |
lib/src/solvers/linear/linear_solver.c |
Dispatches POISSON_METHOD_SOR + POISSON_BACKEND_GPU to the new factory. |
lib/CMakeLists.txt |
Adds the new .cu file to CFD_CUDA_SOURCES. |
CMakeLists.txt |
Adds and registers the new test_poisson_sor_gpu executable/ctest. |
tests/math/test_poisson_sor_gpu.c |
Adds convergence + CPU consistency test for GPU plain SOR with optional-backend skip behavior. |
ROADMAP.md |
Updates the backend-gap matrix and linear-solvers roadmap status. |
docs/reference/solvers.md |
Documents the new sor_gpu backend and GPU Block SOR characteristics. |
.claude/CLAUDE.md |
Updates project matrices/docs (per PR description). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The GPU plain-SOR backend uses in-place red-black tile coloring (race-free because adjacency flips tile parity), not a double-buffered scheme — the double-buffered tile design was abandoned since it leaves tiles Jacobi-coupled and diverges at omega>1. Correct the stale 'double-buffered'/'previous-iteration' wording in the .cu comment, solvers.md, ROADMAP.md, and the test header so the docs match the implemented algorithm (PR #197 review).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Plain SOR is sequential (each cell depends on already-updated left/down neighbors), so a naive GPU mapping fails. The GPU variant uses red-black tile coloring: each CUDA thread sweeps an 8x8 interior tile in row-major order (Gauss-Seidel inside the tile), and tiles are colored so no two simultaneously active tiles share a halo boundary. Two kernel launches per iteration (color=0 then color=1) serve as the synchronization barrier, mirroring the existing Red-Black SOR GPU solver.
The double-buffered tile design tried first diverged at optimal-omega (~1.85 on 33x33) because Jacobi-coupled tiles with omega>1 are unstable. Red-black tile coloring is a consistent ordering and is provably convergent for 0<omega<2, so auto optimal-omega works correctly.
Files changed:
Test result: 440 GPU iters vs 479 CPU iters, max field diff 5.567e-08, L2_gpu = L2_cpu = 2.974e-02.