MODFLOW 6  version 6.7.0.dev2
USGS Modular Hydrologic Model
tsp-ssm.f90
Go to the documentation of this file.
1 !> @brief This module contains the TspSsm Module
2 !!
3 !! This module contains the code for handling sources and sinks
4 !! associated with groundwater flow model stress packages.
5 !!
6 !! todo: need observations for SSM terms
7 !<
9 
10  use kindmodule, only: dp, i4b, lgp
15  use simvariablesmodule, only: errmsg
17  use basedismodule, only: disbasetype
18  use tspfmimodule, only: tspfmitype
20  use tablemodule, only: tabletype, table_cr
21  use tspspcmodule, only: tspspctype
23 
24  implicit none
25  public :: tspssmtype
26  public :: ssm_cr
27 
28  character(len=LENFTYPE) :: ftype = 'SSM'
29  character(len=LENPACKAGENAME) :: text = ' SOURCE-SINK MIX'
30 
31  !> @brief Derived type for the SSM Package
32  !!
33  !! This derived type corresponds to the SSM Package, which adds
34  !! the effects of groundwater sources and sinks to the solute transport
35  !! equation.
36  !<
37  type, extends(numericalpackagetype) :: tspssmtype
38 
39  integer(I4B), pointer :: nbound !< total number of flow boundaries in this time step
40  integer(I4B), dimension(:), pointer, contiguous :: isrctype => null() !< source type 0 is unspecified, 1 is aux, 2 is auxmixed, 3 is ssmi, 4 is ssmimixed
41  integer(I4B), dimension(:), pointer, contiguous :: iauxpak => null() !< aux col for concentration/temperature
42  integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound
43  real(dp), dimension(:), pointer, contiguous :: cnew => null() !< pointer to gwt%x
44  type(tspfmitype), pointer :: fmi => null() !< pointer to fmi object
45  type(tabletype), pointer :: outputtab => null() !< output table object
46  type(tspspctype), dimension(:), pointer :: ssmivec => null() !< array of stress package concentration or temperature objects
47  real(dp), pointer :: eqnsclfac => null() !< governing equation scale factor; =1. for solute; =rhow*cpw for energy
48  character(len=LENVARNAME) :: depvartype = ''
49 
50  contains
51 
52  procedure :: ssm_df
53  procedure :: ssm_ar
54  procedure :: ssm_rp
55  procedure :: ssm_ad
56  procedure :: ssm_fc
57  procedure :: ssm_cq
58  procedure :: ssm_bd
59  procedure :: ssm_ot_flow
60  procedure :: ssm_da
61  procedure :: allocate_scalars
62  procedure, private :: ssm_term
63  procedure, private :: allocate_arrays
64  procedure, private :: source_options
65  procedure, private :: source_sources
66  procedure, private :: source_fileinput
67  procedure, private :: pak_setup_outputtab
68  procedure, private :: set_iauxpak
69  procedure, private :: set_ssmivec
70  procedure, private :: get_ssm_conc
71 
72  end type tspssmtype
73 
74 contains
75 
76  !> @ brief Create a new SSM package
77  !!
78  !! Create a new SSM package by defining names, allocating scalars
79  !<
80  subroutine ssm_cr(ssmobj, name_model, input_mempath, inunit, iout, fmi, &
81  eqnsclfac, depvartype)
82  ! -- dummy
83  type(tspssmtype), pointer :: ssmobj !< TspSsmType object
84  character(len=*), intent(in) :: name_model !< name of the model
85  character(len=*), intent(in) :: input_mempath !< input mempath
86  integer(I4B), intent(in) :: inunit !< fortran unit for input
87  integer(I4B), intent(in) :: iout !< fortran unit for output
88  type(tspfmitype), intent(in), target :: fmi !< Transport FMI package
89  real(dp), intent(in), pointer :: eqnsclfac !< governing equation scale factor
90  character(len=LENVARNAME), intent(in) :: depvartype !< dependent variable type ('concentration' or 'temperature')
91  !
92  ! -- Create the object
93  allocate (ssmobj)
94  !
95  ! -- create name and memory path
96  call ssmobj%set_names(1, name_model, 'SSM', 'SSM', input_mempath)
97  !
98  ! -- Allocate scalars
99  call ssmobj%allocate_scalars()
100  !
101  ! -- Set variables
102  ssmobj%inunit = inunit
103  ssmobj%iout = iout
104  ssmobj%fmi => fmi
105  ssmobj%eqnsclfac => eqnsclfac
106  !
107  ! -- Store pointer to labels associated with the current model so that the
108  ! package has access to the corresponding dependent variable type
109  ssmobj%depvartype = depvartype
110  end subroutine ssm_cr
111 
112  !> @ brief Define SSM Package
113  !!
114  !! This routine is called from gwt_df(), but does not do anything because
115  !! df is typically used to set up dimensions. For the ssm package, the
116  !! total number of ssm entries is defined by the flow model.
117  !<
118  subroutine ssm_df(this)
119  ! -- modules
121  ! -- dummy
122  class(tspssmtype) :: this !< TspSsmType object
123  end subroutine ssm_df
124 
125  !> @ brief Allocate and read SSM Package
126  !!
127  !! This routine is called from gwt_ar(). It allocates arrays, reads
128  !! options and data, and sets up the output table.
129  !<
130  subroutine ssm_ar(this, dis, ibound, cnew)
131  ! -- modules
133  ! -- dummy
134  class(tspssmtype) :: this !< TspSsmType object
135  class(disbasetype), pointer, intent(in) :: dis !< discretization package
136  integer(I4B), dimension(:), pointer, contiguous :: ibound !< GWT model ibound
137  real(DP), dimension(:), pointer, contiguous :: cnew !< GWT model dependent variable
138  ! -- formats
139  character(len=*), parameter :: fmtssm = &
140  "(1x,/1x,'SSM -- SOURCE-SINK MIXING PACKAGE, VERSION 1, 8/25/2017', &
141  &' INPUT READ FROM MEMPATH: ', A, //)"
142  !
143  ! -- print a message identifying the storage package.
144  write (this%iout, fmtssm) this%input_mempath
145  !
146  ! -- store pointers to arguments that were passed in
147  this%dis => dis
148  this%ibound => ibound
149  this%cnew => cnew
150  !
151  ! -- Check to make sure that there are flow packages
152  if (this%fmi%nflowpack == 0) then
153  write (errmsg, '(a)') 'SSM package does not detect any boundary flows &
154  &that require SSM terms. Activate GWF-GWT (or &
155  &GWF-GWE, as appropriate) exchange or activate &
156  &FMI package and provide a budget file that &
157  &contains boundary flows. If no boundary flows &
158  &are present in corresponding GWF model then this &
159  &SSM package should be removed.'
160  call store_error(errmsg)
161  call store_error_filename(this%input_fname)
162  end if
163  !
164  ! -- Allocate arrays
165  call this%allocate_arrays()
166  !
167  ! -- read ssm options
168  call this%source_options()
169  !
170  ! -- read data blocks
171  call this%source_sources()
172  call this%source_fileinput()
173  !
174  ! -- setup the output table
175  call this%pak_setup_outputtab()
176  end subroutine ssm_ar
177 
178  !> @ brief Read and prepare this SSM Package
179  !!
180  !! This routine is called from gwt_rp(). It is called at the beginning of
181  !! each stress period. If any SPC input files are used to provide source
182  !! and sink concentrations (or temperatures), then period blocks for the
183  !! current stress period are read.
184  !<
185  subroutine ssm_rp(this)
186  ! -- dummy
187  class(tspssmtype) :: this !< TspSsmType object
188  ! -- local
189  integer(I4B) :: ip
190  type(tspspctype), pointer :: ssmiptr
191  ! -- formats
192  !
193  ! -- Call the rp method on any ssm input files
194  do ip = 1, this%fmi%nflowpack
195  if (this%fmi%iatp(ip) /= 0) cycle
196  if (this%isrctype(ip) == 3 .or. this%isrctype(ip) == 4) then
197  ssmiptr => this%ssmivec(ip)
198  call ssmiptr%spc_rp()
199  end if
200  end do
201  end subroutine ssm_rp
202 
203  !> @ brief Advance the SSM Package
204  !!
205  !! This routine is called from gwt_ad(). It is called at the beginning of
206  !! each time step. The total number of flow boundaries is counted and stored
207  !! in this%nbound. Also, if any SPC input files are used to provide source
208  !! and sink concentrations (or temperatures) and time series are referenced
209  !! in those files, then ssm concenrations must be interpolated for the time
210  !! step.
211  !<
212  subroutine ssm_ad(this)
213  ! -- dummy
214  class(tspssmtype) :: this !< TspSsmType object
215  ! -- local
216  integer(I4B) :: ip
217  type(tspspctype), pointer :: ssmiptr
218  integer(I4B) :: i
219  integer(I4B) :: node
220  !
221  ! -- Calculate total number of existing flow boundaries. It is possible
222  ! that a node may equal zero. In this case, the bound should be
223  ! skipped and not written to ssm output.
224  this%nbound = 0
225  do ip = 1, this%fmi%nflowpack
226  if (this%fmi%iatp(ip) /= 0) cycle
227  do i = 1, this%fmi%gwfpackages(ip)%nbound
228  node = this%fmi%gwfpackages(ip)%nodelist(i)
229  if (node > 0) then
230  this%nbound = this%nbound + 1
231  end if
232  end do
233  end do
234  !
235  ! -- Call the ad method on any ssm input files so that values for
236  ! time-series are interpolated
237  do ip = 1, this%fmi%nflowpack
238  if (this%fmi%iatp(ip) /= 0) cycle
239  if (this%isrctype(ip) == 3 .or. this%isrctype(ip) == 4) then
240  ssmiptr => this%ssmivec(ip)
241  call ssmiptr%spc_ad(this%fmi%gwfpackages(ip)%nbound, &
242  this%fmi%gwfpackages(ip)%budtxt)
243  end if
244  end do
245  end subroutine ssm_ad
246 
247  !> @ brief Calculate the SSM mass flow rate and hcof and rhs values
248  !!
249  !! This is the primary SSM routine that calculates the matrix coefficient
250  !! and right-hand-side value for any package and package entry. It returns
251  !! several different optional variables that are used throughout this
252  !! package to update matrix terms, budget calculations, and output tables.
253  !<
254  subroutine ssm_term(this, ipackage, ientry, rrate, rhsval, hcofval, &
255  cssm, qssm)
256  ! -- dummy
257  class(tspssmtype) :: this !< TspSsmType
258  integer(I4B), intent(in) :: ipackage !< package number
259  integer(I4B), intent(in) :: ientry !< bound number
260  real(DP), intent(out), optional :: rrate !< calculated mass flow rate
261  real(DP), intent(out), optional :: rhsval !< calculated rhs value
262  real(DP), intent(out), optional :: hcofval !< calculated hcof value
263  real(DP), intent(out), optional :: cssm !< calculated source concentration/temperature depending on flow direction
264  real(DP), intent(out), optional :: qssm !< water flow rate into model cell from boundary package
265  ! -- local
266  logical(LGP) :: lauxmixed
267  integer(I4B) :: n
268  integer(I4B) :: nbound_flow
269  real(DP) :: qbnd
270  real(DP) :: ctmp
271  real(DP) :: omega
272  real(DP) :: hcoftmp
273  real(DP) :: rhstmp
274  !
275  ! -- retrieve node number, qbnd and iauxpos
276  hcoftmp = dzero
277  rhstmp = dzero
278  ctmp = dzero
279  qbnd = dzero
280  nbound_flow = this%fmi%gwfpackages(ipackage)%nbound
281  n = this%fmi%gwfpackages(ipackage)%nodelist(ientry)
282  !
283  ! -- If cell is active (ibound > 0) then calculate values
284  if (this%ibound(n) > 0) then
285  !
286  ! -- retrieve qbnd and iauxpos
287  qbnd = this%fmi%gwfpackages(ipackage)%get_flow(ientry)
288  call this%get_ssm_conc(ipackage, ientry, nbound_flow, ctmp, lauxmixed)
289  !
290  ! -- assign values for hcoftmp, rhstmp, and ctmp for subsequent assignment
291  ! of hcof, rhs, and rate
292  if (.not. lauxmixed) then
293  !
294  ! -- If qbnd is positive, then concentration (or temperature) represents
295  ! the inflow concentration (or temperature). If qbnd is negative,
296  ! then the outflow concentration (or temperature) is set equal to the
297  ! simulated cell's concentration (or temperature).
298  if (qbnd >= dzero) then
299  omega = dzero ! rhs
300  else
301  ctmp = this%cnew(n)
302  omega = done ! lhs
303  if (ctmp < dzero) then
304  omega = dzero ! concentration/temperature is negative, so set mass flux to zero
305  end if
306  end if
307  else
308  !
309  ! -- lauxmixed value indicates that this is a mixed sink type where
310  ! the concentration (or temperature) value represents the injected
311  ! concentration (or temperature) if qbnd is positive. If qbnd is
312  ! negative, then the withdrawn water is equal to the minimum of the
313  ! aux concentration (or temperature) and the cell concentration
314  ! (or temperature).
315  if (qbnd >= dzero) then
316  omega = dzero ! rhs (ctmp is aux value)
317  else
318  if (ctmp < this%cnew(n)) then
319  omega = dzero ! rhs (ctmp is aux value)
320  else
321  omega = done ! lhs (ctmp is cell concentration)
322  ctmp = this%cnew(n)
323  end if
324  end if
325  end if
326  !
327  ! -- Add terms based on qbnd sign
328  if (qbnd <= dzero) then
329  hcoftmp = qbnd * omega * this%eqnsclfac
330  else
331  rhstmp = -qbnd * ctmp * (done - omega) * this%eqnsclfac
332  end if
333  !
334  ! -- end of active ibound
335  end if
336  !
337  ! -- set requested values
338  if (present(hcofval)) hcofval = hcoftmp
339  if (present(rhsval)) rhsval = rhstmp
340  if (present(rrate)) rrate = hcoftmp * ctmp - rhstmp
341  if (present(cssm)) cssm = ctmp
342  if (present(qssm)) qssm = qbnd
343  end subroutine ssm_term
344 
345  !> @ brief Provide bound concentration (or temperature) and mixed flag
346  !!
347  !! SSM concentrations and temperatures can be provided in auxiliary variables
348  !! or through separate SPC files. If not provided, the default
349  !! concentration (or temperature) is zero. This single routine provides
350  !! the SSM bound concentration (or temperature) based on these different
351  !! approaches. The mixed flag indicates whether or not the boundary as a
352  !! mixed type.
353  !<
354  subroutine get_ssm_conc(this, ipackage, ientry, nbound_flow, conc, &
355  lauxmixed)
356  ! -- dummy
357  class(tspssmtype) :: this !< TspSsmType
358  integer(I4B), intent(in) :: ipackage !< package number
359  integer(I4B), intent(in) :: ientry !< bound number
360  integer(I4B), intent(in) :: nbound_flow !< size of flow package bound list
361  real(DP), intent(out) :: conc !< user-specified concentration/temperature for this bound
362  logical(LGP), intent(out) :: lauxmixed !< user-specified flag for marking this as a mixed boundary
363  ! -- local
364  integer(I4B) :: isrctype
365  integer(I4B) :: iauxpos
366  !
367  conc = dzero
368  lauxmixed = .false.
369  isrctype = this%isrctype(ipackage)
370  !
371  select case (isrctype)
372  case (1, 2)
373  iauxpos = this%iauxpak(ipackage)
374  conc = this%fmi%gwfpackages(ipackage)%auxvar(iauxpos, ientry)
375  if (isrctype == 2) lauxmixed = .true.
376  case (3, 4)
377  conc = this%ssmivec(ipackage)%get_value(ientry, nbound_flow)
378  if (isrctype == 4) lauxmixed = .true.
379  end select
380  end subroutine get_ssm_conc
381 
382  !> @ brief Fill coefficients
383  !!
384  !! This routine adds the effects of the SSM to the matrix equations by
385  !! updating the a matrix and right-hand side vector.
386  !<
387  subroutine ssm_fc(this, matrix_sln, idxglo, rhs)
388  ! -- dummy
389  class(tspssmtype) :: this
390  class(matrixbasetype), pointer :: matrix_sln
391  integer(I4B), intent(in), dimension(:) :: idxglo
392  real(DP), intent(inout), dimension(:) :: rhs
393  ! -- local
394  integer(I4B) :: ip
395  integer(I4B) :: i
396  integer(I4B) :: n
397  integer(I4B) :: idiag
398  integer(I4B) :: nflowpack
399  integer(I4B) :: nbound
400  real(DP) :: hcofval
401  real(DP) :: rhsval
402  !
403  ! -- do for each flow package
404  nflowpack = this%fmi%nflowpack
405  do ip = 1, nflowpack
406  if (this%fmi%iatp(ip) /= 0) cycle
407  !
408  ! -- do for each entry in package (ip)
409  nbound = this%fmi%gwfpackages(ip)%nbound
410  do i = 1, nbound
411  n = this%fmi%gwfpackages(ip)%nodelist(i)
412  if (n <= 0) cycle
413  call this%ssm_term(ip, i, rhsval=rhsval, hcofval=hcofval)
414  idiag = idxglo(this%dis%con%ia(n))
415  call matrix_sln%add_value_pos(idiag, hcofval)
416  rhs(n) = rhs(n) + rhsval
417  !
418  end do
419  !
420  end do
421  end subroutine ssm_fc
422 
423  !> @ brief Calculate flow
424  !!
425  !! Calculate the resulting mass flow between the boundary and the connected
426  !! GWT/GWE model cell. Update the diagonal position of the flowja array so
427  !! that it ultimately contains the solute balance residual.
428  !<
429  subroutine ssm_cq(this, flowja)
430  ! -- dummy
431  class(tspssmtype) :: this !< TspSsmType object
432  real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow across each face in the model grid
433  ! -- local
434  integer(I4B) :: ip
435  integer(I4B) :: i
436  integer(I4B) :: n
437  integer(I4B) :: idiag
438  real(DP) :: rate
439  !
440  ! -- do for each flow package
441  do ip = 1, this%fmi%nflowpack
442  !
443  ! -- cycle if package is being managed as an advanced package
444  if (this%fmi%iatp(ip) /= 0) cycle
445  !
446  ! -- do for each boundary
447  do i = 1, this%fmi%gwfpackages(ip)%nbound
448  n = this%fmi%gwfpackages(ip)%nodelist(i)
449  if (n <= 0) cycle
450  call this%ssm_term(ip, i, rrate=rate)
451  idiag = this%dis%con%ia(n)
452  flowja(idiag) = flowja(idiag) + rate
453  !
454  end do
455  !
456  end do
457  end subroutine ssm_cq
458 
459  !> @ brief Calculate the global SSM budget terms
460  !!
461  !! Calculate the global SSM budget terms using separate in and out entries
462  !! for each flow package.
463  !<
464  subroutine ssm_bd(this, isuppress_output, model_budget)
465  ! -- modules
466  use tdismodule, only: delt
467  use budgetmodule, only: budgettype
468  ! -- dummy
469  class(tspssmtype) :: this !< TspSsmType object
470  integer(I4B), intent(in) :: isuppress_output !< flag to suppress output
471  type(budgettype), intent(inout) :: model_budget !< budget object for the GWT model
472  ! -- local
473  character(len=LENBUDROWLABEL) :: rowlabel
474  integer(I4B) :: ip
475  integer(I4B) :: i
476  integer(I4B) :: n
477  real(DP) :: rate
478  real(DP) :: rin
479  real(DP) :: rout
480  !
481  ! -- do for each flow package, unless it is being handled by an advanced
482  ! transport package
483  do ip = 1, this%fmi%nflowpack
484  !
485  ! -- cycle if package is being managed as an advanced package
486  if (this%fmi%iatp(ip) /= 0) cycle
487  !
488  ! -- Initialize the rate accumulators
489  rin = dzero
490  rout = dzero
491  !
492  ! -- do for each boundary
493  do i = 1, this%fmi%gwfpackages(ip)%nbound
494  n = this%fmi%gwfpackages(ip)%nodelist(i)
495  if (n <= 0) cycle
496  call this%ssm_term(ip, i, rrate=rate)
497  if (rate < dzero) then
498  rout = rout - rate
499  else
500  rin = rin + rate
501  end if
502  !
503  end do
504  !
505  rowlabel = 'SSM_'//adjustl(trim(this%fmi%flowpacknamearray(ip)))
506  call model_budget%addentry(rin, rout, delt, &
507  this%fmi%gwfpackages(ip)%budtxt, &
508  isuppress_output, rowlabel=rowlabel)
509  end do
510  end subroutine ssm_bd
511 
512  !> @ brief Output flows
513  !!
514  !! Based on user-specified controls, print SSM mass flow rates to the GWT
515  !! listing file and/or write the SSM mass flow rates to the GWT binary
516  !! budget file.
517  !<
518  subroutine ssm_ot_flow(this, icbcfl, ibudfl, icbcun)
519  ! -- modules
520  use tdismodule, only: kstp, kper
522  ! -- dummy
523  class(tspssmtype) :: this !< TspSsmType object
524  integer(I4B), intent(in) :: icbcfl !< flag for writing binary budget terms
525  integer(I4B), intent(in) :: ibudfl !< flag for printing budget terms to list file
526  integer(I4B), intent(in) :: icbcun !< fortran unit number for binary budget file
527  ! -- local
528  character(len=LINELENGTH) :: title
529  integer(I4B) :: node, nodeu
530  character(len=20) :: nodestr
531  integer(I4B) :: maxrows
532  integer(I4B) :: ip
533  integer(I4B) :: i, n2, ibinun
534  real(DP) :: rrate
535  real(DP) :: qssm
536  real(DP) :: cssm
537  integer(I4B) :: naux
538  real(DP), dimension(0) :: auxrow
539  character(len=LENAUXNAME), dimension(0) :: auxname
540  ! -- for observations
541  character(len=LENBOUNDNAME) :: bname
542  ! -- formats
543  character(len=*), parameter :: fmttkk = &
544  &"(1X,/1X,A,' PERIOD ',I0,' STEP ',I0)"
545  !
546  ! -- initialize
547  naux = 0
548  maxrows = 0
549  if (ibudfl /= 0 .and. this%iprflow /= 0) then
550  call this%outputtab%set_kstpkper(kstp, kper)
551  do ip = 1, this%fmi%nflowpack
552  if (this%fmi%iatp(ip) /= 0) cycle
553  !
554  ! -- do for each boundary
555  do i = 1, this%fmi%gwfpackages(ip)%nbound
556  node = this%fmi%gwfpackages(ip)%nodelist(i)
557  if (node > 0) then
558  maxrows = maxrows + 1
559  end if
560  end do
561  end do
562  if (maxrows > 0) then
563  call this%outputtab%set_maxbound(maxrows)
564  end if
565  title = 'SSM PACKAGE ('//trim(this%packName)// &
566  ') FLOW RATES'
567  call this%outputtab%set_title(title)
568  end if
569  !
570  ! -- Set unit number for binary output
571  if (this%ipakcb < 0) then
572  ibinun = icbcun
573  else if (this%ipakcb == 0) then
574  ibinun = 0
575  else
576  ibinun = this%ipakcb
577  end if
578  if (icbcfl == 0) ibinun = 0
579  !
580  ! -- If cell-by-cell flows will be saved as a list, write header.
581  if (ibinun /= 0) then
582  call this%dis%record_srcdst_list_header(text, this%name_model, &
583  this%name_model, this%name_model, &
584  this%packName, naux, auxname, &
585  ibinun, this%nbound, this%iout)
586  end if
587  !
588  ! -- If no boundaries, skip flow calculations.
589  if (this%nbound > 0) then
590  !
591  ! -- Loop through each boundary calculating flow.
592  do ip = 1, this%fmi%nflowpack
593  if (this%fmi%iatp(ip) /= 0) cycle
594  !
595  ! -- do for each boundary
596  do i = 1, this%fmi%gwfpackages(ip)%nbound
597  !
598  ! -- Calculate rate for this entry
599  node = this%fmi%gwfpackages(ip)%nodelist(i)
600  if (node <= 0) cycle
601  call this%ssm_term(ip, i, rrate=rrate, qssm=qssm, cssm=cssm)
602  !
603  ! -- Print the individual rates if the budget is being printed
604  ! and PRINT_FLOWS was specified (this%iprflow<0)
605  if (ibudfl /= 0) then
606  if (this%iprflow /= 0) then
607  !
608  ! -- set nodestr and write outputtab table
609  nodeu = this%dis%get_nodeuser(node)
610  call this%dis%nodeu_to_string(nodeu, nodestr)
611  bname = this%fmi%gwfpackages(ip)%name
612  call this%outputtab%add_term(i)
613  call this%outputtab%add_term(trim(adjustl(nodestr)))
614  call this%outputtab%add_term(qssm)
615  call this%outputtab%add_term(cssm)
616  call this%outputtab%add_term(rrate)
617  call this%outputtab%add_term(bname)
618  end if
619  end if
620  !
621  ! -- If saving cell-by-cell flows in list, write flow
622  if (ibinun /= 0) then
623  n2 = i
624  call this%dis%record_mf6_list_entry(ibinun, node, n2, rrate, &
625  naux, auxrow, &
626  olconv2=.false.)
627  end if
628  !
629  end do
630  !
631  end do
632  end if
633  if (ibudfl /= 0) then
634  if (this%iprflow /= 0) then
635  write (this%iout, '(1x)')
636  end if
637  end if
638  end subroutine ssm_ot_flow
639 
640  !> @ brief Deallocate
641  !!
642  !! Deallocate the memory associated with this derived type
643  !<
644  subroutine ssm_da(this)
645  ! -- modules
647  ! -- dummy
648  class(tspssmtype) :: this !< TspSsmType object
649  ! -- local
650  integer(I4B) :: ip
651  type(tspspctype), pointer :: ssmiptr
652  !
653  ! -- Deallocate the ssmi objects if package was active
654  if (this%inunit > 0) then
655  do ip = 1, size(this%ssmivec)
656  if (this%isrctype(ip) == 3 .or. this%isrctype(ip) == 4) then
657  ssmiptr => this%ssmivec(ip)
658  call ssmiptr%spc_da()
659  end if
660  end do
661  deallocate (this%ssmivec)
662  end if
663  !
664  ! -- Deallocate arrays if package was active
665  if (this%inunit > 0) then
666  call mem_deallocate(this%iauxpak)
667  call mem_deallocate(this%isrctype)
668  this%ibound => null()
669  this%fmi => null()
670  end if
671  !
672  ! -- output table object
673  if (associated(this%outputtab)) then
674  call this%outputtab%table_da()
675  deallocate (this%outputtab)
676  nullify (this%outputtab)
677  end if
678  !
679  ! -- Scalars
680  call mem_deallocate(this%nbound)
681  !
682  ! -- deallocate parent
683  call this%NumericalPackageType%da()
684  end subroutine ssm_da
685 
686  !> @ brief Allocate scalars
687  !!
688  !! Allocate scalar variables for this derived type
689  !<
690  subroutine allocate_scalars(this)
691  ! -- modules
693  ! -- dummy
694  class(tspssmtype) :: this !< TspSsmType object
695  !
696  ! -- allocate scalars in NumericalPackageType
697  call this%NumericalPackageType%allocate_scalars()
698  !
699  ! -- Allocate
700  call mem_allocate(this%nbound, 'NBOUND', this%memoryPath)
701  !
702  ! -- Initialize
703  this%nbound = 0
704  end subroutine allocate_scalars
705 
706  !> @ brief Allocate arrays
707  !!
708  !! Allocate array variables for this derived type
709  !<
710  subroutine allocate_arrays(this)
711  ! -- modules
713  ! -- dummy
714  class(tspssmtype) :: this !< TspSsmType object
715  ! -- local
716  integer(I4B) :: nflowpack
717  integer(I4B) :: i
718  !
719  ! -- Allocate
720  nflowpack = this%fmi%nflowpack
721  call mem_allocate(this%iauxpak, nflowpack, 'IAUXPAK', this%memoryPath)
722  call mem_allocate(this%isrctype, nflowpack, 'ISRCTYPE', this%memoryPath)
723  !
724  ! -- Initialize
725  do i = 1, nflowpack
726  this%iauxpak(i) = 0
727  this%isrctype(i) = 0
728  end do
729  !
730  ! -- Allocate the ssmivec array
731  allocate (this%ssmivec(nflowpack))
732  end subroutine allocate_arrays
733 
734  !> @brief Source input options
735  !<
736  subroutine source_options(this)
737  ! -- modules
738  !use KindModule, only: LGP
741  ! -- dummy
742  class(tspssmtype) :: this
743  ! -- locals
744  type(gwtssmparamfoundtype) :: found
745  ! -- formats
746  character(len=*), parameter :: fmtiprflow = &
747  "(4x,'SSM FLOW INFORMATION WILL BE PRINTED TO LISTING FILE &
748  &WHENEVER ICBCFL IS NOT ZERO.')"
749  character(len=*), parameter :: fmtisvflow = &
750  "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE &
751  &WHENEVER ICBCFL IS NOT ZERO.')"
752  !
753  ! -- update defaults with idm sourced values
754  call mem_set_value(this%iprflow, 'PRINT_FLOWS', this%input_mempath, &
755  found%print_flows)
756  call mem_set_value(this%ipakcb, 'SAVE_FLOWS', this%input_mempath, &
757  found%save_flows)
758 
759  if (found%save_flows) this%ipakcb = -1
760 
761  ! log options
762  write (this%iout, '(1x,a)') 'PROCESSING SSM OPTIONS'
763  if (found%print_flows) write (this%iout, fmtiprflow)
764  if (found%save_flows) write (this%iout, fmtisvflow)
765  write (this%iout, '(1x,a)') 'END OF SSM OPTIONS'
766  end subroutine source_options
767 
768  !> @brief Source sources input block
769  !<
770  subroutine source_sources(this)
771  ! -- modules
772  !use KindModule, only: LGP
775  ! -- dummy
776  class(tspssmtype) :: this
777  ! -- locals
778  type(characterstringtype), dimension(:), pointer, &
779  contiguous :: pnames, srctypes, auxnames
780  character(len=LINELENGTH) :: pname, srctype, auxname
781  integer(I4B) :: n, ip
782  logical(LGP) :: found
783  ! -- formats
784 
785  ! set pointers to input context
786  call mem_setptr(pnames, 'PNAME_SOURCES', this%input_mempath)
787  call mem_setptr(srctypes, 'SRCTYPE', this%input_mempath)
788  call mem_setptr(auxnames, 'AUXNAME', this%input_mempath)
789 
790  write (this%iout, '(/1x,a)') 'PROCESSING SSM SOURCES'
791  do n = 1, size(pnames)
792 
793  pname = pnames(n)
794  srctype = srctypes(n)
795  auxname = auxnames(n)
796  found = .false.
797 
798  do ip = 1, this%fmi%nflowpack
799  if (trim(adjustl(this%fmi%gwfpackages(ip)%name)) == pname) then
800  found = .true.
801  exit
802  end if
803  end do
804 
805  if (.not. found) then
806  write (errmsg, '(a,a)') 'Flow package cannot be found: ', &
807  trim(pname)
808  call store_error(errmsg)
809  cycle
810  end if
811 
812  ! -- Ensure package was not specified more than once in SOURCES block
813  if (this%isrctype(ip) /= 0) then
814  write (errmsg, '(a, a)') &
815  'A package cannot be specified more than once in the SSM SOURCES &
816  &block. The following package was specified more than once: ', &
817  trim(pname)
818  call store_error(errmsg)
819  cycle
820  end if
821 
822  if (srctype == 'AUX') then
823  this%isrctype(ip) = 1
824  write (this%iout, '(4x,a)') 'AUX SOURCE DETECTED.'
825  else if (srctype == 'AUXMIXED') then
826  this%isrctype(ip) = 2
827  write (this%iout, '(4x,a)') 'AUXMIXED SOURCE DETECTED.'
828  else
829  write (errmsg, '(a, a)') &
830  'SRCTYPE must be AUX or AUXMIXED. Found: ', trim(srctype)
831  call store_error(errmsg)
832  cycle
833  end if
834 
835  ! -- Find and store the auxiliary column
836  call this%set_iauxpak(ip, srctype, auxname)
837  end do
838  write (this%iout, '(1x,a)') 'END PROCESSING SSM SOURCES'
839 
840  ! -- terminate if errors
841  if (count_errors() > 0) then
842  call store_error_filename(this%input_fname)
843  end if
844  end subroutine source_sources
845 
846  !> @brief Source fileinput input block
847  !!
848  !! Initialize an SPC input file reader for each input entry.
849  !<
850  subroutine source_fileinput(this)
851  ! -- modules
852  !use KindModule, only: LGP
855  ! -- dummy
856  class(tspssmtype) :: this
857  ! -- locals
858  type(characterstringtype), dimension(:), pointer, &
859  contiguous :: pnames, ftypes, iotypes, fnames, conditions
860  character(len=LINELENGTH) :: pname, ftype, iotype, fname, condition
861  integer(I4B) :: n, ip, isize
862  logical(LGP) :: found
863  ! -- formats
864 
865  call get_isize('PNAME', this%input_mempath, isize)
866  if (isize == -1) then
867  write (this%iout, '(/1x,a)') &
868  'OPTIONAL SSM FILEINPUT BLOCK INPUT NOT FOUND.'
869  return
870  end if
871 
872  ! set pointers to input context
873  call mem_setptr(pnames, 'PNAME', this%input_mempath)
874  call mem_setptr(ftypes, 'SPC6', this%input_mempath)
875  call mem_setptr(iotypes, 'FILEIN', this%input_mempath)
876  call mem_setptr(fnames, 'SPC6_FILENAME', this%input_mempath)
877  call mem_setptr(conditions, 'MIXED', this%input_mempath)
878 
879  write (this%iout, '(/1x,a)') 'PROCESSING SSM FILEINPUT'
880  do n = 1, size(pnames)
881 
882  pname = pnames(n)
883  ftype = ftypes(n)
884  iotype = iotypes(n)
885  fname = fnames(n)
886  condition = conditions(n)
887  found = .false.
888 
889  do ip = 1, this%fmi%nflowpack
890  if (trim(adjustl(this%fmi%gwfpackages(ip)%name)) == pname) then
891  found = .true.
892  exit
893  end if
894  end do
895 
896  if (.not. found) then
897  write (errmsg, '(a,a)') 'Flow package cannot be found: ', &
898  trim(pname)
899  call store_error(errmsg)
900  cycle
901  end if
902 
903  ! -- Ensure package was not specified more than once in SOURCES block
904  if (this%isrctype(ip) /= 0) then
905  write (errmsg, '(a, a)') &
906  'A package cannot be specified more than once in the SSM SOURCES &
907  &block. The following package was specified more than once: ', &
908  trim(pname)
909  call store_error(errmsg)
910  cycle
911  end if
912 
913  ! verify ftype
914  if (ftype == 'SPC6') then
915  write (this%iout, '(4x,a)') 'SPC6 SOURCE DETECTED:'
916  else
917  write (errmsg, '(a,a)') &
918  'SRCTYPE must be SPC6. Found: ', trim(ftype)
919  call store_error(errmsg)
920  cycle
921  end if
922 
923  ! verify iotype
924  if (iotype /= 'FILEIN') then
925  errmsg = 'SPC6 keyword must be followed by "FILEIN" '// &
926  'then by filename and optionally by <MIXED>.'
927  call store_error(errmsg)
928  cycle
929  end if
930 
931  ! -- Use set_ssmivec to read file name and set up
932  ! ssmi file object
933  call this%set_ssmivec(ip, pname, fname)
934 
935  if (condition == 'MIXED') then
936  this%isrctype(ip) = 4
937  write (this%iout, '(4x,a,a)') 'ASSIGNED MIXED SSM TYPE TO PACKAGE ', &
938  trim(pname)
939  else
940  this%isrctype(ip) = 3
941  end if
942  end do
943  write (this%iout, '(1x,a)') 'END PROCESSING SSM FILEINPUT'
944 
945  ! -- terminate if errors
946  if (count_errors() > 0) then
947  call store_error_filename(this%input_fname)
948  end if
949  end subroutine source_fileinput
950 
951  !> @ brief Set iauxpak array value for package ip
952  !!
953  !! The routine searches through the auxiliary names in package
954  !! ip and sets iauxpak to the column number corresponding to the
955  !! correct auxiliary column.
956  !<
957  subroutine set_iauxpak(this, ip, packname, auxname)
958  ! -- dummy
959  class(tspssmtype), intent(inout) :: this !< TspSsmType
960  integer(I4B), intent(in) :: ip !< package number
961  character(len=*), intent(in) :: packname !< name of package
962  character(len=*), intent(in) :: auxname !< name of aux
963  ! -- local
964  logical :: auxfound
965  integer(I4B) :: iaux
966  !
967  ! -- match package auxiliary
968  auxfound = .false.
969  do iaux = 1, this%fmi%gwfpackages(ip)%naux
970  if (trim(this%fmi%gwfpackages(ip)%auxname(iaux)) == &
971  trim(auxname)) then
972  auxfound = .true.
973  exit
974  end if
975  end do
976  if (.not. auxfound) then
977  write (errmsg, '(a, a)') &
978  'Auxiliary name cannot be found: ', trim(auxname)
979  call store_error(errmsg)
980  call store_error_filename(this%input_fname)
981  end if
982  !
983  ! -- set iauxpak and write message
984  this%iauxpak(ip) = iaux
985  write (this%iout, '(4x, a, i0, a, a)') 'USING AUX COLUMN ', &
986  iaux, ' IN PACKAGE ', trim(packname)
987  end subroutine set_iauxpak
988 
989  !> @ brief Set ssmivec array value for package ip
990  !!
991  !! This routine initializes the SPC input file.
992  !<
993  subroutine set_ssmivec(this, ip, packname, filename)
994  ! -- module
996  ! -- dummy
997  class(tspssmtype), intent(inout) :: this !< TspSsmType
998  integer(I4B), intent(in) :: ip !< package number
999  character(len=*), intent(in) :: packname !< name of package
1000  character(len=*), intent(in) :: filename !< package input file
1001  ! -- local
1002  type(tspspctype), pointer :: ssmiptr
1003  integer(I4B) :: inunit
1004  !
1005  ! -- open file
1006  inunit = getunit()
1007  call openfile(inunit, this%iout, filename, 'SPC', filstat_opt='OLD')
1008  !
1009  ! -- Create the SPC file object
1010  ssmiptr => this%ssmivec(ip)
1011  call ssmiptr%initialize(this%dis, ip, inunit, this%iout, this%name_model, &
1012  trim(packname), this%depvartype)
1013  !
1014  write (this%iout, '(4x, a, a, a, a, a)') 'USING SPC INPUT FILE ', &
1015  trim(filename), ' TO SET ', trim(this%depvartype), &
1016  'S FOR PACKAGE ', trim(packname)
1017  end subroutine set_ssmivec
1018 
1019  !> @ brief Setup the output table
1020  !!
1021  !! Setup the output table by creating the column headers.
1022  !<
1023  subroutine pak_setup_outputtab(this)
1024  ! -- dummy
1025  class(tspssmtype), intent(inout) :: this
1026  ! -- local
1027  character(len=LINELENGTH) :: title
1028  character(len=LINELENGTH) :: text
1029  integer(I4B) :: ntabcol
1030  !
1031  ! -- allocate and initialize the output table
1032  if (this%iprflow /= 0) then
1033  !
1034  ! -- dimension table
1035  ntabcol = 6
1036  !if (this%inamedbound > 0) then
1037  ! ntabcol = ntabcol + 1
1038  !end if
1039  !
1040  ! -- initialize the output table object
1041  title = 'SSM PACKAGE ('//trim(this%packName)// &
1042  ') FLOW RATES'
1043  call table_cr(this%outputtab, this%packName, title)
1044  call this%outputtab%table_df(1, ntabcol, this%iout, transient=.true.)
1045  text = 'NUMBER'
1046  call this%outputtab%initialize_column(text, 10, alignment=tabcenter)
1047  text = 'CELLID'
1048  call this%outputtab%initialize_column(text, 20, alignment=tableft)
1049  text = 'BOUND Q'
1050  call this%outputtab%initialize_column(text, 15, alignment=tabcenter)
1051  text = 'SSM CONC'
1052  call this%outputtab%initialize_column(text, 15, alignment=tabcenter)
1053  text = 'RATE'
1054  call this%outputtab%initialize_column(text, 15, alignment=tabcenter)
1055  text = 'PACKAGE NAME'
1056  call this%outputtab%initialize_column(text, 16, alignment=tabcenter)
1057  !if (this%inamedbound > 0) then
1058  ! text = 'NAME'
1059  ! call this%outputtab%initialize_column(text, 20, alignment=TABLEFT)
1060  !end if
1061  end if
1062  end subroutine pak_setup_outputtab
1063 
1064 end module tspssmmodule
This module contains the BudgetModule.
Definition: Budget.f90:20
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
@ tableft
left justified table column
Definition: Constants.f90:171
integer(i4b), parameter lenpackagename
maximum length of the package name
Definition: Constants.f90:23
integer(i4b), parameter lenbudrowlabel
maximum length of the rowlabel string used in the budget table
Definition: Constants.f90:25
integer(i4b), parameter lenvarname
maximum length of a variable name
Definition: Constants.f90:17
integer(i4b), parameter lenftype
maximum length of a package type (DIS, WEL, OC, etc.)
Definition: Constants.f90:39
integer(i4b), parameter lenauxname
maximum length of a aux variable
Definition: Constants.f90:35
integer(i4b), parameter lenboundname
maximum length of a bound name
Definition: Constants.f90:36
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
real(dp), parameter done
real constant 1
Definition: Constants.f90:76
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
subroutine, public get_isize(name, mem_path, isize)
@ brief Get the number of elements for this variable
This module contains the base numerical package type.
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_filename(filename, terminate)
Store the erroring file name.
Definition: Sim.f90:203
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string
subroutine, public table_cr(this, name, title)
Definition: Table.f90:87
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
real(dp), pointer, public delt
length of the current time step
Definition: tdis.f90:29
This module contains the TspSpc Module.
Definition: TspSpc.f90:7
This module contains the TspSsm Module.
Definition: tsp-ssm.f90:8
subroutine ssm_fc(this, matrix_sln, idxglo, rhs)
@ brief Fill coefficients
Definition: tsp-ssm.f90:388
subroutine ssm_ot_flow(this, icbcfl, ibudfl, icbcun)
@ brief Output flows
Definition: tsp-ssm.f90:519
subroutine source_sources(this)
Source sources input block.
Definition: tsp-ssm.f90:771
subroutine ssm_term(this, ipackage, ientry, rrate, rhsval, hcofval, cssm, qssm)
@ brief Calculate the SSM mass flow rate and hcof and rhs values
Definition: tsp-ssm.f90:256
subroutine allocate_scalars(this)
@ brief Allocate scalars
Definition: tsp-ssm.f90:691
subroutine ssm_cq(this, flowja)
@ brief Calculate flow
Definition: tsp-ssm.f90:430
subroutine source_fileinput(this)
Source fileinput input block.
Definition: tsp-ssm.f90:851
subroutine ssm_bd(this, isuppress_output, model_budget)
@ brief Calculate the global SSM budget terms
Definition: tsp-ssm.f90:465
subroutine source_options(this)
Source input options.
Definition: tsp-ssm.f90:737
subroutine pak_setup_outputtab(this)
@ brief Setup the output table
Definition: tsp-ssm.f90:1024
subroutine ssm_df(this)
@ brief Define SSM Package
Definition: tsp-ssm.f90:119
subroutine get_ssm_conc(this, ipackage, ientry, nbound_flow, conc, lauxmixed)
@ brief Provide bound concentration (or temperature) and mixed flag
Definition: tsp-ssm.f90:356
subroutine ssm_rp(this)
@ brief Read and prepare this SSM Package
Definition: tsp-ssm.f90:186
character(len=lenpackagename) text
Definition: tsp-ssm.f90:29
subroutine ssm_ar(this, dis, ibound, cnew)
@ brief Allocate and read SSM Package
Definition: tsp-ssm.f90:131
subroutine allocate_arrays(this)
@ brief Allocate arrays
Definition: tsp-ssm.f90:711
character(len=lenftype) ftype
Definition: tsp-ssm.f90:28
subroutine set_ssmivec(this, ip, packname, filename)
@ brief Set ssmivec array value for package ip
Definition: tsp-ssm.f90:994
subroutine ssm_ad(this)
@ brief Advance the SSM Package
Definition: tsp-ssm.f90:213
subroutine ssm_da(this)
@ brief Deallocate
Definition: tsp-ssm.f90:645
subroutine, public ssm_cr(ssmobj, name_model, input_mempath, inunit, iout, fmi, eqnsclfac, depvartype)
@ brief Create a new SSM package
Definition: tsp-ssm.f90:82
subroutine set_iauxpak(this, ip, packname, auxname)
@ brief Set iauxpak array value for package ip
Definition: tsp-ssm.f90:958
Derived type for the Budget object.
Definition: Budget.f90:39
This class is used to store a single deferred-length character string. It was designed to work in an ...
Definition: CharString.f90:23
Data for sharing among multiple packages. Originally read in from.
Derived type for managing SPC input.
Definition: TspSpc.f90:39
Derived type for the SSM Package.
Definition: tsp-ssm.f90:37