7 use mom_time_manager,
only : time_type,
operator(==), get_time, get_ticks_per_second
10 implicit none ;
private
12 public doc_param, doc_subroutine, doc_function, doc_module, doc_init, doc_end
13 public doc_openblock, doc_closeblock
17 module procedure doc_param_none, &
18 doc_param_logical, doc_param_logical_array, &
19 doc_param_int, doc_param_int_array, &
20 doc_param_real, doc_param_real_array, &
25 integer,
parameter :: mlen = 1240
29 integer :: unitall = -1
30 integer :: unitshort = -1
31 integer :: unitlayout = -1
32 integer :: unitdebugging = -1
33 logical :: filesareopen = .false.
34 character(len=mLen) :: docfilebase =
''
36 logical :: complete = .true.
37 logical :: minimal = .true.
38 logical :: layout = .true.
39 logical :: debugging = .true.
40 logical :: definesyntax = .false.
41 logical :: warnonconflicts = .false.
42 integer :: commentcolumn = 32
43 integer :: max_line_len = 112
45 character(len=240) :: blockprefix =
''
51 character(len=80) :: name
52 character(len=620) :: msg
55 character(len=4),
parameter :: string_true =
'True'
56 character(len=5),
parameter :: string_false =
'False'
63 subroutine doc_param_none(doc, varname, desc, units)
66 character(len=*),
intent(in) :: varname
67 character(len=*),
intent(in) :: desc
68 character(len=*),
intent(in) :: units
71 character(len=mLen) :: mesg
73 if (.not. (is_root_pe() .and.
associated(doc)))
return
74 call open_doc_file(doc)
76 if (doc%filesAreOpen)
then
77 numspc = max(1,doc%commentColumn-8-len_trim(varname))
78 mesg =
"#define "//trim(varname)//repeat(
" ",numspc)//
"!"
79 if (len_trim(units) > 0) mesg = trim(mesg)//
" ["//trim(units)//
"]"
81 if (mesghasbeendocumented(doc, varname, mesg))
return
82 call writemessageanddesc(doc, mesg, desc)
84 end subroutine doc_param_none
87 subroutine doc_param_logical(doc, varname, desc, units, val, default, &
88 layoutParam, debuggingParam, like_default)
91 character(len=*),
intent(in) :: varname
92 character(len=*),
intent(in) :: desc
93 character(len=*),
intent(in) :: units
94 logical,
intent(in) :: val
95 logical,
optional,
intent(in) :: default
96 logical,
optional,
intent(in) :: layoutParam
97 logical,
optional,
intent(in) :: debuggingParam
98 logical,
optional,
intent(in) :: like_default
101 character(len=mLen) :: mesg
102 logical :: equalsDefault
104 if (.not. (is_root_pe() .and.
associated(doc)))
return
105 call open_doc_file(doc)
107 if (doc%filesAreOpen)
then
109 mesg = define_string(doc, varname, string_true, units)
111 mesg = undef_string(doc, varname, units)
114 equalsdefault = .false.
115 if (
present(like_default)) equalsdefault = like_default
116 if (
present(default))
then
117 if (val .eqv. default) equalsdefault = .true.
119 mesg = trim(mesg)//
" default = "//string_true
121 mesg = trim(mesg)//
" default = "//string_false
125 if (mesghasbeendocumented(doc, varname, mesg))
return
126 call writemessageanddesc(doc, mesg, desc, equalsdefault, &
127 layoutparam=layoutparam, debuggingparam=debuggingparam)
129 end subroutine doc_param_logical
132 subroutine doc_param_logical_array(doc, varname, desc, units, vals, default, &
133 layoutParam, debuggingParam, like_default)
136 character(len=*),
intent(in) :: varname
137 character(len=*),
intent(in) :: desc
138 character(len=*),
intent(in) :: units
139 logical,
intent(in) :: vals(:)
140 logical,
optional,
intent(in) :: default
141 logical,
optional,
intent(in) :: layoutParam
142 logical,
optional,
intent(in) :: debuggingParam
143 logical,
optional,
intent(in) :: like_default
147 character(len=mLen) :: mesg
148 character(len=mLen) :: valstring
149 logical :: equalsDefault
151 if (.not. (is_root_pe() .and.
associated(doc)))
return
152 call open_doc_file(doc)
154 if (doc%filesAreOpen)
then
155 if (vals(1))
then ; valstring = string_true ;
else ; valstring = string_false ;
endif
156 do i=2,min(
size(vals),128)
158 valstring = trim(valstring)//
", "//string_true
160 valstring = trim(valstring)//
", "//string_false
164 mesg = define_string(doc, varname, valstring, units)
166 equalsdefault = .false.
167 if (
present(default))
then
168 equalsdefault = .true.
169 do i=1,
size(vals) ;
if (vals(i) .neqv. default) equalsdefault = .false. ;
enddo
171 mesg = trim(mesg)//
" default = "//string_true
173 mesg = trim(mesg)//
" default = "//string_false
176 if (
present(like_default))
then ;
if (like_default) equalsdefault = .true. ;
endif
178 if (mesghasbeendocumented(doc, varname, mesg))
return
179 call writemessageanddesc(doc, mesg, desc, equalsdefault, &
180 layoutparam=layoutparam, debuggingparam=debuggingparam)
182 end subroutine doc_param_logical_array
185 subroutine doc_param_int(doc, varname, desc, units, val, default, &
186 layoutParam, debuggingParam, like_default)
189 character(len=*),
intent(in) :: varname
190 character(len=*),
intent(in) :: desc
191 character(len=*),
intent(in) :: units
192 integer,
intent(in) :: val
193 integer,
optional,
intent(in) :: default
194 logical,
optional,
intent(in) :: layoutParam
195 logical,
optional,
intent(in) :: debuggingParam
196 logical,
optional,
intent(in) :: like_default
199 character(len=mLen) :: mesg
200 character(len=doc%commentColumn) :: valstring
201 logical :: equalsDefault
203 if (.not. (is_root_pe() .and.
associated(doc)))
return
204 call open_doc_file(doc)
206 if (doc%filesAreOpen)
then
207 valstring = int_string(val)
208 mesg = define_string(doc, varname, valstring, units)
210 equalsdefault = .false.
211 if (
present(like_default)) equalsdefault = like_default
212 if (
present(default))
then
213 if (val == default) equalsdefault = .true.
214 mesg = trim(mesg)//
" default = "//(trim(int_string(default)))
217 if (mesghasbeendocumented(doc, varname, mesg))
return
218 call writemessageanddesc(doc, mesg, desc, equalsdefault, &
219 layoutparam=layoutparam, debuggingparam=debuggingparam)
221 end subroutine doc_param_int
224 subroutine doc_param_int_array(doc, varname, desc, units, vals, default, &
225 layoutParam, debuggingParam, like_default)
228 character(len=*),
intent(in) :: varname
229 character(len=*),
intent(in) :: desc
230 character(len=*),
intent(in) :: units
231 integer,
intent(in) :: vals(:)
232 integer,
optional,
intent(in) :: default
233 logical,
optional,
intent(in) :: layoutParam
234 logical,
optional,
intent(in) :: debuggingParam
235 logical,
optional,
intent(in) :: like_default
239 character(len=mLen) :: mesg
240 character(len=mLen) :: valstring
241 logical :: equalsDefault
243 if (.not. (is_root_pe() .and.
associated(doc)))
return
244 call open_doc_file(doc)
246 if (doc%filesAreOpen)
then
247 valstring = int_string(vals(1))
248 do i=2,min(
size(vals),128)
249 valstring = trim(valstring)//
", "//trim(int_string(vals(i)))
252 mesg = define_string(doc, varname, valstring, units)
254 equalsdefault = .false.
255 if (
present(default))
then
256 equalsdefault = .true.
257 do i=1,
size(vals) ;
if (vals(i) /= default) equalsdefault = .false. ;
enddo
258 mesg = trim(mesg)//
" default = "//(trim(int_string(default)))
260 if (
present(like_default))
then ;
if (like_default) equalsdefault = .true. ;
endif
262 if (mesghasbeendocumented(doc, varname, mesg))
return
263 call writemessageanddesc(doc, mesg, desc, equalsdefault, &
264 layoutparam=layoutparam, debuggingparam=debuggingparam)
267 end subroutine doc_param_int_array
270 subroutine doc_param_real(doc, varname, desc, units, val, default, debuggingParam, like_default)
273 character(len=*),
intent(in) :: varname
274 character(len=*),
intent(in) :: desc
275 character(len=*),
intent(in) :: units
276 real,
intent(in) :: val
277 real,
optional,
intent(in) :: default
278 logical,
optional,
intent(in) :: debuggingParam
279 logical,
optional,
intent(in) :: like_default
282 character(len=mLen) :: mesg
283 character(len=doc%commentColumn) :: valstring
284 logical :: equalsDefault
286 if (.not. (is_root_pe() .and.
associated(doc)))
return
287 call open_doc_file(doc)
289 if (doc%filesAreOpen)
then
290 valstring = real_string(val)
291 mesg = define_string(doc, varname, valstring, units)
293 equalsdefault = .false.
294 if (
present(like_default)) equalsdefault = like_default
295 if (
present(default))
then
296 if (val == default) equalsdefault = .true.
297 mesg = trim(mesg)//
" default = "//trim(real_string(default))
300 if (mesghasbeendocumented(doc, varname, mesg))
return
301 call writemessageanddesc(doc, mesg, desc, equalsdefault, debuggingparam=debuggingparam)
303 end subroutine doc_param_real
306 subroutine doc_param_real_array(doc, varname, desc, units, vals, default, debuggingParam, like_default)
309 character(len=*),
intent(in) :: varname
310 character(len=*),
intent(in) :: desc
311 character(len=*),
intent(in) :: units
312 real,
intent(in) :: vals(:)
313 real,
optional,
intent(in) :: default
314 logical,
optional,
intent(in) :: debuggingParam
315 logical,
optional,
intent(in) :: like_default
319 character(len=mLen) :: mesg
320 character(len=mLen) :: valstring
321 logical :: equalsDefault
323 if (.not. (is_root_pe() .and.
associated(doc)))
return
324 call open_doc_file(doc)
326 if (doc%filesAreOpen)
then
327 valstring = trim(real_array_string(vals(:)))
329 mesg = define_string(doc, varname, valstring, units)
331 equalsdefault = .false.
332 if (
present(default))
then
333 equalsdefault = .true.
334 do i=1,
size(vals) ;
if (vals(i) /= default) equalsdefault = .false. ;
enddo
335 mesg = trim(mesg)//
" default = "//trim(real_string(default))
337 if (
present(like_default))
then ;
if (like_default) equalsdefault = .true. ;
endif
339 if (mesghasbeendocumented(doc, varname, mesg))
return
340 call writemessageanddesc(doc, mesg, desc, equalsdefault, debuggingparam=debuggingparam)
343 end subroutine doc_param_real_array
346 subroutine doc_param_char(doc, varname, desc, units, val, default, &
347 layoutParam, debuggingParam, like_default)
350 character(len=*),
intent(in) :: varname
351 character(len=*),
intent(in) :: desc
352 character(len=*),
intent(in) :: units
353 character(len=*),
intent(in) :: val
355 optional,
intent(in) :: default
356 logical,
optional,
intent(in) :: layoutParam
357 logical,
optional,
intent(in) :: debuggingParam
358 logical,
optional,
intent(in) :: like_default
361 character(len=mLen) :: mesg
362 logical :: equalsDefault
364 if (.not. (is_root_pe() .and.
associated(doc)))
return
365 call open_doc_file(doc)
367 if (doc%filesAreOpen)
then
368 mesg = define_string(doc, varname,
'"'//trim(val)//
'"', units)
370 equalsdefault = .false.
371 if (
present(like_default)) equalsdefault = like_default
372 if (
present(default))
then
373 if (trim(val) == trim(default)) equalsdefault = .true.
374 mesg = trim(mesg)//
' default = "'//trim(adjustl(default))//
'"'
377 if (mesghasbeendocumented(doc, varname, mesg))
return
378 call writemessageanddesc(doc, mesg, desc, equalsdefault, &
379 layoutparam=layoutparam, debuggingparam=debuggingparam)
382 end subroutine doc_param_char
385 subroutine doc_openblock(doc, blockName, desc)
388 character(len=*),
intent(in) :: blockname
389 character(len=*),
optional,
intent(in) :: desc
391 character(len=mLen) :: mesg
392 character(len=doc%commentColumn) :: valstring
394 if (.not. (is_root_pe() .and.
associated(doc)))
return
395 call open_doc_file(doc)
397 if (doc%filesAreOpen)
then
398 mesg = trim(blockname)//
'%'
400 if (
present(desc))
then
401 call writemessageanddesc(doc, mesg, desc)
403 call writemessageanddesc(doc, mesg,
'')
406 doc%blockPrefix = trim(doc%blockPrefix)//trim(blockname)//
'%'
407 end subroutine doc_openblock
410 subroutine doc_closeblock(doc, blockName)
413 character(len=*),
intent(in) :: blockname
415 character(len=mLen) :: mesg
416 character(len=doc%commentColumn) :: valstring
419 if (.not. (is_root_pe() .and.
associated(doc)))
return
420 call open_doc_file(doc)
422 if (doc%filesAreOpen)
then
423 mesg =
'%'//trim(blockname)
425 call writemessageanddesc(doc, mesg,
'')
427 i = index(trim(doc%blockPrefix), trim(blockname)//
'%', .true.)
429 doc%blockPrefix = trim(doc%blockPrefix(1:i-1))
433 end subroutine doc_closeblock
436 subroutine doc_param_time(doc, varname, desc, val, default, units, debuggingParam, like_default)
439 character(len=*),
intent(in) :: varname
440 character(len=*),
intent(in) :: desc
441 type(time_type),
intent(in) :: val
442 type(time_type),
optional,
intent(in) :: default
443 character(len=*),
optional,
intent(in) :: units
444 logical,
optional,
intent(in) :: debuggingParam
445 logical,
optional,
intent(in) :: like_default
449 character(len=mLen) :: mesg
450 character(len=doc%commentColumn) :: valstring
451 logical :: equalsDefault
453 if (.not. (is_root_pe() .and.
associated(doc)))
return
454 call open_doc_file(doc)
456 if (doc%filesAreOpen)
then
457 valstring = time_string(val)
458 if (
present(units))
then
459 mesg = define_string(doc, varname, valstring, units)
461 mesg = define_string(doc, varname, valstring,
"[days : seconds]")
464 equalsdefault = .false.
465 if (
present(like_default)) equalsdefault = like_default
466 if (
present(default))
then
467 if (val == default) equalsdefault = .true.
468 mesg = trim(mesg)//
" default = "//trim(time_string(default))
471 if (mesghasbeendocumented(doc, varname, mesg))
return
472 call writemessageanddesc(doc, mesg, desc, equalsdefault, debuggingparam=debuggingparam)
475 end subroutine doc_param_time
478 subroutine writemessageanddesc(doc, vmesg, desc, valueWasDefault, indent, &
479 layoutParam, debuggingParam)
482 character(len=*),
intent(in) :: vmesg
483 character(len=*),
intent(in) :: desc
484 logical,
optional,
intent(in) :: valueWasDefault
485 integer,
optional,
intent(in) :: indent
486 logical,
optional,
intent(in) :: layoutParam
487 logical,
optional,
intent(in) :: debuggingParam
490 character(len=mLen) :: mesg
491 character(len=mLen) :: mesg_text
492 integer :: start_ind = 1
493 integer :: nl_ind, tab_ind, end_ind
494 integer :: len_text, len_tab, len_nl
497 integer :: substr_start
498 integer :: indnt, msg_pad
499 logical :: msg_done, reset_msg_pad
500 logical :: all, short, layout, debug
502 layout = .false. ;
if (
present(layoutparam)) layout = layoutparam
503 debug = .false. ;
if (
present(debuggingparam)) debug = debuggingparam
504 all = doc%complete .and. (doc%unitAll > 0) .and. .not. (layout .or. debug)
505 short = doc%minimal .and. (doc%unitShort > 0) .and. .not. (layout .or. debug)
506 if (
present(valuewasdefault)) short = short .and. (.not. valuewasdefault)
508 if (all)
write(doc%unitAll,
'(a)') trim(vmesg)
509 if (short)
write(doc%unitShort,
'(a)') trim(vmesg)
510 if (layout)
write(doc%unitLayout,
'(a)') trim(vmesg)
511 if (debug)
write(doc%unitDebugging,
'(a)') trim(vmesg)
513 if (len_trim(desc) == 0)
return
515 len_tab = len_trim(
"_\t_") - 2
516 len_nl = len_trim(
"_\n_") - 2
518 indnt = doc%commentColumn ;
if (
present(indent)) indnt = indent
519 len_text = doc%max_line_len - (indnt + 2)
520 start_ind = 1 ; msg_pad = 0 ; msg_done = .false.
522 if (len_trim(desc(start_ind:)) < 1)
exit
524 len_cor = len_text - msg_pad
526 substr_start = start_ind
527 len_desc = len_trim(desc)
529 if (substr_start >= start_ind+len_cor)
exit
530 tab_ind = index(desc(substr_start:min(len_desc,start_ind+len_cor)),
"\t")
531 if (tab_ind == 0)
exit
532 substr_start = substr_start + tab_ind
533 len_cor = len_cor + (len_tab - 2)
536 nl_ind = index(desc(start_ind:),
"\n")
538 if ((nl_ind > 0) .and. (len_trim(desc(start_ind:start_ind+nl_ind-2)) > len_cor))
then
540 end_ind = scan(desc(start_ind:start_ind+len_cor),
" ", back=.true.) - 1
541 if (end_ind > 0) nl_ind = 0
542 elseif ((nl_ind == 0) .and. (len_trim(desc(start_ind:)) > len_cor))
then
544 end_ind = scan(desc(start_ind:start_ind+len_cor),
" ", back=.true.) - 1
547 reset_msg_pad = .false.
549 mesg_text = trim(desc(start_ind:start_ind+nl_ind-2))
550 start_ind = start_ind + nl_ind + len_nl - 1
551 reset_msg_pad = .true.
552 elseif (end_ind > 0)
then
553 mesg_text = trim(desc(start_ind:start_ind+end_ind))
554 start_ind = start_ind + end_ind + 1
556 start_ind = start_ind + (len_trim(desc(start_ind:)) - len_trim(adjustl(desc(start_ind:))))
558 mesg_text = trim(desc(start_ind:))
562 do ; tab_ind = index(mesg_text,
"\t")
563 if (tab_ind == 0)
exit
564 mesg_text(tab_ind:) =
" "//trim(mesg_text(tab_ind+len_tab:))
567 mesg = repeat(
" ",indnt)//
"! "//repeat(
" ",msg_pad)//trim(mesg_text)
569 if (reset_msg_pad)
then
571 elseif (msg_pad == 0)
then
572 msg_pad = len_trim(mesg_text) - len_trim(adjustl(mesg_text))
574 if (msg_pad >= 2) msg_pad = msg_pad + 2
577 if (all)
write(doc%unitAll,
'(a)') trim(mesg)
578 if (short)
write(doc%unitShort,
'(a)') trim(mesg)
579 if (layout)
write(doc%unitLayout,
'(a)') trim(mesg)
580 if (debug)
write(doc%unitDebugging,
'(a)') trim(mesg)
585 end subroutine writemessageanddesc
591 function time_string(time)
592 type(time_type),
intent(in) :: time
593 character(len=40) :: time_string
596 integer :: secs, days, ticks, ticks_per_sec
598 call get_time(time, secs, days, ticks)
600 time_string = trim(adjustl(int_string(days))) //
":" // trim(adjustl(int_string(secs)))
602 ticks_per_sec = get_ticks_per_second()
603 time_string = trim(time_string) //
":" // &
604 trim(adjustl(int_string(ticks)))//
"/"//trim(adjustl(int_string(ticks_per_sec)))
607 end function time_string
610 function real_string(val)
611 real,
intent(in) :: val
612 character(len=32) :: real_string
616 if ((abs(val) < 1.0e4) .and. (abs(val) >= 1.0e-3))
then
617 write(real_string,
'(F30.11)') val
618 if (.not.testformattedfloatisreal(real_string,val))
then
619 write(real_string,
'(F30.12)') val
620 if (.not.testformattedfloatisreal(real_string,val))
then
621 write(real_string,
'(F30.13)') val
622 if (.not.testformattedfloatisreal(real_string,val))
then
623 write(real_string,
'(F30.14)') val
624 if (.not.testformattedfloatisreal(real_string,val))
then
625 write(real_string,
'(F30.15)') val
626 if (.not.testformattedfloatisreal(real_string,val))
then
627 write(real_string,
'(F30.16)') val
634 len = len_trim(real_string)
635 if ((len<2) .or. (real_string(len-1:len) ==
".0") .or. &
636 (real_string(len:len) /=
"0"))
exit
637 real_string(len:len) =
" "
639 elseif (val == 0.)
then
642 if ((abs(val) <= 1.0e-100) .or. (abs(val) >= 1.0e100))
then
643 write(real_string(1:32),
'(ES24.14E3)') val
644 if (.not.testformattedfloatisreal(real_string,val)) &
645 write(real_string(1:32),
'(ES24.15E3)') val
647 write(real_string(1:32),
'(ES23.14)') val
648 if (.not.testformattedfloatisreal(real_string,val)) &
649 write(real_string(1:32),
'(ES23.15)') val
652 ind = index(real_string,
"0E")
654 if (real_string(ind-1:ind-1) ==
".")
exit
655 real_string = real_string(1:ind-1)//real_string(ind+1:)
658 real_string = adjustl(real_string)
659 end function real_string
663 function real_array_string(vals, sep)
664 character(len=1320) :: real_array_string
665 real,
intent(in) :: vals(:)
667 optional,
intent(in) :: sep
672 integer :: j, n, b, ns
674 character(len=10) :: separator
675 n=1 ; dowrite=.true. ; real_array_string=
'' ; b=1
676 if (
present(sep))
then
677 separator=sep ; ns=len(sep)
679 separator=
', ' ; ns=2
683 if (j<
size(vals))
then
684 if (vals(j)==vals(j+1))
then
691 write(real_array_string(b:),
'(A)') separator
695 write(real_array_string(b:),
'(A,"*",A)') trim(int_string(n)),trim(real_string(vals(j)))
697 write(real_array_string(b:),
'(A)') trim(real_string(vals(j)))
699 n=1 ; b=len_trim(real_array_string)+1
702 end function real_array_string
705 function testformattedfloatisreal(str, val)
706 character(len=*),
intent(in) :: str
707 real,
intent(in) :: val
708 logical :: testformattedfloatisreal
712 read(str(1:),*) scannedval
713 if (scannedval == val)
then
714 testformattedfloatisreal=.true.
716 testformattedfloatisreal=.false.
718 end function testformattedfloatisreal
721 function int_string(val)
722 integer,
intent(in) :: val
723 character(len=24) :: int_string
725 write(int_string,
'(i24)') val
726 int_string = adjustl(int_string)
727 end function int_string
730 function logical_string(val)
731 logical,
intent(in) :: val
732 character(len=24) :: logical_string
734 write(logical_string,
'(l24)') val
735 logical_string = adjustl(logical_string)
736 end function logical_string
739 function define_string(doc, varName, valString, units)
742 character(len=*),
intent(in) :: varname
743 character(len=*),
intent(in) :: valstring
744 character(len=*),
intent(in) :: units
745 character(len=mLen) :: define_string
748 define_string = repeat(
" ",mlen)
749 if (doc%defineSyntax)
then
750 define_string =
"#define "//trim(varname)//
" "//valstring
752 define_string = trim(varname)//
" = "//valstring
754 numspaces = max(1, doc%commentColumn - len_trim(define_string) )
755 define_string = trim(define_string)//repeat(
" ",numspaces)//
"!"
756 if (len_trim(units) > 0) define_string = trim(define_string)//
" ["//trim(units)//
"]"
757 end function define_string
760 function undef_string(doc, varName, units)
763 character(len=*),
intent(in) :: varname
764 character(len=*),
intent(in) :: units
765 character(len=mLen) :: undef_string
768 undef_string = repeat(
" ",240)
769 undef_string =
"#undef "//trim(varname)
770 if (doc%defineSyntax)
then
771 undef_string =
"#undef "//trim(varname)
773 undef_string = trim(varname)//
" = "//string_false
775 numspaces = max(1, doc%commentColumn - len_trim(undef_string) )
776 undef_string = trim(undef_string)//repeat(
" ",numspaces)//
"!"
777 if (len_trim(units) > 0) undef_string = trim(undef_string)//
" ["//trim(units)//
"]"
778 end function undef_string
783 subroutine doc_module(doc, modname, desc, log_to_all, all_default, layoutMod, debuggingMod)
786 character(len=*),
intent(in) :: modname
787 character(len=*),
intent(in) :: desc
788 logical,
optional,
intent(in) :: log_to_all
791 logical,
optional,
intent(in) :: all_default
792 logical,
optional,
intent(in) :: layoutmod
793 logical,
optional,
intent(in) :: debuggingmod
796 character(len=mLen) :: mesg
797 logical :: repeat_doc
799 if (.not. (is_root_pe() .and.
associated(doc)))
return
800 call open_doc_file(doc)
802 if (doc%filesAreOpen)
then
804 call writemessageanddesc(doc,
'',
'', valuewasdefault=all_default, &
805 layoutparam=layoutmod, debuggingparam=debuggingmod)
806 mesg =
"! === module "//trim(modname)//
" ==="
807 call writemessageanddesc(doc, mesg, desc, valuewasdefault=all_default, indent=0, &
808 layoutparam=layoutmod, debuggingparam=debuggingmod)
809 if (
present(log_to_all))
then ;
if (log_to_all)
then
813 if (
present(layoutmod))
then ;
if (layoutmod) repeat_doc = .true. ;
endif
814 if (
present(debuggingmod))
then ;
if (debuggingmod) repeat_doc = .true. ;
endif
816 call writemessageanddesc(doc,
'',
'', valuewasdefault=all_default)
817 call writemessageanddesc(doc, mesg, desc, valuewasdefault=all_default, indent=0)
821 end subroutine doc_module
824 subroutine doc_subroutine(doc, modname, subname, desc)
827 character(len=*),
intent(in) :: modname
828 character(len=*),
intent(in) :: subname
829 character(len=*),
intent(in) :: desc
831 if (.not. (is_root_pe() .and.
associated(doc)))
return
832 call open_doc_file(doc)
834 end subroutine doc_subroutine
837 subroutine doc_function(doc, modname, fnname, desc)
840 character(len=*),
intent(in) :: modname
841 character(len=*),
intent(in) :: fnname
842 character(len=*),
intent(in) :: desc
844 if (.not. (is_root_pe() .and.
associated(doc)))
return
845 call open_doc_file(doc)
847 end subroutine doc_function
852 subroutine doc_init(docFileBase, doc, minimal, complete, layout, debugging)
853 character(len=*),
intent(in) :: docfilebase
857 logical,
optional,
intent(in) :: minimal
859 logical,
optional,
intent(in) :: complete
861 logical,
optional,
intent(in) :: layout
863 logical,
optional,
intent(in) :: debugging
866 if (.not.
associated(doc))
then
870 doc%docFileBase = docfilebase
871 if (
present(minimal)) doc%minimal = minimal
872 if (
present(complete)) doc%complete = complete
873 if (
present(layout)) doc%layout = layout
874 if (
present(debugging)) doc%debugging = debugging
876 end subroutine doc_init
881 subroutine open_doc_file(doc)
885 logical :: opened, new_file
887 character(len=240) :: fileName
889 if (.not. (is_root_pe() .and.
associated(doc)))
return
891 if ((len_trim(doc%docFileBase) > 0) .and. doc%complete .and. (doc%unitAll<0))
then
892 new_file = .true. ;
if (doc%unitAll /= -1) new_file = .false.
893 doc%unitAll = find_unused_unit_number()
895 write(filename(1:240),
'(a)') trim(doc%docFileBase)//
'.all'
897 open(doc%unitAll, file=trim(filename), access=
'SEQUENTIAL', form=
'FORMATTED', &
898 action=
'WRITE', status=
'REPLACE', iostat=ios)
899 write(doc%unitAll,
'(a)') &
900 '! This file was written by the model and records all non-layout '//&
901 'or debugging parameters used at run-time.'
903 open(doc%unitAll, file=trim(filename), access=
'SEQUENTIAL', form=
'FORMATTED', &
904 action=
'WRITE', status=
'OLD', position=
'APPEND', iostat=ios)
906 inquire(doc%unitAll, opened=opened)
907 if ((.not.opened) .or. (ios /= 0))
then
908 call mom_error(fatal,
"Failed to open doc file "//trim(filename)//
".")
910 doc%filesAreOpen = .true.
913 if ((len_trim(doc%docFileBase) > 0) .and. doc%minimal .and. (doc%unitShort<0))
then
914 new_file = .true. ;
if (doc%unitShort /= -1) new_file = .false.
915 doc%unitShort = find_unused_unit_number()
917 write(filename(1:240),
'(a)') trim(doc%docFileBase)//
'.short'
919 open(doc%unitShort, file=trim(filename), access=
'SEQUENTIAL', form=
'FORMATTED', &
920 action=
'WRITE', status=
'REPLACE', iostat=ios)
921 write(doc%unitShort,
'(a)') &
922 '! This file was written by the model and records the non-default parameters used at run-time.'
924 open(doc%unitShort, file=trim(filename), access=
'SEQUENTIAL', form=
'FORMATTED', &
925 action=
'WRITE', status=
'OLD', position=
'APPEND', iostat=ios)
927 inquire(doc%unitShort, opened=opened)
928 if ((.not.opened) .or. (ios /= 0))
then
929 call mom_error(fatal,
"Failed to open doc file "//trim(filename)//
".")
931 doc%filesAreOpen = .true.
934 if ((len_trim(doc%docFileBase) > 0) .and. doc%layout .and. (doc%unitLayout<0))
then
935 new_file = .true. ;
if (doc%unitLayout /= -1) new_file = .false.
936 doc%unitLayout = find_unused_unit_number()
938 write(filename(1:240),
'(a)') trim(doc%docFileBase)//
'.layout'
940 open(doc%unitLayout, file=trim(filename), access=
'SEQUENTIAL', form=
'FORMATTED', &
941 action=
'WRITE', status=
'REPLACE', iostat=ios)
942 write(doc%unitLayout,
'(a)') &
943 '! This file was written by the model and records the layout parameters used at run-time.'
945 open(doc%unitLayout, file=trim(filename), access=
'SEQUENTIAL', form=
'FORMATTED', &
946 action=
'WRITE', status=
'OLD', position=
'APPEND', iostat=ios)
948 inquire(doc%unitLayout, opened=opened)
949 if ((.not.opened) .or. (ios /= 0))
then
950 call mom_error(fatal,
"Failed to open doc file "//trim(filename)//
".")
952 doc%filesAreOpen = .true.
955 if ((len_trim(doc%docFileBase) > 0) .and. doc%debugging .and. (doc%unitDebugging<0))
then
956 new_file = .true. ;
if (doc%unitDebugging /= -1) new_file = .false.
957 doc%unitDebugging = find_unused_unit_number()
959 write(filename(1:240),
'(a)') trim(doc%docFileBase)//
'.debugging'
961 open(doc%unitDebugging, file=trim(filename), access=
'SEQUENTIAL', form=
'FORMATTED', &
962 action=
'WRITE', status=
'REPLACE', iostat=ios)
963 write(doc%unitDebugging,
'(a)') &
964 '! This file was written by the model and records the debugging parameters used at run-time.'
966 open(doc%unitDebugging, file=trim(filename), access=
'SEQUENTIAL', form=
'FORMATTED', &
967 action=
'WRITE', status=
'OLD', position=
'APPEND', iostat=ios)
969 inquire(doc%unitDebugging, opened=opened)
970 if ((.not.opened) .or. (ios /= 0))
then
971 call mom_error(fatal,
"Failed to open doc file "//trim(filename)//
".")
973 doc%filesAreOpen = .true.
976 end subroutine open_doc_file
979 function find_unused_unit_number()
982 integer :: find_unused_unit_number
984 do find_unused_unit_number=512,42,-1
985 inquire( find_unused_unit_number, opened=opened)
986 if (.not.opened)
exit
988 if (opened)
call mom_error(fatal, &
989 "doc_init failed to find an unused unit number.")
990 end function find_unused_unit_number
994 subroutine doc_end(doc)
997 type(
link_msg),
pointer :: this => null(), next => null()
999 if (.not.
associated(doc))
return
1001 if (doc%unitAll > 0)
then
1006 if (doc%unitShort > 0)
then
1007 close(doc%unitShort)
1011 if (doc%unitLayout > 0)
then
1012 close(doc%unitLayout)
1016 if (doc%unitDebugging > 0)
then
1017 close(doc%unitDebugging)
1018 doc%unitDebugging = -2
1021 doc%filesAreOpen = .false.
1023 this => doc%chain_msg
1024 do while(
associated(this) )
1029 end subroutine doc_end
1034 function mesghasbeendocumented(doc,varName,mesg)
1037 character(len=*),
intent(in) :: varname
1038 character(len=*),
intent(in) :: mesg
1040 logical :: mesghasbeendocumented
1042 type(
link_msg),
pointer :: newlink => null(), this => null(), last => null()
1044 mesghasbeendocumented = .false.
1050 this => doc%chain_msg
1051 do while(
associated(this) )
1052 if (trim(doc%blockPrefix)//trim(varname) == trim(this%name))
then
1053 mesghasbeendocumented = .true.
1054 if (trim(mesg) == trim(this%msg))
return
1056 if (mesg(1:1) ==
'!')
return
1057 call mom_error(warning,
"Previous msg:"//trim(this%msg))
1058 call mom_error(warning,
"New message :"//trim(mesg))
1059 call mom_error(warning,
"Encountered inconsistent documentation line for parameter "&
1060 //trim(varname)//
"!")
1068 newlink%name = trim(doc%blockPrefix)//trim(varname)
1069 newlink%msg = trim(mesg)
1070 newlink%next => null()
1071 if (.not.
associated(doc%chain_msg))
then
1072 doc%chain_msg => newlink
1074 if (.not.
associated(last))
call mom_error(fatal, &
1075 "Unassociated LINK in mesgHasBeenDocumented: "//trim(mesg))
1076 last%next => newlink
1078 end function mesghasbeendocumented