MODFLOW 6  version 6.7.0.dev0
USGS Modular Hydrologic Model
prt-oc.f90
Go to the documentation of this file.
1 module prtocmodule
2 
3  use basedismodule, only: disbasetype
4  use kindmodule, only: dp, i4b, lgp
8  use simmodule, only: store_error
16 
17  implicit none
18  private
19  public prtoctype, oc_cr
20 
21  !> @ brief Output control for particle tracking models
22  type, extends(outputcontroltype) :: prtoctype
23 
24  integer(I4B), pointer :: itrkout => null() !< binary output file
25  integer(I4B), pointer :: itrkhdr => null() !< output header file
26  integer(I4B), pointer :: itrkcsv => null() !< CSV output file
27  integer(I4B), pointer :: itrktls => null() !< track time list input file
28  logical(LGP), pointer :: trackrelease => null() !< whether to track release events
29  logical(LGP), pointer :: trackexit => null() !< whether to track cell transition events
30  logical(LGP), pointer :: tracktimestep => null() !< whether to track timestep events
31  logical(LGP), pointer :: trackterminate => null() !< whether to track termination events
32  logical(LGP), pointer :: trackweaksink => null() !< whether to track weak sink exit events
33  logical(LGP), pointer :: trackusertime => null() !< whether to track user-specified times
34  integer(I4B), pointer :: ntracktimes => null() !< number of user-specified tracking times
35  type(timeselecttype), pointer :: tracktimes !< user-specified tracking times
36 
37  contains
38  procedure :: oc_ar
39  procedure :: oc_da => prt_oc_da
40  procedure :: allocate_scalars => prt_oc_allocate_scalars
41  procedure :: read_options => prt_oc_read_options
42  procedure, private :: prt_oc_read_dimensions
43  procedure, private :: prt_oc_read_tracktimes
44 
45  end type prtoctype
46 
47 contains
48 
49  !> @ brief Create an output control object
50  subroutine oc_cr(ocobj, name_model, inunit, iout)
51  type(prtoctype), pointer :: ocobj !< PrtOcType object
52  character(len=*), intent(in) :: name_model !< name of the model
53  integer(I4B), intent(in) :: inunit !< unit number for input
54  integer(I4B), intent(in) :: iout !< unit number for output
55 
56  ! Create the object
57  allocate (ocobj)
58 
59  ! Allocate scalars
60  call ocobj%allocate_scalars(name_model)
61 
62  ! Save unit numbers
63  ocobj%inunit = inunit
64  ocobj%iout = iout
65 
66  ! Initialize block parser
67  call ocobj%parser%Initialize(inunit, iout)
68  end subroutine oc_cr
69 
70  subroutine prt_oc_allocate_scalars(this, name_model)
71  class(prtoctype) :: this
72  character(len=*), intent(in) :: name_model !< name of model
73 
74  this%memoryPath = create_mem_path(name_model, 'OC')
75 
76  allocate (this%name_model)
77  call mem_allocate(this%inunit, 'INUNIT', this%memoryPath)
78  call mem_allocate(this%iout, 'IOUT', this%memoryPath)
79  call mem_allocate(this%ibudcsv, 'IBUDCSV', this%memoryPath)
80  call mem_allocate(this%iperoc, 'IPEROC', this%memoryPath)
81  call mem_allocate(this%iocrep, 'IOCREP', this%memoryPath)
82  call mem_allocate(this%itrkout, 'ITRKOUT', this%memoryPath)
83  call mem_allocate(this%itrkhdr, 'ITRKHDR', this%memoryPath)
84  call mem_allocate(this%itrkcsv, 'ITRKCSV', this%memoryPath)
85  call mem_allocate(this%itrktls, 'ITRKTLS', this%memoryPath)
86  call mem_allocate(this%trackrelease, 'ITRACKRLS', this%memoryPath)
87  call mem_allocate(this%trackexit, 'ITRACKTRS', this%memoryPath)
88  call mem_allocate(this%tracktimestep, 'ITRACKTST', this%memoryPath)
89  call mem_allocate(this%trackterminate, 'ITRACKTER', this%memoryPath)
90  call mem_allocate(this%trackweaksink, 'ITRACKWSK', this%memoryPath)
91  call mem_allocate(this%trackusertime, 'ITRACKTLS', this%memoryPath)
92  call mem_allocate(this%ntracktimes, 'NTRACKTIMES', this%memoryPath)
93 
94  this%name_model = name_model
95  this%inunit = 0
96  this%iout = 0
97  this%ibudcsv = 0
98  this%iperoc = 0
99  this%iocrep = 0
100  this%itrkout = 0
101  this%itrkhdr = 0
102  this%itrkcsv = 0
103  this%itrktls = 0
104  this%trackrelease = .false.
105  this%trackexit = .false.
106  this%tracktimestep = .false.
107  this%trackterminate = .false.
108  this%trackweaksink = .false.
109  this%trackusertime = .false.
110  this%ntracktimes = 0
111 
112  end subroutine prt_oc_allocate_scalars
113 
114  !> @ brief Setup output control variables.
115  subroutine oc_ar(this, dis, dnodata)
116  ! dummy
117  class(prtoctype) :: this !< PrtOcType object
118  class(disbasetype), pointer, intent(in) :: dis !< model discretization package
119  real(DP), intent(in) :: dnodata !< no data value
120  ! local
121  integer(I4B) :: i, nocdobj, inodata
122  type(outputcontroldatatype), pointer :: ocdobjptr
123  real(DP), dimension(:), pointer, contiguous :: nullvec => null()
124 
125  ! Allocate and initialize variables
126  allocate (this%tracktimes)
127  call this%tracktimes%init()
128  inodata = 0
129  nocdobj = 1
130  allocate (this%ocds(nocdobj))
131  do i = 1, nocdobj
132  call ocd_cr(ocdobjptr)
133  select case (i)
134  case (1)
135  call ocdobjptr%init_dbl('BUDGET', nullvec, dis, 'PRINT LAST ', &
136  'COLUMNS 10 WIDTH 11 DIGITS 4 GENERAL ', &
137  this%iout, dnodata)
138  end select
139  this%ocds(i) = ocdobjptr
140  deallocate (ocdobjptr)
141  end do
142 
143  ! Read options, dimensions, and tracktimes
144  ! blocks if this package is enabled
145  if (this%inunit <= 0) return
146  call this%read_options()
147  call this%prt_oc_read_dimensions()
148  call this%prt_oc_read_tracktimes()
149 
150  end subroutine oc_ar
151 
152  subroutine prt_oc_da(this)
153  ! dummy
154  class(prtoctype) :: this
155  ! local
156  integer(I4B) :: i
157 
158  call this%tracktimes%deallocate()
159 
160  do i = 1, size(this%ocds)
161  call this%ocds(i)%ocd_da()
162  end do
163  deallocate (this%ocds)
164 
165  deallocate (this%name_model)
166  call mem_deallocate(this%inunit)
167  call mem_deallocate(this%iout)
168  call mem_deallocate(this%ibudcsv)
169  call mem_deallocate(this%iperoc)
170  call mem_deallocate(this%iocrep)
171  call mem_deallocate(this%itrkout)
172  call mem_deallocate(this%itrkhdr)
173  call mem_deallocate(this%itrkcsv)
174  call mem_deallocate(this%itrktls)
175  call mem_deallocate(this%trackrelease)
176  call mem_deallocate(this%trackexit)
177  call mem_deallocate(this%tracktimestep)
178  call mem_deallocate(this%trackterminate)
179  call mem_deallocate(this%trackweaksink)
180  call mem_deallocate(this%trackusertime)
181  call mem_deallocate(this%ntracktimes)
182 
183  end subroutine prt_oc_da
184 
185  subroutine prt_oc_read_options(this)
186  ! modules
187  use openspecmodule, only: access, form
189  use constantsmodule, only: linelength
193  ! dummy
194  class(prtoctype) :: this
195  ! local
196  character(len=LINELENGTH) :: keyword
197  character(len=LINELENGTH) :: keyword2
198  character(len=LINELENGTH) :: fname
199  character(len=:), allocatable :: line
200  integer(I4B) :: ierr, ipos
201  logical(LGP) :: block_found, param_found, event_found, eob
202  type(outputcontroldatatype), pointer :: ocdobjptr
203  ! formats
204  character(len=*), parameter :: fmttrkbin = &
205  "(4x, 'PARTICLE TRACKS WILL BE SAVED TO BINARY FILE: ', a, /4x, &
206  &'OPENED ON UNIT: ', I0)"
207  character(len=*), parameter :: fmttrkcsv = &
208  "(4x, 'PARTICLE TRACKS WILL BE SAVED TO CSV FILE: ', a, /4x, &
209  &'OPENED ON UNIT: ', I0)"
210 
211  ! get options block
212  call this%parser%GetBlock('OPTIONS', block_found, ierr, &
213  supportopenclose=.true., blockrequired=.false.)
214 
215  ! parse options block if detected
216  if (block_found) then
217  write (this%iout, '(/,1x,a,/)') 'PROCESSING OC OPTIONS'
218  event_found = .false.
219  do
220  call this%parser%GetNextLine(eob)
221  if (eob) exit
222  call this%parser%GetStringCaps(keyword)
223  param_found = .false.
224  select case (keyword)
225  case ('BUDGETCSV')
226  call this%parser%GetStringCaps(keyword2)
227  if (keyword2 /= 'FILEOUT') then
228  errmsg = "BUDGETCSV must be followed by FILEOUT and then budget &
229  &csv file name. Found '"//trim(keyword2)//"'."
230  call store_error(errmsg)
231  call this%parser%StoreErrorUnit()
232  end if
233  call this%parser%GetString(fname)
234  this%ibudcsv = getunit()
235  call openfile(this%ibudcsv, this%iout, fname, 'CSV', &
236  filstat_opt='REPLACE')
237  param_found = .true.
238  case ('TRACK')
239  call this%parser%GetStringCaps(keyword)
240  if (keyword == 'FILEOUT') then
241  ! parse filename
242  call this%parser%GetString(fname)
243  ! open binary track output file
244  this%itrkout = getunit()
245  call openfile(this%itrkout, this%iout, fname, 'DATA(BINARY)', &
246  form, access, filstat_opt='REPLACE', &
247  mode_opt=mnormal)
248  write (this%iout, fmttrkbin) trim(adjustl(fname)), this%itrkout
249  ! open and write ascii track header file
250  this%itrkhdr = getunit()
251  fname = trim(fname)//'.hdr'
252  call openfile(this%itrkhdr, this%iout, fname, 'CSV', &
253  filstat_opt='REPLACE', mode_opt=mnormal)
254  write (this%itrkhdr, '(a,/,a)') trackheader, trackdtypes
255  else
256  call store_error('OPTIONAL TRACK KEYWORD MUST BE '// &
257  'FOLLOWED BY FILEOUT')
258  end if
259  param_found = .true.
260  case ('TRACKCSV')
261  call this%parser%GetStringCaps(keyword)
262  if (keyword == 'FILEOUT') then
263  ! parse filename
264  call this%parser%GetString(fname)
265  ! open CSV track output file and write headers
266  this%itrkcsv = getunit()
267  call openfile(this%itrkcsv, this%iout, fname, 'CSV', &
268  filstat_opt='REPLACE')
269  write (this%iout, fmttrkcsv) trim(adjustl(fname)), this%itrkcsv
270  write (this%itrkcsv, '(a)') trackheader
271  else
272  call store_error('OPTIONAL TRACKCSV KEYWORD MUST BE &
273  &FOLLOWED BY FILEOUT')
274  end if
275  param_found = .true.
276  case ('TRACK_RELEASE')
277  this%trackrelease = .true.
278  event_found = .true.
279  param_found = .true.
280  case ('TRACK_EXIT')
281  this%trackexit = .true.
282  event_found = .true.
283  param_found = .true.
284  case ('TRACK_TIMESTEP')
285  this%tracktimestep = .true.
286  event_found = .true.
287  param_found = .true.
288  case ('TRACK_TERMINATE')
289  this%trackterminate = .true.
290  event_found = .true.
291  param_found = .true.
292  case ('TRACK_WEAKSINK')
293  this%trackweaksink = .true.
294  event_found = .true.
295  param_found = .true.
296  case ('TRACK_USERTIME')
297  this%trackusertime = .true.
298  event_found = .true.
299  param_found = .true.
300  case default
301  param_found = .false.
302  end select
303 
304  ! check if we're done
305  if (.not. param_found) then
306  do ipos = 1, size(this%ocds)
307  ocdobjptr => this%ocds(ipos)
308  if (keyword == trim(ocdobjptr%cname)) then
309  param_found = .true.
310  exit
311  end if
312  end do
313  if (.not. param_found) then
314  errmsg = "UNKNOWN OC OPTION '"//trim(keyword)//"'."
315  call store_error(errmsg)
316  call this%parser%StoreErrorUnit()
317  end if
318  call this%parser%GetRemainingLine(line)
319  call ocdobjptr%set_option(line, this%parser%iuactive, this%iout)
320  end if
321  end do
322 
323  ! default to all events
324  if (.not. event_found) then
325  this%trackrelease = .true.
326  this%trackexit = .true.
327  this%tracktimestep = .true.
328  this%trackterminate = .true.
329  this%trackweaksink = .true.
330  this%trackusertime = .true.
331  end if
332 
333  ! logging
334  write (this%iout, '(1x,a)') 'END OF OC OPTIONS'
335  end if
336  end subroutine prt_oc_read_options
337 
338  !> @brief Read the dimensions block.
339  subroutine prt_oc_read_dimensions(this)
340  use constantsmodule, only: linelength
342  ! dummy
343  class(prtoctype), intent(inout) :: this
344  ! local
345  character(len=LINELENGTH) :: keyword
346  integer(I4B) :: ierr
347  logical(LGP) :: isfound, endOfBlock
348 
349  ! initialize dimensions to -1
350  this%ntracktimes = -1
351 
352  ! get dimensions block
353  call this%parser%GetBlock('DIMENSIONS', isfound, ierr, &
354  supportopenclose=.true., &
355  blockrequired=.false.)
356 
357  ! parse dimensions block if detected
358  if (.not. isfound) return
359  write (this%iout, '(/1x,a)') &
360  'PROCESSING OUTPUT CONTROL DIMENSIONS'
361  do
362  call this%parser%GetNextLine(endofblock)
363  if (endofblock) exit
364  call this%parser%GetStringCaps(keyword)
365  select case (keyword)
366  case ('NTRACKTIMES')
367  this%ntracktimes = this%parser%GetInteger()
368  write (this%iout, '(4x,a,i7)') 'NTRACKTIMES = ', this%ntracktimes
369  case default
370  write (errmsg, '(a,a)') &
371  'UNKNOWN OUTPUT CONTROL DIMENSION: ', trim(keyword)
372  call store_error(errmsg)
373  end select
374  end do
375  write (this%iout, '(1x,a)') &
376  'END OF OUTPUT CONTROL DIMENSIONS'
377 
378  if (this%ntracktimes < 0) then
379  write (errmsg, '(a)') &
380  'NTRACKTIMES WAS NOT SPECIFIED OR WAS SPECIFIED INCORRECTLY.'
381  call store_error(errmsg)
382  end if
383 
384  ! stop if errors were encountered in the block
385  if (count_errors() > 0) &
386  call this%parser%StoreErrorUnit()
387 
388  end subroutine prt_oc_read_dimensions
389 
390  !> @brief Read the tracking times block.
391  subroutine prt_oc_read_tracktimes(this)
392  ! dummy
393  class(prtoctype), intent(inout) :: this
394  ! local
395  integer(I4B) :: i, ierr
396  logical(LGP) :: eob, found, success
397  real(DP) :: t
398 
399  ! get tracktimes block
400  call this%parser%GetBlock('TRACKTIMES', found, ierr, &
401  supportopenclose=.true., &
402  blockrequired=.false.)
403 
404  ! raise an error if tracktimes has a dimension
405  ! but no block was found, otherwise return early
406  if (.not. found) then
407  if (this%ntracktimes <= 0) return
408  write (errmsg, '(a, i0)') &
409  "Expected TRACKTIMES with length ", this%ntracktimes
410  call store_error(errmsg)
411  call this%parser%StoreErrorUnit(terminate=.true.)
412  end if
413 
414  ! allocate time selection
415  call this%tracktimes%expand(this%ntracktimes)
416 
417  ! read the block
418  write (this%iout, '(/1x,a)') &
419  'PROCESSING OUTPUT CONTROL TRACKTIMES'
420  do i = 1, this%ntracktimes
421  call this%parser%GetNextLine(eob)
422  if (eob) exit
423  call this%parser%TryGetDouble(t, success)
424  if (.not. success) then
425  errmsg = "Failed to read double precision value"
426  call store_error(errmsg)
427  call this%parser%StoreErrorUnit(terminate=.true.)
428  end if
429  this%tracktimes%times(i) = t
430  end do
431 
432  ! make sure times strictly increase
433  if (.not. this%tracktimes%increasing()) then
434  errmsg = "TRACKTIMES must strictly increase"
435  call store_error(errmsg)
436  call this%parser%StoreErrorUnit(terminate=.true.)
437  end if
438 
439  end subroutine prt_oc_read_tracktimes
440 
441 end module prtocmodule
This module contains block parser methods.
Definition: BlockParser.f90:7
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
@ mnormal
normal output mode
Definition: Constants.f90:206
integer(i4b), parameter lenmodelname
maximum length of the model name
Definition: Constants.f90:22
integer(i4b) function, public getunit()
Get a free unit number.
subroutine, public lowcase(word)
Convert to lower case.
subroutine, public openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, filstat_opt, mode_opt)
Open a file.
Definition: InputOutput.f90:30
subroutine, public urword(line, icol, istart, istop, ncode, n, r, iout, in)
Extract a word from a string.
This module defines variable data types.
Definition: kind.f90:8
This module contains the LongLineReaderType.
character(len=lenmempath) function create_mem_path(component, subcomponent, context)
returns the path to the memory object
character(len=20) access
Definition: OpenSpec.f90:7
character(len=20) form
Definition: OpenSpec.f90:7
Output control data module.
subroutine, public ocd_cr(ocdobj)
@ brief Create a new output control data type.
Model output control.
subroutine prt_oc_read_dimensions(this)
Read the dimensions block.
Definition: prt-oc.f90:340
subroutine oc_ar(this, dis, dnodata)
@ brief Setup output control variables.
Definition: prt-oc.f90:116
subroutine prt_oc_read_tracktimes(this)
Read the tracking times block.
Definition: prt-oc.f90:392
subroutine prt_oc_allocate_scalars(this, name_model)
Definition: prt-oc.f90:71
subroutine prt_oc_da(this)
Definition: prt-oc.f90:153
subroutine prt_oc_read_options(this)
Definition: prt-oc.f90:186
subroutine, public oc_cr(ocobj, name_model, inunit, iout)
@ brief Create an output control object
Definition: prt-oc.f90:51
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
integer(i4b) function, public count_errors()
Return number of errors.
Definition: Sim.f90:59
subroutine, public store_error_unit(iunit, terminate)
Store the file unit number.
Definition: Sim.f90:168
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string
character(len=maxcharlen) warnmsg
warning message string
Specify times for some event to occur.
Definition: TimeSelect.f90:2
character(len= *), parameter, public trackdtypes
Definition: TrackFile.f90:81
character(len= *), parameter, public trackheader
Definition: TrackFile.f90:77
@ brief Controls model output. Overridden for each model type.
@ brief Output control for particle tracking models
Definition: prt-oc.f90:22
Represents a series of instants at which some event should occur.
Definition: TimeSelect.f90:30