MODFLOW 6  version 6.5.0.dev2
MODFLOW 6 Code Documentation
xt3dalgorithmmodule Module Reference

Functions/Subroutines

subroutine qconds (nnbrmx, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, ck0, nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, vcthresh, allhc0, allhc1, chat01, chati0, chat1j)
 Compute the "conductances" in the normal-flux expression for an interface (modflow-usg version). The cell on one side of the interface is "cell 0", and the one on the other side is "cell 1". More...
 
subroutine abhats (nnbrmx, nnbr, inbr, il01, vc, vn, dl0, dln, ck, vcthresh, allhc, ar01, ahat, bhat)
 Compute "ahat" and "bhat" coefficients for one side of an interface. More...
 
subroutine getrot (nnbrmx, nnbr, inbr, vc, il01, rmat, iml0)
 Compute the matrix that rotates the model-coordinate axes to the "(c, d, e)-coordinate" axes associated with a connection. More...
 
subroutine tranvc (nnbrmx, nnbrs, rmat, vc, vccde)
 Transform local connection unit-vectors from model coordinates to "(c, d, e)" coordinates associated with a connection. More...
 
subroutine abwts (nnbrmx, nnbr, inbr, il01, nde1, vccde, vcthresh, dl0, dln, acd, add, aed, bd)
 Compute "a" and "b" weights for the local connections with respect to the perpendicular direction of primary interest. More...
 

Function/Subroutine Documentation

◆ abhats()

subroutine xt3dalgorithmmodule::abhats ( integer(i4b)  nnbrmx,
integer(i4b)  nnbr,
integer(i4b), dimension(nnbrmx)  inbr,
integer(i4b)  il01,
real(dp), dimension(nnbrmx, 3)  vc,
real(dp), dimension(nnbrmx, 3)  vn,
real(dp), dimension(nnbrmx)  dl0,
real(dp), dimension(nnbrmx)  dln,
real(dp), dimension(3, 3)  ck,
real(dp)  vcthresh,
logical  allhc,
real(dp)  ar01,
real(dp)  ahat,
real(dp), dimension(nnbrmx)  bhat 
)

Definition at line 130 of file Xt3dAlgorithm.f90.

