@@ -111,25 +111,41 @@ function update_albedo!(
111
111
112
112
A pointwise function returning the volumetric liquid fraction
113
113
given the augmented liquid fraction and the effective porosity.
114
+ The output is guaranteed to be in (θ_r, ν_eff].
115
+
116
+ For Richards model, ν_eff = ν; and the clipping below is not required,
117
+ (and will do nothing; ν_eff_safe = ν_eff), but we leave it in for a
118
+ simpler interface.
114
119
"""
115
120
function volumetric_liquid_fraction (ϑ_l:: FT , ν_eff:: FT , θ_r:: FT ) where {FT}
116
- ϑ_l_safe = max (ϑ_l, θ_r + eps (FT))
117
- if ϑ_l_safe < ν_eff
121
+ ϑ_l_safe = max (ϑ_l, θ_r + sqrt (eps (FT)))
122
+ ν_eff_safe = max (ν_eff, θ_r + sqrt (eps (FT)))
123
+ if ϑ_l_safe < ν_eff_safe
118
124
θ_l = ϑ_l_safe
119
125
else
120
- θ_l = ν_eff
126
+ θ_l = ν_eff_safe
121
127
end
122
128
return θ_l
123
129
end
124
130
125
131
"""
126
- effective_saturation(porosity::FT, ϑ_l::FT, θr::FT) where {FT}
132
+ effective_saturation(ν_eff::FT, ϑ_l::FT, θr::FT) where {FT}
133
+
134
+ A point-wise function computing the effective saturation given the
135
+ effective porosity, augmented liquid fraction, and residual water
136
+ fraction as input.
127
137
128
- A point-wise function computing the effective saturation.
138
+ The output is guaranteed to lie in (0, 1].
139
+
140
+ For Richards model, or any other parameterization where ice is not
141
+ relevant, ν_eff = ν; and the clipping below is not required,
142
+ (and will do nothing; ν_eff_safe = ν_eff), but we leave it in for a
143
+ simpler interface.
129
144
"""
130
- function effective_saturation (porosity:: FT , ϑ_l:: FT , θr:: FT ) where {FT}
131
- ϑ_l_safe = max (ϑ_l, θr + eps (FT))
132
- S_l = (ϑ_l_safe - θr) / (porosity - θr)
145
+ function effective_saturation (ν_eff:: FT , ϑ_l:: FT , θr:: FT ) where {FT}
146
+ ϑ_l_safe = max (ϑ_l, θr + sqrt (eps (FT)))
147
+ ν_eff_safe = max (ν_eff, θr + sqrt (eps (FT)))
148
+ S_l = (ϑ_l_safe - θr) / (ν_eff_safe - θr)
133
149
return S_l
134
150
end
135
151
@@ -197,8 +213,9 @@ function pressure_head(
197
213
ν_eff:: FT ,
198
214
S_s:: FT ,
199
215
) where {FT}
200
- ϑ_l_safe = max (ϑ_l, θ_r + eps (FT))
201
- S_l_eff = effective_saturation (ν_eff, ϑ_l_safe, θ_r)
216
+ # effective saturation clips ν_eff and ϑ_l
217
+ # as needed so that S_l ∈ (0,1].
218
+ S_l_eff = effective_saturation (ν_eff, ϑ_l, θ_r)
202
219
if S_l_eff <= FT (1.0 )
203
220
ψ = matric_potential (cm, S_l_eff)
204
221
else
@@ -208,17 +225,23 @@ function pressure_head(
208
225
end
209
226
210
227
"""
211
- dψdϑ(cm::vanGenuchten{FT}, ϑ, ν , θ_r, S_s)
228
+ dψdϑ(cm::vanGenuchten{FT}, ϑ, ν_eff , θ_r, S_s)
212
229
213
230
Computes and returns the derivative of the pressure head
214
231
with respect to ϑ for the van Genuchten formulation.
215
232
"""
216
- function dψdϑ (cm:: vanGenuchten{FT} , ϑ, ν, θ_r, S_s) where {FT}
217
- S = effective_saturation (ν, ϑ, θ_r)
233
+ function dψdϑ (cm:: vanGenuchten{FT} , ϑ, ν_eff, θ_r, S_s) where {FT}
234
+ # effective saturation clips ν_eff and ϑ
235
+ # as needed so that S_l ∈ (0,1],
236
+ # but we use ν_eff alone, so we clip that here.
237
+ # The second clipping in effective saturation
238
+ # will not change it further.
239
+ ν_eff_safe = max (ν_eff, θ_r + sqrt (eps (FT)))
240
+ S = effective_saturation (ν_eff_safe, ϑ, θ_r)
218
241
(; α, m, n) = cm
219
242
if S < 1.0
220
243
return FT (
221
- 1.0 / (α * m * n) / (ν - θ_r) *
244
+ 1.0 / (α * m * n) / (ν_eff_safe - θ_r) *
222
245
(S^ (- 1 / m) - 1 )^ (1 / n - 1 ) *
223
246
S^ (- 1 / m - 1 ),
224
247
)
@@ -288,16 +311,22 @@ end
288
311
289
312
290
313
"""
291
- dψdϑ(cm::BrooksCorey{FT}, ϑ, ν , θ_r, S_s)
314
+ dψdϑ(cm::BrooksCorey{FT}, ϑ, ν_eff , θ_r, S_s)
292
315
293
316
Computes and returns the derivative of the pressure head
294
317
with respect to ϑ for the Brooks and Corey formulation.
295
318
"""
296
- function dψdϑ (cm:: BrooksCorey{FT} , ϑ, ν, θ_r, S_s) where {FT}
297
- S = effective_saturation (ν, ϑ, θ_r)
319
+ function dψdϑ (cm:: BrooksCorey{FT} , ϑ, ν_eff, θ_r, S_s) where {FT}
320
+ # effective saturation clips ν_eff and ϑ
321
+ # as needed so that S_l ∈ (0,1],
322
+ # but we use ν_eff alone, so we clip that here.
323
+ # The second clipping in effective saturation
324
+ # will not change it further.
325
+ ν_eff_safe = max (ν_eff, θ_r + sqrt (eps (FT)))
326
+ S = effective_saturation (ν_eff_safe, ϑ, θ_r)
298
327
(; ψb, c) = cm
299
328
if S < 1.0
300
- return - ψb / (c * (ν - θ_r)) * S^ (- (1 + 1 / c))
329
+ return - ψb / (c * (ν_eff_safe - θ_r)) * S^ (- (1 + 1 / c))
301
330
else
302
331
return 1 / S_s
303
332
end
@@ -347,6 +376,8 @@ function pressure_head(
347
376
ν_eff:: FT ,
348
377
S_s:: FT ,
349
378
) where {FT}
379
+ # effective saturation clips ν_eff and ϑ_l
380
+ # as needed so that S_l ∈ (0,1].
350
381
S_l_eff = effective_saturation (ν_eff, ϑ_l, θ_r)
351
382
if S_l_eff <= FT (1.0 )
352
383
ψ = matric_potential (cm, S_l_eff)
0 commit comments