MODFLOW 6  version 6.6.0.dev0
USGS Modular Hydrologic Model
gwf-vsc.f90
Go to the documentation of this file.
1 ! Viscosity Package for representing variable-viscosity groundwater flow
2 
4 
5  use kindmodule, only: dp, i4b
12  use tdismodule, only: kper, kstp
14  use basedismodule, only: disbasetype
16  use listsmodule, only: basemodellist
17 
18  implicit none
19 
20  private
21  public :: gwfvsctype
22  public :: vsc_cr
23 
25  real(dp), dimension(:), pointer :: conc => null() !< pointer to concentration array
26  integer(I4B), dimension(:), pointer :: icbund => null() !< store pointer to gwt ibound array
27  end type concentrationpointer
28 
29  type, extends(numericalpackagetype) :: gwfvsctype
30  integer(I4B), pointer :: thermivisc => null() !< viscosity formulation flag (1:Linear, 2:Nonlinear)
31  integer(I4B), pointer :: idxtmpr => null() !< if greater than 0 then an index for identifying whether the "species" array is temperature
32  integer(I4B), pointer :: ioutvisc => null() !< unit number for saving viscosity
33  integer(I4B), pointer :: iconcset => null() !< if 1 then conc points to a gwt (or gwe) model%x array
34  integer(I4B), pointer :: ireadelev => null() !< if 1 then elev has been allocated and filled
35  integer(I4B), dimension(:), pointer, contiguous :: ivisc => null() !< viscosity formulation flag for each species (1:Linear, 2:Nonlinear)
36  real(dp), pointer :: viscref => null() !< reference fluid viscosity
37  real(dp), dimension(:), pointer, contiguous :: visc => null() !< viscosity
38  real(dp), dimension(:), pointer, contiguous :: elev => null() !< cell center elevation (optional; if not specified, then use (top+bot)/2)
39  integer(I4B), dimension(:), pointer :: ibound => null() !< store pointer to ibound
40 
41  integer(I4B), pointer :: nviscspecies => null() !< number of concentration species used in viscosity equation
42  real(dp), dimension(:), pointer, contiguous :: dviscdc => null() !< linear change in viscosity with change in concentration
43  real(dp), dimension(:), pointer, contiguous :: cviscref => null() !< reference concentration used in viscosity equation
44  real(dp), dimension(:), pointer, contiguous :: ctemp => null() !< temporary array of size (nviscspec) to pass to calc_visc_x
45  character(len=LENMODELNAME), dimension(:), allocatable :: cmodelname !< names of gwt (or gwe) models used in viscosity equation
46  character(len=LENAUXNAME), dimension(:), allocatable :: cauxspeciesname !< names of aux columns used in viscosity equation
47  character(len=LENAUXNAME) :: name_temp_spec = 'TEMPERATURE'
48  !
49  ! -- Viscosity constants
50  real(dp), pointer :: a2 => null() !< an empirical parameter specified by the user for calculating viscosity
51  real(dp), pointer :: a3 => null() !< an empirical parameter specified by the user for calculating viscosity
52  real(dp), pointer :: a4 => null() !< an empirical parameter specified by the user for calculating viscosity
53 
54  type(concentrationpointer), allocatable, dimension(:) :: modelconc !< concentration (or temperature) pointer for each solute (or heat) transport model
55 
56  real(dp), dimension(:), pointer, contiguous :: k11 => null() !< NPF hydraulic conductivity; if anisotropic, then this is Kx prior to rotation
57  real(dp), dimension(:), pointer, contiguous :: k22 => null() !< NPF hydraulic conductivity; if specified then this is Ky prior to rotation
58  real(dp), dimension(:), pointer, contiguous :: k33 => null() !< NPF hydraulic conductivity; if specified then this is Kz prior to rotation
59  real(dp), dimension(:), pointer, contiguous :: k11input => null() !< NPF hydraulic conductivity as originally specified by the user
60  real(dp), dimension(:), pointer, contiguous :: k22input => null() !< NPF hydraulic conductivity as originally specified by the user
61  real(dp), dimension(:), pointer, contiguous :: k33input => null() !< NPF hydraulic conductivity as originally specified by the user
62  integer(I4B), pointer :: kchangeper => null() ! last stress period in which any node K (or K22, or K33) values were changed (0 if unchanged from start of simulation)
63  integer(I4B), pointer :: kchangestp => null() ! last time step in which any node K (or K22, or K33) values were changed (0 if unchanged from start of simulation)
64  integer(I4B), dimension(:), pointer, contiguous :: nodekchange => null() ! grid array of flags indicating for each node whether its K (or K22, or K33) value changed (1) at (kchangeper, kchangestp) or not (0)
65 
66  contains
67 
68  procedure :: vsc_df
69  procedure :: vsc_ar
70  procedure, public :: vsc_ar_bnd
71  procedure :: vsc_rp
72  procedure :: vsc_ad
73  procedure, public :: vsc_ad_bnd
74  procedure :: vsc_ot_dv
75  procedure :: vsc_da
76  procedure, private :: vsc_calcvisc
77  procedure :: allocate_scalars
78  procedure, private :: allocate_arrays
79  procedure, private :: read_options
80  procedure, private :: set_options
81  procedure, private :: read_dimensions
82  procedure, private :: read_packagedata
83  procedure, private :: set_packagedata
84  procedure, private :: set_npf_pointers
85  procedure, public :: update_k_with_vsc
86  procedure, private :: vsc_set_changed_at
87  procedure, public :: calc_q_visc
88  procedure, public :: get_visc_ratio
90  end type gwfvsctype
91 
92 contains
93 
94  !> @brief Generic function to calculate changes in fluid viscosity using a
95  !! linear formulation
96  !<
97  function calc_visc(ivisc, viscref, dviscdc, cviscref, conc, &
98  a2, a3, a4) result(visc)
99  ! -- dummy
100  integer(I4B), dimension(:), intent(in) :: ivisc
101  real(dp), intent(in) :: viscref
102  real(dp), dimension(:), intent(in) :: dviscdc
103  real(dp), dimension(:), intent(in) :: cviscref
104  real(dp), dimension(:), intent(in) :: conc
105  real(dp), intent(in) :: a2, a3, a4
106  ! -- return
107  real(dp) :: visc
108  ! -- local
109  integer(I4B) :: nviscspec
110  integer(I4B) :: i
111  real(dp) :: mu_t
112  real(dp) :: expon
113  !
114  nviscspec = size(dviscdc)
115  visc = viscref
116  !
117  do i = 1, nviscspec
118  if (ivisc(i) == 1) then
119  visc = visc + dviscdc(i) * (conc(i) - cviscref(i))
120  else
121  expon = -1 * a3 * ((conc(i) - cviscref(i)) / &
122  ((conc(i) + a4) * (cviscref(i) + a4)))
123  mu_t = viscref * a2**expon
124  ! Order matters!! (This assumes we apply the temperature correction after
125  ! accounting for solute concentrations)
126  ! If a nonlinear correction is applied, then b/c it takes into account
127  ! viscref, need to subtract it in this case
128  ! At most, there will only ever be 1 nonlinear correction
129  visc = (visc - viscref) + mu_t
130  end if
131  ! end if
132  end do
133  end function calc_visc
134 
135  !> @ brief Create a new package object
136  !!
137  !! Create a new VSC Package object.
138  !<
139  subroutine vsc_cr(vscobj, name_model, inunit, iout)
140  ! -- dummy
141  type(gwfvsctype), pointer :: vscobj
142  character(len=*), intent(in) :: name_model
143  integer(I4B), intent(in) :: inunit
144  integer(I4B), intent(in) :: iout
145  !
146  ! -- Create the object
147  allocate (vscobj)
148  !
149  ! -- create name and memory path
150  call vscobj%set_names(1, name_model, 'VSC', 'VSC')
151  !
152  ! -- Allocate scalars
153  call vscobj%allocate_scalars()
154  !
155  ! -- Set variables
156  vscobj%inunit = inunit
157  vscobj%iout = iout
158  !
159  ! -- Initialize block parser
160  call vscobj%parser%Initialize(vscobj%inunit, vscobj%iout)
161  end subroutine vsc_cr
162 
163  !> @ brief Define viscosity package options and dimensions
164  !!
165  !! Define viscosity package options and dimensions
166  !<
167  subroutine vsc_df(this, dis, vsc_input)
168  ! -- dummy
169  class(gwfvsctype) :: this !< this viscosity package
170  class(disbasetype), pointer, intent(in) :: dis !< pointer to discretization
171  type(gwfvscinputdatatype), optional, intent(in) :: vsc_input !< optional vsc input data, otherwise read from file
172  ! -- formats
173  character(len=*), parameter :: fmtvsc = &
174  "(1x,/1x,'VSC -- Viscosity Package, version 1, 11/15/2022', &
175  &' input read from unit ', i0, //)"
176  !
177  ! --print a message identifying the viscosity package
178  write (this%iout, fmtvsc) this%inunit
179  !
180  ! -- store pointers to arguments that were passed in
181  this%dis => dis
182  !
183  if (.not. present(vsc_input)) then
184  !
185  ! -- Read viscosity options
186  call this%read_options()
187  !
188  ! -- Read viscosity dimensions
189  call this%read_dimensions()
190  else
191  ! set from input data instead
192  call this%set_options(vsc_input)
193  this%nviscspecies = vsc_input%nviscspecies
194  end if
195  !
196  ! -- Allocate arrays
197  call this%allocate_arrays(dis%nodes)
198  !
199  if (.not. present(vsc_input)) then
200  !
201  ! -- Read viscosity packagedata
202  call this%read_packagedata()
203  else
204  ! set from input data instead
205  call this%set_packagedata(vsc_input)
206  end if
207  end subroutine vsc_df
208 
209  !> @ brief Allocate and read method for viscosity package
210  !!
211  !! Generic method to allocate and read static data for the viscosity
212  !! package available within the GWF model type.
213  !<
214  subroutine vsc_ar(this, ibound)
215  ! -- dummy
216  class(gwfvsctype) :: this
217  integer(I4B), dimension(:), pointer :: ibound
218  !
219  ! -- store pointers to arguments that were passed in
220  this%ibound => ibound
221  !
222  ! -- Set pointers to npf variables
223  call this%set_npf_pointers()
224  end subroutine vsc_ar
225 
226  !> @brief Activate viscosity in advanced packages
227  !!
228  !! Viscosity ar_bnd routine to activate viscosity in the advanced
229  !! packages. This routine is called from gwf_ar() as it moves through each
230  !! package
231  !<
232  subroutine vsc_ar_bnd(this, packobj)
233  ! -- modules
234  use bndmodule, only: bndtype
235  use drnmodule, only: drntype
236  use ghbmodule, only: ghbtype
237  use rivmodule, only: rivtype
238  use lakmodule, only: laktype
239  use sfrmodule, only: sfrtype
240  use mawmodule, only: mawtype
241  ! -- dummy
242  class(gwfvsctype) :: this
243  class(bndtype), pointer :: packobj
244  !
245  ! -- Add density terms based on boundary package type
246  select case (packobj%filtyp)
247  case ('DRN')
248  !
249  ! -- activate viscosity for the drain package
250  select type (packobj)
251  type is (drntype)
252  call packobj%bnd_activate_viscosity()
253  end select
254  case ('GHB')
255  !
256  ! -- activate viscosity for the drain package
257  select type (packobj)
258  type is (ghbtype)
259  call packobj%bnd_activate_viscosity()
260  end select
261  case ('RIV')
262  !
263  ! -- activate viscosity for the drain package
264  select type (packobj)
265  type is (rivtype)
266  call packobj%bnd_activate_viscosity()
267  end select
268  case ('LAK')
269  !
270  ! -- activate viscosity for lake package
271  select type (packobj)
272  type is (laktype)
273  call packobj%lak_activate_viscosity()
274  end select
275  case ('SFR')
276  !
277  ! -- activate viscosity for sfr package
278  select type (packobj)
279  type is (sfrtype)
280  call packobj%sfr_activate_viscosity()
281  end select
282  case ('MAW')
283  !
284  ! -- activate viscosity for maw package
285  select type (packobj)
286  type is (mawtype)
287  call packobj%maw_activate_viscosity()
288  end select
289  case default
290  !
291  ! -- nothing
292  end select
293  end subroutine vsc_ar_bnd
294 
295  !> @brief Set pointers to NPF variables
296  !!
297  !! Set array and variable pointers from the NPF
298  !! package for access by VSC.
299  !<
300  subroutine set_npf_pointers(this)
301  ! -- dummy
302  class(gwfvsctype) :: this
303  ! -- local
304  character(len=LENMEMPATH) :: npfMemoryPath
305  !
306  ! -- Set pointers to other package variables
307  ! -- NPF
308  npfmemorypath = create_mem_path(this%name_model, 'NPF')
309  call mem_setptr(this%k11, 'K11', npfmemorypath)
310  call mem_setptr(this%k22, 'K22', npfmemorypath)
311  call mem_setptr(this%k33, 'K33', npfmemorypath)
312  call mem_setptr(this%k11input, 'K11INPUT', npfmemorypath)
313  call mem_setptr(this%k22input, 'K22INPUT', npfmemorypath)
314  call mem_setptr(this%k33input, 'K33INPUT', npfmemorypath)
315  call mem_setptr(this%kchangeper, 'KCHANGEPER', npfmemorypath)
316  call mem_setptr(this%kchangestp, 'KCHANGESTP', npfmemorypath)
317  call mem_setptr(this%nodekchange, 'NODEKCHANGE', npfmemorypath)
318  end subroutine set_npf_pointers
319 
320  !> @ brief Read new period data in viscosity package
321  !!
322  !! Method to read and prepare period data for the VSC package.
323  !<
324  subroutine vsc_rp(this)
325  ! -- modules
326  use tdismodule, only: kstp, kper
327  ! -- dummy
328  class(gwfvsctype) :: this
329  ! -- local
330  character(len=LINELENGTH) :: errmsg
331  integer(I4B) :: i
332  ! -- formats
333  character(len=*), parameter :: fmtc = &
334  "('Viscosity Package does not have a concentration set &
335  &for species ',i0,'. One or more model names may be specified &
336  &incorrectly in the PACKAGEDATA block or a GWF-GWT exchange may need &
337  &to be activated.')"
338  !
339  ! -- Check to make sure all concentration pointers have been set
340  if (kstp * kper == 1) then
341  do i = 1, this%nviscspecies
342  if (.not. associated(this%modelconc(i)%conc)) then
343  write (errmsg, fmtc) i
344  call store_error(errmsg)
345  end if
346  end do
347  if (count_errors() > 0) then
348  call this%parser%StoreErrorUnit()
349  end if
350  end if
351  end subroutine vsc_rp
352 
353  !> @ brief Advance the viscosity package
354  !!
355  !! Advance data in the VSC package. The method sets or advances time series,
356  !! time array series, and observation data.
357  !<
358  subroutine vsc_ad(this)
359  ! -- dummy
360  class(gwfvsctype) :: this
361  !
362  ! -- update viscosity using the latest concentration/temperature
363  call this%vsc_calcvisc()
364  end subroutine vsc_ad
365 
366  !> @brief Advance the boundary packages when viscosity is active
367  !!
368  !! Update the conductance values associate with inflow from a boundary
369  !! when VSC package is active.
370  !<
371  subroutine vsc_ad_bnd(this, packobj, hnew)
372  ! -- modules
373  use bndmodule, only: bndtype
374  ! -- dummy
375  class(gwfvsctype) :: this
376  class(bndtype), pointer :: packobj
377  real(DP), intent(in), dimension(:) :: hnew
378  ! -- local
379  integer(I4B) :: i, j
380  integer(I4B) :: n, locvisc, locelev
381  integer(I4B), dimension(:), allocatable :: locconc
382  !
383  ! -- initialize
384  locvisc = 0
385  locelev = 0
386  allocate (locconc(this%nviscspecies))
387  locconc(:) = 0
388  !
389  ! -- Add viscosity terms for conductance-dependent boundaries
390  do n = 1, packobj%naux
391  if (packobj%auxname(n) == 'VISCOSITY') then
392  locvisc = n
393  else if (packobj%auxname(n) == 'ELEVATION') then
394  locelev = n
395  end if
396  end do
397  !
398  ! -- find aux columns for conc (or temp.) that affect viscosity
399  do i = 1, this%nviscspecies
400  locconc(i) = 0
401  do j = 1, packobj%naux
402  if (this%cauxspeciesname(i) == packobj%auxname(j)) then
403  locconc(i) = j
404  exit
405  end if
406  end do
407  if (locconc(i) == 0) then
408  ! -- one not found, so don't use and mark all as 0
409  locconc(:) = 0
410  exit
411  end if
412  end do
413  !
414  ! -- apply viscosity terms to inflow from boundary based on package type
415  select case (packobj%filtyp)
416  case ('GHB', 'DRN', 'RIV')
417  !
418  ! -- general head, drain, and river boundary
419  call vsc_ad_standard_bnd(packobj, hnew, this%visc, this%viscref, &
420  locelev, locvisc, locconc, this%dviscdc, &
421  this%cviscref, this%ivisc, this%a2, this%a3, &
422  this%a4, this%ctemp)
423  case ('LAK')
424  !
425  ! -- lake
426  ! Update 'viscratios' internal to lak such that they are
427  ! automatically applied in the LAK calc_cond() routine
428  call vsc_ad_lak(packobj, this%visc, this%viscref, this%elev, locvisc, &
429  locconc, this%dviscdc, this%cviscref, this%ivisc, &
430  this%a2, this%a3, this%a4, this%ctemp)
431  case ('SFR')
432  !
433  ! -- streamflow routing
434  ! Update 'viscratios' internal to sfr such that they are
435  ! automatically applied in the SFR calc_cond() routine
436  call vsc_ad_sfr(packobj, this%visc, this%viscref, this%elev, locvisc, &
437  locconc, this%dviscdc, this%cviscref, this%ivisc, &
438  this%a2, this%a3, this%a4, this%ctemp)
439  case ('MAW')
440  !
441  ! -- multi-aquifer well
442  call vsc_ad_maw(packobj, this%visc, this%viscref, this%elev, locvisc, &
443  locconc, this%dviscdc, this%cviscref, this%ivisc, &
444  this%a2, this%a3, this%a4, this%ctemp)
445  case ('UZF')
446  !
447  ! -- unsaturated-zone flow
448  case default
449  !
450  ! -- nothing
451  end select
452  !
453  ! -- deallocate
454  deallocate (locconc)
455  end subroutine vsc_ad_bnd
456 
457  !> @brief advance ghb while accounting for viscosity
458  !!
459  !! When flow enters from ghb boundary type, take into account the effects
460  !! of viscosity on the user-specified conductance terms
461  !<
462  subroutine vsc_ad_standard_bnd(packobj, hnew, visc, viscref, locelev, &
463  locvisc, locconc, dviscdc, cviscref, &
464  ivisc, a2, a3, a4, ctemp)
465  ! -- modules
466  use bndmodule, only: bndtype
467  use drnmodule, only: drntype
468  use rivmodule, only: rivtype
469  use ghbmodule, only: ghbtype
470  class(bndtype), pointer :: packobj
471  ! -- dummy
472  real(DP), intent(in), dimension(:) :: hnew
473  real(DP), intent(in), dimension(:) :: visc
474  real(DP), intent(in) :: a2, a3, a4
475  real(DP), intent(in) :: viscref
476  integer(I4B), intent(in) :: locelev
477  integer(I4B), intent(in) :: locvisc
478  integer(I4B), dimension(:), intent(in) :: locconc
479  integer(I4B), dimension(:), intent(in) :: ivisc
480  real(DP), dimension(:), intent(in) :: dviscdc
481  real(DP), dimension(:), intent(in) :: cviscref
482  real(DP), dimension(:), intent(inout) :: ctemp
483  ! -- local
484  integer(I4B) :: n
485  integer(I4B) :: node
486  real(DP) :: viscbnd
487  !
488  ! -- Process density terms for each GHB
489  do n = 1, packobj%nbound
490  node = packobj%nodelist(n)
491  !
492  ! -- Check if boundary cell is active, cycle if not
493  if (packobj%ibound(node) <= 0) cycle
494  !
495  ! -- calculate the viscosity associated with the boundary
496  viscbnd = calc_bnd_viscosity(n, locvisc, locconc, viscref, dviscdc, &
497  cviscref, ctemp, ivisc, a2, a3, a4, &
498  packobj%auxvar)
499  !
500  ! -- update boundary conductance based on viscosity effects
501  select case (packobj%filtyp)
502  case ('DRN')
503  select type (packobj)
504  type is (drntype)
505  packobj%cond(n) = update_bnd_cond(viscbnd, viscref, &
506  packobj%condinput(n))
507  end select
508  case ('GHB')
509  select type (packobj)
510  type is (ghbtype)
511  packobj%cond(n) = update_bnd_cond(viscbnd, viscref, &
512  packobj%condinput(n))
513  end select
514  case ('RIV')
515  select type (packobj)
516  type is (rivtype)
517  packobj%cond(n) = update_bnd_cond(viscbnd, viscref, &
518  packobj%condinput(n))
519  end select
520  case default
521  packobj%bound(2, n) = update_bnd_cond(viscbnd, viscref, &
522  packobj%condinput(n))
523  end select
524  !
525  end do
526  end subroutine vsc_ad_standard_bnd
527 
528  !> @brief Update sfr-related viscosity ratios
529  !!
530  !! When the viscosity package is active, update the viscosity ratio that is
531  !! applied to the hydraulic conductivity specified in the SFR package
532  !<
533  subroutine vsc_ad_sfr(packobj, visc, viscref, elev, locvisc, locconc, &
534  dviscdc, cviscref, ivisc, a2, a3, a4, ctemp)
535  ! -- modules
536  use bndmodule, only: bndtype
537  use sfrmodule, only: sfrtype
538  class(bndtype), pointer :: packobj
539  ! -- dummy
540  real(DP), intent(in) :: viscref
541  real(DP), intent(in) :: a2, a3, a4
542  integer(I4B), intent(in) :: locvisc
543  integer(I4B), dimension(:), intent(in) :: locconc
544  integer(I4B), dimension(:), intent(in) :: ivisc
545  real(DP), dimension(:), intent(in) :: visc
546  real(DP), dimension(:), intent(in) :: elev
547  real(DP), dimension(:), intent(in) :: dviscdc
548  real(DP), dimension(:), intent(in) :: cviscref
549  real(DP), dimension(:), intent(inout) :: ctemp
550  ! -- local
551  integer(I4B) :: n
552  integer(I4B) :: node
553  real(DP) :: viscsfr
554  !
555  ! -- update viscosity ratios for updating hyd. cond (and conductance)
556  select type (packobj)
557  type is (sfrtype)
558  do n = 1, packobj%nbound
559  !
560  ! -- get gwf node number
561  node = packobj%nodelist(n)
562  !
563  ! -- Check if boundary cell is active, cycle if not
564  if (packobj%ibound(node) <= 0) cycle
565  !
566  ! --
567  !
568  ! -- calculate the viscosity associated with the boundary
569  viscsfr = calc_bnd_viscosity(n, locvisc, locconc, viscref, dviscdc, &
570  cviscref, ctemp, ivisc, a2, a3, a4, &
571  packobj%auxvar)
572  !
573  ! -- fill sfr relative viscosity into column 1 of viscratios
574  packobj%viscratios(1, n) = calc_vsc_ratio(viscref, viscsfr)
575  !
576  ! -- fill gwf relative viscosity into column 2 of viscratios
577  packobj%viscratios(2, n) = calc_vsc_ratio(viscref, visc(node))
578  end do
579  end select
580  end subroutine vsc_ad_sfr
581 
582  !> @brief Update lak-related viscosity ratios
583  !!
584  !! When the viscosity package is active, update the viscosity ratio that is
585  !! applied to the lakebed conductance calculated in the LAK package
586  !<
587  subroutine vsc_ad_lak(packobj, visc, viscref, elev, locvisc, locconc, &
588  dviscdc, cviscref, ivisc, a2, a3, a4, ctemp)
589  ! -- modules
590  use bndmodule, only: bndtype
591  use lakmodule, only: laktype
592  class(bndtype), pointer :: packobj
593  ! -- dummy
594  real(DP), intent(in) :: viscref
595  real(DP), intent(in) :: a2, a3, a4
596  integer(I4B), intent(in) :: locvisc
597  integer(I4B), dimension(:), intent(in) :: locconc
598  integer(I4B), dimension(:), intent(in) :: ivisc
599  real(DP), dimension(:), intent(in) :: visc
600  real(DP), dimension(:), intent(in) :: elev
601  real(DP), dimension(:), intent(in) :: dviscdc
602  real(DP), dimension(:), intent(in) :: cviscref
603  real(DP), dimension(:), intent(inout) :: ctemp
604  ! -- local
605  integer(I4B) :: n
606  integer(I4B) :: node
607  real(DP) :: visclak
608  !
609  ! -- update viscosity ratios for updating hyd. cond (and conductance)
610  select type (packobj)
611  type is (laktype)
612  do n = 1, packobj%nbound
613  !
614  ! -- get gwf node number
615  node = packobj%nodelist(n)
616  !
617  ! -- Check if boundary cell is active, cycle if not
618  if (packobj%ibound(node) <= 0) cycle
619  !
620  ! --
621  !
622  ! -- calculate the viscosity associated with the boundary
623  visclak = calc_bnd_viscosity(n, locvisc, locconc, viscref, dviscdc, &
624  cviscref, ctemp, ivisc, a2, a3, a4, &
625  packobj%auxvar)
626  !
627  ! -- fill lak relative viscosity into column 1 of viscratios
628  packobj%viscratios(1, n) = calc_vsc_ratio(viscref, visclak)
629  !
630  ! -- fill gwf relative viscosity into column 2 of viscratios
631  packobj%viscratios(2, n) = calc_vsc_ratio(viscref, visc(node))
632  end do
633  end select
634  end subroutine vsc_ad_lak
635 
636  !> @brief Update maw-related viscosity ratios
637  !!
638  !! When the viscosity package is active, update the viscosity ratio that is
639  !! applied to the conductance calculated in the MAW package
640  !<
641  subroutine vsc_ad_maw(packobj, visc, viscref, elev, locvisc, locconc, &
642  dviscdc, cviscref, ivisc, a2, a3, a4, ctemp)
643  ! -- modules
644  use bndmodule, only: bndtype
645  use mawmodule, only: mawtype
646  class(bndtype), pointer :: packobj
647  ! -- dummy
648  real(DP), intent(in) :: viscref
649  real(DP), intent(in) :: a2, a3, a4
650  integer(I4B), intent(in) :: locvisc
651  integer(I4B), dimension(:), intent(in) :: locconc
652  integer(I4B), dimension(:), intent(in) :: ivisc
653  real(DP), dimension(:), intent(in) :: visc
654  real(DP), dimension(:), intent(in) :: elev
655  real(DP), dimension(:), intent(in) :: dviscdc
656  real(DP), dimension(:), intent(in) :: cviscref
657  real(DP), dimension(:), intent(inout) :: ctemp
658  ! -- local
659  integer(I4B) :: n
660  integer(I4B) :: node
661  real(DP) :: viscmaw
662  !
663  ! -- update viscosity ratios for updating hyd. cond (and conductance)
664  select type (packobj)
665  type is (mawtype)
666  do n = 1, packobj%nbound
667  !
668  ! -- get gwf node number
669  node = packobj%nodelist(n)
670  !
671  ! -- Check if boundary cell is active, cycle if not
672  if (packobj%ibound(node) <= 0) cycle
673  !
674  ! --
675  !
676  ! -- calculate the viscosity associated with the boundary
677  viscmaw = calc_bnd_viscosity(n, locvisc, locconc, viscref, dviscdc, &
678  cviscref, ctemp, ivisc, a2, a3, a4, &
679  packobj%auxvar)
680  !
681  ! -- fill lak relative viscosity into column 1 of viscratios
682  packobj%viscratios(1, n) = calc_vsc_ratio(viscref, viscmaw)
683  !
684  ! -- fill gwf relative viscosity into column 2 of viscratios
685  packobj%viscratios(2, n) = calc_vsc_ratio(viscref, visc(node))
686  end do
687  end select
688  end subroutine vsc_ad_maw
689 
690  !> @brief Apply viscosity to the conductance term
691  !!
692  !! When the viscosity package is active apply the viscosity ratio to the
693  !! active boundary package's conductance term.
694  !<
695  function update_bnd_cond(bndvisc, viscref, spcfdcond) result(updatedcond)
696  ! -- dummy
697  real(dp), intent(in) :: viscref
698  real(dp), intent(in) :: bndvisc
699  real(dp), intent(in) :: spcfdcond
700  ! -- local
701  real(dp) :: vscratio
702  real(dp) :: updatedcond
703  !
704  vscratio = calc_vsc_ratio(viscref, bndvisc)
705  !
706  ! -- calculate new conductance here
707  updatedcond = vscratio * spcfdcond
708  end function update_bnd_cond
709 
710  !> @brief calculate and return the viscosity ratio
711  !<
712  function calc_vsc_ratio(viscref, bndvisc) result(viscratio)
713  ! -- dummy
714  real(dp), intent(in) :: viscref
715  real(dp), intent(in) :: bndvisc
716  ! -- local
717  real(dp) :: viscratio
718  !
719  viscratio = viscref / bndvisc
720  end function calc_vsc_ratio
721 
722  !> @ brief Calculate the boundary viscosity
723  !!
724  !! Return the viscosity of the boundary package using one of
725  !! the options in the following order of priority:
726  !! 1. Assign as aux variable in column with name 'VISCOSITY'
727  !! 2. Calculate using viscosity equation and nviscspecies aux columns
728  !! 3. If neither of those, then assign as viscref !!
729  !<
730  function calc_bnd_viscosity(n, locvisc, locconc, viscref, dviscdc, cviscref, &
731  ctemp, ivisc, a2, a3, a4, auxvar) result(viscbnd)
732  ! -- modules
733  ! -- dummy
734  integer(I4B), intent(in) :: n
735  integer(I4B), intent(in) :: locvisc
736  real(dp), intent(in) :: a2, a3, a4
737  integer(I4B), dimension(:), intent(in) :: ivisc
738  integer(I4B), dimension(:), intent(in) :: locconc
739  real(dp), intent(in) :: viscref
740  real(dp), dimension(:), intent(in) :: dviscdc
741  real(dp), dimension(:), intent(in) :: cviscref
742  real(dp), dimension(:), intent(inout) :: ctemp
743  real(dp), dimension(:, :), intent(in) :: auxvar
744  ! -- Return
745  real(dp) :: viscbnd
746  ! -- local
747  integer(I4B) :: i
748  !
749  ! -- assign boundary viscosity based on one of three options
750  if (locvisc > 0) then
751  ! -- assign viscosity to an aux column named 'VISCOSITY'
752  viscbnd = auxvar(locvisc, n)
753  else if (locconc(1) > 0) then
754  ! -- calculate viscosity using one or more concentration auxcolumns
755  do i = 1, size(locconc)
756  ctemp(i) = dzero
757  if (locconc(i) > 0) then
758  ctemp(i) = auxvar(locconc(i), n)
759  end if
760  end do
761  viscbnd = calc_visc(ivisc, viscref, dviscdc, cviscref, ctemp, a2, a3, a4)
762  else
763  ! -- neither of the above, so assign as viscref
764  viscbnd = viscref
765  end if
766  end function calc_bnd_viscosity
767 
768  !> @brief Calculate the viscosity ratio
769  !!
770  !! Calculate the viscosity ratio applied to the hydraulic characteristic
771  !! provided by the user. The viscosity ratio is applicable only
772  !! when the hydraulic characteristic is specified as positive and will not
773  !! be applied when the hydchr is negative
774  !<
775  subroutine get_visc_ratio(this, n, m, gwhdn, gwhdm, viscratio)
776  ! -- modules
777  use constantsmodule, only: done
778  ! -- dummy
779  class(gwfvsctype) :: this
780  integer(I4B), intent(in) :: n, m
781  real(DP), intent(in) :: gwhdn, gwhdm
782  real(DP), intent(inout) :: viscratio
783  ! -- loca
784  integer(I4B) :: cellid
785  !
786  viscratio = done
787  if (gwhdm > gwhdn) then
788  cellid = m
789  else if (gwhdn >= gwhdm) then
790  cellid = n
791  end if
792  call this%calc_q_visc(cellid, viscratio)
793  end subroutine get_visc_ratio
794 
795  !> @brief Account for viscosity in the aquiferhorizontal flow barriers
796  !!
797  !! Will return the viscosity associated with the upgradient node (cell)
798  !! to the HFB package for adjusting the hydraulic characteristic (hydchr)
799  !! of the barrier
800  !<
801  subroutine calc_q_visc(this, cellid, viscratio)
802  ! -- dummy variables
803  class(gwfvsctype) :: this
804  integer(I4B), intent(in) :: cellid
805  ! -- Return
806  real(DP), intent(inout) :: viscratio
807  ! -- local
808  real(DP) :: visc
809  !
810  ! -- Retrieve viscosity for the passed node number
811  visc = this%visc(cellid)
812  !
813  ! -- Calculate the viscosity ratio for the
814  viscratio = calc_vsc_ratio(this%viscref, visc)
815  end subroutine calc_q_visc
816 
817  !> @brief Appled the viscosity ratio (mu_o/mu) to the hydraulic conductivity
818  !!
819  !! This routine called after updating the viscosity values using the latest
820  !! concentration and/or temperature values. The ratio mu_o/mu, reference
821  !! viscosity divided by the updated viscosity value, is multiplied by K
822  !! for each cell.
823  !<
824  subroutine update_k_with_vsc(this)
825  ! -- dummy
826  class(gwfvsctype) :: this
827  ! -- local
828  integer(I4B) :: n
829  real(DP) :: viscratio
830  !
831  ! -- For viscosity-based K's, apply change of K to K11 by starting with
832  ! user-specified K values and not the K's leftover from the last viscosity
833  ! update.
834  do n = 1, this%dis%nodes
835  call this%calc_q_visc(n, viscratio)
836  this%k11(n) = this%k11input(n) * viscratio
837  this%k22(n) = this%k22input(n) * viscratio
838  this%k33(n) = this%k33input(n) * viscratio
839  this%nodekchange(n) = 1
840  end do
841  !
842  ! -- Flag kchange
843  call this%vsc_set_changed_at(kper, kstp)
844  end subroutine update_k_with_vsc
845 
846  !> @brief Mark K changes as having occurred at (kper, kstp)
847  !!
848  !! Procedure called by VSC code when K updated due to viscosity changes.
849  !! K values changed at (kper, kstp).
850  !<
851  subroutine vsc_set_changed_at(this, kper, kstp)
852  ! -- dummy variables
853  class(gwfvsctype) :: this
854  integer(I4B), intent(in) :: kper
855  integer(I4B), intent(in) :: kstp
856  !
857  this%kchangeper = kper
858  this%kchangestp = kstp
859  end subroutine vsc_set_changed_at
860 
861  !> @ brief Output viscosity package dependent-variable terms.
862  !!
863  !! Save calculated viscosity array to binary file
864  !<
865  subroutine vsc_ot_dv(this, idvfl)
866  ! -- dummy
867  class(gwfvsctype) :: this
868  integer(I4B), intent(in) :: idvfl
869  ! -- local
870  character(len=1) :: cdatafmp = ' ', editdesc = ' '
871  integer(I4B) :: ibinun
872  integer(I4B) :: iprint
873  integer(I4B) :: nvaluesp
874  integer(I4B) :: nwidthp
875  real(DP) :: dinact
876  !
877  ! -- Set unit number for viscosity output
878  if (this%ioutvisc /= 0) then
879  ibinun = 1
880  else
881  ibinun = 0
882  end if
883  if (idvfl == 0) ibinun = 0
884  !
885  ! -- save viscosity array
886  if (ibinun /= 0) then
887  iprint = 0
888  dinact = dhnoflo
889  !
890  ! -- write viscosity to binary file
891  if (this%ioutvisc /= 0) then
892  ibinun = this%ioutvisc
893  call this%dis%record_array(this%visc, this%iout, iprint, ibinun, &
894  ' VISCOSITY', cdatafmp, nvaluesp, &
895  nwidthp, editdesc, dinact)
896  end if
897  end if
898  end subroutine vsc_ot_dv
899 
900  !> @ brief Deallocate viscosity package memory
901  !!
902  !! Deallocate viscosity package scalars and arrays.
903  !<
904  subroutine vsc_da(this)
905  ! -- dummy
906  class(gwfvsctype) :: this
907  !
908  ! -- Deallocate arrays if package was active
909  if (this%inunit > 0) then
910  call mem_deallocate(this%visc)
911  call mem_deallocate(this%ivisc)
912  call mem_deallocate(this%dviscdc)
913  call mem_deallocate(this%cviscref)
914  call mem_deallocate(this%ctemp)
915  deallocate (this%cmodelname)
916  deallocate (this%cauxspeciesname)
917  deallocate (this%modelconc)
918  end if
919  !
920  ! -- Scalars
921  call mem_deallocate(this%thermivisc)
922  call mem_deallocate(this%idxtmpr)
923  call mem_deallocate(this%ioutvisc)
924  call mem_deallocate(this%ireadelev)
925  call mem_deallocate(this%iconcset)
926  call mem_deallocate(this%viscref)
927  call mem_deallocate(this%nviscspecies)
928  call mem_deallocate(this%a2)
929  call mem_deallocate(this%a3)
930  call mem_deallocate(this%a4)
931  !
932  ! -- Nullify pointers to other package variables
933  nullify (this%k11)
934  nullify (this%k22)
935  nullify (this%k33)
936  nullify (this%k11input)
937  nullify (this%k22input)
938  nullify (this%k33input)
939  nullify (this%kchangeper)
940  nullify (this%kchangestp)
941  nullify (this%nodekchange)
942  !
943  ! -- deallocate parent
944  call this%NumericalPackageType%da()
945  end subroutine vsc_da
946 
947  !> @ brief Read dimensions
948  !!
949  !! Read dimensions for the viscosity package
950  !<
951  subroutine read_dimensions(this)
952  ! -- modules
953  ! -- dummy
954  class(gwfvsctype), intent(inout) :: this
955  ! -- local
956  character(len=LINELENGTH) :: errmsg, keyword
957  integer(I4B) :: ierr
958  logical :: isfound, endOfBlock
959  !
960  ! -- get dimensions block
961  call this%parser%GetBlock('DIMENSIONS', isfound, ierr, &
962  supportopenclose=.true.)
963  !
964  ! -- parse dimensions block if detected
965  if (isfound) then
966  write (this%iout, '(/1x,a)') 'Processing VSC DIMENSIONS block'
967  do
968  call this%parser%GetNextLine(endofblock)
969  if (endofblock) exit
970  call this%parser%GetStringCaps(keyword)
971  select case (keyword)
972  case ('NVISCSPECIES')
973  this%nviscspecies = this%parser%GetInteger()
974  write (this%iout, '(4x,a,i0)') 'NVISCSPECIES = ', this%nviscspecies
975  case default
976  write (errmsg, '(a,a)') &
977  'Unknown VSC dimension: ', trim(keyword)
978  call store_error(errmsg)
979  call this%parser%StoreErrorUnit()
980  end select
981  end do
982  write (this%iout, '(1x,a)') 'End of VSC DIMENSIONS block'
983  else
984  call store_error('Required VSC DIMENSIONS block not found.')
985  call this%parser%StoreErrorUnit()
986  end if
987  !
988  ! -- check dimension
989  if (this%nviscspecies < 1) then
990  call store_error('NVISCSPECIES must be greater than zero.')
991  call this%parser%StoreErrorUnit()
992  end if
993  end subroutine read_dimensions
994 
995  !> @ brief Read data for package
996  !!
997  !! Method to read data for the viscosity package.
998  !<
999  subroutine read_packagedata(this)
1000  ! -- dummy
1001  class(gwfvsctype) :: this
1002  ! -- local
1003  character(len=LINELENGTH) :: errmsg
1004  character(len=LINELENGTH) :: line
1005  integer(I4B) :: ierr
1006  integer(I4B) :: iviscspec
1007  logical :: isfound, endOfBlock
1008  logical :: blockrequired
1009  integer(I4B), dimension(:), allocatable :: itemp
1010  character(len=10) :: c10
1011  character(len=16) :: c16
1012  ! -- format
1013  character(len=*), parameter :: fmterr = &
1014  "('Invalid value for IRHOSPEC (',i0,') detected in VSC Package. &
1015  &IRHOSPEC must be > 0 and <= NVISCSPECIES, and duplicate values &
1016  &are not allowed.')"
1017  !
1018  ! -- initialize
1019  allocate (itemp(this%nviscspecies))
1020  itemp(:) = 0
1021  !
1022  ! -- get packagedata block
1023  blockrequired = .true.
1024  call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, &
1025  blockrequired=blockrequired, &
1026  supportopenclose=.true.)
1027  !
1028  ! -- parse packagedata block
1029  if (isfound) then
1030  write (this%iout, '(1x,a)') 'Procesing VSC PACKAGEDATA block'
1031  do
1032  call this%parser%GetNextLine(endofblock)
1033  if (endofblock) exit
1034  iviscspec = this%parser%GetInteger()
1035  if (iviscspec < 1 .or. iviscspec > this%nviscspecies) then
1036  write (errmsg, fmterr) iviscspec
1037  call store_error(errmsg)
1038  end if
1039  if (itemp(iviscspec) /= 0) then
1040  write (errmsg, fmterr) iviscspec
1041  call store_error(errmsg)
1042  end if
1043  itemp(iviscspec) = 1
1044  !
1045  this%dviscdc(iviscspec) = this%parser%GetDouble()
1046  this%cviscref(iviscspec) = this%parser%GetDouble()
1047  call this%parser%GetStringCaps(this%cmodelname(iviscspec))
1048  call this%parser%GetStringCaps(this%cauxspeciesname(iviscspec))
1049  !
1050  if (this%cauxspeciesname(iviscspec) == this%name_temp_spec) then
1051  if (this%idxtmpr > 0) then
1052  write (errmsg, '(a)') 'More than one species in VSC input identified &
1053  &as '//trim(this%name_temp_spec)//'. Only one species may be &
1054  &designated to represent temperature.'
1055  call store_error(errmsg)
1056  else
1057  this%idxtmpr = iviscspec
1058  if (this%thermivisc == 2) then
1059  this%ivisc(iviscspec) = 2
1060  end if
1061  end if
1062  end if
1063  end do
1064  else
1065  call store_error('Required VSC PACKAGEDATA block not found.')
1066  call this%parser%StoreErrorUnit()
1067  end if
1068  !
1069  ! -- Check for errors.
1070  if (count_errors() > 0) then
1071  call this%parser%StoreErrorUnit()
1072  end if
1073  !
1074  ! -- write packagedata information
1075  write (this%iout, '(/,1x,a)') 'Summary of species information in VSC Package'
1076  write (this%iout, '(1a11,5a17)') &
1077  'Species', 'DVISCDC', 'CVISCREF', 'Model', 'AUXSPECIESNAME'
1078  do iviscspec = 1, this%nviscspecies
1079  write (c10, '(i0)') iviscspec
1080  line = ' '//adjustr(c10)
1081 
1082  write (c16, '(g15.6)') this%dviscdc(iviscspec)
1083  line = trim(line)//' '//adjustr(c16)
1084  write (c16, '(g15.6)') this%cviscref(iviscspec)
1085  line = trim(line)//' '//adjustr(c16)
1086  write (c16, '(a)') this%cmodelname(iviscspec)
1087  line = trim(line)//' '//adjustr(c16)
1088  write (c16, '(a)') this%cauxspeciesname(iviscspec)
1089  line = trim(line)//' '//adjustr(c16)
1090  write (this%iout, '(a)') trim(line)
1091  end do
1092  !
1093  ! -- deallocate
1094  deallocate (itemp)
1095  !
1096  write (this%iout, '(/,1x,a)') 'End of VSC PACKAGEDATA block'
1097  end subroutine read_packagedata
1098 
1099  !> @brief Sets package data instead of reading from file
1100  !<
1101  subroutine set_packagedata(this, input_data)
1102  ! -- dummy
1103  class(gwfvsctype) :: this !< this vscoancy pkg
1104  type(gwfvscinputdatatype), intent(in) :: input_data !< the input data to be set
1105  ! -- local
1106  integer(I4B) :: ispec
1107  !
1108  do ispec = 1, this%nviscspecies
1109  this%dviscdc(ispec) = input_data%dviscdc(ispec)
1110  this%cviscref(ispec) = input_data%cviscref(ispec)
1111  this%cmodelname(ispec) = input_data%cmodelname(ispec)
1112  this%cauxspeciesname(ispec) = input_data%cauxspeciesname(ispec)
1113  end do
1114  end subroutine set_packagedata
1115 
1116  !> @brief Calculate fluid viscosity
1117  !!
1118  !! Calculates fluid viscosity based on concentration or
1119  !! temperature
1120  !<
1121  subroutine vsc_calcvisc(this)
1122  ! -- dummy
1123  class(gwfvsctype) :: this
1124  ! -- local
1125  integer(I4B) :: n
1126  integer(I4B) :: i
1127  !
1128  ! -- Calculate the viscosity using the specified concentration and/or
1129  ! temperature arrays
1130  do n = 1, this%dis%nodes
1131  do i = 1, this%nviscspecies
1132  if (this%modelconc(i)%icbund(n) == 0) then
1133  this%ctemp = dzero
1134  else
1135  this%ctemp(i) = this%modelconc(i)%conc(n)
1136  end if
1137  end do
1138  !
1139  this%visc(n) = calc_visc(this%ivisc, this%viscref, this%dviscdc, &
1140  this%cviscref, this%ctemp, this%a2, &
1141  this%a3, this%a4)
1142  end do
1143  end subroutine vsc_calcvisc
1144 
1145  !> @ brief Allocate scalars
1146  !!
1147  !! Allocate and initialize scalars for the VSC package. The base model
1148  !! allocate scalars method is also called.
1149  !<
1150  subroutine allocate_scalars(this)
1151  ! -- modules
1152  use constantsmodule, only: dzero, dten, dep3
1153  ! -- dummy
1154  class(gwfvsctype) :: this
1155  !
1156  ! -- allocate scalars in NumericalPackageType
1157  call this%NumericalPackageType%allocate_scalars()
1158  !
1159  ! -- Allocate
1160  call mem_allocate(this%thermivisc, 'THERMIVISC', this%memoryPath)
1161  call mem_allocate(this%idxtmpr, 'IDXTMPR', this%memoryPath)
1162  call mem_allocate(this%ioutvisc, 'IOUTVISC', this%memoryPath)
1163  call mem_allocate(this%ireadelev, 'IREADELEV', this%memoryPath)
1164  call mem_allocate(this%iconcset, 'ICONCSET', this%memoryPath)
1165  call mem_allocate(this%viscref, 'VISCREF', this%memoryPath)
1166  call mem_allocate(this%a2, 'A2', this%memoryPath)
1167  call mem_allocate(this%a3, 'A3', this%memoryPath)
1168  call mem_allocate(this%a4, 'A4', this%memoryPath)
1169  !
1170  call mem_allocate(this%nviscspecies, 'NVISCSPECIES', this%memoryPath)
1171  !
1172  ! -- Initialize
1173  this%thermivisc = 0
1174  this%idxtmpr = 0
1175  this%ioutvisc = 0
1176  this%ireadelev = 0
1177  this%iconcset = 0
1178  this%viscref = dep3
1179  this%A2 = dten
1180  this%A3 = 248.37_dp
1181  this%A4 = 133.15_dp
1182  !
1183  this%nviscspecies = 0
1184  end subroutine allocate_scalars
1185 
1186  !> @ brief Allocate arrays
1187  !!
1188  !! Allocate and initialize arrays for the VSC package.
1189  !<
1190  subroutine allocate_arrays(this, nodes)
1191  ! -- dummy
1192  class(gwfvsctype) :: this
1193  integer(I4B), intent(in) :: nodes
1194  ! -- local
1195  integer(I4B) :: i
1196  !
1197  ! -- Allocate
1198  call mem_allocate(this%visc, nodes, 'VISC', this%memoryPath)
1199  call mem_allocate(this%ivisc, this%nviscspecies, 'IVISC', this%memoryPath)
1200  call mem_allocate(this%dviscdc, this%nviscspecies, 'DRHODC', &
1201  this%memoryPath)
1202  call mem_allocate(this%cviscref, this%nviscspecies, 'CRHOREF', &
1203  this%memoryPath)
1204  call mem_allocate(this%ctemp, this%nviscspecies, 'CTEMP', this%memoryPath)
1205  allocate (this%cmodelname(this%nviscspecies))
1206  allocate (this%cauxspeciesname(this%nviscspecies))
1207  allocate (this%modelconc(this%nviscspecies))
1208  !
1209  ! -- Initialize
1210  do i = 1, nodes
1211  this%visc(i) = this%viscref
1212  end do
1213  !
1214  ! -- Initialize nviscspecies arrays
1215  do i = 1, this%nviscspecies
1216  this%ivisc(i) = 1
1217  this%dviscdc(i) = dzero
1218  this%cviscref(i) = dzero
1219  this%ctemp(i) = dzero
1220  this%cmodelname(i) = ''
1221  this%cauxspeciesname(i) = ''
1222  end do
1223  end subroutine allocate_arrays
1224 
1225  !> @ brief Read Options block
1226  !!
1227  !! Reads the options block inside the VSC package.
1228  !<
1229  subroutine read_options(this)
1230  ! -- modules
1231  use openspecmodule, only: access, form
1233  ! -- dummy
1234  class(gwfvsctype) :: this
1235  ! -- local
1236  character(len=LINELENGTH) :: warnmsg, errmsg, keyword, keyword2
1237  character(len=MAXCHARLEN) :: fname
1238  integer(I4B) :: ierr
1239  logical :: isfound, endOfBlock
1240  ! -- formats
1241  character(len=*), parameter :: fmtfileout = &
1242  "(1x, 'VSC', 1x, a, 1x, 'Will be saved to file: ', &
1243  &a, /4x, 'opened on unit: ', I7)"
1244  character(len=*), parameter :: fmtlinear = &
1245  "(/,1x,'Viscosity will vary linearly with temperature &
1246  &change ')"
1247  character(len=*), parameter :: fmtnonlinear = &
1248  "(/,1x,'Viscosity will vary non-linearly with temperature &
1249  &change ')"
1250  !
1251  ! -- get options block
1252  call this%parser%GetBlock('OPTIONS', isfound, ierr, &
1253  supportopenclose=.true., blockrequired=.false.)
1254  !
1255  ! -- parse options block if detected
1256  if (isfound) then
1257  write (this%iout, '(1x,a)') 'Processing VSC OPTIONS block'
1258  do
1259  call this%parser%GetNextLine(endofblock)
1260  if (endofblock) exit
1261  call this%parser%GetStringCaps(keyword)
1262  select case (keyword)
1263  case ('VISCREF')
1264  this%viscref = this%parser%GetDouble()
1265  write (this%iout, '(4x,a,1pg15.6)') &
1266  'Reference viscosity has been set to: ', &
1267  this%viscref
1268  case ('VISCOSITY')
1269  call this%parser%GetStringCaps(keyword)
1270  if (keyword == 'FILEOUT') then
1271  call this%parser%GetString(fname)
1272  this%ioutvisc = getunit()
1273  call openfile(this%ioutvisc, this%iout, fname, 'DATA(BINARY)', &
1274  form, access, 'REPLACE')
1275  write (this%iout, fmtfileout) &
1276  'VISCOSITY', fname, this%ioutvisc
1277  else
1278  errmsg = 'Optional VISCOSITY keyword must be '// &
1279  'followed by FILEOUT'
1280  call store_error(errmsg)
1281  end if
1282  case ('TEMPERATURE_SPECIES_NAME')
1283  call this%parser%GetStringCaps(this%name_temp_spec)
1284  write (this%iout, '(4x, a)') 'Temperature species name set to: '// &
1285  trim(this%name_temp_spec)
1286  case ('THERMAL_FORMULATION')
1287  call this%parser%GetStringCaps(keyword2)
1288  if (trim(adjustl(keyword2)) == 'LINEAR') this%thermivisc = 1
1289  if (trim(adjustl(keyword2)) == 'NONLINEAR') this%thermivisc = 2
1290  select case (this%thermivisc)
1291  case (1)
1292  write (this%iout, fmtlinear)
1293  case (2)
1294  write (this%iout, fmtnonlinear)
1295  end select
1296  case ('THERMAL_A2')
1297  this%a2 = this%parser%GetDouble()
1298  if (this%thermivisc == 2) then
1299  write (this%iout, '(4x,a,1pg15.6)') &
1300  'A2 in nonlinear viscosity formulation has been set to: ', &
1301  this%a2
1302  else
1303  write (this%iout, '(4x,a,/,4x,a,/,4x,a)') 'THERMAL_A2 specified by user &
1304  &in VSC Package input file. LINEAR viscosity ', 'formulation also &
1305  &specified. THERMAL_A2 will not affect ', 'viscosity calculations.'
1306  end if
1307  case ('THERMAL_A3')
1308  this%a3 = this%parser%GetDouble()
1309  if (this%thermivisc == 2) then
1310  write (this%iout, '(4x,a,1pg15.6)') &
1311  'A3 in nonlinear viscosity formulation has been set to: ', &
1312  this%a3
1313  else
1314  write (this%iout, '(4x,a,/,4x,a,/,4x,a)') 'THERMAL_A3 specified by user &
1315  &in VSC Package input file. LINEAR viscosity ', 'formulation also &
1316  &specified. THERMAL_A3 will not affect ', 'viscosity calculations.'
1317  end if
1318  case ('THERMAL_A4')
1319  this%a4 = this%parser%GetDouble()
1320  if (this%thermivisc == 2) then
1321  write (this%iout, '(4x,a,1pg15.6)') &
1322  'A4 in nonlinear viscosity formulation has been set to: ', &
1323  this%a4
1324  else
1325  write (this%iout, '(4x,a,/,4x,a,/,4x,a)') 'THERMAL_A4 specified by user &
1326  &in VSC Package input file. LINEAR viscosity ', 'formulation also &
1327  &specified. THERMAL_A4 will not affect ', 'viscosity calculations.'
1328  end if
1329  case default
1330  write (errmsg, '(a,a)') 'Unknown VSC option: ', &
1331  trim(keyword)
1332  call store_error(errmsg)
1333  call this%parser%StoreErrorUnit()
1334  end select
1335  end do
1336  !
1337  if (this%thermivisc == 1) then
1338  if (this%a2 == 0.0) then
1339  write (errmsg, '(a)') 'LINEAR option selected for varying &
1340  &viscosity with temperature, but A1, a surrogate for &
1341  &dVISC/dT, set equal to 0.0'
1342  call store_error(errmsg)
1343  end if
1344  end if
1345  if (this%thermivisc > 1) then
1346  if (this%a2 == 0) then
1347  write (warnmsg, '(a)') 'NONLINEAR option selected for &
1348  &varying viscosity with temperature, but A2 set equal to &
1349  &zero which may lead to unintended values for viscosity'
1350  call store_warning(errmsg)
1351  end if
1352  if (this%a3 == 0) then
1353  write (warnmsg, '(a)') 'NONLINEAR option selected for &
1354  &varying viscosity with temperature,, but A3 set equal to &
1355  &zero which may lead to unintended values for viscosity'
1356  call store_warning(warnmsg)
1357  end if
1358  if (this%a4 == 0) then
1359  write (warnmsg, '(a)') 'NONLINEAR option selected for &
1360  &varying viscosity with temperature, BUT A4 SET EQUAL TO &
1361  &zero which may lead to unintended values for viscosity'
1362  call store_warning(warnmsg)
1363  end if
1364  end if
1365  end if
1366  !
1367  write (this%iout, '(/,1x,a)') 'end of VSC options block'
1368  end subroutine read_options
1369 
1370  !> @brief Sets options as opposed to reading them from a file
1371  !<
1372  subroutine set_options(this, input_data)
1373  ! -- dummy
1374  class(gwfvsctype) :: this
1375  type(gwfvscinputdatatype), intent(in) :: input_data !< the input data to be set
1376  !
1377  this%viscref = input_data%viscref
1378  end subroutine set_options
1379 
1380  !> @ brief Set pointers to concentration(s)
1381  !!
1382  !! Pass in a gwt model name, concentration array, and ibound,
1383  !! and store a pointer to these in the VSC package so that
1384  !! viscosity can be calculated from them. This routine is called
1385  !! from the gwfgwt exchange in the exg_ar() method.
1386  !<
1387  subroutine set_concentration_pointer(this, modelname, conc, icbund, istmpr)
1388  ! -- dummy
1389  class(gwfvsctype) :: this
1390  character(len=LENMODELNAME), intent(in) :: modelname
1391  real(DP), dimension(:), pointer :: conc
1392  integer(I4B), dimension(:), pointer :: icbund
1393  integer(I4B), optional, intent(in) :: istmpr
1394  ! -- local
1395  integer(I4B) :: i
1396  logical :: found
1397  !
1398  this%iconcset = 1
1399  found = .false.
1400  do i = 1, this%nviscspecies
1401  if (this%cmodelname(i) == modelname) then
1402  this%modelconc(i)%conc => conc
1403  this%modelconc(i)%icbund => icbund
1404  found = .true.
1405  exit
1406  end if
1407  end do
1408  end subroutine set_concentration_pointer
1409 
1410 end module gwfvscmodule
This module contains the base boundary package.
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
real(dp), parameter dep3
real constant 1000
Definition: Constants.f90:88
integer(i4b), parameter lenmodelname
maximum length of the model name
Definition: Constants.f90:22
real(dp), parameter dhnoflo
real no flow constant
Definition: Constants.f90:93
real(dp), parameter dhalf
real constant 1/2
Definition: Constants.f90:68
integer(i4b), parameter lenauxname
maximum length of a aux variable
Definition: Constants.f90:35
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
real(dp), parameter dten
real constant 10
Definition: Constants.f90:84
integer(i4b), parameter maxcharlen
maximum length of char string
Definition: Constants.f90:47
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
subroutine vsc_da(this)
@ brief Deallocate viscosity package memory
Definition: gwf-vsc.f90:905
subroutine read_dimensions(this)
@ brief Read dimensions
Definition: gwf-vsc.f90:952
subroutine allocate_arrays(this, nodes)
@ brief Allocate arrays
Definition: gwf-vsc.f90:1191
subroutine vsc_set_changed_at(this, kper, kstp)
Mark K changes as having occurred at (kper, kstp)
Definition: gwf-vsc.f90:852
subroutine update_k_with_vsc(this)
Appled the viscosity ratio (mu_o/mu) to the hydraulic conductivity.
Definition: gwf-vsc.f90:825
subroutine vsc_ad_standard_bnd(packobj, hnew, visc, viscref, locelev, locvisc, locconc, dviscdc, cviscref, ivisc, a2, a3, a4, ctemp)
advance ghb while accounting for viscosity
Definition: gwf-vsc.f90:465
subroutine allocate_scalars(this)
@ brief Allocate scalars
Definition: gwf-vsc.f90:1151
subroutine vsc_ad_lak(packobj, visc, viscref, elev, locvisc, locconc, dviscdc, cviscref, ivisc, a2, a3, a4, ctemp)
Update lak-related viscosity ratios.
Definition: gwf-vsc.f90:589
subroutine calc_q_visc(this, cellid, viscratio)
Account for viscosity in the aquiferhorizontal flow barriers.
Definition: gwf-vsc.f90:802
subroutine, public vsc_cr(vscobj, name_model, inunit, iout)
@ brief Create a new package object
Definition: gwf-vsc.f90:140
real(dp) function calc_vsc_ratio(viscref, bndvisc)
calculate and return the viscosity ratio
Definition: gwf-vsc.f90:713
subroutine vsc_calcvisc(this)
Calculate fluid viscosity.
Definition: gwf-vsc.f90:1122
subroutine vsc_ad(this)
@ brief Advance the viscosity package
Definition: gwf-vsc.f90:359
subroutine vsc_ot_dv(this, idvfl)
@ brief Output viscosity package dependent-variable terms.
Definition: gwf-vsc.f90:866
real(dp) function calc_bnd_viscosity(n, locvisc, locconc, viscref, dviscdc, cviscref, ctemp, ivisc, a2, a3, a4, auxvar)
@ brief Calculate the boundary viscosity
Definition: gwf-vsc.f90:732
real(dp) function update_bnd_cond(bndvisc, viscref, spcfdcond)
Apply viscosity to the conductance term.
Definition: gwf-vsc.f90:696
subroutine vsc_ar_bnd(this, packobj)
Activate viscosity in advanced packages.
Definition: gwf-vsc.f90:233
subroutine read_options(this)
@ brief Read Options block
Definition: gwf-vsc.f90:1230
subroutine set_packagedata(this, input_data)
Sets package data instead of reading from file.
Definition: gwf-vsc.f90:1102
subroutine vsc_df(this, dis, vsc_input)
@ brief Define viscosity package options and dimensions
Definition: gwf-vsc.f90:168
subroutine vsc_ad_sfr(packobj, visc, viscref, elev, locvisc, locconc, dviscdc, cviscref, ivisc, a2, a3, a4, ctemp)
Update sfr-related viscosity ratios.
Definition: gwf-vsc.f90:535
subroutine vsc_ar(this, ibound)
@ brief Allocate and read method for viscosity package
Definition: gwf-vsc.f90:215
subroutine set_options(this, input_data)
Sets options as opposed to reading them from a file.
Definition: gwf-vsc.f90:1373
subroutine vsc_rp(this)
@ brief Read new period data in viscosity package
Definition: gwf-vsc.f90:325
subroutine vsc_ad_bnd(this, packobj, hnew)
Advance the boundary packages when viscosity is active.
Definition: gwf-vsc.f90:372
subroutine read_packagedata(this)
@ brief Read data for package
Definition: gwf-vsc.f90:1000
subroutine get_visc_ratio(this, n, m, gwhdn, gwhdm, viscratio)
Calculate the viscosity ratio.
Definition: gwf-vsc.f90:776
subroutine set_npf_pointers(this)
Set pointers to NPF variables.
Definition: gwf-vsc.f90:301
subroutine vsc_ad_maw(packobj, visc, viscref, elev, locvisc, locconc, dviscdc, cviscref, ivisc, a2, a3, a4, ctemp)
Update maw-related viscosity ratios.
Definition: gwf-vsc.f90:643
subroutine set_concentration_pointer(this, modelname, conc, icbund, istmpr)
@ brief Set pointers to concentration(s)
Definition: gwf-vsc.f90:1388
real(dp) function calc_visc(ivisc, viscref, dviscdc, cviscref, conc, a2, a3, a4)
Generic function to calculate changes in fluid viscosity using a linear formulation.
Definition: gwf-vsc.f90:99
subroutine, public urdaux(naux, inunit, iout, lloc, istart, istop, auxname, line, text)
Read auxiliary variables from an input line.
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
subroutine, public urword(line, icol, istart, istop, ncode, n, r, iout, in)
Extract a word from a string.
This module defines variable data types.
Definition: kind.f90:8
type(listtype), public basemodellist
Definition: mf6lists.f90:16
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.
character(len=20) access
Definition: OpenSpec.f90:7
character(len=20) form
Definition: OpenSpec.f90:7
This module contains the SFR package methods.
Definition: gwf-sfr.f90:7
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_warning(msg, substring)
Store warning message.
Definition: Sim.f90:236
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
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
@ brief BndType
Data structure to transfer input configuration to the.