Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Immersed map from Adapting the ImmersedBoundaryGrid #3690

Merged
merged 38 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
58bd4da
add new branch
simone-silvestri Aug 7, 2024
d970dc6
add some comments
simone-silvestri Aug 7, 2024
5632474
add comments
simone-silvestri Aug 7, 2024
93f579a
adapt non hydrostatic model
simone-silvestri Aug 7, 2024
1f31ce4
add inbounds where needed
simone-silvestri Aug 7, 2024
edbc06d
adapt barotropic kernel
simone-silvestri Aug 7, 2024
cacb022
last bugfix?
simone-silvestri Aug 7, 2024
512c0c1
Merge branch 'main' into ss/remove-immersed-map-from-adapt
simone-silvestri Aug 7, 2024
b6d65f3
add some explanation and name changes
simone-silvestri Aug 7, 2024
cfe4618
Merge branch 'ss/remove-immersed-map-from-adapt' of github.com:CliMA/…
simone-silvestri Aug 7, 2024
c407fdb
adding some explanation
simone-silvestri Aug 7, 2024
f0153ee
typo
simone-silvestri Aug 7, 2024
3cc5f12
better naming
simone-silvestri Aug 7, 2024
7b04eb0
better comment
simone-silvestri Aug 7, 2024
21bd603
add comments
simone-silvestri Aug 7, 2024
827080b
add comments
simone-silvestri Aug 7, 2024
7ada6d3
add another explanation
simone-silvestri Aug 7, 2024
9974ac4
change names
simone-silvestri Aug 7, 2024
7a5ac3a
some more explanation
simone-silvestri Aug 7, 2024
dca93d2
add some more explanation
simone-silvestri Aug 7, 2024
28870a6
better naming
simone-silvestri Aug 7, 2024
694ac10
more description
simone-silvestri Aug 7, 2024
be3d3f5
Merge branch 'main' into ss/remove-immersed-map-from-adapt
simone-silvestri Aug 7, 2024
e04eee8
change some naming
simone-silvestri Aug 7, 2024
43e9f96
Merge branch 'ss/remove-immersed-map-from-adapt' of github.com:CliMA/…
simone-silvestri Aug 7, 2024
428610d
typo
simone-silvestri Aug 7, 2024
f9a8200
bugfix
simone-silvestri Aug 7, 2024
d012f05
Update src/ImmersedBoundaries/active_cells_map.jl
simone-silvestri Aug 8, 2024
f7bce0f
Update src/ImmersedBoundaries/active_cells_map.jl
simone-silvestri Aug 8, 2024
79d8c5d
Merge branch 'main' into ss/remove-immersed-map-from-adapt
simone-silvestri Aug 8, 2024
0cd0e9c
Merge branch 'main' into ss/remove-immersed-map-from-adapt
simone-silvestri Aug 12, 2024
e1f2dc5
make sure synchronized architectures do not split the active map
simone-silvestri Aug 14, 2024
2795489
Merge branch 'main' into ss/remove-immersed-map-from-adapt
simone-silvestri Sep 4, 2024
1d481e5
Merge branch 'main' into ss/remove-immersed-map-from-adapt
simone-silvestri Sep 16, 2024
260e554
adding some immersed map tests
simone-silvestri Sep 16, 2024
4bce1fb
no active cells map for grid fitted boundary?
simone-silvestri Sep 16, 2024
68ccbda
active cells map for gridfitted boundary
simone-silvestri Sep 16, 2024
0d3fe7a
revert to previous implementation
simone-silvestri Sep 17, 2024
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
6 changes: 4 additions & 2 deletions src/Grids/Grids.jl
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,10 @@ const YZFlatGrid = AbstractGrid{<:Any, <:Any, Flat, Flat}
const XYZFlatGrid = AbstractGrid{<:Any, Flat, Flat, Flat}

isrectilinear(grid) = false
@inline active_surface_map(::AbstractGrid) = nothing
@inline active_interior_map(::AbstractGrid) = nothing

# Fallback
@inline retrieve_surface_active_cells_map(::AbstractGrid) = nothing
@inline retrieve_interior_active_cells_map(::AbstractGrid, any_map_type) = nothing

include("grid_utils.jl")
include("nodes_and_spacings.jl")
Expand Down
6 changes: 3 additions & 3 deletions src/ImmersedBoundaries/ImmersedBoundaries.jl
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ const IBG = ImmersedBoundaryGrid
@inline get_ibg_property(ibg::IBG, ::Val{:immersed_boundary}) = getfield(ibg, :immersed_boundary)
@inline get_ibg_property(ibg::IBG, ::Val{:underlying_grid}) = getfield(ibg, :underlying_grid)
@inline get_ibg_property(ibg::IBG, ::Val{:interior_active_cells}) = getfield(ibg, :interior_active_cells)
@inline get_ibg_property(ibg::IBG, ::Val{:active_z_columns}) = getfield(ibg, :active_z_columns)
@inline get_ibg_property(ibg::IBG, ::Val{:active_z_columns}) = getfield(ibg, :active_z_columns)

