Skip to content

Commit da52bea

Browse files
committed
rft: clean up surface code
1 parent 8f9cb8c commit da52bea

File tree

3 files changed

+37
-128
lines changed

3 files changed

+37
-128
lines changed

src/prognostic_equations/surface_flux.jl

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,18 +109,12 @@ function surface_flux_tendency!(Yₜ, Y, p, t)
109109
thermo_params = CAP.thermodynamics_params(params)
110110

111111
if !disable_momentum_vertical_diffusion(p.atmos.vertical_diffusion)
112-
btt =
113-
boundary_tendency_momentum(Y.c.ρ, Y.c.uₕ, sfc_conditions.ρ_flux_uₕ)
112+
btt = boundary_tendency_momentum(Y.c.ρ, Y.c.uₕ, sfc_conditions.ρ_flux_uₕ)
114113
@. Yₜ.c.uₕ -= btt
115114
end
116115

117-
ᶜh_tot = @. lazy(
118-
TD.total_specific_enthalpy(
119-
thermo_params,
120-
ᶜts,
121-
specific(Y.c.ρe_tot, Y.c.ρ),
122-
),
123-
)
116+
ᶜe_tot = @. lazy(specific(Y.c.ρe_tot, Y.c.ρ))
117+
ᶜh_tot = @. lazy(TD.total_specific_enthalpy(thermo_params, ᶜts, ᶜe_tot))
124118
btt = boundary_tendency_scalar(ᶜh_tot, sfc_conditions.ρ_flux_h_tot)
125119
@. Yₜ.c.ρe_tot -= btt
126120
ρ_flux_χ = p.scratch.sfc_temp_C3

src/surface_conditions/surface_conditions.jl

