@@ -517,12 +517,12 @@ Base.@kwdef struct EDMFXModel{
517
517
scale_blending_method:: SBM
518
518
end
519
519
520
- # Grouped structures to reduce AtmosModel type parameters
520
+ # Grouped structs to reduce AtmosModel type parameters
521
521
522
522
"""
523
523
AtmosHydrology
524
524
525
- Groups moisture-related models and parameters .
525
+ Groups moisture-related models and types .
526
526
"""
527
527
Base. @kwdef struct AtmosHydrology{MM, PM, CM, NCFM, CCDPS}
528
528
moisture_model:: MM = nothing
535
535
"""
536
536
AtmosForcing
537
537
538
- Groups forcing-related models and parameters .
538
+ Groups forcing-related models and types .
539
539
"""
540
540
Base. @kwdef struct AtmosForcing{F, S, EXTFORCING}
541
541
forcing_type:: F = nothing
546
546
"""
547
547
AtmosRadiation
548
548
549
- Groups radiation-related models and parameters .
549
+ Groups radiation-related models and types .
550
550
"""
551
551
Base. @kwdef struct AtmosRadiation{RM, OZ, CO2, IN}
552
552
radiation_mode:: RM = nothing
558
558
"""
559
559
AtmosAdvection
560
560
561
- Groups advection-related models and parameters .
561
+ Groups advection-related models and types .
562
562
"""
563
563
Base. @kwdef struct AtmosAdvection{LA, AT}
564
564
ls_adv:: LA = nothing
568
568
"""
569
569
AtmosTurbconv
570
570
571
- Groups turbulence convection-related models and parameters .
571
+ Groups turbulence convection-related models and types .
572
572
"""
573
573
Base. @kwdef struct AtmosTurbconv{EC, EDMFX, TCM, SAM, SEDM, SNPM, SMM, SL}
574
574
scm_coriolis:: EC = nothing
584
584
"""
585
585
AtmosGravityWave
586
586
587
- Groups gravity wave-related models and parameters .
587
+ Groups gravity wave-related models and types .
588
588
"""
589
589
Base. @kwdef struct AtmosGravityWave{NOGW, OGW}
590
590
non_orographic_gravity_wave:: NOGW = nothing
594
594
"""
595
595
AtmosSponge
596
596
597
- Groups sponge-related models and parameters .
597
+ Groups sponge-related models and types .
598
598
"""
599
599
Base. @kwdef struct AtmosSponge{VS, RS}
600
600
viscous_sponge:: VS = nothing
604
604
"""
605
605
AtmosSurface
606
606
607
- Groups surface-related models and parameters .
607
+ Groups surface-related models and types .
608
608
"""
609
609
Base. @kwdef struct AtmosSurface{ST, SM, SA}
610
610
sfc_temperature:: ST = nothing
@@ -722,19 +722,37 @@ end
722
722
"""
723
723
AtmosModel(; kwargs...)
724
724
725
- Create an AtmosModel using a unified flat interface .
725
+ Create an AtmosModel with sensible defaults .
726
726
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.
731
728
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
733
748
```julia
734
749
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
+ )
738
756
)
739
757
```
740
758
@@ -743,95 +761,106 @@ model = AtmosModel(;
743
761
model = AtmosModel(;
744
762
moisture_model = EquilMoistModel(),
745
763
precip_model = Microphysics0Moment(),
746
- radiation_mode = RRTMGPI.AllSkyRadiation(
747
- false, false, InteractiveCloudInRadiation(), false, false, false, false
748
- ),
764
+ radiation_mode = RRTMGPI.AllSkyRadiation(),
749
765
ozone = IdealizedOzone(),
750
766
co2 = FixedCO2()
751
767
)
752
768
```
753
769
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
768
778
769
- # Available Parameters
779
+ # Available Structs
770
780
771
- ## Moisture & Clouds
781
+ ## AtmosHydrology
772
782
- `moisture_model`: DryModel(), EquilMoistModel(), NonEquilMoistModel()
773
783
- `precip_model`: NoPrecipitation(), Microphysics0Moment(), Microphysics1Moment(), Microphysics2Moment()
774
784
- `cloud_model`: GridScaleCloud(), QuadratureCloud(), SGSQuadratureCloud()
775
785
- `noneq_cloud_formation_mode`: Explicit(), Implicit()
776
786
- `call_cloud_diagnostics_per_stage`: nothing or CallCloudDiagnosticsPerStage()
777
787
778
- ## Radiation
788
+ ## AtmosRadiation
779
789
- `radiation_mode`: RRTMGPI.ClearSkyRadiation(), RRTMGPI.AllSkyRadiation(), etc.
780
790
- `ozone`: IdealizedOzone(), PrescribedOzone()
781
791
- `co2`: FixedCO2(), MaunaLoaCO2()
782
792
- `insolation`: IdealizedInsolation(), TimeVaryingInsolation(), etc.
783
793
784
- ## Forcing & Advection
794
+ ## AtmosForcing
785
795
- `forcing_type`: nothing, HeldSuarezForcing()
786
796
- `subsidence`: nothing or Subsidence() instances
787
797
- `external_forcing`: nothing or external forcing objects
798
+
799
+ ## AtmosAdvection
788
800
- `ls_adv`: nothing or LargeScaleAdvection() instances
789
801
- `advection_test`: nothing or boolean
790
802
791
- ## Turbulence & Convection
803
+ ## AtmosTurbconv
792
804
- `scm_coriolis`: nothing or SCMCoriolis() instances
793
805
- `edmfx_model`: EDMFXModel() instances
794
806
- `turbconv_model`: nothing, PrognosticEDMFX(), DiagnosticEDMFX(), EDOnlyEDMFX()
795
807
- `sgs_adv_mode`, `sgs_entr_detr_mode`, `sgs_nh_pressure_mode`, `sgs_mf_mode`: Explicit(), Implicit()
796
808
- `smagorinsky_lilly`: nothing or SmagorinskyLilly()
797
809
798
- ## Gravity Waves
810
+ ## AtmosGravityWave
799
811
- `non_orographic_gravity_wave`: nothing or NonOrographicGravityWave() instances
800
812
- `orographic_gravity_wave`: nothing or OrographicGravityWave() instances
801
813
802
- ## Diffusion & Sponges
803
- - `vert_diff`: nothing, VerticalDiffusion(), DecayWithHeightDiffusion()
814
+ ## AtmosSponge
804
815
- `viscous_sponge`: nothing or ViscousSponge() instances
805
816
- `rayleigh_sponge`: nothing or RayleighSponge() instances
806
817
807
- ## Surface
818
+ ## AtmosSurface
808
819
- `sfc_temperature`: ZonallySymmetricSST(), ZonallyAsymmetricSST(), RCEMIPIISST(), ExternalTVColumnSST()
809
820
- `surface_model`: PrescribedSurfaceTemperature(), PrognosticSurfaceTemperature()
810
821
- `surface_albedo`: ConstantAlbedo(), RegressionFunctionAlbedo(), CouplerAlbedo()
811
822
812
823
## Top-level Options
824
+ - `vert_diff`: nothing, VerticalDiffusion(), DecayWithHeightDiffusion()
813
825
- `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())
815
827
- `disable_surface_flux_tendency`: Bool
816
828
817
829
# Notes
818
- - All parameters are optional and have sensible defaults
819
830
- 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`
829
834
"""
830
835
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
+
831
861
# Process keyword arguments: categorize into grouped types (e.g., hydrology -> AtmosHydrology)
832
862
# 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.
835
864
group_kwargs = Dict {Symbol, Dict{Symbol, Any}} ()
836
865
for (_, group_field) in ATMOS_MODEL_GROUPS
837
866
group_kwargs[group_field] = Dict {Symbol, Any} ()
@@ -840,8 +869,21 @@ function AtmosModel(; kwargs...)
840
869
# Kwargs for direct AtmosModel fields (hyperdiff, numerics, vert_diff, disable_surface_flux_tendency)
841
870
atmos_model_kwargs = Dict {Symbol, Any} ()
842
871
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)
844
881
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
845
887
if haskey (GROUPED_PROPERTY_MAP, key)
846
888
group_field = GROUPED_PROPERTY_MAP[key]
847
889
group_kwargs[group_field][key] = value
@@ -851,7 +893,7 @@ function AtmosModel(; kwargs...)
851
893
available_grouped = sort (collect (keys (GROUPED_PROPERTY_MAP)))
852
894
available_direct = sort ([
853
895
fn for fn in fieldnames (AtmosModel) if fn ∉ [
854
- :moisture ,
896
+ :hydrology ,
855
897
:forcing ,
856
898
:radiation ,
857
899
:advection ,
@@ -998,7 +1040,6 @@ function NonEquilMoistAtmosModel(; kwargs...)
998
1040
return AtmosModel (; defaults... , kwargs... )
999
1041
end
1000
1042
1001
- # ============================================================================
1002
1043
1003
1044
abstract type AbstractCallbackFrequency end
1004
1045
struct EveryNSteps <: AbstractCallbackFrequency
0 commit comments