LCOV - code coverage report
Current view: top level - src - cp_dbcsr_operations.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 79.6 % 450 358
Test Date: 2026-07-25 06:35:44 Functions: 75.0 % 28 21

            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              :    USE mathlib,                         ONLY: gcd,&
      45              :                                               lcm
      46              :    USE message_passing,                 ONLY: mp_para_env_type
      47              : 
      48              : !$ USE OMP_LIB, ONLY: omp_get_max_threads, omp_get_thread_num, omp_get_num_threads
      49              : #include "base/base_uses.f90"
      50              : 
      51              :    IMPLICIT NONE
      52              :    PRIVATE
      53              : 
      54              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_dbcsr_operations'
      55              :    LOGICAL, PARAMETER :: debug_mod = .FALSE.
      56              : 
      57              :    INTEGER, SAVE, PUBLIC :: max_elements_per_block = 32
      58              : 
      59              :    PUBLIC :: dbcsr_multiply_local
      60              : 
      61              :    ! CP2K API emulation
      62              :    PUBLIC :: copy_fm_to_dbcsr, copy_dbcsr_to_fm, &
      63              :              cp_dbcsr_sm_fm_multiply, cp_dbcsr_plus_fm_fm_t, &
      64              :              copy_dbcsr_to_fm_bc, copy_fm_to_dbcsr_bc, cp_fm_to_dbcsr_row_template, &
      65              :              cp_dbcsr_m_by_n_from_template, cp_dbcsr_m_by_n_from_row_template, &
      66              :              dbcsr_create_dist_r_unrot
      67              : 
      68              :    ! distribution_2d_type compatibility
      69              :    PUBLIC :: cp_dbcsr_dist2d_to_dist
      70              : 
      71              :    PUBLIC :: dbcsr_copy_columns_hack
      72              : 
      73              :    ! matrix set
      74              :    PUBLIC :: dbcsr_allocate_matrix_set
      75              :    PUBLIC :: dbcsr_deallocate_matrix_set
      76              : 
      77              :    INTERFACE dbcsr_allocate_matrix_set
      78              :       MODULE PROCEDURE allocate_dbcsr_matrix_set_1d
      79              :       MODULE PROCEDURE allocate_dbcsr_matrix_set_2d
      80              :       MODULE PROCEDURE allocate_dbcsr_matrix_set_3d
      81              :       MODULE PROCEDURE allocate_dbcsr_matrix_set_4d
      82              :       MODULE PROCEDURE allocate_dbcsr_matrix_set_5d
      83              :    END INTERFACE
      84              : 
      85              :    INTERFACE dbcsr_deallocate_matrix_set
      86              :       MODULE PROCEDURE deallocate_dbcsr_matrix_set_1d
      87              :       MODULE PROCEDURE deallocate_dbcsr_matrix_set_2d
      88              :       MODULE PROCEDURE deallocate_dbcsr_matrix_set_3d
      89              :       MODULE PROCEDURE deallocate_dbcsr_matrix_set_4d
      90              :       MODULE PROCEDURE deallocate_dbcsr_matrix_set_5d
      91              :    END INTERFACE
      92              : 
      93              : CONTAINS
      94              : 
      95              : ! **************************************************************************************************
      96              : !> \brief   Copy a BLACS matrix to a dbcsr matrix.
      97              : !>
      98              : !>          real_matrix=beta*real_matrix+alpha*fm
      99              : !>          beta defaults to 0, alpha to 1
     100              : !> \param[in] fm              full matrix
     101              : !> \param[out] matrix         DBCSR matrix
     102              : !> \param[in] keep_sparsity   (optional) retains the sparsity of the input
     103              : !>                            matrix
     104              : !> \date    2009-10-13
     105              : !> \par History
     106              : !>          2009-10-13 rewritten based on copy_dbcsr_to_fm
     107              : !> \author  Urban Borstnik
     108              : !> \version 2.0
     109              : ! **************************************************************************************************
     110      1457802 :    SUBROUTINE copy_fm_to_dbcsr(fm, matrix, keep_sparsity)
     111              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm
     112              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix
     113              :       LOGICAL, INTENT(IN), OPTIONAL                      :: keep_sparsity
     114              : 
     115              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'copy_fm_to_dbcsr'
     116              : 
     117              :       INTEGER                                            :: handle
     118              :       LOGICAL                                            :: my_keep_sparsity
     119              :       TYPE(dbcsr_type)                                   :: bc_mat, redist_mat
     120              : 
     121      1457802 :       CALL timeset(routineN, handle)
     122              : 
     123      1457802 :       my_keep_sparsity = .FALSE.
     124      1457802 :       IF (PRESENT(keep_sparsity)) my_keep_sparsity = keep_sparsity
     125              : 
     126      1457802 :       CALL copy_fm_to_dbcsr_bc(fm, bc_mat)
     127              : 
     128      1457802 :       IF (my_keep_sparsity) THEN
     129       280208 :          CALL dbcsr_create(redist_mat, template=matrix)
     130       280208 :          CALL dbcsr_complete_redistribute(bc_mat, redist_mat)
     131       280208 :          CALL dbcsr_copy(matrix, redist_mat, keep_sparsity=.TRUE.)
     132       280208 :          CALL dbcsr_release(redist_mat)
     133              :       ELSE
     134      1177594 :          CALL dbcsr_complete_redistribute(bc_mat, matrix)
     135              :       END IF
     136              : 
     137      1457802 :       CALL dbcsr_release(bc_mat)
     138              : 
     139      1457802 :       CALL timestop(handle)
     140      1457802 :    END SUBROUTINE copy_fm_to_dbcsr
     141              : 
     142              : ! **************************************************************************************************
     143              : !> \brief   Copy a BLACS matrix to a dbcsr matrix with a special block-cyclic distribution,
     144              : !>           which requires no complete redistribution.
     145              : !> \param fm ...
     146              : !> \param bc_mat ...
     147              : ! **************************************************************************************************
     148      1458190 :    SUBROUTINE copy_fm_to_dbcsr_bc(fm, bc_mat)
     149              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm
     150              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: bc_mat
     151              : 
     152              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'copy_fm_to_dbcsr_bc'
     153              : 
     154              :       INTEGER                                            :: col, handle, ncol_block, ncol_global, &
     155              :                                                             nrow_block, nrow_global, row
     156      1458190 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: first_col, first_row, last_col, last_row
     157      1458190 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size, row_blk_size
     158      1458190 :       INTEGER, DIMENSION(:, :), POINTER                  :: pgrid
     159      1458190 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: dbcsr_block, fm_block
     160              :       TYPE(dbcsr_distribution_type)                      :: bc_dist
     161              :       TYPE(dbcsr_iterator_type)                          :: iter
     162              : 
     163      1458190 :       CALL timeset(routineN, handle)
     164              : 
     165              :       ! Create processor grid
     166      1458190 :       pgrid => fm%matrix_struct%context%blacs2mpi
     167              : 
     168              :       ! Create a block-cyclic distribution compatible with the FM matrix.
     169      1458190 :       nrow_block = fm%matrix_struct%nrow_block
     170      1458190 :       ncol_block = fm%matrix_struct%ncol_block
     171      1458190 :       nrow_global = fm%matrix_struct%nrow_global
     172      1458190 :       ncol_global = fm%matrix_struct%ncol_global
     173      1458190 :       NULLIFY (col_blk_size, row_blk_size)
     174              :       CALL dbcsr_create_dist_block_cyclic(bc_dist, &
     175              :                                           nrows=nrow_global, ncolumns=ncol_global, & ! Actual full matrix size
     176              :                                           nrow_block=nrow_block, ncol_block=ncol_block, & ! BLACS parameters
     177              :                                           group_handle=fm%matrix_struct%para_env%get_handle(), pgrid=pgrid, &
     178      1458190 :                                           row_blk_sizes=row_blk_size, col_blk_sizes=col_blk_size) ! block-cyclic row/col sizes
     179              : 
     180              :       ! Create the block-cyclic DBCSR matrix
     181              :       CALL dbcsr_create(bc_mat, "Block-cyclic ", bc_dist, &
     182      1458190 :                         dbcsr_type_no_symmetry, row_blk_size, col_blk_size, reuse_arrays=.TRUE.)
     183      1458190 :       CALL dbcsr_distribution_release(bc_dist)
     184              : 
     185              :       ! allocate all blocks
     186      1458190 :       CALL dbcsr_reserve_all_blocks(bc_mat)
     187              : 
     188      1458190 :       CALL calculate_fm_block_ranges(bc_mat, first_row, last_row, first_col, last_col)
     189              : 
     190              :       ! Copy the FM data to the block-cyclic DBCSR matrix.  This step
     191              :       ! could be skipped with appropriate DBCSR index manipulation.
     192      1458190 :       fm_block => fm%local_data
     193              : !$OMP PARALLEL DEFAULT(NONE) PRIVATE(iter, row, col, dbcsr_block) &
     194      1458190 : !$OMP SHARED(bc_mat, last_row, first_row, last_col, first_col, fm_block)
     195              :       CALL dbcsr_iterator_start(iter, bc_mat)
     196              :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     197              :          CALL dbcsr_iterator_next_block(iter, row, col, dbcsr_block)
     198              :          dbcsr_block(:, :) = fm_block(first_row(row):last_row(row), first_col(col):last_col(col))
     199              :       END DO
     200              :       CALL dbcsr_iterator_stop(iter)
     201              : !$OMP END PARALLEL
     202              : 
     203      1458190 :       CALL timestop(handle)
     204      2916380 :    END SUBROUTINE copy_fm_to_dbcsr_bc
     205              : 
     206              : ! **************************************************************************************************
     207              : !> \brief Copy a DBCSR matrix to a BLACS matrix
     208              : !> \param[in] matrix          DBCSR matrix
     209              : !> \param[out] fm             full matrix
     210              : ! **************************************************************************************************
     211      6326920 :    SUBROUTINE copy_dbcsr_to_fm(matrix, fm)
     212              :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix
     213              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm
     214              : 
     215              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'copy_dbcsr_to_fm'
     216              : 
     217              :       CHARACTER(len=default_string_length)               :: name
     218              :       INTEGER                                            :: group_handle, handle, ncol_block, &
     219              :                                                             nfullcols_total, nfullrows_total, &
     220              :                                                             nrow_block
     221      1581730 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size, row_blk_size
     222      1581730 :       INTEGER, DIMENSION(:, :), POINTER                  :: pgrid
     223              :       TYPE(dbcsr_distribution_type)                      :: bc_dist, dist
     224              :       TYPE(dbcsr_type)                                   :: bc_mat, matrix_nosym
     225              : 
     226      1581730 :       CALL timeset(routineN, handle)
     227              : 
     228              :       ! check compatibility
     229              :       CALL dbcsr_get_info(matrix, &
     230              :                           name=name, &
     231              :                           distribution=dist, &
     232              :                           nfullrows_total=nfullrows_total, &
     233      1581730 :                           nfullcols_total=nfullcols_total)
     234              : 
     235      1581730 :       CPASSERT(fm%matrix_struct%nrow_global == nfullrows_total)
     236      1581730 :       CPASSERT(fm%matrix_struct%ncol_global == nfullcols_total)
     237              : 
     238              :       ! info about the full matrix
     239      1581730 :       nrow_block = fm%matrix_struct%nrow_block
     240      1581730 :       ncol_block = fm%matrix_struct%ncol_block
     241              : 
     242              :       ! Convert DBCSR to a block-cyclic
     243      1581730 :       NULLIFY (col_blk_size, row_blk_size)
     244      1581730 :       CALL dbcsr_distribution_get(dist, group=group_handle, pgrid=pgrid)
     245              :       CALL dbcsr_create_dist_block_cyclic(bc_dist, &
     246              :                                           nrows=nfullrows_total, ncolumns=nfullcols_total, &
     247              :                                           nrow_block=nrow_block, ncol_block=ncol_block, &
     248              :                                           group_handle=group_handle, pgrid=pgrid, &
     249      1581730 :                                           row_blk_sizes=row_blk_size, col_blk_sizes=col_blk_size)
     250              : 
     251              :       CALL dbcsr_create(bc_mat, "Block-cyclic"//name, bc_dist, &
     252      1581730 :                         dbcsr_type_no_symmetry, row_blk_size, col_blk_size, reuse_arrays=.TRUE.)
     253      1581730 :       CALL dbcsr_distribution_release(bc_dist)
     254              : 
     255      1581730 :       CALL dbcsr_create(matrix_nosym, template=matrix, matrix_type="N")
     256      1581730 :       CALL dbcsr_desymmetrize(matrix, matrix_nosym)
     257      1581730 :       CALL dbcsr_complete_redistribute(matrix_nosym, bc_mat)
     258      1581730 :       CALL dbcsr_release(matrix_nosym)
     259              : 
     260      1581730 :       CALL copy_dbcsr_to_fm_bc(bc_mat, fm)
     261              : 
     262      1581730 :       CALL dbcsr_release(bc_mat)
     263              : 
     264      1581730 :       CALL timestop(handle)
     265      1581730 :    END SUBROUTINE copy_dbcsr_to_fm
     266              : 
     267              : ! **************************************************************************************************
     268              : !> \brief Copy a DBCSR_BLACS matrix to a BLACS matrix
     269              : !> \param bc_mat DBCSR matrix
     270              : !> \param[out] fm             full matrix
     271              : ! **************************************************************************************************
     272      1581730 :    SUBROUTINE copy_dbcsr_to_fm_bc(bc_mat, fm)
     273              :       TYPE(dbcsr_type), INTENT(IN)                       :: bc_mat
     274              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm
     275              : 
     276              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'copy_dbcsr_to_fm_bc'
     277              : 
     278              :       INTEGER                                            :: col, handle, row
     279      1581730 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: first_col, first_row, last_col, last_row
     280      1581730 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: dbcsr_block, fm_block
     281              :       TYPE(dbcsr_iterator_type)                          :: iter
     282              : 
     283      1581730 :       CALL timeset(routineN, handle)
     284              : 
     285      1581730 :       CALL calculate_fm_block_ranges(bc_mat, first_row, last_row, first_col, last_col)
     286              : 
     287              :       ! Now copy data to the FM matrix
     288      1581730 :       fm_block => fm%local_data
     289    715254632 :       fm_block = REAL(0.0, KIND=dp)
     290              : !$OMP PARALLEL DEFAULT(NONE) PRIVATE(iter, row, col, dbcsr_block) &
     291      1581730 : !$OMP SHARED(bc_mat, last_row, first_row, last_col, first_col, fm_block)
     292              :       CALL dbcsr_iterator_readonly_start(iter, bc_mat)
     293              :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     294              :          CALL dbcsr_iterator_next_block(iter, row, col, dbcsr_block)
     295              :          fm_block(first_row(row):last_row(row), first_col(col):last_col(col)) = dbcsr_block(:, :)
     296              :       END DO
     297              :       CALL dbcsr_iterator_stop(iter)
     298              : !$OMP END PARALLEL
     299              : 
     300      1581730 :       CALL timestop(handle)
     301      3163460 :    END SUBROUTINE copy_dbcsr_to_fm_bc
     302              : 
     303              : ! **************************************************************************************************
     304              : !> \brief Helper routine used to copy blocks from DBCSR into FM matrices and vice versa
     305              : !> \param bc_mat ...
     306              : !> \param first_row ...
     307              : !> \param last_row ...
     308              : !> \param first_col ...
     309              : !> \param last_col ...
     310              : !> \author Ole Schuett
     311              : ! **************************************************************************************************
     312      3039920 :    SUBROUTINE calculate_fm_block_ranges(bc_mat, first_row, last_row, first_col, last_col)
     313              :       TYPE(dbcsr_type), INTENT(IN)                       :: bc_mat
     314              :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT)    :: first_row, last_row, first_col, last_col
     315              : 
     316              :       INTEGER                                            :: col, nblkcols_local, nblkcols_total, &
     317              :                                                             nblkrows_local, nblkrows_total, row
     318              :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: local_col_sizes, local_row_sizes
     319      3039920 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size, local_cols, local_rows, &
     320      3039920 :                                                             row_blk_size
     321              : 
     322              :       CALL dbcsr_get_info(bc_mat, &
     323              :                           nblkrows_total=nblkrows_total, &
     324              :                           nblkcols_total=nblkcols_total, &
     325              :                           nblkrows_local=nblkrows_local, &
     326              :                           nblkcols_local=nblkcols_local, &
     327              :                           local_rows=local_rows, &
     328              :                           local_cols=local_cols, &
     329              :                           row_blk_size=row_blk_size, &
     330      3039920 :                           col_blk_size=col_blk_size)
     331              : 
     332              :       ! calculate first_row and last_row
     333      9119208 :       ALLOCATE (local_row_sizes(nblkrows_total))
     334      3039920 :       local_row_sizes(:) = 0
     335      3039920 :       IF (nblkrows_local >= 1) THEN
     336      7582308 :          DO row = 1, nblkrows_local
     337      7582308 :             local_row_sizes(local_rows(row)) = row_blk_size(local_rows(row))
     338              :          END DO
     339              :       END IF
     340      9118656 :       ALLOCATE (first_row(nblkrows_total), last_row(nblkrows_total))
     341      3039920 :       CALL dbcsr_convert_sizes_to_offsets(local_row_sizes, first_row, last_row)
     342      3039920 :       DEALLOCATE (local_row_sizes)
     343              : 
     344              :       ! calculate first_col and last_col
     345      9117960 :       ALLOCATE (local_col_sizes(nblkcols_total))
     346      3039920 :       local_col_sizes(:) = 0
     347      3039920 :       IF (nblkcols_local >= 1) THEN
     348      9826794 :          DO col = 1, nblkcols_local
     349      9826794 :             local_col_sizes(local_cols(col)) = col_blk_size(local_cols(col))
     350              :          END DO
     351              :       END IF
     352      9116160 :       ALLOCATE (first_col(nblkcols_total), last_col(nblkcols_total))
     353      3039920 :       CALL dbcsr_convert_sizes_to_offsets(local_col_sizes, first_col, last_col)
     354      3039920 :       DEALLOCATE (local_col_sizes)
     355              : 
     356      3039920 :    END SUBROUTINE calculate_fm_block_ranges
     357              : 
     358              : ! **************************************************************************************************
     359              : !> \brief hack for dbcsr_copy_columns
     360              : !> \param matrix_b ...
     361              : !> \param matrix_a ...
     362              : !> \param ncol ...
     363              : !> \param source_start ...
     364              : !> \param target_start ...
     365              : !> \param para_env ...
     366              : !> \param blacs_env ...
     367              : !> \author vw
     368              : ! **************************************************************************************************
     369         9448 :    SUBROUTINE dbcsr_copy_columns_hack(matrix_b, matrix_a, &
     370              :                                       ncol, source_start, target_start, para_env, blacs_env)
     371              : 
     372              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_b
     373              :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_a
     374              :       INTEGER, INTENT(IN)                                :: ncol, source_start, target_start
     375              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     376              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     377              : 
     378              :       INTEGER                                            :: nfullcols_total, nfullrows_total
     379              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     380              :       TYPE(cp_fm_type)                                   :: fm_matrix_a, fm_matrix_b
     381              : 
     382         2362 :       NULLIFY (fm_struct)
     383         2362 :       CALL dbcsr_get_info(matrix_a, nfullrows_total=nfullrows_total, nfullcols_total=nfullcols_total)
     384              :       CALL cp_fm_struct_create(fm_struct, context=blacs_env, nrow_global=nfullrows_total, &
     385         2362 :                                ncol_global=nfullcols_total, para_env=para_env)
     386         2362 :       CALL cp_fm_create(fm_matrix_a, fm_struct, name="fm_matrix_a")
     387         2362 :       CALL cp_fm_struct_release(fm_struct)
     388              : 
     389         2362 :       CALL dbcsr_get_info(matrix_b, nfullrows_total=nfullrows_total, nfullcols_total=nfullcols_total)
     390              :       CALL cp_fm_struct_create(fm_struct, context=blacs_env, nrow_global=nfullrows_total, &
     391         2362 :                                ncol_global=nfullcols_total, para_env=para_env)
     392         2362 :       CALL cp_fm_create(fm_matrix_b, fm_struct, name="fm_matrix_b")
     393         2362 :       CALL cp_fm_struct_release(fm_struct)
     394              : 
     395         2362 :       CALL copy_dbcsr_to_fm(matrix_a, fm_matrix_a)
     396         2362 :       CALL copy_dbcsr_to_fm(matrix_b, fm_matrix_b)
     397              : 
     398         2362 :       CALL cp_fm_to_fm(fm_matrix_a, fm_matrix_b, ncol, source_start, target_start)
     399              : 
     400         2362 :       CALL copy_fm_to_dbcsr(fm_matrix_b, matrix_b)
     401              : 
     402         2362 :       CALL cp_fm_release(fm_matrix_a)
     403         2362 :       CALL cp_fm_release(fm_matrix_b)
     404              : 
     405         2362 :    END SUBROUTINE dbcsr_copy_columns_hack
     406              : 
     407              : ! **************************************************************************************************
     408              : !> \brief Creates a DBCSR distribution from a distribution_2d
     409              : !> \param[in] dist2d          distribution_2d
     410              : !> \param[out] dist           DBCSR distribution
     411              : !> \par History
     412              : !>    move form dbcsr_operation 01.2010
     413              : ! **************************************************************************************************
     414        11164 :    SUBROUTINE cp_dbcsr_dist2d_to_dist(dist2d, dist)
     415              :       TYPE(distribution_2d_type), INTENT(IN), TARGET     :: dist2d
     416              :       TYPE(dbcsr_distribution_type), INTENT(OUT)         :: dist
     417              : 
     418        11164 :       INTEGER, DIMENSION(:), POINTER                     :: col_dist, row_dist
     419        11164 :       INTEGER, DIMENSION(:, :), POINTER                  :: col_dist_data, pgrid, row_dist_data
     420              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     421              :       TYPE(distribution_2d_type), POINTER                :: dist2d_p
     422              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     423              : 
     424        11164 :       dist2d_p => dist2d
     425              :       CALL distribution_2d_get(dist2d_p, &
     426              :                                row_distribution=row_dist_data, &
     427              :                                col_distribution=col_dist_data, &
     428        11164 :                                blacs_env=blacs_env)
     429        11164 :       CALL blacs_env%get(para_env=para_env, blacs2mpi=pgrid)
     430              : 
     431              :       ! map to 1D arrays
     432        11164 :       row_dist => row_dist_data(:, 1)
     433        11164 :       col_dist => col_dist_data(:, 1)
     434              :       !row_cluster => row_dist_data(:, 2)
     435              :       !col_cluster => col_dist_data(:, 2)
     436              : 
     437              :       CALL dbcsr_distribution_new(dist, &
     438              :                                   group=para_env%get_handle(), pgrid=pgrid, &
     439              :                                   row_dist=row_dist, &
     440        11164 :                                   col_dist=col_dist)
     441              : 
     442        11164 :    END SUBROUTINE cp_dbcsr_dist2d_to_dist
     443              : 
     444              : ! **************************************************************************************************
     445              : !> \brief multiply a dbcsr with a replicated array
     446              : !>        c = alpha_scalar * A (dbscr) * b + c
     447              : !> \param[in] matrix_a DBSCR matrxx
     448              : !> \param[in]  vec_b        vectors b
     449              : !> \param[inout] vec_c      vectors c
     450              : !> \param[in]  ncol         nbr of columns
     451              : !> \param[in]  alpha        alpha
     452              : !>
     453              : ! **************************************************************************************************
     454            0 :    SUBROUTINE dbcsr_multiply_local(matrix_a, vec_b, vec_c, ncol, alpha)
     455              :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_a
     456              :       REAL(dp), DIMENSION(:, :), INTENT(IN)              :: vec_b
     457              :       REAL(dp), DIMENSION(:, :), INTENT(INOUT)           :: vec_c
     458              :       INTEGER, INTENT(in), OPTIONAL                      :: ncol
     459              :       REAL(dp), INTENT(IN), OPTIONAL                     :: alpha
     460              : 
     461              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'dbcsr_multiply_local'
     462              : 
     463              :       INTEGER                                            :: col, coloff, my_ncol, row, rowoff, &
     464              :                                                             timing_handle
     465              :       LOGICAL                                            :: has_symm
     466              :       REAL(dp)                                           :: my_alpha, my_alpha2
     467            0 :       REAL(dp), DIMENSION(:, :), POINTER                 :: data_d
     468              :       TYPE(dbcsr_iterator_type)                          :: iter
     469              : 
     470            0 :       CALL timeset(routineN, timing_handle)
     471              : 
     472            0 :       my_alpha = 1.0_dp
     473            0 :       IF (PRESENT(alpha)) my_alpha = alpha
     474              : 
     475            0 :       my_ncol = SIZE(vec_b, 2)
     476            0 :       IF (PRESENT(ncol)) my_ncol = ncol
     477              : 
     478            0 :       my_alpha2 = 0.0_dp
     479            0 :       IF (dbcsr_get_matrix_type(matrix_a) == dbcsr_type_symmetric) my_alpha2 = my_alpha
     480            0 :       IF (dbcsr_get_matrix_type(matrix_a) == dbcsr_type_antisymmetric) my_alpha2 = -my_alpha
     481              : 
     482              :       has_symm = (dbcsr_get_matrix_type(matrix_a) == dbcsr_type_symmetric .OR. &
     483            0 :                   dbcsr_get_matrix_type(matrix_a) == dbcsr_type_antisymmetric)
     484              : 
     485              : !$OMP     PARALLEL DEFAULT(NONE) SHARED(matrix_a,vec_b,vec_c,ncol,my_alpha2,my_alpha,my_ncol,has_symm) &
     486            0 : !$OMP              PRIVATE(iter,row,col,data_d,rowoff,coloff)
     487              :       CALL dbcsr_iterator_readonly_start(iter, matrix_a, dynamic=.TRUE., dynamic_byrows=.TRUE.)
     488              :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     489              :          CALL dbcsr_iterator_next_block(iter, row, col, data_d, row_offset=rowoff, col_offset=coloff)
     490              :          IF (my_ncol /= 1) THEN
     491              :             CALL dgemm('N', 'N', &
     492              :                        SIZE(data_d, 1), my_ncol, SIZE(data_d, 2), &
     493              :                        my_alpha, data_d(1, 1), SIZE(data_d, 1), &
     494              :                        vec_b(coloff, 1), SIZE(vec_b, 1), &
     495              :                        1.0_dp, vec_c(rowoff, 1), SIZE(vec_c, 1))
     496              :          ELSE
     497              :             CALL dgemv('N', SIZE(data_d, 1), SIZE(data_d, 2), &
     498              :                        my_alpha, data_d(1, 1), SIZE(data_d, 1), &
     499              :                        vec_b(coloff, 1), 1, &
     500              :                        1.0_dp, vec_c(rowoff, 1), 1)
     501              :          END IF
     502              :       END DO
     503              :       CALL dbcsr_iterator_stop(iter)
     504              : !$OMP     END PARALLEL
     505              : 
     506              :       ! FIXME ... in the symmetric case, the writes to vec_c depend on the column, not the row. This makes OMP-ing more difficult
     507              :       ! needs e.g. a buffer for vec_c and a reduction of that buffer.
     508            0 :       IF (has_symm) THEN
     509            0 :          CALL dbcsr_iterator_readonly_start(iter, matrix_a)
     510            0 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
     511            0 :             CALL dbcsr_iterator_next_block(iter, row, col, data_d, row_offset=rowoff, col_offset=coloff)
     512            0 :             IF (row /= col) THEN
     513            0 :                IF (my_ncol /= 1) THEN
     514              :                   CALL dgemm('T', 'N', &
     515              :                              SIZE(data_d, 2), my_ncol, SIZE(data_d, 1), &
     516              :                              my_alpha2, data_d(1, 1), SIZE(data_d, 1), &
     517              :                              vec_b(rowoff, 1), SIZE(vec_b, 1), &
     518            0 :                              1.0_dp, vec_c(coloff, 1), SIZE(vec_c, 1))
     519              :                ELSE
     520              :                   CALL dgemv('T', SIZE(data_d, 1), SIZE(data_d, 2), &
     521              :                              my_alpha2, data_d(1, 1), SIZE(data_d, 1), &
     522              :                              vec_b(rowoff, 1), 1, &
     523            0 :                              1.0_dp, vec_c(coloff, 1), 1)
     524              :                END IF
     525              :             END IF
     526              :          END DO
     527            0 :          CALL dbcsr_iterator_stop(iter)
     528              :       END IF
     529              : 
     530            0 :       CALL timestop(timing_handle)
     531            0 :    END SUBROUTINE dbcsr_multiply_local
     532              : 
     533              : ! **************************************************************************************************
     534              : !> \brief multiply a dbcsr with a fm matrix
     535              : !>
     536              : !> For backwards compatibility with BLAS XGEMM, this routine supports
     537              : !> the multiplication of matrices with incompatible dimensions.
     538              : !>
     539              : !> \param[in]  matrix         DBCSR matrix
     540              : !> \param fm_in full matrix
     541              : !> \param fm_out full matrix
     542              : !> \param[in]  ncol           nbr of columns
     543              : !> \param[in]  alpha          alpha
     544              : !> \param[in]  beta           beta
     545              : !>
     546              : ! **************************************************************************************************
     547      3098718 :    SUBROUTINE cp_dbcsr_sm_fm_multiply(matrix, fm_in, fm_out, ncol, alpha, beta)
     548              :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix
     549              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_in
     550              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm_out
     551              :       INTEGER, INTENT(IN)                                :: ncol
     552              :       REAL(dp), INTENT(IN), OPTIONAL                     :: alpha, beta
     553              : 
     554              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'cp_dbcsr_sm_fm_multiply'
     555              : 
     556              :       INTEGER                                            :: a_ncol, a_nrow, b_ncol, b_nrow, c_ncol, &
     557              :                                                             c_nrow, k_in, k_out, timing_handle, &
     558              :                                                             timing_handle_mult
     559       516453 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size, col_blk_size_right_in, &
     560       516453 :                                                             col_blk_size_right_out, col_dist, &
     561       516453 :                                                             row_blk_size, row_dist
     562              :       TYPE(dbcsr_type)                                   :: in, out
     563              :       TYPE(dbcsr_distribution_type)                      :: dist, dist_right_in, product_dist
     564              :       REAL(dp)                                           :: my_alpha, my_beta
     565              : 
     566       516453 :       CALL timeset(routineN, timing_handle)
     567              : 
     568       516453 :       my_alpha = 1.0_dp
     569       516453 :       my_beta = 0.0_dp
     570       516453 :       IF (PRESENT(alpha)) my_alpha = alpha
     571       516453 :       IF (PRESENT(beta)) my_beta = beta
     572              : 
     573              :       ! TODO
     574       516453 :       CALL cp_fm_get_info(fm_in, ncol_global=b_ncol, nrow_global=b_nrow)
     575       516453 :       CALL cp_fm_get_info(fm_out, ncol_global=c_ncol, nrow_global=c_nrow)
     576       516453 :       CALL dbcsr_get_info(matrix, nfullrows_total=a_nrow, nfullcols_total=a_ncol)
     577              :       !WRITE(*,*) "cp_dbcsr_sm_fm_multiply: A ", a_nrow, "x", a_ncol
     578              :       !WRITE(*,*) "cp_dbcsr_sm_fm_multiply: B ", b_nrow, "x", b_ncol
     579              :       !WRITE(*,*) "cp_dbcsr_sm_fm_multiply: C ", c_nrow, "x", c_ncol
     580              : 
     581       516453 :       CALL cp_fm_get_info(fm_out, ncol_global=k_out)
     582              : 
     583       516453 :       CALL cp_fm_get_info(fm_in, ncol_global=k_in)
     584              :       !write(*,*)routineN//" -----------------------------------"
     585              :       !IF (k_in /= k_out) &
     586              :       !   WRITE(*,'(3(A,I5,1X),2(A,F5.2,1X))')&
     587              :       !   routineN//" ncol", ncol,'k_in',k_in,'k_out',k_out,&
     588              :       !   'alpha',my_alpha,'beta',my_beta
     589              : 
     590       516453 :       IF (ncol > 0 .AND. k_out > 0 .AND. k_in > 0) THEN
     591       515389 :          CALL dbcsr_get_info(matrix, row_blk_size=row_blk_size, col_blk_size=col_blk_size, distribution=dist)
     592       515389 :          CALL dbcsr_create_dist_r_unrot(dist_right_in, dist, k_in, col_blk_size_right_in)
     593              : 
     594              :          CALL dbcsr_create(in, "D", dist_right_in, dbcsr_type_no_symmetry, &
     595       515389 :                            col_blk_size, col_blk_size_right_in)
     596              : 
     597       515389 :          CALL dbcsr_distribution_get(dist, row_dist=row_dist)
     598       515389 :          CALL dbcsr_distribution_get(dist_right_in, col_dist=col_dist)
     599              :          CALL dbcsr_distribution_new(product_dist, template=dist, &
     600       515389 :                                      row_dist=row_dist, col_dist=col_dist)
     601      1546167 :          ALLOCATE (col_blk_size_right_out(SIZE(col_blk_size_right_in)))
     602      2098288 :          col_blk_size_right_out = col_blk_size_right_in
     603       515389 :          CALL match_col_sizes(col_blk_size_right_out, col_blk_size_right_in, k_out)
     604              : 
     605              :          !if (k_in .ne. k_out) then
     606              :          !   write(*,*)routineN//" in cs", col_blk_size_right_in
     607              :          !   write(*,*)routineN//" out cs", col_blk_size_right_out
     608              :          !endif
     609              : 
     610              :          CALL dbcsr_create(out, "D", product_dist, dbcsr_type_no_symmetry, &
     611       515389 :                            row_blk_size, col_blk_size_right_out)
     612              : 
     613       515389 :          CALL copy_fm_to_dbcsr(fm_in, in)
     614       515389 :          IF (ncol /= k_out .OR. my_beta /= 0.0_dp) THEN
     615       114386 :             CALL copy_fm_to_dbcsr(fm_out, out)
     616              :          END IF
     617              : 
     618       515389 :          CALL timeset(routineN//'_core', timing_handle_mult)
     619              :          CALL dbcsr_multiply("N", "N", my_alpha, matrix, in, my_beta, out, &
     620       515389 :                              last_column=ncol)
     621       515389 :          CALL timestop(timing_handle_mult)
     622              : 
     623       515389 :          CALL copy_dbcsr_to_fm(out, fm_out)
     624              : 
     625       515389 :          CALL dbcsr_release(in)
     626       515389 :          CALL dbcsr_release(out)
     627       515389 :          DEALLOCATE (col_blk_size_right_in, col_blk_size_right_out)
     628       515389 :          CALL dbcsr_distribution_release(dist_right_in)
     629      2061556 :          CALL dbcsr_distribution_release(product_dist)
     630              : 
     631              :       END IF
     632              : 
     633       516453 :       CALL timestop(timing_handle)
     634              : 
     635       516453 :    END SUBROUTINE cp_dbcsr_sm_fm_multiply
     636              : 
     637              : ! **************************************************************************************************
     638              : !> \brief ...
     639              : !> \param sizes1 ...
     640              : !> \param sizes2 ...
     641              : !> \param full_num ...
     642              : ! **************************************************************************************************
     643       515389 :    SUBROUTINE match_col_sizes(sizes1, sizes2, full_num)
     644              :       INTEGER, DIMENSION(:), INTENT(INOUT)               :: sizes1
     645              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: sizes2
     646              :       INTEGER, INTENT(IN)                                :: full_num
     647              : 
     648              :       INTEGER                                            :: left, n1, n2, p, rm, used
     649              : 
     650       515389 :       n1 = SIZE(sizes1)
     651       515389 :       n2 = SIZE(sizes2)
     652       515389 :       IF (n1 /= n2) THEN
     653            0 :          CPABORT("distributions must be equal!")
     654              :       END IF
     655      1049144 :       sizes1(1:n1) = sizes2(1:n1)
     656      1049144 :       used = SUM(sizes1(1:n1))
     657              :       ! If sizes1 does not cover everything, then we increase the
     658              :       ! size of the last block; otherwise we reduce the blocks
     659              :       ! (from the end) until it is small enough.
     660       515389 :       IF (used < full_num) THEN
     661            0 :          sizes1(n1) = sizes1(n1) + full_num - used
     662              :       ELSE
     663       515389 :          left = used - full_num
     664       515389 :          p = n1
     665       515389 :          DO WHILE (left > 0 .AND. p > 0)
     666            0 :             rm = MIN(left, sizes1(p))
     667            0 :             sizes1(p) = sizes1(p) - rm
     668            0 :             left = left - rm
     669            0 :             p = p - 1
     670              :          END DO
     671              :       END IF
     672       515389 :    END SUBROUTINE match_col_sizes
     673              : 
     674              : ! **************************************************************************************************
     675              : !> \brief performs the multiplication sparse_matrix+dense_mat*dens_mat^T
     676              : !>        if matrix_g is not explicitly given, matrix_v^T will be used
     677              : !>        this can be important to save the necessary redistribute for a
     678              : !>        different matrix_g and increase performance.
     679              : !> \param sparse_matrix ...
     680              : !> \param matrix_v ...
     681              : !> \param matrix_g ...
     682              : !> \param ncol ...
     683              : !> \param alpha ...
     684              : !> \param keep_sparsity Determines if the sparsity of sparse_matrix is retained
     685              : !>        by default it is TRUE
     686              : !> \param symmetry_mode There are the following modes
     687              : !>        1:     sparse_matrix += 0.5*alpha*(v*g^T+g^T*v)    (symmetric update)
     688              : !>        -1:    sparse_matrix += 0.5*alpha*(v*g^T-g^T*v)    (skewsymmetric update)
     689              : !>        else:  sparse_matrix += alpha*v*g^T                (no symmetry, default)
     690              : !>        saves some redistribution steps
     691              : ! **************************************************************************************************
     692       249520 :    SUBROUTINE cp_dbcsr_plus_fm_fm_t(sparse_matrix, matrix_v, matrix_g, ncol, alpha, keep_sparsity, symmetry_mode)
     693              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: sparse_matrix
     694              :       TYPE(cp_fm_type), INTENT(IN)                       :: matrix_v
     695              :       TYPE(cp_fm_type), INTENT(IN), OPTIONAL             :: matrix_g
     696              :       INTEGER, INTENT(IN)                                :: ncol
     697              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: alpha
     698              :       LOGICAL, INTENT(IN), OPTIONAL                      :: keep_sparsity
     699              :       INTEGER, INTENT(IN), OPTIONAL                      :: symmetry_mode
     700              : 
     701              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'cp_dbcsr_plus_fm_fm_t'
     702              : 
     703              :       INTEGER                                            :: k, my_symmetry_mode, nao, npcols, &
     704              :                                                             timing_handle
     705       249520 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size_left, col_dist_left, &
     706       249520 :                                                             row_blk_size, row_dist
     707              :       LOGICAL                                            :: check_product, my_keep_sparsity
     708              :       REAL(KIND=dp)                                      :: my_alpha, norm
     709              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     710              :       TYPE(cp_fm_type)                                   :: fm_matrix
     711              :       TYPE(dbcsr_distribution_type)                      :: dist_left, sparse_dist
     712              :       TYPE(dbcsr_type)                                   :: mat_g, mat_v, sparse_matrix2, &
     713              :                                                             sparse_matrix3
     714              : 
     715       249520 :       check_product = .FALSE.
     716              : 
     717       249520 :       CALL timeset(routineN, timing_handle)
     718              : 
     719       249520 :       my_keep_sparsity = .TRUE.
     720       249520 :       IF (PRESENT(keep_sparsity)) my_keep_sparsity = keep_sparsity
     721              : 
     722       249520 :       my_symmetry_mode = 0
     723       249520 :       IF (PRESENT(symmetry_mode)) my_symmetry_mode = symmetry_mode
     724              : 
     725       249520 :       NULLIFY (col_dist_left)
     726              : 
     727       249520 :       IF (ncol > 0) THEN
     728       247948 :          IF (.NOT. dbcsr_valid_index(sparse_matrix)) THEN
     729            0 :             CPABORT("sparse_matrix must pre-exist")
     730              :          END IF
     731              :          !
     732              :          ! Setup matrix_v
     733       247948 :          CALL cp_fm_get_info(matrix_v, ncol_global=k)
     734              :          !WRITE(*,*)routineN//'truncated mult k, ncol',k,ncol,' PRESENT (matrix_g)',PRESENT (matrix_g)
     735       247948 :          CALL dbcsr_get_info(sparse_matrix, distribution=sparse_dist)
     736       247948 :          CALL dbcsr_distribution_get(sparse_dist, npcols=npcols, row_dist=row_dist)
     737       247948 :          CALL create_bl_distribution(col_dist_left, col_blk_size_left, k, npcols)
     738              :          CALL dbcsr_distribution_new(dist_left, template=sparse_dist, &
     739       247948 :                                      row_dist=row_dist, col_dist=col_dist_left)
     740       247948 :          DEALLOCATE (col_dist_left)
     741       247948 :          CALL dbcsr_get_info(sparse_matrix, row_blk_size=row_blk_size)
     742              :          CALL dbcsr_create(mat_v, "DBCSR matrix_v", dist_left, dbcsr_type_no_symmetry, &
     743       247948 :                            row_blk_size, col_blk_size_left)
     744       247948 :          CALL copy_fm_to_dbcsr(matrix_v, mat_v)
     745       247948 :          CALL dbcsr_verify_matrix(mat_v)
     746              :          !
     747              :          ! Setup matrix_g
     748       247948 :          IF (PRESENT(matrix_g)) THEN
     749              :             CALL dbcsr_create(mat_g, "DBCSR matrix_g", dist_left, dbcsr_type_no_symmetry, &
     750       120411 :                               row_blk_size, col_blk_size_left)
     751       120411 :             CALL copy_fm_to_dbcsr(matrix_g, mat_g)
     752              :          END IF
     753              :          !
     754       247948 :          DEALLOCATE (col_blk_size_left)
     755       247948 :          CALL dbcsr_distribution_release(dist_left)
     756              :          !
     757              :          !
     758              :          IF (check_product) THEN
     759              :             CALL cp_fm_get_info(matrix_v, nrow_global=nao)
     760              :             CALL cp_fm_struct_create(fm_struct_tmp, context=matrix_v%matrix_struct%context, nrow_global=nao, &
     761              :                                      ncol_global=nao, para_env=matrix_v%matrix_struct%para_env)
     762              :             CALL cp_fm_create(fm_matrix, fm_struct_tmp, name="fm matrix")
     763              :             CALL cp_fm_struct_release(fm_struct_tmp)
     764              :             CALL copy_dbcsr_to_fm(sparse_matrix, fm_matrix)
     765              :             CALL dbcsr_copy(sparse_matrix3, sparse_matrix)
     766              :          END IF
     767              :          !
     768       247948 :          my_alpha = 1.0_dp
     769       247948 :          IF (PRESENT(alpha)) my_alpha = alpha
     770       247948 :          IF (PRESENT(matrix_g)) THEN
     771       120411 :             IF (my_symmetry_mode == 1) THEN
     772              :                ! Symmetric mode
     773              :                CALL dbcsr_multiply("N", "T", 0.5_dp*my_alpha, mat_v, mat_g, &
     774              :                                    1.0_dp, sparse_matrix, &
     775              :                                    retain_sparsity=my_keep_sparsity, &
     776        42274 :                                    last_k=ncol)
     777              :                CALL dbcsr_multiply("N", "T", 0.5_dp*my_alpha, mat_g, mat_v, &
     778              :                                    1.0_dp, sparse_matrix, &
     779              :                                    retain_sparsity=my_keep_sparsity, &
     780        42274 :                                    last_k=ncol)
     781        78137 :             ELSE IF (my_symmetry_mode == -1) THEN
     782              :                ! Skewsymmetric mode
     783              :                CALL dbcsr_multiply("N", "T", 0.5_dp*my_alpha, mat_v, mat_g, &
     784              :                                    1.0_dp, sparse_matrix, &
     785              :                                    retain_sparsity=my_keep_sparsity, &
     786         2362 :                                    last_k=ncol)
     787              :                CALL dbcsr_multiply("N", "T", -0.5_dp*my_alpha, mat_g, mat_v, &
     788              :                                    1.0_dp, sparse_matrix, &
     789              :                                    retain_sparsity=my_keep_sparsity, &
     790         2362 :                                    last_k=ncol)
     791              :             ELSE
     792              :                ! Normal mode
     793              :                CALL dbcsr_multiply("N", "T", my_alpha, mat_v, mat_g, &
     794              :                                    1.0_dp, sparse_matrix, &
     795              :                                    retain_sparsity=my_keep_sparsity, &
     796        75775 :                                    last_k=ncol)
     797              :             END IF
     798              :          ELSE
     799              :             CALL dbcsr_multiply("N", "T", my_alpha, mat_v, mat_v, &
     800              :                                 1.0_dp, sparse_matrix, &
     801              :                                 retain_sparsity=my_keep_sparsity, &
     802       127537 :                                 last_k=ncol)
     803              :          END IF
     804              : 
     805              :          IF (check_product) THEN
     806              :             IF (PRESENT(matrix_g)) THEN
     807              :                IF (my_symmetry_mode == 1) THEN
     808              :                   CALL cp_fm_gemm("N", "T", nao, nao, ncol, 0.5_dp*my_alpha, matrix_v, matrix_g, &
     809              :                                   1.0_dp, fm_matrix)
     810              :                   CALL cp_fm_gemm("N", "T", nao, nao, ncol, 0.5_dp*my_alpha, matrix_g, matrix_v, &
     811              :                                   1.0_dp, fm_matrix)
     812              :                ELSE IF (my_symmetry_mode == -1) THEN
     813              :                   CALL cp_fm_gemm("N", "T", nao, nao, ncol, 0.5_dp*my_alpha, matrix_v, matrix_g, &
     814              :                                   1.0_dp, fm_matrix)
     815              :                   CALL cp_fm_gemm("N", "T", nao, nao, ncol, -0.5_dp*my_alpha, matrix_g, matrix_v, &
     816              :                                   1.0_dp, fm_matrix)
     817              :                ELSE
     818              :                   CALL cp_fm_gemm("N", "T", nao, nao, ncol, my_alpha, matrix_v, matrix_g, &
     819              :                                   1.0_dp, fm_matrix)
     820              :                END IF
     821              :             ELSE
     822              :                CALL cp_fm_gemm("N", "T", nao, nao, ncol, my_alpha, matrix_v, matrix_v, &
     823              :                                1.0_dp, fm_matrix)
     824              :             END IF
     825              : 
     826              :             CALL dbcsr_copy(sparse_matrix2, sparse_matrix)
     827              :             CALL dbcsr_scale(sparse_matrix2, alpha_scalar=0.0_dp)
     828              :             CALL copy_fm_to_dbcsr(fm_matrix, sparse_matrix2, keep_sparsity=my_keep_sparsity)
     829              :             CALL dbcsr_add(sparse_matrix2, sparse_matrix, alpha_scalar=1.0_dp, &
     830              :                            beta_scalar=-1.0_dp)
     831              :             norm = dbcsr_frobenius_norm(sparse_matrix2)
     832              :             WRITE (*, *) 'nao=', nao, ' k=', k, ' ncol=', ncol, ' my_alpha=', my_alpha
     833              :             WRITE (*, *) 'PRESENT (matrix_g)', PRESENT(matrix_g)
     834              :             WRITE (*, *) 'matrix_type=', dbcsr_get_matrix_type(sparse_matrix)
     835              :             WRITE (*, *) 'norm(sm+alpha*v*g^t - fm+alpha*v*g^t)/n=', norm/REAL(nao, dp)
     836              :             CALL dbcsr_release(sparse_matrix2)
     837              :             CALL dbcsr_release(sparse_matrix3)
     838              :             CALL cp_fm_release(fm_matrix)
     839              :          END IF
     840       247948 :          CALL dbcsr_release(mat_v)
     841       247948 :          IF (PRESENT(matrix_g)) CALL dbcsr_release(mat_g)
     842              :       END IF
     843       249520 :       CALL timestop(timing_handle)
     844              : 
     845       249520 :    END SUBROUTINE cp_dbcsr_plus_fm_fm_t
     846              : 
     847              : ! **************************************************************************************************
     848              : !> \brief Utility function to copy a specially shaped fm to dbcsr_matrix
     849              : !>        The result matrix will be the matrix in dbcsr format
     850              : !>        with the row blocks sizes according to the block_sizes of the template
     851              : !>        and the col blocks sizes evenly blocked with the internal dbcsr conversion
     852              : !>        size (32 is the current default)
     853              : !> \param matrix ...
     854              : !> \param fm_in ...
     855              : !> \param template ...
     856              : ! **************************************************************************************************
     857        15531 :    SUBROUTINE cp_fm_to_dbcsr_row_template(matrix, fm_in, template)
     858              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix
     859              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_in
     860              :       TYPE(dbcsr_type), INTENT(IN)                       :: template
     861              : 
     862              :       INTEGER                                            :: k_in
     863         5177 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size_right_in, row_blk_size
     864              :       TYPE(dbcsr_distribution_type)                      :: dist_right_in, tmpl_dist
     865              : 
     866         5177 :       CALL cp_fm_get_info(fm_in, ncol_global=k_in)
     867              : 
     868         5177 :       CALL dbcsr_get_info(template, distribution=tmpl_dist)
     869         5177 :       CALL dbcsr_create_dist_r_unrot(dist_right_in, tmpl_dist, k_in, col_blk_size_right_in)
     870         5177 :       CALL dbcsr_get_info(template, row_blk_size=row_blk_size)
     871              :       CALL dbcsr_create(matrix, "D", dist_right_in, dbcsr_type_no_symmetry, &
     872         5177 :                         row_blk_size, col_blk_size_right_in)
     873              : 
     874         5177 :       CALL copy_fm_to_dbcsr(fm_in, matrix)
     875         5177 :       DEALLOCATE (col_blk_size_right_in)
     876         5177 :       CALL dbcsr_distribution_release(dist_right_in)
     877              : 
     878         5177 :    END SUBROUTINE cp_fm_to_dbcsr_row_template
     879              : 
     880              : ! **************************************************************************************************
     881              : !> \brief Utility function to create an arbitrary shaped dbcsr matrix
     882              : !>        with the same processor grid as the template matrix
     883              : !>        both row sizes and col sizes are evenly blocked with the internal
     884              : !>        dbcsr_conversion size (32 is the current default)
     885              : !> \param matrix dbcsr matrix to be created
     886              : !> \param template template dbcsr matrix giving its mp_env
     887              : !> \param m global row size of output matrix
     888              : !> \param n global col size of output matrix
     889              : !> \param sym ...
     890              : ! **************************************************************************************************
     891       308656 :    SUBROUTINE cp_dbcsr_m_by_n_from_template(matrix, template, m, n, sym)
     892              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix, template
     893              :       INTEGER, INTENT(IN)                                :: m, n
     894              :       CHARACTER, INTENT(IN), OPTIONAL                    :: sym
     895              : 
     896              :       CHARACTER                                          :: mysym
     897              :       INTEGER                                            :: npcols, nprows
     898       154328 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size, col_dist, row_blk_size, &
     899       154328 :                                                             row_dist
     900              :       TYPE(dbcsr_distribution_type)                      :: dist_m_n, tmpl_dist
     901              : 
     902       154328 :       CALL dbcsr_get_info(template, matrix_type=mysym, distribution=tmpl_dist)
     903              : 
     904       154328 :       IF (PRESENT(sym)) mysym = sym
     905              : 
     906       154328 :       NULLIFY (row_dist, col_dist)
     907       154328 :       NULLIFY (row_blk_size, col_blk_size)
     908              :       !NULLIFY (row_cluster, col_cluster)
     909              : 
     910       154328 :       CALL dbcsr_distribution_get(tmpl_dist, nprows=nprows, npcols=npcols)
     911       154328 :       CALL create_bl_distribution(row_dist, row_blk_size, m, nprows)
     912       154328 :       CALL create_bl_distribution(col_dist, col_blk_size, n, npcols)
     913              :       CALL dbcsr_distribution_new(dist_m_n, template=tmpl_dist, &
     914              :                                   row_dist=row_dist, col_dist=col_dist, &
     915              :                                   !row_cluster=row_cluster, col_cluster=col_cluster, &
     916       154328 :                                   reuse_arrays=.TRUE.)
     917              : 
     918              :       CALL dbcsr_create(matrix, "m_n_template", dist_m_n, mysym, &
     919       154328 :                         row_blk_size, col_blk_size, reuse_arrays=.TRUE.)
     920       154328 :       CALL dbcsr_distribution_release(dist_m_n)
     921              : 
     922       154328 :    END SUBROUTINE cp_dbcsr_m_by_n_from_template
     923              : 
     924              : ! **************************************************************************************************
     925              : !> \brief Utility function to create dbcsr matrix, m x n matrix (n arbitrary)
     926              : !>        with the same processor grid and row distribution  as the template matrix
     927              : !>        col sizes are evenly blocked with the internal
     928              : !>        dbcsr_conversion size (32 is the current default)
     929              : !> \param matrix dbcsr matrix to be created
     930              : !> \param template template dbcsr matrix giving its mp_env
     931              : !> \param n global col size of output matrix
     932              : !> \param sym ...
     933              : ! **************************************************************************************************
     934       569472 :    SUBROUTINE cp_dbcsr_m_by_n_from_row_template(matrix, template, n, sym)
     935              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix, template
     936              :       INTEGER                                            :: n
     937              :       CHARACTER, OPTIONAL                                :: sym
     938              : 
     939              :       CHARACTER                                          :: mysym
     940              :       INTEGER                                            :: npcols
     941       142368 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size, col_dist, row_blk_size, &
     942       142368 :                                                             row_dist
     943              :       TYPE(dbcsr_distribution_type)                      :: dist_m_n, tmpl_dist
     944              : 
     945       284736 :       mysym = dbcsr_get_matrix_type(template)
     946       142368 :       IF (PRESENT(sym)) mysym = sym
     947              : 
     948       142368 :       CALL dbcsr_get_info(template, distribution=tmpl_dist)
     949              :       CALL dbcsr_distribution_get(tmpl_dist, &
     950              :                                   npcols=npcols, &
     951       142368 :                                   row_dist=row_dist)
     952              : 
     953       142368 :       NULLIFY (col_dist, col_blk_size)
     954       142368 :       CALL create_bl_distribution(col_dist, col_blk_size, n, npcols)
     955              :       CALL dbcsr_distribution_new(dist_m_n, template=tmpl_dist, &
     956       142368 :                                   row_dist=row_dist, col_dist=col_dist)
     957              : 
     958       142368 :       CALL dbcsr_get_info(template, row_blk_size=row_blk_size)
     959       142368 :       CALL dbcsr_create(matrix, "m_n_template", dist_m_n, mysym, row_blk_size, col_blk_size)
     960              : 
     961       142368 :       DEALLOCATE (col_dist, col_blk_size)
     962       142368 :       CALL dbcsr_distribution_release(dist_m_n)
     963              : 
     964       142368 :    END SUBROUTINE cp_dbcsr_m_by_n_from_row_template
     965              : 
     966              : ! **************************************************************************************************
     967              : !> \brief Distributes elements into blocks and into bins
     968              : !>
     969              : !> \param[out] block_distribution       block distribution to bins
     970              : !> \param[out] block_size       sizes of blocks
     971              : !> \param[in] nelements number of elements to bin
     972              : !> \param[in] nbins             number of bins
     973              : !> \par Term clarification
     974              : !>      An example: blocks are atom blocks and bins are process rows/columns.
     975              : ! **************************************************************************************************
     976      1219538 :    SUBROUTINE create_bl_distribution(block_distribution, &
     977              :                                      block_size, nelements, nbins)
     978              :       INTEGER, DIMENSION(:), INTENT(OUT), POINTER        :: block_distribution, block_size
     979              :       INTEGER, INTENT(IN)                                :: nelements, nbins
     980              : 
     981              :       CHARACTER(len=*), PARAMETER :: routineN = 'create_bl_distribution', &
     982              :          routineP = moduleN//':'//routineN
     983              : 
     984              :       INTEGER                                            :: bin, blk_layer, element_stack, els, &
     985              :                                                             estimated_blocks, max_blocks_per_bin, &
     986              :                                                             nblks, nblocks, stat
     987      1219538 :       INTEGER, DIMENSION(:), POINTER                     :: blk_dist, blk_sizes
     988              : 
     989              : !   ---------------------------------------------------------------------------
     990              : 
     991      1219538 :       NULLIFY (block_distribution)
     992      1219538 :       NULLIFY (block_size)
     993              :       ! Define the sizes on which we build the distribution.
     994      1219538 :       IF (nelements > 0) THEN
     995              : 
     996      1211446 :          nblocks = CEILING(REAL(nelements, KIND=dp)/REAL(max_elements_per_block, KIND=dp))
     997      1211446 :          max_blocks_per_bin = CEILING(REAL(nblocks, KIND=dp)/REAL(nbins, KIND=dp))
     998              : 
     999              :          IF (debug_mod) THEN
    1000              :             WRITE (*, '(1X,A,1X,A,I7,A,I7,A)') routineP, "For", nelements, &
    1001              :                " elements and", nbins, " bins"
    1002              :             WRITE (*, '(1X,A,1X,A,I7,A)') routineP, "There are", &
    1003              :                max_elements_per_block, " max elements per block"
    1004              :             WRITE (*, '(1X,A,1X,A,I7,A)') routineP, "There are", &
    1005              :                nblocks, " blocks"
    1006              :             WRITE (*, '(1X,A,1X,A,I7,A)') routineP, "There are", &
    1007              :                max_blocks_per_bin, " max blocks/bin"
    1008              :          END IF
    1009              : 
    1010      1211446 :          estimated_blocks = max_blocks_per_bin*nbins
    1011      3634338 :          ALLOCATE (blk_dist(estimated_blocks), stat=stat)
    1012      1211446 :          IF (stat /= 0) THEN
    1013            0 :             CPABORT("blk_dist")
    1014              :          END IF
    1015      2422892 :          ALLOCATE (blk_sizes(estimated_blocks), stat=stat)
    1016              :          IF (stat /= 0) THEN
    1017            0 :             CPABORT("blk_sizes")
    1018              :          END IF
    1019      1211446 :          element_stack = 0
    1020      1211446 :          nblks = 0
    1021      2504606 :          DO blk_layer = 1, max_blocks_per_bin
    1022      3932688 :             DO bin = 0, nbins - 1
    1023      1428082 :                els = MIN(max_elements_per_block, nelements - element_stack)
    1024      2721242 :                IF (els > 0) THEN
    1025      1304016 :                   element_stack = element_stack + els
    1026      1304016 :                   nblks = nblks + 1
    1027      1304016 :                   blk_dist(nblks) = bin
    1028      1304016 :                   blk_sizes(nblks) = els
    1029              :                   IF (debug_mod) WRITE (*, '(1X,A,I5,A,I5,A,I5)') routineP//" Assigning", &
    1030              :                      els, " elements as block", nblks, " to bin", bin
    1031              :                END IF
    1032              :             END DO
    1033              :          END DO
    1034              :          ! Create the output arrays.
    1035      1211446 :          IF (nblks == estimated_blocks) THEN
    1036      1087380 :             block_distribution => blk_dist
    1037      1087380 :             block_size => blk_sizes
    1038              :          ELSE
    1039       372198 :             ALLOCATE (block_distribution(nblks), stat=stat)
    1040              :             IF (stat /= 0) THEN
    1041            0 :                CPABORT("blk_dist")
    1042              :             END IF
    1043       499544 :             block_distribution(:) = blk_dist(1:nblks)
    1044       124066 :             DEALLOCATE (blk_dist)
    1045       248132 :             ALLOCATE (block_size(nblks), stat=stat)
    1046              :             IF (stat /= 0) THEN
    1047            0 :                CPABORT("blk_sizes")
    1048              :             END IF
    1049       499544 :             block_size(:) = blk_sizes(1:nblks)
    1050       124066 :             DEALLOCATE (blk_sizes)
    1051              :          END IF
    1052              :       ELSE
    1053         8092 :          ALLOCATE (block_distribution(0), stat=stat)
    1054              :          IF (stat /= 0) THEN
    1055            0 :             CPABORT("blk_dist")
    1056              :          END IF
    1057         8092 :          ALLOCATE (block_size(0), stat=stat)
    1058              :          IF (stat /= 0) THEN
    1059            0 :             CPABORT("blk_sizes")
    1060              :          END IF
    1061              :       END IF
    1062              : 1579  FORMAT(I5, 1X, I5, 1X, I5, 1X, I5, 1X, I5, 1X, I5, 1X, I5, 1X, I5, 1X, I5, 1X, I5)
    1063              :       IF (debug_mod) THEN
    1064              :          WRITE (*, '(1X,A,A)') routineP//" Distribution"
    1065              :          WRITE (*, 1579) block_distribution(:)
    1066              :          WRITE (*, '(1X,A,A)') routineP//" Sizes"
    1067              :          WRITE (*, 1579) block_size(:)
    1068              :       END IF
    1069      1219538 :    END SUBROUTINE create_bl_distribution
    1070              : 
    1071              : ! **************************************************************************************************
    1072              : !> \brief Creates a new distribution for the right matrix in a matrix
    1073              : !>        multiplication with unrotated grid.
    1074              : !> \param[out] dist_right     new distribution for the right matrix
    1075              : !> \param[in] dist_left       the distribution of the left matrix
    1076              : !> \param[in] ncolumns        number of columns in right matrix
    1077              : !> \param[out] right_col_blk_sizes      sizes of blocks in the created column
    1078              : !> \par The new row distribution for the right matrix is the same as the row
    1079              : !>      distribution of the left matrix, while the column distribution is
    1080              : !>      created so that it is appropriate to the parallel environment.
    1081              : ! **************************************************************************************************
    1082       520566 :    SUBROUTINE dbcsr_create_dist_r_unrot(dist_right, dist_left, ncolumns, &
    1083              :                                         right_col_blk_sizes)
    1084              :       TYPE(dbcsr_distribution_type), INTENT(OUT)         :: dist_right
    1085              :       TYPE(dbcsr_distribution_type), INTENT(IN)          :: dist_left
    1086              :       INTEGER, INTENT(IN)                                :: ncolumns
    1087              :       INTEGER, DIMENSION(:), INTENT(OUT), POINTER        :: right_col_blk_sizes
    1088              : 
    1089              :       INTEGER                                            :: multiplicity, ncols, nimages, npcols, &
    1090              :                                                             nprows
    1091              :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: tmp_images
    1092       520566 :       INTEGER, DIMENSION(:), POINTER                     :: old_col_dist, right_col_dist, &
    1093       520566 :                                                             right_row_dist
    1094              : 
    1095              :       CALL dbcsr_distribution_get(dist_left, &
    1096              :                                   ncols=ncols, &
    1097              :                                   col_dist=old_col_dist, &
    1098              :                                   nprows=nprows, &
    1099       520566 :                                   npcols=npcols)
    1100              : 
    1101              :       ! Create the column distribution
    1102       520566 :       CALL create_bl_distribution(right_col_dist, right_col_blk_sizes, ncolumns, npcols)
    1103              :       ! Create an even row distribution.
    1104      2082264 :       ALLOCATE (right_row_dist(ncols), tmp_images(ncols))
    1105       520566 :       nimages = lcm(nprows, npcols)/nprows
    1106       520566 :       multiplicity = nprows/gcd(nprows, npcols)
    1107       520566 :       CALL rebin_distribution(right_row_dist, tmp_images, old_col_dist, nprows, multiplicity, nimages)
    1108              : 
    1109              :       CALL dbcsr_distribution_new(dist_right, &
    1110              :                                   template=dist_left, &
    1111              :                                   row_dist=right_row_dist, &
    1112              :                                   col_dist=right_col_dist, &
    1113              :                                   !row_cluster=dummy,&
    1114              :                                   !col_cluster=dummy,&
    1115       520566 :                                   reuse_arrays=.TRUE.)
    1116       520566 :       DEALLOCATE (tmp_images)
    1117       520566 :    END SUBROUTINE dbcsr_create_dist_r_unrot
    1118              : 
    1119              : ! **************************************************************************************************
    1120              : !> \brief Makes new distribution with decimation and multiplicity
    1121              : !> \param[out] new_bins      new real distribution
    1122              : !> \param[out] images        new image distribution
    1123              : !> \param[in] source_bins    Basis for the new distribution and images
    1124              : !> \param[in] nbins          number of bins in the new real distribution
    1125              : !> \param[in] multiplicity   multiplicity
    1126              : !> \param[in] nimages        number of images in the new distribution
    1127              : !> \par Definition of multiplicity and nimages
    1128              : !>      Multiplicity and decimation (number of images) are used to
    1129              : !>      match process grid coordinates on non-square process
    1130              : !>      grids. Given source_nbins and target_nbins, their relation is
    1131              : !>                source_nbins * target_multiplicity
    1132              : !>              = target_nbins * target_nimages.
    1133              : !>      It is best when both multiplicity and nimages are small. To
    1134              : !>      get these two factors, then, one can use the following formulas:
    1135              : !>          nimages      = lcm(source_nbins, target_nbins) / target_nbins
    1136              : !>          multiplicity = target_nbins / gcd(source_nbins, target_nbins)
    1137              : !>      from the target's point of view (nimages = target_nimages).
    1138              : !> \par Mapping
    1139              : !>      The new distribution comprises of real bins and images within
    1140              : !>      bins. These can be view as target_nbins*nimages virtual
    1141              : !>      columns. These same virtual columns are also
    1142              : !>      source_nbins*multiplicity in number. Therefore these virtual
    1143              : !>      columns are mapped from source_nbins*multiplicity onto
    1144              : !>      target_bins*nimages (each target bin has nimages images):
    1145              : !>      Source 4: |1 2 3|4 5 6|7 8 9|A B C| (4*3)
    1146              : !>      Target 6: |1 2|3 4|5 6|7 8|9 A|B C| (6*2)
    1147              : !>      multiplicity=3, nimages=2, 12 virtual columns (1-C).
    1148              : !>      Source bin elements are evenly mapped into one of multiplicity
    1149              : !>      virtual columns. Other (non-even, block-size aware) mappings
    1150              : !>      could be better.
    1151              : ! **************************************************************************************************
    1152       520566 :    SUBROUTINE rebin_distribution(new_bins, images, source_bins, &
    1153              :                                  nbins, multiplicity, nimages)
    1154              :       INTEGER, DIMENSION(:), INTENT(OUT)                 :: new_bins, images
    1155              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: source_bins
    1156              :       INTEGER, INTENT(IN)                                :: nbins, multiplicity, nimages
    1157              : 
    1158              :       INTEGER                                            :: bin, i, old_nbins, virtual_bin
    1159       520566 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: bin_multiplier
    1160              : 
    1161              : !   ---------------------------------------------------------------------------
    1162              : 
    1163       520566 :       IF (MOD(nbins*nimages, multiplicity) /= 0) THEN
    1164            0 :          CPWARN("mulitplicity is not divisor of new process grid coordinate")
    1165              :       END IF
    1166       520566 :       old_nbins = (nbins*nimages)/multiplicity
    1167      1561698 :       ALLOCATE (bin_multiplier(0:old_nbins - 1))
    1168       520566 :       bin_multiplier(:) = 0
    1169      2472379 :       DO i = 1, SIZE(new_bins)
    1170      1951813 :          IF (i <= SIZE(source_bins)) THEN
    1171      1951813 :             bin = source_bins(i)
    1172              :          ELSE
    1173              :             ! Fill remainder with a cyclic distribution
    1174            0 :             bin = MOD(i, old_nbins)
    1175              :          END IF
    1176      1951813 :          virtual_bin = bin*multiplicity + bin_multiplier(bin)
    1177      1951813 :          new_bins(i) = virtual_bin/nimages
    1178      1951813 :          images(i) = 1 + MOD(virtual_bin, nimages)
    1179      1951813 :          bin_multiplier(bin) = bin_multiplier(bin) + 1
    1180      2472379 :          IF (bin_multiplier(bin) >= multiplicity) THEN
    1181       832841 :             bin_multiplier(bin) = 0
    1182              :          END IF
    1183              :       END DO
    1184       520566 :    END SUBROUTINE rebin_distribution
    1185              : 
    1186              : ! **************************************************************************************************
    1187              : !> \brief Creates a block-cyclic compatible distribution
    1188              : !>
    1189              : !>        All blocks in a dimension, except for possibly the last
    1190              : !>        block, have the same size.
    1191              : !> \param[out] dist           the elemental distribution
    1192              : !> \param[in] nrows           number of full rows
    1193              : !> \param[in] ncolumns        number of full columns
    1194              : !> \param[in] nrow_block      size of row blocks
    1195              : !> \param[in] ncol_block      size of column blocks
    1196              : !> \param group_handle ...
    1197              : !> \param pgrid ...
    1198              : !> \param[out] row_blk_sizes  row block sizes
    1199              : !> \param[out] col_blk_sizes  column block sizes
    1200              : ! **************************************************************************************************
    1201      3039920 :    SUBROUTINE dbcsr_create_dist_block_cyclic(dist, nrows, ncolumns, &
    1202              :                                              nrow_block, ncol_block, group_handle, pgrid, row_blk_sizes, col_blk_sizes)
    1203              :       TYPE(dbcsr_distribution_type), INTENT(OUT)         :: dist
    1204              :       INTEGER, INTENT(IN)                                :: nrows, ncolumns, nrow_block, ncol_block, &
    1205              :                                                             group_handle
    1206              :       INTEGER, DIMENSION(:, :), POINTER                  :: pgrid
    1207              :       INTEGER, DIMENSION(:), INTENT(OUT), POINTER        :: row_blk_sizes, col_blk_sizes
    1208              : 
    1209              :       CHARACTER(len=*), PARAMETER :: routineN = 'dbcsr_create_dist_block_cyclic'
    1210              : 
    1211              :       INTEGER                                            :: nblkcols, nblkrows, npcols, nprows, &
    1212              :                                                             pdim, sz
    1213      3039920 :       INTEGER, DIMENSION(:), POINTER                     :: cd_data, rd_data
    1214              : 
    1215              :       ! Row sizes
    1216      3039920 :       IF (nrow_block == 0) THEN
    1217              :          nblkrows = 0
    1218              :          sz = 0
    1219              :       ELSE
    1220      3039920 :          nblkrows = nrows/nrow_block
    1221      3039920 :          sz = MOD(nrows, nrow_block)
    1222              :       END IF
    1223      3039920 :       IF (sz > 0) nblkrows = nblkrows + 1
    1224     12158576 :       ALLOCATE (row_blk_sizes(nblkrows), rd_data(nblkrows))
    1225     12051622 :       row_blk_sizes = nrow_block
    1226      3039920 :       IF (sz /= 0) row_blk_sizes(nblkrows) = sz
    1227              : 
    1228              :       ! Column sizes
    1229      3039920 :       IF (ncol_block == 0) THEN
    1230              :          nblkcols = 0
    1231              :          sz = 0
    1232              :       ELSE
    1233      3039920 :          nblkcols = ncolumns/ncol_block
    1234      3039920 :          sz = MOD(ncolumns, ncol_block)
    1235              :       END IF
    1236      3039920 :       IF (sz > 0) nblkcols = nblkcols + 1
    1237     12156080 :       ALLOCATE (col_blk_sizes(nblkcols), cd_data(nblkcols))
    1238      9828594 :       col_blk_sizes = ncol_block
    1239      3039920 :       IF (sz /= 0) col_blk_sizes(nblkcols) = sz
    1240              :       !
    1241              :       IF (debug_mod) THEN
    1242              :          WRITE (*, *) routineN//" nrows,nrow_block,nblkrows=", &
    1243              :             nrows, nrow_block, nblkrows
    1244              :          WRITE (*, *) routineN//" ncols,ncol_block,nblkcols=", &
    1245              :             ncolumns, ncol_block, nblkcols
    1246              :       END IF
    1247              :       ! Calculate process row distribution
    1248      3039920 :       nprows = SIZE(pgrid, 1)
    1249      9045148 :       DO pdim = 0, MIN(nprows - 1, nblkrows - 1)
    1250     18056850 :          rd_data(1 + pdim:nblkrows:nprows) = pdim
    1251              :       END DO
    1252              :       ! Calculate process column distribution
    1253      3039920 :       npcols = SIZE(pgrid, 2)
    1254      6078040 :       DO pdim = 0, MIN(npcols - 1, nblkcols - 1)
    1255     12866714 :          cd_data(1 + pdim:nblkcols:npcols) = pdim
    1256              :       END DO
    1257              :       !
    1258              :       IF (debug_mod) THEN
    1259              :          WRITE (*, *) routineN//" row_dist", &
    1260              :             rd_data
    1261              :          WRITE (*, *) routineN//" col_dist", &
    1262              :             cd_data
    1263              :       END IF
    1264              :       !
    1265              :       CALL dbcsr_distribution_new(dist, &
    1266              :                                   group=group_handle, pgrid=pgrid, &
    1267              :                                   row_dist=rd_data, &
    1268              :                                   col_dist=cd_data, &
    1269      3039920 :                                   reuse_arrays=.TRUE.)
    1270              : 
    1271      3039920 :    END SUBROUTINE dbcsr_create_dist_block_cyclic
    1272              : 
    1273              : ! **************************************************************************************************
    1274              : !> \brief   Allocate and initialize a real matrix 1-dimensional set.
    1275              : !> \param[in,out] matrix_set  Set containing the DBCSR matrices
    1276              : !> \param[in] nmatrix         Size of set
    1277              : !> \par History
    1278              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1279              : ! **************************************************************************************************
    1280       196801 :    SUBROUTINE allocate_dbcsr_matrix_set_1d(matrix_set, nmatrix)
    1281              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_set
    1282              :       INTEGER, INTENT(IN)                                :: nmatrix
    1283              : 
    1284              :       INTEGER                                            :: imatrix
    1285              : 
    1286       196801 :       IF (ASSOCIATED(matrix_set)) CALL dbcsr_deallocate_matrix_set(matrix_set)
    1287      1365066 :       ALLOCATE (matrix_set(nmatrix))
    1288       971464 :       DO imatrix = 1, nmatrix
    1289       971464 :          NULLIFY (matrix_set(imatrix)%matrix)
    1290              :       END DO
    1291       196801 :    END SUBROUTINE allocate_dbcsr_matrix_set_1d
    1292              : 
    1293              : ! **************************************************************************************************
    1294              : !> \brief   Allocate and initialize a real matrix 2-dimensional set.
    1295              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1296              : !> \param[in] nmatrix         Size of set
    1297              : !> \param mmatrix ...
    1298              : !> \par History
    1299              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1300              : ! **************************************************************************************************
    1301       189726 :    SUBROUTINE allocate_dbcsr_matrix_set_2d(matrix_set, nmatrix, mmatrix)
    1302              :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_set
    1303              :       INTEGER, INTENT(IN)                                :: nmatrix, mmatrix
    1304              : 
    1305              :       INTEGER                                            :: imatrix, jmatrix
    1306              : 
    1307       189726 :       IF (ASSOCIATED(matrix_set)) CALL dbcsr_deallocate_matrix_set(matrix_set)
    1308      4292928 :       ALLOCATE (matrix_set(nmatrix, mmatrix))
    1309      1838816 :       DO jmatrix = 1, mmatrix
    1310      3723750 :          DO imatrix = 1, nmatrix
    1311      3534024 :             NULLIFY (matrix_set(imatrix, jmatrix)%matrix)
    1312              :          END DO
    1313              :       END DO
    1314       189726 :    END SUBROUTINE allocate_dbcsr_matrix_set_2d
    1315              : 
    1316              : ! **************************************************************************************************
    1317              : !> \brief   Allocate and initialize a real matrix 3-dimensional set.
    1318              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1319              : !> \param[in] nmatrix         Size of set
    1320              : !> \param mmatrix ...
    1321              : !> \param pmatrix ...
    1322              : !> \par History
    1323              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1324              : ! **************************************************************************************************
    1325            0 :    SUBROUTINE allocate_dbcsr_matrix_set_3d(matrix_set, nmatrix, mmatrix, pmatrix)
    1326              :       TYPE(dbcsr_p_type), DIMENSION(:, :, :), POINTER    :: matrix_set
    1327              :       INTEGER, INTENT(IN)                                :: nmatrix, mmatrix, pmatrix
    1328              : 
    1329              :       INTEGER                                            :: imatrix, jmatrix, kmatrix
    1330              : 
    1331            0 :       IF (ASSOCIATED(matrix_set)) CALL dbcsr_deallocate_matrix_set(matrix_set)
    1332            0 :       ALLOCATE (matrix_set(nmatrix, mmatrix, pmatrix))
    1333            0 :       DO kmatrix = 1, pmatrix
    1334            0 :          DO jmatrix = 1, mmatrix
    1335            0 :             DO imatrix = 1, nmatrix
    1336            0 :                NULLIFY (matrix_set(imatrix, jmatrix, kmatrix)%matrix)
    1337              :             END DO
    1338              :          END DO
    1339              :       END DO
    1340            0 :    END SUBROUTINE allocate_dbcsr_matrix_set_3d
    1341              : 
    1342              : ! **************************************************************************************************
    1343              : !> \brief   Allocate and initialize a real matrix 4-dimensional set.
    1344              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1345              : !> \param[in] nmatrix         Size of set
    1346              : !> \param mmatrix ...
    1347              : !> \param pmatrix ...
    1348              : !> \param qmatrix ...
    1349              : !> \par History
    1350              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1351              : ! **************************************************************************************************
    1352            0 :    SUBROUTINE allocate_dbcsr_matrix_set_4d(matrix_set, nmatrix, mmatrix, pmatrix, qmatrix)
    1353              :       TYPE(dbcsr_p_type), DIMENSION(:, :, :, :), POINTER :: matrix_set
    1354              :       INTEGER, INTENT(IN)                                :: nmatrix, mmatrix, pmatrix, qmatrix
    1355              : 
    1356              :       INTEGER                                            :: imatrix, jmatrix, kmatrix, lmatrix
    1357              : 
    1358            0 :       IF (ASSOCIATED(matrix_set)) CALL dbcsr_deallocate_matrix_set(matrix_set)
    1359            0 :       ALLOCATE (matrix_set(nmatrix, mmatrix, pmatrix, qmatrix))
    1360            0 :       DO lmatrix = 1, qmatrix
    1361            0 :       DO kmatrix = 1, pmatrix
    1362            0 :          DO jmatrix = 1, mmatrix
    1363            0 :             DO imatrix = 1, nmatrix
    1364            0 :                NULLIFY (matrix_set(imatrix, jmatrix, kmatrix, lmatrix)%matrix)
    1365              :             END DO
    1366              :          END DO
    1367              :       END DO
    1368              :       END DO
    1369            0 :    END SUBROUTINE allocate_dbcsr_matrix_set_4d
    1370              : 
    1371              : ! **************************************************************************************************
    1372              : !> \brief   Allocate and initialize a real matrix 5-dimensional set.
    1373              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1374              : !> \param[in] nmatrix         Size of set
    1375              : !> \param mmatrix ...
    1376              : !> \param pmatrix ...
    1377              : !> \param qmatrix ...
    1378              : !> \param smatrix ...
    1379              : !> \par History
    1380              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1381              : ! **************************************************************************************************
    1382            0 :    SUBROUTINE allocate_dbcsr_matrix_set_5d(matrix_set, nmatrix, mmatrix, pmatrix, qmatrix, smatrix)
    1383              :       TYPE(dbcsr_p_type), DIMENSION(:, :, :, :, :), &
    1384              :          POINTER                                         :: matrix_set
    1385              :       INTEGER, INTENT(IN)                                :: nmatrix, mmatrix, pmatrix, qmatrix, &
    1386              :                                                             smatrix
    1387              : 
    1388              :       INTEGER                                            :: hmatrix, imatrix, jmatrix, kmatrix, &
    1389              :                                                             lmatrix
    1390              : 
    1391            0 :       IF (ASSOCIATED(matrix_set)) CALL dbcsr_deallocate_matrix_set(matrix_set)
    1392            0 :       ALLOCATE (matrix_set(nmatrix, mmatrix, pmatrix, qmatrix, smatrix))
    1393            0 :       DO hmatrix = 1, smatrix
    1394            0 :       DO lmatrix = 1, qmatrix
    1395            0 :       DO kmatrix = 1, pmatrix
    1396            0 :          DO jmatrix = 1, mmatrix
    1397            0 :             DO imatrix = 1, nmatrix
    1398            0 :                NULLIFY (matrix_set(imatrix, jmatrix, kmatrix, lmatrix, hmatrix)%matrix)
    1399              :             END DO
    1400              :          END DO
    1401              :       END DO
    1402              :       END DO
    1403              :       END DO
    1404            0 :    END SUBROUTINE allocate_dbcsr_matrix_set_5d
    1405              : 
    1406              :    ! **************************************************************************************************
    1407              : !> \brief Deallocate a real matrix set and release all of the member matrices.
    1408              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1409              : !> \par History
    1410              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1411              : ! **************************************************************************************************
    1412       195552 :    SUBROUTINE deallocate_dbcsr_matrix_set_1d(matrix_set)
    1413              : 
    1414              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_set
    1415              : 
    1416              :       INTEGER                                            :: imatrix
    1417              : 
    1418       195552 :       IF (ASSOCIATED(matrix_set)) THEN
    1419       969392 :          DO imatrix = 1, SIZE(matrix_set)
    1420       969392 :             CALL dbcsr_deallocate_matrix(matrix_set(imatrix)%matrix)
    1421              :          END DO
    1422       193894 :          DEALLOCATE (matrix_set)
    1423              :       END IF
    1424              : 
    1425       195552 :    END SUBROUTINE deallocate_dbcsr_matrix_set_1d
    1426              : 
    1427              : ! **************************************************************************************************
    1428              : !> \brief Deallocate a real matrix set and release all of the member matrices.
    1429              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1430              : !> \par History
    1431              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1432              : ! **************************************************************************************************
    1433       194183 :    SUBROUTINE deallocate_dbcsr_matrix_set_2d(matrix_set)
    1434              : 
    1435              :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_set
    1436              : 
    1437              :       INTEGER                                            :: imatrix, jmatrix
    1438              : 
    1439       194183 :       IF (ASSOCIATED(matrix_set)) THEN
    1440      1849036 :          DO jmatrix = 1, SIZE(matrix_set, 2)
    1441      3744311 :             DO imatrix = 1, SIZE(matrix_set, 1)
    1442      3553152 :                CALL dbcsr_deallocate_matrix(matrix_set(imatrix, jmatrix)%matrix)
    1443              :             END DO
    1444              :          END DO
    1445       191159 :          DEALLOCATE (matrix_set)
    1446              :       END IF
    1447       194183 :    END SUBROUTINE deallocate_dbcsr_matrix_set_2d
    1448              : 
    1449              : ! **************************************************************************************************
    1450              : !> \brief Deallocate a real matrix set and release all of the member matrices.
    1451              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1452              : !> \par History
    1453              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1454              : ! **************************************************************************************************
    1455            0 :    SUBROUTINE deallocate_dbcsr_matrix_set_3d(matrix_set)
    1456              : 
    1457              :       TYPE(dbcsr_p_type), DIMENSION(:, :, :), POINTER    :: matrix_set
    1458              : 
    1459              :       INTEGER                                            :: imatrix, jmatrix, kmatrix
    1460              : 
    1461            0 :       IF (ASSOCIATED(matrix_set)) THEN
    1462            0 :          DO kmatrix = 1, SIZE(matrix_set, 3)
    1463            0 :             DO jmatrix = 1, SIZE(matrix_set, 2)
    1464            0 :                DO imatrix = 1, SIZE(matrix_set, 1)
    1465            0 :                   CALL dbcsr_deallocate_matrix(matrix_set(imatrix, jmatrix, kmatrix)%matrix)
    1466              :                END DO
    1467              :             END DO
    1468              :          END DO
    1469            0 :          DEALLOCATE (matrix_set)
    1470              :       END IF
    1471            0 :    END SUBROUTINE deallocate_dbcsr_matrix_set_3d
    1472              : 
    1473              : ! **************************************************************************************************
    1474              : !> \brief Deallocate a real matrix set and release all of the member matrices.
    1475              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1476              : !> \par History
    1477              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1478              : ! **************************************************************************************************
    1479            0 :    SUBROUTINE deallocate_dbcsr_matrix_set_4d(matrix_set)
    1480              : 
    1481              :       TYPE(dbcsr_p_type), DIMENSION(:, :, :, :), POINTER :: matrix_set
    1482              : 
    1483              :       INTEGER                                            :: imatrix, jmatrix, kmatrix, lmatrix
    1484              : 
    1485            0 :       IF (ASSOCIATED(matrix_set)) THEN
    1486            0 :          DO lmatrix = 1, SIZE(matrix_set, 4)
    1487            0 :          DO kmatrix = 1, SIZE(matrix_set, 3)
    1488            0 :             DO jmatrix = 1, SIZE(matrix_set, 2)
    1489            0 :                DO imatrix = 1, SIZE(matrix_set, 1)
    1490            0 :                   CALL dbcsr_deallocate_matrix(matrix_set(imatrix, jmatrix, kmatrix, lmatrix)%matrix)
    1491              :                END DO
    1492              :             END DO
    1493              :          END DO
    1494              :          END DO
    1495            0 :          DEALLOCATE (matrix_set)
    1496              :       END IF
    1497            0 :    END SUBROUTINE deallocate_dbcsr_matrix_set_4d
    1498              : 
    1499              : ! **************************************************************************************************
    1500              : !> \brief Deallocate a real matrix set and release all of the member matrices.
    1501              : !> \param[in,out] matrix_set  Set containing the DBCSR matrix pointer type
    1502              : !> \par History
    1503              : !>      2009-08-17 Adapted from sparse_matrix_type for DBCSR
    1504              : ! **************************************************************************************************
    1505            0 :    SUBROUTINE deallocate_dbcsr_matrix_set_5d(matrix_set)
    1506              : 
    1507              :       TYPE(dbcsr_p_type), DIMENSION(:, :, :, :, :), &
    1508              :          POINTER                                         :: matrix_set
    1509              : 
    1510              :       INTEGER                                            :: hmatrix, imatrix, jmatrix, kmatrix, &
    1511              :                                                             lmatrix
    1512              : 
    1513            0 :       IF (ASSOCIATED(matrix_set)) THEN
    1514            0 :          DO hmatrix = 1, SIZE(matrix_set, 5)
    1515            0 :             DO lmatrix = 1, SIZE(matrix_set, 4)
    1516            0 :             DO kmatrix = 1, SIZE(matrix_set, 3)
    1517            0 :                DO jmatrix = 1, SIZE(matrix_set, 2)
    1518            0 :                   DO imatrix = 1, SIZE(matrix_set, 1)
    1519            0 :                      CALL dbcsr_deallocate_matrix(matrix_set(imatrix, jmatrix, kmatrix, lmatrix, hmatrix)%matrix)
    1520              :                   END DO
    1521              :                END DO
    1522              :             END DO
    1523              :             END DO
    1524              :          END DO
    1525            0 :          DEALLOCATE (matrix_set)
    1526              :       END IF
    1527            0 :    END SUBROUTINE deallocate_dbcsr_matrix_set_5d
    1528              : 
    1529              : END MODULE cp_dbcsr_operations
        

Generated by: LCOV version 2.0-1