Skip to content

Commit c2400fd

Browse files
authored
Make NetCDFWriter work with PartialCellBottom grids (#4462)
* add method for partialCellBottom * add tests * bump patch version
1 parent 3c9afd4 commit c2400fd

File tree

3 files changed

+68
-64
lines changed

3 files changed

+68
-64
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "Oceananigans"
22
uuid = "9e8cae18-63c1-5223-a75c-80ca9d6e9a09"
33
authors = ["Climate Modeling Alliance and contributors"]
4-
version = "0.96.22"
4+
version = "0.96.23"
55

66
[deps]
77
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"

ext/OceananigansNCDatasetsExt.jl

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ using Oceananigans.Grids: topology, halo_size, xspacings, yspacings, zspacings,
1414
using Oceananigans.Fields: reduced_dimensions, reduced_location, location
1515
using Oceananigans.AbstractOperations: KernelFunctionOperation
1616
using Oceananigans.Models: ShallowWaterModel, LagrangianParticles
17-
using Oceananigans.ImmersedBoundaries: ImmersedBoundaryGrid, GridFittedBottom, GFBIBG, GridFittedBoundary
17+
using Oceananigans.ImmersedBoundaries: ImmersedBoundaryGrid, GridFittedBottom, GFBIBG, GridFittedBoundary, PartialCellBottom, PCBIBG
1818
using Oceananigans.TimeSteppers: float_or_date_time
1919
using Oceananigans.BuoyancyFormulations: BuoyancyForce, BuoyancyTracer, SeawaterBuoyancy, LinearEquationOfState
2020
using Oceananigans.Utils: TimeInterval, IterationInterval, WallTimeInterval
@@ -360,34 +360,36 @@ gather_grid_metrics(grid::ImmersedBoundaryGrid, args...) =
360360
# TODO: Proper masks for 2D models?
361361
flat_loc(T, L) = T == Flat ? nothing : L
362362

363-
# For Immersed Boundary Grids (IBG) with a Grid Fitted Bottom (GFB)
364-
function gather_immersed_boundary(grid::GFBIBG, indices, dim_name_generator)
365-
op_mask_ccc = KernelFunctionOperation{Center, Center, Center}(peripheral_node, grid, Center(), Center(), Center())
366-
op_mask_fcc = KernelFunctionOperation{Face, Center, Center}(peripheral_node, grid, Face(), Center(), Center())
367-
op_mask_cfc = KernelFunctionOperation{Center, Face, Center}(peripheral_node, grid, Center(), Face(), Center())
368-
op_mask_ccf = KernelFunctionOperation{Center, Center, Face}(peripheral_node, grid, Center(), Center(), Face())
363+
const PCBorGFBIBG = Union{GFBIBG, PCBIBG}
364+
365+
# For Immersed Boundary Grids (IBG) with either a Grid Fitted Bottom (GFB) or a Partial Cell Bottom (PCB)
366+
function gather_immersed_boundary(grid::PCBorGFBIBG, indices, dim_name_generator)
367+
op_peripheral_nodes_ccc = KernelFunctionOperation{Center, Center, Center}(peripheral_node, grid, Center(), Center(), Center())
368+
op_peripheral_nodes_fcc = KernelFunctionOperation{Face, Center, Center}(peripheral_node, grid, Face(), Center(), Center())
369+
op_peripheral_nodes_cfc = KernelFunctionOperation{Center, Face, Center}(peripheral_node, grid, Center(), Face(), Center())
370+
op_peripheral_nodes_ccf = KernelFunctionOperation{Center, Center, Face}(peripheral_node, grid, Center(), Center(), Face())
369371

370372
return Dict("bottom_height" => Field(grid.immersed_boundary.bottom_height; indices),
371-
"immersed_boundary_mask_ccc" => Field(op_mask_ccc; indices),
372-
"immersed_boundary_mask_fcc" => Field(op_mask_fcc; indices),
373-
"immersed_boundary_mask_cfc" => Field(op_mask_cfc; indices),
374-
"immersed_boundary_mask_ccf" => Field(op_mask_ccf; indices))
373+
"peripheral_nodes_ccc" => Field(op_peripheral_nodes_ccc; indices),
374+
"peripheral_nodes_fcc" => Field(op_peripheral_nodes_fcc; indices),
375+
"peripheral_nodes_cfc" => Field(op_peripheral_nodes_cfc; indices),
376+
"peripheral_nodes_ccf" => Field(op_peripheral_nodes_ccf; indices))
375377
end
376378

