Skip to content

Commit 9eb736a

Browse files
committed
add modifying config variables, add docs, add diagnostic EDMF yaml
1 parent 25240aa commit 9eb736a

File tree

8 files changed

+285
-31
lines changed

8 files changed

+285
-31
lines changed

config/default_configs/default_config.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,3 +398,16 @@ use_itime:
398398
1. Surface conditions that explicitly depend on time (e.g. LifeCycleTan2018, TRMM_LBA, etc.),
399399
2. Time dependent forcing/tendencies use time rounded to the nearest unit of time for dt"
400400
value: false
401+
# DYCOMS-RF02 Perturbation Variables
402+
q_tot_0_dycoms_rf02:
403+
help: "Surface total water mixing ratio for DYCOMS RF02."
404+
value: 9.45
405+
theta_0_dycoms_rf02:
406+
help: "Surface liquid-ice potential temperature for DYCOMS RF02."
407+
value: 288.3
408+
theta_i_dycoms_rf02:
409+
help: "Initial boundary layer liquid-ice potential temperature for DYCOMS RF02."
410+
value: 295.0
411+
z_i_dycoms_rf02:
412+
help: "Initial boundary layer height."
413+
value: 795.0
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
initial_condition: DYCOMS_RF02
2+
subsidence: DYCOMS
3+
scm_coriolis: DYCOMS_RF02
4+
rad: DYCOMS
5+
surface_setup: DYCOMS_RF02
6+
turbconv: "diagnostic_edmfx"
7+
implicit_diffusion: true
8+
approximate_linear_solve_iters: 2
9+
edmfx_upwinding: first_order
10+
edmfx_entr_model: "Generalized"
11+
edmfx_detr_model: "Generalized"
12+
edmfx_sgs_mass_flux: true
13+
edmfx_sgs_diffusive_flux: true
14+
edmfx_nh_pressure: true
15+
edmfx_filter: true
16+
prognostic_tke: true
17+
moist: "nonequil"
18+
cloud_model: "quadrature_sgs"
19+
precip_model: "1M"
20+
call_cloud_diagnostics_per_stage: true
21+
config: "column"
22+
x_elem: 2
23+
y_elem: 2
24+
z_elem: 30
25+
z_max: 1500
26+
z_stretch: false
27+
perturb_initstate: false
28+
dt: 10secs
29+
t_end: 12hours
30+
dt_save_state_to_disk: 10mins
31+
toml: [toml/diagnostic_edmfx_1M.toml]
32+
netcdf_interpolation_num_points: [8, 8, 30]
33+
diagnostics:
34+
- short_name: [ts, ta, thetaa, ha, pfull, rhoa, ua, va, wa, hur, hus, cl, clw, cli, hussfc, evspsbl, pr, lwp, rwp]
35+
period: 10mins
36+
- short_name: [arup, waup, taup, thetaaup, haup, husup, hurup, clwup, cliup, husraup, hussnup, tke]
37+
period: 10mins
38+
- short_name: [entr, detr, lmix, bgrad, strain, edt, evu]
39+
period: 10mins
40+
- short_name: [husra, hussn]
41+
period: 10mins

docs/make.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ include(joinpath(@__DIR__, "src", "config_table.jl"))
1010
doctest(ClimaAtmos; plugins = [bib])
1111
disable_logging(Base.CoreLogging.BelowMinLevel) # Re-enable all logging
1212

