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
776  ! -- dummy
777  class(tspssmtype) :: this
778  ! -- locals
779  type(characterstringtype), dimension(:), pointer, &
780  contiguous :: pnames, srctypes, auxnames
781  character(len=LINELENGTH) :: pname, srctype, auxname
782  integer(I4B) :: n, ip
783  logical(LGP) :: found
784  ! -- formats
785 
786  ! set pointers to input context
787  call mem_setptr(pnames, 'PNAME_SOURCES', this%input_mempath)
788  call mem_setptr(srctypes, 'SRCTYPE', this%input_mempath)
789  call mem_setptr(auxnames, 'AUXNAME', this%input_mempath)
790 
791  write (this%iout, '(/1x,a)') 'PROCESSING SSM SOURCES'
792  do n = 1, size(pnames)
793 
794  pname = pnames(n)
795  srctype = srctypes(n)
796  auxname = auxnames(n)
797  found = .false.
798 
799  do ip = 1, this%fmi%nflowpack
800  if (trim(adjustl(this%fmi%gwfpackages(ip)%name)) == pname) then
801  found = .true.
802  exit
803  end if
804  end do
805 
806  if (.not. found) then
807  write (errmsg, '(a,a)') 'Flow package cannot be found: ', &
808  trim(pname)
809  call store_error(errmsg)
810  cycle
811  end if
812 
813  ! -- Ensure package was not specified more than once in SOURCES block
814  if (this%isrctype(ip) /= 0) then
815  write (errmsg, '(a, a)') &
816  'A package cannot be specified more than once in the SSM SOURCES &
817  &block. The following package was specified more than once: ', &
818  trim(pname)
819  call store_error(errmsg)
820  cycle
821  end if
822 
823  if (srctype == 'AUX') then
824  this%isrctype(ip) = 1
825  write (this%iout, '(4x,a)') 'AUX SOURCE DETECTED.'
826  else if (srctype == 'AUXMIXED') then
827  this%isrctype(ip) = 2
828  write (this%iout, '(4x,a)') 'AUXMIXED SOURCE DETECTED.'
829  else
830  write (errmsg, '(a, a)') &
831  'SRCTYPE must be AUX or AUXMIXED. Found: ', trim(srctype)
832  call store_error(errmsg)
833  cycle
834  end if
835 
836  ! -- Find and store the auxiliary column
837  call this%set_iauxpak(ip, srctype, auxname)
838  end do
839  write (this%iout, '(1x,a)') 'END PROCESSING SSM SOURCES'
840 
841  ! -- terminate if errors
842  if (count_errors() > 0) then
843  call store_error_filename(this%input_fname)
844  end if
845  end subroutine source_sources
846 
847  !> @brief Source fileinput input block
848  !!
849  !! Initialize an SPC input file reader for each input entry.
850  !<
851  subroutine source_fileinput(this)
852  ! -- modules
855  ! -- dummy
856  class(tspssmtype) :: this
857  ! -- locals
858  type(characterstringtype), dimension(:), pointer, &
859  contiguous :: pnames, ftypes, iotypes, fnames, conditions, spc6_mempaths
860  character(len=LINELENGTH) :: pname, ftype, iotype, fname, condition
861  character(len=LENMEMPATH) :: spc_mempath
862  integer(I4B) :: n, ip, isize
863  logical(LGP) :: found
864  ! -- formats
865 
866  call get_isize('PNAME', this%input_mempath, isize)
867  if (isize <= 0) then
868  write (this%iout, '(/1x,a)') &
869  'OPTIONAL SSM FILEINPUT BLOCK NOT FOUND OR EMPTY.'
870  return
871  end if
872 
873  ! set pointers to input context
874  call mem_setptr(pnames, 'PNAME', this%input_mempath)
875  call mem_setptr(ftypes, 'SPC6', this%input_mempath)
876  call mem_setptr(iotypes, 'FILEIN', this%input_mempath)
877  call mem_setptr(fnames, 'SPC6_FILENAME', this%input_mempath)
878  call mem_setptr(conditions, 'MIXED', this%input_mempath)
879  call mem_setptr(spc6_mempaths, 'SPC6_MEMPATH', this%input_mempath)
880 
881  write (this%iout, '(/1x,a)') 'PROCESSING SSM FILEINPUT'
882  do n = 1, size(pnames)
883 
884  pname = pnames(n)
885  ftype = ftypes(n)
886  iotype = iotypes(n)
887  fname = fnames(n)
888  condition = conditions(n)
889  spc_mempath = spc6_mempaths(n)
890  found = .false.
891 
892  do ip = 1, this%fmi%nflowpack
893  if (trim(adjustl(this%fmi%gwfpackages(ip)%name)) == pname) then
894  found = .true.
895  exit
896  end if
897  end do
898 
899  if (.not. found) then
900  write (errmsg, '(a,a)') 'Flow package cannot be found: ', &
901  trim(pname)
902  call store_error(errmsg)
903  cycle
904  end if
905 
906  ! -- Ensure package was not specified more than once in SOURCES block
907  if (this%isrctype(ip) /= 0) then
908  write (errmsg, '(a, a)') &
909  'A package cannot be specified more than once in the SSM SOURCES &
910  &block. The following package was specified more than once: ', &
911  trim(pname)
912  call store_error(errmsg)
913  cycle
914  end if
915 
916  ! verify ftype
917  if (ftype == 'SPC6') then
918  write (this%iout, '(4x,a)') 'SPC6 SOURCE DETECTED:'
919  else
920  write (errmsg, '(a,a)') &
921  'SRCTYPE must be SPC6. Found: ', trim(ftype)
922  call store_error(errmsg)
923  cycle
924  end if
925 
926  ! verify iotype
927  if (iotype /= 'FILEIN') then
928  errmsg = 'SPC6 keyword must be followed by "FILEIN" '// &
929  'then by filename and optionally by <MIXED>.'
930  call store_error(errmsg)
931  cycle
932  end if
933 
934  ! -- Use set_ssmivec to initialize the ssmi object from the
935  ! input mempath
936  call this%set_ssmivec(ip, pname, spc_mempath, trim(fname))
937 
938  if (condition == 'MIXED') then
939  this%isrctype(ip) = 4
940  write (this%iout, '(4x,a,a)') 'ASSIGNED MIXED SSM TYPE TO PACKAGE ', &
941  trim(pname)
942  else
943  this%isrctype(ip) = 3
944  end if
945  end do
946  write (this%iout, '(1x,a)') 'END PROCESSING SSM FILEINPUT'
947 
948  ! -- terminate if errors
949  if (count_errors() > 0) then
950  call store_error_filename(this%input_fname)
951  end if
952  end subroutine source_fileinput
953 
954  !> @ brief Set iauxpak array value for package ip
955  !!
956  !! The routine searches through the auxiliary names in package
957  !! ip and sets iauxpak to the column number corresponding to the
958  !! correct auxiliary column.
959  !<
960  subroutine set_iauxpak(this, ip, packname, auxname)
961  ! -- dummy
962  class(tspssmtype), intent(inout) :: this !< TspSsmType
963  integer(I4B), intent(in) :: ip !< package number
964  character(len=*), intent(in) :: packname !< name of package
965  character(len=*), intent(in) :: auxname !< name of aux
966  ! -- local
967  logical :: auxfound
968  integer(I4B) :: iaux
969  !
970  ! -- match package auxiliary
971  auxfound = .false.
972  do iaux = 1, this%fmi%gwfpackages(ip)%naux
973  if (trim(this%fmi%gwfpackages(ip)%auxname(iaux)) == &
974  trim(auxname)) then
975  auxfound = .true.
976  exit
977  end if
978  end do
979  if (.not. auxfound) then
980  write (errmsg, '(a, a)') &
981  'Auxiliary name cannot be found: ', trim(auxname)
982  call store_error(errmsg)
983  call store_error_filename(this%input_fname)
984  end if
985  !
986  ! -- set iauxpak and write message
987  this%iauxpak(ip) = iaux
988  write (this%iout, '(4x, a, i0, a, a)') 'USING AUX COLUMN ', &
989  iaux, ' IN PACKAGE ', trim(packname)
990  end subroutine set_iauxpak
991 
992  !> @brief Set ssmivec array value for package ip
993  !!
994  !! Initialize TspSpcType from the input mempath.
995  !<
996  subroutine set_ssmivec(this, ip, packname, spc_mempath, input_fname)
997  ! -- dummy
998  class(tspssmtype), intent(inout) :: this !< TspSsmType
999  integer(I4B), intent(in) :: ip !< package number
1000  character(len=*), intent(in) :: packname !< name of corresponding flow package
1001  character(len=*), intent(in) :: spc_mempath !< input mempath for this SPC instance
1002  character(len=*), intent(in) :: input_fname !< SPC input file name (for error messages)
1003  ! -- local
1004  type(tspspctype), pointer :: ssmiptr
1005  !
1006  ! -- initialize the TspSpcType reader for this package
1007  ssmiptr => this%ssmivec(ip)
1008  call ssmiptr%initialize(this%dis, ip, spc_mempath, this%iout, &
1009  this%name_model, trim(packname), &
1010  this%depvartype, input_fname)
1011  end subroutine set_ssmivec
1012 
1013  !> @ brief Setup the output table
1014  !!
1015  !! Setup the output table by creating the column headers.
1016  !<
1017  subroutine pak_setup_outputtab(this)
1018  ! -- dummy
1019  class(tspssmtype), intent(inout) :: this
1020  ! -- local
1021  character(len=LINELENGTH) :: title
1022  character(len=LINELENGTH) :: text
1023  integer(I4B) :: ntabcol
1024  !
1025  ! -- allocate and initialize the output table
1026  if (this%iprflow /= 0) then
1027  !
1028  ! -- dimension table
1029  ntabcol = 6
1030  !if (this%inamedbound > 0) then
1031  ! ntabcol = ntabcol + 1
1032  !end if
1033  !
1034  ! -- initialize the output table object
1035  title = 'SSM PACKAGE ('//trim(this%packName)// &
1036  ') FLOW RATES'
1037  call table_cr(this%outputtab, this%packName, title)
1038  call this%outputtab%table_df(1, ntabcol, this%iout, transient=.true.)
1039  text = 'NUMBER'
1040  call this%outputtab%initialize_column(text, 10, alignment=tabcenter)
1041  text = 'CELLID'
1042  call this%outputtab%initialize_column(text, 20, alignment=tableft)
1043  text = 'BOUND Q'
1044  call this%outputtab%initialize_column(text, 15, alignment=tabcenter)
1045  text = 'SSM CONC'
1046  call this%outputtab%initialize_column(text, 15, alignment=tabcenter)
1047  text = 'RATE'
1048  call this%outputtab%initialize_column(text, 15, alignment=tabcenter)
1049  text = 'PACKAGE NAME'
1050  call this%outputtab%initialize_column(text, 16, alignment=tabcenter)
1051  !if (this%inamedbound > 0) then
1052  ! text = 'NAME'
1053  ! call this%outputtab%initialize_column(text, 20, alignment=TABLEFT)
1054  !end if
1055  end if
1056  end subroutine pak_setup_outputtab
1057 
1058 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 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: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:852
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:1018
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:997
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:961
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