23#include "../../base/base_uses.f90" 
   48   CHARACTER(len=*), 
PARAMETER, 
PRIVATE :: moduleN = 
'dbt_tas_split' 
   56      MODULE PROCEDURE dbt_tas_mp_comm_from_matrix_sizes
 
 
   74      INTEGER, 
INTENT(INOUT)                             :: ngroup
 
   75      INTEGER, 
INTENT(IN)                                :: igroup, split_rowcol
 
   76      LOGICAL, 
INTENT(IN), 
OPTIONAL                      :: own_comm
 
   78      CHARACTER(LEN=*), 
PARAMETER :: routinen = 
'dbt_tas_create_split_rows_or_cols' 
   80      INTEGER                                            :: handle, igroup_check, iproc, &
 
   81                                                            iproc_group, iproc_group_check, &
 
   83      INTEGER, 
DIMENSION(2)                              :: pdims, pdims_group
 
   84      LOGICAL                                            :: own_comm_prv, to_assert
 
   87      CALL timeset(routinen, handle)
 
   89      IF (
PRESENT(own_comm)) 
THEN 
   90         own_comm_prv = own_comm
 
   92         own_comm_prv = .false.
 
   95      IF (own_comm_prv) 
THEN 
   96         split_info%mp_comm = mp_comm
 
   98         CALL split_info%mp_comm%from_dup(mp_comm)
 
  101      split_info%igroup = igroup
 
  102      split_info%split_rowcol = split_rowcol
 
  104      CALL mp_comm_group%from_split(mp_comm, igroup)
 
  106      iproc = mp_comm%mepos
 
  107      pdims = mp_comm%num_pe_cart
 
  108      split_info%pdims = pdims
 
  110      numproc_group = mp_comm_group%num_pe
 
  111      iproc_group = mp_comm_group%mepos
 
  114         to_assert = mod(numproc_group, pdims(mod(split_rowcol, 2) + 1)) == 0
 
  116         split_info%pgrid_split_size = numproc_group/pdims(mod(split_rowcol, 2) + 1)
 
  118      CALL split_info%mp_comm%bcast(split_info%pgrid_split_size, 0)
 
  120      ngroup = (pdims(split_rowcol) + split_info%pgrid_split_size - 1)/split_info%pgrid_split_size
 
  121      split_info%ngroup = ngroup
 
  122      split_info%group_size = split_info%pgrid_split_size*pdims(mod(split_rowcol, 2) + 1)
 
  124      CALL world_to_group_proc_map(iproc, pdims, split_rowcol, split_info%pgrid_split_size, igroup_check, pdims_group, iproc_group)
 
  126      IF (igroup_check .NE. split_info%igroup) 
THEN 
  127         cpabort(
'inconsistent subgroups')
 
  130      CALL split_info%mp_comm_group%create(mp_comm_group, 2, pdims_group)
 
  132      iproc_group_check = split_info%mp_comm_group%mepos
 
  134      cpassert(iproc_group_check .EQ. iproc_group)
 
  136      CALL mp_comm_group%free()
 
  138      ALLOCATE (split_info%refcount)
 
  139      split_info%refcount = 1
 
  141      CALL timestop(handle)
 
 
  156      INTEGER, 
INTENT(IN)                                :: split_rowcol, nsplit
 
  159      CHARACTER(LEN=*), 
PARAMETER                        :: routinen = 
'dbt_tas_mp_comm' 
  161      INTEGER                                            :: handle, numproc
 
  162      INTEGER, 
DIMENSION(2)                              :: npdims
 
  164      CALL timeset(routinen, handle)
 
  166      numproc = mp_comm%num_pe
 
  172      CALL timestop(handle)
 
 
  184      INTEGER, 
INTENT(IN)                                :: numproc, split_rowcol, nsplit
 
  187      INTEGER                                            :: group_size, nsplit_opt
 
  188      INTEGER, 
DIMENSION(2)                              :: group_dims
 
  190      nsplit_opt = get_opt_nsplit(numproc, nsplit, split_pgrid=.false.)
 
  192      group_size = numproc/nsplit_opt
 
  199      SELECT CASE (split_rowcol)
 
  201         group_dims = [minval(group_dims), maxval(group_dims)]
 
  203         group_dims = [maxval(group_dims), minval(group_dims)]
 
  206      SELECT CASE (split_rowcol)
 
 
  225   FUNCTION get_opt_nsplit(numproc, nsplit, split_pgrid, pdim_nonsplit)
 
  226      INTEGER, 
