excitation_generators.F90 Source File


Contents


Source Code

#include "macros.h"

module excitation_generators
    use constants, only: dp, n_int, maxExcit
    use util_mod, only: operator(.isclose.)
    use SystemData, only: nel, nBasis
    use bit_rep_data, only: NIfTot
    use FciMCData, only: excit_gen_store_type, pSingles, pDoubles
    use dSFMT_interface, only: genrand_real2_dSFMT
    use procedure_pointers, only: generate_excitation_t
    use SymExcitDataMod, only: ScratchSize
    use DetBitOps, only: ilut_lt, ilut_gt, EncodeBitDet
    use sets_mod, only: operator(.complement.)
    use symexcit3, only: gen_excits
    use sort_mod, only: sort
    use procedure_pointers, only: generate_excitation, gen_all_excits
    implicit none
    private
    public :: ExcitationGenerator_t, &
        SingleExcitationGenerator_t, DoubleExcitationGenerator_t, TripleExcitationGenerator_t, &
        FCISingleExcitationGenerator_t, FCIDoubleExcitationGenerator_t, &
        gen_exc_sd, get_pgen_sd, gen_all_excits_sd, ClassicAbInitExcitationGenerator_t

    type, abstract :: ExcitationGenerator_t
    contains
        procedure(BoundGenExc_t), public, deferred :: gen_exc
        procedure(BoundGetPgen_t), public, deferred :: get_pgen
        procedure(BoundGenAllExcits_t), public, deferred :: gen_all_excits
        procedure(BoundFinalize_t), public, deferred :: finalize
            !! This procedure finalizes.
            !! It has to be implemented in such a way, that one can
            !! call it on uninitialized instances and in particular
            !! it should be idempotent.
    end type

    type, abstract, extends(ExcitationGenerator_t) :: SingleExcitationGenerator_t
    end type

    type, abstract, extends(SingleExcitationGenerator_t) :: FCISingleExcitationGenerator_t
    contains
        procedure, public :: gen_all_excits => FCI_singles_gen_all_excits
    end type

    type, abstract, extends(ExcitationGenerator_t) :: DoubleExcitationGenerator_t
    end type

    type, abstract, extends(DoubleExcitationGenerator_t) :: FCIDoubleExcitationGenerator_t
    contains
        procedure, public :: gen_all_excits => FCI_doubles_gen_all_excits
    end type

    type, abstract, extends(ExcitationGenerator_t) :: TripleExcitationGenerator_t
    end type

    type, abstract, extends(ExcitationGenerator_t) :: ClassicAbInitExcitationGenerator_t
        !! this abstract excitation generator covers all ab initio Hamiltonians
        !! in the typical sense (i.e. up to double excitations)
        private
        class(DoubleExcitationGenerator_t), public, allocatable :: doubles_generator
        class(SingleExcitationGenerator_t), public, allocatable :: singles_generator
    contains
        private
        procedure, public :: gen_exc => abinit_gen_exc
        procedure, public :: get_pgen => abinit_get_pgen
        procedure, public :: gen_all_excits => abinit_gen_all_excits
        procedure, public :: finalize => abinit_finalize
    end type

    abstract interface
        subroutine BoundGenExc_t(this, nI, ilutI, nJ, ilutJ, exFlag, ic, &
                                         ex, tParity, pGen, hel, store, part_type)
            import :: ExcitationGenerator_t, n_int, dp, excit_gen_store_type, nEl, NifTot, maxExcit
            implicit none
            class(ExcitationGenerator_t), intent(inout) :: this
            integer, intent(in) :: nI(nel), exFlag
            integer(n_int), intent(in) :: ilutI(0:NIfTot)
            integer, intent(out) :: nJ(nel), ic, ex(2, maxExcit)
            integer(n_int), intent(out) :: ilutJ(0:NifTot)
            real(dp), intent(out) :: pGen
            logical, intent(out) :: tParity
            HElement_t(dp), intent(out) :: hel
            type(excit_gen_store_type), intent(inout), target :: store
            integer, intent(in), optional :: part_type
        end subroutine BoundGenExc_t

        subroutine BoundGenAllExcits_t(this, nI, n_excits, det_list)
            import :: ExcitationGenerator_t, n_int, nEl
            class(ExcitationGenerator_t), intent(in) :: this
            integer, intent(in) :: nI(nEl)
            integer, intent(out) :: n_excits
            integer(n_int), allocatable, intent(out) :: det_list(:,:)
        end subroutine BoundGenAllExcits_t

        subroutine BoundFinalize_t(this)
            import :: ExcitationGenerator_t
            class(ExcitationGenerator_t), intent(inout) :: this
        end subroutine BoundFinalize_t

        real(dp) function BoundGetPgen_t(this, nI, ilutI, ex, ic, ClassCount2, ClassCountUnocc2)
            import :: ExcitationGenerator_t, n_int, dp, ScratchSize, maxExcit, NifTot, nEl
            class(ExcitationGenerator_t), intent(inout) :: this
            integer, intent(in) :: nI(nel)
            integer(n_int), intent(in) :: ilutI(0:NIfTot)
            integer, intent(in) :: ex(2, maxExcit), ic
            integer, intent(in) :: ClassCount2(ScratchSize), ClassCountUnocc2(ScratchSize)
        end function BoundGetPgen_t
    end interface