@inline architecture(ibg::IBG) = architecture(ibg.underlying_grid)

Expand All @@ -146,8 +146,8 @@ const IBG = ImmersedBoundaryGrid
Adapt.adapt_structure(to, ibg::IBG{FT, TX, TY, TZ}) where {FT, TX, TY, TZ} =
ImmersedBoundaryGrid{TX, TY, TZ}(adapt(to, ibg.underlying_grid),
adapt(to, ibg.immersed_boundary),
adapt(to, ibg.interior_active_cells),
adapt(to, ibg.active_z_columns))
nothing,
nothing)

with_halo(halo, ibg::ImmersedBoundaryGrid) =
ImmersedBoundaryGrid(with_halo(halo, ibg.underlying_grid), ibg.immersed_boundary)
Expand Down
128 changes: 72 additions & 56 deletions src/ImmersedBoundaries/active_cells_map.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,48 @@ using Oceananigans.Grids: AbstractGrid

using KernelAbstractions: @kernel, @index

import Oceananigans.Grids: active_surface_map, active_interior_map
import Oceananigans.Grids: retrieve_surface_active_cells_map, retrieve_interior_active_cells_map
import Oceananigans.Utils: active_cells_work_layout

using Oceananigans.Solvers: solve_batched_tridiagonal_system_z!, ZDirection
using Oceananigans.DistributedComputations: DistributedGrid

import Oceananigans.Solvers: solve_batched_tridiagonal_system_kernel!

const DistributedActiveCellsIBG = ImmersedBoundaryGrid{<:Any, <:Any, <:Any, <:Any, <:DistributedGrid, <:Any, <:NamedTuple} # Cannot be used to dispatch in kernels!!!
const ArrayActiveCellsIBG = ImmersedBoundaryGrid{<:Any, <:Any, <:Any, <:Any, <:Any, <:Any, <:AbstractArray}
const NamedTupleActiveCellsIBG = ImmersedBoundaryGrid{<:Any, <:Any, <:Any, <:Any, <:Any, <:Any, <:NamedTuple}
# REMEMBER: since the active map is stripped out of the grid when `Adapt`ing to the GPU,
# The following types cannot be used to dispatch in kernels!!!

# An IBG with a single interior active cells map that includes the whole :xyz domain
const WholeActiveCellsMapIBG = ImmersedBoundaryGrid{<:Any, <:Any, <:Any, <:Any, <:Any, <:Any, <:AbstractArray}

# An IBG with an interior active cells map subdivided in 5 different sub-maps.
# Only used (for the moment) in the case of distributed architectures where the boundary adjacent region
# has to be computed separately, these maps hold the active region in the "halo-independent" part of the domain
# (; halo_independent_cells), and the "halo-dependent" regions in the west, east, north, and south, respectively
const SplitActiveCellsMapIBG = ImmersedBoundaryGrid{<:Any, <:Any, <:Any, <:Any, <:Any, <:Any, <:NamedTuple}

# A distributed grid with split interior map
const DistributedActiveCellsIBG = ImmersedBoundaryGrid{<:Any, <:Any, <:Any, <:Any, <:DistributedGrid, <:Any, <:NamedTuple}

"""
A constant representing an immersed boundary grid, where interior active cells are mapped to linear indices in grid.interior_active_cells
"""
const ActiveCellsIBG = Union{DistributedActiveCellsIBG, ArrayActiveCellsIBG, NamedTupleActiveCellsIBG}
const ActiveCellsIBG = Union{DistributedActiveCellsIBG, WholeActiveCellsMapIBG, SplitActiveCellsMapIBG}

"""
A constant representing an immersed boundary grid, where active columns in the Z-direction are mapped to linear indices in grid.active_z_columns
"""
const ActiveZColumnsIBG = ImmersedBoundaryGrid{<:Any, <:Any, <:Any, <:Any, <:Any, <:Any, <:Any, <:AbstractArray}

struct InteriorMap end
struct ZColumnMap end

struct WestMap end
struct EastMap end
struct SouthMap end
struct NorthMap end

@inline active_surface_map(::ActiveZColumnsIBG) = ZColumnMap()
@inline retrieve_surface_active_cells_map(grid::ActiveZColumnsIBG) = grid.active_z_columns

