Octopus
messages.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2021 M. Marques, A. Castro, A. Rubio, G. Bertsch, X. Andrade,
2!! Copyright (C) 2021 M. Lueders
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
22module messages_oct_m
23 use debug_oct_m
24 use global_oct_m
25 use io_oct_m
26 use iso_fortran_env
27 use loct_oct_m
28 use mpi_oct_m
30 use parser_oct_m
31 use string_oct_m
32 use sihash_oct_m
33 use sphash_oct_m
34 use unit_oct_m
36
37 implicit none
38
39 private
40
41 public :: &
48 print_date, &
49 time_sum, &
65
66
67 integer, parameter :: max_lines = 20
68 character(len=256), dimension(max_lines), public :: message
69 character(len=68), parameter, public :: hyphens = &
70 '--------------------------------------------------------------------'
71 character(len=69), parameter, public :: shyphens = '*'//hyphens
72
73 character(len=512), private :: msg
74 integer, parameter, private :: SLEEPYTIME_ALL = 1, sleepytime_nonwriters = 60
75 character(len=64), private :: oct_status = 'undefined'
76
77 type(sihash_t), private :: namespace_unit
78 type(sphash_t), private :: namespace_mpi_grp
79 character(len=256), private :: msg_dir = 'exec'
80
81 ! ---------------------------------------------------------
87 ! ---------------------------------------------------------
89 module procedure messages_print_var_valuei
90 module procedure messages_print_var_values
91 module procedure messages_print_var_valuer
92 module procedure messages_print_var_valuel
93 module procedure messages_print_var_valuear
94 end interface messages_print_var_value
95
96 interface messages_write
97 module procedure messages_write_float
98 module procedure messages_write_integer
99 module procedure messages_write_integer8
100 module procedure messages_write_str
101 module procedure messages_write_logical
102 end interface messages_write
103
104
106 module procedure messages_print_var_option_4
107 module procedure messages_print_var_option_8
108 end interface messages_print_var_option
109
110 integer :: warnings
111 integer :: experimentals
112 integer :: current_line
113
115 interface
116 subroutine get_signal_description(signum, signame)
117 implicit none
118 integer, intent(in) :: signum
119 character(len=*), intent(out) :: signame
120 end subroutine get_signal_description
121
122 subroutine trap_segfault()
123 implicit none
124 end subroutine trap_segfault
125 end interface
126
127
128contains
129
130 ! ---------------------------------------------------------
131 subroutine messages_init(output_dir)
132 character(len=*), intent(in), optional :: output_dir
133
134 logical :: trap_signals
135
136 if (present(output_dir)) then
137 msg_dir = trim(output_dir)
138 endif
139
140 call sihash_init(namespace_unit)
141 call sphash_init(namespace_mpi_grp)
142
143 call messages_obsolete_variable(global_namespace, 'DevelVersion', 'ExperimentalFeatures')
144
145 !%Variable ExperimentalFeatures
146 !%Type logical
147 !%Default no
148 !%Section Execution::Debug
149 !%Description
150 !% If true, allows the use of certain parts of the code that are
151 !% still under development and are not suitable for production
152 !% runs. This should not be used unless you know what you are doing.
153 !% See details on
154 !% <a href=https://www.octopus-code.org/documentation/main/variables/execution/debug/experimentalfeatures>wiki page</a>.
155 !%End
156 call parse_variable(global_namespace, 'ExperimentalFeatures', .false., conf%devel_version)
157
158 call messages_obsolete_variable(global_namespace, 'DebugLevel', 'Debug')
159
162 warnings = 0
163 experimentals = 0
165 !%Variable DebugTrapSignals
166 !%Type logical
167 !%Default yes
168 !%Section Execution::Debug
169 !%Description
170 !% If true, trap signals to handle them in octopus itself and
171 !% print a custom backtrace. If false, do not trap signals; then,
172 !% core dumps can be produced or gdb can be used to stop at the
173 !% point a signal was produced (e.g. a segmentation fault).
174 !%End
175 call parse_variable(global_namespace, 'DebugTrapSignals', .true., trap_signals)
176
177 if (trap_signals) call trap_segfault()
178
180
181 end subroutine messages_init
182
183 ! ---------------------------------------------------------
184 subroutine messages_end()
185
186 type(sihash_iterator_t) :: it
187 integer :: iu
188
190
191 if (experimentals > 0 .or. warnings > 0) then
192 message(1) = ''
193 call messages_info(1)
194 end if
195
196
197 if (warnings > 0) then
198 call messages_write('Octopus emitted ')
199 call messages_write(warnings)
200 if (warnings > 1) then
201 call messages_write(' warnings.')
202 else
203 call messages_write(' warning.')
204 end if
206 end if
207
208 if (experimentals > 0) then
210 call messages_write('Octopus used ')
211 call messages_write(experimentals)
212 if (experimentals > 1) then
213 call messages_write(' experimental features:')
214 else
215 call messages_write(' experimental feature:')
216 end if
217 call messages_new_line()
218 call messages_new_line()
219 call messages_write(' Since you used one or more experimental features, results are likely')
220 call messages_new_line()
221 call messages_write(' wrong and should not be considered as valid scientific data. Check')
222 call messages_new_line()
223 call messages_new_line()
224 call messages_write(' https://www.octopus-code.org/documentation/main/variables/execution/debug/experimentalfeatures')
225 call messages_new_line()
226 call messages_new_line()
227 call messages_write(' or contact the octopus developers for details.')
228 call messages_new_line()
229 call messages_info()
230 end if
231
232 open(unit = iunit_out, file = trim(msg_dir) // '/messages', action = 'write')
233 write(iunit_out, '(a, i9)') "warnings = ", warnings
234 write(iunit_out, '(a, i9)') "experimental = ", experimentals
235 close(iunit_out)
236
237 end if
238
239 call it%start(namespace_unit)
240 do while(it%has_next())
241 iu = it%get_next()
242 if (iu /= stderr .and. iu /= stdout) call io_close(iu)
243 end do
244
245 call sphash_end(namespace_mpi_grp)
246 call sihash_end(namespace_unit)
247
248 end subroutine messages_end
249
250 ! ---------------------------------------------------------
251 integer function messages_get_unit(namespace) result(iunit)
252 type(namespace_t), optional, intent(in) :: namespace
253
254 logical :: found
255
256 if (present(namespace)) then
257
258 if (namespace%get()=="") then
259 iunit = stdout
260 return
261 end if
262
263 iunit = sihash_lookup( namespace_unit, namespace%get(), found)
264
265 if (.not. found) then
266 call io_mkdir('', namespace)
267 iunit = io_open("log", namespace=namespace, action="write")
268 call sihash_insert(namespace_unit, namespace%get(), iunit)
269 endif
270
271 else
272 iunit = stdout
273 end if
274
275 end function messages_get_unit
276
277 ! ---------------------------------------------------------
278 subroutine messages_update_mpi_grp(namespace, mpigrp)
279 type(namespace_t), intent(in) :: namespace
280 type(mpi_grp_t), target, intent(in) :: mpigrp
281
282 ! messages not initialised
283 assert(namespace_mpi_grp%is_associated())
284 call sphash_insert(namespace_mpi_grp, namespace%get(), mpigrp, clone=.true.)
285
286 end subroutine messages_update_mpi_grp
287
288 ! ---------------------------------------------------------
289 function messages_get_mpi_grp(namespace) result(grp)
290 type(namespace_t), optional, intent(in) :: namespace
291 type(mpi_grp_t) :: grp
292
293 class(*), pointer :: value
294 logical :: found
295
296 if (present(namespace)) then
297 ! messages not initialised
298 assert(namespace_mpi_grp%is_associated())
299
300 value => sphash_lookup(namespace_mpi_grp, trim(namespace%get()), found)
301
302 if (.not.found) then
303 grp = mpi_world
304 return
305 endif
306
307 select type(value)
308 type is (mpi_grp_t)
309 grp = value
310 class default
311 write(message(1),*) "Cannot get mpi_grp for namespace ",namespace%get()
312 call messages_fatal(1)
313 end select
314 else
315 grp = mpi_world
316 end if
317
318 end function messages_get_mpi_grp
319
320 ! ---------------------------------------------------------
321 subroutine messages_fatal(no_lines, only_root_writes, namespace)
322 integer, optional, intent(in) :: no_lines
323 logical, optional, intent(in) :: only_root_writes
324 type(namespace_t), optional, intent(in) :: namespace
325
326 type(mpi_grp_t) :: msg_mpi_grp
327 integer :: ii, no_lines_
328 logical :: only_root_writes_, should_write
329 integer, allocatable :: recv_buf(:)
330 type(mpi_request), allocatable :: recv_req(:)
331#ifdef HAVE_MPI
332 integer, parameter :: fatal_tag = 32767
333 logical :: received
334 type(mpi_request) :: send_req
335#endif
336
337 no_lines_ = current_line
338 if (present(no_lines)) no_lines_ = no_lines
339
340 msg_mpi_grp = messages_get_mpi_grp(namespace)
341
342 if (present(only_root_writes)) then
343 should_write = mpi_grp_is_root(msg_mpi_grp) .or. (.not. only_root_writes)
344 only_root_writes_ = only_root_writes
345 else
346 should_write = .true.
347 only_root_writes_ = .false.
348 end if
349
350 ! This is to avoid all nodes reporting an error. The root node
351 ! post a message reception to all nodes, the rest of the nodes
352 ! send a message. If the message is received, the non-root nodes
353 ! know that the root node will report the error, so they do not do
354 ! anything.
355
356 if (.not. only_root_writes_) then
357 if (msg_mpi_grp%rank == 0) then
358
359 allocate(recv_buf(1:msg_mpi_grp%size - 1))
360 allocate(recv_req(1:msg_mpi_grp%size - 1))
361 do ii = 1, msg_mpi_grp%size - 1
362#ifdef HAVE_MPI
363 call mpi_recv_init(recv_buf(ii), 1, mpi_integer, ii, fatal_tag, msg_mpi_grp%comm, recv_req(ii), mpi_err)
364#endif
365 end do
366 deallocate(recv_buf)
367 deallocate(recv_req)
368
369 else
370
371#ifdef HAVE_MPI
372 call mpi_send_init(1, 1, mpi_integer, 0, fatal_tag, msg_mpi_grp%comm, send_req, mpi_err)
373#endif
374 !sleep for a second and check
375 call loct_nanosleep(sleepytime_all, 0)
376#ifdef HAVE_MPI
377 call mpi_test(send_req, received, mpi_status_ignore, mpi_err)
378#endif
379 should_write = .false.
380
381 end if
382 end if
383
384 ! Give a moment for all standard output hopefully to be printed
385 call loct_nanosleep(sleepytime_all, 0)
386
387 ! If we are not writing wait for the root node to get here and
388 ! write the error message. If the root doesn`t get here, we all print the
389 ! error messsage anyways and die. Otherwise, no message might be written.
390 if (.not. should_write) call loct_nanosleep(sleepytime_nonwriters, 0)
391
392 call messages_print_with_emphasis(msg="FATAL ERROR", iunit=stderr)
393 write(msg, '(a)') '*** Fatal Error (description follows)'
394 call flush_msg(msg, stderr)
395
396 if (present(namespace)) then
397 if (len_trim(namespace%get()) > 0) then
398 write(msg, '(3a)') '* In namespace ', trim(namespace%get()), ':'
399 call flush_msg(msg, stderr)
400 end if
401 end if
402
403#ifdef HAVE_MPI
404 if (.not. only_root_writes_ .or. .not. mpi_grp_is_root(msg_mpi_grp)) then
405 call flush_msg(shyphens, stderr)
406 write(msg, '(a,i4)') "* From node = ", msg_mpi_grp%rank
407 call flush_msg(msg, stderr)
408 end if
409#endif
410 call flush_msg(shyphens, stderr)
411 do ii = 1, no_lines_
412 write(msg, '(a,1x,a)') '*', trim(message(ii))
413 call flush_msg(msg, stderr)
414 end do
415
416 ! We only dump the stack in debug mode because subroutine invocations
417 ! are only recorded in debug mode (via push_sub/pop_sub). Otherwise,
418 ! it is a bit confusing that the stack seems to be empty.
419 if (debug%trace) then
420 call flush_msg(shyphens, stderr)
421
422 write(msg, '(a)') '* Stack: '
423 call flush_msg(msg, stderr, adv='no')
424 do ii = 1, no_sub_stack
425 write(msg, '(a,a)') ' > ', trim(sub_stack(ii))
426 call flush_msg(msg, stderr, adv='no')
427 end do
428 call flush_msg(" ", stderr)
429 end if
430
431 if (should_write) then
432 call messages_print_with_emphasis(iunit=stderr)
433 end if
434
435 ! switch file indicator to state aborted
436 call messages_switch_status('aborted')
437
438 call mpi_world%abort()
439
440 call loct_exit_failure()
441 end subroutine messages_fatal
442
443 ! ---------------------------------------------------------
444 subroutine messages_warning(no_lines, all_nodes, namespace)
445 integer, optional, intent(in) :: no_lines
446 logical, optional, intent(in) :: all_nodes
447 type(namespace_t), optional, intent(in) :: namespace
448
449 integer :: il, no_lines_
450 integer :: iunit_namespace
451 logical :: have_to_write, all_nodes_
452 type(mpi_grp_t) :: msg_mpi_grp
453
454 no_lines_ = current_line
455 if (present(no_lines)) no_lines_ = no_lines
456
457 warnings = warnings + 1
458
459 iunit_namespace = messages_get_unit(namespace)
460 msg_mpi_grp = messages_get_mpi_grp(namespace)
461
462 have_to_write = mpi_grp_is_root(msg_mpi_grp)
463
464 all_nodes_ = .false.
465 if (present(all_nodes)) then
466 have_to_write = have_to_write .or. all_nodes
467 all_nodes_ = all_nodes
468 end if
469
470 if (have_to_write) then
471
472 call flush_msg('', stderr)
473 if (iunit_namespace /= stdout) then
474 call flush_msg('', iunit_namespace)
475 end if
476 write(msg, '(a)') '** Warning:'
477 call flush_msg(msg, stderr)
478 if (iunit_namespace /= stdout) then
479 call flush_msg(msg, iunit_namespace)
480 end if
481
482 if (present(namespace)) then
483 if (len_trim(namespace%get()) > 0) then
484 write(msg, '(3a)') '** In namespace ', trim(namespace%get()), ':'
485 call flush_msg(msg, stderr)
486 end if
487 end if
488
489#ifdef HAVE_MPI
490 if (all_nodes_) then
491 write(msg , '(a,i4)') '** From node = ', mpi_world%rank
492 call flush_msg(msg, stderr)
493 if (iunit_namespace /= stdout) then
494 call flush_msg(msg, iunit_namespace)
495 end if
496 end if
497#endif
498
499 do il = 1, no_lines_
500 write(msg , '(a,3x,a)') '**', trim(message(il))
501 call flush_msg(msg, stderr)
502 if (iunit_namespace /= stdout) then
503 call flush_msg(msg, iunit_namespace)
504 end if
505 end do
506 call flush_msg('', stderr)
507 if (iunit_namespace /= stdout) then
508 call flush_msg('', iunit_namespace)
509 end if
510
511 flush(stderr)
512 if (iunit_namespace /= stdout) then
513 flush(iunit_namespace)
514 end if
515
516 end if
517
519
520 end subroutine messages_warning
521
522 ! ---------------------------------------------------------
523 subroutine messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
524 integer, optional, intent(in) :: no_lines
525 integer, optional, intent(in) :: iunit
526 logical, optional, intent(in) :: debug_only
527 logical, optional, intent(in) :: stress
528 logical, optional, intent(in) :: all_nodes
529 type(namespace_t), optional, intent(in) :: namespace
530
531 integer :: il, no_lines_
532 integer :: iunit_
533 type(mpi_grp_t) :: msg_mpi_grp
534
535 assert(.not. (present(iunit) .and. present(namespace)))
536
537 if (present(iunit)) then
538 iunit_ = iunit
539 else
540 iunit_ = messages_get_unit(namespace)
541 end if
542 msg_mpi_grp = messages_get_mpi_grp(namespace)
543
544 if (.not. mpi_grp_is_root(msg_mpi_grp) .and. .not. optional_default(all_nodes, .false.)) then
546 return
547 end if
548
549 no_lines_ = current_line
550 if (present(no_lines)) no_lines_ = no_lines
551
552 if (present(stress)) then
553 call messages_print_with_emphasis(iunit=iunit_)
554 end if
555
556 do il = 1, no_lines_
557 if (.not. optional_default(debug_only, .false.) .or. debug%info) then
558 write(msg, '(a)') trim(message(il))
559 call flush_msg(msg, iunit_)
560 end if
561 end do
562 if (present(stress)) then
563 call messages_print_with_emphasis(iunit=iunit_)
564 end if
565
566 flush(iunit_)
567
569
570 end subroutine messages_info
571
572 ! ---------------------------------------------------------
574 subroutine messages_switch_status(status)
575 character(len=*), intent(in) :: status
576
577 ! only root node is taking care of file I/O
578 if (.not. mpi_grp_is_root(mpi_world)) return
579
580 ! remove old status files first, before we switch to a new state
581 call loct_rm(trim(msg_dir) // '/oct-status-running')
582 call loct_rm(trim(msg_dir) // '/oct-status-finished')
583 call loct_rm(trim(msg_dir) // '/oct-status-aborted')
584 if (oct_status /= 'walltimer-aborted') then
585 call loct_rm(trim(msg_dir) // '/oct-status-walltimer-aborted')
586 end if
587
588 oct_status = status
589
590 ! create empty status file to indicate new state
591 open(unit=iunit_err, file=trim(msg_dir) // '/oct-status-'//trim(status), &
592 action='write', status='unknown')
593 close(iunit_err)
594
595 end subroutine messages_switch_status
596
597 ! ---------------------------------------------------------
598 subroutine alloc_error(size, file, line)
599 integer(int64), intent(in) :: size
600 character(len=*), intent(in) :: file
601 integer, intent(in) :: line
602
603 write(message(1), '(a,i18,3a,i5)') "Failed to allocate ", size, " words in file '", trim(file), "' line ", line
604 call messages_fatal(1)
605
606 end subroutine alloc_error
607
608 ! ---------------------------------------------------------
609 subroutine dealloc_error(size, file, line)
610 integer(int64), intent(in) :: size
611 character(len=*), intent(in) :: file
612 integer, intent(in) :: line
613
614 write(message(1), '(a,i18,3a,i5)') "Failed to deallocate array of ", size, " words in file '", trim(file), "' line ", line
615 call messages_fatal(1)
617 end subroutine dealloc_error
618
619 ! ---------------------------------------------------------
620 subroutine messages_input_error(namespace, var, details, row, column)
621 type(namespace_t), intent(in) :: namespace
622 character(len=*), intent(in) :: var
623 character(len=*), optional, intent(in) :: details
624 integer, optional, intent(in) :: row
625 integer, optional, intent(in) :: column
626
627 character(len=10) :: row_str, column_str
628
629 call messages_write('Input error in the input variable '// trim(var))
630
631 if (present(row)) then
632 ! Print row and, if available, the column. We add one to both values
633 ! in order to translate from the C numbering used by the parser to a
634 ! more human-friendly numbering.
635 write(row_str, '(I10)') row + 1
636 call messages_write(' at row '//adjustl(row_str))
637 if (present(column)) then
638 write(column_str, '(I10)') column + 1
639 call messages_write(', column '//adjustl(column_str))
640 end if
641 end if
642 if (present(details)) then
643 call messages_write(':', new_line = .true.)
644 call messages_new_line()
645 call messages_write(' '//trim(details))
646 end if
647 call messages_write('.', new_line = .true.)
648
649 call messages_new_line()
650
651 call messages_write('You can get the documentation of the variable with the command:', new_line = .true.)
652 call messages_write(' oct-help -p '//trim(var))
653 call messages_fatal(namespace=namespace)
654
655 end subroutine messages_input_error
656
657 ! ---------------------------------------------------------
658 subroutine messages_print_var_valuei(var, val, iunit, namespace)
659 character(len=*), intent(in) :: var
660 integer, intent(in) :: val
661 integer, optional, intent(in) :: iunit
662 type(namespace_t), optional, intent(in) :: namespace
663
664 character(len=10) :: intstring
665
666 assert(.not. (present(iunit) .and. present(namespace)))
668 write(intstring,'(i10)') val
669 message(1) = 'Input: ['//trim(var)//' = '//trim(adjustl(intstring))//']'
670 call messages_info(1, iunit=iunit, namespace=namespace)
671
672 end subroutine messages_print_var_valuei
673
674 ! ---------------------------------------------------------
675 subroutine messages_print_var_values(var, val, iunit, namespace)
676 character(len=*), intent(in) :: var
677 character(len=*), intent(in) :: val
678 integer, optional, intent(in) :: iunit
679 type(namespace_t), optional, intent(in) :: namespace
680
681 assert(.not. (present(iunit) .and. present(namespace)))
682
683 message(1) = 'Input: ['//trim(var)//' = '//trim(val)//']'
684 call messages_info(1, iunit=iunit, namespace=namespace)
685
686 end subroutine messages_print_var_values
687
688 ! ---------------------------------------------------------
689 subroutine messages_print_var_valuer(var, val, unit, iunit, namespace)
690 character(len=*), intent(in) :: var
691 real(real64), intent(in) :: val
692 type(unit_t), optional, intent(in) :: unit
693 integer, optional, intent(in) :: iunit
694 type(namespace_t), optional, intent(in) :: namespace
695
696 character(len=11) :: floatstring
697
698 assert(.not. (present(iunit) .and. present(namespace)))
699
700 if (.not. present(unit)) then
701 write(floatstring,'(g11.4)') val
702 message(1) = 'Input: ['//trim(var)//' = '//trim(adjustl(floatstring))//']'
703 else
704 write(floatstring,'(g11.4)') units_from_atomic(unit, val)
705 message(1) = 'Input: ['//trim(var)//' = '//trim(adjustl(floatstring))//' '//trim(units_abbrev(unit))//']'
706 end if
707 call messages_info(1, iunit=iunit, namespace=namespace)
708
709 end subroutine messages_print_var_valuer
710
711 ! ---------------------------------------------------------
712 subroutine messages_print_var_valuel(var, val, iunit, namespace)
713 character(len=*), intent(in) :: var
714 logical, intent(in) :: val
715 integer, optional, intent(in) :: iunit
716 type(namespace_t), optional, intent(in) :: namespace
717
718 character(len=3) :: lstring
719
720 assert(.not. (present(iunit) .and. present(namespace)))
721
722 if (val) then
723 lstring = 'yes'
724 else
725 lstring = 'no'
726 end if
727 message(1) = 'Input: ['//trim(var)//' = '//trim(lstring)//']'
728 call messages_info(1, iunit=iunit, namespace=namespace)
729
730 end subroutine messages_print_var_valuel
731
732 ! ---------------------------------------------------------
733 subroutine messages_print_var_valuear(var, val, unit, iunit, namespace)
734 character(len=*), intent(in) :: var
735 real(real64), intent(in) :: val(:)
736 type(unit_t), optional, intent(in) :: unit
737 integer, optional, intent(in) :: iunit
738 type(namespace_t), optional, intent(in) :: namespace
739
740 integer :: ii
741 character(len=11) :: floatstring
742
743 assert(.not. (present(iunit) .and. present(namespace)))
744
745 call messages_write('Input: ['//trim(var)//' = (')
746 do ii = 1, size(val)
747 write(floatstring,'(g11.4)') val(ii)
748 call messages_write(trim(adjustl(floatstring)))
749 if (ii < size(val)) call messages_write(', ')
750 end do
752 if (present(unit)) then
753 call messages_write(' '//trim(units_abbrev(unit))//']')
754 else
755 call messages_write(']')
756 end if
757 call messages_info(iunit = iunit, namespace=namespace)
758
759 end subroutine messages_print_var_valuear
760
761 ! ---------------------------------------------------------
762 subroutine messages_print_var_info(var, iunit, namespace)
763 character(len=*), intent(in) :: var
764 integer, optional, intent(in) :: iunit
765 type(namespace_t), optional, intent(in) :: namespace
766
767 integer :: iunit_
768 type(mpi_grp_t) :: mpi_grp
769
770 assert(.not. (present(iunit) .and. present(namespace)))
771
772 mpi_grp = messages_get_mpi_grp(namespace)
773
774 if (.not. mpi_grp_is_root(mpi_grp)) return
775
776 if (present(iunit)) then
777 iunit_ = iunit
778 else
779 iunit_ = messages_get_unit(namespace)
780 end if
781 call varinfo_print(iunit_, var)
783 end subroutine messages_print_var_info
784
785 ! ---------------------------------------------------------
786 subroutine messages_print_var_option_8(var, option, pre, iunit, namespace)
787 character(len=*), intent(in) :: var
788 integer(int64), intent(in) :: option
789 character(len=*), optional, intent(in) :: pre
790 integer, optional, intent(in) :: iunit
791 type(namespace_t), optional, intent(in) :: namespace
792
793 integer :: option4, iunit_
794 type(mpi_grp_t) :: mpi_grp
795
796 assert(.not. (present(iunit) .and. present(namespace)))
797
798 mpi_grp = messages_get_mpi_grp(namespace)
799 if (.not. mpi_grp_is_root(mpi_grp)) return
800
801 option4 = int(option, int32)
802
803 if (present(iunit)) then
804 iunit_ = iunit
805 else
806 iunit_ = messages_get_unit(namespace)
807 end if
808 call varinfo_print_option(iunit_, var, option4, pre)
809
810 end subroutine messages_print_var_option_8
811
812 ! ---------------------------------------------------------
813 subroutine messages_print_var_option_4(var, option, pre, iunit, namespace)
814 character(len=*), intent(in) :: var
815 integer(int32), intent(in) :: option
816 character(len=*), optional, intent(in) :: pre
817 integer, optional, intent(in) :: iunit
818 type(namespace_t), optional, intent(in) :: namespace
819
820 assert(.not. (present(iunit) .and. present(namespace)))
821
822 call messages_print_var_option_8(var, int(option, int64), pre, iunit, namespace)
823
824 end subroutine messages_print_var_option_4
825
826 ! ---------------------------------------------------------
827 subroutine messages_print_with_emphasis(msg, iunit, namespace)
828 character(len=*), optional, intent(in) :: msg
829 integer, optional, intent(in) :: iunit
830 type(namespace_t), optional, intent(in) :: namespace
831
832 integer, parameter :: max_len = 70
833
834 integer :: ii, jj, length
835 integer :: iunit_
836 character(len=70) :: str
837 character(len=max_len) :: msg_combined
838 type(mpi_grp_t) :: msg_mpi_grp
839
840 if (present(iunit)) then
841 iunit_ = iunit
842 else
843 iunit_ = messages_get_unit(namespace)
844 end if
845 msg_mpi_grp = messages_get_mpi_grp(namespace)
846
847 if (.not. mpi_grp_is_root(msg_mpi_grp)) return
848
849 if (present(msg)) then
850 ! make sure we do not get a segfault for too long messages
851 if (len_trim(msg) > max_len) then
852 msg_combined = trim(msg(1:max_len))
853 else
854 msg_combined = trim(msg)
855 end if
856 length = len_trim(msg_combined)
857
858 str = ''
859 jj = 1
860
861 do ii = 1, (max_len - (length + 2))/2
862 str(jj:jj) = '*'
863 jj = jj + 1
864 end do
865
866 str(jj:jj) = ' '
867 jj = jj + 1
868
869 do ii = 1, length
870 str(jj:jj) = msg_combined(ii:ii)
871 jj = jj + 1
872 end do
873
874 str(jj:jj) = ' '
875 jj = jj + 1
876
877 do ii = jj, max_len
878 str(jj:jj) = '*'
879 jj = jj + 1
880 end do
881
882 call flush_msg('', iunit_) ! empty line
883 call flush_msg(str, iunit_) ! print out nice line with the header
884 else
885 do ii = 1, max_len
886 str(ii:ii) = '*'
887 end do
888
889 call flush_msg(str, iunit_) ! print out nice line with the header
890 call flush_msg('', iunit_) ! empty line
891 end if
892
893 flush(iunit_)
894 end subroutine messages_print_with_emphasis
895
896 ! ---------------------------------------------------------
897 subroutine flush_msg(str, iunit, adv)
898 character(len = *), intent(in) :: str
899 integer, intent(in) :: iunit
900 character(len = *), optional, intent(in) :: adv
901
902 character(len = 20) :: adv_
903
904 adv_ = 'yes'
905 if (present(adv)) adv_ = trim(adv)
907 write(iunit, '(a)', advance=adv_) trim(str)
908
909 end subroutine flush_msg
910
911 ! ---------------------------------------------------------
912 subroutine print_date(str)
913 character(len = *), intent(in) :: str
914
915 integer :: val(8)
916
917 call date_and_time(values=val)
918 message(1) = ""
919 write(message(3),'(a,i4,a1,i2.2,a1,i2.2,a,i2.2,a1,i2.2,a1,i2.2)') &
920 str , val(1), "/", val(2), "/", val(3), &
921 " at ", val(5), ":", val(6), ":", val(7)
922 message(2) = str_center(trim(message(3)), 70)
923 message(3) = ""
924 call messages_info(3)
925
926 end subroutine print_date
927
928 ! ---------------------------------------------------------
931 subroutine time_sum(sec1, usec1, sec2, usec2)
932 integer, intent(in) :: sec1
933 integer, intent(in) :: usec1
934 integer, intent(inout) :: sec2
935 integer, intent(inout) :: usec2
936
937 push_sub(time_sum)
938
939 sec2 = sec1 + sec2
940 usec2 = usec1 + usec2
941
942 ! Carry?
943 if (usec2 >= 1000000) then
944 sec2 = sec2 + 1
945 usec2 = usec2 - 1000000
946 end if
947
948 pop_sub(time_sum)
949 end subroutine time_sum
950
951 ! ---------------------------------------------------------
952 subroutine messages_obsolete_variable(namespace, name, rep)
953 type(namespace_t), intent(in) :: namespace
954 character(len=*), intent(in) :: name
955 character(len=*), optional, intent(in) :: rep
956
957 if (parse_is_defined(namespace, trim(name))) then
958
959 write(message(1), '(a)') 'Input variable '//trim(name)//' is obsolete.'
960
961 if (present(rep)) then
962 write(message(2), '(a)') ' '
963 write(message(3), '(a)') 'Equivalent functionality can be obtained with the '//trim(rep)
964 write(message(4), '(a)') 'variable. Check the documentation for details.'
965 write(message(5), '(a)') '(You can use the `oct-help -p '//trim(rep)//'` command).'
966 call messages_fatal(5, only_root_writes = .true., namespace=namespace)
967 else
968 call messages_fatal(1, only_root_writes = .true., namespace=namespace)
969 end if
970
971 end if
972
973 end subroutine messages_obsolete_variable
974
975 ! ---------------------------------------------------------
976 subroutine messages_variable_is_block(namespace, name)
977 type(namespace_t), intent(in) :: namespace
978 character(len=*), intent(in) :: name
979
980 if (parse_is_defined(namespace, trim(name))) then
981
982 write(message(1), '(a)') 'Input variable `'//trim(name)//'` must be defined as a block.'
983 write(message(2), '(a)') 'Please check the documentation for details.'
984 write(message(3), '(a)') '(You can use the `oct-help -p '//trim(name)//'` command).'
985 call messages_fatal(3, only_root_writes = .true., namespace=namespace)
986
987 end if
988
989 end subroutine messages_variable_is_block
991 ! ---------------------------------------------------------
992 subroutine messages_experimental(name, namespace)
993 character(len=*), intent(in) :: name
994 type(namespace_t), optional, intent(in) :: namespace
995
996 experimentals = experimentals + 1
997
998 if (.not. conf%devel_version) then
999 call messages_write(trim(name)//' is an experimental feature.')
1000 call messages_new_line()
1001 call messages_new_line()
1002 call messages_write('If you still want to use this feature (at your own risk), check:')
1003 call messages_new_line()
1004 call messages_new_line()
1005 call messages_write('https://www.octopus-code.org/documentation/main/variables/execution/debug/experimentalfeatures')
1006 call messages_new_line()
1007 call messages_fatal(only_root_writes = .true., namespace=namespace)
1008 else
1009 write(message(1), '(a)') trim(name)//' is under development.'
1010 write(message(2), '(a)') 'It might not work or produce wrong results.'
1011 call messages_warning(2, namespace=namespace)
1012
1013 ! remove this warning from the count
1014 warnings = warnings - 1
1015 end if
1016
1017 end subroutine messages_experimental
1018
1019 ! ------------------------------------------------------------
1020 subroutine messages_not_implemented(feature, namespace)
1021 character(len=*), intent(in) :: feature
1022 type(namespace_t), optional, intent(in) :: namespace
1023
1025
1026 message(1) = trim(feature)//" not implemented."
1027 call messages_fatal(1, only_root_writes = .true., namespace=namespace)
1028
1030 end subroutine messages_not_implemented
1031
1032 ! ------------------------------------------------------------
1033 subroutine messages_reset_lines()
1034
1035 current_line = 1
1036 message(1) = ''
1037
1038 end subroutine messages_reset_lines
1039
1040 ! ------------------------------------------------------------
1041 subroutine messages_new_line()
1042
1043 current_line = current_line + 1
1044 if (current_line > max_lines) stop 'Too many message lines.'
1046 message(current_line) = ''
1047
1048 end subroutine messages_new_line
1049
1050 ! ------------------------------------------------------------
1051 subroutine messages_write_float(val, fmt, new_line, units, align_left, print_units)
1052 real(real64), intent(in) :: val
1053 character(len=*), optional, intent(in) :: fmt
1054 logical, optional, intent(in) :: new_line
1055 type(unit_t), optional, intent(in) :: units
1056 logical, optional, intent(in) :: align_left
1057 logical, optional, intent(in) :: print_units
1058
1059 character(len=30) :: number
1060 real(real64) :: tval
1061
1062 tval = val
1063 if (present(units)) tval = units_from_atomic(units, val)
1064
1065 if (present(fmt)) then
1066 write(number, '('//trim(fmt)//')') tval
1067 else
1068 write(number, '(f12.6)') tval
1069 end if
1070
1071 if (optional_default(align_left, .false.)) then
1072 number = adjustl(number)
1073 number(1:len(number)) = ' '//number(1:len(number)-1)
1074 end if
1075
1076 write(message(current_line), '(a, a)') trim(message(current_line)), trim(number)
1077
1078 if (present(units) .and. optional_default(print_units, .true.)) then
1079 write(message(current_line), '(a, a, a)') trim(message(current_line)), ' ', trim(units_abbrev(units))
1080 end if
1081
1082 if (optional_default(new_line, .false.)) call messages_new_line()
1083
1084 end subroutine messages_write_float
1086 ! ------------------------------------------------------------
1087 subroutine messages_write_integer8(val, fmt, new_line, units, print_units)
1088 integer(int64), intent(in) :: val
1089 character(len=*), optional, intent(in) :: fmt
1090 logical, optional, intent(in) :: new_line
1091 type(unit_t), optional, intent(in) :: units
1092 logical, optional, intent(in) :: print_units
1093
1094 character(len=20) :: number
1095 real(real64) :: val_conv_float
1096
1097 if (present(units)) then
1098 val_conv_float = units_from_atomic(units, dble(val))
1099
1100 if (present(fmt)) then
1101 write(message(current_line), '(a, '//trim(fmt)//')') trim(message(current_line)), val_conv_float
1102 else
1103 write(number, '(f15.3)') val_conv_float
1104 write(message(current_line), '(3a)') trim(message(current_line)), ' ', trim(adjustl(number))
1105 end if
1106
1107 else
1108
1109 if (present(fmt)) then
1110 write(message(current_line), '(a, '//trim(fmt)//')') trim(message(current_line)), val
1111 else
1112 write(number, '(i12)') val
1113 write(message(current_line), '(3a)') trim(message(current_line)), ' ', trim(adjustl(number))
1114 end if
1115
1116 end if
1117
1118
1119 if (present(units) .and. optional_default(print_units, .true.)) then
1120 write(message(current_line), '(a, a, a)') trim(message(current_line)), ' ', trim(adjustl(units_abbrev(units)))
1121 end if
1122
1123 if (present(new_line)) then
1124 if (new_line) call messages_new_line()
1125 end if
1127 end subroutine messages_write_integer8
1128
1129 ! ------------------------------------------------------------
1130 subroutine messages_write_integer(val, fmt, new_line, units, print_units)
1131 integer(int32), intent(in) :: val
1132 character(len=*), optional, intent(in) :: fmt
1133 logical, optional, intent(in) :: new_line
1134 type(unit_t), optional, intent(in) :: units
1135 logical, optional, intent(in) :: print_units
1136
1137 call messages_write_integer8(int(val, int64), fmt, new_line, units, print_units)
1138
1139 end subroutine messages_write_integer
1140
1141 ! ------------------------------------------------------------
1142 subroutine messages_write_str(val, fmt, new_line)
1143 character(len=*), intent(in) :: val
1144 character(len=*), optional, intent(in) :: fmt
1145 logical, optional, intent(in) :: new_line
1146
1147 character(len=100) :: fmt_
1148
1149 if (len(trim(message(current_line))) + len(trim(val)) > len(message(current_line))) then
1150 ! cannot use normal message approach without interfering with message we are trying to write
1151 ! write directly in case trim(val) is itself too long
1152 write(error_unit, *) "Exceeded message line length limit, to write string:", trim(val)
1153 else
1154 fmt_ = optional_default(fmt, '(a)')
1155 write(message(current_line), '(a, '//trim(fmt_)//')') trim(message(current_line)), trim(val)
1156 end if
1157
1158 if (present(new_line)) then
1159 if (new_line) call messages_new_line()
1160 end if
1161
1162 end subroutine messages_write_str
1163
1164 ! ------------------------------------------------------------
1165 subroutine messages_write_logical(val, new_line)
1166 logical, intent(in) :: val
1167 logical, optional, intent(in) :: new_line
1168
1169 character(len=3) :: text
1170
1171 if (val) then
1172 text = 'yes'
1173 else
1174 text = 'no'
1175 end if
1176
1177 if (len(trim(message(current_line))) + len(trim(text)) > len(message(current_line))) then
1178 write(message(current_line + 1), '(3a)') "Exceeded message line length limit, to write logical value '", trim(text), "'"
1179 call messages_fatal(current_line + 1)
1180 end if
1181
1182 write(message(current_line), '(a,1x,a)') trim(message(current_line)), trim(text)
1183
1184 if (present(new_line)) then
1185 if (new_line) call messages_new_line()
1186 end if
1187
1188 end subroutine messages_write_logical
1189
1190 ! -----------------------------------------------------------
1191 subroutine messages_dump_stack(isignal)
1192 integer, intent(in) :: isignal
1193
1194 integer :: ii
1195 character(len=300) :: description
1196
1197 call get_signal_description(isignal, description)
1198
1199 write(msg, '(a)') ''
1200 call flush_msg(msg, stderr)
1201 write(msg, '(a)') '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'
1202 call flush_msg(msg, stderr)
1203 write(msg, '(a)') ''
1204 call flush_msg(msg, stderr)
1205 write(msg, '(a,i2,2a)') ' Octopus was killed by signal ', isignal, ': ', trim(description)
1206 call flush_msg(msg, stderr)
1207 write(msg, '(a,i2)') ''
1208 call flush_msg(msg, stderr)
1209 write(msg, '(a)') ' Note: Octopus is currently trapping signals. This might prevent the'
1210 call flush_msg(msg, stderr)
1211 write(msg, '(a)') ' use of debuggers or the generation of core dumps. To change this'
1212 call flush_msg(msg, stderr)
1213 write(msg, '(a)') ' behavior, use the DebugTrapSignals input option.'
1214 call flush_msg(msg, stderr)
1215 write(msg, '(a)') ''
1216 call flush_msg(msg, stderr)
1217 write(msg, '(a)') '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'
1218 call flush_msg(msg, stderr)
1219
1220 if (debug%trace) then
1221 call flush_msg(shyphens, iunit=stderr)
1222
1223 write(msg, '(a)') 'Octopus debug trace: '
1224 call flush_msg(msg, stderr)
1225 do ii = 1, no_sub_stack
1226 write(msg, '(a,a)') ' > ', trim(sub_stack(ii))
1227 call flush_msg(msg, stderr, adv='no')
1228 end do
1229 call flush_msg(" ", stderr)
1230 else
1231 write(msg, '(a)') " Octopus debug trace not available. You can enable it with 'Debug = trace'."
1232 call flush_msg(msg, stderr)
1233 end if
1234
1235 end subroutine messages_dump_stack
1236
1237end module messages_oct_m
1238
1239! ---------------------------------------------------------
1243subroutine assert_die(s, f, l)
1244 use debug_oct_m
1245 use messages_oct_m
1246 use mpi_oct_m
1247
1248 implicit none
1249
1250 character(len=*), intent(in) :: s, f
1251 integer, intent(in) :: l
1252
1253 call messages_write('Node ')
1254 call messages_write(mpi_world%rank)
1255 call messages_write(':')
1256 call messages_new_line()
1257
1258 call messages_write(' Assertion "'//trim(s)//'"')
1259 call messages_new_line()
1260
1261 call messages_write(' failed in line ')
1262 call messages_write(l)
1263 call messages_write(' of file "'//trim(debug_clean_path(f))//'".')
1264 call messages_new_line()
1265
1266 call messages_write('This should not happen and is likely a bug in the code.')
1267 call messages_new_line()
1268 call messages_write('Please contact the developers and report how this occurred.')
1269 call messages_new_line()
1270 call messages_write('You can open an issue on gitlab as described in Contributing.md.')
1271 call messages_new_line()
1272
1273 call messages_fatal()
1274
1275end subroutine assert_die
1276
1277!-------------------------------------------------------
1278subroutine handle_segv(isignal) bind(c)
1279 use messages_oct_m
1280 use iso_c_binding
1281
1282 implicit none
1283
1284 integer(c_int), intent(in) :: isignal
1285
1286 ! Switch status to aborted
1287 call messages_switch_status('aborted')
1288
1289 ! Dump stack
1290 call messages_dump_stack(isignal)
1291
1292end subroutine handle_segv
1293
1294
1295!! Local Variables:
1296!! mode: f90
1297!! coding: utf-8
1298!! End:
Prints out to iunit a message in the form: ["InputVariable" = value] where "InputVariable" is given b...
Definition: messages.F90:181
subroutine handle_segv(isignal)
Definition: messages.F90:1372
subroutine assert_die(s, f, l)
This subroutine is called by the assert macro, it is not in a module so it can be called from any fil...
Definition: messages.F90:1337
character(len=max_path_len) function, public debug_clean_path(filename)
Prune a filename path to only include subdirectories of the "src" directory.
Definition: debug.F90:603
type(debug_t), save, public debug
Definition: debug.F90:156
subroutine, public debug_init(this, namespace)
Definition: debug.F90:178
integer, public no_sub_stack
Definition: global.F90:240
character(len=80), dimension(50), public sub_stack
The stack.
Definition: global.F90:238
type(conf_t), public conf
Global instance of Octopus configuration.
Definition: global.F90:178
Definition: io.F90:114
subroutine, public io_close(iunit, grp)
Definition: io.F90:418
subroutine, public io_mkdir(fname, namespace, parents)
Definition: io.F90:311
integer, parameter, public iunit_out
Definition: io.F90:148
integer, parameter, public iunit_err
Definition: io.F90:149
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
Definition: io.F90:352
subroutine, public alloc_error(size, file, line)
Definition: messages.F90:692
subroutine, public messages_end()
Definition: messages.F90:278
subroutine messages_write_integer8(val, fmt, new_line, units, print_units)
Definition: messages.F90:1181
subroutine, public messages_print_with_emphasis(msg, iunit, namespace)
Definition: messages.F90:921
subroutine, public messages_not_implemented(feature, namespace)
Definition: messages.F90:1114
subroutine, public messages_init(output_dir)
Definition: messages.F90:225
subroutine messages_print_var_option_8(var, option, pre, iunit, namespace)
Definition: messages.F90:880
subroutine messages_print_var_valuear(var, val, unit, iunit, namespace)
Definition: messages.F90:827
subroutine, public messages_variable_is_block(namespace, name)
Definition: messages.F90:1070
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:538
subroutine messages_write_integer(val, fmt, new_line, units, print_units)
Definition: messages.F90:1224
subroutine, public time_sum(sec1, usec1, sec2, usec2)
Computes t2 <- t1+t2. Parameters as in time_diff Assert: t1,2 <= 0.
Definition: messages.F90:1025
subroutine messages_print_var_option_4(var, option, pre, iunit, namespace)
Definition: messages.F90:907
subroutine, public messages_obsolete_variable(namespace, name, rep)
Definition: messages.F90:1046
subroutine, public messages_switch_status(status)
create status file for asynchronous communication
Definition: messages.F90:668
subroutine, public print_date(str)
Definition: messages.F90:1006
subroutine flush_msg(str, iunit, adv)
Definition: messages.F90:991
subroutine, public messages_print_var_info(var, iunit, namespace)
Definition: messages.F90:856
subroutine, public messages_update_mpi_grp(namespace, mpigrp)
Definition: messages.F90:372
subroutine, public messages_new_line()
Definition: messages.F90:1135
subroutine, public dealloc_error(size, file, line)
Definition: messages.F90:703
subroutine messages_print_var_values(var, val, iunit, namespace)
Definition: messages.F90:769
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:415
subroutine messages_print_var_valuei(var, val, iunit, namespace)
Definition: messages.F90:752
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:714
subroutine messages_print_var_valuer(var, val, unit, iunit, namespace)
Definition: messages.F90:783
integer, parameter, private sleepytime_nonwriters
seconds
Definition: messages.F90:167
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1086
subroutine messages_print_var_valuel(var, val, iunit, namespace)
Definition: messages.F90:806
subroutine messages_write_logical(val, new_line)
Definition: messages.F90:1259
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:617
subroutine messages_write_str(val, fmt, new_line)
Definition: messages.F90:1236
type(mpi_grp_t) function messages_get_mpi_grp(namespace)
Definition: messages.F90:383
subroutine, public messages_dump_stack(isignal)
Definition: messages.F90:1285
integer function messages_get_unit(namespace)
Definition: messages.F90:345
subroutine messages_write_float(val, fmt, new_line, units, align_left, print_units)
Definition: messages.F90:1145
subroutine messages_reset_lines()
Definition: messages.F90:1127
logical function mpi_grp_is_root(grp)
Is the current MPI process of grpcomm, root.
Definition: mpi.F90:430
type(mpi_grp_t), public mpi_world
Definition: mpi.F90:266
integer, public mpi_err
used to store return values of mpi calls
Definition: mpi.F90:269
type(namespace_t), public global_namespace
Definition: namespace.F90:132
logical function, public parse_is_defined(namespace, name)
Definition: parser.F90:502
This module implements a simple hash table for string valued keys and integer values using the C++ ST...
Definition: sihash.F90:118
subroutine, public sihash_insert(h, key, val)
Insert a (key, val) pair into the hash table h.
Definition: sihash.F90:203
subroutine, public sihash_init(h)
Initialize a hash table h with size entries. Since we use separate chaining, the number of entries in...
Definition: sihash.F90:162
integer function, public sihash_lookup(h, key, found)
Look up a value in the hash table h. If found is present, it indicates if key could be found in the t...
Definition: sihash.F90:229
subroutine, public sihash_end(h)
Free a hash table.
Definition: sihash.F90:183
This module implements a simple hash table for string valued keys and integer values using the C++ ST...
Definition: sphash.F90:118
subroutine, public sphash_init(h)
Initialize a hash table h with size entries. Since we use separate chaining, the number of entries in...
Definition: sphash.F90:221
subroutine, public sphash_insert(h, key, val, clone)
Insert a (key, val) pair into the hash table h. If clone=.true., the object will be copied.
Definition: sphash.F90:291
subroutine, public sphash_end(h)
Free a hash table.
Definition: sphash.F90:247
class(*) function, pointer, public sphash_lookup(h, key, found)
Look up a value in the hash table h. If found is present, it indicates if key could be found in the t...
Definition: sphash.F90:323
character(len=80) function, public str_center(s_in, l_in)
puts space around string, so that it is centered
Definition: string.F90:174
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:132
character(len=20) pure function, public units_abbrev(this)
Definition: unit.F90:223
subroutine, public varinfo_print_option(iunit, var, option, pre)
Definition: varinfo.F90:311
subroutine, public varinfo_print(iunit, var, ierr)
Definition: varinfo.F90:204
This is defined even when running serial.
Definition: mpi.F90:142
int true(void)
real(real64) function values(xx)
Definition: test.F90:2003