LCOV - code coverage report
Current view: top level - src - cp_dbcsr_operations.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:123285f) Lines: 84.8 % 561 476
Test Date: 2026-11-04 00:58:17 Functions: 75.7 % 37 28

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief   DBCSR operations in CP2K
      10              : !> \author  Urban Borstnik
      11              : !> \date    2009-05-12
      12              : !> \version 0.8
      13              : !>
      14              : !> <b>Modification history:</b>
      15              : !> - Created 2009-05-12
      16              : !> - Generalized sm_fm_mulitply for matrices w/ different row/col block size (A. Bussy, 11.2018)
      17              : ! **************************************************************************************************
      18              : MODULE cp_dbcsr_operations
      19              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      20              :    USE cp_dbcsr_api,                    ONLY: &
      21              :         dbcsr_add, dbcsr_complete_redistribute, dbcsr_convert_sizes_to_offsets, dbcsr_copy, &
      22              :         dbcsr_create, dbcsr_deallocate_matrix, dbcsr_desymmetrize, dbcsr_distribution_get, &
      23              :         dbcsr_distribution_new, dbcsr_distribution_release, dbcsr_distribution_type, &
      24              :         dbcsr_get_info, dbcsr_get_matrix_type, dbcsr_iterator_blocks_left, &
      25              :         dbcsr_iterator_next_block, dbcsr_iterator_readonly_start, dbcsr_iterator_start, &
      26              :         dbcsr_iterator_stop, dbcsr_iterator_type, dbcsr_multiply, dbcsr_p_type, dbcsr_release, &
      27              :         dbcsr_scale, dbcsr_type, dbcsr_type_antisymmetric, dbcsr_type_no_symmetry, &
      28              :         dbcsr_type_symmetric, dbcsr_valid_index, dbcsr_verify_matrix
      29              :    USE cp_dbcsr_contrib,                ONLY: dbcsr_frobenius_norm,&
      30              :                                               dbcsr_reserve_all_blocks
      31              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_gemm
      32              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      33              :                                               cp_fm_struct_release,&
      34              :                                               cp_fm_struct_type
      35              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      36              :                                               cp_fm_get_info,&
      37              :                                               cp_fm_release,&
      38              :                                               cp_fm_to_fm,&
      39              :                                               cp_fm_type
      40              :    USE distribution_2d_types,           ONLY: distribution_2d_get,&
      41              :                                               distribution_2d_type
      42              :    USE kinds,                           ONLY: default_string_length,&
      43              :                                               dp,&
      44              :                                               int_8
      45              :    USE mathlib,                         ONLY: gcd,&
      46              :                                               lcm
      47              :    USE message_passing,                 ONLY: mp_para_env_type
      48              : 
      49              : !$ USE OMP_LIB, ONLY: omp_get_max_threads, omp_get_thread_num, omp_get_num_threads
      50              : #include "base/base_uses.f90"
      51              : 
      52              :    IMPLICIT NONE
      53              :    PRIVATE
      54              : 
      55              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_dbcsr_operations'
      56              :    LOGICAL, PARAMETER :: debug_mod = .FALSE.
      57              : 
      58              :    INTEGER, SAVE, PUBLIC :: max_elements_per_block = 32
      59              : 
      60              :    ! A plan caches S/A routing for a source block layout and FM distribution.
      61              :    ! Use check_plan for sources whose layout can change. The owner must release
      62              :    ! the plan before releasing the FM structure. All owned storage is allocatable;
      63              :    ! no matrix data pointers or MPI requests are retained. Calls must be serialized.
      64              :    TYPE dbcsr_fm_thread_plan_type
      65              :       INTEGER, ALLOCATABLE :: blocks(:, :), slots(:)
      66              :    END TYPE dbcsr_fm_thread_plan_type
      67              : 
      68              :    TYPE, PUBLIC :: dbcsr_fm_copy_plan_type
      69              :       PRIVATE
      70              :       TYPE(cp_fm_struct_type), POINTER :: matrix_struct => NULL()
      71              :       CHARACTER :: matrix_type = " "
      72              :       TYPE(dbcsr_fm_thread_plan_type), ALLOCATABLE :: thread(:)
      73              :       INTEGER, ALLOCATABLE :: send_count(:), send_disp(:), recv_count(:), recv_disp(:), recv_index(:, :)
      74              :       REAL(KIND=dp), ALLOCATABLE :: send_values(:), recv_values(:)
      75              :    END TYPE dbcsr_fm_copy_plan_type
      76              : 
      77              :    PUBLIC :: copy_dbcsr_to_local, copy_local_to_dbcsr
      78              :    PUBLIC :: dbcsr_multiply_local, dbcsr_sum_many
      79              : 
      80              :    ! CP2K API emulation
      81              :    PUBLIC :: copy_fm_to_dbcsr, copy_dbcsr_to_fm, &
      82              :              cp_dbcsr_sm_fm_multiply, cp_dbcsr_plus_fm_fm_t, &
      83              :              copy_dbcsr_to_fm_bc, copy_fm_to_dbcsr_bc, cp_fm_to_dbcsr_row_template, &
      84              :              cp_dbcsr_m_by_n_from_template, cp_dbcsr_m_by_n_from_row_template, &
      85              :              dbcsr_create_dist_r_unrot
      86              : 
      87              :    ! distribution_2d_type compatibility
      88              :    PUBLIC :: cp_dbcsr_dist2d_to_dist
      89              : 
      90              :    PUBLIC :: dbcsr_copy_columns_hack
      91              : 
      92              :    ! matrix set
      93              :    PUBLIC :: dbcsr_allocate_matrix_set
      94              :    PUBLIC :: dbcsr_deallocate_matrix_set
      95              : 
      96              :    INTERFACE dbcsr_allocate_matrix_set
      97              :       MODULE PROCEDURE allocate_dbcsr_matrix_set_1d
      98              :       MODULE PROCEDURE allocate_dbcsr_matrix_set_2d
      99              :       MODULE PROCEDURE allocate_dbcsr_matrix_set_3d
     100              :       MODULE PROCEDURE allocate_dbcsr_matrix_set_4d
     101              :       MODULE PROCEDURE allocate_dbcsr_matrix_set_5d
     102              :    END INTERFACE
     103              : 
     104              :    INTERFACE dbcsr_deallocate_matrix_set
     105              :       MODULE PROCEDURE deallocate_dbcsr_matrix_set_1d
     106              :       MODULE PROCEDURE deallocate_dbcsr_matrix_set_2d
     107              :       MODULE PROCEDURE deallocate_dbcsr_matrix_set_3d
     108              :       MODULE PROCEDURE deallocate_dbcsr_matrix_set_4d
     109              :       MODULE PROCEDURE deallocate_dbcsr_matrix_set_5d
     110              :    END INTERFACE
     111              : 
     112              : CONTAINS
     113              : 
     114              : ! **************************************************************************************************
     115              : !> \brief Sum local, nonsymmetric matrices in history order, using bounded per-worker storage.
     116              : !>        Pack and store outside OpenMP, including missing or transposed input blocks.
     117              : !> \param matrix_c independent output matrices
     118              : !> \param matrix_a input matrices, indexed by output and history entry; must not alias outputs
     119              : !> \param alpha coefficients of the history entries
     120              : ! **************************************************************************************************
     121          772 :    SUBROUTINE dbcsr_sum_many(matrix_c, matrix_a, alpha)
     122              :       TYPE(dbcsr_p_type), INTENT(IN)                     :: matrix_c(:), matrix_a(:, :)
     123              :       REAL(dp), INTENT(IN)                               :: alpha(:)
     124              : 
     125              :       TYPE local_sum_type
     126              :          REAL(dp), ALLOCATABLE :: value(:, :), buffer(:, :)
     127              :       END TYPE local_sum_type
     128              : 
     129              :       INTEGER                                            :: first, i, j, k, n, nbatch, nworkers
     130          772 :       TYPE(local_sum_type), ALLOCATABLE                  :: work(:)
     131              : 
     132          772 :       CPASSERT(SIZE(matrix_c) == SIZE(matrix_a, 1))
     133          772 :       CPASSERT(SIZE(alpha) == SIZE(matrix_a, 2))
     134          772 :       IF (SIZE(matrix_c) == 0) RETURN
     135          772 :       nworkers = 1
     136          772 : !$    nworkers = MIN(SIZE(matrix_c), omp_get_max_threads())
     137         3088 :       ALLOCATE (work(nworkers))
     138         4568 :       DO first = 1, SIZE(matrix_c), nworkers
     139         3796 :          nbatch = MIN(nworkers, SIZE(matrix_c) - first + 1)
     140         7592 :          DO j = 1, nbatch
     141         3796 :             CALL dbcsr_get_info(matrix_c(first + j - 1)%matrix, nfullrows_total=n, nfullcols_total=k)
     142         3796 :             IF (ALLOCATED(work(j)%value)) THEN
     143         3024 :                IF (SIZE(work(j)%value, 1) /= n .OR. SIZE(work(j)%value, 2) /= k) THEN
     144            0 :                   DEALLOCATE (work(j)%value, work(j)%buffer)
     145              :                END IF
     146              :             END IF
     147         7656 :             IF (.NOT. ALLOCATED(work(j)%value)) ALLOCATE (work(j)%value(n, k), work(j)%buffer(n, k))
     148       699244 :             work(j)%value(:, :) = 0.0_dp
     149              :          END DO
     150        37124 :          DO i = 1, SIZE(alpha)
     151        66656 :             DO j = 1, nbatch
     152        66656 :                CALL copy_dbcsr_to_local(matrix_a(first + j - 1, i)%matrix, work(j)%buffer)
     153              :             END DO
     154        37124 : !$OMP PARALLEL DO DEFAULT(NONE) SCHEDULE(STATIC) NUM_THREADS(nbatch) IF(nbatch > 1) SHARED(work,alpha,i,nbatch)
     155              :             DO j = 1, nbatch
     156              :                work(j)%value(:, :) = work(j)%value(:, :) + alpha(i)*work(j)%buffer(:, :)
     157              :             END DO
     158              : !$OMP END PARALLEL DO
     159              :          END DO
     160         8364 :          DO j = 1, nbatch
     161         7592 :             CALL copy_local_to_dbcsr(matrix_c(first + j - 1)%matrix, work(j)%value)
     162              :          END DO
     163              :       END DO
     164         1544 :    END SUBROUTINE dbcsr_sum_many
     165              : 
     166              : ! **************************************************************************************************
     167              : !> \brief Load a single-rank, nonsymmetric matrix without redistribution.
     168              : !> \param matrix DBCSR matrix
     169              : !> \param dense full local matrix
     170              : ! **************************************************************************************************
     171        99280 :    SUBROUTINE copy_dbcsr_to_local(matrix, dense)
     172              :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix
     173              :       REAL(dp), INTENT(OUT)                              :: dense(:, :)
     174              : 
     175              :       INTEGER                                            :: col, nc, nr, row
     176              :       LOGICAL                                            :: transposed
     177        99280 :       REAL(dp), POINTER                                  :: block(:, :)
     178              :       TYPE(dbcsr_iterator_type)                          :: iter
     179              : 
     180        99280 :       CPASSERT(dbcsr_get_matrix_type(matrix) == dbcsr_type_no_symmetry)
     181     20658348 :       dense(:, :) = 0.0_dp
     182        99280 :       CALL dbcsr_iterator_readonly_start(iter, matrix)
     183       274700 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     184              :          CALL dbcsr_iterator_next_block(iter, block=block, transposed=transposed, &
     185       175420 :                                         row_size=nr, col_size=nc, row_offset=row, col_offset=col)
     186       274700 :          IF (transposed) THEN
     187            0 :             dense(row:row + nr - 1, col:col + nc - 1) = TRANSPOSE(block)
     188              :          ELSE
     189     20765976 :             dense(row:row + nr - 1, col:col + nc - 1) = block
     190              :          END IF
     191              :       END DO
     192        99280 :       CALL dbcsr_iterator_stop(iter)
     193        99280 :    END SUBROUTINE copy_dbcsr_to_local
     194              : 
     195              : ! **************************************************************************************************
     196              : !> \brief Store a single-rank, nonsymmetric matrix without redistribution.
     197              : !> \param matrix DBCSR matrix
     198              : !> \param dense full local matrix
     199              : ! **************************************************************************************************
     200        52206 :    SUBROUTINE copy_local_to_dbcsr(matrix, dense)
     201              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix
     202              :       REAL(dp), INTENT(IN)                               :: dense(:, :)
     203              : 
     204              :       INTEGER                                            :: col, nc, nr, row
     205              :       LOGICAL                                            :: transposed
     206        52206 :       REAL(dp), POINTER                                  :: block(:, :)
     207              :       TYPE(dbcsr_iterator_type)                          :: iter
     208              : 
     209        52206 :       CPASSERT(dbcsr_get_matrix_type(matrix) == dbcsr_type_no_symmetry)
     210        52206 :       CALL dbcsr_reserve_all_blocks(matrix)
     211        52206 :       CALL dbcsr_iterator_start(iter, matrix)
     212       131636 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     213              :          CALL dbcsr_iterator_next_block(iter, block=block, transposed=transposed, &
     214        79430 :                                         row_size=nr, col_size=nc, row_offset=row, col_offset=col)
     215       131636 :          IF (transposed) THEN
     216            0 :             block(:, :) = TRANSPOSE(dense(row:row + nr - 1, col:col + nc - 1))
     217              :          ELSE
     218     10245886 :             block(:, :) = dense(row:row + nr - 1, col:col + nc - 1)
     219              :          END IF
     220              :       END DO
     221        52206 :       CALL dbcsr_iterator_stop(iter)
     222        52206 :    END SUBROUTINE copy_local_to_dbcsr
     223              : 
     224              : ! **************************************************************************************************
     225              : !> \brief   Copy a BLACS matrix to a dbcsr matrix.
     226              : !>
     227              : !>          real_matrix=beta*real_matrix+alpha*fm
     228              : !>          beta defaults to 0, alpha to 1
     229              : !> \param[in] fm              full matrix
     230              : !> \param[out] matrix         DBCSR matrix
     231              : !> \param[in] keep_sparsity   (optional) retains the sparsity of the input
     232              : !>                            matrix
     233              : !> \date    2009-10-13
     234              : !> \par History
     235              : !>          2009-10-13 rewritten based on copy_dbcsr_to_fm
     236              : !> \author  Urban Borstnik
     237              : !> \version 2.0
     238              : ! **************************************************************************************************
     239      1319433 :    SUBROUTINE copy_fm_to_dbcsr(fm, matrix, keep_sparsity)
     240              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm
     241              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix
     242              :       LOGICAL, INTENT(IN), OPTIONAL                      :: keep_sparsity
     243              : 
     244              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'copy_fm_to_dbcsr'
     245              : 
     246              :       INTEGER                                            :: handle
     247              :       LOGICAL                                            :: my_keep_sparsity
     248              :       TYPE(dbcsr_type)                                   :: bc_mat, redist_mat
     249              : 
     250      1319433 :       CALL timeset(routineN, handle)
     251              : 
     252      1319433 :       my_keep_sparsity = .FALSE.
     253      1319433 :       IF (PRESENT(keep_sparsity)) my_keep_sparsity = keep_sparsity
     254              : 
     255      1319433 :       CALL copy_fm_to_dbcsr_bc(fm, bc_mat)
     256              : 
     257      1319433 :       IF (my_keep_sparsity) THEN
     258        46742 :          CALL dbcsr_create(redist_mat, template=matrix)
     259        46742 :          CALL dbcsr_complete_redistribute(bc_mat, redist_mat)
     260        46742 :          CALL dbcsr_copy(matrix, redist_mat, keep_sparsity=.TRUE.)
     261        46742 :          CALL dbcsr_release(redist_mat)
     262              :       ELSE
     263      1272691 :          CALL dbcsr_complete_redistribute(bc_mat, matrix)
     264              :       END IF
     265              : 
     266      1319433 :       CALL dbcsr_release(bc_mat)
     267              : 
     268      1319433 :       CALL timestop(handle)
     269      1319433 :    END SUBROUTINE copy_fm_to_dbcsr
     270              : 
     271              : ! **************************************************************************************************
     272              : !> \brief   Copy a BLACS matrix to a dbcsr matrix with a special block-cyclic distribution,
     273              : !>           which requires no complete redistribution.
     274              : !> \param fm ...
     275              : !> \param bc_mat ...
     276              : ! **************************************************************************************************
     277      1322409 :    SUBROUTINE copy_fm_to_dbcsr_bc(fm, bc_mat)
     278              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm
     279              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: bc_mat
     280              : 
     281              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'copy_fm_to_dbcsr_bc'
     282              : 
     283              :       INTEGER                                            :: col, handle, ncol_block, ncol_global, &
     284              :                                                             nrow_block, nrow_global, row
     285      1322409 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: first_col, first_row, last_col, last_row
     286      1322409 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size, row_blk_size
     287      1322409 :       INTEGER, DIMENSION(:, :), POINTER                  :: pgrid
     288      1322409 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: dbcsr_block, fm_block
     289              :       TYPE(dbcsr_distribution_type)                      :: bc_dist
     290              :       TYPE(dbcsr_iterator_type)                          :: iter
     291              : 
     292      1322409 :       CALL timeset(routineN, handle)
     293              : 
     294              :       ! Create processor grid
     295      1322409 :       pgrid => fm%matrix_struct%context%blacs2mpi
     296              : 
     297              :       ! Create a block-cyclic distribution compatible with the FM matrix.
     298      1322409 :       nrow_block = fm%matrix_struct%nrow_block
     299      1322409 :       ncol_block = fm%matrix_struct%ncol_block
     300      1322409 :       nrow_global = fm%matrix_struct%nrow_global
     301      1322409 :       ncol_global = fm%matrix_struct%ncol_global
     302      1322409 :       NULLIFY (col_blk_size, row_blk_size)
     303              :       CALL dbcsr_create_dist_block_cyclic(bc_dist, &
     304              :                                           nrows=nrow_global, ncolumns=ncol_global, & ! Actual full matrix size
     305              :                                           nrow_block=nrow_block, ncol_block=ncol_block, & ! BLACS parameters
     306              :                                           group_handle=fm%matrix_struct%para_env%get_handle(), pgrid=pgrid, &
     307      1322409 :                                           row_blk_sizes=row_blk_size, col_blk_sizes=col_blk_size) ! block-cyclic row/col sizes
     308              : 
     309              :       ! Create the block-cyclic DBCSR matrix
     310              :       CALL dbcsr_create(bc_mat, "Block-cyclic ", bc_dist, &
     311      1322409 :                         dbcsr_type_no_symmetry, row_blk_size, col_blk_size, reuse_arrays=.TRUE.)
     312      1322409 :       CALL dbcsr_distribution_release(bc_dist)
     313              : 
     314              :       ! allocate all blocks
     315      1322409 :       CALL dbcsr_reserve_all_blocks(bc_mat)
     316              : 
     317      1322409 :       CALL calculate_fm_block_ranges(bc_mat, first_row, last_row, first_col, last_col)
     318              : 
     319              :       ! Copy the FM data to the block-cyclic DBCSR matrix.  This step
     320              :       ! could be skipped with appropriate DBCSR index manipulation.
     321      1322409 :       fm_block => fm%local_data
     322              : !$OMP PARALLEL DEFAULT(NONE) PRIVATE(iter, row, col, dbcsr_block) &
     323      1322409 : !$OMP SHARED(bc_mat, last_row, first_row, last_col, first_col, fm_block)
     324              :       CALL dbcsr_iterator_start(iter, bc_mat)
     325              :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     326              :          CALL dbcsr_iterator_next_block(iter, row, col, dbcsr_block)
     327              :          dbcsr_block(:, :) = fm_block(first_row(row):last_row(row), first_col(col):last_col(col))
     328              :       END DO
     329              :       CALL dbcsr_iterator_stop(iter)
     330              : !$OMP END PARALLEL
     331              : 
     332      1322409 :       CALL timestop(handle)
     333      2644818 :    END SUBROUTINE copy_fm_to_dbcsr_bc
     334              : 
     335              : ! **************************************************************************************************
     336              : !> \brief Copy a DBCSR matrix to a BLACS matrix
     337              : !> \param[in] matrix          DBCSR matrix
     338              : !> \param[out] fm             full matrix
     339              : !> \param plan optional S/A routing plan; discard before releasing the FM structure
     340              : !> \param check_plan check for layout changes and collectively rebuild the plan;
     341              : !>        defaults to false for callers that guarantee fixed layouts and threads
     342              : ! **************************************************************************************************
     343      1274793 :    SUBROUTINE copy_dbcsr_to_fm(matrix, fm, plan, check_plan)
     344              :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix
     345              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm
     346              :       TYPE(dbcsr_fm_copy_plan_type), INTENT(INOUT), &
     347              :          OPTIONAL                                        :: plan
     348              :       LOGICAL, INTENT(IN), OPTIONAL                      :: check_plan
     349              : 
     350              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'copy_dbcsr_to_fm'
     351              : 
     352              :       CHARACTER(len=default_string_length)               :: name
     353              :       INTEGER                                            :: group_handle, handle, ncol_block, &
     354              :                                                             nfullcols_total, nfullrows_total, &
     355              :                                                             nrow_block
     356      1274793 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size, row_blk_size
     357      1274793 :       INTEGER, DIMENSION(:, :), POINTER                  :: pgrid
     358              :       LOGICAL                                            :: validate_plan
     359              :       TYPE(dbcsr_distribution_type)                      :: bc_dist, dist
     360      1274793 :       TYPE(dbcsr_fm_copy_plan_type)                      :: local_plan
     361              :       TYPE(dbcsr_type)                                   :: bc_mat, matrix_nosym
     362              : 
     363      1274793 :       CALL timeset(routineN, handle)
     364      1274793 :       validate_plan = .FALSE.
     365      1274793 :       IF (PRESENT(check_plan)) validate_plan = check_plan
     366              : 
     367              :       ! check compatibility
     368              :       CALL dbcsr_get_info(matrix, &
     369              :                           name=name, &
     370              :                           distribution=dist, &
     371              :                           nfullrows_total=nfullrows_total, &
     372      1274793 :                           nfullcols_total=nfullcols_total)
     373              : 
     374      1274793 :       CPASSERT(fm%matrix_struct%nrow_global == nfullrows_total)
     375      1274793 :       CPASSERT(fm%matrix_struct%ncol_global == nfullcols_total)
     376              : 
     377       419887 :       SELECT CASE (dbcsr_get_matrix_type(matrix))
     378              :       CASE (dbcsr_type_symmetric, dbcsr_type_antisymmetric)
     379       419887 :          IF (PRESENT(plan)) THEN
     380       243046 :             CALL copy_dbcsr_to_fm_sym(matrix, fm, plan, validate_plan)
     381              :          ELSE
     382       176841 :             CALL copy_dbcsr_to_fm_sym(matrix, fm, local_plan, .FALSE.)
     383              :          END IF
     384       419887 :          CALL timestop(handle)
     385      1694680 :          RETURN
     386              :       END SELECT
     387              : 
     388              :       ! Other matrix types use the uncached redistribution path.
     389       854906 :       IF (PRESENT(plan)) plan = dbcsr_fm_copy_plan_type()
     390              : 
     391              :       ! info about the full matrix
     392       854906 :       nrow_block = fm%matrix_struct%nrow_block
     393       854906 :       ncol_block = fm%matrix_struct%ncol_block
     394              : 
     395              :       ! Convert DBCSR to a block-cyclic
     396       854906 :       NULLIFY (col_blk_size, row_blk_size)
     397       854906 :       CALL dbcsr_distribution_get(dist, group=group_handle, pgrid=pgrid)
     398              :       CALL dbcsr_create_dist_block_cyclic(bc_dist, &
     399              :                                           nrows=nfullrows_total, ncolumns=nfullcols_total, &
     400              :                                           nrow_block=nrow_block, ncol_block=ncol_block, &
     401              :                                           group_handle=group_handle, pgrid=pgrid, &
     402       854906 :                                           row_blk_sizes=row_blk_size, col_blk_sizes=col_blk_size)
     403              : 
     404              :       CALL dbcsr_create(bc_mat, "Block-cyclic"//name, bc_dist, &
     405       854906 :                         dbcsr_type_no_symmetry, row_blk_size, col_blk_size, reuse_arrays=.TRUE.)
     406       854906 :       CALL dbcsr_distribution_release(bc_dist)
     407              : 
     408       854906 :       IF (dbcsr_get_matrix_type(matrix) == dbcsr_type_no_symmetry) THEN
     409       854906 :          CALL dbcsr_complete_redistribute(matrix, bc_mat)
     410              :       ELSE
     411            0 :          CALL dbcsr_create(matrix_nosym, template=matrix, matrix_type=dbcsr_type_no_symmetry)
     412            0 :          CALL dbcsr_desymmetrize(matrix, matrix_nosym)
     413            0 :          CALL dbcsr_complete_redistribute(matrix_nosym, bc_mat)
     414       854906 :          CALL dbcsr_release(matrix_nosym)
     415              :       END IF
     416              : 
     417       854906 :       CALL copy_dbcsr_to_fm_bc(bc_mat, fm)
     418              : 
     419       854906 :       CALL dbcsr_release(bc_mat)
     420              : 
     421       854906 :       CALL timestop(handle)
     422      2726427 :    END SUBROUTINE copy_dbcsr_to_fm
     423              : 
     424              : ! **************************************************************************************************
     425              : !> \brief Send S/A values using a routing plan, checking the block sequence while packing.
     426              : !>        Mutable sources require a collective check before using the cached routing.
     427              : !> \param matrix symmetric or antisymmetric DBCSR workspace
     428              : !> \param fm full matrix on the source communicator
     429              : !> \param plan reusable routing and buffers; no outstanding communication on return
     430              : !> \param check_plan rebuild collectively if the source layout, FM structure or threads change
     431              : ! **************************************************************************************************
     432       419887 :    SUBROUTINE copy_dbcsr_to_fm_sym(matrix, fm, plan, check_plan)
     433              :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix
     434              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm
     435              :       TYPE(dbcsr_fm_copy_plan_type), INTENT(INOUT)       :: plan
     436              :       LOGICAL, INTENT(IN)                                :: check_plan
     437              : 
     438              :       INTEGER                                            :: attempt, col, col_offset, i, iblock, j, &
     439              :                                                             k, mirror, ncol, nrecv, nrow, &
     440              :                                                             nthreads, pos, rebuild, row, &
     441              :                                                             row_offset, thread
     442              :       LOGICAL                                            :: block_matches, layout_matches, transposed
     443              :       REAL(KIND=dp)                                      :: symmetry_sign, value
     444       419887 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: block
     445              :       TYPE(dbcsr_iterator_type)                          :: iter
     446              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     447              : 
     448       199835 :       IF (.NOT. ALLOCATED(plan%thread)) CALL dbcsr_to_fm_plan_create(matrix, fm, plan)
     449       419887 :       para_env => fm%matrix_struct%context%para_env
     450       419887 :       symmetry_sign = 1.0_dp
     451       419887 :       IF (dbcsr_get_matrix_type(matrix) == dbcsr_type_antisymmetric) symmetry_sign = -1.0_dp
     452              : 
     453       420071 :       DO attempt = 1, 2
     454              :          layout_matches = ASSOCIATED(plan%matrix_struct, fm%matrix_struct) .AND. &
     455       420071 :                           plan%matrix_type == dbcsr_get_matrix_type(matrix)
     456              :          rebuild = 0
     457              : !$OMP PARALLEL DEFAULT(NONE) SHARED(matrix, plan, symmetry_sign, layout_matches) &
     458              : !$OMP PRIVATE(iter, row, col, block, transposed, row_offset, col_offset, nrow, ncol, &
     459       420071 : !$OMP thread, nthreads, iblock, pos, mirror, i, j, k, value, block_matches) REDUCTION(MAX:rebuild)
     460              :          thread = 0
     461              :          nthreads = 1
     462              : !$       thread = omp_get_thread_num()
     463              : !$       nthreads = omp_get_num_threads()
     464              :          IF (.NOT. layout_matches .OR. nthreads /= SIZE(plan%thread)) THEN
     465              :             rebuild = 1
     466              :          ELSE
     467              :             iblock = 0
     468              :             pos = 0
     469              :             CALL dbcsr_iterator_readonly_start(iter, matrix, dynamic=.FALSE.)
     470              :             DO WHILE (dbcsr_iterator_blocks_left(iter))
     471              :                CALL dbcsr_iterator_next_block(iter, row, col, block, transposed=transposed, &
     472              :                                               row_size=nrow, col_size=ncol, row_offset=row_offset, col_offset=col_offset)
     473              :                iblock = iblock + 1
     474              :                block_matches = iblock <= SIZE(plan%thread(thread)%blocks, 2)
     475              :                IF (block_matches) block_matches = ALL(plan%thread(thread)%blocks(:, iblock) == &
     476              :                                                       [row, col, nrow, ncol, row_offset, col_offset])
     477              :                IF (.NOT. block_matches) THEN
     478              :                   rebuild = 1
     479              :                   EXIT
     480              :                END IF
     481              :                DO j = 1, ncol
     482              :                   DO i = 1, nrow
     483              :                      IF (transposed) THEN
     484              :                         value = symmetry_sign*block(j, i)
     485              :                      ELSE
     486              :                         value = block(i, j)
     487              :                      END IF
     488              :                      DO mirror = 1, 2
     489              :                         IF (mirror == 2 .AND. row == col) CYCLE
     490              :                         pos = pos + 1
     491              :                         k = plan%thread(thread)%slots(pos)
     492              :                         plan%send_values(k) = value
     493              :                         value = symmetry_sign*value
     494              :                      END DO
     495              :                   END DO
     496              :                END DO
     497              :             END DO
     498              :             CALL dbcsr_iterator_stop(iter)
     499              :             IF (iblock /= SIZE(plan%thread(thread)%blocks, 2) .OR. &
     500              :                 pos /= SIZE(plan%thread(thread)%slots)) rebuild = 1
     501              :          END IF
     502              : !$OMP END PARALLEL
     503       420071 :          IF (check_plan) CALL para_env%max(rebuild)
     504       420071 :          IF (rebuild == 0) EXIT
     505          184 :          CPASSERT(check_plan .AND. attempt == 1)
     506       420071 :          CALL dbcsr_to_fm_plan_create(matrix, fm, plan)
     507              :       END DO
     508              : 
     509              :       ! Counts and destination indices were exchanged once when the plan was built.
     510              :       CALL para_env%alltoall(plan%send_values, plan%send_count, plan%send_disp, &
     511       419887 :                              plan%recv_values, plan%recv_count, plan%recv_disp)
     512      1257252 :       nrecv = SUM(plan%recv_count)
     513    206789356 :       fm%local_data = 0.0_dp
     514       419887 : !$OMP PARALLEL DO DEFAULT(NONE) SHARED(fm, plan, nrecv) PRIVATE(k)
     515              :       DO k = 1, nrecv
     516              :          fm%local_data(plan%recv_index(1, k), plan%recv_index(2, k)) = plan%recv_values(k)
     517              :       END DO
     518              : !$OMP END PARALLEL DO
     519              : 
     520       419887 :    END SUBROUTINE copy_dbcsr_to_fm_sym
     521              : 
     522              : ! **************************************************************************************************
     523              : !> \brief Cache source-to-packet slots and destination FM indices, not source pointers.
     524              : !>        Counting and indexing use the same static DBCSR thread assignment. The
     525              : !>        plan is valid only while that assignment and both matrix layouts are fixed.
     526              : !> \param matrix symmetric or antisymmetric DBCSR workspace
     527              : !> \param fm destination full matrix
     528              : !> \param plan new routing plan
     529              : ! **************************************************************************************************
     530       200203 :    SUBROUTINE dbcsr_to_fm_plan_create(matrix, fm, plan)
     531              :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix
     532              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm
     533              :       TYPE(dbcsr_fm_copy_plan_type), INTENT(OUT)         :: plan
     534              : 
     535              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'dbcsr_to_fm_plan_create'
     536              : 
     537              :       INTEGER                                            :: col, col_offset, dest, handle, i, &
     538              :                                                             iblock, j, k, mirror, ncol, nproc, &
     539              :                                                             nrow, nthreads, pass, pos, row, &
     540              :                                                             row_offset, thread, x, y
     541              :       INTEGER(KIND=int_8)                                :: count, offset
     542       200019 :       INTEGER(KIND=int_8), ALLOCATABLE, DIMENSION(:)     :: local_pos
     543       200019 :       INTEGER(KIND=int_8), ALLOCATABLE, DIMENSION(:, :)  :: thread_pos
     544       200019 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: nblocks
     545       200019 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: send_index
     546              :       LOGICAL                                            :: transposed
     547              :       TYPE(cp_fm_struct_type), POINTER                   :: fms
     548              :       TYPE(dbcsr_iterator_type)                          :: iter
     549              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     550              : 
     551       200019 :       CALL timeset(routineN, handle)
     552       200019 :       fms => fm%matrix_struct
     553       200019 :       plan%matrix_struct => fms
     554       200019 :       plan%matrix_type = dbcsr_get_matrix_type(matrix)
     555       200019 :       para_env => fms%context%para_env
     556       200019 :       nproc = para_env%num_pe
     557       200019 :       nthreads = 1
     558       200019 : !$    nthreads = omp_get_max_threads()
     559      1200114 :       ALLOCATE (thread_pos(0:nproc - 1, 0:nthreads - 1), nblocks(0:nthreads - 1))
     560            0 :       ALLOCATE (plan%send_count(0:nproc - 1), plan%send_disp(0:nproc - 1), &
     561      1200114 :                 plan%recv_count(0:nproc - 1), plan%recv_disp(0:nproc - 1))
     562       200019 :       thread_pos(:, :) = 0
     563       200019 :       nblocks(:) = 0
     564              : 
     565              : !$OMP PARALLEL DEFAULT(NONE) &
     566              : !$OMP SHARED(matrix, fms, nproc, nthreads, &
     567              : !$OMP thread_pos, nblocks, send_index, plan) &
     568              : !$OMP PRIVATE(iter, row, col, row_offset, col_offset, nrow, ncol, &
     569       200019 : !$OMP thread, iblock, pos, pass, mirror, i, j, x, y, dest, k, offset, count, local_pos, transposed)
     570              :       thread = 0
     571              : !$    thread = omp_get_thread_num()
     572              :       ALLOCATE (local_pos(0:nproc - 1))
     573              :       local_pos(:) = 0
     574              :       DO pass = 1, 2
     575              :          iblock = 0
     576              :          pos = 0
     577              :          IF (pass == 2) THEN
     578              : !$OMP SINGLE
     579              :             CPASSERT(SUM(thread_pos) <= INT(HUGE(0), int_8)/2)
     580              :             plan%send_count(:) = INT(SUM(thread_pos, DIM=2))
     581              : !$          nthreads = omp_get_num_threads()
     582              :             ALLOCATE (plan%thread(0:nthreads - 1))
     583              :             DO k = 0, nthreads - 1
     584              :                ALLOCATE (plan%thread(k)%blocks(6, nblocks(k)), &
     585              :                          plan%thread(k)%slots(INT(SUM(thread_pos(:, k)))))
     586              :             END DO
     587              :             offset = 0
     588              :             DO dest = 0, nproc - 1
     589              :                plan%send_disp(dest) = INT(offset)
     590              :                DO k = 0, nthreads - 1
     591              :                   count = thread_pos(dest, k)
     592              :                   thread_pos(dest, k) = offset
     593              :                   offset = offset + count
     594              :                END DO
     595              :             END DO
     596              :             ALLOCATE (send_index(2, MAX(1, SUM(plan%send_count))), &
     597              :                       plan%send_values(MAX(1, SUM(plan%send_count))))
     598              :             send_index(:, :) = 0
     599              :             plan%send_values(:) = 0.0_dp
     600              : !$OMP END SINGLE
     601              :             local_pos(:) = thread_pos(:, thread)
     602              :          END IF
     603              :          CALL dbcsr_iterator_readonly_start(iter, matrix, dynamic=.FALSE.)
     604              :          DO WHILE (dbcsr_iterator_blocks_left(iter))
     605              :             CALL dbcsr_iterator_next_block(iter, row, col, row_size=nrow, col_size=ncol, &
     606              :                                            row_offset=row_offset, col_offset=col_offset, transposed=transposed)
     607              :             iblock = iblock + 1
     608              :             IF (pass == 2) THEN
     609              :                plan%thread(thread)%blocks(:, iblock) = [row, col, nrow, ncol, row_offset, col_offset]
     610              :             END IF
     611              :             DO j = 1, ncol
     612              :                DO i = 1, nrow
     613              :                   DO mirror = 1, 2
     614              :                      IF (mirror == 2 .AND. row == col) CYCLE
     615              :                      x = row_offset + i - 1
     616              :                      y = col_offset + j - 1
     617              :                      IF (mirror == 2) THEN
     618              :                         x = col_offset + j - 1
     619              :                         y = row_offset + i - 1
     620              :                      END IF
     621              :                      dest = fms%context%blacs2mpi(fms%g2p_row(x), fms%g2p_col(y))
     622              :                      local_pos(dest) = local_pos(dest) + 1
     623              :                      IF (pass == 1) CYCLE
     624              :                      k = INT(local_pos(dest))
     625              :                      send_index(:, k) = [fms%g2l_row(x), fms%g2l_col(y)]
     626              :                      pos = pos + 1
     627              :                      plan%thread(thread)%slots(pos) = k
     628              :                   END DO
     629              :                END DO
     630              :             END DO
     631              :          END DO
     632              :          CALL dbcsr_iterator_stop(iter)
     633              :          IF (pass == 1) THEN
     634              :             thread_pos(:, thread) = local_pos(:)
     635              :             nblocks(thread) = iblock
     636              :          END IF
     637              : !$OMP BARRIER
     638              :       END DO
     639              :       DEALLOCATE (local_pos)
     640              : !$OMP END PARALLEL
     641       200019 :       DEALLOCATE (thread_pos, nblocks)
     642              : 
     643       200019 :       CALL para_env%alltoall(plan%send_count, plan%recv_count, 1)
     644       599092 :       CPASSERT(SUM(INT(plan%recv_count, int_8)) <= INT(HUGE(0), int_8)/2)
     645       200019 :       plan%recv_disp(0) = 0
     646       399073 :       DO dest = 1, nproc - 1
     647       399073 :          plan%recv_disp(dest) = plan%recv_disp(dest - 1) + plan%recv_count(dest - 1)
     648              :       END DO
     649            0 :       ALLOCATE (plan%recv_index(2, MAX(1, SUM(plan%recv_count))), &
     650      1798241 :                 plan%recv_values(MAX(1, SUM(plan%recv_count))))
     651    209375643 :       plan%recv_index(:, :) = 0
     652     69925227 :       plan%recv_values(:) = 0.0_dp
     653              :       CALL para_env%alltoall(send_index, 2*plan%send_count, 2*plan%send_disp, &
     654      1796311 :                              plan%recv_index, 2*plan%recv_count, 2*plan%recv_disp)
     655       200019 :       CALL timestop(handle)
     656              : 
     657       600057 :    END SUBROUTINE dbcsr_to_fm_plan_create
     658              : 
     659              : ! **************************************************************************************************
     660              : !> \brief Copy a DBCSR_BLACS matrix to a BLACS matrix
     661              : !> \param bc_mat DBCSR matrix
     662              : !> \param[out] fm             full matrix
     663              : ! **************************************************************************************************
     664       854906 :    SUBROUTINE copy_dbcsr_to_fm_bc(bc_mat, fm)
     665              :       TYPE(dbcsr_type), INTENT(IN)                       :: bc_mat
     666              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm
     667              : 
     668              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'copy_dbcsr_to_fm_bc'
     669              : 
     670              :       INTEGER                                            :: col, handle, row
     671       854906 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: first_col, first_row, last_col, last_row
     672       854906 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: dbcsr_block, fm_block
     673              :       TYPE(dbcsr_iterator_type)                          :: iter
     674              : 
     675       854906 :       CALL timeset(routineN, handle)
     676              : 
     677       854906 :       CALL calculate_fm_block_ranges(bc_mat, first_row, last_row, first_col, last_col)
     678              : 
     679              :       ! Now copy data to the FM matrix
     680       854906 :       fm_block => fm%local_data
     681    198092118 :       fm_block = REAL(0.0, KIND=dp)
     682              : !$OMP PARALLEL DEFAULT(NONE) PRIVATE(iter, row, col, dbcsr_block) &
     683       854906 : !$OMP SHARED(bc_mat, last_row, first_row, last_col, first_col, fm_block)
     684              :       CALL dbcsr_iterator_readonly_start(iter, bc_mat)
     685              :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     686              :          CALL dbcsr_iterator_next_block(iter, row, col, dbcsr_block)
     687              :          fm_block(first_row(row):last_row(row), first_col(col):last_col(col)) = dbcsr_block(:, :)
     688              :       END DO
     689              :       CALL dbcsr_iterator_stop(iter)
     690              : !$OMP END PARALLEL
     691              : 
     692       854906 :       CALL timestop(handle)
     693      1709812 :    END SUBROUTINE copy_dbcsr_to_fm_bc
     694              : 
     695              : ! **************************************************************************************************
     696              : !> \brief Helper routine used to copy blocks from DBCSR into FM matrices and vice versa
     697              : !> \param bc_mat ...
     698              : !> \param first_row ...
     699              : !> \param last_row ...
     700              : !> \param first_col ...
     701              : !> \param last_col ...
     702              : !> \author Ole Schuett
     703              : ! **************************************************************************************************
     704      2177315 :    SUBROUTINE calculate_fm_block_ranges(bc_mat, first_row, last_row, first_col, last_col)
     705              :       TYPE(dbcsr_type), INTENT(IN)                       :: bc_mat
     706              :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT)    :: first_row, last_row, first_col, last_col
     707              : 
     708              :       INTEGER                                            :: col, nblkcols_local, nblkcols_total, &
     709              :                                                             nblkrows_local, nblkrows_total, row
     710              :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: local_col_sizes, local_row_sizes
     711      2177315 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size, local_cols, local_rows, &
     712      2177315 :                                                             row_blk_size
     713              : 
     714              :       CALL dbcsr_get_info(bc_mat, &
     715              :                           nblkrows_total=nblkrows_total, &
     716              :                           nblkcols_total=nblkcols_total, &
     717              :                           nblkrows_local=nblkrows_local, &
     718              :                           nblkcols_local=nblkcols_local, &
     719              :                           local_rows=local_rows, &
     720              :                           local_cols=local_cols, &
     721              :                           row_blk_size=row_blk_size, &
     722      2177315 :                           col_blk_size=col_blk_size)
     723              : 
     724              :       ! calculate first_row and last_row
     725      6530697 :       ALLOCATE (local_row_sizes(nblkrows_total))
     726      2177315 :       local_row_sizes(:) = 0
     727      2177315 :       IF (nblkrows_local >= 1) THEN
     728      5401182 :          DO row = 1, nblkrows_local
     729      5401182 :             local_row_sizes(local_rows(row)) = row_blk_size(local_rows(row))
     730              :          END DO
     731              :       END IF
     732      6529449 :       ALLOCATE (first_row(nblkrows_total), last_row(nblkrows_total))
     733      2177315 :       CALL dbcsr_convert_sizes_to_offsets(local_row_sizes, first_row, last_row)
     734      2177315 :       DEALLOCATE (local_row_sizes)
     735              : 
     736              :       ! calculate first_col and last_col
     737      6528329 :       ALLOCATE (local_col_sizes(nblkcols_total))
     738      2177315 :       local_col_sizes(:) = 0
     739      2177315 :       IF (nblkcols_local >= 1) THEN
     740      6209480 :          DO col = 1, nblkcols_local
     741      6209480 :             local_col_sizes(local_cols(col)) = col_blk_size(local_cols(col))
     742              :          END DO
     743              :       END IF
     744      6524713 :       ALLOCATE (first_col(nblkcols_total), last_col(nblkcols_total))
     745      2177315 :       CALL dbcsr_convert_sizes_to_offsets(local_col_sizes, first_col, last_col)
     746      2177315 :       DEALLOCATE (local_col_sizes)
     747              : 
     748      2177315 :    END SUBROUTINE calculate_fm_block_ranges
     749              : 
     750              : ! **************************************************************************************************
     751              : !> \brief hack for dbcsr_copy_columns
     752              : !> \param matrix_b ...
     753              : !> \param matrix_a ...
     754              : !> \param ncol ...
     755              : !> \param source_start ...
     756              : !> \param target_start ...
     757              : !> \param para_env ...
     758              : !> \param blacs_env ...
     759              : !> \author vw
     760              : ! **************************************************************************************************
     761         9232 :    SUBROUTINE dbcsr_copy_columns_hack(matrix_b, matrix_a, &
     762              :                                       ncol, source_start, target_start, para_env, blacs_env)
     763              : 
     764              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_b
     765              :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_a
     766              :       INTEGER, INTENT(IN)                                :: ncol, source_start, target_start
     767              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     768              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     769              : 
     770              :       INTEGER                                            :: nfullcols_total, nfullrows_total
     771              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     772              :       TYPE(cp_fm_type)                                   :: fm_matrix_a, fm_matrix_b
     773              : 
     774         2308 :       NULLIFY (fm_struct)
     775         2308 :       CALL dbcsr_get_info(matrix_a, nfullrows_total=nfullrows_total, nfullcols_total=nfullcols_total)
     776              :       CALL cp_fm_struct_create(fm_struct, context=blacs_env, nrow_global=nfullrows_total, &
     777         2308 :                                ncol_global=nfullcols_total, para_env=para_env)
     778         2308 :       CALL cp_fm_create(fm_matrix_a, fm_struct, name="fm_matrix_a")
     779         2308 :       CALL cp_fm_struct_release(fm_struct)
     780              : 
     781         2308 :       CALL dbcsr_get_info(matrix_b, nfullrows_total=nfullrows_total, nfullcols_total=nfullcols_total)
     782              :       CALL cp_fm_struct_create(fm_struct, context=blacs_env, nrow_global=nfullrows_total, &
     783         2308 :                                ncol_global=nfullcols_total, para_env=para_env)
     784         2308 :       CALL cp_fm_create(fm_matrix_b, fm_struct, name="fm_matrix_b")
     785         2308 :       CALL cp_fm_struct_release(fm_struct)
     786              : 
     787         2308 :       CALL copy_dbcsr_to_fm(matrix_a, fm_matrix_a)
     788         2308 :       CALL copy_dbcsr_to_fm(matrix_b, fm_matrix_b)
     789              : 
     790         2308 :       CALL cp_fm_to_fm(fm_matrix_a, fm_matrix_b, ncol, source_start, target_start)
     791              : 
     792         2308 :       CALL copy_fm_to_dbcsr(fm_matrix_b, matrix_b)
     793              : 
     794         2308 :       CALL cp_fm_release(fm_matrix_a)
     795         2308 :       CALL cp_fm_release(fm_matrix_b)
     796              : 
     797         2308 :    END SUBROUTINE dbcsr_copy_columns_hack
     798              : 
     799              : ! **************************************************************************************************
     800              : !> \brief Creates a DBCSR distribution from a distribution_2d
     801              : !> \param[in] dist2d          distribution_2d
     802              : !> \param[out] dist           DBCSR distribution
     803              : !> \par History
     804              : !>    move form dbcsr_operation 01.2010
     805              : ! **************************************************************************************************
     806        12596 :    SUBROUTINE cp_dbcsr_dist2d_to_dist(dist2d, dist)
     807              :       TYPE(distribution_2d_type), INTENT(IN), TARGET     :: dist2d
     808              :       TYPE(dbcsr_distribution_type), INTENT(OUT)         :: dist
     809              : 
     810        12596 :       INTEGER, DIMENSION(:), POINTER                     :: col_dist, row_dist
     811        12596 :       INTEGER, DIMENSION(:, :), POINTER                  :: col_dist_data, pgrid, row_dist_data
     812              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     813              :       TYPE(distribution_2d_type), POINTER                :: dist2d_p
     814              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     815              : 
     816        12596 :       dist2d_p => dist2d
     817              :       CALL distribution_2d_get(dist2d_p, &
     818              :                                row_distribution=row_dist_data, &
     819              :                                col_distribution=col_dist_data, &
     820        12596 :                                blacs_env=blacs_env)
     821        12596 :       CALL blacs_env%get(para_env=para_env, blacs2mpi=pgrid)
     822              : 
     823              :       ! map to 1D arrays
     824        12596 :       row_dist => row_dist_data(:, 1)
     825        12596 :       col_dist => col_dist_data(:, 1)
     826              :       !row_cluster => row_dist_data(:, 2)
     827              :       !col_cluster => col_dist_data(:, 2)
     828              : 
     829              :       CALL dbcsr_distribution_new(dist, &
     830              :                                   group=para_env%get_handle(), pgrid=pgrid, &
     831              :                                   row_dist=row_dist, &
     832        12596 :                                   col_dist=col_dist)
     833              : 
     834        12596 :    END SUBROUTINE cp_dbcsr_dist2d_to_dist
     835              : 
     836              : ! **************************************************************************************************
     837              : !> \brief multiply a dbcsr with a replicated array
     838              : !>        c = alpha_scalar * A (dbscr) * b + c
     839              : !> \param[in] matrix_a DBSCR matrxx
     840              : !> \param[in]  vec_b        vectors b
     841              : !> \param[inout] vec_c      vectors c
     842              : !> \param[in]  ncol         nbr of columns
     843              : !> \param[in]  alpha        alpha
     844              : !>
     845              : ! **************************************************************************************************
     846            0 :    SUBROUTINE dbcsr_multiply_local(matrix_a, vec_b, vec_c, ncol, alpha)
     847              :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_a
     848              :       REAL(dp), DIMENSION(:, :), INTENT(IN)              :: vec_b
     849              :       REAL(dp), DIMENSION(:, :), INTENT(INOUT)           :: vec_c
     850              :       INTEGER, INTENT(in), OPTIONAL                      :: ncol
     851              :       REAL(dp), INTENT(IN), OPTIONAL                     :: alpha
     852              : 
     853              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'dbcsr_multiply_local'
     854              : 
     855              :       INTEGER                                            :: col, coloff, my_ncol, row, rowoff, &
     856              :                                                             timing_handle
     857              :       LOGICAL                                            :: has_symm
     858              :       REAL(dp)                                           :: my_alpha, my_alpha2
     859            0 :       REAL(dp), DIMENSION(:, :), POINTER                 :: data_d
     860              :       TYPE(dbcsr_iterator_type)                          :: iter
     861              : 
     862            0 :       CALL timeset(routineN, timing_handle)
     863              : 
     864            0 :       my_alpha = 1.0_dp
     865            0 :       IF (PRESENT(alpha)) my_alpha = alpha
     866              : 
     867            0 :       my_ncol = SIZE(vec_b, 2)
     868            0 :       IF (PRESENT(ncol)) my_ncol = ncol
     869              : 
     870            0 :       my_alpha2 = 0.0_dp
     871            0 :       IF (dbcsr_get_matrix_type(matrix_a) == dbcsr_type_symmetric) my_alpha2 = my_alpha
     872            0 :       IF (dbcsr_get_matrix_type(matrix_a) == dbcsr_type_antisymmetric) my_alpha2 = -my_alpha
     873              : 
     874              :       has_symm = (dbcsr_get_matrix_type(matrix_a) == dbcsr_type_symmetric .OR. &
     875            0 :                   dbcsr_get_matrix_type(matrix_a) == dbcsr_type_antisymmetric)
     876              : 
     877              : !$OMP     PARALLEL DEFAULT(NONE) SHARED(matrix_a,vec_b,vec_c,ncol,my_alpha2,my_alpha,my_ncol,has_symm) &
     878            0 : !$OMP              PRIVATE(iter,row,col,data_d,rowoff,coloff)
     879              :       CALL dbcsr_iterator_readonly_start(iter, matrix_a, dynamic=.TRUE., dynamic_byrows=.TRUE.)
     880              :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     881              :          CALL dbcsr_iterator_next_block(iter, row, col, data_d, row_offset=rowoff, col_offset=coloff)
     882              :          IF (my_ncol /= 1) THEN
     883              :             CALL dgemm('N', 'N', &
     884              :                        SIZE(data_d, 1), my_ncol, SIZE(data_d, 2), &
     885              :                        my_alpha, data_d(1, 1), SIZE(data_d, 1), &
     886              :                        vec_b(coloff, 1), SIZE(vec_b, 1), &
     887              :                        1.0_dp, vec_c(rowoff, 1), SIZE(vec_c, 1))
     888              :          ELSE
     889              :             CALL dgemv('N', SIZE(data_d, 1), SIZE(data_d, 2), &
     890              :                        my_alpha, data_d(1, 1), SIZE(data_d, 1), &
     891              :                        vec_b(coloff, 1), 1, &
     892              :                        1.0_dp, vec_c(rowoff, 1), 1)
     893              :          END IF
     894              :       END DO
     895              :       CALL dbcsr_iterator_stop(iter)
     896              : !$OMP     END PARALLEL
     897              : 
     898              :       ! FIXME ... in the symmetric case, the writes to vec_c depend on the column, not the row. This makes OMP-ing more difficult
     899              :       ! needs e.g. a buffer for vec_c and a reduction of that buffer.
     900            0 :       IF (has_symm) THEN
     901            0 :          CALL dbcsr_iterator_readonly_start(iter, matrix_a)
     902            0 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
     903            0 :             CALL dbcsr_iterator_next_block(iter, row, col, data_d, row_offset=rowoff, col_offset=coloff)
     904            0 :             IF (row /= col) THEN
     905            0 :                IF (my_ncol /= 1) THEN
     906              :                   CALL dgemm('T', 'N', &
     907              :                              SIZE(data_d, 2), my_ncol, SIZE(data_d, 1), &
     908              :                              my_alpha2, data_d(1, 1), SIZE(data_d, 1), &
     909              :                              vec_b(rowoff, 1), SIZE(vec_b, 1), &
     910            0 :                              1.0_dp, vec_c(coloff, 1), SIZE(vec_c, 1))
     911              :                ELSE
     912              :                   CALL dgemv('T', SIZE(data_d, 1), SIZE(data_d, 2), &
     913              :                              my_alpha2, data_d(1, 1), SIZE(data_d, 1), &
     914              :                              vec_b(rowoff, 1), 1, &
     915            0 :                              1.0_dp, vec_c(coloff, 1), 1)
     916              :                END IF
     917              :             END IF
     918              :          END DO
     919            0 :          CALL dbcsr_iterator_stop(iter)
     920              :       END IF
     921              : 
     922            0 :       CALL timestop(timing_handle)
     923            0 :    END SUBROUTINE dbcsr_multiply_local
     924              : 
     925              : ! **************************************************************************************************
     926              : !> \brief multiply a dbcsr with a fm matrix
     927              : !>
     928              : !> For backwards compatibility with BLAS XGEMM, this routine supports
     929              : !> the multiplication of matrices with incompatible dimensions.
     930              : !>
     931              : !> \param[in]  matrix         DBCSR matrix
     932              : !> \param fm_in full matrix
     933              : !> \param fm_out full matrix
     934              : !> \param[in]  ncol           nbr of columns
     935              : !> \param[in]  alpha          alpha
     936              : !> \param[in]  beta           beta
     937              : !>
     938              : ! **************************************************************************************************
     939      3191070 :    SUBROUTINE cp_dbcsr_sm_fm_multiply(matrix, fm_in, fm_out, ncol, alpha, beta)
     940              :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix
     941              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_in
     942              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm_out
     943              :       INTEGER, INTENT(IN)                                :: ncol
     944              :       REAL(dp), INTENT(IN), OPTIONAL                     :: alpha, beta
     945              : 
     946              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'cp_dbcsr_sm_fm_multiply'
     947              : 
     948              :       INTEGER                                            :: a_ncol, a_nrow, b_ncol, b_nrow, c_ncol, &
     949              :                                                             c_nrow, k_in, k_out, timing_handle, &
     950              :                                                             timing_handle_mult
     951       531845 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size, col_blk_size_right_in, &
     952       531845 :                                                             col_blk_size_right_out, col_dist, &
     953       531845 :                                                             row_blk_size, row_dist
     954              :       TYPE(dbcsr_type)                                   :: in, out
     955              :       TYPE(dbcsr_distribution_type)                      :: dist, dist_right_in, product_dist
     956              :       REAL(dp)                                           :: my_alpha, my_beta
     957              : 
     958       531845 :       CALL timeset(routineN, timing_handle)
     959              : 
     960       531845 :       my_alpha = 1.0_dp
     961       531845 :       my_beta = 0.0_dp
     962       531845 :       IF (PRESENT(alpha)) my_alpha = alpha
     963       531845 :       IF (PRESENT(beta)) my_beta = beta
     964              : 
     965              :       ! TODO
     966       531845 :       CALL cp_fm_get_info(fm_in, ncol_global=b_ncol, nrow_global=b_nrow)
     967       531845 :       CALL cp_fm_get_info(fm_out, ncol_global=c_ncol, nrow_global=c_nrow)
     968       531845 :       CALL dbcsr_get_info(matrix, nfullrows_total=a_nrow, nfullcols_total=a_ncol)
     969              :       !WRITE(*,*) "cp_dbcsr_sm_fm_multiply: A ", a_nrow, "x", a_ncol
     970              :       !WRITE(*,*) "cp_dbcsr_sm_fm_multiply: B ", b_nrow, "x", b_ncol
     971              :       !WRITE(*,*) "cp_dbcsr_sm_fm_multiply: C ", c_nrow, "x", c_ncol
     972              : 
     973       531845 :       CALL cp_fm_get_info(fm_out, ncol_global=k_out)
     974              : 
     975       531845 :       CALL cp_fm_get_info(fm_in, ncol_global=k_in)
     976              :       !write(*,*)routineN//" -----------------------------------"
     977              :       !IF (k_in /= k_out) &
     978              :       !   WRITE(*,'(3(A,I5,1X),2(A,F5.2,1X))')&
     979              :       !   routineN//" ncol", ncol,'k_in',k_in,'k_out',k_out,&
     980              :       !   'alpha',my_alpha,'beta',my_beta
     981              : 
     982       531845 :       IF (ncol > 0 .AND. k_out > 0 .AND. k_in > 0) THEN
     983       530565 :          CALL dbcsr_get_info(matrix, row_blk_size=row_blk_size, col_blk_size=col_blk_size, distribution=dist)
     984       530565 :          CALL dbcsr_create_dist_r_unrot(dist_right_in, dist, k_in, col_blk_size_right_in)
     985              : 
     986              :          CALL dbcsr_create(in, "D", dist_right_in, dbcsr_type_no_symmetry, &
     987       530565 :                            col_blk_size, col_blk_size_right_in)
     988              : 
     989       530565 :          CALL dbcsr_distribution_get(dist, row_dist=row_dist)
     990       530565 :          CALL dbcsr_distribution_get(dist_right_in, col_dist=col_dist)
     991              :          CALL dbcsr_distribution_new(product_dist, template=dist, &
     992       530565 :                                      row_dist=row_dist, col_dist=col_dist)
     993      1591695 :          ALLOCATE (col_blk_size_right_out(SIZE(col_blk_size_right_in)))
     994      2159384 :          col_blk_size_right_out = col_blk_size_right_in
     995       530565 :          CALL match_col_sizes(col_blk_size_right_out, col_blk_size_right_in, k_out)
     996              : 
     997              :          !if (k_in .ne. k_out) then
     998              :          !   write(*,*)routineN//" in cs", col_blk_size_right_in
     999              :          !   write(*,*)routineN//" out cs", col_blk_size_right_out
    1000              :          !endif
    1001              : 
    1002              :          CALL dbcsr_create(out, "D", product_dist, dbcsr_type_no_symmetry, &
    1003       530565 :                            row_blk_size, col_blk_size_right_out)
    1004              : 
    1005       530565 :          CALL copy_fm_to_dbcsr(fm_in, in)
    1006       530565 :          IF (ncol /= k_out .OR. my_beta /= 0.0_dp) THEN
    1007       119154 :             CALL copy_fm_to_dbcsr(fm_out, out)
    1008              :          END IF
    1009              : 
    1010       530565 :          CALL timeset(routineN//'_core', timing_handle_mult)
    1011              :          CALL dbcsr_multiply("N", "N", my_alpha, matrix, in, my_beta, out, &
    1012       530565 :                              last_column=ncol)
    1013       530565 :          CALL timestop(timing_handle_mult)
    1014              : 
    1015       530565 :          CALL copy_dbcsr_to_fm(out, fm_out)
    1016              : 
    1017       530565 :          CALL dbcsr_release(in)
    1018       530565 :          CALL dbcsr_release(out)
    1019       530565 :          DEALLOCATE (col_blk_size_right_in, col_blk_size_right_out)
    1020       530565 :          CALL dbcsr_distribution_release(dist_right_in)
    1021      2122260 :          CALL dbcsr_distribution_release(product_dist)
    1022              : 
    1023              :       END IF
    1024              : 
    1025       531845 :       CALL timestop(timing_handle)
    1026              : 
    1027       531845 :    END SUBROUTINE cp_dbcsr_sm_fm_multiply
    1028              : 
    1029              : ! **************************************************************************************************
    1030              : !> \brief ...
    1031              : !> \param sizes1 ...
    1032              : !> \param sizes2 ...
    1033              : !> \param full_num ...
    1034              : ! **************************************************************************************************
    1035       530565 :    SUBROUTINE match_col_sizes(sizes1, sizes2, full_num)
    1036              :       INTEGER, DIMENSION(:), INTENT(INOUT)               :: sizes1
    1037              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: sizes2
    1038              :       INTEGER, INTENT(IN)                                :: full_num
    1039              : 
    1040              :       INTEGER                                            :: left, n1, n2, p, rm, used
    1041              : 
    1042       530565 :       n1 = SIZE(sizes1)
    1043       530565 :       n2 = SIZE(sizes2)
    1044       530565 :       IF (n1 /= n2) THEN
    1045            0 :          CPABORT("distributions must be equal!")
    1046              :       END IF
    1047      1079692 :       sizes1(1:n1) = sizes2(1:n1)
    1048      1079692 :       used = SUM(sizes1(1:n1))
    1049              :       ! If sizes1 does not cover everything, then we increase the
    1050              :       ! size of the last block; otherwise we reduce the blocks
    1051              :       ! (from the end) until it is small enough.
    1052       530565 :       IF (used < full_num) THEN
    1053            0 :          sizes1(n1) = sizes1(n1) + full_num - used
    1054              :       ELSE
    1055       530565 :          left = used - full_num
    1056       530565 :          p = n1
    1057       530565 :          DO WHILE (left > 0 .AND. p > 0)
    1058            0 :             rm = MIN(left, sizes1(p))
    1059            0 :             sizes1(p) = sizes1(p) - rm
    1060            0 :             left = left - rm
    1061            0 :             p = p - 1
    1062              :          END DO
    1063              :       END IF
    1064       530565 :    END SUBROUTINE match_col_sizes
    1065              : 
    1066              : ! **************************************************************************************************
    1067              : !> \brief performs the multiplication sparse_matrix+dense_mat*dens_mat^T
    1068              : !>        if matrix_g is not explicitly given, matrix_v^T will be used
    1069              : !>        this can be important to save the necessary redistribute for a
    1070              : !>        different matrix_g and increase performance.
    1071              : !> \param sparse_matrix ...
    1072              : !> \param matrix_v ...
    1073              : !> \param matrix_g ...
    1074              : !> \param ncol ...
    1075              : !> \param alpha ...
    1076              : !> \param keep_sparsity Determines if the sparsity of sparse_matrix is retained
    1077              : !>        by default it is TRUE
    1078              : !> \param symmetry_mode There are the following modes
    1079              : !>        1:     sparse_matrix += 0.5*alpha*(v*g^T+g^T*v)    (symmetric update)
    1080              : !>        -1:    sparse_matrix += 0.5*alpha*(v*g^T-g^T*v)    (skewsymmetric update)
    1081              : !>        else:  sparse_matrix += alpha*v*g^T                (no symmetry, default)
    1082              : !>        saves some redistribution steps
    1083              : ! **************************************************************************************************
    1084       265034 :    SUBROUTINE cp_dbcsr_plus_fm_fm_t(sparse_matrix, matrix_v, matrix_g, ncol, alpha, keep_sparsity, symmetry_mode)
    1085              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: sparse_matrix
    1086              :       TYPE(cp_fm_type), INTENT(IN)                       :: matrix_v
    1087              :       TYPE(cp_fm_type), INTENT(IN), OPTIONAL             :: matrix_g
    1088              :       INTEGER, INTENT(IN)                                :: ncol
    1089              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: alpha
    1090              :       LOGICAL, INTENT(IN), OPTIONAL                      :: keep_sparsity
    1091              :       INTEGER, INTENT(IN), OPTIONAL                      :: symmetry_mode
    1092              : 
    1093              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'cp_dbcsr_plus_fm_fm_t'
    1094              : 
    1095              :       INTEGER                                            :: k, my_symmetry_mode, nao, npcols, &
    1096              :                                                             timing_handle
    1097       265034 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size_left, col_dist_left, &
    1098       265034 :                                                             row_blk_size, row_dist
    1099              :       LOGICAL                                            :: check_product, my_keep_sparsity
    1100              :       REAL(KIND=dp)                                      :: my_alpha, norm
    1101              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
    1102              :       TYPE(cp_fm_type)                                   :: fm_matrix
    1103              :       TYPE(dbcsr_distribution_type)                      :: dist_left, sparse_dist
    1104              :       TYPE(dbcsr_type)                                   :: mat_g, mat_v, sparse_matrix2, &
    1105              :                                                             sparse_matrix3
    1106              : 
    1107       265034 :       check_product = .FALSE.
    1108              : 
    1109       265034 :       CALL timeset(routineN, timing_handle)
    1110              : 
    1111       265034 :       my_keep_sparsity = .TRUE.
    1112       265034 :       IF (PRESENT(keep_sparsity)) my_keep_sparsity = keep_sparsity
    1113              : 
    1114       265034 :       my_symmetry_mode = 0
    1115       265034 :       IF (PRESENT(symmetry_mode)) my_symmetry_mode = symmetry_mode
    1116              : 
    1117       265034 :       NULLIFY (col_dist_left)
    1118              : 
    1119       265034 :       IF (ncol > 0) THEN
    1120       263044 :          IF (.NOT. dbcsr_valid_index(sparse_matrix)) THEN
    1121            0 :             CPABORT("sparse_matrix must pre-exist")
    1122              :          END IF
    1123              :          !
    1124              :          ! Setup matrix_v
    1125       263044 :          CALL cp_fm_get_info(matrix_v, ncol_global=k)
    1126              :          !WRITE(*,*)routineN//'truncated mult k, ncol',k,ncol,' PRESENT (matrix_g)',PRESENT (matrix_g)
    1127       263044 :          CALL dbcsr_get_info(sparse_matrix, distribution=sparse_dist)
    1128       263044 :          CALL dbcsr_distribution_get(sparse_dist, npcols=npcols, row_dist=row_dist)
    1129       263044 :          CALL create_bl_distribution(col_dist_left, col_blk_size_left, k, npcols)
    1130              :          CALL dbcsr_distribution_new(dist_left, template=sparse_dist, &
    1131       263044 :                                      row_dist=row_dist, col_dist=col_dist_left)
    1132       263044 :          DEALLOCATE (col_dist_left)
    1133       263044 :          CALL dbcsr_get_info(sparse_matrix, row_blk_size=row_blk_size)
    1134              :          CALL dbcsr_create(mat_v, "DBCSR matrix_v", dist_left, dbcsr_type_no_symmetry, &
    1135       263044 :                            row_blk_size, col_blk_size_left)
    1136       263044 :          CALL copy_fm_to_dbcsr(matrix_v, mat_v)
    1137       263044 :          CALL dbcsr_verify_matrix(mat_v)
    1138              :          !
    1139              :          ! Setup matrix_g
    1140       263044 :          IF (PRESENT(matrix_g)) THEN
    1141              :             CALL dbcsr_create(mat_g, "DBCSR matrix_g", dist_left, dbcsr_type_no_symmetry, &
    1142       128331 :                               row_blk_size, col_blk_size_left)
    1143       128331 :             CALL copy_fm_to_dbcsr(matrix_g, mat_g)
    1144              :          END IF
    1145              :          !
    1146       263044 :          DEALLOCATE (col_blk_size_left)
    1147       263044 :          CALL dbcsr_distribution_release(dist_left)
    1148              :          !
    1149              :          !
    1150              :          IF (check_product) THEN
    1151              :             CALL cp_fm_get_info(matrix_v, nrow_global=nao)
    1152              :             CALL cp_fm_struct_create(fm_struct_tmp, context=matrix_v%matrix_struct%context, nrow_global=nao, &
    1153              :                                      ncol_global=nao, para_env=matrix_v%matrix_struct%para_env)
    1154              :             CALL cp_fm_create(fm_matrix, fm_struct_tmp, name="fm matrix")
    1155              :             CALL cp_fm_struct_release(fm_struct_tmp)
    1156              :             CALL copy_dbcsr_to_fm(sparse_matrix, fm_matrix)
    1157              :             CALL dbcsr_copy(sparse_matrix3, sparse_matrix)
    1158              :          END IF
    1159              :          !
    1160       263044 :          my_alpha = 1.0_dp
    1161       263044 :          IF (PRESENT(alpha)) my_alpha = alpha
    1162       263044 :          IF (PRESENT(matrix_g)) THEN
    1163       128331 :             IF (my_symmetry_mode == 1) THEN
    1164              :                ! Symmetric mode
    1165              :                CALL dbcsr_multiply("N", "T", 0.5_dp*my_alpha, mat_v, mat_g, &
    1166              :                                    1.0_dp, sparse_matrix, &
    1167              :                                    retain_sparsity=my_keep_sparsity, &
    1168        43940 :                                    last_k=ncol)
    1169              :                CALL dbcsr_multiply("N", "T", 0.5_dp*my_alpha, mat_g, mat_v, &
    1170              :                                    1.0_dp, sparse_matrix, &
    1171              :                                    retain_sparsity=my_keep_sparsity, &
    1172        43940 :                                    last_k=ncol)
    1173        84391 :             ELSE IF (my_symmetry_mode == -1) THEN
    1174              :                ! Skewsymmetric mode
    1175              :                CALL dbcsr_multiply("N", "T", 0.5_dp*my_alpha, mat_v, mat_g, &
    1176              :                                    1.0_dp, sparse_matrix, &
    1177              :                                    retain_sparsity=my_keep_sparsity, &
    1178         2588 :                                    last_k=ncol)
    1179              :                CALL dbcsr_multiply("N", "T", -0.5_dp*my_alpha, mat_g, mat_v, &
    1180              :                                    1.0_dp, sparse_matrix, &
    1181              :                                    retain_sparsity=my_keep_sparsity, &
    1182         2588 :                                    last_k=ncol)
    1183              :             ELSE
    1184              :                ! Normal mode
    1185              :                CALL dbcsr_multiply("N", "T", my_alpha, mat_v, mat_g, &
    1186              :                                    1.0_dp, sparse_matrix, &
    1187              :                                    retain_sparsity=my_keep_sparsity, &
    1188        81803 :                                    last_k=ncol)
    1189              :             END IF
    1190              :          ELSE
    1191              :             CALL dbcsr_multiply("N", "T", my_alpha, mat_v, mat_v, &
    1192              :                                 1.0_dp, sparse_matrix, &
    1193              :                                 retain_sparsity=my_keep_sparsity, &
    1194       134713 :                                 last_k=ncol)
    1195              :          END IF
    1196              : 
    1197              :          IF (check_product) THEN
    1198              :             IF (PRESENT(matrix_g)) THEN
    1199              :                IF (my_symmetry_mode == 1) THEN
    1200              :                   CALL cp_fm_gemm("N", "T", nao, nao, ncol, 0.5_dp*my_alpha, matrix_v, matrix_g, &
    1201              :                                   1.0_dp, fm_matrix)
    1202              :                   CALL cp_fm_gemm("N", "T", nao, nao, ncol, 0.5_dp*my_alpha, matrix_g, matrix_v, &
    1203              :                                   1.0_dp, fm_matrix)
    1204              :                ELSE IF (my_symmetry_mode == -1) THEN
    1205              :                   CALL cp_fm_gemm("N", "T", nao, nao, ncol, 0.5_dp*my_alpha, matrix_v, matrix_g, &
    1206              :                                   1.0_dp, fm_matrix)
    1207              :                   CALL cp_fm_gemm("N", "T", nao, nao, ncol, -0.5_dp*my_alpha, matrix_g, matrix_v, &
    1208              :                                   1.0_dp, fm_matrix)
    1209              :                ELSE
    1210              :                   CALL cp_fm_gemm("N", "T", nao, nao, ncol, my_alpha, matrix_v, matrix_g, &
    1211              :                                   1.0_dp, fm_matrix)
    1212              :                END IF
    1213              :             ELSE
    1214              :                CALL cp_fm_gemm("N", "T", nao, nao, ncol, my_alpha, matrix_v, matrix_v, &
    1215              :                                1.0_dp, fm_matrix)
    1216              :             END IF
    1217              : 
    1218              :             CALL dbcsr_copy(sparse_matrix2, sparse_matrix)
    1219              :             CALL dbcsr_scale(sparse_matrix2, alpha_scalar=0.0_dp)
    1220              :             CALL copy_fm_to_dbcsr(fm_matrix, sparse_matrix2, keep_sparsity=my_keep_sparsity)
    1221              :             CALL dbcsr_add(sparse_matrix2, sparse_matrix, alpha_scalar=1.0_dp, &
    1222              :                            beta_scalar=-1.0_dp)
    1223              :             norm = dbcsr_frobenius_norm(sparse_matrix2)
    1224              :             WRITE (*, *) 'nao=', nao, ' k=', k, ' ncol=', ncol, ' my_alpha=', my_alpha
    1225              :             WRITE (*, *) 'PRESENT (matrix_g)', PRESENT(matrix_g)
    1226              :             WRITE (*, *) 'matrix_type=', dbcsr_get_matrix_type(sparse_matrix)
    1227              :             WRITE (*, *) 'norm(sm+alpha*v*g^t - fm+alpha*v*g^t)/n=', norm/REAL(nao, dp)
    1228              :             CALL dbcsr_release(sparse_matrix2)
    1229              :             CALL dbcsr_release(sparse_matrix3)
    1230              :             CALL cp_fm_release(fm_matrix)
    1231              :          END IF
    1232       263044 :          CALL dbcsr_release(mat_v)
    1233       263044 :          IF (PRESENT(matrix_g)) CALL dbcsr_release(mat_g)
    1234              :       END IF
    1235       265034 :       CALL timestop(timing_handle)
    1236              : 
    1237       265034 :    END SUBROUTINE cp_dbcsr_plus_fm_fm_t
    1238              : 
    1239              : ! **************************************************************************************************
    1240              : !> \brief Utility function to copy a specially shaped fm to dbcsr_matrix
    1241              : !>        The result matrix will be the matrix in dbcsr format
    1242              : !>        with the row blocks sizes according to the block_sizes of the template
    1243              : !>        and the col blocks sizes evenly blocked with the internal dbcsr conversion
    1244              : !>        size (32 is the current default)
    1245              : !> \param matrix ...
    1246              : !> \param fm_in ...
    1247              : !> \param template ...
    1248              : ! **************************************************************************************************
    1249        17169 :    SUBROUTINE cp_fm_to_dbcsr_row_template(matrix, fm_in, template)
    1250              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix
    1251              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_in
    1252              :       TYPE(dbcsr_type), INTENT(IN)                       :: template
    1253              : 
    1254              :       INTEGER                                            :: k_in
    1255         5723 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size_right_in, row_blk_size
    1256              :       TYPE(dbcsr_distribution_type)                      :: dist_right_in, tmpl_dist
    1257              : 
    1258         5723 :       CALL cp_fm_get_info(fm_in, ncol_global=k_in)
    1259              : 
    1260         5723 :       CALL dbcsr_get_info(template, distribution=tmpl_dist)
    1261         5723 :       CALL dbcsr_create_dist_r_unrot(dist_right_in, tmpl_dist, k_in, col_blk_size_right_in)
    1262         5723 :       CALL dbcsr_get_info(template, row_blk_size=row_blk_size)
    1263              :       CALL dbcsr_create(matrix, "D", dist_right_in, dbcsr_type_no_symmetry, &
    1264         5723 :                         row_blk_size, col_blk_size_right_in)
    1265              : 
    1266         5723 :       CALL copy_fm_to_dbcsr(fm_in, matrix)
    1267         5723 :       DEALLOCATE (col_blk_size_right_in)
    1268         5723 :       CALL dbcsr_distribution_release(dist_right_in)
    1269              : 
    1270         5723 :    END SUBROUTINE cp_fm_to_dbcsr_row_template
    1271              : 
    1272              : ! **************************************************************************************************
    1273              : !> \brief Utility function to create an arbitrary shaped dbcsr matrix
    1274              : !>        with the same processor grid as the template matrix
    1275              : !>        both row sizes and col sizes are evenly blocked with the internal
    1276              : !>        dbcsr_conversion size (32 is the current default)
    1277              : !> \param matrix dbcsr matrix to be created
    1278              : !> \param template template dbcsr matrix giving its mp_env
    1279              : !> \param m global row size of output matrix
    1280              : !> \param n global col size of output matrix
    1281              : !> \param sym ...
    1282              : ! **************************************************************************************************
    1283       354656 :    SUBROUTINE cp_dbcsr_m_by_n_from_template(matrix, template, m, n, sym)
    1284              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix, template
    1285              :       INTEGER, INTENT(IN)                                :: m, n
    1286              :       CHARACTER, INTENT(IN), OPTIONAL                    :: sym
    1287              : 
    1288              :       CHARACTER                                          :: mysym
    1289              :       INTEGER                                            :: npcols, nprows
    1290       177328 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size, col_dist, row_blk_size, &
    1291       177328 :                                                             row_dist
    1292              :       TYPE(dbcsr_distribution_type)                      :: dist_m_n, tmpl_dist
    1293              : 
    1294       177328 :       CALL dbcsr_get_info(template, matrix_type=mysym, distribution=tmpl_dist)
    1295              : 
    1296       177328 :       IF (PRESENT(sym)) mysym = sym
    1297              : 
    1298       177328 :       NULLIFY (row_dist, col_dist)
    1299       177328 :       NULLIFY (row_blk_size, col_blk_size)
    1300              :       !NULLIFY (row_cluster, col_cluster)
    1301              : 
    1302       177328 :       CALL dbcsr_distribution_get(tmpl_dist, nprows=nprows, npcols=npcols)
    1303       177328 :       CALL create_bl_distribution(row_dist, row_blk_size, m, nprows)
    1304       177328 :       CALL create_bl_distribution(col_dist, col_blk_size, n, npcols)
    1305              :       CALL dbcsr_distribution_new(dist_m_n, template=tmpl_dist, &
    1306              :                                   row_dist=row_dist, col_dist=col_dist, &
    1307              :                                   !row_cluster=row_cluster, col_cluster=col_cluster, &
    1308       177328 :                                   reuse_arrays=.TRUE.)
    1309              : 
    1310              :       CALL dbcsr_create(matrix, "m_n_template", dist_m_n, mysym, &
    1311       177328 :                         row_blk_size, col_blk_size, reuse_arrays=.TRUE.)
    1312       177328 :       CALL dbcsr_distribution_release(dist_m_n)
    1313              : 
    1314       177328 :    END SUBROUTINE cp_dbcsr_m_by_n_from_template
    1315              : 
    1316              : ! **************************************************************************************************
    1317              : !> \brief Utility function to create dbcsr matrix, m x n matrix (n arbitrary)
    1318              : !>        with the same processor grid and row distribution  as the template matrix
    1319              : !>        col sizes are evenly blocked with the internal
    1320              : !>        dbcsr_conversion size (32 is the current default)
    1321              : !> \param matrix dbcsr matrix to be created
    1322              : !> \param template template dbcsr matrix giving its mp_env
    1323              : !> \param n global col size of output matrix
    1324              : !> \param sym ...
    1325              : ! **************************************************************************************************
    1326       703648 :    SUBROUTINE cp_dbcsr_m_by_n_from_row_template(matrix, template, n, sym)
    1327              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix, template
    1328              :       INTEGER                                            :: n
    1329              :       CHARACTER, OPTIONAL                                :: sym
    1330              : 
    1331              :       CHARACTER                                          :: mysym
    1332              :       INTEGER                                            :: npcols
    1333       175912 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size, col_dist, row_blk_size, &
    1334       175912 :                                                             row_dist
    1335              :       TYPE(dbcsr_distribution_type)                      :: dist_m_n, tmpl_dist
    1336              : 
    1337       351824 :       mysym = dbcsr_get_matrix_type(template)
    1338       175912 :       IF (PRESENT(sym)) mysym = sym
    1339              : 
    1340       175912 :       CALL dbcsr_get_info(template, distribution=tmpl_dist)
    1341              :       CALL dbcsr_distribution_get(tmpl_dist, &
    1342              :                                   npcols=npcols, &
    1343       175912 :                                   row_dist=row_dist)
    1344              : 
    1345       175912 :       NULLIFY (col_dist, col_blk_size)
    1346       175912 :       CALL create_bl_distribution(col_dist, col_blk_size, n, npcols)
    1347              :       CALL dbcsr_distribution_new(dist_m_n, template=tmpl_dist, &
    1348       175912 :                                   row_dist=row_dist, col_dist=col_dist)
    1349              : 
    1350       175912 :       CALL dbcsr_get_info(template, row_blk_size=row_blk_size)
    1351       175912 :       CALL dbcsr_create(matrix, "m_n_template", dist_m_n, mysym, row_blk_size, col_blk_size)
    1352              : 
    1353       175912 :       DEALLOCATE (col_dist, col_blk_size)
    1354       175912 :       CALL dbcsr_distribution_release(dist_m_n)
    1355              : 
    1356       175912 :    END SUBROUTINE cp_dbcsr_m_by_n_from_row_template
    1357              : 
    1358              : ! **************************************************************************************************
    1359              : !> \brief Distributes elements into blocks and into bins
    1360              : !>
    1361              : !> \param[out] block_distribution       block distribution to bins
    1362              : !> \param[out] block_size       sizes of blocks
    1363              : !> \param[in] nelements number of elements to bin
    1364              : !> \param[in] nbins             number of bins
    1365              : !> \par Term clarification
    1366              : !>      An example: blocks are atom blocks and bins are process rows/columns.
    1367              : ! **************************************************************************************************
    1368      1329900 :    SUBROUTINE create_bl_distribution(block_distribution, &
    1369              :                                      block_size, nelements, nbins)
    1370              :       INTEGER, DIMENSION(:), INTENT(OUT), POINTER        :: block_distribution, block_size
    1371              :       INTEGER, INTENT(IN)                                :: nelements, nbins
    1372              : 
    1373              :       CHARACTER(len=*), PARAMETER :: routineN = 'create_bl_distribution', &
    1374              :          routineP = moduleN//':'//routineN
    1375              : 
    1376              :       INTEGER                                            :: bin, blk_layer, element_stack, els, &
    1377              :                                                             estimated_blocks, max_blocks_per_bin, &
    1378              :                                                             nblks, nblocks, stat
    1379      1329900 :       INTEGER, DIMENSION(:), POINTER                     :: blk_dist, blk_sizes
    1380              : 
    1381              : !   ---------------------------------------------------------------------------
    1382              : 
    1383      1329900 :       NULLIFY (block_distribution)
    1384      1329900 :       NULLIFY (block_size)
    1385              :       ! Define the sizes on which we build the distribution.
    1386      1329900 :       IF (nelements > 0) THEN
    1387              : 
    1388      1314502 :          nblocks = CEILING(REAL(nelements, KIND=dp)/REAL(max_elements_per_block, KIND=dp))
    1389      1314502 :          max_blocks_per_bin = CEILING(REAL(nblocks, KIND=dp)/REAL(nbins, KIND=dp))
    1390              : 
    1391              :          IF (debug_mod) THEN
    1392              :             WRITE (*, '(1X,A,1X,A,I7,A,I7,A)') routineP, "For", nelements, &
    1393              :                " elements and", nbins, " bins"
    1394              :             WRITE (*, '(1X,A,1X,A,I7,A)') routineP, "There are", &
    1395              :                max_elements_per_block, " max elements per block"
    1396              :             WRITE (*, '(1X,A,1X,A,I7,A)') routineP, "There are", &
    1397              :                nblocks, " blocks"
    1398              :             WRITE (*, '(1X,A,1X,A,I7,A)') routineP, "There are", &
    1399              :                max_blocks_per_bin, " max blocks/bin"
    1400              :          END IF
    1401              : 
    1402      1314502 :          estimated_blocks = max_blocks_per_bin*nbins
    1403      3943506 :          ALLOCATE (blk_dist(estimated_blocks), stat=stat)
    1404      1314502 :          IF (stat /= 0) THEN
    1405            0 :             CPABORT("blk_dist")
    1406              :          END IF
    1407      2629004 :          ALLOCATE (blk_sizes(estimated_blocks), stat=stat)
    1408              :          IF (stat /= 0) THEN
    1409            0 :             CPABORT("blk_sizes")
    1410              :          END IF
    1411      1314502 :          element_stack = 0
    1412      1314502 :          nblks = 0
    1413      2706620 :          DO blk_layer = 1, max_blocks_per_bin
    1414      4246490 :             DO bin = 0, nbins - 1
    1415      1539870 :                els = MIN(max_elements_per_block, nelements - element_stack)
    1416      2931988 :                IF (els > 0) THEN
    1417      1403042 :                   element_stack = element_stack + els
    1418      1403042 :                   nblks = nblks + 1
    1419      1403042 :                   blk_dist(nblks) = bin
    1420      1403042 :                   blk_sizes(nblks) = els
    1421              :                   IF (debug_mod) WRITE (*, '(1X,A,I5,A,I5,A,I5)') routineP//" Assigning", &
    1422              :                      els, " elements as block", nblks, " to bin", bin
    1423              :                END IF
    1424              :             END DO
    1425              :          END DO
    1426              :          ! Create the output arrays.
    1427      1314502 :          IF (nblks == estimated_blocks) THEN
    1428      1177674 :             block_distribution => blk_dist
    1429      1177674 :             block_size => blk_sizes
    1430              :          ELSE
    1431       410484 :             ALLOCATE (block_distribution(nblks), stat=stat)
    1432              :             IF (stat /= 0) THEN
    1433            0 :                CPABORT("blk_dist")
    1434              :             END IF
    1435       550864 :             block_distribution(:) = blk_dist(1:nblks)
    1436       136828 :             DEALLOCATE (blk_dist)
    1437       273656 :             ALLOCATE (block_size(nblks), stat=stat)
    1438              :             IF (stat /= 0) THEN
    1439            0 :                CPABORT("blk_sizes")
    1440              :             END IF
    1441       550864 :             block_size(:) = blk_sizes(1:nblks)
    1442       136828 :             DEALLOCATE (blk_sizes)
    1443              :          END IF
    1444              :       ELSE
    1445        15398 :          ALLOCATE (block_distribution(0), stat=stat)
    1446              :          IF (stat /= 0) THEN
    1447            0 :             CPABORT("blk_dist")
    1448              :          END IF
    1449        15398 :          ALLOCATE (block_size(0), stat=stat)
    1450              :          IF (stat /= 0) THEN
    1451            0 :             CPABORT("blk_sizes")
    1452              :          END IF
    1453              :       END IF
    1454              : 1579  FORMAT(I5, 1X, I5, 1X, I5, 1X, I5, 1X, I5, 1X, I5, 1X, I5, 1X, I5, 1X, I5, 1X, I5)
    1455              :       IF (debug_mod) THEN
    1456              :          WRITE (*, '(1X,A,A)') routineP//" Distribution"
    1457              :          WRITE (*, 1579) block_distribution(:)
    1458              :          WRITE (*, '(1X,A,A)') routineP//" Sizes"
    1459              :          WRITE (*, 1579) block_size(:)
    1460              :       END IF
    1461      1329900 :    END SUBROUTINE create_bl_distribution
    1462              : 
    1463              : ! **************************************************************************************************
    1464              : !> \brief Creates a new distribution for the right matrix in a matrix
    1465              : !>        multiplication with unrotated grid.
    1466              : !> \param[out] dist_right     new distribution for the right matrix
    1467              : !> \param[in] dist_left       the distribution of the left matrix
    1468              : !> \param[in] ncolumns        number of columns in right matrix
    1469              : !> \param[out] right_col_blk_sizes      sizes of blocks in the created column
    1470              : !> \par The new row distribution for the right matrix is the same as the row
    1471              : !>      distribution of the left matrix, while the column distribution is
    1472              : !>      created so that it is appropriate to the parallel environment.
    1473              : ! **************************************************************************************************
    1474       536288 :    SUBROUTINE dbcsr_create_dist_r_unrot(dist_right, dist_left, ncolumns, &
    1475              :                                         right_col_blk_sizes)
    1476              :       TYPE(dbcsr_distribution_type), INTENT(OUT)         :: dist_right
    1477              :       TYPE(dbcsr_distribution_type), INTENT(IN)          :: dist_left
    1478              :       INTEGER, INTENT(IN)                                :: ncolumns
    1479              :       INTEGER, DIMENSION(:), INTENT(OUT), POINTER        :: right_col_blk_sizes
    1480              : 
    1481              :       INTEGER                                            :: multiplicity, ncols, nimages, npcols, &
    1482              :                                                             nprows
    1483              :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: tmp_images
    1484       536288 :       INTEGER, DIMENSION(:), POINTER                     :: old_col_dist, right_col_dist, &
    1485       536288 :                                                             right_row_dist
    1486              : 
    1487              :       CALL dbcsr_distribution_get(dist_left, &
    1488              :                                   ncols=ncols, &
    1489              :                                   col_dist=old_col_dist, &
    1490              :                                   nprows=nprows, &
    1491       536288 :                                   npcols=npcols)
    1492              : 
    1493              :       ! Create the column distribution
    1494       536288 :       CALL create_bl_distribution(right_col_dist, right_col_blk_sizes, ncolumns, npcols)
    1495              :       ! Create an even row distribution.
    1496      2145152 :       ALLOCATE (right_row_dist(ncols), tmp_images(ncols))
    1497       536288 :       nimages = lcm(nprows, npcols)/nprows
    1498       536288 :       multiplicity = nprows/gcd(nprows, npcols)
    1499       536288 :       CALL rebin_distribution(right_row_dist, tmp_images, old_col_dist, nprows, multiplicity, nimages)
    1500              : 
    1501              :       CALL dbcsr_distribution_new(dist_right, &
    1502              :                                   template=dist_left, &
    1503              :                                   row_dist=right_row_dist, &
    1504              :                                   col_dist=right_col_dist, &
    1505              :                                   !row_cluster=dummy,&
    1506              :                                   !col_cluster=dummy,&
    1507       536288 :                                   reuse_arrays=.TRUE.)
    1508       536288 :       DEALLOCATE (tmp_images)
    1509       536288 :    END SUBROUTINE dbcsr_create_dist_r_unrot
    1510              : 
    1511              : ! **************************************************************************************************
    1512              : !> \brief Makes new distribution with decimation and multiplicity
    1513              : !> \param[out] new_bins      new real distribution
    1514              : !> \param[out] images        new image distribution
    1515              : !> \param[in] source_bins    Basis for the new distribution and images
    1516              : !> \param[in] nbins          number of bins in the new real distribution
    1517              : !> \param[in] multiplicity   multiplicity
    1518              : !> \param[in] nimages        number of images in the new distribution
    1519              : !> \par Definition of multiplicity and nimages
    1520              : !>      Multiplicity and decimation (number of images) are used to
    1521              : !>      match process grid coordinates on non-square process
    1522              : !>      grids. Given source_nbins and target_nbins, their relation is
    1523              : !>                source_nbins * target_multiplicity
    1524              : !>              = target_nbins * target_nimages.
    1525              : !>      It is best when both multiplicity and nimages are small. To
    1526              : !>      get these two factors, then, one can use the following formulas:
    1527              : !>          nimages      = lcm(source_nbins, target_nbins) / target_nbins
    1528              : !>          multiplicity = target_nbins / gcd(source_nbins, target_nbins)
    1529              : !>      from the target's point of view (nimages = target_nimages).
    1530              : !> \par Mapping
    1531              : !>      The new distribution comprises of real bins and images within
    1532              : !>      bins. These can be view as target_nbins*nimages virtual
    1533              : !>      columns. These same virtual columns are also
    1534              : !>      source_nbins*multiplicity in number. Therefore these virtual
    1535              : !>      columns are mapped from source_nbins*multiplicity onto
    1536              : !>      target_bins*nimages (each target bin has nimages images):
    1537              : !>      Source 4: |1 2 3|4 5 6|7 8 9|A B C| (4*3)
    1538              : !>      Target 6: |1 2|3 4|5 6|7 8|9 A|B C| (6*2)
    1539              : !>      multiplicity=3, nimages=2, 12 virtual columns (1-C).
    1540              : !>      Source bin elements are evenly mapped into one of multiplicity
    1541              : !>      virtual columns. Other (non-even, block-size aware) mappings
    1542              : !>      could be better.
    1543              : ! **************************************************************************************************
    1544       536288 :    SUBROUTINE rebin_distribution(new_bins, images, source_bins, &
    1545              :                                  nbins, multiplicity, nimages)
    1546              :       INTEGER, DIMENSION(:), INTENT(OUT)                 :: new_bins, images
    1547              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: source_bins
    1548              :       INTEGER, INTENT(IN)                                :: nbins, multiplicity, nimages
    1549              : 
    1550              :       INTEGER                                            :: bin, i, old_nbins, virtual_bin
    1551       536288 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: bin_multiplier
    1552              : 
    1553              : !   ---------------------------------------------------------------------------
    1554              : 
    1555       536288 :       IF (MOD(nbins*nimages, multiplicity) /= 0) THEN
    1556            0 :          CPWARN("mulitplicity is not divisor of new process grid coordinate")
    1557              :       END IF
    1558       536288 :       old_nbins = (nbins*nimages)/multiplicity
    1559      1608864 :       ALLOCATE (bin_multiplier(0:old_nbins - 1))
    1560       536288 :       bin_multiplier(:) = 0
    1561      2514177 :       DO i = 1, SIZE(new_bins)
    1562      1977889 :          IF (i <= SIZE(source_bins)) THEN
    1563      1977889 :             bin = source_bins(i)
    1564              :          ELSE
    1565              :             ! Fill remainder with a cyclic distribution
    1566            0 :             bin = MOD(i, old_nbins)
    1567              :          END IF
    1568      1977889 :          virtual_bin = bin*multiplicity + bin_multiplier(bin)
    1569      1977889 :          new_bins(i) = virtual_bin/nimages
    1570      1977889 :          images(i) = 1 + MOD(virtual_bin, nimages)
    1571      1977889 :          bin_multiplier(bin) = bin_multiplier(bin) + 1
    1572      2514177 :          IF (bin_multiplier(bin) >= multiplicity) THEN
    1573       841139 :             bin_multiplier(bin) = 0
    1574              :          END IF
    1575              :       END DO
    1576       536288 :    END SUBROUTINE rebin_distribution
    1577              : 
    1578              : ! **************************************************************************************************
    1579              : !> \brief Creates a block-cyclic compatible distribution
    1580              : !>
    1581              : !>        All blocks in a dimension, except for possibly the last
    1582              : !>        block, have the same size.
    1583              : !> \param[out] dist           the elemental distribution
    1584              : !> \param[in] nrows           number of full rows
    1585              : !> \param[in] ncolumns        number of full columns
    1586              : !> \param[in] nrow_block      size of row blocks
    1587              : !> \param[in] ncol_block      size of column blocks
    1588              : !> \param group_handle ...
    1589              : !> \param pgrid ...
    1590              : !> \param[out] row_blk_sizes  row block sizes
    1591              : !> \param[out] col_blk_sizes  column block sizes
    1592              : ! **************************************************************************************************
    1593      2177315 :    SUBROUTINE dbcsr_create_dist_block_cyclic(dist, nrows, ncolumns, &
    1594              :                                              nrow_block, ncol_block, group_handle, pgrid, row_blk_sizes, col_blk_sizes)
    1595              :       TYPE(dbcsr_distribution_type), INTENT(OUT)         :: dist
    1596              :       INTEGER, INTENT(IN)                                :: nrows, ncolumns, nrow_block, ncol_block, &
    1597              :                                                             group_handle
    1598              :       INTEGER, DIMENSION(:, :), POINTER                  :: pgrid
    1599              :       INTEGER, DIMENSION(:), INTENT(OUT), POINTER        :: row_blk_sizes, col_blk_sizes
    1600              : 
    1601              :       CHARACTER(len=*), PARAMETER :: routineN = 'dbcsr_create_dist_block_cyclic'
    1602              : 
    1603              :       INTEGER                                            :: nblkcols, nblkrows, npcols, nprows, &
    1604              :                                                             pdim, sz
    1605      2177315 :       INTEGER, DIMENSION(:), POINTER                     :: cd_data, rd_data
    1606              : 
    1607              :       ! Row sizes
    1608      2177315 :       IF (nrow_block == 0) THEN
    1609              :          nblkrows = 0
    1610              :          sz = 0
    1611              :       ELSE
    1612      2177315 :          nblkrows = nrows/nrow_block
    1613      2177315 :          sz = MOD(nrows, nrow_block)
    1614              :       END IF
    1615      2177315 :       IF (sz > 0) nblkrows = nblkrows + 1
    1616      8706764 :       ALLOCATE (row_blk_sizes(nblkrows), rd_data(nblkrows))
    1617      8550210 :       row_blk_sizes = nrow_block
    1618      2177315 :       IF (sz /= 0) row_blk_sizes(nblkrows) = sz
    1619              : 
    1620              :       ! Column sizes
    1621      2177315 :       IF (ncol_block == 0) THEN
    1622              :          nblkcols = 0
    1623              :          sz = 0
    1624              :       ELSE
    1625      2177315 :          nblkcols = ncolumns/ncol_block
    1626      2177315 :          sz = MOD(ncolumns, ncol_block)
    1627              :       END IF
    1628      2177315 :       IF (sz > 0) nblkcols = nblkcols + 1
    1629      8702028 :       ALLOCATE (col_blk_sizes(nblkcols), cd_data(nblkcols))
    1630      6213096 :       col_blk_sizes = ncol_block
    1631      2177315 :       IF (sz /= 0) col_blk_sizes(nblkcols) = sz
    1632              :       !
    1633              :       IF (debug_mod) THEN
    1634              :          WRITE (*, *) routineN//" nrows,nrow_block,nblkrows=", &
    1635              :             nrows, nrow_block, nblkrows
    1636              :          WRITE (*, *) routineN//" ncols,ncol_block,nblkcols=", &
    1637              :             ncolumns, ncol_block, nblkcols
    1638              :       END IF
    1639              :       ! Calculate process row distribution
    1640      2177315 :       nprows = SIZE(pgrid, 1)
    1641      6447266 :       DO pdim = 0, MIN(nprows - 1, nblkrows - 1)
    1642     12820161 :          rd_data(1 + pdim:nblkrows:nprows) = pdim
    1643              :       END DO
    1644              :       ! Calculate process column distribution
    1645      2177315 :       npcols = SIZE(pgrid, 2)
    1646      4351014 :       DO pdim = 0, MIN(npcols - 1, nblkcols - 1)
    1647      8386795 :          cd_data(1 + pdim:nblkcols:npcols) = pdim
    1648              :       END DO
    1649              :       !
    1650              :       IF (debug_mod) THEN
    1651              :          WRITE (*, *) routineN//" row_dist", &
    1652              :             rd_data
    1653              :          WRITE (*, *) routineN//" col_dist", &
    1654              :             cd_data
    1655              :       END IF
    1656              :       !
    1657              :       CALL dbcsr_distribution_new(dist, &
    1658              :                                   group=group_handle, pgrid=pgrid, &
    1659              :                                   row_dist=rd_data, &
    1660              :                                   col_dist=cd_data, &
    1661      2177315 :                                   reuse_arrays=.TRUE.)
    1662              : 
    1663      2177315 :    END SUBROUTINE dbcsr_create_dist_block_cyclic
    1664              : 
    1665              : ! **************************************************************************************************
    1666              : !> \brief   Allocate and initialize a real matrix 1-dimensional set.
    1667              : !> \param[in,out] matrix_set  Set containing the DBCSR matrices
    1668              : !> \param[in] nmatrix         Size of set
    1669              : !> \par History
    1670              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1671              : ! **************************************************************************************************
    1672       205215 :    SUBROUTINE allocate_dbcsr_matrix_set_1d(matrix_set, nmatrix)
    1673              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_set
    1674              :       INTEGER, INTENT(IN)                                :: nmatrix
    1675              : 
    1676              :       INTEGER                                            :: imatrix
    1677              : 
    1678       205215 :       IF (ASSOCIATED(matrix_set)) CALL dbcsr_deallocate_matrix_set(matrix_set)
    1679      1421112 :       ALLOCATE (matrix_set(nmatrix))
    1680      1010682 :       DO imatrix = 1, nmatrix
    1681      1010682 :          NULLIFY (matrix_set(imatrix)%matrix)
    1682              :       END DO
    1683       205215 :    END SUBROUTINE allocate_dbcsr_matrix_set_1d
    1684              : 
    1685              : ! **************************************************************************************************
    1686              : !> \brief   Allocate and initialize a real matrix 2-dimensional set.
    1687              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1688              : !> \param[in] nmatrix         Size of set
    1689              : !> \param mmatrix ...
    1690              : !> \par History
    1691              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1692              : ! **************************************************************************************************
    1693       199954 :    SUBROUTINE allocate_dbcsr_matrix_set_2d(matrix_set, nmatrix, mmatrix)
    1694              :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_set
    1695              :       INTEGER, INTENT(IN)                                :: nmatrix, mmatrix
    1696              : 
    1697              :       INTEGER                                            :: imatrix, jmatrix
    1698              : 
    1699       199954 :       IF (ASSOCIATED(matrix_set)) CALL dbcsr_deallocate_matrix_set(matrix_set)
    1700      5714454 :       ALLOCATE (matrix_set(nmatrix, mmatrix))
    1701      2500336 :       DO jmatrix = 1, mmatrix
    1702      5114592 :          DO imatrix = 1, nmatrix
    1703      4914638 :             NULLIFY (matrix_set(imatrix, jmatrix)%matrix)
    1704              :          END DO
    1705              :       END DO
    1706       199954 :    END SUBROUTINE allocate_dbcsr_matrix_set_2d
    1707              : 
    1708              : ! **************************************************************************************************
    1709              : !> \brief   Allocate and initialize a real matrix 3-dimensional set.
    1710              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1711              : !> \param[in] nmatrix         Size of set
    1712              : !> \param mmatrix ...
    1713              : !> \param pmatrix ...
    1714              : !> \par History
    1715              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1716              : ! **************************************************************************************************
    1717          328 :    SUBROUTINE allocate_dbcsr_matrix_set_3d(matrix_set, nmatrix, mmatrix, pmatrix)
    1718              :       TYPE(dbcsr_p_type), DIMENSION(:, :, :), POINTER    :: matrix_set
    1719              :       INTEGER, INTENT(IN)                                :: nmatrix, mmatrix, pmatrix
    1720              : 
    1721              :       INTEGER                                            :: imatrix, jmatrix, kmatrix
    1722              : 
    1723          328 :       IF (ASSOCIATED(matrix_set)) CALL dbcsr_deallocate_matrix_set(matrix_set)
    1724         7662 :       ALLOCATE (matrix_set(nmatrix, mmatrix, pmatrix))
    1725          668 :       DO kmatrix = 1, pmatrix
    1726         2562 :          DO jmatrix = 1, mmatrix
    1727         6022 :             DO imatrix = 1, nmatrix
    1728         5682 :                NULLIFY (matrix_set(imatrix, jmatrix, kmatrix)%matrix)
    1729              :             END DO
    1730              :          END DO
    1731              :       END DO
    1732          328 :    END SUBROUTINE allocate_dbcsr_matrix_set_3d
    1733              : 
    1734              : ! **************************************************************************************************
    1735              : !> \brief   Allocate and initialize a real matrix 4-dimensional set.
    1736              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1737              : !> \param[in] nmatrix         Size of set
    1738              : !> \param mmatrix ...
    1739              : !> \param pmatrix ...
    1740              : !> \param qmatrix ...
    1741              : !> \par History
    1742              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1743              : ! **************************************************************************************************
    1744            0 :    SUBROUTINE allocate_dbcsr_matrix_set_4d(matrix_set, nmatrix, mmatrix, pmatrix, qmatrix)
    1745              :       TYPE(dbcsr_p_type), DIMENSION(:, :, :, :), POINTER :: matrix_set
    1746              :       INTEGER, INTENT(IN)                                :: nmatrix, mmatrix, pmatrix, qmatrix
    1747              : 
    1748              :       INTEGER                                            :: imatrix, jmatrix, kmatrix, lmatrix
    1749              : 
    1750            0 :       IF (ASSOCIATED(matrix_set)) CALL dbcsr_deallocate_matrix_set(matrix_set)
    1751            0 :       ALLOCATE (matrix_set(nmatrix, mmatrix, pmatrix, qmatrix))
    1752            0 :       DO lmatrix = 1, qmatrix
    1753            0 :       DO kmatrix = 1, pmatrix
    1754            0 :          DO jmatrix = 1, mmatrix
    1755            0 :             DO imatrix = 1, nmatrix
    1756            0 :                NULLIFY (matrix_set(imatrix, jmatrix, kmatrix, lmatrix)%matrix)
    1757              :             END DO
    1758              :          END DO
    1759              :       END DO
    1760              :       END DO
    1761            0 :    END SUBROUTINE allocate_dbcsr_matrix_set_4d
    1762              : 
    1763              : ! **************************************************************************************************
    1764              : !> \brief   Allocate and initialize a real matrix 5-dimensional set.
    1765              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1766              : !> \param[in] nmatrix         Size of set
    1767              : !> \param mmatrix ...
    1768              : !> \param pmatrix ...
    1769              : !> \param qmatrix ...
    1770              : !> \param smatrix ...
    1771              : !> \par History
    1772              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1773              : ! **************************************************************************************************
    1774            0 :    SUBROUTINE allocate_dbcsr_matrix_set_5d(matrix_set, nmatrix, mmatrix, pmatrix, qmatrix, smatrix)
    1775              :       TYPE(dbcsr_p_type), DIMENSION(:, :, :, :, :), &
    1776              :          POINTER                                         :: matrix_set
    1777              :       INTEGER, INTENT(IN)                                :: nmatrix, mmatrix, pmatrix, qmatrix, &
    1778              :                                                             smatrix
    1779              : 
    1780              :       INTEGER                                            :: hmatrix, imatrix, jmatrix, kmatrix, &
    1781              :                                                             lmatrix
    1782              : 
    1783            0 :       IF (ASSOCIATED(matrix_set)) CALL dbcsr_deallocate_matrix_set(matrix_set)
    1784            0 :       ALLOCATE (matrix_set(nmatrix, mmatrix, pmatrix, qmatrix, smatrix))
    1785            0 :       DO hmatrix = 1, smatrix
    1786            0 :       DO lmatrix = 1, qmatrix
    1787            0 :       DO kmatrix = 1, pmatrix
    1788            0 :          DO jmatrix = 1, mmatrix
    1789            0 :             DO imatrix = 1, nmatrix
    1790            0 :                NULLIFY (matrix_set(imatrix, jmatrix, kmatrix, lmatrix, hmatrix)%matrix)
    1791              :             END DO
    1792              :          END DO
    1793              :       END DO
    1794              :       END DO
    1795              :       END DO
    1796            0 :    END SUBROUTINE allocate_dbcsr_matrix_set_5d
    1797              : 
    1798              :    ! **************************************************************************************************
    1799              : !> \brief Deallocate a real matrix set and release all of the member matrices.
    1800              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1801              : !> \par History
    1802              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1803              : ! **************************************************************************************************
    1804       205364 :    SUBROUTINE deallocate_dbcsr_matrix_set_1d(matrix_set)
    1805              : 
    1806              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_set
    1807              : 
    1808              :       INTEGER                                            :: imatrix
    1809              : 
    1810       205364 :       IF (ASSOCIATED(matrix_set)) THEN
    1811      1414976 :          DO imatrix = LBOUND(matrix_set, 1), UBOUND(matrix_set, 1)
    1812      1009836 :             CALL dbcsr_deallocate_matrix(matrix_set(imatrix)%matrix)
    1813              :          END DO
    1814       202570 :          DEALLOCATE (matrix_set)
    1815              :       END IF
    1816              : 
    1817       205364 :    END SUBROUTINE deallocate_dbcsr_matrix_set_1d
    1818              : 
    1819              : ! **************************************************************************************************
    1820              : !> \brief Deallocate a real matrix set and release all of the member matrices.
    1821              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1822              : !> \par History
    1823              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1824              : ! **************************************************************************************************
    1825       204645 :    SUBROUTINE deallocate_dbcsr_matrix_set_2d(matrix_set)
    1826              : 
    1827              :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_set
    1828              : 
    1829              :       INTEGER                                            :: imatrix, jmatrix
    1830              : 
    1831       204645 :       IF (ASSOCIATED(matrix_set)) THEN
    1832      2915390 :          DO jmatrix = LBOUND(matrix_set, 2), UBOUND(matrix_set, 2)
    1833      9763223 :             DO imatrix = LBOUND(matrix_set, 1), UBOUND(matrix_set, 1)
    1834      4940548 :                CALL dbcsr_deallocate_matrix(matrix_set(imatrix, jmatrix)%matrix)
    1835              :             END DO
    1836              :          END DO
    1837       201621 :          DEALLOCATE (matrix_set)
    1838              :       END IF
    1839       204645 :    END SUBROUTINE deallocate_dbcsr_matrix_set_2d
    1840              : 
    1841              : ! **************************************************************************************************
    1842              : !> \brief Deallocate a real matrix set and release all of the member matrices.
    1843              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1844              : !> \par History
    1845              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1846              : ! **************************************************************************************************
    1847          328 :    SUBROUTINE deallocate_dbcsr_matrix_set_3d(matrix_set)
    1848              : 
    1849              :       TYPE(dbcsr_p_type), DIMENSION(:, :, :), POINTER    :: matrix_set
    1850              : 
    1851              :       INTEGER                                            :: imatrix, jmatrix, kmatrix
    1852              : 
    1853          328 :       IF (ASSOCIATED(matrix_set)) THEN
    1854         1324 :          DO kmatrix = LBOUND(matrix_set, 3), UBOUND(matrix_set, 3)
    1855         3242 :             DO jmatrix = LBOUND(matrix_set, 2), UBOUND(matrix_set, 2)
    1856         9810 :                DO imatrix = LBOUND(matrix_set, 1), UBOUND(matrix_set, 1)
    1857         5682 :                   CALL dbcsr_deallocate_matrix(matrix_set(imatrix, jmatrix, kmatrix)%matrix)
    1858              :                END DO
    1859              :             END DO
    1860              :          END DO
    1861          328 :          DEALLOCATE (matrix_set)
    1862              :       END IF
    1863          328 :    END SUBROUTINE deallocate_dbcsr_matrix_set_3d
    1864              : 
    1865              : ! **************************************************************************************************
    1866              : !> \brief Deallocate a real matrix set and release all of the member matrices.
    1867              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1868              : !> \par History
    1869              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1870              : ! **************************************************************************************************
    1871            0 :    SUBROUTINE deallocate_dbcsr_matrix_set_4d(matrix_set)
    1872              : 
    1873              :       TYPE(dbcsr_p_type), DIMENSION(:, :, :, :), POINTER :: matrix_set
    1874              : 
    1875              :       INTEGER                                            :: imatrix, jmatrix, kmatrix, lmatrix
    1876              : 
    1877            0 :       IF (ASSOCIATED(matrix_set)) THEN
    1878            0 :          DO lmatrix = LBOUND(matrix_set, 4), UBOUND(matrix_set, 4)
    1879            0 :          DO kmatrix = LBOUND(matrix_set, 3), UBOUND(matrix_set, 3)
    1880            0 :             DO jmatrix = LBOUND(matrix_set, 2), UBOUND(matrix_set, 2)
    1881            0 :                DO imatrix = LBOUND(matrix_set, 1), UBOUND(matrix_set, 1)
    1882            0 :                   CALL dbcsr_deallocate_matrix(matrix_set(imatrix, jmatrix, kmatrix, lmatrix)%matrix)
    1883              :                END DO
    1884              :             END DO
    1885              :          END DO
    1886              :          END DO
    1887            0 :          DEALLOCATE (matrix_set)
    1888              :       END IF
    1889            0 :    END SUBROUTINE deallocate_dbcsr_matrix_set_4d
    1890              : 
    1891              : ! **************************************************************************************************
    1892              : !> \brief Deallocate a real matrix set and release all of the member matrices.
    1893              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1894              : !> \par History
    1895              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1896              : ! **************************************************************************************************
    1897            0 :    SUBROUTINE deallocate_dbcsr_matrix_set_5d(matrix_set)
    1898              : 
    1899              :       TYPE(dbcsr_p_type), DIMENSION(:, :, :, :, :), &
    1900              :          POINTER                                         :: matrix_set
    1901              : 
    1902              :       INTEGER                                            :: hmatrix, imatrix, jmatrix, kmatrix, &
    1903              :                                                             lmatrix
    1904              : 
    1905            0 :       IF (ASSOCIATED(matrix_set)) THEN
    1906            0 :          DO hmatrix = LBOUND(matrix_set, 5), UBOUND(matrix_set, 5)
    1907            0 :             DO lmatrix = LBOUND(matrix_set, 4), UBOUND(matrix_set, 4)
    1908            0 :             DO kmatrix = LBOUND(matrix_set, 3), UBOUND(matrix_set, 3)
    1909            0 :                DO jmatrix = LBOUND(matrix_set, 2), UBOUND(matrix_set, 2)
    1910            0 :                   DO imatrix = LBOUND(matrix_set, 1), UBOUND(matrix_set, 1)
    1911            0 :                      CALL dbcsr_deallocate_matrix(matrix_set(imatrix, jmatrix, kmatrix, lmatrix, hmatrix)%matrix)
    1912              :                   END DO
    1913              :                END DO
    1914              :             END DO
    1915              :             END DO
    1916              :          END DO
    1917            0 :          DEALLOCATE (matrix_set)
    1918              :       END IF
    1919            0 :    END SUBROUTINE deallocate_dbcsr_matrix_set_5d
    1920              : 
    1921            0 : END MODULE cp_dbcsr_operations
        

Generated by: LCOV version 2.0-1