mirror of https://gitlab.com/QEF/q-e.git
2531 lines
72 KiB
Fortran
2531 lines
72 KiB
Fortran
!
|
|
! Copyright (C) 2001-2013 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 polarization
|
|
!this module describes the structure for the polarization P
|
|
! and dressed iteraction W, imaginary time/frequency
|
|
USE kinds, ONLY : DP
|
|
|
|
TYPE polaw
|
|
!this structure describe a generic P or W function
|
|
!usually in the space of orthonormalized products of wanniers
|
|
INTEGER :: label!label to read/write to disk
|
|
LOGICAL :: ontime!if .true. is on imaginary time, otherwise frequency
|
|
REAL(kind=DP) :: time!imaginary time or frequency
|
|
INTEGER :: numpw!number of states (products of wanniers)
|
|
REAL(kind=DP), DIMENSION(:,:), POINTER :: pw!the P or W
|
|
COMPLEX(kind=DP) :: factor!complex factor to be multiplied to the real matrix pw
|
|
END TYPE polaw
|
|
|
|
|
|
|
|
CONTAINS
|
|
|
|
SUBROUTINE initialize_polaw(pw)
|
|
!this subroutine initializes polaw
|
|
implicit none
|
|
TYPE(polaw) :: pw
|
|
nullify(pw%pw)
|
|
return
|
|
END SUBROUTINE initialize_polaw
|
|
|
|
SUBROUTINE free_memory_polaw(pw)
|
|
!this subroutine deallocates the green descriptor
|
|
implicit none
|
|
TYPE(polaw) pw
|
|
if(associated(pw%pw)) deallocate(pw%pw)
|
|
nullify(pw%pw)
|
|
return
|
|
END SUBROUTINE
|
|
|
|
SUBROUTINE conjugate_polaw(pw)
|
|
! this subroutine calculculates the conjugate of the polaw matrix
|
|
implicit none
|
|
|
|
TYPE(polaw) pw
|
|
pw%label=-pw%label
|
|
return
|
|
END SUBROUTINE conjugate_polaw
|
|
|
|
|
|
SUBROUTINE write_polaw(pw,debug)
|
|
!this subroutine writes the green function on disk
|
|
!the file name is taken from the label
|
|
|
|
USE io_files, ONLY : prefix,tmp_dir
|
|
implicit none
|
|
INTEGER, EXTERNAL :: find_free_unit
|
|
TYPE(polaw) :: pw!the green function to be written
|
|
LOGICAL :: debug! if .true. produces formatted output
|
|
|
|
LOGICAL :: direct_file = .true.!if true uses direct- access file to write matrix on disk
|
|
|
|
INTEGER :: iw, jw, iung
|
|
CHARACTER(5) :: nfile
|
|
|
|
if(pw%label >= 0 ) then
|
|
write(nfile,'(5i1)') &
|
|
& pw%label/10000,mod(pw%label,10000)/1000,mod(pw%label,1000)/100,mod(pw%label,100)/10,mod(pw%label,10)
|
|
iung = find_free_unit()
|
|
if(.not.debug) then
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.'// nfile, status='unknown',form='unformatted')
|
|
else
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.'// nfile, status='unknown',form='formatted')
|
|
endif
|
|
else
|
|
write(nfile,'(5i1)') &
|
|
& -pw%label/10000,mod(-pw%label,10000)/1000,mod(-pw%label,1000)/100,mod(-pw%label,100)/10,mod(-pw%label,10)
|
|
iung = find_free_unit()
|
|
if(.not.debug) then
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.-'// nfile, status='unknown',form='unformatted')
|
|
else
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.-'// nfile, status='unknown',form='formatted')
|
|
endif
|
|
endif
|
|
if(.not.debug) then
|
|
write(iung) pw%label
|
|
write(iung) pw%ontime
|
|
write(iung) pw%time
|
|
write(iung) pw%numpw
|
|
write(iung) pw%factor
|
|
if(.not. direct_file) then
|
|
do iw=1,pw%numpw
|
|
write(iung) pw%pw(1:pw%numpw,iw)
|
|
enddo
|
|
endif
|
|
else
|
|
write(iung,*) pw%label
|
|
write(iung,*) pw%ontime
|
|
write(iung,*) pw%time
|
|
write(iung,*) pw%numpw
|
|
write(iung,*) pw%factor
|
|
if(.not. direct_file) then
|
|
do iw=1,pw%numpw
|
|
do jw=1,pw%numpw
|
|
write(iung,*) pw%pw(jw,iw)
|
|
enddo
|
|
enddo
|
|
endif
|
|
endif
|
|
|
|
close(iung)
|
|
|
|
if(direct_file) then
|
|
iung = find_free_unit()
|
|
if(pw%label >= 0 ) then
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polawd.'// nfile, &
|
|
&status='unknown',recl=pw%numpw*DP,access='direct')
|
|
else
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polawd.-'// nfile, &
|
|
&status='unknown',recl=pw%numpw*DP,access='direct')
|
|
endif
|
|
do iw=1,pw%numpw
|
|
write(unit=iung, rec=iw) pw%pw(:,iw)
|
|
enddo
|
|
close(iung)
|
|
endif
|
|
|
|
|
|
return
|
|
END SUBROUTINE
|
|
|
|
SUBROUTINE read_polaw(label, pw,debug,l_verbose)
|
|
!this subroutine reads the green function from disk
|
|
!the file name is taken from the label
|
|
|
|
USE io_files, ONLY : prefix,tmp_dir
|
|
USE io_global, ONLY : stdout
|
|
implicit none
|
|
INTEGER, EXTERNAL :: find_free_unit
|
|
TYPE(polaw) :: pw!the green function to be read
|
|
INTEGER :: label! the label identifing the required green function
|
|
LOGICAL :: debug!if true formatted files
|
|
LOGICAL, INTENT(in) :: l_verbose
|
|
|
|
LOGICAL :: direct_file = .true.!if true uses direct- access file to read matrix from disk
|
|
|
|
INTEGER :: iw, jw, iung
|
|
CHARACTER(5) :: nfile
|
|
|
|
if(l_verbose) write(stdout,*) 'Read polaw'!ATTENZIONE
|
|
!first deallocate
|
|
call free_memory_polaw(pw)
|
|
if(l_verbose) write(stdout,*) 'Read polaw2'!ATTENZIONE
|
|
if(label >= 0 ) then
|
|
write(nfile,'(5i1)') label/10000,mod(label,10000)/1000,mod(label,1000)/100,mod(label,100)/10,mod(label,10)
|
|
iung = find_free_unit()
|
|
if(.not.debug) then
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.'// nfile, status='old',form='unformatted')
|
|
else
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.'// nfile, status='old',form='formatted')
|
|
endif
|
|
else
|
|
write(nfile,'(5i1)') -label/10000,mod(-label,10000)/1000,mod(-label,1000)/100,mod(-label,100)/10,mod(-label,10)
|
|
iung = find_free_unit()
|
|
if(.not.debug) then
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.-'// nfile, status='old',form='unformatted')
|
|
else
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.-'// nfile, status='old',form='formatted')
|
|
endif
|
|
endif
|
|
if(.not.debug) then
|
|
read(iung) pw%label
|
|
read(iung) pw%ontime
|
|
read(iung) pw%time
|
|
read(iung) pw%numpw
|
|
read(iung) pw%factor
|
|
else
|
|
read(iung,*) pw%label
|
|
read(iung,*) pw%ontime
|
|
read(iung,*) pw%time
|
|
read(iung,*) pw%numpw
|
|
read(iung,*) pw%factor
|
|
endif
|
|
write(stdout,*) 'Read polaw',pw%numpw!ATTENZIONE
|
|
!now allocate
|
|
allocate(pw%pw(pw%numpw,pw%numpw))
|
|
if(.not. direct_file) then
|
|
if(.not.debug) then
|
|
do iw=1,pw%numpw
|
|
read(iung) pw%pw(1:pw%numpw,iw)
|
|
enddo
|
|
else
|
|
do iw=1,pw%numpw
|
|
do jw=1,pw%numpw
|
|
read(iung,*) pw%pw(jw,iw)
|
|
enddo
|
|
enddo
|
|
endif
|
|
endif
|
|
close(iung)
|
|
if(l_verbose) write(stdout,*) 'Read polaw4'!ATTENZIONE
|
|
if(direct_file) then
|
|
iung = find_free_unit()
|
|
if(label >= 0 ) then
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polawd.'// nfile, &
|
|
&status='unknown',recl=pw%numpw*DP,access='direct')
|
|
else
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polawd.-'// nfile, &
|
|
&status='unknown',recl=pw%numpw*DP,access='direct')
|
|
endif
|
|
if(l_verbose) write(stdout,*) 'Read polaw5'!ATTENZIONE
|
|
do iw=1,pw%numpw
|
|
read(unit=iung, rec=iw) pw%pw(:,iw)
|
|
enddo
|
|
close(iung)
|
|
endif
|
|
if(l_verbose) write(stdout,*) 'Read polaw6'!ATTENZIONE
|
|
|
|
return
|
|
END SUBROUTINE
|
|
|
|
|
|
SUBROUTINE read_polaw_global(label, pw)
|
|
!this subroutine reads the green function from disk
|
|
!the file name is taken from the label
|
|
!the ionode_id distribute to all the processors
|
|
|
|
USE io_files, ONLY : prefix,tmp_dir
|
|
USE io_global, ONLY : stdout, ionode, ionode_id
|
|
USE mp, ONLY : mp_barrier, mp_bcast
|
|
USE mp_world, ONLY : world_comm
|
|
|
|
implicit none
|
|
INTEGER, EXTERNAL :: find_free_unit
|
|
TYPE(polaw) :: pw!the green function to be read
|
|
INTEGER :: label! the label identifing the required green function
|
|
|
|
|
|
LOGICAL :: direct_file = .true.!if true uses direct- access file to read matrix from disk
|
|
|
|
INTEGER :: iw, jw, iung
|
|
CHARACTER(5) :: nfile
|
|
|
|
|
|
!first deallocate
|
|
call free_memory_polaw(pw)
|
|
if(ionode) then
|
|
if(label >= 0 ) then
|
|
write(nfile,'(5i1)') label/10000,mod(label,10000)/1000,mod(label,1000)/100,mod(label,100)/10,mod(label,10)
|
|
iung = find_free_unit()
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.'// nfile, status='old',form='unformatted')
|
|
else
|
|
write(nfile,'(5i1)') -label/10000,mod(-label,10000)/1000,mod(-label,1000)/100,mod(-label,100)/10,mod(-label,10)
|
|
iung = find_free_unit()
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.-'// nfile, status='old',form='unformatted')
|
|
endif
|
|
|
|
|
|
read(iung) pw%label
|
|
read(iung) pw%ontime
|
|
read(iung) pw%time
|
|
read(iung) pw%numpw
|
|
read(iung) pw%factor
|
|
endif
|
|
call mp_bcast(pw%label,ionode_id,world_comm)
|
|
call mp_bcast(pw%ontime,ionode_id,world_comm)
|
|
call mp_bcast(pw%time,ionode_id,world_comm)
|
|
call mp_bcast(pw%numpw,ionode_id,world_comm)
|
|
call mp_bcast(pw%factor,ionode_id,world_comm)
|
|
|
|
allocate(pw%pw(pw%numpw,pw%numpw))
|
|
if(ionode) then
|
|
if(.not. direct_file) then
|
|
do iw=1,pw%numpw
|
|
read(iung) pw%pw(1:pw%numpw,iw)
|
|
enddo
|
|
endif
|
|
close(iung)
|
|
|
|
if(direct_file) then
|
|
iung = find_free_unit()
|
|
if(label >= 0 ) then
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polawd.'// nfile, &
|
|
&status='unknown',recl=pw%numpw*DP,access='direct')
|
|
else
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polawd.-'// nfile, &
|
|
&status='unknown',recl=pw%numpw*DP,access='direct')
|
|
endif
|
|
|
|
do iw=1,pw%numpw
|
|
read(unit=iung, rec=iw) pw%pw(:,iw)
|
|
enddo
|
|
close(iung)
|
|
endif
|
|
endif
|
|
do iw=1,pw%numpw
|
|
call mp_barrier( world_comm )
|
|
call mp_bcast(pw%pw(:,iw),ionode_id,world_comm)
|
|
enddo
|
|
|
|
return
|
|
END SUBROUTINE read_polaw_global
|
|
|
|
|
|
|
|
|
|
SUBROUTINE write_polaw_range( pw, debug, range_min, range_max, full_range )
|
|
!this subroutine writes the green function on disk
|
|
!the file name is taken from the label
|
|
!writes column from range_min to range_max
|
|
|
|
USE io_files, ONLY : prefix,tmp_dir
|
|
USE io_global, ONLY : stdout
|
|
|
|
|
|
implicit none
|
|
INTEGER, EXTERNAL :: find_free_unit
|
|
TYPE(polaw) :: pw!the green function to be written
|
|
LOGICAL :: debug! if .true. produces formatted output
|
|
INTEGER, INTENT(in) :: range_min, range_max!range of column
|
|
LOGICAL, INTENT(IN) :: full_range
|
|
|
|
|
|
LOGICAL :: direct_file = .true.!if true uses direct- access file to write matrix on disk
|
|
|
|
INTEGER :: iw, jw, iung, iww
|
|
CHARACTER(5) :: nfile
|
|
|
|
!check range
|
|
|
|
if(range_min<1 .or. range_max> pw%numpw) then
|
|
write(stdout,*) 'write_polaw_range: out of range = ', range_min, range_max
|
|
stop
|
|
endif
|
|
|
|
|
|
|
|
if(pw%label >= 0 ) then
|
|
write(nfile,'(5i1)') &
|
|
& pw%label/10000,mod(pw%label,10000)/1000,mod(pw%label,1000)/100,mod(pw%label,100)/10,mod(pw%label,10)
|
|
iung = find_free_unit()
|
|
if(.not.debug) then
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.'// nfile, status='unknown',form='unformatted')
|
|
else
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.'// nfile, status='unknown',form='formatted')
|
|
endif
|
|
else
|
|
write(nfile,'(5i1)') &
|
|
& -pw%label/10000,mod(-pw%label,10000)/1000,mod(-pw%label,1000)/100,mod(-pw%label,100)/10,mod(-pw%label,10)
|
|
iung = find_free_unit()
|
|
if(.not.debug) then
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.-'// nfile, status='unknown',form='unformatted')
|
|
else
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.-'// nfile, status='unknown',form='formatted')
|
|
endif
|
|
endif
|
|
if(.not.debug) then
|
|
write(iung) pw%label
|
|
write(iung) pw%ontime
|
|
write(iung) pw%time
|
|
write(iung) pw%numpw
|
|
write(iung) pw%factor
|
|
if(.not. direct_file) then
|
|
do iw=1,pw%numpw
|
|
write(iung) pw%pw(1:pw%numpw,iw)
|
|
enddo
|
|
endif
|
|
else
|
|
write(iung,*) pw%label
|
|
write(iung,*) pw%ontime
|
|
write(iung,*) pw%time
|
|
write(iung,*) pw%numpw
|
|
write(iung,*) pw%factor
|
|
if(.not. direct_file) then
|
|
do iw=1,pw%numpw
|
|
do jw=1,pw%numpw
|
|
write(iung,*) pw%pw(jw,iw)
|
|
enddo
|
|
enddo
|
|
endif
|
|
endif
|
|
|
|
close(iung)
|
|
|
|
if(direct_file) then
|
|
iung = find_free_unit()
|
|
if(pw%label >= 0 ) then
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polawd.'// nfile, &
|
|
&status='unknown',recl=pw%numpw*DP,access='direct')
|
|
else
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polawd.-'// nfile, &
|
|
&status='unknown',recl=pw%numpw*DP,access='direct')
|
|
endif
|
|
do iw=range_min,range_max
|
|
iww = iw
|
|
if( .not. full_range ) iww = iw - range_min + 1
|
|
write(unit=iung, rec=iw) pw%pw(:,iww)
|
|
enddo
|
|
close(iung)
|
|
endif
|
|
|
|
|
|
return
|
|
END SUBROUTINE write_polaw_range
|
|
|
|
SUBROUTINE read_polaw_range(label, pw,debug,range_min,range_max, full_range )
|
|
!this subroutine reads the green function from disk
|
|
!the file name is taken from the label
|
|
!reads columns from range_min to range_max
|
|
|
|
USE io_files, ONLY : prefix,tmp_dir
|
|
USE io_global, ONLY : stdout
|
|
|
|
implicit none
|
|
|
|
INTEGER, EXTERNAL :: find_free_unit
|
|
TYPE(polaw) :: pw!the green function to be read
|
|
INTEGER :: label! the label identifing the required green function
|
|
LOGICAL :: debug!if true formatted files
|
|
INTEGER, INTENT(in) :: range_min, range_max!defining range
|
|
LOGICAL, INTENT(IN) :: full_range
|
|
|
|
|
|
LOGICAL :: direct_file = .true.!if true uses direct- access file to read matrix from disk
|
|
|
|
INTEGER :: iw, jw, iung, iww
|
|
CHARACTER(5) :: nfile
|
|
|
|
|
|
|
|
|
|
!check
|
|
if(range_min<1 ) then
|
|
write(stdout,*) 'read_polaw_range: out of range ', range_min, range_max
|
|
stop
|
|
endif
|
|
|
|
|
|
|
|
!first deallocate
|
|
call free_memory_polaw(pw)
|
|
|
|
|
|
if(label >= 0 ) then
|
|
write(nfile,'(5i1)') label/10000,mod(label,10000)/1000,mod(label,1000)/100,mod(label,100)/10,mod(label,10)
|
|
iung = find_free_unit()
|
|
if(.not.debug) then
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.'// nfile, status='old',form='unformatted')
|
|
else
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.'// nfile, status='old',form='formatted')
|
|
endif
|
|
else
|
|
write(nfile,'(5i1)') -label/10000,mod(-label,10000)/1000,mod(-label,1000)/100,mod(-label,100)/10,mod(-label,10)
|
|
iung = find_free_unit()
|
|
if(.not.debug) then
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.-'// nfile, status='old',form='unformatted')
|
|
else
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polaw.-'// nfile, status='old',form='formatted')
|
|
endif
|
|
endif
|
|
if(.not.debug) then
|
|
read(iung) pw%label
|
|
read(iung) pw%ontime
|
|
read(iung) pw%time
|
|
read(iung) pw%numpw
|
|
read(iung) pw%factor
|
|
else
|
|
read(iung,*) pw%label
|
|
read(iung,*) pw%ontime
|
|
read(iung,*) pw%time
|
|
read(iung,*) pw%numpw
|
|
read(iung,*) pw%factor
|
|
endif
|
|
!now allocate
|
|
|
|
|
|
if( full_range ) then
|
|
allocate(pw%pw(pw%numpw,pw%numpw))
|
|
else
|
|
allocate( pw%pw( pw%numpw, range_max - range_min + 1 ) )
|
|
endif
|
|
|
|
if(.not. direct_file) then
|
|
if(.not.debug) then
|
|
do iw=1,pw%numpw
|
|
read(iung) pw%pw(1:pw%numpw,iw)
|
|
enddo
|
|
else
|
|
do iw=1,pw%numpw
|
|
do jw=1,pw%numpw
|
|
read(iung,*) pw%pw(jw,iw)
|
|
enddo
|
|
enddo
|
|
endif
|
|
endif
|
|
close(iung)
|
|
|
|
if(direct_file) then
|
|
!check
|
|
if(range_max > pw%numpw ) then
|
|
write(stdout,*) 'read_polaw_range: out of range = ', range_min, range_max
|
|
stop
|
|
endif
|
|
|
|
iung = find_free_unit()
|
|
if(label >= 0 ) then
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polawd.'// nfile, &
|
|
&status='unknown',recl=pw%numpw*DP,access='direct')
|
|
else
|
|
open( unit=iung, file=trim(tmp_dir)//trim(prefix)//'-'//'polawd.-'// nfile, &
|
|
&status='unknown',recl=pw%numpw*DP,access='direct')
|
|
endif
|
|
do iw=range_min, range_max
|
|
iww = iw
|
|
if( .not. full_range ) iww = iw - range_min + 1
|
|
read(unit=iung, rec=iw) pw%pw(:,iww)
|
|
enddo
|
|
close(iung)
|
|
endif
|
|
|
|
|
|
return
|
|
END SUBROUTINE read_polaw_range
|
|
|
|
|
|
|
|
|
|
|
|
SUBROUTINE create_polarization(time,pr,gf_p,gf_m,qm,debug)
|
|
!this subroutine set the polarization in imaginary time
|
|
! as P(r,r',it)=G(r,r',it)*G(r,r',-it)
|
|
! for our basis
|
|
! P_{i,j}=\sum_{l,n,m,o} Q_{i,lm}Q_{j,mo}G_{lm}(it)G_{no}(-it)
|
|
!THERE IS ALSO A SPIN FACTOR 2
|
|
|
|
|
|
USE basic_structures, ONLY : q_mat,wannier_P
|
|
USE green_function, ONLY : green
|
|
USE io_global, ONLY : stdout
|
|
USE constants, ONLY : eps8
|
|
|
|
implicit none
|
|
|
|
REAL(kind=DP) :: time!imaginary time t, just a check
|
|
TYPE(polaw) :: pr!polarization P(it) to be created
|
|
TYPE(green) :: gf_p!green function G(it)
|
|
TYPE(green) :: gf_m!green function G(-it)
|
|
TYPE(q_mat) :: qm!overlap matrix Q
|
|
LOGICAL :: debug!if true check for hermeticity
|
|
|
|
INTEGER :: iw,jw, ip,jp
|
|
INTEGER :: l,n,m,o
|
|
|
|
!first annihilation
|
|
call free_memory_polaw(pr)
|
|
|
|
!check time
|
|
if((abs(gf_p%time - time)>=eps8) .OR. (abs(gf_m%time + time) >= eps8)) then!times are wrong
|
|
write(stdout,*) 'Subroutine polarization: times are wrong',gf_p%time,gf_m%time
|
|
stop
|
|
endif
|
|
|
|
!set pr
|
|
pr%ontime=.true.
|
|
pr%time=time
|
|
pr%numpw=qm%numpw
|
|
|
|
!allocate
|
|
allocate(pr%pw( pr%numpw,pr%numpw))
|
|
pr%pw(:,:) =(0.d0,0.d0)
|
|
|
|
do iw=1,pr%numpw
|
|
do jw=iw,pr%numpw
|
|
do ip=1,qm%wp(iw)%numij
|
|
do jp=1,qm%wp(jw)%numij
|
|
|
|
l=qm%wp(iw)%ij(1,ip)
|
|
n=qm%wp(iw)%ij(2,ip)
|
|
m=qm%wp(jw)%ij(1,jp)
|
|
o=qm%wp(jw)%ij(2,jp)
|
|
|
|
pr%pw(iw,jw)=pr%pw(iw,jw)+qm%wp(iw)%o(ip)*qm%wp(jw)%o(jp)* &
|
|
& gf_p%gf(l,m,1)*gf_m%gf(n,o,1)
|
|
|
|
!couples are NOT ordered
|
|
if(l/=n) then
|
|
pr%pw(iw,jw)=pr%pw(iw,jw)+qm%wp(iw)%o(ip)*qm%wp(jw)%o(jp)* &
|
|
& gf_p%gf(n,m,1)*gf_m%gf(l,o,1)
|
|
endif
|
|
|
|
if(m/=o) then
|
|
pr%pw(iw,jw)=pr%pw(iw,jw)+qm%wp(iw)%o(ip)*qm%wp(jw)%o(jp)* &
|
|
& gf_p%gf(l,o,1)*gf_m%gf(n,m,1)
|
|
endif
|
|
|
|
if(l/=n .AND. m/=o) then
|
|
pr%pw(iw,jw)=pr%pw(iw,jw)+qm%wp(iw)%o(ip)*qm%wp(jw)%o(jp)* &
|
|
& gf_p%gf(n,o,1)*gf_m%gf(l,m,1)
|
|
endif
|
|
enddo
|
|
pr%pw(jw,iw)=pr%pw(iw,jw)
|
|
enddo
|
|
enddo
|
|
enddo
|
|
|
|
|
|
pr%factor=(0.d0,-1.d0)
|
|
!now spin factor
|
|
pr%pw(:,:)=2.d0*pr%pw(:,:)
|
|
|
|
return
|
|
|
|
END subroutine
|
|
|
|
SUBROUTINE calculate_w(vp,pp,ww,xc_together,l_symm_epsilon,l_head_epsilon,agz,head,l_divergence,inv_epsi, &
|
|
&l_wing_epsilon, awing, l_verbose)
|
|
!this subroutine calculates W=(1+vp)^{-1}v
|
|
!this is meaningful only on frequency domain
|
|
!lapack routines are used
|
|
USE io_global, ONLY : stdout
|
|
USE basic_structures, ONLY : v_pot, head_epsilon
|
|
|
|
implicit none
|
|
TYPE(v_pot) :: vp!coulomb potential
|
|
TYPE(polaw) :: pp!polarization on imaginary frequency, destroyed on exit
|
|
TYPE(polaw) :: ww!dressed interaction to be calculated
|
|
LOGICAL :: xc_together!if true the entire W is taken, otherwise W-v
|
|
LOGICAL :: l_symm_epsilon! if true uses the symmetrized form of the dielectric matrix
|
|
!for calculating W
|
|
LOGICAL :: l_head_epsilon!if true add to the symmetrized form of the dielectric matrix
|
|
!the head terms
|
|
REAL(kind=DP), DIMENSION(:) :: agz!terms A_ij<\tilde{w^P_j}|G=0>
|
|
REAL(kind=DP) :: head!term (G=0,G=0) of the symmetric dielectric matrix
|
|
LOGICAL, INTENT(in) :: l_divergence!if true calculate the head of the inverse dielectric matrix
|
|
REAL(kind=DP), INTENT(out) :: inv_epsi!head of the inverse dielectric matrix
|
|
LOGICAL, INTENT(in) :: l_wing_epsilon!if true calculate the wings of the symmetrized dielectric matrix
|
|
REAL(kind=DP), DIMENSION(:) :: awing!the terms A_ij wing_j
|
|
LOGICAL, INTENT(in) :: l_verbose
|
|
|
|
INTEGER iw,jw,kw
|
|
REAL(kind=DP), ALLOCATABLE, DIMENSION(:,:) :: dtmp!temporary array
|
|
INTEGER, ALLOCATABLE, DIMENSION(:) :: ipiv
|
|
INTEGER :: info
|
|
REAL(kind=DP),ALLOCATABLE, DIMENSION(:) :: work
|
|
INTEGER :: lwork
|
|
REAL(kind=DP) sca
|
|
REAL(kind=DP) :: workd
|
|
|
|
!deallocate if the case
|
|
call free_memory_polaw(ww)
|
|
|
|
|
|
!check and set
|
|
if(pp%ontime) then
|
|
write(stdout,*) 'Routine calculate_w: frequencies required'
|
|
stop
|
|
endif
|
|
if(pp%numpw /= vp%numpw) then
|
|
write(stdout,*) 'Routine calculate_w: basis set does not correspond',pp%numpw,vp%numpw
|
|
stop
|
|
endif
|
|
|
|
ww%ontime=.false.
|
|
ww%time=pp%time
|
|
ww%label=pp%label
|
|
ww%numpw=pp%numpw
|
|
allocate(ww%pw(ww%numpw,ww%numpw))
|
|
|
|
allocate(dtmp(ww%numpw,ww%numpw))
|
|
allocate(ipiv(ww%numpw))
|
|
|
|
|
|
if(.not.l_symm_epsilon) then
|
|
!not symmetric case calculates -vP
|
|
call dgemm('N','N',ww%numpw,ww%numpw,ww%numpw,-1.d0*dble(pp%factor),&
|
|
& vp%vmat,ww%numpw,pp%pw,ww%numpw,0.d0,dtmp,ww%numpw)
|
|
else
|
|
!symmetric case calculates -v^1/2 P v^1/2
|
|
call dgemm('N','N',ww%numpw,ww%numpw,ww%numpw,-1.d0*dble(pp%factor),&
|
|
& vp%vmat,ww%numpw,pp%pw,ww%numpw,0.d0,dtmp,ww%numpw)
|
|
pp%pw(:,:)=dtmp(:,:)
|
|
call dgemm('N','N',ww%numpw,ww%numpw,ww%numpw,1.d0,&
|
|
& pp%pw,ww%numpw,vp%vmat,ww%numpw,0.d0,dtmp,ww%numpw)
|
|
endif
|
|
|
|
!if required add the head
|
|
if(l_symm_epsilon .and.l_head_epsilon) then
|
|
do jw=1,ww%numpw
|
|
do iw=1,ww%numpw
|
|
dtmp(iw,jw)=dtmp(iw,jw)+agz(iw)*agz(jw)*head
|
|
enddo
|
|
enddo
|
|
endif
|
|
|
|
|
|
!if required add the wings
|
|
if(l_symm_epsilon .and.l_wing_epsilon) then
|
|
do jw=1,ww%numpw
|
|
do iw=1,ww%numpw
|
|
dtmp(iw,jw)=dtmp(iw,jw)+agz(iw)*awing(jw)+agz(jw)*awing(iw)
|
|
enddo
|
|
enddo
|
|
endif
|
|
|
|
do iw=1,ww%numpw
|
|
dtmp(iw,iw)=dtmp(iw,iw)+1.d0
|
|
enddo
|
|
|
|
|
|
!inverse zmat
|
|
|
|
call dgetrf(ww%numpw,ww%numpw,dtmp,ww%numpw,ipiv,info)
|
|
if(info /= 0) then
|
|
write(stdout,*) 'Routine calculate_w: problem with dgetrf :', info
|
|
stop
|
|
endif
|
|
|
|
call dgetri(ww%numpw,dtmp,ww%numpw,ipiv,workd,-1,info)
|
|
if(l_verbose) write(stdout,*) 'Dimension', workd!ATTENZIONE
|
|
allocate(work(int(workd)))
|
|
call dgetri(ww%numpw,dtmp,ww%numpw,ipiv,work,int(workd),info)
|
|
|
|
if(info /= 0) then
|
|
write(stdout,*) 'Routine calculate_w: problem with zgetri :', info
|
|
stop
|
|
endif
|
|
|
|
|
|
if(.not.xc_together) then
|
|
do iw=1,ww%numpw
|
|
dtmp(iw,iw)=dtmp(iw,iw)-1.d0
|
|
enddo
|
|
endif
|
|
|
|
!if required calculates the head (G=0,G=0) of \epsilon^-1
|
|
|
|
if(l_divergence) then
|
|
inv_epsi=0.d0
|
|
do jw=1,ww%numpw
|
|
do iw=1,ww%numpw
|
|
inv_epsi = inv_epsi+dtmp(iw,jw)*agz(iw)*agz(jw)
|
|
enddo
|
|
enddo
|
|
do iw=1,ww%numpw
|
|
dtmp(iw,iw)=dtmp(iw,iw)-inv_epsi
|
|
enddo
|
|
endif
|
|
|
|
if(l_verbose) write(stdout,*) 'INV EPSI G=0,G=0', inv_epsi
|
|
|
|
if(.not. l_symm_epsilon) then
|
|
!calculates (e-1 -1)v
|
|
call dgemm('N','N',ww%numpw,ww%numpw,ww%numpw,1.d0,&
|
|
& dtmp,ww%numpw,vp%vmat,ww%numpw,0.d0,ww%pw,ww%numpw)
|
|
else
|
|
!calculates v^1/2 (e-1-1)v^1/2
|
|
call dgemm('N','N',ww%numpw,ww%numpw,ww%numpw,1.d0,&
|
|
& vp%vmat,ww%numpw,dtmp,ww%numpw,0.d0,pp%pw,ww%numpw)
|
|
call dgemm('N','N',ww%numpw,ww%numpw,ww%numpw,1.d0,&
|
|
& pp%pw,ww%numpw,vp%vmat,ww%numpw,0.d0,ww%pw,ww%numpw)
|
|
endif
|
|
|
|
|
|
ww%factor=(1.d0,0.d0)
|
|
|
|
! if(.not.xc_together) then
|
|
! do iw=1,ww%numpw
|
|
! do jw=1,ww%numpw
|
|
! ww%pw(iw,jw)=ww%pw(iw,jw)-vp%vmat(iw,jw)
|
|
! enddo
|
|
! enddo
|
|
! endif
|
|
|
|
|
|
deallocate(dtmp,ipiv,work)
|
|
return
|
|
END SUBROUTINE
|
|
|
|
SUBROUTINE create_polarization_contraction(time,pr,cp,uu,l_hf_energies, ene_hf)
|
|
!this subroutine set the polarization in imaginary time
|
|
! as P(r,r',it)=G(r,r',it)*G(r,r',-it)
|
|
! for our basis
|
|
!uses contractions
|
|
!THERE IS ALSO A SPIN FACTOR 2
|
|
!if required uses HF energies
|
|
|
|
USE io_global, ONLY : stdout
|
|
USE constants, ONLY : eps8
|
|
USE compact_product, ONLY : contraction_pola
|
|
USE basic_structures, ONLY : wannier_u
|
|
|
|
implicit none
|
|
|
|
REAL(kind=DP) :: time!imaginary time t, just a check
|
|
TYPE(polaw) :: pr!polarization P(it) to be created
|
|
TYPE(contraction_pola) :: cp!the contracted products descriptor
|
|
TYPE(wannier_u) :: uu!for the KS energies
|
|
LOGICAL, INTENT(in) :: l_hf_energies!if true uses HF energies
|
|
REAL(kind=DP), INTENT(in) :: ene_hf(:)!HF energies
|
|
|
|
INTEGER :: iw,jw, vv, cc
|
|
INTEGER :: l,n,m,o
|
|
REAL(kind=DP) :: offset
|
|
REAL(kind=DP),ALLOCATABLE :: expene(:)!to calculate the exponentials just once
|
|
|
|
!first annihilation
|
|
call free_memory_polaw(pr)
|
|
|
|
|
|
!set pr
|
|
pr%ontime=.true.
|
|
pr%time=time
|
|
pr%numpw=cp%numpw
|
|
|
|
!calculates energy offset
|
|
|
|
if(.not.l_hf_energies) then
|
|
if(cp%nums > cp%nums_occ) then
|
|
offset=-(uu%ene(cp%nums_occ+1,1)+uu%ene(cp%nums_occ,1))/2.d0
|
|
else
|
|
offset=-uu%ene(cp%nums_occ,1)
|
|
endif
|
|
else
|
|
if(cp%nums > cp%nums_occ) then
|
|
offset=-(ene_hf(cp%nums_occ+1)+ene_hf(cp%nums_occ))/2.d0
|
|
else
|
|
offset=-ene_hf(cp%nums_occ)
|
|
endif
|
|
endif
|
|
!calcualte exponentials of ks energies
|
|
|
|
allocate(expene(cp%nums))
|
|
if(.not.l_hf_energies) then
|
|
do vv=1,cp%nums_occ
|
|
expene(vv)=exp((uu%ene(vv,1)+offset)*time)
|
|
enddo
|
|
do cc=cp%nums_occ+1,cp%nums
|
|
expene(cc)=exp(-(uu%ene(cc,1)+offset)*time)
|
|
enddo
|
|
else
|
|
do vv=1,cp%nums_occ
|
|
expene(vv)=exp((ene_hf(vv)+offset)*time)
|
|
enddo
|
|
do cc=cp%nums_occ+1,cp%nums
|
|
expene(cc)=exp(-(ene_hf(cc)+offset)*time)
|
|
enddo
|
|
endif
|
|
|
|
!allocate
|
|
allocate(pr%pw( pr%numpw,pr%numpw))
|
|
pr%pw(:,:)=(0.d0,0.d0)
|
|
do iw=1,pr%numpw
|
|
do jw=iw,pr%numpw
|
|
do vv=1,cp%nums_occ
|
|
do cc=1,cp%nums-cp%nums_occ
|
|
pr%pw(iw,jw)=pr%pw(iw,jw) + cp%ou(iw,vv,cc)*conjg(cp%ou(jw,vv,cc))*&
|
|
& expene(vv)*expene(cc+cp%nums_occ)
|
|
enddo
|
|
enddo
|
|
pr%pw(jw,iw)=pr%pw(iw,jw)
|
|
enddo
|
|
enddo
|
|
pr%factor=(0.d0,-1.d0)
|
|
!now spin factor
|
|
pr%pw(:,:)=2.d0*pr%pw(:,:)
|
|
|
|
deallocate(expene)
|
|
return
|
|
END SUBROUTINE
|
|
|
|
SUBROUTINE invert_ortho_polaw(op,opi)
|
|
!this subroutine inverts the orthonormalization matrix
|
|
!acting of products of wanniers
|
|
USE io_global, ONLY : stdout
|
|
USE basic_structures, ONLY : ortho_polaw, free_memory
|
|
|
|
implicit none
|
|
|
|
TYPE(ortho_polaw), INTENT(in) :: op !the descriptor of the orthonormalization matrix to be inverted
|
|
TYPE(ortho_polaw), INTENT(out) :: opi !the descriptor of the orthonormalization matrix to be inverted
|
|
|
|
INTEGER :: info,lwork
|
|
INTEGER, ALLOCATABLE, DIMENSION(:) :: ipiv
|
|
REAL(kind=DP), ALLOCATABLE, DIMENSION(:) :: work
|
|
|
|
lwork=op%numpw
|
|
allocate(ipiv(op%numpw))
|
|
allocate(work(lwork))
|
|
|
|
call free_memory(opi)
|
|
opi%numpw=op%numpw
|
|
allocate(opi%on_mat( opi%numpw, opi%numpw))
|
|
opi%on_mat(:,:)=op%on_mat(:,:)
|
|
|
|
call dgetrf(opi%numpw,opi%numpw,opi%on_mat,opi%numpw,ipiv,info)
|
|
if(info /= 0) then
|
|
write(stdout,*) 'Routine invert_ortho_polaw: problem with dgetrf :', info
|
|
stop
|
|
endif
|
|
|
|
call dgetri(opi%numpw,opi%on_mat,opi%numpw,ipiv,work,lwork,info)
|
|
if(info /= 0) then
|
|
write(stdout,*) 'Routine invert_ortho_polaw: problem with dgetri :', info
|
|
stop
|
|
endif
|
|
|
|
if(op%inverse) then
|
|
opi%inverse=.false.
|
|
else
|
|
opi%inverse=.true.
|
|
endif
|
|
|
|
deallocate(ipiv,work)
|
|
return
|
|
END SUBROUTINE
|
|
|
|
SUBROUTINE distribute_ortho_polaw(op,opd)
|
|
!this subroutine distributes the orthonormalization matrix
|
|
! among processors
|
|
|
|
USE io_global, ONLY : stdout
|
|
USE basic_structures, ONLY : ortho_polaw, free_memory
|
|
USE mp_world, ONLY : nproc,mpime
|
|
|
|
implicit none
|
|
|
|
TYPE(ortho_polaw), INTENT(in) :: op !the descriptor of the orthonormalization matrix to be distributed
|
|
TYPE(ortho_polaw), INTENT(out) :: opd!distributed orthonormalization matrix
|
|
|
|
INTEGER :: l_blk,nbegin,nend,ii
|
|
|
|
call free_memory(opd)
|
|
|
|
opd%numpw = op%numpw
|
|
opd%inverse = op%inverse
|
|
|
|
l_blk= op%numpw/nproc
|
|
if(l_blk*nproc < op%numpw) l_blk = l_blk+1
|
|
nbegin=mpime*l_blk+1
|
|
nend=nbegin+l_blk-1
|
|
if(nend > op%numpw) nend = op%numpw
|
|
|
|
allocate(opd%on_mat(op%numpw,l_blk))
|
|
|
|
do ii=nbegin,nend
|
|
opd%on_mat(:,ii-nbegin+1)=op%on_mat(:,ii)
|
|
enddo
|
|
|
|
return
|
|
|
|
END SUBROUTINE distribute_ortho_polaw
|
|
|
|
SUBROUTINE collect_ortho_polaw(op,opd)
|
|
!this subroutine collects the orthonormalization matrix
|
|
! among processors
|
|
|
|
USE io_global, ONLY : stdout
|
|
USE basic_structures, ONLY : ortho_polaw, free_memory
|
|
USE mp_world, ONLY : nproc,mpime,world_comm!group
|
|
USE parallel_include
|
|
|
|
implicit none
|
|
|
|
TYPE(ortho_polaw), INTENT(out) :: op !the descriptor of the orthonormalization matrix to be distributed
|
|
TYPE(ortho_polaw), INTENT(in) :: opd!distributed orthonormalization matrix
|
|
|
|
INTEGER :: l_blk,nbegin,nend,ierr
|
|
|
|
call free_memory(op)
|
|
|
|
op%numpw = opd%numpw
|
|
op%inverse = opd%inverse
|
|
|
|
l_blk= op%numpw/nproc
|
|
if(l_blk*nproc < op%numpw) l_blk = l_blk+1
|
|
nbegin=mpime*l_blk+1
|
|
nend=nbegin+l_blk-1
|
|
if(nend > op%numpw) nend = op%numpw
|
|
|
|
allocate(op%on_mat(op%numpw,l_blk*nproc))
|
|
|
|
#if defined(__MPI)
|
|
call MPI_ALLGATHER(opd%on_mat,l_blk*op%numpw,MPI_DOUBLE_PRECISION, op%on_mat, &
|
|
& l_blk*op%numpw, MPI_DOUBLE_PRECISION,world_comm, ierr)
|
|
#else
|
|
op%on_mat(:,:)=opd%on_mat
|
|
#endif
|
|
|
|
|
|
return
|
|
END SUBROUTINE collect_ortho_polaw
|
|
|
|
|
|
|
|
|
|
|
|
SUBROUTINE orthonormalize(op,pw)
|
|
!this subroutine rotates the pw data on the basis of the trasform op
|
|
!perform the trasform \sum_{i',j'} B_{i,i'}P_{i',j'}B_{j,j'}
|
|
|
|
USE io_global, ONLY : stdout
|
|
USE basic_structures, ONLY : ortho_polaw
|
|
|
|
implicit none
|
|
|
|
TYPE(polaw), INTENT(inout) :: pw!data
|
|
TYPE(ortho_polaw), INTENT(in) :: op!trasform
|
|
|
|
INTEGER :: iw,jw,kw
|
|
REAL(kind=DP), ALLOCATABLE :: mat(:,:)
|
|
|
|
|
|
|
|
if(op%numpw /= pw%numpw) then
|
|
write(stdout,*) 'ROUTINE ORTHONORMALIZE: BASIS INCONSISTENT'
|
|
stop
|
|
endif
|
|
|
|
allocate(mat(op%numpw,op%numpw))
|
|
|
|
call dgemm('N','N',op%numpw,op%numpw,op%numpw,1.d0,&
|
|
& op%on_mat,op%numpw,pw%pw,op%numpw,0.d0,mat,op%numpw)
|
|
|
|
|
|
|
|
call dgemm('N','T',op%numpw,op%numpw,op%numpw,1.d0,&
|
|
& mat,op%numpw,op%on_mat,op%numpw,0.d0,pw%pw,op%numpw)
|
|
|
|
|
|
deallocate(mat)
|
|
|
|
return
|
|
|
|
END SUBROUTINE
|
|
|
|
SUBROUTINE orthonormalize_inverse(op,pw)
|
|
!this subroutine rotates the pw data on the basis of the trasform op
|
|
!perform the trasform \sum_{i',j'} B_{i',i}P_{i',j'}B_{j',j}
|
|
|
|
USE io_global, ONLY : stdout
|
|
USE basic_structures, ONLY : ortho_polaw
|
|
|
|
implicit none
|
|
|
|
TYPE(polaw), INTENT(inout) :: pw!data
|
|
TYPE(ortho_polaw), INTENT(in) :: op!trasform
|
|
|
|
INTEGER :: iw,jw,kw
|
|
REAL(kind=DP), ALLOCATABLE :: mat(:,:)
|
|
|
|
|
|
|
|
if(op%numpw /= pw%numpw) then
|
|
write(stdout,*) 'ROUTINE ORTHONORMALIZE: BASIS INCONSISTENT'
|
|
stop
|
|
endif
|
|
|
|
allocate(mat(op%numpw,op%numpw))
|
|
|
|
call dgemm('T','N',op%numpw,op%numpw,op%numpw,1.d0,&
|
|
& op%on_mat,op%numpw,pw%pw,op%numpw,0.d0,mat,op%numpw)
|
|
|
|
|
|
|
|
call dgemm('N','N',op%numpw,op%numpw,op%numpw,1.d0,&
|
|
& mat,op%numpw,op%on_mat,op%numpw,0.d0,pw%pw,op%numpw)
|
|
|
|
|
|
|
|
deallocate(mat)
|
|
return
|
|
|
|
END SUBROUTINE
|
|
|
|
SUBROUTINE orthonormalize_vpot_inverse(op,vp)
|
|
!this subroutine rotates the v_pot data on the basis of the trasform op
|
|
!perform the trasform \sum_{i',j'} B_{i',i}P_{i',j'}B_{j',j}
|
|
|
|
USE io_global, ONLY : stdout
|
|
USE basic_structures, ONLY : v_pot, ortho_polaw
|
|
|
|
|
|
implicit none
|
|
|
|
TYPE(v_pot), INTENT(inout) :: vp!data
|
|
TYPE(ortho_polaw), INTENT(in) :: op!trasform
|
|
|
|
INTEGER :: iw,jw,kw
|
|
REAL(kind=DP), ALLOCATABLE :: mat(:,:)
|
|
|
|
|
|
if(op%numpw /= vp%numpw) then
|
|
write(stdout,*) 'ROUTINE ORTHONORMALIZE: BASIS INCONSISTENT'
|
|
stop
|
|
endif
|
|
|
|
allocate(mat(op%numpw,op%numpw))
|
|
! mat(:,:)=0.d0
|
|
! do iw=1,op%numpw
|
|
! do jw=1,op%numpw
|
|
! do kw=1,op%numpw
|
|
! mat(iw,jw)=mat(iw,jw)+op%on_mat(kw,iw)*vp%vmat(kw,jw)
|
|
! enddo
|
|
! enddo
|
|
! enddo
|
|
|
|
call dgemm('T','N',op%numpw,op%numpw,op%numpw,1.d0,op%on_mat,op%numpw,vp%vmat,op%numpw,0.d0,mat,op%numpw)
|
|
|
|
|
|
! vp%vmat(:,:)=0.d0
|
|
! do iw=1,op%numpw
|
|
! do kw=1,op%numpw
|
|
! do jw=1,op%numpw
|
|
! vp%vmat(iw,jw)=vp%vmat(iw,jw)+op%on_mat(kw,jw)*mat(iw,kw)
|
|
! enddo
|
|
! enddo
|
|
! enddo
|
|
|
|
call dgemm('N','N',op%numpw,op%numpw,op%numpw,1.d0,mat,op%numpw,op%on_mat,op%numpw,0.d0,vp%vmat,op%numpw)
|
|
|
|
|
|
|
|
|
|
deallocate(mat)
|
|
return
|
|
|
|
END SUBROUTINE
|
|
|
|
SUBROUTINE orthonormalize_vpot(op,vp)
|
|
!this subroutine rotates the v_pot data on the basis of the trasform op
|
|
!perform the trasform \sum_{i',j'} B_{i,i'}P_{i',j'}B_{j,j'}
|
|
|
|
USE io_global, ONLY : stdout
|
|
USE basic_structures, ONLY : v_pot, ortho_polaw
|
|
|
|
|
|
implicit none
|
|
|
|
TYPE(v_pot), INTENT(inout) :: vp!data
|
|
TYPE(ortho_polaw), INTENT(in) :: op!trasform
|
|
|
|
INTEGER :: iw,jw,kw
|
|
REAL(kind=DP), ALLOCATABLE :: mat(:,:)
|
|
|
|
|
|
if(op%numpw /= vp%numpw) then
|
|
write(stdout,*) 'ROUTINE ORTHONORMALIZE: BASIS INCONSISTENT'
|
|
stop
|
|
endif
|
|
|
|
allocate(mat(op%numpw,op%numpw))
|
|
|
|
! mat(:,:)=0.d0
|
|
! do iw=1,op%numpw
|
|
! do jw=1,op%numpw
|
|
! do kw=1,op%numpw
|
|
! mat(iw,jw)=mat(iw,jw)+op%on_mat(iw,kw)*vp%vmat(kw,jw)
|
|
! enddo
|
|
! enddo
|
|
! enddo
|
|
|
|
call dgemm('N','N',op%numpw,op%numpw,op%numpw,1.d0,op%on_mat,op%numpw,vp%vmat,op%numpw,0.d0,mat,op%numpw)
|
|
|
|
! vp%vmat(:,:)=0.d0
|
|
! do iw=1,op%numpw
|
|
! do jw=1,op%numpw
|
|
! do kw=1,op%numpw
|
|
! vp%vmat(iw,jw)=vp%vmat(iw,jw)+op%on_mat(jw,kw)*mat(iw,kw)
|
|
! enddo
|
|
! enddo
|
|
! enddo
|
|
|
|
call dgemm('N','T',op%numpw,op%numpw,op%numpw,1.d0,mat,op%numpw,op%on_mat,op%numpw,0.d0,vp%vmat,op%numpw)
|
|
|
|
|
|
deallocate(mat)
|
|
return
|
|
|
|
END SUBROUTINE orthonormalize_vpot
|
|
|
|
SUBROUTINE orthonormalize_vpot_para(op,vp)
|
|
!this subroutine rotates the v_pot data on the basis of the trasform op
|
|
!perform the trasform \sum_{i',j'} B_{i,i'}P_{i',j'}B_{j,j'}
|
|
!parallel version
|
|
|
|
USE io_global, ONLY : stdout
|
|
USE basic_structures, ONLY : v_pot, ortho_polaw
|
|
USE mp_world, ONLY : mpime, nproc, world_comm
|
|
USE mp, ONLY : mp_sum
|
|
|
|
|
|
implicit none
|
|
|
|
TYPE(v_pot), INTENT(inout) :: vp!data
|
|
TYPE(ortho_polaw), INTENT(in) :: op!trasform
|
|
|
|
INTEGER :: iw,jw,kw
|
|
REAL(kind=DP), ALLOCATABLE :: mat(:,:)
|
|
|
|
|
|
if(op%numpw /= vp%numpw) then
|
|
write(stdout,*) 'ROUTINE ORTHONORMALIZE: BASIS INCONSISTENT'
|
|
stop
|
|
endif
|
|
|
|
allocate(mat(op%numpw,op%numpw))
|
|
mat(:,:)=0.d0
|
|
do iw=1,op%numpw
|
|
do jw=1,op%numpw
|
|
if(mod(jw,nproc)==mpime) then
|
|
do kw=1,op%numpw
|
|
mat(iw,jw)=mat(iw,jw)+op%on_mat(iw,kw)*vp%vmat(kw,jw)
|
|
enddo
|
|
endif
|
|
enddo
|
|
call mp_sum(mat(iw,:),world_comm)
|
|
enddo
|
|
|
|
vp%vmat(:,:)=0.d0
|
|
do iw=1,op%numpw
|
|
do jw=1,op%numpw
|
|
if(mod(jw,nproc)==mpime) then
|
|
do kw=1,op%numpw
|
|
vp%vmat(iw,jw)=vp%vmat(iw,jw)+op%on_mat(jw,kw)*mat(iw,kw)
|
|
enddo
|
|
endif
|
|
enddo
|
|
call mp_sum(vp%vmat(iw,:),world_comm)
|
|
enddo
|
|
|
|
|
|
|
|
|
|
deallocate(mat)
|
|
return
|
|
|
|
END SUBROUTINE orthonormalize_vpot_para
|
|
|
|
|
|
|
|
|
|
SUBROUTINE invert_v_pot(vp,vpi)
|
|
!this subroutine inverts the coulombian matrix
|
|
!acting on space of orthonormal products of wanniers
|
|
USE io_global, ONLY : stdout
|
|
USE basic_structures, ONLY : v_pot, free_memory
|
|
|
|
implicit none
|
|
|
|
TYPE(v_pot), INTENT(in) :: vp !the descriptor of the coulombian matrix to be inverted
|
|
TYPE(v_pot), INTENT(inout) :: vpi !the descriptor of the inverted coulombian matrix
|
|
|
|
INTEGER :: info,lwork,i,j
|
|
INTEGER, ALLOCATABLE, DIMENSION(:) :: ipiv
|
|
REAL(kind=DP), ALLOCATABLE, DIMENSION(:) :: work
|
|
|
|
call free_memory(vpi)
|
|
|
|
lwork=vp%numpw
|
|
allocate(ipiv(vp%numpw))
|
|
allocate(work(lwork))
|
|
|
|
vpi%numpw=vp%numpw
|
|
allocate(vpi%vmat( vpi%numpw, vpi%numpw))
|
|
!write(stdout,*) size(vpi%vmat,1), size(vpi%vmat,2), size(vp%vmat,1), size(vp%vmat,2)
|
|
! vpi%vmat(:,:)=vp%vmat(:,:) ! bug
|
|
do j = 1, size(vpi%vmat,2)
|
|
do i = 1, size(vpi%vmat,1)
|
|
vpi%vmat(i,j)=vp%vmat(i,j)
|
|
end do
|
|
end do
|
|
|
|
call dgetrf(vpi%numpw,vpi%numpw,vpi%vmat,vpi%numpw,ipiv,info)
|
|
if(info /= 0) then
|
|
write(stdout,*) 'Invert V: problem with dgetrf :', info
|
|
stop
|
|
endif
|
|
|
|
call dgetri(vpi%numpw,vpi%vmat,vpi%numpw,ipiv,work,lwork,info)
|
|
if(info /= 0) then
|
|
write(stdout,*) 'Invert V: problem with dgetri :', info
|
|
stop
|
|
endif
|
|
|
|
deallocate(ipiv,work)
|
|
return
|
|
END SUBROUTINE invert_v_pot
|
|
|
|
SUBROUTINE fake_polarization_io(n)
|
|
!this subroutine just call mp_barrier 2*n+1 times
|
|
USE mp, ONLY : mp_barrier
|
|
USE mp_world, ONLY : world_comm
|
|
|
|
implicit none
|
|
|
|
INTEGER :: n
|
|
INTEGER :: i
|
|
!we take advantage of the t ==> -t symmetry
|
|
! do i=-n,n
|
|
do i=0,n
|
|
call mp_barrier( world_comm )
|
|
enddo
|
|
return
|
|
END SUBROUTINE fake_polarization_io
|
|
|
|
SUBROUTINE orthonormalize_vpot_inverse_para(op,vp)
|
|
!this subroutine rotates the v_pot data on the basis of the trasform op
|
|
!perform the trasform \sum_{i',j'} B_{i',i}P_{i',j'}B_{j',j}
|
|
!parallel version
|
|
|
|
USE io_global, ONLY : stdout
|
|
USE basic_structures, ONLY : v_pot, ortho_polaw
|
|
USE mp_world, ONLY : world_comm, mpime, nproc
|
|
USE mp, ONLY : mp_sum
|
|
|
|
implicit none
|
|
|
|
TYPE(v_pot), INTENT(inout) :: vp!data
|
|
TYPE(ortho_polaw), INTENT(in) :: op!trasform
|
|
|
|
INTEGER :: iw,jw,kw
|
|
REAL(kind=DP), ALLOCATABLE :: mat(:,:)
|
|
|
|
|
|
if(op%numpw /= vp%numpw) then
|
|
write(stdout,*) 'ROUTINE ORTHONORMALIZE: BASIS INCONSISTENT'
|
|
stop
|
|
endif
|
|
|
|
allocate(mat(op%numpw,op%numpw))
|
|
mat(:,:)=0.d0
|
|
do iw=1,op%numpw
|
|
do jw=1,op%numpw
|
|
if(mod(jw,nproc)==mpime) then
|
|
do kw=1,op%numpw
|
|
mat(iw,jw)=mat(iw,jw)+op%on_mat(kw,iw)*vp%vmat(kw,jw)
|
|
enddo
|
|
endif
|
|
enddo
|
|
call mp_sum(mat(iw,:),world_comm)
|
|
enddo
|
|
|
|
vp%vmat(:,:)=0.d0
|
|
do iw=1,op%numpw
|
|
do jw=1,op%numpw
|
|
if(mod(jw,nproc)==mpime) then
|
|
do kw=1,op%numpw
|
|
vp%vmat(iw,jw)=vp%vmat(iw,jw)+op%on_mat(kw,jw)*mat(iw,kw)
|
|
enddo
|
|
endif
|
|
enddo
|
|
call mp_sum(vp%vmat(iw,:),world_comm)
|
|
enddo
|
|
|
|
|
|
|
|
|
|
deallocate(mat)
|
|
return
|
|
|
|
END SUBROUTINE orthonormalize_vpot_inverse_para
|
|
|
|
SUBROUTINE create_polarization_contraction_state(time,pr,uu,l_hf_energies, ene_hf,options)
|
|
!this subroutine set the polarization in imaginary time
|
|
! as P(r,r',it)=G(r,r',it)*G(r,r',-it)
|
|
! for our basis
|
|
!uses contractions
|
|
!THERE IS ALSO A SPIN FACTOR 2
|
|
!if required uses HF energies
|
|
!use single occupied state contractions
|
|
|
|
USE io_global, ONLY : stdout
|
|
USE constants, ONLY : eps8
|
|
USE compact_product, ONLY : contraction_pola_state, free_memory_contraction_pola_state, &
|
|
&read_contraction_pola_state
|
|
USE basic_structures, ONLY : wannier_u
|
|
USE input_gw, ONLY : input_options
|
|
|
|
implicit none
|
|
|
|
REAL(kind=DP) :: time!imaginary time t, just a check
|
|
TYPE(polaw) :: pr!polarization P(it) to be created
|
|
TYPE(wannier_u) :: uu!for the KS energies
|
|
LOGICAL, INTENT(in) :: l_hf_energies!if true uses HF energies
|
|
REAL(kind=DP), INTENT(in) :: ene_hf(:)!HF energies
|
|
TYPE(input_options) :: options!for i/o purpoose
|
|
|
|
INTEGER :: iw,jw, vv, cc
|
|
INTEGER :: l,n,m,o
|
|
REAL(kind=DP) :: offset
|
|
REAL(kind=DP),ALLOCATABLE :: expene(:)!to calculate the exponentials just once
|
|
REAL(kind=DP),ALLOCATABLE :: exptmp(:)!temporary arrays for speed-up
|
|
REAL(kind=DP),ALLOCATABLE :: outmp(:,:)
|
|
REAL(kind=DP),ALLOCATABLE :: tmpc(:)
|
|
TYPE(contraction_pola_state) :: cps
|
|
|
|
!first annihilation
|
|
call free_memory_polaw(pr)
|
|
|
|
|
|
!set pr
|
|
pr%ontime=.true.
|
|
pr%time=time
|
|
|
|
!the following for accessing dimension of polarization matrix
|
|
cps%state=1
|
|
call read_contraction_pola_state(cps,options)
|
|
pr%numpw=cps%numpw
|
|
|
|
!calculates energy offset
|
|
|
|
if(.not.l_hf_energies) then
|
|
if(uu%nums > uu%nums_occ(1)) then
|
|
offset=-(uu%ene(uu%nums_occ(1)+1,1)+uu%ene(uu%nums_occ(1),1))/2.d0
|
|
else
|
|
offset=-uu%ene(uu%nums_occ(1),1)
|
|
endif
|
|
else
|
|
if(uu%nums > uu%nums_occ(1)) then
|
|
offset=-(ene_hf(uu%nums_occ(1)+1)+ene_hf(uu%nums_occ(1)))/2.d0
|
|
else
|
|
offset=-ene_hf(uu%nums_occ(1))
|
|
endif
|
|
endif
|
|
!calcualte exponentials of ks energies
|
|
|
|
allocate(expene(uu%nums))
|
|
|
|
if(.not.l_hf_energies) then
|
|
do vv=1,uu%nums_occ(1)
|
|
expene(vv)=exp((uu%ene(vv,1)+offset)*time)
|
|
enddo
|
|
do cc=uu%nums_occ(1)+1,uu%nums
|
|
expene(cc)=exp(-(uu%ene(cc,1)+offset)*time)
|
|
enddo
|
|
else
|
|
do vv=1,uu%nums_occ(1)
|
|
expene(vv)=exp((ene_hf(vv)+offset)*time)
|
|
enddo
|
|
do cc=uu%nums_occ(1)+1,uu%nums
|
|
expene(cc)=exp(-(ene_hf(cc)+offset)*time)
|
|
enddo
|
|
endif
|
|
|
|
!allocate
|
|
allocate(pr%pw( pr%numpw,pr%numpw))
|
|
pr%pw(:,:)=0.d0
|
|
|
|
allocate(exptmp(cps%nums-cps%nums_occ))
|
|
allocate(outmp(cps%nums-cps%nums_occ,pr%numpw))
|
|
allocate(tmpc(cps%nums-cps%nums_occ))
|
|
do vv=1,cps%nums_occ
|
|
cps%state=vv
|
|
write(stdout,*) 'read_contraction_pola_state'
|
|
if(vv /= 1) call read_contraction_pola_state(cps,options)
|
|
write(stdout,*) 'read_contraction_pola_state', vv
|
|
do cc=1,cps%nums-cps%nums_occ
|
|
exptmp(cc)=expene(vv)*expene(cc+cps%nums_occ)
|
|
enddo
|
|
do iw=1,pr%numpw
|
|
do cc=1,cps%nums-cps%nums_occ
|
|
outmp(cc,iw)=cps%ou(cc,iw)*exptmp(cc)
|
|
enddo
|
|
enddo
|
|
write(stdout,*) 'calculus1'
|
|
! do jw=1,pr%numpw
|
|
! do iw=jw,pr%numpw
|
|
! do cc=1,cps%nums-cps%nums_occ
|
|
! tmpc(cc)=cps%ou(cc,iw)*outmp(cc,jw)
|
|
! enddo
|
|
! pr%pw(iw,jw)=pr%pw(iw,jw)+sum(tmpc(:))
|
|
! enddo
|
|
! enddo
|
|
|
|
call dgemm('T','N',pr%numpw,pr%numpw,cps%nums-cps%nums_occ,1.d0,cps%ou,cps%nums-cps%nums_occ, &
|
|
outmp,cps%nums-cps%nums_occ,1.d0,pr%pw,pr%numpw)
|
|
|
|
call free_memory_contraction_pola_state(cps)
|
|
enddo
|
|
do jw=1,pr%numpw
|
|
do iw=jw,pr%numpw
|
|
pr%pw(jw,iw)=pr%pw(iw,jw)
|
|
enddo
|
|
enddo
|
|
! pr%pw(:,:)=(0.d0,-1.d0)*pr%pw(:,:)
|
|
pr%factor=(0.d0,-1.d0)
|
|
!now spin factor
|
|
pr%pw(:,:)=2.d0*pr%pw(:,:)
|
|
|
|
deallocate(expene)
|
|
deallocate(exptmp)
|
|
deallocate(outmp)
|
|
deallocate(tmpc)
|
|
return
|
|
END SUBROUTINE create_polarization_contraction_state
|
|
|
|
|
|
|
|
SUBROUTINE distribute_v_pot(vp,vpd)
|
|
!this subroutine distributes the coulomb matrix
|
|
! among processors
|
|
|
|
USE io_global, ONLY : stdout
|
|
USE basic_structures, ONLY : v_pot, free_memory
|
|
USE mp_world, ONLY : nproc,mpime
|
|
|
|
implicit none
|
|
|
|
TYPE(v_pot), INTENT(in) :: vp !the descriptor of the coulomb matrix to be distributed
|
|
TYPE(v_pot), INTENT(out) :: vpd!distributed coulomb matrix
|
|
|
|
INTEGER :: l_blk,nbegin,nend,ii
|
|
|
|
call free_memory(vpd)
|
|
|
|
vpd%numpw = vp%numpw
|
|
|
|
|
|
l_blk= vp%numpw/nproc
|
|
if(l_blk*nproc < vp%numpw) l_blk = l_blk+1
|
|
nbegin=mpime*l_blk+1
|
|
nend=nbegin+l_blk-1
|
|
if(nend > vp%numpw) nend = vp%numpw
|
|
|
|
allocate(vpd%vmat(vp%numpw,l_blk))
|
|
|
|
do ii=nbegin,nend
|
|
vpd%vmat(:,ii-nbegin+1)=vp%vmat(:,ii)
|
|
enddo
|
|
|
|
return
|
|
|
|
END SUBROUTINE distribute_v_pot
|
|
|
|
SUBROUTINE collect_v_pot(vp,vpd)
|
|
!this subroutine collects the coulomb matrix
|
|
! among processors
|
|
|
|
USE io_global, ONLY : stdout
|
|
USE basic_structures, ONLY : v_pot, free_memory
|
|
USE mp_world, ONLY : nproc,mpime,world_comm!group
|
|
USE parallel_include
|
|
|
|
implicit none
|
|
|
|
TYPE(v_pot), INTENT(out) :: vp !the descriptor of the coulomb matrix to be distributed
|
|
TYPE(v_pot), INTENT(in) :: vpd!distributed coulomb matrix
|
|
|
|
INTEGER :: l_blk,nbegin,nend,ierr
|
|
|
|
call free_memory(vp)
|
|
|
|
vp%numpw = vpd%numpw
|
|
|
|
l_blk= vp%numpw/nproc
|
|
if(l_blk*nproc < vp%numpw) l_blk = l_blk+1
|
|
nbegin=mpime*l_blk+1
|
|
nend=nbegin+l_blk-1
|
|
if(nend > vp%numpw) nend = vp%numpw
|
|
|
|
allocate(vp%vmat(vp%numpw,l_blk*nproc))
|
|
|
|
#if defined(__MPI)
|
|
call MPI_ALLGATHER(vpd%vmat,l_blk*vp%numpw,MPI_DOUBLE_PRECISION, vp%vmat, &
|
|
& l_blk*vp%numpw, MPI_DOUBLE_PRECISION,world_comm, ierr)
|
|
#else
|
|
vp%vmat(:,:)=vpd%vmat(:,:)
|
|
#endif
|
|
|
|
|
|
|
|
return
|
|
END SUBROUTINE collect_v_pot
|
|
|
|
SUBROUTINE calculate_w_g(vp,pp,ww,xc_together,l_symm_epsilon,l_head_epsilon,agz,head,l_divergence,inv_epsi, &
|
|
&l_wing_epsilon, awing, awing_c)
|
|
!this subroutine calculates W=(1+vp)^{-1}v
|
|
!this is meaningful only on frequency domain
|
|
!lapack routines are used
|
|
!it use exteded basis for G=0 term
|
|
|
|
|
|
USE io_global, ONLY : stdout
|
|
USE basic_structures, ONLY : v_pot, head_epsilon
|
|
|
|
implicit none
|
|
TYPE(v_pot) :: vp!coulomb potential
|
|
TYPE(polaw) :: pp!polarization on imaginary frequency, destroyed on exit
|
|
TYPE(polaw) :: ww!dressed interaction to be calculated
|
|
LOGICAL :: xc_together!if true the entire W is taken, otherwise W-v
|
|
LOGICAL :: l_symm_epsilon! if true uses the symmetrized form of the dielectric matrix
|
|
!for calculating W
|
|
LOGICAL :: l_head_epsilon!if true add to the symmetrized form of the dielectric matrix
|
|
!the head terms
|
|
REAL(kind=DP), DIMENSION(:) :: agz!terms A_ij<\tilde{w^P_j}|G=0>
|
|
REAL(kind=DP) :: head!term (G=0,G=0) of the symmetric dielectric matrix
|
|
LOGICAL, INTENT(in) :: l_divergence!if true calculate the head of the inverse dielectric matrix
|
|
REAL(kind=DP), INTENT(out) :: inv_epsi!head of the inverse dielectric matrix
|
|
LOGICAL, INTENT(in) :: l_wing_epsilon!if true calculate the wings of the symmetrized dielectric matrix
|
|
REAL(kind=DP), DIMENSION(:) :: awing!the terms A_ij wing_j
|
|
REAL(kind=DP), DIMENSION(:) :: awing_c!the terms A_ij wing_j
|
|
|
|
|
|
INTEGER iw,jw,kw
|
|
REAL(kind=DP), ALLOCATABLE, DIMENSION(:,:) :: dtmp!temporary array
|
|
INTEGER, ALLOCATABLE, DIMENSION(:) :: ipiv
|
|
INTEGER :: info
|
|
REAL(kind=DP),ALLOCATABLE, DIMENSION(:) :: work
|
|
INTEGER :: lwork
|
|
REAL(kind=DP) sca
|
|
REAL(kind=DP) :: workd
|
|
|
|
REAL(kind=DP) alpha
|
|
|
|
!deallocate if the case
|
|
call free_memory_polaw(ww)
|
|
|
|
|
|
!check and set
|
|
if(pp%ontime) then
|
|
write(stdout,*) 'Routine calculate_w: frequencies required'
|
|
stop
|
|
endif
|
|
if(pp%numpw /= vp%numpw) then
|
|
write(stdout,*) 'Routine calculate_w: basis set does not correspond',pp%numpw,vp%numpw
|
|
stop
|
|
endif
|
|
|
|
ww%ontime=.false.
|
|
ww%time=pp%time
|
|
ww%label=pp%label
|
|
ww%numpw=pp%numpw
|
|
allocate(ww%pw(ww%numpw,ww%numpw))
|
|
|
|
allocate(dtmp(ww%numpw+1,ww%numpw+1))
|
|
allocate(ipiv(ww%numpw+1))
|
|
|
|
dtmp(:,:)=0.d0
|
|
|
|
if(.not.l_symm_epsilon) then
|
|
!not symmetric case calculates -vP
|
|
call dgemm('N','N',ww%numpw,ww%numpw,ww%numpw,-1.d0*dble(pp%factor),&
|
|
& vp%vmat,ww%numpw,pp%pw,ww%numpw,0.d0,dtmp,ww%numpw+1)
|
|
else
|
|
!symmetric case calculates -v^1/2 P v^1/2
|
|
call dgemm('N','N',ww%numpw,ww%numpw,ww%numpw,-1.d0*dble(pp%factor),&
|
|
& vp%vmat,ww%numpw,pp%pw,ww%numpw,0.d0,dtmp,ww%numpw+1)
|
|
pp%pw(1:ww%numpw,1:ww%numpw)=dtmp(1:ww%numpw,1:ww%numpw)
|
|
call dgemm('N','N',ww%numpw,ww%numpw,ww%numpw,1.d0,&
|
|
& pp%pw,ww%numpw,vp%vmat,ww%numpw,0.d0,dtmp,ww%numpw+1)
|
|
endif
|
|
|
|
!calculate normalization factor alpha
|
|
|
|
sca=1.d0
|
|
do iw=1,ww%numpw
|
|
sca=sca-agz(iw)**2.d0
|
|
enddo
|
|
alpha=1.d0/sqrt(sca)
|
|
|
|
write(stdout,*) 'ALPHA :', alpha
|
|
FLUSH(stdout)
|
|
|
|
!calculate elements 0',0' 0',i i,O'
|
|
dtmp(ww%numpw+1,:)=0.d0
|
|
dtmp(:,ww%numpw+1)=0.d0
|
|
|
|
do iw=1,ww%numpw
|
|
do jw=1,ww%numpw
|
|
dtmp(ww%numpw+1,ww%numpw+1)=dtmp(ww%numpw+1,ww%numpw+1) &
|
|
& + alpha**2.d0 * agz(iw)* agz(jw)*dtmp(iw,jw)
|
|
enddo
|
|
enddo
|
|
|
|
do iw=1,ww%numpw
|
|
do jw=1,ww%numpw
|
|
dtmp(ww%numpw+1,iw)=dtmp(ww%numpw+1,iw)-alpha*dtmp(jw,iw)*agz(jw)
|
|
enddo
|
|
enddo
|
|
do iw=1,ww%numpw
|
|
dtmp(iw,ww%numpw+1)=dtmp(ww%numpw+1,iw)
|
|
enddo
|
|
|
|
!if required add the head
|
|
if(l_symm_epsilon .and.l_head_epsilon) then
|
|
|
|
! terms i,j
|
|
do jw=1,ww%numpw
|
|
do iw=1,ww%numpw
|
|
dtmp(iw,jw)=dtmp(iw,jw)+agz(iw)*agz(jw)*head
|
|
enddo
|
|
enddo
|
|
endif
|
|
!term O',0' 0',i i,0'
|
|
dtmp(ww%numpw+1,ww%numpw+1)= dtmp(ww%numpw+1,ww%numpw+1) + &
|
|
&head/alpha**2.d0
|
|
do iw=1,ww%numpw
|
|
dtmp(ww%numpw+1,iw)=dtmp(ww%numpw+1,iw)+head*agz(iw)/alpha
|
|
dtmp(iw,ww%numpw+1)=dtmp(iw,ww%numpw+1)+head*agz(iw)/alpha
|
|
enddo
|
|
|
|
|
|
|
|
!if required add the wings
|
|
!TODO ATTENZIONE
|
|
if(l_symm_epsilon .and.l_wing_epsilon) then
|
|
!elements i,j
|
|
do jw=1,ww%numpw
|
|
do iw=1,ww%numpw
|
|
dtmp(iw,jw)=dtmp(iw,jw)+agz(iw)*awing_c(jw)+agz(jw)*awing_c(iw)
|
|
enddo
|
|
enddo
|
|
! 0',0'
|
|
do iw=1,ww%numpw
|
|
dtmp(ww%numpw+1,ww%numpw+1)=dtmp(ww%numpw+1,ww%numpw+1) &
|
|
& - 2.d0*agz(iw)*awing_c(iw)
|
|
enddo
|
|
! 0',i ',0'
|
|
do iw=1,ww%numpw
|
|
dtmp(ww%numpw+1,iw)=dtmp(ww%numpw+1,iw)+awing(iw)/alpha
|
|
do jw=1,ww%numpw
|
|
dtmp(ww%numpw+1,iw)=dtmp(ww%numpw+1,iw)-alpha*agz(iw)*awing_c(jw)*agz(jw)
|
|
enddo
|
|
dtmp(iw,ww%numpw+1)=dtmp(ww%numpw+1,iw)
|
|
enddo
|
|
|
|
endif
|
|
|
|
do iw=1,ww%numpw+1
|
|
dtmp(iw,iw)=dtmp(iw,iw)+1.d0
|
|
enddo
|
|
|
|
|
|
!inverse zmat
|
|
|
|
write(stdout,*) 'Before inversion'
|
|
FLUSH(stdout)
|
|
call dgetrf(ww%numpw+1,ww%numpw+1,dtmp,ww%numpw+1,ipiv,info)
|
|
if(info /= 0) then
|
|
write(stdout,*) 'Routine calculate_w: problem with dgetrf :', info
|
|
stop
|
|
endif
|
|
write(stdout,*) 'Before inversion2'
|
|
FLUSH(stdout)
|
|
|
|
call dgetri(ww%numpw+1,dtmp,ww%numpw+1,ipiv,workd,-1,info)
|
|
write(stdout,*) 'Dimension', workd,ww%numpw,info!ATTENZIONE
|
|
FLUSH(stdout)
|
|
allocate(work(int(workd)))
|
|
call dgetri(ww%numpw+1,dtmp,ww%numpw+1,ipiv,work,int(workd),info)
|
|
|
|
write(stdout,*) 'Out of dgetri'
|
|
FLUSH(stdout)
|
|
|
|
|
|
if(info /= 0) then
|
|
write(stdout,*) 'Routine calculate_w: problem with zgetri :', info
|
|
stop
|
|
endif
|
|
|
|
|
|
if(.not.xc_together) then
|
|
do iw=1,ww%numpw+1
|
|
dtmp(iw,iw)=dtmp(iw,iw)-1.d0
|
|
enddo
|
|
endif
|
|
|
|
!if required calculates the head (G=0,G=0) of \epsilon^-1
|
|
|
|
if(l_divergence) then
|
|
inv_epsi=0.d0
|
|
|
|
!term i,j
|
|
do jw=1,ww%numpw
|
|
do iw=1,ww%numpw
|
|
inv_epsi = inv_epsi+dtmp(iw,jw)*agz(iw)*agz(jw)
|
|
enddo
|
|
enddo
|
|
!term 0',0'
|
|
inv_epsi=inv_epsi+dtmp(ww%numpw+1,ww%numpw+1)/alpha**2.d0
|
|
|
|
!terms 0',i i,0'
|
|
do iw=1,ww%numpw
|
|
inv_epsi=inv_epsi+2.d0*agz(iw)*dtmp(ww%numpw+1,iw)/alpha
|
|
enddo
|
|
|
|
|
|
do iw=1,ww%numpw+1
|
|
dtmp(iw,iw)=dtmp(iw,iw)-inv_epsi
|
|
enddo
|
|
endif
|
|
|
|
write(stdout,*) 'INV EPSI G=0,G=0', inv_epsi, dtmp(ww%numpw+1,ww%numpw+1)
|
|
FLUSH(stdout)
|
|
if(l_symm_epsilon .and.l_head_epsilon) then!ATTENZIONE
|
|
!take away the G=0,G=0 term
|
|
! terms i,j
|
|
write(stdout,*) 'Extract G=0,G=0 term'
|
|
do jw=1,ww%numpw
|
|
do iw=1,ww%numpw
|
|
dtmp(iw,jw)=dtmp(iw,jw)-agz(iw)*agz(jw)*inv_epsi
|
|
enddo
|
|
enddo
|
|
endif
|
|
|
|
|
|
|
|
|
|
if(.not. l_symm_epsilon) then
|
|
!calculates (e-1 -1)v
|
|
call dgemm('N','N',ww%numpw,ww%numpw,ww%numpw,1.d0,&
|
|
& dtmp,ww%numpw+1,vp%vmat,ww%numpw,0.d0,ww%pw,ww%numpw)
|
|
else
|
|
!calculates v^1/2 (e-1-1)v^1/2
|
|
call dgemm('N','N',ww%numpw,ww%numpw,ww%numpw,1.d0,&
|
|
& vp%vmat,ww%numpw,dtmp,ww%numpw+1,0.d0,pp%pw,ww%numpw)
|
|
call dgemm('N','N',ww%numpw,ww%numpw,ww%numpw,1.d0,&
|
|
& pp%pw,ww%numpw,vp%vmat,ww%numpw,0.d0,ww%pw,ww%numpw)
|
|
endif
|
|
|
|
|
|
ww%factor=(1.d0,0.d0)
|
|
|
|
! if(.not.xc_together) then
|
|
! do iw=1,ww%numpw
|
|
! do jw=1,ww%numpw
|
|
! ww%pw(iw,jw)=ww%pw(iw,jw)-vp%vmat(iw,jw)
|
|
! enddo
|
|
! enddo
|
|
! endif
|
|
|
|
|
|
deallocate(dtmp,ipiv,work)
|
|
return
|
|
END SUBROUTINE calculate_w_g
|
|
|
|
|
|
|
|
SUBROUTINE create_polarization_file(uu, tf, prefix)
|
|
|
|
USE basic_structures, ONLY : wannier_u, cprim_prod, free_memory, &
|
|
&initialize_memory_cprim_prod
|
|
USE times_gw, ONLY : times_freqs
|
|
USE mp_world, ONLY : world_comm, nproc,mpime
|
|
USE io_global, ONLY : stdout
|
|
USE mp, ONLY : mp_barrier
|
|
|
|
implicit none
|
|
|
|
TYPE(wannier_u), INTENT(in) :: uu!for the energies
|
|
TYPE(times_freqs) :: tf
|
|
CHARACTER(LEN=256), INTENT(in) :: prefix!to designate the PW files
|
|
|
|
INTEGER :: l_blk, nbegin, nend
|
|
INTEGER :: it,iv,ic, iw, jw
|
|
TYPE(polaw) :: pp
|
|
TYPE(cprim_prod) :: cpp
|
|
LOGICAL :: ok_read
|
|
REAL(kind=DP), ALLOCATABLE :: exp_table(:)
|
|
LOGICAL :: l_first!trick for gaining access to numpw, quite BAD
|
|
REAL(kind=DP), ALLOCATABLE :: cpmat_tmp(:,:)
|
|
|
|
write(stdout,*) 'Routine create_polarization_file'
|
|
|
|
allocate(exp_table(uu%nums-uu%nums_occ(1)))
|
|
|
|
!loop on time
|
|
|
|
l_blk= (tf%n+1)/nproc
|
|
if(l_blk*nproc < (tf%n+1)) l_blk = l_blk+1
|
|
nbegin=mpime*l_blk
|
|
nend=nbegin+l_blk-1
|
|
|
|
do it=nbegin,nend
|
|
|
|
|
|
if(it<= tf%n) then
|
|
call initialize_polaw(pp)
|
|
l_first=.true.
|
|
do iv=1,uu%nums_occ(1)
|
|
!loop on v
|
|
write(stdout,*) 'STATE', iv
|
|
FLUSH(stdout)
|
|
|
|
!set table of exponentials
|
|
|
|
do ic=uu%nums_occ(1)+1,uu%nums
|
|
exp_table(ic-uu%nums_occ(1))=exp((uu%ene(iv,1)-uu%ene(ic,1))*tf%times(it))
|
|
enddo
|
|
call mp_barrier( world_comm )
|
|
call initialize_memory_cprim_prod(cpp)
|
|
|
|
!!read in Svci
|
|
cpp%cprim=iv
|
|
call read_data_pw_cprim_prod(cpp, prefix, .true., ok_read, .true.,.false.)
|
|
!if required allocate polaw
|
|
|
|
if(l_first) then
|
|
allocate(pp%pw(cpp%numpw,cpp%numpw))
|
|
pp%pw(:,:)=0.d0
|
|
pp%numpw=cpp%numpw
|
|
l_first=.false.
|
|
endif
|
|
!!!!the following for using blas routine
|
|
allocate(cpmat_tmp(cpp%nums_cond,cpp%numpw))
|
|
call mytranspose(cpp%cpmat, cpp%numpw, cpmat_tmp, cpp%nums_cond, cpp%numpw, cpp%nums_cond)
|
|
do iw=1,cpp%numpw
|
|
cpmat_tmp(:,iw)=cpmat_tmp(:,iw)*exp_table(:)
|
|
enddo
|
|
|
|
!!!
|
|
!calculate term
|
|
! do ic=1,cpp%nums_cond
|
|
! do jw=1,cpp%numpw
|
|
! do iw=1,cpp%numpw
|
|
! pp%pw(iw,jw)=pp%pw(iw,jw)+cpp%cpmat(iw,ic)*cpp%cpmat(jw,ic)*exp_table(ic)
|
|
! enddo
|
|
! enddo
|
|
! enddo
|
|
|
|
|
|
call dgemm('N','N',cpp%numpw,cpp%numpw,cpp%nums_cond,1.d0,cpp%cpmat,cpp%numpw,&
|
|
&cpmat_tmp,cpp%nums_cond,1.d0,pp%pw,cpp%numpw)
|
|
|
|
deallocate(cpmat_tmp)
|
|
call free_memory(cpp)
|
|
enddo
|
|
!write polaw on file
|
|
!
|
|
pp%label=it
|
|
pp%time=tf%times(it)
|
|
pp%factor=(0.d0,-1.d0)
|
|
pp%numpw=cpp%numpw
|
|
pp%ontime=.true.
|
|
pp%pw(:,:)=pp%pw(:,:)*2.d0!for spin multiplicity
|
|
call write_polaw(pp,.false.)
|
|
call free_memory_polaw(pp)
|
|
else
|
|
!just parallelel reading of file
|
|
do iv=1,uu%nums_occ(1)
|
|
call mp_barrier( world_comm )
|
|
call initialize_memory_cprim_prod(cpp)
|
|
cpp%cprim=iv
|
|
call read_data_pw_cprim_prod(cpp, prefix, .true., ok_read, .true.,.false.)
|
|
call free_memory(cpp)
|
|
enddo
|
|
endif
|
|
enddo
|
|
|
|
deallocate(exp_table)
|
|
return
|
|
|
|
END SUBROUTINE create_polarization_file
|
|
|
|
|
|
SUBROUTINE square_root_polaw(pw,numpw)
|
|
!this subroutine calculate the square root of the polaw matrix
|
|
!it is done by calculating the eigenvalues and eigenvectors
|
|
!it assumes that the matrix is symmetric and positive definite
|
|
|
|
USE io_global, ONLY : stdout
|
|
|
|
implicit none
|
|
|
|
REAL(kind=DP) :: pw(numpw,numpw)!the matrix to be operated
|
|
INTEGER :: numpw!dimension of the matrix
|
|
|
|
REAL(kind=DP), ALLOCATABLE :: e_va(:), work(:)
|
|
REAL(kind=DP), ALLOCATABLE :: tmp_pw(:,:)
|
|
|
|
INTEGER :: lwork, info
|
|
REAL(kind=DP) :: loptwork
|
|
INTEGER :: iw,jw,kw
|
|
|
|
#if defined(_OPENMP)
|
|
INTEGER :: ntids
|
|
INTEGER :: omp_get_num_threads, omp_get_max_threads
|
|
EXTERNAL omp_set_num_threads, omp_get_num_threads, omp_get_max_threads
|
|
#endif
|
|
|
|
|
|
allocate(e_va(numpw))
|
|
allocate(tmp_pw(numpw, numpw))
|
|
|
|
tmp_pw(:,:)=pw(:,:)
|
|
|
|
#if defined(_OPENMP)
|
|
! go single-thread
|
|
ntids = omp_get_max_threads()
|
|
call omp_set_num_threads(1)
|
|
#endif
|
|
|
|
|
|
!check for optimal dimension
|
|
call DSYEV( 'V', 'U', numpw, tmp_pw, numpw, e_va, loptwork, -1, info)
|
|
|
|
lwork=int(loptwork)
|
|
allocate(work(lwork))
|
|
|
|
!calculate the eigenvalues, eigenvectors
|
|
|
|
call DSYEV( 'V', 'U', numpw, tmp_pw, numpw, e_va, work, lwork,info )
|
|
if(info /= 0) then
|
|
write(stdout,*) 'Problem with dsyev', info
|
|
stop
|
|
endif
|
|
|
|
#if defined(_OPENMP)
|
|
! go multi-thread
|
|
call omp_set_num_threads(ntids)
|
|
#endif
|
|
|
|
!do square root of eigenvector
|
|
do iw=1,numpw
|
|
if(e_va(iw) < 0.d0) then
|
|
write(stdout,*) 'Problem with eigenvalue', iw
|
|
stop
|
|
endif
|
|
e_va(iw)=dsqrt(e_va(iw))
|
|
enddo
|
|
|
|
!reform the matrix
|
|
|
|
pw(:,:)=0.d0
|
|
|
|
! Carlo substitute with DGEMM
|
|
do kw=1,numpw
|
|
do jw=1,numpw
|
|
do iw=1,numpw
|
|
pw(iw,jw)=pw(iw,jw)+tmp_pw(iw,kw)*tmp_pw(jw,kw)*e_va(kw)
|
|
enddo
|
|
enddo
|
|
enddo
|
|
|
|
deallocate(tmp_pw)
|
|
deallocate(work)
|
|
deallocate(e_va)
|
|
return
|
|
|
|
END SUBROUTINE square_root_polaw
|
|
|
|
|
|
SUBROUTINE create_polarization_beta(time, pr, uu, qm)
|
|
|
|
!this subroutine create the polarization with the strategy beta:
|
|
!P_ij(\tau)=\int dr dr' <\omega^{P'}_i(r)U_{v,v'}exp(E_v\tau)\tilde{\omega_v'}(r)*U_{v,v''}\tilde{\omega_v''}(r')
|
|
! *U_{c,c'}exp(E_c\tau)\tilde{\omega_c'}(r)U_{c,c''}\tilde{\omega_c''}(r)\omega^{P'}_j(r')
|
|
!it makes use of S_{i,vc}=\int dr \omega^{P'}_i(r)\tilde{\omega_v}(r)\tilde{\omega_c}(r)
|
|
|
|
|
|
USE basic_structures, ONLY : wannier_u, free_memory,q_mat, wannier_P
|
|
USE times_gw, ONLY : times_freqs
|
|
USE io_global, ONLY : stdout
|
|
|
|
implicit none
|
|
|
|
REAL(kind=DP), INTENT(in) :: time! imaginary time tau
|
|
TYPE(wannier_u), INTENT(in) :: uu!for the energies and trasformation matrix
|
|
TYPE(polaw), INTENT(out) :: pr!polarization P(it) to be created
|
|
TYPE(q_mat), INTENT(in) :: qm ! for S matrices
|
|
|
|
|
|
INTEGER :: i,j,k, ip, ii, jj
|
|
INTEGER :: nums_cond!number of conduction states
|
|
INTEGER :: iw,jw
|
|
REAL(kind=DP), ALLOCATABLE :: v_val(:,:), exp_table_v(:), v_cond(:,:), exp_table_c(:)
|
|
REAL(kind=DP), ALLOCATABLE :: tmp_mat1(:,:), tmp_mat2(:,:)
|
|
REAL(kind=DP) :: fermi_en
|
|
REAL(kind=DP), ALLOCATABLE :: q(:,:),t(:,:), v(:)
|
|
REAL(kind=DP), EXTERNAL :: ddot
|
|
|
|
write(stdout,*) 'Routine create_polarization_beta'
|
|
!0)set polarization structure
|
|
|
|
pr%ontime=.true.
|
|
pr%time=time
|
|
pr%numpw=qm%numpw
|
|
pr%factor=(0.d0,-1.d0)
|
|
!allocate
|
|
allocate(pr%pw( pr%numpw,pr%numpw))
|
|
pr%pw(:,:) =(0.d0,0.d0)
|
|
|
|
|
|
|
|
!1)calculate V_v'v''= U_{vv'}U_{v,v''}exp(E_v \tau}
|
|
allocate(v_val(uu%nums_occ(1),uu%nums_occ(1)))
|
|
allocate(exp_table_v(uu%nums_occ(1)))
|
|
|
|
!fermi_en is used to reduce the numerical error
|
|
fermi_en=(uu%ene(uu%nums_occ(1)+1,1)+uu%ene(uu%nums_occ(1),1))/2.d0
|
|
exp_table_v(1:uu%nums_occ(1))=exp((uu%ene(1:uu%nums_occ(1),1)-fermi_en)*abs(time))
|
|
|
|
v_val(:,:)=0.d0
|
|
|
|
allocate(tmp_mat1(uu%nums_occ(1),uu%nums_occ(1)), tmp_mat2(uu%nums_occ(1),uu%nums_occ(1)))
|
|
|
|
tmp_mat1(1:uu%nums_occ(1),1:uu%nums_occ(1))=dble(uu%umat(1:uu%nums_occ(1),1:uu%nums_occ(1),1))
|
|
do i=1,uu%nums_occ(1)
|
|
do j=1,uu%nums_occ(1)
|
|
tmp_mat2(i,j)=dble(uu%umat(i,j,1))*exp_table_v(i)
|
|
enddo
|
|
enddo
|
|
|
|
call dgemm('T','N',uu%nums_occ(1),uu%nums_occ(1),uu%nums_occ(1),1.d0,tmp_mat2,uu%nums_occ(1),tmp_mat1,uu%nums_occ(1),&
|
|
&0.d0,v_val,uu%nums_occ(1))
|
|
deallocate(tmp_mat1,tmp_mat2)
|
|
deallocate(exp_table_v)
|
|
|
|
!2) calculate V_c'c''= U_{c,c'}U_{c,c''}exp(-E_c \tau}
|
|
nums_cond=uu%nums-uu%nums_occ(1)
|
|
|
|
allocate(v_cond(nums_cond,nums_cond))
|
|
allocate(exp_table_c(nums_cond))
|
|
|
|
exp_table_c(1:nums_cond)=exp((-uu%ene(uu%nums_occ(1)+1:uu%nums,1) +fermi_en)*abs(time))
|
|
|
|
allocate(tmp_mat1(nums_cond,nums_cond), tmp_mat2(nums_cond,nums_cond))
|
|
|
|
tmp_mat1(1:nums_cond,1:nums_cond)=dble(uu%umat(uu%nums_occ(1)+1:uu%nums,uu%nums_occ(1)+1:uu%nums,1))
|
|
do i=1,nums_cond
|
|
do j=1,nums_cond
|
|
tmp_mat2(i,j)=dble(uu%umat(uu%nums_occ(1)+i,uu%nums_occ(1)+j,1))*exp_table_c(i)
|
|
enddo
|
|
enddo
|
|
|
|
call dgemm('T','N',nums_cond,nums_cond,nums_cond,1.d0,tmp_mat2,nums_cond,tmp_mat1,nums_cond,&
|
|
&0.d0,v_cond,nums_cond)
|
|
deallocate(tmp_mat1,tmp_mat2)
|
|
|
|
|
|
deallocate(exp_table_c)
|
|
|
|
do iw=1,pr%numpw
|
|
|
|
!calculate T_v''c'=S_{i,v'c'}V_{v',v''}
|
|
allocate(t(uu%nums_occ(1),nums_cond))
|
|
t(:,:)=0.d0
|
|
do ip=1,qm%wp(iw)%numij
|
|
i=qm%wp(iw)%ij(1,ip)!valence only
|
|
j=qm%wp(iw)%ij(2,ip)!valence and conduction
|
|
if(i>uu%nums_occ(1)) then
|
|
write(stdout,*) 'create_polarization_beta ERROR'
|
|
FLUSH(stdout)
|
|
stop
|
|
endif
|
|
!only valence*conduction products are required
|
|
if(j>uu%nums_occ(1)) then
|
|
do ii=1,uu%nums_occ(1)
|
|
t(ii,j-uu%nums_occ(1))=t(ii,j-uu%nums_occ(1))+qm%wp(iw)%o(ip)*v_val(i,ii)
|
|
enddo
|
|
endif
|
|
enddo
|
|
|
|
!calculate Q v''c''=T_{v''c'}V_{c'c''}
|
|
allocate( q(uu%nums_occ(1),nums_cond))
|
|
call dgemm('N','N',uu%nums_occ(1),nums_cond,nums_cond,1.d0,t,uu%nums_occ(1),v_cond,nums_cond,0.d0,&
|
|
&q,uu%nums_occ(1))
|
|
deallocate(t)
|
|
|
|
!put q on a right order for multiplication with S_{j,v''c''}
|
|
!WARNING WARNING ATTENZIONE
|
|
!it suppose that the wp(:)%ij are all the same
|
|
allocate(v(qm%wp(1)%numij))
|
|
v(:)=0.d0
|
|
do ip=1,qm%wp(iw)%numij
|
|
i=qm%wp(iw)%ij(1,ip)!valence only
|
|
j=qm%wp(iw)%ij(2,ip)!valence and conduction
|
|
if(j > uu%nums_occ(1)) then
|
|
v(ip)=q(i,j-uu%nums_occ(1))
|
|
endif
|
|
enddo
|
|
|
|
deallocate(q)
|
|
!product with jw
|
|
do jw=iw,pr%numpw
|
|
pr%pw(iw,jw)= ddot(qm%wp(iw)%numij,qm%wp(jw)%o,1,v,1)
|
|
pr%pw(jw,iw)=pr%pw(iw,jw)
|
|
enddo
|
|
|
|
deallocate(v)
|
|
enddo
|
|
!now spin factor
|
|
|
|
pr%pw(:,:)=2.d0*pr%pw(:,:)
|
|
|
|
deallocate(v_val,v_cond)
|
|
return
|
|
|
|
END SUBROUTINE create_polarization_beta
|
|
|
|
|
|
SUBROUTINE create_polarization_upper(uu, tf, prefix)
|
|
!this subroutine adds to the polarization the part from upper reduced states
|
|
|
|
USE basic_structures, ONLY : wannier_u, cprim_prod, free_memory, &
|
|
&initialize_memory, upper_states
|
|
USE times_gw, ONLY : times_freqs
|
|
USE mp_world, ONLY : nproc,mpime
|
|
USE io_global, ONLY : stdout
|
|
|
|
implicit none
|
|
|
|
TYPE(wannier_u), INTENT(in) :: uu!for the energies
|
|
TYPE(times_freqs), INTENT(in) :: tf !for grid on imaginary time
|
|
CHARACTER(LEN=256), INTENT(in) :: prefix!to designate the PW files
|
|
|
|
INTEGER :: l_blk, nbegin, nend
|
|
INTEGER :: it,iv,ic, iw, jw
|
|
TYPE(upper_states) :: us
|
|
TYPE(polaw) :: pp
|
|
TYPE(cprim_prod) :: cpp
|
|
LOGICAL :: ok_read
|
|
REAL(kind=DP), ALLOCATABLE :: exp_table(:)
|
|
REAL(kind=DP), ALLOCATABLE :: cpmat_tmp(:,:)
|
|
|
|
write(stdout,*) 'Routine create_polarization_upper'
|
|
|
|
|
|
!read-in upper states
|
|
call initialize_memory(us)
|
|
call read_data_pw_upper_states(us,prefix)
|
|
|
|
allocate(exp_table(us%nums_reduced))
|
|
|
|
|
|
|
|
|
|
|
|
!loop on time
|
|
|
|
l_blk= (tf%n+1)/nproc
|
|
if(l_blk*nproc < (tf%n+1)) l_blk = l_blk+1
|
|
nbegin=mpime*l_blk
|
|
nend=nbegin+l_blk-1
|
|
|
|
do it=nbegin,nend
|
|
|
|
|
|
if(it<= tf%n) then
|
|
!read polarization
|
|
call initialize_polaw(pp)
|
|
call read_polaw(it,pp,.false.,.false.)
|
|
do iv=1,uu%nums_occ(1)
|
|
!loop on v
|
|
write(stdout,*) 'STATE', iv
|
|
FLUSH(stdout)
|
|
|
|
!set table of exponentials
|
|
|
|
do ic=1,us%nums_reduced
|
|
exp_table(ic)=exp((uu%ene(iv,1)-us%ene(ic))*tf%times(it))
|
|
enddo
|
|
|
|
call initialize_memory(cpp)
|
|
|
|
!!read in Svci
|
|
cpp%cprim=iv
|
|
call read_data_pw_cprim_prod(cpp, prefix, .true., ok_read, .true.,.true.)
|
|
!if required allocate polaw
|
|
|
|
!!!!the following for using blas routine
|
|
allocate(cpmat_tmp(us%nums_reduced,cpp%numpw))
|
|
call mytranspose(cpp%cpmat, cpp%numpw, cpmat_tmp, us%nums_reduced, cpp%numpw, us%nums_reduced)
|
|
do iw=1,cpp%numpw
|
|
cpmat_tmp(:,iw)=cpmat_tmp(:,iw)*exp_table(:)
|
|
enddo
|
|
|
|
!!!
|
|
!calculate term
|
|
! do ic=1,cpp%nums_cond
|
|
! do jw=1,cpp%numpw
|
|
! do iw=1,cpp%numpw
|
|
! pp%pw(iw,jw)=pp%pw(iw,jw)+cpp%cpmat(iw,ic)*cpp%cpmat(jw,ic)*exp_table(ic)
|
|
! enddo
|
|
! enddo
|
|
! enddo
|
|
|
|
!factor 2 for spin multiplicity
|
|
call dgemm('N','N',cpp%numpw,cpp%numpw,us%nums_reduced,2.d0,cpp%cpmat,cpp%numpw,&
|
|
&cpmat_tmp,us%nums_reduced,1.d0,pp%pw,cpp%numpw)
|
|
|
|
deallocate(cpmat_tmp)
|
|
call free_memory(cpp)
|
|
enddo
|
|
!write polaw on file
|
|
!
|
|
|
|
call write_polaw(pp,.false.)
|
|
call free_memory_polaw(pp)
|
|
else
|
|
!just parallelel reading of file
|
|
do iv=1,uu%nums_occ(1)
|
|
call initialize_memory(cpp)
|
|
cpp%cprim=iv
|
|
call read_data_pw_cprim_prod(cpp, prefix, .true., ok_read, .true.,.true.)
|
|
call free_memory(cpp)
|
|
enddo
|
|
endif
|
|
enddo
|
|
|
|
deallocate(exp_table)
|
|
call free_memory(us)
|
|
return
|
|
|
|
END SUBROUTINE create_polarization_upper
|
|
|
|
|
|
|
|
|
|
SUBROUTINE calculate_w_g_l(vp,pp,ww,xc_together,l_head_epsilon,head,inv_epsi, &
|
|
&l_wing_epsilon, awing, awing_c, l_verbose)
|
|
!this subroutine calculates W=(1+vp)^{-1}v
|
|
!this is meaningful only on frequency domain
|
|
!lapack routines are used
|
|
!it use exteded basis for G=0 term
|
|
!version for lanczos chain scheme
|
|
|
|
USE io_global, ONLY : stdout
|
|
USE basic_structures, ONLY : v_pot, head_epsilon
|
|
|
|
implicit none
|
|
TYPE(v_pot) :: vp!coulomb potential
|
|
TYPE(polaw) :: pp!polarization on imaginary frequency, destroyed on exit
|
|
TYPE(polaw) :: ww!dressed interaction to be calculated
|
|
LOGICAL :: xc_together!if true the entire W is taken, otherwise W-v
|
|
LOGICAL :: l_head_epsilon!if true add to the symmetrized form of the dielectric matrix
|
|
!the head terms
|
|
REAL(kind=DP) :: head(3)!term (G=0,G=0) of the symmetric dielectric matrix
|
|
REAL(kind=DP), INTENT(out) :: inv_epsi!head of the inverse dielectric matrix
|
|
LOGICAL, INTENT(in) :: l_wing_epsilon!if true calculate the wings of the symmetrized dielectric matrix
|
|
REAL(kind=DP), DIMENSION(pp%numpw,3) :: awing!the terms A_ij wing_j
|
|
REAL(kind=DP), DIMENSION(pp%numpw,3) :: awing_c!the terms A_ij wing_j
|
|
LOGICAL, INTENT(in) :: l_verbose
|
|
|
|
INTEGER iw,jw,kw,ipol
|
|
REAL(kind=DP), ALLOCATABLE, DIMENSION(:,:) :: dtmp!temporary array
|
|
INTEGER, ALLOCATABLE, DIMENSION(:) :: ipiv
|
|
INTEGER :: info
|
|
REAL(kind=DP),ALLOCATABLE, DIMENSION(:) :: work
|
|
INTEGER :: lwork
|
|
REAL(kind=DP) sca
|
|
REAL(kind=DP) :: workd(1)
|
|
|
|
REAL(kind=DP) alpha
|
|
REAL(kind=DP) head_v
|
|
REAL(kind=DP), ALLOCATABLE :: pw_save(:,:)
|
|
|
|
!deallocate if the case
|
|
call free_memory_polaw(ww)
|
|
|
|
|
|
!check and set
|
|
if(pp%ontime) then
|
|
write(stdout,*) 'Routine calculate_w: frequencies required'
|
|
stop
|
|
endif
|
|
if(pp%numpw /= vp%numpw) then
|
|
write(stdout,*) 'Routine calculate_w: basis set does not correspond',pp%numpw,vp%numpw
|
|
stop
|
|
endif
|
|
|
|
ww%ontime=.false.
|
|
ww%time=pp%time
|
|
ww%label=pp%label
|
|
ww%numpw=pp%numpw
|
|
allocate(ww%pw(ww%numpw,ww%numpw))
|
|
|
|
allocate(dtmp(ww%numpw,ww%numpw))
|
|
allocate(ipiv(ww%numpw))
|
|
|
|
ww%pw(:,:)=0.d0
|
|
|
|
allocate(pw_save(pp%numpw,pp%numpw))
|
|
do ipol=1,3
|
|
if(l_verbose) write(stdout,*) 'MAX P:', maxval(pp%pw(:,:)), 'MIN P:', minval(pp%pw(:,:))
|
|
FLUSH(stdout)
|
|
if(ipol==1) then
|
|
pw_save(:,:)=pp%pw(:,:)
|
|
else
|
|
pp%pw(:,:)=pw_save(:,:)
|
|
endif
|
|
dtmp(:,:)=0.d0
|
|
|
|
head_v=vp%vmat(vp%numpw,vp%numpw)
|
|
|
|
!DEBUG
|
|
if(l_verbose) write(stdout,*) 'IRR POLA HEAD', pp%pw(pp%numpw,pp%numpw)
|
|
if(l_verbose) write(stdout,*) 'IRR POLA FIRST', pp%pw(1,1), l_wing_epsilon
|
|
|
|
! vp%vmat(vp%numpw,1:vp%numpw)=0.d0 !ATTENZIONE DEBUG
|
|
! vp%vmat(1:vp%numpw,vp%numpw)=0.d0
|
|
|
|
pp%pw(pp%numpw,1:pp%numpw)=0.d0
|
|
pp%pw(1:pp%numpw,pp%numpw)=0.d0
|
|
|
|
if(l_wing_epsilon) then!ATTENZIONE
|
|
! 0',i ',0'
|
|
do iw=1,ww%numpw-1
|
|
pp%pw(ww%numpw,iw)=awing(iw,ipol)
|
|
pp%pw(iw,ww%numpw)=pp%pw(ww%numpw,iw)
|
|
enddo
|
|
|
|
endif
|
|
|
|
|
|
!symmetric case calculates -v^1/2 P v^1/2
|
|
call dgemm('N','N',ww%numpw,ww%numpw,ww%numpw,-1.d0*dble(pp%factor),&
|
|
&vp%vmat,ww%numpw,pp%pw,ww%numpw,0.d0,dtmp,ww%numpw)
|
|
pp%pw(1:ww%numpw,1:ww%numpw)=dtmp(1:ww%numpw,1:ww%numpw)
|
|
call dgemm('N','N',ww%numpw,ww%numpw,ww%numpw,1.d0,&
|
|
& pp%pw,ww%numpw,vp%vmat,ww%numpw,0.d0,dtmp,ww%numpw)
|
|
|
|
|
|
|
|
|
|
|
|
!if required add the head
|
|
if(l_head_epsilon) then
|
|
|
|
|
|
!term O',0' 0',i i,0'
|
|
dtmp(ww%numpw,ww%numpw)= head(ipol)
|
|
if(l_verbose) write(stdout,*) 'APPLYING HEAD', head!DEBUG
|
|
endif
|
|
|
|
do iw=1,ww%numpw
|
|
dtmp(iw,iw)=dtmp(iw,iw)+1.d0
|
|
enddo
|
|
|
|
|
|
!inverse zmat
|
|
|
|
if(l_verbose) write(stdout,*) 'MAX D:', maxval(dtmp(:,:)), 'MIN D', minval(dtmp(:,:))
|
|
|
|
if(l_verbose) write(stdout,*) 'Before inversion'
|
|
FLUSH(stdout)
|
|
call dgetrf(ww%numpw,ww%numpw,dtmp,ww%numpw,ipiv,info)
|
|
if(info /= 0) then
|
|
write(stdout,*) 'Routine calculate_w: problem with dgetrf :', info
|
|
stop
|
|
endif
|
|
if(l_verbose) write(stdout,*) 'Before inversion2'
|
|
FLUSH(stdout)
|
|
|
|
call dgetri(ww%numpw,dtmp,ww%numpw,ipiv,workd,-1,info)
|
|
if(l_verbose) write(stdout,*) 'Dimension', workd,ww%numpw,info!ATTENZIONE
|
|
FLUSH(stdout)
|
|
allocate(work(int(workd(1))))
|
|
call dgetri(ww%numpw,dtmp,ww%numpw,ipiv,work,int(workd(1)),info)
|
|
|
|
if(l_verbose) write(stdout,*) 'Out of dgetri'
|
|
FLUSH(stdout)
|
|
|
|
if(l_verbose) write(stdout,*) 'MAX D1:', maxval(dtmp(:,:)), 'MIN D1:', minval(dtmp(:,:))
|
|
|
|
if(info /= 0) then
|
|
write(stdout,*) 'Routine calculate_w: problem with zgetri :', info
|
|
stop
|
|
endif
|
|
|
|
|
|
if(.not.xc_together) then
|
|
do iw=1,ww%numpw
|
|
dtmp(iw,iw)=dtmp(iw,iw)-1.d0
|
|
enddo
|
|
endif
|
|
|
|
|
|
inv_epsi=0.d0
|
|
|
|
!term i,j
|
|
!term 0',0'
|
|
inv_epsi=dtmp(ww%numpw,ww%numpw)
|
|
|
|
write(stdout,*) 'INV EPSI G=0,G=0', inv_epsi, head_v
|
|
FLUSH(stdout)
|
|
|
|
vp%vmat(vp%numpw,vp%numpw)=head_v
|
|
dtmp(ww%numpw,1:ww%numpw-1)=0.d0
|
|
dtmp(1:ww%numpw-1,ww%numpw)=0.d0
|
|
|
|
!DEBUG
|
|
! dtmp(:,:)=0.d0
|
|
! do iw=1,ww%numpw
|
|
! dtmp(iw,iw)=inv_epsi
|
|
! enddo
|
|
! dtmp(ww%numpw,ww%numpw)=0.d0
|
|
|
|
!DEBUG
|
|
if(l_verbose) write(stdout,*) 'MAX D2:', maxval(dtmp(:,:)), 'MIN D2:', minval(dtmp(:,:))
|
|
FLUSH(stdout)
|
|
|
|
!calculates v^1/2 (e-1-1)v^1/2
|
|
call dgemm('N','N',ww%numpw,ww%numpw,ww%numpw,1.d0,&
|
|
& vp%vmat,ww%numpw,dtmp,ww%numpw,0.d0,pp%pw,ww%numpw)
|
|
call dgemm('N','N',ww%numpw,ww%numpw,ww%numpw,1.d0,&
|
|
& pp%pw,ww%numpw,vp%vmat,ww%numpw,1.d0,ww%pw,ww%numpw)
|
|
|
|
if(l_verbose) write(stdout,*) 'MAX W:', maxval(ww%pw(:,:)), 'MIN W:', minval(ww%pw(:,:))
|
|
FLUSH(stdout)
|
|
|
|
|
|
deallocate(work)
|
|
enddo
|
|
deallocate(pw_save)
|
|
ww%pw(:,:)=ww%pw(:,:)/3.d0
|
|
! ww%pw(1:ww%numpw-1,1:ww%numpw-1)=0.d0
|
|
! ww%pw(:,ww%numpw)=0.d0
|
|
ww%factor=(1.d0,0.d0)
|
|
|
|
if(l_verbose) write(stdout,*) 'MAX:', maxval(ww%pw(:,:)), 'MIN:', minval(ww%pw(:,:))
|
|
FLUSH(stdout)
|
|
|
|
|
|
deallocate(dtmp,ipiv)
|
|
return
|
|
END SUBROUTINE calculate_w_g_l
|
|
|
|
|
|
|
|
|
|
|
|
END MODULE polarization
|
|
|