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