377379
const GFBoundaryIBG = ImmersedBoundaryGrid{<:Any, <:Any, <:Any, <:Any, <:Any, <:GridFittedBoundary}
378380

379381
# For Immersed Boundary Grids (IBG) with a Grid Fitted Boundary (also GFB!)
380382
function gather_immersed_boundary(grid::GFBoundaryIBG, indices, dim_name_generator)
381-
op_mask_ccc = KernelFunctionOperation{Center, Center, Center}(peripheral_node, grid, Center(), Center(), Center())
382-
op_mask_fcc = KernelFunctionOperation{Face, Center, Center}(peripheral_node, grid, Face(), Center(), Center())
383-
op_mask_cfc = KernelFunctionOperation{Center, Face, Center}(peripheral_node, grid, Center(), Face(), Center())
384-
op_mask_ccf = KernelFunctionOperation{Center, Center, Face}(peripheral_node, grid, Center(), Center(), Face())
385-
386-
return Dict("immersed_boundary_mask" => Field(grid.immersed_boundary.mask; indices),
387-
"immersed_boundary_mask_ccc" => Field(op_mask_ccc; indices),
388-
"immersed_boundary_mask_fcc" => Field(op_mask_fcc; indices),
389-
"immersed_boundary_mask_cfc" => Field(op_mask_cfc; indices),
390-
"immersed_boundary_mask_ccf" => Field(op_mask_ccf; indices))
383+
op_peripheral_nodes_ccc = KernelFunctionOperation{Center, Center, Center}(peripheral_node, grid, Center(), Center(), Center())
384+
op_peripheral_nodes_fcc = KernelFunctionOperation{Face, Center, Center}(peripheral_node, grid, Face(), Center(), Center())
385+
op_peripheral_nodes_cfc = KernelFunctionOperation{Center, Face, Center}(peripheral_node, grid, Center(), Face(), Center())
386+
op_peripheral_nodes_ccf = KernelFunctionOperation{Center, Center, Face}(peripheral_node, grid, Center(), Center(), Face())
387+
388+
return Dict("peripheral_nodes" => Field(grid.immersed_boundary.mask; indices),
389+
"peripheral_nodes_ccc" => Field(op_peripheral_nodes_ccc; indices),
390+
"peripheral_nodes_fcc" => Field(op_peripheral_nodes_fcc; indices),
391+
"peripheral_nodes_cfc" => Field(op_peripheral_nodes_cfc; indices),
392+
"peripheral_nodes_ccf" => Field(op_peripheral_nodes_ccf; indices))
391393
end
392394

393395
#####

test/test_netcdf_writer.jl

Lines changed: 44 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ function test_netcdf_grid_metrics_latlon(arch, FT)
584584
return nothing
585585
end
586586

587-
function test_netcdf_rectilinear_grid_fitted_bottom(arch)
587+
function test_netcdf_rectilinear_grid_fitted_bottom(arch, bottom_boundary_type)
588588
Nx, Ny, Nz = 16, 16, 16
589589
Hx, Hy, Hz = 2, 3, 4
590590

@@ -603,7 +603,7 @@ function test_netcdf_rectilinear_grid_fitted_bottom(arch)
603603
mount(x, y) = height * exp(-x^2 / 2width^2) * exp(-y^2 / 2width^2)
604604
bottom(x, y) = -H + mount(x, y)
605605

