cpmdinit.F90 Source File


Contents

Source Code


Source Code

#include "macros.h"
module cpmdinit_mod
    use CPMDData, only: DegenTol, EigenValues, Project, BigCell, &
        Trans_Label, K_Vectors, KPntInd, CellSizes, TKP, Improper_OP, &
        Rot_Char, NKPTrans, nKPS, nRotOp, PIInt, EIonIon, EigenValues, &
        tagPIInt, Rot_Label, tSpaceGp, Group_Char, &
        tSpaceGp, nSpGpOp, nRotOp, nKPTrans, tKP, nStates
    use MemoryManager, only: LogMemAlloc, LogMemDealloc, TagIntType
    use OneEInts, only: TMat2D, tCPMDSymTMat, TMatSym, TMatInd
    use SymData, only: IRREPCHARS, KPntSym, tAbelian, nSym, SymClasses, &
        SymLabels, SymLabelChars, nRot, nSymLabels, &
        tagIRREPCHARS, tagSymLabels, tagSymLabelChars, tagSymClasses
    use SystemData, only: BasisFN, BasisFNSize, BasisFNSizeB, &
         Symmetry, SymmetrySize, SymmetrySizeB, NullBasisFn
    use UMatCache, only: SetUmatTrans, SetUMatCacheFlag, SetupUMat2D, &
        SetupUMatCache, tUMAT2D
    use basic_float_math, only: conjgt
    use constants, only: dp, stdout
    use cpmdstub_mod, only: CalcHarPIInts
    use global_utilities, only: timer, set_timer, halt_timer
    use sort_mod, only: sort
    use sym_mod, only: ComposeAbelianSym, GenKPtIrreps, DECOMPOSEREP, &
        GENIRREPS, GENSYMTABLE, GENSYMREPS, LCHKSYM, WriteIrrepTab
    use util_mod, only: near_zero, stop_all
    use Determinants, only: writebasis
    IMPLICIT NONE
    private
    public :: CPMDBASISINIT, GENCPMDSYMREPS, cpmdsysteminit, &
        cpmdinit2indint

contains

    SUBROUTINE CPMDBASISINIT(NBASISMAX, ARR, BRR, G1, LEN)
        INTEGER LEN, nBasisMax(5, *), BRR(LEN)
        TYPE(BASISFN) G1(LEN)
        real(dp) ARR(LEN, 2)
        INTEGER I, J
        TYPE(Symmetry) iDecomp
        LOGICAL ALL1D
        NBASISMAX(1, 1) = 0
        NBASISMAX(2, 1) = 0
        NBASISMAX(3, 1) = 0
        IF (BIGCELL .AND. PROJECT) THEN
            NBASISMAX(1, 2) = CELLSIZES(1) - 1
            NBASISMAX(2, 2) = CELLSIZES(2) - 1
            NBASISMAX(3, 2) = CELLSIZES(3) - 1
        ELSE
            NBASISMAX(1, 2) = 0
            NBASISMAX(2, 2) = 0
            NBASISMAX(3, 2) = 0
        END IF
        NBASISMAX(1, 3) = 2
        NBASISMAX(4, 1) = -1
        NBASISMAX(4, 2) = 1

!.. set ISPINSKIP=0, to tell the SCRs that there's no UMAT
        NBASISMAX(2, 3) = 0
        IF (TKP) THEN
!  We've got a k-point code, so we're not currently using spatial symmetry.  We use translational symmetry according to the k-points
!            JSS: Use Abelian symmetry formulation.
            CALL GenKPtIrreps(NKPTRANS, NKPS, KPNTIND, NSTATES)
        ELSE
            CALL ExtractSymLabels
            CALL GENIRREPS(TKP, IMPROPER_OP, NROTOP)
            CALL GENSYMTABLE
        END IF

        G1(1:LEN) = NullBasisFn
        ALL1D = .TRUE.
        DO I = 1, NSTATES
        if (TAbelian) then
            IDECOMP%s = ComposeAbelianSym(KpntSym(:, KPntInd(I)))
        else
            CALL DECOMPOSEREP(SYMLABELCHARS(1, SymClasses(I)), IDECOMP)
        end if
        IF (ABS(SYMLABELCHARS(1, SymClasses(I)) - 1.0_dp) >= 1.0e-6_dp) ALL1D = .FALSE.
        G1(I * 2 - 1)%SYM = IDECOMP
        G1(I * 2)%SYM = IDECOMP
        G1(I * 2 - 1)%MS = -1
        G1(I * 2)%MS = 1
        IF (BIGCELL .AND. PROJECT) THEN
            DO J = 1, 3
                G1(I * 2 - 1)%K(J) = K_VECTORS(J, TRANS_LABEL(I))
                G1(I * 2)%K(J) = K_VECTORS(J, TRANS_LABEL(I))
            END DO
        ELSE
            DO J = 1, 3
                G1(I * 2 - 1)%K(J) = 0
                G1(I * 2)%K(J) = 0
            END DO
        END IF