@inline active_interior_map(::Val{:west}) = WestMap()
@inline active_interior_map(::Val{:east}) = EastMap()
@inline active_interior_map(::Val{:south}) = SouthMap()
@inline active_interior_map(::Val{:north}) = NorthMap()

@inline active_interior_map(::ActiveCellsIBG) = InteriorMap()
@inline active_interior_map(::DistributedActiveCellsIBG) = InteriorMap()
@inline retrieve_interior_active_cells_map(grid::WholeActiveCellsMapIBG, ::Val{:interior}) = grid.interior_active_cells
@inline retrieve_interior_active_cells_map(grid::SplitActiveCellsMapIBG, ::Val{:interior}) = grid.interior_active_cells.halo_independent_cells
@inline retrieve_interior_active_cells_map(grid::SplitActiveCellsMapIBG, ::Val{:west}) = grid.interior_active_cells.west_halo_dependent_cells
@inline retrieve_interior_active_cells_map(grid::SplitActiveCellsMapIBG, ::Val{:east}) = grid.interior_active_cells.east_halo_dependent_cells
@inline retrieve_interior_active_cells_map(grid::SplitActiveCellsMapIBG, ::Val{:south}) = grid.interior_active_cells.south_halo_dependent_cells
@inline retrieve_interior_active_cells_map(grid::SplitActiveCellsMapIBG, ::Val{:north}) = grid.interior_active_cells.north_halo_dependent_cells
@inline retrieve_interior_active_cells_map(grid::ActiveZColumnsIBG, ::Val{:surface}) = grid.active_z_columns

"""
active_cells_work_layout(group, size, map_type, grid)
Expand All @@ -52,19 +55,12 @@ Compute the work layout for active cells based on the given map type and grid.
# Arguments
- `group`: The previous workgroup.
- `size`: The previous worksize.
- `map_type`: The type of map (e.g., `InteriorMap`, `WestMap`, `EastMap`, `SouthMap`, `NorthMap`).
- `grid`: The grid containing the active cells.
- `active_cells_map`: The map containing the index of the active cells

# Returns
- A tuple `(workgroup, worksize)` representing the work layout for active cells.
"""
@inline active_cells_work_layout(group, size, ::InteriorMap, grid::ArrayActiveCellsIBG) = min(length(grid.interior_active_cells), 256), length(grid.interior_active_cells)
@inline active_cells_work_layout(group, size, ::InteriorMap, grid::NamedTupleActiveCellsIBG) = min(length(grid.interior_active_cells.interior), 256), length(grid.interior_active_cells.interior)
@inline active_cells_work_layout(group, size, ::WestMap, grid::NamedTupleActiveCellsIBG) = min(length(grid.interior_active_cells.west), 256), length(grid.interior_active_cells.west)
@inline active_cells_work_layout(group, size, ::EastMap, grid::NamedTupleActiveCellsIBG) = min(length(grid.interior_active_cells.east), 256), length(grid.interior_active_cells.east)
@inline active_cells_work_layout(group, size, ::SouthMap, grid::NamedTupleActiveCellsIBG) = min(length(grid.interior_active_cells.south), 256), length(grid.interior_active_cells.south)
@inline active_cells_work_layout(group, size, ::NorthMap, grid::NamedTupleActiveCellsIBG) = min(length(grid.interior_active_cells.north), 256), length(grid.interior_active_cells.north)
@inline active_cells_work_layout(group, size, ::ZColumnMap, grid::ActiveZColumnsIBG) = min(length(grid.active_z_columns), 256), length(grid.active_z_columns)
@inline active_cells_work_layout(group, size, active_cells_map) = min(length(active_cells_map), 256), length(active_cells_map)

