cngf-pf

continuum model for granular flows with pore-pressure dynamics (renamed from 1d_fd_simple_shear)
git clone git://src.adamsgaard.dk/cngf-pf # fast
git clone https://src.adamsgaard.dk/cngf-pf.git # slow
Log | Files | Refs | README | LICENSE Back to index

commit 92b06adca3562c68372cf40983590ddea9c3f17e
parent b61f9f0ce52b135939c72bb5294f607638bd9dd1
Author: Anders Damsgaard <anders@adamsgaard.dk>
Date:   Wed, 14 Jan 2026 23:01:20 +0100

refactor(fluid): remove unused epsilon and untrack merge_request.md

Diffstat:
Mfluid.c | 51++++++---------------------------------------------
Mfluid.h | 4+---
Dmerge_request.md | 37-------------------------------------
Msimulation.c | 8+++-----
4 files changed, 10 insertions(+), 90 deletions(-)

diff --git a/fluid.c b/fluid.c @@ -196,23 +196,12 @@ static double darcy_pressure_change_1d_impl( } } -int darcy_solver_1d(struct simulation *sim, const int max_iter, - const double rel_tol) { - int i, iter, solved = 0; - double epsilon, p_f_top, omega, r_norm_max = NAN, *k_n, *phi_n; +int darcy_solver_1d(struct simulation *sim) { + int i, solved = 0; + double p_f_top, *k_n, *phi_n; copy_values(sim->p_f_dot, sim->p_f_dot_old, sim->nz); - /* choose integration method, parameter in [0.0; 1.0] - * epsilon = 0.0: explicit - * epsilon = 0.5: Crank-Nicolson - * epsilon = 1.0: implicit */ - epsilon = 0.5; - - /* underrelaxation parameter in ]0.0; 1.0], - * where omega = 1.0: no underrelaxation */ - omega = 1.0; - for (i = 0; i < sim->nz; ++i) sim->p_f_dot_impl[i] = sim->p_f_dot_expl[i] = 0.0; @@ -232,19 +221,8 @@ int darcy_solver_1d(struct simulation *sim, const int max_iter, set_fluid_bcs(sim->p_f_ghost, sim, p_f_top); set_fluid_bcs(sim->p_f_next_ghost, sim, p_f_top); - /* explicit solution to pressure change */ - if (epsilon < 1.0) { -#ifdef DEBUG - printf("\nEXPLICIT SOLVER IN %s\n", __func__); -#endif - for (i = 0; i < sim->nz - 1; ++i) - sim->p_f_dot_expl[i] = darcy_pressure_change_1d( - i, sim->nz, sim->p_f_ghost, sim->phi, sim->phi_dot, sim->k, sim->dz, - sim->beta_f, sim->alpha, sim->mu_f, sim->D); - } - /* implicit solution with TDMA */ - if (epsilon > 0.0) { + { #ifdef DEBUG printf("\nIMPLICIT SOLVER IN %s\n", __func__); #endif @@ -327,22 +305,8 @@ int darcy_solver_1d(struct simulation *sim, const int max_iter, /* Apply Boundary Conditions to Linear System */ /* Bottom (i=0): Neumann. p_{-1} = p_0 + C. */ - double bc_neumann_val; - if (sim->D > 0.0) { - /* For D > 0, we still use the ghost nodes set by set_fluid_bcs. - p_ghost[0] = p_ghost[1] + ... - The 'a[0]*p_{-1}' logic requires a[0] to be valid. - For D>0, a[0] = -coeff. - Equation: a[0]*p_{-1} + b[0]*p_0 + c[0]*p_1 = d[0]. - Substitute p_{-1} = p_0 + C. - a[0]*p_0 + a[0]*C + b[0]*p_0 + c[0]*p_1 = d[0]. - (a[0]+b[0])*p_0 + c[0]*p_1 = d[0] - a[0]*C. - Same algebra applies. - */ - bc_neumann_val = sim->phi[0] * sim->rho_f * sim->G * sim->dz; - } else { - bc_neumann_val = sim->phi[0] * sim->rho_f * sim->G * sim->dz; - } + /* Bottom (i=0): Neumann. p_{-1} = p_0 + C. */ + double bc_neumann_val = sim->phi[0] * sim->rho_f * sim->G * sim->dz; b[0] += a[0]; d[0] -= a[0] * bc_neumann_val; @@ -376,8 +340,6 @@ int darcy_solver_1d(struct simulation *sim, const int max_iter, add_darcy_iters(1); solved = 1; - } else { - /* Explicit mode skipped */ } for (i = 0; i < sim->nz - 1; ++i) @@ -387,7 +349,6 @@ int darcy_solver_1d(struct simulation *sim, const int max_iter, set_fluid_bcs(sim->p_f_ghost, sim, p_f_top); set_fluid_bcs(sim->p_f_next_ghost, sim, p_f_top); #ifdef DEBUG - printf(".. epsilon = %g\n", epsilon); puts(".. p_f_dot_expl:"); print_array(sim->p_f_dot_expl, sim->nz); puts(".. p_f_dot_impl:"); diff --git a/fluid.h b/fluid.h @@ -9,9 +9,7 @@ void hydrostatic_fluid_pressure_distribution(struct simulation *sim); int set_largest_fluid_timestep(struct simulation *sim, const double safety); -int darcy_solver_1d(struct simulation *sim, - const int max_iter, - const double rel_tol); +int darcy_solver_1d(struct simulation *sim); void add_darcy_iters(int iters); diff --git a/merge_request.md b/merge_request.md @@ -1,37 +0,0 @@ -# Merge Request: Numerical Performance Optimizations - -## Overview -This MR implements significant numerical performance optimizations for the `cngf-pf` solver. The primary change involves replacing iterative solvers for the Poisson and Darcy equations with direct Tridiagonal Matrix Algorithm (TDMA) solvers. - -**Branch**: `feat/numerical-optimization` - -## Changes - -### 1. Solvers -- **Poisson Equation (`simulation.c`)**: Replaced the iterative Successive Over-Relaxation (SOR) solver with a direct TDMA solver. -- **Darcy Equation (`fluid.c`)**: Replaced the iterative implicit solver (Crank-Nicolson) with a Fully Implicit direct TDMA solver. - - *Note*: This change improves stability and performance but modifies the time integration scheme from 2nd order (CN) to 1st order (Backward Euler), resulting in unconditional stability. - - **Correction**: Updated Top BC handling to correctly respect hydrostatic corrections (ghost nodes). - - **Feature**: Added support for constant diffusivity mode (`-D`) in the TDMA path. - -### 2. Math & Build -- **Micro-optimizations**: Replaced `pow(x, 2.0)` and `pow(x, 3.0)` with direct multiplication. -- **Loop Fusion**: Fused adjacent loops in `coupled_shear_solver` to improve cache locality. -- **Compiler Flags**: Added `-O3 -march=native -flto` to `Makefile`. - -## Performance Results -Benchmarks run on the `wet_large` test case (most intensive): - -| Metric | Baseline | Optimized | Improvement | -| :--- | :--- | :--- | :--- | -| **Elapsed Time** | 0.115s | 0.015s | **7.7x Speedup** | -| **Poisson Iterations** | 24,435 | 3,600 | **6.8x Reduction** | -| **Darcy Iterations** | 10,405 | 3,599 | **2.9x Reduction** | - -## Verification -- **Correctness**: Validated using `test/accuracy.sh`. -- **Regression Tests**: All standard tests passed (`make test`). Standard output files (`test/*.std`) were updated to reflect the improved precision and the solver change. -- **Stability**: The transition to a Fully Implicit Darcy solver provides unconditional linear stability. - -## Artifacts -- [Walkthrough](walkthrough.md): Detailed verification report and benchmark logs. diff --git a/simulation.c b/simulation.c @@ -609,9 +609,7 @@ void tridiagonal_solver(double *x, const double *a, const double *b, free(d_prime); } -static int implicit_1d_sor_poisson_solver(struct simulation *sim, - const int max_iter, - const double rel_tol) { +static int implicit_1d_sor_poisson_solver(struct simulation *sim) { /* * Replaced SOR solver with direct TDMA solver. * System: -0.5*g[i-1] + (1 + C)*g[i] - 0.5*g[i+1] = C*g_local[i] @@ -786,7 +784,7 @@ int coupled_shear_solver(struct simulation *sim, const int max_iter, /* step 5, Eq. 13 */ if (sim->fluid && (sim->t > 0)) - if (darcy_solver_1d(sim, MAX_ITER_DARCY, 1e-3 * rel_tol)) + if (darcy_solver_1d(sim)) exit(11); /* step 6 */ @@ -797,7 +795,7 @@ int coupled_shear_solver(struct simulation *sim, const int max_iter, compute_cooperativity_length(sim); /* Eq. 12 */ /* step 8, Eq. 11 */ - if (implicit_1d_sor_poisson_solver(sim, MAX_ITER_GRANULAR, rel_tol)) + if (implicit_1d_sor_poisson_solver(sim)) exit(12); /* step 9 */