INTENT(IN)                                :: numproc, nsplit
 
  227      LOGICAL, 
INTENT(IN)                                :: split_pgrid
 
  228      INTEGER, 
INTENT(IN), 
OPTIONAL                      :: pdim_nonsplit
 
  229      INTEGER                                            :: get_opt_nsplit
 
  231      INTEGER                                            :: count, count_accept, count_square, lb, &
 
  233      INTEGER, 
ALLOCATABLE, 
DIMENSION(:)                 :: nsplit_list, nsplit_list_accept, &
 
  235      INTEGER, 
DIMENSION(2)                              :: dims_sub
 
  239      IF (split_pgrid) 
THEN 
  240         cpassert(
PRESENT(pdim_nonsplit))
 
  248      ALLOCATE (nsplit_list(1:ub - lb + 1), nsplit_list_square(1:ub - lb + 1), nsplit_list_accept(1:ub - lb + 1))
 
  253         IF (mod(numproc, split) == 0) 
THEN 
  255            nsplit_list(count) = split
 
  258            IF (.NOT. split_pgrid) 
THEN 
  261               dims_sub = [numproc/split, pdim_nonsplit]
 
  264            IF (dims_sub(1) == dims_sub(2)) 
THEN 
  265               count_square = count_square + 1
 
  266               nsplit_list_square(count_square) = split
 
  267               count_accept = count_accept + 1
 
  268               nsplit_list_accept(count_accept) = split
 
  270               count_accept = count_accept + 1
 
  271               nsplit_list_accept(count_accept) = split
 
  277      IF (count_square > 0) 
THEN 
  278         minpos = minloc(abs(nsplit_list_square(1:count_square) - nsplit), dim=1)
 
  279         get_opt_nsplit = nsplit_list_square(minpos)
 
  280      ELSEIF (count_accept > 0) 
THEN 
  281         minpos = minloc(abs(nsplit_list_accept(1:count_accept) - nsplit), dim=1)
 
  282         get_opt_nsplit = nsplit_list_accept(minpos)
 
  283      ELSEIF (count > 0) 
THEN 
  284         minpos = minloc(abs(nsplit_list(1:count) - nsplit), dim=1)
 
  285         get_opt_nsplit = nsplit_list(minpos)
 
  287         get_opt_nsplit = nsplit
 
  288         DO WHILE (mod(numproc, get_opt_nsplit) .NE. 0)
 
  289            get_opt_nsplit = get_opt_nsplit - 1
 
  304   FUNCTION dbt_tas_mp_comm_from_matrix_sizes(mp_comm, nblkrows, nblkcols) 
RESULT(mp_comm_new)
 
  306      INTEGER(KIND=int_8), 
INTENT(IN)                    :: nblkrows, nblkcols
 
  309      INTEGER                                            :: nsplit, split_rowcol
 
  311      IF (nblkrows >= nblkcols) 
THEN 
  313         nsplit = int((nblkrows - 1)/nblkcols + 1)
 
  316         nsplit = int((nblkcols - 1)/nblkrows + 1)
 
 
  335      INTEGER, 
INTENT(IN)                                :: split_rowcol, nsplit
 
  336      LOGICAL, 
INTENT(IN), 
OPTIONAL                      :: own_comm, opt_nsplit
 
  338      CHARACTER(LEN=*), 
PARAMETER :: routinen = 
'dbt_tas_create_split' 
  340      INTEGER                                            :: handle, igroup, iproc, nsplit_opt, &
 
  341                                                            pdim_nonsplit, pdim_split
 
  342      INTEGER, 
DIMENSION(2)                              :: pcoord, pdims, pdims_group
 
  343      LOGICAL                                            :: opt_nsplit_prv
 
  345      CALL timeset(routinen, handle)
 
  347      IF (
PRESENT(opt_nsplit)) 
THEN 
  348         opt_nsplit_prv = opt_nsplit
 
  350         opt_nsplit_prv = .true.
 
  355      iproc = mp_comm%mepos
 
  356      pdims = mp_comm%num_pe_cart
 
  357      pcoord = mp_comm%mepos_cart
 
  359      SELECT CASE (split_rowcol)
 
  361         pdim_split = pdims(1)
 
  362         pdim_nonsplit = pdims(2)
 
  364         pdim_split = pdims(2)
 
  365         pdim_nonsplit = pdims(1)
 
  368      IF (opt_nsplit_prv) 
