core_space_util.F90 Source File


Contents

Source Code


Source Code

#include "macros.h"

module core_space_util
    use mpi
    use constants
    use shared_rhash, only: shared_rhash_t
    use shared_memory_mpi
    use MemoryManager, only: TagIntType, LogMemAlloc, LogMemDealloc
    use MPI_wrapper
    use fcimcdata, only: t_global_core_space, core_run
    implicit none

    private
    public :: core_space_t, cs_replicas, sparse_matrix_real, sparse_matrix_int, &
              deallocate_sparse_ham, min_pt, max_pt

    integer, parameter :: min_pt = 1
    integer, parameter :: max_pt = rep_size

    type sparse_matrix_real
        HElement_t(dp), allocatable, dimension(:) :: elements
        integer, allocatable, dimension(:) :: positions
        integer :: num_elements
    end type sparse_matrix_real

    type sparse_matrix_int
        integer, allocatable, dimension(:) :: elements
        integer, allocatable, dimension(:) :: positions
        integer :: num_elements
    end type sparse_matrix_int

    ! Info type containing the characterization of the core space on a given replica
    type :: core_space_t
        ! determ_sizes(i) holds the core space size on processor i.
        integer(MPIArg), allocatable, dimension(:) :: determ_sizes
        ! determ_displs(i) holds sum(determ_sizes(i-1)), that is, the
        ! total number of core states on all processors up to processor i.
        ! (determ_displs(1) == 0).
        integer(MPIArg), allocatable, dimension(:) :: determ_displs
        ! determ_last(i) holds the final index belonging process i.
        integer(MPIArg), allocatable, dimension(:) :: determ_last
        ! The total size of the core space on all processors.
        integer(MPIArg) :: determ_space_size
        ! determ_space_size_int is identical to determ_space_size, but converted
        ! to the default integer kind.
        integer :: determ_space_size_int
        ! This vector will store the indicies of the deterministic states in CurrentDets. This is worked out in the main loop.
        integer, allocatable, dimension(:) :: indices_of_determ_states

        ! This stores the entire core space from all processes, on each process.
        integer(n_int), pointer, dimension(:, :) :: core_space => null()
        integer(n_int), pointer, dimension(:, :) :: core_space_direct => null()
        integer(MPIArg) :: core_space_win

        type(shared_rhash_t) :: core_ht

        ! The core Hamiltonian for semi-stochastiic simulations.
        type(sparse_matrix_real), allocatable, dimension(:) :: sparse_core_ham
        integer(TagIntType), allocatable, dimension(:, :) :: SparseCoreHamilTags
        ! This stores all the amplitudes of the walkers in the deterministic space. This vector has the size of the part
        ! of the deterministic space stored on *this* processor only. It is therefore used to store the deterministic vector
        ! on this processor, before it is combined to give the whole vector, which is stored in full_determ_vecs.
        ! Later in the iteration, it is also used to store the result of the multiplication by the core Hamiltonian on
        ! full_determ_vecs.
        real(dp), allocatable, dimension(:, :) :: partial_determ_vecs
        real(dp), allocatable, dimension(:, :) :: full_determ_vecs
        real(dp), allocatable, dimension(:, :) :: full_determ_vecs_av
        integer(TagIntType) :: FDetermTag, FDetermAvTag, PDetermTag, IDetermTag, CoreSpaceTag
        ! Stores the parities for all connected pairs of states in the core space.
        type(sparse_matrix_int), allocatable, dimension(:) :: core_connections

        ! The diagonal elements of the core-space Hamiltonian (with Hii taken away).
        real(dp), allocatable, dimension(:) :: core_ham_diag

        ! ilut Sign range in which this core space operates
        integer :: max_run, min_run

        ! Is this a global core space?
        logical :: t_global
    contains
        procedure :: alloc_wf
        procedure :: associate_run
        procedure :: dealloc

        procedure :: max_part
        procedure :: min_part

        procedure :: first_run
        procedure :: last_run
    end type core_space_t

    ! Each replica has its own core space information
    type(core_space_t), allocatable :: cs_replicas(:)

contains

    ! Interface function giving access to the core space replicas: This serves to
    ! switch between models with one core space per replica or one shared core space
    ! efficiently
    pure function max_part(this) result(ir)
        class(core_space_t), intent(in) :: this
        integer :: ir

        unused_var(this)
        ir = max_part_type(this%max_run)
    end function max_part

    pure function min_part(this) result(ir)
        class(core_space_t), intent(in) :: this
        integer :: ir

        unused_var(this)
        ir = min_part_type(this%min_run)
    end function min_part

!------------------------------------------------------------------------------------------!

    pure function last_run(this) result(ir)
        class(core_space_t), intent(in) :: this
        integer :: ir

        ir = this%max_run
    end function last_run

    pure function first_run(this) result(ir)
        class(core_space_t), intent(in) :: this
        integer :: ir

        ir = this%min_run
    end function first_run

    !------------------------------------------------------------------------------------------!

    ! Associate this core space with a replica
    subroutine associate_run(this, t_global, run)
        class(core_space_t), intent(inout) :: this
        logical, intent(in) :: t_global
        integer, intent(in) :: run

        this%t_global = t_global
        if (this%t_global) then
            this%min_run = 1
            this%max_run = inum_runs
        else
            this%min_run = run
            this%max_run = run
        end if
    end subroutine associate_run

    !------------------------------------------------------------------------------------------!

    subroutine alloc_wf(this)
        class(core_space_t), intent(inout) :: this
        integer :: vec_size
        integer :: ierr
        character(*), parameter :: t_r = "core_space_t%alloc_wf"

        ! Store the operating range of this core space
        if (this%t_global) then
            vec_size = lenof_sign
        else
            vec_size = rep_size
        end if

        ! Allocate the vectors to store the walker amplitudes and the deterministic Hamiltonian.
        allocate(this%full_determ_vecs(vec_size, this%determ_space_size), stat=ierr)
        call LogMemAlloc('full_determ_vecs', this%determ_space_size_int * lenof_sign, &
                         8, t_r, this%FDetermTag, ierr)
        allocate(this%full_determ_vecs_av(vec_size, this%determ_space_size), stat=ierr)
        call LogMemAlloc('full_determ_vecs_av', this%determ_space_size_int * lenof_sign, &
                         8, t_r, this%FDetermAvTag, ierr)
        allocate(this%partial_determ_vecs(vec_size, this%determ_sizes(iProcIndex)), stat=ierr)
        call LogMemAlloc('partial_determ_vecs', int(this%determ_sizes(iProcIndex), &
                                                    sizeof_int) * lenof_sign, 8, t_r, this%PDetermTag, ierr)

        this%full_determ_vecs = 0.0_dp
        this%full_determ_vecs_av = 0.0_dp
        this%partial_determ_vecs = 0.0_dp

    end subroutine alloc_wf

