MODFLOW 6  version 6.6.0.dev0
USGS Modular Hydrologic Model
exg-swfgwf.f90
Go to the documentation of this file.
1 !> @brief This module contains the SwfGwfExchangeModule Module
2 !!
3 !! This module contains the code for connecting a SWF model with
4 !! a GWF model. The SwfGwfExchangeType class is a parent to the CHF and
5 !! OLF models and should not be used directly.
6 !!
7 !<
9 
10  use kindmodule, only: dp, i4b, lgp
21  use obsmodule, only: obs_cr, obstype
24  use gwfmodule, only: gwfmodeltype
25  use swfmodule, only: swfmodeltype
27  use tablemodule, only: tabletype, table_cr
28 
29  implicit none
30  private
31  public :: swfgwfexchangetype
32 
34 
35  class(numericalmodeltype), pointer :: model1 => null() !< model 1
36  class(numericalmodeltype), pointer :: model2 => null() !< model 2
37  class(swfmodeltype), pointer :: swfmodel => null() !< pointer to SWF Model
38  class(gwfmodeltype), pointer :: gwfmodel => null() !< pointer to GWF Model
39 
40  character(len=LENFTYPE), pointer :: swf_ftype => null() !< type of swf model (CHF or OLF)
41  character(len=LINELENGTH), pointer :: filename => null() !< name of the input file
42  integer(I4B), pointer :: ipr_input => null() !< flag to print input
43  integer(I4B), pointer :: ipr_flow => null() !< print flag for cell by cell flows
44 
45  integer(I4B), pointer :: ifixedcond => null() !< conductance is fixed as product of bedleak and cfact
46 
47  integer(I4B), pointer :: nexg => null() !< number of exchanges
48  integer(I4B), dimension(:), pointer, contiguous :: nodeswf => null() !< node numbers in swf model
49  integer(I4B), dimension(:), pointer, contiguous :: nodegwf => null() !< node numbers in gwf model
50  real(dp), dimension(:), pointer, contiguous :: bedleak => null() !< bed leakance, size: nexg
51  real(dp), dimension(:), pointer, contiguous :: cfact => null() !< factor used in conductance calculation, size: nexg
52  integer(I4B), dimension(:), pointer, contiguous :: idxglo => null() !< mapping to global (solution) amat
53  integer(I4B), dimension(:), pointer, contiguous :: idxsymglo => null() !< mapping to global (solution) symmetric amat
54  real(dp), dimension(:), pointer, contiguous :: simvals => null() !< simulated flow rate for each exchange
55 
56  integer(I4B), pointer :: inobs => null() !< unit number for GWF-GWF observations
57  type(obstype), pointer :: obs => null() !< observation object
58 
59  ! -- table objects
60  type(tabletype), pointer :: outputtab1 => null()
61  type(tabletype), pointer :: outputtab2 => null()
62 
63  contains
64 
65  ! procedure :: exg_df (delegated to CHF and OLF df routines)
66  procedure :: exg_ac => swf_gwf_ac
67  procedure :: exg_mc => swf_gwf_mc
68  procedure :: exg_fc => swf_gwf_fc
69  procedure :: exg_cq => swf_gwf_cq
70  procedure :: exg_bd => swf_gwf_bd
71  procedure :: exg_ot => swf_gwf_ot
72  procedure :: exg_da => swf_gwf_da
73  procedure :: initialize
74  procedure :: allocate_scalars
75  procedure :: allocate_arrays
76  procedure :: swf_gwf_calc_simvals
77  procedure :: swf_gwf_save_simvals
78  procedure :: qcalc
79  procedure :: get_cond
80  procedure :: get_wetted_perimeter
81  procedure :: swf_gwf_add_to_flowja
82  procedure, private :: swf_gwf_chd_bd
83  !todo: procedure :: swf_gwf_bdsav_model
84  procedure :: swf_gwf_bdsav
85  procedure :: connects_model => swf_gwf_connects_model
86 
87  procedure, pass(this) :: noder
88  procedure, pass(this) :: cellstr
89 
90  end type swfgwfexchangetype
91 
92 contains
93 
94  !> @ brief Initialize SWF GWF exchange
95  !<
96  subroutine initialize(this, filename, name, swf_ftype, id, m1_id, m2_id, &
97  input_mempath)
98  ! dummy
99  class(swfgwfexchangetype) :: this !< SwfGwfExchangeType
100  character(len=*), intent(in) :: filename !< filename for reading
101  character(len=*) :: name !< exchange name
102  character(len=*) :: swf_ftype !< type of swf model, CHF or OLF
103  integer(I4B), intent(in) :: id !< id for the exchange
104  integer(I4B), intent(in) :: m1_id !< id for model 1
105  integer(I4B), intent(in) :: m2_id !< id for model 2
106  character(len=*), intent(in) :: input_mempath
107  ! -- local
108  class(basemodeltype), pointer :: mb
109  integer(I4B) :: m1_index, m2_index
110 
111  ! Assign id and name
112  this%id = id
113  this%name = name
114  this%memoryPath = create_mem_path(this%name)
115  this%input_mempath = input_mempath
116 
117  ! allocate scalars and set defaults
118  call this%allocate_scalars()
119  this%filename = filename
120  this%swf_ftype = swf_ftype
121  this%typename = trim(swf_ftype)//'-GWF'
122 
123  ! set swfmodel
124  m1_index = model_loc_idx(m1_id)
125  if (m1_index > 0) then
126  mb => getbasemodelfromlist(basemodellist, m1_index)
127  select type (mb)
128  class is (swfmodeltype)
129  this%model1 => mb
130  this%swfmodel => mb
131  end select
132  end if
133  ! this%v_model1 => get_virtual_model(m1_id)
134  ! this%is_datacopy = .not. this%v_model1%is_local
135 
136  ! set gwfmodel
137  m2_index = model_loc_idx(m2_id)
138  if (m2_index > 0) then
139  mb => getbasemodelfromlist(basemodellist, m2_index)
140  select type (mb)
141  type is (gwfmodeltype)
142  this%model2 => mb
143  this%gwfmodel => mb
144  end select
145  end if
146  ! this%v_model2 => get_virtual_model(m2_id)
147 
148  ! Verify that the surface water model is of the correct type
149  if (.not. associated(this%swfmodel) .and. m1_index > 0) then
150  write (errmsg, '(7a)') &
151  'Problem with ', &
152  trim(this%typename), &
153  ' exchange ', &
154  trim(this%name), &
155  '. Specified ', &
156  trim(this%swf_ftype), &
157  ' model does not appear to be of the correct type.'
158  call store_error(errmsg, terminate=.true.)
159  end if
160 
161  ! Verify that gwf model is of the correct type
162  if (.not. associated(this%gwfmodel) .and. m2_index > 0) then
163  write (errmsg, '(3a)') 'Problem with SWF-GWF exchange ', &
164  trim(this%name), &
165  '. Specified GWF model does not appear to be of the correct type.'
166  call store_error(errmsg, terminate=.true.)
167  end if
168 
169  ! Create the obs package
170  call obs_cr(this%obs, this%inobs)
171 
172  end subroutine initialize
173 
174  !> @ brief Add connections
175  !!
176  !! Override parent exg_ac so that gnc can add connections here.
177  !<
178  subroutine swf_gwf_ac(this, sparse)
179  ! -- modules
180  use sparsemodule, only: sparsematrix
181  ! -- dummy
182  class(swfgwfexchangetype) :: this !< SwfGwfExchangeType
183  type(sparsematrix), intent(inout) :: sparse
184  ! -- local
185  integer(I4B) :: n, iglo, jglo
186  !
187  ! -- add exchange connections
188  do n = 1, this%nexg
189  iglo = this%nodeswf(n) + this%swfmodel%moffset
190  jglo = this%nodegwf(n) + this%gwfmodel%moffset
191  call sparse%addconnection(iglo, jglo, 1)
192  call sparse%addconnection(jglo, iglo, 1)
193  end do
194  end subroutine swf_gwf_ac
195 
196  !> @ brief Map connections
197  !!
198  !! Map the connections in the global matrix
199  !<
200  subroutine swf_gwf_mc(this, matrix_sln)
201  ! -- modules
202  use sparsemodule, only: sparsematrix
203  ! -- dummy
204  class(swfgwfexchangetype) :: this !< SwfGwfExchangeType
205  class(matrixbasetype), pointer :: matrix_sln !< the system matrix
206  ! -- local
207  integer(I4B) :: n, iglo, jglo
208  !
209  ! -- map exchange connections
210  do n = 1, this%nexg
211  iglo = this%nodeswf(n) + this%swfmodel%moffset
212  jglo = this%nodegwf(n) + this%gwfmodel%moffset
213  this%idxglo(n) = matrix_sln%get_position(iglo, jglo)
214  this%idxsymglo(n) = matrix_sln%get_position(jglo, iglo)
215  end do
216  end subroutine swf_gwf_mc
217 
218  !> @ brief Fill coefficients
219  !!
220  !! Fill conductance into coefficient matrix. For now assume
221  !! all connections are vertical and no newton correction is
222  !! needed.
223  !<
224  subroutine swf_gwf_fc(this, kiter, matrix_sln, rhs_sln, inwtflag)
225  ! modules
227  ! dummy
228  class(swfgwfexchangetype) :: this !< SwfGwfExchangeType
229  integer(I4B), intent(in) :: kiter
230  class(matrixbasetype), pointer :: matrix_sln
231  real(DP), dimension(:), intent(inout) :: rhs_sln
232  integer(I4B), optional, intent(in) :: inwtflag
233  ! -- local
234  integer(I4B) :: iexg
235  integer(I4B) :: nodeswf
236  integer(I4B) :: nodegwf
237  integer(I4B) :: nodeswf_sln
238  integer(I4B) :: nodegwf_sln
239  integer(I4B) :: ibdn1
240  integer(I4B) :: ibdn2
241  real(DP) :: hswf
242  real(DP) :: hgwf
243  real(DP) :: qnm
244  real(DP) :: qeps
245  real(DP) :: eps
246  real(DP) :: derv
247 
248  ! Fill terms into solution matrix and rhs vector
249  do iexg = 1, this%nexg
250 
251  nodeswf = this%nodeswf(iexg)
252  nodegwf = this%nodegwf(iexg)
253  nodeswf_sln = this%nodeswf(iexg) + this%swfmodel%moffset
254  nodegwf_sln = this%nodegwf(iexg) + this%gwfmodel%moffset
255  ibdn1 = this%swfmodel%ibound(nodeswf)
256  ibdn2 = this%gwfmodel%ibound(nodegwf)
257  hswf = this%swfmodel%x(nodeswf)
258  hgwf = this%gwfmodel%x(nodegwf)
259 
260  ! First add these terms to the row for the surface water model
261 
262  ! Fill the qnm term on the right-hand side
263  qnm = this%qcalc(iexg, hswf, hgwf)
264  rhs_sln(nodeswf_sln) = rhs_sln(nodeswf_sln) - qnm
265 
266  ! Derivative calculation and fill of n terms
267  eps = get_perturbation(hswf)
268  qeps = this%qcalc(iexg, hswf + eps, hgwf)
269  derv = (qeps - qnm) / eps
270  call matrix_sln%add_diag_value(nodeswf_sln, derv)
271  rhs_sln(nodeswf_sln) = rhs_sln(nodeswf_sln) + derv * hswf
272 
273  ! Derivative calculation and fill of m terms
274  eps = get_perturbation(hgwf)
275  qeps = this%qcalc(iexg, hswf, hgwf + eps)
276  derv = (qeps - qnm) / eps
277  call matrix_sln%add_value_pos(this%idxglo(iexg), derv)
278  rhs_sln(nodeswf_sln) = rhs_sln(nodeswf_sln) + derv * hgwf
279 
280  ! now add these terms to the row for the groundwater model
281 
282  ! Fill the qnm term on the right-hand side
283  qnm = -this%qcalc(iexg, hswf, hgwf)
284  rhs_sln(nodegwf_sln) = rhs_sln(nodegwf_sln) - qnm
285 
286  ! Derivative calculation and fill of n terms
287  eps = get_perturbation(hgwf)
288  qeps = -this%qcalc(iexg, hswf, hgwf + eps)
289  derv = (qeps - qnm) / eps
290  call matrix_sln%add_diag_value(nodegwf_sln, derv)
291  rhs_sln(nodegwf_sln) = rhs_sln(nodegwf_sln) + derv * hgwf
292 
293  ! Derivative calculation and fill of m terms
294  eps = get_perturbation(hswf)
295  qeps = -this%qcalc(iexg, hswf + eps, hgwf)
296  derv = (qeps - qnm) / eps
297  call matrix_sln%add_value_pos(this%idxsymglo(iexg), derv)
298  rhs_sln(nodegwf_sln) = rhs_sln(nodegwf_sln) + derv * hswf
299 
300  end do
301 
302  end subroutine swf_gwf_fc
303 
304  !> @ brief Calculate flow
305  !!
306  !! Calculate flow between two cells and store in simvals, also set
307  !! information needed for specific discharge calculation
308  !<
309  subroutine swf_gwf_cq(this, icnvg, isuppress_output, isolnid)
310  ! -- dummy
311  class(swfgwfexchangetype) :: this !< SwfGwfExchangeType
312  integer(I4B), intent(inout) :: icnvg
313  integer(I4B), intent(in) :: isuppress_output
314  integer(I4B), intent(in) :: isolnid
315  !
316  ! -- calculate flow and store in simvals
317  call this%swf_gwf_calc_simvals()
318  !
319  ! -- set flows to model edges in NPF
320  ! todo: do we add these flows for specific discharge calculation?
321  !call this%swf_gwf_set_flow_to_npf()
322  !
323  ! -- add exchange flows to model's flowja diagonal
324  call this%swf_gwf_add_to_flowja()
325  end subroutine swf_gwf_cq
326 
327  !> @ brief Deallocate
328  !!
329  !! Deallocate memory associated with this object
330  !<
331  subroutine swf_gwf_da(this)
332  ! -- modules
334  ! -- dummy
335  class(swfgwfexchangetype) :: this !< SwfGwfExchangeType
336  !
337  ! -- objects
338  call this%obs%obs_da()
339  deallocate (this%obs)
340  !
341  ! -- arrays
342  call mem_deallocate(this%nodeswf)
343  call mem_deallocate(this%nodegwf)
344  call mem_deallocate(this%bedleak)
345  call mem_deallocate(this%cfact)
346  call mem_deallocate(this%idxglo)
347  call mem_deallocate(this%idxsymglo)
348  call mem_deallocate(this%simvals)
349  !
350  ! -- scalars
351  deallocate (this%swf_ftype)
352  deallocate (this%filename)
353  call mem_deallocate(this%ipr_input)
354  call mem_deallocate(this%ipr_flow)
355  call mem_deallocate(this%ifixedcond)
356  call mem_deallocate(this%nexg)
357  call mem_deallocate(this%inobs)
358  end subroutine swf_gwf_da
359 
360  !> @ brief Allocate scalars
361  !!
362  !! Allocate scalar variables
363  !<
364  subroutine allocate_scalars(this)
365  ! -- modules
366  ! -- dummy
367  class(swfgwfexchangetype) :: this !< SwfGwfExchangeType
368  !
369  allocate (this%swf_ftype)
370  this%swf_ftype = ''
371  allocate (this%filename)
372  this%filename = ''
373  !
374  call mem_allocate(this%ipr_input, 'IPR_INPUT', this%memoryPath)
375  call mem_allocate(this%ipr_flow, 'IPR_FLOW', this%memoryPath)
376  call mem_allocate(this%ifixedcond, 'IFIXEDCOND', this%memoryPath)
377  call mem_allocate(this%nexg, 'NEXG', this%memoryPath)
378  call mem_allocate(this%inobs, 'INOBS', this%memoryPath)
379  !
380  this%ipr_input = 0
381  this%ipr_flow = 0
382  this%ifixedcond = 0
383  this%nexg = 0
384  this%inobs = 0
385  end subroutine allocate_scalars
386 
387  !> @brief Allocate array data, using the number of
388  !! connected nodes @param nexg
389  !<
390  subroutine allocate_arrays(this)
391  ! -- dummy
392  class(swfgwfexchangetype) :: this !< instance of exchange object
393  !
394  call mem_allocate(this%nodeswf, this%nexg, 'NODEM1', this%memoryPath)
395  call mem_allocate(this%nodegwf, this%nexg, 'NODEM2', this%memoryPath)
396  call mem_allocate(this%bedleak, this%nexg, 'BEDLEAK', this%memoryPath)
397  call mem_allocate(this%cfact, this%nexg, 'CFACT', this%memoryPath)
398  call mem_allocate(this%idxglo, this%nexg, 'IDXGLO', this%memoryPath)
399  call mem_allocate(this%idxsymglo, this%nexg, 'IDXSYMGLO', this%memoryPath)
400  call mem_allocate(this%simvals, this%nexg, 'SIMVALS', this%memoryPath)
401  end subroutine allocate_arrays
402 
403  !> @brief
404  !<
405  function noder(this, model, cellid, iout)
406  ! -- modules
407  use geomutilmodule, only: get_node
408  ! -- dummy
409  class(swfgwfexchangetype) :: this !< instance of exchange object
410  class(numericalmodeltype), pointer, intent(in) :: model
411  integer(I4B), dimension(:), intent(in) :: cellid
412  integer(I4B), intent(in) :: iout !< the output file unit
413  integer(I4B) :: noder, node
414  !
415  if (model%dis%ndim == 1) then
416  node = cellid(1)
417  elseif (model%dis%ndim == 2) then
418  node = get_node(cellid(1), 1, cellid(2), &
419  model%dis%mshape(1), 1, &
420  model%dis%mshape(2))
421  else
422  node = get_node(cellid(1), cellid(2), cellid(3), &
423  model%dis%mshape(1), &
424  model%dis%mshape(2), &
425  model%dis%mshape(3))
426  end if
427  noder = model%dis%get_nodenumber(node, 0)
428  end function noder
429 
430  !> @brief
431  !<
432  function cellstr(this, model, cellid, iout)
433  ! -- modules
434  ! -- dummy
435  class(swfgwfexchangetype) :: this !< instance of exchange object
436  class(numericalmodeltype), pointer, intent(in) :: model
437  integer(I4B), dimension(:), intent(in) :: cellid
438  integer(I4B), intent(in) :: iout !< the output file unit
439  character(len=20) :: cellstr
440  character(len=*), parameter :: fmtndim1 = &
441  "('(',i0,')')"
442  character(len=*), parameter :: fmtndim2 = &
443  "('(',i0,',',i0,')')"
444  character(len=*), parameter :: fmtndim3 = &
445  "('(',i0,',',i0,',',i0,')')"
446  !
447  cellstr = ''
448  !
449  select case (model%dis%ndim)
450  case (1)
451  write (cellstr, fmtndim1) cellid(1)
452  case (2)
453  write (cellstr, fmtndim2) cellid(1), cellid(2)
454  case (3)
455  write (cellstr, fmtndim3) cellid(1), cellid(2), cellid(3)
456  case default
457  end select
458  end function cellstr
459 
460  !> @brief Calculate flow rates for the exchanges and store them in a member
461  !! array
462  !<
463  subroutine swf_gwf_calc_simvals(this)
464  ! -- modules
465  use constantsmodule, only: dzero
466  ! -- dummy
467  class(swfgwfexchangetype) :: this !< SwfGwfExchangeType
468  ! -- local
469  integer(I4B) :: iexg
470  integer(I4B) :: nodeswf, nodegwf
471  integer(I4B) :: ibdn1, ibdn2
472  real(DP) :: hswf
473  real(DP) :: hgwf
474  real(DP) :: rrate
475  !
476  do iexg = 1, this%nexg
477  rrate = dzero
478  nodeswf = this%nodeswf(iexg)
479  nodegwf = this%nodegwf(iexg)
480  ibdn1 = this%swfmodel%ibound(nodeswf)
481  ibdn2 = this%gwfmodel%ibound(nodegwf)
482  hswf = this%swfmodel%x(nodeswf)
483  hgwf = this%gwfmodel%x(nodegwf)
484  if (ibdn1 /= 0 .and. ibdn2 /= 0) then
485  rrate = this%qcalc(iexg, hswf, hgwf)
486  end if
487  this%simvals(iexg) = rrate
488  end do
489  end subroutine swf_gwf_calc_simvals
490 
491  !> @ brief Calculate flow
492  !!
493  !! Calculate the flow for the specified exchange and node numbers.
494  !! Flow is positive into the surface water model
495  !<
496  function qcalc(this, iexg, hswf, hgwf)
497  ! -- return
498  real(dp) :: qcalc
499  ! -- dummy
500  class(swfgwfexchangetype) :: this !< SwfGwfExchangeType
501  integer(I4B), intent(in) :: iexg
502  real(dp), intent(in) :: hswf
503  real(dp), intent(in) :: hgwf
504  ! -- local
505  real(dp) :: cond
506 
507  ! Calculate flow between swf and gwf models; positive into swf
508  cond = this%get_cond(iexg, hswf, hgwf)
509  qcalc = cond * (hgwf - hswf)
510 
511  end function qcalc
512 
513  !> @ brief Calculate conductance
514  !!
515  !! Calculate the conductance between the surface water cell
516  !! and the underlying groundwater cell.
517  !<
518  function get_cond(this, iexg, hswf, hgwf)
519  ! module
520  use smoothingmodule, only: squadratic
521  ! return
522  real(dp) :: get_cond
523  ! dummy
524  class(swfgwfexchangetype) :: this !< SwfGwfExchangeType
525  integer(I4B), intent(in) :: iexg !< exchange number
526  real(dp), intent(in) :: hswf !< surface water model head
527  real(dp), intent(in) :: hgwf !< groundwater model head
528  ! local
529  integer(I4B) :: nodeswf
530  real(dp) :: range = 1.d-6
531  real(dp) :: depth_ups
532  real(dp) :: dydx
533  real(dp) :: smooth_factor
534  real(dp) :: area
535  real(dp) :: perimeter
536 
537  ! -- Calculate or return conductance
538  area = this%cfact(iexg)
539  if (this%ifixedcond == 1) then
540  get_cond = this%bedleak(iexg) * area
541  return
542  end if
543 
544  ! Calculate smooth factor between zero, when the upstream-weighted
545  ! depth is zero, and 1.0, when the upstream weighted depth is
546  ! greater than or equal to the smoothening depth
547  nodeswf = this%nodeswf(iexg)
548  depth_ups = max(hswf, hgwf) - this%swfmodel%dis%bot(nodeswf)
549  call squadratic(depth_ups, range, dydx, smooth_factor)
550 
551  ! For channel model calculate the interaction area as product
552  ! of cfact and upstream-wetted perimeter
553  if (this%swfmodel%dfw%is2d == 0) then
554  perimeter = this%get_wetted_perimeter(nodeswf, depth_ups)
555  area = area * perimeter
556  end if
557 
558  ! Calculate conductance
559  get_cond = smooth_factor * this%bedleak(iexg) * area
560  end function get_cond
561 
562  !> @ brief Get wetted perimeter for swf channel model
563  !<
564  function get_wetted_perimeter(this, nodeswf, depth) result(wp)
565  ! return
566  real(dp) :: wp
567  ! dummy
568  class(swfgwfexchangetype) :: this !< SwfGwfExchangeType
569  integer(I4B), intent(in) :: nodeswf !< node number for surface water model cell
570  real(dp), intent(in) :: depth !< water depth in surface water model cell
571  ! local
572  integer(I4B) :: idcxs
573  real(dp) :: width
574  real(dp) :: dummy
575 
576  idcxs = this%swfmodel%dfw%idcxs(nodeswf)
577  call this%swfmodel%dis%get_flow_width(nodeswf, nodeswf, 0, width, dummy)
578  wp = this%swfmodel%cxs%get_wetted_perimeter(idcxs, width, depth)
579 
580  end function get_wetted_perimeter
581 
582  !> @brief Add exchange flow to each model flowja diagonal position so that
583  !! residual is calculated correctly.
584  !<
585  subroutine swf_gwf_add_to_flowja(this)
586  ! -- modules
587  class(swfgwfexchangetype) :: this !< SwfGwfExchangeType
588  ! -- local
589  integer(I4B) :: i
590  integer(I4B) :: n
591  integer(I4B) :: idiag
592  real(DP) :: flow
593  !
594  do i = 1, this%nexg
595  !
596  if (associated(this%swfmodel)) then
597  n = this%nodeswf(i)
598  if (this%swfmodel%ibound(n) > 0) then
599  flow = this%simvals(i)
600  idiag = this%swfmodel%ia(n)
601  this%swfmodel%flowja(idiag) = this%swfmodel%flowja(idiag) + flow
602  end if
603  end if
604  !
605  if (associated(this%gwfmodel)) then
606  n = this%nodegwf(i)
607  if (this%gwfmodel%ibound(n) > 0) then
608  flow = -this%simvals(i)
609  idiag = this%gwfmodel%ia(n)
610  this%gwfmodel%flowja(idiag) = this%gwfmodel%flowja(idiag) + flow
611  end if
612  end if
613  !
614  end do
615  end subroutine swf_gwf_add_to_flowja
616 
617  !> @ brief Budget
618  !!
619  !! Accumulate budget terms
620  !<
621  subroutine swf_gwf_bd(this, icnvg, isuppress_output, isolnid)
622  ! -- modules
624  use budgetmodule, only: rate_accumulator
625  ! -- dummy
626  class(swfgwfexchangetype) :: this !< SwfGwfExchangeType
627  integer(I4B), intent(inout) :: icnvg
628  integer(I4B), intent(in) :: isuppress_output
629  integer(I4B), intent(in) :: isolnid
630  ! -- local
631  character(len=LENBUDTXT), dimension(1) :: budtxt
632  real(DP), dimension(2, 1) :: budterm
633  real(DP) :: ratin, ratout
634  !
635  ! -- initialize
636  budtxt(1) = ' FLOW-JA-FACE'
637  !
638  ! -- Calculate ratin/ratout and pass to model budgets
639  call rate_accumulator(this%simvals, ratin, ratout)
640  !
641  ! -- Add the budget terms to model 1
642  if (associated(this%swfmodel)) then
643  budterm(1, 1) = ratin
644  budterm(2, 1) = ratout
645  call this%swfmodel%model_bdentry(budterm, budtxt, this%name)
646  end if
647  !
648  ! -- Add the budget terms to model 2
649  if (associated(this%gwfmodel)) then
650  budterm(1, 1) = ratout
651  budterm(2, 1) = ratin
652  call this%gwfmodel%model_bdentry(budterm, budtxt, this%name)
653  end if
654  !
655  ! -- Add any flows from one model into a constant head in another model
656  ! as a separate budget term called FLOW-JA-FACE-CHD
657  call this%swf_gwf_chd_bd()
658  end subroutine swf_gwf_bd
659 
660  !> @ brief swf-gwf-chd-bd
661  !!
662  !! Account for flow from an external model into a chd cell
663  !<
664  subroutine swf_gwf_chd_bd(this)
665  ! -- modules
667  ! -- dummy
668  class(swfgwfexchangetype) :: this !< GwfExchangeType
669  ! -- local
670  character(len=LENBUDTXT), dimension(1) :: budtxt
671  integer(I4B) :: n
672  integer(I4B) :: i
673  real(DP), dimension(2, 1) :: budterm
674  real(DP) :: ratin, ratout
675  real(DP) :: q
676  !
677  ! -- initialize
678  budtxt(1) = 'FLOW-JA-FACE-CHD'
679  !
680  ! -- Add the constant-head budget terms for flow from model 2 into model 1
681  if (associated(this%swfmodel)) then
682  ratin = dzero
683  ratout = dzero
684  do i = 1, this%nexg
685  n = this%nodeswf(i)
686  if (this%swfmodel%ibound(n) < 0) then
687  q = this%simvals(i)
688  if (q > dzero) then
689  ratout = ratout + q
690  else
691  ratin = ratin - q
692  end if
693  end if
694  end do
695  budterm(1, 1) = ratin
696  budterm(2, 1) = ratout
697  call this%swfmodel%model_bdentry(budterm, budtxt, this%name)
698  end if
699  !
700  ! -- Add the constant-head budget terms for flow from model 1 into model 2
701  if (associated(this%gwfmodel)) then
702  ratin = dzero
703  ratout = dzero
704  do i = 1, this%nexg
705  n = this%nodegwf(i)
706  if (this%gwfmodel%ibound(n) < 0) then
707  ! -- flip flow sign as flow is relative to model 1
708  q = -this%simvals(i)
709  if (q > dzero) then
710  ratout = ratout + q
711  else
712  ratin = ratin - q
713  end if
714  end if
715  end do
716  budterm(1, 1) = ratin
717  budterm(2, 1) = ratout
718  call this%gwfmodel%model_bdentry(budterm, budtxt, this%name)
719  end if
720  end subroutine swf_gwf_chd_bd
721 
722  !> @ brief Budget save
723  !!
724  !! Output individual flows to listing file and binary budget files
725  !<
726  subroutine swf_gwf_bdsav(this)
727  ! -- dummy
728  class(swfgwfexchangetype) :: this !< SwfGwfExchangeType
729  ! -- local
730  integer(I4B) :: icbcfl, ibudfl
731  ! !
732  ! ! -- budget for model1
733  ! if (associated(this%swfmodel1)) then
734  ! call this%swf_gwf_bdsav_model(this%swfmodel1, this%gwfmodel2%name)
735  ! end if
736  ! !
737  ! ! -- budget for model2
738  ! if (associated(this%gwfmodel2)) then
739  ! call this%swf_gwf_bdsav_model(this%gwfmodel2, this%swfmodel1%name)
740  ! end if
741  !
742  ! -- Set icbcfl, ibudfl to zero so that flows will be printed and
743  ! saved, if the options were set in the MVR package
744  icbcfl = 1
745  ibudfl = 1
746  !
747  ! -- Calculate and write simulated values for observations
748  if (this%inobs /= 0) then
749  call this%swf_gwf_save_simvals()
750  end if
751  end subroutine swf_gwf_bdsav
752 
753  ! subroutine swf_gwf_bdsav_model(this, model, neighbor_name)
754  ! ! -- modules
755  ! use ConstantsModule, only: DZERO, LENBUDTXT, LENPACKAGENAME
756  ! use TdisModule, only: kstp, kper
757  ! ! -- dummy
758  ! class(SwfGwfExchangeType) :: this !< this exchange
759  ! class(NumericalModelType), pointer :: model !< the model to save budget for
760  ! character(len=*), intent(in) :: neighbor_name !< name of the connected neighbor model
761  ! ! -- local
762  ! character(len=LENPACKAGENAME + 4) :: packname
763  ! character(len=LENBUDTXT), dimension(1) :: budtxt
764  ! type(TableType), pointer :: output_tab
765  ! character(len=20) :: nodestr
766  ! character(len=LENBOUNDNAME) :: bname
767  ! integer(I4B) :: ntabrows
768  ! integer(I4B) :: nodeu
769  ! integer(I4B) :: i, n1, n2, n1u, n2u
770  ! integer(I4B) :: ibinun
771  ! real(DP) :: ratin, ratout, rrate
772  ! logical(LGP) :: is_for_model1
773  ! real(DP), dimension(this%naux) :: auxrow
774  ! !
775  ! budtxt(1) = ' FLOW-JA-FACE'
776  ! packname = 'EXG '//this%name
777  ! packname = adjustr(packname)
778  ! if (associated(model, this%swfmodel1)) then
779  ! output_tab => this%outputtab1
780  ! is_for_model1 = .true.
781  ! else
782  ! output_tab => this%outputtab2
783  ! is_for_model1 = .false.
784  ! end if
785  ! !
786  ! ! -- update output tables
787  ! if (this%ipr_flow /= 0) then
788  ! !
789  ! ! -- update titles
790  ! if (model%oc%oc_save('BUDGET')) then
791  ! call output_tab%set_title(packname)
792  ! end if
793  ! !
794  ! ! -- set table kstp and kper
795  ! call output_tab%set_kstpkper(kstp, kper)
796  ! !
797  ! ! -- update maxbound of tables
798  ! ntabrows = 0
799  ! do i = 1, this%nexg
800  ! n1 = this%nodeswf(i)
801  ! n2 = this%nodegwf(i)
802  ! !
803  ! ! -- If both cells are active then calculate flow rate
804  ! if (this%swfmodel1%ibound(n1) /= 0 .and. &
805  ! this%gwfmodel2%ibound(n2) /= 0) then
806  ! ntabrows = ntabrows + 1
807  ! end if
808  ! end do
809  ! if (ntabrows > 0) then
810  ! call output_tab%set_maxbound(ntabrows)
811  ! end if
812  ! end if
813  ! !
814  ! ! -- Print and write budget terms
815  ! !
816  ! ! -- Set binary unit numbers for saving flows
817  ! if (this%ipakcb /= 0) then
818  ! ibinun = model%oc%oc_save_unit('BUDGET')
819  ! else
820  ! ibinun = 0
821  ! end if
822  ! !
823  ! ! -- If save budget flag is zero for this stress period, then
824  ! ! shut off saving
825  ! if (.not. model%oc%oc_save('BUDGET')) ibinun = 0
826  ! !
827  ! ! -- If cell-by-cell flows will be saved as a list, write header.
828  ! if (ibinun /= 0) then
829  ! call model%dis%record_srcdst_list_header(budtxt(1), &
830  ! model%name, &
831  ! this%name, &
832  ! neighbor_name, &
833  ! this%name, &
834  ! this%naux, this%auxname, &
835  ! ibinun, this%nexg, &
836  ! model%iout)
837  ! end if
838  ! !
839  ! ! Initialize accumulators
840  ! ratin = DZERO
841  ! ratout = DZERO
842  ! !
843  ! ! -- Loop through all exchanges
844  ! do i = 1, this%nexg
845  ! !
846  ! ! -- Assign boundary name
847  ! if (this%inamedbound > 0) then
848  ! bname = this%boundname(i)
849  ! else
850  ! bname = ''
851  ! end if
852  ! !
853  ! ! -- Calculate the flow rate between n1 and n2
854  ! rrate = DZERO
855  ! n1 = this%nodeswf(i)
856  ! n2 = this%nodegwf(i)
857  ! !
858  ! ! -- If both cells are active then calculate flow rate
859  ! if (this%v_model1%ibound%get(n1) /= 0 .and. &
860  ! this%v_model2%ibound%get(n2) /= 0) then
861  ! rrate = this%simvals(i)
862  ! !
863  ! ! -- Print the individual rates to model list files if requested
864  ! if (this%ipr_flow /= 0) then
865  ! if (model%oc%oc_save('BUDGET')) then
866  ! !
867  ! ! -- set nodestr and write outputtab table
868  ! if (is_for_model1) then
869  ! nodeu = model%dis%get_nodeuser(n1)
870  ! call model%dis%nodeu_to_string(nodeu, nodestr)
871  ! call output_tab%print_list_entry(i, trim(adjustl(nodestr)), &
872  ! rrate, bname)
873  ! else
874  ! nodeu = model%dis%get_nodeuser(n2)
875  ! call model%dis%nodeu_to_string(nodeu, nodestr)
876  ! call output_tab%print_list_entry(i, trim(adjustl(nodestr)), &
877  ! -rrate, bname)
878  ! end if
879  ! end if
880  ! end if
881  ! if (rrate < DZERO) then
882  ! ratout = ratout - rrate
883  ! else
884  ! ratin = ratin + rrate
885  ! end if
886  ! end if
887  ! !
888  ! ! -- If saving cell-by-cell flows in list, write flow
889  ! n1u = this%v_model1%dis_get_nodeuser(n1)
890  ! n2u = this%v_model2%dis_get_nodeuser(n2)
891  ! if (ibinun /= 0) then
892  ! if (is_for_model1) then
893  ! if (size(auxrow) > 0) then
894  ! auxrow(:) = this%auxvar(:, i)
895  ! end if
896 ! call model%dis%record_mf6_list_entry(ibinun, n1u, n2u, rrate, &
897  ! this%naux, auxrow, &
898  ! .false., .false.)
899  ! else
900  ! call model%dis%record_mf6_list_entry(ibinun, n2u, n1u, -rrate, &
901  ! this%naux, auxrow, &
902  ! .false., .false.)
903  ! end if
904  ! end if
905  ! !
906  ! end do
907  ! !
908  ! ! -- Return
909  ! return
910  ! end subroutine swf_gwf_bdsav_model
911 
912  !> @ brief Output
913  !!
914  !! Write output
915  !<
916  subroutine swf_gwf_ot(this)
917  ! -- modules
918  use simvariablesmodule, only: iout
919  use constantsmodule, only: dzero, linelength
920  ! -- dummy
921  class(swfgwfexchangetype) :: this !< SwfGwfExchangeType
922  ! -- local
923  integer(I4B) :: iexg, n1, n2
924  real(DP) :: flow
925  character(len=LINELENGTH) :: node1str, node2str
926  ! -- format
927  character(len=*), parameter :: fmtheader2 = &
928  "(/1x, 'SUMMARY OF EXCHANGE RATES FOR EXCHANGE ', a, ' WITH ID ', i0, /, &
929  &2a16, 4a16, /, 96('-'))"
930  character(len=*), parameter :: fmtdata = &
931  "(2a16, 5(1pg16.6))"
932  !
933  ! -- Call bdsave
934  call this%swf_gwf_bdsav()
935  !
936  ! -- Write a table of exchanges
937  if (this%ipr_flow /= 0) then
938  write (iout, fmtheader2) trim(adjustl(this%name)), this%id, 'NODEM1', &
939  'NODEM2', 'COND', 'X_M1', 'X_M2', 'FLOW'
940  do iexg = 1, this%nexg
941  n1 = this%nodeswf(iexg)
942  n2 = this%nodegwf(iexg)
943  flow = this%simvals(iexg)
944  call this%swfmodel%dis%noder_to_string(n1, node1str)
945  call this%gwfmodel%dis%noder_to_string(n2, node2str)
946  write (iout, fmtdata) trim(adjustl(node1str)), &
947  trim(adjustl(node2str)), &
948  this%bedleak(iexg), this%swfmodel%x(n1), &
949  this%gwfmodel%x(n2), flow
950  end do
951  end if
952  !
953  ! -- OBS output
954  call this%obs%obs_ot()
955  end subroutine swf_gwf_ot
956 
957  !> @ brief Save simulated flow observations
958  !!
959  !! Save the simulated flows for each exchange
960  !<
961  subroutine swf_gwf_save_simvals(this)
962  ! -- modules
964  use simvariablesmodule, only: errmsg
965  use constantsmodule, only: dzero
966  use observemodule, only: observetype
967  ! -- dummy
968  class(swfgwfexchangetype), intent(inout) :: this
969  ! -- local
970  integer(I4B) :: i
971  integer(I4B) :: j
972  integer(I4B) :: n1
973  integer(I4B) :: n2
974  integer(I4B) :: iexg
975  real(DP) :: v
976  type(observetype), pointer :: obsrv => null()
977  !
978  ! -- Write simulated values for all gwf-gwf observations
979  if (this%obs%npakobs > 0) then
980  call this%obs%obs_bd_clear()
981  do i = 1, this%obs%npakobs
982  obsrv => this%obs%pakobs(i)%obsrv
983  do j = 1, obsrv%indxbnds_count
984  iexg = obsrv%indxbnds(j)
985  v = dzero
986  select case (obsrv%ObsTypeId)
987  case ('FLOW-JA-FACE')
988  n1 = this%nodeswf(iexg)
989  n2 = this%nodegwf(iexg)
990  v = this%simvals(iexg)
991  case default
992  errmsg = 'Unrecognized observation type: '// &
993  trim(obsrv%ObsTypeId)
994  call store_error(errmsg)
995  call store_error_unit(this%inobs)
996  end select
997  call this%obs%SaveOneSimval(obsrv, v)
998  end do
999  end do
1000  end if
1001  end subroutine swf_gwf_save_simvals
1002 
1003  !> @brief Should return true when the exchange should be added to the
1004  !! solution where the model resides
1005  !<
1006  function swf_gwf_connects_model(this, model) result(is_connected)
1007  ! -- dummy
1008  class(swfgwfexchangetype) :: this !< the instance of the exchange
1009  class(basemodeltype), pointer, intent(in) :: model !< the model to which the exchange might hold a connection
1010  ! -- return
1011  logical(LGP) :: is_connected !< true, when connected
1012  !
1013  is_connected = .false.
1014  select type (model)
1015  class is (gwfmodeltype)
1016  if (associated(this%gwfmodel, model)) then
1017  is_connected = .true.
1018  end if
1019  class is (swfmodeltype)
1020  if (associated(this%swfmodel, model)) then
1021  is_connected = .true.
1022  end if
1023  end select
1024  end function
1025 
1026 end module swfgwfexchangemodule
subroutine, public addbaseexchangetolist(list, exchange)
Add the exchange object (BaseExchangeType) to a list.
class(basemodeltype) function, pointer, public getbasemodelfromlist(list, idx)
Definition: BaseModel.f90:172
This module contains the BudgetModule.
Definition: Budget.f90:20
subroutine, public rate_accumulator(flow, rin, rout)
@ brief Rate accumulator subroutine
Definition: Budget.f90:632
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 lenpackagename
maximum length of the package name
Definition: Constants.f90:23
integer(i4b), parameter lenftype
maximum length of a package type (DIS, WEL, OC, etc.)
Definition: Constants.f90:39
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
integer(i4b), parameter lenbudtxt
maximum length of a budget component names
Definition: Constants.f90:37
integer(i4b) function, public get_node(ilay, irow, icol, nlay, nrow, ncol)
Get node number, given layer, row, and column indices for a structured grid. If any argument is inval...
Definition: GeomUtil.f90:83
Definition: gwf.f90:1
integer(i4b) function, public getunit()
Get a free unit number.
subroutine, public openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, filstat_opt, mode_opt)
Open a file.
Definition: InputOutput.f90:30
This module defines variable data types.
Definition: kind.f90:8
type(listtype), public basemodellist
Definition: mf6lists.f90:16
type(listtype), public baseexchangelist
Definition: mf6lists.f90:25
real(dp) function, public get_perturbation(x)
Calculate a numerical perturbation given the value of x.
Definition: MathUtil.f90:372
character(len=lenmempath) function create_mem_path(component, subcomponent, context)
returns the path to the memory object
This module contains the derived types ObserveType and ObsDataType.
Definition: Observe.f90:15
This module contains the derived type ObsType.
Definition: Obs.f90:127
subroutine, public obs_cr(obs, inobs)
@ brief Create a new ObsType object
Definition: Obs.f90:225
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
integer(i4b) function, public count_errors()
Return number of errors.
Definition: Sim.f90:59
subroutine, public store_error_filename(filename, terminate)
Store the erroring file name.
Definition: Sim.f90:203
subroutine, public store_error_unit(iunit, terminate)
Store the file unit number.
Definition: Sim.f90:168
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string
integer(i4b), dimension(:), allocatable model_loc_idx
equals the local index into the basemodel list (-1 when not available)
integer(i4b) iout
file unit number for simulation output
subroutine squadratic(x, range, dydx, y)
@ brief sQuadratic
This module contains the SwfGwfExchangeModule Module.
Definition: exg-swfgwf.f90:8
integer(i4b) function noder(this, model, cellid, iout)
Definition: exg-swfgwf.f90:406
character(len=20) function cellstr(this, model, cellid, iout)
Definition: exg-swfgwf.f90:433
subroutine swf_gwf_mc(this, matrix_sln)
@ brief Map connections
Definition: exg-swfgwf.f90:201
subroutine swf_gwf_fc(this, kiter, matrix_sln, rhs_sln, inwtflag)
@ brief Fill coefficients
Definition: exg-swfgwf.f90:225
subroutine initialize(this, filename, name, swf_ftype, id, m1_id, m2_id, input_mempath)
@ brief Initialize SWF GWF exchange
Definition: exg-swfgwf.f90:98
subroutine swf_gwf_ac(this, sparse)
@ brief Add connections
Definition: exg-swfgwf.f90:179
subroutine swf_gwf_cq(this, icnvg, isuppress_output, isolnid)
@ brief Calculate flow
Definition: exg-swfgwf.f90:310
real(dp) function qcalc(this, iexg, hswf, hgwf)
@ brief Calculate flow
Definition: exg-swfgwf.f90:497
subroutine swf_gwf_save_simvals(this)
@ brief Save simulated flow observations
Definition: exg-swfgwf.f90:962
subroutine swf_gwf_add_to_flowja(this)
Add exchange flow to each model flowja diagonal position so that residual is calculated correctly.
Definition: exg-swfgwf.f90:586
real(dp) function get_wetted_perimeter(this, nodeswf, depth)
@ brief Get wetted perimeter for swf channel model
Definition: exg-swfgwf.f90:565
subroutine swf_gwf_ot(this)
@ brief Output
Definition: exg-swfgwf.f90:917
subroutine allocate_scalars(this)
@ brief Allocate scalars
Definition: exg-swfgwf.f90:365
subroutine swf_gwf_da(this)
@ brief Deallocate
Definition: exg-swfgwf.f90:332
real(dp) function get_cond(this, iexg, hswf, hgwf)
@ brief Calculate conductance
Definition: exg-swfgwf.f90:519
subroutine swf_gwf_bd(this, icnvg, isuppress_output, isolnid)
@ brief Budget
Definition: exg-swfgwf.f90:622
logical(lgp) function swf_gwf_connects_model(this, model)
Should return true when the exchange should be added to the solution where the model resides.
subroutine swf_gwf_bdsav(this)
@ brief Budget save
Definition: exg-swfgwf.f90:727
subroutine swf_gwf_calc_simvals(this)
Calculate flow rates for the exchanges and store them in a member array.
Definition: exg-swfgwf.f90:464
subroutine allocate_arrays(this)
Allocate array data, using the number of connected nodes.
Definition: exg-swfgwf.f90:391
subroutine swf_gwf_chd_bd(this)
@ brief swf-gwf-chd-bd
Definition: exg-swfgwf.f90:665
Surface Water Flow (SWF) Module.
Definition: swf.f90:3
subroutine, public table_cr(this, name, title)
Definition: Table.f90:87
Highest level model type. All models extend this parent type.
Definition: BaseModel.f90:13