add_rdm_1_to_rdm_2 Subroutine

public subroutine add_rdm_1_to_rdm_2(rdm_1, rdm_2, scale_factor)

Arguments

Type IntentOptional Attributes Name
type(rdm_list_t), intent(in) :: rdm_1
type(rdm_list_t), intent(inout) :: rdm_2
real(kind=dp), intent(in), optional :: scale_factor

Contents

Source Code


Source Code

    subroutine add_rdm_1_to_rdm_2(rdm_1, rdm_2, scale_factor)

        ! Take the RDM elements in the rdm_1 object, and add them to the rdm_2
        ! object. The hash table for rdm_2 will also be updated. This literally
        ! performs the numerical addition of the two RDM objects.
        use SystemData, only: nel, nBasis
        use hash, only: hash_table_lookup, add_hash_table_entry
        use Parallel_neci, only: MPISumAll

        type(rdm_list_t), intent(in) :: rdm_1
        type(rdm_list_t), intent(inout) :: rdm_2
        real(dp), intent(in), optional :: scale_factor

        integer :: ielem
        integer(int_rdm) :: ijkl
        integer :: ij, kl, i, j, k, l ! spin or spatial orbitals
        integer :: ind, hash_val
        real(dp) :: real_sign_old(rdm_2%sign_length), real_sign_new(rdm_2%sign_length)
        real(dp) :: spawn_sign(rdm_2%sign_length)
        real(dp) :: internal_scale_factor(rdm_1%sign_length), rdm_trace(rdm_1%sign_length)
        logical :: tSuccess
        character(*), parameter :: this_routine = 'add_rdm_1_to_rdm_2'

        if (present(scale_factor)) then
            if (tGUGA) then
                call stop_all(this_routine, "check scale factor and trace for GUGA!")
            end if
            ! normalize and rescale the rdm_1 if requested here
            call calc_rdm_trace(rdm_1, rdm_trace)
            call MPISumAll(rdm_trace, internal_scale_factor)
            internal_scale_factor = scale_factor * (nel * (nel - 1)) / (2 * internal_scale_factor)
        else
            internal_scale_factor = 1.0_dp
        end if

        if (rdm_1%sign_length /= rdm_2%sign_length) &
            call stop_all(this_routine, "nrdms mismatch")

        do ielem = 1, rdm_1%nelements
            ! Decode the compressed RDM labels.
            ijkl = rdm_1%elements(0, ielem)
            if (tGUGA) then
                call extract_2_rdm_ind(ijkl, i, j, k, l)
            else
                call calc_separate_rdm_labels(ijkl, ij, kl, i, j, k, l)
            end if

            ! Extract the spawned sign.
            call extract_sign_rdm(rdm_1%elements(:, ielem), spawn_sign)

            ! Search to see if this RDM element is already in the RDM 2.
            ! If it, tSuccess will be true and ind will hold the position of the
            ! element in rdm.
            ASSERT(all([i, j, k, l] > 0) .and. all([i, j, k, l] <= nBasis))

            call hash_table_lookup((/i, j, k, l/), (/ijkl/), 0, rdm_2%hash_table, rdm_2%elements, ind, hash_val, tSuccess)

            if (tSuccess) then
                ! Extract the existing sign.
                call extract_sign_rdm(rdm_2%elements(:, ind), real_sign_old)

                ! Update the total sign.
                real_sign_new = real_sign_old + spawn_sign * internal_scale_factor
                ! Encode the new sign.
                call encode_sign_rdm(rdm_2%elements(:, ind), real_sign_new)
            else
                ! If we don't have enough memory in rdm_2, try increasing its
                ! size to be 1.5 times bigger.
                if (rdm_2%nelements + 1 > rdm_2%max_nelements) then
                    call try_rdm_list_realloc(rdm_2, int(1.5 * rdm_2%max_nelements), .false.)
                end if

                ! Update the rdm array, and its hash table, and the number of
                ! RDM elements.
                rdm_2%nelements = rdm_2%nelements + 1
                rdm_2%elements(0, rdm_2%nelements) = ijkl
                call encode_sign_rdm(rdm_2%elements(:, rdm_2%nelements), spawn_sign)
                call add_hash_table_entry(rdm_2%hash_table, rdm_2%nelements, hash_val)
            end if
        end do

    end subroutine add_rdm_1_to_rdm_2