#include "macros.h" module hubbard_mod USE OneEInts, only: TMat2D, TMATSYM, SetupTMAT USE Parallel_neci, only: iProcIndex use SymData, only: SymReps, tagSymReps, & nSym, SymConjTab, SymClasses, SymLabels, nSymLabels, tAbelian, & SymTable, tagSymConjTab, tagSymClasses, tagSymLabels, tagSymTable use SystemData, only: BasisFN, BasisFNSize, BasisFNSizeB, & t_open_bc_x, t_open_bc_y, Symmetry, SymmetrySize, SymmetrySizeB, & t_k_space_hubbard, twisted_bc, nn_bhub use UMatCache, only: UMatInd use constants, only: Pi, Pi2, THIRD, dp, int64, sizeof_int, stdout use global_utilities, only: timer, set_timer, halt_timer, & LogMemAlloc, LogMemDealloc use hfbasis_mod, only: iFindBasisFn use lattice_mod, only: lat use sym_mod, only: RoundSym, AddElecSym, mompbcsym use util_mod, only: stop_all better_implicit_none private public :: genhubmomirrepssymtable, genhubsymreps, & hubkin, hubkinn, setbasislim_hubtilt, setbasislim_hub, calctmathub, & calcumathubreal, write_kspace_umat contains SUBROUTINE CALCUMATHUBREAL(NBASIS, UHUB, UMAT) INTEGER NBASIS HElement_t(dp) UMAT(*) real(dp) UHUB INTEGER I, IC OPEN(10, FILE='UMAT', STATUS='UNKNOWN') IC = 1 !Only do this for each spatial orbital. DO I = 1, NBASIS / 2 UMAT(UMatInd(I, I, I, I)) = h_cast(UHUB) WRITE(10, *) I, I, I, I, UHUB, UMatInd(I, I, I, I) END DO CLOSE(10) RETURN END SUBROUTINE HUBKIN(I, J, K, NBASISMAX, BHUB, TTILT, TOTSUM, TREAL) ! returns the non-interacting energy of state with !..quatum numbers (i,j,k) for Hubbard model of !..lengths (LX,LY,LZ) PBC. !..Returned in sum INTEGER nBasisMax(5, *), AX, AY INTEGER LX, LY, LZ, K, J, I LOGICAL TTILT, TREAL real(dp) :: TOTSUM, BHUB real(dp) :: tb_x, tb_y, nn IF (TREAL) THEN TOTSUM = 0.0_dp ELSE tb_x = twisted_bc(1) tb_y = twisted_bc(2) LX = NBASISMAX(1, 2) - NBASISMAX(1, 1) + 1 LY = NBASISMAX(2, 2) - NBASISMAX(2, 1) + 1 LZ = NBASISMAX(3, 2) - NBASISMAX(3, 1) + 1 AX = NBASISMAX(1, 4) AY = NBASISMAX(2, 4) IF (TTILT) THEN !CCC.. NBASISMAX goes from -NMAXX+1 to MAXX so LX=2MAXX LX = NBASISMAX(1, 5) LX = (LX * (AX * AX + AY * AY)) totsum = cos(2 * pi * ((I + tb_x) * ax + (j + tb_y) * ay) / lx) totsum = totsum + cos(2 * pi * ((i + tb_x) * ay - (j + tb_y) * ax) / lx) nn = cos(2 * pi * (i + tb_x) * AX / lx) + cos((J + tb_y) * ay / lx) ELSE IF (LX > 1) then TOTSUM = COS(2 * PI * (I + tb_x) / LX) nn = cos(2 * pi * (I + tb_x + J * tb_y) / LX) end if IF (LY > 1) then TOTSUM = TOTSUM + COS(2 * PI * (J + tb_y) / LY) nn = cos(2 * pi * (I + tb_x - (J + tb_y)) / LY) end if IF (LZ > 1) TOTSUM = TOTSUM + COS(2 * PI * K / (LZ)) END IF TOTSUM = 2.0_dp * (TOTSUM * BHUB + nn * nn_bhub) END IF RETURN END SUBROUTINE HUBKINN(I, J, K, NBASISMAX, BHUB, TTILT, TOTSUM, TREAL) ! returns the non-interacting energy of state with !..quatum numbers (i,j,k) for Hubbard model of !..lengths (LX,LY,LZ). NON-PBC !..Returned in sum INTEGER nBasisMax(5, *), AX, AY LOGICAL TTILT, TREAL INTEGER II, JJ, KK, K, J, I, LZ, LX, LY real(dp) :: BHUB, TOTSUM if (tReal) then TOTSUM = 0.0_dp return else LX = NBASISMAX(1, 2) - NBASISMAX(1, 1) + 1 LY = NBASISMAX(2, 2) - NBASISMAX(2, 1) + 1 LZ = NBASISMAX(3, 2) - NBASISMAX(3, 1) + 1 AX = NBASISMAX(1, 4) AY = NBASISMAX(2, 4) IF (TTILT) THEN !CCC.. NBASISMAX goes from -NMAXX+1 to MAXX so LX=2MAXX LX = NBASISMAX(1, 5) LX = (LX * (AX * AX + AY * AY)) TOTSUM = COS(PI * (I * AX - J * AY) / (LX + 1)) + COS(PI * (I * AY + J * AX) / (LX + 1)) ELSE II = I - NBASISMAX(1, 1) + 1 JJ = J - NBASISMAX(2, 1) + 1 KK = K - NBASISMAX(3, 1) + 1 IF (LX > 1) TOTSUM = COS(PI * II / (LX + 1)) IF (LY > 1) TOTSUM = TOTSUM + COS(PI * JJ / (LY + 1)) IF (LZ > 1) TOTSUM = TOTSUM + COS(PI * KK / (LZ + 1)) ! IF(LY.GT.1) TOTSUM=TOTSUM+COS(PI*J/(LY+1)) ! IF(LZ.GT.1) TOTSUM=TOTSUM+COS(PI*K/(LZ+1)) END IF TOTSUM = TOTSUM * 2.0_dp * BHUB RETURN end if END SUBROUTINE CALCTMATHUB(NBASIS, NBASISMAX, BHUB, TTILT, G1, TREAL, TPBC) INTEGER NBASIS, nBasisMax(5, *) TYPE(BasisFN) G1(nBasis) real(dp) BHUB INTEGER iSize INTEGER I, J INTEGER DX, DY, DZ, LX, LY, LZ LOGICAL TTILT, TREAL, TPBC real(dp) TOTSUM integer temp_k(3) IF (iProcIndex == 0) OPEN(10, FILE='TMAT', STATUS='UNKNOWN') CALL SetupTMAT(NBASIS, 2, iSize) TOTSUM = 0.0_dp LX = NBASISMAX(1, 2) - NBASISMAX(1, 1) LY = NBASISMAX(2, 2) - NBASISMAX(2, 1) LZ = NBASISMAX(3, 2) - NBASISMAX(3, 1) ! here i have to make some changes in the real-space tilted ! case to construct the correct TMAT IF (LY == 0) LY = -1 IF (LZ == 0) LZ = -1 IF (TREAL) THEN DO I = 1, NBASIS DO J = 1, NBASIS DX = ABS(G1(I)%k(1) - G1(J)%k(1)) DY = ABS(G1(I)%k(2) - G1(J)%k(2)) DZ = ABS(G1(I)%k(3) - G1(J)%k(3)) temp_k = [DX, DY, DZ] call mompbcsym(temp_k, NBASISMAX) temp_k = abs(temp_k) TOTSUM = BHUB IF (TPBC) THEN !This bit is only for if the hubbard lattice only has one site in a certain dimension IF (DX == LX .and. .not. t_open_bc_x) THEN DX = 1 IF (LX == 1) TOTSUM = TOTSUM + BHUB END IF IF (DY == LY .and. .not. t_open_bc_y) THEN DY = 1 IF (LY == 1) TOTSUM = TOTSUM + BHUB END IF IF (DZ == LZ) THEN DZ = 1 IF (LZ == 1) TOTSUM = TOTSUM + BHUB END IF END IF ! make this more general to also use open BC and a ! tilted real-space lattice if (.not. t_open_bc_x .and. .not. t_open_bc_y) then IF (DX + DY + DZ == 1 .or. sum(temp_k) == 1) then if (G1(I)%Ms == G1(J)%MS) THEN !This is for if the site can interact with a periodic image. TMAT2D(I, J) = TOTSUM IF (iProcIndex == 0) WRITE(10, *) I, J, TOTSUM end if END IF else if (DX + DY + DZ == 1 .and. G1(I)%Ms == G1(J)%MS) THEN TMAT2D(I, J) = TOTSUM IF (iProcIndex == 0) WRITE(10, *) I, J, TOTSUM end if end if END DO END DO ELSE IF (TPBC) THEN DO I = 1, NBASIS CALL HUBKIN(G1(I)%k(1), G1(I)%k(2), G1(I)%k(3), NBASISMAX, BHUB, TTILT, TOTSUM, TREAL) TMAT2D(I, I) = TOTSUM IF (iProcIndex == 0) WRITE(10, *) I, I, TMAT2D(I, I) END DO ELSE DO I = 1, NBASIS CALL HUBKINN(G1(I)%k(1), G1(I)%k(2), G1(I)%k(3), NBASISMAX, BHUB, TTILT, TOTSUM, TREAL) TMAT2D(I, I) = TOTSUM IF (iProcIndex == 0) WRITE(10, *) I, I, TMAT2D(I, I) END DO END IF END IF IF (iProcIndex == 0) CLOSE(10) RETURN END !.. NBASISMAX descriptor (1,3) ! ! HUBBARD: ! 0 Non-Tilted Lattice - pbc ! 1 Tilted Lattice - pbc ! 2 Non-Tilted lattice - no pbc ! 3 Tilted Lattice - no pbc !.. four following are REAL ! 4 Non-Tilted Lattice - pbc ! 5 Tilted Lattice - pbc ! 6 Non-Tilted lattice - no pbc ! 7 Tilted Lattice - no pbc ! SUBROUTINE SETBASISLIM_HUB(NBASISMAX, NMAXX, NMAXY, NMAXZ, LEN, TPBC, TREAL) INTEGER nBasisMax(5, *), NMAXX, NMAXY, NMAXZ, LEN LOGICAL TPBC, TREAL IF (TPBC) THEN NBASISMAX(1, 3) = 0 ELSE !.. Non-tilted, not pbc NBASISMAX(1, 3) = 2 END IF IF (TREAL) NBASISMAX(1, 3) = NBASISMAX(1, 3) + 4 ! IF(.NOT.TPBC.AND..NOT.TREAL) THEN !.. non-pbc has Huckel MOs starting k from 1 ! NBASISMAX(1,1)=1 ! NBASISMAX(2,1)=1 ! NBASISMAX(3,1)=1 ! NBASISMAX(1,2)=NMAXX ! NBASISMAX(2,2)=NMAXY ! NBASISMAX(3,2)=NMAXZ ! ELSE IF (MOD(NMAXX, 2) == 0) THEN NBASISMAX(1, 2) = NMAXX / 2 NBASISMAX(1, 1) = -NMAXX / 2 + 1 ELSE NBASISMAX(1, 2) = NMAXX / 2 NBASISMAX(1, 1) = -NMAXX / 2 END IF IF (MOD(NMAXY, 2) == 0) THEN NBASISMAX(2, 2) = NMAXY / 2 NBASISMAX(2, 1) = -NMAXY / 2 + 1 ELSE NBASISMAX(2, 2) = NMAXY / 2 NBASISMAX(2, 1) = -NMAXY / 2 END IF IF (MOD(NMAXZ, 2) == 0) THEN NBASISMAX(3, 2) = NMAXZ / 2 NBASISMAX(3, 1) = -NMAXZ / 2 + 1 ELSE NBASISMAX(3, 2) = NMAXZ / 2 NBASISMAX(3, 1) = -NMAXZ / 2 END IF ! ENDIF NBASISMAX(1, 4) = 0 NBASISMAX(2, 4) = 1 NBASISMAX(1, 5) = NMAXX NBASISMAX(2, 5) = NMAXY NBASISMAX(3, 5) = NMAXZ LEN = NMAXX * NMAXY * NMAXZ * ((NBASISMAX(4, 2) - NBASISMAX(4, 1)) / 2 + 1) END SUBROUTINE SETBASISLIM_HUBTILT(NBASISMAX, NMAXX, NMAXY, NMAXZ, LEN, TPBC, ITILTX, ITILTY) INTEGER nBasisMax(5, *), NMAXX, NMAXY, NMAXZ, LEN LOGICAL TPBC INTEGER ITILTX, ITILTY character(*), parameter :: this_routine = 'SETBASISLIM_HUBTILT' IF (TPBC) THEN !.. Indicate tilted NBASISMAX(1, 3) = 1 ELSE !.. Not periodic boundaries NBASISMAX(1, 3) = 3 END IF NBASISMAX(1, 2) = int(real(NMAXX, dp) * (real(ITILTX + ITILTY, dp) / 2.0_dp), sizeof_int) NBASISMAX(1, 1) = -NBASISMAX(1, 2) !+1-MOD(NMAXX,2) IF (NMAXY /= NMAXX) call stop_all(this_routine, 'CANNOT HANDLE NON-SQUARE TILTED HUBBARD') NBASISMAX(2, 2) = int(real(NMAXX, dp) * (real(ITILTY + ITILTX, dp) / 2.0_dp), sizeof_int) NBASISMAX(2, 1) = -NBASISMAX(2, 2) !+1-MOD(NMAXX,2) IF (NMAXZ > 1) call stop_all(this_routine, 'CANNOT HANDLE TILTED 3D HUBBARD') NBASISMAX(3, 2) = 0 NBASISMAX(3, 1) = 0 NBASISMAX(1, 4) = ITILTX NBASISMAX(2, 4) = ITILTY NBASISMAX(1, 5) = NMAXX NBASISMAX(2, 5) = NMAXY NBASISMAX(3, 5) = NMAXZ !Len is number of basis functions LEN = NMAXX * NMAXY * (ITILTX * ITILTX + ITILTY * ITILTY) * ((NBASISMAX(4, 2) - NBASISMAX(4, 1)) / 2 + 1) ! LEN=NMAXX*NMAXY*2 ! & *((NBASISMAX(4,2)-NBASISMAX(4,1))/2+1) END !Generate the Sym table for a Hubbard Lattice Subroutine GenHubMomIrrepsSymTable(G1, nBasis, nBasisMax) INTEGER nBasis, nBasisMax(*) TYPE(BasisFN) G1(nBasis) INTEGER J, nSyms, K integer(int64) :: I TYPE(BasisFN) NQNS, S character(*), parameter:: this_routine = 'GenHubMomIrrepsSymTable' nSym = nBasis / 2 WRITE(stdout, "(A,I3,A)") "Generating abelian symmetry table with", nBasis / 2, " generators for Hubbard momentum" !.. Now generate a list of sym labels. write(stdout, *) 'SIZES', nSymLabels, nBasis, allocated(symlabels), associated(symclasses), allocated(symconjtab), allocated(symtable) if (allocated(SymLabels)) then write(stdout, '(a/a)') 'Warning: symmetry info already allocated.', 'Deallocating and reallocating.' deallocate(SymLabels) call LogMemDealloc(this_routine, tagSymLabels) end if allocate(SymLabels(nSym)) call LogMemAlloc('SymLabels', nSym, SymmetrySize, this_routine, tagSymLabels) if (associated(SymClasses)) then deallocate(SymClasses) call LogMemDealloc(this_routine, tagSymClasses) end if allocate(SymClasses(nBasis)) call LogMemAlloc('SymClasses', nBasis, 4, this_routine, tagSymClasses) NSYMLABELS = NSYM nSyms = 1 tAbelian = .false. DO I = 1, NBASIS / 2 !.. place the sym label of each state in SymClasses(ISTATE). IF (ALL(G1(I * 2)%k == 0)) THEN SymClasses(I) = 1 NQNS = G1(I * 2) ELSE nSyms = nSyms + 1 SymClasses(I) = nSyms END IF !.. list the symmetry string of each sym label !.. try the new symmetry encoding here if (t_k_space_hubbard) then SymLabels(I)%s = i else SymLabels(I)%s = 2_int64**(I - 1_int64) end if END DO !.. Setup the symmetry product table if (allocated(SymTable)) then deallocate(SymTable) call LogMemDealloc(this_routine, tagSymTable) end if allocate(SymTable(nSym, nSym)) call LogMemAlloc('SymTable', nSym**2, SymmetrySize, this_routine, tagSymTable) if (allocated(SymConjTab)) then deallocate(SymConjTab) call LogMemDealloc(this_routine, tagSymConjTab) end if allocate(SymConjTab(nSym)) call LogMemAlloc('SymConjTable', nSym, 4, this_routine, tagSymConjTab) SYMTABLE(1:NSYM, 1:NSYM) = Symmetry(0) DO I = 1, nBasis / 2 NQNS%k = -G1(I * 2)%k CALL RoundSym(NQNS, nBasisMax) if (t_k_space_hubbard) then ! i could actually include the symmetry rounding in the ! get_orb_from_k_vec functionality! ! i was doing this incorrectly.. i want the spin orbital ! j J = lat%get_orb_from_k_vec(NQNS%k, 2) else J = iFindBasisFn(NQNS, G1, nBasis) end if IF (J == 0) THEN WRITE(stdout, *) "Cannot Find symmetry conjugate to basis fn ", I * 2 call stop_all(this_routine, "Cannot find symmetry conjugate.") END IF SymConjTab(SymClasses(I)) = SymClasses(J / 2) DO J = 1, nBasis / 2 S = G1(I * 2) CALL AddElecSym(J * 2, G1, nBasisMax, S) CALL RoundSym(S, nBasisMax) NQNs%k = S%k if (t_k_space_hubbard) then k = lat%get_orb_from_k_vec(S%k, 2) else K = iFindBasisFn(NQNS, G1, nBasis) end if IF (K == 0) THEN WRITE(stdout, *) "Cannot find symmetry product of basis fns ", I * 2, J * 2 call stop_all(this_routine, "Cannot find symmetry product.") END IF SymTable(SymClasses(I), SymClasses(J)) = SymLabels(SymClasses(K / 2)) END DO END DO DO I = 1, nBasis / 2 G1(I * 2 - 1)%Sym = SymLabels(SymClasses(I)) G1(I * 2)%Sym = SymLabels(SymClasses(I)) END DO WRITE(stdout, *) "Symmetry, Symmetry Conjugate" DO I = 1, NSYM WRITE(stdout, *) I, SymConjTab(I) END DO End !Hubbard Sym Reps are different from normal ones. In hubbard, we have split degenerate sets into 1D subcomponents, ! but a complete degenerate set will count as a sym rep (i.e. if it is filled, its sym can be discounted), ! not just one of the subcomponents SUBROUTINE GENHUBSYMREPS(NBASIS, ARR, BRR) INTEGER I, J INTEGER NBASIS, BRR(NBASIS) real(dp) ARR(NBASIS) character(*), parameter :: this_routine = 'GenHubSymReps' !.. now work out which reps are degenerate and label them if (allocated(SymReps)) deallocate(symreps) allocate(SymReps(2, nBasis)) call LogMemAlloc('SymReps', 2 * nBasis, 4, this_routine, tagSymReps) ! this does not make sense.. SYMREPS = 0 !.. we have a new rep J = 1 SYMREPS(1, BRR(1)) = 1 SYMREPS(2, 1) = 1 DO I = 2, NBASIS IF (ABS(ARR(I) - ARR(I - 1)) < 1.0e-5_dp) THEN !.. we have the same degenerate rep as the previous entry SYMREPS(2, J) = SYMREPS(2, J) + 1 ELSE !.. we have a new rep J = J + 1 SYMREPS(2, J) = 1 END IF SYMREPS(1, BRR(I)) = J END DO END subroutine write_kspace_umat() ! subroutine to output the umat also in the case of the ! momentum space hubbard model, to be easier able to compare it ! with the DMRG calculations for the GUGA matrix elements! use SystemData, only: G1, nSpatOrbs, nBasisMax, uHub, omega use sym_mod, only: mompbcsym use UMatCache, only: gtid integer :: i, j, k, l, k_in(3), k_out(3) open(10, file="UMAT", status="unknown") ! do it really naively and just loop over all the indices and ! check if the momentum consercation is fullfilled! ! actually it is more efficient to loop over the spatial orbitals ! only! and check the momentum for the spin-orbs! do i = 1, nSpatOrbs do j = 1, nSpatOrbs do k = 1, nSpatOrbs do l = 1, nSpatOrbs ! have to figure out which orbitals to compare in ! the physicist notation! ! and convert to fake spin-orbtitals k_in = G1(2 * i)%k + G1(2 * k)%k k_out = G1(2 * j)%k + G1(2 * l)%k ! apply periodic BC call mompbcsym(k_in, nBasisMax) call mompbcsym(k_out, nBasisMax) if (all(k_in == k_out)) then write(10, '(4i7, f19.9)') i, j, k, l, uHub / Omega end if end do end do end do end do close(10) end subroutine write_kspace_umat end module