!.. the eigenvalues
        ARR(2 * I - 1, 1) = EIGENVALUES(I)
        ARR(2 * I, 1) = EIGENVALUES(I)
        ARR(2 * I - 1, 2) = EIGENVALUES(I)
        ARR(2 * I, 2) = EIGENVALUES(I)
        BRR(2 * I - 1) = 2 * I - 1
        BRR(2 * I) = 2 * I
        END DO
        IF (TAbelian) THEN
            WRITE(stdout, *) 'Using Abelian symmetry formulation.'
            NBASISMAX(5, 1) = 0
            NBASISMAX(5, 2) = NSYM - 1
        ELSE IF (ALL1D) THEN
!.. If all reps are 1D, we can block determinants in different symmetries
            NBASISMAX(5, 1) = 0
            NBASISMAX(5, 2) = NSYM - 1
            WRITE(stdout, *) "All orbitals have 1D symmetry. Using blocking symmetry."
        ELSE
            WRITE(stdout, *) "Multidimensional symmetries detected. ", "Not using symmetry blocking."
        END IF
!.. show it's a generic spatial basis
        NBASISMAX(3, 3) = 1
    END
!.. Called to retrieve number of basis functions from CPMD
    SUBROUTINE CPMDSYSTEMINIT(LEN)
        INTEGER LEN
        LEN = NSTATES * 2
        IF (TSPACEGP) THEN
!.. We're dealing with a complete space group rather than just a point
!.. group
            NROT = NSpGpOp
        ELSE
            NROT = NROTOP
        END IF
        IF (TKP) THEN
            NROT = NKPTRANS
        END IF
    END

    SUBROUTINE GENCPMDSYMREPS(G1, NBASIS, ARR)
        INTEGER NBASIS
        type(BasisFn) G1(*)
        real(dp) ARR(NBASIS, 2)
        CALL GENSYMREPS(G1, NBASIS, ARR, DEGENTOL)
    END

    SUBROUTINE EXTRACTSYMLABELS
        INTEGER I, J
        character(*), parameter :: this_routine = 'ExtractSymLabels'
        NSYMLABELS = 0
        DO I = 1, NSTATES
            IF (ROT_LABEL(I) > NSYMLABELS) NSYMLABELS = ROT_LABEL(I)
        END DO
        allocate(SymLabelChars(nRot, nSymLabels))
        call LogMemAlloc('SymLabelChars', nSymLabels * nRot * 2, 16, this_routine, tagSymLabelChars)
        SYMLABELCHARS = 0.0_dp
        allocate(SymLabels(nSymLabels))
        call LogMemAlloc('SymLabels', nSymLabels, 4, this_routine, tagSymLabels)
        allocate(SymClasses(nStates))
        call LogMemAlloc('SymClasses', nStates, 4, this_routine, tagSymClasses)
!.. Two versions - one for space groups and one for point groups
        IF (TSPACEGP) THEN
!.. space group is more complex as we have separate translational and
!.. rotational labels.  We will need to compare each pair of t&r labels
!.. with a stored list.
            WRITE(stdout, *) "Using space group representation."
            DO I = 1, NSTATES
                IF (near_zero(SYMLABELCHARS(1, ROT_LABEL(I)))) THEN
!.. we've found an uninitialized symlabel - fill it
                    DO J = 1, NROT
!.. Indices need to be inverted so cannot straight ICOPY
                        SYMLABELCHARS(J, ROT_LABEL(I)) = GROUP_CHAR(J, I)
                    END DO
                END IF
                SymClasses(I) = ROT_LABEL(I)
            END DO
        ELSE
!.. point group
            WRITE(stdout, *) "Using point group representation."
            DO I = 1, NSTATES
                IF (near_zero(SYMLABELCHARS(1, ROT_LABEL(I)))) THEN
!.. we've found an uninitialized symlabel - fill it
                    DO J = 1, NROT
