@@ -6,6 +6,22 @@ import ClimaCore.Geometry as Geometry
66import ClimaCore. Fields as Fields
77import ClimaCore. Spaces as Spaces
88
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+
925hyperdiffusion_cache (Y, atmos) = hyperdiffusion_cache (
1026 Y,
1127 atmos. hyperdiff,
@@ -34,7 +50,7 @@ function hyperdiffusion_cache(
3450 gs_quantities = (;
3551 ᶜ∇²u = similar (Y. c, C123{FT}),
3652 ᶜ∇²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 )),
3854 )
3955
4056 # Sub-grid scale quantities
@@ -85,7 +101,7 @@ NVTX.@annotate function prep_hyperdiffusion_tendency!(Yₜ, Y, p, t)
85101
86102 n = n_mass_flux_subdomains (turbconv_model)
87103 diffuse_tke = use_prognostic_tke (turbconv_model)
88- (; ᶜp, ᶜspecific ) = p. precomputed
104+ (; ᶜp) = p. precomputed
89105 (; ᶜh_ref) = p. core
90106 (; ᶜ∇²u, ᶜ∇²specific_energy) = p. hyperdiff
91107 if turbconv_model isa PrognosticEDMFX
@@ -125,20 +141,14 @@ NVTX.@annotate function apply_hyperdiffusion_tendency!(Yₜ, Y, p, t)
125141 (; hyperdiff, turbconv_model) = p. atmos
126142 isnothing (hyperdiff) && return nothing
127143
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)
136146
137147 n = n_mass_flux_subdomains (turbconv_model)
138148 diffuse_tke = use_prognostic_tke (turbconv_model)
139149 ᶜJ = Fields. local_geometry_field (Y. c). J
140150 point_type = eltype (Fields. coordinate_field (Y. c))
141- (; ᶜp, ᶜspecific ) = p. precomputed
151+ (; ᶜp) = p. precomputed
142152 (; ᶜ∇²u, ᶜ∇²specific_energy) = p. hyperdiff
143153 if turbconv_model isa PrognosticEDMFX
144154 (; ᶜρa⁰) = p. precomputed
@@ -241,11 +251,12 @@ NVTX.@annotate function prep_tracer_hyperdiffusion_tendency!(Yₜ, Y, p, t)
241251 (; hyperdiff, turbconv_model) = p. atmos
242252 isnothing (hyperdiff) && return nothing
243253
244- (; ᶜspecific) = p. precomputed
245254 (; ᶜ∇²specific_tracers) = p. hyperdiff
246255
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. ρ)))
249260 end
250261
251262 if turbconv_model isa PrognosticEDMFX
@@ -276,31 +287,24 @@ NVTX.@annotate function apply_tracer_hyperdiffusion_tendency!(Yₜ, Y, p, t)
276287 (; hyperdiff, turbconv_model) = p. atmos
277288 isnothing (hyperdiff) && return nothing
278289
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
285293
294+ n = n_mass_flux_subdomains (turbconv_model)
286295 (; ᶜ∇²specific_tracers) = p. hyperdiff
287296
288297 # TODO : Since we are not applying the limiter to density (or area-weighted
289298 # density), the mass redistributed by hyperdiffusion will not be conserved
290299 # 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)
304308 @. Yₜ. c. ρ -= ν₄_scalar * wdivₕ (Y. c. ρ * gradₕ (ᶜ∇²χ))
305309 end
306310 end
@@ -323,13 +327,9 @@ NVTX.@annotate function apply_tracer_hyperdiffusion_tendency!(Yₜ, Y, p, t)
323327 @. Yₜ. c. sgsʲs.:($$ j). q_ice -=
324328 ν₄_scalar * wdivₕ (gradₕ (ᶜ∇²q_iceʲs.:($$ j)))
325329 @. 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)))
329331 @. 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)))
333333 end
334334 end
335335 end
0 commit comments