Skip to content

Commit db01d63

Browse files
committed
add ice_concentration methods, cleanup
1 parent 2c01b24 commit db01d63

File tree

9 files changed

+39
-37
lines changed

9 files changed

+39
-37
lines changed

docs/src/fieldexchanger.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ The specific fields that are exchanged depend on the requirements of the compone
1212
The fields imported from the atmosphere to the coupler are specified by extending `FieldExchanger.import_atmos_fields!`
1313
The default `import_atmos_fields!` imports radiative fluxes, liquid precipitation, and snow precipitation.
1414

15-
The fields of a component model that get updated by the coupler are specified by extending `FieldExchanger.update_sim!`
15+
The fields of a component model that get updated by the coupler are specified by extending `FieldExchanger.update_sim!`.
1616
The default `update_sim!` for an atmosphere model updates the direct and diffuse surface albedos,
1717
the surface temperature, and the turbulent fluxes.
1818
The default `update_sim!` for a surface model updates the air density, radiative fluxes,
@@ -21,6 +21,10 @@ These updates are done via the `update_field!` function, which must be extended
2121
particular variable and component model.
2222
If an `update_field!` function is not defined for a particular component model, it will be ignored.
2323

24+
Note that turbulent fluxes are not updated in `update_sim!`, but rather via
25+
`FluxCalculator.update_turbulent_fluxes!`, where fluxes are computed between
26+
the atmosphere and each surface model.
27+
2428
## FieldExchanger API
2529

