BIN = ../cngf-pf
BIN2 = ../max_depth_simple_shear
BIN3 = ../shear_flux

TESTS = cngf_pf_dry \
	cngf_pf_dry_norm \
	cngf_pf_dry_cohesive \
	cngf_pf_dry_vconst \
	cngf_pf_wet \
	cngf_pf_wet_equilibrium \
	cngf_pf_wet_equilibrium_darcy \
	cngf_pf_wet_norm \
	cngf_pf_wet_vari \
	cngf_pf_wet_vari_diff \
	cngf_pf_wet_vari_pulse \
	cngf_pf_wet_vari_pulse_vlim \
	shear_flux_dry \
	shear_flux_wet \
	test_error_path \
	test_reset_column \
	#cngf_pf_dry_transient \

# Skipped tests:
# - cngf_pf_dry_trans_undercons, cngf_pf_dry_trans_overcons:
#   Transient mode with fixed velocity and non-critical porosity has
#   coupled solver instability (see walkthrough for details)
# - max_depth_misc: test config uses removed -O option


# Self-validating tests carry no .std baseline, so exclude them from the
# regenerable standards.
STANDARDS := $(filter-out cngf_pf_wet_equilibrium.std \
             cngf_pf_wet_equilibrium_darcy.std test_error_path.std \
             test_reset_column.std,\
             $(TESTS:=.std))

CNGF_PF_DRY_OPTS =          -o 0.03 -L 0.64 -n 40e3
CNGF_PF_DRY_NORM_OPTS =     -o 0.03 -L 0.64 -n 40e3 -N
CNGF_PF_DRY_COHESIVE_OPTS = -o 0.03 -L 0.64 -n 40e3 -c 1e3
CNGF_PF_DRY_VCONST_OPTS =   -s 1e-3
CNGF_PF_WET_OPTS =          -o 0.03 -L 0.64 -n 40e3 -F
CNGF_PF_WET_NORM_OPTS =     -o 0.03 -L 0.64 -n 40e3 -F -N
CNGF_PF_WET_VARI_OPTS =     -L 8.0 \
                            -n 150e3 \
                            -F -k 2e-17 \
                            -O 50e3 \
                            -a 50e3 \
                            -q $$( echo "1.0/(3600*24)" | bc -l ) \
                            -I $$( echo "60*1000" | bc -l ) \
                            -e $$( echo "60*20" | bc -l )
CNGF_PF_WET_VARI_DIFF_OPTS =-L 8.0 \
                            -n 150e3 \
                            -F -D $$(awk 'BEGIN{print 2e-17/(1.787e-3*(1e-8 + 0.25*3.9e-10))}') \
                            -O 50e3 \
                            -a 50e3 \
                            -q $$( echo "1.0/(3600*24)" | bc -l ) \
                            -I $$( echo "60*1000" | bc -l ) \
                            -e $$( echo "60*20" | bc -l )
CNGF_PF_WET_VARI_PULSE_OPTS = $(CNGF_PF_WET_VARI_OPTS) \
                              -u 500
CNGF_PF_WET_VARI_PULSE_VLIM_OPTS = $(CNGF_PF_WET_VARI_OPTS) \
                                   -u 500 -l 1e-3
CNGF_PF_DRY_TRANS_OPTS = -T -e 5.0
CNGF_PF_DRY_TRANS_UNDERCONS_OPTS = -T -e 100.0 -I 1.0 -s 0.01 -p 0.25 trans_undercons >/dev/null && \
                                   for f in trans_undercons.output*.txt; do tail -n 1 "$$f"; done
CNGF_PF_DRY_TRANS_OVERCONS_OPTS = -T -e 100.0 -I 1.0 -s 0.01 -p 0.15 trans_overcons >/dev/null && \
                                  for f in trans_overcons.output*.txt; do tail -n 1 "$$f"; done