606-
grid = ImmersedBoundaryGrid(underlying_grid, GridFittedBottom(bottom))
606+
grid = ImmersedBoundaryGrid(underlying_grid, bottom_boundary_type(bottom))
607607

608608
model = NonhydrostaticModel(; grid,
609609
closure = ScalarDiffusivity=4e-2, κ=4e-2),
@@ -666,14 +666,14 @@ function test_netcdf_rectilinear_grid_fitted_bottom(arch)
666666
@test dimsize(ds_h[:bottom_height]) == (x_caa=Nx + 2Hx, y_aca=Ny + 2Hy)
667667

668668
for loc in ("ccc", "fcc", "cfc", "ccf")
669-
@test haskey(ds_h, "immersed_boundary_mask_$loc")
670-
@test eltype(ds_h["immersed_boundary_mask_$loc"]) == Float64
669+
@test haskey(ds_h, "peripheral_nodes_$loc")
670+
@test eltype(ds_h["peripheral_nodes_$loc"]) == Float64
671671
end
672672

673-
@test dimsize(ds_h[:immersed_boundary_mask_ccc]) == (x_caa=Nx + 2Hx, y_aca=Ny + 2Hy, z_aac=Nz + 2Hz)
674-
@test dimsize(ds_h[:immersed_boundary_mask_fcc]) == (x_faa=Nx + 2Hx + 1, y_aca=Ny + 2Hy, z_aac=Nz + 2Hz)
675-
@test dimsize(ds_h[:immersed_boundary_mask_cfc]) == (x_caa=Nx + 2Hx, y_afa=Ny + 2Hy + 1, z_aac=Nz + 2Hz)
676-
@test dimsize(ds_h[:immersed_boundary_mask_ccf]) == (x_caa=Nx + 2Hx, y_aca=Ny + 2Hy, z_aaf=Nz + 2Hz + 1)
673+
@test dimsize(ds_h[:peripheral_nodes_ccc]) == (x_caa=Nx + 2Hx, y_aca=Ny + 2Hy, z_aac=Nz + 2Hz)
674+
@test dimsize(ds_h[:peripheral_nodes_fcc]) == (x_faa=Nx + 2Hx + 1, y_aca=Ny + 2Hy, z_aac=Nz + 2Hz)
675+
@test dimsize(ds_h[:peripheral_nodes_cfc]) == (x_caa=Nx + 2Hx, y_afa=Ny + 2Hy + 1, z_aac=Nz + 2Hz)
676+
@test dimsize(ds_h[:peripheral_nodes_ccf]) == (x_caa=Nx + 2Hx, y_aca=Ny + 2Hy, z_aaf=Nz + 2Hz + 1)
677677

678678
@test all(ds_h[:bottom_height][:, :] .≈ Array(parent(grid.immersed_boundary.bottom_height)))
679679

@@ -688,14 +688,14 @@ function test_netcdf_rectilinear_grid_fitted_bottom(arch)
688688
@test dimsize(ds_n[:bottom_height]) == (x_caa=Nx, y_aca=Ny)
689689

690690
for loc in ("ccc", "fcc", "cfc", "ccf")
691-
@test haskey(ds_n, "immersed_boundary_mask_$loc")
692-
@test eltype(ds_n["immersed_boundary_mask_$loc"]) == Float32
691+
@test haskey(ds_n, "peripheral_nodes_$loc")
692+
@test eltype(ds_n["peripheral_nodes_$loc"]) == Float32
693693
end
694694

