MODFLOW 6  version 6.8.0.dev0
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(this%fmi%gwfpackages(ip)%nbound, &
199  this%fmi%gwfpackages(ip)%budtxt)
200  end if
201  end do
202  end subroutine ssm_rp
203 
204  !> @ brief Advance the SSM Package
205  !!
206  !! This routine is called from gwt_ad(). It is called at the beginning of
207  !! each time step. The total number of flow boundaries is counted and stored
208  !! in this%nbound. Also, if any SPC input files are used to provide source
209  !! and sink concentrations (or temperatures) and time series are referenced
210  !! in those files, then ssm concenrations must be interpolated for the time
211  !! step.
212  !<
213  subroutine ssm_ad(this)
214  ! -- dummy
215  class(tspssmtype) :: this !< TspSsmType object
216  ! -- local
217  integer(I4B) :: ip
218  type(tspspctype), pointer :: ssmiptr
219  integer(I4B) :: i
220  integer(I4B) :: node
221  !
222  ! -- Calculate total number of existing flow boundaries. It is possible
223  ! that a node may equal zero. In this case, the bound should be
224  ! skipped and not written to ssm output.
225  this%nbound = 0
226  do ip = 1, this%fmi%nflowpack
227  if (this%fmi%iatp(ip) /= 0) cycle
228  do i = 1, this%fmi%gwfpackages(ip)%nbound
229  node = this%fmi%gwfpackages(ip)%nodelist(i)
230  if (node > 0) then
231  this%nbound = this%nbound + 1
232  end if
233  end do
234  end do
235  !
236  ! -- Call the ad method on any ssm input files so that values for
237  ! time-series are interpolated
238  do ip = 1, this%fmi%nflowpack
239  if (this%fmi%iatp(ip) /= 0) cycle
240  if (this%isrctype(ip) == 3 .or. this%isrctype(ip) == 4) then
241  ssmiptr => this%ssmivec(ip)
242  call ssmiptr%spc_ad(this%fmi%gwfpackages(ip)%nbound, &
243  this%fmi%gwfpackages(ip)%budtxt)
244  end if
245  end do
246  end subroutine ssm_ad
247 
248  !> @ brief Calculate the SSM mass flow rate and hcof and rhs values
249  !!
250  !! This is the primary SSM routine that calculates the matrix coefficient
251  !! and right-hand-side value for any package and package entry. It returns
252  !! several different optional variables that are used throughout this
253  !! package to update matrix terms, budget calculations, and output tables.
254  !<
255  subroutine ssm_term(this, ipackage, ientry, rrate, rhsval, hcofval, &
256  cssm, qssm)
257  ! -- dummy
258  class(tspssmtype) :: this !< TspSsmType
259  integer(I4B), intent(in) :: ipackage !< package number
260  integer(I4B), intent(in) :: ientry !< bound number
261  real(DP), intent(out), optional :: rrate !< calculated mass flow rate
262  real(DP), intent(out), optional :: rhsval !< calculated rhs value
263  real(DP), intent(out), optional :: hcofval !< calculated hcof value
264  real(DP), intent(out), optional :: cssm !< calculated source concentration/temperature depending on flow direction
265  real(DP), intent(out), optional :: qssm !< water flow rate into model cell from boundary package
266  ! -- local
267  logical(LGP) :: lauxmixed
268  integer(I4B) :: n
269  integer(I4B) :: nbound_flow
270  real(DP) :: qbnd
271  real(DP) :: ctmp
272  real(DP) :: omega
273  real(DP) :: hcoftmp
274  real(DP) :: rhstmp
275  !
276  ! -- retrieve node number, qbnd and iauxpos
277  hcoftmp = dzero
278  rhstmp = dzero
279  ctmp = dzero
280  qbnd = dzero
281  nbound_flow = this%fmi%gwfpackages(ipackage)%nbound
282  n = this%fmi%gwfpackages(ipackage)%nodelist(ientry)
283  !
284  ! -- If cell is active (ibound > 0) then calculate values
285  if (this%ibound(n) > 0) then
286  !
287  ! -- retrieve qbnd and iauxpos
288  qbnd = this%fmi%gwfpackages(ipackage)%get_flow(ientry)
289  call this%get_ssm_conc(ipackage, ientry, nbound_flow, ctmp, lauxmixed)
290  !
291  ! -- assign values for hcoftmp, rhstmp, and ctmp for subsequent assignment
292  ! of hcof, rhs, and rate
293  if (.not. lauxmixed) then
294  !
295  ! -- If qbnd is positive, then concentration (or temperature) represents
296  ! the inflow concentration (or temperature). If qbnd is negative,
297  ! then the outflow concentration (or temperature) is set equal to the
298  ! simulated cell's concentration (or temperature).
299  if (qbnd >= dzero) then
300  omega = dzero ! rhs
301  else
302  ctmp = this%cnew(n)
303  omega = done ! lhs
304  if (ctmp < dzero) then
305  omega = dzero ! concentration/temperature is negative, so set mass flux to zero
306  end if
307  end if
308  else
309  !
310  ! -- lauxmixed value indicates that this is a mixed sink type where
311  ! the concentration (or temperature) value represents the injected
312  ! concentration (or temperature) if qbnd is positive. If qbnd is
313  ! negative, then the withdrawn water is equal to the minimum of the
314  ! aux concentration (or temperature) and the cell concentration
315  ! (or temperature).
316  if (qbnd >= dzero) then
317  omega = dzero ! rhs (ctmp is aux value)
318  else
319  if (ctmp < this%cnew(n)) then
320  omega = dzero ! rhs (ctmp is aux value)
321  else
322  omega = done ! lhs (ctmp is cell concentration)
323  ctmp = this%cnew(n)
324  end if
325  end if
326  end if
327  !
328  ! -- Add terms based on qbnd sign
329  if (qbnd <= dzero) then
330  hcoftmp = qbnd * omega * this%eqnsclfac
331  else
332  rhstmp = -qbnd * ctmp * (done - omega) * this%eqnsclfac
333  end if
334  !
335  ! -- end of active ibound
336  end if
337  !
338  ! -- set requested values
339  if (present(hcofval)) hcofval = hcoftmp
340  if (present(rhsval)) rhsval = rhstmp
341  if (present(rrate)) rrate = hcoftmp * ctmp - rhstmp
342  if (present(cssm)) cssm = ctmp
343  if (present(qssm)) qssm = qbnd
344  end subroutine ssm_term
345 
346  !> @ brief Provide bound concentration (or temperature) and mixed flag
347  !!
348  !! SSM concentrations and temperatures can be provided in auxiliary variables
349  !! or through separate SPC files. If not provided, the default
350  !! concentration (or temperature) is zero. This single routine provides
351  !! the SSM bound concentration (or temperature) based on these different
352  !! approaches. The mixed flag indicates whether or not the boundary as a
353  !! mixed type.
354  !<
355  subroutine get_ssm_conc(this, ipackage, ientry, nbound_flow, conc, &
356  lauxmixed)
357  ! -- dummy
358  class(tspssmtype) :: this !< TspSsmType
359  integer(I4B), intent(in) :: ipackage !< package number
360  integer(I4B), intent(in) :: ientry !< bound number
361  integer(I4B), intent(in) :: nbound_flow !< size of flow package bound list
362  real(DP), intent(out) :: conc !< user-specified concentration/temperature for this bound
363  logical(LGP), intent(out) :: lauxmixed !< user-specified flag for marking this as a mixed boundary
364  ! -- local
365  integer(I4B) :: isrctype
366  integer(I4B) :: iauxpos
367  !
368  conc = dzero
369  lauxmixed = .false.
370  isrctype = this%isrctype(ipackage)
371  !
372  select case (isrctype)
373  case (1, 2)
374  iauxpos = this%iauxpak(ipackage)
375  conc = this%fmi%gwfpackages(ipackage)%auxvar(iauxpos, ientry)
376  if (isrctype == 2) lauxmixed = .true.
377  case (3, 4)
378  conc = this%ssmivec(ipackage)%get_value(ientry, nbound_flow)
379  if (isrctype == 4) lauxmixed = .true.
380  end select
381  end subroutine get_ssm_conc
382 
383  !> @ brief Fill coefficients
384  !!
385  !! This routine adds the effects of the SSM to the matrix equations by
386  !! updating the a matrix and right-hand side vector.
387  !<
388  subroutine ssm_fc(this, matrix_sln, idxglo, rhs)
389  ! -- dummy
390  class(tspssmtype) :: this
391  class(matrixbasetype), pointer :: matrix_sln
392  integer(I4B), intent(in), dimension(:) :: idxglo
393  real(DP), intent(inout), dimension(:) :: rhs
394  ! -- local
395  integer(I4B) :: ip
396  integer(I4B) :: i
397  integer(I4B) :: n
398  integer(I4B) :: idiag
399  integer(I4B) :: nflowpack
400  integer(I4B) :: nbound
401  real(DP) :: hcofval
402  real(DP) :: rhsval
403  !
404  ! -- do for each flow package
405  nflowpack = this%fmi%nflowpack
406  do ip = 1, nflowpack
407  if (this%fmi%iatp(ip) /= 0) cycle
408  !
409  ! -- do for each entry in package (ip)
410  nbound = this%fmi%gwfpackages(ip)%nbound
411  do i = 1, nbound
412  n = this%fmi%gwfpackages(ip)%nodelist(i)
413  if (n <= 0) cycle
414  call this%ssm_term(ip, i, rhsval=rhsval, hcofval=hcofval)
415  idiag = idxglo(this%dis%con%ia(n))
416  call matrix_sln%add_value_pos(idiag, hcofval)
417  rhs(n) = rhs(n) + rhsval
418  !
419  end do
420  !
421  end do
422  end subroutine ssm_fc
423 
424  !> @ brief Calculate flow
425  !!
426  !! Calculate the resulting mass flow between the boundary and the connected
427  !! GWT/GWE model cell. Update the diagonal position of the flowja array so
428  !! that it ultimately contains the solute balance residual.
429  !<
430  subroutine ssm_cq(this, flowja)
431  ! -- dummy
432  class(tspssmtype) :: this !< TspSsmType object
433  real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow across each face in the model grid
434  ! -- local
435  integer(I4B) :: ip
436  integer(I4B) :: i
437  integer(I4B) :: n
438  integer(I4B) :: idiag
439  real(DP) :: rate
440  !
441  ! -- do for each flow package
442  do ip = 1, this%fmi%nflowpack
443  !
444  ! -- cycle if package is being managed as an advanced package
445  if (this%fmi%iatp(ip) /= 0) cycle
446  !
447  ! -- do for each boundary
448  do i = 1, this%fmi%gwfpackages(ip)%nbound
449  n = this%fmi%gwfpackages(ip)%nodelist(i)
450  if (n <= 0) cycle
451  call this%ssm_term(ip, i, rrate=rate)
452  idiag = this%dis%con%ia(n)
453  flowja(idiag) = flowja(idiag) + rate
454  !
455  end do
456  !
457  end do
458  end subroutine ssm_cq
459 
460  !> @ brief Calculate the global SSM budget terms
461  !!
462  !! Calculate the global SSM budget terms using separate in and out entries
463  !! for each flow package.
464  !<
465  subroutine ssm_bd(this, isuppress_output, model_budget)
466  ! -- modules
467  use tdismodule, only: delt
468  use budgetmodule, only: budgettype
469  ! -- dummy
470  class(tspssmtype) :: this !< TspSsmType object
471  integer(I4B), intent(in) :: isuppress_output !< flag to suppress output
472  type(budgettype), intent(inout) :: model_budget !< budget object for the GWT model
473  ! -- local
474  character(len=LENBUDROWLABEL) :: rowlabel
475  integer(I4B) :: ip
476  integer(I4B) :: i
477  integer(I4B) :: n
478  real(DP) :: rate
479  real(DP) :: rin
480  real(DP) :: rout
481  !
482  ! -- do for each flow package, unless it is being handled by an advanced
483  ! transport package
484  do ip = 1, this%fmi%nflowpack
485  !
486  ! -- cycle if package is being managed as an advanced package
487  if (this%fmi%iatp(ip) /= 0) cycle
488  !
489  ! -- Initialize the rate accumulators
490  rin = dzero
491  rout = dzero
492  !
493  ! -- do for each boundary
494  do i = 1, this%fmi%gwfpackages(ip)%nbound
495  n = this%fmi%gwfpackages(ip)%nodelist(i)
496  if (n <= 0) cycle
497  call this%ssm_term(ip, i, rrate=rate)
498  if (rate < dzero) then
499  rout = rout - rate
500  else
501  rin = rin + rate
502  end if
503  !
504  end do
505  !
506  rowlabel = 'SSM_'//adjustl(trim(this%fmi%flowpacknamearray(ip)))
507  call model_budget%addentry(rin, rout, delt, &
508  this%fmi%gwfpackages(ip)%budtxt, &
509  isuppress_output, rowlabel=rowlabel)
510  end do
511  end subroutine ssm_bd
512 
513  !> @ brief Output flows
514  !!
515  !! Based on user-specified controls, print SSM mass flow rates to the GWT
516  !! listing file and/or write the SSM mass flow rates to the GWT binary
517  !! budget file.
518  !<
519  subroutine ssm_ot_flow(this, icbcfl, ibudfl, icbcun)
520  ! -- modules
521  use tdismodule, only: kstp, kper
523  ! -- dummy
524  class(tspssmtype) :: this !< TspSsmType object
525  integer(I4B), intent(in) :: icbcfl !< flag for writing binary budget terms
526  integer(I4B), intent(in) :: ibudfl !< flag for printing budget terms to list file
527  integer(I4B), intent(in) :: icbcun !< fortran unit number for binary budget file
528  ! -- local
529  character(len=LINELENGTH) :: title
530  integer(I4B) :: node, nodeu
531  character(len=20) :: nodestr
532  integer(I4B) :: maxrows
533  integer(I4B) :: ip
534  integer(I4B) :: i, n2, ibinun
535  real(DP) :: rrate
536  real(DP) :: qssm
537  real(DP) :: cssm
538  integer(I4B) :: naux
539  real(DP), dimension(0) :: auxrow
540  character(len=LENAUXNAME), dimension(0) :: auxname
541  ! -- for observations
542  character(len=LENBOUNDNAME) :: bname
543  ! -- formats
544  character(len=*), parameter :: fmttkk = &
545  &"(1X,/1X,A,' PERIOD ',I0,' STEP ',I0)"
546  !
547  ! -- initialize
548  naux = 0
549  maxrows = 0
550  if (ibudfl /= 0 .and. this%iprflow /= 0) then
551  call this%outputtab%set_kstpkper(kstp, kper)
552  do ip = 1, this%fmi%nflowpack
553  if (this%fmi%iatp(ip) /= 0) cycle
554  !
555  ! -- do for each boundary
556  do i = 1, this%fmi%gwfpackages(ip)%nbound
557  node = this%fmi%gwfpackages(ip)%nodelist(i)
558  if (node > 0) then
559  maxrows = maxrows + 1
560  end if
561  end do
562  end do
563  if (maxrows > 0) then
564  call this%outputtab%set_maxbound(maxrows)
565  end if
566  title = 'SSM PACKAGE ('//trim(this%packName)// &
567  ') FLOW RATES'
568  call this%outputtab%set_title(title)
569  end if
570  !
571  ! -- Set unit number for binary output
572  if (this%ipakcb < 0) then
573  ibinun = icbcun
574  else if (this%ipakcb == 0) then
575  ibinun = 0
576  else
577  ibinun = this%ipakcb
578  end if
579  if (icbcfl == 0) ibinun = 0
580  !
581  ! -- If cell-by-cell flows will be saved as a list, write header.
582  if (ibinun /= 0) then
583  call this%dis%record_srcdst_list_header(text, this%name_model, &
584  this%name_model, this%name_model, &
585  this%packName, naux, auxname, &
586  ibinun, this%nbound, this%iout)
587  end if
588  !
589  ! -- If no boundaries, skip flow calculations.
590  if (this%nbound > 0) then
591  !
592  ! -- Loop through each boundary calculating flow.
593  do ip = 1, this%fmi%nflowpack
594  if (this%fmi%iatp(ip) /= 0) cycle
595  !
596  ! -- do for each boundary
597  do i = 1, this%fmi%gwfpackages(ip)%nbound
598  !
599  ! -- Calculate rate for this entry
600  node = this%fmi%gwfpackages(ip)%nodelist(i)
601  if (node <= 0) cycle
602  call this%ssm_term(ip, i, rrate=rrate, qssm=qssm, cssm=cssm)
603  !
604  ! -- Print the individual rates if the budget is being printed
605  ! and PRINT_FLOWS was specified (this%iprflow<0)
606  if (ibudfl /= 0) then
607  if (this%iprflow /= 0) then
608  !
609  ! -- set nodestr and write outputtab table
610  nodeu = this%dis%get_nodeuser(node)
611  call this%dis%nodeu_to_string(nodeu, nodestr)
612  bname = this%fmi%gwfpackages(ip)%name
613  call this%outputtab%add_term(i)
614  call this%outputtab%add_term(trim(adjustl(nodestr)))
615  call this%outputtab%add_term(qssm)
616  call this%outputtab%add_term(cssm)
617  call this%outputtab%add_term(rrate)
618  call this%outputtab%add_term(bname)
619  end if
620  end if
621  !
622  ! -- If saving cell-by-cell flows in list, write flow
623  if (ibinun /= 0) then
624  n2 = i
625  call this%dis%record_mf6_list_entry(ibinun, node, n2, rrate, &
626  naux, auxrow, &
627  olconv2=.false.)
628  end if
629  !
630  end do
631  !
632  end do
633  end if
634  if (ibudfl /= 0) then
635  if (this%iprflow /= 0) then
636  write (this%iout, '(1x)')
637  end if
638  end if
639  end subroutine ssm_ot_flow
640 
641  !> @ brief Deallocate
642  !!
643  !! Deallocate the memory associated with this derived type
644  !<
645  subroutine ssm_da(this)
646  ! -- modules
648  ! -- dummy
649  class(tspssmtype) :: this !< TspSsmType object
650  ! -- local
651  integer(I4B) :: ip
652  type(tspspctype), pointer :: ssmiptr
653  !
654  ! -- Deallocate the ssmi objects if package was active
655  if (this%inunit > 0) then
656  do ip = 1, size(this%ssmivec)
657  if (this%isrctype(ip) == 3 .or. this%isrctype(ip) == 4) then
658  ssmiptr => this%ssmivec(ip)
659  call ssmiptr%spc_da()
660  end if
661  end do
662  deallocate (this%ssmivec)
663  end if
664  !
665  ! -- Deallocate arrays if package was active
666  if (this%inunit > 0) then
667  call mem_deallocate(this%iauxpak)
668  call mem_deallocate(this%isrctype)
669  this%ibound => null()
670  this%fmi => null()
671  end if
672  !
673  ! -- output table object
674  if (associated(this%outputtab)) then
675  call this%outputtab%table_da()
676  deallocate (this%outputtab)
677  nullify (this%outputtab)
678  end if
679  !
680  ! -- Scalars
681  call mem_deallocate(this%nbound)
682  !
683  ! -- deallocate parent
684  call this%NumericalPackageType%da()
685  end subroutine ssm_da
686 
687  !> @ brief Allocate scalars
688  !!
689  !! Allocate scalar variables for this derived type
690  !<
691  subroutine allocate_scalars(this)
692  ! -- modules
694  ! -- dummy
695  class(tspssmtype) :: this !< TspSsmType object
696  !
697  ! -- allocate scalars in NumericalPackageType
698  call this%NumericalPackageType%allocate_scalars()
699  !
700  ! -- Allocate
701  call mem_allocate(this%nbound, 'NBOUND', this%memoryPath)
702  !
703  ! -- Initialize
704  this%nbound = 0
705  end subroutine allocate_scalars
706 
707  !> @ brief Allocate arrays
708  !!
709  !! Allocate array variables for this derived type
710  !<
711  subroutine allocate_arrays(this)
712  ! -- modules
714  ! -- dummy
715  class(tspssmtype) :: this !< TspSsmType object
716  ! -- local
717  integer(I4B) :: nflowpack
718  integer(I4B) :: i
719  !
720  ! -- Allocate
721  nflowpack = this%fmi%nflowpack
722  call mem_allocate(this%iauxpak, nflowpack, 'IAUXPAK', this%memoryPath)
723  call mem_allocate(this%isrctype, nflowpack, 'ISRCTYPE', this%memoryPath)
724  !
725  ! -- Initialize
726  do i = 1, nflowpack
727  this%iauxpak(i) = 0
728  this%isrctype(i) = 0
729  end do
730  !
731  ! -- Allocate the ssmivec array
732  allocate (this%ssmivec(nflowpack))
733  end subroutine allocate_arrays
734 
735  !> @brief Source input options
736  !<
737  subroutine source_options(this)
738  ! -- modules
739  !use KindModule, only: LGP
742  ! -- dummy
743  class(tspssmtype) :: this
744  ! -- locals
745  type(gwtssmparamfoundtype) :: found
746  ! -- formats
747  character(len=*), parameter :: fmtiprflow = &
748  "(4x,'SSM FLOW INFORMATION WILL BE PRINTED TO LISTING FILE &
749  &WHENEVER ICBCFL IS NOT ZERO.')"
750  character(len=*), parameter :: fmtisvflow = &
751  "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE &
752  &WHENEVER ICBCFL IS NOT ZERO.')"
753  !
754  ! -- update defaults with idm sourced values
755  call mem_set_value(this%iprflow, 'PRINT_FLOWS', this%input_mempath, &
756  found%print_flows)
757  call mem_set_value(this%ipakcb, 'SAVE_FLOWS', this%input_mempath, &
758  found%save_flows)
759 
760  if (found%save_flows) this%ipakcb = -1
761 
762  ! log options
763  write (this%iout, '(1x,a)') 'PROCESSING SSM OPTIONS'
764  if (found%print_flows) write (this%iout, fmtiprflow)
765  if (found%save_flows) write (this%iout, fmtisvflow)
766  write (this%iout, '(1x,a)') 'END OF SSM OPTIONS'
767  end subroutine source_options
768 
769  !> @brief Source sources input block
770  !<
771  subroutine source_sources(this)
772  ! -- modules
773  !use KindModule, only: LGP
777  ! -- dummy
778  class(tspssmtype) :: this
779  ! -- locals
780  type(characterstringtype), dimension(:), pointer, &
781  contiguous :: pnames, srctypes, auxnames
782  character(len=LINELENGTH) :: pname, srctype, auxname
783  integer(I4B) :: n, ip
784  logical(LGP) :: found
785  ! -- formats
786 
787  ! set pointers to input context
788  call mem_setptr(pnames, 'PNAME_SOURCES', this%input_mempath)
789  call mem_setptr(srctypes, 'SRCTYPE', this%input_mempath)
790  call mem_setptr(auxnames, 'AUXNAME', this%input_mempath)
791 
792  write (this%iout, '(/1x,a)') 'PROCESSING SSM SOURCES'
793  do n = 1, size(pnames)
794 
795  pname = pnames(n)
796  srctype = srctypes(n)
797  auxname = auxnames(n)
798  found = .false.
799 
800  do ip = 1, this%fmi%nflowpack
801  if (trim(adjustl(this%fmi%gwfpackages(ip)%name)) == pname) then
802  found = .true.
803  exit
804  end if
805  end do
806 
807  if (.not. found) then
808  write (errmsg, '(a,a)') 'Flow package cannot be found: ', &
809  trim(pname)
810  call store_error(errmsg)
811  cycle
812  end if
813 
814  ! -- Ensure package was not specified more than once in SOURCES block
815  if (this%isrctype(ip) /= 0) then
816  write (errmsg, '(a, a)') &
817  'A package cannot be specified more than once in the SSM SOURCES &
818  &block. The following package was specified more than once: ', &
819  trim(pname)
820  call store_error(errmsg)
821  cycle
822  end if
823 
824  if (srctype == 'AUX') then
825  this%isrctype(ip) = 1
826  write (this%iout, '(4x,a)') 'AUX SOURCE DETECTED.'
827  else if (srctype == 'AUXMIXED') then
828  this%isrctype(ip) = 2
829  write (this%iout, '(4x,a)') 'AUXMIXED SOURCE DETECTED.'
830  else
831  write (errmsg, '(a, a)') &
832  'SRCTYPE must be AUX or AUXMIXED. Found: ', trim(srctype)
833  call store_error(errmsg)
834  cycle
835  end if
836 
837  ! -- Find and store the auxiliary column
838  call this%set_iauxpak(ip, srctype, auxname)
839  end do
840  write (this%iout, '(1x,a)') 'END PROCESSING SSM SOURCES'
841 
842  ! -- terminate if errors
843  if (count_errors() > 0) then
844  call store_error_filename(this%input_fname)
845  end if
846 
847  call memorystore_release('PNAME_SOURCES', this%input_mempath)
848  call memorystore_release('SRCTYPE', this%input_mempath)
849  call memorystore_release('AUXNAME', this%input_mempath)
850  end subroutine source_sources
851 
852  !> @brief Source fileinput input block
853  !!
854  !! Initialize an SPC input file reader for each input entry.
855  !<
856  subroutine source_fileinput(this)
857  ! -- modules
861  ! -- dummy
862  class(tspssmtype) :: this
863  ! -- locals
864  type(characterstringtype), dimension(:), pointer, &
865  contiguous :: pnames, ftypes, iotypes, fnames, conditions, spc6_mempaths
866  character(len=LINELENGTH) :: pname, ftype, iotype, fname, condition
867  character(len=LENMEMPATH) :: spc_mempath
868  integer(I4B) :: n, ip, isize
869  logical(LGP) :: found
870  ! -- formats
871 
872  call get_isize('PNAME', this%input_mempath, isize)
873  if (isize <= 0) then
874  write (this%iout, '(/1x,a)') &
875  'OPTIONAL SSM FILEINPUT BLOCK NOT FOUND OR EMPTY.'
876  return
877  end if
878 
879  ! set pointers to input context
880  call mem_setptr(pnames, 'PNAME', this%input_mempath)
881  call mem_setptr(ftypes, 'SPC6', this%input_mempath)
882  call mem_setptr(iotypes, 'FILEIN', this%input_mempath)
883  call mem_setptr(fnames, 'SPC6_FILENAME', this%input_mempath)
884  call mem_setptr(conditions, 'MIXED', this%input_mempath)
885  call mem_setptr(spc6_mempaths, 'SPC6_MEMPATH', this%input_mempath)
886 
887  write (this%iout, '(/1x,a)') 'PROCESSING SSM FILEINPUT'
888  do n = 1, size(pnames)
889 
890  pname = pnames(n)
891  ftype = ftypes(n)
892  iotype = iotypes(n)
893  fname = fnames(n)
894  condition = conditions(n)
895  spc_mempath = spc6_mempaths(n)
896  found = .false.
897 
898  do ip = 1, this%fmi%nflowpack
899  if (trim(adjustl(this%fmi%gwfpackages(ip)%name)) == pname) then
900  found = .true.
901  exit
902  end if
903  end do
904 
905  if (.not. found) then
906  write (errmsg, '(a,a)') 'Flow package cannot be found: ', &
907  trim(pname)
908  call store_error(errmsg)
909  cycle
910  end if
911 
912  ! -- Ensure package was not specified more than once in SOURCES block
913  if (this%isrctype(ip) /= 0) then
914  write (errmsg, '(a, a)') &
915  'A package cannot be specified more than once in the SSM SOURCES &
916  &block. The following package was specified more than once: ', &
917  trim(pname)
918  call store_error(errmsg)
919  cycle
920  end if
921 
922  ! verify ftype
923  if (ftype == 'SPC6') then
924  write (this%iout, '(4x,a)') 'SPC6 SOURCE DETECTED:'
925  else
926  write (errmsg, '(a,a)') &
927  'SRCTYPE must be SPC6. Found: ', trim(ftype)
928  call store_error(errmsg)
929  cycle
930  end if
931 
932  ! verify iotype
933  if (iotype /= 'FILEIN') then
934  errmsg = 'SPC6 keyword must be followed by "FILEIN" '// &
935  'then by filename and optionally by <MIXED>.'
936  call store_error(errmsg)
937  cycle
938  end if
939 
940  ! -- Use set_ssmivec to initialize the ssmi object from the
941  ! input mempath
942  call this%set_ssmivec(ip, pname, spc_mempath, trim(fname))
943 
944  if (condition == 'MIXED') then
945  this%isrctype(ip) = 4
946  write (this%iout, '(4x,a,a)') 'ASSIGNED MIXED SSM TYPE TO PACKAGE ', &
947  trim(pname)
948  else
949  this%isrctype(ip) = 3
950  end if
951  end do
952  write (this%iout, '(1x,a)') 'END PROCESSING SSM FILEINPUT'
953 
954  ! -- terminate if errors
955  if (count_errors() > 0) then
956  call store_error_filename(this%input_fname)
957  end if
958 
959  call memorystore_release('PNAME', this%input_mempath)
960  call memorystore_release('SPC6', this%input_mempath)
961  call memorystore_release('FILEIN', this%input_mempath)
962  call memorystore_release('SPC6_FILENAME', this%input_mempath)
963  call memorystore_release('MIXED', this%input_mempath)
964  call memorystore_release('SPC6_MEMPATH', this%input_mempath)
965  end subroutine source_fileinput
966 
967  !> @ brief Set iauxpak array value for package ip
968  !!
969  !! The routine searches through the auxiliary names in package
970  !! ip and sets iauxpak to the column number corresponding to the
971  !! correct auxiliary column.
972  !<
973  subroutine set_iauxpak(this, ip, packname, auxname)
974  ! -- dummy
975  class(tspssmtype), intent(inout) :: this !< TspSsmType
976  integer(I4B), intent(in) :: ip !< package number
977  character(len=*), intent(in) :: packname !< name of package
978  character(len=*), intent(in) :: auxname !< name of aux
979  ! -- local
980  logical :: auxfound
981  integer(I4B) :: iaux
982  !
983  ! -- match package auxiliary
984  auxfound = .false.
985  do iaux = 1, this%fmi%gwfpackages(ip)%naux
986  if (trim(this%fmi%gwfpackages(ip)%auxname(iaux)) == &
987  trim(auxname)) then
988  auxfound = .true.
989  exit
990  end if
991  end do
992  if (.not. auxfound) then
993  write (errmsg, '(a, a)') &
994  'Auxiliary name cannot be found: ', trim(auxname)
995  call store_error(errmsg)
996  call store_error_filename(this%input_fname)
997  end if
998  !
999  ! -- set iauxpak and write message
1000  this%iauxpak(ip) = iaux
1001  write (this%iout, '(4x, a, i0, a, a)') 'USING AUX COLUMN ', &
1002  iaux, ' IN PACKAGE ', trim(packname)
1003  end subroutine set_iauxpak
1004 
1005  !> @brief Set ssmivec array value for package ip
1006  !!
1007  !! Initialize TspSpcType from the input mempath.
1008  !<
1009  subroutine set_ssmivec(this, ip, packname, spc_mempath, input_fname)
1010  ! -- dummy
1011  class(tspssmtype), intent(inout) :: this !< TspSsmType
1012  integer(I4B), intent(in) :: ip !< package number
1013  character(len=*), intent(in) :: packname !< name of corresponding flow package
1014  character(len=*), intent(in) :: spc_mempath !< input mempath for this SPC instance
1015  character(len=*), intent(in) :: input_fname !< SPC input file name (for error messages)
1016  ! -- local
1017  type(tspspctype), pointer :: ssmiptr
1018  !
1019  ! -- initialize the TspSpcType reader for this package
1020  ssmiptr => this%ssmivec(ip)
1021  call ssmiptr%initialize(this%dis, ip, spc_mempath, this%iout, &
1022  this%name_model, trim(packname), &
1023  this%depvartype, input_fname)
1024  end subroutine set_ssmivec
1025 
1026  !> @ brief Setup the output table
1027  !!
1028  !! Setup the output table by creating the column headers.
1029  !<
1030  subroutine pak_setup_outputtab(this)
1031  ! -- dummy
1032  class(tspssmtype), intent(inout) :: this
1033  ! -- local
1034  character(len=LINELENGTH) :: title
1035  character(len=LINELENGTH) :: text
1036  integer(I4B) :: ntabcol
1037  !
1038  ! -- allocate and initialize the output table
1039  if (this%iprflow /= 0) then
1040  !
1041  ! -- dimension table
1042  ntabcol = 6
1043  !if (this%inamedbound > 0) then
1044  ! ntabcol = ntabcol + 1
1045  !end if
1046  !
1047  ! -- initialize the output table object
1048  title = 'SSM PACKAGE ('//trim(this%packName)// &
1049  ') FLOW RATES'
1050  call table_cr(this%outputtab, this%packName, title)
1051  call this%outputtab%table_df(1, ntabcol, this%iout, transient=.true.)
1052  text = 'NUMBER'
1053  call this%outputtab%initialize_column(text, 10, alignment=tabcenter)
1054  text = 'CELLID'
1055  call this%outputtab%initialize_column(text, 20, alignment=tableft)
1056  text = 'BOUND Q'
1057  call this%outputtab%initialize_column(text, 15, alignment=tabcenter)
1058  text = 'SSM CONC'
1059  call this%outputtab%initialize_column(text, 15, alignment=tabcenter)
1060  text = 'RATE'
1061  call this%outputtab%initialize_column(text, 15, alignment=tabcenter)
1062  text = 'PACKAGE NAME'
1063  call this%outputtab%initialize_column(text, 16, alignment=tabcenter)
1064  !if (this%inamedbound > 0) then
1065  ! text = 'NAME'
1066  ! call this%outputtab%initialize_column(text, 20, alignment=TABLEFT)
1067  !end if
1068  end if
1069  end subroutine pak_setup_outputtab
1070 
1071 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
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
This module defines variable data types.
Definition: kind.f90:8
subroutine, public memorystore_release(varname, memory_path)
Release a single variable from the memory store.
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: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
This module contains the TspSpc Module.
Definition: TspSpc.f90:8
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:389
subroutine ssm_ot_flow(this, icbcfl, ibudfl, icbcun)
@ brief Output flows
Definition: tsp-ssm.f90:520
subroutine source_sources(this)
Source sources input block.
Definition: tsp-ssm.f90:772
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:257
subroutine allocate_scalars(this)
@ brief Allocate scalars
Definition: tsp-ssm.f90:692
subroutine ssm_cq(this, flowja)
@ brief Calculate flow
Definition: tsp-ssm.f90:431
subroutine source_fileinput(this)
Source fileinput input block.
Definition: tsp-ssm.f90:857
subroutine ssm_bd(this, isuppress_output, model_budget)
@ brief Calculate the global SSM budget terms
Definition: tsp-ssm.f90:466
subroutine source_options(this)
Source input options.
Definition: tsp-ssm.f90:738
subroutine pak_setup_outputtab(this)
@ brief Setup the output table
Definition: tsp-ssm.f90:1031
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:357
subroutine ssm_rp(this)
@ brief Read and prepare this SSM Package
Definition: tsp-ssm.f90:186
subroutine set_ssmivec(this, ip, packname, spc_mempath, input_fname)
Set ssmivec array value for package ip.
Definition: tsp-ssm.f90:1010
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:712
character(len=lenftype) ftype
Definition: tsp-ssm.f90:28
subroutine ssm_ad(this)
@ brief Advance the SSM Package
Definition: tsp-ssm.f90:214
subroutine ssm_da(this)
@ brief Deallocate
Definition: tsp-ssm.f90:646
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:974
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:34
Derived type for the SSM Package.
Definition: tsp-ssm.f90:37