1- using Oceananigans. Grids: NegativeZDirection, validate_unit_vector
1+ using Oceananigans. Utils
2+ using Oceananigans. Fields
3+ using Oceananigans. Grids: NegativeZDirection, validate_unit_vector, architecture
4+ using Oceananigans. BoundaryConditions
5+
6+ using KernelAbstractions: @kernel , @index
27using Adapt
38
4- struct BuoyancyForce{M, G}
9+ struct BuoyancyForce{M, G, B }
510 formulation :: M
611 gravity_unit_vector :: G
12+ gradients :: B
713end
814
9- Adapt. adapt_structure (to, bf:: BuoyancyForce ) =
10- BuoyancyForce (adapt (to, bf. formulation),
11- adapt (to, bf. gravity_unit_vector))
12-
1315"""
14- BuoyancyForce(formulation; gravity_unit_vector=NegativeZDirection())
16+ BuoyancyForce(grid, formulation::AbstractBuoyancyFormulation ; gravity_unit_vector=NegativeZDirection(), materialize_gradients=true )
1517
16- Construct a `buoyancy` given a buoyancy `model `. Optional keyword argument `gravity_unit_vector`
18+ Construct a `buoyancy` given a buoyancy `formulation `. Optional keyword argument `gravity_unit_vector`
1719can be used to specify the direction of gravity (default `NegativeZDirection()`).
1820The buoyancy acceleration acts in the direction opposite to gravity.
21+ If `materialize_gradients` is true (default), the buoyancy gradients will be precomputed and stored in fields for
22+ performance reasons. For `materialize_gradients=true`, the `grid` argument must be provided.
1923
2024Example
2125=======
@@ -44,11 +48,31 @@ NonhydrostaticModel{CPU, RectilinearGrid}(time = 0 seconds, iteration = 0)
4448└── coriolis: Nothing
4549```
4650"""
47- function BuoyancyForce (formulation; gravity_unit_vector= NegativeZDirection ())
51+ function BuoyancyForce (grid, formulation:: AbstractBuoyancyFormulation ; gravity_unit_vector= NegativeZDirection (), materialize_gradients = true )
4852 gravity_unit_vector = validate_unit_vector (gravity_unit_vector)
49- return BuoyancyForce (formulation, gravity_unit_vector)
53+
54+ if materialize_gradients
55+ ∂x_b = XFaceField (grid)
56+ ∂y_b = YFaceField (grid)
57+ ∂z_b = ZFaceField (grid)
58+
59+ gradients = (; ∂x_b, ∂y_b, ∂z_b)
60+ else
61+ gradients = nothing
62+ end
63+
64+ return BuoyancyForce (formulation, gravity_unit_vector, gradients)
5065end
5166
67+ # Fallback for when no grid is available, we overwrite `materialize_gradients` to false
68+ BuoyancyForce (formulation:: AbstractBuoyancyFormulation ; materialize_gradients= false , kwargs... ) =
69+ BuoyancyForce (nothing , formulation; materialize_gradients= false , kwargs... )
70+
71+ Adapt. adapt_structure (to, bf:: BuoyancyForce ) =
72+ BuoyancyForce (Adapt. adapt (to, bf. formulation),
73+ Adapt. adapt (to, bf. gravity_unit_vector),
74+ Adapt. adapt (to, bf. gradients))
75+
5276@inline ĝ_x (bf) = @inbounds - bf. gravity_unit_vector[1 ]
5377@inline ĝ_y (bf) = @inbounds - bf. gravity_unit_vector[2 ]
5478@inline ĝ_z (bf) = @inbounds - bf. gravity_unit_vector[3 ]
6589
6690@inline get_temperature_and_salinity (bf:: BuoyancyForce , C) = get_temperature_and_salinity (bf. formulation, C)
6791
68- @inline ∂x_b (i, j, k, grid, b:: BuoyancyForce , C) = ∂x_b (i, j, k, grid, b. formulation, C)
69- @inline ∂y_b (i, j, k, grid, b:: BuoyancyForce , C) = ∂y_b (i, j, k, grid, b. formulation, C)
70- @inline ∂z_b (i, j, k, grid, b:: BuoyancyForce , C) = ∂z_b (i, j, k, grid, b. formulation, C)
92+ @inline ∂x_b (i, j, k, grid, b:: BuoyancyForce{<:Any, <:Any, Nothing} , C) = ∂x_b (i, j, k, grid, b. formulation, C)
93+ @inline ∂y_b (i, j, k, grid, b:: BuoyancyForce{<:Any, <:Any, Nothing} , C) = ∂y_b (i, j, k, grid, b. formulation, C)
94+ @inline ∂z_b (i, j, k, grid, b:: BuoyancyForce{<:Any, <:Any, Nothing} , C) = ∂z_b (i, j, k, grid, b. formulation, C)
7195
7296@inline top_buoyancy_flux (i, j, grid, b:: BuoyancyForce , args... ) = top_buoyancy_flux (i, j, grid, b. formulation, args... )
7397
74- regularize_buoyancy (bf) = bf
75- regularize_buoyancy (formulation:: AbstractBuoyancyFormulation ) = BuoyancyForce (formulation)
98+ materialize_buoyancy (bf, grid; kw... ) = bf
99+ materialize_buoyancy (formulation:: AbstractBuoyancyFormulation , grid; kw... ) = BuoyancyForce (grid, formulation; kw... )
100+
101+ # Fallback
102+ compute_buoyancy_gradients! (:: BuoyancyForce{<:Any, <:Any, <:Nothing} , grid, tracers; kw... ) = nothing
103+ compute_buoyancy_gradients! (:: Nothing , grid, tracers; kw... ) = nothing
76104
77105Base. summary (bf:: BuoyancyForce ) = string (summary (bf. formulation),
78106 " with ĝ = " ,
@@ -89,3 +117,29 @@ function Base.show(io::IO, bf::BuoyancyForce)
89117 " ├── formulation: " , prettysummary (bf. formulation), ' \n ' ,
90118 " └── gravity_unit_vector: " , summarize_vector (bf. gravity_unit_vector))
91119end
120+
121+ # ####
122+ # #### Some performance optimizations for models that compute gradients over and over...
123+ # ####
124+
125+ @inline ∂x_b (i, j, k, grid, b:: BuoyancyForce , C) = @inbounds b. gradients.∂x_b[i, j, k]
126+ @inline ∂y_b (i, j, k, grid, b:: BuoyancyForce , C) = @inbounds b. gradients.∂y_b[i, j, k]
127+ @inline ∂z_b (i, j, k, grid, b:: BuoyancyForce , C) = @inbounds b. gradients.∂z_b[i, j, k]
128+
129+ function compute_buoyancy_gradients! (buoyancy, grid, tracers; parameters= :xyz )
130+ gradients = buoyancy. gradients
131+ formulation = buoyancy. formulation
132+ launch! (architecture (grid), grid, parameters, _compute_buoyancy_gradients!, gradients, grid, formulation, tracers)
133+ fill_halo_regions! (gradients, only_local_halos= true )
134+
135+ return nothing
136+ end
137+
138+ @kernel function _compute_buoyancy_gradients! (g, grid, b, C)
139+ i, j, k = @index (Global, NTuple)
140+ @inbounds begin
141+ g.∂x_b[i, j, k] = ∂x_b (i, j, k, grid, b, C)
142+ g.∂y_b[i, j, k] = ∂y_b (i, j, k, grid, b, C)
143+ g.∂z_b[i, j, k] = ∂z_b (i, j, k, grid, b, C)
144+ end
145+ end
0 commit comments