diff --git a/compass/ocean/cached_files.json b/compass/ocean/cached_files.json
index 2ec036b847..23256adcba 100644
--- a/compass/ocean/cached_files.json
+++ b/compass/ocean/cached_files.json
@@ -103,5 +103,40 @@
"ocean/global_convergence/qu/cosine_bell/QU60/init/namelist.ocean": "global_convergence/qu/cosine_bell/QU60/init/namelist.220528.ocean",
"ocean/global_convergence/qu/cosine_bell/QU60/init/initial_state.nc": "global_convergence/qu/cosine_bell/QU60/init/initial_state.220528.nc",
"ocean/global_convergence/qu/cosine_bell/QU90/init/namelist.ocean": "global_convergence/qu/cosine_bell/QU90/init/namelist.220528.ocean",
- "ocean/global_convergence/qu/cosine_bell/QU90/init/initial_state.nc": "global_convergence/qu/cosine_bell/QU90/init/initial_state.220528.nc"
-}
+ "ocean/global_convergence/qu/cosine_bell/QU90/init/initial_state.nc": "global_convergence/qu/cosine_bell/QU90/init/initial_state.220528.nc",
+ "ocean/global_ocean/Icos240/mesh/base_mesh/mesh.msh": "global_ocean/Icos240/mesh/base_mesh/mesh.220814.msh",
+ "ocean/global_ocean/Icos240/mesh/base_mesh/base_mesh.nc": "global_ocean/Icos240/mesh/base_mesh/base_mesh.220814.nc",
+ "ocean/global_ocean/Icos240/mesh/base_mesh/cellWidthVsLatLon.nc": "global_ocean/Icos240/mesh/base_mesh/cellWidthVsLatLon.220814.nc",
+ "ocean/global_ocean/Icos240/mesh/base_mesh/graph.info": "global_ocean/Icos240/mesh/base_mesh/graph.220814.info",
+ "ocean/global_ocean/Icos240/mesh/cull_mesh/culled_mesh.nc": "global_ocean/Icos240/mesh/cull_mesh/culled_mesh.220814.nc",
+ "ocean/global_ocean/Icos240/mesh/cull_mesh/culled_graph.info": "global_ocean/Icos240/mesh/cull_mesh/culled_graph.220814.info",
+ "ocean/global_ocean/Icos240/mesh/cull_mesh/critical_passages_mask_final.nc": "global_ocean/Icos240/mesh/cull_mesh/critical_passages_mask_final.220814.nc",
+ "ocean/global_ocean/QU240/mesh/base_mesh/mesh.msh": "global_ocean/QU240/mesh/base_mesh/mesh.220814.msh",
+ "ocean/global_ocean/QU240/mesh/base_mesh/base_mesh.nc": "global_ocean/QU240/mesh/base_mesh/base_mesh.220814.nc",
+ "ocean/global_ocean/QU240/mesh/base_mesh/cellWidthVsLatLon.nc": "global_ocean/QU240/mesh/base_mesh/cellWidthVsLatLon.220814.nc",
+ "ocean/global_ocean/QU240/mesh/base_mesh/graph.info": "global_ocean/QU240/mesh/base_mesh/graph.220814.info",
+ "ocean/global_ocean/QU240/mesh/cull_mesh/culled_mesh.nc": "global_ocean/QU240/mesh/cull_mesh/culled_mesh.220814.nc",
+ "ocean/global_ocean/QU240/mesh/cull_mesh/culled_graph.info": "global_ocean/QU240/mesh/cull_mesh/culled_graph.220814.info",
+ "ocean/global_ocean/QU240/mesh/cull_mesh/critical_passages_mask_final.nc": "global_ocean/QU240/mesh/cull_mesh/critical_passages_mask_final.220814.nc",
+ "ocean/global_ocean/QUwISC240/mesh/base_mesh/mesh.msh": "global_ocean/QUwISC240/mesh/base_mesh/mesh.220814.msh",
+ "ocean/global_ocean/QUwISC240/mesh/base_mesh/base_mesh.nc": "global_ocean/QUwISC240/mesh/base_mesh/base_mesh.220814.nc",
+ "ocean/global_ocean/QUwISC240/mesh/base_mesh/cellWidthVsLatLon.nc": "global_ocean/QUwISC240/mesh/base_mesh/cellWidthVsLatLon.220814.nc",
+ "ocean/global_ocean/QUwISC240/mesh/base_mesh/graph.info": "global_ocean/QUwISC240/mesh/base_mesh/graph.220814.info",
+ "ocean/global_ocean/QUwISC240/mesh/cull_mesh/culled_mesh.nc": "global_ocean/QUwISC240/mesh/cull_mesh/culled_mesh.220814.nc",
+ "ocean/global_ocean/QUwISC240/mesh/cull_mesh/culled_graph.info": "global_ocean/QUwISC240/mesh/cull_mesh/culled_graph.220814.info",
+ "ocean/global_ocean/QUwISC240/mesh/cull_mesh/critical_passages_mask_final.nc": "global_ocean/QUwISC240/mesh/cull_mesh/critical_passages_mask_final.220814.nc",
+ "ocean/global_ocean/EC30to60/mesh/base_mesh/mesh.msh": "global_ocean/EC30to60/mesh/base_mesh/mesh.220814.msh",
+ "ocean/global_ocean/EC30to60/mesh/base_mesh/base_mesh.nc": "global_ocean/EC30to60/mesh/base_mesh/base_mesh.220814.nc",
+ "ocean/global_ocean/EC30to60/mesh/base_mesh/cellWidthVsLatLon.nc": "global_ocean/EC30to60/mesh/base_mesh/cellWidthVsLatLon.220814.nc",
+ "ocean/global_ocean/EC30to60/mesh/base_mesh/graph.info": "global_ocean/EC30to60/mesh/base_mesh/graph.220814.info",
+ "ocean/global_ocean/EC30to60/mesh/cull_mesh/culled_mesh.nc": "global_ocean/EC30to60/mesh/cull_mesh/culled_mesh.220814.nc",
+ "ocean/global_ocean/EC30to60/mesh/cull_mesh/culled_graph.info": "global_ocean/EC30to60/mesh/cull_mesh/culled_graph.220814.info",
+ "ocean/global_ocean/EC30to60/mesh/cull_mesh/critical_passages_mask_final.nc": "global_ocean/EC30to60/mesh/cull_mesh/critical_passages_mask_final.220814.nc",
+ "ocean/global_ocean/ECwISC30to60/mesh/base_mesh/mesh.msh": "global_ocean/ECwISC30to60/mesh/base_mesh/mesh.220814.msh",
+ "ocean/global_ocean/ECwISC30to60/mesh/base_mesh/base_mesh.nc": "global_ocean/ECwISC30to60/mesh/base_mesh/base_mesh.220814.nc",
+ "ocean/global_ocean/ECwISC30to60/mesh/base_mesh/cellWidthVsLatLon.nc": "global_ocean/ECwISC30to60/mesh/base_mesh/cellWidthVsLatLon.220814.nc",
+ "ocean/global_ocean/ECwISC30to60/mesh/base_mesh/graph.info": "global_ocean/ECwISC30to60/mesh/base_mesh/graph.220814.info",
+ "ocean/global_ocean/ECwISC30to60/mesh/cull_mesh/culled_mesh.nc": "global_ocean/ECwISC30to60/mesh/cull_mesh/culled_mesh.220814.nc",
+ "ocean/global_ocean/ECwISC30to60/mesh/cull_mesh/culled_graph.info": "global_ocean/ECwISC30to60/mesh/cull_mesh/culled_graph.220814.info",
+ "ocean/global_ocean/ECwISC30to60/mesh/cull_mesh/critical_passages_mask_final.nc": "global_ocean/ECwISC30to60/mesh/cull_mesh/critical_passages_mask_final.220814.nc"
+}
\ No newline at end of file
diff --git a/compass/ocean/mesh/__init__.py b/compass/ocean/mesh/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/compass/ocean/tests/global_ocean/mesh/cull.py b/compass/ocean/mesh/cull.py
old mode 100755
new mode 100644
similarity index 73%
rename from compass/ocean/tests/global_ocean/mesh/cull.py
rename to compass/ocean/mesh/cull.py
index fbe2f9f394..3faf23333d
--- a/compass/ocean/tests/global_ocean/mesh/cull.py
+++ b/compass/ocean/mesh/cull.py
@@ -1,4 +1,5 @@
import xarray
+import os
from geometric_features import GeometricFeatures, FeatureCollection, \
read_feature_collection
@@ -6,11 +7,127 @@
from mpas_tools.mesh.mask import compute_mpas_flood_fill_mask
import mpas_tools.io
from mpas_tools.io import write_netcdf
+from mpas_tools.ocean import inject_bathymetry
from mpas_tools.ocean.coastline_alteration import widen_transect_edge_masks, \
add_critical_land_blockages, add_land_locked_cells_to_mask
from mpas_tools.viz.paraview_extractor import extract_vtk
from mpas_tools.logging import LoggingContext, check_call
+from compass.step import Step
+
+
+class CullMeshStep(Step):
+ """
+ A step for culling a global MPAS-Ocean mesh
+
+ Attributes
+ ----------
+ base_mesh_step : compass.mesh.spherical.SphericalBaseStep
+ The base mesh step containing input files to this step
+
+ with_ice_shelf_cavities : bool
+ Whether the mesh includes ice-shelf cavities
+
+ do_inject_bathymetry : bool
+ Whether to interpolate bathymetry from a data file so it
+ can be used as a culling criteria
+
+ preserve_floodplain : bool
+ Whether to leave land cells in the mesh based on bathymetry
+ specified by do_inject_bathymetry
+ """
+
+ def __init__(self, test_case, base_mesh_step, with_ice_shelf_cavities,
+ name='cull_mesh', subdir=None, do_inject_bathymetry=False,
+ preserve_floodplain=False):
+ """
+ Create a new step
+
+ Parameters
+ ----------
+ test_case : compass.ocean.tests.global_ocean.mesh.Mesh
+ The test case this step belongs to
+
+ base_mesh_step : compass.mesh.spherical.SphericalBaseStep
+ The base mesh step containing input files to this step
+
+ with_ice_shelf_cavities : bool
+ Whether the mesh includes ice-shelf cavities
+
+ name : str, optional
+ the name of the step
+
+ subdir : str, optional
+ the subdirectory for the step. The default is ``name``
+
+ do_inject_bathymetry : bool, optional
+ Whether to interpolate bathymetry from a data file so it
+ can be used as a culling criteria
+
+ preserve_floodplain : bool, optional
+ Whether to leave land cells in the mesh based on bathymetry
+ specified by do_inject_bathymetry
+ """
+ super().__init__(test_case, name=name, subdir=subdir,
+ cpus_per_task=None, min_cpus_per_task=None)
+ self.base_mesh_step = base_mesh_step
+
+ for file in ['culled_mesh.nc', 'culled_graph.info',
+ 'critical_passages_mask_final.nc']:
+ self.add_output_file(filename=file)
+
+ self.with_ice_shelf_cavities = with_ice_shelf_cavities
+ self.do_inject_bathymetry = do_inject_bathymetry
+ self.preserve_floodplain = preserve_floodplain
+
+ def setup(self):
+ """
+ Set up the test case in the work directory, including downloading any
+ dependencies.
+ """
+ super().setup()
+ if self.do_inject_bathymetry:
+ self.add_input_file(
+ filename='earth_relief_15s.nc',
+ target='SRTM15_plus_earth_relief_15s.nc',
+ database='bathymetry_database')
+
+ # get the these properties from the config options
+ config = self.config
+ # todo: move to constrain_resources()
+ self.cpus_per_task = config.getint('spherical_mesh',
+ 'cull_mesh_cpus_per_task')
+ self.min_cpus_per_task = config.getint('spherical_mesh',
+ 'cull_mesh_min_cpus_per_task')
+
+ base_path = self.base_mesh_step.path
+ base_filename = self.base_mesh_step.config.get(
+ 'spherical_mesh', 'mpas_mesh_filename')
+ target = os.path.join(base_path, base_filename)
+ self.add_input_file(filename='base_mesh.nc', work_dir_target=target)
+
+ def run(self):
+ """
+ Run this step of the test case
+ """
+ with_ice_shelf_cavities = self.with_ice_shelf_cavities
+ logger = self.logger
+
+ # only use progress bars if we're not writing to a log file
+ use_progress_bar = self.log_filename is None
+
+ do_inject_bathymetry = self.do_inject_bathymetry
+ preserve_floodplain = self.preserve_floodplain
+
+ cull_mesh(with_critical_passages=True, logger=logger,
+ use_progress_bar=use_progress_bar,
+ preserve_floodplain=preserve_floodplain,
+ with_cavities=with_ice_shelf_cavities,
+ process_count=self.cpus_per_task)
+
+ if do_inject_bathymetry:
+ inject_bathymetry(mesh_file='culled_mesh.nc')
+
def cull_mesh(with_cavities=False, with_critical_passages=False,
custom_critical_passages=None, custom_land_blockages=None,
diff --git a/compass/ocean/mesh/floodplain.py b/compass/ocean/mesh/floodplain.py
new file mode 100644
index 0000000000..eef8db0098
--- /dev/null
+++ b/compass/ocean/mesh/floodplain.py
@@ -0,0 +1,63 @@
+from mpas_tools.ocean import inject_bathymetry, inject_preserve_floodplain
+
+from compass.mesh.spherical import QuasiUniformSphericalMeshStep
+
+
+class FloodplainMeshStep(QuasiUniformSphericalMeshStep):
+ """
+ A step for creating a global MPAS-Ocean mesh that includes variables
+ needed for preserving a floodplain
+
+ preserve_floodplain : bool
+ Whether the mesh includes land cells
+ """
+
+ def __init__(self, test_case, name='base_mesh', subdir=None,
+ cell_width=None, preserve_floodplain=True):
+ """
+ Create a new step
+
+ Parameters
+ ----------
+ test_case : compass.testcase.TestCase
+ The test case this step belongs to
+
+ name : str
+ the name of the step
+
+ subdir : {str, None}
+ the subdirectory for the step. The default is ``name``
+
+ cell_width : float, optional
+ The approximate cell width in km of the mesh if constant resolution
+
+ preserve_floodplain : bool, optional
+ Whether the mesh includes land cells
+ """
+
+ super().__init__(test_case=test_case, name=name, subdir=subdir,
+ cell_width=cell_width)
+
+ self.preserve_floodplain = preserve_floodplain
+
+ self.add_input_file(filename='earth_relief_15s.nc',
+ target='SRTM15_plus_earth_relief_15s.nc',
+ database='bathymetry_database')
+
+ def run(self):
+ """
+ Run this step of the test case
+ """
+ super().run()
+
+ config = self.config
+
+ mesh_filename = config.get('spherical_mesh', 'mpas_mesh_filename')
+
+ inject_bathymetry(mesh_file=mesh_filename)
+ if self.preserve_floodplain:
+ floodplain_elevation = config.getfloat('spherical_mesh',
+ 'floodplain_elevation')
+ inject_preserve_floodplain(
+ mesh_file=mesh_filename,
+ floodplain_elevation=floodplain_elevation)
diff --git a/compass/ocean/tests/global_ocean/__init__.py b/compass/ocean/tests/global_ocean/__init__.py
index ede88adf45..c6f38cf31e 100644
--- a/compass/ocean/tests/global_ocean/__init__.py
+++ b/compass/ocean/tests/global_ocean/__init__.py
@@ -36,7 +36,7 @@ def __init__(self, mpas_core):
super().__init__(mpas_core=mpas_core, name='global_ocean')
# we do a lot of tests for QU240/QUwISC240
- for mesh_name in ['QU240', 'QUwISC240']:
+ for mesh_name in ['QU240', 'Icos240', 'QUwISC240']:
mesh = Mesh(test_group=self, mesh_name=mesh_name)
self.add_test_case(mesh)
diff --git a/compass/ocean/tests/global_ocean/configure.py b/compass/ocean/tests/global_ocean/configure.py
index 043a358c52..0d4f30002b 100644
--- a/compass/ocean/tests/global_ocean/configure.py
+++ b/compass/ocean/tests/global_ocean/configure.py
@@ -18,8 +18,8 @@ def configure_global_ocean(test_case, mesh, init=None):
The test case that produces the initial condition for this run
"""
config = test_case.config
- mesh_step = mesh.mesh_step
- config.add_from_package(mesh_step.package, mesh_step.mesh_config_filename,
+ config.add_from_package('compass.mesh', 'mesh.cfg')
+ config.add_from_package(mesh.package, mesh.mesh_config_filename,
exception=True)
if mesh.with_ice_shelf_cavities:
diff --git a/compass/ocean/tests/global_ocean/files_for_e3sm/ocean_graph_partition.py b/compass/ocean/tests/global_ocean/files_for_e3sm/ocean_graph_partition.py
index a63de5c349..93a200fb61 100644
--- a/compass/ocean/tests/global_ocean/files_for_e3sm/ocean_graph_partition.py
+++ b/compass/ocean/tests/global_ocean/files_for_e3sm/ocean_graph_partition.py
@@ -38,7 +38,7 @@ def __init__(self, test_case, mesh, restart_filename):
self.add_input_file(filename='restart.nc',
target='../{}'.format(restart_filename))
- mesh_path = mesh.mesh_step.path
+ mesh_path = mesh.get_cull_mesh_path()
self.add_input_file(
filename='graph.info',
work_dir_target='{}/culled_graph.info'.format(mesh_path))
diff --git a/compass/ocean/tests/global_ocean/forward.py b/compass/ocean/tests/global_ocean/forward.py
index 8793055cb2..91313bbba8 100644
--- a/compass/ocean/tests/global_ocean/forward.py
+++ b/compass/ocean/tests/global_ocean/forward.py
@@ -103,7 +103,7 @@ def __init__(self, test_case, mesh, init, time_integrator, name='forward',
self.add_streams_file(
'compass.ocean.tests.global_ocean', 'streams.bgc')
- mesh_package = mesh.mesh_step.package
+ mesh_package = mesh.package
mesh_package_contents = list(contents(mesh_package))
mesh_namelists = ['namelist.forward',
f'namelist.{time_integrator.lower()}']
diff --git a/compass/ocean/tests/global_ocean/global_ocean.cfg b/compass/ocean/tests/global_ocean/global_ocean.cfg
index 41d1223708..634954247c 100644
--- a/compass/ocean/tests/global_ocean/global_ocean.cfg
+++ b/compass/ocean/tests/global_ocean/global_ocean.cfg
@@ -1,15 +1,19 @@
-# options for global ocean testcases
-[global_ocean]
+# options for spherical meshes
+[spherical_mesh]
-## each mesh should replace these with appropriate values in its config file
-
-## config options related to the mesh step
+## config options related to the step for culling land from the mesh
# number of cores to use
-mesh_cpus_per_task = 18
+cull_mesh_cpus_per_task = 18
# minimum of cores, below which the step fails
-mesh_min_cpus_per_task = 1
+cull_mesh_min_cpus_per_task = 1
# maximum memory usage allowed (in MB)
-mesh_max_memory = 1000
+cull_mesh_max_memory = 1000
+
+
+# options for global ocean testcases
+[global_ocean]
+
+## each mesh should replace these with appropriate values in its config file
## config options related to the initial_state step
# number of cores to use
diff --git a/compass/ocean/tests/global_ocean/init/initial_state.py b/compass/ocean/tests/global_ocean/init/initial_state.py
index a5a0da92f0..155039f0b4 100644
--- a/compass/ocean/tests/global_ocean/init/initial_state.py
+++ b/compass/ocean/tests/global_ocean/init/initial_state.py
@@ -113,7 +113,7 @@ def __init__(self, test_case, mesh, initial_condition, with_bgc):
'1timeLevel.nc',
database='initial_condition_database')
- mesh_path = mesh.mesh_step.path
+ mesh_path = self.mesh.get_cull_mesh_path()
self.add_input_file(
filename='mesh.nc',
@@ -123,7 +123,7 @@ def __init__(self, test_case, mesh, initial_condition, with_bgc):
filename='graph.info',
work_dir_target=f'{mesh_path}/culled_graph.info')
- if mesh.with_ice_shelf_cavities:
+ if self.mesh.with_ice_shelf_cavities:
self.add_input_file(
filename='land_ice_mask.nc',
work_dir_target=f'{mesh_path}/land_ice_mask.nc')
diff --git a/compass/ocean/tests/global_ocean/init/ssh_adjustment.py b/compass/ocean/tests/global_ocean/init/ssh_adjustment.py
index d85de6c7a3..fab3ee5731 100644
--- a/compass/ocean/tests/global_ocean/init/ssh_adjustment.py
+++ b/compass/ocean/tests/global_ocean/init/ssh_adjustment.py
@@ -49,7 +49,7 @@ def __init__(self, test_case, ntasks=None, min_tasks=None,
self.add_streams_file('compass.ocean.tests.global_ocean.init',
'streams.ssh_adjust')
- mesh_path = test_case.mesh.mesh_step.path
+ mesh_path = test_case.mesh.get_cull_mesh_path()
init_path = test_case.steps['initial_state'].path
self.add_input_file(
diff --git a/compass/ocean/tests/global_ocean/mesh/__init__.py b/compass/ocean/tests/global_ocean/mesh/__init__.py
index 9e24b5aa97..1655aa4d09 100644
--- a/compass/ocean/tests/global_ocean/mesh/__init__.py
+++ b/compass/ocean/tests/global_ocean/mesh/__init__.py
@@ -1,8 +1,10 @@
from compass.testcase import TestCase
-from compass.ocean.tests.global_ocean.mesh.qu240 import QU240Mesh
-from compass.ocean.tests.global_ocean.mesh.ec30to60 import EC30to60Mesh
-from compass.ocean.tests.global_ocean.mesh.so12to60 import SO12to60Mesh
-from compass.ocean.tests.global_ocean.mesh.wc14 import WC14Mesh
+from compass.mesh.spherical import IcosahedralMeshStep, \
+ QuasiUniformSphericalMeshStep
+from compass.ocean.mesh.cull import CullMeshStep
+from compass.ocean.tests.global_ocean.mesh.ec30to60 import EC30to60BaseMesh
+from compass.ocean.tests.global_ocean.mesh.so12to60 import SO12to60BaseMesh
+from compass.ocean.tests.global_ocean.mesh.wc14 import WC14BaseMesh
from compass.ocean.tests.global_ocean.configure import configure_global_ocean
from compass.validate import compare_variables
@@ -13,8 +15,11 @@ class Mesh(TestCase):
Attributes
----------
- mesh_step : compass.ocean.tests.global_ocean.mesh.mesh.MeshStep
- The step for creating the mesh
+ package : str
+ The python package for the mesh
+
+ mesh_config_filename : str
+ The name of the mesh config file
with_ice_shelf_cavities : bool
Whether the mesh includes ice-shelf cavities
@@ -34,52 +39,51 @@ def __init__(self, test_group, mesh_name):
name = 'mesh'
subdir = '{}/{}'.format(mesh_name, name)
super().__init__(test_group=test_group, name=name, subdir=subdir)
- if mesh_name in 'QU240':
- self.mesh_step = QU240Mesh(self, mesh_name,
- with_ice_shelf_cavities=False)
- elif mesh_name in 'QUwISC240':
- self.mesh_step = QU240Mesh(self, mesh_name,
- with_ice_shelf_cavities=True)
- elif mesh_name in 'EC30to60':
- self.mesh_step = EC30to60Mesh(self, mesh_name,
- with_ice_shelf_cavities=False)
- elif mesh_name in 'ECwISC30to60':
- self.mesh_step = EC30to60Mesh(self, mesh_name,
- with_ice_shelf_cavities=True)
- elif mesh_name in 'SOwISC12to60':
- self.mesh_step = SO12to60Mesh(self, mesh_name,
- with_ice_shelf_cavities=True)
+
+ with_ice_shelf_cavities = 'wISC' in mesh_name
+ mesh_lower = mesh_name.lower()
+ if with_ice_shelf_cavities:
+ mesh_lower = mesh_lower.replace('wisc', '')
+ if 'icos' in mesh_lower:
+ mesh_lower = mesh_lower.replace('icos', 'qu')
+
+ self.package = f'compass.ocean.tests.global_ocean.mesh.{mesh_lower}'
+ self.mesh_config_filename = f'{mesh_lower}.cfg'
+
+ self.mesh_name = mesh_name
+ self.with_ice_shelf_cavities = with_ice_shelf_cavities
+
+ name = 'base_mesh'
+ subdir = None
+ if mesh_name in ['Icos240', 'IcoswISC240']:
+ base_mesh_step = IcosahedralMeshStep(
+ self, name=name, subdir=subdir, cell_width=240)
+ elif mesh_name in ['QU240', 'QUwISC240']:
+ base_mesh_step = QuasiUniformSphericalMeshStep(
+ self, name=name, subdir=subdir, cell_width=240)
+ elif mesh_name in ['EC30to60', 'ECwISC30to60']:
+ base_mesh_step = EC30to60BaseMesh(self, name=name, subdir=subdir)
+ elif mesh_name in ['SOwISC12to60']:
+ base_mesh_step = SO12to60BaseMesh(self, name=name, subdir=subdir)
elif mesh_name in 'WC14':
- self.mesh_step = WC14Mesh(self, mesh_name,
- with_ice_shelf_cavities=False)
+ base_mesh_step = WC14BaseMesh(self, name=name, subdir=subdir)
else:
- raise ValueError('Unknown mesh name {}'.format(mesh_name))
+ raise ValueError(f'Unknown mesh name {mesh_name}')
- self.add_step(self.mesh_step)
+ self.add_step(base_mesh_step)
- self.mesh_name = mesh_name
- self.with_ice_shelf_cavities = self.mesh_step.with_ice_shelf_cavities
+ self.add_step(CullMeshStep(
+ test_case=self, base_mesh_step=base_mesh_step,
+ with_ice_shelf_cavities=self.with_ice_shelf_cavities))
def configure(self):
"""
Modify the configuration options for this test case
"""
configure_global_ocean(test_case=self, mesh=self)
-
- def run(self):
- """
- Run each step of the testcase
- """
- step = self.mesh_step
config = self.config
- # get the these properties from the config options
- step.cpus_per_task = config.getint(
- 'global_ocean', 'mesh_cpus_per_task')
- step.min_cpus_per_task = config.getint(
- 'global_ocean', 'mesh_min_cpus_per_task')
-
- # run the step
- super().run()
+ config.set('spherical_mesh', 'add_mesh_density', 'True')
+ config.set('spherical_mesh', 'plot_cell_width', 'True')
def validate(self):
"""
@@ -88,4 +92,14 @@ def validate(self):
"""
variables = ['xCell', 'yCell', 'zCell']
compare_variables(test_case=self, variables=variables,
- filename1='mesh/culled_mesh.nc')
+ filename1='cull_mesh/culled_mesh.nc')
+
+ def get_cull_mesh_path(self):
+ """
+ Get the path of the cull mesh step (for input files)
+ Returns
+ -------
+ cull_mesh_path : str
+ The path to the work directory of the cull mesh step.
+ """
+ return self.steps['cull_mesh'].path
diff --git a/compass/ocean/tests/global_ocean/mesh/ec30to60/__init__.py b/compass/ocean/tests/global_ocean/mesh/ec30to60/__init__.py
index 1a599c7952..cb1b0e19d3 100644
--- a/compass/ocean/tests/global_ocean/mesh/ec30to60/__init__.py
+++ b/compass/ocean/tests/global_ocean/mesh/ec30to60/__init__.py
@@ -1,32 +1,13 @@
import numpy as np
import mpas_tools.mesh.creation.mesh_definition_tools as mdt
-from compass.ocean.tests.global_ocean.mesh.mesh import MeshStep
+from compass.mesh import QuasiUniformSphericalMeshStep
-class EC30to60Mesh(MeshStep):
+class EC30to60BaseMesh(QuasiUniformSphericalMeshStep):
"""
A step for creating EC30to60 and ECwISC30to60 meshes
"""
- def __init__(self, test_case, mesh_name, with_ice_shelf_cavities):
- """
- Create a new step
-
- Parameters
- ----------
- test_case : compass.TestCase
- The test case this step belongs to
-
- mesh_name : str
- The name of the mesh
-
- with_ice_shelf_cavities : bool
- Whether the mesh includes ice-shelf cavities
- """
-
- super().__init__(test_case, mesh_name, with_ice_shelf_cavities,
- package=self.__module__,
- mesh_config_filename='ec30to60.cfg')
def build_cell_width_lat_lon(self):
"""
diff --git a/compass/ocean/tests/global_ocean/mesh/mesh.py b/compass/ocean/tests/global_ocean/mesh/mesh.py
deleted file mode 100644
index ea406d9192..0000000000
--- a/compass/ocean/tests/global_ocean/mesh/mesh.py
+++ /dev/null
@@ -1,138 +0,0 @@
-from mpas_tools.ocean import build_spherical_mesh
-from mpas_tools.ocean import inject_bathymetry
-from abc import abstractmethod
-
-from compass.ocean.tests.global_ocean.mesh.cull import cull_mesh
-from compass.step import Step
-
-
-class MeshStep(Step):
- """
- A step for creating a global MPAS-Ocean mesh
-
- Attributes
- ----------
- mesh_name : str
- The name of the mesh
-
- with_ice_shelf_cavities : bool
- Whether the mesh includes ice-shelf cavities
-
- package : str
- The python package for the mesh
-
- mesh_config_filename : str
- The name of the mesh config file
- """
- def __init__(self, test_case, mesh_name, with_ice_shelf_cavities,
- package, mesh_config_filename, name='mesh', subdir=None,
- do_inject_bathymetry=False, preserve_floodplain=False):
- """
- Create a new step
-
- Parameters
- ----------
- test_case : compass.ocean.tests.global_ocean.mesh.Mesh
- The test case this step belongs to
-
- mesh_name : str
- The name of the mesh
-
- with_ice_shelf_cavities : bool
- Whether the mesh includes ice-shelf cavities
-
- package : str
- The python package for the mesh
-
- mesh_config_filename : str
- The name of the mesh config file
-
- name : str, optional
- the name of the step
-
- subdir : str, optional
- the subdirectory for the step. The default is ``name``
-
- do_inject_bathymetry : bool, optional
- Whether to interpolate bathymetry from a data file so it
- can be used as a culling criteria
-
- preserve_floodplain : bool, optional
- Whether to leave land cells in the mesh based on bathymetry
- specified by do_inject_bathymetry
- """
- super().__init__(test_case, name=name, subdir=subdir, ntasks=1,
- min_tasks=1, cpus_per_task=None,
- min_cpus_per_task=None, openmp_threads=1)
- for file in ['culled_mesh.nc', 'culled_graph.info',
- 'critical_passages_mask_final.nc']:
- self.add_output_file(filename=file)
-
- self.mesh_name = mesh_name
- self.with_ice_shelf_cavities = with_ice_shelf_cavities
- self.package = package
- self.mesh_config_filename = mesh_config_filename
- self.do_inject_bathymetry = do_inject_bathymetry
- self.preserve_floodplain = preserve_floodplain
-
- def setup(self):
- """
- Set up the test case in the work directory, including downloading any
- dependencies.
- """
- # get the these properties from the config options
- config = self.config
- self.cpus_per_task = config.getint('global_ocean',
- 'mesh_cpus_per_task')
- self.min_cpus_per_task = config.getint('global_ocean',
- 'mesh_min_cpus_per_task')
-
- def run(self):
- """
- Run this step of the test case
- """
- with_ice_shelf_cavities = self.with_ice_shelf_cavities
- logger = self.logger
- do_inject_bathymetry = self.do_inject_bathymetry
- preserve_floodplain = self.preserve_floodplain
- floodplain_elevation = self.config.getfloat('global_ocean',
- 'floodplain_elevation')
-
- # only use progress bars if we're not writing to a log file
- use_progress_bar = self.log_filename is None
-
- # create the base mesh
- cellWidth, lon, lat = self.build_cell_width_lat_lon()
- build_spherical_mesh(cellWidth, lon, lat, out_filename='base_mesh.nc',
- logger=logger, use_progress_bar=use_progress_bar,
- do_inject_bathymetry=do_inject_bathymetry,
- preserve_floodplain=preserve_floodplain,
- floodplain_elevation=floodplain_elevation)
-
- cull_mesh(with_critical_passages=True, logger=logger,
- use_progress_bar=use_progress_bar,
- preserve_floodplain=preserve_floodplain,
- with_cavities=with_ice_shelf_cavities)
-
- if do_inject_bathymetry:
- inject_bathymetry(mesh_file='culled_mesh.nc')
-
- @abstractmethod
- def build_cell_width_lat_lon(self):
- """
- A function for creating cell width array for this mesh on a regular
- latitude-longitude grid. Child classes need to override this function
- to return the expected data
-
- Returns
- -------
- cellWidth : numpy.array
- m x n array of cell width in km
-
- lon : numpy.array
- longitude in degrees (length n and between -180 and 180)
-
- lat : numpy.array
- longitude in degrees (length m and between -90 and 90)
- """
- pass
diff --git a/compass/ocean/tests/global_ocean/mesh/qu240/__init__.py b/compass/ocean/tests/global_ocean/mesh/qu240/__init__.py
index 5174e1de3a..e69de29bb2 100644
--- a/compass/ocean/tests/global_ocean/mesh/qu240/__init__.py
+++ b/compass/ocean/tests/global_ocean/mesh/qu240/__init__.py
@@ -1,56 +0,0 @@
-import numpy as np
-
-from compass.ocean.tests.global_ocean.mesh.mesh import MeshStep
-
-
-class QU240Mesh(MeshStep):
- """
- A step for creating QU240 and QUwISC240 meshes
- """
- def __init__(self, test_case, mesh_name, with_ice_shelf_cavities):
- """
- Create a new step
-
- Parameters
- ----------
- test_case : compass.TestCase
- The test case this step belongs to
-
- mesh_name : str
- The name of the mesh
-
- with_ice_shelf_cavities : bool
- Whether the mesh includes ice-shelf cavities
- """
-
- super().__init__(test_case, mesh_name, with_ice_shelf_cavities,
- package=self.__module__,
- mesh_config_filename='qu240.cfg')
-
- def build_cell_width_lat_lon(self):
- """
- Create cell width array for this mesh on a regular latitude-longitude
- grid
-
- Returns
- -------
- cellWidth : numpy.array
- m x n array of cell width in km
-
- lon : numpy.array
- longitude in degrees (length n and between -180 and 180)
-
- lat : numpy.array
- longitude in degrees (length m and between -90 and 90)
- """
- dlon = 10.
- dlat = dlon
- constantCellWidth = 240.
-
- nlat = int(180/dlat) + 1
- nlon = int(360/dlon) + 1
- lat = np.linspace(-90., 90., nlat)
- lon = np.linspace(-180., 180., nlon)
-
- cellWidth = constantCellWidth * np.ones((lat.size, lon.size))
- return cellWidth, lon, lat
diff --git a/compass/ocean/tests/global_ocean/mesh/so12to60/__init__.py b/compass/ocean/tests/global_ocean/mesh/so12to60/__init__.py
index 096a5f31a3..d1df6f4c4a 100644
--- a/compass/ocean/tests/global_ocean/mesh/so12to60/__init__.py
+++ b/compass/ocean/tests/global_ocean/mesh/so12to60/__init__.py
@@ -6,39 +6,26 @@
from geometric_features import read_feature_collection
from mpas_tools.cime.constants import constants
-from compass.ocean.tests.global_ocean.mesh.mesh import MeshStep
+from compass.mesh import QuasiUniformSphericalMeshStep
-class SO12to60Mesh(MeshStep):
+class SO12to60BaseMesh(QuasiUniformSphericalMeshStep):
"""
A step for creating SOwISC12to60 meshes
"""
- def __init__(self, test_case, mesh_name, with_ice_shelf_cavities):
+ def setup(self):
"""
- Create a new step
-
- Parameters
- ----------
- test_case : compass.TestCase
- The test case this step belongs to
-
- mesh_name : str
- The name of the mesh
-
- with_ice_shelf_cavities : bool
- Whether the mesh includes ice-shelf cavities
+ Add some input files
"""
- super().__init__(test_case, mesh_name, with_ice_shelf_cavities,
- package=self.__module__,
- mesh_config_filename='so12to60.cfg')
-
self.add_input_file(filename='atlantic.geojson',
package=self.__module__)
self.add_input_file(filename='high_res_region.geojson',
package=self.__module__)
+ super().setup()
+
def build_cell_width_lat_lon(self):
"""
Create cell width array for this mesh on a regular latitude-longitude
diff --git a/compass/ocean/tests/global_ocean/mesh/wc14/__init__.py b/compass/ocean/tests/global_ocean/mesh/wc14/__init__.py
index 0cd1baee2a..2583e9b941 100644
--- a/compass/ocean/tests/global_ocean/mesh/wc14/__init__.py
+++ b/compass/ocean/tests/global_ocean/mesh/wc14/__init__.py
@@ -10,33 +10,18 @@
from mpas_tools.cime.constants import constants
from mpas_tools.viz.colormaps import register_sci_viz_colormaps
-from compass.ocean.tests.global_ocean.mesh.mesh import MeshStep
+from compass.mesh import QuasiUniformSphericalMeshStep
-class WC14Mesh(MeshStep):
+class WC14BaseMesh(QuasiUniformSphericalMeshStep):
"""
A step for creating SOwISC12to60 meshes
"""
- def __init__(self, test_case, mesh_name, with_ice_shelf_cavities):
+ def setup(self):
"""
- Create a new step
-
- Parameters
- ----------
- test_case : compass.ocean.tests.global_ocean.Mesh
- The test case this step belongs to
-
- mesh_name : str
- The name of the mesh
-
- with_ice_shelf_cavities : bool
- Whether the mesh includes ice-shelf cavities
+ Add some input files
"""
- super().__init__(test_case, mesh_name, with_ice_shelf_cavities,
- package=self.__module__,
- mesh_config_filename='wc14.cfg')
-
inputs = ['coastline_CUSP.geojson',
'land_mask_Kamchatka.geojson',
'land_mask_Mexico.geojson',
@@ -51,6 +36,8 @@ def __init__(self, test_case, mesh_name, with_ice_shelf_cavities):
self.add_input_file(filename=filename,
package=self.__module__)
+ super().setup()
+
def build_cell_width_lat_lon(self):
"""
Create cell width array for this mesh on a regular latitude-longitude
diff --git a/compass/ocean/tests/hurricane/configure.py b/compass/ocean/tests/hurricane/configure.py
index c7708e937f..4f0db8eff9 100644
--- a/compass/ocean/tests/hurricane/configure.py
+++ b/compass/ocean/tests/hurricane/configure.py
@@ -13,13 +13,11 @@ def configure_hurricane(test_case, mesh):
mesh : compass.ocean.tests.global_ocean.mesh.Mesh
The test case that produces the mesh for this run
-
- init : compass.ocean.tests.global_ocean.init.Init, optional
- The test case that produces the initial condition for this run
"""
config = test_case.config
- mesh_step = mesh.mesh_step
- config.add_from_package(mesh_step.package, mesh_step.mesh_config_filename,
+
+ config.add_from_package('compass.mesh', 'mesh.cfg')
+ config.add_from_package(mesh.package, mesh.mesh_config_filename,
exception=True)
get_author_and_email_from_git(config)
diff --git a/compass/ocean/tests/hurricane/forward/forward.py b/compass/ocean/tests/hurricane/forward/forward.py
index 37a444bfea..cc2047cce0 100644
--- a/compass/ocean/tests/hurricane/forward/forward.py
+++ b/compass/ocean/tests/hurricane/forward/forward.py
@@ -45,7 +45,7 @@ def __init__(self, test_case, mesh, init, name='forward', subdir=None):
self.add_streams_file(
'compass.ocean.tests.hurricane.forward', 'streams.ocean')
- mesh_package = mesh.mesh_step.package
+ mesh_package = mesh.package
self.add_namelist_file(mesh_package, 'namelist.ocean')
initial_state_target = \
diff --git a/compass/ocean/tests/hurricane/init/create_pointstats_file.py b/compass/ocean/tests/hurricane/init/create_pointstats_file.py
index e026aa378d..564f44031d 100644
--- a/compass/ocean/tests/hurricane/init/create_pointstats_file.py
+++ b/compass/ocean/tests/hurricane/init/create_pointstats_file.py
@@ -47,7 +47,7 @@ def __init__(self, test_case, mesh, storm):
'USGS_stations.txt']
self.pointstats_file = 'points.nc'
- mesh_path = mesh.mesh_step.path
+ mesh_path = mesh.steps['cull_mesh'].path
self.add_input_file(
filename=self.mesh_file,
diff --git a/compass/ocean/tests/hurricane/init/initial_state.py b/compass/ocean/tests/hurricane/init/initial_state.py
index 9064b0a620..6a9f13c164 100644
--- a/compass/ocean/tests/hurricane/init/initial_state.py
+++ b/compass/ocean/tests/hurricane/init/initial_state.py
@@ -38,7 +38,7 @@ def __init__(self, test_case, mesh):
# generate the streams file
self.add_streams_file(package, 'streams.init', mode='init')
- mesh_path = mesh.mesh_step.path
+ mesh_path = mesh.steps['cull_mesh'].path
self.add_input_file(
filename='mesh.nc',
diff --git a/compass/ocean/tests/hurricane/init/interpolate_atm_forcing.py b/compass/ocean/tests/hurricane/init/interpolate_atm_forcing.py
index 665c9f0a2b..f3b79c3601 100644
--- a/compass/ocean/tests/hurricane/init/interpolate_atm_forcing.py
+++ b/compass/ocean/tests/hurricane/init/interpolate_atm_forcing.py
@@ -75,7 +75,7 @@ def __init__(self, test_case, mesh, storm):
target=f'{storm}_prmsl.nc',
database='initial_condition_database')
- mesh_path = mesh.mesh_step.path
+ mesh_path = mesh.steps['cull_mesh'].path
self.add_input_file(
filename='mesh.nc',
diff --git a/compass/ocean/tests/hurricane/mesh/__init__.py b/compass/ocean/tests/hurricane/mesh/__init__.py
index 6202d37fb1..7006427e60 100644
--- a/compass/ocean/tests/hurricane/mesh/__init__.py
+++ b/compass/ocean/tests/hurricane/mesh/__init__.py
@@ -1,16 +1,13 @@
from compass.testcase import TestCase
from compass.ocean.tests.hurricane.mesh.dequ120at30cr10rr2 \
- import DEQU120at30cr10rr2Mesh
+ import DEQU120at30cr10rr2BaseMesh
+from compass.ocean.tests.hurricane.configure import configure_hurricane
+from compass.ocean.mesh.cull import CullMeshStep
class Mesh(TestCase):
"""
A test case for creating a global MPAS-Ocean mesh
-
- Attributes
- ----------
- mesh_step : compass.ocean.tests.global_ocean.mesh.mesh.MeshStep
- The step for creating the mesh
"""
def __init__(self, test_group, mesh_name):
"""
@@ -28,39 +25,31 @@ def __init__(self, test_group, mesh_name):
name = 'mesh'
subdir = '{}/{}'.format(mesh_name, name)
super().__init__(test_group=test_group, name=name, subdir=subdir)
+
+ name = 'base_mesh'
if mesh_name == 'DEQU120at30cr10rr2':
- self.mesh_step = DEQU120at30cr10rr2Mesh(
- self, mesh_name,
- preserve_floodplain=False)
+ base_mesh_step = DEQU120at30cr10rr2BaseMesh(
+ self, name=name, preserve_floodplain=False)
+ mesh_lower = 'dequ120at30cr10rr2'
elif mesh_name == 'DEQU120at30cr10rr2WD':
- self.mesh_step = DEQU120at30cr10rr2Mesh(
- self, mesh_name,
- preserve_floodplain=True)
+ base_mesh_step = DEQU120at30cr10rr2BaseMesh(
+ self, name=name, preserve_floodplain=True)
+ mesh_lower = 'dequ120at30cr10rr2'
else:
raise ValueError(f'Unexpected mesh name {mesh_name}')
- self.add_step(self.mesh_step)
+ self.package = f'compass.ocean.tests.hurricane.mesh.{mesh_lower}'
+ self.mesh_config_filename = f'{mesh_lower}.cfg'
+
+ self.add_step(base_mesh_step)
+
+ self.add_step(CullMeshStep(
+ test_case=self, base_mesh_step=base_mesh_step,
+ with_ice_shelf_cavities=False, do_inject_bathymetry=True,
+ preserve_floodplain=True))
def configure(self):
"""
Modify the configuration options for this test case
"""
- self.config.add_from_package(self.mesh_step.package,
- self.mesh_step.mesh_config_filename,
- exception=True)
-
- def run(self):
- """
- Run each step of the testcase
- """
- step = self.mesh_step
- config = self.config
-
- # get the these properties from the config options
- step.cpus_per_task = config.getint(
- 'global_ocean', 'mesh_cpus_per_task')
- step.min_cpus_per_task = config.getint(
- 'global_ocean', 'mesh_min_cpus_per_task')
-
- # run the step
- super().run()
+ configure_hurricane(test_case=self, mesh=self)
diff --git a/compass/ocean/tests/hurricane/mesh/dequ120at30cr10rr2/__init__.py b/compass/ocean/tests/hurricane/mesh/dequ120at30cr10rr2/__init__.py
index 573f6d6a21..5e5951fb02 100644
--- a/compass/ocean/tests/hurricane/mesh/dequ120at30cr10rr2/__init__.py
+++ b/compass/ocean/tests/hurricane/mesh/dequ120at30cr10rr2/__init__.py
@@ -1,41 +1,12 @@
import mpas_tools.ocean.coastal_tools as ct
-from compass.ocean.tests.global_ocean.mesh.mesh import MeshStep
+from compass.ocean.mesh.floodplain import FloodplainMeshStep
-class DEQU120at30cr10rr2Mesh(MeshStep):
+class DEQU120at30cr10rr2BaseMesh(FloodplainMeshStep):
"""
A step for creating DEQU120at30cr10rr2 meshes
"""
- def __init__(self, test_case, mesh_name, preserve_floodplain):
- """
- Create a new step
-
- Parameters
- ----------
- test_case : compass.TestCase
- The test case this step belongs to
-
- mesh_name : str
- The name of the mesh
-
- preserve_floodplain : bool
- Whether the mesh includes land cells
- """
-
- with_ice_shelf_cavities = False
-
- super().__init__(test_case, mesh_name, with_ice_shelf_cavities,
- package=self.__module__,
- mesh_config_filename='dequ120at30cr10rr2.cfg',
- do_inject_bathymetry=True,
- preserve_floodplain=preserve_floodplain)
-
- self.add_input_file(
- filename='earth_relief_15s.nc',
- target='SRTM15_plus_earth_relief_15s.nc',
- database='bathymetry_database')
-
def build_cell_width_lat_lon(self):
"""
Create cell width array for this mesh on a regular latitude-longitude
diff --git a/compass/ocean/tests/hurricane/mesh/dequ120at30cr10rr2/dequ120at30cr10rr2.cfg b/compass/ocean/tests/hurricane/mesh/dequ120at30cr10rr2/dequ120at30cr10rr2.cfg
index 0ddf050d72..6f37302e9d 100644
--- a/compass/ocean/tests/hurricane/mesh/dequ120at30cr10rr2/dequ120at30cr10rr2.cfg
+++ b/compass/ocean/tests/hurricane/mesh/dequ120at30cr10rr2/dequ120at30cr10rr2.cfg
@@ -1,19 +1,25 @@
-# options for global ocean testcases
-[global_ocean]
+# options for spherical meshes
+[spherical_mesh]
-## config options related to the mesh step
+## config options related to the step for culling land from the mesh
# number of cores to use
-mesh_cpus_per_task = 1
+cull_mesh_cpus_per_task = 18
# minimum of cores, below which the step fails
-mesh_min_cpus_per_task = 1
+cull_mesh_min_cpus_per_task = 1
+# maximum memory usage allowed (in MB)
+cull_mesh_max_memory = 1000
+
+# Elevation threshold to use for including land cells
+floodplain_elevation = 10.0
+
+
+# options for global ocean testcases
+[global_ocean]
# The following options are detected from .gitconfig if not explicitly entered
author = autodetect
email = autodetect
-# Elevation threshold to use for including land cells
-floodplain_elevation = 10.0
-
# options for hurricane testcases
[hurricane]
diff --git a/docs/developers_guide/ocean/api.rst b/docs/developers_guide/ocean/api.rst
index d5d704910f..1796805acf 100644
--- a/docs/developers_guide/ocean/api.rst
+++ b/docs/developers_guide/ocean/api.rst
@@ -166,32 +166,25 @@ test cases and steps
mesh.Mesh
mesh.Mesh.configure
mesh.Mesh.run
- mesh.cull.cull_mesh
- mesh.mesh.MeshStep
- mesh.mesh.MeshStep.setup
- mesh.mesh.MeshStep.run
- mesh.mesh.MeshStep.build_cell_width_lat_lon
- mesh.ec30to60.EC30to60Mesh
- mesh.ec30to60.EC30to60Mesh.build_cell_width_lat_lon
+ mesh.ec30to60.EC30to60BaseMesh
+ mesh.ec30to60.EC30to60BaseMesh.build_cell_width_lat_lon
mesh.ec30to60.dynamic_adjustment.EC30to60DynamicAdjustment
mesh.ec30to60.dynamic_adjustment.EC30to60DynamicAdjustment.configure
mesh.ec30to60.dynamic_adjustment.EC30to60DynamicAdjustment.run
- mesh.qu240.QU240Mesh
- mesh.qu240.QU240Mesh.build_cell_width_lat_lon
mesh.qu240.dynamic_adjustment.QU240DynamicAdjustment
mesh.qu240.dynamic_adjustment.QU240DynamicAdjustment.configure
mesh.qu240.dynamic_adjustment.QU240DynamicAdjustment.run
- mesh.so12to60.SO12to60Mesh
- mesh.so12to60.SO12to60Mesh.build_cell_width_lat_lon
+ mesh.so12to60.SO12to60BaseMesh
+ mesh.so12to60.SO12to60BaseMesh.build_cell_width_lat_lon
mesh.so12to60.dynamic_adjustment.SO12to60DynamicAdjustment
mesh.so12to60.dynamic_adjustment.SO12to60DynamicAdjustment.configure
mesh.so12to60.dynamic_adjustment.SO12to60DynamicAdjustment.run
- mesh.wc14.WC14Mesh
- mesh.wc14.WC14Mesh.build_cell_width_lat_lon
+ mesh.wc14.WC14BaseMesh
+ mesh.wc14.WC14BaseMesh.build_cell_width_lat_lon
mesh.wc14.dynamic_adjustment.WC14DynamicAdjustment
mesh.wc14.dynamic_adjustment.WC14DynamicAdjustment.configure
mesh.wc14.dynamic_adjustment.WC14DynamicAdjustment.run
@@ -281,8 +274,8 @@ test cases and steps
mesh.Mesh.configure
mesh.Mesh.run
- mesh.dequ120at30cr10rr2.DEQU120at30cr10rr2Mesh
- mesh.dequ120at30cr10rr2.DEQU120at30cr10rr2Mesh.build_cell_width_lat_lon
+ mesh.dequ120at30cr10rr2.DEQU120at30cr10rr2BaseMesh
+ mesh.dequ120at30cr10rr2.DEQU120at30cr10rr2BaseMesh.build_cell_width_lat_lon
init.Init
init.Init.configure
@@ -669,6 +662,14 @@ ocean framework
.. autosummary::
:toctree: generated/
+ mesh.cull.CullMeshStep
+ mesh.cull.CullMeshStep.setup
+ mesh.cull.CullMeshStep.run
+ mesh.cull.cull_mesh
+
+ mesh.floodplain.FloodplainMeshStep
+ mesh.floodplain.FloodplainMeshStep.run
+
haney.compute_haney_number
iceshelf.compute_land_ice_pressure_and_draft
diff --git a/docs/developers_guide/ocean/framework.rst b/docs/developers_guide/ocean/framework.rst
index 1b44481d56..2676015b77 100644
--- a/docs/developers_guide/ocean/framework.rst
+++ b/docs/developers_guide/ocean/framework.rst
@@ -37,6 +37,86 @@ and ``restingThickness`` variables for :ref:`ocean_z_level` and
:ref:`ocean_z_star` coordinates using the ``ssh`` and ``bottomDepth`` as well
as config options from ``vertical_grid``.
+.. _dev_ocean_framework_mesh:
+
+Mesh
+----
+
+The ``compass.ocean.mesh`` package includes modules for spherical ocean meshes
+shared across test groups.
+
+
+.. _dev_ocean_framework_cull_mesh:
+
+Culling Meshes
+~~~~~~~~~~~~~~
+
+The ``compass.ocean.mesh.cull`` module is for culling land cells from
+global ocean meshes.
+
+The class :py:class:`compass.ocean.mesh.cull.CullMeshStep` culls out land
+cells by calling ``cull_mesh()``.
+
+:py:func:`compass.ocean.mesh.cull.cull_mesh()` uses a number of
+capabilities from `MPAS-Tools `_
+and `geometric_features `_
+to cull the mesh. It performs the following steps:
+
+1. combining Natural Earth land coverage north of 60S with Antarctic
+ ice coverage or grounded ice coverage from BedMachineAntarctica
+
+2. combining transects defining critical passages (if
+ ``with_critical_passages=True``)
+
+3. combining points used to seed a flood fill of the global ocean.
+
+4. create masks from land coverage
+
+5. add land-locked cells to land coverage mask.
+
+6. create masks from transects (if ``with_critical_passages=True``)
+
+7. cull cells based on land coverage but with transects present
+
+8. create flood-fill mask based on seeds
+
+9. cull cells based on flood-fill mask
+
+10. create masks from transects on the final culled mesh (if
+ ``with_critical_passages=True``)
+
+
+.. _dev_ocean_framework_floodplain:
+
+Including a Floodplain
+~~~~~~~~~~~~~~~~~~~~~~
+
+The ``compass.ocean.mesh.floodplain`` module is for adding support for a
+floodplain to a base global ocean mesh.
+
+The class :py:class:`compass.ocean.mesh.floodplain.FloodplainMeshStep`
+descends from :py:class:`compass.mesh.QuasiUniformSphericalMeshStep`, adding
+an attribute:
+
+``self.preserve_floodplain``
+ A ``bool`` defining whether the mesh includes land cells
+
+and including topography in the base mesh from the
+`SRTM15_plus_earth_relief_15s.nc` file in the `bathymetry_database`. The
+``run()`` method uses the config option:
+
+.. code-block:: ini
+
+ # options for spherical meshes
+ [spherical_mesh]
+
+ # Elevation threshold to use for including land cells
+ floodplain_elevation = 10.0
+
+to determine the elevation of the floodplain to maintain above sea level.
+The bathymetry and the floodplain are added to the mesh using
+:py:func:`mpas_tools.ocean.inject_bathymetry()` and
+:py:func:`mpas_tools.ocean.inject_preserve_floodplain()`, respectively.
.. _dev_ocean_framework_haney:
diff --git a/docs/developers_guide/ocean/test_groups/global_ocean.rst b/docs/developers_guide/ocean/test_groups/global_ocean.rst
index 6fe63cc184..5d68ca9315 100644
--- a/docs/developers_guide/ocean/test_groups/global_ocean.rst
+++ b/docs/developers_guide/ocean/test_groups/global_ocean.rst
@@ -268,21 +268,10 @@ to improve model efficiency.
A :py:class:`compass.ocean.tests.global_ocean.mesh.Mesh` object is constructed
with the ``mesh_name`` as one of its arguments. Based on this argument, it
determines the appropriate child class of
-:py:class:`compass.ocean.tests.global_ocean.mesh.mesh.MeshStep` to create.
+:py:class:`compass.mesh.spherical.SphericalBaseStep` to create the base mesh
+and adds a :py:class:`compass.ocean.mesh.cull.CullMeshStep`.
-.. _dev_ocean_global_ocean_mesh_step:
-
-mesh step
-^^^^^^^^^
-
-The parent class :py:class:`compass.ocean.tests.global_ocean.mesh.mesh.MeshStep`
-defines a method
-:py:meth:`compass.ocean.tests.global_ocean.mesh.mesh.MeshStep.build_cell_width_lat_lon()`
-that a child class for each mesh type must override to define the size of
-MPAS cells as a function of longitude and latitude.
-
-This class also takes care of defining the output from the step and storing
-attributes:
+This class also stores attributes:
``self.mesh_name``
the name of the mesh
@@ -297,39 +286,6 @@ attributes:
``self.mesh_config_filename``
the name of the config file with mesh-specific config options
-In its ``run()`` method, ``MeshStep`` calls the ``build_cell_width_lat_lon()``
-method to get the desired mesh resolution, then creates the mesh by calling
-:py:func:`mpas_tools.ocean.build_mesh.build_spherical_mesh()` culls out land
-cells by calling :py:func:`compass.ocean.tests.global_ocean.mesh.cull.cull_mesh()`.
-
-``cull_mesh()`` uses a number of capabilities from
-`MPAS-Tools `_
-and `geometric_features `_
-to cull the mesh. It performs the following steps:
-
-1. combining Natural Earth land coverage north of 60S with Antarctic
- ice coverage or grounded ice coverage from BedMachineAntarctica
-
-2. combining transects defining critical passages (if
- ``with_critical_passages=True``)
-
-3. combining points used to seed a flood fill of the global ocean.
-
-4. create masks from land coverage
-
-5. add land-locked cells to land coverage mask.
-
-6. create masks from transects (if ``with_critical_passages=True``)
-
-7. cull cells based on land coverage but with transects present
-
-8. create flood-fill mask based on seeds
-
-9. cull cells based on flood-fill mask
-
-10. create masks from transects on the final culled mesh (if
- ``with_critical_passages=True``)
-
.. _dev_ocean_global_ocean_meshes:
meshes
@@ -344,12 +300,12 @@ QU240 and QUwISC240
The ``QU240`` mesh is a quasi-uniform mesh with 240-km resolution. The
``QUwISC240`` mesh is identical except that it includes the cavities below ice
-shelves in the ocean domain. The class
-:py:class:`compass.ocean.tests.global_ocean.mesh.qu240.QU240Mesh` defines the
-resolution for both meshes. The ``compass.ocean.tests.global_ocean.mesh.qu240``
-module includes namelist options appropriate for forward simulations with both
-RK4 and split-explicit time integration on this mesh. These set the time step
-and default run duration for short runs with this mesh.
+shelves in the ocean domain. The mesh is defined by
+:py:class:`compass.mesh.QuasiUniformSphericalMeshStep`. The
+``compass.ocean.tests.global_ocean.mesh.qu240`` module includes namelist
+options appropriate for forward simulations with both RK4 and split-explicit
+time integration on this mesh. These set the time step and default run
+duration for short runs with this mesh.
The default config options for this mesh are:
@@ -379,23 +335,19 @@ The default config options for this mesh are:
## config options related to the initial_state step
# number of cores to use
- init_cores = 4
+ init_ntasks = 4
# minimum of cores, below which the step fails
- init_min_cores = 1
+ init_min_tasks = 1
# maximum memory usage allowed (in MB)
init_max_memory = 1000
- # maximum disk usage allowed (in MB)
- init_max_disk = 1000
## config options related to the forward steps
# number of cores to use
- forward_cores = 4
+ forward_ntasks = 4
# minimum of cores, below which the step fails
- forward_min_cores = 1
+ forward_min_tasks = 1
# maximum memory usage allowed (in MB)
forward_max_memory = 1000
- # maximum disk usage allowed (in MB)
- forward_max_disk = 1000
## metadata related to the mesh
# the prefix (e.g. QU, EC, WC, SO)
@@ -420,6 +372,17 @@ The default config options for this mesh are:
The vertical grid is a ``tanh_dz`` profile (see :ref:`dev_ocean_framework_vertical`)
with 16 vertical levels ranging in thickness from 3 to 500 m.
+.. _dev_ocean_global_ocean_isco240:
+
+Icos240 and IcoswISC240
++++++++++++++++++++++++
+
+The ``Icos240`` mesh is a subdivided icosahedral mesh with 240-km resolution
+using the :py:class:`compass.mesh.IcosahedralMeshStep` class. The
+``IcoswISC240`` mesh is identical except that it includes the cavities below
+ice shelves in the ocean domain. Aside from the base mesh, these are identical
+to :ref:`dev_ocean_global_ocean_qu240`.
+
.. _dev_ocean_global_ocean_ec30to60:
EC30to60 and ECwISC30to60
@@ -454,23 +417,19 @@ The default config options for this mesh are:
## config options related to the initial_state step
# number of cores to use
- init_cores = 36
+ init_ntasks = 36
# minimum of cores, below which the step fails
- init_min_cores = 8
+ init_min_tasks = 8
# maximum memory usage allowed (in MB)
init_max_memory = 1000
- # maximum disk usage allowed (in MB)
- init_max_disk = 1000
## config options related to the forward steps
# number of cores to use
- forward_cores = 128
+ forward_ntasks = 128
# minimum of cores, below which the step fails
- forward_min_cores = 36
+ forward_min_tasks = 36
# maximum memory usage allowed (in MB)
forward_max_memory = 1000
- # maximum disk usage allowed (in MB)
- forward_max_disk = 1000
## metadata related to the mesh
# the prefix (e.g. QU, EC, WC, SO)
@@ -528,23 +487,19 @@ The default config options for this mesh are:
## config options related to the initial_state step
# number of cores to use
- init_cores = 36
+ init_ntasks = 36
# minimum of cores, below which the step fails
- init_min_cores = 8
+ init_min_tasks = 8
# maximum memory usage allowed (in MB)
init_max_memory = 1000
- # maximum disk usage allowed (in MB)
- init_max_disk = 1000
## config options related to the forward steps
# number of cores to use
- forward_cores = 1296
+ forward_ntasks = 1296
# minimum of cores, below which the step fails
- forward_min_cores = 128
+ forward_min_tasks = 128
# maximum memory usage allowed (in MB)
forward_max_memory = 1000
- # maximum disk usage allowed (in MB)
- forward_max_disk = 1000
## metadata related to the mesh
# the prefix (e.g. QU, EC, WC, SO)
@@ -607,23 +562,19 @@ The default config options for this mesh are:
## config options related to the initial_state step
# number of cores to use
- init_cores = 36
+ init_ntasks = 36
# minimum of cores, below which the step fails
- init_min_cores = 8
+ init_min_tasks = 8
# maximum memory usage allowed (in MB)
init_max_memory = 1000
- # maximum disk usage allowed (in MB)
- init_max_disk = 1000
## config options related to the forward steps
# number of cores to use
- forward_cores = 720
+ forward_ntasks = 720
# minimum of cores, below which the step fails
- forward_min_cores = 144
+ forward_min_tasks = 144
# maximum memory usage allowed (in MB)
forward_max_memory = 1000
- # maximum disk usage allowed (in MB)
- forward_max_disk = 1000
## metadata related to the mesh
# the prefix (e.g. QU, EC, WC, SO)
diff --git a/docs/users_guide/ocean/test_groups/global_ocean.rst b/docs/users_guide/ocean/test_groups/global_ocean.rst
index 81d16a12b6..514f818679 100644
--- a/docs/users_guide/ocean/test_groups/global_ocean.rst
+++ b/docs/users_guide/ocean/test_groups/global_ocean.rst
@@ -33,44 +33,42 @@ Note that meshes and test cases may modify these options, as noted below.
.. code-block:: cfg
- # options for global ocean testcases
- [global_ocean]
-
- ## each mesh should replace these with appropriate values in its config file
+ # options for spherical meshes
+ [spherical_mesh]
- ## config options related to the mesh step
+ ## config options related to the step for culling land from the mesh
# number of cores to use
- mesh_cores = 1
+ cull_mesh_cpus_per_task = 18
# minimum of cores, below which the step fails
- mesh_min_cores = 1
+ cull_mesh_min_cpus_per_task = 1
# maximum memory usage allowed (in MB)
- mesh_max_memory = 1000
- # maximum disk usage allowed (in MB)
- mesh_max_disk = 1000
+ cull_mesh_max_memory = 1000
+
+
+ # options for global ocean testcases
+ [global_ocean]
+
+ ## each mesh should replace these with appropriate values in its config file
## config options related to the initial_state step
# number of cores to use
- init_cores = 4
+ init_ntasks = 4
# minimum of cores, below which the step fails
- init_min_cores = 1
+ init_min_tasks = 1
# maximum memory usage allowed (in MB)
init_max_memory = 1000
- # maximum disk usage allowed (in MB)
- init_max_disk = 1000
# number of threads
init_threads = 1
## config options related to the forward steps
# number of cores to use
- forward_cores = 4
+ forward_ntasks = 4
# minimum of cores, below which the step fails
- forward_min_cores = 1
+ forward_min_tasks = 1
# number of threads
forward_threads = 1
# maximum memory usage allowed (in MB)
forward_max_memory = 1000
- # maximum disk usage allowed (in MB)
- forward_max_disk = 1000
## metadata related to the mesh
# whether to add metadata to output files
@@ -105,6 +103,16 @@ Note that meshes and test cases may modify these options, as noted below.
# The URL of the pull request documenting the creation of the mesh
pull_request = <<>>
+ # Elevation threshold for including land cells
+ floodplain_elevation = 10.0
+
+
+ # config options related to dynamic adjustment
+ [dynamic_adjustment]
+
+ # the maximum allowed value of temperatureMax in global statistics
+ temperature_max = 33.0
+
# config options related to initial condition and diagnostics support files
# for E3SM
@@ -140,8 +148,8 @@ Note that meshes and test cases may modify these options, as noted below.
comparisonArcticStereoWidth = 6000.
comparisonArcticStereoResolution = 10.
-The ``mesh_*``, ``init_*`` and ``forward:*`` config options are used to specify
-the resources used in in the ``mesh`` step of the :ref:`global_ocean_mesh`,
+The ``cull_mesh_*``, ``init_*`` and ``forward:*`` config options are used to
+specify the resources used in in the ``mesh`` step of the :ref:`global_ocean_mesh`,
the ``initial_state`` step of the :ref:`global_ocean_init` and the
:ref:`global_ocean_forward`, respectively. These values will differ between
test cases and meshes.
@@ -378,7 +386,7 @@ options directly in ``namelist.ocean`` or modifying streams in
you can change in the config file for a test case. Since some test cases like
:ref:`global_ocean_restart_test` and :ref`global_ocean_dynamic_adjustment` have
more than one forward run, it is convenient to change options like
-``forward_cores`` once in the config file, knowing that this will change the
+``forward_ntasks`` once in the config file, knowing that this will change the
target number of cores of all forward model runs in the test case. The same
applies to the other ``forward_*`` config options that change the minimum cores
allowed, the number of threads, and (in the future) the maximum memory and disk
diff --git a/docs/users_guide/ocean/test_groups/hurricane.rst b/docs/users_guide/ocean/test_groups/hurricane.rst
index e0418baada..f908a2413d 100644
--- a/docs/users_guide/ocean/test_groups/hurricane.rst
+++ b/docs/users_guide/ocean/test_groups/hurricane.rst
@@ -26,22 +26,28 @@ Note that meshes and test cases may modify these options, as noted below.
.. code-block:: cfg
- # options for global ocean testcases
- [global_ocean]
+ # options for spherical meshes
+ [spherical_mesh]
- ## config options related to the mesh step
+ ## config options related to the step for culling land from the mesh
# number of cores to use
- mesh_ntasks = 1
+ cull_mesh_cpus_per_task = 18
# minimum of cores, below which the step fails
- mesh_min_tasks = 1
+ cull_mesh_min_cpus_per_task = 1
+ # maximum memory usage allowed (in MB)
+ cull_mesh_max_memory = 1000
+
+ # Elevation threshold to use for including land cells
+ floodplain_elevation = 10.0
+
+
+ # options for global ocean testcases
+ [global_ocean]
# The following options are detected from .gitconfig if not explicitly entered
author = autodetect
email = autodetect
- # Elevation threshold to use for including land cells
- floodplain_elevation = 10.0
-
# options for hurricane testcases
[hurricane]