MODFLOW 6  version 6.6.0.dev0
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 654 of file prt-prp.f90.

655  class(PrtPrpType), intent(inout) :: this
656  ! 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 439 of file prt-prp.f90.

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

◆ log_release()

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

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

358  class(PrtPrpType), intent(inout) :: this !< prp
359  if (this%iprpak > 0) then
360  write (this%iout, "(1x,/1x,a,1x,i0)") &
361  'PARTICLE RELEASE FOR PRP', this%ibcnum
362  call this%schedule%log(this%iout)
363  end if

◆ prp_ad()

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

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

315  class(PrtPrpType) :: this
316  integer(I4B) :: ip, it
317 
318  ! Notes
319  ! -----
320  ! Each release point can be thought of as
321  ! a gumball machine with infinite supply:
322  ! a point can release an arbitrary number
323  ! of particles, but only one at any time.
324  ! Coincident release times are merged to
325  ! a single time by the release scheduler.
326 
327  ! Reset mass accumulators for this time step.
328  do ip = 1, this%nreleasepoints
329  this%rptm(ip) = dzero
330  end do
331 
332  ! Advance the release schedule and check if
333  ! any releases will be made this time step.
334  call this%schedule%advance()
335  if (.not. this%schedule%any()) return
336 
337  ! Log the schedule to the list file.
338  call this%log_release()
339 
340  ! Expand the particle store. We know from the
341  ! schedule how many particles will be released.
342  call this%particles%resize( &
343  this%particles%num_stored() + &
344  (this%nreleasepoints * this%schedule%count()), &
345  this%memoryPath)
346 
347  ! Release a particle from each point for
348  ! each release time in the current step.
349  do ip = 1, this%nreleasepoints
350  do it = 1, this%schedule%count()
351  call this%release(ip, this%schedule%times(it))
352  end do
353  end do

◆ 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 206 of file prt-prp.f90.

207  ! dummy
208  class(PrtPrpType) :: this
209  integer(I4B), dimension(:), pointer, contiguous, optional :: nodelist
210  real(DP), dimension(:, :), pointer, contiguous, optional :: auxvar
211  ! local
212  integer(I4B) :: nps
213 
214  ! Allocate particle store, starting with the number
215  ! of release points (arrays resized if/when needed)
216  call allocate_particle_store( &
217  this%particles, &
218  this%nreleasepoints, &
219  this%memoryPath)
220 
221  ! Allocate arrays
222  call mem_allocate(this%rptx, this%nreleasepoints, 'RPTX', this%memoryPath)
223  call mem_allocate(this%rpty, this%nreleasepoints, 'RPTY', this%memoryPath)
224  call mem_allocate(this%rptz, this%nreleasepoints, 'RPTZ', this%memoryPath)
225  call mem_allocate(this%rptm, this%nreleasepoints, 'RPTMASS', this%memoryPath)
226  call mem_allocate(this%rptnode, this%nreleasepoints, 'RPTNODER', &
227  this%memoryPath)
228  call mem_allocate(this%rptname, lenboundname, this%nreleasepoints, &
229  'RPTNAME', this%memoryPath)
230 
231  ! Initialize arrays
232  do nps = 1, this%nreleasepoints
233  this%rptm(nps) = dzero
234  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 238 of file prt-prp.f90.

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

◆ prp_ar()

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

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

296  ! dummy variables
297  class(PrtPrpType), intent(inout) :: this
298  ! local variables
299  integer(I4B) :: n
300 
301  call this%obs%obs_ar()
302  call this%BndType%allocate_arrays()
303  if (this%inamedbound /= 0) then
304  do n = 1, this%nreleasepoints
305  this%boundname(n) = this%rptname(n)
306  end do
307  end if
308  do n = 1, this%nreleasepoints
309  this%nodelist(n) = this%rptnode(n)
310  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 620 of file prt-prp.f90.

621  ! modules
622  use tdismodule, only: delt
623  ! dummy variables
624  class(PrtPrpType) :: this
625  real(DP), dimension(:), intent(in) :: hnew
626  real(DP), dimension(:), intent(inout) :: flowja !< flow between package and model
627  integer(I4B), intent(in) :: imover !< flag indicating if the mover package is active
628  ! local variables
629  integer(I4B) :: i
630  integer(I4B) :: node
631  integer(I4B) :: idiag
632  real(DP) :: rrate
633 
634  ! If no boundaries, skip flow calculations.
635  if (this%nbound <= 0) return
636 
637  ! Loop through each boundary calculating flow.
638  do i = 1, this%nbound
639  node = this%nodelist(i)
640  rrate = dzero
641  ! If cell is no-flow or constant-head, then ignore it.
642  if (node > 0) then
643  ! Calculate the flow rate into the cell.
644  idiag = this%dis%con%ia(node)
645  rrate = this%rptm(i) * (done / delt) ! reciprocal of tstp length
646  flowja(idiag) = flowja(idiag) + rrate
647  end if
648 
649  ! Save simulated value to simvals array.
650  this%simvals(i) = rrate
651  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 101 of file prt-prp.f90.

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

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

◆ prp_df_obs()

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

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

667  ! dummy
668  class(PrtPrpType) :: this
669  ! local
670  integer(I4B) :: indx
671  call this%obs%StoreObsType('prp', .true., indx)
672  this%obs%obsData(indx)%ProcessIdPtr => defaultobsidprocessor
673 
674  ! Store obs type and assign procedure pointer
675  ! for to-mvr observation type.
676  call this%obs%StoreObsType('to-mvr', .true., indx)
677  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 1079 of file prt-prp.f90.

