MODFLOW 6  version 6.9.0.dev0
USGS Modular Hydrologic Model
BoundaryPackageExt.f90
Go to the documentation of this file.
1 !> @brief This module contains the extended boundary package
2 !!
3 !! This module contains the extended boundary type that itself
4 !! should be extended by model boundary packages that have been
5 !! updated to source static and dynamic input data from the
6 !! input context.
7 !!
8 !<
10 
11  use kindmodule, only: dp, lgp, i4b
13  dzero, dnodata
15  use obsmodule, only: obs_cr
16  use simvariablesmodule, only: errmsg
18  use bndmodule, only: bndtype
19  use geomutilmodule, only: get_node, get_ijk
20 
21  implicit none
22 
23  private
24  public :: bndexttype
25 
26  !> @ brief BndExtType
27  !!
28  !! Generic extended boundary package type. This derived type can be
29  !! overridden to define concrete boundary package types that source
30  !! all input from the input context.
31  !<
32  type, extends(bndtype) :: bndexttype
33  ! -- characters
34  ! -- scalars
35  integer(I4B), pointer :: iper
36  logical(LGP), pointer :: readarraygrid
37  logical(LGP), pointer :: readasarrays
38  logical(LGP), pointer :: ts_active !< .true. if TS6 files are configured in OPTIONS
39  ! -- list/layerarray/gridarray package arrays
40  integer(I4B), dimension(:, :), pointer, contiguous :: cellid => null() !< input user cellid list
41  integer(I4B), dimension(:), pointer, contiguous :: nodeulist => null() !< input user nodelist
42  ! -- advanced package arrays
43  integer(I4B), dimension(:), pointer, contiguous :: pkg_ifno => null() !< advanced feature index
44  real(dp), dimension(:, :), pointer, contiguous :: featureauxvar => null() !< advanced per-feature AUX array
45  contains
46  procedure :: bnd_df => bndext_df
47  procedure :: bnd_ad => bndext_ad
48  procedure :: bnd_rp => bndext_rp
49  procedure :: bnd_rp_log => bndext_rp_log
50  procedure :: validate_ifno
51  procedure :: report_ifno_coverage
52  procedure :: bnd_da => bndext_da
53  procedure :: allocate_scalars => bndext_allocate_scalars
54  procedure :: allocate_arrays => bndext_allocate_arrays
56  procedure :: source_options
57  procedure :: log_options
58  procedure :: source_dimensions
59  procedure :: cellid_to_nlist
60  procedure :: nodeu_to_nlist
61  procedure :: layarr_to_nlist
62  procedure :: default_nodelist
63  procedure :: check_cellid
64  procedure :: write_lstfile
65  procedure :: bound_value
66  end type bndexttype
67 
68  !> @ brief BndExtFoundType
69  !!
70  !! This type is used to simplify the tracking of common parameters
71  !! that are sourced from the input context.
72  !<
74  logical :: naux = .false.
75  logical :: ipakcb = .false.
76  logical :: iprpak = .false.
77  logical :: iprflow = .false.
78  logical :: boundnames = .false.
79  logical :: auxmultname = .false.
80  logical :: inewton = .false.
81  logical :: auxiliary = .false.
82  logical :: maxbound = .false.
83  end type bndextfoundtype
84 
85 contains
86 
87  !> @ brief Define boundary package options and dimensions
88  !!
89  !! Define base boundary package options and dimensions for
90  !! a model boundary package.
91  !!
92  !<
93  subroutine bndext_df(this, neq, dis)
94  ! -- modules
95  use basedismodule, only: disbasetype
100  ! -- dummy variables
101  class(bndexttype), intent(inout) :: this !< BndExtType object
102  integer(I4B), intent(inout) :: neq !< number of equations
103  class(disbasetype), pointer :: dis !< discretization object
104  ! -- local
105  integer(I4B) :: isize
106  ! -- formats
107  character(len=*), parameter :: fmtpkghdr = &
108  &"(1X,/1X,a,' -- ',a,' PACKAGE, VERSION 8, 2/22/2014',&
109  &' INPUT READ FROM MEMPATH: ',a)"
110  !
111  ! -- set pointer to dis object for the model
112  this%dis => dis
113  !
114  ! -- Create time series managers
115  ! -- Not in use by this type but BndType uses and deallocates
116  call tsmanager_cr(this%TsManager, this%iout)
117  call tasmanager_cr(this%TasManager, dis, this%name_model, this%iout)
118  !
119  ! -- create obs package
120  call obs_cr(this%obs, this%inobspkg)
121  !
122  ! -- Write information to model list file
123  write (this%iout, fmtpkghdr) trim(this%filtyp), trim(adjustl(this%text)), &
124  this%input_mempath
125  !
126  ! -- source options
127  call this%source_options()
128  !
129  ! -- detect TS6 files; used by subclass _ad to bypass per-timestep re-dispatch
130  call get_isize('TS6_FILENAME', this%input_mempath, isize)
131  if (isize > 0) this%ts_active = .true.
132  !
133  ! -- Define time series managers
134  call this%tsmanager%tsmanager_df()
135  call this%tasmanager%tasmanager_df()
136  !
137  ! -- source dimensions
138  call this%source_dimensions()
139  !
140  ! -- update package moffset for packages that add rows
141  if (this%npakeq > 0) then
142  this%ioffset = neq - this%dis%nodes
143  end if
144  !
145  ! -- update neq
146  neq = neq + this%npakeq
147  !
148  ! -- Store information needed for observations
149  if (this%bnd_obs_supported()) then
150  call this%obs%obs_df(this%iout, this%packName, this%filtyp, this%dis)
151  call this%bnd_df_obs()
152  end if
153  !
154  ! -- Call define_listlabel to construct the list label that is written
155  ! when PRINT_INPUT option is used.
156  call this%define_listlabel()
157  end subroutine bndext_df
158 
159  !> @brief Advance the package one time step
160  !!
161  !! Does not call this%TsManager%ad()/this%TasManager%ad() -- those
162  !! managers are unused by this type (see bndext_df).
163  !<
164  subroutine bndext_ad(this)
165  ! -- dummy
166  class(bndexttype) :: this
167  !
168  ! -- advance observations
169  call this%obs%obs_ad()
170  end subroutine bndext_ad
171 
172  subroutine bndext_rp(this)
173  ! -- modules
174  use tdismodule, only: kper
177  ! -- dummy variables
178  class(bndexttype), intent(inout) :: this !< BndExtType object
179  ! -- local variables
180  logical(LGP) :: found
181  integer(I4B) :: n
182  !
183  if (this%iper /= kper) return
184 
185  if (.not. this%readasarrays) then
186  ! -- copy nbound from input context
187  call mem_set_value(this%nbound, 'NBOUND', this%input_mempath, &
188  found, release=.false.)
189  end if
190 
191  if (this%readarraygrid) then
192  call this%nodeu_to_nlist()
193  else if (this%readasarrays) then
194  call this%layarr_to_nlist()
195  else
196  call this%cellid_to_nlist()
197  !
198  ! -- update boundname string list
199  if (this%inamedbound /= 0) then
200  do n = 1, size(this%boundname_cst)
201  this%boundname(n) = this%boundname_cst(n)
202  end do
203  end if
204  end if
205  end subroutine bndext_rp
206 
207  !> @brief Write the input list to the listing file if requested
208  !!
209  !! Called from model control files after bnd_rp(), which ensures
210  !! bound_value() dispatches to the correct derived type.
211  !<
212  subroutine bndext_rp_log(this)
213  ! -- dummy
214  class(bndexttype), intent(inout) :: this
215  !
216  if (this%iprpak /= 0 .and. this%isadvpak == 0) then
217  call this%write_lstfile()
218  end if
219  end subroutine bndext_rp_log
220 
221  !> @ brief Validate a list-input row's IFNO and update the per-feature
222  !! coverage counter
223  !!
224  !! Returns the validated feature index, or 0 if out of range (an error is
225  !! logged; the caller should skip further processing for the row).
226  !<
227  function validate_ifno(this, ifno_val, nfeatures, nboundchk, &
228  feature_label, blockname) result(idx)
229  ! -- dummy
230  class(bndexttype), intent(inout) :: this
231  integer(I4B), intent(in) :: ifno_val
232  integer(I4B), intent(in) :: nfeatures
233  integer(I4B), dimension(:), intent(inout) :: nboundchk
234  character(len=*), intent(in) :: feature_label
235  character(len=*), intent(in) :: blockname
236  ! -- return
237  integer(I4B) :: idx
238  !
239  idx = ifno_val
240  if (idx < 1 .or. idx > nfeatures) then
241  write (errmsg, '(a,1x,a,1x,a,i0,a,1x,i0,a)') &
242  trim(blockname), trim(feature_label), '(', idx, &
243  ') must be greater than 0 and less than or equal to', nfeatures, '.'
244  call store_error(errmsg)
245  idx = 0
246  return
247  end if
248  nboundchk(idx) = nboundchk(idx) + 1
249  end function validate_ifno
250 
251  !> @ brief Report missing or duplicate list-input rows for each feature
252  !!
253  !! Set check_missing=.false. for an optional block where not every
254  !! feature is expected to have a row (duplicates are still reported).
255  !<
256  subroutine report_ifno_coverage(this, nboundchk, nfeatures, feature_label, &
257  blockname, check_missing)
258  ! -- dummy
259  class(bndexttype), intent(inout) :: this
260  integer(I4B), dimension(:), intent(in) :: nboundchk
261  integer(I4B), intent(in) :: nfeatures
262  character(len=*), intent(in) :: feature_label
263  character(len=*), intent(in) :: blockname
264  logical(LGP), intent(in), optional :: check_missing
265  ! -- local
266  integer(I4B) :: n
267  logical(LGP) :: do_check_missing
268  !
269  do_check_missing = .true.
270  if (present(check_missing)) do_check_missing = check_missing
271  !
272  do n = 1, nfeatures
273  if (do_check_missing .and. nboundchk(n) == 0) then
274  write (errmsg, '(a,1x,a,1x,a,1x,i0,a)') &
275  trim(blockname), 'no data specified for', trim(feature_label), n, '.'
276  call store_error(errmsg)
277  else if (nboundchk(n) > 1) then
278  write (errmsg, '(a,1x,a,1x,a,1x,i0,1x,a,1x,i0,1x,a)') &
279  trim(blockname), 'data for', trim(feature_label), n, &
280  'specified', nboundchk(n), 'times.'
281  call store_error(errmsg)
282  end if
283  end do
284  end subroutine report_ifno_coverage
285 
286  !> @ brief Deallocate package memory
287  !<
288  subroutine bndext_da(this)
289  ! -- modules
291  ! -- dummy variables
292  class(bndexttype) :: this !< BndExtType object
293  !
294  if (this%isadvpak /= 0) then
295  !
296  ! -- advanced package cleanup (MAW, SFR, LAK, UZF)
297  nullify (this%featureauxvar)
298  call mem_deallocate(this%auxvar, 'AUXVAR_IDM', this%memoryPath)
299  nullify (this%pkg_ifno)
300  else
301  !
302  ! -- list/array package cleanup
303  call mem_deallocate(this%cellid, 'CELLID', this%memoryPath)
304  call mem_deallocate(this%nodeulist, 'NODEULIST', this%memoryPath)
305  call mem_deallocate(this%boundname_cst, 'BOUNDNAME_IDM', this%memoryPath)
306  call mem_deallocate(this%auxvar, 'AUXVAR_IDM', this%memoryPath)
307  !
308  ! -- reassign pointers for base class _da
309  call mem_setptr(this%boundname_cst, 'BOUNDNAME_CST', this%memoryPath)
310  call mem_setptr(this%auxvar, 'AUXVAR', this%memoryPath)
311  end if
312  !
313  ! -- scalars
314  deallocate (this%readarraygrid)
315  deallocate (this%readasarrays)
316  deallocate (this%ts_active)
317  nullify (this%readarraygrid)
318  nullify (this%readasarrays)
319  nullify (this%ts_active)
320  nullify (this%iper)
321  !
322  ! -- deallocate
323  call this%BndType%bnd_da()
324  end subroutine bndext_da
325 
326  !> @ brief Allocate package scalars
327  !!
328  !! Allocate and initialize base boundary package scalars. This method
329  !! only needs to be overridden if additional scalars are defined
330  !! for a specific package.
331  !!
332  !<
333  subroutine bndext_allocate_scalars(this)
334  ! -- modules
336  ! -- dummy variables
337  class(bndexttype) :: this !< BndExtType object
338  ! -- local variables
339  !
340  ! -- allocate base BndType scalars
341  call this%BndType%allocate_scalars()
342  !
343  ! -- set IPER pointer
344  call mem_setptr(this%iper, 'IPER', this%input_mempath)
345 
346  ! -- allocate internal scalars
347  allocate (this%readarraygrid)
348  allocate (this%readasarrays)
349  allocate (this%ts_active)
350 
351  ! -- initialize internal scalars
352  this%readarraygrid = .false.
353  this%readasarrays = .false.
354  this%ts_active = .false.
355  end subroutine bndext_allocate_scalars
356 
357  !> @ brief Allocate package arrays
358  !!
359  !! Allocate and initialize base boundary package arrays. This method
360  !! only needs to be overridden if additional arrays are defined
361  !! for a specific package.
362  !!
363  !<
364  subroutine bndext_allocate_arrays(this, nodelist, auxvar)
365  ! -- modules
367  ! -- dummy variables
368  class(bndexttype) :: this !< BndExtType object
369  ! -- local variables
370  integer(I4B), dimension(:), pointer, contiguous, optional :: nodelist !< package nodelist
371  real(DP), dimension(:, :), pointer, contiguous, optional :: auxvar !< package aux variable array
372  !
373  if (this%isadvpak /= 0) then
374  !
375  ! -- advanced package (MAW, SFR, LAK, UZF): allocate connections-level BndType arrays
376  call this%BndType%allocate_arrays(nodelist, auxvar)
377  call mem_checkin(this%auxvar, 'AUXVAR_IDM', this%memoryPath, 'AUXVAR', &
378  this%memoryPath)
379  return
380  end if
381  !
382  ! -- list/layerarray/gridarray package: allocate base BndType arrays
383  call this%BndType%allocate_arrays(nodelist, auxvar)
384  !
385  ! -- set input context pointers
386  call mem_setptr(this%cellid, 'CELLID', this%input_mempath)
387  call mem_setptr(this%nodeulist, 'NODEULIST', this%input_mempath)
388  call mem_setptr(this%boundname_cst, 'BOUNDNAME', this%input_mempath)
389  !
390  ! -- checkin input context pointers
391  call mem_checkin(this%cellid, 'CELLID', this%memoryPath, &
392  'CELLID', this%input_mempath)
393  call mem_checkin(this%nodeulist, 'NODEULIST', this%memoryPath, &
394  'NODEULIST', this%input_mempath)
395  call mem_checkin(this%boundname_cst, lenboundname, 'BOUNDNAME_IDM', &
396  this%memoryPath, 'BOUNDNAME', this%input_mempath)
397  !
398  if (present(auxvar)) then
399  ! no-op
400  else
401  ! -- set auxvar input context pointer
402  call mem_setptr(this%auxvar, 'AUXVAR', this%input_mempath)
403  !
404  ! -- checkin auxvar input context pointer
405  call mem_checkin(this%auxvar, 'AUXVAR_IDM', this%memoryPath, &
406  'AUXVAR', this%input_mempath)
407  end if
408  end subroutine bndext_allocate_arrays
409 
410  !> @brief Point the per-feature auxiliary variable array at the input
411  !! context's permanent, feature-indexed AUX array.
412  !! For packages with PACKAGEDATA AUX variables only. A live alias,
413  !! permuted from row order to IFNO order, skipping out-of-range IFNO.
414  !<
415  subroutine allocate_featureauxvar(this)
416  ! -- modules
418  ! -- dummy
419  class(bndexttype) :: this !< BndExtType object
420  ! -- local
421  real(DP), dimension(:, :), allocatable :: aux_row_order
422  integer(I4B) :: n, ifeat, jj, nrow
423  !
424  ! -- set input context PACKAGEDATA pointers
425  call mem_setptr(this%pkg_ifno, 'PACKAGEDATA_IFNO', this%input_mempath)
426  if (this%naux > 0) then
427  call mem_setptr(this%featureauxvar, 'AUX', this%input_mempath)
428  nrow = size(this%pkg_ifno)
429  allocate (aux_row_order(this%naux, nrow))
430  aux_row_order = this%featureauxvar(:, 1:nrow)
431  do n = 1, nrow
432  ifeat = this%pkg_ifno(n)
433  if (ifeat < 1 .or. ifeat > size(this%featureauxvar, 2)) cycle
434  do jj = 1, this%naux
435  this%featureauxvar(jj, ifeat) = aux_row_order(jj, n)
436  end do
437  end do
438  deallocate (aux_row_order)
439  end if
440  end subroutine allocate_featureauxvar
441 
442  !> @ brief Source package options from input context
443  !<
444  subroutine source_options(this)
445  ! -- modules
446  use memorymanagermodule, only: mem_reallocate, mem_setptr !, get_isize
451  ! -- dummy variables
452  class(bndexttype), intent(inout) :: this !< BndExtType object
453  ! -- local variables
454  type(bndextfoundtype) :: found
455  logical(LGP) :: found_readarr
456  character(len=LENAUXNAME) :: sfacauxname
457  integer(I4B) :: n
458  !
459  ! -- update defaults with idm sourced values
460  call mem_set_value(this%naux, 'NAUX', this%input_mempath, found%naux, &
461  release=.false.)
462  call mem_set_value(this%ipakcb, 'IPAKCB', this%input_mempath, found%ipakcb)
463  call mem_set_value(this%iprpak, 'IPRPAK', this%input_mempath, found%iprpak)
464  call mem_set_value(this%iprflow, 'IPRFLOW', this%input_mempath, found%iprflow)
465  call mem_set_value(this%inamedbound, 'BOUNDNAMES', this%input_mempath, &
466  found%boundnames, release=.false.)
467  call mem_set_value(sfacauxname, 'AUXMULTNAME', this%input_mempath, &
468  found%auxmultname)
469  call mem_set_value(this%inewton, 'INEWTON', this%input_mempath, found%inewton)
470  call mem_set_value(this%readarraygrid, 'READARRAYGRID', this%input_mempath, &
471  found_readarr)
472  call mem_set_value(this%readasarrays, 'READASARRAYS', this%input_mempath, &
473  found_readarr)
474  !
475  ! -- log found options
476  call this%log_options(found, sfacauxname)
477  !
478  ! -- reallocate aux arrays if aux variables provided
479  if (found%naux .and. this%naux > 0) then
480  call mem_reallocate(this%auxname, lenauxname, this%naux, &
481  'AUXNAME', this%memoryPath)
482  call mem_reallocate(this%auxname_cst, lenauxname, this%naux, &
483  'AUXNAME_CST', this%memoryPath)
484  call mem_set_value(this%auxname_cst, 'AUXILIARY', this%input_mempath, &
485  found%auxiliary, release=.false.)
486  !
487  do n = 1, this%naux
488  this%auxname(n) = this%auxname_cst(n)
489  end do
490  end if
491  !
492  ! -- save flows option active
493  if (found%ipakcb) this%ipakcb = -1
494  !
495  ! -- auxmultname provided
496  if (found%auxmultname) this%iauxmultcol = -1
497  !
498  !
499  ! -- enforce 0 or 1 OBS6_FILENAME entries in option block
500  if (filein_fname(this%obs%inputFilename, 'OBS6_FILENAME', &
501  this%input_mempath, this%input_fname)) then
502  this%obs%active = .true.
503  this%obs%inUnitObs = getunit()
504  call openfile(this%obs%inUnitObs, this%iout, this%obs%inputFilename, 'OBS')
505  end if
506  !
507  ! -- no newton specified
508  if (found%inewton) this%inewton = 0
509  !
510  ! -- AUXMULTNAME was specified, so find column of auxvar that will be multiplier
511  if (this%iauxmultcol < 0) then
512  !
513  ! -- Error if no aux variable specified
514  if (this%naux == 0) then
515  write (errmsg, '(a,2(1x,a))') &
516  'AUXMULTNAME was specified as', trim(adjustl(sfacauxname)), &
517  'but no AUX variables specified.'
518  call store_error(errmsg)
519  end if
520  !
521  ! -- Assign mult column
522  this%iauxmultcol = 0
523  do n = 1, this%naux
524  if (sfacauxname == this%auxname(n)) then
525  this%iauxmultcol = n
526  exit
527  end if
528  end do
529  !
530  ! -- Error if aux variable cannot be found
531  if (this%iauxmultcol == 0) then
532  write (errmsg, '(a,2(1x,a))') &
533  'AUXMULTNAME was specified as', trim(adjustl(sfacauxname)), &
534  'but no AUX variable found with this name.'
535  call store_error(errmsg)
536  end if
537  end if
538  !
539  if (this%readasarrays) then
540  if (.not. this%dis%supports_layers()) then
541  errmsg = 'READASARRAYS option is not compatible with selected'// &
542  ' discretization type.'
543  call store_error(errmsg)
544  call store_error_filename(this%input_fname)
545  end if
546  end if
547  !
548  ! -- terminate if errors were detected
549  if (count_errors() > 0) then
550  call store_error_filename(this%input_fname)
551  end if
552  end subroutine source_options
553 
554  !> @ brief Log package options
555  !<
556  subroutine log_options(this, found, sfacauxname)
557  ! -- modules
558  ! -- dummy variables
559  class(bndexttype), intent(inout) :: this !< BndExtType object
560  type(bndextfoundtype), intent(in) :: found
561  character(len=*), intent(in) :: sfacauxname
562  ! -- local variables
563  ! -- format
564  character(len=*), parameter :: fmtreadasarrays = &
565  &"(4x, 'PACKAGE INPUT WILL BE READ AS LAYER ARRAYS.')"
566  character(len=*), parameter :: fmtreadarraygrid = &
567  &"(4x, 'PACKAGE INPUT WILL BE READ AS GRID ARRAYS.')"
568  character(len=*), parameter :: fmtflow = &
569  &"(4x, 'FLOWS WILL BE SAVED TO BUDGET FILE SPECIFIED IN OUTPUT CONTROL')"
570  !
571  ! -- log found options
572  write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text)) &
573  //' BASE OPTIONS'
574  !
575  if (this%readasarrays) then
576  write (this%iout, fmtreadasarrays)
577  end if
578  !
579  if (this%readarraygrid) then
580  write (this%iout, fmtreadarraygrid)
581  end if
582  !
583  if (found%ipakcb) then
584  write (this%iout, fmtflow)
585  end if
586  !
587  if (found%iprpak) then
588  write (this%iout, '(4x,a)') &
589  'LISTS OF '//trim(adjustl(this%text))//' CELLS WILL BE PRINTED.'
590  end if
591  !
592  if (found%iprflow) then
593  write (this%iout, '(4x,a)') trim(adjustl(this%text))// &
594  ' FLOWS WILL BE PRINTED TO LISTING FILE.'
595  end if
596  !
597  if (found%boundnames) then
598  write (this%iout, '(4x,a)') trim(adjustl(this%text))// &
599  ' BOUNDARIES HAVE NAMES IN LAST COLUMN.'
600  end if
601  !
602  if (found%auxmultname) then
603  write (this%iout, '(4x,a,a)') &
604  'AUXILIARY MULTIPLIER NAME: ', sfacauxname
605  end if
606  !
607  if (found%inewton) then
608  write (this%iout, '(4x,a)') &
609  'NEWTON-RAPHSON method disabled for unconfined cells'
610  end if
611  !
612  ! -- close logging block
613  write (this%iout, '(1x,a)') &
614  'END OF '//trim(adjustl(this%text))//' BASE OPTIONS'
615  end subroutine log_options
616 
617  !> @ brief Source package dimensions from input context
618  !<
619  subroutine source_dimensions(this)
621  ! -- dummy variables
622  class(bndexttype), intent(inout) :: this !< BndExtType object
623  ! -- local variables
624  type(bndextfoundtype) :: found
625  !
626  if (this%readasarrays) then
627  this%maxbound = this%dis%get_ncpl()
628  else
629  ! -- open dimensions logging block
630  write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// &
631  ' BASE DIMENSIONS'
632 
633  ! -- update defaults with idm sourced values
634  call mem_set_value(this%maxbound, 'MAXBOUND', this%input_mempath, &
635  found%maxbound, release=.false.)
636 
637  write (this%iout, '(4x,a,i7)') 'MAXBOUND = ', this%maxbound
638 
639  ! -- close logging block
640  write (this%iout, '(1x,a)') &
641  'END OF '//trim(adjustl(this%text))//' BASE DIMENSIONS'
642  end if
643  !
644  ! -- verify dimensions were set
645  if (this%maxbound <= 0) then
646  write (errmsg, '(a)') 'MAXBOUND must be an integer greater than zero.'
647  call store_error(errmsg)
648  call store_error_filename(this%input_fname)
649  end if
650  end subroutine source_dimensions
651 
652  !> @ brief Update package nodelist
653  !!
654  !! Convert period updated cellids to node numbers.
655  !!
656  !<
657  subroutine cellid_to_nlist(this)
658  ! -- modules
659  use simvariablesmodule, only: errmsg
660  ! -- dummy
661  class(bndexttype) :: this !< BndExtType object
662  ! -- local
663  integer(I4B), dimension(:), pointer :: cellid
664  integer(I4B) :: n, nodeu, noder
665  character(len=LINELENGTH) :: nodestr
666  !
667  ! -- update nodelist
668  do n = 1, this%nbound
669  !
670  ! -- set cellid
671  cellid => this%cellid(:, n)
672  !
673  ! -- ensure cellid is valid, store an error otherwise
674  call this%check_cellid(n, cellid, this%dis%mshape, this%dis%ndim)
675  !
676  ! -- Determine user node number
677  if (this%dis%ndim == 1) then
678  nodeu = cellid(1)
679  elseif (this%dis%ndim == 2) then
680  nodeu = get_node(cellid(1), 1, cellid(2), &
681  this%dis%mshape(1), 1, &
682  this%dis%mshape(2))
683  else
684  nodeu = get_node(cellid(1), cellid(2), cellid(3), &
685  this%dis%mshape(1), &
686  this%dis%mshape(2), &
687  this%dis%mshape(3))
688  end if
689  !
690  ! -- update the nodelist
691  if (this%dis%nodes < this%dis%nodesuser) then
692  ! -- convert user to reduced node numbers
693  noder = this%dis%get_nodenumber(nodeu, 0)
694  if (noder <= 0) then
695  call this%dis%nodeu_to_string(nodeu, nodestr)
696  write (errmsg, *) &
697  ' Cell is outside active grid domain: '// &
698  trim(adjustl(nodestr))
699  call store_error(errmsg)
700  end if
701  this%nodelist(n) = noder
702  else
703  this%nodelist(n) = nodeu
704  end if
705  end do
706  !
707  ! -- exit if errors were found
708  if (count_errors() > 0) then
709  write (errmsg, *) count_errors(), ' errors encountered.'
710  call store_error(errmsg)
711  call store_error_filename(this%input_fname)
712  end if
713  end subroutine cellid_to_nlist
714 
715  !> @ brief Update package nodelist
716  !!
717  !! Convert period user nodes to reduced nodes
718  !!
719  !<
720  subroutine nodeu_to_nlist(this)
721  ! -- modules
723  ! -- dummy
724  class(bndexttype) :: this !< BndExtType object
725  integer(I4B) :: n, noder, nodeuser, ninactive
726 
727  ninactive = 0
728 
729  ! -- Set the nodelist
730  do n = 1, this%nbound
731  nodeuser = this%nodeulist(n)
732  noder = this%dis%get_nodenumber(nodeuser, 0)
733  if (noder > 0) then
734  this%nodelist(n) = noder
735  else
736  ninactive = ninactive + 1
737  end if
738  end do
739 
740  ! update nbound
741  this%nbound = this%nbound - ninactive
742  end subroutine nodeu_to_nlist
743 
744  !> @brief Update the nodelist based on layer number variable input
745  !!
746  !! This is a module scoped routine to check for I<filtyp>
747  !! input. If array input was provided, INI<filtyp> and I<filtyp>
748  !! will be allocated in the input context. If the read
749  !! state variable INI<filtyp> is set to 1 during this period
750  !! update, I<filtyp> input was read and is used here to update
751  !! the nodelist.
752  !!
753  !<
754  subroutine layarr_to_nlist(this)
755  ! -- modules
757  use constantsmodule, only: lenvarname
758  ! -- dummy
759  class(bndexttype) :: this !< BndExtType object
760  character(len=LENVARNAME) :: ilayname, inilayname
761  character(len=24) :: aname = ' LAYER OR NODE INDEX'
762  ! -- local
763  integer(I4B), dimension(:), contiguous, &
764  pointer :: ilay => null()
765  integer(I4B), pointer :: inilay => null()
766  !
767  ! set ilay and read state variable names
768  ilayname = 'I'//trim(this%filtyp)
769  inilayname = 'INI'//trim(this%filtyp)
770  !
771  ! -- set pointer to input context read state variable
772  call mem_setptr(inilay, inilayname, this%input_mempath)
773  !
774  ! -- check read state
775  if (inilay == 1) then
776  ! -- ilay variable was read this period
777  !
778  ! -- set pointer to input context layer index variable
779  call mem_setptr(ilay, ilayname, this%input_mempath)
780  !
781  ! -- update nodelist
782  call this%dis%nlarray_to_nodelist(ilay, this%nodelist, this%maxbound, &
783  this%nbound, aname)
784  end if
785  end subroutine layarr_to_nlist
786 
787  !> @brief Assign default nodelist when READASARRAYS is specified.
788  !!
789  !! Equivalent to reading layer number array as CONSTANT 1
790  !<
791  subroutine default_nodelist(this)
792  ! -- dummy
793  class(bndexttype) :: this
794  ! -- local
795  integer(I4B) :: il, ir, ic, ncol, nrow, nlay, nodeu, noder, ipos
796  !
797  if (this%readasarrays) then
798  !
799  ! -- set variables
800  if (this%dis%ndim == 3) then
801  nlay = this%dis%mshape(1)
802  nrow = this%dis%mshape(2)
803  ncol = this%dis%mshape(3)
804  elseif (this%dis%ndim == 2) then
805  nlay = this%dis%mshape(1)
806  nrow = 1
807  ncol = this%dis%mshape(2)
808  end if
809  !
810  ! -- Populate nodelist
811  ipos = 1
812  il = 1
813  do ir = 1, nrow
814  do ic = 1, ncol
815  nodeu = get_node(il, ir, ic, nlay, nrow, ncol)
816  noder = this%dis%get_nodenumber(nodeu, 0)
817  this%nodelist(ipos) = noder
818  ipos = ipos + 1
819  end do
820  end do
821  !
822  ! -- Assign nbound
823  this%nbound = ipos - 1
824  end if
825  end subroutine default_nodelist
826 
827  !> @ brief Check for valid cellid
828  !<
829  subroutine check_cellid(this, ii, cellid, mshape, ndim)
830  ! -- modules
831  use simvariablesmodule, only: errmsg
832  ! -- dummy
833  class(bndexttype) :: this !< BndExtType object
834  ! -- local
835  integer(I4B), intent(in) :: ii
836  integer(I4B), dimension(:), intent(in) :: cellid !< cellid
837  integer(I4B), dimension(:), intent(in) :: mshape !< model shape
838  integer(I4B), intent(in) :: ndim !< size of mshape
839  character(len=20) :: cellstr, mshstr
840  character(len=*), parameter :: fmterr = &
841  "('List entry ',i0,' contains cellid ',a,' but this cellid is invalid &
842  &for model with shape ', a)"
843  character(len=*), parameter :: fmtndim1 = &
844  "('(',i0,')')"
845  character(len=*), parameter :: fmtndim2 = &
846  "('(',i0,',',i0,')')"
847  character(len=*), parameter :: fmtndim3 = &
848  "('(',i0,',',i0,',',i0,')')"
849  select case (ndim)
850  case (1)
851  !
852  if (cellid(1) < 1 .or. cellid(1) > mshape(1)) then
853  write (cellstr, fmtndim1) cellid(1)
854  write (mshstr, fmtndim1) mshape(1)
855  write (errmsg, fmterr) ii, trim(adjustl(cellstr)), trim(adjustl(mshstr))
856  call store_error(errmsg)
857  end if
858  !
859  case (2)
860  !
861  if (cellid(1) < 1 .or. cellid(1) > mshape(1) .or. &
862  cellid(2) < 1 .or. cellid(2) > mshape(2)) then
863  write (cellstr, fmtndim2) cellid(1), cellid(2)
864  write (mshstr, fmtndim2) mshape(1), mshape(2)
865  write (errmsg, fmterr) ii, trim(adjustl(cellstr)), trim(adjustl(mshstr))
866  call store_error(errmsg)
867  end if
868  !
869  case (3)
870  !
871  if (cellid(1) < 1 .or. cellid(1) > mshape(1) .or. &
872  cellid(2) < 1 .or. cellid(2) > mshape(2) .or. &
873  cellid(3) < 1 .or. cellid(3) > mshape(3)) then
874  write (cellstr, fmtndim3) cellid(1), cellid(2), cellid(3)
875  write (mshstr, fmtndim3) mshape(1), mshape(2), mshape(3)
876  write (errmsg, fmterr) ii, trim(adjustl(cellstr)), trim(adjustl(mshstr))
877  call store_error(errmsg)
878  end if
879  !
880  case default
881  end select
882  end subroutine check_cellid
883 
884  !> @ brief Log package stress period input
885  !!
886  !! Log period based input. This routine requires a package specific
887  !! bound_value() routine to report accurate bound values.
888  !!
889  !<
890  subroutine write_lstfile(this)
891  ! -- modules
894  use inputoutputmodule, only: ulstlb
895  use tablemodule, only: tabletype, table_cr
896  ! -- dummy
897  class(bndexttype) :: this !< BndExtType object
898  ! -- local
899  character(len=10) :: cpos
900  character(len=LINELENGTH) :: tag
901  character(len=LINELENGTH), allocatable, dimension(:) :: words
902  integer(I4B) :: ntabrows
903  integer(I4B) :: ntabcols
904  integer(I4B) :: ipos
905  integer(I4B) :: ii, jj, i, j, k, nod
906  integer(I4B) :: ldim
907  integer(I4B) :: naux
908  type(tabletype), pointer :: inputtab => null()
909  ! -- formats
910  character(len=LINELENGTH) :: fmtlstbn
911  !
912  ! -- Determine sizes
913  ldim = this%ncolbnd
914  naux = size(this%auxvar, 1)
915  !
916  ! -- dimension table
917  ntabrows = this%nbound
918  !
919  ! -- start building format statement to parse this%label, which
920  ! contains the column headers (except for boundname and auxnames)
921  ipos = index(this%listlabel, 'NO.')
922  if (ipos /= 0) then
923  write (cpos, '(i10)') ipos + 3
924  fmtlstbn = '(a'//trim(adjustl(cpos))
925  else
926  fmtlstbn = '(a7'
927  end if
928  ! -- sequence number, layer, row, and column.
929  if (size(this%dis%mshape) == 3) then
930  ntabcols = 4
931  fmtlstbn = trim(fmtlstbn)//',a7,a7,a7'
932  !
933  ! -- sequence number, layer, and cell2d.
934  else if (size(this%dis%mshape) == 2) then
935  ntabcols = 3
936  fmtlstbn = trim(fmtlstbn)//',a7,a7'
937  !
938  ! -- sequence number and node.
939  else
940  ntabcols = 2
941  fmtlstbn = trim(fmtlstbn)//',a7'
942  end if
943  !
944  ! -- Add fields for non-optional real values
945  ntabcols = ntabcols + ldim
946  do i = 1, ldim
947  fmtlstbn = trim(fmtlstbn)//',a16'
948  end do
949  !
950  ! -- Add field for boundary name
951  if (this%inamedbound == 1) then
952  ntabcols = ntabcols + 1
953  fmtlstbn = trim(fmtlstbn)//',a16'
954  end if
955  !
956  ! -- Add fields for auxiliary variables
957  ntabcols = ntabcols + naux
958  do i = 1, naux
959  fmtlstbn = trim(fmtlstbn)//',a16'
960  end do
961  fmtlstbn = trim(fmtlstbn)//')'
962  !
963  ! -- allocate words
964  allocate (words(ntabcols))
965  !
966  ! -- parse this%listlabel into words
967  read (this%listlabel, fmtlstbn) (words(i), i=1, ntabcols)
968  !
969  ! -- initialize the input table object
970  call table_cr(inputtab, ' ', ' ')
971  call inputtab%table_df(ntabrows, ntabcols, this%iout)
972  !
973  ! -- add the columns
974  ipos = 1
975  call inputtab%initialize_column(words(ipos), 10, alignment=tabcenter)
976  !
977  ! -- discretization
978  do i = 1, size(this%dis%mshape)
979  ipos = ipos + 1
980  call inputtab%initialize_column(words(ipos), 7, alignment=tabcenter)
981  end do
982  !
983  ! -- non-optional variables
984  do i = 1, ldim
985  ipos = ipos + 1
986  call inputtab%initialize_column(words(ipos), 16, alignment=tabcenter)
987  end do
988  !
989  ! -- boundname
990  if (this%inamedbound == 1) then
991  ipos = ipos + 1
992  tag = 'BOUNDNAME'
993  call inputtab%initialize_column(tag, lenboundname, alignment=tableft)
994  end if
995  !
996  ! -- aux variables
997  do i = 1, naux
998  call inputtab%initialize_column(this%auxname(i), 16, alignment=tabcenter)
999  end do
1000  !
1001  ! -- Write the table
1002  do ii = 1, this%nbound
1003  call inputtab%add_term(ii)
1004  !
1005  ! -- discretization
1006  if (size(this%dis%mshape) == 3) then
1007  nod = this%nodelist(ii)
1008  call get_ijk(nod, this%dis%mshape(2), this%dis%mshape(3), &
1009  this%dis%mshape(1), i, j, k)
1010  call inputtab%add_term(k)
1011  call inputtab%add_term(i)
1012  call inputtab%add_term(j)
1013  else if (size(this%dis%mshape) == 2) then
1014  nod = this%nodelist(ii)
1015  call get_ijk(nod, 1, this%dis%mshape(2), this%dis%mshape(1), i, j, k)
1016  call inputtab%add_term(k)
1017  call inputtab%add_term(j)
1018  else
1019  nod = this%nodelist(ii)
1020  call inputtab%add_term(nod)
1021  end if
1022  !
1023  ! -- non-optional variables
1024  do jj = 1, ldim
1025  call inputtab%add_term(this%bound_value(jj, ii))
1026  end do
1027  !
1028  ! -- boundname
1029  if (this%inamedbound == 1) then
1030  call inputtab%add_term(this%boundname(ii))
1031  end if
1032  !
1033  ! -- aux variables
1034  do jj = 1, naux
1035  call inputtab%add_term(this%auxvar(jj, ii))
1036  end do
1037  end do
1038  !
1039  ! -- deallocate the local variables
1040  call inputtab%table_da()
1041  deallocate (inputtab)
1042  nullify (inputtab)
1043  deallocate (words)
1044  end subroutine write_lstfile
1045 
1046  !> @ brief Return a bound value
1047  !!
1048  !! Return a bound value associated with an ncolbnd index
1049  !! and row. This function should be overridden in the
1050  !! derived package class.
1051  !!
1052  !<
1053  function bound_value(this, col, row) result(bndval)
1054  ! -- modules
1055  use constantsmodule, only: dnodata
1056  ! -- dummy variables
1057  class(bndexttype), intent(inout) :: this !< BndExtType object
1058  integer(I4B), intent(in) :: col
1059  integer(I4B), intent(in) :: row
1060  ! -- result
1061  real(dp) :: bndval
1062  !
1063  ! -- override this return value by redefining this
1064  ! routine in the derived package.
1065  bndval = dnodata
1066  end function bound_value
1067 
1068 end module bndextmodule
This module contains the extended boundary package.
subroutine bndext_ad(this)
Advance the package one time step.
integer(i4b) function validate_ifno(this, ifno_val, nfeatures, nboundchk, feature_label, blockname)
@ brief Validate a list-input row's IFNO and update the per-feature coverage counter
subroutine bndext_rp(this)
subroutine bndext_allocate_arrays(this, nodelist, auxvar)
@ brief Allocate package arrays
subroutine bndext_rp_log(this)
Write the input list to the listing file if requested.
subroutine bndext_df(this, neq, dis)
@ brief Define boundary package options and dimensions
subroutine bndext_da(this)
@ brief Deallocate package memory
subroutine allocate_featureauxvar(this)
Point the per-feature auxiliary variable array at the input context's permanent, feature-indexed AUX ...
subroutine default_nodelist(this)
Assign default nodelist when READASARRAYS is specified.
subroutine write_lstfile(this)
@ brief Log package stress period input
subroutine report_ifno_coverage(this, nboundchk, nfeatures, feature_label, blockname, check_missing)
@ brief Report missing or duplicate list-input rows for each feature
subroutine log_options(this, found, sfacauxname)
@ brief Log package options
subroutine cellid_to_nlist(this)
@ brief Update package nodelist
subroutine source_dimensions(this)
@ brief Source package dimensions from input context
subroutine check_cellid(this, ii, cellid, mshape, ndim)
@ brief Check for valid cellid
subroutine nodeu_to_nlist(this)
@ brief Update package nodelist
subroutine layarr_to_nlist(this)
Update the nodelist based on layer number variable input.
real(dp) function bound_value(this, col, row)
@ brief Return a bound value
subroutine source_options(this)
@ brief Source package options from input context
subroutine bndext_allocate_scalars(this)
@ brief Allocate package scalars
This module contains the base boundary package.
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
@ tabcenter
centered table column
Definition: Constants.f90:173
@ tableft
left justified table column
Definition: Constants.f90:172
real(dp), parameter dnodata
real no data constant
Definition: Constants.f90:95
integer(i4b), parameter lenvarname
maximum length of a variable name
Definition: Constants.f90:17
integer(i4b), parameter lenauxname
maximum length of a aux variable
Definition: Constants.f90:35
integer(i4b), parameter lenboundname
maximum length of a bound name
Definition: Constants.f90:36
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
integer(i4b), parameter lenmempath
maximum length of the memory path
Definition: Constants.f90:27
integer(i4b) function, public get_node(ilay, irow, icol, nlay, nrow, ncol)
Get node number, given layer, row, and column indices for a structured grid. If any argument is inval...
Definition: GeomUtil.f90:92
subroutine, public get_ijk(nodenumber, nrow, ncol, nlay, irow, icol, ilay)
Get row, column and layer indices from node number and grid dimensions. If nodenumber is invalid,...
Definition: GeomUtil.f90:109
integer(i4b) function, public getunit()
Get a free unit number.
subroutine, public ulstlb(iout, label, caux, ncaux, naux)
Print a label for a list.
subroutine, public openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, filstat_opt, mode_opt)
Open a file.
Definition: InputOutput.f90:30
This module defines variable data types.
Definition: kind.f90:8
subroutine, public get_isize(name, mem_path, isize)
@ brief Get the number of elements for this variable
This module contains the derived type ObsType.
Definition: Obs.f90:127
subroutine, public obs_cr(obs, inobs)
@ brief Create a new ObsType object
Definition: Obs.f90:225
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
integer(i4b) function, public count_errors()
Return number of errors.
Definition: Sim.f90:59
subroutine, public store_error_filename(filename, terminate)
Store the erroring file name.
Definition: Sim.f90:204
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string
This module contains the SourceCommonModule.
Definition: SourceCommon.f90:7
logical(lgp) function, public filein_fname(filename, tagname, input_mempath, input_fname)
enforce and set a single input filename provided via FILEIN keyword
subroutine, public table_cr(this, name, title)
Definition: Table.f90:87
integer(i4b), pointer, public kper
current stress period number
Definition: tdis.f90:26
subroutine, public tasmanager_cr(this, dis, modelname, iout)
Create the time-array series manager.
subroutine, public tsmanager_cr(this, iout, removeTsLinksOnCompletion, extendTsToEndOfSimulation)
Create the tsmanager.
@ brief BndType
This class is used to store a single deferred-length character string. It was designed to work in an ...
Definition: CharString.f90:23