!.. Indices need to be inverted so cannot straight ICOPY
                        SYMLABELCHARS(J, ROT_LABEL(I)) = NINT(ROT_CHAR(I, J))
                    END DO
                END IF
                SymClasses(I) = ROT_LABEL(I)
            END DO
        END IF
        WRITE(stdout, *) "SYMMETRY CLASSES"
        CALL writeirreptab(stdout, SYMLABELCHARS, NROT, NSYMLABELS)
!.. Allocate memory gor irreps.
!.. Assume there will be no more than 64 irreps
        allocate(IRREPCHARS(NROT, NROT)) ! nSym==nRot
        call LogMemAlloc('IRREPCHARS', nROT**2, 16, this_routine, tagIRREPCHARS)
!CALL N_MEMORY(IP_IRREPCHARS,NROT*64*2,"IRREPCH")
    END

!.. Calculate the h_ij elements for CPMD orbitals.
!.. E_i is the eigenvalue for state i.
!.. f_i is the occupation number for state i.
!.. delta_ij is the Dirac delta.
!.. (ab|cd) is the 4-index Coulomb integral between states, i,j,k,l
!.. h_ij=(E_i+xi) delta_ij - Sum_k f_k (ik|jk)
    SUBROUTINE CPMDINIT2INDINT(NHG, NORBUSED, G1, NEL, ECORE, TORDER, ARR, BRR, iCacheFlag)
        INTEGER NHG
        HElement_t(dp) CPMD1EINT(NSTATES, NSTATES)
        INTEGER I, J, NSTATESUSED, NORBUSED, II, JJ
        type(timer), save :: proc_timer
        HElement_t(dp) TOT

        TYPE(BASISFN) G1(NHG)
        real(dp) ECORE
        INTEGER NEL
        real(dp) DIAGTMAT(NSTATES)
        INTEGER STATEORDER(NSTATES)
        LOGICAL TORDER
        INTEGER BRR(NSTATES * 2), NLOCK
        real(dp) ARR(NSTATES * 2, 2)
        complex(dp), allocatable, save :: HarInt(:, :)
        INTEGER iCacheFlag
! For ZHEEV (eigenvalues of FockMatrix).
        integer(TagIntType) :: tagHarInt = 0
        character(*), parameter :: this_routine = 'CPMDINIT2INDINT'
        proc_timer%timer_name = 'CPMDINIT2I'
        call set_timer(proc_timer)

        ECORE = EIONION
        WRITE(stdout, *) "Core Energy:", ECORE
        NLOCK = (NEL + 1) / 2
        IF (TORDER) THEN
!.. We have to cache all states, as we don't, as yet, know which ones we're going to freeze because we have to reorder.
            NSTATESUSED = NSTATES
        ELSE
            NSTATESUSED = NORBUSED / 2
        END IF
        IF (.NOT. BTEST(iCacheFlag, 1)) THEN
!Don't initialize the cache if it's already there
            allocate(HarInt(NStatesUsed, NStatesUsed))
            call LogMemAlloc('HarInt', nStatesUsed**2, 16, this_routine, tagHarInt)
            allocate(PIInt(nStates))
            call LogMemAlloc('PIInt', nStates, 8, this_routine, tagPIInt)
!            allocate(FockMat(nStatesUsed,nStatesUsed))
!.. If we're freezing we allocate a small cache first to store the <ij|kj> integrals, which will be deallocated and a larger cache made later.
            CALL SETUPUMATCACHE(NSTATESUSED, NSTATESUSED /= NSTATES)
        END IF
        call stop_all(this_routine, 'Code deprecated')
!         CALL N_MEMORY_CHECK()
        OPEN(10, FILE='TMAT', STATUS='UNKNOWN')
        IF (.NOT. BTEST(iCacheFlag, 1)) THEN
!Don't initialize the cache if it's already there
!.. Set the UMAT cache to cache things in the lowest possible position
            CALL SETUMATCACHEFLAG(1)
!   JSS  Calculate the elements of the type <ij|ij> and <ij|ji> efficiently.
            CALL SETUPUMAT2D(G1, HarInt)
! Must now calculate the hartree integrals and periodic integrals
! (otherwise done in CPMDAntiSymIntEl) if not using UMAT2D.
            if (.not. TUMAT2D) call CalcHarPIInts(HarInt, NStatesUsed)
            CALL SETUMATCACHEFLAG(0)
        END IF

