Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
f15a82b
Add devr45to5rr1 mesh
sbrus89 May 3, 2024
3a18601
Modifications for subgrid in hurricane case
sbrus89 Oct 31, 2024
5341349
Turn on SAL and TWD in forward namelist
sbrus89 Dec 3, 2024
abf2b39
Copy bed_elevation to bottomDepthObserved in init step
sbrus89 Dec 3, 2024
fb68372
Prevent infinite loop in calculate_wave_drag.py when fixing Nan values
sbrus89 Dec 3, 2024
b2bccbc
Add calculate wave drag and remap bathymetry steps to hurricane init
sbrus89 Dec 3, 2024
e11202a
Add 15sec resolution option to pixel file step
sbrus89 Dec 3, 2024
6638d9b
Create pixel file for all meshes
sbrus89 Dec 3, 2024
8e73595
Use dem_remap instead of inject_bathymetry in floodplain mesh
sbrus89 Dec 3, 2024
993ee9f
Use modified box for specifying Delaware resolution
sbrus89 Jan 8, 2025
417bc88
Cull mesh using remapped topography for ice shelves, region mask for …
sbrus89 Jan 8, 2025
509ecd7
Update remap_bathymetry
sbrus89 Jan 8, 2025
2ce5753
Add topotgraphic wave drag file to forward step and streams
sbrus89 Jan 8, 2025
c57a6d5
Add ice shelf cavity information in initial state
sbrus89 Jan 8, 2025
d17e1ee
Set start date for analysis plots back to being closer to landfall (1…
sbrus89 Jan 8, 2025
b3740c1
Remove do_inject_bathymetry option
sbrus89 Jan 8, 2025
cfa86b4
Ignore Northern hemisphere land ice masks
sbrus89 Jan 13, 2025
64d62f5
Add back SRTM as input file
sbrus89 Jan 14, 2025
02b63b1
Fix initial_stat for standard wetting and drying
sbrus89 Mar 28, 2025
9ac6342
Add code for barrier island identification
sbrus89 Apr 1, 2025
d071310
Update remap_topography config
sbrus89 Apr 3, 2025
7d0553b
Update hurricane analysis step
sbrus89 May 9, 2025
991f961
Update initial state for NCEI dem data
sbrus89 Jul 8, 2025
0777e23
Create load-balanced graph files for subgrid init
sbrus89 Jul 18, 2025
25b60d4
Insert ice shelf cavity information into last subgrid init file
sbrus89 Jul 21, 2025
d2d94ee
Increase number of tasks for init
sbrus89 Jul 21, 2025
b0395c8
Increase subgrid refinement level
sbrus89 Jul 21, 2025
b3ba349
Update DEM file names
sbrus89 Jul 21, 2025
562b2c3
Add streams template
sbrus89 Jul 21, 2025
de30f69
Replace dem file name in initial namelist
sbrus89 Jul 21, 2025
918af4f
Remove old namelist and streams files
sbrus89 Aug 20, 2025
b1a8081
Add step to interpolate mannings n
sbrus89 Aug 22, 2025
4587a71
Add Chesapeake DEMS
sbrus89 Aug 22, 2025
20a663f
Use pnetcdf,cdf5 as io type for streams
sbrus89 Aug 22, 2025
7c8198d
Enable increased levels for subgrid tables
sbrus89 Aug 22, 2025
1df06d3
Enable variable mannings n in forward run
sbrus89 Aug 28, 2025
0122ac5
Fix bug in initial state for final subgrid file
sbrus89 Aug 28, 2025
2e77044
Increase subgrid dt to 10s and turn off del4
sbrus89 Aug 28, 2025
d395ca2
Add updates for subgrid drag
sbrus89 Sep 12, 2025
8b9e39b
Extend adjustment period for observations
sbrus89 Sep 16, 2025
edfcfc4
Add option to plot DEM and LULC around stations
sbrus89 Sep 25, 2025
f510b49
Fix rebase issues from cull step topography smoothing option
sbrus89 Sep 25, 2025
7999355
Clean up parabolic bowl test case
sbrus89 Oct 21, 2025
0be480d
Clean up buttermilk bay test case
sbrus89 Oct 21, 2025
369cbca
Improve DEM plotting around stations
sbrus89 Oct 21, 2025
188329b
Remove highest resolution Delware Bay refinement
sbrus89 Oct 21, 2025
1147826
Add clipping limits to subgrid hurricane init namelist
sbrus89 Oct 21, 2025
deec975
Format decimal seconds for dt in buttermilk bay case
sbrus89 Feb 16, 2026
30222ef
Enable mannings n subgrid friction in buttermilk bay case
sbrus89 Feb 16, 2026
30c6057
Update buttermilk bay analysis points
sbrus89 Feb 16, 2026
cc01e98
Update subgrid refinement level based on resolution in buttermilk bay…
sbrus89 Feb 16, 2026
869dc78
Update buttermilk bay viz
sbrus89 Feb 16, 2026
548b9ba
Update parabolic bowl viz step
sbrus89 Feb 16, 2026
f940176
Add comment to cull.py about floodplains
sbrus89 Feb 16, 2026
78b87dd
Increase floodplain elevation to 40m for devr45to5rr1 mesh
sbrus89 Feb 17, 2026
d3538b5
Add floodplain region capability
sbrus89 Feb 17, 2026
401e83c
Add RRS6to18 mesh
sbrus89 Feb 17, 2026
02b3b33
Update hurricane analysis
sbrus89 Feb 17, 2026
2066357
Add error and plot_subgrid scripts for buttermilk bay case
sbrus89 Feb 17, 2026
854328d
Only load balance graph for subgrid
sbrus89 May 28, 2026
b813562
Compass v2.0.0 compatibility changes to hurricane
bmooremaley Jun 23, 2026
f5965aa
Namelist changes to hurricane/forward to account for E3SM/master changes
bmooremaley Jul 20, 2026
f64ef5a
Updated user docs for ocean/hurricane test group
bmooremaley Jul 22, 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