MODFLOW 6  version 6.8.0.dev0
USGS Modular Hydrologic Model
gwf-sfr-tvd.f90
Go to the documentation of this file.
1 submodule(sfrmodule) sfrmoduletvd
2 contains
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 
145 end 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