Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
bbbdf67
begin to add xarray capability and add new variables in coords
browniea Nov 18, 2025
bb27980
fix waterdepth name
browniea Nov 19, 2025
2e78821
calculate_grid_convergence_index
browniea Jan 28, 2026
a43446c
add test for calculate_grid_convergence_index
browniea Jan 28, 2026
0f5e015
black an pylint formating
browniea Jan 28, 2026
d2155a8
black and pulint formatting
browniea Jan 28, 2026
3d11517
add xarray input to error checks
browniea Jan 28, 2026
27800f7
update to develop branch
browniea Feb 2, 2026
fbb2434
added checkes to GCI function
browniea Feb 4, 2026
6209f68
added citation
browniea Feb 4, 2026
de92303
fixed typo
browniea Feb 4, 2026
8a15145
xarray testing still in progress
browniea Feb 4, 2026
f875e5f
update git_layer_function to take xarray
browniea Feb 9, 2026
6c5d9d8
updated convert_time to take xarray
browniea Feb 24, 2026
8229a7b
changed function to Second_to_index from convert_time
browniea Feb 24, 2026
861d9d1
updated get_layer_data for xarray
browniea Feb 24, 2026
82facb0
Merge branch 'develop' of https://github.com/MHKiT-Software/MHKiT-Pyt…
akeeste Feb 24, 2026
ed1273c
updated get_all_data for xarray
browniea Feb 24, 2026
e1b0d1a
finished adding xarray input analysis
browniea Feb 26, 2026
665f23c
consolodated get_layer_data depth interpolation
browniea Feb 26, 2026
f8a4483
updated test to test xarray input
browniea Feb 27, 2026
d669bc6
Merge remote-tracking branch 'upstream/develop' into D3D_updates
simmsa Apr 13, 2026
085ea85
Dev: Format with black
simmsa Apr 13, 2026
930c2bc
removed grid_convergence_test wrong branch
browniea Apr 14, 2026
ad928ec
skip pylint errors
browniea Apr 14, 2026
050ce85
black formatting
browniea Apr 14, 2026
fc5f3c6
add calculate_grid_convergence_index
browniea Apr 14, 2026
13cf7ff
black formating
browniea Apr 14, 2026
d4c8fe0
moved pylint: disable to many lines
browniea Apr 14, 2026
e48ee94
updated GCI checkes
browniea Apr 14, 2026
e1d0e0e
pylint too longs error
browniea Apr 14, 2026
6c38594
added in some functionality back in that got removed at some point
browniea Apr 14, 2026
4dc6613
added mesh2D cords name
browniea Apr 15, 2026
eba3109
black
browniea Apr 15, 2026
d4577a0
ignore pylint error
browniea Apr 16, 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
71 changes: 57 additions & 14 deletions mhkit/river/io/d3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ def get_all_time(data: netCDF4.Dataset) -> NDArray:
simulation conditions at that time.
"""

if not isinstance(data, netCDF4.Dataset):
raise TypeError("data must be a NetCDF4 object")
if not isinstance(data, (netCDF4.Dataset, xr.Dataset)):
raise TypeError("data must be a NetCDF4 object or xarray Dataset")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a test for xarray input


seconds_run = np.ma.getdata(data.variables["time"][:], False)

Expand Down Expand Up @@ -118,8 +118,8 @@ def _convert_time(
provided, returns the closest matching time_index.
"""

if not isinstance(data, netCDF4.Dataset):
raise TypeError("data must be NetCDF4 object")
if not isinstance(data, (netCDF4.Dataset, xr.Dataset)):
raise TypeError("data must be NetCDF4 object or xarray Dataset")

