mimic_sort_fragments Subroutine

public subroutine mimic_sort_fragments(subsystem, quantum_fragment, cutoff_distance, sorting_method)

sort fragments into short- and long-range according to distance criterion

Arguments

TypeIntentOptionalAttributesName
type(subsystem_type), intent(inout) :: subsystem

array of subsystems associated with client codes

type(quantum_fragment_type), intent(in) :: quantum_fragment

the quantum fragment

real(kind=dp), intent(in) :: cutoff_distance

distance cutoff

integer, intent(in) :: sorting_method

sorting method (centroid, center_of_mass, center_of_charge, minimum_distance)


Contents

Source Code


Source Code

subroutine mimic_sort_fragments(subsystem, quantum_fragment, cutoff_distance, sorting_method)

    intrinsic :: norm2

    !> array of subsystems associated with client codes
    type(subsystem_type), intent(inout) :: subsystem
    !> the quantum fragment
    type(quantum_fragment_type), intent(in) :: quantum_fragment
    !> distance cutoff
    real(dp), intent(in) :: cutoff_distance
    !> sorting method (centroid, center_of_mass, center_of_charge, minimum_distance)
    integer, intent(in) :: sorting_method

    integer :: i, j, k
    integer :: num_atoms
    integer, dimension(:), allocatable :: sr_indices
    integer, dimension(:), allocatable :: lr_indices
    integer, dimension(:), allocatable :: temporary_indices
    real(dp) :: distance
    real(dp), dimension(3) :: fragment_center
    real(dp), dimension(3) :: qm_fragment_center

    call timer_start("mimic_sort_fragments")

    if (allocated(subsystem%sr_atoms)) then
        deallocate(subsystem%sr_atoms)
    end if
    if (allocated(subsystem%lr_atoms)) then
        deallocate(subsystem%lr_atoms)
    end if
    if (allocated(subsystem%sr_fragments)) then
        deallocate(subsystem%sr_fragments)
    end if
    if (allocated(subsystem%lr_fragments)) then
        deallocate(subsystem%lr_fragments)
    end if

    allocate(sr_indices(0))
    allocate(lr_indices(0))

    select case (sorting_method)
    ! sort according to distance between centroids
    case (CENTROID)
        qm_fragment_center = quantum_fragment%centroid()
        do i = 1, subsystem%num_fragments
            fragment_center = subsystem%fragments(i)%centroid()
            distance = norm2(fragment_center - qm_fragment_center)
            if (distance <= cutoff_distance) then
                call move_alloc(sr_indices, temporary_indices)
                allocate(sr_indices, source=[temporary_indices, i])
            else
                call move_alloc(lr_indices, temporary_indices)
                allocate(lr_indices, source=[temporary_indices, i])
            end if
        end do
    ! sort according to distance between center-of-mass
    case (CENTER_OF_MASS)
        qm_fragment_center = quantum_fragment%center_of_mass()
        do i = 1, subsystem%num_fragments
            fragment_center = subsystem%fragments(i)%center_of_mass()
            distance = norm2(fragment_center - qm_fragment_center)
            if (distance <= cutoff_distance) then
                call move_alloc(sr_indices, temporary_indices)
                allocate(sr_indices, source=[temporary_indices, i])
            else
                call move_alloc(lr_indices, temporary_indices)
                allocate(lr_indices, source=[temporary_indices, i])
            end if
        end do
    ! sort according to distance between center-of-charge for charged fragments and center-of-mass for other fragments
    case (CENTER_OF_CHARGE)
        qm_fragment_center = quantum_fragment%center_of_charge()
        do i = 1, subsystem%num_fragments
            if (nint(subsystem%fragments(i)%charge) /= 0) then
                fragment_center = subsystem%fragments(i)%center_of_charge()
            else
                fragment_center = subsystem%fragments(i)%center_of_mass()
            end if
            distance = norm2(fragment_center - qm_fragment_center)
            if (distance <= cutoff_distance) then
                call move_alloc(sr_indices, temporary_indices)
                allocate(sr_indices, source=[temporary_indices, i])
            else
                call move_alloc(lr_indices, temporary_indices)
                allocate(lr_indices, source=[temporary_indices, i])
            end if
        end do
    ! sort according to minimum distance
    case (MINIMUM_DISTANCE)
        do i = 1, subsystem%num_fragments
            distance = compute_minimum_distance(subsystem%fragments(i)%atoms, quantum_fragment%nuclei)
            if (distance <= cutoff_distance) then
                call move_alloc(sr_indices, temporary_indices)
                allocate(sr_indices, source=[temporary_indices, i])
            else
                call move_alloc(lr_indices, temporary_indices)
                allocate(lr_indices, source=[temporary_indices, i])
            end if
        end do
    ! sort individual atoms into one short-range and one long-range fragment
    case (ATOM_WISE)
        qm_fragment_center = quantum_fragment%centroid()
        do i = 1, subsystem%num_atoms
            distance = norm2(qm_fragment_center - subsystem%atoms(i)%coordinate)
            if (distance <= cutoff_distance) then
                call move_alloc(sr_indices, temporary_indices)
                allocate(sr_indices, source=[temporary_indices, i])
            else
                call move_alloc(lr_indices, temporary_indices)
                allocate(lr_indices, source=[temporary_indices, i])
            end if
        end do
    case default
        call handle_error(SEVERITY_FATAL, &
                          TYPE_INCORRECT_ARG, &
                          "Unrecognized atom sorting method", &
                          __FILE__, __LINE__)
    end select

    if (sorting_method == ATOM_WISE) then
        subsystem%num_sr_fragments = 1
        allocate(subsystem%sr_fragments(subsystem%num_sr_fragments))
        subsystem%num_sr_atoms = size(sr_indices)
        allocate(subsystem%sr_atoms(size(sr_indices)))
        do i = 1, subsystem%num_sr_atoms
            subsystem%sr_atoms(i) = subsystem%atoms(sr_indices(i))
        end do
        call subsystem%sr_fragments(1)%init(1, subsystem%sr_atoms)
        subsystem%num_lr_fragments = 1
        allocate(subsystem%lr_fragments(subsystem%num_lr_fragments))
        subsystem%num_lr_atoms = size(lr_indices)
        allocate(subsystem%lr_atoms(size(lr_indices)))
        do i = 1, subsystem%num_lr_atoms
            subsystem%lr_atoms(i) = subsystem%atoms(lr_indices(i))
        end do
        call subsystem%lr_fragments(1)%init(1, subsystem%lr_atoms)
    else
        subsystem%num_sr_fragments = size(sr_indices)
        allocate(subsystem%sr_fragments(subsystem%num_sr_fragments))
        num_atoms = 0
        do i = 1, subsystem%num_sr_fragments
            subsystem%sr_fragments(i) = subsystem%fragments(sr_indices(i))
            num_atoms = num_atoms + subsystem%sr_fragments(i)%num_atoms
        end do
        subsystem%num_sr_atoms = num_atoms
        allocate(subsystem%sr_atoms(subsystem%num_sr_atoms))
        k = 0
        do i = 1, subsystem%num_sr_fragments
            j = k + 1
            k = k + subsystem%sr_fragments(i)%num_atoms
            subsystem%sr_atoms(j:k) = subsystem%sr_fragments(i)%atoms
        end do
        subsystem%num_lr_fragments = size(lr_indices)
        allocate(subsystem%lr_fragments(subsystem%num_lr_fragments))
        num_atoms = 0
        do i = 1, subsystem%num_lr_fragments
            subsystem%lr_fragments(i) = subsystem%fragments(lr_indices(i))
            num_atoms = num_atoms + subsystem%lr_fragments(i)%num_atoms
        end do
        subsystem%num_lr_atoms = num_atoms
        allocate(subsystem%lr_atoms(subsystem%num_lr_atoms))
        k = 0
        do i = 1, subsystem%num_lr_fragments
            j = k + 1
            k = k + subsystem%lr_fragments(i)%num_atoms
            subsystem%lr_atoms(j:k) = subsystem%lr_fragments(i)%atoms
        end do
    end if

    call timer_stop

end subroutine mimic_sort_fragments