Line data Source code
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 various routines to log and control the output.
10 : !> The idea is that decisions about where to log should not be done in
11 : !> the code that generates the log, but should be globally changeable
12 : !> a central place.
13 : !> So some care has been taken to have enough information about the
14 : !> place from where the log comes so that in the future intelligent and
15 : !> flexible decisions can be taken by the logger, without having to change
16 : !> other code.
17 : !> \note
18 : !> contains also routines to convert to a string.
19 : !> in my idea they should have been with variable length,
20 : !> (i.e. they should have returned a trim(adjustl(actual_result)))
21 : !> As a logger should be robust, at the moment I have given up.
22 : !>
23 : !> At the moment logging and output refer to the same object
24 : !> (cp_logger_type)
25 : !> as these are actually different it might be better to separate them
26 : !> (they have already separate routines in a separate module
27 : !> @see cp_output_handling).
28 : !>
29 : !> some practices (use of print *, no cp_error_type,
30 : !> manual retain release of some objects) are dictated by the need to
31 : !> have minimal dependency
32 : !> \par History
33 : !> 08.2002 major update: retain, release, printkeys, para_env,
34 : !> local logging [fawzi]
35 : !> 02.2004 made a stack of default loggers [Joost VandeVondele]
36 : !> \par
37 : !> @see cp_error_handling
38 : !> \author Fawzi Mohamed
39 : !> @version 12.2001
40 : ! **************************************************************************************************
41 : MODULE cp_log_handling
42 : USE cp_files, ONLY: close_file,&
43 : open_file
44 : USE cp_iter_types, ONLY: cp_iteration_info_create,&
45 : cp_iteration_info_release,&
46 : cp_iteration_info_retain,&
47 : cp_iteration_info_type
48 : USE kinds, ONLY: default_path_length,&
49 : default_string_length,&
50 : dp
51 : USE machine, ONLY: default_output_unit,&
52 : m_getpid,&
53 : m_hostnm
54 : USE message_passing, ONLY: mp_para_env_release,&
55 : mp_para_env_type
56 : USE string_utilities, ONLY: compress
57 : USE timings, ONLY: print_stack
58 : #include "../base/base_uses.f90"
59 :
60 : IMPLICIT NONE
61 : PRIVATE
62 :
63 : !API types
64 : PUBLIC :: cp_logger_type, cp_logger_p_type
65 : !API parameter vars
66 : PUBLIC :: cp_note_level, cp_warning_level, cp_failure_level, cp_fatal_level
67 : !API default loggers
68 : PUBLIC :: cp_get_default_logger, cp_add_default_logger, cp_rm_default_logger, &
69 : cp_default_logger_stack_size
70 : !API logger routines
71 : PUBLIC :: cp_logger_create, cp_logger_retain, cp_logger_release, &
72 : cp_logger_would_log, cp_logger_set, cp_logger_get_default_unit_nr, &
73 : cp_logger_get_default_io_unit, cp_logger_get_unit_nr, &
74 : cp_logger_set_log_level, cp_logger_generate_filename, &
75 : cp_to_string
76 :
77 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_log_handling'
78 : LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .FALSE.
79 :
80 : !! level of an error
81 : INTEGER, PARAMETER :: cp_fatal_level = 3
82 : !! level of a failure
83 : INTEGER, PARAMETER :: cp_failure_level = 2
84 : !! level of a warning
85 : INTEGER, PARAMETER :: cp_warning_level = 1
86 : !! level of a note
87 : INTEGER, PARAMETER :: cp_note_level = 0
88 :
89 : !! a generic function to transform different types to strings
90 : INTERFACE cp_to_string
91 : MODULE PROCEDURE cp_int_to_string, cp_real_dp_to_string, cp_logical_to_string
92 : END INTERFACE
93 :
94 : ! **************************************************************************************************
95 : !> \brief type of a logger, at the moment it contains just a print level
96 : !> starting at which level it should be logged
97 : !> (0 note, 1 warning, 2 failure, 3 fatal)
98 : !> it could be expanded with the ability to focus on one or more
99 : !> module/object/thread/processor
100 : !> \param ref_count reference count (see cp2k/doc/ReferenceCounting.html)
101 : !> \param print_level the level starting at which something gets printed
102 : !> \param default_local_unit_nr default unit for local logging (-1 if not
103 : !> yet initialized). Local logging guarantee to each task its own
104 : !> file.
105 : !> \param default_global_unit_nr default unit for global logging
106 : !> (-1 if not yet initialized). This unit is valid only on the
107 : !> processor with %para_env%mepos==%para_env%source.
108 : !> \param para_env the parallel environment for the output.
109 : !> this might be a super environment of your computation environment
110 : !> i.e. be very careful not to do global operations like broadcast
111 : !> with a subset of its processors (use your computation environment
112 : !> instead).
113 : !> \param close_local_unit_on_dealloc if the local unit should be closed
114 : !> when this logger is deallocated
115 : !> \param close_global_unit_on_dealloc whether the global unit should be
116 : !> closed when this logger is deallocated
117 : !> \param suffix a short string that is used as suffix in all the filenames
118 : !> created by this logger. Can be used to guarantee the unicity of
119 : !> generated filename
120 : !> \param local_filename the root of the name of the file used for local
121 : !> logging (can be different from the name of the file corresponding
122 : !> to default_local_unit_nr, only the one used if the unit needs to
123 : !> be opened)
124 : !> \param global_filename the root of the name of the file used for
125 : !> global logging (can be different from the name of the file
126 : !> corresponding to default_global_unit_nr, only the one used if
127 : !> the unit needs to be opened)
128 : !> \param print_keys print keys that tell what should be logged/outputted
129 : !> \note
130 : !> This should be private, but as the output functions have been
131 : !> moved to another module and there is no "friend" keyword, they
132 : !> are public.
133 : !> DO NOT USE THE INTERNAL COMPONENTS DIRECTLY!!!
134 : !> \par History
135 : !> 04.2002 revised [fawzi]
136 : !> 08.2002 major update: retain, release, printkeys, para_env,
137 : !> local logging [fawzi]
138 : !> \author Fawzi Mohamed
139 : ! **************************************************************************************************
140 : TYPE cp_logger_type
141 : INTEGER :: ref_count = -1
142 : INTEGER :: print_level = -1
143 : INTEGER :: default_local_unit_nr = -1
144 : INTEGER :: default_global_unit_nr = -1
145 : LOGICAL :: close_local_unit_on_dealloc = .FALSE., close_global_unit_on_dealloc = .FALSE.
146 : CHARACTER(len=default_string_length) :: suffix = ""
147 : CHARACTER(len=default_path_length) :: local_filename = "", global_filename = ""
148 : TYPE(mp_para_env_type), POINTER :: para_env => NULL()
149 : TYPE(cp_iteration_info_type), POINTER :: iter_info => NULL()
150 : END TYPE cp_logger_type
151 :
152 : TYPE cp_logger_p_type
153 : TYPE(cp_logger_type), POINTER :: p => Null()
154 : END TYPE cp_logger_p_type
155 :
156 : ! **************************************************************************************************
157 : TYPE default_logger_stack_type
158 : TYPE(cp_logger_type), POINTER :: cp_default_logger => Null()
159 : END TYPE default_logger_stack_type
160 :
161 : INTEGER, PRIVATE :: stack_pointer = 0
162 : INTEGER, PARAMETER, PRIVATE :: max_stack_pointer = 10
163 : TYPE(default_logger_stack_type), SAVE, DIMENSION(max_stack_pointer) :: default_logger_stack
164 :
165 : CONTAINS
166 :
167 : ! **************************************************************************************************
168 : !> \brief ...
169 : !> \return ...
170 : !> \author fawzi
171 : ! **************************************************************************************************
172 26992 : FUNCTION cp_default_logger_stack_size() RESULT(res)
173 : INTEGER :: res
174 :
175 26992 : res = stack_pointer
176 26992 : END FUNCTION cp_default_logger_stack_size
177 :
178 : ! **************************************************************************************************
179 : !> \brief adds a default logger.
180 : !> MUST be called before logging occours
181 : !> \param logger ...
182 : !> \author Fawzi Mohamed
183 : !> \note
184 : !> increments a stack of default loggers the latest one will be
185 : !> available within the program
186 : ! **************************************************************************************************
187 111713 : SUBROUTINE cp_add_default_logger(logger)
188 : TYPE(cp_logger_type), INTENT(INOUT), TARGET :: logger
189 :
190 : CHARACTER(len=*), PARAMETER :: routineN = 'cp_add_default_logger', &
191 : routineP = moduleN//':'//routineN
192 :
193 111713 : IF (stack_pointer + 1 > max_stack_pointer) THEN
194 : CALL cp_abort(__LOCATION__, routineP// &
195 0 : "too many default loggers, increase max_stack_pointer in "//moduleN)
196 : END IF
197 :
198 111713 : stack_pointer = stack_pointer + 1
199 111713 : NULLIFY (default_logger_stack(stack_pointer)%cp_default_logger)
200 :
201 111713 : default_logger_stack(stack_pointer)%cp_default_logger => logger
202 111713 : CALL cp_logger_retain(logger)
203 :
204 111713 : END SUBROUTINE cp_add_default_logger
205 :
206 : ! **************************************************************************************************
207 : !> \brief the cousin of cp_add_default_logger, decrements the stack, so that
208 : !> the default logger is what it has
209 : !> been
210 : !> \author Joost VandeVondele
211 : ! **************************************************************************************************
212 111713 : SUBROUTINE cp_rm_default_logger()
213 111713 : IF (stack_pointer - 1 < 0) THEN
214 : CALL cp_abort(__LOCATION__, moduleN//":cp_rm_default_logger "// &
215 0 : "can not destroy default logger "//moduleN)
216 : END IF
217 :
218 111713 : CALL cp_logger_release(default_logger_stack(stack_pointer)%cp_default_logger)
219 111713 : NULLIFY (default_logger_stack(stack_pointer)%cp_default_logger)
220 111713 : stack_pointer = stack_pointer - 1
221 :
222 111713 : END SUBROUTINE cp_rm_default_logger
223 :
224 : ! **************************************************************************************************
225 : !> \brief returns the default logger
226 : !> \return ...
227 : !> \par History
228 : !> 4.2002 created [fawzi]
229 : !> \author Fawzi Mohamed
230 : !> \note
231 : !> initializes the default loggers if necessary
232 : ! **************************************************************************************************
233 11855076 : FUNCTION cp_get_default_logger() RESULT(res)
234 : TYPE(cp_logger_type), POINTER :: res
235 :
236 11855076 : IF (.NOT. stack_pointer > 0) THEN
237 : CALL cp_abort(__LOCATION__, "cp_log_handling:cp_get_default_logger "// &
238 0 : "default logger not yet initialized (CALL cp_init_default_logger)")
239 : END IF
240 11855076 : res => default_logger_stack(stack_pointer)%cp_default_logger
241 11855076 : IF (.NOT. ASSOCIATED(res)) THEN
242 : CALL cp_abort(__LOCATION__, "cp_log_handling:cp_get_default_logger "// &
243 0 : "default logger is null (released too much ?)")
244 : END IF
245 11855076 : END FUNCTION cp_get_default_logger
246 :
247 : ! ================== log ==================
248 :
249 : ! **************************************************************************************************
250 : !> \brief initializes a logger
251 : !> \param logger the logger to initialize
252 : !> \param para_env the parallel environment (this is most likely the global
253 : !> parallel environment
254 : !> \param print_level the level starting with which something is written
255 : !> (defaults to cp_note_level)
256 : !> \param default_global_unit_nr the default unit_nr for output
257 : !> (if not given, and no file is given defaults to the standard output)
258 : !> \param default_local_unit_nr the default unit number for local (i.e. task)
259 : !> output. If not given defaults to a out.taskid file created upon
260 : !> \param global_filename a new file to open (can be given instread of the
261 : !> global_unit_nr)
262 : !> \param local_filename a new file to open (with suffix and para_env%mepos
263 : !> appended). Can be given instread of the default_local_unit_nr).
264 : !> the file is created only upon the first local logging request
265 : !> \param close_global_unit_on_dealloc if the unit should be closed when the
266 : !> logger is deallocated (defaults to true if a local_filename is given,
267 : !> to false otherwise)
268 : !> \param iter_info ...
269 : !> \param close_local_unit_on_dealloc if the unit should be closed when the
270 : !> logger is deallocated (defaults to true)
271 : !> \param suffix the suffix that should be added to all the generated filenames
272 : !> \param template_logger a logger from where to take the unspecified things
273 : !> \par History
274 : !> 4.2002 created [fawzi]
275 : !> \author Fawzi Mohamed
276 : !> \note
277 : !> the handling of *_filename, default_*_unit_nr, close_*_unit_on_dealloc
278 : !> tries to take the right decision with different inputs, and thus is a
279 : !> little complex.
280 : ! **************************************************************************************************
281 19679 : SUBROUTINE cp_logger_create(logger, para_env, print_level, &
282 : default_global_unit_nr, default_local_unit_nr, global_filename, &
283 : local_filename, close_global_unit_on_dealloc, iter_info, &
284 : close_local_unit_on_dealloc, suffix, template_logger)
285 : TYPE(cp_logger_type), POINTER :: logger
286 : TYPE(mp_para_env_type), OPTIONAL, POINTER :: para_env
287 : INTEGER, INTENT(in), OPTIONAL :: print_level, default_global_unit_nr, &
288 : default_local_unit_nr
289 : CHARACTER(len=*), INTENT(in), OPTIONAL :: global_filename, local_filename
290 : LOGICAL, INTENT(in), OPTIONAL :: close_global_unit_on_dealloc
291 : TYPE(cp_iteration_info_type), OPTIONAL, POINTER :: iter_info
292 : LOGICAL, INTENT(in), OPTIONAL :: close_local_unit_on_dealloc
293 : CHARACTER(len=*), INTENT(in), OPTIONAL :: suffix
294 : TYPE(cp_logger_type), OPTIONAL, POINTER :: template_logger
295 :
296 : CHARACTER(len=*), PARAMETER :: routineN = 'cp_logger_create', &
297 : routineP = moduleN//':'//routineN
298 :
299 0 : ALLOCATE (logger)
300 :
301 : NULLIFY (logger%para_env)
302 : NULLIFY (logger%iter_info)
303 19679 : logger%ref_count = 1
304 :
305 19679 : IF (PRESENT(template_logger)) THEN
306 124 : IF (template_logger%ref_count < 1) &
307 0 : CPABORT(routineP//" template_logger%ref_count<1")
308 124 : logger%print_level = template_logger%print_level
309 124 : logger%default_global_unit_nr = template_logger%default_global_unit_nr
310 124 : logger%close_local_unit_on_dealloc = template_logger%close_local_unit_on_dealloc
311 124 : IF (logger%close_local_unit_on_dealloc) THEN
312 59 : logger%default_local_unit_nr = -1
313 : ELSE
314 65 : logger%default_local_unit_nr = template_logger%default_local_unit_nr
315 : END IF
316 124 : logger%close_global_unit_on_dealloc = template_logger%close_global_unit_on_dealloc
317 124 : IF (logger%close_global_unit_on_dealloc) THEN
318 0 : logger%default_global_unit_nr = -1
319 : ELSE
320 124 : logger%default_global_unit_nr = template_logger%default_global_unit_nr
321 : END IF
322 124 : logger%local_filename = template_logger%local_filename
323 124 : logger%global_filename = template_logger%global_filename
324 124 : logger%para_env => template_logger%para_env
325 124 : logger%suffix = template_logger%suffix
326 124 : logger%iter_info => template_logger%iter_info
327 : ELSE
328 : ! create a file if nothing is specified, one can also get the unit from the default logger
329 : ! which should have something reasonable as the argument is required in that case
330 : logger%default_global_unit_nr = -1
331 19555 : logger%close_global_unit_on_dealloc = .TRUE.
332 19555 : logger%local_filename = "localLog"
333 19555 : logger%global_filename = "mainLog"
334 19555 : logger%print_level = cp_note_level
335 : ! generate a file for default local logger
336 : ! except the ionode that should write to the default global logger
337 : logger%default_local_unit_nr = -1
338 19555 : logger%close_local_unit_on_dealloc = .TRUE.
339 19555 : logger%suffix = ""
340 : END IF
341 19679 : IF (PRESENT(para_env)) logger%para_env => para_env
342 19679 : IF (.NOT. ASSOCIATED(logger%para_env)) &
343 0 : CPABORT(routineP//" para env not associated")
344 19679 : IF (.NOT. logger%para_env%is_valid()) &
345 0 : CPABORT(routineP//" para_env%ref_count<1")
346 19679 : CALL logger%para_env%retain()
347 :
348 19679 : IF (PRESENT(print_level)) logger%print_level = print_level
349 :
350 19679 : IF (PRESENT(default_global_unit_nr)) &
351 19561 : logger%default_global_unit_nr = default_global_unit_nr
352 19679 : IF (PRESENT(global_filename)) THEN
353 0 : logger%global_filename = global_filename
354 0 : logger%close_global_unit_on_dealloc = .TRUE.
355 0 : logger%default_global_unit_nr = -1
356 : END IF
357 19679 : IF (PRESENT(close_global_unit_on_dealloc)) THEN
358 19561 : logger%close_global_unit_on_dealloc = close_global_unit_on_dealloc
359 19561 : IF (PRESENT(default_global_unit_nr) .AND. PRESENT(global_filename) .AND. &
360 : (.NOT. close_global_unit_on_dealloc)) THEN
361 0 : logger%default_global_unit_nr = default_global_unit_nr
362 : END IF
363 : END IF
364 :
365 19679 : IF (PRESENT(default_local_unit_nr)) &
366 0 : logger%default_local_unit_nr = default_local_unit_nr
367 19679 : IF (PRESENT(local_filename)) THEN
368 0 : logger%local_filename = local_filename
369 0 : logger%close_local_unit_on_dealloc = .TRUE.
370 0 : logger%default_local_unit_nr = -1
371 : END IF
372 19679 : IF (PRESENT(suffix)) logger%suffix = suffix
373 :
374 19679 : IF (PRESENT(close_local_unit_on_dealloc)) THEN
375 0 : logger%close_local_unit_on_dealloc = close_local_unit_on_dealloc
376 0 : IF (PRESENT(default_local_unit_nr) .AND. PRESENT(local_filename) .AND. &
377 : (.NOT. close_local_unit_on_dealloc)) THEN
378 0 : logger%default_local_unit_nr = default_local_unit_nr
379 : END IF
380 : END IF
381 :
382 19679 : IF (logger%default_local_unit_nr == -1) THEN
383 19614 : IF (logger%para_env%is_source()) THEN
384 10250 : logger%default_local_unit_nr = logger%default_global_unit_nr
385 10250 : logger%close_local_unit_on_dealloc = .FALSE.
386 : END IF
387 : END IF
388 19679 : IF (PRESENT(iter_info)) logger%iter_info => iter_info
389 19679 : IF (ASSOCIATED(logger%iter_info)) THEN
390 124 : CALL cp_iteration_info_retain(logger%iter_info)
391 : ELSE
392 19555 : CALL cp_iteration_info_create(logger%iter_info, "")
393 : END IF
394 19679 : END SUBROUTINE cp_logger_create
395 :
396 : ! **************************************************************************************************
397 : !> \brief retains the given logger (to be called to keep a shared copy of
398 : !> the logger)
399 : !> \param logger the logger to retain
400 : !> \par History
401 : !> 08.2002 created [fawzi]
402 : !> \author Fawzi Mohamed
403 : ! **************************************************************************************************
404 120320 : SUBROUTINE cp_logger_retain(logger)
405 : TYPE(cp_logger_type), INTENT(INOUT) :: logger
406 :
407 : CHARACTER(len=*), PARAMETER :: routineN = 'cp_logger_retain', &
408 : routineP = moduleN//':'//routineN
409 :
410 120320 : IF (logger%ref_count < 1) &
411 0 : CPABORT(routineP//" logger%ref_count<1")
412 120320 : logger%ref_count = logger%ref_count + 1
413 120320 : END SUBROUTINE cp_logger_retain
414 :
415 : ! **************************************************************************************************
416 : !> \brief releases this logger
417 : !> \param logger the logger to release
418 : !> \par History
419 : !> 4.2002 created [fawzi]
420 : !> \author Fawzi Mohamed
421 : ! **************************************************************************************************
422 139999 : SUBROUTINE cp_logger_release(logger)
423 : TYPE(cp_logger_type), POINTER :: logger
424 :
425 : CHARACTER(len=*), PARAMETER :: routineN = 'cp_logger_release', &
426 : routineP = moduleN//':'//routineN
427 :
428 139999 : IF (ASSOCIATED(logger)) THEN
429 139999 : IF (logger%ref_count < 1) &
430 0 : CPABORT(routineP//" logger%ref_count<1")
431 139999 : logger%ref_count = logger%ref_count - 1
432 139999 : IF (logger%ref_count == 0) THEN
433 19679 : IF (logger%close_global_unit_on_dealloc .AND. &
434 : logger%default_global_unit_nr >= 0) THEN
435 0 : CALL close_file(logger%default_global_unit_nr)
436 0 : logger%close_global_unit_on_dealloc = .FALSE.
437 0 : logger%default_global_unit_nr = -1
438 : END IF
439 19679 : IF (logger%close_local_unit_on_dealloc .AND. &
440 : logger%default_local_unit_nr >= 0) THEN
441 246 : CALL close_file(logger%default_local_unit_nr)
442 246 : logger%close_local_unit_on_dealloc = .FALSE.
443 246 : logger%default_local_unit_nr = -1
444 : END IF
445 19679 : CALL mp_para_env_release(logger%para_env)
446 19679 : CALL cp_iteration_info_release(logger%iter_info)
447 19679 : DEALLOCATE (logger)
448 : END IF
449 : END IF
450 139999 : NULLIFY (logger)
451 139999 : END SUBROUTINE cp_logger_release
452 :
453 : ! **************************************************************************************************
454 : !> \brief this function can be called to check if the logger would log
455 : !> a message with the given level from the given source
456 : !> you should use this function if you do direct logging
457 : !> (without using cp_logger_log), or if you want to know if the generation
458 : !> of some costly log info is necessary
459 : !> \param logger the logger you want to log in
460 : !> \param level describes the of the message: cp_fatal_level(3),
461 : !> cp_failure_level(2), cp_warning_level(1), cp_note_level(0).
462 : !> \return ...
463 : !> \par History
464 : !> 4.2002 revised [fawzi]
465 : !> \author Fawzi Mohamed
466 : ! **************************************************************************************************
467 4352 : FUNCTION cp_logger_would_log(logger, level) RESULT(res)
468 : TYPE(cp_logger_type), POINTER :: logger
469 : INTEGER, INTENT(in) :: level
470 : LOGICAL :: res
471 :
472 : CHARACTER(len=*), PARAMETER :: routineN = 'cp_logger_would_log', &
473 : routineP = moduleN//':'//routineN
474 :
475 : TYPE(cp_logger_type), POINTER :: lggr
476 :
477 4352 : lggr => logger
478 4352 : IF (.NOT. ASSOCIATED(lggr)) lggr => cp_get_default_logger()
479 4352 : IF (lggr%ref_count < 1) &
480 0 : CPABORT(routineP//" logger%ref_count<1")
481 :
482 4352 : res = level >= lggr%print_level
483 4352 : END FUNCTION cp_logger_would_log
484 :
485 : ! **************************************************************************************************
486 : !> \brief returns the unit nr for the requested kind of log.
487 : !> \param logger the logger you want to log in
488 : !> \param local if true returns a local logger (one per task), otherwise
489 : !> returns a global logger (only the process with para_env%mepos==
490 : !> para_env%source should write to the global logger). Defaults to
491 : !> false
492 : !> \return ...
493 : !> \par History
494 : !> 4.2002 revised [fawzi]
495 : !> \author Fawzi Mohamed
496 : ! **************************************************************************************************
497 212 : FUNCTION cp_logger_get_unit_nr(logger, local) RESULT(res)
498 : TYPE(cp_logger_type), POINTER :: logger
499 : LOGICAL, INTENT(in), OPTIONAL :: local
500 : INTEGER :: res
501 :
502 212 : res = cp_logger_get_default_unit_nr(logger, local=local)
503 212 : END FUNCTION cp_logger_get_unit_nr
504 :
505 : ! **************************************************************************************************
506 : !> \brief returns the unit nr for the ionode (-1 on all other processors)
507 : !> skips as well checks if the procs calling this function is not the ionode
508 : !> \param logger the logger you want to log in
509 : !> \return ...
510 : !> \par History
511 : !> 12.2009 created [tlaino]
512 : !> \author Teodoro Laino
513 : ! **************************************************************************************************
514 7532842 : FUNCTION cp_logger_get_default_io_unit(logger) RESULT(res)
515 : TYPE(cp_logger_type), OPTIONAL, POINTER :: logger
516 : INTEGER :: res
517 :
518 : TYPE(cp_logger_type), POINTER :: local_logger
519 :
520 7532842 : IF (PRESENT(logger)) THEN
521 482589 : local_logger => logger
522 7050253 : ELSE IF (stack_pointer == 0) THEN
523 7532842 : res = -1 ! edge case: default logger not yet/anymore available
524 : RETURN
525 : ELSE
526 7050253 : local_logger => cp_get_default_logger()
527 : END IF
528 :
529 7532842 : res = cp_logger_get_default_unit_nr(local_logger, local=.FALSE., skip_not_ionode=.TRUE.)
530 7532842 : END FUNCTION cp_logger_get_default_io_unit
531 :
532 : ! *************************** cp_logger_type settings ***************************
533 :
534 : ! **************************************************************************************************
535 : !> \brief changes the logging level. Log messages with a level less than the one
536 : !> given wo not be printed.
537 : !> \param logger the logger to change
538 : !> \param level the new logging level for the logger
539 : !> \par History
540 : !> 4.2002 revised [fawzi]
541 : !> \author Fawzi Mohamed
542 : ! **************************************************************************************************
543 0 : SUBROUTINE cp_logger_set_log_level(logger, level)
544 : TYPE(cp_logger_type), INTENT(INOUT) :: logger
545 : INTEGER, INTENT(in) :: level
546 :
547 : CHARACTER(len=*), PARAMETER :: routineN = 'cp_logger_set_log_level', &
548 : routineP = moduleN//':'//routineN
549 :
550 0 : IF (logger%ref_count < 1) &
551 0 : CPABORT(routineP//" logger%ref_count<1")
552 0 : logger%print_level = level
553 0 : END SUBROUTINE cp_logger_set_log_level
554 :
555 : ! **************************************************************************************************
556 : !> \brief asks the default unit number of the given logger.
557 : !> try to use cp_logger_get_unit_nr
558 : !> \param logger the logger you want info from
559 : !> \param local if you want the local unit nr (defaults to false)
560 : !> \param skip_not_ionode ...
561 : !> \return ...
562 : !> \par History
563 : !> 4.2002 revised [fawzi]
564 : !> \author Fawzi Mohamed
565 : ! **************************************************************************************************
566 7927475 : RECURSIVE FUNCTION cp_logger_get_default_unit_nr(logger, local, skip_not_ionode) RESULT(res)
567 : TYPE(cp_logger_type), OPTIONAL, POINTER :: logger
568 : LOGICAL, INTENT(in), OPTIONAL :: local, skip_not_ionode
569 : INTEGER :: res
570 :
571 : CHARACTER(len=*), PARAMETER :: routineN = 'cp_logger_get_default_unit_nr', &
572 : routineP = moduleN//':'//routineN
573 :
574 : CHARACTER(len=default_path_length) :: filename, host_name
575 : INTEGER :: iostat, pid
576 : LOGICAL :: loc, skip
577 : TYPE(cp_logger_type), POINTER :: lggr
578 :
579 7927475 : loc = .TRUE.
580 7927475 : skip = .FALSE.
581 7927475 : IF (PRESENT(logger)) THEN
582 7924592 : lggr => logger
583 : ELSE
584 2883 : NULLIFY (lggr)
585 : END IF
586 7927475 : IF (.NOT. ASSOCIATED(lggr)) lggr => cp_get_default_logger()
587 7927475 : IF (lggr%ref_count < 1) &
588 0 : CPABORT(routineP//" logger%ref_count<1")
589 :
590 7927475 : IF (PRESENT(local)) loc = local
591 7927475 : IF (PRESENT(skip_not_ionode)) skip = skip_not_ionode
592 7927475 : IF (.NOT. loc) THEN
593 7885844 : IF (lggr%default_global_unit_nr <= 0) THEN
594 3037570 : IF (lggr%para_env%is_source()) THEN
595 : CALL cp_logger_generate_filename(lggr, filename, lggr%global_filename, &
596 0 : ".out", local=.FALSE.)
597 : CALL open_file(TRIM(filename), file_status="unknown", &
598 : file_action="WRITE", file_position="APPEND", &
599 0 : unit_number=lggr%default_global_unit_nr)
600 3037570 : ELSE IF (.NOT. skip) THEN
601 0 : lggr%default_global_unit_nr = cp_logger_get_default_unit_nr(lggr, .TRUE.)
602 0 : lggr%close_global_unit_on_dealloc = .FALSE.
603 : ELSE
604 3037570 : lggr%default_global_unit_nr = -1
605 3037570 : lggr%close_global_unit_on_dealloc = .FALSE.
606 : END IF
607 : END IF
608 7885844 : IF (.NOT. (lggr%para_env%is_source() .OR. skip)) THEN
609 : WRITE (UNIT=lggr%default_global_unit_nr, FMT='(/,T2,A)', IOSTAT=iostat) &
610 0 : ' *** WARNING non ionode asked for global logger ***'
611 0 : IF (iostat /= 0) THEN
612 0 : CALL m_getpid(pid)
613 0 : CALL m_hostnm(host_name)
614 0 : PRINT *, " *** Error trying to WRITE to the local logger ***"
615 0 : PRINT *, " *** MPI_id = ", lggr%para_env%mepos
616 0 : PRINT *, " *** MPI_Communicator = ", lggr%para_env%get_handle()
617 0 : PRINT *, " *** PID = ", pid
618 0 : PRINT *, " *** Hostname = "//TRIM(host_name)
619 0 : CALL print_stack(default_output_unit)
620 : ELSE
621 0 : CALL print_stack(lggr%default_global_unit_nr)
622 : END IF
623 : END IF
624 7885844 : res = lggr%default_global_unit_nr
625 : ELSE
626 41631 : IF (lggr%default_local_unit_nr <= 0) THEN
627 : CALL cp_logger_generate_filename(lggr, filename, lggr%local_filename, &
628 246 : ".out", local=.TRUE.)
629 : CALL open_file(TRIM(filename), file_status="unknown", &
630 : file_action="WRITE", &
631 : file_position="APPEND", &
632 246 : unit_number=lggr%default_local_unit_nr)
633 : WRITE (UNIT=lggr%default_local_unit_nr, FMT='(/,T2,A,I0,A,I0,A)', IOSTAT=iostat) &
634 246 : '*** Local logger file of MPI task ', lggr%para_env%mepos, &
635 492 : ' in communicator ', lggr%para_env%get_handle(), ' ***'
636 246 : IF (iostat == 0) THEN
637 246 : CALL m_getpid(pid)
638 246 : CALL m_hostnm(host_name)
639 : WRITE (UNIT=lggr%default_local_unit_nr, FMT='(T2,A,I0)', IOSTAT=iostat) &
640 246 : '*** PID = ', pid, &
641 492 : '*** Hostname = '//host_name
642 246 : CALL print_stack(lggr%default_local_unit_nr)
643 : END IF
644 246 : IF (iostat /= 0) THEN
645 0 : CALL m_getpid(pid)
646 0 : CALL m_hostnm(host_name)
647 0 : PRINT *, " *** Error trying to WRITE to the local logger ***"
648 0 : PRINT *, " *** MPI_id = ", lggr%para_env%mepos
649 0 : PRINT *, " *** MPI_Communicator = ", lggr%para_env%get_handle()
650 0 : PRINT *, " *** PID = ", pid
651 0 : PRINT *, " *** Hostname = "//TRIM(host_name)
652 0 : CALL print_stack(default_output_unit)
653 : END IF
654 :
655 : END IF
656 41631 : res = lggr%default_local_unit_nr
657 : END IF
658 7927475 : END FUNCTION cp_logger_get_default_unit_nr
659 :
660 : ! **************************************************************************************************
661 : !> \brief generates a unique filename (ie adding eventual suffixes and
662 : !> process ids)
663 : !> \param logger ...
664 : !> \param res the resulting string
665 : !> \param root the start of filename
666 : !> \param postfix the end of the name
667 : !> \param local if the name should be local to this task (defaults to false)
668 : !> \par History
669 : !> 08.2002 created [fawzi]
670 : !> \author Fawzi Mohamed
671 : !> \note
672 : !> this should be a function returning a variable length string.
673 : !> All spaces are moved to the end of the string.
674 : !> Not fully optimized: result must be a little longer than the
675 : !> resulting compressed filename
676 : ! **************************************************************************************************
677 96457 : SUBROUTINE cp_logger_generate_filename(logger, res, root, postfix, &
678 : local)
679 : TYPE(cp_logger_type), POINTER :: logger
680 : CHARACTER(len=*), INTENT(inout) :: res
681 : CHARACTER(len=*), INTENT(in) :: root, postfix
682 : LOGICAL, INTENT(in), OPTIONAL :: local
683 :
684 : CHARACTER(len=*), PARAMETER :: routineN = 'cp_logger_generate_filename', &
685 : routineP = moduleN//':'//routineN
686 :
687 : LOGICAL :: loc
688 : TYPE(cp_logger_type), POINTER :: lggr
689 :
690 96457 : loc = .FALSE.
691 96457 : res = ' '
692 96457 : lggr => logger
693 :
694 96457 : IF (.NOT. ASSOCIATED(lggr)) lggr => cp_get_default_logger()
695 96457 : IF (lggr%ref_count < 1) &
696 0 : CPABORT(routineP//" logger%ref_count<1")
697 96457 : IF (PRESENT(local)) loc = local
698 96457 : IF (loc) THEN
699 : res = TRIM(root)//TRIM(lggr%suffix)//'_p'// &
700 441 : cp_to_string(lggr%para_env%mepos)//postfix
701 : ELSE
702 96016 : res = TRIM(root)//TRIM(lggr%suffix)//postfix
703 : END IF
704 96457 : CALL compress(res, full=.TRUE.)
705 96457 : END SUBROUTINE cp_logger_generate_filename
706 :
707 : ! **************************************************************************************************
708 : !> \brief sets various attributes of the given logger
709 : !> \param logger the logger you want to change
710 : !> \param local_filename the root of the name of the file used for local
711 : !> logging
712 : !> \param global_filename the root of the name of the file used for
713 : !> global logging
714 : !> \author Fawzi Mohamed
715 : ! **************************************************************************************************
716 11105 : SUBROUTINE cp_logger_set(logger, local_filename, global_filename)
717 : TYPE(cp_logger_type), INTENT(INOUT) :: logger
718 : CHARACTER(len=*), INTENT(in), OPTIONAL :: local_filename, global_filename
719 :
720 11105 : IF (PRESENT(local_filename)) logger%local_filename = local_filename
721 11105 : IF (PRESENT(global_filename)) logger%global_filename = global_filename
722 11105 : END SUBROUTINE cp_logger_set
723 :
724 : ! **************************************************************************************************
725 : !> \brief converts an int to a string
726 : !> (should be a variable length string, but that does not work with
727 : !> all the compilers)
728 : !> \param i the integer to convert
729 : !> \param fmt Optional format string
730 : !> \return ...
731 : !> \par History
732 : !> 4.2002 revised [fawzi]
733 : !> \author Fawzi Mohamed, MK
734 : ! **************************************************************************************************
735 7652293 : FUNCTION cp_int_to_string(i, fmt) RESULT(res)
736 : INTEGER, INTENT(in) :: i
737 : CHARACTER(len=*), OPTIONAL :: fmt
738 : CHARACTER(len=25) :: res
739 :
740 : CHARACTER(len=25) :: t_res
741 : INTEGER :: iostat
742 : REAL(KIND=dp) :: tmp_r
743 :
744 7652293 : iostat = 0
745 7652293 : IF (PRESENT(fmt)) THEN
746 1824 : WRITE (t_res, FMT=fmt, IOSTAT=iostat) i
747 7650469 : ELSE IF (i > 999999 .OR. i < -99999) THEN
748 1 : tmp_r = i
749 1 : WRITE (t_res, FMT='(ES8.1)', IOSTAT=iostat) tmp_r
750 : ELSE
751 7650468 : WRITE (t_res, FMT='(I6)', IOSTAT=iostat) i
752 : END IF
753 7652293 : res = t_res
754 7652293 : IF (iostat /= 0) THEN
755 0 : PRINT *, "cp_int_to_string I/O error", iostat
756 0 : CALL print_stack(cp_logger_get_default_unit_nr())
757 : END IF
758 :
759 7652293 : END FUNCTION cp_int_to_string
760 :
761 : ! **************************************************************************************************
762 : !> \brief Convert a double precision real in a string
763 : !> (should be a variable length string, but that does not work with
764 : !> all the compilers)
765 : !> \param val the number to convert
766 : !> \param fmt Optional format string
767 : !> \return ...
768 : !> \par History
769 : !> 4.2002 revised [fawzi]
770 : !> \author Fawzi Mohamed, MK
771 : ! **************************************************************************************************
772 103407 : FUNCTION cp_real_dp_to_string(val, fmt) RESULT(res)
773 : REAL(KIND=dp), INTENT(in) :: val
774 : CHARACTER(len=*), OPTIONAL :: fmt
775 : CHARACTER(len=25) :: res
776 :
777 : INTEGER :: iostat
778 :
779 103407 : IF (PRESENT(fmt)) THEN
780 1824 : WRITE (res, FMT=fmt, IOSTAT=iostat) val
781 : ELSE
782 101583 : WRITE (res, FMT='(ES11.4)', IOSTAT=iostat) val
783 : END IF
784 103407 : IF (iostat /= 0) THEN
785 0 : PRINT *, "cp_real_dp_to_string I/O error", iostat
786 0 : CALL print_stack(cp_logger_get_default_unit_nr())
787 : END IF
788 :
789 103407 : END FUNCTION cp_real_dp_to_string
790 :
791 : ! **************************************************************************************************
792 : !> \brief convert a logical in a string ('T' or 'F')
793 : !> \param val the number to convert
794 : !> \return ...
795 : !> \author fawzi
796 : ! **************************************************************************************************
797 0 : ELEMENTAL FUNCTION cp_logical_to_string(val) RESULT(res)
798 : LOGICAL, INTENT(in) :: val
799 : CHARACTER(len=1) :: res
800 :
801 0 : IF (val) THEN
802 0 : res = 'T'
803 : ELSE
804 0 : res = 'F'
805 : END IF
806 0 : END FUNCTION cp_logical_to_string
807 :
808 0 : END MODULE cp_log_handling
809 :
|