(git:07a6c39)
Loading...
Searching...
No Matches
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-2026 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,&
17 USE kinds, ONLY: dp
18 USE machine, ONLY: default_output_unit,&
19 m_flush,&
21 USE message_passing, ONLY: mp_abort
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
34
35 !API (via pointer assignment to hook, PR67982, not meant to be called directly)
37
38 INTEGER, PUBLIC, SAVE :: warning_counter = 0
39
40CONTAINS
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) THEN
67 unit_nr = default_output_unit
68 END IF ! fall back to stdout
69
70 CALL print_abort_message(message, location, unit_nr)
71 CALL print_stack(unit_nr)
72 FLUSH (unit_nr) ! ignore &GLOBAL / FLUSH_SHOULD_FLUSH
73
74 CALL mp_abort()
75 END SUBROUTINE cp_abort_handler
76
77! **************************************************************************************************
78!> \brief Signal a warning
79!> \param location ...
80!> \param message ...
81!> \author Ole Schuett
82! **************************************************************************************************
83 SUBROUTINE cp_warn_handler(location, message)
84 CHARACTER(len=*), INTENT(in) :: location, message
85
86 INTEGER :: unit_nr
87
88!$OMP MASTER
90!$OMP END MASTER
91
93 IF (unit_nr > 0) THEN
94 CALL print_message("WARNING in "//trim(location)//' :: '//trim(adjustl(message)), unit_nr, 1, 1, 1)
95 CALL m_flush(unit_nr)
96 END IF
97 END SUBROUTINE cp_warn_handler
98
99! **************************************************************************************************
100!> \brief Signal a hint
101!> \param location ...
102!> \param message ...
103!> \author Ole Schuett
104! **************************************************************************************************
105 SUBROUTINE cp_hint_handler(location, message)
106 CHARACTER(len=*), INTENT(in) :: location, message
107
108 INTEGER :: unit_nr
109
111 IF (unit_nr > 0) THEN
112 CALL print_message("HINT in "//trim(location)//' :: '//trim(adjustl(message)), unit_nr, 1, 1, 1)
113 CALL m_flush(unit_nr)
114 END IF
115 END SUBROUTINE cp_hint_handler
116
117! **************************************************************************************************
118!> \brief Delay non-master ranks/threads, used by cp_abort_handler()
119!> \author Ole Schuett
120! **************************************************************************************************
121 SUBROUTINE delay_non_master()
122 INTEGER :: unit_nr
123 REAL(kind=dp) :: t1, wait_time
124
125 wait_time = 0.0_dp
126
127 ! we (ab)use the logger to determine the first MPI rank
129 IF (unit_nr <= 0) THEN
130 wait_time = wait_time + 1.0_dp
131 END IF ! rank-0 gets a head start of one second.
132
133!$ IF (omp_get_thread_num() /= 0) &
134!$ wait_time = wait_time + 1.0_dp ! master threads gets another second
135
136 ! sleep
137 IF (wait_time > 0.0_dp) THEN
138 t1 = m_walltime()
139 DO
140 IF (m_walltime() - t1 > wait_time .OR. t1 < 0) EXIT
141 END DO
142 END IF
143
144 END SUBROUTINE delay_non_master
145
146! **************************************************************************************************
147!> \brief Prints a nicely formatted abort message box
148!> \param message ...
149!> \param location ...
150!> \param output_unit ...
151!> \author Ole Schuett
152! **************************************************************************************************
153 SUBROUTINE print_abort_message(message, location, output_unit)
154 CHARACTER(LEN=*), INTENT(IN) :: message, location
155 INTEGER, INTENT(IN) :: output_unit
156
157 INTEGER, PARAMETER :: img_height = 8, img_width = 9, screen_width = 80, &
158 txt_width = screen_width - img_width - 5
159 CHARACTER(LEN=img_width), DIMENSION(img_height), PARAMETER :: img = [" ___ ", " / \ "&
160 , " [ABORT] ", " \___/ ", " | ", " O/| ", " /| | ", " / \ "]
161
162 CHARACTER(LEN=screen_width) :: msg_line
163 INTEGER :: a, b, c, fill, i, img_start, indent, &
164 msg_height, msg_start
165
166! count message lines
167
168 a = 1; b = -1; msg_height = 0
169 DO WHILE (b < len_trim(message))
170 b = next_linebreak(message, a, txt_width)
171 a = b + 1
172 msg_height = msg_height + 1
173 END DO
174
175 ! calculate message and image starting lines
176 IF (img_height > msg_height) THEN
177 msg_start = (img_height - msg_height)/2 + 1
178 img_start = 1
179 ELSE
180 msg_start = 1
181 img_start = msg_height - img_height + 2
182 END IF
183
184 ! print empty line
185 WRITE (unit=output_unit, fmt="(A)") ""
186
187 ! print opening line
188 WRITE (unit=output_unit, fmt="(T2,A)") repeat("*", screen_width - 1)
189
190 ! print body
191 a = 1; b = -1; c = 1
192 DO i = 1, max(img_height - 1, msg_height)
193 WRITE (unit=output_unit, fmt="(A)", advance='no') " *"
194 IF (i < img_start) THEN
195 WRITE (unit=output_unit, fmt="(A)", advance='no') repeat(" ", img_width)
196 ELSE
197 WRITE (unit=output_unit, fmt="(A)", advance='no') img(c)
198 c = c + 1
199 END IF
200 IF (i < msg_start) THEN
201 WRITE (unit=output_unit, fmt="(A)", advance='no') repeat(" ", txt_width + 2)
202 ELSE
203 b = next_linebreak(message, a, txt_width)
204 msg_line = message(a:b)
205 a = b + 1
206 fill = (txt_width - len_trim(msg_line))/2 + 1
207 indent = txt_width - len_trim(msg_line) - fill + 2
208 WRITE (unit=output_unit, fmt="(A)", advance='no') repeat(" ", indent)
209 WRITE (unit=output_unit, fmt="(A)", advance='no') trim(msg_line)
210 WRITE (unit=output_unit, fmt="(A)", advance='no') repeat(" ", fill)
211 END IF
212 WRITE (unit=output_unit, fmt="(A)", advance='yes') "*"
213 END DO
214
215 ! print location line
216 WRITE (unit=output_unit, fmt="(A)", advance='no') " *"
217 WRITE (unit=output_unit, fmt="(A)", advance='no') img(c)
218 indent = txt_width - len_trim(location) + 1
219 WRITE (unit=output_unit, fmt="(A)", advance='no') repeat(" ", indent)
220 WRITE (unit=output_unit, fmt="(A)", advance='no') trim(location)
221 WRITE (unit=output_unit, fmt="(A)", advance='yes') " *"
222
223 ! print closing line
224 WRITE (unit=output_unit, fmt="(T2,A)") repeat("*", screen_width - 1)
225
226 ! print empty line
227 WRITE (unit=output_unit, fmt="(A)") ""
228
229 END SUBROUTINE print_abort_message
230
231! **************************************************************************************************
232!> \brief Helper routine for print_abort_message()
233!> \param message ...
234!> \param pos ...
235!> \param rowlen ...
236!> \return ...
237!> \author Ole Schuett
238! **************************************************************************************************
239 FUNCTION next_linebreak(message, pos, rowlen) RESULT(ibreak)
240 CHARACTER(LEN=*), INTENT(IN) :: message
241 INTEGER, INTENT(IN) :: pos, rowlen
242 INTEGER :: ibreak
243
244 INTEGER :: i, n
245
246 n = len_trim(message)
247 IF (n - pos <= rowlen) THEN
248 ibreak = n ! remaining message shorter than line
249 ELSE
250 i = index(message(pos + 1:pos + 1 + rowlen), " ", back=.true.)
251 IF (i == 0) THEN
252 ibreak = pos + rowlen - 1 ! no space found, break mid-word
253 ELSE
254 ibreak = pos + i ! break at space closest to rowlen
255 END IF
256 END IF
257 END FUNCTION next_linebreak
258
259END 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:46
subroutine, public m_flush(lunit)
flushes units if the &GLOBAL flag is set accordingly
Definition machine.F:124
real(kind=dp) function, public m_walltime()
returns time from a real-time clock, protected against rolling early/easily
Definition machine.F:141
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:437