THEN 
  369         nsplit_opt = get_opt_nsplit(pdim_split, nsplit, split_pgrid=.true., pdim_nonsplit=pdim_nonsplit)
 
  371         IF (mod(pdims(split_rowcol), nsplit) .NE. 0) 
THEN 
  372            cpabort(
"Split factor does not divide process grid dimension")
 
  378      pdims_group(split_rowcol) = pdims_group(split_rowcol)/nsplit_opt
 
  380      igroup = pcoord(split_rowcol)/pdims_group(split_rowcol)
 
  385         ALLOCATE (split_info%ngroup_opt, source=nsplit)
 
  388      CALL timestop(handle)
 
 
  400      INTEGER, 
DIMENSION(2), 
INTENT(IN)                  :: dims
 
  401      LOGICAL, 
INTENT(IN)                                :: relative
 
  404      INTEGER, 
DIMENSION(2)                              :: dims_opt
 
 
  429      INTEGER, 
INTENT(OUT), 
OPTIONAL                     :: nsplit, igroup
 
  430      TYPE(
mp_cart_type), 
INTENT(OUT), 
OPTIONAL          :: mp_comm_group
 
  431      INTEGER, 
INTENT(OUT), 
OPTIONAL                     :: split_rowcol
 
  432      INTEGER, 
DIMENSION(2), 
INTENT(OUT), 
OPTIONAL       :: pgrid_offset
 
  434      IF (
PRESENT(mp_comm)) mp_comm = info%mp_comm
 
  435      IF (
PRESENT(mp_comm_group)) mp_comm_group = info%mp_comm_group
 
  436      IF (
PRESENT(split_rowcol)) split_rowcol = info%split_rowcol
 
  437      IF (
PRESENT(igroup)) igroup = info%igroup
 
  438      IF (
PRESENT(nsplit)) nsplit = info%ngroup
 
  440      IF (
PRESENT(pgrid_offset)) 
THEN 
  441         SELECT CASE (info%split_rowcol)
 
  443            pgrid_offset(:) = [info%igroup*info%pgrid_split_size, 0]
 
  445            pgrid_offset(:) = [0, info%igroup*info%pgrid_split_size]
 
 
  463      IF (.NOT. 
ASSOCIATED(split_info%refcount)) 
THEN 
  465      ELSEIF (split_info%refcount < 1) 
THEN 
  470         cpabort(
"can not destroy non-existing split_info")
 
  473      split_info%refcount = split_info%refcount - 1
 
  475      IF (split_info%refcount == 0) 
THEN 
  476         CALL split_info%mp_comm_group%free()
 
  477         CALL split_info%mp_comm%free()
 
  478         DEALLOCATE (split_info%refcount)
 
  483      IF (
ALLOCATED(split_info%ngroup_opt)) 
DEALLOCATE (split_info%ngroup_opt)
 
 
  494      INTEGER, 
POINTER                                   :: ref
 
  496      IF (split_info%refcount < 1) 
THEN 
  497         cpabort(
"can not hold non-existing split_info")
 
  499      ref => split_info%refcount
 
 
  515                                      pdims_group, iproc_group)
 
  516      INTEGER, 
INTENT(IN)                                :: iproc
 
  517      INTEGER, 
DIMENSION(2), 
INTENT(IN)                  :: pdims
 
  518      INTEGER, 
INTENT(IN)                                :: split_rowcol, pgrid_split_size
 
  519      INTEGER, 
INTENT(OUT)                               :: igroup
 
  520      INTEGER, 
DIMENSION(2), 
INTENT(OUT), 
OPTIONAL       :: pdims_group
 
  521      INTEGER, 
INTENT(OUT), 
OPTIONAL                     :: iproc_group
 
  523      INTEGER, 
