MODFLOW 6  version 6.8.0.dev0
USGS Modular Hydrologic Model
tsp-mvt.f90
Go to the documentation of this file.
1 ! -- Groundwater Transport Mover Module
2 ! -- This module is responsible for sending mass from providers into
3 ! -- receiver qmfrommvr arrays and writing a mover transport budget
4 
6 
7  use kindmodule, only: dp, i4b, lgp
11 
12  use simmodule, only: store_error
13  use basedismodule, only: disbasetype
15  use tspfmimodule, only: tspfmitype
18  use tablemodule, only: tabletype, table_cr
19 
20  implicit none
21 
22  private
23  public :: tspmvttype
24  public :: mvt_cr
25 
26  !> @brief Type to store mover-transport flow and concentration for one budget term
27  !<í
28  type :: mvrtermtype
29  logical(LGP) :: prov_is_m1 !< true when provider is in model1, false when in model 2
30  real(dp), dimension(:), pointer, contiguous :: qty => null() !< concentration or temperature of provider
31  end type mvrtermtype
32 
33  type, extends(numericalpackagetype) :: tspmvttype
34 
35  character(len=LENMODELNAME) :: gwfmodelname1 = '' !< name of model 1
36  character(len=LENMODELNAME) :: gwfmodelname2 = '' !< name of model 2 (set to modelname 1 for single model MVT)
37  integer(I4B), pointer :: maxpackages !< max number of packages
38  integer(I4B), pointer :: ibudgetout => null() !< unit number for budget output file
39  integer(I4B), pointer :: ibudcsv => null() !< unit number for csv budget output file
40  real(dp), pointer :: eqnsclfac => null() !< governing equation scale factor; =1. for solute; =rhow*cpw for energy
41  type(tspfmitype), pointer :: fmi1 => null() !< pointer to fmi object for model 1
42  type(tspfmitype), pointer :: fmi2 => null() !< pointer to fmi object for model 2 (set to fmi1 for single model)
43  type(budgettype), pointer :: budget => null() !< mover transport budget object (used to write balance table)
44  type(budgetobjecttype), pointer :: budobj => null() !< budget container (used to write binary file)
45  type(budgetobjecttype), pointer :: mvrbudobj => null() !< pointer to the water mover budget object
46  character(len=LENPACKAGENAME), &
47  dimension(:), pointer, contiguous :: paknames => null() !< array of package names
48  character(len=LENVARNAME) :: depvartype = ''
49  !
50  ! -- table objects
51  type(tabletype), pointer :: outputtab => null()
52  !
53  ! -- mover transport terms
54  type(mvrtermtype), dimension(:), pointer, contiguous :: mvrterm => null() !< qty and flow per budget term
55 
56  contains
57  procedure :: mvt_init
58  procedure :: mvt_df
59  procedure :: mvt_ar
60  procedure :: mvt_rp
61  procedure :: mvt_fc
62  procedure :: mvt_fill_mvrterm
63  procedure :: mvt_update_qmfrommvr
64  procedure :: mvt_cc
65  procedure :: mvt_bd
66  procedure :: mvt_ot_saveflow
67  procedure :: mvt_ot_printflow
68  procedure :: mvt_ot_bdsummary
69  procedure :: mvt_da
70  procedure :: allocate_scalars
71  procedure :: read_options
72  procedure :: mvt_setup_budobj
73  procedure :: mvt_fill_budobj
74  procedure :: mvt_scan_mvrbudobj
75  procedure :: set_pointer_mvrbudobj
76  procedure :: set_fmi
77  procedure, private :: mvt_setup_outputtab
78  procedure, private :: mvt_print_outputtab
79  end type tspmvttype
80 
81 contains
82 
83  subroutine mvt_cr(mvt, name_model, inunit, iout, fmi1, eqnsclfac, &
84  depvartype, gwfmodelname1, gwfmodelname2, fmi2)
85  type(tspmvttype), pointer :: mvt
86  character(len=*), intent(in) :: name_model
87  integer(I4B), intent(in) :: inunit
88  integer(I4B), intent(in) :: iout
89  type(tspfmitype), intent(in), pointer :: fmi1
90  real(dp), intent(in), pointer :: eqnsclfac !< governing equation scale factor
91  character(len=LENVARNAME), intent(in) :: depvartype !< dependent variable type ('concentration' or 'temperature')
92  character(len=*), intent(in), optional :: gwfmodelname1
93  character(len=*), intent(in), optional :: gwfmodelname2
94  type(tspfmitype), intent(in), pointer, optional :: fmi2
95 
96  allocate (mvt)
97  call mvt%mvt_init(name_model, inunit, iout, fmi1, eqnsclfac, &
98  depvartype, gwfmodelname1, gwfmodelname2, fmi2)
99 
100  end subroutine mvt_cr
101 
102  !> @brief Create a new mover transport object
103  !<
104  subroutine mvt_init(this, name_model, inunit, iout, fmi1, eqnsclfac, &
105  depvartype, gwfmodelname1, gwfmodelname2, fmi2)
106  ! -- dummy
107  class(tspmvttype) :: this
108  character(len=*), intent(in) :: name_model
109  integer(I4B), intent(in) :: inunit
110  integer(I4B), intent(in) :: iout
111  type(tspfmitype), intent(in), pointer :: fmi1
112  real(DP), intent(in), pointer :: eqnsclfac !< governing equation scale factor
113  character(len=LENVARNAME), intent(in) :: depvartype !< dependent variable type ('concentration' or 'temperature')
114  character(len=*), intent(in), optional :: gwfmodelname1
115  character(len=*), intent(in), optional :: gwfmodelname2
116  type(tspfmitype), intent(in), pointer, optional :: fmi2
117  !
118  ! -- Create name and memory path
119  call this%set_names(1, name_model, 'MVT', 'MVT')
120  !
121  ! -- Allocate scalars
122  call this%allocate_scalars()
123  !
124  this%inunit = inunit
125  this%iout = iout
126  !
127  ! -- Assume that this MVT is owned by a GWT Model
128  this%fmi1 => fmi1
129  this%fmi2 => fmi1
130  !
131  ! -- Set pointers
132  if (present(fmi2)) then
133  this%fmi2 => fmi2
134  end if
135  !
136  ! -- Set model names
137  if (present(gwfmodelname1)) then
138  this%gwfmodelname1 = gwfmodelname1
139  end if
140  if (present(gwfmodelname2)) then
141  this%gwfmodelname2 = gwfmodelname2
142  end if
143  !
144  ! -- Create the budget object
145  call budgetobject_cr(this%budobj, 'TRANSPORT MOVER')
146  !
147  ! -- Store pointer to governing equation scale factor
148  this%eqnsclfac => eqnsclfac
149  !
150  ! -- Store pointer to labels associated with the current model so that the
151  ! package has access to the corresponding dependent variable type
152  this%depvartype = depvartype
153 
154  end subroutine mvt_init
155 
156  !> @brief Define mover transport object
157  !<
158  subroutine mvt_df(this, dis)
159  ! -- dummy
160  class(tspmvttype) :: this
161  class(disbasetype), pointer, intent(in) :: dis
162  ! -- formats
163  character(len=*), parameter :: fmtmvt = &
164  "(1x,/1x,'MVT -- MOVER TRANSPORT PACKAGE, VERSION 1, 4/15/2020', &
165  &' INPUT READ FROM UNIT ', i0, //)"
166  !
167  ! -- Set pointer to dis
168  this%dis => dis
169  !
170  ! -- Print a message identifying the MVT package.
171  write (this%iout, fmtmvt) this%inunit
172  !
173  ! -- Initialize block parser
174  call this%parser%Initialize(this%inunit, this%iout)
175  !
176  ! -- Initialize the budget table writer
177  call budget_cr(this%budget, this%memoryPath)
178  !
179  ! -- Read mvt options
180  call this%read_options()
181  end subroutine mvt_df
182 
183  !> @ brief Set pointer to mvrbudobj
184  !!
185  !! Store a pointer to mvrbudobj, which contains the simulated water
186  !! mover flows from either a gwf model MVR package or from a gwf-gwf
187  !! exchange MVR package.
188  !<
189  subroutine set_pointer_mvrbudobj(this, mvrbudobj)
190  class(tspmvttype) :: this
191  type(budgetobjecttype), intent(in), target :: mvrbudobj
192  this%mvrbudobj => mvrbudobj
193  end subroutine set_pointer_mvrbudobj
194 
195  !> @brief Allocate and read mover-for-transport information
196  !<
197  subroutine mvt_ar(this)
198  ! -- dummy
199  class(tspmvttype) :: this
200  !
201  ! -- Setup the output table
202  call this%mvt_setup_outputtab()
203  end subroutine mvt_ar
204 
205  !> @brief Read and prepare mover transport object
206  !<
207  subroutine mvt_rp(this)
208  ! -- modules
209  use tdismodule, only: kper, kstp
210  ! -- dummy
211  class(tspmvttype) :: this
212  !
213  ! -- At this point, the mvrbudobj is available to set up the mvt budobj
214  if (kper * kstp == 1) then
215  !
216  ! -- If mvt is for a single model then point to fmi1
217  !cdl todo: this needs to be called from GwtGwtExg somehow for the 2 model case
218  if (associated(this%fmi1, this%fmi2)) then
219  call this%set_pointer_mvrbudobj(this%fmi1%mvrbudobj)
220  end if
221  !
222  ! -- Set up the mvt budobject
223  call this%mvt_scan_mvrbudobj()
224  call this%mvt_setup_budobj()
225  !
226  ! -- Define the budget object to be the size of maxpackages
227  call this%budget%budget_df(this%maxpackages, 'TRANSPORT MOVER', bddim='M')
228  call this%budget%set_ibudcsv(this%ibudcsv)
229  end if
230  end subroutine mvt_rp
231 
232  !> @brief Calculate coefficients and fill amat and rhs
233  !!
234  !! The mvt package adds the mass flow rate to the provider qmfrommvr array.
235  !! The advanced packages know enough to subtract any mass that is leaving, so
236  !! the mvt just adds mass coming in from elsewhere. Because the movers
237  !! change by stress period, their solute effects must be added to the right-
238  !! hand side of the transport matrix equations.
239  !<
240  subroutine mvt_fc(this, cnew1, cnew2)
241  class(tspmvttype) :: this
242  real(DP), intent(in), dimension(:), contiguous, target :: cnew1
243  real(DP), intent(in), dimension(:), contiguous, target :: cnew2
244 
245  call this%mvt_fill_mvrterm(cnew1, cnew2)
246  call this%mvt_update_qmfrommvr()
247 
248  end subroutine mvt_fc
249 
250  !> @brief Fill mvrterm with provider concentration and flow for each budget term
251  !<
252  subroutine mvt_fill_mvrterm(this, cnew1, cnew2)
253  class(tspmvttype) :: this
254  real(DP), intent(in), dimension(:), contiguous, target :: cnew1
255  real(DP), intent(in), dimension(:), contiguous, target :: cnew2
256  ! local
257  integer(I4B) :: i, n
258  integer(I4B) :: id1, nlist
259  integer(I4B) :: ipr
260  integer(I4B) :: igwtnode
261  integer(I4B) :: nbudterm
262  real(DP) :: cp
263  real(DP), dimension(:), pointer :: concpak
264  real(DP), dimension(:), contiguous, pointer :: cnew_pr !, pointer to provider dep. var.
265  type(tspfmitype), pointer :: fmi_pr !< pointer to provider model fmi package
266 
267  nbudterm = this%mvrbudobj%nbudterm
268  do i = 1, nbudterm
269  nlist = this%mvrbudobj%budterm(i)%nlist
270  if (nlist == 0) cycle
271 
272  ! fetch fmi package
273  call this%set_fmi(i, fmi_pr, .true.)
274  if (.not. associated(fmi_pr)) cycle
275 
276  cnew_pr => cnew1
277  if (associated(fmi_pr, this%fmi2)) then
278  cnew_pr => cnew2
279  end if
280 
281  call fmi_pr%get_package_index(this%mvrbudobj%budterm(i)%text2id1, ipr)
282 
283  ! use package concentration for APT
284  if (fmi_pr%iatp(ipr) /= 0) then
285  concpak => fmi_pr%datp(ipr)%concpack
286  end if
287 
288  do n = 1, nlist
289 
290  ! lak/sfr/maw/uzf id1 (provider)
291  id1 = this%mvrbudobj%budterm(i)%id1(n)
292  cp = dzero
293  if (fmi_pr%iatp(ipr) /= 0) then
294  ! concentration from APT
295  cp = concpak(id1)
296  else
297  igwtnode = fmi_pr%gwfpackages(ipr)%nodelist(id1)
298  cp = cnew_pr(igwtnode)
299  end if
300 
301  this%mvrterm(i)%qty(n) = cp
302  end do
303  end do
304  end subroutine mvt_fill_mvrterm
305 
306  !> @brief Assign mover transport mass into each receiver's qmfrommvr
307  !<
308  subroutine mvt_update_qmfrommvr(this)
309  class(tspmvttype) :: this
310  ! local
311  integer(I4B) :: i, n
312  integer(I4B) :: id2, nlist
313  integer(I4B) :: irc
314  integer(I4B) :: nbudterm
315  type(tspfmitype), pointer :: fmi_rc !< pointer to receiver model fmi package
316 
317  nbudterm = this%mvrbudobj%nbudterm
318  do i = 1, nbudterm
319  nlist = this%mvrbudobj%budterm(i)%nlist
320  if (nlist == 0) cycle
321 
322  call this%set_fmi(i, fmi_rc, .false.)
323  if (.not. associated(fmi_rc)) cycle
324 
325  call fmi_rc%get_package_index(this%mvrbudobj%budterm(i)%text2id2, irc)
326 
327  do n = 1, nlist
328 
329  ! lak/sfr/maw/uzf id2 (receiver)
330  id2 = this%mvrbudobj%budterm(i)%id2(n)
331 
332  ! add the mover rate times the provider concentration into the receiver;
333  ! accumulated since multiple providers can move water into the same receiver
334  if (fmi_rc%iatp(irc) /= 0) then
335  fmi_rc%datp(irc)%qmfrommvr(id2) = fmi_rc%datp(irc)%qmfrommvr(id2) - &
336  this%mvrbudobj%budterm(i)%flow(n) * &
337  this%mvrterm(i)%qty(n) * &
338  this%eqnsclfac
339  end if
340  end do
341  end do
342  end subroutine mvt_update_qmfrommvr
343 
344  subroutine set_fmi(this, ibudterm, fmi, set_provider)
345  class(tspmvttype) :: this
346  integer(I4B), intent(in) :: ibudterm
347  type(tspfmitype), pointer :: fmi
348  logical(LGP) :: set_provider !< set provider fmi when true, receiver fmi otherwise
349  ! local
350  character(len=LENMODELNAME) :: model_name
351 
352  fmi => null()
353  if (this%gwfmodelname1 == '' .and. this%gwfmodelname2 == '') then
354  fmi => this%fmi1 ! fmi2 equals fmi1 here
355  return
356  end if
357 
358  ! model name for provider is text1id1, receiver is text1id2
359  if (set_provider) then
360  model_name = this%mvrbudobj%budterm(ibudterm)%text1id1
361  else
362  model_name = this%mvrbudobj%budterm(ibudterm)%text1id2
363  end if
364 
365  if (model_name == this%gwfmodelname1) then
366  ! model 1 is the provider/receiver
367  fmi => this%fmi1
368  else if (model_name == this%gwfmodelname2) then
369  ! model 2 is the provider
370  fmi => this%fmi2
371  end if
372 
373  end subroutine set_fmi
374 
375  !> @brief Extra convergence check for mover
376  !<
377  subroutine mvt_cc(this, kiter, iend, icnvgmod, cpak, dpak)
378  ! -- dummy
379  class(tspmvttype) :: this
380  integer(I4B), intent(in) :: kiter
381  integer(I4B), intent(in) :: iend
382  integer(I4B), intent(in) :: icnvgmod
383  character(len=LENPAKLOC), intent(inout) :: cpak
384  real(DP), intent(inout) :: dpak
385  ! -- formats
386  character(len=*), parameter :: fmtmvrcnvg = &
387  "(/,1x,'MOVER PACKAGE REQUIRES AT LEAST TWO OUTER ITERATIONS. CONVERGE &
388  &FLAG HAS BEEN RESET TO FALSE.')"
389  !
390  ! -- If there are active movers, then at least 2 outers required
391  if (associated(this%mvrbudobj)) then
392  if (icnvgmod == 1 .and. kiter == 1) then
393  dpak = dnodata
394  cpak = trim(this%packName)
395  write (this%iout, fmtmvrcnvg)
396  end if
397  end if
398  end subroutine mvt_cc
399 
400  !> @brief Write mover terms to listing file
401  !<
402  subroutine mvt_bd(this)
403  ! -- dummy
404  class(tspmvttype) :: this
405  !
406  ! -- Fill the budget object
407  call this%mvt_fill_budobj()
408  end subroutine mvt_bd
409 
410  !> @brief Write mover budget terms
411  !<
412  subroutine mvt_ot_saveflow(this, icbcfl, ibudfl)
413  ! -- modules
414  use tdismodule, only: kstp, kper, delt, pertim, totim
415  ! -- dummy
416  class(tspmvttype) :: this
417  integer(I4B), intent(in) :: icbcfl
418  integer(I4B), intent(in) :: ibudfl
419  ! -- locals
420  integer(I4B) :: ibinun
421  !
422  ! -- Save the mover flows from the budobj to a mover binary file
423  ibinun = 0
424  if (this%ibudgetout /= 0) then
425  ibinun = this%ibudgetout
426  end if
427  if (icbcfl == 0) ibinun = 0
428  if (ibinun > 0) then
429  call this%budobj%save_flows(this%dis, ibinun, kstp, kper, delt, &
430  pertim, totim, this%iout)
431  end if
432  end subroutine mvt_ot_saveflow
433 
434  !> @brief Print mover flow table
435  !<
436  subroutine mvt_ot_printflow(this, icbcfl, ibudfl)
437  ! -- dummy
438  class(tspmvttype) :: this
439  integer(I4B), intent(in) :: icbcfl
440  integer(I4B), intent(in) :: ibudfl
441  !
442  ! -- Print the mover flow table
443  if (ibudfl /= 0 .and. this%iprflow /= 0) then
444  call this%mvt_print_outputtab()
445  end if
446  end subroutine mvt_ot_printflow
447 
448  !> @brief Write mover budget to listing file
449  !<
450  subroutine mvt_ot_bdsummary(this, ibudfl)
451  ! -- modules
452  use tdismodule, only: kstp, kper, delt, totim
453  ! -- dummy
454  class(tspmvttype) :: this
455  integer(I4B), intent(in) :: ibudfl
456  ! -- locals
457  integer(I4B) :: i, j, n
458  real(DP), allocatable, dimension(:) :: ratin, ratout
459  !
460  ! -- Allocate and initialize ratin/ratout
461  allocate (ratin(this%maxpackages), ratout(this%maxpackages))
462  do j = 1, this%maxpackages
463  ratin(j) = dzero
464  ratout(j) = dzero
465  end do
466  !
467  ! -- Accumulate the rates
468  do i = 1, this%maxpackages
469  do j = 1, this%budobj%nbudterm
470  do n = 1, this%budobj%budterm(j)%nlist
471  !
472  ! -- Provider is inflow to mover
473  if (this%paknames(i) == this%budobj%budterm(j)%text2id1) then
474  ratin(i) = ratin(i) + this%budobj%budterm(j)%flow(n)
475  end if
476  !
477  ! -- Receiver is outflow from mover
478  if (this%paknames(i) == this%budobj%budterm(j)%text2id2) then
479  ratout(i) = ratout(i) + this%budobj%budterm(j)%flow(n)
480  end if
481  end do
482  end do
483  end do
484  !
485  ! -- Send rates to budget object
486  call this%budget%reset()
487  do j = 1, this%maxpackages
488  call this%budget%addentry(ratin(j), ratout(j), delt, this%paknames(j))
489  end do
490  !
491  ! -- Write the budget
492  call this%budget%finalize_step(delt)
493  if (ibudfl /= 0) then
494  call this%budget%budget_ot(kstp, kper, this%iout)
495  end if
496  !
497  ! -- Write budget csv
498  call this%budget%writecsv(totim)
499  !
500  ! -- Deallocate
501  deallocate (ratin, ratout)
502  !
503  ! -- Output mvr budget
504  ! Not using budobj write_table here because it would result
505  ! in a table that has one entry. A custom table looks
506  ! better here with a row for each package.
507  !call this%budobj%write_budtable(kstp, kper, this%iout)
508  end subroutine mvt_ot_bdsummary
509 
510  !> @ brief Deallocate memory
511  !!
512  !! Method to deallocate memory for the package.
513  !<
514  subroutine mvt_da(this)
515  ! -- modules
517  ! -- dummy
518  class(tspmvttype) :: this
519  ! -- local
520  integer(I4B) :: i
521  !
522  ! -- Deallocate arrays if package was active
523  if (this%inunit > 0) then
524  !
525  ! -- mvrterm
526  if (associated(this%mvrterm)) then
527  do i = 1, size(this%mvrterm)
528  deallocate (this%mvrterm(i)%qty)
529  end do
530  deallocate (this%mvrterm)
531  end if
532  !
533  ! -- Character array
534  deallocate (this%paknames)
535  !
536  ! -- Budget object
537  call this%budget%budget_da()
538  deallocate (this%budget)
539  !
540  ! -- Budobj
541  call this%budobj%budgetobject_da()
542  deallocate (this%budobj)
543  nullify (this%budobj)
544  !
545  ! -- Output table object
546  if (associated(this%outputtab)) then
547  call this%outputtab%table_da()
548  deallocate (this%outputtab)
549  nullify (this%outputtab)
550  end if
551  end if
552  !
553  ! -- Scalars
554  this%fmi1 => null()
555  this%fmi1 => null()
556  this%mvrbudobj => null()
557  call mem_deallocate(this%maxpackages)
558  call mem_deallocate(this%ibudgetout)
559  call mem_deallocate(this%ibudcsv)
560  !
561  ! -- Deallocate scalars in NumericalPackageType
562  call this%NumericalPackageType%da()
563  end subroutine mvt_da
564 
565  !> @ brief Allocate scalar variables for package
566  !!
567  !! Method to allocate scalar variables for the MVT package.
568  !<
569  subroutine allocate_scalars(this)
570  ! -- modules
572  ! -- dummy
573  class(tspmvttype) :: this
574  !
575  ! -- Allocate scalars in NumericalPackageType
576  call this%NumericalPackageType%allocate_scalars()
577  !
578  ! -- Allocate
579  call mem_allocate(this%maxpackages, 'MAXPACKAGES', this%memoryPath)
580  call mem_allocate(this%ibudgetout, 'IBUDGETOUT', this%memoryPath)
581  call mem_allocate(this%ibudcsv, 'IBUDCSV', this%memoryPath)
582  !
583  ! -- Initialize
584  this%maxpackages = 0
585  this%ibudgetout = 0
586  this%ibudcsv = 0
587  end subroutine allocate_scalars
588 
589  !> @brief Read mover-for-transport options block
590  !<
591  subroutine read_options(this)
592  ! -- modules
593  use openspecmodule, only: access, form
595  ! -- dummy
596  class(tspmvttype) :: this
597  ! -- local
598  character(len=LINELENGTH) :: errmsg, keyword
599  character(len=MAXCHARLEN) :: fname
600  integer(I4B) :: ierr
601  logical :: isfound, endOfBlock
602  ! -- formats
603  character(len=*), parameter :: fmtflow = &
604  "(4x, a, 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, &
605  &/4x, 'OPENED ON UNIT: ', I0)"
606  character(len=*), parameter :: fmtflow2 = &
607  &"(4x, 'FLOWS WILL BE SAVED TO BUDGET FILE')"
608  !
609  ! -- Get options block
610  call this%parser%GetBlock('OPTIONS', isfound, ierr, blockrequired=.false., &
611  supportopenclose=.true.)
612  !
613  ! -- Parse options block if detected
614  if (isfound) then
615  write (this%iout, '(1x,a)') 'PROCESSING MVT OPTIONS'
616  do
617  call this%parser%GetNextLine(endofblock)
618  if (endofblock) exit
619  call this%parser%GetStringCaps(keyword)
620  select case (keyword)
621  case ('SAVE_FLOWS')
622  this%ipakcb = -1
623  write (this%iout, fmtflow2)
624  case ('PRINT_INPUT')
625  this%iprpak = 1
626  write (this%iout, '(4x,a)') 'MVT INPUT WILL BE PRINTED.'
627  case ('PRINT_FLOWS')
628  this%iprflow = 1
629  write (this%iout, '(4x,a)') &
630  'MVT FLOWS WILL BE PRINTED TO LISTING FILE.'
631  case ('BUDGET')
632  call this%parser%GetStringCaps(keyword)
633  if (keyword == 'FILEOUT') then
634  call this%parser%GetString(fname)
635  call assign_iounit(this%ibudgetout, this%inunit, "BUDGET fileout")
636  call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', &
637  form, access, 'REPLACE')
638  write (this%iout, fmtflow) 'MVT', 'BUDGET', trim(adjustl(fname)), &
639  this%ibudgetout
640  else
641  call store_error('Optional BUDGET keyword must &
642  &be followed by FILEOUT')
643  end if
644  case ('BUDGETCSV')
645  call this%parser%GetStringCaps(keyword)
646  if (keyword == 'FILEOUT') then
647  call this%parser%GetString(fname)
648  call assign_iounit(this%ibudcsv, this%inunit, "BUDGETCSV fileout")
649  call openfile(this%ibudcsv, this%iout, fname, 'CSV', &
650  filstat_opt='REPLACE')
651  write (this%iout, fmtflow) 'MVT', 'BUDGET CSV', &
652  trim(adjustl(fname)), this%ibudcsv
653  else
654  call store_error('Optional BUDGETCSV keyword must be followed by &
655  &FILEOUT')
656  end if
657  case default
658  write (errmsg, '(a,a)') 'Unknown MVT option: ', &
659  trim(keyword)
660  call store_error(errmsg)
661  call this%parser%StoreErrorUnit()
662  end select
663  end do
664  write (this%iout, '(1x,a)') 'END OF MVT OPTIONS'
665  end if
666  end subroutine read_options
667 
668  !> @brief Set up the budget object that stores all the mvr flows
669  !<
670  subroutine mvt_setup_budobj(this)
671  ! -- modules
672  use constantsmodule, only: lenbudtxt
673  ! -- dummy
674  class(tspmvttype) :: this
675  ! -- local
676  integer(I4B) :: nbudterm
677  integer(I4B) :: ncv
678  integer(I4B) :: maxlist
679  integer(I4B) :: i
680  integer(I4B) :: naux
681  character(len=LENMODELNAME) :: modelname1, modelname2
682  character(len=LENPACKAGENAME) :: packagename1, packagename2
683  character(len=LENBUDTXT) :: text
684  !
685  ! -- Assign terms to set up the mover budget object
686  nbudterm = this%mvrbudobj%nbudterm
687  ncv = 0
688  naux = 0
689  if (this%depvartype == 'CONCENTRATION') then
690  text = ' MVT-FLOW'
691  else
692  text = ' MVE-FLOW'
693  end if
694  !
695  ! -- Set up budobj
696  call this%budobj%budgetobject_df(ncv, nbudterm, 0, 0, bddim_opt='M')
697  !
698  ! -- Allocate mvrterm
699  allocate (this%mvrterm(nbudterm))
700  !
701  ! -- Go through the water mover budget terms and set up the transport
702  ! mover budget terms
703  do i = 1, nbudterm
704  modelname1 = this%mvrbudobj%budterm(i)%text1id1
705  packagename1 = this%mvrbudobj%budterm(i)%text2id1
706  modelname2 = this%mvrbudobj%budterm(i)%text1id2
707  packagename2 = this%mvrbudobj%budterm(i)%text2id2
708  maxlist = this%mvrbudobj%budterm(i)%maxlist
709  call this%budobj%budterm(i)%initialize(text, &
710  modelname1, &
711  packagename1, &
712  modelname2, &
713  packagename2, &
714  maxlist, .false., .false., &
715  naux)
716  this%mvrterm(i)%prov_is_m1 = (this%gwfmodelname1 == modelname1)
717  allocate (this%mvrterm(i)%qty(maxlist))
718  this%mvrterm(i)%qty = dnodata
719  end do
720  end subroutine mvt_setup_budobj
721 
722  !> @brief Copy mover-for-transport flow terms into this%budobj
723  !<
724  subroutine mvt_fill_budobj(this)
725  ! -- dummy
726  class(tspmvttype) :: this
727  ! -- local
728  type(tspfmitype), pointer :: fmi_rc
729  integer(I4B) :: nbudterm
730  integer(I4B) :: nlist
731  integer(I4B) :: irc
732  integer(I4B) :: i
733  integer(I4B) :: j
734  integer(I4B) :: n1, n2
735  real(DP) :: cp
736  real(DP) :: q
737  real(DP) :: rate
738  !
739  ! -- Go through the water mover budget terms and set up the transport
740  ! mover budget terms
741  nbudterm = this%mvrbudobj%nbudterm
742  do i = 1, nbudterm
743  nlist = this%mvrbudobj%budterm(i)%nlist
744  call this%set_fmi(i, fmi_rc, .false.)
745  if (.not. associated(fmi_rc)) cycle
746 
747  call fmi_rc%get_package_index(this%mvrbudobj%budterm(i)%text2id2, irc)
748  call this%budobj%budterm(i)%reset(nlist)
749  do j = 1, nlist
750  n1 = this%mvrbudobj%budterm(i)%id1(j)
751  n2 = this%mvrbudobj%budterm(i)%id2(j)
752  q = this%mvrbudobj%budterm(i)%flow(j)
753  cp = this%mvrterm(i)%qty(j)
754 
755  ! calculate solute mover rate
756  rate = dzero
757  if (fmi_rc%iatp(irc) /= 0) then
758  rate = -q * cp * this%eqnsclfac
759  end if
760  !
761  ! -- Add the rate to the budterm
762  call this%budobj%budterm(i)%update_term(n1, n2, rate)
763  end do
764  end do
765  !
766  ! --Terms are filled, now accumulate them for this time step
767  call this%budobj%accumulate_terms()
768  end subroutine mvt_fill_budobj
769 
770  !> @brief Determine max number of packages in use
771  !!
772  !! Scan through the gwf water mover budget object and determine the maximum
773  !! number of packages and unique package names
774  !<
775  subroutine mvt_scan_mvrbudobj(this)
776  class(tspmvttype) :: this
777  integer(I4B) :: nbudterm
778  integer(I4B) :: maxpackages
779  integer(I4B) :: i, j
780  integer(I4B) :: ipos
781  logical :: found
782  !
783  ! -- Calculate maxpackages, which is the the square of nbudterm
784  nbudterm = this%mvrbudobj%nbudterm
785  do i = 1, nbudterm
786  if (i * i == nbudterm) then
787  maxpackages = i
788  exit
789  end if
790  end do
791  this%maxpackages = maxpackages
792  !
793  ! -- Allocate paknames
794  if (associated(this%paknames)) deallocate (this%paknames)
795  allocate (this%paknames(this%maxpackages))
796  do i = 1, this%maxpackages
797  this%paknames(i) = ''
798  end do
799  !
800  ! -- Scan through mvrbudobj and create unique paknames
801  ipos = 1
802  do i = 1, nbudterm
803  found = .false.
804  do j = 1, ipos
805  if (this%mvrbudobj%budterm(i)%text2id1 == this%paknames(j)) then
806  found = .true.
807  exit
808  end if
809  end do
810  if (.not. found) then
811  this%paknames(ipos) = this%mvrbudobj%budterm(i)%text2id1
812  ipos = ipos + 1
813  end if
814  end do
815  end subroutine mvt_scan_mvrbudobj
816 
817  !> @brief Set up the mover-for-transport output table
818  !<
819  subroutine mvt_setup_outputtab(this)
820  ! -- dummy
821  class(tspmvttype), intent(inout) :: this
822  ! -- local
823  character(len=LINELENGTH) :: title
824  character(len=LINELENGTH) :: text
825  integer(I4B) :: ntabcol
826  integer(I4B) :: maxrow
827  integer(I4B) :: ilen
828  !
829  ! -- Allocate and initialize the output table
830  if (this%iprflow /= 0) then
831  !
832  ! -- Dimension table
833  ntabcol = 7
834  maxrow = 0
835  !
836  ! -- Initialize the output table object
837  title = 'TRANSPORT MOVER PACKAGE ('//trim(this%packName)// &
838  ') FLOW RATES'
839  call table_cr(this%outputtab, this%packName, title)
840  call this%outputtab%table_df(maxrow, ntabcol, this%iout, &
841  transient=.true.)
842  text = 'NUMBER'
843  call this%outputtab%initialize_column(text, 10, alignment=tabcenter)
844  text = 'PROVIDER LOCATION'
845  ilen = lenmodelname + lenpackagename + 1
846  call this%outputtab%initialize_column(text, ilen)
847  text = 'PROVIDER ID'
848  call this%outputtab%initialize_column(text, 10)
849  text = 'PROVIDER FLOW RATE'
850  call this%outputtab%initialize_column(text, 10)
851  text = 'PROVIDER TRANSPORT RATE'
852  call this%outputtab%initialize_column(text, 10)
853  text = 'RECEIVER LOCATION'
854  ilen = lenmodelname + lenpackagename + 1
855  call this%outputtab%initialize_column(text, ilen)
856  text = 'RECEIVER ID'
857  call this%outputtab%initialize_column(text, 10)
858  !
859  end if
860  end subroutine mvt_setup_outputtab
861 
862  !> @brief Set up mover-for-transport output table
863  !<
864  subroutine mvt_print_outputtab(this)
865  ! -- module
866  use tdismodule, only: kstp, kper
867  ! -- dummy
868  class(tspmvttype), intent(inout) :: this
869  ! -- local
870  character(len=LINELENGTH) :: title
871  character(len=LENMODELNAME + LENPACKAGENAME + 1) :: cloc1, cloc2
872  integer(I4B) :: i
873  integer(I4B) :: n
874  integer(I4B) :: inum
875  integer(I4B) :: ntabrows
876  integer(I4B) :: nlist
877  !
878  ! -- Determine number of table rows
879  ntabrows = 0
880  do i = 1, this%budobj%nbudterm
881  nlist = this%budobj%budterm(i)%nlist
882  ntabrows = ntabrows + nlist
883  end do
884  !
885  ! -- Set table kstp and kper
886  call this%outputtab%set_kstpkper(kstp, kper)
887  !
888  ! -- Add terms and print the table
889  title = 'TRANSPORT MOVER PACKAGE ('//trim(this%packName)// &
890  ') FLOW RATES'
891  call this%outputtab%set_title(title)
892  call this%outputtab%set_maxbound(ntabrows)
893  !
894  ! -- Process each table row
895  inum = 1
896  do i = 1, this%budobj%nbudterm
897  nlist = this%budobj%budterm(i)%nlist
898  do n = 1, nlist
899  cloc1 = trim(adjustl(this%budobj%budterm(i)%text1id1))//' '// &
900  trim(adjustl(this%budobj%budterm(i)%text2id1))
901  cloc2 = trim(adjustl(this%budobj%budterm(i)%text1id2))//' '// &
902  trim(adjustl(this%budobj%budterm(i)%text2id2))
903  call this%outputtab%add_term(inum)
904  call this%outputtab%add_term(cloc1)
905  call this%outputtab%add_term(this%budobj%budterm(i)%id1(n))
906  call this%outputtab%add_term(-this%mvrbudobj%budterm(i)%flow(n))
907  call this%outputtab%add_term(this%budobj%budterm(i)%flow(n))
908  call this%outputtab%add_term(cloc2)
909  call this%outputtab%add_term(this%budobj%budterm(i)%id2(n))
910  inum = inum + 1
911  end do
912  end do
913  end subroutine mvt_print_outputtab
914 
915 end module tspmvtmodule
916 
This module contains the BudgetModule.
Definition: Budget.f90:20
subroutine, public budget_cr(this, name_model)
@ brief Create a new budget object
Definition: Budget.f90:84
subroutine, public budgetobject_cr(this, name)
Create a new budget object.
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
@ tabcenter
centered table column
Definition: Constants.f90:172
integer(i4b), parameter lenmodelname
maximum length of the model name
Definition: Constants.f90:22
integer(i4b), parameter lenpackagename
maximum length of the package name
Definition: Constants.f90:23
real(dp), parameter dnodata
real no data constant
Definition: Constants.f90:95
integer(i4b), parameter lenpakloc
maximum length of a package location
Definition: Constants.f90:50
integer(i4b), parameter lenvarname
maximum length of a variable name
Definition: Constants.f90:17
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
integer(i4b), parameter maxcharlen
maximum length of char string
Definition: Constants.f90:47
integer(i4b), parameter lenbudtxt
maximum length of a budget component names
Definition: Constants.f90:37
subroutine, public assign_iounit(iounit, errunit, description)
@ brief assign io 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 simulation methods.
Definition: Sim.f90:10
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
subroutine, public table_cr(this, name, title)
Definition: Table.f90:87
real(dp), pointer, public pertim
time relative to start of stress period
Definition: tdis.f90:33
real(dp), pointer, public totim
time relative to start of simulation
Definition: tdis.f90:35
integer(i4b), pointer, public kstp
current time step number
Definition: tdis.f90:27
integer(i4b), pointer, public kper
current stress period number
Definition: tdis.f90:26
real(dp), pointer, public delt
length of the current time step
Definition: tdis.f90:32
subroutine mvt_setup_outputtab(this)
Set up the mover-for-transport output table.
Definition: tsp-mvt.f90:820
subroutine mvt_scan_mvrbudobj(this)
Determine max number of packages in use.
Definition: tsp-mvt.f90:776
subroutine set_pointer_mvrbudobj(this, mvrbudobj)
@ brief Set pointer to mvrbudobj
Definition: tsp-mvt.f90:190
subroutine, public mvt_cr(mvt, name_model, inunit, iout, fmi1, eqnsclfac, depvartype, gwfmodelname1, gwfmodelname2, fmi2)
Definition: tsp-mvt.f90:85
subroutine mvt_bd(this)
Write mover terms to listing file.
Definition: tsp-mvt.f90:403
subroutine mvt_fill_mvrterm(this, cnew1, cnew2)
Fill mvrterm with provider concentration and flow for each budget term.
Definition: tsp-mvt.f90:253
subroutine mvt_fill_budobj(this)
Copy mover-for-transport flow terms into thisbudobj.
Definition: tsp-mvt.f90:725
subroutine mvt_ot_saveflow(this, icbcfl, ibudfl)
Write mover budget terms.
Definition: tsp-mvt.f90:413
subroutine mvt_ot_bdsummary(this, ibudfl)
Write mover budget to listing file.
Definition: tsp-mvt.f90:451
subroutine mvt_rp(this)
Read and prepare mover transport object.
Definition: tsp-mvt.f90:208
subroutine mvt_update_qmfrommvr(this)
Assign mover transport mass into each receiver's qmfrommvr.
Definition: tsp-mvt.f90:309
subroutine mvt_cc(this, kiter, iend, icnvgmod, cpak, dpak)
Extra convergence check for mover.
Definition: tsp-mvt.f90:378
subroutine read_options(this)
Read mover-for-transport options block.
Definition: tsp-mvt.f90:592
subroutine mvt_setup_budobj(this)
Set up the budget object that stores all the mvr flows.
Definition: tsp-mvt.f90:671
subroutine mvt_print_outputtab(this)
Set up mover-for-transport output table.
Definition: tsp-mvt.f90:865
subroutine mvt_df(this, dis)
Define mover transport object.
Definition: tsp-mvt.f90:159
subroutine mvt_ar(this)
Allocate and read mover-for-transport information.
Definition: tsp-mvt.f90:198
subroutine mvt_fc(this, cnew1, cnew2)
Calculate coefficients and fill amat and rhs.
Definition: tsp-mvt.f90:241
subroutine mvt_da(this)
@ brief Deallocate memory
Definition: tsp-mvt.f90:515
subroutine mvt_ot_printflow(this, icbcfl, ibudfl)
Print mover flow table.
Definition: tsp-mvt.f90:437
subroutine mvt_init(this, name_model, inunit, iout, fmi1, eqnsclfac, depvartype, gwfmodelname1, gwfmodelname2, fmi2)
Create a new mover transport object.
Definition: tsp-mvt.f90:106
subroutine set_fmi(this, ibudterm, fmi, set_provider)
Definition: tsp-mvt.f90:345
subroutine allocate_scalars(this)
@ brief Allocate scalar variables for package
Definition: tsp-mvt.f90:570
Derived type for the Budget object.
Definition: Budget.f90:39
Type to store mover-transport flow and concentration for one budget term.
Definition: tsp-mvt.f90:28