LCOV - code coverage report
Current view: top level - src - cp_dbcsr_operations.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:20da4d9) Lines: 355 447 79.4 %
Date: 2024-05-07 06:35:50 Functions: 25 32 78.1 %

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

Generated by: LCOV version 1.15