Skip to content

Commit 1e9bbb8

Browse files
authored
Merge pull request #3975 from CliMA/as/update-pressure-ref
Update PGF + modify hyperdiffusion reference state.
2 parents 47166b3 + e92cd90 commit 1e9bbb8

File tree

11 files changed

+132
-65
lines changed

11 files changed

+132
-65
lines changed

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ ClimaAtmos.jl Release Notes
44
main
55
-------
66

7+
v0.31.5
8+
-------
9+
PR [#3975](https://github.com/CliMA/ClimaAtmos.jl/pull/3975) updates the pressure gradient formulation to subtract a reference state and use the Exner pressure.
10+
711
v0.31.4
812
-------
913

config/model_configs/box_hydrostatic_balance.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
t_end: "1days"
22
config: "box"
3-
hyperdiff: false
3+
hyperdiff: true
44
dt: "20secs"
55
perturb_initstate: false
66
disable_surface_flux_tendency: true

docs/src/equations.md

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -61,36 +61,32 @@ We make use of the following operators
6161
```math
6262
\boldsymbol{\Omega} = \Omega \sin(\phi) \boldsymbol{e}^v
6363
```
64-
where ``\phi`` is latitude, and ``\Omega`` is the planetary rotation rate in rads/sec (for Earth, ``7.29212 \times 10^{-5} s^{-1}``) and ``\boldsymbol{e}^v`` is the unit radial basis vector. This implies that the horizontal contravariant component ``\boldsymbol{\Omega}^h`` is zero.
64+
where ``\phi`` is latitude, and ``\Omega`` is the planetary rotation rate in rads/sec (for Earth, ``7.29212 \times 10^{-5} s^{-1}``) and ``\boldsymbol{e}^v`` is the unit radial basis vector. This implies that the horizontal contravariant component ``\boldsymbol{\Omega}^h`` is zero.
65+
6566
* a _deep atmosphere_, with
6667
```math
6768
\boldsymbol{\Omega} = (0, 0, \Omega)
6869
```
6970
i.e. aligned with Earth's rotational axis.
7071
* ``\tilde{\boldsymbol{u}}`` is the mass-weighted reconstruction of velocity at the interfaces:
7172
by interpolation of contravariant components
72-
```math
73-
\tilde{\boldsymbol{u}} = WI^f(\rho J, \boldsymbol{u}_h) + \boldsymbol{u}_v
73+
```math
74+
7475
```
7576
* ``\bar{\boldsymbol{u}}`` is the reconstruction of velocity at cell-centers, carried out by linear interpolation of the covariant vertical component:
7677
```math
7778
\bar{\boldsymbol{u}} = \boldsymbol{u}_h + I_{c}(\boldsymbol{u}_v)
7879
```
7980

8081
* ``\Phi = g z`` is the geopotential, where ``g`` is the gravitational acceleration rate and ``z`` is altitude above the mean sea level.
81-
* ``\boldsymbol{b}`` is the reduced gravitational acceleration
82-
```math
83-
\boldsymbol{b} = - \frac{\rho - \rho_{\text{ref}}}{\rho} \nabla \Phi
84-
```
85-
* ``\rho_{\text{ref}}`` is the reference state density
8682
* ``K = \tfrac{1}{2} \|\boldsymbol{u}\|^2 `` is the specific kinetic energy (J/kg), reconstructed at cell centers by
8783
```math
8884
K = \tfrac{1}{2} (\boldsymbol{u}_{h} \cdot \boldsymbol{u}_{h} + 2 \boldsymbol{u}_{h} \cdot I_{c} (\boldsymbol{u}_{v}) + I_{c}(\boldsymbol{u}_{v} \cdot \boldsymbol{u}_{v})),
8985
```
9086
where ``\boldsymbol{u}_{h}`` is defined on cell-centers, ``\boldsymbol{u}_{v}`` is defined on cell-faces, and ``I_{c} (\boldsymbol{u}_{v})`` is interpolated using covariant components.
9187

9288
* ``p`` is air pressure, derived from the thermodynamic state, reconstructed at cell centers.
93-
* ``p_{\text{ref}}`` is the reference state pressure. It is related to the reference state density by analytical hydrostatic balance: ``\nabla p_{\text{ref}} = - \rho_{\text{ref}} \nabla \Phi``.
89+
* ``\Pi = (\frac{p}{p_0})^{\frac{R_d}{c_{pd}}}`` is the Exner function evaluated with dry-air constants.
9490
* ``\boldsymbol{F}_R`` are the radiative fluxes: these are assumed to align vertically (i.e. the horizontal contravariant components are zero), and are constructed at cell faces from [RRTMGP.jl](https://github.com/CliMA/RRTMGP.jl).
9591

9692
* ``\nu_u``, ``\nu_h``, and ``\nu_\chi`` are hyperdiffusion coefficients, and ``c`` is the divergence damping factor.
@@ -126,20 +122,31 @@ term treated implicitly (check this)
126122

127123
Uses the advective form equation
128124
```math
129-
\frac{\partial}{\partial t} \boldsymbol{u} = - (2 \boldsymbol{\Omega} + \nabla \times \boldsymbol{u}) \times \boldsymbol{u} - \frac{1}{\rho} \nabla (p - p_{\text{ref}}) + \boldsymbol{b} - \nabla K
125+
\frac{\partial}{\partial t} \boldsymbol{u} = - (2 \boldsymbol{\Omega} + \nabla \times \boldsymbol{u}) \times \boldsymbol{u} - c_{pd} (\theta_v - \theta_{v, r}) \nabla_h \Pi - \nabla_h [(\Phi - \Phi_r) + K].
126+
```
127+
Here, we use the Exner function to compute pressure gradients and are subtracting a hydrostatic reference state
128+
```math
129+
- \frac{1}{\rho} \nabla p = - c_{pd} \theta_v \Pi
130+
```
131+
where ``\theta_v`` is the virtual potential temperature. ``\theta_{v,r} = T_r / \Pi`` is a reference virtual potential temperature (with reference temperature ``T_r``), and
132+
```math
133+
\Phi_r = -c_{pd} \left[ T_\text{min} \log(\Pi) + \frac{(T_\text{sfc} - T_\text{min})}{n_s} (\Pi^{n_s} - 1) \right],
130134
```
135+
is a reference geopotential, which satisfies the hydrostatic balance equation $c_{pd} \theta_{v,r} \nabla \Pi + \nabla \Phi_r = 0$ for any $\Pi$.
136+
We use the reference temperature profile ``T_r = T_\text{min} + (T_\text{sfc} - T_\text{min}) \Pi^{n_s}``, with constants ``T_\text{min} = 215\,K``, ``T_\text{sfc}= 288\,K``, and ``n_s = 7``.
131137

132138
#### Horizontal momentum
133139

134-
By breaking the curl and cross product terms into horizontal and vertical contributions, and removing zero terms (e.g. ``\nabla_v \times \boldsymbol{u}_v = 0``), we obtain
135-
140+
By breaking the curl and cross product terms into horizontal and vertical contributions, and removing zero terms (e.g. ``\nabla_v \times \boldsymbol{u}_v = 0``), we obtain
136141
```math
137142
\frac{\partial}{\partial t} \boldsymbol{u}_h =
138143
- (2 \boldsymbol{\Omega}^h + \nabla_v \times \boldsymbol{u}_h + \nabla_h \times \boldsymbol{u}_v) \times \boldsymbol{u}^v
139144
- (2 \boldsymbol{\Omega}^v + \nabla_h \times \boldsymbol{u}_h) \times \boldsymbol{u}^h
140-
- \frac{1}{\rho} \nabla_h (p - p_{\text{ref}}) - \nabla_h (\Phi + K),
145+
- c_{pd} (\theta_v - \theta_{v, r}) \nabla_h \Pi - \nabla_h [(\Phi - \Phi_r) + K],
141146
```
142-
where ``\boldsymbol{u}^h`` and ``\boldsymbol{u}^v`` are the horizontal and vertical _contravariant_ vectors. The effect of topography is accounted for through the computation of the contravariant velocity components (projections from the covariant velocity representation) prior to computing the cross-product contributions.
147+
where ``\boldsymbol{u}^h`` and ``\boldsymbol{u}^v`` are the horizontal and vertical _contravariant_ vectors.
148+
149+
The effect of topography is accounted for through the computation of the contravariant velocity components (projections from the covariant velocity representation) prior to computing the cross-product contributions.
143150

144151
This is stabilized with the addition of 4th-order vector hyperviscosity
145152
```math
@@ -163,9 +170,9 @@ The ``(2 \boldsymbol{\Omega}^v + \nabla_h \times \boldsymbol{u}_h) \times \bolds
163170
```math
164171
(2 \boldsymbol{\Omega}^v + \mathcal{C}_h[\boldsymbol{u}_h]) \times \boldsymbol{u}^h
165172
```
166-
and the ``\frac{1}{\rho} \nabla_h (p - p_h) + \nabla_h (\Phi + K)`` as
173+
and the ``c_{pd} (\theta_v - \theta_{v,r}) \nabla_h \Pi + \nabla_h (\Phi - \Phi_r + K)`` term is discretized as
167174
```math
168-
\frac{1}{\rho} \mathcal{G}_h[p - p_{\text{ref}}] + \mathcal{G}_h[\Phi + K] ,
175+
c_{pd} (\theta_v - \theta_{v,r}) \mathcal{G}_h[\Pi] + \mathcal{G}_h[\Phi - \Phi_r + K] ,
169176
```
170177
where all these terms are treated explicitly.
171178

@@ -183,18 +190,22 @@ Similarly for vertical velocity
183190
```math
184191
\frac{\partial}{\partial t} \boldsymbol{u}_v =
185192
- (2 \boldsymbol{\Omega}^h + \nabla_v \times \boldsymbol{u}_h + \nabla_h \times \boldsymbol{u}_v) \times \boldsymbol{u}^h
186-
- \frac{1}{\rho} \nabla_v (p - p_{\text{ref}}) - \frac{\rho - \rho_{\text{ref}}}{\rho} \nabla_v \Phi - \nabla_v K .
193+
-c_{pd} (\theta_v - \theta_{v, r}) \nabla_v \Pi - \nabla_v [(\Phi - \Phi_r)].
187194
```
188195

189196
The ``(2 \boldsymbol{\Omega}^h + \nabla_v \times \boldsymbol{u}_h + \nabla_h \times \boldsymbol{u}_v) \times \boldsymbol{u}^h`` term is discretized as
190197
```math
191198
(2 \boldsymbol{\Omega}^h + \mathcal{C}^f_v[\boldsymbol{u}_h] + \mathcal{C}_h[\boldsymbol{u}_v]) \times I^f(\boldsymbol{u}^h) ,
192199
```
193-
and the ``\frac{1}{\rho} \nabla_v (p - p_{\text{ref}}) - \frac{\rho - \rho_{\text{ref}}}{\rho} \nabla_v \Phi - \nabla_v K`` term as
200+
The ``\nabla_v K`` term is discretized as
201+
```math
202+
\mathcal{G}^f_v[K],
203+
```
204+
The ``c_{pd} (\theta_v - \theta_{v,r}) \nabla_v \Pi + \nabla_v (\Phi - \Phi_r)`` term is discretized as
194205
```math
195-
\frac{1}{I^f(\rho)} \mathcal{G}^f_v[p - p_{\text{ref}}] - \frac{I^f(\rho - \rho_{\text{ref}})}{I^f(\rho)} \mathcal{G}^f_v[\Phi] - \mathcal{G}^f_v[K] ,
206+
I^f[c_{pd} (\theta_v - \theta_{v, r} ) ] \mathcal{G}^f_v[\Pi] - \mathcal{G}^f_v[\Phi - \Phi_r],
196207
```
197-
with the latter treated implicitly.
208+
and is treated implicitly.
198209

199210
This is stabilized with the addition of 4th-order vector hyperviscosity
200211
```math

reproducibility_tests/ref_counter.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
266
1+
267
22

33
# **README**
44
#
@@ -20,6 +20,10 @@
2020

2121

2222
#=
23+
267
24+
- Changed the pressure-gradient formulation to use the Exner function
25+
and virtual potential temperature.
26+
2327
266
2428
- No behavior change, but some new diagnostics are added, and the reference
2529
simulations don't have those diagnostics for plotting

src/ClimaAtmos.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ include(joinpath("cache", "surface_albedo.jl"))
4747
include(joinpath("initial_conditions", "InitialConditions.jl"))
4848
include(joinpath("surface_conditions", "SurfaceConditions.jl"))
4949
include(joinpath("utils", "discrete_hydrostatic_balance.jl"))
50+
include(joinpath("utils", "refstate_thermodynamics.jl"))
5051

5152
include(joinpath("prognostic_equations", "pressure_work.jl"))
5253
include(joinpath("prognostic_equations", "zero_velocity.jl"))

src/cache/cache.jl

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -129,42 +129,6 @@ function build_cache(
129129
sfc_local_geometry =
130130
Fields.level(Fields.local_geometry_field(Y.f), Fields.half)
131131

132-
# Reference enthalpy for hyperdiffusion computation
133-
ᶜz = Fields.coordinate_field(Y.c).z
134-
T_ref = similar(ᶜz)
135-
p_ref = similar(ᶜz)
136-
q_tot_ref = similar(ᶜz)
137-
cv_m = similar(ᶜz)
138-
thermo_params = CAP.thermodynamics_params(params)
139-
decay_scale_height = FT(8000)
140-
141-
# Reference State
142-
temp_profile = TD.TemperatureProfiles.DecayingTemperatureProfile{FT}(
143-
thermo_params,
144-
FT(300), # surface temperature
145-
FT(220), # top temperature
146-
decay_scale_height, # decay height scale
147-
)
148-
149-
rel_hum_ref =
150-
atmos.moisture_model isa DryModel ? FT(0) :
151-
@. FT(0.5) * exp(- ᶜz / decay_scale_height)
152-
153-
T_0 = CAP.T_0(params)
154-
grav = CAP.grav(params)
155-
@. T_ref = first(temp_profile(thermo_params, ᶜz))
156-
@. p_ref = last(temp_profile(thermo_params, ᶜz))
157-
@. q_tot_ref =
158-
TD.q_vap_from_RH_liquid(thermo_params, p_ref, T_ref, rel_hum_ref)
159-
@. cv_m = TD.cv_m(thermo_params, TD.PhasePartition(q_tot_ref, FT(0), FT(0)))
160-
161-
ᶜh_ref = @. TD.total_specific_enthalpy(
162-
thermo_params,
163-
cv_m * (T_ref - T_0) + grav * ᶜz,
164-
T_ref,
165-
TD.PhasePartition(q_tot_ref, FT(0), FT(0)),
166-
)
167-
168132
core = (
169133
ᶜΦ,
170134
ᶠgradᵥ_ᶜΦ = ᶠgradᵥ.(ᶜΦ),
@@ -175,7 +139,6 @@ function build_cache(
175139
surface_ct3_unit = CT3.(
176140
unit_basis_vector_data.(CT3, sfc_local_geometry)
177141
),
178-
ᶜh_ref,
179142
)
180143
external_forcing = external_forcing_cache(Y, atmos, params, start_date)
181144
sfc_setup = surface_setup(params)

src/prognostic_equations/advection.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ NVTX.@annotate function horizontal_dynamics_tendency!(Yₜ, Y, p, t)
3939
(; ᶜu, ᶜK, ᶜp, ᶜts) = p.precomputed
4040
(; params) = p
4141
thermo_params = CAP.thermodynamics_params(params)
42+
cp_d = thermo_params.cp_d
4243

4344
if p.atmos.turbconv_model isa PrognosticEDMFX
4445
(; ᶜuʲs) = p.precomputed
@@ -82,7 +83,12 @@ NVTX.@annotate function horizontal_dynamics_tendency!(Yₜ, Y, p, t)
8283

8384
end
8485

85-
@. Yₜ.c.uₕ -= C12(gradₕ(ᶜp) / Y.c.ρ + gradₕ(ᶜK + ᶜΦ))
86+
# This is equivalent to grad_h(Φ + K) + grad_h(p) / ρ
87+
ᶜΦ_r = @. lazy(phi_r(thermo_params, ᶜts))
88+
ᶜθ_v = @. lazy(theta_v(thermo_params, ᶜts))
89+
ᶜθ_vr = @. lazy(theta_vr(thermo_params, ᶜts))
90+
ᶜΠ = @. lazy(dry_exner_function(thermo_params, ᶜts))
91+
@. Yₜ.c.uₕ -= C12(gradₕ(ᶜK + ᶜΦ - ᶜΦ_r) + cp_d * (ᶜθ_v - ᶜθ_vr) * gradₕ(ᶜΠ))
8692
# Without the C12(), the right-hand side would be a C1 or C2 in 2D space.
8793
return nothing
8894
end

src/prognostic_equations/hyperdiffusion.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,16 @@ end
106106
# dss_hyperdiffusion_tendency_pairs
107107
NVTX.@annotate function prep_hyperdiffusion_tendency!(Yₜ, Y, p, t)
108108
(; hyperdiff, turbconv_model) = p.atmos
109+
(; params) = p
110+
(; ᶜΦ) = p.core
111+
(; ᶜts) = p.precomputed
112+
thermo_params = CAP.thermodynamics_params(params)
113+
109114
isnothing(hyperdiff) && return nothing
110115

111116
n = n_mass_flux_subdomains(turbconv_model)
112117
diffuse_tke = use_prognostic_tke(turbconv_model)
113118
(; ᶜp) = p.precomputed
114-
(; ᶜh_ref) = p.core
115119
(; ᶜ∇²u, ᶜ∇²specific_energy) = p.hyperdiff
116120
if turbconv_model isa PrognosticEDMFX
117121
(; ᶜ∇²uₕʲs, ᶜ∇²uᵥʲs, ᶜ∇²uʲs, ᶜ∇²mseʲs) = p.hyperdiff
@@ -122,6 +126,8 @@ NVTX.@annotate function prep_hyperdiffusion_tendency!(Yₜ, Y, p, t)
122126
C123(wgradₕ(divₕ(p.precomputed.ᶜu))) -
123127
C123(wcurlₕ(C123(curlₕ(p.precomputed.ᶜu))))
124128

129+
ᶜh_ref = @. lazy(h_dr(thermo_params, ᶜts, ᶜΦ))
130+
125131
@. ᶜ∇²specific_energy =
126132
wdivₕ(gradₕ(specific(Y.c.ρe_tot, Y.c.ρ) + ᶜp / Y.c.ρ - ᶜh_ref))
127133

src/prognostic_equations/implicit/implicit_tendency.jl

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,14 @@ vertical_advection(ᶠu³, ᶜχ, ::Val{:third_order}) =
151151
function implicit_vertical_advection_tendency!(Yₜ, Y, p, t)
152152
(; moisture_model, turbconv_model, rayleigh_sponge, microphysics_model) =
153153
p.atmos
154-
(; dt) = p
154+
(; params, dt) = p
155155
n = n_mass_flux_subdomains(turbconv_model)
156156
ᶜJ = Fields.local_geometry_field(axes(Y.c)).J
157157
ᶠJ = Fields.local_geometry_field(axes(Y.f)).J
158158
(; ᶠgradᵥ_ᶜΦ) = p.core
159159
(; ᶠu³, ᶜp, ᶜts) = p.precomputed
160-
thermo_params = CAP.thermodynamics_params(p.params)
160+
thermo_params = CAP.thermodynamics_params(params)
161+
cp_d = CAP.cp_d(params)
161162
ᶜh_tot = @. lazy(
162163
TD.total_specific_enthalpy(
163164
thermo_params,
@@ -245,7 +246,13 @@ function implicit_vertical_advection_tendency!(Yₜ, Y, p, t)
245246
# TODO - decide if this needs to be explicit or implicit
246247
#vertical_advection_of_water_tendency!(Yₜ, Y, p, t)
247248

248-
@. Yₜ.f.u₃ -= ᶠgradᵥ(ᶜp) / ᶠinterp(Y.c.ρ) + ᶠgradᵥ_ᶜΦ
249+
# This is equivalent to grad_v(Φ) + grad_v(p) / ρ
250+
ᶜΦ_r = @. lazy(phi_r(thermo_params, ᶜts))
251+
ᶜθ_v = @. lazy(theta_v(thermo_params, ᶜts))
252+
ᶜθ_vr = @. lazy(theta_vr(thermo_params, ᶜts))
253+
ᶜΠ = @. lazy(dry_exner_function(thermo_params, ᶜts))
254+
@. Yₜ.f.u₃ -= ᶠgradᵥ_ᶜΦ - ᶠgradᵥ(ᶜΦ_r) +
255+
cp_d * (ᶠinterp(ᶜθ_v - ᶜθ_vr)) * ᶠgradᵥ(ᶜΠ)
249256

250257
if rayleigh_sponge isa RayleighSponge
251258
ᶠz = Fields.coordinate_field(Y.f).z

src/prognostic_equations/implicit/manual_sparse_jacobian.jl

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,11 +462,20 @@ function update_jacobian!(alg::ManualSparseJacobian, cache, Y, p, dtγ, t)
462462

463463
∂ᶠu₃_err_∂ᶜρ = matrix[@name(f.u₃), @name(c.ρ)]
464464
∂ᶠu₃_err_∂ᶜρe_tot = matrix[@name(f.u₃), @name(c.ρe_tot)]
465+
466+
ᶜθ_v = @. lazy(theta_v(thermo_params, ᶜts))
467+
ᶜΠ = @. lazy(dry_exner_function(thermo_params, ᶜts))
468+
# In implicit tendency, we use the new pressure-gradient formulation (PGF) and gravitational acceleration:
469+
# grad(p) / ρ + grad(Φ) = cp_d * θ_v * grad(Π) + grad(Φ).
470+
# Here below, we use the old formulation of (grad(Φ) + grad(p) / ρ).
471+
# This is because the new formulation would require computing the derivative of θ_v.
472+
# The only exception is:
473+
# We are rewriting grad(p) / ρ from the expansion of ∂ᶠu₃_err_∂ᶜρ with the new PGF.
465474
@. ∂ᶠu₃_err_∂ᶜρ =
466475
dtγ * (
467476
ᶠp_grad_matrix
468477
DiagonalMatrixRow(ᶜkappa_m * (T_0 * cp_d - ᶜK - ᶜΦ)) +
469-
DiagonalMatrixRow(ᶠgradᵥ(ᶜp) / abs2(ᶠinterp(ᶜρ)))
478+
DiagonalMatrixRow(cp_d * ᶠinterp(ᶜθ_v) * ᶠgradᵥ(ᶜΠ) / ᶠinterp(ᶜρ))
470479
ᶠinterp_matrix()
471480
)
472481
@. ∂ᶠu₃_err_∂ᶜρe_tot = dtγ * ᶠp_grad_matrix DiagonalMatrixRow(ᶜkappa_m)

0 commit comments

Comments
 (0)