132  ! -- dummy
133  integer(I4B) :: nnbrmx
134  integer(I4B) :: nnbr
135  integer(I4B), dimension(nnbrmx) :: inbr
136  integer(I4B) :: il01
137  real(DP), dimension(nnbrmx, 3) :: vc
138  real(DP), dimension(nnbrmx, 3) :: vn
139  real(DP), dimension(nnbrmx) :: dl0
140  real(DP), dimension(nnbrmx) :: dln
141  real(DP), dimension(3, 3) :: ck
142  real(DP) :: vcthresh
143  logical :: allhc
144  real(DP) :: ar01
145  real(DP) :: ahat
146  real(DP), dimension(nnbrmx) :: bhat
147  ! -- local
148  logical :: iscomp
149  real(DP), dimension(nnbrmx, 3) :: vccde
150  real(DP), dimension(3, 3) :: rmat
151  real(DP), dimension(3) :: sigma
152  real(DP), dimension(nnbrmx) :: bd
153  real(DP), dimension(nnbrmx) :: be
154  real(DP), dimension(nnbrmx) :: betad
155  real(DP), dimension(nnbrmx) :: betae
156  integer(I4B) :: iml0
157  integer(I4B) :: il
158  real(DP) :: acd
159  real(DP) :: add
160  real(DP) :: aed
161  real(DP) :: ace
162  real(DP) :: aee
163  real(DP) :: ade
164  real(DP) :: determ
165  real(DP) :: oodet
166  real(DP) :: alphad
167  real(DP) :: alphae
168  real(DP) :: dl0il
169  !
170  ! -- Determine the basis vectors for local "(c, d, e)" coordinates
171  ! associated with the connection between cells 0 and 1, and set the
172  ! rotation matrix that transforms vectors from model coordinates to
173  ! (c, d, e) coordinates. (If no active connection is found that has a
174  ! non-negligible component perpendicular to the primary connection,
175  ! ilmo=0 is returned.)
176  call getrot(nnbrmx, nnbr, inbr, vc, il01, rmat, iml0)
177  !
178  ! -- If no active connection with a non-negligible perpendicular
179  ! component, assume no perpendicular gradient and base gradient solely
180  ! on the primary connection. Otherwise, proceed with basing weights on
181  ! information from neighboring connections.
182  if (iml0 .eq. 0) then
183  !
184  ! -- Compute ahat and bhat coefficients assuming perpendicular components
185  ! of gradient are zero.
186  sigma(1) = dot_product(vn(il01, :), matmul(ck, rmat(:, 1)))
187  ahat = sigma(1) / dl0(il01)
188  bhat = 0d0
189  else
190  !
191  ! -- Transform local connection unit-vectors from model coordinates to
192  ! "(c, d, e)" coordinates associated with the connection between cells
193  ! 0 and 1.
194  call tranvc(nnbrmx, nnbr, rmat, vc, vccde)
195  !
196  ! -- Get "a" and "b" weights for first perpendicular direction.
197  call abwts(nnbrmx, nnbr, inbr, il01, 2, vccde, &
198  vcthresh, dl0, dln, acd, add, aed, bd)
199  !
200  ! -- If all neighboring connections are user-designated as horizontal, or
201  ! if none have a non-negligible component in the second perpendicular
202  ! direction, assume zero gradient in the second perpendicular direction.
203  ! Otherwise, get "a" and "b" weights for second perpendicular direction
204  ! based on neighboring connections.
205  if (allhc) then
206  ace = 0d0
207  aee = 1d0
208  ade = 0d0
209  be = 0d0
210  else
211  iscomp = .false.
212  do il = 1, nnbr
213  if ((il == il01) .or. (inbr(il) == 0)) then
214  cycle
215  else if (dabs(vccde(il, 3)) > 1d-10) then
216  iscomp = .true.
217  exit
218  end if
219  end do
220  if (iscomp) then
221  call abwts(nnbrmx, nnbr, inbr, il01, 3, vccde, &
222  vcthresh, dl0, dln, ace, aee, ade, be)
223  else
224  ace = 0d0
225  aee = 1d0
226  ade = 0d0
227  be = 0d0
228  end if
229  end if
230  !
231  ! -- Compute alpha and beta coefficients.
232  determ = add * aee - ade * aed
233  oodet = 1d0 / determ
234  alphad = (acd * aee - ace * aed) * oodet
235  alphae = (ace * add - acd * ade) * oodet
236  betad = 0d0
237  betae = 0d0
238  do il = 1, nnbr
239  ! -- If this is connection (0,1) or inactive, skip.
240  if ((il == il01) .or. (inbr(il) == 0)) cycle
241  betad(il) = (bd(il) * aee - be(il) * aed) * oodet
242  betae(il) = (be(il) * add - bd(il) * ade) * oodet
243  end do
244  !
245  ! -- Compute sigma coefficients.
246  sigma = matmul(vn(il01, :), matmul(ck, rmat))
247  !
248  ! -- Compute ahat and bhat coefficients.
249  ahat = (sigma(1) - sigma(2) * alphad - sigma(3) * alphae) / dl0(il01)
250  bhat = 0d0
251  do il = 1, nnbr
252  ! -- If this is connection (0,1) or inactive, skip.
253  if ((il == il01) .or. (inbr(il) == 0)) cycle
254  dl0il = dl0(il) + dln(il)
255  bhat(il) = (sigma(2) * betad(il) + sigma(3) * betae(il)) / dl0il
256  end do
257  ! -- Set the bhat for connection (0,1) to zero here, since we have been
258  ! skipping it in our do loops to avoiding explicitly computing it.
259  ! This will carry through to the corresponding chati0 and chat1j value,
260  ! so that they too are zero.
261  bhat(il01) = 0d0
262  !
263  end if
264  !
265  ! -- Multiply by area.
266  ahat = ahat * ar01
267  bhat = bhat * ar01
268  !
269  ! -- Return
270  return
Here is the call graph for this function:
Here is the caller graph for this function:

◆ abwts()