"""
active_linear_index_to_tuple(idx, map, grid)
Expand All @@ -73,19 +69,12 @@ Converts a linear index to a tuple of indices based on the given map and grid.

# Arguments
- `idx`: The linear index to convert.
- `map`: The map indicating the type of index conversion to perform.
- `grid`: The grid containing the active cells.
- `active_cells_map`: The map containing the N-dimensional index of the active cells

# Returns
A tuple of indices corresponding to the linear index.
"""
@inline active_linear_index_to_tuple(idx, ::InteriorMap, grid::ArrayActiveCellsIBG) = Base.map(Int, grid.interior_active_cells[idx])
@inline active_linear_index_to_tuple(idx, ::InteriorMap, grid::NamedTupleActiveCellsIBG) = Base.map(Int, grid.interior_active_cells.interior[idx])
@inline active_linear_index_to_tuple(idx, ::WestMap, grid::NamedTupleActiveCellsIBG) = Base.map(Int, grid.interior_active_cells.west[idx])
@inline active_linear_index_to_tuple(idx, ::EastMap, grid::NamedTupleActiveCellsIBG) = Base.map(Int, grid.interior_active_cells.east[idx])
@inline active_linear_index_to_tuple(idx, ::SouthMap, grid::NamedTupleActiveCellsIBG) = Base.map(Int, grid.interior_active_cells.south[idx])
@inline active_linear_index_to_tuple(idx, ::NorthMap, grid::NamedTupleActiveCellsIBG) = Base.map(Int, grid.interior_active_cells.north[idx])
@inline active_linear_index_to_tuple(idx, ::ZColumnMap, grid::ActiveZColumnsIBG) = Base.map(Int, grid.active_z_columns[idx])
@inline active_linear_index_to_tuple(idx, active_cells_map) = @inbounds Base.map(Int, active_cells_map[idx])

function ImmersedBoundaryGrid(grid, ib; active_cells_map::Bool = true)

Expand Down Expand Up @@ -126,22 +115,33 @@ function compute_interior_active_cells(ibg; parameters = :xyz)
end

function compute_active_z_columns(ibg)
one_field = ConditionalOperation{Center, Center, Center}(OneField(Int), identity, ibg, NotImmersed(truefunc), 0)
column = sum(one_field, dims = 3)
is_immersed_column = KernelFunctionOperation{Center, Center, Nothing}(active_column, ibg, column)
active_cells_field = Field{Center, Center, Nothing}(ibg, Bool)
set!(active_cells_field, is_immersed_column)
return active_cells_field
one_field = OneField(Int)
condition = NotImmersed(truefunc)
mask = 0

# Compute all the active cells in a z-column using a ConditionalOperation
conditional_active_cells = ConditionalOperation{Center, Center, Center}(one_field, identity, ibg, condition, mask)
active_cells_in_column = sum(conditional_active_cells, dims = 3)

# Check whether the column ``i, j`` is immersed, which would correspond to `active_cells_in_column[i, j, 1] == 0`
is_immersed_column = KernelFunctionOperation{Center, Center, Nothing}(active_column, ibg, active_cells_in_column)
active_z_columns = Field{Center, Center, Nothing}(ibg, Bool)
set!(active_z_columns, is_immersed_column)

return active_z_columns
end

# Maximum integer represented by the
# `UInt8`, `UInt16` and `UInt32` types
const MAXUInt8 = 2^8 - 1
const MAXUInt16 = 2^16 - 1
const MAXUInt32 = 2^32 - 1

