MODFLOW 6  version 6.9.0.dev0
USGS Modular Hydrologic Model
Xt3dInterface.f90
Go to the documentation of this file.
1 module xt3dmodule
2 
3  use kindmodule, only: dp, i4b
5  use basedismodule, only: disbasetype
8  implicit none
9 
10  public xt3dtype
11  public :: xt3d_cr
12 
13  type xt3dtype
14 
15  character(len=LENMEMPATH) :: memorypath !< location in memory manager for storing package variables
16  integer(I4B), pointer :: inunit => null() !< unit number from where xt3d was read
17  integer(I4B), pointer :: iout => null() !< unit number for output
18  integer(I4B), pointer :: inewton => null() !< Newton flag
19  integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound
20  integer(I4B), dimension(:), pointer, contiguous :: iax => null() !< ia array for extended neighbors used by xt3d
21  integer(I4B), dimension(:), pointer, contiguous :: jax => null() !< ja array for extended neighbors used by xt3d
22  integer(I4B), dimension(:), pointer, contiguous :: idxglox => null() !< mapping array for extended neighbors used by xt3d
23  integer(I4B), dimension(:), pointer, contiguous :: ia_xt3d => null() !< ia array for local extended xt3d connections (no diagonal)
24  integer(I4B), dimension(:), pointer, contiguous :: ja_xt3d => null() !< ja array for local extended xt3d connections (no diagonal)
25  integer(I4B), pointer :: numextnbrs => null() !< dimension of jax array
26  integer(I4B), pointer :: ixt3d => null() !< xt3d flag (0 is off, 1 is lhs, 2 is rhs)
27  logical, pointer :: nozee => null() !< nozee flag
28  real(dp), pointer :: vcthresh => null() !< attenuation function threshold
29  real(dp), dimension(:, :), pointer, contiguous :: rmatck => null() !< rotation matrix for the conductivity tensor
30  real(dp), dimension(:), pointer, contiguous :: qsat => null() !< saturated flow saved for Newton
31  integer(I4B), pointer :: nbrmax => null() !< maximum number of neighbors for any cell
32  real(dp), dimension(:), pointer, contiguous :: amatpc => null() !< saved contributions to amat from permanently confined connections, direct neighbors
33  real(dp), dimension(:), pointer, contiguous :: amatpcx => null() !< saved contributions to amat from permanently confined connections, extended neighbors
34  integer(I4B), dimension(:), pointer, contiguous :: iallpc => null() !< indicates for each node whether all connections processed by xt3d are permanently confined (0 no, 1 yes)
35  logical, pointer :: lamatsaved => null() !< indicates whether amat has been saved for permanently confined connections
36  class(disbasetype), pointer :: dis => null() !< discretization object
37  ! pointers to npf variables
38  real(dp), dimension(:), pointer, contiguous :: k11 => null() !< horizontal hydraulic conductivity
39  real(dp), dimension(:), pointer, contiguous :: k22 => null() !< minor axis of horizontal hydraulic conductivity ellipse
40  real(dp), dimension(:), pointer, contiguous :: k33 => null() !< vertical hydraulic conductivity
41  integer(I4B), pointer :: ik22 => null() !< flag indicates K22 was read
42  integer(I4B), pointer :: ik33 => null() !< flag indicates K33 was read
43  real(dp), dimension(:), pointer, contiguous :: sat => null() !< saturation (0. to 1.) for each cell
44  integer(I4B), dimension(:), pointer, contiguous :: icelltype => null() !< cell type (confined or unconfined)
45  integer(I4B), pointer :: iangle1 => null() !< flag to indicate angle1 was read
46  integer(I4B), pointer :: iangle2 => null() !< flag to indicate angle2 was read
47  integer(I4B), pointer :: iangle3 => null() !< flag to indicate angle3 was read
48  real(dp), dimension(:), pointer, contiguous :: angle1 => null() !< k ellipse rotation in xy plane around z axis (yaw)
49  real(dp), dimension(:), pointer, contiguous :: angle2 => null() !< k ellipse rotation up from xy plane around y axis (pitch)
50  real(dp), dimension(:), pointer, contiguous :: angle3 => null() !< k tensor rotation around x axis (roll)
51  logical, pointer :: ldispersion => null() !< flag to indicate dispersion
52 
53  contains
54 
55  procedure :: xt3d_df
56  procedure :: xt3d_ac
57  procedure :: xt3d_mc
58  procedure :: xt3d_ar
59  procedure :: xt3d_fc
60  procedure :: xt3d_fcpc
61  procedure :: xt3d_fhfb
62  procedure :: xt3d_flowjahfb
63  procedure :: xt3d_fn
64  procedure :: xt3d_flowja
65  procedure :: xt3d_da
66  procedure, private :: allocate_scalars
67  procedure, private :: allocate_arrays
68  procedure, private :: xt3d_load
69  procedure, private :: xt3d_load_inbr
70  procedure, private :: xt3d_indices
71  procedure, private :: xt3d_areas
72  procedure, private :: xt3d_amat_nbrs
73  procedure, private :: xt3d_amatpc_nbrs
74  procedure, private :: xt3d_amat_nbrnbrs
75  procedure, private :: xt3d_amatpcx_nbrnbrs
76  procedure, private :: xt3d_iallpc
77  procedure, private :: xt3d_get_iinm
78  procedure, private :: xt3d_get_iinmx
79  procedure, private :: xt3d_rhs
80  procedure, private :: xt3d_fillrmatck
81  procedure, private :: xt3d_qnbrs
82 
83  end type xt3dtype
84 
85 contains
86 
87  !> @brief Create a new xt3d object
88  !<
89  subroutine xt3d_cr(xt3dobj, name_model, inunit, iout, ldispopt)
90  ! -- dummy
91  type(xt3dtype), pointer :: xt3dobj
92  character(len=*), intent(in) :: name_model
93  integer(I4B), intent(in) :: inunit
94  integer(I4B), intent(in) :: iout
95  logical, optional, intent(in) :: ldispopt
96  !
97  ! -- Create the object
98  allocate (xt3dobj)
99  !
100  ! -- Assign the memory path
101  xt3dobj%memoryPath = create_mem_path(name_model, 'XT3D')
102  !
103  ! -- Allocate scalars
104  call xt3dobj%allocate_scalars()
105  !
106  ! -- Set variables
107  xt3dobj%inunit = inunit
108  xt3dobj%iout = iout
109  if (present(ldispopt)) xt3dobj%ldispersion = ldispopt
110  end subroutine xt3d_cr
111 
112  !> @brief Define the xt3d object
113  !<
114  subroutine xt3d_df(this, dis)
115  ! -- dummy
116  class(xt3dtype) :: this
117  class(disbasetype), pointer, intent(inout) :: dis
118  !
119  this%dis => dis
120  end subroutine xt3d_df
121 
122  !> @brief Add connections for extended neighbors to the sparse matrix
123  !<
124  subroutine xt3d_ac(this, moffset, sparse)
125  ! -- modules
126  use sparsemodule, only: sparsematrix
128  ! -- dummy
129  class(xt3dtype) :: this
130  integer(I4B), intent(in) :: moffset
131  type(sparsematrix), intent(inout) :: sparse
132  ! -- local
133  type(sparsematrix) :: sparse_xt3d
134  integer(I4B) :: i, j, k, jj, kk, iglo, kglo, iadded
135  integer(I4B) :: nnz
136  integer(I4B) :: ierror
137  !
138  ! -- If not rhs, add connections
139  if (this%ixt3d == 1) then
140  ! -- Assume nnz is 19, which is an approximate value
141  ! based on a 3d structured grid
142  nnz = 19
143  call sparse_xt3d%init(this%dis%nodes, this%dis%nodes, nnz)
144  !
145  ! -- Loop over nodes and store extended xt3d neighbors
146  ! temporarily in sparse_xt3d; this will be converted to
147  ! ia_xt3d and ja_xt3d next
148  do i = 1, this%dis%nodes
149  iglo = i + moffset
150  ! -- loop over neighbors
151  do jj = this%dis%con%ia(i) + 1, this%dis%con%ia(i + 1) - 1
152  j = this%dis%con%ja(jj)
153  ! -- loop over neighbors of neighbors
154  do kk = this%dis%con%ia(j) + 1, this%dis%con%ia(j + 1) - 1
155  k = this%dis%con%ja(kk)
156  kglo = k + moffset
157  call sparse_xt3d%addconnection(i, k, 1)
158  end do
159  end do
160  end do
161  !
162  ! -- calculate ia_xt3d and ja_xt3d from sparse_xt3d and
163  ! then destroy sparse
164  call mem_allocate(this%ia_xt3d, this%dis%nodes + 1, 'IA_XT3D', &
165  trim(this%memoryPath))
166  call mem_allocate(this%ja_xt3d, sparse_xt3d%nnz, 'JA_XT3D', &
167  trim(this%memoryPath))
168  call sparse_xt3d%filliaja(this%ia_xt3d, this%ja_xt3d, ierror)
169  call sparse_xt3d%destroy()
170  !
171  ! -- add extended neighbors to sparse and count number of
172  ! extended neighbors
173  do i = 1, this%dis%nodes
174  iglo = i + moffset
175  do kk = this%ia_xt3d(i), this%ia_xt3d(i + 1) - 1
176  k = this%ja_xt3d(kk)
177  kglo = k + moffset
178  call sparse%addconnection(iglo, kglo, 1, iadded)
179  this%numextnbrs = this%numextnbrs + 1
180  end do
181  end do
182  else
183  ! -- Arrays not needed; set to size zero
184  call mem_allocate(this%ia_xt3d, 0, 'IA_XT3D', trim(this%memoryPath))
185  call mem_allocate(this%ja_xt3d, 0, 'JA_XT3D', trim(this%memoryPath))
186  end if
187  end subroutine xt3d_ac
188 
189  !> @brief Map connections and construct iax, jax, and idxglox
190  !<
191  subroutine xt3d_mc(this, moffset, matrix_sln)
192  ! -- modules
194  ! -- dummy
195  class(xt3dtype) :: this
196  integer(I4B), intent(in) :: moffset
197  class(matrixbasetype), pointer :: matrix_sln
198  ! -- local
199  integer(I4B) :: i, j, iglo, jglo, niax, njax, ipos
200  integer(I4B) :: ipos_sln, icol_first, icol_last
201  integer(I4B) :: jj_xt3d
202  integer(I4B) :: igfirstnod, iglastnod
203  logical :: isextnbr
204  !
205  ! -- If not rhs, map connections for extended neighbors and construct iax,
206  ! -- jax, and idxglox
207  if (this%ixt3d == 1) then
208  !
209  ! -- calculate the first node for the model and the last node in global
210  ! numbers
211  igfirstnod = moffset + 1
212  iglastnod = moffset + this%dis%nodes
213  !
214  ! -- allocate iax, jax, and idxglox
215  niax = this%dis%nodes + 1
216  njax = this%numextnbrs ! + 1
217  call mem_allocate(this%iax, niax, 'IAX', trim(this%memoryPath))
218  call mem_allocate(this%jax, njax, 'JAX', trim(this%memoryPath))
219  call mem_allocate(this%idxglox, njax, 'IDXGLOX', trim(this%memoryPath))
220  !
221  ! -- load first iax entry
222  ipos = 1
223  this%iax(1) = ipos
224  !
225  ! -- loop over nodes
226  do i = 1, this%dis%nodes
227  !
228  ! -- calculate global node number
229  iglo = i + moffset
230  icol_first = matrix_sln%get_first_col_pos(iglo)
231  icol_last = matrix_sln%get_last_col_pos(iglo)
232  do ipos_sln = icol_first, icol_last
233  !
234  ! -- if jglo is in a different model, then it cannot be an extended
235  ! neighbor, so skip over it
236  jglo = matrix_sln%get_column(ipos_sln)
237  if (jglo < igfirstnod .or. jglo > iglastnod) then
238  cycle
239  end if
240  !
241  ! -- Check to see if this local connection was added by
242  ! xt3d. If not, then this connection was added by
243  ! something else, such as an interface model.
244  j = jglo - moffset
245  isextnbr = .false.
246  do jj_xt3d = this%ia_xt3d(i), this%ia_xt3d(i + 1) - 1
247  if (j == this%ja_xt3d(jj_xt3d)) then
248  isextnbr = .true.
249  exit
250  end if
251  end do
252  !
253  ! -- if an extended neighbor, add it to jax and idxglox
254  if (isextnbr) then
255  this%jax(ipos) = matrix_sln%get_column(ipos_sln) - moffset
256  this%idxglox(ipos) = ipos_sln
257  ipos = ipos + 1
258  end if
259  end do
260  ! -- load next iax entry
261  this%iax(i + 1) = ipos
262  end do
263  !
264  else
265  !
266  call mem_allocate(this%iax, 0, 'IAX', trim(this%memoryPath))
267  call mem_allocate(this%jax, 0, 'JAX', trim(this%memoryPath))
268  call mem_allocate(this%idxglox, 0, 'IDXGLOX', trim(this%memoryPath))
269  !
270  end if
271  end subroutine xt3d_mc
272 
273  !> @brief Allocate and Read
274  !<
275  subroutine xt3d_ar(this, ibound, k11, ik33, k33, sat, ik22, k22, iangle1, &
276  iangle2, iangle3, angle1, angle2, angle3, inewton, icelltype)
277  ! -- modules
278  use simmodule, only: store_error
279  ! -- dummy
280  class(xt3dtype) :: this
281  integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: ibound
282  real(DP), dimension(:), intent(in), pointer, contiguous :: k11
283  integer(I4B), intent(in), pointer :: ik33
284  real(DP), dimension(:), intent(in), pointer, contiguous :: k33
285  real(DP), dimension(:), intent(in), pointer, contiguous :: sat
286  integer(I4B), intent(in), pointer :: ik22
287  real(DP), dimension(:), intent(in), pointer, contiguous :: k22
288  integer(I4B), intent(in), pointer :: iangle1
289  integer(I4B), intent(in), pointer :: iangle2
290  integer(I4B), intent(in), pointer :: iangle3
291  real(DP), dimension(:), intent(in), pointer, contiguous :: angle1
292  real(DP), dimension(:), intent(in), pointer, contiguous :: angle2
293  real(DP), dimension(:), intent(in), pointer, contiguous :: angle3
294  integer(I4B), intent(in), pointer, optional :: inewton
295  integer(I4B), dimension(:), intent(in), pointer, &
296  contiguous, optional :: icelltype
297  ! -- local
298  integer(I4B) :: n, nnbrs
299  ! -- formats
300  character(len=*), parameter :: fmtheader = &
301  "(1x, /1x, 'XT3D is active.'//)"
302  !
303  ! -- Print a message identifying the xt3d module.
304  if (this%iout > 0) then
305  write (this%iout, fmtheader)
306  end if
307  !
308  ! -- Store pointers to arguments that were passed in
309  this%ibound => ibound
310  this%k11 => k11
311  this%ik33 => ik33
312  this%k33 => k33
313  this%sat => sat
314  this%ik22 => ik22
315  this%k22 => k22
316  this%iangle1 => iangle1
317  this%iangle2 => iangle2
318  this%iangle3 => iangle3
319  this%angle1 => angle1
320  this%angle2 => angle2
321  this%angle3 => angle3
322  !
323  if (present(inewton)) then
324  ! -- inewton is not needed for transport so it's optional.
325  this%inewton = inewton
326  end if
327  if (present(icelltype)) then
328  ! -- icelltype is not needed for transport, so it's optional.
329  ! It is only needed to determine if cell connections are permanently
330  ! confined, which means that some matrix terms can be precalculated
331  this%icelltype => icelltype
332  end if
333  !
334  ! -- If angle1 and angle2 were not specified, then there is no z
335  ! component in the xt3d formulation for horizontal connections.
336  if (this%iangle2 == 0) this%nozee = .true.
337  !
338  ! -- Determine the maximum number of neighbors for any cell.
339  this%nbrmax = 0
340  do n = 1, this%dis%nodes
341  nnbrs = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1
342  this%nbrmax = max(nnbrs, this%nbrmax)
343  end do
344  !
345  ! -- Check to make sure dis package can calculate connection direction info
346  if (this%dis%icondir == 0) then
347  call store_error('Vertices not specified for discretization package, '// &
348  'but XT3D is active: '//trim(adjustl(this%memoryPath))// &
349  '. Vertices must be specified in discretization '// &
350  'package in order to use XT3D.', terminate=.true.)
351  end if
352  !
353  ! -- Check to make sure ANGLEDEGX is available for interface normals
354  if (this%dis%con%ianglex == 0) then
355  call store_error('ANGLDEGX is not specified in the DIS package, '// &
356  'but XT3D is active: '//trim(adjustl(this%memoryPath))// &
357  '. ANGLDEGX must be provided in discretization '// &
358  'package in order to use XT3D.', terminate=.true.)
359  end if
360  !
361  ! -- allocate arrays
362  call this%allocate_arrays()
363  !
364  ! -- If not Newton and not rhs, precalculate amatpc and amatpcx for
365  ! -- permanently confined connections
366  if (this%lamatsaved .and. .not. this%ldispersion) &
367  call this%xt3d_fcpc(this%dis%nodes, .true.)
368  end subroutine xt3d_ar
369 
370  !> @brief Formulate
371  subroutine xt3d_fc(this, kiter, matrix_sln, idxglo, rhs, hnew)
372  ! -- modules
373  use constantsmodule, only: done
374  use xt3dalgorithmmodule, only: qconds
375  ! -- dummy
376  class(xt3dtype) :: this
377  integer(I4B) :: kiter
378  class(matrixbasetype), pointer :: matrix_sln
379  integer(I4B), intent(in), dimension(:) :: idxglo
380  real(DP), intent(inout), dimension(:) :: rhs
381  real(DP), intent(inout), dimension(:) :: hnew
382  ! -- local
383  integer(I4B) :: nodes, nja
384  integer(I4B) :: n, m, ipos
385  logical :: allhc0, allhc1
386  integer(I4B) :: nnbr0, nnbr1
387  integer(I4B) :: il0, ii01, jjs01, il01, il10, ii00, ii11, ii10
388  integer(I4B) :: i
389  integer(I4B), dimension(this%nbrmax) :: inbr0, inbr1
390  real(DP) :: ar01, ar10
391  real(DP), dimension(this%nbrmax, 3) :: vc0, vn0, vc1, vn1
392  real(DP), dimension(this%nbrmax) :: dl0, dl0n, dl1, dl1n
393  real(DP), dimension(3, 3) :: ck0, ck1
394  real(DP) :: chat01
395  real(DP), dimension(this%nbrmax) :: chati0, chat1j
396  real(DP) :: qnm, qnbrs
397  !
398  ! -- Calculate xt3d conductance-like coefficients and put into amat and rhs
399  ! -- as appropriate
400  !
401  nodes = this%dis%nodes
402  nja = this%dis%con%nja
403  if (this%lamatsaved) then
404  do i = 1, this%dis%con%nja
405  call matrix_sln%add_value_pos(idxglo(i), this%amatpc(i))
406  end do
407  do i = 1, this%numextnbrs
408  call matrix_sln%add_value_pos(this%idxglox(i), this%amatpcx(i))
409  end do
410  end if
411  !
412  do n = 1, nodes
413  ! -- Skip if inactive.
414  if (this%ibound(n) .eq. 0) cycle
415  ! -- Skip if all connections are permanently confined
416  if (this%lamatsaved) then
417  if (this%iallpc(n) == 1) cycle
418  end if
419  nnbr0 = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1
420  ! -- Load conductivity and connection info for cell 0.
421  call this%xt3d_load(nodes, n, nnbr0, inbr0, vc0, vn0, dl0, dl0n, &
422  ck0, allhc0)
423  ! -- Loop over active neighbors of cell 0 that have a higher
424  ! cell number (taking advantage of reciprocity).
425  do il0 = 1, nnbr0
426  ipos = this%dis%con%ia(n) + il0
427  if (this%dis%con%mask(ipos) == 0) cycle
428 
429  m = inbr0(il0)
430  ! -- Skip if neighbor is inactive or has lower cell number.
431  if ((m .eq. 0) .or. (m .lt. n)) cycle
432  nnbr1 = this%dis%con%ia(m + 1) - this%dis%con%ia(m) - 1
433  ! -- Load conductivity and connection info for cell 1.
434  call this%xt3d_load(nodes, m, nnbr1, inbr1, vc1, vn1, dl1, dl1n, &
435  ck1, allhc1)
436  ! -- Set various indices.
437  call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, &
438  ii00, ii11, ii10)
439  ! -- Compute areas.
440  if (this%inewton /= 0) then
441  ar01 = done
442  ar10 = done
443  else
444  call this%xt3d_areas(nodes, n, m, jjs01, .false., ar01, ar10, hnew)
445  end if
446  ! -- Compute "conductances" for interface between
447  ! cells 0 and 1.
448  call qconds(this%nbrmax, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, ck0, &
449  nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, &
450  this%vcthresh, allhc0, allhc1, chat01, chati0, chat1j)
451  ! -- If Newton, compute and save saturated flow, then scale
452  ! conductance-like coefficients by the actual area for
453  ! subsequent amat and rhs assembly.
454  if (this%inewton /= 0) then
455  ! -- Contribution to flow from primary connection.
456  qnm = chat01 * (hnew(m) - hnew(n))
457  ! -- Contribution from immediate neighbors of node 0.
458  call this%xt3d_qnbrs(nodes, n, m, nnbr0, inbr0, chati0, hnew, qnbrs)
459  qnm = qnm + qnbrs
460  ! -- Contribution from immediate neighbors of node 1.
461  call this%xt3d_qnbrs(nodes, m, n, nnbr1, inbr1, chat1j, hnew, qnbrs)
462  qnm = qnm - qnbrs
463  ! -- Multiply by saturated area and save in qsat.
464  call this%xt3d_areas(nodes, n, m, jjs01, .true., ar01, ar10, hnew)
465  this%qsat(ii01) = qnm * ar01
466  ! -- Scale coefficients by actual area.
467  call this%xt3d_areas(nodes, n, m, jjs01, .false., ar01, ar10, hnew, &
468  this%qsat(ii01))
469  chat01 = chat01 * ar01
470  chati0 = chati0 * ar01
471  chat1j = chat1j * ar01
472  end if
473  !
474  ! -- Contribute to rows for cells 0 and 1.
475  call matrix_sln%add_value_pos(idxglo(ii00), -chat01)
476  call matrix_sln%add_value_pos(idxglo(ii01), chat01)
477  call matrix_sln%add_value_pos(idxglo(ii11), -chat01)
478  call matrix_sln%add_value_pos(idxglo(ii10), chat01)
479  if (this%ixt3d == 1) then
480  call this%xt3d_amat_nbrs(nodes, n, ii00, nnbr0, nja, matrix_sln, &
481  inbr0, idxglo, chati0)
482  call this%xt3d_amat_nbrnbrs(nodes, n, m, ii01, nnbr1, nja, matrix_sln, &
483  inbr1, idxglo, chat1j)
484  call this%xt3d_amat_nbrs(nodes, m, ii11, nnbr1, nja, matrix_sln, &
485  inbr1, idxglo, chat1j)
486  call this%xt3d_amat_nbrnbrs(nodes, m, n, ii10, nnbr0, nja, matrix_sln, &
487  inbr0, idxglo, chati0)
488  else
489  call this%xt3d_rhs(nodes, n, m, nnbr0, inbr0, chati0, hnew, rhs)
490  call this%xt3d_rhs(nodes, m, n, nnbr1, inbr1, chat1j, hnew, rhs)
491  end if
492  !
493  end do
494  end do
495  end subroutine xt3d_fc
496 
497  !> @brief Formulate for permanently confined connections and save in amatpc
498  !! and amatpcx
499  !<
500  subroutine xt3d_fcpc(this, nodes, lsat)
501  ! -- modules
502  use xt3dalgorithmmodule, only: qconds
503  ! -- dummy
504  class(xt3dtype) :: this
505  integer(I4B), intent(in) :: nodes
506  logical, intent(in) :: lsat !< if true, then calculations made with saturated areas (should be false for solute dispersion; should be true for heat)
507  ! -- local
508  integer(I4B) :: n, m, ipos
509  !
510  logical :: allhc0, allhc1
511  integer(I4B) :: nnbr0, nnbr1
512  integer(I4B) :: il0, ii01, jjs01, il01, il10, ii00, ii11, ii10
513  integer(I4B), dimension(this%nbrmax) :: inbr0, inbr1
514  real(DP) :: ar01, ar10
515  real(DP), dimension(this%nbrmax, 3) :: vc0, vn0, vc1, vn1
516  real(DP), dimension(this%nbrmax) :: dl0, dl0n, dl1, dl1n
517  real(DP), dimension(3, 3) :: ck0, ck1
518  real(DP) :: chat01
519  real(DP), dimension(this%nbrmax) :: chati0, chat1j
520  !
521  ! -- Initialize amatpc and amatpcx to zero
522  do n = 1, size(this%amatpc)
523  this%amatpc(n) = dzero
524  end do
525  do n = 1, size(this%amatpcx)
526  this%amatpcx(n) = dzero
527  end do
528  !
529  ! -- Calculate xt3d conductance-like coefficients for permanently confined
530  ! -- connections and put into amatpc and amatpcx as appropriate
531  do n = 1, nodes
532  ! -- Skip if not iallpc.
533  if (this%iallpc(n) == 0) cycle
534  if (this%ibound(n) == 0) cycle
535  nnbr0 = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1
536  ! -- Load conductivity and connection info for cell 0.
537  call this%xt3d_load(nodes, n, nnbr0, inbr0, vc0, vn0, dl0, dl0n, &
538  ck0, allhc0)
539  ! -- Loop over active neighbors of cell 0 that have a higher
540  ! -- cell number (taking advantage of reciprocity).
541  do il0 = 1, nnbr0
542  ipos = this%dis%con%ia(n) + il0
543  if (this%dis%con%mask(ipos) == 0) cycle
544 
545  m = inbr0(il0)
546  ! -- Skip if neighbor has lower cell number.
547  if (m .lt. n) cycle
548  nnbr1 = this%dis%con%ia(m + 1) - this%dis%con%ia(m) - 1
549  ! -- Load conductivity and connection info for cell 1.
550  call this%xt3d_load(nodes, m, nnbr1, inbr1, vc1, vn1, dl1, dl1n, &
551  ck1, allhc1)
552  ! -- Set various indices.
553  call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, &
554  ii00, ii11, ii10)
555  ! -- Compute confined areas.
556  call this%xt3d_areas(nodes, n, m, jjs01, lsat, ar01, ar10)
557  ! -- Compute "conductances" for interface between
558  ! -- cells 0 and 1.
559  call qconds(this%nbrmax, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, ck0, &
560  nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, &
561  this%vcthresh, allhc0, allhc1, chat01, chati0, chat1j)
562  ! -- Contribute to rows for cells 0 and 1.
563  this%amatpc(ii00) = this%amatpc(ii00) - chat01
564  this%amatpc(ii01) = this%amatpc(ii01) + chat01
565  this%amatpc(ii11) = this%amatpc(ii11) - chat01
566  this%amatpc(ii10) = this%amatpc(ii10) + chat01
567  call this%xt3d_amatpc_nbrs(nodes, n, ii00, nnbr0, inbr0, chati0)
568  call this%xt3d_amatpcx_nbrnbrs(nodes, n, m, ii01, nnbr1, inbr1, chat1j)
569  call this%xt3d_amatpc_nbrs(nodes, m, ii11, nnbr1, inbr1, chat1j)
570  call this%xt3d_amatpcx_nbrnbrs(nodes, m, n, ii10, nnbr0, inbr0, chati0)
571  end do
572  end do
573  end subroutine xt3d_fcpc
574 
575  !> @brief Formulate HFB correction
576  !<
577  subroutine xt3d_fhfb(this, kiter, nodes, nja, matrix_sln, idxglo, rhs, hnew, &
578  n, m, condhfb)
579  ! -- modules
580  use constantsmodule, only: done
581  use xt3dalgorithmmodule, only: qconds
582  ! -- dummy
583  class(xt3dtype) :: this
584  integer(I4B) :: kiter
585  integer(I4B), intent(in) :: nodes
586  integer(I4B), intent(in) :: nja
587  class(matrixbasetype), pointer :: matrix_sln
588  integer(I4B) :: n, m
589  integer(I4B), intent(in), dimension(nja) :: idxglo
590  real(DP), intent(inout), dimension(nodes) :: rhs
591  real(DP), intent(inout), dimension(nodes) :: hnew
592  real(DP) :: condhfb
593  ! -- local
594  logical :: allhc0, allhc1
595  integer(I4B) :: nnbr0, nnbr1
596  integer(I4B) :: il0, ii01, jjs01, il01, il10, ii00, ii11, ii10, il
597  integer(I4B), dimension(this%nbrmax) :: inbr0, inbr1
598  real(DP) :: ar01, ar10
599  real(DP), dimension(this%nbrmax, 3) :: vc0, vn0, vc1, vn1
600  real(DP), dimension(this%nbrmax) :: dl0, dl0n, dl1, dl1n
601  real(DP), dimension(3, 3) :: ck0, ck1
602  real(DP) :: chat01
603  real(DP), dimension(this%nbrmax) :: chati0, chat1j
604  real(DP) :: qnm, qnbrs
605  real(DP) :: term
606  !
607  ! -- Calculate hfb corrections to xt3d conductance-like coefficients and
608  ! put into amat and rhs as appropriate
609  !
610  nnbr0 = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1
611  ! -- Load conductivity and connection info for cell 0.
612  call this%xt3d_load(nodes, n, nnbr0, inbr0, vc0, vn0, dl0, dl0n, &
613  ck0, allhc0)
614  ! -- Find local neighbor number of cell 1.
615  do il = 1, nnbr0
616  if (inbr0(il) .eq. m) then
617  il0 = il
618  exit
619  end if
620  end do
621  nnbr1 = this%dis%con%ia(m + 1) - this%dis%con%ia(m) - 1
622  ! -- Load conductivity and connection info for cell 1.
623  call this%xt3d_load(nodes, m, nnbr1, inbr1, vc1, vn1, dl1, dl1n, &
624  ck1, allhc1)
625  ! -- Set various indices.
626  call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, &
627  ii00, ii11, ii10)
628  ! -- Compute areas.
629  if (this%inewton /= 0) then
630  ar01 = done
631  ar10 = done
632  else
633  call this%xt3d_areas(nodes, n, m, jjs01, .false., ar01, ar10, hnew)
634  end if
635  !
636  ! -- Compute "conductances" for interface between
637  ! cells 0 and 1.
638  call qconds(this%nbrmax, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, &
639  ck0, nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, &
640  this%vcthresh, allhc0, allhc1, chat01, chati0, chat1j)
641  !
642  ! -- Apply scale factor to compute "conductances" for hfb correction
643  if (condhfb > dzero) then
644  term = chat01 / (chat01 + condhfb)
645  else
646  term = -condhfb
647  end if
648  chat01 = -chat01 * term
649  chati0 = -chati0 * term
650  chat1j = -chat1j * term
651  !
652  ! -- If Newton, compute and save saturated flow, then scale conductance-like
653  ! coefficients by the actual area for subsequent amat and rhs assembly.
654  if (this%inewton /= 0) then
655  ! -- Contribution to flow from primary connection.
656  qnm = chat01 * (hnew(m) - hnew(n))
657  ! -- Contribution from immediate neighbors of node 0.
658  call this%xt3d_qnbrs(nodes, n, m, nnbr0, inbr0, chati0, hnew, qnbrs)
659  qnm = qnm + qnbrs
660  ! -- Contribution from immediate neighbors of node 1.
661  call this%xt3d_qnbrs(nodes, m, n, nnbr1, inbr1, chat1j, hnew, qnbrs)
662  qnm = qnm - qnbrs
663  ! -- Multiply by saturated area and add correction to qsat.
664  ! xt3d_fc selected the upstream cell from qsat before this
665  ! correction was added. That is consistent only because the HFB
666  ! correction reduces the magnitude of the flow and cannot reverse
667  ! its sign; a future correction that could change the sign of
668  ! qsat would require the upstream cell to be selected after all
669  ! corrections are applied.
670  call this%xt3d_areas(nodes, n, m, jjs01, .true., ar01, ar10, hnew)
671  this%qsat(ii01) = this%qsat(ii01) + qnm * ar01
672  ! -- Scale coefficients by actual area.
673  call this%xt3d_areas(nodes, n, m, jjs01, .false., ar01, ar10, hnew, &
674  this%qsat(ii01))
675  chat01 = chat01 * ar01
676  chati0 = chati0 * ar01
677  chat1j = chat1j * ar01
678  end if
679  !
680  ! -- Contribute to rows for cells 0 and 1.
681  call matrix_sln%add_value_pos(idxglo(ii00), -chat01)
682  call matrix_sln%add_value_pos(idxglo(ii01), chat01)
683  call matrix_sln%add_value_pos(idxglo(ii11), -chat01)
684  call matrix_sln%add_value_pos(idxglo(ii10), chat01)
685  if (this%ixt3d == 1) then
686  call this%xt3d_amat_nbrs(nodes, n, ii00, nnbr0, nja, matrix_sln, &
687  inbr0, idxglo, chati0)
688  call this%xt3d_amat_nbrnbrs(nodes, n, m, ii01, nnbr1, nja, matrix_sln, &
689  inbr1, idxglo, chat1j)
690  call this%xt3d_amat_nbrs(nodes, m, ii11, nnbr1, nja, matrix_sln, &
691  inbr1, idxglo, chat1j)
692  call this%xt3d_amat_nbrnbrs(nodes, m, n, ii10, nnbr0, nja, matrix_sln, &
693  inbr0, idxglo, chati0)
694  else
695  call this%xt3d_rhs(nodes, n, m, nnbr0, inbr0, chati0, hnew, rhs)
696  call this%xt3d_rhs(nodes, m, n, nnbr1, inbr1, chat1j, hnew, rhs)
697  end if
698  end subroutine xt3d_fhfb
699 
700  !> @brief Fill Newton terms for xt3d
701  subroutine xt3d_fn(this, kiter, nodes, nja, matrix_sln, idxglo, rhs, hnew)
702  ! -- modules
703  use constantsmodule, only: done
705  ! -- dummy
706  class(xt3dtype) :: this
707  integer(I4B) :: kiter
708  integer(I4B), intent(in) :: nodes
709  integer(I4B), intent(in) :: nja
710  class(matrixbasetype), pointer :: matrix_sln
711  integer(I4B), intent(in), dimension(nja) :: idxglo
712  real(DP), intent(inout), dimension(nodes) :: rhs
713  real(DP), intent(inout), dimension(nodes) :: hnew
714  ! -- local
715  integer(I4B) :: n, m, ipos
716  integer(I4B) :: nnbr0
717  integer(I4B) :: il0, ii01, jjs01, il01, il10, ii00, ii11, ii10
718  integer(I4B), dimension(this%nbrmax) :: inbr0
719  integer(I4B) :: iups, idn
720  real(DP) :: topup, botup, derv, term
721  !
722  ! -- Update amat and rhs with Newton terms
723  do n = 1, nodes
724  !
725  ! -- Skip if inactive.
726  if (this%ibound(n) .eq. 0) cycle
727  !
728  ! -- No Newton correction if amat saved (which implies no rhs option)
729  ! and all connections for the cell are permanently confined.
730  if (this%lamatsaved) then
731  if (this%iallpc(n) == 1) cycle
732  end if
733  nnbr0 = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1
734  !
735  ! -- Load neighbors of cell. Set cell numbers for inactive
736  ! neighbors to zero.
737  call this%xt3d_load_inbr(n, nnbr0, inbr0)
738  !
739  ! -- Loop over active neighbors of cell 0 that have a higher
740  ! cell number (taking advantage of reciprocity).
741  do il0 = 1, nnbr0
742  ipos = this%dis%con%ia(n) + il0
743  if (this%dis%con%mask(ipos) == 0) cycle
744  !
745  m = inbr0(il0)
746  !
747  ! -- Skip if neighbor is inactive or has lower cell number.
748  if ((inbr0(il0) .eq. 0) .or. (m .lt. n)) cycle
749  !
750  ! -- Set various indices.
751  call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, &
752  ii00, ii11, ii10)
753  !
754  ! -- Determine upstream node from the direction of the saturated
755  ! xt3d flow (qsat > 0 is flow into n from m), consistent with the
756  ! saturation used to scale the flow in xt3d_areas
757  iups = m
758  if (this%qsat(ii01) < dzero) iups = n
759  idn = n
760  if (iups == n) idn = m
761  !
762  ! -- No Newton terms if upstream cell is confined and no rhs option
763  if ((this%icelltype(iups) == 0) .and. (this%ixt3d .eq. 1)) cycle
764  !
765  ! -- Set the upstream top and bot, and then recalculate for a
766  ! vertically staggered horizontal connection
767  topup = this%dis%top(iups)
768  botup = this%dis%bot(iups)
769  if (this%dis%con%ihc(jjs01) == 2) then
770  topup = min(this%dis%top(n), this%dis%top(m))
771  botup = max(this%dis%bot(n), this%dis%bot(m))
772  end if
773  !
774  ! -- Derivative term
775  derv = squadraticsaturationderivative(topup, botup, hnew(iups))
776  term = this%qsat(ii01) * derv
777  !
778  ! -- Fill Jacobian for n being the upstream node
779  if (iups == n) then
780  !
781  ! -- Fill in row of n
782  call matrix_sln%add_value_pos(idxglo(ii00), term)
783  rhs(n) = rhs(n) + term * hnew(n)
784  !
785  ! -- Fill in row of m
786  call matrix_sln%add_value_pos(idxglo(ii10), -term)
787  rhs(m) = rhs(m) - term * hnew(n)
788  !
789  ! -- Fill Jacobian for m being the upstream node
790  else
791  !
792  ! -- Fill in row of n
793  call matrix_sln%add_value_pos(idxglo(ii01), term)
794  rhs(n) = rhs(n) + term * hnew(m)
795  !
796  ! -- Fill in row of m
797  call matrix_sln%add_value_pos(idxglo(ii11), -term)
798  rhs(m) = rhs(m) - term * hnew(m)
799  !
800  end if
801  end do
802  end do
803  end subroutine xt3d_fn
804 
805  !> @brief Budget
806  !<
807  subroutine xt3d_flowja(this, hnew, flowja)
808  ! -- modules
809  use xt3dalgorithmmodule, only: qconds
810  ! -- dummy
811  class(xt3dtype) :: this
812  real(DP), intent(inout), dimension(:) :: hnew
813  real(DP), intent(inout), dimension(:) :: flowja
814  ! -- local
815  integer(I4B) :: n, ipos, m, nodes
816  real(DP) :: qnm, qnbrs
817  logical :: allhc0, allhc1
818  integer(I4B) :: nnbr0, nnbr1
819  integer(I4B) :: il0, ii01, jjs01, il01, il10, ii00, ii11, ii10
820  integer(I4B), dimension(this%nbrmax) :: inbr0, inbr1
821  real(DP) :: ar01, ar10
822  real(DP), dimension(this%nbrmax, 3) :: vc0, vn0, vc1, vn1
823  real(DP), dimension(this%nbrmax) :: dl0, dl0n, dl1, dl1n
824  real(DP), dimension(3, 3) :: ck0, ck1
825  real(DP) :: chat01
826  real(DP), dimension(this%nbrmax) :: chati0, chat1j
827  !
828  ! -- Calculate the flow across each cell face and store in flowja
829  nodes = this%dis%nodes
830  do n = 1, nodes
831  !
832  ! -- Skip if inactive.
833  if (this%ibound(n) .eq. 0) cycle
834  nnbr0 = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1
835  !
836  ! -- Load conductivity and connection info for cell 0.
837  call this%xt3d_load(nodes, n, nnbr0, inbr0, vc0, vn0, dl0, dl0n, &
838  ck0, allhc0)
839  !
840  ! -- Loop over active neighbors of cell 0 that have a higher
841  ! cell number (taking advantage of reciprocity).
842  do il0 = 1, nnbr0
843  m = inbr0(il0)
844  !
845  ! -- Skip if neighbor is inactive or has lower cell number.
846  if ((inbr0(il0) .eq. 0) .or. (m .lt. n)) cycle
847  nnbr1 = this%dis%con%ia(m + 1) - this%dis%con%ia(m) - 1
848  !
849  ! -- Load conductivity and connection info for cell 1.
850  call this%xt3d_load(nodes, m, nnbr1, inbr1, vc1, vn1, dl1, dl1n, &
851  ck1, allhc1)
852  !
853  ! -- Set various indices.
854  call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, &
855  ii00, ii11, ii10)
856  !
857  ! -- Compute areas.
858  if (this%inewton /= 0) then
859  call this%xt3d_areas(nodes, n, m, jjs01, .true., ar01, ar10, hnew)
860  call this%xt3d_areas(nodes, n, m, jjs01, .false., ar01, ar10, hnew, &
861  this%qsat(ii01))
862  else
863  call this%xt3d_areas(nodes, n, m, jjs01, .false., ar01, ar10, hnew)
864  end if
865  !
866  ! -- Compute "conductances" for interface between
867  ! cells 0 and 1.
868  call qconds(this%nbrmax, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, ck0, &
869  nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, &
870  this%vcthresh, allhc0, allhc1, chat01, chati0, chat1j)
871  !
872  ! -- Contribution to flow from primary connection.
873  qnm = chat01 * (hnew(m) - hnew(n))
874  !
875  ! -- Contribution from immediate neighbors of node 0.
876  call this%xt3d_qnbrs(nodes, n, m, nnbr0, inbr0, chati0, hnew, qnbrs)
877  qnm = qnm + qnbrs
878  !
879  ! -- Contribution from immediate neighbors of node 1.
880  call this%xt3d_qnbrs(nodes, m, n, nnbr1, inbr1, chat1j, hnew, qnbrs)
881  qnm = qnm - qnbrs
882  ipos = ii01
883  flowja(ipos) = flowja(ipos) + qnm
884  flowja(this%dis%con%isym(ipos)) = flowja(this%dis%con%isym(ipos)) - qnm
885  end do
886  end do
887  end subroutine xt3d_flowja
888 
889  !> @brief hfb contribution to flowja when xt3d is used
890  !<
891  subroutine xt3d_flowjahfb(this, n, m, hnew, flowja, condhfb)
892  ! -- modules
893  use constantsmodule, only: done
894  use xt3dalgorithmmodule, only: qconds
895  ! -- dummy
896  class(xt3dtype) :: this
897  integer(I4B) :: n, m
898  real(DP), intent(inout), dimension(:) :: hnew
899  real(DP), intent(inout), dimension(:) :: flowja
900  real(DP) :: condhfb
901  ! -- local
902  integer(I4B) :: nodes
903  logical :: allhc0, allhc1
904  ! integer(I4B), parameter :: nbrmax = 10
905  integer(I4B) :: nnbr0, nnbr1
906  integer(I4B) :: il0, ii01, jjs01, il01, il10, ii00, ii11, ii10, il
907  integer(I4B), dimension(this%nbrmax) :: inbr0, inbr1
908  integer(I4B) :: ipos
909  real(DP) :: ar01, ar10
910  real(DP), dimension(this%nbrmax, 3) :: vc0, vn0, vc1, vn1
911  real(DP), dimension(this%nbrmax) :: dl0, dl0n, dl1, dl1n
912  real(DP), dimension(3, 3) :: ck0, ck1
913  real(DP) :: chat01
914  real(DP), dimension(this%nbrmax) :: chati0, chat1j
915  real(DP) :: qnm, qnbrs
916  real(DP) :: term
917  !
918  ! -- Calculate hfb corrections to xt3d conductance-like coefficients and
919  ! put into amat and rhs as appropriate
920  nodes = this%dis%nodes
921  nnbr0 = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1
922  !
923  ! -- Load conductivity and connection info for cell 0.
924  call this%xt3d_load(nodes, n, nnbr0, inbr0, vc0, vn0, dl0, dl0n, &
925  ck0, allhc0)
926  !
927  ! -- Find local neighbor number of cell 1.
928  do il = 1, nnbr0
929  if (inbr0(il) .eq. m) then
930  il0 = il
931  exit
932  end if
933  end do
934  !
935  nnbr1 = this%dis%con%ia(m + 1) - this%dis%con%ia(m) - 1
936  !
937  ! -- Load conductivity and connection info for cell 1.
938  call this%xt3d_load(nodes, m, nnbr1, inbr1, vc1, vn1, dl1, dl1n, &
939  ck1, allhc1)
940  !
941  ! -- Set various indices.
942  call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, &
943  ii00, ii11, ii10)
944  !
945  ! -- Compute areas.
946  if (this%inewton /= 0) then
947  ar01 = done
948  ar10 = done
949  else
950  call this%xt3d_areas(nodes, n, m, jjs01, .false., ar01, ar10, hnew)
951  end if
952  !
953  ! -- Compute "conductances" for interface between
954  ! cells 0 and 1.
955  call qconds(this%nbrmax, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, &
956  ck0, nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, &
957  this%vcthresh, allhc0, allhc1, chat01, chati0, chat1j)
958  !
959  ! -- Apply scale factor to compute "conductances" for hfb correction
960  if (condhfb > dzero) then
961  term = chat01 / (chat01 + condhfb)
962  else
963  term = -condhfb
964  end if
965  chat01 = -chat01 * term
966  chati0 = -chati0 * term
967  chat1j = -chat1j * term
968  !
969  ! -- Contribution to flow from primary connection.
970  qnm = chat01 * (hnew(m) - hnew(n))
971  !
972  ! -- Contribution from immediate neighbors of node 0.
973  call this%xt3d_qnbrs(nodes, n, m, nnbr0, inbr0, chati0, hnew, qnbrs)
974  qnm = qnm + qnbrs
975  !
976  ! -- Contribution from immediate neighbors of node 1.
977  call this%xt3d_qnbrs(nodes, m, n, nnbr1, inbr1, chat1j, hnew, qnbrs)
978  qnm = qnm - qnbrs
979  !
980  ! -- If Newton, scale conductance-like coefficients by the
981  ! actual area.
982  if (this%inewton /= 0) then
983  call this%xt3d_areas(nodes, n, m, jjs01, .true., ar01, ar10, hnew)
984  call this%xt3d_areas(nodes, n, m, jjs01, .false., ar01, ar10, hnew, &
985  this%qsat(ii01))
986  qnm = qnm * ar01
987  end if
988  !
989  ipos = ii01
990  flowja(ipos) = flowja(ipos) + qnm
991  flowja(this%dis%con%isym(ipos)) = flowja(this%dis%con%isym(ipos)) - qnm
992  end subroutine xt3d_flowjahfb
993 
994  !> @brief Deallocate variables
995  !<
996  subroutine xt3d_da(this)
997  ! -- modules
999  ! -- dummy
1000  class(xt3dtype) :: this
1001  !
1002  ! -- Deallocate arrays
1003  if (this%ixt3d /= 0) then
1004  call mem_deallocate(this%iax)
1005  call mem_deallocate(this%jax)
1006  call mem_deallocate(this%idxglox)
1007  call mem_deallocate(this%ia_xt3d)
1008  call mem_deallocate(this%ja_xt3d)
1009  call mem_deallocate(this%rmatck)
1010  call mem_deallocate(this%qsat)
1011  call mem_deallocate(this%amatpc)
1012  call mem_deallocate(this%amatpcx)
1013  call mem_deallocate(this%iallpc)
1014  end if
1015  !
1016  ! -- Scalars
1017  call mem_deallocate(this%ixt3d)
1018  call mem_deallocate(this%inunit)
1019  call mem_deallocate(this%iout)
1020  call mem_deallocate(this%inewton)
1021  call mem_deallocate(this%numextnbrs)
1022  call mem_deallocate(this%nozee)
1023  call mem_deallocate(this%vcthresh)
1024  call mem_deallocate(this%lamatsaved)
1025  call mem_deallocate(this%nbrmax)
1026  call mem_deallocate(this%ldispersion)
1027  end subroutine xt3d_da
1028 
1029  !> @brief Allocate scalar pointer variables
1030  !<
1031  subroutine allocate_scalars(this)
1032  ! -- modules
1034  ! -- dummy
1035  class(xt3dtype) :: this
1036  !
1037  ! -- Allocate scalars
1038  call mem_allocate(this%ixt3d, 'IXT3D', this%memoryPath)
1039  call mem_allocate(this%nbrmax, 'NBRMAX', this%memoryPath)
1040  call mem_allocate(this%inunit, 'INUNIT', this%memoryPath)
1041  call mem_allocate(this%iout, 'IOUT', this%memoryPath)
1042  call mem_allocate(this%inewton, 'INEWTON', this%memoryPath)
1043  call mem_allocate(this%numextnbrs, 'NUMEXTNBRS', this%memoryPath)
1044  call mem_allocate(this%nozee, 'NOZEE', this%memoryPath)
1045  call mem_allocate(this%vcthresh, 'VCTHRESH', this%memoryPath)
1046  call mem_allocate(this%lamatsaved, 'LAMATSAVED', this%memoryPath)
1047  call mem_allocate(this%ldispersion, 'LDISPERSION', this%memoryPath)
1048  !
1049  ! -- Initialize value
1050  this%ixt3d = 0
1051  this%nbrmax = 0
1052  this%inunit = 0
1053  this%iout = 0
1054  this%inewton = 0
1055  this%numextnbrs = 0
1056  this%nozee = .false.
1057  this%vcthresh = 1.d-10
1058  this%lamatsaved = .false.
1059  this%ldispersion = .false.
1060  end subroutine allocate_scalars
1061 
1062  !> @brief Allocate xt3d arrays
1063  !<
1064  subroutine allocate_arrays(this)
1065  ! -- modules
1067  ! -- dummy
1068  class(xt3dtype) :: this
1069  ! -- local
1070  integer(I4B) :: njax
1071  integer(I4B) :: n
1072  !
1073  ! -- Allocate Newton-dependent arrays
1074  if (this%inewton /= 0) then
1075  call mem_allocate(this%qsat, this%dis%nja, 'QSAT', this%memoryPath)
1076  else
1077  call mem_allocate(this%qsat, 0, 'QSAT', this%memoryPath)
1078  end if
1079  !
1080  ! -- If dispersion, set iallpc to 1 otherwise call xt3d_iallpc to go through
1081  ! each connection and mark cells that are permanenntly confined and can
1082  ! have their coefficients precalculated
1083  if (this%ldispersion) then
1084  !
1085  ! -- xt3d is being used for dispersion; all matrix terms are precalculated
1086  ! and used repeatedly until flows change
1087  this%lamatsaved = .true.
1088  call mem_allocate(this%iallpc, this%dis%nodes, 'IALLPC', this%memoryPath)
1089  do n = 1, this%dis%nodes
1090  this%iallpc(n) = 1
1091  end do
1092  else
1093  !
1094  ! -- xt3d is being used for flow so find where connections are
1095  ! permanently confined and precalculate matrix terms case where
1096  ! conductances do not depend on head
1097  call this%xt3d_iallpc()
1098  end if
1099  !
1100  ! -- Allocate space for precalculated matrix terms
1101  if (this%lamatsaved) then
1102  call mem_allocate(this%amatpc, this%dis%nja, 'AMATPC', this%memoryPath)
1103  njax = this%numextnbrs ! + 1
1104  call mem_allocate(this%amatpcx, njax, 'AMATPCX', this%memoryPath)
1105  else
1106  call mem_allocate(this%amatpc, 0, 'AMATPC', this%memoryPath)
1107  call mem_allocate(this%amatpcx, 0, 'AMATPCX', this%memoryPath)
1108  end if
1109  !
1110  ! -- Allocate work arrays
1111  call mem_allocate(this%rmatck, 3, 3, 'RMATCK', this%memoryPath)
1112  !
1113  ! -- Initialize arrays to zero
1114  this%rmatck = dzero
1115  if (this%inewton /= 0) then
1116  this%qsat = dzero
1117  else if (this%lamatsaved) then
1118  this%amatpc = dzero
1119  this%amatpcx = dzero
1120  end if
1121  end subroutine allocate_arrays
1122 
1123  !> @brief Allocate and populate iallpc array. Set lamatsaved.
1124  subroutine xt3d_iallpc(this)
1125  ! -- modules
1127  ! -- dummy
1128  class(xt3dtype) :: this
1129  ! -- local
1130  integer(I4B) :: n, m, mm, il0, il1
1131  integer(I4B) :: nnbr0, nnbr1
1132  integer(I4B), dimension(this%nbrmax) :: inbr0, inbr1
1133  !
1134  if (this%ixt3d == 2) then
1135  this%lamatsaved = .false.
1136  call mem_allocate(this%iallpc, 0, 'IALLPC', this%memoryPath)
1137  else
1138  !
1139  ! -- allocate memory for iallpc and initialize to 1
1140  call mem_allocate(this%iallpc, this%dis%nodes, 'IALLPC', this%memoryPath)
1141  do n = 1, this%dis%nodes
1142  this%iallpc(n) = 1
1143  end do
1144  !
1145  ! -- Go through cells and connections and set iallpc to 0 if any
1146  ! connected cell is not confined
1147  do n = 1, this%dis%nodes
1148  if (this%icelltype(n) /= 0) then
1149  this%iallpc(n) = 0
1150  cycle
1151  end if
1152  nnbr0 = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1
1153  call this%xt3d_load_inbr(n, nnbr0, inbr0)
1154  do il0 = 1, nnbr0
1155  m = inbr0(il0)
1156  if (m .lt. n) cycle
1157  if (this%icelltype(m) /= 0) then
1158  this%iallpc(n) = 0
1159  this%iallpc(m) = 0
1160  cycle
1161  end if
1162  nnbr1 = this%dis%con%ia(m + 1) - this%dis%con%ia(m) - 1
1163  call this%xt3d_load_inbr(m, nnbr1, inbr1)
1164  do il1 = 1, nnbr1
1165  mm = inbr1(il1)
1166  if (this%icelltype(mm) /= 0) then
1167  this%iallpc(n) = 0
1168  this%iallpc(m) = 0
1169  this%iallpc(mm) = 0
1170  end if
1171  end do
1172  end do
1173  end do
1174  !
1175  ! -- If any cells have all permanently confined connections then
1176  ! performance can be improved by precalculating coefficients
1177  ! so set lamatsaved to true.
1178  this%lamatsaved = .false.
1179  do n = 1, this%dis%nodes
1180  if (this%iallpc(n) == 1) then
1181  this%lamatsaved = .true.
1182  exit
1183  end if
1184  end do
1185  end if
1186  !
1187  if (.not. this%lamatsaved) then
1188  ! there are no permanently confined connections so deallocate iallpc
1189  ! in order to save memory
1190  call mem_reallocate(this%iallpc, 0, 'IALLPC', this%memoryPath)
1191  end if
1192  end subroutine xt3d_iallpc
1193 
1194  !> @brief Set various indices for XT3D.
1195  !<
1196  subroutine xt3d_indices(this, n, m, il0, ii01, jjs01, il01, il10, &
1197  ii00, ii11, ii10)
1198  ! -- dummy
1199  class(xt3dtype) :: this
1200  integer(I4B) :: n, m, il0, ii01, jjs01, il01, il10, ii00, ii11, ii10
1201  ! -- local
1202  integer(I4B) :: iinm
1203  !
1204  ! -- Set local number of node 0-1 connection (local cell number of cell 1
1205  ! in cell 0's neighbor list).
1206  il01 = il0
1207  ! -- Set local number of node 1-0 connection (local cell number of cell 0
1208  ! in cell 1's neighbor list).
1209  call this%xt3d_get_iinm(m, n, iinm)
1210  il10 = iinm - this%dis%con%ia(m)
1211  ! -- Set index of node 0 diagonal in the ja array.
1212  ii00 = this%dis%con%ia(n)
1213  ! -- Set index of node 0-1 connection in the ja array.
1214  ii01 = ii00 + il01
1215  ! -- Set symmetric index of node 0-1 connection.
1216  jjs01 = this%dis%con%jas(ii01)
1217  ! -- Set index of node 1 diagonal in the ja array.
1218  ii11 = this%dis%con%ia(m)
1219  ! -- Set index of node 1-0 connection in the ja array.
1220  ii10 = ii11 + il10
1221  end subroutine xt3d_indices
1222 
1223  !> @brief Load conductivity and connection info for a cell into arrays used
1224  !! by XT3D
1225  !<
1226  subroutine xt3d_load(this, nodes, n, nnbr, inbr, vc, vn, dl, dln, ck, allhc)
1227  ! -- module
1228  use constantsmodule, only: dzero, dhalf, done
1229  ! -- dummy
1230  class(xt3dtype) :: this
1231  logical :: allhc
1232  integer(I4B), intent(in) :: nodes
1233  integer(I4B) :: n, nnbr
1234  integer(I4B), dimension(this%nbrmax) :: inbr
1235  real(DP), dimension(this%nbrmax, 3) :: vc, vn
1236  real(DP), dimension(this%nbrmax) :: dl, dln
1237  real(DP), dimension(3, 3) :: ck
1238  ! -- local
1239  integer(I4B) :: il, ii, jj, jjs
1240  integer(I4B) :: ihcnjj
1241  real(DP) :: satn, satjj
1242  real(DP) :: cl1njj, cl2njj, dltot, ooclsum
1243  !
1244  ! -- Set conductivity tensor for cell.
1245  ck = dzero
1246  ck(1, 1) = this%k11(n)
1247  ck(2, 2) = this%k22(n)
1248  ck(3, 3) = this%k33(n)
1249  call this%xt3d_fillrmatck(n)
1250  ck = matmul(this%rmatck, ck)
1251  ck = matmul(ck, transpose(this%rmatck))
1252  !
1253  ! -- Load neighbors of cell. Set cell numbers for inactive neighbors to
1254  ! zero so xt3d knows to ignore them. Compute direct connection lengths
1255  ! from perpendicular connection lengths. Also determine if all active
1256  ! connections are horizontal.
1257  allhc = .true.
1258  do il = 1, nnbr
1259  ii = il + this%dis%con%ia(n)
1260  jj = this%dis%con%ja(ii)
1261  jjs = this%dis%con%jas(ii)
1262  if (this%ibound(jj) .ne. 0) then
1263  inbr(il) = jj
1264  satn = this%sat(n)
1265  satjj = this%sat(jj)
1266  !
1267  ! -- DISV and DIS
1268  ihcnjj = this%dis%con%ihc(jjs)
1269  call this%dis%connection_normal(n, jj, ihcnjj, vn(il, 1), vn(il, 2), &
1270  vn(il, 3), ii)
1271  call this%dis%connection_vector(n, jj, this%nozee, satn, satjj, ihcnjj, &
1272  vc(il, 1), vc(il, 2), vc(il, 3), dltot)
1273  if (jj > n) then
1274  cl1njj = this%dis%con%cl1(jjs)
1275  cl2njj = this%dis%con%cl2(jjs)
1276  else
1277  cl1njj = this%dis%con%cl2(jjs)
1278  cl2njj = this%dis%con%cl1(jjs)
1279  end if
1280  ooclsum = 1d0 / (cl1njj + cl2njj)
1281  dl(il) = dltot * cl1njj * ooclsum
1282  dln(il) = dltot * cl2njj * ooclsum
1283  if (this%dis%con%ihc(jjs) .eq. 0) allhc = .false.
1284  else
1285  inbr(il) = 0
1286  end if
1287  end do
1288  end subroutine xt3d_load
1289 
1290  !> @brief Load neighbor list for a cell.
1291  !<
1292  subroutine xt3d_load_inbr(this, n, nnbr, inbr)
1293  ! -- dummy
1294  class(xt3dtype) :: this
1295  integer(I4B) :: n, nnbr
1296  integer(I4B), dimension(this%nbrmax) :: inbr
1297  ! -- local
1298  integer(I4B) :: il, ii, jj
1299  !
1300  ! -- Load neighbors of cell. Set cell numbers for inactive
1301  ! neighbors to zero so xt3d knows to ignore them.
1302  do il = 1, nnbr
1303  ii = il + this%dis%con%ia(n)
1304  jj = this%dis%con%ja(ii)
1305  if (this%ibound(jj) .ne. 0) then
1306  inbr(il) = jj
1307  else
1308  inbr(il) = 0
1309  end if
1310  end do
1311  end subroutine xt3d_load_inbr
1312 
1313  !> @brief Compute interfacial areas.
1314  !<
1315  subroutine xt3d_areas(this, nodes, n, m, jjs01, lsat, ar01, ar10, hnew, qsat)
1316  ! -- modules
1317  use simmodule, only: store_error
1318  ! -- dummy
1319  class(xt3dtype) :: this
1320  logical :: lsat
1321  integer(I4B) :: nodes, n, m, jjs01
1322  real(DP) :: ar01, ar10
1323  real(DP), intent(inout), dimension(:), optional :: hnew
1324  real(DP), intent(in), optional :: qsat !< saturated flow into n from m; if present, its sign selects the upstream cell
1325  ! -- local
1326  real(DP) :: topn, botn, topm, botm, thksatn, thksatm
1327  real(DP) :: sill_top, sill_bot, tpn, tpm
1328  real(DP) :: satups
1329  !
1330  ! -- Compute area depending on connection type
1331  if (this%dis%con%ihc(jjs01) == 0) then
1332  !
1333  ! -- Vertical connection
1334  ar01 = this%dis%con%hwva(jjs01)
1335  ar10 = ar01
1336  else if (this%inewton /= 0) then
1337  !
1338  ! -- If Newton horizontal connection
1339  if (lsat) then
1340  !
1341  ! -- lsat true means use full saturation
1342  topn = this%dis%top(n)
1343  botn = this%dis%bot(n)
1344  topm = this%dis%top(m)
1345  botm = this%dis%bot(m)
1346  thksatn = topn - botn
1347  thksatm = topm - botm
1348  if (this%dis%con%ihc(jjs01) .eq. 2) then
1349  ! -- Vertically staggered
1350  sill_top = min(topn, topm)
1351  sill_bot = max(botn, botm)
1352  tpn = botn + thksatn
1353  tpm = botm + thksatm
1354  thksatn = max(min(tpn, sill_top) - sill_bot, dzero)
1355  thksatm = max(min(tpm, sill_top) - sill_bot, dzero)
1356  end if
1357  ar01 = this%dis%con%hwva(jjs01) * dhalf * (thksatn + thksatm)
1358  else
1359  ! -- If Newton and lsat=.false., it is assumed that the fully saturated
1360  ! areas have already been calculated and are being passed in through
1361  ! ar01 and ar10. The actual areas are obtained simply by scaling by
1362  ! the upstream saturation.
1363  if (present(qsat)) then
1364  !
1365  ! -- Upstream cell is the cell the saturated xt3d flow comes from.
1366  ! Using the flow direction rather than the head difference keeps
1367  ! the product of flow and saturation continuous, because the
1368  ! xt3d flow across a face is generally not zero when the heads
1369  ! of the two cells are equal.
1370  if (qsat < dzero) then
1371  satups = this%sat(n)
1372  else
1373  satups = this%sat(m)
1374  end if
1375  else
1376  !
1377  ! -- Every Newton call for the actual area must provide qsat;
1378  ! selecting the upstream cell from the head difference instead
1379  ! would reintroduce the discontinuity described above
1380  call store_error('Program error: xt3d_areas called for a Newton &
1381  &horizontal connection without the saturated &
1382  &flow qsat.', terminate=.true.)
1383  satups = dzero
1384  end if
1385  ar01 = ar01 * satups
1386  end if
1387  ar10 = ar01
1388  else
1389  !
1390  ! -- Non-Newton horizontal connection
1391  topn = this%dis%top(n)
1392  botn = this%dis%bot(n)
1393  topm = this%dis%top(m)
1394  botm = this%dis%bot(m)
1395  thksatn = topn - botn
1396  thksatm = topm - botm
1397  if (.not. lsat) then
1398  thksatn = this%sat(n) * thksatn
1399  thksatm = this%sat(m) * thksatm
1400  end if
1401  if (this%dis%con%ihc(jjs01) == 2) then
1402  ! -- Vertically staggered
1403  sill_top = min(topn, topm)
1404  sill_bot = max(botn, botm)
1405  tpn = botn + thksatn
1406  tpm = botm + thksatm
1407  thksatn = max(min(tpn, sill_top) - sill_bot, dzero)
1408  thksatm = max(min(tpm, sill_top) - sill_bot, dzero)
1409  end if
1410  ar01 = this%dis%con%hwva(jjs01) * thksatn
1411  ar10 = this%dis%con%hwva(jjs01) * thksatm
1412  end if
1413  end subroutine xt3d_areas
1414 
1415  !> @brief Add contributions from neighbors to amat.
1416  !<
1417  subroutine xt3d_amat_nbrs(this, nodes, n, idiag, nnbr, nja, &
1418  matrix_sln, inbr, idxglo, chat)
1419  ! -- dummy
1420  class(xt3dtype) :: this
1421  integer(I4B), intent(in) :: nodes
1422  integer(I4B) :: n, idiag, nnbr, nja
1423  class(matrixbasetype), pointer :: matrix_sln
1424  integer(I4B), dimension(this%nbrmax) :: inbr
1425  integer(I4B), intent(in), dimension(nja) :: idxglo
1426  real(DP), dimension(this%nbrmax) :: chat
1427  ! -- local
1428  integer(I4B) :: iil, iii
1429  !
1430  do iil = 1, nnbr
1431  if (inbr(iil) .ne. 0) then
1432  iii = this%dis%con%ia(n) + iil
1433  call matrix_sln%add_value_pos(idxglo(idiag), -chat(iil))
1434  call matrix_sln%add_value_pos(idxglo(iii), chat(iil))
1435  end if
1436  end do
1437  end subroutine xt3d_amat_nbrs
1438 
1439  !> @brief Add contributions from neighbors of neighbor to amat.
1440  !<
1441  subroutine xt3d_amat_nbrnbrs(this, nodes, n, m, ii01, nnbr, nja, &
1442  matrix_sln, inbr, idxglo, chat)
1443  ! -- dummy
1444  class(xt3dtype) :: this
1445  integer(I4B), intent(in) :: nodes
1446  integer(I4B) :: n, m, ii01, nnbr, nja
1447  class(matrixbasetype), pointer :: matrix_sln
1448  integer(I4B), dimension(this%nbrmax) :: inbr
1449  integer(I4B), intent(in), dimension(nja) :: idxglo
1450  real(DP), dimension(this%nbrmax) :: chat
1451  ! -- local
1452  integer(I4B) :: iil, iii, jjj, iixjjj, iijjj
1453  !
1454  do iil = 1, nnbr
1455  if (inbr(iil) .ne. 0) then
1456  call matrix_sln%add_value_pos(idxglo(ii01), chat(iil))
1457  iii = this%dis%con%ia(m) + iil
1458  jjj = this%dis%con%ja(iii)
1459  call this%xt3d_get_iinmx(n, jjj, iixjjj)
1460  if (iixjjj .ne. 0) then
1461  call matrix_sln%add_value_pos(this%idxglox(iixjjj), -chat(iil))
1462  else
1463  call this%xt3d_get_iinm(n, jjj, iijjj)
1464  call matrix_sln%add_value_pos(idxglo(iijjj), -chat(iil))
1465  end if
1466  end if
1467  end do
1468  end subroutine xt3d_amat_nbrnbrs
1469 
1470  !> @brief Add contributions from neighbors to amatpc.
1471  !<
1472  subroutine xt3d_amatpc_nbrs(this, nodes, n, idiag, nnbr, inbr, chat)
1473  ! -- dummy
1474  class(xt3dtype) :: this
1475  integer(I4B), intent(in) :: nodes
1476  integer(I4B) :: n, idiag, nnbr
1477  integer(I4B), dimension(this%nbrmax) :: inbr
1478  real(DP), dimension(this%nbrmax) :: chat
1479  ! -- local
1480  integer(I4B) :: iil, iii
1481  !
1482  do iil = 1, nnbr
1483  iii = this%dis%con%ia(n) + iil
1484  this%amatpc(idiag) = this%amatpc(idiag) - chat(iil)
1485  this%amatpc(iii) = this%amatpc(iii) + chat(iil)
1486  end do
1487  end subroutine xt3d_amatpc_nbrs
1488 
1489  !> @brief Add contributions from neighbors of neighbor to amatpc and amatpcx
1490  !<
1491  subroutine xt3d_amatpcx_nbrnbrs(this, nodes, n, m, ii01, nnbr, inbr, chat)
1492  ! -- dummy
1493  class(xt3dtype) :: this
1494  integer(I4B), intent(in) :: nodes
1495  integer(I4B) :: n, m, ii01, nnbr
1496  integer(I4B), dimension(this%nbrmax) :: inbr
1497  real(DP), dimension(this%nbrmax) :: chat
1498  ! -- local
1499  integer(I4B) :: iil, iii, jjj, iixjjj, iijjj
1500  !
1501  do iil = 1, nnbr
1502  this%amatpc(ii01) = this%amatpc(ii01) + chat(iil)
1503  iii = this%dis%con%ia(m) + iil
1504  jjj = this%dis%con%ja(iii)
1505  call this%xt3d_get_iinmx(n, jjj, iixjjj)
1506  if (iixjjj .ne. 0) then
1507  this%amatpcx(iixjjj) = this%amatpcx(iixjjj) - chat(iil)
1508  else
1509  call this%xt3d_get_iinm(n, jjj, iijjj)
1510  this%amatpc(iijjj) = this%amatpc(iijjj) - chat(iil)
1511  end if
1512  end do
1513  end subroutine xt3d_amatpcx_nbrnbrs
1514 
1515  !> @brief Get position of n-m connection in ja array (return 0 if not
1516  !! connected)
1517  !<
1518  subroutine xt3d_get_iinm(this, n, m, iinm)
1519  ! -- dummy
1520  class(xt3dtype) :: this
1521  integer(I4B) :: n, m, iinm
1522  ! -- local
1523  integer(I4B) :: ii, jj
1524  !
1525  iinm = 0
1526  do ii = this%dis%con%ia(n), this%dis%con%ia(n + 1) - 1
1527  jj = this%dis%con%ja(ii)
1528  if (jj .eq. m) then
1529  iinm = ii
1530  exit
1531  end if
1532  end do
1533  end subroutine xt3d_get_iinm
1534 
1535  !> @brief Get position of n-m "extended connection" in jax array (return 0 if
1536  !! not connected)
1537  !<
1538  subroutine xt3d_get_iinmx(this, n, m, iinmx)
1539  ! -- dummy
1540  class(xt3dtype) :: this
1541  integer(I4B) :: n, m, iinmx
1542  ! -- local
1543  integer(I4B) :: iix, jjx
1544  !
1545  iinmx = 0
1546  do iix = this%iax(n), this%iax(n + 1) - 1
1547  jjx = this%jax(iix)
1548  if (jjx .eq. m) then
1549  iinmx = iix
1550  exit
1551  end if
1552  end do
1553  end subroutine xt3d_get_iinmx
1554 
1555  !> @brief Add contributions to rhs.
1556  !<
1557  subroutine xt3d_rhs(this, nodes, n, m, nnbr, inbr, chat, hnew, &
1558  rhs)
1559  ! -- dummy
1560  class(xt3dtype) :: this
1561  integer(I4B), intent(in) :: nodes
1562  integer(I4B) :: n, m, nnbr
1563  integer(I4B), dimension(this%nbrmax) :: inbr
1564  real(DP), dimension(this%nbrmax) :: chat
1565  real(DP), intent(inout), dimension(nodes) :: hnew, rhs
1566  ! -- local
1567  integer(I4B) :: iil, iii, jjj
1568  real(DP) :: term
1569  !
1570  do iil = 1, nnbr
1571  if (inbr(iil) .ne. 0) then
1572  iii = iil + this%dis%con%ia(n)
1573  jjj = this%dis%con%ja(iii)
1574  term = chat(iil) * (hnew(jjj) - hnew(n))
1575  rhs(n) = rhs(n) - term
1576  rhs(m) = rhs(m) + term
1577  end if
1578  end do
1579  end subroutine xt3d_rhs
1580 
1581  !> @brief Add contributions to flow from neighbors
1582  !<
1583  subroutine xt3d_qnbrs(this, nodes, n, m, nnbr, inbr, chat, hnew, &
1584  qnbrs)
1585  ! -- dummy
1586  class(xt3dtype) :: this
1587  integer(I4B), intent(in) :: nodes
1588  integer(I4B) :: n, m, nnbr
1589  integer(I4B), dimension(this%nbrmax) :: inbr
1590  real(DP) :: qnbrs
1591  real(DP), dimension(this%nbrmax) :: chat
1592  real(DP), intent(inout), dimension(nodes) :: hnew
1593  ! -- local
1594  integer(I4B) :: iil, iii, jjj
1595  real(DP) :: term
1596  !
1597  qnbrs = 0d0
1598  do iil = 1, nnbr
1599  if (inbr(iil) .ne. 0) then
1600  iii = iil + this%dis%con%ia(n)
1601  jjj = this%dis%con%ja(iii)
1602  term = chat(iil) * (hnew(jjj) - hnew(n))
1603  qnbrs = qnbrs + term
1604  end if
1605  end do
1606  end subroutine xt3d_qnbrs
1607 
1608  !> @brief Fill rmat array for cell n.
1609  !!
1610  !! angle1, 2, and 3 must be in radians.
1611  !<
1612  subroutine xt3d_fillrmatck(this, n)
1613  ! -- dummy
1614  class(xt3dtype) :: this
1615  integer(I4B), intent(in) :: n
1616  ! -- local
1617  real(DP) :: ang1, ang2, ang3, ang2d, ang3d
1618  real(DP) :: s1, c1, s2, c2, s3, c3
1619  !
1620  if (this%nozee) then
1621  ang2d = 0d0
1622  ang3d = 0d0
1623  ang1 = this%angle1(n)
1624  ang2 = 0d0
1625  ang3 = 0d0
1626  else
1627  ang1 = this%angle1(n)
1628  ang2 = this%angle2(n)
1629  ang3 = this%angle3(n)
1630  end if
1631  s1 = sin(ang1)
1632  c1 = cos(ang1)
1633  s2 = sin(ang2)
1634  c2 = cos(ang2)
1635  s3 = sin(ang3)
1636  c3 = cos(ang3)
1637  this%rmatck(1, 1) = c1 * c2
1638  this%rmatck(1, 2) = c1 * s2 * s3 - s1 * c3
1639  this%rmatck(1, 3) = -c1 * s2 * c3 - s1 * s3
1640  this%rmatck(2, 1) = s1 * c2
1641  this%rmatck(2, 2) = s1 * s2 * s3 + c1 * c3
1642  this%rmatck(2, 3) = -s1 * s2 * c3 + c1 * s3
1643  this%rmatck(3, 1) = s2
1644  this%rmatck(3, 2) = -c2 * s3
1645  this%rmatck(3, 3) = c2 * c3
1646  end subroutine xt3d_fillrmatck
1647 
1648 end module xt3dmodule
This module contains simulation constants.
Definition: Constants.f90:9
real(dp), parameter dhalf
real constant 1/2
Definition: Constants.f90:68
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
integer(i4b), parameter lenmempath
maximum length of the memory path
Definition: Constants.f90:27
real(dp), parameter done
real constant 1
Definition: Constants.f90:76
This module defines variable data types.
Definition: kind.f90:8
character(len=lenmempath) function create_mem_path(component, subcomponent, context)
returns the path to the memory object
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
real(dp) function squadraticsaturationderivative(top, bot, x, eps)
@ brief Derivative of the quadratic saturation function
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)....
subroutine xt3d_load(this, nodes, n, nnbr, inbr, vc, vn, dl, dln, ck, allhc)
Load conductivity and connection info for a cell into arrays used by XT3D.
subroutine xt3d_ac(this, moffset, sparse)
Add connections for extended neighbors to the sparse matrix.
subroutine xt3d_get_iinmx(this, n, m, iinmx)
Get position of n-m "extended connection" in jax array (return 0 if not connected)
subroutine xt3d_amatpcx_nbrnbrs(this, nodes, n, m, ii01, nnbr, inbr, chat)
Add contributions from neighbors of neighbor to amatpc and amatpcx.
subroutine allocate_arrays(this)
Allocate xt3d arrays.
subroutine xt3d_amat_nbrnbrs(this, nodes, n, m, ii01, nnbr, nja, matrix_sln, inbr, idxglo, chat)
Add contributions from neighbors of neighbor to amat.
subroutine xt3d_da(this)
Deallocate variables.
subroutine allocate_scalars(this)
Allocate scalar pointer variables.
subroutine xt3d_amat_nbrs(this, nodes, n, idiag, nnbr, nja, matrix_sln, inbr, idxglo, chat)
Add contributions from neighbors to amat.
subroutine xt3d_flowja(this, hnew, flowja)
Budget.
subroutine xt3d_get_iinm(this, n, m, iinm)
Get position of n-m connection in ja array (return 0 if not connected)
subroutine xt3d_areas(this, nodes, n, m, jjs01, lsat, ar01, ar10, hnew, qsat)
Compute interfacial areas.
subroutine xt3d_fhfb(this, kiter, nodes, nja, matrix_sln, idxglo, rhs, hnew, n, m, condhfb)
Formulate HFB correction.
subroutine xt3d_flowjahfb(this, n, m, hnew, flowja, condhfb)
hfb contribution to flowja when xt3d is used
subroutine xt3d_indices(this, n, m, il0, ii01, jjs01, il01, il10, ii00, ii11, ii10)
Set various indices for XT3D.
subroutine xt3d_load_inbr(this, n, nnbr, inbr)
Load neighbor list for a cell.
subroutine xt3d_fcpc(this, nodes, lsat)
Formulate for permanently confined connections and save in amatpc and amatpcx.
subroutine xt3d_fn(this, kiter, nodes, nja, matrix_sln, idxglo, rhs, hnew)
Fill Newton terms for xt3d.
subroutine xt3d_fillrmatck(this, n)
Fill rmat array for cell n.
subroutine xt3d_mc(this, moffset, matrix_sln)
Map connections and construct iax, jax, and idxglox.
subroutine, public xt3d_cr(xt3dobj, name_model, inunit, iout, ldispopt)
Create a new xt3d object.
subroutine xt3d_qnbrs(this, nodes, n, m, nnbr, inbr, chat, hnew, qnbrs)
Add contributions to flow from neighbors.
subroutine xt3d_fc(this, kiter, matrix_sln, idxglo, rhs, hnew)
Formulate.
subroutine xt3d_rhs(this, nodes, n, m, nnbr, inbr, chat, hnew, rhs)
Add contributions to rhs.
subroutine xt3d_df(this, dis)
Define the xt3d object.
subroutine xt3d_iallpc(this)
Allocate and populate iallpc array. Set lamatsaved.
subroutine xt3d_ar(this, ibound, k11, ik33, k33, sat, ik22, k22, iangle1, iangle2, iangle3, angle1, angle2, angle3, inewton, icelltype)
Allocate and Read.
subroutine xt3d_amatpc_nbrs(this, nodes, n, idiag, nnbr, inbr, chat)
Add contributions from neighbors to amatpc.