-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #785 from sbrus89/subgrid_pr
Add test cases for subgrid scale wetting and drying corrections
- Loading branch information
Showing
39 changed files
with
1,195 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from compass.ocean.tests.buttermilk_bay.default import Default | ||
from compass.testgroup import TestGroup | ||
|
||
|
||
class ButtermilkBay(TestGroup): | ||
""" | ||
A test group for Buttermilk Bay (subgrid wetting-and-drying) test cases | ||
""" | ||
|
||
def __init__(self, mpas_core): | ||
""" | ||
mpas_core : compass.MpasCore | ||
the MPAS core that this test group belongs to | ||
""" | ||
super().__init__(mpas_core=mpas_core, name='buttermilk_bay') | ||
for wetdry in ['standard', 'subgrid']: | ||
self.add_test_case( | ||
Default(test_group=self, wetdry=wetdry)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
[job] | ||
|
||
wall_time = 2:00:00 | ||
|
||
|
||
# config options for buttermilk bay | ||
[buttermilk_bay] | ||
|
||
# dimensions of domain in x and y directions (m) | ||
Lx = 4608 | ||
Ly = 4608 | ||
|
||
# a list of resolutions (m) to test | ||
resolutions = 256, 128, 64 | ||
|
||
# time step per resolution (s/m), since dt is proportional to resolution | ||
dt_per_m = 0.02 | ||
|
||
# the number of cells per core to aim for | ||
goal_cells_per_core = 300 | ||
|
||
# the approximate maximum number of cells per core (the test will fail if too | ||
# few cores are available) | ||
max_cells_per_core = 3000 | ||
|
||
# config options for visualizing drying slope ouptut | ||
[buttermilk_bay_viz] | ||
|
||
# coordinates (in km) for timeseries plot | ||
points = [2.8, 0.53], [1.9, 1.66], [2.4, 3.029], [2.51, 3.027], [1.26, 1.56] | ||
|
||
# generate contour plots at a specified interval between output timesnaps | ||
plot_interval = 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
import numpy as np | ||
|
||
from compass.config import CompassConfigParser | ||
from compass.ocean.tests.buttermilk_bay.forward import Forward | ||
from compass.ocean.tests.buttermilk_bay.initial_state import InitialState | ||
from compass.ocean.tests.buttermilk_bay.viz import Viz | ||
from compass.testcase import TestCase | ||
from compass.validate import compare_variables | ||
|
||
|
||
class Default(TestCase): | ||
""" | ||
The default buttermilk_bay test case | ||
Attributes | ||
---------- | ||
wetdry : str | ||
The type of wetting and drying (``standard``, ``subgrid``) | ||
""" | ||
|
||
def __init__(self, test_group, wetdry): | ||
""" | ||
Create the test case | ||
Parameters | ||
---------- | ||
test_group : compass.ocean.tests.buttermilk_bay.ButtermilkBay | ||
The test group that this test case belongs to | ||
wetdry : str | ||
The type of wetting and drying used (``standard``, ``subgrid``) | ||
""" | ||
name = wetdry | ||
subdir = wetdry | ||
super().__init__(test_group=test_group, name=name, | ||
subdir=subdir) | ||
|
||
self.resolutions = None | ||
self.wetdry = wetdry | ||
# add the steps with default resolutions so they can be listed | ||
config = CompassConfigParser() | ||
config.add_from_package('compass.ocean.tests.buttermilk_bay', | ||
'buttermilk_bay.cfg') | ||
self._setup_steps(config) | ||
|
||
def configure(self): | ||
""" | ||
Set config options for the test case | ||
""" | ||
config = self.config | ||
# set up the steps again in case a user has provided new resolutions | ||
self._setup_steps(config) | ||
|
||
self.update_cores() | ||
|
||
def update_cores(self): | ||
""" Update the number of cores and min_tasks for each forward step """ | ||
|
||
config = self.config | ||
|
||
goal_cells_per_core = config.getfloat('buttermilk_bay', | ||
'goal_cells_per_core') | ||
max_cells_per_core = config.getfloat('buttermilk_bay', | ||
'max_cells_per_core') | ||
lx = config.getfloat('buttermilk_bay', 'Lx') | ||
ly = config.getfloat('buttermilk_bay', 'Ly') | ||
|
||
for resolution in self.resolutions: | ||
|
||
nx = 2 * int(0.5 * lx / resolution + 0.5) | ||
ny = 2 * int(0.5 * ly * (2. / np.sqrt(3)) / resolution + 0.5) | ||
|
||
approx_cells = nx * ny | ||
# ideally, about 300 cells per core | ||
# (make it a multiple of 4 because...it looks better?) | ||
ntasks = max(1, | ||
4 * round(approx_cells / (4 * goal_cells_per_core))) | ||
# In a pinch, about 3000 cells per core | ||
min_tasks = max(1, | ||
round(approx_cells / max_cells_per_core)) | ||
|
||
res_name = f'{resolution}m' | ||
step = self.steps[f'forward_{res_name}'] | ||
step.ntasks = ntasks | ||
step.min_tasks = min_tasks | ||
|
||
config.set('buttermilk_bay', f'{res_name}_ntasks', str(ntasks), | ||
comment=f'Target core count for {res_name} mesh') | ||
config.set('buttermilk_bay', f'{res_name}_min_tasks', | ||
str(min_tasks), | ||
comment=f'Minimum core count for {res_name} mesh') | ||
|
||
def _setup_steps(self, config): | ||
""" setup steps given resolutions """ | ||
|
||
default_resolutions = '256, 128, 64' | ||
|
||
# set the default values that a user may change before setup | ||
config.set('buttermilk_bay', 'resolutions', default_resolutions, | ||
comment='a list of resolutions (m) to test') | ||
|
||
# get the resolutions back, perhaps with values set in the user's | ||
# config file | ||
resolutions = config.getlist('buttermilk_bay', | ||
'resolutions', dtype=int) | ||
|
||
if self.resolutions is not None and self.resolutions == resolutions: | ||
return | ||
|
||
# start fresh with no steps | ||
self.steps = dict() | ||
self.steps_to_run = list() | ||
|
||
self.resolutions = resolutions | ||
|
||
for resolution in self.resolutions: | ||
|
||
res_name = f'{resolution}m' | ||
|
||
init_step = InitialState(test_case=self, | ||
name=f'initial_state_{res_name}', | ||
resolution=resolution, | ||
wetdry=self.wetdry) | ||
self.add_step(init_step) | ||
self.add_step(Forward(test_case=self, | ||
name=f'forward_{res_name}', | ||
resolution=resolution, | ||
wetdry=self.wetdry)) | ||
self.add_step(Viz(test_case=self, | ||
wetdry=self.wetdry, | ||
resolutions=resolutions)) | ||
|
||
def validate(self): | ||
""" | ||
Validate variables against a baseline | ||
""" | ||
super().validate() | ||
variables = ['layerThickness', 'normalVelocity'] | ||
for res in self.resolutions: | ||
compare_variables(test_case=self, variables=variables, | ||
filename1=f'forward_{res}m/output.nc') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import time | ||
|
||
from compass.model import run_model | ||
from compass.step import Step | ||
|
||
|
||
class Forward(Step): | ||
""" | ||
A step for performing forward MPAS-Ocean runs as part of buttermilk bay | ||
test cases. | ||
""" | ||
def __init__(self, test_case, resolution, | ||
name, | ||
coord_type='single_layer', | ||
wetdry='standard'): | ||
""" | ||
Create a new test case | ||
Parameters | ||
---------- | ||
test_case : compass.TestCase | ||
The test case this step belongs to | ||
resolution : float | ||
The resolution of the test case | ||
name : str | ||
The name of the test case | ||
subdir : str, optional | ||
The subdirectory for the step. The default is ``name`` | ||
coord_type : str, optional | ||
Vertical coordinate configuration | ||
""" | ||
|
||
self.resolution = resolution | ||
|
||
super().__init__(test_case=test_case, name=name) | ||
|
||
self.add_namelist_file('compass.ocean.tests.buttermilk_bay', | ||
'namelist.forward') | ||
|
||
res_name = f'{resolution}m' | ||
self.add_namelist_file('compass.ocean.tests.buttermilk_bay', | ||
f'namelist.{coord_type}.forward') | ||
|
||
if wetdry == 'subgrid': | ||
self.add_namelist_file('compass.ocean.tests.buttermilk_bay', | ||
'namelist.subgrid.forward') | ||
self.add_streams_file('compass.ocean.tests.buttermilk_bay', | ||
'streams.subgrid.forward') | ||
else: | ||
self.add_streams_file('compass.ocean.tests.buttermilk_bay', | ||
'streams.forward') | ||
input_path = f'../initial_state_{res_name}' | ||
self.add_input_file(filename='mesh.nc', | ||
target=f'{input_path}/culled_mesh.nc') | ||
self.add_input_file(filename='init.nc', | ||
target=f'{input_path}/ocean.nc') | ||
self.add_input_file(filename='graph.info', | ||
target=f'{input_path}/culled_graph.info') | ||
self.add_input_file(filename='forcing.nc', | ||
target=f'{input_path}/init_mode_forcing_data.nc') | ||
|
||
self.add_model_as_input() | ||
|
||
self.add_output_file(filename='output.nc') | ||
|
||
def setup(self): | ||
""" | ||
Set namelist options based on config options | ||
""" | ||
dt = self.get_dt() | ||
self.add_namelist_options({'config_dt': dt}) | ||
self._get_resources() | ||
|
||
def constrain_resources(self, available_cores): | ||
""" | ||
Update resources at runtime from config options | ||
""" | ||
self._get_resources() | ||
super().constrain_resources(available_cores) | ||
|
||
def run(self): | ||
""" | ||
Run this step of the testcase | ||
""" | ||
# update dt in case the user has changed dt_per_m | ||
dt = self.get_dt() | ||
self.update_namelist_at_runtime(options={'config_dt': dt}, | ||
out_name='namelist.ocean') | ||
|
||
run_model(self) | ||
|
||
def get_dt(self): | ||
""" | ||
Get the time step | ||
Returns | ||
------- | ||
dt : str | ||
the time step in HH:MM:SS | ||
""" | ||
config = self.config | ||
# dt is proportional to resolution | ||
dt_per_m = config.getfloat('buttermilk_bay', 'dt_per_m') | ||
|
||
dt = dt_per_m * self.resolution | ||
# https://stackoverflow.com/a/1384565/7728169 | ||
dt = time.strftime('%H:%M:%S', time.gmtime(dt)) | ||
|
||
return dt | ||
|
||
def _get_resources(self): | ||
""" get the these properties from the config options """ | ||
config = self.config | ||
self.ntasks = config.getint('buttermilk_bay', | ||
f'{self.resolution}m_ntasks') | ||
self.min_tasks = config.getint('buttermilk_bay', | ||
f'{self.resolution}m_min_tasks') | ||
self.openmp_threads = 1 |
Oops, something went wrong.