Skip to content

Commit 05d5aa3

Browse files
committed
break up AtmosModel constructor
1 parent 0352480 commit 05d5aa3

File tree

5 files changed

+256
-248
lines changed

5 files changed

+256
-248
lines changed

src/diagnostics/Diagnostics.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import Thermodynamics as TD
1414
import ..lazy
1515

1616
import ..AtmosModel
17-
import ..AtmosHydrology
17+
import ..AtmosWater
1818
import ..AtmosRadiation
1919
import ..AtmosTurbconv
2020
import ..AtmosCallback

src/diagnostics/default_diagnostics.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ function default_diagnostics(
215215
end
216216

217217
function default_diagnostics(
218-
atmos_hydrology::AtmosHydrology,
218+
atmos_hydrology::AtmosWater,
219219
duration,
220220
start_date;
221221
output_writer,

src/solver/type_getters.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ function get_atmos(config::AtmosConfig, params)
8686
)
8787

8888
atmos = AtmosModel(;
89-
# AtmosHydrology - Moisture, Precipitation & Clouds
89+
# AtmosWater - Moisture, Precipitation & Clouds
9090
moisture_model,
9191
precip_model,
9292
cloud_model,

src/solver/types.jl

Lines changed: 96 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -520,11 +520,11 @@ end
520520
# Grouped structs to reduce AtmosModel type parameters
521521

522522
"""
523-
AtmosHydrology
523+
AtmosWater
524524
525525
Groups moisture-related models and types.
526526
"""
527-
Base.@kwdef struct AtmosHydrology{MM, PM, CM, NCFM, CCDPS}
527+
Base.@kwdef struct AtmosWater{MM, PM, CM, NCFM, CCDPS}
528528
moisture_model::MM = nothing
529529
precip_model::PM = nothing
530530
cloud_model::CM = nothing
@@ -613,7 +613,7 @@ Base.@kwdef struct AtmosSurface{ST, SM, SA}
613613
end
614614

615615
# Add broadcastable for the new grouped types
616-
Base.broadcastable(x::AtmosHydrology) = tuple(x)
616+
Base.broadcastable(x::AtmosWater) = tuple(x)
617617
Base.broadcastable(x::AtmosForcing) = tuple(x)
618618
Base.broadcastable(x::AtmosRadiation) = tuple(x)
619619
Base.broadcastable(x::AtmosAdvection) = tuple(x)
@@ -639,10 +639,9 @@ struct AtmosModel{H, F, R, A, TC, GW, HD, VD, SP, SU, NU}
639639
disable_surface_flux_tendency::Bool
640640
end
641641

642-
# BACKWARD COMPATIBILITY FOR AtmosModel
643642
# Map grouped struct types to their names in AtmosModel struct
644643
const ATMOS_MODEL_GROUPS = (
645-
(AtmosHydrology, :hydrology),
644+
(AtmosWater, :hydrology),
646645
(AtmosForcing, :forcing),
647646
(AtmosRadiation, :radiation),
648647
(AtmosAdvection, :advection),
@@ -653,17 +652,12 @@ const ATMOS_MODEL_GROUPS = (
653652
(AtmosNumerics, :numerics),
654653
)
655654

656-
# Auto-generate map from property_name to group_field
657-
# Use let closure to avoid polluting module scope with temporary variables
658-
const GROUPED_PROPERTY_MAP = let
659-
property_map = Dict{Symbol, Symbol}()
660-
for (group_type, group_field) in ATMOS_MODEL_GROUPS
661-
for property in fieldnames(group_type)
662-
property_map[property] = group_field
663-
end
664-
end
665-
property_map
666-
end
655+
# Auto-generate map from property_name to group_field
656+
const GROUPED_PROPERTY_MAP = Dict{Symbol, Symbol}(
657+
property => group_field for
658+
(group_type, group_field) in ATMOS_MODEL_GROUPS for
659+
property in fieldnames(group_type)
660+
)
667661

668662
# Forward property access: atmos.moisture_model → atmos.moisture.moisture_model
669663
# Use ::Val constant for @generated compile-time access
@@ -729,7 +723,7 @@ This constructor provides sensible defaults for a minimal dry atmospheric model
729723
730724
All model components are automatically organized into appropriate grouped sub-structs
731725
internally:
732-
- [`AtmosHydrology`](@ref)
726+
- [`AtmosWater`](@ref)
733727
- [`AtmosForcing`](@ref)
734728
- [`AtmosRadiation`](@ref)
735729
- [`AtmosAdvection`](@ref)
@@ -779,7 +773,7 @@ The default AtmosModel provides:
779773
780774
# Available Structs
781775
782-
## AtmosHydrology
776+
## AtmosWater
783777
- `moisture_model`: DryModel(), EquilMoistModel(), NonEquilMoistModel()
784778
- `precip_model`: NoPrecipitation(), Microphysics0Moment(), Microphysics1Moment(), Microphysics2Moment()
785779
- `cloud_model`: GridScaleCloud(), QuadratureCloud(), SGSQuadratureCloud()
@@ -834,76 +828,9 @@ The default AtmosModel provides:
834828
- Property access works both ways: `model.moisture_model` and `model.hydrology.moisture_model`
835829
"""
836830
function AtmosModel(; kwargs...)
837-
# TODO: Break this into separate functions for defaults and kwarg processing
838-
# this is hard to understand and maintain
831+
group_kwargs, atmos_model_kwargs = _partition_atmos_model_kwargs(kwargs)
839832

840-
# Set defaults that create a minimal viable atmospheric model
841-
default_args = (
842-
moisture_model = DryModel(),
843-
precip_model = NoPrecipitation(),
844-
cloud_model = GridScaleCloud(),
845-
surface_model = PrescribedSurfaceTemperature(),
846-
sfc_temperature = ZonallySymmetricSST(),
847-
insolation = IdealizedInsolation(),
848-
numerics = AtmosNumerics(
849-
energy_upwinding = Val(:first_order),
850-
tracer_upwinding = Val(:first_order),
851-
edmfx_upwinding = Val(:first_order),
852-
edmfx_sgsflux_upwinding = Val(:none),
853-
test_dycore_consistency = nothing,
854-
limiter = nothing,
855-
diff_mode = Explicit(),
856-
),
857-
858-
# Top-level
859-
disable_surface_flux_tendency = false,
860-
)
861-
862-
# Process keyword arguments: categorize into grouped types (e.g., hydrology -> AtmosHydrology)
863-
# vs direct AtmosModel fields (e.g., hyperdiff, numerics). Use GROUPED_PROPERTY_MAP to organize grouped types
864-
# into appropriate grouped structs, then construct AtmosModel with all top-level fields.
865-
group_kwargs = Dict{Symbol, Dict{Symbol, Any}}()
866-
for (_, group_field) in ATMOS_MODEL_GROUPS
867-
group_kwargs[group_field] = Dict{Symbol, Any}()
868-
end
869-
870-
# Kwargs for direct AtmosModel fields (hyperdiff, numerics, vert_diff, disable_surface_flux_tendency)
871-
atmos_model_kwargs = Dict{Symbol, Any}()
872-
873-
# Merge defaults with kwargs
874-
all_kwargs = merge(default_args, kwargs)
875-
876-
# Sort kwargs into a hierarchy of dicts
877-
for (key, value) in all_kwargs
878-
if haskey(GROUPED_PROPERTY_MAP, key)
879-
group_field = GROUPED_PROPERTY_MAP[key]
880-
group_kwargs[group_field][key] = value
881-
elseif key in fieldnames(AtmosModel)
882-
atmos_model_kwargs[key] = value
883-
else
884-
available_grouped = sort(collect(keys(GROUPED_PROPERTY_MAP)))
885-
available_direct = sort([
886-
fn for fn in fieldnames(AtmosModel) if fn [
887-
:hydrology,
888-
:forcing,
889-
:radiation,
890-
:advection,
891-
:turbconv,
892-
:gravity_wave,
893-
:sponge,
894-
:surface,
895-
]
896-
])
897-
available_all = [available_grouped; available_direct]
898-
error(
899-
"Unknown AtmosModel argument: $key. " *
900-
"Available arguments:\n " *
901-
join(available_all, "\n "),
902-
)
903-
end
904-
end
905-
906-
moisture = AtmosHydrology(; group_kwargs[:hydrology]...)
833+
moisture = AtmosWater(; group_kwargs[:hydrology]...)
907834
forcing = AtmosForcing(; group_kwargs[:forcing]...)
908835
radiation = AtmosRadiation(; group_kwargs[:radiation]...)
909836
advection = AtmosAdvection(; group_kwargs[:advection]...)
@@ -946,6 +873,88 @@ function AtmosModel(; kwargs...)
946873
)
947874
end
948875

876+
const _DEFAULT_ATMOS_MODEL_KWARGS = (
877+
moisture_model = DryModel(),
878+
precip_model = NoPrecipitation(),
879+
cloud_model = GridScaleCloud(),
880+
surface_model = PrescribedSurfaceTemperature(),
881+
sfc_temperature = ZonallySymmetricSST(),
882+
insolation = IdealizedInsolation(),
883+
numerics = AtmosNumerics(
884+
energy_upwinding = Val(:first_order),
885+
tracer_upwinding = Val(:first_order),
886+
edmfx_upwinding = Val(:first_order),
887+
edmfx_sgsflux_upwinding = Val(:none),
888+
test_dycore_consistency = nothing,
889+
limiter = nothing,
890+
diff_mode = Explicit(),
891+
),
892+
893+
# Top-level
894+
disable_surface_flux_tendency = false,
895+
)
896+
897+
"""
898+
_partition_atmos_model_kwargs(kwargs)
899+
900+
Partition the given kwargs into grouped and direct kwargs matching the AtmosModel struct.
901+
902+
Helper function for the AtmosModel constructor.
903+
"""
904+
function _partition_atmos_model_kwargs(kwargs)
905+
906+
# Merge default minimal model arguments with given kwargs
907+
all_kwargs = merge(_DEFAULT_ATMOS_MODEL_KWARGS, kwargs)
908+
909+
# group_kwargs contains a Dict for each group in ATMOS_MODEL_GROUPS
910+
group_kwargs = Dict(map(ATMOS_MODEL_GROUPS) do (_, group_field)
911+
group_field => Dict{Symbol, Any}()
912+
end)
913+
914+
# Sort kwargs into a hierarchy of dicts matching the AtmosModel struct
915+
atmos_model_kwargs = Dict{Symbol, Any}()
916+
unknown_args = Symbol[]
917+
918+
for (key, value) in pairs(all_kwargs)
919+
if haskey(GROUPED_PROPERTY_MAP, key)
920+
group_field = GROUPED_PROPERTY_MAP[key]
921+
group_kwargs[group_field][key] = value
922+
elseif key in fieldnames(AtmosModel)
923+
atmos_model_kwargs[key] = value
924+
else
925+
push!(unknown_args, key)
926+
end
927+
end
928+
929+
# Throw error for all unknown arguments at once
930+
if !isempty(unknown_args)
931+
_throw_unknown_atmos_model_argument_error(unknown_args)
932+
end
933+
934+
return group_kwargs, atmos_model_kwargs
935+
end
936+
937+
"""
938+
_throw_unknown_atmos_model_argument_error(unknown_args)
939+
940+
Throw a helpful error message for unknown AtmosModel constructor arguments.
941+
"""
942+
function _throw_unknown_atmos_model_argument_error(unknown_args)
943+
n_unknown = length(unknown_args)
944+
plural = n_unknown > 1 ? "s" : ""
945+
946+
# All valid arguments: forwarded properties + direct AtmosModel fields
947+
available_forwarded = sort(collect(keys(GROUPED_PROPERTY_MAP)))
948+
available_direct = sort(collect(fieldnames(AtmosModel)))
949+
available_all = sort(unique([available_forwarded; available_direct]))
950+
951+
error(
952+
"Unknown AtmosModel argument$plural: $(join(unknown_args, ", ")). " *
953+
"Available arguments:\n " *
954+
join(available_all, "\n "),
955+
)
956+
end
957+
949958
# Convenience constructors for common configurations
950959

951960
"""

0 commit comments

Comments
 (0)