Skip to content

Commit bc3a361

Browse files
committed
Change density reconstruction on cell faces to match dycore paper
1 parent cedbf1b commit bc3a361

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
@@ -531,6 +531,7 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
531531
ᶜuₕ = Y.c.uₕ
532532
ᶠu₃ = Y.f.u₃
533533
ᶜJ = Fields.local_geometry_field(Y.c).J
534+
ᶠJ = Fields.local_geometry_field(Y.f).J
534535
ᶜgⁱʲ = Fields.local_geometry_field(Y.c).gⁱʲ
535536
ᶠgⁱʲ = Fields.local_geometry_field(Y.f).gⁱʲ
536537

@@ -552,7 +553,7 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
552553
@. ᶠp_grad_matrix = DiagonalMatrixRow(-1 / ᶠinterp(ᶜρ)) ᶠgradᵥ_matrix()
553554

554555
@. ᶜadvection_matrix =
555-
-(ᶜadvdivᵥ_matrix()) DiagonalMatrixRow(ᶠwinterp(ᶜJ, ᶜρ))
556+
-(ᶜadvdivᵥ_matrix()) DiagonalMatrixRow(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ)
556557

557558
if use_derivative(topography_flag)
558559
∂ᶜρ_err_∂ᶜuₕ = matrix[@name(c.ρ), @name(c.uₕ)]
@@ -634,7 +635,7 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
634635
#TODO: tetsing explicit vs implicit
635636
#@. ∂ᶜρe_tot_err_∂ᶜρe_tot +=
636637
# dtγ * -(ᶜprecipdivᵥ_matrix()) ⋅
637-
# DiagonalMatrixRow(ᶠwinterp(ᶜJ, ᶜρ)) ⋅ ᶠright_bias_matrix() ⋅
638+
# DiagonalMatrixRow(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ) ⋅ ᶠright_bias_matrix() ⋅
638639
# DiagonalMatrixRow(
639640
# -(1 + ᶜkappa_m) / ᶜρ * ifelse(
640641
# ᶜh_tot == 0,
@@ -648,7 +649,7 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
648649
#TODO: tetsing explicit vs implicit
649650
#@. ∂ᶜρe_tot_err_∂ᶜρq_tot =
650651
# dtγ * -(ᶜprecipdivᵥ_matrix()) ⋅
651-
# DiagonalMatrixRow(ᶠwinterp(ᶜJ, ᶜρ)) ⋅ ᶠright_bias_matrix() ⋅
652+
# DiagonalMatrixRow(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ) ⋅ ᶠright_bias_matrix() ⋅
652653
# DiagonalMatrixRow(
653654
# -(ᶜkappa_m) * ∂e_int_∂q_tot / ᶜρ * ifelse(
654655
# ᶜh_tot == 0,
@@ -662,7 +663,7 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
662663
#TODO: tetsing explicit vs implicit
663664
#@. ∂ᶜρq_tot_err_∂ᶜρq_tot =
664665
# dtγ * -(ᶜprecipdivᵥ_matrix()) ⋅
665-
# DiagonalMatrixRow(ᶠwinterp(ᶜJ, ᶜρ)) ⋅ ᶠright_bias_matrix() ⋅
666+
# DiagonalMatrixRow(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ) ⋅ ᶠright_bias_matrix() ⋅
666667
# DiagonalMatrixRow(
667668
# -1 / ᶜρ * ifelse(
668669
# ᶜspecific.q_tot == 0,
@@ -677,7 +678,8 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
677678
ᶜwₚ = MatrixFields.get_field(p, wₚ_name)
678679
@. ∂ᶜρqₚ_err_∂ᶜρqₚ =
679680
dtγ * -(ᶜprecipdivᵥ_matrix())
680-
DiagonalMatrixRow(ᶠwinterp(ᶜJ, ᶜρ)) ᶠright_bias_matrix()
681+
DiagonalMatrixRow(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ)
682+
ᶠright_bias_matrix()
681683
DiagonalMatrixRow(-Geometry.WVector(ᶜwₚ) / ᶜρ) - (I,)
682684
end
683685

