MODFLOW 6  version 6.7.0.dev3
USGS Modular Hydrologic Model
ParticleTracks.f90
Go to the documentation of this file.
1 !> @brief Particle track output module.
2 !!
3 !! Each particle's track consists of events reported as the particle is
4 !! advected through the model domain. Events are snapshots of particle
5 !! state, along with optional metadata, at a particular moment in time.
6 !!
7 !! Particles have no ID property. A particle can be uniquely identified
8 !! by the unique combination of its release attributes (model, package,
9 !! position, and time). This is possible because only one particle may
10 !! be released from a given point at a given time.
11 !!
12 !! This module consumes particle events and is responsible for writing
13 !! them to one or more track files, binary or CSV, and for logging the
14 !! events if requested. Each track file is associated with either a PRP
15 !! package or with the full PRT model (there may only be 1 such latter).
16 !<
18 
19  use kindmodule, only: dp, i4b, lgp
20  use errorutilmodule, only: pstop
21  use constantsmodule, only: dzero, done, dpio180
34  use basedismodule, only: disbasetype
35  use geomutilmodule, only: transform
36 
37  implicit none
38  public :: particletrackfiletype, &
41  private :: save_event
42 
43  character(len=*), parameter, public :: trackheader = &
44  'kper,kstp,imdl,iprp,irpt,ilay,icell,izone,&
45  &istatus,ireason,trelease,t,x,y,z,name'
46 
47  character(len=*), parameter, public :: trackdtypes = &
48  '<i4,<i4,<i4,<i4,<i4,<i4,<i4,<i4,&
49  &<i4,<i4,<f8,<f8,<f8,<f8,<f8,|S40'
50 
51  !> @brief Output file containing all or some particle pathlines.
52  !!
53  !! Can be associated with a particle release point (PRP) package
54  !! or with an entire model, and can be binary or comma-separated.
55  !<
57  private
58  integer(I4B), public :: iun = 0 !< file unit number
59  logical(LGP), public :: csv = .false. !< whether the file is binary or CSV
60  integer(I4B), public :: iprp = -1 !< -1 is model-level file, 0 is exchange PRP
61  end type particletrackfiletype
62 
63  !> @brief Selection of particle events.
65  logical(LGP) :: release !< track release events
66  logical(LGP) :: featexit !< track grid feature exits
67  logical(LGP) :: timestep !< track timestep ends
68  logical(LGP) :: terminate !< track termination events
69  logical(LGP) :: weaksink !< track weak sink exit events
70  logical(LGP) :: usertime !< track user-selected times
71  logical(LGP) :: subfexit !< track subfeature exits
72  logical(LGP) :: dropped !< track water table drops
74 
75  !> @brief Manages particle track output (logging/writing).
76  !!
77  !! Optionally filters events as selected in the PRT Output Control package.
78  !! An arbitrary number of files can be managed, resizing is done as needed.
79  !<
81  private
82  integer(I4B), public :: iout = -1 !< log file unit
83  integer(I4B), public :: ntrackfiles !< number of track files
84  type(particletrackfiletype), public, allocatable :: files(:) !< track files
85  type(particletrackeventselectiontype), public :: selected !< event selection
86  contains
87  procedure, public :: init_file
88  procedure, public :: is_selected
89  procedure, public :: select_events
90  procedure, public :: destroy
91  procedure :: expand_files
92  procedure :: handle_event
93  procedure :: should_save
94  procedure :: should_log
95  end type particletrackstype
96 
97 contains
98 
99  !> @brief Initialize a binary or CSV file.
100  subroutine init_file(this, iun, csv, iprp)
101  ! dummy
102  class(particletrackstype) :: this
103  integer(I4B), intent(in) :: iun
104  logical(LGP), intent(in), optional :: csv
105  integer(I4B), intent(in), optional :: iprp
106  ! local
107  type(particletrackfiletype), pointer :: file
108 
109  if (.not. allocated(this%files)) then
110  allocate (this%files(1))
111  else
112  call this%expand_files(increment=1)
113  end if
114 
115  allocate (file)
116  file%iun = iun
117  if (present(csv)) file%csv = csv
118  if (present(iprp)) file%iprp = iprp
119  this%ntrackfiles = size(this%files)
120  this%files(this%ntrackfiles) = file
121  end subroutine init_file
122 
123  subroutine destroy(this)
124  class(particletrackstype) :: this
125  if (allocated(this%files)) deallocate (this%files)
126  end subroutine destroy
127 
128  !> @brief Grow the array of track files.
129  subroutine expand_files(this, increment)
130  ! dummy
131  class(particletrackstype) :: this
132  integer(I4B), optional, intent(in) :: increment
133  ! local
134  integer(I4B) :: inclocal
135  integer(I4B) :: isize
136  integer(I4B) :: newsize
137  type(particletrackfiletype), allocatable, dimension(:) :: temp
138 
139  if (present(increment)) then
140  inclocal = increment
141  else
142  inclocal = 1
143  end if
144 
145  if (allocated(this%files)) then
146  isize = size(this%files)
147  newsize = isize + inclocal
148  allocate (temp(newsize))
149  temp(1:isize) = this%files
150  deallocate (this%files)
151  call move_alloc(temp, this%files)
152  else
153  allocate (this%files(inclocal))
154  end if
155  end subroutine expand_files
156 
157  !> @brief Pick events to track.
158  subroutine select_events(this, &
159  release, &
160  featexit, &
161  timestep, &
162  terminate, &
163  weaksink, &
164  usertime, &
165  subfexit, &
166  dropped)
167  class(particletrackstype) :: this
168  logical(LGP), intent(in) :: release
169  logical(LGP), intent(in) :: featexit
170  logical(LGP), intent(in) :: timestep
171  logical(LGP), intent(in) :: terminate
172  logical(LGP), intent(in) :: weaksink
173  logical(LGP), intent(in) :: usertime
174  logical(LGP), intent(in) :: subfexit
175  logical(LGP), intent(in) :: dropped
176  this%selected%release = release
177  this%selected%featexit = featexit
178  this%selected%timestep = timestep
179  this%selected%terminate = terminate
180  this%selected%weaksink = weaksink
181  this%selected%usertime = usertime
182  this%selected%subfexit = subfexit
183  this%selected%dropped = dropped
184  end subroutine select_events
185 
186  !> @brief Check if a given event code is selected for tracking.
187  logical function is_selected(this, event) result(selected)
188  class(particletrackstype), intent(inout) :: this
189  class(particleeventtype), intent(in) :: event
190 
191  select type (event)
192  type is (releaseeventtype)
193  selected = this%selected%release
194  type is (cellexiteventtype)
195  selected = this%selected%featexit
196  type is (subcellexiteventtype)
197  selected = this%selected%subfexit
198  type is (timestepeventtype)
199  selected = this%selected%timestep
200  type is (terminationeventtype)
201  selected = this%selected%terminate
202  type is (weaksinkeventtype)
203  selected = this%selected%weaksink
204  type is (usertimeeventtype)
205  selected = this%selected%usertime
206  type is (droppedeventtype)
207  selected = this%selected%dropped
208  class default
209  call pstop(1, "unknown event type")
210  selected = .false.
211  end select
212 
213  end function is_selected
214 
215  !> @brief Check whether a particle belongs in a given file i.e.
216  !! if the file is enabled and its group matches the particle's.
217  logical function should_save(this, particle, file) result(save)
218  class(particletrackstype), intent(inout) :: this
219  type(particletype), pointer, intent(in) :: particle
220  type(particletrackfiletype), intent(in) :: file
221  save = (file%iun > 0 .and. &
222  (file%iprp == -1 .or. file%iprp == particle%iprp))
223  end function should_save
224 
225  !> @brief Save an event to a binary or CSV file.
226  subroutine save_event(iun, particle, event, csv)
227  ! dummy
228  integer(I4B), intent(in) :: iun
229  type(particletype), pointer, intent(in) :: particle
230  class(particleeventtype), pointer, intent(in) :: event
231  logical(LGP), intent(in) :: csv
232 
233  if (csv) then
234  write (iun, '(*(G0,:,","))') &
235  event%kper, &
236  event%kstp, &
237  event%imdl, &
238  event%iprp, &
239  event%irpt, &
240  event%ilay, &
241  event%icu, &
242  event%izone, &
243  event%istatus, &
244  event%get_code(), &
245  event%trelease, &
246  event%ttrack, &
247  event%x, &
248  event%y, &
249  event%z, &
250  trim(adjustl(particle%name))
251  else
252  write (iun) &
253  event%kper, &
254  event%kstp, &
255  event%imdl, &
256  event%iprp, &
257  event%irpt, &
258  event%ilay, &
259  event%icu, &
260  event%izone, &
261  event%istatus, &
262  event%get_code(), &
263  event%trelease, &
264  event%ttrack, &
265  event%x, &
266  event%y, &
267  event%z, &
268  particle%name
269  end if
270  end subroutine save_event
271 
272  !> @brief Log output unit valid?
273  logical function should_log(this)
274  class(particletrackstype), intent(inout) :: this
275  should_log = this%iout >= 0
276  end function should_log
277 
278  !> @brief Handle a particle event.
279  subroutine handle_event(this, particle, event)
280  ! dummy
281  class(particletrackstype), intent(inout) :: this
282  type(particletype), pointer, intent(in) :: particle
283  class(particleeventtype), pointer, intent(in) :: event
284  ! local
285  integer(I4B) :: i
286  type(particletrackfiletype) :: file
287 
288  if (this%should_log()) &
289  call event%log(this%iout)
290 
291  if (this%is_selected(event)) then
292  do i = 1, this%ntrackfiles
293  file = this%files(i)
294  if (this%should_save(particle, file)) &
295  call save_event(file%iun, particle, event, csv=file%csv)
296  end do
297  end if
298  end subroutine handle_event
299 
300 end module particletracksmodule
This module contains simulation constants.
Definition: Constants.f90:9
real(dp), parameter dpio180
real constant
Definition: Constants.f90:130
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
real(dp), parameter done
real constant 1
Definition: Constants.f90:76
subroutine pstop(status, message)
Stop the program, optionally specifying an error status code.
Definition: ErrorUtil.f90:24
subroutine, public transform(xin, yin, zin, xout, yout, zout, xorigin, yorigin, zorigin, sinrot, cosrot, invert)
Apply a 3D translation and optional 2D rotation to coordinates.
Definition: GeomUtil.f90:183
This module defines variable data types.
Definition: kind.f90:8
Particle track output module.
logical function is_selected(this, event)
Check if a given event code is selected for tracking.
subroutine destroy(this)
subroutine init_file(this, iun, csv, iprp)
Initialize a binary or CSV file.
character(len= *), parameter, public trackheader
subroutine select_events(this, release, featexit, timestep, terminate, weaksink, usertime, subfexit, dropped)
Pick events to track.
subroutine expand_files(this, increment)
Grow the array of track files.
subroutine, private save_event(iun, particle, event, csv)
Save an event to a binary or CSV file.
logical function should_log(this)
Log output unit valid?
character(len= *), parameter, public trackdtypes
logical function should_save(this, particle, file)
Check whether a particle belongs in a given file i.e. if the file is enabled and its group matches th...
Base type for particle events.
Particle tracked by the PRT model.
Definition: Particle.f90:56
Output file containing all or some particle pathlines.
Manages particle track output (logging/writing).