Skip to content

Commit 8ee21dc

Browse files
authored
Merge pull request #1210 from CliMA/js/get_field_defaults
add default get_field methods
2 parents b30a881 + e9c1235 commit 8ee21dc

File tree

8 files changed

+37
-22
lines changed

8 files changed

+37
-22
lines changed

NEWS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ ClimaCoupler.jl Release Notes
66

77
### ClimaCoupler features
88

9+
#### Add default `get_field` methods for surface models PR[#1210](https://github.com/CliMA/ClimaCoupler.jl/pull/1210)
10+
Add default methods for `get_field` methods that are commonly
11+
not extended for surface models. These return reasonable default
12+
values, and can be extended by surface models that won't use the
13+
defaults (e.g. the full land model).
14+
915
#### Add coupler fields based on simulation type PR[#1207](https://github.com/CliMA/ClimaCoupler.jl/pull/1207)
1016
Previously, the coupler fields were hardcoded to be the same for all
1117
simulations, independent of what components were included. Now, each

docs/src/interfacer.md

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ this function for both `AtmosModelSimulation` and
6767
the coupler. This function can optionally be extended to include
6868
additional field updates as desired.
6969

70+
- `get_field(::ComponentModelSimulation, ::Val{property})`:
71+
Default `get_field` functions are provided for `energy` and `water` fields,
72+
described in the table below.
73+
These quantities are used to track conservation, and the defaults
74+
return `nothing`. To check conservation throughout a simulation, these
75+
functions must be extended for all models being run.
76+
77+
| Coupler name | Description | Units | Default value |
78+
|-------------------|-------------|-------|---------------|
79+
| `energy` | globally integrated energy | J | `nothing` |
80+
| `water` | globally integrated water | kg | `nothing` |
81+
7082
### AtmosModelSimulation - required functions
7183
In addition to the functions required for a general
7284
`ComponentModelSimulation`, an `AtmosModelSimulation` requires the
@@ -79,7 +91,6 @@ for the following properties:
7991
| Coupler name | Description | Units |
8092
|-------------------|-------------|-------|
8193
| `air_density` | air density of the atmosphere | kg m^-3 |
82-
| `energy` | globally integrated energy | J |
8394
| `height_int` | height at the first internal model level | m |
8495
| `height_sfc` | height at the surface (only required when using `PartitionedStateFluxes`) | m |
8596
| `liquid_precipitation` | liquid precipitation at the surface | kg m^-2 s^-1 |
@@ -90,9 +101,6 @@ for the following properties:
90101
| `turbulent_moisture_flux` | aerodynamic turbulent surface fluxes of energy (evaporation) | kg m^-2 s^-1 |
91102
| `thermo_state_int` | thermodynamic state at the first internal model level | |
92103
| `uv_int` | horizontal wind velocity vector at the first internal model level | m s^-1 |
93-
| `water` | globally integrated water | kg |
94-
95-
96104

97105
- `update_field!(::AtmosModelSimulation. ::Val{property}, field)`:
98106
A function to update the value of property in the component model
@@ -118,23 +126,22 @@ extrapolated to the surface, with units of [kg m^-3].
118126
### SurfaceModelSimulation - required functions
119127
Analogously to the `AtmosModelSimulation`, a `SurfaceModelSimulation`
120128
requires additional functions to those required for a general `ComponentModelSimulation`.
121-
- `get_field(::SurfaceModelSimulation. ::Val{property})`: This getter
129+
- `get_field(::SurfaceModelSimulation, ::Val{property})`: This getter
122130
function returns the value of the field property for the simulation at
123131
the current time. For a `SurfaceModelSimulation`, it must be extended
124132
for the following properties:
125133

126134
| Coupler name | Description | Units |
127135
|-------------------|-------------|-------|
128136
| `area_fraction` | fraction of the simulation grid surface area this model covers | |
129-
| `beta` | factor that scales evaporation based on its estimated level of saturation | |
130137
| `roughness_buoyancy` | aerodynamic roughness length for buoyancy | m |
131138
| `roughness_momentum` | aerodynamic roughness length for momentum | m |
132139
| `surface_direct albedo` | bulk direct surface albedo | |
133140
| `surface_diffuse albedo` | bulk diffuse surface albedo | |
134141
| `surface_humidity` | surface humidity | kg kg^-1 |
135142
| `surface_temperature` | surface temperature | K |
136143

137-
- `update_field!(::SurfaceModelSimulation. ::Val{property}, field)`:
144+
- `update_field!(::SurfaceModelSimulation, ::Val{property}, field)`:
138145
A function to update the value of property in the component model
139146
simulation, using the values in `field` passed from the coupler
140147
This update should be done in place. If this function
@@ -157,6 +164,16 @@ following properties:
157164
| `surface_diffuse_albedo` | bulk diffuse surface albedo; needed if calculated externally of the surface model (e.g. ocean albedo from the atmospheric state) | |
158165

