Skip to content

Commit ea14db9

Browse files
authored
Merge pull request #1537 from CliMA/revert-1531-js/nonbinary-fractions
use binary ice fraction and fix the temperature in sea ice radiation
2 parents 82781b3 + 06f080e commit ea14db9

File tree

3 files changed

+30
-24
lines changed

3 files changed

+30
-24
lines changed

experiments/ClimaEarth/components/ocean/prescr_seaice.jl

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ import ClimaCoupler: Checkpointer, FluxCalculator, Interfacer, Utilities
1515
1616
Ice concentration is prescribed, and we solve the following energy equation:
1717
18-
(h * ρ * c) d T_sfc dt = (-F_turb_energy + (1 - α) * SW_d + LW_d - LW_u) + F_conductive
18+
(h * ρ * c) d T_bulk dt = (-F_turb_energy + (1 - α) * SW_d + LW_d - LW_u) + F_conductive
1919
2020
with
21-
F_conductive = k_ice (T_base - T_sfc) / (h)
21+
F_conductive = k_ice (T_base - T_bulk) / (h)
2222
23-
The surface temperature (`T_sfc`) is the prognostic variable which is being
23+
The bulk temperature (`T_bulk`) is the prognostic variable which is being
2424
modified by turbulent aerodynamic (`F_turb_energy`) and radiative (`F_turb_energy`) fluxes,
2525
as well as a conductive flux that depends on the temperature difference
2626
across the ice layer (with `T_base` being prescribed).
@@ -50,7 +50,7 @@ end
5050
function slab_ice_space_init(::Type{FT}, space, params) where {FT}
5151
# bulk temperatures commonly 10-20 K below freezing for sea ice 2m thick in winter,
5252
# and closer to freezing in summer and when melting.
53-
Y = CC.Fields.FieldVector(T_sfc = ones(space) .* params.T_freeze .- FT(5.0))
53+
Y = CC.Fields.FieldVector(T_bulk = ones(space) .* params.T_freeze .- FT(5.0))
5454
return Y
5555
end
5656

