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-06-23 13:41:07 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           23 : 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           23 :     sor_context_t* ctx = (sor_context_t*)cfd_calloc(1, sizeof(sor_context_t));
      47           23 :     if (!ctx) {
      48              :         return CFD_ERROR_NOMEM;
      49              :     }
      50              : 
      51           23 :     ctx->dx2 = dx * dx;
      52           23 :     ctx->dy2 = dy * dy;
      53           23 :     ctx->inv_dz2 = poisson_solver_compute_inv_dz2(dz);
      54           23 :     poisson_solver_compute_3d_bounds(nz, nx, ny,
      55              :         &ctx->stride_z, &ctx->k_start, &ctx->k_end);
      56              : 
      57           23 :     double factor = 2.0 * (1.0 / ctx->dx2 + 1.0 / ctx->dy2 + ctx->inv_dz2);
      58           23 :     ctx->inv_factor = 1.0 / factor;
      59           23 :     ctx->omega = poisson_solver_resolve_omega(
      60              :         params ? params->omega : 0.0, nx, ny, nz, dx, dy, dz);
      61           23 :     ctx->initialized = 1;
      62              : 
      63           23 :     solver->context = ctx;
      64           23 :     return CFD_SUCCESS;
      65              : }
      66              : 
      67           24 : static void sor_scalar_destroy(poisson_solver_t* solver) {
      68           24 :     if (solver && solver->context) {
      69           23 :         cfd_free(solver->context);
      70           23 :         solver->context = NULL;
      71              :     }
      72           24 : }
      73              : 
      74              : /**
      75              :  * Sequential SOR iteration
      76              :  *
      77              :  * Updates cells in row-major order, using already-updated values
      78              :  * from the current iteration (Gauss-Seidel behavior).
      79              :  */
      80        57681 : static cfd_status_t sor_scalar_iterate(
      81              :     poisson_solver_t* solver,
      82              :     double* x,
      83              :     double* x_temp,
      84              :     const double* rhs,
      85              :     double* residual)
      86              : {
      87        57681 :     (void)x_temp;  /* Not needed for in-place SOR */
      88              : 
      89        57681 :     sor_context_t* ctx = (sor_context_t*)solver->context;
      90        57681 :     size_t nx = solver->nx;
      91        57681 :     size_t ny = solver->ny;
      92        57681 :     double dx2 = ctx->dx2;
      93        57681 :     double dy2 = ctx->dy2;
      94        57681 :     double inv_factor = ctx->inv_factor;
      95        57681 :     double omega = ctx->omega;
      96              : 
      97        57681 :     size_t stride_z = ctx->stride_z;
      98        57681 :     double inv_dz2 = ctx->inv_dz2;
      99              : 
     100              :     /* Single sweep: row-major order */
     101       119534 :     for (size_t k = ctx->k_start; k < ctx->k_end; k++) {
     102      2057016 :         for (size_t j = 1; j < ny - 1; j++) {
     103     80368016 :             for (size_t i = 1; i < nx - 1; i++) {
     104     78372853 :                 size_t idx = k * stride_z + IDX_2D(i, j, nx);
     105              : 
     106              :                 /* Compute Gauss-Seidel update
     107              :                  * Note: x[idx-1] and x[idx-nx] are already updated this iteration
     108              :                  */
     109     78372853 :                 double p_new = -(rhs[idx]
     110     78372853 :                     - (x[idx + 1] + x[idx - 1]) / dx2
     111     78372853 :                     - (x[idx + nx] + x[idx - nx]) / dy2
     112     78372853 :                     - (x[idx + stride_z] + x[idx - stride_z]) * inv_dz2
     113              :                     ) * inv_factor;
     114              : 
     115              :                 /* SOR relaxation */
     116     78372853 :                 x[idx] = x[idx] + omega * (p_new - x[idx]);
     117              :             }
     118              :         }
     119              :     }
     120              : 
     121              :     /* Apply boundary conditions */
     122        57681 :     poisson_solver_apply_bc(solver, x);
     123              : 
     124              :     /* Compute residual if requested */
     125        57681 :     if (residual) {
     126        57681 :         *residual = poisson_solver_compute_residual(solver, x, rhs);
     127              :     }
     128              : 
     129        57681 :     return CFD_SUCCESS;
     130              : }
     131              : 
     132              : /* ============================================================================
     133              :  * FACTORY FUNCTION
     134              :  * ============================================================================ */
     135              : 
     136           24 : poisson_solver_t* create_sor_scalar_solver(void) {
     137           24 :     poisson_solver_t* solver = (poisson_solver_t*)cfd_calloc(1, sizeof(poisson_solver_t));
     138           24 :     if (!solver) {
     139              :         return NULL;
     140              :     }
     141              : 
     142           24 :     solver->name = POISSON_SOLVER_TYPE_SOR_SCALAR;
     143           24 :     solver->description = "SOR iteration (scalar CPU, sequential)";
     144           24 :     solver->method = POISSON_METHOD_SOR;
     145           24 :     solver->backend = POISSON_BACKEND_SCALAR;
     146           24 :     solver->params = poisson_solver_params_default();
     147              : 
     148           24 :     solver->init = sor_scalar_init;
     149           24 :     solver->destroy = sor_scalar_destroy;
     150           24 :     solver->solve = NULL;  /* Use common solve loop */
     151           24 :     solver->iterate = sor_scalar_iterate;
     152           24 :     solver->apply_bc = NULL;  /* Use default Neumann */
     153              : 
     154           24 :     return solver;
     155              : }
        

Generated by: LCOV version 2.0-1