Skip to content

Commit b3fe8a4

Browse files
Remove use of matching subfields
Remove more use of matching_subfields Make more compile-time friendly Fixes Apply suggestions Try simple for-statement Try foreach_scalar Use more foreach_scalar Apply more suggestions Improve names Add tracer name to foreach_tracer Remove is_ρq_tot Add other non-tracers Update src/utils/variable_manipulations.jl Co-authored-by: Tapio Schneider <tapio@caltech.edu> Update src/utils/variable_manipulations.jl Co-authored-by: Tapio Schneider <tapio@caltech.edu> Update src/utils/variable_manipulations.jl Co-authored-by: Tapio Schneider <tapio@caltech.edu> foreach_tracer -> foreach_gs_tracer Bump allocation limits Apply formatter Bump allocation limit
1 parent b107abd commit b3fe8a4

File tree

8 files changed

+114
-44
lines changed

8 files changed

+114
-44
lines changed

perf/benchmark.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ are_boundschecks_forced = Base.JLOptions().check_bounds == 1
4949
if haskey(trials, name)
5050
if trials[name].memory mem
5151
@warn "Allocation limits for $name can be reduced to $(trials[name].memory)."
52+
else
53+
@info "trials[$name].memory: $(trials[name].memory)"
5254
end
5355
return trials[name].memory mem
5456
else
@@ -58,8 +60,8 @@ are_boundschecks_forced = Base.JLOptions().check_bounds == 1
5860
end
5961
@test compare_mem(trials, "Wfact", 0)
6062
@test compare_mem(trials, "ldiv!", 0)
61-
@test compare_mem(trials, "T_imp!", 1000000000000000000000)
62-
@test compare_mem(trials, "T_exp_T_lim!", 10496)
63+
@test compare_mem(trials, "T_imp!", 96)
64+
@test compare_mem(trials, "T_exp_T_lim!", 190420)
6365
@test compare_mem(trials, "lim!", 0)
6466
@test compare_mem(trials, "dss!", 0)
6567
@test compare_mem(trials, "cache!", 120)

perf/flame.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ ProfileCanvas.html_file(joinpath(output_dir, "flame.html"), results)
4040
allocs_limit = Dict()
4141
allocs_limit["flame_baroclinic_wave_moist_gpu"] = 1_243_048
4242
allocs_limit["flame_default"] = 99_928
43-
allocs_limit["flame_default_1m"] = 441_904
43+
allocs_limit["flame_default_1m"] = 527_712
4444
allocs_limit["flame_diagnostics"] = 10_677_144
4545
allocs_limit["flame_aquaplanet_diagedmf"] = 11_644_128
46-
allocs_limit["flame_aquaplanet_progedmf"] = 697_520
47-
allocs_limit["flame_aquaplanet_progedmf_dense_autodiff"] = 727_512
48-
allocs_limit["flame_diffusion"] = 100_360
46+
allocs_limit["flame_aquaplanet_progedmf"] = 774_712
47+
allocs_limit["flame_aquaplanet_progedmf_dense_autodiff"] = 774_712
48+
allocs_limit["flame_diffusion"] = 138_432
4949
allocs_limit["flame_threaded"] = 2047_736
5050
allocs_limit["flame_callbacks"] = 391_864
5151
allocs_limit["flame_gravity_wave"] = 581_381_976

