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 
133  qlat = qlat / this%length(n)
134 
135  number_picard = this%maxsfrpicard
136  if (igwfconn == 1) then
137  number_picard = this%maxsfrpicard
138  else
139  number_picard = 1
140  end if
141 
142  kinematicpicard: do i = 1, number_picard
143  if (igwfconn == 1) then
144  q = qu + qi + qr - qe + qro + qfrommvr
145  call this%sfr_calc_qgwf(n, d1, hgwf, qgwf)
146  qgwf = -qgwf
147  if (qgwf > q) then
148  qgwf = q
149  end if
150  end if
151 
152  qsrc = qlat - qgwf / this%length(n)
153 
154  newton: do j = 1, this%maxsfrit
155  qd2 = qd + dq
156  call this%sfr_calc_reach_depth(n, qd2, dd2)
157  ad2 = this%calc_area_wet(n, dd2)
158 
159  residual = kinematic_residual(qa, qb, qc, qd, &
160  xsa_a, xsa_b, xsa_c, ad, &
161  qsrc, this%length(n), weight, delt, &
162  courant)
163 
164  residual2 = kinematic_residual(qa, qb, qc, qd2, &
165  xsa_a, xsa_b, xsa_c, ad2, &
166  qsrc, this%length(n), weight, delt, &
167  courant)
168  qderv = (residual2 - residual) / dq
169  if (qderv > dzero) then
170  delq = -residual / qderv
171  else
172  delq = dzero
173  end if
174 
175  if (qd + delq < dem30) then
176  delq = -qd
177  end if
178 
179  qd = qd + delq
180 
181  call this%sfr_calc_reach_depth(n, qd, dd)
182  ad = this%calc_area_wet(n, dd)
183  residual_final = kinematic_residual(qa, qb, qc, qd, &
184  xsa_a, xsa_b, xsa_c, ad, &
185  qsrc, this%length(n), weight, delt, &
186  courant)
187 
188  if (abs(delq) < qtol .and. abs(residual_final) < qtol) then
189  exit newton
190  end if
191 
192  end do newton
193 
194  qd = max(qd, dzero)
195  if (lbisect) then
196  ! -- bisection step. dmid is the depth implied by the routed flow at the
197  ! current depth d1; the root is where the two are equal. Move the
198  ! bracket end that keeps the root inside it.
199  dmid = (dc + dd) * dhalf
200  if (dmid > d1) then
201  en1 = d1
202  else
203  en2 = d1
204  end if
205  d1 = dhalf * (en1 + en2)
206  delh = en2 - en1
207  else
208  d1 = (dc + dd) * dhalf
209  delh = (d1 - d1old)
210  end if
211 
212  if (i > 1 .and. abs(delh) < this%dmaxchg) then
213  exit kinematicpicard
214  end if
215 
216  end do kinematicpicard
217 
218  this%storage(n) = kinematic_storage(xsa_a, xsa_b, xsa_c, ad, &
219  this%length(n), delt, &
220  courant)
221 
222  end procedure sfr_calc_transient
223 
224 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