determ_projection Subroutine

public subroutine determ_projection()

Arguments

None

Contents

Source Code


Source Code

    subroutine determ_projection()

        ! This subroutine gathers together partial_determ_vecs from each processor so
        ! that the full vector for the whole deterministic space is stored on each processor.
        ! It then performs the deterministic multiplication of the projector on this full vector.

        use FciMCData, only: SemiStoch_Comms_Time
        use FciMCData, only: SemiStoch_Multiply_Time
        use Parallel_neci, only: MPIBarrier, MPIAllGatherV
        use DetBitOps, only: DetBitEQ
        integer :: run
        integer :: i, j, part_type, c_run
        integer :: ierr
        integer(MPIArg) :: MPIerr
        real(dp) :: scaledDiagSft(inum_runs)

        do run = 1, size(cs_replicas)
            associate(rep => cs_replicas(run))
                call MPIBarrier(ierr)

                call set_timer(SemiStoch_Comms_Time)

                call MPIAllGatherV(rep%partial_determ_vecs, rep%full_determ_vecs, &
                                   rep%determ_sizes, rep%determ_displs)

                call halt_timer(SemiStoch_Comms_Time)

                call set_timer(SemiStoch_Multiply_Time)

                if (rep%determ_sizes(iProcIndex) >= 1) then

                    ! For the moment, we're only adding in these contributions when we need the energy
                    ! This will need refinement if we want to continue with the option of inst vs true full RDMs
                    ! (as in another CMO branch).

                    ! Perform the multiplication.

                    rep%partial_determ_vecs = 0.0_dp

#ifdef CMPLX_
                    block
                        integer :: r_pt, i_pt
                        do i = 1, rep%determ_sizes(iProcIndex)
                            do j = 1, rep%sparse_core_ham(i)%num_elements
                                do r_pt = rep%min_part(), rep%max_part(), 2
                                    i_pt = r_pt + 1
                                    rep%partial_determ_vecs(r_pt, i) = rep%partial_determ_vecs(r_pt, i) &
                                        - Real(rep%sparse_core_ham(i)%elements(j)) &
                                         * rep%full_determ_vecs(r_pt, rep%sparse_core_ham(i)%positions(j)) &
                                        + Aimag(rep%sparse_core_ham(i)%elements(j)) &
                                         * rep%full_determ_vecs(i_pt, rep%sparse_core_ham(i)%positions(j))

                                    rep%partial_determ_vecs(i_pt, i) = rep%partial_determ_vecs(i_pt, i) &
                                        - Aimag(rep%sparse_core_ham(i)%elements(j)) &
                                         * rep%full_determ_vecs(r_pt, rep%sparse_core_ham(i)%positions(j)) &
                                        - Real(rep%sparse_core_ham(i)%elements(j)) &
                                        * rep%full_determ_vecs(i_pt, rep%sparse_core_ham(i)%positions(j))
                                end do
                            end do
                        end do
                    end block
#else

                    do i = 1, rep%determ_sizes(iProcIndex)
                        do j = 1, rep%sparse_core_ham(i)%num_elements
                            rep%partial_determ_vecs(:, i) = rep%partial_determ_vecs(:, i) &
                                - rep%sparse_core_ham(i)%elements(j) &
                                 * rep%full_determ_vecs(:, rep%sparse_core_ham(i)%positions(j))
                        end do
                    end do
#endif

                    ! Now add shift*full_determ_vecs to account for the shift, not stored in
                    ! sparse_core_ham.
#ifdef CMPLX_
                    do i = 1, rep%determ_sizes(iProcIndex)
                        ! Only scale the shift for the corespace when the option is set
                        if (tCoreAdaptiveShift .and. tAdaptiveShift) then
                            ! scale the shift using the abs of this run's complex coefficient
                            scaledDiagSft(run) = &
                                shiftFactorFunction( &
                                rep%indices_of_determ_states(i), run, &
                                    sqrt(rep%full_determ_vecs(&
                                            min_pt, i + rep%determ_displs(iProcIndex))**2 + &
                                        rep%full_determ_vecs(&
                                            max_pt, i + rep%determ_displs(iProcIndex))**2)) &
                                    * DiagSft(run)
                        else
                            scaledDiagSft = DiagSft
                        end if

                        do part_type = 1, size(rep%partial_determ_vecs, dim=1)
                            ! Convert the index along partial_determ_vecs into a part_type
                            rep%partial_determ_vecs(part_type, i) = &
                                rep%partial_determ_vecs(part_type, i) + &
                                scaledDiagSft(part_type_to_run(rep%min_part() + part_type - 1)) &
                                * rep%full_determ_vecs(part_type, i + rep%determ_displs(iProcIndex))
                        end do
                    end do
#else
                    do i = 1, rep%determ_sizes(iProcIndex)
                        ! Only scale the shift for the corespace when the option is set
                        if (tCoreAdaptiveShift .and. tAdaptiveShift) then
                            ! Here, translate between positins in the full_determ_vecs
                            ! and replicas
                            if (rep%t_global) then
                                c_run = run
                            else
                                c_run = 1
                            end if
                            ! get the re-scaled shift accounting for undersampling error
                            scaledDiagSft(run) = DiagSft(run) * shiftFactorFunction( &
                                 rep%indices_of_determ_states(i), run, &
                                 abs(rep%full_determ_vecs(c_run, i + rep%determ_displs(iProcIndex))))
                        else
                            scaledDiagSft = DiagSft
                        end if
                        rep%partial_determ_vecs(:, i) = rep%partial_determ_vecs(:, i) &
                            + scaledDiagSft(run) * rep%full_determ_vecs(:, i + rep%determ_displs(iProcIndex))
                    end do
#endif

                    ! Now multiply the vector by tau to get the final projected vector.
                    rep%partial_determ_vecs = rep%partial_determ_vecs * tau

                    do i = 1, rep%determ_sizes(iProcIndex)
                        if (tSkipRef(run) .and. DetBitEQ(CurrentDets(:, rep%indices_of_determ_states(i)), &
                            iLutRef(:, run), nIfD)) then
                            rep%partial_determ_vecs(:, i) = 0.0_dp
                        end if
                    end do
                end if
            end associate

            call halt_timer(SemiStoch_Multiply_Time)
        end do
    end subroutine determ_projection