MODFLOW 6  version 6.5.0.dev2
MODFLOW 6 Code Documentation
gwf-sto.f90
Go to the documentation of this file.
1 !> @brief This module contains the storage package methods
2 !!
3 !! This module contains the methods used to add the effects of storage
4 !! on the groundwater flow equation. The contribution of specific
5 !! storage and specific yield can be represented.
6 !!
7 !<
9 
10  use kindmodule, only: dp, i4b, lgp
11  use constantsmodule, only: dzero, dem6, dem4, dhalf, done, dtwo, &
13  use simvariablesmodule, only: errmsg
18  use basedismodule, only: disbasetype
23  use tvsmodule, only: tvstype, tvs_cr
25 
26  implicit none
27  public :: gwfstotype, sto_cr
28 
29  character(len=LENBUDTXT), dimension(2) :: budtxt = & !< text labels for budget terms
30  &[' STO-SS', ' STO-SY']
31 
32  type, extends(numericalpackagetype) :: gwfstotype
33  integer(I4B), pointer :: istor_coef => null() !< indicates if ss is the storage coefficient
34  integer(I4B), pointer :: iconf_ss => null() !< indicates if ss is 0 below the top of a layer
35  integer(I4B), pointer :: iorig_ss => null() !< indicates if the original storage specific storage formulation should be used
36  integer(I4B), pointer :: iss => null() !< steady state flag: 1 = steady, 0 = transient
37  integer(I4B), pointer :: iusesy => null() !< flag set if any cell is convertible (0, 1)
38  integer(I4B), dimension(:), pointer, contiguous :: iconvert => null() !< confined (0) or convertible (1)
39  real(dp), dimension(:), pointer, contiguous :: ss => null() !< specific storage or storage coefficient
40  real(dp), dimension(:), pointer, contiguous :: sy => null() !< specific yield
41  real(dp), dimension(:), pointer, contiguous :: strgss => null() !< vector of specific storage rates
42  real(dp), dimension(:), pointer, contiguous :: strgsy => null() !< vector of specific yield rates
43  integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound
44  real(dp), pointer :: satomega => null() !< newton-raphson saturation omega
45  integer(I4B), pointer :: integratechanges => null() !< indicates if mid-simulation ss and sy changes should be integrated via an additional matrix formulation term
46  integer(I4B), pointer :: intvs => null() !< TVS (time-varying storage) unit number (0 if unused)
47  type(tvstype), pointer :: tvs => null() !< TVS object
48  real(dp), dimension(:), pointer, contiguous, private :: oldss => null() !< previous time step specific storage
49  real(dp), dimension(:), pointer, contiguous, private :: oldsy => null() !< previous time step specific yield
50  contains
51  procedure :: sto_ar
52  procedure :: sto_rp
53  procedure :: sto_ad
54  procedure :: sto_fc
55  procedure :: sto_fn
56  procedure :: sto_cq
57  procedure :: sto_bd
58  procedure :: sto_save_model_flows
59  procedure :: sto_da
60  procedure :: allocate_scalars
61  procedure, private :: allocate_arrays
62  !procedure, private :: register_handlers
63  procedure, private :: read_options
64  procedure, private :: read_data
65  procedure, private :: save_old_ss_sy
66  end type
67 
68 contains
69 
70  !> @ brief Create a new package object
71  !!
72  !! Create a new storage (STO) object
73  !!
74  !<
75  subroutine sto_cr(stoobj, name_model, inunit, iout)
76  ! -- dummy variables
77  type(gwfstotype), pointer :: stoobj !< GwfStoType object
78  character(len=*), intent(in) :: name_model !< name of model
79  integer(I4B), intent(in) :: inunit !< package input file unit
80  integer(I4B), intent(in) :: iout !< model listing file unit
81  !
82  ! -- Create the object
83  allocate (stoobj)
84  !
85  ! -- create name and memory path
86  call stoobj%set_names(1, name_model, 'STO', 'STO')
87  !
88  ! -- Allocate scalars
89  call stoobj%allocate_scalars()
90  !
91  ! -- Set variables
92  stoobj%inunit = inunit
93  stoobj%iout = iout
94  !
95  ! -- Initialize block parser
96  call stoobj%parser%Initialize(stoobj%inunit, stoobj%iout)
97  !
98  ! -- return
99  return
100  end subroutine sto_cr
101 
102  !> @ brief Allocate and read method for package
103  !!
104  !! Method to allocate and read static data for the STO package.
105  !!
106  !<
107  subroutine sto_ar(this, dis, ibound)
108  ! -- modules
111  ! -- dummy variables
112  class(gwfstotype) :: this !< GwfStoType object
113  class(disbasetype), pointer, intent(in) :: dis !< model discretization object
114  integer(I4B), dimension(:), pointer, contiguous :: ibound !< model ibound array
115  ! -- local variables
116  ! -- formats
117  character(len=*), parameter :: fmtsto = &
118  "(1x,/1x,'STO -- STORAGE PACKAGE, VERSION 1, 5/19/2014', &
119  &' INPUT READ FROM UNIT ', i0, //)"
120  !
121  ! --print a message identifying the storage package.
122  write (this%iout, fmtsto) this%inunit
123  !
124  ! -- store pointers to arguments that were passed in
125  this%dis => dis
126  this%ibound => ibound
127  !
128  ! -- set pointer to gwf iss
129  call mem_setptr(this%iss, 'ISS', create_mem_path(this%name_model))
130  !
131  ! -- Allocate arrays
132  call this%allocate_arrays(dis%nodes)
133  !!
134  !! -- Register side effect handlers
135  !call this%register_handlers()
136  !
137  ! -- Read storage options
138  call this%read_options()
139  !
140  ! -- read the data block
141  call this%read_data()
142  !
143  ! -- TVS
144  if (this%intvs /= 0) then
145  call this%tvs%ar(this%dis)
146  end if
147  !
148  ! -- return
149  return
150  end subroutine sto_ar
151 
152  !> @ brief Read and prepare method for package
153  !!
154  !! Method to read and prepare stress period data for the STO package.
155  !!
156  !<
157  subroutine sto_rp(this)
158  ! -- modules
159  use tdismodule, only: kper, nper
160  implicit none
161  ! -- dummy variables
162  class(gwfstotype) :: this !< GwfStoType object
163  ! -- local variables
164  integer(I4B) :: ierr
165  logical :: isfound, readss, readsy, endOfBlock
166  character(len=16) :: css(0:1)
167  character(len=LINELENGTH) :: line, keyword
168  ! -- formats
169  character(len=*), parameter :: fmtlsp = &
170  &"(1X,/1X,'REUSING ',A,' FROM LAST STRESS PERIOD')"
171  character(len=*), parameter :: fmtblkerr = &
172  &"('Error. Looking for BEGIN PERIOD iper. Found ', a, ' instead.')"
173  ! -- data
174  data css(0)/' TRANSIENT'/
175  data css(1)/' STEADY-STATE'/
176 ! ------------------------------------------------------------------------------
177  !
178  ! -- Store ss and sy values from end of last stress period if needed
179  if (this%integratechanges /= 0) then
180  call this%save_old_ss_sy()
181  end if
182  !
183  ! -- get stress period data
184  if (this%ionper < kper) then
185  !
186  ! -- get period block
187  call this%parser%GetBlock('PERIOD', isfound, ierr, &
188  supportopenclose=.true., &
189  blockrequired=.false.)
190  if (isfound) then
191  !
192  ! -- read ionper and check for increasing period numbers
193  call this%read_check_ionper()
194  else
195  !
196  ! -- PERIOD block not found
197  if (ierr < 0) then
198  ! -- End of file found; data applies for remainder of simulation.
199  this%ionper = nper + 1
200  else
201  ! -- Found invalid block
202  call this%parser%GetCurrentLine(line)
203  write (errmsg, fmtblkerr) adjustl(trim(line))
204  call store_error(errmsg)
205  call this%parser%StoreErrorUnit()
206  end if
207  end if
208  end if
209  !
210  ! -- read data if ionper == kper
211  ! are these here to anticipate reading ss,sy per stress period?
212  readss = .false.
213  readsy = .false.
214 
215  !stotxt = aname(2)
216  if (this%ionper == kper) then
217  write (this%iout, '(//,1x,a)') 'PROCESSING STORAGE PERIOD DATA'
218  do
219  call this%parser%GetNextLine(endofblock)
220  if (endofblock) exit
221  call this%parser%GetStringCaps(keyword)
222  select case (keyword)
223  case ('STEADY-STATE')
224  this%iss = 1
225  case ('TRANSIENT')
226  this%iss = 0
227  case default
228  write (errmsg, '(a,a)') 'Unknown STORAGE data tag: ', &
229  trim(keyword)
230  call store_error(errmsg)
231  call this%parser%StoreErrorUnit()
232  end select
233  end do
234  write (this%iout, '(1x,a)') 'END PROCESSING STORAGE PERIOD DATA'
235  !else
236  ! write(this%iout,fmtlsp) 'STORAGE VALUES'
237  end if
238 
239  write (this%iout, '(//1X,A,I0,A,A,/)') &
240  'STRESS PERIOD ', kper, ' IS ', trim(adjustl(css(this%iss)))
241  !
242  ! -- TVS
243  if (this%intvs /= 0) then
244  call this%tvs%rp()
245  end if
246  !
247  ! -- return
248  return
249  end subroutine sto_rp
250 
251  !> @ brief Advance the package
252  !!
253  !! Advance data in the STO package.
254  !!
255  !<
256  subroutine sto_ad(this)
257  ! -- modules
258  use tdismodule, only: kstp
259  ! -- dummy variables
260  class(gwfstotype) :: this !< GwfStoType object
261  !
262  ! -- Store ss and sy values from end of last time step if needed
263  if (this%integratechanges /= 0 .and. kstp > 1) then
264  call this%save_old_ss_sy()
265  end if
266  !
267  ! -- TVS
268  if (this%intvs /= 0) then
269  call this%tvs%ad()
270  end if
271  !
272  ! -- return
273  return
274  end subroutine sto_ad
275 
276  !> @ brief Fill A and right-hand side for the package
277  !!
278  !! Fill the coefficient matrix and right-hand side with the STO package terms.
279  !!
280  !<
281  subroutine sto_fc(this, kiter, hold, hnew, matrix_sln, idxglo, rhs)
282  ! -- modules
283  use tdismodule, only: delt
284  ! -- dummy variables
285  class(gwfstotype) :: this !< GwfStoType object
286  integer(I4B), intent(in) :: kiter !< outer iteration number
287  real(DP), intent(in), dimension(:) :: hold !< previous heads
288  real(DP), intent(in), dimension(:) :: hnew !< current heads
289  class(matrixbasetype), pointer :: matrix_sln !< A matrix
290  integer(I4B), intent(in), dimension(:) :: idxglo !< global index model to solution
291  real(DP), intent(inout), dimension(:) :: rhs !< right-hand side
292  ! -- local variables
293  integer(I4B) :: n
294  integer(I4B) :: idiag
295  real(DP) :: tled
296  real(DP) :: sc1
297  real(DP) :: sc2
298  real(DP) :: rho1
299  real(DP) :: rho2
300  real(DP) :: sc1old
301  real(DP) :: sc2old
302  real(DP) :: rho1old
303  real(DP) :: rho2old
304  real(DP) :: tp
305  real(DP) :: bt
306  real(DP) :: snold
307  real(DP) :: snnew
308  real(DP) :: aterm
309  real(DP) :: rhsterm
310  ! -- formats
311  character(len=*), parameter :: fmtsperror = &
312  &"('DETECTED TIME STEP LENGTH OF ZERO. GWF STORAGE PACKAGE CANNOT BE ', &
313  &'USED UNLESS DELT IS NON-ZERO.')"
314  !
315  ! -- test if steady-state stress period
316  if (this%iss /= 0) return
317  !
318  ! -- Ensure time step length is not zero
319  if (delt == dzero) then
320  write (errmsg, fmtsperror)
321  call store_error(errmsg, terminate=.true.)
322  end if
323  !
324  ! -- set variables
325  tled = done / delt
326  !
327  ! -- loop through and calculate storage contribution to hcof and rhs
328  do n = 1, this%dis%nodes
329  idiag = this%dis%con%ia(n)
330  if (this%ibound(n) < 1) cycle
331  !
332  ! -- aquifer elevations and thickness
333  tp = this%dis%top(n)
334  bt = this%dis%bot(n)
335  !
336  ! -- aquifer saturation
337  if (this%iconvert(n) == 0) then
338  snold = done
339  snnew = done
340  else
341  snold = squadraticsaturation(tp, bt, hold(n), this%satomega)
342  snnew = squadraticsaturation(tp, bt, hnew(n), this%satomega)
343  end if
344  !
345  ! -- storage coefficients
346  sc1 = sscapacity(this%istor_coef, tp, bt, this%dis%area(n), this%ss(n))
347  rho1 = sc1 * tled
348  !
349  if (this%integratechanges /= 0) then
350  ! -- Integration of storage changes (e.g. when using TVS):
351  ! separate the old (start of time step) and new (end of time step)
352  ! primary storage capacities
353  sc1old = sscapacity(this%istor_coef, tp, bt, this%dis%area(n), &
354  this%oldss(n))
355  rho1old = sc1old * tled
356  else
357  ! -- No integration of storage changes: old and new values are
358  ! identical => normal MF6 storage formulation
359  rho1old = rho1
360  end if
361  !
362  ! -- calculate specific storage terms
363  call ssterms(this%iconvert(n), this%iorig_ss, this%iconf_ss, tp, bt, &
364  rho1, rho1old, snnew, snold, hnew(n), hold(n), &
365  aterm, rhsterm)
366  !
367  ! -- add specific storage terms to amat and rhs
368  call matrix_sln%add_value_pos(idxglo(idiag), aterm)
369  rhs(n) = rhs(n) + rhsterm
370  !
371  ! -- specific yield
372  if (this%iconvert(n) /= 0) then
373  rhsterm = dzero
374  !
375  ! -- secondary storage coefficient
376  sc2 = sycapacity(this%dis%area(n), this%sy(n))
377  rho2 = sc2 * tled
378  !
379  if (this%integratechanges /= 0) then
380  ! -- Integration of storage changes (e.g. when using TVS):
381  ! separate the old (start of time step) and new (end of time step)
382  ! secondary storage capacities
383  sc2old = sycapacity(this%dis%area(n), this%oldsy(n))
384  rho2old = sc2old * tled
385  else
386  ! -- No integration of storage changes: old and new values are
387  ! identical => normal MF6 storage formulation
388  rho2old = rho2
389  end if
390  !
391  ! -- calculate specific storage terms
392  call syterms(tp, bt, rho2, rho2old, snnew, snold, &
393  aterm, rhsterm)
394 !
395  ! -- add specific yield terms to amat and rhs
396  call matrix_sln%add_value_pos(idxglo(idiag), aterm)
397  rhs(n) = rhs(n) + rhsterm
398  end if
399  end do
400  !
401  ! -- return
402  return
403  end subroutine sto_fc
404 
405  !> @ brief Fill Newton-Raphson terms in A and right-hand side for the package
406  !!
407  !! Fill the coefficient matrix and right-hand side with STO package
408  !! with Newton-Raphson terms.
409  !!
410  !<
411  subroutine sto_fn(this, kiter, hold, hnew, matrix_sln, idxglo, rhs)
412  ! -- modules
413  use tdismodule, only: delt
414  ! -- dummy variables
415  class(gwfstotype) :: this !< GwfStoType object
416  integer(I4B), intent(in) :: kiter !< outer iteration number
417  real(DP), intent(in), dimension(:) :: hold !< previous heads
418  real(DP), intent(in), dimension(:) :: hnew !< current heads
419  class(matrixbasetype), pointer :: matrix_sln !< A matrix
420  integer(I4B), intent(in), dimension(:) :: idxglo !< global index model to solution
421  real(DP), intent(inout), dimension(:) :: rhs !< right-hand side
422  ! -- local variables
423  integer(I4B) :: n
424  integer(I4B) :: idiag
425  real(DP) :: tled
426  real(DP) :: sc1
427  real(DP) :: sc2
428  real(DP) :: rho1
429  real(DP) :: rho2
430  real(DP) :: tp
431  real(DP) :: bt
432  real(DP) :: tthk
433  real(DP) :: h
434  real(DP) :: snnew
435  real(DP) :: derv
436  real(DP) :: rterm
437  real(DP) :: drterm
438  !
439  ! -- test if steady-state stress period
440  if (this%iss /= 0) return
441  !
442  ! -- set variables
443  tled = done / delt
444  !
445  ! -- loop through and calculate storage contribution to hcof and rhs
446  do n = 1, this%dis%nodes
447  idiag = this%dis%con%ia(n)
448  if (this%ibound(n) <= 0) cycle
449  !
450  ! -- aquifer elevations and thickness
451  tp = this%dis%top(n)
452  bt = this%dis%bot(n)
453  tthk = tp - bt
454  h = hnew(n)
455  !
456  ! -- aquifer saturation
457  snnew = squadraticsaturation(tp, bt, h)
458  !
459  ! -- storage coefficients
460  sc1 = sscapacity(this%istor_coef, tp, bt, this%dis%area(n), this%ss(n))
461  sc2 = sycapacity(this%dis%area(n), this%sy(n))
462  rho1 = sc1 * tled
463  rho2 = sc2 * tled
464  !
465  ! -- calculate newton terms for specific storage
466  ! and specific yield
467  if (this%iconvert(n) /= 0) then
468  !
469  ! -- calculate saturation derivative
470  derv = squadraticsaturationderivative(tp, bt, h)
471  !
472  ! -- newton terms for specific storage
473  if (this%iconf_ss == 0) then
474  if (this%iorig_ss == 0) then
475  drterm = -rho1 * derv * (h - bt) + rho1 * tthk * snnew * derv
476  else
477  drterm = -(rho1 * derv * h)
478  end if
479  call matrix_sln%add_value_pos(idxglo(idiag), drterm)
480  rhs(n) = rhs(n) + drterm * h
481  end if
482  !
483  ! -- newton terms for specific yield
484  ! only calculated if the current saturation
485  ! is less than one
486  if (snnew < done) then
487  ! -- calculate newton terms for specific yield
488  if (snnew > dzero) then
489  rterm = -rho2 * tthk * snnew
490  drterm = -rho2 * tthk * derv
491  call matrix_sln%add_value_pos(idxglo(idiag), drterm + rho2)
492  rhs(n) = rhs(n) - rterm + drterm * h + rho2 * bt
493  end if
494  end if
495  end if
496  end do
497  !
498  ! -- return
499  return
500  end subroutine sto_fn
501 
502  !> @ brief Calculate flows for package
503  !!
504  !! Flow calculation for the STO package components. Components include
505  !! specific storage and specific yield storage.
506  !!
507  !<
508  subroutine sto_cq(this, flowja, hnew, hold)
509  ! -- modules
510  use tdismodule, only: delt
511  ! -- dummy variables
512  class(gwfstotype) :: this !< GwfStoType object
513  real(DP), dimension(:), contiguous, intent(inout) :: flowja !< connection flows
514  real(DP), dimension(:), contiguous, intent(in) :: hnew !< current head
515  real(DP), dimension(:), contiguous, intent(in) :: hold !< previous head
516  ! -- local variables
517  integer(I4B) :: n
518  integer(I4B) :: idiag
519  real(DP) :: rate
520  real(DP) :: tled
521  real(DP) :: sc1
522  real(DP) :: sc2
523  real(DP) :: rho1
524  real(DP) :: rho2
525  real(DP) :: sc1old
526  real(DP) :: sc2old
527  real(DP) :: rho1old
528  real(DP) :: rho2old
529  real(DP) :: tp
530  real(DP) :: bt
531  real(DP) :: snold
532  real(DP) :: snnew
533  real(DP) :: aterm
534  real(DP) :: rhsterm
535  !
536  ! -- initialize strg arrays
537  do n = 1, this%dis%nodes
538  this%strgss(n) = dzero
539  this%strgsy(n) = dzero
540  end do
541  !
542  ! -- Set strt to zero or calculate terms if not steady-state stress period
543  if (this%iss == 0) then
544  !
545  ! -- set variables
546  tled = done / delt
547  !
548  ! -- Calculate storage change
549  do n = 1, this%dis%nodes
550  if (this%ibound(n) <= 0) cycle
551  ! -- aquifer elevations and thickness
552  tp = this%dis%top(n)
553  bt = this%dis%bot(n)
554  !
555  ! -- aquifer saturation
556  if (this%iconvert(n) == 0) then
557  snold = done
558  snnew = done
559  else
560  snold = squadraticsaturation(tp, bt, hold(n), this%satomega)
561  snnew = squadraticsaturation(tp, bt, hnew(n), this%satomega)
562  end if
563  !
564  ! -- primary storage coefficient
565  sc1 = sscapacity(this%istor_coef, tp, bt, this%dis%area(n), this%ss(n))
566  rho1 = sc1 * tled
567  !
568  if (this%integratechanges /= 0) then
569  ! -- Integration of storage changes (e.g. when using TVS):
570  ! separate the old (start of time step) and new (end of time step)
571  ! primary storage capacities
572  sc1old = sscapacity(this%istor_coef, tp, bt, this%dis%area(n), &
573  this%oldss(n))
574  rho1old = sc1old * tled
575  else
576  ! -- No integration of storage changes: old and new values are
577  ! identical => normal MF6 storage formulation
578  rho1old = rho1
579  end if
580  !
581  ! -- calculate specific storage terms and rate
582  call ssterms(this%iconvert(n), this%iorig_ss, this%iconf_ss, tp, bt, &
583  rho1, rho1old, snnew, snold, hnew(n), hold(n), &
584  aterm, rhsterm, rate)
585  !
586  ! -- save rate
587  this%strgss(n) = rate
588  !
589  ! -- add storage term to flowja
590  idiag = this%dis%con%ia(n)
591  flowja(idiag) = flowja(idiag) + rate
592  !
593  ! -- specific yield
594  rate = dzero
595  if (this%iconvert(n) /= 0) then
596  !
597  ! -- secondary storage coefficient
598  sc2 = sycapacity(this%dis%area(n), this%sy(n))
599  rho2 = sc2 * tled
600  !
601  if (this%integratechanges /= 0) then
602  ! -- Integration of storage changes (e.g. when using TVS):
603  ! separate the old (start of time step) and new (end of time
604  ! step) secondary storage capacities
605  sc2old = sycapacity(this%dis%area(n), this%oldsy(n))
606  rho2old = sc2old * tled
607  else
608  ! -- No integration of storage changes: old and new values are
609  ! identical => normal MF6 storage formulation
610  rho2old = rho2
611  end if
612  !
613  ! -- calculate specific yield storage terms and rate
614  call syterms(tp, bt, rho2, rho2old, snnew, snold, &
615  aterm, rhsterm, rate)
616 
617  end if
618  this%strgsy(n) = rate
619  !
620  ! -- add storage term to flowja
621  idiag = this%dis%con%ia(n)
622  flowja(idiag) = flowja(idiag) + rate
623  end do
624  end if
625  !
626  ! -- return
627  return
628  end subroutine sto_cq
629 
630  !> @ brief Model budget calculation for package
631  !!
632  !! Budget calculation for the STO package components. Components include
633  !! specific storage and specific yield storage.
634  !!
635  !<
636  subroutine sto_bd(this, isuppress_output, model_budget)
637  ! -- modules
638  use tdismodule, only: delt
640  ! -- dummy variables
641  class(gwfstotype) :: this !< GwfStoType object
642  integer(I4B), intent(in) :: isuppress_output !< flag to suppress model output
643  type(budgettype), intent(inout) :: model_budget !< model budget object
644  ! -- local variables
645  real(DP) :: rin
646  real(DP) :: rout
647  !
648  ! -- Add confined storage rates to model budget
649  call rate_accumulator(this%strgss, rin, rout)
650  call model_budget%addentry(rin, rout, delt, budtxt(1), &
651  isuppress_output, ' STORAGE')
652  !
653  ! -- Add unconfined storage rates to model budget
654  if (this%iusesy == 1) then
655  call rate_accumulator(this%strgsy, rin, rout)
656  call model_budget%addentry(rin, rout, delt, budtxt(2), &
657  isuppress_output, ' STORAGE')
658  end if
659  !
660  ! -- return
661  return
662  end subroutine sto_bd
663 
664  !> @ brief Save model flows for package
665  !!
666  !! Save cell-by-cell budget terms for the STO package.
667  !!
668  !<
669  subroutine sto_save_model_flows(this, icbcfl, icbcun)
670  ! -- dummy variables
671  class(gwfstotype) :: this !< GwfStoType object
672  integer(I4B), intent(in) :: icbcfl !< flag to output budget data
673  integer(I4B), intent(in) :: icbcun !< cell-by-cell file unit number
674  ! -- local variables
675  integer(I4B) :: ibinun
676  integer(I4B) :: iprint, nvaluesp, nwidthp
677  character(len=1) :: cdatafmp = ' ', editdesc = ' '
678  real(DP) :: dinact
679  !
680  ! -- Set unit number for binary output
681  if (this%ipakcb < 0) then
682  ibinun = icbcun
683  elseif (this%ipakcb == 0) then
684  ibinun = 0
685  else
686  ibinun = this%ipakcb
687  end if
688  if (icbcfl == 0) ibinun = 0
689  !
690  ! -- Record the storage rates if requested
691  if (ibinun /= 0) then
692  iprint = 0
693  dinact = dzero
694  !
695  ! -- storage(ss)
696  call this%dis%record_array(this%strgss, this%iout, iprint, -ibinun, &
697  budtxt(1), cdatafmp, nvaluesp, &
698  nwidthp, editdesc, dinact)
699  !
700  ! -- storage(sy)
701  if (this%iusesy == 1) then
702  call this%dis%record_array(this%strgsy, this%iout, iprint, -ibinun, &
703  budtxt(2), cdatafmp, nvaluesp, &
704  nwidthp, editdesc, dinact)
705  end if
706  end if
707  !
708  ! -- return
709  return
710  end subroutine sto_save_model_flows
711 
712  !> @ brief Deallocate package memory
713  !!
714  !! Deallocate STO package scalars and arrays.
715  !!
716  !<
717  subroutine sto_da(this)
718  ! -- modules
720  ! -- dummy variables
721  class(gwfstotype) :: this !< GwfStoType object
722  !
723  ! -- TVS
724  if (this%intvs /= 0) then
725  call this%tvs%da()
726  deallocate (this%tvs)
727  end if
728  !
729  ! -- Deallocate arrays if package is active
730  if (this%inunit > 0) then
731  call mem_deallocate(this%iconvert)
732  call mem_deallocate(this%ss)
733  call mem_deallocate(this%sy)
734  call mem_deallocate(this%strgss)
735  call mem_deallocate(this%strgsy)
736  !
737  ! -- deallocate TVS arrays
738  if (associated(this%oldss)) then
739  call mem_deallocate(this%oldss)
740  end if
741  if (associated(this%oldsy)) then
742  call mem_deallocate(this%oldsy)
743  end if
744  end if
745  !
746  ! -- Deallocate scalars
747  call mem_deallocate(this%istor_coef)
748  call mem_deallocate(this%iconf_ss)
749  call mem_deallocate(this%iorig_ss)
750  call mem_deallocate(this%iusesy)
751  call mem_deallocate(this%satomega)
752  call mem_deallocate(this%integratechanges)
753  call mem_deallocate(this%intvs)
754  !
755  ! -- deallocate parent
756  call this%NumericalPackageType%da()
757  !
758  ! -- return
759  return
760  end subroutine sto_da
761 
762  !> @ brief Allocate scalars
763  !!
764  !! Allocate and initialize scalars for the STO package. The base numerical
765  !! package allocate scalars method is also called.
766  !!
767  !<
768  subroutine allocate_scalars(this)
769  ! -- modules
771  ! -- dummy variables
772  class(gwfstotype) :: this !< GwfStoType object
773  !
774  ! -- allocate scalars in NumericalPackageType
775  call this%NumericalPackageType%allocate_scalars()
776  !
777  ! -- allocate scalars
778  call mem_allocate(this%istor_coef, 'ISTOR_COEF', this%memoryPath)
779  call mem_allocate(this%iconf_ss, 'ICONF_SS', this%memoryPath)
780  call mem_allocate(this%iorig_ss, 'IORIG_SS', this%memoryPath)
781  call mem_allocate(this%iusesy, 'IUSESY', this%memoryPath)
782  call mem_allocate(this%satomega, 'SATOMEGA', this%memoryPath)
783  call mem_allocate(this%integratechanges, 'INTEGRATECHANGES', &
784  this%memoryPath)
785  call mem_allocate(this%intvs, 'INTVS', this%memoryPath)
786  !
787  ! -- initialize scalars
788  this%istor_coef = 0
789  this%iconf_ss = 0
790  this%iorig_ss = 0
791  this%iusesy = 0
792  this%satomega = dzero
793  this%integratechanges = 0
794  this%intvs = 0
795  !
796  ! -- return
797  return
798  end subroutine allocate_scalars
799 
800  !> @ brief Allocate package arrays
801  !!
802  !! Allocate and initialize STO package arrays.
803  !!
804  !<
805  subroutine allocate_arrays(this, nodes)
806  ! -- modules
808  ! -- dummy variables
809  class(gwfstotype), target :: this !< GwfStoType object
810  integer(I4B), intent(in) :: nodes !< active model nodes
811  ! -- local variables
812  integer(I4B) :: n
813  !
814  ! -- Allocate arrays
815  call mem_allocate(this%iconvert, nodes, 'ICONVERT', this%memoryPath)
816  call mem_allocate(this%ss, nodes, 'SS', this%memoryPath)
817  call mem_allocate(this%sy, nodes, 'SY', this%memoryPath)
818  call mem_allocate(this%strgss, nodes, 'STRGSS', this%memoryPath)
819  call mem_allocate(this%strgsy, nodes, 'STRGSY', this%memoryPath)
820  !
821  ! -- Initialize arrays
822  this%iss = 0
823  do n = 1, nodes
824  this%iconvert(n) = 1
825  this%ss(n) = dzero
826  this%sy(n) = dzero
827  this%strgss(n) = dzero
828  this%strgsy(n) = dzero
829  if (this%integratechanges /= 0) then
830  this%oldss(n) = dzero
831  if (this%iusesy /= 0) then
832  this%oldsy(n) = dzero
833  end if
834  end if
835  end do
836  !
837  ! -- return
838  return
839  end subroutine allocate_arrays
840 
841  !> @ brief Read options for package
842  !!
843  !! Read options block for STO package.
844  !!
845  !<
846  subroutine read_options(this)
847  ! -- modules
848  ! -- dummy variables
849  class(gwfstotype) :: this !< GwfStoType object
850  ! -- local variables
851  character(len=LINELENGTH) :: keyword, fname
852  integer(I4B) :: ierr
853  logical :: isfound, endOfBlock
854  ! -- formats
855  character(len=*), parameter :: fmtisvflow = &
856  "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE &
857  &WHENEVER ICBCFL IS NOT ZERO.')"
858  character(len=*), parameter :: fmtflow = &
859  &"(4x, 'FLOWS WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I7)"
860  character(len=*), parameter :: fmtorigss = &
861  "(4X,'ORIGINAL_SPECIFIC_STORAGE OPTION:',/, &
862  &1X,'The original specific storage formulation will be used')"
863  character(len=*), parameter :: fmtstoc = &
864  "(4X,'STORAGECOEFFICIENT OPTION:',/, &
865  &1X,'Read storage coefficient rather than specific storage')"
866  character(len=*), parameter :: fmtconfss = &
867  "(4X,'SS_CONFINED_ONLY OPTION:',/, &
868  &1X,'Specific storage changes only occur under confined conditions')"
869  !
870  ! -- get options block
871  call this%parser%GetBlock('OPTIONS', isfound, ierr, &
872  supportopenclose=.true., blockrequired=.false.)
873  !
874  ! -- parse options block if detected
875  if (isfound) then
876  write (this%iout, '(1x,a)') 'PROCESSING STORAGE OPTIONS'
877  do
878  call this%parser%GetNextLine(endofblock)
879  if (endofblock) exit
880  call this%parser%GetStringCaps(keyword)
881  select case (keyword)
882  case ('SAVE_FLOWS')
883  this%ipakcb = -1
884  write (this%iout, fmtisvflow)
885  case ('STORAGECOEFFICIENT')
886  this%istor_coef = 1
887  write (this%iout, fmtstoc)
888  case ('SS_CONFINED_ONLY')
889  this%iconf_ss = 1
890  this%iorig_ss = 0
891  write (this%iout, fmtconfss)
892  case ('TVS6')
893  if (this%intvs /= 0) then
894  errmsg = 'Multiple TVS6 keywords detected in OPTIONS block.'// &
895  ' Only one TVS6 entry allowed.'
896  call store_error(errmsg, terminate=.true.)
897  end if
898  call this%parser%GetStringCaps(keyword)
899  if (trim(adjustl(keyword)) /= 'FILEIN') then
900  errmsg = 'TVS6 keyword must be followed by "FILEIN" '// &
901  'then by filename.'
902  call store_error(errmsg, terminate=.true.)
903  end if
904  call this%parser%GetString(fname)
905  this%intvs = getunit()
906  call openfile(this%intvs, this%iout, fname, 'TVS')
907  call tvs_cr(this%tvs, this%name_model, this%intvs, this%iout)
908  !
909  ! -- right now these are options that are only available in the
910  ! development version and are not included in the documentation.
911  ! These options are only available when IDEVELOPMODE in
912  ! constants module is set to 1
913  case ('DEV_ORIGINAL_SPECIFIC_STORAGE')
914  this%iorig_ss = 1
915  write (this%iout, fmtorigss)
916  case ('DEV_OLDSTORAGEFORMULATION')
917  call this%parser%DevOpt()
918  this%iconf_ss = 1
919  this%iorig_ss = 0
920  write (this%iout, fmtconfss)
921  case default
922  write (errmsg, '(a,a)') 'Unknown STO option: ', &
923  trim(keyword)
924  call store_error(errmsg, terminate=.true.)
925  end select
926  end do
927  write (this%iout, '(1x,a)') 'END OF STORAGE OPTIONS'
928  end if
929  !
930  ! -- set omega value used for saturation calculations
931  if (this%inewton > 0) then
932  this%satomega = dem6
933  end if
934  !
935  ! -- return
936  return
937  end subroutine read_options
938 
939  !> @ brief Read data for package
940  !!
941  !! Read griddata block for STO package.
942  !!
943  !<
944  subroutine read_data(this)
945  ! -- modules
946  ! -- dummy variables
947  class(gwfstotype) :: this !< GwfStoType object
948  ! -- local variables
949  character(len=LINELENGTH) :: keyword
950  character(len=:), allocatable :: line
951  character(len=LINELENGTH) :: cellstr
952  integer(I4B) :: istart, istop, lloc, ierr
953  logical :: isfound, endOfBlock
954  logical :: readiconv
955  logical :: readss
956  logical :: readsy
957  logical :: isconv
958  character(len=24), dimension(4) :: aname
959  integer(I4B) :: n
960  ! -- formats
961  !data
962  data aname(1)/' ICONVERT'/
963  data aname(2)/' SPECIFIC STORAGE'/
964  data aname(3)/' SPECIFIC YIELD'/
965  data aname(4)/' STORAGE COEFFICIENT'/
966  !
967  ! -- initialize
968  isfound = .false.
969  readiconv = .false.
970  readss = .false.
971  readsy = .false.
972  isconv = .false.
973  !
974  ! -- get stodata block
975  call this%parser%GetBlock('GRIDDATA', isfound, ierr)
976  if (isfound) then
977  write (this%iout, '(1x,a)') 'PROCESSING GRIDDATA'
978  do
979  call this%parser%GetNextLine(endofblock)
980  if (endofblock) exit
981  call this%parser%GetStringCaps(keyword)
982  call this%parser%GetRemainingLine(line)
983  lloc = 1
984  select case (keyword)
985  case ('ICONVERT')
986  call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, &
987  this%parser%iuactive, this%iconvert, &
988  aname(1))
989  readiconv = .true.
990  case ('SS')
991  call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, &
992  this%parser%iuactive, this%ss, &
993  aname(2))
994  readss = .true.
995  case ('SY')
996  call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, &
997  this%parser%iuactive, this%sy, &
998  aname(3))
999  readsy = .true.
1000  case default
1001  write (errmsg, '(a,a)') 'Unknown GRIDDATA tag: ', &
1002  trim(keyword)
1003  call store_error(errmsg)
1004  call this%parser%StoreErrorUnit()
1005  end select
1006  end do
1007  write (this%iout, '(1x,a)') 'END PROCESSING GRIDDATA'
1008  else
1009  write (errmsg, '(a)') 'Required GRIDDATA block not found.'
1010  call store_error(errmsg)
1011  call this%parser%StoreErrorUnit()
1012  end if
1013  !
1014  ! -- Check for ICONVERT
1015  if (.not. readiconv) then
1016  write (errmsg, '(a, a, a)') 'Error in GRIDDATA block: ', &
1017  trim(adjustl(aname(1))), ' not found.'
1018  call store_error(errmsg)
1019  else
1020  isconv = .false.
1021  do n = 1, this%dis%nodes
1022  if (this%iconvert(n) /= 0) then
1023  isconv = .true.
1024  this%iusesy = 1
1025  exit
1026  end if
1027  end do
1028  end if
1029  !
1030  ! -- Check for SS
1031  if (.not. readss) then
1032  write (errmsg, '(a, a, a)') 'Error in GRIDDATA block: ', &
1033  trim(adjustl(aname(2))), ' not found.'
1034  call store_error(errmsg)
1035  end if
1036  !
1037  ! -- Check for SY
1038  if (.not. readsy .and. isconv) then
1039  write (errmsg, '(a, a, a)') 'Error in GRIDDATA block: ', &
1040  trim(adjustl(aname(3))), ' not found.'
1041  call store_error(errmsg)
1042  end if
1043  !
1044  if (count_errors() > 0) then
1045  call this%parser%StoreErrorUnit()
1046  end if
1047  !
1048  ! -- Check SS and SY for negative values
1049  do n = 1, this%dis%nodes
1050  if (this%ss(n) < dzero) then
1051  call this%dis%noder_to_string(n, cellstr)
1052  write (errmsg, '(a,2(1x,a),1x,g0,1x,a)') &
1053  'Error in SS DATA: SS value in cell', trim(adjustl(cellstr)), &
1054  'is less than zero (', this%ss(n), ').'
1055  call store_error(errmsg)
1056  end if
1057  if (readsy) then
1058  if (this%sy(n) < dzero) then
1059  call this%dis%noder_to_string(n, cellstr)
1060  write (errmsg, '(a,2(1x,a),1x,g0,1x,a)') &
1061  'Error in SY DATA: SY value in cell', trim(adjustl(cellstr)), &
1062  'is less than zero (', this%sy(n), ').'
1063  call store_error(errmsg)
1064  end if
1065  end if
1066  end do
1067  !
1068  ! -- return
1069  return
1070  end subroutine read_data
1071 
1072  !> @ brief Save old storage property values
1073  !!
1074  !! Save ss and sy values from the previous time step for use with storage
1075  !! integration when integratechanges is non-zero.
1076  !!
1077  !<
1078  subroutine save_old_ss_sy(this)
1079  ! -- modules
1081  ! -- dummy variables
1082  class(gwfstotype) :: this !< GwfStoType object
1083  ! -- local variables
1084  integer(I4B) :: n
1085  !
1086  ! -- Allocate TVS arrays if needed
1087  if (.not. associated(this%oldss)) then
1088  call mem_allocate(this%oldss, this%dis%nodes, 'OLDSS', this%memoryPath)
1089  end if
1090  if (this%iusesy == 1 .and. .not. associated(this%oldsy)) then
1091  call mem_allocate(this%oldsy, this%dis%nodes, 'OLDSY', this%memoryPath)
1092  end if
1093  !
1094  ! -- Save current specific storage
1095  do n = 1, this%dis%nodes
1096  this%oldss(n) = this%ss(n)
1097  end do
1098  !
1099  ! -- Save current specific yield, if used
1100  if (this%iusesy == 1) then
1101  do n = 1, this%dis%nodes
1102  this%oldsy(n) = this%sy(n)
1103  end do
1104  end if
1105  !
1106  ! -- Return
1107  return
1108  end subroutine save_old_ss_sy
1109 
1110 end module gwfstomodule
This module contains block parser methods.
Definition: BlockParser.f90:7
This module contains the BudgetModule.
Definition: Budget.f90:20
subroutine, public rate_accumulator(flow, rin, rout)
@ brief Rate accumulator subroutine
Definition: Budget.f90:664
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:44
real(dp), parameter dhalf
real constant 1/2
Definition: Constants.f90:67
real(dp), parameter dem4
real constant 1e-4
Definition: Constants.f90:106
real(dp), parameter dem6
real constant 1e-6
Definition: Constants.f90:108
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:64
real(dp), parameter dtwo
real constant 2
Definition: Constants.f90:78
integer(i4b), parameter lenbudtxt
maximum length of a budget component names
Definition: Constants.f90:36
real(dp), parameter done
real constant 1
Definition: Constants.f90:75
This module contains the storage package methods.
Definition: gwf-sto.f90:8
subroutine sto_bd(this, isuppress_output, model_budget)
@ brief Model budget calculation for package
Definition: gwf-sto.f90:637
subroutine read_data(this)
@ brief Read data for package
Definition: gwf-sto.f90:945
subroutine, public sto_cr(stoobj, name_model, inunit, iout)
@ brief Create a new package object
Definition: gwf-sto.f90:76
subroutine sto_ar(this, dis, ibound)
@ brief Allocate and read method for package
Definition: gwf-sto.f90:108
subroutine sto_da(this)
@ brief Deallocate package memory
Definition: gwf-sto.f90:718
subroutine sto_fc(this, kiter, hold, hnew, matrix_sln, idxglo, rhs)
@ brief Fill A and right-hand side for the package
Definition: gwf-sto.f90:282
subroutine read_options(this)
@ brief Read options for package
Definition: gwf-sto.f90:847
subroutine sto_fn(this, kiter, hold, hnew, matrix_sln, idxglo, rhs)
@ brief Fill Newton-Raphson terms in A and right-hand side for the package
Definition: gwf-sto.f90:412
subroutine sto_rp(this)
@ brief Read and prepare method for package
Definition: gwf-sto.f90:158
subroutine sto_cq(this, flowja, hnew, hold)
@ brief Calculate flows for package
Definition: gwf-sto.f90:509
subroutine save_old_ss_sy(this)
@ brief Save old storage property values
Definition: gwf-sto.f90:1079
subroutine sto_save_model_flows(this, icbcfl, icbcun)
@ brief Save model flows for package
Definition: gwf-sto.f90:670
subroutine allocate_scalars(this)
@ brief Allocate scalars
Definition: gwf-sto.f90:769
subroutine allocate_arrays(this, nodes)
@ brief Allocate package arrays
Definition: gwf-sto.f90:806
subroutine sto_ad(this)
@ brief Advance the package
Definition: gwf-sto.f90:257
character(len=lenbudtxt), dimension(2) budtxt
Definition: gwf-sto.f90:29
This module contains stateless storage subroutines and functions.
pure real(dp) function, public sycapacity(area, sy)
Calculate the specific yield capacity.
pure subroutine, public syterms(top, bot, rho2, rho2old, snnew, snold, aterm, rhsterm, rate)
Calculate the specific yield storage terms.
pure subroutine, public ssterms(iconvert, iorig_ss, iconf_ss, top, bot, rho1, rho1old, snnew, snold, hnew, hold, aterm, rhsterm, rate)
Calculate the specific storage terms.
pure real(dp) function, public sscapacity(istor_coef, top, bot, area, ss)
Calculate the specific storage capacity.
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
character(len=lenmempath) function create_mem_path(component, subcomponent, context)
returns the path to the memory object
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
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string
real(dp) function squadraticsaturation(top, bot, x, eps)
@ brief sQuadraticSaturation
real(dp) function slinearsaturation(top, bot, x)
@ brief sLinearSaturation
real(dp) function squadraticsaturationderivative(top, bot, x, eps)
@ brief Derivative of the quadratic saturation function
real(dp) function sqsaturation(top, bot, x, c1, c2)
@ brief sQSaturation
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
integer(i4b), pointer, public nper
number of stress period
Definition: tdis.f90:21
This module contains the time-varying storage package methods.
Definition: gwf-tvs.f90:8
subroutine, public tvs_cr(tvs, name_model, inunit, iout)
Create a new TvsType object.
Definition: gwf-tvs.f90:49
Derived type for the Budget object.
Definition: Budget.f90:39