45#include "../base/base_uses.f90" 
   49   CHARACTER(len=*), 
PARAMETER, 
PRIVATE :: moduleN = 
'dbt_types' 
  100      INTEGER                                 :: nproc = -1
 
 
  104      REAL(
dp)         :: nsplit_avg = 0.0_dp
 
  105      INTEGER          :: ibatch = -1
 
  107      LOGICAL          :: static = .false.
 
 
  119      INTEGER, 
DIMENSION(:), 
ALLOCATABLE         :: nblks_local
 
  120      INTEGER, 
DIMENSION(:), 
ALLOCATABLE         :: nfull_local
 
  121      LOGICAL                                    :: valid = .false.
 
  122      LOGICAL                                    :: owns_matrix = .false.
 
  123      CHARACTER(LEN=default_string_length)       :: name = 
"" 
  125      INTEGER, 
POINTER                           :: refcount => null()
 
 
  134      INTEGER, 
POINTER                :: refcount => null()
 
 
  146      INTEGER, 
DIMENSION(:), 
ALLOCATABLE :: dims
 
  147      INTEGER, 
DIMENSION(:), 
ALLOCATABLE :: dims_grid
 
  150      PROCEDURE                          :: dist => tas_dist_t
 
  151      PROCEDURE                          :: rowcols => tas_rowcols_t
 
  160      INTEGER, 
DIMENSION(:), 
ALLOCATABLE :: dims
 
  163      PROCEDURE                          :: data => tas_blk_size_t
 
  167      MODULE PROCEDURE dbt_create_new
 
  168      MODULE PROCEDURE dbt_create_template
 
  169      MODULE PROCEDURE dbt_create_matrix
 
 
  172   INTERFACE dbt_tas_dist_t
 
  173      MODULE PROCEDURE new_dbt_tas_dist_t
 
  176   INTERFACE dbt_tas_blk_size_t
 
  177      MODULE PROCEDURE new_dbt_tas_blk_size_t
 
  191   FUNCTION new_dbt_tas_dist_t(nd_dist, map_blks, map_grid, which_dim)
 
  192      TYPE(array_list), 
INTENT(IN)       :: nd_dist
 
  193      TYPE(nd_to_2d_mapping), 
INTENT(IN) :: map_blks, map_grid
 
  194      INTEGER, 
INTENT(IN)                :: which_dim
 
  196      TYPE(dbt_tas_dist_t)               :: new_dbt_tas_dist_t
 
  197      INTEGER, 
DIMENSION(2)              :: grid_dims
 
  198      INTEGER(KIND=int_8), 
DIMENSION(2)  :: matrix_dims
 
  199      INTEGER, 
DIMENSION(:), 
ALLOCATABLE :: index_map
 
  201      IF (which_dim == 1) 
THEN 
  205                                   dims_2d_i8=matrix_dims, &
 
  207                                   dims1_2d=new_dbt_tas_dist_t%dims)
 
  211                                   dims1_2d=new_dbt_tas_dist_t%dims_grid)
 
  212      ELSEIF (which_dim == 2) 
THEN 
  216                                   dims_2d_i8=matrix_dims, &
 
  218                                   dims2_2d=new_dbt_tas_dist_t%dims)
 
  222                                   dims2_2d=new_dbt_tas_dist_t%dims_grid)
 
  224         cpabort(
"Unknown value for which_dim")
 
  227      new_dbt_tas_dist_t%nd_dist = 
array_sublist(nd_dist, index_map)
 
  228      new_dbt_tas_dist_t%nprowcol = grid_dims(which_dim)
 
  229      new_dbt_tas_dist_t%nmrowcol = matrix_dims(which_dim)
 
  235   FUNCTION tas_dist_t(t, rowcol)
 
  236      CLASS(dbt_tas_dist_t), 
INTENT(IN) :: t
 
  237      INTEGER(KIND=int_8), 
INTENT(IN) :: rowcol
 
  238      INTEGER, 
DIMENSION(4) :: ind_blk
 
  239      INTEGER, 
DIMENSION(4) :: dist_blk
 
  240      INTEGER :: tas_dist_t
 
  250   FUNCTION tas_rowcols_t(t, dist)
 
  251      CLASS(dbt_tas_dist_t), 
INTENT(IN) :: t
 
  252      INTEGER, 
INTENT(IN) :: dist
 
  253      INTEGER(KIND=int_8), 
DIMENSION(:), 
ALLOCATABLE :: tas_rowcols_t
 
  254      INTEGER, 
DIMENSION(4) :: dist_blk
 
  255      INTEGER, 
DIMENSION(:), 
ALLOCATABLE :: dist_1, dist_2, dist_3, dist_4, blks_1, blks_2, blks_3, blks_4, blks_tmp, nd_ind
 
  256      INTEGER :: i_1, i_2, i_3, i_4, i, iblk, iblk_count, nblks
 
  257      INTEGER(KIND=int_8) :: nrowcols
 
  258      TYPE(array_list) :: blks
 
  262         IF (
SIZE(t%dims) == 1) 
THEN 
  265         IF (
SIZE(t%dims) == 2) 
THEN 
  268         IF (
SIZE(t%dims) == 3) 
THEN 
  269            CALL get_arrays(t%nd_dist, dist_1, dist_2, dist_3)
 
  271         IF (
SIZE(t%dims) == 4) 
THEN 
  272            CALL get_arrays(t%nd_dist, dist_1, dist_2, dist_3, dist_4)
 
  275         IF (
SIZE(t%dims) .GE. 1) 
THEN 
  277            ALLOCATE (blks_tmp(nblks))
 
  280               IF (dist_1(iblk) == dist_blk(1)) 
THEN 
  281                  iblk_count = iblk_count + 1
 
  282                  blks_tmp(iblk_count) = iblk
 
  285            ALLOCATE (blks_1(iblk_count))
 
  286            blks_1(:) = blks_tmp(:iblk_count)
 
  287            DEALLOCATE (blks_tmp)
 
  289         IF (
SIZE(t%dims) .GE. 2) 
THEN 
  291            ALLOCATE (blks_tmp(nblks))
 
  294               IF (dist_2(iblk) == dist_blk(2)) 
THEN 
  295                  iblk_count = iblk_count + 1
 
  296                  blks_tmp(iblk_count) = iblk
 
  299            ALLOCATE (blks_2(iblk_count))
 
  300            blks_2(:) = blks_tmp(:iblk_count)
 
  301            DEALLOCATE (blks_tmp)
 
  303         IF (
SIZE(t%dims) .GE. 3) 
THEN 
  305            ALLOCATE (blks_tmp(nblks))
 
  308               IF (dist_3(iblk) == dist_blk(3)) 
THEN 
  309                  iblk_count = iblk_count + 1
 
  310                  blks_tmp(iblk_count) = iblk
 
  313            ALLOCATE (blks_3(iblk_count))
 
  314            blks_3(:) = blks_tmp(:iblk_count)
 
  315            DEALLOCATE (blks_tmp)
 
  317         IF (
SIZE(t%dims) .GE. 4) 
THEN 
  319            ALLOCATE (blks_tmp(nblks))
 
  322               IF (dist_4(iblk) == dist_blk(4)) 
THEN 
  323                  iblk_count = iblk_count + 1
 
  324                  blks_tmp(iblk_count) = iblk
 
  327            ALLOCATE (blks_4(iblk_count))
 
  328            blks_4(:) = blks_tmp(:iblk_count)
 
  329            DEALLOCATE (blks_tmp)
 
  332         IF (
SIZE(t%dims) == 1) 
THEN 
  335         IF (
SIZE(t%dims) == 2) 
THEN 
  338         IF (
SIZE(t%dims) == 3) 
THEN 
  341         IF (
SIZE(t%dims) == 4) 
THEN 
  346      ALLOCATE (tas_rowcols_t(nrowcols))
 
  348         IF (
SIZE(t%dims) == 1) 
THEN 
  351               DO i_1 = 1, 