src/parameterized_tendencies/les_sgs_models/smagorinsky_lilly.jl

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -107,22 +107,23 @@ function horizontal_smagorinsky_lilly_tendency!(Yₜ, Y, p, t, ::SmagorinskyLill
107107
@. Yₜ.c.ρe_tot += wdivₕ(Y.c.ρ * ᶜD_smag * gradₕ(ᶜh_tot))
108108

109109
## Tracer diffusion and associated mass changes
110-
for (ᶜρχₜ, ᶜχ, χ_name) in CA.matching_subfields(Yₜ.c, ᶜspecific)
111-
χ_name == :e_tot && continue
112-
ᶜρχₜ_diffusion =
113-
@. p.scratch.ᶜtemp_scalar = wdivₕ(Y.c.ρ * ᶜD_smag * gradₕ(ᶜχ))
110+
foreach_gs_tracer(Yₜ, Y) do ᶜρχₜ, ᶜρχ, ρχ_name
111+
ᶜχ = @. lazy(specific(ᶜρχ, Y.c.ρ))
112+
ᶜρχₜ_diffusion = @. lazy(wdivₕ(Y.c.ρ * ᶜD_smag * gradₕ(ᶜχ)))
114113
@. ᶜρχₜ += ᶜρχₜ_diffusion
115114
# Rain and snow does not affect the mass
116-
if χ_name (:q_rai, :q_sno)
115+
if ρχ_name == @name(ρq_tot)
117116
@. Yₜ.c.ρ += ᶜρχₜ_diffusion
118117
end
119118
end
120119

121120
end
122121

122+
import UnrolledUtilities as UU
123+
123124
function vertical_smagorinsky_lilly_tendency!(Yₜ, Y, p, t, ::SmagorinskyLilly)
124125
FT = eltype(Y)
125-
(; sfc_temp_C3, ᶠtemp_scalar, ᶜtemp_scalar) = p.scratch
126+
(; sfc_temp_C3, ᶠtemp_scalar) = p.scratch
126127
(; ᶜτ_smag, ᶠτ_smag, ᶠD_smag, ᶜspecific, ᶜh_tot, sfc_conditions) =
127128
p.precomputed
128129
(; ρ_flux_uₕ, ρ_flux_h_tot) = sfc_conditions
@@ -155,18 +156,17 @@ function vertical_smagorinsky_lilly_tendency!(Yₜ, Y, p, t, ::SmagorinskyLilly)
155156
@. Yₜ.c.ρe_tot -= ᶜdivᵥ_ρe_tot(-(ᶠρ * ᶠD_smag * ᶠgradᵥ(ᶜh_tot)))
156157

157158
## Tracer diffusion and associated mass changes
158-
for (ᶜρχₜ, ᶜχ, χ_name) in CA.matching_subfields(Yₜ.c, ᶜspecific)
159-
χ_name == :e_tot && continue
160-
161-
ᶜdivᵥ_ρχ = Operators.DivergenceF2C(;
162-
top = Operators.SetValue(C3(FT(0))),
163-
bottom = Operators.SetValue(C3(FT(0))),
164-
)
159+
ᶜdivᵥ_ρχ = Operators.DivergenceF2C(;
160+
top = Operators.SetValue(C3(FT(0))),
161+
bottom = Operators.SetValue(C3(FT(0))),
162+
)
165163

166-
ᶜ∇ᵥρD∇χₜ = @. ᶜtemp_scalar = ᶜdivᵥ_ρχ(-(ᶠρ * ᶠD_smag * ᶠgradᵥ(ᶜχ)))
164+
foreach_gs_tracer(Yₜ, Y) do ᶜρχₜ, ᶜρχ, ρχ_name
165+
ᶜ∇ᵥρD∇χₜ =
166+
@. lazy(ᶜdivᵥ_ρχ(-(ᶠρ * ᶠD_smag * ᶠgradᵥ(specific(ᶜρχ, Y.c.ρ)))))
167167
@. ᶜρχₜ -= ᶜ∇ᵥρD∇χₜ
168168
# Rain and snow does not affect the mass
169-
if χ_name == :q_tot
169+
if ρχ_name == @name(ρq_tot)
170170
@. Yₜ.c.ρ -= ᶜ∇ᵥρD∇χₜ
171171
end
172172
end

src/prognostic_equations/advection.jl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,10 +213,12 @@ NVTX.@annotate function explicit_vertical_advection_tendency!(Yₜ, Y, p, t)
213213
ᶜρ = Y.c.ρ
214214

215215
# Full vertical advection of passive tracers (like liq, rai, etc) ...
216-
for (ᶜρχₜ, ᶜχ, χ_name) in matching_subfields(Yₜ.c, ᶜspecific)
217-
χ_name in (:e_tot, :q_tot) && continue
218-
vtt = vertical_transport(ᶜρ, ᶠu³, ᶜχ, float(dt), tracer_upwinding)
219-
@. ᶜρχₜ += vtt
216+
foreach_gs_tracer(Yₜ, Y) do ᶜρχₜ, ᶜρχ, ρχ_name
217+
if !(ρχ_name in (@name(ρe_tot), @name(ρq_tot)))
218+
ᶜχ = @. lazy(specific(ᶜρχ, Y.c.ρ))
219+
vtt = vertical_transport(ᶜρ, ᶠu³, ᶜχ, float(dt), tracer_upwinding)
220+
@. ᶜρχₜ += vtt
221+
end
220222
end
221223
# ... and upwinding correction of energy and total water.
222224
# (The central advection of energy and total water is done implicitly.)

src/prognostic_equations/remaining_tendency.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ NVTX.@annotate function additional_tendency!(Yₜ, Y, p, t)
166166
@. Yₜ.c.ρe_tot += vst_ρe_tot
167167

168168
# TODO: can we write this out explicitly?
169-
for (ᶜρχₜ, ᶜχ, χ_name) in matching_subfields(Yₜ.c, ᶜspecific)
170-
χ_name == :e_tot && continue
169+
foreach_gs_tracer(Yₜ, Y) do ᶜρχₜ, ᶜρχ, ρχ_name
170+
ᶜχ = @. lazy(specific(ᶜρχ, Y.c.ρ))
171171
vst_tracer = viscous_sponge_tendency_tracer(ᶜρ, ᶜχ, viscous_sponge)
172172
@. ᶜρχₜ += vst_tracer
173173
@. Yₜ.c.ρ += vst_tracer # TODO: This doesn't look right for all tracers here. Remove?

src/prognostic_equations/surface_flux.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,16 @@ function surface_flux_tendency!(Yₜ, Y, p, t)
115115
btt = boundary_tendency_scalar(ᶜh_tot, sfc_conditions.ρ_flux_h_tot)
116116
@. Yₜ.c.ρe_tot -= btt
117117
ρ_flux_χ = p.scratch.sfc_temp_C3
118-
for (ᶜρχₜ, ᶜχ, χ_name) in matching_subfields(Yₜ.c, ᶜspecific)
119-
χ_name == :e_tot && continue
120-
if χ_name == :q_tot
118+
foreach_gs_tracer(Yₜ, Y) do ᶜρχₜ, ᶜρχ, ρχ_name
119+
ᶜχ = @. lazy(specific(ᶜρχ, Y.c.ρ))
120+
if ρχ_name == @name(ρq_tot)
121121
@. ρ_flux_χ = sfc_conditions.ρ_flux_q_tot
122122
else
123123
@. ρ_flux_χ = C3(FT(0))
124124
end
125125
btt = boundary_tendency_scalar(ᶜχ, ρ_flux_χ)
126126
@. ᶜρχₜ -= btt
127-
if χ_name == :q_tot
127+
if ρχ_name == @name(ρq_tot)
128128
@. Yₜ.c.ρ -= btt
129129
end
130130
end

src/prognostic_equations/vertical_diffusion_boundary_layer.jl

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ This function is dispatched based on the type of the vertical diffusion model
4646
for scalars. Zero-flux boundary conditions are explicitly applied.
4747
- **Note on mass conservation for `q_tot` diffusion**: The current implementation
4848
also modifies the tendency of total moist air density `Yₜ.c.ρ` based on the
49-
diffusion tendency of total specific humidity `ρq_tot`:
49+
diffusion tendency of total specific humidity `ρq_tot`:
5050
`Yₜ.c.ρ -= ᶜρχₜ_diffusion_for_q_tot`.
5151
5252
Arguments for all methods:
@@ -58,7 +58,7 @@ Arguments for all methods:
5858
- `t`: Current simulation time (not directly used in diffusion calculations).
5959
- `vert_diff_model` (for dispatched methods): The specific vertical diffusion model instance.
6060
61-
Modifies components of tendency vector `Yₜ.c` (e.g., `Yₜ.c.uₕ`, `Yₜ.c.ρe_tot`, `Yₜ.c.ρ`, and
61+
Modifies components of tendency vector `Yₜ.c` (e.g., `Yₜ.c.uₕ`, `Yₜ.c.ρe_tot`, `Yₜ.c.ρ`, and
6262
various tracer fields such as `Yₜ.c.ρq_tot`).
6363
"""
6464

@@ -96,23 +96,27 @@ function vertical_diffusion_boundary_layer_tendency!(
9696

9797
ᶜρχₜ_diffusion = p.scratch.ᶜtemp_scalar
9898
ᶜK_h_scaled = p.scratch.ᶜtemp_scalar_2
99-
for (ᶜρχₜ, ᶜχ, χ_name) in matching_subfields(Yₜ.c, ᶜspecific)
100-
χ_name == :e_tot && continue
101-
if χ_name in (:q_rai, :q_sno, :n_rai)
99+
ᶜdivᵥ_ρχ = Operators.DivergenceF2C(
100+
top = Operators.SetValue(C3(0)),
101+
bottom = Operators.SetValue(C3(0)),
102+
)
103+
foreach_gs_tracer(Yₜ, Y) do ᶜρχₜ, ᶜρχ, ρχ_name
104+
if ρχ_name in (@name(ρq_rai), @name(ρq_sno), @name(ρn_rai))
102105
@. ᶜK_h_scaled = α_vert_diff_tracer * ᶜK_h
103106
else
104107
@. ᶜK_h_scaled = ᶜK_h
105108
end
106-
ᶜdivᵥ_ρχ = Operators.DivergenceF2C(
107-
top = Operators.SetValue(C3(0)),
108-
bottom = Operators.SetValue(C3(0)),
109+
@. ᶜρχₜ_diffusion = ᶜdivᵥ_ρχ(
110+
-(
111+
ᶠinterp(Y.c.ρ) *
112+
ᶠinterp(ᶜK_h_scaled) *
113+
ᶠgradᵥ(specific(ᶜρχ, Y.c.ρ))
114+
),
109115
)
110-
@. ᶜρχₜ_diffusion =
111-
ᶜdivᵥ_ρχ(-(ᶠinterp(Y.c.ρ) * ᶠinterp(ᶜK_h_scaled) * ᶠgradᵥ(ᶜχ)))
112116
@. ᶜρχₜ -= ᶜρχₜ_diffusion
113-
# Only add contribution from total water diffusion to mass tendency
114-
# (exclude contributions from diffusion of condensate, precipitation)
115-
if χ_name == :q_tot
117+
# Only add contribution from total water diffusion to mass tendency
118+
# (exclude contributions from diffusion of condensate, precipitation)
119+
if ρχ_name == @name(ρq_tot)
116120
@. Yₜ.c.ρ -= ᶜρχₜ_diffusion
117121
end
118122
end

src/utils/variable_manipulations.jl

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import ClimaCore.MatrixFields: @name
2+
13
"""
24
specific(ρχ, ρ)
35
specific(ρaχ, ρa, ρχ, ρ, turbconv_model)
@@ -51,6 +53,66 @@ Arguments:
5153
return ρa == 0 ? ρχ / ρ : weight * ρaχ / ρa + (1 - weight) * ρχ / ρ
5254
end
5355

56+
"""
57+
tracer_names(field)
58+
59+
Filters and returns the names of the variables from a given state
60+
vector component, excluding `ρ`, `ρe_tot`, and `uₕ` and SGS fields.
61+
62+
Arguments:
63+
64+
- `field`: A component of the state vector `Y.c`.
65+
66+
Returns:
67+
68+
- A `Tuple` of `ClimaCore.MatrixFields.FieldName`s corresponding to the tracers.
69+
"""
70+
tracer_names(field) =
71+
unrolled_filter(MatrixFields.top_level_names(field)) do name
72+
!(
73+
name in
74+
(@name(ρ), @name(ρe_tot), @name(uₕ), @name(sgs⁰), @name(sgsʲs))
75+
)
76+
end
77+
78+
"""
79+
foreach_gs_tracer(f::F, Yₜ, Y) where {F}
80+
81+
Applies a given function `f` to each grid-scale scalar variable (except `ρ` and `ρe_tot`)
82+
in the state `Y` and its corresponding tendency `Yₜ`.
83+
This utility abstracts the process of iterating over all scalars. It uses
84+
`tracer_names` to identify the relevant variables and `unrolled_foreach` to
85+
ensure a performant loop. For each tracer, it calls the provided function `f`
86+
with the tendency field, the state field, and a boolean flag indicating if
87+
the current tracer is `ρq_tot` (to allow for special handling).
88+
89+
Arguments:
90+
91+
- `f`: A function to apply to each grid-scale scalar. It must have the signature `f
92+
(ᶜρχₜ, ᶜρχ, ρχ_name)`, where `ᶜρχₜ` is the tendency field, `ᶜρχ`
93+
is the state field, and `ρχ_name` is a `MatrixFields.@name` object.
94+
- `Yₜ`: The tendency state vector.
95+
- `Y`: The current state vector.
96+
97+
# Example
98+
99+
```julia
100+
foreach_gs_tracer(Yₜ, Y) do ᶜρχₜ, ᶜρχ, ρχ_name
101+
# Apply some operation, e.g., a sponge layer
102+
@. ᶜρχₜ += some_sponge_function(ᶜρχ)
103+
if ρχ_name == @name(ρq_tot)
104+
# Perform an additional operation only for ρq_tot
105+
end
106+
end
107+
```
108+
"""
109+
foreach_gs_tracer(f::F, Yₜ, Y) where {F} =
110+
unrolled_foreach(tracer_names(Y.c)) do scalar_name
111+
ᶜρχₜ = MatrixFields.get_field(Yₜ.c, scalar_name)
112+
ᶜρχ = MatrixFields.get_field(Y.c, scalar_name)
113+
f(ᶜρχₜ, ᶜρχ, scalar_name)
114+
end
115+
54116
"""
55117
sgs_weight_function(a, a_half)
56118

0 commit comments

Comments
 (0)