MODFLOW 6  version 6.7.0.dev1
USGS Modular Hydrologic Model
prtprpmodule Module Reference

Data Types

type  prtprptype
 Particle release point (PRP) package. More...
 

Functions/Subroutines

subroutine, public prp_create (packobj, id, ibcnum, inunit, iout, namemodel, pakname, fmi)
 Create a new particle release point package. More...
 
subroutine prp_da (this)
 Deallocate memory. More...
 
subroutine prp_set_pointers (this, ibound, izone, trackctl)
 @ brief Set pointers to model variables More...
 
subroutine prp_allocate_arrays (this, nodelist, auxvar)
 Allocate arrays. More...
 
subroutine prp_allocate_scalars (this)
 Allocate scalars. More...
 
subroutine prp_ar (this)
 @ brief Allocate and read period data More...
 
subroutine prp_ad (this)
 Advance a time step and release particles if scheduled. More...
 
subroutine log_release (this)
 Log the release scheduled for this time step. More...
 
subroutine validate_release_point (this, ic, x, y, z)
 Verify that the release point is in the cell. More...
 
subroutine release (this, ip, trelease)
 Release a particle at the specified time. More...
 
subroutine initialize_particle (this, particle, ip, trelease)
 
subroutine prp_rp (this)
 @ brief Read and prepare period data for particle input More...
 
subroutine prp_cq_simrate (this, hnew, flowja, imover)
 @ brief Calculate flow between package and model. More...
 
subroutine define_listlabel (this)
 
logical function prp_obs_supported (this)
 Indicates whether observations are supported. More...
 
subroutine prp_df_obs (this)
 Store supported observations. More...
 
subroutine prp_options (this, option, found)
 Set options specific to PrtPrpType. More...
 
subroutine prp_read_dimensions (this)
 Read package dimensions. More...
 
subroutine prp_read_packagedata (this)
 Load package data (release points). More...
 
subroutine prp_read_releasetimes (this)
 Load explicitly specified release times. More...
 
subroutine prp_load_releasetimefrequency (this)
 Load regularly spaced release times if configured. More...
 

Variables

character(len=lenftype) ftype = 'PRP'
 
character(len=16) text = ' PRP'
 

Function/Subroutine Documentation

◆ define_listlabel()

subroutine prtprpmodule::define_listlabel ( class(prtprptype), intent(inout)  this)

Definition at line 666 of file prt-prp.f90.

667  class(PrtPrpType), intent(inout) :: this
668  ! not implemented, not used

◆ initialize_particle()

subroutine prtprpmodule::initialize_particle ( class(prtprptype), intent(inout)  this,
type(particletype), intent(inout), pointer  particle,
integer(i4b), intent(in)  ip,
real(dp), intent(in)  trelease 
)
private
Parameters
[in,out]thisthis instance
[in,out]particlethe particle
[in]ipparticle index
[in]treleaserelease time

Definition at line 447 of file prt-prp.f90.

449  class(PrtPrpType), intent(inout) :: this !< this instance
450  type(ParticleType), pointer, intent(inout) :: particle !< the particle
451  integer(I4B), intent(in) :: ip !< particle index
452  real(DP), intent(in) :: trelease !< release time
453  ! local
454  integer(I4B) :: irow, icol, ilay, icpl
455  integer(I4B) :: ic, icu, ic_old
456  real(DP) :: x, y, z
457  real(DP) :: top, bot, hds
458 
459  ic = this%rptnode(ip)
460  icu = this%dis%get_nodeuser(ic)
461 
462  call create_particle(particle)
463 
464  if (size(this%boundname) /= 0) then
465  particle%name = this%boundname(ip)
466  else
467  particle%name = ''
468  end if
469 
470  particle%irpt = ip
471  particle%istopweaksink = this%istopweaksink
472  particle%istopzone = this%istopzone
473  particle%idrymeth = this%idrymeth
474  particle%icu = icu
475 
476  select type (dis => this%dis)
477  type is (distype)
478  call get_ijk(icu, dis%nrow, dis%ncol, dis%nlay, irow, icol, ilay)
479  type is (disvtype)
480  call get_jk(icu, dis%ncpl, dis%nlay, icpl, ilay)
481  end select
482  particle%ilay = ilay
483  particle%izone = this%rptzone(ic)
484  particle%istatus = 0 ! status 0 until tracking starts
485  ! If the cell is inactive, either drape the particle
486  ! to the top-most active cell beneath it if drape is
487  ! enabled, or else terminate permanently unreleased.
488  if (this%ibound(ic) == 0) then
489  ic_old = ic
490  if (this%idrape > 0) then
491  call this%dis%highest_active(ic, this%ibound)
492  if (ic == ic_old .or. this%ibound(ic) == 0) then
493  ! negative unreleased status signals to the
494  ! tracking method that we haven't yet saved
495  ! a termination record, it needs to do so.
496  particle%istatus = -1 * term_unreleased
497  end if
498  else
499  particle%istatus = -1 * term_unreleased
500  end if
501  end if
502 
503  ! Load coordinates and transform if needed
504  x = this%rptx(ip)
505  y = this%rpty(ip)
506  if (this%ilocalz > 0) then
507  top = this%fmi%dis%top(ic)
508  bot = this%fmi%dis%bot(ic)
509  hds = this%fmi%gwfhead(ic)
510  z = bot + this%rptz(ip) * (hds - bot)
511  else
512  z = this%rptz(ip)
513  end if
514 
515  call this%validate_release_point(ic, x, y, z)
516 
517  particle%x = x
518  particle%y = y
519  particle%z = z
520  particle%trelease = trelease
521 
522  ! Set stop time to earlier of STOPTIME and STOPTRAVELTIME
523  if (this%stoptraveltime == huge(1d0)) then
524  particle%tstop = this%stoptime
525  else
526  particle%tstop = particle%trelease + this%stoptraveltime
527  if (this%stoptime < particle%tstop) particle%tstop = this%stoptime
528  end if
529 
530  particle%ttrack = particle%trelease
531  particle%idomain(1) = 0
532  particle%iboundary(1) = 0
533  particle%idomain(2) = ic
534  particle%iboundary(2) = 0
535  particle%idomain(3) = 0
536  particle%iboundary(3) = 0
537  particle%ifrctrn = this%ifrctrn
538  particle%iexmeth = this%iexmeth
539  particle%iextend = this%iextend
540  particle%extol = this%extol
@ term_unreleased
terminated permanently unreleased
Definition: Particle.f90:38
Here is the call graph for this function:

