MODFLOW 6  version 6.6.0.dev0
USGS Modular Hydrologic Model
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 :: trackexit !< 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  ! * is this necessary?
114  ! ** unnecessary since PRT makes no distinction between forwards/backwards tracking
115  ! *** e.g., released into an inactive cell, a stop zone cell, or a termination zone
116  ! **** this may coincide with termination, in which case two events are reported
117  ! ***** PRT-specific status indicating a particle stopped within a cell subcell
118 
119 contains
120 
121  !> @brief Initialize a new track file
122  subroutine init_track_file(this, iun, csv, iprp)
123  ! -- dummy
124  class(trackfilecontroltype) :: this
125  integer(I4B), intent(in) :: iun
126  logical(LGP), intent(in), optional :: csv
127  integer(I4B), intent(in), optional :: iprp
128  ! -- local
129  type(trackfiletype), pointer :: file
130 
131  ! -- allocate or expand array
132  if (.not. allocated(this%trackfiles)) then
133  allocate (this%trackfiles(1))
134  else
135  call this%expand(increment=1)
136  end if
137 
138  ! -- setup new file
139  allocate (file)
140  file%iun = iun
141  if (present(csv)) file%csv = csv
142  if (present(iprp)) file%iprp = iprp
143 
144  ! -- update array and counter
145  this%ntrackfiles = size(this%trackfiles)
146  this%trackfiles(this%ntrackfiles) = file
147 
148  end subroutine init_track_file
149 
150  !> @brief Expand the trackfile array, internal use only
151  subroutine expand(this, increment)
152  ! -- dummy
153  class(trackfilecontroltype) :: this
154  integer(I4B), optional, intent(in) :: increment
155  ! -- local
156  integer(I4B) :: inclocal
157  integer(I4B) :: isize
158  integer(I4B) :: newsize
159  type(trackfiletype), allocatable, dimension(:) :: temp
160 
161  ! -- initialize
162  if (present(increment)) then
163  inclocal = increment
164  else
165  inclocal = 1
166  end if
167 
168  ! -- increase size of array
169  if (allocated(this%trackfiles)) then
170  isize = size(this%trackfiles)
171  newsize = isize + inclocal
172  allocate (temp(newsize))
173  temp(1:isize) = this%trackfiles
174  deallocate (this%trackfiles)
175  call move_alloc(temp, this%trackfiles)
176  else
177  allocate (this%trackfiles(inclocal))
178  end if
179 
180  end subroutine expand
181 
182  !> @brief Save record to binary or CSV file, internal use only
183  subroutine save_record(iun, particle, kper, kstp, reason, csv)
184  ! -- dummy
185  integer(I4B), intent(in) :: iun
186  type(particletype), pointer, intent(in) :: particle
187  integer(I4B), intent(in) :: kper
188  integer(I4B), intent(in) :: kstp
189  integer(I4B), intent(in) :: reason
190  logical(LGP), intent(in) :: csv
191  ! -- local
192  real(dp) :: x
193  real(dp) :: y
194  real(dp) :: z
195  integer(I4B) :: status
196 
197  ! -- Get model (global) coordinates
198  call particle%get_model_coords(x, y, z)
199 
200  ! -- Get status
201  if (particle%istatus .lt. 0) then
202  status = 1
203  else
204  status = particle%istatus
205  end if
206 
207  if (csv) then
208  write (iun, '(*(G0,:,","))') &
209  kper, &
210  kstp, &
211  particle%imdl, &
212  particle%iprp, &
213  particle%irpt, &
214  particle%ilay, &
215  particle%icu, &
216  particle%izone, &
217  status, &
218  reason, &
219  particle%trelease, &
220  particle%ttrack, &
221  x, &
222  y, &
223  z, &
224  trim(adjustl(particle%name))
225  else
226  write (iun) &
227  kper, &
228  kstp, &
229  particle%imdl, &
230  particle%iprp, &
231  particle%irpt, &
232  particle%ilay, &
233  particle%icu, &
234  particle%izone, &
235  status, &
236  reason, &
237  particle%trelease, &
238  particle%ttrack, &
239  x, &
240  y, &
241  z, &
242  particle%name
243  end if
244 
245  end subroutine
246 
247  !> @brief Save the particle's state to track output file(s).
248  !!
249  !! A record is saved to all enabled model-level files and to
250  !! any PRP-level files with PRP index matching the particle's
251  !! PRP index.
252  !<
253  subroutine save(this, particle, kper, kstp, reason, level)
254  ! -- dummy
255  class(trackfilecontroltype), intent(inout) :: this
256  type(particletype), pointer, intent(in) :: particle
257  integer(I4B), intent(in) :: kper
258  integer(I4B), intent(in) :: kstp
259  integer(I4B), intent(in) :: reason
260  integer(I4B), intent(in), optional :: level
261  ! -- local
262  integer(I4B) :: i
263  type(trackfiletype) :: file
264 
265  ! -- Only save if reporting is enabled for specified event.
266  if (.not. ((this%trackrelease .and. reason == 0) .or. &
267  (this%trackexit .and. reason == 1) .or. &
268  (this%tracktimestep .and. reason == 2) .or. &
269  (this%trackterminate .and. reason == 3) .or. &
270  (this%trackweaksink .and. reason == 4) .or. &
271  (this%trackusertime .and. reason == 5))) &
272  return
273 
274  ! -- For now, only allow reporting from outside the tracking
275  ! algorithm (e.g. release time), in which case level will
276  ! not be provided, or if within the tracking solution, in
277  ! subcells (level 3) only. This may change if the subcell
278  ! ever delegates tracking to even smaller subcomponents.
279  if (present(level)) then
280  if (level .ne. 3) return
281  end if
282 
283  ! -- Save to any enabled model-scoped or PRP-scoped files
284  do i = 1, this%ntrackfiles
285  file = this%trackfiles(i)
286  if (file%iun > 0 .and. &
287  (file%iprp == -1 .or. &
288  file%iprp == particle%iprp)) &
289  call save_record(file%iun, particle, &
290  kper, kstp, reason, csv=file%csv)
291  end do
292 
293  end subroutine save
294 
295  !> @brief Configure particle events to track.
296  !!
297  !! Each tracking event corresponds to an "ireason" code
298  !! as appears in each row of track output.
299  !<
300  subroutine set_track_events(this, &
301  release, &
302  cellexit, &
303  timestep, &
304  terminate, &
305  weaksink, &
306  usertime)
307  class(trackfilecontroltype) :: this
308  logical(LGP), intent(in) :: release
309  logical(LGP), intent(in) :: cellexit
310  logical(LGP), intent(in) :: timestep
311  logical(LGP), intent(in) :: terminate
312  logical(LGP), intent(in) :: weaksink
313  logical(LGP), intent(in) :: usertime
314  this%trackrelease = release
315  this%trackexit = cellexit
316  this%tracktimestep = timestep
317  this%trackterminate = terminate
318  this%trackweaksink = weaksink
319  this%trackusertime = usertime
320  end subroutine set_track_events
321 
322 end module trackmodule
This module contains simulation constants.
Definition: Constants.f90:9
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
subroutine, private save_record(iun, particle, kper, kstp, reason, csv)
Save record to binary or CSV file, internal use only.
Definition: TrackData.f90:184
character(len= *), parameter, public trackheader
Definition: TrackData.f90:56
subroutine expand(this, increment)
Expand the trackfile array, internal use only.
Definition: TrackData.f90:152
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:254
subroutine init_track_file(this, iun, csv, iprp)
Initialize a new track file.
Definition: TrackData.f90:123
subroutine set_track_events(this, release, cellexit, timestep, terminate, weaksink, usertime)
Configure particle events to track.
Definition: TrackData.f90:307
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