dysonvirtatom.f90 Source File


Source Code

!-------------------------------------------------------------------------------
!> Summary: Dyson equation for the virtual atom
!> Author: 
!> this is part of the 'u-transformation' (see PhD David Bauer) 
!> which can be used to shift positions of impurity atoms with respect 
!> to their original position. It is intended for relaxations of impurities 
!-------------------------------------------------------------------------------
module mod_dysonvirtatom
contains

!-------------------------------------------------------------------------------
!> Summary: Dyson equation for the virtual atom
!> Author: 
!> Category: KKRimp, geometry, structural-greensfunction
!> Deprecated: False
!> this is part of the 'u-transformation' (see PhD David Bauer) 
!> which can be used to shift positions of impurity atoms with respect 
!> to their original position. It is intended for relaxations of impurities 
!-------------------------------------------------------------------------------
subroutine dysonvirtatom(natom,ntotatom,lmsizehost,gmathost,tmat,killatom, &
                         isvatom,lmaxatom,gmatimp,nlmhostnew,lattice_relax,NSOC)
use mod_mathtools
use mod_config, only: config_testflag
  implicit none
!interface
integer,intent( in)              :: natom      !! Number of atoms in impurity cluster, excl. "killed atoms"
integer,intent( in)              :: ntotatom   !! Number of host sites where GF is read in, incl. "killed atoms"
integer,intent( in)              :: lmsizehost !! Host lm-max * NSOC (see below for NSOC)
double complex,intent( in)       :: gmathost(ntotatom*lmsizehost, ntotatom*lmsizehost)
double complex,intent( in)       :: tmat(lmsizehost,lmsizehost,ntotatom)
integer,intent( in)              :: killatom(ntotatom)
integer,intent( in)              :: isvatom(ntotatom)
integer,intent( in)              :: lmaxatom(ntotatom) !! lmax to be used for specific atom
integer,intent( in)              :: lattice_relax
integer,intent( in)              :: NSOC         !! =2 if host-GF is 2x2 in spin space; =1 otherwise
double complex,intent(out),allocatable  :: gmatimp(:,:)

!local
integer                          :: iatom
integer                          :: nlmhostnew,lmstart,lmstart2,lmstop,lmstop2
integer                          :: ilm,iat_imp1,iat_imp2,iat_host1,iat_host2,isoc1,isoc2
integer                          :: lmmax_imp1,lmmax_imp2
integer                          :: istart_host1,istop_host1,istart_host2,istop_host2 
integer                          :: istart_imp1,istart_imp2,istop_imp1,istop_imp2
integer                          :: ilms_start_imp1,ilms_start_imp2

double complex,allocatable                   :: gmatout(:,:)
double complex,allocatable                   :: tmatbig(:,:)
double complex,allocatable                   :: gmatnew(:,:)

allocate(gmatout(ntotatom*lmsizehost, ntotatom*lmsizehost), &
                 tmatbig(lmsizehost*ntotatom,lmsizehost*ntotatom), &
                 gmatnew(lmsizehost*ntotatom,lmsizehost*ntotatom))


tmatbig=(0.0D0,0.0D0)
do iatom=1,ntotatom
  lmstart=lmsizehost*(iatom-1)+1


    if (isvatom(iatom)==0) then !killatom(iatom)==1
      tmatbig(lmstart:lmstart-1+lmsizehost,lmstart:lmstart-1+lmsizehost) = tmat(:,:,iatom)
    end if

! ##############################################################
! better version as the one above maybe replace in the future
! ##############################################################
if(.false.) then
  if (isvatom(iatom)==0) then !killatom(iatom)==1

    call matmat_dcdc(gmathost(:,lmstart:lmstart-1+lmsizehost), tmat(:,:,iatom),gmatnew(:,lmstart:lmstart-1+lmsizehost))
  else
    gmatnew(:,lmstart:lmstart-1+lmsizehost) = (0.0D0,0.0D0)
  end if
end if

 end do

call matmat_dcdc(gmathost,tmatbig,gmatnew)


! *******   calculate        *********
! gmatnew= gmatnew + 1
! ************************************
do ilm=1,ntotatom*lmsizehost
  gmatnew(ilm,ilm)=gmatnew(ilm,ilm)+(1.0D0,0.0D0)
end do

! *******   calculate        *********
! gmatout = inverse(gmatnew)*g
! ************************************

gmatout=gmathost


if (.not. config_testflag('nopredyson')) then
  call linearsolve_dc(gmatnew,gmatout)
end if !(.not. config_testopt('nodyson')) then





allocate( gmatimp(nlmhostnew,nlmhostnew) )



gmatnew=(0.0D0,0.0D0)
lmstart2=1 !-(lmaxatom(1)+1)**2

