LCOV - code coverage report
Current view: top level - src - cp_dbcsr_operations.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:15a58fb) Lines: 363 455 79.8 %
Date: 2025-02-18 08:24:35 Functions: 21 28 75.0 %

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

Generated by: LCOV version 1.15