DIMENSION(2)                              :: pcoord, pcoord_group
 
  525      IF (
PRESENT(iproc_group)) 
THEN 
  526         cpassert(
PRESENT(pdims_group))
 
  529      pcoord = [iproc/pdims(2), mod(iproc, pdims(2))]
 
  531      igroup = pcoord(split_rowcol)/pgrid_split_size
 
  533      SELECT CASE (split_rowcol)
 
  535         IF (
PRESENT(pdims_group)) pdims_group = [pgrid_split_size, pdims(2)]
 
  536         IF (
PRESENT(iproc_group)) pcoord_group = [mod(pcoord(1), pgrid_split_size), pcoord(2)]
 
  538         IF (
PRESENT(pdims_group)) pdims_group = [pdims(1), pgrid_split_size]
 
  539         IF (
PRESENT(iproc_group)) pcoord_group = [pcoord(1), mod(pcoord(2), pgrid_split_size)]
 
  541      IF (
PRESENT(iproc_group)) iproc_group = pcoord_group(1)*pdims_group(2) + pcoord_group(2)
 
 
  556      INTEGER, 
INTENT(OUT)                               :: iproc
 
  557      INTEGER, 
DIMENSION(2), 
INTENT(IN)                  :: pdims
 
  558      INTEGER, 
INTENT(IN)                                :: split_rowcol, pgrid_split_size, igroup, &
 
  561      INTEGER, 
DIMENSION(2)                              :: pcoord, pcoord_group, pdims_group
 
  563      SELECT CASE (split_rowcol)
 
  565         pdims_group = [pgrid_split_size, pdims(2)]
 
  567         pdims_group = [pdims(1), pgrid_split_size]
 
  570      pcoord_group = [iproc_group/pdims_group(2), mod(iproc_group, pdims_group(2))]
 
  572      SELECT CASE (split_rowcol)
 
  574         pcoord = [igroup*pgrid_split_size + pcoord_group(1), pcoord_group(2)]
 
  576         pcoord = [pcoord_group(1), igroup*pgrid_split_size + pcoord_group(2)]
 
  578      iproc = pcoord(1)*pdims(2) + pcoord(2)
 
 
  594      INTEGER, 
INTENT(IN), 
OPTIONAL                      :: row_group, column_group
 
  595      INTEGER(KIND=int_8), 
INTENT(OUT), 
OPTIONAL         :: row, column
 
  597      SELECT CASE (info%split_rowcol)
 
  599         associate(rows => dist%local_rowcols)
 
  600            IF (
PRESENT(row)) row = rows(row_group)
 
  601            IF (
PRESENT(column)) column = column_group
 
  604         associate(cols => dist%local_rowcols)
 
  605            IF (
PRESENT(row)) row = row_group
 
  606            IF (
PRESENT(column)) column = cols(column_group)
 
 
  622      TYPE(dbt_tas_split_info), 
INTENT(IN)               :: info
 
  623      TYPE(dbt_tas_distribution_type), 
INTENT(IN)        :: dist
 
  624      INTEGER(KIND=int_8), 
INTENT(IN), 
OPTIONAL          :: row, column
 
  625      INTEGER, 
INTENT(OUT), 
OPTIONAL                     :: row_group, column_group
 
  627      SELECT CASE (info%split_rowcol)
 
  629         IF (
PRESENT(row_group)) row_group = i8_bsearch(dist%local_rowcols, row)
 
  630         IF (
PRESENT(column_group)) column_group = int(column)
 
  632         IF (
PRESENT(row_group)) row_group = int(row)
 
  633         IF (
PRESENT(column_group)) column_group = i8_bsearch(dist%local_rowcols, column)
 
 
  647   FUNCTION i8_bsearch(array, el, l_index, u_index) 
RESULT(res)
 
  648      INTEGER(KIND=int_8), 
INTENT(in)                    :: array(:), el
 
  649      INTEGER, 
INTENT(in), 
OPTIONAL                      :: l_index, u_index
 
  652      INTEGER                                            :: aindex, lindex, uindex
 
  656      IF (
PRESENT(l_index)) lindex = l_index
 
  657      IF (
PRESENT(u_index)) uindex = u_index
 
  658      DO WHILE (lindex <= uindex)
 
  659         aindex = (lindex + uindex)/2
 
  660         IF (array(aindex) < el) 
THEN 
  678      TYPE(dbt_tas_split_info), 
INTENT(IN)               :: info
 
  680      CLASS(dbt_tas_distribution), 
