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

Generated by: LCOV version 1.15