MODFLOW 6  version 6.7.0.dev2
USGS Modular Hydrologic Model
utvdschememodule Module Reference

Data Types

interface  utvdschemetype
 Total Variation Diminishing (TVD) interpolation scheme. More...
 

Functions/Subroutines

type(utvdschemetype) function constructor (dis, fmi, gradient)
 
type(coefficientstype) function, target compute (this, n, m, iposnm, phi)
 
subroutine find_local_extrema (this, n, phi, min_phi, max_phi)
 
real(dp) function limiter (this, r)
 

Function/Subroutine Documentation

◆ compute()

type(coefficientstype) function, target utvdschememodule::compute ( class(utvdschemetype), target  this,
integer(i4b), intent(in)  n,
integer(i4b), intent(in)  m,
integer(i4b), intent(in)  iposnm,
real(dp), dimension(:), intent(in)  phi 
)
private

Definition at line 68 of file UTVDScheme.f90.

69  !-- return
70  type(CoefficientsType), target :: phi_face ! Output: coefficients for the face between cells n and m
71  ! -- dummy
72  class(UTVDSchemeType), target :: this
73  integer(I4B), intent(in) :: n ! Index of the first cell
74  integer(I4B), intent(in) :: m ! Index of the second cell
75  integer(I4B), intent(in) :: iposnm ! Position in the connectivity array for the n-m connection
76  real(DP), intent(in), dimension(:) :: phi ! Array of scalar values (e.g., concentrations) at all cells
77  ! -- local
78  integer(I4B) :: iup, idn, isympos ! Indices for upwind, downwind, and symmetric position in connectivity
79  real(DP) :: qnm ! Flow rate across the face between n and m
80  real(DP), pointer :: coef_up, coef_dn ! Pointers to upwind and downwind coefficients in phi_face
81  real(DP), dimension(3) :: grad_c ! gradient at upwind cell
82  real(DP), dimension(3) :: dnm ! vector from upwind to downwind cell
83  real(DP) :: smooth ! Smoothness indicator for limiter i.e. ratio of gradients
84  real(DP) :: alimiter ! Value of the TVD limiter
85  real(DP) :: cl1, cl2 ! Connection lengths from upwind and downwind cells to the face
86  real(DP) :: relative_distance ! Relative distance factor for high-order term
87  real(DP) :: c_virtual ! Virtual node concentration (Darwish method)
88  real(DP) :: min_phi, max_phi ! Local minimum and maximum among cell and neighbors
89 
90  isympos = this%dis%con%jas(iposnm)
91  qnm = this%fmi%gwfflowja(iposnm)
92  !
93  ! -- Find upstream node
94  if (qnm > dzero) then
95  ! -- positive flow into n means m is upstream
96  iup = m
97  idn = n
98 
99  cl1 = this%dis%con%cl2(isympos)
100  cl2 = this%dis%con%cl1(isympos)
101 
102  coef_up => phi_face%c_m
103  coef_dn => phi_face%c_n
104  else
105  iup = n
106  idn = m
107 
108  cl1 = this%dis%con%cl1(isympos)
109  cl2 = this%dis%con%cl2(isympos)
110 
111  coef_up => phi_face%c_n
112  coef_dn => phi_face%c_m
113  end if
114  !
115  ! -- Add low order terms
116  coef_up = done
117  !
118  ! -- Add high order terms
119  !
120  ! -- Return if straddled cells have same value
121  if (abs(phi(idn) - phi(iup)) < dsame) return
122  !
123  ! -- Compute cell concentration gradient
124  grad_c = this%gradient%get(iup, phi)
125  !
126  ! Darwish's method to compute virtual node concentration
127  dnm = node_distance(this%dis, iup, idn)
128  c_virtual = phi(idn) - 2.0_dp * (dot_product(grad_c, dnm))
129  !
130  ! Enforce local TVD condition.
131  ! This is done by limiting the virtual concentration to the range of
132  ! the max and min concentration of the neighbouring cells.
133  call find_local_extrema(this, iup, phi, min_phi, max_phi)
134 
135  if (c_virtual > max_phi) then
136  c_virtual = max_phi
137  end if
138 
139  if (c_virtual < max(min_phi, dzero)) then
140  c_virtual = max(min_phi, dzero)
141  end if
142  !
143  ! -- Compute smoothness factor
144  smooth = (phi(iup) - c_virtual) / (phi(idn) - phi(iup))
145  !
146  ! -- Compute limiter
147  alimiter = this%limiter(smooth)
148 
149  ! High order term is:
150  relative_distance = cl1 / (cl1 + cl2)
151  phi_face%rhs = -relative_distance * alimiter * (phi(idn) - phi(iup))
152 
153  ! Alternative way of writing the high order term by adding it to the
154  ! coefficients matrix. The equation to be added is:
155  ! high_order = cl1 / (cl1 + cl2) * alimiter * qnm * (phi(idn) - phi(iup))
156  ! This is split into two parts:
157  ! coef_up = coef_up - relative_distance * alimiter
158  ! coef_dn = coef_dn + relative_distance * alimiter
159 
Here is the call graph for this function:

◆ constructor()

type(utvdschemetype) function utvdschememodule::constructor ( class(disbasetype), intent(in), pointer  dis,
type(tspfmitype), intent(in), pointer  fmi,
class(igradienttype), intent(in), allocatable, target  gradient 
)
private

Definition at line 53 of file UTVDScheme.f90.

55  ! -- return
56  type(UTVDSchemeType) :: interpolation_scheme
57  ! --dummy
58  class(DisBaseType), pointer, intent(in) :: dis
59  type(TspFmiType), pointer, intent(in) :: fmi
60  class(IGradientType), allocatable, target, intent(in) :: gradient
61 
62  interpolation_scheme%dis => dis
63  interpolation_scheme%fmi => fmi
64  interpolation_scheme%gradient => gradient
65 
Here is the caller graph for this function:

◆ find_local_extrema()

subroutine utvdschememodule::find_local_extrema ( class(utvdschemetype this,
integer(i4b), intent(in)  n,
real(dp), dimension(:), intent(in)  phi,
real(dp), intent(out)  min_phi,
real(dp), intent(out)  max_phi 
)
private

Definition at line 162 of file UTVDScheme.f90.

163  ! -- dummy
164  class(UTVDSchemeType) :: this
165  integer(I4B), intent(in) :: n
166  real(DP), intent(in), dimension(:) :: phi
167  real(DP), intent(out) :: min_phi, max_phi
168  ! -- local
169  integer(I4B) :: ipos, m
170 
171  min_phi = phi(n)
172  max_phi = phi(n)
173  do ipos = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1
174  m = this%dis%con%ja(ipos)
175  min_phi = min(min_phi, phi(m))
176  max_phi = max(max_phi, phi(m))
177  end do
Here is the caller graph for this function:

◆ limiter()

real(dp) function utvdschememodule::limiter ( class(utvdschemetype this,
real(dp)  r 
)
private

Definition at line 180 of file UTVDScheme.f90.

181  ! -- return
182  real(DP) :: theta ! limited slope
183  ! -- dummy
184  class(UTVDSchemeType) :: this
185  real(DP) :: r ! ratio of successive gradients
186 
187  select case (this%limiter_id)
188  case (2) ! van Leer
189  theta = max(0.0_dp, min((r + dabs(r)) / (1.0_dp + dabs(r)), 2.0_dp))
190  case (3) ! Koren
191  theta = max(0.0_dp, min(2.0_dp * r, &
192  1.0_dp / 3.0_dp + 2.0_dp / 3.0_dp * r, 2.0_dp))
193  case (4) ! Superbee
194  theta = max(0.0_dp, min(2.0_dp * r, 1.0_dp), min(r, 2.0_dp))
195  case (5) ! van Albada
196  theta = max(0.0_dp, (r * r + r) / (r * r + 1.0_dp))
197  case (6) ! Koren modified
198  theta = max(0.0_dp, min(4.0_dp * r * r + r, &
199  1.0_dp / 3.0_dp + 2.0_dp / 3.0_dp * r, 2.0_dp))
200  case default
201  theta = dzero
202  end select