MODFLOW 6  version 6.5.0.dev2
MODFLOW 6 Code Documentation
OutputControl.f90
Go to the documentation of this file.
1 !> @brief This module contains the OutputControlModule
2 !!
3 !! This module defines the OutputControlType. This type
4 !! is overridden by GWF and GWT to create an Output Control
5 !! package for the model.
6 !!
7 !<
9 
10  use kindmodule, only: dp, i4b
12  use simvariablesmodule, only: errmsg
16 
17  implicit none
18  private
19  public outputcontroltype, oc_cr
20 
21  !> @ brief OutputControlType
22  !!
23  !! Generalized output control package
24  !<
26  character(len=LENMEMPATH) :: memorypath !< path to data stored in the memory manager
27  character(len=LENMODELNAME), pointer :: name_model => null() !< name of the model
28  integer(I4B), pointer :: inunit => null() !< unit number for input file
29  integer(I4B), pointer :: iout => null() !< unit number for output file
30  integer(I4B), pointer :: ibudcsv => null() !< unit number for budget csv output file
31  integer(I4B), pointer :: iperoc => null() !< stress period number for next output control
32  integer(I4B), pointer :: iocrep => null() !< output control repeat flag (period 0 step 0)
33  type(outputcontroldatatype), dimension(:), &
34  pointer, contiguous :: ocdobj => null() !< output control objects
35  type(blockparsertype) :: parser
36  contains
37  procedure :: oc_df
38  procedure :: oc_rp
39  procedure :: oc_ot
40  procedure :: oc_da
41  procedure :: allocate_scalars
42  procedure :: read_options
43  procedure :: oc_save
44  procedure :: oc_print
45  procedure :: oc_save_unit
46  procedure :: set_print_flag
47  end type outputcontroltype
48 
49 contains
50 
51  !> @ brief Create OutputControlType
52  !!
53  !! Create by allocating a new OutputControlType object and initializing
54  !! member variables.
55  !!
56  !<
57  subroutine oc_cr(ocobj, name_model, inunit, iout)
58  ! -- dummy
59  type(outputcontroltype), pointer :: ocobj !< OutputControlType object
60  character(len=*), intent(in) :: name_model !< name of the model
61  integer(I4B), intent(in) :: inunit !< unit number for input
62  integer(I4B), intent(in) :: iout !< unit number for output
63  !
64  ! -- Create the object
65  allocate (ocobj)
66  !
67  ! -- Allocate scalars
68  call ocobj%allocate_scalars(name_model)
69  !
70  ! -- Save unit numbers
71  ocobj%inunit = inunit
72  ocobj%iout = iout
73  !
74  ! -- Initialize block parser
75  call ocobj%parser%Initialize(inunit, iout)
76  !
77  ! -- Return
78  return
79  end subroutine oc_cr
80 
81  !> @ brief Define OutputControlType
82  !!
83  !! Placeholder routine for the moment.
84  !!
85  !<
86  subroutine oc_df(this)
87  ! -- dummy
88  class(outputcontroltype) :: this !< OutputControlType object
89  !
90  ! -- Return
91  return
92  end subroutine oc_df
93 
94  !> @ brief Read and prepare OutputControlType
95  !!
96  !! Read a period data block.
97  !!
98  !<
99  subroutine oc_rp(this)
100  ! -- modules
101  use tdismodule, only: kper, nper
102  use constantsmodule, only: linelength
104  ! -- dummy
105  class(outputcontroltype) :: this !< OutputControlType object
106  ! -- local
107  integer(I4B) :: ierr, ival, ipos
108  logical :: isfound, found, endOfBlock
109  character(len=:), allocatable :: line
110  character(len=LINELENGTH) :: ermsg, keyword1, keyword2
111  character(len=LINELENGTH) :: printsave
112  class(outputcontroldatatype), pointer :: ocdobjptr
113  ! -- formats
114  character(len=*), parameter :: fmtboc = &
115  &"(1X,/1X,'BEGIN READING OUTPUT CONTROL FOR STRESS PERIOD ',I0)"
116  character(len=*), parameter :: fmteoc = &
117  &"(/,1X,'END READING OUTPUT CONTROL FOR STRESS PERIOD ',I0)"
118  character(len=*), parameter :: fmterr = &
119  &"(' ERROR READING OUTPUT CONTROL PERIOD BLOCK: ')"
120  character(len=*), parameter :: fmtroc = &
121  "(1X,/1X,'OUTPUT CONTROL FOR STRESS PERIOD ',I0, &
122  &' IS REPEATED USING SETTINGS FROM A PREVIOUS STRESS PERIOD.')"
123  character(len=*), parameter :: fmtpererr = &
124  &"(1x,'CURRENT STRESS PERIOD GREATER THAN PERIOD IN OUTPUT CONTROL.')"
125  character(len=*), parameter :: fmtpererr2 = &
126  &"(1x,'CURRENT STRESS PERIOD: ',I0,' SPECIFIED STRESS PERIOD: ',I0)"
127  !
128  ! -- Read next block header if kper greater than last one read
129  if (this%iperoc < kper) then
130  !
131  ! -- Get period block
132  call this%parser%GetBlock('PERIOD', isfound, ierr, &
133  supportopenclose=.true., &
134  blockrequired=.false.)
135  !
136  ! -- If end of file, set iperoc past kper, else parse line
137  if (ierr < 0) then
138  this%iperoc = nper + 1
139  write (this%iout, '(/,1x,a)') 'END OF FILE DETECTED IN OUTPUT CONTROL.'
140  write (this%iout, '(1x,a)') 'CURRENT OUTPUT CONTROL SETTINGS WILL BE '
141  write (this%iout, '(1x,a)') 'REPEATED UNTIL THE END OF THE SIMULATION.'
142  else
143  !
144  ! -- Read period number
145  ival = this%parser%GetInteger()
146  !
147  ! -- Check to see if this is a valid kper
148  if (ival <= 0 .or. ival > nper) then
149  write (ermsg, '(a,i0)') 'PERIOD NOT VALID IN OUTPUT CONTROL: ', ival
150  call store_error(ermsg)
151  write (ermsg, '(a, a)') 'LINE: ', trim(adjustl(line))
152  call store_error(ermsg)
153  end if
154  !
155  ! -- Check to see if specified is less than kper
156  if (ival < kper) then
157  write (ermsg, fmtpererr)
158  call store_error(ermsg)
159  write (ermsg, fmtpererr2) kper, ival
160  call store_error(ermsg)
161  write (ermsg, '(a, a)') 'LINE: ', trim(adjustl(line))
162  call store_error(ermsg)
163  end if
164  !
165  ! -- Stop or set iperoc and continue
166  if (count_errors() > 0) then
167  call this%parser%StoreErrorUnit()
168  end if
169  this%iperoc = ival
170  end if
171  end if
172  !
173  ! -- Read the stress period block
174  if (this%iperoc == kper) then
175  !
176  ! -- Clear io flags
177  do ipos = 1, size(this%ocdobj)
178  ocdobjptr => this%ocdobj(ipos)
179  call ocdobjptr%psmobj%init()
180  end do
181  !
182  ! -- Output control time step matches simulation time step.
183  write (this%iout, fmtboc) this%iperoc
184  !
185  ! -- loop to read records
186  recordloop: do
187  !
188  ! -- Read the line
189  call this%parser%GetNextLine(endofblock)
190  if (endofblock) exit
191  call this%parser%GetStringCaps(keyword1)
192  !
193  ! -- Set printsave string and then read the record type (e.g.
194  ! BUDGET, HEAD)
195  printsave = keyword1
196  call this%parser%GetStringCaps(keyword2)
197  !
198  ! -- Look through the output control data objects that are
199  ! available and set ocdobjptr to the correct one based on
200  ! cname. Set found to .false. if not a valid record type.
201  found = .false.
202  do ipos = 1, size(this%ocdobj)
203  ocdobjptr => this%ocdobj(ipos)
204  if (keyword2 == trim(ocdobjptr%cname)) then
205  found = .true.
206  exit
207  end if
208  end do
209  if (.not. found) then
210  call this%parser%GetCurrentLine(line)
211  write (ermsg, fmterr)
212  call store_error(ermsg)
213  call store_error('UNRECOGNIZED KEYWORD: '//keyword2)
214  call store_error(trim(line))
215  call this%parser%StoreErrorUnit()
216  end if
217  call this%parser%GetRemainingLine(line)
218  call ocdobjptr%psmobj%rp(trim(printsave)//' '//line, &
219  this%iout)
220  call ocdobjptr%ocd_rp_check(this%parser%iuactive)
221  !
222  ! -- End of recordloop
223  end do recordloop
224  write (this%iout, fmteoc) this%iperoc
225  else
226  !
227  ! -- Write message that output control settings are from a previous
228  ! stress period.
229  write (this%iout, fmtroc) kper
230  end if
231  !
232  ! -- return
233  return
234  end subroutine oc_rp
235 
236  !> @ brief Output method for OutputControlType
237  !!
238  !! Go through each output control data type and output, which will print
239  !! and/or save data based on user-specified controls.
240  !!
241  !<
242  subroutine oc_ot(this, ipflg)
243  ! -- modules
244  use tdismodule, only: kstp, endofperiod
245  ! -- dummy
246  class(outputcontroltype) :: this !< OutputControlType object
247  integer(I4B), intent(inout) :: ipflg !< flag indicating if data was printed
248  ! -- local
249  integer(I4B) :: ipos
250  type(outputcontroldatatype), pointer :: ocdobjptr
251  !
252  ! -- Clear printout flag(ipflg). This flag indicates that an array was
253  ! printed to the listing file.
254  ipflg = 0
255  !
256  do ipos = 1, size(this%ocdobj)
257  ocdobjptr => this%ocdobj(ipos)
258  call ocdobjptr%ocd_ot(ipflg, kstp, endofperiod, this%iout)
259  end do
260  !
261  ! -- Return
262  return
263  end subroutine oc_ot
264 
265  !> @ brief Deallocate method for OutputControlType
266  !!
267  !! Deallocate member variables.
268  !!
269  !<
270  subroutine oc_da(this)
271  ! -- modules
273  ! -- dummy
274  class(outputcontroltype) :: this !< OutputControlType object
275  ! -- local
276  integer(I4B) :: i
277  !
278  do i = 1, size(this%ocdobj)
279  call this%ocdobj(i)%ocd_da()
280  end do
281  deallocate (this%ocdobj)
282  !
283  deallocate (this%name_model)
284  call mem_deallocate(this%inunit)
285  call mem_deallocate(this%iout)
286  call mem_deallocate(this%ibudcsv)
287  call mem_deallocate(this%iperoc)
288  call mem_deallocate(this%iocrep)
289  !
290  ! -- return
291  return
292  end subroutine oc_da
293 
294  !> @ brief Allocate scalars method for OutputControlType
295  !!
296  !! Allocate and initialize member variables.
297  !!
298  !<
299  subroutine allocate_scalars(this, name_model)
300  ! -- modules
303  ! -- dummy
304  class(outputcontroltype) :: this !< OutputControlType object
305  character(len=*), intent(in) :: name_model !< name of model
306  !
307  this%memoryPath = create_mem_path(name_model, 'OC')
308  !
309  allocate (this%name_model)
310  call mem_allocate(this%inunit, 'INUNIT', this%memoryPath)
311  call mem_allocate(this%iout, 'IOUT', this%memoryPath)
312  call mem_allocate(this%ibudcsv, 'IBUDCSV', this%memoryPath)
313  call mem_allocate(this%iperoc, 'IPEROC', this%memoryPath)
314  call mem_allocate(this%iocrep, 'IOCREP', this%memoryPath)
315  !
316  this%name_model = name_model
317  this%inunit = 0
318  this%iout = 0
319  this%ibudcsv = 0
320  this%iperoc = 0
321  this%iocrep = 0
322  !
323  ! -- return
324  return
325  end subroutine allocate_scalars
326 
327  !> @ brief Read options for OutputControlType
328  !!
329  !! Read options block and set member variables.
330  !!
331  !<
332  subroutine read_options(this)
333  ! -- modules
334  use constantsmodule, only: linelength
336  ! -- dummy
337  class(outputcontroltype) :: this !< OutputControlType object
338  ! -- local
339  character(len=LINELENGTH) :: keyword
340  character(len=LINELENGTH) :: keyword2
341  character(len=LINELENGTH) :: fname
342  character(len=:), allocatable :: line
343  integer(I4B) :: ierr
344  integer(I4B) :: ipos
345  logical :: isfound, found, endOfBlock
346  type(outputcontroldatatype), pointer :: ocdobjptr
347  !
348  ! -- get options block
349  call this%parser%GetBlock('OPTIONS', isfound, ierr, &
350  supportopenclose=.true., blockrequired=.false.)
351  !
352  ! -- parse options block if detected
353  if (isfound) then
354  write (this%iout, '(/,1x,a,/)') 'PROCESSING OC OPTIONS'
355  do
356  call this%parser%GetNextLine(endofblock)
357  if (endofblock) exit
358  call this%parser%GetStringCaps(keyword)
359  found = .false.
360  if (keyword == 'BUDGETCSV') then
361  call this%parser%GetStringCaps(keyword2)
362  if (keyword2 /= 'FILEOUT') then
363  errmsg = "BUDGETCSV must be followed by FILEOUT and then budget &
364  &csv file name. Found '"//trim(keyword2)//"'."
365  call store_error(errmsg)
366  call this%parser%StoreErrorUnit()
367  end if
368  call this%parser%GetString(fname)
369  this%ibudcsv = getunit()
370  call openfile(this%ibudcsv, this%iout, fname, 'CSV', &
371  filstat_opt='REPLACE')
372  found = .true.
373  end if
374 
375  if (.not. found) then
376  do ipos = 1, size(this%ocdobj)
377  ocdobjptr => this%ocdobj(ipos)
378  if (keyword == trim(ocdobjptr%cname)) then
379  found = .true.
380  exit
381  end if
382  end do
383  if (.not. found) then
384  errmsg = "UNKNOWN OC OPTION '"//trim(keyword)//"'."
385  call store_error(errmsg)
386  call this%parser%StoreErrorUnit()
387  end if
388  call this%parser%GetRemainingLine(line)
389  call ocdobjptr%set_option(line, this%parser%iuactive, this%iout)
390  end if
391  end do
392  write (this%iout, '(1x,a)') 'END OF OC OPTIONS'
393  end if
394  !
395  ! -- return
396  return
397  end subroutine read_options
398 
399  !> @ brief Save data to file
400  !!
401  !! Go through data and save if requested by user.
402  !!
403  !<
404  logical function oc_save(this, cname)
405  ! -- modules
406  use tdismodule, only: kstp, endofperiod
407  ! -- dummy
408  class(outputcontroltype) :: this !< OutputControlType object
409  character(len=*), intent(in) :: cname !< character string for data name
410  ! -- local
411  integer(I4B) :: ipos
412  logical :: found
413  class(outputcontroldatatype), pointer :: ocdobjptr
414  !
415  oc_save = .false.
416  found = .false.
417  do ipos = 1, size(this%ocdobj)
418  ocdobjptr => this%ocdobj(ipos)
419  if (cname == trim(ocdobjptr%cname)) then
420  found = .true.
421  exit
422  end if
423  end do
424  if (found) then
425  oc_save = ocdobjptr%psmobj%kstp_to_save(kstp, endofperiod)
426  end if
427  !
428  ! -- Return
429  return
430  end function oc_save
431 
432  !> @ brief Determine if time to print
433  !!
434  !! Determine if it is time to print the data corresponding to cname.
435  !!
436  !<
437  logical function oc_print(this, cname)
438  ! -- modules
439  use tdismodule, only: kstp, endofperiod
440  ! -- dummy
441  class(outputcontroltype) :: this !< OutputControlType object
442  character(len=*), intent(in) :: cname !< character string for data name
443  ! -- local
444  integer(I4B) :: ipos
445  logical :: found
446  class(outputcontroldatatype), pointer :: ocdobjptr
447  !
448  oc_print = .false.
449  found = .false.
450  do ipos = 1, size(this%ocdobj)
451  ocdobjptr => this%ocdobj(ipos)
452  if (cname == trim(ocdobjptr%cname)) then
453  found = .true.
454  exit
455  end if
456  end do
457  if (found) then
458  oc_print = ocdobjptr%psmobj%kstp_to_print(kstp, endofperiod)
459  end if
460  !
461  ! -- Return
462  return
463  end function oc_print
464 
465  !> @ brief Determine unit number for saving
466  !!
467  !! Determine the unit number for saving cname.
468  !!
469  !<
470  function oc_save_unit(this, cname)
471  ! -- modules
472  ! -- return
473  integer(I4B) :: oc_save_unit
474  ! -- dummy
475  class(outputcontroltype) :: this !< OutputControlType object
476  character(len=*), intent(in) :: cname !< character string for data name
477  ! -- local
478  integer(I4B) :: ipos
479  logical :: found
480  class(outputcontroldatatype), pointer :: ocdobjptr
481  !
482  oc_save_unit = 0
483  found = .false.
484  do ipos = 1, size(this%ocdobj)
485  ocdobjptr => this%ocdobj(ipos)
486  if (cname == trim(ocdobjptr%cname)) then
487  found = .true.
488  exit
489  end if
490  end do
491  if (found) then
492  oc_save_unit = ocdobjptr%idataun
493  end if
494  !
495  ! -- Return
496  return
497  end function oc_save_unit
498 
499  !> @ brief Set the print flag
500  !!
501  !! Set the print flag based on convergence and simulation parameters.
502  !!
503  !<
504  function set_print_flag(this, cname, icnvg, endofperiod) result(iprint_flag)
505  ! -- modules
507  ! -- return
508  integer(I4B) :: iprint_flag
509  ! -- dummy
510  class(outputcontroltype) :: this !< OutputControlType object
511  character(len=*), intent(in) :: cname !< character string for data name
512  integer(I4B), intent(in) :: icnvg !< convergence flag
513  logical, intent(in) :: endofperiod !< end of period logical flag
514  ! -- local
515  !
516  ! -- default is to not print
517  iprint_flag = 0
518  !
519  ! -- if the output control file indicates that cname should be printed
520  if (this%oc_print(cname)) iprint_flag = 1
521  !
522  ! -- if it is not a CONTINUE run, then set to print if not converged
523  if (isimcontinue == 0) then
524  if (icnvg == 0) iprint_flag = 1
525  end if
526  !
527  ! -- if it's the end of the period, then set flag to print
528  if (endofperiod) iprint_flag = 1
529  !
530  ! -- Return
531  return
532  end function set_print_flag
533 
534 end module outputcontrolmodule
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:44
integer(i4b), parameter lenmodelname
maximum length of the model name
Definition: Constants.f90:21
integer(i4b), parameter lenmempath
maximum length of the memory path
Definition: Constants.f90:26
integer(i4b) function, public getunit()
Get a free unit number.
subroutine, public openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, filstat_opt, mode_opt)
Open a file.
Definition: InputOutput.f90:30
This module defines variable data types.
Definition: kind.f90:8
character(len=lenmempath) function create_mem_path(component, subcomponent, context)
returns the path to the memory object
This module contains the OutputControlDataModule.
subroutine, public ocd_cr(ocdobj)
@ brief Create OutputControlDataType
This module contains the OutputControlModule.
subroutine oc_rp(this)
@ brief Read and prepare OutputControlType
logical function oc_save(this, cname)
@ brief Save data to file
logical function oc_print(this, cname)
@ brief Determine if time to print
subroutine oc_df(this)
@ brief Define OutputControlType
integer(i4b) function set_print_flag(this, cname, icnvg, endofperiod)
@ brief Set the print flag
integer(i4b) function oc_save_unit(this, cname)
@ brief Determine unit number for saving
subroutine oc_ot(this, ipflg)
@ brief Output method for OutputControlType
subroutine allocate_scalars(this, name_model)
@ brief Allocate scalars method for OutputControlType
subroutine read_options(this)
@ brief Read options for OutputControlType
subroutine, public oc_cr(ocobj, name_model, inunit, iout)
@ brief Create OutputControlType
subroutine oc_da(this)
@ brief Deallocate method for OutputControlType
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
integer(i4b) isimcontinue
simulation continue flag (1) to continue if isimcnvg = 0, (0) to terminate
logical(lgp), pointer, public endofperiod
flag indicating end of stress period
Definition: tdis.f90:27
integer(i4b), pointer, public kstp
current time step number
Definition: tdis.f90:24
integer(i4b), pointer, public kper
current stress period number
Definition: tdis.f90:23
integer(i4b), pointer, public nper
number of stress period
Definition: tdis.f90:21