subroutine xt3dalgorithmmodule::abwts ( integer(i4b)  nnbrmx,
integer(i4b)  nnbr,
integer(i4b), dimension(nnbrmx)  inbr,
integer(i4b)  il01,
integer(i4b)  nde1,
real(dp), dimension(nnbrmx, 3)  vccde,
real(dp)  vcthresh,
real(dp), dimension(nnbrmx)  dl0,
real(dp), dimension(nnbrmx)  dln,
real(dp)  acd,
real(dp)  add,
real(dp)  aed,
real(dp), dimension(nnbrmx)  bd 
)

nde1 = number that indicates the perpendicular direction of primary interest on this call: "d" (2) or "e" (3). vccde = array of connection unit-vectors with respect to (c, d, e) coordinates. bd = array of "b" weights. aed = "a" weight that goes on the matrix side of the 2x2 problem. acd = "a" weight that goes on the right-hand side of the 2x2 problem.

Definition at line 398 of file Xt3dAlgorithm.f90.

400  ! -- dummy
401  integer(I4B) :: nnbrmx
402  integer(I4B) :: nnbr
403  integer(I4B), dimension(nnbrmx) :: inbr
404  integer(I4B) :: il01
405  integer(I4B) :: nde1
406  real(DP), dimension(nnbrmx, 3) :: vccde
407  real(DP) :: vcthresh
408  real(DP), dimension(nnbrmx) :: dl0
409  real(DP), dimension(nnbrmx) :: dln
410  real(DP) :: acd
411  real(DP) :: add
412  real(DP) :: aed
413  real(DP), dimension(nnbrmx) :: bd
414  ! -- local
415  integer(I4B) :: nde2
416  integer(I4B) :: il
417  real(DP) :: vcmx
418  real(DP) :: dlm
419  real(DP) :: cosang
420  real(DP) :: dl4wt
421  real(DP) :: fact
422  real(DP) :: dsum
423  real(DP) :: oodsum
424  real(DP) :: fatten
425  real(DP), dimension(nnbrmx) :: omwt
426  !
427  ! -- Set the perpendicular direction of secondary interest.
428  nde2 = 5 - nde1
429  !
430  ! -- Begin computing "omega" weights.
431  omwt = 0d0
432  dsum = 0d0
433  vcmx = 0d0
434  do il = 1, nnbr
435  ! -- If this is connection (0,1) or inactive, skip.
436  if ((il .eq. il01) .or. (inbr(il) .eq. 0)) cycle
437  vcmx = max(dabs(vccde(il, nde1)), vcmx)
438  dlm = 5d-1 * (dl0(il) + dln(il))
439  ! -- Distance-based weighting. dl4wt is the distance between the point
440  ! supplying the gradient information and the point at which the flux is
441  ! being estimated. Could be coded as a special case of resistance-based
442  ! weighting (by setting the conductivity matrix to be the identity
443  ! matrix), but this is more efficient.
444  cosang = vccde(il, 1)
445  dl4wt = dsqrt(dlm * dlm + dl0(il01) * dl0(il01) &
446  - 2d0 * dlm * dl0(il01) * cosang)
447  omwt(il) = dabs(vccde(il, nde1)) * dl4wt
448  dsum = dsum + omwt(il)
449  end do
450  !
451  ! -- Finish computing non-normalized "omega" weights. [Add a tiny bit to
452  ! dsum so that the normalized omega weight later evaluates to
453  ! (essentially) 1 in the case of a single relevant connection, avoiding
454  ! 0/0.]
455  dsum = dsum + 1d-10 * dsum
456  do il = 1, nnbr
457  ! -- If this is connection (0,1) or inactive, skip.
458  if ((il .eq. il01) .or. (inbr(il) .eq. 0)) cycle
459  fact = dsum - omwt(il)
460  omwt(il) = fact * dabs(vccde(il, nde1))
461  end do
462  !
463  ! -- Compute "b" weights.
464  bd = 0d0
465  dsum = 0d0
466  do il = 1, nnbr
467  ! -- If this is connection (0,1) or inactive, skip.
468  if ((il .eq. il01) .or. (inbr(il) .eq. 0)) cycle
469  bd(il) = omwt(il) * sign(1d0, vccde(il, nde1))
470  dsum = dsum + omwt(il) * dabs(vccde(il, nde1))
471  end do
472  !
473  oodsum = 1d0 / dsum
474  do il = 1, nnbr
475  ! -- If this is connection (0,1) or inactive, skip.
476  if ((il .eq. il01) .or. (inbr(il) .eq. 0)) cycle
477  bd(il) = bd(il) * oodsum
478  end do
479  !
480  ! -- Compute "a" weights.
481  add = 1d0
482  acd = 0d0
483  aed = 0d0
484  do il = 1, nnbr
485  ! -- If this is connection (0,1) or inactive, skip.
486  if ((il .eq. il01) .or. (inbr(il) .eq. 0)) cycle
487  acd = acd + bd(il) * vccde(il, 1)
488  aed = aed + bd(il) * vccde(il, nde2)
489  end do
490  !
491  ! -- Apply attenuation function to acd, aed, and bd.
492  if (vcmx .lt. vcthresh) then
493  fatten = vcmx / vcthresh
494  acd = acd * fatten
495  aed = aed * fatten
496  bd = bd * fatten
497  end if
498  !
Here is the caller graph for this function:

◆ getrot()

subroutine xt3dalgorithmmodule::getrot ( integer(i4b)  nnbrmx,
integer(i4b)  nnbr,
integer(i4b), dimension(nnbrmx)  inbr,
real(dp), dimension(nnbrmx, 3)  vc,
integer(i4b)  il01,
real(dp), dimension(3, 3)  rmat,
integer(i4b)  iml0 
)

This is also the matrix that transforms the components of a vector from (c, d, e) coordinates to model coordinates. [Its transpose transforms from model to (c, d, e) coordinates.]

vcc = unit vector for the primary connection, in model coordinates. vcd = unit vector for the first perpendicular direction, in model coordinates. vce = unit vector for the second perpendicular direction, in model coordinates. vcmax = unit vector for the connection with the maximum component perpendicular to the primary connection, in model coordinates. rmat = rotation matrix from model to (c, d, e) coordinates.

Definition at line 289 of file Xt3dAlgorithm.f90.

290  ! -- dummy
291  integer(I4B) :: nnbrmx
292  integer(I4B) :: nnbr
293  integer(I4B), dimension(nnbrmx) :: inbr
294  real(DP), dimension(nnbrmx, 3) :: vc
295  integer(I4B) :: il01
296  real(DP), dimension(3, 3) :: rmat
297  integer(I4B) :: iml0
298  ! -- local
299  real(DP), dimension(3) :: vcc
300  real(DP), dimension(3) :: vcd
301  real(DP), dimension(3) :: vce
302  real(DP), dimension(3) :: vcmax
303  integer(I4B) :: il
304  real(DP) :: acmpmn
305  real(DP) :: cmp
306  real(DP) :: acmp
307  real(DP) :: cmpmn
308  !
309  ! -- Set vcc.
310  vcc(:) = vc(il01, :)
311  !
312  ! -- Set vcmax. (If no connection has a perpendicular component greater
313  ! than some tiny threshold, return with iml0=0 and the first column of
314  ! rmat set to vcc -- the other columns are not needed.)
315  acmpmn = 1d0 - 1d-10
316  iml0 = 0
317  do il = 1, nnbr
318  if ((il .eq. il01) .or. (inbr(il) .eq. 0)) then
319  cycle
320  else
321  cmp = dot_product(vc(il, :), vcc)
322  acmp = dabs(cmp)
323  if (acmp .lt. acmpmn) then
324  cmpmn = cmp
325  acmpmn = acmp
326  iml0 = il
327  end if
328  end if
329  end do
330  if (iml0 == 0) then
331  rmat(:, 1) = vcc(:)
332  goto 999
333  else
334  vcmax(:) = vc(iml0, :)
335  end if
336  !
337  ! -- Set the first perpendicular direction as the direction that is coplanar
338  ! with vcc and vcmax and perpendicular to vcc.
339  vcd = vcmax - cmpmn * vcc
340  vcd = vcd / dsqrt(1d0 - cmpmn * cmpmn)
341  !
342  ! -- Set the second perpendicular direction as the cross product of the
343  ! primary and first-perpendicular directions.
344  vce(1) = vcc(2) * vcd(3) - vcc(3) * vcd(2)
345  vce(2) = vcc(3) * vcd(1) - vcc(1) * vcd(3)
346  vce(3) = vcc(1) * vcd(2) - vcc(2) * vcd(1)
347  !
348  ! -- Set the rotation matrix as the matrix with vcc, vcd, and vce as its
349  ! columns.
350  rmat(:, 1) = vcc(:)
351  rmat(:, 2) = vcd(:)
352  rmat(:, 3) = vce(:)
353  !
354  ! -- Return
355 999 return
Here is the caller graph for this function:

◆ qconds()

subroutine xt3dalgorithmmodule::qconds ( integer(i4b)  nnbrmx,
integer(i4b)  nnbr0,
integer(i4b), dimension(nnbrmx)  inbr0,
integer(i4b)  il01,
real(dp), dimension(nnbrmx, 3)  vc0,
real(dp), dimension(nnbrmx, 3)  vn0,
real(dp), dimension(nnbrmx)  dl0,
real(dp), dimension(nnbrmx)  dl0n,
real(dp), dimension(3, 3)  ck0,
integer(i4b)  nnbr1,
integer(i4b), dimension(nnbrmx)  inbr1,
integer(i4b)  il10,
real(dp), dimension(nnbrmx)  vc1,
real(dp), dimension(nnbrmx)  vn1,
real(dp), dimension(nnbrmx)  dl1,
real(dp), dimension(nnbrmx)  dl1n,
real(dp), dimension(3, 3)  ck1,
real(dp)  ar01,
real(dp)  ar10,
real(dp)  vcthresh,
logical  allhc0,
logical  allhc1,
real(dp)  chat01,
real(dp), dimension(nnbrmx)  chati0,
real(dp), dimension(nnbrmx)  chat1j 
)

nnbrmx = maximum number of neighbors allowed for a cell. nnbr0 = number of neighbors (local connections) for cell 0. inbr0 = array with the list of neighbors for cell 0. il01 = local node number of cell 1 with respect to cell 0. vc0 = array of connection unit-vectors for cell 0 with its neighbors. vn0 = array of unit normal vectors for cell 0's interfaces. dl0 = array of lengths contributed by cell 0 to its connections with its neighbors. dl0n = array of lengths contributed by cell 0's neighbors to their connections with cell 0. ck0 = conductivity tensor for cell 0. nnbr1 = number of neighbors (local connections) for cell 1. inbr1 = array with the list of neighbors for cell 1. il10 = local node number of cell 0 with respect to cell 1. vc1 = array of connection unit-vectors for cell 1 with its neighbors. vn1 = array of unit normal vectors for cell 1's interfaces. dl1 = array of lengths contributed by cell 1 to its connections with its neighbors. dl1n = array of lengths contributed by cell 1's neighbors to their connections with cell 1. ck1 = conductivity tensor for cell1. ar01 = area of interface (0,1). ar10 = area of interface (1,0). chat01 = "conductance" for connection (0,1). chati0 = array of "conductances" for connections of cell 0. (zero for connection with cell 1, as this connection is already covered by chat01.) chat1j = array of "conductances" for connections of cell 1. (zero for connection with cell 0., as this connection is already covered by chat01.)

Definition at line 47 of file Xt3dAlgorithm.f90.

