Skip to content

Commit c98b81f

Browse files
committed
does this work on gpu
1 parent 192c433 commit c98b81f

File tree

4 files changed

+272
-4
lines changed

4 files changed

+272
-4
lines changed

src/prognostic_equations/advection.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ NVTX.@annotate function horizontal_dynamics_tendency!(Yₜ, Y, p, t)
7373

7474
(; ᶜq_tot_safe) = p.precomputed
7575
ᶜΦ_r = @. lazy(phi_r(thermo_params, ᶜp))
76-
ᶜθ_v = @. lazy(theta_v(thermo_params, ᶜT, ᶜp, ᶜq_tot_safe, ᶜq_liq_rai, ᶜq_ice_sno))
76+
ᶜθ_v = p.scratch.ᶜtemp_scalar
77+
@. ᶜθ_v = theta_v(thermo_params, ᶜT, ᶜp, ᶜq_tot_safe, ᶜq_liq_rai, ᶜq_ice_sno)
7778
ᶜθ_vr = @. lazy(theta_vr(thermo_params, ᶜp))
7879
ᶜΠ = @. lazy(TD.exner_given_pressure(thermo_params, ᶜp))
7980
ᶜθ_v_diff = @. lazy(ᶜθ_v - ᶜθ_vr)

src/prognostic_equations/implicit/implicit_tendency.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,8 @@ function implicit_vertical_advection_tendency!(Yₜ, Y, p, t)
196196

197197
# This is equivalent to grad_v(Φ) + grad_v(p) / ρ
198198
ᶜΦ_r = @. lazy(phi_r(thermo_params, ᶜp))
199-
ᶜθ_v = @. lazy(theta_v(thermo_params, ᶜT, ᶜp, ᶜq_tot_safe, ᶜq_liq_rai, ᶜq_ice_sno))
199+
ᶜθ_v = p.scratch.ᶜtemp_scalar
200+
@. ᶜθ_v = theta_v(thermo_params, ᶜT, ᶜp, ᶜq_tot_safe, ᶜq_liq_rai, ᶜq_ice_sno)
200201
ᶜθ_vr = @. lazy(theta_vr(thermo_params, ᶜp))
201202
ᶜΠ = @. lazy(TD.exner_given_pressure(thermo_params, ᶜp))
202203
@. Yₜ.f.u₃ -= ᶠgradᵥ_ᶜΦ - ᶠgradᵥ(ᶜΦ_r) +

src/prognostic_equations/implicit/manual_sparse_jacobian.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ function update_jacobian!(alg::ManualSparseJacobian, cache, Y, p, dtγ, t)
479479
ᶠz = Fields.coordinate_field(Y.f).z
480480
zmax = z_max(axes(Y.f))
481481

482-
ᶜkappa_m = p.scratch.ᶜtemp_scalar
482+
ᶜkappa_m = p.scratch.ᶜtemp_scalar_2
483483
@. ᶜkappa_m =
484484
TD.gas_constant_air(thermo_params, ᶜq_tot_safe, ᶜq_liq_rai, ᶜq_ice_sno) /
485485
TD.cv_m(thermo_params, ᶜq_tot_safe, ᶜq_liq_rai, ᶜq_ice_sno)
@@ -533,7 +533,8 @@ function update_jacobian!(alg::ManualSparseJacobian, cache, Y, p, dtγ, t)
533533
∂ᶠu₃_err_∂ᶜρ = matrix[@name(f.u₃), @name(c.ρ)]
534534
∂ᶠu₃_err_∂ᶜρe_tot = matrix[@name(f.u₃), @name(c.ρe_tot)]
535535

