quantum-espresso/upflib/upfconv.f90

434 lines
14 KiB
Fortran

!
! Copyright (C) 2020-2023 Quantum ESPRESSO Foundation
! 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 .
!
! Original code "upf2casino" from Simon Binnie, 2011
!---------------------------------------------------------------------
PROGRAM upfconv
!---------------------------------------------------------------------
!
! Pseudopotential conversion utility, can
! - convert from:
! UPF v.1 or v.2 containing "&" characters,
! norm-conserving PPs in .psml format (experimental),
! old PWSCF norm-conserving and Ultrasoft formats,
! Vanderbilt ultrasoft PP generation code format,
! CPMD format (TYPE=NUMERIC, LOGARITHMIC, CAR, GOEDECKER)
! to:
! UPF v.2, or new UPF with schema (xml)
! - extract and write to separate files:
! wavefunctions
! projectors ("beta" functions)
! potential
! if available, core wavefunctions from GIPAW section
! - convert to CASINO tabulated format (obsolete?)
!
USE pseudo_types, ONLY : pseudo_upf, reset_upf, deallocate_pseudo_upf
USE casino_pp, ONLY : conv_upf2casino, write_casino_tab
USE write_upf_new,ONLY : write_upf
!
IMPLICIT NONE
TYPE(pseudo_upf) :: upf
INTEGER :: prefix_len, nargs, i,j, ierr
CHARACTER(LEN=256) :: filein, fileout
CHARACTER(LEN=2) :: conversion=' '
CHARACTER(LEN=5) :: schema='none'
!
nargs = command_argument_count()
IF ( nargs < 1 .OR. nargs > 2 ) THEN
WRITE(*,*) 'Usage: upfconv -c|-u|-x|-e "pseudopotential file"'
WRITE(*,*) ' upfconv -h'
STOP
END IF
!
CALL get_command_argument(1, conversion)
!
IF ( conversion == "-h" ) THEN
WRITE(*,*) 'Converts a pseudopotential file to either upf v.2, xml or CASINO formats.'
WRITE(*,*) 'Usage: upfconv -c|-u|-x|-e "pseudopotential file"'
WRITE(*,*) 'Options: -c convert to CASINO format. MAY OR MAY NOT WORK (LIKELY IT DOES NOT)'
WRITE(*,*) 'Options: -c Make sure that the local channel chosen in the CASINO pp file'
WRITE(*,*) ' is what you expect'
WRITE(*,*) ' -u convert to upf v.2 format'
WRITE(*,*) ' -x convert to xml format'
WRITE(*,*) ' -e extract GIPAW core wavefunctions if available,'
WRITE(*,*) ' wavefunctions, projectors, potential'
WRITE(*,*) ' -p write Vloc, betas in plottable format to file,'
WRITE(*,*) ' both on the radial grid and Bessel-transformed'
WRITE(*,*) ' -h print this message'
WRITE(*,*) 'The pseudopotential file can be any of the following:'
WRITE(*,*) '*.upf or *.UPF upf (v.1 or 2)'
WRITE(*,*) '*.vdb or *.van Vanderbilt US pseudopotential code format'
WRITE(*,*) '*.rrkj3 or *.RRKJ3 Old US pseudopotential format of atomic code'
WRITE(*,*) '*.cpi or *.fhi FHI/abinit formats'
WRITE(*,*) '*.gth DOES NOT WORK Goedecker-Teter-Hutter NC pseudo format'
WRITE(*,*) '*.cpmd CPMD format (TYPE=NUMERIC, LOGARITHMIC, CAR, GOEDECKER)'
WRITE(*,*) 'none of the above Old PWSCF norm-conserving format'
STOP
END IF
!
CALL get_command_argument(2, filein)
IF ( INDEX(TRIM(filein),'.UPF' ) > 0) THEN
prefix_len = INDEX(TRIM(filein),'.UPF') - 1
ELSE IF (INDEX(TRIM(filein),'.upf') > 0 ) THEN
prefix_len = INDEX(TRIM(filein),'.upf') - 1
ELSE IF (INDEX(TRIM(filein),'.psml') > 0 ) THEN
prefix_len = INDEX(TRIM(filein),'.psml') - 1
ELSE
prefix_len = LEN_TRIM(filein)
ENDIF
IF ( conversion == "-c" ) THEN
fileout = filein(1:prefix_len) //'.out'
WRITE(*,*) 'UPF to CASINO conversion'
WRITE(*,*) 'All pseudopotential files generated should be &
&thoroughly checked.'
WRITE(*,*) 'In particular make sure the local channel chosen&
& in the CASINO pp file is what you expected.'
ELSE IF ( conversion == "-x" ) THEN
fileout = filein(1:prefix_len) //'.xml'
WRITE(*,*) 'conversion to xml format'
ELSE IF ( conversion == "-u" ) THEN
fileout = filein(1:prefix_len) //'.UPF2'
WRITE(*,*) 'conversion to UPF v.2'
ELSE IF ( conversion == "-e" .or. conversion == "-p" ) THEN
fileout = filein(1:prefix_len)
ELSE
WRITE(*,*) 'Invalid option ' // conversion
WRITE(*,*) 'Usage: upfconv -c|-u|-x|-e|-p "pseudopotential file"'
STOP
END IF
IF ( prefix_len < 1 ) THEN
WRITE(*,*) 'Empty file, stopping'
STOP
END IF
WRITE(*,*) 'input file: ' // trim(filein), ', output file: ' // trim(fileout)
!
CALL reset_upf( upf )
!
CALL read_ps_new ( filein, upf, .false., ierr )
IF ( ierr > 0 ) THEN
WRITE(*,*) 'Cannot read file, stopping'
STOP
END IF
IF ( conversion == "-c" ) THEN
!
CALL conv_upf2casino(upf)
CALL write_casino_tab(upf, fileout)
!
ELSE IF ( conversion == "-e" ) THEN
!
CALL write_files ( upf, fileout )
!
ELSE IF ( conversion == "-p" ) THEN
!
CALL plot_ps_loc ( upf, fileout )
CALL plot_ps_beta( upf, fileout )
!
ELSE
!
CALL conv_upf2xml(upf)
IF ( conversion == "-x" ) THEN
schema = 'qe_pp'
ELSE IF ( conversion == "-u" ) THEN
schema = 'v2'
END IF
CALL write_upf (FILENAME = fileout, UPF = upf, SCHEMA = schema)
!
ENDIF
!
CALL deallocate_pseudo_upf (upf)
!
STOP
END PROGRAM upfconv
SUBROUTINE write_files( upf, fileout )
!
USE upf_const, ONLY : fpi
USE pseudo_types, ONLY : pseudo_upf
!
IMPLICIT NONE
TYPE(pseudo_upf), INTENT(inout) :: upf
CHARACTER (LEN=*) :: fileout
INTEGER :: i, j, n, ios, iunps
!
iunps=999
!
OPEN ( UNIT=iunps, FILE=TRIM(fileout)//'.wfc', STATUS='unknown', &
FORM='formatted', IOSTAT=ios)
IF ( ios /= 0 ) THEN
WRITE(*,"('cannot write wfc file, stopping')" )
STOP
END IF
WRITE(*,"('writing: ',a)") TRIM(fileout)//'.wfc'
DO n=1,upf%mesh
WRITE(iunps,'(30f12.6)') upf%r(n), (upf%chi(n,j), j=1,upf%nwfc)
ENDDO
CLOSE(iunps)
OPEN ( UNIT=iunps, FILE=TRIM(fileout)//'.beta', STATUS='unknown', &
FORM='formatted', IOSTAT=ios)
IF ( ios /= 0 ) THEN
WRITE(*,"('cannot write beta file, stopping')" )
STOP
END IF
WRITE(*,"('writing: ',a)") TRIM(fileout)//'.beta'
DO n=1,upf%mesh
WRITE(iunps,'(30f12.6)') upf%r(n), (upf%beta(n,j), j=1,upf%nbeta)
ENDDO
CLOSE(iunps)
OPEN ( UNIT=iunps, FILE=TRIM(fileout)//'.pot', STATUS='unknown', &
FORM='formatted', IOSTAT=ios)
IF ( ios /= 0 ) THEN
WRITE(*,"('cannot write beta file, stopping')" )
STOP
END IF
WRITE(*,"('writing: ',a)") TRIM(fileout)//'.pot'
DO n=1,upf%mesh
WRITE(iunps,'(4f12.6)') upf%r(n), upf%vloc(n), &
upf%rho_at(n), upf%rho_atc(n)*fpi*upf%r(n)**2
ENDDO
CLOSE(iunps)
IF(upf%has_gipaw) THEN
DO j = 1, upf%gipaw_ncore_orbitals
OPEN(unit=iunps, file = TRIM(fileout)//TRIM(upf%gipaw_core_orbital_el(j))//".out")
WRITE(*,"('writing: ',a)") TRIM(fileout)//TRIM(upf%gipaw_core_orbital_el(j))//".out"
DO n = 1, upf%mesh
WRITE(iunps,*) upf%r(n), upf%gipaw_core_orbital(n,j)
WRITE(iunps+1,*) upf%r(n), upf%gipaw_core_orbital(n,j)
ENDDO
CLOSE(iunps)
ENDDO
! write the same, but all in one file for xspectra
OPEN(unit=iunps, file = TRIM(fileout)//".xspectra")
WRITE(*,"('writing: ',a)") TRIM(fileout)//".xspectra"
WRITE(iunps,"('# mesh size',i6,'; core orbitals:',99(a3,', '))") upf%mesh, upf%gipaw_core_orbital_el(:)
DO j = 1, upf%gipaw_ncore_orbitals
DO n = 1, upf%mesh
WRITE(iunps,*) upf%r(n), upf%gipaw_core_orbital(n,j)
ENDDO
ENDDO
CLOSE(iunps)
ELSE
WRITE(*,*) "Core charge not written: this pseudopotential does not contain gipaw data"
ENDIF
END SUBROUTINE write_files
SUBROUTINE conv_upf2xml( upf )
!
USE pseudo_types, ONLY : pseudo_upf
USE upf_utils, ONLY : version_compare
!
IMPLICIT NONE
TYPE(pseudo_upf), INTENT(inout) :: upf
INTEGER, EXTERNAL :: atomic_number
!
! convert a few variables from UPF v.1 to UPF v.2/xml
!
IF ( version_compare(upf%nv,"2.0.1") == 'equal') RETURN
upf%nv="2.0.1"
!
IF ( upf%nwfc > 0 ) THEN
IF ( .NOT. ALLOCATED(upf%nchi) ) THEN
ALLOCATE(upf%nchi(upf%nwfc))
upf%nchi(:) = 0
END IF
IF ( .NOT. ALLOCATED(upf%rcut_chi) ) THEN
ALLOCATE(upf%rcut_chi(upf%nwfc))
upf%rcut_chi(:) = upf%rcut(:)
END IF
IF ( .NOT. ALLOCATED(upf%rcutus_chi) ) THEN
ALLOCATE(upf%rcutus_chi(upf%nwfc))
upf%rcutus_chi(:) = upf%rcutus(:)
END IF
IF ( .NOT. ALLOCATED(upf%epseu) ) THEN
ALLOCATE(upf%epseu(upf%nwfc))
upf%epseu(:) = 0.0
END IF
END IF
IF ( TRIM(upf%rel) == '' ) THEN
IF (upf%has_so) THEN
upf%rel="full"
ELSE IF ( upf%zmesh > 18 ) THEN
upf%rel="scalar"
ELSE
upf%rel="no"
ENDIF
ENDIF
!
IF ( .not. upf%has_so) THEN
upf%rmax = upf%r(upf%mesh)
upf%zmesh = atomic_number( upf%psd )
IF (upf%r(1) .GT. 1.d-16) THEN
upf%dx = log(upf%rmax/upf%r(1))/(upf%mesh-1)
upf%xmin = log(upf%r(1)*upf%zmesh )
END IF
END IF
!
END SUBROUTINE conv_upf2xml
!
SUBROUTINE plot_ps_loc ( upf, fileout )
!
! Plots Vloc in both real and reciprocal space and in plottable format,
! for testing purposes.
! File contains
! "fileout"-vofr.dat r, Vloc(r), Vloc(r)+Ze^2/r
! "fileout"-vofq.dat q, q^2*Vloc(q)
! where f(q) = \int f(r) j_l(qr) r^2 dr
!
USE pseudo_types, ONLY : pseudo_upf
!
USE upf_kinds, ONLY : dp
USE upf_const, ONLY : fpi, e2
!
IMPLICIT NONE
!
TYPE(pseudo_upf), intent(in) :: upf
CHARACTER(LEN=256) :: fileout
!
REAL(DP), parameter :: dq = 0.01_dp
INTEGER, PARAMETER :: nq = 4000
REAL(DP) :: q(nq), vq(nq), vq2(nq), aux(upf%mesh), aux1(upf%mesh)
REAL(DP) :: vq0, vq1, vlq
INTEGER :: iq, ir, msh
!
open( unit = 100, file=trim(fileout) // '-vofr.dat', status='unknown', &
form='formatted' )
write(100,'("# r, vloc(r), vloc+Ze^2/r")')
do ir=1,upf%mesh
write(100,'(f10.4,2f25.12)') upf%r(ir), upf%vloc(ir), &
upf%vloc(ir) + upf%zp*e2/max(0.1_dp,upf%r(ir))
end do
close(unit=100)
do iq = 1, nq
q(iq) = (iq-1)*dq
end do
!
! Compute vloc(q=0) for the local potential without the divergence
!
do ir = 1, upf%mesh
aux (ir) = upf%r(ir) * (upf%r(ir)*upf%vloc(ir) + upf%zp * e2)
if ( upf%r(ir) < 10 ) msh = ir
enddo
!
print '("msh, mesh = ",2i5)',msh,upf%mesh
call simpson (upf%mesh, aux, upf%rab, vq0)
call simpson (msh, aux, upf%rab, vq1)
!
! Compute q^2*vloc(q). We first store the part of the integrand
! function independent of q in real space
!
do ir = 1, upf%mesh
aux1 (ir) = upf%r(ir) * upf%vloc(ir) + upf%zp * e2 * erf (upf%r(ir) )
enddo
!
! and here we perform the integral, after multiplication
! with the q-dependent part
!
do iq = 1, nq
do ir = 1, upf%mesh
aux(ir) = aux1(ir) * sin (q(iq)*upf%r(ir)) * q(iq)
enddo
call simpson (upf%mesh, aux, upf%rab, vlq)
!
! here we re-add the analytic fourier transform of the erf function
!
vq(iq) = vlq - e2 * upf%zp * exp ( - q(iq)**2/4.0_dp) !!! / q(iq)**2
!
call simpson (msh, aux, upf%rab, vlq)
vq2(iq)= vlq - e2 * upf%zp * exp ( - q(iq)**2/4.0_dp) !!! / q(iq)**2
enddo
!!! vq(:) = vq(:) * fpi / omega
!
open( unit = 100, file=trim(fileout) // '-vofq.dat', status='unknown', &
form='formatted' )
write(100,'("# q, q^2*v(q) (mesh) q^2*v(q) (msh) v(0) = ",2f15.8)') &
vq0,vq1
do iq=1,nq
write(100,'(f10.4,2f25.12)') q(iq), vq(iq), vq2(iq)
end do
close(unit=100)
!
END SUBROUTINE plot_ps_loc
!
SUBROUTINE plot_ps_beta ( upf, fileout )
!
! Plots beta projectors in both real and reciprocal space
! and in plottable format for testing purposes.
! File contains
! "fileout"-betar-n.dat r, beta_n(r)
! "fileout"-betaq-n.dat q, q^2 beta_n(q)
! where f(q) = \int f(r) j_l(qr) r^2 dr
!
USE pseudo_types, ONLY : pseudo_upf
!
USE upf_kinds, ONLY : dp
USE upf_const, ONLY : fpi, e2
!
IMPLICIT NONE
!
TYPE(pseudo_upf), intent(in) :: upf
CHARACTER(LEN=256) :: fileout
!
REAL(DP) :: dq = 0.01_dp
INTEGER, PARAMETER :: nq = 4000
REAL(DP) :: q(nq), aux(upf%mesh), aux1(upf%mesh)
REAL(DP) :: vq0, vq1
INTEGER :: iq, ir, nb, iun
character(len=256) :: filename
character(len=2) :: number
!
print '("kkbeta = ",1i5)',upf%kkbeta
do nb=1,upf%nbeta
if ( nb < 10 ) then
write(filename,'(A,"-betar-",i1,".dat")') trim(fileout),nb
else
write(filename,'(A,"-betar-",i2,".dat")') trim(fileout),nb
end if
iun = 199 + nb
open( unit=iun, file=filename, status='unknown', form='formatted' )
write(iun,'("# r, vbeta(r,lm)")')
do ir=1,upf%kkbeta
write(iun,'(f10.4,f25.12)') upf%r(ir), upf%beta(ir,nb)
end do
close(unit=iun)
end do
do iq = 1, nq
q(iq) = (iq-1)*dq
end do
!
! Compute q^2*beta(q)
!
do nb=1,upf%nbeta
if ( nb < 10 ) then
write(filename,'(A,"-betaq-",i1,".dat")') trim(fileout),nb
else
write(filename,'(A,"-betaq-",i2,".dat")') trim(fileout),nb
end if
iun = 299 + nb
open( unit=iun, file=filename, status='unknown', form='formatted' )
write(iun,'("# q, q^2*v(q) ((old) a^2*v(q) (cp90)")')
do iq = 1, nq
do ir = 1, upf%kkbeta
aux(ir) = upf%beta(ir,nb) * sin (q(iq)*upf%r(ir)) * q(iq)
enddo
call simpson (upf%kkbeta, aux, upf%rab, vq0)
call simpson_cp90 (upf%kkbeta, aux, upf%rab, vq1)
write(iun,'(f10.4,2f25.12)') q(iq), vq0, vq1
end do
close(unit=iun)
enddo
!
END SUBROUTINE plot_ps_beta