MODFLOW 6  version 6.9.0.dev0
USGS Modular Hydrologic Model
LoadContext.f90
Go to the documentation of this file.
1 !> @brief Load context for IDM generic dynamic loaders.
2 !!
3 !! LoadContextType classifies each input, builds the in-scope parameter
4 !! list for the active block, and manages memory-manager dimension scalars
5 !! and array pointers. It is used by all dynamic loaders: ListLoadType,
6 !! KeystringLoadType, LayerArrayLoadType, GridArrayLoadType, and
7 !! StructArray-based static loads.
8 !!
9 !<
11 
12  use kindmodule, only: dp, i4b, lgp
15  use simvariablesmodule, only: errmsg
16  use simmodule, only: store_error
21 
22  implicit none
23  private
24  public :: loadcontexttype
25  public :: readstatevartype
26  public :: rsv_name
27  public :: is_keystring_period
28  public :: is_feature_keystring
29  public :: is_advanced
30 
31  enum, bind(C)
32  enumerator :: load_undef = 0 !< undefined load type
33  enumerator :: list = 1 !< list load
34  enumerator :: layerarray = 2 !< readasarrays load
35  enumerator :: gridarray = 3 !< readarraygrid load
36  enumerator :: keystring = 4 !< keystring period block load
37  end enum
38 
39  !> @brief Pointer type for read state variable
40  !<
42  integer(I4B), pointer :: invar
43  end type readstatevartype
44 
45  interface setptr
46  module procedure setptr_int, setptr_charstr1d, &
48  end interface setptr
49 
50  ! addressing modes for an applied keystring setting
51  integer(I4B), parameter, public :: addr_none = 0 !< not an applied setting
52  integer(I4B), parameter, public :: addr_feature = 1 !< addressed by leading id (IFNO/BNDNO)
53  integer(I4B), parameter, public :: addr_node = 2 !< addressed by CELLID
54  integer(I4B), parameter, public :: addr_subindex = 3 !< addressed by (id, subindex)
55 
56  !> @brief One descriptor per expanded keystring item, so loaders iterate
57  !! uniformly instead of re-deriving per-mode state.
58  !<
59  type, public :: keystringitemtype
60  type(inputparamdefinitiontype), pointer :: idt => null() !< input definition
61  integer(I4B) :: sa_icol = 0 !< struct-array column (SETTING offset resolved)
62  logical(LGP) :: is_body = .false. !< RECORD body (non-head)
63  integer(I4B) :: head_nbody = 0 !< if a head: number of body members; else 0
64  character(len=LENVARNAME) :: head_setting_varname = '' !< body: owning head's SETTING keyword (dispatch key); '' otherwise
65  logical(LGP) :: idm_managed = .false. !< IDM allocates+applies a permanent array
66  integer(I4B) :: addr_mode = addr_none !< how a row resolves to an index
67  real(dp) :: init_value = dzero !< DZERO (feature/SPC) | DNODATA (node)
68  integer(I4B) :: nfeatures = 0 !< permanent-array length (per-item; LAK lake/outlet)
69  end type keystringitemtype
70 
71  !> @brief Input load context for generic dynamic loaders and StructArray
72  !! based static loads. Classifies the input, determines in-scope
73  !! parameters, and manages memory-manager scalars and array pointers.
74  !<
76  ! memory-manager dimension/option scalars and arrays
77  integer(I4B), pointer :: naux => null() !< number of auxiliary variables
78  integer(I4B), pointer :: maxbound => null() !< value associated with named_bound
79  integer(I4B), pointer :: boundnames => null() !< are bound names optioned
80  integer(I4B), pointer :: iprpak => null() !< print input option
81  integer(I4B), pointer :: nbound => null() !< number of bounds in period
82  integer(I4B), pointer :: ncpl => null() !< ncpl associated with model shape
83  integer(I4B), pointer :: nodes => null() !< nodes associated with model shape
84  integer(I4B), dimension(:), pointer, contiguous :: mshape => null() !< model shape
85  type(characterstringtype), dimension(:), pointer, &
86  contiguous :: auxname_cst => null() !< array of auxiliary names
87  type(characterstringtype), dimension(:), pointer, &
88  contiguous :: boundname_cst => null() !< array of bound names
89  real(dp), dimension(:, :), pointer, &
90  contiguous :: auxvar => null() !< auxiliary variable array
91  ! classification
92  integer(I4B) :: loadtype !< load type enum: LIST, LAYERARRAY, GRIDARRAY, KEYSTRING
93  logical(LGP) :: set_scalars = .false. !< .true. when dimension scalars must be set
94  logical(LGP) :: set_mshape = .false. !< .true. when model shape is load dependency
95  logical(LGP) :: is_exchange = .false. !< .true. for exchange contexts
96  logical(LGP) :: is_advanced = .false. !< .true. for an advanced package, any loadtype
97  ! input handle and in-scope params
98  character(len=LENVARNAME) :: blockname !< load block name
99  character(len=LENVARNAME) :: named_bound !< name of dimension variable for maxbound; defaults to MAXBOUND
100  integer(I4B) :: nleading = 0 !< count of leading (pre-keystring) columns
101  character(len=LINELENGTH), dimension(:), allocatable :: params !< in-scope param tagnames
102  type(modflowinputtype) :: mf6_input !< description of input
103  ! keystring-specific (only set for KEYSTRING loads)
104  logical(LGP) :: keystring_by_feature = .false. !< .true. for feature-addressed (IFNO/NUMBER/BNDNO) KEYSTRING loadtype
105  logical(LGP) :: keystring_by_node = .false. !< .true. for CELLID-addressed (e.g. TVK/TVS) KEYSTRING loadtype
106  logical(LGP) :: has_setting_dispatch = .false. !< .true. when keystring_by_feature .or. keystring_by_node
107  type(inputparamdefinitiontype), pointer :: setting_idt => null() !< internal idt for SETTING column
108  integer(I4B) :: nkeystring_items = 0 !< count of expanded keystring items (0 for non-keystring)
109  type(keystringitemtype), allocatable :: keystring_items(:)
110  character(len=LENVARNAME) :: feature_id_varname = '' !< leading id column mf6varname (feature-addressed)
111  contains
112  ! --- public interface ---
113  procedure :: init
114  procedure :: allocate_arrays
115  procedure :: allocate_params
116  procedure :: rsv_alloc
117  procedure :: destroy
118  ! --- internal ---
119  procedure, private :: resolve_context
120  procedure, private :: resolve_loadtype
121  procedure, private :: set_params
122  procedure, private :: keystring_item_names
123  procedure, private :: resolve_dimensions
124  procedure, private :: scale_keystring_maxbound
125  procedure, private :: allocate_param
126  procedure :: check_developmode
127  procedure, private :: in_scope
128  procedure :: subindex_dependency
129  procedure, private :: option_check
131  procedure, private :: resolve_nfeatures
133  procedure, private :: shape_param_is_array
134  end type loadcontexttype
135 
136 contains
137 
138  !> @brief Initialize the load context.
139  !!
140  !! Classifies the input, builds the in-scope parameter list,
141  !! and resolves memory-manager dimension scalars.
142  !<
143  subroutine init(this, mf6_input, blockname, named_bound)
144  use inputoutputmodule, only: upcase
145  class(loadcontexttype) :: this
146  type(modflowinputtype), intent(in) :: mf6_input
147  character(len=*), optional, intent(in) :: blockname
148  character(len=*), optional, intent(in) :: named_bound
149 
150  this%mf6_input = mf6_input
151 
152  if (present(blockname)) then
153  this%blockname = blockname
154  call upcase(this%blockname)
155  else
156  this%blockname = 'PERIOD'
157  end if
158 
159  if (present(named_bound)) then
160  this%named_bound = named_bound
161  call upcase(this%named_bound)
162  else
163  this%named_bound = 'MAXBOUND'
164  end if
165 
166  call this%resolve_context()
167  call this%resolve_loadtype()
168  call this%set_params()
169  call this%resolve_dimensions()
170  ! build the per-item descriptor table (keystring only)
171  if (this%loadtype == keystring) call this%build_keystring_items()
172  end subroutine init
173 
174  !> @brief Set context flags from input load_scope and component metadata.
175  !<
176  subroutine resolve_context(this)
177  class(loadcontexttype) :: this
178 
179  this%set_scalars = .false.
180  this%set_mshape = .false.
181  this%is_exchange = .false.
182 
183  select case (this%mf6_input%load_scope)
184  case ('ROOT')
185  ! no memory setup needed for root context
186  case ('SIM')
187  ! only exchange inputs need scalar setup under SIM scope
188  if (this%mf6_input%component_type == 'EXG') then
189  this%set_scalars = .true.
190  this%is_exchange = .true.
191  end if
192  case ('MODEL')
193  this%set_scalars = .true.
194  ! OC and STO are model packages without period block stress data
195  if (this%mf6_input%subcomponent_type /= 'OC' .and. &
196  this%mf6_input%subcomponent_type /= 'STO') then
197  this%set_mshape = .true.
198  end if
199  case default
200  errmsg = 'LoadContext unrecognized load_scope for mempath: '// &
201  trim(this%mf6_input%mempath)
202  call store_error(errmsg, .true.)
203  end select
204  end subroutine resolve_context
205 
206  !> @brief Determine loadtype from block and param definitions.
207  !<
208  subroutine resolve_loadtype(this)
211  class(loadcontexttype) :: this
212  type(inputparamdefinitiontype), pointer :: idt, aidt
213  character(len=LINELENGTH), dimension(:), allocatable :: cols
214  integer(I4B) :: n, nparam
215 
216  this%loadtype = load_undef
217 
218  ! detect aggregate (list/keystring) load type
219  do n = 1, size(this%mf6_input%block_dfns)
220  if (this%mf6_input%block_dfns(n)%blockname == this%blockname) then
221  if (this%mf6_input%block_dfns(n)%aggregate) then
222  if (this%blockname == 'PERIOD' .and. &
223  is_keystring_period(this%mf6_input)) then
224  this%loadtype = keystring
225  else
226  this%loadtype = list
227  end if
228  exit
229  end if
230  end if
231  end do
232 
233  this%is_advanced = is_advanced(this%mf6_input)
234 
235  ! classify by the KEYSTRING aggregate's own leading column
236  if (this%loadtype == keystring) then
237  aidt => &
238  get_aggregate_definition_type(this%mf6_input%aggregate_dfns, &
239  this%mf6_input%component_type, &
240  this%mf6_input%subcomponent_type, &
241  this%blockname)
242  call idt_parse_rectype(aidt, cols, nparam)
243  if (is_feature_tag(cols(1))) then
244  this%keystring_by_feature = .true.
245  else if (cols(1) == 'CELLID') then
246  this%keystring_by_node = .true.
247  end if
248  if (allocated(cols)) deallocate (cols)
249  this%has_setting_dispatch = &
250  this%keystring_by_feature .or. this%keystring_by_node
251  if (this%has_setting_dispatch) then
252  this%setting_idt => &
253  idt_default(this%mf6_input%component_type, &
254  this%mf6_input%subcomponent_type, &
255  this%blockname, 'SETTING', 'SETTING', 'STRING')
256  end if
257  end if
258 
259  ! detect array-based load
260  if (this%loadtype == load_undef) then
261  do n = 1, size(this%mf6_input%param_dfns)
262  idt => this%mf6_input%param_dfns(n)
263  if (idt%blockname == 'OPTIONS') then
264  select case (idt%tagname)
265  case ('READASARRAYS')
266  this%loadtype = layerarray
267  case ('READARRAYGRID')
268  this%loadtype = gridarray
269  case default
270  ! no-op
271  end select
272  end if
273  end do
274  end if
275  end subroutine resolve_loadtype
276 
277  !> @brief Resolve dimension scalars and scale keystring maxbound.
278  !<
279  subroutine resolve_dimensions(this)
281  class(loadcontexttype) :: this
282 
283  if (this%set_scalars) then
284 
285  call setptr(this%nbound, 'NBOUND', this%mf6_input%mempath)
286  call setval(this%naux, 'NAUX', this%mf6_input%mempath)
287  call setval(this%ncpl, 'NCPL', this%mf6_input%mempath)
288  call setval(this%nodes, 'NODES', this%mf6_input%mempath)
289  call setval(this%boundnames, 'BOUNDNAMES', this%mf6_input%mempath)
290  call setval(this%iprpak, 'IPRPAK', this%mf6_input%mempath)
291  call setval(this%maxbound, this%named_bound, this%mf6_input%mempath)
292 
293  ! reset nbound
294  this%nbound = 0
295  end if
296 
297  if (this%set_mshape .and. &
298  this%blockname == 'PERIOD') then
299  call mem_setptr(this%mshape, 'MODEL_SHAPE', &
300  this%mf6_input%component_mempath)
301 
302  if (this%ncpl == 0) then
303  if (size(this%mshape) == 2) then
304  this%ncpl = this%mshape(2)
305  else if (size(this%mshape) == 3) then
306  this%ncpl = this%mshape(2) * this%mshape(3)
307  end if
308  end if
309 
310  if (this%nodes == 0) this%nodes = product(this%mshape)
311  if (this%loadtype == keystring) call this%scale_keystring_maxbound()
312  end if
313  end subroutine resolve_dimensions
314 
315  !> @brief Scale maxbound (a feature or node count) by the number of
316  !! KEYSTRING items, so every feature can use every setting in one
317  !! period.
318  !<
319  subroutine scale_keystring_maxbound(this)
320  class(loadcontexttype) :: this
321  integer(I4B) :: nkeystring_items
322 
323  nkeystring_items = this%nkeystring_items
324 
325  if (nkeystring_items > 0) then
326  if (this%maxbound == 0) then
327  if (.not. this%keystring_by_feature) then
328  this%maxbound = this%nodes * nkeystring_items
329  end if
330  ! else: feature-addressed, genuinely zero stays 0
331  else
332  this%maxbound = this%maxbound * nkeystring_items
333  end if
334  end if
335  end subroutine scale_keystring_maxbound
336 
337  !> @brief allocate arrays
338  !!
339  !! Call after input parameters are allocated: after load_params() with
340  !! create for array-based loaders, or after all mem_create_vector()
341  !! calls for list-based load.
342  !<
343  subroutine allocate_arrays(this)
345  class(loadcontexttype) :: this
346  integer(I4B), dimension(:, :), pointer, contiguous :: cellid
347  integer(I4B), dimension(:), pointer, contiguous :: nodeulist
348 
349  if (this%set_mshape .and. &
350  this%blockname == 'PERIOD') then
351  ! allocate cellid if this is not list input
352  if (this%loadtype == layerarray .or. &
353  this%loadtype == gridarray) then
354  call mem_allocate(cellid, 0, 0, 'CELLID', this%mf6_input%mempath)
355  end if
356 
357  ! allocate nodeulist for list and layerarray packages only;
358  ! keystring and advanced packages do not use a flat nodeulist
359  if (this%loadtype /= gridarray .and. &
360  this%loadtype /= keystring) then
361  call mem_allocate(nodeulist, 0, 'NODEULIST', this%mf6_input%mempath)
362  end if
363 
364  ! set pointers to aux/bound arrays for non-keystring packages;
365  ! keystring packages manage aux through struct array columns
366  if (this%loadtype /= keystring) then
367  call setptr(this%auxname_cst, 'AUXILIARY', &
368  this%mf6_input%mempath, lenauxname)
369  call setptr(this%boundname_cst, 'BOUNDNAME', &
370  this%mf6_input%mempath, lenboundname)
371  call setptr(this%auxvar, this%mf6_input%mempath)
372  end if
373 
374  else if (this%is_exchange) then
375  ! set pointers to arrays
376  call setptr(this%auxname_cst, 'AUXILIARY', &
377  this%mf6_input%mempath, lenauxname)
378  call setptr(this%boundname_cst, 'BOUNDNAME', &
379  this%mf6_input%mempath, lenboundname)
380  call setptr(this%auxvar, this%mf6_input%mempath)
381  end if
382  end subroutine allocate_arrays
383 
384  !> @brief allocate a package dynamic input parameter
385  !!
386  !! Called only from allocate_params(), itself called only by the
387  !! LAYERARRAY/GRIDARRAY loaders -- this%loadtype is never LIST here.
388  !<
389  subroutine allocate_param(this, idt)
391  class(loadcontexttype) :: this
392  type(inputparamdefinitiontype), pointer :: idt
393  integer(I4B) :: dimsize
394 
395  ! initialize
396  dimsize = 0
397 
398  if (this%loadtype == layerarray .or. &
399  this%loadtype == gridarray) then
400  select case (idt%shape)
401  case ('NCPL', 'NAUX NCPL')
402  dimsize = this%ncpl
403  case ('NODES', 'NAUX NODES')
404  dimsize = this%maxbound
405  case default
406  end select
407  end if
408 
409  select case (idt%datatype)
410  case ('INTEGER1D')
411  if (this%loadtype == layerarray .or. &
412  this%loadtype == gridarray) then
413  call allocate_int1d(dimsize, idt%mf6varname, &
414  this%mf6_input%mempath)
415  end if
416  case ('DOUBLE1D')
417  if (idt%shape == 'NAUX') then
418  call allocate_dbl2d(this%naux, this%maxbound, &
419  idt%mf6varname, this%mf6_input%mempath)
420  else if (this%loadtype == layerarray .or. &
421  this%loadtype == gridarray) then
422  call allocate_dbl1d(dimsize, idt%mf6varname, &
423  this%mf6_input%mempath)
424  end if
425  case ('DOUBLE2D')
426  if (this%loadtype == layerarray .or. &
427  this%loadtype == gridarray) then
428  call allocate_dbl2d(this%naux, dimsize, idt%mf6varname, &
429  this%mf6_input%mempath)
430  end if
431  case default
432  end select
433  end subroutine allocate_param
434 
435  !> @brief Allocate each in-scope parameter in the memory manager.
436  !!
437  !! Call after init() for array-based loaders (LAYERARRAY, GRIDARRAY) that
438  !! need memory-manager storage allocated for every in-scope parameter.
439  !! Loaders access this%params and size(this%params) directly.
440  !<
441  subroutine allocate_params(this)
443  class(loadcontexttype) :: this
444  type(inputparamdefinitiontype), pointer :: idt
445  integer(I4B) :: n
446  do n = 1, size(this%params)
447  idt => get_param_definition_type(this%mf6_input%param_dfns, &
448  this%mf6_input%component_type, &
449  this%mf6_input%subcomponent_type, &
450  this%blockname, this%params(n), '')
451  call this%allocate_param(idt)
452  end do
453  end subroutine allocate_params
454 
455  !> @brief Return .true. if an optional parameter is active for this load.
456  !! Required/structural params are handled by the caller; generic
457  !! conditions are checked first, then package-specific ones by
458  !! subcomponent_type.
459  !<
460  function in_scope(this, tagname)
462  class(loadcontexttype) :: this
463  character(len=*), intent(in) :: tagname
464  logical(LGP) :: in_scope
465  type(inputparamdefinitiontype), pointer :: idt
466  character(len=LINELENGTH) :: datatype
467 
468  idt => get_param_definition_type(this%mf6_input%param_dfns, &
469  this%mf6_input%component_type, &
470  this%mf6_input%subcomponent_type, &
471  this%blockname, tagname, '')
472  ! required params are always in scope
473  if (idt%required) then
474  in_scope = .true.
475  return
476  else
477  in_scope = .false.
478  end if
479 
480  ! structural container types are never loaded as leaf params
481  datatype = idt_datatype(idt)
482  if (datatype == 'KEYSTRING' .or. &
483  datatype == 'RECARRAY' .or. &
484  datatype == 'RECORD') return
485 
486  ! advanced packages: every optional leaf param is in scope
487  if (this%is_advanced) then
488  in_scope = .true.
489  return
490  end if
491 
492  ! --- generic conditions ---
493  if (tagname == 'AUXVAR' .or. tagname == 'AUX') then
494  in_scope = this%option_check('NAUX', 0)
495  return
496  end if
497 
498  if (tagname == 'BOUNDNAME') then
499  in_scope = this%option_check('BOUNDNAMES', 0)
500  return
501  end if
502 
503  ! readarray indicator variable (e.g. IRCH, IRET): in scope for LAYERARRAY only
504  if (tagname == 'I'//trim(this%mf6_input%subcomponent_type(1:3))) then
505  in_scope = (this%loadtype == layerarray)
506  return
507  end if
508 
509  ! --- package-specific conditions ---
510  select case (this%mf6_input%subcomponent_type)
511  case ('EVT')
512  if (tagname == 'PXDP' .or. tagname == 'PETM') then
513  in_scope = this%option_check('NSEG', 1)
514  else if (tagname == 'PETM0') then
515  in_scope = this%option_check('SURFRATESPEC', 0)
516  end if
517  case ('MVR', 'MVT', 'MVE')
518  if (tagname == 'MNAME' .or. &
519  tagname == 'MNAME1' .or. &
520  tagname == 'MNAME2') then
521  in_scope = this%option_check('MODELNAMES', 0)
522  end if
523  case ('NAM')
524  in_scope = .true.
525  case ('SSM')
526  if (tagname == 'MIXED') in_scope = .true.
527  case ('SPC', 'SPCA')
528  in_scope = .true.
529  case ('SFRTAB')
530  ! MANFRACTION present only when NCOL=3 (2 base columns otherwise)
531  if (tagname == 'MANFRACTION') in_scope = this%option_check('NCOL', 2)
532  case ('LAKTAB')
533  ! BAREA present only for embedded lakes, whose table has 4 columns
534  if (tagname == 'BAREA') in_scope = this%option_check('NCOL', 3)
535  case default
536  ! unrecognized subcomponent with an optional param not handled
537  ! above is a development error -- abort so the gap is visible
538  errmsg = 'LoadContext in_scope needs new case for: '// &
539  trim(this%mf6_input%subcomponent_type)//'/'//trim(tagname)
540  call store_error(errmsg, .true.)
541  end select
542  end function in_scope
543 
544  !> @brief Hardcoded per-package dependency for a subindex param
545  !! with no SHAPE of its own -- same category of special-casing as
546  !! in_scope, for a dimension name and subindex field instead.
547  !<
548  function subindex_dependency(this, tagname, dimname, subindex_tagname) &
549  result(found)
550  class(loadcontexttype) :: this
551  character(len=*), intent(in) :: tagname
552  character(len=LENVARNAME), intent(out) :: dimname
553  character(len=LENVARNAME), intent(out) :: subindex_tagname
554  logical(LGP) :: found
555 
556  found = .false.
557  dimname = ''
558  subindex_tagname = ''
559  select case (this%mf6_input%subcomponent_type)
560  case ('SFR')
561  if (tagname == 'DIVFLOW') then
562  dimname = 'NDV'
563  subindex_tagname = 'IDV'
564  found = .true.
565  end if
566  end select
567  end function subindex_dependency
568 
569  !> @brief Return .true. if a memory-manager integer option variable exceeds a threshold.
570  !<
571  function option_check(this, varname, threshold)
573  class(loadcontexttype) :: this
574  character(len=*), intent(in) :: varname
575  integer(I4B), intent(in) :: threshold
576  logical(LGP) :: option_check
577  integer(I4B) :: isize
578  integer(I4B), pointer :: intptr
579  option_check = .false.
580  call get_isize(varname, this%mf6_input%mempath, isize)
581  if (isize > 0) then
582  call mem_setptr(intptr, varname, this%mf6_input%mempath)
583  if (intptr > threshold) option_check = .true.
584  end if
585  end function option_check
586 
587  !> @brief Build the per-item descriptor table, the single source of
588  !! truth for how each keystring item is allocated and applied.
589  !<
590  subroutine build_keystring_items(this)
592  class(loadcontexttype) :: this
593  type(inputparamdefinitiontype), pointer :: idt
594  integer(I4B) :: icol, k, padj, nfeatures, nkeystring_items
595  character(len=LENVARNAME) :: dimname, subindex_tagname
596  logical(LGP) :: found, node
597  character(len=LINELENGTH), allocatable :: item_names(:)
598  integer(I4B), allocatable :: head_nbody(:)
599  logical(LGP), allocatable :: item_is_body(:)
600  character(len=LENVARNAME) :: cur_head !< most recent head's SETTING keyword
601 
602  if (.not. this%has_setting_dispatch) return
603 
604  ! derive per-item metadata (single computation; not stored as ctx state)
605  call this%keystring_item_names(item_names, head_nbody, item_is_body, &
606  nkeystring_items)
607  if (nkeystring_items < 1) return
608 
609  ! generic leading-id address varname (feature-addressed packages,
610  ! advanced or not, e.g. SPC): the leading column's mf6varname.
611  if (this%keystring_by_feature) then
612  idt => get_param_definition_type(this%mf6_input%param_dfns, &
613  this%mf6_input%component_type, &
614  this%mf6_input%subcomponent_type, &
615  this%blockname, this%params(1), '')
616  this%feature_id_varname = trim(idt%mf6varname)
617  end if
618 
619  padj = 1 ! SETTING column present whenever has_setting_dispatch
620  node = this%keystring_by_node
621 
622  allocate (this%keystring_items(nkeystring_items))
623  nfeatures = this%resolve_nfeatures()
624  cur_head = ''
625 
626  do icol = this%nleading + 1, size(this%params)
627  k = icol - this%nleading
628  idt => get_param_definition_type(this%mf6_input%param_dfns, &
629  this%mf6_input%component_type, &
630  this%mf6_input%subcomponent_type, &
631  this%blockname, this%params(icol), '')
632  this%keystring_items(k)%idt => idt
633  this%keystring_items(k)%sa_icol = icol + padj
634  this%keystring_items(k)%is_body = item_is_body(k)
635  this%keystring_items(k)%head_nbody = head_nbody(k)
636 
637  ! track the current record head's SETTING keyword; a body dispatches
638  ! on its owning head's keyword (the SETTING token on the input row),
639  ! not on its own mf6varname.
640  if (.not. this%keystring_items(k)%is_body) then
641  if (this%keystring_items(k)%head_nbody > 0) then
642  cur_head = trim(idt%mf6varname) ! opening a RECORD
643  else
644  cur_head = '' ! standalone item; not a record head
645  end if
646  else
647  this%keystring_items(k)%head_setting_varname = trim(cur_head)
648  end if
649 
650  ! managed only for DOUBLE + timeseries standalone settings, which
651  ! require a permanent array for cross-period timeseries persistence.
652  this%keystring_items(k)%idm_managed = &
653  (idt%datatype == 'DOUBLE' .and. idt%timeseries .and. &
654  .not. this%keystring_items(k)%is_body)
655 
656  if (this%keystring_items(k)%idm_managed) then
657  if (node) then
658  this%keystring_items(k)%addr_mode = addr_node
659  this%keystring_items(k)%init_value = dnodata
660  if (associated(this%nodes)) &
661  this%keystring_items(k)%nfeatures = this%nodes
662  else
663  this%keystring_items(k)%addr_mode = addr_feature
664  this%keystring_items(k)%init_value = dzero
665  this%keystring_items(k)%nfeatures = &
666  this%resolve_item_nfeatures(idt%tagname, idt%shape, nfeatures)
667  end if
668  end if
669 
670  ! subindex (SFR DIVFLOW): classify here; df-time fields
671  ! (index_icol/head_icol/offsets/nfeatures) are completed in df().
672  if (this%is_advanced .and. this%keystring_items(k)%is_body) then
673  found = this%subindex_dependency(idt%tagname, dimname, &
674  subindex_tagname)
675  if (found) then
676  this%keystring_items(k)%addr_mode = addr_subindex
677  this%keystring_items(k)%idm_managed = .true.
678  end if
679  end if
680  end do
681  end subroutine build_keystring_items
682 
683  !> @brief Resolve the permanent array's feature count. The explicit
684  !! DIMENSIONS dimension (named_bound) is authoritative when present;
685  !! PACKAGEDATA row count is the fallback. Both present and disagreeing
686  !! is an error.
687  !<
688  function resolve_nfeatures(this) result(nfeatures)
689  use memorymanagermodule, only: get_isize
691  use simmodule, only: store_error
692  class(loadcontexttype) :: this
693  integer(I4B) :: nfeatures
694  integer(I4B) :: isize, nkeystring_items, nrow, ndim
695  integer(I4B), pointer :: dimval
696  logical(LGP) :: have_dim, have_nrow
697  character(len=LINELENGTH) :: errmsg
698 
699  ! read the RAW dimension scalar from the memory manager, not
700  ! this%maxbound (a scaled copy used only for read-array sizing)
701  ndim = 0
702  have_dim = .false.
703  allocate (dimval)
704  dimval = 0
705  call mem_set_value(dimval, this%named_bound, this%mf6_input%mempath, &
706  have_dim, release=.false.)
707  if (have_dim) ndim = dimval
708  deallocate (dimval)
709 
710  call get_isize('PACKAGEDATA_IFNO', this%mf6_input%mempath, isize)
711  have_nrow = (isize > 0)
712  nrow = isize
713 
714  if (have_dim .and. have_nrow .and. ndim /= nrow) then
715  write (errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') &
716  'IDM dimension mismatch:', trim(this%named_bound), ndim, &
717  'does not match the PACKAGEDATA row count', nrow, '.'
718  call store_error(errmsg)
719  end if
720 
721  if (have_dim) then
722  nfeatures = ndim
723  return
724  else if (have_nrow) then
725  nfeatures = nrow
726  return
727  end if
728 
729  ! defensive: only if neither an explicit dimension nor PACKAGEDATA
730  ! is available (not expected for current packages)
731  nfeatures = 0
732  nkeystring_items = this%nkeystring_items
733  if (nkeystring_items > 0 .and. associated(this%maxbound)) then
734  if (this%maxbound > 0) nfeatures = this%maxbound / nkeystring_items
735  end if
736  end function resolve_nfeatures
737 
738  !> @brief Per-item feature count from a named dimension, falling back to
739  !! default_nfeatures if unset. Populated-then-released is an error.
740  !<
741  function resolve_item_nfeatures(this, item_tagname, dimname, &
742  default_nfeatures) result(nfeatures)
744  use simmodule, only: store_error
745  class(loadcontexttype) :: this
746  character(len=*), intent(in) :: item_tagname
747  character(len=*), intent(in) :: dimname
748  integer(I4B), intent(in) :: default_nfeatures
749  integer(I4B) :: nfeatures
750  integer(I4B), pointer :: shape_val => null()
751  integer(I4B), dimension(:), pointer, contiguous :: shape_arr => null()
752  integer(I4B) :: isize
753  character(len=LINELENGTH) :: errmsg
754 
755  nfeatures = default_nfeatures
756  if (dimname == '') return
757  call get_isize(trim(dimname), this%mf6_input%mempath, isize)
758  if (isize < 0) then
759  nfeatures = 0
760  return
761  else if (isize == 0) then
762  write (errmsg, '(a,1x,a,1x,a)') &
763  'item', trim(item_tagname)//': DIMENSION', &
764  trim(dimname)//' is not defined.'
765  call store_error(errmsg)
766  nfeatures = 0
767  return
768  else if (.not. this%shape_param_is_array(trim(dimname))) then
769  call mem_setptr(shape_val, trim(dimname), this%mf6_input%mempath)
770  nfeatures = shape_val
771  else
772  call mem_setptr(shape_arr, trim(dimname), this%mf6_input%mempath)
773  nfeatures = sum(shape_arr)
774  end if
775  end function resolve_item_nfeatures
776 
777  !> @brief Is shape_varname a per-feature array (PACKAGEDATA) rather than
778  !! a package-wide scalar (DIMENSIONS)?
779  !<
780  function shape_param_is_array(this, shape_varname) result(is_array)
781  class(loadcontexttype) :: this
782  character(len=*), intent(in) :: shape_varname
783  logical(LGP) :: is_array
784  integer(I4B) :: i
785 
786  is_array = .false.
787  do i = 1, size(this%mf6_input%param_dfns)
788  if (this%mf6_input%param_dfns(i)%component_type == &
789  this%mf6_input%component_type .and. &
790  this%mf6_input%param_dfns(i)%subcomponent_type == &
791  this%mf6_input%subcomponent_type .and. &
792  trim(this%mf6_input%param_dfns(i)%mf6varname) == &
793  trim(shape_varname)) then
794  is_array = &
795  (trim(this%mf6_input%param_dfns(i)%blockname) == 'PACKAGEDATA')
796  exit
797  end if
798  end do
799  end function shape_param_is_array
800 
801  !> @brief set set of in scope parameters for package
802  !<
803  subroutine set_params(this)
808  class(loadcontexttype) :: this
809  type(inputparamdefinitiontype), pointer :: idt, aidt
810  character(len=LINELENGTH), dimension(:), allocatable :: param_buf
811  character(len=LINELENGTH), dimension(:), allocatable :: cols
812  character(len=LINELENGTH), allocatable :: item_names(:)
813  integer(I4B), allocatable :: head_nbody(:)
814  logical(LGP), allocatable :: item_is_body(:)
815  integer(I4B) :: keepcnt, iparam, nparam, nkeystring_items, n
816  logical(LGP) :: keep, tag_found
817 
818  ! initialize
819  keepcnt = 0
820 
821  if (this%loadtype == list .or. &
822  this%loadtype == keystring) then
823  ! get aggregate param definition for period block
824  aidt => &
825  get_aggregate_definition_type(this%mf6_input%aggregate_dfns, &
826  this%mf6_input%component_type, &
827  this%mf6_input%subcomponent_type, &
828  this%blockname)
829  ! split recarray definition
830  call idt_parse_rectype(aidt, cols, nparam)
831  else
832  nparam = size(this%mf6_input%param_dfns)
833  end if
834 
835  ! allocate dfn input params
836  do iparam = 1, nparam
837  if (this%loadtype == list .or. &
838  this%loadtype == keystring) then
839  ! use found so keystring placeholders are silently skipped
840  idt => get_param_definition_type(this%mf6_input%param_dfns, &
841  this%mf6_input%component_type, &
842  this%mf6_input%subcomponent_type, &
843  this%blockname, cols(iparam), '', &
844  found=tag_found)
845  else
846  tag_found = .true.
847  idt => this%mf6_input%param_dfns(iparam)
848  end if
849 
850  if (.not. tag_found) then
851  keep = .false.
852  else if (idt%blockname /= this%blockname) then
853  keep = .false.
854  else
855  keep = this%in_scope(idt%tagname)
856  end if
857 
858  if (keep) then
859  keepcnt = keepcnt + 1
860  call expandarray(param_buf)
861  param_buf(keepcnt) = trim(idt%tagname)
862  end if
863  end do
864 
865  ! record leading-column count before item expansion
866  if (this%loadtype == list .or. &
867  this%loadtype == keystring) this%nleading = keepcnt
868 
869  ! for keystring packages: append item names (metadata head_nbody/
870  ! item_is_body is derived into the descriptor by build_keystring_items)
871  if (this%loadtype == keystring) then
872  call this%keystring_item_names(item_names, head_nbody, &
873  item_is_body, nkeystring_items)
874  this%nkeystring_items = nkeystring_items
875  do n = 1, nkeystring_items
876  keepcnt = keepcnt + 1
877  call expandarray(param_buf)
878  param_buf(keepcnt) = trim(item_names(n))
879  end do
880  end if
881 
882  ! update nparam to total (leading + items)
883  nparam = keepcnt
884 
885  ! allocate and fill params
886  allocate (this%params(nparam))
887  do iparam = 1, nparam
888  this%params(iparam) = trim(param_buf(iparam))
889  end do
890 
891  ! cleanup
892  if (allocated(param_buf)) deallocate (param_buf)
893  end subroutine set_params
894 
895  !> @brief allocate a read state variable
896  !!
897  !! Create and set a read state variable, e.g. 'INRECHARGE',
898  !! which are updated per iper load as follows:
899  !! -1: unset, not in use
900  !! 0: not read in most recent period block
901  !! 1: numeric input read in most recent period block
902  !! 2: time series input read in most recent period block
903  !!
904  !<
905  function rsv_alloc(this, mf6varname) result(varname)
906  use constantsmodule, only: lenvarname
908  class(loadcontexttype) :: this
909  character(len=*), intent(in) :: mf6varname
910  character(len=LENVARNAME) :: varname
911  integer(I4B), pointer :: intvar
912  varname = rsv_name(mf6varname)
913  call mem_allocate(intvar, varname, this%mf6_input%mempath)
914  intvar = -1
915  end function rsv_alloc
916 
917  !> @brief destroy input context object
918  !<
919  subroutine destroy(this)
920  class(loadcontexttype) :: this
921 
922  if (associated(this%setting_idt)) then
923  deallocate (this%setting_idt)
924  nullify (this%setting_idt)
925  end if
926 
927  if (this%set_scalars) then
928  ! deallocate local
929  deallocate (this%naux)
930  deallocate (this%ncpl)
931  deallocate (this%nodes)
932  deallocate (this%maxbound)
933  deallocate (this%boundnames)
934  deallocate (this%iprpak)
935  end if
936 
937  ! nullify
938  nullify (this%naux)
939  nullify (this%nbound)
940  nullify (this%ncpl)
941  nullify (this%nodes)
942  nullify (this%maxbound)
943  nullify (this%boundnames)
944  nullify (this%iprpak)
945  nullify (this%auxname_cst)
946  nullify (this%boundname_cst)
947  nullify (this%auxvar)
948  nullify (this%mshape)
949  end subroutine destroy
950 
951  !> @brief Return the KEYSTRING aggregate for the SETTING token in rec_cols, or null().
952  !<
953  function find_setting_aggregate(mf6_input, rec_cols, nrec_col) result(ks_aidt)
954  use inputoutputmodule, only: upcase
956  type(modflowinputtype), intent(in) :: mf6_input
957  character(len=LINELENGTH), intent(in) :: rec_cols(:)
958  integer(I4B), intent(in) :: nrec_col
959  type(inputparamdefinitiontype), pointer :: ks_aidt
960  character(len=LINELENGTH) :: token, tagname
961  integer(I4B) :: m, n, ilen
962  ks_aidt => null()
963  do m = 1, nrec_col
964  token = trim(rec_cols(m))
965  call upcase(token)
966  ilen = len_trim(token)
967  ! minimum 8 chars: a valid XSETTING token is at least 1 char prefix + 7 for 'SETTING'
968  if (ilen < 8) cycle
969  if (token(ilen - 6:ilen) /= 'SETTING') cycle
970  do n = 1, size(mf6_input%aggregate_dfns)
971  tagname = mf6_input%aggregate_dfns(n)%tagname
972  call upcase(tagname)
973  if (trim(tagname) == trim(token)) then
974  ks_aidt => mf6_input%aggregate_dfns(n)
975  if (idt_datatype(ks_aidt) /= 'KEYSTRING') ks_aidt => null()
976  exit
977  end if
978  end do
979  exit
980  end do
981  end function find_setting_aggregate
982 
983  !> @brief Append body column names from a RECORD compound entry to item_names.
984  !<
985  subroutine expand_record_body(mf6_input, rec_idt, item_names, nkeystring_items)
986  use inputoutputmodule, only: upcase
989  type(modflowinputtype), intent(in) :: mf6_input
990  type(inputparamdefinitiontype), pointer, intent(in) :: rec_idt
991  character(len=LINELENGTH), allocatable, intent(inout) :: item_names(:)
992  integer(I4B), intent(inout) :: nkeystring_items
993  type(inputparamdefinitiontype), pointer :: sub_idt
994  character(len=LINELENGTH), allocatable :: sub_cols(:)
995  character(len=LINELENGTH) :: token, tagname
996  integer(I4B) :: k, j, nsub_col
997  call idt_parse_rectype(rec_idt, sub_cols, nsub_col)
998  do k = 1, nsub_col
999  token = trim(sub_cols(k))
1000  call upcase(token)
1001  do j = 1, size(mf6_input%param_dfns)
1002  sub_idt => mf6_input%param_dfns(j)
1003  if (sub_idt%blockname /= 'PERIOD') cycle
1004  tagname = sub_idt%tagname
1005  call upcase(tagname)
1006  if (trim(tagname) /= trim(token)) cycle
1007  if (idt_datatype(sub_idt) == 'RECORD') cycle
1008  nkeystring_items = nkeystring_items + 1
1009  call expandarray(item_names)
1010  item_names(nkeystring_items) = trim(sub_idt%tagname)
1011  exit
1012  end do
1013  end do
1014  if (allocated(sub_cols)) deallocate (sub_cols)
1015  end subroutine expand_record_body
1016 
1017  !> @brief Return .true. if mf6_input's PERIOD block uses keystring dispatch.
1018  !<
1019  function is_keystring_period(mf6_input) result(res)
1022  type(modflowinputtype), intent(in) :: mf6_input
1023  logical(LGP) :: res, has_period
1024  type(inputparamdefinitiontype), pointer :: aidt, ks_aidt
1025  character(len=LINELENGTH), allocatable :: cols(:)
1026  integer(I4B) :: n, ncol
1027  res = .false.
1028  has_period = .false.
1029  do n = 1, size(mf6_input%block_dfns)
1030  if (mf6_input%block_dfns(n)%blockname == 'PERIOD') then
1031  has_period = .true.
1032  end if
1033  end do
1034  if (.not. has_period) return
1035  aidt => get_aggregate_definition_type(mf6_input%aggregate_dfns, &
1036  mf6_input%component_type, &
1037  mf6_input%subcomponent_type, &
1038  'PERIOD')
1039  call idt_parse_rectype(aidt, cols, ncol)
1040  if (ncol >= 2) then
1041  ks_aidt => find_setting_aggregate(mf6_input, cols, ncol)
1042  if (associated(ks_aidt)) res = .true.
1043  end if
1044  if (allocated(cols)) deallocate (cols)
1045  end function is_keystring_period
1046 
1047  !> @brief .true. if mf6_input's PERIOD block is feature-addressed
1048  !! (see is_feature_tag). Block-independent, unlike LoadContextType's own
1049  !! keystring_by_feature, which is only valid for a PERIOD-scoped instance.
1050  !<
1051  function is_feature_keystring(mf6_input) result(res)
1054  type(modflowinputtype), intent(in) :: mf6_input
1055  logical(LGP) :: res
1056  type(inputparamdefinitiontype), pointer :: aidt
1057  character(len=LINELENGTH), allocatable :: cols(:)
1058  integer(I4B) :: ncol
1059  res = .false.
1060  if (.not. is_keystring_period(mf6_input)) return
1061  aidt => get_aggregate_definition_type(mf6_input%aggregate_dfns, &
1062  mf6_input%component_type, &
1063  mf6_input%subcomponent_type, &
1064  'PERIOD')
1065  call idt_parse_rectype(aidt, cols, ncol)
1066  res = is_feature_tag(cols(1))
1067  if (allocated(cols)) deallocate (cols)
1068  end function is_feature_keystring
1069 
1070  !> @brief .true. if tagname is a record's leading id column (IFNO and
1071  !! its legacy package-specific aliases). Single source for both
1072  !! resolve_loadtype and is_feature_keystring.
1073  !<
1074  function is_feature_tag(tagname) result(res)
1075  character(len=*), intent(in) :: tagname
1076  logical(LGP) :: res
1077  select case (tagname)
1078  case ('IFNO', 'NUMBER', 'BNDNO', 'RNO', 'LAKENO', 'MAWNO', 'UZFNO')
1079  res = .true.
1080  case default
1081  res = .false.
1082  end select
1083  end function is_feature_tag
1084 
1085  !> @brief Return .true. if mf6_input is an advanced package
1086  !<
1087  function is_advanced(mf6_input) result(res)
1088  type(modflowinputtype), intent(in) :: mf6_input
1089  logical(LGP) :: res
1090  res = idm_is_advanced(mf6_input%component_type, mf6_input%subcomponent_type)
1091  end function is_advanced
1092 
1093  !> @brief Return keystring item column names, per-head body counts, and
1094  !! body flags. A RECORD group's trailing columns are body members; its head
1095  !! and any direct-dispatch param are not.
1096  !<
1097  subroutine keystring_item_names(this, item_names, head_nbody, &
1098  item_is_body, nkeystring_items)
1099  use inputoutputmodule, only: upcase
1100  use arrayhandlersmodule, only: expandarray
1103  class(loadcontexttype) :: this
1104  character(len=LINELENGTH), allocatable, intent(out) :: item_names(:)
1105  integer(I4B), allocatable, intent(out) :: head_nbody(:)
1106  logical(LGP), allocatable, intent(out) :: item_is_body(:)
1107  integer(I4B), intent(out) :: nkeystring_items
1108  type(inputparamdefinitiontype), pointer :: aidt, ks_aidt, idt
1109  character(len=LINELENGTH), allocatable :: rec_cols(:), ks_cols(:)
1110  character(len=LINELENGTH) :: rec_token, tagname
1111  integer(I4B) :: m, n, nrec_col, nks_col, nitems0, k
1112 
1113  nkeystring_items = 0
1114 
1115  ! get RECARRAY aggregate for period block and parse its column tokens
1116  aidt => get_aggregate_definition_type(this%mf6_input%aggregate_dfns, &
1117  this%mf6_input%component_type, &
1118  this%mf6_input%subcomponent_type, &
1119  this%blockname)
1120  call idt_parse_rectype(aidt, rec_cols, nrec_col)
1121 
1122  ! find the KEYSTRING aggregate for the SETTING token
1123  ks_aidt => find_setting_aggregate(this%mf6_input, rec_cols, nrec_col)
1124  if (allocated(rec_cols)) deallocate (rec_cols)
1125  if (.not. associated(ks_aidt)) return
1126 
1127  ! parse the KEYSTRING aggregate to get item token list — canonical order
1128  call idt_parse_rectype(ks_aidt, ks_cols, nks_col)
1129 
1130  ! walk the keystring token list in aggregate order
1131  do m = 1, nks_col
1132  rec_token = trim(ks_cols(m))
1133  call upcase(rec_token)
1134 
1135  ! locate matching param_dfns entry for this token
1136  do n = 1, size(this%mf6_input%param_dfns)
1137  if (this%mf6_input%param_dfns(n)%blockname /= this%blockname) cycle
1138  tagname = this%mf6_input%param_dfns(n)%tagname
1139  call upcase(tagname)
1140  if (trim(tagname) /= trim(rec_token)) cycle
1141 
1142  idt => this%mf6_input%param_dfns(n)
1143  if (idt_datatype(idt) == 'RECORD') then
1144  ! compound group: expand body members in RECORD type order
1145  nitems0 = nkeystring_items
1146  call expand_record_body(this%mf6_input, idt, item_names, &
1147  nkeystring_items)
1148  ! first added entry is the KEYWORD head; remaining are body members
1149  do k = nitems0 + 1, nkeystring_items
1150  call expandarray(head_nbody)
1151  call expandarray(item_is_body)
1152  if (k == nitems0 + 1) then
1153  head_nbody(k) = nkeystring_items - nitems0 - 1
1154  item_is_body(k) = .false.
1155  else
1156  head_nbody(k) = 0
1157  item_is_body(k) = .true.
1158  end if
1159  end do
1160  else
1161  ! direct-dispatch param
1162  nkeystring_items = nkeystring_items + 1
1163  call expandarray(item_names)
1164  call expandarray(head_nbody)
1165  call expandarray(item_is_body)
1166  item_names(nkeystring_items) = &
1167  trim(this%mf6_input%param_dfns(n)%tagname)
1168  head_nbody(nkeystring_items) = 0
1169  item_is_body(nkeystring_items) = .false.
1170  end if
1171  exit
1172  end do
1173  end do
1174 
1175  if (allocated(ks_cols)) deallocate (ks_cols)
1176  end subroutine keystring_item_names
1177 
1178  !> @brief Check whether any in-scope parameter is a development-mode feature.
1179  !<
1180  subroutine check_developmode(this, input_name)
1181  use featureflagsmodule, only: developmode
1182  use simvariablesmodule, only: iout
1184  class(loadcontexttype) :: this
1185  character(len=*), intent(in) :: input_name
1186  type(inputparamdefinitiontype), pointer :: idt
1187  character(len=LINELENGTH) :: dev_msg
1188  integer(I4B) :: n
1189 
1190  do n = 1, size(this%params)
1191  idt => get_param_definition_type(this%mf6_input%param_dfns, &
1192  this%mf6_input%component_type, &
1193  this%mf6_input%subcomponent_type, &
1194  this%blockname, this%params(n), '')
1195  if (idt%developmode) then
1196  dev_msg = 'Input tag "'//trim(idt%tagname)// &
1197  &'" read from file "'//trim(input_name)// &
1198  &'" is still under development. Install the &
1199  &nightly build or compile from source with IDEVELOPMODE = 1.'
1200  call developmode(dev_msg, iout)
1201  end if
1202  end do
1203  end subroutine check_developmode
1204 
1205  !> @brief create read state variable name
1206  !<
1207  function rsv_name(mf6varname) result(varname)
1208  use constantsmodule, only: lenvarname
1209  character(len=*), intent(in) :: mf6varname
1210  character(len=LENVARNAME) :: varname
1211  integer(I4B) :: ilen
1212  character(len=2) :: prefix = 'IN'
1213  ilen = len_trim(mf6varname)
1214  if (ilen > (lenvarname - len(prefix))) then
1215  varname = prefix//mf6varname(1:(lenvarname - len(prefix)))
1216  else
1217  varname = prefix//trim(mf6varname)
1218  end if
1219  end function rsv_name
1220 
1221  !> @brief allocate int1d
1222  !<
1223  subroutine allocate_int1d(nrow, varname, mempath)
1225  integer(I4B), intent(in) :: nrow !< integer array number of rows
1226  character(len=*), intent(in) :: varname !< variable name
1227  character(len=*), intent(in) :: mempath !< variable mempath
1228  integer(I4B), dimension(:), pointer, contiguous :: int1d
1229  integer(I4B) :: n
1230  call mem_allocate(int1d, nrow, varname, mempath)
1231  do n = 1, nrow
1232  int1d(n) = izero
1233  end do
1234  end subroutine allocate_int1d
1235 
1236  !> @brief allocate dbl1d
1237  !<
1238  subroutine allocate_dbl1d(nrow, varname, mempath)
1240  integer(I4B), intent(in) :: nrow !< integer array number of rows
1241  character(len=*), intent(in) :: varname !< variable name
1242  character(len=*), intent(in) :: mempath !< variable mempath
1243  real(DP), dimension(:), pointer, contiguous :: dbl1d
1244  integer(I4B) :: n
1245  call mem_allocate(dbl1d, nrow, varname, mempath)
1246  do n = 1, nrow
1247  dbl1d(n) = dzero
1248  end do
1249  end subroutine allocate_dbl1d
1250 
1251  !> @brief allocate dbl2d
1252  !<
1253  subroutine allocate_dbl2d(ncol, nrow, varname, mempath)
1255  integer(I4B), intent(in) :: ncol !< integer array number of cols
1256  integer(I4B), intent(in) :: nrow !< integer array number of rows
1257  character(len=*), intent(in) :: varname !< variable name
1258  character(len=*), intent(in) :: mempath !< variable mempath
1259  real(DP), dimension(:, :), pointer, contiguous :: dbl2d
1260  integer(I4B) :: n, m
1261  call mem_allocate(dbl2d, ncol, nrow, varname, mempath)
1262  do m = 1, nrow
1263  do n = 1, ncol
1264  dbl2d(n, m) = dzero
1265  end do
1266  end do
1267  end subroutine allocate_dbl2d
1268 
1269  !> @brief allocate intptr and update from input context
1270  !!
1271  !<
1272  subroutine setval(intptr, varname, mempath)
1274  integer(I4B), pointer, intent(inout) :: intptr
1275  character(len=*), intent(in) :: varname
1276  character(len=*), intent(in) :: mempath
1277  logical(LGP) :: found
1278  allocate (intptr)
1279  intptr = 0
1280  call mem_set_value(intptr, varname, mempath, found, release=.false.)
1281  end subroutine setval
1282 
1283  !> @brief set intptr to varname
1284  !!
1285  !<
1286  subroutine setptr_int(intptr, varname, mempath)
1288  integer(I4B), pointer, intent(inout) :: intptr
1289  character(len=*), intent(in) :: varname
1290  character(len=*), intent(in) :: mempath
1291  integer(I4B) :: isize
1292  call get_isize(varname, mempath, isize)
1293  if (isize > -1) then
1294  call mem_setptr(intptr, varname, mempath)
1295  else
1296  call mem_allocate(intptr, varname, mempath)
1297  intptr = 0
1298  end if
1299  end subroutine setptr_int
1300 
1301  !> @brief set charstr1d pointer to varname
1302  !<
1303  subroutine setptr_charstr1d(charstr1d, varname, mempath, strlen)
1305  type(characterstringtype), dimension(:), pointer, &
1306  contiguous, intent(inout) :: charstr1d
1307  character(len=*), intent(in) :: varname
1308  character(len=*), intent(in) :: mempath
1309  integer(I4B), intent(in) :: strlen
1310  integer(I4B) :: isize
1311  call get_isize(varname, mempath, isize)
1312  if (isize > -1) then
1313  call mem_setptr(charstr1d, varname, mempath)
1314  else
1315  call mem_allocate(charstr1d, strlen, 0, varname, mempath)
1316  end if
1317  end subroutine setptr_charstr1d
1318 
1319  !> @brief set auxvar pointer
1320  !!
1321  !<
1322  subroutine setptr_auxvar(auxvar, mempath)
1324  real(DP), dimension(:, :), pointer, &
1325  contiguous, intent(inout) :: auxvar
1326  character(len=*), intent(in) :: mempath
1327  integer(I4B) :: isize
1328  call get_isize('AUXVAR', mempath, isize)
1329  if (isize > -1) then
1330  call mem_setptr(auxvar, 'AUXVAR', mempath)
1331  else
1332  call mem_allocate(auxvar, 0, 0, 'AUXVAR', mempath)
1333  end if
1334  end subroutine setptr_auxvar
1335 
1336 end module loadcontextmodule
subroutine init()
Definition: GridSorting.f90:25
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
real(dp), parameter dnodata
real no data constant
Definition: Constants.f90:95
integer(i4b), parameter lenvarname
maximum length of a variable name
Definition: Constants.f90:17
integer(i4b), parameter 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
integer(i4b), parameter izero
integer constant zero
Definition: Constants.f90:51
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
This module contains the DefinitionSelectModule.
type(inputparamdefinitiontype) function, pointer, public idt_default(component_type, subcomponent_type, blockname, tagname, mf6varname, datatype)
return allocated input definition type
type(inputparamdefinitiontype) function, pointer, public get_aggregate_definition_type(input_definition_types, component_type, subcomponent_type, blockname)
Return aggregate definition.
subroutine, public idt_parse_rectype(idt, cols, ncol)
allocate and set RECARRAY, KEYSTRING or RECORD param list
character(len=linelength) function, public idt_datatype(idt)
return input definition type datatype
type(inputparamdefinitiontype) function, pointer, public get_param_definition_type(input_definition_types, component_type, subcomponent_type, blockname, tagname, filename, found)
Return parameter definition.
Disable development features in release mode.
Definition: FeatureFlags.f90:2
subroutine, public developmode(errmsg, iunit)
Terminate if in release mode (guard development features)
logical function, public idm_is_advanced(component, subcomponent)
Input definition module.
subroutine, public upcase(word)
Convert to upper case.
This module defines variable data types.
Definition: kind.f90:8
Load context for IDM generic dynamic loaders.
Definition: LoadContext.f90:10
subroutine set_params(this)
set set of in scope parameters for package
subroutine expand_record_body(mf6_input, rec_idt, item_names, nkeystring_items)
Append body column names from a RECORD compound entry to item_names.
subroutine allocate_dbl2d(ncol, nrow, varname, mempath)
allocate dbl2d
subroutine build_keystring_items(this)
Build the per-item descriptor table, the single source of truth for how each keystring item is alloca...
subroutine setptr_auxvar(auxvar, mempath)
set auxvar pointer
logical(lgp) function option_check(this, varname, threshold)
Return .true. if a memory-manager integer option variable exceeds a threshold.
integer(i4b), parameter, public addr_feature
addressed by leading id (IFNO/BNDNO)
Definition: LoadContext.f90:52
subroutine check_developmode(this, input_name)
Check whether any in-scope parameter is a development-mode feature.
integer(i4b), parameter, public addr_none
not an applied setting
Definition: LoadContext.f90:51
logical(lgp) function, public is_feature_keystring(mf6_input)
.true. if mf6_input's PERIOD block is feature-addressed (see is_feature_tag). Block-independent,...
subroutine allocate_params(this)
Allocate each in-scope parameter in the memory manager.
logical(lgp) function shape_param_is_array(this, shape_varname)
Is shape_varname a per-feature array (PACKAGEDATA) rather than a package-wide scalar (DIMENSIONS)?
subroutine resolve_loadtype(this)
Determine loadtype from block and param definitions.
subroutine allocate_int1d(nrow, varname, mempath)
allocate int1d
subroutine keystring_item_names(this, item_names, head_nbody, item_is_body, nkeystring_items)
Return keystring item column names, per-head body counts, and body flags. A RECORD group's trailing c...
integer(i4b), parameter, public addr_subindex
addressed by (id, subindex)
Definition: LoadContext.f90:54
@ load_undef
undefined load type
Definition: LoadContext.f90:32
@ gridarray
readarraygrid load
Definition: LoadContext.f90:35
@ keystring
keystring period block load
Definition: LoadContext.f90:36
@ layerarray
readasarrays load
Definition: LoadContext.f90:34
type(inputparamdefinitiontype) function, pointer find_setting_aggregate(mf6_input, rec_cols, nrec_col)
Return the KEYSTRING aggregate for the SETTING token in rec_cols, or null().
subroutine allocate_dbl1d(nrow, varname, mempath)
allocate dbl1d
logical(lgp) function is_feature_tag(tagname)
.true. if tagname is a record's leading id column (IFNO and its legacy package-specific aliases)....
integer(i4b) function resolve_item_nfeatures(this, item_tagname, dimname, default_nfeatures)
Per-item feature count from a named dimension, falling back to default_nfeatures if unset....
subroutine setval(intptr, varname, mempath)
allocate intptr and update from input context
subroutine allocate_param(this, idt)
allocate a package dynamic input parameter
subroutine resolve_dimensions(this)
Resolve dimension scalars and scale keystring maxbound.
logical(lgp) function, public is_advanced(mf6_input)
Return .true. if mf6_input is an advanced package.
subroutine allocate_arrays(this)
allocate arrays
subroutine setptr_int(intptr, varname, mempath)
set intptr to varname
integer(i4b) function resolve_nfeatures(this)
Resolve the permanent array's feature count. The explicit DIMENSIONS dimension (named_bound) is autho...
subroutine destroy(this)
destroy input context object
subroutine scale_keystring_maxbound(this)
Scale maxbound (a feature or node count) by the number of KEYSTRING items, so every feature can use e...
subroutine resolve_context(this)
Set context flags from input load_scope and component metadata.
logical(lgp) function subindex_dependency(this, tagname, dimname, subindex_tagname)
Hardcoded per-package dependency for a subindex param with no SHAPE of its own – same category of spe...
character(len=lenvarname) function, public rsv_name(mf6varname)
create read state variable name
character(len=lenvarname) function rsv_alloc(this, mf6varname)
allocate a read state variable
logical(lgp) function in_scope(this, tagname)
Return .true. if an optional parameter is active for this load. Required/structural params are handle...
subroutine setptr_charstr1d(charstr1d, varname, mempath, strlen)
set charstr1d pointer to varname
logical(lgp) function, public is_keystring_period(mf6_input)
Return .true. if mf6_input's PERIOD block uses keystring dispatch.
integer(i4b), parameter, public addr_node
addressed by CELLID
Definition: LoadContext.f90:53
subroutine, public get_isize(name, mem_path, isize)
@ brief Get the number of elements for this variable
This module contains the ModflowInputModule.
Definition: ModflowInput.f90:9
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string
integer(i4b) iout
file unit number for simulation output
This class is used to store a single deferred-length character string. It was designed to work in an ...
Definition: CharString.f90:23
Input parameter definition. Describes an input parameter.
One descriptor per expanded keystring item, so loaders iterate uniformly instead of re-deriving per-m...
Definition: LoadContext.f90:59
Input load context for generic dynamic loaders and StructArray based static loads....
Definition: LoadContext.f90:75
Pointer type for read state variable.
Definition: LoadContext.f90:41
derived type for storing input definition for a file