2
2
# #### Held-Suarez
3
3
# ####
4
4
5
+ import Thermodynamics as TD
6
+ import Thermodynamics. Parameters as TDP
5
7
import ClimaCore. Spaces as Spaces
6
8
import ClimaCore. Fields as Fields
7
9
8
- forcing_cache (Y, atmos:: AtmosModel ) = forcing_cache (Y, atmos. forcing_type)
9
-
10
10
# ####
11
11
# #### No forcing
12
12
# ####
13
13
14
- forcing_cache (Y, forcing_type:: Nothing ) = (;)
15
14
forcing_tendency! (Yₜ, Y, p, t, :: Nothing ) = nothing
16
15
17
16
# ####
18
17
# #### Held-Suarez forcing
19
18
# ####
20
19
21
- function forcing_cache (Y, forcing_type:: HeldSuarezForcing )
22
- FT = Spaces. undertype (axes (Y. c))
23
- return (;
24
- ᶜσ = similar (Y. c, FT),
25
- ᶜheight_factor = similar (Y. c, FT),
26
- ᶜΔρT = similar (Y. c, FT),
27
- ᶜφ = deg2rad .(Fields. coordinate_field (Y. c). lat),
28
- )
29
- end
30
-
31
20
function held_suarez_ΔT_y_T_equator (params, moisture_model:: DryModel )
32
21
FT = eltype (params)
33
22
ΔT_y = FT (CAP. ΔT_y_dry (params))
@@ -45,10 +34,76 @@ function held_suarez_ΔT_y_T_equator(
45
34
return ΔT_y, T_equator
46
35
end
47
36
37
+ struct HeldSuarezForcingParams{FT}
38
+ ΔT_y:: FT
39
+ day:: FT
40
+ σ_b:: FT
41
+ R_d:: FT
42
+ T_min:: FT
43
+ T_equator:: FT
44
+ Δθ_z:: FT
45
+ p_ref_theta:: FT
46
+ κ_d:: FT
47
+ grav:: FT
48
+ MSLP:: FT
49
+ end
50
+ Base. Broadcast. broadcastable (x:: HeldSuarezForcingParams ) = tuple (x)
51
+
52
+ function compute_ΔρT (
53
+ thermo_params:: TDP.ThermodynamicsParameters ,
54
+ ts_surf:: TD.ThermodynamicState ,
55
+ ρ:: FT ,
56
+ p:: FT ,
57
+ lat:: FT ,
58
+ z_surface:: FT ,
59
+ s:: HeldSuarezForcingParams ,
60
+ ) where {FT}
61
+ σ = compute_σ (thermo_params, z_surface, p, ts_surf, s)
62
+ k_a = 1 / (40 * s. day)
63
+ k_s = 1 / (4 * s. day)
64
+
65
+ φ = deg2rad (lat)
66
+ return (k_a + (k_s - k_a) * height_factor (σ, s. σ_b) * abs2 (abs2 (cos (φ)))) *
67
+ ρ *
68
+ ( # ᶜT - ᶜT_equil
69
+ p / (ρ * s. R_d) - max (
70
+ s. T_min,
71
+ (
72
+ s. T_equator - s. ΔT_y * abs2 (sin (φ)) -
73
+ s. Δθ_z * log (p / s. p_ref_theta) * abs2 (cos (φ))
74
+ ) * fast_pow (p / s. p_ref_theta, s. κ_d),
75
+ )
76
+ )
77
+ end
78
+
79
+ function compute_σ (
80
+ thermo_params:: TDP.ThermodynamicsParameters ,
81
+ z_surface:: FT ,
82
+ p:: FT ,
83
+ ts_surf:: TD.ThermodynamicState ,
84
+ s:: HeldSuarezForcingParams ,
85
+ ) where {FT}
86
+ p / (
87
+ s. MSLP * exp (
88
+ - s. grav * z_surface / s. R_d /
89
+ TD. air_temperature (thermo_params, ts_surf),
90
+ )
91
+ )
92
+ end
93
+
94
+ height_factor (σ:: FT , σ_b:: FT ) where {FT} = max (0 , (σ - σ_b) / (1 - σ_b))
95
+ height_factor (
96
+ thermo_params:: TDP.ThermodynamicsParameters ,
97
+ z_surface:: FT ,
98
+ p:: FT ,
99
+ ts_surf:: TD.ThermodynamicState ,
100
+ s:: HeldSuarezForcingParams ,
101
+ ) where {FT} =
102
+ height_factor (compute_σ (thermo_params, z_surface, p, ts_surf, s), s. σ_b)
103
+
48
104
function forcing_tendency! (Yₜ, Y, p, t, :: HeldSuarezForcing )
49
105
(; params) = p
50
106
(; ᶜp, sfc_conditions) = p. precomputed
51
- (; ᶜσ, ᶜheight_factor, ᶜΔρT, ᶜφ) = p. forcing
52
107
53
108
# TODO : Don't need to enforce FT here, it should be done at param creation.
54
109
FT = Spaces. undertype (axes (Y. c))
@@ -63,37 +118,46 @@ function forcing_tendency!(Yₜ, Y, p, t, ::HeldSuarezForcing)
63
118
T_min = FT (CAP. T_min_hs (params))
64
119
thermo_params = CAP. thermodynamics_params (params)
65
120
σ_b = CAP. σ_b (params)
66
- k_a = 1 / (40 * day)
67
- k_s = 1 / (4 * day)
68
121
k_f = 1 / day
69
122
70
123
z_surface = Fields. level (Fields. coordinate_field (Y. f). z, Fields. half)
71
124
72
125
ΔT_y, T_equator = held_suarez_ΔT_y_T_equator (params, p. atmos. moisture_model)
73
126
74
- @. ᶜσ =
75
- ᶜp / (
76
- MSLP * exp (
77
- - grav * z_surface / R_d /
78
- TD. air_temperature (thermo_params, sfc_conditions. ts),
79
- )
80
- )
127
+ hs_params = HeldSuarezForcingParams {FT} (
128
+ ΔT_y,
129
+ day,
130
+ σ_b,
131
+ R_d,
132
+ T_min,
133
+ T_equator,
134
+ Δθ_z,
135
+ p_ref_theta,
136
+ κ_d,
137
+ grav,
138
+ MSLP,
139
+ )
81
140
82
- @. ᶜheight_factor = max (0 , (ᶜσ - σ_b) / (1 - σ_b))
83
- @. ᶜΔρT =
84
- (k_a + (k_s - k_a) * ᶜheight_factor * abs2 (abs2 (cos (ᶜφ)))) *
85
- Y. c. ρ *
86
- ( # ᶜT - ᶜT_equil
87
- ᶜp / (Y. c. ρ * R_d) - max (
88
- T_min,
89
- (
90
- T_equator - ΔT_y * abs2 (sin (ᶜφ)) -
91
- Δθ_z * log (ᶜp / p_ref_theta) * abs2 (cos (ᶜφ))
92
- ) * fast_pow (ᶜp / p_ref_theta, κ_d),
141
+ lat = Fields. coordinate_field (Y. c). lat
142
+ @. Yₜ. c. uₕ -=
143
+ (
144
+ k_f * height_factor (
145
+ thermo_params,
146
+ z_surface,
147
+ ᶜp,
148
+ sfc_conditions. ts,
149
+ hs_params,
93
150
)
94
- )
95
-
96
- @. Yₜ. c. uₕ -= (k_f * ᶜheight_factor) * Y. c. uₕ
97
- @. Yₜ. c. ρe_tot -= ᶜΔρT * cv_d
151
+ ) * Y. c. uₕ
152
+ @. Yₜ. c. ρe_tot -=
153
+ compute_ΔρT (
154
+ thermo_params,
155
+ sfc_conditions. ts,
156
+ Y. c. ρ,
157
+ ᶜp,
158
+ lat,
159
+ z_surface,
160
+ hs_params,
161
+ ) * cv_d
98
162
return nothing
99
163
end
0 commit comments