Skip to content

Commit d672825

Browse files
committed
Add sensible defaults for AtmosModel
1 parent 2c7a4f5 commit d672825

File tree

3 files changed

+222
-161
lines changed

3 files changed

+222
-161
lines changed

src/solver/type_getters.jl

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,28 +86,30 @@ function get_atmos(config::AtmosConfig, params)
8686
)
8787

8888
atmos = AtmosModel(;
89-
# Moisture & Clouds
89+
# AtmosHydrology - Moisture, Precipitation & Clouds
9090
moisture_model,
9191
precip_model,
9292
cloud_model,
9393
noneq_cloud_formation_mode = implicit_noneq_cloud_formation ?
9494
Implicit() : Explicit(),
9595
call_cloud_diagnostics_per_stage,
9696

97-
# Forcing & Advection
97+
# AtmosForcing
9898
forcing_type,
9999
subsidence = get_subsidence_model(parsed_args, radiation_mode, FT),
100100
external_forcing = get_external_forcing_model(parsed_args, FT),
101+
102+
# AtmosAdvection
101103
ls_adv = get_large_scale_advection_model(parsed_args, FT),
102104
advection_test,
103105

104-
# Radiation
106+
# AtmosRadiation
105107
radiation_mode,
106108
ozone,
107109
co2,
108110
insolation = get_insolation_form(parsed_args),
109111

110-
# Turbulence & Convection
112+
# AtmosTurbconv - Turbulence & Convection
111113
scm_coriolis = get_scm_coriolis(parsed_args, FT),
112114
edmfx_model,
113115
turbconv_model = get_turbconv_model(FT, parsed_args, turbconv_params),
@@ -118,7 +120,7 @@ function get_atmos(config::AtmosConfig, params)
118120
sgs_mf_mode = implicit_sgs_mass_flux ? Implicit() : Explicit(),
119121
smagorinsky_lilly = get_smagorinsky_lilly_model(parsed_args),
120122

121-
# Gravity Waves
123+
# AtmosGravityWave
122124
non_orographic_gravity_wave = get_non_orographic_gravity_wave_model(
123125
parsed_args,
124126
FT,
@@ -128,17 +130,17 @@ function get_atmos(config::AtmosConfig, params)
128130
FT,
129131
),
130132

131-
# Diffusion & Sponges
132-
vert_diff,
133+
# AtmosSponge
133134
viscous_sponge = get_viscous_sponge_model(parsed_args, params, FT),
134135
rayleigh_sponge = get_rayleigh_sponge_model(parsed_args, params, FT),
135136

136-
# Surface
137+
# AtmosSurface
137138
sfc_temperature = get_sfc_temperature_form(parsed_args),
138139
surface_model = get_surface_model(parsed_args),
139140
surface_albedo = get_surface_albedo_model(parsed_args, params, FT),
140141

141-
# Numerics and Top-level Options
142+
# Top-level options (not grouped)
143+
vert_diff,
142144
hyperdiff = get_hyperdiffusion_model(parsed_args, FT),
143145
numerics = get_numerics(parsed_args),
144146
disable_surface_flux_tendency = parsed_args["disable_surface_flux_tendency"],

src/solver/types.jl

Lines changed: 101 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -517,12 +517,12 @@ Base.@kwdef struct EDMFXModel{
517517
scale_blending_method::SBM
518518
end
519519

520-
# Grouped structures to reduce AtmosModel type parameters
520+
# Grouped structs to reduce AtmosModel type parameters
521521

522522
"""
523523
AtmosHydrology
524524
525-
Groups moisture-related models and parameters.
525+
Groups moisture-related models and types.
526526
"""
527527
Base.@kwdef struct AtmosHydrology{MM, PM, CM, NCFM, CCDPS}
528528
moisture_model::MM = nothing
@@ -535,7 +535,7 @@ end
535535
"""
536536
AtmosForcing
537537
538-
Groups forcing-related models and parameters.
538+
Groups forcing-related models and types.
539539
"""
540540
Base.@kwdef struct AtmosForcing{F, S, EXTFORCING}
541541
forcing_type::F = nothing
@@ -546,7 +546,7 @@ end
546546
"""
547547
AtmosRadiation
548548
549-
Groups radiation-related models and parameters.
549+
Groups radiation-related models and types.
550550
"""
551551
Base.@kwdef struct AtmosRadiation{RM, OZ, CO2, IN}
552552
radiation_mode::RM = nothing
@@ -558,7 +558,7 @@ end
558558
"""
559559
AtmosAdvection
560560
561-
Groups advection-related models and parameters.
561+
Groups advection-related models and types.
562562
"""
563563
Base.@kwdef struct AtmosAdvection{LA, AT}
564564
ls_adv::LA = nothing
@@ -568,7 +568,7 @@ end
568568
"""
569569
AtmosTurbconv
570570
571-
Groups turbulence convection-related models and parameters.
571+
Groups turbulence convection-related models and types.
572572
"""
573573
Base.@kwdef struct AtmosTurbconv{EC, EDMFX, TCM, SAM, SEDM, SNPM, SMM, SL}
574574
scm_coriolis::EC = nothing
@@ -584,7 +584,7 @@ end
584584
"""
585585
AtmosGravityWave
586586
587-
Groups gravity wave-related models and parameters.
587+
Groups gravity wave-related models and types.
588588
"""
589589
Base.@kwdef struct AtmosGravityWave{NOGW, OGW}
590590
non_orographic_gravity_wave::NOGW = nothing
@@ -594,7 +594,7 @@ end
594594
"""
595595
AtmosSponge
596596
597-
Groups sponge-related models and parameters.
597+
Groups sponge-related models and types.
598598
"""
599599
Base.@kwdef struct AtmosSponge{VS, RS}
600600
viscous_sponge::VS = nothing
@@ -604,7 +604,7 @@ end
604604
"""
605605
AtmosSurface
606606
607-
Groups surface-related models and parameters.
607+
Groups surface-related models and types.
608608
"""
609609
Base.@kwdef struct AtmosSurface{ST, SM, SA}
610610
sfc_temperature::ST = nothing
@@ -722,19 +722,37 @@ end
722722
"""
723723
AtmosModel(; kwargs...)
724724
725-
Create an AtmosModel using a unified flat interface.
725+
Create an AtmosModel with sensible defaults.
726726
727-
This constructor allows you to specify individual model components directly as
728-
keyword arguments, which are automatically organized into the appropriate grouped
729-
sub-structures internally. This interface is used by both interactive users and
730-
the config system via `get_atmos()`.
727+
This constructor provides sensible defaults for a minimal dry atmospheric model with full customization through keyword arguments.
731728
732-
# Example: Basic dry model
729+
All model components are automatically organized into appropriate grouped sub-structs
730+
internally:
731+
- [`AtmosHydrology`](@ref)
732+
- [`AtmosForcing`](@ref)
733+
- [`AtmosRadiation`](@ref)
734+
- [`AtmosAdvection`](@ref)
735+
- [`AtmosTurbconv`](@ref)
736+
- [`AtmosGravityWave`](@ref)
737+
- [`AtmosSponge`](@ref)
738+
- [`AtmosSurface`](@ref)
739+
- [`AtmosNumerics`](@ref)
740+
The one exception is the top-level `disable_surface_flux_tendency` field, which is not grouped.
741+
742+
# Example: Minimal model (uses defaults)
743+
```julia
744+
model = AtmosModel() # Creates a basic dry atmospheric model
745+
```
746+
747+
# Example: Basic dry model with forcing
733748
```julia
734749
model = AtmosModel(;
735-
moisture_model = DryModel(),
736-
surface_model = PrescribedSurfaceTemperature(),
737-
precip_model = NoPrecipitation()
750+
forcing_type = HeldSuarezForcing(),
751+
hyperdiff = ClimaHyperdiffusion(;
752+
ν₄_vorticity_coeff = 1e15,
753+
ν₄_scalar_coeff = 1e15,
754+
divergence_damping_factor = 1.0
755+
)
738756
)
739757
```
740758
@@ -743,95 +761,106 @@ model = AtmosModel(;
743761
model = AtmosModel(;
744762
moisture_model = EquilMoistModel(),
745763
precip_model = Microphysics0Moment(),
746-
radiation_mode = RRTMGPI.AllSkyRadiation(
747-
false, false, InteractiveCloudInRadiation(), false, false, false, false
748-
),
764+
radiation_mode = RRTMGPI.AllSkyRadiation(),
749765
ozone = IdealizedOzone(),
750766
co2 = FixedCO2()
751767
)
752768
```
753769
754-
# Example: Model with hyperdiffusion and sponge layers
755-
```julia
756-
model = AtmosModel(;
757-
moisture_model = NonEquilMoistModel(),
758-
precip_model = Microphysics1Moment(),
759-
hyperdiff = ClimaHyperdiffusion(;
760-
ν₄_vorticity_coeff = 1e15,
761-
ν₄_scalar_coeff = 1e15,
762-
divergence_damping_factor = 1.0
763-
),
764-
rayleigh_sponge = RayleighSponge(; zd = 12000.0, α_uₕ = 4.0, α_w = 2.0),
765-
disable_surface_flux_tendency = false
766-
)
767-
```
770+
# Default Configuration
771+
The default AtmosModel provides:
772+
- **Dry atmosphere**: DryModel() with NoPrecipitation()
773+
- **Basic surface**: PrescribedSurfaceTemperature() with ZonallySymmetricSST()
774+
- **Simple clouds**: GridScaleCloud()
775+
- **Idealized insolation**: IdealizedInsolation()
776+
- **Conservative numerics**: First-order upwinding with Explicit() timestepping
777+
- **No advanced physics**: No radiation, turbulence, or forcing by default
768778
769-
# Available Parameters
779+
# Available Structs
770780
771-
## Moisture & Clouds
781+
## AtmosHydrology
772782
- `moisture_model`: DryModel(), EquilMoistModel(), NonEquilMoistModel()
773783
- `precip_model`: NoPrecipitation(), Microphysics0Moment(), Microphysics1Moment(), Microphysics2Moment()
774784
- `cloud_model`: GridScaleCloud(), QuadratureCloud(), SGSQuadratureCloud()
775785
- `noneq_cloud_formation_mode`: Explicit(), Implicit()
776786
- `call_cloud_diagnostics_per_stage`: nothing or CallCloudDiagnosticsPerStage()
777787
778-
## Radiation
788+
## AtmosRadiation
779789
- `radiation_mode`: RRTMGPI.ClearSkyRadiation(), RRTMGPI.AllSkyRadiation(), etc.
780790
- `ozone`: IdealizedOzone(), PrescribedOzone()
781791
- `co2`: FixedCO2(), MaunaLoaCO2()
782792
- `insolation`: IdealizedInsolation(), TimeVaryingInsolation(), etc.
783793
784-
## Forcing & Advection
794+
## AtmosForcing
785795
- `forcing_type`: nothing, HeldSuarezForcing()
786796
- `subsidence`: nothing or Subsidence() instances
787797
- `external_forcing`: nothing or external forcing objects
798+
799+
## AtmosAdvection
788800
- `ls_adv`: nothing or LargeScaleAdvection() instances
789801
- `advection_test`: nothing or boolean
790802
791-
## Turbulence & Convection
803+
## AtmosTurbconv
792804
- `scm_coriolis`: nothing or SCMCoriolis() instances
793805
- `edmfx_model`: EDMFXModel() instances
794806
- `turbconv_model`: nothing, PrognosticEDMFX(), DiagnosticEDMFX(), EDOnlyEDMFX()
795807
- `sgs_adv_mode`, `sgs_entr_detr_mode`, `sgs_nh_pressure_mode`, `sgs_mf_mode`: Explicit(), Implicit()
796808
- `smagorinsky_lilly`: nothing or SmagorinskyLilly()
797809
798-
## Gravity Waves
810+
## AtmosGravityWave
799811
- `non_orographic_gravity_wave`: nothing or NonOrographicGravityWave() instances
800812
- `orographic_gravity_wave`: nothing or OrographicGravityWave() instances
801813
802-
## Diffusion & Sponges
803-
- `vert_diff`: nothing, VerticalDiffusion(), DecayWithHeightDiffusion()
814+
## AtmosSponge
804815
- `viscous_sponge`: nothing or ViscousSponge() instances
805816
- `rayleigh_sponge`: nothing or RayleighSponge() instances
806817
807-
## Surface
818+
## AtmosSurface
808819
- `sfc_temperature`: ZonallySymmetricSST(), ZonallyAsymmetricSST(), RCEMIPIISST(), ExternalTVColumnSST()
809820
- `surface_model`: PrescribedSurfaceTemperature(), PrognosticSurfaceTemperature()
810821
- `surface_albedo`: ConstantAlbedo(), RegressionFunctionAlbedo(), CouplerAlbedo()
811822
812823
## Top-level Options
824+
- `vert_diff`: nothing, VerticalDiffusion(), DecayWithHeightDiffusion()
813825
- `hyperdiff`: nothing or ClimaHyperdiffusion() instances
814-
- `numerics`: nothing or AtmosNumerics() instances (includes `diff_mode`: Explicit(), Implicit())
826+
- `numerics`: AtmosNumerics() instances (includes `diff_mode`: Explicit(), Implicit())
815827
- `disable_surface_flux_tendency`: Bool
816828
817829
# Notes
818-
- All parameters are optional and have sensible defaults
819830
- This unified interface is used by both interactive users and the config system
820-
- Parameters are automatically grouped into appropriate sub-structures
821-
- Unknown parameter names produce helpful error messages listing all available options
822-
- Property access works both ways: `model.moisture_model` and `model.moisture.moisture_model`
823-
- The Atmos prefix is kind of annoying and could be removed
824-
825-
# Todo
826-
- improve documentation
827-
- add exports?
828-
- remove the Atmos prefix for grouped types?
831+
- Arguments are automatically grouped into appropriate sub-structs
832+
- Unknown argument names produce helpful error messages listing all available options
833+
- Property access works both ways: `model.moisture_model` and `model.hydrology.moisture_model`
829834
"""
830835
function AtmosModel(; kwargs...)
836+
# TODO: Break this into separate functions for defaults and kwarg processing
837+
# this is hard to understand and maintain
838+
839+
# Set defaults that create a minimal viable atmospheric model
840+
default_args = (
841+
moisture_model = DryModel(),
842+
precip_model = NoPrecipitation(),
843+
cloud_model = GridScaleCloud(),
844+
surface_model = PrescribedSurfaceTemperature(),
845+
sfc_temperature = ZonallySymmetricSST(),
846+
insolation = IdealizedInsolation(),
847+
numerics = AtmosNumerics(
848+
energy_upwinding = Val(:first_order),
849+
tracer_upwinding = Val(:first_order),
850+
edmfx_upwinding = Val(:first_order),
851+
edmfx_sgsflux_upwinding = Val(:none),
852+
test_dycore_consistency = nothing,
853+
limiter = nothing,
854+
diff_mode = Explicit(),
855+
),
856+
857+
# Top-level
858+
disable_surface_flux_tendency = false,
859+
)
860+
831861
# Process keyword arguments: categorize into grouped types (e.g., hydrology -> AtmosHydrology)
832862
# vs direct AtmosModel fields (e.g., hyperdiff, numerics). Use GROUPED_PROPERTY_MAP to organize grouped types
833-
# into appropriate nested structs, then construct AtmosModel with all top-level fields.
834-
863+
# into appropriate grouped structs, then construct AtmosModel with all top-level fields.
835864
group_kwargs = Dict{Symbol, Dict{Symbol, Any}}()
836865
for (_, group_field) in ATMOS_MODEL_GROUPS
837866
group_kwargs[group_field] = Dict{Symbol, Any}()
@@ -840,8 +869,21 @@ function AtmosModel(; kwargs...)
840869
# Kwargs for direct AtmosModel fields (hyperdiff, numerics, vert_diff, disable_surface_flux_tendency)
841870
atmos_model_kwargs = Dict{Symbol, Any}()
842871

843-
# Sort kwargs into appropriate groups
872+
# Make all kwargs: apply defaults for any missing kwargs, then sort into appropriate groups
873+
all_kwargs = Dict{Symbol, Any}()
874+
875+
# First add defaults
876+
for (key, default_value) in pairs(default_args)
877+
all_kwargs[key] = default_value
878+
end
879+
880+
# Then add user kwargs (overriding defaults)
844881
for (key, value) in kwargs
882+
all_kwargs[key] = value
883+
end
884+
885+
# Sort kwargs into appropriate groups
886+
for (key, value) in all_kwargs
845887
if haskey(GROUPED_PROPERTY_MAP, key)
846888
group_field = GROUPED_PROPERTY_MAP[key]
847889
group_kwargs[group_field][key] = value
@@ -851,7 +893,7 @@ function AtmosModel(; kwargs...)
851893
available_grouped = sort(collect(keys(GROUPED_PROPERTY_MAP)))
852894
available_direct = sort([
853895
fn for fn in fieldnames(AtmosModel) if fn [
854-
:moisture,
896+
:hydrology,
855897
:forcing,
856898
:radiation,
857899
:advection,
@@ -998,7 +1040,6 @@ function NonEquilMoistAtmosModel(; kwargs...)
9981040
return AtmosModel(; defaults..., kwargs...)
9991041
end
10001042

1001-
# ============================================================================
10021043

10031044
abstract type AbstractCallbackFrequency end
10041045
struct EveryNSteps <: AbstractCallbackFrequency

0 commit comments

Comments
 (0)