50  ! -- dummy
51  integer(I4B) :: nnbrmx
52  integer(I4B) :: nnbr0
53  integer(I4B), dimension(nnbrmx) :: inbr0
54  integer(I4B) :: il01
55  real(DP), dimension(nnbrmx, 3) :: vc0
56  real(DP), dimension(nnbrmx, 3) :: vn0
57  real(DP), dimension(nnbrmx) :: dl0
58  real(DP), dimension(nnbrmx) :: dl0n
59  real(DP), dimension(3, 3) :: ck0
60  integer(I4B) :: nnbr1
61  integer(I4B), dimension(nnbrmx) :: inbr1
62  integer(I4B) :: il10
63  real(DP), dimension(nnbrmx) :: vc1
64  real(DP), dimension(nnbrmx) :: vn1
65  real(DP), dimension(nnbrmx) :: dl1
66  real(DP), dimension(nnbrmx) :: dl1n
67  real(DP), dimension(3, 3) :: ck1
68  real(DP) :: ar01
69  real(DP) :: ar10
70  real(DP) :: vcthresh
71  logical :: allhc0
72  logical :: allhc1
73  real(DP) :: chat01
74  real(DP), dimension(nnbrmx) :: chati0
75  real(DP), dimension(nnbrmx) :: chat1j
76  ! -- local
77  integer(I4B) :: i1
78  integer(I4B) :: i
79  real(DP) :: ahat0
80  real(DP) :: ahat1
81  real(DP) :: wght1
82  real(DP) :: wght0
83  real(DP), dimension(nnbrmx) :: bhat0
84  real(DP), dimension(nnbrmx) :: bhat1
85  real(DP) :: denom
86  !
87  ! -- Set the global cell number for cell 1, as found in the neighbor list
88  ! for cell 0. It is assumed that cells 0 and 1 are both active, or else
89  ! this subroutine would not have been called.
90  i1 = inbr0(il01)
91  !
92  ! -- If area ar01 is zero (in which case ar10 is also zero, since this can
93  ! only happen here in the case of Newton), then the "conductances" are
94  ! all zero.
95  if (ar01 .eq. 0d0) then
96  chat01 = 0d0
97  do i = 1, nnbrmx
98  chati0(i) = 0d0
99  chat1j(i) = 0d0
100  end do
101  ! -- Else compute "conductances."
102  else
103  ! -- Compute contributions from cell 0.
104  call abhats(nnbrmx, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, ck0, &
105  vcthresh, allhc0, ar01, ahat0, bhat0)
106  ! -- Compute contributions from cell 1.
107  call abhats(nnbrmx, nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, &
108  vcthresh, allhc1, ar10, ahat1, bhat1)
109  ! -- Compute "conductances" based on the two flux estimates.
110  denom = (ahat0 + ahat1)
111  if (abs(denom) > dprec) then
112  wght1 = ahat0 / (ahat0 + ahat1)
113  else
114  wght1 = done
115  end if
116  wght0 = 1d0 - wght1
117  chat01 = wght1 * ahat1
118  do i = 1, nnbrmx
119  chati0(i) = wght0 * bhat0(i)
120  chat1j(i) = wght1 * bhat1(i)
121  end do
122  end if
123  !
124  ! -- Return
125  return
Here is the call graph for this function:
Here is the caller graph for this function:

◆ tranvc()

subroutine xt3dalgorithmmodule::tranvc ( integer(i4b)  nnbrmx,
integer(i4b)  nnbrs,
real(dp), dimension(3, 3)  rmat,
real(dp), dimension(nnbrmx, 3)  vc,
real(dp), dimension(nnbrmx, 3)  vccde 
)

nnbrs = number of neighbors (local connections) rmat = rotation matrix from (c, d, e) to model coordinates. vc = array of connection unit-vectors with respect to model coordinates. vccde = array of connection unit-vectors with respect to (c, d, e) coordinates.

Definition at line 366 of file Xt3dAlgorithm.f90.

367  ! -- dummy
368  integer(I4B) :: nnbrmx
369  integer(I4B) :: nnbrs
370  real(DP), dimension(3, 3) :: rmat
371  real(DP), dimension(nnbrmx, 3) :: vc
372  real(DP), dimension(nnbrmx, 3) :: vccde
373  ! -- local
374  integer(I4B) :: il
375  !
376  ! -- Loop over the local connections, transforming the unit vectors.
377  ! Note that we are multiplying by the transpose of the rotation matrix
378  ! so that the transformation is from model to (c, d, e) coordinates.
379  do il = 1, nnbrs
380  vccde(il, :) = matmul(transpose(rmat), vc(il, :))
381  end do
382  !
383  ! -- Return
384  return
Here is the caller graph for this function: