MODFLOW 6  version 6.8.0.dev0
USGS Modular Hydrologic Model
gwf-sfr-transient.f90
Go to the documentation of this file.
1 submodule(sfrmodule) sfrmoduletransient
2 contains
3 
4  !> @brief Method for solving for transient reaches
5  !!
6  !! Method to solve the continuity equation for a SFR package
7  !! reach using the kinematic wave approximation.
8  !!
9  !<
10  module procedure sfr_calc_transient
11  use tdismodule, only: delt
12 
13  integer(I4B) :: igwfconn
14  integer(I4B) :: number_picard
15  integer(I4B) :: i
16  integer(I4B) :: j
17  real(DP) :: kinematic_residual
18  real(DP) :: kinematic_storage
19  real(DP) :: weight
20  real(DP) :: celerity
21  real(DP) :: courant
22  real(DP) :: dq
23  real(DP) :: qtol
24  real(DP) :: qsrc
25  real(DP) :: qlat
26  real(DP) :: da
27  real(DP) :: db
28  real(DP) :: dc
29  real(DP) :: dd
30  real(DP) :: qa
31  real(DP) :: qb
32  real(DP) :: qc
33  real(DP) :: xsa_a
34  real(DP) :: xsa_b
35  real(DP) :: xsa_c
36  real(DP) :: q
37  real(DP) :: q2
38  real(DP) :: d
39  real(DP) :: d2
40  real(DP) :: a
41  real(DP) :: a2
42  real(DP) :: d1old
43  real(DP) :: qd2
44  real(DP) :: ad
45  real(DP) :: ad2
46  real(DP) :: residual
47  real(DP) :: residual2
48  real(DP) :: residual_final
49  real(DP) :: qderv
50  real(DP) :: delq
51  real(DP) :: delh
52  real(DP) :: dd2
53  real(DP) :: en1
54  real(DP) :: en2
55  real(DP) :: dmid
56  logical :: lbisect
57 
58  weight = this%storage_weight
59  dq = this%deps
60  qtol = dq * dtwo
61 
62  celerity = dzero
63  qgwf = dzero
64  lbisect = .false.
65 
66  qlat = qr + qro - qe
67 
68  this%usinflow(n) = qu + qi + qfrommvr
69 
70  qa = this%usinflowold(n)
71  qb = this%dsflowold(n)
72  call this%sfr_calc_reach_depth(n, qa, da)
73  call this%sfr_calc_reach_depth(n, qb, db)
74 
75  qc = this%usinflow(n)
76  call this%sfr_calc_reach_depth(n, qc, dc)
77 
78  xsa_a = this%calc_area_wet(n, da)
79  xsa_b = this%calc_area_wet(n, db)
80  xsa_c = this%calc_area_wet(n, dc)
81 
82  ! estimate qd
83  qd = this%dsflow(n)
84  if (qd == dzero) then
85  qd = (qc + qb) * dhalf
86  end if
87  call this%sfr_calc_reach_depth(n, qd, dd)
88  ad = this%calc_area_wet(n, dd)
89 
90  ! estimate the depth at the midpoint
91  d1 = (dc + dd) * dhalf
92  d1old = d1
93 
94  ! estimate qgwf
95  igwfconn = this%sfr_gwf_conn(n)
96  if (igwfconn == 1) then
97  ! -- a dry gaining reach with no inflow can get stuck at zero depth under
98  ! Picard iteration: with a small time step zero depth is a stable fixed
99  ! point because conductance and saturation vanish there. Only in that
100  ! case (aquifer head above the streambed top and effectively no routed
101  ! inflow) solve the depth by bisection instead, bracketed between the
102  ! wet-streambed depth (DEM5) and the aquifer depth above the streambed
103  ! top, so the reach rewets at any dt. A reach with meaningful inflow
104  ! (dc >= DEM5) is left on the untouched Picard path.
105  en2 = hgwf - this%strtop(n)
106  if (en2 > dtwo * dem5 .and. dc < dem5) then
107  lbisect = .true.
108  en1 = dem5
109  d1 = dhalf * (en1 + en2)
110  end if
111  q = qu + qi + qr - qe + qro + qfrommvr
112  call this%sfr_calc_qgwf(n, d1, hgwf, qgwf)
113  qgwf = -qgwf
114  if (qgwf > q) then
115  qgwf = q
116  end if
117  end if
118 
119  ! calculate maximum wave speed and courant number
120  q = qc + qlat - qgwf
121  call this%sfr_calc_reach_depth(n, q, d)
122  a = this%calc_area_wet(n, d)
123  if (d > dzero) then
124  q2 = q + dq
125  call this%sfr_calc_reach_depth(n, q2, d2)
126  a2 = this%calc_area_wet(n, d2)
127  celerity = (q2 - q) / (a2 - a)
128  else
129  celerity = dzero
130  end if
131  courant = celerity * delt / this%length(n)
132  if (courant > dzero) then
133  if (courant < this%crmin(n)) this%crmin(n) = courant
134  if (courant > this%crmax(n)) this%crmax(n) = courant
135  this%crsum(n) = this%crsum(n) + courant
136  this%crcnt(n) = this%crcnt(n) + 1
137  end if
138 
139  qlat = qlat / this%length(n)
140 
141  number_picard = this%maxsfrpicard
142  if (igwfconn == 1) then
143  number_picard = this%maxsfrpicard
144  else
145  number_picard = 1
146  end if
147 
148  kinematicpicard: do i = 1, number_picard
149  if (igwfconn == 1) then
150  q = qu + qi + qr - qe + qro + qfrommvr
151  call this%sfr_calc_qgwf(n, d1, hgwf, qgwf)
152  qgwf = -qgwf
153  if (qgwf > q) then
154  qgwf = q
155  end if
156  end if
157 
158  qsrc = qlat - qgwf / this%length(n)
159 
160  newton: do j = 1, this%maxsfrit
161  qd2 = qd + dq
162  call this%sfr_calc_reach_depth(n, qd2, dd2)
163  ad2 = this%calc_area_wet(n, dd2)
164 
165  residual = kinematic_residual(qa, qb, qc, qd, &
166  xsa_a, xsa_b, xsa_c, ad, &
167  qsrc, this%length(n), weight, delt, &
168  courant)
169 
170  residual2 = kinematic_residual(qa, qb, qc, qd2, &
171  xsa_a, xsa_b, xsa_c, ad2, &
172  qsrc, this%length(n), weight, delt, &
173  courant)
174  qderv = (residual2 - residual) / dq
175  if (qderv > dzero) then
176  delq = -residual / qderv
177  else
178  delq = dzero
179  end if
180 
181  if (qd + delq < dem30) then
182  delq = -qd
183  end if
184 
185  qd = qd + delq
186 
187  call this%sfr_calc_reach_depth(n, qd, dd)
188  ad = this%calc_area_wet(n, dd)
189  residual_final = kinematic_residual(qa, qb, qc, qd, &
190  xsa_a, xsa_b, xsa_c, ad, &
191  qsrc, this%length(n), weight, delt, &
192  courant)
193 
194  if (abs(delq) < qtol .and. abs(residual_final) < qtol) then
195  exit newton
196  end if
197 
198  end do newton
199 
200  qd = max(qd, dzero)
201  if (lbisect) then
202  ! -- bisection step. dmid is the depth implied by the routed flow at the
203  ! current depth d1; the root is where the two are equal. Move the
204  ! bracket end that keeps the root inside it.
205  dmid = (dc + dd) * dhalf
206  if (dmid > d1) then
207  en1 = d1
208  else
209  en2 = d1
210  end if
211  d1 = dhalf * (en1 + en2)
212  delh = en2 - en1
213  else
214  d1 = (dc + dd) * dhalf
215  delh = (d1 - d1old)
216  end if
217 
218  if (i > 1 .and. abs(delh) < this%dmaxchg) then
219  exit kinematicpicard
220  end if
221 
222  end do kinematicpicard
223 
224  this%storage(n) = kinematic_storage(xsa_a, xsa_b, xsa_c, ad, &
225  this%length(n), delt, &
226  courant)
227 
228  end procedure sfr_calc_transient
229 
230 end submodule
real(dp) function kinematic_storage(aa, ab, ac, ad, length, delt, courant)
Kinematic routing equation storage term.
real(dp) function kinematic_residual(qa, qb, qc, qd, aa, ab, ac, ad, qsrc, length, weight, delt, courant)
Kinematic routing equation residual.
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