Skip to content

Commit e47c70a

Browse files
committed
ft: Add Kinematic Driver (KiD) model configuration
1 parent 409c47c commit e47c70a

File tree

14 files changed

+314
-18
lines changed

14 files changed

+314
-18
lines changed

config/default_configs/default_config.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,3 +425,6 @@ use_itime:
425425
1. Surface conditions that explicitly depend on time (e.g. LifeCycleTan2018, TRMM_LBA, etc.),
426426
2. Time dependent forcing/tendencies use time rounded to the nearest unit of time for dt"
427427
value: false
428+
prescribed_flow:
429+
help: "Prescribe a flow field [`nothing` (default), `ShipwayHill2012`]"
430+
value: ~
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
## Model
2+
prescribed_flow: ShipwayHill2012
3+
initial_condition: ShipwayHill2012
4+
surface_setup: ShipwayHill2012
5+
energy_q_tot_upwinding: first_order
6+
tracer_upwinding: first_order
7+
# moist: "nonequil"
8+
# precip_model: "1M"
9+
moist: "equil"
10+
precip_model: "0M"
11+
cloud_model: "grid_scale"
12+
call_cloud_diagnostics_per_stage: true
13+
config: "column"
14+
hyperdiff: "false"
15+
## Simulation
16+
# z_max: 2e3 # TODO: Update top boundary condition for ρu₃qₜ to allow lower z_max
17+
# z_elem: 128
18+
z_max: 8e3
19+
z_elem: 512
20+
z_stretch: false
21+
# ode_algo: "ARS111" # try: Explicit Euler
22+
dt: "1secs"
23+
# t_end: "1hours"
24+
t_end: "20mins"
25+
dt_save_state_to_disk: "1hours"
26+
toml: [toml/kinematic_driver.toml]
27+
check_nan_every: 1
28+
## Diagnostics
29+
output_default_diagnostics: false
30+
diagnostics:
31+
- short_name: [
32+
# (z,t) fields
33+
ta, thetaa, ha, rhoa, wa, hur, hus, cl, clw, cli, ua, va, ke,
34+
# (t,) fields
35+
lwp, pr,
36+
# 1M
37+
# (z,t) fields
38+
# husra, hussn,
39+
# (t,) fields
40+
# rwp,
41+
]
42+
period: 10secs

