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