MODFLOW 6  version 6.9.0.dev0
USGS Modular Hydrologic Model
gwf-npf.f90
Go to the documentation of this file.
2  use kindmodule, only: dp, i4b
4  use disumodule, only: disutype
5  use constantsmodule, only: dzero, dem9, dem8, dem7, dem6, dem2, &
6  dhalf, dp9, done, dtwo, &
7  dhnoflo, dhdry, dem10, &
14  use basedismodule, only: disbasetype
15  use gwficmodule, only: gwfictype
16  use gwfvscmodule, only: gwfvsctype
17  use xt3dmodule, only: xt3dtype
19  use tvkmodule, only: tvktype, tvk_cr
24  use hgeoutilmodule, only: hyeff
26  condmean, thksatnm, &
32 
33  implicit none
34 
35  private
36  public :: gwfnpftype
37  public :: npf_cr
38 
39  type, extends(numericalpackagetype) :: gwfnpftype
40 
41  type(gwfictype), pointer :: ic => null() !< initial conditions object
42  type(gwfvsctype), pointer :: vsc => null() !< viscosity object
43  type(xt3dtype), pointer :: xt3d => null() !< xt3d pointer
44  integer(I4B), pointer :: iname => null() !< length of variable names
45  character(len=24), dimension(:), pointer :: aname => null() !< variable names
46  integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound
47  real(dp), dimension(:), pointer, contiguous :: hnew => null() !< pointer to model xnew
48  integer(I4B), pointer :: ixt3d => null() !< xt3d flag (0 is off, 1 is lhs, 2 is rhs)
49  integer(I4B), pointer :: ixt3drhs => null() !< xt3d rhs flag, xt3d rhs is set active if 1
50  integer(I4B), pointer :: iperched => null() !< vertical flow corrections if 1
51  integer(I4B), pointer :: ivarcv => null() !< CV is function of water table
52  integer(I4B), pointer :: idewatcv => null() !< CV may be a discontinuous function of water table
53  integer(I4B), pointer :: ithickstrt => null() !< thickstrt option flag
54  integer(I4B), pointer :: ihighcellsat => null() !< highest_cell_saturation option flag
55  integer(I4B), pointer :: igwfnewtonur => null() !< newton head dampening using node bottom option flag
56  integer(I4B), pointer :: icalcspdis => null() !< Calculate specific discharge at cell centers
57  integer(I4B), pointer :: isavspdis => null() !< Save specific discharge at cell centers
58  integer(I4B), pointer :: isavsat => null() !< Save sat to budget file
59  real(dp), pointer :: hnoflo => null() !< default is 1.e30
60  real(dp), pointer :: satomega => null() !< newton-raphson saturation omega
61  integer(I4B), pointer :: irewet => null() !< rewetting (0:off, 1:on)
62  integer(I4B), pointer :: iwetit => null() !< wetting interval (default is 1)
63  integer(I4B), pointer :: ihdwet => null() !< (0 or not 0)
64  integer(I4B), pointer :: icellavg => null() !< harmonic(0), logarithmic(1), or arithmetic thick-log K (2)
65  real(dp), pointer :: wetfct => null() !< wetting factor
66  real(dp), pointer :: hdry => null() !< default is -1.d30
67  integer(I4B), dimension(:), pointer, contiguous :: icelltype => null() !< confined (0) or convertible (1)
68  integer(I4B), dimension(:), pointer, contiguous :: ithickstartflag => null() !< array of flags for handling the thickstrt option
69  !
70  ! K properties
71  real(dp), dimension(:), pointer, contiguous :: k11 => null() !< hydraulic conductivity; if anisotropic, then this is Kx prior to rotation
72  real(dp), dimension(:), pointer, contiguous :: k22 => null() !< hydraulic conductivity; if specified then this is Ky prior to rotation
73  real(dp), dimension(:), pointer, contiguous :: k33 => null() !< hydraulic conductivity; if specified then this is Kz prior to rotation
74  real(dp), dimension(:), pointer, contiguous :: krel => null() !< relative permeability; unless UZR flow is active in a cell, this is 1
75  real(dp), dimension(:), pointer, contiguous :: k11input => null() !< hydraulic conductivity originally specified by user prior to TVK or VSC modification
76  real(dp), dimension(:), pointer, contiguous :: k22input => null() !< hydraulic conductivity originally specified by user prior to TVK or VSC modification
77  real(dp), dimension(:), pointer, contiguous :: k33input => null() !< hydraulic conductivity originally specified by user prior to TVK or VSC modification
78  integer(I4B), pointer :: iavgkeff => null() !< effective conductivity averaging (0: harmonic, 1: arithmetic)
79  integer(I4B), pointer :: ik22 => null() !< flag that k22 is specified
80  integer(I4B), pointer :: ik33 => null() !< flag that k33 is specified
81  integer(I4B), pointer :: ik22overk => null() !< flag that k22 is specified as anisotropy ratio
82  integer(I4B), pointer :: ik33overk => null() !< flag that k33 is specified as anisotropy ratio
83  integer(I4B), pointer :: iangle1 => null() !< flag to indicate angle1 was read
84  integer(I4B), pointer :: iangle2 => null() !< flag to indicate angle2 was read
85  integer(I4B), pointer :: iangle3 => null() !< flag to indicate angle3 was read
86  real(dp), dimension(:), pointer, contiguous :: angle1 => null() !< k ellipse rotation in xy plane around z axis (yaw)
87  real(dp), dimension(:), pointer, contiguous :: angle2 => null() !< k ellipse rotation up from xy plane around y axis (pitch)
88  real(dp), dimension(:), pointer, contiguous :: angle3 => null() !< k tensor rotation around x axis (roll)
89  !
90  integer(I4B), pointer :: iwetdry => null() !< flag to indicate angle1 was read
91  real(dp), dimension(:), pointer, contiguous :: wetdry => null() !< wetdry array
92  real(dp), dimension(:), pointer, contiguous :: sat => null() !< saturation (0. to 1.) for each cell
93  real(dp), dimension(:), pointer, contiguous :: condsat => null() !< saturated conductance (symmetric array)
94  integer(I4B), dimension(:), pointer, contiguous :: ibotnode => null() !< bottom node used if igwfnewtonur /= 0
95  ! spdis machinery:
96  real(dp), dimension(:, :), pointer, contiguous :: spdis => null() !< specific discharge : qx, qy, qz (nodes, 3)
97  integer(I4B), pointer :: nedges => null() !< number of cell edges
98  integer(I4B), pointer :: lastedge => null() !< last edge number
99  integer(I4B), dimension(:), pointer, contiguous :: nodedge => null() !< array of node numbers that have edges
100  integer(I4B), dimension(:), pointer, contiguous :: ihcedge => null() !< edge type (horizontal or vertical)
101  real(dp), dimension(:, :), pointer, contiguous :: propsedge => null() !< edge properties (Q, area, nx, ny, distance)
102  integer(I4B), dimension(:), pointer, contiguous :: iedge_ptr => null() !< csr pointer into edge index array
103  integer(I4B), dimension(:), pointer, contiguous :: edge_idxs => null() !< sorted edge indexes for faster lookup
104  type(spdisworkarraytype), pointer :: spdis_wa => null() !< work arrays for spdis calculation
105  !
106  integer(I4B), pointer :: intvk => null() !< TVK (time-varying K) unit number (0 if unused)
107  integer(I4B), pointer :: invsc => null() !< VSC (viscosity) unit number (0 if unused); viscosity leads to time-varying K's
108  type(tvktype), pointer :: tvk => null() !< TVK object
109  integer(I4B), pointer :: kchangeper => null() !< last stress period in which any node K (or K22, or K33) values were changed (0 if unchanged from start of simulation)
110  integer(I4B), pointer :: kchangestp => null() !< last time step in which any node K (or K22, or K33) values were changed (0 if unchanged from start of simulation)
111  integer(I4B), dimension(:), pointer, contiguous :: nodekchange => null() ! grid array of flags indicating for each node whether its K (or K22, or K33) value changed (1) at (kchangeper, kchangestp) or not (0)
112  !
113  integer(I4B), dimension(:), pointer, contiguous :: iformulation => null() !< active formulation for the connection (size: nja)
114  type(gwfnpfformcontainertype), dimension(MAX_EXT_FLOW_FORMS), private :: &
115  flow_formulations !< alternative flow calculations by extension
116  class(gwfnpfformulationtype), pointer :: default_form => null() !< default conductance formulation
117  contains
118  procedure :: npf_df
119  procedure :: npf_ac
120  procedure :: npf_mc
121  procedure :: npf_ar
122  procedure :: npf_rp
123  procedure :: npf_ad
124  procedure :: npf_cf
125  procedure :: npf_fc
126  procedure :: npf_fn
127  procedure :: npf_cq
128  procedure :: npf_save_model_flows
129  procedure :: npf_nur
131  procedure :: npf_da
132  procedure :: allocate_scalars
133  procedure :: rewet_check
134  procedure :: hy_eff
135  procedure :: calc_spdis
136  procedure :: sav_spdis
137  procedure :: sav_sat
138  procedure :: increase_edge_count
139  procedure :: set_edge_properties
140  procedure :: calcsatthickness
141  procedure :: add_flow_formulation
142  ! private
143  procedure, private :: thksat => sgwf_npf_thksat
144  procedure, private :: qcalc => sgwf_npf_qcalc
145  procedure, private :: wd => sgwf_npf_wetdry
146  procedure, private :: wdmsg => sgwf_npf_wdmsg
147  procedure, private :: store_original_k_arrays
148  procedure, private :: allocate_arrays
149  procedure, private :: source_options
150  procedure, private :: source_griddata
151  procedure, private :: log_options
152  procedure, private :: log_griddata
153  procedure, private :: set_options
154  procedure, private :: check_options
155  procedure, private :: prepcheck
156  procedure, private :: preprocess_input
157  procedure, private :: cf_default_flow
158  procedure, private :: fc_default_flow
159  procedure, private :: fn_default_flow
160  procedure, private :: cq_default_flow
161  procedure, private :: calc_condsat
162  procedure, private :: calc_initial_sat
163  procedure, private :: calc_max_conns
164  procedure, private :: prepare_edge_lookup
165  procedure, private :: highest_cell_saturation
166  end type
167 
168  !> @brief Default conductance flow formulation
169  !!
170  !! Wraps the standard NPF conductance fill so it participates in the
171  !! additive list of flow formulations. Faces claimed by an exclusive
172  !! formulation are skipped.
173  !<
175  class(gwfnpftype), pointer :: npf => null() !< owning NPF package
176  contains
177  procedure :: cf => default_flow_cf
178  procedure :: fc => default_flow_fc
179  procedure :: fn => default_flow_fn
180  procedure :: cq => default_flow_cq
182 
183 contains
184 
185  !> @brief Create a new NPF object. Pass a inunit value of 0 if npf data will
186  !! initialized from memory
187  !<
188  subroutine npf_cr(npfobj, name_model, input_mempath, inunit, iout)
189  ! -- modules
190  use kindmodule, only: lgp
192  ! -- dummy
193  type(gwfnpftype), pointer :: npfobj
194  character(len=*), intent(in) :: name_model
195  character(len=*), intent(in) :: input_mempath
196  integer(I4B), intent(in) :: inunit
197  integer(I4B), intent(in) :: iout
198  ! -- formats
199  character(len=*), parameter :: fmtheader = &
200  "(1x, /1x, 'NPF -- NODE PROPERTY FLOW PACKAGE, VERSION 1, 3/30/2015', &
201  &' INPUT READ FROM MEMPATH: ', A, /)"
202  !
203  ! -- Create the object
204  allocate (npfobj)
205  !
206  ! -- create name and memory path
207  call npfobj%set_names(1, name_model, 'NPF', 'NPF', input_mempath)
208  !
209  ! -- Allocate scalars
210  call npfobj%allocate_scalars()
211  !
212  ! -- Set variables
213  npfobj%inunit = inunit
214  npfobj%iout = iout
215  !
216  ! -- check if npf is enabled
217  if (inunit > 0) then
218  !
219  ! -- Print a message identifying the node property flow package.
220  write (iout, fmtheader) input_mempath
221  end if
222 
223  ! allocate spdis structure
224  allocate (npfobj%spdis_wa)
225 
226  end subroutine npf_cr
227 
228  !> @brief Define the NPF package instance
229  !!
230  !! This is a hybrid routine: it either reads the options for this package
231  !! from the input file, or the optional argument @param npf_options
232  !! should be passed. A consistency check is performed, and finally
233  !! xt3d_df is called, when enabled.
234  !<
235  subroutine npf_df(this, dis, xt3d, ingnc, invsc, npf_options)
236  ! -- modules
237  use simmodule, only: store_error
238  use xt3dmodule, only: xt3d_cr
239  ! -- dummy
240  class(gwfnpftype) :: this !< instance of the NPF package
241  class(disbasetype), pointer, intent(inout) :: dis !< the pointer to the discretization
242  type(xt3dtype), pointer :: xt3d !< the pointer to the XT3D 'package'
243  integer(I4B), intent(in) :: ingnc !< ghostnodes enabled? (>0 means yes)
244  integer(I4B), intent(in) :: invsc !< viscosity enabled? (>0 means yes)
245  type(gwfnpfoptionstype), optional, intent(in) :: npf_options !< the optional options, for when not constructing from file
246  !
247  ! -- Set a pointer to dis
248  this%dis => dis
249  !
250  ! -- Set flag signifying whether vsc is active
251  if (invsc > 0) this%invsc = invsc
252  !
253  if (.not. present(npf_options)) then
254  !
255  ! -- source options
256  call this%source_options()
257  !
258  ! -- allocate arrays
259  call this%allocate_arrays(this%dis%nodes, this%dis%njas)
260  !
261  ! -- source griddata, set, and convert/check the input
262  call this%source_griddata()
263  call this%prepcheck()
264  else
265  call this%set_options(npf_options)
266  !
267  ! -- allocate arrays
268  call this%allocate_arrays(this%dis%nodes, this%dis%njas)
269  end if
270  !
271  call this%check_options()
272  !
273  ! -- Save pointer to xt3d object
274  this%xt3d => xt3d
275  if (this%ixt3d /= 0) xt3d%ixt3d = this%ixt3d
276  call this%xt3d%xt3d_df(dis)
277  !
278  ! -- Ensure GNC and XT3D are not both on at the same time
279  if (this%ixt3d /= 0 .and. ingnc > 0) then
280  call store_error('Error in model '//trim(this%name_model)// &
281  '. The XT3D option cannot be used with the GNC &
282  &Package.', terminate=.true.)
283  end if
284  end subroutine npf_df
285 
286  !> @brief Add connections for extended neighbors to the sparse matrix
287  !<
288  subroutine npf_ac(this, moffset, sparse)
289  ! -- modules
290  use sparsemodule, only: sparsematrix
291  ! -- dummy
292  class(gwfnpftype) :: this
293  integer(I4B), intent(in) :: moffset
294  type(sparsematrix), intent(inout) :: sparse
295  !
296  ! -- Add extended neighbors (neighbors of neighbors)
297  if (this%ixt3d /= 0) call this%xt3d%xt3d_ac(moffset, sparse)
298  end subroutine npf_ac
299 
300  !> @brief Map connections and construct iax, jax, and idxglox
301  !<
302  subroutine npf_mc(this, moffset, matrix_sln)
303  ! -- dummy
304  class(gwfnpftype) :: this
305  integer(I4B), intent(in) :: moffset
306  class(matrixbasetype), pointer :: matrix_sln
307  !
308  if (this%ixt3d /= 0) call this%xt3d%xt3d_mc(moffset, matrix_sln)
309  end subroutine npf_mc
310 
311  !> @brief Allocate and read this NPF instance
312  !!
313  !! Allocate remaining package arrays, preprocess the input data and
314  !! call *_ar on xt3d, when active.
315  !<
316  subroutine npf_ar(this, ic, vsc, ibound, hnew)
317  ! -- modules
320  ! -- dummy
321  class(gwfnpftype) :: this !< instance of the NPF package
322  type(gwfictype), pointer, intent(in) :: ic !< initial conditions
323  type(gwfvsctype), pointer, intent(in) :: vsc !< viscosity package
324  integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: ibound !< model ibound array
325  real(DP), dimension(:), pointer, contiguous, intent(inout) :: hnew !< pointer to model head array
326  ! -- local
327  integer(I4B) :: n
328  !
329  ! -- Store pointers to arguments that were passed in
330  this%ic => ic
331  this%ibound => ibound
332  this%hnew => hnew
333  !
334  if (this%icalcspdis == 1) then
335  call mem_reallocate(this%spdis, 3, this%dis%nodes, 'SPDIS', this%memoryPath)
336  call mem_reallocate(this%nodedge, this%nedges, 'NODEDGE', this%memoryPath)
337  call mem_reallocate(this%ihcedge, this%nedges, 'IHCEDGE', this%memoryPath)
338  call mem_reallocate(this%propsedge, 5, this%nedges, 'PROPSEDGE', &
339  this%memoryPath)
340  call mem_reallocate(this%iedge_ptr, this%dis%nodes + 1, &
341  'NREDGESNODE', this%memoryPath)
342  call mem_reallocate(this%edge_idxs, this%nedges, &
343  'EDGEIDXS', this%memoryPath)
344 
345  do n = 1, this%nedges
346  this%edge_idxs(n) = 0
347  end do
348  do n = 1, this%dis%nodes
349  this%iedge_ptr(n) = 0
350  this%spdis(:, n) = dzero
351  end do
352  end if
353  !
354  ! -- Store pointer to VSC if active
355  if (this%invsc /= 0) then
356  this%vsc => vsc
357  end if
358  !
359  ! -- allocate arrays to store original user input in case TVK/VSC modify them
360  if (this%invsc > 0) then
361  !
362  ! -- Reallocate arrays that store user-input values.
363  call mem_reallocate(this%k11input, this%dis%nodes, 'K11INPUT', &
364  this%memoryPath)
365  call mem_reallocate(this%k22input, this%dis%nodes, 'K22INPUT', &
366  this%memoryPath)
367  call mem_reallocate(this%k33input, this%dis%nodes, 'K33INPUT', &
368  this%memoryPath)
369  ! Allocate arrays that will store the original K values. When VSC active,
370  ! the current Kxx arrays carry the viscosity-adjusted K values.
371  ! This approach leverages existing functionality that makes use of K.
372  call this%store_original_k_arrays(this%dis%nodes, this%dis%njas)
373  end if
374  !
375  ! -- preprocess data
376  call this%preprocess_input()
377  !
378  ! -- xt3d
379  ! -- Terminate if the DISU ANGLDEGX values are inconsistent and this
380  ! package requires ANGLDEGX (it has no effect otherwise)
381  if (this%ixt3d /= 0 .or. this%ik22 /= 0 .or. this%icalcspdis /= 0) then
382  select type (dis => this%dis)
383  type is (disutype)
384  if (dis%nangldegxerr > 0) then
385  write (errmsg, '(a,1x,i0,1x,a)') &
386  'ANGLDEGX values in the DISU Package are inconsistent for', &
387  dis%nangldegxerr, 'cell faces (see the warnings written after &
388  &the DISU Package input in the model listing file). ANGLDEGX &
389  &must be correct because it is required input for the NPF &
390  &Package when XT3D, K22, or SAVE_SPECIFIC_DISCHARGE is specified.'
391  call store_error(errmsg)
392  call store_error_filename(dis%input_fname)
393  end if
394  end select
395  end if
396  !
397  if (this%ixt3d /= 0) then
398  call this%xt3d%xt3d_ar(ibound, this%k11, this%ik33, this%k33, &
399  this%sat, this%ik22, this%k22, &
400  this%iangle1, this%iangle2, this%iangle3, &
401  this%angle1, this%angle2, this%angle3, &
402  this%inewton, this%icelltype)
403  end if
404  !
405  ! -- TVK
406  if (this%intvk /= 0) then
407  call this%tvk%ar(this%dis)
408  end if
409  end subroutine npf_ar
410 
411  !> @brief Read and prepare method for package
412  !!
413  !! Read and prepare NPF stress period data.
414  !<
415  subroutine npf_rp(this)
416  implicit none
417  ! -- dummy
418  class(gwfnpftype) :: this
419  !
420  ! -- TVK
421  if (this%intvk /= 0) then
422  call this%tvk%rp()
423  end if
424  end subroutine npf_rp
425 
426  !> @brief Advance
427  !!
428  !! Sets hold (head old) to bot whenever a wettable cell is dry
429  !<
430  subroutine npf_ad(this, nodes, hold, hnew, irestore)
431  ! -- modules
432  use tdismodule, only: kper, kstp
433  !
434  implicit none
435  ! -- dummy
436  class(gwfnpftype) :: this
437  integer(I4B), intent(in) :: nodes
438  real(DP), dimension(nodes), intent(inout) :: hold
439  real(DP), dimension(nodes), intent(inout) :: hnew
440  integer(I4B), intent(in) :: irestore
441  ! -- local
442  integer(I4B) :: n
443  !
444  ! -- loop through all cells and set hold=bot if wettable cell is dry
445  if (this%irewet > 0) then
446  do n = 1, this%dis%nodes
447  if (this%wetdry(n) == dzero) cycle
448  if (this%ibound(n) /= 0) cycle
449  hold(n) = this%dis%bot(n)
450  end do
451  !
452  ! -- if restore state, then set hnew to DRY if it is a dry wettable cell
453  do n = 1, this%dis%nodes
454  if (this%wetdry(n) == dzero) cycle
455  if (this%ibound(n) /= 0) cycle
456  hnew(n) = dhdry
457  end do
458  end if
459  !
460  ! -- TVK
461  if (this%intvk /= 0) then
462  call this%tvk%ad()
463  end if
464  !
465  ! -- VSC
466  ! -- Hit the TVK-updated K's with VSC correction before calling/updating condsat
467  if (this%invsc /= 0) then
468  call this%vsc%update_k_with_vsc()
469  end if
470  !
471  ! -- If any K values have changed, we need to update CONDSAT or XT3D arrays
472  if (this%kchangeper == kper .and. this%kchangestp == kstp) then
473  if (this%ixt3d == 0) then
474  !
475  ! -- Update the saturated conductance for all connections
476  ! -- of the affected nodes
477  do n = 1, this%dis%nodes
478  if (this%nodekchange(n) == 1) then
479  call this%calc_condsat(n, .false.)
480  end if
481  end do
482  else
483  !
484  ! -- Recompute XT3D coefficients for permanently confined connections
485  if (this%xt3d%lamatsaved .and. .not. this%xt3d%ldispersion) then
486  call this%xt3d%xt3d_fcpc(this%dis%nodes, .true.)
487  end if
488  end if
489  end if
490  end subroutine npf_ad
491 
492  !> @brief Calculate coefficients
493  !<
494  subroutine npf_cf(this, kiter, nodes, hnew)
495  class(gwfnpftype) :: this
496  integer(I4B) :: kiter
497  integer(I4B), intent(in) :: nodes
498  real(DP), intent(inout), dimension(nodes) :: hnew
499  ! local
500  integer(I4B) :: iform
501 
502  ! Perform wetting and drying
503  if (this%inewton /= 1) then
504  call this%wd(kiter, hnew)
505  end if
506 
507  ! Each active formulation runs over all cells and adds its
508  ! terms; the default conductance formulation is always active.
509  call this%default_form%cf(kiter)
510  do iform = 1, max_ext_flow_forms
511  if (associated(this%flow_formulations(iform)%form)) then
512  call this%flow_formulations(iform)%form%cf(kiter)
513  end if
514  end do
515 
516  end subroutine npf_cf
517 
518  !> @brief Calculate coefficients for the default conductance formulation
519  !!
520  !! Runs over all cells and computes the saturated fraction for
521  !! convertible cells, skipping cells claimed by an exclusive formulation.
522  !<
523  subroutine default_flow_cf(this, kiter)
524  class(defaultflowformulationtype), intent(inout) :: this !< default formulation
525  integer(I4B), intent(in) :: kiter !< outer iteration number
526  ! local
527  integer(I4B) :: n, idiag
528 
529  do n = 1, this%npf%dis%nodes
530  ! skip cells claimed by an exclusive formulation
531  idiag = this%npf%dis%con%ia(n)
532  if (this%npf%iformulation(idiag) /= default_flow) cycle
533  call this%npf%cf_default_flow(kiter, n)
534  end do
535 
536  end subroutine default_flow_cf
537 
538  !> @brief Calculate coefficients using the
539  !< standard conductance formulation
540  subroutine cf_default_flow(this, kiter, n)
541  class(gwfnpftype) :: this
542  integer(I4B) :: kiter
543  integer(I4B) :: n
544  ! local
545  real(DP) :: satn
546 
547  ! Calculate saturated fraction for convertible cells
548  if (this%icelltype(n) /= 0) then
549  if (this%ibound(n) == 0) then
550  satn = dzero
551  else
552  call this%thksat(n, this%hnew(n), satn)
553  end if
554  this%sat(n) = satn
555  end if
556 
557  end subroutine cf_default_flow
558 
559  !> @brief Formulate coefficients
560  !<
561  subroutine npf_fc(this, kiter, matrix_sln, idxglo, rhs, hnew)
562  class(gwfnpftype) :: this !< this instance
563  integer(I4B) :: kiter !< outer iteration number
564  class(matrixbasetype), pointer :: matrix_sln !< the system to be formulated
565  integer(I4B), intent(in), dimension(:) :: idxglo !< lookup table from local to global connection number
566  real(DP), intent(inout), dimension(:) :: rhs !< the righthandside vector
567  real(DP), intent(inout), dimension(:) :: hnew !< the new head values
568  ! local
569  integer(I4B) :: iform
570 
571  if (this%ixt3d /= 0) then
572  call this%xt3d%xt3d_fc(kiter, matrix_sln, idxglo, rhs, hnew)
573  else
574  ! Each active formulation runs over all connections and adds its
575  ! terms; the default conductance formulation is always active.
576  call this%default_form%fc(kiter, matrix_sln, idxglo, rhs, hnew)
577  do iform = 1, max_ext_flow_forms
578  if (associated(this%flow_formulations(iform)%form)) then
579  call this%flow_formulations(iform)%form%fc(kiter, matrix_sln, &
580  idxglo, rhs, hnew)
581  end if
582  end do
583  end if
584 
585  end subroutine npf_fc
586 
587  !> @brief Calculate and add coefficients using the
588  !< standard conductance formulation
589  subroutine fc_default_flow(this, n, m, ipos, matrix_sln, rhs, idxglo, hnew)
590  class(gwfnpftype) :: this !< this instance
591  integer(I4B) :: n !< node number n
592  integer(I4B) :: m !< node number m
593  integer(I4B) :: ipos !< connection number
594  class(matrixbasetype), pointer :: matrix_sln !< system matrix
595  real(DP), intent(inout), dimension(:) :: rhs !< rhs vector
596  integer(I4B), intent(in), dimension(:) :: idxglo !< lookup table from local ipos to global system
597  real(DP), intent(inout), dimension(:) :: hnew !< new head values
598  ! local
599  integer(I4B) :: idiag, ihc
600  integer(I4B) :: isymcon, idiagm
601  real(DP) :: hyn, hym
602  real(DP) :: cond
603  real(DP) :: satn
604  real(DP) :: satm
605 
606  ihc = this%dis%con%ihc(this%dis%con%jas(ipos))
607  hyn = this%hy_eff(n, m, ihc, ipos=ipos)
608  hym = this%hy_eff(m, n, ihc, ipos=ipos)
609 
610  if (ihc == c3d_vertical) then
611  ! Horizontal conductance
612  cond = vcond(this%ibound(n), this%ibound(m), &
613  this%icelltype(n), this%icelltype(m), this%inewton, &
614  this%ivarcv, this%idewatcv, &
615  this%condsat(this%dis%con%jas(ipos)), hnew(n), hnew(m), &
616  hyn, hym, &
617  this%sat(n), this%sat(m), &
618  this%dis%top(n), this%dis%top(m), &
619  this%dis%bot(n), this%dis%bot(m), &
620  this%dis%con%hwva(this%dis%con%jas(ipos)))
621 
622  ! Vertical flow for perched conditions
623  if (this%iperched /= 0) then
624  if (this%icelltype(m) /= 0) then
625  if (hnew(m) < this%dis%top(m)) then
626 
627  ! Fill diagonal for n, and add to RHS
628  idiag = this%dis%con%ia(n)
629  rhs(n) = rhs(n) - cond * this%dis%bot(n)
630  call matrix_sln%add_value_pos(idxglo(idiag), -cond)
631 
632  ! Fill diagonal for m, and add to RHS
633  isymcon = this%dis%con%isym(ipos)
634  call matrix_sln%add_value_pos(idxglo(isymcon), cond)
635  rhs(m) = rhs(m) + cond * this%dis%bot(n)
636 
637  ! go to next connection
638  return
639  end if
640  end if
641  end if
642  else
643  satn = this%sat(n)
644  satm = this%sat(m)
645  if (this%ihighcellsat /= 0) then
646  call this%highest_cell_saturation(n, m, &
647  hnew(n), hnew(m), &
648  satn, satm)
649  end if
650  ! Horizontal conductance
651  cond = hcond(this%ibound(n), this%ibound(m), &
652  this%icelltype(n), this%icelltype(m), &
653  this%inewton, &
654  this%dis%con%ihc(this%dis%con%jas(ipos)), &
655  this%icellavg, &
656  this%condsat(this%dis%con%jas(ipos)), &
657  hnew(n), hnew(m), satn, satm, hyn, hym, &
658  this%dis%top(n), this%dis%top(m), &
659  this%dis%bot(n), this%dis%bot(m), &
660  this%dis%con%cl1(this%dis%con%jas(ipos)), &
661  this%dis%con%cl2(this%dis%con%jas(ipos)), &
662  this%dis%con%hwva(this%dis%con%jas(ipos)))
663  end if
664 
665  ! Fill row n
666  idiag = this%dis%con%ia(n)
667  call matrix_sln%add_value_pos(idxglo(ipos), cond)
668  call matrix_sln%add_value_pos(idxglo(idiag), -cond)
669 
670  ! Fill row m
671  isymcon = this%dis%con%isym(ipos)
672  idiagm = this%dis%con%ia(m)
673  call matrix_sln%add_value_pos(idxglo(isymcon), cond)
674  call matrix_sln%add_value_pos(idxglo(idiagm), -cond)
675 
676  end subroutine fc_default_flow
677 
678  !> @brief Fill coefficients for the default conductance formulation
679  !!
680  !! Runs over all connections and fills the standard NPF conductance
681  !! terms, skipping faces claimed by an exclusive formulation.
682  !<
683  subroutine default_flow_fc(this, kiter, matrix_sln, idxglo, rhs, hnew)
684  class(defaultflowformulationtype), intent(inout) :: this !< default formulation
685  integer(I4B), intent(in) :: kiter !< outer iteration number
686  class(matrixbasetype), pointer, intent(inout) :: matrix_sln !< system matrix
687  integer(I4B), dimension(:), intent(in) :: idxglo !< local to global connection map
688  real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector
689  real(DP), dimension(:), intent(inout) :: hnew !< new head values
690  ! local
691  integer(I4B) :: n, m, ipos
692 
693  do n = 1, this%npf%dis%nodes
694  do ipos = this%npf%dis%con%ia(n) + 1, this%npf%dis%con%ia(n + 1) - 1
695  if (this%npf%dis%con%mask(ipos) == 0) cycle
696 
697  m = this%npf%dis%con%ja(ipos)
698 
699  ! Calculate upper triangle only, but insert into
700  ! upper and lower parts of matrix
701  if (m < n) cycle
702 
703  ! skip faces claimed by an exclusive formulation
704  if (this%npf%iformulation(ipos) /= default_flow) cycle
705 
706  call this%npf%fc_default_flow(n, m, ipos, matrix_sln, &
707  rhs, idxglo, hnew)
708  end do
709  end do
710 
711  end subroutine default_flow_fc
712 
713  !> @brief Calculate dry cell saturation
714  !!
715  !! Calculate the saturation based on the maximum cell bottom for
716  !! two connected cells
717  !<
718  subroutine highest_cell_saturation(this, n, m, hn, hm, satn, satm)
719  ! dummy
720  class(gwfnpftype) :: this
721  integer(I4B), intent(in) :: n, m
722  real(DP), intent(in) :: hn, hm
723  real(DP), intent(inout) :: satn, satm
724  ! local
725  integer(I4B) :: ihdbot
726  real(DP) :: botn, botm
727  real(DP) :: top, bot
728 
729  botn = this%dis%bot(n)
730  botm = this%dis%bot(m)
731 
732  ihdbot = n
733  if (botm > botn) ihdbot = m
734 
735  ! recalculate saturation if the difference in elevation between
736  ! two cells exceed a threshold value
737  if (abs(botm - botn) >= dem2) then
738  top = this%dis%top(ihdbot)
739  bot = this%dis%bot(ihdbot)
740  satn = squadraticsaturation(top, bot, hn, this%satomega)
741  satm = squadraticsaturation(top, bot, hm, this%satomega)
742  end if
743  end subroutine highest_cell_saturation
744 
745  !> @brief Fill newton terms
746  !<
747  subroutine npf_fn(this, kiter, matrix_sln, idxglo, rhs, hnew)
748  ! -- dummy
749  class(gwfnpftype) :: this
750  integer(I4B) :: kiter
751  class(matrixbasetype), pointer :: matrix_sln
752  integer(I4B), intent(in), dimension(:) :: idxglo
753  real(DP), intent(inout), dimension(:) :: rhs
754  real(DP), intent(inout), dimension(:) :: hnew
755  ! -- local
756  integer(I4B) :: nodes, nja
757  integer(I4B) :: iform
758  !
759  ! -- add newton terms to solution matrix
760  nodes = this%dis%nodes
761  nja = this%dis%con%nja
762  if (this%ixt3d /= 0) then
763  call this%xt3d%xt3d_fn(kiter, nodes, nja, matrix_sln, idxglo, rhs, hnew)
764  else
765  ! Each active formulation runs over all connections and adds its
766  ! newton terms; the default conductance formulation is always active.
767  call this%default_form%fn(kiter, matrix_sln, idxglo, rhs, hnew)
768  do iform = 1, max_ext_flow_forms
769  if (associated(this%flow_formulations(iform)%form)) then
770  call this%flow_formulations(iform)%form%fn(kiter, matrix_sln, &
771  idxglo, rhs, hnew)
772  end if
773  end do
774  end if
775  end subroutine npf_fn
776 
777  !> @brief Fill newton terms for the default conductance formulation
778  !!
779  !! Runs over all connections and fills the standard NPF newton terms,
780  !! skipping faces claimed by an exclusive formulation.
781  !<
782  subroutine default_flow_fn(this, kiter, matrix_sln, idxglo, rhs, hnew)
783  class(defaultflowformulationtype), intent(inout) :: this !< default formulation
784  integer(I4B), intent(in) :: kiter !< outer iteration number
785  class(matrixbasetype), pointer, intent(inout) :: matrix_sln !< system matrix
786  integer(I4B), dimension(:), intent(in) :: idxglo !< local to global connection map
787  real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector
788  real(DP), dimension(:), intent(inout) :: hnew !< new head values
789  ! local
790  integer(I4B) :: n, m, ipos
791 
792  do n = 1, this%npf%dis%nodes
793  do ipos = this%npf%dis%con%ia(n) + 1, this%npf%dis%con%ia(n + 1) - 1
794  if (this%npf%dis%con%mask(ipos) == 0) cycle
795 
796  m = this%npf%dis%con%ja(ipos)
797 
798  ! work on upper triangle
799  if (m < n) cycle
800 
801  ! skip faces claimed by an exclusive formulation
802  if (this%npf%iformulation(ipos) /= default_flow) cycle
803 
804  call this%npf%fn_default_flow(n, m, ipos, matrix_sln, &
805  rhs, idxglo, hnew)
806  end do
807  end do
808 
809  end subroutine default_flow_fn
810 
811  subroutine fn_default_flow(this, n, m, ipos, matrix_sln, rhs, idxglo, hnew)
812  class(gwfnpftype) :: this
813  integer(I4B) :: n
814  integer(I4B) :: m
815  integer(I4B) :: ipos
816  class(matrixbasetype), pointer :: matrix_sln
817  real(DP), intent(inout), dimension(:) :: rhs
818  integer(I4B), intent(in), dimension(:) :: idxglo
819  real(DP), intent(inout), dimension(:) :: hnew
820  ! local
821  integer(I4B) :: isymcon
822  integer(I4B) :: idiag, idiagm
823  integer(I4B) :: iups
824  integer(I4B) :: idn
825  real(DP) :: cond
826  real(DP) :: consterm
827  real(DP) :: filledterm
828  real(DP) :: derv
829  real(DP) :: hds
830  real(DP) :: term
831  real(DP) :: topup
832  real(DP) :: botup
833 
834  idiag = this%dis%con%ia(n)
835  isymcon = this%dis%con%isym(ipos)
836 
837  if (this%dis%con%ihc(this%dis%con%jas(ipos)) == 0 .and. &
838  this%ivarcv == 0) then
839  return
840  end if
841 
842  ! determine upstream node
843  iups = m
844  if (hnew(m) < hnew(n)) iups = n
845  idn = n
846  if (iups == n) idn = m
847  !
848  ! -- no newton terms if upstream cell is confined
849  if (this%icelltype(iups) == 0) return
850  !
851  ! -- Set the upstream top and bot, and then recalculate for a
852  ! vertically staggered horizontal connection
853  topup = this%dis%top(iups)
854  botup = this%dis%bot(iups)
855  if (this%dis%con%ihc(this%dis%con%jas(ipos)) == 2) then
856  topup = min(this%dis%top(n), this%dis%top(m))
857  botup = max(this%dis%bot(n), this%dis%bot(m))
858  end if
859  !
860  ! get saturated conductivity for derivative
861  cond = this%condsat(this%dis%con%jas(ipos))
862  !
863  ! compute additional term
864  consterm = -cond * (hnew(iups) - hnew(idn)) !needs to use hwadi instead of hnew(idn)
865  !filledterm = cond
866  filledterm = matrix_sln%get_value_pos(idxglo(ipos))
867  derv = squadraticsaturationderivative(topup, botup, hnew(iups), &
868  this%satomega)
869  idiagm = this%dis%con%ia(m)
870  ! fill jacobian for n being the upstream node
871  if (iups == n) then
872  hds = hnew(m)
873  !isymcon = this%dis%con%isym(ii)
874  term = consterm * derv
875  rhs(n) = rhs(n) + term * hnew(n) !+ amat(idxglo(isymcon)) * (dwadi * hds - hds) !need to add dwadi
876  rhs(m) = rhs(m) - term * hnew(n) !- amat(idxglo(isymcon)) * (dwadi * hds - hds) !need to add dwadi
877  ! fill in row of n
878  call matrix_sln%add_value_pos(idxglo(idiag), term)
879  ! fill newton term in off diagonal if active cell
880  if (this%ibound(n) > 0) then
881  filledterm = matrix_sln%get_value_pos(idxglo(ipos))
882  call matrix_sln%set_value_pos(idxglo(ipos), filledterm) !* dwadi !need to add dwadi
883  end if
884  !fill row of m
885  filledterm = matrix_sln%get_value_pos(idxglo(idiagm))
886  call matrix_sln%set_value_pos(idxglo(idiagm), filledterm) !- filledterm * (dwadi - DONE) !need to add dwadi
887  ! fill newton term in off diagonal if active cell
888  if (this%ibound(m) > 0) then
889  call matrix_sln%add_value_pos(idxglo(isymcon), -term)
890  end if
891  ! fill jacobian for m being the upstream node
892  else
893  hds = hnew(n)
894  term = -consterm * derv
895  rhs(n) = rhs(n) + term * hnew(m) !+ amat(idxglo(ii)) * (dwadi * hds - hds) !need to add dwadi
896  rhs(m) = rhs(m) - term * hnew(m) !- amat(idxglo(ii)) * (dwadi * hds - hds) !need to add dwadi
897  ! fill in row of n
898  filledterm = matrix_sln%get_value_pos(idxglo(idiag))
899  call matrix_sln%set_value_pos(idxglo(idiag), filledterm) !- filledterm * (dwadi - DONE) !need to add dwadi
900  ! fill newton term in off diagonal if active cell
901  if (this%ibound(n) > 0) then
902  call matrix_sln%add_value_pos(idxglo(ipos), term)
903  end if
904  !fill row of m
905  call matrix_sln%add_value_pos(idxglo(idiagm), -term)
906  ! fill newton term in off diagonal if active cell
907  if (this%ibound(m) > 0) then
908  filledterm = matrix_sln%get_value_pos(idxglo(isymcon))
909  call matrix_sln%set_value_pos(idxglo(isymcon), filledterm) !* dwadi !need to add dwadi
910  end if
911  end if
912 
913  end subroutine fn_default_flow
914 
915  !> @brief Under-relaxation
916  !!
917  !! Under-relaxation of Groundwater Flow Model Heads for current outer
918  !! iteration using the cell bottoms at the bottom of the model
919  !<
920  subroutine npf_nur(this, neqmod, x, xtemp, dx, inewtonur, dxmax, locmax)
921  ! -- dummy
922  class(gwfnpftype) :: this
923  integer(I4B), intent(in) :: neqmod
924  real(DP), dimension(neqmod), intent(inout) :: x
925  real(DP), dimension(neqmod), intent(in) :: xtemp
926  real(DP), dimension(neqmod), intent(inout) :: dx
927  integer(I4B), intent(inout) :: inewtonur
928  real(DP), intent(inout) :: dxmax
929  integer(I4B), intent(inout) :: locmax
930  ! -- local
931  integer(I4B) :: n
932  integer(I4B) :: ibot
933  real(DP) :: botm
934  real(DP) :: xx
935  real(DP) :: dxx
936  !
937  ! -- Newton-Raphson under-relaxation
938  do n = 1, this%dis%nodes
939  if (this%ibound(n) < 1) cycle
940  ibot = this%ibotnode(n)
941  ! Newton-Raphson under-relaxation is only applied to convertible cells where
942  ! the bottom cell in a stack is convertible
943  if (this%icelltype(n) > 0 .and. this%icelltype(ibot) > 0) then
944  botm = this%dis%bot(ibot)
945  ! Newton-Raphson under-relaxation applied when solution head is
946  ! below the bottom of the model
947  if (x(n) < botm) then
948  inewtonur = 1
949  xx = xtemp(n) * (done - dp9) + botm * dp9
950  dxx = xx - xtemp(n)
951  if (abs(dxx) > abs(dxmax)) then
952  locmax = n
953  dxmax = dxx
954  end if
955  x(n) = xx
956  dx(n) = xtemp(n) - x(n)
957  end if
958  end if
959  end do
960  end subroutine npf_nur
961 
962  !> @brief Calculate flowja
963  !<
964  subroutine npf_cq(this, hnew, flowja)
965  ! -- dummy
966  class(gwfnpftype) :: this
967  real(DP), intent(inout), dimension(:) :: hnew
968  real(DP), intent(inout), dimension(:) :: flowja
969  ! -- local
970  integer(I4B) :: iform
971  !
972  ! -- Calculate the flow across each cell face and store in flowja
973  !
974  if (this%ixt3d /= 0) then
975  call this%xt3d%xt3d_flowja(hnew, flowja)
976  else
977  ! Each active formulation runs over all connections and adds its
978  ! flows; the default conductance formulation is always active.
979  call this%default_form%cq(hnew, flowja)
980  do iform = 1, max_ext_flow_forms
981  if (associated(this%flow_formulations(iform)%form)) then
982  call this%flow_formulations(iform)%form%cq(hnew, flowja)
983  end if
984  end do
985  end if
986  end subroutine npf_cq
987 
988  !> @brief Calculate flows for the default conductance formulation
989  !!
990  !! Runs over all connections and stores the standard NPF face flows,
991  !! skipping faces claimed by an exclusive formulation.
992  !<
993  subroutine default_flow_cq(this, hnew, flowja)
994  class(defaultflowformulationtype), intent(inout) :: this !< default formulation
995  real(DP), dimension(:), intent(inout) :: hnew !< new head values
996  real(DP), dimension(:), intent(inout) :: flowja !< flow between cells
997  ! local
998  integer(I4B) :: n, m, ipos
999 
1000  do n = 1, this%npf%dis%nodes
1001  do ipos = this%npf%dis%con%ia(n) + 1, this%npf%dis%con%ia(n + 1) - 1
1002  m = this%npf%dis%con%ja(ipos)
1003  if (m < n) cycle
1004  !TODO_MJR: why don't we exclude masked connections here?
1005 
1006  ! skip faces claimed by an exclusive formulation
1007  if (this%npf%iformulation(ipos) /= default_flow) cycle
1008 
1009  call this%npf%cq_default_flow(n, m, ipos, flowja, hnew)
1010  end do
1011  end do
1012 
1013  end subroutine default_flow_cq
1014 
1015  subroutine cq_default_flow(this, n, m, ipos, flowja, hnew)
1016  class(gwfnpftype) :: this
1017  integer(I4B), intent(in) :: n
1018  integer(I4B), intent(in) :: m
1019  integer(I4B), intent(in) :: ipos
1020  real(DP), dimension(:), intent(inout) :: flowja
1021  real(DP), dimension(:), intent(in) :: hnew
1022  ! local
1023  real(DP) :: qnm
1024 
1025  call this%qcalc(n, m, hnew(n), hnew(m), ipos, qnm)
1026  flowja(ipos) = qnm
1027  flowja(this%dis%con%isym(ipos)) = -qnm
1028 
1029  end subroutine cq_default_flow
1030 
1031  !> @brief Fractional cell saturation
1032  !<
1033  subroutine sgwf_npf_thksat(this, n, hn, thksat)
1034  ! -- dummy
1035  class(gwfnpftype) :: this
1036  integer(I4B), intent(in) :: n
1037  real(DP), intent(in) :: hn
1038  real(DP), intent(inout) :: thksat
1039  !
1040  ! -- Standard Formulation
1041  if (hn >= this%dis%top(n)) then
1042  thksat = done
1043  else
1044  thksat = (hn - this%dis%bot(n)) / (this%dis%top(n) - this%dis%bot(n))
1045  end if
1046  !
1047  ! -- Newton-Raphson Formulation
1048  if (this%inewton /= 0) then
1049  thksat = squadraticsaturation(this%dis%top(n), this%dis%bot(n), hn, &
1050  this%satomega)
1051  end if
1052  end subroutine sgwf_npf_thksat
1053 
1054  !> @brief Flow between two cells
1055  !<
1056  subroutine sgwf_npf_qcalc(this, n, m, hn, hm, icon, qnm)
1057  ! -- dummy
1058  class(gwfnpftype) :: this
1059  integer(I4B), intent(in) :: n
1060  integer(I4B), intent(in) :: m
1061  real(DP), intent(in) :: hn
1062  real(DP), intent(in) :: hm
1063  integer(I4B), intent(in) :: icon
1064  real(DP), intent(inout) :: qnm
1065  ! -- local
1066  real(DP) :: hyn, hym
1067  real(DP) :: condnm
1068  real(DP) :: hntemp, hmtemp
1069  real(DP) :: satn, satm
1070  integer(I4B) :: ihc
1071  !
1072  ! -- Initialize
1073  ihc = this%dis%con%ihc(this%dis%con%jas(icon))
1074  hyn = this%hy_eff(n, m, ihc, ipos=icon)
1075  hym = this%hy_eff(m, n, ihc, ipos=icon)
1076  !
1077  ! -- Calculate conductance
1078  if (ihc == c3d_vertical) then
1079  condnm = vcond(this%ibound(n), this%ibound(m), &
1080  this%icelltype(n), this%icelltype(m), this%inewton, &
1081  this%ivarcv, this%idewatcv, &
1082  this%condsat(this%dis%con%jas(icon)), hn, hm, &
1083  hyn, hym, &
1084  this%sat(n), this%sat(m), &
1085  this%dis%top(n), this%dis%top(m), &
1086  this%dis%bot(n), this%dis%bot(m), &
1087  this%dis%con%hwva(this%dis%con%jas(icon)))
1088  else
1089  satn = this%sat(n)
1090  satm = this%sat(m)
1091  if (this%ihighcellsat /= 0) then
1092  call this%highest_cell_saturation(n, m, hn, hm, satn, satm)
1093  end if
1094 
1095  condnm = hcond(this%ibound(n), this%ibound(m), &
1096  this%icelltype(n), this%icelltype(m), &
1097  this%inewton, &
1098  this%dis%con%ihc(this%dis%con%jas(icon)), &
1099  this%icellavg, &
1100  this%condsat(this%dis%con%jas(icon)), &
1101  hn, hm, satn, satm, hyn, hym, &
1102  this%dis%top(n), this%dis%top(m), &
1103  this%dis%bot(n), this%dis%bot(m), &
1104  this%dis%con%cl1(this%dis%con%jas(icon)), &
1105  this%dis%con%cl2(this%dis%con%jas(icon)), &
1106  this%dis%con%hwva(this%dis%con%jas(icon)))
1107  end if
1108  !
1109  ! -- Initialize hntemp and hmtemp
1110  hntemp = hn
1111  hmtemp = hm
1112  !
1113  ! -- Check and adjust for dewatered conditions
1114  if (this%iperched /= 0) then
1115  if (this%dis%con%ihc(this%dis%con%jas(icon)) == 0) then
1116  if (n > m) then
1117  if (this%icelltype(n) /= 0) then
1118  if (hn < this%dis%top(n)) hntemp = this%dis%bot(m)
1119  end if
1120  else
1121  if (this%icelltype(m) /= 0) then
1122  if (hm < this%dis%top(m)) hmtemp = this%dis%bot(n)
1123  end if
1124  end if
1125  end if
1126  end if
1127  !
1128  ! -- Calculate flow positive into cell n
1129  qnm = condnm * (hmtemp - hntemp)
1130  end subroutine sgwf_npf_qcalc
1131 
1132  !> @brief Record flowja and calculate specific discharge if requested
1133  !<
1134  subroutine npf_save_model_flows(this, flowja, icbcfl, icbcun)
1135  ! -- dummy
1136  class(gwfnpftype) :: this
1137  real(DP), dimension(:), intent(in) :: flowja
1138  integer(I4B), intent(in) :: icbcfl
1139  integer(I4B), intent(in) :: icbcun
1140  ! -- local
1141  integer(I4B) :: ibinun
1142  !
1143  ! -- Set unit number for binary output
1144  if (this%ipakcb < 0) then
1145  ibinun = icbcun
1146  elseif (this%ipakcb == 0) then
1147  ibinun = 0
1148  else
1149  ibinun = this%ipakcb
1150  end if
1151  if (icbcfl == 0) ibinun = 0
1152  !
1153  ! -- Write the face flows if requested
1154  if (ibinun /= 0) then
1155  call this%dis%record_connection_array(flowja, ibinun, this%iout)
1156  end if
1157  !
1158  ! -- Calculate specific discharge at cell centers and write, if requested
1159  if (this%isavspdis /= 0) then
1160  if (ibinun /= 0) call this%sav_spdis(ibinun)
1161  end if
1162  !
1163  ! -- Save saturation, if requested
1164  if (this%isavsat /= 0) then
1165  if (ibinun /= 0) call this%sav_sat(ibinun)
1166  end if
1167  end subroutine npf_save_model_flows
1168 
1169  !> @brief Print budget
1170  !<
1171  subroutine npf_print_model_flows(this, ibudfl, flowja)
1172  ! -- modules
1173  use tdismodule, only: kper, kstp
1174  use constantsmodule, only: lenbigline
1175  ! -- dummy
1176  class(gwfnpftype) :: this
1177  integer(I4B), intent(in) :: ibudfl
1178  real(DP), intent(inout), dimension(:) :: flowja
1179  ! -- local
1180  character(len=LENBIGLINE) :: line
1181  character(len=30) :: tempstr
1182  integer(I4B) :: n, ipos, m
1183  real(DP) :: qnm
1184  ! -- formats
1185  character(len=*), parameter :: fmtiprflow = &
1186  &"(/,4x,'CALCULATED INTERCELL FLOW FOR PERIOD ', i0, ' STEP ', i0)"
1187  !
1188  ! -- Write flowja to list file if requested
1189  if (ibudfl /= 0 .and. this%iprflow > 0) then
1190  write (this%iout, fmtiprflow) kper, kstp
1191  do n = 1, this%dis%nodes
1192  line = ''
1193  call this%dis%noder_to_string(n, tempstr)
1194  line = trim(tempstr)//':'
1195  do ipos = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1
1196  m = this%dis%con%ja(ipos)
1197  call this%dis%noder_to_string(m, tempstr)
1198  line = trim(line)//' '//trim(tempstr)
1199  qnm = flowja(ipos)
1200  write (tempstr, '(1pg15.6)') qnm
1201  line = trim(line)//' '//trim(adjustl(tempstr))
1202  end do
1203  write (this%iout, '(a)') trim(line)
1204  end do
1205  end if
1206  end subroutine npf_print_model_flows
1207 
1208  !> @brief Deallocate variables
1209  !<
1210  subroutine npf_da(this)
1211  ! -- modules
1213  use simvariablesmodule, only: idm_context
1214  ! -- dummy
1215  class(gwfnpftype) :: this
1216 
1217  ! free spdis work structure
1218  if (this%icalcspdis == 1 .and. this%spdis_wa%is_created()) &
1219  call this%spdis_wa%destroy()
1220  deallocate (this%spdis_wa)
1221  !
1222  ! -- Deallocate input memory
1223  call memorystore_remove(this%name_model, 'NPF', idm_context)
1224  !
1225  ! -- TVK
1226  if (this%intvk /= 0) then
1227  call this%tvk%da()
1228  deallocate (this%tvk)
1229  end if
1230  !
1231  ! -- VSC
1232  if (this%invsc /= 0) then
1233  nullify (this%vsc)
1234  end if
1235  !
1236  ! -- Scalars
1237  call mem_deallocate(this%iname)
1238  call mem_deallocate(this%ixt3d)
1239  call mem_deallocate(this%ixt3drhs)
1240  call mem_deallocate(this%satomega)
1241  call mem_deallocate(this%hnoflo)
1242  call mem_deallocate(this%hdry)
1243  call mem_deallocate(this%icellavg)
1244  call mem_deallocate(this%iavgkeff)
1245  call mem_deallocate(this%ik22)
1246  call mem_deallocate(this%ik33)
1247  call mem_deallocate(this%iperched)
1248  call mem_deallocate(this%ivarcv)
1249  call mem_deallocate(this%idewatcv)
1250  call mem_deallocate(this%ithickstrt)
1251  call mem_deallocate(this%ihighcellsat)
1252  call mem_deallocate(this%isavspdis)
1253  call mem_deallocate(this%isavsat)
1254  call mem_deallocate(this%icalcspdis)
1255  call mem_deallocate(this%irewet)
1256  call mem_deallocate(this%wetfct)
1257  call mem_deallocate(this%iwetit)
1258  call mem_deallocate(this%ihdwet)
1259  call mem_deallocate(this%ibotnode)
1260  call mem_deallocate(this%iwetdry)
1261  call mem_deallocate(this%iangle1)
1262  call mem_deallocate(this%iangle2)
1263  call mem_deallocate(this%iangle3)
1264  call mem_deallocate(this%nedges)
1265  call mem_deallocate(this%lastedge)
1266  call mem_deallocate(this%ik22overk)
1267  call mem_deallocate(this%ik33overk)
1268  call mem_deallocate(this%intvk)
1269  call mem_deallocate(this%invsc)
1270  call mem_deallocate(this%kchangeper)
1271  call mem_deallocate(this%kchangestp)
1272  !
1273  ! -- Deallocate arrays
1274  deallocate (this%aname)
1275  call mem_deallocate(this%ithickstartflag)
1276  call mem_deallocate(this%icelltype)
1277  call mem_deallocate(this%k11)
1278  call mem_deallocate(this%k22)
1279  call mem_deallocate(this%k33)
1280  call mem_deallocate(this%krel)
1281  call mem_deallocate(this%k11input)
1282  call mem_deallocate(this%k22input)
1283  call mem_deallocate(this%k33input)
1284  call mem_deallocate(this%sat, 'SAT', this%memoryPath)
1285  call mem_deallocate(this%condsat)
1286  call mem_deallocate(this%wetdry)
1287  call mem_deallocate(this%angle1)
1288  call mem_deallocate(this%angle2)
1289  call mem_deallocate(this%angle3)
1290  call mem_deallocate(this%nodedge)
1291  call mem_deallocate(this%ihcedge)
1292  call mem_deallocate(this%propsedge)
1293  call mem_deallocate(this%iedge_ptr)
1294  call mem_deallocate(this%edge_idxs)
1295  call mem_deallocate(this%spdis, 'SPDIS', this%memoryPath)
1296  call mem_deallocate(this%nodekchange)
1297  call mem_deallocate(this%iformulation)
1298  !
1299  ! -- deallocate the default conductance formulation
1300  if (associated(this%default_form)) then
1301  deallocate (this%default_form)
1302  this%default_form => null()
1303  end if
1304  !
1305  ! -- deallocate parent
1306  call this%NumericalPackageType%da()
1307 
1308  ! pointers
1309  this%hnew => null()
1310 
1311  end subroutine npf_da
1312 
1313  !> @ brief Allocate scalars
1314  !!
1315  !! Allocate and initialize scalars for the VSC package. The base model
1316  !! allocate scalars method is also called.
1317  !<
1318  subroutine allocate_scalars(this)
1319  ! -- modules
1321  ! -- dummy
1322  class(gwfnpftype) :: this
1323  !
1324  ! -- allocate scalars in NumericalPackageType
1325  call this%NumericalPackageType%allocate_scalars()
1326  !
1327  ! -- Allocate scalars
1328  call mem_allocate(this%iname, 'INAME', this%memoryPath)
1329  call mem_allocate(this%ixt3d, 'IXT3D', this%memoryPath)
1330  call mem_allocate(this%ixt3drhs, 'IXT3DRHS', this%memoryPath)
1331  call mem_allocate(this%satomega, 'SATOMEGA', this%memoryPath)
1332  call mem_allocate(this%hnoflo, 'HNOFLO', this%memoryPath)
1333  call mem_allocate(this%hdry, 'HDRY', this%memoryPath)
1334  call mem_allocate(this%icellavg, 'ICELLAVG', this%memoryPath)
1335  call mem_allocate(this%iavgkeff, 'IAVGKEFF', this%memoryPath)
1336  call mem_allocate(this%ik22, 'IK22', this%memoryPath)
1337  call mem_allocate(this%ik33, 'IK33', this%memoryPath)
1338  call mem_allocate(this%ik22overk, 'IK22OVERK', this%memoryPath)
1339  call mem_allocate(this%ik33overk, 'IK33OVERK', this%memoryPath)
1340  call mem_allocate(this%iperched, 'IPERCHED', this%memoryPath)
1341  call mem_allocate(this%ivarcv, 'IVARCV', this%memoryPath)
1342  call mem_allocate(this%idewatcv, 'IDEWATCV', this%memoryPath)
1343  call mem_allocate(this%ithickstrt, 'ITHICKSTRT', this%memoryPath)
1344  call mem_allocate(this%ihighcellsat, 'IHIGHCELLSAT', this%memoryPath)
1345  call mem_allocate(this%icalcspdis, 'ICALCSPDIS', this%memoryPath)
1346  call mem_allocate(this%isavspdis, 'ISAVSPDIS', this%memoryPath)
1347  call mem_allocate(this%isavsat, 'ISAVSAT', this%memoryPath)
1348  call mem_allocate(this%irewet, 'IREWET', this%memoryPath)
1349  call mem_allocate(this%wetfct, 'WETFCT', this%memoryPath)
1350  call mem_allocate(this%iwetit, 'IWETIT', this%memoryPath)
1351  call mem_allocate(this%ihdwet, 'IHDWET', this%memoryPath)
1352  call mem_allocate(this%iangle1, 'IANGLE1', this%memoryPath)
1353  call mem_allocate(this%iangle2, 'IANGLE2', this%memoryPath)
1354  call mem_allocate(this%iangle3, 'IANGLE3', this%memoryPath)
1355  call mem_allocate(this%iwetdry, 'IWETDRY', this%memoryPath)
1356  call mem_allocate(this%nedges, 'NEDGES', this%memoryPath)
1357  call mem_allocate(this%lastedge, 'LASTEDGE', this%memoryPath)
1358  call mem_allocate(this%intvk, 'INTVK', this%memoryPath)
1359  call mem_allocate(this%invsc, 'INVSC', this%memoryPath)
1360  call mem_allocate(this%kchangeper, 'KCHANGEPER', this%memoryPath)
1361  call mem_allocate(this%kchangestp, 'KCHANGESTP', this%memoryPath)
1362  !
1363  ! -- set pointer to inewtonur
1364  call mem_setptr(this%igwfnewtonur, 'INEWTONUR', &
1365  create_mem_path(this%name_model))
1366  !
1367  ! -- Initialize value
1368  this%iname = 8
1369  this%ixt3d = 0
1370  this%ixt3drhs = 0
1371  this%satomega = dzero
1372  this%hnoflo = dhnoflo !1.d30
1373  this%hdry = dhdry !-1.d30
1374  this%icellavg = ccond_hmean
1375  this%iavgkeff = 0
1376  this%ik22 = 0
1377  this%ik33 = 0
1378  this%ik22overk = 0
1379  this%ik33overk = 0
1380  this%iperched = 0
1381  this%ivarcv = 0
1382  this%idewatcv = 0
1383  this%ithickstrt = 0
1384  this%ihighcellsat = 0
1385  this%icalcspdis = 0
1386  this%isavspdis = 0
1387  this%isavsat = 0
1388  this%irewet = 0
1389  this%wetfct = done
1390  this%iwetit = 1
1391  this%ihdwet = 0
1392  this%iangle1 = 0
1393  this%iangle2 = 0
1394  this%iangle3 = 0
1395  this%iwetdry = 0
1396  this%nedges = 0
1397  this%lastedge = 0
1398  this%intvk = 0
1399  this%invsc = 0
1400  this%kchangeper = 0
1401  this%kchangestp = 0
1402  !
1403  ! -- If newton is on, then NPF creates asymmetric matrix
1404  this%iasym = this%inewton
1405  end subroutine allocate_scalars
1406 
1407  !> @ brief Store backup copy of hydraulic conductivity when the VSC
1408  !! package is activate
1409  !!
1410  !! The K arrays (K11, etc.) get multiplied by the viscosity ratio so that
1411  !! subsequent uses of K already take into account the effect of viscosity.
1412  !! Thus the original user-specified K array values are lost unless they are
1413  !! backed up in k11input, for example. In a new stress period/time step,
1414  !! the values in k11input are multiplied by the viscosity ratio, not k11
1415  !! since it contains viscosity-adjusted hydraulic conductivity values.
1416  !<
1417  subroutine store_original_k_arrays(this, ncells, njas)
1418  ! -- modules
1420  ! -- dummy
1421  class(gwfnpftype) :: this
1422  integer(I4B), intent(in) :: ncells
1423  integer(I4B), intent(in) :: njas
1424  ! -- local
1425  integer(I4B) :: n
1426  !
1427  ! -- Retain copy of user-specified K arrays
1428  do n = 1, ncells
1429  this%k11input(n) = this%k11(n)
1430  this%k22input(n) = this%k22(n)
1431  this%k33input(n) = this%k33(n)
1432  end do
1433  end subroutine store_original_k_arrays
1434 
1435  !> @brief Allocate npf arrays
1436  !<
1437  subroutine allocate_arrays(this, ncells, njas)
1438  ! -- dummy
1439  class(gwfnpftype), target :: this
1440  integer(I4B), intent(in) :: ncells
1441  integer(I4B), intent(in) :: njas
1442  ! -- local
1443  integer(I4B) :: n
1444  !
1445  call mem_allocate(this%ithickstartflag, ncells, 'ITHICKSTARTFLAG', &
1446  this%memoryPath)
1447  call mem_allocate(this%icelltype, ncells, 'ICELLTYPE', this%memoryPath)
1448  call mem_allocate(this%k11, ncells, 'K11', this%memoryPath)
1449  call mem_allocate(this%krel, ncells, 'KREL', this%memoryPath)
1450  call mem_allocate(this%sat, ncells, 'SAT', this%memoryPath)
1451  call mem_allocate(this%condsat, njas, 'CONDSAT', this%memoryPath)
1452  !
1453  ! -- Optional arrays dimensioned to full size initially
1454  call mem_allocate(this%k22, ncells, 'K22', this%memoryPath)
1455  call mem_allocate(this%k33, ncells, 'K33', this%memoryPath)
1456  call mem_allocate(this%wetdry, ncells, 'WETDRY', this%memoryPath)
1457  call mem_allocate(this%angle1, ncells, 'ANGLE1', this%memoryPath)
1458  call mem_allocate(this%angle2, ncells, 'ANGLE2', this%memoryPath)
1459  call mem_allocate(this%angle3, ncells, 'ANGLE3', this%memoryPath)
1460  !
1461  ! -- Optional arrays
1462  call mem_allocate(this%ibotnode, 0, 'IBOTNODE', this%memoryPath)
1463  call mem_allocate(this%nodedge, 0, 'NODEDGE', this%memoryPath)
1464  call mem_allocate(this%ihcedge, 0, 'IHCEDGE', this%memoryPath)
1465  call mem_allocate(this%propsedge, 0, 0, 'PROPSEDGE', this%memoryPath)
1466  call mem_allocate(this%iedge_ptr, 0, 'NREDGESNODE', this%memoryPath)
1467  call mem_allocate(this%edge_idxs, 0, 'EDGEIDXS', this%memoryPath)
1468  !
1469  ! -- Optional arrays only needed when vsc package is active
1470  call mem_allocate(this%k11input, 0, 'K11INPUT', this%memoryPath)
1471  call mem_allocate(this%k22input, 0, 'K22INPUT', this%memoryPath)
1472  call mem_allocate(this%k33input, 0, 'K33INPUT', this%memoryPath)
1473  !
1474  ! -- Specific discharge is (re-)allocated when nedges is known
1475  call mem_allocate(this%spdis, 3, 0, 'SPDIS', this%memoryPath)
1476  !
1477  ! -- Time-varying property flag arrays
1478  call mem_allocate(this%nodekchange, ncells, 'NODEKCHANGE', this%memoryPath)
1479  !
1480  call mem_allocate(this%iformulation, this%dis%con%nja, 'IFORM', &
1481  this%memoryPath)
1482  !
1483  ! -- set to standard NPF flow
1484  do n = 1, size(this%iformulation)
1485  this%iformulation(n) = default_flow
1486  end do
1487  !
1488  ! -- create the default conductance formulation and point it at this package
1489  allocate (defaultflowformulationtype :: this%default_form)
1490  select type (form => this%default_form)
1491  type is (defaultflowformulationtype)
1492  form%npf => this
1493  end select
1494  !
1495  ! -- initialize iangle1, iangle2, iangle3, and wetdry
1496  do n = 1, ncells
1497  this%angle1(n) = dzero
1498  this%angle2(n) = dzero
1499  this%angle3(n) = dzero
1500  this%wetdry(n) = dzero
1501  this%nodekchange(n) = dzero
1502  this%krel(n) = done
1503  end do
1504  !
1505  ! -- allocate variable names
1506  allocate (this%aname(this%iname))
1507  this%aname = [' ICELLTYPE', ' K', &
1508  ' K33', ' K22', &
1509  ' WETDRY', ' ANGLE1', &
1510  ' ANGLE2', ' ANGLE3']
1511  end subroutine allocate_arrays
1512 
1513  !> @brief Log npf options sourced from the input mempath
1514  !<
1515  subroutine log_options(this, found)
1516  ! -- modules
1517  use kindmodule, only: lgp
1519  ! -- dummy
1520  class(gwfnpftype) :: this
1521  ! -- locals
1522  type(gwfnpfparamfoundtype), intent(in) :: found
1523  !
1524  write (this%iout, '(1x,a)') 'Setting NPF Options'
1525  if (found%iprflow) &
1526  write (this%iout, '(4x,a)') 'Cell-by-cell flow information will be printed &
1527  &to listing file whenever ICBCFL is not zero.'
1528  if (found%ipakcb) &
1529  write (this%iout, '(4x,a)') 'Cell-by-cell flow information will be saved &
1530  &to binary file whenever ICBCFL is not zero.'
1531  if (found%cellavg) &
1532  write (this%iout, '(4x,a,i0)') 'Alternative cell averaging [1=logarithmic, &
1533  &2=AMT-LMK, 3=AMT-HMK] set to: ', &
1534  this%icellavg
1535  if (found%ithickstrt) &
1536  write (this%iout, '(4x,a)') 'THICKSTRT option has been activated.'
1537  if (found%ihighcellsat) &
1538  write (this%iout, '(4x,a)') 'HIGHEST_CELL_SATURATION option &
1539  &has been activated.'
1540  if (found%iperched) &
1541  write (this%iout, '(4x,a)') 'Vertical flow will be adjusted for perched &
1542  &conditions.'
1543  if (found%ivarcv) &
1544  write (this%iout, '(4x,a)') 'Vertical conductance varies with water table.'
1545  if (found%idewatcv) &
1546  write (this%iout, '(4x,a)') 'Vertical conductance is calculated using &
1547  &only the saturated thickness and properties &
1548  &of the overlying cell if the head in the &
1549  &underlying cell is below its top.'
1550  if (found%ixt3d) write (this%iout, '(4x,a)') 'XT3D formulation is selected.'
1551  if (found%ixt3drhs) &
1552  write (this%iout, '(4x,a)') 'XT3D RHS formulation is selected.'
1553  if (found%isavspdis) &
1554  write (this%iout, '(4x,a)') 'Specific discharge will be calculated at cell &
1555  &centers and written to DATA-SPDIS in budget &
1556  &file when requested.'
1557  if (found%isavsat) &
1558  write (this%iout, '(4x,a)') 'Saturation will be written to DATA-SAT in &
1559  &budget file when requested.'
1560  if (found%ik22overk) &
1561  write (this%iout, '(4x,a)') 'Values specified for K22 are anisotropy &
1562  &ratios and will be multiplied by K before &
1563  &being used in calculations.'
1564  if (found%ik33overk) &
1565  write (this%iout, '(4x,a)') 'Values specified for K33 are anisotropy &
1566  &ratios and will be multiplied by K before &
1567  &being used in calculations.'
1568  if (found%inewton) &
1569  write (this%iout, '(4x,a)') 'NEWTON-RAPHSON method disabled for unconfined &
1570  &cells'
1571  if (found%satomega) &
1572  write (this%iout, '(4x,a,1pg15.6)') 'Saturation omega: ', this%satomega
1573  if (found%irewet) &
1574  write (this%iout, '(4x,a)') 'Rewetting is active.'
1575  if (found%wetfct) &
1576  write (this%iout, '(4x,a,1pg15.6)') &
1577  'Wetting factor (WETFCT) has been set to: ', this%wetfct
1578  if (found%iwetit) &
1579  write (this%iout, '(4x,a,i5)') &
1580  'Wetting iteration interval (IWETIT) has been set to: ', this%iwetit
1581  if (found%ihdwet) &
1582  write (this%iout, '(4x,a,i5)') &
1583  'Head rewet equation (IHDWET) has been set to: ', this%ihdwet
1584  write (this%iout, '(1x,a,/)') 'End Setting NPF Options'
1585  end subroutine log_options
1586 
1587  !> @brief Update simulation options from input mempath
1588  !<
1589  subroutine source_options(this)
1590  ! -- modules
1595  use sourcecommonmodule, only: filein_fname
1597  ! -- dummy
1598  class(gwfnpftype) :: this
1599  ! -- locals
1600  character(len=LENVARNAME), dimension(3) :: cellavg_method = &
1601  &[character(len=LENVARNAME) :: 'LOGARITHMIC', 'AMT-LMK', 'AMT-HMK']
1602  type(gwfnpfparamfoundtype) :: found
1603  type(characterstringtype), dimension(:), pointer, contiguous :: tvk6_mempaths
1604  character(len=LINELENGTH) :: tvk6_filename
1605  character(len=LENMEMPATH) :: tvk6_mempath
1606  !
1607  ! -- update defaults with idm sourced values
1608  call mem_set_value(this%iprflow, 'IPRFLOW', this%input_mempath, found%iprflow)
1609  call mem_set_value(this%ipakcb, 'IPAKCB', this%input_mempath, found%ipakcb)
1610  call mem_set_value(this%icellavg, 'CELLAVG', this%input_mempath, &
1611  cellavg_method, found%cellavg)
1612  call mem_set_value(this%ithickstrt, 'ITHICKSTRT', this%input_mempath, &
1613  found%ithickstrt)
1614  call mem_set_value(this%ihighcellsat, 'IHIGHCELLSAT', this%input_mempath, &
1615  found%ihighcellsat)
1616  call mem_set_value(this%iperched, 'IPERCHED', this%input_mempath, &
1617  found%iperched)
1618  call mem_set_value(this%ivarcv, 'IVARCV', this%input_mempath, found%ivarcv)
1619  call mem_set_value(this%idewatcv, 'IDEWATCV', this%input_mempath, &
1620  found%idewatcv)
1621  call mem_set_value(this%ixt3d, 'IXT3D', this%input_mempath, found%ixt3d)
1622  call mem_set_value(this%ixt3drhs, 'IXT3DRHS', this%input_mempath, &
1623  found%ixt3drhs)
1624  call mem_set_value(this%isavspdis, 'ISAVSPDIS', this%input_mempath, &
1625  found%isavspdis)
1626  call mem_set_value(this%isavsat, 'ISAVSAT', this%input_mempath, found%isavsat)
1627  call mem_set_value(this%ik22overk, 'IK22OVERK', this%input_mempath, &
1628  found%ik22overk)
1629  call mem_set_value(this%ik33overk, 'IK33OVERK', this%input_mempath, &
1630  found%ik33overk)
1631  call mem_set_value(this%inewton, 'INEWTON', this%input_mempath, found%inewton)
1632  call mem_set_value(this%satomega, 'SATOMEGA', this%input_mempath, &
1633  found%satomega)
1634  call mem_set_value(this%irewet, 'IREWET', this%input_mempath, found%irewet)
1635  call mem_set_value(this%wetfct, 'WETFCT', this%input_mempath, found%wetfct)
1636  call mem_set_value(this%iwetit, 'IWETIT', this%input_mempath, found%iwetit)
1637  call mem_set_value(this%ihdwet, 'IHDWET', this%input_mempath, found%ihdwet)
1638  !
1639  ! -- save flows option active
1640  if (found%ipakcb) this%ipakcb = -1
1641  !
1642  ! -- xt3d active with rhs
1643  if (found%ixt3d .and. found%ixt3drhs) this%ixt3d = 2
1644  !
1645  ! -- save specific discharge active
1646  if (found%isavspdis) this%icalcspdis = this%isavspdis
1647  !
1648  ! -- no newton specified
1649  if (found%inewton) then
1650  this%inewton = 0
1651  this%iasym = 0
1652  end if
1653  !
1654  ! -- TVK6 subpackage
1655  if (filein_fname(tvk6_filename, 'TVK6_FILENAME', &
1656  this%input_mempath, this%input_fname)) then
1657  call mem_setptr(tvk6_mempaths, 'TVK6_MEMPATH', this%input_mempath)
1658  tvk6_mempath = tvk6_mempaths(1)
1659  this%intvk = 1 ! tvk active
1660  call tvk_cr(this%tvk, this%name_model, tvk6_mempath, this%intvk, this%iout)
1661  end if
1662  !
1663  ! -- verify ALTERNATIVE_CELL_AVERAGING input value is supported
1664  if (found%cellavg) then
1665  if (this%icellavg == 0) then
1666  errmsg = 'Unrecognized input value for ALTERNATIVE_CELL_AVERAGING option.'
1667  call store_error(errmsg)
1668  call store_error_filename(this%input_fname)
1669  end if
1670  end if
1671  !
1672  ! -- log options
1673  if (this%iout > 0) then
1674  call this%log_options(found)
1675  end if
1676  end subroutine source_options
1677 
1678  !> @brief Set options in the NPF object
1679  !<
1680  subroutine set_options(this, options)
1681  ! -- dummy
1682  class(gwfnpftype) :: this
1683  type(gwfnpfoptionstype), intent(in) :: options
1684  !
1685  this%ithickstrt = options%ithickstrt
1686  this%ihighcellsat = options%ihighcellsat
1687  this%iperched = options%iperched
1688  this%ivarcv = options%ivarcv
1689  this%idewatcv = options%idewatcv
1690  this%irewet = options%irewet
1691  this%wetfct = options%wetfct
1692  this%iwetit = options%iwetit
1693  this%ihdwet = options%ihdwet
1694  end subroutine set_options
1695 
1696  !> @brief Check for conflicting NPF options
1697  !<
1698  subroutine check_options(this)
1699  ! -- modules
1700  use simmodule, only: store_error, store_warning, &
1702  use constantsmodule, only: linelength
1703  ! -- dummy
1704  class(gwfnpftype) :: this
1705  !
1706  ! -- set omega value used for saturation calculations
1707  if (this%inewton > 0) then
1708  this%satomega = dem6
1709  end if
1710  !
1711  if (this%inewton > 0) then
1712  if (this%iperched > 0) then
1713  write (errmsg, '(a)') 'ERROR IN NPF OPTIONS. NEWTON OPTION CANNOT '// &
1714  'BE USED WITH PERCHED OPTION.'
1715  call store_error(errmsg)
1716  end if
1717  if (this%ivarcv > 0) then
1718  write (errmsg, '(a)') 'ERROR IN NPF OPTIONS. NEWTON OPTION CANNOT '// &
1719  'BE USED WITH VARIABLECV OPTION.'
1720  call store_error(errmsg)
1721  end if
1722  if (this%irewet > 0) then
1723  write (errmsg, '(a)') 'ERROR IN NPF OPTIONS. NEWTON OPTION CANNOT '// &
1724  'BE USED WITH REWET OPTION.'
1725  call store_error(errmsg)
1726  end if
1727  else
1728  if (this%ihighcellsat /= 0) then
1729  write (warnmsg, '(a)') 'HIGHEST_CELL_SATURATION '// &
1730  'option cannot be used when NEWTON option in not specified. '// &
1731  'Resetting HIGHEST_CELL_SATURATION option to off.'
1732  this%ihighcellsat = 0
1733  call store_warning(warnmsg)
1734  end if
1735  end if
1736  !
1737  if (this%ixt3d /= 0) then
1738  if (this%icellavg > 0) then
1739  write (errmsg, '(a)') 'ERROR IN NPF OPTIONS. '// &
1740  'ALTERNATIVE_CELL_AVERAGING OPTION '// &
1741  'CANNOT BE USED WITH XT3D OPTION.'
1742  call store_error(errmsg)
1743  end if
1744  if (this%ithickstrt > 0) then
1745  write (errmsg, '(a)') 'ERROR IN NPF OPTIONS. THICKSTRT OPTION '// &
1746  'CANNOT BE USED WITH XT3D OPTION.'
1747  call store_error(errmsg)
1748  end if
1749  if (this%iperched > 0) then
1750  write (errmsg, '(a)') 'ERROR IN NPF OPTIONS. PERCHED OPTION '// &
1751  'CANNOT BE USED WITH XT3D OPTION.'
1752  call store_error(errmsg)
1753  end if
1754  if (this%ivarcv > 0) then
1755  write (errmsg, '(a)') 'ERROR IN NPF OPTIONS. VARIABLECV OPTION '// &
1756  'CANNOT BE USED WITH XT3D OPTION.'
1757  call store_error(errmsg)
1758  end if
1759  end if
1760  !
1761  ! -- Terminate if errors
1762  if (count_errors() > 0) then
1763  call store_error_filename(this%input_fname)
1764  end if
1765  end subroutine check_options
1766 
1767  !> @brief Write dimensions to list file
1768  !<
1769  subroutine log_griddata(this, found)
1770  ! -- modules
1772  ! -- dummy
1773  class(gwfnpftype) :: this
1774  type(gwfnpfparamfoundtype), intent(in) :: found
1775  !
1776  write (this%iout, '(1x,a)') 'Setting NPF Griddata'
1777  !
1778  if (found%icelltype) then
1779  write (this%iout, '(4x,a)') 'ICELLTYPE set from input file'
1780  end if
1781  !
1782  if (found%k) then
1783  write (this%iout, '(4x,a)') 'K set from input file'
1784  end if
1785  !
1786  if (found%k33) then
1787  write (this%iout, '(4x,a)') 'K33 set from input file'
1788  else
1789  write (this%iout, '(4x,a)') 'K33 not provided. Setting K33 = K.'
1790  end if
1791  !
1792  if (found%k22) then
1793  write (this%iout, '(4x,a)') 'K22 set from input file'
1794  else
1795  write (this%iout, '(4x,a)') 'K22 not provided. Setting K22 = K.'
1796  end if
1797  !
1798  if (found%wetdry) then
1799  write (this%iout, '(4x,a)') 'WETDRY set from input file'
1800  end if
1801  !
1802  if (found%angle1) then
1803  write (this%iout, '(4x,a)') 'ANGLE1 set from input file'
1804  end if
1805  !
1806  if (found%angle2) then
1807  write (this%iout, '(4x,a)') 'ANGLE2 set from input file'
1808  end if
1809  !
1810  if (found%angle3) then
1811  write (this%iout, '(4x,a)') 'ANGLE3 set from input file'
1812  end if
1813  !
1814  write (this%iout, '(1x,a,/)') 'End Setting NPF Griddata'
1815  end subroutine log_griddata
1816 
1817  !> @brief Update simulation griddata from input mempath
1818  !<
1819  subroutine source_griddata(this)
1820  ! -- modules
1821  use simmodule, only: count_errors, store_error
1825  ! -- dummy
1826  class(gwfnpftype) :: this
1827  ! -- locals
1828  character(len=LINELENGTH) :: errmsg
1829  type(gwfnpfparamfoundtype) :: found
1830  logical, dimension(2) :: afound
1831  integer(I4B), dimension(:), pointer, contiguous :: map
1832  !
1833  ! -- set map to convert user input data into reduced data
1834  map => null()
1835  if (this%dis%nodes < this%dis%nodesuser) map => this%dis%nodeuser
1836  !
1837  ! -- update defaults with idm sourced values
1838  call mem_set_value(this%icelltype, 'ICELLTYPE', this%input_mempath, map, &
1839  found%icelltype)
1840  call mem_set_value(this%k11, 'K', this%input_mempath, map, found%k, &
1841  release=.false.)
1842  call mem_set_value(this%k33, 'K33', this%input_mempath, map, found%k33)
1843  call mem_set_value(this%k22, 'K22', this%input_mempath, map, found%k22)
1844  call mem_set_value(this%wetdry, 'WETDRY', this%input_mempath, map, &
1845  found%wetdry)
1846  call mem_set_value(this%angle1, 'ANGLE1', this%input_mempath, map, &
1847  found%angle1)
1848  call mem_set_value(this%angle2, 'ANGLE2', this%input_mempath, map, &
1849  found%angle2)
1850  call mem_set_value(this%angle3, 'ANGLE3', this%input_mempath, map, &
1851  found%angle3)
1852  !
1853  ! -- ensure ICELLTYPE was found
1854  if (.not. found%icelltype) then
1855  write (errmsg, '(a)') 'Error in GRIDDATA block: ICELLTYPE not found.'
1856  call store_error(errmsg)
1857  end if
1858  !
1859  ! -- ensure K was found
1860  if (.not. found%k) then
1861  write (errmsg, '(a)') 'Error in GRIDDATA block: K not found.'
1862  call store_error(errmsg)
1863  end if
1864  !
1865  ! -- set error if ik33overk set with no k33
1866  if (.not. found%k33 .and. this%ik33overk /= 0) then
1867  write (errmsg, '(a)') 'K33OVERK option specified but K33 not specified.'
1868  call store_error(errmsg)
1869  end if
1870  !
1871  ! -- set error if ik22overk set with no k22
1872  if (.not. found%k22 .and. this%ik22overk /= 0) then
1873  write (errmsg, '(a)') 'K22OVERK option specified but K22 not specified.'
1874  call store_error(errmsg)
1875  end if
1876  !
1877  ! -- handle found side effects
1878  if (found%k33) this%ik33 = 1
1879  if (found%k22) this%ik22 = 1
1880  if (found%wetdry) this%iwetdry = 1
1881  if (found%angle1) this%iangle1 = 1
1882  if (found%angle2) this%iangle2 = 1
1883  if (found%angle3) this%iangle3 = 1
1884  !
1885  ! -- handle not found side effects
1886  if (.not. found%k33) then
1887  call mem_set_value(this%k33, 'K', this%input_mempath, map, afound(1), &
1888  release=.false.)
1889  end if
1890  if (.not. found%k22) then
1891  call mem_set_value(this%k22, 'K', this%input_mempath, map, afound(2), &
1892  release=.false.)
1893  end if
1894  if (.not. found%wetdry) call mem_reallocate(this%wetdry, 1, 'WETDRY', &
1895  trim(this%memoryPath))
1896  if (.not. found%angle1 .and. this%ixt3d == 0) &
1897  call mem_reallocate(this%angle1, 0, 'ANGLE1', trim(this%memoryPath))
1898  if (.not. found%angle2 .and. this%ixt3d == 0) &
1899  call mem_reallocate(this%angle2, 0, 'ANGLE2', trim(this%memoryPath))
1900  if (.not. found%angle3 .and. this%ixt3d == 0) &
1901  call mem_reallocate(this%angle3, 0, 'ANGLE3', trim(this%memoryPath))
1902  !
1903  ! -- cleanup
1904  call memorystore_release('K', this%input_mempath)
1905  !
1906  ! -- log griddata
1907  if (this%iout > 0) then
1908  call this%log_griddata(found)
1909  end if
1910  end subroutine source_griddata
1911 
1912  !> @brief Initialize and check NPF data
1913  !<
1914  subroutine prepcheck(this)
1915  ! -- modules
1916  use constantsmodule, only: linelength, dpio180
1918  ! -- dummy
1919  class(gwfnpftype) :: this
1920  ! -- local
1921  character(len=24), dimension(:), pointer :: aname
1922  character(len=LINELENGTH) :: cellstr, errmsg
1923  integer(I4B) :: nerr, n
1924  ! -- format
1925  character(len=*), parameter :: fmtkerr = &
1926  &"(1x, 'Hydraulic property ',a,' is <= 0 for cell ',a, ' ', 1pg15.6)"
1927  character(len=*), parameter :: fmtkerr2 = &
1928  &"(1x, '... ', i0,' additional errors not shown for ',a)"
1929  !
1930  ! -- initialize
1931  aname => this%aname
1932  !
1933  ! -- check k11
1934  nerr = 0
1935  do n = 1, size(this%k11)
1936  if (this%k11(n) <= dzero) then
1937  nerr = nerr + 1
1938  if (nerr <= 20) then
1939  call this%dis%noder_to_string(n, cellstr)
1940  write (errmsg, fmtkerr) trim(adjustl(aname(2))), trim(cellstr), &
1941  this%k11(n)
1942  call store_error(errmsg)
1943  end if
1944  end if
1945  end do
1946  if (nerr > 20) then
1947  write (errmsg, fmtkerr2) nerr, trim(adjustl(aname(2)))
1948  call store_error(errmsg)
1949  end if
1950  !
1951  ! -- check k33 because it was read
1952  if (this%ik33 /= 0) then
1953  !
1954  ! -- Check to make sure values are greater than or equal to zero
1955  nerr = 0
1956  do n = 1, size(this%k33)
1957  if (this%ik33overk /= 0) this%k33(n) = this%k33(n) * this%k11(n)
1958  if (this%k33(n) <= dzero) then
1959  nerr = nerr + 1
1960  if (nerr <= 20) then
1961  call this%dis%noder_to_string(n, cellstr)
1962  write (errmsg, fmtkerr) trim(adjustl(aname(3))), trim(cellstr), &
1963  this%k33(n)
1964  call store_error(errmsg)
1965  end if
1966  end if
1967  end do
1968  if (nerr > 20) then
1969  write (errmsg, fmtkerr2) nerr, trim(adjustl(aname(3)))
1970  call store_error(errmsg)
1971  end if
1972  end if
1973  !
1974  ! -- check k22 because it was read
1975  if (this%ik22 /= 0) then
1976  !
1977  ! -- Check to make sure that angles are available
1978  if (this%dis%con%ianglex == 0) then
1979  write (errmsg, '(a)') 'Error. ANGLDEGX not provided in '// &
1980  'discretization file, but K22 was specified. '
1981  call store_error(errmsg)
1982  end if
1983  !
1984  ! -- Check to make sure values are greater than or equal to zero
1985  nerr = 0
1986  do n = 1, size(this%k22)
1987  if (this%ik22overk /= 0) this%k22(n) = this%k22(n) * this%k11(n)
1988  if (this%k22(n) <= dzero) then
1989  nerr = nerr + 1
1990  if (nerr <= 20) then
1991  call this%dis%noder_to_string(n, cellstr)
1992  write (errmsg, fmtkerr) trim(adjustl(aname(4))), trim(cellstr), &
1993  this%k22(n)
1994  call store_error(errmsg)
1995  end if
1996  end if
1997  end do
1998  if (nerr > 20) then
1999  write (errmsg, fmtkerr2) nerr, trim(adjustl(aname(4)))
2000  call store_error(errmsg)
2001  end if
2002  end if
2003  !
2004  ! -- check for wetdry conflicts
2005  if (this%irewet == 1) then
2006  if (this%iwetdry == 0) then
2007  write (errmsg, '(a, a, a)') 'Error in GRIDDATA block: ', &
2008  trim(adjustl(aname(5))), ' not found.'
2009  call store_error(errmsg)
2010  end if
2011  end if
2012  !
2013  ! -- Check for angle conflicts
2014  if (this%iangle1 /= 0) then
2015  do n = 1, size(this%angle1)
2016  this%angle1(n) = this%angle1(n) * dpio180
2017  end do
2018  else
2019  if (this%ixt3d /= 0) then
2020  this%iangle1 = 1
2021  write (this%iout, '(a)') 'XT3D IN USE, BUT ANGLE1 NOT SPECIFIED. '// &
2022  'SETTING ANGLE1 TO ZERO.'
2023  do n = 1, size(this%angle1)
2024  this%angle1(n) = dzero
2025  end do
2026  end if
2027  end if
2028  if (this%iangle2 /= 0) then
2029  if (this%iangle1 == 0) then
2030  write (errmsg, '(a)') 'ANGLE2 SPECIFIED BUT NOT ANGLE1. '// &
2031  'ANGLE2 REQUIRES ANGLE1. '
2032  call store_error(errmsg)
2033  end if
2034  if (this%iangle3 == 0) then
2035  write (errmsg, '(a)') 'ANGLE2 SPECIFIED BUT NOT ANGLE3. '// &
2036  'SPECIFY BOTH OR NEITHER ONE. '
2037  call store_error(errmsg)
2038  end if
2039  do n = 1, size(this%angle2)
2040  this%angle2(n) = this%angle2(n) * dpio180
2041  end do
2042  end if
2043  if (this%iangle3 /= 0) then
2044  if (this%iangle1 == 0) then
2045  write (errmsg, '(a)') 'ANGLE3 SPECIFIED BUT NOT ANGLE1. '// &
2046  'ANGLE3 REQUIRES ANGLE1. '
2047  call store_error(errmsg)
2048  end if
2049  if (this%iangle2 == 0) then
2050  write (errmsg, '(a)') 'ANGLE3 SPECIFIED BUT NOT ANGLE2. '// &
2051  'SPECIFY BOTH OR NEITHER ONE. '
2052  call store_error(errmsg)
2053  end if
2054  do n = 1, size(this%angle3)
2055  this%angle3(n) = this%angle3(n) * dpio180
2056  end do
2057  end if
2058  !
2059  ! -- terminate if data errors
2060  if (count_errors() > 0) then
2061  call store_error_filename(this%input_fname)
2062  end if
2063  end subroutine prepcheck
2064 
2065  !> @brief preprocess the NPF input data
2066  !!
2067  !! This routine consists of the following steps:
2068  !!
2069  !! 1. convert cells to noflow when all transmissive parameters equal zero
2070  !! 2. perform initial wetting and drying
2071  !! 3. initialize cell saturation
2072  !! 4. calculate saturated conductance (when not xt3d)
2073  !! 5. If NEWTON under-relaxation, determine lower most node
2074  !<
2075  subroutine preprocess_input(this)
2076  ! -- modules
2077  use constantsmodule, only: linelength
2079  ! -- dummy
2080  class(gwfnpftype) :: this !< the instance of the NPF package
2081  ! -- local
2082  integer(I4B) :: n, m, ii, nn
2083  real(DP) :: hyn, hym
2084  real(DP) :: satn, topn, botn
2085  integer(I4B) :: nextn
2086  real(DP) :: minbot, botm
2087  logical :: finished
2088  character(len=LINELENGTH) :: cellstr, errmsg
2089  ! -- format
2090  character(len=*), parameter :: fmtcnv = &
2091  "(1X,'CELL ', A, &
2092  &' ELIMINATED BECAUSE ALL HYDRAULIC CONDUCTIVITIES TO NODE ARE 0.')"
2093  character(len=*), parameter :: fmtnct = &
2094  &"(1X,'Negative cell thickness at cell ', A)"
2095  character(len=*), parameter :: fmtihbe = &
2096  &"(1X,'Initial head, bottom elevation:',1P,2G13.5)"
2097  character(len=*), parameter :: fmttebe = &
2098  &"(1X,'Top elevation, bottom elevation:',1P,2G13.5)"
2099  !
2100  do n = 1, this%dis%nodes
2101  this%ithickstartflag(n) = 0
2102  end do
2103  !
2104  ! -- Insure that each cell has at least one non-zero transmissive parameter
2105  ! Note that a cell can be deactivated even if it has a valid connection
2106  ! to another model.
2107  nodeloop: do n = 1, this%dis%nodes
2108  !
2109  ! -- Skip if already inactive
2110  if (this%ibound(n) == 0) then
2111  if (this%irewet /= 0) then
2112  if (this%wetdry(n) == dzero) cycle nodeloop
2113  else
2114  cycle nodeloop
2115  end if
2116  end if
2117  !
2118  ! -- Cycle if k11 is not zero
2119  if (this%k11(n) /= dzero) cycle nodeloop
2120  !
2121  ! -- Cycle if at least one vertical connection has non-zero k33
2122  ! for n and m
2123  do ii = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1
2124  m = this%dis%con%ja(ii)
2125  if (this%dis%con%ihc(this%dis%con%jas(ii)) == 0) then
2126  hyn = this%k11(n)
2127  if (this%ik33 /= 0) hyn = this%k33(n)
2128  if (hyn /= dzero) then
2129  hym = this%k11(m)
2130  if (this%ik33 /= 0) hym = this%k33(m)
2131  if (hym /= dzero) cycle
2132  end if
2133  end if
2134  end do
2135  !
2136  ! -- If this part of the loop is reached, then all connections have
2137  ! zero transmissivity, so convert to noflow.
2138  this%ibound(n) = 0
2139  this%hnew(n) = this%hnoflo
2140  if (this%irewet /= 0) this%wetdry(n) = dzero
2141  call this%dis%noder_to_string(n, cellstr)
2142  write (this%iout, fmtcnv) trim(adjustl(cellstr))
2143  !
2144  end do nodeloop
2145  !
2146  ! -- Preprocess cell status and heads based on initial conditions
2147  if (this%inewton == 0) then
2148  !
2149  ! -- For standard formulation (non-Newton) call wetdry routine
2150  call this%wd(0, this%hnew)
2151  else
2152  !
2153  ! -- Newton formulation, so adjust heads to be above bottom
2154  ! (Not used in present formulation because variable cv
2155  ! cannot be used with Newton)
2156  if (this%ivarcv == 1) then
2157  do n = 1, this%dis%nodes
2158  if (this%hnew(n) < this%dis%bot(n)) then
2159  this%hnew(n) = this%dis%bot(n) + dem6
2160  end if
2161  end do
2162  end if
2163  end if
2164  !
2165  ! -- If THCKSTRT is not active, then loop through icelltype and replace
2166  ! any negative values with 1.
2167  if (this%ithickstrt == 0) then
2168  do n = 1, this%dis%nodes
2169  if (this%icelltype(n) < 0) then
2170  this%icelltype(n) = 1
2171  end if
2172  end do
2173  end if
2174  !
2175  ! -- Initialize sat to zero for ibound=0 cells, unless the cell can
2176  ! rewet. Initialize sat to the saturated fraction based on strt
2177  ! if icelltype is negative and the THCKSTRT option is in effect.
2178  ! Initialize sat to 1.0 for all other cells in order to calculate
2179  ! condsat in next section.
2180  do n = 1, this%dis%nodes
2181  if (this%ibound(n) == 0) then
2182  this%sat(n) = done
2183  if (this%icelltype(n) < 0 .and. this%ithickstrt /= 0) then
2184  this%ithickstartflag(n) = 1
2185  this%icelltype(n) = 0
2186  end if
2187  else
2188  topn = this%dis%top(n)
2189  botn = this%dis%bot(n)
2190  if (this%icelltype(n) < 0 .and. this%ithickstrt /= 0) then
2191  call this%thksat(n, this%ic%strt(n), satn)
2192  if (botn > this%ic%strt(n)) then
2193  call this%dis%noder_to_string(n, cellstr)
2194  write (errmsg, fmtnct) trim(adjustl(cellstr))
2195  call store_error(errmsg)
2196  write (errmsg, fmtihbe) this%ic%strt(n), botn
2197  call store_error(errmsg)
2198  end if
2199  this%ithickstartflag(n) = 1
2200  this%icelltype(n) = 0
2201  else
2202  satn = done
2203  if (botn > topn) then
2204  call this%dis%noder_to_string(n, cellstr)
2205  write (errmsg, fmtnct) trim(adjustl(cellstr))
2206  call store_error(errmsg)
2207  write (errmsg, fmttebe) topn, botn
2208  call store_error(errmsg)
2209  end if
2210  end if
2211  this%sat(n) = satn
2212  end if
2213  end do
2214  if (count_errors() > 0) then
2215  call store_error_filename(this%input_fname)
2216  end if
2217  !
2218  ! -- Calculate condsat, but only if xt3d is not active. If xt3d is
2219  ! active, then condsat is allocated to size of zero.
2220  if (this%ixt3d == 0) then
2221  !
2222  ! -- Calculate the saturated conductance for all connections assuming
2223  ! that saturation is 1 (except for case where icelltype was entered
2224  ! as a negative value and THCKSTRT option in effect)
2225  do n = 1, this%dis%nodes
2226  call this%calc_condsat(n, .true.)
2227  end do
2228  !
2229  end if
2230  !
2231  ! -- Determine the lower most node
2232  if (this%igwfnewtonur /= 0) then
2233  call mem_reallocate(this%ibotnode, this%dis%nodes, 'IBOTNODE', &
2234  trim(this%memoryPath))
2235  do n = 1, this%dis%nodes
2236  !
2237  minbot = this%dis%bot(n)
2238  nn = n
2239  finished = .false.
2240  do while (.not. finished)
2241  nextn = 0
2242  !
2243  ! -- Go through the connecting cells
2244  do ii = this%dis%con%ia(nn) + 1, this%dis%con%ia(nn + 1) - 1
2245  !
2246  ! -- Set the m cell number
2247  m = this%dis%con%ja(ii)
2248  botm = this%dis%bot(m)
2249  !
2250  ! -- select vertical connections: ihc == 0
2251  if (this%dis%con%ihc(this%dis%con%jas(ii)) == 0) then
2252  if (m > nn .and. botm < minbot) then
2253  nextn = m
2254  minbot = botm
2255  end if
2256  end if
2257  end do
2258  if (nextn > 0) then
2259  nn = nextn
2260  else
2261  finished = .true.
2262  end if
2263  end do
2264  this%ibotnode(n) = nn
2265  end do
2266  end if
2267  !
2268  ! -- nullify unneeded gwf pointers
2269  this%igwfnewtonur => null()
2270  end subroutine preprocess_input
2271 
2272  !> @brief Calculate CONDSAT array entries for the given node
2273  !!
2274  !! Calculate saturated conductances for all connections of the given node,
2275  !! or optionally for the upper portion of the matrix only.
2276  !<
2277  subroutine calc_condsat(this, node, upperOnly)
2278  ! -- dummy variables
2279  class(gwfnpftype) :: this
2280  integer(I4B), intent(in) :: node
2281  logical, intent(in) :: upperOnly
2282  ! -- local variables
2283  integer(I4B) :: ii, m, n, ihc, jj
2284  real(DP) :: topm, topn, topnode, botm, botn, botnode, satm, satn, satnode
2285  real(DP) :: hyn, hym, hn, hm, fawidth, csat
2286  !
2287  satnode = this%calc_initial_sat(node)
2288  !
2289  topnode = this%dis%top(node)
2290  botnode = this%dis%bot(node)
2291  !
2292  ! -- Go through the connecting cells
2293  do ii = this%dis%con%ia(node) + 1, this%dis%con%ia(node + 1) - 1
2294  !
2295  ! -- Set the m cell number and cycle if lower triangle connection and
2296  ! -- we're not updating both upper and lower matrix parts for this node
2297  m = this%dis%con%ja(ii)
2298  jj = this%dis%con%jas(ii)
2299  if (m < node) then
2300  if (upperonly) cycle
2301  ! m => node, n => neighbour
2302  n = m
2303  m = node
2304  topm = topnode
2305  botm = botnode
2306  satm = satnode
2307  topn = this%dis%top(n)
2308  botn = this%dis%bot(n)
2309  satn = this%calc_initial_sat(n)
2310  else
2311  ! n => node, m => neighbour
2312  n = node
2313  topn = topnode
2314  botn = botnode
2315  satn = satnode
2316  topm = this%dis%top(m)
2317  botm = this%dis%bot(m)
2318  satm = this%calc_initial_sat(m)
2319  end if
2320  !
2321  ihc = this%dis%con%ihc(jj)
2322  hyn = this%hy_eff(n, m, ihc, ipos=ii)
2323  hym = this%hy_eff(m, n, ihc, ipos=ii)
2324  if (this%ithickstartflag(n) == 0) then
2325  hn = topn
2326  else
2327  hn = this%ic%strt(n)
2328  end if
2329  if (this%ithickstartflag(m) == 0) then
2330  hm = topm
2331  else
2332  hm = this%ic%strt(m)
2333  end if
2334  !
2335  ! -- Calculate conductance depending on whether connection is
2336  ! vertical (0), horizontal (1), or staggered horizontal (2)
2337  if (ihc == c3d_vertical) then
2338  !
2339  ! -- Vertical conductance for fully saturated conditions
2340  csat = vcond(1, 1, 1, 1, 0, 1, 1, done, &
2341  botn, botm, &
2342  hyn, hym, &
2343  satn, satm, &
2344  topn, topm, &
2345  botn, botm, &
2346  this%dis%con%hwva(jj))
2347  else
2348  !
2349  ! -- Horizontal conductance for fully saturated conditions
2350  fawidth = this%dis%con%hwva(jj)
2351  csat = hcond(1, 1, 1, 1, 0, &
2352  ihc, &
2353  this%icellavg, &
2354  done, &
2355  hn, hm, satn, satm, hyn, hym, &
2356  topn, topm, &
2357  botn, botm, &
2358  this%dis%con%cl1(jj), &
2359  this%dis%con%cl2(jj), &
2360  fawidth)
2361  end if
2362  this%condsat(jj) = csat
2363  end do
2364  end subroutine calc_condsat
2365 
2366  !> @brief Calculate initial saturation for the given node
2367  !!
2368  !! Calculate saturation as a fraction of thickness for the given node, used
2369  !! for saturated conductance calculations: full thickness by default (1.0) or
2370  !! saturation based on initial conditions if the THICKSTRT option is used.
2371  !!
2372  !<
2373  function calc_initial_sat(this, n) result(satn)
2374  ! -- dummy variables
2375  class(gwfnpftype) :: this
2376  integer(I4B), intent(in) :: n
2377  ! -- Return
2378  real(dp) :: satn
2379  !
2380  satn = done
2381  if (this%ibound(n) /= 0 .and. this%ithickstartflag(n) /= 0) then
2382  call this%thksat(n, this%ic%strt(n), satn)
2383  end if
2384  end function calc_initial_sat
2385 
2386  !> @brief Perform wetting and drying
2387  !<
2388  subroutine sgwf_npf_wetdry(this, kiter, hnew)
2389  ! -- modules
2390  use tdismodule, only: kstp, kper
2392  use constantsmodule, only: linelength
2393  ! -- dummy
2394  class(gwfnpftype) :: this
2395  integer(I4B), intent(in) :: kiter
2396  real(DP), intent(inout), dimension(:) :: hnew
2397  ! -- local
2398  integer(I4B) :: n, m, ii, ihc
2399  real(DP) :: ttop, bbot, thick
2400  integer(I4B) :: ncnvrt, ihdcnv
2401  character(len=30), dimension(5) :: nodcnvrt
2402  character(len=30) :: nodestr
2403  character(len=3), dimension(5) :: acnvrt
2404  character(len=LINELENGTH) :: errmsg
2405  integer(I4B) :: irewet
2406  ! -- formats
2407  character(len=*), parameter :: fmtnct = &
2408  "(1X,/1X,'Negative cell thickness at (layer,row,col)', &
2409  &I4,',',I5,',',I5)"
2410  character(len=*), parameter :: fmttopbot = &
2411  &"(1X,'Top elevation, bottom elevation:',1P,2G13.5)"
2412  character(len=*), parameter :: fmttopbotthk = &
2413  &"(1X,'Top elevation, bottom elevation, thickness:',1P,3G13.5)"
2414  character(len=*), parameter :: fmtdrychd = &
2415  &"(1X,/1X,'CONSTANT-HEAD CELL WENT DRY -- SIMULATION ABORTED')"
2416  character(len=*), parameter :: fmtni = &
2417  &"(1X,'CELLID=',a,' ITERATION=',I0,' TIME STEP=',I0,' STRESS PERIOD=',I0)"
2418  !
2419  ! -- Initialize
2420  ncnvrt = 0
2421  ihdcnv = 0
2422  !
2423  ! -- Convert dry cells to wet
2424  do n = 1, this%dis%nodes
2425  do ii = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1
2426  m = this%dis%con%ja(ii)
2427  ihc = this%dis%con%ihc(this%dis%con%jas(ii))
2428  call this%rewet_check(kiter, n, hnew(m), this%ibound(m), ihc, hnew, &
2429  irewet)
2430  if (irewet == 1) then
2431  call this%wdmsg(2, ncnvrt, nodcnvrt, acnvrt, ihdcnv, kiter, n)
2432  end if
2433  end do
2434  end do
2435  !
2436  ! -- Perform drying
2437  do n = 1, this%dis%nodes
2438  !
2439  ! -- cycle if inactive or confined
2440  if (this%ibound(n) == 0) cycle
2441  if (this%icelltype(n) == 0) cycle
2442  !
2443  ! -- check for negative cell thickness
2444  bbot = this%dis%bot(n)
2445  ttop = this%dis%top(n)
2446  if (bbot > ttop) then
2447  write (errmsg, fmtnct) n
2448  call store_error(errmsg)
2449  write (errmsg, fmttopbot) ttop, bbot
2450  call store_error(errmsg)
2451  call store_error_filename(this%input_fname)
2452  end if
2453  !
2454  ! -- Calculate saturated thickness
2455  if (this%icelltype(n) /= 0) then
2456  if (hnew(n) < ttop) ttop = hnew(n)
2457  end if
2458  thick = ttop - bbot
2459  !
2460  ! -- If thick<0 print message, set hnew, and ibound
2461  if (thick <= dzero) then
2462  call this%wdmsg(1, ncnvrt, nodcnvrt, acnvrt, ihdcnv, kiter, n)
2463  hnew(n) = this%hdry
2464  if (this%ibound(n) < 0) then
2465  errmsg = 'CONSTANT-HEAD CELL WENT DRY -- SIMULATION ABORTED'
2466  call store_error(errmsg)
2467  write (errmsg, fmttopbotthk) ttop, bbot, thick
2468  call store_error(errmsg)
2469  call this%dis%noder_to_string(n, nodestr)
2470  write (errmsg, fmtni) trim(adjustl(nodestr)), kiter, kstp, kper
2471  call store_error(errmsg)
2472  call store_error_filename(this%input_fname)
2473  end if
2474  this%ibound(n) = 0
2475  end if
2476  end do
2477  !
2478  ! -- Print remaining cell conversions
2479  call this%wdmsg(0, ncnvrt, nodcnvrt, acnvrt, ihdcnv, kiter, n)
2480  !
2481  ! -- Change ibound from 30000 to 1
2482  do n = 1, this%dis%nodes
2483  if (this%ibound(n) == 30000) this%ibound(n) = 1
2484  end do
2485  end subroutine sgwf_npf_wetdry
2486 
2487  !> @brief Determine if a cell should rewet
2488  !!
2489  !! This method can be called from any external object that has a head that
2490  !! can be used to rewet the GWF cell node. The ihc value is used to
2491  !! determine if it is a vertical or horizontal connection, which can operate
2492  !! differently depending on user settings.
2493  !<
2494  subroutine rewet_check(this, kiter, node, hm, ibdm, ihc, hnew, irewet)
2495  ! -- dummy
2496  class(gwfnpftype) :: this
2497  integer(I4B), intent(in) :: kiter
2498  integer(I4B), intent(in) :: node
2499  real(DP), intent(in) :: hm
2500  integer(I4B), intent(in) :: ibdm
2501  integer(I4B), intent(in) :: ihc
2502  real(DP), intent(inout), dimension(:) :: hnew
2503  integer(I4B), intent(out) :: irewet
2504  ! -- local
2505  integer(I4B) :: itflg
2506  real(DP) :: wd, awd, turnon, bbot
2507  !
2508  irewet = 0
2509  !
2510  ! -- Convert a dry cell to wet if it meets the criteria
2511  if (this%irewet > 0) then
2512  itflg = mod(kiter, this%iwetit)
2513  if (itflg == 0) then
2514  if (this%ibound(node) == 0 .and. this%wetdry(node) /= dzero) then
2515  !
2516  ! -- Calculate wetting elevation
2517  bbot = this%dis%bot(node)
2518  wd = this%wetdry(node)
2519  awd = wd
2520  if (wd < 0) awd = -wd
2521  turnon = bbot + awd
2522  !
2523  ! -- Check head in adjacent cells to see if wetting elevation has
2524  ! been reached
2525  if (ihc == c3d_vertical) then
2526  !
2527  ! -- check cell below
2528  if (ibdm > 0 .and. hm >= turnon) irewet = 1
2529  else
2530  if (wd > dzero) then
2531  !
2532  ! -- check horizontally adjacent cells
2533  if (ibdm > 0 .and. hm >= turnon) irewet = 1
2534  end if
2535  end if
2536  !
2537  if (irewet == 1) then
2538  ! -- rewet cell; use equation 3a if ihdwet=0; use equation 3b if
2539  ! ihdwet is not 0.
2540  if (this%ihdwet == 0) then
2541  hnew(node) = bbot + this%wetfct * (hm - bbot)
2542  else
2543  hnew(node) = bbot + this%wetfct * awd !(hm - bbot)
2544  end if
2545  this%ibound(node) = 30000
2546  end if
2547  end if
2548  end if
2549  end if
2550  end subroutine rewet_check
2551 
2552  !> @brief Print wet/dry message
2553  !<
2554  subroutine sgwf_npf_wdmsg(this, icode, ncnvrt, nodcnvrt, acnvrt, ihdcnv, &
2555  kiter, n)
2556  ! -- modules
2557  use tdismodule, only: kstp, kper
2558  ! -- dummy
2559  class(gwfnpftype) :: this
2560  integer(I4B), intent(in) :: icode
2561  integer(I4B), intent(inout) :: ncnvrt
2562  character(len=30), dimension(5), intent(inout) :: nodcnvrt
2563  character(len=3), dimension(5), intent(inout) :: acnvrt
2564  integer(I4B), intent(inout) :: ihdcnv
2565  integer(I4B), intent(in) :: kiter
2566  integer(I4B), intent(in) :: n
2567  ! -- local
2568  integer(I4B) :: l
2569  ! -- formats
2570  character(len=*), parameter :: fmtcnvtn = &
2571  "(1X,/1X,'CELL CONVERSIONS FOR ITER.=',I0, &
2572  &' STEP=',I0,' PERIOD=',I0,' (NODE or LRC)')"
2573  character(len=*), parameter :: fmtnode = "(1X,3X,5(A4, A20))"
2574  !
2575  ! -- Keep track of cell conversions
2576  if (icode > 0) then
2577  ncnvrt = ncnvrt + 1
2578  call this%dis%noder_to_string(n, nodcnvrt(ncnvrt))
2579  if (icode == 1) then
2580  acnvrt(ncnvrt) = 'DRY'
2581  else
2582  acnvrt(ncnvrt) = 'WET'
2583  end if
2584  end if
2585  !
2586  ! -- Print a line if 5 conversions have occurred or if icode indicates that a
2587  ! partial line should be printed
2588  if (ncnvrt == 5 .or. (icode == 0 .and. ncnvrt > 0)) then
2589  if (ihdcnv == 0) write (this%iout, fmtcnvtn) kiter, kstp, kper
2590  ihdcnv = 1
2591  write (this%iout, fmtnode) &
2592  (acnvrt(l), trim(adjustl(nodcnvrt(l))), l=1, ncnvrt)
2593  ncnvrt = 0
2594  end if
2595  end subroutine sgwf_npf_wdmsg
2596 
2597  !> @brief Calculate the effective hydraulic conductivity for the n-m connection
2598  !!
2599  !! n is primary node node number
2600  !! m is connected node (not used if vg is provided)
2601  !! ihc is horizontal indicator (0 vertical, 1 horizontal, 2 vertically
2602  !! staggered)
2603  !! ipos_opt is position of connection in ja array
2604  !! vg is the global unit vector that expresses the direction from which to
2605  !! calculate an effective hydraulic conductivity.
2606  !<
2607  function hy_eff(this, n, m, ihc, ipos, vg) result(hy)
2608  ! -- return
2609  real(dp) :: hy
2610  ! -- dummy
2611  class(gwfnpftype) :: this
2612  integer(I4B), intent(in) :: n
2613  integer(I4B), intent(in) :: m
2614  integer(I4B), intent(in) :: ihc
2615  integer(I4B), intent(in), optional :: ipos
2616  real(dp), dimension(3), intent(in), optional :: vg
2617  ! -- local
2618  integer(I4B) :: iipos
2619  real(dp) :: hy11, hy22, hy33
2620  real(dp) :: ang1, ang2, ang3
2621  real(dp) :: vg1, vg2, vg3
2622  !
2623  ! -- Initialize
2624  iipos = 0
2625  if (present(ipos)) iipos = ipos
2626  hy11 = this%k11(n)
2627  hy22 = this%k11(n)
2628  hy33 = this%k11(n)
2629  hy22 = this%k22(n)
2630  hy33 = this%k33(n)
2631  !
2632  ! -- Calculate effective K based on whether connection is vertical
2633  ! or horizontal
2634  if (ihc == c3d_vertical) then
2635  !
2636  ! -- Handle rotated anisotropy case that would affect the effective
2637  ! vertical hydraulic conductivity
2638  hy = hy33
2639  if (this%iangle2 > 0) then
2640  if (present(vg)) then
2641  vg1 = vg(1)
2642  vg2 = vg(2)
2643  vg3 = vg(3)
2644  else
2645  call this%dis%connection_normal(n, m, ihc, vg1, vg2, vg3, iipos)
2646  end if
2647  ang1 = this%angle1(n)
2648  ang2 = this%angle2(n)
2649  ang3 = dzero
2650  if (this%iangle3 > 0) ang3 = this%angle3(n)
2651  hy = hyeff(hy11, hy22, hy33, ang1, ang2, ang3, vg1, vg2, vg3, &
2652  this%iavgkeff)
2653  end if
2654  !
2655  else
2656  !
2657  ! -- Handle horizontal case
2658  hy = hy11
2659  if (this%ik22 > 0) then
2660  if (present(vg)) then
2661  vg1 = vg(1)
2662  vg2 = vg(2)
2663  vg3 = vg(3)
2664  else
2665  call this%dis%connection_normal(n, m, ihc, vg1, vg2, vg3, iipos)
2666  end if
2667  ang1 = dzero
2668  ang2 = dzero
2669  ang3 = dzero
2670  if (this%iangle1 > 0) then
2671  ang1 = this%angle1(n)
2672  if (this%iangle2 > 0) then
2673  ang2 = this%angle2(n)
2674  if (this%iangle3 > 0) ang3 = this%angle3(n)
2675  end if
2676  end if
2677  hy = hyeff(hy11, hy22, hy33, ang1, ang2, ang3, vg1, vg2, vg3, &
2678  this%iavgkeff)
2679  end if
2680  !
2681  end if
2682  end function hy_eff
2683 
2684  !> @brief Calculate the 3 components of specific discharge at the cell center
2685  !<
2686  subroutine calc_spdis(this, flowja)
2687  ! -- modules
2688  use simmodule, only: store_error
2689  ! -- dummy
2690  class(gwfnpftype) :: this
2691  real(DP), intent(in), dimension(:) :: flowja
2692  ! -- local
2693  integer(I4B) :: n
2694  integer(I4B) :: m
2695  integer(I4B) :: ipos
2696  integer(I4B) :: iedge
2697  integer(I4B) :: isympos
2698  integer(I4B) :: ihc
2699  integer(I4B) :: ic
2700  integer(I4B) :: iz
2701  integer(I4B) :: nc
2702  integer(I4B) :: ncz
2703  real(DP) :: qz
2704  real(DP) :: vx
2705  real(DP) :: vy
2706  real(DP) :: vz
2707  real(DP) :: xn
2708  real(DP) :: yn
2709  real(DP) :: zn
2710  real(DP) :: xc
2711  real(DP) :: yc
2712  real(DP) :: zc
2713  real(DP) :: cl1
2714  real(DP) :: cl2
2715  real(DP) :: dltot
2716  real(DP) :: ooclsum
2717  real(DP) :: dsumx
2718  real(DP) :: dsumy
2719  real(DP) :: dsumz
2720  real(DP) :: denom
2721  real(DP) :: area
2722  real(DP) :: dz
2723  real(DP) :: axy
2724  real(DP) :: ayx
2725  logical :: nozee = .true.
2726  type(spdisworkarraytype), pointer :: swa => null() !< pointer to spdis work arrays structure
2727  !
2728  ! -- Ensure dis has necessary information
2729  if (this%icalcspdis /= 0 .and. this%dis%con%ianglex == 0) then
2730  call store_error('Error. ANGLDEGX not provided in '// &
2731  'discretization file. ANGLDEGX required for '// &
2732  'calculation of specific discharge.', terminate=.true.)
2733  end if
2734 
2735  swa => this%spdis_wa
2736  if (.not. swa%is_created()) then
2737  ! prepare work arrays
2738  call this%spdis_wa%create(this%calc_max_conns())
2739 
2740  ! prepare lookup table
2741  if (this%nedges > 0) call this%prepare_edge_lookup()
2742  end if
2743  !
2744  ! -- Go through each cell and calculate specific discharge
2745  do n = 1, this%dis%nodes
2746  !
2747  ! -- first calculate geometric properties for x and y directions and
2748  ! the specific discharge at a face (vi)
2749  ic = 0
2750  iz = 0
2751 
2752  ! reset work arrays
2753  call swa%reset()
2754 
2755  do ipos = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1
2756  m = this%dis%con%ja(ipos)
2757  isympos = this%dis%con%jas(ipos)
2758  ihc = this%dis%con%ihc(isympos)
2759  area = this%dis%con%hwva(isympos)
2760  if (ihc == c3d_vertical) then
2761  !
2762  ! -- vertical connection
2763  iz = iz + 1
2764  !call this%dis%connection_normal(n, m, ihc, xn, yn, zn, ipos)
2765  call this%dis%connection_vector(n, m, nozee, this%sat(n), this%sat(m), &
2766  ihc, xc, yc, zc, dltot)
2767  cl1 = this%dis%con%cl1(isympos)
2768  cl2 = this%dis%con%cl2(isympos)
2769  if (m < n) then
2770  cl1 = this%dis%con%cl2(isympos)
2771  cl2 = this%dis%con%cl1(isympos)
2772  end if
2773  ooclsum = done / (cl1 + cl2)
2774  swa%diz(iz) = dltot * cl1 * ooclsum
2775  qz = flowja(ipos)
2776  if (n > m) qz = -qz
2777  swa%viz(iz) = qz / area
2778  else
2779  !
2780  ! -- horizontal connection
2781  ic = ic + 1
2782  dz = thksatnm(this%ibound(n), this%ibound(m), &
2783  this%icelltype(n), this%icelltype(m), &
2784  this%inewton, ihc, &
2785  this%hnew(n), this%hnew(m), this%sat(n), this%sat(m), &
2786  this%dis%top(n), this%dis%top(m), this%dis%bot(n), &
2787  this%dis%bot(m))
2788  area = area * dz
2789  call this%dis%connection_normal(n, m, ihc, xn, yn, zn, ipos)
2790  call this%dis%connection_vector(n, m, nozee, this%sat(n), this%sat(m), &
2791  ihc, xc, yc, zc, dltot)
2792  cl1 = this%dis%con%cl1(isympos)
2793  cl2 = this%dis%con%cl2(isympos)
2794  if (m < n) then
2795  cl1 = this%dis%con%cl2(isympos)
2796  cl2 = this%dis%con%cl1(isympos)
2797  end if
2798  ooclsum = done / (cl1 + cl2)
2799  swa%nix(ic) = -xn
2800  swa%niy(ic) = -yn
2801  swa%di(ic) = dltot * cl1 * ooclsum
2802  if (area > dzero) then
2803  swa%vi(ic) = flowja(ipos) / area
2804  else
2805  swa%vi(ic) = dzero
2806  end if
2807  end if
2808  end do
2809 
2810  ! add contribution from edge flows (i.e. from exchanges)
2811  if (this%nedges > 0) then
2812  do ipos = this%iedge_ptr(n), this%iedge_ptr(n + 1) - 1
2813  iedge = this%edge_idxs(ipos)
2814 
2815  ! propsedge: (Q, area, nx, ny, distance)
2816  ihc = this%ihcedge(iedge)
2817  area = this%propsedge(2, iedge)
2818  if (ihc == c3d_vertical) then
2819  iz = iz + 1
2820  swa%viz(iz) = this%propsedge(1, iedge) / area
2821  swa%diz(iz) = this%propsedge(5, iedge)
2822  else
2823  ic = ic + 1
2824  swa%nix(ic) = -this%propsedge(3, iedge)
2825  swa%niy(ic) = -this%propsedge(4, iedge)
2826  swa%di(ic) = this%propsedge(5, iedge)
2827  if (area > dzero) then
2828  swa%vi(ic) = this%propsedge(1, iedge) / area
2829  else
2830  swa%vi(ic) = dzero
2831  end if
2832  end if
2833  end do
2834  end if
2835  !
2836  ! -- Assign number of vertical and horizontal connections
2837  ncz = iz
2838  nc = ic
2839  !
2840  ! -- calculate z weight (wiz) and z velocity
2841  if (ncz == 1) then
2842  swa%wiz(1) = done
2843  else
2844  dsumz = dzero
2845  do iz = 1, ncz
2846  dsumz = dsumz + swa%diz(iz)
2847  end do
2848  denom = (ncz - done)
2849  if (denom < dzero) denom = dzero
2850  dsumz = dsumz + dem10 * dsumz
2851  do iz = 1, ncz
2852  if (dsumz > dzero) swa%wiz(iz) = done - swa%diz(iz) / dsumz
2853  if (denom > 0) then
2854  swa%wiz(iz) = swa%wiz(iz) / denom
2855  else
2856  swa%wiz(iz) = dzero
2857  end if
2858  end do
2859  end if
2860  vz = dzero
2861  do iz = 1, ncz
2862  vz = vz + swa%wiz(iz) * swa%viz(iz)
2863  end do
2864  !
2865  ! -- distance-based weighting
2866  nc = ic
2867  dsumx = dzero
2868  dsumy = dzero
2869  dsumz = dzero
2870  do ic = 1, nc
2871  swa%wix(ic) = swa%di(ic) * abs(swa%nix(ic))
2872  swa%wiy(ic) = swa%di(ic) * abs(swa%niy(ic))
2873  dsumx = dsumx + swa%wix(ic)
2874  dsumy = dsumy + swa%wiy(ic)
2875  end do
2876  !
2877  ! -- Finish computing omega weights. Add a tiny bit
2878  ! to dsum so that the normalized omega weight later
2879  ! evaluates to (essentially) 1 in the case of a single
2880  ! relevant connection, avoiding 0/0.
2881  dsumx = dsumx + dem10 * dsumx
2882  dsumy = dsumy + dem10 * dsumy
2883  do ic = 1, nc
2884  swa%wix(ic) = (dsumx - swa%wix(ic)) * abs(swa%nix(ic))
2885  swa%wiy(ic) = (dsumy - swa%wiy(ic)) * abs(swa%niy(ic))
2886  end do
2887  !
2888  ! -- compute B weights
2889  dsumx = dzero
2890  dsumy = dzero
2891  do ic = 1, nc
2892  swa%bix(ic) = swa%wix(ic) * sign(done, swa%nix(ic))
2893  swa%biy(ic) = swa%wiy(ic) * sign(done, swa%niy(ic))
2894  dsumx = dsumx + swa%wix(ic) * abs(swa%nix(ic))
2895  dsumy = dsumy + swa%wiy(ic) * abs(swa%niy(ic))
2896  end do
2897  if (dsumx > dzero) dsumx = done / dsumx
2898  if (dsumy > dzero) dsumy = done / dsumy
2899  axy = dzero
2900  ayx = dzero
2901  do ic = 1, nc
2902  swa%bix(ic) = swa%bix(ic) * dsumx
2903  swa%biy(ic) = swa%biy(ic) * dsumy
2904  axy = axy + swa%bix(ic) * swa%niy(ic)
2905  ayx = ayx + swa%biy(ic) * swa%nix(ic)
2906  end do
2907  !
2908  ! -- Calculate specific discharge. The divide by zero checking below
2909  ! is problematic for cells with only one flow, such as can happen
2910  ! with triangular cells in corners. In this case, the resulting
2911  ! cell velocity will be calculated as zero. The method should be
2912  ! improved so that edge flows of zero are included in these
2913  ! calculations. But this needs to be done with consideration for LGR
2914  ! cases in which flows are submitted from an exchange.
2915  vx = dzero
2916  vy = dzero
2917  do ic = 1, nc
2918  vx = vx + (swa%bix(ic) - axy * swa%biy(ic)) * swa%vi(ic)
2919  vy = vy + (swa%biy(ic) - ayx * swa%bix(ic)) * swa%vi(ic)
2920  end do
2921  denom = done - axy * ayx
2922  if (denom /= dzero) then
2923  vx = vx / denom
2924  vy = vy / denom
2925  end if
2926  !
2927  this%spdis(1, n) = vx
2928  this%spdis(2, n) = vy
2929  this%spdis(3, n) = vz
2930  !
2931  end do
2932 
2933  end subroutine calc_spdis
2934 
2935  !> @brief Save specific discharge in binary format to ibinun
2936  !<
2937  subroutine sav_spdis(this, ibinun)
2938  ! -- dummy
2939  class(gwfnpftype) :: this
2940  integer(I4B), intent(in) :: ibinun
2941  ! -- local
2942  character(len=16) :: text
2943  character(len=16), dimension(3) :: auxtxt
2944  integer(I4B) :: n
2945  integer(I4B) :: naux
2946  !
2947  ! -- Write the header
2948  text = ' DATA-SPDIS'
2949  naux = 3
2950  auxtxt(:) = [' qx', ' qy', ' qz']
2951  call this%dis%record_srcdst_list_header(text, this%name_model, &
2952  this%packName, this%name_model, &
2953  this%packName, naux, auxtxt, ibinun, &
2954  this%dis%nodes, this%iout)
2955  !
2956  ! -- Write a zero for Q, and then write qx, qy, qz as aux variables
2957  do n = 1, this%dis%nodes
2958  call this%dis%record_mf6_list_entry(ibinun, n, n, dzero, naux, &
2959  this%spdis(:, n))
2960  end do
2961  end subroutine sav_spdis
2962 
2963  !> @brief Save saturation in binary format to ibinun
2964  !<
2965  subroutine sav_sat(this, ibinun)
2966  ! -- dummy
2967  class(gwfnpftype) :: this
2968  integer(I4B), intent(in) :: ibinun
2969  ! -- local
2970  character(len=16) :: text
2971  character(len=16), dimension(1) :: auxtxt
2972  real(DP), dimension(1) :: a
2973  integer(I4B) :: n
2974  integer(I4B) :: naux
2975  !
2976  ! -- Write the header
2977  text = ' DATA-SAT'
2978  naux = 1
2979  auxtxt(:) = [' sat']
2980  call this%dis%record_srcdst_list_header(text, this%name_model, &
2981  this%packName, this%name_model, &
2982  this%packName, naux, auxtxt, ibinun, &
2983  this%dis%nodes, this%iout)
2984  !
2985  ! -- Write a zero for Q, and then write saturation as an aux variables
2986  do n = 1, this%dis%nodes
2987  a(1) = this%sat(n)
2988  call this%dis%record_mf6_list_entry(ibinun, n, n, dzero, naux, a)
2989  end do
2990  end subroutine sav_sat
2991 
2992  !> @brief Reserve space for nedges cells that have an edge on them.
2993  !!
2994  !! This must be called before the npf%allocate_arrays routine, which is
2995  !! called from npf%ar.
2996  !<
2997  subroutine increase_edge_count(this, nedges)
2998  ! -- dummy
2999  class(gwfnpftype) :: this
3000  integer(I4B), intent(in) :: nedges
3001  !
3002  this%nedges = this%nedges + nedges
3003  end subroutine increase_edge_count
3004 
3005  !> @brief Calculate the maximum number of connections for any cell
3006  !<
3007  function calc_max_conns(this) result(max_conns)
3008  class(gwfnpftype) :: this
3009  integer(I4B) :: max_conns
3010  ! local
3011  integer(I4B) :: n, m, ic
3012 
3013  max_conns = 0
3014  do n = 1, this%dis%nodes
3015 
3016  ! Count internal model connections
3017  ic = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1
3018 
3019  ! Add edge connections
3020  do m = 1, this%nedges
3021  if (this%nodedge(m) == n) then
3022  ic = ic + 1
3023  end if
3024  end do
3025 
3026  ! Set max number of connections for any cell
3027  if (ic > max_conns) max_conns = ic
3028  end do
3029 
3030  end function calc_max_conns
3031 
3032  !> @brief Provide the npf package with edge properties
3033  !<
3034  subroutine set_edge_properties(this, nodedge, ihcedge, q, area, nx, ny, &
3035  distance)
3036  ! -- dummy
3037  class(gwfnpftype) :: this
3038  integer(I4B), intent(in) :: nodedge
3039  integer(I4B), intent(in) :: ihcedge
3040  real(DP), intent(in) :: q
3041  real(DP), intent(in) :: area
3042  real(DP), intent(in) :: nx
3043  real(DP), intent(in) :: ny
3044  real(DP), intent(in) :: distance
3045  ! -- local
3046  integer(I4B) :: lastedge
3047  !
3048  this%lastedge = this%lastedge + 1
3049  lastedge = this%lastedge
3050  this%nodedge(lastedge) = nodedge
3051  this%ihcedge(lastedge) = ihcedge
3052  this%propsedge(1, lastedge) = q
3053  this%propsedge(2, lastedge) = area
3054  this%propsedge(3, lastedge) = nx
3055  this%propsedge(4, lastedge) = ny
3056  this%propsedge(5, lastedge) = distance
3057  !
3058  ! -- If this is the last edge, then the next call must be starting a new
3059  ! edge properties assignment loop, so need to reset lastedge to 0
3060  if (this%lastedge == this%nedges) this%lastedge = 0
3061  end subroutine set_edge_properties
3062 
3063  subroutine prepare_edge_lookup(this)
3064  class(gwfnpftype) :: this
3065  ! local
3066  integer(I4B) :: i, inode, iedge
3067  integer(I4B) :: n, start, end
3068  integer(I4B) :: prev_cnt, strt_idx, ipos
3069 
3070  do i = 1, size(this%iedge_ptr)
3071  this%iedge_ptr(i) = 0
3072  end do
3073  do i = 1, size(this%edge_idxs)
3074  this%edge_idxs(i) = 0
3075  end do
3076 
3077  ! count
3078  do iedge = 1, this%nedges
3079  n = this%nodedge(iedge)
3080  this%iedge_ptr(n) = this%iedge_ptr(n) + 1
3081  end do
3082 
3083  ! determine start indexes
3084  prev_cnt = this%iedge_ptr(1)
3085  this%iedge_ptr(1) = 1
3086  do inode = 2, this%dis%nodes + 1
3087  strt_idx = this%iedge_ptr(inode - 1) + prev_cnt
3088  prev_cnt = this%iedge_ptr(inode)
3089  this%iedge_ptr(inode) = strt_idx
3090  end do
3091 
3092  ! loop over edges to fill lookup table
3093  do iedge = 1, this%nedges
3094  n = this%nodedge(iedge)
3095  start = this%iedge_ptr(n)
3096  end = this%iedge_ptr(n + 1) - 1
3097  do ipos = start, end
3098  if (this%edge_idxs(ipos) > 0) cycle ! go to next
3099  this%edge_idxs(ipos) = iedge
3100  exit
3101  end do
3102  end do
3103 
3104  end subroutine prepare_edge_lookup
3105 
3106  !> Calculate saturated thickness between cell n and m
3107  !<
3108  function calcsatthickness(this, n, m, ihc) result(satThickness)
3109  ! -- dummy
3110  class(gwfnpftype) :: this !< this NPF instance
3111  integer(I4B) :: n !< node n
3112  integer(I4B) :: m !< node m
3113  integer(I4B) :: ihc !< 1 = horizontal connection, 0 for vertical
3114  ! -- return
3115  real(dp) :: satthickness !< saturated thickness
3116  !
3117  satthickness = thksatnm(this%ibound(n), &
3118  this%ibound(m), &
3119  this%icelltype(n), &
3120  this%icelltype(m), &
3121  this%inewton, &
3122  ihc, &
3123  this%hnew(n), &
3124  this%hnew(m), &
3125  this%sat(n), &
3126  this%sat(m), &
3127  this%dis%top(n), &
3128  this%dis%top(m), &
3129  this%dis%bot(n), &
3130  this%dis%bot(m))
3131  end function calcsatthickness
3132 
3133  subroutine add_flow_formulation(this, npf_form, form_id)
3134  class(gwfnpftype), intent(inout) :: this !< this NPF instance
3135  class(gwfnpfformulationtype), pointer :: npf_form !< the extended flow calculator
3136  integer(I4B) :: form_id !< the id for the flow formulation
3137 
3138  this%flow_formulations(form_id)%form => npf_form
3139 
3140  end subroutine add_flow_formulation
3141 
3142 end module gwfnpfmodule
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
@ c3d_vertical
vertical connection
Definition: Constants.f90:223
real(dp), parameter dhdry
real dry cell constant
Definition: Constants.f90:94
real(dp), parameter dp9
real constant 9/10
Definition: Constants.f90:72
real(dp), parameter dem10
real constant 1e-10
Definition: Constants.f90:113
real(dp), parameter dem7
real constant 1e-7
Definition: Constants.f90:110
real(dp), parameter dem8
real constant 1e-8
Definition: Constants.f90:111
integer(i4b), parameter lenbigline
maximum length of a big line
Definition: Constants.f90:15
real(dp), parameter dhnoflo
real no flow constant
Definition: Constants.f90:93
integer(i4b), parameter lenvarname
maximum length of a variable name
Definition: Constants.f90:17
real(dp), parameter dhalf
real constant 1/2
Definition: Constants.f90:68
real(dp), parameter dpio180
real constant
Definition: Constants.f90:130
real(dp), parameter dem6
real constant 1e-6
Definition: Constants.f90:109
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
real(dp), parameter dem9
real constant 1e-9
Definition: Constants.f90:112
real(dp), parameter dem2
real constant 1e-2
Definition: Constants.f90:105
real(dp), parameter dtwo
real constant 2
Definition: Constants.f90:79
integer(i4b), parameter lenmempath
maximum length of the memory path
Definition: Constants.f90:27
real(dp), parameter done
real constant 1
Definition: Constants.f90:76
This module contains stateless conductance functions.
real(dp) function, public thksatnm(ibdn, ibdm, ictn, ictm, iupstream, ihc, hn, hm, satn, satm, topn, topm, botn, botm)
Calculate wetted cell thickness at interface between two cells.
real(dp) function, public condmean(k1, k2, thick1, thick2, cl1, cl2, width, iavgmeth)
Calculate the conductance between two cells.
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.
@, public ccond_hmean
Harmonic mean.
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.
integer(i4b), parameter, public default_flow
Definition: GwfNpfExt.f90:7
integer(i4b), parameter, public max_ext_flow_forms
Definition: GwfNpfExt.f90:10
subroutine set_options(this, options)
Set options in the NPF object.
Definition: gwf-npf.f90:1681
subroutine npf_save_model_flows(this, flowja, icbcfl, icbcun)
Record flowja and calculate specific discharge if requested.
Definition: gwf-npf.f90:1135
subroutine source_options(this)
Update simulation options from input mempath.
Definition: gwf-npf.f90:1590
real(dp) function calc_initial_sat(this, n)
Calculate initial saturation for the given node.
Definition: gwf-npf.f90:2374
subroutine calc_condsat(this, node, upperOnly)
Calculate CONDSAT array entries for the given node.
Definition: gwf-npf.f90:2278
subroutine rewet_check(this, kiter, node, hm, ibdm, ihc, hnew, irewet)
Determine if a cell should rewet.
Definition: gwf-npf.f90:2495
integer(i4b) function calc_max_conns(this)
Calculate the maximum number of connections for any cell.
Definition: gwf-npf.f90:3008
subroutine npf_mc(this, moffset, matrix_sln)
Map connections and construct iax, jax, and idxglox.
Definition: gwf-npf.f90:303
subroutine npf_fc(this, kiter, matrix_sln, idxglo, rhs, hnew)
Formulate coefficients.
Definition: gwf-npf.f90:562
subroutine npf_ac(this, moffset, sparse)
Add connections for extended neighbors to the sparse matrix.
Definition: gwf-npf.f90:289
subroutine sgwf_npf_wetdry(this, kiter, hnew)
Perform wetting and drying.
Definition: gwf-npf.f90:2389
subroutine source_griddata(this)
Update simulation griddata from input mempath.
Definition: gwf-npf.f90:1820
subroutine default_flow_fc(this, kiter, matrix_sln, idxglo, rhs, hnew)
Fill coefficients for the default conductance formulation.
Definition: gwf-npf.f90:684
subroutine npf_nur(this, neqmod, x, xtemp, dx, inewtonur, dxmax, locmax)
Under-relaxation.
Definition: gwf-npf.f90:921
subroutine add_flow_formulation(this, npf_form, form_id)
Definition: gwf-npf.f90:3134
subroutine sav_spdis(this, ibinun)
Save specific discharge in binary format to ibinun.
Definition: gwf-npf.f90:2938
subroutine sgwf_npf_thksat(this, n, hn, thksat)
Fractional cell saturation.
Definition: gwf-npf.f90:1034
subroutine preprocess_input(this)
preprocess the NPF input data
Definition: gwf-npf.f90:2076
subroutine set_edge_properties(this, nodedge, ihcedge, q, area, nx, ny, distance)
Provide the npf package with edge properties.
Definition: gwf-npf.f90:3036
subroutine prepare_edge_lookup(this)
Definition: gwf-npf.f90:3064
subroutine npf_da(this)
Deallocate variables.
Definition: gwf-npf.f90:1211
subroutine log_griddata(this, found)
Write dimensions to list file.
Definition: gwf-npf.f90:1770
real(dp) function hy_eff(this, n, m, ihc, ipos, vg)
Calculate the effective hydraulic conductivity for the n-m connection.
Definition: gwf-npf.f90:2608
subroutine calc_spdis(this, flowja)
Calculate the 3 components of specific discharge at the cell center.
Definition: gwf-npf.f90:2687
subroutine, public npf_cr(npfobj, name_model, input_mempath, inunit, iout)
Create a new NPF object. Pass a inunit value of 0 if npf data will initialized from memory.
Definition: gwf-npf.f90:189
subroutine increase_edge_count(this, nedges)
Reserve space for nedges cells that have an edge on them.
Definition: gwf-npf.f90:2998
subroutine npf_fn(this, kiter, matrix_sln, idxglo, rhs, hnew)
Fill newton terms.
Definition: gwf-npf.f90:748
subroutine log_options(this, found)
Log npf options sourced from the input mempath.
Definition: gwf-npf.f90:1516
subroutine npf_print_model_flows(this, ibudfl, flowja)
Print budget.
Definition: gwf-npf.f90:1172
subroutine allocate_arrays(this, ncells, njas)
Allocate npf arrays.
Definition: gwf-npf.f90:1438
subroutine sav_sat(this, ibinun)
Save saturation in binary format to ibinun.
Definition: gwf-npf.f90:2966
subroutine prepcheck(this)
Initialize and check NPF data.
Definition: gwf-npf.f90:1915
subroutine npf_df(this, dis, xt3d, ingnc, invsc, npf_options)
Define the NPF package instance.
Definition: gwf-npf.f90:236
subroutine highest_cell_saturation(this, n, m, hn, hm, satn, satm)
Calculate dry cell saturation.
Definition: gwf-npf.f90:719
subroutine cq_default_flow(this, n, m, ipos, flowja, hnew)
Definition: gwf-npf.f90:1016
subroutine npf_ad(this, nodes, hold, hnew, irestore)
Advance.
Definition: gwf-npf.f90:431
subroutine sgwf_npf_wdmsg(this, icode, ncnvrt, nodcnvrt, acnvrt, ihdcnv, kiter, n)
Print wet/dry message.
Definition: gwf-npf.f90:2556
subroutine sgwf_npf_qcalc(this, n, m, hn, hm, icon, qnm)
Flow between two cells.
Definition: gwf-npf.f90:1057
subroutine npf_rp(this)
Read and prepare method for package.
Definition: gwf-npf.f90:416
real(dp) function calcsatthickness(this, n, m, ihc)
Calculate saturated thickness between cell n and m.
Definition: gwf-npf.f90:3109
subroutine store_original_k_arrays(this, ncells, njas)
@ brief Store backup copy of hydraulic conductivity when the VSC package is activate
Definition: gwf-npf.f90:1418
subroutine fc_default_flow(this, n, m, ipos, matrix_sln, rhs, idxglo, hnew)
Calculate and add coefficients using the.
Definition: gwf-npf.f90:590
subroutine allocate_scalars(this)
@ brief Allocate scalars
Definition: gwf-npf.f90:1319
subroutine npf_cq(this, hnew, flowja)
Calculate flowja.
Definition: gwf-npf.f90:965
subroutine fn_default_flow(this, n, m, ipos, matrix_sln, rhs, idxglo, hnew)
Definition: gwf-npf.f90:812
subroutine npf_ar(this, ic, vsc, ibound, hnew)
Allocate and read this NPF instance.
Definition: gwf-npf.f90:317
subroutine default_flow_cf(this, kiter)
Calculate coefficients for the default conductance formulation.
Definition: gwf-npf.f90:524
subroutine check_options(this)
Check for conflicting NPF options.
Definition: gwf-npf.f90:1699
subroutine cf_default_flow(this, kiter, n)
Calculate coefficients using the.
Definition: gwf-npf.f90:541
subroutine npf_cf(this, kiter, nodes, hnew)
Calculate coefficients.
Definition: gwf-npf.f90:495
subroutine default_flow_fn(this, kiter, matrix_sln, idxglo, rhs, hnew)
Fill newton terms for the default conductance formulation.
Definition: gwf-npf.f90:783
subroutine default_flow_cq(this, hnew, flowja)
Calculate flows for the default conductance formulation.
Definition: gwf-npf.f90:994
General-purpose hydrogeologic functions.
Definition: HGeoUtil.f90:2
real(dp) function, public hyeff(k11, k22, k33, ang1, ang2, ang3, vg1, vg2, vg3, iavgmeth)
Calculate the effective horizontal hydraulic conductivity from an ellipse using a specified direction...
Definition: HGeoUtil.f90:31
This module defines variable data types.
Definition: kind.f90:8
character(len=lenmempath) function create_mem_path(component, subcomponent, context)
returns the path to the memory object
subroutine, public memorystore_remove(component, subcomponent, context)
subroutine, public memorystore_release(varname, memory_path)
Release a single variable from the memory store.
subroutine, public get_isize(name, mem_path, isize)
@ brief Get the number of elements for this variable
This module contains the base numerical package type.
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_warning(msg, substring)
Store warning message.
Definition: Sim.f90:237
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:204
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string
character(len=linelength) idm_context
character(len=maxcharlen) warnmsg
warning message string
real(dp) function squadraticsaturation(top, bot, x, eps)
@ brief sQuadraticSaturation
real(dp) function squadraticsaturationderivative(top, bot, x, eps)
@ brief Derivative of the quadratic saturation function
This module contains the SourceCommonModule.
Definition: SourceCommon.f90:7
logical(lgp) function, public filein_fname(filename, tagname, input_mempath, input_fname)
enforce and set a single input filename provided via FILEIN keyword
integer(i4b), pointer, public kstp
current time step number
Definition: tdis.f90:27
integer(i4b), pointer, public kper
current stress period number
Definition: tdis.f90:26
This module contains time-varying conductivity package methods.
Definition: gwf-tvk.f90:8
subroutine, public tvk_cr(tvk, name_model, mempath, inunit, iout)
Create a new TvkType object.
Definition: gwf-tvk.f90:56
subroutine, public xt3d_cr(xt3dobj, name_model, inunit, iout, ldispopt)
Create a new xt3d object.
This class is used to store a single deferred-length character string. It was designed to work in an ...
Definition: CharString.f90:23
Unstructured grid discretization.
Definition: Disu.f90:30
Container to allow arrays of polymorphic extension pointers.
Definition: GwfNpfExt.f90:28
Abstract flow formulation that additively contributes terms.
Definition: GwfNpfExt.f90:18
Default conductance flow formulation.
Definition: gwf-npf.f90:174
Data structure and helper methods for passing NPF options into npf_df, as an alternative to reading t...
Helper class with work arrays for the SPDIS calculation in NPF.