159166
### SurfaceModelSimulation - optional functions
167+
- `get_field(::SurfaceModelSimulation, ::Val{property})`:
168+
For some quantities, default `get_field` functions are provided, which may be
169+
overwritten or used as-is. These currently include the following:
170+
171+
| Coupler name | Description | Units | Default value |
172+
|-------------------|-------------|-------|---------------|
173+
| `beta` | factor that scales evaporation based on its estimated level of saturation | | 1 |
174+
| `emissivity` | measure of how much energy a surface radiates | | 1 |
175+
| `height_disp` | displacement height relative to the surface | m | 0 |
176+
160177
- `update_turbulent_fluxes!(::ComponentModelSimulation, fields::NamedTuple)`:
161178
This function updates the turbulent fluxes of the component model simulation
162179
at this point in horizontal space. The values are updated using the energy
@@ -176,13 +193,11 @@ the cache variables specified as:
176193
```
177194
get_field(sim::AbstractSurfaceStub, ::Val{:area_fraction}) = sim.cache.area_fraction
178195
get_field(sim::AbstractSurfaceStub, ::Val{:beta}) = sim.cache.beta
179-
get_field(sim::AbstractSurfaceStub, ::Val{:energy}) = nothing
180196
get_field(sim::AbstractSurfaceStub, ::Val{:roughness_buoyancy}) = sim.cache.z0b
181197
get_field(sim::AbstractSurfaceStub, ::Val{:roughness_momentum}) = sim.cache.z0m
182198
get_field(sim::AbstractSurfaceStub, ::Union{Val{:surface_direct_albedo}, Val{:surface_diffuse_albedo}}) = sim.cache.α
183199
get_field(sim::AbstractSurfaceStub, ::Val{:surface_humidity}) = TD.q_vap_saturation_generic.(sim.cache.thermo_params, sim.cache.T_sfc, sim.cache.ρ_sfc, sim.cache.phase)
184200
get_field(sim::AbstractSurfaceStub, ::Val{:surface_temperature}) = sim.cache.T_sfc
185-
get_field(sim::AbstractSurfaceStub, ::Val{:water}) = nothing
186201
```
187202
and with the corresponding `update_field!` functions
188203
```

experiments/ClimaEarth/components/ocean/eisenman_seaice.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ end
9393

9494
# extensions required by Interfacer
9595
Interfacer.get_field(sim::EisenmanIceSimulation, ::Val{:area_fraction}) = sim.integrator.p.area_fraction
96-
Interfacer.get_field(sim::EisenmanIceSimulation, ::Val{:beta}) = convert(eltype(sim.integrator.u), 1.0)
9796
Interfacer.get_field(sim::EisenmanIceSimulation, ::Val{:roughness_buoyancy}) =
9897
@. sim.integrator.p.params.p_i.z0b * (sim.integrator.p.ice_area_fraction) +
9998
sim.integrator.p.params.p_o.z0b .* (1 - sim.integrator.p.ice_area_fraction)
@@ -105,7 +104,6 @@ Interfacer.get_field(sim::EisenmanIceSimulation, ::Union{Val{:surface_direct_alb
105104
sim.integrator.p.params.p_o.α .* (1 - sim.integrator.p.ice_area_fraction)
106105
Interfacer.get_field(sim::EisenmanIceSimulation, ::Val{:surface_humidity}) = sim.integrator.u.q_sfc
107106
Interfacer.get_field(sim::EisenmanIceSimulation, ::Val{:surface_temperature}) = sim.integrator.u.T_sfc
108-
Interfacer.get_field(sim::EisenmanIceSimulation, ::Val{:water}) = nothing
109107

110108
"""
111109
Interfacer.get_field(sim::EisenmanIceSimulation, ::Val{:energy})

experiments/ClimaEarth/components/ocean/prescr_seaice.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,12 @@ end
155155

156156
# extensions required by Interfacer
157157
Interfacer.get_field(sim::PrescribedIceSimulation, ::Val{:area_fraction}) = sim.integrator.p.area_fraction
158-
Interfacer.get_field(sim::PrescribedIceSimulation, ::Val{:beta}) = convert(eltype(sim.integrator.u), 1.0)
159158
Interfacer.get_field(sim::PrescribedIceSimulation, ::Val{:roughness_buoyancy}) = sim.integrator.p.params.z0b
160159
Interfacer.get_field(sim::PrescribedIceSimulation, ::Val{:roughness_momentum}) = sim.integrator.p.params.z0m
161160
Interfacer.get_field(sim::PrescribedIceSimulation, ::Union{Val{:surface_direct_albedo}, Val{:surface_diffuse_albedo}}) =
162161
sim.integrator.p.params.α
163162
Interfacer.get_field(sim::PrescribedIceSimulation, ::Val{:surface_humidity}) = sim.integrator.p.q_sfc
164163
Interfacer.get_field(sim::PrescribedIceSimulation, ::Val{:surface_temperature}) = sim.integrator.u.T_sfc
165-
Interfacer.get_field(sim::PrescribedIceSimulation, ::Val{:water}) = nothing
166164

167165
"""
168166
Interfacer.get_field(sim::PrescribedIceSimulation, ::Val{:energy})

experiments/ClimaEarth/components/ocean/slab_ocean.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,12 @@ end
108108

109109
# extensions required by Interfacer
110110
Interfacer.get_field(sim::SlabOceanSimulation, ::Val{:area_fraction}) = sim.integrator.p.area_fraction
111-
Interfacer.get_field(sim::SlabOceanSimulation, ::Val{:beta}) = convert(eltype(sim.integrator.u), 1.0)
112111
Interfacer.get_field(sim::SlabOceanSimulation, ::Val{:roughness_buoyancy}) = sim.integrator.p.params.z0b
113112
Interfacer.get_field(sim::SlabOceanSimulation, ::Val{:roughness_momentum}) = sim.integrator.p.params.z0m
114113
Interfacer.get_field(sim::SlabOceanSimulation, ::Val{:surface_direct_albedo}) = sim.integrator.p.α_direct
115114
Interfacer.get_field(sim::SlabOceanSimulation, ::Val{:surface_diffuse_albedo}) = sim.integrator.p.α_diffuse
116115
Interfacer.get_field(sim::SlabOceanSimulation, ::Val{:surface_humidity}) = sim.integrator.p.q_sfc
117116
Interfacer.get_field(sim::SlabOceanSimulation, ::Val{:surface_temperature}) = sim.integrator.u.T_sfc
118-
Interfacer.get_field(sim::SlabOceanSimulation, ::Val{:water}) = nothing
119117

120118
"""
121119
Interfacer.get_field(sim::SlabOceanSimulation, ::Val{:energy})

src/Interfacer.jl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@ an atmosphere component model.
155155
get_field(
156156
sim::AtmosModelSimulation,
157157
val::Union{
158-
Val{:energy},
159158
Val{:height_int},
160159
Val{:height_sfc},
161160
Val{:liquid_precipitation},
@@ -166,7 +165,6 @@ get_field(
166165
Val{:turbulent_moisture_flux},
167166
Val{:thermo_state_int},
168167
Val{:uv_int},
169-
Val{:water},
170168
},
171169
) = get_field_error(sim, val)
172170

@@ -181,7 +179,6 @@ get_field(
181179
sim::SurfaceModelSimulation,
182180
val::Union{
183181
Val{:area_fraction},
184-
Val{:beta},
185182
Val{:roughness_buoyancy},
186183
Val{:roughness_momentum},
187184
Val{:surface_direct_albedo},
@@ -200,6 +197,13 @@ get_field(sim::ComponentModelSimulation, val::Val) = get_field_error(sim, val)
200197

201198
get_field_error(sim, val::Val{X}) where {X} = error("undefined field `$X` for " * name(sim))
202199

200+
# Set default values for fields that are not defined in all component models
201+
get_field(::ComponentModelSimulation, ::Val{:energy}) = nothing
202+
get_field(::ComponentModelSimulation, ::Val{:water}) = nothing
203+
get_field(sim::SurfaceModelSimulation, ::Val{:beta}) = convert(eltype(sim.integrator.u), 1.0)
204+
get_field(sim::SurfaceModelSimulation, ::Val{:emissivity}) = convert(eltype(sim.integrator.u), 1.0)
205+
get_field(sim::SurfaceModelSimulation, ::Val{:height_disp}) = convert(eltype(sim.integrator.u), 0.0)
206+
203207
"""
204208
update_field!(::AtmosModelSimulation, ::Val, _...)
205209

src/surface_stub.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ get_field(sim::AbstractSurfaceStub, ::Val{:surface_diffuse_albedo}) = sim.cache.
4343
get_field(sim::AbstractSurfaceStub, ::Val{:surface_humidity}) =
4444
TD.q_vap_saturation_generic.(sim.cache.thermo_params, sim.cache.T_sfc, sim.cache.ρ_sfc, sim.cache.phase)
4545
get_field(sim::AbstractSurfaceStub, ::Val{:surface_temperature}) = sim.cache.T_sfc
46-
get_field(sim::AbstractSurfaceStub, ::Val{:water}) = nothing
4746

4847
"""
4948
update_field!(sim::AbstractSurfaceStub, ::Val{:area_fraction}, field::CC.Fields.Field)

test/interfacer_tests.jl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ end
133133
# Test that get_field gives correct warnings for unextended fields
134134
for value in (
135135
:area_fraction,
136-
:beta,
137136
:roughness_buoyancy,
138137
:roughness_momentum,
139138
:surface_direct_albedo,
@@ -156,7 +155,6 @@ end
156155

157156
# Test that get_field gives correct warnings for unextended fields
158157
for value in (
159-
:energy,
160158
:height_int,
161159
:height_sfc,
162160
:liquid_precipitation,
@@ -167,7 +165,6 @@ end
167165
:turbulent_moisture_flux,
168166
:thermo_state_int,
169167
:uv_int,
170-
:water,
171168
)
172169
val = Val(value)
173170
@test_throws ErrorException("undefined field `$value` for " * Interfacer.name(sim)) Interfacer.get_field(

0 commit comments

Comments
 (0)