LCOV - code coverage report
Current view: top level - eigen - local_hamiltonian.F90 (source / functions) Hit Total Coverage
Test: FLEUR test coverage Lines: 73 109 67.0 %
Date: 2024-04-28 04:28:00 Functions: 4 5 80.0 %

          Line data    Source code
       1             : MODULE m_local_Hamiltonian
       2             :    USE m_judft
       3             :    IMPLICIT NONE
       4             :    PRIVATE
       5             :    PUBLIC:: local_ham
       6             :   !*********************************************************************
       7             :   !     sets up the local Hamiltonian, i.e. the Hamiltonian in the
       8             :   !     l',m',l,m,u- basis which is independent from k!
       9             :   !     shifts this local Hamiltonian to make it positive definite
      10             :   !     and does a cholesky decomposition
      11             :   !*********************************************************************
      12             : CONTAINS
      13         748 :    SUBROUTINE local_ham(sphhar,atoms,sym,noco,nococonv,enpara,&
      14             :        fmpi,v,vx,inden,input,hub1inp,hub1data,td,ud,alpha_hybrid,l_dfptmod)
      15             :       !! Should probably be called tlmplm_postprocess or something, as there is a
      16             :       !! lot more happening than only the Cholesky decomposition.
      17             : 
      18             :       ! Add onto the t_{L'L}^{\mu} matrices from tlmplm some contributions from
      19             :       ! DFT+U, DFT+HIA, DFT+OPC, constraint fields and the diagonal E_{l} terms
      20             :       ! etc. In the diagonal case, Cholesky decompose the nonspherical part of
      21             :       ! the Hamiltonian by shifting the diagonal part upwards until the matrix
      22             :       ! is positive-definite.
      23             :       USE m_spnorb
      24             :       USE m_tlmplm
      25             :       USE m_types
      26             :     
      27             :       TYPE(t_mpi),      INTENT(IN)    :: fmpi
      28             :       TYPE(t_noco),     INTENT(IN)    :: noco
      29             :       TYPE(t_nococonv), INTENT(IN)    :: nococonv
      30             :       TYPE(t_input),    INTENT(IN)    :: input
      31             :       TYPE(t_sphhar),   INTENT(IN)    :: sphhar
      32             :       TYPE(t_atoms),    INTENT(IN)    :: atoms
      33             :       TYPE(t_sym),      INTENT(IN)    :: sym
      34             :       TYPE(t_enpara),   INTENT(IN)    :: enpara
      35             :       TYPE(t_hub1inp),  INTENT(IN)    :: hub1inp
      36             :       TYPE(t_hub1data), INTENT(INOUT) :: hub1data
      37             :       TYPE(t_potden),   INTENT(IN)    :: v,vx,inden
      38             :       TYPE(t_tlmplm),   INTENT(INOUT) :: td
      39             :       TYPE(t_usdus),    INTENT(INOUT) :: ud
      40             : 
      41             :       ! Scalar Arguments
      42             :       
      43             :       REAL,    INTENT(IN) :: alpha_hybrid
      44             : 
      45             :       LOGICAL, INTENT(IN),OPTIONAL :: l_dfptmod
      46             : 
      47             :       ! Local Scalars
      48             :       INTEGER :: l,lm,j1,j2,jsp
      49             :       INTEGER :: n,m,s
      50             :       COMPLEX :: one
      51             : 
      52         748 :       CALL timestart("local_hamiltonian")
      53        2150 :       CALL td%init(atoms,input%jspins,(noco%l_noco.AND.noco%l_soc.AND..NOT.noco%l_ss).OR.any(noco%l_constrained))
      54             : 
      55        4578 :       DO jsp=1,MERGE(4,input%jspins,any(noco%l_unrestrictMT).OR.any(noco%l_spinoffd_ldau))
      56             : 
      57        4312 :          DO j1=merge(jsp,1,jsp<3),merge(jsp,2,jsp<3)
      58        1232 :             j2  = MERGE(j1,3-j1,jsp<3)
      59        1232 :             one = MERGE(CMPLX(1.,0.),CMPLX(0.,1.),jsp<4)
      60        1232 :             one = MERGE(CONJG(one),one,j1<j2)
      61             : 
      62             :             !$OMP PARALLEL DO DEFAULT(NONE) PRIVATE(l,m,lm,s)&
      63        1232 :             !$OMP SHARED(atoms,sphhar,sym,enpara,nococonv,j1,j2,jsp,fmpi,v,vx,input,hub1inp,hub1data,td,ud,alpha_hybrid,one,l_dfptmod,noco)
      64             :             DO  n = 1,atoms%ntype
      65             :                IF (j1==j2.OR.noco%l_unrestrictMT(n)) THEN
      66             :                   CALL tlmplm(n,sphhar,atoms,sym,enpara,nococonv,j1,j2,jsp,fmpi,v,vx,input,hub1inp,hub1data,td,ud,alpha_hybrid,one,PRESENT(l_dfptmod))
      67             :                END IF
      68             :                !Copy local hamiltonian for non_spherical setup
      69             :                call restrict_to_lnonsph(td%h_loc(:,:,n,j1,j2),td%h_loc2(n),td%h_loc2_nonsph(n),td%h_loc_nonsph(:,:,n,j1,j2))
      70             :                ! Now add diagonal contributions to the matrices:
      71             :                IF (jsp<3) THEN
      72             :                   DO l = 0,atoms%lmax(n)
      73             :                      DO  m = -l,l
      74             :                         lm = l*(l+1) + m
      75             :                         s = td%h_loc2(n)
      76             :                         td%h_loc(lm,lm,n,jsp,jsp)     = td%h_loc(lm,lm,n,jsp,jsp)     + enpara%el0(l,n,jsp)
      77             :                         td%h_loc(lm,lm+s,n,jsp,jsp)   = td%h_loc(lm,lm+s,n,jsp,jsp)   + 0.5 ! Symmetrized from 1.0
      78             :                         td%h_loc(lm+s,lm,n,jsp,jsp)   = td%h_loc(lm+s,lm,n,jsp,jsp)   + 0.5 ! Symmetrized from 0.0
      79             :                         td%h_loc(lm+s,lm+s,n,jsp,jsp) = td%h_loc(lm+s,lm+s,n,jsp,jsp) + enpara%el0(l,n,jsp)*ud%ddn(l,n,jsp)
      80             :                      END DO
      81             :                   END DO
      82             :                END IF
      83             :                ! Store Matrices needed for LOs 
      84             :                if (atoms%nlotot>0) call restrict_to_lnonsph(td%h_loc(:,:,n,j1,j2),td%h_loc2(n),td%h_loc2_nonsph(n),td%h_loc_LO(:,:,n,j1,j2))
      85             :             ENDDO
      86             :             !$OMP end parallel do
      87             :             !Add LDA+U
      88        1232 :             call add_ldaU(fmpi,inden,jsp,atoms,v,ud,input,hub1data,enpara,td%h_loc_nonsph,td%h_loc2_nonsph,j1,j2,.false.)
      89             :             !Add LDA+U also to LO part   
      90        1232 :             if (atoms%nlotot>0) call add_ldaU(fmpi,inden,jsp,atoms,v,ud,input,hub1data,enpara,td%h_loc_LO,td%h_loc2_nonsph,j1,j2,.true.)
      91             :             ! Create Cholesky decomposition of local hamiltonian
      92             :             ! For DFPT, do not decompose!
      93        1232 :             IF (jsp<3.AND..NOT.PRESENT(l_dfptmod)) THEN
      94        1144 :                call cholesky_decompose(td%h_loc_nonsph(:,:,:,j1,j2),td%e_shift(:,jsp),atoms,ud,jsp)
      95             :             endif
      96             : 
      97        4558 :             IF (any(noco%l_constrained)) CALL tlmplm_constrained(atoms,v,enpara,input,hub1data,ud,nococonv,td)
      98             :          END DO
      99             :       END DO
     100             : 
     101             :       !Setup of soc parameters for first-variation SOC
     102         748 :       IF (noco%l_soc.AND.noco%l_noco.AND..NOT.noco%l_ss) THEN
     103          64 :          CALL spnorb(atoms,noco,nococonv,input,fmpi,enpara,v%mt,ud,td%rsoc,.FALSE.,hub1inp,hub1data)
     104             :       END IF
     105         748 :       CALL timestop("local_hamiltonian")
     106         748 :    END SUBROUTINE 
     107             : 
     108           0 :    SUBROUTINE tlmplm_constrained(atoms,v,enpara,input,hub1data,ud,nococonv,td)
     109             :       USE m_radovlp
     110             :       USE m_types
     111             :       USE m_tlmplm
     112             :       TYPE(t_input),    INTENT(IN)    :: input
     113             :       TYPE(t_atoms),    INTENT(IN)    :: atoms
     114             :       TYPE(t_enpara),   INTENT(IN)    :: enpara
     115             :       TYPE(t_potden),   INTENT(IN)    :: v
     116             :       TYPE(t_tlmplm),   INTENT(INOUT) :: td
     117             :       TYPE(t_usdus),    INTENT(INOUT) :: ud
     118             :       TYPE(t_nococonv), INTENT(IN)    :: nococonv
     119             :       TYPE(t_hub1data), INTENT(IN)    :: hub1data
     120             : 
     121           0 :       REAL, ALLOCATABLE :: uun21(:,:),udn21(:,:),dun21(:,:),ddn21(:,:)
     122             :  
     123             :       COMPLEX :: c
     124             :       INTEGER :: n,l,s
     125             : 
     126             :       ALLOCATE(uun21(0:atoms%lmaxd,atoms%ntype),udn21(0:atoms%lmaxd,atoms%ntype), &
     127           0 :              & dun21(0:atoms%lmaxd,atoms%ntype),ddn21(0:atoms%lmaxd,atoms%ntype))
     128             : 
     129           0 :       CALL rad_ovlp(atoms,ud,input,hub1data,v%mt,enpara%el0,uun21,udn21,dun21,ddn21)
     130             : 
     131           0 :       DO  n = 1,atoms%ntype
     132             :          ! In a constraint calculation, we have to calculate the local spin
     133             :          ! off-diagonal contributions
     134             : 
     135           0 :          s=atoms%lnonsph(n)+1
     136             :          ! First ispin=1,jspin=2 case
     137           0 :          DO l=0, atoms%lnonsph(n)
     138           0 :             c = (-0.5)*CMPLX(nococonv%b_con(1,n),nococonv%b_con(2,n))
     139           0 :             td%h_off(l  ,l  ,n,1,2)     =td%h_off(l  ,l  ,n,1,2) + uun21(l,n)*c
     140           0 :             td%h_off(l  ,l+s,n,1,2)     =td%h_off(l  ,l+s,n,1,2) + udn21(l,n)*c
     141           0 :             td%h_off(l+s,l  ,n,1,2)     =td%h_off(l+s,l  ,n,1,2) + dun21(l,n)*c
     142           0 :             td%h_off(l+s,l+s,n,1,2)     =td%h_off(l+s,l+s,n,1,2) + ddn21(l,n)*c
     143             :          END DO
     144             : 
     145             :          ! Then ispin=2,jspin=1 case
     146           0 :          DO l = 0, atoms%lnonsph(n)
     147           0 :             c = (-0.5)*CMPLX(nococonv%b_con(1,n),-nococonv%b_con(2,n))
     148           0 :             td%h_off(l  ,l  ,n,2,1)     =td%h_off(l  ,l  ,n,2,1) + uun21(l,n)*c
     149           0 :             td%h_off(l  ,l+s,n,2,1)     =td%h_off(l  ,l+s,n,2,1) + udn21(l,n)*c
     150           0 :             td%h_off(l+s,l  ,n,2,1)     =td%h_off(l+s,l  ,n,2,1) + dun21(l,n)*c
     151           0 :             td%h_off(l+s,l+s,n,2,1)     =td%h_off(l+s,l+s,n,2,1) + ddn21(l,n)*c
     152             :          END DO
     153             :       END DO
     154           0 :    END SUBROUTINE tlmplm_constrained
     155             : 
     156        2024 :    SUBROUTINE add_ldaU(fmpi,inden,jsp,atoms,v,ud,input,hub1data,enpara,mat,mat_half,j1,j2,l_lomatrix)
     157             :                ! Include contribution from LDA+U and LDA+HIA (latter are behind LDA+U contributions)
     158             :       USE m_radovlp
     159             :       USE m_opc_setup
     160             :       TYPE(t_mpi),      INTENT(IN)    :: fmpi
     161             :       TYPE(t_input),    INTENT(IN)    :: input
     162             :       TYPE(t_atoms),    INTENT(IN)    :: atoms
     163             :       TYPE(t_enpara),   INTENT(IN)    :: enpara
     164             :       TYPE(t_hub1data), INTENT(IN)    :: hub1data
     165             :       TYPE(t_usdus),    INTENT(INOUT) :: ud
     166             :       TYPE(t_potden),   INTENT(IN)    :: v,inden
     167             :       INTEGER,INTENT(IN)              :: jsp,j1,j2
     168             :       COMPLEX,INTENT(INOUT)           :: mat(:,:,:,:,:)
     169             :       INTEGER,INTENT(IN)              :: mat_half(:)
     170             :       LOGICAL,INTENT(IN)              :: l_lomatrix
     171             : 
     172             :       INTEGER  :: i_u,n,s,l,lp,m,lm,mp,lmp,i_opc
     173        2024 :       REAL, ALLOCATABLE :: uun21(:,:),udn21(:,:),dun21(:,:),ddn21(:,:)
     174        2024 :       REAL, ALLOCATABLE :: opc_corrections(:)
     175             : 
     176        2024 :       IF(atoms%n_u+atoms%n_hia+atoms%n_opc==0) return !No LDA+U
     177             : 
     178         274 :       IF (j1.ne.j2) THEN
     179             :          !Calculate overlap integrals for the off-diagonal LDA+U contributions
     180           0 :          ALLOCATE(uun21(0:atoms%lmaxd,atoms%ntype),source=0.0)
     181           0 :          ALLOCATE(udn21(0:atoms%lmaxd,atoms%ntype),source=0.0)
     182           0 :          ALLOCATE(dun21(0:atoms%lmaxd,atoms%ntype),source=0.0)
     183           0 :          ALLOCATE(ddn21(0:atoms%lmaxd,atoms%ntype),source=0.0)
     184           0 :          CALL rad_ovlp(atoms,ud,input,hub1data,v%mt,enpara%el0, uun21,udn21,dun21,ddn21)
     185             :       ELSE 
     186         274 :          IF (atoms%n_opc > 0) THEN
     187             :             CALL opc_setup(input,atoms,fmpi,v,inden,jsp,opc_corrections)
     188             :          END IF
     189             :       
     190             :       END IF
     191             :    
     192             :       !!$OMP PARALLEL DO DEFAULT(NONE) private(n,s,l,lp,m,lm,mp,lmp)&
     193             :       !!$OMP shared(atoms,mat_half,l_lomatrix,v,mat,uun21,udn21,dun21,ddn21,j1,j2,ud,jsp)
     194         650 :       DO i_u=1,atoms%n_u+atoms%n_hia
     195         376 :          if (l_lomatrix.and..not.atoms%lda_u(i_u)%use_lo) cycle
     196         256 :          n=atoms%lda_u(i_u)%atomType
     197         256 :          s=mat_half(n)
     198             :          ! Found a "U" for this atom type
     199         256 :          l  = atoms%lda_u(i_u)%l
     200         256 :          lp = atoms%lda_u(i_u)%l
     201             :          
     202        1722 :          DO m = -l,l
     203        1192 :             lm = l* (l+1) + m +1 !indexing from 1
     204        7456 :             DO mp = -lp,lp
     205        5888 :                lmp = lp*(lp+1) + mp +1 !indexing from 1
     206        7080 :                IF (j1==j2) THEN
     207        5888 :                   mat(lm  ,lmp  ,n,j1,j2) = mat(lm  ,lmp  ,n,j1,j2) + v%mmpMat(m,mp,i_u,jsp)
     208        5888 :                   mat(lm+s,lmp+s,n,j1,j2) = mat(lm+s,lmp+s,n,j1,j2) + v%mmpMat(m,mp,i_u,jsp) * ud%ddn(lp,n,jsp)
     209           0 :                ELSE IF(j1>j2) THEN
     210           0 :                   mat(lm  ,lmp  ,n,j1,j2) = mat(lm  ,lmp  ,n,j1,j2) + v%mmpMat(m,mp,i_u,3) * uun21(l,n)
     211           0 :                   mat(lm  ,lmp+s,n,j1,j2) = mat(lm  ,lmp+s,n,j1,j2) + v%mmpMat(m,mp,i_u,3) * udn21(l,n)
     212           0 :                   mat(lm+s,lmp  ,n,j1,j2) = mat(lm+s,lmp  ,n,j1,j2) + v%mmpMat(m,mp,i_u,3) * dun21(l,n)
     213           0 :                   mat(lm+s,lmp+s,n,j1,j2) = mat(lm+s,lmp+s,n,j1,j2) + v%mmpMat(m,mp,i_u,3) * ddn21(l,n)
     214             :                ELSE
     215             :                   ! For this part of the Hamiltonian we need to perform Hermitian conjugation on mmpMat
     216           0 :                   mat(lm  ,lmp  ,n,j1,j2) = mat(lm  ,lmp  ,n,j1,j2) + conjg(v%mmpMat(mp,m,i_u,3)) * uun21(l,n)
     217           0 :                   mat(lm  ,lmp+s,n,j1,j2) = mat(lm  ,lmp+s,n,j1,j2) + conjg(v%mmpMat(mp,m,i_u,3)) * udn21(l,n)
     218           0 :                   mat(lm+s,lmp  ,n,j1,j2) = mat(lm+s,lmp  ,n,j1,j2) + conjg(v%mmpMat(mp,m,i_u,3)) * dun21(l,n)
     219           0 :                   mat(lm+s,lmp+s,n,j1,j2) = mat(lm+s,lmp+s,n,j1,j2) + conjg(v%mmpMat(mp,m,i_u,3)) * ddn21(l,n)
     220             :                END IF
     221             :             END DO
     222             :          END DO
     223             :       END DO
     224             :       !!$OMP end parallel do
     225         466 :       DO i_opc=1,atoms%n_opc
     226         192 :          n=atoms%lda_opc(i_opc)%atomType
     227         192 :          s=mat_half(n)
     228             :          ! Found an "OPC" for this atom type
     229         192 :          l=atoms%lda_opc(i_opc)%l
     230        1426 :          DO m = -l,l
     231         960 :             lm = l*(l+1) + m +1 !indexing from 1
     232         960 :             mat(lm  ,lm  ,n,j1,j2) = mat(lm  ,lm  ,n,j1,j2) + opc_corrections(i_opc) * m
     233        1152 :             mat(lm+s,lm+s,n,j1,j2) = mat(lm+s,lm+s,n,j1,j2) + opc_corrections(i_opc) * m * ud%ddn(l,n,jsp)
     234             :          END DO
     235             :       END DO
     236         274 :     END SUBROUTINE
     237             : 
     238        1144 :     subroutine cholesky_decompose(matrix,e_shift,atoms,ud,jsp)
     239             :     USE m_types
     240             :     TYPE(t_atoms),    INTENT(IN)    :: atoms
     241             :     TYPE(t_usdus),INTENT(IN)        :: ud
     242             :     COMPLEX,INTENT(INOUT)           :: matrix(0:,0:,:)
     243             :     REAL, INTENT(OUT)               :: e_shift(:)
     244             :     INTEGER,INTENT(IN)              :: jsp
     245             : 
     246             :     REAL, PARAMETER :: e_shift_min=0.5
     247             :     REAL, PARAMETER :: e_shift_max=65.0
     248             : 
     249             :     INTEGER :: n,info,s,l,lp,lmp,mp
     250        1144 :     COMPLEX,ALLOCATABLE :: mat(:,:)
     251             : 
     252        3146 :     e_shift=e_shift_min
     253             : 
     254        3146 :     DO n=1,atoms%ntype
     255        2002 :       s=atoms%lnonsph(n)*(atoms%lnonsph(n)+2)+1
     256        2002 :       info=1
     257        4004 :       cholesky_loop:DO WHILE(info.ne.0)
     258    28372208 :          mat=matrix(0:,0:,n)
     259             :          !Mat is now using a lower bound of 1!!
     260             :          ! Add shift onto the diagonal terms to make matrix positive definite
     261       16392 :          DO lp = 0,atoms%lnonsph(n)
     262      123146 :                DO mp = -lp,lp
     263      106754 :                lmp = lp* (lp+1) + mp +1
     264      106754 :                mat(lmp,lmp)=e_shift(n)+mat(lmp,lmp)
     265      121144 :                mat(lmp+s,lmp+s)=e_shift(n)*ud%ddn(lp,n,jsp)+mat(lmp+s,lmp+s)
     266             :                END DO
     267             :          END DO
     268        2002 :          IF (lmp.NE.s) CALL judft_error("BUG in local_Hamiltonian:cholesky")
     269             : 
     270             :          ! Perform cholesky decomposition
     271        2002 :          CALL zpotrf("L",2*s,mat(:,:),SIZE(mat,1),info)
     272             : 
     273             :          ! Set upper part to zero
     274      215510 :          DO l=1,2*s
     275    12912184 :                DO lp=1,l-1
     276    12910182 :                mat(lp,l)=0.0
     277             :                END DO
     278             :          END DO
     279             : 
     280        4004 :          IF (info.NE.0) THEN
     281           0 :                e_shift(n)=e_shift(n)*2.0
     282           0 :                IF (e_shift(n)>e_shift_max) THEN
     283           0 :                CALL judft_error("Potential shift at maximum")
     284             :                END IF
     285             :          END IF
     286             :       END DO cholesky_loop
     287    28371350 :       matrix(0:,0:,n)=mat
     288             :    ENDDO   
     289        1144 :    END SUBROUTINE
     290             : 
     291             : 
     292        3484 :     subroutine restrict_to_lnonsph(mat,s2,s,mat_nonsph)
     293             :         COMPLEX,INTENT(IN)   :: mat(0:,0:)
     294             :         INTEGER,INTENT(IN)   :: s,s2
     295             :         COMPLEX,INTENT(OUT)  :: mat_nonsph(0:,0:)
     296             :         ! Set up local hamiltonian
     297    11909124 :         mat_nonsph(0:s-1,0:s-1)    = mat(0:s-1,0:s-1)
     298    11909124 :         mat_nonsph(s:s+s-1,0:s-1)  = mat(s2:s+s2-1,0:s-1)
     299    11909124 :         mat_nonsph(0:s-1,s:s+s-1)  = mat(0:s-1,s2:s+s2-1)
     300    11909124 :         mat_nonsph(s:s+s-1,s:s+s-1)= mat(s2:s+s2-1,s2:s+s2-1)
     301        3484 :     end subroutine
     302             :         
     303             : END MODULE m_local_Hamiltonian

Generated by: LCOV version 1.14