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 default
533  ! unrecognized subcomponent with an optional param not handled
534  ! above is a development error -- abort so the gap is visible
535  errmsg = 'LoadContext in_scope needs new case for: '// &
536  trim(this%mf6_input%subcomponent_type)//'/'//trim(tagname)
537  call store_error(errmsg, .true.)
538  end select
539  end function in_scope
540 
541  !> @brief Hardcoded per-package dependency for a subindex param
542  !! with no SHAPE of its own -- same category of special-casing as
543  !! in_scope, for a dimension name and subindex field instead.
544  !<
545  function subindex_dependency(this, tagname, dimname, subindex_tagname) &
546  result(found)
547  class(loadcontexttype) :: this
548  character(len=*), intent(in) :: tagname
549  character(len=LENVARNAME), intent(out) :: dimname
550  character(len=LENVARNAME), intent(out) :: subindex_tagname
551  logical(LGP) :: found
552 
553  found = .false.
554  dimname = ''
555  subindex_tagname = ''
556  select case (this%mf6_input%subcomponent_type)
557  case ('SFR')
558  if (tagname == 'DIVFLOW') then
559  dimname = 'NDV'
560  subindex_tagname = 'IDV'
561  found = .true.
562  end if
563  end select
564  end function subindex_dependency
565 
566  !> @brief Return .true. if a memory-manager integer option variable exceeds a threshold.
567  !<
568  function option_check(this, varname, threshold)
570  class(loadcontexttype) :: this
571  character(len=*), intent(in) :: varname
572  integer(I4B), intent(in) :: threshold
573  logical(LGP) :: option_check
574  integer(I4B) :: isize
575  integer(I4B), pointer :: intptr
576  option_check = .false.
577  call get_isize(varname, this%mf6_input%mempath, isize)
578  if (isize > 0) then
579  call mem_setptr(intptr, varname, this%mf6_input%mempath)
580  if (intptr > threshold) option_check = .true.
581  end if
582  end function option_check
583 
584  !> @brief Build the per-item descriptor table, the single source of
585  !! truth for how each keystring item is allocated and applied.
586  !<
587  subroutine build_keystring_items(this)
589  class(loadcontexttype) :: this
590  type(inputparamdefinitiontype), pointer :: idt
591  integer(I4B) :: icol, k, padj, nfeatures, nkeystring_items
592  character(len=LENVARNAME) :: dimname, subindex_tagname
593  logical(LGP) :: found, node
594  character(len=LINELENGTH), allocatable :: item_names(:)
595  integer(I4B), allocatable :: head_nbody(:)
596  logical(LGP), allocatable :: item_is_body(:)
597  character(len=LENVARNAME) :: cur_head !< most recent head's SETTING keyword
598 
599  if (.not. this%has_setting_dispatch) return
600 
601  ! derive per-item metadata (single computation; not stored as ctx state)
602  call this%keystring_item_names(item_names, head_nbody, item_is_body, &
603  nkeystring_items)
604  if (nkeystring_items < 1) return
605 
606  ! generic leading-id address varname (feature-addressed packages,
607  ! advanced or not, e.g. SPC): the leading column's mf6varname.
608  if (this%keystring_by_feature) then
609  idt => get_param_definition_type(this%mf6_input%param_dfns, &
610  this%mf6_input%component_type, &
611  this%mf6_input%subcomponent_type, &
612  this%blockname, this%params(1), '')
613  this%feature_id_varname = trim(idt%mf6varname)
614  end if
615 
616  padj = 1 ! SETTING column present whenever has_setting_dispatch
617  node = this%keystring_by_node
618 
619  allocate (this%keystring_items(nkeystring_items))
620  nfeatures = this%resolve_nfeatures()
621  cur_head = ''
622 
623  do icol = this%nleading + 1, size(this%params)
624  k = icol - this%nleading
625  idt => get_param_definition_type(this%mf6_input%param_dfns, &
626  this%mf6_input%component_type, &
627  this%mf6_input%subcomponent_type, &
628  this%blockname, this%params(icol), '')
629  this%keystring_items(k)%idt => idt
630  this%keystring_items(k)%sa_icol = icol + padj
631  this%keystring_items(k)%is_body = item_is_body(k)
632  this%keystring_items(k)%head_nbody = head_nbody(k)
633 
634  ! track the current record head's SETTING keyword; a body dispatches
635  ! on its owning head's keyword (the SETTING token on the input row),
636  ! not on its own mf6varname.
637  if (.not. this%keystring_items(k)%is_body) then
638  if (this%keystring_items(k)%head_nbody > 0) then
639  cur_head = trim(idt%mf6varname) ! opening a RECORD
640  else
641  cur_head = '' ! standalone item; not a record head
642  end if
643  else
644  this%keystring_items(k)%head_setting_varname = trim(cur_head)
645  end if
646 
647  ! managed only for DOUBLE + timeseries standalone settings, which
648  ! require a permanent array for cross-period timeseries persistence.
649  this%keystring_items(k)%idm_managed = &
650  (idt%datatype == 'DOUBLE' .and. idt%timeseries .and. &
651  .not. this%keystring_items(k)%is_body)
652 
653  if (this%keystring_items(k)%idm_managed) then
654  if (node) then
655  this%keystring_items(k)%addr_mode = addr_node
656  this%keystring_items(k)%init_value = dnodata
657  if (associated(this%nodes)) &
658  this%keystring_items(k)%nfeatures = this%nodes
659  else
660  this%keystring_items(k)%addr_mode = addr_feature
661  this%keystring_items(k)%init_value = dzero
662  this%keystring_items(k)%nfeatures = &
663  this%resolve_item_nfeatures(idt%tagname, idt%shape, nfeatures)
664  end if
665  end if
666 
667  ! subindex (SFR DIVFLOW): classify here; df-time fields
668  ! (index_icol/head_icol/offsets/nfeatures) are completed in df().
669  if (this%is_advanced .and. this%keystring_items(k)%is_body) then
670  found = this%subindex_dependency(idt%tagname, dimname, &
671  subindex_tagname)
672  if (found) then
673  this%keystring_items(k)%addr_mode = addr_subindex
674  this%keystring_items(k)%idm_managed = .true.
675  end if
676  end if
677  end do
678  end subroutine build_keystring_items
679 
680  !> @brief Resolve the permanent array's feature count. The explicit
681  !! DIMENSIONS dimension (named_bound) is authoritative when present;
682  !! PACKAGEDATA row count is the fallback. Both present and disagreeing
683  !! is an error.
684  !<
685  function resolve_nfeatures(this) result(nfeatures)
686  use memorymanagermodule, only: get_isize
688  use simmodule, only: store_error
689  class(loadcontexttype) :: this
690  integer(I4B) :: nfeatures
691  integer(I4B) :: isize, nkeystring_items, nrow, ndim
692  integer(I4B), pointer :: dimval
693  logical(LGP) :: have_dim, have_nrow
694  character(len=LINELENGTH) :: errmsg
695 
696  ! read the RAW dimension scalar from the memory manager, not
697  ! this%maxbound (a scaled copy used only for read-array sizing)
698  ndim = 0
699  have_dim = .false.
700  allocate (dimval)
701  dimval = 0
702  call mem_set_value(dimval, this%named_bound, this%mf6_input%mempath, &
703  have_dim, release=.false.)
704  if (have_dim) ndim = dimval
705  deallocate (dimval)
706 
707  call get_isize('PACKAGEDATA_IFNO', this%mf6_input%mempath, isize)
708  have_nrow = (isize > 0)
709  nrow = isize
710 
711  if (have_dim .and. have_nrow .and. ndim /= nrow) then
712  write (errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') &
713  'IDM dimension mismatch:', trim(this%named_bound), ndim, &
714  'does not match the PACKAGEDATA row count', nrow, '.'
715  call store_error(errmsg)
716  end if
717 
718  if (have_dim) then
719  nfeatures = ndim
720  return
721  else if (have_nrow) then
722  nfeatures = nrow
723  return
724  end if
725 
726  ! defensive: only if neither an explicit dimension nor PACKAGEDATA
727  ! is available (not expected for current packages)
728  nfeatures = 0
729  nkeystring_items = this%nkeystring_items
730  if (nkeystring_items > 0 .and. associated(this%maxbound)) then
731  if (this%maxbound > 0) nfeatures = this%maxbound / nkeystring_items
732  end if
733  end function resolve_nfeatures
734 
735  !> @brief Per-item feature count from a named dimension, falling back to
736  !! default_nfeatures if unset. Populated-then-released is an error.
737  !<
738  function resolve_item_nfeatures(this, item_tagname, dimname, &
739  default_nfeatures) result(nfeatures)
741  use simmodule, only: store_error
742  class(loadcontexttype) :: this
743  character(len=*), intent(in) :: item_tagname
744  character(len=*), intent(in) :: dimname
745  integer(I4B), intent(in) :: default_nfeatures
746  integer(I4B) :: nfeatures
747  integer(I4B), pointer :: shape_val => null()
748  integer(I4B), dimension(:), pointer, contiguous :: shape_arr => null()
749  integer(I4B) :: isize
750  character(len=LINELENGTH) :: errmsg
751 
752  nfeatures = default_nfeatures
753  if (dimname == '') return
754  call get_isize(trim(dimname), this%mf6_input%mempath, isize)
755  if (isize < 0) then
756  nfeatures = 0
757  return
758  else if (isize == 0) then
759  write (errmsg, '(a,1x,a,1x,a)') &
760  'item', trim(item_tagname)//': DIMENSION', &
761  trim(dimname)//' is not defined.'
762  call store_error(errmsg)
763  nfeatures = 0
764  return
765  else if (.not. this%shape_param_is_array(trim(dimname))) then
766  call mem_setptr(shape_val, trim(dimname), this%mf6_input%mempath)
767  nfeatures = shape_val
768  else
769  call mem_setptr(shape_arr, trim(dimname), this%mf6_input%mempath)
770  nfeatures = sum(shape_arr)
771  end if
772  end function resolve_item_nfeatures
773 
774  !> @brief Is shape_varname a per-feature array (PACKAGEDATA) rather than
775  !! a package-wide scalar (DIMENSIONS)?
776  !<
777  function shape_param_is_array(this, shape_varname) result(is_array)
778  class(loadcontexttype) :: this
779  character(len=*), intent(in) :: shape_varname
780  logical(LGP) :: is_array
781  integer(I4B) :: i
782 
783  is_array = .false.
784  do i = 1, size(this%mf6_input%param_dfns)
785  if (this%mf6_input%param_dfns(i)%component_type == &
786  this%mf6_input%component_type .and. &
787  this%mf6_input%param_dfns(i)%subcomponent_type == &
788  this%mf6_input%subcomponent_type .and. &
789  trim(this%mf6_input%param_dfns(i)%mf6varname) == &
790  trim(shape_varname)) then
791  is_array = &
792  (trim(this%mf6_input%param_dfns(i)%blockname) == 'PACKAGEDATA')
793  exit
794  end if
795  end do
796  end function shape_param_is_array
797 
798  !> @brief set set of in scope parameters for package
799  !<
800  subroutine set_params(this)
805  class(loadcontexttype) :: this
806  type(inputparamdefinitiontype), pointer :: idt, aidt
807  character(len=LINELENGTH), dimension(:), allocatable :: param_buf
808  character(len=LINELENGTH), dimension(:), allocatable :: cols
809  character(len=LINELENGTH), allocatable :: item_names(:)
810  integer(I4B), allocatable :: head_nbody(:)
811  logical(LGP), allocatable :: item_is_body(:)
812  integer(I4B) :: keepcnt, iparam, nparam, nkeystring_items, n
813  logical(LGP) :: keep, tag_found
814 
815  ! initialize
816  keepcnt = 0
817 
818  if (this%loadtype == list .or. &
819  this%loadtype == keystring) then
820  ! get aggregate param definition for period block
821  aidt => &
822  get_aggregate_definition_type(this%mf6_input%aggregate_dfns, &
823  this%mf6_input%component_type, &
824  this%mf6_input%subcomponent_type, &
825  this%blockname)
826  ! split recarray definition
827  call idt_parse_rectype(aidt, cols, nparam)
828  else
829  nparam = size(this%mf6_input%param_dfns)
830  end if
831 
832  ! allocate dfn input params
833  do iparam = 1, nparam
834  if (this%loadtype == list .or. &
835  this%loadtype == keystring) then
836  ! use found so keystring placeholders are silently skipped
837  idt => get_param_definition_type(this%mf6_input%param_dfns, &
838  this%mf6_input%component_type, &
839  this%mf6_input%subcomponent_type, &
840  this%blockname, cols(iparam), '', &
841  found=tag_found)
842  else
843  tag_found = .true.
844  idt => this%mf6_input%param_dfns(iparam)
845  end if
846 
847  if (.not. tag_found) then
848  keep = .false.
849  else if (idt%blockname /= this%blockname) then
850  keep = .false.
851  else
852  keep = this%in_scope(idt%tagname)
853  end if
854 
855  if (keep) then
856  keepcnt = keepcnt + 1
857  call expandarray(param_buf)
858  param_buf(keepcnt) = trim(idt%tagname)
859  end if
860  end do
861 
862  ! record leading-column count before item expansion
863  if (this%loadtype == list .or. &
864  this%loadtype == keystring) this%nleading = keepcnt
865 
866  ! for keystring packages: append item names (metadata head_nbody/
867  ! item_is_body is derived into the descriptor by build_keystring_items)
868  if (this%loadtype == keystring) then
869  call this%keystring_item_names(item_names, head_nbody, &
870  item_is_body, nkeystring_items)
871  this%nkeystring_items = nkeystring_items
872  do n = 1, nkeystring_items
873  keepcnt = keepcnt + 1
874  call expandarray(param_buf)
875  param_buf(keepcnt) = trim(item_names(n))
876  end do
877  end if
878 
879  ! update nparam to total (leading + items)
880  nparam = keepcnt
881 
882  ! allocate and fill params
883  allocate (this%params(nparam))
884  do iparam = 1, nparam
885  this%params(iparam) = trim(param_buf(iparam))
886  end do
887 
888  ! cleanup
889  if (allocated(param_buf)) deallocate (param_buf)
890  end subroutine set_params
891 
892  !> @brief allocate a read state variable
893  !!
894  !! Create and set a read state variable, e.g. 'INRECHARGE',
895  !! which are updated per iper load as follows:
896  !! -1: unset, not in use
897  !! 0: not read in most recent period block
898  !! 1: numeric input read in most recent period block
899  !! 2: time series input read in most recent period block
900  !!
901  !<
902  function rsv_alloc(this, mf6varname) result(varname)
903  use constantsmodule, only: lenvarname
905  class(loadcontexttype) :: this
906  character(len=*), intent(in) :: mf6varname
907  character(len=LENVARNAME) :: varname
908  integer(I4B), pointer :: intvar
909  varname = rsv_name(mf6varname)
910  call mem_allocate(intvar, varname, this%mf6_input%mempath)
911  intvar = -1
912  end function rsv_alloc
913 
914  !> @brief destroy input context object
915  !<
916  subroutine destroy(this)
917  class(loadcontexttype) :: this
918 
919  if (associated(this%setting_idt)) then
920  deallocate (this%setting_idt)
921  nullify (this%setting_idt)
922  end if
923 
924  if (this%set_scalars) then
925  ! deallocate local
926  deallocate (this%naux)
927  deallocate (this%ncpl)
928  deallocate (this%nodes)
929  deallocate (this%maxbound)
930  deallocate (this%boundnames)
931  deallocate (this%iprpak)
932  end if
933 
934  ! nullify
935  nullify (this%naux)
936  nullify (this%nbound)
937  nullify (this%ncpl)
938  nullify (this%nodes)
939  nullify (this%maxbound)
940  nullify (this%boundnames)
941  nullify (this%iprpak)
942  nullify (this%auxname_cst)
943  nullify (this%boundname_cst)
944  nullify (this%auxvar)
945  nullify (this%mshape)
946  end subroutine destroy
947 
948  !> @brief Return the KEYSTRING aggregate for the SETTING token in rec_cols, or null().
949  !<
950  function find_setting_aggregate(mf6_input, rec_cols, nrec_col) result(ks_aidt)
951  use inputoutputmodule, only: upcase
953  type(modflowinputtype), intent(in) :: mf6_input
954  character(len=LINELENGTH), intent(in) :: rec_cols(:)
955  integer(I4B), intent(in) :: nrec_col
956  type(inputparamdefinitiontype), pointer :: ks_aidt
957  character(len=LINELENGTH) :: token, tagname
958  integer(I4B) :: m, n, ilen
959  ks_aidt => null()
960  do m = 1, nrec_col
961  token = trim(rec_cols(m))
962  call upcase(token)
963  ilen = len_trim(token)
964  ! minimum 8 chars: a valid XSETTING token is at least 1 char prefix + 7 for 'SETTING'
965  if (ilen < 8) cycle
966  if (token(ilen - 6:ilen) /= 'SETTING') cycle
967  do n = 1, size(mf6_input%aggregate_dfns)
968  tagname = mf6_input%aggregate_dfns(n)%tagname
969  call upcase(tagname)
970  if (trim(tagname) == trim(token)) then
971  ks_aidt => mf6_input%aggregate_dfns(n)
972  if (idt_datatype(ks_aidt) /= 'KEYSTRING') ks_aidt => null()
973  exit
974  end if
975  end do
976  exit
977  end do
978  end function find_setting_aggregate
979 
980  !> @brief Append body column names from a RECORD compound entry to item_names.
981  !<
982  subroutine expand_record_body(mf6_input, rec_idt, item_names, nkeystring_items)
983  use inputoutputmodule, only: upcase
986  type(modflowinputtype), intent(in) :: mf6_input
987  type(inputparamdefinitiontype), pointer, intent(in) :: rec_idt
988  character(len=LINELENGTH), allocatable, intent(inout) :: item_names(:)
989  integer(I4B), intent(inout) :: nkeystring_items
990  type(inputparamdefinitiontype), pointer :: sub_idt
991  character(len=LINELENGTH), allocatable :: sub_cols(:)
992  character(len=LINELENGTH) :: token, tagname
993  integer(I4B) :: k, j, nsub_col
994  call idt_parse_rectype(rec_idt, sub_cols, nsub_col)
995  do k = 1, nsub_col
996  token = trim(sub_cols(k))
997  call upcase(token)
998  do j = 1, size(mf6_input%param_dfns)
999  sub_idt => mf6_input%param_dfns(j)
1000  if (sub_idt%blockname /= 'PERIOD') cycle
1001  tagname = sub_idt%tagname
1002  call upcase(tagname)
1003  if (trim(tagname) /= trim(token)) cycle
1004  if (idt_datatype(sub_idt) == 'RECORD') cycle
1005  nkeystring_items = nkeystring_items + 1
1006  call expandarray(item_names)
1007  item_names(nkeystring_items) = trim(sub_idt%tagname)
1008  exit
1009  end do
1010  end do
1011  if (allocated(sub_cols)) deallocate (sub_cols)
1012  end subroutine expand_record_body
1013 
1014  !> @brief Return .true. if mf6_input's PERIOD block uses keystring dispatch.
1015  !<
1016  function is_keystring_period(mf6_input) result(res)
1019  type(modflowinputtype), intent(in) :: mf6_input
1020  logical(LGP) :: res, has_period
1021  type(inputparamdefinitiontype), pointer :: aidt, ks_aidt
1022  character(len=LINELENGTH), allocatable :: cols(:)
1023  integer(I4B) :: n, ncol
1024  res = .false.
1025  has_period = .false.
1026  do n = 1, size(mf6_input%block_dfns)
1027  if (mf6_input%block_dfns(n)%blockname == 'PERIOD') then
1028  has_period = .true.
1029  end if
1030  end do
1031  if (.not. has_period) return
1032  aidt => get_aggregate_definition_type(mf6_input%aggregate_dfns, &
1033  mf6_input%component_type, &
1034  mf6_input%subcomponent_type, &
1035  'PERIOD')
1036  call idt_parse_rectype(aidt, cols, ncol)
1037  if (ncol >= 2) then
1038  ks_aidt => find_setting_aggregate(mf6_input, cols, ncol)
1039  if (associated(ks_aidt)) res = .true.
1040  end if
1041  if (allocated(cols)) deallocate (cols)
1042  end function is_keystring_period
1043 
1044  !> @brief .true. if mf6_input's PERIOD block is feature-addressed
1045  !! (see is_feature_tag). Block-independent, unlike LoadContextType's own
1046  !! keystring_by_feature, which is only valid for a PERIOD-scoped instance.
1047  !<
1048  function is_feature_keystring(mf6_input) result(res)
1051  type(modflowinputtype), intent(in) :: mf6_input
1052  logical(LGP) :: res
1053  type(inputparamdefinitiontype), pointer :: aidt
1054  character(len=LINELENGTH), allocatable :: cols(:)
1055  integer(I4B) :: ncol
1056  res = .false.
1057  if (.not. is_keystring_period(mf6_input)) return
1058  aidt => get_aggregate_definition_type(mf6_input%aggregate_dfns, &
1059  mf6_input%component_type, &
1060  mf6_input%subcomponent_type, &
1061  'PERIOD')
1062  call idt_parse_rectype(aidt, cols, ncol)
1063  res = is_feature_tag(cols(1))
1064  if (allocated(cols)) deallocate (cols)
1065  end function is_feature_keystring
1066 
1067  !> @brief .true. if tagname is a record's leading id column (IFNO and
1068  !! its legacy package-specific aliases). Single source for both
1069  !! resolve_loadtype and is_feature_keystring.
1070  !<
1071  function is_feature_tag(tagname) result(res)
1072  character(len=*), intent(in) :: tagname
1073  logical(LGP) :: res
1074  select case (tagname)
1075  case ('IFNO', 'NUMBER', 'BNDNO', 'RNO', 'LAKENO', 'MAWNO', 'UZFNO')
1076  res = .true.
1077  case default
1078  res = .false.
1079  end select
1080  end function is_feature_tag
1081 
1082  !> @brief Return .true. if mf6_input is an advanced package
1083  !<
1084  function is_advanced(mf6_input) result(res)
1085  type(modflowinputtype), intent(in) :: mf6_input
1086  logical(LGP) :: res
1087  res = idm_is_advanced(mf6_input%component_type, mf6_input%subcomponent_type)
1088  end function is_advanced
1089 
1090  !> @brief Return keystring item column names, per-head body counts, and
1091  !! body flags. A RECORD group's trailing columns are body members; its head
1092  !! and any direct-dispatch param are not.
1093  !<
1094  subroutine keystring_item_names(this, item_names, head_nbody, &
1095  item_is_body, nkeystring_items)
1096  use inputoutputmodule, only: upcase
1097  use arrayhandlersmodule, only: expandarray
1100  class(loadcontexttype) :: this
1101  character(len=LINELENGTH), allocatable, intent(out) :: item_names(:)
1102  integer(I4B), allocatable, intent(out) :: head_nbody(:)
1103  logical(LGP), allocatable, intent(out) :: item_is_body(:)
1104  integer(I4B), intent(out) :: nkeystring_items
1105  type(inputparamdefinitiontype), pointer :: aidt, ks_aidt, idt
1106  character(len=LINELENGTH), allocatable :: rec_cols(:), ks_cols(:)
1107  character(len=LINELENGTH) :: rec_token, tagname
1108  integer(I4B) :: m, n, nrec_col, nks_col, nitems0, k
1109 
1110  nkeystring_items = 0
1111 
1112  ! get RECARRAY aggregate for period block and parse its column tokens
1113  aidt => get_aggregate_definition_type(this%mf6_input%aggregate_dfns, &
1114  this%mf6_input%component_type, &
1115  this%mf6_input%subcomponent_type, &
1116  this%blockname)
1117  call idt_parse_rectype(aidt, rec_cols, nrec_col)
1118 
1119  ! find the KEYSTRING aggregate for the SETTING token
1120  ks_aidt => find_setting_aggregate(this%mf6_input, rec_cols, nrec_col)
1121  if (allocated(rec_cols)) deallocate (rec_cols)
1122  if (.not. associated(ks_aidt)) return
1123 
1124  ! parse the KEYSTRING aggregate to get item token list — canonical order
1125  call idt_parse_rectype(ks_aidt, ks_cols, nks_col)
1126 
1127  ! walk the keystring token list in aggregate order
1128  do m = 1, nks_col
1129  rec_token = trim(ks_cols(m))
1130  call upcase(rec_token)
1131 
1132  ! locate matching param_dfns entry for this token
1133  do n = 1, size(this%mf6_input%param_dfns)
1134  if (this%mf6_input%param_dfns(n)%blockname /= this%blockname) cycle
1135  tagname = this%mf6_input%param_dfns(n)%tagname
1136  call upcase(tagname)
1137  if (trim(tagname) /= trim(rec_token)) cycle
1138 
1139  idt => this%mf6_input%param_dfns(n)
1140  if (idt_datatype(idt) == 'RECORD') then
1141  ! compound group: expand body members in RECORD type order
1142  nitems0 = nkeystring_items
1143  call expand_record_body(this%mf6_input, idt, item_names, &
1144  nkeystring_items)
1145  ! first added entry is the KEYWORD head; remaining are body members
1146  do k = nitems0 + 1, nkeystring_items
1147  call expandarray(head_nbody)
1148  call expandarray(item_is_body)
1149  if (k == nitems0 + 1) then
1150  head_nbody(k) = nkeystring_items - nitems0 - 1
1151  item_is_body(k) = .false.
1152  else
1153  head_nbody(k) = 0
1154  item_is_body(k) = .true.
1155  end if
1156  end do
1157  else
1158  ! direct-dispatch param
1159  nkeystring_items = nkeystring_items + 1
1160  call expandarray(item_names)
1161  call expandarray(head_nbody)
1162  call expandarray(item_is_body)
1163  item_names(nkeystring_items) = &
1164  trim(this%mf6_input%param_dfns(n)%tagname)
1165  head_nbody(nkeystring_items) = 0
1166  item_is_body(nkeystring_items) = .false.
1167  end if
1168  exit
1169  end do
1170  end do
1171 
1172  if (allocated(ks_cols)) deallocate (ks_cols)
1173  end subroutine keystring_item_names
1174 
1175  !> @brief Check whether any in-scope parameter is a development-mode feature.
1176  !<
1177  subroutine check_developmode(this, input_name)
1178  use featureflagsmodule, only: developmode
1179  use simvariablesmodule, only: iout
1181  class(loadcontexttype) :: this
1182  character(len=*), intent(in) :: input_name
1183  type(inputparamdefinitiontype), pointer :: idt
1184  character(len=LINELENGTH) :: dev_msg
1185  integer(I4B) :: n
1186 
1187  do n = 1, size(this%params)
1188  idt => get_param_definition_type(this%mf6_input%param_dfns, &
1189  this%mf6_input%component_type, &
1190  this%mf6_input%subcomponent_type, &
1191  this%blockname, this%params(n), '')
1192  if (idt%developmode) then
1193  dev_msg = 'Input tag "'//trim(idt%tagname)// &
1194  &'" read from file "'//trim(input_name)// &
1195  &'" is still under development. Install the &
1196  &nightly build or compile from source with IDEVELOPMODE = 1.'
1197  call developmode(dev_msg, iout)
1198  end if
1199  end do
1200  end subroutine check_developmode
1201 
1202  !> @brief create read state variable name
1203  !<
1204  function rsv_name(mf6varname) result(varname)
1205  use constantsmodule, only: lenvarname
1206  character(len=*), intent(in) :: mf6varname
1207  character(len=LENVARNAME) :: varname
1208  integer(I4B) :: ilen
1209  character(len=2) :: prefix = 'IN'
1210  ilen = len_trim(mf6varname)
1211  if (ilen > (lenvarname - len(prefix))) then
1212  varname = prefix//mf6varname(1:(lenvarname - len(prefix)))
1213  else
1214  varname = prefix//trim(mf6varname)
1215  end if
1216  end function rsv_name
1217 
1218  !> @brief allocate int1d
1219  !<
1220  subroutine allocate_int1d(nrow, varname, mempath)
1222  integer(I4B), intent(in) :: nrow !< integer array number of rows
1223  character(len=*), intent(in) :: varname !< variable name
1224  character(len=*), intent(in) :: mempath !< variable mempath
1225  integer(I4B), dimension(:), pointer, contiguous :: int1d
1226  integer(I4B) :: n
1227  call mem_allocate(int1d, nrow, varname, mempath)
1228  do n = 1, nrow
1229  int1d(n) = izero
1230  end do
1231  end subroutine allocate_int1d
1232 
1233  !> @brief allocate dbl1d
1234  !<
1235  subroutine allocate_dbl1d(nrow, varname, mempath)
1237  integer(I4B), intent(in) :: nrow !< integer array number of rows
1238  character(len=*), intent(in) :: varname !< variable name
1239  character(len=*), intent(in) :: mempath !< variable mempath
1240  real(DP), dimension(:), pointer, contiguous :: dbl1d
1241  integer(I4B) :: n
1242  call mem_allocate(dbl1d, nrow, varname, mempath)
1243  do n = 1, nrow
1244  dbl1d(n) = dzero
1245  end do
1246  end subroutine allocate_dbl1d
1247 
1248  !> @brief allocate dbl2d
1249  !<
1250  subroutine allocate_dbl2d(ncol, nrow, varname, mempath)
1252  integer(I4B), intent(in) :: ncol !< integer array number of cols
1253  integer(I4B), intent(in) :: nrow !< integer array number of rows
1254  character(len=*), intent(in) :: varname !< variable name
1255  character(len=*), intent(in) :: mempath !< variable mempath
1256  real(DP), dimension(:, :), pointer, contiguous :: dbl2d
1257  integer(I4B) :: n, m
1258  call mem_allocate(dbl2d, ncol, nrow, varname, mempath)
1259  do m = 1, nrow
1260  do n = 1, ncol
1261  dbl2d(n, m) = dzero
1262  end do
1263  end do
1264  end subroutine allocate_dbl2d
1265 
1266  !> @brief allocate intptr and update from input context
1267  !!
1268  !<
1269  subroutine setval(intptr, varname, mempath)
1271  integer(I4B), pointer, intent(inout) :: intptr
1272  character(len=*), intent(in) :: varname
1273  character(len=*), intent(in) :: mempath
1274  logical(LGP) :: found
1275  allocate (intptr)
1276  intptr = 0
1277  call mem_set_value(intptr, varname, mempath, found, release=.false.)
1278  end subroutine setval
1279 
1280  !> @brief set intptr to varname
1281  !!
1282  !<
1283  subroutine setptr_int(intptr, varname, mempath)
1285  integer(I4B), pointer, intent(inout) :: intptr
1286  character(len=*), intent(in) :: varname
1287  character(len=*), intent(in) :: mempath
1288  integer(I4B) :: isize
1289  call get_isize(varname, mempath, isize)
1290  if (isize > -1) then
1291  call mem_setptr(intptr, varname, mempath)
1292  else
1293  call mem_allocate(intptr, varname, mempath)
1294  intptr = 0
1295  end if
1296  end subroutine setptr_int
1297 
1298  !> @brief set charstr1d pointer to varname
1299  !<
1300  subroutine setptr_charstr1d(charstr1d, varname, mempath, strlen)
1302  type(characterstringtype), dimension(:), pointer, &
1303  contiguous, intent(inout) :: charstr1d
1304  character(len=*), intent(in) :: varname
1305  character(len=*), intent(in) :: mempath
1306  integer(I4B), intent(in) :: strlen
1307  integer(I4B) :: isize
1308  call get_isize(varname, mempath, isize)
1309  if (isize > -1) then
1310  call mem_setptr(charstr1d, varname, mempath)
1311  else
1312  call mem_allocate(charstr1d, strlen, 0, varname, mempath)
1313  end if
1314  end subroutine setptr_charstr1d
1315 
1316  !> @brief set auxvar pointer
1317  !!
1318  !<
1319  subroutine setptr_auxvar(auxvar, mempath)
1321  real(DP), dimension(:, :), pointer, &
1322  contiguous, intent(inout) :: auxvar
1323  character(len=*), intent(in) :: mempath
1324  integer(I4B) :: isize
1325  call get_isize('AUXVAR', mempath, isize)
1326  if (isize > -1) then
1327  call mem_setptr(auxvar, 'AUXVAR', mempath)
1328  else
1329  call mem_allocate(auxvar, 0, 0, 'AUXVAR', mempath)
1330  end if
1331  end subroutine setptr_auxvar
1332 
1333 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