docs/bibliography.bib

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,15 @@ @article{Wing2018
283283
url = {https://gmd.copernicus.org/articles/11/793/2018/},
284284
doi = {10.5194/gmd-11-793-2018}
285285
}
286+
287+
@article{ShipwayHill2012,
288+
title = {Diagnosis of systematic differences between multiple parametrizations of warm rain microphysics using a kinematic framework},
289+
volume = {138},
290+
url = {https://onlinelibrary.wiley.com/doi/abs/10.1002/qj.1913},
291+
doi = {10.1002/qj.1913},
292+
pages = {2196--2211},
293+
number = {669},
294+
journaltitle = {Quarterly Journal of the Royal Meteorological Society},
295+
author = {Shipway, B. J. and Hill, A. A.},
296+
date = {2012},
297+
}

post_processing/ci_plots.jl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,3 +1550,40 @@ function make_plots(
15501550
output_name = "summary_3D",
15511551
)
15521552
end
1553+
1554+
function make_plots(::Val{:kinematic_driver}, output_paths::Vector{<:AbstractString})
1555+
function rescale_time_to_min(var)
1556+
if haskey(var.dims, "time")
1557+
var.dims["time"] .= var.dims["time"] ./ 60
1558+
var.dim_attributes["time"]["units"] = "min"
1559+
end
1560+
return var
1561+
end
1562+
simdirs = SimDir.(output_paths)
1563+
short_names = [
1564+
"hus", "clw", "husra", "ta", #"thetaa", "rhoa",
1565+
"wa",
1566+
# "cli", "hussn",
1567+
# "ke",
1568+
]
1569+
short_names = short_names collect(keys(simdirs[1].vars))
1570+
vars = map_comparison(simdirs, short_names) do simdir, short_name
1571+
var = slice(get(simdir; short_name), x = 0, y = 0)
1572+
if short_name in ["hus", "clw", "husra", "cli", "hussn"]
1573+
var.data .= var.data .* 1000
1574+
var.attributes["units"] = "g/kg"
1575+
end
1576+
return rescale_time_to_min(var)
1577+
end
1578+
file_contour = make_plots_generic(output_paths, vars;
1579+
output_name = "tmp_contour",
1580+
)
1581+
1582+
short_names_lines = ["lwp", "rwp", "pr"]
1583+
short_names_lines = short_names_lines collect(keys(simdirs[1].vars))
1584+
vars_lines = map_comparison(simdirs, short_names_lines) do simdir, short_name
1585+
var = slice(get(simdir; short_name), x = 0, y = 0)
1586+
return rescale_time_to_min(var)
1587+
end
1588+
make_plots_generic(output_paths, vars_lines; summary_files = [file_contour])
1589+
end

src/cache/precomputed_quantities.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -468,8 +468,10 @@ NVTX.@annotate function set_implicit_precomputed_quantities!(Y, p, t)
468468

469469
# TODO: We might want to move this to dss! (and rename dss! to something
470470
# like enforce_constraints!).
471-
set_velocity_at_surface!(Y, ᶠuₕ³, turbconv_model)
472-
set_velocity_at_top!(Y, turbconv_model)
471+
if !(p.atmos.prescribed_flow isa PrescribedFlow)
472+
set_velocity_at_surface!(Y, ᶠuₕ³, turbconv_model)
473+
set_velocity_at_top!(Y, turbconv_model)
474+
end
473475

474476
set_velocity_quantities!(ᶜu, ᶠu³, ᶜK, Y.f.u₃, Y.c.uₕ, ᶠuₕ³)
475477
ᶜJ = Fields.local_geometry_field(Y.c).J

src/cache/temporary_quantities.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,5 +116,6 @@ function temporary_quantities(Y, atmos)
116116
ᶜdiffusion_u_matrix = similar(Y.c, TridiagonalMatrixRow{FT}),
117117
ᶜtridiagonal_matrix_scalar = similar(Y.c, TridiagonalMatrixRow{FT}),
118118
ᶠtridiagonal_matrix_c3 = similar(Y.f, TridiagonalMatrixRow{C3{FT}}),
119+
(!isnothing(atmos.prescribed_flow) ? (; temp_Yₜ_imp = similar(Y)) : (;))...,
119120
)
120121
end

src/initial_conditions/initial_conditions.jl

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1859,3 +1859,43 @@ function (initial_condition::ISDAC)(params)
18591859
)
18601860
end
18611861
end
1862+
1863+
"""
1864+
ShipwayHill2012
1865+
1866+
The `InitialCondition` described in [ShipwayHill2012](@cite), but with a hydrostatically
1867+
balanced pressure profile.
1868+
1869+
B. J. Shipway and A. A. Hill.
1870+
Diagnosis of systematic differences between multiple parametrizations of warm rain microphysics using a kinematic framework.
1871+
Quarterly Journal of the Royal Meteorological Society 138, 2196-2211 (2012).
1872+
"""
1873+
struct ShipwayHill2012 <: InitialCondition end
1874+
function (initial_condition::ShipwayHill2012)(params)
1875+
FT = eltype(params)
1876+
1877+
## Initialize the profile
1878+
z_values = FT[0, 740, 3260]
1879+
rv_values = FT[0.015, 0.0138, 0.0024] # water vapor mixing ratio
1880+
θ_values = FT[297.9, 297.9, 312.66] # potential temperature
1881+
linear_profile(zs, vals) = Intp.extrapolate(
1882+
Intp.interpolate((zs,), vals, Intp.Gridded(Intp.Linear())), Intp.Linear(),
1883+
)
1884+
# profile of water vapour mixing ratio
1885+
rv(z) = linear_profile(z_values, rv_values)(z)
1886+
q_tot(z) = rv(z) / (1 + rv(z))
1887+
# profile of potential temperature
1888+
θ(z) = linear_profile(z_values, θ_values)(z)
1889+
## Hydrostatically balanced pressure profile
1890+
thermo_params = CAP.thermodynamics_params(params)
1891+
p_0 = FT(100_700) # Pa
1892+
p = hydrostatic_pressure_profile(; thermo_params, p_0, θ, q_tot)
1893+
function local_state(local_geometry)
1894+
(; z) = local_geometry.coordinates
1895+
return LocalState(; params, geometry = local_geometry,
1896+
thermo_state = TD.PhaseEquil_pθq(thermo_params, p(z), θ(z), q_tot(z)),
1897+
precip_state = NoPrecipState{typeof(z)}(),
1898+
)
1899+
end
1900+
return local_state
1901+
end

