MODFLOW 6  version 6.7.0.dev2
USGS Modular Hydrologic Model
ParticleReleaseSchedule.f90
Go to the documentation of this file.
1 !> @brief Particle release scheduling.
3 
6  use kindmodule, only: i4b, lgp, 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  !! This routine is idempotent.
107  !<
108  subroutine advance(this, lines)
109  use tdismodule, only: totimc, kstp, endofperiod
110  class(particlereleasescheduletype), intent(inout) :: this
111  character(len=LINELENGTH), intent(in), optional :: lines(:)
112  integer(I4B) :: it, i
113  real(DP) :: tprevious
114  real(DP) :: trelease
115 
116  ! Advance the time selection.
117  call this%time_select%advance()
118 
119  ! Reinitialize the time step selection if new
120  ! period-block release settings are provided.
121  if (present(lines)) then
122  call this%step_select%init()
123  do i = 1, size(lines)
124  call this%step_select%read(lines(i))
125  end do
126  end if
127 
128  ! Reinitialize the release time schedule.
129  if (allocated(this%times)) deallocate (this%times)
130  allocate (this%times(0))
131 
132  tprevious = -done
133  trelease = -done
134 
135  ! Add a release time configured by period-block
136  ! settings, if one is scheduled this time step.
137  if (this%step_select%is_selected(kstp, endofperiod=endofperiod)) then
138  trelease = totimc
139  call this%schedule(trelease)
140  tprevious = trelease
141  end if
142 
143  ! Schedule explicitly specified release times, up
144  ! to the configured tolerance of coincidence
145  if (this%time_select%any()) then
146  do it = this%time_select%selection(1), this%time_select%selection(2)
147  trelease = this%time_select%times(it)
148  if (tprevious >= dzero .and. is_close( &
149  tprevious, &
150  trelease, &
151  atol=this%tolerance)) cycle
152 
153  call this%schedule(trelease)
154  tprevious = trelease
155  end do
156  end if
157  end subroutine advance
158 
159  !> @brief Check if any releases are scheduled.
160  !!
161  !! Note: be sure to call advance() before calling this function,
162  !! or the result may still be associated with a prior time step.
163  !<
164  logical function any(this) result(a)
165  class(particlereleasescheduletype) :: this
166  a = this%count() > 0
167  end function any
168 
169  !> @brief Return the number of releases scheduled.
170  !!
171  !! Note: be sure to call advance() before calling this function,
172  !! or the result may still be associated with a prior time step.
173  !<
174  integer function count(this) result(n)
175  class(particlereleasescheduletype) :: this
176  n = size(this%times)
177  end function count
178 
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:27
real(dp), pointer, public totimc
simulation time at start of time step
Definition: tdis.f90:33
integer(i4b), pointer, public kstp
current time step number
Definition: tdis.f90:24
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:30