695-
@test dimsize(ds_n[:immersed_boundary_mask_ccc]) == (x_caa=Nx, y_aca=Ny, z_aac=Nz)
696-
@test dimsize(ds_n[:immersed_boundary_mask_fcc]) == (x_faa=Nx + 1, y_aca=Ny, z_aac=Nz)
697-
@test dimsize(ds_n[:immersed_boundary_mask_cfc]) == (x_caa=Nx, y_afa=Ny + 1, z_aac=Nz)
698-
@test dimsize(ds_n[:immersed_boundary_mask_ccf]) == (x_caa=Nx, y_aca=Ny, z_aaf=Nz + 1)
695+
@test dimsize(ds_n[:peripheral_nodes_ccc]) == (x_caa=Nx, y_aca=Ny, z_aac=Nz)
696+
@test dimsize(ds_n[:peripheral_nodes_fcc]) == (x_faa=Nx + 1, y_aca=Ny, z_aac=Nz)
697+
@test dimsize(ds_n[:peripheral_nodes_cfc]) == (x_caa=Nx, y_afa=Ny + 1, z_aac=Nz)
698+
@test dimsize(ds_n[:peripheral_nodes_ccf]) == (x_caa=Nx, y_aca=Ny, z_aaf=Nz + 1)
699699

700700
@test all(ds_n[:bottom_height][:, :] .≈ Array(interior(grid.immersed_boundary.bottom_height)))
701701

@@ -710,14 +710,14 @@ function test_netcdf_rectilinear_grid_fitted_bottom(arch)
710710
@test dimsize(ds_s[:bottom_height]) == (x_caa=nx, y_aca=ny)
711711

712712
for loc in ("ccc", "fcc", "cfc", "ccf")
713-
@test haskey(ds_s, "immersed_boundary_mask_$loc")
714-
@test eltype(ds_s["immersed_boundary_mask_$loc"]) == Float32
713+
@test haskey(ds_s, "peripheral_nodes_$loc")
714+
@test eltype(ds_s["peripheral_nodes_$loc"]) == Float32
715715
end
716716

717-
@test dimsize(ds_s[:immersed_boundary_mask_ccc]) == (x_caa=nx, y_aca=ny, z_aac=nz)
718-
@test dimsize(ds_s[:immersed_boundary_mask_fcc]) == (x_faa=nx, y_aca=ny, z_aac=nz)
719-
@test dimsize(ds_s[:immersed_boundary_mask_cfc]) == (x_caa=nx, y_afa=ny, z_aac=nz)
720-
@test dimsize(ds_s[:immersed_boundary_mask_ccf]) == (x_caa=nx, y_aca=ny, z_aaf=nz)
717+
@test dimsize(ds_s[:peripheral_nodes_ccc]) == (x_caa=nx, y_aca=ny, z_aac=nz)
718+
@test dimsize(ds_s[:peripheral_nodes_fcc]) == (x_faa=nx, y_aca=ny, z_aac=nz)
719+
@test dimsize(ds_s[:peripheral_nodes_cfc]) == (x_caa=nx, y_afa=ny, z_aac=nz)
720+
@test dimsize(ds_s[:peripheral_nodes_ccf]) == (x_caa=nx, y_aca=ny, z_aaf=nz)
721721

722722
@test all(ds_s[:bottom_height][:, :] .≈ Array(interior(grid.immersed_boundary.bottom_height, i_slice, j_slice)))
723723

@@ -727,7 +727,7 @@ function test_netcdf_rectilinear_grid_fitted_bottom(arch)
727727
return nothing
728728
end
729729

730-
function test_netcdf_latlon_grid_fitted_bottom(arch)
730+
function test_netcdf_latlon_grid_fitted_bottom(arch, bottom_boundary_type)
731731
Nλ, Nφ, Nz = 16, 16, 16
732732
Hλ, Hφ, Hz = 2, 3, 4
733733
Lλ, Lφ, H = 20, 10, 1000
@@ -747,7 +747,7 @@ function test_netcdf_latlon_grid_fitted_bottom(arch)
747747
seamount(λ, φ) = height * exp(-λ^2 / 2λ_width^2) * exp(-φ^2 / 2φ_width^2)
748748
bottom(λ, φ) = -H + seamount(λ, φ)
749749

750-
grid = ImmersedBoundaryGrid(underlying_grid, GridFittedBottom(bottom))
750+
grid = ImmersedBoundaryGrid(underlying_grid, bottom_boundary_type(bottom))
751751

