Skip to content

Commit 09770a4

Browse files
Merge pull request #3696 from CliMA/ck/rrtmgp_refactor5
Hoist lookup table logic
2 parents aad291f + 56cfdf2 commit 09770a4

File tree

1 file changed

+154
-99
lines changed

1 file changed

+154
-99
lines changed

src/parameterized_tendencies/radiation/RRTMGPInterface.jl

Lines changed: 154 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,142 @@ function Base.propertynames(model::RRTMGPModel, private::Bool = false)
288288
return private ? (names..., fieldnames(typeof(model))...) : names
289289
end
290290

291+
"""
292+
lookup_tables(::AbstractRRTMGPMode, device, FloatType)
293+
294+
Return a NamedTuple, containing
295+
- RRTMGP lookup tables (varies by radiation mode)
296+
- nbnd_lw
297+
- nbnd_sw
298+
- ngas_lw (absent for GrayRadiation)
299+
- ngas_sw (absent for GrayRadiation)
300+
301+
TODO:
302+
- We should add type annotations for the data read from NC files as this will
303+
improve inference and the return type of `lookup_tables`.
304+
"""
305+
function lookup_tables end
306+
307+
lookup_tables(
308+
radiation_mode::GrayRadiation,
309+
device::ClimaComms.AbstractDevice,
310+
::Type{FT},
311+
) where {FT} = (; lookups = (;), lu_kwargs = (; nbnd_lw = 1, nbnd_sw = 1))
312+
313+
function lookup_tables(
314+
radiation_mode::ClearSkyRadiation,
315+
device::ClimaComms.AbstractDevice,
316+
::Type{FT},
317+
) where {FT}
318+
DA = ClimaComms.array_type(device)
319+
# turn kwargs into a Dict, so that values can be dynamically popped from it
320+
321+
artifact(t, b, n) =
322+
NC.Dataset(RRTMGP.ArtifactPaths.get_lookup_filename(t, b)) do ds
323+
getproperty(RRTMGP.LookUpTables, n)(ds, FT, DA)
324+
end
325+
lookup_lw, idx_gases_lw = artifact(:gas, :lw, :LookUpLW)
326+
327+
nbnd_lw = RRTMGP.LookUpTables.get_n_bnd(lookup_lw)
328+
ngas_lw = RRTMGP.LookUpTables.get_n_gases(lookup_lw)
329+
330+
lookup_lw_aero, idx_aerosol_lw, idx_aerosize_lw =
331+
if radiation_mode.aerosol_radiation
332+
artifact(:aerosol, :lw, :LookUpAerosolMerra)
333+
else
334+
(nothing, nothing, nothing)
335+
end
336+
337+
lookup_sw, idx_gases_sw = artifact(:gas, :sw, :LookUpSW)
338+
339+
nbnd_sw = RRTMGP.LookUpTables.get_n_bnd(lookup_sw)
340+
ngas_sw = RRTMGP.LookUpTables.get_n_gases(lookup_sw)
341+
342+
lookup_sw_aero, idx_aerosol_sw, idx_aerosize_sw =
343+
if radiation_mode.aerosol_radiation
344+
artifact(:aerosol, :sw, :LookUpAerosolMerra)
345+
else
346+
(nothing, nothing, nothing)
347+
end
348+
349+
lookups = (;
350+
idx_aerosize_lw,
351+
idx_aerosize_sw,
352+
idx_aerosol_lw,
353+
idx_aerosol_sw,
354+
idx_gases_lw,
355+
idx_gases_sw,
356+
lookup_lw,
357+
lookup_lw_aero,
358+
lookup_sw,
359+
lookup_sw_aero,
360+
)
361+
362+
@assert RRTMGP.LookUpTables.get_n_gases(lookup_lw) ==
363+
RRTMGP.LookUpTables.get_n_gases(lookup_sw)
364+
@assert lookup_lw.p_ref_min == lookup_sw.p_ref_min
365+
return (; lookups, lu_kwargs = (; nbnd_lw, ngas_lw, nbnd_sw, ngas_sw))
366+
end
367+
368+
function lookup_tables(
369+
radiation_mode::Union{
370+
AllSkyRadiation,
371+
AllSkyRadiationWithClearSkyDiagnostics,
372+
},
373+
device::ClimaComms.AbstractDevice,
374+
::Type{FT},
375+
) where {FT}
376+
DA = ClimaComms.array_type(device)
377+
# turn kwargs into a Dict, so that values can be dynamically popped from it
378+
379+
artifact(t, b, n) =
380+
NC.Dataset(RRTMGP.ArtifactPaths.get_lookup_filename(t, b)) do ds
381+
getproperty(RRTMGP.LookUpTables, n)(ds, FT, DA)
382+
end
383+
lookup_lw, idx_gases_lw = artifact(:gas, :lw, :LookUpLW)
384+
lookup_lw_cld = artifact(:cloud, :lw, :LookUpCld)
385+
lookup_lw_aero, idx_aerosol_lw, idx_aerosize_lw =
386+
if radiation_mode.aerosol_radiation
387+
artifact(:aerosol, :lw, :LookUpAerosolMerra)
388+
else
389+
(nothing, nothing, nothing)
390+
end
391+
lookup_sw, idx_gases_sw = artifact(:gas, :sw, :LookUpSW)
392+
lookup_sw_cld = artifact(:cloud, :sw, :LookUpCld)
393+
394+
lookup_sw_aero, idx_aerosol_sw, idx_aerosize_sw =
395+
if radiation_mode.aerosol_radiation
396+
artifact(:aerosol, :sw, :LookUpAerosolMerra)
397+
else
398+
(nothing, nothing, nothing)
399+
end
400+
401+
nbnd_lw = RRTMGP.LookUpTables.get_n_bnd(lookup_lw)
402+
ngas_lw = RRTMGP.LookUpTables.get_n_gases(lookup_lw)
403+
nbnd_sw = RRTMGP.LookUpTables.get_n_bnd(lookup_sw)
404+
ngas_sw = RRTMGP.LookUpTables.get_n_gases(lookup_sw)
405+
406+
lookups = (;
407+
idx_aerosize_lw,
408+
idx_aerosize_sw,
409+
idx_aerosol_lw,
410+
idx_aerosol_sw,
411+
idx_gases_lw,
412+
idx_gases_sw,
413+
lookup_lw,
414+
lookup_lw_aero,
415+
lookup_lw_cld,
416+
lookup_sw,
417+
lookup_sw_aero,
418+
lookup_sw_cld,
419+
)
420+
421+
@assert RRTMGP.LookUpTables.get_n_gases(lookup_lw) ==
422+
RRTMGP.LookUpTables.get_n_gases(lookup_sw)
423+
@assert lookup_lw.p_ref_min == lookup_sw.p_ref_min
424+
return (; lookups, lu_kwargs = (; nbnd_lw, ngas_lw, nbnd_sw, ngas_sw))
425+
end
426+
291427
"""
292428
RRTMGPModel(params; kwargs...)
293429
@@ -454,47 +590,12 @@ function _RRTMGPModel(
454590
pressures/temperatures are specified")
455591
end
456592

457-
lookups = NamedTuple()
593+
(; lookups, lu_kwargs) = lookup_tables(radiation_mode, device, FT)
458594
views = []
459595

460596
nlay = domain_nlay + Int(radiation_mode.add_isothermal_boundary_layer)
461597
t = (views, domain_nlay)
462598

463-
if radiation_mode isa GrayRadiation
464-
nbnd_lw = 1
465-
else
466-
local lookup_lw, idx_gases
467-
NC.Dataset(RRTMGP.ArtifactPaths.get_lookup_filename(:gas, :lw)) do ds
468-
lookup_lw, idx_gases = RRTMGP.LookUpTables.LookUpLW(ds, FT, DA)
469-
end
470-
lookups = (; lookups..., lookup_lw, idx_gases)
471-
472-
nbnd_lw = RRTMGP.LookUpTables.get_n_bnd(lookup_lw)
473-
ngas = RRTMGP.LookUpTables.get_n_gases(lookup_lw)
474-
475-
if !(radiation_mode isa ClearSkyRadiation)
476-
local lookup_lw_cld
477-
NC.Dataset(
478-
RRTMGP.ArtifactPaths.get_lookup_filename(:cloud, :lw),
479-
) do ds
480-
lookup_lw_cld = RRTMGP.LookUpTables.LookUpCld(ds, FT, DA)
481-
end
482-
lookups = (; lookups..., lookup_lw_cld)
483-
end
484-
if radiation_mode.aerosol_radiation
485-
local lookup_lw_aero, idx_aerosol, idx_aerosize
486-
NC.Dataset(
487-
RRTMGP.ArtifactPaths.get_lookup_filename(:aerosol, :lw),
488-
) do ds
489-
lookup_lw_aero, idx_aerosol, idx_aerosize =
490-
RRTMGP.LookUpTables.LookUpAerosolMerra(ds, FT, DA)
491-
end
492-
else
493-
lookup_lw_aero = nothing
494-
end
495-
lookups = (; lookups..., lookup_lw_aero)
496-
end
497-
498599
src_lw = RRTMGP.Sources.source_func_longwave(
499600
params,
500601
FT,
@@ -517,7 +618,7 @@ function _RRTMGPModel(
517618
set_and_save!(flux_lw2.flux_net, "face_clear_lw_flux", t...)
518619
end
519620

520-
sfc_emis = DA{FT}(undef, nbnd_lw, ncol)
621+
sfc_emis = DA{FT}(undef, lu_kwargs.nbnd_lw, ncol)
521622
set_and_save!(sfc_emis, "surface_emissivity", t..., dict)
522623
name = "top_of_atmosphere_lw_flux_dn"
523624
if Symbol(name) in keys(dict)
@@ -527,43 +628,6 @@ function _RRTMGPModel(
527628
inc_flux = nothing
528629
end
529630
bcs_lw = RRTMGP.BCs.LwBCs(sfc_emis, inc_flux)
530-
531-
if radiation_mode isa GrayRadiation
532-
nbnd_sw = 1
533-
else
534-
local lookup_sw, idx_gases
535-
NC.Dataset(RRTMGP.ArtifactPaths.get_lookup_filename(:gas, :sw)) do ds
536-
lookup_sw, idx_gases = RRTMGP.LookUpTables.LookUpSW(ds, FT, DA)
537-
end
538-
lookups = (; lookups..., lookup_sw, idx_gases)
539-
540-
nbnd_sw = RRTMGP.LookUpTables.get_n_bnd(lookup_sw)
541-
ngas = RRTMGP.LookUpTables.get_n_gases(lookup_sw)
542-
543-
if !(radiation_mode isa ClearSkyRadiation)
544-
local lookup_sw_cld
545-
NC.Dataset(
546-
RRTMGP.ArtifactPaths.get_lookup_filename(:cloud, :sw),
547-
) do ds
548-
lookup_sw_cld = RRTMGP.LookUpTables.LookUpCld(ds, FT, DA)
549-
end
550-
lookups = (; lookups..., lookup_sw_cld)
551-
end
552-
553-
if radiation_mode.aerosol_radiation
554-
local lookup_sw_aero, idx_aerosol, idx_aerosize
555-
NC.Dataset(
556-
RRTMGP.ArtifactPaths.get_lookup_filename(:aerosol, :sw),
557-
) do ds
558-
lookup_sw_aero, idx_aerosol, idx_aerosize =
559-
RRTMGP.LookUpTables.LookUpAerosolMerra(ds, FT, DA)
560-
end
561-
else
562-
lookup_sw_aero = nothing
563-
end
564-
lookups = (; lookups..., lookup_sw_aero)
565-
end
566-
567631
src_sw =
568632
RRTMGP.Sources.source_func_shortwave(FT, ncol, nlay, :TwoStream, DA)
569633
flux_sw = RRTMGP.Fluxes.FluxSW(ncol, nlay, FT, DA)
@@ -590,9 +654,9 @@ function _RRTMGPModel(
590654
set_and_save!(cos_zenith, "cos_zenith", t..., dict)
591655
toa_flux = DA{FT}(undef, ncol)
592656
set_and_save!(toa_flux, "weighted_irradiance", t..., dict)
593-
sfc_alb_direct = DA{FT}(undef, nbnd_sw, ncol)
657+
sfc_alb_direct = DA{FT}(undef, lu_kwargs.nbnd_sw, ncol)
594658
set_and_save!(sfc_alb_direct, "direct_sw_surface_albedo", t..., dict)
595-
sfc_alb_diffuse = DA{FT}(undef, nbnd_sw, ncol)
659+
sfc_alb_diffuse = DA{FT}(undef, lu_kwargs.nbnd_sw, ncol)
596660
set_and_save!(sfc_alb_diffuse, "diffuse_sw_surface_albedo", t..., dict)
597661
name = "top_of_atmosphere_diffuse_sw_flux_dn"
598662
if Symbol(name) in keys(dict)
@@ -615,11 +679,6 @@ function _RRTMGPModel(
615679
if radiation_mode isa AllSkyRadiationWithClearSkyDiagnostics
616680
set_and_save!(similar(flux_lw2.flux_net), "face_clear_flux", t...)
617681
end
618-
if !(radiation_mode isa GrayRadiation)
619-
@assert RRTMGP.LookUpTables.get_n_gases(lookup_lw) ==
620-
RRTMGP.LookUpTables.get_n_gases(lookup_sw)
621-
@assert lookup_lw.p_ref_min == lookup_sw.p_ref_min
622-
end
623682

624683
if !(:latitude in keys(dict))
625684
lon = lat = nothing
@@ -643,13 +702,9 @@ function _RRTMGPModel(
643702
z_lev = DA{FT}(undef, nlay + 1, ncol) # TODO: z_lev required but unused
644703

645704
# lapse_rate is a constant, so don't use set_and_save! to get it
646-
if !(:lapse_rate in keys(dict))
647-
throw(UndefKeywordError(:lapse_rate))
648-
end
705+
:lapse_rate in keys(dict) || throw(UndefKeywordError(:lapse_rate))
649706
α = pop!(dict, :lapse_rate)
650-
if !isa Real)
651-
error("lapse_rate must be a Real")
652-
end
707+
α isa Real || error("lapse_rate must be a Real")
653708

654709
d0 = DA{FT}(undef, ncol)
655710
set_and_save!(d0, "optical_thickness_parameter", t..., dict)
@@ -676,7 +731,7 @@ function _RRTMGPModel(
676731
gas_names = filter(
677732
gas_name ->
678733
!(gas_name in ("h2o", "h2o_frgn", "h2o_self", "o3")),
679-
keys(idx_gases),
734+
keys(lookups.idx_gases_sw),
680735
)
681736
# TODO: This gives the wrong types for CUDA 3.4 and above.
682737
# gm = use_global_means_for_well_mixed_gases
@@ -685,19 +740,19 @@ function _RRTMGPModel(
685740
vmr = RRTMGP.Vmrs.VmrGM(
686741
DA{FT}(undef, nlay, ncol),
687742
DA{FT}(undef, nlay, ncol),
688-
DA{FT}(undef, ngas),
743+
DA{FT}(undef, lu_kwargs.ngas_sw),
689744
)
690745
vmr.vmr .= 0 # TODO: do we need this?
691746
set_and_save!(vmr.vmr_h2o, "center_$(vmr_str)h2o", t..., dict)
692747
set_and_save!(vmr.vmr_o3, "center_$(vmr_str)o3", t..., dict)
693748
for gas_name in gas_names
694-
gas_view = view(vmr.vmr, idx_gases[gas_name])
749+
gas_view = view(vmr.vmr, lookups.idx_gases_sw[gas_name])
695750
set_and_save!(gas_view, "$vmr_str$gas_name", t..., dict)
696751
end
697752
else
698-
vmr = RRTMGP.Vmrs.Vmr(DA{FT}(undef, ngas, nlay, ncol))
753+
vmr = RRTMGP.Vmrs.Vmr(DA{FT}(undef, lu_kwargs.ngas_sw, nlay, ncol))
699754
for gas_name in ["h2o", "o3", gas_names...]
700-
gas_view = view(vmr.vmr, idx_gases[gas_name], :, :)
755+
gas_view = view(vmr.vmr, lookups.idx_gases_sw[gas_name], :, :)
701756
set_and_save!(gas_view, "center_$vmr_str$gas_name", t..., dict)
702757
end
703758
end
@@ -752,8 +807,8 @@ function _RRTMGPModel(
752807
set_and_save!(aod_sw_ext, "aod_sw_extinction", t..., dict)
753808
set_and_save!(aod_sw_sca, "aod_sw_scattering", t..., dict)
754809

755-
n_aerosol_sizes = maximum(values(idx_aerosize))
756-
n_aerosols = length(idx_aerosol)
810+
n_aerosol_sizes = maximum(values(lookups.idx_aerosize_sw)) # TODO: verify correctness
811+
n_aerosols = length(lookups.idx_aerosol_sw) # TODO: verify correctness
757812
# See the lookup table in RRTMGP for the order of aerosols
758813
aero_size = DA{FT}(undef, n_aerosol_sizes, nlay, ncol)
759814
aero_mass = DA{FT}(undef, n_aerosols, nlay, ncol)
@@ -973,7 +1028,7 @@ get_p_min(model) = get_p_min(model.as, model.lookups)
9731028
get_p_min(as::RRTMGP.AtmosphericStates.GrayAtmosphericState, lookups) =
9741029
zero(eltype(as.p_lay))
9751030
get_p_min(as::RRTMGP.AtmosphericStates.AtmosphericState, lookups) =
976-
lookups[1].p_ref_min
1031+
lookups.lookup_lw.p_ref_min # TODO: verify correctness
9771032

9781033
function update_implied_values!(model)
9791034
(; p_lev, t_lev, t_sfc) = model.as
@@ -1090,12 +1145,12 @@ update_concentrations!(radiation_mode, model) = RRTMGP.Optics.compute_col_gas!(
10901145
model.as.p_lev,
10911146
AS.getview_col_dry(model.as),
10921147
model.params,
1093-
get_vmr_h2o(model.as.vmr, model.lookups.idx_gases),
1148+
get_vmr_h2o(model.as.vmr, model.lookups.idx_gases_sw),
10941149
model.as.lat,
10951150
)
1096-
get_vmr_h2o(vmr::RRTMGP.Vmrs.VmrGM, idx_gases) = vmr.vmr_h2o
1097-
get_vmr_h2o(vmr::RRTMGP.Vmrs.Vmr, idx_gases) =
1098-
view(vmr.vmr, idx_gases["h2o"], :, :)
1151+
get_vmr_h2o(vmr::RRTMGP.Vmrs.VmrGM, idx_gases_sw) = vmr.vmr_h2o
1152+
get_vmr_h2o(vmr::RRTMGP.Vmrs.Vmr, idx_gases_sw) =
1153+
view(vmr.vmr, idx_gases_sw["h2o"], :, :)
10991154

11001155
NVTX.@annotate update_lw_fluxes!(::GrayRadiation, model) =
11011156
RRTMGP.RTESolver.solve_lw!(model.lw_solver, model.as)

0 commit comments

Comments
 (0)