if not (time_index or seconds_run):
raise ValueError("Input of time_index or seconds_run needed")
Expand Down Expand Up @@ -199,8 +199,8 @@ def get_layer_data(
if not isinstance(layer_index, int):
raise TypeError("layer_index must be an int")

if not isinstance(data, netCDF4.Dataset):
raise TypeError("data must be NetCDF4 object")
if not isinstance(data, (netCDF4.Dataset, xr.Dataset)):
raise TypeError("data must be NetCDF4 object or xarray Dataset")

if variable not in data.variables.keys():
raise ValueError("variable not recognized")
Expand Down Expand Up @@ -244,6 +244,10 @@ def get_layer_data(
"name": "mesh2d_nLayers",
"coords": data.variables["mesh2d_layer_sigma"][:],
},
"mesh2d_face_x mesh2d_face_y mesh2d_layer_sigma": {
"name": "mesh2d_nLayers",
"coords": data.variables["mesh2d_layer_sigma"][:],
},
"mesh2d_edge_x mesh2d_edge_y": {
"name": "mesh2d_nInterfaces",
"coords": data.variables["mesh2d_interface_sigma"][:],
Expand All @@ -253,7 +257,7 @@ def get_layer_data(
data.variables["mesh2d_waterdepth"][time_index, :], False
)
waterlevel = np.ma.getdata(data.variables["mesh2d_s1"][time_index, :], False)
coords = str(data.variables["waterdepth"].coordinates).split()
coords = str(data.variables["mesh2d_waterdepth"].coordinates).split()
Comment thread
akeeste marked this conversation as resolved.
Outdated

elif str(data.variables[variable].coordinates) == "FlowElem_xcc FlowElem_ycc":
cords_to_layers = {
Expand Down Expand Up @@ -534,8 +538,10 @@ def variable_interpolation(
f"If a string, points must be cells or faces. Got {points}"
)

if not isinstance(data, netCDF4.Dataset):
raise TypeError(f"data must be netCDF4 object. Got {type(data)}")
if not isinstance(data, (netCDF4.Dataset, xr.Dataset)):
raise TypeError(
f"data must be netCDF4 object or xarray Dataset. Got {type(data)}"
)

if not isinstance(to_pandas, bool):
raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}")
Expand Down Expand Up @@ -616,8 +622,8 @@ def get_all_data_points(
if not isinstance(time_index, int):
raise TypeError("time_index must be an int")

if not isinstance(data, netCDF4.Dataset):
raise TypeError("data must be NetCDF4 object")
if not isinstance(data, (netCDF4.Dataset, xr.Dataset)):
raise TypeError("data must be NetCDF4 object or xarray Dataset")

if variable not in data.variables.keys():
raise ValueError("variable not recognized")
Expand All @@ -637,6 +643,10 @@ def get_all_data_points(
"name": "mesh2d_nLayers",
"coords": data.variables["mesh2d_layer_sigma"][:],
},
"mesh2d_face_x mesh2d_face_y mesh2d_layer_sigma": {
"name": "mesh2d_nLayers",
"coords": data.variables["mesh2d_layer_sigma"][:],
},
"mesh2d_edge_x mesh2d_edge_y": {
"name": "mesh2d_nInterfaces",
"coords": data.variables["mesh2d_interface_sigma"][:],
Expand Down Expand Up @@ -784,8 +794,8 @@ def turbulent_intensity(
f"value of the max time index {max_time_index}"
)

if not isinstance(data, netCDF4.Dataset):
raise TypeError("data must be netCDF4 object")
if not isinstance(data, (netCDF4.Dataset, xr.Dataset)):
raise TypeError("data must be netCDF4 object or xarray Dataset")

for variable in ["turkin1", "ucx", "ucy", "ucz"]:
if variable not in data.variables.keys():
Expand Down Expand Up @@ -878,11 +888,44 @@ def list_variables(data: Union[netCDF4.Dataset, xr.Dataset, xr.DataArray]) -> Li
>>> print(variables)
['time', 'x', 'y', 'waterdepth', 'ucx', 'ucy', 'ucz', 'turkin1']
"""
if isinstance(data, netCDF4.Dataset):
if isinstance(
data,
netCDF4.Dataset,
):
return list(data.variables.keys())
if isinstance(data, (xr.Dataset, xr.DataArray)):
return list(data.variables.keys())
raise TypeError(
"data must be a NetCDF4 Dataset, xarray Dataset, or "
f"xarray DataArray. Got: {type(data)}"
)


def calculate_grid_convergence_index(
fine_grid, coarse_grid, refinement_ratio, factor_of_safety=1.25, order=2
):
"""
Calculate the Grid Convergence Index (GCI) between two grid sizes. https://www.grc.nasa.gov/WWW/wind/valid/tutorial/spatconv.html

Comment thread
browniea marked this conversation as resolved.
Parameters
----------
fine_grid: numpy.ndarray
Results from the finer grid.
coarse_grid: numpy.ndarray
Results from the coarser grid.
refinement_ratio: float
Refinement ratio between the grids.
order: int
Order of accuracy (default is 2).

Returns
-------
gci: float
Grid Convergence Index (GCI).
"""
# Calculate the approximate relative error
Comment thread
akeeste marked this conversation as resolved.
error = np.abs((fine_grid - coarse_grid) / fine_grid)

# Calculate the GCI
gci = (factor_of_safety * error) / (refinement_ratio**order - 1)
return gci
9 changes: 9 additions & 0 deletions mhkit/tests/river/test_io_d3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,15 @@ def test_turbulent_intensity(self):
ucx_size = np.size(ucx["ucx"])
self.assertEqual(TI_size, ucx_size)

def test_calculate_grid_convergence_index(self):
fine_grid = np.array([1.0, 2.0, 3.0])
coarse_grid = np.array([0.5, 1.5, 2.5])
refinement_ratio = 2.0
gci = river.io.d3d.calculate_grid_convergence_index(
fine_grid, coarse_grid, refinement_ratio
)
assert_array_almost_equal(gci, np.array([0.2083, 0.1042, 0.0694]), decimal=3)

Comment on lines +374 to +382
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test is failing, but I'm pretty sure it's an issue with the install that #436 should address


if __name__ == "__main__":
unittest.main()
Loading