MODFLOW 6  version 6.9.0.dev0
USGS Modular Hydrologic Model
LoadMf6File.f90
Go to the documentation of this file.
1 !> @brief This module contains the LoadMf6FileModule
2 !!
3 !! This module contains the input data model routines for
4 !! loading static data from a MODFLOW 6 input file using the
5 !! block parser.
6 !!
7 !<
9 
10  use kindmodule, only: dp, i4b, lgp
11  use simvariablesmodule, only: errmsg
12  use simmodule, only: store_error
25  use inputoutputmodule, only: parseline
36 
37  implicit none
38  private
39  public :: loadmf6filetype
40  public :: read_control_record
41 
42  !> @brief Fortran workaround for allocatable arrays of pointers; wraps a StructArray pointer for deferred TS linking.
43  !<
44  type :: staticsatype
45  type(structarraytype), pointer :: sa => null()
46  end type staticsatype
47 
48  !> @brief Static parser based input loader
49  !!
50  !! This type defines a static input context loader
51  !! for traditional mf6 ascii input files.
52  !!
53  !<
55  type(blockparsertype), pointer :: parser !< ascii block parser
56  integer(I4B), dimension(:), pointer, contiguous :: mshape => null() !< model shape
57  type(structarraytype), pointer :: structarray => null() !< structarray for loading list input
58  type(staticsatype), allocatable :: ts_sas(:) !< saved structarrays for deferred TS linking
59  type(modflowinputtype) :: mf6_input !< description of input
60  type(ncpackagevarstype), pointer :: nc_vars => null()
61  character(len=LINELENGTH) :: filename !< name of ascii input file
62  character(len=LINELENGTH), dimension(:), allocatable :: block_tags !< read block tags
63  logical(LGP) :: ts_active !< is timeseries active
64  logical(LGP) :: export !< is array export active
65  logical(LGP) :: readasarrays
66  logical(LGP) :: readarraygrid
67  integer(I4B) :: inamedbound
68  integer(I4B) :: iauxiliary
69  integer(I4B) :: iout !< inunit for list log
70  contains
71  procedure :: load
72  procedure :: init
73  procedure :: load_block
74  procedure :: finalize
75  procedure :: parse_block
76  procedure :: block_post_process
77  procedure :: parse_io_tag
78  procedure :: parse_record_tag
79  procedure :: load_tag
80  procedure :: block_index_dfn
82  procedure :: save_ts_sa
83  procedure :: ts_sa_count
84  procedure :: get_ts_sa
85  procedure :: cleanup
86  end type loadmf6filetype
87 
88 contains
89 
90  !> @brief load all static input blocks
91  !!
92  !! Invoke this routine to load all static input blocks
93  !! in single call.
94  !!
95  !<
96  subroutine load(this, parser, mf6_input, nc_vars, filename, iout)
97  class(loadmf6filetype) :: this
98  type(blockparsertype), target, intent(inout) :: parser
99  type(modflowinputtype), intent(in) :: mf6_input
100  type(ncpackagevarstype), pointer, intent(in) :: nc_vars
101  character(len=*), intent(in) :: filename
102  integer(I4B), intent(in) :: iout
103  integer(I4B) :: iblk
104 
105  ! initialize static load
106  call this%init(parser, mf6_input, filename, iout)
107 
108  ! set netcdf vars
109  this%nc_vars => nc_vars
110 
111  ! process blocks
112  do iblk = 1, size(this%mf6_input%block_dfns)
113  ! don't load dynamic input data
114  if (this%mf6_input%block_dfns(iblk)%blockname == 'PERIOD') exit
115  ! load the block
116  call this%load_block(iblk)
117  end do
118 
119  ! finalize static load
120  call this%finalize()
121  end subroutine load
122 
123  !> @brief init
124  !!
125  !! init / finalize are only used when load_block() will be called
126  !!
127  !<
128  subroutine init(this, parser, mf6_input, filename, iout)
129  class(loadmf6filetype) :: this
130  type(blockparsertype), target, intent(inout) :: parser
131  type(modflowinputtype), intent(in) :: mf6_input
132  character(len=*), intent(in) :: filename
133  integer(I4B), intent(in) :: iout
134  integer(I4B) :: isize
135 
136  this%parser => parser
137  this%mf6_input = mf6_input
138  this%filename = filename
139  this%ts_active = .false.
140  this%export = .false.
141  this%readasarrays = .false.
142  this%readarraygrid = .false.
143  this%inamedbound = 0
144  this%iauxiliary = 0
145  this%iout = iout
146 
147  call get_isize('MODEL_SHAPE', mf6_input%component_mempath, isize)
148  if (isize > 0) then
149  call mem_setptr(this%mshape, 'MODEL_SHAPE', mf6_input%component_mempath)
150  end if
151 
152  ! init ts stuctarray list
153  allocate (this%ts_sas(0))
154 
155  ! log lst file header
156  call idm_log_header(this%mf6_input%component_name, &
157  this%mf6_input%subcomponent_name, this%iout)
158  end subroutine init
159 
160  !> @brief load a single block
161  !!
162  !! Assumed in order load of single (next) block. If a
163  !! StructArray object is allocated to load this block
164  !! it persists until this routine (or finalize) is
165  !! called again.
166  !!
167  !<
168  subroutine load_block(this, iblk)
170  class(loadmf6filetype) :: this
171  integer(I4B), intent(in) :: iblk
172 
173  ! reset structarray if it was created for previous block
174  if (associated(this%structarray)) then
175  ! destroy the structured array reader
176  call destructstructarray(this%structarray)
177  end if
178 
179  allocate (this%block_tags(0))
180  ! load the block
181  call this%parse_block(iblk, .false.)
182  ! post process block
183  call this%block_post_process(iblk)
184  ! cleanup
185  deallocate (this%block_tags)
186  end subroutine load_block
187 
188  !> @brief finalize
189  !!
190  !! init / finalize are only used when load_block() will be called
191  !!
192  !<
193  subroutine finalize(this)
195  class(loadmf6filetype) :: this
196  ! cleanup
197  if (associated(this%structarray)) then
198  ! destroy the structured array reader
199  call destructstructarray(this%structarray)
200  end if
201  ! close logging block
202  call idm_log_close(this%mf6_input%component_name, &
203  this%mf6_input%subcomponent_name, this%iout)
204  end subroutine finalize
205 
206  !> @brief Post parse block handling
207  !!
208  !<
209  subroutine block_post_process(this, iblk)
211  class(loadmf6filetype) :: this
212  integer(I4B), intent(in) :: iblk
213  type(inputparamdefinitiontype), pointer :: idt
214  integer(I4B) :: iparam
215  integer(I4B), pointer :: intptr
216 
217  ! update state based on read tags
218  do iparam = 1, size(this%block_tags)
219  select case (this%mf6_input%block_dfns(iblk)%blockname)
220  case ('OPTIONS')
221  if (this%block_tags(iparam) == 'AUXILIARY') then
222  this%iauxiliary = 1
223  else if (this%block_tags(iparam) == 'BOUNDNAMES') then
224  this%inamedbound = 1
225  else if (this%block_tags(iparam) == 'READASARRAYS') then
226  this%readasarrays = .true.
227  else if (this%block_tags(iparam) == 'READARRAYGRID') then
228  this%readarraygrid = .true.
229  else if (this%block_tags(iparam) == 'TS6_FILENAME') then
230  this%ts_active = .true.
231  else if (this%block_tags(iparam) == 'EXPORT_ARRAY_ASCII') then
232  this%export = .true.
233  end if
234  case default
235  end select
236  end do
237 
238  ! update input context allocations based on dfn set and input
239  select case (this%mf6_input%block_dfns(iblk)%blockname)
240  case ('OPTIONS')
241  ! allocate naux and set to 0 if not allocated
242  do iparam = 1, size(this%mf6_input%param_dfns)
243  idt => this%mf6_input%param_dfns(iparam)
244  if (idt%blockname == 'OPTIONS' .and. &
245  idt%tagname == 'AUXILIARY') then
246  if (this%iauxiliary == 0) then
247  call mem_allocate(intptr, 'NAUX', this%mf6_input%mempath)
248  intptr = 0
249  end if
250  exit
251  end if
252  end do
253  case ('DIMENSIONS')
254  ! set model shape if discretization dimensions have been read
255  if (this%mf6_input%pkgtype(1:3) == 'DIS') then
256  call set_model_shape(this%mf6_input%pkgtype, this%filename, &
257  this%mf6_input%component_mempath, &
258  this%mf6_input%mempath, this%mshape)
259  end if
260  case default
261  end select
262  end subroutine block_post_process
263 
264  !> @brief parse block
265  !!
266  !<
267  recursive subroutine parse_block(this, iblk, recursive_call)
268  use memorytypemodule, only: memorytype
270  class(loadmf6filetype) :: this
271  integer(I4B), intent(in) :: iblk
272  logical(LGP), intent(in) :: recursive_call !< true if recursive call
273  logical(LGP) :: isblockfound
274  logical(LGP) :: endofblock
275  logical(LGP) :: supportopenclose
276  integer(I4B) :: ierr
277  logical(LGP) :: found, required
278  type(memorytype), pointer :: mt
279  character(len=LINELENGTH) :: tag
280  type(inputparamdefinitiontype), pointer :: idt
281 
282  ! disu vertices/cell2d blocks are contingent on NVERT dimension
283  if (this%mf6_input%pkgtype == 'DISU6' .or. &
284  this%mf6_input%pkgtype == 'DISV1D6' .or. &
285  this%mf6_input%pkgtype == 'DISV2D6') then
286  if (this%mf6_input%block_dfns(iblk)%blockname == 'VERTICES' .or. &
287  this%mf6_input%block_dfns(iblk)%blockname == 'CELL2D') then
288  call get_from_memorystore('NVERT', this%mf6_input%mempath, mt, found, &
289  .false.)
290  if (.not. found) return
291  if (mt%intsclr == 0) return
292  end if
293  end if
294 
295  ! block open/close support
296  supportopenclose = (this%mf6_input%block_dfns(iblk)%blockname /= 'GRIDDATA')
297 
298  ! parser search for block
299  required = this%mf6_input%block_dfns(iblk)%required .and. .not. recursive_call
300  call this%parser%GetBlock(this%mf6_input%block_dfns(iblk)%blockname, &
301  isblockfound, ierr, &
302  supportopenclose=supportopenclose, &
303  blockrequired=required)
304  ! process block
305  if (isblockfound) then
306  if (this%mf6_input%block_dfns(iblk)%aggregate) then
307  ! process block recarray type, set of variable 1d/2d types
308  call this%parse_structarray_block(iblk)
309  else
310  do
311  ! process each line in block
312  call this%parser%GetNextLine(endofblock)
313  if (endofblock) exit
314  ! process line as tag(s)
315  call this%parser%GetStringCaps(tag)
316  idt => get_param_definition_type( &
317  this%mf6_input%param_dfns, &
318  this%mf6_input%component_type, &
319  this%mf6_input%subcomponent_type, &
320  this%mf6_input%block_dfns(iblk)%blockname, &
321  tag, this%filename)
322  if (idt%in_record) then
323  call this%parse_record_tag(iblk, idt, .false.)
324  else
325  call this%load_tag(iblk, idt)
326  end if
327  end do
328  end if
329  end if
330 
331  ! recurse if block is reloadable and was just read
332  if (this%mf6_input%block_dfns(iblk)%block_variable) then
333  if (isblockfound) then
334  call this%parse_block(iblk, .true.)
335  end if
336  end if
337  end subroutine parse_block
338 
339  subroutine parse_io_tag(this, iblk, pkgtype, which, tag)
341  class(loadmf6filetype) :: this
342  integer(I4B), intent(in) :: iblk
343  character(len=*), intent(in) :: pkgtype
344  character(len=*), intent(in) :: which
345  character(len=*), intent(in) :: tag
346  type(inputparamdefinitiontype), pointer :: idt !< input data type object describing this record
347  ! matches, read and load file name
348  idt => &
349  get_param_definition_type(this%mf6_input%param_dfns, &
350  this%mf6_input%component_type, &
351  this%mf6_input%subcomponent_type, &
352  this%mf6_input%block_dfns(iblk)%blockname, &
353  tag, this%filename)
354  ! load io tag
355  call load_io_tag(this%parser, idt, this%mf6_input%mempath, which, this%iout)
356  call expandarray(this%block_tags)
357  this%block_tags(size(this%block_tags)) = trim(idt%tagname)
358  end subroutine parse_io_tag
359 
360  recursive subroutine parse_record_tag(this, iblk, inidt, recursive_call)
364  class(loadmf6filetype) :: this
365  integer(I4B), intent(in) :: iblk
366  type(inputparamdefinitiontype), pointer, intent(in) :: inidt
367  logical(LGP), intent(in) :: recursive_call !< true if recursive call
368  type(inputparamdefinitiontype), pointer :: idt
369  character(len=40), dimension(:), allocatable :: words
370  integer(I4B) :: n, istart, nwords
371  character(len=LINELENGTH) :: tag
372 
373  nullify (idt)
374  istart = 1
375 
376  if (recursive_call) then
377  call split_record_dfn_tag1(this%mf6_input%param_dfns, &
378  this%mf6_input%component_type, &
379  this%mf6_input%subcomponent_type, &
380  inidt%tagname, nwords, words)
381  call this%load_tag(iblk, inidt)
382  istart = 3
383  else
384  call this%parser%GetStringCaps(tag)
385  if (tag /= '') then
386  call split_record_dfn_tag2(this%mf6_input%param_dfns, &
387  this%mf6_input%component_type, &
388  this%mf6_input%subcomponent_type, &
389  inidt%tagname, tag, nwords, words)
390  if (nwords == 4 .and. &
391  (tag == 'FILEIN' .or. &
392  tag == 'FILEOUT')) then
393  call this%parse_io_tag(iblk, words(2), words(3), words(4))
394  nwords = 0
395  else
396  idt => get_param_definition_type( &
397  this%mf6_input%param_dfns, &
398  this%mf6_input%component_type, &
399  this%mf6_input%subcomponent_type, &
400  this%mf6_input%block_dfns(iblk)%blockname, &
401  tag, this%filename)
402  ! avoid namespace collisions (CIM)
403  if (tag /= 'PRINT_FORMAT') call this%load_tag(iblk, inidt)
404  call this%load_tag(iblk, idt)
405  istart = 4
406  end if
407  else
408  call this%load_tag(iblk, inidt)
409  nwords = 0
410  end if
411  end if
412 
413  if (istart > 1 .and. nwords == 0) then
414  write (errmsg, '(5a)') &
415  '"', trim(this%mf6_input%block_dfns(iblk)%blockname), &
416  '" block input record that includes keyword "', trim(inidt%tagname), &
417  '" is not properly formed.'
418  call store_error(errmsg)
419  call this%parser%StoreErrorUnit()
420  end if
421 
422  do n = istart, nwords
423  idt => get_param_definition_type( &
424  this%mf6_input%param_dfns, &
425  this%mf6_input%component_type, &
426  this%mf6_input%subcomponent_type, &
427  this%mf6_input%block_dfns(iblk)%blockname, &
428  words(n), this%filename)
429  if (idt_datatype(idt) == 'RECORD') then
430  call this%parser%GetStringCaps(tag)
431  idt => get_param_definition_type( &
432  this%mf6_input%param_dfns, &
433  this%mf6_input%component_type, &
434  this%mf6_input%subcomponent_type, &
435  this%mf6_input%block_dfns(iblk)%blockname, &
436  tag, this%filename)
437  call this%parse_record_tag(iblk, idt, .true.)
438  exit
439  else
440  if (idt%tagname /= 'FORMAT') then
441  call this%parser%GetStringCaps(tag)
442  if (tag == '') then
443  exit
444  else if (idt%tagname /= tag) then
445  write (errmsg, '(5a)') 'Expecting record input tag "', &
446  trim(idt%tagname), '" but instead found "', trim(tag), '".'
447  call store_error(errmsg)
448  call this%parser%StoreErrorUnit()
449  end if
450  end if
451  call this%load_tag(iblk, idt)
452  end if
453  end do
454 
455  if (allocated(words)) deallocate (words)
456  end subroutine parse_record_tag
457 
458  !> @brief load input keyword
459  !! Load input associated with tag key into the memory manager.
460  !<
461  subroutine load_tag(this, iblk, idt)
464  class(loadmf6filetype) :: this
465  integer(I4B), intent(in) :: iblk
466  type(inputparamdefinitiontype), pointer, intent(in) :: idt !< input data type object describing this record
467  character(len=LINELENGTH) :: dev_msg
468 
469  ! check if input param is developmode
470  if (idt%developmode) then
471  dev_msg = 'Input tag "'//trim(idt%tagname)// &
472  &'" read from file "'//trim(this%filename)// &
473  &'" is still under development. Install the &
474  &nightly build or compile from source with IDEVELOPMODE = 1.'
475  call developmode(dev_msg, this%iout)
476  end if
477 
478  ! allocate and load data type
479  select case (idt%datatype)
480  case ('KEYWORD')
481  call load_keyword_type(this%parser, idt, this%mf6_input%mempath, this%iout)
482  ! check/set as dev option
483  if (idt%tagname(1:4) == 'DEV_' .and. &
484  this%mf6_input%block_dfns(iblk)%blockname == 'OPTIONS') then
485  call this%parser%DevOpt()
486  end if
487  case ('STRING')
488  if (idt%shape == 'NAUX') then
489  call load_auxvar_names(this%parser, idt, this%mf6_input%mempath, &
490  this%iout)
491  else
492  call load_string_type(this%parser, idt, this%mf6_input%mempath, this%iout)
493  end if
494  case ('INTEGER')
495  call load_integer_type(this%parser, idt, this%mf6_input%mempath, this%iout)
496  case ('INTEGER1D')
497  call load_integer1d_type(this%parser, idt, this%mf6_input, this%mshape, &
498  this%export, this%nc_vars, this%filename, &
499  this%iout)
500  case ('INTEGER2D')
501  call load_integer2d_type(this%parser, idt, this%mf6_input, this%mshape, &
502  this%export, this%nc_vars, this%filename, &
503  this%iout)
504  case ('INTEGER3D')
505  call load_integer3d_type(this%parser, idt, this%mf6_input, this%mshape, &
506  this%export, this%nc_vars, this%filename, &
507  this%iout)
508  case ('DOUBLE')
509  call load_double_type(this%parser, idt, this%mf6_input%mempath, this%iout)
510  case ('DOUBLE1D')
511  call load_double1d_type(this%parser, idt, this%mf6_input, this%mshape, &
512  this%export, this%nc_vars, this%filename, this%iout)
513  case ('DOUBLE2D')
514  call load_double2d_type(this%parser, idt, this%mf6_input, this%mshape, &
515  this%export, this%nc_vars, this%filename, this%iout)
516  case ('DOUBLE3D')
517  call load_double3d_type(this%parser, idt, this%mf6_input, this%mshape, &
518  this%export, this%nc_vars, this%filename, this%iout)
519  case default
520  write (errmsg, '(a,a)') 'Failure reading data for tag: ', trim(idt%tagname)
521  call store_error(errmsg)
522  call this%parser%StoreErrorUnit()
523  end select
524 
525  call expandarray(this%block_tags)
526  this%block_tags(size(this%block_tags)) = trim(idt%tagname)
527  end subroutine load_tag
528 
529  function block_index_dfn(this, iblk) result(idt)
530  class(loadmf6filetype) :: this
531  integer(I4B), intent(in) :: iblk
532  type(inputparamdefinitiontype) :: idt !< input data type object describing this record
533  character(len=LENVARNAME) :: varname
534  integer(I4B) :: ilen
535  character(len=3) :: block_suffix = 'NUM'
536 
537  ! assign first column as the block number
538  ilen = len_trim(this%mf6_input%block_dfns(iblk)%blockname)
539 
540  if (ilen > (lenvarname - len(block_suffix))) then
541  varname = &
542  this%mf6_input%block_dfns(iblk)% &
543  blockname(1:(lenvarname - len(block_suffix)))//block_suffix
544  else
545  varname = trim(this%mf6_input%block_dfns(iblk)%blockname)//block_suffix
546  end if
547 
548  idt%component_type = trim(this%mf6_input%component_type)
549  idt%subcomponent_type = trim(this%mf6_input%subcomponent_type)
550  idt%blockname = trim(this%mf6_input%block_dfns(iblk)%blockname)
551  idt%tagname = varname
552  idt%mf6varname = varname
553  idt%datatype = 'INTEGER'
554  end function block_index_dfn
555 
556  !> @brief parse a structured array record into memory manager
557  !!
558  !! A structarray is similar to a numpy recarray. It it used to
559  !! load a list of data in which each column in the list may be a
560  !! different type. Each column in the list is stored as a 1d
561  !! vector.
562  !!
563  !<
564  subroutine parse_structarray_block(this, iblk)
567  class(loadmf6filetype) :: this
568  integer(I4B), intent(in) :: iblk
569  type(loadcontexttype) :: ctx
570  character(len=LINELENGTH), dimension(:), allocatable :: param_names
571  type(inputparamdefinitiontype), pointer :: idt !< input data type object describing this record
572  type(inputparamdefinitiontype), pointer :: shape_idt
573  type(inputparamdefinitiontype), target :: blockvar_idt
574  integer(I4B) :: blocknum
575  integer(I4B), pointer :: nrow
576  integer(I4B), dimension(:), pointer, contiguous :: int1d
577  integer(I4B) :: nrows, nrowsread
578  integer(I4B) :: mem_rank, isize
579  integer(I4B) :: ibinary, oc_inunit
580  integer(I4B) :: icol, iparam
581  integer(I4B) :: ncol, nparam
582  logical(LGP) :: shape_found
583  logical(LGP) :: is_sum_shape
584  character(len=LINELENGTH) :: shape_name
585  integer(I4B), pointer :: pkgdata_maxbound
586 
587  nrows = -1
588 
589  ! initialize load context
590  call ctx%init(this%mf6_input, blockname= &
591  this%mf6_input%block_dfns(iblk)%blockname)
592  ! set in-scope params directly from context
593  param_names = ctx%params
594  nparam = size(ctx%params)
595  call ctx%check_developmode(this%filename)
596  ! set input definition for this block
597  idt => &
598  get_aggregate_definition_type(this%mf6_input%aggregate_dfns, &
599  this%mf6_input%component_type, &
600  this%mf6_input%subcomponent_type, &
601  this%mf6_input%block_dfns(iblk)%blockname)
602  ! if block is reloadable read the block number
603  if (this%mf6_input%block_dfns(iblk)%block_variable) then
604  blocknum = this%parser%GetInteger()
605  else
606  blocknum = 0
607  end if
608 
609  ! set ncol
610  ncol = nparam
611  ! add col if block is reloadable
612  if (blocknum > 0) ncol = ncol + 1
613  ! use shape to set the max num of rows
614  if (idt%shape /= '') then
615  ! "SUM(name)" means total rows = sum of a per-feature array (e.g.
616  ! LAK's CONNECTIONDATA: NLAKECONN summed across all lakes); this
617  ! notation is declared explicitly in the dfn, not inferred
618  is_sum_shape = .false.
619  shape_name = idt%shape
620  if (idt%shape(1:4) == 'SUM(') then
621  is_sum_shape = .true.
622  shape_name = idt%shape(5:len_trim(idt%shape) - 1)
623  end if
624  shape_idt => &
625  get_param_definition_type(this%mf6_input%param_dfns, &
626  this%mf6_input%component_type, &
627  this%mf6_input%subcomponent_type, &
628  'DIMENSIONS', shape_name, this%filename, &
629  found=shape_found)
630  if (.not. shape_found) then
631  ! also allow a per-row PACKAGEDATA field (e.g. LAK's NLAKECONN)
632  shape_idt => &
633  get_param_definition_type(this%mf6_input%param_dfns, &
634  this%mf6_input%component_type, &
635  this%mf6_input%subcomponent_type, &
636  'PACKAGEDATA', shape_name, this%filename, &
637  found=shape_found)
638  end if
639  if (shape_found) then
640  call get_isize(shape_idt%mf6varname, this%mf6_input%mempath, isize)
641  if (isize < 0) then
642  if (shape_idt%required) then
643  write (errmsg, '(3a)') 'Required dimension "', &
644  trim(shape_name), '" not found.'
645  call store_error(errmsg)
646  call this%parser%StoreErrorUnit()
647  end if
648  else
649  ! cross-check the dfn's declared SUM(...)/plain shape against the
650  ! variable's actual rank, so a mismatch errors instead of
651  ! silently mis-using a scalar/array pointer
652  call get_mem_rank(shape_idt%mf6varname, this%mf6_input%mempath, &
653  mem_rank)
654  if (is_sum_shape .and. mem_rank == 1) then
655  call mem_setptr(int1d, shape_idt%mf6varname, this%mf6_input%mempath)
656  nrows = sum(int1d)
657  nullify (int1d)
658  else if (.not. is_sum_shape .and. mem_rank == 0) then
659  ! scalar shape variable (e.g. NLAKES, MAXBOUND) — use value directly
660  call mem_setptr(nrow, shape_idt%mf6varname, this%mf6_input%mempath)
661  nrows = nrow
662  else
663  write (errmsg, '(5a)') 'Shape variable "', trim(shape_name), &
664  '" rank does not match its declared shape "', &
665  trim(idt%shape), '".'
666  call store_error(errmsg)
667  call this%parser%StoreErrorUnit()
668  end if
669  end if
670  end if
671  ! -- else: shape variable not found; nrows stays at its initial -1, so
672  ! the block falls back to deferred sizing
673  end if
674 
675  ! create a structured array; use a larger deferred init for blocks with no
676  ! explicit shape, which include APT based advanced packages.
677  if (nrows < 0) then
678  this%structarray => constructstructarray(this%mf6_input, ncol, nrows, &
679  blocknum, this%mf6_input%mempath, &
680  this%mf6_input%component_mempath, &
681  size_init=64)
682  else
683  this%structarray => constructstructarray(this%mf6_input, ncol, nrows, &
684  blocknum, this%mf6_input%mempath, &
685  this%mf6_input%component_mempath)
686  end if
687  ! create structarray vectors for each column
688  do icol = 1, ncol
689  ! if block is reloadable, block number is first column
690  if (blocknum > 0) then
691  if (icol == 1) then
692  blockvar_idt = this%block_index_dfn(iblk)
693  idt => blockvar_idt
694  call this%structarray%mem_create_vector(icol, idt)
695  ! continue as this column managed by internally SA object
696  cycle
697  end if
698  ! set indexes (where first column is blocknum)
699  iparam = icol - 1
700  else
701  ! set indexes (no blocknum column)
702  iparam = icol
703  end if
704  ! set pointer to input definition for this 1d vector
705  idt => &
706  get_param_definition_type(this%mf6_input%param_dfns, &
707  this%mf6_input%component_type, &
708  this%mf6_input%subcomponent_type, &
709  this%mf6_input%block_dfns(iblk)%blockname, &
710  param_names(iparam), this%filename)
711  ! allocate variable in memory manager
712  call this%structarray%mem_create_vector(icol, idt)
713  end do
714 
715  ! finish context setup after allocating vectors
716  call ctx%allocate_arrays()
717 
718  ! read the block control record
719  ibinary = read_control_record(this%parser, oc_inunit, this%iout)
720 
721  if (ibinary == 1) then
722  ! read from binary
723  nrowsread = this%structarray%read_from_binary(oc_inunit, this%iout)
724  call this%parser%terminateblock()
725  close (oc_inunit)
726  else
727  ! read from ascii
728  nrowsread = this%structarray%read_from_parser(this%parser, this%ts_active, &
729  this%iout, this%filename)
730  ! save structarray for deferred TS linking in df() if any strlocs were stored
731  if (this%ts_active) call this%save_ts_sa()
732  end if
733 
734  ! an advanced package's PACKAGEDATA row count is published as
735  ! MAXBOUND, the feature count the PERIOD block's load context needs
736  if (this%mf6_input%block_dfns(iblk)%blockname == 'PACKAGEDATA' .and. &
737  is_feature_keystring(this%mf6_input) .and. ctx%is_advanced) then
738  call get_isize('MAXBOUND', this%mf6_input%mempath, isize)
739  if (isize < 0) then
740  call mem_allocate(pkgdata_maxbound, 'MAXBOUND', this%mf6_input%mempath)
741  pkgdata_maxbound = nrowsread
742  end if
743  end if
744 
745  ! clean up
746  call ctx%destroy()
747  end subroutine parse_structarray_block
748 
749  !> @brief Return number of saved static StructArrays with deferred TS strlocs
750  !<
751  function ts_sa_count(this) result(n)
752  class(loadmf6filetype), intent(in) :: this
753  integer(I4B) :: n
754  n = size(this%ts_sas)
755  end function ts_sa_count
756 
757  !> @brief Return the n-th saved static StructArray pointer
758  !<
759  function get_ts_sa(this, n) result(sa)
760  class(loadmf6filetype), intent(in) :: this
761  integer(I4B), intent(in) :: n
762  type(structarraytype), pointer :: sa
763  sa => this%ts_sas(n)%sa
764  end function get_ts_sa
765 
766  !> @brief load type keyword
767  !<
768  subroutine load_keyword_type(parser, idt, memoryPath, iout)
769  type(blockparsertype), intent(inout) :: parser !< block parser
770  type(inputparamdefinitiontype), intent(in) :: idt !< input data type object describing this record
771  character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information
772  integer(I4B), intent(in) :: iout !< unit number for output
773  integer(I4B), pointer :: intvar
774  call mem_allocate(intvar, idt%mf6varname, memorypath)
775  intvar = 1
776  call idm_log_var(intvar, idt%tagname, memorypath, idt%datatype, iout)
777  end subroutine load_keyword_type
778 
779  !> @brief load type string
780  !<
781  subroutine load_string_type(parser, idt, memoryPath, iout)
782  use constantsmodule, only: lenbigline
783  type(blockparsertype), intent(inout) :: parser !< block parser
784  type(inputparamdefinitiontype), intent(in) :: idt !< input data type object describing this record
785  character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information
786  integer(I4B), intent(in) :: iout !< unit number for output
787  character(len=LINELENGTH), pointer :: cstr
788  character(len=LENBIGLINE), pointer :: bigcstr
789  integer(I4B) :: ilen
790  select case (idt%shape)
791  case ('LENBIGLINE')
792  ilen = lenbigline
793  call mem_allocate(bigcstr, ilen, idt%mf6varname, memorypath)
794  call parser%GetString(bigcstr, (.not. idt%preserve_case))
795  call idm_log_var(bigcstr, idt%tagname, memorypath, iout)
796  case default
797  ilen = linelength
798  call mem_allocate(cstr, ilen, idt%mf6varname, memorypath)
799  call parser%GetString(cstr, (.not. idt%preserve_case))
800  call idm_log_var(cstr, idt%tagname, memorypath, iout)
801  end select
802  end subroutine load_string_type
803 
804  !> @brief load io tag
805  !<
806  subroutine load_io_tag(parser, idt, memoryPath, which, iout)
809  type(blockparsertype), intent(inout) :: parser !< block parser
810  type(inputparamdefinitiontype), intent(in) :: idt !< input data type object describing this record
811  character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information
812  character(len=*), intent(in) :: which
813  integer(I4B), intent(in) :: iout !< unit number for output
814  character(len=LINELENGTH) :: cstr
815  type(characterstringtype), dimension(:), pointer, contiguous :: charstr1d
816  integer(I4B) :: ilen, isize, idx
817  ilen = linelength
818  if (which == 'FILEIN') then
819  call get_isize(idt%mf6varname, memorypath, isize)
820  if (isize < 0) then
821  call mem_allocate(charstr1d, ilen, 1, idt%mf6varname, memorypath)
822  idx = 1
823  else
824  call mem_setptr(charstr1d, idt%mf6varname, memorypath)
825  call mem_reallocate(charstr1d, ilen, isize + 1, idt%mf6varname, &
826  memorypath)
827  idx = isize + 1
828  end if
829  call parser%GetString(cstr, (.not. idt%preserve_case))
830  charstr1d(idx) = cstr
831  else if (which == 'FILEOUT') then
832  call load_string_type(parser, idt, memorypath, iout)
833  end if
834  end subroutine load_io_tag
835 
836  !> @brief load aux variable names
837  !!
838  !<
839  subroutine load_auxvar_names(parser, idt, memoryPath, iout)
841  use inputoutputmodule, only: urdaux
843  type(blockparsertype), intent(inout) :: parser !< block parser
844  type(inputparamdefinitiontype), intent(in) :: idt !< input data type object describing this record
845  character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information
846  integer(I4B), intent(in) :: iout !< unit number for output
847  character(len=:), allocatable :: line
848  character(len=LENAUXNAME), dimension(:), allocatable :: caux
849  integer(I4B) :: lloc
850  integer(I4B) :: istart
851  integer(I4B) :: istop
852  integer(I4B) :: i
853  character(len=LENPACKAGENAME) :: text = ''
854  integer(I4B), pointer :: intvar
855  type(characterstringtype), dimension(:), &
856  pointer, contiguous :: acharstr1d !< variable for allocation
857  call mem_allocate(intvar, idt%shape, memorypath)
858  intvar = 0
859  call parser%GetRemainingLine(line)
860  lloc = 1
861  call urdaux(intvar, parser%iuactive, iout, lloc, &
862  istart, istop, caux, line, text)
863  call mem_allocate(acharstr1d, lenauxname, intvar, idt%mf6varname, memorypath)
864  do i = 1, intvar
865  acharstr1d(i) = caux(i)
866  end do
867  deallocate (line)
868  deallocate (caux)
869  end subroutine load_auxvar_names
870 
871  !> @brief load type integer
872  !<
873  subroutine load_integer_type(parser, idt, memoryPath, iout)
874  type(blockparsertype), intent(inout) :: parser !< block parser
875  type(inputparamdefinitiontype), intent(in) :: idt !< input data type object describing this record
876  character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information
877  integer(I4B), intent(in) :: iout !< unit number for output
878  integer(I4B), pointer :: intvar
879  call mem_allocate(intvar, idt%mf6varname, memorypath)
880  intvar = parser%GetInteger()
881  call idm_log_var(intvar, idt%tagname, memorypath, idt%datatype, iout)
882  end subroutine load_integer_type
883 
884  !> @brief load type 1d integer
885  !<
886  subroutine load_integer1d_type(parser, idt, mf6_input, mshape, export, &
887  nc_vars, input_fname, iout)
890  type(blockparsertype), intent(inout) :: parser !< block parser
891  type(inputparamdefinitiontype), intent(in) :: idt !< input data type object describing this record
892  type(modflowinputtype), intent(in) :: mf6_input !< description of input
893  integer(I4B), dimension(:), contiguous, pointer, intent(in) :: mshape !< model shape
894  logical(LGP), intent(in) :: export !< export to ascii layer files
895  type(ncpackagevarstype), pointer, intent(in) :: nc_vars
896  character(len=*), intent(in) :: input_fname !< ascii input file name
897  integer(I4B), intent(in) :: iout !< unit number for output
898  integer(I4B), dimension(:), pointer, contiguous :: int1d
899  integer(I4B) :: nlay
900  integer(I4B) :: nvals
901  integer(I4B), dimension(:), allocatable :: array_shape
902  integer(I4B), dimension(:), allocatable :: layer_shape
903  character(len=LINELENGTH) :: keyword
904 
905  ! Check if it is a full grid sized array (NODES), otherwise use
906  ! idt%shape to construct shape from variables in memoryPath
907  if (idt%shape == 'NODES') then
908  nvals = product(mshape)
909  else
910  call get_shape_from_string(idt%shape, array_shape, mf6_input%mempath)
911  nvals = array_shape(1)
912  end if
913 
914  ! allocate memory for the array
915  call mem_allocate(int1d, nvals, idt%mf6varname, mf6_input%mempath)
916 
917  ! read keyword
918  keyword = ''
919  call parser%GetStringCaps(keyword)
920 
921  ! check for "NETCDF" and "LAYERED"
922  if (keyword == 'NETCDF') then
923  call netcdf_read_array(int1d, mshape, idt, mf6_input, nc_vars, &
924  input_fname, iout)
925  else if (keyword == 'LAYERED' .and. idt%layered) then
926  call get_layered_shape(mshape, nlay, layer_shape)
927  call read_int1d_layered(parser, int1d, idt%mf6varname, nlay, layer_shape)
928  else
929  call read_int1d(parser, int1d, idt%mf6varname)
930  end if
931 
932  ! log information on the loaded array to the list file
933  call idm_log_var(int1d, idt%tagname, mf6_input%mempath, iout)
934 
935  ! create export file for griddata parameters if optioned
936  if (export) then
937  if (idt%blockname == 'GRIDDATA') then
938  call idm_export(int1d, idt%tagname, mf6_input%mempath, idt%shape, iout)
939  end if
940  end if
941  end subroutine load_integer1d_type
942 
943  !> @brief load type 2d integer
944  !<
945  subroutine load_integer2d_type(parser, idt, mf6_input, mshape, export, &
946  nc_vars, input_fname, iout)
949  type(blockparsertype), intent(inout) :: parser !< block parser
950  type(inputparamdefinitiontype), intent(in) :: idt !< input data type object describing this record
951  type(modflowinputtype), intent(in) :: mf6_input !< description of input
952  integer(I4B), dimension(:), contiguous, pointer, intent(in) :: mshape !< model shape
953  logical(LGP), intent(in) :: export !< export to ascii layer files
954  type(ncpackagevarstype), pointer, intent(in) :: nc_vars
955  character(len=*), intent(in) :: input_fname !< ascii input file name
956  integer(I4B), intent(in) :: iout !< unit number for output
957  integer(I4B), dimension(:, :), pointer, contiguous :: int2d
958  integer(I4B) :: nlay
959  integer(I4B) :: nsize1, nsize2
960  integer(I4B), dimension(:), allocatable :: array_shape
961  integer(I4B), dimension(:), allocatable :: layer_shape
962  character(len=LINELENGTH) :: keyword
963 
964  ! determine the array shape from the input data definition (idt%shape),
965  ! which looks like "NCOL, NROW, NLAY"
966  call get_shape_from_string(idt%shape, array_shape, mf6_input%mempath)
967  nsize1 = array_shape(1)
968  nsize2 = array_shape(2)
969 
970  ! create a new 3d memory managed variable
971  call mem_allocate(int2d, nsize1, nsize2, idt%mf6varname, mf6_input%mempath)
972 
973  ! read keyword
974  keyword = ''
975  call parser%GetStringCaps(keyword)
976 
977  ! check for "NETCDF" and "LAYERED"
978  if (keyword == 'NETCDF') then
979  call netcdf_read_array(int2d, mshape, idt, mf6_input, nc_vars, &
980  input_fname, iout)
981  else if (keyword == 'LAYERED' .and. idt%layered) then
982  call get_layered_shape(mshape, nlay, layer_shape)
983  call read_int2d_layered(parser, int2d, idt%mf6varname, nlay, layer_shape)
984  else
985  call read_int2d(parser, int2d, idt%mf6varname)
986  end if
987 
988  ! log information on the loaded array to the list file
989  call idm_log_var(int2d, idt%tagname, mf6_input%mempath, iout)
990 
991  ! create export file for griddata parameters if optioned
992  if (export) then
993  if (idt%blockname == 'GRIDDATA') then
994  call idm_export(int2d, idt%tagname, mf6_input%mempath, idt%shape, iout)
995  end if
996  end if
997  end subroutine load_integer2d_type
998 
999  !> @brief load type 3d integer
1000  !<
1001  subroutine load_integer3d_type(parser, idt, mf6_input, mshape, export, &
1002  nc_vars, input_fname, iout)
1005  type(blockparsertype), intent(inout) :: parser !< block parser
1006  type(inputparamdefinitiontype), intent(in) :: idt !< input data type object describing this record
1007  type(modflowinputtype), intent(in) :: mf6_input !< description of input
1008  integer(I4B), dimension(:), contiguous, pointer, intent(in) :: mshape !< model shape
1009  logical(LGP), intent(in) :: export !< export to ascii layer files
1010  type(ncpackagevarstype), pointer, intent(in) :: nc_vars
1011  character(len=*), intent(in) :: input_fname !< ascii input file name
1012  integer(I4B), intent(in) :: iout !< unit number for output
1013  integer(I4B), dimension(:, :, :), pointer, contiguous :: int3d
1014  integer(I4B) :: nlay
1015  integer(I4B) :: nsize1, nsize2, nsize3
1016  integer(I4B), dimension(:), allocatable :: array_shape
1017  integer(I4B), dimension(:), allocatable :: layer_shape
1018  integer(I4B), dimension(:), pointer, contiguous :: int1d_ptr
1019  character(len=LINELENGTH) :: keyword
1020 
1021  ! determine the array shape from the input data definition (idt%shape),
1022  ! which looks like "NCOL, NROW, NLAY"
1023  call get_shape_from_string(idt%shape, array_shape, mf6_input%mempath)
1024  nsize1 = array_shape(1)
1025  nsize2 = array_shape(2)
1026  nsize3 = array_shape(3)
1027 
1028  ! create a new 3d memory managed variable
1029  call mem_allocate(int3d, nsize1, nsize2, nsize3, idt%mf6varname, &
1030  mf6_input%mempath)
1031 
1032  ! read keyword
1033  keyword = ''
1034  call parser%GetStringCaps(keyword)
1035 
1036  ! check for "NETCDF" and "LAYERED"
1037  if (keyword == 'NETCDF') then
1038  call netcdf_read_array(int3d, mshape, idt, mf6_input, nc_vars, &
1039  input_fname, iout)
1040  else if (keyword == 'LAYERED' .and. idt%layered) then
1041  call get_layered_shape(mshape, nlay, layer_shape)
1042  call read_int3d_layered(parser, int3d, idt%mf6varname, nlay, &
1043  layer_shape)
1044  else
1045  int1d_ptr(1:nsize1 * nsize2 * nsize3) => int3d(:, :, :)
1046  call read_int1d(parser, int1d_ptr, idt%mf6varname)
1047  end if
1048 
1049  ! log information on the loaded array to the list file
1050  call idm_log_var(int3d, idt%tagname, mf6_input%mempath, iout)
1051 
1052  ! create export file for griddata parameters if optioned
1053  if (export) then
1054  if (idt%blockname == 'GRIDDATA') then
1055  call idm_export(int3d, idt%tagname, mf6_input%mempath, idt%shape, iout)
1056  end if
1057  end if
1058  end subroutine load_integer3d_type
1059 
1060  !> @brief load type double
1061  !<
1062  subroutine load_double_type(parser, idt, memoryPath, iout)
1063  type(blockparsertype), intent(inout) :: parser !< block parser
1064  type(inputparamdefinitiontype), intent(in) :: idt !< input data type object describing this record
1065  character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information
1066  integer(I4B), intent(in) :: iout !< unit number for output
1067  real(DP), pointer :: dblvar
1068  call mem_allocate(dblvar, idt%mf6varname, memorypath)
1069  dblvar = parser%GetDouble()
1070  call idm_log_var(dblvar, idt%tagname, memorypath, iout)
1071  end subroutine load_double_type
1072 
1073  !> @brief load type 1d double
1074  !<
1075  subroutine load_double1d_type(parser, idt, mf6_input, mshape, export, &
1076  nc_vars, input_fname, iout)
1079  type(blockparsertype), intent(inout) :: parser !< block parser
1080  type(inputparamdefinitiontype), intent(in) :: idt !< input data type object describing this record
1081  type(modflowinputtype), intent(in) :: mf6_input !< description of input
1082  integer(I4B), dimension(:), contiguous, pointer, intent(in) :: mshape !< model shape
1083  logical(LGP), intent(in) :: export !< export to ascii layer files
1084  type(ncpackagevarstype), pointer, intent(in) :: nc_vars
1085  character(len=*), intent(in) :: input_fname !< ascii input file name
1086  integer(I4B), intent(in) :: iout !< unit number for output
1087  real(DP), dimension(:), pointer, contiguous :: dbl1d
1088  integer(I4B) :: nlay
1089  integer(I4B) :: nvals
1090  integer(I4B), dimension(:), allocatable :: array_shape
1091  integer(I4B), dimension(:), allocatable :: layer_shape
1092  character(len=LINELENGTH) :: keyword
1093 
1094  ! Check if it is a full grid sized array (NODES)
1095  if (idt%shape == 'NODES') then
1096  nvals = product(mshape)
1097  else
1098  call get_shape_from_string(idt%shape, array_shape, mf6_input%mempath)
1099  nvals = array_shape(1)
1100  end if
1101 
1102  ! allocate memory for the array
1103  call mem_allocate(dbl1d, nvals, idt%mf6varname, mf6_input%mempath)
1104 
1105  ! read keyword
1106  keyword = ''
1107  call parser%GetStringCaps(keyword)
1108 
1109  ! check for "NETCDF" and "LAYERED"
1110  if (keyword == 'NETCDF') then
1111  call netcdf_read_array(dbl1d, mshape, idt, mf6_input, nc_vars, &
1112  input_fname, iout)
1113  else if (keyword == 'LAYERED' .and. idt%layered) then
1114  call get_layered_shape(mshape, nlay, layer_shape)
1115  call read_dbl1d_layered(parser, dbl1d, idt%mf6varname, nlay, layer_shape)
1116  else
1117  call read_dbl1d(parser, dbl1d, idt%mf6varname)
1118  end if
1119 
1120  ! log information on the loaded array to the list file
1121  call idm_log_var(dbl1d, idt%tagname, mf6_input%mempath, iout)
1122 
1123  ! create export file for griddata parameters if optioned
1124  if (export) then
1125  if (idt%blockname == 'GRIDDATA') then
1126  call idm_export(dbl1d, idt%tagname, mf6_input%mempath, idt%shape, iout)
1127  end if
1128  end if
1129  end subroutine load_double1d_type
1130 
1131  !> @brief load type 2d double
1132  !<
1133  subroutine load_double2d_type(parser, idt, mf6_input, mshape, export, &
1134  nc_vars, input_fname, iout)
1137  type(blockparsertype), intent(inout) :: parser !< block parser
1138  type(inputparamdefinitiontype), intent(in) :: idt !< input data type object describing this record
1139  type(modflowinputtype), intent(in) :: mf6_input !< description of input
1140  integer(I4B), dimension(:), contiguous, pointer, intent(in) :: mshape !< model shape
1141  logical(LGP), intent(in) :: export !< export to ascii layer files
1142  type(ncpackagevarstype), pointer, intent(in) :: nc_vars
1143  character(len=*), intent(in) :: input_fname !< ascii input file name
1144  integer(I4B), intent(in) :: iout !< unit number for output
1145  real(DP), dimension(:, :), pointer, contiguous :: dbl2d
1146  integer(I4B) :: nlay
1147  integer(I4B) :: nsize1, nsize2
1148  integer(I4B), dimension(:), allocatable :: array_shape
1149  integer(I4B), dimension(:), allocatable :: layer_shape
1150  character(len=LINELENGTH) :: keyword
1151 
1152  ! determine the array shape from the input data definition (idt%shape),
1153  ! which looks like "NCOL, NROW, NLAY"
1154  call get_shape_from_string(idt%shape, array_shape, mf6_input%mempath)
1155  nsize1 = array_shape(1)
1156  nsize2 = array_shape(2)
1157 
1158  ! create a new 3d memory managed variable
1159  call mem_allocate(dbl2d, nsize1, nsize2, idt%mf6varname, mf6_input%mempath)
1160 
1161  ! read keyword
1162  keyword = ''
1163  call parser%GetStringCaps(keyword)
1164 
1165  ! check for "NETCDF" and "LAYERED"
1166  if (keyword == 'NETCDF') then
1167  call netcdf_read_array(dbl2d, mshape, idt, mf6_input, nc_vars, &
1168  input_fname, iout)
1169  else if (keyword == 'LAYERED' .and. idt%layered) then
1170  call get_layered_shape(mshape, nlay, layer_shape)
1171  call read_dbl2d_layered(parser, dbl2d, idt%mf6varname, nlay, layer_shape)
1172  else
1173  call read_dbl2d(parser, dbl2d, idt%mf6varname)
1174  end if
1175 
1176  ! log information on the loaded array to the list file
1177  call idm_log_var(dbl2d, idt%tagname, mf6_input%mempath, iout)
1178 
1179  ! create export file for griddata parameters if optioned
1180  if (export) then
1181  if (idt%blockname == 'GRIDDATA') then
1182  call idm_export(dbl2d, idt%tagname, mf6_input%mempath, idt%shape, iout)
1183  end if
1184  end if
1185  end subroutine load_double2d_type
1186 
1187  !> @brief load type 3d double
1188  !<
1189  subroutine load_double3d_type(parser, idt, mf6_input, mshape, export, &
1190  nc_vars, input_fname, iout)
1193  type(blockparsertype), intent(inout) :: parser !< block parser
1194  type(inputparamdefinitiontype), intent(in) :: idt !< input data type object describing this record
1195  type(modflowinputtype), intent(in) :: mf6_input !< description of input
1196  integer(I4B), dimension(:), contiguous, pointer, intent(in) :: mshape !< model shape
1197  logical(LGP), intent(in) :: export !< export to ascii layer files
1198  type(ncpackagevarstype), pointer, intent(in) :: nc_vars
1199  character(len=*), intent(in) :: input_fname !< ascii input file name
1200  integer(I4B), intent(in) :: iout !< unit number for output
1201  real(DP), dimension(:, :, :), pointer, contiguous :: dbl3d
1202  integer(I4B) :: nlay
1203  integer(I4B) :: nsize1, nsize2, nsize3
1204  integer(I4B), dimension(:), allocatable :: array_shape
1205  integer(I4B), dimension(:), allocatable :: layer_shape
1206  real(DP), dimension(:), pointer, contiguous :: dbl1d_ptr
1207  character(len=LINELENGTH) :: keyword
1208 
1209  ! determine the array shape from the input data definition (idt%shape),
1210  ! which looks like "NCOL, NROW, NLAY"
1211  call get_shape_from_string(idt%shape, array_shape, mf6_input%mempath)
1212  nsize1 = array_shape(1)
1213  nsize2 = array_shape(2)
1214  nsize3 = array_shape(3)
1215 
1216  ! create a new 3d memory managed variable
1217  call mem_allocate(dbl3d, nsize1, nsize2, nsize3, idt%mf6varname, &
1218  mf6_input%mempath)
1219 
1220  ! read keyword
1221  keyword = ''
1222  call parser%GetStringCaps(keyword)
1223 
1224  ! check for "NETCDF" and "LAYERED"
1225  if (keyword == 'NETCDF') then
1226  call netcdf_read_array(dbl3d, mshape, idt, mf6_input, nc_vars, &
1227  input_fname, iout)
1228  else if (keyword == 'LAYERED' .and. idt%layered) then
1229  call get_layered_shape(mshape, nlay, layer_shape)
1230  call read_dbl3d_layered(parser, dbl3d, idt%mf6varname, nlay, &
1231  layer_shape)
1232  else
1233  dbl1d_ptr(1:nsize1 * nsize2 * nsize3) => dbl3d(:, :, :)
1234  call read_dbl1d(parser, dbl1d_ptr, idt%mf6varname)
1235  end if
1236 
1237  ! log information on the loaded array to the list file
1238  call idm_log_var(dbl3d, idt%tagname, mf6_input%mempath, iout)
1239 
1240  ! create export file for griddata parameters if optioned
1241  if (export) then
1242  if (idt%blockname == 'GRIDDATA') then
1243  call idm_export(dbl3d, idt%tagname, mf6_input%mempath, idt%shape, iout)
1244  end if
1245  end if
1246  end subroutine load_double3d_type
1247 
1248  function read_control_record(parser, oc_inunit, iout) result(ibinary)
1249  use simmodule, only: store_error_unit
1250  use inputoutputmodule, only: urword
1251  use inputoutputmodule, only: openfile
1252  use openspecmodule, only: form, access
1253  use constantsmodule, only: linelength
1255  type(blockparsertype), intent(inout) :: parser
1256  integer(I4B), intent(inout) :: oc_inunit
1257  integer(I4B), intent(in) :: iout
1258  integer(I4B) :: ibinary
1259  integer(I4B) :: lloc, istart, istop, idum, inunit, itmp, ierr
1260  integer(I4B) :: nunopn = 99
1261  character(len=:), allocatable :: line
1262  character(len=LINELENGTH) :: fname
1263  logical(LGP) :: exists
1264  real(dp) :: r
1265  character(len=*), parameter :: fmtocne = &
1266  &"('Specified OPEN/CLOSE file ',(A),' does not exist')"
1267  character(len=*), parameter :: fmtobf = &
1268  &"(1X,/1X,'OPENING BINARY FILE ON UNIT ',I0,':',/1X,A)"
1269 
1270  ! initialize oc_inunit and ibinary
1271  oc_inunit = 0
1272  ibinary = 0
1273  inunit = parser%getunit()
1274 
1275  ! Read to the first non-commented line
1276  lloc = 1
1277  call parser%line_reader%rdcom(inunit, iout, line, ierr)
1278  call urword(line, lloc, istart, istop, 1, idum, r, iout, inunit)
1279 
1280  if (line(istart:istop) == 'OPEN/CLOSE') then
1281  ! get filename
1282  call urword(line, lloc, istart, istop, 0, idum, r, &
1283  iout, inunit)
1284  fname = line(istart:istop)
1285  ! check to see if file OPEN/CLOSE file exists
1286  inquire (file=fname, exist=exists)
1287  if (.not. exists) then
1288  write (errmsg, fmtocne) line(istart:istop)
1289  call store_error(errmsg)
1290  call store_error('Specified OPEN/CLOSE file does not exist')
1291  call store_error_unit(inunit)
1292  end if
1293 
1294  ! Check for (BINARY) keyword
1295  call urword(line, lloc, istart, istop, 1, idum, r, &
1296  iout, inunit)
1297 
1298  if (line(istart:istop) == '(BINARY)') ibinary = 1
1299  ! Open the file depending on ibinary flag
1300  if (ibinary == 1) then
1301  oc_inunit = nunopn
1302  itmp = iout
1303  if (iout > 0) then
1304  itmp = 0
1305  write (iout, fmtobf) oc_inunit, trim(adjustl(fname))
1306  end if
1307  call openfile(oc_inunit, itmp, fname, 'OPEN/CLOSE', &
1308  fmtarg_opt=form, accarg_opt=access)
1309  end if
1310  end if
1311 
1312  if (ibinary == 0) then
1313  call parser%line_reader%bkspc(parser%getunit())
1314  end if
1315  end function read_control_record
1316 
1317  !> @brief Save structarray pointer for deferred TS linking
1318  !!
1319  !! Saves the current structarray pointer when it contains TS string locs,
1320  !! then nullifies the pointer so load_block does not destroy it.
1321  !<
1322  subroutine save_ts_sa(this)
1323  class(loadmf6filetype), intent(inout) :: this
1324  type(structvectortype), pointer :: svect
1325  type(staticsatype), allocatable :: tmp(:)
1326  logical(LGP) :: has_ts
1327  integer(I4B) :: m, n
1328 
1329  ! check if any column has deferred TS strlocs
1330  has_ts = .false.
1331  do m = 1, this%structarray%count()
1332  svect => this%structarray%get(m)
1333  if (svect%idt%timeseries .and. svect%ts_strlocs%count() > 0) then
1334  has_ts = .true.
1335  exit
1336  end if
1337  end do
1338 
1339  if (has_ts) then
1340  n = size(this%ts_sas)
1341  allocate (tmp(n + 1))
1342  tmp(1:n) = this%ts_sas
1343  tmp(n + 1)%sa => this%structarray
1344  call move_alloc(tmp, this%ts_sas)
1345  ! nullify so load_block does not destroy the saved SA
1346  nullify (this%structarray)
1347  end if
1348  end subroutine save_ts_sa
1349 
1350  !> @brief Clean up saved static structarrays
1351  !!
1352  !! Called from destroy() of dynamic loaders.
1353  !<
1354  subroutine cleanup(this)
1356  class(loadmf6filetype), intent(inout) :: this
1357  integer(I4B) :: n
1358  do n = 1, size(this%ts_sas)
1359  if (associated(this%ts_sas(n)%sa)) then
1360  call destructstructarray(this%ts_sas(n)%sa)
1361  nullify (this%ts_sas(n)%sa)
1362  end if
1363  end do
1364  deallocate (this%ts_sas)
1365  end subroutine cleanup
1366 
1367 end module loadmf6filemodule
subroutine init()
Definition: GridSorting.f90:25
This module contains block parser methods.
Definition: BlockParser.f90:7
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
integer(i4b), parameter lenpackagename
maximum length of the package name
Definition: Constants.f90:23
integer(i4b), parameter lenbigline
maximum length of a big line
Definition: Constants.f90:15
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
This module contains the DefinitionSelectModule.
subroutine, public split_record_dfn_tag1(input_definition_types, component_type, subcomponent_type, tagname, nwords, words)
Return aggregate definition.
type(inputparamdefinitiontype) function, pointer, public get_aggregate_definition_type(input_definition_types, component_type, subcomponent_type, blockname)
Return aggregate definition.
subroutine, public split_record_dfn_tag2(input_definition_types, component_type, subcomponent_type, tagname, tag2, nwords, words)
Return aggregate definition.
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.
subroutine, public read_dbl1d(parser, dbl1d, aname)
subroutine, public read_dbl2d(parser, dbl2d, aname)
Disable development features in release mode.
Definition: FeatureFlags.f90:2
subroutine, public developmode(errmsg, iunit)
Terminate if in release mode (guard development features)
This module contains the Input Data Model Logger Module.
Definition: IdmLogger.f90:7
subroutine, public idm_log_close(component, subcomponent, iout)
@ brief log the closing message
Definition: IdmLogger.f90:56
subroutine, public idm_log_header(component, subcomponent, iout)
@ brief log a header message
Definition: IdmLogger.f90:44
Input definition module.
subroutine, public urdaux(naux, inunit, iout, lloc, istart, istop, auxname, line, text)
Read auxiliary variables from an input line.
subroutine, public parseline(line, nwords, words, inunit, filename)
Parse a line into words.
subroutine, public openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, filstat_opt, mode_opt)
Open a file.
Definition: InputOutput.f90:30
subroutine, public urword(line, icol, istart, istop, ncode, n, r, iout, in)
Extract a word from a string.
subroutine, public read_int1d(parser, int1d, aname)
subroutine, public read_int2d(parser, int2d, aname)
This module defines variable data types.
Definition: kind.f90:8
subroutine, public read_int1d_layered(parser, int1d, aname, nlay, layer_shape)
subroutine, public read_dbl1d_layered(parser, dbl1d, aname, nlay, layer_shape)
subroutine, public read_dbl2d_layered(parser, dbl2d, aname, nlay, layer_shape)
subroutine, public read_int3d_layered(parser, int3d, aname, nlay, layer_shape)
subroutine, public read_dbl3d_layered(parser, dbl3d, aname, nlay, layer_shape)
subroutine, public read_int2d_layered(parser, int2d, aname, nlay, layer_shape)
Load context for IDM generic dynamic loaders.
Definition: LoadContext.f90:10
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,...
This module contains the LoadMf6FileModule.
Definition: LoadMf6File.f90:8
subroutine cleanup(this)
Clean up saved static structarrays.
type(inputparamdefinitiontype) function block_index_dfn(this, iblk)
subroutine load_integer1d_type(parser, idt, mf6_input, mshape, export, nc_vars, input_fname, iout)
load type 1d integer
subroutine load_io_tag(parser, idt, memoryPath, which, iout)
load io tag
subroutine load_double3d_type(parser, idt, mf6_input, mshape, export, nc_vars, input_fname, iout)
load type 3d double
subroutine load_string_type(parser, idt, memoryPath, iout)
load type string
type(structarraytype) function, pointer get_ts_sa(this, n)
Return the n-th saved static StructArray pointer.
subroutine load_keyword_type(parser, idt, memoryPath, iout)
load type keyword
subroutine load_auxvar_names(parser, idt, memoryPath, iout)
load aux variable names
subroutine load_double1d_type(parser, idt, mf6_input, mshape, export, nc_vars, input_fname, iout)
load type 1d double
subroutine load_block(this, iblk)
load a single block
subroutine parse_io_tag(this, iblk, pkgtype, which, tag)
subroutine save_ts_sa(this)
Save structarray pointer for deferred TS linking.
subroutine load_double2d_type(parser, idt, mf6_input, mshape, export, nc_vars, input_fname, iout)
load type 2d double
subroutine load_integer_type(parser, idt, memoryPath, iout)
load type integer
recursive subroutine parse_block(this, iblk, recursive_call)
parse block
subroutine load_integer3d_type(parser, idt, mf6_input, mshape, export, nc_vars, input_fname, iout)
load type 3d integer
subroutine block_post_process(this, iblk)
Post parse block handling.
integer(i4b) function ts_sa_count(this)
Return number of saved static StructArrays with deferred TS strlocs.
subroutine finalize(this)
finalize
subroutine load_tag(this, iblk, idt)
load input keyword Load input associated with tag key into the memory manager.
subroutine load_double_type(parser, idt, memoryPath, iout)
load type double
subroutine load_integer2d_type(parser, idt, mf6_input, mshape, export, nc_vars, input_fname, iout)
load type 2d integer
subroutine parse_structarray_block(this, iblk)
parse a structured array record into memory manager
subroutine load(this, parser, mf6_input, nc_vars, filename, iout)
load all static input blocks
Definition: LoadMf6File.f90:97
integer(i4b) function, public read_control_record(parser, oc_inunit, iout)
recursive subroutine parse_record_tag(this, iblk, inidt, recursive_call)
This module contains the LoadNCInputModule.
Definition: LoadNCInput.F90:7
subroutine, public get_from_memorystore(name, mem_path, mt, found, check)
@ brief Get a memory type entry from the memory list
subroutine, public get_isize(name, mem_path, isize)
@ brief Get the number of elements for this variable
subroutine, public get_mem_rank(name, mem_path, rank)
@ brief Get the variable rank
This module contains the ModflowInputModule.
Definition: ModflowInput.f90:9
This module contains the NCFileVarsModule.
Definition: NCFileVars.f90:7
character(len=20) access
Definition: OpenSpec.f90:7
character(len=20) form
Definition: OpenSpec.f90:7
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
subroutine, public store_error_unit(iunit, terminate)
Store the file unit number.
Definition: Sim.f90:169
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string
This module contains the SourceCommonModule.
Definition: SourceCommon.f90:7
subroutine, public get_layered_shape(mshape, nlay, layer_shape)
subroutine, public get_shape_from_string(shape_string, array_shape, memoryPath)
subroutine, public set_model_shape(ftype, fname, model_mempath, dis_mempath, model_shape)
routine for setting the model shape
This module contains the StructArrayModule.
Definition: StructArray.f90:8
subroutine, public destructstructarray(struct_array)
destructor for a struct_array
type(structarraytype) function, pointer, public constructstructarray(mf6_input, ncol, nrow, blocknum, mempath, component_mempath, size_init)
constructor for a struct_array
Definition: StructArray.f90:90
This module contains the StructVectorModule.
Definition: StructVector.f90:7
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.
Input load context for generic dynamic loaders and StructArray based static loads....
Definition: LoadContext.f90:75
Static parser based input loader.
Definition: LoadMf6File.f90:54
Fortran workaround for allocatable arrays of pointers; wraps a StructArray pointer for deferred TS li...
Definition: LoadMf6File.f90:44
derived type for storing input definition for a file
Type describing input variables for a package in NetCDF file.
Definition: NCFileVars.f90:22
type for structured array
Definition: StructArray.f90:47
derived type for generic vector