MODFLOW 6 version 6.9.0.dev0
USGS Modular Hydrologic Model
Loading...
Searching...
No Matches
gwf-lak.f90
Go to the documentation of this file.
2 !
3 use kindmodule, only: dp, i4b, lgp
20 use bndmodule, only: bndtype
21 use bndextmodule, only: bndexttype
24 use observemodule, only: observetype
25 use obsmodule, only: obstype
26 use geomutilmodule, only: get_node
29 use basedismodule, only: disbasetype
33 use mathutilmodule, only: is_close
35 use openspecmodule, only: access, form
39 !
40 implicit none
41 !
42 private
43 public :: laktype
44 public :: lak_create
45 !
46 character(len=LENFTYPE) :: ftype = 'LAK'
47 character(len=LENPACKAGENAME) :: text = ' LAK'
48 !
50 real(dp), dimension(:), pointer, contiguous :: tabstage => null()
51 real(dp), dimension(:), pointer, contiguous :: tabvolume => null()
52 real(dp), dimension(:), pointer, contiguous :: tabsarea => null()
53 real(dp), dimension(:), pointer, contiguous :: tabwarea => null()
54 end type laktabtype
55 !
56 !> @brief input context runtime pointers for LAK
57 !!
58 !! Groups all input context PERIOD and OUTLETS array pointers used at
59 !! runtime. All pointers are set once in lak_ar and remain valid for
60 !! the simulation lifetime.
61 !<
63 ! -- period
64 integer(I4B), pointer :: nbound => null()
65 integer(I4B), dimension(:), pointer, contiguous :: ifno => null()
66 type(characterstringtype), dimension(:), pointer, contiguous :: &
67 setting => null()
68 type(characterstringtype), dimension(:), pointer, contiguous :: &
69 status => null()
70 type(characterstringtype), dimension(:), pointer, contiguous :: &
71 auxname => null()
72 real(dp), dimension(:), pointer, contiguous :: &
73 auxval => null()
74 ! -- outlets (static, TS-linked)
75 integer(I4B), dimension(:), pointer, contiguous :: outletno => null()
76 real(dp), dimension(:), pointer, contiguous :: outlets_invert => null()
77 real(dp), dimension(:), pointer, contiguous :: outlets_width => null()
78 real(dp), dimension(:), pointer, contiguous :: outlets_rough => null()
79 real(dp), dimension(:), pointer, contiguous :: outlets_slope => null()
80 integer(I4B), dimension(:), pointer :: invert_tslink => null() !< nonzero for OUTLETS_INVERT rows linked to a time series
81 integer(I4B), dimension(:), pointer :: width_tslink => null() !< nonzero for OUTLETS_WIDTH rows linked to a time series
82 integer(I4B), dimension(:), pointer :: rough_tslink => null() !< nonzero for OUTLETS_ROUGH rows linked to a time series
83 integer(I4B), dimension(:), pointer :: slope_tslink => null() !< nonzero for OUTLETS_SLOPE rows linked to a time series
84 contains
85 procedure :: init => lak_input_init
86 procedure :: destroy => lak_input_destroy
87 end type lakinputtype
88 !
89 type, extends(bndexttype) :: laktype
90 ! -- scalars
91 ! -- characters
92 character(len=16), dimension(:), pointer, contiguous :: clakbudget => null()
93 character(len=16), dimension(:), pointer, contiguous :: cauxcbc => null()
94 ! -- control variables
95 ! -- integers
96 integer(I4B), pointer :: iprhed => null()
97 integer(I4B), pointer :: istageout => null()
98 integer(I4B), pointer :: ibudgetout => null()
99 integer(I4B), pointer :: ibudcsv => null()
100 integer(I4B), pointer :: ipakcsv => null()
101 character(len=:), allocatable :: pakcsvfile !< requested PACKAGE_CONVERGENCE file, opened in lak_ar once the IMPLICIT option is known
102 integer(I4B), pointer :: cbcauxitems => null()
103 integer(I4B), pointer :: nlakes => null()
104 integer(I4B), pointer :: noutlets => null()
105 integer(I4B), pointer :: ntables => null()
106 real(dp), pointer :: convlength => null()
107 real(dp), pointer :: convtime => null()
108 real(dp), pointer :: outdmax => null()
109 integer(I4B), pointer :: igwhcopt => null()
110 integer(I4B), pointer :: iconvchk => null()
111 integer(I4B), pointer :: maxlakit => null() !< maximum number of iterations in LAK solve
112 real(dp), pointer :: surfdep => null()
113 real(dp), pointer :: dmaxchg => null()
114 real(dp), pointer :: delh => null()
115 integer(I4B), pointer :: check_attr => null()
116 ! -- implicit formulation: solve the lake stage as an unknown in the
117 ! groundwater flow matrix instead of by the legacy substitution iteration
118 integer(I4B), pointer :: iimplicit => null() !< flag: solve lake stage in the gwf matrix
119 integer(I4B), pointer :: iforceleg => null() !< flag (dev): force every active lake onto the legacy solver
120 integer(I4B), pointer :: iforceleglak => null() !< lake (dev) forced onto the legacy solver, 0 if none
121 ! -- for budgets
122 integer(I4B), pointer :: bditems => null()
123 ! -- vectors
124 ! -- lake data
125 integer(I4B), dimension(:), pointer, contiguous :: nlakeconn => null()
126 integer(I4B), dimension(:), pointer, contiguous :: idxlakeconn => null()
127 integer(I4B), dimension(:), pointer, contiguous :: ntabrow => null()
128 real(dp), dimension(:), pointer, contiguous :: strt => null()
129 real(dp), dimension(:), pointer, contiguous :: laketop => null()
130 real(dp), dimension(:), pointer, contiguous :: lakebot => null()
131 real(dp), dimension(:), pointer, contiguous :: sareamax => null()
132 character(len=LENBOUNDNAME), dimension(:), pointer, &
133 contiguous :: lakename => null()
134 character(len=8), dimension(:), pointer, contiguous :: status => null()
135 real(dp), dimension(:), pointer, contiguous :: avail => null()
136 real(dp), dimension(:), pointer, contiguous :: lkgwsink => null()
137 real(dp), dimension(:), pointer, contiguous :: stage => null()
138 real(dp), dimension(:), pointer, contiguous :: rainfall => null()
139 real(dp), dimension(:), pointer, contiguous :: evaporation => null()
140 real(dp), dimension(:), pointer, contiguous :: runoff => null()
141 real(dp), dimension(:), pointer, contiguous :: inflow => null()
142 real(dp), dimension(:), pointer, contiguous :: withdrawal => null()
143 !
144 ! -- table data
145 integer(I4B), dimension(:), pointer, contiguous :: ialaktab => null()
146 real(dp), dimension(:), pointer, contiguous :: tabstage => null()
147 real(dp), dimension(:), pointer, contiguous :: tabvolume => null()
148 real(dp), dimension(:), pointer, contiguous :: tabsarea => null()
149 real(dp), dimension(:), pointer, contiguous :: tabwarea => null()
150 !
151 ! -- lake solution data
152 integer(I4B), dimension(:), pointer, contiguous :: ncncvr => null()
153 ! -- IMPLICIT legacy solve: solve flagged lakes by substitution,
154 ! and a per-lake count of consecutive non-converging outer iterations used
155 ! to decide when to switch a stalled IMPLICIT lake to the legacy solver
156 integer(I4B), dimension(:), pointer, contiguous :: ilegacy => null()
157 integer(I4B), dimension(:), pointer, contiguous :: nstuck => null()
158 real(dp), dimension(:), pointer, contiguous :: surfin => null()
159 real(dp), dimension(:), pointer, contiguous :: surfout => null()
160 real(dp), dimension(:), pointer, contiguous :: surfout1 => null()
161 real(dp), dimension(:), pointer, contiguous :: precip => null()
162 real(dp), dimension(:), pointer, contiguous :: precip1 => null()
163 real(dp), dimension(:), pointer, contiguous :: evap => null()
164 real(dp), dimension(:), pointer, contiguous :: evap1 => null()
165 real(dp), dimension(:), pointer, contiguous :: evapo => null()
166 real(dp), dimension(:), pointer, contiguous :: withr => null()
167 real(dp), dimension(:), pointer, contiguous :: withr1 => null()
168 real(dp), dimension(:), pointer, contiguous :: flwin => null()
169 real(dp), dimension(:), pointer, contiguous :: flwiter => null()
170 real(dp), dimension(:), pointer, contiguous :: flwiter1 => null()
171 real(dp), dimension(:), pointer, contiguous :: seep => null()
172 real(dp), dimension(:), pointer, contiguous :: seep1 => null()
173 real(dp), dimension(:), pointer, contiguous :: seep0 => null()
174 real(dp), dimension(:), pointer, contiguous :: stageiter => null()
175 real(dp), dimension(:), pointer, contiguous :: chterm => null()
176 !
177 ! -- lake convergence
178 integer(I4B), dimension(:), pointer, contiguous :: iseepc => null()
179 integer(I4B), dimension(:), pointer, contiguous :: idhc => null()
180 real(dp), dimension(:), pointer, contiguous :: en1 => null()
181 real(dp), dimension(:), pointer, contiguous :: en2 => null()
182 real(dp), dimension(:), pointer, contiguous :: r1 => null()
183 real(dp), dimension(:), pointer, contiguous :: r2 => null()
184 real(dp), dimension(:), pointer, contiguous :: dh0 => null()
185 real(dp), dimension(:), pointer, contiguous :: s0 => null()
186 real(dp), dimension(:), pointer, contiguous :: qgwf0 => null()
187 ! -- groundwater flow matrix bookkeeping for the implicit formulation
188 integer(I4B), dimension(:), pointer, contiguous :: idxlocnode => null() !< local index of each lake row in x/rhs
189 integer(I4B), dimension(:), pointer, contiguous :: idxdiag => null() !< position of lake-row diagonal (per lake)
190 integer(I4B), dimension(:), pointer, contiguous :: idxoffdglo => null() !< position of lake-row -> gwf column (per connection)
191 integer(I4B), dimension(:), pointer, contiguous :: idxsymdglo => null() !< position of gwf-row diagonal (per connection)
192 integer(I4B), dimension(:), pointer, contiguous :: idxsymoffdglo => null() !< position of gwf-row -> lake column (per connection)
193 !
194 ! -- lake connection data
195 integer(I4B), dimension(:), pointer, contiguous :: imap => null()
196 integer(I4B), dimension(:), pointer, contiguous :: gwfconn => null()
197 integer(I4B), dimension(:), pointer, contiguous :: nodesontop => null()
198 integer(I4B), dimension(:), pointer, contiguous :: ictype => null()
199 real(dp), dimension(:), pointer, contiguous :: bedleak => null()
200 real(dp), dimension(:), pointer, contiguous :: belev => null()
201 real(dp), dimension(:), pointer, contiguous :: telev => null()
202 real(dp), dimension(:), pointer, contiguous :: connlength => null()
203 real(dp), dimension(:), pointer, contiguous :: connwidth => null()
204 real(dp), dimension(:), pointer, contiguous :: sarea => null()
205 real(dp), dimension(:), pointer, contiguous :: warea => null()
206 real(dp), dimension(:), pointer, contiguous :: satcond => null()
207 real(dp), dimension(:), pointer, contiguous :: simcond => null()
208 real(dp), dimension(:), pointer, contiguous :: simlakgw => null()
209 !
210 ! -- lake outlet data
211 integer(I4B), dimension(:), pointer, contiguous :: lakein => null()
212 integer(I4B), dimension(:), pointer, contiguous :: lakeout => null()
213 integer(I4B), dimension(:), pointer, contiguous :: iouttype => null()
214 real(dp), dimension(:), pointer, contiguous :: outrate => null()
215 real(dp), dimension(:), pointer, contiguous :: outinvert => null()
216 real(dp), dimension(:), pointer, contiguous :: outwidth => null()
217 real(dp), dimension(:), pointer, contiguous :: outrough => null()
218 real(dp), dimension(:), pointer, contiguous :: outslope => null()
219 real(dp), dimension(:), pointer, contiguous :: simoutrate => null()
220 ! -- true once a PERIOD-block setting has overridden the OUTLETS
221 ! block's own (separately time-series-linked) baseline geometry for
222 ! that outlet; prevents lak_ad's OUTLETS resync from clobbering it
223 logical(LGP), dimension(:), pointer, contiguous :: outlet_invert_set => null()
224 logical(LGP), dimension(:), pointer, contiguous :: outlet_width_set => null()
225 logical(LGP), dimension(:), pointer, contiguous :: outlet_rough_set => null()
226 logical(LGP), dimension(:), pointer, contiguous :: outlet_slope_set => null()
227 !
228 ! -- lake output data
229 real(dp), dimension(:), pointer, contiguous :: qauxcbc => null()
230 real(dp), dimension(:), pointer, contiguous :: dbuff => null()
231 real(dp), dimension(:), pointer, contiguous :: qleak => null()
232 ! -- connected-cell head at the previous outer iteration (per connection),
233 ! used by the IMPLICIT legacy-switch detection to compare a lake's stage change
234 ! against the change in its connected aquifer heads
235 real(dp), dimension(:), pointer, contiguous :: holdconn => null()
236 real(dp), dimension(:), pointer, contiguous :: qsto => null()
237 !
238 ! -- pointer to gwf iss and gwf hk
239 integer(I4B), pointer :: gwfiss => null()
240 real(dp), dimension(:), pointer, contiguous :: gwfk11 => null()
241 real(dp), dimension(:), pointer, contiguous :: gwfk33 => null()
242 real(dp), dimension(:), pointer, contiguous :: gwfsat => null()
243 integer(I4B), pointer :: gwfik33 => null()
244 !
245 ! -- package x, xold, and ibound
246 integer(I4B), dimension(:), pointer, contiguous :: iboundpak => null() !package ibound
247 real(dp), dimension(:), pointer, contiguous :: xnewpak => null() !package x vector
248 real(dp), dimension(:), pointer, contiguous :: xoldpak => null() !package xold vector
249 !
250 ! -- lake budget object
251 type(budgetobjecttype), pointer :: budobj => null()
252 !
253 ! -- input context runtime pointers (PERIOD + OUTLETS arrays)
254 type(lakinputtype) :: input
255 !
256 ! -- lake table objects
257 type(tabletype), pointer :: stagetab => null()
258 type(tabletype), pointer :: pakcsvtab => null()
259 !
260 ! -- density variables
261 integer(I4B), pointer :: idense
262 real(dp), dimension(:, :), pointer, contiguous :: denseterms => null()
263 !
264 ! -- viscosity variables
265 real(dp), dimension(:, :), pointer, contiguous :: viscratios => null() !< viscosity ratios (1: lak vsc ratio; 2: gwf vsc ratio)
266 !
267 ! -- type bound procedures
268
269 contains
270
276 procedure :: read_initial_attr => lak_read_initial_attr
278 procedure :: bnd_ar => lak_ar
279 procedure :: bnd_ac => lak_ac
280 procedure :: bnd_mc => lak_mc
281 procedure :: bnd_rp => lak_rp
282 procedure :: bnd_ad => lak_ad
283 procedure :: bnd_cf => lak_cf
284 procedure :: bnd_fc => lak_fc
285 procedure :: bnd_fn => lak_fn
286 procedure :: bnd_nur => lak_nur
287 procedure :: bnd_cc => lak_cc
288 procedure, private :: lak_set_legacy
289 procedure, private :: lak_check_disconnected
290 procedure :: bnd_cq => lak_cq
293 procedure :: bnd_ot_dv => lak_ot_dv
295 procedure :: bnd_da => lak_da
296 procedure :: define_listlabel
297 ! -- methods for observations
298 procedure, public :: bnd_obs_supported => lak_obs_supported
299 procedure, public :: bnd_df_obs => lak_df_obs
300 procedure, public :: bnd_rp_obs => lak_rp_obs
301 procedure, public :: bnd_bd_obs => lak_bd_obs
302 ! -- private procedures
303 procedure, private :: lak_source_packagedata
304 procedure, private :: lak_source_connectiondata
305 procedure, private :: lak_source_outlets
306 procedure, private :: lak_source_tables
307 procedure, private :: lak_source_table
308 procedure, private :: lak_check_valid
309 procedure, private :: lak_set_nonneg_value
310 procedure, private :: lak_set_attribute_error
311 procedure, private :: lak_bound_update
312 procedure, private :: lak_calculate_sarea
313 procedure, private :: lak_calculate_warea
314 procedure, private :: lak_calculate_conn_warea
315 procedure, public :: lak_calculate_vol
316 procedure, private :: lak_calculate_conductance
317 procedure, private :: lak_calculate_cond_head
318 procedure, private :: lak_calculate_conn_conductance
319 procedure, private :: lak_calculate_exchange
320 procedure, private :: lak_calculate_conn_exchange
322 procedure, private :: lak_estimate_conn_exchange
323 procedure, private :: lak_calculate_storagechange
324 procedure, private :: lak_calculate_rainfall
325 procedure, private :: lak_calculate_runoff
326 procedure, private :: lak_calculate_inflow
327 procedure, private :: lak_calculate_external
328 procedure, private :: lak_calculate_withdrawal
329 procedure, private :: lak_calculate_evaporation
330 procedure, private :: lak_calculate_outlet_inflow
331 procedure, private :: lak_calculate_outlet_outflow
332 procedure, private :: lak_get_internal_inlet
333 procedure, private :: lak_get_internal_outlet
334 procedure, private :: lak_get_external_outlet
335 procedure, private :: lak_get_internal_mover
336 procedure, private :: lak_get_external_mover
337 procedure, private :: lak_get_outlet_tomover
338 procedure, private :: lak_accumulate_chterm
339 procedure, private :: lak_vol2stage
340 procedure, private :: lak_solve
341 procedure, private :: lak_solve_single
342 procedure, private :: lak_estimate_seepage_single
343 procedure, private :: lak_fc_implicit
344 procedure, private :: lak_budget_nogwf
345 procedure, private :: lak_outlet_outflow_rate
346 procedure, private :: lak_bisection
347 procedure, private :: lak_calculate_available
348 procedure, private :: lak_calculate_residual
349 procedure, private :: lak_linear_interpolation
350 procedure, private :: lak_setup_budobj
351 procedure, private :: lak_fill_budobj
352 procedure, private :: laktables_to_vectors
353 ! -- table
354 procedure, private :: lak_setup_tableobj
355 ! -- density
357 procedure, private :: lak_calculate_density_exchange
358 ! -- viscosity
360 end type laktype
361
362 ! -- implicit-formulation procedures, implemented in the gwf-lak-implicit
363 ! submodule (submodules/gwf-lak-implicit.f90)
364 interface
365 module subroutine lak_budget_nogwf(this, n, stage, b)
366 class(laktype), intent(inout) :: this
367 integer(I4B), intent(in) :: n
368 real(dp), intent(in) :: stage
369 real(dp), intent(inout) :: b
370 end subroutine
371 end interface
372
373 interface
374 module subroutine lak_fc_implicit(this, rhs, matrix_sln)
375 class(laktype) :: this
376 real(dp), dimension(:), intent(inout) :: rhs
377 class(matrixbasetype), pointer :: matrix_sln
378 end subroutine
379 end interface
380
381 interface
382 module subroutine lak_set_legacy(this, kiter, icnvgmod)
383 class(laktype), intent(inout) :: this
384 integer(I4B), intent(in) :: kiter !< outer (Picard) iteration number
385 integer(I4B), intent(in) :: icnvgmod !< 0 if the model has not converged
386 end subroutine
387 end interface
388
389 interface
390 module subroutine lak_check_disconnected(this)
391 class(laktype), intent(inout) :: this
392 end subroutine
393 end interface
394
395contains
396
397 !> @brief Create a new LAK Package and point bndobj to the new package
398 !<
399 subroutine lak_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, &
400 mempath)
401 ! -- modules
403 ! -- dummy
404 class(bndtype), pointer :: packobj
405 integer(I4B), intent(in) :: id
406 integer(I4B), intent(in) :: ibcnum
407 integer(I4B), intent(in) :: inunit
408 integer(I4B), intent(in) :: iout
409 character(len=*), intent(in) :: namemodel
410 character(len=*), intent(in) :: pakname
411 character(len=*), intent(in) :: mempath
412 ! -- local
413 type(laktype), pointer :: lakobj
414 !
415 ! -- allocate the object and assign values to object variables
416 allocate (lakobj)
417 packobj => lakobj
418 !
419 ! -- create name and memory path
420 call packobj%set_names(ibcnum, namemodel, pakname, ftype, mempath)
421 packobj%text = text
422 !
423 ! -- allocate scalars
424 call lakobj%lak_allocate_scalars()
425 !
426 ! -- initialize package
427 call packobj%pack_initialize()
428 !
429 packobj%inunit = inunit
430 packobj%iout = iout
431 packobj%id = id
432 packobj%ibcnum = ibcnum
433 packobj%ncolbnd = 3
434 packobj%iscloc = 0 ! not supported
435 packobj%isadvpak = 1
436 packobj%ictMemPath = create_mem_path(namemodel, 'NPF')
437 end subroutine lak_create
438
439 !> @brief Allocate scalar members
440 !<
441 subroutine lak_allocate_scalars(this)
442 ! -- dummy
443 class(laktype), intent(inout) :: this
444 !
445 ! -- call standard BndExtType allocate scalars
446 call this%BndExtType%allocate_scalars()
447 !
448 ! -- allocate the object and assign values to object variables
449 call mem_allocate(this%iprhed, 'IPRHED', this%memoryPath)
450 call mem_allocate(this%istageout, 'ISTAGEOUT', this%memoryPath)
451 call mem_allocate(this%ibudgetout, 'IBUDGETOUT', this%memoryPath)
452 call mem_allocate(this%ibudcsv, 'IBUDCSV', this%memoryPath)
453 call mem_allocate(this%ipakcsv, 'IPAKCSV', this%memoryPath)
454 call mem_allocate(this%nlakes, 'NLAKES', this%memoryPath)
455 call mem_allocate(this%noutlets, 'NOUTLETS', this%memoryPath)
456 call mem_allocate(this%ntables, 'NTABLES', this%memoryPath)
457 call mem_allocate(this%convlength, 'CONVLENGTH', this%memoryPath)
458 call mem_allocate(this%convtime, 'CONVTIME', this%memoryPath)
459 call mem_allocate(this%outdmax, 'OUTDMAX', this%memoryPath)
460 call mem_allocate(this%igwhcopt, 'IGWHCOPT', this%memoryPath)
461 call mem_allocate(this%iconvchk, 'ICONVCHK', this%memoryPath)
462 call mem_allocate(this%maxlakit, 'MAXLAKIT', this%memoryPath)
463 call mem_allocate(this%surfdep, 'SURFDEP', this%memoryPath)
464 call mem_allocate(this%dmaxchg, 'DMAXCHG', this%memoryPath)
465 call mem_allocate(this%delh, 'DELH', this%memoryPath)
466 call mem_allocate(this%check_attr, 'CHECK_ATTR', this%memoryPath)
467 call mem_allocate(this%iimplicit, 'IIMPLICIT', this%memoryPath)
468 call mem_allocate(this%iforceleg, 'IFORCELEG', this%memoryPath)
469 call mem_allocate(this%iforceleglak, 'IFORCELEGLAK', this%memoryPath)
470 call mem_allocate(this%bditems, 'BDITEMS', this%memoryPath)
471 call mem_allocate(this%cbcauxitems, 'CBCAUXITEMS', this%memoryPath)
472 call mem_allocate(this%idense, 'IDENSE', this%memoryPath)
473 !
474 ! -- Set values
475 this%iprhed = 0
476 this%istageout = 0
477 this%ibudgetout = 0
478 this%ibudcsv = 0
479 this%ipakcsv = 0
480 this%nlakes = 0
481 this%noutlets = 0
482 this%ntables = 0
483 this%convlength = done
484 this%convtime = done
485 this%outdmax = dzero
486 this%igwhcopt = 0
487 this%iconvchk = 1
488 this%maxlakit = maxadpit
489 this%surfdep = dzero
490 this%dmaxchg = dem5
491 this%delh = dp999 * this%dmaxchg
492 this%iimplicit = 0
493 this%iforceleg = 0
494 this%iforceleglak = 0
495 this%bditems = 11
496 this%cbcauxitems = 1
497 this%idense = 0
498 this%ivsc = 0
499 end subroutine lak_allocate_scalars
500
501 !> @brief Allocate scalar members
502 !<
503 subroutine lak_allocate_arrays(this)
504 ! -- modules
505 ! -- dummy
506 class(laktype), intent(inout) :: this
507 ! -- local
508 integer(I4B) :: i
509 !
510 ! -- call standard BndExtType allocate arrays
511 call this%BndExtType%allocate_arrays()
512 !
513 ! -- allocate featureauxvar and set pkg_ifno/pkg_auxvar input context pointers
514 call this%BndExtType%allocate_featureauxvar()
515 !
516 ! -- allocate character array for budget text
517 allocate (this%clakbudget(this%bditems))
518 !
519 !-- fill clakbudget
520 this%clakbudget(1) = ' GWF'
521 this%clakbudget(2) = ' RAINFALL'
522 this%clakbudget(3) = ' EVAPORATION'
523 this%clakbudget(4) = ' RUNOFF'
524 this%clakbudget(5) = ' EXT-INFLOW'
525 this%clakbudget(6) = ' WITHDRAWAL'
526 this%clakbudget(7) = ' EXT-OUTFLOW'
527 this%clakbudget(8) = ' STORAGE'
528 this%clakbudget(9) = ' CONSTANT'
529 this%clakbudget(10) = ' FROM-MVR'
530 this%clakbudget(11) = ' TO-MVR'
531 !
532 ! -- allocate and initialize dbuff
533 if (this%istageout > 0) then
534 call mem_allocate(this%dbuff, this%nlakes, 'DBUFF', this%memoryPath)
535 do i = 1, this%nlakes
536 this%dbuff(i) = dzero
537 end do
538 else
539 call mem_allocate(this%dbuff, 0, 'DBUFF', this%memoryPath)
540 end if
541 !
542 ! -- allocate character array for budget text
543 allocate (this%cauxcbc(this%cbcauxitems))
544 !
545 ! -- allocate and initialize qauxcbc
546 call mem_allocate(this%qauxcbc, this%cbcauxitems, 'QAUXCBC', this%memoryPath)
547 do i = 1, this%cbcauxitems
548 this%qauxcbc(i) = dzero
549 end do
550 !
551 ! -- allocate qleak and qsto
552 call mem_allocate(this%qleak, this%maxbound, 'QLEAK', this%memoryPath)
553 do i = 1, this%maxbound
554 this%qleak(i) = dzero
555 end do
556 ! -- holdconn is only used by the implicit legacy-switch detector; allocate it at
557 ! size 0 otherwise so legacy LAK runs do not pay the maxbound memory cost
558 if (this%iimplicit /= 0) then
559 call mem_allocate(this%holdconn, this%maxbound, 'HOLDCONN', this%memoryPath)
560 do i = 1, this%maxbound
561 this%holdconn(i) = dzero
562 end do
563 else
564 call mem_allocate(this%holdconn, 0, 'HOLDCONN', this%memoryPath)
565 end if
566 call mem_allocate(this%qsto, this%nlakes, 'QSTO', this%memoryPath)
567 do i = 1, this%nlakes
568 this%qsto(i) = dzero
569 end do
570 !
571 ! -- allocate denseterms to size 0
572 call mem_allocate(this%denseterms, 3, 0, 'DENSETERMS', this%memoryPath)
573 !
574 ! -- allocate viscratios to size 0
575 call mem_allocate(this%viscratios, 2, 0, 'VISCRATIOS', this%memoryPath)
576 end subroutine lak_allocate_arrays
577
578 !> @brief Alias deprecated LAK variable names to their current storage
579 !!
580 !! IDM integration (#3021) moved several lake and outlet variables into the
581 !! input context, renaming some, and renamed the lake connection cell array.
582 !! The legacy solver refactor (#2976) renamed the fallback variables. These
583 !! aliases share memory with the current variables so that programs
584 !! addressing them through the API by their old package-path names continue
585 !! to resolve; each use is reported as deprecated. Outlet names are only
586 !! aliased when outlets are present.
587 !<
588 subroutine lak_checkin_deprecated_names(this)
589 ! -- modules
592 ! -- dummy
593 class(laktype), intent(inout) :: this
594 ! -- local
595 real(DP), dimension(:, :), pointer, contiguous :: aux => null()
596 integer(I4B) :: isize
597 ! -- code
598 !
599 ! -- lake period data
600 call mem_alias_deprecated(this%stage, 'STAGE', this%memoryPath, &
601 'STAGE', this%input_mempath, '6.8.2')
602 call mem_alias_deprecated(this%rainfall, 'RAINFALL', this%memoryPath, &
603 'RAINFALL', this%input_mempath, '6.8.2')
604 call mem_alias_deprecated(this%evaporation, 'EVAPORATION', &
605 this%memoryPath, 'EVAPORATION', &
606 this%input_mempath, '6.8.2')
607 call mem_alias_deprecated(this%runoff, 'RUNOFF', this%memoryPath, &
608 'RUNOFF', this%input_mempath, '6.8.2')
609 call mem_alias_deprecated(this%inflow, 'INFLOW', this%memoryPath, &
610 'INFLOW', this%input_mempath, '6.8.2')
611 call mem_alias_deprecated(this%withdrawal, 'WITHDRAWAL', this%memoryPath, &
612 'WITHDRAWAL', this%input_mempath, '6.8.2')
613 !
614 ! -- outlet period data
615 call mem_alias_deprecated(this%outrate, 'OUTRATE', this%memoryPath, &
616 'RATE', this%input_mempath, '6.8.2')
617 call mem_alias_deprecated(this%outinvert, 'OUTINVERT', this%memoryPath, &
618 'INVERT', this%input_mempath, '6.8.2')
619 call mem_alias_deprecated(this%outwidth, 'OUTWIDTH', this%memoryPath, &
620 'WIDTH', this%input_mempath, '6.8.2')
621 call mem_alias_deprecated(this%outslope, 'OUTSLOPE', this%memoryPath, &
622 'SLOPE', this%input_mempath, '6.8.2')
623 call mem_alias_deprecated(this%outrough, 'OUTROUGH', this%memoryPath, &
624 'ROUGH', this%input_mempath, '6.8.2')
625 !
626 ! -- lake auxiliary values, present (possibly empty) in the input context
627 call get_isize('AUX', this%input_mempath, isize)
628 if (isize >= 0) then
629 call mem_setptr(aux, 'AUX', this%input_mempath)
630 call mem_alias_deprecated(aux, 'LAUXVAR', this%memoryPath, &
631 'AUX', this%input_mempath, '6.8.2')
632 end if
633 !
634 ! -- renamed at the package path: CELLID by IDM integration (#3021),
635 ! IFALLBACK and IFORCEFB by the legacy solver refactor (#2976)
636 call mem_alias_deprecated(this%gwfconn, 'CELLID', this%memoryPath, &
637 'GWFCONN', this%memoryPath, '6.8.2')
638 call mem_alias_deprecated(this%ilegacy, 'IFALLBACK', this%memoryPath, &
639 'ILEGACY', this%memoryPath, '6.8.2')
640 call mem_alias_deprecated(this%iforceleg, 'IFORCEFB', this%memoryPath, &
641 'IFORCELEG', this%memoryPath, '6.8.2')
642 end subroutine lak_checkin_deprecated_names
643
644 !> @brief Source PACKAGEDATA block from input context
645 !<
646 subroutine lak_source_packagedata(this)
647 ! -- dummy
648 class(laktype), intent(inout) :: this
649 ! -- local
650 integer(I4B) :: n
651 integer(I4B) :: ilak, nconn
652 character(len=9) :: cno
653 character(len=LENBOUNDNAME) :: bndName
654 integer(I4B), dimension(:), pointer, contiguous :: ifno => null()
655 real(DP), dimension(:), pointer, contiguous :: strt => null()
656 integer(I4B), dimension(:), pointer, contiguous :: nlakeconn => null()
657 type(characterstringtype), dimension(:), pointer, contiguous :: &
658 boundname_cst => null()
659 integer(I4B), allocatable :: nboundchk(:)
660 !
661 write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// &
662 ' PACKAGEDATA'
663 !
664 ! -- allocate lake arrays
665 call mem_allocate(this%nlakeconn, this%nlakes, 'NLAKECONN', this%memoryPath)
666 call mem_allocate(this%idxlakeconn, this%nlakes + 1, 'IDXLAKECONN', &
667 this%memoryPath)
668 call mem_allocate(this%ntabrow, this%nlakes, 'NTABROW', this%memoryPath)
669 call mem_allocate(this%strt, this%nlakes, 'STRT', this%memoryPath)
670 call mem_allocate(this%laketop, this%nlakes, 'LAKETOP', this%memoryPath)
671 call mem_allocate(this%lakebot, this%nlakes, 'LAKEBOT', this%memoryPath)
672 call mem_allocate(this%sareamax, this%nlakes, 'SAREAMAX', this%memoryPath)
673 ! -- alias into the input context's permanent, feature-indexed arrays
674 ! (allocated and DZERO-initialized by the loader)
675 call mem_setptr(this%stage, 'STAGE', this%input_mempath)
676 call mem_setptr(this%rainfall, 'RAINFALL', this%input_mempath)
677 call mem_setptr(this%evaporation, 'EVAPORATION', this%input_mempath)
678 call mem_setptr(this%runoff, 'RUNOFF', this%input_mempath)
679 call mem_setptr(this%inflow, 'INFLOW', this%input_mempath)
680 call mem_setptr(this%withdrawal, 'WITHDRAWAL', this%input_mempath)
681 call mem_allocate(this%avail, this%nlakes, 'AVAIL', this%memoryPath)
682 call mem_allocate(this%lkgwsink, this%nlakes, 'LKGWSINK', this%memoryPath)
683 call mem_allocate(this%ncncvr, this%nlakes, 'NCNCVR', this%memoryPath)
684 call mem_allocate(this%ilegacy, this%nlakes, 'ILEGACY', this%memoryPath)
685 call mem_allocate(this%nstuck, this%nlakes, 'NSTUCK', this%memoryPath)
686 call mem_allocate(this%surfin, this%nlakes, 'SURFIN', this%memoryPath)
687 call mem_allocate(this%surfout, this%nlakes, 'SURFOUT', this%memoryPath)
688 call mem_allocate(this%surfout1, this%nlakes, 'SURFOUT1', this%memoryPath)
689 call mem_allocate(this%precip, this%nlakes, 'PRECIP', this%memoryPath)
690 call mem_allocate(this%precip1, this%nlakes, 'PRECIP1', this%memoryPath)
691 call mem_allocate(this%evap, this%nlakes, 'EVAP', this%memoryPath)
692 call mem_allocate(this%evap1, this%nlakes, 'EVAP1', this%memoryPath)
693 call mem_allocate(this%evapo, this%nlakes, 'EVAPO', this%memoryPath)
694 call mem_allocate(this%withr, this%nlakes, 'WITHR', this%memoryPath)
695 call mem_allocate(this%withr1, this%nlakes, 'WITHR1', this%memoryPath)
696 call mem_allocate(this%flwin, this%nlakes, 'FLWIN', this%memoryPath)
697 call mem_allocate(this%flwiter, this%nlakes, 'FLWITER', this%memoryPath)
698 call mem_allocate(this%flwiter1, this%nlakes, 'FLWITER1', this%memoryPath)
699 call mem_allocate(this%seep, this%nlakes, 'SEEP', this%memoryPath)
700 call mem_allocate(this%seep1, this%nlakes, 'SEEP1', this%memoryPath)
701 call mem_allocate(this%seep0, this%nlakes, 'SEEP0', this%memoryPath)
702 call mem_allocate(this%stageiter, this%nlakes, 'STAGEITER', this%memoryPath)
703 call mem_allocate(this%chterm, this%nlakes, 'CHTERM', this%memoryPath)
704 !
705 ! -- lake boundary and stages. In the implicit formulation iboundpak
706 ! and xnewpak are aliased to slices of the global ibound/x vectors in
707 ! lak_set_pointers (called before this routine), so they are not
708 ! allocated here.
709 if (this%iimplicit == 0) then
710 call mem_allocate(this%iboundpak, this%nlakes, 'IBOUND', this%memoryPath)
711 call mem_allocate(this%xnewpak, this%nlakes, 'XNEWPAK', this%memoryPath)
712 end if
713 call mem_allocate(this%xoldpak, this%nlakes, 'XOLDPAK', this%memoryPath)
714 !
715 ! -- lake iteration variables
716 call mem_allocate(this%iseepc, this%nlakes, 'ISEEPC', this%memoryPath)
717 call mem_allocate(this%idhc, this%nlakes, 'IDHC', this%memoryPath)
718 call mem_allocate(this%en1, this%nlakes, 'EN1', this%memoryPath)
719 call mem_allocate(this%en2, this%nlakes, 'EN2', this%memoryPath)
720 call mem_allocate(this%r1, this%nlakes, 'R1', this%memoryPath)
721 call mem_allocate(this%r2, this%nlakes, 'R2', this%memoryPath)
722 call mem_allocate(this%dh0, this%nlakes, 'DH0', this%memoryPath)
723 call mem_allocate(this%s0, this%nlakes, 'S0', this%memoryPath)
724 call mem_allocate(this%qgwf0, this%nlakes, 'QGWF0', this%memoryPath)
725 !
726 ! -- allocate character storage
727 allocate (this%lakename(this%nlakes))
728 allocate (this%status(this%nlakes))
729 !
730 ! -- initialize arrays
731 do n = 1, this%nlakes
732 this%ntabrow(n) = 0
733 this%status(n) = 'ACTIVE'
734 this%laketop(n) = -dep20
735 this%lakebot(n) = dep20
736 this%sareamax(n) = dzero
737 ! -- in the implicit formulation iboundpak/xnewpak are not yet associated
738 ! (they are aliased to the global arrays later in lak_set_pointers and
739 ! initialized in lak_read_initial_attr); only touch them here for the
740 ! legacy formulation
741 if (this%iimplicit == 0) then
742 this%iboundpak(n) = 1
743 this%xnewpak(n) = dep20
744 end if
745 this%xoldpak(n) = dep20
746 this%rainfall(n) = dzero
747 this%evaporation(n) = dzero
748 this%runoff(n) = dzero
749 this%inflow(n) = dzero
750 this%withdrawal(n) = dzero
751 this%ilegacy(n) = 0
752 this%nstuck(n) = 0
753 end do
754 !
755 ! -- get input context PACKAGEDATA column arrays
756 call mem_setptr(ifno, 'PACKAGEDATA_IFNO', this%input_mempath)
757 call mem_setptr(strt, 'STRT', this%input_mempath)
758 call mem_setptr(nlakeconn, 'NLAKECONN', this%input_mempath)
759 if (this%inamedbound /= 0) then
760 call mem_setptr(boundname_cst, 'BOUNDNAME', this%input_mempath)
761 end if
762 !
763 ! -- allocate check array
764 allocate (nboundchk(this%nlakes))
765 nboundchk = 0
766 ilak = 0
767 nconn = 0
768 !
769 do n = 1, this%nlakes
770 !
771 ! -- lake number from input
772 ilak = this%validate_ifno(ifno(n), this%nlakes, nboundchk, &
773 'lakeno', 'PACKAGEDATA')
774 if (ilak == 0) cycle
775 !
776 ! -- strt
777 this%strt(ilak) = strt(n)
778 !
779 ! -- nlakeconn
780 if (nlakeconn(n) < 0) then
781 write (errmsg, '(a,1x,i0)') 'nlakeconn MUST BE >= 0 for lake ', ilak
782 call store_error(errmsg)
783 end if
784 !
785 ! -- the IMPLICIT formulation solves the lake stage as a matrix unknown,
786 ! which requires at least one groundwater connection to give the lake
787 ! row a non-zero diagonal; a lake with no connections is not supported
788 if (this%iimplicit /= 0 .and. nlakeconn(n) == 0) then
789 write (errmsg, '(a,1x,i0,1x,a)') &
790 'lake', ilak, 'has no connections; the IMPLICIT option requires &
791 &each lake to have at least one GWF connection.'
792 call store_error(errmsg)
793 end if
794 !
795 nconn = nconn + nlakeconn(n)
796 this%nlakeconn(ilak) = nlakeconn(n)
797 !
798 ! -- set default bndName
799 write (cno, '(i9.9)') ilak
800 bndname = 'Lake'//cno
801 !
802 ! -- lakename from boundname if provided
803 if (this%inamedbound /= 0) then
804 bndname = boundname_cst(n)
805 if (trim(bndname) == '') then
806 write (cno, '(i9.9)') ilak
807 bndname = 'Lake'//cno
808 end if
809 end if
810 this%lakename(ilak) = bndname
811 end do
812 !
813 ! -- check for duplicate or missing lakes
814 call this%report_ifno_coverage(nboundchk, this%nlakes, 'lake', &
815 'PACKAGEDATA')
816 !
817 write (this%iout, '(1x,a)') 'END OF '//trim(adjustl(this%text))// &
818 ' PACKAGEDATA'
819 !
820 ! -- terminate if any errors were detected
821 if (count_errors() > 0) then
822 call store_error_filename(this%input_fname)
823 end if
824 !
825 ! -- set MAXBOUND
826 this%MAXBOUND = nconn
827 write (this%iout, '(//4x,a,i7)') 'MAXBOUND = ', this%maxbound
828 !
829 ! -- set idxlakeconn
830 this%idxlakeconn(1) = 1
831 do n = 1, this%nlakes
832 this%idxlakeconn(n + 1) = this%idxlakeconn(n) + this%nlakeconn(n)
833 end do
834 !
835 ! -- deallocate check array
836 deallocate (nboundchk)
837 !
838 ! -- release input context packagedata memory; PACKAGEDATA_IFNO excluded
839 ! because allocate_featureauxvar retains a pointer to it
840 call memorystore_release('STRT', this%input_mempath)
841 call memorystore_release('NLAKECONN', this%input_mempath)
842 call memorystore_release('BOUNDNAME', this%input_mempath)
843 end subroutine lak_source_packagedata
844
845 !> @brief Source CONNECTIONDATA block from input context
846 !<
847 subroutine lak_source_connectiondata(this)
848 ! -- dummy
849 class(laktype), intent(inout) :: this
850 ! -- local
851 integer(I4B) :: n, j, ipos, nn
852 integer(I4B) :: ilak, iconn
853 integer(I4B) :: ipos0, icellid0, icellid, nn2
854 logical(LGP) :: is_lake_bed
855 character(len=LINELENGTH) :: cellid_str
856 character(len=LINELENGTH) :: ctypenm
857 character(len=LINELENGTH) :: cbleak
858 real(DP) :: top, bot, rval
859 integer(I4B), dimension(:), pointer, contiguous :: ifno => null()
860 integer(I4B), dimension(:), pointer, contiguous :: iconns => null()
861 integer(I4B), dimension(:, :), pointer, contiguous :: cellid => null()
862 type(characterstringtype), dimension(:), pointer, contiguous :: &
863 claktype => null()
864 type(characterstringtype), dimension(:), pointer, contiguous :: &
865 bedleak => null()
866 real(DP), dimension(:), pointer, contiguous :: belev => null()
867 real(DP), dimension(:), pointer, contiguous :: telev => null()
868 real(DP), dimension(:), pointer, contiguous :: connlen => null()
869 real(DP), dimension(:), pointer, contiguous :: connwidth => null()
870 integer(I4B), allocatable :: nboundchk(:)
871 !
872 ! -- allocate connection data arrays
873 call mem_allocate(this%imap, this%MAXBOUND, 'IMAP', this%memoryPath)
874 call mem_allocate(this%gwfconn, this%MAXBOUND, 'GWFCONN', this%memoryPath)
875 call mem_allocate(this%nodesontop, this%MAXBOUND, 'NODESONTOP', &
876 this%memoryPath)
877 call mem_allocate(this%ictype, this%MAXBOUND, 'ICTYPE', this%memoryPath)
878 call mem_allocate(this%bedleak, this%MAXBOUND, 'BEDLEAK', this%memoryPath)
879 call mem_allocate(this%belev, this%MAXBOUND, 'BELEV', this%memoryPath)
880 call mem_allocate(this%telev, this%MAXBOUND, 'TELEV', this%memoryPath)
881 call mem_allocate(this%connlength, this%MAXBOUND, 'CONNLENGTH', &
882 this%memoryPath)
883 call mem_allocate(this%connwidth, this%MAXBOUND, 'CONNWIDTH', &
884 this%memoryPath)
885 call mem_allocate(this%sarea, this%MAXBOUND, 'SAREA', this%memoryPath)
886 call mem_allocate(this%warea, this%MAXBOUND, 'WAREA', this%memoryPath)
887 call mem_allocate(this%satcond, this%MAXBOUND, 'SATCOND', this%memoryPath)
888 call mem_allocate(this%simcond, this%MAXBOUND, 'SIMCOND', this%memoryPath)
889 call mem_allocate(this%simlakgw, this%MAXBOUND, 'SIMLAKGW', this%memoryPath)
890 !
891 write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// &
892 ' CONNECTIONDATA'
893 !
894 ! -- get input context CONNECTIONDATA column arrays
895 call mem_setptr(ifno, 'CONNDATA_IFNO', this%input_mempath)
896 call mem_setptr(iconns, 'ICONN', this%input_mempath)
897 call mem_setptr(cellid, 'CELLID', this%input_mempath)
898 call mem_setptr(claktype, 'CLAKTYPE', this%input_mempath)
899 call mem_setptr(bedleak, 'BEDLEAK', this%input_mempath)
900 call mem_setptr(belev, 'BELEV', this%input_mempath)
901 call mem_setptr(telev, 'TELEV', this%input_mempath)
902 call mem_setptr(connlen, 'CONNLEN', this%input_mempath)
903 call mem_setptr(connwidth, 'CONNWIDTH', this%input_mempath)
904 !
905 ! -- allocate check array
906 allocate (nboundchk(this%MAXBOUND))
907 nboundchk = 0
908 !
909 do n = 1, this%MAXBOUND
910 !
911 ilak = ifno(n)
912 iconn = iconns(n)
913 !
914 if (ilak < 1 .or. ilak > this%nlakes) then
915 write (errmsg, '(a,1x,i0)') 'lakeno MUST BE > 0 and <= ', this%nlakes
916 call store_error(errmsg)
917 cycle
918 end if
919 if (iconn < 1 .or. iconn > this%nlakeconn(ilak)) then
920 write (errmsg, '(a,1x,i0,1x,a,1x,i0)') &
921 'iconn FOR LAKE ', ilak, 'MUST BE > 0 and <= ', this%nlakeconn(ilak)
922 call store_error(errmsg)
923 cycle
924 end if
925 !
926 ipos = this%idxlakeconn(ilak) + iconn - 1
927 this%imap(ipos) = ilak
928 nboundchk(ipos) = nboundchk(ipos) + 1
929 !
930 ! -- convert cellid integer array to string and resolve to a node number.
931 write (cellid_str, '(10(i0,1x))') cellid(1:this%dis%ndim, n)
932 nn = this%dis%noder_from_cellid(cellid_str, this%inunit, this%iout)
933 if (nn < 1) then
934 write (errmsg, '(a,1x,i0,1x,a,1x,i0)') &
935 'INVALID cellid FOR LAKE ', ilak, 'connection', iconn
936 call store_error(errmsg)
937 end if
938 this%gwfconn(ipos) = nn
939 this%nodesontop(ipos) = nn
940 !
941 ! -- connection type
942 ctypenm = claktype(n)
943 select case (trim(ctypenm))
944 case ('VERTICAL')
945 this%ictype(ipos) = 0
946 case ('HORIZONTAL')
947 this%ictype(ipos) = 1
948 case ('EMBEDDEDH')
949 this%ictype(ipos) = 2
950 case ('EMBEDDEDV')
951 this%ictype(ipos) = 3
952 case default
953 write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a,a,a)') &
954 'UNKNOWN ctype FOR LAKE ', ilak, 'connection', iconn, &
955 '(', trim(ctypenm), ')'
956 call store_error(errmsg)
957 end select
958 !
959 ! -- bed leakance
960 cbleak = bedleak(n)
961 select case (trim(cbleak))
962 case ('NONE')
963 is_lake_bed = .false.
964 rval = dnodata
965 write (warnmsg, '(2(a,1x,i0,1x),a,1pe8.1,a)') &
966 'BEDLEAK for connection', iconn, 'in lake', ilak, &
967 'is specified to be NONE. Lake connections where the lake-GWF '// &
968 'connection conductance is solely a function of aquifer '// &
969 'properties in the connected GWF cell should be specified '// &
970 'with a DNODATA (', dnodata, ') value.'
971 call deprecation_warning('CONNECTIONDATA', 'bedleak=NONE', '6.4.3', &
972 warnmsg, this%inunit)
973 case default
974 read (cbleak, *) rval
975 if (is_close(rval, dnodata)) then
976 is_lake_bed = .false.
977 else
978 is_lake_bed = .true.
979 end if
980 end select
981 this%bedleak(ipos) = rval
982 if (is_lake_bed .and. this%bedleak(ipos) < dzero) then
983 write (errmsg, '(a,1x,i0,1x,a)') 'bedleak FOR LAKE ', ilak, &
984 'MUST BE >= 0'
985 call store_error(errmsg)
986 end if
987 !
988 ! -- belev
989 this%belev(ipos) = belev(n)
990 !
991 ! -- telev
992 this%telev(ipos) = telev(n)
993 !
994 ! -- connection length
995 rval = connlen(n)
996 if (rval <= dzero) then
997 if (this%ictype(ipos) == 1 .or. this%ictype(ipos) == 2 .or. &
998 this%ictype(ipos) == 3) then
999 write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a,a,1x,a)') &
1000 'connection length (connlen) FOR LAKE ', ilak, &
1001 ', CONNECTION NO.', iconn, ', MUST BE > 0 FOR SPECIFIED ', &
1002 'connection type (ctype)', trim(ctypenm)
1003 call store_error(errmsg)
1004 else
1005 rval = dzero
1006 end if
1007 end if
1008 this%connlength(ipos) = rval
1009 !
1010 ! -- connection width
1011 rval = connwidth(n)
1012 if (rval < dzero) then
1013 if (this%ictype(ipos) == 1) then
1014 write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a)') &
1015 'cell width (connwidth) FOR LAKE ', ilak, &
1016 ' HORIZONTAL CONNECTION ', iconn, 'MUST BE >= 0'
1017 call store_error(errmsg)
1018 else
1019 rval = dzero
1020 end if
1021 end if
1022 this%connwidth(ipos) = rval
1023 end do
1024 !
1025 write (this%iout, '(1x,a)') &
1026 'END OF '//trim(adjustl(this%text))//' CONNECTIONDATA'
1027 !
1028 ! -- terminate if any errors were detected
1029 if (count_errors() > 0) then
1030 call store_error_filename(this%input_fname)
1031 end if
1032 !
1033 ! -- check that embedded lakes have only one connection
1034 do n = 1, this%nlakes
1035 j = 0
1036 do ipos = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
1037 if (this%ictype(ipos) /= 2 .and. this%ictype(ipos) /= 3) cycle
1038 j = j + 1
1039 if (j > 1) then
1040 write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a)') &
1041 'nlakeconn FOR LAKE', n, 'EMBEDDED CONNECTION', j, ' EXCEEDS 1.'
1042 call store_error(errmsg)
1043 end if
1044 end do
1045 end do
1046 ! -- check that an embedded lake is not in the same cell as a lake
1047 ! with a vertical connection
1048 do n = 1, this%nlakes
1049 ipos0 = this%idxlakeconn(n)
1050 icellid0 = this%gwfconn(ipos0)
1051 if (this%ictype(ipos0) /= 2 .and. this%ictype(ipos0) /= 3) cycle
1052 do nn2 = 1, this%nlakes
1053 if (nn2 == n) cycle
1054 j = 0
1055 do ipos = this%idxlakeconn(nn2), this%idxlakeconn(nn2 + 1) - 1
1056 j = j + 1
1057 icellid = this%gwfconn(ipos)
1058 if (icellid == icellid0) then
1059 if (this%ictype(ipos) == 0) then
1060 write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a,1x,i0,1x,a)') &
1061 'EMBEDDED LAKE', n, &
1062 'CANNOT COINCIDE WITH VERTICAL CONNECTION', j, &
1063 'IN LAKE', nn2, '.'
1064 call store_error(errmsg)
1065 end if
1066 end if
1067 end do
1068 end do
1069 end do
1070 !
1071 ! -- process the data (post-processing: telev/belev/laketop/lakebot)
1072 do n = 1, this%nlakes
1073 j = 0
1074 do ipos = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
1075 j = j + 1
1076 nn = this%gwfconn(ipos)
1077 top = this%dis%top(nn)
1078 bot = this%dis%bot(nn)
1079 if (this%ictype(ipos) == 0) then
1080 this%telev(ipos) = top + this%surfdep
1081 this%belev(ipos) = top
1082 this%lakebot(n) = min(this%belev(ipos), this%lakebot(n))
1083 else if (this%ictype(ipos) == 1) then
1084 if (this%belev(ipos) == this%telev(ipos)) then
1085 this%telev(ipos) = top
1086 this%belev(ipos) = bot
1087 else
1088 if (this%belev(ipos) >= this%telev(ipos)) then
1089 write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a)') &
1090 'telev FOR LAKE ', n, ' HORIZONTAL CONNECTION ', j, &
1091 'MUST BE >= belev'
1092 call store_error(errmsg)
1093 else if (this%belev(ipos) < bot) then
1094 write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a,1x,g15.7,1x,a)') &
1095 'belev FOR LAKE ', n, ' HORIZONTAL CONNECTION ', j, &
1096 'MUST BE >= cell bottom (', bot, ')'
1097 call store_error(errmsg)
1098 else if (this%telev(ipos) > top) then
1099 write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a,1x,g15.7,1x,a)') &
1100 'telev FOR LAKE ', n, ' HORIZONTAL CONNECTION ', j, &
1101 'MUST BE <= cell top (', top, ')'
1102 call store_error(errmsg)
1103 end if
1104 end if
1105 this%laketop(n) = max(this%telev(ipos), this%laketop(n))
1106 this%lakebot(n) = min(this%belev(ipos), this%lakebot(n))
1107 else if (this%ictype(ipos) == 2 .or. this%ictype(ipos) == 3) then
1108 this%telev(ipos) = top
1109 this%belev(ipos) = bot
1110 this%lakebot(n) = bot
1111 end if
1112 !
1113 ! -- check for missing or duplicate connections
1114 if (nboundchk(ipos) == 0) then
1115 write (errmsg, '(a,1x,i0,1x,a,1x,i0)') &
1116 'NO DATA SPECIFIED FOR LAKE', n, 'CONNECTION', j
1117 call store_error(errmsg)
1118 else if (nboundchk(ipos) > 1) then
1119 write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a,1x,i0,1x,a)') &
1120 'DATA FOR LAKE', n, 'CONNECTION', j, &
1121 'SPECIFIED', nboundchk(ipos), 'TIMES'
1122 call store_error(errmsg)
1123 end if
1124 end do
1125 if (this%laketop(n) == -dep20) then
1126 this%laketop(n) = this%lakebot(n) + 100.
1127 end if
1128 end do
1129 !
1130 deallocate (nboundchk)
1131 !
1132 if (count_errors() > 0) then
1133 call store_error_filename(this%input_fname)
1134 end if
1135 !
1136 ! -- release input context connectiondata memory
1137 call memorystore_release('CONNDATA_IFNO', this%input_mempath)
1138 call memorystore_release('ICONN', this%input_mempath)
1139 call memorystore_release('CELLID', this%input_mempath)
1140 call memorystore_release('CLAKTYPE', this%input_mempath)
1141 call memorystore_release('BEDLEAK', this%input_mempath)
1142 call memorystore_release('BELEV', this%input_mempath)
1143 call memorystore_release('TELEV', this%input_mempath)
1144 call memorystore_release('CONNLEN', this%input_mempath)
1145 call memorystore_release('CONNWIDTH', this%input_mempath)
1146 end subroutine lak_source_connectiondata
1147
1148 !> @brief Source TABLES block from input context
1149 !<
1150 subroutine lak_source_tables(this)
1151 ! -- dummy
1152 class(laktype), intent(inout) :: this
1153 ! -- local
1154 integer(I4B) :: n, ntabs
1155 integer(I4B) :: ilak, iconn
1156 character(len=LENMEMPATH) :: mempath
1157 integer(I4B), dimension(:), pointer, contiguous :: ifno => null()
1158 type(characterstringtype), dimension(:), pointer, contiguous :: &
1159 laktab6_mempaths => null()
1160 type(laktabtype), dimension(:), allocatable :: laketables
1161 integer(I4B), allocatable :: nboundchk(:)
1162 !
1163 ! -- skip if no tables
1164 if (this%ntables < 1) return
1165 !
1166 ! -- guard: TABLES block required when ntables > 0
1167 call get_isize('TABLES_IFNO', this%input_mempath, ntabs)
1168 if (ntabs < 1) then
1169 write (errmsg, '(a)') &
1170 'NTABLES > 0 BUT A TABLES BLOCK WAS NOT FOUND IN THE LAK INPUT.'
1171 call store_error(errmsg, .true.)
1172 end if
1173 !
1174 write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// &
1175 ' TABLES'
1176 !
1177 ! -- set input context pointers
1178 call mem_setptr(ifno, 'TABLES_IFNO', this%input_mempath)
1179 call mem_setptr(laktab6_mempaths, 'LAKTAB6_MEMPATH', this%input_mempath)
1180 !
1181 ntabs = size(ifno)
1182 !
1183 ! -- allocate
1184 allocate (laketables(this%nlakes))
1185 allocate (nboundchk(this%nlakes))
1186 nboundchk = 0
1187 !
1188 do n = 1, ntabs
1189 ilak = this%validate_ifno(ifno(n), this%nlakes, nboundchk, &
1190 'lakeno', 'TABLES')
1191 if (ilak == 0) cycle
1192 mempath = laktab6_mempaths(n)
1193 call this%lak_source_table(ilak, mempath, laketables(ilak))
1194 end do
1195 !
1196 write (this%iout, '(1x,a)') 'END OF '//trim(adjustl(this%text))//' TABLES'
1197 !
1198 ! -- check for missing or duplicate table data
1199 if (ntabs < this%ntables) then
1200 write (errmsg, '(a,1x,i0,1x,a,1x,i0)') &
1201 'TABLE DATA ARE SPECIFIED', ntabs, &
1202 'TIMES BUT NTABLES IS SET TO', this%ntables
1203 call store_error(errmsg)
1204 end if
1205 ! -- a table that never loaded any rows is not reported as a duplicate
1206 do n = 1, this%nlakes
1207 if (this%ntabrow(n) == 0) nboundchk(n) = 0
1208 end do
1209 call this%report_ifno_coverage(nboundchk, this%nlakes, 'lakeno', &
1210 'TABLES', check_missing=.false.)
1211 !
1212 deallocate (nboundchk)
1213 !
1214 if (count_errors() > 0) then
1215 call store_error_filename(this%input_fname)
1216 end if
1217 !
1218 ! -- release input context tables memory
1219 call memorystore_release('TABLES_IFNO', this%input_mempath)
1220 !
1221 ! -- convert laketables to vectors
1222 call this%laktables_to_vectors(laketables)
1223 !
1224 ! -- destroy laketables
1225 do n = 1, this%nlakes
1226 if (this%ntabrow(n) > 0) then
1227 deallocate (laketables(n)%tabstage)
1228 deallocate (laketables(n)%tabvolume)
1229 deallocate (laketables(n)%tabsarea)
1230 iconn = this%idxlakeconn(n)
1231 if (this%ictype(iconn) == 2 .or. this%ictype(iconn) == 3) then
1232 deallocate (laketables(n)%tabwarea)
1233 end if
1234 end if
1235 end do
1236 deallocate (laketables)
1237 end subroutine lak_source_tables
1238
1239 !> @brief Copy the laketables structure data into flattened vectors that are
1240 !! stored in the memory manager
1241 !<
1242 subroutine laktables_to_vectors(this, laketables)
1243 class(laktype), intent(inout) :: this
1244 type(laktabtype), intent(in), dimension(:), contiguous :: laketables
1245 integer(I4B) :: n
1246 integer(I4B) :: ntabrows
1247 integer(I4B) :: j
1248 integer(I4B) :: ipos
1249 integer(I4B) :: iconn
1250 !
1251 ! -- allocate index array for lak tables
1252 call mem_allocate(this%ialaktab, this%nlakes + 1, 'IALAKTAB', this%memoryPath)
1253 !
1254 ! -- Move the laktables structure information into flattened arrays
1255 this%ialaktab(1) = 1
1256 do n = 1, this%nlakes
1257 ! -- ialaktab contains a pointer into the flattened lak table data
1258 this%ialaktab(n + 1) = this%ialaktab(n) + this%ntabrow(n)
1259 end do
1260 !
1261 ! -- Allocate vectors for storing all lake table data
1262 ntabrows = this%ialaktab(this%nlakes + 1) - 1
1263 call mem_allocate(this%tabstage, ntabrows, 'TABSTAGE', this%memoryPath)
1264 call mem_allocate(this%tabvolume, ntabrows, 'TABVOLUME', this%memoryPath)
1265 call mem_allocate(this%tabsarea, ntabrows, 'TABSAREA', this%memoryPath)
1266 call mem_allocate(this%tabwarea, ntabrows, 'TABWAREA', this%memoryPath)
1267 !
1268 ! -- Copy data from laketables into vectors
1269 do n = 1, this%nlakes
1270 j = 1
1271 do ipos = this%ialaktab(n), this%ialaktab(n + 1) - 1
1272 this%tabstage(ipos) = laketables(n)%tabstage(j)
1273 this%tabvolume(ipos) = laketables(n)%tabvolume(j)
1274 this%tabsarea(ipos) = laketables(n)%tabsarea(j)
1275 iconn = this%idxlakeconn(n)
1276 if (this%ictype(iconn) == 2 .or. this%ictype(iconn) == 3) then
1277 !
1278 ! -- tabwarea only filled for ictype 2 and 3
1279 this%tabwarea(ipos) = laketables(n)%tabwarea(j)
1280 else
1281 this%tabwarea(ipos) = dzero
1282 end if
1283 j = j + 1
1284 end do
1285 end do
1286 end subroutine laktables_to_vectors
1287
1288 !> @brief Source one lake's table from its LAKTAB6 subpackage
1289 !<
1290 subroutine lak_source_table(this, ilak, mempath, laketable)
1291 ! -- dummy
1292 class(laktype), intent(inout) :: this
1293 integer(I4B), intent(in) :: ilak
1294 character(len=*), intent(in) :: mempath
1295 type(laktabtype), intent(inout) :: laketable
1296 ! -- local
1297 integer(I4B), pointer :: nrow => null()
1298 integer(I4B), pointer :: ncol => null()
1299 real(DP), dimension(:), pointer, contiguous :: stage => null()
1300 real(DP), dimension(:), pointer, contiguous :: volume => null()
1301 real(DP), dimension(:), pointer, contiguous :: sarea => null()
1302 real(DP), dimension(:), pointer, contiguous :: barea => null()
1303 character(len=:), pointer :: tabfname => null()
1304 integer(I4B) :: jmin, iconn, n, nerr0
1305 real(DP) :: vol, sa, wa, v, v0
1306 ! -- formats
1307 character(len=*), parameter :: fmttaberr = &
1308 &'(a,1x,i0,1x,a,1x,g15.6,1x,a,1x,i0,1x,a,1x,i0,1x,a,1x,g15.6,1x,a)'
1309 !
1310 ! -- this table's own input file, for error attribution below
1311 call mem_setptr(tabfname, 'INPUT_FNAME', mempath)
1312 call mem_setptr(nrow, 'NROW', mempath)
1313 call mem_setptr(ncol, 'NCOL', mempath)
1314 !
1315 ! -- errors added below this point belong to this lake's own table
1316 nerr0 = count_errors()
1317 !
1318 if (nrow < 1) then
1319 write (errmsg, '(a,1x,i0)') &
1320 'LAKE TABLE NROW MUST BE > 0 FOR LAKE', ilak
1321 call store_error(errmsg)
1322 end if
1323 !
1324 iconn = this%idxlakeconn(ilak)
1325 if (this%ictype(iconn) == 2 .or. this%ictype(iconn) == 3) then
1326 jmin = 4
1327 else
1328 jmin = 3
1329 end if
1330 if (ncol < jmin) then
1331 write (errmsg, '(a,1x,i0,1x,a,1x,i0)') &
1332 'LAKE TABLE NCOL MUST BE >=', jmin, 'FOR LAKE', ilak
1333 call store_error(errmsg)
1334 end if
1335 !
1336 if (count_errors() > nerr0) then
1337 call store_error_filename(tabfname, terminate=.false.)
1338 call memorystore_release('NROW', mempath)
1339 call memorystore_release('NCOL', mempath)
1340 call memorystore_release('INPUT_FNAME', mempath)
1341 return
1342 end if
1343 !
1344 this%ntabrow(ilak) = nrow
1345 allocate (laketable%tabstage(nrow))
1346 allocate (laketable%tabvolume(nrow))
1347 allocate (laketable%tabsarea(nrow))
1348 call mem_setptr(stage, 'STAGE', mempath)
1349 call mem_setptr(volume, 'VOLUME', mempath)
1350 call mem_setptr(sarea, 'SAREA', mempath)
1351 laketable%tabstage = stage
1352 laketable%tabvolume = volume
1353 laketable%tabsarea = sarea
1354 if (this%ictype(iconn) == 2 .or. this%ictype(iconn) == 3) then
1355 allocate (laketable%tabwarea(nrow))
1356 call mem_setptr(barea, 'BAREA', mempath)
1357 laketable%tabwarea = barea
1358 end if
1359 !
1360 ! -- set lake bottom based on table if it is an embedded lake
1361 if (this%ictype(iconn) == 2 .or. this%ictype(iconn) == 3) then
1362 do n = 1, this%ntabrow(ilak)
1363 vol = laketable%tabvolume(n)
1364 sa = laketable%tabsarea(n)
1365 wa = laketable%tabwarea(n)
1366 vol = vol * sa * wa
1367 ! -- check if all entries are zero
1368 if (vol > dzero) exit
1369 ! -- set lake bottom
1370 this%lakebot(ilak) = laketable%tabstage(n)
1371 this%belev(ilak) = laketable%tabstage(n)
1372 end do
1373 ! -- set maximum surface area for rainfall
1374 n = this%ntabrow(ilak)
1375 this%sareamax(ilak) = laketable%tabsarea(n)
1376 end if
1377 !
1378 ! -- verify the table data
1379 do n = 2, this%ntabrow(ilak)
1380 v = laketable%tabstage(n)
1381 v0 = laketable%tabstage(n - 1)
1382 if (v <= v0) then
1383 write (errmsg, fmttaberr) &
1384 'TABLE STAGE ENTRY', n, '(', laketable%tabstage(n), ') FOR LAKE ', &
1385 ilak, 'MUST BE GREATER THAN THE PREVIOUS STAGE ENTRY', &
1386 n - 1, '(', laketable%tabstage(n - 1), ')'
1387 call store_error(errmsg)
1388 end if
1389 v = laketable%tabvolume(n)
1390 v0 = laketable%tabvolume(n - 1)
1391 if (v <= v0) then
1392 write (errmsg, fmttaberr) &
1393 'TABLE VOLUME ENTRY', n, '(', laketable%tabvolume(n), &
1394 ') FOR LAKE ', &
1395 ilak, 'MUST BE GREATER THAN THE PREVIOUS VOLUME ENTRY', &
1396 n - 1, '(', laketable%tabvolume(n - 1), ')'
1397 call store_error(errmsg)
1398 end if
1399 v = laketable%tabsarea(n)
1400 v0 = laketable%tabsarea(n - 1)
1401 if (v < v0) then
1402 write (errmsg, fmttaberr) &
1403 'TABLE SURFACE AREA ENTRY', n, '(', &
1404 laketable%tabsarea(n), ') FOR LAKE ', ilak, &
1405 'MUST BE GREATER THAN OR EQUAL TO THE PREVIOUS SURFACE AREA ENTRY', &
1406 n - 1, '(', laketable%tabsarea(n - 1), ')'
1407 call store_error(errmsg)
1408 end if
1409 if (this%ictype(iconn) == 2 .or. this%ictype(iconn) == 3) then
1410 v = laketable%tabwarea(n)
1411 v0 = laketable%tabwarea(n - 1)
1412 if (v < v0) then
1413 write (errmsg, fmttaberr) &
1414 'TABLE EXCHANGE AREA ENTRY', n, '(', &
1415 laketable%tabwarea(n), ') FOR LAKE ', ilak, &
1416 'MUST BE GREATER THAN OR EQUAL TO THE PREVIOUS EXCHANGE AREA '// &
1417 'ENTRY', n - 1, '(', laketable%tabwarea(n - 1), ')'
1418 call store_error(errmsg)
1419 end if
1420 end if
1421 end do
1422 !
1423 if (count_errors() > nerr0) then
1424 call store_error_filename(tabfname, terminate=.false.)
1425 end if
1426 !
1427 ! -- release this table's own input context memory
1428 call memorystore_release('NROW', mempath)
1429 call memorystore_release('NCOL', mempath)
1430 call memorystore_release('STAGE', mempath)
1431 call memorystore_release('VOLUME', mempath)
1432 call memorystore_release('SAREA', mempath)
1433 if (this%ictype(iconn) == 2 .or. this%ictype(iconn) == 3) then
1434 call memorystore_release('BAREA', mempath)
1435 end if
1436 call memorystore_release('INPUT_FNAME', mempath)
1437 end subroutine lak_source_table
1438
1439 !> @brief Source OUTLETS block from input context
1440 !<
1441 subroutine lak_source_outlets(this)
1442 ! -- dummy
1443 class(laktype), intent(inout) :: this
1444 ! -- local
1445 integer(I4B) :: n, isize, ioutlet
1446 character(len=LINELENGTH) :: keyword
1447 integer(I4B), dimension(:), pointer, contiguous :: outletno => null()
1448 integer(I4B), dimension(:), pointer, contiguous :: lakein => null()
1449 integer(I4B), dimension(:), pointer, contiguous :: lakeout => null()
1450 type(characterstringtype), dimension(:), pointer, contiguous :: &
1451 couttype => null()
1452 real(DP), dimension(:), pointer, contiguous :: outlets_invert => null()
1453 real(DP), dimension(:), pointer, contiguous :: outlets_width => null()
1454 real(DP), dimension(:), pointer, contiguous :: outlets_rough => null()
1455 real(DP), dimension(:), pointer, contiguous :: outlets_slope => null()
1456 integer(I4B), allocatable :: nboundchk(:)
1457 !
1458 ! -- skip if no outlets
1459 if (this%noutlets < 1) return
1460 !
1461 ! -- guard: OUTLETS block required when noutlets > 0
1462 call get_isize('OUTLETS_OUTLETNO', this%input_mempath, isize)
1463 if (isize < 1) then
1464 write (errmsg, '(a)') &
1465 'NOUTLETS > 0 BUT AN OUTLETS BLOCK WAS NOT FOUND IN THE LAK INPUT.'
1466 call store_error(errmsg, .true.)
1467 end if
1468 !
1469 ! -- allocate outlet arrays
1470 call mem_allocate(this%lakein, this%noutlets, 'LAKEIN', this%memoryPath)
1471 call mem_allocate(this%lakeout, this%noutlets, 'LAKEOUT', this%memoryPath)
1472 call mem_allocate(this%iouttype, this%noutlets, 'IOUTTYPE', this%memoryPath)
1473 ! -- alias into the input context's permanent, feature-indexed arrays
1474 ! (allocated and DZERO-initialized by the loader)
1475 call mem_setptr(this%outrate, 'RATE', this%input_mempath)
1476 call mem_setptr(this%outinvert, 'INVERT', this%input_mempath)
1477 call mem_setptr(this%outwidth, 'WIDTH', this%input_mempath)
1478 call mem_setptr(this%outrough, 'ROUGH', this%input_mempath)
1479 call mem_setptr(this%outslope, 'SLOPE', this%input_mempath)
1480 call mem_allocate(this%simoutrate, this%noutlets, 'SIMOUTRATE', &
1481 this%memoryPath)
1482 call mem_allocate(this%outlet_invert_set, this%noutlets, &
1483 'INVERT_SET', this%memoryPath)
1484 call mem_allocate(this%outlet_width_set, this%noutlets, &
1485 'WIDTH_SET', this%memoryPath)
1486 call mem_allocate(this%outlet_rough_set, this%noutlets, &
1487 'ROUGH_SET', this%memoryPath)
1488 call mem_allocate(this%outlet_slope_set, this%noutlets, &
1489 'SLOPE_SET', this%memoryPath)
1490 this%outlet_invert_set = .false.
1491 this%outlet_width_set = .false.
1492 this%outlet_rough_set = .false.
1493 this%outlet_slope_set = .false.
1494 !
1495 write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// &
1496 ' OUTLETS'
1497 !
1498 ! -- set input context pointers
1499 call mem_setptr(outletno, 'OUTLETS_OUTLETNO', this%input_mempath)
1500 call mem_setptr(lakein, 'LAKEIN', this%input_mempath)
1501 call mem_setptr(lakeout, 'LAKEOUT', this%input_mempath)
1502 call mem_setptr(couttype, 'COUTTYPE', this%input_mempath)
1503 call mem_setptr(outlets_invert, 'OUTLETS_INVERT', this%input_mempath)
1504 call mem_setptr(outlets_width, 'OUTLETS_WIDTH', this%input_mempath)
1505 call mem_setptr(outlets_rough, 'OUTLETS_ROUGH', this%input_mempath)
1506 call mem_setptr(outlets_slope, 'OUTLETS_SLOPE', this%input_mempath)
1507 !
1508 allocate (nboundchk(this%noutlets))
1509 nboundchk = 0
1510 !
1511 do n = 1, size(outletno)
1512 ioutlet = this%validate_ifno(outletno(n), this%noutlets, &
1513 nboundchk, 'outletno', 'OUTLETS')
1514 if (ioutlet == 0) cycle
1515 !
1516 ! -- lakein
1517 if (lakein(n) < 1 .or. lakein(n) > this%nlakes) then
1518 write (errmsg, '(a,1x,i0,1x,a,1x,i0)') &
1519 'lakein FOR OUTLET ', ioutlet, 'MUST BE > 0 and <= ', this%nlakes
1520 call store_error(errmsg)
1521 end if
1522 this%lakein(ioutlet) = lakein(n)
1523 !
1524 ! -- lakeout
1525 if (lakeout(n) < 0 .or. lakeout(n) > this%nlakes) then
1526 write (errmsg, '(a,1x,i0,1x,a,1x,i0)') &
1527 'lakeout FOR OUTLET ', ioutlet, 'MUST BE >= 0 and <= ', this%nlakes
1528 call store_error(errmsg)
1529 end if
1530 this%lakeout(ioutlet) = lakeout(n)
1531 !
1532 ! -- outlet type
1533 keyword = couttype(n)
1534 select case (trim(keyword))
1535 case ('SPECIFIED')
1536 this%iouttype(ioutlet) = 0
1537 case ('MANNING')
1538 this%iouttype(ioutlet) = 1
1539 case ('WEIR')
1540 this%iouttype(ioutlet) = 2
1541 case default
1542 write (errmsg, '(a,1x,i0,1x,a,a,a)') &
1543 'UNKNOWN couttype FOR OUTLET ', ioutlet, '(', trim(keyword), ')'
1544 call store_error(errmsg)
1545 end select
1546 !
1547 ! -- outlet invert, width, roughness, slope
1548 this%outinvert(ioutlet) = outlets_invert(n)
1549 this%outwidth(ioutlet) = outlets_width(n)
1550 this%outrough(ioutlet) = outlets_rough(n)
1551 this%outslope(ioutlet) = outlets_slope(n)
1552 end do
1553 !
1554 write (this%iout, '(1x,a)') 'END OF '//trim(adjustl(this%text))//' OUTLETS'
1555 !
1556 ! -- check for duplicate or missing outlets
1557 call this%report_ifno_coverage(nboundchk, this%noutlets, 'outlet', &
1558 'OUTLETS')
1559 !
1560 deallocate (nboundchk)
1561 !
1562 if (count_errors() > 0) then
1563 call store_error_filename(this%input_fname)
1564 end if
1565 !
1566 ! -- release input context outlets memory; OUTLETS_OUTLETNO/INVERT/
1567 ! WIDTH/ROUGH/SLOPE excluded (bound by lak_input_init for PERIOD use)
1568 call memorystore_release('LAKEIN', this%input_mempath)
1569 call memorystore_release('LAKEOUT', this%input_mempath)
1570 call memorystore_release('COUTTYPE', this%input_mempath)
1571 end subroutine lak_source_outlets
1572
1573 !> @brief Source DIMENSIONS block from input context and load static data
1574 !<
1575 subroutine lak_source_dimensions(this)
1576 ! -- dummy
1577 class(laktype), intent(inout) :: this
1578 ! -- local
1579 type(gwflakparamfoundtype) :: found
1580 !
1581 ! -- initialize dimensions to -1
1582 this%nlakes = -1
1583 this%maxbound = -1
1584 !
1585 write (this%iout, '(/1x,a)') &
1586 'PROCESSING '//trim(adjustl(this%text))//' DIMENSIONS'
1587 !
1588 ! -- NLAKES (mf6internal: nlakes); kept in the input context (not
1589 ! released) since PERIOD settings resolve it by name via SHAPE
1590 call mem_set_value(this%nlakes, 'NLAKES', this%input_mempath, &
1591 found%nlakes, release=.false.)
1592 if (found%nlakes) write (this%iout, '(4x,a,i7)') 'NLAKES = ', this%nlakes
1593 !
1594 ! -- NOUTLETS (mf6internal: noutlets); kept in the input context (not
1595 ! released) since PERIOD settings resolve it by name via SHAPE
1596 call mem_set_value(this%noutlets, 'NOUTLETS', this%input_mempath, &
1597 found%noutlets, release=.false.)
1598 if (found%noutlets) write (this%iout, '(4x,a,i7)') &
1599 'NOUTLETS = ', this%noutlets
1600 !
1601 ! -- NTABLES (mf6internal: ntables)
1602 call mem_set_value(this%ntables, 'NTABLES', this%input_mempath, found%ntables)
1603 if (found%ntables) write (this%iout, '(4x,a,i7)') 'NTABLES = ', this%ntables
1604 !
1605 write (this%iout, '(1x,a)') &
1606 'END OF '//trim(adjustl(this%text))//' DIMENSIONS'
1607 !
1608 if (this%nlakes < 0) then
1609 write (errmsg, '(a)') &
1610 'NLAKES WAS NOT SPECIFIED OR WAS SPECIFIED INCORRECTLY.'
1611 call store_error(errmsg)
1612 call store_error_filename(this%input_fname)
1613 return
1614 end if
1615 !
1616 if (this%iforceleglak /= 0) then
1617 if (this%iforceleglak < 1 .or. this%iforceleglak > this%nlakes) then
1618 write (errmsg, '(a,i0,a,i0,a)') &
1619 'DEV_FORCE_LEGACY_LAKE (', this%iforceleglak, &
1620 ') MUST BE BETWEEN 1 AND NLAKES (', this%nlakes, ').'
1621 call store_error(errmsg)
1622 call store_error_filename(this%input_fname)
1623 return
1624 end if
1625 end if
1626 !
1627 ! -- read PACKAGEDATA
1628 call this%lak_source_packagedata()
1629 !
1630 ! -- for the implicit formulation each lake adds one equation (one row and
1631 ! column) to the groundwater flow matrix
1632 if (this%iimplicit /= 0) then
1633 this%npakeq = this%nlakes
1634 ! -- the implicit lake-aquifer coupling is asymmetric for perched
1635 ! connections, so flag the coefficient matrix as asymmetric (which
1636 ! requires the BICGSTAB linear acceleration). Only raise the flag; never
1637 ! clear an asymmetry already indicated elsewhere.
1638 this%iasym = 1
1639 end if
1640 !
1641 ! -- read CONNECTIONDATA
1642 call this%lak_source_connectiondata()
1643 !
1644 ! -- read TABLES
1645 call this%lak_source_tables()
1646 !
1647 ! -- read OUTLETS
1648 call this%lak_source_outlets()
1649 !
1650 ! -- alias deprecated variable names
1651 call this%lak_checkin_deprecated_names()
1652 !
1653 ! -- Call define_listlabel
1654 call this%define_listlabel()
1655 !
1656 ! -- setup the budget object
1657 call this%lak_setup_budobj()
1658 !
1659 ! -- setup the stage table object
1660 call this%lak_setup_tableobj()
1661 end subroutine lak_source_dimensions
1662
1663 !> @brief Read the initial parameters for this package
1664 !<
1665 subroutine lak_read_initial_attr(this)
1666 use constantsmodule, only: linelength
1669 ! -- dummy
1670 class(laktype), intent(inout) :: this
1671 ! -- local
1672 integer(I4B) :: j, n
1673 integer(I4B) :: nn
1674 integer(I4B) :: idx
1675 real(DP) :: top
1676 real(DP) :: bot
1677 real(DP) :: k
1678 real(DP) :: area
1679 real(DP) :: length
1680 real(DP) :: s
1681 real(DP) :: dx
1682 real(DP) :: c
1683 real(DP) :: sa
1684 real(DP) :: wa
1685 real(DP) :: v
1686 real(DP) :: fact
1687 real(DP) :: c1
1688 real(DP) :: c2
1689 real(DP), allocatable, dimension(:) :: clb, caq
1690 character(len=14) :: cbedleak
1691 character(len=14) :: cbedcond
1692 character(len=10), dimension(0:3) :: ctype
1693 character(len=15) :: nodestr
1694 ! -- data
1695 data ctype(0)/'VERTICAL '/
1696 data ctype(1)/'HORIZONTAL'/
1697 data ctype(2)/'EMBEDDEDH '/
1698 data ctype(3)/'EMBEDDEDV '/
1699 !
1700 ! -- initialize xnewpak and set stage
1701 do n = 1, this%nlakes
1702 this%xnewpak(n) = this%strt(n)
1703 this%stage(n) = this%strt(n)
1704 end do
1705 !
1706 ! -- initialize status (iboundpak) of lakes to active
1707 do n = 1, this%nlakes
1708 if (this%status(n) == 'CONSTANT') then
1709 this%iboundpak(n) = -1
1710 else if (this%status(n) == 'INACTIVE') then
1711 this%iboundpak(n) = 0
1712 else if (this%status(n) == 'ACTIVE ') then
1713 this%iboundpak(n) = 1
1714 end if
1715 end do
1716 !
1717 ! -- set boundname for each connection
1718 if (this%inamedbound /= 0) then
1719 do n = 1, this%nlakes
1720 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
1721 this%boundname(j) = this%lakename(n)
1722 end do
1723 end do
1724 end if
1725 !
1726 ! -- copy boundname into boundname_cst
1727 call this%copy_boundname()
1728 !
1729 ! -- set pointer to gwf iss and gwf hk
1730 call mem_setptr(this%gwfiss, 'ISS', create_mem_path(this%name_model))
1731 call mem_setptr(this%gwfk11, 'K11', create_mem_path(this%name_model, 'NPF'))
1732 call mem_setptr(this%gwfk33, 'K33', create_mem_path(this%name_model, 'NPF'))
1733 call mem_setptr(this%gwfik33, 'IK33', create_mem_path(this%name_model, 'NPF'))
1734 call mem_setptr(this%gwfsat, 'SAT', create_mem_path(this%name_model, 'NPF'))
1735 !
1736 ! -- allocate temporary storage
1737 allocate (clb(this%MAXBOUND))
1738 allocate (caq(this%MAXBOUND))
1739 !
1740 ! -- calculate saturated conductance for each connection
1741 do n = 1, this%nlakes
1742 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
1743 nn = this%gwfconn(j)
1744 top = this%dis%top(nn)
1745 bot = this%dis%bot(nn)
1746 ! vertical connection
1747 if (this%ictype(j) == 0) then
1748 area = this%dis%area(nn)
1749 this%sarea(j) = area
1750 this%warea(j) = area
1751 this%sareamax(n) = this%sareamax(n) + area
1752 if (this%gwfik33 == 0) then
1753 k = this%gwfk11(nn)
1754 else
1755 k = this%gwfk33(nn)
1756 end if
1757 length = dhalf * (top - bot)
1758 ! horizontal connection
1759 else if (this%ictype(j) == 1) then
1760 area = (this%telev(j) - this%belev(j)) * this%connwidth(j)
1761 ! -- recalculate area if connected cell is confined and lake
1762 ! connection top and bot are equal to the cell top and bot
1763 if (top == this%telev(j) .and. bot == this%belev(j)) then
1764 if (this%icelltype(nn) == 0) then
1765 area = this%gwfsat(nn) * (top - bot) * this%connwidth(j)
1766 end if
1767 end if
1768 this%sarea(j) = dzero
1769 this%warea(j) = area
1770 this%sareamax(n) = this%sareamax(n) + dzero
1771 k = this%gwfk11(nn)
1772 length = this%connlength(j)
1773 ! embedded horizontal connection
1774 else if (this%ictype(j) == 2) then
1775 area = done
1776 this%sarea(j) = dzero
1777 this%warea(j) = area
1778 this%sareamax(n) = this%sareamax(n) + dzero
1779 k = this%gwfk11(nn)
1780 length = this%connlength(j)
1781 ! embedded vertical connection
1782 else if (this%ictype(j) == 3) then
1783 area = done
1784 this%sarea(j) = dzero
1785 this%warea(j) = area
1786 this%sareamax(n) = this%sareamax(n) + dzero
1787 if (this%gwfik33 == 0) then
1788 k = this%gwfk11(nn)
1789 else
1790 k = this%gwfk33(nn)
1791 end if
1792 length = this%connlength(j)
1793 end if
1794 if (is_close(this%bedleak(j), dnodata)) then
1795 clb(j) = dnodata
1796 else if (this%bedleak(j) > dzero) then
1797 clb(j) = done / this%bedleak(j)
1798 else
1799 clb(j) = dzero
1800 end if
1801 if (k > dzero) then
1802 caq(j) = length / k
1803 else
1804 caq(j) = dzero
1805 end if
1806 if (is_close(this%bedleak(j), dnodata)) then
1807 this%satcond(j) = area / caq(j)
1808 else if (clb(j) * caq(j) > dzero) then
1809 this%satcond(j) = area / (clb(j) + caq(j))
1810 else
1811 this%satcond(j) = dzero
1812 end if
1813 end do
1814 end do
1815 !
1816 ! -- write a summary of the conductance
1817 if (this%iprpak > 0) then
1818 write (this%iout, '(//,29x,a,/)') &
1819 'INTERFACE CONDUCTANCE BETWEEN LAKE AND AQUIFER CELLS'
1820 write (this%iout, '(1x,a)') &
1821 & ' LAKE CONNECTION CONNECTION LAKEBED'// &
1822 & ' C O N D U C T A N C E S '
1823 write (this%iout, '(1x,a)') &
1824 & ' NUMBER NUMBER CELLID DIRECTION LEAKANCE'// &
1825 & ' LAKEBED AQUIFER COMBINED'
1826 write (this%iout, "(1x,108('-'))")
1827 do n = 1, this%nlakes
1828 idx = 0
1829 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
1830 idx = idx + 1
1831 fact = done
1832 if (this%ictype(j) == 1) then
1833 fact = this%telev(j) - this%belev(j)
1834 if (abs(fact) > dzero) then
1835 fact = done / fact
1836 end if
1837 end if
1838 nn = this%gwfconn(j)
1839 area = this%warea(j)
1840 c1 = dzero
1841 if (is_close(clb(j), dnodata)) then
1842 cbedleak = ' NONE '
1843 cbedcond = ' NONE '
1844 else if (clb(j) > dzero) then
1845 c1 = area * fact / clb(j)
1846 write (cbedleak, '(g14.5)') this%bedleak(j)
1847 write (cbedcond, '(g14.5)') c1
1848 else
1849 write (cbedleak, '(g14.5)') c1
1850 write (cbedcond, '(g14.5)') c1
1851 end if
1852 c2 = dzero
1853 if (caq(j) > dzero) then
1854 c2 = area * fact / caq(j)
1855 end if
1856 call this%dis%noder_to_string(nn, nodestr)
1857 write (this%iout, &
1858 '(1x,i10,1x,i10,1x,a15,1x,a10,2(1x,a14),2(1x,g14.5))') &
1859 n, idx, nodestr, ctype(this%ictype(j)), cbedleak, &
1860 cbedcond, c2, this%satcond(j) * fact
1861 end do
1862 end do
1863 write (this%iout, "(1x,108('-'))")
1864 write (this%iout, '(1x,a)') &
1865 'IF VERTICAL CONNECTION, CONDUCTANCE (L^2/T) IS &
1866 &BETWEEN AQUIFER CELL AND OVERLYING LAKE CELL.'
1867 write (this%iout, '(1x,a)') &
1868 'IF HORIZONTAL CONNECTION, CONDUCTANCES ARE PER &
1869 &UNIT SATURATED THICKNESS (L/T).'
1870 write (this%iout, '(1x,a)') &
1871 'IF EMBEDDED CONNECTION, CONDUCTANCES ARE PER &
1872 &UNIT EXCHANGE AREA (1/T).'
1873 !
1874 ! write(this%iout,*) n, idx, nodestr, this%sarea(j), this%warea(j)
1875 !
1876 ! -- calculate stage, surface area, wetted area, volume relation
1877 do n = 1, this%nlakes
1878 write (this%iout, '(//1x,a,1x,i10)') 'STAGE/VOLUME RELATION FOR LAKE ', n
1879 write (this%iout, '(/1x,5(a14))') ' STAGE', ' SURFACE AREA', &
1880 & ' WETTED AREA', ' CONDUCTANCE', &
1881 & ' VOLUME'
1882 write (this%iout, "(1x,70('-'))")
1883 dx = (this%laketop(n) - this%lakebot(n)) / 150.
1884 s = this%lakebot(n)
1885 do j = 1, 151
1886 call this%lak_calculate_conductance(n, s, c)
1887 call this%lak_calculate_sarea(n, s, sa)
1888 call this%lak_calculate_warea(n, s, wa, s)
1889 call this%lak_calculate_vol(n, s, v)
1890 write (this%iout, '(1x,5(E14.5))') s, sa, wa, c, v
1891 s = s + dx
1892 end do
1893 write (this%iout, "(1x,70('-'))")
1894 !
1895 write (this%iout, '(//1x,a,1x,i10)') 'STAGE/VOLUME RELATION FOR LAKE ', n
1896 write (this%iout, '(/1x,4(a14))') ' ', ' ', &
1897 & ' CALCULATED', ' STAGE'
1898 write (this%iout, '(1x,4(a14))') ' STAGE', ' VOLUME', &
1899 & ' STAGE', ' DIFFERENCE'
1900 write (this%iout, "(1x,56('-'))")
1901 s = this%lakebot(n) - dx
1902 do j = 1, 156
1903 call this%lak_calculate_vol(n, s, v)
1904 call this%lak_vol2stage(n, v, c)
1905 write (this%iout, '(1x,4(E14.5))') s, v, c, s - c
1906 s = s + dx
1907 end do
1908 write (this%iout, "(1x,56('-'))")
1909 end do
1910 end if
1911 !
1912 ! -- finished with pointer to gwf hydraulic conductivity
1913 this%gwfk11 => null()
1914 this%gwfk33 => null()
1915 this%gwfsat => null()
1916 this%gwfik33 => null()
1917 !
1918 ! -- deallocate temporary storage
1919 deallocate (clb)
1920 deallocate (caq)
1921 end subroutine lak_read_initial_attr
1922
1923 !> @brief Perform linear interpolation of two vectors.
1924 !!
1925 !! Function assumes x data is sorted in ascending order
1926 !<
1927 subroutine lak_linear_interpolation(this, n, x, y, z, v)
1928 ! -- dummy
1929 class(laktype), intent(inout) :: this
1930 integer(I4B), intent(in) :: n
1931 real(DP), dimension(n), intent(in) :: x
1932 real(DP), dimension(n), intent(in) :: y
1933 real(DP), intent(in) :: z
1934 real(DP), intent(inout) :: v
1935 ! -- local
1936 integer(I4B) :: i
1937 real(DP) :: dx, dydx
1938 ! code
1939 v = dzero
1940 ! below bottom of range - set to lowest value
1941 if (z <= x(1)) then
1942 v = y(1)
1943 ! above highest value
1944 ! slope calculated from interval between n and n-1
1945 else if (z > x(n)) then
1946 dx = x(n) - x(n - 1)
1947 dydx = dzero
1948 if (abs(dx) > dzero) then
1949 dydx = (y(n) - y(n - 1)) / dx
1950 end if
1951 dx = (z - x(n))
1952 v = y(n) + dydx * dx
1953 ! between lowest and highest value in current interval
1954 else
1955 do i = 2, n
1956 dx = x(i) - x(i - 1)
1957 dydx = dzero
1958 if (z >= x(i - 1) .and. z <= x(i)) then
1959 if (abs(dx) > dzero) then
1960 dydx = (y(i) - y(i - 1)) / dx
1961 end if
1962 dx = (z - x(i - 1))
1963 v = y(i - 1) + dydx * dx
1964 exit
1965 end if
1966 end do
1967 end if
1968 end subroutine lak_linear_interpolation
1969
1970 !> @brief Calculate the surface area of a lake at a given stage
1971 !<
1972 subroutine lak_calculate_sarea(this, ilak, stage, sarea)
1973 ! -- dummy
1974 class(laktype), intent(inout) :: this
1975 integer(I4B), intent(in) :: ilak
1976 real(DP), intent(in) :: stage
1977 real(DP), intent(inout) :: sarea
1978 ! -- local
1979 integer(I4B) :: i
1980 integer(I4B) :: ifirst
1981 integer(I4B) :: ilast
1982 real(DP) :: topl
1983 real(DP) :: botl
1984 real(DP) :: sat
1985 real(DP) :: sa
1986 !
1987 sarea = dzero
1988 i = this%ntabrow(ilak)
1989 if (i > 0) then
1990 ifirst = this%ialaktab(ilak)
1991 ilast = this%ialaktab(ilak + 1) - 1
1992 if (stage <= this%tabstage(ifirst)) then
1993 sarea = this%tabsarea(ifirst)
1994 else if (stage >= this%tabstage(ilast)) then
1995 sarea = this%tabsarea(ilast)
1996 else
1997 call this%lak_linear_interpolation(i, this%tabstage(ifirst:ilast), &
1998 this%tabsarea(ifirst:ilast), &
1999 stage, sarea)
2000 end if
2001 else
2002 do i = this%idxlakeconn(ilak), this%idxlakeconn(ilak + 1) - 1
2003 topl = this%telev(i)
2004 botl = this%belev(i)
2005 sat = squadraticsaturation(topl, botl, stage)
2006 sa = sat * this%sarea(i)
2007 sarea = sarea + sa
2008 end do
2009 end if
2010 end subroutine lak_calculate_sarea
2011
2012 !> @brief Calculate the wetted area of a lake at a given stage.
2013 !<
2014 subroutine lak_calculate_warea(this, ilak, stage, warea, hin)
2015 ! -- dummy
2016 class(laktype), intent(inout) :: this
2017 integer(I4B), intent(in) :: ilak
2018 real(DP), intent(in) :: stage
2019 real(DP), intent(inout) :: warea
2020 real(DP), optional, intent(inout) :: hin
2021 ! -- local
2022 integer(I4B) :: i
2023 integer(I4B) :: igwfnode
2024 real(DP) :: head
2025 real(DP) :: wa
2026 !
2027 warea = dzero
2028 do i = this%idxlakeconn(ilak), this%idxlakeconn(ilak + 1) - 1
2029 if (present(hin)) then
2030 head = hin
2031 else
2032 igwfnode = this%gwfconn(i)
2033 head = this%xnew(igwfnode)
2034 end if
2035 call this%lak_calculate_conn_warea(ilak, i, stage, head, wa)
2036 warea = warea + wa
2037 end do
2038 end subroutine lak_calculate_warea
2039
2040 !> @brief Calculate the wetted area of a lake connection at a given stage
2041 !<
2042 subroutine lak_calculate_conn_warea(this, ilak, iconn, stage, head, wa)
2043 ! -- dummy
2044 class(laktype), intent(inout) :: this
2045 integer(I4B), intent(in) :: ilak
2046 integer(I4B), intent(in) :: iconn
2047 real(DP), intent(in) :: stage
2048 real(DP), intent(in) :: head
2049 real(DP), intent(inout) :: wa
2050 ! -- local
2051 integer(I4B) :: i
2052 integer(I4B) :: ifirst
2053 integer(I4B) :: ilast
2054 integer(I4B) :: node
2055 real(DP) :: topl
2056 real(DP) :: botl
2057 real(DP) :: vv
2058 real(DP) :: sat
2059 !
2060 wa = dzero
2061 topl = this%telev(iconn)
2062 botl = this%belev(iconn)
2063 call this%lak_calculate_cond_head(iconn, stage, head, vv)
2064 if (this%ictype(iconn) == 2 .or. this%ictype(iconn) == 3) then
2065 if (vv > topl) vv = topl
2066 i = this%ntabrow(ilak)
2067 ifirst = this%ialaktab(ilak)
2068 ilast = this%ialaktab(ilak + 1) - 1
2069 if (vv <= this%tabstage(ifirst)) then
2070 wa = this%tabwarea(ifirst)
2071 else if (vv >= this%tabstage(ilast)) then
2072 wa = this%tabwarea(ilast)
2073 else
2074 call this%lak_linear_interpolation(i, this%tabstage(ifirst:ilast), &
2075 this%tabwarea(ifirst:ilast), &
2076 vv, wa)
2077 end if
2078 else
2079 node = this%gwfconn(iconn)
2080 ! -- confined cell
2081 if (this%icelltype(node) == 0) then
2082 sat = done
2083 ! -- convertible cell
2084 else
2085 sat = squadraticsaturation(topl, botl, vv)
2086 end if
2087 wa = sat * this%warea(iconn)
2088 end if
2089 end subroutine lak_calculate_conn_warea
2090
2091 !> @brief Calculate the volume of a lake at a given stage
2092 !<
2093 subroutine lak_calculate_vol(this, ilak, stage, volume)
2094 ! -- dummy
2095 class(laktype), intent(inout) :: this
2096 integer(I4B), intent(in) :: ilak
2097 real(DP), intent(in) :: stage
2098 real(DP), intent(inout) :: volume
2099 ! -- local
2100 integer(I4B) :: i
2101 integer(I4B) :: ifirst
2102 integer(I4B) :: ilast
2103 real(DP) :: topl
2104 real(DP) :: botl
2105 real(DP) :: ds
2106 real(DP) :: sa
2107 real(DP) :: v
2108 real(DP) :: sat
2109 !
2110 volume = dzero
2111 i = this%ntabrow(ilak)
2112 if (i > 0) then
2113 ifirst = this%ialaktab(ilak)
2114 ilast = this%ialaktab(ilak + 1) - 1
2115 if (stage <= this%tabstage(ifirst)) then
2116 volume = this%tabvolume(ifirst)
2117 else if (stage >= this%tabstage(ilast)) then
2118 ds = stage - this%tabstage(ilast)
2119 sa = this%tabsarea(ilast)
2120 volume = this%tabvolume(ilast) + ds * sa
2121 else
2122 call this%lak_linear_interpolation(i, this%tabstage(ifirst:ilast), &
2123 this%tabvolume(ifirst:ilast), &
2124 stage, volume)
2125 end if
2126 else
2127 do i = this%idxlakeconn(ilak), this%idxlakeconn(ilak + 1) - 1
2128 topl = this%telev(i)
2129 botl = this%belev(i)
2130 sat = squadraticsaturation(topl, botl, stage)
2131 sa = sat * this%sarea(i)
2132 if (stage < botl) then
2133 v = dzero
2134 else if (stage > botl .and. stage < topl) then
2135 v = sa * (stage - botl)
2136 else
2137 v = sa * (topl - botl) + sa * (stage - topl)
2138 end if
2139 volume = volume + v
2140 end do
2141 end if
2142 end subroutine lak_calculate_vol
2143
2144 !> @brief Calculate the total conductance for a lake at a provided stage
2145 !<
2146 subroutine lak_calculate_conductance(this, ilak, stage, conductance)
2147 ! -- dummy
2148 class(laktype), intent(inout) :: this
2149 integer(I4B), intent(in) :: ilak
2150 real(DP), intent(in) :: stage
2151 real(DP), intent(inout) :: conductance
2152 ! -- local
2153 integer(I4B) :: i
2154 real(DP) :: c
2155 !
2156 conductance = dzero
2157 do i = this%idxlakeconn(ilak), this%idxlakeconn(ilak + 1) - 1
2158 call this%lak_calculate_conn_conductance(ilak, i, stage, stage, c)
2159 conductance = conductance + c
2160 end do
2161 end subroutine lak_calculate_conductance
2162
2163 !> @brief Calculate the controlling lake stage or groundwater head used to
2164 !! calculate the conductance for a lake connection from a provided stage and
2165 !! groundwater head
2166 !<
2167 subroutine lak_calculate_cond_head(this, iconn, stage, head, vv)
2168 ! -- dummy
2169 class(laktype), intent(inout) :: this
2170 integer(I4B), intent(in) :: iconn
2171 real(DP), intent(in) :: stage
2172 real(DP), intent(in) :: head
2173 real(DP), intent(inout) :: vv
2174 ! -- local
2175 real(DP) :: ss
2176 real(DP) :: hh
2177 real(DP) :: topl
2178 real(DP) :: botl
2179 !
2180 topl = this%telev(iconn)
2181 botl = this%belev(iconn)
2182 ss = min(stage, topl)
2183 hh = min(head, topl)
2184 if (this%igwhcopt > 0) then
2185 vv = hh
2186 else if (this%inewton > 0) then
2187 vv = max(ss, hh)
2188 else
2189 vv = dhalf * (ss + hh)
2190 end if
2191 end subroutine lak_calculate_cond_head
2192
2193 !> @brief Calculate the conductance for a lake connection at a provided stage
2194 !! and groundwater head
2195 !<
2196 subroutine lak_calculate_conn_conductance(this, ilak, iconn, stage, head, cond)
2197 ! -- dummy
2198 class(laktype), intent(inout) :: this
2199 integer(I4B), intent(in) :: ilak
2200 integer(I4B), intent(in) :: iconn
2201 real(DP), intent(in) :: stage
2202 real(DP), intent(in) :: head
2203 real(DP), intent(inout) :: cond
2204 ! -- local
2205 integer(I4B) :: node
2206 !real(DP) :: ss
2207 !real(DP) :: hh
2208 real(DP) :: vv
2209 real(DP) :: topl
2210 real(DP) :: botl
2211 real(DP) :: sat
2212 real(DP) :: wa
2213 real(DP) :: vscratio
2214 !
2215 cond = dzero
2216 vscratio = done
2217 topl = this%telev(iconn)
2218 botl = this%belev(iconn)
2219 call this%lak_calculate_cond_head(iconn, stage, head, vv)
2220 sat = squadraticsaturation(topl, botl, vv)
2221 ! vertical connection
2222 ! use full saturated conductance if top and bottom of the lake connection
2223 ! are equal
2224 if (this%ictype(iconn) == 0) then
2225 if (abs(topl - botl) < dprec) then
2226 sat = done
2227 end if
2228 ! horizontal connection
2229 ! use full saturated conductance if the connected cell is not convertible
2230 else if (this%ictype(iconn) == 1) then
2231 node = this%gwfconn(iconn)
2232 if (this%icelltype(node) == 0) then
2233 sat = done
2234 end if
2235 ! embedded connection
2236 else if (this%ictype(iconn) == 2 .or. this%ictype(iconn) == 3) then
2237 node = this%gwfconn(iconn)
2238 if (this%icelltype(node) == 0) then
2239 vv = this%telev(iconn)
2240 call this%lak_calculate_conn_warea(ilak, iconn, vv, vv, wa)
2241 else
2242 call this%lak_calculate_conn_warea(ilak, iconn, stage, head, wa)
2243 end if
2244 sat = wa
2245 end if
2246 !
2247 ! -- account for viscosity effects (if vsc active)
2248 if (this%ivsc == 1) then
2249 ! flow from lake to aquifer
2250 if (stage > head) then
2251 vscratio = this%viscratios(1, iconn)
2252 ! flow from aquifer to lake
2253 else
2254 vscratio = this%viscratios(2, iconn)
2255 end if
2256 end if
2257 cond = sat * this%satcond(iconn) * vscratio
2258 end subroutine lak_calculate_conn_conductance
2259
2260 !> @brief Calculate the total groundwater-lake flow at a provided stage
2261 !<
2262 subroutine lak_calculate_exchange(this, ilak, stage, totflow)
2263 ! -- dummy
2264 class(laktype), intent(inout) :: this
2265 integer(I4B), intent(in) :: ilak
2266 real(DP), intent(in) :: stage
2267 real(DP), intent(inout) :: totflow
2268 ! -- local
2269 integer(I4B) :: j
2270 integer(I4B) :: igwfnode
2271 real(DP) :: flow
2272 real(DP) :: hgwf
2273 !
2274 totflow = dzero
2275 do j = this%idxlakeconn(ilak), this%idxlakeconn(ilak + 1) - 1
2276 igwfnode = this%gwfconn(j)
2277 hgwf = this%xnew(igwfnode)
2278 call this%lak_calculate_conn_exchange(ilak, j, stage, hgwf, flow)
2279 totflow = totflow + flow
2280 end do
2281 end subroutine lak_calculate_exchange
2282
2283 !> @brief Calculate the groundwater-lake flow at a provided stage and
2284 !! groundwater head
2285 !<
2286 subroutine lak_calculate_conn_exchange(this, ilak, iconn, stage, head, flow, &
2287 gwfhcof, gwfrhs)
2288 ! -- dummy
2289 class(laktype), intent(inout) :: this
2290 integer(I4B), intent(in) :: ilak
2291 integer(I4B), intent(in) :: iconn
2292 real(DP), intent(in) :: stage
2293 real(DP), intent(in) :: head
2294 real(DP), intent(inout) :: flow
2295 real(DP), intent(inout), optional :: gwfhcof
2296 real(DP), intent(inout), optional :: gwfrhs
2297 ! -- local
2298 real(DP) :: botl
2299 real(DP) :: cond
2300 real(DP) :: ss
2301 real(DP) :: hh
2302 real(DP) :: gwfhcof0
2303 real(DP) :: gwfrhs0
2304 !
2305 flow = dzero
2306 call this%lak_calculate_conn_conductance(ilak, iconn, stage, head, cond)
2307 botl = this%belev(iconn)
2308 !
2309 ! -- Set ss to stage or botl
2310 if (stage >= botl) then
2311 ss = stage
2312 else
2313 ss = botl
2314 end if
2315 !
2316 ! -- set hh to head or botl
2317 if (head >= botl) then
2318 hh = head
2319 else
2320 hh = botl
2321 end if
2322 !
2323 ! -- calculate flow, positive into lake
2324 flow = cond * (hh - ss)
2325 !
2326 ! -- Calculate gwfhcof and gwfrhs
2327 if (head >= botl) then
2328 gwfhcof0 = -cond
2329 gwfrhs0 = -cond * ss
2330 else
2331 gwfhcof0 = dzero
2332 gwfrhs0 = flow
2333 end if
2334 !
2335 ! Add density contributions, if active
2336 if (this%idense /= 0) then
2337 call this%lak_calculate_density_exchange(iconn, stage, head, cond, botl, &
2338 flow, gwfhcof0, gwfrhs0)
2339 end if
2340 !
2341 ! -- If present update gwfhcof and gwfrhs
2342 if (present(gwfhcof)) gwfhcof = gwfhcof0
2343 if (present(gwfrhs)) gwfrhs = gwfrhs0
2344 end subroutine lak_calculate_conn_exchange
2345
2346 !> @brief Lakebed seepage and its derivatives for a connection (IMPLICIT)
2347 !!
2348 !! Returns the lakebed seepage for one connection, positive into the lake,
2349 !! and optionally its stage and head derivatives. The stage and the connected-
2350 !! cell head are each held at or above the lake bottom, the same wet/dry cutoff
2351 !! used by the default formulation, so the implicit seepage matches the default
2352 !! formulation exactly. lak_fc_implicit uses this to assemble the matrix and
2353 !! lak_cq uses it to report the budget, so the two are consistent.
2354 !<
2355 subroutine lak_calculate_conn_exchange_deriv(this, ilak, iconn, stage, &
2356 head, flow, dqds, dqdh)
2357 ! -- dummy
2358 class(laktype), intent(inout) :: this
2359 integer(I4B), intent(in) :: ilak
2360 integer(I4B), intent(in) :: iconn
2361 real(DP), intent(in) :: stage
2362 real(DP), intent(in) :: head
2363 real(DP), intent(inout) :: flow
2364 real(DP), intent(inout), optional :: dqds
2365 real(DP), intent(inout), optional :: dqdh
2366 ! -- local
2367 real(DP) :: cond, botl, dps, dph, ss, hh
2368 !
2369 call this%lak_calculate_conn_conductance(ilak, iconn, stage, head, cond)
2370 botl = this%belev(iconn)
2371 if (stage >= botl) then
2372 ss = stage
2373 dps = done
2374 else
2375 ss = botl
2376 dps = dzero
2377 end if
2378 if (head >= botl) then
2379 hh = head
2380 dph = done
2381 else
2382 hh = botl
2383 dph = dzero
2384 end if
2385 flow = cond * (hh - ss)
2386 if (present(dqds)) dqds = -cond * dps
2387 if (present(dqdh)) dqdh = cond * dph
2388 end subroutine lak_calculate_conn_exchange_deriv
2389
2390 !> @brief Calculate the groundwater-lake flow at a provided stage and
2391 !! groundwater head
2392 !<
2393 subroutine lak_estimate_conn_exchange(this, iflag, ilak, iconn, idry, stage, &
2394 head, flow, source, gwfhcof, gwfrhs)
2395 ! -- dummy
2396 class(laktype), intent(inout) :: this
2397 integer(I4B), intent(in) :: iflag
2398 integer(I4B), intent(in) :: ilak
2399 integer(I4B), intent(in) :: iconn
2400 integer(I4B), intent(inout) :: idry
2401 real(DP), intent(in) :: stage
2402 real(DP), intent(in) :: head
2403 real(DP), intent(inout) :: flow
2404 real(DP), intent(inout) :: source
2405 real(DP), intent(inout), optional :: gwfhcof
2406 real(DP), intent(inout), optional :: gwfrhs
2407 ! -- local
2408 real(DP) :: gwfhcof0, gwfrhs0
2409 !
2410 flow = dzero
2411 idry = 0
2412 call this%lak_calculate_conn_exchange(ilak, iconn, stage, head, flow, &
2413 gwfhcof0, gwfrhs0)
2414 if (iflag == 1) then
2415 if (flow > dzero) then
2416 source = source + flow
2417 end if
2418 else if (iflag == 2) then
2419 if (-flow > source) then
2420 flow = -source
2421 source = dzero
2422 idry = 1
2423 else if (flow < dzero) then
2424 source = source + flow
2425 end if
2426 end if
2427 !
2428 ! -- Set gwfhcof and gwfrhs if present
2429 if (present(gwfhcof)) gwfhcof = gwfhcof0
2430 if (present(gwfrhs)) gwfrhs = gwfrhs0
2431 end subroutine lak_estimate_conn_exchange
2432
2433 !> @brief Calculate the storage change in a lake based on provided stages
2434 !! and a passed delt
2435 !<
2436 subroutine lak_calculate_storagechange(this, ilak, stage, stage0, delt, dvr)
2437 ! -- dummy
2438 class(laktype), intent(inout) :: this
2439 integer(I4B), intent(in) :: ilak
2440 real(DP), intent(in) :: stage
2441 real(DP), intent(in) :: stage0
2442 real(DP), intent(in) :: delt
2443 real(DP), intent(inout) :: dvr
2444 ! -- local
2445 real(DP) :: v
2446 real(DP) :: v0
2447 !
2448 dvr = dzero
2449 if (this%gwfiss /= 1) then
2450 call this%lak_calculate_vol(ilak, stage, v)
2451 call this%lak_calculate_vol(ilak, stage0, v0)
2452 dvr = (v0 - v) / delt
2453 end if
2454 end subroutine lak_calculate_storagechange
2455
2456 !> @brief Calculate the rainfall for a lake
2457 !<
2458 subroutine lak_calculate_rainfall(this, ilak, stage, ra)
2459 ! -- dummy
2460 class(laktype), intent(inout) :: this
2461 integer(I4B), intent(in) :: ilak
2462 real(DP), intent(in) :: stage
2463 real(DP), intent(inout) :: ra
2464 ! -- local
2465 integer(I4B) :: iconn
2466 real(DP) :: sa
2467 !
2468 ! -- rainfall
2469 iconn = this%idxlakeconn(ilak)
2470 if (this%ictype(iconn) == 2 .or. this%ictype(iconn) == 3) then
2471 sa = this%sareamax(ilak)
2472 else
2473 call this%lak_calculate_sarea(ilak, stage, sa)
2474 end if
2475 ra = this%rainfall(ilak) * sa
2476 end subroutine lak_calculate_rainfall
2477
2478 !> @brief Calculate runoff to a lake
2479 !<
2480 subroutine lak_calculate_runoff(this, ilak, ro)
2481 ! -- dummy
2482 class(laktype), intent(inout) :: this
2483 integer(I4B), intent(in) :: ilak
2484 real(DP), intent(inout) :: ro
2485 !
2486 ! -- runoff
2487 ro = this%runoff(ilak)
2488 end subroutine lak_calculate_runoff
2489
2490 !> @brief Calculate specified inflow to a lake
2491 !<
2492 subroutine lak_calculate_inflow(this, ilak, qin)
2493 ! -- dummy
2494 class(laktype), intent(inout) :: this
2495 integer(I4B), intent(in) :: ilak
2496 real(DP), intent(inout) :: qin
2497 !
2498 ! -- inflow to lake
2499 qin = this%inflow(ilak)
2500 end subroutine lak_calculate_inflow
2501
2502 !> @brief Calculate the external flow terms to a lake
2503 !<
2504 subroutine lak_calculate_external(this, ilak, ex)
2505 ! -- dummy
2506 class(laktype), intent(inout) :: this
2507 integer(I4B), intent(in) :: ilak
2508 real(DP), intent(inout) :: ex
2509 !
2510 ! -- If mover is active, add receiver water to rhs and
2511 ! store available water (as positive value)
2512 ex = dzero
2513 if (this%imover == 1) then
2514 ex = this%pakmvrobj%get_qfrommvr(ilak)
2515 end if
2516 end subroutine lak_calculate_external
2517
2518 !> @brief Calculate the withdrawal from a lake subject to an available volume
2519 !<
2520 subroutine lak_calculate_withdrawal(this, ilak, avail, wr)
2521 ! -- dummy
2522 class(laktype), intent(inout) :: this
2523 integer(I4B), intent(in) :: ilak
2524 real(DP), intent(inout) :: avail
2525 real(DP), intent(inout) :: wr
2526 !
2527 ! -- withdrawals - limit to sum of inflows and available volume
2528 wr = this%withdrawal(ilak)
2529 if (wr > avail) then
2530 wr = -avail
2531 else
2532 if (wr > dzero) then
2533 wr = -wr
2534 end if
2535 end if
2536 avail = avail + wr
2537 end subroutine lak_calculate_withdrawal
2538
2539 !> @brief Calculate the evaporation from a lake at a provided stage subject
2540 !! to an available volume
2541 !<
2542 subroutine lak_calculate_evaporation(this, ilak, stage, avail, ev)
2543 ! -- dummy
2544 class(laktype), intent(inout) :: this
2545 integer(I4B), intent(in) :: ilak
2546 real(DP), intent(in) :: stage
2547 real(DP), intent(inout) :: avail
2548 real(DP), intent(inout) :: ev
2549 ! -- local
2550 real(DP) :: sa
2551 !
2552 ! -- evaporation - limit to sum of inflows and available volume
2553 call this%lak_calculate_sarea(ilak, stage, sa)
2554 ev = sa * this%evaporation(ilak)
2555 if (ev > avail) then
2556 if (is_close(avail, dprec)) then
2557 ev = dzero
2558 else
2559 ev = -avail
2560 end if
2561 else
2562 ev = -ev
2563 end if
2564 avail = avail + ev
2565 end subroutine lak_calculate_evaporation
2566
2567 !> @brief Calculate the outlet inflow to a lake
2568 !<
2569 subroutine lak_calculate_outlet_inflow(this, ilak, outinf)
2570 ! -- dummy
2571 class(laktype), intent(inout) :: this
2572 integer(I4B), intent(in) :: ilak
2573 real(DP), intent(inout) :: outinf
2574 ! -- local
2575 integer(I4B) :: n
2576 !
2577 outinf = dzero
2578 do n = 1, this%noutlets
2579 if (this%lakeout(n) == ilak) then
2580 outinf = outinf - this%simoutrate(n)
2581 if (this%imover == 1) then
2582 outinf = outinf - this%pakmvrobj%get_qtomvr(n)
2583 end if
2584 end if
2585 end do
2586 end subroutine lak_calculate_outlet_inflow
2587
2588 !> @brief Calculate the outlet outflow from a lake
2589 !<
2590 subroutine lak_calculate_outlet_outflow(this, ilak, stage, avail, outoutf)
2591 ! -- dummy
2592 class(laktype), intent(inout) :: this
2593 integer(I4B), intent(in) :: ilak
2594 real(DP), intent(in) :: stage
2595 real(DP), intent(inout) :: avail
2596 real(DP), intent(inout) :: outoutf
2597 ! -- local
2598 integer(I4B) :: n
2599 real(DP) :: g
2600 real(DP) :: d
2601 real(DP) :: c
2602 real(DP) :: gsm
2603 real(DP) :: rate
2604 !
2605 outoutf = dzero
2606 do n = 1, this%noutlets
2607 if (this%lakein(n) == ilak) then
2608 rate = dzero
2609 d = stage - this%outinvert(n)
2610 if (this%outdmax > dzero) then
2611 if (d > this%outdmax) d = this%outdmax
2612 end if
2613 g = dgravity * this%convlength * this%convtime * this%convtime
2614 select case (this%iouttype(n))
2615 ! specified rate
2616 case (0)
2617 rate = this%outrate(n)
2618 if (-rate > avail) then
2619 rate = -avail
2620 end if
2621 ! manning
2622 case (1)
2623 if (d > dzero) then
2624 c = (this%convlength**donethird) * this%convtime
2625 gsm = dzero
2626 if (this%outrough(n) > dzero) then
2627 gsm = done / this%outrough(n)
2628 end if
2629 rate = -c * gsm * this%outwidth(n) * (d**dfivethirds) * &
2630 sqrt(this%outslope(n))
2631 end if
2632 ! weir
2633 case (2)
2634 if (d > dzero) then
2635 rate = -dtwothirds * dcd * this%outwidth(n) * d * &
2636 sqrt(dtwo * g * d)
2637 end if
2638 end select
2639 this%simoutrate(n) = rate
2640 avail = avail + rate
2641 outoutf = outoutf + rate
2642 end if
2643 end do
2644 end subroutine lak_calculate_outlet_outflow
2645
2646 !> @brief Total uncapped outlet outflow rate from a lake at a provided stage
2647 !!
2648 !! Side-effect-free companion to lak_calculate_outlet_outflow used by the
2649 !! implicit formulation: returns the summed (negative) rating-curve outflow for
2650 !! all outlets whose source is ilak, without applying the available-water cap or
2651 !! updating simoutrate. Used to linearize the outlet-outflow sink on the lake
2652 !! row in stage.
2653 !<
2654 subroutine lak_outlet_outflow_rate(this, ilak, stage, qout)
2655 ! -- dummy
2656 class(laktype), intent(inout) :: this
2657 integer(I4B), intent(in) :: ilak
2658 real(DP), intent(in) :: stage
2659 real(DP), intent(inout) :: qout
2660 ! -- local
2661 integer(I4B) :: n
2662 real(DP) :: g, d, c, gsm, rate
2663 !
2664 qout = dzero
2665 do n = 1, this%noutlets
2666 if (this%lakein(n) /= ilak) cycle
2667 rate = dzero
2668 d = stage - this%outinvert(n)
2669 if (this%outdmax > dzero .and. d > this%outdmax) d = this%outdmax
2670 g = dgravity * this%convlength * this%convtime * this%convtime
2671 select case (this%iouttype(n))
2672 case (0) ! specified rate
2673 rate = this%outrate(n)
2674 case (1) ! manning
2675 if (d > dzero) then
2676 c = (this%convlength**donethird) * this%convtime
2677 gsm = dzero
2678 if (this%outrough(n) > dzero) gsm = done / this%outrough(n)
2679 rate = -c * gsm * this%outwidth(n) * (d**dfivethirds) * &
2680 sqrt(this%outslope(n))
2681 end if
2682 case (2) ! weir
2683 if (d > dzero) then
2684 rate = -dtwothirds * dcd * this%outwidth(n) * d * sqrt(dtwo * g * d)
2685 end if
2686 end select
2687 qout = qout + rate
2688 end do
2689 end subroutine lak_outlet_outflow_rate
2690
2691 !> @brief Get the outlet inflow to a lake from another lake
2692 !<
2693 subroutine lak_get_internal_inlet(this, ilak, outinf)
2694 ! -- dummy
2695 class(laktype), intent(inout) :: this
2696 integer(I4B), intent(in) :: ilak
2697 real(DP), intent(inout) :: outinf
2698 ! -- local
2699 integer(I4B) :: n
2700 !
2701 outinf = dzero
2702 do n = 1, this%noutlets
2703 if (this%lakeout(n) == ilak) then
2704 outinf = outinf - this%simoutrate(n)
2705 if (this%imover == 1) then
2706 outinf = outinf - this%pakmvrobj%get_qtomvr(n)
2707 end if
2708 end if
2709 end do
2710 end subroutine lak_get_internal_inlet
2711
2712 !> @brief Get the outlet from a lake to another lake
2713 !<
2714 subroutine lak_get_internal_outlet(this, ilak, outoutf)
2715 ! -- dummy
2716 class(laktype), intent(inout) :: this
2717 integer(I4B), intent(in) :: ilak
2718 real(DP), intent(inout) :: outoutf
2719 ! -- local
2720 integer(I4B) :: n
2721 !
2722 outoutf = dzero
2723 do n = 1, this%noutlets
2724 if (this%lakein(n) == ilak) then
2725 if (this%lakeout(n) < 1) cycle
2726 outoutf = outoutf + this%simoutrate(n)
2727 end if
2728 end do
2729 end subroutine lak_get_internal_outlet
2730
2731 !> @brief Get the outlet outflow from a lake to an external boundary
2732 !<
2733 subroutine lak_get_external_outlet(this, ilak, outoutf)
2734 ! -- dummy
2735 class(laktype), intent(inout) :: this
2736 integer(I4B), intent(in) :: ilak
2737 real(DP), intent(inout) :: outoutf
2738 ! -- local
2739 integer(I4B) :: n
2740 !
2741 outoutf = dzero
2742 do n = 1, this%noutlets
2743 if (this%lakein(n) == ilak) then
2744 if (this%lakeout(n) > 0) cycle
2745 outoutf = outoutf + this%simoutrate(n)
2746 end if
2747 end do
2748 end subroutine lak_get_external_outlet
2749
2750 !> @brief Get the mover outflow from a lake to an external boundary
2751 !<
2752 subroutine lak_get_external_mover(this, ilak, outoutf)
2753 ! -- dummy
2754 class(laktype), intent(inout) :: this
2755 integer(I4B), intent(in) :: ilak
2756 real(DP), intent(inout) :: outoutf
2757 ! -- local
2758 integer(I4B) :: n
2759 !
2760 outoutf = dzero
2761 if (this%imover == 1) then
2762 do n = 1, this%noutlets
2763 if (this%lakein(n) == ilak) then
2764 if (this%lakeout(n) > 0) cycle
2765 outoutf = outoutf + this%pakmvrobj%get_qtomvr(n)
2766 end if
2767 end do
2768 end if
2769 end subroutine lak_get_external_mover
2770
2771 !> @brief Get the mover outflow from a lake to another lake
2772 !<
2773 subroutine lak_get_internal_mover(this, ilak, outoutf)
2774 ! -- dummy
2775 class(laktype), intent(inout) :: this
2776 integer(I4B), intent(in) :: ilak
2777 real(DP), intent(inout) :: outoutf
2778 ! -- local
2779 integer(I4B) :: n
2780 !
2781 outoutf = dzero
2782 if (this%imover == 1) then
2783 do n = 1, this%noutlets
2784 if (this%lakein(n) == ilak) then
2785 if (this%lakeout(n) < 1) cycle
2786 outoutf = outoutf + this%pakmvrobj%get_qtomvr(n)
2787 end if
2788 end do
2789 end if
2790 end subroutine lak_get_internal_mover
2791
2792 !> @brief Get the outlet to mover from a lake
2793 !<
2794 subroutine lak_get_outlet_tomover(this, ilak, outoutf)
2795 ! -- dummy
2796 class(laktype), intent(inout) :: this
2797 integer(I4B), intent(in) :: ilak
2798 real(DP), intent(inout) :: outoutf
2799 ! -- local
2800 integer(I4B) :: n
2801 !
2802 outoutf = dzero
2803 if (this%imover == 1) then
2804 do n = 1, this%noutlets
2805 if (this%lakein(n) == ilak) then
2806 outoutf = outoutf + this%pakmvrobj%get_qtomvr(n)
2807 end if
2808 end do
2809 end if
2810 end subroutine lak_get_outlet_tomover
2811
2812 !> @brief Determine the stage from a provided volume
2813 !<
2814 subroutine lak_vol2stage(this, ilak, vol, stage)
2815 ! -- dummy
2816 class(laktype), intent(inout) :: this
2817 integer(I4B), intent(in) :: ilak
2818 real(DP), intent(in) :: vol
2819 real(DP), intent(inout) :: stage
2820 ! -- local
2821 integer(I4B) :: i
2822 integer(I4B) :: ibs
2823 real(DP) :: s0, s1, sm
2824 real(DP) :: v0, v1, vm
2825 real(DP) :: f0, f1, fm
2826 real(DP) :: sa
2827 real(DP) :: en0, en1
2828 real(DP) :: ds, ds0
2829 real(DP) :: denom
2830 !
2831 s0 = this%lakebot(ilak)
2832 call this%lak_calculate_vol(ilak, s0, v0)
2833 s1 = this%laketop(ilak)
2834 call this%lak_calculate_vol(ilak, s1, v1)
2835 ! -- zero volume
2836 if (vol <= v0) then
2837 stage = s0
2838 ! -- linear relation between stage and volume above top of lake
2839 else if (vol >= v1) then
2840 call this%lak_calculate_sarea(ilak, s1, sa)
2841 stage = s1 + (vol - v1) / sa
2842 ! -- use combination of secant and bisection
2843 else
2844 en0 = s0
2845 en1 = s1
2846 ! sm = s1 ! causes divide by zero in 1st line in secantbisection loop
2847 ! sm = s0 ! causes divide by zero in 1st line in secantbisection loop
2848 sm = dzero
2849 f0 = vol - v0
2850 f1 = vol - v1
2851 ibs = 0
2852 secantbisection: do i = 1, 150
2853 denom = f1 - f0
2854 if (denom /= dzero) then
2855 ds = f1 * (s1 - s0) / denom
2856 else
2857 ibs = 13
2858 end if
2859 if (i == 1) then
2860 ds0 = ds
2861 end if
2862 ! -- use bisection if end points are exceeded
2863 if (sm < en0 .or. sm > en1) ibs = 13
2864 ! -- use bisection if secant method stagnates or if
2865 ! ds exceeds previous ds - bisection would occur
2866 ! after conditions exceeded in 13 iterations
2867 if (ds * ds0 < dprec .or. abs(ds) > abs(ds0)) ibs = ibs + 1
2868 if (ibs > 12) then
2869 ds = dhalf * (s1 - s0)
2870 ibs = 0
2871 end if
2872 sm = s1 - ds
2873 if (abs(ds) < dem6) then
2874 exit secantbisection
2875 end if
2876 call this%lak_calculate_vol(ilak, sm, vm)
2877 fm = vol - vm
2878 s0 = s1
2879 f0 = f1
2880 s1 = sm
2881 f1 = fm
2882 ds0 = ds
2883 end do secantbisection
2884 stage = sm
2885 if (abs(ds) >= dem6) then
2886 write (this%iout, '(1x,a,1x,i0,4(1x,a,1x,g15.6))') &
2887 & 'LAK_VOL2STAGE failed for lake', ilak, 'volume error =', fm, &
2888 & 'finding stage (', stage, ') for volume =', vol, &
2889 & 'final change in stage =', ds
2890 end if
2891 end if
2892 end subroutine lak_vol2stage
2893
2894 !> @brief Determine if a valid lake or outlet number has been specified
2895 function lak_check_valid(this, itemno) result(ierr)
2896 ! -- modules
2897 use simmodule, only: store_error
2898 ! -- return
2899 integer(I4B) :: ierr
2900 ! -- dummy
2901 class(laktype), intent(inout) :: this
2902 integer(I4B), intent(in) :: itemno
2903 ! -- local
2904 integer(I4B) :: ival
2905 !
2906 ierr = 0
2907 ival = abs(itemno)
2908 if (itemno > 0) then
2909 if (ival < 1 .or. ival > this%nlakes) then
2910 write (errmsg, '(a,1x,i0,1x,a,1x,i0,a)') &
2911 'LAKENO', itemno, 'must be greater than 0 and less than or equal to', &
2912 this%nlakes, '.'
2913 call store_error(errmsg)
2914 ierr = 1
2915 end if
2916 else
2917 if (ival < 1 .or. ival > this%noutlets) then
2918 write (errmsg, '(a,1x,i0,1x,a,1x,i0,a)') &
2919 'IOUTLET', itemno, 'must be greater than 0 and less than or equal to', &
2920 this%noutlets, '.'
2921 call store_error(errmsg)
2922 ierr = 1
2923 end if
2924 end if
2925 end function lak_check_valid
2926
2927 !> @brief Apply a PERIOD lake setting and require its value be non-negative
2928 subroutine lak_set_nonneg_value(this, n, itemno, setting, value_array, label)
2929 ! -- dummy
2930 class(laktype), intent(inout) :: this
2931 integer(I4B), intent(in) :: n
2932 integer(I4B), intent(in) :: itemno
2933 character(len=*), intent(in) :: setting
2934 real(DP), dimension(:), intent(inout) :: value_array
2935 character(len=*), intent(in) :: label
2936 ! -- local
2937 integer(I4B) :: istat
2938 !
2939 istat = this%lak_check_valid(itemno)
2940 if (istat /= 0) return
2941 if (itemno < 1 .or. itemno > this%nlakes) return
2942 if (value_array(itemno) < dzero) then
2943 write (errmsg, '(a,i0,a,g0,a)') &
2944 'Lake ', itemno, ' was assigned a '//trim(label)//' value of ', &
2945 value_array(itemno), '. Value must be positive.'
2946 call store_error(errmsg)
2947 end if
2948 end subroutine lak_set_nonneg_value
2949
2950 !> @brief Issue a parameter error for lake ilak
2951 !<
2952 subroutine lak_set_attribute_error(this, ilak, keyword, msg)
2953 ! -- modules
2954 use simmodule, only: store_error
2955 ! -- dummy
2956 class(laktype), intent(inout) :: this
2957 integer(I4B), intent(in) :: ilak
2958 character(len=*), intent(in) :: keyword
2959 character(len=*), intent(in) :: msg
2960 !
2961 if (len(msg) == 0) then
2962 write (errmsg, '(a,1x,a,1x,i0,1x,a)') &
2963 keyword, ' for LAKE', ilak, 'has already been set.'
2964 else
2965 write (errmsg, '(a,1x,a,1x,i0,1x,a)') keyword, ' for LAKE', ilak, msg
2966 end if
2967 call store_error(errmsg)
2968 end subroutine lak_set_attribute_error
2969
2970 !> @brief Source OPTIONS block from input context
2971 !<
2972 subroutine lak_source_options(this)
2973 ! -- dummy
2974 class(laktype), intent(inout) :: this
2975 ! -- local
2976 type(gwflakparamfoundtype) :: found
2977 integer(I4B) :: isize
2978 character(len=LINELENGTH) :: fname
2979 ! -- formats
2980 character(len=*), parameter :: fmtlengthconv = &
2981 &"(4x, 'LENGTH CONVERSION VALUE (',g15.7,') SPECIFIED.')"
2982 character(len=*), parameter :: fmttimeconv = &
2983 &"(4x, 'TIME CONVERSION VALUE (',g15.7,') SPECIFIED.')"
2984 character(len=*), parameter :: fmtlakeopt = &
2985 &"(4x, 'LAKE ', a, ' VALUE (',g15.7,') SPECIFIED.')"
2986 character(len=*), parameter :: fmtoutdmax = &
2987 &"(4x, 'MAXIMUM OUTLET WATER DEPTH (',g15.7,') SPECIFIED.')"
2988 character(len=*), parameter :: fmtlakbin = &
2989 "(4x, 'LAK ', 1x, a, 1x, ' WILL BE SAVED TO FILE: ', &
2990 &a, /4x, 'OPENED ON UNIT: ', I0)"
2991 character(len=*), parameter :: fmtiter = &
2992 &"(4x, 'MAXIMUM LAK ITERATION VALUE (',i0,') SPECIFIED.')"
2993 character(len=*), parameter :: fmtdmaxchg = &
2994 &"(4x, 'MAXIMUM STAGE CHANGE VALUE (',g0,') SPECIFIED.')"
2995 !
2996 ! -- call base class to handle AUXILIARY/NAUX, BOUNDNAMES, PRINT_INPUT,
2997 ! PRINT_FLOWS, SAVE_FLOWS, OBS6_FILENAME
2998 call this%BndExtType%source_options()
2999 !
3000 write (this%iout, '(1x,a)') &
3001 'PROCESSING '//trim(adjustl(this%text))//' OPTIONS'
3002 !
3003 ! -- PRINT_STAGE
3004 call mem_set_value(this%iprhed, 'PRINT_STAGE', this%input_mempath, &
3005 found%print_stage)
3006 if (found%print_stage) then
3007 write (this%iout, '(4x,a)') trim(adjustl(this%text))// &
3008 ' STAGES WILL BE PRINTED TO LISTING FILE.'
3009 end if
3010 !
3011 ! -- STAGE FILEOUT
3012 call mem_set_value(fname, 'STAGEFILE', this%input_mempath, found%stagefile)
3013 if (found%stagefile) then
3014 this%istageout = getunit()
3015 call openfile(this%istageout, this%iout, fname, 'DATA(BINARY)', &
3016 form, access, 'REPLACE', mode_opt=mnormal)
3017 write (this%iout, fmtlakbin) 'STAGE', trim(adjustl(fname)), this%istageout
3018 end if
3019 !
3020 ! -- BUDGET FILEOUT
3021 call mem_set_value(fname, 'BUDGETFILE', this%input_mempath, found%budgetfile)
3022 if (found%budgetfile) then
3023 call assign_iounit(this%ibudgetout, this%inunit, 'BUDGET fileout')
3024 call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', &
3025 form, access, 'REPLACE', mode_opt=mnormal)
3026 write (this%iout, fmtlakbin) 'BUDGET', trim(adjustl(fname)), this%ibudgetout
3027 end if
3028 !
3029 ! -- BUDGETCSV FILEOUT
3030 call mem_set_value(fname, 'BUDGETCSVFILE', this%input_mempath, &
3031 found%budgetcsvfile)
3032 if (found%budgetcsvfile) then
3033 call assign_iounit(this%ibudcsv, this%inunit, 'BUDGETCSV fileout')
3034 call openfile(this%ibudcsv, this%iout, fname, 'CSV', filstat_opt='REPLACE')
3035 write (this%iout, fmtlakbin) 'BUDGET CSV', trim(adjustl(fname)), &
3036 this%ibudcsv
3037 end if
3038 !
3039 ! -- PACKAGE_CONVERGENCE FILEOUT (mf6internal: pkgconvfname)
3040 ! -- defer opening until lak_ar, where the IMPLICIT option is known. The
3041 ! file is not opened for the implicit formulation (lak_cc does not
3042 ! write package convergence in that case).
3043 call mem_set_value(fname, 'PKGCONVFNAME', this%input_mempath, &
3044 found%pkgconvfname)
3045 if (found%pkgconvfname) then
3046 this%pakcsvfile = trim(adjustl(fname))
3047 end if
3048 !
3049 ! -- MOVER
3050 call mem_set_value(this%imover, 'MOVER', this%input_mempath, found%mover)
3051 if (found%mover) then
3052 write (this%iout, '(4x,A)') 'MOVER OPTION ENABLED'
3053 end if
3054 !
3055 ! -- LENGTH_CONVERSION (mf6internal: convlength)
3056 call mem_set_value(this%convlength, 'CONVLENGTH', this%input_mempath, &
3057 found%convlength)
3058 if (found%convlength) write (this%iout, fmtlengthconv) this%convlength
3059 !
3060 ! -- TIME_CONVERSION (mf6internal: convtime)
3061 call mem_set_value(this%convtime, 'CONVTIME', this%input_mempath, &
3062 found%convtime)
3063 if (found%convtime) write (this%iout, fmttimeconv) this%convtime
3064 !
3065 ! -- SURFDEP (mf6internal: surfdep)
3066 call mem_set_value(this%surfdep, 'SURFDEP', this%input_mempath, found%surfdep)
3067 if (found%surfdep) then
3068 if (this%surfdep < dzero) this%surfdep = dzero
3069 write (this%iout, fmtlakeopt) 'SURFDEP', this%surfdep
3070 end if
3071 !
3072 ! -- MAXIMUM_ITERATIONS (mf6internal: maxlakit)
3073 call mem_set_value(this%maxlakit, 'MAXLAKIT', this%input_mempath, &
3074 found%maxlakit)
3075 if (found%maxlakit) write (this%iout, fmtiter) this%maxlakit
3076 !
3077 ! -- MAXIMUM_STAGE_CHANGE (mf6internal: dmaxchg)
3078 call mem_set_value(this%dmaxchg, 'DMAXCHG', this%input_mempath, found%dmaxchg)
3079 if (found%dmaxchg) then
3080 this%delh = dp999 * this%dmaxchg
3081 write (this%iout, fmtdmaxchg) this%dmaxchg
3082 end if
3083 !
3084 ! -- DEV_GROUNDWATER_HEAD_CONDUCTANCE (mf6internal: igwhcopt)
3085 call mem_set_value(this%igwhcopt, 'IGWHCOPT', this%input_mempath, &
3086 found%igwhcopt)
3087 if (found%igwhcopt) then
3088 write (this%iout, '(4x,a)') &
3089 'CONDUCTANCE FOR HORIZONTAL CONNECTIONS WILL BE CALCULATED &
3090 &USING THE GROUNDWATER HEAD'
3091 end if
3092 !
3093 ! -- IMPLICIT (mf6internal: iimplicit)
3094 call mem_set_value(this%iimplicit, 'IIMPLICIT', this%input_mempath, &
3095 found%iimplicit)
3096 if (found%iimplicit) then
3097 write (this%iout, '(4x,a)') &
3098 'LAKE STAGE WILL BE SOLVED AS AN UNKNOWN IN THE GROUNDWATER FLOW '// &
3099 'MATRIX (IMPLICIT FORMULATION)'
3100 end if
3101 !
3102 ! -- DEV_FORCE_LEGACY (mf6internal: iforceleg)
3103 call mem_set_value(this%iforceleg, 'IFORCELEG', this%input_mempath, &
3104 found%iforceleg)
3105 !
3106 ! -- DEV_FORCE_LEGACY_LAKE (mf6internal: iforceleglak); loaded before
3107 ! either block below so both mutual-exclusion checks see a final value
3108 call mem_set_value(this%iforceleglak, 'IFORCELEGLAK', this%input_mempath, &
3109 found%iforceleglak)
3110 !
3111 if (found%iforceleg) then
3112 write (this%iout, '(4x,a)') &
3113 'EVERY ACTIVE LAKE WILL BE SOLVED WITH THE LEGACY SUBSTITUTION '// &
3114 'SOLVER UNDER THE IMPLICIT FORMULATION'
3115 if (this%iforceleglak /= 0) then
3116 call store_error('DEV_FORCE_LEGACY and DEV_FORCE_LEGACY_LAKE '// &
3117 'cannot both be specified.')
3118 end if
3119 end if
3120 !
3121 if (found%iforceleglak) then
3122 write (this%iout, '(4x,a,i0,a)') 'LAKE ', this%iforceleglak, &
3123 ' WILL BE SOLVED WITH THE LEGACY SUBSTITUTION SOLVER UNDER THE '// &
3124 'IMPLICIT FORMULATION'
3125 if (this%iforceleg /= 0) then
3126 call store_error('DEV_FORCE_LEGACY and DEV_FORCE_LEGACY_LAKE '// &
3127 'cannot both be specified.')
3128 end if
3129 end if
3130 !
3131 ! -- DEV_NO_FINAL_CHECK (mf6internal: iconvchk)
3132 call get_isize('ICONVCHK', this%input_mempath, isize)
3133 if (isize > 0) then
3134 this%iconvchk = 0
3135 write (this%iout, '(4x,a)') &
3136 'A FINAL CONVERGENCE CHECK OF THE CHANGE IN LAKE STAGES &
3137 &WILL NOT BE MADE'
3138 end if
3139 !
3140 ! -- DEV_MAXIMUM_OUTLET_DEPTH (mf6internal: outdmax)
3141 call mem_set_value(this%outdmax, 'OUTDMAX', this%input_mempath, found%outdmax)
3142 if (found%outdmax) write (this%iout, fmtoutdmax) this%outdmax
3143 !
3144 write (this%iout, '(1x,a)') 'END OF '//trim(adjustl(this%text))//' OPTIONS'
3145 end subroutine lak_source_options
3146
3147 !> @brief Bind LakInputType pointers.
3148 !!
3149 !! Called once from lak_ar; pointers remain valid for the simulation lifetime.
3150 !! Input tsmanager advances TS-linked values transparently each timestep.
3151 !<
3152 subroutine lak_input_init(this, mempath, naux, noutlets)
3154 ! -- dummy
3155 class(lakinputtype), intent(inout) :: this
3156 character(len=*), intent(in) :: mempath
3157 integer(I4B), intent(in) :: naux
3158 integer(I4B), intent(in) :: noutlets
3159 ! -- local
3160 integer(I4B), dimension(:, :), pointer, contiguous :: tslink => null()
3161 type(characterstringtype), dimension(:), pointer, contiguous :: &
3162 tslinkvars => null()
3163 integer(I4B) :: n
3164 !
3165 ! -- period
3166 call mem_setptr(this%nbound, 'NBOUND', mempath)
3167 call mem_setptr(this%ifno, 'IFNO', mempath)
3168 call mem_setptr(this%setting, 'SETTING', mempath)
3169 call mem_setptr(this%status, 'STATUS', mempath)
3170 if (naux > 0) then
3171 call mem_setptr(this%auxname, 'AUXNAME', mempath)
3172 call mem_setptr(this%auxval, 'AUXVAL', mempath)
3173 end if
3174 ! -- outlets
3175 if (noutlets > 0) then
3176 call mem_setptr(this%outletno, 'OUTLETS_OUTLETNO', mempath)
3177 call mem_setptr(this%outlets_invert, 'OUTLETS_INVERT', mempath)
3178 call mem_setptr(this%outlets_width, 'OUTLETS_WIDTH', mempath)
3179 call mem_setptr(this%outlets_rough, 'OUTLETS_ROUGH', mempath)
3180 call mem_setptr(this%outlets_slope, 'OUTLETS_SLOPE', mempath)
3181 call mem_setptr(tslink, 'TSLINK_OL', mempath)
3182 call mem_setptr(tslinkvars, 'TSLINKVARS_OL', mempath)
3183 do n = 1, size(tslinkvars)
3184 if (tslinkvars(n) == 'OUTLETS_INVERT') &
3185 this%invert_tslink => tslink(n, :)
3186 if (tslinkvars(n) == 'OUTLETS_WIDTH') this%width_tslink => tslink(n, :)
3187 if (tslinkvars(n) == 'OUTLETS_ROUGH') this%rough_tslink => tslink(n, :)
3188 if (tslinkvars(n) == 'OUTLETS_SLOPE') this%slope_tslink => tslink(n, :)
3189 end do
3190 end if
3191 end subroutine lak_input_init
3192
3193 !> @brief Nullify all LakInputType pointers.
3194 !<
3195 subroutine lak_input_destroy(this)
3196 ! -- dummy
3197 class(lakinputtype), intent(inout) :: this
3198 !
3199 nullify (this%nbound)
3200 nullify (this%ifno)
3201 nullify (this%setting)
3202 nullify (this%status)
3203 nullify (this%auxname)
3204 nullify (this%auxval)
3205 nullify (this%outletno)
3206 nullify (this%outlets_invert)
3207 nullify (this%outlets_width)
3208 nullify (this%outlets_rough)
3209 nullify (this%outlets_slope)
3210 nullify (this%invert_tslink)
3211 nullify (this%width_tslink)
3212 nullify (this%rough_tslink)
3213 nullify (this%slope_tslink)
3214 end subroutine lak_input_destroy
3215
3216 !> @brief Allocate and Read
3217 !!
3218 !! Create new LAK package and point bndobj to the new package
3219 !<
3220 subroutine lak_ar(this)
3221 ! -- modules
3222 use constantsmodule, only: mnormal
3224 ! -- dummy
3225 class(laktype), intent(inout) :: this
3226 ! -- formats
3227 character(len=*), parameter :: fmtlakbin = &
3228 "(4x, 'LAK ', 1x, a, 1x, ' WILL BE SAVED TO FILE: ', &
3229 &a, /4x, 'OPENED ON UNIT: ', I0)"
3230 !
3231 ! -- open the deferred PACKAGE_CONVERGENCE file now that all options have
3232 ! been read. lak_cc does not write package convergence for the implicit
3233 ! formulation, because the lake stage is part of the solver (IMS)
3234 ! convergence check. With the IMPLICIT option the file is therefore left
3235 ! unopened (ipakcsv stays 0) and a warning is issued instead.
3236 if (allocated(this%pakcsvfile)) then
3237 if (this%iimplicit /= 0) then
3238 write (warnmsg, '(a)') &
3239 'PACKAGE_CONVERGENCE output file "'//trim(this%pakcsvfile)// &
3240 '" is not written when the IMPLICIT option is active; the lake '// &
3241 'stage is part of the solver (IMS) convergence check.'
3242 call store_warning(warnmsg)
3243 else
3244 this%ipakcsv = getunit()
3245 call openfile(this%ipakcsv, this%iout, this%pakcsvfile, 'CSV', &
3246 filstat_opt='REPLACE', mode_opt=mnormal)
3247 write (this%iout, fmtlakbin) 'PACKAGE_CONVERGENCE', &
3248 trim(this%pakcsvfile), this%ipakcsv
3249 end if
3250 deallocate (this%pakcsvfile)
3251 end if
3252 !
3253 call this%obs%obs_ar()
3254 !
3255 ! -- Allocate arrays in LAK and in package superclass
3256 call this%lak_allocate_arrays()
3257 !
3258 ! -- read optional initial package parameters
3259 call this%read_initial_attr()
3260 !
3261 ! -- bind input context persistent pointers
3262 call this%input%init(this%input_mempath, this%naux, this%noutlets)
3263 if (this%noutlets > 0) then
3264 if (.not. (associated(this%input%invert_tslink) .and. &
3265 associated(this%input%width_tslink) .and. &
3266 associated(this%input%rough_tslink) .and. &
3267 associated(this%input%slope_tslink))) then
3268 call store_error('Time series links for OUTLETS not found in input.')
3269 call store_error_filename(this%input_fname)
3270 end if
3271 end if
3272 !
3273 ! -- setup pakmvrobj
3274 if (this%imover /= 0) then
3275 allocate (this%pakmvrobj)
3276 call this%pakmvrobj%ar(this%noutlets, this%nlakes, this%memoryPath)
3277 end if
3278 end subroutine lak_ar
3279
3280 !> @brief Read and prepare (stress period data)
3281 !<
3282 subroutine lak_rp(this)
3283 ! -- modules
3284 use constantsmodule, only: lenvarname
3285 use tdismodule, only: kper
3286 ! -- dummy
3287 class(laktype), intent(inout) :: this
3288 ! -- local
3289 character(len=LINELENGTH) :: str = ' '
3290 real(DP) :: auxvaldbl = dzero
3291 character(len=LINELENGTH) :: title
3292 character(len=LINELENGTH) :: text
3293 character(len=LENVARNAME) :: setting
3294 integer(I4B) :: node, n, j, itemno
3295 integer(I4B) :: istat
3296 ! -- formats
3297 character(len=*), parameter :: fmtlsp = &
3298 &"(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')"
3299 !
3300 ! -- set nbound to maxbound
3301 this%nbound = this%maxbound
3302 !
3303 ! -- check if data has been loaded for this stress period
3304 if (this%iper == kper) then
3305 !
3306 this%check_attr = 1
3307 !
3308 ! -- setup table to echo period data
3309 if (this%iprpak /= 0) then
3310 title = trim(adjustl(this%text))//' PACKAGE ('// &
3311 trim(adjustl(this%packName))//') DATA FOR PERIOD'
3312 write (title, '(a,1x,i6)') trim(adjustl(title)), kper
3313 call table_cr(this%inputtab, this%packName, title)
3314 call this%inputtab%table_df(1, 4, this%iout, finalize=.false.)
3315 text = 'NUMBER'
3316 call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
3317 text = 'KEYWORD'
3318 call this%inputtab%initialize_column(text, 20, alignment=tableft)
3319 do n = 1, 2
3320 write (text, '(a,1x,i6)') 'VALUE', n
3321 call this%inputtab%initialize_column(text, 15, alignment=tabcenter)
3322 end do
3323 end if
3324 !
3325 ! -- process each period data entry
3326 do n = 1, this%input%nbound
3327 itemno = this%input%ifno(n)
3328 !
3329 ! -- dispatch key for this row
3330 setting = this%input%setting(n)
3331 str = ' '
3332 !
3333 ! -- STATUS (lake only; not TS-enabled)
3334 if (trim(setting) == 'STATUS') then
3335 str = this%input%status(n)
3336 istat = this%lak_check_valid(itemno)
3337 if (istat == 0 .and. itemno >= 1 .and. itemno <= this%nlakes) then
3338 if (trim(str) == 'CONSTANT') then
3339 this%iboundpak(itemno) = -1
3340 else if (trim(str) == 'INACTIVE') then
3341 this%iboundpak(itemno) = 0
3342 else if (trim(str) == 'ACTIVE') then
3343 this%iboundpak(itemno) = 1
3344 else
3345 write (errmsg, '(a,a)') &
3346 'Unknown '//trim(this%text)//' STATUS keyword: ', &
3347 trim(str)//'.'
3348 call store_error(errmsg)
3349 end if
3350 this%status(itemno) = trim(str)
3351 end if
3352 end if
3353 !
3354 ! -- STAGE (validate itemno; assignment via helper)
3355 if (trim(setting) == 'STAGE') then
3356 istat = this%lak_check_valid(itemno)
3357 end if
3358 !
3359 ! -- RAINFALL, EVAPORATION, RUNOFF, INFLOW, WITHDRAWAL (require
3360 ! non-negative)
3361 if (trim(setting) == 'RAINFALL') &
3362 call this%lak_set_nonneg_value(n, itemno, setting, this%rainfall, &
3363 'rainfall')
3364 if (trim(setting) == 'EVAPORATION') &
3365 call this%lak_set_nonneg_value(n, itemno, setting, &
3366 this%evaporation, 'evaporation')
3367 if (trim(setting) == 'RUNOFF') &
3368 call this%lak_set_nonneg_value(n, itemno, setting, this%runoff, &
3369 'runoff')
3370 if (trim(setting) == 'INFLOW') &
3371 call this%lak_set_nonneg_value(n, itemno, setting, this%inflow, &
3372 'inflow')
3373 if (trim(setting) == 'WITHDRAWAL') &
3374 call this%lak_set_nonneg_value(n, itemno, setting, &
3375 this%withdrawal, 'withdrawal')
3376 !
3377 ! -- RATE, INVERT, WIDTH, ROUGH, SLOPE (outlet; validate with
3378 ! negative sign convention)
3379 if (trim(setting) == 'RATE' .or. trim(setting) == 'INVERT' .or. &
3380 trim(setting) == 'WIDTH' .or. trim(setting) == 'ROUGH' .or. &
3381 trim(setting) == 'SLOPE') then
3382 istat = this%lak_check_valid(-itemno)
3383 end if
3384 !
3385 ! -- INVERT, WIDTH, ROUGH, SLOPE latch here so the OUTLETS block's
3386 ! own (separately time-series-linked) baseline resync in lak_ad
3387 ! stops overwriting this outlet's PERIOD-block override
3388 if (istat == 0 .and. itemno >= 1 .and. itemno <= this%noutlets) then
3389 if (trim(setting) == 'INVERT') this%outlet_invert_set(itemno) = .true.
3390 if (trim(setting) == 'WIDTH') this%outlet_width_set(itemno) = .true.
3391 if (trim(setting) == 'ROUGH') this%outlet_rough_set(itemno) = .true.
3392 if (trim(setting) == 'SLOPE') this%outlet_slope_set(itemno) = .true.
3393 end if
3394 !
3395 ! -- AUXILIARY; featureauxvar set via sync_auxvar()
3396 if (this%naux > 0) then
3397 if (trim(setting) == 'PERIOD_AUXILIARY') then
3398 if (itemno >= 1 .and. itemno <= this%nlakes) then
3399 str = this%input%auxname(n)
3400 auxvaldbl = this%input%auxval(n)
3401 end if
3402 end if
3403 end if
3404 !
3405 ! -- echo row to period data table
3406 if (this%iprpak /= 0) then
3407 call this%inputtab%add_term(itemno)
3408 if (trim(setting) == 'PERIOD_AUXILIARY') then
3409 call this%inputtab%add_term('AUXILIARY')
3410 else
3411 call this%inputtab%add_term(trim(setting))
3412 end if
3413 select case (trim(setting))
3414 case ('STATUS')
3415 call this%inputtab%add_term(trim(str))
3416 call this%inputtab%add_term(' ')
3417 case ('STAGE')
3418 call this%inputtab%add_term(this%stage(itemno))
3419 call this%inputtab%add_term(' ')
3420 case ('RAINFALL')
3421 call this%inputtab%add_term(this%rainfall(itemno))
3422 call this%inputtab%add_term(' ')
3423 case ('EVAPORATION')
3424 call this%inputtab%add_term(this%evaporation(itemno))
3425 call this%inputtab%add_term(' ')
3426 case ('RUNOFF')
3427 call this%inputtab%add_term(this%runoff(itemno))
3428 call this%inputtab%add_term(' ')
3429 case ('INFLOW')
3430 call this%inputtab%add_term(this%inflow(itemno))
3431 call this%inputtab%add_term(' ')
3432 case ('WITHDRAWAL')
3433 call this%inputtab%add_term(this%withdrawal(itemno))
3434 call this%inputtab%add_term(' ')
3435 case ('RATE')
3436 call this%inputtab%add_term(this%outrate(itemno))
3437 call this%inputtab%add_term(' ')
3438 case ('INVERT')
3439 call this%inputtab%add_term(this%outinvert(itemno))
3440 call this%inputtab%add_term(' ')
3441 case ('WIDTH')
3442 call this%inputtab%add_term(this%outwidth(itemno))
3443 call this%inputtab%add_term(' ')
3444 case ('ROUGH')
3445 call this%inputtab%add_term(this%outrough(itemno))
3446 call this%inputtab%add_term(' ')
3447 case ('SLOPE')
3448 call this%inputtab%add_term(this%outslope(itemno))
3449 call this%inputtab%add_term(' ')
3450 case ('PERIOD_AUXILIARY')
3451 call this%inputtab%add_term(trim(str))
3452 call this%inputtab%add_term(auxvaldbl)
3453 case default
3454 call this%inputtab%add_term(' ')
3455 call this%inputtab%add_term(' ')
3456 end select
3457 end if
3458 end do
3459 if (this%iprpak /= 0) then
3460 call this%inputtab%finalize_table()
3461 end if
3462 !
3463 ! -- write summary of lake stress period error messages
3464 if (count_errors() > 0) then
3465 call store_error_filename(this%input_fname)
3466 end if
3467 !
3468 ! -- fill bound array with lake stage, conductance, and bottom elevation
3469 do n = 1, this%nlakes
3470 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
3471 node = this%gwfconn(j)
3472 this%nodelist(j) = node
3473 this%bound(1, j) = this%xnewpak(n)
3474 this%bound(2, j) = this%satcond(j)
3475 this%bound(3, j) = this%belev(j)
3476 end do
3477 end do
3478 !
3479 ! -- copy lakein into iprmap so mvr budget contains lake instead of outlet
3480 if (this%imover == 1) then
3481 do n = 1, this%noutlets
3482 this%pakmvrobj%iprmap(n) = this%lakein(n)
3483 end do
3484 end if
3485 else
3486 write (this%iout, fmtlsp) trim(this%filtyp)
3487 end if
3488 !
3489 ! -- fill nodelist and bound(3) every period; nodelist for non-vertical
3490 ! connections is not updated by lak_cf so must be set here.
3491 ! bound(3) (bed elevation) is static and only needs to be set once.
3492 do n = 1, this%nlakes
3493 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
3494 this%nodelist(j) = this%gwfconn(j)
3495 this%bound(3, j) = this%belev(j)
3496 end do
3497 end do
3498 end subroutine lak_rp
3499
3500 !> @brief Add package connection to matrix
3501 !<
3502 subroutine lak_ad(this)
3503 ! -- modules
3505 ! -- dummy
3506 class(laktype) :: this
3507 ! -- local
3508 integer(I4B) :: n
3509 integer(I4B) :: j
3510 integer(I4B) :: iaux
3511 integer(I4B) :: itemno
3512 !
3513 ! -- sync PACKAGEDATA AUX TS and advance observations;
3514 ! sync_period_auxvar (inside bnd_ad) handles PERIOD AUXILIARY TS
3515 call this%BndExtType%bnd_ad()
3516 !
3517 ! -- re-sync static OUTLETS values (invert, width, rough, slope) linked
3518 ! to a time series, skipping any field a PERIOD-block setting has
3519 ! already overridden for this outlet -- that override must persist
3520 ! until a later PERIOD block changes it
3521 if (this%ts_active .and. this%noutlets > 0) then
3522 do n = 1, size(this%input%outletno)
3523 itemno = this%input%outletno(n)
3524 if (itemno < 1 .or. itemno > this%noutlets) cycle
3525 if (.not. this%outlet_invert_set(itemno) .and. &
3526 this%input%invert_tslink(n) /= 0) &
3527 this%outinvert(itemno) = this%input%outlets_invert(n)
3528 if (.not. this%outlet_width_set(itemno) .and. &
3529 this%input%width_tslink(n) /= 0) &
3530 this%outwidth(itemno) = this%input%outlets_width(n)
3531 if (.not. this%outlet_rough_set(itemno) .and. &
3532 this%input%rough_tslink(n) /= 0) &
3533 this%outrough(itemno) = this%input%outlets_rough(n)
3534 if (.not. this%outlet_slope_set(itemno) .and. &
3535 this%input%slope_tslink(n) /= 0) &
3536 this%outslope(itemno) = this%input%outlets_slope(n)
3537 end do
3538 end if
3539 !
3540 ! -- update auxiliary variables
3541 if (this%naux > 0) then
3542 do n = 1, this%nlakes
3543 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
3544 do iaux = 1, this%naux
3545 if (this%noupdateauxvar(iaux) /= 0) cycle
3546 this%auxvar(iaux, j) = this%featureauxvar(iaux, n)
3547 end do
3548 end do
3549 end do
3550 end if
3551 !
3552 ! -- Update or restore state
3553 if (ifailedstepretry == 0) then
3554 !
3555 ! -- copy xnew into xold and set xnewpak to stage for
3556 ! constant stage lakes
3557 do n = 1, this%nlakes
3558 this%xoldpak(n) = this%xnewpak(n)
3559 this%stageiter(n) = this%xnewpak(n)
3560 if (this%iboundpak(n) < 0) then
3561 this%xnewpak(n) = this%stage(n)
3562 end if
3563 this%seep0(n) = dzero
3564 end do
3565 else
3566 !
3567 ! -- copy xold back into xnew as this is a
3568 ! retry of this time step
3569 do n = 1, this%nlakes
3570 this%xnewpak(n) = this%xoldpak(n)
3571 this%stageiter(n) = this%xnewpak(n)
3572 if (this%iboundpak(n) < 0) then
3573 this%xnewpak(n) = this%stage(n)
3574 end if
3575 this%seep0(n) = dzero
3576 end do
3577 end if
3578 !
3579 ! -- pakmvrobj ad
3580 if (this%imover == 1) then
3581 call this%pakmvrobj%ad()
3582 end if
3583 end subroutine lak_ad
3584
3585 !> @brief Formulate the HCOF and RHS terms
3586 !!
3587 !! Skip if no lakes, otherwise calculate hcof and rhs
3588 !<
3589 subroutine lak_cf(this)
3590 ! -- dummy
3591 class(laktype) :: this
3592 ! -- local
3593 integer(I4B) :: j, n
3594 integer(I4B) :: igwfnode
3595 real(DP) :: hlak, bottom_lake
3596 !
3597 ! -- save groundwater seepage for lake solution
3598 do n = 1, this%nlakes
3599 this%seep0(n) = this%seep(n)
3600 end do
3601 !
3602 ! -- save variables for convergence check
3603 do n = 1, this%nlakes
3604 this%s0(n) = this%xnewpak(n)
3605 call this%lak_calculate_exchange(n, this%s0(n), this%qgwf0(n))
3606 end do
3607 !
3608 ! -- find highest active cell
3609 do n = 1, this%nlakes
3610 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
3611 ! -- skip horizontal connections
3612 if (this%ictype(j) /= 0) then
3613 cycle
3614 end if
3615 igwfnode = this%nodesontop(j)
3616 if (this%ibound(igwfnode) == 0) then
3617 call this%dis%highest_active(igwfnode, this%ibound)
3618 end if
3619 this%nodelist(j) = igwfnode
3620 this%gwfconn(j) = igwfnode
3621 end do
3622 end do
3623 !
3624 ! -- reset ibound for cells where lake stage is above the bottom
3625 ! of the lake in the cell or the lake is inactive - only applied to
3626 ! vertical connections
3627 do n = 1, this%nlakes
3628 !
3629 hlak = this%xnewpak(n)
3630 !
3631 ! -- Go through lake connections
3632 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
3633 !
3634 ! -- assign gwf node number
3635 igwfnode = this%gwfconn(j)
3636 !
3637 ! -- skip inactive or constant head GWF cells
3638 if (this%ibound(igwfnode) < 1) then
3639 cycle
3640 end if
3641 !
3642 ! -- skip horizontal connections
3643 if (this%ictype(j) /= 0) then
3644 cycle
3645 end if
3646 !
3647 ! -- skip embedded lakes
3648 if (this%ictype(j) == 2 .or. this%ictype(j) == 3) then
3649 cycle
3650 end if
3651 !
3652 ! -- Mark ibound for wet lakes or inactive lakes; reset to 1 otherwise
3653 bottom_lake = this%belev(j)
3654 if (hlak > bottom_lake .or. this%iboundpak(n) == 0) then
3655 this%ibound(igwfnode) = iwetlake
3656 else
3657 this%ibound(igwfnode) = 1
3658 end if
3659 end do
3660 !
3661 end do
3662 !
3663 ! -- Store the lake stage and cond in bound array for other
3664 ! packages, such as the BUY package
3665 call this%lak_bound_update()
3666 end subroutine lak_cf
3667
3668 !> @brief Copy rhs and hcof into solution rhs and amat
3669 !<
3670 subroutine lak_fc(this, rhs, ia, idxglo, matrix_sln)
3671 ! -- dummy
3672 class(laktype) :: this
3673 real(DP), dimension(:), intent(inout) :: rhs
3674 integer(I4B), dimension(:), intent(in) :: ia
3675 integer(I4B), dimension(:), intent(in) :: idxglo
3676 class(matrixbasetype), pointer :: matrix_sln
3677 ! -- local
3678 integer(I4B) :: j, n
3679 integer(I4B) :: igwfnode
3680 integer(I4B) :: ipossymd
3681 !
3682 ! -- pakmvrobj fc
3683 if (this%imover == 1) then
3684 call this%pakmvrobj%fc()
3685 end if
3686 !
3687 ! -- implicit formulation: assemble the lake equations directly into the
3688 ! groundwater flow matrix instead of solving the stage by substitution
3689 if (this%iimplicit /= 0) then
3690 call this%lak_fc_implicit(rhs, matrix_sln)
3691 return
3692 end if
3693 !
3694 ! -- legacy formulation: solve the lake stage by substitution, then add the
3695 ! resulting lake-aquifer exchange terms to the groundwater flow matrix
3696 call this%lak_solve()
3697 do n = 1, this%nlakes
3698 if (this%iboundpak(n) == 0) cycle
3699 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
3700 igwfnode = this%gwfconn(j)
3701 if (this%ibound(igwfnode) < 1) cycle
3702 ipossymd = idxglo(ia(igwfnode))
3703 call matrix_sln%add_value_pos(ipossymd, this%hcof(j))
3704 rhs(igwfnode) = rhs(igwfnode) + this%rhs(j)
3705 end do
3706 end do
3707 end subroutine lak_fc
3708
3709 !> @brief Fill newton terms
3710 !<
3711 subroutine lak_fn(this, rhs, ia, idxglo, matrix_sln)
3712 ! -- dummy
3713 class(laktype) :: this
3714 real(DP), dimension(:), intent(inout) :: rhs
3715 integer(I4B), dimension(:), intent(in) :: ia
3716 integer(I4B), dimension(:), intent(in) :: idxglo
3717 class(matrixbasetype), pointer :: matrix_sln
3718 ! -- local
3719 integer(I4B) :: j, n
3720 integer(I4B) :: ipos
3721 integer(I4B) :: igwfnode
3722 integer(I4B) :: idry
3723 real(DP) :: hlak
3724 real(DP) :: avail
3725 real(DP) :: ra
3726 real(DP) :: ro
3727 real(DP) :: qinf
3728 real(DP) :: ex
3729 real(DP) :: head
3730 real(DP) :: q
3731 real(DP) :: q1
3732 real(DP) :: rterm
3733 real(DP) :: drterm
3734 !
3735 ! -- implicit formulation: the lakebed seepage Jacobian is already
3736 ! assembled exactly in lak_fc_implicit for constant-conductance
3737 ! (confined / saturated) connections. Nonlinear conductance Newton terms
3738 ! are Phase 2.
3739 if (this%iimplicit /= 0) then
3740 return
3741 end if
3742 !
3743 do n = 1, this%nlakes
3744 if (this%iboundpak(n) == 0) cycle
3745 hlak = this%xnewpak(n)
3746 call this%lak_calculate_available(n, hlak, avail, &
3747 ra, ro, qinf, ex, this%delh)
3748 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
3749 igwfnode = this%gwfconn(j)
3750 ipos = ia(igwfnode)
3751 head = this%xnew(igwfnode)
3752 if (-this%hcof(j) > dzero) then
3753 if (this%ibound(igwfnode) > 0) then
3754 ! -- estimate lake-aquifer exchange with perturbed groundwater head
3755 ! exchange is relative to the lake
3756 !avail = DEP20
3757 call this%lak_estimate_conn_exchange(2, n, j, idry, hlak, &
3758 head + this%delh, q1, avail)
3759 q1 = -q1
3760 ! -- calculate unperturbed lake-aquifer exchange
3761 q = this%hcof(j) * head - this%rhs(j)
3762 ! -- calculate rterm
3763 rterm = this%hcof(j) * head
3764 ! -- calculate derivative
3765 drterm = (q1 - q) / this%delh
3766 ! -- add terms to convert conductance formulation into
3767 ! newton-raphson formulation
3768 call matrix_sln%add_value_pos(idxglo(ipos), drterm - this%hcof(j))
3769 rhs(igwfnode) = rhs(igwfnode) - rterm + drterm * head
3770 end if
3771 end if
3772 end do
3773 end do
3774 end subroutine lak_fn
3775
3776 !> @brief Apply Newton under-relaxation to the lake stage
3777 !!
3778 !! Implicit formulation only. The model Newton under-relaxation step (gwf_nur)
3779 !! calls this routine with the lake-stage part of the solution. If an updated
3780 !! stage falls below the lake bottom, it is relaxed back toward the bottom (90
3781 !! percent of the way) and its change is zeroed. Active only when the model
3782 !! uses NEWTON UNDER_RELAXATION.
3783 !<
3784 subroutine lak_nur(this, neqpak, x, xtemp, dx, inewtonur, dxmax, locmax)
3785 ! -- dummy
3786 class(laktype), intent(inout) :: this
3787 integer(I4B), intent(in) :: neqpak
3788 real(DP), dimension(neqpak), intent(inout) :: x
3789 real(DP), dimension(neqpak), intent(in) :: xtemp
3790 real(DP), dimension(neqpak), intent(inout) :: dx
3791 integer(I4B), intent(inout) :: inewtonur
3792 real(DP), intent(inout) :: dxmax
3793 integer(I4B), intent(inout) :: locmax
3794 ! -- local
3795 integer(I4B) :: n
3796 real(DP) :: botl
3797 real(DP) :: xx
3798 real(DP) :: dxx
3799 !
3800 ! -- only the implicit formulation has the lake stage in the global solution
3801 if (this%iimplicit == 0) return
3802 !
3803 ! -- Newton-Raphson under-relaxation: hold the stage at the lake bottom
3804 do n = 1, this%nlakes
3805 if (this%iboundpak(n) < 1) cycle
3806 botl = this%lakebot(n)
3807 !
3808 ! -- only apply under-relaxation if the updated stage is below the bottom
3809 ! of the lake
3810 if (x(n) < botl) then
3811 inewtonur = 1
3812 xx = xtemp(n) * (done - dp9) + botl * dp9
3813 dxx = x(n) - xx
3814 if (abs(dxx) > abs(dxmax)) then
3815 locmax = n
3816 dxmax = dxx
3817 end if
3818 x(n) = xx
3819 dx(n) = dzero
3820 end if
3821 end do
3822 end subroutine lak_nur
3823
3824 !> @brief Final convergence check for package
3825 !<
3826 subroutine lak_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak)
3827 ! -- modules
3828 use tdismodule, only: totim, kstp, kper, delt
3829 ! -- dummy
3830 class(laktype), intent(inout) :: this
3831 integer(I4B), intent(in) :: innertot
3832 integer(I4B), intent(in) :: kiter
3833 integer(I4B), intent(in) :: iend
3834 integer(I4B), intent(in) :: icnvgmod
3835 character(len=LENPAKLOC), intent(inout) :: cpak
3836 integer(I4B), intent(inout) :: ipak
3837 real(DP), intent(inout) :: dpak
3838 ! -- local
3839 character(len=LENPAKLOC) :: cloc
3840 character(len=LINELENGTH) :: tag
3841 integer(I4B) :: icheck
3842 integer(I4B) :: ipakfail
3843 integer(I4B) :: locdhmax
3844 integer(I4B) :: locresidmax
3845 integer(I4B) :: locdgwfmax
3846 integer(I4B) :: locdqoutmax
3847 integer(I4B) :: locdqfrommvrmax
3848 integer(I4B) :: ntabrows
3849 integer(I4B) :: ntabcols
3850 integer(I4B) :: n
3851 real(DP) :: q
3852 real(DP) :: q0
3853 real(DP) :: qtolfact
3854 real(DP) :: area
3855 real(DP) :: gwf0
3856 real(DP) :: gwf
3857 real(DP) :: dh
3858 real(DP) :: resid
3859 real(DP) :: dgwf
3860 real(DP) :: hlak0
3861 real(DP) :: hlak
3862 real(DP) :: qout0
3863 real(DP) :: qout
3864 real(DP) :: dqout
3865 real(DP) :: inf
3866 real(DP) :: ra
3867 real(DP) :: ro
3868 real(DP) :: qinf
3869 real(DP) :: ex
3870 real(DP) :: dhmax
3871 real(DP) :: residmax
3872 real(DP) :: dgwfmax
3873 real(DP) :: dqoutmax
3874 real(DP) :: dqfrommvr
3875 real(DP) :: dqfrommvrmax
3876 ! -- switch any stalled IMPLICIT lake back to the legacy solver
3877 call this%lak_set_legacy(kiter, icnvgmod)
3878 !
3879 ! -- on the last outer iteration of a solution that has not converged, warn
3880 ! about a perched (disconnected) lake that has no practical steady state.
3881 ! Done for both formulations (the implicit path returns just below).
3882 if (iend /= 0 .and. icnvgmod == 0) then
3883 call this%lak_check_disconnected()
3884 end if
3885 !
3886 ! -- implicit formulation: lake stage is solved in the global matrix,
3887 ! so its convergence is governed by the solution's dvclose check on the
3888 ! stage unknown; no separate package convergence check is performed here.
3889 if (this%iimplicit /= 0) then
3890 return
3891 end if
3892 !
3893 ! -- initialize local variables
3894 icheck = this%iconvchk
3895 ipakfail = 0
3896 locdhmax = 0
3897 locresidmax = 0
3898 locdgwfmax = 0
3899 locdqoutmax = 0
3900 locdqfrommvrmax = 0
3901 dhmax = dzero
3902 residmax = dzero
3903 dgwfmax = dzero
3904 dqoutmax = dzero
3905 dqfrommvrmax = dzero
3906 !
3907 ! -- if not saving package convergence data on check convergence if
3908 ! the model is considered converged
3909 if (this%ipakcsv == 0) then
3910 if (icnvgmod == 0) then
3911 icheck = 0
3912 end if
3913 !
3914 ! -- saving package convergence data
3915 else
3916 !
3917 ! -- header for package csv
3918 if (.not. associated(this%pakcsvtab)) then
3919 !
3920 ! -- determine the number of columns and rows
3921 ntabrows = 1
3922 ntabcols = 11
3923 if (this%noutlets > 0) then
3924 ntabcols = ntabcols + 2
3925 end if
3926 if (this%imover == 1) then
3927 ntabcols = ntabcols + 2
3928 end if
3929 !
3930 ! -- setup table
3931 call table_cr(this%pakcsvtab, this%packName, '')
3932 call this%pakcsvtab%table_df(ntabrows, ntabcols, this%ipakcsv, &
3933 lineseparator=.false., separator=',', &
3934 finalize=.false.)
3935 !
3936 ! -- add columns to package csv
3937 tag = 'total_inner_iterations'
3938 call this%pakcsvtab%initialize_column(tag, 10, alignment=tableft)
3939 tag = 'totim'
3940 call this%pakcsvtab%initialize_column(tag, 10, alignment=tableft)
3941 tag = 'kper'
3942 call this%pakcsvtab%initialize_column(tag, 10, alignment=tableft)
3943 tag = 'kstp'
3944 call this%pakcsvtab%initialize_column(tag, 10, alignment=tableft)
3945 tag = 'nouter'
3946 call this%pakcsvtab%initialize_column(tag, 10, alignment=tableft)
3947 tag = 'dvmax'
3948 call this%pakcsvtab%initialize_column(tag, 15, alignment=tableft)
3949 tag = 'dvmax_loc'
3950 call this%pakcsvtab%initialize_column(tag, 15, alignment=tableft)
3951 tag = 'residmax'
3952 call this%pakcsvtab%initialize_column(tag, 15, alignment=tableft)
3953 tag = 'residmax_loc'
3954 call this%pakcsvtab%initialize_column(tag, 15, alignment=tableft)
3955 tag = 'dgwfmax'
3956 call this%pakcsvtab%initialize_column(tag, 15, alignment=tableft)
3957 tag = 'dgwfmax_loc'
3958 call this%pakcsvtab%initialize_column(tag, 15, alignment=tableft)
3959 if (this%noutlets > 0) then
3960 tag = 'dqoutmax'
3961 call this%pakcsvtab%initialize_column(tag, 15, alignment=tableft)
3962 tag = 'dqoutmax_loc'
3963 call this%pakcsvtab%initialize_column(tag, 15, alignment=tableft)
3964 end if
3965 if (this%imover == 1) then
3966 tag = 'dqfrommvrmax'
3967 call this%pakcsvtab%initialize_column(tag, 15, alignment=tableft)
3968 tag = 'dqfrommvrmax_loc'
3969 call this%pakcsvtab%initialize_column(tag, 16, alignment=tableft)
3970 end if
3971 end if
3972 end if
3973 !
3974 ! -- perform package convergence check
3975 if (icheck /= 0) then
3976 final_check: do n = 1, this%nlakes
3977 if (this%iboundpak(n) < 1) cycle
3978 !
3979 ! -- set previous and current lake stage
3980 hlak0 = this%s0(n)
3981 hlak = this%xnewpak(n)
3982 !
3983 ! -- stage difference
3984 dh = hlak0 - hlak
3985 !
3986 ! -- calculate surface area
3987 call this%lak_calculate_sarea(n, hlak, area)
3988 !
3989 ! -- set the Q to length factor
3990 if (area > dzero) then
3991 qtolfact = delt / area
3992 else
3993 qtolfact = dzero
3994 end if
3995 !
3996 ! -- difference in the residual
3997 call this%lak_calculate_residual(n, hlak, resid)
3998 resid = resid * qtolfact
3999 !
4000 ! -- change in gwf exchange
4001 dgwf = dzero
4002 if (area > dzero) then
4003 gwf0 = this%qgwf0(n)
4004 call this%lak_calculate_exchange(n, hlak, gwf)
4005 dgwf = (gwf0 - gwf) * qtolfact
4006 end if
4007 !
4008 ! -- change in outflows
4009 dqout = dzero
4010 if (this%noutlets > 0) then
4011 if (area > dzero) then
4012 call this%lak_calculate_available(n, hlak0, inf, ra, ro, qinf, ex)
4013 call this%lak_calculate_outlet_outflow(n, hlak0, inf, qout0)
4014 call this%lak_calculate_available(n, hlak, inf, ra, ro, qinf, ex)
4015 call this%lak_calculate_outlet_outflow(n, hlak, inf, qout)
4016 dqout = (qout0 - qout) * qtolfact
4017 end if
4018 end if
4019 !
4020 ! -- q from mvr
4021 dqfrommvr = dzero
4022 if (this%imover == 1) then
4023 q = this%pakmvrobj%get_qfrommvr(n)
4024 q0 = this%pakmvrobj%get_qfrommvr0(n)
4025 dqfrommvr = qtolfact * (q0 - q)
4026 end if
4027 !
4028 ! -- evaluate magnitude of differences
4029 if (n == 1) then
4030 locdhmax = n
4031 dhmax = dh
4032 locdgwfmax = n
4033 residmax = resid
4034 locresidmax = n
4035 dgwfmax = dgwf
4036 locdqoutmax = n
4037 dqoutmax = dqout
4038 dqfrommvrmax = dqfrommvr
4039 locdqfrommvrmax = n
4040 else
4041 if (abs(dh) > abs(dhmax)) then
4042 locdhmax = n
4043 dhmax = dh
4044 end if
4045 if (abs(resid) > abs(residmax)) then
4046 locresidmax = n
4047 residmax = resid
4048 end if
4049 if (abs(dgwf) > abs(dgwfmax)) then
4050 locdgwfmax = n
4051 dgwfmax = dgwf
4052 end if
4053 if (abs(dqout) > abs(dqoutmax)) then
4054 locdqoutmax = n
4055 dqoutmax = dqout
4056 end if
4057 if (abs(dqfrommvr) > abs(dqfrommvrmax)) then
4058 dqfrommvrmax = dqfrommvr
4059 locdqfrommvrmax = n
4060 end if
4061 end if
4062 end do final_check
4063 !
4064 ! -- set dpak and cpak
4065 if (abs(dhmax) > abs(dpak)) then
4066 ipak = locdhmax
4067 dpak = dhmax
4068 write (cloc, "(a,'-',a)") &
4069 trim(this%packName), 'stage'
4070 cpak = trim(cloc)
4071 end if
4072 if (abs(residmax) > abs(dpak)) then
4073 ipak = locresidmax
4074 dpak = residmax
4075 write (cloc, "(a,'-',a)") &
4076 trim(this%packName), 'residual'
4077 cpak = trim(cloc)
4078 end if
4079 if (abs(dgwfmax) > abs(dpak)) then
4080 ipak = locdgwfmax
4081 dpak = dgwfmax
4082 write (cloc, "(a,'-',a)") &
4083 trim(this%packName), 'gwf'
4084 cpak = trim(cloc)
4085 end if
4086 if (this%noutlets > 0) then
4087 if (abs(dqoutmax) > abs(dpak)) then
4088 ipak = locdqoutmax
4089 dpak = dqoutmax
4090 write (cloc, "(a,'-',a)") &
4091 trim(this%packName), 'outlet'
4092 cpak = trim(cloc)
4093 end if
4094 end if
4095 if (this%imover == 1) then
4096 if (abs(dqfrommvrmax) > abs(dpak)) then
4097 ipak = locdqfrommvrmax
4098 dpak = dqfrommvrmax
4099 write (cloc, "(a,'-',a)") trim(this%packName), 'qfrommvr'
4100 cpak = trim(cloc)
4101 end if
4102 end if
4103 !
4104 ! -- write convergence data to package csv
4105 if (this%ipakcsv /= 0) then
4106 !
4107 ! -- write the data
4108 call this%pakcsvtab%add_term(innertot)
4109 call this%pakcsvtab%add_term(totim)
4110 call this%pakcsvtab%add_term(kper)
4111 call this%pakcsvtab%add_term(kstp)
4112 call this%pakcsvtab%add_term(kiter)
4113 call this%pakcsvtab%add_term(dhmax)
4114 call this%pakcsvtab%add_term(locdhmax)
4115 call this%pakcsvtab%add_term(residmax)
4116 call this%pakcsvtab%add_term(locresidmax)
4117 call this%pakcsvtab%add_term(dgwfmax)
4118 call this%pakcsvtab%add_term(locdgwfmax)
4119 if (this%noutlets > 0) then
4120 call this%pakcsvtab%add_term(dqoutmax)
4121 call this%pakcsvtab%add_term(locdqoutmax)
4122 end if
4123 if (this%imover == 1) then
4124 call this%pakcsvtab%add_term(dqfrommvrmax)
4125 call this%pakcsvtab%add_term(locdqfrommvrmax)
4126 end if
4127 !
4128 ! -- finalize the package csv
4129 if (iend == 1) then
4130 call this%pakcsvtab%finalize_table()
4131 end if
4132 end if
4133 end if
4134 end subroutine lak_cc
4135
4136 !> @brief Calculate flows
4137 !<
4138 subroutine lak_cq(this, x, flowja, iadv)
4139 ! -- modules
4140 use tdismodule, only: delt
4141 ! -- dummy
4142 class(laktype), intent(inout) :: this
4143 real(DP), dimension(:), intent(in) :: x
4144 real(DP), dimension(:), contiguous, intent(inout) :: flowja
4145 integer(I4B), optional, intent(in) :: iadv
4146 ! -- local
4147 real(DP) :: rrate
4148 real(DP) :: chratin, chratout
4149 ! -- for budget
4150 integer(I4B) :: j, n, igwfnode
4151 real(DP) :: hlak, head, flow, dqdh
4152 real(DP) :: v0, v1, sa, sf
4153 !
4154 call this%lak_solve(update=.false.)
4155 !
4156 ! -- for the IMPLICIT formulation, report the lake terms with the same
4157 ! treatment that lak_fc_implicit assembled into the matrix, so the lake
4158 ! and gwf-cell budgets match the solved flows. lak_solve above set these
4159 ! from the substitution path (hard-cutoff seepage; availability-limited
4160 ! losses), which is correct for a lake on the legacy solver but
4161 ! not for an implicit lake, so overwrite them for the implicit
4162 ! (non-legacy) lakes only.
4163 if (this%iimplicit /= 0) then
4164 do n = 1, this%nlakes
4165 if (this%iboundpak(n) < 1 .or. this%ilegacy(n) /= 0) cycle
4166 hlak = this%xnewpak(n)
4167 !
4168 ! -- lakebed seepage: use the same exchange the matrix assembled
4169 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
4170 igwfnode = this%gwfconn(j)
4171 if (this%ibound(igwfnode) < 1) cycle
4172 head = this%xnew(igwfnode)
4173 call this%lak_calculate_conn_exchange_deriv(n, j, hlak, head, &
4174 flow, dqdh=dqdh)
4175 this%hcof(j) = -dqdh
4176 this%rhs(j) = -dqdh * head + flow
4177 end do
4178 !
4179 ! -- stage-driven losses: the matrix (lak_budget_nogwf) ramps
4180 ! evaporation and withdrawal toward zero as the lake approaches its
4181 ! bottom with the surfdep factor (sf) rather than the substitution
4182 ! solver's availability limiting, so report them the same way. This
4183 ! keeps the lake budget closed for a drying lake. (The outlet
4184 ! outflow is already near zero at the bottom, as its invert is above
4185 ! the lake bottom, and the storage term reflects the solved stage.)
4186 call this%lak_calculate_sarea(n, hlak, sa)
4187 sf = done
4188 if (this%surfdep > dzero) then
4189 sf = squadraticsaturation(this%lakebot(n) + this%surfdep, &
4190 this%lakebot(n), hlak)
4191 end if
4192 this%evap(n) = -this%evaporation(n) * sa * sf
4193 this%withr(n) = -this%withdrawal(n) * sf
4194 end do
4195 end if
4196 !
4197 ! -- call base functionality in bnd_cq. This will calculate lake-gwf flows
4198 ! and put them into this%simvals
4199 call this%BndType%bnd_cq(x, flowja, iadv=1)
4200 !
4201 ! -- calculate several budget terms
4202 chratin = dzero
4203 chratout = dzero
4204 do n = 1, this%nlakes
4205 this%chterm(n) = dzero
4206 if (this%iboundpak(n) == 0) cycle
4207 hlak = this%xnewpak(n)
4208 call this%lak_calculate_vol(n, hlak, v1)
4209 !
4210 ! -- add budget terms for active lakes
4211 if (this%iboundpak(n) /= 0) then
4212 !
4213 ! -- rainfall
4214 rrate = this%precip(n)
4215 call this%lak_accumulate_chterm(n, rrate, chratin, chratout)
4216 !
4217 ! -- evaporation
4218 rrate = this%evap(n)
4219 call this%lak_accumulate_chterm(n, rrate, chratin, chratout)
4220 !
4221 ! -- runoff
4222 rrate = this%runoff(n)
4223 call this%lak_accumulate_chterm(n, rrate, chratin, chratout)
4224 !
4225 ! -- inflow
4226 rrate = this%inflow(n)
4227 call this%lak_accumulate_chterm(n, rrate, chratin, chratout)
4228 !
4229 ! -- withdrawals
4230 rrate = this%withr(n)
4231 call this%lak_accumulate_chterm(n, rrate, chratin, chratout)
4232 !
4233 ! -- add lake storage changes
4234 rrate = dzero
4235 if (this%iboundpak(n) > 0) then
4236 if (this%gwfiss /= 1) then
4237 call this%lak_calculate_vol(n, this%xoldpak(n), v0)
4238 rrate = -(v1 - v0) / delt
4239 call this%lak_accumulate_chterm(n, rrate, chratin, chratout)
4240 end if
4241 end if
4242 this%qsto(n) = rrate
4243 !
4244 ! -- add external outlets
4245 call this%lak_get_external_outlet(n, rrate)
4246 call this%lak_accumulate_chterm(n, rrate, chratin, chratout)
4247 !
4248 ! -- add mover terms
4249 if (this%imover == 1) then
4250 if (this%iboundpak(n) /= 0) then
4251 rrate = this%pakmvrobj%get_qfrommvr(n)
4252 else
4253 rrate = dzero
4254 end if
4255 call this%lak_accumulate_chterm(n, rrate, chratin, chratout)
4256 end if
4257 end if
4258 end do
4259 !
4260 ! -- gwf flow and constant flow to lake
4261 do n = 1, this%nlakes
4262 rrate = dzero
4263 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
4264 ! simvals is from aquifer perspective, and so it is positive
4265 ! for flow into the aquifer. Need to switch sign for lake
4266 ! perspective.
4267 rrate = -this%simvals(j)
4268 this%qleak(j) = rrate
4269 if (this%iboundpak(n) /= 0) then
4270 call this%lak_accumulate_chterm(n, rrate, chratin, chratout)
4271 end if
4272 end do
4273 end do
4274 !
4275 ! -- fill the budget object
4276 call this%lak_fill_budobj()
4277 end subroutine lak_cq
4278
4279 !> @brief Output LAK package flow terms
4280 !<
4281 subroutine lak_ot_package_flows(this, icbcfl, ibudfl)
4282 use tdismodule, only: kstp, kper, delt, pertim, totim
4283 class(laktype) :: this
4284 integer(I4B), intent(in) :: icbcfl
4285 integer(I4B), intent(in) :: ibudfl
4286 integer(I4B) :: ibinun
4287 !
4288 ! -- write the flows from the budobj
4289 ibinun = 0
4290 if (this%ibudgetout /= 0) then
4291 ibinun = this%ibudgetout
4292 end if
4293 if (icbcfl == 0) ibinun = 0
4294 if (ibinun > 0) then
4295 call this%budobj%save_flows(this%dis, ibinun, kstp, kper, delt, &
4296 pertim, totim, this%iout)
4297 end if
4298 !
4299 ! -- Print lake flows table
4300 if (ibudfl /= 0 .and. this%iprflow /= 0) then
4301 call this%budobj%write_flowtable(this%dis, kstp, kper)
4302 end if
4303 end subroutine lak_ot_package_flows
4304
4305 !> @brief Write flows to binary file and/or print flows to budget
4306 !<
4307 subroutine lak_ot_model_flows(this, icbcfl, ibudfl, icbcun, imap)
4308 class(laktype) :: this
4309 integer(I4B), intent(in) :: icbcfl
4310 integer(I4B), intent(in) :: ibudfl
4311 integer(I4B), intent(in) :: icbcun
4312 integer(I4B), dimension(:), optional, intent(in) :: imap
4313 !
4314 ! -- write the flows from the budobj
4315 call this%BndType%bnd_ot_model_flows(icbcfl, ibudfl, icbcun, this%imap)
4316 end subroutine lak_ot_model_flows
4317
4318 !> @brief Save LAK-calculated values to binary file
4319 !<
4320 subroutine lak_ot_dv(this, idvsave, idvprint)
4321 use tdismodule, only: kstp, kper, pertim, totim
4322 use constantsmodule, only: dhnoflo, dhdry
4323 use inputoutputmodule, only: ulasav
4324 class(laktype) :: this
4325 integer(I4B), intent(in) :: idvsave
4326 integer(I4B), intent(in) :: idvprint
4327 integer(I4B) :: ibinun
4328 integer(I4B) :: n
4329 real(DP) :: v
4330 real(DP) :: d
4331 real(DP) :: stage
4332 real(DP) :: sa
4333 real(DP) :: wa
4334 !
4335 ! -- set unit number for binary dependent variable output
4336 ibinun = 0
4337 if (this%istageout /= 0) then
4338 ibinun = this%istageout
4339 end if
4340 if (idvsave == 0) ibinun = 0
4341 !
4342 ! -- write lake binary output
4343 if (ibinun > 0) then
4344 do n = 1, this%nlakes
4345 v = this%xnewpak(n)
4346 d = v - this%lakebot(n)
4347 if (this%iboundpak(n) == 0) then
4348 v = dhnoflo
4349 else if (d <= dzero) then
4350 v = dhdry
4351 end if
4352 this%dbuff(n) = v
4353 end do
4354 call ulasav(this%dbuff, ' STAGE', kstp, kper, pertim, totim, &
4355 this%nlakes, 1, 1, ibinun)
4356 end if
4357 !
4358 ! -- Print lake stage table
4359 if (idvprint /= 0 .and. this%iprhed /= 0) then
4360 !
4361 ! -- set table kstp and kper
4362 call this%stagetab%set_kstpkper(kstp, kper)
4363 !
4364 ! -- write data
4365 do n = 1, this%nlakes
4366 if (this%iboundpak(n) == 0) then
4367 stage = dhnoflo
4368 sa = dhnoflo
4369 wa = dhnoflo
4370 v = dhnoflo
4371 else
4372 stage = this%xnewpak(n)
4373 call this%lak_calculate_sarea(n, stage, sa)
4374 call this%lak_calculate_warea(n, stage, wa)
4375 call this%lak_calculate_vol(n, stage, v)
4376 end if
4377 if (this%inamedbound == 1) then
4378 call this%stagetab%add_term(this%lakename(n))
4379 end if
4380 call this%stagetab%add_term(n)
4381 call this%stagetab%add_term(stage)
4382 call this%stagetab%add_term(sa)
4383 call this%stagetab%add_term(wa)
4384 call this%stagetab%add_term(v)
4385 end do
4386 end if
4387 end subroutine lak_ot_dv
4388
4389 !> @brief Write LAK budget to listing file
4390 !<
4391 subroutine lak_ot_bdsummary(this, kstp, kper, iout, ibudfl)
4392 ! -- module
4393 use tdismodule, only: totim, delt
4394 ! -- dummy
4395 class(laktype) :: this !< LakType object
4396 integer(I4B), intent(in) :: kstp !< time step number
4397 integer(I4B), intent(in) :: kper !< period number
4398 integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file
4399 integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written
4400 !
4401 call this%budobj%write_budtable(kstp, kper, iout, ibudfl, totim, delt)
4402 end subroutine lak_ot_bdsummary
4403
4404 !> @brief Deallocate objects
4405 !<
4406 subroutine lak_da(this)
4407 ! -- modules
4409 ! -- dummy
4410 class(laktype) :: this
4411 !
4412 ! -- nullify input context runtime pointers
4413 call this%input%destroy()
4414 !
4415 ! -- arrays
4416 deallocate (this%lakename)
4417 deallocate (this%status)
4418 deallocate (this%clakbudget)
4419 call mem_deallocate(this%dbuff)
4420 deallocate (this%cauxcbc)
4421 call mem_deallocate(this%qauxcbc)
4422 call mem_deallocate(this%qleak)
4423 call mem_deallocate(this%holdconn)
4424 call mem_deallocate(this%qsto)
4425 call mem_deallocate(this%denseterms)
4426 call mem_deallocate(this%viscratios)
4427 !
4428 ! -- tables
4429 if (this%ntables > 0) then
4430 call mem_deallocate(this%ialaktab)
4431 call mem_deallocate(this%tabstage)
4432 call mem_deallocate(this%tabvolume)
4433 call mem_deallocate(this%tabsarea)
4434 call mem_deallocate(this%tabwarea)
4435 end if
4436 !
4437 ! -- budobj
4438 call this%budobj%budgetobject_da()
4439 deallocate (this%budobj)
4440 nullify (this%budobj)
4441 !
4442 ! -- outlets
4443 if (this%noutlets > 0) then
4444 call mem_deallocate(this%lakein)
4445 call mem_deallocate(this%lakeout)
4446 call mem_deallocate(this%iouttype)
4447 ! -- outrate/outinvert/outwidth/outrough/outslope are live aliases
4448 ! into the input context's permanent arrays, not owned here
4449 call mem_deallocate(this%simoutrate)
4450 call mem_deallocate(this%outlet_invert_set)
4451 call mem_deallocate(this%outlet_width_set)
4452 call mem_deallocate(this%outlet_rough_set)
4453 call mem_deallocate(this%outlet_slope_set)
4454 end if
4455 !
4456 ! -- stage table
4457 if (this%iprhed > 0) then
4458 call this%stagetab%table_da()
4459 deallocate (this%stagetab)
4460 nullify (this%stagetab)
4461 end if
4462 !
4463 ! -- package csv table
4464 if (this%ipakcsv > 0) then
4465 if (associated(this%pakcsvtab)) then
4466 call this%pakcsvtab%table_da()
4467 deallocate (this%pakcsvtab)
4468 nullify (this%pakcsvtab)
4469 end if
4470 end if
4471 !
4472 ! -- scalars
4473 call mem_deallocate(this%iprhed)
4474 call mem_deallocate(this%istageout)
4475 call mem_deallocate(this%ibudgetout)
4476 call mem_deallocate(this%ibudcsv)
4477 call mem_deallocate(this%ipakcsv)
4478 if (allocated(this%pakcsvfile)) deallocate (this%pakcsvfile)
4479 call mem_deallocate(this%nlakes)
4480 call mem_deallocate(this%noutlets)
4481 call mem_deallocate(this%ntables)
4482 call mem_deallocate(this%convlength)
4483 call mem_deallocate(this%convtime)
4484 call mem_deallocate(this%outdmax)
4485 call mem_deallocate(this%igwhcopt)
4486 call mem_deallocate(this%iconvchk)
4487 call mem_deallocate(this%maxlakit)
4488 call mem_deallocate(this%surfdep)
4489 call mem_deallocate(this%dmaxchg)
4490 call mem_deallocate(this%delh)
4491 call mem_deallocate(this%check_attr)
4492 call mem_deallocate(this%iimplicit)
4493 call mem_deallocate(this%iforceleg)
4494 call mem_deallocate(this%iforceleglak)
4495 call mem_deallocate(this%bditems)
4496 call mem_deallocate(this%cbcauxitems)
4497 call mem_deallocate(this%idense)
4498 !
4499 call mem_deallocate(this%nlakeconn)
4500 call mem_deallocate(this%idxlakeconn)
4501 call mem_deallocate(this%ntabrow)
4502 call mem_deallocate(this%strt)
4503 call mem_deallocate(this%laketop)
4504 call mem_deallocate(this%lakebot)
4505 call mem_deallocate(this%sareamax)
4506 ! -- stage/rainfall/evaporation/runoff/inflow/withdrawal are live aliases
4507 ! into the input context's permanent arrays, not owned here
4508 call mem_deallocate(this%avail)
4509 call mem_deallocate(this%lkgwsink)
4510 call mem_deallocate(this%ncncvr)
4511 call mem_deallocate(this%ilegacy)
4512 call mem_deallocate(this%nstuck)
4513 call mem_deallocate(this%surfin)
4514 call mem_deallocate(this%surfout)
4515 call mem_deallocate(this%surfout1)
4516 call mem_deallocate(this%precip)
4517 call mem_deallocate(this%precip1)
4518 call mem_deallocate(this%evap)
4519 call mem_deallocate(this%evap1)
4520 call mem_deallocate(this%evapo)
4521 call mem_deallocate(this%withr)
4522 call mem_deallocate(this%withr1)
4523 call mem_deallocate(this%flwin)
4524 call mem_deallocate(this%flwiter)
4525 call mem_deallocate(this%flwiter1)
4526 call mem_deallocate(this%seep)
4527 call mem_deallocate(this%seep1)
4528 call mem_deallocate(this%seep0)
4529 call mem_deallocate(this%stageiter)
4530 call mem_deallocate(this%chterm)
4531 !
4532 ! -- lake boundary and stages
4533 if (this%iimplicit == 0) then
4534 call mem_deallocate(this%iboundpak)
4535 call mem_deallocate(this%xnewpak)
4536 else
4537 ! -- iboundpak aliases the global ibound (not deallocated here); xnewpak
4538 ! was checked in to the global x vector
4539 call mem_deallocate(this%xnewpak, 'XNEWPAK', this%memoryPath)
4540 end if
4541 call mem_deallocate(this%xoldpak)
4542 !
4543 ! -- implicit-formulation matrix-mapping arrays
4544 call mem_deallocate(this%idxlocnode)
4545 call mem_deallocate(this%idxdiag)
4546 call mem_deallocate(this%idxoffdglo)
4547 call mem_deallocate(this%idxsymdglo)
4548 call mem_deallocate(this%idxsymoffdglo)
4549 !
4550 ! -- lake iteration variables
4551 call mem_deallocate(this%iseepc)
4552 call mem_deallocate(this%idhc)
4553 call mem_deallocate(this%en1)
4554 call mem_deallocate(this%en2)
4555 call mem_deallocate(this%r1)
4556 call mem_deallocate(this%r2)
4557 call mem_deallocate(this%dh0)
4558 call mem_deallocate(this%s0)
4559 call mem_deallocate(this%qgwf0)
4560 !
4561 ! -- lake connection variables
4562 call mem_deallocate(this%imap)
4563 call mem_deallocate(this%gwfconn)
4564 call mem_deallocate(this%nodesontop)
4565 call mem_deallocate(this%ictype)
4566 call mem_deallocate(this%bedleak)
4567 call mem_deallocate(this%belev)
4568 call mem_deallocate(this%telev)
4569 call mem_deallocate(this%connlength)
4570 call mem_deallocate(this%connwidth)
4571 call mem_deallocate(this%sarea)
4572 call mem_deallocate(this%warea)
4573 call mem_deallocate(this%satcond)
4574 call mem_deallocate(this%simcond)
4575 call mem_deallocate(this%simlakgw)
4576 !
4577 ! -- pointers to gwf variables
4578 nullify (this%gwfiss)
4579 !
4580 ! -- Parent object
4581 call this%BndExtType%bnd_da()
4582 end subroutine lak_da
4583
4584 !> @brief Define the list heading that is written to iout when PRINT_INPUT
4585 !! option is used
4586 !<
4587 subroutine define_listlabel(this)
4588 ! -- modules
4589 class(laktype), intent(inout) :: this
4590 !
4591 ! -- create the header list label
4592 this%listlabel = trim(this%filtyp)//' NO.'
4593 if (this%dis%ndim == 3) then
4594 write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER'
4595 write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW'
4596 write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL'
4597 elseif (this%dis%ndim == 2) then
4598 write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER'
4599 write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D'
4600 else
4601 write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE'
4602 end if
4603 write (this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE'
4604 if (this%inamedbound == 1) then
4605 write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME'
4606 end if
4607 end subroutine define_listlabel
4608
4609 !> @brief Set pointers to model arrays and variables so that a package has
4610 !! access to these things
4611 !<
4612 subroutine lak_set_pointers(this, neq, ibound, xnew, xold, flowja)
4613 ! -- modules
4615 ! -- dummy
4616 class(laktype) :: this
4617 integer(I4B), pointer :: neq
4618 integer(I4B), dimension(:), pointer, contiguous :: ibound
4619 real(DP), dimension(:), pointer, contiguous :: xnew
4620 real(DP), dimension(:), pointer, contiguous :: xold
4621 real(DP), dimension(:), pointer, contiguous :: flowja
4622 ! -- local
4623 integer(I4B) :: n
4624 integer(I4B) :: istart, iend
4625 !
4626 ! -- call base BndType set_pointers
4627 call this%BndType%set_pointers(neq, ibound, xnew, xold, flowja)
4628 !
4629 ! -- for the implicit formulation, point the lake stage and ibound at the
4630 ! matching slice of the model solution (xnew) and ibound vectors so the
4631 ! stage is solved directly in the matrix. (The default formulation keeps
4632 ! these as its own arrays, allocated in lak_allocate_arrays.)
4633 if (this%iimplicit /= 0) then
4634 istart = this%dis%nodes + this%ioffset + 1
4635 iend = istart + this%nlakes - 1
4636 this%iboundpak => this%ibound(istart:iend)
4637 this%xnewpak => this%xnew(istart:iend)
4638 call mem_checkin(this%xnewpak, 'XNEWPAK', this%memoryPath, 'X', &
4639 this%memoryPathModel)
4640 !
4641 ! -- initialize xnewpak
4642 do n = 1, this%nlakes
4643 this%xnewpak(n) = dep20
4644 end do
4645 end if
4646 end subroutine lak_set_pointers
4647
4648 !> @brief Add the lake rows and columns to the sparse matrix
4649 !!
4650 !! Implicit formulation only. Each lake adds one equation (row and column) to
4651 !! the groundwater flow matrix: a diagonal entry, plus a symmetric off-diagonal
4652 !! pair (lake-to-cell and cell-to-lake) for every lake-cell connection.
4653 !<
4654 subroutine lak_ac(this, moffset, sparse)
4655 use sparsemodule, only: sparsematrix
4656 ! -- dummy
4657 class(laktype), intent(inout) :: this
4658 integer(I4B), intent(in) :: moffset
4659 type(sparsematrix), intent(inout) :: sparse
4660 ! -- local
4661 integer(I4B) :: j, n
4662 integer(I4B) :: jj
4663 integer(I4B) :: jglo
4664 integer(I4B) :: nglo
4665 !
4666 ! -- the default formulation adds no rows to the matrix
4667 if (this%iimplicit == 0) return
4668 !
4669 ! -- add a row for each lake and its connections to the cells
4670 do n = 1, this%nlakes
4671 nglo = moffset + this%dis%nodes + this%ioffset + n
4672 call sparse%addconnection(nglo, nglo, 1)
4673 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
4674 jj = this%gwfconn(j)
4675 jglo = jj + moffset
4676 call sparse%addconnection(nglo, jglo, 1)
4677 call sparse%addconnection(jglo, nglo, 1)
4678 end do
4679 end do
4680 end subroutine lak_ac
4681
4682 !> @brief Find the matrix position of each lake row and connection
4683 !!
4684 !! Implicit formulation only. Finds the position in the assembled matrix of
4685 !! each lake-row diagonal, lake-to-cell, cell diagonal, and cell-to-lake entry
4686 !! and stores them in the idx* arrays so they can be filled during assembly.
4687 !<
4688 subroutine lak_mc(this, moffset, matrix_sln)
4690 ! -- dummy
4691 class(laktype), intent(inout) :: this
4692 integer(I4B), intent(in) :: moffset
4693 class(matrixbasetype), pointer :: matrix_sln
4694 ! -- local
4695 integer(I4B) :: n
4696 integer(I4B) :: j
4697 integer(I4B) :: iglo
4698 integer(I4B) :: jglo
4699 integer(I4B) :: ipos
4700 !
4701 ! -- the connection-mapping vectors are only used by the implicit
4702 ! formulation; allocate them at size 0 otherwise so legacy LAK runs do not
4703 ! pay the maxbound memory cost (lak_da stays symmetric either way)
4704 if (this%iimplicit == 0) then
4705 call mem_allocate(this%idxlocnode, 0, 'IDXLOCNODE', this%memoryPath)
4706 call mem_allocate(this%idxdiag, 0, 'IDXDIAG', this%memoryPath)
4707 call mem_allocate(this%idxoffdglo, 0, 'IDXOFFDGLO', this%memoryPath)
4708 call mem_allocate(this%idxsymdglo, 0, 'IDXSYMDGLO', this%memoryPath)
4709 call mem_allocate(this%idxsymoffdglo, 0, 'IDXSYMOFFDGLO', this%memoryPath)
4710 return
4711 end if
4712 call mem_allocate(this%idxlocnode, this%nlakes, 'IDXLOCNODE', &
4713 this%memoryPath)
4714 call mem_allocate(this%idxdiag, this%nlakes, 'IDXDIAG', this%memoryPath)
4715 call mem_allocate(this%idxoffdglo, this%maxbound, 'IDXOFFDGLO', &
4716 this%memoryPath)
4717 call mem_allocate(this%idxsymdglo, this%maxbound, 'IDXSYMDGLO', &
4718 this%memoryPath)
4719 call mem_allocate(this%idxsymoffdglo, this%maxbound, 'IDXSYMOFFDGLO', &
4720 this%memoryPath)
4721 !
4722 ! -- lake rows: a per-lake diagonal position and the per-connection
4723 ! lake->cell off-diagonals. The diagonal is stored per lake (idxdiag) so a
4724 ! lake with no connections still has a valid diagonal position.
4725 ipos = 1
4726 do n = 1, this%nlakes
4727 iglo = moffset + this%dis%nodes + this%ioffset + n
4728 this%idxlocnode(n) = this%dis%nodes + this%ioffset + n
4729 this%idxdiag(n) = matrix_sln%get_position_diag(iglo)
4730 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
4731 jglo = this%gwfconn(j) + moffset
4732 this%idxoffdglo(ipos) = matrix_sln%get_position(iglo, jglo)
4733 ipos = ipos + 1
4734 end do
4735 end do
4736 !
4737 ! -- lake contributions to the gwf portion of the global matrix
4738 ipos = 1
4739 do n = 1, this%nlakes
4740 jglo = moffset + this%dis%nodes + this%ioffset + n
4741 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
4742 iglo = this%gwfconn(j) + moffset
4743 this%idxsymdglo(ipos) = matrix_sln%get_position_diag(iglo)
4744 this%idxsymoffdglo(ipos) = matrix_sln%get_position(iglo, jglo)
4745 ipos = ipos + 1
4746 end do
4747 end do
4748 end subroutine lak_mc
4749
4750 !> @brief Procedures related to observations (type-bound)
4751 !!
4752 !! Return true because LAK package supports observations. Overrides
4753 !! BndType%bnd_obs_supported()
4754 !<
4755 logical function lak_obs_supported(this)
4756 ! -- dummy
4757 class(laktype) :: this
4758 !
4759 lak_obs_supported = .true.
4760 end function lak_obs_supported
4761
4762 !> @brief Store observation type supported by LAK package. Overrides
4763 !! BndType%bnd_df_obs
4764 !<
4765 subroutine lak_df_obs(this)
4766 ! -- dummy
4767 class(laktype) :: this
4768 ! -- local
4769 integer(I4B) :: indx
4770 !
4771 ! -- Store obs type and assign procedure pointer
4772 ! for stage observation type.
4773 call this%obs%StoreObsType('stage', .false., indx)
4774 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4775 !
4776 ! -- Store obs type and assign procedure pointer
4777 ! for ext-inflow observation type.
4778 call this%obs%StoreObsType('ext-inflow', .true., indx)
4779 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4780 !
4781 ! -- Store obs type and assign procedure pointer
4782 ! for outlet-inflow observation type.
4783 call this%obs%StoreObsType('outlet-inflow', .true., indx)
4784 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4785 !
4786 ! -- Store obs type and assign procedure pointer
4787 ! for inflow observation type.
4788 call this%obs%StoreObsType('inflow', .true., indx)
4789 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4790 !
4791 ! -- Store obs type and assign procedure pointer
4792 ! for from-mvr observation type.
4793 call this%obs%StoreObsType('from-mvr', .true., indx)
4794 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4795 !
4796 ! -- Store obs type and assign procedure pointer
4797 ! for rainfall observation type.
4798 call this%obs%StoreObsType('rainfall', .true., indx)
4799 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4800 !
4801 ! -- Store obs type and assign procedure pointer
4802 ! for runoff observation type.
4803 call this%obs%StoreObsType('runoff', .true., indx)
4804 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4805 !
4806 ! -- Store obs type and assign procedure pointer
4807 ! for lak observation type.
4808 call this%obs%StoreObsType('lak', .true., indx)
4809 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4810 !
4811 ! -- Store obs type and assign procedure pointer
4812 ! for evaporation observation type.
4813 call this%obs%StoreObsType('evaporation', .true., indx)
4814 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4815 !
4816 ! -- Store obs type and assign procedure pointer
4817 ! for withdrawal observation type.
4818 call this%obs%StoreObsType('withdrawal', .true., indx)
4819 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4820 !
4821 ! -- Store obs type and assign procedure pointer
4822 ! for ext-outflow observation type.
4823 call this%obs%StoreObsType('ext-outflow', .true., indx)
4824 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4825 !
4826 ! -- Store obs type and assign procedure pointer
4827 ! for to-mvr observation type.
4828 call this%obs%StoreObsType('to-mvr', .true., indx)
4829 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4830 !
4831 ! -- Store obs type and assign procedure pointer
4832 ! for storage observation type.
4833 call this%obs%StoreObsType('storage', .true., indx)
4834 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4835 !
4836 ! -- Store obs type and assign procedure pointer
4837 ! for constant observation type.
4838 call this%obs%StoreObsType('constant', .true., indx)
4839 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4840 !
4841 ! -- Store obs type and assign procedure pointer
4842 ! for outlet observation type.
4843 call this%obs%StoreObsType('outlet', .true., indx)
4844 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4845 !
4846 ! -- Store obs type and assign procedure pointer
4847 ! for volume observation type.
4848 call this%obs%StoreObsType('volume', .true., indx)
4849 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4850 !
4851 ! -- Store obs type and assign procedure pointer
4852 ! for surface-area observation type.
4853 call this%obs%StoreObsType('surface-area', .true., indx)
4854 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4855 !
4856 ! -- Store obs type and assign procedure pointer
4857 ! for wetted-area observation type.
4858 call this%obs%StoreObsType('wetted-area', .true., indx)
4859 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4860 !
4861 ! -- Store obs type and assign procedure pointer
4862 ! for conductance observation type.
4863 call this%obs%StoreObsType('conductance', .true., indx)
4864 this%obs%obsData(indx)%ProcessIdPtr => lak_process_obsid
4865 end subroutine lak_df_obs
4866
4867 !> @brief Calculate observations this time step and call ObsType%SaveOneSimval
4868 !! for each LakType observation.
4869 !<
4870 subroutine lak_bd_obs(this)
4871 ! -- dummy
4872 class(laktype) :: this
4873 ! -- local
4874 integer(I4B) :: i
4875 integer(I4B) :: igwfnode
4876 integer(I4B) :: j
4877 integer(I4B) :: jj
4878 integer(I4B) :: n
4879 real(DP) :: hgwf
4880 real(DP) :: hlak
4881 real(DP) :: v
4882 real(DP) :: v2
4883 type(observetype), pointer :: obsrv => null()
4884 !
4885 ! Write simulated values for all LAK observations
4886 if (this%obs%npakobs > 0) then
4887 call this%obs%obs_bd_clear()
4888 do i = 1, this%obs%npakobs
4889 obsrv => this%obs%pakobs(i)%obsrv
4890 do j = 1, obsrv%indxbnds_count
4891 v = dnodata
4892 jj = obsrv%indxbnds(j)
4893 select case (obsrv%ObsTypeId)
4894 case ('STAGE')
4895 if (this%iboundpak(jj) /= 0) then
4896 v = this%xnewpak(jj)
4897 end if
4898 case ('EXT-INFLOW')
4899 if (this%iboundpak(jj) /= 0) then
4900 call this%lak_calculate_inflow(jj, v)
4901 end if
4902 case ('OUTLET-INFLOW')
4903 if (this%iboundpak(jj) /= 0) then
4904 call this%lak_calculate_outlet_inflow(jj, v)
4905 end if
4906 case ('INFLOW')
4907 if (this%iboundpak(jj) /= 0) then
4908 call this%lak_calculate_inflow(jj, v)
4909 call this%lak_calculate_outlet_inflow(jj, v2)
4910 v = v + v2
4911 end if
4912 case ('FROM-MVR')
4913 if (this%iboundpak(jj) /= 0) then
4914 if (this%imover == 1) then
4915 v = this%pakmvrobj%get_qfrommvr(jj)
4916 end if
4917 end if
4918 case ('RAINFALL')
4919 if (this%iboundpak(jj) /= 0) then
4920 v = this%precip(jj)
4921 end if
4922 case ('RUNOFF')
4923 if (this%iboundpak(jj) /= 0) then
4924 v = this%runoff(jj)
4925 end if
4926 case ('LAK')
4927 n = this%imap(jj)
4928 if (this%iboundpak(n) /= 0) then
4929 igwfnode = this%gwfconn(jj)
4930 hgwf = this%xnew(igwfnode)
4931 if (this%hcof(jj) /= dzero) then
4932 v = -(this%hcof(jj) * (this%xnewpak(n) - hgwf))
4933 else
4934 v = -this%rhs(jj)
4935 end if
4936 end if
4937 case ('EVAPORATION')
4938 if (this%iboundpak(jj) /= 0) then
4939 v = this%evap(jj)
4940 end if
4941 case ('WITHDRAWAL')
4942 if (this%iboundpak(jj) /= 0) then
4943 v = this%withr(jj)
4944 end if
4945 case ('EXT-OUTFLOW')
4946 n = this%lakein(jj)
4947 if (this%iboundpak(n) /= 0) then
4948 if (this%lakeout(jj) == 0) then
4949 v = this%simoutrate(jj)
4950 if (v < dzero) then
4951 if (this%imover == 1) then
4952 v = v + this%pakmvrobj%get_qtomvr(jj)
4953 end if
4954 end if
4955 end if
4956 end if
4957 case ('TO-MVR')
4958 n = this%lakein(jj)
4959 if (this%iboundpak(n) /= 0) then
4960 if (this%imover == 1) then
4961 v = this%pakmvrobj%get_qtomvr(jj)
4962 if (v > dzero) then
4963 v = -v
4964 end if
4965 end if
4966 end if
4967 case ('STORAGE')
4968 if (this%iboundpak(jj) /= 0) then
4969 v = this%qsto(jj)
4970 end if
4971 case ('CONSTANT')
4972 if (this%iboundpak(jj) /= 0) then
4973 v = this%chterm(jj)
4974 end if
4975 case ('OUTLET')
4976 n = this%lakein(jj)
4977 if (this%iboundpak(n) /= 0) then
4978 v = this%simoutrate(jj)
4979 end if
4980 case ('VOLUME')
4981 if (this%iboundpak(jj) /= 0) then
4982 call this%lak_calculate_vol(jj, this%xnewpak(jj), v)
4983 end if
4984 case ('SURFACE-AREA')
4985 if (this%iboundpak(jj) /= 0) then
4986 hlak = this%xnewpak(jj)
4987 call this%lak_calculate_sarea(jj, hlak, v)
4988 end if
4989 case ('WETTED-AREA')
4990 n = this%imap(jj)
4991 if (this%iboundpak(n) /= 0) then
4992 hlak = this%xnewpak(n)
4993 igwfnode = this%gwfconn(jj)
4994 hgwf = this%xnew(igwfnode)
4995 call this%lak_calculate_conn_warea(n, jj, hlak, hgwf, v)
4996 end if
4997 case ('CONDUCTANCE')
4998 n = this%imap(jj)
4999 if (this%iboundpak(n) /= 0) then
5000 hlak = this%xnewpak(n)
5001 igwfnode = this%gwfconn(jj)
5002 hgwf = this%xnew(igwfnode)
5003 call this%lak_calculate_conn_conductance(n, jj, hlak, hgwf, v)
5004 end if
5005 case default
5006 errmsg = 'Unrecognized observation type: '//trim(obsrv%ObsTypeId)
5007 call store_error(errmsg)
5008 end select
5009 call this%obs%SaveOneSimval(obsrv, v)
5010 end do
5011 end do
5012 !
5013 ! -- write summary of error messages
5014 if (count_errors() > 0) then
5015 call store_error_filename(this%input_fname)
5016 end if
5017 end if
5018 end subroutine lak_bd_obs
5019
5020 !> @brief Process each observation
5021 !!
5022 !! Only done the first stress period since boundaries are fixed for the
5023 !! simulation
5024 !<
5025 subroutine lak_rp_obs(this)
5026 use tdismodule, only: kper
5027 ! -- dummy
5028 class(laktype), intent(inout) :: this
5029 ! -- local
5030 integer(I4B) :: i
5031 integer(I4B) :: j
5032 integer(I4B) :: nn1
5033 integer(I4B) :: nn2
5034 integer(I4B) :: jj
5035 character(len=LENBOUNDNAME) :: bname
5036 logical(LGP) :: jfound
5037 class(observetype), pointer :: obsrv => null()
5038 ! -- formats
503910 format('Boundary "', a, '" for observation "', a, &
5040 '" is invalid in package "', a, '"')
5041 !
5042 ! -- process each package observation
5043 ! only done the first stress period since boundaries are fixed
5044 ! for the simulation
5045 if (kper == 1) then
5046 do i = 1, this%obs%npakobs
5047 obsrv => this%obs%pakobs(i)%obsrv
5048 !
5049 ! -- get node number 1
5050 nn1 = obsrv%NodeNumber
5051 if (nn1 == namedboundflag) then
5052 bname = obsrv%FeatureName
5053 if (bname /= '') then
5054 ! -- Observation lake is based on a boundary name.
5055 ! Iterate through all lakes to identify and store
5056 ! corresponding index in bound array.
5057 jfound = .false.
5058 if (obsrv%ObsTypeId == 'LAK' .or. &
5059 obsrv%ObsTypeId == 'CONDUCTANCE' .or. &
5060 obsrv%ObsTypeId == 'WETTED-AREA') then
5061 if (this%inamedbound /= 0) then
5062 do j = 1, this%nlakes
5063 do jj = this%idxlakeconn(j), this%idxlakeconn(j + 1) - 1
5064 if (this%boundname(jj) == bname) then
5065 jfound = .true.
5066 call obsrv%AddObsIndex(jj)
5067 end if
5068 end do
5069 end do
5070 end if
5071 else if (obsrv%ObsTypeId == 'EXT-OUTFLOW' .or. &
5072 obsrv%ObsTypeId == 'TO-MVR' .or. &
5073 obsrv%ObsTypeId == 'OUTLET') then
5074 do j = 1, this%noutlets
5075 jj = this%lakein(j)
5076 if (this%lakename(jj) == bname) then
5077 jfound = .true.
5078 call obsrv%AddObsIndex(j)
5079 end if
5080 end do
5081 else
5082 do j = 1, this%nlakes
5083 if (this%lakename(j) == bname) then
5084 jfound = .true.
5085 call obsrv%AddObsIndex(j)
5086 end if
5087 end do
5088 end if
5089 if (.not. jfound) then
5090 write (errmsg, 10) &
5091 trim(bname), trim(obsrv%Name), trim(this%packName)
5092 call store_error(errmsg)
5093 end if
5094 end if
5095 else
5096 if (obsrv%indxbnds_count == 0) then
5097 if (obsrv%ObsTypeId == 'LAK' .or. &
5098 obsrv%ObsTypeId == 'CONDUCTANCE' .or. &
5099 obsrv%ObsTypeId == 'WETTED-AREA') then
5100 nn2 = obsrv%NodeNumber2
5101 if (nn1 < 1 .or. nn1 > this%nlakes) then
5102 write (errmsg, '(5a,i0,a,i0,a)') &
5103 'Observation ', trim(obsrv%Name), ' of type ', &
5104 trim(adjustl(obsrv%ObsTypeId)), ' was assigned lake ', &
5105 nn1, '. Lake must be >= 1 and <= ', this%nlakes, '.'
5106 call store_error(errmsg)
5107 else if (nn2 < 1 .or. nn2 > this%nlakeconn(nn1)) then
5108 write (errmsg, '(5a,i0,a,i0,a,i0,a)') &
5109 'Observation ', trim(obsrv%Name), ' of type ', &
5110 trim(adjustl(obsrv%ObsTypeId)), &
5111 ' was assigned connection ', nn2, ' of lake ', nn1, &
5112 '. Connection must be >= 1 and <= ', &
5113 this%nlakeconn(nn1), '.'
5114 call store_error(errmsg)
5115 else
5116 j = this%idxlakeconn(nn1) + nn2 - 1
5117 call obsrv%AddObsIndex(j)
5118 end if
5119 else
5120 call obsrv%AddObsIndex(nn1)
5121 end if
5122 else
5123 errmsg = 'Programming error in lak_rp_obs'
5124 call store_error(errmsg)
5125 end if
5126 end if
5127 !
5128 ! -- catch non-cumulative observation assigned to observation defined
5129 ! by a boundname that is assigned to more than one element
5130 if (obsrv%ObsTypeId == 'STAGE') then
5131 if (obsrv%indxbnds_count > 1) then
5132 write (errmsg, '(a,3(1x,a))') &
5133 trim(adjustl(obsrv%ObsTypeId)), &
5134 'for observation', trim(adjustl(obsrv%Name)), &
5135 ' must be assigned to a lake with a unique boundname.'
5136 call store_error(errmsg)
5137 end if
5138 end if
5139 !
5140 ! -- check that index values are valid
5141 if (obsrv%ObsTypeId == 'TO-MVR' .or. &
5142 obsrv%ObsTypeId == 'EXT-OUTFLOW' .or. &
5143 obsrv%ObsTypeId == 'OUTLET') then
5144 do j = 1, obsrv%indxbnds_count
5145 nn1 = obsrv%indxbnds(j)
5146 if (nn1 < 1 .or. nn1 > this%noutlets) then
5147 write (errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') &
5148 trim(adjustl(obsrv%ObsTypeId)), &
5149 ' outlet must be > 0 and <=', this%noutlets, &
5150 '(specified value is ', nn1, ')'
5151 call store_error(errmsg)
5152 end if
5153 end do
5154 else if (obsrv%ObsTypeId == 'LAK' .or. &
5155 obsrv%ObsTypeId == 'CONDUCTANCE' .or. &
5156 obsrv%ObsTypeId == 'WETTED-AREA') then
5157 do j = 1, obsrv%indxbnds_count
5158 nn1 = obsrv%indxbnds(j)
5159 if (nn1 < 1 .or. nn1 > this%maxbound) then
5160 write (errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') &
5161 trim(adjustl(obsrv%ObsTypeId)), &
5162 'lake connection number must be > 0 and <=', this%maxbound, &
5163 '(specified value is ', nn1, ')'
5164 call store_error(errmsg)
5165 end if
5166 end do
5167 else
5168 do j = 1, obsrv%indxbnds_count
5169 nn1 = obsrv%indxbnds(j)
5170 if (nn1 < 1 .or. nn1 > this%nlakes) then
5171 write (errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') &
5172 trim(adjustl(obsrv%ObsTypeId)), &
5173 ' lake must be > 0 and <=', this%nlakes, &
5174 '(specified value is ', nn1, ')'
5175 call store_error(errmsg)
5176 end if
5177 end do
5178 end if
5179 end do
5180 !
5181 ! -- evaluate if there are any observation errors
5182 if (count_errors() > 0) then
5183 call store_error_filename(this%input_fname)
5184 end if
5185 end if
5186 end subroutine lak_rp_obs
5187
5188 !
5189 ! -- Procedures related to observations (NOT type-bound)
5190
5191 !> @brief This procedure is pointed to by ObsDataType%ProcesssIdPtr. It
5192 !! processes the ID string of an observation definition for LAK package
5193 !! observations.
5194 !<
5195 subroutine lak_process_obsid(obsrv, dis, inunitobs, iout)
5196 ! -- dummy
5197 type(observetype), intent(inout) :: obsrv
5198 class(disbasetype), intent(in) :: dis
5199 integer(I4B), intent(in) :: inunitobs
5200 integer(I4B), intent(in) :: iout
5201 ! -- local
5202 integer(I4B) :: nn1, nn2
5203 integer(I4B) :: icol, istart, istop
5204 character(len=LINELENGTH) :: string
5205 character(len=LENBOUNDNAME) :: bndname
5206 !
5207 string = obsrv%IDstring
5208 ! -- Extract lake number from string and store it.
5209 ! If 1st item is not an integer(I4B), it should be a
5210 ! lake name--deal with it.
5211 icol = 1
5212 ! -- get lake number or boundary name
5213 call extract_idnum_or_bndname(string, icol, istart, istop, nn1, bndname)
5214 if (nn1 == namedboundflag) then
5215 obsrv%FeatureName = bndname
5216 else
5217 if (obsrv%ObsTypeId == 'LAK' .or. obsrv%ObsTypeId == 'CONDUCTANCE' .or. &
5218 obsrv%ObsTypeId == 'WETTED-AREA') then
5219 call extract_idnum_or_bndname(string, icol, istart, istop, nn2, bndname)
5220 if (len_trim(bndname) < 1 .and. nn2 < 0) then
5221 write (errmsg, '(a,1x,a,a,1x,a,1x,a)') &
5222 'For observation type', trim(adjustl(obsrv%ObsTypeId)), &
5223 ', ID given as an integer and not as boundname,', &
5224 'but ID2 (iconn) is missing. Either change ID to valid', &
5225 'boundname or supply valid entry for ID2.'
5226 call store_error(errmsg)
5227 end if
5228 if (nn2 == namedboundflag) then
5229 obsrv%FeatureName = bndname
5230 ! -- reset nn1
5231 nn1 = nn2
5232 else
5233 obsrv%NodeNumber2 = nn2
5234 end if
5235 end if
5236 end if
5237 ! -- store lake number (NodeNumber)
5238 obsrv%NodeNumber = nn1
5239 end subroutine lak_process_obsid
5240
5241 !
5242 ! -- private LAK methods
5243 !
5244
5245 !> @brief Accumulate constant head terms for budget
5246 !<
5247 subroutine lak_accumulate_chterm(this, ilak, rrate, chratin, chratout)
5248 ! -- dummy
5249 class(laktype) :: this
5250 integer(I4B), intent(in) :: ilak
5251 real(DP), intent(in) :: rrate
5252 real(DP), intent(inout) :: chratin
5253 real(DP), intent(inout) :: chratout
5254 ! -- locals
5255 real(DP) :: q
5256 !
5257 ! code
5258 if (this%iboundpak(ilak) < 0) then
5259 q = -rrate
5260 this%chterm(ilak) = this%chterm(ilak) + q
5261 !
5262 ! -- See if flow is into lake or out of lake.
5263 if (q < dzero) then
5264 !
5265 ! -- Flow is out of lake subtract rate from ratout.
5266 chratout = chratout - q
5267 else
5268 !
5269 ! -- Flow is into lake; add rate to ratin.
5270 chratin = chratin + q
5271 end if
5272 end if
5273 end subroutine lak_accumulate_chterm
5274
5275 !> @brief Store the lake head and connection conductance in the bound array
5276 !<
5277 subroutine lak_bound_update(this)
5278 ! -- dummy
5279 class(laktype), intent(inout) :: this
5280 ! -- local
5281 integer(I4B) :: j, n, node
5282 real(DP) :: hlak, head, clak
5283 !
5284 ! -- Return if no lak lakes
5285 if (this%nbound == 0) return
5286 !
5287 ! -- Calculate hcof and rhs for each lak entry
5288 do n = 1, this%nlakes
5289 hlak = this%xnewpak(n)
5290 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
5291 node = this%gwfconn(j)
5292 head = this%xnew(node)
5293 call this%lak_calculate_conn_conductance(n, j, hlak, head, clak)
5294 this%bound(1, j) = hlak
5295 this%bound(2, j) = clak
5296 end do
5297 end do
5298 end subroutine lak_bound_update
5299
5300 !> @brief Solve for lake stage
5301 !!
5302 !! Solve the lake stage by substitution. With only_legacy set, solve only
5303 !! the lakes flagged for the legacy solver (this%ilegacy /= 0) and
5304 !! leave the remaining lakes -- whose stage is solved in the global matrix by
5305 !! the IMPLICIT formulation -- untouched. Without it (the default), every
5306 !! active lake is solved.
5307 !<
5308 subroutine lak_solve(this, update, only_legacy)
5309 ! -- modules
5310 use tdismodule, only: delt
5311 ! -- dummy
5312 class(laktype), intent(inout) :: this
5313 logical(LGP), intent(in), optional :: update
5314 logical(LGP), intent(in), optional :: only_legacy
5315 ! -- local
5316 logical(LGP) :: lupdate
5317 logical(LGP) :: legonly
5318 integer(I4B) :: j
5319 integer(I4B) :: n
5320 integer(I4B) :: iicnvg
5321 integer(I4B) :: iter
5322 integer(I4B) :: maxiter
5323 integer(I4B) :: ncnv
5324 real(DP) :: hlak
5325 real(DP) :: hlak0
5326 real(DP) :: v0
5327 real(DP) :: v1
5328 real(DP) :: ro
5329 real(DP) :: qinf
5330 real(DP) :: ex
5331 real(DP) :: outinf
5332 real(DP) :: avail
5333 !
5334 ! -- set lupdate
5335 if (present(update)) then
5336 lupdate = update
5337 else
5338 lupdate = .true.
5339 end if
5340 !
5341 ! -- set legonly (solve only the lakes flagged for the legacy solver)
5342 if (present(only_legacy)) then
5343 legonly = only_legacy
5344 else
5345 legonly = .false.
5346 end if
5347 !
5348 ! -- initialize
5349 avail = dzero
5350 !
5351 ! -- initialize
5352 do n = 1, this%nlakes
5353 ! -- a lake not being solved on this call (an IMPLICIT lake when only the
5354 ! flagged lakes are solved) is treated as already converged and left
5355 ! untouched
5356 if (legonly .and. this%ilegacy(n) == 0) then
5357 this%ncncvr(n) = 1
5358 cycle
5359 end if
5360 this%ncncvr(n) = 0
5361 this%surfin(n) = dzero
5362 this%surfout(n) = dzero
5363 this%surfout1(n) = dzero
5364 if (this%xnewpak(n) < this%lakebot(n)) then
5365 this%xnewpak(n) = this%lakebot(n)
5366 end if
5367 if (this%gwfiss /= 0) then
5368 this%xoldpak(n) = this%xnewpak(n)
5369 end if
5370 ! -- lake iteration items
5371 this%iseepc(n) = 0
5372 this%idhc(n) = 0
5373 this%en1(n) = this%lakebot(n)
5374 call this%lak_calculate_residual(n, this%en1(n), this%r1(n))
5375 this%en2(n) = this%laketop(n)
5376 call this%lak_calculate_residual(n, this%en2(n), this%r2(n))
5377 end do
5378 ! -- a legacy-only solve keeps the outlet rates of the implicit lakes,
5379 ! which are final and still needed for the mover and downstream lakes
5380 do n = 1, this%noutlets
5381 if (legonly .and. this%ilegacy(this%lakein(n)) == 0) cycle
5382 this%simoutrate(n) = dzero
5383 end do
5384 !
5385 ! -- sum up inflows from mover inflows
5386 do n = 1, this%nlakes
5387 call this%lak_calculate_outlet_inflow(n, this%surfin(n))
5388 end do
5389 !
5390 ! -- sum up overland runoff, inflows, and external flows into lake
5391 ! (includes maximum lake volume)
5392 do n = 1, this%nlakes
5393 hlak0 = this%xoldpak(n)
5394 hlak = this%xnewpak(n)
5395 call this%lak_calculate_runoff(n, ro)
5396 call this%lak_calculate_inflow(n, qinf)
5397 call this%lak_calculate_external(n, ex)
5398 call this%lak_calculate_vol(n, hlak0, v0)
5399 call this%lak_calculate_vol(n, hlak, v1)
5400 this%flwin(n) = this%surfin(n) + ro + qinf + ex + &
5401 max(v0, v1) / delt
5402 end do
5403 !
5404 ! -- sum up inflows from upstream outlets
5405 do n = 1, this%nlakes
5406 call this%lak_calculate_outlet_inflow(n, outinf)
5407 this%flwin(n) = this%flwin(n) + outinf
5408 end do
5409 !
5410 iicnvg = 0
5411 maxiter = this%maxlakit
5412 !
5413 ! -- outer loop
5414 converge: do iter = 1, maxiter
5415 ncnv = 0
5416 do n = 1, this%nlakes
5417 if (this%ncncvr(n) == 0) ncnv = 1
5418 end do
5419 if (iter == maxiter) ncnv = 0
5420 if (ncnv == 0) iicnvg = 1
5421 !
5422 ! -- initialize variables
5423 do n = 1, this%nlakes
5424 this%evap(n) = dzero
5425 this%precip(n) = dzero
5426 this%precip1(n) = dzero
5427 this%seep(n) = dzero
5428 this%seep1(n) = dzero
5429 this%evap(n) = dzero
5430 this%evap1(n) = dzero
5431 this%evapo(n) = dzero
5432 this%withr(n) = dzero
5433 this%withr1(n) = dzero
5434 this%flwiter(n) = this%flwin(n)
5435 this%flwiter1(n) = this%flwin(n)
5436 if (this%gwfiss /= 0) then
5437 this%flwiter(n) = dep20
5438 this%flwiter1(n) = dep20
5439 end if
5440 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
5441 this%hcof(j) = dzero
5442 this%rhs(j) = dzero
5443 end do
5444 end do
5445 !
5446 do n = 1, this%nlakes
5447 if (legonly .and. this%ilegacy(n) == 0) cycle
5448 call this%lak_estimate_seepage_single(n, ncnv)
5449 end do
5450 !
5451 laklevel: do n = 1, this%nlakes
5452 if (legonly .and. this%ilegacy(n) == 0) cycle laklevel
5453 call this%lak_solve_single(n, iter, maxiter, ncnv, lupdate)
5454 end do laklevel
5455 !
5456 if (iicnvg == 1) exit converge
5457 !
5458 end do converge
5459 !
5460 ! -- Mover terms: store outflow after diversion loss
5461 ! as qformvr and reduce outflow (qd)
5462 ! by how much was actually sent to the mover. A legacy-only solve
5463 ! skips this because the implicit formulation accumulates the mover
5464 ! terms for every outlet once the legacy-solved stages are known.
5465 if (this%imover == 1 .and. .not. legonly) then
5466 do n = 1, this%noutlets
5467 call this%pakmvrobj%accumulate_qformvr(n, -this%simoutrate(n))
5468 end do
5469 end if
5470 end subroutine lak_solve
5471
5472 !> @brief Advance one lake stage by a single substitution iteration
5473 !!
5474 !! Performs one Newton update (with a bisection backup) of lake n's stage in
5475 !! the default substitution solver, using the per-iteration seepage estimate
5476 !! (this%seep / this%seep1) already computed for the lake. Extracted from
5477 !! lak_solve so the same per-lake update can be reused to solve a single lake
5478 !! stage on its own -- the per-lake legacy solve for the IMPLICIT formulation.
5479 !<
5480 subroutine lak_solve_single(this, n, iter, maxiter, ncnv, lupdate)
5481 ! -- modules
5482 use tdismodule, only: delt
5483 ! -- dummy
5484 class(laktype), intent(inout) :: this
5485 integer(I4B), intent(in) :: n
5486 integer(I4B), intent(in) :: iter
5487 integer(I4B), intent(in) :: maxiter
5488 integer(I4B), intent(in) :: ncnv
5489 logical(LGP), intent(in) :: lupdate
5490 ! -- local
5491 integer(I4B) :: ibflg
5492 integer(I4B) :: idhp
5493 real(DP) :: hlak
5494 real(DP) :: hlak0
5495 real(DP) :: ra
5496 real(DP) :: ro
5497 real(DP) :: qinf
5498 real(DP) :: ex
5499 real(DP) :: ev
5500 real(DP) :: wr
5501 real(DP) :: resid
5502 real(DP) :: resid1
5503 real(DP) :: residb
5504 real(DP) :: derv
5505 real(DP) :: dh
5506 real(DP) :: ts
5507 real(DP) :: adh
5508 real(DP) :: adh0
5509 real(DP) :: v0
5510 real(DP) :: v1
5511 real(DP) :: area
5512 real(DP) :: qtolfact
5513 real(DP) :: delh
5514 !
5515 delh = this%delh
5516 !
5517 ! -- skip inactive lakes
5518 if (this%iboundpak(n) == 0) then
5519 this%ncncvr(n) = 1
5520 return
5521 end if
5522 ibflg = 0
5523 hlak = this%xnewpak(n)
5524 if (iter < maxiter) then
5525 this%stageiter(n) = this%xnewpak(n)
5526 end if
5527 call this%lak_calculate_rainfall(n, hlak, ra)
5528 this%precip(n) = ra
5529 this%flwiter(n) = this%flwiter(n) + ra
5530 call this%lak_calculate_rainfall(n, hlak + delh, ra)
5531 this%precip1(n) = ra
5532 this%flwiter1(n) = this%flwiter1(n) + ra
5533 !
5534 ! -- limit withdrawals to lake inflows and lake storage
5535 call this%lak_calculate_withdrawal(n, this%flwiter(n), wr)
5536 this%withr(n) = wr
5537 call this%lak_calculate_withdrawal(n, this%flwiter1(n), wr)
5538 this%withr1(n) = wr
5539 !
5540 ! -- limit evaporation to lake inflows and lake storage
5541 call this%lak_calculate_evaporation(n, hlak, this%flwiter(n), ev)
5542 this%evap(n) = ev
5543 call this%lak_calculate_evaporation(n, hlak + delh, this%flwiter1(n), ev)
5544 this%evap1(n) = ev
5545 !
5546 ! -- no outlet flow if evaporation consumes all water
5547 call this%lak_calculate_outlet_outflow(n, hlak + delh, &
5548 this%flwiter1(n), &
5549 this%surfout1(n))
5550 call this%lak_calculate_outlet_outflow(n, hlak, this%flwiter(n), &
5551 this%surfout(n))
5552 !
5553 ! -- update the surface inflow values
5554 call this%lak_calculate_outlet_inflow(n, this%surfin(n))
5555 !
5556 !
5557 if (ncnv == 1) then
5558 if (this%iboundpak(n) > 0 .and. lupdate .eqv. .true.) then
5559 !
5560 ! -- recalculate flwin
5561 hlak0 = this%xoldpak(n)
5562 hlak = this%xnewpak(n)
5563 call this%lak_calculate_vol(n, hlak0, v0)
5564 call this%lak_calculate_vol(n, hlak, v1)
5565 call this%lak_calculate_runoff(n, ro)
5566 call this%lak_calculate_inflow(n, qinf)
5567 call this%lak_calculate_external(n, ex)
5568 this%flwin(n) = this%surfin(n) + ro + qinf + ex + &
5569 max(v0, v1) / delt
5570 !
5571 ! -- compute new lake stage using Newton's method
5572 resid = this%precip(n) + this%evap(n) + this%withr(n) + ro + &
5573 qinf + ex + this%surfin(n) + &
5574 this%surfout(n) + this%seep(n)
5575 resid1 = this%precip1(n) + this%evap1(n) + this%withr1(n) + ro + &
5576 qinf + ex + this%surfin(n) + &
5577 this%surfout1(n) + this%seep1(n)
5578 !
5579 ! -- add storage changes for transient stress periods
5580 hlak = this%xnewpak(n)
5581 if (this%gwfiss /= 1) then
5582 call this%lak_calculate_vol(n, hlak, v1)
5583 resid = resid + (v0 - v1) / delt
5584 call this%lak_calculate_vol(n, hlak + delh, v1)
5585 resid1 = resid1 + (v0 - v1) / delt
5586 end if
5587 !
5588 ! -- determine the derivative and the stage change
5589 if (abs(resid1 - resid) > dzero) then
5590 derv = (resid1 - resid) / delh
5591 dh = dzero
5592 if (abs(derv) > dprec) then
5593 dh = resid / derv
5594 end if
5595 else
5596 if (resid < dzero) then
5597 resid = dzero
5598 end if
5599 call this%lak_vol2stage(n, resid, dh)
5600 dh = hlak - dh
5601 this%ncncvr(n) = 1
5602 end if
5603 !
5604 ! -- determine if the updated stage is outside the endpoints
5605 ts = hlak - dh
5606 if (iter == 1) this%dh0(n) = dh
5607 adh = abs(dh)
5608 adh0 = abs(this%dh0(n))
5609 if ((ts >= this%en2(n)) .or. (ts < this%en1(n))) then
5610 ! -- use bisection if dh is increasing or updated stage is below the
5611 ! bottom of the lake
5612 if ((adh > adh0) .or. (ts - this%lakebot(n)) < dprec) then
5613 residb = resid
5614 call this%lak_bisection(n, ibflg, hlak, ts, dh, residb)
5615 end if
5616 end if
5617 !
5618 ! -- set seep0 on the first lake iteration
5619 if (iter == 1) then
5620 this%seep0(n) = this%seep(n)
5621 end if
5622 !
5623 ! -- check for slow convergence
5624 if (this%seep(n) * this%seep0(n) < dprec) then
5625 this%iseepc(n) = this%iseepc(n) + 1
5626 else
5627 this%iseepc(n) = 0
5628 end if
5629 ! -- determine of convergence is slow and oscillating
5630 idhp = 0
5631 if (dh * this%dh0(n) < dprec) idhp = 1
5632 ! -- determine if stage change is increasing
5633 adh = abs(dh)
5634 if (adh > adh0) idhp = 1
5635 ! -- increment idhc convergence flag
5636 if (idhp == 1) then
5637 this%idhc(n) = this%idhc(n) + 1
5638 end if
5639 !
5640 ! -- switch to bisection when the Newton-Raphson method oscillates
5641 ! or when convergence is slow
5642 if (ibflg == 1) then
5643 if (this%iseepc(n) > 7 .or. this%idhc(n) > 12) then
5644 call this%lak_bisection(n, ibflg, hlak, ts, dh, residb)
5645 end if
5646 end if
5647 else
5648 dh = dzero
5649 end if
5650 !
5651 ! -- update lake stage
5652 hlak = hlak - dh
5653 if (hlak < this%lakebot(n)) then
5654 hlak = this%lakebot(n)
5655 end if
5656 !
5657 ! -- calculate surface area
5658 call this%lak_calculate_sarea(n, hlak, area)
5659 !
5660 ! -- set the Q to length factor
5661 if (area > dzero) then
5662 qtolfact = delt / area
5663 else
5664 qtolfact = dzero
5665 end if
5666 !
5667 ! -- recalculate the residual
5668 call this%lak_calculate_residual(n, hlak, resid)
5669 !
5670 ! -- evaluate convergence
5671 !if (ABS(dh) < delh) then
5672 if (abs(dh) < delh .and. abs(resid) * qtolfact < this%dmaxchg) then
5673 this%ncncvr(n) = 1
5674 end if
5675 this%xnewpak(n) = hlak
5676 !
5677 ! -- save iterates for lake
5678 this%seep0(n) = this%seep(n)
5679 this%dh0(n) = dh
5680 end if
5681 end subroutine lak_solve_single
5682
5683 !> @brief Estimate the lakebed seepage for a single lake
5684 !!
5685 !! Runs the two-pass connection-seepage estimate for lake n at its current
5686 !! stage and the perturbed stage, accumulating this%seep(n)/this%seep1(n) and,
5687 !! on the final pass when ncnv == 0, the gwf-cell hcof/rhs contributions. Lakes
5688 !! do not couple within this estimate (each connection touches only its own
5689 !! lake's flwiter), so evaluating both passes per lake is equivalent to the
5690 !! all-lakes-per-pass ordering in lak_solve. Extracted from lak_solve so the
5691 !! same estimate can drive the single-lake legacy solve for the IMPLICIT
5692 !! formulation.
5693 !<
5694 subroutine lak_estimate_seepage_single(this, n, ncnv)
5695 ! -- dummy
5696 class(laktype), intent(inout) :: this
5697 integer(I4B), intent(in) :: n
5698 integer(I4B), intent(in) :: ncnv
5699 ! -- local
5700 integer(I4B) :: i
5701 integer(I4B) :: j
5702 integer(I4B) :: igwfnode
5703 integer(I4B) :: idry
5704 integer(I4B) :: idry1
5705 real(DP) :: hlak
5706 real(DP) :: head
5707 real(DP) :: qlakgw
5708 real(DP) :: qlakgw1
5709 real(DP) :: gwfhcof
5710 real(DP) :: gwfrhs
5711 real(DP) :: delh
5712 !
5713 delh = this%delh
5714 !
5715 ! -- skip inactive lakes
5716 if (this%iboundpak(n) == 0) return
5717 !
5718 estseep: do i = 1, 2
5719 ! - set xoldpak to xnewpak if steady-state
5720 if (this%gwfiss /= 0) then
5721 this%xoldpak(n) = this%xnewpak(n)
5722 end if
5723 hlak = this%xnewpak(n)
5724 calcconnseep: do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
5725 igwfnode = this%gwfconn(j)
5726 head = this%xnew(igwfnode)
5727 if (this%ncncvr(n) /= 2) then
5728 if (this%ibound(igwfnode) > 0) then
5729 call this%lak_estimate_conn_exchange(i, n, j, idry, hlak, &
5730 head, qlakgw, &
5731 this%flwiter(n), &
5732 gwfhcof, gwfrhs)
5733 call this%lak_estimate_conn_exchange(i, n, j, idry1, &
5734 hlak + delh, head, qlakgw1, &
5735 this%flwiter1(n))
5736 !
5737 ! -- add to gwf matrix
5738 if (ncnv == 0 .and. i == 2) then
5739 if (j == this%maxbound) then
5740 this%ncncvr(n) = 2
5741 end if
5742 if (idry /= 1) then
5743 this%hcof(j) = gwfhcof
5744 this%rhs(j) = gwfrhs
5745 else
5746 this%hcof(j) = dzero
5747 this%rhs(j) = qlakgw
5748 end if
5749 end if
5750 if (i == 2) then
5751 this%seep(n) = this%seep(n) + qlakgw
5752 this%seep1(n) = this%seep1(n) + qlakgw1
5753 end if
5754 end if
5755 end if
5756 end do calcconnseep
5757 end do estseep
5758 end subroutine lak_estimate_seepage_single
5759
5760 !> @ brief Lake package bisection method
5761 !!
5762 !! Use bisection method to find lake stage that reduces the residual
5763 !<
5764 subroutine lak_bisection(this, n, ibflg, hlak, temporary_stage, dh, residual)
5765 ! -- dummy
5766 class(laktype), intent(inout) :: this
5767 integer(I4B), intent(in) :: n !< lake number
5768 integer(I4B), intent(inout) :: ibflg !< bisection flag
5769 real(DP), intent(in) :: hlak !< lake stage
5770 real(DP), intent(inout) :: temporary_stage !< temporary lake stage
5771 real(DP), intent(inout) :: dh !< lake stage change
5772 real(DP), intent(inout) :: residual !< lake residual
5773 ! -- local
5774 integer(I4B) :: i
5775 real(DP) :: temporary_stage0
5776 real(DP) :: residuala
5777 real(DP) :: endpoint1
5778 real(DP) :: endpoint2
5779 ! -- code
5780 ibflg = 1
5781 temporary_stage0 = hlak
5782 endpoint1 = this%en1(n)
5783 endpoint2 = this%en2(n)
5784 call this%lak_calculate_residual(n, temporary_stage, residuala)
5785 if (hlak > endpoint1 .and. hlak < endpoint2) then
5786 endpoint2 = hlak
5787 end if
5788 do i = 1, this%maxlakit
5789 temporary_stage = dhalf * (endpoint1 + endpoint2)
5790 call this%lak_calculate_residual(n, temporary_stage, residual)
5791 if (abs(residual) == dzero .or. &
5792 abs(temporary_stage0 - temporary_stage) < this%dmaxchg) then
5793 exit
5794 end if
5795 call this%lak_calculate_residual(n, endpoint1, residuala)
5796 ! -- change end points
5797 ! -- root is between temporary_stage and endpoint2
5798 if (sign(done, residuala) == sign(done, residual)) then
5799 endpoint1 = temporary_stage
5800 ! -- root is between endpoint1 and temporary_stage
5801 else
5802 endpoint2 = temporary_stage
5803 end if
5804 temporary_stage0 = temporary_stage
5805 end do
5806 dh = hlak - temporary_stage
5807 end subroutine lak_bisection
5808
5809 !> @brief Calculate the available volumetric rate for a lake given a passed
5810 !! stage
5811 !<
5812 subroutine lak_calculate_available(this, n, hlak, avail, &
5813 ra, ro, qinf, ex, headp)
5814 ! -- modules
5815 use tdismodule, only: delt
5816 ! -- dummy
5817 class(laktype), intent(inout) :: this
5818 integer(I4B), intent(in) :: n
5819 real(DP), intent(in) :: hlak
5820 real(DP), intent(inout) :: avail
5821 real(DP), intent(inout) :: ra
5822 real(DP), intent(inout) :: ro
5823 real(DP), intent(inout) :: qinf
5824 real(DP), intent(inout) :: ex
5825 real(DP), intent(in), optional :: headp
5826 ! -- local
5827 integer(I4B) :: j
5828 integer(I4B) :: idry
5829 integer(I4B) :: igwfnode
5830 real(DP) :: hp
5831 real(DP) :: head
5832 real(DP) :: qlakgw
5833 real(DP) :: v0
5834 !
5835 ! -- set hp
5836 if (present(headp)) then
5837 hp = headp
5838 else
5839 hp = dzero
5840 end if
5841 !
5842 ! -- initialize
5843 avail = dzero
5844 !
5845 ! -- calculate the aquifer sources to the lake
5846 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
5847 igwfnode = this%gwfconn(j)
5848 if (this%ibound(igwfnode) == 0) cycle
5849 head = this%xnew(igwfnode) + hp
5850 call this%lak_estimate_conn_exchange(1, n, j, idry, hlak, head, qlakgw, &
5851 avail)
5852 end do
5853 !
5854 ! -- add rainfall
5855 call this%lak_calculate_rainfall(n, hlak, ra)
5856 avail = avail + ra
5857 !
5858 ! -- calculate runoff
5859 call this%lak_calculate_runoff(n, ro)
5860 avail = avail + ro
5861 !
5862 ! -- calculate inflow
5863 call this%lak_calculate_inflow(n, qinf)
5864 avail = avail + qinf
5865 !
5866 ! -- calculate external flow terms
5867 call this%lak_calculate_external(n, ex)
5868 avail = avail + ex
5869 !
5870 ! -- calculate volume available in storage
5871 call this%lak_calculate_vol(n, this%xoldpak(n), v0)
5872 avail = avail + v0 / delt
5873 end subroutine lak_calculate_available
5874
5875 !> @brief Calculate the residual for a lake given a passed stage
5876 !<
5877 subroutine lak_calculate_residual(this, n, hlak, resid, headp)
5878 ! -- modules
5879 use tdismodule, only: delt
5880 ! -- dummy
5881 class(laktype), intent(inout) :: this
5882 integer(I4B), intent(in) :: n
5883 real(DP), intent(in) :: hlak
5884 real(DP), intent(inout) :: resid
5885 real(DP), intent(in), optional :: headp
5886 ! -- local
5887 integer(I4B) :: j
5888 integer(I4B) :: idry
5889 integer(I4B) :: igwfnode
5890 real(DP) :: hp
5891 real(DP) :: avail
5892 real(DP) :: head
5893 real(DP) :: ra
5894 real(DP) :: ro
5895 real(DP) :: qinf
5896 real(DP) :: ex
5897 real(DP) :: ev
5898 real(DP) :: wr
5899 real(DP) :: sout
5900 real(DP) :: sin
5901 real(DP) :: qlakgw
5902 real(DP) :: seep
5903 real(DP) :: hlak0
5904 real(DP) :: v0
5905 real(DP) :: v1
5906 !
5907 ! -- set hp
5908 if (present(headp)) then
5909 hp = headp
5910 else
5911 hp = dzero
5912 end if
5913 !
5914 ! -- initialize
5915 resid = dzero
5916 avail = dzero
5917 seep = dzero
5918 !
5919 ! -- calculate the available water
5920 call this%lak_calculate_available(n, hlak, avail, &
5921 ra, ro, qinf, ex, hp)
5922 !
5923 ! -- calculate groundwater seepage
5924 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
5925 igwfnode = this%gwfconn(j)
5926 if (this%ibound(igwfnode) == 0) cycle
5927 head = this%xnew(igwfnode) + hp
5928 call this%lak_estimate_conn_exchange(2, n, j, idry, hlak, head, qlakgw, &
5929 avail)
5930 seep = seep + qlakgw
5931 end do
5932 !
5933 ! -- limit withdrawals to lake inflows and lake storage
5934 call this%lak_calculate_withdrawal(n, avail, wr)
5935 !
5936 ! -- limit evaporation to lake inflows and lake storage
5937 call this%lak_calculate_evaporation(n, hlak, avail, ev)
5938 !
5939 ! -- no outlet flow if evaporation consumes all water
5940 call this%lak_calculate_outlet_outflow(n, hlak, avail, sout)
5941 !
5942 ! -- update the surface inflow values
5943 call this%lak_calculate_outlet_inflow(n, sin)
5944 !
5945 ! -- calculate residual
5946 resid = ra + ev + wr + ro + qinf + ex + sin + sout + seep
5947 !
5948 ! -- include storage
5949 if (this%gwfiss /= 1) then
5950 hlak0 = this%xoldpak(n)
5951 call this%lak_calculate_vol(n, hlak0, v0)
5952 call this%lak_calculate_vol(n, hlak, v1)
5953 resid = resid + (v0 - v1) / delt
5954 end if
5955 end subroutine lak_calculate_residual
5956
5957 !> @brief Set up the budget object that stores all the lake flows
5958 !<
5959 subroutine lak_setup_budobj(this)
5960 ! -- modules
5961 use constantsmodule, only: lenbudtxt
5962 ! -- dummy
5963 class(laktype) :: this
5964 ! -- local
5965 integer(I4B) :: nbudterm
5966 integer(I4B) :: nlen
5967 integer(I4B) :: j, n, n1, n2
5968 integer(I4B) :: maxlist, naux
5969 integer(I4B) :: idx
5970 real(DP) :: q
5971 character(len=LENBUDTXT) :: text
5972 character(len=LENBUDTXT), dimension(1) :: auxtxt
5973 !
5974 ! -- Determine the number of lake budget terms. These are fixed for
5975 ! the simulation and cannot change
5976 nbudterm = 9
5977 nlen = 0
5978 do n = 1, this%noutlets
5979 if (this%lakein(n) > 0 .and. this%lakeout(n) > 0) then
5980 nlen = nlen + 1
5981 end if
5982 end do
5983 if (nlen > 0) nbudterm = nbudterm + 1
5984 if (this%imover == 1) nbudterm = nbudterm + 2
5985 if (this%naux > 0) nbudterm = nbudterm + 1
5986 !
5987 ! -- set up budobj
5988 call budgetobject_cr(this%budobj, this%packName)
5989 call this%budobj%budgetobject_df(this%nlakes, nbudterm, 0, 0, &
5990 ibudcsv=this%ibudcsv)
5991 idx = 0
5992 !
5993 ! -- Go through and set up each budget term. nlen is the number
5994 ! of outlets that discharge into another lake
5995 if (nlen > 0) then
5996 text = ' FLOW-JA-FACE'
5997 idx = idx + 1
5998 maxlist = 2 * nlen
5999 naux = 0
6000 call this%budobj%budterm(idx)%initialize(text, &
6001 this%name_model, &
6002 this%packName, &
6003 this%name_model, &
6004 this%packName, &
6005 maxlist, .false., .false., &
6006 naux, ordered_id1=.false.)
6007 !
6008 ! -- store connectivity
6009 call this%budobj%budterm(idx)%reset(2 * nlen)
6010 q = dzero
6011 do n = 1, this%noutlets
6012 n1 = this%lakein(n)
6013 n2 = this%lakeout(n)
6014 if (n1 > 0 .and. n2 > 0) then
6015 call this%budobj%budterm(idx)%update_term(n1, n2, q)
6016 call this%budobj%budterm(idx)%update_term(n2, n1, -q)
6017 end if
6018 end do
6019 end if
6020 !
6021 ! --
6022 text = ' GWF'
6023 idx = idx + 1
6024 maxlist = this%maxbound
6025 naux = 1
6026 auxtxt(1) = ' FLOW-AREA'
6027 call this%budobj%budterm(idx)%initialize(text, &
6028 this%name_model, &
6029 this%packName, &
6030 this%name_model, &
6031 this%name_model, &
6032 maxlist, .false., .true., &
6033 naux, auxtxt)
6034 call this%budobj%budterm(idx)%reset(this%maxbound)
6035 q = dzero
6036 do n = 1, this%nlakes
6037 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
6038 n2 = this%gwfconn(j)
6039 call this%budobj%budterm(idx)%update_term(n, n2, q)
6040 end do
6041 end do
6042 !
6043 ! --
6044 text = ' RAINFALL'
6045 idx = idx + 1
6046 maxlist = this%nlakes
6047 naux = 0
6048 call this%budobj%budterm(idx)%initialize(text, &
6049 this%name_model, &
6050 this%packName, &
6051 this%name_model, &
6052 this%packName, &
6053 maxlist, .false., .false., &
6054 naux)
6055 !
6056 ! --
6057 text = ' EVAPORATION'
6058 idx = idx + 1
6059 maxlist = this%nlakes
6060 naux = 0
6061 call this%budobj%budterm(idx)%initialize(text, &
6062 this%name_model, &
6063 this%packName, &
6064 this%name_model, &
6065 this%packName, &
6066 maxlist, .false., .false., &
6067 naux)
6068 !
6069 ! --
6070 text = ' RUNOFF'
6071 idx = idx + 1
6072 maxlist = this%nlakes
6073 naux = 0
6074 call this%budobj%budterm(idx)%initialize(text, &
6075 this%name_model, &
6076 this%packName, &
6077 this%name_model, &
6078 this%packName, &
6079 maxlist, .false., .false., &
6080 naux)
6081 !
6082 ! --
6083 text = ' EXT-INFLOW'
6084 idx = idx + 1
6085 maxlist = this%nlakes
6086 naux = 0
6087 call this%budobj%budterm(idx)%initialize(text, &
6088 this%name_model, &
6089 this%packName, &
6090 this%name_model, &
6091 this%packName, &
6092 maxlist, .false., .false., &
6093 naux)
6094 !
6095 ! --
6096 text = ' WITHDRAWAL'
6097 idx = idx + 1
6098 maxlist = this%nlakes
6099 naux = 0
6100 call this%budobj%budterm(idx)%initialize(text, &
6101 this%name_model, &
6102 this%packName, &
6103 this%name_model, &
6104 this%packName, &
6105 maxlist, .false., .false., &
6106 naux)
6107 !
6108 ! --
6109 text = ' EXT-OUTFLOW'
6110 idx = idx + 1
6111 maxlist = this%nlakes
6112 naux = 0
6113 call this%budobj%budterm(idx)%initialize(text, &
6114 this%name_model, &
6115 this%packName, &
6116 this%name_model, &
6117 this%packName, &
6118 maxlist, .false., .false., &
6119 naux)
6120 !
6121 ! --
6122 text = ' STORAGE'
6123 idx = idx + 1
6124 maxlist = this%nlakes
6125 naux = 1
6126 auxtxt(1) = ' VOLUME'
6127 call this%budobj%budterm(idx)%initialize(text, &
6128 this%name_model, &
6129 this%packName, &
6130 this%name_model, &
6131 this%packName, &
6132 maxlist, .false., .false., &
6133 naux, auxtxt)
6134 !
6135 ! --
6136 text = ' CONSTANT'
6137 idx = idx + 1
6138 maxlist = this%nlakes
6139 naux = 0
6140 call this%budobj%budterm(idx)%initialize(text, &
6141 this%name_model, &
6142 this%packName, &
6143 this%name_model, &
6144 this%packName, &
6145 maxlist, .false., .false., &
6146 naux)
6147 !
6148 ! --
6149 if (this%imover == 1) then
6150 !
6151 ! --
6152 text = ' FROM-MVR'
6153 idx = idx + 1
6154 maxlist = this%nlakes
6155 naux = 0
6156 call this%budobj%budterm(idx)%initialize(text, &
6157 this%name_model, &
6158 this%packName, &
6159 this%name_model, &
6160 this%packName, &
6161 maxlist, .false., .false., &
6162 naux)
6163 !
6164 ! --
6165 text = ' TO-MVR'
6166 idx = idx + 1
6167 maxlist = this%noutlets
6168 naux = 0
6169 call this%budobj%budterm(idx)%initialize(text, &
6170 this%name_model, &
6171 this%packName, &
6172 this%name_model, &
6173 this%packName, &
6174 maxlist, .false., .false., &
6175 naux, ordered_id1=.false.)
6176 !
6177 ! -- store to-mvr connection information
6178 call this%budobj%budterm(idx)%reset(this%noutlets)
6179 q = dzero
6180 do n = 1, this%noutlets
6181 n1 = this%lakein(n)
6182 call this%budobj%budterm(idx)%update_term(n1, n1, q)
6183 end do
6184 end if
6185 !
6186 ! --
6187 naux = this%naux
6188 if (naux > 0) then
6189 !
6190 ! --
6191 text = ' AUXILIARY'
6192 idx = idx + 1
6193 maxlist = this%nlakes
6194 call this%budobj%budterm(idx)%initialize(text, &
6195 this%name_model, &
6196 this%packName, &
6197 this%name_model, &
6198 this%packName, &
6199 maxlist, .false., .false., &
6200 naux, this%auxname)
6201 end if
6202 !
6203 ! -- if lake flow for each reach are written to the listing file
6204 if (this%iprflow /= 0) then
6205 call this%budobj%flowtable_df(this%iout)
6206 end if
6207 end subroutine lak_setup_budobj
6208
6209 !> @brief Copy flow terms into this%budobj
6210 !<
6211 subroutine lak_fill_budobj(this)
6212 ! -- dummy
6213 class(laktype) :: this
6214 ! -- local
6215 integer(I4B) :: naux
6216 real(DP), dimension(:), allocatable :: auxvartmp
6217 !integer(I4B) :: i
6218 integer(I4B) :: j
6219 integer(I4B) :: n
6220 integer(I4B) :: n1
6221 integer(I4B) :: n2
6222 integer(I4B) :: ii
6223 integer(I4B) :: jj
6224 integer(I4B) :: idx
6225 integer(I4B) :: nlen
6226 real(DP) :: v, v1
6227 real(DP) :: q
6228 real(DP) :: lkstg, gwhead, wa
6229 !
6230 ! -- initialize counter
6231 idx = 0
6232
6233 ! -- FLOW JA FACE
6234 nlen = 0
6235 do n = 1, this%noutlets
6236 if (this%lakein(n) > 0 .and. this%lakeout(n) > 0) then
6237 nlen = nlen + 1
6238 end if
6239 end do
6240 if (nlen > 0) then
6241 idx = idx + 1
6242 call this%budobj%budterm(idx)%reset(2 * nlen)
6243 do n = 1, this%noutlets
6244 n1 = this%lakein(n)
6245 n2 = this%lakeout(n)
6246 if (n1 > 0 .and. n2 > 0) then
6247 q = this%simoutrate(n)
6248 if (this%imover == 1) then
6249 q = q + this%pakmvrobj%get_qtomvr(n)
6250 end if
6251 call this%budobj%budterm(idx)%update_term(n1, n2, q)
6252 call this%budobj%budterm(idx)%update_term(n2, n1, -q)
6253 end if
6254 end do
6255 end if
6256 !
6257 ! -- GWF (LEAKAGE)
6258 idx = idx + 1
6259 call this%budobj%budterm(idx)%reset(this%maxbound)
6260 do n = 1, this%nlakes
6261 do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1
6262 n2 = this%gwfconn(j)
6263 q = this%qleak(j)
6264 lkstg = this%xnewpak(n)
6265 ! -- For the case when the lak stage is exactly equal
6266 ! to the lake bottom, the wetted area is not returned
6267 ! equal to 0.0
6268 gwhead = this%xnew(n2)
6269 call this%lak_calculate_conn_warea(n, j, lkstg, gwhead, wa)
6270 ! -- For thermal conduction between a lake and a gw cell,
6271 ! the shared wetted area should be reset to zero when the lake
6272 ! stage is below the cell bottom
6273 if (this%belev(j) > lkstg) wa = dzero
6274 this%qauxcbc(1) = wa
6275 call this%budobj%budterm(idx)%update_term(n, n2, q, this%qauxcbc)
6276 end do
6277 end do
6278 !
6279 ! -- RAIN
6280 idx = idx + 1
6281 call this%budobj%budterm(idx)%reset(this%nlakes)
6282 do n = 1, this%nlakes
6283 q = this%precip(n)
6284 call this%budobj%budterm(idx)%update_term(n, n, q)
6285 end do
6286 !
6287 ! -- EVAPORATION
6288 idx = idx + 1
6289 call this%budobj%budterm(idx)%reset(this%nlakes)
6290 do n = 1, this%nlakes
6291 q = this%evap(n)
6292 call this%budobj%budterm(idx)%update_term(n, n, q)
6293 end do
6294 !
6295 ! -- RUNOFF
6296 idx = idx + 1
6297 call this%budobj%budterm(idx)%reset(this%nlakes)
6298 do n = 1, this%nlakes
6299 q = this%runoff(n)
6300 call this%budobj%budterm(idx)%update_term(n, n, q)
6301 end do
6302 !
6303 ! -- INFLOW
6304 idx = idx + 1
6305 call this%budobj%budterm(idx)%reset(this%nlakes)
6306 do n = 1, this%nlakes
6307 q = this%inflow(n)
6308 call this%budobj%budterm(idx)%update_term(n, n, q)
6309 end do
6310 !
6311 ! -- WITHDRAWAL
6312 idx = idx + 1
6313 call this%budobj%budterm(idx)%reset(this%nlakes)
6314 do n = 1, this%nlakes
6315 q = this%withr(n)
6316 call this%budobj%budterm(idx)%update_term(n, n, q)
6317 end do
6318 !
6319 ! -- EXTERNAL OUTFLOW
6320 idx = idx + 1
6321 call this%budobj%budterm(idx)%reset(this%nlakes)
6322 do n = 1, this%nlakes
6323 call this%lak_get_external_outlet(n, q)
6324 ! subtract tomover from external outflow
6325 call this%lak_get_external_mover(n, v)
6326 q = q + v
6327 call this%budobj%budterm(idx)%update_term(n, n, q)
6328 end do
6329 !
6330 ! -- STORAGE
6331 idx = idx + 1
6332 call this%budobj%budterm(idx)%reset(this%nlakes)
6333 do n = 1, this%nlakes
6334 call this%lak_calculate_vol(n, this%xnewpak(n), v1)
6335 q = this%qsto(n)
6336 this%qauxcbc(1) = v1
6337 call this%budobj%budterm(idx)%update_term(n, n, q, this%qauxcbc)
6338 end do
6339 !
6340 ! -- CONSTANT FLOW
6341 idx = idx + 1
6342 call this%budobj%budterm(idx)%reset(this%nlakes)
6343 do n = 1, this%nlakes
6344 q = this%chterm(n)
6345 call this%budobj%budterm(idx)%update_term(n, n, q)
6346 end do
6347 !
6348 ! -- MOVER
6349 if (this%imover == 1) then
6350 !
6351 ! -- FROM MOVER
6352 idx = idx + 1
6353 call this%budobj%budterm(idx)%reset(this%nlakes)
6354 do n = 1, this%nlakes
6355 q = this%pakmvrobj%get_qfrommvr(n)
6356 call this%budobj%budterm(idx)%update_term(n, n, q)
6357 end do
6358 !
6359 ! -- TO MOVER
6360 idx = idx + 1
6361 call this%budobj%budterm(idx)%reset(this%noutlets)
6362 do n = 1, this%noutlets
6363 n1 = this%lakein(n)
6364 q = this%pakmvrobj%get_qtomvr(n)
6365 if (q > dzero) then
6366 q = -q
6367 end if
6368 call this%budobj%budterm(idx)%update_term(n1, n1, q)
6369 end do
6370 !
6371 end if
6372 !
6373 ! -- AUXILIARY VARIABLES
6374 naux = this%naux
6375 if (naux > 0) then
6376 idx = idx + 1
6377 allocate (auxvartmp(naux))
6378 call this%budobj%budterm(idx)%reset(this%nlakes)
6379 do n = 1, this%nlakes
6380 q = dzero
6381 do jj = 1, naux
6382 ii = n
6383 auxvartmp(jj) = this%featureauxvar(jj, ii)
6384 end do
6385 call this%budobj%budterm(idx)%update_term(n, n, q, auxvartmp)
6386 end do
6387 deallocate (auxvartmp)
6388 end if
6389 !
6390 ! --Terms are filled, now accumulate them for this time step
6391 call this%budobj%accumulate_terms()
6392 end subroutine lak_fill_budobj
6393
6394 !> @brief Set up the table object that is used to write the lak stage data
6395 !!
6396 !! The terms listed here must correspond in number and order to the ones
6397 !! written to the stage table in the lak_ot method
6398 !<
6399 subroutine lak_setup_tableobj(this)
6400 ! -- modules
6402 ! -- dummy
6403 class(laktype) :: this
6404 ! -- local
6405 integer(I4B) :: nterms
6406 character(len=LINELENGTH) :: title
6407 character(len=LINELENGTH) :: text
6408 !
6409 ! -- setup stage table
6410 if (this%iprhed > 0) then
6411 !
6412 ! -- Determine the number of lake stage terms. These are fixed for
6413 ! the simulation and cannot change. This includes FLOW-JA-FACE
6414 ! so they can be written to the binary budget files, but these internal
6415 ! flows are not included as part of the budget table.
6416 nterms = 5
6417 if (this%inamedbound == 1) then
6418 nterms = nterms + 1
6419 end if
6420 !
6421 ! -- set up table title
6422 title = trim(adjustl(this%text))//' PACKAGE ('// &
6423 trim(adjustl(this%packName))//') STAGES FOR EACH CONTROL VOLUME'
6424 !
6425 ! -- set up stage tableobj
6426 call table_cr(this%stagetab, this%packName, title)
6427 call this%stagetab%table_df(this%nlakes, nterms, this%iout, &
6428 transient=.true.)
6429 !
6430 ! -- Go through and set up table budget term
6431 if (this%inamedbound == 1) then
6432 text = 'NAME'
6433 call this%stagetab%initialize_column(text, 20, alignment=tableft)
6434 end if
6435 !
6436 ! -- lake number
6437 text = 'NUMBER'
6438 call this%stagetab%initialize_column(text, 10, alignment=tabcenter)
6439 !
6440 ! -- lake stage
6441 text = 'STAGE'
6442 call this%stagetab%initialize_column(text, 12, alignment=tabcenter)
6443 !
6444 ! -- lake surface area
6445 text = 'SURFACE AREA'
6446 call this%stagetab%initialize_column(text, 12, alignment=tabcenter)
6447 !
6448 ! -- lake wetted area
6449 text = 'WETTED AREA'
6450 call this%stagetab%initialize_column(text, 12, alignment=tabcenter)
6451 !
6452 ! -- lake volume
6453 text = 'VOLUME'
6454 call this%stagetab%initialize_column(text, 12, alignment=tabcenter)
6455 end if
6456 end subroutine lak_setup_tableobj
6457
6458 !> @brief Activate addition of density terms
6459 !<
6460 subroutine lak_activate_density(this)
6461 ! -- dummy
6462 class(laktype), intent(inout) :: this
6463 ! -- local
6464 integer(I4B) :: i, j
6465 !
6466 ! -- the IMPLICIT formulation does not include the density terms yet
6467 if (this%iimplicit /= 0) then
6468 write (errmsg, '(a)') &
6469 'The IMPLICIT option cannot be used with the BUY package until the &
6470 &implicit formulation includes density terms. Remove the IMPLICIT &
6471 &option from LAK package '//trim(this%packName)//' to simulate &
6472 &density.'
6473 call store_error(errmsg)
6474 call store_error_filename(this%input_fname)
6475 end if
6476 !
6477 ! -- Set idense and reallocate denseterms to be of size MAXBOUND
6478 this%idense = 1
6479 call mem_reallocate(this%denseterms, 3, this%MAXBOUND, 'DENSETERMS', &
6480 this%memoryPath)
6481 do i = 1, this%maxbound
6482 do j = 1, 3
6483 this%denseterms(j, i) = dzero
6484 end do
6485 end do
6486 write (this%iout, '(/1x,a)') 'DENSITY TERMS HAVE BEEN ACTIVATED FOR LAKE &
6487 &PACKAGE: '//trim(adjustl(this%packName))
6488 end subroutine lak_activate_density
6489
6490 !> @brief Activate viscosity terms
6491 !!
6492 !! Method to activate addition of viscosity terms for a LAK package reach.
6493 !<
6494 subroutine lak_activate_viscosity(this)
6495 ! -- modules
6497 ! -- dummy variables
6498 class(laktype), intent(inout) :: this !< LakType object
6499 ! -- local variables
6500 integer(I4B) :: i
6501 integer(I4B) :: j
6502 !
6503 ! -- Set ivsc and reallocate viscratios to be of size MAXBOUND
6504 this%ivsc = 1
6505 call mem_reallocate(this%viscratios, 2, this%MAXBOUND, 'VISCRATIOS', &
6506 this%memoryPath)
6507 do i = 1, this%maxbound
6508 do j = 1, 2
6509 this%viscratios(j, i) = done
6510 end do
6511 end do
6512 write (this%iout, '(/1x,a)') 'VISCOSITY HAS BEEN ACTIVATED FOR LAK &
6513 &PACKAGE: '//trim(adjustl(this%packName))
6514 end subroutine lak_activate_viscosity
6515
6516 !> @brief Calculate the groundwater-lake density exchange terms
6517 !!
6518 !! Arguments are as follows:
6519 !! iconn : lak-gwf connection number
6520 !! stage : lake stage
6521 !! head : gwf head
6522 !! cond : conductance
6523 !! botl : bottom elevation of this connection
6524 !! flow : calculated flow, updated here with density terms
6525 !! gwfhcof : gwf head coefficient, updated here with density terms
6526 !! gwfrhs : gwf right-hand-side value, updated here with density terms
6527 !!
6528 !! Member variable used here
6529 !! denseterms : shape (3, MAXBOUND), filled by buoyancy package
6530 !! col 1 is relative density of lake (denselak / denseref)
6531 !! col 2 is relative density of gwf cell (densegwf / denseref)
6532 !! col 3 is elevation of gwf cell
6533 !<
6534 subroutine lak_calculate_density_exchange(this, iconn, stage, head, cond, &
6535 botl, flow, gwfhcof, gwfrhs)
6536 ! -- dummy
6537 class(laktype), intent(inout) :: this
6538 integer(I4B), intent(in) :: iconn
6539 real(DP), intent(in) :: stage
6540 real(DP), intent(in) :: head
6541 real(DP), intent(in) :: cond
6542 real(DP), intent(in) :: botl
6543 real(DP), intent(inout) :: flow
6544 real(DP), intent(inout) :: gwfhcof
6545 real(DP), intent(inout) :: gwfrhs
6546 ! -- local
6547 real(DP) :: ss
6548 real(DP) :: hh
6549 real(DP) :: havg
6550 real(DP) :: rdenselak
6551 real(DP) :: rdensegwf
6552 real(DP) :: rdenseavg
6553 real(DP) :: elevlak
6554 real(DP) :: elevgwf
6555 real(DP) :: elevavg
6556 real(DP) :: d1
6557 real(DP) :: d2
6558 logical(LGP) :: stage_below_bot
6559 logical(LGP) :: head_below_bot
6560 !
6561 ! -- Set lak density to lak density or gwf density
6562 if (stage >= botl) then
6563 ss = stage
6564 stage_below_bot = .false.
6565 rdenselak = this%denseterms(1, iconn) ! lak rel density
6566 else
6567 ss = botl
6568 stage_below_bot = .true.
6569 rdenselak = this%denseterms(2, iconn) ! gwf rel density
6570 end if
6571 !
6572 ! -- set hh to head or botl
6573 if (head >= botl) then
6574 hh = head
6575 head_below_bot = .false.
6576 rdensegwf = this%denseterms(2, iconn) ! gwf rel density
6577 else
6578 hh = botl
6579 head_below_bot = .true.
6580 rdensegwf = this%denseterms(1, iconn) ! lak rel density
6581 end if
6582 !
6583 ! -- todo: hack because denseterms not updated in a cf calculation
6584 if (rdensegwf == dzero) return
6585 !
6586 ! -- Update flow
6587 if (stage_below_bot .and. head_below_bot) then
6588 !
6589 ! -- flow is zero, so no terms are updated
6590 !
6591 else
6592 !
6593 ! -- calculate average relative density
6594 rdenseavg = dhalf * (rdenselak + rdensegwf)
6595 !
6596 ! -- Add contribution of first density term:
6597 ! cond * (denseavg/denseref - 1) * (hgwf - hlak)
6598 d1 = cond * (rdenseavg - done)
6599 gwfhcof = gwfhcof - d1
6600 gwfrhs = gwfrhs - d1 * ss
6601 d1 = d1 * (hh - ss)
6602 flow = flow + d1
6603 !
6604 ! -- Add second density term if stage and head not below bottom
6605 if (.not. stage_below_bot .and. .not. head_below_bot) then
6606 !
6607 ! -- Add contribution of second density term:
6608 ! cond * (havg - elevavg) * (densegwf - denselak) / denseref
6609 elevgwf = this%denseterms(3, iconn)
6610 if (this%ictype(iconn) == 0 .or. this%ictype(iconn) == 3) then
6611 ! -- vertical or embedded vertical connection
6612 elevlak = botl
6613 else
6614 ! -- horizontal or embedded horizontal connection
6615 elevlak = elevgwf
6616 end if
6617 elevavg = dhalf * (elevlak + elevgwf)
6618 havg = dhalf * (hh + ss)
6619 d2 = cond * (havg - elevavg) * (rdensegwf - rdenselak)
6620 gwfrhs = gwfrhs + d2
6621 flow = flow + d2
6622 end if
6623 end if
6624 end subroutine lak_calculate_density_exchange
6625
6626end module lakmodule
subroutine init()
This module contains the extended boundary package.
subroutine source_dimensions(this)
@ brief Source package dimensions from input context
subroutine source_options(this)
@ brief Source package options from input context
This module contains the base boundary package.
logical(lgp) function bnd_obs_supported(this)
Determine if observations are supported.
subroutine bnd_ar(this)
@ brief Allocate and read method for boundary package
subroutine bnd_rp(this)
@ brief Allocate and read method for package
subroutine bnd_ot_dv(this, idvsave, idvprint)
@ brief Output advanced package dependent-variable terms.
subroutine bnd_nur(this, neqpak, x, xtemp, dx, inewtonur, dxmax, locmax)
@ brief Apply Newton-Raphson under-relaxation for package.
subroutine bnd_ot_package_flows(this, icbcfl, ibudfl)
@ brief Output advanced package flow terms.
subroutine bnd_ot_model_flows(this, icbcfl, ibudfl, icbcun, imap)
@ brief Output package flow terms.
subroutine bnd_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak)
@ brief Convergence check for package.
subroutine bnd_bd_obs(this)
Save observations for the package.
subroutine bnd_da(this)
@ brief Deallocate package memory
subroutine bnd_mc(this, moffset, matrix_sln)
@ brief Map boundary package connection to matrix
subroutine bnd_fc(this, rhs, ia, idxglo, matrix_sln)
@ brief Copy hcof and rhs terms into solution.
subroutine bnd_ac(this, moffset, sparse)
@ brief Add boundary package connection to matrix
subroutine bnd_ot_bdsummary(this, kstp, kper, iout, ibudfl)
@ brief Output advanced package budget summary.
subroutine bnd_df_obs(this)
Define the observation types available in the package.
subroutine set_pointers(this, neq, ibound, xnew, xold, flowja)
@ brief Set pointers to model variables
subroutine bnd_rp_obs(this)
Read and prepare observations for a package.
subroutine bnd_cf(this)
@ brief Formulate the package hcof and rhs terms.
subroutine bnd_fn(this, rhs, ia, idxglo, matrix_sln)
@ brief Add Newton-Raphson terms for package into solution.
subroutine bnd_ad(this)
@ brief Advance the boundary package
subroutine bnd_cq(this, x, flowja, iadv)
@ brief Calculate advanced package flows.
subroutine define_listlabel(this)
@ brief Define the list label for the package
subroutine, public budgetobject_cr(this, name)
Create a new budget object.
subroutine destroy(this)
This module contains simulation constants.
Definition Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition Constants.f90:45
real(dp), parameter dhdry
real dry cell constant
Definition Constants.f90:94
@ tabcenter
centered table column
@ tabright
right justified table column
@ tableft
left justified table column
@ mnormal
normal output mode
real(dp), parameter dtwothirds
real constant 2/3
Definition Constants.f90:70
@ tabucstring
upper case string table data
@ tabstring
string table data
@ tabreal
real table data
@ tabinteger
integer table data
integer(i4b), parameter lenpackagename
maximum length of the package name
Definition Constants.f90:23
real(dp), parameter dp9
real constant 9/10
Definition Constants.f90:72
integer(i4b), parameter iwetlake
integer constant for a dry lake
Definition Constants.f90:52
real(dp), parameter deight
real constant 8
Definition Constants.f90:83
real(dp), parameter dfivethirds
real constant 5/3
Definition Constants.f90:78
real(dp), parameter dp999
real constant 999/1000
Definition Constants.f90:74
integer(i4b), parameter namedboundflag
named bound flag
Definition Constants.f90:49
real(dp), parameter donethird
real constant 1/3
Definition Constants.f90:67
real(dp), parameter dnodata
real no data constant
Definition Constants.f90:95
real(dp), parameter dhnoflo
real no flow constant
Definition Constants.f90:93
real(dp), parameter dhundred
real constant 100
Definition Constants.f90:86
integer(i4b), parameter lenpakloc
maximum length of a package location
Definition Constants.f90:50
real(dp), parameter dep20
real constant 1e20
Definition Constants.f90:91
real(dp), parameter dem1
real constant 1e-1
integer(i4b), parameter maxadpit
maximum advanced package Newton-Raphson iterations
Definition Constants.f90:53
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
integer(i4b), parameter lenftype
maximum length of a package type (DIS, WEL, OC, etc.)
Definition Constants.f90:39
real(dp), parameter dgravity
real constant gravitational acceleration (m/(s s))
real(dp), parameter dpi
real constant
integer(i4b), parameter lenboundname
maximum length of a bound name
Definition Constants.f90:36
real(dp), parameter dem4
real constant 1e-4
real(dp), parameter dem30
real constant 1e-30
real(dp), parameter dem6
real constant 1e-6
real(dp), parameter dzero
real constant zero
Definition Constants.f90:65
real(dp), parameter dcd
real constant weir coefficient in SI units
real(dp), parameter dem5
real constant 1e-5
real(dp), parameter dten
real constant 10
Definition Constants.f90:84
real(dp), parameter dprec
real constant machine precision
real(dp), parameter dp7
real constant 7/10
Definition Constants.f90:71
real(dp), parameter dem9
real constant 1e-9
real(dp), parameter dem2
real constant 1e-2
real(dp), parameter dtwo
real constant 2
Definition Constants.f90:79
integer(i4b), parameter lenbudtxt
maximum length of a budget component names
Definition Constants.f90:37
integer(i4b), parameter lenmempath
maximum length of the memory path
Definition Constants.f90:27
real(dp), parameter dthree
real constant 3
Definition Constants.f90:80
real(dp), parameter done
real constant 1
Definition Constants.f90:76
integer(i4b) function, public get_node(ilay, irow, icol, nlay, nrow, ncol)
Get node number, given layer, row, and column indices for a structured grid. If any argument is inval...
Definition GeomUtil.f90:92
subroutine, public assign_iounit(iounit, errunit, description)
@ brief assign io unit number
subroutine, public extract_idnum_or_bndname(line, icol, istart, istop, idnum, bndname)
Starting at position icol, define string as line(istart:istop).
integer(i4b) function, public getunit()
Get a free unit number.
subroutine, public ulasav(buf, text, kstp, kper, pertim, totim, ncol, nrow, ilay, ichn)
Save 1 layer array on disk.
subroutine, public openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, filstat_opt, mode_opt)
Open a file.
subroutine, public urword(line, icol, istart, istop, ncode, n, r, iout, in)
Extract a word from a string.
This module defines variable data types.
Definition kind.f90:8
subroutine lak_activate_density(this)
Activate addition of density terms.
Definition gwf-lak.f90:6461
subroutine lak_cq(this, x, flowja, iadv)
Calculate flows.
Definition gwf-lak.f90:4139
subroutine lak_nur(this, neqpak, x, xtemp, dx, inewtonur, dxmax, locmax)
Apply Newton under-relaxation to the lake stage.
Definition gwf-lak.f90:3785
subroutine lak_vol2stage(this, ilak, vol, stage)
Determine the stage from a provided volume.
Definition gwf-lak.f90:2815
subroutine lak_calculate_outlet_outflow(this, ilak, stage, avail, outoutf)
Calculate the outlet outflow from a lake.
Definition gwf-lak.f90:2591
subroutine lak_calculate_sarea(this, ilak, stage, sarea)
Calculate the surface area of a lake at a given stage.
Definition gwf-lak.f90:1973
subroutine lak_fn(this, rhs, ia, idxglo, matrix_sln)
Fill newton terms.
Definition gwf-lak.f90:3712
subroutine lak_ac(this, moffset, sparse)
Add the lake rows and columns to the sparse matrix.
Definition gwf-lak.f90:4655
subroutine lak_source_dimensions(this)
Source DIMENSIONS block from input context and load static data.
Definition gwf-lak.f90:1576
subroutine lak_ot_package_flows(this, icbcfl, ibudfl)
Output LAK package flow terms.
Definition gwf-lak.f90:4282
subroutine lak_accumulate_chterm(this, ilak, rrate, chratin, chratout)
Accumulate constant head terms for budget.
Definition gwf-lak.f90:5248
subroutine lak_get_external_mover(this, ilak, outoutf)
Get the mover outflow from a lake to an external boundary.
Definition gwf-lak.f90:2753
subroutine lak_cf(this)
Formulate the HCOF and RHS terms.
Definition gwf-lak.f90:3590
subroutine lak_calculate_density_exchange(this, iconn, stage, head, cond, botl, flow, gwfhcof, gwfrhs)
Calculate the groundwater-lake density exchange terms.
Definition gwf-lak.f90:6536
subroutine lak_source_outlets(this)
Source OUTLETS block from input context.
Definition gwf-lak.f90:1442
subroutine lak_calculate_evaporation(this, ilak, stage, avail, ev)
Calculate the evaporation from a lake at a provided stage subject to an available volume.
Definition gwf-lak.f90:2543
subroutine lak_setup_budobj(this)
Set up the budget object that stores all the lake flows.
Definition gwf-lak.f90:5960
subroutine lak_calculate_external(this, ilak, ex)
Calculate the external flow terms to a lake.
Definition gwf-lak.f90:2505
subroutine lak_source_connectiondata(this)
Source CONNECTIONDATA block from input context.
Definition gwf-lak.f90:848
subroutine lak_calculate_warea(this, ilak, stage, warea, hin)
Calculate the wetted area of a lake at a given stage.
Definition gwf-lak.f90:2015
subroutine lak_calculate_vol(this, ilak, stage, volume)
Calculate the volume of a lake at a given stage.
Definition gwf-lak.f90:2094
subroutine lak_da(this)
Deallocate objects.
Definition gwf-lak.f90:4407
subroutine lak_calculate_storagechange(this, ilak, stage, stage0, delt, dvr)
Calculate the storage change in a lake based on provided stages and a passed delt.
Definition gwf-lak.f90:2437
subroutine lak_get_internal_outlet(this, ilak, outoutf)
Get the outlet from a lake to another lake.
Definition gwf-lak.f90:2715
subroutine lak_calculate_conductance(this, ilak, stage, conductance)
Calculate the total conductance for a lake at a provided stage.
Definition gwf-lak.f90:2147
subroutine laktables_to_vectors(this, laketables)
Copy the laketables structure data into flattened vectors that are stored in the memory manager.
Definition gwf-lak.f90:1243
subroutine lak_calculate_residual(this, n, hlak, resid, headp)
Calculate the residual for a lake given a passed stage.
Definition gwf-lak.f90:5878
subroutine lak_get_outlet_tomover(this, ilak, outoutf)
Get the outlet to mover from a lake.
Definition gwf-lak.f90:2795
subroutine lak_allocate_arrays(this)
Allocate scalar members.
Definition gwf-lak.f90:504
subroutine, public lak_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, mempath)
Create a new LAK Package and point bndobj to the new package.
Definition gwf-lak.f90:401
subroutine lak_source_options(this)
Source OPTIONS block from input context.
Definition gwf-lak.f90:2973
subroutine lak_calculate_available(this, n, hlak, avail, ra, ro, qinf, ex, headp)
Calculate the available volumetric rate for a lake given a passed stage.
Definition gwf-lak.f90:5814
logical function lak_obs_supported(this)
Procedures related to observations (type-bound).
Definition gwf-lak.f90:4756
subroutine lak_set_pointers(this, neq, ibound, xnew, xold, flowja)
Set pointers to model arrays and variables so that a package has access to these things.
Definition gwf-lak.f90:4613
subroutine lak_calculate_inflow(this, ilak, qin)
Calculate specified inflow to a lake.
Definition gwf-lak.f90:2493
subroutine lak_calculate_conn_exchange_deriv(this, ilak, iconn, stage, head, flow, dqds, dqdh)
Lakebed seepage and its derivatives for a connection (IMPLICIT).
Definition gwf-lak.f90:2357
character(len=lenpackagename) text
Definition gwf-lak.f90:47
subroutine lak_mc(this, moffset, matrix_sln)
Find the matrix position of each lake row and connection.
Definition gwf-lak.f90:4689
subroutine lak_set_nonneg_value(this, n, itemno, setting, value_array, label)
Apply a PERIOD lake setting and require its value be non-negative.
Definition gwf-lak.f90:2929
subroutine lak_ot_model_flows(this, icbcfl, ibudfl, icbcun, imap)
Write flows to binary file and/or print flows to budget.
Definition gwf-lak.f90:4308
subroutine lak_rp_obs(this)
Process each observation.
Definition gwf-lak.f90:5026
subroutine lak_calculate_conn_conductance(this, ilak, iconn, stage, head, cond)
Calculate the conductance for a lake connection at a provided stage and groundwater head.
Definition gwf-lak.f90:2197
subroutine lak_calculate_exchange(this, ilak, stage, totflow)
Calculate the total groundwater-lake flow at a provided stage.
Definition gwf-lak.f90:2263
subroutine lak_linear_interpolation(this, n, x, y, z, v)
Perform linear interpolation of two vectors.
Definition gwf-lak.f90:1928
subroutine lak_input_destroy(this)
Nullify all LakInputType pointers.
Definition gwf-lak.f90:3196
subroutine lak_source_packagedata(this)
Source PACKAGEDATA block from input context.
Definition gwf-lak.f90:647
subroutine lak_setup_tableobj(this)
Set up the table object that is used to write the lak stage data.
Definition gwf-lak.f90:6400
subroutine lak_ot_dv(this, idvsave, idvprint)
Save LAK-calculated values to binary file.
Definition gwf-lak.f90:4321
subroutine lak_get_external_outlet(this, ilak, outoutf)
Get the outlet outflow from a lake to an external boundary.
Definition gwf-lak.f90:2734
subroutine lak_calculate_rainfall(this, ilak, stage, ra)
Calculate the rainfall for a lake.
Definition gwf-lak.f90:2459
subroutine lak_get_internal_inlet(this, ilak, outinf)
Get the outlet inflow to a lake from another lake.
Definition gwf-lak.f90:2694
subroutine lak_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak)
Final convergence check for package.
Definition gwf-lak.f90:3827
subroutine lak_rp(this)
Read and prepare (stress period data).
Definition gwf-lak.f90:3283
subroutine lak_activate_viscosity(this)
Activate viscosity terms.
Definition gwf-lak.f90:6495
subroutine lak_checkin_deprecated_names(this)
Alias deprecated LAK variable names to their current storage.
Definition gwf-lak.f90:589
subroutine lak_read_initial_attr(this)
Read the initial parameters for this package.
Definition gwf-lak.f90:1666
integer(i4b) function lak_check_valid(this, itemno)
Determine if a valid lake or outlet number has been specified.
Definition gwf-lak.f90:2896
subroutine lak_bisection(this, n, ibflg, hlak, temporary_stage, dh, residual)
@ brief Lake package bisection method
Definition gwf-lak.f90:5765
subroutine lak_ad(this)
Add package connection to matrix.
Definition gwf-lak.f90:3503
character(len=lenftype) ftype
Definition gwf-lak.f90:46
subroutine lak_fc(this, rhs, ia, idxglo, matrix_sln)
Copy rhs and hcof into solution rhs and amat.
Definition gwf-lak.f90:3671
subroutine lak_set_attribute_error(this, ilak, keyword, msg)
Issue a parameter error for lake ilak.
Definition gwf-lak.f90:2953
subroutine lak_calculate_runoff(this, ilak, ro)
Calculate runoff to a lake.
Definition gwf-lak.f90:2481
subroutine define_listlabel(this)
Define the list heading that is written to iout when PRINT_INPUT option is used.
Definition gwf-lak.f90:4588
subroutine lak_calculate_withdrawal(this, ilak, avail, wr)
Calculate the withdrawal from a lake subject to an available volume.
Definition gwf-lak.f90:2521
subroutine lak_calculate_conn_warea(this, ilak, iconn, stage, head, wa)
Calculate the wetted area of a lake connection at a given stage.
Definition gwf-lak.f90:2043
subroutine lak_solve(this, update, only_legacy)
Solve for lake stage.
Definition gwf-lak.f90:5309
subroutine lak_estimate_seepage_single(this, n, ncnv)
Estimate the lakebed seepage for a single lake.
Definition gwf-lak.f90:5695
subroutine lak_source_table(this, ilak, mempath, laketable)
Source one lake's table from its LAKTAB6 subpackage.
Definition gwf-lak.f90:1291
subroutine lak_df_obs(this)
Store observation type supported by LAK package. Overrides BndTypebnd_df_obs.
Definition gwf-lak.f90:4766
subroutine lak_allocate_scalars(this)
Allocate scalar members.
Definition gwf-lak.f90:442
subroutine lak_bound_update(this)
Store the lake head and connection conductance in the bound array.
Definition gwf-lak.f90:5278
subroutine lak_calculate_cond_head(this, iconn, stage, head, vv)
Calculate the controlling lake stage or groundwater head used to calculate the conductance for a lake...
Definition gwf-lak.f90:2168
subroutine lak_ot_bdsummary(this, kstp, kper, iout, ibudfl)
Write LAK budget to listing file.
Definition gwf-lak.f90:4392
subroutine lak_bd_obs(this)
Calculate observations this time step and call ObsTypeSaveOneSimval for each LakType observation.
Definition gwf-lak.f90:4871
subroutine lak_estimate_conn_exchange(this, iflag, ilak, iconn, idry, stage, head, flow, source, gwfhcof, gwfrhs)
Calculate the groundwater-lake flow at a provided stage and groundwater head.
Definition gwf-lak.f90:2395
subroutine lak_fill_budobj(this)
Copy flow terms into thisbudobj.
Definition gwf-lak.f90:6212
subroutine lak_get_internal_mover(this, ilak, outoutf)
Get the mover outflow from a lake to another lake.
Definition gwf-lak.f90:2774
subroutine lak_calculate_outlet_inflow(this, ilak, outinf)
Calculate the outlet inflow to a lake.
Definition gwf-lak.f90:2570
subroutine lak_outlet_outflow_rate(this, ilak, stage, qout)
Total uncapped outlet outflow rate from a lake at a provided stage.
Definition gwf-lak.f90:2655
subroutine lak_calculate_conn_exchange(this, ilak, iconn, stage, head, flow, gwfhcof, gwfrhs)
Calculate the groundwater-lake flow at a provided stage and groundwater head.
Definition gwf-lak.f90:2288
subroutine lak_source_tables(this)
Source TABLES block from input context.
Definition gwf-lak.f90:1151
subroutine lak_ar(this)
Allocate and Read.
Definition gwf-lak.f90:3221
subroutine lak_input_init(this, mempath, naux, noutlets)
Bind LakInputType pointers.
Definition gwf-lak.f90:3153
subroutine lak_solve_single(this, n, iter, maxiter, ncnv, lupdate)
Advance one lake stage by a single substitution iteration.
Definition gwf-lak.f90:5481
pure logical function, public is_close(a, b, rtol, atol, symmetric)
Check if a real value is approximately equal to another.
Definition MathUtil.f90:46
Previous variable names checked in as deprecated aliases.
character(len=lenmempath) function create_mem_path(component, subcomponent, context)
returns the path to the memory object
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 derived types ObserveType and ObsDataType.
Definition Observe.f90:15
This module contains the derived type ObsType.
Definition Obs.f90:127
character(len=20) access
Definition OpenSpec.f90:7
character(len=20) form
Definition OpenSpec.f90:7
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 deprecation_warning(cblock, cvar, cver, endmsg, iunit)
Store deprecation warning message.
Definition Sim.f90:257
subroutine, public store_error_filename(filename, terminate)
Store the erroring file name.
Definition Sim.f90:204
This module contains simulation variables.
character(len=maxcharlen) errmsg
error message string
integer(i4b) ifailedstepretry
current retry for this time step
character(len=maxcharlen) warnmsg
warning message string
integer(i4b) iout
file unit number for simulation output
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
real(dp) function sqsaturationderivative(top, bot, x, c1, c2)
@ brief sQSaturationDerivative
real(dp) function sqsaturation(top, bot, x, c1, c2)
@ brief sQSaturation
subroutine finalize(this)
Definition Table.f90:407
subroutine, public table_cr(this, name, title)
Definition Table.f90:87
real(dp), pointer, public pertim
time relative to start of stress period
Definition tdis.f90:33
real(dp), pointer, public totim
time relative to start of simulation
Definition tdis.f90:35
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
real(dp), pointer, public delt
length of the current time step
Definition tdis.f90:32
This class is used to store a single deferred-length character string. It was designed to work in an ...
input context runtime pointers for LAK
Definition gwf-lak.f90:62