apply_symmetries_for_output Subroutine

public subroutine apply_symmetries_for_output(rdm, rdm_recv, spawn, open_shell)

Arguments

Type IntentOptional Attributes Name
type(rdm_list_t), intent(in) :: rdm
type(rdm_list_t), intent(inout) :: rdm_recv
type(rdm_spawn_t), intent(inout) :: spawn
logical, intent(in) :: open_shell

Contents


Source Code

    subroutine apply_symmetries_for_output(rdm, rdm_recv, spawn, open_shell)

        ! This routine will take in rdm, and output a new rdm which will have
        ! all appropriate symmetries applied so that the latter RDM can be
        ! passed to the routine to write RDMs.

        ! The input RDM must already have hermiticy symmetry applied to it.

        ! WARNING: To clarify potential confusion, we point out that this
        ! routine also applies hermiticy again, but *only* for the spatial
        ! labels, not the full spin labels. It does so specifically using a
        ! particular legacy ordering. This is not a mistake - for open shell
        ! systems we do need to apply full hermiticy, but also need to apply spatial
        ! hermiticy because spatial labels are written within each output file.

        use rdm_data_utils, only: annihilate_rdm_list

        type(rdm_list_t), intent(in) :: rdm
        type(rdm_list_t), intent(inout) :: rdm_recv
        type(rdm_spawn_t), intent(inout) :: spawn
        logical, intent(in) :: open_shell

        integer(int_rdm) :: ijkl
        integer :: ielem
        integer :: ij, kl, i, j, k, l ! spin orbitals
        integer :: p, q, r, s ! spatial orbitals
        integer :: pq_legacy, rs_legacy ! spatial orbitals
        real(dp) :: rdm_sign(rdm%sign_length)
        logical :: nearly_full, finished, all_finished
#ifdef DEBUG_
        character(*), parameter :: this_routine = "apply_symmetries_for_output"
#endif
        ASSERT(.not. tGUGA)

        ! If we're about to fill up the spawn list, perform a communication.
        nearly_full = .false.
        ! Have we finished adding RDM elements to the spawned list?
        finished = .false.
        rdm_recv%nelements = 0

        do ielem = 1, rdm%nelements
            ! If the spawned list is nearly full, perform a communication.
            if (nearly_full) then
                call communicate_rdm_spawn_t_wrapper(spawn, rdm_recv, finished, all_finished)
                nearly_full = .false.
            end if

            ijkl = rdm%elements(0, ielem)
            ! Obtain spin orbital labels and the RDM element.
            call calc_separate_rdm_labels(ijkl, ij, kl, i, j, k, l)
            call extract_sign_rdm(rdm%elements(:, ielem), rdm_sign)

            ! When there are two elements which are guaranteed to be exactly the
            ! same, we usually only want to print one of them (and to average
            ! over the equal terms). This function returns the labels we want.
            call apply_legacy_output_ordering(i, j, k, l, rdm_sign, pq_legacy, rs_legacy)

            ! For closed shell systems, want bbbb -> aaaa, baba -> abab,
            ! baab -> abba, by flipping all spins, which is a symmetry for such
            ! systems. If the first label has beta spin then we definitely want
            ! to move this RDM element to the equivalent flipped term so go ahead
            ! and flip all the spins.
            if (.not. open_shell) then
                if (is_beta(i)) then
                    ! The ab_pair macro swaps alpha and beta spins of a label
                    ! while keeping the spatial orbital unchanged.
                    i = ab_pair(i)
                    j = ab_pair(j)
                    k = ab_pair(k)
                    l = ab_pair(l)
                end if
                ! If the spatial parts of i and j are the same, and the spatial
                ! parts of k and l are *also* the same, then the RDM element won't
                ! have been added into both equivalent spin-flipped arrays
                ! because i<j and k<l is enforced), so we don't count twice.
                if (.not. (is_in_pair(i, j) .and. is_in_pair(k, l))) then
                    ! Also, if (i,j) and (k,l) have the same spatial parts, but
                    ! different spin parts ((alpha,beta) and (beta,alpha), or
                    ! vice versa) then they only occur once, again because we
                    ! enforce i<j and k<l for all stored RDM elements.
                    if (.not. (pq_legacy == rs_legacy .and. (.not. ij == kl))) then
                        rdm_sign = rdm_sign * 0.5_dp
                    end if
                end if
            end if

            call add_to_rdm_spawn_t(spawn, i, j, k, l, rdm_sign, .false., nearly_full)

            if (open_shell) then
                ! For open shell systems, if i and j have the same spatial parts,
                ! and k and l do too, then we only have baba spin signature,
                ! (because we enforce i<j, k<l) but we'd like to print out abab too.
                if (is_in_pair(i, j) .and. is_in_pair(k, l)) then
                    call add_to_rdm_spawn_t(spawn, j, i, l, k, rdm_sign, .false., nearly_full)
                end if

                ! Because we enforce hermiticy symmetry in the output, we would
                ! only print the following terms with baab. We want to print it
                ! with abba too here, so do that.
                if (pq_legacy == rs_legacy .and. (.not. ij == kl)) then
                    call add_to_rdm_spawn_t(spawn, k, l, i, j, rdm_sign, .false., nearly_full)
                end if
            end if
        end do

        finished = .true.
        ! Keep performing communications until all RDM spawnings on every
        ! processor have been communicated.
        do
            call communicate_rdm_spawn_t_wrapper(spawn, rdm_recv, finished, all_finished)
            if (all_finished) exit
        end do
        call annihilate_rdm_list(rdm_recv)

    end subroutine apply_symmetries_for_output