MODFLOW 6  version 6.7.0.dev2
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
33  use basedismodule, only: disbasetype
34  use geomutilmodule, only: transform
35 
36  implicit none
37  public :: particletrackfiletype, &
40  private :: save_event
41 
42  character(len=*), parameter, public :: trackheader = &
43  'kper,kstp,imdl,iprp,irpt,ilay,icell,izone,&
44  &istatus,ireason,trelease,t,x,y,z,name'
45 
46  character(len=*), parameter, public :: trackdtypes = &
47  '<i4,<i4,<i4,<i4,<i4,<i4,<i4,<i4,&
48  &<i4,<i4,<f8,<f8,<f8,<f8,<f8,|S40'
49 
50  !> @brief Output file containing all or some particle pathlines.
51  !!
52  !! Can be associated with a particle release point (PRP) package
53  !! or with an entire model, and can be binary or comma-separated.
54  !<
56  private
57  integer(I4B), public :: iun = 0 !< file unit number
58  logical(LGP), public :: csv = .false. !< whether the file is binary or CSV
59  integer(I4B), public :: iprp = -1 !< -1 is model-level file, 0 is exchange PRP
60  end type particletrackfiletype
61 
62  !> @brief Selection of particle events.
64  logical(LGP) :: release !< track release events
65  logical(LGP) :: featexit !< track grid feature exits
66  logical(LGP) :: timestep !< track timestep ends
67  logical(LGP) :: terminate !< track termination events
68  logical(LGP) :: weaksink !< track weak sink exit events
69  logical(LGP) :: usertime !< track user-selected times
70  logical(LGP) :: subfexit !< track subfeature exits
72 
73  !> @brief Manages particle track output (logging/writing).
74  !!
75  !! Optionally filters events as selected in the PRT Output Control package.
76  !! An arbitrary number of files can be managed, resizing is done as needed.
77  !<
79  private
80  integer(I4B), public :: iout = -1 !< log file unit
81  integer(I4B), public :: ntrackfiles !< number of track files
82  type(particletrackfiletype), public, allocatable :: files(:) !< track files
83  type(particletrackeventselectiontype), public :: selected !< event selection
84  contains
85  procedure, public :: init_file
86  procedure, public :: is_selected
87  procedure, public :: select_events
88  procedure, public :: destroy
89  procedure :: expand_files
90  procedure :: handle_event
91  procedure :: should_save
92  procedure :: should_log
93  end type particletrackstype
94 
95 contains
96 
97  !> @brief Initialize a binary or CSV file.
98  subroutine init_file(this, iun, csv, iprp)
99  ! dummy
100  class(particletrackstype) :: this
101  integer(I4B), intent(in) :: iun
102  logical(LGP), intent(in), optional :: csv
103  integer(I4B), intent(in), optional :: iprp
104  ! local
105  type(particletrackfiletype), pointer :: file
106 
107  if (.not. allocated(this%files)) then
108  allocate (this%files(1))
109  else
110  call this%expand_files(increment=1)
111  end if
112 
113  allocate (file)
114  file%iun = iun
115  if (present(csv)) file%csv = csv
116  if (present(iprp)) file%iprp = iprp
117  this%ntrackfiles = size(this%files)
118  this%files(this%ntrackfiles) = file
119  end subroutine init_file
120 
121  subroutine destroy(this)
122  class(particletrackstype) :: this
123  if (allocated(this%files)) deallocate (this%files)
124  end subroutine destroy
125 
126  !> @brief Grow the array of track files.
127  subroutine expand_files(this, increment)
128  ! dummy
129  class(particletrackstype) :: this
130  integer(I4B), optional, intent(in) :: increment
131  ! local
132  integer(I4B) :: inclocal
133  integer(I4B) :: isize
134  integer(I4B) :: newsize
135  type(particletrackfiletype), allocatable, dimension(:) :: temp
136 
137  if (present(increment)) then
138  inclocal = increment
139  else
140  inclocal = 1
141  end if
142 
143  if (allocated(this%files)) then
144  isize = size(this%files)
145  newsize = isize + inclocal
146  allocate (temp(newsize))
147  temp(1:isize) = this%files
148  deallocate (this%files)
149  call move_alloc(temp, this%files)
150  else
151  allocate (this%files(inclocal))
152  end if
153  end subroutine expand_files
154 
155  !> @brief Pick events to track.
156  subroutine select_events(this, &
157  release, &
158  featexit, &
159  timestep, &
160  terminate, &
161  weaksink, &
162  usertime, &
163  subfexit)
164  class(particletrackstype) :: this
165  logical(LGP), intent(in) :: release
166  logical(LGP), intent(in) :: featexit
167  logical(LGP), intent(in) :: timestep
168  logical(LGP), intent(in) :: terminate
169  logical(LGP), intent(in) :: weaksink
170  logical(LGP), intent(in) :: usertime
171  logical(LGP), intent(in) :: subfexit
172  this%selected%release = release
173  this%selected%featexit = featexit
174  this%selected%timestep = timestep
175  this%selected%terminate = terminate
176  this%selected%weaksink = weaksink
177  this%selected%usertime = usertime
178  this%selected%subfexit = subfexit
179  end subroutine select_events
180 
181  !> @brief Check if a given event code is selected for tracking.
182  logical function is_selected(this, event) result(selected)
183  class(particletrackstype), intent(inout) :: this
184  class(particleeventtype), intent(in) :: event
185 
186  select type (event)
187  type is (releaseeventtype)
188  selected = this%selected%release
189  type is (cellexiteventtype)
190  selected = this%selected%featexit
191  type is (subcellexiteventtype)
192  selected = this%selected%subfexit
193  type is (timestepeventtype)
194  selected = this%selected%timestep
195  type is (terminationeventtype)
196  selected = this%selected%terminate
197  type is (weaksinkeventtype)
198  selected = this%selected%weaksink
199  type is (usertimeeventtype)
200  selected = this%selected%usertime
201  class default
202  call pstop(1, "unknown event type")
203  selected = .false.
204  end select
205 
206  end function is_selected
207 
208  !> @brief Check whether a particle belongs in a given file i.e.
209  !! if the file is enabled and its group matches the particle's.
210  logical function should_save(this, particle, file) result(save)
211  class(particletrackstype), intent(inout) :: this
212  type(particletype), pointer, intent(in) :: particle
213  type(particletrackfiletype), intent(in) :: file
214  save = (file%iun > 0 .and. &
215  (file%iprp == -1 .or. file%iprp == particle%iprp))
216  end function should_save
217 
218  !> @brief Save an event to a binary or CSV file.
219  subroutine save_event(iun, particle, event, csv)
220  ! dummy
221  integer(I4B), intent(in) :: iun
222  type(particletype), pointer, intent(in) :: particle
223  class(particleeventtype), pointer, intent(in) :: event
224  logical(LGP), intent(in) :: csv
225 
226  if (csv) then
227  write (iun, '(*(G0,:,","))') &
228  event%kper, &
229  event%kstp, &
230  event%imdl, &
231  event%iprp, &
232  event%irpt, &
233  event%ilay, &
234  event%icu, &
235  event%izone, &
236  event%istatus, &
237  event%get_code(), &
238  event%trelease, &
239  event%ttrack, &
240  event%x, &
241  event%y, &
242  event%z, &
243  trim(adjustl(particle%name))
244  else
245  write (iun) &
246  event%kper, &
247  event%kstp, &
248  event%imdl, &
249  event%iprp, &
250  event%irpt, &
251  event%ilay, &
252  event%icu, &
253  event%izone, &
254  event%istatus, &
255  event%get_code(), &
256  event%trelease, &
257  event%ttrack, &
258  event%x, &
259  event%y, &
260  event%z, &
261  particle%name
262  end if
263  end subroutine save_event
264 
265  !> @brief Log output unit valid?
266  logical function should_log(this)
267  class(particletrackstype), intent(inout) :: this
268  should_log = this%iout >= 0
269  end function should_log
270 
271  !> @brief Handle a particle event.
272  subroutine handle_event(this, particle, event)
273  ! dummy
274  class(particletrackstype), intent(inout) :: this
275  type(particletype), pointer, intent(in) :: particle
276  class(particleeventtype), pointer, intent(in) :: event
277  ! local
278  integer(I4B) :: i
279  type(particletrackfiletype) :: file
280 
281  if (this%should_log()) &
282  call event%log(this%iout)
283 
284  if (this%is_selected(event)) then
285  do i = 1, this%ntrackfiles
286  file = this%files(i)
287  if (this%should_save(particle, file)) &
288  call save_event(file%iun, particle, event, csv=file%csv)
289  end do
290  end if
291  end subroutine handle_event
292 
293 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.
subroutine select_events(this, release, featexit, timestep, terminate, weaksink, usertime, subfexit)
Pick events to track.
character(len= *), parameter, public trackheader
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).