(git:34ef472)
cp_error_handling.F
Go to the documentation of this file.
1 !--------------------------------------------------------------------------------------------------!
2 ! CP2K: A general program to perform molecular dynamics simulations !
3 ! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4 ! !
5 ! SPDX-License-Identifier: GPL-2.0-or-later !
6 !--------------------------------------------------------------------------------------------------!
7 
8 ! **************************************************************************************************
9 !> \brief Module that contains the routines for error handling
10 !> \author Ole Schuett
11 ! **************************************************************************************************
13  USE base_hooks, ONLY: cp_abort_hook,&
14  cp_hint_hook,&
17  USE kinds, ONLY: dp
18  USE machine, ONLY: default_output_unit,&
19  m_flush,&
21  USE message_passing, ONLY: mp_abort
22  USE print_messages, ONLY: print_message
23  USE timings, ONLY: print_stack
24 
25 !$ USE OMP_LIB, ONLY: omp_get_thread_num
26 
27  IMPLICIT NONE
28  PRIVATE
29 
30  CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_error_handling'
31 
32  !API public routines
33  PUBLIC :: cp_error_handling_setup
34 
35  !API (via pointer assignment to hook, PR67982, not meant to be called directly)
37 
38  INTEGER, PUBLIC, SAVE :: warning_counter = 0
39 
40 CONTAINS
41 
42 ! **************************************************************************************************
43 !> \brief Registers handlers with base_hooks.F
44 !> \author Ole Schuett
45 ! **************************************************************************************************
50  END SUBROUTINE cp_error_handling_setup
51 
52 ! **************************************************************************************************
53 !> \brief Abort program with error message
54 !> \param location ...
55 !> \param message ...
56 !> \author Ole Schuett
57 ! **************************************************************************************************
58  SUBROUTINE cp_abort_handler(location, message)
59  CHARACTER(len=*), INTENT(in) :: location, message
60 
61  INTEGER :: unit_nr
62 
63  CALL delay_non_master() ! cleaner output if all ranks abort simultaneously
64 
66  IF (unit_nr <= 0) &
67  unit_nr = default_output_unit ! fall back to stdout
68 
69  CALL print_abort_message(message, location, unit_nr)
70  CALL print_stack(unit_nr)
71  FLUSH (unit_nr) ! ignore &GLOBAL / FLUSH_SHOULD_FLUSH
72 
73  CALL mp_abort()
74  END SUBROUTINE cp_abort_handler
75 
76 ! **************************************************************************************************
77 !> \brief Signal a warning
78 !> \param location ...
79 !> \param message ...
80 !> \author Ole Schuett
81 ! **************************************************************************************************
82  SUBROUTINE cp_warn_handler(location, message)
83  CHARACTER(len=*), INTENT(in) :: location, message
84 
85  INTEGER :: unit_nr
86 
87 !$OMP MASTER
89 !$OMP END MASTER
90 
92  IF (unit_nr > 0) THEN
93  CALL print_message("WARNING in "//trim(location)//' :: '//trim(adjustl(message)), unit_nr, 1, 1, 1)
94  CALL m_flush(unit_nr)
95  END IF
96  END SUBROUTINE cp_warn_handler
97 
98 ! **************************************************************************************************
99 !> \brief Signal a hint
100 !> \param location ...
101 !> \param message ...
102 !> \author Ole Schuett
103 ! **************************************************************************************************
104  SUBROUTINE cp_hint_handler(location, message)
105  CHARACTER(len=*), INTENT(in) :: location, message
106 
107  INTEGER :: unit_nr
108 
110  IF (unit_nr > 0) THEN
111  CALL print_message("HINT in "//trim(location)//' :: '//trim(adjustl(message)), unit_nr, 1, 1, 1)
112  CALL m_flush(unit_nr)
113  END IF
114  END SUBROUTINE cp_hint_handler
115 
116 ! **************************************************************************************************
117 !> \brief Delay non-master ranks/threads, used by cp_abort_handler()
118 !> \author Ole Schuett
119 ! **************************************************************************************************
120  SUBROUTINE delay_non_master()
121  INTEGER :: unit_nr
122  REAL(kind=dp) :: t1, wait_time
123 
124  wait_time = 0.0_dp
125 
126  ! we (ab)use the logger to determine the first MPI rank
128  IF (unit_nr <= 0) &
129  wait_time = wait_time + 1.0_dp ! rank-0 gets a head start of one second.
130 
131 !$ IF (omp_get_thread_num() /= 0) &
132 !$ wait_time = wait_time + 1.0_dp ! master threads gets another second
133 
134  ! sleep
135  IF (wait_time > 0.0_dp) THEN
136  t1 = m_walltime()
137  DO
138  IF (m_walltime() - t1 > wait_time .OR. t1 < 0) EXIT
139  END DO
140  END IF
141 
142  END SUBROUTINE delay_non_master
143 
144 ! **************************************************************************************************
145 !> \brief Prints a nicely formatted abort message box
146 !> \param message ...
147 !> \param location ...
148 !> \param output_unit ...
149 !> \author Ole Schuett
150 ! **************************************************************************************************
151  SUBROUTINE print_abort_message(message, location, output_unit)
152  CHARACTER(LEN=*), INTENT(IN) :: message, location
153  INTEGER, INTENT(IN) :: output_unit
154 
155  INTEGER, PARAMETER :: img_height = 8, img_width = 9, screen_width = 80, &
156  txt_width = screen_width - img_width - 5
157  CHARACTER(LEN=img_width), DIMENSION(img_height), PARAMETER :: img = [" ___ ", " / \ "&
158  , " [ABORT] ", " \___/ ", " | ", " O/| ", " /| | ", " / \ "]
159 
160  CHARACTER(LEN=screen_width) :: msg_line
161  INTEGER :: a, b, c, fill, i, img_start, indent, &
162  msg_height, msg_start
163 
164 ! count message lines
165 
166  a = 1; b = -1; msg_height = 0
167  DO WHILE (b < len_trim(message))
168  b = next_linebreak(message, a, txt_width)
169  a = b + 1
170  msg_height = msg_height + 1
171  END DO
172 
173  ! calculate message and image starting lines
174  IF (img_height > msg_height) THEN
175  msg_start = (img_height - msg_height)/2 + 1
176  img_start = 1
177  ELSE
178  msg_start = 1
179  img_start = msg_height - img_height + 2
180  END IF
181 
182  ! print empty line
183  WRITE (unit=output_unit, fmt="(A)") ""
184 
185  ! print opening line
186  WRITE (unit=output_unit, fmt="(T2,A)") repeat("*", screen_width - 1)
187 
188  ! print body
189  a = 1; b = -1; c = 1
190  DO i = 1, max(img_height - 1, msg_height)
191  WRITE (unit=output_unit, fmt="(A)", advance='no') " *"
192  IF (i < img_start) THEN
193  WRITE (unit=output_unit, fmt="(A)", advance='no') repeat(" ", img_width)
194  ELSE
195  WRITE (unit=output_unit, fmt="(A)", advance='no') img(c)
196  c = c + 1
197  END IF
198  IF (i < msg_start) THEN
199  WRITE (unit=output_unit, fmt="(A)", advance='no') repeat(" ", txt_width + 2)
200  ELSE
201  b = next_linebreak(message, a, txt_width)
202  msg_line = message(a:b)
203  a = b + 1
204  fill = (txt_width - len_trim(msg_line))/2 + 1
205  indent = txt_width - len_trim(msg_line) - fill + 2
206  WRITE (unit=output_unit, fmt="(A)", advance='no') repeat(" ", indent)
207  WRITE (unit=output_unit, fmt="(A)", advance='no') trim(msg_line)
208  WRITE (unit=output_unit, fmt="(A)", advance='no') repeat(" ", fill)
209  END IF
210  WRITE (unit=output_unit, fmt="(A)", advance='yes') "*"
211  END DO
212 
213  ! print location line
214  WRITE (unit=output_unit, fmt="(A)", advance='no') " *"
215  WRITE (unit=output_unit, fmt="(A)", advance='no') img(c)
216  indent = txt_width - len_trim(location) + 1
217  WRITE (unit=output_unit, fmt="(A)", advance='no') repeat(" ", indent)
218  WRITE (unit=output_unit, fmt="(A)", advance='no') trim(location)
219  WRITE (unit=output_unit, fmt="(A)", advance='yes') " *"
220 
221  ! print closing line
222  WRITE (unit=output_unit, fmt="(T2,A)") repeat("*", screen_width - 1)
223 
224  ! print empty line
225  WRITE (unit=output_unit, fmt="(A)") ""
226 
227  END SUBROUTINE print_abort_message
228 
229 ! **************************************************************************************************
230 !> \brief Helper routine for print_abort_message()
231 !> \param message ...
232 !> \param pos ...
233 !> \param rowlen ...
234 !> \return ...
235 !> \author Ole Schuett
236 ! **************************************************************************************************
237  FUNCTION next_linebreak(message, pos, rowlen) RESULT(ibreak)
238  CHARACTER(LEN=*), INTENT(IN) :: message
239  INTEGER, INTENT(IN) :: pos, rowlen
240  INTEGER :: ibreak
241 
242  INTEGER :: i, n
243 
244  n = len_trim(message)
245  IF (n - pos <= rowlen) THEN
246  ibreak = n ! remaining message shorter than line
247  ELSE
248  i = index(message(pos + 1:pos + 1 + rowlen), " ", back=.true.)
249  IF (i == 0) THEN
250  ibreak = pos + rowlen - 1 ! no space found, break mid-word
251  ELSE
252  ibreak = pos + i ! break at space closest to rowlen
253  END IF
254  END IF
255  END FUNCTION next_linebreak
256 
257 END MODULE cp_error_handling
Central dispatch for basic hooks.
Definition: base_hooks.F:12
procedure(cp_warn_interface), pointer, public cp_warn_hook
Definition: base_hooks.F:59
procedure(cp_abort_interface), pointer, public cp_abort_hook
Definition: base_hooks.F:58
procedure(cp_hint_interface), pointer, public cp_hint_hook
Definition: base_hooks.F:60
Module that contains the routines for error handling.
integer, save, public warning_counter
subroutine, public cp_abort_handler(location, message)
Abort program with error message.
subroutine, public cp_warn_handler(location, message)
Signal a warning.
subroutine, public cp_error_handling_setup()
Registers handlers with base_hooks.F.
subroutine, public cp_hint_handler(location, message)
Signal a hint.
various routines to log and control the output. The idea is that decisions about where to log should ...
integer function, public cp_logger_get_default_io_unit(logger)
returns the unit nr for the ionode (-1 on all other processors) skips as well checks if the procs cal...
Defines the basic variable types.
Definition: kinds.F:23
integer, parameter, public dp
Definition: kinds.F:34
Machine interface based on Fortran 2003 and POSIX.
Definition: machine.F:17
integer, parameter, public default_output_unit
Definition: machine.F:45
subroutine, public m_flush(lunit)
flushes units if the &GLOBAL flag is set accordingly
Definition: machine.F:106
real(kind=dp) function, public m_walltime()
returns time from a real-time clock, protected against rolling early/easily
Definition: machine.F:123
Interface to the message passing library MPI.
subroutine, public mp_abort()
globally stops all tasks this is intended to be low level, most of CP2K should call cp_abort()
Perform an abnormal program termination.
subroutine, public print_message(message, output_unit, declev, before, after)
Perform a basic blocking of the text in message and print it optionally decorated with a frame of sta...
Timing routines for accounting.
Definition: timings.F:17
subroutine, public print_stack(unit_nr)
Print current routine stack.
Definition: timings.F:432