src/prognostic_equations/advection.jl

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,30 @@ NVTX.@annotate function horizontal_tracer_advection_tendency!(Yₜ, Y, p, t)
164164
return nothing
165165
end
166166

167+
"""
168+
ᶜρq_tot_vertical_transport_bc(flow, thermo_params, t, ᶠu³)
169+
170+
Computes the vertical transport of `ρq_tot` at the surface due to prescribed flow.
171+
172+
If the flow is not prescribed, this has no effect.
173+
174+
# Arguments
175+
- `flow`: The prescribed flow model, see [`PrescribedFlow`](@ref).
176+
- If `flow` is `nothing`, this has no effect.
177+
- `thermo_params`: The thermodynamic parameters, needed to compute surface air density.
178+
- `t`: The current time.
179+
- `ᶠu³`: The vertical velocity field.
180+
181+
# Returns
182+
- The vertical transport of `ρq_tot` at the surface due to prescribed flow.
183+
"""
184+
ᶜρq_tot_vertical_transport_bc(::Nothing, _, _, _) = NullBroadcasted()
185+
function ᶜρq_tot_vertical_transport_bc(flow::PrescribedFlow, thermo_params, t, ᶠu³)
186+
ρu₃qₜ_sfc_bc = get_ρu₃qₜ_surface(flow, thermo_params, t)
187+
ᶜadvdivᵥ = Operators.DivergenceF2C(; bottom = Operators.SetValue(ρu₃qₜ_sfc_bc))
188+
return @. lazy(-(ᶜadvdivᵥ(zero(ᶠu³))))
189+
end
190+
167191
"""
168192
explicit_vertical_advection_tendency!(Yₜ, Y, p, t)
169193
@@ -193,7 +217,7 @@ Modifies `Yₜ.c` (various tracers, `ρe_tot`, `ρq_tot`, `uₕ`), `Yₜ.f.u₃`
193217
`Yₜ.f.sgsʲs` (updraft `u₃`), and `Yₜ.c.sgs⁰.ρatke` as applicable.
194218
"""
195219
NVTX.@annotate function explicit_vertical_advection_tendency!(Yₜ, Y, p, t)
196-
(; turbconv_model) = p.atmos
220+
(; turbconv_model, prescribed_flow) = p.atmos
197221
n = n_prognostic_mass_flux_subdomains(turbconv_model)
198222
advect_tke = use_prognostic_tke(turbconv_model)
199223
point_type = eltype(Fields.coordinate_field(Y.c))
@@ -290,6 +314,10 @@ NVTX.@annotate function explicit_vertical_advection_tendency!(Yₜ, Y, p, t)
290314
vtt = vertical_transport(ᶜρ, ᶠu³, ᶜq_tot, dt, energy_q_tot_upwinding)
291315
vtt_central = vertical_transport(ᶜρ, ᶠu³, ᶜq_tot, dt, Val(:none))
292316
@. Yₜ.c.ρq_tot += vtt - vtt_central
317+
if prescribed_flow isa PrescribedFlow
318+
vtt_bc = ᶜρq_tot_vertical_transport_bc(prescribed_flow, thermo_params, t, ᶠu³)
319+
@. Yₜ.c.ρq_tot += vtt_bc
320+
end
293321
end
294322

295323
if isnothing(ᶠf¹²)

