Skip to content

Commit 143f9ea

Browse files
Merge pull request #3875 from CliMA/ne/atmos_model
Refactor AtmosModel
2 parents 1b253e1 + 0d008f7 commit 143f9ea

File tree

10 files changed

+822
-99
lines changed

10 files changed

+822
-99
lines changed

src/diagnostics/Diagnostics.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ module Diagnostics
22

33
import Dates: Month, Day, Hour, DateTime, Period
44

5-
import ClimaComms
6-
75
import LinearAlgebra: dot
86

7+
import ClimaComms
98
import ClimaCore:
109
Fields, Geometry, InputOutput, Meshes, Spaces, Operators, Domains, Grids
1110
import ClimaCore.Utilities: half
@@ -15,6 +14,9 @@ import Thermodynamics as TD
1514
import ..lazy
1615

1716
import ..AtmosModel
17+
import ..AtmosWater
18+
import ..AtmosRadiation
19+
import ..AtmosTurbconv
1820
import ..AtmosCallback
1921
import ..EveryNSteps
2022

src/diagnostics/default_diagnostics.jl

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,38 @@ function default_diagnostics(
214214
return [average_func(moist_diagnostics...; output_writer, start_date)...]
215215
end
216216

217+
function default_diagnostics(
218+
atmos_water::AtmosWater,
219+
duration,
220+
start_date;
221+
output_writer,
222+
)
223+
diagnostics = []
224+
225+
# Add moisture and precipitation model diagnostics
226+
for model in (atmos_water.moisture_model, atmos_water.precip_model)
227+
!isnothing(model) && append!(
228+
diagnostics,
229+
default_diagnostics(model, duration, start_date; output_writer),
230+
)
231+
end
232+
233+
return diagnostics
234+
end
235+
217236
#######################
218237
# Precipitation model #
219238
#######################
239+
function default_diagnostics(
240+
::Microphysics0Moment,
241+
duration,
242+
start_date;
243+
output_writer,
244+
)
245+
# 0-moment microphysics doesn't have additional diagnostics beyond basic moisture
246+
return []
247+
end
248+
220249
function default_diagnostics(
221250
::Microphysics1Moment,
222251
duration,
@@ -401,3 +430,41 @@ function default_diagnostics(::EDOnlyEDMFX, duration, start_date; output_writer)
401430
average_func(edonly_edmfx_diagnostics...; output_writer, start_date)...,
402431
]
403432
end
433+
434+
function default_diagnostics(
435+
atmos_radiation::AtmosRadiation,
436+
duration,
437+
start_date;
438+
output_writer,
439+
)
440+
# Add radiation mode diagnostics
441+
if !isnothing(atmos_radiation.radiation_mode)
442+
return default_diagnostics(
443+
atmos_radiation.radiation_mode,
444+
duration,
445+
start_date;
446+
output_writer,
447+
)
448+
else
449+
return []
450+
end
451+
end
452+
453+
function default_diagnostics(
454+
atmos_turbconv::AtmosTurbconv,
455+
duration,
456+
start_date;
457+
output_writer,
458+
)
459+
# Add turbulence convection model diagnostics
460+
if !isnothing(atmos_turbconv.turbconv_model)
461+
return default_diagnostics(
462+
atmos_turbconv.turbconv_model,
463+
duration,
464+
start_date;
465+
output_writer,
466+
)
467+
else
468+
return []
469+
end
470+
end

src/diagnostics/radiation_diagnostics.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ function compute_rsd!(
4545
cache.radiation.rrtmgp_model.face_sw_flux_dn,
4646
axes(state.f),
4747
)
48-
@assert out !== nothing "Output field 'out' must not be `nothing` in this branch"
48+
@assert !isnothing(out) "Output field 'out' must not be `nothing` in this branch"
4949
radiation_mode.deep_atmosphere &&
5050
apply_geometric_scaling!(out, z_lev, planet_radius, FT)
5151
end

src/parameterized_tendencies/radiation/radiation.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,12 @@ radiation_model_cache(Y, atmos::AtmosModel, args...) =
2828
##### No Radiation
2929
#####
3030

31-
radiation_model_cache(Y, radiation_mode::Nothing; args...) = (;)
32-
radiation_tendency!(Yₜ, Y, p, t, ::Nothing) = nothing
31+
radiation_model_cache(
32+
Y,
33+
radiation_mode::Union{Nothing, HeldSuarezForcing};
34+
args...,
35+
) = (;)
36+
radiation_tendency!(Yₜ, Y, p, t, ::Union{Nothing, HeldSuarezForcing}) = nothing
3337

3438
#####
3539
##### RRTMGP Radiation

src/prognostic_equations/remaining_tendency.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ NVTX.@annotate function additional_tendency!(Yₜ, Y, p, t)
141141
ᶜuₕ = Y.c.uₕ
142142
ᶠu₃ = Y.f.u₃
143143
ᶜρ = Y.c.ρ
144-
(; forcing_type, moisture_model, rayleigh_sponge, viscous_sponge) = p.atmos
144+
(; radiation_mode, moisture_model, rayleigh_sponge, viscous_sponge) =
145+
p.atmos
145146
(; ls_adv, scm_coriolis) = p.atmos
146147
(; params) = p
147148
thermo_params = CAP.thermodynamics_params(params)
@@ -151,7 +152,9 @@ NVTX.@annotate function additional_tendency!(Yₜ, Y, p, t)
151152
vst_u₃ = viscous_sponge_tendency_u₃(ᶠu₃, viscous_sponge)
152153
vst_ρe_tot = viscous_sponge_tendency_ρe_tot(ᶜρ, ᶜh_tot, viscous_sponge)
153154
rst_uₕ = rayleigh_sponge_tendency_uₕ(ᶜuₕ, rayleigh_sponge)
154-
hs_args = (ᶜuₕ, ᶜp, params, sfc_conditions.ts, moisture_model, forcing_type)
155+
# For HeldSuarezForcing, the radiation_mode is used as the forcing parameter
156+
forcing = radiation_mode isa HeldSuarezForcing ? radiation_mode : nothing
157+
hs_args = (ᶜuₕ, ᶜp, params, sfc_conditions.ts, moisture_model, forcing)
155158
hs_tendency_uₕ = held_suarez_forcing_tendency_uₕ(hs_args...)
156159
hs_tendency_ρe_tot = held_suarez_forcing_tendency_ρe_tot(ᶜρ, hs_args...)
157160
edmf_cor_tend_uₕ = scm_coriolis_tendency_uₕ(ᶜuₕ, scm_coriolis)

src/solver/model_getters.jl

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ function get_radiation_mode(parsed_args, ::Type{FT}) where {FT}
246246
"gray",
247247
"allsky",
248248
"allskywithclear",
249+
"held_suarez",
249250
"DYCOMS",
250251
"TRMM_LBA",
251252
"ISDAC",
@@ -286,6 +287,8 @@ function get_radiation_mode(parsed_args, ::Type{FT}) where {FT}
286287
reset_rng_seed,
287288
deep_atmosphere,
288289
)
290+
elseif radiation_name == "held_suarez"
291+
HeldSuarezForcing()
289292
elseif radiation_name == "DYCOMS"
290293
RadiationDYCOMS{FT}()
291294
elseif radiation_name == "TRMM_LBA"
@@ -352,11 +355,11 @@ end
352355
function get_forcing_type(parsed_args)
353356
forcing = parsed_args["forcing"]
354357
@assert forcing in (nothing, "held_suarez")
355-
return if forcing == nothing
356-
nothing
357-
elseif forcing == "held_suarez"
358-
HeldSuarezForcing()
358+
if forcing == "held_suarez"
359+
@warn "The 'held_suarez' forcing option is deprecated. Use rad='held_suarez' instead to set HeldSuarezForcing as a radiation mode."
360+
return HeldSuarezForcing() # Still return the object for backward compatibility
359361
end
362+
return nothing
360363
end
361364

362365
struct CallCloudDiagnosticsPerStage end
@@ -372,7 +375,7 @@ end
372375

373376
function get_subsidence_model(parsed_args, radiation_mode, FT)
374377
subsidence = parsed_args["subsidence"]
375-
subsidence == nothing && return nothing
378+
isnothing(subsidence) && return nothing
376379

377380
prof = if subsidence == "Bomex"
378381
APL.Bomex_subsidence(FT)
@@ -382,6 +385,8 @@ function get_subsidence_model(parsed_args, radiation_mode, FT)
382385
APL.Rico_subsidence(FT)
383386
elseif subsidence == "DYCOMS"
384387
@assert radiation_mode isa RadiationDYCOMS
388+
# For DYCOMS case, subsidence is linearly proportional to height
389+
# with slope equal to the divergence rate specified in radiation mode
385390
z -> -z * radiation_mode.divergence
386391
elseif subsidence == "ISDAC"
387392
APL.ISDAC_subsidence(FT)

src/solver/type_getters.jl

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,11 @@ function get_atmos(config::AtmosConfig, params)
4848
(!isnothing(co2) && !with_rrtmgp) &&
4949
@warn ("$(co2) does nothing if RRTMGP is not used")
5050

51-
disable_momentum_vertical_diffusion = forcing_type isa HeldSuarezForcing
51+
# HeldSuarezForcing can be set via radiation_mode or legacy forcing option for now
52+
final_radiation_mode =
53+
forcing_type isa HeldSuarezForcing ? forcing_type : radiation_mode
54+
disable_momentum_vertical_diffusion =
55+
final_radiation_mode isa HeldSuarezForcing
5256

5357
advection_test = parsed_args["advection_test"]
5458
@assert advection_test in (false, true)
@@ -86,23 +90,38 @@ function get_atmos(config::AtmosConfig, params)
8690
)
8791

