MODFLOW 6  version 6.5.0.dev2
MODFLOW 6 Code Documentation
tsp-apt.f90
Go to the documentation of this file.
1 ! -- Advanced Package Transport Module
2 ! -- This module contains most of the routines for simulating transport
3 ! -- through the advanced packages.
4 ! -- Future work:
5 ! * support decay, sorption
6 ! * dispersion in SFT and UZT?
7 !
8 ! AFP flows (flowbudptr) index var ATP term Transport Type
9 !---------------------------------------------------------------------------------
10 
11 ! -- specialized terms in the flow budget
12 ! FLOW-JA-FACE idxbudfjf FLOW-JA-FACE cv2cv
13 ! GWF (aux FLOW-AREA) idxbudgwf GWF cv2gwf
14 ! STORAGE (aux VOLUME) idxbudsto none used for cv volumes
15 ! FROM-MVR idxbudfmvr FROM-MVR q * cext = this%qfrommvr(:) ! rhow*cpw is applied to various terms for heat transport
16 ! TO-MVR idxbudtmvr TO-MVR q * cfeat
17 
18 ! -- generalized source/sink terms (except ET?)
19 ! RAINFALL idxbudrain RAINFALL q * crain
20 ! EVAPORATION idxbudevap EVAPORATION cfeat<cevap: q*cfeat, else: q*cevap ! latent heat may be applied for evaporative cooling
21 ! RUNOFF idxbudroff RUNOFF q * croff
22 ! EXT-INFLOW idxbudiflw EXT-INFLOW q * ciflw
23 ! WITHDRAWAL idxbudwdrl WITHDRAWAL q * cfeat
24 ! EXT-OUTFLOW idxbudoutf EXT-OUTFLOW q * cfeat
25 
26 ! -- terms from a flow file that should be skipped
27 ! CONSTANT none none none
28 ! AUXILIARY none none none
29 
30 ! -- terms that are written to the transport budget file
31 ! none none STORAGE (aux MASS) dM/dt
32 ! none none AUXILIARY none
33 ! none none CONSTANT accumulate
34 !
35 !
37 
38  use kindmodule, only: dp, i4b, lgp
45  use simvariablesmodule, only: errmsg
46  use bndmodule, only: bndtype
47  use tspfmimodule, only: tspfmitype
50  use tablemodule, only: tabletype, table_cr
51  use observemodule, only: observetype
53  use basedismodule, only: disbasetype
55 
56  implicit none
57 
58  public :: tspapttype
59  public :: apt_process_obsid
60  public :: apt_process_obsid12
61 
62  character(len=LENFTYPE) :: ftype = 'APT'
63  character(len=LENVARNAME) :: text = ' APT'
64 
65  type, extends(bndtype) :: tspapttype
66 
67  character(len=LENPACKAGENAME) :: flowpackagename = '' !< name of corresponding flow package
68  character(len=8), &
69  dimension(:), pointer, contiguous :: status => null() !< active, inactive, constant
70  character(len=LENAUXNAME) :: cauxfpconc = '' !< name of aux column in flow package auxvar array for concentration (or temperature)
71  integer(I4B), pointer :: iauxfpconc => null() !< column in flow package bound array to insert concs
72  integer(I4B), pointer :: imatrows => null() !< if active, add new rows to matrix
73  integer(I4B), pointer :: iprconc => null() !< print conc to listing file
74  integer(I4B), pointer :: iconcout => null() !< unit number for conc output file
75  integer(I4B), pointer :: ibudgetout => null() !< unit number for budget output file
76  integer(I4B), pointer :: ibudcsv => null() !< unit number for csv budget output file
77  integer(I4B), pointer :: ncv => null() !< number of control volumes
78  integer(I4B), pointer :: igwfaptpak => null() !< package number of corresponding this package
79  integer(I4B), pointer :: idxprepak => null() !< budget-object index that precedes package-specific budget objects
80  integer(I4B), pointer :: idxlastpak => null() !< budget-object index of last package-specific budget object
81  real(dp), dimension(:), pointer, contiguous :: strt => null() !< starting feature concentration (or temperature)
82  real(dp), dimension(:), pointer, contiguous :: ktf => null() !< thermal conductivity between the apt and groundwater cell
83  real(dp), dimension(:), pointer, contiguous :: rfeatthk => null() !< thickness of streambed/lakebed/filter-pack material through which thermal conduction occurs
84  integer(I4B), dimension(:), pointer, contiguous :: idxlocnode => null() !< map position in global rhs and x array of pack entry
85  integer(I4B), dimension(:), pointer, contiguous :: idxpakdiag => null() !< map diag position of feature in global amat
86  integer(I4B), dimension(:), pointer, contiguous :: idxdglo => null() !< map position in global array of package diagonal row entries
87  integer(I4B), dimension(:), pointer, contiguous :: idxoffdglo => null() !< map position in global array of package off diagonal row entries
88  integer(I4B), dimension(:), pointer, contiguous :: idxsymdglo => null() !< map position in global array of package diagonal entries to model rows
89  integer(I4B), dimension(:), pointer, contiguous :: idxsymoffdglo => null() !< map position in global array of package off diagonal entries to model rows
90  integer(I4B), dimension(:), pointer, contiguous :: idxfjfdglo => null() !< map diagonal feature to feature in global amat
91  integer(I4B), dimension(:), pointer, contiguous :: idxfjfoffdglo => null() !< map off diagonal feature to feature in global amat
92  integer(I4B), dimension(:), pointer, contiguous :: iboundpak => null() !< package ibound
93  real(dp), dimension(:), pointer, contiguous :: xnewpak => null() !< feature concentration (or temperature) for current time step
94  real(dp), dimension(:), pointer, contiguous :: xoldpak => null() !< feature concentration (or temperature) from previous time step
95  real(dp), dimension(:), pointer, contiguous :: dbuff => null() !< temporary storage array
96  character(len=LENBOUNDNAME), &
97  dimension(:), pointer, contiguous :: featname => null()
98  real(dp), dimension(:), pointer, contiguous :: concfeat => null() !< concentration (or temperature) of the feature
99  real(dp), dimension(:, :), pointer, contiguous :: lauxvar => null() !< auxiliary variable
100  type(tspfmitype), pointer :: fmi => null() !< pointer to fmi object
101  real(dp), dimension(:), pointer, contiguous :: qsto => null() !< mass (or energy) flux due to storage change
102  real(dp), dimension(:), pointer, contiguous :: ccterm => null() !< mass (or energy) flux required to maintain constant concentration (or temperature)
103  integer(I4B), pointer :: idxbudfjf => null() !< index of flow ja face in flowbudptr
104  integer(I4B), pointer :: idxbudgwf => null() !< index of gwf terms in flowbudptr
105  integer(I4B), pointer :: idxbudsto => null() !< index of storage terms in flowbudptr
106  integer(I4B), pointer :: idxbudtmvr => null() !< index of to mover terms in flowbudptr
107  integer(I4B), pointer :: idxbudfmvr => null() !< index of from mover terms in flowbudptr
108  integer(I4B), pointer :: idxbudaux => null() !< index of auxiliary terms in flowbudptr
109  integer(I4B), dimension(:), pointer, contiguous :: idxbudssm => null() !< flag that flowbudptr%buditem is a general solute source/sink
110  integer(I4B), pointer :: nconcbudssm => null() !< number of concbudssm terms (columns)
111  real(dp), dimension(:, :), pointer, contiguous :: concbudssm => null() !< user specified concentrations (or temperatures) for flow terms
112  real(dp), dimension(:), pointer, contiguous :: qmfrommvr => null() !< a mass or energy flow coming from the mover that needs to be added
113  real(dp), pointer :: eqnsclfac => null() !< governing equation scale factor; =1. for solute; =rhow*cpw for energy
114  character(len=LENVARNAME) :: depvartype = '' !< stores string identifying dependent variable type, depending on model type
115  character(len=LENVARNAME) :: depvarunit = '' !< "mass" or "energy"
116  character(len=LENVARNAME) :: depvarunitabbrev = '' !< "M" or "E"
117  !
118  ! -- pointer to flow package boundary
119  type(bndtype), pointer :: flowpackagebnd => null()
120  !
121  ! -- budget objects
122  type(budgetobjecttype), pointer :: budobj => null() !< apt solute budget object
123  type(budgetobjecttype), pointer :: flowbudptr => null() !< GWF flow budget object
124  !
125  ! -- table objects
126  type(tabletype), pointer :: dvtab => null()
127 
128  contains
129 
130  procedure :: set_pointers => apt_set_pointers
131  procedure :: bnd_ac => apt_ac
132  procedure :: bnd_mc => apt_mc
133  procedure :: bnd_ar => apt_ar
134  procedure :: bnd_rp => apt_rp
135  procedure :: bnd_ad => apt_ad
136  procedure :: bnd_reset => apt_reset
137  procedure :: bnd_fc => apt_fc
138  procedure, public :: apt_fc_expanded ! Made public for uze
139  procedure :: pak_fc_expanded
140  procedure, private :: apt_fc_nonexpanded
141  procedure, public :: apt_cfupdate ! Made public for uze
142  procedure :: apt_check_valid
143  procedure :: apt_set_stressperiod
144  procedure :: pak_set_stressperiod
146  procedure :: bnd_cq => apt_cq
147  procedure :: bnd_ot_package_flows => apt_ot_package_flows
148  procedure :: bnd_ot_dv => apt_ot_dv
149  procedure :: bnd_ot_bdsummary => apt_ot_bdsummary
150  procedure :: bnd_da => apt_da
151  procedure :: allocate_scalars
153  procedure :: apt_allocate_arrays
154  procedure :: find_apt_package
155  procedure :: apt_solve
156  procedure :: pak_solve
157  procedure :: bnd_options => apt_options
158  procedure :: read_dimensions => apt_read_dimensions
159  procedure :: apt_read_cvs
160  procedure :: read_initial_attr => apt_read_initial_attr
161  procedure :: define_listlabel
162  ! -- methods for observations
163  procedure :: bnd_obs_supported => apt_obs_supported
164  procedure :: bnd_df_obs => apt_df_obs
165  procedure :: pak_df_obs
166  procedure :: pak_rp_obs
167  procedure :: bnd_rp_obs => apt_rp_obs
168  procedure :: rp_obs_byfeature
169  procedure :: rp_obs_budterm
170  procedure :: rp_obs_flowjaface
171  procedure :: bnd_bd_obs => apt_bd_obs
172  procedure :: pak_bd_obs
173  procedure :: get_volumes
174  procedure :: pak_get_nbudterms
175  procedure :: apt_setup_budobj
176  procedure :: pak_setup_budobj
177  procedure :: apt_fill_budobj
178  procedure :: pak_fill_budobj
179  procedure, public :: apt_stor_term
180  procedure, public :: apt_tmvr_term
181  procedure, public :: apt_fmvr_term ! Made public for uze
182  procedure, public :: apt_fjf_term ! Made public for uze
183  procedure, private :: apt_copy2flowp
184  procedure, private :: apt_setup_tableobj
185  procedure, public :: get_mvr_depvar
186 
187  end type tspapttype
188 
189 contains
190 
191  !> @brief Add package connection to matrix
192  !<
193  subroutine apt_ac(this, moffset, sparse)
195  use sparsemodule, only: sparsematrix
196  ! -- dummy
197  class(tspapttype), intent(inout) :: this
198  integer(I4B), intent(in) :: moffset
199  type(sparsematrix), intent(inout) :: sparse
200  ! -- local
201  integer(I4B) :: i, n
202  integer(I4B) :: jj, jglo
203  integer(I4B) :: nglo
204  ! -- format
205  !
206  ! -- Add package rows to sparse
207  if (this%imatrows /= 0) then
208  !
209  ! -- diagonal
210  do n = 1, this%ncv
211  nglo = moffset + this%dis%nodes + this%ioffset + n
212  call sparse%addconnection(nglo, nglo, 1)
213  end do
214  !
215  ! -- apt-gwf connections
216  do i = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
217  n = this%flowbudptr%budterm(this%idxbudgwf)%id1(i)
218  jj = this%flowbudptr%budterm(this%idxbudgwf)%id2(i)
219  nglo = moffset + this%dis%nodes + this%ioffset + n
220  jglo = jj + moffset
221  call sparse%addconnection(nglo, jglo, 1)
222  call sparse%addconnection(jglo, nglo, 1)
223  end do
224  !
225  ! -- apt-apt connections
226  if (this%idxbudfjf /= 0) then
227  do i = 1, this%flowbudptr%budterm(this%idxbudfjf)%maxlist
228  n = this%flowbudptr%budterm(this%idxbudfjf)%id1(i)
229  jj = this%flowbudptr%budterm(this%idxbudfjf)%id2(i)
230  nglo = moffset + this%dis%nodes + this%ioffset + n
231  jglo = moffset + this%dis%nodes + this%ioffset + jj
232  call sparse%addconnection(nglo, jglo, 1)
233  end do
234  end if
235  end if
236  !
237  ! -- Return
238  return
239  end subroutine apt_ac
240 
241  !> @brief Advanced package transport map package connections to matrix
242  !<
243  subroutine apt_mc(this, moffset, matrix_sln)
244  use sparsemodule, only: sparsematrix
245  ! -- dummy
246  class(tspapttype), intent(inout) :: this
247  integer(I4B), intent(in) :: moffset
248  class(matrixbasetype), pointer :: matrix_sln
249  ! -- local
250  integer(I4B) :: n, j, iglo, jglo
251  integer(I4B) :: ipos
252  ! -- format
253  !
254  ! -- allocate memory for index arrays
255  call this%apt_allocate_index_arrays()
256  !
257  ! -- store index positions
258  if (this%imatrows /= 0) then
259  !
260  ! -- Find the position of each connection in the global ia, ja structure
261  ! and store them in idxglo. idxglo allows this model to insert or
262  ! retrieve values into or from the global A matrix
263  ! -- apt rows
264  do n = 1, this%ncv
265  this%idxlocnode(n) = this%dis%nodes + this%ioffset + n
266  iglo = moffset + this%dis%nodes + this%ioffset + n
267  this%idxpakdiag(n) = matrix_sln%get_position_diag(iglo)
268  end do
269  do ipos = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
270  n = this%flowbudptr%budterm(this%idxbudgwf)%id1(ipos)
271  j = this%flowbudptr%budterm(this%idxbudgwf)%id2(ipos)
272  iglo = moffset + this%dis%nodes + this%ioffset + n
273  jglo = j + moffset
274  this%idxdglo(ipos) = matrix_sln%get_position_diag(iglo)
275  this%idxoffdglo(ipos) = matrix_sln%get_position(iglo, jglo)
276  end do
277  !
278  ! -- apt contributions to gwf portion of global matrix
279  do ipos = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
280  n = this%flowbudptr%budterm(this%idxbudgwf)%id1(ipos)
281  j = this%flowbudptr%budterm(this%idxbudgwf)%id2(ipos)
282  iglo = j + moffset
283  jglo = moffset + this%dis%nodes + this%ioffset + n
284  this%idxsymdglo(ipos) = matrix_sln%get_position_diag(iglo)
285  this%idxsymoffdglo(ipos) = matrix_sln%get_position(iglo, jglo)
286  end do
287  !
288  ! -- apt-apt contributions to gwf portion of global matrix
289  if (this%idxbudfjf /= 0) then
290  do ipos = 1, this%flowbudptr%budterm(this%idxbudfjf)%nlist
291  n = this%flowbudptr%budterm(this%idxbudfjf)%id1(ipos)
292  j = this%flowbudptr%budterm(this%idxbudfjf)%id2(ipos)
293  iglo = moffset + this%dis%nodes + this%ioffset + n
294  jglo = moffset + this%dis%nodes + this%ioffset + j
295  this%idxfjfdglo(ipos) = matrix_sln%get_position_diag(iglo)
296  this%idxfjfoffdglo(ipos) = matrix_sln%get_position(iglo, jglo)
297  end do
298  end if
299  end if
300  !
301  ! -- Return
302  return
303  end subroutine apt_mc
304 
305  !> @brief Advanced package transport allocate and read (ar) routine
306  !<
307  subroutine apt_ar(this)
308  ! -- modules
309  ! -- dummy
310  class(tspapttype), intent(inout) :: this
311  ! -- local
312  integer(I4B) :: j
313  logical :: found
314  ! -- formats
315  character(len=*), parameter :: fmtapt = &
316  "(1x,/1x,'APT -- ADVANCED PACKAGE TRANSPORT, VERSION 1, 3/5/2020', &
317  &' INPUT READ FROM UNIT ', i0, //)"
318  !
319  ! -- Get obs setup
320  call this%obs%obs_ar()
321  !
322  ! --print a message identifying the apt package.
323  write (this%iout, fmtapt) this%inunit
324  !
325  ! -- Allocate arrays
326  call this%apt_allocate_arrays()
327  !
328  ! -- read optional initial package parameters
329  call this%read_initial_attr()
330  !
331  ! -- Find the package index in the GWF model or GWF budget file
332  ! for the corresponding apt flow package
333  call this%fmi%get_package_index(this%flowpackagename, this%igwfaptpak)
334  !
335  ! -- Tell fmi that this package is being handled by APT, otherwise
336  ! SSM would handle the flows into GWT from this pack. Then point the
337  ! fmi data for an advanced package to xnewpak and qmfrommvr
338  this%fmi%iatp(this%igwfaptpak) = 1
339  this%fmi%datp(this%igwfaptpak)%concpack => this%get_mvr_depvar()
340  this%fmi%datp(this%igwfaptpak)%qmfrommvr => this%qmfrommvr
341  !
342  ! -- If there is an associated flow package and the user wishes to put
343  ! simulated concentrations (or temperatures) into a aux variable
344  ! column, then find the column number.
345  if (associated(this%flowpackagebnd)) then
346  if (this%cauxfpconc /= '') then
347  found = .false.
348  do j = 1, this%flowpackagebnd%naux
349  if (this%flowpackagebnd%auxname(j) == this%cauxfpconc) then
350  this%iauxfpconc = j
351  found = .true.
352  exit
353  end if
354  end do
355  if (this%iauxfpconc == 0) then
356  errmsg = 'Could not find auxiliary variable '// &
357  trim(adjustl(this%cauxfpconc))//' in flow package '// &
358  trim(adjustl(this%flowpackagename))
359  call store_error(errmsg)
360  call this%parser%StoreErrorUnit()
361  else
362  ! -- tell package not to update this auxiliary variable
363  this%flowpackagebnd%noupdateauxvar(this%iauxfpconc) = 1
364  call this%apt_copy2flowp()
365  end if
366  end if
367  end if
368  !
369  ! -- Return
370  return
371  end subroutine apt_ar
372 
373  !> @brief Advanced package transport read and prepare (rp) routine
374  !!
375  !! This subroutine calls the attached packages' read and prepare routines.
376  !<
377  subroutine apt_rp(this)
378  use tdismodule, only: kper, nper
379  ! -- dummy
380  class(tspapttype), intent(inout) :: this
381  ! -- local
382  integer(I4B) :: ierr
383  integer(I4B) :: n
384  logical :: isfound, endOfBlock
385  character(len=LINELENGTH) :: title
386  character(len=LINELENGTH) :: line
387  integer(I4B) :: itemno
388  integer(I4B) :: igwfnode
389  ! -- formats
390  character(len=*), parameter :: fmtblkerr = &
391  &"('Error. Looking for BEGIN PERIOD iper. Found ', a, ' instead.')"
392  character(len=*), parameter :: fmtlsp = &
393  &"(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')"
394  !
395  ! -- set nbound to maxbound
396  this%nbound = this%maxbound
397  !
398  ! -- Set ionper to the stress period number for which a new block of data
399  ! will be read.
400  if (this%inunit == 0) return
401  !
402  ! -- get stress period data
403  if (this%ionper < kper) then
404  !
405  ! -- get period block
406  call this%parser%GetBlock('PERIOD', isfound, ierr, &
407  supportopenclose=.true., &
408  blockrequired=.false.)
409  if (isfound) then
410  !
411  ! -- read ionper and check for increasing period numbers
412  call this%read_check_ionper()
413  else
414  !
415  ! -- PERIOD block not found
416  if (ierr < 0) then
417  ! -- End of file found; data applies for remainder of simulation.
418  this%ionper = nper + 1
419  else
420  ! -- Found invalid block
421  call this%parser%GetCurrentLine(line)
422  write (errmsg, fmtblkerr) adjustl(trim(line))
423  call store_error(errmsg)
424  call this%parser%StoreErrorUnit()
425  end if
426  end if
427  end if
428  !
429  ! -- Read data if ionper == kper
430  if (this%ionper == kper) then
431  !
432  ! -- setup table for period data
433  if (this%iprpak /= 0) then
434  !
435  ! -- reset the input table object
436  title = trim(adjustl(this%text))//' PACKAGE ('// &
437  trim(adjustl(this%packName))//') DATA FOR PERIOD'
438  write (title, '(a,1x,i6)') trim(adjustl(title)), kper
439  call table_cr(this%inputtab, this%packName, title)
440  call this%inputtab%table_df(1, 4, this%iout, finalize=.false.)
441  text = 'NUMBER'
442  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
443  text = 'KEYWORD'
444  call this%inputtab%initialize_column(text, 20, alignment=tableft)
445  do n = 1, 2
446  write (text, '(a,1x,i6)') 'VALUE', n
447  call this%inputtab%initialize_column(text, 15, alignment=tabcenter)
448  end do
449  end if
450  !
451  ! -- read data
452  stressperiod: do
453  call this%parser%GetNextLine(endofblock)
454  if (endofblock) exit
455  !
456  ! -- get feature number
457  itemno = this%parser%GetInteger()
458  !
459  ! -- read data from the rest of the line
460  call this%apt_set_stressperiod(itemno)
461  !
462  ! -- write line to table
463  if (this%iprpak /= 0) then
464  call this%parser%GetCurrentLine(line)
465  call this%inputtab%line_to_columns(line)
466  end if
467  end do stressperiod
468 
469  if (this%iprpak /= 0) then
470  call this%inputtab%finalize_table()
471  end if
472  !
473  ! -- using stress period data from the previous stress period
474  else
475  write (this%iout, fmtlsp) trim(this%filtyp)
476  end if
477  !
478  ! -- write summary of stress period error messages
479  ierr = count_errors()
480  if (ierr > 0) then
481  call this%parser%StoreErrorUnit()
482  end if
483  !
484  ! -- fill arrays
485  do n = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
486  igwfnode = this%flowbudptr%budterm(this%idxbudgwf)%id2(n)
487  this%nodelist(n) = igwfnode
488  end do
489  !
490  ! -- Return
491  return
492  end subroutine apt_rp
493 
494  !> @brief Advanced package transport set stress period routine.
495  !!
496  !! Set a stress period attribute for an advanced transport package feature
497  !! (itemno) using keywords.
498  !<
499  subroutine apt_set_stressperiod(this, itemno)
500  ! -- module
502  ! -- dummy
503  class(tspapttype), intent(inout) :: this
504  integer(I4B), intent(in) :: itemno
505  ! -- local
506  character(len=LINELENGTH) :: text
507  character(len=LINELENGTH) :: caux
508  character(len=LINELENGTH) :: keyword
509  integer(I4B) :: ierr
510  integer(I4B) :: ii
511  integer(I4B) :: jj
512  real(DP), pointer :: bndElem => null()
513  logical :: found
514  ! -- formats
515  !
516  ! -- Support these general options in LKT, SFT, MWT, UZT
517  ! STATUS <status>
518  ! CONCENTRATION <concentration> or TEMPERATURE <temperature>
519  ! WITHDRAWAL <withdrawal>
520  ! AUXILIARY <auxname> <auxval>
521  !
522  ! -- read line
523  call this%parser%GetStringCaps(keyword)
524  select case (keyword)
525  case ('STATUS')
526  ierr = this%apt_check_valid(itemno)
527  if (ierr /= 0) then
528  goto 999
529  end if
530  call this%parser%GetStringCaps(text)
531  this%status(itemno) = text(1:8)
532  if (text == 'CONSTANT') then
533  this%iboundpak(itemno) = -1
534  else if (text == 'INACTIVE') then
535  this%iboundpak(itemno) = 0
536  else if (text == 'ACTIVE') then
537  this%iboundpak(itemno) = 1
538  else
539  write (errmsg, '(a,a)') &
540  'Unknown '//trim(this%text)//' status keyword: ', text//'.'
541  call store_error(errmsg)
542  end if
543  case ('CONCENTRATION', 'TEMPERATURE')
544  ierr = this%apt_check_valid(itemno)
545  if (ierr /= 0) then
546  goto 999
547  end if
548  call this%parser%GetString(text)
549  jj = 1 ! For feature concentration
550  bndelem => this%concfeat(itemno)
551  call read_value_or_time_series_adv(text, itemno, jj, bndelem, &
552  this%packName, 'BND', this%tsManager, &
553  this%iprpak, this%depvartype)
554  case ('AUXILIARY')
555  ierr = this%apt_check_valid(itemno)
556  if (ierr /= 0) then
557  goto 999
558  end if
559  call this%parser%GetStringCaps(caux)
560  do jj = 1, this%naux
561  if (trim(adjustl(caux)) /= trim(adjustl(this%auxname(jj)))) cycle
562  call this%parser%GetString(text)
563  ii = itemno
564  bndelem => this%lauxvar(jj, ii)
565  call read_value_or_time_series_adv(text, itemno, jj, bndelem, &
566  this%packName, 'AUX', &
567  this%tsManager, this%iprpak, &
568  this%auxname(jj))
569  exit
570  end do
571  case default
572  !
573  ! -- call the specific package to look for stress period data
574  call this%pak_set_stressperiod(itemno, keyword, found)
575  !
576  ! -- terminate with error if data not valid
577  if (.not. found) then
578  write (errmsg, '(2a)') &
579  'Unknown '//trim(adjustl(this%text))//' data keyword: ', &
580  trim(keyword)//'.'
581  call store_error(errmsg)
582  end if
583  end select
584  !
585  ! -- terminate if any errors were detected
586 999 if (count_errors() > 0) then
587  call this%parser%StoreErrorUnit()
588  end if
589  !
590  ! -- Return
591  return
592  end subroutine apt_set_stressperiod
593 
594  !> @brief Advanced package transport set stress period routine.
595  !!
596  !! Set a stress period attribute for an individual package. This routine
597  !! must be overridden.
598  !<
599  subroutine pak_set_stressperiod(this, itemno, keyword, found)
600  ! -- dummy
601  class(tspapttype), intent(inout) :: this
602  integer(I4B), intent(in) :: itemno
603  character(len=*), intent(in) :: keyword
604  logical, intent(inout) :: found
605  ! -- local
606 
607  ! -- formats
608  !
609  ! -- this routine should never be called
610  found = .false.
611  call store_error('Program error: pak_set_stressperiod not implemented.', &
612  terminate=.true.)
613  !
614  ! -- Return
615  return
616  end subroutine pak_set_stressperiod
617 
618  !> @brief Advanced package transport routine
619  !!
620  !! Determine if a valid feature number has been specified.
621  !<
622  function apt_check_valid(this, itemno) result(ierr)
623  ! -- return
624  integer(I4B) :: ierr
625  ! -- dummy
626  class(tspapttype), intent(inout) :: this
627  integer(I4B), intent(in) :: itemno
628  ! -- formats
629  ierr = 0
630  if (itemno < 1 .or. itemno > this%ncv) then
631  write (errmsg, '(a,1x,i6,1x,a,1x,i6)') &
632  'Featureno ', itemno, 'must be > 0 and <= ', this%ncv
633  call store_error(errmsg)
634  ierr = 1
635  end if
636  end function apt_check_valid
637 
638  !> @brief Advanced package transport utility function
639  !!
640  !! Set the concentration (or temperature) to be used by either MVT or MVE
641  !<
642  function get_mvr_depvar(this)
643  ! -- dummy
644  class(tspapttype) :: this
645  ! -- return
646  real(dp), dimension(:), contiguous, pointer :: get_mvr_depvar
647  !
648  get_mvr_depvar => this%xnewpak
649  end function get_mvr_depvar
650 
651  !> @brief Advanced package transport routine
652  !!
653  !! Add package connections to matrix
654  !<
655  subroutine apt_ad(this)
656  ! -- modules
658  ! -- dummy
659  class(tspapttype) :: this
660  ! -- local
661  integer(I4B) :: n
662  integer(I4B) :: j, iaux
663  !
664  ! -- Advance the time series
665  call this%TsManager%ad()
666  !
667  ! -- update auxiliary variables by copying from the derived-type time
668  ! series variable into the bndpackage auxvar variable so that this
669  ! information is properly written to the GWF budget file
670  if (this%naux > 0) then
671  do j = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
672  n = this%flowbudptr%budterm(this%idxbudgwf)%id1(j)
673  do iaux = 1, this%naux
674  this%auxvar(iaux, j) = this%lauxvar(iaux, n)
675  end do
676  end do
677  end if
678  !
679  ! -- copy xnew into xold and set xnewpak to specified concentration (or
680  ! temperature) for constant concentration/temperature features
681  if (ifailedstepretry == 0) then
682  do n = 1, this%ncv
683  this%xoldpak(n) = this%xnewpak(n)
684  if (this%iboundpak(n) < 0) then
685  this%xnewpak(n) = this%concfeat(n)
686  end if
687  end do
688  else
689  do n = 1, this%ncv
690  this%xnewpak(n) = this%xoldpak(n)
691  if (this%iboundpak(n) < 0) then
692  this%xnewpak(n) = this%concfeat(n)
693  end if
694  end do
695  end if
696  !
697  ! -- pakmvrobj ad
698  !if (this%imover == 1) then
699  ! call this%pakmvrobj%ad()
700  !end if
701  !
702  ! -- For each observation, push simulated value and corresponding
703  ! simulation time from "current" to "preceding" and reset
704  ! "current" value.
705  call this%obs%obs_ad()
706  !
707  ! -- Return
708  return
709  end subroutine apt_ad
710 
711  !> @brief Override bnd reset for custom mover logic
712  subroutine apt_reset(this)
713  class(tspapttype) :: this !< GwtAptType object
714  ! local
715  integer(I4B) :: i
716  !
717  do i = 1, size(this%qmfrommvr)
718  this%qmfrommvr(i) = dzero
719  end do
720  !
721  ! -- Return
722  return
723  end subroutine apt_reset
724 
725  subroutine apt_fc(this, rhs, ia, idxglo, matrix_sln)
726  ! -- modules
727  ! -- dummy
728  class(tspapttype) :: this
729  real(DP), dimension(:), intent(inout) :: rhs
730  integer(I4B), dimension(:), intent(in) :: ia
731  integer(I4B), dimension(:), intent(in) :: idxglo
732  class(matrixbasetype), pointer :: matrix_sln
733  ! -- local
734  !
735  ! -- Call fc depending on whether or not a matrix is expanded or not
736  if (this%imatrows == 0) then
737  call this%apt_fc_nonexpanded(rhs, ia, idxglo, matrix_sln)
738  else
739  call this%apt_fc_expanded(rhs, ia, idxglo, matrix_sln)
740  end if
741  !
742  ! -- Return
743  return
744  end subroutine apt_fc
745 
746  !> @brief Advanced package transport fill coefficient (fc) method
747  !!
748  !! Routine to formulate the nonexpanded matrix case in which feature
749  !! concentrations (or temperatures) are solved explicitly
750  !<
751  subroutine apt_fc_nonexpanded(this, rhs, ia, idxglo, matrix_sln)
752  ! -- modules
753  ! -- dummy
754  class(tspapttype) :: this
755  real(DP), dimension(:), intent(inout) :: rhs
756  integer(I4B), dimension(:), intent(in) :: ia
757  integer(I4B), dimension(:), intent(in) :: idxglo
758  class(matrixbasetype), pointer :: matrix_sln
759  ! -- local
760  integer(I4B) :: j, igwfnode, idiag
761  !
762  ! -- solve for concentration (or temperatures) in the features
763  call this%apt_solve()
764  !
765  ! -- add hcof and rhs terms (from apt_solve) to the gwf matrix
766  do j = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
767  igwfnode = this%flowbudptr%budterm(this%idxbudgwf)%id2(j)
768  if (this%ibound(igwfnode) < 1) cycle
769  idiag = idxglo(ia(igwfnode))
770  call matrix_sln%add_value_pos(idiag, this%hcof(j))
771  rhs(igwfnode) = rhs(igwfnode) + this%rhs(j)
772  end do
773  !
774  ! -- Return
775  return
776  end subroutine apt_fc_nonexpanded
777 
778  !> @brief Advanced package transport fill coefficient (fc) method
779  !!
780  !! Routine to formulate the expanded matrix case in which new rows are added
781  !! to the system of equations for each advanced package transport feature
782  !<
783  subroutine apt_fc_expanded(this, rhs, ia, idxglo, matrix_sln)
784  ! -- modules
785  ! -- dummy
786  class(tspapttype) :: this
787  real(DP), dimension(:), intent(inout) :: rhs
788  integer(I4B), dimension(:), intent(in) :: ia
789  integer(I4B), dimension(:), intent(in) :: idxglo
790  class(matrixbasetype), pointer :: matrix_sln
791  ! -- local
792  integer(I4B) :: j, n, n1, n2
793  integer(I4B) :: iloc
794  integer(I4B) :: iposd, iposoffd
795  integer(I4B) :: ipossymd, ipossymoffd
796  real(DP) :: cold
797  real(DP) :: qbnd, qbnd_scaled
798  real(DP) :: omega
799  real(DP) :: rrate
800  real(DP) :: rhsval
801  real(DP) :: hcofval
802  !
803  ! -- call the specific method for the advanced transport package, such as
804  ! what would be overridden by
805  ! GwtLktType, GwtSftType, GwtMwtType, GwtUztType
806  ! This routine will add terms for rainfall, runoff, or other terms
807  ! specific to the package
808  call this%pak_fc_expanded(rhs, ia, idxglo, matrix_sln)
809  !
810  ! -- mass (or energy) storage in features
811  do n = 1, this%ncv
812  cold = this%xoldpak(n)
813  iloc = this%idxlocnode(n)
814  iposd = this%idxpakdiag(n)
815  call this%apt_stor_term(n, n1, n2, rrate, rhsval, hcofval)
816  call matrix_sln%add_value_pos(iposd, hcofval)
817  rhs(iloc) = rhs(iloc) + rhsval
818  end do
819  !
820  ! -- add to mover contribution
821  if (this%idxbudtmvr /= 0) then
822  do j = 1, this%flowbudptr%budterm(this%idxbudtmvr)%nlist
823  call this%apt_tmvr_term(j, n1, n2, rrate, rhsval, hcofval)
824  iloc = this%idxlocnode(n1)
825  iposd = this%idxpakdiag(n1)
826  call matrix_sln%add_value_pos(iposd, hcofval)
827  rhs(iloc) = rhs(iloc) + rhsval
828  end do
829  end if
830  !
831  ! -- add from mover contribution
832  if (this%idxbudfmvr /= 0) then
833  do n = 1, this%ncv
834  rhsval = this%qmfrommvr(n) ! this will already be in terms of energy for heat transport
835  iloc = this%idxlocnode(n)
836  rhs(iloc) = rhs(iloc) - rhsval
837  end do
838  end if
839  !
840  ! -- go through each apt-gwf connection
841  do j = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
842  !
843  ! -- set n to feature number and process if active feature
844  n = this%flowbudptr%budterm(this%idxbudgwf)%id1(j)
845  if (this%iboundpak(n) /= 0) then
846  !
847  ! -- set acoef and rhs to negative so they are relative to apt and not gwt
848  qbnd = this%flowbudptr%budterm(this%idxbudgwf)%flow(j)
849  omega = dzero
850  if (qbnd < dzero) omega = done
851  qbnd_scaled = qbnd * this%eqnsclfac
852  !
853  ! -- add to apt row
854  iposd = this%idxdglo(j)
855  iposoffd = this%idxoffdglo(j)
856  call matrix_sln%add_value_pos(iposd, omega * qbnd_scaled)
857  call matrix_sln%add_value_pos(iposoffd, (done - omega) * qbnd_scaled)
858  !
859  ! -- add to gwf row for apt connection
860  ipossymd = this%idxsymdglo(j)
861  ipossymoffd = this%idxsymoffdglo(j)
862  call matrix_sln%add_value_pos(ipossymd, -(done - omega) * qbnd_scaled)
863  call matrix_sln%add_value_pos(ipossymoffd, -omega * qbnd_scaled)
864  end if
865  end do
866  !
867  ! -- go through each apt-apt connection
868  if (this%idxbudfjf /= 0) then
869  do j = 1, this%flowbudptr%budterm(this%idxbudfjf)%nlist
870  n1 = this%flowbudptr%budterm(this%idxbudfjf)%id1(j)
871  n2 = this%flowbudptr%budterm(this%idxbudfjf)%id2(j)
872  qbnd = this%flowbudptr%budterm(this%idxbudfjf)%flow(j)
873  if (qbnd <= dzero) then
874  omega = done
875  else
876  omega = dzero
877  end if
878  qbnd_scaled = qbnd * this%eqnsclfac
879  iposd = this%idxfjfdglo(j)
880  iposoffd = this%idxfjfoffdglo(j)
881  call matrix_sln%add_value_pos(iposd, omega * qbnd_scaled)
882  call matrix_sln%add_value_pos(iposoffd, (done - omega) * qbnd_scaled)
883  end do
884  end if
885  !
886  ! -- Return
887  return
888  end subroutine apt_fc_expanded
889 
890  !> @brief Advanced package transport fill coefficient (fc) method
891  !!
892  !! Routine to allow a subclass advanced transport package to inject
893  !! terms into the matrix assembly. This method must be overridden.
894  !<
895  subroutine pak_fc_expanded(this, rhs, ia, idxglo, matrix_sln)
896  ! -- modules
897  ! -- dummy
898  class(tspapttype) :: this
899  real(DP), dimension(:), intent(inout) :: rhs
900  integer(I4B), dimension(:), intent(in) :: ia
901  integer(I4B), dimension(:), intent(in) :: idxglo
902  class(matrixbasetype), pointer :: matrix_sln
903  ! -- local
904  !
905  ! -- this routine should never be called
906  call store_error('Program error: pak_fc_expanded not implemented.', &
907  terminate=.true.)
908  !
909  ! -- Return
910  return
911  end subroutine pak_fc_expanded
912 
913  !> @brief Advanced package transport routine
914  !!
915  !! Calculate advanced package transport hcof and rhs so transport budget is
916  !! calculated.
917  !<
918  subroutine apt_cfupdate(this)
919  ! -- modules
920  ! -- dummy
921  class(tspapttype) :: this
922  ! -- local
923  integer(I4B) :: j, n
924  real(DP) :: qbnd
925  real(DP) :: omega
926  !
927  ! -- Calculate hcof and rhs terms so GWF exchanges are calculated correctly
928  ! -- go through each apt-gwf connection and calculate
929  ! rhs and hcof terms for gwt/gwe matrix rows
930  do j = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
931  n = this%flowbudptr%budterm(this%idxbudgwf)%id1(j)
932  this%hcof(j) = dzero
933  this%rhs(j) = dzero
934  if (this%iboundpak(n) /= 0) then
935  qbnd = this%flowbudptr%budterm(this%idxbudgwf)%flow(j)
936  omega = dzero
937  if (qbnd < dzero) omega = done
938  this%hcof(j) = -(done - omega) * qbnd * this%eqnsclfac
939  this%rhs(j) = omega * qbnd * this%xnewpak(n) * this%eqnsclfac
940  end if
941  end do
942  !
943  ! -- Return
944  return
945  end subroutine apt_cfupdate
946 
947  !> @brief Advanced package transport calculate flows (cq) routine
948  !!
949  !! Calculate flows for the advanced package transport feature
950  !<
951  subroutine apt_cq(this, x, flowja, iadv)
952  ! -- modules
953  ! -- dummy
954  class(tspapttype), intent(inout) :: this
955  real(DP), dimension(:), intent(in) :: x
956  real(DP), dimension(:), contiguous, intent(inout) :: flowja
957  integer(I4B), optional, intent(in) :: iadv
958  ! -- local
959  integer(I4B) :: n, n1, n2
960  real(DP) :: rrate
961  !
962  ! -- Solve the feature concentrations (or temperatures) again or update
963  ! the feature hcof and rhs terms
964  if (this%imatrows == 0) then
965  call this%apt_solve()
966  else
967  call this%apt_cfupdate()
968  end if
969  !
970  ! -- call base functionality in bnd_cq
971  call this%BndType%bnd_cq(x, flowja)
972  !
973  ! -- calculate storage term
974  do n = 1, this%ncv
975  rrate = dzero
976  if (this%iboundpak(n) > 0) then
977  call this%apt_stor_term(n, n1, n2, rrate)
978  end if
979  this%qsto(n) = rrate
980  end do
981  !
982  ! -- Copy concentrations (or temperatures) into the flow package auxiliary variable
983  call this%apt_copy2flowp()
984  !
985  ! -- fill the budget object
986  call this%apt_fill_budobj(x, flowja)
987  !
988  ! -- Return
989  return
990  end subroutine apt_cq
991 
992  !> @brief Save advanced package flows routine
993  !<
994  subroutine apt_ot_package_flows(this, icbcfl, ibudfl)
995  use tdismodule, only: kstp, kper, delt, pertim, totim
996  class(tspapttype) :: this
997  integer(I4B), intent(in) :: icbcfl
998  integer(I4B), intent(in) :: ibudfl
999  integer(I4B) :: ibinun
1000  !
1001  ! -- write the flows from the budobj
1002  ibinun = 0
1003  if (this%ibudgetout /= 0) then
1004  ibinun = this%ibudgetout
1005  end if
1006  if (icbcfl == 0) ibinun = 0
1007  if (ibinun > 0) then
1008  call this%budobj%save_flows(this%dis, ibinun, kstp, kper, delt, &
1009  pertim, totim, this%iout)
1010  end if
1011  !
1012  ! -- Print lake flows table
1013  if (ibudfl /= 0 .and. this%iprflow /= 0) then
1014  call this%budobj%write_flowtable(this%dis, kstp, kper)
1015  end if
1016  !
1017  ! -- Return
1018  return
1019  end subroutine apt_ot_package_flows
1020 
1021  subroutine apt_ot_dv(this, idvsave, idvprint)
1022  ! -- modules
1023  use constantsmodule, only: lenbudtxt
1024  use tdismodule, only: kstp, kper, pertim, totim
1025  use constantsmodule, only: dhnoflo, dhdry, lenbudtxt
1026  use inputoutputmodule, only: ulasav
1027  ! -- dummy
1028  class(tspapttype) :: this
1029  integer(I4B), intent(in) :: idvsave
1030  integer(I4B), intent(in) :: idvprint
1031  ! -- local
1032  integer(I4B) :: ibinun
1033  integer(I4B) :: n
1034  real(DP) :: c
1035  character(len=LENBUDTXT) :: text
1036  !
1037  ! -- set unit number for binary dependent variable output
1038  ibinun = 0
1039  if (this%iconcout /= 0) then
1040  ibinun = this%iconcout
1041  end if
1042  if (idvsave == 0) ibinun = 0
1043  !
1044  ! -- write binary output
1045  if (ibinun > 0) then
1046  do n = 1, this%ncv
1047  c = this%xnewpak(n)
1048  if (this%iboundpak(n) == 0) then
1049  c = dhnoflo
1050  end if
1051  this%dbuff(n) = c
1052  end do
1053  write (text, '(a)') str_pad_left(this%depvartype, lenvarname)
1054  call ulasav(this%dbuff, text, kstp, kper, pertim, totim, &
1055  this%ncv, 1, 1, ibinun)
1056  end if
1057  !
1058  ! -- write apt conc table
1059  if (idvprint /= 0 .and. this%iprconc /= 0) then
1060  !
1061  ! -- set table kstp and kper
1062  call this%dvtab%set_kstpkper(kstp, kper)
1063  !
1064  ! -- fill concentration data
1065  do n = 1, this%ncv
1066  if (this%inamedbound == 1) then
1067  call this%dvtab%add_term(this%featname(n))
1068  end if
1069  call this%dvtab%add_term(n)
1070  call this%dvtab%add_term(this%xnewpak(n))
1071  end do
1072  end if
1073  !
1074  ! -- Return
1075  return
1076  end subroutine apt_ot_dv
1077 
1078  !> @brief Print advanced package transport dependent variables
1079  !<
1080  subroutine apt_ot_bdsummary(this, kstp, kper, iout, ibudfl)
1081  ! -- module
1082  use tdismodule, only: totim, delt
1083  ! -- dummy
1084  class(tspapttype) :: this !< TspAptType object
1085  integer(I4B), intent(in) :: kstp !< time step number
1086  integer(I4B), intent(in) :: kper !< period number
1087  integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file
1088  integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written
1089  !
1090  call this%budobj%write_budtable(kstp, kper, iout, ibudfl, totim, delt)
1091  !
1092  ! -- Return
1093  return
1094  end subroutine apt_ot_bdsummary
1095 
1096  !> @ brief Allocate scalars
1097  !!
1098  !! Allocate scalar variables for an advanced package
1099  !<
1100  subroutine allocate_scalars(this)
1101  ! -- modules
1103  ! -- dummy
1104  class(tspapttype) :: this
1105  ! -- local
1106  !
1107  ! -- allocate scalars in NumericalPackageType
1108  call this%BndType%allocate_scalars()
1109  !
1110  ! -- Allocate
1111  call mem_allocate(this%iauxfpconc, 'IAUXFPCONC', this%memoryPath)
1112  call mem_allocate(this%imatrows, 'IMATROWS', this%memoryPath)
1113  call mem_allocate(this%iprconc, 'IPRCONC', this%memoryPath)
1114  call mem_allocate(this%iconcout, 'ICONCOUT', this%memoryPath)
1115  call mem_allocate(this%ibudgetout, 'IBUDGETOUT', this%memoryPath)
1116  call mem_allocate(this%ibudcsv, 'IBUDCSV', this%memoryPath)
1117  call mem_allocate(this%igwfaptpak, 'IGWFAPTPAK', this%memoryPath)
1118  call mem_allocate(this%ncv, 'NCV', this%memoryPath)
1119  call mem_allocate(this%idxbudfjf, 'IDXBUDFJF', this%memoryPath)
1120  call mem_allocate(this%idxbudgwf, 'IDXBUDGWF', this%memoryPath)
1121  call mem_allocate(this%idxbudsto, 'IDXBUDSTO', this%memoryPath)
1122  call mem_allocate(this%idxbudtmvr, 'IDXBUDTMVR', this%memoryPath)
1123  call mem_allocate(this%idxbudfmvr, 'IDXBUDFMVR', this%memoryPath)
1124  call mem_allocate(this%idxbudaux, 'IDXBUDAUX', this%memoryPath)
1125  call mem_allocate(this%nconcbudssm, 'NCONCBUDSSM', this%memoryPath)
1126  call mem_allocate(this%idxprepak, 'IDXPREPAK', this%memoryPath)
1127  call mem_allocate(this%idxlastpak, 'IDXLASTPAK', this%memoryPath)
1128  !
1129  ! -- Initialize
1130  this%iauxfpconc = 0
1131  this%imatrows = 1
1132  this%iprconc = 0
1133  this%iconcout = 0
1134  this%ibudgetout = 0
1135  this%ibudcsv = 0
1136  this%igwfaptpak = 0
1137  this%ncv = 0
1138  this%idxbudfjf = 0
1139  this%idxbudgwf = 0
1140  this%idxbudsto = 0
1141  this%idxbudtmvr = 0
1142  this%idxbudfmvr = 0
1143  this%idxbudaux = 0
1144  this%nconcbudssm = 0
1145  this%idxprepak = 0
1146  this%idxlastpak = 0
1147  !
1148  ! -- set this package as causing asymmetric matrix terms
1149  this%iasym = 1
1150  !
1151  ! -- Return
1152  return
1153  end subroutine allocate_scalars
1154 
1155  !> @ brief Allocate index arrays
1156  !!
1157  !! Allocate arrays that map to locations in the numerical solution
1158  !<
1159  subroutine apt_allocate_index_arrays(this)
1160  ! -- modules
1162  ! -- dummy
1163  class(tspapttype), intent(inout) :: this
1164  ! -- local
1165  integer(I4B) :: n
1166  !
1167  if (this%imatrows /= 0) then
1168  !
1169  ! -- count number of flow-ja-face connections
1170  n = 0
1171  if (this%idxbudfjf /= 0) then
1172  n = this%flowbudptr%budterm(this%idxbudfjf)%maxlist
1173  end if
1174  !
1175  ! -- allocate pointers to global matrix
1176  call mem_allocate(this%idxlocnode, this%ncv, 'IDXLOCNODE', &
1177  this%memoryPath)
1178  call mem_allocate(this%idxpakdiag, this%ncv, 'IDXPAKDIAG', &
1179  this%memoryPath)
1180  call mem_allocate(this%idxdglo, this%maxbound, 'IDXGLO', &
1181  this%memoryPath)
1182  call mem_allocate(this%idxoffdglo, this%maxbound, 'IDXOFFDGLO', &
1183  this%memoryPath)
1184  call mem_allocate(this%idxsymdglo, this%maxbound, 'IDXSYMDGLO', &
1185  this%memoryPath)
1186  call mem_allocate(this%idxsymoffdglo, this%maxbound, 'IDXSYMOFFDGLO', &
1187  this%memoryPath)
1188  call mem_allocate(this%idxfjfdglo, n, 'IDXFJFDGLO', &
1189  this%memoryPath)
1190  call mem_allocate(this%idxfjfoffdglo, n, 'IDXFJFOFFDGLO', &
1191  this%memoryPath)
1192  else
1193  call mem_allocate(this%idxlocnode, 0, 'IDXLOCNODE', &
1194  this%memoryPath)
1195  call mem_allocate(this%idxpakdiag, 0, 'IDXPAKDIAG', &
1196  this%memoryPath)
1197  call mem_allocate(this%idxdglo, 0, 'IDXGLO', &
1198  this%memoryPath)
1199  call mem_allocate(this%idxoffdglo, 0, 'IDXOFFDGLO', &
1200  this%memoryPath)
1201  call mem_allocate(this%idxsymdglo, 0, 'IDXSYMDGLO', &
1202  this%memoryPath)
1203  call mem_allocate(this%idxsymoffdglo, 0, 'IDXSYMOFFDGLO', &
1204  this%memoryPath)
1205  call mem_allocate(this%idxfjfdglo, 0, 'IDXFJFDGLO', &
1206  this%memoryPath)
1207  call mem_allocate(this%idxfjfoffdglo, 0, 'IDXFJFOFFDGLO', &
1208  this%memoryPath)
1209  end if
1210  !
1211  ! -- Return
1212  return
1213  end subroutine apt_allocate_index_arrays
1214 
1215  !> @ brief Allocate arrays
1216  !!
1217  !! Allocate advanced package transport arrays
1218  !<
1219  subroutine apt_allocate_arrays(this)
1220  ! -- modules
1222  ! -- dummy
1223  class(tspapttype), intent(inout) :: this
1224  ! -- local
1225  integer(I4B) :: n
1226  !
1227  ! -- call standard BndType allocate scalars
1228  call this%BndType%allocate_arrays()
1229  !
1230  ! -- Allocate
1231  !
1232  ! -- allocate and initialize dbuff
1233  if (this%iconcout > 0) then
1234  call mem_allocate(this%dbuff, this%ncv, 'DBUFF', this%memoryPath)
1235  do n = 1, this%ncv
1236  this%dbuff(n) = dzero
1237  end do
1238  else
1239  call mem_allocate(this%dbuff, 0, 'DBUFF', this%memoryPath)
1240  end if
1241  !
1242  ! -- allocate character array for status
1243  allocate (this%status(this%ncv))
1244  !
1245  ! -- time series
1246  call mem_allocate(this%concfeat, this%ncv, 'CONCFEAT', this%memoryPath)
1247  !
1248  ! -- budget terms
1249  call mem_allocate(this%qsto, this%ncv, 'QSTO', this%memoryPath)
1250  call mem_allocate(this%ccterm, this%ncv, 'CCTERM', this%memoryPath)
1251  !
1252  ! -- concentration for budget terms
1253  call mem_allocate(this%concbudssm, this%nconcbudssm, this%ncv, &
1254  'CONCBUDSSM', this%memoryPath)
1255  !
1256  ! -- mass (or energy) added from the mover transport package
1257  call mem_allocate(this%qmfrommvr, this%ncv, 'QMFROMMVR', this%memoryPath)
1258  !
1259  ! -- initialize arrays
1260  do n = 1, this%ncv
1261  this%status(n) = 'ACTIVE'
1262  this%qsto(n) = dzero
1263  this%ccterm(n) = dzero
1264  this%qmfrommvr(n) = dzero
1265  this%concbudssm(:, n) = dzero
1266  this%concfeat(n) = dzero
1267  end do
1268  !
1269  ! -- Return
1270  return
1271  end subroutine apt_allocate_arrays
1272 
1273  !> @ brief Deallocate memory
1274  !!
1275  !! Deallocate memory associated with this package
1276  !<
1277  subroutine apt_da(this)
1278  ! -- modules
1280  ! -- dummy
1281  class(tspapttype) :: this
1282  ! -- local
1283  !
1284  ! -- deallocate arrays
1285  call mem_deallocate(this%dbuff)
1286  call mem_deallocate(this%qsto)
1287  call mem_deallocate(this%ccterm)
1288  call mem_deallocate(this%strt)
1289  call mem_deallocate(this%ktf)
1290  call mem_deallocate(this%rfeatthk)
1291  call mem_deallocate(this%lauxvar)
1292  call mem_deallocate(this%xoldpak)
1293  if (this%imatrows == 0) then
1294  call mem_deallocate(this%iboundpak)
1295  call mem_deallocate(this%xnewpak)
1296  end if
1297  call mem_deallocate(this%concbudssm)
1298  call mem_deallocate(this%concfeat)
1299  call mem_deallocate(this%qmfrommvr)
1300  deallocate (this%status)
1301  deallocate (this%featname)
1302  !
1303  ! -- budobj
1304  call this%budobj%budgetobject_da()
1305  deallocate (this%budobj)
1306  nullify (this%budobj)
1307  !
1308  ! -- conc table
1309  if (this%iprconc > 0) then
1310  call this%dvtab%table_da()
1311  deallocate (this%dvtab)
1312  nullify (this%dvtab)
1313  end if
1314  !
1315  ! -- index pointers
1316  call mem_deallocate(this%idxlocnode)
1317  call mem_deallocate(this%idxpakdiag)
1318  call mem_deallocate(this%idxdglo)
1319  call mem_deallocate(this%idxoffdglo)
1320  call mem_deallocate(this%idxsymdglo)
1321  call mem_deallocate(this%idxsymoffdglo)
1322  call mem_deallocate(this%idxfjfdglo)
1323  call mem_deallocate(this%idxfjfoffdglo)
1324  !
1325  ! -- deallocate scalars
1326  call mem_deallocate(this%iauxfpconc)
1327  call mem_deallocate(this%imatrows)
1328  call mem_deallocate(this%iprconc)
1329  call mem_deallocate(this%iconcout)
1330  call mem_deallocate(this%ibudgetout)
1331  call mem_deallocate(this%ibudcsv)
1332  call mem_deallocate(this%igwfaptpak)
1333  call mem_deallocate(this%ncv)
1334  call mem_deallocate(this%idxbudfjf)
1335  call mem_deallocate(this%idxbudgwf)
1336  call mem_deallocate(this%idxbudsto)
1337  call mem_deallocate(this%idxbudtmvr)
1338  call mem_deallocate(this%idxbudfmvr)
1339  call mem_deallocate(this%idxbudaux)
1340  call mem_deallocate(this%idxbudssm)
1341  call mem_deallocate(this%nconcbudssm)
1342  call mem_deallocate(this%idxprepak)
1343  call mem_deallocate(this%idxlastpak)
1344  !
1345  ! -- deallocate scalars in NumericalPackageType
1346  call this%BndType%bnd_da()
1347  !
1348  ! -- Return
1349  return
1350  end subroutine apt_da
1351 
1352  !> @brief Find corresponding advanced package transport package
1353  !<
1354  subroutine find_apt_package(this)
1355  ! -- modules
1357  ! -- dummy
1358  class(tspapttype) :: this
1359  ! -- local
1360  !
1361  ! -- this routine should never be called
1362  call store_error('Program error: pak_solve not implemented.', &
1363  terminate=.true.)
1364  !
1365  ! -- Return
1366  return
1367  end subroutine find_apt_package
1368 
1369  !> @brief Set options specific to the TspAptType
1370  !!
1371  !! This routine overrides BndType%bnd_options
1372  !<
1373  subroutine apt_options(this, option, found)
1374  use constantsmodule, only: maxcharlen, dzero
1375  use openspecmodule, only: access, form
1377  ! -- dummy
1378  class(tspapttype), intent(inout) :: this
1379  character(len=*), intent(inout) :: option
1380  logical, intent(inout) :: found
1381  ! -- local
1382  character(len=MAXCHARLEN) :: fname, keyword
1383  ! -- formats
1384  character(len=*), parameter :: fmtaptbin = &
1385  "(4x, a, 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, &
1386  &/4x, 'OPENED ON UNIT: ', I0)"
1387  !
1388  found = .true.
1389  select case (option)
1390  case ('FLOW_PACKAGE_NAME')
1391  call this%parser%GetStringCaps(this%flowpackagename)
1392  write (this%iout, '(4x,a)') &
1393  'THIS '//trim(adjustl(this%text))//' PACKAGE CORRESPONDS TO A GWF &
1394  &PACKAGE WITH THE NAME '//trim(adjustl(this%flowpackagename))
1395  case ('FLOW_PACKAGE_AUXILIARY_NAME')
1396  call this%parser%GetStringCaps(this%cauxfpconc)
1397  write (this%iout, '(4x,a)') &
1398  'SIMULATED CONCENTRATIONS WILL BE COPIED INTO THE FLOW PACKAGE &
1399  &AUXILIARY VARIABLE WITH THE NAME '//trim(adjustl(this%cauxfpconc))
1400  case ('DEV_NONEXPANDING_MATRIX')
1401  ! -- use an iterative solution where concentration is not solved
1402  ! as part of the matrix. It is instead solved separately with a
1403  ! general mixing equation and then added to the RHS of the GWT
1404  ! equations
1405  call this%parser%DevOpt()
1406  this%imatrows = 0
1407  write (this%iout, '(4x,a)') &
1408  trim(adjustl(this%text))// &
1409  ' WILL NOT ADD ADDITIONAL ROWS TO THE A MATRIX.'
1410  case ('PRINT_CONCENTRATION', 'PRINT_TEMPERATURE')
1411  this%iprconc = 1
1412  write (this%iout, '(4x,a,1x,a,1x,a)') trim(adjustl(this%text))// &
1413  trim(adjustl(this%depvartype))//'S WILL BE PRINTED TO LISTING &
1414  &FILE.'
1415  case ('CONCENTRATION', 'TEMPERATURE')
1416  call this%parser%GetStringCaps(keyword)
1417  if (keyword == 'FILEOUT') then
1418  call this%parser%GetString(fname)
1419  this%iconcout = getunit()
1420  call openfile(this%iconcout, this%iout, fname, 'DATA(BINARY)', &
1421  form, access, 'REPLACE')
1422  write (this%iout, fmtaptbin) &
1423  trim(adjustl(this%text)), trim(adjustl(this%depvartype)), &
1424  trim(fname), this%iconcout
1425  else
1426  write (errmsg, "('Optional', 1x, a, 1X, 'keyword must &
1427  &be followed by FILEOUT')") this%depvartype
1428  call store_error(errmsg)
1429  end if
1430  case ('BUDGET')
1431  call this%parser%GetStringCaps(keyword)
1432  if (keyword == 'FILEOUT') then
1433  call this%parser%GetString(fname)
1434  this%ibudgetout = getunit()
1435  call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', &
1436  form, access, 'REPLACE')
1437  write (this%iout, fmtaptbin) trim(adjustl(this%text)), 'BUDGET', &
1438  trim(fname), this%ibudgetout
1439  else
1440  call store_error('Optional BUDGET keyword must be followed by FILEOUT')
1441  end if
1442  case ('BUDGETCSV')
1443  call this%parser%GetStringCaps(keyword)
1444  if (keyword == 'FILEOUT') then
1445  call this%parser%GetString(fname)
1446  this%ibudcsv = getunit()
1447  call openfile(this%ibudcsv, this%iout, fname, 'CSV', &
1448  filstat_opt='REPLACE')
1449  write (this%iout, fmtaptbin) trim(adjustl(this%text)), 'BUDGET CSV', &
1450  trim(fname), this%ibudcsv
1451  else
1452  call store_error('Optional BUDGETCSV keyword must be followed by &
1453  &FILEOUT')
1454  end if
1455  case default
1456  !
1457  ! -- No options found
1458  found = .false.
1459  end select
1460  !
1461  ! -- Return
1462  return
1463  end subroutine apt_options
1464 
1465  !> @brief Determine dimensions for this advanced package
1466  !<
1467  subroutine apt_read_dimensions(this)
1468  ! -- dummy
1469  class(tspapttype), intent(inout) :: this
1470  ! -- local
1471  integer(I4B) :: ierr
1472  ! -- format
1473  !
1474  ! -- Set a pointer to the GWF LAK Package budobj
1475  if (this%flowpackagename == '') then
1476  this%flowpackagename = this%packName
1477  write (this%iout, '(4x,a)') &
1478  'THE FLOW PACKAGE NAME FOR '//trim(adjustl(this%text))//' WAS NOT &
1479  &SPECIFIED. SETTING FLOW PACKAGE NAME TO '// &
1480  &trim(adjustl(this%flowpackagename))
1481 
1482  end if
1483  call this%find_apt_package()
1484  !
1485  ! -- Set dimensions from the GWF advanced package
1486  this%ncv = this%flowbudptr%ncv
1487  this%maxbound = this%flowbudptr%budterm(this%idxbudgwf)%maxlist
1488  this%nbound = this%maxbound
1489  write (this%iout, '(a, a)') 'SETTING DIMENSIONS FOR PACKAGE ', this%packName
1490  write (this%iout, '(2x,a,i0)') 'NUMBER OF CONTROL VOLUMES = ', this%ncv
1491  write (this%iout, '(2x,a,i0)') 'MAXBOUND = ', this%maxbound
1492  write (this%iout, '(2x,a,i0)') 'NBOUND = ', this%nbound
1493  if (this%imatrows /= 0) then
1494  this%npakeq = this%ncv
1495  write (this%iout, '(2x,a)') trim(adjustl(this%text))// &
1496  ' SOLVED AS PART OF GWT MATRIX EQUATIONS'
1497  else
1498  write (this%iout, '(2x,a)') trim(adjustl(this%text))// &
1499  ' SOLVED SEPARATELY FROM GWT MATRIX EQUATIONS '
1500  end if
1501  write (this%iout, '(a, //)') 'DONE SETTING DIMENSIONS FOR '// &
1502  trim(adjustl(this%text))
1503  !
1504  ! -- Check for errors
1505  if (this%ncv < 0) then
1506  write (errmsg, '(a)') &
1507  'Number of control volumes could not be determined correctly.'
1508  call store_error(errmsg)
1509  end if
1510  !
1511  ! -- stop if errors were encountered in the DIMENSIONS block
1512  ierr = count_errors()
1513  if (ierr > 0) then
1514  call store_error_unit(this%inunit)
1515  end if
1516  !
1517  ! -- read packagedata block
1518  call this%apt_read_cvs()
1519  !
1520  ! -- Call define_listlabel to construct the list label that is written
1521  ! when PRINT_INPUT option is used.
1522  call this%define_listlabel()
1523  !
1524  ! -- setup the budget object
1525  call this%apt_setup_budobj()
1526  !
1527  ! -- setup the conc table object
1528  call this%apt_setup_tableobj()
1529  !
1530  ! -- Return
1531  return
1532  end subroutine apt_read_dimensions
1533 
1534  !> @brief Read feature information for this advanced package
1535  !<
1536  subroutine apt_read_cvs(this)
1537  ! -- modules
1540  ! -- dummy
1541  class(tspapttype), intent(inout) :: this
1542  ! -- local
1543  character(len=LINELENGTH) :: text
1544  character(len=LENBOUNDNAME) :: bndName, bndNameTemp
1545  character(len=9) :: cno
1546  character(len=50), dimension(:), allocatable :: caux
1547  integer(I4B) :: ierr
1548  logical :: isfound, endOfBlock
1549  integer(I4B) :: n
1550  integer(I4B) :: ii, jj
1551  integer(I4B) :: iaux
1552  integer(I4B) :: itmp
1553  integer(I4B) :: nlak
1554  integer(I4B) :: nconn
1555  integer(I4B), dimension(:), pointer, contiguous :: nboundchk
1556  real(DP), pointer :: bndElem => null()
1557  !
1558  ! -- initialize itmp
1559  itmp = 0
1560  !
1561  ! -- allocate apt data
1562  call mem_allocate(this%strt, this%ncv, 'STRT', this%memoryPath)
1563  call mem_allocate(this%ktf, this%ncv, 'KTF', this%memoryPath)
1564  call mem_allocate(this%rfeatthk, this%ncv, 'RFEATTHK', this%memoryPath)
1565  call mem_allocate(this%lauxvar, this%naux, this%ncv, 'LAUXVAR', &
1566  this%memoryPath)
1567  !
1568  ! -- lake boundary and concentrations
1569  if (this%imatrows == 0) then
1570  call mem_allocate(this%iboundpak, this%ncv, 'IBOUND', this%memoryPath)
1571  call mem_allocate(this%xnewpak, this%ncv, 'XNEWPAK', this%memoryPath)
1572  end if
1573  call mem_allocate(this%xoldpak, this%ncv, 'XOLDPAK', this%memoryPath)
1574  !
1575  ! -- allocate character storage not managed by the memory manager
1576  allocate (this%featname(this%ncv)) ! ditch after boundnames allocated??
1577  !allocate(this%status(this%ncv))
1578  !
1579  do n = 1, this%ncv
1580  this%strt(n) = dep20
1581  this%ktf(n) = dzero
1582  this%rfeatthk(n) = dzero
1583  this%lauxvar(:, n) = dzero
1584  this%xoldpak(n) = dep20
1585  if (this%imatrows == 0) then
1586  this%iboundpak(n) = 1
1587  this%xnewpak(n) = dep20
1588  end if
1589  end do
1590  !
1591  ! -- allocate local storage for aux variables
1592  if (this%naux > 0) then
1593  allocate (caux(this%naux))
1594  end if
1595  !
1596  ! -- allocate and initialize temporary variables
1597  allocate (nboundchk(this%ncv))
1598  do n = 1, this%ncv
1599  nboundchk(n) = 0
1600  end do
1601  !
1602  ! -- get packagedata block
1603  call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, &
1604  supportopenclose=.true.)
1605  !
1606  ! -- parse locations block if detected
1607  if (isfound) then
1608  write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// &
1609  ' PACKAGEDATA'
1610  nlak = 0
1611  nconn = 0
1612  do
1613  call this%parser%GetNextLine(endofblock)
1614  if (endofblock) exit
1615  n = this%parser%GetInteger()
1616 
1617  if (n < 1 .or. n > this%ncv) then
1618  write (errmsg, '(a,1x,i6)') &
1619  'Itemno must be > 0 and <= ', this%ncv
1620  call store_error(errmsg)
1621  cycle
1622  end if
1623  !
1624  ! -- increment nboundchk
1625  nboundchk(n) = nboundchk(n) + 1
1626  !
1627  ! -- strt
1628  this%strt(n) = this%parser%GetDouble()
1629  !
1630  ! -- If GWE model, read additional thermal conductivity terms
1631  if (this%depvartype == 'TEMPERATURE') then
1632  ! -- Skip for UZE
1633  if (trim(adjustl(this%text)) /= 'UZE') then
1634  this%ktf(n) = this%parser%GetDouble()
1635  this%rfeatthk(n) = this%parser%GetDouble()
1636  if (this%rfeatthk(n) <= dzero) then
1637  write (errmsg, '(4x,a)') &
1638  '****ERROR. Specified thickness used for thermal &
1639  &conduction MUST BE > 0 else divide by zero error occurs'
1640  call store_error(errmsg)
1641  cycle
1642  end if
1643  end if
1644  end if
1645  !
1646  ! -- get aux data
1647  do iaux = 1, this%naux
1648  call this%parser%GetString(caux(iaux))
1649  end do
1650 
1651  ! -- set default bndName
1652  write (cno, '(i9.9)') n
1653  bndname = 'Feature'//cno
1654 
1655  ! -- featname
1656  if (this%inamedbound /= 0) then
1657  call this%parser%GetStringCaps(bndnametemp)
1658  if (bndnametemp /= '') then
1659  bndname = bndnametemp
1660  end if
1661  end if
1662  this%featname(n) = bndname
1663 
1664  ! -- fill time series aware data
1665  ! -- fill aux data
1666  do jj = 1, this%naux
1667  text = caux(jj)
1668  ii = n
1669  bndelem => this%lauxvar(jj, ii)
1670  call read_value_or_time_series_adv(text, ii, jj, bndelem, &
1671  this%packName, 'AUX', &
1672  this%tsManager, this%iprpak, &
1673  this%auxname(jj))
1674  end do
1675  !
1676  nlak = nlak + 1
1677  end do
1678  !
1679  ! -- check for duplicate or missing lakes
1680  do n = 1, this%ncv
1681  if (nboundchk(n) == 0) then
1682  write (errmsg, '(a,1x,i0)') 'No data specified for feature', n
1683  call store_error(errmsg)
1684  else if (nboundchk(n) > 1) then
1685  write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a)') &
1686  'Data for feature', n, 'specified', nboundchk(n), 'times'
1687  call store_error(errmsg)
1688  end if
1689  end do
1690  !
1691  write (this%iout, '(1x,a)') &
1692  'END OF '//trim(adjustl(this%text))//' PACKAGEDATA'
1693  else
1694  call store_error('Required packagedata block not found.')
1695  end if
1696  !
1697  ! -- terminate if any errors were detected
1698  if (count_errors() > 0) then
1699  call this%parser%StoreErrorUnit()
1700  end if
1701  !
1702  ! -- deallocate local storage for aux variables
1703  if (this%naux > 0) then
1704  deallocate (caux)
1705  end if
1706  !
1707  ! -- deallocate local storage for nboundchk
1708  deallocate (nboundchk)
1709  !
1710  ! -- Return
1711  return
1712  end subroutine apt_read_cvs
1713 
1714  !> @brief Read the initial parameters for an advanced package
1715  !<
1716  subroutine apt_read_initial_attr(this)
1717  use constantsmodule, only: linelength
1718  use budgetmodule, only: budget_cr
1719  ! -- dummy
1720  class(tspapttype), intent(inout) :: this
1721  ! -- local
1722  !character(len=LINELENGTH) :: text
1723  integer(I4B) :: j, n
1724 
1725  !
1726  ! -- initialize xnewpak and set feature concentration (or temperature)
1727  ! -- todo: this should be a time series?
1728  do n = 1, this%ncv
1729  this%xnewpak(n) = this%strt(n)
1730  !
1731  ! -- todo: read aux
1732  !
1733  ! -- todo: read boundname
1734  end do
1735  !
1736  ! -- initialize status (iboundpak) of lakes to active
1737  do n = 1, this%ncv
1738  if (this%status(n) == 'CONSTANT') then
1739  this%iboundpak(n) = -1
1740  else if (this%status(n) == 'INACTIVE') then
1741  this%iboundpak(n) = 0
1742  else if (this%status(n) == 'ACTIVE ') then
1743  this%iboundpak(n) = 1
1744  end if
1745  end do
1746  !
1747  ! -- set boundname for each connection
1748  if (this%inamedbound /= 0) then
1749  do j = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
1750  n = this%flowbudptr%budterm(this%idxbudgwf)%id1(j)
1751  this%boundname(j) = this%featname(n)
1752  end do
1753  end if
1754  !
1755  ! -- copy boundname into boundname_cst
1756  call this%copy_boundname()
1757  !
1758  ! -- Return
1759  return
1760  end subroutine apt_read_initial_attr
1761 
1762  !> @brief Add terms specific to advanced package transport to the explicit
1763  !! solve
1764  !!
1765  !! Explicit solve for concentration (or temperature) in advaced package
1766  !! features, which is an alternative to the iterative implicit solve.
1767  !<
1768  subroutine apt_solve(this)
1769  use constantsmodule, only: linelength
1770  ! -- dummy
1771  class(tspapttype) :: this
1772  ! -- local
1773  integer(I4B) :: n, j, igwfnode
1774  integer(I4B) :: n1, n2
1775  real(DP) :: rrate
1776  real(DP) :: ctmp
1777  real(DP) :: c1, qbnd
1778  real(DP) :: hcofval, rhsval
1779  !
1780  ! -- initialize dbuff
1781  do n = 1, this%ncv
1782  this%dbuff(n) = dzero
1783  end do
1784  !
1785  ! -- call the individual package routines to add terms specific to the
1786  ! advanced transport package
1787  call this%pak_solve()
1788  !
1789  ! -- add to mover contribution
1790  if (this%idxbudtmvr /= 0) then
1791  do j = 1, this%flowbudptr%budterm(this%idxbudtmvr)%nlist
1792  call this%apt_tmvr_term(j, n1, n2, rrate)
1793  this%dbuff(n1) = this%dbuff(n1) + rrate
1794  end do
1795  end if
1796  !
1797  ! -- add from mover contribution
1798  if (this%idxbudfmvr /= 0) then
1799  do n1 = 1, size(this%qmfrommvr)
1800  rrate = this%qmfrommvr(n1) ! Will be in terms of energy for heat transport
1801  this%dbuff(n1) = this%dbuff(n1) + rrate
1802  end do
1803  end if
1804  !
1805  ! -- go through each gwf connection and accumulate
1806  ! total mass (or energy) in dbuff mass
1807  do j = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
1808  n = this%flowbudptr%budterm(this%idxbudgwf)%id1(j)
1809  this%hcof(j) = dzero
1810  this%rhs(j) = dzero
1811  igwfnode = this%flowbudptr%budterm(this%idxbudgwf)%id2(j)
1812  qbnd = this%flowbudptr%budterm(this%idxbudgwf)%flow(j)
1813  if (qbnd <= dzero) then
1814  ctmp = this%xnewpak(n)
1815  this%rhs(j) = qbnd * ctmp * this%eqnsclfac
1816  else
1817  ctmp = this%xnew(igwfnode)
1818  this%hcof(j) = -qbnd * this%eqnsclfac
1819  end if
1820  c1 = qbnd * ctmp * this%eqnsclfac
1821  this%dbuff(n) = this%dbuff(n) + c1
1822  end do
1823  !
1824  ! -- go through each "within apt-apt" connection (e.g., lak-lak) and
1825  ! accumulate total mass (or energy) in dbuff mass
1826  if (this%idxbudfjf /= 0) then
1827  do j = 1, this%flowbudptr%budterm(this%idxbudfjf)%nlist
1828  call this%apt_fjf_term(j, n1, n2, rrate)
1829  c1 = rrate
1830  this%dbuff(n1) = this%dbuff(n1) + c1
1831  end do
1832  end if
1833  !
1834  ! -- calculate the feature concentration/temperature
1835  do n = 1, this%ncv
1836  call this%apt_stor_term(n, n1, n2, rrate, rhsval, hcofval)
1837  !
1838  ! -- at this point, dbuff has q * c for all sources, so now
1839  ! add Vold / dt * Cold
1840  this%dbuff(n) = this%dbuff(n) - rhsval
1841  !
1842  ! -- Now to calculate c, need to divide dbuff by hcofval
1843  c1 = -this%dbuff(n) / hcofval
1844  if (this%iboundpak(n) > 0) then
1845  this%xnewpak(n) = c1
1846  end if
1847  end do
1848  !
1849  ! -- Return
1850  return
1851  end subroutine apt_solve
1852 
1853  !> @brief Add terms specific to advanced package transport features to the
1854  !! explicit solve routine
1855  !!
1856  !! This routine must be overridden by the specific apt package
1857  !<
1858  subroutine pak_solve(this)
1859  ! -- dummy
1860  class(tspapttype) :: this
1861  ! -- local
1862  !
1863  ! -- this routine should never be called
1864  call store_error('Program error: pak_solve not implemented.', &
1865  terminate=.true.)
1866  !
1867  ! -- Return
1868  return
1869  end subroutine pak_solve
1870 
1871  !> @brief Accumulate constant concentration (or temperature) terms for budget
1872  !<
1873  subroutine apt_accumulate_ccterm(this, ilak, rrate, ccratin, ccratout)
1874  ! -- dummy
1875  class(tspapttype) :: this
1876  integer(I4B), intent(in) :: ilak
1877  real(DP), intent(in) :: rrate
1878  real(DP), intent(inout) :: ccratin
1879  real(DP), intent(inout) :: ccratout
1880  ! -- locals
1881  real(DP) :: q
1882  ! format
1883  ! code
1884  !
1885  if (this%iboundpak(ilak) < 0) then
1886  q = -rrate
1887  this%ccterm(ilak) = this%ccterm(ilak) + q
1888  !
1889  ! -- See if flow is into lake or out of lake.
1890  if (q < dzero) then
1891  !
1892  ! -- Flow is out of lake subtract rate from ratout.
1893  ccratout = ccratout - q
1894  else
1895  !
1896  ! -- Flow is into lake; add rate to ratin.
1897  ccratin = ccratin + q
1898  end if
1899  end if
1900  !
1901  ! -- Return
1902  return
1903  end subroutine apt_accumulate_ccterm
1904 
1905  !> @brief Define the list heading that is written to iout when PRINT_INPUT
1906  !! option is used.
1907  !<
1908  subroutine define_listlabel(this)
1909  class(tspapttype), intent(inout) :: this
1910  !
1911  ! -- create the header list label
1912  this%listlabel = trim(this%filtyp)//' NO.'
1913  if (this%dis%ndim == 3) then
1914  write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER'
1915  write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW'
1916  write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL'
1917  elseif (this%dis%ndim == 2) then
1918  write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER'
1919  write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D'
1920  else
1921  write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE'
1922  end if
1923  write (this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE'
1924  if (this%inamedbound == 1) then
1925  write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME'
1926  end if
1927  !
1928  ! -- Return
1929  return
1930  end subroutine define_listlabel
1931 
1932  !> @brief Set pointers to model arrays and variables so that a package has
1933  !! access to these items.
1934  !<
1935  subroutine apt_set_pointers(this, neq, ibound, xnew, xold, flowja)
1936  class(tspapttype) :: this
1937  integer(I4B), pointer :: neq
1938  integer(I4B), dimension(:), pointer, contiguous :: ibound
1939  real(DP), dimension(:), pointer, contiguous :: xnew
1940  real(DP), dimension(:), pointer, contiguous :: xold
1941  real(DP), dimension(:), pointer, contiguous :: flowja
1942  ! -- local
1943  integer(I4B) :: istart, iend
1944  !
1945  ! -- call base BndType set_pointers
1946  call this%BndType%set_pointers(neq, ibound, xnew, xold, flowja)
1947  !
1948  ! -- Set the pointers
1949  !
1950  ! -- set package pointers
1951  if (this%imatrows /= 0) then
1952  istart = this%dis%nodes + this%ioffset + 1
1953  iend = istart + this%ncv - 1
1954  this%iboundpak => this%ibound(istart:iend)
1955  this%xnewpak => this%xnew(istart:iend)
1956  end if
1957  !
1958  ! -- Return
1959  return
1960  end subroutine apt_set_pointers
1961 
1962  !> @brief Return the feature new volume and old volume
1963  !<
1964  subroutine get_volumes(this, icv, vnew, vold, delt)
1965  ! -- modules
1966  ! -- dummy
1967  class(tspapttype) :: this
1968  integer(I4B), intent(in) :: icv
1969  real(DP), intent(inout) :: vnew, vold
1970  real(DP), intent(in) :: delt
1971  ! -- local
1972  real(DP) :: qss
1973  !
1974  ! -- get volumes
1975  vold = dzero
1976  vnew = vold
1977  if (this%idxbudsto /= 0) then
1978  qss = this%flowbudptr%budterm(this%idxbudsto)%flow(icv)
1979  vnew = this%flowbudptr%budterm(this%idxbudsto)%auxvar(1, icv)
1980  vold = vnew + qss * delt
1981  end if
1982  !
1983  ! -- Return
1984  return
1985  end subroutine get_volumes
1986 
1987  !> @brief Function to return the number of budget terms just for this package
1988  !!
1989  !! This function must be overridden.
1990  !<
1991  function pak_get_nbudterms(this) result(nbudterms)
1992  ! -- modules
1993  ! -- dummy
1994  class(tspapttype) :: this
1995  ! -- return
1996  integer(I4B) :: nbudterms
1997  ! -- local
1998  !
1999  ! -- this routine should never be called
2000  call store_error('Program error: pak_get_nbudterms not implemented.', &
2001  terminate=.true.)
2002  nbudterms = 0
2003  !
2004  ! -- Return
2005  return
2006  end function pak_get_nbudterms
2007 
2008  !> @brief Set up the budget object that stores advanced package flow terms
2009  !<
2010  subroutine apt_setup_budobj(this)
2011  ! -- modules
2012  use constantsmodule, only: lenbudtxt
2013  ! -- dummy
2014  class(tspapttype) :: this
2015  ! -- local
2016  integer(I4B) :: nbudterm
2017  integer(I4B) :: nlen
2018  integer(I4B) :: n, n1, n2
2019  integer(I4B) :: maxlist, naux
2020  integer(I4B) :: idx
2021  logical :: ordered_id1
2022  real(DP) :: q
2023  character(len=LENBUDTXT) :: bddim_opt
2024  character(len=LENBUDTXT) :: text, textt
2025  character(len=LENBUDTXT), dimension(1) :: auxtxt
2026  !
2027  ! -- initialize nbudterm
2028  nbudterm = 0
2029  !
2030  ! -- Determine if there are flow-ja-face terms
2031  nlen = 0
2032  if (this%idxbudfjf /= 0) then
2033  nlen = this%flowbudptr%budterm(this%idxbudfjf)%maxlist
2034  end if
2035  !
2036  ! -- Determine the number of budget terms associated with apt.
2037  ! These are fixed for the simulation and cannot change
2038  !
2039  ! -- add one if flow-ja-face present
2040  if (this%idxbudfjf /= 0) nbudterm = nbudterm + 1
2041  !
2042  ! -- All the APT packages have GWF, STORAGE, and CONSTANT
2043  nbudterm = nbudterm + 3
2044  !
2045  ! -- add terms for the specific package
2046  nbudterm = nbudterm + this%pak_get_nbudterms()
2047  !
2048  ! -- add for mover terms and auxiliary
2049  if (this%idxbudtmvr /= 0) nbudterm = nbudterm + 1
2050  if (this%idxbudfmvr /= 0) nbudterm = nbudterm + 1
2051  if (this%naux > 0) nbudterm = nbudterm + 1
2052  !
2053  ! -- set up budobj
2054  call budgetobject_cr(this%budobj, this%packName)
2055  !
2056  bddim_opt = this%depvarunitabbrev
2057  call this%budobj%budgetobject_df(this%ncv, nbudterm, 0, 0, &
2058  bddim_opt=bddim_opt, ibudcsv=this%ibudcsv)
2059  idx = 0
2060  !
2061  ! -- Go through and set up each budget term
2062  if (nlen > 0) then
2063  text = ' FLOW-JA-FACE'
2064  idx = idx + 1
2065  maxlist = this%flowbudptr%budterm(this%idxbudfjf)%maxlist
2066  naux = 0
2067  ordered_id1 = this%flowbudptr%budterm(this%idxbudfjf)%ordered_id1
2068  call this%budobj%budterm(idx)%initialize(text, &
2069  this%name_model, &
2070  this%packName, &
2071  this%name_model, &
2072  this%packName, &
2073  maxlist, .false., .false., &
2074  naux, ordered_id1=ordered_id1)
2075  !
2076  ! -- store outlet connectivity
2077  call this%budobj%budterm(idx)%reset(maxlist)
2078  q = dzero
2079  do n = 1, maxlist
2080  n1 = this%flowbudptr%budterm(this%idxbudfjf)%id1(n)
2081  n2 = this%flowbudptr%budterm(this%idxbudfjf)%id2(n)
2082  call this%budobj%budterm(idx)%update_term(n1, n2, q)
2083  end do
2084  end if
2085  !
2086  ! --
2087  text = ' GWF'
2088  idx = idx + 1
2089  maxlist = this%flowbudptr%budterm(this%idxbudgwf)%maxlist
2090  naux = 0
2091  call this%budobj%budterm(idx)%initialize(text, &
2092  this%name_model, &
2093  this%packName, &
2094  this%name_model, &
2095  this%name_model, &
2096  maxlist, .false., .true., &
2097  naux)
2098  call this%budobj%budterm(idx)%reset(maxlist)
2099  q = dzero
2100  do n = 1, maxlist
2101  n1 = this%flowbudptr%budterm(this%idxbudgwf)%id1(n)
2102  n2 = this%flowbudptr%budterm(this%idxbudgwf)%id2(n)
2103  call this%budobj%budterm(idx)%update_term(n1, n2, q)
2104  end do
2105  !
2106  ! -- Reserve space for the package specific terms
2107  this%idxprepak = idx
2108  call this%pak_setup_budobj(idx)
2109  this%idxlastpak = idx
2110  !
2111  ! --
2112  text = ' STORAGE'
2113  idx = idx + 1
2114  maxlist = this%flowbudptr%budterm(this%idxbudsto)%maxlist
2115  naux = 1
2116  write (textt, '(a)') str_pad_left(this%depvarunit, 16)
2117  auxtxt(1) = textt ! ' MASS' or ' ENERGY'
2118  call this%budobj%budterm(idx)%initialize(text, &
2119  this%name_model, &
2120  this%packName, &
2121  this%name_model, &
2122  this%packName, &
2123  maxlist, .false., .false., &
2124  naux, auxtxt)
2125  if (this%idxbudtmvr /= 0) then
2126  !
2127  ! --
2128  text = ' TO-MVR'
2129  idx = idx + 1
2130  maxlist = this%flowbudptr%budterm(this%idxbudtmvr)%maxlist
2131  naux = 0
2132  ordered_id1 = this%flowbudptr%budterm(this%idxbudtmvr)%ordered_id1
2133  call this%budobj%budterm(idx)%initialize(text, &
2134  this%name_model, &
2135  this%packName, &
2136  this%name_model, &
2137  this%packName, &
2138  maxlist, .false., .false., &
2139  naux, ordered_id1=ordered_id1)
2140  end if
2141  if (this%idxbudfmvr /= 0) then
2142  !
2143  ! --
2144  text = ' FROM-MVR'
2145  idx = idx + 1
2146  maxlist = this%ncv
2147  naux = 0
2148  call this%budobj%budterm(idx)%initialize(text, &
2149  this%name_model, &
2150  this%packName, &
2151  this%name_model, &
2152  this%packName, &
2153  maxlist, .false., .false., &
2154  naux)
2155  end if
2156  !
2157  ! --
2158  text = ' CONSTANT'
2159  idx = idx + 1
2160  maxlist = this%ncv
2161  naux = 0
2162  call this%budobj%budterm(idx)%initialize(text, &
2163  this%name_model, &
2164  this%packName, &
2165  this%name_model, &
2166  this%packName, &
2167  maxlist, .false., .false., &
2168  naux)
2169 
2170  !
2171  ! --
2172  naux = this%naux
2173  if (naux > 0) then
2174  !
2175  ! --
2176  text = ' AUXILIARY'
2177  idx = idx + 1
2178  maxlist = this%ncv
2179  call this%budobj%budterm(idx)%initialize(text, &
2180  this%name_model, &
2181  this%packName, &
2182  this%name_model, &
2183  this%packName, &
2184  maxlist, .false., .false., &
2185  naux, this%auxname)
2186  end if
2187  !
2188  ! -- if flow for each control volume are written to the listing file
2189  if (this%iprflow /= 0) then
2190  call this%budobj%flowtable_df(this%iout)
2191  end if
2192  !
2193  ! -- Return
2194  return
2195  end subroutine apt_setup_budobj
2196 
2197  !> @brief Set up a budget object that stores an advanced package flows
2198  !!
2199  !! Individual packages set up their budget terms. Must be overridden.
2200  !<
2201  subroutine pak_setup_budobj(this, idx)
2202  ! -- modules
2203  ! -- dummy
2204  class(tspapttype) :: this
2205  integer(I4B), intent(inout) :: idx
2206  ! -- local
2207  !
2208  ! -- this routine should never be called
2209  call store_error('Program error: pak_setup_budobj not implemented.', &
2210  terminate=.true.)
2211  !
2212  ! -- Return
2213  return
2214  end subroutine pak_setup_budobj
2215 
2216  !> @brief Copy flow terms into this%budobj
2217  !<
2218  subroutine apt_fill_budobj(this, x, flowja)
2219  ! -- modules
2220  use tdismodule, only: delt
2221  ! -- dummy
2222  class(tspapttype) :: this
2223  real(DP), dimension(:), intent(in) :: x
2224  real(DP), dimension(:), contiguous, intent(inout) :: flowja
2225  ! -- local
2226  integer(I4B) :: naux
2227  real(DP), dimension(:), allocatable :: auxvartmp
2228  integer(I4B) :: i, j, n1, n2
2229  integer(I4B) :: idx
2230  integer(I4B) :: nlen
2231  integer(I4B) :: nlist
2232  integer(I4B) :: igwfnode
2233  real(DP) :: q
2234  real(DP) :: v0, v1
2235  real(DP) :: ccratin, ccratout
2236  ! -- formats
2237  !
2238  ! -- initialize counter
2239  idx = 0
2240  !
2241  ! -- initialize ccterm, which is used to sum up all mass (or energy) flows
2242  ! into a constant concentration (or temperature) cell
2243  ccratin = dzero
2244  ccratout = dzero
2245  do n1 = 1, this%ncv
2246  this%ccterm(n1) = dzero
2247  end do
2248  !
2249  ! -- FLOW JA FACE
2250  nlen = 0
2251  if (this%idxbudfjf /= 0) then
2252  nlen = this%flowbudptr%budterm(this%idxbudfjf)%maxlist
2253  end if
2254  if (nlen > 0) then
2255  idx = idx + 1
2256  nlist = this%flowbudptr%budterm(this%idxbudfjf)%maxlist
2257  call this%budobj%budterm(idx)%reset(nlist)
2258  q = dzero
2259  do j = 1, nlist
2260  call this%apt_fjf_term(j, n1, n2, q)
2261  call this%budobj%budterm(idx)%update_term(n1, n2, q)
2262  call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout)
2263  end do
2264  end if
2265  !
2266  ! -- GWF (LEAKAGE)
2267  idx = idx + 1
2268  call this%budobj%budterm(idx)%reset(this%maxbound)
2269  do j = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
2270  q = dzero
2271  n1 = this%flowbudptr%budterm(this%idxbudgwf)%id1(j)
2272  if (this%iboundpak(n1) /= 0) then
2273  igwfnode = this%flowbudptr%budterm(this%idxbudgwf)%id2(j)
2274  q = this%hcof(j) * x(igwfnode) - this%rhs(j)
2275  q = -q ! flip sign so relative to advanced package feature
2276  end if
2277  call this%budobj%budterm(idx)%update_term(n1, igwfnode, q)
2278  call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout)
2279  end do
2280  !
2281  ! -- skip individual package terms for now and process them last
2282  ! -- in case they depend on the other terms (as for uze)
2283  idx = this%idxlastpak
2284  !
2285  ! -- STORAGE
2286  idx = idx + 1
2287  call this%budobj%budterm(idx)%reset(this%ncv)
2288  allocate (auxvartmp(1))
2289  do n1 = 1, this%ncv
2290  call this%get_volumes(n1, v1, v0, delt)
2291  auxvartmp(1) = v1 * this%xnewpak(n1) ! Note: When GWE is added, check if this needs a factor of eqnsclfac
2292  q = this%qsto(n1)
2293  call this%budobj%budterm(idx)%update_term(n1, n1, q, auxvartmp)
2294  call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout)
2295  end do
2296  deallocate (auxvartmp)
2297  !
2298  ! -- TO MOVER
2299  if (this%idxbudtmvr /= 0) then
2300  idx = idx + 1
2301  nlist = this%flowbudptr%budterm(this%idxbudtmvr)%nlist
2302  call this%budobj%budterm(idx)%reset(nlist)
2303  do j = 1, nlist
2304  call this%apt_tmvr_term(j, n1, n2, q)
2305  call this%budobj%budterm(idx)%update_term(n1, n2, q)
2306  call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout)
2307  end do
2308  end if
2309  !
2310  ! -- FROM MOVER
2311  if (this%idxbudfmvr /= 0) then
2312  idx = idx + 1
2313  nlist = this%ncv
2314  call this%budobj%budterm(idx)%reset(nlist)
2315  do j = 1, nlist
2316  call this%apt_fmvr_term(j, n1, n2, q)
2317  call this%budobj%budterm(idx)%update_term(n1, n1, q)
2318  call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout)
2319  end do
2320  end if
2321  !
2322  ! -- CONSTANT FLOW
2323  idx = idx + 1
2324  call this%budobj%budterm(idx)%reset(this%ncv)
2325  do n1 = 1, this%ncv
2326  q = this%ccterm(n1)
2327  call this%budobj%budterm(idx)%update_term(n1, n1, q)
2328  end do
2329  !
2330  ! -- AUXILIARY VARIABLES
2331  naux = this%naux
2332  if (naux > 0) then
2333  idx = idx + 1
2334  allocate (auxvartmp(naux))
2335  call this%budobj%budterm(idx)%reset(this%ncv)
2336  do n1 = 1, this%ncv
2337  q = dzero
2338  do i = 1, naux
2339  auxvartmp(i) = this%lauxvar(i, n1)
2340  end do
2341  call this%budobj%budterm(idx)%update_term(n1, n1, q, auxvartmp)
2342  end do
2343  deallocate (auxvartmp)
2344  end if
2345  !
2346  ! -- individual package terms processed last
2347  idx = this%idxprepak
2348  call this%pak_fill_budobj(idx, x, flowja, ccratin, ccratout)
2349  !
2350  ! --Terms are filled, now accumulate them for this time step
2351  call this%budobj%accumulate_terms()
2352  !
2353  ! -- Return
2354  return
2355  end subroutine apt_fill_budobj
2356 
2357  !> @brief Copy flow terms into this%budobj, must be overridden
2358  !<
2359  subroutine pak_fill_budobj(this, idx, x, flowja, ccratin, ccratout)
2360  ! -- modules
2361  ! -- dummy
2362  class(tspapttype) :: this
2363  integer(I4B), intent(inout) :: idx
2364  real(DP), dimension(:), intent(in) :: x
2365  real(DP), dimension(:), contiguous, intent(inout) :: flowja
2366  real(DP), intent(inout) :: ccratin
2367  real(DP), intent(inout) :: ccratout
2368  ! -- local
2369  ! -- formats
2370  !
2371  ! -- this routine should never be called
2372  call store_error('Program error: pak_fill_budobj not implemented.', &
2373  terminate=.true.)
2374  !
2375  ! -- Return
2376  return
2377  end subroutine pak_fill_budobj
2378 
2379  !> @brief Account for mass or energy storage in advanced package features
2380  !<
2381  subroutine apt_stor_term(this, ientry, n1, n2, rrate, &
2382  rhsval, hcofval)
2383  use tdismodule, only: delt
2384  class(tspapttype) :: this
2385  integer(I4B), intent(in) :: ientry
2386  integer(I4B), intent(inout) :: n1
2387  integer(I4B), intent(inout) :: n2
2388  real(DP), intent(inout), optional :: rrate
2389  real(DP), intent(inout), optional :: rhsval
2390  real(DP), intent(inout), optional :: hcofval
2391  real(DP) :: v0, v1
2392  real(DP) :: c0, c1
2393  !
2394  n1 = ientry
2395  n2 = ientry
2396  call this%get_volumes(n1, v1, v0, delt)
2397  c0 = this%xoldpak(n1)
2398  c1 = this%xnewpak(n1)
2399  if (present(rrate)) then
2400  rrate = (-c1 * v1 / delt + c0 * v0 / delt) * this%eqnsclfac
2401  end if
2402  if (present(rhsval)) rhsval = -c0 * v0 * this%eqnsclfac / delt
2403  if (present(hcofval)) hcofval = -v1 * this%eqnsclfac / delt
2404  !
2405  ! -- Return
2406  return
2407  end subroutine apt_stor_term
2408 
2409  !> @brief Account for mass or energy transferred to the MVR package
2410  !<
2411  subroutine apt_tmvr_term(this, ientry, n1, n2, rrate, &
2412  rhsval, hcofval)
2413  ! -- modules
2414  ! -- dummy
2415  class(tspapttype) :: this
2416  integer(I4B), intent(in) :: ientry
2417  integer(I4B), intent(inout) :: n1
2418  integer(I4B), intent(inout) :: n2
2419  real(DP), intent(inout), optional :: rrate
2420  real(DP), intent(inout), optional :: rhsval
2421  real(DP), intent(inout), optional :: hcofval
2422  ! -- local
2423  real(DP) :: qbnd
2424  real(DP) :: ctmp
2425  !
2426  ! -- Calculate MVR-related terms
2427  n1 = this%flowbudptr%budterm(this%idxbudtmvr)%id1(ientry)
2428  n2 = this%flowbudptr%budterm(this%idxbudtmvr)%id2(ientry)
2429  qbnd = this%flowbudptr%budterm(this%idxbudtmvr)%flow(ientry)
2430  ctmp = this%xnewpak(n1)
2431  if (present(rrate)) rrate = ctmp * qbnd * this%eqnsclfac
2432  if (present(rhsval)) rhsval = dzero
2433  if (present(hcofval)) hcofval = qbnd * this%eqnsclfac
2434  !
2435  ! -- Return
2436  return
2437  end subroutine apt_tmvr_term
2438 
2439  !> @brief Account for mass or energy transferred to this package from the
2440  !! MVR package
2441  !<
2442  subroutine apt_fmvr_term(this, ientry, n1, n2, rrate, &
2443  rhsval, hcofval)
2444  ! -- modules
2445  ! -- dummy
2446  class(tspapttype) :: this
2447  integer(I4B), intent(in) :: ientry
2448  integer(I4B), intent(inout) :: n1
2449  integer(I4B), intent(inout) :: n2
2450  real(DP), intent(inout), optional :: rrate
2451  real(DP), intent(inout), optional :: rhsval
2452  real(DP), intent(inout), optional :: hcofval
2453  !
2454  ! -- Calculate MVR-related terms
2455  n1 = ientry
2456  n2 = n1
2457  if (present(rrate)) rrate = this%qmfrommvr(n1) ! NOTE: When bringing in GWE, ensure this is in terms of energy. Might need to apply eqnsclfac here.
2458  if (present(rhsval)) rhsval = this%qmfrommvr(n1)
2459  if (present(hcofval)) hcofval = dzero
2460  !
2461  ! -- Return
2462  return
2463  end subroutine apt_fmvr_term
2464 
2465  !> @brief Go through each "within apt-apt" connection (e.g., lkt-lkt, or
2466  !! sft-sft) and accumulate total mass (or energy) in dbuff mass
2467  !<
2468  subroutine apt_fjf_term(this, ientry, n1, n2, rrate, &
2469  rhsval, hcofval)
2470  ! -- modules
2471  ! -- dummy
2472  class(tspapttype) :: this
2473  integer(I4B), intent(in) :: ientry
2474  integer(I4B), intent(inout) :: n1
2475  integer(I4B), intent(inout) :: n2
2476  real(DP), intent(inout), optional :: rrate
2477  real(DP), intent(inout), optional :: rhsval
2478  real(DP), intent(inout), optional :: hcofval
2479  ! -- local
2480  real(DP) :: qbnd
2481  real(DP) :: ctmp
2482  !
2483  n1 = this%flowbudptr%budterm(this%idxbudfjf)%id1(ientry)
2484  n2 = this%flowbudptr%budterm(this%idxbudfjf)%id2(ientry)
2485  qbnd = this%flowbudptr%budterm(this%idxbudfjf)%flow(ientry)
2486  if (qbnd <= 0) then
2487  ctmp = this%xnewpak(n1)
2488  else
2489  ctmp = this%xnewpak(n2)
2490  end if
2491  if (present(rrate)) rrate = ctmp * qbnd * this%eqnsclfac
2492  if (present(rhsval)) rhsval = -rrate * this%eqnsclfac
2493  if (present(hcofval)) hcofval = dzero
2494  !
2495  ! -- Return
2496  return
2497  end subroutine apt_fjf_term
2498 
2499  !> @brief Copy concentrations (or temperatures) into flow package aux
2500  !! variable
2501  !<
2502  subroutine apt_copy2flowp(this)
2503  ! -- modules
2504  ! -- dummy
2505  class(tspapttype) :: this
2506  ! -- local
2507  integer(I4B) :: n, j
2508  !
2509  ! -- copy
2510  if (this%iauxfpconc /= 0) then
2511  !
2512  ! -- go through each apt-gwf connection
2513  do j = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist
2514  !
2515  ! -- set n to feature number and process if active feature
2516  n = this%flowbudptr%budterm(this%idxbudgwf)%id1(j)
2517  this%flowpackagebnd%auxvar(this%iauxfpconc, j) = this%xnewpak(n)
2518  end do
2519  end if
2520  !
2521  ! -- Return
2522  return
2523  end subroutine apt_copy2flowp
2524 
2525  !> @brief Determine whether an obs type is supported
2526  !!
2527  !! This function:
2528  !! - returns true if APT package supports named observation.
2529  !! - overrides BndType%bnd_obs_supported()
2530  !<
2531  logical function apt_obs_supported(this)
2532  ! -- modules
2533  ! -- dummy
2534  class(tspapttype) :: this
2535  !
2536  ! -- Set to true
2537  apt_obs_supported = .true.
2538  !
2539  ! -- Return
2540  return
2541  end function apt_obs_supported
2542 
2543  !> @brief Define observation type
2544  !!
2545  !! This routine:
2546  !! - stores observation types supported by APT package.
2547  !! - overrides BndType%bnd_df_obs
2548  !<
2549  subroutine apt_df_obs(this)
2550  ! -- modules
2551  ! -- dummy
2552  class(tspapttype) :: this
2553  ! -- local
2554  !
2555  ! -- call additional specific observations for lkt, sft, mwt, and uzt
2556  call this%pak_df_obs()
2557  !
2558  ! -- Return
2559  return
2560  end subroutine apt_df_obs
2561 
2562  !> @brief Define apt observation type
2563  !!
2564  !! This routine:
2565  !! - stores observations supported by the APT package
2566  !! - must be overridden by child class
2567  subroutine pak_df_obs(this)
2568  ! -- modules
2569  ! -- dummy
2570  class(tspapttype) :: this
2571  ! -- local
2572  !
2573  ! -- this routine should never be called
2574  call store_error('Program error: pak_df_obs not implemented.', &
2575  terminate=.true.)
2576  !
2577  ! -- Return
2578  return
2579  end subroutine pak_df_obs
2580 
2581  !> @brief Process package specific obs
2582  !!
2583  !! Method to process specific observations for this package.
2584  !<
2585  subroutine pak_rp_obs(this, obsrv, found)
2586  ! -- dummy
2587  class(tspapttype), intent(inout) :: this !< package class
2588  type(observetype), intent(inout) :: obsrv !< observation object
2589  logical, intent(inout) :: found !< indicate whether observation was found
2590  ! -- local
2591  !
2592  ! -- this routine should never be called
2593  call store_error('Program error: pak_rp_obs not implemented.', &
2594  terminate=.true.)
2595  !
2596  ! -- Return
2597  return
2598  end subroutine pak_rp_obs
2599 
2600  !> @brief Prepare observation
2601  !!
2602  !! Find the indices for this observation assuming they are indexed by
2603  !! feature number
2604  !<
2605  subroutine rp_obs_byfeature(this, obsrv)
2606  class(tspapttype), intent(inout) :: this !< object
2607  type(observetype), intent(inout) :: obsrv !< observation
2608  integer(I4B) :: nn1
2609  integer(I4B) :: j
2610  logical :: jfound
2611  character(len=*), parameter :: fmterr = &
2612  "('Boundary ', a, ' for observation ', a, &
2613  &' is invalid in package ', a)"
2614  nn1 = obsrv%NodeNumber
2615  if (nn1 == namedboundflag) then
2616  jfound = .false.
2617  do j = 1, this%ncv
2618  if (this%featname(j) == obsrv%FeatureName) then
2619  jfound = .true.
2620  call obsrv%AddObsIndex(j)
2621  end if
2622  end do
2623  if (.not. jfound) then
2624  write (errmsg, fmterr) trim(obsrv%FeatureName), trim(obsrv%Name), &
2625  trim(this%packName)
2626  call store_error(errmsg)
2627  end if
2628  else
2629  !
2630  ! -- ensure nn1 is > 0 and < ncv
2631  if (nn1 < 0 .or. nn1 > this%ncv) then
2632  write (errmsg, '(7a, i0, a, i0, a)') &
2633  'Observation ', trim(obsrv%Name), ' of type ', &
2634  trim(adjustl(obsrv%ObsTypeId)), ' in package ', &
2635  trim(this%packName), ' was assigned ID = ', nn1, &
2636  '. ID must be >= 1 and <= ', this%ncv, '.'
2637  call store_error(errmsg)
2638  end if
2639  call obsrv%AddObsIndex(nn1)
2640  end if
2641  !
2642  ! -- Return
2643  return
2644  end subroutine rp_obs_byfeature
2645 
2646  !> @brief Prepare observation
2647  !!
2648  !! Find the indices for this observation assuming they are first indexed
2649  !! by feature number and secondly by a connection number
2650  !<
2651  subroutine rp_obs_budterm(this, obsrv, budterm)
2652  class(tspapttype), intent(inout) :: this !< object
2653  type(observetype), intent(inout) :: obsrv !< observation
2654  type(budgettermtype), intent(in) :: budterm !< budget term
2655  integer(I4B) :: nn1
2656  integer(I4B) :: iconn
2657  integer(I4B) :: icv
2658  integer(I4B) :: idx
2659  integer(I4B) :: j
2660  logical :: jfound
2661  character(len=*), parameter :: fmterr = &
2662  "('Boundary ', a, ' for observation ', a, &
2663  &' is invalid in package ', a)"
2664  nn1 = obsrv%NodeNumber
2665  if (nn1 == namedboundflag) then
2666  jfound = .false.
2667  do j = 1, budterm%nlist
2668  icv = budterm%id1(j)
2669  if (this%featname(icv) == obsrv%FeatureName) then
2670  jfound = .true.
2671  call obsrv%AddObsIndex(j)
2672  end if
2673  end do
2674  if (.not. jfound) then
2675  write (errmsg, fmterr) trim(obsrv%FeatureName), trim(obsrv%Name), &
2676  trim(this%packName)
2677  call store_error(errmsg)
2678  end if
2679  else
2680  !
2681  ! -- ensure nn1 is > 0 and < ncv
2682  if (nn1 < 0 .or. nn1 > this%ncv) then
2683  write (errmsg, '(7a, i0, a, i0, a)') &
2684  'Observation ', trim(obsrv%Name), ' of type ', &
2685  trim(adjustl(obsrv%ObsTypeId)), ' in package ', &
2686  trim(this%packName), ' was assigned ID = ', nn1, &
2687  '. ID must be >= 1 and <= ', this%ncv, '.'
2688  call store_error(errmsg)
2689  end if
2690  iconn = obsrv%NodeNumber2
2691  do j = 1, budterm%nlist
2692  if (budterm%id1(j) == nn1) then
2693  ! -- Look for the first occurrence of nn1, then set indxbnds
2694  ! to the iconn record after that
2695  idx = j + iconn - 1
2696  call obsrv%AddObsIndex(idx)
2697  exit
2698  end if
2699  end do
2700  if (idx < 1 .or. idx > budterm%nlist) then
2701  write (errmsg, '(7a, i0, a, i0, a)') &
2702  'Observation ', trim(obsrv%Name), ' of type ', &
2703  trim(adjustl(obsrv%ObsTypeId)), ' in package ', &
2704  trim(this%packName), ' specifies iconn = ', iconn, &
2705  ', but this is not a valid connection for ID ', nn1, '.'
2706  call store_error(errmsg)
2707  else if (budterm%id1(idx) /= nn1) then
2708  write (errmsg, '(7a, i0, a, i0, a)') &
2709  'Observation ', trim(obsrv%Name), ' of type ', &
2710  trim(adjustl(obsrv%ObsTypeId)), ' in package ', &
2711  trim(this%packName), ' specifies iconn = ', iconn, &
2712  ', but this is not a valid connection for ID ', nn1, '.'
2713  call store_error(errmsg)
2714  end if
2715  end if
2716  !
2717  ! -- Return
2718  return
2719  end subroutine rp_obs_budterm
2720 
2721  !> @brief Prepare observation
2722  !!
2723  !! Find the indices for this observation assuming they are first indexed
2724  !! by a feature number and secondly by a second feature number
2725  !<
2726  subroutine rp_obs_flowjaface(this, obsrv, budterm)
2727  class(tspapttype), intent(inout) :: this !< object
2728  type(observetype), intent(inout) :: obsrv !< observation
2729  type(budgettermtype), intent(in) :: budterm !< budget term
2730  integer(I4B) :: nn1
2731  integer(I4B) :: nn2
2732  integer(I4B) :: icv
2733  integer(I4B) :: j
2734  logical :: jfound
2735  character(len=*), parameter :: fmterr = &
2736  "('Boundary ', a, ' for observation ', a, &
2737  &' is invalid in package ', a)"
2738  nn1 = obsrv%NodeNumber
2739  if (nn1 == namedboundflag) then
2740  jfound = .false.
2741  do j = 1, budterm%nlist
2742  icv = budterm%id1(j)
2743  if (this%featname(icv) == obsrv%FeatureName) then
2744  jfound = .true.
2745  call obsrv%AddObsIndex(j)
2746  end if
2747  end do
2748  if (.not. jfound) then
2749  write (errmsg, fmterr) trim(obsrv%FeatureName), trim(obsrv%Name), &
2750  trim(this%packName)
2751  call store_error(errmsg)
2752  end if
2753  else
2754  !
2755  ! -- ensure nn1 is > 0 and < ncv
2756  if (nn1 < 0 .or. nn1 > this%ncv) then
2757  write (errmsg, '(7a, i0, a, i0, a)') &
2758  'Observation ', trim(obsrv%Name), ' of type ', &
2759  trim(adjustl(obsrv%ObsTypeId)), ' in package ', &
2760  trim(this%packName), ' was assigned ID = ', nn1, &
2761  '. ID must be >= 1 and <= ', this%ncv, '.'
2762  call store_error(errmsg)
2763  end if
2764  nn2 = obsrv%NodeNumber2
2765  !
2766  ! -- ensure nn2 is > 0 and < ncv
2767  if (nn2 < 0 .or. nn2 > this%ncv) then
2768  write (errmsg, '(7a, i0, a, i0, a)') &
2769  'Observation ', trim(obsrv%Name), ' of type ', &
2770  trim(adjustl(obsrv%ObsTypeId)), ' in package ', &
2771  trim(this%packName), ' was assigned ID2 = ', nn2, &
2772  '. ID must be >= 1 and <= ', this%ncv, '.'
2773  call store_error(errmsg)
2774  end if
2775  ! -- Look for nn1 and nn2 in id1 and id2
2776  jfound = .false.
2777  do j = 1, budterm%nlist
2778  if (budterm%id1(j) == nn1 .and. budterm%id2(j) == nn2) then
2779  call obsrv%AddObsIndex(j)
2780  jfound = .true.
2781  end if
2782  end do
2783  if (.not. jfound) then
2784  write (errmsg, '(7a, i0, a, i0, a)') &
2785  'Observation ', trim(obsrv%Name), ' of type ', &
2786  trim(adjustl(obsrv%ObsTypeId)), ' in package ', &
2787  trim(this%packName), &
2788  ' specifies a connection between feature ', nn1, &
2789  ' feature ', nn2, ', but these features are not connected.'
2790  call store_error(errmsg)
2791  end if
2792  end if
2793  !
2794  ! -- Return
2795  return
2796  end subroutine rp_obs_flowjaface
2797 
2798  !> @brief Read and prepare apt-related observations
2799  !!
2800  !! Method to process specific observations for an apt package
2801  !<
2802  subroutine apt_rp_obs(this)
2803  ! -- modules
2804  use tdismodule, only: kper
2805  ! -- dummy
2806  class(tspapttype), intent(inout) :: this
2807  ! -- local
2808  integer(I4B) :: i
2809  logical :: found
2810  class(observetype), pointer :: obsrv => null()
2811  !
2812  if (kper == 1) then
2813  do i = 1, this%obs%npakobs
2814  obsrv => this%obs%pakobs(i)%obsrv
2815  select case (obsrv%ObsTypeId)
2816  case ('CONCENTRATION', 'TEMPERATURE')
2817  call this%rp_obs_byfeature(obsrv)
2818  !
2819  ! -- catch non-cumulative observation assigned to observation defined
2820  ! by a boundname that is assigned to more than one element
2821  if (obsrv%indxbnds_count > 1) then
2822  write (errmsg, '(a, a, a, a)') &
2823  trim(adjustl(this%depvartype))// &
2824  ' for observation', trim(adjustl(obsrv%Name)), &
2825  ' must be assigned to a feature with a unique boundname.'
2826  call store_error(errmsg)
2827  end if
2828  case ('LKT', 'SFT', 'MWT', 'UZT', 'LKE', 'SFE', 'MWE', 'UZE')
2829  call this%rp_obs_budterm(obsrv, &
2830  this%flowbudptr%budterm(this%idxbudgwf))
2831  case ('FLOW-JA-FACE')
2832  if (this%idxbudfjf > 0) then
2833  call this%rp_obs_flowjaface(obsrv, &
2834  this%flowbudptr%budterm(this%idxbudfjf))
2835  else
2836  write (errmsg, '(7a)') &
2837  'Observation ', trim(obsrv%Name), ' of type ', &
2838  trim(adjustl(obsrv%ObsTypeId)), ' in package ', &
2839  trim(this%packName), &
2840  ' cannot be processed because there are no flow connections.'
2841  call store_error(errmsg)
2842  end if
2843  case ('STORAGE')
2844  call this%rp_obs_byfeature(obsrv)
2845  case ('CONSTANT')
2846  call this%rp_obs_byfeature(obsrv)
2847  case ('FROM-MVR')
2848  call this%rp_obs_byfeature(obsrv)
2849  case default
2850  !
2851  ! -- check the child package for any specific obs
2852  found = .false.
2853  call this%pak_rp_obs(obsrv, found)
2854  !
2855  ! -- if none found then terminate with an error
2856  if (.not. found) then
2857  errmsg = 'Unrecognized observation type "'// &
2858  trim(obsrv%ObsTypeId)//'" for '// &
2859  trim(adjustl(this%text))//' package '// &
2860  trim(this%packName)
2861  call store_error(errmsg, terminate=.true.)
2862  end if
2863  end select
2864 
2865  end do
2866  !
2867  ! -- check for errors
2868  if (count_errors() > 0) then
2869  call store_error_unit(this%obs%inunitobs)
2870  end if
2871  end if
2872  !
2873  ! -- Return
2874  return
2875  end subroutine apt_rp_obs
2876 
2877  !> @brief Calculate observation values
2878  !!
2879  !! Routine calculates observations common to SFT/LKT/MWT/UZT
2880  !! (or SFE/LKE/MWE/UZE) for as many TspAptType observations that are common
2881  !! among the advanced transport packages
2882  !<
2883  subroutine apt_bd_obs(this)
2884  ! -- modules
2885  ! -- dummy
2886  class(tspapttype) :: this
2887  ! -- local
2888  integer(I4B) :: i
2889  integer(I4B) :: igwfnode
2890  integer(I4B) :: j
2891  integer(I4B) :: jj
2892  integer(I4B) :: n
2893  integer(I4B) :: n1
2894  integer(I4B) :: n2
2895  real(DP) :: v
2896  type(observetype), pointer :: obsrv => null()
2897  logical :: found
2898 ! ------------------------------------------------------------------------------
2899  !
2900  ! -- Write simulated values for all Advanced Package observations
2901  if (this%obs%npakobs > 0) then
2902  call this%obs%obs_bd_clear()
2903  do i = 1, this%obs%npakobs
2904  obsrv => this%obs%pakobs(i)%obsrv
2905  do j = 1, obsrv%indxbnds_count
2906  v = dnodata
2907  jj = obsrv%indxbnds(j)
2908  select case (obsrv%ObsTypeId)
2909  case ('CONCENTRATION', 'TEMPERATURE')
2910  if (this%iboundpak(jj) /= 0) then
2911  v = this%xnewpak(jj)
2912  end if
2913  case ('LKT', 'SFT', 'MWT', 'UZT', 'LKE', 'SFE', 'MWE', 'UZE')
2914  n = this%flowbudptr%budterm(this%idxbudgwf)%id1(jj)
2915  if (this%iboundpak(n) /= 0) then
2916  igwfnode = this%flowbudptr%budterm(this%idxbudgwf)%id2(jj)
2917  v = this%hcof(jj) * this%xnew(igwfnode) - this%rhs(jj)
2918  v = -v
2919  end if
2920  case ('FLOW-JA-FACE')
2921  n = this%flowbudptr%budterm(this%idxbudfjf)%id1(jj)
2922  if (this%iboundpak(n) /= 0) then
2923  call this%apt_fjf_term(jj, n1, n2, v)
2924  end if
2925  case ('STORAGE')
2926  if (this%iboundpak(jj) /= 0) then
2927  v = this%qsto(jj)
2928  end if
2929  case ('CONSTANT')
2930  if (this%iboundpak(jj) /= 0) then
2931  v = this%ccterm(jj)
2932  end if
2933  case ('FROM-MVR')
2934  if (this%iboundpak(jj) /= 0 .and. this%idxbudfmvr > 0) then
2935  call this%apt_fmvr_term(jj, n1, n2, v)
2936  end if
2937  case ('TO-MVR')
2938  if (this%idxbudtmvr > 0) then
2939  n = this%flowbudptr%budterm(this%idxbudtmvr)%id1(jj)
2940  if (this%iboundpak(n) /= 0) then
2941  call this%apt_tmvr_term(jj, n1, n2, v)
2942  end if
2943  end if
2944  case default
2945  found = .false.
2946  !
2947  ! -- check the child package for any specific obs
2948  call this%pak_bd_obs(obsrv%ObsTypeId, jj, v, found)
2949  !
2950  ! -- if none found then terminate with an error
2951  if (.not. found) then
2952  errmsg = 'Unrecognized observation type "'// &
2953  trim(obsrv%ObsTypeId)//'" for '// &
2954  trim(adjustl(this%text))//' package '// &
2955  trim(this%packName)
2956  call store_error(errmsg, terminate=.true.)
2957  end if
2958  end select
2959  call this%obs%SaveOneSimval(obsrv, v)
2960  end do
2961  end do
2962  !
2963  ! -- write summary of error messages
2964  if (count_errors() > 0) then
2965  call store_error_unit(this%obs%inunitobs)
2966  end if
2967  end if
2968  !
2969  ! -- Return
2970  return
2971  end subroutine apt_bd_obs
2972 
2973  !> @brief Check if observation exists in an advanced package
2974  !<
2975  subroutine pak_bd_obs(this, obstypeid, jj, v, found)
2976  ! -- dummy
2977  class(tspapttype), intent(inout) :: this
2978  character(len=*), intent(in) :: obstypeid
2979  integer(I4B), intent(in) :: jj
2980  real(DP), intent(inout) :: v
2981  logical, intent(inout) :: found
2982  ! -- local
2983  !
2984  ! -- set found = .false. because obstypeid is not known
2985  found = .false.
2986  !
2987  ! -- Return
2988  return
2989  end subroutine pak_bd_obs
2990 
2991  !> @brief Process observation IDs for an advanced package
2992  !!
2993  !! Method to process observation ID strings for an APT package.
2994  !! This processor is only for observation types that support ID1
2995  !! and not ID2.
2996  !<
2997  subroutine apt_process_obsid(obsrv, dis, inunitobs, iout)
2998  ! -- dummy variables
2999  type(observetype), intent(inout) :: obsrv !< Observation object
3000  class(disbasetype), intent(in) :: dis !< Discretization object
3001  integer(I4B), intent(in) :: inunitobs !< file unit number for the package observation file
3002  integer(I4B), intent(in) :: iout !< model listing file unit number
3003  ! -- local variables
3004  integer(I4B) :: nn1
3005  integer(I4B) :: icol
3006  integer(I4B) :: istart
3007  integer(I4B) :: istop
3008  character(len=LINELENGTH) :: string
3009  character(len=LENBOUNDNAME) :: bndname
3010  !
3011  ! -- initialize local variables
3012  string = obsrv%IDstring
3013  !
3014  ! -- Extract reach number from string and store it.
3015  ! If 1st item is not an integer(I4B), it should be a
3016  ! boundary name--deal with it.
3017  icol = 1
3018  !
3019  ! -- get reach number or boundary name
3020  call extract_idnum_or_bndname(string, icol, istart, istop, nn1, bndname)
3021  if (nn1 == namedboundflag) then
3022  obsrv%FeatureName = bndname
3023  end if
3024  !
3025  ! -- store reach number (NodeNumber)
3026  obsrv%NodeNumber = nn1
3027  !
3028  ! -- store NodeNumber2 as 1 so that this can be used
3029  ! as the iconn value for SFT. This works for SFT
3030  ! because there is only one reach per GWT connection.
3031  obsrv%NodeNumber2 = 1
3032  !
3033  ! -- return
3034  return
3035  end subroutine apt_process_obsid
3036 
3037  !> @brief Process observation IDs for a package
3038  !!
3039  !! Method to process observation ID strings for an APT package. This
3040  !! processor is for the case where if ID1 is an integer then ID2 must be
3041  !! provided.
3042  !<
3043  subroutine apt_process_obsid12(obsrv, dis, inunitobs, iout)
3044  ! -- dummy variables
3045  type(observetype), intent(inout) :: obsrv !< Observation object
3046  class(disbasetype), intent(in) :: dis !< Discretization object
3047  integer(I4B), intent(in) :: inunitobs !< file unit number for the package observation file
3048  integer(I4B), intent(in) :: iout !< model listing file unit number
3049  ! -- local variables
3050  integer(I4B) :: nn1
3051  integer(I4B) :: iconn
3052  integer(I4B) :: icol
3053  integer(I4B) :: istart
3054  integer(I4B) :: istop
3055  character(len=LINELENGTH) :: string
3056  character(len=LENBOUNDNAME) :: bndname
3057  !
3058  ! -- initialize local variables
3059  string = obsrv%IDstring
3060  !
3061  ! -- Extract reach number from string and store it.
3062  ! If 1st item is not an integer(I4B), it should be a
3063  ! boundary name--deal with it.
3064  icol = 1
3065  !
3066  ! -- get reach number or boundary name
3067  call extract_idnum_or_bndname(string, icol, istart, istop, nn1, bndname)
3068  if (nn1 == namedboundflag) then
3069  obsrv%FeatureName = bndname
3070  else
3071  call extract_idnum_or_bndname(string, icol, istart, istop, iconn, bndname)
3072  if (len_trim(bndname) < 1 .and. iconn < 0) then
3073  write (errmsg, '(a,1x,a,a,1x,a,1x,a)') &
3074  'For observation type', trim(adjustl(obsrv%ObsTypeId)), &
3075  ', ID given as an integer and not as boundname,', &
3076  'but ID2 is missing. Either change ID to valid', &
3077  'boundname or supply valid entry for ID2.'
3078  call store_error(errmsg)
3079  end if
3080  obsrv%NodeNumber2 = iconn
3081  end if
3082  !
3083  ! -- store reach number (NodeNumber)
3084  obsrv%NodeNumber = nn1
3085  !
3086  ! -- Return
3087  return
3088  end subroutine apt_process_obsid12
3089 
3090  !> @brief Setup a table object an advanced package
3091  !!
3092  !! Set up the table object that is used to write the apt concentration
3093  !! (or temperature) data. The terms listed here must correspond in the
3094  !! apt_ot method.
3095  !<
3096  subroutine apt_setup_tableobj(this)
3097  ! -- modules
3099  ! -- dummy
3100  class(tspapttype) :: this
3101  ! -- local
3102  integer(I4B) :: nterms
3103  character(len=LINELENGTH) :: title
3104  character(len=LINELENGTH) :: text_temp
3105  !
3106  ! -- setup well head table
3107  if (this%iprconc > 0) then
3108  !
3109  ! -- Determine the number of head table columns
3110  nterms = 2
3111  if (this%inamedbound == 1) nterms = nterms + 1
3112  !
3113  ! -- set up table title
3114  title = trim(adjustl(this%text))//' PACKAGE ('// &
3115  trim(adjustl(this%packName))// &
3116  ') '//trim(adjustl(this%depvartype))// &
3117  &' FOR EACH CONTROL VOLUME'
3118  !
3119  ! -- set up dv tableobj
3120  call table_cr(this%dvtab, this%packName, title)
3121  call this%dvtab%table_df(this%ncv, nterms, this%iout, &
3122  transient=.true.)
3123  !
3124  ! -- Go through and set up table budget term
3125  if (this%inamedbound == 1) then
3126  text_temp = 'NAME'
3127  call this%dvtab%initialize_column(text_temp, 20, alignment=tableft)
3128  end if
3129  !
3130  ! -- feature number
3131  text_temp = 'NUMBER'
3132  call this%dvtab%initialize_column(text_temp, 10, alignment=tabcenter)
3133  !
3134  ! -- feature conc
3135  text_temp = this%depvartype(1:4)
3136  call this%dvtab%initialize_column(text_temp, 12, alignment=tabcenter)
3137  end if
3138  !
3139  ! -- return
3140  return
3141  end subroutine apt_setup_tableobj
3142 
3143 end module tspaptmodule
This module contains the base boundary package.
This module contains the BudgetModule.
Definition: Budget.f90:20
subroutine, public budget_cr(this, name_model)
@ brief Create a new budget object
Definition: Budget.f90:84
subroutine, public budgetobject_cr(this, name)
Create a new budget object.
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:44
real(dp), parameter dhdry
real dry cell constant
Definition: Constants.f90:93
@ tabcenter
centered table column
Definition: Constants.f90:171
@ tabright
right justified table column
Definition: Constants.f90:172
@ tableft
left justified table column
Definition: Constants.f90:170
@ tabucstring
upper case string table data
Definition: Constants.f90:179
@ tabstring
string table data
Definition: Constants.f90:178
@ tabreal
real table data
Definition: Constants.f90:181
@ tabinteger
integer table data
Definition: Constants.f90:180
integer(i4b), parameter lenpackagename
maximum length of the package name
Definition: Constants.f90:22
integer(i4b), parameter namedboundflag
named bound flag
Definition: Constants.f90:48
real(dp), parameter dnodata
real no data constant
Definition: Constants.f90:94
real(dp), parameter dhnoflo
real no flow constant
Definition: Constants.f90:92
real(dp), parameter dep20
real constant 1e20
Definition: Constants.f90:90
integer(i4b), parameter lenvarname
maximum length of a variable name
Definition: Constants.f90:17
integer(i4b), parameter lenftype
maximum length of a package type (DIS, WEL, OC, etc.)
Definition: Constants.f90:38
integer(i4b), parameter lenauxname
maximum length of a aux variable
Definition: Constants.f90:34
integer(i4b), parameter lenboundname
maximum length of a bound name
Definition: Constants.f90:35
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:64
integer(i4b), parameter maxcharlen
maximum length of char string
Definition: Constants.f90:46
integer(i4b), parameter lenbudtxt
maximum length of a budget component names
Definition: Constants.f90:36
real(dp), parameter done
real constant 1
Definition: Constants.f90:75
subroutine, public extract_idnum_or_bndname(line, icol, istart, istop, idnum, bndname)
Starting at position icol, define string as line(istart:istop).
integer(i4b) function, public getunit()
Get a free unit number.
character(len=max(len_trim(str), width)) function, public str_pad_left(str, width)
Function for string manipulation.
subroutine, public ulasav(buf, text, kstp, kper, pertim, totim, ncol, nrow, ilay, ichn)
Save 1 layer array on disk.
subroutine, public openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, filstat_opt, mode_opt)
Open a file.
Definition: InputOutput.f90:30
subroutine, public urword(line, icol, istart, istop, ncode, n, r, iout, in)
Extract a word from a string.
This module defines variable data types.
Definition: kind.f90:8
This module contains the derived types ObserveType and ObsDataType.
Definition: Observe.f90:15
character(len=20) access
Definition: OpenSpec.f90:7
character(len=20) form
Definition: OpenSpec.f90:7
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_unit(iunit, terminate)
Store the file unit number.
Definition: Sim.f90:168
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string
integer(i4b) ifailedstepretry
current retry for this time step
subroutine, public table_cr(this, name, title)
Definition: Table.f90:85
real(dp), pointer, public pertim
time relative to start of stress period
Definition: tdis.f90:30
real(dp), pointer, public totim
time relative to start of simulation
Definition: tdis.f90:32
integer(i4b), pointer, public kstp
current time step number
Definition: tdis.f90:24
integer(i4b), pointer, public kper
current stress period number
Definition: tdis.f90:23
real(dp), pointer, public delt
length of the current time step
Definition: tdis.f90:29
integer(i4b), pointer, public nper
number of stress period
Definition: tdis.f90:21
subroutine, public read_value_or_time_series_adv(textInput, ii, jj, bndElem, pkgName, auxOrBnd, tsManager, iprpak, varName)
Call this subroutine from advanced packages to define timeseries link for a variable (varName).
subroutine apt_ot_bdsummary(this, kstp, kper, iout, ibudfl)
Print advanced package transport dependent variables.
Definition: tsp-apt.f90:1081
subroutine apt_cfupdate(this)
Advanced package transport routine.
Definition: tsp-apt.f90:919
subroutine pak_setup_budobj(this, idx)
Set up a budget object that stores an advanced package flows.
Definition: tsp-apt.f90:2202
subroutine apt_ar(this)
Advanced package transport allocate and read (ar) routine.
Definition: tsp-apt.f90:308
subroutine pak_fill_budobj(this, idx, x, flowja, ccratin, ccratout)
Copy flow terms into thisbudobj, must be overridden.
Definition: tsp-apt.f90:2360
subroutine rp_obs_flowjaface(this, obsrv, budterm)
Prepare observation.
Definition: tsp-apt.f90:2727
subroutine pak_set_stressperiod(this, itemno, keyword, found)
Advanced package transport set stress period routine.
Definition: tsp-apt.f90:600
subroutine pak_bd_obs(this, obstypeid, jj, v, found)
Check if observation exists in an advanced package.
Definition: tsp-apt.f90:2976
subroutine apt_fc_expanded(this, rhs, ia, idxglo, matrix_sln)
Advanced package transport fill coefficient (fc) method.
Definition: tsp-apt.f90:784
subroutine pak_fc_expanded(this, rhs, ia, idxglo, matrix_sln)
Advanced package transport fill coefficient (fc) method.
Definition: tsp-apt.f90:896
subroutine apt_fjf_term(this, ientry, n1, n2, rrate, rhsval, hcofval)
Go through each "within apt-apt" connection (e.g., lkt-lkt, or sft-sft) and accumulate total mass (or...
Definition: tsp-apt.f90:2470
subroutine rp_obs_budterm(this, obsrv, budterm)
Prepare observation.
Definition: tsp-apt.f90:2652
subroutine allocate_scalars(this)
@ brief Allocate scalars
Definition: tsp-apt.f90:1101
subroutine apt_read_initial_attr(this)
Read the initial parameters for an advanced package.
Definition: tsp-apt.f90:1717
subroutine apt_setup_budobj(this)
Set up the budget object that stores advanced package flow terms.
Definition: tsp-apt.f90:2011
subroutine apt_allocate_index_arrays(this)
@ brief Allocate index arrays
Definition: tsp-apt.f90:1160
subroutine apt_rp_obs(this)
Read and prepare apt-related observations.
Definition: tsp-apt.f90:2803
character(len=lenvarname) text
Definition: tsp-apt.f90:63
subroutine apt_ot_package_flows(this, icbcfl, ibudfl)
Save advanced package flows routine.
Definition: tsp-apt.f90:995
real(dp) function, dimension(:), pointer, contiguous get_mvr_depvar(this)
Advanced package transport utility function.
Definition: tsp-apt.f90:643
subroutine get_volumes(this, icv, vnew, vold, delt)
Return the feature new volume and old volume.
Definition: tsp-apt.f90:1965
subroutine apt_allocate_arrays(this)
@ brief Allocate arrays
Definition: tsp-apt.f90:1220
integer(i4b) function pak_get_nbudterms(this)
Function to return the number of budget terms just for this package.
Definition: tsp-apt.f90:1992
subroutine apt_set_stressperiod(this, itemno)
Advanced package transport set stress period routine.
Definition: tsp-apt.f90:500
subroutine apt_df_obs(this)
Define observation type.
Definition: tsp-apt.f90:2550
character(len=lenftype) ftype
Definition: tsp-apt.f90:62
subroutine apt_fmvr_term(this, ientry, n1, n2, rrate, rhsval, hcofval)
Account for mass or energy transferred to this package from the MVR package.
Definition: tsp-apt.f90:2444
subroutine apt_da(this)
@ brief Deallocate memory
Definition: tsp-apt.f90:1278
subroutine apt_read_dimensions(this)
Determine dimensions for this advanced package.
Definition: tsp-apt.f90:1468
subroutine apt_mc(this, moffset, matrix_sln)
Advanced package transport map package connections to matrix.
Definition: tsp-apt.f90:244
subroutine apt_fill_budobj(this, x, flowja)
Copy flow terms into thisbudobj.
Definition: tsp-apt.f90:2219
subroutine pak_rp_obs(this, obsrv, found)
Process package specific obs.
Definition: tsp-apt.f90:2586
logical function apt_obs_supported(this)
Determine whether an obs type is supported.
Definition: tsp-apt.f90:2532
subroutine apt_read_cvs(this)
Read feature information for this advanced package.
Definition: tsp-apt.f90:1537
subroutine apt_bd_obs(this)
Calculate observation values.
Definition: tsp-apt.f90:2884
subroutine apt_solve(this)
Add terms specific to advanced package transport to the explicit solve.
Definition: tsp-apt.f90:1769
subroutine apt_tmvr_term(this, ientry, n1, n2, rrate, rhsval, hcofval)
Account for mass or energy transferred to the MVR package.
Definition: tsp-apt.f90:2413
subroutine apt_set_pointers(this, neq, ibound, xnew, xold, flowja)
Set pointers to model arrays and variables so that a package has access to these items.
Definition: tsp-apt.f90:1936
subroutine apt_accumulate_ccterm(this, ilak, rrate, ccratin, ccratout)
Accumulate constant concentration (or temperature) terms for budget.
Definition: tsp-apt.f90:1874
subroutine apt_setup_tableobj(this)
Setup a table object an advanced package.
Definition: tsp-apt.f90:3097
subroutine find_apt_package(this)
Find corresponding advanced package transport package.
Definition: tsp-apt.f90:1355
subroutine apt_rp(this)
Advanced package transport read and prepare (rp) routine.
Definition: tsp-apt.f90:378
subroutine apt_stor_term(this, ientry, n1, n2, rrate, rhsval, hcofval)
Account for mass or energy storage in advanced package features.
Definition: tsp-apt.f90:2383
subroutine apt_options(this, option, found)
Set options specific to the TspAptType.
Definition: tsp-apt.f90:1374
subroutine rp_obs_byfeature(this, obsrv)
Prepare observation.
Definition: tsp-apt.f90:2606
subroutine apt_copy2flowp(this)
Copy concentrations (or temperatures) into flow package aux variable.
Definition: tsp-apt.f90:2503
subroutine apt_cq(this, x, flowja, iadv)
Advanced package transport calculate flows (cq) routine.
Definition: tsp-apt.f90:952
subroutine apt_ac(this, moffset, sparse)
Add package connection to matrix.
Definition: tsp-apt.f90:194
subroutine, public apt_process_obsid(obsrv, dis, inunitobs, iout)
Process observation IDs for an advanced package.
Definition: tsp-apt.f90:2998
subroutine apt_ad(this)
Advanced package transport routine.
Definition: tsp-apt.f90:656
integer(i4b) function apt_check_valid(this, itemno)
Advanced package transport routine.
Definition: tsp-apt.f90:623
subroutine define_listlabel(this)
Define the list heading that is written to iout when PRINT_INPUT option is used.
Definition: tsp-apt.f90:1909
subroutine pak_solve(this)
Add terms specific to advanced package transport features to the explicit solve routine.
Definition: tsp-apt.f90:1859
subroutine apt_fc_nonexpanded(this, rhs, ia, idxglo, matrix_sln)
Advanced package transport fill coefficient (fc) method.
Definition: tsp-apt.f90:752
subroutine apt_reset(this)
Override bnd reset for custom mover logic.
Definition: tsp-apt.f90:713
subroutine apt_fc(this, rhs, ia, idxglo, matrix_sln)
Definition: tsp-apt.f90:726
subroutine apt_ot_dv(this, idvsave, idvprint)
Definition: tsp-apt.f90:1022
subroutine pak_df_obs(this)
Define apt observation type.
Definition: tsp-apt.f90:2568
subroutine, public apt_process_obsid12(obsrv, dis, inunitobs, iout)
Process observation IDs for a package.
Definition: tsp-apt.f90:3044
@ brief BndType