@@ -125,6 +125,7 @@ function PrescribedIceSimulation(
125125
# Overwrite ice fraction with the static land area fraction anywhere we have nonzero land area
126126
# max needed to avoid Float32 errors (see issue #271; Heisenbug on HPC)
127127
ice_fraction = @. max(min(SIC_init, FT(1) - land_fraction), FT(0))
128+
ice_fraction = ifelse.(ice_fraction .> FT(0.5), FT(1), FT(0))
128129

129130
params = IceSlabParameters{FT}()
130131

@@ -178,26 +179,27 @@ Interfacer.get_field(
178179
sim::PrescribedIceSimulation,
179180
::Union{Val{:surface_direct_albedo}, Val{:surface_diffuse_albedo}},
180181
) = sim.integrator.p.params.α
181-
# approximates the surface temperature of the sea ice
182-
# assuming sim.integrator.u.T_sfc represents the vertically-averaged (bulk) temperature
183-
# and the ice temperature varies linearly between the ice surface and the base.
184182
Interfacer.get_field(sim::PrescribedIceSimulation, ::Val{:surface_temperature}) =
185-
2 .* sim.integrator.u.T_sfc .- sim.integrator.p.params.T_base
183+
ice_surface_temperature.(sim.integrator.u.T_bulk, sim.integrator.p.params.T_base)
186184

187185
function Interfacer.get_field(sim::PrescribedIceSimulation, ::Val{:beta})
188186
# assume no LHF over sea ice
189187
FT = eltype(sim.integrator.u)
190188
return FT(0)
191189
end
192190

191+
# Approximates the surface temperature of the sea ice assuming
192+
# the ice temperature varies linearly between the ice surface and the base
193+
ice_surface_temperature(T_bulk, T_base) = 2 * T_bulk - T_base
194+
193195
"""
194196
Interfacer.get_field(sim::PrescribedIceSimulation, ::Val{:energy})
195197
196198
Extension of Interfacer.get_field to get the energy of the ocean.
197199
It multiplies the the slab temperature by the heat capacity, density, and depth.
198200
"""
199201
Interfacer.get_field(sim::PrescribedIceSimulation, ::Val{:energy}) =
200-
sim.integrator.p.params.ρ .* sim.integrator.p.params.c .* sim.integrator.u.T_sfc .*
202+
sim.integrator.p.params.ρ .* sim.integrator.p.params.c .* sim.integrator.u.T_bulk .*
201203
sim.integrator.p.params.h
202204

203205
function Interfacer.update_field!(
@@ -268,25 +270,28 @@ function ice_rhs!(dY, Y, p, t)
268270

269271
# Update the cached area fraction with the current SIC
270272
evaluate!(p.area_fraction, p.SIC_timevaryinginput, t)
273+
@. p.area_fraction = ifelse(p.area_fraction > FT(0.5), FT(1), FT(0))
271274

272275
# Overwrite ice fraction with the static land area fraction anywhere we have nonzero land area
273276
# max needed to avoid Float32 errors (see issue #271; Heisenbug on HPC)
274277
@. p.area_fraction = max(min(p.area_fraction, FT(1) - p.land_fraction), FT(0))
275278

276279
# Calculate the conductive flux, and set it to zero if the area fraction is zero
277-
F_conductive = @. k_ice / (h) * (T_base - Y.T_sfc) # fluxes are defined to be positive when upward
280+
F_conductive = @. k_ice / (h) * (T_base - Y.T_bulk) # fluxes are defined to be positive when upward
278281

279282
# TODO: get sigma from parameters
280283
σ = FT(5.67e-8)
281284
rhs = @. (
282-
-p.F_turb_energy + (1 - α) * p.SW_d + ϵ * (p.LW_d - σ * Y.T_sfc^4) + F_conductive
285+
-p.F_turb_energy +
286+
(1 - α) * p.SW_d +
287+
ϵ * (p.LW_d - σ * ice_surface_temperature(Y.T_bulk, T_base)^4) +
288+
F_conductive
283289
) / (h * ρ * c)
284-
285290
# Zero out tendencies where there is no ice, so that ice temperature remains constant there
286291
@. rhs = ifelse(p.area_fraction 0, zero(rhs), rhs)
287292

288293
# If tendencies lead to temperature above freezing, set temperature to freezing
289-
@. dY.T_sfc = min(rhs, (T_freeze - Y.T_sfc) / float(p.dt))
294+
@. dY.T_bulk = min(rhs, (T_freeze - Y.T_bulk) / float(p.dt))
290295
end
291296

292297
"""

experiments/ClimaEarth/setup_run.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ function CoupledSimulation(config_dict::AbstractDict)
359359

360360
## ocean model using prescribed data
361361
ice_fraction = Interfacer.get_field(ice_sim, Val(:area_fraction))
362+
ice_fraction = ifelse.(ice_fraction .> FT(0.5), FT(1), FT(0))
362363
ocean_fraction = FT(1) .- ice_fraction .- land_fraction
363364

364365
if sim_mode <: CMIPMode

experiments/ClimaEarth/test/component_model_tests/prescr_seaice_tests.jl

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -73,41 +73,41 @@ for FT in (Float32, Float64)
7373
σ = FT(5.67e-8)
7474

7575
# check expected dT due to upwelling longwave flux only
76-
# (zero conduction when T_base == initial T_sfc)
76+
# (zero conduction when T_base == initial T_bulk)
7777
T_base_eq = IceSlabParameters{FT}().T_freeze - FT(5.0)
7878
dY, Y, p = test_sea_ice_rhs(T_base = T_base_eq)
7979
dT_expected =
8080
(-p.params.ϵ * σ * T_base_eq^4) / (p.params.h * p.params.ρ * p.params.c)
81-
@test all(T -> T == FT(0) || T dT_expected, Array(parent(dY.T_sfc)))
81+
@test all(T -> T == FT(0) || T dT_expected, Array(parent(dY.T_bulk)))
8282

8383
# check expected dT due to downwelling shortwave flux and upwelling longwave flux
84-
# (again set T_base == initial T_sfc)
84+
# (again set T_base == initial T_bulk)
8585
dY, Y, p = test_sea_ice_rhs(SW_d = 1.0, LW_d = 0.0, T_base = T_base_eq)
8686
dT_expected =
8787
((1 - p.params.α) * 1.0 - p.params.ϵ * σ * T_base_eq^4) /
8888
(p.params.h * p.params.ρ * p.params.c)
89-
@test all(T -> T == FT(0) || T dT_expected, Array(parent(dY.T_sfc)))
89+
@test all(T -> T == FT(0) || T dT_expected, Array(parent(dY.T_bulk)))
9090

9191
# check expected dT due to downwelling and upwelling longwave flux
92-
# (again set T_base == initial T_sfc)
92+
# (again set T_base == initial T_bulk)
9393
dY, Y, p = test_sea_ice_rhs(SW_d = 0.0, LW_d = 2.0, T_base = T_base_eq)
94-
@show extrema(Y.T_sfc)
9594
dT_expected =
9695
(p.params.ϵ * (2.0 - σ * T_base_eq^4)) / (p.params.h * p.params.ρ * p.params.c)
97-
@test all(T -> T == FT(0) || T dT_expected, Array(parent(dY.T_sfc)))
96+
@test all(T -> T == FT(0) || T dT_expected, Array(parent(dY.T_bulk)))
9897

9998
# check that tendency will not result in above freezing T
10099
dY, Y, p = test_sea_ice_rhs(SW_d = 0.0, LW_d = 0.0, T_base = 330.0) # Float32 requires a large number here!
101-
dT_maximum = @. (p.params.T_freeze - Y.T_sfc) / p.dt
102-
@test minimum(dT_maximum .- dY.T_sfc) >= FT(0.0)
100+
dT_maximum = @. (p.params.T_freeze - Y.T_bulk) / p.dt
101+
@test minimum(dT_maximum .- dY.T_bulk) >= FT(0.0)
103102

104103
# check that the correct tendency was added due to basal conductive flux and upwelling longwave flux
105104
T_base = 269.2
106105
dY, Y, p = test_sea_ice_rhs(SW_d = 0.0, LW_d = 0.0, T_base = T_base)
107-
T_sfc = minimum(Y.T_sfc) # get the non-zero temperature value
106+
T_bulk = minimum(Y.T_bulk) # get the non-zero temperature value
108107
(; k_ice, h, ρ, c, T_base, ϵ) = p.params
109108
dT_expected =
110-
(k_ice / (h * h * ρ * c)) * (T_base - T_sfc) -* σ * T_sfc^4) / (h * ρ * c)
109+
(k_ice / (h * h * ρ * c)) * (T_base - T_bulk) -
110+
* σ * ice_surface_temperature(T_bulk, T_base)^4) / (h * ρ * c)
111111
@test minimum(dY) FT(dT_expected)
112112
@test maximum(dY) FT(0)
113113
end

0 commit comments

Comments
 (0)