INTENT(IN)                     :: rowcol_dist
 
  681      INTEGER, 
INTENT(IN)                                         :: igroup
 
  682      INTEGER(KIND=int_8), 
DIMENSION(:), 
ALLOCATABLE, 
INTENT(OUT) :: rowcols
 
  683      INTEGER, 
DIMENSION(0:info%pgrid_split_size - 1)             :: nrowcols_group
 
  684      INTEGER                                                     :: pcoord, nrowcols, count, pcoord_group
 
  685      INTEGER, 
DIMENSION(:), 
ALLOCATABLE                          :: sort_indices
 
  687      nrowcols_group(:) = 0
 
  688      DO pcoord = igroup*info%pgrid_split_size, (igroup + 1)*info%pgrid_split_size - 1
 
  689         pcoord_group = pcoord - igroup*info%pgrid_split_size
 
  690         nrowcols_group(pcoord_group) = 
SIZE(rowcol_dist%rowcols(pcoord))
 
  692      nrowcols = sum(nrowcols_group)
 
  694      ALLOCATE (rowcols(nrowcols))
 
  697      DO pcoord = igroup*info%pgrid_split_size, (igroup + 1)*info%pgrid_split_size - 1
 
  698         pcoord_group = pcoord - igroup*info%pgrid_split_size
 
  699         rowcols(count + 1:count + nrowcols_group(pcoord_group)) = rowcol_dist%rowcols(pcoord)
 
  700         count = count + nrowcols_group(pcoord_group)
 
  703      ALLOCATE (sort_indices(nrowcols))
 
  704      CALL sort(rowcols, nrowcols, sort_indices)
 
 
  713      TYPE(dbt_tas_split_info), 
INTENT(INOUT)            :: info
 
  715      info%strict_split = [.true., .true.]
 
 
Global data (distribution and block sizes) for tall-and-skinny matrices For very sparse matrices with...
methods to split tall-and-skinny matrices along longest dimension. Basically, we are splitting proces...
subroutine, public dbt_index_global_to_local(info, dist, row, column, row_group, column_group)
map global block index to group local index
integer function, dimension(2), public dbt_tas_mp_dims(numproc, split_rowcol, nsplit)
Get optimal process grid dimensions consistent with dbt_tas_create_split.
subroutine, public group_to_mrowcol(info, rowcol_dist, igroup, rowcols)
maps a process subgroup to matrix rows/columns
subroutine, public dbt_tas_release_info(split_info)
...
subroutine, public dbt_index_local_to_global(info, dist, row_group, column_group, row, column)
map group local block index to global matrix index
integer, parameter, public rowsplit
subroutine, public dbt_tas_get_split_info(info, mp_comm, nsplit, igroup, mp_comm_group, split_rowcol, pgrid_offset)
Get info on split.
integer, parameter, public colsplit
subroutine, public dbt_tas_create_split(split_info, mp_comm, split_rowcol, nsplit, own_comm, opt_nsplit)
Split Cartesian process grid using a default split heuristic.
subroutine, public dbt_tas_create_split_rows_or_cols(split_info, mp_comm, ngroup, igroup, split_rowcol, own_comm)
split mpi grid by rows or columns
real(dp), parameter, public default_nsplit_accept_ratio
subroutine, public world_to_group_proc_map(iproc, pdims, split_rowcol, pgrid_split_size, igroup, pdims_group, iproc_group)
map global process info to group
real(dp), parameter, public default_pdims_accept_ratio
subroutine, public dbt_tas_info_hold(split_info)
...
subroutine, public dbt_tas_set_strict_split(info)
freeze current split factor such that it is never changed during multiplication
subroutine, public group_to_world_proc_map(iproc, pdims, split_rowcol, pgrid_split_size, igroup, iproc_group)
map local process info to global info
logical function, public accept_pgrid_dims(dims, relative)
Whether to accept proposed process grid dimensions (based on ratio of dimensions)
DBT tall-and-skinny base types. Mostly wrappers around existing DBM routines.
Defines the basic variable types.
integer, parameter, public int_8
integer, parameter, public dp
Interface to the message passing library MPI.
subroutine, public mp_dims_create(nodes, dims)
wrapper to MPI_Dims_create
All kind of helpful little routines.