|
| 1 | +function soil_moisture!( |
| 2 | + θ::V, ψ::V, θ_prev::V, ψ_prev::V, ∂θ∂ψ::V, K::V, K₊ₕ::V, tri::TriSolver{FT}, |
| 3 | + ps::HydraulicProfile, sink::V, ψ0::FT; |
| 4 | + ibeg::Int, N::Int, Δz_cm::V, Δz₊ₕ_cm::V, dt::FT, |
| 5 | + ψ0_boundary::NamedTuple{(:i0, :dz0₊ₕ),Tuple{Int,FT}}, ψ0_location=:boundary, |
| 6 | + debug::Bool=true) where {FT<:Real,V<:AbstractVector{FT}} |
| 7 | + |
| 8 | + (; u, a, b, c, d, e, f) = tri |
| 9 | + ψ_next = u |
| 10 | + dt = dt / 3600 # [s] -> [h] |
| 11 | + |
| 12 | + for i in 1:N # backup |
| 13 | + θ_prev[i] = θ[i] |
| 14 | + ψ_prev[i] = ψ[i] |
| 15 | + end |
| 16 | + |
| 17 | + # cal_ψ!(ψ, ps, θ; N, ibeg) |
| 18 | + # cal_K!(K, K₊ₕ, ps, θ; N, ibeg, Δz=Δz_cm) |
| 19 | + # cal_∂θ∂ψ!(∂θ∂ψ, ps, ψ; N, ibeg) |
| 20 | + cal_θKCap!(θ, K, K₊ₕ, ∂θ∂ψ, ps, ψ; N, ibeg, Δz=Δz_cm) |
| 21 | + |
| 22 | + (; i0, dz0₊ₕ) = ψ0_boundary # TODO: improve this interface |
| 23 | + K0₊ₕ = (ψ0_location === :boundary || ibeg == 1) ? K[ibeg] : K₊ₕ[i0] |
| 24 | + |
| 25 | + dt_half = 0.5 * dt |
| 26 | + # first round: |
| 27 | + @inbounds for i = ibeg:N |
| 28 | + if i == ibeg |
| 29 | + a[i] = 0.0 |
| 30 | + c[i] = -K₊ₕ[i] / Δz₊ₕ_cm[i] |
| 31 | + b[i] = ∂θ∂ψ[i] * Δz_cm[i] / dt_half + K0₊ₕ / dz0₊ₕ - c[i] |
| 32 | + d[i] = ∂θ∂ψ[i] * Δz_cm[i] / dt_half * ψ[i] + K0₊ₕ / dz0₊ₕ * ψ0 + K0₊ₕ - K₊ₕ[i] |
| 33 | + elseif i < N |
| 34 | + a[i] = -K₊ₕ[i-1] / Δz₊ₕ_cm[i-1] |
| 35 | + c[i] = -K₊ₕ[i] / Δz₊ₕ_cm[i] |
| 36 | + b[i] = ∂θ∂ψ[i] * Δz_cm[i] / dt_half - a[i] - c[i] |
| 37 | + d[i] = ∂θ∂ψ[i] * Δz_cm[i] / dt_half * ψ[i] + K₊ₕ[i-1] - K₊ₕ[i] |
| 38 | + elseif i == N |
| 39 | + a[i] = -K₊ₕ[N-1] / Δz₊ₕ_cm[N-1] |
| 40 | + c[i] = 0.0 |
| 41 | + b[i] = ∂θ∂ψ[i] * Δz_cm[i] / dt_half - a[i] - c[i] |
| 42 | + d[i] = ∂θ∂ψ[i] * Δz_cm[i] / dt_half * ψ[i] + K₊ₕ[N-1] - K[i] |
| 43 | + end |
| 44 | + d[i] -= sink[i] |
| 45 | + end |
| 46 | + tridiagonal_solver!(a, b, c, d, e, f, ψ_next; ibeg, N) |
| 47 | + |
| 48 | + ## update: θ, K and ∂θ∂ψ |
| 49 | + # cal_θ!(θ, ps, ψ_next; N, ibeg) |
| 50 | + # cal_K!(K, K₊ₕ, ps, θ; N, ibeg, Δz_cm) |
| 51 | + # cal_∂θ∂ψ!(∂θ∂ψ, ps, ψ_next; N, ibeg) |
| 52 | + cal_θKCap!(θ, K, K₊ₕ, ∂θ∂ψ, ps, ψ_next; N, ibeg, Δz=Δz_cm) |
| 53 | + K0₊ₕ = (ψ0_location === :boundary || ibeg == 1) ? K[ibeg] : K₊ₕ[i0] |
| 54 | + |
| 55 | + ## second round: in half step |
| 56 | + @inbounds for i = ibeg:N |
| 57 | + if i == ibeg |
| 58 | + a[i] = 0 |
| 59 | + c[i] = -K₊ₕ[i] / (2 * Δz₊ₕ_cm[i]) |
| 60 | + b[i] = ∂θ∂ψ[i] * Δz_cm[i] / dt - c[i] + K0₊ₕ / (2 * dz0₊ₕ) |
| 61 | + d[i] = ∂θ∂ψ[i] * Δz_cm[i] / dt * ψ[i] + |
| 62 | + K0₊ₕ / (2 * dz0₊ₕ) * (2ψ0 - ψ[i]) + |
| 63 | + c[i] * (ψ[i] - ψ[i+1]) + K0₊ₕ - K₊ₕ[i] |
| 64 | + elseif i < N |
| 65 | + a[i] = -K₊ₕ[i-1] / (2 * Δz₊ₕ_cm[i-1]) |
| 66 | + c[i] = -K₊ₕ[i] / (2 * Δz₊ₕ_cm[i]) |
| 67 | + b[i] = ∂θ∂ψ[i] * Δz_cm[i] / dt - a[i] - c[i] |
| 68 | + d[i] = ∂θ∂ψ[i] * Δz_cm[i] / dt * ψ[i] - a[i] * (ψ[i-1] - ψ[i]) + |
| 69 | + c[i] * (ψ[i] - ψ[i+1]) + K₊ₕ[i-1] - K₊ₕ[i] |
| 70 | + elseif i == N |
| 71 | + a[i] = -K₊ₕ[i-1] / (2 * Δz₊ₕ_cm[i-1]) |
| 72 | + c[i] = 0 |
| 73 | + b[i] = ∂θ∂ψ[i] * Δz_cm[i] / dt - a[i] - c[i] |
| 74 | + d[i] = ∂θ∂ψ[i] * Δz_cm[i] / dt * ψ[i] - a[i] * (ψ[i-1] - ψ[i]) + K₊ₕ[i-1] - K[i] |
| 75 | + end |
| 76 | + d[i] -= sink[i] |
| 77 | + end |
| 78 | + tridiagonal_solver!(a, b, c, d, e, f, ψ; ibeg, N) |
| 79 | + # cal_θ!(soil, ψ) |
| 80 | + |
| 81 | + ## Check water balance |
| 82 | + Q0 = -K0₊ₕ / (2 * dz0₊ₕ) * ((ψ0 - ψ_prev[ibeg]) + (ψ0 - ψ[ibeg])) - K0₊ₕ # 两个时刻的 |
| 83 | + QN = -K[N] |
| 84 | + |
| 85 | + dθ = 0 |
| 86 | + for i = 1:N |
| 87 | + dθ += (θ[i] - θ_prev[i]) * Δz_cm[i] |
| 88 | + end |
| 89 | + |
| 90 | + err = dθ - (QN - Q0) * dt |
| 91 | + debug && return Q0, QN, dθ, err |
| 92 | + return nothing |
| 93 | +end |
0 commit comments