LCOV - code coverage report
Current view: top level - solvers/linear/cpu - linear_solver_sor.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 56 56
Test Date: 2026-03-04 10:22:18 Functions: 100.0 % 4 4

            Line data    Source code
       1              : /**
       2              :  * @file linear_solver_sor.c
       3              :  * @brief Sequential SOR (Successive Over-Relaxation) solver - scalar CPU implementation
       4              :  *
       5              :  * SOR characteristics:
       6              :  * - Inherently sequential (Gauss-Seidel + relaxation)
       7              :  * - In-place updates (no temporary buffer needed)
       8              :  * - Fastest convergence per iteration
       9              :  * - Cannot be parallelized (unlike Red-Black SOR)
      10              :  */
      11              : 
      12              : #include "../linear_solver_internal.h"
      13              : 
      14              : #include "cfd/boundary/boundary_conditions.h"
      15              : #include "cfd/core/indexing.h"
      16              : #include "cfd/core/memory.h"
      17              : 
      18              : #include <math.h>
      19              : 
      20              : /* ============================================================================
      21              :  * SOR CONTEXT
      22              :  * ============================================================================ */
      23              : 
      24              : typedef struct {
      25              :     double dx2;        /* dx^2 */
      26              :     double dy2;        /* dy^2 */
      27              :     double inv_dz2;
      28              :     double inv_factor; /* 1 / (2 * (1/dx^2 + 1/dy^2)) */
      29              :     double omega;      /* SOR relaxation parameter */
      30              :     size_t stride_z;
      31              :     size_t k_start;
      32              :     size_t k_end;
      33              :     int initialized;
      34              : } sor_context_t;
      35              : 
      36              : /* ============================================================================
      37              :  * SOR SCALAR IMPLEMENTATION
      38              :  * ============================================================================ */
      39              : 
      40           21 : static cfd_status_t sor_scalar_init(
      41              :     poisson_solver_t* solver,
      42              :     size_t nx, size_t ny, size_t nz,
      43              :     double dx, double dy, double dz,
      44              :     const poisson_solver_params_t* params)
      45              : {
      46           21 :     sor_context_t* ctx = (sor_context_t*)cfd_calloc(1, sizeof(sor_context_t));
      47           21 :     if (!ctx) {
      48              :         return CFD_ERROR_NOMEM;
      49              :     }
      50              : 
      51           21 :     ctx->dx2 = dx * dx;
      52           21 :     ctx->dy2 = dy * dy;
      53           21 :     ctx->inv_dz2 = poisson_solver_compute_inv_dz2(dz);
      54           21 :     poisson_solver_compute_3d_bounds(nz, nx, ny,
      55              :         &ctx->stride_z, &ctx->k_start, &ctx->k_end);
      56              : 
      57           21 :     double factor = 2.0 * (1.0 / ctx->dx2 + 1.0 / ctx->dy2 + ctx->inv_dz2);
      58           21 :     ctx->inv_factor = 1.0 / factor;
      59           21 :     ctx->omega = params ? params->omega : 1.5;
      60           21 :     ctx->initialized = 1;
      61              : 
      62           21 :     solver->context = ctx;
      63           21 :     return CFD_SUCCESS;
      64              : }
      65              : 
      66           22 : static void sor_scalar_destroy(poisson_solver_t* solver) {
      67           22 :     if (solver && solver->context) {
      68           21 :         cfd_free(solver->context);
      69           21 :         solver->context = NULL;
      70              :     }
      71           22 : }
      72              : 
      73              : /**
      74              :  * Sequential SOR iteration
      75              :  *
      76              :  * Updates cells in row-major order, using already-updated values
      77              :  * from the current iteration (Gauss-Seidel behavior).
      78              :  */
      79        57021 : static cfd_status_t sor_scalar_iterate(
      80              :     poisson_solver_t* solver,
      81              :     double* x,
      82              :     double* x_temp,
      83              :     const double* rhs,
      84              :     double* residual)
      85              : {
      86        57021 :     (void)x_temp;  /* Not needed for in-place SOR */
      87              : 
      88        57021 :     sor_context_t* ctx = (sor_context_t*)solver->context;
      89        57021 :     size_t nx = solver->nx;
      90        57021 :     size_t ny = solver->ny;
      91        57021 :     double dx2 = ctx->dx2;
      92        57021 :     double dy2 = ctx->dy2;
      93        57021 :     double inv_factor = ctx->inv_factor;
      94        57021 :     double omega = ctx->omega;
      95              : 
      96        57021 :     size_t stride_z = ctx->stride_z;
      97        57021 :     double inv_dz2 = ctx->inv_dz2;
      98              : 
      99              :     /* Single sweep: row-major order */
     100       118214 :     for (size_t k = ctx->k_start; k < ctx->k_end; k++) {
     101      2046456 :         for (size_t j = 1; j < ny - 1; j++) {
     102     80209616 :             for (size_t i = 1; i < nx - 1; i++) {
     103     78224353 :                 size_t idx = k * stride_z + IDX_2D(i, j, nx);
     104              : 
     105              :                 /* Compute Gauss-Seidel update
     106              :                  * Note: x[idx-1] and x[idx-nx] are already updated this iteration
     107              :                  */
     108     78224353 :                 double p_new = -(rhs[idx]
     109     78224353 :                     - (x[idx + 1] + x[idx - 1]) / dx2
     110     78224353 :                     - (x[idx + nx] + x[idx - nx]) / dy2
     111     78224353 :                     - (x[idx + stride_z] + x[idx - stride_z]) * inv_dz2
     112              :                     ) * inv_factor;
     113              : 
     114              :                 /* SOR relaxation */
     115     78224353 :                 x[idx] = x[idx] + omega * (p_new - x[idx]);
     116              :             }
     117              :         }
     118              :     }
     119              : 
     120              :     /* Apply boundary conditions */
     121        57021 :     poisson_solver_apply_bc(solver, x);
     122              : 
     123              :     /* Compute residual if requested */
     124        57021 :     if (residual) {
     125        57021 :         *residual = poisson_solver_compute_residual(solver, x, rhs);
     126              :     }
     127              : 
     128        57021 :     return CFD_SUCCESS;
     129              : }
     130              : 
     131              : /* ============================================================================
     132              :  * FACTORY FUNCTION
     133              :  * ============================================================================ */
     134              : 
     135           22 : poisson_solver_t* create_sor_scalar_solver(void) {
     136           22 :     poisson_solver_t* solver = (poisson_solver_t*)cfd_calloc(1, sizeof(poisson_solver_t));
     137           22 :     if (!solver) {
     138              :         return NULL;
     139              :     }
     140              : 
     141           22 :     solver->name = POISSON_SOLVER_TYPE_SOR_SCALAR;
     142           22 :     solver->description = "SOR iteration (scalar CPU, sequential)";
     143           22 :     solver->method = POISSON_METHOD_SOR;
     144           22 :     solver->backend = POISSON_BACKEND_SCALAR;
     145           22 :     solver->params = poisson_solver_params_default();
     146              : 
     147           22 :     solver->init = sor_scalar_init;
     148           22 :     solver->destroy = sor_scalar_destroy;
     149           22 :     solver->solve = NULL;  /* Use common solve loop */
     150           22 :     solver->iterate = sor_scalar_iterate;
     151           22 :     solver->apply_bc = NULL;  /* Use default Neumann */
     152              : 
     153           22 :     return solver;
     154              : }
        

Generated by: LCOV version 2.0-1