Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
9b7aebe
Add devr45to5rr1 mesh
sbrus89 May 3, 2024
eba8ab0
Modifications for subgrid in hurricane case
sbrus89 Oct 31, 2024
97f5370
Turn on SAL and TWD in forward namelist
sbrus89 Dec 3, 2024
14ddd9a
Copy bed_elevation to bottomDepthObserved in init step
sbrus89 Dec 3, 2024
7376e73
Prevent infinite loop in calculate_wave_drag.py when fixing Nan values
sbrus89 Dec 3, 2024
38bbc6b
Add calculate wave drag and remap bathymetry steps to hurricane init
sbrus89 Dec 3, 2024
574f7a7
Add 15sec resolution option to pixel file step
sbrus89 Dec 3, 2024
80b84e3
Create pixel file for all meshes
sbrus89 Dec 3, 2024
7c126ee
Use dem_remap instead of inject_bathymetry in floodplain mesh
sbrus89 Dec 3, 2024
e445427
Use modified box for specifying Delaware resolution
sbrus89 Jan 8, 2025
7f77130
Cull mesh using remapped topography for ice shelves, region mask for …
sbrus89 Jan 8, 2025
4b19ec5
Update remap_bathymetry
sbrus89 Jan 8, 2025
ef87b29
Add topotgraphic wave drag file to forward step and streams
sbrus89 Jan 8, 2025
13f67ea
Add ice shelf cavity information in initial state
sbrus89 Jan 8, 2025
9955af1
Set start date for analysis plots back to being closer to landfall (1…
sbrus89 Jan 8, 2025
b13d8f3
Remove do_inject_bathymetry option
sbrus89 Jan 8, 2025
8289ffd
Ignore Northern hemisphere land ice masks
sbrus89 Jan 13, 2025
000e4d1
Add back SRTM as input file
sbrus89 Jan 14, 2025
7ec5b12
Fix initial_stat for standard wetting and drying
sbrus89 Mar 28, 2025
38669e1
Add code for barrier island identification
sbrus89 Apr 1, 2025
b611cdd
Update remap_topography config
sbrus89 Apr 3, 2025
f29782d
Update hurricane analysis step
sbrus89 May 9, 2025
9938f75
Update initial state for NCEI dem data
sbrus89 Jul 8, 2025
8277fe0
Create load-balanced graph files for subgrid init
sbrus89 Jul 18, 2025
74e507c
Insert ice shelf cavity information into last subgrid init file
sbrus89 Jul 21, 2025
c3c81e5
Increase number of tasks for init
sbrus89 Jul 21, 2025
4730445
Increase subgrid refinement level
sbrus89 Jul 21, 2025
13e14ff
Update DEM file names
sbrus89 Jul 21, 2025
0a46691
Add streams template
sbrus89 Jul 21, 2025
4f66fca
Replace dem file name in initial namelist
sbrus89 Jul 21, 2025
6a86890
Remove old namelist and streams files
sbrus89 Aug 20, 2025
494ef7d
Add step to interpolate mannings n
sbrus89 Aug 22, 2025
0bfc75b
Add Chesapeake DEMS
sbrus89 Aug 22, 2025
3a2d365
Use pnetcdf,cdf5 as io type for streams
sbrus89 Aug 22, 2025
82a66c8
Enable increased levels for subgrid tables
sbrus89 Aug 22, 2025
fb96e19
Enable variable mannings n in forward run
sbrus89 Aug 28, 2025
27eae0f
Fix bug in initial state for final subgrid file
sbrus89 Aug 28, 2025
bf1683d
Increase subgrid dt to 10s and turn off del4
sbrus89 Aug 28, 2025
e002257
Add updates for subgrid drag
sbrus89 Sep 12, 2025
d2f806c
Extend adjustment period for observations
sbrus89 Sep 16, 2025
711c875
Add option to plot DEM and LULC around stations
sbrus89 Sep 25, 2025
008ac75
Fix rebase issues from cull step topography smoothing option
sbrus89 Sep 25, 2025
e3e7b59
Clean up parabolic bowl test case
sbrus89 Oct 21, 2025
b7bf47e
Clean up buttermilk bay test case
sbrus89 Oct 21, 2025
dc1ca00
Improve DEM plotting around stations
sbrus89 Oct 21, 2025
5b81335
Remove highest resolution Delware Bay refinement
sbrus89 Oct 21, 2025
b386a4b
Add clipping limits to subgrid hurricane init namelist
sbrus89 Oct 21, 2025
6d12dd4
Format decimal seconds for dt in buttermilk bay case
sbrus89 Feb 16, 2026
117c3ae
Enable mannings n subgrid friction in buttermilk bay case
sbrus89 Feb 16, 2026
cfb5cb0
Update buttermilk bay analysis points
sbrus89 Feb 16, 2026
a145780
Update subgrid refinement level based on resolution in buttermilk bay…
sbrus89 Feb 16, 2026
d51ca4a
Update buttermilk bay viz
sbrus89 Feb 16, 2026
ffc2f70
Update parabolic bowl viz step
sbrus89 Feb 16, 2026
e50e635
Add comment to cull.py about floodplains
sbrus89 Feb 16, 2026
81f862c
Increase floodplain elevation to 40m for devr45to5rr1 mesh
sbrus89 Feb 17, 2026
84054e9
Add floodplain region capability
sbrus89 Feb 17, 2026
4dc48b6
Add RRS6to18 mesh
sbrus89 Feb 17, 2026
9dad9ec
Update hurricane analysis
sbrus89 Feb 17, 2026
7385d37
Add error and plot_subgrid scripts for buttermilk bay case
sbrus89 Feb 17, 2026
245ff01
Only load balance graph for subgrid
sbrus89 May 28, 2026
5b58984
Compass v2.0.0 compatibility changes to hurricane
bmooremaley Jun 23, 2026
b75604c
Namelist changes to hurricane/forward to account for E3SM/master changes
bmooremaley Jul 20, 2026
3eda88a
Updated user docs for ocean/hurricane test group
bmooremaley Jul 22, 2026
0f7f22f
Updated developer docs for ocean/hurricane test group
bmooremaley Jul 22, 2026
ed4fa9a
Fix _ocean_hurricane_sandy_subgrid ref in ocean/hurricane user docs
bmooremaley Jul 28, 2026
ab70518
Fix rst syntax in ocean/hurricane user docs
bmooremaley Jul 29, 2026
aec1710
Fix ocean/hurricane docstrings and update API
bmooremaley Jul 31, 2026
77efd64
Run linter on subgrid_hurricane changes
bmooremaley Jul 31, 2026
1aaeec7
Update to v2.0.0-alpha.3
bmooremaley Aug 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 7 additions & 24 deletions compass/ocean/mesh/cull.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from mpas_tools.mesh.creation.sort_mesh import sort_mesh
from mpas_tools.mesh.cull import cull_dataset, map_culled_to_base
from mpas_tools.mesh.mask import compute_mpas_flood_fill_mask
from mpas_tools.ocean import inject_bathymetry
from mpas_tools.ocean.coastline_alteration import (
add_critical_land_blockages,
add_land_locked_cells_to_mask,
Expand All @@ -38,13 +37,9 @@ class CullMeshStep(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
Whether to leave land cells in the mesh based on floodplain
specified by regionCellMasks

unsmoothed_topo : compass.ocean.mesh.remap_topography.RemapTopography
A step for remapping topography. If provided, the remapped
Expand All @@ -57,7 +52,7 @@ class CullMeshStep(Step):
"""

def __init__(self, test_case, base_mesh_step, with_ice_shelf_cavities,
name='cull_mesh', subdir=None, do_inject_bathymetry=False,
name='cull_mesh', subdir=None,
preserve_floodplain=False, unsmoothed_topo=None,
smoothed_topo=None):
"""
Expand All @@ -80,13 +75,10 @@ def __init__(self, test_case, base_mesh_step, with_ice_shelf_cavities,
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
Whether to leave land cells in the mesh based on floodplain
specified by regionCellMasks

unsmoothed_topo : compass.ocean.mesh.remap_topography.RemapTopography, optional
A step for remapping topography. If provided, the remapped
Expand All @@ -110,7 +102,6 @@ def __init__(self, test_case, base_mesh_step, with_ice_shelf_cavities,
self.add_output_file(filename='land_ice_mask.nc')

self.with_ice_shelf_cavities = with_ice_shelf_cavities
self.do_inject_bathymetry = do_inject_bathymetry
self.preserve_floodplain = preserve_floodplain

def setup(self):
Expand All @@ -119,11 +110,6 @@ def setup(self):
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')

base_path = self.base_mesh_step.path
base_filename = self.base_mesh_step.config.get(
Expand Down Expand Up @@ -180,7 +166,6 @@ def run(self):
# 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

convert_to_cdf5 = config.getboolean('spherical_mesh',
Expand All @@ -200,9 +185,6 @@ def run(self):
latitude_threshold=latitude_threshold,
sweep_count=sweep_count)

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,
Expand Down Expand Up @@ -257,7 +239,7 @@ def cull_mesh(with_cavities=False, with_critical_passages=False,
(``with_critical_passages=True``)

preserve_floodplain : bool, optional
Whether to use the ``cellSeedMask`` field in the base mesh to preserve
Whether to use ``regionCellMasks`` field in the base mesh to preserve
a floodplain at elevations above z=0

logger : logging.Logger, optional
Expand Down Expand Up @@ -399,6 +381,7 @@ def _cull_mesh_with_logging(logger, with_cavities, with_critical_passages,
dsPreserve.append(dsCritPassMask)

if preserve_floodplain:
# base mesh contains regionCellMasks field to indicate floodplain
dsPreserve.append(dsBaseMesh)

# fix land locked cells after adding critical land blockages, as these
Expand Down
130 changes: 126 additions & 4 deletions compass/ocean/mesh/floodplain.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
from mpas_tools.ocean import inject_bathymetry, inject_preserve_floodplain
import netCDF4 as nc4
import numpy as np
from geometric_features import read_feature_collection
from inpoly import inpoly2
from mpas_tools.mesh.creation.signed_distance import _add_poly

import compass.ocean.tests.tides.dem.dem_remap as dem_remap
from compass.mesh.spherical import QuasiUniformSphericalMeshStep


Expand Down Expand Up @@ -44,6 +49,14 @@ def __init__(self, test_case, name='base_mesh', subdir=None,
target='SRTM15_plus_earth_relief_15s.nc',
database='bathymetry_database')

pixel_path = test_case.steps['pixel'].path
pixel_file = f'{pixel_path}/RTopo_2_0_4_GEBCO_v2023_30sec_pixel.nc'
self.add_input_file(
filename='bathy.nc',
work_dir_target=pixel_file)

self.bottomDepth_varname = 'bottomDepthObserved'

def run(self):
"""
Run this step of the test case
Expand All @@ -54,10 +67,119 @@ def run(self):

mesh_filename = config.get('spherical_mesh', 'mpas_mesh_filename')

inject_bathymetry(mesh_file=mesh_filename)
dem_remap.dem_remap('bathy.nc', mesh_filename)

# Create new NetCDF variables in mesh file, if necessary
nc_mesh = nc4.Dataset(mesh_filename, 'r+')
nc_vars = nc_mesh.variables.keys()
if 'bottomDepthObserved' not in nc_vars:
nc_mesh.createVariable('bottomDepthObserved', 'f8', ('nCells'))

# Write to mesh file
nc_mesh.variables['bottomDepthObserved'][:] = \
nc_mesh.variables['bed_elevation'][:]
nc_mesh.close()

if self.preserve_floodplain:
floodplain_elevation = config.getfloat('spherical_mesh',
'floodplain_elevation')
inject_preserve_floodplain(
min_depth_outside_floodplain = config.getfloat(
'spherical_mesh',
'min_depth_outside_floodplain')
if config.has_option('spherical_mesh', 'floodplain_resolution'):
floodplain_resolution = config.getfloat(
'spherical_mesh',
'floodplain_resolution')
else:
floodplain_resolution = 1e10
if config.has_option('spherical_mesh', 'floodplain_geojson'):
floodplain_geojson = config.get(
'spherical_mesh',
'floodplain_geojson')
floodplain_region = read_feature_collection(floodplain_geojson)
else:
floodplain_region = None

self.inject_preserve_floodplain(
mesh_file=mesh_filename,
floodplain_elevation=floodplain_elevation)
floodplain_elevation=floodplain_elevation,
floodplain_resolution=floodplain_resolution,
floodplain_region=floodplain_region,
min_depth_outside_floodplain=min_depth_outside_floodplain)

def inject_preserve_floodplain(self, mesh_file, floodplain_elevation,
floodplain_resolution=1e10,
floodplain_region=None,
min_depth_outside_floodplain=5.0):

nc_mesh = nc4.Dataset(mesh_file, 'r+')
nc_vars = nc_mesh.variables.keys()

if 'regionCellMasks' not in nc_vars:
nc_mesh.createDimension('nRegions', 1)
nc_mesh.createVariable('regionCellMasks', 'i',
('nCells', 'nRegions'))
nc_mesh.variables['regionCellMasks'][:] = 0.0

if 'transectCellMasks' not in nc_vars:
nc_mesh.createDimension('nTransects', 1)
nc_mesh.createVariable('transectCellMasks', 'i',
('nCells', 'nTransects'))
nc_mesh.variables['transectCellMasks'][:] = 0.0

floodplain = self.find_floodplain(mesh_file, floodplain_elevation,
floodplain_resolution,
floodplain_region)

nc_mesh.variables['regionCellMasks'][:] = floodplain

nc_mesh.close()

def find_floodplain(self, mesh_file, floodplain_elevation,
floodplain_resolution,
floodplain_region):

nc_mesh = nc4.Dataset(mesh_file, 'r+')

bottomDepth = self.bottomDepth_varname
h = 2.0 * np.sqrt(nc_mesh.variables['areaCell'][:] / np.pi) / 1000.0
floodplain = np.logical_and(
h < floodplain_resolution,
nc_mesh.variables[bottomDepth][:] < floodplain_elevation)
if floodplain_region:
print("adding floodplain region")
nodes = list()
edges = list()
for feature in floodplain_region.features:
if feature['geometry']['type'] == 'Polygon':
for poly in feature['geometry']['coordinates']:
_add_poly(poly, edges, nodes)

elif feature['geometry']['type'] == 'MultiPolygon':
for mpoly in feature['geometry']['coordinates']:
for poly in mpoly:
_add_poly(poly, edges, nodes)

nodes = np.array(nodes)
edges = np.array(edges)
print(nodes)
print(edges)

lon = np.degrees(nc_mesh.variables['lonCell'][:])
lon = np.mod(lon + 180.0, 360.0) - 180.0
lat = np.degrees(nc_mesh.variables['latCell'][:])

points = np.vstack([lon, lat]).T

floodplain_mask, _ = inpoly2(points, nodes, edges)
floodplain_mask = 1 * floodplain_mask
print(np.max(floodplain_mask))
print(np.min(floodplain_mask))

else:
floodplain_mask = 1
floodplain = floodplain_mask * floodplain

nc_mesh.close()

return floodplain
3 changes: 2 additions & 1 deletion compass/ocean/tests/buttermilk_bay/buttermilk_bay.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ max_cells_per_core = 3000
[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]
#points = [2.8, 0.53], [1.9, 1.66], [2.4, 3.029], [2.51, 3.027], [1.26, 1.56]
points = [2.8, 0.53], [1.9, 1.66], [3.0, 3.25], [2.6, 3.25], [1.26, 1.56]

# generate contour plots at a specified interval between output timesnaps
plot_interval = 1
22 changes: 18 additions & 4 deletions compass/ocean/tests/buttermilk_bay/forward.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import time

from compass.model import run_model
from compass.step import Step

Expand Down Expand Up @@ -107,11 +105,27 @@ def get_dt(self):
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))
dt = self.format_seconds(dt, 1)

return dt

def format_seconds(self, seconds, decimal_places=2):
# Handle negative values
is_negative = seconds < 0
seconds = abs(seconds)

# Extract hours, minutes, and seconds
hours = int(seconds // 3600)
remaining = seconds % 3600
minutes = int(remaining // 60)
secs = remaining % 60

# Format the string with specified decimal places
sign = '-' if is_negative else ''
time = (f"{sign}{hours:02d}:{minutes:02d}:"
f"{secs:0{3 + decimal_places}.{decimal_places}f}")
return time

def _get_resources(self):
""" get the these properties from the config options """
config = self.config
Expand Down
10 changes: 9 additions & 1 deletion compass/ocean/tests/buttermilk_bay/initial_state.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import numpy as np
from mpas_tools.io import write_netcdf
from mpas_tools.mesh.conversion import convert, cull
from mpas_tools.planar_hex import make_planar_hex_mesh
Expand All @@ -23,6 +24,7 @@ def __init__(self, test_case, name, resolution,
"""
self.coord_type = coord_type
self.resolution = resolution
self.wetdry = wetdry

super().__init__(test_case=test_case, name=name, ntasks=1,
min_tasks=1, openmp_threads=1)
Expand All @@ -40,14 +42,19 @@ def __init__(self, test_case, name, resolution,
self.add_input_file(
filename='buttermilk_bathy.nc',
target='buttermilk_bathy.nc',
database='bathymetry_database')
database='buttermilk_bay')

for file in ['base_mesh.nc', 'culled_mesh.nc', 'culled_graph.info',
'ocean.nc', 'init_mode_forcing_data.nc']:
self.add_output_file(file)

self.add_model_as_input()

def setup(self):
level = int(self.resolution * np.tan(np.pi / 6.0)) + 1
option = {'config_subgrid_refinement_level': f'{level}'}
self.add_namelist_options(option, mode='init')

def run(self):
"""
Run this step of the test case
Expand All @@ -62,6 +69,7 @@ def run(self):
else:
vert_levels = config.getint('vertical_grid', 'vert_levels')
options = {'config_buttermilk_bay_vert_levels': f'{vert_levels}'}

self.update_namelist_at_runtime(options)

# Determine mesh parameters
Expand Down
2 changes: 2 additions & 0 deletions compass/ocean/tests/buttermilk_bay/namelist.forward
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ config_mom_del2 = 2.0e1
config_use_tidal_forcing = .true.
config_tidal_forcing_type = 'direct'
config_tidal_forcing_model = 'monochromatic'
config_use_variable_drag = .true.
config_implicit_bottom_drag_type = 'mannings'
config_zero_drying_velocity_ramp = .true.
config_zero_drying_velocity_ramp_hmin = 0.05
config_zero_drying_velocity_ramp_hmax = 0.10
Expand Down
11 changes: 10 additions & 1 deletion compass/ocean/tests/buttermilk_bay/namelist.init
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ config_use_wetting_drying = .true.
config_drying_min_cell_height = 0.05
config_write_cull_cell_mask = .false.
config_Buttermilk_bay_vert_levels = 1
config_Buttermilk_bay_topography_file = 'buttermilk_bathy.nc'
config_write_cull_cell_mask = .true.
config_use_tidal_forcing = .true.
config_use_variable_drag = .true.
config_subgrid_topography_file = 'buttermilk_bathy.nc'
config_use_subgrid_wetting_drying = .true.
config_subgrid_table_levels = -1
config_Buttermilk_bay_subgrid_table_levels = 100
config_subgrid_ssh_table_min = -3.0
config_subgrid_ssh_table_max = 3.0
config_subgrid_refinement_level = 10
config_subgrid_use_thin_layer = .false.
config_subgrid_edge_bathymetry_max_pixel = .true.
6 changes: 3 additions & 3 deletions compass/ocean/tests/buttermilk_bay/namelist.subgrid.init
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
config_use_subgrid_wetting_drying = .true.
config_subgrid_table_levels = -1
config_Buttermilk_bay_subgrid_table_levels = 100
config_Buttermilk_bay_subgrid_refinement_level = 10
config_Buttermilk_bay_subgrid_use_thin_layer = .false.
config_Buttermilk_bay_subgrid_edge_bathymetry_max_pixel = .true.
config_subgrid_refinement_level = 10
config_subgrid_use_thin_layer = .false.
config_subgrid_edge_bathymetry_max_pixel = .true.
8 changes: 8 additions & 0 deletions compass/ocean/tests/buttermilk_bay/streams.forward
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,12 @@
<var name="tidalInputMask"/>
</stream>

<stream name="bottomDrag"
type="input"
filename_template="init.nc"
input_interval="initial_only">

<var name="bottomDrag"/>
</stream>

</streams>
Loading
Loading