Lines changed: 28 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ Updates the value of `p.precomputed.sfc_conditions` based on the current state `
55
`t`. This function will only update the surface conditions if the surface_setup
66
is not a PrescribedSurface.
77
"""
8-
98
function update_surface_conditions!(Y, p, t)
109
# Need to extract the field values so that we can do
1110
# a DataLayout broadcast rather than a Field broadcast
@@ -22,17 +21,13 @@ function update_surface_conditions!(Y, p, t)
2221
surface_temp_params = CAP.surface_temp_params(params)
2322
int_ts_values = Fields.field_values(Fields.level(ᶜts, 1))
2423
int_u_values = Fields.field_values(Fields.level(ᶜu, 1))
25-
int_z_values =
26-
Fields.field_values(Fields.level(Fields.coordinate_field(Y.c).z, 1))
24+
int_z_values = Fields.field_values(Fields.level(Fields.coordinate_field(Y.c).z, 1))
2725
sfc_conditions_values = Fields.field_values(sfc_conditions)
2826
wrapped_sfc_setup = sfc_setup_wrapper(sfc_setup)
2927
if p.atmos.sfc_temperature isa ExternalTVColumnSST
30-
evaluate!(
31-
p.external_forcing.surface_inputs.ts,
32-
p.external_forcing.surface_timevaryinginputs.ts,
33-
t,
34-
)
35-
sfc_temp_var = Fields.field_values(p.external_forcing.surface_inputs.ts)
28+
(; surface_inputs, surface_timevaryinginputs) = p.external_forcing
29+
evaluate!(surface_inputs.ts, surface_timevaryinginputs.ts, t)
30+
sfc_temp_var = Fields.field_values(surface_inputs.ts)
3631
elseif p.atmos.surface_model isa SlabOceanSST
3732
sfc_temp_var = Fields.field_values(Y.sfc.T)
3833
else
@@ -72,10 +67,7 @@ end
7267
surface_state(sfc_setup_wrapper::SurfaceState, _, _, _) = sfc_setup_wrapper
7368

7469
surface_state(
75-
wrapped_sfc_setup::F,
76-
sfc_local_geometry_values,
77-
int_z_values,
78-
t,
70+
wrapped_sfc_setup::F, sfc_local_geometry_values, int_z_values, t,
7971
) where {F <: Function} =
8072
wrapped_sfc_setup(sfc_local_geometry_values.coordinates, int_z_values, t)
8173

@@ -97,10 +89,7 @@ function set_dummy_surface_conditions!(p)
9789
@. sfc_conditions.ts = TD.PhaseDry_ρT(thermo_params, FT(1), FT(300))
9890
else
9991
@. sfc_conditions.ts = TD.PhaseNonEquil_ρTq(
100-
thermo_params,
101-
FT(1),
102-
FT(300),
103-
TD.PhasePartition(FT(0)),
92+
thermo_params, FT(1), FT(300), TD.PhasePartition(FT(0)),
10493
)
10594
@. sfc_conditions.ρ_flux_q_tot = C3(FT(0))
10695
end
@@ -110,8 +99,7 @@ function set_dummy_surface_conditions!(p)
11099
c = p.scratch.ᶠtemp_scalar
111100
# elsewhere known as 𝒢
112101
sfc_local_geometry = Fields.level(Fields.local_geometry_field(c), half)
113-
@. sfc_conditions.ρ_flux_uₕ =
114-
tensor_from_components(0, 0, sfc_local_geometry)
102+
@. sfc_conditions.ρ_flux_uₕ = tensor_from_components(0, 0, sfc_local_geometry)
115103
end
116104

117105
"""
@@ -137,9 +125,7 @@ function set_surface_conditions!(p, surface_conditions, surface_ts)
137125
sfc_local_geometry =
138126
Fields.level(Fields.local_geometry_field(ᶠtemp_scalar), Fields.half)
139127
@. sfc_conditions = atmos_surface_conditions(
140-
surface_conditions,
141-
surface_ts,
142-
sfc_local_geometry,
128+
surface_conditions, surface_ts, sfc_local_geometry,
143129
)
144130
end
145131

@@ -179,8 +165,7 @@ function surface_state_to_conditions(
179165
sfc_temp_var,
180166
t,
181167
) where {WSS}
182-
surf_state =
183-
surface_state(wrapped_sfc_setup, surface_local_geometry, interior_z, t)
168+
surf_state = surface_state(wrapped_sfc_setup, surface_local_geometry, interior_z, t)
184169
parameterization = surf_state.parameterization
185170
(; coordinates) = surface_local_geometry
186171
FT = eltype(thermo_params)
@@ -190,11 +175,7 @@ function surface_state_to_conditions(
190175

191176
T = if isnothing(sfc_temp_var)
192177
if isnothing(surf_state.T)
193-
surface_temperature(
194-
atmos.sfc_temperature,
195-
coordinates,
196-
surface_temp_params,
197-
)
178+
surface_temperature(atmos.sfc_temperature, coordinates, surface_temp_params)
198179
else
199180
surf_state.T
200181
end
@@ -216,8 +197,7 @@ function surface_state_to_conditions(
216197
else
217198
# Assume that the surface is water with saturated air directly
218199
# above it.
219-
q_vap_sat =
220-
TD.q_vap_saturation_generic(thermo_params, T, ρ, TD.Liquid())
200+
q_vap_sat = TD.q_vap_saturation_generic(thermo_params, T, ρ, TD.Liquid())
221201
q_vap = ifelsenothing(surf_state.q_vap, q_vap_sat)
222202
q = TD.PhasePartition(q_vap)
223203
ts = TD.PhaseNonEquil_ρTq(thermo_params, ρ, T, q)
@@ -231,11 +211,9 @@ function surface_state_to_conditions(
231211
# Assume that the surface is water with saturated air directly
232212
# above it.
233213
phase = TD.Liquid()
234-
p_sat =
235-
TD.saturation_vapor_pressure(thermo_params, T, phase)
214+
p_sat = TD.saturation_vapor_pressure(thermo_params, T, phase)
236215
ϵ_v =
237-
TD.Parameters.R_d(thermo_params) /
238-
TD.Parameters.R_v(thermo_params)
216+
TD.Parameters.R_d(thermo_params) / TD.Parameters.R_v(thermo_params)
239217
ϵ_v * p_sat / (p - p_sat * (1 - ϵ_v))
240218
else
241219
surf_state.q_vap
@@ -247,9 +225,7 @@ function surface_state_to_conditions(
247225

248226
surface_values = SF.StateValues(coordinates.z, SA.SVector(u, v), ts)
249227
interior_values = SF.StateValues(
250-
interior_z,
251-
SA.SVector(interior_u, interior_v),
252-
interior_ts,
228+
interior_z, SA.SVector(interior_u, interior_v), interior_ts,
253229
)
254230

255231
if parameterization isa ExchangeCoefficients
@@ -302,11 +278,7 @@ function surface_state_to_conditions(
302278
end
303279
if isnothing(surf_state.gustiness)
304280
buoyancy_flux = SF.compute_buoyancy_flux(
305-
surface_fluxes_params,
306-
shf,
307-
lhf,
308-
interior_ts,
309-
ts,
281+
surface_fluxes_params, shf, lhf, interior_ts, ts,
310282
SF.PointValueScheme(),
311283
)
312284
# TODO: We are assuming that the average mixed layer depth is
@@ -322,24 +294,13 @@ function surface_state_to_conditions(
322294
)
323295
if isnothing(parameterization.ustar)
324296
inputs = SF.Fluxes(
325-
interior_values,
326-
surface_values,
327-
shf,
328-
lhf,
329-
parameterization.z0m,
330-
parameterization.z0b,
331-
gustiness,
297+
interior_values, surface_values, shf, lhf,
298+
parameterization.z0m, parameterization.z0b, gustiness,
332299
)
333300
else
334301
inputs = SF.FluxesAndFrictionVelocity(
335-
interior_values,
336-
surface_values,
337-
shf,
338-
lhf,
339-
parameterization.ustar,
340-
parameterization.z0m,
341-
parameterization.z0m,
342-
gustiness,
302+
interior_values, surface_values, shf, lhf, parameterization.ustar,
303+
parameterization.z0m, parameterization.z0m, gustiness,
343304
)
344305
end
345306
end
@@ -360,7 +321,6 @@ function surface_temperature(
360321
)
361322
(; lat) = coordinates
362323
(; SST_mean, SST_delta, SST_wavelength_latitude) = surface_temp_params
363-
FT = eltype(lat)
364324
T = SST_mean + SST_delta / 2 * cosd(360 * lat / SST_wavelength_latitude)
365325
return T
366326
end
@@ -373,8 +333,7 @@ function surface_temperature(
373333
)
374334
(; x) = coordinates
375335
(; SST_mean, SST_delta, SST_wavelength) = surface_temp_params
376-
FT = eltype(x)
377-
T = SST_mean - SST_delta / 2 * cos(2 * FT(pi) * x / SST_wavelength)
336+
T = SST_mean - SST_delta / 2 * cospi(2 * x / SST_wavelength)
378337
return T
379338
end
380339

@@ -424,23 +383,14 @@ function surface_temperature(
424383
end
425384

426385
"""
427-
atmos_surface_conditions(
428-
surface_conditions,
429-
ts,
430-
surface_local_geometry
431-
)
386+
atmos_surface_conditions(surface_conditions, ts, surface_local_geometry)
432387
433388
Adds local geometry information to the `SurfaceFluxes.SurfaceFluxConditions` struct
434389
along with information about the thermodynamic state. The resulting values are the
435390
ones actually used by ClimaAtmos operator boundary conditions.
436391
"""
437-
function atmos_surface_conditions(
438-
surface_conditions,
439-
ts,
440-
surface_local_geometry,
441-
)
442-
(; ustar, L_MO, buoy_flux, ρτxz, ρτyz, shf, lhf, evaporation) =
443-
surface_conditions
392+
function atmos_surface_conditions(surface_conditions, ts, surface_local_geometry)
393+
(; ustar, L_MO, buoy_flux, ρτxz, ρτyz, shf, lhf, evaporation) = surface_conditions
444394

445395
# surface normal
446396
z = surface_normal(surface_local_geometry)
@@ -456,12 +406,7 @@ function atmos_surface_conditions(
456406
obukhov_length = L_MO,
457407
buoyancy_flux = buoy_flux,
458408
# This drops the C3 component of ρ_flux_u, need to add ρ_flux_u₃
459-
ρ_flux_uₕ = tensor_from_components(
460-
ρτxz,
461-
ρτyz,
462-
surface_local_geometry,
463-
z,
464-
),
409+
ρ_flux_uₕ = tensor_from_components(ρτxz, ρτyz, surface_local_geometry, z),
465410
energy_flux...,
466411
moisture_flux...,
467412
)
@@ -490,21 +435,12 @@ function surface_conditions_type(atmos, ::Type{FT}) where {FT}
490435
# NOTE: Technically ρ_flux_q_tot is not really needed for a dry model, but
491436
# SF always has evaporation
492437
moisture_flux_names = (:ρ_flux_q_tot,)
493-
names = (
494-
:ts,
495-
:ustar,
496-
:obukhov_length,
497-
:buoyancy_flux,
498-
:ρ_flux_uₕ,
499-
energy_flux_names...,
500-
moisture_flux_names...,
438+
names = (:ts, :ustar, :obukhov_length, :buoyancy_flux, :ρ_flux_uₕ,
439+
energy_flux_names..., moisture_flux_names...,
501440
)
502441
type_tuple = Tuple{
503-
atmos.moisture_model isa DryModel ? TD.PhaseDry{FT} :
504-
TD.PhaseNonEquil{FT},
505-
FT,
506-
FT,
507-
FT,
442+
atmos.moisture_model isa DryModel ? TD.PhaseDry{FT} : TD.PhaseNonEquil{FT},
443+
FT, FT, FT,
508444
typeof(C3(FT(0)) C12(FT(0), FT(0))),
509445
ntuple(_ -> C3{FT}, Val(length(energy_flux_names)))...,
510446
ntuple(_ -> C3{FT}, Val(length(moisture_flux_names)))...,

src/surface_conditions/surface_state.jl

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -43,25 +43,9 @@ SurfaceState(;
4343
v::FTN5 = nothing,
4444
gustiness::FTN6 = nothing,
4545
beta::FTN7 = nothing,
46-
) where {
47-
SFP <: SurfaceParameterization,
48-
FTN1,
49-
FTN2,
50-
FTN3,
51-
FTN4,
52-
FTN5,
53-
FTN6,
54-
FTN7,
55-
} =
46+
) where {SFP <: SurfaceParameterization, FTN1, FTN2, FTN3, FTN4, FTN5, FTN6, FTN7} =
5647
SurfaceState{float_type(SFP), SFP, FTN1, FTN2, FTN3, FTN4, FTN5, FTN6, FTN7}(
57-
parameterization,
58-
T,
59-
p,
60-
q_vap,
61-
u,
62-
v,
63-
gustiness,
64-
beta,
48+
parameterization, T, p, q_vap, u, v, gustiness, beta,
6549
)
6650

6751
"""
@@ -71,8 +55,7 @@ Container for heat fluxes
7155
- shf: Sensible heat flux
7256
- lhf: Latent heat flux
7357
"""
74-
Base.@kwdef struct HeatFluxes{FT, FTN <: Union{FT, Nothing}} <:
75-
PrescribedFluxes{FT}
58+
Base.@kwdef struct HeatFluxes{FT, FTN <: Union{FT, Nothing}} <: PrescribedFluxes{FT}
7659
shf::FT
7760
lhf::FTN = nothing
7861
end
@@ -82,8 +65,7 @@ end
8265
8366
Container for quantities used to calculate sensible and latent heat fluxes.
8467
"""
85-
Base.@kwdef struct θAndQFluxes{FT, FTN <: Union{FT, Nothing}} <:
86-
PrescribedFluxes{FT}
68+
Base.@kwdef struct θAndQFluxes{FT, FTN <: Union{FT, Nothing}} <: PrescribedFluxes{FT}
8769
θ_flux::FT
8870
q_flux::FTN = nothing
8971
end
@@ -133,11 +115,8 @@ struct MoninObukhov{
133115
end
134116

135117
function MoninObukhov(;
136-
z0 = nothing,
137-
z0m = nothing,
138-
z0b = nothing,
139-
fluxes = nothing,
140-
ustar = nothing,
118+
z0 = nothing, z0m = nothing, z0b = nothing,
119+
fluxes = nothing, ustar = nothing,
141120
)
142121
if !isnothing(z0)
143122
if isnothing(z0m) && isnothing(z0b)

0 commit comments

Comments
 (0)