11SHELL = bash
2- MPIRUN ?= mpirun
32
3+ # User-defined configuration
44-include config.mk
55
6+ # Default configurations
7+ MPIRUN ?= mpirun
8+ DO_REPRO_TESTS ?= true
9+
610# ---
711# Dependencies
812BASE = $(dir $(abspath $(lastword $(MAKEFILE_LIST ) ) ) ) /..
@@ -36,42 +40,53 @@ MKMF_TEMPLATE ?= $(DEPS)/mkmf/templates/ncrc-gnu.mk
3640# Test configuration
3741
3842# Executables
39- BUILDS = symmetric asymmetric repro
40- CONFIGS := $(foreach n,$(shell seq 0 3) ,tc$(n ) )
41- TESTS = grids layouts restarts repros nans dims
43+ BUILDS = symmetric asymmetric repro openmp
44+ CONFIGS := $(wildcard tc* )
45+ TESTS = grids layouts restarts nans dims openmps
46+
47+ # REPRO tests enable reproducibility with optimization, and often do not match
48+ # the DEBUG results in older GCCs and vendor compilers, so we can optionally
49+ # disable them.
50+ ifeq ($(DO_REPRO_TESTS ) , true)
51+ BUILDS += repro
52+ TESTS += repros
53+ endif
4254
4355# The following variables are configured by Travis:
4456# DO_REGRESSION_TESTS: true if $(TRAVIS_PULL_REQUEST) is a PR number
4557# MOM_TARGET_SLUG: TRAVIS_REPO_SLUG
4658# MOM_TARGET_LOCAL_BRANCH: TRAVIS_BRANCH
47- #
48- # These are set to true by Travis if testing a pull request
59+
60+ # These are set to true by our Travis configuration if testing a pull request
4961DO_REGRESSION_TESTS ?=
5062REPORT_COVERAGE ?=
5163
5264ifeq ($(DO_REGRESSION_TESTS ) , true)
53- BUILDS += target
54- TEST += regressions
65+ BUILDS += target
66+ TESTS += regressions
5567
56- MOM_TARGET_SLUG ?= NOAA-GFDL/MOM6
57- MOM_TARGET_URL ?= https://github.com/$(MOM_TARGET_SLUG)
68+ MOM_TARGET_SLUG ?= NOAA-GFDL/MOM6
69+ MOM_TARGET_URL ?= https://github.com/$(MOM_TARGET_SLUG )
5870
59- MOM_TARGET_LOCAL_BRANCH ?= dev/gfdl
60- MOM_TARGET_BRANCH := origin/$(MOM_TARGET_LOCAL_BRANCH)
71+ MOM_TARGET_LOCAL_BRANCH ?= dev/gfdl
72+ MOM_TARGET_BRANCH := origin/$(MOM_TARGET_LOCAL_BRANCH )
6173
62- TARGET_CODEBASE = $(BUILD)/target_codebase
74+ TARGET_CODEBASE = $(BUILD ) /target_codebase
6375else
64- MOM_TARGET_URL =
65- MOM_TARGET_BRANCH =
66- TARGET_CODEBASE =
76+ MOM_TARGET_URL =
77+ MOM_TARGET_BRANCH =
78+ TARGET_CODEBASE =
6779endif
6880
81+ SOURCE = $(wildcard $(BASE ) /src/* /* .F90 $(BASE ) /src/* /* /* .F90 $(BASE ) /config_src/solo_driver/* .F90)
82+
6983
7084# ---
7185# Rules
7286
73- .PHONY : all
87+ .PHONY : all build.regressions
7488all : $(foreach b,$(BUILDS ) ,$(BUILD ) /$(b ) /MOM6)
89+ build.regressions : $(foreach b,symmetric target,$(BUILD ) /$(b ) /MOM6)
7590
7691# Executable
7792BUILD_TARGETS = MOM6 Makefile path_names
@@ -84,6 +99,7 @@ $(BUILD)/target/MOM6: MOMFLAGS=NETCDF=3 DEBUG=1
8499$(BUILD ) /symmetric/MOM6 : MOMFLAGS=NETCDF=3 DEBUG=1 $(COVFLAG )
85100$(BUILD ) /asymmetric/MOM6 : MOMFLAGS=NETCDF=3 DEBUG=1
86101$(BUILD ) /repro/MOM6 : MOMFLAGS=NETCDF=3 REPRO=1
102+ $(BUILD ) /openmp/MOM6 : MOMFLAGS=NETCDF=3 DEBUG=1 OPENMP=1
87103
88104$(BUILD ) /asymmetric/path_names : GRID_SRC=config_src/dynamic
89105$(BUILD ) /% /path_names : GRID_SRC=config_src/dynamic_symmetric
@@ -110,7 +126,7 @@ $(BUILD)/target/path_names: $(LIST_PATHS) $(TARGET_CODEBASE)
110126 $(TARGET_CODEBASE ) /config_src/solo_driver \
111127 $(TARGET_CODEBASE ) /$(GRID_SRC )
112128
113- $(BUILD ) /% /path_names : $(LIST_PATHS )
129+ $(BUILD ) /% /path_names : $(LIST_PATHS ) $( SOURCE )
114130 mkdir -p $(@D )
115131 cd $(@D ) && $(LIST_PATHS ) -l \
116132 $(BASE ) /src \
@@ -164,71 +180,90 @@ test: $(foreach t,$(TESTS),test.$(t))
164180# NOTE: We remove tc3 (OBC) from grid test since it cannot run asymmetric grids
165181
166182.PHONY : $(foreach t,$(TESTS ) ,test.$(t ) )
167- test.regressions : $(foreach c,$(CONFIGS ) ,$(c ) .regression $(c ) .regression.diag)
168183test.grids : $(foreach c,$(filter-out tc3,$(CONFIGS ) ) ,$(c ) .grid $(c ) .grid.diag)
169184test.layouts : $(foreach c,$(CONFIGS ) ,$(c ) .layout $(c ) .layout.diag)
170185test.restarts : $(foreach c,$(CONFIGS ) ,$(c ) .restart)
171186test.repros : $(foreach c,$(CONFIGS ) ,$(c ) .repro $(c ) .repro.diag)
187+ test.openmps : $(foreach c,$(CONFIGS ) ,$(c ) .openmp $(c ) .openmp.diag)
172188test.nans : $(foreach c,$(CONFIGS ) ,$(c ) .nan $(c ) .nan.diag)
173189test.dims : $(foreach c,$(CONFIGS ) ,$(foreach d,t l h z,$(c ) .dim.$(d ) $(c ) .dim.$(d ) .diag) )
174190
175- # NOTE: chksum_diag return code of cmp is currently ignored since many fail!
191+ test.regressions : $(foreach c,$(CONFIGS ) ,$(c ) .regression $(c ) .regression.diag)
192+ ! ls -1 results/* /* .reg
193+
176194define CMP_RULE
177- .PRECIOUS: $(foreach b,$(2 ) ,$( BASE ) /.testing /% /ocean.stats.$(b ) )
178- %.$(1 ) : $(foreach b,$(2 ) ,$( BASE ) /.testing /% /ocean.stats.$(b ) )
179- cmp $$^
195+ .PRECIOUS: $(foreach b,$(2 ) ,results /% /ocean.stats.$(b ) )
196+ %.$(1 ) : $(foreach b,$(2 ) ,results /% /ocean.stats.$(b ) )
197+ cmp $$^ || diff $$^
180198
181- .PRECIOUS: $(foreach b,$(2 ) ,$( BASE ) /.testing /% /chksum_diag.$(b ) )
182- %.$(1 ) .diag: $(foreach b,$(2 ) ,$( BASE ) /.testing /% /chksum_diag.$(b ) )
183- cmp $$^ || true
199+ .PRECIOUS: $(foreach b,$(2 ) ,results /% /chksum_diag.$(b ) )
200+ %.$(1 ) .diag: $(foreach b,$(2 ) ,results /% /chksum_diag.$(b ) )
201+ cmp $$^ || diff $$^
184202endef
185203
186- $(eval $(call CMP_RULE,regression,symmetric target))
187204$(eval $(call CMP_RULE,grid,symmetric asymmetric))
188205$(eval $(call CMP_RULE,layout,symmetric layout))
189206$(eval $(call CMP_RULE,repro,symmetric repro))
207+ $(eval $(call CMP_RULE,openmp,symmetric openmp))
190208$(eval $(call CMP_RULE,nan,symmetric nan))
191209$(foreach d,t l h z,$(eval $(call CMP_RULE,dim.$(d),symmetric dim.$(d))))
192210
211+ # Custom comparison rules
212+
213+ .PRECIOUS : $(foreach b,symmetric restart target,results/% /ocean.stats.$(b ) )
214+
193215# Restart tests only compare the final stat record
194- .PRECIOUS : $(foreach b,symmetric restart,$( BASE ) /.testing /% /ocean.stats.$(b ) )
195- % .restart : $(foreach b,symmetric restart, $( BASE ) /.testing/ % /ocean.stats. $( b ) )
196- cmp $( foreach f, $^ ,<(tr -s ' ' < $( f ) | cut -d ' ' -f3- | tail -n 1) )
216+ % .restart : $(foreach b,symmetric restart,results /% /ocean.stats.$(b ) )
217+ cmp $(foreach f, $^ ,<(tr -s ' ' < $( f ) | cut -d ' ' -f3- | tail -n 1) ) \
218+ || diff $^
197219
198220# TODO: chksum_diag parsing of restart files
199221
222+ # All regression tests must be completed when considering answer changes
223+ % .regression : $(foreach b,symmetric target,results/% /ocean.stats.$(b ) )
224+ cmp $^ || (diff $^ > $< .reg || true)
225+
226+ % .regression.diag : $(foreach b,symmetric target,results/% /chksum_diag.$(b ) )
227+ cmp $^ || (diff $^ > $< .reg || true)
200228
201229# ---
202230# Test run output files
203231
204- # (1): Configuration name
205- # (2): Executable type
206- # (3): Enable coverage flag
207- # (4): MOM_override configuration
208- # (5): Environment variables
209- # (6): Number of MPI ranks
210-
211- # Simple function for generalised Slurm (srun) and OpenMPI (mpirun) support
212- # (1): Environment variables
213-
214- ifeq ($(MPIRUN ) , srun)
215- MPIRUN_CMD =$(1 ) $(MPIRUN )
232+ # Generalized MPI environment variable support
233+ # $(1): Environment variables
234+ ifeq ($(shell $(MPIRUN ) -x tmp=1 true 2> /dev/null ; echo $$? ) , 0)
235+ MPIRUN_CMD =$(MPIRUN ) $(if $(1 ) ,-x $(1 ) ,)
236+ else ifeq ($(shell $(MPIRUN) -env tmp=1 true 2> /dev/null ; echo $$?), 0)
237+ MPIRUN_CMD =$(MPIRUN ) $(if $(1 ) ,-env $(1 ) ,)
216238else
217- MPIRUN_CMD =$(MPIRUN ) $( if $( 1 ) ,-x $(1 ) , )
239+ MPIRUN_CMD =$(1 ) $(MPIRUN )
218240endif
219241
242+ # Rule to build results/<tc>/{ocean.stats,chksum_diag}.<tag>
243+ # $(1): Test configuration name <tag>
244+ # $(2): Executable type
245+ # $(3): Enable coverage flag
246+ # $(4): MOM_override configuration
247+ # $(5): Environment variables
248+ # $(6): Number of MPI ranks
220249define STAT_RULE
221- $$(BASE ) /.testing/%/ocean.stats.$(1 ) : $$(BUILD ) /$(2 ) /MOM6
222- if [ $(3 ) ]; then find $$(BUILD ) -name *.gcda -exec rm -f '{}' \; ; fi
223- mkdir -p $$(@D ) /RESTART
224- echo $(4 ) > $$(@D ) /MOM_override
225- cd $$(@D ) && $$(call MPIRUN_CMD,$(5 ) ) -n $(6 ) $$< 2> debug.out
226- cp $$(@D ) /ocean.stats $$@
227- > $$(@D ) /MOM_override
228- if [ $(3 ) ]; then cd $$(BASE ) && bash <(curl -s https://codecov.io/bash) -n $$@ ; fi
229-
230- $$(BASE ) /.testing/%/chksum_diag.$(1 ) : $$(BASE ) /.testing/%/ocean.stats.$(1 )
231- cp $$(@D ) /chksum_diag $$@
250+ results/%/ocean.stats.$(1 ) : ../build/$(2 ) /MOM6
251+ if [ $(3 ) ]; then find ../build/$(2 ) -name *.gcda -exec rm -f '{}' \; ; fi
252+ mkdir -p work/$$* /$(1 )
253+ cp -rL $$* /* work/$$* /$(1 )
254+ cd work/$$* /$(1 ) && if [ -f Makefile ]; then make; fi
255+ mkdir -p work/$$* /$(1 ) /RESTART
256+ echo $(4 ) > work/$$* /$(1 ) /MOM_override
257+ cd work/$$* /$(1 ) && $$(call MPIRUN_CMD,$(5 ) ) -n $(6 ) ../../../$$< 2> debug.out > std.out \
258+ || ! sed 's/^/$$* .$(1 ) : /' std.out debug.out \
259+ && sed 's/^/$$* .$(1 ) : /' std.out
260+ mkdir -p $$(@D )
261+ cp work/$$* /$(1 ) /ocean.stats $$@
262+ if [ $(3 ) ]; then cd .. && bash <(curl -s https://codecov.io/bash) -n $$@ ; fi
263+
264+ results/%/chksum_diag.$(1 ) : results/%/ocean.stats.$(1 )
265+ mkdir -p $$(@D )
266+ cp work/$$* /$(1 ) /chksum_diag $$@
232267endef
233268
234269# Define $(,) as comma escape character
@@ -238,51 +273,58 @@ $(eval $(call STAT_RULE,symmetric,symmetric,$(REPORT_COVERAGE),,,1))
238273$(eval $(call STAT_RULE,asymmetric,asymmetric,,,,1))
239274$(eval $(call STAT_RULE,target,target,,,,1))
240275$(eval $(call STAT_RULE,repro,repro,,,,1))
276+ $(eval $(call STAT_RULE,openmp,openmp,,,,1))
241277$(eval $(call STAT_RULE,layout,symmetric,,LAYOUT=2$(,)1,,2))
242278$(eval $(call STAT_RULE,nan,symmetric,,,MALLOC_PERTURB_=256,1))
243279$(eval $(call STAT_RULE,dim.t,symmetric,,T_RESCALE_POWER=11,,1))
244280$(eval $(call STAT_RULE,dim.l,symmetric,,L_RESCALE_POWER=11,,1))
245281$(eval $(call STAT_RULE,dim.h,symmetric,,H_RESCALE_POWER=11,,1))
246282$(eval $(call STAT_RULE,dim.z,symmetric,,Z_RESCALE_POWER=11,,1))
247283
248- # Restart tests require signicant preprocessing, and are handled separately.
249- $(BASE ) /.testing/% /ocean.stats.restart : $(BUILD ) /symmetric/MOM6
250- # Cleanup
251- mkdir -p $(@D ) /RESTART
252- git checkout $(@D ) /input.nml
253- > $(@D ) /MOM_override
284+ # Restart tests require significant preprocessing, and are handled separately.
285+ results/% /ocean.stats.restart : ../build/symmetric/MOM6
286+ rm -rf work/$* /restart
287+ mkdir -p work/$* /restart
288+ cp -rL $* /* work/$* /restart
289+ cd work/$* /restart && if [ -f Makefile ]; then make; fi
290+ mkdir -p work/$* /restart/RESTART
254291 # Generate the half-period input namelist
255292 # TODO: Assumes runtime set by DAYMAX, will fail if set by input.nml
256- cd $( @D ) \
293+ cd work/ $* /restart \
257294 && daymax=$$(grep DAYMAX MOM_input | cut -d '!' -f 1 | cut -d '=' -f 2 | xargs ) \
258295 && timeunit=$$(grep TIMEUNIT MOM_input | cut -d '!' -f 1 | cut -d '=' -f 2 | xargs ) \
259296 && if [ -z " $$ {timeunit}" ]; then timeunit=" 8.64e4" ; fi \
260297 && printf -v timeunit_int " %.f" " $$ {timeunit}" \
261298 && halfperiod=$$(printf "%.f" $$(bc <<< "scale=10; 0.5 * $${daymax} * $${timeunit_int}" ) ) \
262- && printf " \n&ocean_solo_nml\n seconds = $$ {halfperiod}\n/\n" >> input.nml \
263- && echo $$ {daymax} $$ {timeunit}
299+ && printf " \n&ocean_solo_nml\n seconds = $$ {halfperiod}\n/\n" >> input.nml
264300 # Run the first half-period
265- cd $(@D ) && $(MPIRUN ) -n 1 $< 2> debug.out
301+ cd work/$* /restart && $(MPIRUN ) -n 1 ../../../$< 2> debug1.out > std1.out \
302+ || ! sed ' s/^/$*.restart1: /' std1.out debug1.out \
303+ && sed ' s/^/$*.restart1: /' std1.out
266304 # Setup the next inputs
267- rm -rf $( @D ) / INPUT && mv $( @D ) / RESTART $( @D ) / INPUT
268- mkdir $( @D ) /RESTART
269- cd $( @D ) && sed -i -e " s/input_filename *= *'n'/input_filename = 'r'/g" input.nml
305+ cd work/ $* /restart && rm -rf INPUT && mv RESTART INPUT
306+ mkdir work/ $* /restart /RESTART
307+ cd work/ $* /restart && sed -i -e " s/input_filename *= *'n'/input_filename = 'r'/g" input.nml
270308 # Run the second half-period
271- cd $(@D ) && $(MPIRUN ) -n 1 $< 2> debug.out
309+ cd work/$* /restart && $(MPIRUN ) -n 1 ../../../$< 2> debug2.out > std2.out \
310+ || ! sed ' s/^/$*.restart2: /' std2.out debug2.out \
311+ && sed ' s/^/$*.restart2: /' std2.out
272312 # Archive the results and cleanup
273- cp $(@D ) /ocean.stats $@
274- rm -rf $(@D ) /INPUT
275- git checkout $(@D ) /input.nml
313+ mkdir -p $(@D )
314+ cp work/$* /restart/ocean.stats $@
276315
277316# TODO: Restart checksum diagnostics
278317
279318
280319# ----
281320.PHONY : clean
282321clean : clean.stats
283- rm -rf $(BUILD )
322+ @# Assert that we are in .testing for recursive delete
323+ @[ $$ (basename $$ (pwd)) = .testing ]
324+ rm -rf ../build
284325
285326.PHONY : clean.stats
286327clean.stats :
287- find $(BASE ) /.testing -name ocean.stats* -exec rm {} \;
288- find $(BASE ) /.testing -name chksum_diag* -exec rm {} \;
328+ @# Assert that we are in .testing for recursive delete
329+ @[ $$ (basename $$ (pwd)) = .testing ]
330+ rm -rf work results
0 commit comments