MAX_DEPTH_MISC = sh -c 'for A_f in 1e3 5e3 10e3 50e3 100e3; \
                        	do ./$(BIN2) -O 101e3 -a $$A_f -q 0.01;\
                        	./$(BIN2) -O 101e3 -a $$A_f -q 0.001;\
                        	./$(BIN2) -O 101e3 -a $$A_f -q 0.0001; done'

test: $(TESTS)

standards: $(STANDARDS)

cngf_pf_dry: $(BIN)
	./$(BIN) $(CNGF_PF_DRY_OPTS) | diff $@.std -

cngf_pf_dry_norm: $(BIN)
	./$(BIN) $(CNGF_PF_DRY_NORM_OPTS) | diff $@.std -

cngf_pf_dry_cohesive: $(BIN)
	./$(BIN) $(CNGF_PF_DRY_COHESIVE_OPTS) | diff $@.std -

cngf_pf_dry_vconst: $(BIN)
	./$(BIN) $(CNGF_PF_DRY_VCONST_OPTS) | diff $@.std -

cngf_pf_wet: $(BIN)
	./$(BIN) $(CNGF_PF_WET_OPTS) | diff $@.std -

# Self-validating invariant (no .std baseline): starting from the hydrostatic
# initial state with a constant top pressure and no forcing, the profile must
# stay hydrostatic, so the top physical node must equal p_f_top (0 Pa here).
cngf_pf_wet_equilibrium: $(BIN)
	./$(BIN) $(CNGF_PF_WET_OPTS) | tail -n1 | \
	awk '{ d = $$4; if (d < 0) d = -d; \
	       if (d > 1.0) { \
	         printf "error: top p_f deviates from p_f_top: %s Pa\n", $$4; \
	         exit 1 } }'

# Same invariant, but over multiple timesteps so the Darcy solver actually
# runs (it is gated on t > 0): with constant p_f_top and uniform porosity the
# hydrostatic profile is a steady state of the Darcy system, so the top
# physical node must stay at p_f_top (0 Pa here).
cngf_pf_wet_equilibrium_darcy: $(BIN)
	./$(BIN) $(CNGF_PF_WET_OPTS) -e 60 -I 60 | tail -n1 | \
	awk '{ d = $$4; if (d < 0) d = -d; \
	       if (d > 1.0) { \
	         printf "error: top p_f deviates from p_f_top: %s Pa\n", $$4; \
	         exit 1 } }'

cngf_pf_wet_norm: $(BIN)
	./$(BIN) $(CNGF_PF_WET_NORM_OPTS) | diff $@.std -

cngf_pf_wet_vari: $(BIN)
	./$(BIN) $(CNGF_PF_WET_VARI_OPTS) | diff $@.std -

cngf_pf_wet_vari_diff: $(BIN)
	./$(BIN) $(CNGF_PF_WET_VARI_DIFF_OPTS) | diff $@.std -

cngf_pf_wet_vari_pulse: $(BIN)
	./$(BIN) $(CNGF_PF_WET_VARI_PULSE_OPTS) | diff $@.std -

cngf_pf_wet_vari_pulse_vlim: $(BIN)
	./$(BIN) $(CNGF_PF_WET_VARI_PULSE_VLIM_OPTS) | diff $@.std -

cngf_pf_dry_transient: $(BIN)
	./$(BIN) $(CNGF_PF_DRY_TRANS_OPTS) | diff $@.std -

cngf_pf_dry_trans_undercons: $(BIN)
	./$(BIN) $(CNGF_PF_DRY_TRANS_UNDERCONS_OPTS) | diff $@.std -

cngf_pf_dry_trans_overcons: $(BIN)
	./$(BIN) $(CNGF_PF_DRY_TRANS_OVERCONS_OPTS) | diff $@.std -

max_depth_misc: $(BIN2)
	$(MAX_DEPTH_MISC) | diff $@.std -

shear_flux_dry: $(BIN) $(BIN3)
	./$(BIN) $(CNGF_PF_DRY_OPTS) | ./$(BIN3) | diff $@.std -