◆ log_release()

subroutine prtprpmodule::log_release ( class(prtprptype), intent(inout)  this)
Parameters
[in,out]thisprp

Definition at line 371 of file prt-prp.f90.

372  class(PrtPrpType), intent(inout) :: this !< prp
373  if (this%iprpak > 0) then
374  write (this%iout, "(1x,/1x,a,1x,i0)") &
375  'PARTICLE RELEASE FOR PRP', this%ibcnum
376  call this%schedule%log(this%iout)
377  end if

◆ prp_ad()

subroutine prtprpmodule::prp_ad ( class(prtprptype this)
private

Definition at line 310 of file prt-prp.f90.

311  use tdismodule, only: totalsimtime
312  class(PrtPrpType) :: this
313  integer(I4B) :: ip, it
314  real(DP) :: t
315 
316  ! Notes
317  ! -----
318  ! Each release point can be thought of as
319  ! a gumball machine with infinite supply:
320  ! a point can release an arbitrary number
321  ! of particles, but only one at any time.
322  ! Coincident release times are merged to
323  ! a single time by the release scheduler.
324 
325  ! Reset mass accumulators for this time step.
326  do ip = 1, this%nreleasepoints
327  this%rptm(ip) = dzero
328  end do
329 
330  ! Advance the release schedule and check if
331  ! any releases will be made this time step.
332  call this%schedule%advance()
333  if (.not. this%schedule%any()) return
334 
335  ! Log the schedule to the list file.
336  call this%log_release()
337 
338  ! Expand the particle store. We know from the
339  ! schedule how many particles will be released.
340  call this%particles%resize( &
341  this%particles%num_stored() + &
342  (this%nreleasepoints * this%schedule%count()), &
343  this%memoryPath)
344 
345  ! Release a particle from each point for
346  ! each release time in the current step.
347  do ip = 1, this%nreleasepoints
348  do it = 1, this%schedule%count()
349  t = this%schedule%times(it)
350  ! Skip the release time if it's before the simulation
351  ! starts, or if no `extend_tracking`, after it ends.
352  if (t < dzero) then
353  write (warnmsg, '(a,g0,a)') &
354  'Skipping negative release time (t=', t, ').'
355  call store_warning(warnmsg)
356  cycle
357  else if (t > totalsimtime .and. this%iextend == 0) then
358  write (warnmsg, '(a,g0,a)') &
359  'Skipping release time falling after the end of the &
360  &simulation (t=', t, '). Enable EXTEND_TRACKING to &
361  &release particles after the simulation end time.'
362  call store_warning(warnmsg)
363  cycle
364  end if
365  call this%release(ip, t)
366  end do
367  end do
real(dp), pointer, public totalsimtime
time at end of simulation
Definition: tdis.f90:37
Here is the call graph for this function:

◆ prp_allocate_arrays()

subroutine prtprpmodule::prp_allocate_arrays ( class(prtprptype this,
integer(i4b), dimension(:), optional, pointer, contiguous  nodelist,
real(dp), dimension(:, :), optional, pointer, contiguous  auxvar 
)
private

Definition at line 204 of file prt-prp.f90.

205  ! dummy
206  class(PrtPrpType) :: this
207  integer(I4B), dimension(:), pointer, contiguous, optional :: nodelist
208  real(DP), dimension(:, :), pointer, contiguous, optional :: auxvar
209  ! local
210  integer(I4B) :: nps
211 
212  ! Allocate particle store, starting with the number
213  ! of release points (arrays resized if/when needed)
214  call create_particle_store( &
215  this%particles, &
216  this%nreleasepoints, &
217  this%memoryPath)
218 
219  ! Allocate arrays
220  call mem_allocate(this%rptx, this%nreleasepoints, 'RPTX', this%memoryPath)
221  call mem_allocate(this%rpty, this%nreleasepoints, 'RPTY', this%memoryPath)
222  call mem_allocate(this%rptz, this%nreleasepoints, 'RPTZ', this%memoryPath)
223  call mem_allocate(this%rptm, this%nreleasepoints, 'RPTMASS', this%memoryPath)
224  call mem_allocate(this%rptnode, this%nreleasepoints, 'RPTNODER', &
225  this%memoryPath)
226  call mem_allocate(this%rptname, lenboundname, this%nreleasepoints, &
227  'RPTNAME', this%memoryPath)
228 
229  ! Initialize arrays
230  do nps = 1, this%nreleasepoints
231  this%rptm(nps) = dzero
232  end do
Here is the call graph for this function:

◆ prp_allocate_scalars()

subroutine prtprpmodule::prp_allocate_scalars ( class(prtprptype this)
private

Definition at line 236 of file prt-prp.f90.

237  class(PrtPrpType) :: this
238 
239  ! Allocate parent's scalars
240  call this%BndType%allocate_scalars()
241 
242  ! Allocate scalars for this type
243  call mem_allocate(this%ilocalz, 'ILOCALZ', this%memoryPath)
244  call mem_allocate(this%iextend, 'IEXTEND', this%memoryPath)
245  call mem_allocate(this%offset, 'OFFSET', this%memoryPath)
246  call mem_allocate(this%stoptime, 'STOPTIME', this%memoryPath)
247  call mem_allocate(this%stoptraveltime, 'STOPTRAVELTIME', this%memoryPath)
248  call mem_allocate(this%istopweaksink, 'ISTOPWEAKSINK', this%memoryPath)
249  call mem_allocate(this%istopzone, 'ISTOPZONE', this%memoryPath)
250  call mem_allocate(this%idrape, 'IDRAPE', this%memoryPath)
251  call mem_allocate(this%idrymeth, 'IDRYMETH', this%memoryPath)
252  call mem_allocate(this%nreleasepoints, 'NRELEASEPOINTS', this%memoryPath)
253  call mem_allocate(this%nreleasetimes, 'NRELEASETIMES', this%memoryPath)
254  call mem_allocate(this%nparticles, 'NPARTICLES', this%memoryPath)
255  call mem_allocate(this%itrkout, 'ITRKOUT', this%memoryPath)
256  call mem_allocate(this%itrkhdr, 'ITRKHDR', this%memoryPath)
257  call mem_allocate(this%itrkcsv, 'ITRKCSV', this%memoryPath)
258  call mem_allocate(this%irlstls, 'IRLSTLS', this%memoryPath)
259  call mem_allocate(this%ifrctrn, 'IFRCTRN', this%memoryPath)
260  call mem_allocate(this%iexmeth, 'IEXMETH', this%memoryPath)
261  call mem_allocate(this%extol, 'EXTOL', this%memoryPath)
262  call mem_allocate(this%rttol, 'RTTOL', this%memoryPath)
263  call mem_allocate(this%rtfreq, 'RTFREQ', this%memoryPath)
264 
265  ! Set values
266  this%ilocalz = 0
267  this%iextend = 0
268  this%offset = dzero
269  this%stoptime = huge(1d0)
270  this%stoptraveltime = huge(1d0)
271  this%istopweaksink = 0
272  this%istopzone = 0
273  this%idrape = 0
274  this%idrymeth = 0
275  this%nreleasepoints = 0
276  this%nreleasetimes = 0
277  this%nparticles = 0
278  this%itrkout = 0
279  this%itrkhdr = 0
280  this%itrkcsv = 0
281  this%irlstls = 0
282  this%ifrctrn = 0
283  this%iexmeth = 0
284  this%extol = dem5
285  this%rttol = dsame * dep9
286  this%rtfreq = dzero
287 

◆ prp_ar()

subroutine prtprpmodule::prp_ar ( class(prtprptype), intent(inout)  this)
private

Definition at line 291 of file prt-prp.f90.

292  ! dummy variables
293  class(PrtPrpType), intent(inout) :: this
294  ! local variables
295  integer(I4B) :: n
296 
297  call this%obs%obs_ar()
298  call this%BndType%allocate_arrays()
299  if (this%inamedbound /= 0) then
300  do n = 1, this%nreleasepoints
301  this%boundname(n) = this%rptname(n)
302  end do
303  end if
304  do n = 1, this%nreleasepoints
305  this%nodelist(n) = this%rptnode(n)
306  end do

◆ prp_cq_simrate()

subroutine prtprpmodule::prp_cq_simrate ( class(prtprptype this,
real(dp), dimension(:), intent(in)  hnew,
real(dp), dimension(:), intent(inout)  flowja,
integer(i4b), intent(in)  imover 
)
Parameters
[in,out]flowjaflow between package and model
[in]imoverflag indicating if the mover package is active

Definition at line 632 of file prt-prp.f90.

633  ! modules
634  use tdismodule, only: delt
635  ! dummy variables
636  class(PrtPrpType) :: this
637  real(DP), dimension(:), intent(in) :: hnew
638  real(DP), dimension(:), intent(inout) :: flowja !< flow between package and model
639  integer(I4B), intent(in) :: imover !< flag indicating if the mover package is active
640  ! local variables
641  integer(I4B) :: i
642  integer(I4B) :: node
643  integer(I4B) :: idiag
644  real(DP) :: rrate
645 
646  ! If no boundaries, skip flow calculations.
647  if (this%nbound <= 0) return
648 
649  ! Loop through each boundary calculating flow.
650  do i = 1, this%nbound
651  node = this%nodelist(i)
652  rrate = dzero
653  ! If cell is no-flow or constant-head, then ignore it.
654  if (node > 0) then
655  ! Calculate the flow rate into the cell.
656  idiag = this%dis%con%ia(node)
657  rrate = this%rptm(i) * (done / delt) ! reciprocal of tstp length
658  flowja(idiag) = flowja(idiag) + rrate
659  end if
660 
661  ! Save simulated value to simvals array.
662  this%simvals(i) = rrate
663  end do
real(dp), pointer, public delt
length of the current time step
Definition: tdis.f90:29

◆ prp_create()

subroutine, public prtprpmodule::prp_create ( class(bndtype), pointer  packobj,
integer(i4b), intent(in)  id,
integer(i4b), intent(in)  ibcnum,
integer(i4b), intent(in)  inunit,
integer(i4b), intent(in)  iout,
character(len=*), intent(in)  namemodel,
character(len=*), intent(in)  pakname,
type(prtfmitype), pointer  fmi 
)

Definition at line 100 of file prt-prp.f90.

102  ! dummy
103  class(BndType), pointer :: packobj
104  integer(I4B), intent(in) :: id
105  integer(I4B), intent(in) :: ibcnum
106  integer(I4B), intent(in) :: inunit
107  integer(I4B), intent(in) :: iout
108  character(len=*), intent(in) :: namemodel
109  character(len=*), intent(in) :: pakname
110  type(PrtFmiType), pointer :: fmi
111  ! local
112  type(PrtPrpType), pointer :: prpobj
113  ! formats
114  character(len=*), parameter :: fmtheader = &
115  "(1x, /1x, 'PRP PARTICLE RELEASE POINT PACKAGE', &
116  &' INPUT READ FROM UNIT ', i0, /)"
117 
118  ! allocate the object and assign values to object variables
119  allocate (prpobj)
120  packobj => prpobj
121 
122  ! create name and memory path
123  call packobj%set_names(ibcnum, namemodel, pakname, ftype)
124  prpobj%text = text
125 
126  ! allocate scalars
127  call prpobj%prp_allocate_scalars()
128 
129  ! initialize package
130  call packobj%pack_initialize()
131 
132  packobj%inunit = inunit
133  packobj%iout = iout
134  packobj%id = id
135  packobj%ibcnum = ibcnum
136  packobj%ncolbnd = 4
137  packobj%iscloc = 1
138 
139  ! store pointer to flow model interface
140  prpobj%fmi => fmi
141 
142  ! if prp is enabled, print a message identifying it
143  if (inunit > 0) write (iout, fmtheader) inunit
Here is the caller graph for this function:

◆ prp_da()

subroutine prtprpmodule::prp_da ( class(prtprptype this)
private

Definition at line 147 of file prt-prp.f90.

148  class(PrtPrpType) :: this
149 
150  ! Deallocate parent
151  call this%BndType%bnd_da()
152 
153  ! Deallocate scalars
154  call mem_deallocate(this%ilocalz)
155  call mem_deallocate(this%iextend)
156  call mem_deallocate(this%offset)
157  call mem_deallocate(this%stoptime)
158  call mem_deallocate(this%stoptraveltime)
159  call mem_deallocate(this%istopweaksink)
160  call mem_deallocate(this%istopzone)
161  call mem_deallocate(this%idrape)
162  call mem_deallocate(this%idrymeth)
163  call mem_deallocate(this%nreleasepoints)
164  call mem_deallocate(this%nreleasetimes)
165  call mem_deallocate(this%nparticles)
166  call mem_deallocate(this%itrkout)
167  call mem_deallocate(this%itrkhdr)
168  call mem_deallocate(this%itrkcsv)
169  call mem_deallocate(this%irlstls)
170  call mem_deallocate(this%ifrctrn)
171  call mem_deallocate(this%iexmeth)
172  call mem_deallocate(this%extol)
173  call mem_deallocate(this%rttol)
174  call mem_deallocate(this%rtfreq)
175 
176  ! Deallocate arrays
177  call mem_deallocate(this%rptx)
178  call mem_deallocate(this%rpty)
179  call mem_deallocate(this%rptz)
180  call mem_deallocate(this%rptnode)
181  call mem_deallocate(this%rptm)
182  call mem_deallocate(this%rptname, 'RPTNAME', this%memoryPath)
183 
184  ! Deallocate objects
185  call this%particles%destroy(this%memoryPath)
186  call this%schedule%deallocate()
187  deallocate (this%particles)
188  deallocate (this%schedule)

◆ prp_df_obs()

subroutine prtprpmodule::prp_df_obs ( class(prtprptype this)
private

Definition at line 678 of file prt-prp.f90.

679  ! dummy
680  class(PrtPrpType) :: this
681  ! local
682  integer(I4B) :: indx
683  call this%obs%StoreObsType('prp', .true., indx)
684  this%obs%obsData(indx)%ProcessIdPtr => defaultobsidprocessor
685 
686  ! Store obs type and assign procedure pointer
687  ! for to-mvr observation type.
688  call this%obs%StoreObsType('to-mvr', .true., indx)
689  this%obs%obsData(indx)%ProcessIdPtr => defaultobsidprocessor
Here is the call graph for this function:

◆ prp_load_releasetimefrequency()

subroutine prtprpmodule::prp_load_releasetimefrequency ( class(prtprptype), intent(inout)  this)
private

Definition at line 1087 of file prt-prp.f90.

1088  ! modules
1089  use tdismodule, only: totalsimtime
1090  ! dummy
1091  class(PrtPrpType), intent(inout) :: this
1092  ! local
1093  real(DP), allocatable :: times(:)
1094 
1095  ! check if a release time frequency is configured
1096  if (this%rtfreq <= dzero) return
1097 
1098  ! create array of regularly-spaced release times
1099  times = arange( &
1100  start=dzero, &
1101  stop=totalsimtime, &
1102  step=this%rtfreq)
1103 
1104  ! register times with release schedule
1105  call this%schedule%time_select%extend(times)
1106 
1107  ! make sure times strictly increase
1108  if (.not. this%schedule%time_select%increasing()) then
1109  errmsg = "Release times must strictly increase"
1110  call store_error(errmsg)
1111  call this%parser%StoreErrorUnit(terminate=.true.)
1112  end if
1113 
1114  ! deallocate
1115  deallocate (times)
1116 
Here is the call graph for this function:

◆ prp_obs_supported()

logical function prtprpmodule::prp_obs_supported ( class(prtprptype this)
private

Definition at line 672 of file prt-prp.f90.

673  class(PrtPrpType) :: this
674  prp_obs_supported = .true.

◆ prp_options()

subroutine prtprpmodule::prp_options ( class(prtprptype), intent(inout)  this,
character(len=*), intent(inout)  option,
logical(lgp), intent(inout)  found 
)
private

Definition at line 693 of file prt-prp.f90.

694  use openspecmodule, only: access, form
695  use constantsmodule, only: maxcharlen, dzero
698  ! dummy
699  class(PrtPrpType), intent(inout) :: this
700  character(len=*), intent(inout) :: option
701  logical(LGP), intent(inout) :: found
702  ! locals
703  character(len=MAXCHARLEN) :: fname
704  character(len=MAXCHARLEN) :: keyword
705  ! formats
706  character(len=*), parameter :: fmttrkbin = &
707  "(4x, 'PARTICLE TRACKS WILL BE SAVED TO BINARY FILE: ', a, /4x, &
708  &'OPENED ON UNIT: ', I0)"
709  character(len=*), parameter :: fmttrkcsv = &
710  "(4x, 'PARTICLE TRACKS WILL BE SAVED TO CSV FILE: ', a, /4x, &
711  &'OPENED ON UNIT: ', I0)"
712 
713  select case (option)
714  case ('STOPTIME')
715  this%stoptime = this%parser%GetDouble()
716  found = .true.
717  case ('STOPTRAVELTIME')
718  this%stoptraveltime = this%parser%GetDouble()
719  found = .true.
720  case ('STOP_AT_WEAK_SINK')
721  this%istopweaksink = 1
722  found = .true.
723  case ('ISTOPZONE')
724  this%istopzone = this%parser%GetInteger()
725  found = .true.
726  case ('DRAPE')
727  this%idrape = 1
728  found = .true.
729  case ('DRY_TRACKING_METHOD')
730  call this%parser%GetStringCaps(keyword)
731  select case (keyword)
732  case ('DROP')
733  this%idrymeth = 0
734  case ('STOP')
735  this%idrymeth = 1
736  case ('STAY')
737  this%idrymeth = 2
738  case default
739  write (errmsg, '(a, a)') &
740  'Unknown dry tracking method: ', trim(keyword)
741  call store_error(errmsg)
742  write (errmsg, '(a, a)') &
743  'DRY must be "DROP", "STOP" or "STAY"'
744  call store_error(errmsg)
745  call this%parser%StoreErrorUnit()
746  end select
747  found = .true.
748  case ('TRACK')
749  call this%parser%GetStringCaps(keyword)
750  if (keyword == 'FILEOUT') then
751  ! parse filename
752  call this%parser%GetString(fname)
753  ! open binary output file
754  this%itrkout = getunit()
755  call openfile(this%itrkout, this%iout, fname, 'DATA(BINARY)', &
756  form, access, filstat_opt='REPLACE', &
757  mode_opt=mnormal)
758  write (this%iout, fmttrkbin) trim(adjustl(fname)), this%itrkout
759  ! open and write ascii header spec file
760  this%itrkhdr = getunit()
761  fname = trim(fname)//'.hdr'
762  call openfile(this%itrkhdr, this%iout, fname, 'CSV', &
763  filstat_opt='REPLACE', mode_opt=mnormal)
764  write (this%itrkhdr, '(a,/,a)') trackheader, trackdtypes
765  else
766  call store_error('OPTIONAL TRACK KEYWORD MUST BE '// &
767  'FOLLOWED BY FILEOUT')
768  end if
769  found = .true.
770  case ('TRACKCSV')
771  call this%parser%GetStringCaps(keyword)
772  if (keyword == 'FILEOUT') then
773  ! parse filename
774  call this%parser%GetString(fname)
775  ! open CSV output file and write headers
776  this%itrkcsv = getunit()
777  call openfile(this%itrkcsv, this%iout, fname, 'CSV', &
778  filstat_opt='REPLACE')
779  write (this%iout, fmttrkcsv) trim(adjustl(fname)), this%itrkcsv
780  write (this%itrkcsv, '(a)') trackheader
781  else
782  call store_error('OPTIONAL TRACKCSV KEYWORD MUST BE &
783  &FOLLOWED BY FILEOUT')
784  end if
785  found = .true.
786  case ('LOCAL_Z')
787  this%ilocalz = 1
788  found = .true.
789  case ('EXTEND_TRACKING')
790  this%iextend = 1
791  found = .true.
792  case ('EXIT_SOLVE_TOLERANCE')
793  this%extol = this%parser%GetDouble()
794  if (this%extol <= dzero) &
795  call store_error('EXIT_SOLVE_TOLERANCE MUST BE POSITIVE')
796  found = .true.
797  case ('RELEASE_TIME_TOLERANCE')
798  this%rttol = this%parser%GetDouble()
799  if (this%rttol <= dzero) &
800  call store_error('RELEASE_TIME_TOLERANCE MUST BE POSITIVE')
801  found = .true.
802  case ('RELEASE_TIME_FREQUENCY')
803  this%rtfreq = this%parser%GetDouble()
804  if (this%rtfreq <= dzero) &
805  call store_error('RELEASE_TIME_FREQUENCY MUST BE POSITIVE')
806  found = .true.
807  case ('DEV_FORCETERNARY')
808  call this%parser%DevOpt()
809  this%ifrctrn = 1
810  write (this%iout, '(4x,a)') &
811  'TRACKING WILL BE DONE USING THE TERNARY METHOD REGARDLESS OF CELL TYPE'
812  found = .true.
813  case ('DEV_EXIT_SOLVE_METHOD')
814  call this%parser%DevOpt()
815  this%iexmeth = this%parser%GetInteger()
816  if (.not. (this%iexmeth /= 1 .or. this%iexmeth /= 2)) &
817  call store_error('DEV_EXIT_SOLVE_METHOD MUST BE &
818  &1 (BRENT) OR 2 (CHANDRUPATLA)')
819  found = .true.
820  case default
821  found = .false.
822  end select
823 
824  ! Catch unrecognized options
825  if (.not. found) then
826  errmsg = "UNKNOWN PRP OPTION '"//trim(keyword)//"'."
827  call store_error(errmsg)
828  call this%parser%StoreErrorUnit()
829  end if
830 
831  ! Create release schedule now that we know
832  ! the coincident release time tolerance
833  this%schedule => create_release_schedule(tol=this%rttol)
834 
This module contains simulation constants.
Definition: Constants.f90:9
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
integer(i4b), parameter maxcharlen
maximum length of char string
Definition: Constants.f90:47
integer(i4b) function, public getunit()
Get a free unit number.
subroutine, public openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, filstat_opt, mode_opt)
Open a file.
Definition: InputOutput.f90:30
subroutine, public urword(line, icol, istart, istop, ncode, n, r, iout, in)
Extract a word from a string.
character(len=20) access
Definition: OpenSpec.f90:7
character(len=20) form
Definition: OpenSpec.f90:7
character(len= *), parameter, public trackdtypes
Definition: TrackFile.f90:39
character(len= *), parameter, public trackheader
Definition: TrackFile.f90:35
Here is the call graph for this function:

◆ prp_read_dimensions()

subroutine prtprpmodule::prp_read_dimensions ( class(prtprptype), intent(inout)  this)

Definition at line 838 of file prt-prp.f90.

839  ! dummy
840  class(PrtPrpType), intent(inout) :: this
841  ! local
842  character(len=LINELENGTH) :: errmsg, keyword
843  integer(I4B) :: ierr
844  logical :: isfound, endOfBlock
845 
846  ! get dimension block
847  call this%parser%GetBlock('DIMENSIONS', isfound, ierr, &
848  supportopenclose=.true.)
849 
850  ! parse dimension block if detected
851  if (isfound) then
852  write (this%iout, '(1x,a)') 'PROCESSING PARTICLE INPUT DIMENSIONS'
853  do
854  call this%parser%GetNextLine(endofblock)
855  if (endofblock) exit
856  call this%parser%GetStringCaps(keyword)
857  select case (keyword)
858  case ('NRELEASEPTS')
859  this%nreleasepoints = this%parser%GetInteger()
860  case ('NRELEASETIMES')
861  this%nreleasetimes = this%parser%GetInteger()
862  case default
863  write (errmsg, &
864  '(4x,a,a)') '****ERROR. UNKNOWN PARTICLE INPUT DIMENSION: ', &
865  trim(keyword)
866  call store_error(errmsg)
867  call this%parser%StoreErrorUnit()
868  end select
869  end do
870  write (this%iout, '(1x,a)') 'END OF PARTICLE INPUT DIMENSIONS'
871  else
872  call store_error('ERROR. REQUIRED DIMENSIONS BLOCK NOT FOUND.')
873  end if
874 
875  ! set maxbound and nbound to nreleasepts
876  this%maxbound = this%nreleasepoints
877  this%nbound = this%nreleasepoints
878 
879  ! allocate arrays for prp package
880  call this%prp_allocate_arrays()
881 
882  ! read packagedata and releasetimes blocks
883  call this%prp_read_packagedata()
884  call this%prp_read_releasetimes()
885  call this%prp_load_releasetimefrequency()
Here is the call graph for this function:

◆ prp_read_packagedata()

subroutine prtprpmodule::prp_read_packagedata ( class(prtprptype), intent(inout)  this)
private

Definition at line 889 of file prt-prp.f90.

890  ! dummy
891  class(PrtPrpType), intent(inout) :: this
892  ! local
893  character(len=LINELENGTH) :: cellid
894  character(len=LENBOUNDNAME) :: bndName, bndNameTemp
895  character(len=9) :: cno
896  logical :: isfound
897  logical :: endOfBlock
898  integer(I4B) :: ival
899  integer(I4B) :: n
900  integer(I4B) :: ierr
901  character(len=LENBOUNDNAME), dimension(:), allocatable :: nametxt
902  integer(I4B), dimension(:), allocatable :: nboundchk
903  integer(I4B), dimension(:), allocatable :: noder
904  real(DP), dimension(:), allocatable :: x
905  real(DP), dimension(:), allocatable :: y
906  real(DP), dimension(:), allocatable :: z
907  real(DP), dimension(:), allocatable :: tstop
908  ! format
909  character(len=*), parameter :: fmttend = &
910  "('end time (', G0, ') must be greater than or equal to the &
911  &begin time (', G0, ').')"
912 
913  ! allocate temporary variables
914  allocate (noder(this%nreleasepoints))
915  allocate (x(this%nreleasepoints))
916  allocate (y(this%nreleasepoints))
917  allocate (z(this%nreleasepoints))
918  allocate (tstop(this%nreleasepoints))
919  allocate (nametxt(this%nreleasepoints))
920  allocate (nboundchk(this%nreleasepoints))
921 
922  ! initialize temporary variables
923  do n = 1, this%nreleasepoints
924  nboundchk(n) = 0
925  end do
926 
927  ! read particle release point data
928  ! get particle release points block
929  call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, &
930  supportopenclose=.true.)
931 
932  ! parse block if detected
933  if (isfound) then
934  write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%packName)) &
935  //' PACKAGEDATA'
936  do
937  call this%parser%GetNextLine(endofblock)
938  if (endofblock) exit
939  ival = this%parser%GetInteger()
940  n = ival
941 
942  if (n < 1 .or. n > this%nreleasepoints) then
943  write (errmsg, '(a,i0,a,i0,a)') &
944  'Expected ', this%nreleasepoints, ' release points. &
945  &Points must be numbered from 1 to ', this%nreleasepoints, '.'
946  call store_error(errmsg)
947  cycle
948  end if
949 
950  ! increment nboundchk
951  nboundchk(n) = nboundchk(n) + 1
952 
953  ! node number
954  call this%parser%GetCellid(this%dis%ndim, cellid)
955  noder(n) = this%dis%noder_from_cellid(cellid, this%inunit, this%iout)
956 
957  ! x, y, z coordinates
958  x(n) = this%parser%GetDouble()
959  y(n) = this%parser%GetDouble()
960  z(n) = this%parser%GetDouble()
961 
962  if (this%ilocalz > 0 .and. (z(n) < 0 .or. z(n) > 1)) then
963  call store_error('Local z coordinate must fall in the interval [0, 1]')
964  cycle
965  end if
966 
967  ! set default boundname
968  write (cno, '(i9.9)') n
969  bndname = 'PRP'//cno
970 
971  ! read boundnames from file, if provided
972  if (this%inamedbound /= 0) then
973  call this%parser%GetStringCaps(bndnametemp)
974  if (bndnametemp /= '') &
975  bndname = bndnametemp
976  else
977  bndname = ''
978  end if
979 
980  ! store temp boundnames
981  nametxt(n) = bndname
982  end do
983 
984  write (this%iout, '(1x,a)') &
985  'END OF '//trim(adjustl(this%packName))//' PACKAGEDATA'
986 
987  ! check for duplicate or missing particle release points
988  do n = 1, this%nreleasepoints
989  if (nboundchk(n) == 0) then
990  write (errmsg, '(a,a,1x,i0,a)') 'No data specified for particle ', &
991  'release point', n, '.'
992  call store_error(errmsg)
993  else if (nboundchk(n) > 1) then
994  write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a)') &
995  'Data for particle release point', n, 'specified', nboundchk(n), &
996  'times.'
997  call store_error(errmsg)
998  end if
999  end do
1000  else
1001  call store_error('Required packagedata block not found.')
1002  end if
1003 
1004  ! terminate if any errors were detected
1005  if (count_errors() > 0) then
1006  call this%parser%StoreErrorUnit()
1007  end if
1008 
1009  ! fill particle release point data with data stored in temporary local arrays
1010  do n = 1, this%nreleasepoints
1011  this%rptnode(n) = noder(n)
1012  this%rptx(n) = x(n)
1013  this%rpty(n) = y(n)
1014  this%rptz(n) = z(n)
1015  this%rptname(n) = nametxt(n)
1016  end do
1017 
1018  ! deallocate local storage
1019  deallocate (noder)
1020  deallocate (x)
1021  deallocate (y)
1022  deallocate (z)
1023  deallocate (tstop)
1024  deallocate (nametxt)
1025  deallocate (nboundchk)
Here is the call graph for this function:

◆ prp_read_releasetimes()

subroutine prtprpmodule::prp_read_releasetimes ( class(prtprptype), intent(inout)  this)
private

Definition at line 1029 of file prt-prp.f90.

1030  ! dummy
1031  class(PrtPrpType), intent(inout) :: this
1032  ! local
1033  integer(I4B) :: i, ierr
1034  logical(LGP) :: eob, found, success
1035  real(DP) :: t
1036  real(DP), allocatable :: times(:)
1037 
1038  ! get releasetimes block
1039  call this%parser%GetBlock('RELEASETIMES', found, ierr, &
1040  supportopenclose=.true., &
1041  blockrequired=.false.)
1042 
1043  ! raise an error if releasetimes has a dimension
1044  ! but no block was found, otherwise return early
1045  if (.not. found) then
1046  if (this%nreleasetimes <= 0) return
1047  write (errmsg, '(a, i0)') &
1048  "Expected RELEASETIMES with length ", this%nreleasetimes
1049  call store_error(errmsg)
1050  call this%parser%StoreErrorUnit(terminate=.true.)
1051  end if
1052 
1053  ! allocate times array
1054  allocate (times(this%nreleasetimes))
1055 
1056  ! read times from the block
1057  write (this%iout, '(/1x,a)') &
1058  'PROCESSING '//trim(adjustl(this%text))//' RELEASETIMES'
1059  do i = 1, this%nreleasetimes
1060  call this%parser%GetNextLine(eob)
1061  if (eob) exit
1062  call this%parser%TryGetDouble(t, success)
1063  if (.not. success) then
1064  errmsg = "Failed to read double precision value"
1065  call store_error(errmsg)
1066  call this%parser%StoreErrorUnit(terminate=.true.)
1067  end if
1068  times(i) = t
1069  end do
1070 
1071  ! register times with the release schedule
1072  call this%schedule%time_select%extend(times)
1073 
1074  ! make sure times strictly increase
1075  if (.not. this%schedule%time_select%increasing()) then
1076  errmsg = "Release times must strictly increase"
1077  call store_error(errmsg)
1078  call this%parser%StoreErrorUnit(terminate=.true.)
1079  end if
1080 
1081  ! deallocate
1082  deallocate (times)
1083 
Here is the call graph for this function:

◆ prp_rp()

subroutine prtprpmodule::prp_rp ( class(prtprptype), intent(inout)  this)

Definition at line 544 of file prt-prp.f90.

545  ! modules
546  use tdismodule, only: kper, nper
547  use inputoutputmodule, only: urword
548  ! dummy variables
549  class(PrtPrpType), intent(inout) :: this
550  ! local variables
551  integer(I4B) :: ierr
552  logical(LGP) :: is_found
553  logical(LGP) :: end_of_block
554  logical(LGP) :: no_blocks
555  character(len=LINELENGTH) :: line
556  character(len=LINELENGTH), allocatable :: lines(:)
557  ! formats
558  character(len=*), parameter :: fmtblkerr = &
559  "('Looking for BEGIN PERIOD iper. &
560  &Found ', a, ' instead.')"
561  character(len=*), parameter :: fmt_steps = &
562  "(6x,'TIME STEP(S) ',50(I0,' '))" ! 50 limit is similar to STEPS in OC
563  character(len=*), parameter :: fmt_freq = &
564  "(6x,'EVERY ',I0,' TIME STEP(S)')"
565  character(len=*), parameter :: fmt_fracs = &
566  "(6x,50(f10.3,' '))"
567 
568  ! Set ionper to the stress period number for which a new block of data
569  ! will be read.
570  if (this%inunit == 0) return
571 
572  ! get stress period data
573  no_blocks = .false.
574  if (this%ionper < kper) then
575  ! get period block
576  call this%parser%GetBlock('PERIOD', is_found, ierr, &
577  supportopenclose=.true., &
578  blockrequired=.false.)
579  if (is_found) then
580  ! read ionper and check for increasing period numbers
581  call this%read_check_ionper()
582  else
583  ! PERIOD block not found
584  if (ierr < 0) then
585  if (kper == 1) then
586  ! End of file found; no period data for the simulation.
587  no_blocks = .true.
588  else
589  ! End of file found; no more period data.
590  this%ionper = nper + 1
591  end if
592  else
593  ! Found invalid block
594  call this%parser%GetCurrentLine(line)
595  write (errmsg, fmtblkerr) adjustl(trim(line))
596  call store_error(errmsg, terminate=.true.)
597  end if
598  end if
599  end if
600 
601  ! If the user hasn't provided any release settings (neither
602  ! explicit release times, release time frequency, or period
603  ! block release settings), default to a single release at the
604  ! start of the first period's first time step.
605  if (no_blocks .and. &
606  kper == 1 .and. &
607  size(this%schedule%time_select%times) == 0) then
608  allocate (lines(1))
609  line = "FIRST"
610  lines(1) = line
611  call this%schedule%advance(lines=lines)
612  else if (this%ionper == kper) then
613  ! If the current stress period matches the
614  ! block we are reading, parse the setting
615  ! and register it with the schedule.
616  allocate (lines(0))
617  recordloop: do
618  call this%parser%GetNextLine(end_of_block)
619  if (end_of_block) exit recordloop
620  call this%parser%GetCurrentLine(line)
621  call expandarray(lines)
622  lines(size(lines)) = line
623  end do recordloop
624  if (size(lines) > 0) &
625  call this%schedule%advance(lines=lines)
626  deallocate (lines)
627  end if
628 
integer(i4b), pointer, public kper
current stress period number
Definition: tdis.f90:23
integer(i4b), pointer, public nper
number of stress period
Definition: tdis.f90:21
Here is the call graph for this function:

