MODFLOW 6 version 6.9.0.dev0
USGS Modular Hydrologic Model
Loading...
Searching...
No Matches
prt-prp.f90
Go to the documentation of this file.
2 use kindmodule, only: dp, i4b, lgp
6 use bndmodule, only: bndtype
7 use bndextmodule, only: bndexttype
9 use prtfmimodule, only: prtfmitype
22 use dismodule, only: distype
23 use disvmodule, only: disvtype
24 use errorutilmodule, only: pstop
27
28 implicit none
29
30 private
31 public :: prtprptype, exgprtprptype
32 public :: prp_create
33
34 character(len=LENFTYPE) :: ftype = 'PRP'
35 character(len=16) :: text = ' PRP'
36 real(dp), parameter :: default_exit_solve_tolerance = dem5
37
38 !> @brief Particle release point (PRP) package
39 type, extends(bndexttype) :: prtprptype
40 ! options
41 logical(LGP), pointer :: extend => null() !< extend tracking beyond simulation's end
42 logical(LGP), pointer :: frctrn => null() !< force ternary solution for quad grids
43 logical(LGP), pointer :: drape => null() !< whether to drape particle to topmost active cell
44 logical(LGP), pointer :: localz => null() !< compute z coordinates local to the release cell
45 integer(I4B), pointer :: istopweaksink => null() !< weak sink option: 0 = no stop, 1 = stop
46 integer(I4B), pointer :: istopzone => null() !< optional stop zone number: 0 = no stop zone
47 integer(I4B), pointer :: idrymeth => null() !< dry tracking method: 0 = drop, 1 = stop, 2 = stay
48 integer(I4B), pointer :: itrkout => null() !< binary track file
49 integer(I4B), pointer :: itrkhdr => null() !< track header file
50 integer(I4B), pointer :: itrkcsv => null() !< CSV track file
51 integer(I4B), pointer :: irlstls => null() !< release time file
52 integer(I4B), pointer :: iexmeth => null() !< method for iterative solution of particle exit location and time in generalized Pollock's method
53 integer(I4B), pointer :: ichkmeth => null() !< method for checking particle release coordinates are in the specified cells, 0 = none, 1 = eager
54 integer(I4B), pointer :: icycwin => null() !< cycle detection window size
55 real(dp), pointer :: extol => null() !< tolerance for iterative solution of particle exit location and time in generalized Pollock's method
56 real(dp), pointer :: rttol => null() !< tolerance for coincident particle release times
57 real(dp), pointer :: rtfreq => null() !< frequency for regularly spaced release times
58 real(dp), pointer :: offset => null() !< release time offset
59 real(dp), pointer :: stoptime => null() !< stop time for all release points
60 real(dp), pointer :: stoptraveltime => null() !< stop travel time for all points
61 ! members
62 type(prtfmitype), pointer :: fmi => null() !< flow model interface
63 type(particlestoretype), pointer :: particles => null() !< committed particle state (end of last successful time step)
64 type(particlestoretype), pointer :: particles_staging => null() !< staging particle state for the current solve attempt
65 type(particlereleasescheduletype), pointer :: schedule => null() !< particle release schedule
66 integer(I4B), pointer :: nreleasepoints => null() !< number of release points
67 integer(I4B), pointer :: nreleasetimes => null() !< number of user-specified particle release times
68 integer(I4B), pointer :: nparticles => null() !< number of particles released
69 integer(I4B), pointer, contiguous :: rptnode(:) => null() !< release point reduced nns
70 integer(I4B), pointer, contiguous :: rptzone(:) => null() !< release point zone numbers
71 real(dp), pointer, contiguous :: rptx(:) => null() !< release point x coordinates
72 real(dp), pointer, contiguous :: rpty(:) => null() !< release point y coordinates
73 real(dp), pointer, contiguous :: rptz(:) => null() !< release point z coordinates
74 real(dp), pointer, contiguous :: rptm(:) => null() !< total mass released from point
75 character(len=LENBOUNDNAME), pointer, contiguous :: rptname(:) => null() !< release point names
76 character(len=LINELENGTH), allocatable :: period_block_lines(:) !< last period block configuration for fill-forward
77 integer(I4B) :: applied_kper !< period for which configuration was last applied
78 contains
81 procedure :: bnd_ar => prp_ar
82 procedure :: bnd_ad => prp_ad
83 procedure :: bnd_rp => prp_rp
85 procedure :: bnd_da => prp_da
86 procedure :: prp_commit
87 procedure :: define_listlabel
88 procedure :: prp_set_pointers
91 procedure :: prp_log_options
92 procedure :: prp_packagedata
93 procedure :: prp_releasetimes
95 procedure :: release
96 procedure :: log_release
99 procedure, public :: bnd_obs_supported => prp_obs_supported
100 procedure, public :: bnd_df_obs => prp_df_obs
101 end type prtprptype
102
103 !> @brief Exchange PRP package. A variant of the normal PRP package
104 !! that doesn't read from input files but instead receives particle
105 !! transfers from coupled models while preserving the pattern where
106 !! PRP packages own particles. Call it "Particle Registry Package"?
107 type, extends(prtprptype) :: exgprtprptype
108 contains
113 procedure :: bnd_ar => exg_prp_ar
114 procedure :: bnd_rp => exg_prp_rp
115 procedure :: bnd_ad => exg_prp_ad
117 procedure :: bnd_bd => exg_prp_bd
119 end type exgprtprptype
120contains
121
122 !> @brief Create a new particle release point package.
123 !!
124 !! Creates either a standard PRP (reads from input file) or an exchange
125 !! PRP (programmatically populated). The type is determined by whether
126 !! input_mempath is provided: if present, standard; if absent, exchange.
127 subroutine prp_create(packobj, id, ibcnum, inunit, iout, namemodel, &
128 pakname, fmi, input_mempath)
129 ! dummy
130 class(bndtype), pointer :: packobj
131 integer(I4B), intent(in) :: id
132 integer(I4B), intent(in) :: ibcnum
133 integer(I4B), intent(in) :: inunit
134 integer(I4B), intent(in) :: iout
135 character(len=*), intent(in) :: namemodel
136 character(len=*), intent(in) :: pakname
137 character(len=*), intent(in), optional :: input_mempath
138 type(prtfmitype), pointer :: fmi
139 ! local
140 type(prtprptype), pointer :: prpobj
141 type(exgprtprptype), pointer :: exgprpobj
142 ! formats
143 character(len=*), parameter :: fmtheader = &
144 "(1x, /1x, 'PRP PARTICLE RELEASE POINT PACKAGE', &
145 &' INPUT READ FROM MEMPATH: ', a, /)"
146 character(len=*), parameter :: fmtexgheader = &
147 "(1x, /1x, 'PRP-EXG EXCHANGE PARTICLE RELEASE POINT PACKAGE', &
148 &' (PROGRAMMATIC INPUT)', /)"
149
150 if (present(input_mempath)) then
151 ! standard PRP
152 allocate (prpobj)
153 packobj => prpobj
154
155 call packobj%set_names(ibcnum, namemodel, pakname, ftype, input_mempath)
156 prpobj%text = text
157
158 call prpobj%prp_allocate_scalars()
159 call packobj%pack_initialize()
160
161 packobj%inunit = inunit
162 packobj%iout = iout
163 packobj%id = id
164 packobj%ibcnum = ibcnum
165 packobj%ncolbnd = 4
166 packobj%iscloc = 1
167 prpobj%fmi => fmi
168
169 if (inunit > 0) write (iout, fmtheader) input_mempath
170 else
171 ! exchange PRP
172 allocate (exgprpobj)
173 packobj => exgprpobj
174
175 call packobj%set_names(ibcnum, namemodel, pakname, ftype)
176 exgprpobj%text = text
177
178 call exgprpobj%prp_allocate_scalars()
179 call packobj%pack_initialize()
180
181 packobj%inunit = inunit
182 packobj%iout = iout
183 packobj%id = id
184 packobj%ibcnum = ibcnum
185 packobj%ncolbnd = 4
186 packobj%iscloc = 1
187 exgprpobj%fmi => fmi
188
189 if (iout > 0) write (iout, fmtexgheader)
190 end if
191 end subroutine prp_create
192
193 !> @brief Deallocate memory
194 subroutine prp_da(this)
195 class(prtprptype) :: this
196
197 ! Deallocate parent
198 call this%BndExtType%bnd_da()
199
200 ! Deallocate scalars
201 call mem_deallocate(this%localz)
202 call mem_deallocate(this%extend)
203 call mem_deallocate(this%offset)
204 call mem_deallocate(this%stoptime)
205 call mem_deallocate(this%stoptraveltime)
206 call mem_deallocate(this%istopweaksink)
207 call mem_deallocate(this%istopzone)
208 call mem_deallocate(this%drape)
209 call mem_deallocate(this%idrymeth)
210 call mem_deallocate(this%nreleasepoints)
211 call mem_deallocate(this%nreleasetimes)
212 call mem_deallocate(this%nparticles)
213 call mem_deallocate(this%itrkout)
214 call mem_deallocate(this%itrkhdr)
215 call mem_deallocate(this%itrkcsv)
216 call mem_deallocate(this%irlstls)
217 call mem_deallocate(this%frctrn)
218 call mem_deallocate(this%iexmeth)
219 call mem_deallocate(this%ichkmeth)
220 call mem_deallocate(this%icycwin)
221 call mem_deallocate(this%extol)
222 call mem_deallocate(this%rttol)
223 call mem_deallocate(this%rtfreq)
224
225 ! Deallocate arrays
226 call mem_deallocate(this%rptx)
227 call mem_deallocate(this%rpty)
228 call mem_deallocate(this%rptz)
229 call mem_deallocate(this%rptnode)
230 call mem_deallocate(this%rptm)
231 call mem_deallocate(this%rptname, 'RPTNAME', this%memoryPath)
232
233 ! Deallocate period block storage
234 if (allocated(this%period_block_lines)) deallocate (this%period_block_lines)
235
236 ! Deallocate objects
237 call this%particles%destroy(this%memoryPath)
238 call this%particles_staging%destroy(trim(this%memoryPath)//'-STAGING')
239 call this%schedule%destroy()
240 deallocate (this%particles)
241 deallocate (this%particles_staging)
242 deallocate (this%schedule)
243 end subroutine prp_da
244
245 !> @ brief Set pointers to model variables
246 subroutine prp_set_pointers(this, ibound, izone)
247 class(prtprptype) :: this
248 integer(I4B), dimension(:), pointer, contiguous :: ibound
249 integer(I4B), dimension(:), pointer, contiguous :: izone
250
251 this%ibound => ibound
252 this%rptzone => izone
253 end subroutine prp_set_pointers
254
255 !> @brief Allocate arrays
256 subroutine prp_allocate_arrays(this, nodelist, auxvar)
257 ! dummy
258 class(prtprptype) :: this
259 integer(I4B), dimension(:), pointer, contiguous, optional :: nodelist
260 real(DP), dimension(:, :), pointer, contiguous, optional :: auxvar
261 ! local
262 integer(I4B) :: nps
263
264 call this%BndExtType%allocate_arrays()
265
266 ! Allocate particle stores
268 this%particles, 0, &
269 this%memoryPath)
271 this%particles_staging, 0, &
272 trim(this%memoryPath)//'-STAGING')
273
274 ! Allocate arrays
275 call mem_allocate(this%rptx, this%nreleasepoints, 'RPTX', this%memoryPath)
276 call mem_allocate(this%rpty, this%nreleasepoints, 'RPTY', this%memoryPath)
277 call mem_allocate(this%rptz, this%nreleasepoints, 'RPTZ', this%memoryPath)
278 call mem_allocate(this%rptm, this%nreleasepoints, 'RPTMASS', &
279 this%memoryPath)
280 call mem_allocate(this%rptnode, this%nreleasepoints, 'RPTNODER', &
281 this%memoryPath)
282 call mem_allocate(this%rptname, lenboundname, this%nreleasepoints, &
283 'RPTNAME', this%memoryPath)
284
285 ! Initialize arrays
286 do nps = 1, this%nreleasepoints
287 this%rptm(nps) = dzero
288 end do
289 end subroutine prp_allocate_arrays
290
291 !> @brief Allocate scalars
292 subroutine prp_allocate_scalars(this)
293 class(prtprptype) :: this
294
295 ! Allocate parent's scalars
296 call this%BndExtType%allocate_scalars()
297
298 ! Allocate scalars for this type
299 call mem_allocate(this%localz, 'LOCALZ', this%memoryPath)
300 call mem_allocate(this%extend, 'EXTEND', this%memoryPath)
301 call mem_allocate(this%offset, 'OFFSET', this%memoryPath)
302 call mem_allocate(this%stoptime, 'STOPTIME', this%memoryPath)
303 call mem_allocate(this%stoptraveltime, 'STOPTRAVELTIME', this%memoryPath)
304 call mem_allocate(this%istopweaksink, 'ISTOPWEAKSINK', this%memoryPath)
305 call mem_allocate(this%istopzone, 'ISTOPZONE', this%memoryPath)
306 call mem_allocate(this%drape, 'DRAPE', this%memoryPath)
307 call mem_allocate(this%idrymeth, 'IDRYMETH', this%memoryPath)
308 call mem_allocate(this%nreleasepoints, 'NRELEASEPOINTS', this%memoryPath)
309 call mem_allocate(this%nreleasetimes, 'NRELEASETIMES', this%memoryPath)
310 call mem_allocate(this%nparticles, 'NPARTICLES', this%memoryPath)
311 call mem_allocate(this%itrkout, 'ITRKOUT', this%memoryPath)
312 call mem_allocate(this%itrkhdr, 'ITRKHDR', this%memoryPath)
313 call mem_allocate(this%itrkcsv, 'ITRKCSV', this%memoryPath)
314 call mem_allocate(this%irlstls, 'IRLSTLS', this%memoryPath)
315 call mem_allocate(this%frctrn, 'FRCTRN', this%memoryPath)
316 call mem_allocate(this%iexmeth, 'IEXMETH', this%memoryPath)
317 call mem_allocate(this%ichkmeth, 'ICHKMETH', this%memoryPath)
318 call mem_allocate(this%icycwin, 'ICYCWIN', this%memoryPath)
319 call mem_allocate(this%extol, 'EXTOL', this%memoryPath)
320 call mem_allocate(this%rttol, 'RTTOL', this%memoryPath)
321 call mem_allocate(this%rtfreq, 'RTFREQ', this%memoryPath)
322
323 ! Set values
324 this%localz = .false.
325 this%extend = .false.
326 this%offset = dzero
327 this%stoptime = huge(1d0)
328 this%stoptraveltime = huge(1d0)
329 this%istopweaksink = 0
330 this%istopzone = 0
331 this%drape = .false.
332 this%idrymeth = 0
333 this%nreleasepoints = 0
334 this%nreleasetimes = 0
335 this%nparticles = 0
336 this%itrkout = 0
337 this%itrkhdr = 0
338 this%itrkcsv = 0
339 this%irlstls = 0
340 this%frctrn = .false.
341 this%iexmeth = 0
342 this%ichkmeth = 1
343 this%icycwin = 0
345 this%rttol = dsame * dep9
346 this%rtfreq = dzero
347 this%applied_kper = 0
348
349 end subroutine prp_allocate_scalars
350
351 !> @ brief Allocate and read period data
352 subroutine prp_ar(this)
353 class(prtprptype), intent(inout) :: this
354 integer(I4B) :: n
355
356 call this%obs%obs_ar()
357
358 if (this%inamedbound /= 0) then
359 do n = 1, this%nreleasepoints
360 this%boundname(n) = this%rptname(n)
361 end do
362 end if
363 do n = 1, this%nreleasepoints
364 this%nodelist(n) = this%rptnode(n)
365 end do
366 end subroutine prp_ar
367
368 !> @brief Allocate scalars for exchange PRP.
369 !!
370 !! The exchange PRP is a headless package (no input file) but BndExtType
371 !! expects certain variables to exist in the input context (IPER, IONPER)
372 !! so we need to manually create them before calling the parent procedure.
375 class(exgprtprptype) :: this
376 integer(I4B), pointer :: iper, ionper
377
378 this%input_mempath = trim(this%memoryPath)//'-INPUT'
379
380 call mem_allocate(iper, 'IPER', this%input_mempath)
381 call mem_allocate(ionper, 'IONPER', this%input_mempath)
382
383 ! set iper = 0. this forces BndExtType%bnd_rp to
384 ! return early, since iper will never match kper.
385 iper = 0
386 ionper = 0
387
388 call this%PrtPrpType%prp_allocate_scalars()
389 end subroutine exg_prp_allocate_scalars
390
391 !> @brief Allocate arrays for exchange PRP.
392 !!
393 !! BndExtType expects certain array variables to exist in the input context
394 !! (CELLID, NODEULIST, BOUNDNAME, AUXVAR). This method manually creates
395 !! zero-sized arrays before calling the parent's allocate_arrays.
396 subroutine exg_prp_allocate_arrays(this, nodelist, auxvar)
399 class(exgprtprptype) :: this
400 integer(I4B), dimension(:), pointer, contiguous, optional :: nodelist
401 real(DP), dimension(:, :), pointer, contiguous, optional :: auxvar
402 ! local
403 integer(I4B), dimension(:, :), pointer, contiguous :: cellid
404 integer(I4B), dimension(:), pointer, contiguous :: nodeulist
405 type(characterstringtype), dimension(:), pointer, contiguous :: boundname
406 real(DP), dimension(:, :), pointer, contiguous :: auxvar_input
407
408 call mem_allocate(cellid, this%dis%ndim, 0, 'CELLID', this%input_mempath)
409 call mem_allocate(nodeulist, 0, 'NODEULIST', this%input_mempath)
410 call mem_allocate(boundname, lenboundname, 0, 'BOUNDNAME', &
411 this%input_mempath)
412 call mem_allocate(auxvar_input, 0, 0, 'AUXVAR', this%input_mempath)
413
414 call this%PrtPrpType%prp_allocate_arrays(nodelist, auxvar)
415 end subroutine exg_prp_allocate_arrays
416
417 !> @ brief No-op AR method override for exchange PRP.
418 subroutine exg_prp_ar(this)
419 class(exgprtprptype), intent(inout) :: this
420 end subroutine exg_prp_ar
421
422 !> @brief Advance a time step and release particles if scheduled.
423 subroutine prp_ad(this)
424 use tdismodule, only: totalsimtime, kstp, kper
425 class(prtprptype) :: this
426 integer(I4B) :: ip, it
427 real(DP) :: t
428
429 ! Notes
430 ! -----
431 ! Each release point can be thought of as
432 ! a gumball machine with infinite supply:
433 ! a point can release an arbitrary number
434 ! of particles, but only one at any time.
435 ! Coincident release times are merged to
436 ! a single time by the release scheduler.
437
438 ! Reset staging from committed state for this solve attempt.
439 if (.not. this%fmi%flows_from_file) then
440 call this%particles_staging%resize( &
441 this%particles%num_stored(), &
442 trim(this%memoryPath)//'-STAGING')
443 call this%particles_staging%copy_from(this%particles)
444 this%nparticles = this%particles%num_stored()
445 end if
446
447 ! Reset mass accumulators for this time step.
448 do ip = 1, this%nreleasepoints
449 this%rptm(ip) = dzero
450 end do
451
452 ! Advance the release schedule. At the start of each period (kstp==1),
453 ! apply period block configuration if available and not yet applied.
454 ! This handles both new configuration and fill-forward periods.
455 ! For subsequent time steps, just advance without arguments to
456 ! advance the time selection object to the current time step.
457 if (kstp == 1 .and. &
458 kper /= this%applied_kper .and. &
459 allocated(this%period_block_lines)) then
460 call this%schedule%advance(lines=this%period_block_lines)
461 this%applied_kper = kper
462 else
463 call this%schedule%advance()
464 end if
465
466 ! Check if any releases will be made this time step.
467 if (.not. this%schedule%any()) return
468
469 ! Log the schedule to the list file.
470 call this%log_release()
471
472 ! Expand the staging store. We know from the
473 ! schedule how many particles will be released.
474 call this%particles_staging%resize( &
475 this%particles_staging%num_stored() + &
476 (this%nreleasepoints * this%schedule%count()), &
477 trim(this%memoryPath)//'-STAGING')
478
479 ! Release a particle from each point for
480 ! each release time in the current step.
481 do ip = 1, this%nreleasepoints
482 do it = 1, this%schedule%count()
483 t = this%schedule%times(it)
484 ! Skip the release time if it's before the simulation
485 ! starts, or if no `extend_tracking`, after it ends.
486 if (t < dzero) then
487 write (warnmsg, '(a,g0,a)') &
488 'Skipping negative release time (t=', t, ').'
490 cycle
491 else if (t > totalsimtime .and. .not. this%extend) then
492 write (warnmsg, '(a,g0,a)') &
493 'Skipping release time falling after the end of the &
494 &simulation (t=', t, '). Enable EXTEND_TRACKING to &
495 &release particles after the simulation end time.'
497 cycle
498 end if
499 call this%release(ip, t)
500 end do
501 end do
502 end subroutine prp_ad
503
504 !> @brief Commit staged particle state to the "final" store.
505 subroutine prp_commit(this)
506 class(prtprptype) :: this
507 call this%particles%resize( &
508 this%particles_staging%num_stored(), &
509 this%memoryPath)
510 call this%particles%copy_from(this%particles_staging)
511 end subroutine prp_commit
512
513 !> @brief No-op AD method override for exchange PRP.
514 subroutine exg_prp_ad(this)
515 class(exgprtprptype) :: this
516 end subroutine exg_prp_ad
517
518 !> @brief No-op flow calculation for exchange PRP.
519 !!
520 !! Exchange PRP particles are transferred from other models and already
521 !! active, so their mass is already accounted for in the STORAGE term.
522 subroutine exg_prp_cq_simrate(this, hnew, flowja, imover)
523 class(exgprtprptype) :: this
524 real(DP), dimension(:), intent(in) :: hnew
525 real(DP), dimension(:), intent(inout) :: flowja
526 integer(I4B), intent(in) :: imover
527 end subroutine exg_prp_cq_simrate
528
529 !> @brief No-op budget method for exchange PRP.
530 !! Likewise about the STORAGE term accounting.
531 subroutine exg_prp_bd(this, model_budget)
532 use budgetmodule, only: budgettype
533 class(exgprtprptype) :: this
534 type(budgettype), intent(inout) :: model_budget
535 end subroutine exg_prp_bd
536
537 !> @brief No-op flow output method for exchange PRP.
538 !! No contribution to budget, no need to write output.
539 subroutine exg_prp_ot_model_flows(this, icbcfl, ibudfl, icbcun, imap)
540 class(exgprtprptype) :: this
541 integer(I4B), intent(in) :: icbcfl
542 integer(I4B), intent(in) :: ibudfl
543 integer(I4B), intent(in) :: icbcun
544 integer(I4B), dimension(:), optional, intent(in) :: imap
545 end subroutine exg_prp_ot_model_flows
546
547 !> @brief Log the release scheduled for this time step.
548 subroutine log_release(this)
549 class(prtprptype), intent(inout) :: this !< prp
550 if (this%iprpak > 0) then
551 write (this%iout, "(1x,/1x,a,1x,i0)") &
552 'PARTICLE RELEASE FOR PRP', this%ibcnum
553 call this%schedule%log(this%iout)
554 end if
555 end subroutine log_release
556
557 !> @brief Verify that the release point is in the cell.
558 !!
559 !! Terminate with an error if the release point lies outside the
560 !! given cell, or if the point is above or below the grid top or
561 !! bottom, respectively.
562 !<
563 subroutine validate_release_point(this, ic, x, y, z)
564 class(prtprptype), intent(inout) :: this !< this instance
565 integer(I4B), intent(in) :: ic !< cell index
566 real(DP), intent(in) :: x, y, z !< release point
567 ! local
568 real(DP), allocatable :: polyverts(:, :)
569 real(DP) :: cellsize, tol
570
571 call this%fmi%dis%get_polyverts(ic, polyverts)
572 ! Check that the point is within the cell. The point-in-polygon
573 ! check is exact by default, which is unreliable when coords are
574 ! are rotated or very large relative to the cell's size: release
575 ! points on or very close to the cell edge could be rejected as
576 ! outside the cell. Give the check a tolerance scaled to the
577 ! cell extent to reduce sensitivity to coordinate inexactness.
578 cellsize = max(maxval(polyverts(1, :)) - minval(polyverts(1, :)), &
579 maxval(polyverts(2, :)) - minval(polyverts(2, :)))
580 tol = cellsize * cellsize * dem7
581 if (.not. point_in_polygon(x, y, polyverts, tol)) then
582 write (errmsg, '(a,g0,a,g0,a,i0)') &
583 'Error: release point (x=', x, ', y=', y, ') is not in cell ', &
584 this%dis%get_nodeuser(ic)
585 call store_error(errmsg, terminate=.false.)
586 call store_error_filename(this%input_fname)
587 end if
588 if (z > maxval(this%dis%top)) then
589 write (errmsg, '(a,g0,a,g0,a,i0)') &
590 'Error: release point (z=', z, ') is above grid top ', &
591 maxval(this%dis%top)
592 call store_error(errmsg, terminate=.false.)
593 call store_error_filename(this%input_fname)
594 else if (z < minval(this%dis%bot)) then
595 write (errmsg, '(a,g0,a,g0,a,i0)') &
596 'Error: release point (z=', z, ') is below grid bottom ', &
597 minval(this%dis%bot)
598 call store_error(errmsg, terminate=.false.)
599 call store_error_filename(this%input_fname)
600 end if
601 deallocate (polyverts)
602 end subroutine validate_release_point
603
604 !> Release a particle at the specified time.
605 !!
606 !! Releasing a particle entails validating the particle's
607 !! coordinates and settings, transforming its coordinates
608 !! if needed, initializing the particle's initial tracking
609 !! time to the given release time, storing the particle in
610 !! the particle store (from which the PRT model will later
611 !! retrieve it, apply the tracking method, and check it in
612 !! again), and accumulating the particle's mass (the total
613 !! mass released from each release point is calculated for
614 !! budget reporting).
615 !<
616 subroutine release(this, ip, trelease)
617 ! dummy
618 class(prtprptype), intent(inout) :: this !< this instance
619 integer(I4B), intent(in) :: ip !< particle index
620 real(DP), intent(in) :: trelease !< release time
621 ! local
622 integer(I4B) :: np
623 type(particletype), pointer :: particle
624
625 call this%initialize_particle(particle, ip, trelease)
626 np = this%nparticles + 1
627 this%nparticles = np
628 call this%particles_staging%put(particle, np)
629 deallocate (particle)
630 this%rptm(ip) = this%rptm(ip) + done ! TODO configurable mass
631
632 end subroutine release
633
634 subroutine initialize_particle(this, particle, ip, trelease)
636 class(prtprptype), intent(inout) :: this !< this instance
637 type(particletype), pointer, intent(inout) :: particle !< the particle
638 integer(I4B), intent(in) :: ip !< particle index
639 real(DP), intent(in) :: trelease !< release time
640 ! local
641 logical(LGP) :: draped
642 integer(I4B) :: irow, icol, ilay, icpl
643 integer(I4B) :: ic, icu, ic_old
644 real(DP) :: x, y, z
645 ! formats
646 character(len=*), parameter :: fmticterr = &
647 "('Error in ',a,': Flow model interface does not contain ICELLTYPE. &
648 &ICELLTYPE is required for PRT to distinguish convertible cells &
649 &from confined cells if LOCAL_Z release coordinates are provided. &
650 &Make sure a GWFGRID entry is configured in the PRT FMI package.')"
651
652 ic = this%rptnode(ip)
653
654 call create_particle(particle)
655
656 if (size(this%boundname) /= 0) then
657 particle%name = this%boundname(ip)
658 else
659 particle%name = ''
660 end if
661
662 particle%irpt = ip
663 particle%istopweaksink = this%istopweaksink
664 particle%istopzone = this%istopzone
665 particle%idrymeth = this%idrymeth
666 particle%istatus = 0 ! status 0 until tracking starts
667
668 ! If the cell is inactive, either drape the particle
669 ! to the top-most active cell beneath it if drape is
670 ! enabled, or else terminate permanently unreleased.
671 draped = .false.
672 if (this%ibound(ic) == 0) then
673 ic_old = ic
674 if (this%drape) then
675 call this%dis%highest_active(ic, this%ibound)
676 draped = ic /= ic_old
677 if (.not. draped .and. this%ibound(ic) == 0) then
678 ! negative unreleased status signals to the
679 ! tracking method that we haven't yet saved
680 ! a termination record, it needs to do so.
681 particle%istatus = -1 * term_unreleased
682 end if
683 else
684 particle%istatus = -1 * term_unreleased
685 end if
686 end if
687
688 icu = this%dis%get_nodeuser(ic)
689 particle%icu = icu
690 select type (dis => this%dis)
691 type is (distype)
692 call get_ijk(icu, dis%nrow, dis%ncol, dis%nlay, irow, icol, ilay)
693 type is (disvtype)
694 call get_jk(icu, dis%ncpl, dis%nlay, icpl, ilay)
695 end select
696 particle%ilay = ilay
697 particle%izone = this%rptzone(ic)
698
699 ! if the particle was draped to this cell, set the z coord to
700 ! the effective top of the cell. if it was not draped, and is
701 ! a local z coord, calculate the corresponding model z coord.
702 if (draped) then
703 z = this%fmi%dis%bot(ic) + &
704 this%fmi%gwfsat(ic) * &
705 (this%fmi%dis%top(ic) - this%fmi%dis%bot(ic))
706 else if (this%localz) then
707 z = this%fmi%dis%bot(ic) + &
708 this%rptz(ip) * &
709 this%fmi%gwfsat(ic) * &
710 (this%fmi%dis%top(ic) - this%fmi%dis%bot(ic))
711 else
712 z = this%rptz(ip)
713 end if
714
715 x = this%rptx(ip)
716 y = this%rpty(ip)
717
718 if (this%ichkmeth > 0) &
719 call this%validate_release_point(ic, x, y, z)
720
721 particle%x = x
722 particle%y = y
723 particle%z = z
724 particle%trelease = trelease
725
726 ! Set stop time to earlier of STOPTIME and STOPTRAVELTIME
727 if (this%stoptraveltime == huge(1d0)) then
728 particle%tstop = this%stoptime
729 else
730 particle%tstop = particle%trelease + this%stoptraveltime
731 if (this%stoptime < particle%tstop) particle%tstop = this%stoptime
732 end if
733
734 particle%ttrack = particle%trelease
735 particle%itrdomain(level_model) = 0
736 particle%iboundary(level_model) = 0
737 particle%itrdomain(level_feature) = ic
738 particle%iboundary(level_feature) = 0
739 particle%itrdomain(level_subfeature) = 0
740 particle%iboundary(level_subfeature) = 0
741 particle%frctrn = this%frctrn
742 particle%iexmeth = this%iexmeth
743 particle%extend = this%extend
744 particle%icycwin = this%icycwin
745 particle%extol = this%extol
746 end subroutine initialize_particle
747
748 !> @ brief Read and prepare period data for particle input
749 subroutine prp_rp(this)
750 ! modules
751 use tdismodule, only: kper, nper
754 ! dummy variables
755 class(prtprptype), intent(inout) :: this
756 ! local variables
757 type(characterstringtype), dimension(:), contiguous, &
758 pointer :: settings
759 integer(I4B), pointer :: iper, ionper, nlist
760 integer(I4B) :: n
761
762 ! set pointer to last and next period loaded
763 call mem_setptr(iper, 'IPER', this%input_mempath)
764 call mem_setptr(ionper, 'IONPER', this%input_mempath)
765
766 if (kper == 1 .and. &
767 (iper == 0) .and. &
768 (ionper > nper) .and. &
769 size(this%schedule%time_select%times) == 0) then
770 ! If the user hasn't provided any release settings (neither
771 ! explicit release times, release time frequency, nor period
772 ! block release settings), default to a single release at the
773 ! start of the simulation (t=0). Add t=0 directly to the time
774 ! selection rather than time step selection because the latter
775 ! would fill forward, releasing at the start of every period.
776 call this%schedule%time_select%extend([dzero])
777 return
778 else if (iper /= kper) then
779 return
780 end if
781
782 ! set input context pointers
783 call mem_setptr(nlist, 'NBOUND', this%input_mempath)
784 call mem_setptr(settings, 'SETTING', this%input_mempath)
785
786 ! Store period block configuration for fill-forward.
787 if (allocated(this%period_block_lines)) deallocate (this%period_block_lines)
788 allocate (this%period_block_lines(nlist))
789 do n = 1, nlist
790 this%period_block_lines(n) = settings(n)
791 end do
792 end subroutine prp_rp
793
794 !> @ brief No-op RP method override for exchange PRP.
795 subroutine exg_prp_rp(this)
796 class(exgprtprptype), intent(inout) :: this
797 end subroutine exg_prp_rp
798
799 !> @ brief Calculate flow between package and model.
800 subroutine prp_cq_simrate(this, hnew, flowja, imover)
801 ! modules
802 use tdismodule, only: delt
803 ! dummy variables
804 class(prtprptype) :: this
805 real(DP), dimension(:), intent(in) :: hnew
806 real(DP), dimension(:), intent(inout) :: flowja !< flow between package and model
807 integer(I4B), intent(in) :: imover !< flag indicating if the mover package is active
808 ! local variables
809 integer(I4B) :: i
810 integer(I4B) :: node
811 integer(I4B) :: idiag
812 real(DP) :: rrate
813
814 ! If no boundaries, skip flow calculations.
815 if (this%nbound <= 0) return
816
817 ! Loop through each boundary calculating flow.
818 do i = 1, this%nbound
819 node = this%nodelist(i)
820 rrate = dzero
821 ! If cell is no-flow or constant-head, then ignore it.
822 if (node > 0) then
823 ! Calculate the flow rate into the cell.
824 idiag = this%dis%con%ia(node)
825 rrate = this%rptm(i) * (done / delt) ! reciprocal of tstp length
826 flowja(idiag) = flowja(idiag) + rrate
827 end if
828
829 ! Save simulated value to simvals array.
830 this%simvals(i) = rrate
831 end do
832 end subroutine prp_cq_simrate
833
834 subroutine define_listlabel(this)
835 class(prtprptype), intent(inout) :: this
836 ! not implemented, not used
837 end subroutine define_listlabel
838
839 !> @brief Indicates whether observations are supported.
840 logical function prp_obs_supported(this)
841 class(prtprptype) :: this
842 prp_obs_supported = .true.
843 end function prp_obs_supported
844
845 !> @brief Store supported observations
846 subroutine prp_df_obs(this)
847 ! dummy
848 class(prtprptype) :: this
849 ! local
850 integer(I4B) :: indx
851 call this%obs%StoreObsType('prp', .true., indx)
852 this%obs%obsData(indx)%ProcessIdPtr => defaultobsidprocessor
853
854 ! Store obs type and assign procedure pointer
855 ! for to-mvr observation type.
856 call this%obs%StoreObsType('to-mvr', .true., indx)
857 this%obs%obsData(indx)%ProcessIdPtr => defaultobsidprocessor
858 end subroutine prp_df_obs
859
860 !> @ brief Set options specific to PrtPrpType
861 subroutine prp_options(this)
862 ! -- modules
865 use openspecmodule, only: access, form
868 ! -- dummy variables
869 class(prtprptype), intent(inout) :: this
870 ! -- local variables
871 character(len=LENVARNAME), dimension(3) :: drytrack_method = &
872 &[character(len=LENVARNAME) :: 'DROP', 'STOP', 'STAY']
873 character(len=lenvarname), dimension(2) :: coorcheck_method = &
874 &[character(len=LENVARNAME) :: 'NONE', 'EAGER']
875 character(len=LINELENGTH) :: trackfile, trackcsvfile, fname
876 type(prtprpparamfoundtype) :: found
877 character(len=*), parameter :: fmtextolwrn = &
878 "('WARNING: EXIT_SOLVE_TOLERANCE is set to ',g10.3,' &
879 &which is much greater than the default value of ',g10.3,'. &
880 &The tolerance that strikes the best balance between accuracy &
881 &and runtime is problem-dependent. Since the variable being &
882 &solved varies from 0 to 1, tolerance values much less than 1 &
883 &typically give the best results.')"
884
885 ! source base class options
886 call this%BndExtType%source_options()
887
888 ! update defaults from input context
889 call mem_set_value(this%stoptime, 'STOPTIME', this%input_mempath, &
890 found%stoptime)
891 call mem_set_value(this%stoptraveltime, 'STOPTRAVELTIME', &
892 this%input_mempath, found%stoptraveltime)
893 call mem_set_value(this%istopweaksink, 'ISTOPWEAKSINK', this%input_mempath, &
894 found%istopweaksink)
895 call mem_set_value(this%istopzone, 'ISTOPZONE', this%input_mempath, &
896 found%istopzone)
897 call mem_set_value(this%drape, 'DRAPE', this%input_mempath, &
898 found%drape)
899 call mem_set_value(this%idrymeth, 'IDRYMETH', this%input_mempath, &
900 drytrack_method, found%idrymeth)
901 call mem_set_value(trackfile, 'TRACKFILE', this%input_mempath, &
902 found%trackfile)
903 call mem_set_value(trackcsvfile, 'TRACKCSVFILE', this%input_mempath, &
904 found%trackcsvfile)
905 call mem_set_value(this%localz, 'LOCALZ', this%input_mempath, &
906 found%localz)
907 call mem_set_value(this%extend, 'EXTEND', this%input_mempath, &
908 found%extend)
909 call mem_set_value(this%extol, 'EXTOL', this%input_mempath, &
910 found%extol)
911 call mem_set_value(this%rttol, 'RTTOL', this%input_mempath, &
912 found%rttol)
913 call mem_set_value(this%rtfreq, 'RTFREQ', this%input_mempath, &
914 found%rtfreq)
915 call mem_set_value(this%frctrn, 'FRCTRN', this%input_mempath, &
916 found%frctrn)
917 call mem_set_value(this%iexmeth, 'IEXMETH', this%input_mempath, &
918 found%iexmeth)
919 call mem_set_value(this%ichkmeth, 'ICHKMETH', this%input_mempath, &
920 coorcheck_method, found%ichkmeth)
921 call mem_set_value(this%icycwin, 'ICYCWIN', this%input_mempath, found%icycwin)
922
923 ! update internal state and validate input
924 if (found%idrymeth) then
925 if (this%idrymeth == 0) then
926 write (errmsg, '(a)') 'Unsupported dry tracking method. &
927 &DRY_TRACKING_METHOD must be "DROP", "STOP", or "STAY"'
928 call store_error(errmsg)
929 else
930 ! adjust for method zero indexing
931 this%idrymeth = this%idrymeth - 1
932 end if
933 end if
934
935 if (found%extol) then
936 if (this%extol <= dzero) &
937 call store_error('EXIT_SOLVE_TOLERANCE MUST BE POSITIVE')
938 if (this%extol > dem2) then
939 write (warnmsg, fmt=fmtextolwrn) &
942 end if
943 end if
944
945 if (found%rttol) then
946 if (this%rttol <= dzero) &
947 call store_error('RELEASE_TIME_TOLERANCE MUST BE POSITIVE')
948 end if
949
950 if (found%rtfreq) then
951 if (this%rtfreq <= dzero) &
952 call store_error('RELEASE_TIME_FREQUENCY MUST BE POSITIVE')
953 end if
954
955 if (found%iexmeth) then
956 if (.not. (this%iexmeth /= 1 .or. this%iexmeth /= 2)) &
957 call store_error('DEV_EXIT_SOLVE_METHOD MUST BE &
958 &1 (BRENT) OR 2 (CHANDRUPATLA)')
959 end if
960
961 if (found%ichkmeth) then
962 if (this%ichkmeth == 0) then
963 write (errmsg, '(a)') 'Unsupported coordinate check method. &
964 &COORDINATE_CHECK_METHOD must be "NONE" or "EAGER"'
965 call store_error(errmsg)
966 else
967 ! adjust for method zero based indexing
968 this%ichkmeth = this%ichkmeth - 1
969 end if
970 end if
971
972 if (found%icycwin) then
973 if (this%icycwin < 0) &
974 call store_error('CYCLE_DETECTION_WINDOW MUST BE NON-NEGATIVE')
975 end if
976
977 ! fileout options
978 if (found%trackfile) then
979 this%itrkout = getunit()
980 call openfile(this%itrkout, this%iout, trackfile, 'DATA(BINARY)', &
981 form, access, filstat_opt='REPLACE', &
982 mode_opt=mnormal)
983 ! open and write ascii header spec file
984 this%itrkhdr = getunit()
985 fname = trim(trackfile)//'.hdr'
986 call openfile(this%itrkhdr, this%iout, fname, 'CSV', &
987 filstat_opt='REPLACE', mode_opt=mnormal)
988 write (this%itrkhdr, '(a,/,a)') trackheader, trackdtypes
989 end if
990
991 if (found%trackcsvfile) then
992 this%itrkcsv = getunit()
993 call openfile(this%itrkcsv, this%iout, trackcsvfile, 'CSV', &
994 filstat_opt='REPLACE')
995 write (this%itrkcsv, '(a)') trackheader
996 end if
997
998 ! terminate if any errors were detected
999 if (count_errors() > 0) then
1000 call store_error_filename(this%input_fname)
1001 end if
1002
1003 ! log found options
1004 call this%prp_log_options(found, trackfile, trackcsvfile)
1005
1006 ! Create release schedule now that we know
1007 ! the coincident release time tolerance
1008 this%schedule => create_release_schedule(tolerance=this%rttol)
1009 end subroutine prp_options
1010
1011 !> @ brief No-op options method override for exchange PRP.
1012 !! Just creates an empty release schedule.
1013 subroutine exg_prp_options(this)
1014 class(exgprtprptype), intent(inout) :: this
1015 this%schedule => create_release_schedule(tolerance=this%rttol)
1016 end subroutine exg_prp_options
1017
1018 !> @ brief Log options specific to PrtPrpType
1019 subroutine prp_log_options(this, found, trackfile, trackcsvfile)
1020 ! -- modules
1022 ! -- dummy variables
1023 class(prtprptype), intent(inout) :: this
1024 type(prtprpparamfoundtype), intent(in) :: found
1025 character(len=*), intent(in) :: trackfile
1026 character(len=*), intent(in) :: trackcsvfile
1027 ! -- local variables
1028 ! formats
1029 character(len=*), parameter :: fmttrkbin = &
1030 "(4x, 'PARTICLE TRACKS WILL BE SAVED TO BINARY FILE: ', a, /4x, &
1031 &'OPENED ON UNIT: ', I0)"
1032 character(len=*), parameter :: fmttrkcsv = &
1033 "(4x, 'PARTICLE TRACKS WILL BE SAVED TO CSV FILE: ', a, /4x, &
1034 &'OPENED ON UNIT: ', I0)"
1035
1036 write (this%iout, '(1x,a)') 'PROCESSING PARTICLE INPUT DIMENSIONS'
1037
1038 if (found%frctrn) then
1039 write (this%iout, '(4x,a)') &
1040 'IF DISV, TRACKING WILL USE THE TERNARY METHOD REGARDLESS OF CELL TYPE'
1041 end if
1042
1043 if (found%trackfile) then
1044 write (this%iout, fmttrkbin) trim(adjustl(trackfile)), this%itrkout
1045 end if
1046
1047 if (found%trackcsvfile) then
1048 write (this%iout, fmttrkcsv) trim(adjustl(trackcsvfile)), this%itrkcsv
1049 end if
1050
1051 write (this%iout, '(1x,a)') 'END OF PARTICLE INPUT DIMENSIONS'
1052 end subroutine prp_log_options
1053
1054 !> @ brief Set dimensions specific to PrtPrpType
1055 subroutine prp_dimensions(this)
1056 ! modules
1059 ! dummy variables
1060 class(prtprptype), intent(inout) :: this
1061 ! local variables
1062 type(prtprpparamfoundtype) :: found
1063
1064 call mem_set_value(this%nreleasepoints, 'NRELEASEPTS', this%input_mempath, &
1065 found%nreleasepts)
1066 call mem_set_value(this%nreleasetimes, 'NRELEASETIMES', this%input_mempath, &
1067 found%nreleasetimes)
1068
1069 write (this%iout, '(1x,a)') 'PROCESSING PARTICLE INPUT DIMENSIONS'
1070 write (this%iout, '(4x,a,i0)') 'NRELEASEPTS = ', this%nreleasepoints
1071 write (this%iout, '(4x,a,i0)') 'NRELEASETIMES = ', this%nreleasetimes
1072 write (this%iout, '(1x,a)') 'END OF PARTICLE INPUT DIMENSIONS'
1073
1074 ! set maxbound and nbound to nreleasepts
1075 this%maxbound = this%nreleasepoints
1076 this%nbound = this%nreleasepoints
1077
1078 call this%prp_allocate_arrays()
1079 call this%prp_packagedata()
1080 call this%prp_releasetimes()
1081 call this%prp_load_releasetimefrequency()
1082 end subroutine prp_dimensions
1083
1084 !> @ brief Dimensions method override for exchange PRP.
1085 !! Just set all dimensions to zero and allocate arrays.
1086 subroutine exg_prp_dimensions(this)
1087 class(exgprtprptype), intent(inout) :: this
1088
1089 this%nreleasepoints = 0
1090 this%nreleasetimes = 0
1091 this%maxbound = 0
1092 this%nbound = 0
1093
1094 call this%prp_allocate_arrays()
1095 end subroutine exg_prp_dimensions
1096
1097 !> @brief Load package data (release points).
1098 subroutine prp_packagedata(this)
1101 use geomutilmodule, only: get_node
1103 ! dummy
1104 class(prtprptype), intent(inout) :: this
1105 ! local
1106 integer(I4B), dimension(:), pointer, contiguous :: irptno
1107 integer(I4B), dimension(:, :), pointer, contiguous :: cellids
1108 real(DP), dimension(:), pointer, contiguous :: xrpts, yrpts, zrpts
1109 type(characterstringtype), dimension(:), pointer, &
1110 contiguous :: boundnames
1111 character(len=LENBOUNDNAME) :: bndName, bndNameTemp
1112 character(len=9) :: cno
1113 character(len=20) :: cellidstr
1114 integer(I4B), dimension(:), allocatable :: nboundchk
1115 integer(I4B), dimension(:), pointer :: cellid
1116 integer(I4B) :: n, noder, nodeu, rptno
1117
1118 ! set input context pointers
1119 call mem_setptr(irptno, 'IRPTNO', this%input_mempath)
1120 call mem_setptr(cellids, 'CELLID', this%input_mempath)
1121 call mem_setptr(xrpts, 'XRPT', this%input_mempath)
1122 call mem_setptr(yrpts, 'YRPT', this%input_mempath)
1123 call mem_setptr(zrpts, 'ZRPT', this%input_mempath)
1124 call mem_setptr(boundnames, 'BOUNDNAME', this%input_mempath)
1125
1126 ! allocate and initialize temporary variables
1127 allocate (nboundchk(this%nreleasepoints))
1128 do n = 1, this%nreleasepoints
1129 nboundchk(n) = 0
1130 end do
1131
1132 write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%packName)) &
1133 //' PACKAGEDATA'
1134
1135 do n = 1, size(irptno)
1136
1137 rptno = irptno(n)
1138
1139 if (rptno < 1 .or. rptno > this%nreleasepoints) then
1140 write (errmsg, '(a,i0,a,i0,a)') &
1141 'Expected ', this%nreleasepoints, ' release points. &
1142 &Points must be numbered from 1 to ', this%nreleasepoints, '.'
1143 call store_error(errmsg)
1144 cycle
1145 end if
1146
1147 ! increment nboundchk
1148 nboundchk(rptno) = nboundchk(rptno) + 1
1149
1150 ! set cellid
1151 cellid => cellids(:, n)
1152
1153 ! set node user
1154 if (this%dis%ndim == 1) then
1155 nodeu = cellid(1)
1156 elseif (this%dis%ndim == 2) then
1157 nodeu = get_node(cellid(1), 1, cellid(2), &
1158 this%dis%mshape(1), 1, &
1159 this%dis%mshape(2))
1160 else
1161 nodeu = get_node(cellid(1), cellid(2), cellid(3), &
1162 this%dis%mshape(1), &
1163 this%dis%mshape(2), &
1164 this%dis%mshape(3))
1165 end if
1166
1167 ! set noder
1168 noder = this%dis%get_nodenumber(nodeu, 1)
1169 if (noder <= 0) then
1170 call this%dis%nodeu_to_string(nodeu, cellidstr)
1171 write (errmsg, '(a)') &
1172 'Particle release point configured for nonexistent cell: '// &
1173 trim(adjustl(cellidstr))//'. This cell has IDOMAIN <= 0 and '&
1174 &'therefore does not exist in the model grid.'
1175 call store_error(errmsg)
1176 cycle
1177 else
1178 this%rptnode(rptno) = noder
1179 end if
1180
1181 if (this%localz .and. (zrpts(n) < 0 .or. zrpts(n) > 1)) then
1182 call store_error('Local z coordinate must fall in the interval [0, 1]')
1183 cycle
1184 end if
1185
1186 ! set coordinates
1187 this%rptx(rptno) = xrpts(n)
1188 this%rpty(rptno) = yrpts(n)
1189 this%rptz(rptno) = zrpts(n)
1190
1191 ! set default boundname
1192 write (cno, '(i9.9)') rptno
1193 bndname = 'PRP'//cno
1194
1195 ! read boundnames from file, if provided
1196 if (this%inamedbound /= 0) then
1197 bndnametemp = boundnames(n)
1198 if (bndnametemp /= '') bndname = bndnametemp
1199 else
1200 bndname = ''
1201 end if
1202
1203 ! set boundname
1204 this%rptname(rptno) = bndname
1205 end do
1206
1207 write (this%iout, '(1x,a)') &
1208 'END OF '//trim(adjustl(this%packName))//' PACKAGEDATA'
1209
1210 ! check for duplicate or missing particle release points
1211 do n = 1, this%nreleasepoints
1212 if (nboundchk(n) == 0) then
1213 write (errmsg, '(a,a,1x,i0,a)') 'No data specified for particle ', &
1214 'release point', n, '.'
1215 call store_error(errmsg)
1216 else if (nboundchk(n) > 1) then
1217 write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a)') &
1218 'Data for particle release point', n, 'specified', nboundchk(n), &
1219 'times.'
1220 call store_error(errmsg)
1221 end if
1222 end do
1223
1224 ! terminate if any errors were detected
1225 if (count_errors() > 0) then
1226 call store_error_filename(this%input_fname)
1227 end if
1228
1229 ! cleanup
1230 deallocate (nboundchk)
1231
1232 call memorystore_release('IRPTNO', this%input_mempath)
1233 call memorystore_release('CELLID', this%input_mempath)
1234 call memorystore_release('XRPT', this%input_mempath)
1235 call memorystore_release('YRPT', this%input_mempath)
1236 call memorystore_release('ZRPT', this%input_mempath)
1237 call memorystore_release('BOUNDNAME', this%input_mempath)
1238 end subroutine prp_packagedata
1239
1240 !> @brief Load explicitly specified release times.
1241 subroutine prp_releasetimes(this)
1243 ! dummy
1244 class(prtprptype), intent(inout) :: this
1245 ! local
1246 real(DP), dimension(:), pointer, contiguous :: time
1247 integer(I4B) :: n, isize
1248 real(DP), allocatable :: times(:)
1249
1250 if (this%nreleasetimes <= 0) return
1251
1252 ! allocate times array
1253 allocate (times(this%nreleasetimes))
1254
1255 ! check if input array was read
1256 call get_isize('TIME', this%input_mempath, isize)
1257
1258 if (isize <= 0) then
1259 errmsg = "RELEASTIMES block expected when &
1260 &NRELEASETIMES dimension is non-zero."
1261 call store_error(errmsg)
1262 call store_error_filename(this%input_fname)
1263 end if
1264
1265 ! set input context pointer
1266 call mem_setptr(time, 'TIME', this%input_mempath)
1267
1268 ! set input data
1269 do n = 1, size(time)
1270 times(n) = time(n)
1271 end do
1272
1273 ! register times with the release schedule
1274 call this%schedule%time_select%extend(times)
1275
1276 ! make sure times strictly increase
1277 if (.not. this%schedule%time_select%increasing()) then
1278 errmsg = "RELEASTIMES block entries must strictly increase."
1279 call store_error(errmsg)
1280 call store_error_filename(this%input_fname)
1281 end if
1282
1283 ! deallocate
1284 deallocate (times)
1285 end subroutine prp_releasetimes
1286
1287 !> @brief Load regularly spaced release times if configured.
1289 ! modules
1290 use tdismodule, only: totalsimtime
1291 ! dummy
1292 class(prtprptype), intent(inout) :: this
1293 ! local
1294 real(DP), allocatable :: times(:)
1295
1296 ! check if a release time frequency is configured
1297 if (this%rtfreq <= dzero) return
1298
1299 ! create array of regularly-spaced release times
1300 times = arange( &
1301 start=dzero, &
1302 stop=totalsimtime, &
1303 step=this%rtfreq)
1304
1305 ! register times with release schedule
1306 call this%schedule%time_select%extend(times)
1307
1308 ! make sure times strictly increase
1309 if (.not. this%schedule%time_select%increasing()) then
1310 errmsg = "Release times must strictly increase"
1311 call store_error(errmsg)
1312 call store_error_filename(this%input_fname)
1313 end if
1314
1315 ! deallocate
1316 deallocate (times)
1317
1318 end subroutine prp_load_releasetimefrequency
1319
1320end module prtprpmodule
This module contains the extended boundary package.
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_model_flows(this, icbcfl, ibudfl, icbcun, imap)
@ brief Output package flow terms.
subroutine bnd_da(this)
@ brief Deallocate package memory
subroutine bnd_bd(this, model_budget)
@ brief Add package flows to model budget.
subroutine bnd_cq_simrate(this, hnew, flowja, imover)
@ brief Calculate simrate.
subroutine bnd_df_obs(this)
Define the observation types available in the package.
subroutine bnd_ad(this)
@ brief Advance the boundary package
subroutine define_listlabel(this)
@ brief Define the list label for the package
This module contains the BudgetModule.
Definition Budget.f90:20
This module contains simulation constants.
Definition Constants.f90:9
real(dp), parameter dsame
real constant for values that are considered the same based on machine precision
integer(i4b), parameter linelength
maximum length of a standard line
Definition Constants.f90:45
@ tabcenter
centered table column
@ tableft
left justified table column
@ mnormal
normal output mode
real(dp), parameter dep3
real constant 1000
Definition Constants.f90:88
real(dp), parameter dem7
real constant 1e-7
integer(i4b), parameter lenpakloc
maximum length of a package location
Definition Constants.f90:50
@ dis
DIS6 discretization.
real(dp), parameter dem1
real constant 1e-1
real(dp), parameter dep9
real constant 1e9
Definition Constants.f90:90
integer(i4b), parameter lenvarname
maximum length of a variable name
Definition Constants.f90:17
integer(i4b), parameter lenftype
maximum length of a package type (DIS, WEL, OC, etc.)
Definition Constants.f90:39
integer(i4b), parameter lenboundname
maximum length of a bound name
Definition Constants.f90:36
real(dp), parameter dzero
real constant zero
Definition Constants.f90:65
real(dp), parameter dem5
real constant 1e-5
real(dp), parameter dem2
real constant 1e-2
real(dp), parameter done
real constant 1
Definition Constants.f90:76
subroutine source_dimensions(this)
Copy dimensions from IDM into package.
Definition Dis.f90:246
subroutine source_options(this)
Copy options from IDM into package.
Definition Dis.f90:186
subroutine pstop(status, message)
Stop the program, optionally specifying an error status code.
Definition ErrorUtil.f90:24
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
logical function, public point_in_polygon(x, y, poly, tol)
Check if a point is within a polygon.
Definition GeomUtil.f90:31
subroutine, public get_ijk(nodenumber, nrow, ncol, nlay, irow, icol, ilay)
Get row, column and layer indices from node number and grid dimensions. If nodenumber is invalid,...
Definition GeomUtil.f90:109
subroutine, public get_jk(nodenumber, ncpl, nlay, icpl, ilay)
Get layer index and within-layer node index from node number and grid dimensions. If nodenumber is in...
Definition GeomUtil.f90:137
integer(i4b) function, public getunit()
Get a free unit number.
subroutine, public openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, filstat_opt, mode_opt)
Open a file.
This module defines variable data types.
Definition kind.f90:8
pure real(dp) function, dimension(:), allocatable, public arange(start, stop, step)
Return reals separated by the given step over the given interval.
Definition MathUtil.f90:384
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
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
Particle tracking strategies.
Definition Method.f90:2
@ level_subfeature
Definition Method.f90:41
subroutine terminate(this, particle, status)
A particle terminates.
Definition Method.f90:222
This module contains the derived type ObsType.
Definition Obs.f90:127
subroutine, public defaultobsidprocessor(obsrv, dis, inunitobs, iout)
@ brief Process IDstring provided for each observation
Definition Obs.f90:246
character(len=20) access
Definition OpenSpec.f90:7
character(len=20) form
Definition OpenSpec.f90:7
subroutine create_particle_store(store, np, mempath)
Allocate particle store.
Definition Particle.f90:160
@ term_unreleased
terminated permanently unreleased
Definition Particle.f90:38
subroutine create_particle(particle)
Create a new particle.
Definition Particle.f90:153
Particle release scheduling.
subroutine schedule(this, trelease)
Add a release time to the schedule.
type(particlereleasescheduletype) function, pointer, public create_release_schedule(tolerance)
Create a new release schedule.
Particle track output module.
character(len= *), parameter, public trackheader
character(len= *), parameter, public trackdtypes
character(len=lenpackagename) text
Definition prt-fmi.f90:19
subroutine exg_prp_allocate_arrays(this, nodelist, auxvar)
Allocate arrays for exchange PRP.
Definition prt-prp.f90:397
subroutine exg_prp_ar(this)
@ brief No-op AR method override for exchange PRP.
Definition prt-prp.f90:419
subroutine prp_allocate_arrays(this, nodelist, auxvar)
Allocate arrays.
Definition prt-prp.f90:257
subroutine exg_prp_cq_simrate(this, hnew, flowja, imover)
No-op flow calculation for exchange PRP.
Definition prt-prp.f90:523
subroutine prp_rp(this)
@ brief Read and prepare period data for particle input
Definition prt-prp.f90:750
subroutine exg_prp_rp(this)
@ brief No-op RP method override for exchange PRP.
Definition prt-prp.f90:796
subroutine prp_load_releasetimefrequency(this)
Load regularly spaced release times if configured.
Definition prt-prp.f90:1289
subroutine prp_cq_simrate(this, hnew, flowja, imover)
@ brief Calculate flow between package and model.
Definition prt-prp.f90:801
subroutine exg_prp_allocate_scalars(this)
Allocate scalars for exchange PRP.
Definition prt-prp.f90:374
subroutine exg_prp_ad(this)
No-op AD method override for exchange PRP.
Definition prt-prp.f90:515
character(len=lenftype) ftype
Definition prt-prp.f90:34
subroutine exg_prp_bd(this, model_budget)
No-op budget method for exchange PRP. Likewise about the STORAGE term accounting.
Definition prt-prp.f90:532
subroutine prp_df_obs(this)
Store supported observations.
Definition prt-prp.f90:847
real(dp), parameter default_exit_solve_tolerance
Definition prt-prp.f90:36
subroutine log_release(this)
Log the release scheduled for this time step.
Definition prt-prp.f90:549
subroutine exg_prp_options(this)
@ brief No-op options method override for exchange PRP. Just creates an empty release schedule.
Definition prt-prp.f90:1014
subroutine prp_ad(this)
Advance a time step and release particles if scheduled.
Definition prt-prp.f90:424
subroutine prp_allocate_scalars(this)
Allocate scalars.
Definition prt-prp.f90:293
subroutine prp_dimensions(this)
@ brief Set dimensions specific to PrtPrpType
Definition prt-prp.f90:1056
subroutine exg_prp_dimensions(this)
@ brief Dimensions method override for exchange PRP. Just set all dimensions to zero and allocate arr...
Definition prt-prp.f90:1087
subroutine prp_set_pointers(this, ibound, izone)
@ brief Set pointers to model variables
Definition prt-prp.f90:247
subroutine exg_prp_ot_model_flows(this, icbcfl, ibudfl, icbcun, imap)
No-op flow output method for exchange PRP. No contribution to budget, no need to write output.
Definition prt-prp.f90:540
subroutine initialize_particle(this, particle, ip, trelease)
Definition prt-prp.f90:635
subroutine prp_da(this)
Deallocate memory.
Definition prt-prp.f90:195
subroutine prp_releasetimes(this)
Load explicitly specified release times.
Definition prt-prp.f90:1242
subroutine prp_commit(this)
Commit staged particle state to the "final" store.
Definition prt-prp.f90:506
subroutine prp_options(this)
@ brief Set options specific to PrtPrpType
Definition prt-prp.f90:862
subroutine prp_log_options(this, found, trackfile, trackcsvfile)
@ brief Log options specific to PrtPrpType
Definition prt-prp.f90:1020
logical function prp_obs_supported(this)
Indicates whether observations are supported.
Definition prt-prp.f90:841
subroutine prp_ar(this)
@ brief Allocate and read period data
Definition prt-prp.f90:353
subroutine release(this, ip, trelease)
Release a particle at the specified time.
Definition prt-prp.f90:617
subroutine, public prp_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, fmi, input_mempath)
Create a new particle release point package.
Definition prt-prp.f90:129
subroutine validate_release_point(this, ic, x, y, z)
Verify that the release point is in the cell.
Definition prt-prp.f90:564
subroutine prp_packagedata(this)
Load package data (release points).
Definition prt-prp.f90:1099
This module contains simulation methods.
Definition Sim.f90:10
subroutine, public store_warning(msg, substring)
Store warning message.
Definition Sim.f90:237
subroutine, public store_error(msg, terminate)
Store an error message.
Definition Sim.f90:92
integer(i4b) function, public count_errors()
Return number of errors.
Definition Sim.f90:59
subroutine, public store_error_filename(filename, terminate)
Store the erroring file name.
Definition Sim.f90:204
This module contains simulation variables.
character(len=maxcharlen) errmsg
error message string
character(len=maxcharlen) warnmsg
warning message string
integer(i4b) iout
file unit number for simulation output
real(dp), pointer, public totalsimtime
time at end of simulation
Definition tdis.f90:40
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
integer(i4b), pointer, public nper
number of stress period
Definition tdis.f90:24
Derived type for the Budget object.
Definition Budget.f90:40
This class is used to store a single deferred-length character string. It was designed to work in an ...
Structured grid discretization.
Definition Dis.f90:23
Vertex grid discretization.
Definition Disv.f90:25
Structure of arrays to store particles.
Definition Particle.f90:111
Particle tracked by the PRT model.
Definition Particle.f90:64
Particle track output manager. Handles printing as well as writing to files. One output unit can be c...
Exchange PRP package. A variant of the normal PRP package that doesn't read from input files but inst...
Definition prt-prp.f90:107
Particle release point (PRP) package.
Definition prt-prp.f90:39