2630
```@docs

docs/src/fluxcalculator.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,23 @@ turbulent fluxes and ancillary quantities, such as the Obukhov length, using
1111
function is called at the end of each coupling step.
1212

1313
All the quantities computed in `turbulent_fluxes!` are calculated
14-
separately for each surface type using the
14+
separately for each surface model using the
1515
[`FluxCalculator.compute_surface_fluxes!`](@ref) function. This function can be
1616
extended by component models if they need specific type of flux calculation, and
1717
a default is provided for models that can use the standard flux calculation.
18-
The final result of `turbulent_fluxes!` is an area-weighted sum of
19-
all the contributions of the various surfaces.
2018

2119
The default method of [`FluxCalculator.compute_surface_fluxes!`](@ref), in turn,
2220
calls [`FluxCalculator.get_surface_fluxes`](@ref). This function uses a thermal
2321
state obtained by using the model surface temperature, extrapolates atmospheric
2422
density adiabatically to the surface, and with the surface humidity (if
2523
available, if not, assuming a saturation specific humidity for liquid phase).
26-
`compute_surface_fluxes!` also updates the component internal fluxes fields with
24+
`compute_surface_fluxes!` also updates the component internal fluxes fields via
2725
[`FluxCalculator.update_turbulent_fluxes!`](@ref), and adds the area-weighted
2826
contribution from this component model to the `CoupledSimulation` fluxes fields.
29-
Any extension of this function for a particular surface model is also expected
30-
to update both the component models' internal fluxes and the CoupledSimulation
31-
object's fluxes fields.
27+
28+
Any extension of `FluxCalculator.compute_surface_fluxes!` for a particular
29+
surface model is also expected to update both the component models' internal
30+
fluxes and the CoupledSimulation object's fluxes fields.
3231

3332
[`FluxCalculator.compute_surface_fluxes!`](@ref) sets:
3433
- the flux of momenta, `F_turb_ρτxz`, `F_turb_ρτyz`;

docs/src/interfacer.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ for the following properties:
223223
| `surface_direct albedo` | bulk direct surface albedo | |
224224
| `surface_diffuse albedo` | bulk diffuse surface albedo | |
225225
| `surface_temperature` | surface temperature | K |
226+
| `ice_concentration` | sea ice concentration (*sea ice models only*) | |
226227

227228
!!! note
228229
`area_fraction` is expected to be defined on the boundary space of the simulation,

experiments/ClimaEarth/components/ocean/clima_seaice.jl

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -82,33 +82,25 @@ function ClimaSeaIceSimulation(land_fraction, ocean; output_dir)
8282
# Allocate space for the sea ice-ocean (io) fluxes
8383
ocean_ice_fluxes = ocean.ocean_ice_fluxes
8484

85-
# TODO clean this up
8685
# Get the initial area fraction from the fractional ice concentration
87-
area_fraction = ice.model.ice_concentration
88-
89-
# Overwrite ice fraction with the static land area fraction anywhere we have nonzero land area
90-
# max needed to avoid Float32 errors (see issue #271; Heisenbug on HPC)
9186
boundary_space = axes(ocean.area_fraction)
9287
FT = CC.Spaces.undertype(boundary_space)
88+
area_fraction = Interfacer.remap(ice.model.ice_concentration, boundary_space)
9389

94-
area_fraction_boundary_space = Interfacer.remap(area_fraction, boundary_space)
95-
@. area_fraction_boundary_space =
96-
max(min(area_fraction_boundary_space, FT(1) - land_fraction), FT(0))
90+
# Overwrite ice fraction with the static land area fraction anywhere we have nonzero land area
91+
# max needed to avoid Float32 errors (see issue #271; Heisenbug on HPC)
92+
@. area_fraction = max(min(area_fraction, FT(1) - land_fraction), FT(0))
9793

9894
sim = ClimaSeaIceSimulation(
9995
ice,
100-
area_fraction_boundary_space,
96+
area_fraction,
10197
melting_speed,
10298
remapping,
10399
ocean_ice_fluxes,
104100
)
105101
return sim
106102
end
107103

108-
function update_sic!(area_fraction, ice)
109-
# TODO
110-
end
111-
112104
###############################################################################
113105
### Functions required by ClimaCoupler.jl for a SurfaceModelSimulation
114106
###############################################################################
@@ -146,6 +138,8 @@ Interfacer.get_field(sim::ClimaSeaIceSimulation, ::Val{:surface_temperature}) =
146138
Update the turbulent fluxes in the simulation using the values stored in the coupler fields.
147139
These include latent heat flux, sensible heat flux, momentum fluxes, and moisture flux.
148140
141+
The input `fields` are already area-weighted, so there's no need to weight them again.
142+
149143
Note that currently the moisture flux has no effect on the sea ice model, which has
150144
constant salinity.
151145
@@ -202,10 +196,7 @@ function FluxCalculator.update_turbulent_fluxes!(sim::ClimaSeaIceSimulation, fie
202196
# Update the sea ice only where the concentration is greater than zero.
203197
si_flux_heat = ice_sim.ice.model.external_heat_fluxes.top
204198
OC.interior(si_flux_heat, :, :, 1) .=
205-
OC.interior(si_flux_heat, :, :, 1) .+ (
206-
(OC.interior(sim.ice.model.ice_concentration, :, :, 1) .> 0) .*
207-
(remapped_F_lh .+ remapped_F_sh)
208-
)
199+
OC.interior(si_flux_heat, :, :, 1) .+ (remapped_F_lh .+ remapped_F_sh)
209200

210201
return nothing
211202
end
@@ -245,16 +236,14 @@ function FieldExchanger.update_sim!(sim::ClimaSeaIceSimulation, csf, area_fracti
245236

246237
# Update only the part due to radiative fluxes. For the full update, the component due
247238
# to latent and sensible heat is missing and will be updated in update_turbulent_fluxes.
248-
# Update the sea ice only where the concentration is greater than zero.
249239
si_flux_heat = sim.ice.model.external_heat_fluxes.top
250-
OC.interior(si_flux_heat, :, :, 1) .=
251-
(OC.interior(sim.ice.model.ice_concentration, :, :, 1) .> 0) .* remapped_F_radiative
240+
OC.interior(si_flux_heat, :, :, 1) .= remapped_F_radiative
252241

253242
return nothing
254243
end
255244

256245
"""
257-
ocean_seaice_fluxes!(ocean_sim, ice_sim)
246+
ocean_seaice_fluxes!(ocean_sim::OceananigansSimulation, ice_sim::ClimaSeaIceSimulation)
258247
259248
Compute the fluxes between the ocean and sea ice, storing them in the `ocean_ice_fluxes`
260249
fields of the ocean and sea ice simulations.

experiments/ClimaEarth/components/ocean/oceananigans.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ Interfacer.get_field(sim::OceananigansSimulation, ::Val{:surface_temperature}) =
283283
Update the turbulent fluxes in the simulation using the values computed at this time step.
284284
These include latent heat flux, sensible heat flux, momentum fluxes, and moisture flux.
285285
286-
The input fields are already area-weighted, so there's no need to weight them again.
286+
The input `fields` are already area-weighted, so there's no need to weight them again.
287287
288288
A note on sign conventions:
289289
SurfaceFluxes and Oceananigans both use the convention that a positive flux is an upward flux.
@@ -402,7 +402,6 @@ function FieldExchanger.update_sim!(sim::OceananigansSimulation, csf, area_fract
402402
# Update only the part due to radiative fluxes. For the full update, the component due
403403
# to latent and sensible heat is missing and will be updated in update_turbulent_fluxes.
404404
oc_flux_T = surface_flux(sim.ocean.model.tracers.T)
405-
# TODO document ordering of flux updates somewhere
406405
OC.interior(oc_flux_T, :, :, 1) .=
407406
OC.interior(oc_flux_T, :, :, 1) .+
408407
remapped_F_radiative ./ (ocean_reference_density * ocean_heat_capacity)

experiments/ClimaEarth/components/ocean/prescr_seaice.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,10 @@ function PrescribedIceSimulation(
162162
end
163163

164164
# extensions required by Interfacer
165-
Interfacer.get_field(sim::PrescribedIceSimulation, ::Val{:area_fraction}) =
166-
sim.integrator.p.area_fraction
165+
Interfacer.get_field(
166+
sim::PrescribedIceSimulation,
167+
::Union{Val{:area_fraction}, Val{:ice_concentration}},
168+
) = sim.integrator.p.area_fraction
167169
Interfacer.get_field(sim::PrescribedIceSimulation, ::Val{:roughness_buoyancy}) =
168170
sim.integrator.p.params.z0b
169171
Interfacer.get_field(sim::PrescribedIceSimulation, ::Val{:roughness_momentum}) =

experiments/ClimaEarth/setup_run.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -601,12 +601,11 @@ function CoupledSimulation(config_dict::AbstractDict)
601601

602602
# 3. Update any fields in the model caches that can only be filled after the initial exchange.
603603
FieldExchanger.set_caches!(cs)
604-
# TODO add a step "update area fractions" to avoid ordering between steps 3/4
605604

606605
# 4. Compute any ocean-sea ice fluxes
607606
FluxCalculator.ocean_seaice_fluxes!(cs)
608607

609-
# 4. Calculate and update turbulent fluxes for each surface model,
608+
# 5. Calculate and update turbulent fluxes for each surface model,
610609
# and save the weighted average in coupler fields
611610
FluxCalculator.turbulent_fluxes!(cs)
612611
end
@@ -748,9 +747,12 @@ function step!(cs::CoupledSimulation)
748747
## update the surface fractions for surface models
749748
FieldExchanger.update_surface_fractions!(cs)
750749

751-
## exchange all non-turbulent flux fields between models
750+
## exchange all non-turbulent flux fields between models, including radiative and precipitation fluxes
752751
FieldExchanger.exchange!(cs)
753752

753+
## compute any ocean-sea ice fluxes
754+
FluxCalculator.ocean_seaice_fluxes!(cs)
755+
754756
## calculate turbulent fluxes in the coupler and update the model simulations with them
755757
FluxCalculator.turbulent_fluxes!(cs)
756758

src/FieldExchanger.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,11 +210,13 @@ end
210210
"""
211211
update_sim!(sim::SurfaceModelSimulation, csf, area_fraction)
212212
213-
Updates the surface component model cache with the current coupler fields besides turbulent fluxes.
213+
Updates the surface component model cache with the current coupler fields
214+
*besides turbulent fluxes*, which are updated in `update_turbulent_fluxes`.
214215
215216
# Arguments
216217
- `sim`: [Interfacer.SurfaceModelSimulation] containing a surface model simulation object.
217218
- `csf`: [NamedTuple] containing coupler fields.
219+
- `area_fraction`: [CC.Fields.Field] containing the area fraction of this surface model.
218220
"""
219221
function update_sim!(sim::Interfacer.SurfaceModelSimulation, csf, area_fraction)
220222
FT = eltype(area_fraction)

src/Interfacer.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ get_field(
219219
},
220220
) = get_field_error(sim, val)
221221

222+
# Sea ice models need to provide ice concentration
223+
get_field(sim::SeaIceModelSimulation, val::Val{:ice_concentration}) =
224+
get_field_error(sim, val)
225+
222226
"""
223227
get_field(sim::ComponentModelSimulation, val::Val)
224228

0 commit comments

Comments
 (0)