MODFLOW 6  version 6.9.0.dev0
USGS Modular Hydrologic Model
gwe-uze.f90
Go to the documentation of this file.
1 ! -- Unsaturated Zone Flow Energy Transport Module
2 ! -- todo: save the uze temperature into the uze aux variable?
3 ! -- todo: calculate the uzf DENSE aux variable using temperature?
4 ! -- todo: GWD and GWD-TO-MVR do not seem to be included; prob in UZF?
5 !
6 ! UZF flows (flowbudptr) index var UZE term Transport Type
7 !---------------------------------------------------------------------------------
8 
9 ! -- terms from UZF that will be handled by parent APT Package
10 ! FLOW-JA-FACE idxbudfjf FLOW-JA-FACE cv2cv
11 ! GWF (aux FLOW-AREA) idxbudgwf GWF uzf2gwf
12 ! STORAGE (aux VOLUME) idxbudsto none used for water volumes
13 ! FROM-MVR idxbudfmvr FROM-MVR q * cext = this%qfrommvr(:)
14 ! AUXILIARY none none none
15 ! none none STORAGE (aux MASS)
16 ! none none AUXILIARY none
17 
18 ! -- terms from UZF that need to be handled here
19 ! INFILTRATION idxbudinfl INFILTRATION q < 0: q * cwell, else q * cuser
20 ! REJ-INF idxbudrinf REJ-INF q * cuze
21 ! UZET idxbuduzet UZET q * cet
22 ! REJ-INF-TO-MVR idxbudritm REJ-INF-TO-MVR q * cinfil?
23 ! THERMAL-EQUIL idxbudtheq THERMAL-EQUIL residual
24 
25 ! -- terms from UZF that should be skipped
26 
28 
29  use kindmodule, only: dp, i4b
34  use bndmodule, only: bndtype, getbndfromlist
35  use tspfmimodule, only: tspfmitype
36  use uzfmodule, only: uzftype
37  use observemodule, only: observetype
42 
43  implicit none
44 
45  public uze_create
46 
47  character(len=*), parameter :: ftype = 'UZE'
48  character(len=*), parameter :: flowtype = 'UZF'
49  character(len=16) :: text = ' UZE'
50 
51  type, extends(tspapttype) :: gweuzetype
52 
53  type(gweinputdatatype), pointer :: gwecommon => null() !< pointer to shared gwe data used by multiple packages but set in mst
54 
55  integer(I4B), pointer :: idxbudinfl => null() !< index of uzf infiltration terms in flowbudptr
56  integer(I4B), pointer :: idxbudrinf => null() !< index of rejected infiltration terms in flowbudptr
57  integer(I4B), pointer :: idxbuduzet => null() !< index of unsat et terms in flowbudptr
58  integer(I4B), pointer :: idxbudritm => null() !< index of rej infil to mover rate to mover terms in flowbudptr
59  integer(I4B), pointer :: idxbudtheq => null() !< index of thermal equilibration terms in flowbudptr
60 
61  real(dp), dimension(:), pointer, contiguous :: tempinfl => null() !< infiltration temperature
62  real(dp), dimension(:), pointer, contiguous :: tempuzet => null() !< unsat et temperature
63 
64  contains
65 
66  procedure :: bnd_da => uze_da
67  procedure :: allocate_scalars
68  procedure :: apt_allocate_arrays => uze_allocate_arrays
69  procedure :: find_apt_package => find_uze_package
70  procedure :: apt_setting_value => uze_setting_value
71  procedure :: apt_fc_expanded => uze_fc_expanded
72  procedure :: pak_solve => uze_solve
73  procedure :: pak_get_nbudterms => uze_get_nbudterms
74  procedure :: pak_setup_budobj => uze_setup_budobj
75  procedure :: pak_fill_budobj => uze_fill_budobj
76  procedure :: uze_infl_term
77  procedure :: uze_rinf_term
78  procedure :: uze_uzet_term
79  procedure :: uze_ritm_term
80  procedure :: uze_theq_term
81  procedure :: pak_df_obs => uze_df_obs
82  procedure :: pak_rp_obs => uze_rp_obs
83  procedure :: pak_bd_obs => uze_bd_obs
84  procedure :: apt_ad_chk => uze_ad_chk
85  procedure :: bnd_ac => uze_ac
86  procedure :: bnd_mc => uze_mc
87  procedure :: get_mvr_depvar
88  procedure, private :: area_error
89 
90  end type gweuzetype
91 
92 contains
93 
94  !> @brief Create a new UZE package
95  !<
96  subroutine uze_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, &
97  mempath, fmi, eqnsclfac, gwecommon, dvt, dvu, dvua)
98  ! -- dummy
99  class(bndtype), pointer :: packobj
100  integer(I4B), intent(in) :: id
101  integer(I4B), intent(in) :: ibcnum
102  integer(I4B), intent(in) :: inunit
103  integer(I4B), intent(in) :: iout
104  character(len=*), intent(in) :: namemodel
105  character(len=*), intent(in) :: pakname
106  character(len=*), intent(in) :: mempath !< input memory path
107  type(tspfmitype), pointer :: fmi
108  real(dp), intent(in), pointer :: eqnsclfac !< governing equation scale factor
109  type(gweinputdatatype), intent(in), target :: gwecommon !< shared data container for use by multiple GWE packages
110  character(len=*), intent(in) :: dvt !< For GWE, set to "TEMPERATURE" in TspAptType
111  character(len=*), intent(in) :: dvu !< For GWE, set to "energy" in TspAptType
112  character(len=*), intent(in) :: dvua !< For GWE, set to "E" in TspAptType
113  ! -- local
114  type(gweuzetype), pointer :: uzeobj
115  !
116  ! -- Allocate the object and assign values to object variables
117  allocate (uzeobj)
118  packobj => uzeobj
119  !
120  ! -- Create name and memory path
121  call packobj%set_names(ibcnum, namemodel, pakname, ftype, mempath)
122  packobj%text = text
123  !
124  ! -- Allocate scalars
125  call uzeobj%allocate_scalars()
126  !
127  ! -- Initialize package
128  call packobj%pack_initialize()
129  !
130  packobj%inunit = inunit
131  packobj%iout = iout
132  packobj%id = id
133  packobj%ibcnum = ibcnum
134  packobj%ncolbnd = 1
135  packobj%iscloc = 1
136  packobj%isadvpak = 1
137 
138  ! -- Store pointer to flow model interface. When the GwfGwt exchange is
139  ! created, it sets fmi%bndlist so that the GWT model has access to all
140  ! the flow packages
141  uzeobj%fmi => fmi
142  !
143  ! -- Store pointer to governing equation scale factor
144  uzeobj%eqnsclfac => eqnsclfac
145  !
146  ! -- Store pointer to shared data module for accessing cpw, rhow
147  ! for the budget calculations, and for accessing the latent heat of
148  ! vaporization
149  uzeobj%gwecommon => gwecommon
150  !
151  ! -- Set labels that will be used in generalized APT class
152  uzeobj%depvartype = dvt
153  uzeobj%depvarunit = dvu
154  uzeobj%depvarunitabbrev = dvua
155  end subroutine uze_create
156 
157  !> @brief Find corresponding uze package
158  !<
159  subroutine find_uze_package(this)
160  ! -- modules
162  use simvariablesmodule, only: errmsg
163  ! -- dummy
164  class(gweuzetype) :: this
165  ! -- local
166  class(bndtype), pointer :: packobj
167  integer(I4B) :: ip, icount
168  integer(I4B) :: nbudterm
169  logical :: found
170  !
171  ! -- Initialize found to false, and error later if flow package cannot
172  ! be found
173  found = .false.
174  !
175  ! -- If user is specifying flows in a binary budget file, then set up
176  ! the budget file reader, otherwise set a pointer to the flow package
177  ! budobj
178  if (this%fmi%flows_from_file) then
179  call this%fmi%set_aptbudobj_pointer(this%flowpackagename, this%flowbudptr)
180  if (associated(this%flowbudptr)) then
181  found = .true.
182  end if
183  !
184  else
185  if (associated(this%fmi%gwfbndlist)) then
186  ! -- Look through gwfbndlist for a flow package with the same name as
187  ! this transport package name
188  do ip = 1, this%fmi%gwfbndlist%Count()
189  packobj => getbndfromlist(this%fmi%gwfbndlist, ip)
190  if (packobj%packName == this%flowpackagename) then
191  found = .true.
192  !
193  ! -- Store BndType pointer to packobj, and then
194  ! use the select type to point to the budobj in flow package
195  this%flowpackagebnd => packobj
196  select type (packobj)
197  type is (uzftype)
198  this%flowbudptr => packobj%budobj
199  end select
200  end if
201  if (found) exit
202  end do
203  end if
204  end if
205  !
206  ! -- Error if flow package not found
207  if (.not. found) then
208  write (errmsg, '(a)') 'Could not find flow package with name '&
209  &//trim(adjustl(this%flowpackagename))//'.'
210  call store_error(errmsg)
211  call store_error_filename(this%input_fname)
212  end if
213  !
214  ! -- Allocate space for idxbudssm, which indicates whether this is a
215  ! special budget term or one that is a general source and sink
216  nbudterm = this%flowbudptr%nbudterm
217  call mem_allocate(this%idxbudssm, nbudterm, 'IDXBUDSSM', this%memoryPath)
218  !
219  ! -- Process budget terms and identify special budget terms
220  write (this%iout, '(/, a, a)') &
221  'PROCESSING '//ftype//' INFORMATION FOR ', this%packName
222  write (this%iout, '(a)') ' IDENTIFYING FLOW TERMS IN '//flowtype//' PACKAGE'
223  write (this%iout, '(a, i0)') &
224  ' NUMBER OF '//flowtype//' = ', this%flowbudptr%ncv
225  icount = 1
226  do ip = 1, this%flowbudptr%nbudterm
227  select case (trim(adjustl(this%flowbudptr%budterm(ip)%flowtype)))
228  case ('FLOW-JA-FACE')
229  this%idxbudfjf = ip
230  this%idxbudssm(ip) = 0
231  case ('GWF')
232  this%idxbudgwf = ip
233  this%idxbudssm(ip) = 0
234  case ('STORAGE')
235  this%idxbudsto = ip
236  this%idxbudssm(ip) = 0
237  case ('INFILTRATION')
238  this%idxbudinfl = ip
239  this%idxbudssm(ip) = 0
240  case ('REJ-INF')
241  this%idxbudrinf = ip
242  this%idxbudssm(ip) = 0
243  case ('UZET')
244  this%idxbuduzet = ip
245  this%idxbudssm(ip) = 0
246  case ('REJ-INF-TO-MVR')
247  this%idxbudritm = ip
248  this%idxbudssm(ip) = 0
249  case ('TO-MVR')
250  this%idxbudtmvr = ip
251  this%idxbudssm(ip) = 0
252  case ('FROM-MVR')
253  this%idxbudfmvr = ip
254  this%idxbudssm(ip) = 0
255  case ('AUXILIARY')
256  this%idxbudaux = ip
257  this%idxbudssm(ip) = 0
258  case default
259  !
260  ! -- Set idxbudssm equal to a column index for where the temperatures
261  ! are stored in the tempbud(nbudssm, ncv) array
262  this%idxbudssm(ip) = icount
263  icount = icount + 1
264  end select
265  !
266  write (this%iout, '(a, i0, " = ", a,/, a, i0)') &
267  ' TERM ', ip, trim(adjustl(this%flowbudptr%budterm(ip)%flowtype)), &
268  ' MAX NO. OF ENTRIES = ', this%flowbudptr%budterm(ip)%maxlist
269  end do
270  write (this%iout, '(a, //)') 'DONE PROCESSING '//ftype//' INFORMATION'
271  !
272  ! -- Thermal equilibration term
273  this%idxbudtheq = this%flowbudptr%nbudterm + 1
274  end subroutine find_uze_package
275 
276  !> @brief Value for a package-specific PERIOD setting
277  !!
278  !! Already resolved by the input context; this only supplies it for
279  !! the shared apt_rp table echo.
280  !<
281  function uze_setting_value(this, itemno, key) result(val)
282  ! -- dummy
283  class(gweuzetype), intent(inout) :: this
284  integer(I4B), intent(in) :: itemno
285  character(len=*), intent(in) :: key
286  real(dp) :: val
287  !
288  val = dzero
289  select case (trim(key))
290  case ('INFILTRATION')
291  val = this%tempinfl(itemno)
292  case ('UZET')
293  val = this%tempuzet(itemno)
294  end select
295  end function uze_setting_value
296 
297  !> @brief Add package connection to matrix.
298  !!
299  !! Overrides apt_ac to fold the UZE heat balance terms into the row
300  !! corresponding to the host cell and enforce thermal equilibrium between
301  !! UZE and the GWE cell.
302  !<
303  subroutine uze_ac(this, moffset, sparse)
305  use sparsemodule, only: sparsematrix
306  ! -- dummy
307  class(gweuzetype), intent(inout) :: this
308  integer(I4B), intent(in) :: moffset !< current models starting position in global matrix
309  type(sparsematrix), intent(inout) :: sparse
310  ! -- local
311  integer(I4B) :: i, ii
312  integer(I4B) :: n !< index of a uze object within the complete list of uze objects
313  integer(I4B) :: jj !<
314  integer(I4B) :: nglo !< index of uze object in global matrix
315  integer(I4B) :: jglo !< host cell's position in global matrix for a uze object
316  integer(I4B) :: idxn !< used for cross-check
317  integer(I4B) :: idxjj !< used for cross-check
318  integer(I4B) :: idxnglo !< used for cross-check
319  integer(I4B) :: idxjglo !< used for cross-check
320  !
321  ! -- Add package rows to sparse
322  if (this%imatrows /= 0) then
323  !
324  ! -- Diagonal on the row assoc. with the uze feature
325  do n = 1, this%ncv
326  nglo = moffset + this%dis%nodes + this%ioffset + n
327  call sparse%addconnection(nglo, nglo, 1)
328  end do
329  !
330  ! -- Add uze-to-gwe connections. For uze, this particular do loop
331  ! is the same as its counterpart in apt_ac.
332  ! nlist: number of gwe cells with a connection to at least one uze object
333  do i = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
334  n = this%flowbudptr%budterm(this%idxbudgwf)%id1(i) !< uze object position within uze object list
335  jj = this%flowbudptr%budterm(this%idxbudgwf)%id2(i) !< position of gwe cell to which uze feature is connected
336  nglo = moffset + this%dis%nodes + this%ioffset + n !< uze feature position
337  jglo = moffset + jj !< gwe cell position
338  call sparse%addconnection(nglo, jglo, 1)
339  call sparse%addconnection(jglo, nglo, 1)
340  end do
341  !
342  ! -- For uze, add feature-to-feature connections (i.e.,
343  ! vertically stacked UZ objects) to row corresponding
344  ! to the host cell. Terms added to the row associated with host
345  ! cell are added to columns associated with other uze features.
346  ! This approach deviates from the approach taken in apt_ac.
347  if (this%idxbudfjf /= 0) then
348  do i = 1, this%flowbudptr%budterm(this%idxbudfjf)%maxlist
349  n = this%flowbudptr%budterm(this%idxbudfjf)%id1(i) !< position of currently considered uze feature
350  jj = this%flowbudptr%budterm(this%idxbudfjf)%id2(i) !< position of connected uze feature
351  nglo = moffset + this%dis%nodes + this%ioffset + n !< global position of currently considered uze feature
352  jglo = moffset + this%dis%nodes + this%ioffset + jj !< global position of connected uze feature
353  ! -- If connected uze feature is upstream, find cell that hosts currently
354  ! considered uze feature and add connection to that cell's row
355  do ii = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist !< uze object id among uze objects
356  idxn = this%flowbudptr%budterm(this%idxbudgwf)%id1(ii) !< uze object position within uze object list
357  idxjj = this%flowbudptr%budterm(this%idxbudgwf)%id2(ii) !< position of gwe cell to which uze feature is connected
358  idxnglo = moffset + this%dis%nodes + this%ioffset + idxn !< uze feature global position
359  idxjglo = moffset + idxjj !< gwe cell global position
360  if (nglo == idxnglo) exit
361  end do
362  call sparse%addconnection(idxjglo, jglo, 1)
363  end do
364  end if
365  end if
366  end subroutine uze_ac
367 
368  !> @brief Map package connection to matrix
369  !<
370  subroutine uze_mc(this, moffset, matrix_sln)
371  use sparsemodule, only: sparsematrix
372  ! -- dummy
373  class(gweuzetype), intent(inout) :: this
374  integer(I4B), intent(in) :: moffset
375  class(matrixbasetype), pointer :: matrix_sln
376  ! -- local
377  integer(I4B) :: n, j, iglo, jglo
378  integer(I4B) :: idxn, idxj, idxiglo, idxjglo
379  integer(I4B) :: ipos, idxpos
380  !
381  ! -- Allocate memory for index arrays
382  call this%apt_allocate_index_arrays()
383  !
384  ! -- Store index positions
385  if (this%imatrows /= 0) then
386  !
387  ! -- Find the position of each connection in the global ia, ja structure
388  ! and store them in idxglo. idxglo allows this model to insert or
389  ! retrieve values into or from the global A matrix
390  ! apt rows
391  !
392  ! -- Feature diagonal in global matrix
393  do n = 1, this%ncv
394  iglo = moffset + this%dis%nodes + this%ioffset + n
395  this%idxpakdiag(n) = matrix_sln%get_position_diag(iglo)
396  end do
397  !
398  ! -- Cell to feature connection in global matrix
399  do ipos = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
400  n = this%flowbudptr%budterm(this%idxbudgwf)%id1(ipos) !< feature number
401  j = this%flowbudptr%budterm(this%idxbudgwf)%id2(ipos) !< cell number
402  iglo = moffset + this%dis%nodes + this%ioffset + n !< feature row index
403  jglo = j + moffset !< cell row index
404  ! -- Note that this is where idxlocnode is set for uze; it is set
405  ! to the host cell local row index rather than the feature local
406  ! row index
407  this%idxlocnode(n) = j ! kluge note: do we want to introduce a new array instead of co-opting idxlocnode???
408  ! -- For connection ipos in list of feature-cell connections,
409  ! global positions of feature-row diagonal and off-diagonal
410  ! corresponding to the cell
411  this%idxdglo(ipos) = matrix_sln%get_position_diag(iglo)
412  this%idxoffdglo(ipos) = matrix_sln%get_position(iglo, jglo)
413  end do
414  !
415  ! -- Feature to cell connection in global matrix
416  do ipos = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
417  n = this%flowbudptr%budterm(this%idxbudgwf)%id1(ipos) !< feature number
418  j = this%flowbudptr%budterm(this%idxbudgwf)%id2(ipos) !< cell number
419  iglo = j + moffset !< cell row index
420  jglo = moffset + this%dis%nodes + this%ioffset + n !< feature row index
421  ! -- For connection ipos in list of feature-cell connections,
422  ! global positions of cell-row diagonal and off-diagonal
423  ! corresponding to the feature
424  this%idxsymdglo(ipos) = matrix_sln%get_position_diag(iglo)
425  this%idxsymoffdglo(ipos) = matrix_sln%get_position(iglo, jglo)
426  end do
427  !
428  ! -- Feature to feature connection in global matrix
429  if (this%idxbudfjf /= 0) then
430  do ipos = 1, this%flowbudptr%budterm(this%idxbudfjf)%nlist
431  n = this%flowbudptr%budterm(this%idxbudfjf)%id1(ipos) !< number of currently considered uze feature
432  j = this%flowbudptr%budterm(this%idxbudfjf)%id2(ipos) !< number of connected uze feature
433  iglo = moffset + this%dis%nodes + this%ioffset + n !< global position of currently considered uze feature
434  jglo = moffset + this%dis%nodes + this%ioffset + j !< global position of connected uze feature
435  ! -- If connected uze feature is upstream, find cell that hosts currently
436  ! considered uze feature and map connection to that cell's row
437  do idxpos = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
438  idxn = this%flowbudptr%budterm(this%idxbudgwf)%id1(idxpos) !< feature number
439  idxj = this%flowbudptr%budterm(this%idxbudgwf)%id2(idxpos) !< cell number)
440  idxjglo = moffset + this%dis%nodes + this%ioffset + idxn !< feature row index
441  idxiglo = moffset + idxj !< cell row index
442  if (idxjglo == iglo) exit
443  end do
444  ! -- For connection ipos in list of feature-feature connections,
445  ! global positions of host-cell-row entries corresponding to
446  ! (in the same columns as) the feature-id1-row diagonal and the
447  ! feature-id1-row off-diagonal corresponding to feature id2
448  this%idxfjfdglo(ipos) = matrix_sln%get_position_diag(idxiglo)
449  this%idxfjfoffdglo(ipos) = matrix_sln%get_position(idxiglo, jglo)
450  end do
451  end if
452  end if
453  end subroutine uze_mc
454 
455  !> @brief Add matrix terms related to UZE
456  !!
457  !! This will be called from TspAptType%apt_fc_expanded()
458  !! in order to add matrix terms specifically for this package
459  !<
460  subroutine uze_fc_expanded(this, rhs, ia, idxglo, matrix_sln)
461  ! -- dummy
462  class(gweuzetype) :: this
463  real(DP), dimension(:), intent(inout) :: rhs
464  integer(I4B), dimension(:), intent(in) :: ia
465  integer(I4B), dimension(:), intent(in) :: idxglo
466  class(matrixbasetype), pointer :: matrix_sln
467  ! -- local
468  integer(I4B) :: j, n, n1, n2
469  integer(I4B) :: iloc
470  integer(I4B) :: iposd, iposoffd
471  integer(I4B) :: ipossymoffd
472  real(DP) :: cold
473  real(DP) :: qbnd
474  real(DP) :: omega
475  real(DP) :: rrate
476  real(DP) :: rhsval
477  real(DP) :: hcofval
478  !
479  ! -- Add infiltration contribution
480  ! uze does not put feature balance coefficients in the row
481  ! associated with the feature. Instead, these coefficients are
482  ! moved into the row associated with cell hosting the uze feature
483  if (this%idxbudinfl /= 0) then
484  do j = 1, this%flowbudptr%budterm(this%idxbudinfl)%nlist
485  call this%uze_infl_term(j, n1, n2, rrate, rhsval, hcofval)
486  iloc = this%idxlocnode(n1) !< for uze idxlocnode stores the host cell local row index
487  ipossymoffd = this%idxsymoffdglo(j)
488  call matrix_sln%add_value_pos(ipossymoffd, hcofval)
489  rhs(iloc) = rhs(iloc) + rhsval
490  end do
491  end if
492  !
493  ! -- Add rejected infiltration contribution
494  if (this%idxbudrinf /= 0) then
495  do j = 1, this%flowbudptr%budterm(this%idxbudrinf)%nlist
496  call this%uze_rinf_term(j, n1, n2, rrate, rhsval, hcofval)
497  iloc = this%idxlocnode(n1) ! for uze idxlocnode stores the host cell local row index
498  ipossymoffd = this%idxsymoffdglo(j)
499  call matrix_sln%add_value_pos(ipossymoffd, hcofval)
500  rhs(iloc) = rhs(iloc) + rhsval
501  end do
502  end if
503  !
504  ! -- Add unsaturated et contribution
505  if (this%idxbuduzet /= 0) then
506  do j = 1, this%flowbudptr%budterm(this%idxbuduzet)%nlist
507  call this%uze_uzet_term(j, n1, n2, rrate, rhsval, hcofval)
508  iloc = this%idxlocnode(n1) ! for uze idxlocnode stores the host cell local row index
509  ipossymoffd = this%idxsymoffdglo(j)
510  call matrix_sln%add_value_pos(ipossymoffd, hcofval)
511  rhs(iloc) = rhs(iloc) + rhsval
512  end do
513  end if
514  !
515  ! -- Add rejected infiltration to mover contribution
516  if (this%idxbudritm /= 0) then
517  do j = 1, this%flowbudptr%budterm(this%idxbudritm)%nlist
518  call this%uze_ritm_term(j, n1, n2, rrate, rhsval, hcofval)
519  iloc = this%idxlocnode(n1) ! for uze idxlocnode stores the host cell local row index
520  ipossymoffd = this%idxsymoffdglo(j)
521  call matrix_sln%add_value_pos(ipossymoffd, hcofval)
522  rhs(iloc) = rhs(iloc) + rhsval
523  end do
524  end if
525  !
526  ! -- For UZE, content of apt_fc_expanded placed here as the approach is to
527  ! completely override apt_fc_expanded() with what follows
528  !
529  ! -- Mass (or energy) storage in features
530  do n = 1, this%ncv
531  cold = this%xoldpak(n)
532  iloc = this%idxlocnode(n) ! for uze idxlocnode stores the host cell local row index
533  ipossymoffd = this%idxsymoffdglo(n)
534  call this%apt_stor_term(n, n1, n2, rrate, rhsval, hcofval)
535  call matrix_sln%add_value_pos(ipossymoffd, hcofval)
536  rhs(iloc) = rhs(iloc) + rhsval
537  end do
538  !
539  ! -- Add to mover contribution
540  if (this%idxbudtmvr /= 0) then
541  do j = 1, this%flowbudptr%budterm(this%idxbudtmvr)%nlist
542  call this%apt_tmvr_term(j, n1, n2, rrate, rhsval, hcofval)
543  iloc = this%idxlocnode(n1) ! for uze, idxlocnode stores the host cell local row index
544  ipossymoffd = this%idxsymoffdglo(j)
545  call matrix_sln%add_value_pos(ipossymoffd, hcofval)
546  rhs(iloc) = rhs(iloc) + rhsval
547  end do
548  end if
549  !
550  ! -- Add from mover contribution
551  if (this%idxbudfmvr /= 0) then
552  do n = 1, this%ncv
553  rhsval = this%qmfrommvr(n) ! kluge note: presumably already in terms of energy
554  iloc = this%idxlocnode(n) ! for uze idxlocnode stores the host cell local row index
555  rhs(iloc) = rhs(iloc) - rhsval
556  end do
557  end if
558  !
559  ! -- Go through each apt-gwf connection
560  do j = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
561  !
562  ! -- Set n to feature number and process if active feature
563  n = this%flowbudptr%budterm(this%idxbudgwf)%id1(j)
564  if (this%iboundpak(n) /= 0) then
565  !
566  ! -- This code altered from its counterpart appearing in apt; this equates
567  ! uze temperature to cell temperature using the feature's row
568  iposd = this%idxdglo(j)
569  iposoffd = this%idxoffdglo(j)
570  call matrix_sln%add_value_pos(iposd, done)
571  call matrix_sln%add_value_pos(iposoffd, -done)
572  end if
573  end do
574  !
575  ! -- Go through each apt-apt connection
576  if (this%idxbudfjf /= 0) then
577  do j = 1, this%flowbudptr%budterm(this%idxbudfjf)%nlist
578  n1 = this%flowbudptr%budterm(this%idxbudfjf)%id1(j)
579  n2 = this%flowbudptr%budterm(this%idxbudfjf)%id2(j)
580  qbnd = this%flowbudptr%budterm(this%idxbudfjf)%flow(j)
581  if (qbnd <= dzero) then
582  omega = done
583  else
584  omega = dzero
585  end if
586  iposd = this%idxfjfdglo(j) !< position of feature-id1 column in feature id1's host-cell row
587  iposoffd = this%idxfjfoffdglo(j) !< position of feature-id2 column in feature id1's host-cell row
588  call matrix_sln%add_value_pos(iposd, omega * qbnd * this%eqnsclfac)
589  call matrix_sln%add_value_pos(iposoffd, &
590  (done - omega) * qbnd * this%eqnsclfac)
591  end do
592  end if
593  end subroutine uze_fc_expanded
594 
595  !> @brief Explicit solve
596  !!
597  !! There should be no explicit solve for uze. However, if there were, then
598  !! this subroutine would add terms specific to the unsaturated zone to the
599  !! explicit unsaturated-zone solve
600  subroutine uze_solve(this)
601  ! -- dummy
602  class(gweuzetype) :: this
603  ! -- local
604  integer(I4B) :: j
605  integer(I4B) :: n1, n2
606  real(DP) :: rrate
607  !
608  ! -- Add infiltration contribution
609  if (this%idxbudinfl /= 0) then
610  do j = 1, this%flowbudptr%budterm(this%idxbudinfl)%nlist
611  call this%uze_infl_term(j, n1, n2, rrate)
612  this%dbuff(n1) = this%dbuff(n1) + rrate
613  end do
614  end if
615  !
616  ! -- Add rejected infiltration contribution
617  if (this%idxbudrinf /= 0) then
618  do j = 1, this%flowbudptr%budterm(this%idxbudrinf)%nlist
619  call this%uze_rinf_term(j, n1, n2, rrate)
620  this%dbuff(n1) = this%dbuff(n1) + rrate
621  end do
622  end if
623  !
624  ! -- Add unsaturated et contribution
625  if (this%idxbuduzet /= 0) then
626  do j = 1, this%flowbudptr%budterm(this%idxbuduzet)%nlist
627  call this%uze_uzet_term(j, n1, n2, rrate)
628  this%dbuff(n1) = this%dbuff(n1) + rrate
629  end do
630  end if
631  !
632  ! -- Add rejected infiltration to mover contribution
633  if (this%idxbudritm /= 0) then
634  do j = 1, this%flowbudptr%budterm(this%idxbudritm)%nlist
635  call this%uze_ritm_term(j, n1, n2, rrate)
636  this%dbuff(n1) = this%dbuff(n1) + rrate
637  end do
638  end if
639  end subroutine uze_solve
640 
641  !> @brief Return the number of UZE-specific budget terms
642  !!
643  !! Function to return the number of budget terms just for this package.
644  !! This overrides function in parent.
645  !<
646  function uze_get_nbudterms(this) result(nbudterms)
647  ! -- dummy
648  class(gweuzetype) :: this
649  ! -- Return
650  integer(I4B) :: nbudterms
651  !
652  ! -- Number of budget terms is 5
653  nbudterms = 0
654  if (this%idxbudinfl /= 0) nbudterms = nbudterms + 1
655  if (this%idxbudrinf /= 0) nbudterms = nbudterms + 1
656  if (this%idxbuduzet /= 0) nbudterms = nbudterms + 1
657  if (this%idxbudritm /= 0) nbudterms = nbudterms + 1
658  if (this%idxbudtheq /= 0) nbudterms = nbudterms + 1
659  end function uze_get_nbudterms
660 
661  !> @brief Override similarly named function in APT
662  !!
663  !! Set the temperature to be used by MVE as the user-specified
664  !! temperature applied to the infiltration
665  !<
666  function get_mvr_depvar(this)
667  ! -- dummy
668  class(gweuzetype) :: this
669  ! -- return
670  real(dp), dimension(:), contiguous, pointer :: get_mvr_depvar
671  !
672  get_mvr_depvar => this%tempinfl
673  end function get_mvr_depvar
674 
675  !> @brief Setup budget object
676  !!
677  !! Set up the budget object that stores all the unsaturated-zone
678  !! flows
679  !<
680  subroutine uze_setup_budobj(this, idx)
681  ! -- modules
682  use constantsmodule, only: lenbudtxt
683  ! -- dummy
684  class(gweuzetype) :: this
685  integer(I4B), intent(inout) :: idx
686  ! -- local
687  integer(I4B) :: maxlist, naux
688  character(len=LENBUDTXT) :: text
689  !
690  ! -- Infiltration
691  text = ' INFILTRATION'
692  idx = idx + 1
693  maxlist = this%flowbudptr%budterm(this%idxbudinfl)%maxlist
694  naux = 0
695  call this%budobj%budterm(idx)%initialize(text, &
696  this%name_model, &
697  this%packName, &
698  this%name_model, &
699  this%packName, &
700  maxlist, .false., .false., &
701  naux)
702  !
703  ! -- Rejected infiltration (Hortonian flow)
704  if (this%idxbudrinf /= 0) then
705  text = ' REJ-INF'
706  idx = idx + 1
707  maxlist = this%flowbudptr%budterm(this%idxbudrinf)%maxlist
708  naux = 0
709  call this%budobj%budterm(idx)%initialize(text, &
710  this%name_model, &
711  this%packName, &
712  this%name_model, &
713  this%packName, &
714  maxlist, .false., .false., &
715  naux)
716  end if
717  !
718  ! -- Evapotranspiration from the unsaturated zone
719  if (this%idxbuduzet /= 0) then
720  text = ' UZET'
721  idx = idx + 1
722  maxlist = this%flowbudptr%budterm(this%idxbuduzet)%maxlist
723  naux = 0
724  call this%budobj%budterm(idx)%initialize(text, &
725  this%name_model, &
726  this%packName, &
727  this%name_model, &
728  this%packName, &
729  maxlist, .false., .false., &
730  naux)
731  end if
732  !
733  ! -- Rejected infiltration that is subsequently transferred by MVR
734  if (this%idxbudritm /= 0) then
735  text = ' INF-REJ-TO-MVR'
736  idx = idx + 1
737  maxlist = this%flowbudptr%budterm(this%idxbudritm)%maxlist
738  naux = 0
739  call this%budobj%budterm(idx)%initialize(text, &
740  this%name_model, &
741  this%packName, &
742  this%name_model, &
743  this%packName, &
744  maxlist, .false., .false., &
745  naux)
746  end if
747  !
748  ! -- Energy transferred to solid phase by the thermal equilibrium assumption
749  text = ' THERMAL-EQUIL'
750  idx = idx + 1
751  ! -- use dimension of GWF term
752  maxlist = this%flowbudptr%budterm(this%idxbudgwf)%maxlist
753  naux = 0
754  call this%budobj%budterm(idx)%initialize(text, &
755  this%name_model, &
756  this%packName, &
757  this%name_model, &
758  this%packName, &
759  maxlist, .false., .false., &
760  naux)
761  end subroutine uze_setup_budobj
762 
763  !> @brief Fill UZE budget object
764  !!
765  !! Copy flow terms into this%budobj
766  !<
767  subroutine uze_fill_budobj(this, idx, x, flowja, ccratin, ccratout)
768  ! -- modules
769  ! -- dummy
770  class(gweuzetype) :: this
771  integer(I4B), intent(inout) :: idx
772  real(DP), dimension(:), intent(in) :: x
773  real(DP), dimension(:), contiguous, intent(inout) :: flowja
774  real(DP), intent(inout) :: ccratin
775  real(DP), intent(inout) :: ccratout
776  ! -- local
777  integer(I4B) :: j, n1, n2, indx
778  integer(I4B) :: nlist, nlen
779  integer(I4B) :: igwfnode
780  integer(I4B) :: idiag
781  real(DP) :: q
782  real(DP), dimension(:), allocatable :: budresid
783  !
784  allocate (budresid(this%ncv))
785  do n1 = 1, this%ncv
786  budresid(n1) = dzero
787  end do
788  !
789  indx = 0
790  !
791  ! -- FLOW JA FACE into budresid
792  nlen = 0
793  if (this%idxbudfjf /= 0) then
794  nlen = this%flowbudptr%budterm(this%idxbudfjf)%maxlist
795  end if
796  if (nlen > 0) then
797  indx = indx + 1
798  nlist = this%budobj%budterm(indx)%nlist
799  do j = 1, nlist
800  n1 = this%budobj%budterm(indx)%id1(j)
801  n2 = this%budobj%budterm(indx)%id2(j)
802  if (n1 < n2) then
803  q = this%budobj%budterm(indx)%flow(j)
804  budresid(n1) = budresid(n1) + q
805  budresid(n2) = budresid(n2) - q
806  end if
807  end do
808  end if
809  !
810  ! -- GWF (LEAKAGE) into budresid
811  indx = indx + 1
812  nlist = this%budobj%budterm(indx)%nlist
813  do j = 1, nlist
814  n1 = this%budobj%budterm(indx)%id1(j)
815  q = this%budobj%budterm(indx)%flow(j)
816  budresid(n1) = budresid(n1) + q
817  end do
818  !
819  ! -- Skip individual package terms
820  indx = this%idxlastpak
821  !
822  ! -- STORAGE into budresid
823  indx = indx + 1
824  do n1 = 1, this%ncv
825  q = this%budobj%budterm(indx)%flow(n1)
826  budresid(n1) = budresid(n1) + q
827  end do
828  !
829  ! -- TO MOVER into budresid
830  if (this%idxbudtmvr /= 0) then
831  indx = indx + 1
832  nlist = this%budobj%budterm(indx)%nlist
833  do j = 1, nlist
834  n1 = this%budobj%budterm(indx)%id1(j)
835  q = this%budobj%budterm(indx)%flow(j)
836  budresid(n1) = budresid(n1) + q
837  end do
838  end if
839  !
840  ! -- FROM MOVER into budresid
841  if (this%idxbudfmvr /= 0) then
842  indx = indx + 1
843  nlist = this%budobj%budterm(indx)%nlist
844  do j = 1, nlist
845  n1 = this%budobj%budterm(indx)%id1(j)
846  q = this%budobj%budterm(indx)%flow(j)
847  budresid(n1) = budresid(n1) + q
848  end do
849  end if
850  !
851  ! -- CONSTANT FLOW into budresid
852  indx = indx + 1
853  do n1 = 1, this%ncv
854  q = this%budobj%budterm(indx)%flow(n1)
855  budresid(n1) = budresid(n1) + q
856  end do
857  !
858  ! -- AUXILIARY VARIABLES into budresid
859  ! -- (No flows associated with these)
860  !
861  ! -- Individual package terms processed last
862  !
863  ! -- Infiltration
864  idx = idx + 1
865  nlist = this%flowbudptr%budterm(this%idxbudinfl)%nlist
866  call this%budobj%budterm(idx)%reset(nlist)
867  do j = 1, nlist
868  call this%uze_infl_term(j, n1, n2, q)
869  call this%budobj%budterm(idx)%update_term(n1, n2, q)
870  call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout)
871  budresid(n1) = budresid(n1) + q
872  end do
873  !
874  ! -- Rej-Inf
875  if (this%idxbudrinf /= 0) then
876  idx = idx + 1
877  nlist = this%flowbudptr%budterm(this%idxbudrinf)%nlist
878  call this%budobj%budterm(idx)%reset(nlist)
879  do j = 1, nlist
880  call this%uze_rinf_term(j, n1, n2, q)
881  call this%budobj%budterm(idx)%update_term(n1, n2, q)
882  call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout)
883  budresid(n1) = budresid(n1) + q
884  end do
885  end if
886  !
887  ! -- UZET
888  if (this%idxbuduzet /= 0) then
889  idx = idx + 1
890  nlist = this%flowbudptr%budterm(this%idxbuduzet)%nlist
891  call this%budobj%budterm(idx)%reset(nlist)
892  do j = 1, nlist
893  call this%uze_uzet_term(j, n1, n2, q)
894  call this%budobj%budterm(idx)%update_term(n1, n2, q)
895  call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout)
896  budresid(n1) = budresid(n1) + q
897  end do
898  end if
899  !
900  ! -- Rej-Inf-To-MVR
901  if (this%idxbudritm /= 0) then
902  idx = idx + 1
903  nlist = this%flowbudptr%budterm(this%idxbudritm)%nlist
904  call this%budobj%budterm(idx)%reset(nlist)
905  do j = 1, nlist
906  call this%uze_ritm_term(j, n1, n2, q)
907  call this%budobj%budterm(idx)%update_term(n1, n2, q)
908  call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout)
909  budresid(n1) = budresid(n1) + q
910  end do
911  end if
912  !
913  ! -- Thermal-Equil
914  ! -- processed last because it is calculated from the residual
915  idx = idx + 1
916  nlist = this%flowbudptr%budterm(this%idxbudgwf)%nlist
917  call this%budobj%budterm(idx)%reset(nlist)
918  do j = 1, nlist
919  n1 = this%flowbudptr%budterm(this%idxbudgwf)%id1(j)
920  igwfnode = this%flowbudptr%budterm(this%idxbudgwf)%id2(j)
921  q = -budresid(n1)
922  call this%uze_theq_term(j, n1, igwfnode, q)
923  call this%budobj%budterm(idx)%update_term(n1, igwfnode, q)
924  call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout)
925  if (this%iboundpak(n1) /= 0) then
926  ! -- Contribution to gwe cell budget
927  this%simvals(n1) = this%simvals(n1) - q
928  idiag = this%dis%con%ia(igwfnode)
929  flowja(idiag) = flowja(idiag) - q
930  end if
931  end do
932  !
933  deallocate (budresid)
934  end subroutine uze_fill_budobj
935 
936  !> @brief Allocate scalars
937  !!
938  !! Allocate scalars specific to UZE package
939  !<
940  subroutine allocate_scalars(this)
941  ! -- modules
943  ! -- dummy
944  class(gweuzetype) :: this
945  ! -- local
946  !
947  ! -- Allocate scalars in TspAptType
948  call this%TspAptType%allocate_scalars()
949  !
950  ! -- Allocate
951  call mem_allocate(this%idxbudinfl, 'IDXBUDINFL', this%memoryPath)
952  call mem_allocate(this%idxbudrinf, 'IDXBUDRINF', this%memoryPath)
953  call mem_allocate(this%idxbuduzet, 'IDXBUDUZET', this%memoryPath)
954  call mem_allocate(this%idxbudritm, 'IDXBUDRITM', this%memoryPath)
955  call mem_allocate(this%idxbudtheq, 'IDXBUDTHEQ', this%memoryPath)
956  !
957  ! -- Initialize
958  this%idxbudinfl = 0
959  this%idxbudrinf = 0
960  this%idxbuduzet = 0
961  this%idxbudritm = 0
962  this%idxbudtheq = 0
963  end subroutine allocate_scalars
964 
965  !> @brief Allocate arrays
966  !!
967  !! Allocate arrays used by the UZE package
968  !<
969  subroutine uze_allocate_arrays(this)
970  ! -- modules
972  ! -- dummy
973  class(gweuzetype), intent(inout) :: this
974  !
975  ! -- alias into the input context's permanent, feature-indexed arrays
976  ! (allocated and DZERO-initialized by the input context)
977  call mem_setptr(this%tempinfl, 'INFILTRATION', this%input_mempath)
978  call mem_setptr(this%tempuzet, 'UZET', this%input_mempath)
979  !
980  ! -- Call standard TspAptType allocate arrays
981  call this%TspAptType%apt_allocate_arrays()
982  !
983  end subroutine uze_allocate_arrays
984 
985  !> @brief Deallocate memory
986  !<
987  subroutine uze_da(this)
988  ! -- modules
990  ! -- dummy
991  class(gweuzetype) :: this
992  !
993  ! -- Deallocate scalars
994  call mem_deallocate(this%idxbudinfl)
995  call mem_deallocate(this%idxbudrinf)
996  call mem_deallocate(this%idxbuduzet)
997  call mem_deallocate(this%idxbudritm)
998  call mem_deallocate(this%idxbudtheq)
999  !
1000  ! -- input-context-owned aliases, not package-allocated
1001  nullify (this%tempinfl)
1002  nullify (this%tempuzet)
1003  !
1004  ! -- Deallocate scalars in TspAptType
1005  call this%TspAptType%bnd_da()
1006  end subroutine uze_da
1007 
1008  !> @brief Infiltration term
1009  !!
1010  !! Accounts for energy added to the subsurface via infiltration, for example,
1011  !! energy entering the model domain via rainfall or irrigation.
1012  !<
1013  subroutine uze_infl_term(this, ientry, n1, n2, rrate, &
1014  rhsval, hcofval)
1015  ! -- dummy
1016  class(gweuzetype) :: this
1017  integer(I4B), intent(in) :: ientry
1018  integer(I4B), intent(inout) :: n1
1019  integer(I4B), intent(inout) :: n2
1020  real(DP), intent(inout), optional :: rrate
1021  real(DP), intent(inout), optional :: rhsval
1022  real(DP), intent(inout), optional :: hcofval
1023  ! -- local
1024  real(DP) :: qbnd
1025  real(DP) :: ctmp
1026  real(DP) :: h, r
1027  !
1028  n1 = this%flowbudptr%budterm(this%idxbudinfl)%id1(ientry)
1029  n2 = this%flowbudptr%budterm(this%idxbudinfl)%id2(ientry)
1030  !
1031  ! -- Note that qbnd is negative for negative infiltration
1032  qbnd = this%flowbudptr%budterm(this%idxbudinfl)%flow(ientry)
1033  if (qbnd < dzero) then
1034  ctmp = this%xnewpak(n1)
1035  h = qbnd
1036  r = dzero
1037  else
1038  ctmp = this%tempinfl(n1)
1039  h = dzero
1040  r = -qbnd * ctmp
1041  end if
1042  if (present(rrate)) rrate = qbnd * ctmp * this%eqnsclfac
1043  if (present(rhsval)) rhsval = r * this%eqnsclfac
1044  if (present(hcofval)) hcofval = h * this%eqnsclfac
1045  end subroutine uze_infl_term
1046 
1047  !> @brief Rejected infiltration term
1048  !!
1049  !! Accounts for energy that is added to the model from specifying an
1050  !! infiltration rate and temperature, but is subsequently removed from
1051  !! the model as that portion of the infiltration that is rejected (and
1052  !! NOT transferred to another advanced package via the MVR/MVT packages).
1053  !<
1054  subroutine uze_rinf_term(this, ientry, n1, n2, rrate, &
1055  rhsval, hcofval)
1056  ! -- dummy
1057  class(gweuzetype) :: this
1058  integer(I4B), intent(in) :: ientry
1059  integer(I4B), intent(inout) :: n1
1060  integer(I4B), intent(inout) :: n2
1061  real(DP), intent(inout), optional :: rrate
1062  real(DP), intent(inout), optional :: rhsval
1063  real(DP), intent(inout), optional :: hcofval
1064  ! -- local
1065  real(DP) :: qbnd
1066  real(DP) :: ctmp
1067  !
1068  n1 = this%flowbudptr%budterm(this%idxbudrinf)%id1(ientry)
1069  n2 = this%flowbudptr%budterm(this%idxbudrinf)%id2(ientry)
1070  qbnd = this%flowbudptr%budterm(this%idxbudrinf)%flow(ientry)
1071  ctmp = this%tempinfl(n1)
1072  if (present(rrate)) rrate = ctmp * qbnd * this%eqnsclfac
1073  if (present(rhsval)) rhsval = dzero
1074  if (present(hcofval)) hcofval = qbnd * this%eqnsclfac
1075  end subroutine uze_rinf_term
1076 
1077  !> @brief Evapotranspiration from the unsaturated-zone term
1078  !!
1079  !! Accounts for thermal cooling in the unsaturated zone as a result of
1080  !! evapotranspiration from the unsaturated zone. Amount of water converted
1081  !! to vapor phase (UZET) determined by GWF model
1082  !<
1083  subroutine uze_uzet_term(this, ientry, n1, n2, rrate, rhsval, hcofval)
1084  ! -- dummy
1085  class(gweuzetype) :: this
1086  integer(I4B), intent(in) :: ientry
1087  integer(I4B), intent(inout) :: n1
1088  integer(I4B), intent(inout) :: n2
1089  real(DP), intent(inout), optional :: rrate
1090  real(DP), intent(inout), optional :: rhsval
1091  real(DP), intent(inout), optional :: hcofval
1092  ! -- local
1093  real(DP) :: qbnd
1094  real(DP) :: ctmp
1095  real(DP) :: omega
1096  !
1097  n1 = this%flowbudptr%budterm(this%idxbuduzet)%id1(ientry)
1098  n2 = this%flowbudptr%budterm(this%idxbuduzet)%id2(ientry)
1099  ! -- Note that qbnd is negative for uzet
1100  qbnd = this%flowbudptr%budterm(this%idxbuduzet)%flow(ientry)
1101  ctmp = this%tempuzet(n1)
1102  if (this%xnewpak(n1) < ctmp) then
1103  omega = done
1104  else
1105  omega = dzero
1106  end if
1107  if (present(rrate)) &
1108  rrate = (omega * qbnd * this%xnewpak(n1) + &
1109  (done - omega) * qbnd * ctmp) * this%eqnsclfac
1110  if (present(rhsval)) rhsval = -(done - omega) * qbnd * ctmp * this%eqnsclfac
1111  if (present(hcofval)) hcofval = omega * qbnd * this%eqnsclfac
1112  end subroutine uze_uzet_term
1113 
1114  !> @brief Rejected infiltration to MVR/MVT term
1115  !!
1116  !! Accounts for energy that is added to the model from specifying an
1117  !! infiltration rate and temperature, but does not infiltrate into the
1118  !! subsurface. This subroutine is called when the rejected infiltration
1119  !! is transferred to another advanced package via the MVR/MVT packages.
1120  !<
1121  subroutine uze_ritm_term(this, ientry, n1, n2, rrate, &
1122  rhsval, hcofval)
1123  ! -- dummy
1124  class(gweuzetype) :: this
1125  integer(I4B), intent(in) :: ientry
1126  integer(I4B), intent(inout) :: n1
1127  integer(I4B), intent(inout) :: n2
1128  real(DP), intent(inout), optional :: rrate
1129  real(DP), intent(inout), optional :: rhsval
1130  real(DP), intent(inout), optional :: hcofval
1131  ! -- local
1132  real(DP) :: qbnd
1133  real(DP) :: ctmp
1134  !
1135  n1 = this%flowbudptr%budterm(this%idxbudritm)%id1(ientry)
1136  n2 = this%flowbudptr%budterm(this%idxbudritm)%id2(ientry)
1137  qbnd = this%flowbudptr%budterm(this%idxbudritm)%flow(ientry)
1138  ctmp = this%tempinfl(n1)
1139  if (present(rrate)) rrate = ctmp * qbnd * this%eqnsclfac
1140  if (present(rhsval)) rhsval = dzero
1141  if (present(hcofval)) hcofval = qbnd * this%eqnsclfac
1142  end subroutine uze_ritm_term
1143 
1144  !> @brief Heat transferred through thermal equilibrium with the solid phase
1145  !!
1146  !! Accounts for the transfer of energy from the liquid phase to the solid
1147  !! phase as a result of the instantaneous thermal equilibrium assumption.
1148  !<
1149  subroutine uze_theq_term(this, ientry, n1, n2, rrate)
1150  ! -- modules
1151  use constantsmodule, only: lenbudtxt
1152  ! -- dummy
1153  class(gweuzetype) :: this
1154  integer(I4B), intent(in) :: ientry
1155  integer(I4B), intent(inout) :: n1
1156  integer(I4B), intent(inout) :: n2
1157  real(DP), intent(inout) :: rrate
1158  ! -- local
1159  real(DP) :: r
1160  integer(I4B) :: i
1161  character(len=LENBUDTXT) :: flowtype
1162  !
1163  r = dzero
1164  n1 = this%flowbudptr%budterm(this%idxbudgwf)%id1(ientry)
1165  n2 = this%flowbudptr%budterm(this%idxbudgwf)%id2(ientry)
1166  if (this%iboundpak(n1) /= 0) then
1167  do i = 1, this%budobj%nbudterm
1168  flowtype = this%budobj%budterm(i)%flowtype
1169  select case (trim(adjustl(flowtype)))
1170  case ('THERMAL-EQUIL')
1171  ! -- Skip
1172  continue
1173  case default
1174  r = r - this%budobj%budterm(i)%flow(ientry)
1175  end select
1176  end do
1177  end if
1178  rrate = r
1179  end subroutine uze_theq_term
1180 
1181  !> @brief Define UZE Observation
1182  !!
1183  !! This subroutine:
1184  !! - Stores observation types supported by the parent APT package.
1185  !! - Overrides BndType%bnd_df_obs
1186  !<
1187  subroutine uze_df_obs(this)
1188  ! -- dummy
1189  class(gweuzetype) :: this
1190  ! -- local
1191  integer(I4B) :: indx
1192  !
1193  ! -- Store obs type and assign procedure pointer
1194  ! for temperature observation type.
1195  call this%obs%StoreObsType('temperature', .false., indx)
1196  this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsid
1197  !
1198  ! -- Store obs type and assign procedure pointer
1199  ! for flow between uze cells.
1200  call this%obs%StoreObsType('flow-ja-face', .true., indx)
1201  this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsid12
1202  !
1203  ! -- Store obs type and assign procedure pointer
1204  ! for from-mvr observation type.
1205  call this%obs%StoreObsType('from-mvr', .true., indx)
1206  this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsid
1207  !
1208  ! -- to-mvr not supported for uze
1209  !call this%obs%StoreObsType('to-mvr', .true., indx)
1210  !this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID
1211  !
1212  ! -- Store obs type and assign procedure pointer
1213  ! for storage observation type.
1214  call this%obs%StoreObsType('storage', .true., indx)
1215  this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsid
1216  !
1217  ! -- Store obs type and assign procedure pointer
1218  ! for constant observation type.
1219  call this%obs%StoreObsType('constant', .true., indx)
1220  this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsid
1221  !
1222  ! -- Store obs type and assign procedure pointer
1223  ! for observation type: uze
1224  call this%obs%StoreObsType('uze', .true., indx)
1225  this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsid
1226  !
1227  ! -- Store obs type and assign procedure pointer
1228  ! for observation type.
1229  call this%obs%StoreObsType('infiltration', .true., indx)
1230  this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsid
1231  !
1232  ! -- Store obs type and assign procedure pointer
1233  ! for observation type.
1234  call this%obs%StoreObsType('rej-inf', .true., indx)
1235  this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsid
1236  !
1237  ! -- Store obs type and assign procedure pointer
1238  ! for observation type.
1239  call this%obs%StoreObsType('uzet', .true., indx)
1240  this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsid
1241  !
1242  ! -- Store obs type and assign procedure pointer
1243  ! for observation type.
1244  call this%obs%StoreObsType('rej-inf-to-mvr', .true., indx)
1245  this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsid
1246  !
1247  ! -- Store obs type and assign procedure pointer
1248  ! for observation type.
1249  call this%obs%StoreObsType('thermal-equil', .true., indx)
1250  this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsid
1251  end subroutine uze_df_obs
1252 
1253  !> @brief Process package specific obs
1254  !!
1255  !! Method to process specific observations for this package.
1256  !<
1257  subroutine uze_rp_obs(this, obsrv, found)
1258  ! -- dummy
1259  class(gweuzetype), intent(inout) :: this !< package class
1260  type(observetype), intent(inout) :: obsrv !< observation object
1261  logical, intent(inout) :: found !< indicate whether observation was found
1262  !
1263  found = .true.
1264  select case (obsrv%ObsTypeId)
1265  case ('INFILTRATION')
1266  call this%rp_obs_byfeature(obsrv)
1267  case ('REJ-INF')
1268  call this%rp_obs_byfeature(obsrv)
1269  case ('UZET')
1270  call this%rp_obs_byfeature(obsrv)
1271  case ('REJ-INF-TO-MVR')
1272  call this%rp_obs_byfeature(obsrv)
1273  case ('THERMAL-EQUIL')
1274  call this%rp_obs_byfeature(obsrv)
1275  case default
1276  found = .false.
1277  end select
1278  end subroutine uze_rp_obs
1279 
1280  !> @brief Calculate observation value and pass it back to APT
1281  !<
1282  subroutine uze_bd_obs(this, obstypeid, jj, v, found)
1283  ! -- dummy
1284  class(gweuzetype), intent(inout) :: this
1285  character(len=*), intent(in) :: obstypeid
1286  real(DP), intent(inout) :: v
1287  integer(I4B), intent(in) :: jj
1288  logical, intent(inout) :: found
1289  ! -- local
1290  integer(I4B) :: n1, n2
1291  !
1292  found = .true.
1293  select case (obstypeid)
1294  case ('INFILTRATION')
1295  if (this%iboundpak(jj) /= 0 .and. this%idxbudinfl > 0) then
1296  call this%uze_infl_term(jj, n1, n2, v)
1297  end if
1298  case ('REJ-INF')
1299  if (this%iboundpak(jj) /= 0 .and. this%idxbudrinf > 0) then
1300  call this%uze_rinf_term(jj, n1, n2, v)
1301  end if
1302  case ('UZET')
1303  if (this%iboundpak(jj) /= 0 .and. this%idxbuduzet > 0) then
1304  call this%uze_uzet_term(jj, n1, n2, v)
1305  end if
1306  case ('REJ-INF-TO-MVR')
1307  if (this%iboundpak(jj) /= 0 .and. this%idxbudritm > 0) then
1308  call this%uze_ritm_term(jj, n1, n2, v)
1309  end if
1310  case ('THERMAL-EQUIL')
1311  if (this%iboundpak(jj) /= 0 .and. this%idxbudtheq > 0) then
1312  call this%uze_theq_term(jj, n1, n2, v)
1313  end if
1314  case default
1315  found = .false.
1316  end select
1317  end subroutine uze_bd_obs
1318 
1319  !> @brief Check if UZF object area is not equal to the cell area
1320  !!
1321  !! GWE equilibrates the temperature of a UZE object with the host cell. UZE
1322  !! assumes that the area associated with a specific UZE object is equal to
1323  !! the area of the host cell. When this condition is not true, the code
1324  !! exits with an appropriate message.
1325  !<
1326  subroutine uze_ad_chk(this)
1327  ! -- modules
1328  use constantsmodule, only: izero
1329  use mathutilmodule, only: is_close
1330  use simmodule, only: count_errors
1331  ! -- dummy
1332  class(gweuzetype), intent(inout) :: this
1333  ! -- local
1334  integer(I4B) :: nuz
1335  integer(I4B) :: n
1336  integer(I4B) :: igwfnode
1337  real(DP) :: carea
1338  real(DP) :: uzarea
1339 
1340  nuz = this%flowbudptr%budterm(this%idxbudgwf)%maxlist
1341 
1342  ! cycle through uze objects, stop at first occurrence of more than one
1343  ! uze object in a cell
1344  do n = 1, nuz
1345  igwfnode = this%flowbudptr%budterm(this%idxbudgwf)%id2(n)
1346  carea = this%dis%area(igwfnode)
1347  uzarea = this%flowbudptr%budterm(this%idxbudgwf)%auxvar(1, n)
1348  ! compare areas
1349  if (.not. is_close(carea, uzarea)) then
1350  call this%area_error(igwfnode)
1351  end if
1352  end do
1353  if (count_errors() > 0) then
1354  call store_error_filename(this%input_fname)
1355  end if
1356  end subroutine uze_ad_chk
1357 
1358  !> @brief Print and store error msg indicating area of UZF object is not
1359  !! equal to that of the host cell
1360  !<
1361  subroutine area_error(this, iloc)
1362  ! -- modules
1363  use simvariablesmodule, only: errmsg
1364  ! -- dummy
1365  class(gweuzetype) :: this
1366  integer(I4B) :: iloc
1367  ! -- local
1368  character(len=30) :: nodestr
1369  !
1370  call this%dis%noder_to_string(iloc, nodestr)
1371  write (errmsg, '(3a)') &
1372  'In a GWE model, the area of every UZF object must be equal to that of &
1373  &the host cell. This condition is violated in cell ', &
1374  trim(adjustl(nodestr)), '. Check use of AUXMULTNAME option in UZF &
1375  &package.'
1376  call store_error(errmsg)
1377  end subroutine area_error
1378 
1379 end module gweuzemodule
This module contains the base boundary package.
class(bndtype) function, pointer, public getbndfromlist(list, idx)
Get boundary from package list.
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
real(dp), parameter dnodata
real no data constant
Definition: Constants.f90:95
integer(i4b), parameter lenvarname
maximum length of a variable name
Definition: Constants.f90:17
integer(i4b), parameter izero
integer constant zero
Definition: Constants.f90:51
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
integer(i4b), parameter lenbudtxt
maximum length of a budget component names
Definition: Constants.f90:37
real(dp), parameter done
real constant 1
Definition: Constants.f90:76
subroutine uze_ad_chk(this)
Check if UZF object area is not equal to the cell area.
Definition: gwe-uze.f90:1327
subroutine uze_rp_obs(this, obsrv, found)
Process package specific obs.
Definition: gwe-uze.f90:1258
character(len= *), parameter ftype
Definition: gwe-uze.f90:47
subroutine uze_mc(this, moffset, matrix_sln)
Map package connection to matrix.
Definition: gwe-uze.f90:371
subroutine uze_ac(this, moffset, sparse)
Add package connection to matrix.
Definition: gwe-uze.f90:304
subroutine allocate_scalars(this)
Allocate scalars.
Definition: gwe-uze.f90:941
character(len=16) text
Definition: gwe-uze.f90:49
subroutine, public uze_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, mempath, fmi, eqnsclfac, gwecommon, dvt, dvu, dvua)
Create a new UZE package.
Definition: gwe-uze.f90:98
subroutine uze_setup_budobj(this, idx)
Setup budget object.
Definition: gwe-uze.f90:681
subroutine uze_ritm_term(this, ientry, n1, n2, rrate, rhsval, hcofval)
Rejected infiltration to MVR/MVT term.
Definition: gwe-uze.f90:1123
subroutine uze_df_obs(this)
Define UZE Observation.
Definition: gwe-uze.f90:1188
subroutine uze_bd_obs(this, obstypeid, jj, v, found)
Calculate observation value and pass it back to APT.
Definition: gwe-uze.f90:1283
subroutine uze_fc_expanded(this, rhs, ia, idxglo, matrix_sln)
Add matrix terms related to UZE.
Definition: gwe-uze.f90:461
subroutine uze_theq_term(this, ientry, n1, n2, rrate)
Heat transferred through thermal equilibrium with the solid phase.
Definition: gwe-uze.f90:1150
subroutine uze_rinf_term(this, ientry, n1, n2, rrate, rhsval, hcofval)
Rejected infiltration term.
Definition: gwe-uze.f90:1056
integer(i4b) function uze_get_nbudterms(this)
Return the number of UZE-specific budget terms.
Definition: gwe-uze.f90:647
subroutine uze_solve(this)
Explicit solve.
Definition: gwe-uze.f90:601
character(len= *), parameter flowtype
Definition: gwe-uze.f90:48
subroutine uze_da(this)
Deallocate memory.
Definition: gwe-uze.f90:988
real(dp) function, dimension(:), pointer, contiguous get_mvr_depvar(this)
Override similarly named function in APT.
Definition: gwe-uze.f90:667
subroutine find_uze_package(this)
Find corresponding uze package.
Definition: gwe-uze.f90:160
subroutine uze_fill_budobj(this, idx, x, flowja, ccratin, ccratout)
Fill UZE budget object.
Definition: gwe-uze.f90:768
subroutine uze_allocate_arrays(this)
Allocate arrays.
Definition: gwe-uze.f90:970
subroutine area_error(this, iloc)
Print and store error msg indicating area of UZF object is not equal to that of the host cell.
Definition: gwe-uze.f90:1362
subroutine uze_infl_term(this, ientry, n1, n2, rrate, rhsval, hcofval)
Infiltration term.
Definition: gwe-uze.f90:1015
subroutine uze_uzet_term(this, ientry, n1, n2, rrate, rhsval, hcofval)
Evapotranspiration from the unsaturated-zone term.
Definition: gwe-uze.f90:1084
real(dp) function uze_setting_value(this, itemno, key)
Value for a package-specific PERIOD setting.
Definition: gwe-uze.f90:282
This module defines variable data types.
Definition: kind.f90:8
pure logical function, public is_close(a, b, rtol, atol, symmetric)
Check if a real value is approximately equal to another.
Definition: MathUtil.f90:46
This module contains the derived types ObserveType and ObsDataType.
Definition: Observe.f90:15
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
integer(i4b) function, public count_errors()
Return number of errors.
Definition: Sim.f90:59
subroutine, public store_error_filename(filename, terminate)
Store the erroring file name.
Definition: Sim.f90:204
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string
subroutine, public apt_process_obsid(obsrv, dis, inunitobs, iout)
Process observation IDs for an advanced package.
Definition: tsp-apt.f90:2690
subroutine, public apt_process_obsid12(obsrv, dis, inunitobs, iout)
Process observation IDs for a package.
Definition: tsp-apt.f90:2733
@ brief BndType
This class is used to store a single deferred-length character string. It was designed to work in an ...
Definition: CharString.f90:23
Data for sharing among multiple packages. Originally read in from.