src/prognostic_equations/dss.jl

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,37 @@ See also:
7474
dss!(Y_state, params, t_current)
7575
# The ClimaCore.Field objects within Y_state.c and Y_state.f are now updated
7676
# with DSS applied, ensuring continuity across distributed elements.
77+
```
7778
"""
7879

79-
NVTX.@annotate function dss!(Y, p, t)
80+
NVTX.@annotate function dss!(Y, p, t) # TODO: Rename to e.g. `apply_constraints!`
81+
prescribe_flow!(Y, p, t, p.atmos.prescribed_flow)
8082
if do_dss(axes(Y.c))
8183
Spaces.weighted_dss!(Y.c => p.ghost_buffer.c, Y.f => p.ghost_buffer.f)
8284
end
8385
return nothing
8486
end
87+
88+
prescribe_flow!(_, _, _, ::Nothing) = nothing
89+
function prescribe_flow!(Y, p, t, flow::PrescribedFlow)
90+
(; ᶜΦ) = p.core
91+
ᶠlg = Fields.local_geometry_field(Y.f)
92+
z = Fields.coordinate_field(Y.f).z
93+
@. Y.f.u₃ = C3(Geometry.WVector(flow(z, t)), ᶠlg)
94+
95+
### Fix energy to initial temperature
96+
ᶜlg = Fields.local_geometry_field(Y.c)
97+
local_state = InitialConditions.ShipwayHill2012()(p.params)
98+
get_ρ_init_dry(ls) = ls.thermo_state.ρ * (1 - ls.thermo_state.q_tot)
99+
get_T_init(ls) = TD.air_temperature(ls.thermo_params, ls.thermo_state)
100+
ᶜρ_init_dry = @. lazy(get_ρ_init_dry(local_state(ᶜlg)))
101+
ᶜT_init = @. lazy(get_T_init(local_state(ᶜlg)))
102+
103+
thermo_params = CAP.thermodynamics_params(p.params)
104+
105+
@. Y.c.ρ = ᶜρ_init_dry + Y.c.ρq_tot
106+
ᶜts = @. lazy(TD.PhaseEquil_ρTq(thermo_params, Y.c.ρ, ᶜT_init, Y.c.ρq_tot / Y.c.ρ))
107+
ᶜe_kin = compute_kinetic(Y.c.uₕ, Y.f.u₃)
108+
@. Y.c.ρe_tot = Y.c.ρ * TD.total_energy(thermo_params, ᶜts, ᶜe_kin, ᶜΦ)
109+
return nothing
110+
end

src/solver/model_getters.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,8 @@ function check_case_consistency(parsed_args)
655655
imp_vert_diff = parsed_args["implicit_diffusion"]
656656
vert_diff = parsed_args["vert_diff"]
657657
turbconv = parsed_args["turbconv"]
658+
topography = parsed_args["topography"]
659+
prescribed_flow = parsed_args["prescribed_flow"]
658660

659661
ISDAC_mandatory = (ic, subs, surf, rad, extf)
660662
if "ISDAC" in ISDAC_mandatory
@@ -671,5 +673,20 @@ function check_case_consistency(parsed_args)
671673
"Implicit vertical diffusion is only supported when using a " *
672674
"turbulence convection model or vertical diffusion model.",
673675
)
676+
elseif !isnothing(prescribed_flow)
677+
@assert(topography == "NoWarp",
678+
"Prescribed flow elides `set_velocity_at_surface!` and `set_velocity_at_top!` \
679+
which is needed for topography. Thus, prescribed flow must have flat surface."
680+
)
681+
@assert(
682+
!parsed_args["implicit_noneq_cloud_formation"] &&
683+
!parsed_args["implicit_diffusion"] &&
684+
!parsed_args["implicit_sgs_advection"] &&
685+
!parsed_args["implicit_sgs_entr_detr"] &&
686+
!parsed_args["implicit_sgs_nh_pressure"] &&
687+
!parsed_args["implicit_sgs_vertdiff"] &&
688+
!parsed_args["implicit_sgs_mass_flux"],
689+
"Prescribed flow does not use the implicit solver."
690+
)
674691
end
675692
end

0 commit comments

Comments
 (0)