if (lattice_relax==0) then

   ! Starting point for atom 1 of impurity-block
   ilms_start_imp1 = 1
   iat_imp1 = 1

   ! Loop 1 over host block
   do iat_host1 = 1,ntotatom

      ! Exclude killed atoms
      if (killatom(iat_host1)/=1) then 
         lmmax_imp1 = (lmaxatom(iat_imp1)+1)**2

         ! Starting point for atom 2 of impurity-block
         ilms_start_imp2 = 1
         iat_imp2 = 1
         ! Loop 2 over host block
         do iat_host2 = 1,ntotatom

            ! Exclude killed atoms
            if (killatom(iat_host2)/=1) then
               lmmax_imp2 = (lmaxatom(iat_imp2)+1)**2

               !-------------------------------------------------------------
               ! Loop over spins (both spin directions in case of NSOC=2)
               do isoc1 = 1,NSOC                   ! NSOC=2 if host GF is 2x2 matrix in spin space 
               do isoc2 = 1,NSOC                   ! NSOC=1 otherwise

                  ! Select block from the host GF matrix
                  ! Remember, lmsizehost includes spin index in case of SOC
                  istart_host1 = (iat_host1 - 1)*lmsizehost + (isoc1 - 1)*lmsizehost/NSOC + 1
                  istop_host1 = istart_host1 + lmmax_imp1 - 1   
                  istart_host2 = (iat_host2 - 1)*lmsizehost + (isoc2 - 1)*lmsizehost/NSOC + 1
                  istop_host2 = istart_host2 +  lmmax_imp2 - 1   

                  ! Select block from the impurity GF matrix
                  ! Remember, lmmax_imp does _not_ include spin index
                  istart_imp1 = ilms_start_imp1 + (isoc1 - 1) * lmmax_imp1
                  istop_imp1 = istart_imp1 + lmmax_imp1 - 1
                  istart_imp2 = ilms_start_imp2 + (isoc2 - 1) * lmmax_imp2
                  istop_imp2 = istart_imp2 + lmmax_imp2 - 1


                  ! Write out the copied blocks for test case
                  !write(*,*) 'dysonviratom:--------------------------------'
                  !write(*,*) 'dysonviratom: isoc1 isoc2',isoc1,isoc2
                  !write(*,*) 'dysonviratom:--------------------------------'
                  !write(*,*) 'dysonviratom: atoms',iat_host1,iat_host2,iat_imp1,iat_imp2
                  !write(*,*) 'dysonviratom: host',istart_host1 ,istop_host1, istart_host2 ,istop_host2
                  !write(*,*) 'dysonviratom:  imp',istart_imp1 ,istop_imp1, istart_imp2 ,istop_imp2

                  ! Copy lmmax x lmmax block
                  gmatimp(istart_imp1 :istop_imp1, istart_imp2 :istop_imp2 ) =        &
                & gmatout(istart_host1:istop_host1,istart_host2:istop_host2)

               enddo ! isoc2 = 1,NSOC 
               enddo ! isoc1 = 1,NSOC 
               !-------------------------------------------------------------


            ! Shift starting point of next block for impurity 2 to next atom
            ilms_start_imp2 = ilms_start_imp2 + lmmax_imp2 * NSOC
            endif ! (killatom(iat_host2)/=1)
            iat_imp2 = iat_imp2 + 1 ! This is outside the if-block because the lmax(impurity) from 
                                    ! the kkrflex_atominfo file is read in even for the killed atoms.

         enddo ! iat_host2 = 1,ntotatom

      ! Shift starting point of next block for impurity 1 to next atom
      ilms_start_imp1 = ilms_start_imp1 + lmmax_imp1 * NSOC
      endif ! (killatom(iat_host1)/=1)
      iat_imp1 = iat_imp1 + 1


   enddo ! iat_host1 = 1,ntotatom


else  ! (lattice_relax==0)

  do iatom=1,ntotatom
    lmstart=(iatom-1)*lmsizehost+1
    lmstop = lmstart+lmsizehost-1
    if (killatom(iatom)/=1) then
      lmstop2  = lmstart2-1 + lmsizehost
      gmatnew(:,lmstart2:lmstop2)=gmatout(:,lmstart:lmstop)
      lmstart2 = lmstart2   + lmsizehost
    end if
  end do

  lmstart2=1 !-(lmaxatom(1)+1)**2
  do iatom=1,ntotatom
    lmstart=(iatom-1)*lmsizehost+1
    lmstop = lmstart+lmsizehost-1
    if (killatom(iatom)/=1) then
      lmstop2  = lmstart2-1 + lmsizehost
      gmatimp(lmstart2:lmstop2,:)=gmatnew(lmstart:lmstop,:)
      lmstart2 = lmstart2   + lmsizehost
    end if
  end do

end if  ! (lattice_relax==0)



end subroutine dysonvirtatom




  !-------------------------------------------------------------------------------
  !> Summary: Matrix multiplication
  !> Author: 
  !> Category: KKRimp, numerical-tools
  !> Deprecated: False
  !>
  !> Check dimensions of the two matrices and multiply them
  !-------------------------------------------------------------------------------
  !> @note
  !> Maybe it can be substituted just by the matriz multiplication (matmul).
  !> @endnote
  !-------------------------------------------------------------------------------
      subroutine matmat_dcdc(mat1,mat2,matout)
      implicit none
      double complex, intent(in) :: mat1(:,:),mat2(:,:)
      double complex             :: matout(size(mat1,1),size(mat2,2))
      integer                :: n1,n,n2
      n1 = size(mat1,1)
      n  = size(mat1,2)
      n2 = size(mat2,2)
      if(size(mat2,1).ne.n) stop 'matmat_zmzm: dimensions of matrices are inconsistent.'
      call zgemm('N','N',n1,n2,n,(1d0,0d0),mat1,n1,mat2,n,(0d0,0d0),matout,n1)
      end subroutine matmat_dcdc



end module mod_dysonvirtatom