MODFLOW 6  version 6.7.0.dev0
USGS Modular Hydrologic Model
FlowModelInterface.f90
Go to the documentation of this file.
2 
3  use kindmodule, only: dp, i4b, lgp
7  use simvariablesmodule, only: errmsg
9  use basedismodule, only: disbasetype
10  use listmodule, only: listtype
15 
16  implicit none
17  private
18  public :: flowmodelinterfacetype
19 
21 
22  character(len=LENPACKAGENAME) :: text = '' !< text string for package
23  logical, pointer :: flows_from_file => null() !< if .false., then flows come from GWF through GWF-Model exg
24  type(listtype), pointer :: gwfbndlist => null() !< list of gwf stress packages
25  integer(I4B), pointer :: iflowsupdated => null() !< flows were updated for this time step
26  integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to Model ibound
27  real(dp), dimension(:), pointer, contiguous :: gwfflowja => null() !< pointer to the GWF flowja array
28  real(dp), dimension(:, :), pointer, contiguous :: gwfspdis => null() !< pointer to npf specific discharge array
29  real(dp), dimension(:), pointer, contiguous :: gwfhead => null() !< pointer to the GWF head array
30  real(dp), dimension(:), pointer, contiguous :: gwfsat => null() !< pointer to the GWF saturation array
31  integer(I4B), dimension(:), pointer, contiguous :: ibdgwfsat0 => null() !< mark cells with saturation = 0 to exclude from dispersion
32  integer(I4B), pointer :: idryinactive => null() !< mark cells with an additional flag to exclude from deactivation (gwe will simulate conduction through dry cells)
33  real(dp), dimension(:), pointer, contiguous :: gwfstrgss => null() !< pointer to flow model QSTOSS
34  real(dp), dimension(:), pointer, contiguous :: gwfstrgsy => null() !< pointer to flow model QSTOSY
35  integer(I4B), pointer :: igwfstrgss => null() !< indicates if gwfstrgss is available
36  integer(I4B), pointer :: igwfstrgsy => null() !< indicates if gwfstrgsy is available
37  integer(I4B), pointer :: iubud => null() !< unit number GWF budget file
38  integer(I4B), pointer :: iuhds => null() !< unit number GWF head file
39  integer(I4B), pointer :: iumvr => null() !< unit number GWF mover budget file
40  integer(I4B), pointer :: nflowpack => null() !< number of GWF flow packages
41  integer(I4B), dimension(:), pointer, contiguous :: igwfmvrterm => null() !< flag to indicate that gwf package is a mover term
42  type(budgetfilereadertype) :: bfr !< budget file reader
43  type(headfilereadertype) :: hfr !< head file reader
44  type(packagebudgettype), dimension(:), allocatable :: gwfpackages !< used to get flows between a package and gwf
45  type(budgetobjecttype), pointer :: mvrbudobj => null() !< pointer to the mover budget budget object
46  character(len=16), dimension(:), allocatable :: flowpacknamearray !< array of boundary package names (e.g. LAK-1, SFR-3, etc.)
47  character(len=LENVARNAME) :: depvartype = ''
48 
49  contains
50 
51  procedure :: advance_bfr
52  procedure :: advance_hfr
53  procedure :: allocate_arrays
54  procedure :: allocate_gwfpackages
55  procedure :: allocate_scalars
57  procedure :: finalize_bfr
58  procedure :: finalize_hfr
59  procedure :: fmi_ar
60  procedure :: fmi_da
61  procedure :: fmi_df
62  procedure :: get_package_index
63  procedure :: initialize_bfr
66  procedure :: initialize_hfr
67  procedure :: read_options
68  procedure :: read_packagedata
69 
70  end type flowmodelinterfacetype
71 
72 contains
73 
74  !> @brief Define the flow model interface
75  !<
76  subroutine fmi_df(this, dis, idryinactive)
77  ! -- modules
78  use simmodule, only: store_error
79  ! -- dummy
80  class(flowmodelinterfacetype) :: this
81  class(disbasetype), pointer, intent(in) :: dis
82  integer(I4B), intent(in) :: idryinactive
83  ! -- formats
84  character(len=*), parameter :: fmtfmi = &
85  "(1x,/1x,'FMI -- FLOW MODEL INTERFACE, VERSION 2, 8/17/2023', &
86  &' INPUT READ FROM UNIT ', i0, //)"
87  character(len=*), parameter :: fmtfmi0 = &
88  "(1x,/1x,'FMI -- FLOW MODEL INTERFACE,'&
89  &' VERSION 2, 8/17/2023')"
90  !
91  ! --print a message identifying the FMI package.
92  if (this%iout > 0) then
93  if (this%inunit /= 0) then
94  write (this%iout, fmtfmi) this%inunit
95  else
96  write (this%iout, fmtfmi0)
97  if (this%flows_from_file) then
98  write (this%iout, '(a)') ' FLOWS ARE ASSUMED TO BE ZERO.'
99  else
100  write (this%iout, '(a)') ' FLOWS PROVIDED BY A GWF MODEL IN THIS &
101  &SIMULATION'
102  end if
103  end if
104  end if
105  !
106  ! -- Store pointers
107  this%dis => dis
108  !
109  ! -- Read fmi options
110  if (this%inunit /= 0) then
111  call this%read_options()
112  end if
113  !
114  ! -- Read packagedata options
115  if (this%inunit /= 0 .and. this%flows_from_file) then
116  call this%read_packagedata()
117  call this%initialize_gwfterms_from_bfr()
118  end if
119  !
120  ! -- If GWF-Model exchange is active, setup flow terms
121  if (.not. this%flows_from_file) then
122  call this%initialize_gwfterms_from_gwfbndlist()
123  end if
124  !
125  ! -- Set flag that stops dry flows from being deactivated in a GWE
126  ! transport model since conduction will still be simulated.
127  ! 0: GWE (skip deactivation step); 1: GWT (default: use existing code)
128  this%idryinactive = idryinactive
129  end subroutine fmi_df
130 
131  !> @brief Allocate the package
132  !<
133  subroutine fmi_ar(this, ibound)
134  ! -- modules
135  use simmodule, only: store_error
136  ! -- dummy
137  class(flowmodelinterfacetype) :: this
138  integer(I4B), dimension(:), pointer, contiguous :: ibound
139  !
140  ! -- store pointers to arguments that were passed in
141  this%ibound => ibound
142  !
143  ! -- Allocate arrays
144  call this%allocate_arrays(this%dis%nodes)
145  end subroutine fmi_ar
146 
147  !> @brief Deallocate variables
148  !<
149  subroutine fmi_da(this)
150  ! -- modules
152  ! -- dummy
153  class(flowmodelinterfacetype) :: this
154  ! -- todo: finalize hfr and bfr either here or in a finalize routine
155  !
156  ! -- deallocate any memory stored with gwfpackages
157  call this%deallocate_gwfpackages()
158  !
159  ! -- deallocate fmi arrays
160  deallocate (this%gwfpackages)
161  deallocate (this%flowpacknamearray)
162  call mem_deallocate(this%igwfmvrterm)
163  call mem_deallocate(this%ibdgwfsat0)
164  !
165  if (this%flows_from_file) then
166  call mem_deallocate(this%gwfstrgss)
167  call mem_deallocate(this%gwfstrgsy)
168  end if
169  !
170  ! -- special treatment, these could be from mem_checkin
171  call mem_deallocate(this%gwfhead, 'GWFHEAD', this%memoryPath)
172  call mem_deallocate(this%gwfsat, 'GWFSAT', this%memoryPath)
173  call mem_deallocate(this%gwfspdis, 'GWFSPDIS', this%memoryPath)
174  call mem_deallocate(this%gwfflowja, 'GWFFLOWJA', this%memoryPath)
175  !
176  ! -- deallocate scalars
177  call mem_deallocate(this%flows_from_file)
178  call mem_deallocate(this%iflowsupdated)
179  call mem_deallocate(this%igwfstrgss)
180  call mem_deallocate(this%igwfstrgsy)
181  call mem_deallocate(this%iubud)
182  call mem_deallocate(this%iuhds)
183  call mem_deallocate(this%iumvr)
184  call mem_deallocate(this%nflowpack)
185  call mem_deallocate(this%idryinactive)
186  !
187  ! -- deallocate parent
188  call this%NumericalPackageType%da()
189  end subroutine fmi_da
190 
191  !> @brief Allocate scalars
192  !<
193  subroutine allocate_scalars(this)
194  ! -- modules
196  ! -- dummy
197  class(flowmodelinterfacetype) :: this
198  ! -- local
199  !
200  ! -- allocate scalars in NumericalPackageType
201  call this%NumericalPackageType%allocate_scalars()
202  !
203  ! -- Allocate
204  call mem_allocate(this%flows_from_file, 'FLOWS_FROM_FILE', this%memoryPath)
205  call mem_allocate(this%iflowsupdated, 'IFLOWSUPDATED', this%memoryPath)
206  call mem_allocate(this%igwfstrgss, 'IGWFSTRGSS', this%memoryPath)
207  call mem_allocate(this%igwfstrgsy, 'IGWFSTRGSY', this%memoryPath)
208  call mem_allocate(this%iubud, 'IUBUD', this%memoryPath)
209  call mem_allocate(this%iuhds, 'IUHDS', this%memoryPath)
210  call mem_allocate(this%iumvr, 'IUMVR', this%memoryPath)
211  call mem_allocate(this%nflowpack, 'NFLOWPACK', this%memoryPath)
212  call mem_allocate(this%idryinactive, "IDRYINACTIVE", this%memoryPath)
213  !
214  ! !
215  ! -- Initialize
216  this%flows_from_file = .true.
217  this%iflowsupdated = 1
218  this%igwfstrgss = 0
219  this%igwfstrgsy = 0
220  this%iubud = 0
221  this%iuhds = 0
222  this%iumvr = 0
223  this%nflowpack = 0
224  this%idryinactive = 1
225  end subroutine allocate_scalars
226 
227  !> @brief Allocate arrays
228  !<
229  subroutine allocate_arrays(this, nodes)
231  !modules
232  use constantsmodule, only: dzero
233  ! -- dummy
234  class(flowmodelinterfacetype) :: this
235  integer(I4B), intent(in) :: nodes
236  ! -- local
237  integer(I4B) :: n
238  !
239  ! -- Allocate ibdgwfsat0, which is an indicator array marking cells with
240  ! saturation greater than 0.0 with a value of 1
241  call mem_allocate(this%ibdgwfsat0, nodes, 'IBDGWFSAT0', this%memoryPath)
242  do n = 1, nodes
243  this%ibdgwfsat0(n) = 1
244  end do
245  !
246  ! -- Allocate differently depending on whether or not flows are
247  ! being read from a file.
248  if (this%flows_from_file) then
249  call mem_allocate(this%gwfflowja, this%dis%con%nja, &
250  'GWFFLOWJA', this%memoryPath)
251  call mem_allocate(this%gwfsat, nodes, 'GWFSAT', this%memoryPath)
252  call mem_allocate(this%gwfhead, nodes, 'GWFHEAD', this%memoryPath)
253  call mem_allocate(this%gwfspdis, 3, nodes, 'GWFSPDIS', this%memoryPath)
254  do n = 1, nodes
255  this%gwfsat(n) = done
256  this%gwfhead(n) = dzero
257  this%gwfspdis(:, n) = dzero
258  end do
259  do n = 1, size(this%gwfflowja)
260  this%gwfflowja(n) = dzero
261  end do
262  !
263  ! -- allocate and initialize storage arrays
264  if (this%igwfstrgss == 0) then
265  call mem_allocate(this%gwfstrgss, 1, 'GWFSTRGSS', this%memoryPath)
266  else
267  call mem_allocate(this%gwfstrgss, nodes, 'GWFSTRGSS', this%memoryPath)
268  end if
269  if (this%igwfstrgsy == 0) then
270  call mem_allocate(this%gwfstrgsy, 1, 'GWFSTRGSY', this%memoryPath)
271  else
272  call mem_allocate(this%gwfstrgsy, nodes, 'GWFSTRGSY', this%memoryPath)
273  end if
274  do n = 1, size(this%gwfstrgss)
275  this%gwfstrgss(n) = dzero
276  end do
277  do n = 1, size(this%gwfstrgsy)
278  this%gwfstrgsy(n) = dzero
279  end do
280  !
281  ! -- If there is no fmi package, then there are no flows at all or a
282  ! connected GWF model, so allocate gwfpackages to zero
283  if (this%inunit == 0) call this%allocate_gwfpackages(this%nflowpack)
284  end if
285  end subroutine allocate_arrays
286 
287  !> @brief Read options from input file
288  !<
289  subroutine read_options(this)
290  ! -- modules
291  use constantsmodule, only: linelength, dem6
294  ! -- dummy
295  class(flowmodelinterfacetype) :: this
296  ! -- local
297  character(len=LINELENGTH) :: keyword
298  integer(I4B) :: ierr
299  logical :: isfound, endOfBlock
300  !
301  ! -- get options block
302  call this%parser%GetBlock('OPTIONS', isfound, ierr, blockrequired=.false., &
303  supportopenclose=.true.)
304  !
305  ! -- parse options block if detected
306  if (isfound) then
307  write (this%iout, '(1x,a)') 'PROCESSING FMI OPTIONS'
308  do
309  call this%parser%GetNextLine(endofblock)
310  if (endofblock) exit
311  call this%parser%GetStringCaps(keyword)
312  select case (keyword)
313  case ('SAVE_FLOWS')
314  this%ipakcb = -1
315  case default
316  write (errmsg, '(a,3(1x,a))') &
317  'UNKNOWN', trim(adjustl(this%text)), 'OPTION:', trim(keyword)
318  call store_error(errmsg)
319  call this%parser%StoreErrorUnit()
320  end select
321  end do
322  write (this%iout, '(1x,a)') 'END OF FMI OPTIONS'
323  end if
324  end subroutine read_options
325 
326  !> @brief Read packagedata block from input file
327  !<
328  subroutine read_packagedata(this)
329  ! -- modules
330  use openspecmodule, only: access, form
334  ! -- dummy
335  class(flowmodelinterfacetype) :: this
336  ! -- local
337  character(len=LINELENGTH) :: keyword, fname
338  integer(I4B) :: ierr
339  integer(I4B) :: inunit
340  integer(I4B) :: iapt
341  logical :: isfound, endOfBlock
342  logical :: blockrequired
343  logical :: exist
344  !
345  ! -- initialize
346  iapt = 0
347  blockrequired = .true.
348  !
349  ! -- get options block
350  call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, &
351  blockrequired=blockrequired, &
352  supportopenclose=.true.)
353  !
354  ! -- parse options block if detected
355  if (isfound) then
356  write (this%iout, '(1x,a)') 'PROCESSING FMI PACKAGEDATA'
357  do
358  call this%parser%GetNextLine(endofblock)
359  if (endofblock) exit
360  call this%parser%GetStringCaps(keyword)
361  select case (keyword)
362  case ('GWFBUDGET')
363  call this%parser%GetStringCaps(keyword)
364  if (keyword /= 'FILEIN') then
365  call store_error('GWFBUDGET KEYWORD MUST BE FOLLOWED BY '// &
366  '"FILEIN" then by filename.')
367  call this%parser%StoreErrorUnit()
368  end if
369  call this%parser%GetString(fname)
370  inunit = getunit()
371  inquire (file=trim(fname), exist=exist)
372  if (.not. exist) then
373  call store_error('Could not find file '//trim(fname))
374  call this%parser%StoreErrorUnit()
375  end if
376  call openfile(inunit, this%iout, fname, 'DATA(BINARY)', form, &
377  access, 'UNKNOWN')
378  this%iubud = inunit
379  call this%initialize_bfr()
380  case ('GWFHEAD')
381  call this%parser%GetStringCaps(keyword)
382  if (keyword /= 'FILEIN') then
383  call store_error('GWFHEAD KEYWORD MUST BE FOLLOWED BY '// &
384  '"FILEIN" then by filename.')
385  call this%parser%StoreErrorUnit()
386  end if
387  call this%parser%GetString(fname)
388  inquire (file=trim(fname), exist=exist)
389  if (.not. exist) then
390  call store_error('Could not find file '//trim(fname))
391  call this%parser%StoreErrorUnit()
392  end if
393  inunit = getunit()
394  call openfile(inunit, this%iout, fname, 'DATA(BINARY)', form, &
395  access, 'UNKNOWN')
396  this%iuhds = inunit
397  call this%initialize_hfr()
398  case ('GWFMOVER')
399  call this%parser%GetStringCaps(keyword)
400  if (keyword /= 'FILEIN') then
401  call store_error('GWFMOVER KEYWORD MUST BE FOLLOWED BY '// &
402  '"FILEIN" then by filename.')
403  call this%parser%StoreErrorUnit()
404  end if
405  call this%parser%GetString(fname)
406  inunit = getunit()
407  call openfile(inunit, this%iout, fname, 'DATA(BINARY)', form, &
408  access, 'UNKNOWN')
409  this%iumvr = inunit
410  call budgetobject_cr_bfr(this%mvrbudobj, 'MVT', this%iumvr, &
411  this%iout)
412  call this%mvrbudobj%fill_from_bfr(this%dis, this%iout)
413  case default
414  write (errmsg, '(a,3(1x,a))') &
415  'UNKNOWN', trim(adjustl(this%text)), 'PACKAGEDATA:', trim(keyword)
416  call store_error(errmsg)
417  end select
418  end do
419  write (this%iout, '(1x,a)') 'END OF FMI PACKAGEDATA'
420  end if
421  end subroutine read_packagedata
422 
423  !> @brief Initialize the budget file reader
424  !<
425  subroutine initialize_bfr(this)
426  ! -- modules
427  class(flowmodelinterfacetype) :: this
428  ! -- dummy
429  integer(I4B) :: ncrbud
430  !
431  ! -- Initialize the budget file reader
432  call this%bfr%initialize(this%iubud, this%iout, ncrbud)
433  !
434  ! -- todo: need to run through the budget terms
435  ! and do some checking
436  end subroutine initialize_bfr
437 
438  !> @brief Advance the budget file reader
439  !!
440  !! Advance the budget file reader by reading the next chunk
441  !! of information for the current time step and stress period.
442  !!
443  !<
444  subroutine advance_bfr(this)
445  ! -- modules
446  use tdismodule, only: kstp, kper
447  ! -- dummy
448  class(flowmodelinterfacetype) :: this
449  ! -- local
450  logical :: success
451  integer(I4B) :: n
452  integer(I4B) :: ipos
453  integer(I4B) :: nu, nr
454  integer(I4B) :: ip, i
455  logical :: readnext
456  ! -- format
457  character(len=*), parameter :: fmtkstpkper = &
458  "(1x,/1x,'FMI READING BUDGET TERMS &
459  &FOR KSTP ', i0, ' KPER ', i0)"
460  character(len=*), parameter :: fmtbudkstpkper = &
461  "(1x,/1x, 'FMI SETTING BUDGET TERMS &
462  &FOR KSTP ', i0, ' AND KPER ', &
463  &i0, ' TO BUDGET FILE TERMS FROM &
464  &KSTP ', i0, ' AND KPER ', i0)"
465  !
466  ! -- If the latest record read from the budget file is from a stress
467  ! -- period with only one time step, reuse that record (do not read a
468  ! -- new record) if the running model is still in that same stress period,
469  ! -- or if that record is the last one in the budget file.
470  readnext = .true.
471  if (kstp * kper > 1) then
472  if (this%bfr%kstp == 1) then
473  if (this%bfr%kpernext == kper + 1) then
474  readnext = .false.
475  else if (this%bfr%endoffile) then
476  readnext = .false.
477  end if
478  else if (this%bfr%endoffile) then
479  write (errmsg, '(4x,a)') 'REACHED END OF GWF BUDGET &
480  &FILE BEFORE READING SUFFICIENT BUDGET INFORMATION FOR THIS &
481  &GWT SIMULATION.'
482  call store_error(errmsg)
483  call store_error_unit(this%iubud)
484  end if
485  end if
486  !
487  ! -- Read the next record
488  if (readnext) then
489  !
490  ! -- Write the current time step and stress period
491  write (this%iout, fmtkstpkper) kstp, kper
492  !
493  ! -- loop through the budget terms for this stress period
494  ! i is the counter for gwf flow packages
495  ip = 1
496  do n = 1, this%bfr%nbudterms
497  call this%bfr%read_record(success, this%iout)
498  if (.not. success) then
499  write (errmsg, '(4x,a)') 'GWF BUDGET READ NOT SUCCESSFUL'
500  call store_error(errmsg)
501  call store_error_unit(this%iubud)
502  end if
503  !
504  ! -- Ensure kper is same between model and budget file
505  if (kper /= this%bfr%kper) then
506  write (errmsg, '(4x,a)') 'PERIOD NUMBER IN BUDGET FILE &
507  &DOES NOT MATCH PERIOD NUMBER IN TRANSPORT MODEL. IF THERE &
508  &IS MORE THAN ONE TIME STEP IN THE BUDGET FILE FOR A GIVEN &
509  &STRESS PERIOD, BUDGET FILE TIME STEPS MUST MATCH GWT MODEL &
510  &TIME STEPS ONE-FOR-ONE IN THAT STRESS PERIOD.'
511  call store_error(errmsg)
512  call store_error_unit(this%iubud)
513  end if
514  !
515  ! -- if budget file kstp > 1, then kstp must match
516  if (this%bfr%kstp > 1 .and. (kstp /= this%bfr%kstp)) then
517  write (errmsg, '(4x,a)') 'TIME STEP NUMBER IN BUDGET FILE &
518  &DOES NOT MATCH TIME STEP NUMBER IN TRANSPORT MODEL. IF THERE &
519  &IS MORE THAN ONE TIME STEP IN THE BUDGET FILE FOR A GIVEN STRESS &
520  &PERIOD, BUDGET FILE TIME STEPS MUST MATCH GWT MODEL TIME STEPS &
521  &ONE-FOR-ONE IN THAT STRESS PERIOD.'
522  call store_error(errmsg)
523  call store_error_unit(this%iubud)
524  end if
525  !
526  ! -- parse based on the type of data, and compress all user node
527  ! numbers into reduced node numbers
528  select case (trim(adjustl(this%bfr%budtxt)))
529  case ('FLOW-JA-FACE')
530  !
531  ! -- bfr%flowja contains only reduced connections so there is
532  ! a one-to-one match with this%gwfflowja
533  do ipos = 1, size(this%bfr%flowja)
534  this%gwfflowja(ipos) = this%bfr%flowja(ipos)
535  end do
536  case ('DATA-SPDIS')
537  do i = 1, this%bfr%nlist
538  nu = this%bfr%nodesrc(i)
539  nr = this%dis%get_nodenumber(nu, 0)
540  if (nr <= 0) cycle
541  this%gwfspdis(1, nr) = this%bfr%auxvar(1, i)
542  this%gwfspdis(2, nr) = this%bfr%auxvar(2, i)
543  this%gwfspdis(3, nr) = this%bfr%auxvar(3, i)
544  end do
545  case ('DATA-SAT')
546  do i = 1, this%bfr%nlist
547  nu = this%bfr%nodesrc(i)
548  nr = this%dis%get_nodenumber(nu, 0)
549  if (nr <= 0) cycle
550  this%gwfsat(nr) = this%bfr%auxvar(1, i)
551  end do
552  case ('STO-SS')
553  do nu = 1, this%dis%nodesuser
554  nr = this%dis%get_nodenumber(nu, 0)
555  if (nr <= 0) cycle
556  this%gwfstrgss(nr) = this%bfr%flow(nu)
557  end do
558  case ('STO-SY')
559  do nu = 1, this%dis%nodesuser
560  nr = this%dis%get_nodenumber(nu, 0)
561  if (nr <= 0) cycle
562  this%gwfstrgsy(nr) = this%bfr%flow(nu)
563  end do
564  case default
565  call this%gwfpackages(ip)%copy_values( &
566  this%bfr%nlist, &
567  this%bfr%nodesrc, &
568  this%bfr%flow, &
569  this%bfr%auxvar)
570  do i = 1, this%gwfpackages(ip)%nbound
571  nu = this%gwfpackages(ip)%nodelist(i)
572  nr = this%dis%get_nodenumber(nu, 0)
573  this%gwfpackages(ip)%nodelist(i) = nr
574  end do
575  ip = ip + 1
576  end select
577  end do
578  else
579  !
580  ! -- write message to indicate that flows are being reused
581  write (this%iout, fmtbudkstpkper) kstp, kper, this%bfr%kstp, this%bfr%kper
582  !
583  ! -- set the flag to indicate that flows were not updated
584  this%iflowsupdated = 0
585  end if
586  end subroutine advance_bfr
587 
588  !> @brief Finalize the budget file reader
589  !<
590  subroutine finalize_bfr(this)
591  ! -- modules
592  class(flowmodelinterfacetype) :: this
593  ! -- dummy
594  !
595  ! -- Finalize the budget file reader
596  call this%bfr%finalize()
597  !
598  end subroutine finalize_bfr
599 
600  !> @brief Initialize the head file reader
601  !<
602  subroutine initialize_hfr(this)
603  ! -- modules
604  class(flowmodelinterfacetype) :: this
605  ! -- dummy
606  !
607  ! -- Initialize the budget file reader
608  call this%hfr%initialize(this%iuhds, this%iout)
609  !
610  ! -- todo: need to run through the head terms
611  ! and do some checking
612  end subroutine initialize_hfr
613 
614  !> @brief Advance the head file reader
615  !<
616  subroutine advance_hfr(this)
617  ! -- modules
618  use tdismodule, only: kstp, kper
619  class(flowmodelinterfacetype) :: this
620  integer(I4B) :: nu, nr, i, ilay
621  integer(I4B) :: ncpl
622  real(DP) :: val
623  logical :: readnext
624  logical :: success
625  character(len=*), parameter :: fmtkstpkper = &
626  "(1x,/1x,'FMI READING HEAD FOR &
627  &KSTP ', i0, ' KPER ', i0)"
628  character(len=*), parameter :: fmthdskstpkper = &
629  "(1x,/1x, 'FMI SETTING HEAD FOR KSTP ', i0, ' AND KPER ', &
630  &i0, ' TO BINARY FILE HEADS FROM KSTP ', i0, ' AND KPER ', i0)"
631  !
632  ! -- If the latest record read from the head file is from a stress
633  ! -- period with only one time step, reuse that record (do not read a
634  ! -- new record) if the running model is still in that same stress period,
635  ! -- or if that record is the last one in the head file.
636  readnext = .true.
637  if (kstp * kper > 1) then
638  if (this%hfr%kstp == 1) then
639  if (this%hfr%kpernext == kper + 1) then
640  readnext = .false.
641  else if (this%hfr%endoffile) then
642  readnext = .false.
643  end if
644  else if (this%hfr%endoffile) then
645  write (errmsg, '(4x,a)') 'REACHED END OF GWF HEAD &
646  &FILE BEFORE READING SUFFICIENT HEAD INFORMATION FOR THIS &
647  &GWT SIMULATION.'
648  call store_error(errmsg)
649  call store_error_unit(this%iuhds)
650  end if
651  end if
652  !
653  ! -- Read the next record
654  if (readnext) then
655  !
656  ! -- write to list file that heads are being read
657  write (this%iout, fmtkstpkper) kstp, kper
658  !
659  ! -- loop through the layered heads for this time step
660  do ilay = 1, this%hfr%nlay
661  !
662  ! -- read next head chunk
663  call this%hfr%read_record(success, this%iout)
664  if (.not. success) then
665  write (errmsg, '(4x,a)') 'GWF HEAD READ NOT SUCCESSFUL'
666  call store_error(errmsg)
667  call store_error_unit(this%iuhds)
668  end if
669  !
670  ! -- Ensure kper is same between model and head file
671  if (kper /= this%hfr%kper) then
672  write (errmsg, '(4x,a)') 'PERIOD NUMBER IN HEAD FILE &
673  &DOES NOT MATCH PERIOD NUMBER IN TRANSPORT MODEL. IF THERE &
674  &IS MORE THAN ONE TIME STEP IN THE HEAD FILE FOR A GIVEN STRESS &
675  &PERIOD, HEAD FILE TIME STEPS MUST MATCH GWT MODEL TIME STEPS &
676  &ONE-FOR-ONE IN THAT STRESS PERIOD.'
677  call store_error(errmsg)
678  call store_error_unit(this%iuhds)
679  end if
680  !
681  ! -- if head file kstp > 1, then kstp must match
682  if (this%hfr%kstp > 1 .and. (kstp /= this%hfr%kstp)) then
683  write (errmsg, '(4x,a)') 'TIME STEP NUMBER IN HEAD FILE &
684  &DOES NOT MATCH TIME STEP NUMBER IN TRANSPORT MODEL. IF THERE &
685  &IS MORE THAN ONE TIME STEP IN THE HEAD FILE FOR A GIVEN STRESS &
686  &PERIOD, HEAD FILE TIME STEPS MUST MATCH GWT MODEL TIME STEPS &
687  &ONE-FOR-ONE IN THAT STRESS PERIOD.'
688  call store_error(errmsg)
689  call store_error_unit(this%iuhds)
690  end if
691  !
692  ! -- fill the head array for this layer and
693  ! compress into reduced form
694  ncpl = size(this%hfr%head)
695  do i = 1, ncpl
696  nu = (ilay - 1) * ncpl + i
697  nr = this%dis%get_nodenumber(nu, 0)
698  val = this%hfr%head(i)
699  if (nr > 0) this%gwfhead(nr) = val
700  end do
701  end do
702  else
703  write (this%iout, fmthdskstpkper) kstp, kper, this%hfr%kstp, this%hfr%kper
704  end if
705  end subroutine advance_hfr
706 
707  !> @brief Finalize the head file reader
708  !<
709  subroutine finalize_hfr(this)
710  ! -- modules
711  class(flowmodelinterfacetype) :: this
712  ! -- dummy
713  !
714  ! -- Finalize the head file reader
715  close (this%iuhds)
716  !
717  end subroutine finalize_hfr
718 
719  !> @brief Initialize gwf terms from budget file
720  !!
721  !! initialize terms and figure out how many
722  !! different terms and packages are contained within the file
723  !!
724  !<
726  ! -- modules
729  ! -- dummy
730  class(flowmodelinterfacetype) :: this
731  ! -- local
732  integer(I4B) :: nflowpack
733  integer(I4B) :: i, ip
734  integer(I4B) :: naux
735  logical :: found_flowja
736  logical :: found_dataspdis
737  logical :: found_datasat
738  logical :: found_stoss
739  logical :: found_stosy
740  integer(I4B), dimension(:), allocatable :: imap
741  !
742  ! -- Calculate the number of gwf flow packages
743  allocate (imap(this%bfr%nbudterms))
744  imap(:) = 0
745  nflowpack = 0
746  found_flowja = .false.
747  found_dataspdis = .false.
748  found_datasat = .false.
749  found_stoss = .false.
750  found_stosy = .false.
751  do i = 1, this%bfr%nbudterms
752  select case (trim(adjustl(this%bfr%budtxtarray(i))))
753  case ('FLOW-JA-FACE')
754  found_flowja = .true.
755  case ('DATA-SPDIS')
756  found_dataspdis = .true.
757  case ('DATA-SAT')
758  found_datasat = .true.
759  case ('STO-SS')
760  found_stoss = .true.
761  this%igwfstrgss = 1
762  case ('STO-SY')
763  found_stosy = .true.
764  this%igwfstrgsy = 1
765  case default
766  nflowpack = nflowpack + 1
767  imap(i) = 1
768  end select
769  end do
770  !
771  ! -- allocate gwfpackage arrays
772  call this%allocate_gwfpackages(nflowpack)
773  !
774  ! -- Copy the package name and aux names from budget file reader
775  ! to the gwfpackages derived-type variable
776  ip = 1
777  do i = 1, this%bfr%nbudterms
778  if (imap(i) == 0) cycle
779  call this%gwfpackages(ip)%set_name(this%bfr%dstpackagenamearray(i), &
780  this%bfr%budtxtarray(i))
781  naux = this%bfr%nauxarray(i)
782  call this%gwfpackages(ip)%set_auxname(naux, this%bfr%auxtxtarray(1:naux, i))
783  ip = ip + 1
784  end do
785  !
786  ! -- Copy just the package names for the boundary packages into
787  ! the flowpacknamearray
788  ip = 1
789  do i = 1, size(imap)
790  if (imap(i) == 1) then
791  this%flowpacknamearray(ip) = this%bfr%dstpackagenamearray(i)
792  ip = ip + 1
793  end if
794  end do
795  !
796  ! -- Error if specific discharge, saturation or flowja not found
797  if (.not. found_dataspdis) then
798  write (errmsg, '(4x,a)') 'SPECIFIC DISCHARGE NOT FOUND IN &
799  &BUDGET FILE. SAVE_SPECIFIC_DISCHARGE AND &
800  &SAVE_FLOWS MUST BE ACTIVATED IN THE NPF PACKAGE.'
801  call store_error(errmsg)
802  end if
803  if (.not. found_datasat) then
804  write (errmsg, '(4x,a)') 'SATURATION NOT FOUND IN &
805  &BUDGET FILE. SAVE_SATURATION AND &
806  &SAVE_FLOWS MUST BE ACTIVATED IN THE NPF PACKAGE.'
807  call store_error(errmsg)
808  end if
809  if (.not. found_flowja) then
810  write (errmsg, '(4x,a)') 'FLOWJA NOT FOUND IN &
811  &BUDGET FILE. SAVE_FLOWS MUST &
812  &BE ACTIVATED IN THE NPF PACKAGE.'
813  call store_error(errmsg)
814  end if
815  if (count_errors() > 0) then
816  call this%parser%StoreErrorUnit()
817  end if
818  end subroutine initialize_gwfterms_from_bfr
819 
820  !> @brief Initialize gwf terms from a GWF exchange
821  !<
823  ! -- modules
824  use bndmodule, only: bndtype, getbndfromlist
825  ! -- dummy
826  class(flowmodelinterfacetype) :: this
827  ! -- local
828  integer(I4B) :: ngwfpack
829  integer(I4B) :: ngwfterms
830  integer(I4B) :: ip
831  integer(I4B) :: imover
832  integer(I4B) :: ntomvr
833  integer(I4B) :: iterm
834  character(len=LENPACKAGENAME) :: budtxt
835  class(bndtype), pointer :: packobj => null()
836  !
837  ! -- determine size of gwf terms
838  ngwfpack = this%gwfbndlist%Count()
839  !
840  ! -- Count number of to-mvr terms, but do not include advanced packages
841  ! as those mover terms are not losses from the cell, but rather flows
842  ! within the advanced package
843  ntomvr = 0
844  do ip = 1, ngwfpack
845  packobj => getbndfromlist(this%gwfbndlist, ip)
846  imover = packobj%imover
847  if (packobj%isadvpak /= 0) imover = 0
848  if (imover /= 0) then
849  ntomvr = ntomvr + 1
850  end if
851  end do
852  !
853  ! -- Allocate arrays in fmi of size ngwfterms, which is the number of
854  ! packages plus the number of packages with mover terms.
855  ngwfterms = ngwfpack + ntomvr
856  call this%allocate_gwfpackages(ngwfterms)
857  !
858  ! -- Assign values in the fmi package
859  iterm = 1
860  do ip = 1, ngwfpack
861  !
862  ! -- set and store names
863  packobj => getbndfromlist(this%gwfbndlist, ip)
864  budtxt = adjustl(packobj%text)
865  call this%gwfpackages(iterm)%set_name(packobj%packName, budtxt)
866  this%flowpacknamearray(iterm) = packobj%packName
867  iterm = iterm + 1
868  !
869  ! -- if this package has a mover associated with it, then add another
870  ! term that corresponds to the mover flows
871  imover = packobj%imover
872  if (packobj%isadvpak /= 0) imover = 0
873  if (imover /= 0) then
874  budtxt = trim(adjustl(packobj%text))//'-TO-MVR'
875  call this%gwfpackages(iterm)%set_name(packobj%packName, budtxt)
876  this%flowpacknamearray(iterm) = packobj%packName
877  this%igwfmvrterm(iterm) = 1
878  iterm = iterm + 1
879  end if
880  end do
882 
883  !> @brief Allocate budget packages
884  !!
885  !! gwfpackages is an array of PackageBudget objects.
886  !! This routine allocates gwfpackages to the proper size and initializes some
887  !! member variables.
888  !<
889  subroutine allocate_gwfpackages(this, ngwfterms)
890  ! -- modules
891  use constantsmodule, only: lenmempath
893  ! -- dummy
894  class(flowmodelinterfacetype) :: this
895  integer(I4B), intent(in) :: ngwfterms
896  ! -- local
897  integer(I4B) :: n
898  character(len=LENMEMPATH) :: memPath
899  !
900  ! -- direct allocate
901  allocate (this%gwfpackages(ngwfterms))
902  allocate (this%flowpacknamearray(ngwfterms))
903  !
904  ! -- mem_allocate
905  call mem_allocate(this%igwfmvrterm, ngwfterms, 'IGWFMVRTERM', this%memoryPath)
906  !
907  ! -- initialize
908  this%nflowpack = ngwfterms
909  do n = 1, this%nflowpack
910  this%igwfmvrterm(n) = 0
911  this%flowpacknamearray(n) = ''
912  !
913  ! -- Create a mempath for each individual flow package data set
914  ! of the form, MODELNAME/FMI-FTn
915  write (mempath, '(a, i0)') trim(this%memoryPath)//'-FT', n
916  call this%gwfpackages(n)%initialize(mempath)
917  end do
918  end subroutine allocate_gwfpackages
919 
920  !> @brief Deallocate memory in the gwfpackages array
921  !<
922  subroutine deallocate_gwfpackages(this)
923  ! -- modules
924  ! -- dummy
925  class(flowmodelinterfacetype) :: this
926  ! -- local
927  integer(I4B) :: n
928  !
929  ! -- initialize
930  do n = 1, this%nflowpack
931  call this%gwfpackages(n)%da()
932  end do
933  end subroutine deallocate_gwfpackages
934 
935  !> @brief Find the package index for the package with the given name
936  !<
937  subroutine get_package_index(this, name, idx)
938  use bndmodule, only: bndtype, getbndfromlist
939  class(flowmodelinterfacetype) :: this
940  character(len=*), intent(in) :: name
941  integer(I4B), intent(inout) :: idx
942  ! -- local
943  integer(I4B) :: ip
944  !
945  ! -- Look through all the packages and return the index with name
946  idx = 0
947  do ip = 1, size(this%flowpacknamearray)
948  if (this%flowpacknamearray(ip) == name) then
949  idx = ip
950  exit
951  end if
952  end do
953  if (idx == 0) then
954  call store_error('Error in get_package_index. Could not find '//name, &
955  terminate=.true.)
956  end if
957  end subroutine get_package_index
958 
959 end module flowmodelinterfacemodule
This module contains the base boundary package.
class(bndtype) function, pointer, public getbndfromlist(list, idx)
Get boundary from package list.
subroutine, public budgetobject_cr_bfr(this, name, ibinun, iout, colconv1, colconv2)
Create a new budget object from a binary flow file.
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 lenvarname
maximum length of a variable name
Definition: Constants.f90:17
real(dp), parameter dhalf
real constant 1/2
Definition: Constants.f90:68
real(dp), parameter dem6
real constant 1e-6
Definition: Constants.f90:109
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
integer(i4b), parameter lenbudtxt
maximum length of a budget component names
Definition: Constants.f90:37
integer(i4b), parameter lenmempath
maximum length of the memory path
Definition: Constants.f90:27
real(dp), parameter done
real constant 1
Definition: Constants.f90:76
subroutine allocate_scalars(this)
Allocate scalars.
subroutine fmi_ar(this, ibound)
Allocate the package.
subroutine allocate_gwfpackages(this, ngwfterms)
Allocate budget packages.
subroutine deallocate_gwfpackages(this)
Deallocate memory in the gwfpackages array.
subroutine read_options(this)
Read options from input file.
subroutine finalize_hfr(this)
Finalize the head file reader.
subroutine fmi_df(this, dis, idryinactive)
Define the flow model interface.
subroutine get_package_index(this, name, idx)
Find the package index for the package with the given name.
subroutine advance_bfr(this)
Advance the budget file reader.
subroutine initialize_gwfterms_from_gwfbndlist(this)
Initialize gwf terms from a GWF exchange.
subroutine initialize_hfr(this)
Initialize the head file reader.
subroutine fmi_da(this)
Deallocate variables.
subroutine read_packagedata(this)
Read packagedata block from input file.
subroutine advance_hfr(this)
Advance the head file reader.
subroutine initialize_gwfterms_from_bfr(this)
Initialize gwf terms from budget file.
subroutine finalize_bfr(this)
Finalize the budget file reader.
subroutine allocate_arrays(this, nodes)
Allocate arrays.
subroutine initialize_bfr(this)
Initialize the budget file reader.
subroutine, public urdaux(naux, inunit, iout, lloc, istart, istop, auxname, line, text)
Read auxiliary variables from an input line.
integer(i4b) function, public getunit()
Get a free unit number.
subroutine, public openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, filstat_opt, mode_opt)
Open a file.
Definition: InputOutput.f90:30
This module defines variable data types.
Definition: kind.f90:8
This module contains the base numerical package type.
character(len=20) access
Definition: OpenSpec.f90:7
character(len=20) form
Definition: OpenSpec.f90:7
This module contains the PackageBudgetModule Module.
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
integer(i4b) function, public count_errors()
Return number of errors.
Definition: Sim.f90:59
subroutine, public store_error_unit(iunit, terminate)
Store the file unit number.
Definition: Sim.f90:168
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string
integer(i4b), pointer, public kstp
current time step number
Definition: tdis.f90:24
integer(i4b), pointer, public kper
current stress period number
Definition: tdis.f90:23
@ brief BndType
A generic heterogeneous doubly-linked list.
Definition: List.f90:14
Derived type for storing flows.