1
- using Oceananigans. Fields: location
1
+ using Oceananigans. Fields: location, instantiated_location
2
2
using Oceananigans. TurbulenceClosures: implicit_step!
3
3
using Oceananigans. ImmersedBoundaries: get_active_cells_map, get_active_column_map
4
4
5
- import Oceananigans. TimeSteppers: split_rk3_substep!, _split_rk3_substep_field!
5
+ import Oceananigans. TimeSteppers: split_rk3_substep!, _split_rk3_substep_field!, store_fields!
6
6
7
7
function split_rk3_substep! (model:: HydrostaticFreeSurfaceModel , Δt, γⁿ, ζⁿ)
8
8
9
9
grid = model. grid
10
10
timestepper = model. timestepper
11
11
free_surface = model. free_surface
12
-
12
+
13
13
compute_free_surface_tendency! (grid, model, free_surface)
14
14
15
15
rk3_substep_velocities! (model. velocities, model, Δt, γⁿ, ζⁿ)
@@ -18,8 +18,7 @@ function split_rk3_substep!(model::HydrostaticFreeSurfaceModel, Δt, γⁿ, ζ
18
18
# Full step for Implicit and Split-Explicit, substep for Explicit
19
19
step_free_surface! (free_surface, model, timestepper, Δt)
20
20
21
- # Average free surface variables
22
- # in the second stage
21
+ # Average free surface variables in the second stage
23
22
if model. clock. stage == 2
24
23
rk3_average_free_surface! (free_surface, grid, timestepper, γⁿ, ζⁿ)
25
24
end
@@ -46,11 +45,17 @@ function rk3_average_free_surface!(free_surface::SplitExplicitFreeSurface, grid,
46
45
47
46
Uⁿ⁻¹ = timestepper. Ψ⁻. U
48
47
Vⁿ⁻¹ = timestepper. Ψ⁻. V
48
+ ηⁿ⁻¹ = timestepper. Ψ⁻. η
49
49
Uⁿ = free_surface. barotropic_velocities. U
50
50
Vⁿ = free_surface. barotropic_velocities. V
51
+ ηⁿ = free_surface. η
51
52
52
53
launch! (arch, grid, :xy , _rk3_average_free_surface!, Uⁿ, grid, Uⁿ⁻¹, γⁿ, ζⁿ)
53
54
launch! (arch, grid, :xy , _rk3_average_free_surface!, Vⁿ, grid, Vⁿ⁻¹, γⁿ, ζⁿ)
55
+
56
+ # Averaging the free surface is only required for a grid with Mutable vertical coordinates,
57
+ # which needs to update the grid based on the value of the free surface
58
+ launch! (arch, grid, :xy , _rk3_average_free_surface!, ηⁿ, grid, ηⁿ⁻¹, γⁿ, ζⁿ)
54
59
55
60
return nothing
56
61
end
@@ -97,19 +102,20 @@ function rk3_substep_tracers!(tracers, model, Δt, γⁿ, ζⁿ)
97
102
98
103
closure = model. closure
99
104
grid = model. grid
105
+ FT = eltype (grid)
100
106
101
107
# Tracer update kernels
102
108
for (tracer_index, tracer_name) in enumerate (propertynames (tracers))
103
109
104
110
Gⁿ = model. timestepper. Gⁿ[tracer_name]
105
111
Ψ⁻ = model. timestepper. Ψ⁻[tracer_name]
106
- tracer_field = tracers[tracer_name]
112
+ θ = tracers[tracer_name]
107
113
closure = model. closure
108
114
109
115
launch! (architecture (grid), grid, :xyz ,
110
- _split_rk3_substep_field !, tracer_field, Δt , γⁿ, ζⁿ, Gⁿ, Ψ⁻)
116
+ _split_rk3_substep_tracer_field !, θ, grid, convert (FT, Δt) , γⁿ, ζⁿ, Gⁿ, Ψ⁻)
111
117
112
- implicit_step! (tracer_field ,
118
+ implicit_step! (θ ,
113
119
model. timestepper. implicit_solver,
114
120
closure,
115
121
model. diffusivity_fields,
@@ -119,4 +125,56 @@ function rk3_substep_tracers!(tracers, model, Δt, γⁿ, ζⁿ)
119
125
end
120
126
121
127
return nothing
122
- end
128
+ end
129
+
130
+ # ####
131
+ # #### Tracer update in mutable vertical coordinates
132
+ # ####
133
+
134
+ # σθ is the evolved quantity.
135
+ # We store temporarily σθ in θ. Once σⁿ⁺¹ is known we can retrieve θⁿ⁺¹
136
+ # with the `unscale_tracers!` function. Ψ⁻ is the previous tracer already scaled
137
+ # by the vertical coordinate scaling factor: ψ⁻ = σ * θ
138
+ @kernel function _split_rk3_substep_tracer_field! (θ, grid, Δt, γⁿ, ζⁿ, Gⁿ, Ψ⁻)
139
+ i, j, k = @index (Global, NTuple)
140
+
141
+ σᶜᶜⁿ = σⁿ (i, j, k, grid, Center (), Center (), Center ())
142
+ @inbounds θ[i, j, k] = ζⁿ * Ψ⁻[i, j, k] + γⁿ * σᶜᶜⁿ * (θ[i, j, k] + Δt * Gⁿ[i, j, k])
143
+ end
144
+
145
+ # We store temporarily σθ in θ.
146
+ # The unscaled θ will be retrieved with `unscale_tracers!`
147
+ @kernel function _split_rk3_substep_tracer_field! (θ, grid, Δt, :: Nothing , :: Nothing , Gⁿ, Ψ⁻)
148
+ i, j, k = @index (Global, NTuple)
149
+ @inbounds θ[i, j, k] = Ψ⁻[i, j, k] + Δt * Gⁿ[i, j, k] * σⁿ (i, j, k, grid, Center (), Center (), Center ())
150
+ end
151
+
152
+ # ####
153
+ # #### Storing previous fields for the RK3 update
154
+ # ####
155
+
156
+ # Tracers are multiplied by the vertical coordinate scaling factor
157
+ @kernel function _store_tracer_fields! (Ψ⁻, grid, Ψⁿ)
158
+ i, j, k = @index (Global, NTuple)
159
+ @inbounds Ψ⁻[i, j, k] = Ψⁿ[i, j, k] * σⁿ (i, j, k, grid, Center (), Center (), Center ())
160
+ end
161
+
162
+ function store_fields! (model:: HydrostaticFreeSurfaceModel )
163
+
164
+ previous_fields = model. timestepper. Ψ⁻
165
+ model_fields = prognostic_fields (model)
166
+ grid = model. grid
167
+ arch = architecture (grid)
168
+
169
+ for name in keys (model_fields)
170
+ Ψ⁻ = previous_fields[name]
171
+ Ψⁿ = model_fields[name]
172
+ if name ∈ keys (model. tracers) # Tracers are stored with the grid scaling
173
+ launch! (arch, grid, :xyz , _store_tracer_fields!, Ψ⁻, grid, Ψⁿ)
174
+ else # Velocities and free surface are stored without the grid scaling
175
+ parent (Ψ⁻) .= parent (Ψⁿ)
176
+ end
177
+ end
178
+
179
+ return nothing
180
+ end
0 commit comments