!------------------------------------------------------------------------------------------!

    subroutine dealloc(this)
        class(core_space_t), intent(inout) :: this
        character(*), parameter :: t_r = "core_space_t%dealloc"
        integer :: ierr
        call this%core_ht%dealloc()
        if (allocated(this%indices_of_determ_states)) then
            deallocate(this%indices_of_determ_states, stat=ierr)
            call LogMemDealloc(t_r, this%IDetermTag, ierr)
        end if
        if (associated(this%core_space)) then
            this%core_space => null()
            call shared_deallocate_mpi(this%core_space_win, this%core_space_direct)
            call LogMemDealloc(t_r, this%CoreSpaceTag, ierr)
        end if

        if (allocated(this%determ_sizes)) then
            deallocate(this%determ_sizes, stat=ierr)
            if (ierr /= 0) write(stdout, '("Error when deallocating determ_sizes:",1X,i8)') ierr
        end if
        if (allocated(this%determ_displs)) then
            deallocate(this%determ_displs, stat=ierr)
            if (ierr /= 0) write(stdout, '("Error when deallocating determ_displs:",1X,i8)') ierr
        end if
        if (allocated(this%determ_last)) then
            deallocate(this%determ_last, stat=ierr)
            if (ierr /= 0) write(stdout, '("Error when deallocating determ_last:",1X,i8)') ierr
        end if

        if (allocated(this%partial_determ_vecs)) then
            deallocate(this%partial_determ_vecs, stat=ierr)
            call LogMemDealloc(t_r, this%PDetermTag, ierr)
        end if
        if (allocated(this%full_determ_vecs)) then
            deallocate(this%full_determ_vecs, stat=ierr)
            call LogMemDealloc(t_r, this%FDetermTag, ierr)
        end if
        if (allocated(this%full_determ_vecs_av)) then
            deallocate(this%full_determ_vecs_av, stat=ierr)
            call LogMemDealloc(t_r, this%FDetermAvTag, ierr)
        end if

        call deallocate_sparse_ham(this%sparse_core_ham, this%SparseCoreHamilTags)

        call deallocate_sparse_matrix_int(this%core_connections)
        if (allocated(this%core_ham_diag)) then
            deallocate(this%core_ham_diag, stat=ierr)
        end if

    end subroutine dealloc

    subroutine deallocate_sparse_ham(sparse_matrix, sparse_tags)

        ! Deallocate the whole array, and remove all rows from the memory manager.

        type(sparse_matrix_real), intent(inout), allocatable :: sparse_matrix(:)
        integer(TagIntType), intent(inout), allocatable :: sparse_tags(:, :)
        integer :: sparse_matrix_size, i, ierr
        character(len=*), parameter :: t_r = "deallocate_sparse_ham"

        sparse_matrix_size = size(sparse_matrix)

        do i = sparse_matrix_size, 1, -1

            deallocate(sparse_matrix(i)%elements, stat=ierr)
            !call LogMemDealloc(t_r, sparse_tags(1,i), ierr)

            deallocate(sparse_matrix(i)%positions, stat=ierr)
            !call LogMemDealloc(t_r, sparse_tags(2,i), ierr)

        end do

        if (allocated(sparse_tags)) deallocate(sparse_tags)
        if (allocated(sparse_matrix)) deallocate(sparse_matrix)

    end subroutine deallocate_sparse_ham

    subroutine deallocate_sparse_matrix_int(sparse_mat)

        type(sparse_matrix_int), intent(inout), allocatable :: sparse_mat(:)

        integer :: i, ierr

        if (allocated(sparse_mat)) then
            do i = 1, size(sparse_mat)
                if (allocated(sparse_mat(i)%elements)) then
                    deallocate(sparse_mat(i)%elements, stat=ierr)
                    if (ierr /= 0) write(stdout, '("Error when deallocating sparse matrix elements array:",1X,i8)') ierr
                end if
                if (allocated(sparse_mat(i)%positions)) then
                    deallocate(sparse_mat(i)%positions, stat=ierr)
                    if (ierr /= 0) write(stdout, '("Error when deallocating sparse matrix positions array:",1X,i8)') ierr
                end if
            end do

            deallocate(sparse_mat, stat=ierr)
            if (ierr /= 0) write(stdout, '("Error when deallocating sparse matrix array:",1X,i8)') ierr
        end if

    end subroutine deallocate_sparse_matrix_int

    pure function get_core_run(run) result(crun)
        integer, intent(in) :: run
        integer :: crun

        if(t_global_core_space) then
            crun = core_run
        else
            crun = run
        end if
    end function get_core_run

end module core_space_util