Skip to content

Commit 6346a93

Browse files
Merge pull request #3584 from CliMA/dy/face_density
Change density on cell faces to match dycore paper
2 parents a10f2d7 + bc3a361 commit 6346a93

File tree

6 files changed

+73
-51
lines changed

6 files changed

+73
-51
lines changed

NEWS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ If `netcdf_interpolation_num_points` is not provided, `ClimaAtmos` will
1212
determine it automatically by matching approximately the same number of points
1313
as the model grid.
1414

15+
### Change reconstruction of density on cell faces for stretched grids
16+
17+
PR [3584](https://github.com/CliMA/ClimaAtmos.jl/pull/3584) changes the weighted
18+
interpolation of density from centers to faces so that it uses `ᶜJ` and `ᶠJ`,
19+
rather than `ᶜJ` and `ᶠint(ᶜJ)`. As of ClimaCore v0.14.25, `ᶠJ` is no longer
20+
equivalent to `ᶠint(ᶜJ)` for stretched grids.
21+
1522
v0.28.5
1623
-------
1724

reproducibility_tests/ref_counter.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
216
1+
217
22

33
# **README**
44
#
@@ -21,6 +21,9 @@
2121

2222
#=
2323
24+
217
25+
- Change reconstruction of density on cell faces
26+
2427
216
2528
- Change prescribed aerosols in `aquaplanet_nonequil_allsky_gw_res.yml`
2629

src/parameterized_tendencies/microphysics/precipitation.jl

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -325,30 +325,31 @@ function compute_precipitation_surface_fluxes!(
325325
(; surface_rain_flux, surface_snow_flux) = p.precipitation
326326
(; col_integrated_precip_energy_tendency,) = p.conservation_check
327327
(; ᶜwᵣ, ᶜwₛ, ᶜspecific) = p.precomputed
328-
329-
(; ᶠtemp_scalar) = p.scratch
330-
slg = Fields.level(Fields.local_geometry_field(ᶠtemp_scalar), Fields.half)
331-
332-
# Constant extrapolation: - put values from bottom cell center to bottom cell face
333-
ˢρ = Fields.Field(Fields.field_values(Fields.level(Y.c.ρ, 1)), axes(slg))
334-
# For density this is equivalent with ᶠwinterp(ᶜJ, Y.c.ρ) and therefore
335-
# consistent with the way we do vertical advection
336-
ˢqᵣ = Fields.Field(
328+
ᶜJ = Fields.local_geometry_field(Y.c).J
329+
ᶠJ = Fields.local_geometry_field(Y.f).J
330+
sfc_J = Fields.level(ᶠJ, Fields.half)
331+
sfc_space = axes(sfc_J)
332+
333+
# Jacobian-weighted extrapolation from interior to surface, consistent with
334+
# the reconstruction of density on cell faces, ᶠρ = ᶠinterp(Y.c.ρ * ᶜJ) / ᶠJ
335+
int_J = Fields.Field(Fields.field_values(Fields.level(ᶜJ, 1)), sfc_space)
336+
int_ρ = Fields.Field(Fields.field_values(Fields.level(Y.c.ρ, 1)), sfc_space)
337+
sfc_ρ = @. lazy(int_ρ * int_J / sfc_J)
338+
339+
# Constant extrapolation to surface, consistent with simple downwinding
340+
sfc_qᵣ = Fields.Field(
337341
Fields.field_values(Fields.level(ᶜspecific.q_rai, 1)),
338-
axes(slg),
342+
sfc_space,
339343
)
340-
ˢqₛ = Fields.Field(
344+
sfc_qₛ = Fields.Field(
341345
Fields.field_values(Fields.level(ᶜspecific.q_sno, 1)),
342-
axes(slg),
346+
sfc_space,
343347
)
344-
ˢwᵣ = Fields.Field(Fields.field_values(Fields.level(ᶜwᵣ, 1)), axes(slg))
345-
ˢwₛ = Fields.Field(Fields.field_values(Fields.level(ᶜwₛ, 1)), axes(slg))
346-
347-
# Project the flux to CT3 vector and convert to physical units.
348-
@. surface_rain_flux =
349-
-projected_vector_data(CT3, ˢρ * ˢqᵣ * Geometry.WVector(ˢwᵣ), slg)
350-
@. surface_snow_flux =
351-
-projected_vector_data(CT3, ˢρ * ˢqₛ * Geometry.WVector(ˢwₛ), slg)
348+
sfc_wᵣ = Fields.Field(Fields.field_values(Fields.level(ᶜwᵣ, 1)), sfc_space)
349+
sfc_wₛ = Fields.Field(Fields.field_values(Fields.level(ᶜwₛ, 1)), sfc_space)
350+
351+
@. surface_rain_flux = sfc_ρ * sfc_qᵣ * (-sfc_wᵣ)
352+
@. surface_snow_flux = sfc_ρ * sfc_qₛ * (-sfc_wₛ)
352353
end
353354

354355
function precipitation_tendency!(

src/prognostic_equations/implicit/implicit_solver.jl

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
560560
ᶜuₕ = Y.c.uₕ
561561
ᶠu₃ = Y.f.u₃
562562
ᶜJ = Fields.local_geometry_field(Y.c).J
563+
ᶠJ = Fields.local_geometry_field(Y.f).J
563564
ᶜgⁱʲ = Fields.local_geometry_field(Y.c).gⁱʲ
564565
ᶠgⁱʲ = Fields.local_geometry_field(Y.f).gⁱʲ
565566

@@ -581,7 +582,7 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
581582
@. ᶠp_grad_matrix = DiagonalMatrixRow(-1 / ᶠinterp(ᶜρ)) ᶠgradᵥ_matrix()
582583

583584
@. ᶜadvection_matrix =
584-
-(ᶜadvdivᵥ_matrix()) DiagonalMatrixRow(ᶠwinterp(ᶜJ, ᶜρ))
585+
-(ᶜadvdivᵥ_matrix()) DiagonalMatrixRow(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ)
585586

586587
if use_derivative(topography_flag)
587588
∂ᶜρ_err_∂ᶜuₕ = matrix[@name(c.ρ), @name(c.uₕ)]
@@ -663,7 +664,7 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
663664
#TODO: tetsing explicit vs implicit
664665
#@. ∂ᶜρe_tot_err_∂ᶜρe_tot +=
665666
# dtγ * -(ᶜprecipdivᵥ_matrix()) ⋅
666-
# DiagonalMatrixRow(ᶠwinterp(ᶜJ, ᶜρ)) ⋅ ᶠright_bias_matrix() ⋅
667+
# DiagonalMatrixRow(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ) ⋅ ᶠright_bias_matrix() ⋅
667668
# DiagonalMatrixRow(
668669
# -(1 + ᶜkappa_m) / ᶜρ * ifelse(
669670
# ᶜh_tot == 0,
@@ -677,7 +678,7 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
677678
#TODO: tetsing explicit vs implicit
678679
#@. ∂ᶜρe_tot_err_∂ᶜρq_tot =
679680
# dtγ * -(ᶜprecipdivᵥ_matrix()) ⋅
680-
# DiagonalMatrixRow(ᶠwinterp(ᶜJ, ᶜρ)) ⋅ ᶠright_bias_matrix() ⋅
681+
# DiagonalMatrixRow(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ) ⋅ ᶠright_bias_matrix() ⋅
681682
# DiagonalMatrixRow(
682683
# -(ᶜkappa_m) * ∂e_int_∂q_tot / ᶜρ * ifelse(
683684
# ᶜh_tot == 0,
@@ -691,7 +692,7 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
691692
#TODO: tetsing explicit vs implicit
692693
#@. ∂ᶜρq_tot_err_∂ᶜρq_tot =
693694
# dtγ * -(ᶜprecipdivᵥ_matrix()) ⋅
694-
# DiagonalMatrixRow(ᶠwinterp(ᶜJ, ᶜρ)) ⋅ ᶠright_bias_matrix() ⋅
695+
# DiagonalMatrixRow(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ) ⋅ ᶠright_bias_matrix() ⋅
695696
# DiagonalMatrixRow(
696697
# -1 / ᶜρ * ifelse(
697698
# ᶜspecific.q_tot == 0,
@@ -706,7 +707,8 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
706707
ᶜwₚ = MatrixFields.get_field(p, wₚ_name)
707708
@. ∂ᶜρqₚ_err_∂ᶜρqₚ =
708709
dtγ * -(ᶜprecipdivᵥ_matrix())
709-
DiagonalMatrixRow(ᶠwinterp(ᶜJ, ᶜρ)) ᶠright_bias_matrix()
710+
DiagonalMatrixRow(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ)
711+
ᶠright_bias_matrix()
710712
DiagonalMatrixRow(-Geometry.WVector(ᶜwₚ) / ᶜρ) - (I,)
711713
end
712714

@@ -881,13 +883,13 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
881883
ᶠu³ʲs.:(1),
882884
draft_area(Y.c.sgsʲs.:(1).ρa, ᶜρʲs.:(1)),
883885
),
884-
),
885-
) ᶠwinterp_matrix(ᶜJ) DiagonalMatrixRow(
886-
ᶜkappa_mʲ * (ᶜρʲs.:(1))^2 / ((ᶜkappa_mʲ + 1) * ᶜp) *
886+
) / ᶠJ,
887+
) ᶠinterp_matrix() DiagonalMatrixRow(
888+
ᶜJ * ᶜkappa_mʲ * (ᶜρʲs.:(1))^2 / ((ᶜkappa_mʲ + 1) * ᶜp) *
887889
∂e_int_∂q_tot,
888890
)
889891
@. ᶠbidiagonal_matrix_ct3_2 =
890-
DiagonalMatrixRow(ᶠwinterp(ᶜJ, ᶜρʲs.:(1)))
892+
DiagonalMatrixRow(ᶠinterp(ᶜρʲs.:(1) * ᶜJ) / ᶠJ)
891893
ᶠset_upwind_matrix_bcs(ᶠupwind_matrix(ᶠu³ʲs.:(1)))
892894
DiagonalMatrixRow(
893895
Y.c.sgsʲs.:(1).ρa * ᶜkappa_mʲ / ((ᶜkappa_mʲ + 1) * ᶜp) *
@@ -906,12 +908,12 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
906908
ᶠu³ʲs.:(1),
907909
draft_area(Y.c.sgsʲs.:(1).ρa, ᶜρʲs.:(1)),
908910
),
909-
),
910-
) ᶠwinterp_matrix(ᶜJ) DiagonalMatrixRow(
911-
ᶜkappa_mʲ * (ᶜρʲs.:(1))^2 / ((ᶜkappa_mʲ + 1) * ᶜp),
911+
) / ᶠJ,
912+
) ᶠinterp_matrix() DiagonalMatrixRow(
913+
ᶜJ * ᶜkappa_mʲ * (ᶜρʲs.:(1))^2 / ((ᶜkappa_mʲ + 1) * ᶜp),
912914
)
913915
@. ᶠbidiagonal_matrix_ct3_2 =
914-
DiagonalMatrixRow(ᶠwinterp(ᶜJ, ᶜρʲs.:(1)))
916+
DiagonalMatrixRow(ᶠinterp(ᶜρʲs.:(1) * ᶜJ) / ᶠJ)
915917
ᶠset_upwind_matrix_bcs(ᶠupwind_matrix(ᶠu³ʲs.:(1)))
916918
DiagonalMatrixRow(
917919
Y.c.sgsʲs.:(1).ρa * ᶜkappa_mʲ / ((ᶜkappa_mʲ + 1) * ᶜp),
@@ -923,7 +925,7 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
923925
matrix[@name(c.sgsʲs.:(1).ρa), @name(c.sgsʲs.:(1).ρa)]
924926
@. ᶜadvection_matrix =
925927
-(ᶜadvdivᵥ_matrix())
926-
DiagonalMatrixRow(ᶠwinterp(ᶜJ, ᶜρʲs.:(1)))
928+
DiagonalMatrixRow(ᶠinterp(ᶜρʲs.:(1) * ᶜJ) / ᶠJ)
927929
@. ∂ᶜρaʲ_err_∂ᶜρaʲ =
928930
dtγ * ᶜadvection_matrix
929931
ᶠset_upwind_matrix_bcs(ᶠupwind_matrix(ᶠu³ʲs.:(1)))

src/prognostic_equations/implicit/implicit_tendency.jl

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -54,48 +54,54 @@ end
5454

5555
function vertical_transport(ᶜρ, ᶠu³, ᶜχ, dt, ::Val{:none})
5656
ᶜJ = Fields.local_geometry_field(ᶜρ).J
57-
return @. lazy(-(ᶜadvdivᵥ(ᶠwinterp(ᶜJ, ᶜρ) * ᶠu³ * ᶠinterp(ᶜχ))))
57+
ᶠJ = Fields.local_geometry_field(ᶠu³).J
58+
return @. lazy(-(ᶜadvdivᵥ(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ * ᶠu³ * ᶠinterp(ᶜχ))))
5859
end
5960
function vertical_transport(ᶜρ, ᶠu³, ᶜχ, dt, ::Val{:first_order})
6061
ᶜJ = Fields.local_geometry_field(ᶜρ).J
61-
return @. lazy(-(ᶜadvdivᵥ(ᶠwinterp(ᶜJ, ᶜρ) * ᶠupwind1(ᶠu³, ᶜχ))))
62+
ᶠJ = Fields.local_geometry_field(ᶠu³).J
63+
return @. lazy(-(ᶜadvdivᵥ(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ * ᶠupwind1(ᶠu³, ᶜχ))))
6264
end
6365
@static if pkgversion(ClimaCore) v"0.14.22"
6466
function vertical_transport(ᶜρ, ᶠu³, ᶜχ, dt, ::Val{:vanleer_limiter})
6567
ᶜJ = Fields.local_geometry_field(ᶜρ).J
68+
ᶠJ = Fields.local_geometry_field(ᶠu³).J
6669
return @. lazy(
67-
-(ᶜadvdivᵥ(ᶠwinterp(ᶜJ, ᶜρ) * ᶠlin_vanleer(ᶠu³, ᶜχ, dt))),
70+
-(ᶜadvdivᵥ(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ * ᶠlin_vanleer(ᶠu³, ᶜχ, dt))),
6871
)
6972
end
7073
end
7174
function vertical_transport(ᶜρ, ᶠu³, ᶜχ, dt, ::Val{:third_order})
7275
ᶜJ = Fields.local_geometry_field(ᶜρ).J
73-
return @. lazy(-(ᶜadvdivᵥ(ᶠwinterp(ᶜJ, ᶜρ) * ᶠupwind3(ᶠu³, ᶜχ))))
76+
ᶠJ = Fields.local_geometry_field(ᶠu³).J
77+
return @. lazy(-(ᶜadvdivᵥ(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ * ᶠupwind3(ᶠu³, ᶜχ))))
7478
end
7579
function vertical_transport(ᶜρ, ᶠu³, ᶜχ, dt, ::Val{:boris_book})
7680
ᶜJ = Fields.local_geometry_field(ᶜρ).J
81+
ᶠJ = Fields.local_geometry_field(ᶠu³).J
7782
return @. lazy(
7883
-(ᶜadvdivᵥ(
79-
ᶠwinterp(ᶜJ, ᶜρ) * (
84+
ᶠinterp(ᶜρ * ᶜJ) / ᶠJ * (
8085
ᶠupwind1(ᶠu³, ᶜχ) + ᶠfct_boris_book(
8186
ᶠupwind3(ᶠu³, ᶜχ) - ᶠupwind1(ᶠu³, ᶜχ),
8287
ᶜχ / dt -
83-
ᶜadvdivᵥ(ᶠwinterp(ᶜJ, ᶜρ) * ᶠupwind1(ᶠu³, ᶜχ)) / ᶜρ,
88+
ᶜadvdivᵥ(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ * ᶠupwind1(ᶠu³, ᶜχ)) / ᶜρ,
8489
)
8590
),
8691
)),
8792
)
8893
end
8994
function vertical_transport(ᶜρ, ᶠu³, ᶜχ, dt, ::Val{:zalesak})
9095
ᶜJ = Fields.local_geometry_field(ᶜρ).J
96+
ᶠJ = Fields.local_geometry_field(ᶠu³).J
9197
return @. lazy(
9298
-(ᶜadvdivᵥ(
93-
ᶠwinterp(ᶜJ, ᶜρ) * (
99+
ᶠinterp(ᶜρ * ᶜJ) / ᶠJ * (
94100
ᶠupwind1(ᶠu³, ᶜχ) + ᶠfct_zalesak(
95101
ᶠupwind3(ᶠu³, ᶜχ) - ᶠupwind1(ᶠu³, ᶜχ),
96102
ᶜχ / dt,
97103
ᶜχ / dt -
98-
ᶜadvdivᵥ(ᶠwinterp(ᶜJ, ᶜρ) * ᶠupwind1(ᶠu³, ᶜχ)) / ᶜρ,
104+
ᶜadvdivᵥ(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ * ᶠupwind1(ᶠu³, ᶜχ)) / ᶜρ,
99105
)
100106
),
101107
)),
@@ -114,10 +120,11 @@ function implicit_vertical_advection_tendency!(Yₜ, Y, p, t)
114120
(; dt) = p
115121
n = n_mass_flux_subdomains(turbconv_model)
116122
ᶜJ = Fields.local_geometry_field(Y.c).J
123+
ᶠJ = Fields.local_geometry_field(Y.f).J
117124
(; ᶠgradᵥ_ᶜΦ) = p.core
118125
(; ᶜh_tot, ᶜspecific, ᶠu³, ᶜp) = p.precomputed
119126

120-
@. Yₜ.c.ρ -= ᶜdivᵥ(ᶠwinterp(ᶜJ, Y.c.ρ) * ᶠu³)
127+
@. Yₜ.c.ρ -= ᶜdivᵥ(ᶠinterp(Y.c.ρ * ᶜJ) / ᶠJ * ᶠu³)
121128

122129
# Central advection of active tracers (e_tot and q_tot)
123130
vtt = vertical_transport(Y.c.ρ, ᶠu³, ᶜh_tot, dt, Val(:none))
@@ -133,11 +140,11 @@ function implicit_vertical_advection_tendency!(Yₜ, Y, p, t)
133140
if moisture_model isa NonEquilMoistModel
134141
(; ᶜwₗ, ᶜwᵢ) = p.precomputed
135142
@. Yₜ.c.ρq_liq -= ᶜprecipdivᵥ(
136-
ᶠwinterp(ᶜJ, Y.c.ρ) *
143+
ᶠinterp(Y.c.ρ * ᶜJ) / ᶠJ *
137144
ᶠright_bias(Geometry.WVector(-(ᶜwₗ)) * ᶜspecific.q_liq),
138145
)
139146
@. Yₜ.c.ρq_ice -= ᶜprecipdivᵥ(
140-
ᶠwinterp(ᶜJ, Y.c.ρ) *
147+
ᶠinterp(Y.c.ρ * ᶜJ) / ᶠJ *
141148
ᶠright_bias(Geometry.WVector(-(ᶜwᵢ)) * ᶜspecific.q_ice),
142149
)
143150
end
@@ -149,11 +156,11 @@ function implicit_vertical_advection_tendency!(Yₜ, Y, p, t)
149156
# using downward biasing and free outflow bottom boundary condition
150157
(; ᶜwᵣ, ᶜwₛ) = p.precomputed
151158
@. Yₜ.c.ρq_rai -= ᶜprecipdivᵥ(
152-
ᶠwinterp(ᶜJ, Y.c.ρ) *
159+
ᶠinterp(Y.c.ρ * ᶜJ) / ᶠJ *
153160
ᶠright_bias(Geometry.WVector(-(ᶜwᵣ)) * ᶜspecific.q_rai),
154161
)
155162
@. Yₜ.c.ρq_sno -= ᶜprecipdivᵥ(
156-
ᶠwinterp(ᶜJ, Y.c.ρ) *
163+
ᶠinterp(Y.c.ρ * ᶜJ) / ᶠJ *
157164
ᶠright_bias(Geometry.WVector(-(ᶜwₛ)) * ᶜspecific.q_sno),
158165
)
159166
end

src/prognostic_equations/water_advection.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ import ClimaCore: Fields
33
function vertical_advection_of_water_tendency!(Yₜ, Y, p, t)
44

55
ᶜJ = Fields.local_geometry_field(Y.c).J
6+
ᶠJ = Fields.local_geometry_field(Y.f).J
67
(; ᶜwₜqₜ, ᶜwₕhₜ) = p.precomputed
78

89
if !(p.atmos.moisture_model isa DryModel)
9-
@. Yₜ.c.ρ -= ᶜprecipdivᵥ(ᶠwinterp(ᶜJ, Y.c.ρ) * ᶠright_bias(-(ᶜwₜqₜ)))
10+
@. Yₜ.c.ρ -=
11+
ᶜprecipdivᵥ(ᶠinterp(Y.c.ρ * ᶜJ) / ᶠJ * ᶠright_bias(-(ᶜwₜqₜ)))
1012
@. Yₜ.c.ρe_tot -=
11-
ᶜprecipdivᵥ(ᶠwinterp(ᶜJ, Y.c.ρ) * ᶠright_bias(-(ᶜwₕhₜ)))
13+
ᶜprecipdivᵥ(ᶠinterp(Y.c.ρ * ᶜJ) / ᶠJ * ᶠright_bias(-(ᶜwₕhₜ)))
1214
@. Yₜ.c.ρq_tot -=
13-
ᶜprecipdivᵥ(ᶠwinterp(ᶜJ, Y.c.ρ) * ᶠright_bias(-(ᶜwₜqₜ)))
15+
ᶜprecipdivᵥ(ᶠinterp(Y.c.ρ * ᶜJ) / ᶠJ * ᶠright_bias(-(ᶜwₜqₜ)))
1416
end
1517
return nothing
1618
end

0 commit comments

Comments
 (0)