MODFLOW 6  version 6.8.0.dev0
USGS Modular Hydrologic Model
Method.f90
Go to the documentation of this file.
1 !> @brief Particle tracking strategies
3 
4  use kindmodule, only: dp, i4b, lgp
5  use constantsmodule, only: dzero
6  use errorutilmodule, only: pstop
7  use subcellmodule, only: subcelltype
18  use basedismodule, only: disbasetype
19  use prtfmimodule, only: prtfmitype
20  use cellmodule, only: celltype
21  use celldefnmodule, only: celldefntype
23  use mathutilmodule, only: is_close
25  use listmodule, only: listtype
26  implicit none
27 
29 
30  !> @brief Tracking method level enumeration.
31  !!
32  !> Tracking levels: 1: model, 2: grid feature, 3: grid subfeature.
33  !! A tracking level identifies the domain through which a tracking
34  !! method is responsible for moving a particle. Methods operate on
35  !! a particular level and delegate to submethods for levels higher
36  !! than (i.e. below the scope of) their own.
37  !<
38  enum, bind(C)
39  enumerator :: level_model = 1
40  enumerator :: level_feature = 2
41  enumerator :: level_subfeature = 3
42  end enum
43 
44  private
45  public :: methodtype
46 
47  !> @brief Base type for particle tracking methods.
48  !!
49  !! The PRT tracking algorithm invokes a "tracking method" for each
50  !! domain. A domain can be a model, cell in a model, or subcell in
51  !! a cell. Tracking proceeds recursively, delegating to a possibly
52  !! arbitrary number of subdomains (currently, only the three above
53  !! are recognized). A tracking method is responsible for advancing
54  !! a particle through a domain, delegating to subdomains as needed
55  !! depending on cell geometry (implementing the strategy pattern).
56  !<
57  type, abstract :: methodtype
58  character(len=40), pointer, public :: name !< method name
59  logical(LGP), public :: delegates !< whether the method delegates
60  type(prtfmitype), pointer, public :: fmi => null() !< ptr to fmi
61  class(celltype), pointer, public :: cell => null() !< ptr to the current cell
62  class(subcelltype), pointer, public :: subcell => null() !< ptr to the current subcell
63  type(particleeventdispatchertype), pointer, public :: events => null() !< ptr to event dispatcher
64  type(timeselecttype), pointer, public :: tracktimes => null() !< ptr to user-defined tracking times
65  integer(I4B), dimension(:), pointer, contiguous, public :: izone => null() !< pointer to zone numbers
66  real(dp), dimension(:), pointer, contiguous, public :: flowja => null() !< pointer to intercell flows
67  real(dp), dimension(:), pointer, contiguous, public :: porosity => null() !< pointer to aquifer porosity
68  real(dp), dimension(:), pointer, contiguous, public :: retfactor => null() !< pointer to retardation factor
69  contains
70  ! Implemented in all subtypes
71  procedure(apply), deferred :: apply !< apply the method to the particle
72  procedure(assess), deferred :: assess !< assess conditions before tracking
73  procedure(deallocate), deferred :: deallocate !< deallocate the method object
74  procedure :: get_level !< get the tracking method level
75  ! Overridden in subtypes that delegate
76  procedure :: pass !< pass the particle to the next subdomain
77  procedure :: load !< load the subdomain tracking method
78  ! Implemented here
79  procedure :: init
80  procedure :: track
81  procedure :: try_pass
82  ! Event firing methods
83  procedure :: release
84  procedure :: terminate
85  procedure :: timestep
86  procedure :: weaksink
87  procedure :: usertime
88  procedure :: dropped
89  end type methodtype
90 
91  abstract interface
92  subroutine apply(this, particle, tmax)
93  import dp
94  import methodtype
95  import particletype
96  class(methodtype), intent(inout) :: this
97  type(particletype), pointer, intent(inout) :: particle
98  real(DP), intent(in) :: tmax
99  end subroutine apply
100  subroutine assess(this, particle, cell_defn, tmax)
101  import dp
102  import methodtype
103  import particletype
104  import celldefntype
105  class(methodtype), intent(inout) :: this
106  type(particletype), pointer, intent(inout) :: particle
107  type(celldefntype), pointer, intent(inout) :: cell_defn
108  real(DP), intent(in) :: tmax
109  end subroutine assess
110  subroutine deallocate (this)
111  import methodtype
112  class(methodtype), intent(inout) :: this
113  end subroutine deallocate
114  end interface
115 
116 contains
117 
118  !> @brief Initialize the method with pointers to model data.
119  subroutine init(this, fmi, cell, subcell, events, tracktimes, &
120  izone, flowja, porosity, retfactor)
121  class(methodtype), intent(inout) :: this
122  type(prtfmitype), intent(in), pointer, optional :: fmi
123  class(celltype), intent(in), pointer, optional :: cell
124  class(subcelltype), intent(in), pointer, optional :: subcell
125  type(particleeventdispatchertype), intent(in), pointer, optional :: events
126  type(timeselecttype), intent(in), pointer, optional :: tracktimes
127  integer(I4B), intent(in), pointer, optional :: izone(:)
128  real(DP), intent(in), pointer, optional :: flowja(:)
129  real(DP), intent(in), pointer, optional :: porosity(:)
130  real(DP), intent(in), pointer, optional :: retfactor(:)
131 
132  if (present(fmi)) this%fmi => fmi
133  if (present(cell)) this%cell => cell
134  if (present(subcell)) this%subcell => subcell
135  if (present(events)) this%events => events
136  if (present(tracktimes)) this%tracktimes => tracktimes
137  if (present(izone)) this%izone => izone
138  if (present(flowja)) this%flowja => flowja
139  if (present(porosity)) this%porosity => porosity
140  if (present(retfactor)) this%retfactor => retfactor
141  end subroutine init
142 
143  !> @brief Track the particle over subdomains of the given
144  ! level until the particle terminates or tmax is reached.
145  recursive subroutine track(this, particle, level, tmax)
146  ! dummy
147  class(methodtype), intent(inout) :: this
148  type(particletype), pointer, intent(inout) :: particle
149  integer(I4B) :: level
150  real(dp), intent(in) :: tmax
151  ! local
152  logical(LGP) :: advancing
153  integer(I4B) :: nextlevel
154  class(methodtype), pointer :: submethod
155 
156  advancing = .true.
157  nextlevel = level + 1
158  do while (advancing)
159  call this%load(particle, nextlevel, submethod)
160  call submethod%apply(particle, tmax)
161  call this%try_pass(particle, nextlevel, advancing)
162  end do
163  end subroutine track
164 
165  !> @brief Try passing the particle to the next subdomain.
166  subroutine try_pass(this, particle, nextlevel, advancing)
167  class(methodtype), intent(inout) :: this
168  type(particletype), pointer, intent(inout) :: particle
169  integer(I4B) :: nextlevel
170  logical(LGP) :: advancing
171 
172  if (particle%advancing) then
173  ! if still advancing, pass to the next subdomain.
174  ! if that puts us on a boundary, then we're done.
175  call this%pass(particle)
176  if (particle%iboundary(nextlevel - 1) .ne. 0) &
177  advancing = .false.
178  else
179  ! otherwise we're already done so
180  ! reset the domain boundary value.
181  advancing = .false.
182  particle%iboundary = 0
183  end if
184  end subroutine try_pass
185 
186  !> @brief Get tracking method level.
187  function get_level(this) result(level)
188  class(methodtype), intent(in) :: this
189  integer(I4B) :: level
190  level = -1 ! suppress compiler warning
191  call pstop(1, "get_level must be overridden")
192  end function get_level
193 
194  !> @brief Load subdomain tracking method (submethod).
195  subroutine load(this, particle, next_level, submethod)
196  class(methodtype), intent(inout) :: this
197  type(particletype), pointer, intent(inout) :: particle
198  integer, intent(in) :: next_level
199  class(methodtype), pointer, intent(inout) :: submethod
200  call pstop(1, "load must be overridden")
201  end subroutine load
202 
203  !> @brief Pass particle to the next subdomain or to a domain boundary.
204  subroutine pass(this, particle)
205  class(methodtype), intent(inout) :: this
206  type(particletype), pointer, intent(inout) :: particle
207  call pstop(1, "pass must be overridden")
208  end subroutine pass
209 
210  !> @brief A particle is released.
211  subroutine release(this, particle)
212  class(methodtype), intent(inout) :: this
213  type(particletype), pointer, intent(inout) :: particle
214  class(particleeventtype), pointer :: event
215  allocate (releaseeventtype :: event)
216  call this%events%broadcast(particle, event)
217  deallocate (event)
218  end subroutine release
219 
220  !> @brief A particle terminates.
221  subroutine terminate(this, particle, status)
222  class(methodtype), intent(inout) :: this
223  type(particletype), pointer, intent(inout) :: particle
224  integer(I4B), intent(in), optional :: status
225  class(particleeventtype), pointer :: event
226  particle%advancing = .false.
227  if (present(status)) particle%istatus = status
228  allocate (terminationeventtype :: event)
229  call this%events%broadcast(particle, event)
230  deallocate (event)
231  end subroutine terminate
232 
233  !> @brief A time step ends.
234  subroutine timestep(this, particle)
235  class(methodtype), intent(inout) :: this
236  type(particletype), pointer, intent(inout) :: particle
237  class(particleeventtype), pointer :: event
238  allocate (timestepeventtype :: event)
239  call this%events%broadcast(particle, event)
240  deallocate (event)
241  end subroutine timestep
242 
243  !> @brief A particle leaves a weak sink.
244  subroutine weaksink(this, particle)
245  class(methodtype), intent(inout) :: this
246  type(particletype), pointer, intent(inout) :: particle
247  class(particleeventtype), pointer :: event
248  allocate (weaksinkeventtype :: event)
249  call this%events%broadcast(particle, event)
250  deallocate (event)
251  end subroutine weaksink
252 
253  !> @brief A user-defined tracking time occurs.
254  subroutine usertime(this, particle)
255  class(methodtype), intent(inout) :: this
256  type(particletype), pointer, intent(inout) :: particle
257  class(particleeventtype), pointer :: event
258  allocate (usertimeeventtype :: event)
259  call this%events%broadcast(particle, event)
260  deallocate (event)
261  end subroutine usertime
262 
263  !> @brief A particle drops to the water table.
264  subroutine dropped(this, particle)
265  class(methodtype), intent(inout) :: this
266  type(particletype), pointer, intent(inout) :: particle
267  class(particleeventtype), pointer :: event
268  allocate (droppedeventtype :: event)
269  call this%events%broadcast(particle, event)
270  deallocate (event)
271  end subroutine dropped
272 
273 end module methodmodule
This module contains simulation constants.
Definition: Constants.f90:9
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
subroutine pstop(status, message)
Stop the program, optionally specifying an error status code.
Definition: ErrorUtil.f90:24
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 tracking strategies.
Definition: Method.f90:2
subroutine dropped(this, particle)
A particle drops to the water table.
Definition: Method.f90:265
subroutine load(this, particle, next_level, submethod)
Load subdomain tracking method (submethod).
Definition: Method.f90:196
subroutine terminate(this, particle, status)
A particle terminates.
Definition: Method.f90:222
subroutine release(this, particle)
A particle is released.
Definition: Method.f90:212
recursive subroutine track(this, particle, level, tmax)
Track the particle over subdomains of the given.
Definition: Method.f90:146
subroutine weaksink(this, particle)
A particle leaves a weak sink.
Definition: Method.f90:245
subroutine try_pass(this, particle, nextlevel, advancing)
Try passing the particle to the next subdomain.
Definition: Method.f90:167
integer(i4b) function get_level(this)
Get tracking method level.
Definition: Method.f90:188
subroutine timestep(this, particle)
A time step ends.
Definition: Method.f90:235
@, public level_feature
Definition: Method.f90:40
subroutine usertime(this, particle)
A user-defined tracking time occurs.
Definition: Method.f90:255
@, public level_subfeature
Definition: Method.f90:41
@, public level_model
Definition: Method.f90:39
subroutine pass(this, particle)
Pass particle to the next subdomain or to a domain boundary.
Definition: Method.f90:205
Specify times for some event to occur.
Definition: TimeSelect.f90:2
Base grid cell definition.
Definition: CellDefn.f90:25
Base type for grid cells of a concrete type. Contains a cell-definition which is information shared b...
Definition: Cell.f90:12
Base type for exit solutions.
A generic heterogeneous doubly-linked list.
Definition: List.f90:14
Base type for particle tracking methods.
Definition: Method.f90:57
Base type for particle events.
Dispatcher for particle events. Consumers subscribe handlers to the dispatcher. Events may be dispatc...
Particle tracked by the PRT model.
Definition: Particle.f90:64
A subcell of a cell.
Definition: Subcell.f90:10
Represents a series of instants at which some event should occur.
Definition: TimeSelect.f90:34