commit c8a8f4d1023c7ba4fca2f979e454c42f5747dd06
parent 8ee190a791f59c6d83108b5f7018217a652f47c8
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:
2 files changed, 152 insertions(+), 3 deletions(-)
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
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;
+}