mirror of https://gitlab.com/QEF/q-e.git
194 lines
7.1 KiB
Fortran
194 lines
7.1 KiB
Fortran
! Copyright (C) 2008 Quantum ESPRESSO group
|
|
! This file is distributed under the terms of the
|
|
! GNU General Public License. See the file `License'
|
|
! in the root directory of the present distribution,
|
|
! or http://www.gnu.org/copyleft/gpl.txt .
|
|
!
|
|
!=----------------------------------------------------------------------------=!
|
|
MODULE upf_module
|
|
!=----------------------------------------------------------------------------=!
|
|
!! author: Unknown
|
|
!! this module handles reading of unified pseudopotential format (UPF)
|
|
!! in either v1 or v2 of schema format.
|
|
!! @Note
|
|
!! 14/11/17 Pietro Delugas: new revision passed from iotk to FoX lib, added support
|
|
!! new schema for UPF files
|
|
!
|
|
!
|
|
! A macro to trim both from left and right
|
|
#define TRIM(a) trim(adjustl(a))
|
|
!
|
|
USE kinds, ONLY: DP
|
|
USE pseudo_types, ONLY: pseudo_upf, deallocate_pseudo_upf
|
|
!
|
|
IMPLICIT NONE
|
|
PUBLIC
|
|
!PRIVATE
|
|
!PUBLIC :: read_upf, pseudo_upf, deallocate_pseudo_upf
|
|
!
|
|
CONTAINS
|
|
|
|
!------------------------------------------------+
|
|
SUBROUTINE read_upf(upf, grid, ierr, unit, filename, xml_only) !
|
|
!---------------------------------------------+
|
|
!! Reads pseudopotential in UPF format (either v.1 or v.2 or upf_schema).
|
|
!! Derived type variable *upf* and optionally *grid* store in output the data read
|
|
!! from file.
|
|
!! If the unit number is provided with the *unit* argument only UPF v1 format
|
|
!! is checked, the pseudo file must be opened and closed outside the routine.
|
|
!! Otherwise the *filename* argument must be given, file is opened and closed inside
|
|
!! the routine and all formats will be checked. The logical *xml_only* optional
|
|
!! argument may be given with true value to prevent the routine to check v1 format.
|
|
!! @Note last revision: 14-11-2017
|
|
!
|
|
USE radial_grids, ONLY: radial_grid_type, deallocate_radial_grid
|
|
USE read_upf_v1_module,ONLY: read_upf_v1
|
|
USE read_upf_v2_module,ONLY: read_upf_v2
|
|
USE read_upf_schema_module,ONLY: read_upf_schema
|
|
USE mp, ONLY: mp_barrier
|
|
USE mp_world, ONLY: world_comm
|
|
USE io_global, ONLY: ionode
|
|
USE io_files, ONLY: tmp_dir
|
|
USE FoX_DOM, ONLY: Node, domException, parseFile, getFirstChild, getExceptionCode,&
|
|
getTagName
|
|
USE wrappers, ONLY: f_remove
|
|
IMPLICIT NONE
|
|
INTEGER,INTENT(IN), OPTIONAL :: unit
|
|
!! i/o unit:
|
|
CHARACTER(len=*),INTENT(IN),OPTIONAL :: filename
|
|
!! i/o filename
|
|
LOGICAL,INTENT(IN), OPTIONAL :: xml_only
|
|
!! if present and true the program will parse only xml documents neglecting version 1 upf format
|
|
TYPE(pseudo_upf),INTENT(INOUT) :: upf
|
|
!! the derived type storing the pseudo data
|
|
TYPE(radial_grid_type),OPTIONAL,INTENT(INOUT),TARGET :: grid
|
|
!! derived type where is possible to store data on the radial mesh
|
|
INTEGER,INTENT(OUT) :: ierr
|
|
!
|
|
LOGICAL :: xml_only_ = .FALSE.
|
|
TYPE(Node),POINTER :: u,doc
|
|
INTEGER :: u_temp,& ! i/o unit in case of upf v1
|
|
iun, ferr
|
|
TYPE(DOMException) :: ex
|
|
INTEGER, EXTERNAL :: find_free_unit
|
|
|
|
IF (PRESENT(xml_only) ) xml_only_ = xml_only
|
|
ierr = 0
|
|
|
|
IF ( present ( unit ) ) THEN
|
|
REWIND (unit)
|
|
CALL deallocate_pseudo_upf(upf)
|
|
CALL deallocate_radial_grid( grid )
|
|
CALL read_upf_v1 (unit, upf, grid, ierr )
|
|
IF (ierr == 0 ) ierr = -1
|
|
!
|
|
RETURN
|
|
!
|
|
ELSE IF (PRESENT(filename) ) THEN
|
|
doc => parseFile(TRIM(filename), EX = ex )
|
|
ierr = getExceptionCode( ex )
|
|
IF ( ierr == 81 ) THEN
|
|
IF ( ionode ) CALL make_emended_upf_copy( TRIM(filename), TRIM(tmp_dir)//'tmp.UPF')
|
|
CALL mp_barrier ( world_comm)
|
|
doc => parseFile(TRIM(tmp_dir)//'tmp.UPF', EX = ex )
|
|
ierr = getExceptionCode( ex )
|
|
CALL mp_barrier(world_comm)
|
|
IF (ionode) ferr = f_remove(TRIM(tmp_dir)//'tmp.UPF')
|
|
END IF
|
|
IF ( ierr == 0 ) THEN
|
|
u => getFirstChild(doc)
|
|
SELECT CASE (TRIM(getTagname(u)))
|
|
CASE ('UPF')
|
|
CALL read_upf_v2( u, upf, grid, ierr )
|
|
CASE ('pseudo')
|
|
CALL read_upf_schema( u, upf, grid, ierr)
|
|
IF ( ierr == 0 ) ierr = -2
|
|
CASE default
|
|
ierr = 1
|
|
CALL errore('read_upf', 'unrecognized xml format '//TRIM(getTagName(u)),ierr)
|
|
END SELECT
|
|
IF ( ierr > 0 ) CALL errore( 'read_upf', 'File is Incomplete or wrong: '//TRIM(filename), ierr)
|
|
!
|
|
RETURN
|
|
!
|
|
ELSE IF ( ierr > 0 ) THEN
|
|
!
|
|
IF ( .NOT. xml_only ) THEN
|
|
u_temp = find_free_unit()
|
|
open (unit = u_temp, file = TRIM(filename), status = 'old', form = 'formatted', iostat = ierr)
|
|
CALL deallocate_pseudo_upf( upf )
|
|
CALL deallocate_radial_grid( grid )
|
|
CALL read_upf_v1( u_temp, upf, grid, ierr )
|
|
IF ( ierr == 0 ) ierr = -1
|
|
CLOSE ( u_temp)
|
|
END IF
|
|
!
|
|
RETURN
|
|
!
|
|
END IF
|
|
ELSE
|
|
CALL errore('read_upf',&
|
|
'Nothing to read !!! you must provide one of filename or unit optional arguments',1)
|
|
END IF
|
|
|
|
|
|
END SUBROUTINE read_upf
|
|
|
|
SUBROUTINE make_emended_upf_copy( filename, tempname)
|
|
IMPLICIT NONE
|
|
CHARACTER(LEN=*),INTENT(IN) :: filename, tempname
|
|
!
|
|
INTEGER :: iun_source, iun_dest, ierr
|
|
INTEGER,EXTERNAL :: find_free_unit
|
|
LOGICAL :: icopy = .FALSE.
|
|
CHARACTER(LEN=256) :: line
|
|
!
|
|
iun_source = find_free_unit()
|
|
OPEN (UNIT = iun_source, FILE = TRIM(filename), STATUS = 'old', ACTION = 'read', FORM='formatted')
|
|
iun_dest = find_free_unit()
|
|
OPEN (UNIT = iun_dest, FILE = TRIM(tempname), STATUS = 'unknown', ACTION = 'write', FORM = 'formatted')
|
|
copy_loop: DO
|
|
!
|
|
READ(iun_source, "(a256)", IOSTAT = ierr ) line
|
|
IF (ierr < 0 ) EXIT copy_loop
|
|
!
|
|
IF ( INDEX(line,"<UPF") /= 0 ) icopy = .TRUE.
|
|
IF ( .NOT. icopy ) CYCLE copy_loop
|
|
!
|
|
WRITE ( iun_dest,"(a)") TRIM(check( line ))
|
|
!
|
|
IF ( INDEX( line, "</UPF") /= 0 ) EXIT copy_loop
|
|
END DO copy_loop
|
|
!
|
|
CLOSE ( iun_source)
|
|
CLOSE ( iun_dest )
|
|
CONTAINS
|
|
FUNCTION check(in) RESULT (out)
|
|
CHARACTER (LEN = *) :: in
|
|
#if defined(__PGI)
|
|
INTEGER, PARAMETER :: length = 255
|
|
CHARACTER(LEN=length ) :: out
|
|
#else
|
|
CHARACTER(LEN = LEN(in) ) :: out
|
|
#endif
|
|
INTEGER :: i, o, disp
|
|
!
|
|
disp = 0
|
|
DO i = 1, LEN(in)
|
|
o = i + disp
|
|
IF ( o > LEN (in) ) EXIT
|
|
IF (in(i:i) == '&') THEN
|
|
out(o:o+4) = '&'
|
|
disp = disp+4
|
|
ELSE
|
|
out(o:o) = in (i:i)
|
|
END IF
|
|
END DO
|
|
END FUNCTION check
|
|
END SUBROUTINE make_emended_upf_copy
|
|
!=----------------------------------------------------------------------------=!
|
|
END MODULE upf_module
|
|
!=----------------------------------------------------------------------------=!
|
|
#undef TRIM
|
|
|