MODFLOW 6  version 6.8.0.dev0
USGS Modular Hydrologic Model
Sim.f90
Go to the documentation of this file.
1 !> @brief This module contains simulation methods
2 !!
3 !! This module contains simulation methods for storing warning and error
4 !! messages and notes. This module also has methods for counting warnings,
5 !! errors, and notes in addition to stopping the simulation. The module does
6 !! not have any dependencies on models, exchanges, or solutions in a
7 !! simulation.
8 !!
9 !<
10 module simmodule
11 
12  use kindmodule, only: dp, i4b
13  use errorutilmodule, only: pstop
14  use definedmacros, only: get_os
16  done, &
17  iustart, iulast, &
18  vsummary, vall, vdebug, &
19  oswin, osundef
21  iforcestop, iunext, &
22  warnmsg
24 
25  implicit none
26 
27  private
28  public :: count_errors
29  public :: store_error
30  public :: ustop
31  public :: converge_reset
32  public :: converge_check
33  public :: initial_message
34  public :: final_message
35  public :: store_warning
36  public :: deprecation_warning
37  public :: store_note
38  public :: count_warnings
39  public :: count_notes
40  public :: store_error_unit
41  public :: store_error_filename
42  public :: maxerrors
43 
48 
49 contains
50 
51  !> @brief Return number of errors
52  !!
53  !! Function to return the number of errors messages that have been stored.
54  !!
55  !! @return ncount number of error messages stored
56  !!
57  !<
58  function count_errors() result(ncount)
59  integer(I4B) :: ncount
60  ncount = sim_errors%count()
61  end function count_errors
62 
63  !> @brief Return number of warnings
64  !!
65  !! Function to return the number of warning messages that have been stored.
66  !!
67  !! @return ncount number of warning messages stored
68  !!
69  !<
70  function count_warnings() result(ncount)
71  integer(I4B) :: ncount
72  ncount = sim_warnings%count()
73  end function count_warnings
74 
75  !> @brief Return the number of notes stored.
76  !<
77  function count_notes() result(ncount)
78  integer(I4B) :: ncount
79  ncount = sim_notes%count()
80  end function count_notes
81 
82  !> @brief Set the maximum number of errors to be stored.
83  !<
84  subroutine maxerrors(imax)
85  integer(I4B), intent(in) :: imax !< maximum number of error messages that will be stored
86  call sim_errors%set_max(imax)
87  end subroutine maxerrors
88 
89  !> @brief Store an error message.
90  !<
91  subroutine store_error(msg, terminate)
92  ! -- dummy variable
93  character(len=*), intent(in) :: msg !< error message
94  logical, optional, intent(in) :: terminate !< boolean indicating if the simulation should be terminated
95  ! -- local variables
96  logical :: lterminate
97  !
98  ! -- process optional variables
99  if (present(terminate)) then
100  lterminate = terminate
101  else
102  lterminate = .false.
103  end if
104  !
105  ! -- store error
106  call sim_errors%store(msg)
107  !
108  ! -- terminate the simulation
109  if (lterminate) then
110  call ustop()
111  end if
112 
113  end subroutine store_error
114 
115  !> @brief Get the file name
116  !!
117  !! Subroutine to get the file name from the unit number for a open file.
118  !! If the INQUIRE function returns the full path (for example, the INTEL
119  !! compiler) then the returned file name (fname) is limited to the filename
120  !! without the path.
121  !!
122  !<
123  subroutine get_filename(iunit, fname)
124  ! -- dummy variables
125  integer(I4B), intent(in) :: iunit !< open file unit number
126  character(len=*), intent(inout) :: fname !< file name attached to the open file unit number
127  ! -- local variables
128  integer(I4B) :: ipos
129  integer(I4B) :: ios
130  integer(I4B) :: ilen
131  !
132  ! -- get file name from unit number
133  ipos = 0
134  inquire (unit=iunit, name=fname)
135  !
136  ! -- determine the operating system
137  ios = get_os()
138  !
139  ! -- extract filename from full path, if present
140  ! forward slash on linux, unix, and osx
141  if (ios /= oswin) then
142  ipos = index(fname, '/', back=.true.)
143  end if
144  !
145  ! -- check for backslash on windows or undefined os and
146  ! forward slashes were not found
147  if (ios == oswin .or. ios == osundef) then
148  if (ipos < 1) then
149  ipos = index(fname, '\', back=.true.)
150  end if
151  end if
152  !
153  ! -- exclude the path from the file name
154  if (ipos > 0) then
155  ilen = len_trim(fname)
156  write (fname, '(a)') fname(ipos + 1:ilen)//' '
157  end if
158 
159  end subroutine get_filename
160 
161  !> @brief Store the file unit number
162  !!
163  !! Subroutine to convert the unit number for a open file to a file name
164  !! and indicate that there is an error reading from the file. By default,
165  !! the simulation is terminated when this subroutine is called.
166  !!
167  !<
168  subroutine store_error_unit(iunit, terminate)
169  ! -- dummy variables
170  integer(I4B), intent(in) :: iunit !< open file unit number
171  logical, optional, intent(in) :: terminate !< boolean indicating if the simulation should be terminated
172  ! -- local variables
173  logical :: lterminate
174  character(len=LINELENGTH) :: fname
175  character(len=LINELENGTH) :: errmsg
176  !
177  ! -- process optional variables
178  if (present(terminate)) then
179  lterminate = terminate
180  else
181  lterminate = .true.
182  end if
183  !
184  ! -- store error unit
185  call get_filename(iunit, fname)
186  write (errmsg, '(3a)') &
187  "Error occurred while reading file '", trim(adjustl(fname)), "'"
188  call sim_uniterrors%store(errmsg)
189  !
190  ! -- terminate the simulation
191  if (lterminate) then
192  call ustop()
193  end if
194 
195  end subroutine store_error_unit
196 
197  !> @brief Store the erroring file name
198  !!
199  !! Subroutine to store the file name issuing an error. By default,
200  !! the simulation is terminated when this subroutine is called
201  !!
202  !<
203  subroutine store_error_filename(filename, terminate)
204  ! -- dummy variables
205  character(len=*), intent(in) :: filename !< erroring file name
206  logical, optional, intent(in) :: terminate !< boolean indicating if the simulation should be terminated
207  ! -- local variables
208  logical :: lterminate
209  character(len=LINELENGTH) :: errmsg
210  !
211  ! -- process optional variables
212  if (present(terminate)) then
213  lterminate = terminate
214  else
215  lterminate = .true.
216  end if
217  !
218  ! -- store error unit
219  write (errmsg, '(3a)') &
220  "ERROR OCCURRED WHILE READING FILE '", trim(adjustl(filename)), "'"
221  call sim_uniterrors%store(errmsg)
222  !
223  ! -- terminate the simulation
224  if (lterminate) then
225  call ustop()
226  end if
227 
228  end subroutine store_error_filename
229 
230  !> @brief Store warning message
231  !!
232  !! Subroutine to store a warning message for printing at the end of
233  !! the simulation.
234  !!
235  !<
236  subroutine store_warning(msg, substring)
237  ! -- dummy variables
238  character(len=*), intent(in) :: msg !< warning message
239  character(len=*), intent(in), optional :: substring !< optional string that can be used
240  !! to prevent storing duplicate messages
241  !
242  ! -- store warning
243  if (present(substring)) then
244  call sim_warnings%store(msg, substring)
245  else
246  call sim_warnings%store(msg)
247  end if
248  end subroutine store_warning
249 
250  !> @brief Store deprecation warning message
251  !!
252  !! Subroutine to store a warning message for deprecated variables
253  !! and printing at the end of simulation.
254  !!
255  !<
256  subroutine deprecation_warning(cblock, cvar, cver, endmsg, iunit)
257  ! -- modules
259  ! -- dummy variables
260  character(len=*), intent(in) :: cblock !< block name
261  character(len=*), intent(in) :: cvar !< variable name
262  character(len=*), intent(in) :: cver !< version when variable was deprecated
263  character(len=*), intent(in), optional :: endmsg !< optional user defined message to append
264  !! at the end of the deprecation warning
265  integer(I4B), intent(in), optional :: iunit !< optional input file unit number with
266  !! the deprecated variable
267  ! -- local variables
268  character(len=MAXCHARLEN) :: message
269  character(len=LINELENGTH) :: fname
270  !
271  ! -- build message
272  write (message, '(a)') &
273  trim(cblock)//" BLOCK VARIABLE '"//trim(cvar)//"'"
274  if (present(iunit)) then
275  call get_filename(iunit, fname)
276  write (message, '(a,1x,3a)') &
277  trim(message), "IN FILE '", trim(fname), "'"
278  end if
279  write (message, '(a)') &
280  trim(message)//' WAS DEPRECATED IN VERSION '//trim(cver)//'.'
281  if (present(endmsg)) then
282  write (message, '(a,1x,2a)') trim(message), trim(endmsg), '.'
283  end if
284  !
285  ! -- store warning
286  call sim_warnings%store(message)
287 
288  end subroutine deprecation_warning
289 
290  !> @brief Store note
291  !!
292  !! Subroutine to store a note for printing at the end of the simulation.
293  !!
294  !<
295  subroutine store_note(note)
296  ! -- modules
298  ! -- dummy variables
299  character(len=*), intent(in) :: note !< note
300  !
301  ! -- store note
302  call sim_notes%store(note)
303 
304  end subroutine store_note
305 
306  !> @brief Stop the simulation.
307  !!
308  !! Subroutine to stop the simulations with option to print message
309  !! before stopping with the active error code.
310  !!
311  !<
312  subroutine ustop(stopmess, ioutlocal)
313  ! -- dummy variables
314  character, optional, intent(in) :: stopmess * (*) !< optional message to print before
315  !! stopping the simulation
316  integer(I4B), optional, intent(in) :: ioutlocal !< optional output file to
317  !! final message to
318  !
319  ! -- print the final message
320  call print_final_message(stopmess, ioutlocal)
321  !
322  ! -- terminate with the appropriate error code
323  call pstop(ireturnerr)
324 
325  end subroutine ustop
326 
327  !> @brief Print the final messages
328  !!
329  !! Subroutine to print the notes, warnings, errors and the final message (if passed).
330  !! The subroutine also closes all open files.
331  !!
332  !<
333  subroutine print_final_message(stopmess, ioutlocal)
334  ! -- dummy variables
335  character, optional, intent(in) :: stopmess * (*) !< optional message to print before
336  !! stopping the simulation
337  integer(I4B), optional, intent(in) :: ioutlocal !< optional output file to
338  !! final message to
339  ! -- local variables
340  character(len=*), parameter :: fmt = '(1x,a)'
341  character(len=*), parameter :: msg = 'Stopping due to error(s)'
342  !
343  ! -- print the accumulated messages
344  if (isim_level >= vall) then
345  call sim_notes%write_all('NOTES:', 'note(s)', &
346  iunit=iout)
347  call sim_warnings%write_all('WARNING REPORT:', 'warning(s)', &
348  iunit=iout)
349  end if
350  call sim_errors%write_all('ERROR REPORT:', 'error(s)', iunit=iout)
351  call sim_uniterrors%write_all('UNIT ERROR REPORT:', &
352  'file unit error(s)', iunit=iout)
353  !
354  ! -- write a stop message, if one is passed
355  if (present(stopmess)) then
356  if (stopmess .ne. ' ') then
357  call write_message(stopmess, fmt=fmt, iunit=iout)
358  call write_message(stopmess, fmt=fmt)
359  if (present(ioutlocal)) then
360  if (ioutlocal > 0 .and. ioutlocal /= iout) then
361  write (ioutlocal, fmt) trim(stopmess)
362  close (ioutlocal)
363  end if
364  end if
365  end if
366  end if
367  !
368  ! -- write console buffer output to stdout
369  flush (istdout)
370  !
371  ! -- determine if an error condition has occurred
372  if (sim_errors%count() > 0) then
373  ireturnerr = 2
374  if (present(ioutlocal)) then
375  if (ioutlocal > 0 .and. ioutlocal /= iout) write (ioutlocal, fmt) msg
376  end if
377  end if
378  !
379  ! -- close all open files
380  call sim_closefiles()
381 
382  end subroutine print_final_message
383 
384  !> @brief Reset the simulation convergence flag
385  !!
386  !! Subroutine to reset the simulation convergence flag.
387  !!
388  !<
389  subroutine converge_reset()
390  use simvariablesmodule, only: isimcnvg
391  isimcnvg = 1
392  end subroutine converge_reset
393 
394  !> @brief Simulation convergence check
395  !!
396  !! Subroutine to check simulation convergence. If the continue option is
397  !! set the simulation convergence flag is set to True if the simulation
398  !! did not actually converge for a time step and the non-convergence counter
399  !! is incremented.
400  !!
401  !<
402  subroutine converge_check(hasConverged)
403  ! -- modules
405  ! -- dummy variables
406  logical, intent(inout) :: hasconverged !< boolean indicting if the
407  !! simulation is considered converged
408  ! -- format
409  character(len=*), parameter :: fmtfail = &
410  "(1x, 'Simulation convergence failure.', &
411  &' Simulation will terminate after output and deallocation.')"
412  !
413  ! -- Initialize hasConverged to True
414  hasconverged = .true.
415  !
416  ! -- Count number of failures
417  if (isimcnvg == 0) then
419  end if
420  !
421  ! -- Continue if 'CONTINUE' specified in simulation control file
422  if (isimcontinue == 1) then
423  if (isimcnvg == 0) then
424  isimcnvg = 1
425  end if
426  end if
427  !
428  ! -- save simulation failure message
429  if (isimcnvg == 0) then
430  call write_message('', fmt=fmtfail, iunit=iout)
431  hasconverged = .false.
432  end if
433 
434  end subroutine converge_check
435 
436  !> @brief Print the header and initializes messaging
437  !!
438  !! Subroutine that prints the initial message and initializes the notes,
439  !! warning messages, unit errors, and error messages.
440  !!
441  !<
442  subroutine initial_message()
443  ! -- modules
446  !
447  ! -- initialize message lists
448  call sim_errors%init()
449  call sim_uniterrors%init()
450  call sim_warnings%init()
451  call sim_notes%init()
452  !
453  ! -- Write banner to screen (unit stdout)
454  call write_listfile_header(istdout, write_kind_info=.false., &
455  write_sys_command=.false.)
456  !
457  call write_message(' MODFLOW runs in '//trim(simulation_mode)//' mode', &
458  skipafter=1)
459  !
460  if (simulation_mode == 'PARALLEL' .and. nr_procs == 1) then
461  call store_warning('Running parallel MODFLOW on only 1 process')
462  end if
463  !
464  end subroutine initial_message
465 
466  !> @brief Create final message
467  !!
468  !! Subroutine that creates the appropriate final message and
469  !! terminates the program with an error message, if necessary.
470  !!
471  !<
472  subroutine final_message()
473  ! -- modules
476  ! -- formats
477  character(len=*), parameter :: fmtnocnvg = &
478  &"(1x, 'Simulation convergence failure occurred ', i0, ' time(s).')"
479  !
480  ! -- Write message if nonconvergence occurred in at least one timestep
481  if (numnoconverge > 0) then
482  write (warnmsg, fmtnocnvg) numnoconverge
483  if (isimcontinue == 0) then
484  call sim_errors%store(warnmsg)
485  else
486  call sim_warnings%store(warnmsg)
487  end if
488  end if
489  !
490  ! -- write final message
491  if (isimcnvg == 0) then
492  call print_final_message('Premature termination of simulation.', iout)
493  else
494  call print_final_message('Normal termination of simulation.', iout)
495  end if
496  !
497  ! -- If the simulation did not converge and the continue
498  ! option was not set, then set the return code to 1. The
499  ! purpose of setting the returncode this way is that the
500  ! program will terminate without a stop code if the simulation
501  ! reached the end and the continue flag was set, even if the
502  ! the simulation did not converge.
503  if (isimcnvg == 0 .and. isimcontinue == 0) then
504  ireturnerr = 1
505  end if
506  !
507  ! -- destroy messages
508  call sim_errors%deallocate()
509  call sim_uniterrors%deallocate()
510  call sim_warnings%deallocate()
511  call sim_notes%deallocate()
512  !
513  ! -- return or halt
514  if (iforcestop == 1) then
515  call pstop(ireturnerr)
516  end if
517 
518  end subroutine final_message
519 
520  !> @brief Close all open files
521  !!
522  !! Subroutine that closes all open files at the end of the simulation.
523  !!
524  !<
525  subroutine sim_closefiles()
526  ! -- local variables
527  integer(I4B) :: i
528  logical :: opened
529  character(len=7) :: output_file
530  !
531  ! -- close all open file units
532  do i = iustart, iunext - 1
533  !
534  ! -- determine if file unit i is open
535  inquire (unit=i, opened=opened)
536  !
537  ! -- skip file units that are no longer open
538  if (.not. opened) then
539  cycle
540  end if
541  !
542  ! -- flush the file if it can be written to
543  inquire (unit=i, write=output_file)
544  if (trim(adjustl(output_file)) == 'YES') then
545  flush (i)
546  end if
547  !
548  ! -- close file unit i
549  close (i)
550  end do
551 
552  end subroutine sim_closefiles
553 
554 end module simmodule
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
integer(i4b), parameter iulast
maximum file unit number (this allows for 9000 open files)
Definition: Constants.f90:58
integer(i4b), parameter iustart
starting file unit number
Definition: Constants.f90:57
@ osundef
unknown operating system
Definition: Constants.f90:196
@ oswin
Windows operating system.
Definition: Constants.f90:199
integer(i4b), parameter maxcharlen
maximum length of char string
Definition: Constants.f90:47
@ vsummary
write summary output
Definition: Constants.f90:188
@ vdebug
write debug output
Definition: Constants.f90:190
@ vall
write all simulation notes and warnings
Definition: Constants.f90:189
real(dp), parameter done
real constant 1
Definition: Constants.f90:76
integer(i4b) function, public get_os()
Get operating system.
Definition: defmacro.F90:17
subroutine pstop(status, message)
Stop the program, optionally specifying an error status code.
Definition: ErrorUtil.f90:24
This module defines variable data types.
Definition: kind.f90:8
Store and issue logging messages to output units.
Definition: Message.f90:2
subroutine, public write_message(text, iunit, fmt, skipbefore, skipafter, advance)
Write a message to an output unit.
Definition: Message.f90:210
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public ustop(stopmess, ioutlocal)
Stop the simulation.
Definition: Sim.f90:313
subroutine, public store_warning(msg, substring)
Store warning message.
Definition: Sim.f90:237
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
subroutine, public maxerrors(imax)
Set the maximum number of errors to be stored.
Definition: Sim.f90:85
type(messagestype) sim_uniterrors
Definition: Sim.f90:45
subroutine, public converge_reset()
Reset the simulation convergence flag.
Definition: Sim.f90:390
subroutine, public initial_message()
Print the header and initializes messaging.
Definition: Sim.f90:443
integer(i4b) function, public count_errors()
Return number of errors.
Definition: Sim.f90:59
subroutine sim_closefiles()
Close all open files.
Definition: Sim.f90:526
integer(i4b) function, public count_notes()
Return the number of notes stored.
Definition: Sim.f90:78
integer(i4b) function, public count_warnings()
Return number of warnings.
Definition: Sim.f90:71
subroutine, public final_message()
Create final message.
Definition: Sim.f90:473
subroutine, public deprecation_warning(cblock, cvar, cver, endmsg, iunit)
Store deprecation warning message.
Definition: Sim.f90:257
subroutine, public store_error_filename(filename, terminate)
Store the erroring file name.
Definition: Sim.f90:204
subroutine, public store_error_unit(iunit, terminate)
Store the file unit number.
Definition: Sim.f90:169
subroutine get_filename(iunit, fname)
Get the file name.
Definition: Sim.f90:124
type(messagestype) sim_warnings
Definition: Sim.f90:46
subroutine print_final_message(stopmess, ioutlocal)
Print the final messages.
Definition: Sim.f90:334
type(messagestype) sim_notes
Definition: Sim.f90:47
type(messagestype) sim_errors
Definition: Sim.f90:44
subroutine, public store_note(note)
Store note.
Definition: Sim.f90:296
subroutine, public converge_check(hasConverged)
Simulation convergence check.
Definition: Sim.f90:403
This module contains simulation variables.
Definition: SimVariables.f90:9
integer(i4b) iforcestop
forced stop flag (1) forces a call to ustop(..) when the simulation has ended, (0) doesn't
integer(i4b) isimcontinue
simulation continue flag (1) to continue if isimcnvg = 0, (0) to terminate
character(len=linelength) simulation_mode
integer(i4b) nr_procs
integer(i4b) isim_level
simulation output level
integer(i4b) ireturnerr
return code for program (0) successful, (1) non-convergence, (2) error
character(len=maxcharlen) warnmsg
warning message string
integer(i4b) numnoconverge
number of times the simulation did not converge
integer(i4b) iout
file unit number for simulation output
integer(i4b) iunext
next file unit number to assign
integer(i4b) istdout
unit number for stdout
integer(i4b) isimcnvg
simulation convergence flag (1) if all objects have converged, (0) otherwise
This module contains version information.
Definition: version.f90:7
subroutine write_listfile_header(iout, cmodel_type, write_sys_command, write_kind_info)
@ brief Write program header
Definition: version.f90:103
Container for related messages.
Definition: Message.f90:21