MODFLOW 6  version 6.9.0.dev0
USGS Modular Hydrologic Model
ParticleReleaseSchedule.f90
Go to the documentation of this file.
1 !> @brief Particle release scheduling.
3 
6  use kindmodule, only: i4b, dp
7  use mathutilmodule, only: is_close
10 
11  implicit none
12  private
14  public :: create_release_schedule
15 
16  !> @brief Particle release scheduling utility.
17  !!
18  !! The release schedule composes a time selection object for any
19  !! explicitly specified release times, and a time step selection
20  !! object for release times specified in period/time step terms.
21  !!
22  !! Release time coincidence is computed within a given tolerance;
23  !! times closer than the tolerance are merged into a single time.
24  !!
25  !! The release schedule must be refreshed each time step. This is
26  !! achieved by calling `advance()`. After this, the `times` array
27  !! is a debounced/consolidated schedule for the current time step.
28  !<
30  real(dp), allocatable :: times(:) !< release times
31  real(dp) :: tolerance !< release time coincidence tolerance
32  type(timeselecttype), pointer :: time_select !< time selection
33  type(timestepselecttype), pointer :: step_select !< time step selection
34  contains
35  procedure :: advance
36  procedure :: any
37  procedure :: count
38  procedure :: destroy
39  procedure :: log
40  procedure :: schedule
42 
43 contains
44 
45  !> @brief Create a new release schedule.
46  function create_release_schedule(tolerance) result(schedule_)
47  real(dp), intent(in) :: tolerance !< coincident release time tolerance
48  type(particlereleasescheduletype), pointer :: schedule_ !< schedule pointer
49 
50  allocate (schedule_)
51  allocate (schedule_%times(0))
52  allocate (schedule_%time_select)
53  allocate (schedule_%step_select)
54  call schedule_%time_select%init()
55  call schedule_%step_select%init()
56  schedule_%tolerance = tolerance
57  end function create_release_schedule
58 
59  !> @brief Deallocate the release schedule.
60  subroutine destroy(this)
61  class(particlereleasescheduletype), intent(inout) :: this !< this instance
62 
63  deallocate (this%times)
64  call this%time_select%deallocate()
65  call this%step_select%deallocate()
66  deallocate (this%time_select)
67  deallocate (this%step_select)
68  end subroutine destroy
69 
70  !> @brief Write the release schedule to the given output unit.
71  subroutine log(this, iout)
72  class(particlereleasescheduletype), intent(inout) :: this !< this instance
73  integer(I4B), intent(in) :: iout !< output unit
74  character(len=*), parameter :: fmt = &
75  &"(6x,A,': ',50(G0,' '))"
76 
77  if (this%any()) then
78  write (iout, fmt) 'RELEASE SCHEDULE', this%times
79  else
80  write (iout, "(1x,a,1x,a)") 'NO RELEASES SCHEDULED'
81  end if
82  end subroutine log
83 
84  !> @brief Add a release time to the schedule.
85  !!
86  !! To schedule multiple release times at once, expand
87  !! and populate the time selection object by hand. DO
88  !! NOT attempt to manipulate the times array; this is
89  !! a read-only property which the schedule maintains.
90  !<
91  subroutine schedule(this, trelease)
92  class(particlereleasescheduletype), intent(inout) :: this
93  real(DP), intent(in) :: trelease
94  call expandarray(this%times)
95  this%times(size(this%times)) = trelease
96  end subroutine schedule
97 
98  !> @brief Refresh the schedule for the current time step.
99  !!
100  !! This involves several tasks: first, advance the time
101  !! selection. Then, if period-block release setting lines
102  !! are provided, reinitialize the time step selection for
103  !! the given period. Finally, refresh the schedule array,
104  !! deduplicating any times closer than the set tolerance.
105  !<
106  subroutine advance(this, lines)
107  use tdismodule, only: totimc, kstp, endofperiod
108  class(particlereleasescheduletype), intent(inout) :: this
109  character(len=LINELENGTH), intent(in), optional :: lines(:)
110  integer(I4B) :: it, i
111  real(DP) :: tprevious
112  real(DP) :: trelease
113 
114  ! Advance the time selection.
115  call this%time_select%advance()
116 
117  ! Reinitialize the time step selection if new
118  ! period-block release settings are provided.
119  if (present(lines)) then
120  call this%step_select%init()
121  do i = 1, size(lines)
122  call this%step_select%read(lines(i))
123  end do
124  end if
125 
126  ! Reinitialize the release time schedule.
127  if (allocated(this%times)) deallocate (this%times)
128  allocate (this%times(0))
129 
130  tprevious = -done
131  trelease = -done
132 
133  ! Add a release time configured by period-block settings, if one
134  ! is scheduled this time step and doesn't coincide with any
135  ! explicitly configured release time (see above).
136  if (this%step_select%is_selected(kstp, endofperiod=endofperiod)) then
137  trelease = totimc
138  if (.not. this%time_select%contains_close(trelease, this%tolerance)) then
139  call this%schedule(trelease)
140  tprevious = trelease
141  end if
142  end if
143 
144  ! Schedule explicitly specified release times, up
145  ! to the configured tolerance of coincidence
146  if (this%time_select%any()) then
147  do it = this%time_select%selection(1), this%time_select%selection(2)
148  trelease = this%time_select%times(it)
149  if (tprevious >= dzero .and. is_close( &
150  tprevious, &
151  trelease, &
152  atol=this%tolerance)) cycle
153 
154  call this%schedule(trelease)
155  tprevious = trelease
156  end do
157  end if
158  end subroutine advance
159 
160  !> @brief Check if any releases are scheduled.
161  !!
162  !! Note: be sure to call advance() before calling this function,
163  !! or the result may still be associated with a prior time step.
164  !<
165  logical function any(this) result(a)
166  class(particlereleasescheduletype) :: this
167  a = this%count() > 0
168  end function any
169 
170  !> @brief Return the number of releases scheduled.
171  !!
172  !! Note: be sure to call advance() before calling this function,
173  !! or the result may still be associated with a prior time step.
174  !<
175  integer function count(this) result(n)
176  class(particlereleasescheduletype) :: this
177  n = size(this%times)
178  end function count
179 
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
real(dp), parameter done
real constant 1
Definition: Constants.f90:76
This module defines variable data types.
Definition: kind.f90:8
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
Particle release scheduling.
subroutine log(this, iout)
Write the release schedule to the given output unit.
subroutine destroy(this)
Deallocate the release schedule.
subroutine advance(this, lines)
Refresh the schedule for the current time step.
logical function any(this)
Check if any releases are scheduled.
subroutine schedule(this, trelease)
Add a release time to the schedule.
integer function count(this)
Return the number of releases scheduled.
type(particlereleasescheduletype) function, pointer, public create_release_schedule(tolerance)
Create a new release schedule.
logical(lgp), pointer, public endofperiod
flag indicating end of stress period
Definition: tdis.f90:30
real(dp), pointer, public totimc
simulation time at start of time step
Definition: tdis.f90:36
integer(i4b), pointer, public kstp
current time step number
Definition: tdis.f90:27
Specify times for some event to occur.
Definition: TimeSelect.f90:2
Time step selection module.
Represents a series of instants at which some event should occur.
Definition: TimeSelect.f90:35