<commit_before>module hamiltonian

use const
use basis
use determinants
use hubbard
use parallel

implicit none

! Flags for doing exact and/or Lanczos diagonalisation.
logical :: t_exact = .false., t_lanczos = .false.

! Hamiltonian matrix.  Clearly the scaling of the memory demands with system
! size is horrendous.
real(dp), allocatable :: hamil(:,:) ! (ndets, ndets)

! If true, then the eigenvectors are found during exact diagonalisation as well
! as the eigenvalues.  Doing this is substantially more expensive.
logical :: find_eigenvectors = .false.

! If true then the non-zero elements of the Hamiltonian matrix are written to hamiltonian_file.
logical :: write_hamiltonian = .false.
character(255) :: hamiltonian_file = 'HAMIL'

! Number of Lanczos eigenpairs to find.
integer :: nlanczos_eigv = 5
! Size of Lanczos basis.
integer :: lanczos_basis_length = 40

private :: hamil_vector

contains

    subroutine generate_hamil()

        ! Generate the Hamiltonian matrix.
        ! Only generate the upper diagonal for use with Lapack routines.

        use utils, only: get_free_unit

        integer :: ierr, i, j, iunit

        allocate(hamil(ndets,ndets), stat=ierr)

        forall (i=1:ndets) 
            forall (j=i:ndets) hamil(i,j) = get_hmatel(i,j)
        end forall

        ! Fill in rest of Hamiltonian matrix.  In this case the Hamiltonian is
        ! symmetric (rather than "just" Hermitian).
!        do i=1,ndets
!            do j=1,i-1
!                hamil(i,j) = hamil(j,i)
!            end do
!        end do

        if (write_hamiltonian) then
            iunit = get_free_unit()
            open(iunit, file=hamiltonian_file, status='unknown')
            do i=1,ndets
                write (iunit,*) i,i,hamil(i,i)
                do j=i+1, ndets
                    if (abs(hamil(i,j)) > depsilon) write (iunit,*) i,j,hamil(i,j)
                end do
            end do
            close(iunit, status='keep')
        end if

    end subroutine generate_hamil

    subroutine end_hamil()

        ! Clean up hamiltonian module.

        integer :: ierr

        deallocate(hamil, stat=ierr)

    end subroutine end_hamil

    subroutine exact_diagonalisation()
    
        ! Perform an exact diagonalisation of the Hamiltonian matrix.
        ! Note that this destroys the Hamiltonian matrix stored in hamil.

        real(dp), allocatable :: eigv(:), work(:)
        integer :: info, ierr, lwork<commit_msg>Initial structure for distribution of the Hamiltonian matrix.<commit_after>module hamiltonian

use const
use basis
use determinants
use hubbard
use parallel

implicit none

! Flags for doing exact and/or Lanczos diagonalisation.
logical :: t_exact = .false., t_lanczos = .false.

! Hamiltonian matrix.  Clearly the scaling of the memory demands with system
! size is horrendous.
real(dp), allocatable :: hamil(:,:) ! (ndets, ndets)

! If true, then the eigenvectors are found during exact diagonalisation as well
! as the eigenvalues.  Doing this is substantially more expensive.
logical :: find_eigenvectors = .false.

! If true then the non-zero elements of the Hamiltonian matrix are written to hamiltonian_file.
logical :: write_hamiltonian = .false.
character(255) :: hamiltonian_file = 'HAMIL'

! Number of Lanczos eigenpairs to find.
integer :: nlanczos_eigv = 5
! Size of Lanczos basis.
integer :: lanczos_basis_length = 40

! BLACS info for diagonalisation
type(blacs_info) :: proc_blacs_info

! Procedure to multiply the hamiltonian matrix by a Lanczos vector.
private :: hamil_vector

contains

    subroutine generate_hamil(distribute_mode)

        ! Generate the Hamiltonian matrix.
        ! Only generate the upper diagonal for use with Lapack routines.

        use utils, only: get_free_unit
        use errors

        integer, optional :: distribute_mode
        integer, parameter :: distribute_off = 0, distribute_blocks = 1, distribute_cols = 2
        integer :: ierr, i, j, iunit, distribute, n1, n2

        if (allocated(hamil)) then
            deallocate(hamil, stat=ierr)
        end if

        if (present(distribute_mode)) then
            distribute = distribute_mode
        else
            distribute = distribute_off
        end if

        ! Find dimensions of local array.
        select case(distribute)
        case(distribute_off)
            n1 = ndets
            n2 = ndets
        case(distribute_blocks)
            proc_blacs_info = get_blacs_info(ndets)
        case(distribute_cols)
            call stop_all('generate_hamil','Distribution scheme not currently implemented.')
        case default
            call stop_all('generate_hamil','Unknown distribution scheme.')
        end select

        allocate(hamil(n1,n2), stat=ierr)

        ! Form the Hamiltonian matrix < D_i | H | D_j >.
        select case(distribute)
        case(distribute_off)
            forall (i=1:ndets) 
                forall (j=i:ndets) hamil(i,j) = get_hmatel(i,j)
            end forall
        case(distribute_blocks)
            call stop_all('generate_hamil','Distribution scheme not currently implemented.')
        case(distribute_cols)
            call stop_all('generate_hamil','Distribution scheme not currently implemented.')
        end select

        if (write_hamiltonian) then
            if (nprocs > 1) then
                if (parent) call warning('generate_hamil','Output of hamiltonian not implemented in parallel.')
            else
                iunit = get_free_unit()
                open(iunit, file=hamiltonian_file, status='unknown')
                do i=1,ndets
                    write (iunit,*) i,i,hamil(i,i)
                    do j=i+1, ndets
                        if (abs(hamil(i,j)) > depsilon) write (iunit,*) i,j,hamil(i,j)
                    end do
                end do
                close(iunit, status='keep')
            end if
        end if

    end subroutine generate_hamil

    subroutine end_hamil()

        ! Clean up hamiltonian module.

        integer :: ierr

        deallocate(hamil, stat=ierr)

    end subroutine end_hamil

    subroutine exact_diagonalisation()
    
        ! Perform an exact diagonalisation of the Hamiltonian matrix.
        ! Note that this destroys the Hamiltonian matrix stored in hamil.

        real(dp), allocatable :: eigv(:), work(:)
        integer :: info, ierr, lwork
{'fraction_non_alphanumeric': 0.08010701920050362, 'fraction_numerical': 0.004878816493547372, 'mean_word_length': 2.438852813852814, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5174774', 'n_tokens_mistral': 1939, 'n_tokens_neox': 1814, 'n_words': 589}