"""
interior_active_indices(ibg; parameters = :xyz)

Compute the indices of the active interior cells in the given immersed boundary grid.
Compute the indices of the active interior cells in the given immersed boundary grid within the indices
specified by the `parameters` keyword argument

# Arguments
- `ibg`: The immersed boundary grid.
Expand All @@ -158,7 +158,9 @@ function interior_active_indices(ibg; parameters = :xyz)

IndicesType = Tuple{IntType, IntType, IntType}

# Cannot findall on the entire field because we incur on OOM errors
# Cannot findall on the entire field because we could incur on OOM errors
# For this reason, we split the computation in vertical levels and `findall` the active indices in
# subsequent xy planes, then stitch them back together
active_indices = IndicesType[]
active_indices = findall_active_indices!(active_indices, active_cells_field, ibg, IndicesType)
active_indices = on_architecture(architecture(ibg), active_indices)
Expand Down Expand Up @@ -187,12 +189,22 @@ function convert_interior_indices(interior_indices, k, IndicesType)
return interior_indices
end

@inline add_3rd_index(t::Tuple, k) = (t[1], t[2], k)
@inline add_3rd_index(ij::Tuple, k) = (ij[1], ij[2], k)

# In case of a serial grid, the interior computations are performed over the whole three-dimensional
# domain. Therefore, the `interior_active_cells` field contains the indices of all the active cells in
# the range 1:Nx, 1:Ny and 1:Nz (i.e., we construct the map with parameters :xyz)
map_interior_active_cells(ibg) = interior_active_indices(ibg; parameters = :xyz)

# In case of a `DistributedGrid` we want to have different maps depending on the
# partitioning of the domain
# In case of a `DistributedGrid` we want to have different maps depending on the partitioning of the domain:
#
# If we partition the domain in the x-direction, we typically want to have the option to split three-dimensional
# kernels in a `halo-independent` part in the range Hx+1:Nx-Hx, 1:Ny, 1:Nz and two `halo-dependent` computations:
# a west one spanning 1:Hx, 1:Ny, 1:Nz and an east one spanning Nx-Hx+1:Nx, 1:Ny, 1:Nz.
# For this reason we need three different maps, one containing the `halo_independent` active region, a `west` map and an `east` map.
# For the same reason we need to construct `south` and `north` maps if we partition the domain in the y-direction.
# Therefore, the `interior_active_cells` in this case is a `NamedTuple` containing 5 elements.
# Note that boundary-adjacent maps corresponding to non-partitioned directions are set to `nothing`
function map_interior_active_cells(ibg::ImmersedBoundaryGrid{<:Any, <:Any, <:Any, <:Any, <:DistributedGrid})

arch = architecture(ibg)
Expand All @@ -213,20 +225,24 @@ function map_interior_active_cells(ibg::ImmersedBoundaryGrid{<:Any, <:Any, <:Any
include_south = !isa(ibg, YFlatGrid) && (Ry != 1) && !(Ty == RightConnected)
include_north = !isa(ibg, YFlatGrid) && (Ry != 1) && !(Ty == LeftConnected)

west = include_west ? interior_active_indices(ibg; parameters = KernelParameters(x_boundary, left_offsets)) : nothing
east = include_east ? interior_active_indices(ibg; parameters = KernelParameters(x_boundary, right_x_offsets)) : nothing
south = include_south ? interior_active_indices(ibg; parameters = KernelParameters(y_boundary, left_offsets)) : nothing
north = include_north ? interior_active_indices(ibg; parameters = KernelParameters(y_boundary, right_y_offsets)) : nothing
west_halo_dependent_cells = include_west ? interior_active_indices(ibg; parameters = KernelParameters(x_boundary, left_offsets)) : nothing
east_halo_dependent_cells = include_east ? interior_active_indices(ibg; parameters = KernelParameters(x_boundary, right_x_offsets)) : nothing
south_halo_dependent_cells = include_south ? interior_active_indices(ibg; parameters = KernelParameters(y_boundary, left_offsets)) : nothing
north_halo_dependent_cells = include_north ? interior_active_indices(ibg; parameters = KernelParameters(y_boundary, right_y_offsets)) : nothing

nx = Rx == 1 ? Nx : (Tx == RightConnected || Tx == LeftConnected ? Nx - Hx : Nx - 2Hx)
ny = Ry == 1 ? Ny : (Ty == RightConnected || Ty == LeftConnected ? Ny - Hy : Ny - 2Hy)

ox = Rx == 1 || Tx == RightConnected ? 0 : Hx
oy = Ry == 1 || Ty == RightConnected ? 0 : Hy

interior = interior_active_indices(ibg; parameters = KernelParameters((nx, ny, Nz), (ox, oy, 0)))
halo_independent_cells = interior_active_indices(ibg; parameters = KernelParameters((nx, ny, Nz), (ox, oy, 0)))

return (; interior, west, east, south, north)
return (; halo_independent_cells,
west_halo_dependent_cells,
east_halo_dependent_cells,
south_halo_dependent_cells,
north_halo_dependent_cells)
end

# If we eventually want to perform also barotropic step, `w` computation and `p`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Oceananigans.Models: compute_boundary_tendencies!
import Oceananigans.Models: compute_boundary_tendencies!

using Oceananigans.Grids: halo_size
using Oceananigans.ImmersedBoundaries: active_interior_map, DistributedActiveCellsIBG
using Oceananigans.ImmersedBoundaries: retrieve_interior_active_cells_map, DistributedActiveCellsIBG
using Oceananigans.Models.NonhydrostaticModels: boundary_tendency_kernel_parameters,
boundary_p_kernel_parameters,
boundary_κ_kernel_parameters,
Expand Down Expand Up @@ -38,13 +38,15 @@ function compute_boundary_tendency_contributions!(grid::DistributedActiveCellsIB
maps = grid.interior_active_cells

for (name, map) in zip(keys(maps), maps)
compute_boundary = (name != :interior) && !isnothing(map)

# If there exists a boundary map, then we compute the boundary contributions
# If there exists a boundary map, then we compute the boundary contributions. If not, the
# boundary contributions have already been calculated. We exclude the interior because it has
# already been calculated
compute_boundary = (name != :interior) && !isnothing(map)

if compute_boundary
active_boundary_map = active_interior_map(Val(name))
compute_hydrostatic_free_surface_tendency_contributions!(model, tuple(:xyz);
active_cells_map = active_boundary_map)
active_cells_map = retrieve_interior_active_cells_map(grid, Val(name))
compute_hydrostatic_free_surface_tendency_contributions!(model, tuple(:xyz); active_cells_map)
end
end

Expand Down
Loading