536-
ᶜθ_v = @. lazy(theta_v(thermo_params, ᶜT, ᶜp, ᶜq_tot_safe, ᶜq_liq_rai, ᶜq_ice_sno))
536+
ᶜθ_v = p.scratch.ᶜtemp_scalar
537+
@. ᶜθ_v = theta_v(thermo_params, ᶜT, ᶜp, ᶜq_tot_safe, ᶜq_liq_rai, ᶜq_ice_sno)
537538
ᶜΠ = @. lazy(TD.exner_given_pressure(thermo_params, ᶜp))
538539
# In implicit tendency, we use the new pressure-gradient formulation (PGF) and gravitational acceleration:
539540
# grad(p) / ρ + grad(Φ) = cp_d * θ_v * grad(Π) + grad(Φ).
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
#=
2+
Minimal Working Example (MWE) to reproduce GPU issue with horizontal dynamics tendency.
3+
4+
This reproduces the issue on lines 82-88 of src/prognostic_equations/advection.jl:
5+
@. Yₜ.c.uₕ -= C12(
6+
gradₕ(ᶜK + ᶜΦ - ᶜΦ_r) +
7+
cp_d *
8+
(
9+
ᶜθ_v_diff * gradₕ(ᶜΠ) + gradₕ(ᶜθ_v_diff * ᶜΠ) - ᶜΠ * gradₕ(ᶜθ_v_diff)
10+
) / 2,
11+
)
12+
13+
The issue is that gradₕ is being called with lazy broadcast expressions
14+
which may not work properly on GPU.
15+
=#
16+
17+
using ClimaComms
18+
ClimaComms.@import_required_backends
19+
using ClimaCore
20+
using ClimaCore: Geometry, Spaces, Fields, Operators
21+
import ClimaAtmos: lazy
22+
import Thermodynamics as TD
23+
import ClimaParams as CP
24+
25+
# Automatically choose device (GPU if available, otherwise CPU)
26+
const device = ClimaComms.device()
27+
const context = ClimaComms.context(device)
28+
29+
# Float type
30+
const FT = Float64
31+
32+
# Import necessary submodules
33+
import ClimaCore.Domains as Domains
34+
import ClimaCore.Meshes as Meshes
35+
import ClimaCore.Topologies as Topologies
36+
import ClimaCore.Quadratures as Quadratures
37+
38+
#=
39+
Setup a simple spherical shell mesh with horizontal spectral element discretization
40+
and vertical finite difference discretization.
41+
=#
42+
function create_test_space(::Type{FT}; context) where {FT}
43+
# Horizontal mesh (cubed sphere)
44+
radius = FT(6.371e6) # Earth radius in meters
45+
h_elem = 4 # Number of horizontal elements per edge
46+
npoly = 3 # Polynomial degree
47+
48+
# Create horizontal domain
49+
h_domain = Domains.SphereDomain(radius)
50+
h_mesh = Meshes.EquiangularCubedSphere(h_domain, h_elem)
51+
h_topology = Topologies.Topology2D(context, h_mesh)
52+
quad = Quadratures.GLL{npoly + 1}()
53+
h_space = Spaces.SpectralElementSpace2D(h_topology, quad)
54+
55+
# Vertical mesh (finite difference)
56+
z_elem = 10 # Number of vertical levels
57+
z_min = FT(0)
58+
z_max = FT(30000) # 30 km domain height
59+
60+
z_domain = Domains.IntervalDomain(
61+
Geometry.ZPoint(z_min),
62+
Geometry.ZPoint(z_max);
63+
boundary_names = (:bottom, :top),
64+
)
65+
z_mesh = Meshes.IntervalMesh(z_domain; nelems = z_elem)
66+
z_topology = Topologies.IntervalTopology(context, z_mesh)
67+
68+
z_space_center = Spaces.CenterFiniteDifferenceSpace(z_topology)
69+
z_space_face = Spaces.FaceFiniteDifferenceSpace(z_topology)
70+
71+
# Create hybrid 3D spaces
72+
center_space = Spaces.ExtrudedFiniteDifferenceSpace(h_space, z_space_center)
73+
face_space = Spaces.FaceExtrudedFiniteDifferenceSpace(center_space)
74+
75+
return center_space, face_space
76+
end
77+
78+
#=
79+
Create the operator instances we need
80+
=#
81+
const gradₕ = Operators.Gradient()
82+
const C12 = Geometry.Covariant12Vector
83+
84+
#=
85+
Get thermodynamic parameters
86+
=#
87+
function get_thermo_params()
88+
toml_dict = CP.create_toml_dict(FT)
89+
return TD.Parameters.ThermodynamicsParameters(toml_dict)
90+
end
91+
92+
#=
93+
Simplified versions of the reference state functions from refstate_thermodynamics.jl
94+
=#
95+
function phi_r(thermo_params, p)
96+
cp_d = TD.Parameters.cp_d(thermo_params)
97+
T_min = TD.Parameters.T_min_ref(thermo_params)
98+
T_sfc = TD.Parameters.T_surf_ref(thermo_params)
99+
s_ref = 7
100+
101+
Π = TD.exner_given_pressure(thermo_params, p)
102+
return -cp_d * (T_min * log(Π) + (T_sfc - T_min) / s_ref *^s_ref - 1))
103+
end
104+
105+
function theta_v(thermo_params, T, p, q_tot, q_liq, q_ice)
106+
R_d = TD.Parameters.R_d(thermo_params)
107+
R_m = TD.gas_constant_air(thermo_params, TD.PhasePartition(q_tot, q_liq, q_ice))
108+
Π = TD.exner_given_pressure(thermo_params, p)
109+
return T * R_m /* R_d)
110+
end
111+
112+
function air_temperature_reference(thermo_params, p)
113+
T_min = TD.Parameters.T_min_ref(thermo_params)
114+
T_sfc = TD.Parameters.T_surf_ref(thermo_params)
115+
s_ref = 7
116+
Π = TD.exner_given_pressure(thermo_params, p)
117+
return T_min + (T_sfc - T_min) * Π^s_ref
118+
end
119+
120+
function theta_vr(thermo_params, p)
121+
T_r = air_temperature_reference(thermo_params, p)
122+
Π = TD.exner_given_pressure(thermo_params, p)
123+
return T_r / Π
124+
end
125+
126+
#=
127+
Main test function: lazy expressions with gradₕ (this is what advection.jl does)
128+
=#
129+
function test_horizontal_dynamics_with_lazy()
130+
# Create test spaces
131+
center_space, face_space = create_test_space(FT; context)
132+
133+
# Get thermodynamic parameters
134+
thermo_params = get_thermo_params()
135+
cp_d = TD.Parameters.cp_d(thermo_params)
136+
137+
# Create test fields on center space
138+
ᶜK = Fields.ones(FT, center_space) .* FT(100) # kinetic energy
139+
ᶜΦ = Fields.ones(FT, center_space) .* FT(1000) # geopotential
140+
ᶜp = Fields.ones(FT, center_space) .* FT(1e5) # pressure
141+
ᶜT = Fields.ones(FT, center_space) .* FT(280) # temperature
142+
ᶜq_tot_safe = Fields.ones(FT, center_space) .* FT(0.01)
143+
ᶜq_liq_rai = Fields.zeros(FT, center_space)
144+
ᶜq_ice_sno = Fields.zeros(FT, center_space)
145+
146+
# Create velocity tendency field (Covariant12Vector)
147+
Yₜ_uₕ = fill(Geometry.Covariant12Vector(FT(0), FT(0)), center_space)
148+
149+
# Compute the lazy expressions (as done in advection.jl lines 75-80)
150+
ᶜΦ_r = @. lazy(phi_r(thermo_params, ᶜp))
151+
ᶜθ_v = @. lazy(theta_v(thermo_params, ᶜT, ᶜp, ᶜq_tot_safe, ᶜq_liq_rai, ᶜq_ice_sno))
152+
ᶜθ_vr = @. lazy(theta_vr(thermo_params, ᶜp))
153+
ᶜΠ = @. lazy(TD.exner_given_pressure(thermo_params, ᶜp))
154+
ᶜθ_v_diff = @. lazy(ᶜθ_v - ᶜθ_vr)
155+
156+
# This is the problematic line (lines 82-88 in advection.jl)
157+
# split form pressure gradient: 0.5 * cp_d * [θv ∇Π + ∇(θv Π) - Π∇θv]
158+
@. Yₜ_uₕ -= C12(
159+
gradₕ(ᶜK + ᶜΦ - ᶜΦ_r) +
160+
cp_d *
161+
(
162+
ᶜθ_v_diff * gradₕ(ᶜΠ) + gradₕ(ᶜθ_v_diff * ᶜΠ) - ᶜΠ * gradₕ(ᶜθ_v_diff)
163+
) / 2,
164+
)
165+
166+
return nothing
167+
end
168+
169+
#=
170+
Alternative test: materialize intermediate fields first (potential workaround)
171+
=#
172+
function test_horizontal_dynamics_with_materialized()
173+
# Create test spaces
174+
center_space, face_space = create_test_space(FT; context)
175+
176+
# Get thermodynamic parameters
177+
thermo_params = get_thermo_params()
178+
cp_d = TD.Parameters.cp_d(thermo_params)
179+
180+
# Create test fields on center space
181+
ᶜK = Fields.ones(FT, center_space) .* FT(100)
182+
ᶜΦ = Fields.ones(FT, center_space) .* FT(1000)
183+
ᶜp = Fields.ones(FT, center_space) .* FT(1e5)
184+
ᶜT = Fields.ones(FT, center_space) .* FT(280)
185+
ᶜq_tot_safe = Fields.ones(FT, center_space) .* FT(0.01)
186+
ᶜq_liq_rai = Fields.zeros(FT, center_space)
187+
ᶜq_ice_sno = Fields.zeros(FT, center_space)
188+
189+
# Create velocity tendency field (Covariant12Vector)
190+
Yₜ_uₕ = fill(Geometry.Covariant12Vector(FT(0), FT(0)), center_space)
191+
192+
# Materialize intermediate fields instead of using lazy
193+
ᶜΦ_r = @. phi_r(thermo_params, ᶜp)
194+
ᶜθ_v = @. theta_v(thermo_params, ᶜT, ᶜp, ᶜq_tot_safe, ᶜq_liq_rai, ᶜq_ice_sno)
195+
ᶜθ_vr = @. theta_vr(thermo_params, ᶜp)
196+
ᶜΠ = @. TD.exner_given_pressure(thermo_params, ᶜp)
197+
ᶜθ_v_diff = @. ᶜθ_v - ᶜθ_vr
198+
199+
# Now use the materialized fields
200+
@. Yₜ_uₕ -= C12(
201+
gradₕ(ᶜK + ᶜΦ - ᶜΦ_r) +
202+
cp_d *
203+
(
204+
ᶜθ_v_diff * gradₕ(ᶜΠ) + gradₕ(ᶜθ_v_diff * ᶜΠ) - ᶜΠ * gradₕ(ᶜθ_v_diff)
205+
) / 2,
206+
)
207+
208+
return nothing
209+
end
210+
211+
#=
212+
Alternative test: materialize everything including gradₕ inputs
213+
=#
214+
function test_horizontal_dynamics_fully_materialized()
215+
# Create test spaces
216+
center_space, face_space = create_test_space(FT; context)
217+
218+
# Get thermodynamic parameters
219+
thermo_params = get_thermo_params()
220+
cp_d = TD.Parameters.cp_d(thermo_params)
221+
222+
# Create test fields on center space
223+
ᶜK = Fields.ones(FT, center_space) .* FT(100)
224+
ᶜΦ = Fields.ones(FT, center_space) .* FT(1000)
225+
ᶜp = Fields.ones(FT, center_space) .* FT(1e5)
226+
ᶜT = Fields.ones(FT, center_space) .* FT(280)
227+
ᶜq_tot_safe = Fields.ones(FT, center_space) .* FT(0.01)
228+
ᶜq_liq_rai = Fields.zeros(FT, center_space)
229+
ᶜq_ice_sno = Fields.zeros(FT, center_space)
230+
231+
# Create velocity tendency field (Covariant12Vector)
232+
Yₜ_uₕ = fill(Geometry.Covariant12Vector(FT(0), FT(0)), center_space)
233+
234+
# Materialize all intermediate fields
235+
ᶜΦ_r = @. phi_r(thermo_params, ᶜp)
236+
ᶜθ_v = @. theta_v(thermo_params, ᶜT, ᶜp, ᶜq_tot_safe, ᶜq_liq_rai, ᶜq_ice_sno)
237+
ᶜθ_vr = @. theta_vr(thermo_params, ᶜp)
238+
ᶜΠ = @. TD.exner_given_pressure(thermo_params, ᶜp)
239+
ᶜθ_v_diff = @. ᶜθ_v - ᶜθ_vr
240+
241+
# Also materialize the gradₕ inputs
242+
ᶜscalar_for_grad1 = @. ᶜK + ᶜΦ - ᶜΦ_r
243+
ᶜscalar_for_grad2 = @. ᶜθ_v_diff * ᶜΠ
244+
245+
# Use fully materialized fields
246+
@. Yₜ_uₕ -= C12(
247+
gradₕ(ᶜscalar_for_grad1) +
248+
cp_d *
249+
(
250+
ᶜθ_v_diff * gradₕ(ᶜΠ) + gradₕ(ᶜscalar_for_grad2) - ᶜΠ * gradₕ(ᶜθ_v_diff)
251+
) / 2,
252+
)
253+
254+
return nothing
255+
end
256+
257+
# Run the tests
258+
# Test 1: With lazy expressions (this is what advection.jl does)
259+
test_horizontal_dynamics_with_lazy()
260+
261+
# Test 2: With materialized intermediate fields
262+
test_horizontal_dynamics_with_materialized()
263+
264+
# Test 3: With fully materialized fields including gradₕ inputs
265+
test_horizontal_dynamics_fully_materialized()

0 commit comments

Comments
 (0)