SIZE(blks_1)
 
  358         IF (
SIZE(t%dims) == 2) 
THEN 
  361               DO i_1 = 1, 
SIZE(blks_1)
 
  362               DO i_2 = 1, 
SIZE(blks_2)
 
  370         IF (
SIZE(t%dims) == 3) 
THEN 
  373               DO i_1 = 1, 
SIZE(blks_1)
 
  374               DO i_2 = 1, 
SIZE(blks_2)
 
  375               DO i_3 = 1, 
SIZE(blks_3)
 
  384         IF (
SIZE(t%dims) == 4) 
THEN 
  387               DO i_1 = 1, 
SIZE(blks_1)
 
  388               DO i_2 = 1, 
SIZE(blks_2)
 
  389               DO i_3 = 1, 
SIZE(blks_3)
 
  390               DO i_4 = 1, 
SIZE(blks_4)
 
  411         FUNCTION new_dbt_tas_blk_size_t(blk_size, map_blks, which_dim)
 
  412            TYPE(array_list), 
INTENT(IN)                   :: blk_size
 
  413            TYPE(nd_to_2d_mapping), 
INTENT(IN)             :: map_blks
 
  414            INTEGER, 
INTENT(IN) :: which_dim
 
  415            INTEGER(KIND=int_8), 
DIMENSION(2) :: matrix_dims
 
  416            INTEGER, 
DIMENSION(:), 
ALLOCATABLE :: index_map
 
  417            TYPE(dbt_tas_blk_size_t) :: new_dbt_tas_blk_size_t
 
  419            IF (which_dim == 1) 
THEN 
  423                                         dims_2d_i8=matrix_dims, &
 
  425                                         dims1_2d=new_dbt_tas_blk_size_t%dims)
 
  426            ELSEIF (which_dim == 2) 
THEN 
  430                                         dims_2d_i8=matrix_dims, &
 
  432                                         dims2_2d=new_dbt_tas_blk_size_t%dims)
 
  434               cpabort(
"Unknown value for which_dim")
 
  437            new_dbt_tas_blk_size_t%blk_size = 
array_sublist(blk_size, index_map)
 
  438            new_dbt_tas_blk_size_t%nmrowcol = matrix_dims(which_dim)
 
  440            new_dbt_tas_blk_size_t%nfullrowcol = product(int(
sum_of_arrays(new_dbt_tas_blk_size_t%blk_size), &
 
  447         FUNCTION tas_blk_size_t(t, rowcol)
 
  448            CLASS(dbt_tas_blk_size_t), 
INTENT(IN) :: t
 
  449            INTEGER(KIND=int_8), 
INTENT(IN) :: rowcol
 
  450            INTEGER :: tas_blk_size_t
 
  451            INTEGER, 
DIMENSION(SIZE(t%dims)) :: ind_blk
 
  452            INTEGER, 
DIMENSION(SIZE(t%dims)) :: blk_size
 
  456            tas_blk_size_t = product(blk_size)
 
  469         PURE FUNCTION accept_pdims_loadbalancing(pdims_avail, pdim, tdim, lb_ratio)
 
  470            INTEGER, 
INTENT(IN) :: pdims_avail
 
  471            INTEGER, 
INTENT(IN) :: pdim
 
  472            INTEGER, 
INTENT(IN) :: tdim
 
  473            REAL(dp), 
INTENT(IN) :: lb_ratio
 
  474            LOGICAL :: accept_pdims_loadbalancing
 
  476            accept_pdims_loadbalancing = .false.
 
  477            IF (mod(pdims_avail, pdim) == 0) 
THEN 
  478               IF (real(tdim, dp)*lb_ratio < real(pdim, dp)) 
THEN 
  479                  IF (mod(tdim, pdim) == 0) accept_pdims_loadbalancing = .true.
 
  481                  accept_pdims_loadbalancing = .true.
 
  498            INTEGER, 
INTENT(IN) :: nodes
 
  499            INTEGER, 
DIMENSION(:), 
INTENT(INOUT) :: dims
 
  500            INTEGER, 
DIMENSION(:), 
INTENT(IN) :: tensor_dims
 
  501            REAL(
dp), 
INTENT(IN), 
OPTIONAL :: lb_ratio
 
  503            INTEGER, 
DIMENSION(:), 
ALLOCATABLE :: tensor_dims_sorted, sort_indices, dims_store
 
  504            REAL(
dp), 
DIMENSION(:), 
ALLOCATABLE :: sort_key
 
  505            INTEGER :: pdims_rem, idim, pdim
 
  506            REAL(
dp) :: lb_ratio_prv
 
  508            IF (
PRESENT(lb_ratio)) 
THEN 
  509               lb_ratio_prv = lb_ratio
 
  511               lb_ratio_prv = 0.1_dp
 
  514            ALLOCATE (dims_store, source=dims)
 
  517            IF (any(dims == 0)) 
THEN 
  522            ALLOCATE (sort_key(
SIZE(tensor_dims)))
 
  523            sort_key(:) = real(tensor_dims, 
dp)/dims
 
  525            ALLOCATE (tensor_dims_sorted, source=tensor_dims)
 
  526            ALLOCATE (sort_indices(
SIZE(sort_key)))
 
  527            CALL sort(sort_key, 
SIZE(sort_key), sort_indices)
 
  528            tensor_dims_sorted(:) = tensor_dims_sorted(sort_indices)
 
  529            dims(:) = dims(sort_indices)
 
  534            DO idim = 1, 
SIZE(tensor_dims_sorted)
 
  535               IF (.NOT. accept_pdims_loadbalancing(pdims_rem, dims(idim), tensor_dims_sorted(idim), lb_ratio_prv)) 
THEN 
  536                  pdim = tensor_dims_sorted(idim)
 
  537                  DO WHILE (.NOT. accept_pdims_loadbalancing(pdims_rem, pdim, tensor_dims_sorted(idim), lb_ratio_prv))
 
  541                  pdims_rem = pdims_rem/dims(idim)
 
  543                  IF (idim .NE. 
SIZE(tensor_dims_sorted)) 
THEN 
  546                  ELSEIF (lb_ratio_prv < 0.5_dp) 
THEN 
  559                  pdims_rem = pdims_rem/dims(idim)
 
  563            dims(sort_indices) = dims
 
 
  595            INTEGER, 
DIMENSION(:), 
INTENT(INOUT) :: dims
 
  597            INTEGER, 
DIMENSION(:), 
INTENT(IN) :: map1_2d, map2_2d
 
  598            INTEGER, 
DIMENSION(:), 
INTENT(IN), 
OPTIONAL :: tensor_dims
 
  599            INTEGER, 
INTENT(IN), 
OPTIONAL :: nsplit, dimsplit
 
  600            INTEGER, 
DIMENSION(2) :: pdims_2d
 
  601            INTEGER :: nproc, ndims, handle
 
  604            CHARACTER(LEN=*), 
PARAMETER :: routinen = 
'dbt_pgrid_create_expert' 
  606            CALL timeset(routinen, handle)
 
  610            nproc = mp_comm%num_pe
 
  611            IF (any(dims == 0)) 
THEN 
  612               IF (.NOT. 
PRESENT(tensor_dims)) 
THEN 
  620            CALL pgrid%mp_comm_2d%create(mp_comm, 2, pdims_2d)
 
  622            IF (
PRESENT(nsplit)) 
THEN 
  623               cpassert(
PRESENT(dimsplit))
 
  625               ALLOCATE (pgrid%tas_split_info, source=info)
 
  631            CALL timestop(handle)
 
 
  651         FUNCTION dbt_nd_mp_comm(comm_2d, map1_2d, map2_2d, dims_nd, dims1_nd, dims2_nd, pdims_2d, tdims, &
 
  654            INTEGER, 
DIMENSION(:), 
INTENT(IN)                 :: map1_2d, map2_2d
 
  655            INTEGER, 
DIMENSION(SIZE(map1_2d) + SIZE(map2_2d)), &
 
  656               INTENT(IN), 
OPTIONAL                           :: dims_nd
 
  657            INTEGER, 
DIMENSION(SIZE(map1_2d)), 
INTENT(IN), 
OPTIONAL :: dims1_nd
 
  658            INTEGER, 
DIMENSION(SIZE(map2_2d)), 
INTENT(IN), 
OPTIONAL :: dims2_nd
 
  659            INTEGER, 
DIMENSION(2), 
INTENT(IN), 
OPTIONAL           :: pdims_2d
 
  660            INTEGER, 
DIMENSION(SIZE(map1_2d) + SIZE(map2_2d)), &
 
  661               INTENT(IN), 
OPTIONAL                           :: tdims
 
  662            INTEGER, 
INTENT(IN), 
OPTIONAL :: nsplit, dimsplit
 
  663            INTEGER                                           :: ndim1, ndim2
 
  664            INTEGER, 
DIMENSION(2)                             :: dims_2d
 
  666            INTEGER, 
DIMENSION(SIZE(map1_2d)) :: dims1_nd_prv
 
  667            INTEGER, 
DIMENSION(SIZE(map2_2d)) :: dims2_nd_prv
 
  668            INTEGER, 
DIMENSION(SIZE(map1_2d) + SIZE(map2_2d)) :: dims_nd_prv
 
  670            CHARACTER(LEN=*), 
PARAMETER :: routinen = 
'dbt_nd_mp_comm' 
  673            CALL timeset(routinen, handle)
 
  675            ndim1 = 
SIZE(map1_2d); ndim2 = 
SIZE(map2_2d)
 
  677            IF (
PRESENT(pdims_2d)) 
THEN 
  678               dims_2d(:) = pdims_2d
 
  682               SELECT TYPE (comm_2d)
 
  684                  dims_2d = comm_2d%num_pe_cart
 
  686                  CALL cp_abort(__location__, 
"If the argument pdims_2d is not given, the "// &
 
  687                                "communicator comm_2d must be of class mp_cart_type.")
 
  691            IF (.NOT. 
PRESENT(dims_nd)) 
THEN 
  692               dims1_nd_prv = 0; dims2_nd_prv = 0
 
  693               IF (
PRESENT(dims1_nd)) 
THEN 
  694                  dims1_nd_prv(:) = dims1_nd
 
  697                  IF (
PRESENT(tdims)) 
THEN 
  704               IF (
PRESENT(dims2_nd)) 
THEN 
  705                  dims2_nd_prv(:) = dims2_nd
 
  707                  IF (
PRESENT(tdims)) 
THEN 
  713               dims_nd_prv(map1_2d) = dims1_nd_prv
 
  714               dims_nd_prv(map2_2d) = dims2_nd_prv
 
  716               cpassert(product(dims_nd(map1_2d)) == dims_2d(1))
 
  717               cpassert(product(dims_nd(map2_2d)) == dims_2d(2))
 
  718               dims_nd_prv = dims_nd
 
  722                                         tensor_dims=tdims, map1_2d=map1_2d, map2_2d=map2_2d, nsplit=nsplit, dimsplit=dimsplit)
 
  724            CALL timestop(handle)
 
 
  744         SUBROUTINE dbt_pgrid_remap(pgrid_in, map1_2d, map2_2d, pgrid_out)
 
  746            INTEGER, 
DIMENSION(:), 
INTENT(IN) :: map1_2d, map2_2d
 
  748            INTEGER, 
DIMENSION(:), 
ALLOCATABLE :: dims
 
  749            INTEGER, 
DIMENSION(ndims_mapping_row(pgrid_in%nd_index_grid)) :: map1_2d_old
 
  750            INTEGER, 
DIMENSION(ndims_mapping_column(pgrid_in%nd_index_grid)) :: map2_2d_old
 
  752            ALLOCATE (dims(
SIZE(map1_2d) + 
SIZE(map2_2d)))
 
  753            CALL dbt_get_mapping_info(pgrid_in%nd_index_grid, dims_nd=dims, map1_2d=map1_2d_old, map2_2d=map2_2d_old)
 
  755            IF (array_eq_i(map1_2d_old, map1_2d) .AND. array_eq_i(map2_2d_old, map2_2d)) 
THEN 
  756               IF (
ALLOCATED(pgrid_in%tas_split_info)) 
THEN 
  757                  ALLOCATE (pgrid_out%tas_split_info, source=pgrid_in%tas_split_info)
 
  769            INTEGER, 
DIMENSION(ndims_mapping(pgrid%nd_index_grid)), 
INTENT(OUT) :: dims
 
  770            INTEGER, 
DIMENSION(ndims_mapping(pgrid%nd_index_grid)), 
INTENT(OUT) :: task_coor
 
  771            INTEGER, 
DIMENSION(2)                                          :: task_coor_2d
 
  773            task_coor_2d = pgrid%mp_comm_2d%mepos_cart
 
 
  789            INTEGER, 
DIMENSION(:), 
INTENT(IN)               :: map1_2d
 
  790            INTEGER, 
DIMENSION(:), 
INTENT(IN)               :: map2_2d
 
  791            INTEGER, 
DIMENSION(:), 
INTENT(IN), 
OPTIONAL     :: nd_dist_1, nd_dist_2, nd_dist_3, nd_dist_4
 
  792            LOGICAL, 
INTENT(IN), 
OPTIONAL                   :: own_comm
 
  795            INTEGER, 
DIMENSION(2)                           :: pdims_2d_check, &
 
  797            INTEGER, 
DIMENSION(SIZE(map1_2d) + SIZE(map2_2d)) :: dims, nblks_nd, task_coor
 
  801            TYPE(dbt_tas_dist_t)                          :: row_dist_obj, col_dist_obj
 
  803            LOGICAL                                         :: need_pgrid_remap
 
  804            INTEGER, 
DIMENSION(ndims_mapping_row(pgrid%nd_index_grid)) :: map1_2d_check
 
  805            INTEGER, 
DIMENSION(ndims_mapping_column(pgrid%nd_index_grid)) :: map2_2d_check
 
  806            CHARACTER(LEN=*), 
PARAMETER :: routinen = 
'dbt_distribution_new_expert' 
  808            CALL timeset(routinen, handle)
 
  809            ndims = 
SIZE(map1_2d) + 
SIZE(map2_2d)
 
  810            cpassert(ndims .GE. 2 .AND. ndims .LE. 4)
 
  812            CALL create_array_list(nd_dist, ndims, nd_dist_1, nd_dist_2, nd_dist_3, nd_dist_4)
 
  816            need_pgrid_remap = .true.
 
  817            IF (
PRESENT(own_comm)) 
THEN 
  820                  IF (.NOT. array_eq_i(map1_2d_check, map1_2d) .OR. .NOT. array_eq_i(map2_2d_check, map2_2d)) 
THEN 
  821                     cpabort(
"map1_2d / map2_2d are not consistent with pgrid")
 
  824                  need_pgrid_remap = .false.
 
  828            IF (need_pgrid_remap) 
CALL dbt_pgrid_remap(pgrid, map1_2d, map2_2d, pgrid_prv)
 
  839            row_dist_obj = dbt_tas_dist_t(nd_dist, map_blks, map_grid, 1)
 
  840            col_dist_obj = dbt_tas_dist_t(nd_dist, map_blks, map_grid, 2)
 
  844            comm_2d = pgrid_prv%mp_comm_2d
 
  846            pdims_2d_check = comm_2d%num_pe_cart
 
  847            IF (any(pdims_2d_check .NE. pdims_2d)) 
THEN 
  848               cpabort(
"inconsistent process grid dimensions")
 
  851            IF (
ALLOCATED(pgrid_prv%tas_split_info)) 
THEN 
  855               ALLOCATE (pgrid_prv%tas_split_info, source=dist%dist%info)
 
  859            dist%nd_dist = nd_dist
 
  860            dist%pgrid = pgrid_prv
 
  862            ALLOCATE (dist%refcount)
 
  864            CALL timestop(handle)
 
 
  877            INTEGER, 
DIMENSION(:), 
INTENT(IN), 
OPTIONAL     :: nd_dist_1, nd_dist_2, nd_dist_3, nd_dist_4
 
  878            INTEGER, 
DIMENSION(ndims_mapping_row(pgrid%nd_index_grid)) :: map1_2d
 
  879            INTEGER, 
DIMENSION(ndims_mapping_column(pgrid%nd_index_grid)) :: map2_2d
 
 
  895            LOGICAL, 
INTENT(IN), 
OPTIONAL           :: keep_comm
 
  896            LOGICAL :: keep_comm_prv
 
  897            IF (
PRESENT(keep_comm)) 
THEN 
  898               keep_comm_prv = keep_comm
 
  900               keep_comm_prv = .false.
 
  902            IF (.NOT. keep_comm_prv) 
CALL pgrid%mp_comm_2d%free()
 
  904            IF (
ALLOCATED(pgrid%tas_split_info) .AND. .NOT. keep_comm_prv) 
THEN 
  906               DEALLOCATE (pgrid%tas_split_info)
 
 
  917            CHARACTER(LEN=*), 
PARAMETER :: routinen = 
'dbt_distribution_destroy' 
  920            CALL timeset(routinen, handle)
 
  925            IF (.NOT. 
ASSOCIATED(dist%refcount)) 
THEN 
  927            ELSEIF (dist%refcount < 1) 
THEN 
  932               cpabort(
"can not destroy non-existing tensor distribution")
 
  935            dist%refcount = dist%refcount - 1
 
  937            IF (dist%refcount == 0) 
THEN 
  939               DEALLOCATE (dist%refcount)
 
  944            CALL timestop(handle)
 
 
  952         SUBROUTINE dbt_distribution_hold(dist)
 
  954            INTEGER, 
POINTER                            :: ref
 
  956            IF (dist%refcount < 1) 
THEN 
  957               cpabort(
"can not hold non-existing tensor distribution")
 
  981         SUBROUTINE dbt_distribution_remap(dist_in, map1_2d, map2_2d, dist_out)
 
  983            INTEGER, 
DIMENSION(:), 
INTENT(IN) :: map1_2d, map2_2d
 
  985            INTEGER, 
DIMENSION(:), 
ALLOCATABLE :: dist_1, dist_2, dist_3, dist_4
 
  987            ndims = 
SIZE(map1_2d) + 
SIZE(map2_2d)
 
  993                  CALL get_arrays(dist_in%nd_dist, dist_1, dist_2)
 
  997                  CALL get_arrays(dist_in%nd_dist, dist_1, dist_2, dist_3)
 
 1000               IF (ndims == 4) 
THEN 
 1001                  CALL get_arrays(dist_in%nd_dist, dist_1, dist_2, dist_3, dist_4)
 
 1016         SUBROUTINE dbt_create_new(tensor, name, dist, map1_2d, map2_2d, &
 
 1017                                   blk_size_1, blk_size_2, blk_size_3, blk_size_4)
 
 1018            TYPE(
dbt_type), 
INTENT(OUT)                   :: tensor
 
 1019            CHARACTER(len=*), 
INTENT(IN)                      :: name
 
 1021            INTEGER, 
DIMENSION(:), 
INTENT(IN)                 :: map1_2d
 
 1022            INTEGER, 
DIMENSION(:), 
INTENT(IN)                 :: map2_2d
 
 1023            INTEGER, 
DIMENSION(:), 
INTENT(IN), 
OPTIONAL       :: blk_size_1, blk_size_2, blk_size_3, blk_size_4
 
 1025            INTEGER(KIND=int_8), 
DIMENSION(2)                             :: dims_2d
 
 1026            INTEGER, 
DIMENSION(SIZE(map1_2d) + SIZE(map2_2d)) :: dims, pdims, task_coor
 
 1027            TYPE(dbt_tas_blk_size_t)                        :: col_blk_size_obj, row_blk_size_obj
 
 1032            CHARACTER(LEN=*), 
PARAMETER :: routineN = 
'dbt_create_new' 
 1033            INTEGER, 
DIMENSION(:), 
ALLOCATABLE              :: blks_local_1, blks_local_2, blks_local_3, blks_local_4
 
 1034            INTEGER, 
DIMENSION(:), 
ALLOCATABLE              :: dist_1, dist_2, dist_3, dist_4
 
 1035            INTEGER                                         :: iblk_count, iblk
 
 1036            INTEGER, 
DIMENSION(:), 
ALLOCATABLE              :: nblks_local, nfull_local
 
 1038            CALL timeset(routinen, handle)
 
 1039            ndims = 
SIZE(map1_2d) + 
SIZE(map2_2d)
 
 1040            CALL create_array_list(blk_size, ndims, blk_size_1, blk_size_2, blk_size_3, blk_size_4)
 
 1046            row_blk_size_obj = dbt_tas_blk_size_t(blk_size, map, 1)
 
 1047            col_blk_size_obj = dbt_tas_blk_size_t(blk_size, map, 2)
 
 1049            CALL dbt_distribution_remap(dist, map1_2d, map2_2d, dist_new)
 
 1051            ALLOCATE (tensor%matrix_rep)
 
 1053                                name=trim(name)//
" matrix", &
 
 1054                                dist=dist_new%dist, &
 
 1055                                row_blk_size=row_blk_size_obj, &
 
 1056                                col_blk_size=col_blk_size_obj)
 
 1058            tensor%owns_matrix = .true.
 
 1060            tensor%nd_index_blk = map
 
 1068            tensor%nd_index = map
 
 1069            tensor%blk_sizes = blk_size
 
 1073               IF (ndims == 1) 
THEN 
 1076               IF (ndims == 2) 
THEN 
 1077                  CALL get_arrays(dist_new%nd_dist, dist_1, dist_2)
 
 1079               IF (ndims == 3) 
THEN 
 1080                  CALL get_arrays(dist_new%nd_dist, dist_1, dist_2, dist_3)
 
 1082               IF (ndims == 4) 
THEN 
 1083                  CALL get_arrays(dist_new%nd_dist, dist_1, dist_2, dist_3, dist_4)
 
 1086            ALLOCATE (nblks_local(ndims))
 
 1087            ALLOCATE (nfull_local(ndims))
 
 1089               IF (ndims .GE. 1) 
THEN 
 1090                  nblks_local(1) = count(dist_1 == task_coor(1))
 
 1091                  ALLOCATE (blks_local_1(nblks_local(1)))
 
 1093                  DO iblk = 1, 
SIZE(dist_1)
 
 1094                     IF (dist_1(iblk) == task_coor(1)) 
THEN 
 1095                        iblk_count = iblk_count + 1
 
 1096                        blks_local_1(iblk_count) = iblk
 
 1097                        nfull_local(1) = nfull_local(1) + blk_size_1(iblk)
 
 1101               IF (ndims .GE. 2) 
THEN 
 1102                  nblks_local(2) = count(dist_2 == task_coor(2))
 
 1103                  ALLOCATE (blks_local_2(nblks_local(2)))
 
 1105                  DO iblk = 1, 
SIZE(dist_2)
 
 1106                     IF (dist_2(iblk) == task_coor(2)) 
THEN 
 1107                        iblk_count = iblk_count + 1
 
 1108                        blks_local_2(iblk_count) = iblk
 
 1109                        nfull_local(2) = nfull_local(2) + blk_size_2(iblk)
 
 1113               IF (ndims .GE. 3) 
THEN 
 1114                  nblks_local(3) = count(dist_3 == task_coor(3))
 
 1115                  ALLOCATE (blks_local_3(nblks_local(3)))
 
 1117                  DO iblk = 1, 
SIZE(dist_3)
 
 1118                     IF (dist_3(iblk) == task_coor(3)) 
THEN 
 1119                        iblk_count = iblk_count + 1
 
 1120                        blks_local_3(iblk_count) = iblk
 
 1121                        nfull_local(3) = nfull_local(3) + blk_size_3(iblk)
 
 1125               IF (ndims .GE. 4) 
THEN 
 1126                  nblks_local(4) = count(dist_4 == task_coor(4))
 
 1127                  ALLOCATE (blks_local_4(nblks_local(4)))
 
 1129                  DO iblk = 1, 
SIZE(dist_4)
 
 1130                     IF (dist_4(iblk) == task_coor(4)) 
THEN 
 1131                        iblk_count = iblk_count + 1
 
 1132                        blks_local_4(iblk_count) = iblk
 
 1133                        nfull_local(4) = nfull_local(4) + blk_size_4(iblk)
 
 1138               IF (ndims == 1) 
THEN 
 1141               IF (ndims == 2) 
THEN 
 1144               IF (ndims == 3) 
THEN 
 1147               IF (ndims == 4) 
THEN 
 1148                  CALL create_array_list(blks_local, 4, blks_local_1, blks_local_2, blks_local_3, blks_local_4)
 
 1151            ALLOCATE (tensor%nblks_local(ndims))
 
 1152            ALLOCATE (tensor%nfull_local(ndims))
 
 1153            tensor%nblks_local(:) = nblks_local
 
 1154            tensor%nfull_local(:) = nfull_local
 
 1156            tensor%blks_local = blks_local
 
 1158            tensor%nd_dist = dist_new%nd_dist
 
 1159            tensor%pgrid = dist_new%pgrid
 
 1161            CALL dbt_distribution_hold(dist_new)
 
 1162            tensor%refcount => dist_new%refcount
 
 1167            tensor%valid = .true.
 
 1168            CALL timestop(handle)
 
 
 1178            INTEGER, 
POINTER :: ref
 
 1180            IF (
tensor%refcount < 1) 
THEN 
 1181               cpabort(
"can not hold non-existing tensor")
 
 
 1228            INTEGER, 
DIMENSION(ndims_tensor(tensor)), &
 
 1232            dims = 
tensor%nd_index%dims_nd
 
 
 1239         SUBROUTINE dbt_create_template(tensor_in, tensor, name, dist, map1_2d, map2_2d)
 
 1240            TYPE(
dbt_type), 
INTENT(INOUT)      :: tensor_in
 
 1241            TYPE(
dbt_type), 
INTENT(OUT)        :: tensor
 
 1242            CHARACTER(len=*), 
INTENT(IN), 
OPTIONAL :: name
 
 1244               INTENT(INOUT), 
OPTIONAL             :: dist
 
 1245            INTEGER, 
DIMENSION(:), 
INTENT(IN), &
 
 1246               OPTIONAL                            :: map1_2d, map2_2d
 
 1248            CHARACTER(LEN=*), 
PARAMETER :: routineN = 
'dbt_create_template' 
 1249            INTEGER, 
DIMENSION(:), 
ALLOCATABLE     :: bsize_1, bsize_2, bsize_3, bsize_4
 
 1250            INTEGER, 
DIMENSION(:), 
ALLOCATABLE     :: map1_2d_prv, map2_2d_prv
 
 1251            CHARACTER(len=default_string_length)   :: name_prv
 
 1254            CALL timeset(routinen, handle)
 
 1256            IF (
PRESENT(dist) .OR. 
PRESENT(map1_2d) .OR. 
PRESENT(map2_2d)) 
THEN 
 1258               IF (
PRESENT(dist)) 
THEN 
 1263               IF (
PRESENT(map1_2d) .AND. 
PRESENT(map2_2d)) 
THEN 
 1264                  ALLOCATE (map1_2d_prv, source=map1_2d)
 
 1265                  ALLOCATE (map2_2d_prv, source=map2_2d)
 
 1271               IF (
PRESENT(name)) 
THEN 
 1274                  name_prv = tensor_in%name
 
 1278                     CALL get_arrays(tensor_in%blk_sizes, bsize_1)
 
 1279                     CALL dbt_create(tensor, name_prv, dist_prv, map1_2d_prv, map2_2d_prv, &
 
 1283                     CALL get_arrays(tensor_in%blk_sizes, bsize_1, bsize_2)
 
 1284                     CALL dbt_create(tensor, name_prv, dist_prv, map1_2d_prv, map2_2d_prv, &
 
 1288                     CALL get_arrays(tensor_in%blk_sizes, bsize_1, bsize_2, bsize_3)
 
 1289                     CALL dbt_create(tensor, name_prv, dist_prv, map1_2d_prv, map2_2d_prv, &
 
 1290                                     bsize_1, bsize_2, bsize_3)
 
 1293                     CALL get_arrays(tensor_in%blk_sizes, bsize_1, bsize_2, bsize_3, bsize_4)
 
 1294                     CALL dbt_create(tensor, name_prv, dist_prv, map1_2d_prv, map2_2d_prv, &
 
 1295                                     bsize_1, bsize_2, bsize_3, bsize_4)
 
 1299               ALLOCATE (tensor%matrix_rep)
 
 1300               IF (.NOT. 
PRESENT(name)) 
THEN 
 1302                                      name=trim(tensor_in%name)//
" matrix")
 
 1304                  CALL dbt_tas_create(tensor_in%matrix_rep, tensor%matrix_rep, name=trim(name)//
" matrix")
 
 1306               tensor%owns_matrix = .true.
 
 1309               tensor%nd_index_blk = tensor_in%nd_index_blk
 
 1310               tensor%nd_index = tensor_in%nd_index
 
 1311               tensor%blk_sizes = tensor_in%blk_sizes
 
 1312               tensor%blk_offsets = tensor_in%blk_offsets
 
 1313               tensor%nd_dist = tensor_in%nd_dist
 
 1314               tensor%blks_local = tensor_in%blks_local
 
 1316               tensor%nblks_local(:) = tensor_in%nblks_local
 
 1318               tensor%nfull_local(:) = tensor_in%nfull_local
 
 1319               tensor%pgrid = tensor_in%pgrid
 
 1321               tensor%refcount => tensor_in%refcount
 
 1324               tensor%valid = .true.
 
 1325               IF (
PRESENT(name)) 
THEN 
 1328                  tensor%name = tensor_in%name
 
 1331            CALL timestop(handle)
 
 
 1338         SUBROUTINE dbt_create_matrix(matrix_in, tensor, order, name)
 
 1340            TYPE(
dbt_type), 
INTENT(OUT)        :: tensor
 
 1341            INTEGER, 
DIMENSION(2), 
INTENT(IN), 
OPTIONAL :: order
 
 1342            CHARACTER(len=*), 
INTENT(IN), 
OPTIONAL      :: name
 
 1344            CHARACTER(len=default_string_length)        :: name_in
 
 1345            INTEGER, 
DIMENSION(2)                       :: order_in
 
 1349            INTEGER, 
DIMENSION(:), 
POINTER              :: row_blk_size, col_blk_size
 
 1350            INTEGER, 
DIMENSION(:), 
POINTER              :: col_dist, row_dist
 
 1351            INTEGER                                   :: handle, comm_2d_handle
 
 1352            CHARACTER(LEN=*), 
PARAMETER :: routineN = 
'dbt_create_matrix' 
 1354            INTEGER, 
DIMENSION(2)                     :: pdims_2d
 
 1356            CALL timeset(routinen, handle)
 
 1358            NULLIFY (row_blk_size, col_blk_size, col_dist, row_dist)
 
 1359            IF (
PRESENT(name)) 
THEN 
 1365            IF (
PRESENT(order)) 
THEN 
 1373                                        nprows=pdims_2d(1), npcols=pdims_2d(2))
 
 1374            CALL comm_2d%set_handle(comm_2d_handle)
 
 1375            comm_nd = 
dbt_nd_mp_comm(comm_2d, [order_in(1)], [order_in(2)], pdims_2d=pdims_2d)
 
 1380               [order_in(1)], [order_in(2)], &
 
 1381               row_dist, col_dist, own_comm=.true.)
 
 1383            CALL dbcsr_get_info(matrix_in, row_blk_size=row_blk_size, col_blk_size=col_blk_size)
 
 1385            CALL dbt_create_new(tensor, name_in, dist, &
 
 1386                                [order_in(1)], [order_in(2)], &
 
 1391            CALL timestop(handle)
 
 
 1401            CHARACTER(LEN=*), 
PARAMETER :: routinen = 
'dbt_destroy' 
 1404            CALL timeset(routinen, handle)
 
 1405            IF (
tensor%owns_matrix) 
THEN 
 1407               DEALLOCATE (
tensor%matrix_rep)
 
 1409               NULLIFY (
tensor%matrix_rep)
 
 1411            tensor%owns_matrix = .false.
 
 1424            IF (.NOT. 
ASSOCIATED(
tensor%refcount)) 
THEN 
 1426            ELSEIF (
tensor%refcount < 1) 
THEN 
 1431               cpabort(
"can not destroy non-existing tensor")
 
 1436            IF (
tensor%refcount == 0) 
THEN 
 1440               DEALLOCATE (
tensor%refcount)
 
 1447            CALL timestop(handle)
 
 
 1456            INTEGER, 
DIMENSION(ndims_tensor(tensor)), &
 
 1460            dims = 
tensor%nd_index_blk%dims_nd
 
 
 1469            INTEGER, 
DIMENSION(ndims_tensor(tensor)), &
 
 1471            INTEGER, 
DIMENSION(ndims_tensor(tensor)), &
 
 1472               INTENT(OUT)                              :: blk_size
 
 
 1485            INTEGER, 
DIMENSION(ndims_tensor(tensor)), &
 
 1487            INTEGER, 
DIMENSION(ndims_tensor(tensor)), &
 
 1488               INTENT(OUT)                              :: blk_offset
 
 
 1500            INTEGER, 
DIMENSION(ndims_tensor(tensor)), &
 
 1501               INTENT(IN)                                :: ind_nd
 
 1502            INTEGER, 
INTENT(OUT)                         :: processor
 
 1504            INTEGER(KIND=int_8), 
DIMENSION(2)                        :: ind_2d
 
 
 1515            INTEGER, 
DIMENSION(:), 
INTENT(INOUT) :: dims
 
 1517            INTEGER, 
DIMENSION(:), 
INTENT(IN), 
OPTIONAL :: tensor_dims
 
 1518            INTEGER, 
DIMENSION(:), 
ALLOCATABLE :: map1_2d, map2_2d
 
 1523            ALLOCATE (map1_2d(ndims/2))
 
 1524            ALLOCATE (map2_2d(ndims - ndims/2))
 
 1525            map1_2d(:) = (/(i, i=1, 
SIZE(map1_2d))/)
 
 1526            map2_2d(:) = (/(i, i=
SIZE(map1_2d) + 1, 
SIZE(map1_2d) + 
SIZE(map2_2d))/)
 
 
 1549            INTEGER, 
DIMENSION(:), 
INTENT(INOUT)    :: pdims
 
 1551            INTEGER                                 :: nsplit, dimsplit
 
 1552            INTEGER, 
DIMENSION(ndims_mapping_row(pgrid%nd_index_grid)) :: map1_2d
 
 1553            INTEGER, 
DIMENSION(ndims_mapping_column(pgrid%nd_index_grid)) :: map2_2d
 
 1555            INTEGER, 
DIMENSION(2)                   :: pdims_2d
 
 1557            cpassert(all(pdims > 0))
 
 1562            IF (mod(pdims_2d(dimsplit), nsplit) == 0) 
THEN 
 1564                                            nsplit=nsplit, dimsplit=dimsplit)
 
 
 1578            REAL(
dp), 
INTENT(IN)                :: eps
 
 
 1590            INTEGER, 
INTENT(IN) :: idim
 
 
 1607            INTEGER, 
INTENT(IN) :: idim
 
 
 1639                                 blks_local_1, blks_local_2, blks_local_3, blks_local_4, &
 
 1640                                 proc_dist_1, proc_dist_2, proc_dist_3, proc_dist_4, &
 
 1641                                 blk_size_1, blk_size_2, blk_size_3, blk_size_4, &
 
 1642                                 blk_offset_1, blk_offset_2, blk_offset_3, blk_offset_4, &
 
 1646            INTEGER, 
INTENT(OUT), 
OPTIONAL, 
DIMENSION(ndims_tensor(tensor)) :: nblks_total
 
 1647            INTEGER, 
INTENT(OUT), 
OPTIONAL, 
DIMENSION(ndims_tensor(tensor)) :: nfull_total
 
 1648            INTEGER, 
INTENT(OUT), 
OPTIONAL, 
DIMENSION(ndims_tensor(tensor)) :: nblks_local
 
 1649            INTEGER, 
INTENT(OUT), 
OPTIONAL, 
DIMENSION(ndims_tensor(tensor)) :: nfull_local
 
 1650            INTEGER, 
INTENT(OUT), 
OPTIONAL, 
DIMENSION(ndims_tensor(tensor)) :: my_ploc
 
 1651            INTEGER, 
INTENT(OUT), 
OPTIONAL, 
DIMENSION(ndims_tensor(tensor)) :: pdims
 
 1652               INTEGER, 
DIMENSION(dbt_nblks_local(tensor, 1)), 
INTENT(OUT), 
OPTIONAL :: blks_local_1
 
 1653               INTEGER, 
DIMENSION(dbt_nblks_total(tensor, 1)), 
INTENT(OUT), 
OPTIONAL :: proc_dist_1
 
 1654               INTEGER, 
DIMENSION(dbt_nblks_total(tensor, 1)), 
INTENT(OUT), 
OPTIONAL :: blk_size_1
 
 1655               INTEGER, 
DIMENSION(dbt_nblks_total(tensor, 1)), 
INTENT(OUT), 
OPTIONAL :: blk_offset_1
 
 1656               INTEGER, 
DIMENSION(dbt_nblks_local(tensor, 2)), 
INTENT(OUT), 
OPTIONAL :: blks_local_2
 
 1657               INTEGER, 
DIMENSION(dbt_nblks_total(tensor, 2)), 
INTENT(OUT), 
OPTIONAL :: proc_dist_2
 
 1658               INTEGER, 
DIMENSION(dbt_nblks_total(tensor, 2)), 
INTENT(OUT), 
OPTIONAL :: blk_size_2
 
 1659               INTEGER, 
DIMENSION(dbt_nblks_total(tensor, 2)), 
INTENT(OUT), 
OPTIONAL :: blk_offset_2
 
 1660               INTEGER, 
DIMENSION(dbt_nblks_local(tensor, 3)), 
INTENT(OUT), 
OPTIONAL :: blks_local_3
 
 1661               INTEGER, 
DIMENSION(dbt_nblks_total(tensor, 3)), 
INTENT(OUT), 
OPTIONAL :: proc_dist_3
 
 1662               INTEGER, 
DIMENSION(dbt_nblks_total(tensor, 3)), 
INTENT(OUT), 
OPTIONAL :: blk_size_3
 
 1663               INTEGER, 
DIMENSION(dbt_nblks_total(tensor, 3)), 
INTENT(OUT), 
OPTIONAL :: blk_offset_3
 
 1664               INTEGER, 
DIMENSION(dbt_nblks_local(tensor, 4)), 
INTENT(OUT), 
OPTIONAL :: blks_local_4
 
 1665               INTEGER, 
DIMENSION(dbt_nblks_total(tensor, 4)), 
INTENT(OUT), 
OPTIONAL :: proc_dist_4
 
 1666               INTEGER, 
DIMENSION(dbt_nblks_total(tensor, 4)), 
INTENT(OUT), 
OPTIONAL :: blk_size_4
 
 1667               INTEGER, 
DIMENSION(dbt_nblks_total(tensor, 4)), 
INTENT(OUT), 
OPTIONAL :: blk_offset_4
 
 1669            CHARACTER(len=*), 
INTENT(OUT), 
OPTIONAL                   :: name
 
 1670            INTEGER, 
DIMENSION(ndims_tensor(tensor))                  :: pdims_tmp, my_ploc_tmp
 
 1674            IF (
PRESENT(nblks_local)) nblks_local(:) = 
tensor%nblks_local
 
 1675            IF (
PRESENT(nfull_local)) nfull_local(:) = 
tensor%nfull_local
 
 1678            IF (
PRESENT(my_ploc)) my_ploc = my_ploc_tmp
 
 1679            IF (
PRESENT(pdims)) pdims = pdims_tmp
 
 1739            IF (
PRESENT(name)) name = 
tensor%name
 
 
 1749            INTEGER                           :: num_blocks
 
 
 1759            INTEGER(KIND=int_8)               :: num_blocks
 
 
 1789            REAL(
dp), 
INTENT(IN) :: alpha
 
 
 1817            INTEGER, 
DIMENSION(ndims_tensor(tensor)), &
 
 1819            INTEGER, 
INTENT(IN) :: idim
 
 1820            INTEGER, 
DIMENSION(ndims_tensor(tensor)) :: blk_size
 
 
 1840            INTEGER :: blk_count, nproc
 
 1841            INTEGER, 
DIMENSION(ndims_tensor(tensor)) :: bdims
 
 1842            INTEGER(int_8) :: blk_count_total
 
 1843            INTEGER, 
PARAMETER :: max_load_imbalance = 2
 
 1847            blk_count_total = product(int(bdims, 
int_8))
 
 1850            nproc = 
tensor%pgrid%nproc
 
 1852            blk_count = int(blk_count_total/nproc*max_load_imbalance)
 
 
 1865            INTEGER, 
INTENT(IN)                                :: nblk
 
 1866            INTEGER, 
INTENT(IN)                                :: nproc
 
 1867            INTEGER, 
DIMENSION(nblk), 
INTENT(IN)                :: blk_size
 
 1868            INTEGER, 
DIMENSION(nblk), 
INTENT(OUT)               :: dist
 
 
 1877            TYPE(
dbt_type), 
INTENT(IN) :: tensor_in
 
 1878            TYPE(
dbt_type), 
INTENT(INOUT) :: tensor_out
 
 1882            IF (tensor_in%matrix_rep%do_batched > 0) 
THEN 
 1883               ALLOCATE (tas_storage_tmp, source=tensor_in%matrix_rep%mm_storage)
 
 1885               IF (
ALLOCATED(tensor_out%matrix_rep%mm_storage)) 
DEALLOCATE (tensor_out%matrix_rep%mm_storage)
 
 1886               CALL move_alloc(tas_storage_tmp, tensor_out%matrix_rep%mm_storage)
 
 1889                                           opt_grid=tensor_in%matrix_rep%has_opt_pgrid)
 
 1890            IF (
ALLOCATED(tensor_in%contraction_storage)) 
THEN 
 1891               ALLOCATE (tensor_storage_tmp, source=tensor_in%contraction_storage)
 
 1893            IF (
ALLOCATED(tensor_out%contraction_storage)) 
DEALLOCATE (tensor_out%contraction_storage)
 
 1894            IF (
ALLOCATED(tensor_storage_tmp)) 
CALL move_alloc(tensor_storage_tmp, tensor_out%contraction_storage)
 
 
subroutine, public dbcsr_get_info(matrix, nblkrows_total, nblkcols_total, nfullrows_total, nfullcols_total, nblkrows_local, nblkcols_local, nfullrows_local, nfullcols_local, my_prow, my_pcol, local_rows, local_cols, proc_row_dist, proc_col_dist, row_blk_size, col_blk_size, row_blk_offset, col_blk_offset, distribution, name, matrix_type, group)
...
subroutine, public dbcsr_distribution_get(dist, row_dist, col_dist, nrows, ncols, has_threads, group, mynode, numnodes, nprows, npcols, myprow, mypcol, pgrid, subgroups_defined, prow_group, pcol_group)
...
subroutine, public dbm_scale(matrix, alpha)
Multiplies all entries in the given matrix by the given factor alpha.
Wrapper for allocating, copying and reshaping arrays.
Representation of arbitrary number of 1d integer arrays with arbitrary sizes. This is needed for gene...
integer function, dimension(:), allocatable, public sum_of_arrays(list)
sum of all elements for each array stored in list
subroutine, public get_arrays(list, data_1, data_2, data_3, data_4, i_selected)
Get all arrays contained in list.
subroutine, public create_array_list(list, ndata, data_1, data_2, data_3, data_4)
collects any number of arrays of different sizes into a single array (listcol_data),...
subroutine, public destroy_array_list(list)
destroy array list.
integer function, dimension(:), allocatable, public sizes_of_arrays(list)
sizes of arrays stored in list
subroutine, public array_offsets(list_in, list_out)
partial sums of array elements.
pure integer function, dimension(number_of_arrays(list)), public get_array_elements(list, indices)
Get an element for each array.
type(array_list) function, public array_sublist(list, i_selected)
extract a subset of arrays
tensor index and mapping to DBM index
subroutine, public create_nd_to_2d_mapping(map, dims, map1_2d, map2_2d, base, col_major)
Create all data needed to quickly map between nd index and 2d index.
pure integer function, dimension(map%ndim_nd), public get_nd_indices_pgrid(map, ind_in)
transform 2d index to nd index, using info from index mapping.
pure integer function, public ndims_mapping_row(map)
how many tensor dimensions are mapped to matrix row
pure integer(kind=int_8) function, dimension(2), public get_2d_indices_tensor(map, ind_in)
transform nd index to 2d index, using info from index mapping.
pure integer function, public ndims_mapping(map)
pure integer(kind=int_8) function, public combine_tensor_index(ind_in, dims)
transform nd index to flat index
pure subroutine, public dbt_get_mapping_info(map, ndim_nd, ndim1_2d, ndim2_2d, dims_2d_i8, dims_2d, dims_nd, dims1_2d, dims2_2d, map1_2d, map2_2d, map_nd, base, col_major)
get mapping info
pure integer function, public combine_pgrid_index(ind_in, dims)
transform nd index to flat index
pure integer function, public ndims_mapping_column(map)
how many tensor dimensions are mapped to matrix column
subroutine, public destroy_nd_to_2d_mapping(map)
pure integer function, dimension(size(dims)), public split_tensor_index(ind_in, dims)
transform flat index to nd index
pure integer function, dimension(size(dims)), public split_pgrid_index(ind_in, dims)
transform flat index to nd index
Tall-and-skinny matrices: base routines similar to DBM API, mostly wrappers around existing DBM routi...
integer(kind=int_8) function, public dbt_tas_get_nze_total(matrix)
Get total number of non-zero elements.
subroutine, public dbt_tas_distribution_destroy(dist)
...
subroutine, public dbt_tas_get_stored_coordinates(matrix, row, column, processor)
As dbt_get_stored_coordinates.
pure integer function, public dbt_tas_get_nze(matrix)
As dbt_get_nze: get number of local non-zero elements.
subroutine, public dbt_tas_get_info(matrix, nblkrows_total, nblkcols_total, local_rows, local_cols, proc_row_dist, proc_col_dist, row_blk_size, col_blk_size, distribution, name)
...
subroutine, public dbt_tas_finalize(matrix)
...
subroutine, public dbt_tas_distribution_new(dist, mp_comm, row_dist, col_dist, split_info, nosplit)
create new distribution. Exactly like dbm_distribution_new but with custom types for row_dist and col...
subroutine, public dbt_tas_filter(matrix, eps)
As dbm_filter.
subroutine, public dbt_tas_clear(matrix)
Clear matrix (erase all data)
subroutine, public dbt_tas_destroy(matrix)
...
integer(kind=int_8) function, public dbt_tas_get_num_blocks_total(matrix)
get total number of blocks
pure integer function, public dbt_tas_get_num_blocks(matrix)
As dbt_get_num_blocks: get number of local blocks.
Global data (distribution and block sizes) for tall-and-skinny matrices For very sparse matrices with...
subroutine, public dbt_tas_default_distvec(nblk, nproc, blk_size, dist)
get a load-balanced and randomized distribution along one tensor dimension
Matrix multiplication for tall-and-skinny matrices. This uses the k-split (non-recursive) CARMA algor...
subroutine, public dbt_tas_set_batched_state(matrix, state, opt_grid)
set state flags during batched multiplication
methods to split tall-and-skinny matrices along longest dimension. Basically, we are splitting proces...
subroutine, public dbt_tas_release_info(split_info)
...
subroutine, public dbt_tas_get_split_info(info, mp_comm, nsplit, igroup, mp_comm_group, split_rowcol, pgrid_offset)
Get info on split.
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
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
DBT tall-and-skinny base types. Mostly wrappers around existing DBM routines.
DBT tensor framework for block-sparse tensor contraction: Types and create/destroy routines.
subroutine, public dbt_pgrid_destroy(pgrid, keep_comm)
destroy process grid
subroutine, public dbt_distribution_new(dist, pgrid, nd_dist_1, nd_dist_2, nd_dist_3, nd_dist_4)
Create a tensor distribution.
subroutine, public blk_dims_tensor(tensor, dims)
tensor block dimensions
subroutine, public dims_tensor(tensor, dims)
tensor dimensions
subroutine, public dbt_copy_contraction_storage(tensor_in, tensor_out)
type(dbt_pgrid_type) function, public dbt_nd_mp_comm(comm_2d, map1_2d, map2_2d, dims_nd, dims1_nd, dims2_nd, pdims_2d, tdims, nsplit, dimsplit)
Create a default nd process topology that is consistent with a given 2d topology. Purpose: a nd tenso...
subroutine, public dbt_blk_sizes(tensor, ind, blk_size)
Size of tensor block.
subroutine, public dbt_destroy(tensor)
Destroy a tensor.
pure integer function, public dbt_max_nblks_local(tensor)
returns an estimate of maximum number of local blocks in tensor (irrespective of the actual number of...
recursive subroutine, public dbt_mp_dims_create(nodes, dims, tensor_dims, lb_ratio)
Create process grid dimensions corresponding to one dimension of the matrix representation of a tenso...
subroutine, public dbt_get_info(tensor, nblks_total, nfull_total, nblks_local, nfull_local, pdims, my_ploc, blks_local_1, blks_local_2, blks_local_3, blks_local_4, proc_dist_1, proc_dist_2, proc_dist_3, proc_dist_4, blk_size_1, blk_size_2, blk_size_3, blk_size_4, blk_offset_1, blk_offset_2, blk_offset_3, blk_offset_4, distribution, name)
As block_get_info but for tensors.
subroutine, public dbt_distribution_new_expert(dist, pgrid, map1_2d, map2_2d, nd_dist_1, nd_dist_2, nd_dist_3, nd_dist_4, own_comm)
Create a tensor distribution.
type(dbt_distribution_type) function, public dbt_distribution(tensor)
get distribution from tensor
pure integer function, public ndims_tensor(tensor)
tensor rank
subroutine, public dbt_pgrid_set_strict_split(pgrid)
freeze current split factor such that it is never changed during contraction
pure integer function, public dbt_nblks_total(tensor, idim)
total numbers of blocks along dimension idim
pure integer function, public dbt_blk_size(tensor, ind, idim)
block size of block with index ind along dimension idim
pure integer function, public dbt_get_num_blocks(tensor)
As block_get_num_blocks: get number of local blocks.
subroutine, public dbt_default_distvec(nblk, nproc, blk_size, dist)
get a load-balanced and randomized distribution along one tensor dimension
subroutine, public dbt_hold(tensor)
reference counting for tensors (only needed for communicator handle that must be freed when no longer...
subroutine, public dbt_pgrid_create_expert(mp_comm, dims, pgrid, map1_2d, map2_2d, tensor_dims, nsplit, dimsplit)
Create an n-dimensional process grid. We can not use a n-dimensional MPI cartesian grid for tensors s...
subroutine, public dbt_clear(tensor)
Clear tensor (s.t. it does not contain any blocks)
subroutine, public dbt_finalize(tensor)
Finalize tensor, as block_finalize. This should be taken care of internally in DBT tensors,...
integer(kind=int_8) function, public dbt_get_nze_total(tensor)
pure integer function, public dbt_nblks_local(tensor, idim)
local number of blocks along dimension idim
subroutine, public mp_environ_pgrid(pgrid, dims, task_coor)
as mp_environ but for special pgrid type
subroutine, public dbt_get_stored_coordinates(tensor, ind_nd, processor)
Generalization of block_get_stored_coordinates for tensors.
pure integer function, public dbt_get_nze(tensor)
subroutine, public dbt_pgrid_create(mp_comm, dims, pgrid, tensor_dims)
integer(kind=int_8) function, public dbt_get_num_blocks_total(tensor)
Get total number of blocks.
pure integer(int_8) function, public ndims_matrix_row(tensor)
how many tensor dimensions are mapped to matrix row
subroutine, public dbt_pgrid_change_dims(pgrid, pdims)
change dimensions of an existing process grid.
pure integer(int_8) function, public ndims_matrix_column(tensor)
how many tensor dimensions are mapped to matrix column
subroutine, public dbt_nd_mp_free(mp_comm)
Release the MPI communicator.
subroutine, public dbt_blk_offsets(tensor, ind, blk_offset)
offset of tensor block
subroutine, public dbt_filter(tensor, eps)
As block_filter.
subroutine, public dbt_distribution_destroy(dist)
Destroy tensor distribution.
subroutine, public dbt_scale(tensor, alpha)
as block_scale
Defines the basic variable types.
integer, parameter, public int_8
integer, parameter, public dp
integer, parameter, public default_string_length
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.