contains

    !>  @brief
    !>  The excitation generator subroutine for singles and doubles
    subroutine gen_exc_sd(nI, ilutI, nJ, ilutJ, exFlag, ic, &
                        ex, tParity, pGen, hel, store, part_type, &
                        singles_generator, doubles_generator)
        integer, intent(in) :: nI(nel), exFlag
        integer(n_int), intent(in) :: ilutI(0:NIfTot)
        integer, intent(out) :: nJ(nel), ic, ex(2, maxExcit)
        integer(n_int), intent(out) :: ilutJ(0:NifTot)
        real(dp), intent(out) :: pGen
        logical, intent(out) :: tParity
        HElement_t(dp), intent(out) :: hel
        type(excit_gen_store_type), intent(inout), target :: store
        integer, intent(in), optional :: part_type
        class(SingleExcitationGenerator_t), intent(inout) :: singles_generator
        class(DoubleExcitationGenerator_t), intent(inout) :: doubles_generator

        if (genrand_real2_dSFMT() < pSingles) then
            ic = 1
            call singles_generator%gen_exc(nI, ilutI, nJ, ilutJ, exFlag, ic, &
                                                ex, tParity, pGen, hel, store, part_type)
            pgen = pgen * pSingles
        else
            ic = 2
            call doubles_generator%gen_exc(nI, ilutI, nJ, ilutJ, exFlag, ic, &
                                                ex, tParity, pGen, hel, store, part_type)
            pgen = pgen * pDoubles
        end if
    end subroutine


    function get_pgen_sd(nI, ilutI, ex, ic, ClassCount2, ClassCountUnocc2, &
                         singles_generator, doubles_generator) result(pgen)
        integer, intent(in) :: nI(nel)
        integer(n_int), intent(in) :: ilutI(0:NIfTot)
        integer, intent(in) :: ex(2, maxExcit), ic
        integer, intent(in) :: ClassCount2(ScratchSize), ClassCountUnocc2(ScratchSize)
        class(SingleExcitationGenerator_t), intent(inout) :: singles_generator
        class(DoubleExcitationGenerator_t), intent(inout) :: doubles_generator
        real(dp) :: pgen

        if (ic == 1) then
            pgen = pSingles * singles_generator%get_pgen(nI, ilutI, ex, ic, ClassCount2, ClassCountUnocc2)
        else if (ic == 2) then
            pgen = (1.0 - pSingles) * doubles_generator%get_pgen(nI, ilutI, ex, ic, ClassCount2, ClassCountUnocc2)
        else
            pgen = 0.0_dp
        end if
    end function

    subroutine gen_all_excits_sd(nI, n_excits, det_list, singles_generator, doubles_generator)
        integer, intent(in) :: nI(nEl)
        integer, intent(out) :: n_excits
        integer(n_int), allocatable, intent(out) :: det_list(:,:)
        class(SingleExcitationGenerator_t), intent(in) :: singles_generator
        class(DoubleExcitationGenerator_t), intent(in) :: doubles_generator

        integer :: idummy
        integer(n_int), allocatable :: singles(:, :), doubles(:, :)

        call singles_generator%gen_all_excits(nI, idummy, singles)
        call doubles_generator%gen_all_excits(nI, idummy, doubles)

        n_excits = size(singles, 2) + size(doubles, 2)
        allocate(det_list(0:niftot, n_excits))

        det_list(:, : size(singles, 2)) = singles(:, :)
        det_list(:, size(singles, 2) + 1 :) = doubles(:, :)
        call sort(det_list, ilut_lt, ilut_gt)
    end subroutine

    subroutine FCI_singles_gen_all_excits(this, nI, n_excits, det_list)
        class(FCISingleExcitationGenerator_t), intent(in) :: this
        integer, intent(in) :: nI(nEl)
        integer, intent(out) :: n_excits
        integer(n_int), allocatable, intent(out) :: det_list(:,:)
        unused_var(this)
        call gen_excits(nI, n_excits, det_list, ex_flag=1)
    end subroutine

    subroutine FCI_doubles_gen_all_excits(this, nI, n_excits, det_list)
        class(FCIDoubleExcitationGenerator_t), intent(in) :: this
        integer, intent(in) :: nI(nEl)
        integer, intent(out) :: n_excits
        integer(n_int), allocatable, intent(out) :: det_list(:,:)
        unused_var(this)
        call gen_excits(nI, n_excits, det_list, ex_flag=2)
    end subroutine

    !!! ClassicAbInitExcitationGenerator_t methods !!!
    subroutine abinit_gen_exc(this, nI, ilutI, nJ, ilutJ, exFlag, ic, &
        ex, tParity, pGen, hel, store, part_type)
        class(ClassicAbInitExcitationGenerator_t), intent(inout) :: this
        integer, intent(in) :: nI(nel), exFlag
        integer(n_int), intent(in) :: ilutI(0:NIfTot)
        integer, intent(out) :: nJ(nel), ic, ex(2, maxExcit)
        integer(n_int), intent(out) :: ilutJ(0:NifTot)
        real(dp), intent(out) :: pGen
        logical, intent(out) :: tParity
        HElement_t(dp), intent(out) :: hel
        type(excit_gen_store_type), intent(inout), target :: store
        integer, intent(in), optional :: part_type

        call gen_exc_sd(nI, ilutI, nJ, ilutJ, exFlag, ic, &
            ex, tParity, pGen, hel, store, part_type, &
            this%singles_generator, this%doubles_generator)
    end subroutine abinit_gen_exc

    real(dp) function abinit_get_pgen(&
            this, nI, ilutI, ex, ic, ClassCount2, ClassCountUnocc2) &
                result(pgen)
        class(ClassicAbInitExcitationGenerator_t), intent(inout) :: this
        integer, intent(in) :: nI(nel)
        integer(n_int), intent(in) :: ilutI(0:NIfTot)
        integer, intent(in) :: ex(2, maxExcit), ic
        integer, intent(in) :: ClassCount2(ScratchSize), ClassCountUnocc2(ScratchSize)
        pgen = get_pgen_sd(&
                        nI, ilutI, ex, ic, ClassCount2, ClassCountUnocc2, &
                        this%singles_generator, this%doubles_generator)
    end function abinit_get_pgen


    subroutine abinit_gen_all_excits(this, nI, n_excits, det_list)
        class(ClassicAbInitExcitationGenerator_t), intent(in) :: this
        integer, intent(in) :: nI(nEl)
        integer, intent(out) :: n_excits
        integer(n_int), allocatable, intent(out) :: det_list(:,:)
        call gen_all_excits_sd(nI, n_excits, det_list, &
                               this%singles_generator, this%doubles_generator)
    end subroutine abinit_gen_all_excits

    subroutine abinit_finalize(this)
        class(ClassicAbInitExcitationGenerator_t), intent(inout) :: this
        if (allocated(this%doubles_generator)) then
            call this%doubles_generator%finalize()
            call this%singles_generator%finalize()
            ! Yes, we assume that either both or none are allocated
            deallocate(this%singles_generator, this%doubles_generator)
        end if
    end subroutine abinit_finalize

end module