1!
2!        ~~~ BUffer Input/Output Library. ~~~
3! Copyright Lorenzo Paulatto <paulatz@gmail.com> 2013
4!
5! Contains a few changes by PG wrt the original implementation:
6! - data is complex, not real
7! - most routines are functions that return error status instead of stopping
8! - added possibility to store file name info in the linked list
9!
10! This file is distributed under the terms of the
11! GNU General Public License. See the file `License'
12! in the root directory of the present distribution,
13! or http://www.gnu.org/copyleft/gpl.txt
14!
15! <<^V^\\=========================================//-//-//========//O\\//
16MODULE buiol
17  !! BUffer Input/Output Library
18  !
19  USE kinds, ONLY : DP
20  !
21  PUBLIC :: init_buiol          ! init the linked chain of i/o units
22  PUBLIC :: is_init_buiol       ! .t. between call to init_buiol and stop_buiol
23  PUBLIC :: stop_buiol          ! destroy the linked chain, dealloc everything
24  PUBLIC :: report_buiol        ! report on total number of units and memory usage
25  PUBLIC :: buiol_open_unit     ! (unit, recl, ext, dir) open a new unit
26  PUBLIC :: buiol_close_unit    ! (unit) close the unit, dealloc the space
27  PUBLIC :: buiol_check_unit    ! (unit) returns recl, if opened, -1 if closed
28  PUBLIC :: buiol_get_ext       ! (unit) returns file extension
29  PUBLIC :: buiol_get_dir       ! (unit) returns dir where file is opened
30  PUBLIC :: buiol_report_unit   ! (unit, mem?) report about unit status (on stdout)
31  PUBLIC :: buiol_write_record  ! (unit, recl, nrec, DATA) write DATA(recl) in record nrec of unit
32  PUBLIC :: buiol_read_record   ! (unit, recl, nrec, DATA) read DATA(recl) from record nrec of unit
33  !
34  PRIVATE
35  !
36  INTEGER,PARAMETER :: nrec0 = 1024
37  !! initial number of records in the buffer (each record will only be allocated on write!)
38
39  REAL(DP),PARAMETER :: fact0 = 1.5_dp
40  !! when writing beyond the last available record increase the index by AT LEAST this factor..
41
42  REAL(DP),PARAMETER :: fact1 = 1.2_dp
43  !! .. furthermore, allocate up to AT LEAST this factor times the required overflowing nrec
44  !
45  ! NOTE: the new buffer size will be determined with both methods, taking the MAX of the two
46  !
47  INTEGER,PARAMETER :: size0 = DP ! 8 bytes
48  !! Size of the single item of the record (for memory usage report only)
49  !
50  TYPE index_of_list
51    !! base element of the linked chain of buffers
52    TYPE(data_in_the_list),POINTER :: index(:)
53    INTEGER :: nrec, unit, recl
54    CHARACTER(LEN=256) :: extension, save_dir
55    TYPE(index_of_list),POINTER :: next => null()
56  END TYPE
57  !
58  TYPE data_in_the_list
59    !! sub-structure containing the data buffer
60    COMPLEX(DP), POINTER :: data(:) => null()
61  END TYPE
62  !
63  TYPE(index_of_list),SAVE,POINTER :: ENTRY => null()
64  !! beginning of the linked chain, statically allocated (for implementation simplicity)
65  !
66  LOGICAL,SAVE :: is_init_buiol = .false.
67  !! set to true when the library has been initialized
68  !
69  CONTAINS
70  ! <<^V^\\=========================================//-//-//========//O\\//
71  !
72  SUBROUTINE init_buiol
73    IMPLICIT NONE
74    ! avoid initializing twice, or we will loose the head of the list!
75    IF (is_init_buiol) THEN
76#if defined(__DEBUG)
77       CALL infomsg('buiol', 'already initialized')
78#endif
79       RETURN
80    ENDIF
81    !
82    ALLOCATE(ENTRY)
83    ALLOCATE(ENTRY%index(0))
84    ENTRY%nrec =  0
85    ENTRY%unit = -1
86    ENTRY%recl = -1
87    ENTRY%extension= ' '
88    ENTRY%save_dir = ' '
89    NULLIFY(ENTRY%next)
90    is_init_buiol = .true.
91    !
92    RETURN
93  END SUBROUTINE init_buiol
94  ! \/o\________\\\_________________________________________/^>
95  SUBROUTINE stop_buiol
96    IMPLICIT NONE
97    TYPE(index_of_list),POINTER :: CURSOR, AUX
98    IF (.not.is_init_buiol) RETURN
99    IF (.not.associated(ENTRY) ) CALL errore('stop_buiol', 'ENTRY was lost.',1)
100    !
101    CURSOR => ENTRY
102    DO WHILE (associated(CURSOR%NEXT))
103      AUX => CURSOR
104      CURSOR => CURSOR%NEXT
105      CALL dealloc_buffer(AUX)
106    ENDDO
107    CALL dealloc_buffer(CURSOR)
108    !
109    is_init_buiol=.false.
110    RETURN
111  END SUBROUTINE stop_buiol
112  ! \/o\________\\\_________________________________________/^>
113  SUBROUTINE report_buiol
114    IMPLICIT NONE
115    TYPE(index_of_list),POINTER :: CURSOR
116    INTEGER :: mem
117    !
118    IF (.not.is_init_buiol) THEN
119      WRITE(*,'(2x,a,3i14)') "[BUIOL] not even initialized"
120      RETURN
121    ENDIF
122    !
123    WRITE(*,'(2x,106("-") )')
124    mem = 0
125    CURSOR => ENTRY
126    DO WHILE (associated(CURSOR%NEXT))
127      CALL buiol_report_buffer(CURSOR, mem)
128      CURSOR => CURSOR%NEXT
129    ENDDO
130    CALL buiol_report_buffer(CURSOR, mem)
131    WRITE(*,'(2x,106("-"))')
132    WRITE(*,'(2x,a,3i14)') "[BUIOL] total memory used B/KB/MB", mem, mem/1024, mem/1024**2
133    WRITE(*,'(2x,106("-"))')
134
135    RETURN
136  END SUBROUTINE report_buiol
137  ! \/o\________\\\_________________________________________/^>
138  FUNCTION buiol_open_unit(unit, recl, extension, save_dir) RESULT (ierr)
139    IMPLICIT NONE
140    INTEGER,INTENT(in) :: unit, recl
141    CHARACTER(LEN=*), INTENT(in) :: extension, save_dir
142    INTEGER :: ierr
143    TYPE(index_of_list),POINTER :: CURSOR
144    !
145    IF (.not.is_init_buiol) CALL errore('buiol_open_unit', 'You must init before open',1)
146    IF(recl<0) THEN
147#if defined(__DEBUG)
148       CALL infomsg('buiol_open_unit', 'wrong recl')
149#endif
150       ierr = 1
151       RETURN
152    END IF
153    !
154    ! check if the unit is already opened
155    CURSOR => find_unit(unit)
156    IF(associated(CURSOR)) THEN
157#if defined(__DEBUG)
158       CALL infomsg('buiol_open_unit', 'unit already opened')
159#endif
160       ierr = -1
161       RETURN
162    END IF
163    !
164    ! all is fine, allocate a new unit with standard size
165    CURSOR => alloc_buffer(unit, recl, nrec0, extension, save_dir)
166    !
167    ! place it at the beginning of the chain
168    CURSOR%next => ENTRY%next
169    ENTRY%next  => CURSOR
170    ierr = 0
171    !
172    RETURN
173    !
174  END FUNCTION buiol_open_unit
175  ! \/o\________\\\_________________________________________/^>
176  FUNCTION buiol_close_unit(unit) RESULT (ierr)
177    IMPLICIT NONE
178    INTEGER,INTENT(in) :: unit
179    INTEGER :: ierr
180    TYPE(index_of_list),POINTER :: CURSOR, AUX
181    !
182    ! find the unit to close
183    CURSOR => find_prev_unit(unit)
184    IF(.not.associated(CURSOR))  THEN
185#if defined(__DEBUG)
186       CALL infomsg('buiol_close_unit', 'cannot close this unit')
187#endif
188       ierr = 1
189    END IF
190    IF(.not.associated(CURSOR%next)) THEN
191#if defined(__DEBUG)
192       CALL infomsg('buiol_close_unit', 'cannot find unit to close',1)
193#endif
194       ierr = 2
195    END IF
196    !
197    ! replace this unit with the next, but keep track of it
198    AUX => CURSOR%next
199    CURSOR%next => AUX%next ! <--- works even if %next is null()
200    !
201    ! destroy the closed unit
202    CALL dealloc_buffer(AUX)
203    ierr = 0
204    !
205    RETURN
206    !
207  END FUNCTION buiol_close_unit
208  ! \/o\________\\\_________________________________________/^>
209  FUNCTION buiol_check_unit(unit) RESULT(recl)
210    IMPLICIT NONE
211    INTEGER,INTENT(in) :: unit
212    INTEGER :: recl
213    TYPE(index_of_list),POINTER :: CURSOR
214    !
215    ! find the unit
216    CURSOR => find_unit(unit)
217    IF(.not.associated(CURSOR)) THEN
218      recl = -1
219    ELSE
220      recl = CURSOR%recl
221    ENDIF
222    !
223    RETURN
224    !
225  END FUNCTION buiol_check_unit
226  ! \/o\________\\\_________________________________________/^>
227  FUNCTION buiol_get_ext(unit) RESULT(extension)
228    IMPLICIT NONE
229    INTEGER,INTENT(in) :: unit
230    CHARACTER(LEN=256) :: extension
231    TYPE(index_of_list),POINTER :: CURSOR
232    !
233    ! find the unit
234    CURSOR => find_unit(unit)
235    IF(.not.associated(CURSOR)) THEN
236      extension = ' '
237    ELSE
238      extension = CURSOR%extension
239    ENDIF
240    !
241    RETURN
242    !
243  END FUNCTION buiol_get_ext
244  ! \/o\________\\\_________________________________________/^>
245  FUNCTION buiol_get_dir(unit) RESULT(save_dir)
246    IMPLICIT NONE
247    INTEGER,INTENT(in) :: unit
248    CHARACTER(LEN=256) :: save_dir
249    TYPE(index_of_list),POINTER :: CURSOR
250    !
251    ! find the unit
252    CURSOR => find_unit(unit)
253    IF(.not.associated(CURSOR)) THEN
254      save_dir = ' '
255    ELSE
256      save_dir = CURSOR%save_dir
257    ENDIF
258    !
259    RETURN
260    !
261  END FUNCTION buiol_get_dir
262  ! \/o\______\\_______________________________________/^>
263  SUBROUTINE increase_nrec(nrec_new, CURSOR)
264    IMPLICIT NONE
265    INTEGER,INTENT(in) :: nrec_new
266    TYPE(index_of_list),POINTER,INTENT(inout) :: CURSOR
267    !
268    INTEGER :: i
269    TYPE(data_in_the_list),POINTER :: new(:), old(:)
270    !
271    IF(nrec_new < CURSOR%nrec) CALL errore('increase_nrec', 'wrong new nrec',1)
272    !
273    ! create a new index with more space
274    ALLOCATE(new(nrec_new))
275    !
276    ! associate the data to the new unit
277    old => CURSOR%index
278    DO i = 1, CURSOR%nrec
279      new(i)%data => old(i)%data ! <-- also the null() are copied
280    ENDDO
281    CURSOR%index => new
282    !
283    ! clean the old index
284    CURSOR%nrec = nrec_new
285    DEALLOCATE(old)
286    !
287    RETURN
288    !
289  END SUBROUTINE increase_nrec
290  ! \/o\________\\\_________________________________________/^>
291  FUNCTION buiol_write_record(unit, recl, nrec, DATA) RESULT (ierr)
292    IMPLICIT NONE
293    INTEGER,INTENT(in) :: unit, recl, nrec
294    COMPLEX(dp),INTENT(in) :: DATA(recl)
295    INTEGER :: ierr
296    !
297    TYPE(index_of_list),POINTER :: CURSOR
298    INTEGER :: nrec_new
299    !
300    ! find the unit, if it exists
301    CURSOR => find_unit(unit)
302    IF(.not.associated(CURSOR)) THEN
303#if defined(__DEBUG)
304       CALL infomsg('buiol_write_record', 'cannot write: unit not opened')
305#endif
306       ierr = 1
307       RETURN
308    END IF
309    IF(CURSOR%recl/=recl) THEN
310#if defined(__DEBUG)
311       CALL infomsg('buiol_write_record', 'cannot write: wrong recl')
312#endif
313       ierr = 2
314       RETURN
315    END IF
316    !
317    ! increase size of index, if necessary
318    IF(CURSOR%nrec<nrec) THEN
319      nrec_new = NINT(MAX(fact0*DBLE(CURSOR%nrec),fact1*DBLE(nrec)))
320      CALL increase_nrec(nrec_new, CURSOR )
321    ENDIF
322    !
323    IF(.not.associated(CURSOR%index(nrec)%data)) &
324      ALLOCATE( CURSOR%index(nrec)%data(recl) )
325    !
326    ! copy the data
327    CURSOR%index(nrec)%data = DATA
328    ierr = 0
329    RETURN
330    !
331  END FUNCTION
332  ! \/o\________\\\_________________________________________/^>
333  FUNCTION buiol_read_record(unit, recl, nrec, DATA) RESULT (ierr)
334    IMPLICIT NONE
335    INTEGER,INTENT(in) :: unit, recl, nrec
336    COMPLEX(dp),INTENT(out) :: DATA(recl)
337    INTEGER :: ierr
338    !
339    TYPE(index_of_list),POINTER :: CURSOR
340    !
341    ! sanity checks
342    CURSOR => find_unit(unit)
343    IF(.not.associated(CURSOR)) THEN
344#if defined(__DEBUG)
345       CALL infomsg('buiol_read_record', 'cannot read: unit not opened')
346#endif
347       ierr = 1
348       RETURN
349    END IF
350    IF(CURSOR%recl/=recl) THEN
351#if defined(__DEBUG)
352        CALL infomsg('buiol_read_record', 'cannot read: wrong recl')
353#endif
354       ierr = 1
355       RETURN
356    END IF
357    IF(CURSOR%nrec<nrec) THEN
358#if defined(__DEBUG)
359       CALL infomsg('buiol_read_record', 'cannot read: wrong nrec')
360#endif
361       ierr =-1
362       RETURN
363    END IF
364    IF(.not.associated(CURSOR%index(nrec)%data)) THEN
365#if defined(__DEBUG)
366       CALL infomsg('buiol_read_record', 'cannot read: virgin nrec')
367#endif
368       ierr =-1
369       RETURN
370    END IF
371    !
372    DATA = CURSOR%index(nrec)%data
373    ierr = 0
374    RETURN
375    !
376  END FUNCTION buiol_read_record
377  ! \/o\________\\\_________________________________________/^>
378  SUBROUTINE buiol_report_unit(unit)
379    IMPLICIT NONE
380    INTEGER,INTENT(in) :: unit
381    !
382    TYPE(index_of_list),POINTER :: CURSOR
383    ! sanity checks
384    CURSOR => find_unit(unit)
385#if defined(__DEBUG)
386    IF(.not.associated(CURSOR)) CALL errore('buiol_report_unit', 'cannot report: unit not opened',1)
387#endif
388    CALL buiol_report_buffer(CURSOR)
389    RETURN
390    !
391  END SUBROUTINE buiol_report_unit
392  ! \/o\________\\\_________________________________________/^>
393  SUBROUTINE buiol_report_buffer(CURSOR, mem)
394    IMPLICIT NONE
395    TYPE(index_of_list),INTENT(in) :: CURSOR
396    INTEGER,OPTIONAL,INTENT(inout) :: mem
397    !
398    INTEGER :: i, ndata, bytes
399    !
400    ndata = 0
401    DO i = 1,CURSOR%nrec
402      IF(associated(CURSOR%index(i)%data)) ndata=ndata+1
403    ENDDO
404    !
405    bytes = ndata*CURSOR%recl*size0
406    WRITE(*,'(2x,a,2(a,i8),(a,2i8),(a,i12))') "[BUIOL] ", &
407             "unit:", CURSOR%unit, &
408        "   | recl:", CURSOR%recl, &
409        "   | nrec (idx/alloc):", CURSOR%nrec, ndata, &
410        "   | memory used:", bytes
411    IF(present(mem)) mem = mem+bytes
412    RETURN
413    !
414  END SUBROUTINE buiol_report_buffer
415  ! \/o\________\\\_________________________________________/^>
416  FUNCTION find_unit(unit) RESULT(CURSOR)
417    IMPLICIT NONE
418    INTEGER,INTENT(in) :: unit
419    TYPE(index_of_list),POINTER :: CURSOR
420    !
421    IF (.not.is_init_buiol) CALL errore('find_unit', 'You must init before find_unit',1)
422    !
423    CURSOR => ENTRY
424    DO WHILE (associated(CURSOR%NEXT))
425      CURSOR => CURSOR%NEXT
426      IF(CURSOR%unit == unit) RETURN ! <-- found
427    ENDDO
428    CURSOR => null() ! <------------------ not found
429    RETURN
430  END FUNCTION find_unit
431  ! \/o\________\\\_________________________________________/^>
432  FUNCTION find_prev_unit(unit) RESULT(CURSOR)
433    IMPLICIT NONE
434    INTEGER,INTENT(in) :: unit
435    TYPE(index_of_list),POINTER :: CURSOR
436    !
437    IF (.not.is_init_buiol) CALL errore('find_prev_unit', 'You must init before find_prev_unit',1)
438    !
439    CURSOR => ENTRY
440    DO WHILE (associated(CURSOR%NEXT))
441      IF(CURSOR%next%unit == unit) RETURN ! <-- found
442      CURSOR => CURSOR%NEXT
443    ENDDO
444    CURSOR => null() ! <------------------ not found
445    RETURN
446  END FUNCTION find_prev_unit
447  ! \/o\________\\\_________________________________________/^>
448  FUNCTION alloc_buffer(unit, recl, nrec, extension, save_dir)
449    IMPLICIT NONE
450    INTEGER,INTENT(in) :: unit, recl, nrec
451    CHARACTER(LEN=*), INTENT(in) :: extension, save_dir
452    TYPE(index_of_list),POINTER :: alloc_buffer
453    TYPE(index_of_list),POINTER :: CURSOR
454    !
455    ALLOCATE(CURSOR)
456    CURSOR%unit = unit
457    CURSOR%recl = recl
458    CURSOR%nrec = nrec0
459    CURSOR%extension = extension
460    CURSOR%save_dir  = save_dir
461    NULLIFY(CURSOR%next)
462    ALLOCATE(CURSOR%index(CURSOR%nrec))
463    !
464    alloc_buffer => CURSOR
465    RETURN
466  END FUNCTION alloc_buffer
467  ! \/o\________\\\_________________________________________/^>
468  SUBROUTINE dealloc_buffer(CURSOR)
469    IMPLICIT NONE
470    TYPE(index_of_list),POINTER,INTENT(inout) :: CURSOR
471    !
472    INTEGER :: i
473    DO i = 1,CURSOR%nrec
474      IF(associated(CURSOR%index(i)%data)) THEN
475         DEALLOCATE(CURSOR%index(i)%data)
476         NULLIFY(CURSOR%index(i)%data)
477      ENDIF
478    ENDDO
479    DEALLOCATE(CURSOR%index)
480    CURSOR%unit = -1
481    CURSOR%recl = -1
482    CURSOR%nrec = -1
483    DEALLOCATE(CURSOR)
484    NULLIFY(CURSOR)
485    !
486  END SUBROUTINE dealloc_buffer
487  ! \/o\________\\\_________________________________________/^>
488END MODULE buiol
489! <<^V^\\=========================================//-//-//========//O\\//
490!
491MODULE buffers
492  !
493  !! It includes QE interfaces to BUIOL module.
494  !
495  USE kinds, ONLY: DP
496  USE buiol, ONLY: init_buiol, buiol_open_unit, buiol_close_unit, &
497                   buiol_check_unit, buiol_get_ext, buiol_get_dir, &
498                   buiol_read_record, buiol_write_record, is_init_buiol
499  !
500  IMPLICIT NONE
501  !
502  ! QE interfaces to BUIOL module
503  !
504  PUBLIC :: open_buffer, get_buffer, save_buffer, close_buffer
505  !
506  PRIVATE
507  INTEGER:: nunits = 0
508  !
509CONTAINS
510  !
511  !---------------------------------------------------------------------------------
512  SUBROUTINE open_buffer( unit, extension, nword, io_level, exst, exst_file, direc )
513    !-------------------------------------------------------------------------------
514    !! io_level>0: connect unit "unit" to file "wfc_dir"/"prefix"."extension"
515    !! (or "direc"/"prefix"."extension" if optional variable direc specified)
516    !! for direct I/O access, with record length = nword complex numbers;
517    !! on output, exst=T(F) if the file (does not) exists.
518    !
519    !! io_level=0: open a buffer for storing records of length nword complex
520    !! numbers; store in memory file-related variables for later usage.
521    !! on output, exst=T(F) if the buffer is already allocated.
522    !
523    !! On output, optional variable exst_file=T(F) if file is present (absent).
524    !
525    USE io_files,  ONLY : diropn, wfc_dir
526    !
527    IMPLICIT NONE
528    !
529    CHARACTER(LEN=*), INTENT(IN) :: extension
530    CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: direc
531    INTEGER, INTENT(IN) :: unit, nword, io_level
532    LOGICAL, INTENT(OUT) :: exst
533    LOGICAL, INTENT(OUT), OPTIONAL :: exst_file
534    CHARACTER(LEN=256) :: save_dir
535    !
536    INTEGER :: ierr
537    !
538    !   not-so-elegant way to initialize the linked chain with units
539    !
540    IF ( nunits == 0 ) CALL init_buiol()
541    !
542    IF (extension == ' ') &
543       CALL errore( 'open_buffer', 'filename extension not given', 1 )
544    !
545    IF (PRESENT(direc)) THEN
546       save_dir = TRIM(direc)
547    ELSE
548       save_dir = TRIM(wfc_dir)
549    ENDIF
550    !
551    IF ( io_level <= 0 ) THEN
552       CALL diropn( unit, extension, -1, exst, save_dir )
553       IF (PRESENT(exst_file)) exst_file=exst
554       ierr = buiol_open_unit( unit, nword, extension, save_dir )
555       IF ( ierr > 0 ) CALL errore( 'open_buffer', ' cannot open unit', 2 )
556       exst = ( ierr == -1 )
557       IF (exst) THEN
558          CALL infomsg( 'open_buffer', 'unit already opened' )
559          nunits = nunits - 1
560       END IF
561    ELSE
562       CALL diropn( unit, extension, 2*nword, exst, save_dir )
563       IF (PRESENT(exst_file)) exst_file=exst
564    ENDIF
565    nunits = nunits + 1
566    !
567    RETURN
568    !
569  END SUBROUTINE open_buffer
570  !
571  !
572  !----------------------------------------------------------------------------
573  SUBROUTINE save_buffer( vect, nword, unit, nrec )
574    !--------------------------------------------------------------------------
575    !! Copy vect(1:nword) into the "nrec"-th record of a previously
576    !! allocated buffer / opened direct-access file, depending upon
577    !! how "open_buffer" was called.
578    !
579    IMPLICIT NONE
580    !
581    INTEGER, INTENT(IN) :: nword, unit, nrec
582    COMPLEX(DP), INTENT(INOUT) :: vect(nword)
583    INTEGER :: ierr
584    !
585    ierr = buiol_check_unit( unit )
586    IF( ierr > 0 ) THEN
587       ierr = buiol_write_record( unit, nword, nrec, vect )
588       IF ( ierr > 0 ) &
589           CALL errore( 'save_buffer', 'cannot write record', unit )
590#if defined(__DEBUG)
591       print *, 'save_buffer: record', nrec, ' written to unit', unit
592#endif
593    ELSE
594       CALL davcio( vect, 2*nword, unit, nrec, +1 )
595    ENDIF
596    !
597  END SUBROUTINE save_buffer
598  !
599  !----------------------------------------------------------------------------
600  SUBROUTINE get_buffer( vect, nword, unit, nrec )
601    !!---------------------------------------------------------------------------
602    !! Copy vect(1:nword) from the "nrec"-th record of a previously
603    !! allocated buffer / opened direct-access file, depending upon
604    !! how "open_buffer" was called. If buffer access was chosen
605    !! but buffer is not allocated, open the file, read from file.
606    !
607    USE io_files, ONLY : diropn
608    !
609    IMPLICIT NONE
610    !
611    INTEGER, INTENT(IN) :: nword, unit, nrec
612    COMPLEX(DP), INTENT(OUT) :: vect(nword)
613    CHARACTER(LEN=256) :: extension, save_dir
614    INTEGER :: ierr
615    LOGICAL :: opnd
616    !
617    ierr = buiol_check_unit( unit )
618    IF( ierr > 0 ) THEN
619       ierr = buiol_read_record( unit, nword, nrec, vect )
620#if defined(__DEBUG)
621       PRINT *, 'get_buffer: record', nrec, ' read from unit', unit
622#endif
623       IF ( ierr < 0 ) THEN
624          ! record not found: open file if not opened, read from it...
625          INQUIRE( UNIT = unit, OPENED = opnd )
626          IF ( .NOT. opnd ) THEN
627             extension = buiol_get_ext(unit)
628             save_dir  = buiol_get_dir(unit)
629             CALL diropn( unit, extension, 2*nword, opnd, save_dir )
630          END IF
631          CALL davcio( vect, 2*nword, unit, nrec, -1 )
632          ! ... and save to memory
633          ierr =  buiol_write_record( unit, nword, nrec, vect )
634          IF ( ierr /= 0 ) CALL errore( 'get_buffer', &
635                                  'cannot store record in memory', unit )
636#if defined(__DEBUG)
637          PRINT *, 'get_buffer: record', nrec, ' read from file', unit
638#endif
639       ENDIF
640#if defined(__DEBUG)
641       PRINT *, 'get_buffer: record', nrec, ' read from unit', unit
642#endif
643    ELSE
644       CALL davcio( vect, 2*nword, unit, nrec, -1 )
645    ENDIF
646    !
647  END SUBROUTINE get_buffer
648  !
649  !------------------------------------------------------------
650  SUBROUTINE close_buffer( unit, status )
651    !----------------------------------------------------------
652    !! Close unit with status "status" ('keep' or 'delete')
653    !! deallocate related buffer if any; if "status='keep'"
654    !! save it to file (opening it if not already opened).
655    !! Does not complain if closing an already closed unit.
656    !
657    USE io_files, ONLY : diropn
658    !
659    IMPLICIT NONE
660    !
661    INTEGER, INTENT(IN) :: unit
662    CHARACTER(LEN=*), INTENT(IN) :: status
663    !
664    COMPLEX(dp), ALLOCATABLE :: vect(:)
665    CHARACTER(LEN=256) :: extension, save_dir
666    INTEGER :: n, ierr, nrec, nword
667    LOGICAL :: opnd
668    !
669    IF ( .NOT. is_init_buiol ) RETURN
670    nword = buiol_check_unit( unit )
671    !
672    IF( nword > 0 ) THEN
673       ! data is in memory buffer
674       IF ( status == 'keep' .OR. status == 'KEEP' ) THEN
675          ! open file if not previously opened
676          INQUIRE( UNIT = unit, OPENED = opnd )
677          IF ( .NOT. opnd ) THEN
678             extension = buiol_get_ext (unit)
679             save_dir  = buiol_get_dir (unit)
680             CALL diropn( unit, extension, 2*nword, opnd, save_dir )
681          ENDIF
682          ALLOCATE( vect(nword) )
683          n = 1
684  10      CONTINUE
685             ierr = buiol_read_record( unit, nword, n, vect )
686             IF ( ierr /= 0 ) GO TO 20
687             CALL davcio( vect, 2*nword, unit, n, +1 )
688             n = n+1
689          GO TO 10
690  20      DEALLOCATE( vect )
691       ENDIF
692       ierr = buiol_close_unit( unit )
693       if ( ierr < 0 ) &
694            CALL errore( 'close_buffer', 'error closing', ABS(unit) )
695#if defined(__DEBUG)
696       PRINT *, 'close_buffer: unit ',unit, 'closed'
697#endif
698    ENDIF
699    INQUIRE( UNIT = unit, OPENED = opnd )
700    IF ( opnd ) CLOSE( UNIT = unit, STATUS = status )
701    nunits = nunits - 1
702    !
703  END SUBROUTINE close_buffer
704  !
705  ! end interface for old "buffers" module
706  !
707END MODULE buffers
708