Create the secondary (intraobject) subcommunicators
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
class(supercell_type), | intent(inout) | :: | self |
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