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