13+
example_pages = ["Perturbation Experiments" => "perturbation_experiments.md"]
14+
1315
makedocs(;
1416
plugins = [bib],
1517
modules = [ClimaAtmos],
@@ -38,8 +40,9 @@ makedocs(;
3840
"Implicit Solver" => "implicit_solver.md",
3941
"Radiative Equilibrium" => "radiative_equilibrium.md",
4042
"Single Column Model" => "single_column_prospect.md",
41-
"Restarts and checkpoints" => "restarts.md",
43+
"Restarts and Checkpoints" => "restarts.md",
4244
"REPL scripts" => "repl_scripts.md",
45+
"Examples" => example_pages,
4346
"Configuration" => "config.md",
4447
"Parameters" => "parameters.md",
4548
"Longruns" => "longruns.md",

docs/src/contributor_guide.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,16 @@ or clarification that you can take care of while you are here.
165165

166166
Here is an example of a docstring:
167167

168-
TODO: add example
168+
```
169+
"""
170+
InitialCondition
171+
172+
A mechanism for specifying the `LocalState` of an `AtmosModel` at every point in
173+
the domain. Given some `initial_condition`, calling `initial_condition(params)`
174+
returns a function of the form `local_state(local_geometry)::LocalState`.
175+
"""
176+
abstract type InitialCondition end
177+
```
169178

170179
You can preview how the Documentation will look like after merging by building the documentation
171180
locally. From the main directory of your local repository call
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
2+
# Creating custom arguments for perturbation experiments
3+
In cases where it is of interest to run ensembles of the same model configuration but with perturbed initial conditions, it may be of use to add new keyword arguments to the .yml file. The idea is to allow modifications to initial conditions to be passed directly through the .yml file and then creating multiple copies of the files but with different variations and combinations of these parameters.
4+
5+
As an example, we will explore modifying the total water mixing ratio (`q_tot_0`), liquid-ice potential temperature profiles (`theta_0` & `theta_i`), and initial boundary layer height (`z_i`) in the DYCOMS-RF02 simulation setup.
6+
7+
### Modify initial_conditions.jl
8+
To start, we need to go to the part of the source code responsible for defining the initial conditions. For both of the DYCOMS research flight simulation setups, the total water mixing ratio and liquid-ice potential temperature are pulled from another library called AtmosphericProfilesLibrary (APL).
9+
10+
There are many ways to modify the functions to allow for perturbation to the initial conditions, but for the sake of this example we will overwrite the function signature with our own version where we can pass in our own custom profiles. We must import the functions from the APL library and then define a new function with the same signature. This looks like:
11+
12+
```
13+
import AtmosphericProfilesLibrary: Dycoms_RF02_θ_liq_ice, Dycoms_RF02_q_tot
14+
[...]
15+
16+
# Redefine the profile functions here. Here we redefine the functions such that
17+
# we can pass in our own values for q_tot and θ_liq_ice, as well as modifying
18+
# the initial boundary layer height.
19+
20+
""" [Ackerman2009](@cite) """
21+
Dycoms_RF02_θ_liq_ice(::Type{FT}, theta_0, theta_i, z_i) where {FT} =
22+
APL.ZProfile(z -> if z <= z_i
23+
FT(theta_0)
24+
else
25+
FT(theta_i) + (z - FT(z_i))^FT(1.0 / 3.0)
26+
end)
27+
28+
""" [Ackerman2009](@cite) """
29+
Dycoms_RF02_q_tot(::Type{FT}, q_tot_0, z_i) where {FT} =
30+
APL.ZProfile(z -> if z <= z_i
31+
FT(q_tot_0) / FT(1000.0)
32+
else
33+
(FT(5) - FT(3) * (FT(1) - exp(-(z - FT(z_i)) / FT(500)))) / FT(1000)
34+
end)
35+
```
36+
37+
Now that we have redefined our functions, we can pass these new functions to our intial conditions structure for the DYCOMS-RF02 setup. Here we can also begin to define our new keyword arguments that will serve as inputs for the new functions we defined. In the `DYCOMS_RF02` structure, we add the names of our new inputs:
38+
39+
```
40+
Base.@kwdef struct DYCOMS_RF02 <: InitialCondition
41+
prognostic_tke::Bool = false
42+
q_tot_0_dycoms_rf02 # Define total water mixing ratio.
43+
theta_0_dycoms_rf02 # Define liquid-ice θ at surface.
44+
theta_i_dycoms_rf02 # Define liquid-ice θ at initial boundary layer height.
45+
z_i_dycoms_rf02 # Define initial boundary layer height.
46+
end
47+
48+
for IC in (:Dycoms_RF01, :Dycoms_RF02)
49+
IC_Type = Symbol(uppercase(string(IC)))
50+
θ_func_name = Symbol(IC, :_θ_liq_ice)
51+
q_tot_func_name = Symbol(IC, :_q_tot)
52+
[...]
53+
if IC == :Dycoms_RF02
54+
@eval function (initial_condition::$IC_Type)(params)
55+
(; prognostic_tke, q_tot_0_dycoms_rf02, theta_0_dycoms_rf02, theta_i_dycoms_rf02, z_i_dycoms_rf02) = initial_condition #unpack the new arguments here. These arguments will be provided through the model .yml file.
56+
FT = eltype(params)
57+
[...]
58+
θ = $θ_func_name(FT, FT(theta_0_dycoms_rf02), FT(theta_i_dycoms_rf02), FT(z_i_dycoms_rf02)) # Change function signature here.
59+
q_tot = $q_tot_func_name(FT, FT(q_tot_0_dycoms_rf02), FT(z_i_dycoms_rf02)) # Change function signature here.
60+
end
61+
else
62+
[...]
63+
end
64+
end
65+
```
66+
67+
### Add keywords to .yml & Modify default_config.yml
68+
Now that we have added a new keyword argument to be used in initial conditions, it is time to define the keyword argument in the YAML files responsible for configuring the model runs. In the YAML file for running a DYCOMS-RF02 single column experiment, we add and adjust the following lines:
69+
70+
```
71+
q_tot_0_dycoms_rf02: 9.45 # Define variables here.
72+
theta_0_dycoms_rf02: 288.3 # Define variables here.
73+
theta_i_dycoms_rf02: 295.0 # Define variables here.
74+
z_i_dycoms_rf02: 795.0 # Define variables here.
75+
```
76+
77+
These are the same default values being used by the original APL function, but we can modify it in the YAML file if we want to test different initial conditions. Additionally, we need to provide a backup default value in the case that the keyword argument is not used or provided in the setup YAML file. To do this, we go to default_config.yml and add the following:
78+
79+
```
80+
q_tot_0_dycoms_rf02: # Additional variables here.
81+
help: "Surface total water mixing ratio for DYCOMS RF02."
82+
value: 9.45 # Default value.
83+
theta_0_dycoms_rf02: # Additional variables here.
84+
help: "Surface liquid-ice potential temperature for DYCOMS RF02."
85+
value: 288.3 # Default value.
86+
theta_i_dycoms_rf02: # Additional variables here.
87+
help: "Initial boundary layer liquid-ice potential temperature for DYCOMS RF02."
88+
value: 295.0 # Default value.
89+
z_i_dycoms_rf02: # Additional variables here.
90+
help: "Initial boundary layer height."
91+
value: 795.0 # Default value.
92+
```
93+
94+
### Modify type_getters.jl
95+
Finally, we need to update type_getters.jl with our new keyword arguments as well. We find where DYCOMS-RF02 is specified and then we replace it with a separate block that looks like:
96+
97+
```
98+
[...]
99+
elseif parsed_args["initial_condition"] == "DYCOMS_RF02"
100+
return getproperty(ICs, Symbol(parsed_args["initial_condition"]))(
101+
parsed_args["prognostic_tke"],
102+
parsed_args["q_tot_0_dycoms_rf02"], # Add parsed args here.
103+
parsed_args["theta_0_dycoms_rf02"], # Add parsed args here.
104+
parsed_args["theta_i_dycoms_rf02"], # Add parsed args here.
105+
parsed_args["z_i_dycoms_rf02"], # Add parsed args here.
106+
)
107+
[...]
108+
```
109+
110+
With this step complete, we are now ready to pass a new keyword argument that we defined ourselves to modify or change the initial conditions.
111+
112+
The recommended workflow is the create multiple copies of the .yml files and label them according to the initial conditions used. For example, the default file might look like `prognostic_edmfx_dycoms_rf02_column_qtot0_6.5_theta0_284.0_thetai_290.0_zi_795.0_prescribedN_1.0e8.yml`.

post_processing/ci_plots.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,6 +1405,7 @@ DiagEDMFBoxPlotsWithPrecip = Union{
14051405
Val{:diagnostic_edmfx_dycoms_rf02_box},
14061406
Val{:diagnostic_edmfx_rico_box},
14071407
Val{:diagnostic_edmfx_trmm_box},
1408+
Val{:diagnostic_edmfx_dycoms_rf02_column},
14081409
}
14091410
"""
14101411
plot_edmf_vert_profile!(grid_loc, var_group)

src/initial_conditions/initial_conditions.jl

Lines changed: 96 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,7 @@ end
881881
##
882882
# TODO: Get rid of this
883883
import AtmosphericProfilesLibrary as APL
884+
import AtmosphericProfilesLibrary: Dycoms_RF02_θ_liq_ice, Dycoms_RF02_q_tot
884885

885886
const FunctionOrSpline =
886887
Union{Function, APL.AbstractProfile, Intp.Extrapolation}
@@ -1107,6 +1108,7 @@ hydrostatically balanced pressure profile.
11071108
"""
11081109
Base.@kwdef struct DYCOMS_RF01 <: InitialCondition
11091110
prognostic_tke::Bool = false
1111+
11101112
end
11111113

11121114
"""
@@ -1117,45 +1119,111 @@ hydrostatically balanced pressure profile.
11171119
"""
11181120
Base.@kwdef struct DYCOMS_RF02 <: InitialCondition
11191121
prognostic_tke::Bool = false
1122+
q_tot_0_dycoms_rf02::Any
1123+
theta_0_dycoms_rf02::Any
1124+
theta_i_dycoms_rf02::Any
1125+
z_i_dycoms_rf02::Any
11201126
end
11211127

1128+
""" [Ackerman2009](@cite) """
1129+
Dycoms_RF02_θ_liq_ice(::Type{FT}, theta_0, theta_i, z_i) where {FT} =
1130+
APL.ZProfile(z -> if z <= z_i
1131+
FT(theta_0)
1132+
else
1133+
FT(theta_i) + (z - FT(z_i))^FT(1.0 / 3.0)
1134+
end)
1135+
1136+
""" [Ackerman2009](@cite) """
1137+
Dycoms_RF02_q_tot(::Type{FT}, q_tot_0, z_i) where {FT} = APL.ZProfile(
1138+
z -> if z <= z_i
1139+
FT(q_tot_0) / FT(1000.0)
1140+
else
1141+
(FT(5) - FT(3) * (FT(1) - exp(-(z - FT(z_i)) / FT(500)))) / FT(1000)
1142+
end,
1143+
)
1144+
11221145
for IC in (:Dycoms_RF01, :Dycoms_RF02)
11231146
IC_Type = Symbol(uppercase(string(IC)))
11241147
θ_func_name = Symbol(IC, :_θ_liq_ice)
11251148
q_tot_func_name = Symbol(IC, :_q_tot)
11261149
u_func_name = Symbol(IC, IC == :Dycoms_RF01 ? :_u0 : :_u)
11271150
v_func_name = Symbol(IC, IC == :Dycoms_RF01 ? :_v0 : :_v)
11281151
tke_func_name = Symbol(IC, :_tke_prescribed)
1129-
@eval function (initial_condition::$IC_Type)(params)
1130-
(; prognostic_tke) = initial_condition
1131-
FT = eltype(params)
1132-
thermo_params = CAP.thermodynamics_params(params)
1133-
p_0 = FT(101780.0)
1134-
θ = APL.$θ_func_name(FT)
1135-
q_tot = APL.$q_tot_func_name(FT)
1136-
p = hydrostatic_pressure_profile(; thermo_params, p_0, θ, q_tot)
1137-
u = APL.$u_func_name(FT)
1138-
v = APL.$v_func_name(FT)
1139-
#tke = APL.$tke_func_name(FT)
1140-
tke = APL.Dycoms_RF01_tke_prescribed(FT) #TODO - dont have the tke profile for Dycoms_RF02
1141-
function local_state(local_geometry)
1142-
(; z) = local_geometry.coordinates
1143-
return LocalState(;
1144-
params,
1145-
geometry = local_geometry,
1146-
thermo_state = TD.PhaseEquil_pθq(
1147-
thermo_params,
1148-
p(z),
1149-
θ(z),
1150-
q_tot(z),
1151-
),
1152-
velocity = Geometry.UVVector(u(z), v(z)),
1153-
turbconv_state = EDMFState(;
1154-
tke = prognostic_tke ? FT(0) : tke(z),
1155-
),
1152+
if IC == :Dycoms_RF02
1153+
@eval function (initial_condition::$IC_Type)(params)
1154+
(;
1155+
prognostic_tke,
1156+
q_tot_0_dycoms_rf02,
1157+
theta_0_dycoms_rf02,
1158+
theta_i_dycoms_rf02,
1159+
z_i_dycoms_rf02,
1160+
) = initial_condition
1161+
FT = eltype(params)
1162+
thermo_params = CAP.thermodynamics_params(params)
1163+
p_0 = FT(101780.0)
1164+
θ = $θ_func_name(
1165+
FT,
1166+
theta_0_dycoms_rf02,
1167+
theta_i_dycoms_rf02,
1168+
z_i_dycoms_rf02,
11561169
)
1170+
q_tot = $q_tot_func_name(FT, q_tot_0_dycoms_rf02, z_i_dycoms_rf02)
1171+
p = hydrostatic_pressure_profile(; thermo_params, p_0, θ, q_tot)
1172+
u = APL.$u_func_name(FT)
1173+
v = APL.$v_func_name(FT)
1174+
#tke = APL.$tke_func_name(FT)
1175+
tke = APL.Dycoms_RF01_tke_prescribed(FT) #TODO - dont have the tke profile for Dycoms_RF02
1176+
function local_state(local_geometry)
1177+
(; z) = local_geometry.coordinates
1178+
return LocalState(;
1179+
params,
1180+
geometry = local_geometry,
1181+
thermo_state = TD.PhaseEquil_pθq(
1182+
thermo_params,
1183+
p(z),
1184+
θ(z),
1185+
q_tot(z),
1186+
),
1187+
velocity = Geometry.UVVector(u(z), v(z)),
1188+
turbconv_state = EDMFState(;
1189+
tke = prognostic_tke ? FT(0) : tke(z),
1190+
),
1191+
)
1192+
end
1193+
return local_state
1194+
end
1195+
else
1196+
@eval function (initial_condition::$IC_Type)(params)
1197+
(; prognostic_tke) = initial_condition
1198+
FT = eltype(params)
1199+
thermo_params = CAP.thermodynamics_params(params)
1200+
p_0 = FT(101780.0)
1201+
θ = APL.$θ_func_name(FT)
1202+
q_tot = APL.$q_tot_func_name(FT)
1203+
p = hydrostatic_pressure_profile(; thermo_params, p_0, θ, q_tot)
1204+
u = APL.$u_func_name(FT)
1205+
v = APL.$v_func_name(FT)
1206+
#tke = APL.$tke_func_name(FT)
1207+
tke = APL.Dycoms_RF01_tke_prescribed(FT) #TODO - dont have the tke profile for Dycoms_RF02
1208+
function local_state(local_geometry)
1209+
(; z) = local_geometry.coordinates
1210+
return LocalState(;
1211+
params,
1212+
geometry = local_geometry,
1213+
thermo_state = TD.PhaseEquil_pθq(
1214+
thermo_params,
1215+
p(z),
1216+
θ(z),
1217+
q_tot(z),
1218+
),
1219+
velocity = Geometry.UVVector(u(z), v(z)),
1220+
turbconv_state = EDMFState(;
1221+
tke = prognostic_tke ? FT(0) : tke(z),
1222+
),
1223+
)
1224+
end
1225+
return local_state
11571226
end
1158-
return local_state
11591227
end
11601228
end
11611229

src/solver/type_getters.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,14 +381,21 @@ function get_initial_condition(parsed_args, atmos)
381381
"LifeCycleTan2018",
382382
"ARM_SGP",
383383
"DYCOMS_RF01",
384-
"DYCOMS_RF02",
385384
"Rico",
386385
"TRMM_LBA",
387386
"SimplePlume",
388387
]
389388
return getproperty(ICs, Symbol(parsed_args["initial_condition"]))(
390389
parsed_args["prognostic_tke"],
391390
)
391+
elseif parsed_args["initial_condition"] == "DYCOMS_RF02"
392+
return getproperty(ICs, Symbol(parsed_args["initial_condition"]))(
393+
parsed_args["prognostic_tke"],
394+
parsed_args["q_tot_0_dycoms_rf02"],
395+
parsed_args["theta_0_dycoms_rf02"],
396+
parsed_args["theta_i_dycoms_rf02"],
397+
parsed_args["z_i_dycoms_rf02"],
398+
)
392399
elseif parsed_args["initial_condition"] == "ISDAC"
393400
ICs.ISDAC(
394401
parsed_args["prognostic_tke"],

0 commit comments

Comments
 (0)