shear_flux_wet: $(BIN)
	./$(BIN) $(CNGF_PF_WET_OPTS) | ./$(BIN3) | diff $@.std -

# In-process check: a non-converging solver must return a non-zero code
# instead of terminating the process.
test_error_path: $(BIN)
	$(CC) -I.. -o $@ $@.c ../simulation.o ../arrays.o ../fluid.o -lm
	./$@
	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) > $@

cngf_pf_dry_norm.std: $(BIN)
	./$(BIN) $(CNGF_PF_DRY_NORM_OPTS) > $@

cngf_pf_dry_cohesive.std: $(BIN)
	./$(BIN) $(CNGF_PF_DRY_COHESIVE_OPTS) > $@

cngf_pf_dry_vconst.std: $(BIN)
	./$(BIN) $(CNGF_PF_DRY_VCONST_OPTS) > $@

cngf_pf_wet.std: $(BIN)
	./$(BIN) $(CNGF_PF_WET_OPTS) > $@

cngf_pf_wet_norm.std: $(BIN)
	./$(BIN) $(CNGF_PF_WET_NORM_OPTS) > $@

cngf_pf_wet_vari.std: $(BIN)
	./$(BIN) $(CNGF_PF_WET_VARI_OPTS) > $@

cngf_pf_wet_vari_diff.std: $(BIN)
	./$(BIN) $(CNGF_PF_WET_VARI_DIFF_OPTS) > $@

cngf_pf_wet_vari_pulse.std: $(BIN)
	./$(BIN) $(CNGF_PF_WET_VARI_PULSE_OPTS) > $@

cngf_pf_wet_vari_pulse_vlim.std: $(BIN)
	./$(BIN) $(CNGF_PF_WET_VARI_PULSE_VLIM_OPTS) > $@

cngf_pf_dry_transient.std: $(BIN)
	./$(BIN) $(CNGF_PF_DRY_TRANS_OPTS) > $@

cngf_pf_dry_trans_undercons.std: $(BIN)
	./$(BIN) $(CNGF_PF_DRY_TRANS_UNDERCONS_OPTS) > $@

cngf_pf_dry_trans_overcons.std: $(BIN)
	./$(BIN) $(CNGF_PF_DRY_TRANS_OVERCONS_OPTS) > $@

max_depth_misc.std: $(BIN2)
	$(MAX_DEPTH_MISC) > $@

shear_flux_dry.std: $(BIN) $(BIN3)
	./$(BIN) $(CNGF_PF_DRY_OPTS) | ./$(BIN3) > $@

shear_flux_wet.std: $(BIN) $(BIN3)
	./$(BIN) $(CNGF_PF_WET_OPTS) | ./$(BIN3) > $@

$(BIN):
	make -C ..

clean:
	rm -f *.txt test_error_path test_reset_column

# Benchmark configurations for performance/stability testing
# These are more intensive than the regression tests
BENCH_DRY_SMALL = -o 0.03 -L 0.64 -n 40e3
BENCH_DRY_LARGE = -L 10.0 -n 200e3 -e 10.0
BENCH_WET_SMALL = -o 0.03 -L 0.64 -n 40e3 -F
BENCH_WET_LARGE = -L 8.0 -n 150e3 -F -k 2e-17 -O 50e3 -a 50e3 -q 0.0000115741 -e 3600

bench_dry_small:
	./$(BIN) -B $(BENCH_DRY_SMALL) 2>&1

bench_dry_large:
	./$(BIN) -B $(BENCH_DRY_LARGE) 2>&1

bench_wet_small:
	./$(BIN) -B $(BENCH_WET_SMALL) 2>&1

bench_wet_large:
	./$(BIN) -B $(BENCH_WET_LARGE) 2>&1

bench: bench_dry_small bench_dry_large bench_wet_small bench_wet_large

.PHONY: $(TESTS) cngf_pf_wet_equilibrium cngf_pf_wet_equilibrium_darcy test_error_path test_reset_column test standards clean bench bench_dry_small bench_dry_large bench_wet_small bench_wet_large