@@ -852,13 +854,13 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
852854
ᶠu³ʲs.:(1),
853855
draft_area(Y.c.sgsʲs.:(1).ρa, ᶜρʲs.:(1)),
854856
),
855-
),
856-
) ᶠwinterp_matrix(ᶜJ) DiagonalMatrixRow(
857-
ᶜkappa_mʲ * (ᶜρʲs.:(1))^2 / ((ᶜkappa_mʲ + 1) * ᶜp) *
857+
) / ᶠJ,
858+
) ᶠinterp_matrix() DiagonalMatrixRow(
859+
ᶜJ * ᶜkappa_mʲ * (ᶜρʲs.:(1))^2 / ((ᶜkappa_mʲ + 1) * ᶜp) *
858860
∂e_int_∂q_tot,
859861
)
860862
@. ᶠbidiagonal_matrix_ct3_2 =
861-
DiagonalMatrixRow(ᶠwinterp(ᶜJ, ᶜρʲs.:(1)))
863+
DiagonalMatrixRow(ᶠinterp(ᶜρʲs.:(1) * ᶜJ) / ᶠJ)
862864
ᶠset_upwind_matrix_bcs(ᶠupwind_matrix(ᶠu³ʲs.:(1)))
863865
DiagonalMatrixRow(
864866
Y.c.sgsʲs.:(1).ρa * ᶜkappa_mʲ / ((ᶜkappa_mʲ + 1) * ᶜp) *
@@ -877,12 +879,12 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
877879
ᶠu³ʲs.:(1),
878880
draft_area(Y.c.sgsʲs.:(1).ρa, ᶜρʲs.:(1)),
879881
),
880-
),
881-
) ᶠwinterp_matrix(ᶜJ) DiagonalMatrixRow(
882-
ᶜkappa_mʲ * (ᶜρʲs.:(1))^2 / ((ᶜkappa_mʲ + 1) * ᶜp),
882+
) / ᶠJ,
883+
) ᶠinterp_matrix() DiagonalMatrixRow(
884+
ᶜJ * ᶜkappa_mʲ * (ᶜρʲs.:(1))^2 / ((ᶜkappa_mʲ + 1) * ᶜp),
883885
)
884886
@. ᶠbidiagonal_matrix_ct3_2 =
885-
DiagonalMatrixRow(ᶠwinterp(ᶜJ, ᶜρʲs.:(1)))
887+
DiagonalMatrixRow(ᶠinterp(ᶜρʲs.:(1) * ᶜJ) / ᶠJ)
886888
ᶠset_upwind_matrix_bcs(ᶠupwind_matrix(ᶠu³ʲs.:(1)))
887889
DiagonalMatrixRow(
888890
Y.c.sgsʲs.:(1).ρa * ᶜkappa_mʲ / ((ᶜkappa_mʲ + 1) * ᶜp),
@@ -894,7 +896,7 @@ function update_implicit_equation_jacobian!(A, Y, p, dtγ)
894896
matrix[@name(c.sgsʲs.:(1).ρa), @name(c.sgsʲs.:(1).ρa)]
895897
@. ᶜadvection_matrix =
896898
-(ᶜadvdivᵥ_matrix())
897-
DiagonalMatrixRow(ᶠwinterp(ᶜJ, ᶜρʲs.:(1)))
899+
DiagonalMatrixRow(ᶠinterp(ᶜρʲs.:(1) * ᶜJ) / ᶠJ)
898900
@. ∂ᶜρaʲ_err_∂ᶜρaʲ =
899901
dtγ * ᶜadvection_matrix
900902
ᶠ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
@@ -49,48 +49,54 @@ end
4949

5050
function vertical_transport(ᶜρ, ᶠu³, ᶜχ, dt, ::Val{:none})
5151
ᶜJ = Fields.local_geometry_field(ᶜρ).J
52-
return @. lazy(-(ᶜadvdivᵥ(ᶠwinterp(ᶜJ, ᶜρ) * ᶠu³ * ᶠinterp(ᶜχ))))
52+
ᶠJ = Fields.local_geometry_field(ᶠu³).J
53+
return @. lazy(-(ᶜadvdivᵥ(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ * ᶠu³ * ᶠinterp(ᶜχ))))
5354
end
5455
function vertical_transport(ᶜρ, ᶠu³, ᶜχ, dt, ::Val{:first_order})
5556
ᶜJ = Fields.local_geometry_field(ᶜρ).J
56-
return @. lazy(-(ᶜadvdivᵥ(ᶠwinterp(ᶜJ, ᶜρ) * ᶠupwind1(ᶠu³, ᶜχ))))
57+
ᶠJ = Fields.local_geometry_field(ᶠu³).J
58+
return @. lazy(-(ᶜadvdivᵥ(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ * ᶠupwind1(ᶠu³, ᶜχ))))
5759
end
5860
@static if pkgversion(ClimaCore) v"0.14.22"
5961
function vertical_transport(ᶜρ, ᶠu³, ᶜχ, dt, ::Val{:vanleer_limiter})
6062
ᶜJ = Fields.local_geometry_field(ᶜρ).J
63+
ᶠJ = Fields.local_geometry_field(ᶠu³).J
6164
return @. lazy(
62-
-(ᶜadvdivᵥ(ᶠwinterp(ᶜJ, ᶜρ) * ᶠlin_vanleer(ᶠu³, ᶜχ, dt))),
65+
-(ᶜadvdivᵥ(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ * ᶠlin_vanleer(ᶠu³, ᶜχ, dt))),
6366
)
6467
end
6568
end
6669
function vertical_transport(ᶜρ, ᶠu³, ᶜχ, dt, ::Val{:third_order})
6770
ᶜJ = Fields.local_geometry_field(ᶜρ).J
68-
return @. lazy(-(ᶜadvdivᵥ(ᶠwinterp(ᶜJ, ᶜρ) * ᶠupwind3(ᶠu³, ᶜχ))))
71+
ᶠJ = Fields.local_geometry_field(ᶠu³).J
72+
return @. lazy(-(ᶜadvdivᵥ(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ * ᶠupwind3(ᶠu³, ᶜχ))))
6973
end
7074
function vertical_transport(ᶜρ, ᶠu³, ᶜχ, dt, ::Val{:boris_book})
7175
ᶜJ = Fields.local_geometry_field(ᶜρ).J
76+
ᶠJ = Fields.local_geometry_field(ᶠu³).J
7277
return @. lazy(
7378
-(ᶜadvdivᵥ(
74-
ᶠwinterp(ᶜJ, ᶜρ) * (
79+
ᶠinterp(ᶜρ * ᶜJ) / ᶠJ * (
7580
ᶠupwind1(ᶠu³, ᶜχ) + ᶠfct_boris_book(
7681
ᶠupwind3(ᶠu³, ᶜχ) - ᶠupwind1(ᶠu³, ᶜχ),
7782
ᶜχ / dt -
78-
ᶜadvdivᵥ(ᶠwinterp(ᶜJ, ᶜρ) * ᶠupwind1(ᶠu³, ᶜχ)) / ᶜρ,
83+
ᶜadvdivᵥ(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ * ᶠupwind1(ᶠu³, ᶜχ)) / ᶜρ,
7984
)
8085
),
8186
)),
8287
)
8388
end
8489
function vertical_transport(ᶜρ, ᶠu³, ᶜχ, dt, ::Val{:zalesak})
8590
ᶜJ = Fields.local_geometry_field(ᶜρ).J
91+
ᶠJ = Fields.local_geometry_field(ᶠu³).J
8692
return @. lazy(
8793
-(ᶜadvdivᵥ(
88-
ᶠwinterp(ᶜJ, ᶜρ) * (
94+
ᶠinterp(ᶜρ * ᶜJ) / ᶠJ * (
8995
ᶠupwind1(ᶠu³, ᶜχ) + ᶠfct_zalesak(
9096
ᶠupwind3(ᶠu³, ᶜχ) - ᶠupwind1(ᶠu³, ᶜχ),
9197
ᶜχ / dt,
9298
ᶜχ / dt -
93-
ᶜadvdivᵥ(ᶠwinterp(ᶜJ, ᶜρ) * ᶠupwind1(ᶠu³, ᶜχ)) / ᶜρ,
99+
ᶜadvdivᵥ(ᶠinterp(ᶜρ * ᶜJ) / ᶠJ * ᶠupwind1(ᶠu³, ᶜχ)) / ᶜρ,
94100
)
95101
),
96102
)),
@@ -109,10 +115,11 @@ function implicit_vertical_advection_tendency!(Yₜ, Y, p, t)
109115
(; dt) = p
110116
n = n_mass_flux_subdomains(turbconv_model)
111117
ᶜJ = Fields.local_geometry_field(Y.c).J
118+
ᶠJ = Fields.local_geometry_field(Y.f).J
112119
(; ᶠgradᵥ_ᶜΦ) = p.core
113120
(; ᶜh_tot, ᶜspecific, ᶠu³, ᶜp) = p.precomputed
114121

115-
@. Yₜ.c.ρ -= ᶜdivᵥ(ᶠwinterp(ᶜJ, Y.c.ρ) * ᶠu³)
122+
@. Yₜ.c.ρ -= ᶜdivᵥ(ᶠinterp(Y.c.ρ * ᶜJ) / ᶠJ * ᶠu³)
116123

117124
# Central advection of active tracers (e_tot and q_tot)
118125
vtt = vertical_transport(Y.c.ρ, ᶠu³, ᶜh_tot, dt, Val(:none))
@@ -128,11 +135,11 @@ function implicit_vertical_advection_tendency!(Yₜ, Y, p, t)
128135
if moisture_model isa NonEquilMoistModel
129136
(; ᶜwₗ, ᶜwᵢ) = p.precomputed
130137
@. Yₜ.c.ρq_liq -= ᶜprecipdivᵥ(
131-
ᶠwinterp(ᶜJ, Y.c.ρ) *
138+
ᶠinterp(Y.c.ρ * ᶜJ) / ᶠJ *
132139
ᶠright_bias(Geometry.WVector(-(ᶜwₗ)) * ᶜspecific.q_liq),
133140
)
134141
@. Yₜ.c.ρq_ice -= ᶜprecipdivᵥ(
135-
ᶠwinterp(ᶜJ, Y.c.ρ) *
142+
ᶠinterp(Y.c.ρ * ᶜJ) / ᶠJ *
136143
ᶠright_bias(Geometry.WVector(-(ᶜwᵢ)) * ᶜspecific.q_ice),
137144
)
138145
end
@@ -144,11 +151,11 @@ function implicit_vertical_advection_tendency!(Yₜ, Y, p, t)
144151
# using downward biasing and free outflow bottom boundary condition
145152
(; ᶜwᵣ, ᶜwₛ) = p.precomputed
146153
@. Yₜ.c.ρq_rai -= ᶜprecipdivᵥ(
147-
ᶠwinterp(ᶜJ, Y.c.ρ) *
154+
ᶠinterp(Y.c.ρ * ᶜJ) / ᶠJ *
148155
ᶠright_bias(Geometry.WVector(-(ᶜwᵣ)) * ᶜspecific.q_rai),
149156
)
150157
@. Yₜ.c.ρq_sno -= ᶜprecipdivᵥ(
151-
ᶠwinterp(ᶜJ, Y.c.ρ) *
158+
ᶠinterp(Y.c.ρ * ᶜJ) / ᶠJ *
152159
ᶠright_bias(Geometry.WVector(-(ᶜwₛ)) * ᶜspecific.q_sno),
153160
)
154161
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)