Octopus
io.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
21module io_oct_m
22 use debug_oct_m
23 use global_oct_m
24 use loct_oct_m
25 use mpi_oct_m
27 use parser_oct_m
28
29 implicit none
30
31 private
32 public :: &
34 io_open, &
35 io_mkdir, &
36 io_rm, &
37 io_init, &
38 io_end, &
40 io_close, &
43 iopar_read, &
55
56 integer, parameter, public :: iunit_out = 8
57 integer, parameter, public :: iunit_err = 9
58 character(len=MAX_PATH_LEN) :: work_dir
59 character(len=MAX_PATH_LEN) :: current_working_dir
60 integer(int64), save :: io_open_count
61 integer(int64), save :: io_close_count
62
63contains
64
65 ! ---------------------------------------------------------
69 subroutine io_init(defaults)
70 logical, optional, intent(in) :: defaults
71
72 character(len=MAX_PATH_LEN) :: filename
73 integer :: status
74
75 io_open_count = 0
76 io_close_count = 0
77
78 call get_environment_variable("PWD", current_working_dir, status=status)
79 if (status /= 0) then
80 write(*,'("ERROR: could not determine current working directory!")')
81 error stop -1
82 end if
83
84
85 ! cannot use push/pop before initializing io
86
87 if (present(defaults)) then
88 if (defaults) then
89 stdin = 5
90 stdout = 6
91 stderr = 0
92 work_dir = current_working_dir
93 return
94 end if
95 end if
96
97 stdin = 5
98
99 !%Variable stdout
100 !%Type string
101 !%Default "-"
102 !%Section Execution::IO
103 !%Description
104 !% The standard output by default goes to, well, to standard output. This can
105 !% be changed by setting this variable: if you give it a name (other than "-")
106 !% the output stream is printed in that file instead.
107 !%End
108 call parse_variable(global_namespace, 'stdout', '-', filename)
109 stdout = 6
110 if (trim(filename) /= '-') then
111 close(stdout)
112 open(stdout, file=filename, status='unknown')
113 end if
114
115 !%Variable stderr
116 !%Type string
117 !%Default "-"
118 !%Section Execution::IO
119 !%Description
120 !% The standard error by default goes to, well, to standard error. This can
121 !% be changed by setting this variable: if you give it a name (other than "-")
122 !% the output stream is printed in that file instead.
123 !%End
124 call parse_variable(global_namespace, 'stderr', '-', filename)
125 stderr = 0
126 if (trim(filename) /= '-') then
127 close(stderr)
128 open(stderr, file=filename, status='unknown')
129 end if
130
131 !%Variable WorkDir
132 !%Type string
133 !%Default "."
134 !%Section Execution::IO
135 !%Description
136 !% By default, all files are written and read from the working directory,
137 !% <i>i.e.</i> the directory from which the executable was launched, appended by the system name.
138 !% This behavior can be changed by setting this variable. If you set <tt>WorkDir</tt> to a name other than ".",
139 !% the following directories are written and read in that directory:
140 !%<ul>
141 !% <li>"casida/"</li>
142 !% <li>"em_resp_fd/"</li>
143 !% <li>"em_resp/"</li>
144 !% <li>"geom/"</li>
145 !% <li>"kdotp/"</li>
146 !% <li>"local.general"</li>
147 !% <li>"pcm/"</li>
148 !% <li>"profiling/"</li>
149 !% <li>"restart/"</li>
150 !% <li>"static/"</li>
151 !% <li>"td.general/"</li>
152 !% <li>"vdw/"</li>
153 !% <li>"vib_modes/"</li>
154 !%</ul>
155 !% Furthermore, some of the debug information (see <tt>Debug</tt>) is also written to <tt>WorkDir</tt> and
156 !% the non-absolute paths defined in <tt>OutputIterDir</tt> are relative to <tt>WorkDir</tt>.
157 !%End
158 call parse_variable(global_namespace, 'WorkDir', '.', work_dir)
159 ! ... and if necessary create workdir (will not harm if work_dir is already there)
160 if (work_dir /= '.') call loct_mkdir(trim(work_dir))
161
162 if (debug%info .or. debug%interaction_graph .or. debug%propagation_graph) then
163 call io_mkdir('debug', global_namespace)
164 end if
165
166 if (debug%trace_file) then
167 !wipe out debug trace files from previous runs to start fresh rather than appending
168 call debug_delete_trace()
169 end if
170
171 end subroutine io_init
172
173 ! ---------------------------------------------------------
174 subroutine io_end()
175
176 ! no PUSH/POP, because the POP would write to stderr after it was closed.
177
178 if (stderr /= 0) call io_close(stderr)
179 if (stdin /= 5) call io_close(stdin)
180 if (stdout /= 6) call io_close(stdout)
181
182 end subroutine io_end
183
188 ! ---------------------------------------------------------
189 character(len=MAX_PATH_LEN) function io_workdir() result (wpath)
190
191 integer :: len_work_dir
192 character :: first_char
193
194 len_work_dir = len_trim(work_dir)
195 first_char = work_dir(1:1)
196
197 select case (first_char)
198 case ('/')
199 ! absolute path: we just copy it
200 wpath = work_dir
201 case ('.')
202 if (len_work_dir>1) then
203 ! relative path of form './dir'. Strip '.' and append to cwd.
204 wpath = trim(current_working_dir) // trim(work_dir(2:len_work_dir))
205 else
206 wpath = current_working_dir
207 end if
208 case default
209 ! relative path without './'. Append to cwd with missing '/'
210 wpath = trim(current_working_dir) // "/" // trim(work_dir)
211 end select
212
213 end function io_workdir
214
215 ! ---------------------------------------------------------
220 !
221 character(len=MAX_PATH_LEN) function io_workpath(path, namespace) result(wpath)
222 character(len=*), intent(in) :: path
223 type(namespace_t), optional, intent(in) :: namespace
224
225 logical :: absolute_path
226 integer :: total_len
227
228 ! use the logical to avoid problems with the string length
229 absolute_path = .false.
230 if (len_trim(path) > 0) then
231 absolute_path = path(1:1) == '/'
232 end if
233
234 ! check that the path is not longer than the maximum allowed
235 total_len = len_trim(path)
236 if (.not. absolute_path) then
237 total_len = total_len + len_trim(work_dir) + 1
238 if (present(namespace)) then
239 if (namespace%len() > 0) total_len = total_len + namespace%len() + 1
240 end if
241 end if
242 if (total_len > max_path_len) then
243 write(stderr,"(A,I5)") "Path is longer than the maximum path length of ", max_path_len
244 write(stderr,"(A)") path
245 stop -1
246 end if
247
248 if (absolute_path) then
249 ! we do not change absolute path names
250 wpath = trim(path)
251 else
252 wpath = trim(work_dir)
253 if (present(namespace)) then
254 ! insert namespace into path
255 if (namespace%len() > 0) wpath = trim(wpath) + "/" + trim(namespace%get('/'))
256 end if
257 wpath = trim(wpath) + "/" + trim(path)
258 end if
259
260 end function io_workpath
261
262
263 ! ---------------------------------------------------------
264 subroutine io_mkdir(fname, namespace, parents)
265 character(len=*), intent(in) :: fname
266 type(namespace_t), optional, intent(in) :: namespace
267 logical, optional, intent(in) :: parents
268
269 logical :: parents_
270 integer :: last_slash, pos, length
271
272 parents_ = .false.
273 if (present(parents)) parents_ = parents
274
275 if (.not. parents_) then
276 call loct_mkdir(trim(io_workpath("", namespace=namespace)))
277 call loct_mkdir(trim(io_workpath(fname, namespace=namespace)))
278 else
279 last_slash = max(index(fname, "/", .true.), len_trim(fname))
280 pos = 1
281 length = index(fname, '/') - 1
282 do while (pos < last_slash)
283 call loct_mkdir(trim(io_workpath(fname(1:pos+length-1), namespace=namespace)))
284 pos = pos + length + 1
285 length = index(fname(pos:), "/") - 1
286 if (length < 1) length = len_trim(fname(pos:))
287 end do
288
289 end if
290
291 end subroutine io_mkdir
292
293
294 ! ---------------------------------------------------------
295 subroutine io_rm(fname, namespace)
296 character(len=*), intent(in) :: fname
297 type(namespace_t), optional, intent(in) :: namespace
298
299 call loct_rm(trim(io_workpath(fname, namespace=namespace)))
300
301 end subroutine io_rm
302
303
304 ! ---------------------------------------------------------
305 integer function io_open(file, namespace, action, status, form, position, die, recl, grp) result(iunit)
306 character(len=*), intent(in) :: file, action
307 type(namespace_t),intent(in), optional :: namespace
308 character(len=*), intent(in), optional :: status, form, position
309 logical, intent(in), optional :: die
310 integer, intent(in), optional :: recl
311 type(mpi_grp_t), intent(in), optional :: grp
312
313 character(len=20) :: status_, form_, position_
314 character(len=MAX_PATH_LEN) :: file_
315 logical :: die_
316 integer :: iostat
317 character(len=100) :: io_emsg
318 type(mpi_grp_t) :: grp_
319
320 if (present(grp)) then
321 grp_%comm = grp%comm
322 grp_%rank = grp%rank
323 grp_%size = grp%size
324 else
326 end if
327
328
329 if (grp_%is_root()) then
330
331 status_ = 'unknown'
332 if (present(status)) status_ = status
333 form_ = 'formatted'
334 if (present(form)) form_ = form
335 position_ = 'asis'
336 if (present(position)) position_ = position
337
338 die_ = optional_default(die, .true.)
339
340 file_ = io_workpath(file, namespace=namespace)
341
342 if (present(recl)) then
343 open(newunit=iunit, file=trim(file_), status=trim(status_), form=trim(form_), &
344 recl=recl, action=trim(action), position=trim(position_), iostat=iostat, iomsg=io_emsg)
345 else
346 open(newunit=iunit, file=trim(file_), status=trim(status_), form=trim(form_), &
347 action=trim(action), position=trim(position_), iostat=iostat, iomsg=io_emsg)
348 end if
349
350 io_open_count = io_open_count + 1
351
352 if (iostat /= 0) then
353 iunit = -1
354 if (die_) then
355 write(stderr, '(a,a)') '*** IO Error: ', trim(io_emsg)
356 call mpi_world%abort()
357 end if
358 end if
360 end if
361
362 if (grp_%size > 1) then
363 call grp_%bcast(iunit, 1, mpi_integer, 0)
364 end if
365
366 end function io_open
367
368
369 ! ---------------------------------------------------------
370 subroutine io_close(iunit, grp)
371 integer, intent(inout) :: iunit
372 type(mpi_grp_t), intent(in), optional :: grp
373
374 type(mpi_grp_t) :: grp_
375
376 if (present(grp)) then
377 grp_%comm = grp%comm
378 grp_%rank = grp%rank
379 grp_%size = grp%size
380 else
382 end if
383
384 if (grp_%is_root()) then
385 close(iunit)
386 io_close_count = io_close_count + 1
387 end if
388
389 iunit = -1
391 end subroutine io_close
392
393 ! ---------------------------------------------------------
394 subroutine io_dump_file(ounit, filename)
395 integer, intent(in) :: ounit
396 character(len=*), intent(in) :: filename
397
398 integer :: iunit, err
399 character(len=80) :: line
401 if (.not. mpi_world%is_root()) return
402
403 open(newunit=iunit, file=filename, iostat=err, action='read', status='old')
404
405 do while(err == 0)
406 read(iunit, fmt='(a80)', iostat=err) line
407 if (err == 0) then
408 write(ounit, '(a)') trim(line)
409 end if
410 end do
411
412 call io_close(iunit)
413
414 end subroutine io_dump_file
415
416
417 ! ---------------------------------------------------------
421 character(len=8) function io_get_extension(path) result(ext)
422 character(len = *), intent(in) :: path
423 integer :: i, j
424
425 i = index(path, ".", back = .true.)
426 j = index(path(i+1:), "/")
427 if (i == 0 .or. j /= 0) then
428 ext = ""
429 else
430 ext = path(i+1:)
431 end if
432
433 end function io_get_extension
434
435
436 ! ---------------------------------------------------------
438 subroutine io_debug_on_the_fly(namespace)
439 type(namespace_t), intent(in) :: namespace
440
441 ! only root node performs the check
442 if (mpi_world%is_root()) then
443 if (io_file_exists('enable_debug_mode', msg='Enabling DebugMode')) then
444 call debug_enable(debug)
445 ! this call does not hurt if the directory is already there
446 ! but is otherwise required
447 call io_mkdir('debug', namespace)
448 ! we have been notified by the user, so we can cleanup the file
449 call loct_rm('enable_debug_mode')
450 ! artificially increase sub stack to avoid underflow
452 end if
453
454 if (io_file_exists('disable_debug_mode', msg='Disabling DebugMode')) then
455 call debug_disable(debug)
456 ! we have been notified by the user, so we can cleanup the file
457 call loct_rm('disable_debug_mode')
458 end if
459
460 end if
461
462 end subroutine io_debug_on_the_fly
463
464
467 ! ---------------------------------------------------------
468 logical function io_file_exists(filename, msg) result(file_exists)
469 character(len=*), intent(in) :: filename
470 character(len=*), optional, intent(in) :: msg
471
472 file_exists = .false.
473 inquire(file=trim(filename), exist=file_exists)
474 if (file_exists .and. present(msg)) then
475 write(stderr, '(a)') trim(msg)
476 end if
477
478 end function io_file_exists
479
481 ! ---------------------------------------------------------
482 logical function io_dir_exists(dir, namespace)
483 character(len=*), intent(in) :: dir
484 type(namespace_t), optional, intent(in) :: namespace
485
486 io_dir_exists = loct_dir_exists(trim(io_workpath(dir, namespace)))
487
488 end function io_dir_exists
490 ! ---------------------------------------------------------
491 subroutine iopar_read(grp, iunit, lines, n_lines, ierr)
492 type(mpi_grp_t), intent(in) :: grp
493 integer, intent(in) :: iunit
494 character(len=*), intent(out) :: lines(:)
495 integer, intent(in) :: n_lines
496 integer, intent(out) :: ierr
497
498 integer :: il
499
500 assert(n_lines <= size(lines))
501
502 if (grp%is_root()) then
503 do il = 1, n_lines
504 read(iunit, '(a)', iostat=ierr) lines(il)
505 if (ierr /= 0) exit
506 end do
507 end if
508
509 call grp%bcast(ierr, 1, mpi_integer, 0)
510 call grp%bcast(lines(1), len(lines(1))*n_lines, mpi_character, 0)
511
512 end subroutine iopar_read
513
514 ! ---------------------------------------------------------
515 subroutine iopar_backspace(grp, iunit)
516 type(mpi_grp_t), intent(in) :: grp
517 integer, intent(in) :: iunit
518
519 if (grp%is_root()) then
520 backspace(iunit)
521 end if
522
523 end subroutine iopar_backspace
524
525
526 ! ---------------------------------------------------------
527 subroutine iopar_find_line(grp, iunit, line, ierr)
528 type(mpi_grp_t), intent(in) :: grp
529 integer, intent(in) :: iunit
530 character(len=*), intent(in) :: line
531 integer, intent(out) :: ierr
532
533 character(len=80) :: read_line
534
535 if (grp%is_root()) then
536 rewind(iunit)
537 do
538 read(iunit, '(a)', iostat=ierr) read_line
539 if (ierr /= 0 .or. trim(line) == trim(read_line)) exit
540 end do
541 end if
542
543 call grp%bcast(ierr, 1, mpi_integer, 0)
544
545 end subroutine iopar_find_line
546
547
548 ! ---------------------------------------------------------
549 subroutine io_skip_header(iunit)
550 integer, intent(in) :: iunit
551
552 character(len=1) :: a
553
554 rewind(iunit)
555 read(iunit,'(a)') a
556 do while(a == '#')
557 read(iunit,'(a)') a
558 end do
559 backspace(iunit)
560
561 end subroutine io_skip_header
562
563 ! ---------------------------------------------------------
564 integer(int64) pure function io_get_open_count() result(count)
565
566 count = io_open_count
567
568 end function io_get_open_count
569
570 ! ---------------------------------------------------------
571 integer(int64) pure function io_get_close_count() result(count)
572
573 count = io_close_count
574
575 end function io_get_close_count
576
577 ! ---------------------------------------------------------
578 subroutine io_incr_open_count()
579
581
582 end subroutine io_incr_open_count
583
584 ! ---------------------------------------------------------
585 subroutine io_incr_close_count()
588
589 end subroutine io_incr_close_count
590
591 ! ---------------------------------------------------------
592 subroutine io_incr_counters(iio)
593 integer, intent(in) :: iio
594
595 integer :: open_count
596
597 open_count = int(iio/100)
598 io_open_count = io_open_count + open_count
599 io_close_count = io_close_count + iio - open_count * 100
600
601 end subroutine io_incr_counters
602
603
604end module io_oct_m
605
606!! Local Variables:
607!! mode: f90
608!! coding: utf-8
609!! End:
File-handling.
Definition: loct.F90:217
subroutine, public debug_enable(this)
Definition: debug.F90:330
type(debug_t), save, public debug
Definition: debug.F90:158
subroutine, public debug_disable(this)
Definition: debug.F90:345
subroutine, public debug_delete_trace()
Definition: debug.F90:354
integer, public no_sub_stack
Definition: global.F90:244
integer, parameter, public max_path_len
Public types, variables and procedures.
Definition: global.F90:149
Definition: io.F90:116
character(len=8) function, public io_get_extension(path)
Given a path, it returns the extension (if it exists) of the file (that is, the part of the name that...
Definition: io.F90:517
integer(int64), save io_open_count
Definition: io.F90:155
subroutine, public io_init(defaults)
If the argument defaults is present and set to true, then the routine will not try to read anything f...
Definition: io.F90:165
subroutine, public io_close(iunit, grp)
Definition: io.F90:466
subroutine, public io_skip_header(iunit)
Definition: io.F90:645
subroutine, public io_incr_counters(iio)
Definition: io.F90:688
subroutine, public io_incr_close_count()
Definition: io.F90:681
subroutine, public io_end()
Definition: io.F90:270
subroutine, public iopar_read(grp, iunit, lines, n_lines, ierr)
Definition: io.F90:587
integer(int64) pure function, public io_get_close_count()
Definition: io.F90:667
logical function, public io_file_exists(filename, msg)
Returns true if a file with name 'filename' exists and issues a reminder.
Definition: io.F90:564
character(len=max_path_len) function, public io_workpath(path, namespace)
construct path name from given name and namespace
Definition: io.F90:317
subroutine, public io_incr_open_count()
Definition: io.F90:674
subroutine, public iopar_backspace(grp, iunit)
Definition: io.F90:611
integer(int64), save io_close_count
Definition: io.F90:156
subroutine, public io_debug_on_the_fly(namespace)
check if debug mode should be enabled or disabled on the fly
Definition: io.F90:534
subroutine, public io_rm(fname, namespace)
Definition: io.F90:391
character(len=max_path_len) function, public io_workdir()
construct working directory
Definition: io.F90:285
subroutine, public io_mkdir(fname, namespace, parents)
Definition: io.F90:360
logical function, public io_dir_exists(dir, namespace)
Returns true if a dir with name 'dir' exists.
Definition: io.F90:578
subroutine, public iopar_find_line(grp, iunit, line, ierr)
Definition: io.F90:623
integer(int64) pure function, public io_get_open_count()
Definition: io.F90:660
subroutine, public io_dump_file(ounit, filename)
Definition: io.F90:490
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
Definition: io.F90:401
logical function, public loct_dir_exists(dirname)
Definition: loct.F90:328
type(mpi_comm), parameter, public mpi_comm_undefined
used to indicate a communicator has not been initialized
Definition: mpi.F90:138
type(mpi_grp_t), public mpi_world
Definition: mpi.F90:272
subroutine mpi_grp_init(grp, comm)
Initialize MPI group instance.
Definition: mpi.F90:310
type(namespace_t), public global_namespace
Definition: namespace.F90:134
This is defined even when running serial.
Definition: mpi.F90:144
int true(void)