@@ -6,6 +6,22 @@ import ClimaCore.Geometry as Geometry
6
6
import ClimaCore. Fields as Fields
7
7
import ClimaCore. Spaces as Spaces
8
8
9
+ """
10
+ ν₄(hyperdiff, Y)
11
+
12
+ A `NamedTuple` of the hyperdiffusivity `ν₄_scalar` and the hyperviscosity
13
+ `ν₄_vorticity`. These quantities are assumed to scale with `h^3`, where `h` is
14
+ the mean nodal distance, following the empirical results of Lauritzen et al.
15
+ (2018, https://doi.org/10.1029/2017MS001257). When `h == 1`, these quantities
16
+ are equal to `hyperdiff.ν₄_scalar_coeff` and `hyperdiff.ν₄_vorticity_coeff`.
17
+ """
18
+ function ν₄ (hyperdiff, Y)
19
+ h = Spaces. node_horizontal_length_scale (Spaces. horizontal_space (axes (Y. c)))
20
+ ν₄_scalar = hyperdiff. ν₄_scalar_coeff * h^ 3
21
+ ν₄_vorticity = hyperdiff. ν₄_vorticity_coeff * h^ 3
22
+ return (; ν₄_scalar, ν₄_vorticity)
23
+ end
24
+
9
25
hyperdiffusion_cache (Y, atmos) = hyperdiffusion_cache (
10
26
Y,
11
27
atmos. hyperdiff,
@@ -34,7 +50,7 @@ function hyperdiffusion_cache(
34
50
gs_quantities = (;
35
51
ᶜ∇²u = similar (Y. c, C123{FT}),
36
52
ᶜ∇²specific_energy = similar (Y. c, FT),
37
- ᶜ∇²specific_tracers = remove_energy_var .( specific_gs .(Y . c )),
53
+ ᶜ∇²specific_tracers = Base . materialize ( ᶜspecific_gs_tracers (Y )),
38
54
)
39
55
40
56
# Sub-grid scale quantities
@@ -85,7 +101,7 @@ NVTX.@annotate function prep_hyperdiffusion_tendency!(Yₜ, Y, p, t)
85
101
86
102
n = n_mass_flux_subdomains (turbconv_model)
87
103
diffuse_tke = use_prognostic_tke (turbconv_model)
88
- (; ᶜp, ᶜspecific ) = p. precomputed
104
+ (; ᶜp) = p. precomputed
89
105
(; ᶜh_ref) = p. core
90
106
(; ᶜ∇²u, ᶜ∇²specific_energy) = p. hyperdiff
91
107
if turbconv_model isa PrognosticEDMFX
@@ -125,20 +141,14 @@ NVTX.@annotate function apply_hyperdiffusion_tendency!(Yₜ, Y, p, t)
125
141
(; hyperdiff, turbconv_model) = p. atmos
126
142
isnothing (hyperdiff) && return nothing
127
143
128
- (; ν₄_vorticity_coeff, ν₄_scalar_coeff, divergence_damping_factor) =
129
- hyperdiff
130
-
131
- h_space = Spaces. horizontal_space (axes (Y. c))
132
- h_length_scale = Spaces. node_horizontal_length_scale (h_space) # mean nodal distance
133
-
134
- ν₄_scalar = ν₄_scalar_coeff * h_length_scale^ 3
135
- ν₄_vorticity = ν₄_vorticity_coeff * h_length_scale^ 3
144
+ (; divergence_damping_factor) = hyperdiff
145
+ (; ν₄_scalar, ν₄_vorticity) = ν₄ (hyperdiff, Y)
136
146
137
147
n = n_mass_flux_subdomains (turbconv_model)
138
148
diffuse_tke = use_prognostic_tke (turbconv_model)
139
149
ᶜJ = Fields. local_geometry_field (Y. c). J
140
150
point_type = eltype (Fields. coordinate_field (Y. c))
141
- (; ᶜp, ᶜspecific ) = p. precomputed
151
+ (; ᶜp) = p. precomputed
142
152
(; ᶜ∇²u, ᶜ∇²specific_energy) = p. hyperdiff
143
153
if turbconv_model isa PrognosticEDMFX
144
154
(; ᶜρa⁰) = p. precomputed
@@ -241,11 +251,12 @@ NVTX.@annotate function prep_tracer_hyperdiffusion_tendency!(Yₜ, Y, p, t)
241
251
(; hyperdiff, turbconv_model) = p. atmos
242
252
isnothing (hyperdiff) && return nothing
243
253
244
- (; ᶜspecific) = p. precomputed
245
254
(; ᶜ∇²specific_tracers) = p. hyperdiff
246
255
247
- for χ_name in propertynames (ᶜ∇²specific_tracers)
248
- @. ᶜ∇²specific_tracers.:($$ χ_name) = wdivₕ (gradₕ (ᶜspecific.:($$ χ_name)))
256
+ # TODO : Fix RecursiveApply bug in gradₕ to fuse this operation.
257
+ # ᶜ∇²specific_tracers .= wdivₕ.(gradₕ.(ᶜspecific_gs_tracers(Y)))
258
+ foreach_gs_tracer (Y, ᶜ∇²specific_tracers) do ᶜρχ, ᶜ∇²χ, _
259
+ @. ᶜ∇²χ = wdivₕ (gradₕ (specific (ᶜρχ, Y. c. ρ)))
249
260
end
250
261
251
262
if turbconv_model isa PrognosticEDMFX
@@ -276,31 +287,24 @@ NVTX.@annotate function apply_tracer_hyperdiffusion_tendency!(Yₜ, Y, p, t)
276
287
(; hyperdiff, turbconv_model) = p. atmos
277
288
isnothing (hyperdiff) && return nothing
278
289
279
- α_hyperdiff_tracer = CAP. α_hyperdiff_tracer (p. params)
280
- (; ν₄_scalar_coeff) = hyperdiff
281
- h_space = Spaces. horizontal_space (axes (Y. c))
282
- h_length_scale = Spaces. node_horizontal_length_scale (h_space) # mean nodal distance
283
- ν₄_scalar = ν₄_scalar_coeff * h_length_scale^ 3
284
- n = n_mass_flux_subdomains (turbconv_model)
290
+ # Rescale the hyperdiffusivity for precipitating species.
291
+ (; ν₄_scalar) = ν₄ (hyperdiff, Y)
292
+ ν₄_scalar_for_precip = CAP. α_hyperdiff_tracer (p. params) * ν₄_scalar
285
293
294
+ n = n_mass_flux_subdomains (turbconv_model)
286
295
(; ᶜ∇²specific_tracers) = p. hyperdiff
287
296
288
297
# TODO : Since we are not applying the limiter to density (or area-weighted
289
298
# density), the mass redistributed by hyperdiffusion will not be conserved
290
299
# by the limiter. Is this a significant problem?
291
- # TODO : Figure out why caching the duplicated tendencies in ᶜtemp_scalar
292
- # triggers allocations.
293
- for (ᶜρχₜ, ᶜ∇²χ, χ_name) in matching_subfields (Yₜ. c, ᶜ∇²specific_tracers)
294
- ν₄_scalar = ifelse (
295
- χ_name in (:q_rai , :q_sno , :n_rai ),
296
- α_hyperdiff_tracer * ν₄_scalar,
297
- ν₄_scalar,
298
- )
299
- @. ᶜρχₜ -= ν₄_scalar * wdivₕ (Y. c. ρ * gradₕ (ᶜ∇²χ))
300
-
301
- # Exclude contributions from hyperdiffusion of condensate,
302
- # precipitating species from mass tendency.
303
- if χ_name == :q_tot
300
+ foreach_gs_tracer (Yₜ, ᶜ∇²specific_tracers) do ᶜρχₜ, ᶜ∇²χ, ρχ_name
301
+ ν₄_scalar_for_χ =
302
+ ρχ_name in (@name (ρq_rai), @name (ρq_sno), @name (ρn_rai)) ?
303
+ ν₄_scalar_for_precip : ν₄_scalar
304
+ @. ᶜρχₜ -= ν₄_scalar_for_χ * wdivₕ (Y. c. ρ * gradₕ (ᶜ∇²χ))
305
+
306
+ # Take into account the effect of total water diffusion on density.
307
+ if ρχ_name == @name (ρq_tot)
304
308
@. Yₜ. c. ρ -= ν₄_scalar * wdivₕ (Y. c. ρ * gradₕ (ᶜ∇²χ))
305
309
end
306
310
end
@@ -323,13 +327,9 @@ NVTX.@annotate function apply_tracer_hyperdiffusion_tendency!(Yₜ, Y, p, t)
323
327
@. Yₜ. c. sgsʲs.:($$ j). q_ice -=
324
328
ν₄_scalar * wdivₕ (gradₕ (ᶜ∇²q_iceʲs.:($$ j)))
325
329
@. Yₜ. c. sgsʲs.:($$ j). q_rai -=
326
- α_hyperdiff_tracer *
327
- ν₄_scalar *
328
- wdivₕ (gradₕ (ᶜ∇²q_raiʲs.:($$ j)))
330
+ ν₄_scalar_for_precip * wdivₕ (gradₕ (ᶜ∇²q_raiʲs.:($$ j)))
329
331
@. Yₜ. c. sgsʲs.:($$ j). q_sno -=
330
- α_hyperdiff_tracer *
331
- ν₄_scalar *
332
- wdivₕ (gradₕ (ᶜ∇²q_snoʲs.:($$ j)))
332
+ ν₄_scalar_for_precip * wdivₕ (gradₕ (ᶜ∇²q_snoʲs.:($$ j)))
333
333
end
334
334
end
335
335
end
0 commit comments