sc_make_subcom_2 Subroutine

private subroutine sc_make_subcom_2(self)

Uses

Create the secondary (intraobject) subcommunicators

Type Bound

supercell_type

Arguments

Type IntentOptional Attributes Name
class(supercell_type), intent(inout) :: self

Contents

Source Code


Source Code

  subroutine sc_make_subcom_2(self)
    use mp, only: comm_type, split, sum_allreduce_sub, proc0
    use mp, only: mp_undefined, min_allreduce_sub, nproc, iproc
    implicit none
    class(supercell_type), intent(inout) :: self
    integer :: colour, cc
    integer, dimension(3) :: colours
    type(comm_type) :: tmp
    logical :: some_empty, some_pd, some_all, is_partial_data
    !Exit if we don't have this supercell
    if (.not. self%is_local) return

    ! Set local flags
    colours = 0
    is_partial_data = .not. (self%is_empty .or. self%is_all_local)
    if (self%is_empty) colours(1) = 1
    if (is_partial_data) colours(2) = 1
    if (self%is_all_local) colours(3) = 1

    ! Get global flags
    call sum_allreduce_sub(colours, self%sc_sub_all%id)

    !/Work out if we have any empty procs
    some_empty = colours(1) /= 0
    !/Work out if we have any partial data procs
    some_pd = colours(2) /= 0
    !/Work out if we have any all local procs
    some_all = colours(3) /= 0

    !/Now make a subcommunicator involving all procs
    !which have part of the supercell data range (but not all of it)
    if (some_pd) then
       colour = mp_undefined
       if (is_partial_data) colour = 1
       call split(colour, tmp, self%sc_sub_all%id)
       if (colour /= mp_undefined) then
          !/Store communicator
          self%sc_sub_pd = tmp
       end if
    end if

    !Decide if we're the head proc
    !Note: We also decide which proc is in charge of filling the empty
    !procs with data. By allowing this to be different from the head proc
    !we have a better chance of being able to overlap comms and computations
    !Note: We try to make proc0 the head proc if it is a member of the supercell
    !which has data as it means we don't need to send this supercell to anyone.
    if (some_all) then
       ! Here we try to determine which processor will be the head.
       ! If proc0 is included and has is_all_local we prefer that. If not we can
       ! identify the head as the first proc in sc_sub_all which has is_all_local.
       ! 1. We can determine if proc0 is present and has is_all_local
       !    by simply setting cc = (proc0 .and. self%is_all_local) ? 1 : 0
       !    and then reducing that on sc_sub_all.
       ! 2. If proc0 is not present then the head will just be the proc with
       !    the lowest rank in sc_sub_all with is_all_local true. Therefore we
       !    instead take min_allreduce of cc = is_all_local ? sc_sub_all%iproc : nproc + 1
       !    and then set self%is_head = sc_sub_all%iproc == cc
       ! Work out if proc0 is a member of sc_sub_all _and_ has is_all_local
       cc = 0
       if (proc0 .and. self%is_all_local) cc = 1
       call sum_allreduce_sub(cc, self%sc_sub_all%id)
       if (cc == 1) then
          ! If we have proc0 then that is head
          self%is_head = proc0
       else
          if (self%is_all_local) then
             cc = self%sc_sub_all%iproc
          else
             cc = nproc + 1
          end if
          ! We don't currently have an implementation for this.
          call min_allreduce_sub(cc, self%sc_sub_all%id)
          ! If we don't have proc0 then the head is the processor
          ! with the lowest rank in sc_sub_all which has is_all_local
          self%is_head = cc == self%sc_sub_all%iproc
       end if
    else
       if (self%sc_sub_pd%nproc > 0)then
          cc = 0
          if (proc0) cc = 1
          call sum_allreduce_sub(cc, self%sc_sub_pd%id)

          !Decide if we're the head, prefer proc0 to be head
          !if it's a member of our group
          if (cc /= 0) then
             self%is_head = proc0
          else
             self%is_head = self%sc_sub_pd%proc0
          end if
       end if
    end if

    !Store the head_iproc values
    colours = 0
    if (self%is_head) then
       colours(1) = self%sc_sub_all%iproc
       colours(2) = self%sc_sub_pd%iproc
       colours(3) = iproc
    end if

    call sum_allreduce_sub(colours, self%sc_sub_all%id)
    self%head_iproc = colours(1)
    self%head_iproc_pd = colours(2)
    self%head_iproc_world = colours(3)
  end subroutine sc_make_subcom_2