diff --git a/driver/Cases.jl b/driver/Cases.jl index 7738d464dc..9670d00e56 100644 --- a/driver/Cases.jl +++ b/driver/Cases.jl @@ -1110,7 +1110,25 @@ end ##### LES_driven_SCM ##### -forcing_kwargs(::LES_driven_SCM, namelist) = (; nudge_tau = namelist["forcing"]["nudging_timescale"]) +function forcing_kwargs(::LES_driven_SCM, namelist) + les_filename = namelist["meta"]["lesfile"] + cfsite_number, forcing_model, month, experiment = TC.parse_les_path(les_filename) + LES_library = TC.get_LES_library() + les_type = LES_library[forcing_model][string(month, pad = 2)]["cfsite_numbers"][string(cfsite_number, pad = 2)] + if les_type == "shallow" + wind_nudge_τᵣ = 6.0 * 3600.0 + scalar_nudge_zᵢ = 3000.0 + scalar_nudge_zᵣ = 3500.0 + scalar_nudge_τᵣ = 24.0 * 3600.0 + elseif les_type == "deep" + wind_nudge_τᵣ = 3600.0 + scalar_nudge_zᵢ = 16000.0 + scalar_nudge_zᵣ = 20000.0 + scalar_nudge_τᵣ = 2.0 * 3600.0 + end + + return (; wind_nudge_τᵣ, scalar_nudge_zᵢ, scalar_nudge_zᵣ, scalar_nudge_τᵣ) +end function surface_param_kwargs(::LES_driven_SCM, namelist) les_filename = namelist["meta"]["lesfile"] @@ -1129,8 +1147,8 @@ function surface_param_kwargs(::LES_driven_SCM, namelist) return (; LESDat) end -function ForcingBase(case::LES_driven_SCM, param_set::APS; nudge_tau) - ForcingBase(get_forcing_type(case); apply_coriolis = false, coriolis_param = 0.376e-4, nudge_tau = nudge_tau) +function ForcingBase(case::LES_driven_SCM, param_set::APS; kwargs...) + ForcingBase(get_forcing_type(case); apply_coriolis = false, coriolis_param = 0.376e-4, kwargs...) end function surface_ref_state(::LES_driven_SCM, param_set::APS, namelist) diff --git a/driver/dycore.jl b/driver/dycore.jl index c7738caed0..0dcab46dfa 100644 --- a/driver/dycore.jl +++ b/driver/dycore.jl @@ -442,10 +442,10 @@ function compute_gm_tendencies!( if TC.force_type(force) <: TC.ForcingLES H_fluc = aux_gm.dTdt_fluc[k] / Π - gm_U_nudge_k = (aux_gm.u_nudge[k] - prog_gm.u[k]) / force.nudge_tau - gm_V_nudge_k = (aux_gm.v_nudge[k] - prog_gm.v[k]) / force.nudge_tau + gm_U_nudge_k = (aux_gm.u_nudge[k] - prog_gm.u[k]) / force.wind_nudge_τᵣ + gm_V_nudge_k = (aux_gm.v_nudge[k] - prog_gm.v[k]) / force.wind_nudge_τᵣ - Γᵣ = TC.compute_les_Γᵣ(grid.zc[k]) + Γᵣ = TC.compute_les_Γᵣ(grid.zc[k], force.scalar_nudge_τᵣ, force.scalar_nudge_zᵢ, force.scalar_nudge_zᵣ) gm_H_nudge_k = Γᵣ * (aux_gm.H_nudge[k] - aux_gm.θ_liq_ice[k]) gm_q_tot_nudge_k = Γᵣ * (aux_gm.qt_nudge[k] - aux_gm.q_tot[k]) if edmf.moisture_model isa TC.NonEquilibriumMoisture diff --git a/driver/generate_namelist.jl b/driver/generate_namelist.jl index b769ed7553..f5f280a455 100644 --- a/driver/generate_namelist.jl +++ b/driver/generate_namelist.jl @@ -532,12 +532,12 @@ function LES_driven_SCM(namelist_defaults) # average in 1 hour interval around `t_interval_from_end_s` namelist["initial_condition_averaging_window_s"] = 3600.0 + # LES filename should follow pattern: + # Stats.cfsite___2004-2008..nc namelist["meta"]["lesfile"] = joinpath(les_driven_scm_data_folder(), "Stats.cfsite23_HadGEM2-A_amip_2004-2008.07.nc") namelist["meta"]["simname"] = "LES_driven_SCM" namelist["meta"]["casename"] = "LES_driven_SCM" - namelist["forcing"] = Dict() - namelist["forcing"]["nudging_timescale"] = 6.0 * 3600.0 return namelist end diff --git a/driver/main.jl b/driver/main.jl index 4788aff79b..0211de5010 100644 --- a/driver/main.jl +++ b/driver/main.jl @@ -256,6 +256,7 @@ function construct_grid(namelist; FT = Float64) ) les_filename = namelist["meta"]["lesfile"] + TC.valid_lespath(les_filename) zmax = NC.Dataset(les_filename, "r") do data Array(TC.get_nc_data(data, "zf"))[end] end diff --git a/src/types.jl b/src/types.jl index c18ff74aaf..f71c4ce424 100644 --- a/src/types.jl +++ b/src/types.jl @@ -394,8 +394,14 @@ Base.@kwdef struct ForcingBase{T, R} apply_coriolis::Bool = false "Coriolis parameter" coriolis_param::Float64 = 0 - "Momentum relaxation timescale" - nudge_tau::Float64 = 0.0 + "Wind relaxation timescale" + wind_nudge_τᵣ::Float64 = 0.0 + "Scalar relaxation lower z" + scalar_nudge_zᵢ::Float64 = 0.0 + "Scalar relaxation upper z" + scalar_nudge_zᵣ::Float64 = 0.0 + "Scalar maximum relaxation timescale" + scalar_nudge_τᵣ::Float64 = 0.0 "Radiative forcing" rad::R end diff --git a/src/utility_functions.jl b/src/utility_functions.jl index 215d8445c0..1ae741c91d 100644 --- a/src/utility_functions.jl +++ b/src/utility_functions.jl @@ -70,3 +70,77 @@ function compare(a::F, b::F, pn0 = "") where {F <: CC.Fields.Field} end end end +### Utility functions for LES_driven_SCM cases +""" + get_LES_library +Hierarchical dictionary of available LES simulations described in [Shen2022](@cite). +The following cfsites are available across listed models, months, +and experiments. +""" +function get_LES_library() + LES_library = Dict("HadGEM2-A" => Dict(), "CNRM-CM5" => Dict(), "CNRM-CM6-1" => Dict()) + Shen_et_al_sites = collect(2:15) + append!(Shen_et_al_sites, collect(17:23)) + Shen_et_al_deep_convection_sites = (collect(30:33)..., collect(66:70)..., 82, 92, 94, 96, 99, 100) + append!(Shen_et_al_sites, Shen_et_al_deep_convection_sites) + + LES_library["HadGEM2-A"]["10"] = Dict() + LES_library["HadGEM2-A"]["10"]["cfsite_numbers"] = setdiff(Shen_et_al_sites, [94, 100]) + LES_library["HadGEM2-A"]["07"] = Dict() + LES_library["HadGEM2-A"]["07"]["cfsite_numbers"] = Shen_et_al_sites + LES_library["HadGEM2-A"]["04"] = Dict() + LES_library["HadGEM2-A"]["04"]["cfsite_numbers"] = setdiff(Shen_et_al_sites, [15, 17, 18, 32, 92, 94]) + LES_library["HadGEM2-A"]["01"] = Dict() + LES_library["HadGEM2-A"]["01"]["cfsite_numbers"] = setdiff(Shen_et_al_sites, [15, 17, 18, 19, 20]) + + for month in ["01", "04", "07", "10"] + LES_library["HadGEM2-A"][month]["experiments"] = ["amip", "amip4K"] + end + + LES_library_full = deepcopy(LES_library) + for month in ["01", "04", "07", "10"] + LES_library_full["HadGEM2-A"][month]["cfsite_numbers"] = Dict() + for cfsite_number in LES_library["HadGEM2-A"][month]["cfsite_numbers"] + if cfsite_number >= 30 + cfsite_number = string(cfsite_number, pad = 2) + LES_library_full["HadGEM2-A"][month]["cfsite_numbers"][cfsite_number] = "deep" + else + cfsite_number = string(cfsite_number, pad = 2) + LES_library_full["HadGEM2-A"][month]["cfsite_numbers"][cfsite_number] = "shallow" + end + end + end + return LES_library_full +end + +""" + parse_les_path(les_path) +Given path to LES stats file, return cfsite_number, forcing_model, month, and experiment from filename. +Inputs: + - les_path - path to les simulation containing stats folder +Outputs: + - cfsite_number :: cfsite number + - forcing_model :: {"HadGEM2-A", "CNRM-CM5", "CNRM-CM6-1", "IPSL-CM6A-LR"} - name of climate model used for forcing. Currently, only "HadGEM2-A" simulations are available reliably. + - month :: {1, 4, 7, 10} - month of simulation. + - experiment :: {"amip", "amip4K"} - experiment from which LES was forced. +""" +function parse_les_path(les_path) + fname = basename(les_path) + fname_split = split(fname, ('.', '_')) + forcing_model = fname_split[3] + experiment = fname_split[4] + month = parse(Int64, fname_split[6]) + cfsite_number = parse(Int64, replace(fname_split[2], "cfsite" => "")) + return (cfsite_number, forcing_model, month, experiment) +end + +function valid_lespath(les_path) + cfsite_number, forcing_model, month, experiment = parse_les_path(les_path) + month = string(month, pad = 2) + cfsite_number = string(cfsite_number, pad = 2) + LES_library = get_LES_library() + @assert forcing_model in keys(LES_library) + @assert month in keys(LES_library[forcing_model]) + @assert cfsite_number in keys(LES_library[forcing_model][month]["cfsite_numbers"]) + @assert experiment in LES_library[forcing_model][month]["experiments"] +end