libSUFR
a LIBrary of Some Useful Fortran Routines
All Classes Namespaces Files Functions Variables Pages
system.f90
Go to the documentation of this file.
1!> \file system.f90 System-related procedures
2
3
4! Copyright (c) 2002-2025 Marc van der Sluys - Nikhef/Utrecht University - marc.vandersluys.nl
5!
6! This file is part of the libSUFR package,
7! see: http://libsufr.sourceforge.net/
8!
9! This is free software: you can redistribute it and/or modify it under the terms of the European Union
10! Public Licence 1.2 (EUPL 1.2). This software is distributed in the hope that it will be useful, but
11! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12! PURPOSE. See the EU Public Licence for more details. You should have received a copy of the European
13! Union Public Licence along with this code. If not, see <https://www.eupl.eu/1.2/en/>.
14!
15!
16
17
18
19
20!***********************************************************************************************************************************
21!> \brief System-related procedures
22
24 implicit none
25 save
26
27contains
28
29 !*********************************************************************************************************************************
30 !> \brief Print a message to StdOut and stop the execution of the current program
31 !!
32 !! \param message Exit message
33
34 subroutine quit_program(message)
35 implicit none
36 character, intent(in) :: message*(*)
37
38 write(*,'(//,A)')' '//trim(message)
39 write(*,'(A,/)') ' Exiting...'
40 stop
41
42 end subroutine quit_program
43 !*********************************************************************************************************************************
44
45
46 !*********************************************************************************************************************************
47 !> \brief Print a warning to StdOut and stop the execution of the current program
48 !!
49 !! \param message Exit message/warning
50 !! \param status Exit code: 0-ok, 1-not ok. This makes the stop command appear on screen
51
52 subroutine quit_program_warning(message, status)
54 implicit none
55 character, intent(in) :: message*(*)
56 integer, intent(in) :: status
57
58 write(*,'(//,A)')' * Warning: '//trim(program_name)//': '//trim(message)//' *'
59 if(status.eq.0) then
60 write(*,'(A,/)') ' Exiting...'
61 stop
62 else
63 write(*,'(A)', advance='no')' * '
64 stop 1
65 end if
66
67 end subroutine quit_program_warning
68 !*********************************************************************************************************************************
69
70
71 !*********************************************************************************************************************************
72 !> \brief Print an error message to StdErr and stop the execution of the current program
73 !!
74 !! \param message Exit/error message
75 !! \param status Exit code: 0-ok, 1-not ok. The latter makes the stop command appear on screen
76
77 subroutine quit_program_error(message, status)
79 implicit none
80 character, intent(in) :: message*(*)
81 integer, intent(in) :: status
82
83 write(0,'(//,A)')' *** ERROR: '//trim(program_name)//': '//trim(message)//' ***'
84 if(status.eq.0) then
85 write(0,'(A,/)') ' Exiting...'
86 stop
87 else
88 write(0,'(A)', advance='no')' *** '
89 stop 1
90 end if
91
92 end subroutine quit_program_error
93 !*********************************************************************************************************************************
94
95
96 !*********************************************************************************************************************************
97 !> \brief Execute a shell command and print a message upon error. Optionally stop the execution of the current program in that case.
98 !!
99 !! \param command Command line to execute
100 !! \param wait Execute command synchronously (in the foreground) if true, asynchronously (in the background) if false (optional; default=true)
101 !! \param status Exit code: 0-ok, 1-not ok. The latter makes the stop command appear on screen (optional; default=1)
102 !! \param quit_on_error Quit the program upon error (optional; defaults to false)
103
104 subroutine execute_command_line_verbose(command, wait, status, quit_on_error)
105 implicit none
106 character, intent(in) :: command*(*)
107 logical, intent(in), optional :: wait, quit_on_error
108 integer, intent(in), optional :: status
109
110 integer :: exitstat, cmdstat, lstatus
111 character :: cmdmsg*(1024)
112 logical :: lwait, lquit_on_error
113
114 ! Handle optional variables:
115 lwait = .true.
116 lstatus = 1
117 lquit_on_error = .false.
118 if(present(wait)) lwait = wait
119 if(present(status)) lstatus = status
120 if(present(quit_on_error)) lquit_on_error = quit_on_error
121
122 ! Execute command:
123 cmdmsg = ''
124 call execute_command_line(command, lwait, exitstat, cmdstat, cmdmsg)
125
126 if(lwait .and. exitstat.ne.0) then
127 if(lquit_on_error) then
128 call quit_program_error('the command "'//trim(command)//'" was not executed correctly', lstatus)
129 else
130 call error('the command "'//trim(command)//'" was not executed correctly')
131 end if
132 end if
133
134 if(cmdstat.ne.0) then
135 if(lquit_on_error) then
136 call quit_program_error('the command "'//trim(command)//'" could not be executed: '//trim(cmdmsg), lstatus)
137 else
138 call error('the command "'//trim(command)//'" could not be executed: '//trim(cmdmsg))
139 end if
140 end if
141
142 end subroutine execute_command_line_verbose
143 !*********************************************************************************************************************************
144
145
146 !*********************************************************************************************************************************
147 !> \brief Execute a shell command. Upon error, print a message and stop the execution of the current program
148 !!
149 !! \param command Command line to execute
150 !! \param wait Execute command synchronously (in the foreground) if true, asynchronously (in the background) if false (optional; default=true)
151 !! \param status Exit code: 0-ok, 1-not ok. The latter makes the stop command appear on screen (optional; default=1)
152
153 subroutine execute_command_line_quit_on_error(command, wait, status)
154 implicit none
155 character, intent(in) :: command*(*)
156 logical, intent(in), optional :: wait
157 integer, intent(in), optional :: status
158
159 integer :: lstatus
160 logical :: lwait
161
162 ! Handle optional variables:
163 lwait = .true.
164 lstatus = 1
165 if(present(wait)) lwait = wait
166 if(present(status)) lstatus = status
167 call execute_command_line_verbose(command, lwait, lstatus, quit_on_error=.true.)
168
170 !*********************************************************************************************************************************
171
172
173 !*********************************************************************************************************************************
174 !> \brief Execute a shell command and return the result as a string
175 !!
176 !! \param command Command line to execute
177 !! \param wait Execute command synchronously (in the foreground) if true, asynchronously (in the background) if false (optional; default=true)
178 !! \param status Exit code: 0-ok, 1-not ok. The latter makes the stop command appear on screen (optional; default=1)
179 !!
180 !! \retval String containing the result. Multiple lines are separated by newline code. The size is 10kb, and an error occurs when one attempts to stuff more into it.
181
182 function execute_command_line_and_return_str(command, wait, status)
183 use sufr_kinds, only: double
184 use sufr_constants, only: homedir, newline
186
187 implicit none
188 character, intent(in) :: command*(*)
189 logical, intent(in), optional :: wait
190 integer, intent(in), optional :: status
191 character :: execute_command_line_and_return_str*(1024*10) ! Runtime errors: >10kb: corrupted size vs. prev_size; >19kb: malloc(): corrupted top size; >82kb: Segmentation fault - invalid memory reference
192
193 integer :: seed,ip,ln, lstatus, iostat
194 real(double) :: randble
195 character :: line*(1024), ranfile*(128), iomsg*(128)
196 logical :: lwait
197
198 ! Handle optional variables:
199 lwait = .true.
200 lstatus = 1
201 if(present(wait)) lwait = wait
202 if(present(status)) lstatus = status
203
204 ! Get random name for temporary file:
205 seed = get_ran_seed(0)
206 randble = ran_unif(seed)
207 write(ranfile, '(A,I8.8,A)') trim(homedir)//'/.libsufr-system-file-', nint(randble*1.d8), '.temp'
208
209 ! Execute command and redirect output to file:
210 call execute_command_line_verbose(command//' > '//trim(ranfile), lwait, lstatus)
211
212 ! Open file with output:
213 call find_free_io_unit(ip)
214 open(unit=ip,form='formatted', status='old', action='read', position='rewind', file=trim(ranfile), iostat=iostat)
215 if(iostat.ne.0) call file_open_error_quit(trim(ranfile), 1, 1) ! 1: input file, 1: status: not ok
216
217 ! Read file with output:
218 ln = 0
219 execute_command_line_and_return_str = '' ! Prevent lingering rubbish from entering
220 do while(.true.)
221 ln = ln + 1
222
223 ! Read a line:
224 read(ip,'(A)',iostat=iostat, iomsg=iomsg) line
225 if(iostat.lt.0) exit
226 if(iostat.gt.0) call file_read_error_quit(trim(ranfile), ln, 0, iomsg=trim(iomsg))
227
228 ! Stick multiple lines together:
229 if(ln.eq.1) then
230 write(execute_command_line_and_return_str, '(A)') trim(line)
231 else
233 end if
234
235 end do ! ln
236 close(ip)
237
238 ! Remove temporary output file:
239 call execute_command_line_verbose('rm -f '//trim(ranfile))
240
242 !*********************************************************************************************************************************
243
244
245 !*********************************************************************************************************************************
246 !> \brief Execute a shell command and return the result as an integer
247 !!
248 !! \param command Command line to execute
249 !! \param wait Execute command synchronously (in the foreground) if true, asynchronously (in the background) if false (optional; default=true)
250 !! \param status Exit code: 0-ok, 1-not ok. The latter makes the stop command appear on screen (optional; default=1)
251 !!
252 !! \retval Integer containing the result. If more data were returned by the command, only the first is parsed.
253
254 function execute_command_line_and_return_int(command, wait, status)
255 implicit none
256 character, intent(in) :: command*(*)
257 logical, intent(in), optional :: wait
258 integer, intent(in), optional :: status
260 character :: return_str*(1024*10), iomsg*(1024)
261
262 integer :: lstatus, iostat
263 logical :: lwait
264
265 ! Handle optional variables:
266 lwait = .true.
267 lstatus = 1
268 if(present(wait)) lwait = wait
269 if(present(status)) lstatus = status
270
271 ! Call the command and return the output as a string:
272 return_str = execute_command_line_and_return_str(command, lwait, lstatus)
273
274 ! Read the integer from the return string:
275 read(return_str, *, iostat=iostat, iomsg=iomsg) execute_command_line_and_return_int
276 if(iostat.ne.0) call quit_program_error('the command "'//trim(command)//'" did not return an integer: '//trim(iomsg), lstatus)
277
279 !*********************************************************************************************************************************
280
281
282 !*********************************************************************************************************************************
283 !> \brief Print a syntax message to StdErr
284 !!
285 !! \param syntax Description of syntax
286 !! \param descr Program description (optional; default = none)
287
288 subroutine syntax_print(syntax, descr)
290 implicit none
291 character, intent(in) :: syntax*(*)
292 character, intent(in), optional :: descr*(*)
293
294 write(0,*) ''
295 if(present(descr)) write(0,'(A)') trim(descr)
296
297 write(0,'(A,/)') 'Syntax: '//trim(program_name)//' '//trim(syntax)
298
299 end subroutine syntax_print
300 !*********************************************************************************************************************************
301
302
303 !*********************************************************************************************************************************
304 !> \brief Print a syntax message to StdErr and stop the execution of the current program
305 !!
306 !! \param syntax Description of syntax
307 !! \param status Exit code: 0-ok, 1-not ok. The latter makes the stop command appear on screen (optional; default = 0)
308 !! \param descr Program description (optional; default = none)
309
310 subroutine syntax_quit(syntax, status, descr)
312 implicit none
313 character, intent(in) :: syntax*(*)
314 integer, intent(in), optional :: status
315 character, intent(in), optional :: descr*(*)
316 integer :: lstatus
317
318 write(0,*) ''
319 if(present(descr)) write(0,'(A)') trim(descr)
320
321 write(0,'(A,/)') 'Syntax: '//trim(program_name)//' '//trim(syntax)
322
323 lstatus = 0 ! No stop message by default
324 if(present(status)) lstatus = status
325
326 if(lstatus.eq.0) then
327 stop
328 else
329 write(0,'(A)', advance='no') ' *** '
330 stop 1 ! This will print "STOP 1" or "1" to screen, as well as use exit code 1
331 end if
332
333 end subroutine syntax_quit
334 !*********************************************************************************************************************************
335
336
337 !*********************************************************************************************************************************
338 !> \brief Print a message to StdErr upon file open error
339 !!
340 !! \param filename Filename
341 !! \param filetype File type: 0: (0)utput, 1: (1)nput
342 !! \param ioStat IO status (optional)
343 !! \param ioMsg IO status message (optional; default = none)
344
345 subroutine file_open_error(filename, filetype, ioStat,ioMsg)
347 implicit none
348 character, intent(in) :: filename*(*)
349 integer, intent(in) :: filetype
350 integer, intent(in), optional :: ioStat
351 character, intent(in), optional :: ioMsg*(*)
352
353 select case(filetype)
354 case(0)
355 write(0,'(A)') ' *** '//trim(program_name)//': Error opening output file '//trim(filename)//' ***'
356 case(1)
357 write(0,'(A)') ' *** '//trim(program_name)//': Error opening input file '//trim(filename)//' ***'
358 case default
359 write(0,'(A)') ' *** '//trim(program_name)//', file_open_error_quit(): filetype must be 0 or 1 ***'
360 end select
361
362 ! Print IO status code and/or message:
363 if(present(iostat)) then
364 if(iostat.ne.0) then
365 write(0,'(A,I0,A)', advance='no') 'Error ', iostat, ' occurred'
366 if(present(iomsg)) then
367 write(0,'(A)') ': '//trim(iomsg)
368 else
369 write(0,'(A)') '.'
370 end if
371 end if
372 else if(present(iomsg)) then
373 if(len_trim(iomsg).gt.0) write(0,'(A)') ': '//trim(iomsg)
374 end if
375
376 end subroutine file_open_error
377 !*********************************************************************************************************************************
378
379
380 !*********************************************************************************************************************************
381 !> \brief Print a message to StdErr on file open error, and stop the execution of the current program
382 !!
383 !! \param filename Filename
384 !! \param filetype File type: 0: (0)utput, 1: (1)nput
385 !! \param ioStat IO status (optional): 0-ok, otherwise not ok. The latter makes the stop command appear on screen
386 !! \param ioMsg IO status message (optional; default = none)
387
388 subroutine file_open_error_quit(filename, filetype, ioStat,ioMsg)
389 implicit none
390 character, intent(in) :: filename*(*)
391 integer, intent(in) :: filetype
392 integer, intent(in), optional :: ioStat
393 character, intent(in), optional :: ioMsg*(*)
394 integer :: ioStatL
395 character :: ioMsgL*(999)
396
397 iostatl = 0
398 if(present(iostat)) iostatl = iostat
399 iomsgl = ''
400 if(present(iomsg)) iomsgl = trim(iomsg)
401
402 call file_open_error(filename, filetype, iostat,iomsgl)
403
404 if(iostatl.eq.0) then
405 stop
406 else
407 write(0,'(A)', advance='no')' *** '
408 stop 1
409 end if
410
411 end subroutine file_open_error_quit
412 !*********************************************************************************************************************************
413
414
415 !*********************************************************************************************************************************
416 !> \brief Print a message to StdErr on file read error
417 !!
418 !! \param filename Filename
419 !! \param line Line number where read error occurred - 0: no line
420 !! \param procedure Name of the procedure this subroutine is called from (without "()" - optional; default = none)
421 !! \param ioStat IO status code (optional)
422 !! \param ioMsg IO status message (optional; default = none)
423
424 subroutine file_read_error(filename, line, procedure, ioStat,ioMsg)
426
427 implicit none
428 character, intent(in) :: filename*(*)
429 integer, intent(in) :: line
430 character, intent(in), optional :: procedure*(*)
431 integer, intent(in), optional :: ioStat
432 character, intent(in), optional :: ioMsg*(*)
433
434 write(0,'(/,A)', advance='no') ' *** '//trim(program_name)
435 if(present(procedure)) then
436 if(len_trim(procedure).gt.0) write(0,'(A)', advance='no') ', '//trim(procedure)
437 end if
438 write(0,'(A)', advance='no') ': Error reading input file '//trim(filename)
439 if(line.gt.0) write(0,'(A,I0)', advance='no') ', line ', line
440 if(present(iostat)) then
441 if(iostat.ne.0) write(0,'(A,I0)', advance='no') ', status code ',iostat
442 end if
443 if(present(iomsg)) then
444 if(len_trim(iomsg).gt.0) write(0,'(A)', advance='no') ': '//trim(iomsg)
445 end if
446 write(*,'(A,/)') ' ***'
447
448 end subroutine file_read_error
449 !*********************************************************************************************************************************
450
451
452 !*********************************************************************************************************************************
453 !> \brief Print a message to StdErr on file read error, and stop the execution of the current program
454 !!
455 !! \param filename Filename
456 !! \param line Line number where read error occurred - 0: no line
457 !! \param status Exit code: 0-ok, 1-not ok. The latter makes the stop command appear on screen
458 !! \param procedure Name of the procedure this subroutine is called from (without "()"; optional; default = none)
459 !! \param ioStat IO status code (optional)
460 !! \param ioMsg IO status message (optional; default = none)
461
462 subroutine file_read_error_quit(filename, line, status, procedure, ioStat,ioMsg)
463 implicit none
464 character, intent(in) :: filename*(*)
465 integer, intent(in) :: line, status
466 character, intent(in), optional :: procedure*(*), ioMsg*(*)
467 integer, intent(in), optional :: ioStat
468 integer :: ioStatL
469 character :: procedureL*(999), ioMsgL*(999)
470
471 procedurel = ''
472 if(present(procedure)) procedurel = trim(procedure)
473 iostatl = 0
474 if(present(iostat)) iostatl = iostat
475 iomsgl = ''
476 if(present(iomsg)) iomsgl = trim(iomsg)
477
478 call file_read_error(filename, line, procedurel, iostatl,iomsgl)
479
480 if(status.eq.0) then
481 stop
482 else
483 write(0,'(A)', advance='no') ' *** '
484 stop 1
485 end if
486
487 end subroutine file_read_error_quit
488 !*********************************************************************************************************************************
489
490
491 !*********************************************************************************************************************************
492 !> \brief Print a message to StdErr on file write error
493 !!
494 !! \param filename Filename
495 !! \param line Line number where write error occurred - 0: no line
496
497 subroutine file_write_error(filename, line)
499 implicit none
500 character, intent(in) :: filename*(*)
501 integer, intent(in) :: line
502
503 select case(line)
504 case(0)
505 write(0,'(/,A,/)') ' *** '//trim(program_name)//': Error writing input file '//trim(filename)//' ***'
506 case default
507 write(0,'(/,A,I0,A/)') ' *** '//trim(program_name)//': Error writing input file '//trim(filename)//', line ',line, &
508 ' ***'
509 end select
510
511 end subroutine file_write_error
512 !*********************************************************************************************************************************
513
514
515 !*********************************************************************************************************************************
516 !> \brief Print a message to StdErr on file write error, and stop the execution of the current program
517 !!
518 !! \param filename Filename
519 !! \param line Line number where write error occurred - 0: no line
520 !! \param status Exit code: 0-ok, 1-not ok. The latter makes the stop command appear on screen
521
522 subroutine file_write_error_quit(filename, line, status)
524 implicit none
525 character, intent(in) :: filename*(*)
526 integer, intent(in) :: line, status
527
528 select case(line)
529 case(0)
530 write(0,'(/,A,/)') ' *** '//trim(program_name)//': Error writing input file '//trim(filename)//', aborting ***'
531 case default
532 write(0,'(/,A,I0,A/)') ' *** '//trim(program_name)//': Error writing input file '//trim(filename)//', line ',line, &
533 ', aborting ***'
534 end select
535
536 if(status.eq.0) then
537 stop
538 else
539 write(0,'(A)', advance='no')' *** '
540 stop 1
541 end if
542
543 end subroutine file_write_error_quit
544 !*********************************************************************************************************************************
545
546
547 !*********************************************************************************************************************************
548 !> \brief Print a message to StdErr on reaching the end of a file while reading
549 !!
550 !! \param filename Filename
551
552 subroutine file_end_error(filename)
554 implicit none
555 character, intent(in) :: filename*(*)
556
557 write(0,'(/,A,/)') ' *** '//trim(program_name)//': Error while reading input file '//trim(filename)// &
558 ': reached the end of the file ***'
559
560 end subroutine file_end_error
561 !*********************************************************************************************************************************
562
563
564 !*********************************************************************************************************************************
565 !> \brief Print a message to StdErr on reaching the end of a file while reading, and stop the code
566 !!
567 !! \param filename Filename
568 !! \param status Exit code: 0-ok, 1-not ok. The latter makes the stop command appear on screen
569
570 subroutine file_end_quit(filename, status)
572 implicit none
573 character, intent(in) :: filename*(*)
574 integer, intent(in) :: status
575
576 write(0,'(/,A,/)') ' *** '//trim(program_name)//': Error while reading input file '//trim(filename)// &
577 ': reached the end of the file ***'
578
579 if(status.eq.0) then
580 stop
581 else
582 write(0,'(A)', advance='no') ' *** '
583 stop 1
584 end if
585
586 end subroutine file_end_quit
587 !*********************************************************************************************************************************
588
589
590
591 !*********************************************************************************************************************************
592 !> \brief Print a message to StdErr on read error or reaching the end of a file while reading, and optionally stop the code
593 !!
594 !! \param filename Filename
595 !! \param line Line number where read error occurred - 0: no line
596 !! \param readstatus Read status provided by iostat
597 !! \param stopcode Stop the execution of the code: 0-no, 1-yes
598 !! \param exitstatus Exit code: 0-ok, 1-not ok. The latter makes the stop command appear on screen
599 !! \param message Custom message (optional; default = none)
600
601 subroutine file_read_end_error(filename, line, readstatus, stopcode, exitstatus, message)
602 implicit none
603 character, intent(in) :: filename*(*)
604 integer, intent(in) :: line, readstatus, stopcode, exitstatus
605 character, intent(in), optional :: message*(*)
606
607 select case(readstatus)
608 case(:-1) ! End of file reached (<0)
609 if(stopcode.eq.0) then
610 call file_end_error(trim(filename))
611 else
612 call file_end_quit(trim(filename), exitstatus)
613 end if
614 case(1:) ! Read error (>0)
615 if(stopcode.eq.0) then
616 if(present(message)) then
617 call file_read_error(trim(filename), line, iomsg=trim(message))
618 else
619 call file_read_error(trim(filename), line)
620 end if
621 else
622 if(present(message)) then
623 call file_read_error_quit(trim(filename), line, exitstatus, iomsg=trim(message))
624 else
625 call file_read_error_quit(trim(filename), line, exitstatus)
626 end if
627 end if
628 end select
629
630 end subroutine file_read_end_error
631 !*********************************************************************************************************************************
632
633
634
635
636
637
638
639 !*********************************************************************************************************************************
640 !> \brief Print a warning to StdOut or StErr
641 !!
642 !! \param message Warning message
643 !! \param unit Output unit: 0-StdErr, 1-StdOut (optional; default = 0)
644
645 subroutine warn(message, unit)
647 implicit none
648 character, intent(in) :: message*(*)
649 integer, intent(in), optional :: unit
650 integer :: lunit
651
652 ! Handle optional variable:
653 lunit = 6 ! Default: stdOut
654 if(present(unit)) lunit = unit ! Optional variable
655 if(lunit.ne.6) lunit = 0 ! If not stdOut, then stdErr: 0
656
657 write(lunit,'(/,A,/)')' * Warning: '//trim(program_name)//': '//trim(message)//' *'
658
659 end subroutine warn
660 !*********************************************************************************************************************************
661
662
663
664 !*********************************************************************************************************************************
665 !> \brief Print an error to StdOut or StErr
666 !!
667 !! \param message Warning message
668 !! \param unit Output unit: 0-StdErr, 1-StdOut - (optional; default = 0)
669
670 subroutine error(message, unit)
672 implicit none
673 character, intent(in) :: message*(*)
674 integer, intent(in), optional :: unit
675 integer :: lunit
676
677 ! Handle optional variable:
678 lunit = 0 ! Default: stdErr
679 if(present(unit)) lunit = unit ! Optional variable
680 if(lunit.ne.0) lunit = 6 ! If not StdErr, then StdOut: 6
681
682 write(lunit,'(/,A,/)')' *** ERROR: '//trim(program_name)//': '//trim(message)//' ****'
683
684 end subroutine error
685 !*********************************************************************************************************************************
686
687
688
689
690 !*********************************************************************************************************************************
691 !> \brief Get date and time from the system clock
692 !!
693 !! \param year Current year CE
694 !! \param month Current month
695 !! \param day Current day of month
696 !!
697 !! \param hour Current hour of day
698 !! \param minute Current minute of time
699 !! \param second Current second of time
700 !!
701 !! \param tz Time zone in hours (optional)
702
703 subroutine system_time(year,month,day, hour,minute,second, tz)
704 use sufr_kinds, only: double
705 use sufr_dummy, only: dumstr99
706
707 implicit none
708 integer, intent(out) :: year,month,day, hour,minute
709 real(double), intent(out) :: second
710 real(double), intent(out), optional :: tz
711 integer :: dt(8)
712
713 call date_and_time(dumstr99,dumstr99,dumstr99, dt)
714
715 year = dt(1)
716 month = dt(2)
717 day = dt(3)
718
719 if(present(tz)) tz = dble(dt(4))/60.d0
720
721 hour = dt(5)
722 minute = dt(6)
723 second = dble(dt(7)) + dble(dt(8))*1.d-3
724
725 end subroutine system_time
726 !*********************************************************************************************************************************
727
728
729
730
731
732
733 !*********************************************************************************************************************************
734 !> \brief Return the time stamp in seconds since 1970-01-01 00:00:00 UTC
735 !!
736 !! \retval timestamp Unix timestamp: number of seconds since 1970-01-01 00:00:00 UTC, accuracy: 1ms
737
738 function timestamp()
739 use sufr_kinds, only: double
741 use sufr_dummy, only: dumstr99
742
743 implicit none
744 integer :: dt(8)
745 real(double) :: timestamp, jd,djd
746
747 call date_and_time(dumstr99,dumstr99,dumstr99, dt) ! dt: y,m,d, tz (min), h,m,s, ms
748 jd = ymdhms2jd( dt(1), dt(2), dt(3), dt(5), dt(6)-dt(4), dble(dt(7))+dble(dt(8))/1.d3 ) ! y,m,d, h, m-tz, s+ms
749 djd = jd - ymdhms2jd(1970, 1, 1, 0, 0, 0.d0)
750 timestamp = djd * 86400 ! Day -> s
751
752 end function timestamp
753 !*********************************************************************************************************************************
754
755
756 !*********************************************************************************************************************************
757 !> \brief Print a text progress bar to the screen, optionally with estimated time left
758 !!
759 !! \param frac Fraction of the task completed
760 !! \param timestamp0 Timestamp of start of task (optional; default = don't print time left)
761
762 subroutine printprogressbar(frac, timestamp0)
763 use sufr_kinds, only: double
764 use sufr_constants, only: cursorup
765
766 implicit none
767 integer, parameter :: nsteps = 100
768 real(double), intent(in) :: frac
769 real(double), intent(in), optional :: timestamp0
770
771 integer :: st, perc
772
773 write(*,*) cursorup
774 perc = nint(frac*nsteps)
775 write(*,'(A,I3,A)',advance='no') ' Progress: ',perc,'% ['
776 do st=1,nsteps
777 if(st.le.perc) then
778 write(*,'(A1)',advance='no') '#'
779 else
780 write(*,'(A1)',advance='no') ' '
781 end if
782 end do
783
784 if(present(timestamp0)) then
785 write(*,'(A,A9)') '] Est.time left:',tms((timestamp()-timestamp0)*(1.d0-frac)/frac/3600.d0)
786 else
787 write(*,'(A)') ']'
788 end if
789
790 end subroutine printprogressbar
791 !*********************************************************************************************************************************
792
793 !*********************************************************************************************************************************
794 !> \brief Print time as mm:ss.s string, input in hours
795 !!
796 !! \param t Time (h)
797 !! \retval tms Time as mm:ss.s string
798 !!
799 !! \note use here to drop dependency to SUFR_time2string. Alternative: move printProgressBar elsewhere
800
801 pure function tms(t)
802 use sufr_kinds, only: double
803 implicit none
804 real(double), intent(in) :: t
805 real(double) :: a,s
806 integer :: m
807 character :: tms*(8),ss*(4)
808
809 a = t
810 m = int((a)*60.d0)
811 s = (a-m/60.d0)*3600.d0
812
813 write(ss,'(F4.1)') s
814 if(nint(s*10).lt.100) write(ss,'(A1,F3.1)') '0',s
815 write(tms,'(I2.2,A1,A4,A1)') m,'m',ss,'s'
816
817 end function tms
818 !*********************************************************************************************************************************
819
820
821
822
823 !*********************************************************************************************************************************
824 !> \brief Print run times: wall time and CPU time
825 !!
826 !! \param calltype Type of call: 1-reset time; 2-print and reset time; 3-print time (optional; default = 1 on first call, else 3)
827 !! \param sp Number of leading spaces (optional; default = 0)
828 !! \param dec Number of decimals in the time (optional; default = 3)
829
830 subroutine print_runtimes(calltype, sp,dec)
831 use sufr_kinds, only: double, long
832 implicit none
833 integer, intent(in), optional :: calltype, sp, dec
834 integer :: loc_calltype, loc_sp, loc_dec
835
836 integer, save :: firstcall
837 real(double), save :: oldcputime,oldwalltime
838
839 integer(long) :: count, count_rate, count_max
840 real(double) :: cputime, walltime
841 character :: fmt*(99)
842
843 ! Optional dummy variables:
844 loc_calltype = 1 ! First call - reset time, don't print
845 if(firstcall.eq.213546879) loc_calltype = 3 ! >= 2nd call - print times, don't reset
846 if(present(calltype)) loc_calltype = calltype
847
848 loc_sp = 0 ! No leading spaces by default
849 if(present(sp)) loc_sp = sp
850
851 loc_dec = 3 ! 3 decimals in time in seconds by default
852 if(present(dec)) loc_dec = dec
853
854
855 ! Get CPU time:
856 call cpu_time(cputime)
857
858 ! Get wall time:
859 call system_clock(count, count_rate, count_max)
860 if(count_rate.gt.0.d0) then
861 walltime = dble(count)/dble(count_rate)
862 else
863 walltime = 0.d0
864 end if
865
866 ! Print times:
867 if(loc_calltype.ge.2) then
868 if(firstcall.ne.213546879) then
869 call warn('libSUFR print_runtime(): loc_calltype should be 1 on the first call', 0)
870 return
871 end if
872
873 if(loc_sp.eq.0) then ! No leading spaces:
874 write(fmt, '(A,I0,A)') '(A,2(F0.',max(0,loc_dec),',A))'
875 else
876 write(fmt, '(A,I0,A,I0,A)') '(',max(0,loc_sp),'x,A,2(F0.',max(0,loc_dec),',A))'
877 end if
878 write(*,trim(fmt)) 'Program took ',walltime-oldwalltime,' seconds of wall time and ',cputime-oldcputime, &
879 ' seconds of CPU time.'
880 end if
881
882 ! Reset times:
883 if(loc_calltype.le.2) then
884 oldcputime = cputime
885 oldwalltime = walltime
886 end if
887 firstcall = 213546879
888
889 end subroutine print_runtimes
890 !*********************************************************************************************************************************
891
892
893
894 !*********************************************************************************************************************************
895 !> \brief Print CPU time since the first execution of the program
896 !!
897 !! \param sp Number of leading spaces (optional; default = 0)
898 !! \param dec Number of decimals in the time (optional; default = 3)
899 !! \param unit Output unit (0: stdErr, 6: stdOut; optional; default = 6)
900
901 subroutine print_cputime(sp,dec,unit)
902 use sufr_kinds, only: double
903 implicit none
904 integer, intent(in), optional :: sp, dec, unit
905 integer :: loc_sp, loc_dec, loc_unit
906
907 real(double) :: cputime
908 character :: fmt*(99)
909
910 ! Optional dummy variables:
911 loc_sp = 0 ! No leading spaces by default
912 if(present(sp)) loc_sp = sp
913
914 loc_dec = 3 ! 3 decimals in time in seconds by default
915 if(present(dec)) loc_dec = dec
916
917 loc_unit = 6
918 if(present(unit)) loc_unit = max(unit, 0) ! Don't use a negative unit number
919
920 ! Get CPU time:
921 call cpu_time(cputime)
922
923 ! Print CPU time:
924 if(loc_sp.eq.0) then ! No leading spaces:
925 write(fmt, '(A,I0,A)') '(A,2(F0.',max(0,loc_dec),',A))'
926 else
927 write(fmt, '(A,I0,A,I0,A)') '(',max(0,loc_sp),'x,A,2(F0.',max(0,loc_dec),',A))'
928 end if
929
930 if(loc_unit.eq.6) then ! Use stdOut
931 write(*,trim(fmt)) 'Program took ',cputime,' seconds of CPU time.'
932 else ! Use specified unit
933 write(unit,trim(fmt)) 'Program took ',cputime,' seconds of CPU time.'
934 end if
935
936 end subroutine print_cputime
937 !*********************************************************************************************************************************
938
939
940
941
942
943
944
945 !*********************************************************************************************************************************
946 !> \brief Find the first unused I/O unit larger than 100
947 !!
948 !! \param unit I/O unit; unit > 100 (output)
949
950 subroutine find_free_io_unit(unit)
951 implicit none
952 integer, intent(out) :: unit
953 logical :: status
954
955 do unit=101,huge(unit)-1
956 inquire(unit=unit, opened=status)
957 if(.not.status) exit
958 end do
959
960 end subroutine find_free_io_unit
961 !*********************************************************************************************************************************
962
963
964
965 !*********************************************************************************************************************************
966 !> \brief Skip the next (e.g. first) lines of a file
967 !!
968 !! \param unit File unit
969 !! \param nLines Number of lines to skip
970
971 subroutine file_skip_header(unit, nLines)
972 use sufr_dummy, only: dumstr
973 implicit none
974 integer, intent(in) :: unit, nLines
975 integer :: ln
976
977 ! Read and discard lines in file:
978 do ln=1,nlines
979 read(unit,'(A)') dumstr
980 end do
981
982 end subroutine file_skip_header
983 !*********************************************************************************************************************************
984
985
986
987 !*********************************************************************************************************************************
988 !> \brief Swap two integer variables
989 !!
990 !! \param int1 Integer 1
991 !! \param int2 Integer 2
992
993 pure subroutine swapint(int1, int2)
994 implicit none
995 integer, intent(inout) :: int1,int2
996 integer :: int0
997
998 int0 = int1
999 int1 = int2
1000 int2 = int0
1001
1002 end subroutine swapint
1003 !*********************************************************************************************************************************
1004
1005
1006
1007 !*********************************************************************************************************************************
1008 !> \brief Swap two single-precision real variables
1009 !!
1010 !! \param rl1 real 1
1011 !! \param rl2 real 2
1012
1013 pure subroutine swapreal(rl1, rl2)
1014 implicit none
1015 real, intent(inout) :: rl1,rl2
1016 real :: rl0
1017
1018 rl0 = rl1
1019 rl1 = rl2
1020 rl2 = rl0
1021
1022 end subroutine swapreal
1023 !*********************************************************************************************************************************
1024
1025
1026
1027 !*********************************************************************************************************************************
1028 !> \brief Swap two double-precision real variables
1029 !!
1030 !! \param dbl1 Double 1
1031 !! \param dbl2 Double 2
1032
1033 pure subroutine swapdbl(dbl1, dbl2)
1034 use sufr_kinds, only: double
1035 implicit none
1036 real(double), intent(inout) :: dbl1,dbl2
1037 real(double) :: dbl0
1038
1039 dbl0 = dbl1
1040 dbl1 = dbl2
1041 dbl2 = dbl0
1042
1043 end subroutine swapdbl
1044 !*********************************************************************************************************************************
1045
1046
1047 !*********************************************************************************************************************************
1048 !> \brief Swap two strings
1049 !!
1050 !! \param str1 String 1 (I/O)
1051 !! \param str2 String 2 (I/O)
1052
1053 subroutine swapstr(str1,str2)
1054 implicit none
1055 character, intent(inout) :: str1*(*),str2*(*)
1056 character :: str0*(max(len(str1),len(str2)))
1057
1058 if(len_trim(str1).gt.len(str2) .or. len_trim(str2).gt.len(str1)) &
1059 call warn('libSUFR - swapstr(): partial loss of characters when swapping strings', 0)
1060
1061 str0 = trim(str1)
1062 str1 = trim(str2)
1063 str2 = trim(str0)
1064
1065 end subroutine swapstr
1066 !*********************************************************************************************************************************
1067
1068
1069end module sufr_system
1070!***********************************************************************************************************************************
1071
Provides all constants in the library, and routines to define them.
Definition constants.f90:23
character, dimension(4), parameter, public cursorup
Print this to move the cursor up one line on screen (need 2 lines since print gives a hard return)
character, dimension(2), parameter, public newline
Newline character: ASCII Carriage Return (13) + Line Feed (10)
character, dimension(199), public program_name
Name of the currently running program, without the path.
character, dimension(199), public homedir
Current user's home directory (= $HOME, will contain e.g. '/home/user')
Procedures for manipulation of date and time.
elemental real(double) function ymdhms2jd(yy, mmo, dd, h, m, s)
Convert date and time (y,m,d, h,m,s) to JD. Input and output in UT.
Module containing dummy variables for all kinds.
character dumstr
Dummy character.
character, dimension(99) dumstr99
Dummy string of length 99.
Provides kinds and related constants/routines.
Definition kinds.f90:26
integer, parameter double
Double-precision float. Precision = 15, range = 307.
Definition kinds.f90:35
integer, parameter long
Long integer.
Definition kinds.f90:31
Procedures to generate random numbers.
integer function get_ran_seed(degree, date_array)
Use the system clock to get a random initialisation seed (i.e., negative integer) for a random-numbed...
real(double) function ran_unif(seed)
Generate a pseudo-random number from a uniform distribution 0 < r < 1.
System-related procedures.
Definition system.f90:23
subroutine print_runtimes(calltype, sp, dec)
Print run times: wall time and CPU time.
Definition system.f90:831
subroutine file_read_error(filename, line, procedure, iostat, iomsg)
Print a message to StdErr on file read error.
Definition system.f90:425
subroutine error(message, unit)
Print an error to StdOut or StErr.
Definition system.f90:671
subroutine quit_program_error(message, status)
Print an error message to StdErr and stop the execution of the current program.
Definition system.f90:78
subroutine file_read_end_error(filename, line, readstatus, stopcode, exitstatus, message)
Print a message to StdErr on read error or reaching the end of a file while reading,...
Definition system.f90:602
subroutine file_read_error_quit(filename, line, status, procedure, iostat, iomsg)
Print a message to StdErr on file read error, and stop the execution of the current program.
Definition system.f90:463
subroutine find_free_io_unit(unit)
Find the first unused I/O unit larger than 100.
Definition system.f90:951
subroutine file_end_quit(filename, status)
Print a message to StdErr on reaching the end of a file while reading, and stop the code.
Definition system.f90:571
subroutine warn(message, unit)
Print a warning to StdOut or StErr.
Definition system.f90:646
subroutine file_open_error(filename, filetype, iostat, iomsg)
Print a message to StdErr upon file open error.
Definition system.f90:346
pure character function, dimension(8) tms(t)
Print time as mm:ss.s string, input in hours.
Definition system.f90:802
real(double) function timestamp()
Return the time stamp in seconds since 1970-01-01 00:00:00 UTC.
Definition system.f90:739
subroutine file_end_error(filename)
Print a message to StdErr on reaching the end of a file while reading.
Definition system.f90:553
subroutine quit_program_warning(message, status)
Print a warning to StdOut and stop the execution of the current program.
Definition system.f90:53
subroutine execute_command_line_quit_on_error(command, wait, status)
Execute a shell command. Upon error, print a message and stop the execution of the current program.
Definition system.f90:154
subroutine quit_program(message)
Print a message to StdOut and stop the execution of the current program.
Definition system.f90:35
character function, dimension(1024 *10) execute_command_line_and_return_str(command, wait, status)
Execute a shell command and return the result as a string.
Definition system.f90:183
subroutine print_cputime(sp, dec, unit)
Print CPU time since the first execution of the program.
Definition system.f90:902
subroutine execute_command_line_verbose(command, wait, status, quit_on_error)
Execute a shell command and print a message upon error. Optionally stop the execution of the current ...
Definition system.f90:105
subroutine file_write_error_quit(filename, line, status)
Print a message to StdErr on file write error, and stop the execution of the current program.
Definition system.f90:523
subroutine syntax_print(syntax, descr)
Print a syntax message to StdErr.
Definition system.f90:289
subroutine printprogressbar(frac, timestamp0)
Print a text progress bar to the screen, optionally with estimated time left.
Definition system.f90:763
subroutine syntax_quit(syntax, status, descr)
Print a syntax message to StdErr and stop the execution of the current program.
Definition system.f90:311
pure subroutine swapint(int1, int2)
Swap two integer variables.
Definition system.f90:994
integer function execute_command_line_and_return_int(command, wait, status)
Execute a shell command and return the result as an integer.
Definition system.f90:255
subroutine file_open_error_quit(filename, filetype, iostat, iomsg)
Print a message to StdErr on file open error, and stop the execution of the current program.
Definition system.f90:389
subroutine swapstr(str1, str2)
Swap two strings.
Definition system.f90:1054
subroutine file_write_error(filename, line)
Print a message to StdErr on file write error.
Definition system.f90:498
pure subroutine swapreal(rl1, rl2)
Swap two single-precision real variables.
Definition system.f90:1014
pure subroutine swapdbl(dbl1, dbl2)
Swap two double-precision real variables.
Definition system.f90:1034
subroutine file_skip_header(unit, nlines)
Skip the next (e.g. first) lines of a file.
Definition system.f90:972
subroutine system_time(year, month, day, hour, minute, second, tz)
Get date and time from the system clock.
Definition system.f90:704