MODFLOW 6 version 6.9.0.dev0
USGS Modular Hydrologic Model
Loading...
Searching...
No Matches
gwf-sfr-tvd.f90
Go to the documentation of this file.
1submodule(sfrmodule) sfrmoduletvd
2contains
3
4 !> @brief Kinematic-wave routing with TVD flux limiter
5 !!
6 !! Explicit van Leer TVD update of the continuity equation with exact
7 !! volume balance; reverts to first-order upwind for Cr > 1 and at
8 !! confluences.
9 !<
10 module procedure sfr_calc_tvd
11 use tdismodule, only: delt
12 ! -- local
13 integer(I4B) :: igwfconn
14 integer(I4B) :: i
15 integer(I4B) :: j
16 integer(I4B) :: iup
17 real(DP) :: celerity
18 real(DP) :: courant
19 real(DP) :: d_old
20 real(DP) :: a_old
21 real(DP) :: a_new
22 real(DP) :: v_new
23 real(DP) :: q_out_old
24 real(DP) :: q_in_old
25 real(DP) :: q_in2_old
26 real(DP) :: dq_loc
27 real(DP) :: dq_up
28 real(DP) :: r
29 real(DP) :: phi
30 real(DP) :: q_tvd
31 real(DP) :: q_in_new
32 real(DP) :: q_lat
33 real(DP) :: q_avail
34 real(DP) :: d1_old
35 real(DP) :: tw
36 real(DP) :: res
37 real(DP) :: delh
38 !
39 ! -- old depth from start-of-timestep state; frozen by sfr_ad so the TVD
40 ! update is idempotent across outer Picard iterations
41 d_old = max(this%stageold(n) - this%strtop(n), dzero)
42 a_old = this%calc_area_wet(n, d_old)
43 !
44 ! -- Manning flow at old depth gives the first-order upwind flux
45 call this%sfr_calc_qman(n, d_old, q_out_old)
46 q_in_old = this%usinflowold(n)
47 !
48 ! -- celerity from a flow perturbation
49 call this%sfr_calc_celerity(n, q_out_old, celerity)
50 courant = celerity * delt / this%length(n)
51 !
52 ! -- accumulate Courant statistics at every step
53 if (courant > dzero) then
54 if (courant < this%crmin(n)) this%crmin(n) = courant
55 if (courant > this%crmax(n)) this%crmax(n) = courant
56 this%crsum(n) = this%crsum(n) + courant
57 this%crcnt(n) = this%crcnt(n) + 1
58 end if
59 !
60 ! -- TVD outflow: upwind + van Leer correction (Cr <= 1 only)
61 q_tvd = q_out_old
62 if (courant <= done) then
63 iup = this%itvd_upstream(n)
64 if (iup > 0) then
65 q_in2_old = this%usinflowold(iup)
66 dq_loc = q_out_old - q_in_old
67 dq_up = q_in_old - q_in2_old
68 if (abs(dq_loc) > dem30) then
69 r = dq_up / dq_loc
70 ! -- van Leer limiter: phi(r) = (r + |r|) / (1 + |r|)
71 phi = (r + abs(r)) / (done + abs(r))
72 ! -- Lax-Wendroff anti-diffusion correction bounded by limiter
73 q_tvd = q_out_old + dhalf * (done - courant) * phi * dq_loc
74 end if
75 end if
76 end if
77 !
78 ! -- the anti-diffusion correction cannot drive the outflow negative; clamp
79 ! here (before the volume balance) so the stored volume and the reported
80 ! outflow use the same flux and the budget still closes exactly
81 q_tvd = max(q_tvd, dzero)
82 !
83 ! -- total new-time volumetric inflows
84 q_in_new = qu + qi + qfrommvr
85 q_lat = qr + qro - qe
86 !
87 ! -- GWF exchange (initialized to zero for non-connected reaches)
88 igwfconn = this%sfr_gwf_conn(n)
89 qgwf = dzero
90 !
91 ! -- seed depth; on wetting (dry reach, a_new > 0) use a_new/B for a
92 ! non-zero top width
93 d1 = d_old
94 d1_old = d1
95 !
96 ! -- Picard iteration: refine qgwf and depth to convergence
97 picard: do i = 1, this%maxsfrpicard
98 if (igwfconn == 1) then
99 call this%sfr_calc_qgwf(n, d1, hgwf, qgwf)
100 qgwf = -qgwf
101 q_avail = q_in_new + q_lat
102 if (qgwf > q_avail) qgwf = q_avail
103 end if
104 !
105 ! -- conservative volume balance (exact mass conservation)
106 v_new = a_old * this%length(n) + delt * (q_in_new + q_lat - qgwf - q_tvd)
107 if (v_new < dzero) then
108 ! -- reach goes dry: reduce outflow to available water
109 q_tvd = max(q_in_new + q_lat - qgwf + &
110 a_old * this%length(n) / delt, dzero)
111 v_new = dzero
112 end if
113 a_new = v_new / this%length(n)
114 !
115 ! -- Newton solve for depth from area: calc_area_wet(n, d1) = a_new
116 d1 = max(d1, dzero)
117 if (d1 <= dzero .and. a_new > dzero) then
118 d1 = a_new / max(this%station(this%iacross(n)), dem30)
119 end if
120 newton_depth: do j = 1, this%maxsfrit
121 res = this%calc_area_wet(n, d1) - a_new
122 tw = this%calc_top_width_wet(n, d1)
123 if (tw > dem30) then
124 d1 = d1 - res / tw
125 else
126 d1 = dzero
127 end if
128 if (d1 < dzero) d1 = dzero
129 if (abs(res) < this%deps) exit newton_depth
130 end do newton_depth
131 !
132 delh = abs(d1 - d1_old)
133 if (i > 1 .and. delh < this%dmaxchg) exit picard
134 d1_old = d1
135 end do picard
136 !
137 ! -- set outflow and storage budget term (exact: closes budget by construction)
138 qd = max(q_tvd, dzero)
139 this%storage(n) = (a_old - a_new) * this%length(n) / delt
140 !
141
142 !
143 end procedure sfr_calc_tvd
144
145end submodule
This module contains the SFR package methods.
Definition gwf-sfr.f90:7
real(dp), pointer, public delt
length of the current time step
Definition tdis.f90:32