! JSS. 25/01/08.  Calculate the Fock matrix.
! F_ij = < i | -1/2 \nabla^2 + v_ext | j > + \sum_k [ <ik|jk> - <ik|kj> ]
!      = - h^{KS}_ij - <i|v_xc|j> - \sum_k <ik|kj>
!      = \epsilon_i \delta_ij - \sum_k <ik|kj>
! where h^{KS}_ij = < i | -1/2 \nabla^2 + v_ext + v_har + v_xc | j >
! and h^{KS}_ii = \epsilon_i
!         FockMat(:,:)=dcmplx(0.0_dp,0.0_dp)

        WRITE(stdout, *) "Calculating TMAT"
        DO I = 1, NSTATESUSED
            II = I * 2 - 1
            DO J = I, NSTATESUSED
                JJ = J * 2 - 1

                IF (LCHKSYM(G1(II), G1(JJ))) THEN

                    TOT = 0.0_dp
                    IF (I == J) THEN
                        TOT = TOT + (EIGENVALUES(I) + PIInt(I) / 2.0_dp)
!                      FockMat(I,J)=FockMat(I,J)+Eigenvalues(I)
                    END IF
                    TOT = TOT - CPMD1EINT(I, J)
                    TOT = TOT - real(HarInt(i, j), dp)
!                  FockMat(i,j)=FockMat(i,j)-dcmplx(CPMD1EInt(I,J))
                    IF (tCPMDSymTMat) THEN
                        TMATSYM(TMatInd(II + 1, JJ + 1)) = TOT ! Indexing needs to be compatiable with TMatInd.
                    ELSE
                        TMAT2D(II, JJ) = TOT
                        TMAT2D(II + 1, JJ + 1) = TOT
!ifdef CMPLX_
                        TMAT2D(JJ, II) = conjgt(TOT)
                        TMAT2D(JJ + 1, II + 1) = conjgt(TOT)
!else
                        TMAT2D(JJ, II) = (TOT)
                        TMAT2D(JJ + 1, II + 1) = (TOT)
!endif
                    END IF
                    WRITE(10, *) I, J, TOT
                    IF (I == J) THEN
                        DIAGTMAT(I) = ABS(TOT)
                        STATEORDER(I) = I
                    END IF

                    ! Subtract exchange integrals from Fock matrix.
!                 do K=1,nStates
!                     call CPMDGetOcc(K,F) ! F is the occupation number of state K.
!                      if (F.gt.1.0e-5_dp) then
!                          ! Get exchange integral <ik|kj>
!                          if (K.gt.nStatesUsed) then
!                              write (stdout,"(a,i4,a,f10.6)")
!     &                             "Top frozen state ",K,
!     &                             " has occupation number",F
!                              stop "Top Frozen states occupied."
!                          end if
!                          U=GetUMatEl(nBasisMax,UMat,ALAT,NHG,ISS,G1,
!     &                                I,K,K,J)
!                          FockMat(i,j)=FockMat(i,j)-F*dcmplx(U)/2
!                      end if
!                  end do
!                 FockMat(j,i)=conjg(FockMat(i,j))

                END IF

            END DO
        END DO

!.. Now we order it if we need to
        IF (TORDER) THEN
            WRITE(stdout, *) "Re-ordering CPMD orbitals according ", "to one-electron energies."
            call sort(diagTMAT(nlock + 1:nStatesUsed), stateOrder(nlock + 1:nStatesUsed))
!           CALL NECI_SORT2(NSTATESUSED-NLOCK,DIAGTMAT(NLOCK+1),
!     &         STATEORDER(NLOCK+1))
!.. Now copy to BRR
            DO I = 1, NSTATES
                BRR(2 * I - 1) = STATEORDER(I) * 2 - 1
                BRR(2 * I) = STATEORDER(I) * 2
                ARR(2 * I - 1, 1) = DIAGTMAT(I)
                ARR(2 * I, 1) = DIAGTMAT(I)
            END DO
!.. we only need a translation table if we've reordered the states.
!.. This should save some time in the UMAT lookup.
            CALL SETUMATTRANS(STATEORDER)
            CALL writebasis(stdout, G1, NSTATES * 2, ARR, BRR)
        END IF
!.. Set the UMAT cache to cache normally again
        WRITE(stdout, *) "Finished TMAT"
        CLOSE(10)

        IF (.not. BTEST(iCacheFlag, 0)) THEN
            deallocate(HarInt)
            call LogMemDealloc(this_routine, tagHarInt)
            deallocate(PIInt)
            call LogMemDealloc(this_routine, tagPIInt)
        end if
        call halt_timer(proc_timer)
    END

end module cpmdinit_mod