8892
atmos = AtmosModel(;
93+
# AtmosWater - Moisture, Precipitation & Clouds
8994
moisture_model,
90-
ozone,
91-
co2,
92-
radiation_mode,
93-
subsidence = get_subsidence_model(parsed_args, radiation_mode, FT),
94-
ls_adv = get_large_scale_advection_model(parsed_args, FT),
95-
external_forcing = get_external_forcing_model(parsed_args, FT),
96-
scm_coriolis = get_scm_coriolis(parsed_args, FT),
97-
advection_test,
98-
edmfx_model,
9995
precip_model,
10096
cloud_model,
10197
noneq_cloud_formation_mode = implicit_noneq_cloud_formation ?
10298
Implicit() : Explicit(),
103-
forcing_type,
10499
call_cloud_diagnostics_per_stage,
100+
101+
# SCMSetup - Single-Column Model components
102+
subsidence = get_subsidence_model(parsed_args, radiation_mode, FT),
103+
external_forcing = get_external_forcing_model(parsed_args, FT),
104+
ls_adv = get_large_scale_advection_model(parsed_args, FT),
105+
advection_test,
106+
scm_coriolis = get_scm_coriolis(parsed_args, FT),
107+
108+
# AtmosRadiation
109+
radiation_mode = final_radiation_mode,
110+
ozone,
111+
co2,
112+
insolation = get_insolation_form(parsed_args),
113+
114+
# AtmosTurbconv - Turbulence & Convection
115+
edmfx_model,
105116
turbconv_model = get_turbconv_model(FT, parsed_args, turbconv_params),
117+
sgs_adv_mode = implicit_sgs_advection ? Implicit() : Explicit(),
118+
sgs_entr_detr_mode = implicit_sgs_entr_detr ? Implicit() : Explicit(),
119+
sgs_nh_pressure_mode = implicit_sgs_nh_pressure ? Implicit() :
120+
Explicit(),
121+
sgs_mf_mode = implicit_sgs_mass_flux ? Implicit() : Explicit(),
122+
smagorinsky_lilly = get_smagorinsky_lilly_model(parsed_args),
123+
124+
# AtmosGravityWave
106125
non_orographic_gravity_wave = get_non_orographic_gravity_wave_model(
107126
parsed_args,
108127
FT,
@@ -111,24 +130,22 @@ function get_atmos(config::AtmosConfig, params)
111130
parsed_args,
112131
FT,
113132
),
114-
hyperdiff = get_hyperdiffusion_model(parsed_args, FT),
115-
vert_diff,
116-
diff_mode = implicit_diffusion ? Implicit() : Explicit(),
117-
sgs_adv_mode = implicit_sgs_advection ? Implicit() : Explicit(),
118-
sgs_entr_detr_mode = implicit_sgs_entr_detr ? Implicit() : Explicit(),
119-
sgs_nh_pressure_mode = implicit_sgs_nh_pressure ? Implicit() :
120-
Explicit(),
121-
sgs_mf_mode = implicit_sgs_mass_flux ? Implicit() : Explicit(),
133+
134+
# AtmosSponge
122135
viscous_sponge = get_viscous_sponge_model(parsed_args, params, FT),
123-
smagorinsky_lilly = get_smagorinsky_lilly_model(parsed_args),
124136
rayleigh_sponge = get_rayleigh_sponge_model(parsed_args, params, FT),
137+
138+
# AtmosSurface
125139
sfc_temperature = get_sfc_temperature_form(parsed_args),
126-
insolation = get_insolation_form(parsed_args),
127-
disable_surface_flux_tendency = parsed_args["disable_surface_flux_tendency"],
128140
surface_model = get_surface_model(parsed_args),
129141
surface_albedo = get_surface_albedo_model(parsed_args, params, FT),
130-
numerics = get_numerics(parsed_args),
142+
143+
# Top-level options (not grouped)
144+
vert_diff,
145+
numerics = get_numerics(parsed_args, FT),
146+
disable_surface_flux_tendency = parsed_args["disable_surface_flux_tendency"],
131147
)
148+
# TODO: Should this go in the AtmosModel constructor?
132149
@assert !@any_reltype(atmos, (UnionAll, DataType))
133150

134151
@info "AtmosModel: \n$(summary(atmos))"
@@ -146,7 +163,7 @@ function get_scale_blending_method(parsed_args)
146163
end
147164
end
148165

149-
function get_numerics(parsed_args)
166+
function get_numerics(parsed_args, FT)
150167
test_dycore =
151168
parsed_args["test_dycore_consistency"] ? TestDycoreConsistency() :
152169
nothing
@@ -173,13 +190,19 @@ function get_numerics(parsed_args)
173190
limiter = parsed_args["apply_limiter"] ? CA.QuasiMonotoneLimiter() : nothing
174191

175192
# wrap each upwinding mode in a Val for dispatch
193+
diff_mode = parsed_args["implicit_diffusion"] ? Implicit() : Explicit()
194+
195+
hyperdiff = get_hyperdiffusion_model(parsed_args, FT)
196+
176197
numerics = AtmosNumerics(;
177198
energy_upwinding,
178199
tracer_upwinding,
179200
edmfx_upwinding,
180201
edmfx_sgsflux_upwinding,
181202
limiter,
182203
test_dycore_consistency = test_dycore,
204+
diff_mode,
205+
hyperdiff,
183206
)
184207
@info "numerics $(summary(numerics))"
185208

0 commit comments

Comments
 (0)