MODFLOW 6  version 6.5.0.dev2
MODFLOW 6 Code Documentation
TrackData.f90
Go to the documentation of this file.
1 module trackmodule
2 
3  use kindmodule, only: dp, i4b, lgp
4  use constantsmodule, only: dzero, done
6 
7  implicit none
8 
9  private save_record
10  public :: trackfiletype
11  public :: trackfilecontroltype
12 
13  !> @brief Output file containing all or some particle pathlines.
14  !!
15  !! Can be associated with a particle release point (PRP) package
16  !! or with an entire model, and can be binary or comma-separated.
17  !<
18  type :: trackfiletype
19  integer(I4B) :: iun = 0 !< file unit number
20  logical(LGP) :: csv = .false. !< whether the file is binary or CSV
21  integer(I4B) :: iprp = -1 !< -1 is model-level file, 0 is exchange PRP
22  end type trackfiletype
23 
24  !> @brief Manages particle track (i.e. pathline) files.
25  !!
26  !! Optionally filters events ("ireason" codes, selectable in the PRT-OC pkg):
27  !!
28  !! 0: RELEASE: particle is released
29  !! 1: TRANSIT: particle moves from cell to cell
30  !! 2: TIMESTEP: timestep ends
31  !! 3: TERMINATE: tracking stops for a particle
32  !! 4: WEAKSINK: particle exits a weak sink
33  !! 5: USERTIME: user-specified tracking time
34  !!
35  !! An arbitrary number of files can be managed. Internal arrays
36  !! are resized as needed.
37  !<
39  private
40  type(trackfiletype), public, allocatable :: trackfiles(:) !< output files
41  integer(I4B), public :: ntrackfiles !< number of output files
42  logical(LGP), public :: trackrelease !< track release events
43  logical(LGP), public :: tracktransit !< track cell-to-cell transitions
44  logical(LGP), public :: tracktimestep !< track timestep ends
45  logical(LGP), public :: trackterminate !< track termination events
46  logical(LGP), public :: trackweaksink !< track weak sink exit events
47  logical(LGP), public :: trackusertime !< track user-selected times
48  contains
49  procedure :: expand
50  procedure, public :: init_track_file
51  procedure, public :: save
52  procedure, public :: set_track_events
53  end type trackfilecontroltype
54 
55  ! Track file header
56  character(len=*), parameter, public :: trackheader = &
57  'kper,kstp,imdl,iprp,irpt,ilay,icell,izone,&
58  &istatus,ireason,trelease,t,x,y,z,name'
59 
60  ! Track file dtypes
61  character(len=*), parameter, public :: trackdtypes = &
62  '<i4,<i4,<i4,<i4,<i4,<i4,<i4,<i4,&
63  &<i4,<i4,<f8,<f8,<f8,<f8,<f8,|S40'
64 
65  ! Notes
66  ! -----
67  !
68  ! Each particle's pathline consists of 1+ records reported as the particle
69  ! is tracked over the model domain. Records are snapshots of the particle's
70  ! state (e.g. tracking status, position) at a particular moment in time.
71  !
72  ! Particles have no ID property. Particles can be uniquely identified
73  ! by composite key, i.e. combination of:
74  !
75  ! - imdl: originating model ID
76  ! - iprp: originating PRP ID
77  ! - irpt: particle release location ID
78  ! - trelease: particle release time
79  !
80  ! Each record has an "ireason" property, which identifies the cause of
81  ! the record. The user selects 1+ conditions or events for recording.
82  ! Identical records (except "ireason") may be duplicated if multiple
83  ! reporting conditions apply to particles at the same moment in time.
84  ! Each "ireason" value corresponds to an OC "trackevent" option value:
85  !
86  ! 0: particle released
87  ! 1: particle transitioned between cells
88  ! 2: current time step ended****
89  ! 3: particle terminated
90  ! 4: particle exited weak sink
91  ! 5: user-specified tracking time
92  !
93  ! Each record has an "istatus" property, which is the tracking status;
94  ! e.g., awaiting release, active, terminated. A particle may terminate
95  ! for several reasons. Status values greater than one imply termination.
96  ! Particle status strictly increases over time, starting at zero:
97  !
98  ! 0: pending release*
99  ! 1: active
100  ! 2: terminated at boundary face
101  ! 3: terminated in weak sink cell
102  ! 4: terminated in weak source cell**
103  ! 5: terminated in cell with no exit face
104  ! 6: terminated in cell with specified zone number
105  ! 7: terminated in inactive cell
106  ! 8: permanently unreleased***
107  ! 9: terminated in subcell with no exit face*****
108  !
109  ! PRT shares the same status enumeration as MODPATH 7. However, some
110  ! don't apply to PRT; for instance, MODPATH 7 distinguishes forwards
111  ! and backwards tracking, but status value 4 is not used by PRT.
112  !
113  ! --------------------------------------------------
114  ! * is this necessary?
115  ! ** unnecessary since PRT makes no distinction between forwards/backwards tracking
116  ! *** e.g., released into an inactive cell, a stop zone cell, or a termination zone
117  ! **** this may coincide with termination, in which case two events are reported
118  ! ***** PRT-specific status indicating a particle stopped within a cell subcell
119 
120 contains
121 
122  !> @brief Initialize a new track file
123  subroutine init_track_file(this, iun, csv, iprp)
124  ! -- dummy
125  class(trackfilecontroltype) :: this
126  integer(I4B), intent(in) :: iun
127  logical(LGP), intent(in), optional :: csv
128  integer(I4B), intent(in), optional :: iprp
129  ! -- local
130  type(trackfiletype), pointer :: file
131 
132  ! -- allocate or expand array
133  if (.not. allocated(this%trackfiles)) then
134  allocate (this%trackfiles(1))
135  else
136  call this%expand(increment=1)
137  end if
138 
139  ! -- setup new file
140  allocate (file)
141  file%iun = iun
142  if (present(csv)) file%csv = csv
143  if (present(iprp)) file%iprp = iprp
144 
145  ! -- update array and counter
146  this%ntrackfiles = size(this%trackfiles)
147  this%trackfiles(this%ntrackfiles) = file
148 
149  end subroutine init_track_file
150 
151  !> @brief Expand the trackfile array, internal use only
152  subroutine expand(this, increment)
153  ! -- dummy
154  class(trackfilecontroltype) :: this
155  integer(I4B), optional, intent(in) :: increment
156  ! -- local
157  integer(I4B) :: inclocal
158  integer(I4B) :: isize
159  integer(I4B) :: newsize
160  type(trackfiletype), allocatable, dimension(:) :: temp
161 
162  ! -- initialize
163  if (present(increment)) then
164  inclocal = increment
165  else
166  inclocal = 1
167  end if
168 
169  ! -- increase size of array
170  if (allocated(this%trackfiles)) then
171  isize = size(this%trackfiles)
172  newsize = isize + inclocal
173  allocate (temp(newsize))
174  temp(1:isize) = this%trackfiles
175  deallocate (this%trackfiles)
176  call move_alloc(temp, this%trackfiles)
177  else
178  allocate (this%trackfiles(inclocal))
179  end if
180 
181  end subroutine expand
182 
183  !> @brief Save record to binary or CSV file, internal use only
184  subroutine save_record(iun, particle, kper, kstp, reason, csv)
185  ! -- dummy
186  integer(I4B), intent(in) :: iun
187  type(particletype), pointer, intent(in) :: particle
188  integer(I4B), intent(in) :: kper
189  integer(I4B), intent(in) :: kstp
190  integer(I4B), intent(in) :: reason
191  logical(LGP), intent(in) :: csv
192  ! -- local
193  real(dp) :: x
194  real(dp) :: y
195  real(dp) :: z
196  integer(I4B) :: status
197 
198  ! -- Get model (global) coordinates
199  call particle%get_model_coords(x, y, z)
200 
201  ! -- Get status
202  if (particle%istatus .lt. 0) then
203  status = 1
204  else
205  status = particle%istatus
206  end if
207 
208  if (csv) then
209  write (iun, '(*(G0,:,","))') &
210  kper, &
211  kstp, &
212  particle%imdl, &
213  particle%iprp, &
214  particle%irpt, &
215  particle%ilay, &
216  particle%icu, &
217  particle%izone, &
218  status, &
219  reason, &
220  particle%trelease, &
221  particle%ttrack, &
222  x, &
223  y, &
224  z, &
225  trim(adjustl(particle%name))
226  else
227  write (iun) &
228  kper, &
229  kstp, &
230  particle%imdl, &
231  particle%iprp, &
232  particle%irpt, &
233  particle%ilay, &
234  particle%icu, &
235  particle%izone, &
236  status, &
237  reason, &
238  particle%trelease, &
239  particle%ttrack, &
240  x, &
241  y, &
242  z, &
243  particle%name
244  end if
245 
246  end subroutine
247 
248  !> @brief Save the particle's state to track output file(s).
249  !!
250  !! A record is saved to all enabled model-level files and to
251  !! any PRP-level files with PRP index matching the particle's
252  !! PRP index.
253  !<
254  subroutine save(this, particle, kper, kstp, reason, level)
255  ! -- dummy
256  class(trackfilecontroltype), intent(inout) :: this
257  type(particletype), pointer, intent(in) :: particle
258  integer(I4B), intent(in) :: kper
259  integer(I4B), intent(in) :: kstp
260  integer(I4B), intent(in) :: reason
261  integer(I4B), intent(in), optional :: level
262  ! -- local
263  integer(I4B) :: i
264  type(trackfiletype) :: file
265 
266  ! -- Only save if reporting is enabled for specified event.
267  if (.not. ((this%trackrelease .and. reason == 0) .or. &
268  (this%tracktransit .and. reason == 1) .or. &
269  (this%tracktimestep .and. reason == 2) .or. &
270  (this%trackterminate .and. reason == 3) .or. &
271  (this%trackweaksink .and. reason == 4) .or. &
272  (this%trackusertime .and. reason == 5))) &
273  return
274 
275  ! -- For now, only allow reporting from outside the tracking
276  ! algorithm (e.g. release time), in which case level will
277  ! not be provided, or if within the tracking solution, in
278  ! subcells (level 3) only. This may change if the subcell
279  ! ever delegates tracking to even smaller subcomponents.
280  if (present(level)) then
281  if (level .ne. 3) return
282  end if
283 
284  ! -- Save to any enabled model-scoped or PRP-scoped files
285  do i = 1, this%ntrackfiles
286  file = this%trackfiles(i)
287  if (file%iun > 0 .and. &
288  (file%iprp == -1 .or. &
289  file%iprp == particle%iprp)) &
290  call save_record(file%iun, particle, &
291  kper, kstp, reason, csv=file%csv)
292  end do
293 
294  end subroutine save
295 
296  !> @brief Configure particle events to track.
297  !!
298  !! Each tracking event corresponds to an "ireason" code
299  !! as appears in each row of track output.
300  !<
301  subroutine set_track_events(this, &
302  release, &
303  transit, &
304  timestep, &
305  terminate, &
306  weaksink, &
307  usertime)
308  class(trackfilecontroltype) :: this
309  logical(LGP), intent(in) :: release
310  logical(LGP), intent(in) :: transit
311  logical(LGP), intent(in) :: timestep
312  logical(LGP), intent(in) :: terminate
313  logical(LGP), intent(in) :: weaksink
314  logical(LGP), intent(in) :: usertime
315  this%trackrelease = release
316  this%tracktransit = transit
317  this%tracktimestep = timestep
318  this%trackterminate = terminate
319  this%trackweaksink = weaksink
320  this%trackusertime = usertime
321  end subroutine set_track_events
322 
323 end module trackmodule
This module contains simulation constants.
Definition: Constants.f90:9
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:64
real(dp), parameter done
real constant 1
Definition: Constants.f90:75
This module defines variable data types.
Definition: kind.f90:8
subroutine, private save_record(iun, particle, kper, kstp, reason, csv)
Save record to binary or CSV file, internal use only.
Definition: TrackData.f90:185
subroutine set_track_events(this, release, transit, timestep, terminate, weaksink, usertime)
Configure particle events to track.
Definition: TrackData.f90:308
character(len= *), parameter, public trackheader
Definition: TrackData.f90:56
subroutine expand(this, increment)
Expand the trackfile array, internal use only.
Definition: TrackData.f90:153
character(len= *), parameter, public trackdtypes
Definition: TrackData.f90:61
subroutine save(this, particle, kper, kstp, reason, level)
Save the particle's state to track output file(s).
Definition: TrackData.f90:255
subroutine init_track_file(this, iun, csv, iprp)
Initialize a new track file.
Definition: TrackData.f90:124
A particle tracked by the PRT model.
Definition: Particle.f90:32
Manages particle track (i.e. pathline) files.
Definition: TrackData.f90:38
Output file containing all or some particle pathlines.
Definition: TrackData.f90:18