1080  ! modules
1081  use tdismodule, only: totalsimtime
1082  ! dummy
1083  class(PrtPrpType), intent(inout) :: this
1084  ! local
1085  real(DP), allocatable :: times(:)
1086 
1087  ! check if a release time frequency is configured
1088  if (this%rtfreq <= dzero) return
1089 
1090  ! create array of regularly-spaced release times
1091  times = arange( &
1092  start=dzero, &
1093  stop=totalsimtime, &
1094  step=this%rtfreq)
1095 
1096  ! register times with release schedule
1097  call this%schedule%time_select%extend(times)
1098 
1099  ! make sure times strictly increase
1100  if (.not. this%schedule%time_select%increasing()) then
1101  errmsg = "Release times must strictly increase"
1102  call store_error(errmsg)
1103  call this%parser%StoreErrorUnit(terminate=.true.)
1104  end if
1105 
1106  ! deallocate
1107  deallocate (times)
1108 
real(dp), pointer, public totalsimtime
time at end of simulation
Definition: tdis.f90:37
Here is the call graph for this function:

◆ prp_obs_supported()

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

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

661  class(PrtPrpType) :: this
662  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 681 of file prt-prp.f90.

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

◆ prp_read_dimensions()

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

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

828  ! dummy
829  class(PrtPrpType), intent(inout) :: this
830  ! local
831  character(len=LINELENGTH) :: errmsg, keyword
832  integer(I4B) :: ierr
833  logical :: isfound, endOfBlock
834 
835  if (.not. this%foundtol) &
836  call store_error('EXIT_SOLVE_TOLERANCE MISSING, VALUE REQUIRED')
837 
838  ! get dimension block
839  call this%parser%GetBlock('DIMENSIONS', isfound, ierr, &
840  supportopenclose=.true.)
841 
842  ! parse dimension block if detected
843  if (isfound) then
844  write (this%iout, '(1x,a)') 'PROCESSING PARTICLE INPUT DIMENSIONS'
845  do
846  call this%parser%GetNextLine(endofblock)
847  if (endofblock) exit
848  call this%parser%GetStringCaps(keyword)
849  select case (keyword)
850  case ('NRELEASEPTS')
851  this%nreleasepoints = this%parser%GetInteger()
852  case ('NRELEASETIMES')
853  this%nreleasetimes = this%parser%GetInteger()
854  case default
855  write (errmsg, &
856  '(4x,a,a)') '****ERROR. UNKNOWN PARTICLE INPUT DIMENSION: ', &
857  trim(keyword)
858  call store_error(errmsg)
859  call this%parser%StoreErrorUnit()
860  end select
861  end do
862  write (this%iout, '(1x,a)') 'END OF PARTICLE INPUT DIMENSIONS'
863  else
864  call store_error('ERROR. REQUIRED DIMENSIONS BLOCK NOT FOUND.')
865  end if
866 
867  ! set maxbound and nbound to nreleasepts
868  this%maxbound = this%nreleasepoints
869  this%nbound = this%nreleasepoints
870 
871  ! allocate arrays for prp package
872  call this%prp_allocate_arrays()
873 
874  ! read packagedata and releasetimes blocks
875  call this%prp_read_packagedata()
876  call this%prp_read_releasetimes()
877  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 881 of file prt-prp.f90.

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

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

◆ prp_rp()

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

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

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

195  class(PrtPrpType) :: this
196  integer(I4B), dimension(:), pointer, contiguous :: ibound
197  integer(I4B), dimension(:), pointer, contiguous :: izone
198  type(TrackControlType), pointer :: trackctl
199 
200  this%ibound => ibound
201  this%rptzone => izone
202  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 415 of file prt-prp.f90.

416  ! dummy
417  class(PrtPrpType), intent(inout) :: this !< this instance
418  integer(I4B), intent(in) :: ip !< particle index
419  real(DP), intent(in) :: trelease !< release time
420  ! local
421  integer(I4B) :: np
422  type(ParticleType), pointer :: particle
423 
424  call this%initialize_particle(particle, ip, trelease)
425 
426  ! Increment cumulative particle count
427  np = this%nparticles + 1
428  this%nparticles = np
429 
430  ! Save the particle to the store
431  call this%particles%save_particle(particle, np)
432  deallocate (particle)
433 
434  ! Accumulate mass for release point
435  this%rptm(ip) = this%rptm(ip) + done
436 

◆ 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 372 of file prt-prp.f90.

373  class(PrtPrpType), intent(inout) :: this !< this instance
374  integer(I4B), intent(in) :: ic !< cell index
375  real(DP), intent(in) :: x, y, z !< release point
376  ! local
377  real(DP), allocatable :: polyverts(:, :)
378 
379  call this%fmi%dis%get_polyverts(ic, polyverts)
380  if (.not. point_in_polygon(x, y, polyverts)) then
381  write (errmsg, '(a,g0,a,g0,a,i0)') &
382  'Error: release point (x=', x, ', y=', y, ') is not in cell ', &
383  this%dis%get_nodeuser(ic)
384  call store_error(errmsg, terminate=.false.)
385  call store_error_unit(this%inunit, terminate=.true.)
386  end if
387  if (z > maxval(this%dis%top)) then
388  write (errmsg, '(a,g0,a,g0,a,i0)') &
389  'Error: release point (z=', z, ') is above grid top ', &
390  maxval(this%dis%top)
391  call store_error(errmsg, terminate=.false.)
392  call store_error_unit(this%inunit, terminate=.true.)
393  else if (z < minval(this%dis%bot)) then
394  write (errmsg, '(a,g0,a,g0,a,i0)') &
395  'Error: release point (z=', z, ') is below grid bottom ', &
396  minval(this%dis%bot)
397  call store_error(errmsg, terminate=.false.)
398  call store_error_unit(this%inunit, terminate=.true.)
399  end if
400  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'