MODFLOW 6  version 6.6.0.dev0
USGS Modular Hydrologic Model
gwf-buy.f90
Go to the documentation of this file.
1 ! Buoyancy Package for representing variable-density groundwater flow
2 ! The BUY Package does not work yet with the NPF XT3D option
3 
5 
6  use kindmodule, only: dp, i4b
13  use basedismodule, only: disbasetype
14  use gwfnpfmodule, only: gwfnpftype
17 
18  implicit none
19 
20  private
21  public :: gwfbuytype
22  public :: buy_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) :: gwfbuytype
30  type(gwfnpftype), pointer :: npf => null() !< npf object
31  integer(I4B), pointer :: ioutdense => null() !< unit number for saving density
32  integer(I4B), pointer :: iform => null() !< formulation: 0 freshwater head, 1 hh rhs, 2 hydraulic head
33  integer(I4B), pointer :: ireadelev => null() !< if 1 then elev has been allocated and filled
34  integer(I4B), pointer :: ireadconcbuy => null() !< if 1 then dense has been read from this buy input file
35  integer(I4B), pointer :: iconcset => null() !< if 1 then conc is pointed to a gwt model%x
36  real(dp), pointer :: denseref => null() !< reference fluid density
37  real(dp), dimension(:), pointer, contiguous :: dense => null() !< density
38  real(dp), dimension(:), pointer, contiguous :: concbuy => null() !< concentration array if specified in buy package
39  real(dp), dimension(:), pointer, contiguous :: elev => null() !< cell center elevation (optional; if not specified, then use (top+bot)/2)
40  integer(I4B), dimension(:), pointer :: ibound => null() !< store pointer to ibound
41 
42  integer(I4B), pointer :: nrhospecies => null() !< number of species used in equation of state to calculate density
43  real(dp), dimension(:), pointer, contiguous :: drhodc => null() !< change in density with change in concentration
44  real(dp), dimension(:), pointer, contiguous :: crhoref => null() !< reference concentration used in equation of state
45  real(dp), dimension(:), pointer, contiguous :: ctemp => null() !< temporary array of size (nrhospec) to pass to calcdens
46  character(len=LENMODELNAME), dimension(:), allocatable :: cmodelname !< names of gwt models used in equation of state
47  character(len=LENAUXNAME), dimension(:), allocatable :: cauxspeciesname !< names of gwt models used in equation of state
48 
49  type(concentrationpointer), allocatable, dimension(:) :: modelconc !< concentration pointer for each transport model
50 
51  contains
52  procedure :: buy_df
53  procedure :: buy_ar
54  procedure :: buy_ar_bnd
55  procedure :: buy_rp
56  procedure :: buy_ad
57  procedure :: buy_cf
58  procedure :: buy_cf_bnd
59  procedure :: buy_fc
60  procedure :: buy_ot_dv
61  procedure :: buy_cq
62  procedure :: buy_da
63  procedure, private :: calcbuy
64  procedure, private :: calchhterms
65  procedure, private :: buy_calcdens
66  procedure, private :: buy_calcelev
67  procedure :: allocate_scalars
68  procedure, private :: allocate_arrays
69  procedure, private :: read_options
70  procedure, private :: set_options
71  procedure, private :: read_dimensions
72  procedure, private :: read_packagedata
73  procedure, private :: set_packagedata
75  end type gwfbuytype
76 
77 contains
78 
79  !> @brief Generic function to calculate fluid density from concentration
80  !<
81  function calcdens(denseref, drhodc, crhoref, conc) result(dense)
82  ! -- dummy
83  real(dp), intent(in) :: denseref
84  real(dp), dimension(:), intent(in) :: drhodc
85  real(dp), dimension(:), intent(in) :: crhoref
86  real(dp), dimension(:), intent(in) :: conc
87  ! -- return
88  real(dp) :: dense
89  ! -- local
90  integer(I4B) :: nrhospec
91  integer(I4B) :: i
92  !
93  nrhospec = size(drhodc)
94  dense = denseref
95  do i = 1, nrhospec
96  dense = dense + drhodc(i) * (conc(i) - crhoref(i))
97  end do
98  end function calcdens
99 
100  !> @brief Create a new BUY object
101  !<
102  subroutine buy_cr(buyobj, name_model, inunit, iout)
103  ! -- dummy
104  type(gwfbuytype), pointer :: buyobj
105  character(len=*), intent(in) :: name_model
106  integer(I4B), intent(in) :: inunit
107  integer(I4B), intent(in) :: iout
108  !
109  ! -- Create the object
110  allocate (buyobj)
111  !
112  ! -- create name and memory path
113  call buyobj%set_names(1, name_model, 'BUY', 'BUY')
114  !
115  ! -- Allocate scalars
116  call buyobj%allocate_scalars()
117  !
118  ! -- Set variables
119  buyobj%inunit = inunit
120  buyobj%iout = iout
121  !
122  ! -- Initialize block parser
123  call buyobj%parser%Initialize(buyobj%inunit, buyobj%iout)
124  end subroutine buy_cr
125 
126  !> @brief Read options and package data, or set from argument
127  !<
128  subroutine buy_df(this, dis, buy_input)
129  ! -- dummy
130  class(gwfbuytype) :: this !< this buoyancy package
131  class(disbasetype), pointer, intent(in) :: dis !< pointer to discretization
132  type(gwfbuyinputdatatype), optional, intent(in) :: buy_input !< optional buy input data, otherwise read from file
133  ! -- local
134  ! -- formats
135  character(len=*), parameter :: fmtbuy = &
136  "(1x,/1x,'BUY -- Buoyancy Package, Version 1, 5/16/2018', &
137  &' input read from unit ', i0, //)"
138  !
139  ! --print a message identifying the buoyancy package.
140  if (.not. present(buy_input)) then
141  write (this%iout, fmtbuy) this%inunit
142  end if
143  !
144  ! -- store pointers to arguments that were passed in
145  this%dis => dis
146 
147  if (.not. present(buy_input)) then
148  !
149  ! -- Read buoyancy options
150  call this%read_options()
151  !
152  ! -- Read buoyancy dimensions
153  call this%read_dimensions()
154  else
155  ! set from input data instead
156  call this%set_options(buy_input)
157  this%nrhospecies = buy_input%nrhospecies
158  end if
159  !
160  ! -- Allocate arrays
161  call this%allocate_arrays(dis%nodes)
162 
163  if (.not. present(buy_input)) then
164  !
165  ! -- Read buoyancy packagedata
166  call this%read_packagedata()
167  else
168  ! set from input data instead
169  call this%set_packagedata(buy_input)
170  end if
171  end subroutine buy_df
172 
173  !> @brief Allocate and Read
174  !<
175  subroutine buy_ar(this, npf, ibound)
176  ! -- dummy
177  class(gwfbuytype) :: this
178  type(gwfnpftype), pointer, intent(in) :: npf
179  integer(I4B), dimension(:), pointer :: ibound
180  !
181  ! -- store pointers to arguments that were passed in
182  this%npf => npf
183  this%ibound => ibound
184  !
185  ! -- Ensure NPF XT3D is not on
186  if (this%npf%ixt3d /= 0) then
187  call store_error('Error in model '//trim(this%name_model)// &
188  '. The XT3D option cannot be used with the BUY Package.')
189  call this%parser%StoreErrorUnit()
190  end if
191  !
192  ! -- Calculate cell elevations
193  call this%buy_calcelev()
194  end subroutine buy_ar
195 
196  !> @brief Buoyancy ar_bnd routine to activate density in packages
197  !!
198  !! This routine is called from gwf_ar() as it goes through each package
199  !<
200  subroutine buy_ar_bnd(this, packobj, hnew)
201  ! -- modules
202  use bndmodule, only: bndtype
203  use lakmodule, only: laktype
204  use sfrmodule, only: sfrtype
205  use mawmodule, only: mawtype
206  ! -- dummy
207  class(gwfbuytype) :: this
208  class(bndtype), pointer :: packobj
209  real(DP), intent(in), dimension(:) :: hnew
210  !
211  ! -- Add density terms based on boundary package type
212  select case (packobj%filtyp)
213  case ('LAK')
214  !
215  ! -- activate density for lake package
216  select type (packobj)
217  type is (laktype)
218  call packobj%lak_activate_density()
219  end select
220  !
221  case ('SFR')
222  !
223  ! -- activate density for sfr package
224  select type (packobj)
225  type is (sfrtype)
226  call packobj%sfr_activate_density()
227  end select
228  !
229  case ('MAW')
230  !
231  ! -- activate density for maw package
232  select type (packobj)
233  type is (mawtype)
234  call packobj%maw_activate_density()
235  end select
236  !
237  case default
238  !
239  ! -- nothing
240  end select
241  end subroutine buy_ar_bnd
242 
243  !> @brief Check for new buy period data
244  !<
245  subroutine buy_rp(this)
246  ! -- modules
247  use tdismodule, only: kstp, kper
248  ! -- dummy
249  class(gwfbuytype) :: this
250  ! -- local
251  character(len=LINELENGTH) :: errmsg
252  integer(I4B) :: i
253  ! -- formats
254  character(len=*), parameter :: fmtc = &
255  "('Buoyancy Package does not have a concentration set &
256  &for species ',i0,'. One or more model names may be specified &
257  &incorrectly in the PACKAGEDATA block or a gwf-gwt exchange may need &
258  &to be activated.')"
259  !
260  ! -- Check to make sure all concentration pointers have been set
261  if (kstp * kper == 1) then
262  do i = 1, this%nrhospecies
263  if (.not. associated(this%modelconc(i)%conc)) then
264  write (errmsg, fmtc) i
265  call store_error(errmsg)
266  end if
267  end do
268  if (count_errors() > 0) then
269  call this%parser%StoreErrorUnit()
270  end if
271  end if
272  end subroutine buy_rp
273 
274  !> @brief Advance
275  !<
276  subroutine buy_ad(this)
277  ! -- dummy
278  class(gwfbuytype) :: this
279  !
280  ! -- update density using the last concentration
281  call this%buy_calcdens()
282  end subroutine buy_ad
283 
284  !> @brief Fill coefficients
285  !<
286  subroutine buy_cf(this, kiter)
287  ! -- dummy
288  class(gwfbuytype) :: this
289  integer(I4B) :: kiter
290  !
291  ! -- Recalculate the elev array for this iteration
292  if (this%ireadelev == 0) then
293  if (this%iform == 1 .or. this%iform == 2) then
294  call this%buy_calcelev()
295  end if
296  end if
297  end subroutine buy_cf
298 
299  !> @brief Fill coefficients
300  !<
301  subroutine buy_cf_bnd(this, packobj, hnew) !, hcof, rhs, auxnam, auxvar)
302  ! -- modules
303  use bndmodule, only: bndtype
304  ! -- dummy
305  class(gwfbuytype) :: this
306  class(bndtype), pointer :: packobj
307  real(DP), intent(in), dimension(:) :: hnew
308  ! -- local
309  integer(I4B) :: i, j
310  integer(I4B) :: n, locdense, locelev
311  integer(I4B), dimension(:), allocatable :: locconc
312  !
313  ! -- Return if freshwater head formulation; all boundary heads must be
314  ! entered as freshwater equivalents
315  if (this%iform == 0) return
316  !
317  ! -- initialize
318  locdense = 0
319  locelev = 0
320  allocate (locconc(this%nrhospecies))
321  locconc(:) = 0
322  !
323  ! -- Add buoyancy terms for head-dependent boundaries
324  do n = 1, packobj%naux
325  if (packobj%auxname(n) == 'DENSITY') then
326  locdense = n
327  else if (packobj%auxname(n) == 'ELEVATION') then
328  locelev = n
329  end if
330  end do
331  !
332  ! -- find aux columns for concentrations that affect density
333  do i = 1, this%nrhospecies
334  locconc(i) = 0
335  do j = 1, packobj%naux
336  if (this%cauxspeciesname(i) == packobj%auxname(j)) then
337  locconc(i) = j
338  exit
339  end if
340  end do
341  if (locconc(i) == 0) then
342  ! -- one not found, so don't use and mark all as 0
343  locconc(:) = 0
344  exit
345  end if
346  end do
347  !
348  ! -- Add density terms based on boundary package type
349  select case (packobj%filtyp)
350  case ('GHB')
351  !
352  ! -- general head boundary
353  call buy_cf_ghb(packobj, hnew, this%dense, this%elev, this%denseref, &
354  locelev, locdense, locconc, this%drhodc, this%crhoref, &
355  this%ctemp, this%iform)
356  case ('RIV')
357  !
358  ! -- river
359  call buy_cf_riv(packobj, hnew, this%dense, this%elev, this%denseref, &
360  locelev, locdense, locconc, this%drhodc, this%crhoref, &
361  this%ctemp, this%iform)
362  case ('DRN')
363  !
364  ! -- drain
365  call buy_cf_drn(packobj, hnew, this%dense, this%denseref)
366  case ('LAK')
367  !
368  ! -- lake
369  call buy_cf_lak(packobj, hnew, this%dense, this%elev, this%denseref, &
370  locdense, locconc, this%drhodc, this%crhoref, &
371  this%ctemp, this%iform)
372  case ('SFR')
373  !
374  ! -- sfr
375  call buy_cf_sfr(packobj, hnew, this%dense, this%elev, this%denseref, &
376  locdense, locconc, this%drhodc, this%crhoref, &
377  this%ctemp, this%iform)
378  case ('MAW')
379  !
380  ! -- maw
381  call buy_cf_maw(packobj, hnew, this%dense, this%elev, this%denseref, &
382  locdense, locconc, this%drhodc, this%crhoref, &
383  this%ctemp, this%iform)
384  case default
385  !
386  ! -- nothing
387  end select
388  !
389  ! -- deallocate
390  deallocate (locconc)
391  end subroutine buy_cf_bnd
392 
393  !> @brief Return the density of the boundary package using one of several
394  !! different options in the following order of priority:
395  !! 1. Assign as aux variable in column with name 'DENSITY'
396  !! 2. Calculate using equation of state and nrhospecies aux columns
397  !! 3. If neither of those, then assign as denseref
398  !<
399  function get_bnd_density(n, locdense, locconc, denseref, drhodc, crhoref, &
400  ctemp, auxvar) result(densebnd)
401  ! -- dummy
402  integer(I4B), intent(in) :: n
403  integer(I4B), intent(in) :: locdense
404  integer(I4B), dimension(:), intent(in) :: locconc
405  real(dp), intent(in) :: denseref
406  real(dp), dimension(:), intent(in) :: drhodc
407  real(dp), dimension(:), intent(in) :: crhoref
408  real(dp), dimension(:), intent(inout) :: ctemp
409  real(dp), dimension(:, :), intent(in) :: auxvar
410  ! -- return
411  real(dp) :: densebnd
412  ! -- local
413  integer(I4B) :: i
414  !
415  ! -- assign boundary density based on one of three options
416  if (locdense > 0) then
417  ! -- assign density to an aux column named 'DENSITY'
418  densebnd = auxvar(locdense, n)
419  else if (locconc(1) > 0) then
420  ! -- calculate density using one or more concentration auxcolumns
421  do i = 1, size(locconc)
422  ctemp(i) = dzero
423  if (locconc(i) > 0) then
424  ctemp(i) = auxvar(locconc(i), n)
425  end if
426  end do
427  densebnd = calcdens(denseref, drhodc, crhoref, ctemp)
428  else
429  ! -- neither of the above, so assign as denseref
430  densebnd = denseref
431  end if
432  end function get_bnd_density
433 
434  !> @brief Fill ghb coefficients
435  !<
436  subroutine buy_cf_ghb(packobj, hnew, dense, elev, denseref, locelev, &
437  locdense, locconc, drhodc, crhoref, ctemp, &
438  iform)
439  ! -- modules
440  use bndmodule, only: bndtype
441  use ghbmodule, only: ghbtype
442  class(bndtype), pointer :: packobj
443  ! -- dummy
444  real(DP), intent(in), dimension(:) :: hnew
445  real(DP), intent(in), dimension(:) :: dense
446  real(DP), intent(in), dimension(:) :: elev
447  real(DP), intent(in) :: denseref
448  integer(I4B), intent(in) :: locelev
449  integer(I4B), intent(in) :: locdense
450  integer(I4B), dimension(:), intent(in) :: locconc
451  real(DP), dimension(:), intent(in) :: drhodc
452  real(DP), dimension(:), intent(in) :: crhoref
453  real(DP), dimension(:), intent(inout) :: ctemp
454  integer(I4B), intent(in) :: iform
455  ! -- local
456  integer(I4B) :: n
457  integer(I4B) :: node
458  real(DP) :: denseghb
459  real(DP) :: elevghb
460  real(DP) :: hghb
461  real(DP) :: cond
462  real(DP) :: hcofterm, rhsterm
463  !
464  ! -- Process density terms for each GHB
465  select type (packobj)
466  type is (ghbtype)
467  do n = 1, packobj%nbound
468  node = packobj%nodelist(n)
469  if (packobj%ibound(node) <= 0) cycle
470  !
471  ! -- density
472  denseghb = get_bnd_density(n, locdense, locconc, denseref, &
473  drhodc, crhoref, ctemp, packobj%auxvar)
474  !
475  ! -- elevation
476  elevghb = elev(node)
477  if (locelev > 0) elevghb = packobj%auxvar(locelev, n)
478  !
479  ! -- boundary head and conductance
480  hghb = packobj%bhead(n)
481  cond = packobj%cond(n)
482  !
483  ! -- calculate HCOF and RHS terms
484  call calc_ghb_hcof_rhs_terms(denseref, denseghb, dense(node), &
485  elevghb, elev(node), hghb, hnew(node), &
486  cond, iform, rhsterm, hcofterm)
487  packobj%hcof(n) = packobj%hcof(n) + hcofterm
488  packobj%rhs(n) = packobj%rhs(n) - rhsterm
489  !
490  end do
491  end select
492  end subroutine buy_cf_ghb
493 
494  !> @brief Calculate density hcof and rhs terms for ghb conditions
495  !<
496  subroutine calc_ghb_hcof_rhs_terms(denseref, denseghb, densenode, &
497  elevghb, elevnode, hghb, hnode, &
498  cond, iform, rhsterm, hcofterm)
499  ! -- dummy
500  real(DP), intent(in) :: denseref
501  real(DP), intent(in) :: denseghb
502  real(DP), intent(in) :: densenode
503  real(DP), intent(in) :: elevghb
504  real(DP), intent(in) :: elevnode
505  real(DP), intent(in) :: hghb
506  real(DP), intent(in) :: hnode
507  real(DP), intent(in) :: cond
508  integer(I4B), intent(in) :: iform
509  real(DP), intent(inout) :: rhsterm
510  real(DP), intent(inout) :: hcofterm
511  ! -- local
512  real(DP) :: t1, t2
513  real(DP) :: avgdense, avgelev
514  !
515  ! -- Calculate common terms
516  avgdense = dhalf * denseghb + dhalf * densenode
517  avgelev = dhalf * elevghb + dhalf * elevnode
518  t1 = avgdense / denseref - done
519  t2 = (denseghb - densenode) / denseref
520  !
521  ! -- Add hcof terms
522  hcofterm = -cond * t1
523  if (iform == 2) then
524  !
525  ! -- this term goes on RHS for iform == 1
526  hcofterm = hcofterm + dhalf * cond * t2
527  end if
528  !
529  ! -- Add rhs terms
530  rhsterm = cond * t1 * hghb
531  rhsterm = rhsterm - cond * t2 * avgelev
532  rhsterm = rhsterm + dhalf * cond * t2 * hghb
533  if (iform == 1) then
534  !
535  ! -- this term goes on LHS for iform == 2
536  rhsterm = rhsterm + dhalf * cond * t2 * hnode
537  end if
538  end subroutine calc_ghb_hcof_rhs_terms
539 
540  !> @brief Fill riv coefficients
541  !<
542  subroutine buy_cf_riv(packobj, hnew, dense, elev, denseref, locelev, &
543  locdense, locconc, drhodc, crhoref, ctemp, &
544  iform)
545  ! -- modules
546  use bndmodule, only: bndtype
547  use rivmodule, only: rivtype
548  class(bndtype), pointer :: packobj
549  ! -- dummy
550  real(DP), intent(in), dimension(:) :: hnew
551  real(DP), intent(in), dimension(:) :: dense
552  real(DP), intent(in), dimension(:) :: elev
553  real(DP), intent(in) :: denseref
554  integer(I4B), intent(in) :: locelev
555  integer(I4B), intent(in) :: locdense
556  integer(I4B), dimension(:), intent(in) :: locconc
557  real(DP), dimension(:), intent(in) :: drhodc
558  real(DP), dimension(:), intent(in) :: crhoref
559  real(DP), dimension(:), intent(inout) :: ctemp
560  integer(I4B), intent(in) :: iform
561  ! -- local
562  integer(I4B) :: n
563  integer(I4B) :: node
564  real(DP) :: denseriv
565  real(DP) :: elevriv
566  real(DP) :: hriv
567  real(DP) :: rbot
568  real(DP) :: cond
569  real(DP) :: hcofterm
570  real(DP) :: rhsterm
571  !
572  ! -- Process density terms for each RIV
573  select type (packobj)
574  type is (rivtype)
575  do n = 1, packobj%nbound
576  node = packobj%nodelist(n)
577  if (packobj%ibound(node) <= 0) cycle
578  !
579  ! -- density
580  denseriv = get_bnd_density(n, locdense, locconc, denseref, &
581  drhodc, crhoref, ctemp, packobj%auxvar)
582  !
583  ! -- elevation
584  elevriv = elev(node)
585  if (locelev > 0) elevriv = packobj%auxvar(locelev, n)
586  !
587  ! -- boundary head and conductance
588  hriv = packobj%stage(n)
589  cond = packobj%cond(n)
590  rbot = packobj%rbot(n)
591  !
592  ! -- calculate and add terms depending on whether head is above rbot
593  if (hnew(node) > rbot) then
594  !
595  ! --calculate HCOF and RHS terms, similar to GHB in this case
596  call calc_ghb_hcof_rhs_terms(denseref, denseriv, dense(node), &
597  elevriv, elev(node), hriv, hnew(node), &
598  cond, iform, rhsterm, hcofterm)
599  else
600  hcofterm = dzero
601  rhsterm = cond * (denseriv / denseref - done) * (hriv - rbot)
602  end if
603  !
604  ! -- Add terms to package hcof and rhs accumulators
605  packobj%hcof(n) = packobj%hcof(n) + hcofterm
606  packobj%rhs(n) = packobj%rhs(n) - rhsterm
607  end do
608  end select
609  end subroutine buy_cf_riv
610 
611  !> @brief Fill drn coefficients
612  !<
613  subroutine buy_cf_drn(packobj, hnew, dense, denseref)
614  ! -- modules
615  use bndmodule, only: bndtype
616  use drnmodule, only: drntype
617  class(bndtype), pointer :: packobj
618  ! -- dummy
619  real(DP), intent(in), dimension(:) :: hnew
620  real(DP), intent(in), dimension(:) :: dense
621  real(DP), intent(in) :: denseref
622  ! -- local
623  integer(I4B) :: n
624  integer(I4B) :: node
625  real(DP) :: rho
626  real(DP) :: hbnd
627  real(DP) :: cond
628  real(DP) :: hcofterm
629  real(DP) :: rhsterm
630  !
631  ! -- Process density terms for each DRN
632  select type (packobj)
633  type is (drntype)
634  do n = 1, packobj%nbound
635  node = packobj%nodelist(n)
636  if (packobj%ibound(node) <= 0) cycle
637  rho = dense(node)
638  hbnd = packobj%elev(n)
639  cond = packobj%cond(n)
640  if (hnew(node) > hbnd) then
641  hcofterm = -cond * (rho / denseref - done)
642  rhsterm = hcofterm * hbnd
643  packobj%hcof(n) = packobj%hcof(n) + hcofterm
644  packobj%rhs(n) = packobj%rhs(n) + rhsterm
645  end if
646  end do
647  end select
648  end subroutine buy_cf_drn
649 
650  !> @brief Pass density information into lak package; density terms are
651  !! calculated in the lake package as part of lak_calculate_density_exchange
652  !! method
653  !<
654  subroutine buy_cf_lak(packobj, hnew, dense, elev, denseref, locdense, &
655  locconc, drhodc, crhoref, ctemp, iform)
656  ! -- modules
657  use bndmodule, only: bndtype
658  use lakmodule, only: laktype
659  class(bndtype), pointer :: packobj
660  ! -- dummy
661  real(DP), intent(in), dimension(:) :: hnew
662  real(DP), intent(in), dimension(:) :: dense
663  real(DP), intent(in), dimension(:) :: elev
664  real(DP), intent(in) :: denseref
665  integer(I4B), intent(in) :: locdense
666  integer(I4B), dimension(:), intent(in) :: locconc
667  real(DP), dimension(:), intent(in) :: drhodc
668  real(DP), dimension(:), intent(in) :: crhoref
669  real(DP), dimension(:), intent(inout) :: ctemp
670  integer(I4B), intent(in) :: iform
671  ! -- local
672  integer(I4B) :: n
673  integer(I4B) :: node
674  real(DP) :: denselak
675  !
676  ! -- Insert the lake and gwf relative densities into col 1 and 2 and the
677  ! gwf elevation into col 3 of the lake package denseterms array
678  select type (packobj)
679  type is (laktype)
680  do n = 1, packobj%nbound
681  !
682  ! -- get gwf node number
683  node = packobj%nodelist(n)
684  if (packobj%ibound(node) <= 0) cycle
685  !
686  ! -- Determine lak density
687  denselak = get_bnd_density(n, locdense, locconc, denseref, &
688  drhodc, crhoref, ctemp, packobj%auxvar)
689  !
690  ! -- fill lak relative density into column 1 of denseterms
691  packobj%denseterms(1, n) = denselak / denseref
692  !
693  ! -- fill gwf relative density into column 2 of denseterms
694  packobj%denseterms(2, n) = dense(node) / denseref
695  !
696  ! -- fill gwf elevation into column 3 of denseterms
697  packobj%denseterms(3, n) = elev(node)
698  !
699  end do
700  end select
701  end subroutine buy_cf_lak
702 
703  !> @brief Pass density information into sfr package; density terms are
704  !! calculated in the sfr package as part of sfr_calculate_density_exchange
705  !! method
706  !<
707  subroutine buy_cf_sfr(packobj, hnew, dense, elev, denseref, locdense, &
708  locconc, drhodc, crhoref, ctemp, iform)
709  ! -- modules
710  use bndmodule, only: bndtype
711  use sfrmodule, only: sfrtype
712  class(bndtype), pointer :: packobj
713  ! -- dummy
714  real(DP), intent(in), dimension(:) :: hnew
715  real(DP), intent(in), dimension(:) :: dense
716  real(DP), intent(in), dimension(:) :: elev
717  real(DP), intent(in) :: denseref
718  integer(I4B), intent(in) :: locdense
719  integer(I4B), dimension(:), intent(in) :: locconc
720  real(DP), dimension(:), intent(in) :: drhodc
721  real(DP), dimension(:), intent(in) :: crhoref
722  real(DP), dimension(:), intent(inout) :: ctemp
723  integer(I4B), intent(in) :: iform
724  ! -- local
725  integer(I4B) :: n
726  integer(I4B) :: node
727  real(DP) :: densesfr
728  !
729  ! -- Insert the sfr and gwf relative densities into col 1 and 2 and the
730  ! gwf elevation into col 3 of the sfr package denseterms array
731  select type (packobj)
732  type is (sfrtype)
733  do n = 1, packobj%nbound
734  !
735  ! -- get gwf node number
736  node = packobj%nodelist(n)
737  if (packobj%ibound(node) <= 0) cycle
738  !
739  ! -- Determine sfr density
740  densesfr = get_bnd_density(n, locdense, locconc, denseref, &
741  drhodc, crhoref, ctemp, packobj%auxvar)
742  !
743  ! -- fill sfr relative density into column 1 of denseterms
744  packobj%denseterms(1, n) = densesfr / denseref
745  !
746  ! -- fill gwf relative density into column 2 of denseterms
747  packobj%denseterms(2, n) = dense(node) / denseref
748  !
749  ! -- fill gwf elevation into column 3 of denseterms
750  packobj%denseterms(3, n) = elev(node)
751  !
752  end do
753  end select
754  end subroutine buy_cf_sfr
755 
756  !> @brief Pass density information into maw package; density terms are
757  !! calculated in the maw package as part of maw_calculate_density_exchange
758  !! method
759  !<
760  subroutine buy_cf_maw(packobj, hnew, dense, elev, denseref, locdense, &
761  locconc, drhodc, crhoref, ctemp, iform)
762  ! -- modules
763  use bndmodule, only: bndtype
764  use mawmodule, only: mawtype
765  class(bndtype), pointer :: packobj
766  ! -- dummy
767  real(DP), intent(in), dimension(:) :: hnew
768  real(DP), intent(in), dimension(:) :: dense
769  real(DP), intent(in), dimension(:) :: elev
770  real(DP), intent(in) :: denseref
771  integer(I4B), intent(in) :: locdense
772  integer(I4B), dimension(:), intent(in) :: locconc
773  real(DP), dimension(:), intent(in) :: drhodc
774  real(DP), dimension(:), intent(in) :: crhoref
775  real(DP), dimension(:), intent(inout) :: ctemp
776  integer(I4B), intent(in) :: iform
777  ! -- local
778  integer(I4B) :: n
779  integer(I4B) :: node
780  real(DP) :: densemaw
781  !
782  ! -- Insert the maw and gwf relative densities into col 1 and 2 and the
783  ! gwf elevation into col 3 of the maw package denseterms array
784  select type (packobj)
785  type is (mawtype)
786  do n = 1, packobj%nbound
787  !
788  ! -- get gwf node number
789  node = packobj%nodelist(n)
790  if (packobj%ibound(node) <= 0) cycle
791  !
792  ! -- Determine maw density
793  densemaw = get_bnd_density(n, locdense, locconc, denseref, &
794  drhodc, crhoref, ctemp, packobj%auxvar)
795  !
796  ! -- fill maw relative density into column 1 of denseterms
797  packobj%denseterms(1, n) = densemaw / denseref
798  !
799  ! -- fill gwf relative density into column 2 of denseterms
800  packobj%denseterms(2, n) = dense(node) / denseref
801  !
802  ! -- fill gwf elevation into column 3 of denseterms
803  packobj%denseterms(3, n) = elev(node)
804  !
805  end do
806  end select
807  end subroutine buy_cf_maw
808 
809  !> @brief Fill coefficients
810  !<
811  subroutine buy_fc(this, kiter, matrix_sln, idxglo, rhs, hnew)
812  ! -- dummy
813  class(gwfbuytype) :: this
814  integer(I4B) :: kiter
815  class(matrixbasetype), pointer :: matrix_sln
816  integer(I4B), intent(in), dimension(:) :: idxglo
817  real(DP), dimension(:), intent(inout) :: rhs
818  real(DP), intent(inout), dimension(:) :: hnew
819  ! -- local
820  integer(I4B) :: n, m, ipos, idiag
821  real(DP) :: rhsterm, amatnn, amatnm
822  !
823  ! -- initialize
824  amatnn = dzero
825  amatnm = dzero
826  !
827  ! -- fill buoyancy flow term
828  do n = 1, this%dis%nodes
829  if (this%ibound(n) == 0) cycle
830  idiag = this%dis%con%ia(n)
831  do ipos = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1
832  m = this%dis%con%ja(ipos)
833  if (this%ibound(m) == 0) cycle
834  if (this%iform == 0) then
835  call this%calcbuy(n, m, ipos, hnew(n), hnew(m), rhsterm)
836  else
837  call this%calchhterms(n, m, ipos, hnew(n), hnew(m), rhsterm, &
838  amatnn, amatnm)
839  end if
840  !
841  ! -- Add terms to rhs, diagonal, and off diagonal
842  rhs(n) = rhs(n) - rhsterm
843  call matrix_sln%add_value_pos(idxglo(idiag), -amatnn)
844  call matrix_sln%add_value_pos(idxglo(ipos), amatnm)
845  end do
846  end do
847  end subroutine buy_fc
848 
849  !> @brief Save density array to binary file
850  !<
851  subroutine buy_ot_dv(this, idvfl)
852  ! -- dummy
853  class(gwfbuytype) :: this
854  integer(I4B), intent(in) :: idvfl
855  ! -- local
856  character(len=1) :: cdatafmp = ' ', editdesc = ' '
857  integer(I4B) :: ibinun
858  integer(I4B) :: iprint
859  integer(I4B) :: nvaluesp
860  integer(I4B) :: nwidthp
861  real(DP) :: dinact
862  !
863  ! -- Set unit number for density output
864  if (this%ioutdense /= 0) then
865  ibinun = 1
866  else
867  ibinun = 0
868  end if
869  if (idvfl == 0) ibinun = 0
870  !
871  ! -- save density array
872  if (ibinun /= 0) then
873  iprint = 0
874  dinact = dhnoflo
875  !
876  ! -- write density to binary file
877  if (this%ioutdense /= 0) then
878  ibinun = this%ioutdense
879  call this%dis%record_array(this%dense, this%iout, iprint, ibinun, &
880  ' DENSITY', cdatafmp, nvaluesp, &
881  nwidthp, editdesc, dinact)
882  end if
883  end if
884  end subroutine buy_ot_dv
885 
886  !> @brief Add buy term to flowja
887  !<
888  subroutine buy_cq(this, hnew, flowja)
889  implicit none
890  class(gwfbuytype) :: this
891  real(DP), intent(in), dimension(:) :: hnew
892  real(DP), intent(inout), dimension(:) :: flowja
893  integer(I4B) :: n, m, ipos
894  real(DP) :: deltaQ
895  real(DP) :: rhsterm, amatnn, amatnm
896  !
897  ! -- Calculate the flow across each cell face and store in flowja
898  do n = 1, this%dis%nodes
899  do ipos = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1
900  m = this%dis%con%ja(ipos)
901  if (m < n) cycle
902  if (this%iform == 0) then
903  ! -- equivalent freshwater head formulation
904  call this%calcbuy(n, m, ipos, hnew(n), hnew(m), deltaq)
905  else
906  ! -- hydraulic head formulation
907  call this%calchhterms(n, m, ipos, hnew(n), hnew(m), rhsterm, &
908  amatnn, amatnm)
909  deltaq = amatnm * hnew(m) - amatnn * hnew(n) + rhsterm
910  end if
911  flowja(ipos) = flowja(ipos) + deltaq
912  flowja(this%dis%con%isym(ipos)) = flowja(this%dis%con%isym(ipos)) - &
913  deltaq
914  end do
915  end do
916  end subroutine buy_cq
917 
918  !> @brief Deallocate
919  !<
920  subroutine buy_da(this)
921  ! -- dummy
922  class(gwfbuytype) :: this
923  !
924  ! -- Deallocate arrays if package was active
925  if (this%inunit > 0) then
926  call mem_deallocate(this%elev)
927  call mem_deallocate(this%dense)
928  call mem_deallocate(this%concbuy)
929  call mem_deallocate(this%drhodc)
930  call mem_deallocate(this%crhoref)
931  call mem_deallocate(this%ctemp)
932  deallocate (this%cmodelname)
933  deallocate (this%cauxspeciesname)
934  deallocate (this%modelconc)
935  end if
936  !
937  ! -- Scalars
938  call mem_deallocate(this%ioutdense)
939  call mem_deallocate(this%iform)
940  call mem_deallocate(this%ireadelev)
941  call mem_deallocate(this%ireadconcbuy)
942  call mem_deallocate(this%iconcset)
943  call mem_deallocate(this%denseref)
944  !
945  call mem_deallocate(this%nrhospecies)
946  !
947  ! -- deallocate parent
948  call this%NumericalPackageType%da()
949  end subroutine buy_da
950 
951  !> @brief Read the dimensions for this package
952  !<
953  subroutine read_dimensions(this)
954  ! -- dummy
955  class(gwfbuytype), intent(inout) :: this
956  ! -- local
957  character(len=LINELENGTH) :: errmsg, keyword
958  integer(I4B) :: ierr
959  logical :: isfound, endOfBlock
960  ! -- format
961  !
962  ! -- get dimensions block
963  call this%parser%GetBlock('DIMENSIONS', isfound, ierr, &
964  supportopenclose=.true.)
965  !
966  ! -- parse dimensions block if detected
967  if (isfound) then
968  write (this%iout, '(/1x,a)') 'Processing BUY DIMENSIONS block'
969  do
970  call this%parser%GetNextLine(endofblock)
971  if (endofblock) exit
972  call this%parser%GetStringCaps(keyword)
973  select case (keyword)
974  case ('NRHOSPECIES')
975  this%nrhospecies = this%parser%GetInteger()
976  write (this%iout, '(4x,a,i0)') 'NRHOSPECIES = ', this%nrhospecies
977  case default
978  write (errmsg, '(a,a)') &
979  'Unknown BUY dimension: ', trim(keyword)
980  call store_error(errmsg)
981  call this%parser%StoreErrorUnit()
982  end select
983  end do
984  write (this%iout, '(1x,a)') 'End of BUY DIMENSIONS block'
985  else
986  call store_error('Required BUY DIMENSIONS block not found.')
987  call this%parser%StoreErrorUnit()
988  end if
989  !
990  ! -- check dimension
991  if (this%nrhospecies < 1) then
992  call store_error('NRHOSPECIES must be greater than zero.')
993  call this%parser%StoreErrorUnit()
994  end if
995  end subroutine read_dimensions
996 
997  !> @brief Read PACKAGEDATA block
998  !<
999  subroutine read_packagedata(this)
1000  ! -- dummy
1001  class(gwfbuytype) :: this
1002  ! -- local
1003  character(len=LINELENGTH) :: errmsg
1004  character(len=LINELENGTH) :: line
1005  integer(I4B) :: ierr
1006  integer(I4B) :: irhospec
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 BUY Package. &
1015  &IRHOSPEC must be > 0 and <= NRHOSPECIES, and duplicate values &
1016  &are not allowed.')"
1017  !
1018  ! -- initialize
1019  allocate (itemp(this%nrhospecies))
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)') 'Processing BUY PACKAGEDATA block'
1031  do
1032  call this%parser%GetNextLine(endofblock)
1033  if (endofblock) exit
1034  irhospec = this%parser%GetInteger()
1035  if (irhospec < 1 .or. irhospec > this%nrhospecies) then
1036  write (errmsg, fmterr) irhospec
1037  call store_error(errmsg)
1038  end if
1039  if (itemp(irhospec) /= 0) then
1040  write (errmsg, fmterr) irhospec
1041  call store_error(errmsg)
1042  end if
1043  itemp(irhospec) = 1
1044  this%drhodc(irhospec) = this%parser%GetDouble()
1045  this%crhoref(irhospec) = this%parser%GetDouble()
1046  call this%parser%GetStringCaps(this%cmodelname(irhospec))
1047  call this%parser%GetStringCaps(this%cauxspeciesname(irhospec))
1048  end do
1049  write (this%iout, '(1x,a)') 'End of BUY PACKAGEDATA block'
1050  else
1051  call store_error('Required BUY PACKAGEDATA block not found.')
1052  call this%parser%StoreErrorUnit()
1053  end if
1054  !
1055  ! -- Check for errors.
1056  if (count_errors() > 0) then
1057  call this%parser%StoreErrorUnit()
1058  end if
1059  !
1060  ! -- write packagedata information
1061  write (this%iout, '(/,a)') 'Summary of species information in BUY Package'
1062  write (this%iout, '(1a11, 4a17)') &
1063  'SPECIES', 'DRHODC', 'CRHOREF', 'MODEL', &
1064  'AUXSPECIESNAME'
1065  do irhospec = 1, this%nrhospecies
1066  write (c10, '(i0)') irhospec
1067  line = ' '//adjustr(c10)
1068  write (c16, '(g15.6)') this%drhodc(irhospec)
1069  line = trim(line)//' '//adjustr(c16)
1070  write (c16, '(g15.6)') this%crhoref(irhospec)
1071  line = trim(line)//' '//adjustr(c16)
1072  write (c16, '(a)') this%cmodelname(irhospec)
1073  line = trim(line)//' '//adjustr(c16)
1074  write (c16, '(a)') this%cauxspeciesname(irhospec)
1075  line = trim(line)//' '//adjustr(c16)
1076  write (this%iout, '(a)') trim(line)
1077  end do
1078  !
1079  ! -- deallocate
1080  deallocate (itemp)
1081  end subroutine read_packagedata
1082 
1083  !> @brief Sets package data instead of reading from file
1084  !<
1085  subroutine set_packagedata(this, input_data)
1086  ! -- dummy
1087  class(gwfbuytype) :: this !< this buyoancy pkg
1088  type(gwfbuyinputdatatype), intent(in) :: input_data !< the input data to be set
1089  ! -- local
1090  integer(I4B) :: ispec
1091 
1092  do ispec = 1, this%nrhospecies
1093  this%drhodc(ispec) = input_data%drhodc(ispec)
1094  this%crhoref(ispec) = input_data%crhoref(ispec)
1095  this%cmodelname(ispec) = input_data%cmodelname(ispec)
1096  this%cauxspeciesname(ispec) = input_data%cauxspeciesname(ispec)
1097  end do
1098  end subroutine set_packagedata
1099 
1100  !> @brief Calculate buyancy term for this connection
1101  !<
1102  subroutine calcbuy(this, n, m, icon, hn, hm, buy)
1103  ! -- modules
1105  ! -- dummy
1106  class(gwfbuytype) :: this
1107  integer(I4B), intent(in) :: n
1108  integer(I4B), intent(in) :: m
1109  integer(I4B), intent(in) :: icon
1110  real(DP), intent(in) :: hn
1111  real(DP), intent(in) :: hm
1112  real(DP), intent(inout) :: buy
1113  ! -- local
1114  integer(I4B) :: ihc
1115  real(DP) :: densen, densem, cl1, cl2, avgdense, wt, elevn, elevm, &
1116  cond, tp, bt
1117  real(DP) :: hyn
1118  real(DP) :: hym
1119  !
1120  ! -- Average density
1121  densen = this%dense(n)
1122  densem = this%dense(m)
1123  if (m > n) then
1124  cl1 = this%dis%con%cl1(this%dis%con%jas(icon))
1125  cl2 = this%dis%con%cl2(this%dis%con%jas(icon))
1126  else
1127  cl1 = this%dis%con%cl2(this%dis%con%jas(icon))
1128  cl2 = this%dis%con%cl1(this%dis%con%jas(icon))
1129  end if
1130  wt = cl1 / (cl1 + cl2)
1131  avgdense = wt * densen + (done - wt) * densem
1132  !
1133  ! -- Elevations
1134  if (this%ireadelev == 0) then
1135  tp = this%dis%top(n)
1136  bt = this%dis%bot(n)
1137  elevn = bt + dhalf * this%npf%sat(n) * (tp - bt)
1138  tp = this%dis%top(m)
1139  bt = this%dis%bot(m)
1140  elevm = bt + dhalf * this%npf%sat(m) * (tp - bt)
1141  else
1142  elevn = this%elev(n)
1143  elevm = this%elev(m)
1144  end if
1145  !
1146  ihc = this%dis%con%ihc(this%dis%con%jas(icon))
1147  hyn = this%npf%hy_eff(n, m, ihc, ipos=icon)
1148  hym = this%npf%hy_eff(m, n, ihc, ipos=icon)
1149  !
1150  ! -- Conductance
1151  if (this%dis%con%ihc(this%dis%con%jas(icon)) == 0) then
1152  cond = vcond(this%ibound(n), this%ibound(m), &
1153  this%npf%icelltype(n), this%npf%icelltype(m), &
1154  this%npf%inewton, &
1155  this%npf%ivarcv, this%npf%idewatcv, &
1156  this%npf%condsat(this%dis%con%jas(icon)), hn, hm, &
1157  hyn, hym, &
1158  this%npf%sat(n), this%npf%sat(m), &
1159  this%dis%top(n), this%dis%top(m), &
1160  this%dis%bot(n), this%dis%bot(m), &
1161  this%dis%con%hwva(this%dis%con%jas(icon)))
1162  else
1163  cond = hcond(this%ibound(n), this%ibound(m), &
1164  this%npf%icelltype(n), this%npf%icelltype(m), &
1165  this%npf%inewton, &
1166  this%dis%con%ihc(this%dis%con%jas(icon)), &
1167  this%npf%icellavg, &
1168  this%npf%condsat(this%dis%con%jas(icon)), &
1169  hn, hm, this%npf%sat(n), this%npf%sat(m), &
1170  hyn, hym, &
1171  this%dis%top(n), this%dis%top(m), &
1172  this%dis%bot(n), this%dis%bot(m), &
1173  this%dis%con%cl1(this%dis%con%jas(icon)), &
1174  this%dis%con%cl2(this%dis%con%jas(icon)), &
1175  this%dis%con%hwva(this%dis%con%jas(icon)))
1176  end if
1177  !
1178  ! -- Calculate buoyancy term
1179  buy = cond * (avgdense - this%denseref) / this%denseref * (elevm - elevn)
1180  end subroutine calcbuy
1181 
1182  !> @brief Calculate hydraulic head term for this connection
1183  !<
1184  subroutine calchhterms(this, n, m, icon, hn, hm, rhsterm, amatnn, amatnm)
1185  ! -- modules
1187  ! -- dummy
1188  class(gwfbuytype) :: this
1189  integer(I4B), intent(in) :: n
1190  integer(I4B), intent(in) :: m
1191  integer(I4B), intent(in) :: icon
1192  real(DP), intent(in) :: hn
1193  real(DP), intent(in) :: hm
1194  real(DP), intent(inout) :: rhsterm
1195  real(DP), intent(inout) :: amatnn
1196  real(DP), intent(inout) :: amatnm
1197  ! -- local
1198  integer(I4B) :: ihc
1199  real(DP) :: densen, densem, cl1, cl2, avgdense, wt, elevn, elevm, cond
1200  real(DP) :: rhonormn, rhonormm
1201  real(DP) :: rhoterm
1202  real(DP) :: elevnm
1203  real(DP) :: hphi
1204  real(DP) :: hyn
1205  real(DP) :: hym
1206  !
1207  ! -- Average density
1208  densen = this%dense(n)
1209  densem = this%dense(m)
1210  if (m > n) then
1211  cl1 = this%dis%con%cl1(this%dis%con%jas(icon))
1212  cl2 = this%dis%con%cl2(this%dis%con%jas(icon))
1213  else
1214  cl1 = this%dis%con%cl2(this%dis%con%jas(icon))
1215  cl2 = this%dis%con%cl1(this%dis%con%jas(icon))
1216  end if
1217  wt = cl1 / (cl1 + cl2)
1218  avgdense = wt * densen + (1.0 - wt) * densem
1219  !
1220  ! -- Elevations
1221  elevn = this%elev(n)
1222  elevm = this%elev(m)
1223  elevnm = (done - wt) * elevn + wt * elevm
1224  !
1225  ihc = this%dis%con%ihc(this%dis%con%jas(icon))
1226  hyn = this%npf%hy_eff(n, m, ihc, ipos=icon)
1227  hym = this%npf%hy_eff(m, n, ihc, ipos=icon)
1228  !
1229  ! -- Conductance
1230  if (ihc == 0) then
1231  cond = vcond(this%ibound(n), this%ibound(m), &
1232  this%npf%icelltype(n), this%npf%icelltype(m), &
1233  this%npf%inewton, &
1234  this%npf%ivarcv, this%npf%idewatcv, &
1235  this%npf%condsat(this%dis%con%jas(icon)), hn, hm, &
1236  hyn, hym, &
1237  this%npf%sat(n), this%npf%sat(m), &
1238  this%dis%top(n), this%dis%top(m), &
1239  this%dis%bot(n), this%dis%bot(m), &
1240  this%dis%con%hwva(this%dis%con%jas(icon)))
1241  else
1242  cond = hcond(this%ibound(n), this%ibound(m), &
1243  this%npf%icelltype(n), this%npf%icelltype(m), &
1244  this%npf%inewton, &
1245  this%dis%con%ihc(this%dis%con%jas(icon)), &
1246  this%npf%icellavg, &
1247  this%npf%condsat(this%dis%con%jas(icon)), &
1248  hn, hm, this%npf%sat(n), this%npf%sat(m), &
1249  hyn, hym, &
1250  this%dis%top(n), this%dis%top(m), &
1251  this%dis%bot(n), this%dis%bot(m), &
1252  this%dis%con%cl1(this%dis%con%jas(icon)), &
1253  this%dis%con%cl2(this%dis%con%jas(icon)), &
1254  this%dis%con%hwva(this%dis%con%jas(icon)))
1255  end if
1256  !
1257  ! -- Calculate terms
1258  rhonormn = densen / this%denseref
1259  rhonormm = densem / this%denseref
1260  rhoterm = wt * rhonormn + (done - wt) * rhonormm
1261  amatnn = cond * (rhoterm - done)
1262  amatnm = amatnn
1263  rhsterm = -cond * (rhonormm - rhonormn) * elevnm
1264  if (this%iform == 1) then
1265  ! -- rhs (lag the h terms and keep matrix symmetric)
1266  hphi = (done - wt) * hn + wt * hm
1267  rhsterm = rhsterm + cond * hphi * (rhonormm - rhonormn)
1268  else
1269  ! -- lhs, results in asymmetric matrix due to weight term
1270  amatnn = amatnn - cond * (done - wt) * (rhonormm - rhonormn)
1271  amatnm = amatnm + cond * wt * (rhonormm - rhonormn)
1272  end if
1273  end subroutine calchhterms
1274 
1275  !> @brief calculate fluid density from concentration
1276  !<
1277  subroutine buy_calcdens(this)
1278  ! -- dummy
1279  class(gwfbuytype) :: this
1280 
1281  ! -- local
1282  integer(I4B) :: n
1283  integer(I4B) :: i
1284  !
1285  ! -- Calculate the density using the specified concentration array
1286  do n = 1, this%dis%nodes
1287  do i = 1, this%nrhospecies
1288  if (this%modelconc(i)%icbund(n) == 0) then
1289  this%ctemp = dzero
1290  else
1291  this%ctemp(i) = this%modelconc(i)%conc(n)
1292  end if
1293  end do
1294  this%dense(n) = calcdens(this%denseref, this%drhodc, this%crhoref, &
1295  this%ctemp)
1296  end do
1297  end subroutine buy_calcdens
1298 
1299  !> @brief Calculate cell elevations to use in density flow equations
1300  !<
1301  subroutine buy_calcelev(this)
1302  ! -- dummy
1303  class(gwfbuytype) :: this
1304  ! -- local
1305  integer(I4B) :: n
1306  real(DP) :: tp, bt, frac
1307  !
1308  ! -- Calculate the elev array
1309  do n = 1, this%dis%nodes
1310  tp = this%dis%top(n)
1311  bt = this%dis%bot(n)
1312  frac = this%npf%sat(n)
1313  this%elev(n) = bt + dhalf * frac * (tp - bt)
1314  end do
1315  end subroutine buy_calcelev
1316 
1317  !> @brief Allocate scalars used by the package
1318  !<
1319  subroutine allocate_scalars(this)
1320  ! -- modules
1321  use constantsmodule, only: dzero
1322  ! -- dummy
1323  class(gwfbuytype) :: this
1324  ! -- local
1325  !
1326  ! -- allocate scalars in NumericalPackageType
1327  call this%NumericalPackageType%allocate_scalars()
1328  !
1329  ! -- Allocate
1330  call mem_allocate(this%ioutdense, 'IOUTDENSE', this%memoryPath)
1331  call mem_allocate(this%iform, 'IFORM', this%memoryPath)
1332  call mem_allocate(this%ireadelev, 'IREADELEV', this%memoryPath)
1333  call mem_allocate(this%ireadconcbuy, 'IREADCONCBUY', this%memoryPath)
1334  call mem_allocate(this%iconcset, 'ICONCSET', this%memoryPath)
1335  call mem_allocate(this%denseref, 'DENSEREF', this%memoryPath)
1336  !
1337  call mem_allocate(this%nrhospecies, 'NRHOSPECIES', this%memoryPath)
1338  !
1339  ! -- Initialize
1340  this%ioutdense = 0
1341  this%ireadelev = 0
1342  this%iconcset = 0
1343  this%ireadconcbuy = 0
1344  this%denseref = 1000.d0
1345  !
1346  this%nrhospecies = 0
1347  !
1348  ! -- Initialize default to LHS implementation of hydraulic head formulation
1349  this%iform = 2
1350  this%iasym = 1
1351  end subroutine allocate_scalars
1352 
1353  !> @brief Allocate arrays used by the package
1354  !<
1355  subroutine allocate_arrays(this, nodes)
1356  ! -- dummy
1357  class(gwfbuytype) :: this
1358  integer(I4B), intent(in) :: nodes
1359  ! -- local
1360  integer(I4B) :: i
1361  !
1362  ! -- Allocate
1363  call mem_allocate(this%dense, nodes, 'DENSE', this%memoryPath)
1364  call mem_allocate(this%concbuy, 0, 'CONCBUY', this%memoryPath)
1365  call mem_allocate(this%elev, nodes, 'ELEV', this%memoryPath)
1366  call mem_allocate(this%drhodc, this%nrhospecies, 'DRHODC', this%memoryPath)
1367  call mem_allocate(this%crhoref, this%nrhospecies, 'CRHOREF', this%memoryPath)
1368  call mem_allocate(this%ctemp, this%nrhospecies, 'CTEMP', this%memoryPath)
1369  allocate (this%cmodelname(this%nrhospecies))
1370  allocate (this%cauxspeciesname(this%nrhospecies))
1371  allocate (this%modelconc(this%nrhospecies))
1372  !
1373  ! -- Initialize
1374  do i = 1, nodes
1375  this%dense(i) = this%denseref
1376  this%elev(i) = dzero
1377  end do
1378  !
1379  ! -- Initialize nrhospecies arrays
1380  do i = 1, this%nrhospecies
1381  this%drhodc(i) = dzero
1382  this%crhoref(i) = dzero
1383  this%ctemp(i) = dzero
1384  this%cmodelname(i) = ''
1385  this%cauxspeciesname(i) = ''
1386  end do
1387  end subroutine allocate_arrays
1388 
1389  !> @brief Read package options
1390  !<
1391  subroutine read_options(this)
1392  ! -- modules
1393  use openspecmodule, only: access, form
1395  ! -- dummy
1396  class(gwfbuytype) :: this
1397  ! -- local
1398  character(len=LINELENGTH) :: errmsg, keyword
1399  character(len=MAXCHARLEN) :: fname
1400  integer(I4B) :: ierr
1401  logical :: isfound, endOfBlock
1402  ! -- formats
1403  character(len=*), parameter :: fmtfileout = &
1404  "(4x, 'BUY ', 1x, a, 1x, ' will be saved to file: ', &
1405  &a, /4x, 'opened on unit: ', I7)"
1406  !
1407  ! -- get options block
1408  call this%parser%GetBlock('OPTIONS', isfound, ierr, &
1409  supportopenclose=.true., blockrequired=.false.)
1410  !
1411  ! -- parse options block if detected
1412  if (isfound) then
1413  write (this%iout, '(1x,a)') 'Processing BUY OPTIONS block'
1414  do
1415  call this%parser%GetNextLine(endofblock)
1416  if (endofblock) exit
1417  call this%parser%GetStringCaps(keyword)
1418  select case (keyword)
1419  case ('HHFORMULATION_RHS')
1420  this%iform = 1
1421  this%iasym = 0
1422  write (this%iout, '(4x,a)') &
1423  'Hydraulic head formulation set to right-hand side'
1424  case ('DENSEREF')
1425  this%denseref = this%parser%GetDouble()
1426  write (this%iout, '(4x,a,1pg15.6)') &
1427  'Reference density has been set to: ', &
1428  this%denseref
1429  case ('DEV_EFH_FORMULATION')
1430  call this%parser%DevOpt()
1431  this%iform = 0
1432  this%iasym = 0
1433  write (this%iout, '(4x,a)') &
1434  'Formulation set to equivalent freshwater head'
1435  case ('DENSITY')
1436  call this%parser%GetStringCaps(keyword)
1437  if (keyword == 'FILEOUT') then
1438  call this%parser%GetString(fname)
1439  this%ioutdense = getunit()
1440  call openfile(this%ioutdense, this%iout, fname, 'DATA(BINARY)', &
1441  form, access, 'REPLACE')
1442  write (this%iout, fmtfileout) &
1443  'DENSITY', fname, this%ioutdense
1444  else
1445  errmsg = 'Optional density keyword must be '// &
1446  'followed by FILEOUT'
1447  call store_error(errmsg)
1448  end if
1449  case default
1450  write (errmsg, '(a,a)') 'Unknown BUY option: ', &
1451  trim(keyword)
1452  call store_error(errmsg)
1453  call this%parser%StoreErrorUnit()
1454  end select
1455  end do
1456  write (this%iout, '(1x,a)') 'End of BUY OPTIONS block'
1457  end if
1458  end subroutine read_options
1459 
1460  !> @brief Sets options as opposed to reading them from a file
1461  !<
1462  subroutine set_options(this, input_data)
1463  ! -- dummy
1464  class(gwfbuytype) :: this
1465  type(gwfbuyinputdatatype), intent(in) :: input_data !< the input data to be set
1466  !
1467  this%iform = input_data%iform
1468  this%denseref = input_data%denseref
1469  !
1470  ! derived option:
1471  ! if not iform==2, there is no asymmetry
1472  if (this%iform == 0 .or. this%iform == 1) then
1473  this%iasym = 0
1474  end if
1475  end subroutine set_options
1476 
1477  !> @brief Pass in a gwt model name, concentration array and ibound, and store
1478  !! a pointer to these in the BUY package so that density can be calculated
1479  !! from them
1480  !!
1481  !! This routine is called from the gwfgwt exchange in the exg_ar() method
1482  !<
1483  subroutine set_concentration_pointer(this, modelname, conc, icbund)
1484  ! -- dummy
1485  class(gwfbuytype) :: this
1486  character(len=LENMODELNAME), intent(in) :: modelname
1487  real(DP), dimension(:), pointer :: conc
1488  integer(I4B), dimension(:), pointer :: icbund
1489  ! -- local
1490  integer(I4B) :: i
1491  logical :: found
1492  !
1493  this%iconcset = 1
1494  found = .false.
1495  do i = 1, this%nrhospecies
1496  if (this%cmodelname(i) == modelname) then
1497  this%modelconc(i)%conc => conc
1498  this%modelconc(i)%icbund => icbund
1499  found = .true.
1500  exit
1501  end if
1502  end do
1503  end subroutine set_concentration_pointer
1504 
1505 end module gwfbuymodule
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
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
integer(i4b), parameter maxcharlen
maximum length of char string
Definition: Constants.f90:47
real(dp), parameter done
real constant 1
Definition: Constants.f90:76
real(dp) function calcdens(denseref, drhodc, crhoref, conc)
Generic function to calculate fluid density from concentration.
Definition: gwf-buy.f90:82
subroutine buy_cf(this, kiter)
Fill coefficients.
Definition: gwf-buy.f90:287
subroutine buy_cf_bnd(this, packobj, hnew)
Fill coefficients.
Definition: gwf-buy.f90:302
subroutine read_options(this)
Read package options.
Definition: gwf-buy.f90:1392
subroutine buy_cf_lak(packobj, hnew, dense, elev, denseref, locdense, locconc, drhodc, crhoref, ctemp, iform)
Pass density information into lak package; density terms are calculated in the lake package as part o...
Definition: gwf-buy.f90:656
subroutine set_options(this, input_data)
Sets options as opposed to reading them from a file.
Definition: gwf-buy.f90:1463
subroutine calchhterms(this, n, m, icon, hn, hm, rhsterm, amatnn, amatnm)
Calculate hydraulic head term for this connection.
Definition: gwf-buy.f90:1185
subroutine buy_rp(this)
Check for new buy period data.
Definition: gwf-buy.f90:246
subroutine, public buy_cr(buyobj, name_model, inunit, iout)
Create a new BUY object.
Definition: gwf-buy.f90:103
subroutine buy_cf_maw(packobj, hnew, dense, elev, denseref, locdense, locconc, drhodc, crhoref, ctemp, iform)
Pass density information into maw package; density terms are calculated in the maw package as part of...
Definition: gwf-buy.f90:762
subroutine buy_fc(this, kiter, matrix_sln, idxglo, rhs, hnew)
Fill coefficients.
Definition: gwf-buy.f90:812
subroutine calc_ghb_hcof_rhs_terms(denseref, denseghb, densenode, elevghb, elevnode, hghb, hnode, cond, iform, rhsterm, hcofterm)
Calculate density hcof and rhs terms for ghb conditions.
Definition: gwf-buy.f90:499
subroutine allocate_scalars(this)
Allocate scalars used by the package.
Definition: gwf-buy.f90:1320
subroutine buy_cq(this, hnew, flowja)
Add buy term to flowja.
Definition: gwf-buy.f90:889
subroutine buy_calcelev(this)
Calculate cell elevations to use in density flow equations.
Definition: gwf-buy.f90:1302
subroutine set_concentration_pointer(this, modelname, conc, icbund)
Pass in a gwt model name, concentration array and ibound, and store a pointer to these in the BUY pac...
Definition: gwf-buy.f90:1484
subroutine buy_cf_riv(packobj, hnew, dense, elev, denseref, locelev, locdense, locconc, drhodc, crhoref, ctemp, iform)
Fill riv coefficients.
Definition: gwf-buy.f90:545
subroutine set_packagedata(this, input_data)
Sets package data instead of reading from file.
Definition: gwf-buy.f90:1086
subroutine buy_df(this, dis, buy_input)
Read options and package data, or set from argument.
Definition: gwf-buy.f90:129
subroutine read_packagedata(this)
Read PACKAGEDATA block.
Definition: gwf-buy.f90:1000
subroutine buy_cf_sfr(packobj, hnew, dense, elev, denseref, locdense, locconc, drhodc, crhoref, ctemp, iform)
Pass density information into sfr package; density terms are calculated in the sfr package as part of...
Definition: gwf-buy.f90:709
subroutine buy_ot_dv(this, idvfl)
Save density array to binary file.
Definition: gwf-buy.f90:852
real(dp) function get_bnd_density(n, locdense, locconc, denseref, drhodc, crhoref, ctemp, auxvar)
Return the density of the boundary package using one of several different options in the following or...
Definition: gwf-buy.f90:401
subroutine buy_cf_ghb(packobj, hnew, dense, elev, denseref, locelev, locdense, locconc, drhodc, crhoref, ctemp, iform)
Fill ghb coefficients.
Definition: gwf-buy.f90:439
subroutine read_dimensions(this)
Read the dimensions for this package.
Definition: gwf-buy.f90:954
subroutine buy_ar(this, npf, ibound)
Allocate and Read.
Definition: gwf-buy.f90:176
subroutine buy_da(this)
Deallocate.
Definition: gwf-buy.f90:921
subroutine buy_cf_drn(packobj, hnew, dense, denseref)
Fill drn coefficients.
Definition: gwf-buy.f90:614
subroutine buy_ad(this)
Advance.
Definition: gwf-buy.f90:277
subroutine allocate_arrays(this, nodes)
Allocate arrays used by the package.
Definition: gwf-buy.f90:1356
subroutine buy_ar_bnd(this, packobj, hnew)
Buoyancy ar_bnd routine to activate density in packages.
Definition: gwf-buy.f90:201
subroutine calcbuy(this, n, m, icon, hn, hm, buy)
Calculate buyancy term for this connection.
Definition: gwf-buy.f90:1103
subroutine buy_calcdens(this)
calculate fluid density from concentration
Definition: gwf-buy.f90:1278
This module contains stateless conductance functions.
real(dp) function, public hcond(ibdn, ibdm, ictn, ictm, iupstream, ihc, icellavg, condsat, hn, hm, satn, satm, hkn, hkm, topn, topm, botn, botm, cln, clm, fawidth)
Horizontal conductance between two cells.
real(dp) function, public vcond(ibdn, ibdm, ictn, ictm, inewton, ivarcv, idewatcv, condsat, hn, hm, vkn, vkm, satn, satm, topn, topm, botn, botm, flowarea)
Vertical conductance between two cells.
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
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_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.