◆ prp_set_pointers()

subroutine prtprpmodule::prp_set_pointers ( class(prtprptype this,
integer(i4b), dimension(:), pointer, contiguous  ibound,
integer(i4b), dimension(:), pointer, contiguous  izone,
type(trackcontroltype), pointer  trackctl 
)
private

Definition at line 192 of file prt-prp.f90.

193  class(PrtPrpType) :: this
194  integer(I4B), dimension(:), pointer, contiguous :: ibound
195  integer(I4B), dimension(:), pointer, contiguous :: izone
196  type(TrackControlType), pointer :: trackctl
197 
198  this%ibound => ibound
199  this%rptzone => izone
200  this%trackctl => trackctl

◆ release()

subroutine prtprpmodule::release ( class(prtprptype), intent(inout)  this,
integer(i4b), intent(in)  ip,
real(dp), intent(in)  trelease 
)
private

Releasing a particle entails validating the particle's coordinates and settings, transforming its coordinates if needed, initializing the particle's initial tracking time to the given release time, storing the particle in the particle store (from which the PRT model will later retrieve it, apply the tracking method, and check it in again), and accumulating the particle's mass (the total mass released from each release point is calculated for budget reporting).

Parameters
[in,out]thisthis instance
[in]ipparticle index
[in]treleaserelease time

Definition at line 429 of file prt-prp.f90.

430  ! dummy
431  class(PrtPrpType), intent(inout) :: this !< this instance
432  integer(I4B), intent(in) :: ip !< particle index
433  real(DP), intent(in) :: trelease !< release time
434  ! local
435  integer(I4B) :: np
436  type(ParticleType), pointer :: particle
437 
438  call this%initialize_particle(particle, ip, trelease)
439  np = this%nparticles + 1
440  this%nparticles = np
441  call this%particles%put(particle, np)
442  deallocate (particle)
443  this%rptm(ip) = this%rptm(ip) + done ! TODO configurable mass
444 

◆ validate_release_point()

subroutine prtprpmodule::validate_release_point ( class(prtprptype), intent(inout)  this,
integer(i4b), intent(in)  ic,
real(dp), intent(in)  x,
real(dp), intent(in)  y,
real(dp), intent(in)  z 
)
private

Terminate with an error if the release point lies outside the given cell, or if the point is above or below the grid top or bottom, respectively.

Parameters
[in,out]thisthis instance
[in]iccell index
[in]zrelease point

Definition at line 386 of file prt-prp.f90.

387  class(PrtPrpType), intent(inout) :: this !< this instance
388  integer(I4B), intent(in) :: ic !< cell index
389  real(DP), intent(in) :: x, y, z !< release point
390  ! local
391  real(DP), allocatable :: polyverts(:, :)
392 
393  call this%fmi%dis%get_polyverts(ic, polyverts)
394  if (.not. point_in_polygon(x, y, polyverts)) then
395  write (errmsg, '(a,g0,a,g0,a,i0)') &
396  'Error: release point (x=', x, ', y=', y, ') is not in cell ', &
397  this%dis%get_nodeuser(ic)
398  call store_error(errmsg, terminate=.false.)
399  call store_error_unit(this%inunit, terminate=.true.)
400  end if
401  if (z > maxval(this%dis%top)) then
402  write (errmsg, '(a,g0,a,g0,a,i0)') &
403  'Error: release point (z=', z, ') is above grid top ', &
404  maxval(this%dis%top)
405  call store_error(errmsg, terminate=.false.)
406  call store_error_unit(this%inunit, terminate=.true.)
407  else if (z < minval(this%dis%bot)) then
408  write (errmsg, '(a,g0,a,g0,a,i0)') &
409  'Error: release point (z=', z, ') is below grid bottom ', &
410  minval(this%dis%bot)
411  call store_error(errmsg, terminate=.false.)
412  call store_error_unit(this%inunit, terminate=.true.)
413  end if
414  deallocate (polyverts)
Here is the call graph for this function:

Variable Documentation

◆ ftype

character(len=lenftype) prtprpmodule::ftype = 'PRP'
private

Definition at line 37 of file prt-prp.f90.

37  character(len=LENFTYPE) :: ftype = 'PRP'

◆ text

character(len=16) prtprpmodule::text = ' PRP'
private

Definition at line 38 of file prt-prp.f90.

38  character(len=16) :: text = ' PRP'