752752
model = HydrostaticFreeSurfaceModel(; grid,
753753
momentum_advection = VectorInvariant(),
@@ -815,14 +815,14 @@ function test_netcdf_latlon_grid_fitted_bottom(arch)
815815
@test dimsize(ds_h[:bottom_height]) == (λ_caa=+ 2Hλ, φ_aca=+ 2Hφ)
816816

817817
for loc in ("ccc", "fcc", "cfc", "ccf")
818-
@test haskey(ds_h, "immersed_boundary_mask_$loc")
819-
@test eltype(ds_h["immersed_boundary_mask_$loc"]) == Float64
818+
@test haskey(ds_h, "peripheral_nodes_$loc")
819+
@test eltype(ds_h["peripheral_nodes_$loc"]) == Float64
820820
end
821821

822-
@test dimsize(ds_h[:immersed_boundary_mask_ccc]) == (λ_caa=+ 2Hλ, φ_aca=+ 2Hφ, z_aac=Nz + 2Hz)
823-
@test dimsize(ds_h[:immersed_boundary_mask_fcc]) == (λ_faa=+ 2+ 1, φ_aca=+ 2Hφ, z_aac=Nz + 2Hz)
824-
@test dimsize(ds_h[:immersed_boundary_mask_cfc]) == (λ_caa=+ 2Hλ, φ_afa=+ 2+ 1, z_aac=Nz + 2Hz)
825-
@test dimsize(ds_h[:immersed_boundary_mask_ccf]) == (λ_caa=+ 2Hλ, φ_aca=+ 2Hφ, z_aaf=Nz + 2Hz + 1)
822+
@test dimsize(ds_h[:peripheral_nodes_ccc]) == (λ_caa=+ 2Hλ, φ_aca=+ 2Hφ, z_aac=Nz + 2Hz)
823+
@test dimsize(ds_h[:peripheral_nodes_fcc]) == (λ_faa=+ 2+ 1, φ_aca=+ 2Hφ, z_aac=Nz + 2Hz)
824+
@test dimsize(ds_h[:peripheral_nodes_cfc]) == (λ_caa=+ 2Hλ, φ_afa=+ 2+ 1, z_aac=Nz + 2Hz)
825+
@test dimsize(ds_h[:peripheral_nodes_ccf]) == (λ_caa=+ 2Hλ, φ_aca=+ 2Hφ, z_aaf=Nz + 2Hz + 1)
826826

827827
@test all(ds_h[:bottom_height][:, :] .≈ Array(parent(grid.immersed_boundary.bottom_height)))
828828

@@ -837,14 +837,14 @@ function test_netcdf_latlon_grid_fitted_bottom(arch)
837837
@test dimsize(ds_n[:bottom_height]) == (λ_caa=Nλ, φ_aca=Nφ)
838838

839839
for loc in ("ccc", "fcc", "cfc", "ccf")
840-
@test haskey(ds_n, "immersed_boundary_mask_$loc")
841-
@test eltype(ds_n["immersed_boundary_mask_$loc"]) == Float32
840+
@test haskey(ds_n, "peripheral_nodes_$loc")
841+
@test eltype(ds_n["peripheral_nodes_$loc"]) == Float32
842842
end
843843

844-
@test dimsize(ds_n[:immersed_boundary_mask_ccc]) == (λ_caa=Nλ, φ_aca=Nφ, z_aac=Nz)
845-
@test dimsize(ds_n[:immersed_boundary_mask_fcc]) == (λ_faa=+ 1, φ_aca=Nφ, z_aac=Nz)
846-
@test dimsize(ds_n[:immersed_boundary_mask_cfc]) == (λ_caa=Nλ, φ_afa=+ 1, z_aac=Nz)
847-
@test dimsize(ds_n[:immersed_boundary_mask_ccf]) == (λ_caa=Nλ, φ_aca=Nφ, z_aaf=Nz + 1)
844+
@test dimsize(ds_n[:peripheral_nodes_ccc]) == (λ_caa=Nλ, φ_aca=Nφ, z_aac=Nz)
845+
@test dimsize(ds_n[:peripheral_nodes_fcc]) == (λ_faa=+ 1, φ_aca=Nφ, z_aac=Nz)
846+
@test dimsize(ds_n[:peripheral_nodes_cfc]) == (λ_caa=Nλ, φ_afa=+ 1, z_aac=Nz)
847+
@test dimsize(ds_n[:peripheral_nodes_ccf]) == (λ_caa=Nλ, φ_aca=Nφ, z_aaf=Nz + 1)
848848

849849
@test all(ds_n[:bottom_height][:, :] .≈ Array(interior(grid.immersed_boundary.bottom_height)))
850850

@@ -859,14 +859,14 @@ function test_netcdf_latlon_grid_fitted_bottom(arch)
859859
@test dimsize(ds_s[:bottom_height]) == (λ_caa=nλ, φ_aca=nφ)
860860

861861
for loc in ("ccc", "fcc", "cfc", "ccf")
862-
@test haskey(ds_s, "immersed_boundary_mask_$loc")
863-
@test eltype(ds_s["immersed_boundary_mask_$loc"]) == Float32
862+
@test haskey(ds_s, "peripheral_nodes_$loc")
863+
@test eltype(ds_s["peripheral_nodes_$loc"]) == Float32
864864
end
865865

866-
@test dimsize(ds_s[:immersed_boundary_mask_ccc]) == (λ_caa=nλ, φ_aca=nφ, z_aac=nz)
867-
@test dimsize(ds_s[:immersed_boundary_mask_fcc]) == (λ_faa=nλ, φ_aca=nφ, z_aac=nz)
868-
@test dimsize(ds_s[:immersed_boundary_mask_cfc]) == (λ_caa=nλ, φ_afa=nφ, z_aac=nz)
869-
@test dimsize(ds_s[:immersed_boundary_mask_ccf]) == (λ_caa=nλ, φ_aca=nφ, z_aaf=nz)
866+
@test dimsize(ds_s[:peripheral_nodes_ccc]) == (λ_caa=nλ, φ_aca=nφ, z_aac=nz)
867+
@test dimsize(ds_s[:peripheral_nodes_fcc]) == (λ_faa=nλ, φ_aca=nφ, z_aac=nz)
868+
@test dimsize(ds_s[:peripheral_nodes_cfc]) == (λ_caa=nλ, φ_afa=nφ, z_aac=nz)
869+
@test dimsize(ds_s[:peripheral_nodes_ccf]) == (λ_caa=nλ, φ_aca=nφ, z_aaf=nz)
870870

871871
@test all(ds_s[:bottom_height][:, :] .≈ Array(interior(grid.immersed_boundary.bottom_height, i_slice, j_slice)))
872872

@@ -2738,8 +2738,10 @@ for arch in archs
27382738
test_netcdf_grid_metrics_latlon(arch, Float64)
27392739
test_netcdf_grid_metrics_latlon(arch, Float32)
27402740

2741-
test_netcdf_rectilinear_grid_fitted_bottom(arch)
2742-
test_netcdf_latlon_grid_fitted_bottom(arch)
2741+
test_netcdf_rectilinear_grid_fitted_bottom(arch, GridFittedBottom)
2742+
test_netcdf_rectilinear_grid_fitted_bottom(arch, PartialCellBottom)
2743+
test_netcdf_latlon_grid_fitted_bottom(arch, GridFittedBottom)
2744+
test_netcdf_latlon_grid_fitted_bottom(arch, PartialCellBottom)
27432745

27442746
test_netcdf_rectilinear_flat_xy(arch)
27452747
test_netcdf_rectilinear_flat_xz(arch, immersed=false)

0 commit comments

Comments
 (0)