MOM6
MOM_file_parser.F90
Go to the documentation of this file.
2 !***********************************************************************
3 !* GNU General Public License *
4 !* This file is a part of MOM. *
5 !* *
6 !* MOM is free software; you can redistribute it and/or modify it and *
7 !* are expected to follow the terms of the GNU General Public License *
8 !* as published by the Free Software Foundation; either version 2 of *
9 !* the License, or (at your option) any later version. *
10 !* *
11 !* MOM is distributed in the hope that it will be useful, but WITHOUT *
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
13 !* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public *
14 !* License for more details. *
15 !* *
16 !* For the full text of the GNU General Public License, *
17 !* write to: Free Software Foundation, Inc., *
18 !* 675 Mass Ave, Cambridge, MA 02139, USA. *
19 !* or see: http://www.gnu.org/licenses/gpl.html *
20 !***********************************************************************
21 
22 !********+*********+*********+*********+*********+*********+*********+**
23 !* *
24 !* By Robert Hallberg and Alistair Adcroft, updated 9/2013. *
25 !* *
26 !* The subroutines here parse a set of input files for the value *
27 !* a named parameter and sets that parameter at run time. Currently *
28 !* these files use use one of several formats: *
29 !* #define VAR ! To set the logical VAR to true. *
30 !* VAR = True ! To set the logical VAR to true. *
31 !* #undef VAR ! To set the logical VAR to false. *
32 !* VAR = False ! To set the logical VAR to false. *
33 !* #define VAR 999 ! To set the real or integer VAR to 999. *
34 !* VAR = 999 ! To set the real or integer VAR to 999. *
35 !* #override VAR = 888 ! To override a previously set value. *
36 !* VAR = 1.1, 2.2, 3.3 ! To set an array of real values. *
37 !* *
38 !* In addition, when set by the get_param interface, the values of *
39 !* parameters are automatically logged, along with defaults, units, *
40 !* and a description. It is an error for a variable to be overridden *
41 !* more than once, and MOM6 has a facility to check for unused lines *
42 !* to set variables, which may indicate miss-spelled or archaic *
43 !* parameters. Parameter names are case-specific, and lines may use *
44 !* a F90 or C++ style comment, starting with ! or //. *
45 !* *
46 !********+*********+*********+*********+*********+*********+*********+**
47 
48 use mom_coms, only : root_pe, broadcast
49 use mom_error_handler, only : mom_error, fatal, warning, mom_mesg
50 use mom_error_handler, only : is_root_pe, stdlog, stdout
51 use mom_time_manager, only : set_time, get_time, time_type, get_ticks_per_second
52 use mom_time_manager, only : set_date, get_date
57 
58 implicit none ; private
59 
60 integer, parameter, public :: max_param_files = 5 ! Maximum number of parameter files.
61 integer, parameter :: input_str_length = 200 ! Maximum linelength in parameter file.
62 integer, parameter :: filename_length = 200 ! Maximum number of characters in
63  ! file names.
64 
65 ! The all_PEs_read option should be eliminated with post-riga shared code.
66 logical :: all_pes_read = .false.
67 
68 ! Defaults
69 logical, parameter :: report_unused_default = .false.
70 logical, parameter :: unused_params_fatal_default = .false.
71 logical, parameter :: log_to_stdout_default = .false.
72 logical, parameter :: complete_doc_default = .true.
73 logical, parameter :: minimal_doc_default = .true.
74 
75 type, private :: file_data_type ; private
76  integer :: num_lines = 0
77  character(len=INPUT_STR_LENGTH), pointer, dimension(:) :: line => null()
78  logical, pointer, dimension(:) :: line_used => null()
79 end type file_data_type
80 
81 type :: link_parameter ; private
82  type(link_parameter), pointer :: next => null() ! Facilitates linked list
83  character(len=80) :: name ! Parameter name
84  logical :: hasissuedoverridewarning = .false. ! Has a default value
85 end type link_parameter
86 
87 type :: parameter_block ; private
88  character(len=240) :: name = '' ! Parameter name
89 end type parameter_block
90 
91 type, public :: param_file_type ; private
92  integer :: nfiles = 0 ! The number of open files.
93  integer :: iounit(max_param_files) ! The unit number of an open file.
94  character(len=FILENAME_LENGTH) :: filename(max_param_files) ! The names of the open files.
95  logical :: netcdf_file(max_param_files)! If true, the input file is in NetCDF.
96  ! This is not yet implemented.
97  type(file_data_type) :: param_data(max_param_files) ! Structures that contain
98  ! the valid data lines from the parameter
99  ! files, enabling all subsequent reads of
100  ! parameter data to occur internally.
101  logical :: report_unused = report_unused_default ! If true, report any
102  ! parameter lines that are not used in the run.
103  logical :: unused_params_fatal = unused_params_fatal_default ! If true, kill
104  ! the run if there are any unused parameters.
105  logical :: log_to_stdout = log_to_stdout_default ! If true, all log
106  ! messages are also sent to stdout.
107  logical :: log_open = .false. ! True if the log file has been opened.
108  integer :: stdout, stdlog ! The units from stdout() and stdlog().
109  character(len=240) :: doc_file ! A file where all run-time parameters, their
110  ! settings and defaults are documented.
111  logical :: complete_doc = complete_doc_default ! If true, document all
112  ! run-time parameters.
113  logical :: minimal_doc = minimal_doc_default ! If true, document only those
114  ! run-time parameters that differ from defaults.
115  type(doc_type), pointer :: doc => null() ! A structure that contains information
116  ! related to parameter documentation.
117  type(link_parameter), pointer :: chain => null() ! Facilitates linked list
118  type(parameter_block), pointer :: blockname => null() ! Name of active parameter block
119 end type param_file_type
120 
122 public doc_param, get_param
124 
125 interface read_param
129 end interface
130 interface log_param
131  module procedure log_param_int, log_param_real, log_param_logical, &
134 end interface
135 interface get_param
136  module procedure get_param_int, get_param_real, get_param_logical, &
139 end interface
140 interface log_version
141  module procedure log_version_cs, log_version_plain
142 end interface
143 
144 contains
145 
146 subroutine open_param_file(filename, CS, checkable, component, doc_file_dir)
147  character(len=*), intent(in) :: filename
148  type(param_file_type), intent(inout) :: CS
149  logical, optional, intent(in) :: checkable
150  character(len=*), optional, intent(in) :: component
151  character(len=*), optional, intent(in) :: doc_file_dir
152 
153  logical :: file_exists, unit_in_use, Netcdf_file, may_check
154  integer :: ios, iounit, strlen, i
155  character(len=240) :: doc_path
156  type(parameter_block), pointer :: block
157 
158  may_check = .true. ; if (present(checkable)) may_check = checkable
159 
160  ! Check for non-blank filename
161  strlen = len_trim(filename)
162  if (strlen == 0) then
163  call mom_error(fatal, "open_param_file: Input file has not been specified.")
164  endif
165 
166  ! Check that this file has not already been opened
167  if (cs%nfiles > 0) then
168  inquire(file=trim(filename), number=iounit)
169  if (iounit /= -1) then
170  do i = 1, cs%nfiles
171  if (cs%iounit(i) == iounit) then
172  if (trim(cs%filename(1)) /= trim(filename)) then
173  call mom_error(fatal, &
174  "open_param_file: internal inconsistency! "//trim(filename)// &
175  " is registered as open but has the wrong unit number!")
176  else
177  call mom_error(warning, &
178  "open_param_file: file "//trim(filename)// &
179  " has already been opened. This should NOT happen!"// &
180  " Did you specify the same file twice in a namelist?")
181  return
182  endif ! filenames
183  endif ! unit numbers
184  enddo ! i
185  endif
186  endif
187 
188  ! Check that the file exists to readstdlog
189  inquire(file=trim(filename), exist=file_exists)
190  if (.not.file_exists) call mom_error(fatal, &
191  "open_param_file: Input file "// trim(filename)//" does not exist.")
192 
193  netcdf_file = .false.
194  if (strlen > 3) then
195  if (filename(strlen-2:strlen) == ".nc") netcdf_file = .true.
196  endif
197 
198  if (netcdf_file) &
199  call mom_error(fatal,"open_param_file: NetCDF files are not yet supported.")
200 
201  if (all_pes_read .or. is_root_pe()) then
202  ! Find an unused unit number.
203  do iounit=10,512
204  INQUIRE(iounit,opened=unit_in_use) ; if (.not.unit_in_use) exit
205  enddo
206  if (iounit >= 512) call mom_error(fatal, &
207  "open_param_file: No unused file unit could be found.")
208 
209  ! Open the parameter file.
210  open(iounit, file=trim(filename), access='SEQUENTIAL', &
211  form='FORMATTED', action='READ', position='REWIND', iostat=ios)
212  if (ios /= 0) call mom_error(fatal, "open_param_file: Error opening "// &
213  trim(filename))
214  else
215  iounit = 1
216  endif
217 
218  ! Store/register the unit and details
219  i = cs%nfiles + 1
220  cs%nfiles = i
221  cs%iounit(i) = iounit
222  cs%filename(i) = filename
223  cs%NetCDF_file(i) = netcdf_file
224  allocate(block) ; block%name = '' ; cs%blockName => block
225 
226  call mom_mesg("open_param_file: "// trim(filename)// &
227  " has been opened successfully.", 5)
228 
229  call populate_param_data(iounit, filename, cs%param_data(i))
230 
231  call read_param(cs,"SEND_LOG_TO_STDOUT",cs%log_to_stdout)
232  call read_param(cs,"REPORT_UNUSED_PARAMS",cs%report_unused)
233  call read_param(cs,"FATAL_UNUSED_PARAMS",cs%unused_params_fatal)
234  cs%doc_file = "MOM_parameter_doc"
235  if (present(component)) cs%doc_file = trim(component)//"_parameter_doc"
236  call read_param(cs,"DOCUMENT_FILE", cs%doc_file)
237  if (.not.may_check) then
238  cs%report_unused = .false.
239  cs%unused_params_fatal = .false.
240  endif
241 
242  ! Open the log file.
243  cs%stdlog = stdlog() ; cs%stdout = stdout()
244  cs%log_open = (stdlog() > 0)
245 
246  doc_path = cs%doc_file
247  if (len_trim(cs%doc_file) > 0) then
248  cs%complete_doc = complete_doc_default
249  call read_param(cs, "COMPLETE_DOCUMENTATION", cs%complete_doc)
250  cs%minimal_doc = minimal_doc_default
251  call read_param(cs, "MINIMAL_DOCUMENTATION", cs%minimal_doc)
252  if (present(doc_file_dir)) then ; if (len_trim(doc_file_dir) > 0) then
253  doc_path = trim(slasher(doc_file_dir))//trim(cs%doc_file)
254  endif ; endif
255  else
256  cs%complete_doc = .false.
257  cs%minimal_doc = .false.
258  endif
259  call doc_init(doc_path, cs%doc, cs%minimal_doc, cs%complete_doc)
260 
261 end subroutine open_param_file
262 
263 subroutine close_param_file(CS, quiet_close, component)
264  type(param_file_type), intent(inout) :: CS
265  logical, optional, intent(in) :: quiet_close
266  character(len=*), optional, intent(in) :: component
267 ! Arguments: CS - the param_file_type to close
268 ! (in,opt) quiet_close - if present and true, do not do any logging with this
269 ! call.
270 ! This include declares and sets the variable "version".
271 #include "version_variable.h"
272  character(len=128) :: docfile_default
273  character(len=40) :: mdl ! This module's name.
274  integer :: i, n, num_unused
275 
276  if (present(quiet_close)) then ; if (quiet_close) then
277  do i = 1, cs%nfiles
278  if (all_pes_read .or. is_root_pe()) close(cs%iounit(i))
279  call mom_mesg("close_param_file: "// trim(cs%filename(i))// &
280  " has been closed successfully.", 5)
281  cs%iounit(i) = -1
282  cs%filename(i) = ''
283  cs%NetCDF_file(i) = .false.
284  deallocate (cs%param_data(i)%line)
285  deallocate (cs%param_data(i)%line_used)
286  enddo
287  cs%log_open = .false.
288  call doc_end(cs%doc)
289  return
290  endif ; endif
291 
292  ! Log the parameters for the parser.
293  mdl = "MOM_file_parser"
294  call log_version(cs, mdl, version, "")
295  call log_param(cs, mdl, "SEND_LOG_TO_STDOUT", &
296  cs%log_to_stdout, &
297  "If true, all log messages are also sent to stdout.", &
298  default=log_to_stdout_default)
299  call log_param(cs, mdl, "REPORT_UNUSED_PARAMS", &
300  cs%report_unused, &
301  "If true, report any parameter lines that are not used \n"//&
302  "in the run.", default=report_unused_default)
303  call log_param(cs, mdl, "FATAL_UNUSED_PARAMS", &
304  cs%unused_params_fatal, &
305  "If true, kill the run if there are any unused \n"//&
306  "parameters.", default=unused_params_fatal_default)
307  docfile_default = "MOM_parameter_doc"
308  if (present(component)) docfile_default = trim(component)//"_parameter_doc"
309  call log_param(cs, mdl, "DOCUMENT_FILE", cs%doc_file, &
310  "The basename for files where run-time parameters, their\n"//&
311  "settings, units and defaults are documented. Blank will\n"//&
312  "disable all parameter documentation.", default=docfile_default)
313  if (len_trim(cs%doc_file) > 0) then
314  call log_param(cs, mdl, "COMPLETE_DOCUMENTATION", &
315  cs%complete_doc, &
316  "If true, all run-time parameters are\n"//&
317  "documented in "//trim(cs%doc_file)//&
318  ".all .", default=complete_doc_default)
319  call log_param(cs, mdl, "MINIMAL_DOCUMENTATION", &
320  cs%minimal_doc, &
321  "If true, non-default run-time parameters are\n"//&
322  "documented in "//trim(cs%doc_file)//&
323  ".short .", default=minimal_doc_default)
324  endif
325 
326  num_unused = 0
327  do i = 1, cs%nfiles
328  if (is_root_pe() .and. (cs%report_unused .or. &
329  cs%unused_params_fatal)) then
330  ! Check for unused lines.
331  do n=1,cs%param_data(i)%num_lines
332  if (.not.cs%param_data(i)%line_used(n)) then
333  num_unused = num_unused + 1
334  if (cs%report_unused) &
335  call mom_error(warning, "Unused line in "//trim(cs%filename(i))// &
336  " : "//trim(cs%param_data(i)%line(n)))
337  endif
338  enddo
339  endif
340 
341  if (all_pes_read .or. is_root_pe()) close(cs%iounit(i))
342  call mom_mesg("close_param_file: "// trim(cs%filename(i))// &
343  " has been closed successfully.", 5)
344  cs%iounit(i) = -1
345  cs%filename(i) = ''
346  cs%NetCDF_file(i) = .false.
347  deallocate (cs%param_data(i)%line)
348  deallocate (cs%param_data(i)%line_used)
349  enddo
350 
351  if (is_root_pe() .and. (num_unused>0) .and. cs%unused_params_fatal) &
352  call mom_error(fatal, "Run stopped because of unused parameter lines.")
353 
354  cs%log_open = .false.
355  call doc_end(cs%doc)
356 
357 end subroutine close_param_file
358 
359 subroutine populate_param_data(iounit, filename, param_data)
360  integer, intent(in) :: iounit
361  character(len=*), intent(in) :: filename
362  type(file_data_type), intent(inout) :: param_data
363 
364  character(len=INPUT_STR_LENGTH) :: line
365  integer :: num_lines
366  logical :: inMultiLineComment
367 
368 ! Find the number of keyword lines in a parameter file
369 ! Allocate the space to hold the lines in param_data%line
370 ! Populate param_data%line with the keyword lines from parameter file
371 
372  if (iounit <= 0) return
373 
374  if (all_pes_read .or. is_root_pe()) then
375  ! rewind the parameter file
376  rewind(iounit)
377 
378  ! count the number of valid entries in the parameter file
379  num_lines = 0
380  inmultilinecomment = .false.
381  do while(.true.)
382  read(iounit, '(a)', end=8, err=9) line
383  line = replacetabs(line)
384  if (inmultilinecomment) then
385  if (closemultilinecomment(line)) inmultilinecomment=.false.
386  else
387  if (lastnoncommentnonblank(line)>0) num_lines = num_lines + 1
388  if (openmultilinecomment(line)) inmultilinecomment=.true.
389  endif
390  enddo ! while (.true.)
391  8 continue ! get here when read() reaches EOF
392 
393  if (inmultilinecomment .and. is_root_pe()) &
394  call mom_error(fatal, 'MOM_file_parser : A C-style multi-line comment '// &
395  '(/* ... */) was not closed before the end of '//trim(filename))
396 
397  ! allocate space to hold contents of the parameter file
398  param_data%num_lines = num_lines
399  endif ! (is_root_pe())
400 
401  ! Broadcast the number of valid entries in parameter file
402  if (.not. all_pes_read) then
403  call broadcast(param_data%num_lines, root_pe())
404  endif
405 
406  ! Set up the space for storing the actual lines.
407  num_lines = param_data%num_lines
408  allocate (param_data%line(num_lines))
409  allocate (param_data%line_used(num_lines))
410  param_data%line(:) = ' '
411  param_data%line_used(:) = .false.
412 
413  ! Read the actual lines.
414  if (all_pes_read .or. is_root_pe()) then
415  ! rewind the parameter file
416  rewind(iounit)
417 
418  ! Populate param_data%line
419  num_lines = 0
420  do while(.true.)
421  read(iounit, '(a)', end=18, err=9) line
422  line = replacetabs(line)
423  if (inmultilinecomment) then
424  if (closemultilinecomment(line)) inmultilinecomment=.false.
425  else
426  if (lastnoncommentnonblank(line)>0) then
427  line = removecomments(line)
428  line = simplifywhitespace(line(:len_trim(line)))
429  num_lines = num_lines + 1
430  param_data%line(num_lines) = line
431  endif
432  if (openmultilinecomment(line)) inmultilinecomment=.true.
433  endif
434  enddo ! while (.true.)
435 18 continue ! get here when read() reaches EOF
436 
437  if (num_lines /= param_data%num_lines) &
438  call mom_error(fatal, 'MOM_file_parser : Found different number of '// &
439  'valid lines on second reading of '//trim(filename))
440  endif ! (is_root_pe())
441 
442  ! Broadcast the populated array param_data%line
443  if (.not. all_pes_read) then
444  call broadcast(param_data%line, input_str_length, root_pe())
445  endif
446 
447  return
448 
449 9 call mom_error(fatal, "MOM_file_parser : "//&
450  "Error while reading file "//trim(filename))
451 
452 end subroutine populate_param_data
453 
454 function openmultilinecomment(string)
455  character(len=*), intent(in) :: string
456  logical :: openMultiLineComment
457 ! True if a /* appears on this line without a closing */
458  integer :: icom, last
459  openmultilinecomment = .false.
460  last = lastnoncommentindex(string)+1
461  icom = index(string(last:), "/*")
462  if (icom > 0) then
463  openmultilinecomment=.true.
464  last = last+icom+1
465  endif
466  icom = index(string(last:), "*/") ; if (icom > 0) openmultilinecomment=.false.
467 end function openmultilinecomment
468 
469 function closemultilinecomment(string)
470  character(len=*), intent(in) :: string
471  logical :: closeMultiLineComment
472 ! True if a */ appears on this line
473  closemultilinecomment = .false.
474  if (index(string, "*/")>0) closemultilinecomment=.true.
475 end function closemultilinecomment
476 
477 function lastnoncommentindex(string)
478  character(len=*), intent(in) :: string
479  integer :: lastNonCommentIndex
480 ! Find position of last character before any comments
481 ! This s/r is the only place where a comment needs to be defined
482  integer :: icom, last
483  last = len_trim(string)
484  icom = index(string(:last), "!") ; if (icom > 0) last = icom-1 ! F90 style
485  icom = index(string(:last), "//") ; if (icom > 0) last = icom-1 ! C+ style
486  icom = index(string(:last), "/*") ; if (icom > 0) last = icom-1 ! C style
487  lastnoncommentindex = last
488 end function lastnoncommentindex
489 
490 function lastnoncommentnonblank(string)
491  character(len=*), intent(in) :: string
492  integer :: lastNonCommentNonBlank
493 ! Find position of last non-blank character before any comments
494  lastnoncommentnonblank = len_trim(string(:lastnoncommentindex(string))) ! Ignore remaining trailing blanks
495 end function lastnoncommentnonblank
496 
497 function replacetabs(string)
498  character(len=*), intent(in) :: string
499  character(len=len(string)) :: replaceTabs
500 ! Returns string with tabs replaced by a ablank
501  integer :: i
502  do i=1, len(string)
503  if (string(i:i)==achar(9)) then
504  replacetabs(i:i)=" "
505  else
506  replacetabs(i:i)=string(i:i)
507  endif
508  enddo
509 end function replacetabs
510 
511 function removecomments(string)
512  character(len=*), intent(in) :: string
513  character(len=len(string)) :: removeComments
514 ! Trims comments and leading blanks from string
515  integer :: last
516  removecomments=repeat(" ",len(string))
517  last = lastnoncommentnonblank(string)
518  removecomments(:last)=adjustl(string(:last)) ! Copy only the non-comment part of string
519 end function removecomments
520 
521 function simplifywhitespace(string)
522  character(len=*), intent(in) :: string
523  character(len=len(string)+16) :: simplifyWhiteSpace
524 ! Constructs a string with all repeated whitespace replaced with single blanks
525 ! and insert white space where it helps delineate tokens (e.g. around =)
526  integer :: i,j
527  logical :: nonBlank = .false., insidestring = .false.
528  character(len=1) :: quoteChar=" "
529  nonblank = .false.; insidestring = .false. ! NOTE: For some reason this line is needed??
530  i=0
531  simplifywhitespace=repeat(" ",len(string)+16)
532  do j=1,len_trim(string)
533  if (insidestring) then ! Do not change formatting inside strings
534  i=i+1
535  simplifywhitespace(i:i)=string(j:j)
536  if (string(j:j)==quotechar) insidestring=.false. ! End of string
537  else ! The following is outside of string delimiters
538  if (string(j:j)==" " .or. string(j:j)==achar(9)) then ! Space or tab
539  if (nonblank) then ! Only copy a blank if the preceeding character was non-blank
540  i=i+1
541  simplifywhitespace(i:i)=" " ! Not string(j:j) so that tabs are replace by blanks
542  nonblank=.false.
543  endif
544  elseif (string(j:j)=='"' .or. string(j:j)=="'") then ! Start a sting
545  i=i+1
546  simplifywhitespace(i:i)=string(j:j)
547  insidestring=.true.
548  quotechar=string(j:j) ! Keep copy of starting quote
549  nonblank=.true. ! For exit from string
550  elseif (string(j:j)=='=') then
551  ! Insert spaces if this character is "=" so that line contains " = "
552  if (nonblank) then
553  i=i+1
554  simplifywhitespace(i:i)=" "
555  endif
556  i=i+2
557  simplifywhitespace(i-1:i)=string(j:j)//" "
558  nonblank=.false.
559  else ! All other characters
560  i=i+1
561  simplifywhitespace(i:i)=string(j:j)
562  nonblank=.true.
563  endif
564  endif ! if (insideString)
565  enddo ! j
566  if (insidestring) then ! A missing close quote should be flagged
567  if (is_root_pe()) call mom_error(fatal, &
568  "There is a mismatched quote in the parameter file line: "// &
569  trim(string))
570  endif
571 end function simplifywhitespace
572 
573 subroutine read_param_int(CS, varname, value, fail_if_missing)
574  type(param_file_type), intent(in) :: CS
575  character(len=*), intent(in) :: varname
576  integer, intent(inout) :: value
577  logical, optional, intent(in) :: fail_if_missing
578 ! This subroutine determines the value of an integer model parameter
579 ! from a parameter file. The arguments are the unit of the open file
580 ! which is to be read, the (case-sensitive) variable name, the variable
581 ! where the value is to be stored, and (optionally) a flag indicating
582 ! whether to fail if this parameter can not be found.
583  character(len=INPUT_STR_LENGTH) :: value_string(1)
584  logical :: found, defined
585 
586  call get_variable_line(cs, varname, found, defined, value_string)
587  if (found .and. defined .and. (len_trim(value_string(1)) > 0)) then
588  read(value_string(1),*,err = 1001) value
589  else
590  if (present(fail_if_missing)) then ; if (fail_if_missing) then
591  if (.not.found) then
592  call mom_error(fatal,'read_param_int: Unable to find variable '//trim(varname)// &
593  ' in any input files.')
594  else
595  call mom_error(fatal,'read_param_int: Variable '//trim(varname)// &
596  ' found but not set in input files.')
597  endif
598  endif ; endif
599  endif
600  return
601  1001 call mom_error(fatal,'read_param_int: read error for integer variable '//trim(varname)// &
602  ' parsing "'//trim(value_string(1))//'"')
603 end subroutine read_param_int
604 
605 subroutine read_param_int_array(CS, varname, value, fail_if_missing)
606  type(param_file_type), intent(in) :: CS
607  character(len=*), intent(in) :: varname
608  integer, intent(inout) :: value(:)
609  logical, optional, intent(in) :: fail_if_missing
610 ! This subroutine determines the value of an integer model parameter
611 ! from a parameter file. The arguments are the unit of the open file
612 ! which is to be read, the (case-sensitive) variable name, the variable
613 ! where the value is to be stored, and (optionally) a flag indicating
614 ! whether to fail if this parameter can not be found.
615  character(len=INPUT_STR_LENGTH) :: value_string(1)
616  logical :: found, defined
617 
618  call get_variable_line(cs, varname, found, defined, value_string)
619  if (found .and. defined .and. (len_trim(value_string(1)) > 0)) then
620  read(value_string(1),*,end=991,err=1002) value
621  991 return
622  else
623  if (present(fail_if_missing)) then ; if (fail_if_missing) then
624  if (.not.found) then
625  call mom_error(fatal,'read_param_int_array: Unable to find variable '//trim(varname)// &
626  ' in any input files.')
627  else
628  call mom_error(fatal,'read_param_int_array: Variable '//trim(varname)// &
629  ' found but not set in input files.')
630  endif
631  endif ; endif
632  endif
633  return
634  1002 call mom_error(fatal,'read_param_int_array: read error for integer array '//trim(varname)// &
635  ' parsing "'//trim(value_string(1))//'"')
636 end subroutine read_param_int_array
637 
638 subroutine read_param_real(CS, varname, value, fail_if_missing)
639  type(param_file_type), intent(in) :: CS
640  character(len=*), intent(in) :: varname
641  real, intent(inout) :: value
642  logical, optional, intent(in) :: fail_if_missing
643 ! This subroutine determines the value of an integer model parameter
644 ! from a parameter file. The arguments are the unit of the open file
645 ! which is to be read, the (case-sensitive) variable name, the variable
646 ! where the value is to be stored, and (optionally) a flag indicating
647 ! whether to fail if this parameter can not be found.
648  character(len=INPUT_STR_LENGTH) :: value_string(1)
649  logical :: found, defined
650 
651  call get_variable_line(cs, varname, found, defined, value_string)
652  if (found .and. defined .and. (len_trim(value_string(1)) > 0)) then
653  read(value_string(1),*,err=1003) value
654  else
655  if (present(fail_if_missing)) then ; if (fail_if_missing) then
656  if (.not.found) then
657  call mom_error(fatal,'read_param_real: Unable to find variable '//trim(varname)// &
658  ' in any input files.')
659  else
660  call mom_error(fatal,'read_param_real: Variable '//trim(varname)// &
661  ' found but not set in input files.')
662  endif
663  endif ; endif
664  endif
665  return
666  1003 call mom_error(fatal,'read_param_real: read error for real variable '//trim(varname)// &
667  ' parsing "'//trim(value_string(1))//'"')
668 end subroutine read_param_real
669 
670 subroutine read_param_real_array(CS, varname, value, fail_if_missing)
671  type(param_file_type), intent(in) :: CS
672  character(len=*), intent(in) :: varname
673  real, intent(inout) :: value(:)
674  logical, optional, intent(in) :: fail_if_missing
675 ! This subroutine determines the value of an integer model parameter
676 ! from a parameter file. The arguments are the unit of the open file
677 ! which is to be read, the (case-sensitive) variable name, the variable
678 ! where the value is to be stored, and (optionally) a flag indicating
679 ! whether to fail if this parameter can not be found.
680  character(len=INPUT_STR_LENGTH) :: value_string(1)
681  logical :: found, defined
682 
683  call get_variable_line(cs, varname, found, defined, value_string)
684  if (found .and. defined .and. (len_trim(value_string(1)) > 0)) then
685  read(value_string(1),*,end=991,err=1004) value
686  991 return
687  else
688  if (present(fail_if_missing)) then ; if (fail_if_missing) then
689  if (.not.found) then
690  call mom_error(fatal,'read_param_real_array: Unable to find variable '//trim(varname)// &
691  ' in any input files.')
692  else
693  call mom_error(fatal,'read_param_real_array: Variable '//trim(varname)// &
694  ' found but not set in input files.')
695  endif
696  endif ; endif
697  endif
698  return
699  1004 call mom_error(fatal,'read_param_real_array: read error for real array '//trim(varname)// &
700  ' parsing "'//trim(value_string(1))//'"')
701 end subroutine read_param_real_array
702 
703 subroutine read_param_char(CS, varname, value, fail_if_missing)
704  type(param_file_type), intent(in) :: CS
705  character(len=*), intent(in) :: varname
706  character(len=*), intent(inout) :: value
707  logical, optional, intent(in) :: fail_if_missing
708 ! This subroutine determines the value of an integer model parameter
709 ! from a parameter file. The arguments are the unit of the open file
710 ! which is to be read, the (case-sensitive) variable name, the variable
711 ! where the value is to be stored, and (optionally) a flag indicating
712 ! whether to fail if this parameter can not be found.
713  character(len=INPUT_STR_LENGTH) :: value_string(1)
714  logical :: found, defined
715 
716  call get_variable_line(cs, varname, found, defined, value_string)
717  if (found) then
718  value = trim(strip_quotes(value_string(1)))
719  elseif (present(fail_if_missing)) then ; if (fail_if_missing) then
720  call mom_error(fatal,'Unable to find variable '//trim(varname)// &
721  ' in any input files.')
722  endif ; endif
723 
724 end subroutine read_param_char
725 
726 subroutine read_param_char_array(CS, varname, value, fail_if_missing)
727  type(param_file_type), intent(in) :: CS
728  character(len=*), intent(in) :: varname
729  character(len=*), intent(inout) :: value(:)
730  logical, optional, intent(in) :: fail_if_missing
731 ! This subroutine determines the value of an integer model parameter
732 ! from a parameter file. The arguments are the unit of the open file
733 ! which is to be read, the (case-sensitive) variable name, the variable
734 ! where the value is to be stored, and (optionally) a flag indicating
735 ! whether to fail if this parameter can not be found.
736  character(len=INPUT_STR_LENGTH) :: value_string(1), loc_string
737  logical :: found, defined
738  integer :: i, i_out
739 
740  call get_variable_line(cs, varname, found, defined, value_string)
741  if (found) then
742  loc_string = trim(value_string(1))
743  i = index(loc_string,",")
744  i_out = 1
745  do while(i>0)
746  value(i_out) = trim(strip_quotes(loc_string(:i-1)))
747  i_out = i_out+1
748  loc_string = trim(adjustl(loc_string(i+1:)))
749  i = index(loc_string,",")
750  enddo
751  if (len_trim(loc_string)>0) then
752  value(i_out) = trim(strip_quotes(adjustl(loc_string)))
753  i_out = i_out+1
754  endif
755  do i=i_out,SIZE(value) ; value(i) = " " ; enddo
756  elseif (present(fail_if_missing)) then ; if (fail_if_missing) then
757  call mom_error(fatal,'Unable to find variable '//trim(varname)// &
758  ' in any input files.')
759  endif ; endif
760 
761 end subroutine read_param_char_array
762 
763 subroutine read_param_logical(CS, varname, value, fail_if_missing)
764  type(param_file_type), intent(in) :: CS
765  character(len=*), intent(in) :: varname
766  logical, intent(inout) :: value
767  logical, optional, intent(in) :: fail_if_missing
768 ! This subroutine determines the value of an integer model parameter
769 ! from a parameter file. The arguments are the unit of the open file
770 ! which is to be read, the (case-sensitive) variable name, the variable
771 ! where the value is to be stored, and (optionally) a flag indicating
772 ! whether to fail if this parameter can not be found.
773  character(len=INPUT_STR_LENGTH) :: value_string(1)
774  logical :: found, defined
775 
776  call get_variable_line(cs, varname, found, defined, value_string, paramislogical=.true.)
777  if (found) then
778  value = defined
779  elseif (present(fail_if_missing)) then ; if (fail_if_missing) then
780  call mom_error(fatal,'Unable to find variable '//trim(varname)// &
781  ' in any input files.')
782  endif ; endif
783 end subroutine read_param_logical
784 
785 
786 subroutine read_param_time(CS, varname, value, timeunit, fail_if_missing, date_format)
787  type(param_file_type), intent(in) :: CS
788  character(len=*), intent(in) :: varname
789  type(time_type), intent(inout) :: value
790  real, optional, intent(in) :: timeunit
791  logical, optional, intent(in) :: fail_if_missing
792  logical, optional, intent(out) :: date_format
793 ! This subroutine determines the value of an time-type model parameter
794 ! from a parameter file. The arguments are the unit of the open file
795 ! which is to be read, the (case-sensitive) variable name, the variable
796 ! where the value is to be stored, and (optionally) a flag indicating
797 ! whether to fail if this parameter can not be found. The unique argument
798 ! to read time is the number of seconds to use as the unit of time being read.
799  character(len=INPUT_STR_LENGTH) :: value_string(1)
800  character(len=240) :: err_msg
801  logical :: found, defined
802  real :: real_time, time_unit
803  integer :: days, secs, vals(7)
804 
805  if (present(date_format)) date_format = .false.
806 
807  call get_variable_line(cs, varname, found, defined, value_string)
808  if (found .and. defined .and. (len_trim(value_string(1)) > 0)) then
809  ! Determine whether value string should be parsed for a real number
810  ! or a date, in either a string format or a comma-delimited list of values.
811  if ((index(value_string(1),'-') > 0) .and. &
812  (index(value_string(1),'-',back=.true.) > index(value_string(1),'-'))) then
813  ! There are two dashes, so this must be a date format.
814  value = set_date(value_string(1), err_msg=err_msg)
815  if (len_trim(err_msg) > 0) call mom_error(fatal,'read_param_time: '//&
816  trim(err_msg)//' in integer list read error for time-type variable '//&
817  trim(varname)// ' parsing "'//trim(value_string(1))//'"')
818  if (present(date_format)) date_format = .true.
819  elseif (index(value_string(1),',') > 0) then
820  ! Initialize vals with an invalid date.
821  vals(:) = (/ -999, -999, -999, 0, 0, 0, 0 /)
822  read(value_string(1),*,end=995,err=1005) vals
823  995 continue
824  if ((vals(1) < 0) .or. (vals(2) < 0) .or. (vals(3) < 0)) &
825  call mom_error(fatal,'read_param_time: integer list read error for time-type variable '//&
826  trim(varname)// ' parsing "'//trim(value_string(1))//'"')
827  value = set_date(vals(1), vals(2), vals(3), vals(4), vals(5), vals(6), &
828  vals(7), err_msg=err_msg)
829  if (len_trim(err_msg) > 0) call mom_error(fatal,'read_param_time: '//&
830  trim(err_msg)//' in integer list read error for time-type variable '//&
831  trim(varname)// ' parsing "'//trim(value_string(1))//'"')
832  if (present(date_format)) date_format = .true.
833  else
834  time_unit = 1.0 ; if (present(timeunit)) time_unit = timeunit
835  read( value_string(1), *) real_time
836  days = int(real_time*(time_unit/86400.0))
837  secs = int(floor((real_time*(time_unit/86400.0)-days)*86400.0 + 0.5))
838  value = set_time(secs, days)
839  endif
840  else
841  if (present(fail_if_missing)) then ; if (fail_if_missing) then
842  if (.not.found) then
843  call mom_error(fatal,'Unable to find variable '//trim(varname)// &
844  ' in any input files.')
845  else
846  call mom_error(fatal,'Variable '//trim(varname)// &
847  ' found but not set in input files.')
848  endif
849  endif ; endif
850  endif
851  return
852  1005 call mom_error(fatal,'read_param_time: read error for time-type variable '//&
853  trim(varname)// ' parsing "'//trim(value_string(1))//'"')
854 end subroutine read_param_time
855 
856 function strip_quotes(val_str)
857  character(len=*) :: val_str
858  character(len=INPUT_STR_LENGTH) :: strip_quotes
859  ! Local variables
860  integer :: i
861  strip_quotes = val_str
862  i = index(strip_quotes,achar(34)) ! Double quote
863  do while (i>0)
864  if (i > 1) then ; strip_quotes = strip_quotes(:i-1)//strip_quotes(i+1:)
865  else ; strip_quotes = strip_quotes(2:) ; endif
866  i = index(strip_quotes,achar(34)) ! Double quote
867  enddo
868  i = index(strip_quotes,achar(39)) ! Single quote
869  do while (i>0)
870  if (i > 1) then ; strip_quotes = strip_quotes(:i-1)//strip_quotes(i+1:)
871  else ; strip_quotes = strip_quotes(2:) ; endif
872  i = index(strip_quotes,achar(39)) ! Single quote
873  enddo
874 end function strip_quotes
875 
876 subroutine get_variable_line(CS, varname, found, defined, value_string, paramIsLogical)
877  type(param_file_type), intent(in) :: CS
878  character(len=*), intent(in) :: varname
879  logical, intent(out) :: found, defined
880  character(len=*), intent(out) :: value_string(:)
881  logical, optional, intent(in) :: paramIsLogical
882 
883  character(len=INPUT_STR_LENGTH) :: val_str, lname, origLine
884  character(len=INPUT_STR_LENGTH) :: line, continuationBuffer, blockName
885  character(len=FILENAME_LENGTH) :: filename
886  integer :: is, id, isd, isu, ise, iso, verbose, ipf
887  integer :: last, last1, ival, oval, max_vals, count, contBufSize
888  character(len=52) :: set
889  logical :: found_override, found_equals
890  logical :: found_define, found_undef
891  logical :: force_cycle, defined_in_line, continuedLine
892  logical :: variableKindIsLogical, valueIsSame
893  logical :: inWrongBlock, fullPathParameter
894  logical, parameter :: requireNamedClose = .false.
895  set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
896  continuationbuffer = repeat(" ",input_str_length)
897  contbufsize = 0
898  verbose = 1
899 
900  variablekindislogical=.false.
901  if (present(paramislogical)) variablekindislogical = paramislogical
902 
903  ! Find the first instance (if any) where the named variable is found, and
904  ! return variables indicating whether this variable is defined and the string
905  ! that contains the value of this variable.
906  found = .false.
907  oval = 0; ival = 0;
908  max_vals = SIZE(value_string)
909  do is=1,max_vals ; value_string(is) = " " ; enddo
910 
911  paramfile_loop: do ipf = 1, cs%nfiles
912  filename = cs%filename(ipf)
913  continuedline = .false.
914  blockname = ''
915 
916  ! Scan through each line of the file
917  do count = 1, cs%param_data(ipf)%num_lines
918  line = cs%param_data(ipf)%line(count)
919  last = len_trim(line)
920 
921  last1 = max(1,last)
922  ! Check if line ends in continuation character (either & or \)
923  ! Note achar(92) is a backslash
924  if (line(last1:last1) == achar(92).or.line(last1:last1) == "&") then
925  continuationbuffer(contbufsize+1:contbufsize+len_trim(line))=line(:last-1)
926  contbufsize=contbufsize + len_trim(line)-1
927  continuedline = .true.
928  if (count==cs%param_data(ipf)%num_lines .and. is_root_pe()) &
929  call mom_error(fatal, "MOM_file_parser : the last line"// &
930  " of the file ends in a continuation character but"// &
931  " there are no more lines to read. "// &
932  " Line: '"//trim(line(:last))//"'"//&
933  " in file "//trim(filename)//".")
934  cycle ! cycle inorder to append the next line of the file
935  elseif (continuedline) then
936  ! If we reached this point then this is the end of line continuation
937  continuationbuffer(contbufsize+1:contbufsize+len_trim(line))=line(:last)
938  line = continuationbuffer
939  continuationbuffer=repeat(" ",input_str_length) ! Clear for next use
940  contbufsize = 0
941  continuedline = .false.
942  last = len_trim(line)
943  endif
944 
945  origline = trim(line) ! Keep original for error messages
946 
947  ! Check for '#override' at start of line
948  found_override = .false.; found_define = .false.; found_undef = .false.
949  iso = index(line(:last), "#override " )!; if (is > 0) found_override = .true.
950  if (iso>1) call mom_error(fatal, "MOM_file_parser : #override was found "// &
951  " but was not the first keyword."// &
952  " Line: '"//trim(line(:last))//"'"//&
953  " in file "//trim(filename)//".")
954  if (iso==1) then
955  found_override = .true.
956  if (index(line(:last), "#override define ")==1) found_define = .true.
957  if (index(line(:last), "#override undef ")==1) found_undef = .true.
958  line = trim(adjustl(line(iso+10:last))); last = len_trim(line)
959  endif
960 
961  ! Check for start of fortran namelist, ie. '&namelist'
962  if (index(line(:last),'&')==1) then
963  iso=index(line(:last),' ')
964  if (iso>0) then ! possibly simething else on this line
965  blockname = pushblocklevel(blockname,line(2:iso-1))
966  line=trim(adjustl(line(iso:last)))
967  last=len_trim(line)
968  if (last==0) cycle ! nothing else on this line
969  else ! just the namelist on this line
970  if (len_trim(blockname)>0) then
971  blockname = trim(blockname) // '%' //trim(line(2:last))
972  else
973  blockname = trim(line(2:last))
974  endif
975  call flag_line_as_read(cs%param_data(ipf)%line_used,count)
976  cycle
977  endif
978  endif
979 
980  ! Newer form of parameter block, block%, %block or block%param or
981  iso=index(line(:last),'%')
982  fullpathparameter = .false.
983  if (iso==1) then ! % is first character means this is a close
984  if (len_trim(blockname)==0 .and. is_root_pe()) call mom_error(fatal, &
985  'get_variable_line: An extra close block was encountered. Line="'// &
986  trim(line(:last))//'"' )
987  if (last>1 .and. trim(blockname)/=trim(line(2:last)) .and. is_root_pe()) &
988  call mom_error(fatal, 'get_variable_line: A named close for a parameter'// &
989  ' block did not match the open block. Line="'//trim(line(:last))//'"' )
990  if (last==1 .and. requirenamedclose) & ! line = '%' is a generic (unnamed) close
991  call mom_error(fatal, 'get_variable_line: A named close for a parameter'// &
992  ' block is required but found "%". Block="'//trim(blockname)//'"' )
993  blockname = popblocklevel(blockname)
994  call flag_line_as_read(cs%param_data(ipf)%line_used,count)
995  elseif (iso==last) then ! This is a new block if % is last character
996  blockname = pushblocklevel(blockname, line(:iso-1))
997  call flag_line_as_read(cs%param_data(ipf)%line_used,count)
998  else ! This is of the form block%parameter = ... (full path parameter)
999  iso=index(line(:last),'%',.true.)
1000  ! Check that the parameter block names on the line matches the state set by the caller
1001  if (iso>0 .and. trim(cs%blockName%name)==trim(line(:iso-1))) then
1002  fullpathparameter = .true.
1003  line = trim(line(iso+1:last)) ! Strip away the block name for subsequent processing
1004  last = len_trim(line)
1005  endif
1006  endif
1007 
1008  ! We should only interpret this line if this block is the active block
1009  inwrongblock = .false.
1010  if (len_trim(blockname)>0) then ! In a namelist block in file
1011  if (trim(cs%blockName%name)/=trim(blockname)) inwrongblock = .true. ! Not in the required block
1012  endif
1013  if (len_trim(cs%blockName%name)>0) then ! In a namelist block in the model
1014  if (trim(cs%blockName%name)/=trim(blockname)) inwrongblock = .true. ! Not in the required block
1015  endif
1016 
1017  ! Check for termination of a fortran namelist (with a '/')
1018  if (line(last:last)=='/') then
1019  if (len_trim(blockname)==0 .and. is_root_pe()) call mom_error(fatal, &
1020  'get_variable_line: An extra namelist/block end was encountered. Line="'// &
1021  trim(line(:last))//'"' )
1022  blockname = popblocklevel(blockname)
1023  last = last - 1 ! Ignore the termination character from here on
1024  endif
1025  if (inwrongblock .and. .not. fullpathparameter) then
1026  if (index(" "//line(:last+1), " "//trim(varname)//" ")>0) &
1027  call mom_error(warning,"MOM_file_parser : "//trim(varname)// &
1028  ' found outside of block '//trim(cs%blockName%name)//'%. Ignoring.')
1029  cycle
1030  endif
1031 
1032  ! Determine whether this line mentions the named parameter or not
1033  if (index(" "//line(:last)//" ", " "//trim(varname)//" ") == 0) cycle
1034 
1035  ! Detect keywords
1036  found_equals = .false.
1037  isd = index(line(:last), "define" )!; if (isd > 0) found_define = .true.
1038  isu = index(line(:last), "undef" )!; if (isu > 0) found_undef = .true.
1039  ise = index(line(:last), " = " ); if (ise > 1) found_equals = .true.
1040  if (index(line(:last), "#define ")==1) found_define = .true.
1041  if (index(line(:last), "#undef ")==1) found_undef = .true.
1042 
1043  ! Check for missing, mutually exclusive or incomplete keywords
1044  if (is_root_pe()) then
1045  if (.not. (found_define .or. found_undef .or. found_equals)) &
1046  call mom_error(fatal, "MOM_file_parser : the parameter name '"// &
1047  trim(varname)//"' was found without define or undef."// &
1048  " Line: '"//trim(line(:last))//"'"//&
1049  " in file "//trim(filename)//".")
1050  if (found_define .and. found_undef) call mom_error(fatal, &
1051  "MOM_file_parser : Both 'undef' and 'define' occur."// &
1052  " Line: '"//trim(line(:last))//"'"//&
1053  " in file "//trim(filename)//".")
1054  if (found_equals .and. (found_define .or. found_undef)) &
1055  call mom_error(fatal, &
1056  "MOM_file_parser : Both 'a=b' and 'undef/define' syntax occur."// &
1057  " Line: '"//trim(line(:last))//"'"//&
1058  " in file "//trim(filename)//".")
1059  if (found_override .and. .not. (found_define .or. found_undef .or. found_equals)) &
1060  call mom_error(fatal, "MOM_file_parser : override was found "// &
1061  " without a define or undef."// &
1062  " Line: '"//trim(line(:last))//"'"//&
1063  " in file "//trim(filename)//".")
1064  endif
1065 
1066  ! Interpret the line and collect values, if any
1067  if (found_define) then
1068  ! Move starting pointer to first letter of defined name.
1069  is = isd + 5 + scan(line(isd+6:last), set)
1070 
1071  id = scan(line(is:last), ' ') ! Find space between name and value
1072  if ( id == 0 ) then
1073  ! There is no space so the name is simply being defined.
1074  lname = trim(line(is:last))
1075  if (trim(lname) /= trim(varname)) cycle
1076  val_str = " "
1077  else
1078  ! There is a string or number after the name.
1079  lname = trim(line(is:is+id-1))
1080  if (trim(lname) /= trim(varname)) cycle
1081  val_str = trim(adjustl(line(is+id:last)))
1082  endif
1083  found = .true. ; defined_in_line = .true.
1084  elseif (found_undef) then
1085  ! Move starting pointer to first letter of undefined name.
1086  is = isu + 4 + scan(line(isu+5:last), set)
1087 
1088  id = scan(line(is:last), ' ') ! Find the first space after the name.
1089  if (id > 0) last = is + id - 1
1090  lname = trim(line(is:last))
1091  if (trim(lname) /= trim(varname)) cycle
1092  val_str = " "
1093  found = .true. ; defined_in_line = .false.
1094  elseif (found_equals) then
1095  ! Move starting pointer to first letter of defined name.
1096  is = scan(line(1:ise), set)
1097  lname = trim(line(is:ise-1))
1098  if (trim(lname) /= trim(varname)) cycle
1099  val_str = trim(adjustl(line(ise+3:last)))
1100  if (variablekindislogical) then ! Special handling for logicals
1101  read(val_str(:len_trim(val_str)),*) defined_in_line
1102  else
1103  defined_in_line = .true.
1104  endif
1105  found = .true.
1106  else
1107  call mom_error(fatal, "MOM_file_parser (non-root PE?): the parameter name '"// &
1108  trim(varname)//"' was found without an assignment, define or undef."// &
1109  " Line: '"//trim(line(:last))//"'"//" in file "//trim(filename)//".")
1110  endif
1111 
1112  ! This line has now been used.
1113  call flag_line_as_read(cs%param_data(ipf)%line_used,count)
1114 
1115  ! Detect inconsistencies
1116  force_cycle = .false.
1117  valueissame = (trim(val_str) == trim(value_string(max_vals)))
1118  if (found_override .and. (oval >= max_vals)) then
1119  if (is_root_pe()) then
1120  if ((defined_in_line .neqv. defined) .or. .not. valueissame) then
1121  call mom_error(fatal,"MOM_file_parser : "//trim(varname)// &
1122  " found with multiple inconsistent overrides."// &
1123  " Line A: '"//trim(value_string(max_vals))//"'"//&
1124  " Line B: '"//trim(line(:last))//"'"//&
1125  " in file "//trim(filename)//" caused the model failure.")
1126  else
1127  call mom_error(warning,"MOM_file_parser : "//trim(varname)// &
1128  " over-ridden more times than is permitted."// &
1129  " Line: '"//trim(line(:last))//"'"//&
1130  " in file "//trim(filename)//" is being ignored.")
1131  endif
1132  endif
1133  force_cycle = .true.
1134  endif
1135  if (.not.found_override .and. (oval > 0)) then
1136  if (is_root_pe()) &
1137  call mom_error(warning,"MOM_file_parser : "//trim(varname)// &
1138  " has already been over-ridden."// &
1139  " Line: '"//trim(line(:last))//"'"//&
1140  " in file "//trim(filename)//" is being ignored.")
1141  force_cycle = .true.
1142  endif
1143  if (.not.found_override .and. (ival >= max_vals)) then
1144  if (is_root_pe()) then
1145  if ((defined_in_line .neqv. defined) .or. .not. valueissame) then
1146  call mom_error(fatal,"MOM_file_parser : "//trim(varname)// &
1147  " found with multiple inconsistent definitions."// &
1148  " Line A: '"//trim(value_string(max_vals))//"'"//&
1149  " Line B: '"//trim(line(:last))//"'"//&
1150  " in file "//trim(filename)//" caused the model failure.")
1151  else
1152  call mom_error(warning,"MOM_file_parser : "//trim(varname)// &
1153  " occurs more times than is permitted."// &
1154  " Line: '"//trim(line(:last))//"'"//&
1155  " in file "//trim(filename)//" is being ignored.")
1156  endif
1157  endif
1158  force_cycle = .true.
1159  endif
1160  if (force_cycle) cycle
1161 
1162  ! Store new values
1163  if (found_override) then
1164  oval = oval + 1
1165  value_string(oval) = trim(val_str)
1166  defined = defined_in_line
1167  if (verbose > 0 .and. ival > 0 .and. is_root_pe() .and. &
1168  .not. overridewarninghasbeenissued(cs%chain, trim(varname)) ) &
1169  call mom_error(warning,"MOM_file_parser : "//trim(varname)// &
1170  " over-ridden. Line: '"//trim(line(:last))//"'"//&
1171  " in file "//trim(filename)//".")
1172  else ! (.not. found_overide)
1173  ival = ival + 1
1174  value_string(ival) = trim(val_str)
1175  defined = defined_in_line
1176  if (verbose > 1 .and. is_root_pe()) &
1177  call mom_error(warning,"MOM_file_parser : "//trim(varname)// &
1178  " set. Line: '"//trim(line(:last))//"'"//&
1179  " in file "//trim(filename)//".")
1180  endif
1181 
1182  enddo ! CS%param_data(ipf)%num_lines
1183 
1184  if (len_trim(blockname)>0 .and. is_root_pe()) call mom_error(fatal, &
1185  'A namelist/parameter block was not closed. Last open block appears '// &
1186  'to be "'//trim(blockname)//'".')
1187 
1188  enddo paramfile_loop
1189 
1190 end subroutine get_variable_line
1191 
1192 subroutine flag_line_as_read(line_used,count)
1193  logical, dimension(:), pointer :: line_used
1194  integer, intent(in) :: count
1195  line_used(count) = .true.
1196 end subroutine flag_line_as_read
1197 
1198 function overridewarninghasbeenissued(chain, varName)
1199  type(link_parameter), pointer :: chain
1200  character(len=*), intent(in) :: varName
1201  logical :: overrideWarningHasBeenIssued
1202 ! Returns true if an override warning has been issued for the variable varName
1203  type(link_parameter), pointer :: newLink, this
1204  overridewarninghasbeenissued = .false.
1205  this => chain
1206  do while( associated(this) )
1207  if (trim(varname) == trim(this%name)) then
1208  overridewarninghasbeenissued = .true.
1209  return
1210  endif
1211  this => this%next
1212  enddo
1213  allocate(newlink)
1214  newlink%name = trim(varname)
1215  newlink%hasIssuedOverrideWarning = .true.
1216  newlink%next => chain
1217  chain => newlink
1218 end function overridewarninghasbeenissued
1219 
1220 ! The following subroutines write out to a log file.
1221 
1222 !> Log the version of a module to a log file and/or stdout, and/or to the
1223 !! parameter documentation file.
1224 subroutine log_version_cs(CS, modulename, version, desc)
1225  type(param_file_type), intent(in) :: CS !< File parser type
1226  character(len=*), intent(in) :: modulename !< Name of calling module
1227  character(len=*), intent(in) :: version !< Version string of module
1228  character(len=*), optional, intent(in) :: desc !< Module description
1229  ! Local variables
1230  character(len=240) :: mesg
1231 
1232  mesg = trim(modulename)//": "//trim(version)
1233  if (is_root_pe()) then
1234  if (cs%log_open) write(cs%stdlog,'(a)') trim(mesg)
1235  if (cs%log_to_stdout) write(cs%stdout,'(a)') trim(mesg)
1236  endif
1237 
1238  if (present(desc)) call doc_module(cs%doc, modulename, desc)
1239 
1240 end subroutine log_version_cs
1241 
1242 !> Log the version of a module to a log file and/or stdout.
1243 subroutine log_version_plain(modulename, version)
1244  character(len=*), intent(in) :: modulename !< Name of calling module
1245  character(len=*), intent(in) :: version !< Version string of module
1246  ! Local variables
1247  character(len=240) :: mesg
1248 
1249  mesg = trim(modulename)//": "//trim(version)
1250  if (is_root_pe()) then
1251  write(stdlog(),'(a)') trim(mesg)
1252  endif
1253 
1254 end subroutine log_version_plain
1255 
1256 subroutine log_param_int(CS, modulename, varname, value, desc, units, &
1257  default, layoutParam)
1258  type(param_file_type), intent(in) :: CS
1259  character(len=*), intent(in) :: modulename
1260  character(len=*), intent(in) :: varname
1261  integer, intent(in) :: value
1262  character(len=*), optional, intent(in) :: desc, units
1263  integer, optional, intent(in) :: default
1264  logical, optional, intent(in) :: layoutParam
1265 ! This subroutine writes the value of an integer parameter to a log file,
1266 ! along with its name and the module it came from.
1267  character(len=240) :: mesg, myunits
1268 
1269  write(mesg, '(" ",a," ",a,": ",a)') trim(modulename), trim(varname), trim(left_int(value))
1270  if (is_root_pe()) then
1271  if (cs%log_open) write(cs%stdlog,'(a)') trim(mesg)
1272  if (cs%log_to_stdout) write(cs%stdout,'(a)') trim(mesg)
1273  endif
1274 
1275  myunits=" "; if (present(units)) write(myunits(1:240),'(A)') trim(units)
1276  if (present(desc)) &
1277  call doc_param(cs%doc, varname, desc, myunits, value, default, &
1278  layoutparam=layoutparam)
1279 
1280 end subroutine log_param_int
1281 
1282 subroutine log_param_int_array(CS, modulename, varname, value, desc, &
1283  units, default, layoutParam)
1284  type(param_file_type), intent(in) :: CS
1285  character(len=*), intent(in) :: modulename
1286  character(len=*), intent(in) :: varname
1287  integer, intent(in) :: value(:)
1288  character(len=*), optional, intent(in) :: desc, units
1289  integer, optional, intent(in) :: default
1290  logical, optional, intent(in) :: layoutParam
1291 ! This subroutine writes the value of an integer parameter to a log file,
1292 ! along with its name and the module it came from.
1293  character(len=1320) :: mesg
1294  character(len=240) :: myunits
1295 
1296  write(mesg, '(" ",a," ",a,": ",A)') trim(modulename), trim(varname), trim(left_ints(value))
1297  if (is_root_pe()) then
1298  if (cs%log_open) write(cs%stdlog,'(a)') trim(mesg)
1299  if (cs%log_to_stdout) write(cs%stdout,'(a)') trim(mesg)
1300  endif
1301 
1302  myunits=" "; if (present(units)) write(myunits(1:240),'(A)') trim(units)
1303  if (present(desc)) &
1304  call doc_param(cs%doc, varname, desc, myunits, value, default, &
1305  layoutparam=layoutparam)
1306 
1307 end subroutine log_param_int_array
1308 
1309 subroutine log_param_real(CS, modulename, varname, value, desc, units, &
1310  default)
1311  type(param_file_type), intent(in) :: CS
1312  character(len=*), intent(in) :: modulename
1313  character(len=*), intent(in) :: varname
1314  real, intent(in) :: value
1315  character(len=*), optional, intent(in) :: desc, units
1316  real, optional, intent(in) :: default
1317 ! This subroutine writes the value of a real parameter to a log file,
1318 ! along with its name and the module it came from.
1319  character(len=240) :: mesg, myunits
1320 
1321  write(mesg, '(" ",a," ",a,": ",a)') &
1322  trim(modulename), trim(varname), trim(left_real(value))
1323  if (is_root_pe()) then
1324  if (cs%log_open) write(cs%stdlog,'(a)') trim(mesg)
1325  if (cs%log_to_stdout) write(cs%stdout,'(a)') trim(mesg)
1326  endif
1327 
1328  myunits="not defined"; if (present(units)) write(myunits(1:240),'(A)') trim(units)
1329  if (present(desc)) &
1330  call doc_param(cs%doc, varname, desc, myunits, value, default)
1331 
1332 end subroutine log_param_real
1333 
1334 subroutine log_param_real_array(CS, modulename, varname, value, desc, &
1335  units, default)
1336  type(param_file_type), intent(in) :: CS
1337  character(len=*), intent(in) :: modulename
1338  character(len=*), intent(in) :: varname
1339  real, intent(in) :: value(:)
1340  character(len=*), optional, intent(in) :: desc, units
1341  real, optional, intent(in) :: default
1342 ! This subroutine writes the value of a real parameter to a log file,
1343 ! along with its name and the module it came from.
1344  character(len=1320) :: mesg
1345  character(len=240) :: myunits
1346 
1347  !write(mesg, '(" ",a," ",a,": ",ES19.12,99(",",ES19.12))') &
1348  !write(mesg, '(" ",a," ",a,": ",G,99(",",G))') &
1349  ! trim(modulename), trim(varname), value
1350  write(mesg, '(" ",a," ",a,": ",a)') &
1351  trim(modulename), trim(varname), trim(left_reals(value))
1352  if (is_root_pe()) then
1353  if (cs%log_open) write(cs%stdlog,'(a)') trim(mesg)
1354  if (cs%log_to_stdout) write(cs%stdout,'(a)') trim(mesg)
1355  endif
1356 
1357  myunits="not defined"; if (present(units)) write(myunits(1:240),'(A)') trim(units)
1358  if (present(desc)) &
1359  call doc_param(cs%doc, varname, desc, myunits, value, default)
1360 
1361 end subroutine log_param_real_array
1362 
1363 subroutine log_param_logical(CS, modulename, varname, value, desc, &
1364  units, default, layoutParam)
1365  type(param_file_type), intent(in) :: CS
1366  character(len=*), intent(in) :: modulename
1367  character(len=*), intent(in) :: varname
1368  logical, intent(in) :: value
1369  character(len=*), optional, intent(in) :: desc, units
1370  logical, optional, intent(in) :: default
1371  logical, optional, intent(in) :: layoutParam
1372 ! This subroutine writes the value of a logical parameter to a log file,
1373 ! along with its name and the module it came from.
1374  character(len=240) :: mesg, myunits
1375 
1376  if (value) then
1377  write(mesg, '(" ",a," ",a,": True")') trim(modulename), trim(varname)
1378  else
1379  write(mesg, '(" ",a," ",a,": False")') trim(modulename), trim(varname)
1380  endif
1381  if (is_root_pe()) then
1382  if (cs%log_open) write(cs%stdlog,'(a)') trim(mesg)
1383  if (cs%log_to_stdout) write(cs%stdout,'(a)') trim(mesg)
1384  endif
1385 
1386  myunits="Boolean"; if (present(units)) write(myunits(1:240),'(A)') trim(units)
1387  if (present(desc)) &
1388  call doc_param(cs%doc, varname, desc, myunits, value, default, &
1389  layoutparam=layoutparam)
1390 
1391 end subroutine log_param_logical
1392 
1393 subroutine log_param_char(CS, modulename, varname, value, desc, units, &
1394  default, layoutParam)
1395  type(param_file_type), intent(in) :: CS
1396  character(len=*), intent(in) :: modulename
1397  character(len=*), intent(in) :: varname
1398  character(len=*), intent(in) :: value
1399  character(len=*), optional, intent(in) :: desc, units
1400  character(len=*), optional, intent(in) :: default
1401  logical, optional, intent(in) :: layoutParam
1402 ! This subroutine writes the value of a character string parameter to a log
1403 ! file, along with its name and the module it came from.
1404  character(len=240) :: mesg, myunits
1405 
1406  write(mesg, '(" ",a," ",a,": ",a)') &
1407  trim(modulename), trim(varname), trim(value)
1408  if (is_root_pe()) then
1409  if (cs%log_open) write(cs%stdlog,'(a)') trim(mesg)
1410  if (cs%log_to_stdout) write(cs%stdout,'(a)') trim(mesg)
1411  endif
1412 
1413  myunits=" "; if (present(units)) write(myunits(1:240),'(A)') trim(units)
1414  if (present(desc)) &
1415  call doc_param(cs%doc, varname, desc, myunits, value, default, &
1416  layoutparam=layoutparam)
1417 
1418 end subroutine log_param_char
1419 
1420 !> This subroutine writes the value of a time-type parameter to a log file,
1421 !! along with its name and the module it came from.
1422 subroutine log_param_time(CS, modulename, varname, value, desc, units, &
1423  default, timeunit, layoutParam, log_date)
1424  type(param_file_type), intent(in) :: CS
1425  character(len=*), intent(in) :: modulename
1426  character(len=*), intent(in) :: varname
1427  type(time_type), intent(in) :: value
1428  character(len=*), optional, intent(in) :: desc, units
1429  type(time_type), optional, intent(in) :: default
1430  real, optional, intent(in) :: timeunit
1431  logical, optional, intent(in) :: log_date !< If true, log the time_type in date format.
1432  logical, optional, intent(in) :: layoutParam
1433 
1434  real :: real_time, real_default
1435  logical :: use_timeunit, date_format
1436  character(len=240) :: mesg, myunits
1437  character(len=80) :: date_string, default_string
1438  integer :: days, secs, ticks, ticks_per_sec
1439 
1440  use_timeunit = .false.
1441  date_format = .false. ; if (present(log_date)) date_format = log_date
1442 
1443  call get_time(value, secs, days, ticks)
1444 
1445  if (ticks == 0) then
1446  write(mesg, '(" ",a," ",a," (Time): ",i0,":",i0)') trim(modulename), &
1447  trim(varname), days, secs
1448  else
1449  write(mesg, '(" ",a," ",a," (Time): ",i0,":",i0,":",i0)') trim(modulename), &
1450  trim(varname), days, secs, ticks
1451  endif
1452  if (is_root_pe()) then
1453  if (cs%log_open) write(cs%stdlog,'(a)') trim(mesg)
1454  if (cs%log_to_stdout) write(cs%stdout,'(a)') trim(mesg)
1455  endif
1456 
1457  if (present(desc)) then
1458  if (present(timeunit)) use_timeunit = (timeunit > 0.0)
1459  if (date_format) then
1460  myunits='[date]'
1461 
1462  date_string = convert_date_to_string(value)
1463  if (present(default)) then
1464  default_string = convert_date_to_string(default)
1465  call doc_param(cs%doc, varname, desc, myunits, date_string, &
1466  default=default_string, layoutparam=layoutparam)
1467  else
1468  call doc_param(cs%doc, varname, desc, myunits, date_string, &
1469  layoutparam=layoutparam)
1470  endif
1471  elseif (use_timeunit) then
1472  if (present(units)) then
1473  write(myunits(1:240),'(A)') trim(units)
1474  else
1475  if (abs(timeunit-1.0) < 0.01) then ; myunits = "seconds"
1476  elseif (abs(timeunit-3600.0) < 1.0) then ; myunits = "hours"
1477  elseif (abs(timeunit-86400.0) < 1.0) then ; myunits = "days"
1478  elseif (abs(timeunit-3.1e7) < 1.0e6) then ; myunits = "years"
1479  else ; write(myunits,'(es8.2," sec")') timeunit ; endif
1480  endif
1481  real_time = (86400.0/timeunit)*days + secs/timeunit
1482  if (ticks > 0) real_time = real_time + &
1483  real(ticks) / (timeunit*get_ticks_per_second())
1484  if (present(default)) then
1485  call get_time(default, secs, days, ticks)
1486  real_default = (86400.0/timeunit)*days + secs/timeunit
1487  if (ticks > 0) real_default = real_default + &
1488  real(ticks) / (timeunit*get_ticks_per_second())
1489  call doc_param(cs%doc, varname, desc, myunits, real_time, real_default)
1490  else
1491  call doc_param(cs%doc, varname, desc, myunits, real_time)
1492  endif
1493  else
1494  myunits='not defined'; if (present(units)) write(myunits(1:240),'(A)') trim(units)
1495  call doc_param(cs%doc, varname, desc, myunits, value, default)
1496  endif
1497  endif
1498 
1499 end subroutine log_param_time
1500 
1501 !> This function converts a date into a string, valid with ticks and for dates up to year 99,999,999
1502 function convert_date_to_string(date) result(date_string)
1503  type(time_type), intent(in) :: date !< The date to be translated into a string.
1504  character(len=40) :: date_string !< A date string in a format like YYYY-MM-DD HH:MM:SS.sss
1505 
1506  character(len=40) :: sub_string
1507  real :: real_secs
1508  integer :: yrs, mons, days, hours, mins, secs, ticks, ticks_per_sec
1509 
1510  call get_date(date, yrs, mons, days, hours, mins, secs, ticks)
1511  write (date_string, '(i8.4)') yrs
1512  write (sub_string, '("-", i2.2, "-", I2.2, " ", i2.2, ":", i2.2, ":")') &
1513  mons, days, hours, mins
1514  date_string = trim(adjustl(date_string)) // trim(sub_string)
1515  if (ticks > 0) then
1516  ticks_per_sec = get_ticks_per_second()
1517  real_secs = secs + ticks/ticks_per_sec
1518  if (ticks_per_sec <= 100) then
1519  write (sub_string, '(F7.3)') real_secs
1520  else
1521  write (sub_string, '(F10.6)') real_secs
1522  endif
1523  else
1524  write (sub_string, '(i2.2)') secs
1525  endif
1526  date_string = trim(date_string) // trim(adjustl(sub_string))
1527 
1528 end function convert_date_to_string
1529 
1530 subroutine get_param_int(CS, modulename, varname, value, desc, units, &
1531  default, fail_if_missing, do_not_read, do_not_log, &
1532  static_value, layoutParam)
1533  type(param_file_type), intent(in) :: CS
1534  character(len=*), intent(in) :: modulename
1535  character(len=*), intent(in) :: varname
1536  integer, intent(inout) :: value
1537  character(len=*), optional, intent(in) :: desc, units
1538  integer, optional, intent(in) :: default, static_value
1539  logical, optional, intent(in) :: fail_if_missing
1540  logical, optional, intent(in) :: do_not_read, do_not_log
1541  logical, optional, intent(in) :: layoutParam
1542 ! This subroutine writes the value of a real parameter to a log file,
1543 ! along with its name and the module it came from.
1544  logical :: do_read, do_log
1545 
1546  do_read = .true. ; if (present(do_not_read)) do_read = .not.do_not_read
1547  do_log = .true. ; if (present(do_not_log)) do_log = .not.do_not_log
1548 
1549  if (do_read) then
1550  if (present(default)) value = default
1551  if (present(static_value)) value = static_value
1552  call read_param_int(cs, varname, value, fail_if_missing)
1553  endif
1554 
1555  if (do_log) then
1556  call log_param_int(cs, modulename, varname, value, desc, units, &
1557  default, layoutparam)
1558  endif
1559 
1560 end subroutine get_param_int
1561 
1562 subroutine get_param_int_array(CS, modulename, varname, value, desc, units, &
1563  default, fail_if_missing, do_not_read, do_not_log, &
1564  static_value, layoutParam)
1565  type(param_file_type), intent(in) :: CS
1566  character(len=*), intent(in) :: modulename
1567  character(len=*), intent(in) :: varname
1568  integer, intent(inout) :: value(:)
1569  character(len=*), optional, intent(in) :: desc, units
1570  integer, optional, intent(in) :: default, static_value
1571  logical, optional, intent(in) :: fail_if_missing
1572  logical, optional, intent(in) :: do_not_read, do_not_log
1573  logical, optional, intent(in) :: layoutParam
1574 ! This subroutine writes the value of a real parameter to a log file,
1575 ! along with its name and the module it came from.
1576  logical :: do_read, do_log
1577 
1578  do_read = .true. ; if (present(do_not_read)) do_read = .not.do_not_read
1579  do_log = .true. ; if (present(do_not_log)) do_log = .not.do_not_log
1580 
1581  if (do_read) then
1582  if (present(default)) then ; value(:) = default ; endif
1583  if (present(static_value)) then ; value(:) = static_value ; endif
1584  call read_param_int_array(cs, varname, value, fail_if_missing)
1585  endif
1586 
1587  if (do_log) then
1588  call log_param_int_array(cs, modulename, varname, value, desc, &
1589  units, default, layoutparam)
1590  endif
1591 
1592 end subroutine get_param_int_array
1593 
1594 subroutine get_param_real(CS, modulename, varname, value, desc, units, &
1595  default, fail_if_missing, do_not_read, do_not_log, static_value)
1596  type(param_file_type), intent(in) :: CS
1597  character(len=*), intent(in) :: modulename
1598  character(len=*), intent(in) :: varname
1599  real, intent(inout) :: value
1600  character(len=*), optional, intent(in) :: desc, units
1601  real, optional, intent(in) :: default, static_value
1602  logical, optional, intent(in) :: fail_if_missing
1603  logical, optional, intent(in) :: do_not_read, do_not_log
1604 ! This subroutine writes the value of a real parameter to a log file,
1605 ! along with its name and the module it came from.
1606  logical :: do_read, do_log
1607 
1608  do_read = .true. ; if (present(do_not_read)) do_read = .not.do_not_read
1609  do_log = .true. ; if (present(do_not_log)) do_log = .not.do_not_log
1610 
1611  if (do_read) then
1612  if (present(default)) value = default
1613  if (present(static_value)) value = static_value
1614  call read_param_real(cs, varname, value, fail_if_missing)
1615  endif
1616 
1617  if (do_log) then
1618  call log_param_real(cs, modulename, varname, value, desc, units, &
1619  default)
1620  endif
1621 
1622 end subroutine get_param_real
1623 
1624 subroutine get_param_real_array(CS, modulename, varname, value, desc, units, &
1625  default, fail_if_missing, do_not_read, do_not_log, static_value)
1626  type(param_file_type), intent(in) :: CS
1627  character(len=*), intent(in) :: modulename
1628  character(len=*), intent(in) :: varname
1629  real, intent(inout) :: value(:)
1630  character(len=*), optional, intent(in) :: desc, units
1631  real, optional, intent(in) :: default, static_value
1632  logical, optional, intent(in) :: fail_if_missing
1633  logical, optional, intent(in) :: do_not_read, do_not_log
1634 ! This subroutine writes the value of a real parameter to a log file,
1635 ! along with its name and the module it came from.
1636  logical :: do_read, do_log
1637 
1638  do_read = .true. ; if (present(do_not_read)) do_read = .not.do_not_read
1639  do_log = .true. ; if (present(do_not_log)) do_log = .not.do_not_log
1640 
1641  if (do_read) then
1642  if (present(default)) then ; value(:) = default ; endif
1643  if (present(static_value)) then ; value(:) = static_value ; endif
1644  call read_param_real_array(cs, varname, value, fail_if_missing)
1645  endif
1646 
1647  if (do_log) then
1648  call log_param_real_array(cs, modulename, varname, value, desc, &
1649  units, default)
1650  endif
1651 
1652 end subroutine get_param_real_array
1653 
1654 subroutine get_param_char(CS, modulename, varname, value, desc, units, &
1655  default, fail_if_missing, do_not_read, do_not_log, &
1656  static_value, layoutParam)
1657  type(param_file_type), intent(in) :: CS
1658  character(len=*), intent(in) :: modulename
1659  character(len=*), intent(in) :: varname
1660  character(len=*), intent(inout) :: value
1661  character(len=*), optional, intent(in) :: desc, units
1662  character(len=*), optional, intent(in) :: default, static_value
1663  logical, optional, intent(in) :: fail_if_missing
1664  logical, optional, intent(in) :: do_not_read, do_not_log
1665  logical, optional, intent(in) :: layoutParam
1666 ! This subroutine writes the value of a real parameter to a log file,
1667 ! along with its name and the module it came from.
1668  logical :: do_read, do_log
1669 
1670  do_read = .true. ; if (present(do_not_read)) do_read = .not.do_not_read
1671  do_log = .true. ; if (present(do_not_log)) do_log = .not.do_not_log
1672 
1673  if (do_read) then
1674  if (present(default)) value = default
1675  if (present(static_value)) value = static_value
1676  call read_param_char(cs, varname, value, fail_if_missing)
1677  endif
1678 
1679  if (do_log) then
1680  call log_param_char(cs, modulename, varname, value, desc, units, &
1681  default, layoutparam)
1682  endif
1683 
1684 end subroutine get_param_char
1685 
1686 subroutine get_param_char_array(CS, modulename, varname, value, desc, units, &
1687  default, fail_if_missing, do_not_read, do_not_log, static_value)
1688  type(param_file_type), intent(in) :: CS
1689  character(len=*), intent(in) :: modulename
1690  character(len=*), intent(in) :: varname
1691  character(len=*), intent(inout) :: value(:)
1692  character(len=*), optional, intent(in) :: desc, units
1693  character(len=*), optional, intent(in) :: default, static_value
1694  logical, optional, intent(in) :: fail_if_missing
1695  logical, optional, intent(in) :: do_not_read, do_not_log
1696 ! This subroutine writes the value of a real parameter to a log file,
1697 ! along with its name and the module it came from.
1698  logical :: do_read, do_log
1699  integer :: i, len_tot, len_val
1700  character(len=240) :: cat_val
1701 
1702  do_read = .true. ; if (present(do_not_read)) do_read = .not.do_not_read
1703  do_log = .true. ; if (present(do_not_log)) do_log = .not.do_not_log
1704 
1705  if (do_read) then
1706  if (present(default)) then ; value(:) = default ; endif
1707  if (present(static_value)) then ; value(:) = static_value ; endif
1708  call read_param_char_array(cs, varname, value, fail_if_missing)
1709  endif
1710 
1711  if (do_log) then
1712  cat_val = trim(value(1)); len_tot = len_trim(value(1))
1713  do i=2,size(value)
1714  len_val = len_trim(value(i))
1715  if ((len_val > 0) .and. (len_tot + len_val + 2 < 240)) then
1716  cat_val = trim(cat_val)//achar(34)// ", "//achar(34)//trim(value(i))
1717  len_tot = len_tot + len_val
1718  endif
1719  enddo
1720  call log_param_char(cs, modulename, varname, cat_val, desc, &
1721  units, default)
1722  endif
1723 
1724 end subroutine get_param_char_array
1725 
1726 subroutine get_param_logical(CS, modulename, varname, value, desc, units, &
1727  default, fail_if_missing, do_not_read, do_not_log, &
1728  static_value, layoutParam)
1729  type(param_file_type), intent(in) :: CS
1730  character(len=*), intent(in) :: modulename
1731  character(len=*), intent(in) :: varname
1732  logical, intent(inout) :: value
1733  character(len=*), optional, intent(in) :: desc, units
1734  logical, optional, intent(in) :: default, static_value
1735  logical, optional, intent(in) :: fail_if_missing
1736  logical, optional, intent(in) :: do_not_read, do_not_log
1737  logical, optional, intent(in) :: layoutParam
1738 ! This subroutine writes the value of a real parameter to a log file,
1739 ! along with its name and the module it came from.
1740  logical :: do_read, do_log
1741 
1742  do_read = .true. ; if (present(do_not_read)) do_read = .not.do_not_read
1743  do_log = .true. ; if (present(do_not_log)) do_log = .not.do_not_log
1744 
1745  if (do_read) then
1746  if (present(default)) value = default
1747  if (present(static_value)) value = static_value
1748  call read_param_logical(cs, varname, value, fail_if_missing)
1749  endif
1750 
1751  if (do_log) then
1752  call log_param_logical(cs, modulename, varname, value, desc, &
1753  units, default, layoutparam)
1754  endif
1755 
1756 end subroutine get_param_logical
1757 
1758 subroutine get_param_time(CS, modulename, varname, value, desc, units, &
1759  default, fail_if_missing, do_not_read, do_not_log, &
1760  timeunit, static_value, layoutParam, log_as_date)
1761  type(param_file_type), intent(in) :: CS
1762  character(len=*), intent(in) :: modulename
1763  character(len=*), intent(in) :: varname
1764  type(time_type), intent(inout) :: value
1765  character(len=*), optional, intent(in) :: desc, units
1766  type(time_type), optional, intent(in) :: default, static_value
1767  logical, optional, intent(in) :: fail_if_missing
1768  logical, optional, intent(in) :: do_not_read, do_not_log
1769  real, optional, intent(in) :: timeunit
1770  logical, optional, intent(in) :: layoutParam
1771  logical, optional, intent(in) :: log_as_date
1772 ! This subroutine writes the value of a real parameter to a log file,
1773 ! along with its name and the module it came from.
1774  logical :: do_read, do_log, date_format, log_date
1775 
1776  do_read = .true. ; if (present(do_not_read)) do_read = .not.do_not_read
1777  do_log = .true. ; if (present(do_not_log)) do_log = .not.do_not_log
1778  log_date = .false.
1779 
1780  if (do_read) then
1781  if (present(default)) value = default
1782  if (present(static_value)) value = static_value
1783  call read_param_time(cs, varname, value, timeunit, fail_if_missing, date_format=log_date)
1784  endif
1785 
1786  if (do_log) then
1787  if (present(log_as_date)) log_date = log_as_date
1788  call log_param_time(cs, modulename, varname, value, desc, units, default, &
1789  timeunit, layoutparam=layoutparam, log_date=log_date)
1790  endif
1791 
1792 end subroutine get_param_time
1793 
1794 ! -----------------------------------------------------------------------------
1795 
1796 subroutine clearparameterblock(CS)
1797  type(param_file_type), intent(in) :: CS
1798 ! Resets the parameter block name to blank
1799  type(parameter_block), pointer :: block
1800  if (associated(cs%blockName)) then
1801  block => cs%blockName
1802  block%name = ''
1803  else
1804  if (is_root_pe()) call mom_error(fatal, &
1805  'clearParameterBlock: A clear was attempted before allocation.')
1806  endif
1807 end subroutine clearparameterblock
1808 
1809 subroutine openparameterblock(CS,blockName,desc)
1810  type(param_file_type), intent(in) :: CS
1811  character(len=*), intent(in) :: blockName
1812  character(len=*), optional, intent(in) :: desc
1813 ! Tags blockName onto the end of the active parameter block name
1814  type(parameter_block), pointer :: block
1815  if (associated(cs%blockName)) then
1816  block => cs%blockName
1817  block%name = pushblocklevel(block%name,blockname)
1818  call doc_openblock(cs%doc,block%name,desc)
1819  else
1820  if (is_root_pe()) call mom_error(fatal, &
1821  'openParameterBlock: A push was attempted before allocation.')
1822  endif
1823 end subroutine openparameterblock
1824 
1825 subroutine closeparameterblock(CS)
1826  type(param_file_type), intent(in) :: CS
1827 ! Remove the lowest level of recursion from the active block name
1828  type(parameter_block), pointer :: block
1829 
1830  if (associated(cs%blockName)) then
1831  block => cs%blockName
1832  if (is_root_pe().and.len_trim(block%name)==0) call mom_error(fatal, &
1833  'closeParameterBlock: A pop was attempted on an empty stack. ("'//&
1834  trim(block%name)//'")')
1835  call doc_closeblock(cs%doc,block%name)
1836  else
1837  if (is_root_pe()) call mom_error(fatal, &
1838  'closeParameterBlock: A pop was attempted before allocation.')
1839  endif
1840  block%name = popblocklevel(block%name)
1841 end subroutine closeparameterblock
1842 
1843 function pushblocklevel(oldblockName,newBlockName)
1844  character(len=*), intent(in) :: oldBlockName, newBlockName
1845  character(len=len(oldBlockName)+40) :: pushBlockLevel
1846 ! Extends block name (deeper level of parameter block)
1847  if (len_trim(oldblockname)>0) then
1848  pushblocklevel=trim(oldblockname)//'%'//trim(newblockname)
1849  else
1850  pushblocklevel=trim(newblockname)
1851  endif
1852 end function pushblocklevel
1853 
1854 function popblocklevel(oldblockName)
1855  character(len=*), intent(in) :: oldBlockName
1856  character(len=len(oldBlockName)+40) :: popBlockLevel
1857 ! Truncates block name (shallower level of parameter block)
1858  integer :: i
1859  i = index(trim(oldblockname), '%', .true.)
1860  if (i>1) then
1861  popblocklevel = trim(oldblockname(1:i-1))
1862  elseif (i==0) then
1863  popblocklevel = ''
1864  else ! i==1
1865  if (is_root_pe()) call mom_error(fatal, &
1866  'popBlockLevel: A pop was attempted leaving an empty block name.')
1867  endif
1868 end function popblocklevel
1869 
1870 end module mom_file_parser
integer, parameter input_str_length
subroutine read_param_real_array(CS, varname, value, fail_if_missing)
subroutine log_param_real_array(CS, modulename, varname, value, desc, units, default)
subroutine get_param_logical(CS, modulename, varname, value, desc, units, default, fail_if_missing, do_not_read, do_not_log, static_value, layoutParam)
subroutine get_variable_line(CS, varname, found, defined, value_string, paramIsLogical)
character(len=40) function convert_date_to_string(date)
This function converts a date into a string, valid with ticks and for dates up to year 99...
character(len=len(string)+16) function simplifywhitespace(string)
subroutine read_param_time(CS, varname, value, timeunit, fail_if_missing, date_format)
subroutine get_param_int(CS, modulename, varname, value, desc, units, default, fail_if_missing, do_not_read, do_not_log, static_value, layoutParam)
subroutine get_param_int_array(CS, modulename, varname, value, desc, units, default, fail_if_missing, do_not_read, do_not_log, static_value, layoutParam)
subroutine get_param_time(CS, modulename, varname, value, desc, units, default, fail_if_missing, do_not_read, do_not_log, timeunit, static_value, layoutParam, log_as_date)
logical, parameter unused_params_fatal_default
subroutine, public doc_end(doc)
logical, parameter complete_doc_default
subroutine log_param_int_array(CS, modulename, varname, value, desc, units, default, layoutParam)
subroutine, public doc_init(docFileBase, doc, minimal, complete)
subroutine log_param_char(CS, modulename, varname, value, desc, units, default, layoutParam)
integer, parameter filename_length
logical, parameter log_to_stdout_default
character(len=len(string)) function replacetabs(string)
subroutine log_param_logical(CS, modulename, varname, value, desc, units, default, layoutParam)
character(len=19) function, public left_int(i)
character(len=32) function, public left_real(val)
subroutine populate_param_data(iounit, filename, param_data)
subroutine, public open_param_file(filename, CS, checkable, component, doc_file_dir)
subroutine read_param_char_array(CS, varname, value, fail_if_missing)
character(len=input_str_length) function strip_quotes(val_str)
subroutine read_param_logical(CS, varname, value, fail_if_missing)
subroutine, public clearparameterblock(CS)
subroutine get_param_char_array(CS, modulename, varname, value, desc, units, default, fail_if_missing, do_not_read, do_not_log, static_value)
subroutine flag_line_as_read(line_used, count)
logical function overridewarninghasbeenissued(chain, varName)
integer, parameter, public max_param_files
character(len=len(dir)+2) function, public slasher(dir)
Returns a directory name that is terminated with a "/" or "./" if the argument is an empty string...
logical function openmultilinecomment(string)
subroutine read_param_int_array(CS, varname, value, fail_if_missing)
subroutine, public doc_closeblock(doc, blockName)
subroutine, public doc_openblock(doc, blockName, desc)
character(len=len(oldblockname)+40) function pushblocklevel(oldblockName, newBlockName)
subroutine, public close_param_file(CS, quiet_close, component)
subroutine, public closeparameterblock(CS)
subroutine read_param_real(CS, varname, value, fail_if_missing)
integer function lastnoncommentindex(string)
subroutine, public openparameterblock(CS, blockName, desc)
subroutine log_version_plain(modulename, version)
Log the version of a module to a log file and/or stdout.
logical function, public is_root_pe()
character(len=len(oldblockname)+40) function popblocklevel(oldblockName)
character(len=1320) function, public left_ints(i)
character(len=len(string)) function removecomments(string)
subroutine get_param_real_array(CS, modulename, varname, value, desc, units, default, fail_if_missing, do_not_read, do_not_log, static_value)
subroutine read_param_int(CS, varname, value, fail_if_missing)
subroutine, public mom_mesg(message, verb, all_print)
subroutine get_param_real(CS, modulename, varname, value, desc, units, default, fail_if_missing, do_not_read, do_not_log, static_value)
subroutine get_param_char(CS, modulename, varname, value, desc, units, default, fail_if_missing, do_not_read, do_not_log, static_value, layoutParam)
subroutine read_param_char(CS, varname, value, fail_if_missing)
logical, parameter report_unused_default
character(len=1320) function, public left_reals(r, sep)
subroutine log_version_cs(CS, modulename, version, desc)
Log the version of a module to a log file and/or stdout, and/or to the parameter documentation file...
subroutine log_param_int(CS, modulename, varname, value, desc, units, default, layoutParam)
subroutine, public mom_error(level, message, all_print)
integer function lastnoncommentnonblank(string)
subroutine log_param_real(CS, modulename, varname, value, desc, units, default)
subroutine log_param_time(CS, modulename, varname, value, desc, units, default, timeunit, layoutParam, log_date)
This subroutine writes the value of a time-type parameter to a log file, along with its name and the ...
logical function closemultilinecomment(string)
subroutine, public doc_module(doc, modname, desc)
logical, parameter minimal_doc_default