Source code for compass.landice.tests.greenland.decomposition_test
from compass.landice.tests.greenland.run_model import RunModel
from compass.landice.util import calculate_decomp_core_pair
from compass.testcase import TestCase
from compass.validate import compare_variables
[docs]
class DecompositionTest(TestCase):
"""
A test case for performing two MALI runs of the Greenland Ice Sheet setup
with different decompositions. The larger decomposition targets up to 32
tasks, subject to available resources, and the smaller decomposition is
roughly half of the larger one.
Attributes
----------
velo_solver : str
The velocity solver used for the test case
proc_list : list of int
The pair of processor counts used in the decomposition comparison
run_dirs : list of str
The names of the subdirectories for the two decomposition runs
"""
[docs]
def __init__(self, test_group, velo_solver):
"""
Create the test case
Parameters
----------
test_group : compass.landice.tests.greenland.Greenland
The test group that this test case belongs to
velo_solver : {'sia', 'FO'}
The velocity solver to use for the test case
"""
name = 'decomposition_test'
self.velo_solver = velo_solver
self.proc_list = None
self.run_dirs = None
subdir = '{}_{}'.format(velo_solver.lower(), name)
super().__init__(test_group=test_group, name=name, subdir=subdir)
[docs]
def configure(self):
"""
Choose decomposition sizes from framework-detected resources and add
run steps.
The larger decomposition targets up to 32 tasks. FO runs require at
least 10 tasks; SIA runs require at least 2 tasks.
"""
target_max_tasks = 32
if self.velo_solver == 'FO':
smallest_acceptable_max_tasks = 10
elif self.velo_solver == 'sia':
smallest_acceptable_max_tasks = 2
else:
raise ValueError(f'Unexpected velo_solver {self.velo_solver}')
self.proc_list = calculate_decomp_core_pair(
self.config, target_max_tasks, smallest_acceptable_max_tasks)
self.run_dirs = []
for procs in self.proc_list:
name = '{}proc_run'.format(procs)
if name in self.run_dirs:
name = '{}_{}'.format(name, len(self.run_dirs) + 1)
self.run_dirs.append(name)
self.add_step(
RunModel(test_case=self, velo_solver=self.velo_solver,
name=name,
subdir=name, ntasks=procs, min_tasks=procs,
openmp_threads=1))
# no run() method is needed
def validate(self):
"""
Test cases can override this method to perform validation of variables
and timers
"""
name1 = self.run_dirs[0]
name2 = self.run_dirs[1]
if self.velo_solver == 'sia':
compare_variables(test_case=self,
variables=['thickness', 'normalVelocity'],
filename1='{}/output.nc'.format(name1),
filename2='{}/output.nc'.format(name2))
elif self.velo_solver == 'FO':
# validate thickness
compare_variables(test_case=self,
variables=['thickness', ],
filename1='{}/output.nc'.format(name1),
filename2='{}/output.nc'.format(name2),
l1_norm=1.0e-4,
l2_norm=1.0e-4,
linf_norm=1.0e-4,
quiet=False)
# validate normalVelocity
compare_variables(test_case=self,
variables=['normalVelocity', ],
filename1='{}/output.nc'.format(name1),
filename2='{}/output.nc'.format(name2),
l1_norm=1.0e-5,
l2_norm=1.0e-5,
linf_norm=1.0e-5,
quiet=False)