URI:
       test: add reset_column round-trip check against a fresh column run - cngf-pf - continuum model for granular flows with pore-pressure dynamics (renamed from 1d_fd_simple_shear)
  HTML git clone git://src.adamsgaard.dk/cngf-pf
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit c8a8f4d1023c7ba4fca2f979e454c42f5747dd06
   DIR parent 8ee190a791f59c6d83108b5f7018217a652f47c8
  HTML Author: Anders Damsgaard <anders@adamsgaard.dk>
       Date:   Fri,  3 Jul 2026 11:50:16 +0200
       
       test: add reset_column round-trip check against a fresh column run
       
       Diffstat:
         M test/Makefile                       |      15 ++++++++++++---
         A test/test_reset_column.c            |     140 +++++++++++++++++++++++++++++++
       
       2 files changed, 152 insertions(+), 3 deletions(-)
       ---
   DIR diff --git a/test/Makefile b/test/Makefile
       @@ -16,6 +16,7 @@ TESTS = cngf_pf_dry \
                shear_flux_dry \
                shear_flux_wet \
                test_error_path \
       +        test_reset_column \
                #cngf_pf_dry_transient \
        
        # Skipped tests:
       @@ -27,7 +28,8 @@ TESTS = cngf_pf_dry \
        
        # Self-validating tests carry no .std baseline, so exclude them from the
        # regenerable standards.
       -STANDARDS := $(filter-out cngf_pf_wet_equilibrium.std test_error_path.std,\
       +STANDARDS := $(filter-out cngf_pf_wet_equilibrium.std test_error_path.std \
       +             test_reset_column.std,\
                     $(TESTS:=.std))
        
        CNGF_PF_DRY_OPTS =          -o 0.03 -L 0.64 -n 40e3
       @@ -136,6 +138,13 @@ test_error_path: $(BIN)
                ./$@
                rm -f $@
        
       +# In-process check: rerunning a column after reset_column() must reproduce a
       +# fresh prepare_arrays() run bit for bit.
       +test_reset_column: $(BIN)
       +        $(CC) -I.. -o $@ $@.c ../simulation.o ../arrays.o ../fluid.o -lm
       +        ./$@
       +        rm -f $@
       +
        cngf_pf_dry.std: $(BIN)
                ./$(BIN) $(CNGF_PF_DRY_OPTS) > $@
        
       @@ -188,7 +197,7 @@ $(BIN):
                make -C ..
        
        clean:
       -        rm -f *.txt test_error_path
       +        rm -f *.txt test_error_path test_reset_column
        
        # Benchmark configurations for performance/stability testing
        # These are more intensive than the regression tests
       @@ -211,4 +220,4 @@ bench_wet_large:
        
        bench: bench_dry_small bench_dry_large bench_wet_small bench_wet_large
        
       -.PHONY: $(TESTS) cngf_pf_wet_equilibrium test_error_path test standards clean bench bench_dry_small bench_dry_large bench_wet_small bench_wet_large
       +.PHONY: $(TESTS) cngf_pf_wet_equilibrium test_error_path test_reset_column test standards clean bench bench_dry_small bench_dry_large bench_wet_small bench_wet_large
   DIR diff --git a/test/test_reset_column.c b/test/test_reset_column.c
       @@ -0,0 +1,140 @@
       +/*
       + * In-process check that reset_column() returns a used simulation struct to a
       + * state equivalent to a freshly prepared one: running the same column setup
       + * after a reset must reproduce a fresh run bit for bit. A host embedder
       + * (e.g. PISM) relies on this to reuse one allocated struct across many
       + * independent till columns.
       + */
       +#include <math.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +
       +#include "../fluid.h"
       +#include "../simulation.h"
       +
       +#define NSTEPS 3
       +#define PHI_TEST 0.3
       +#define K_TEST 2e-15
       +
       +static int
       +cmp(const char *name, const double *a, const double *b, int n)
       +{
       +        if (memcmp(a, b, (size_t)n * sizeof(double)) != 0) {
       +                fprintf(stderr, "error: %s differs between fresh and reset run\n",
       +                        name);
       +                return 1;
       +        }
       +        return 0;
       +}
       +
       +static int
       +setup_column(struct simulation *sim)
       +{
       +        int i;
       +
       +        for (i = 0; i < sim->nz; ++i) {
       +                sim->phi[i] = PHI_TEST;
       +                sim->k[i] = K_TEST;
       +        }
       +        hydrostatic_fluid_pressure_distribution(sim);
       +        lithostatic_pressure_distribution(sim);
       +        compute_effective_stress(sim);
       +        return set_largest_fluid_timestep(sim, 0.5);
       +}
       +
       +static int
       +run_column(struct simulation *sim)
       +{
       +        int n, ret;
       +
       +        for (n = 0; n < NSTEPS; ++n)
       +                if ((ret = coupled_shear_solver(sim, 100000, 1e-5))) {
       +                        fprintf(stderr, "error: solver returned %d at step %d\n",
       +                                ret, n);
       +                        return 1;
       +                }
       +        return 0;
       +}
       +
       +static void
       +init_column(struct simulation *sim)
       +{
       +        init_sim(sim);
       +        sim->nz = 10;
       +        sim->origo_z = 0.03;
       +        sim->L_z = 0.64;
       +        sim->P_wall = 40e3;
       +        sim->fluid = 1;
       +}
       +
       +int
       +main(void)
       +{
       +        int i, status = 0;
       +        struct simulation fresh, reused;
       +
       +        init_column(&fresh);
       +        if (prepare_arrays(&fresh)) {
       +                fprintf(stderr, "error: prepare_arrays failed\n");
       +                return 2;
       +        }
       +        if (setup_column(&fresh) || run_column(&fresh))
       +                return 2;
       +
       +        /* dirty a second struct with a different column, then reset and rerun
       +         * the same column as the fresh reference */
       +        init_column(&reused);
       +        if (prepare_arrays(&reused)) {
       +                fprintf(stderr, "error: prepare_arrays failed\n");
       +                return 2;
       +        }
       +        for (i = 0; i < reused.nz; ++i) {
       +                reused.phi[i] = 0.2;
       +                reused.k[i] = 1.9e-15;
       +        }
       +        hydrostatic_fluid_pressure_distribution(&reused);
       +        lithostatic_pressure_distribution(&reused);
       +        compute_effective_stress(&reused);
       +        if (set_largest_fluid_timestep(&reused, 0.5) || run_column(&reused))
       +                return 2;
       +
       +        reset_column(&reused);
       +        if (setup_column(&reused) || run_column(&reused))
       +                return 2;
       +
       +        status |= cmp("phi", fresh.phi, reused.phi, fresh.nz);
       +        status |= cmp("k", fresh.k, reused.k, fresh.nz);
       +        status |= cmp("v_x", fresh.v_x, reused.v_x, fresh.nz);
       +        status |= cmp("d_x", fresh.d_x, reused.d_x, fresh.nz);
       +        status |= cmp("mu", fresh.mu, reused.mu, fresh.nz);
       +        status |= cmp("mu_c", fresh.mu_c, reused.mu_c, fresh.nz);
       +        status |= cmp("sigma_n", fresh.sigma_n, reused.sigma_n, fresh.nz);
       +        status |= cmp("sigma_n_eff", fresh.sigma_n_eff, reused.sigma_n_eff,
       +                      fresh.nz);
       +        status |= cmp("gamma_dot_p", fresh.gamma_dot_p, reused.gamma_dot_p,
       +                      fresh.nz);
       +        status |= cmp("I", fresh.I, reused.I, fresh.nz);
       +        status |= cmp("tan_psi", fresh.tan_psi, reused.tan_psi, fresh.nz);
       +        status |= cmp("xi", fresh.xi, reused.xi, fresh.nz);
       +        status |= cmp("g_local", fresh.g_local, reused.g_local, fresh.nz);
       +        status |= cmp("phi_c", fresh.phi_c, reused.phi_c, fresh.nz);
       +        status |= cmp("phi_dot", fresh.phi_dot, reused.phi_dot, fresh.nz);
       +        status |= cmp("p_f_dot", fresh.p_f_dot, reused.p_f_dot, fresh.nz);
       +        status |= cmp("p_f_ghost", fresh.p_f_ghost, reused.p_f_ghost,
       +                      fresh.nz + 2);
       +        status |= cmp("p_f_next_ghost", fresh.p_f_next_ghost,
       +                      reused.p_f_next_ghost, fresh.nz + 2);
       +        status |= cmp("g_ghost", fresh.g_ghost, reused.g_ghost, fresh.nz + 2);
       +        status |= cmp("t", &fresh.t, &reused.t, 1);
       +        status |= cmp("mu_wall", &fresh.mu_wall, &reused.mu_wall, 1);
       +
       +        free_arrays(&fresh);
       +        free_arrays(&reused);
       +
       +        if (status)
       +                return 1;
       +
       +        printf("ok: reset_column reproduces a fresh column run\n");
       +        return 0;
       +}