Neko  0.9.0
A portable framework for high-order spectral element flow simulations
log.f90
Go to the documentation of this file.
1 ! Copyright (c) 2021-2024, The Neko Authors
2 ! All rights reserved.
3 !
4 ! Redistribution and use in source and binary forms, with or without
5 ! modification, are permitted provided that the following conditions
6 ! are met:
7 !
8 ! * Redistributions of source code must retain the above copyright
9 ! notice, this list of conditions and the following disclaimer.
10 !
11 ! * Redistributions in binary form must reproduce the above
12 ! copyright notice, this list of conditions and the following
13 ! disclaimer in the documentation and/or other materials provided
14 ! with the distribution.
15 !
16 ! * Neither the name of the authors nor the names of its
17 ! contributors may be used to endorse or promote products derived
18 ! from this software without specific prior written permission.
19 !
20 ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 ! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 ! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 ! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 ! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 ! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 ! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 ! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 ! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 ! POSSIBILITY OF SUCH DAMAGE.
32 !
34 module logger
35  use comm, only : pe_rank
36  use num_types, only : rp
37  use, intrinsic :: iso_fortran_env, only: stdout => output_unit, &
38  stderr => error_unit
39  implicit none
40  private
41 
42  integer, public, parameter :: log_size = 80
43 
44  type, public :: log_t
45  integer :: indent_
46  integer :: section_id_
47  integer :: level_
48  integer :: unit_
49  contains
50  procedure, pass(this) :: init => log_init
51  procedure, pass(this) :: begin => log_begin
52  procedure, pass(this) :: end => log_end
53  procedure, pass(this) :: indent => log_indent
54  procedure, pass(this) :: newline => log_newline
55  procedure, pass(this) :: message => log_message
56  procedure, pass(this) :: section => log_section
57  procedure, pass(this) :: status => log_status
58  procedure, pass(this) :: header => log_header
59  procedure, pass(this) :: error => log_error
60  procedure, pass(this) :: warning => log_warning
61  procedure, pass(this) :: end_section => log_end_section
62  end type log_t
63 
65  type(log_t), public :: neko_log
67  integer, public, parameter :: neko_log_quiet = 0
69  integer, public, parameter :: neko_log_info = 1
71  integer, public, parameter :: neko_log_verbose = 2
73  integer, public, parameter :: neko_log_debug = 10
74 
75 contains
76 
78  subroutine log_init(this)
79  class(log_t), intent(inout) :: this
80  character(len=255) :: log_level
81  character(len=255) :: log_file
82  integer :: envvar_len
83 
84  this%indent_ = 1
85  this%section_id_ = 0
86 
87  call get_environment_variable("NEKO_LOG_LEVEL", log_level, envvar_len)
88  if (envvar_len .gt. 0) then
89  read(log_level(1:envvar_len), *) this%level_
90  else
91  this%level_ = neko_log_info
92  end if
93 
94  call get_environment_variable("NEKO_LOG_FILE", log_file, envvar_len)
95  if (envvar_len .gt. 0) then
96  this%unit_ = 69
97  open(unit = this%unit_, file = trim(log_file), status = 'replace', &
98  action = 'write')
99  else
100  this%unit_ = stdout
101  end if
102 
103  end subroutine log_init
104 
106  subroutine log_begin(this)
107  class(log_t), intent(inout) :: this
108 
109  if (pe_rank .eq. 0) then
110  this%indent_ = this%indent_ + 1
111  end if
112 
113  end subroutine log_begin
114 
116  subroutine log_end(this)
117  class(log_t), intent(inout) :: this
118 
119  if (pe_rank .eq. 0) then
120  this%indent_ = this%indent_ - 1
121  end if
122 
123  end subroutine log_end
124 
126  subroutine log_indent(this)
127  class(log_t), intent(in) :: this
128  integer :: i
129 
130  if (pe_rank .eq. 0) then
131  write(this%unit_, '(A)', advance = 'no') repeat(' ', this%indent_)
132  end if
133 
134  end subroutine log_indent
135 
137  subroutine log_newline(this, lvl)
138  class(log_t), intent(in) :: this
139  integer, optional :: lvl
140 
141  integer :: lvl_
142 
143  if (present(lvl)) then
144  lvl_ = lvl
145  else
146  lvl_ = neko_log_info
147  end if
148 
149  if (lvl_ .gt. this%level_) then
150  return
151  end if
152 
153  if (pe_rank .eq. 0) then
154  write(this%unit_, '(A)') ''
155  end if
156 
157  end subroutine log_newline
158 
160  subroutine log_message(this, msg, lvl)
161  class(log_t), intent(in) :: this
162  character(len=*), intent(in) :: msg
163  integer, optional :: lvl
164  integer :: lvl_
165 
166  if (present(lvl)) then
167  lvl_ = lvl
168  else
169  lvl_ = neko_log_info
170  end if
171 
172  if (lvl_ .gt. this%level_) then
173  return
174  end if
175 
176  if (pe_rank .eq. 0) then
177  call this%indent()
178  write(this%unit_, '(A)') trim(msg)
179  end if
180 
181  end subroutine log_message
182 
184  subroutine log_header(this, version, build_info)
185  class(log_t), intent(in) :: this
186  character(len=*), intent(in) :: version
187  character(len=*), intent(in) :: build_info
188 
189  if (pe_rank .eq. 0) then
190  write(this%unit_, '(A)') ''
191  write(this%unit_, '(1X,A)') ' _ __ ____ __ __ ____ '
192  write(this%unit_, '(1X,A)') ' / |/ / / __/ / //_/ / __ \ '
193  write(this%unit_, '(1X,A)') ' / / / _/ / ,< / /_/ / '
194  write(this%unit_, '(1X,A)') '/_/|_/ /___/ /_/|_| \____/ '
195  write(this%unit_, '(A)') ''
196  write(this%unit_, '(1X,A,A,A)') '(version: ', trim(version), ')'
197  write(this%unit_, '(1X,A)') trim(build_info)
198  write(this%unit_, '(A)') ''
199  end if
200 
201  end subroutine log_header
202 
204  subroutine log_error(this, msg)
205  class(log_t), intent(in) :: this
206  character(len=*), intent(in) :: msg
207 
208  if (pe_rank .eq. 0) then
209  call this%indent()
210  write(stderr, '(A,A,A)') '*** ERROR: ', trim(msg), ' ***'
211  end if
212 
213  end subroutine log_error
214 
216  subroutine log_warning(this, msg)
217  class(log_t), intent(in) :: this
218  character(len=*), intent(in) :: msg
219 
220  if (pe_rank .eq. 0) then
221  call this%indent()
222  write(this%unit_, '(A,A,A)') '*** WARNING: ', trim(msg), ' ***'
223  end if
224 
225  end subroutine log_warning
226 
228  subroutine log_section(this, msg, lvl)
229  class(log_t), intent(inout) :: this
230  character(len=*), intent(in) :: msg
231  integer, optional :: lvl
232 
233  integer :: i, pre, pos
234  integer :: lvl_
235 
236  if (present(lvl)) then
237  lvl_ = lvl
238  else
239  lvl_ = neko_log_info
240  end if
241 
242  if (lvl_ .gt. this%level_) then
243  return
244  end if
245 
246  if (pe_rank .eq. 0) then
247 
248  this%indent_ = this%indent_ + this%section_id_
249  this%section_id_ = this%section_id_ + 1
250 
251  pre = (30 - len_trim(msg)) / 2
252  pos = 30 - (len_trim(msg) + pre)
253 
254  write(this%unit_, '(A)') ''
255  call this%indent()
256  write(this%unit_, '(A,A,A)') &
257  repeat('-', pre), trim(msg), repeat('-', pos)
258 
259  end if
260 
261  end subroutine log_section
262 
264  subroutine log_end_section(this, msg, lvl)
265  class(log_t), intent(inout) :: this
266  character(len=*), intent(in), optional :: msg
267  integer, optional :: lvl
268  integer :: lvl_
269 
270  if (present(lvl)) then
271  lvl_ = lvl
272  else
273  lvl_ = neko_log_info
274  end if
275 
276  if (lvl_ .gt. this%level_) then
277  return
278  end if
279 
280  if (present(msg)) then
281  call this%message(msg, neko_log_quiet)
282  end if
283 
284  if (pe_rank .eq. 0) then
285  this%section_id_ = this%section_id_ - 1
286  this%indent_ = this%indent_ - this%section_id_
287  end if
288 
289  end subroutine log_end_section
290 
293  subroutine log_status(this, t, T_end)
294  class(log_t), intent(in) :: this
295  real(kind=rp), intent(in) :: t
296  real(kind=rp), intent(in) :: t_end
297  character(len=LOG_SIZE) :: log_buf
298  real(kind=rp) :: t_prog
299 
300  t_prog = 100d0 * t / t_end
301  write(log_buf, '(A4,E15.7,34X,A2,F6.2,A3)') 't = ', t, '[ ', t_prog, '% ]'
302 
303  call this%message(repeat('-', 64), neko_log_quiet)
304  call this%message(log_buf, neko_log_quiet)
305  call this%message(repeat('-', 64), neko_log_quiet)
306 
307  end subroutine log_status
308 
309  !
310  ! Rudimentary C interface
311  !
312 
315  subroutine log_message_c(c_msg) bind(c, name = 'log_message')
316  use, intrinsic :: iso_c_binding
317  character(kind=c_char), dimension(*), intent(in) :: c_msg
318  character(len=LOG_SIZE) :: msg
319  integer :: len
320 
321  if (pe_rank .eq. 0) then
322  len = 0
323  do
324  if (c_msg(len+1) .eq. c_null_char) exit
325  len = len + 1
326  msg(len:len) = c_msg(len)
327  end do
328 
329  call neko_log%indent()
330  write(neko_log%unit_, '(A)') trim(msg(1:len))
331  end if
332 
333  end subroutine log_message_c
334 
337  subroutine log_error_c(c_msg) bind(c, name = "log_error")
338  use, intrinsic :: iso_c_binding
339  character(kind=c_char), dimension(*), intent(in) :: c_msg
340  character(len=LOG_SIZE) :: msg
341  integer :: len
342 
343  if (pe_rank .eq. 0) then
344  len = 0
345  do
346  if (c_msg(len+1) .eq. c_null_char) exit
347  len = len + 1
348  msg(len:len) = c_msg(len)
349  end do
350 
351  call neko_log%indent()
352  write(stderr, '(A,A,A)') '*** ERROR: ', trim(msg(1:len)), ' ***'
353  end if
354 
355  end subroutine log_error_c
356 
359  subroutine log_warning_c(c_msg) bind(c, name = "log_warning")
360  use, intrinsic :: iso_c_binding
361  character(kind=c_char), dimension(*), intent(in) :: c_msg
362  character(len=LOG_SIZE) :: msg
363  integer :: len
364 
365  if (pe_rank .eq. 0) then
366  len = 0
367  do
368  if (c_msg(len+1) .eq. c_null_char) exit
369  len = len + 1
370  msg(len:len) = c_msg(len)
371  end do
372 
373  call neko_log%indent()
374  write(neko_log%unit_, '(A,A,A)') &
375  '*** WARNING: ', trim(msg(1:len)), ' ***'
376  end if
377 
378  end subroutine log_warning_c
379 
382  subroutine log_section_c(c_msg) bind(c, name = "log_section")
383  use, intrinsic :: iso_c_binding
384  character(kind=c_char), dimension(*), intent(in) :: c_msg
385  character(len=LOG_SIZE) :: msg
386  integer :: len
387 
388  if (pe_rank .eq. 0) then
389  len = 0
390  do
391  if (c_msg(len+1) .eq. c_null_char) exit
392  len = len + 1
393  msg(len:len) = c_msg(len)
394  end do
395 
396  call neko_log%section(trim(msg(1:len)))
397  end if
398 
399  end subroutine log_section_c
400 
403  subroutine log_end_section_c() bind(c, name = "log_end_section")
404 
405  call neko_log%end_section()
406 
407  end subroutine log_end_section_c
408 
409 end module logger
Definition: comm.F90:1
integer pe_rank
MPI rank.
Definition: comm.F90:28
Module for file I/O operations.
Definition: file.f90:34
Logging routines.
Definition: log.f90:34
subroutine log_end_section_c()
End a log section (from C)
Definition: log.f90:404
subroutine log_status(this, t, T_end)
Write status banner.
Definition: log.f90:294
subroutine log_end(this)
Decrease indention level.
Definition: log.f90:117
subroutine log_header(this, version, build_info)
Write the Neko header to a log.
Definition: log.f90:185
integer, parameter, public neko_log_verbose
Verbose log level.
Definition: log.f90:71
subroutine log_message(this, msg, lvl)
Write a message to a log.
Definition: log.f90:161
integer, parameter, public neko_log_quiet
Always logged.
Definition: log.f90:67
subroutine log_begin(this)
Increase indention level.
Definition: log.f90:107
subroutine log_message_c(c_msg)
Write a message to a log (from C)
Definition: log.f90:316
subroutine log_end_section(this, msg, lvl)
End a log section.
Definition: log.f90:265
subroutine log_init(this)
Initialize a log.
Definition: log.f90:79
subroutine log_warning(this, msg)
Write a warning message to a log.
Definition: log.f90:217
subroutine log_error_c(c_msg)
Write an error message to a log (from C)
Definition: log.f90:338
subroutine log_indent(this)
Indent a log.
Definition: log.f90:127
subroutine log_warning_c(c_msg)
Write a warning message to a log (from C)
Definition: log.f90:360
subroutine log_newline(this, lvl)
Write a new line to a log.
Definition: log.f90:138
subroutine log_section_c(c_msg)
Begin a new log section (from C)
Definition: log.f90:383
integer, parameter, public neko_log_debug
Debug log level.
Definition: log.f90:73
type(log_t), public neko_log
Global log stream.
Definition: log.f90:65
integer, parameter, public log_size
Definition: log.f90:42
integer, parameter, public neko_log_info
Default log level.
Definition: log.f90:69
subroutine log_section(this, msg, lvl)
Begin a new log section.
Definition: log.f90:229
subroutine log_error(this, msg)
Write an error message to a log.
Definition: log.f90:205
integer, parameter, public rp
Global precision used in computations.
Definition: num_types.f90:12