LCOV - code coverage report
Current view: top level - src/dbt - dbt_block.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:123285f) Lines: 93.9 % 179 168
Test Date: 2026-11-04 00:58:17 Functions: 85.7 % 35 30

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Methods to operate on n-dimensional tensor blocks.
      10              : !> \author Patrick Seewald
      11              : ! **************************************************************************************************
      12              : MODULE dbt_block
      13              : 
      14              :    #:include "dbt_macros.fypp"
      15              :    #:set maxdim = maxrank
      16              :    #:set ndims = range(2,maxdim+1)
      17              : 
      18              :    USE OMP_LIB, ONLY: omp_get_thread_num, omp_get_num_threads, omp_get_level
      19              :    USE util, ONLY: get_limit
      20              :    USE cp_dbcsr_api, ONLY: &
      21              :       dbcsr_type, dbcsr_release, &
      22              :       dbcsr_iterator_type, dbcsr_iterator_start, dbcsr_iterator_blocks_left, dbcsr_iterator_next_block, &
      23              :       dbcsr_has_symmetry, dbcsr_desymmetrize, dbcsr_get_num_blocks, dbcsr_iterator_stop, &
      24              :       dbcsr_reserve_blocks, dbcsr_finalize
      25              :    USE dbt_allocate_wrap, ONLY: &
      26              :       allocate_any
      27              :    USE dbt_tas_types, ONLY: &
      28              :       dbt_tas_iterator
      29              :    USE dbt_tas_base, ONLY: &
      30              :       dbt_tas_iterator_next_block, dbt_tas_iterator_blocks_left, dbt_tas_iterator_start, &
      31              :       dbt_tas_iterator_stop, dbt_tas_get_block_p, dbt_tas_put_block, dbt_tas_reserve_blocks, &
      32              :       dbt_tas_iterator_num_blocks
      33              :    USE kinds, ONLY: dp, int_8, dp
      34              :    USE dbt_index, ONLY: &
      35              :       nd_to_2d_mapping, ndims_mapping, get_nd_indices_tensor, destroy_nd_to_2d_mapping, get_2d_indices_tensor, &
      36              :       create_nd_to_2d_mapping
      37              :    USE dbt_array_list_methods, ONLY: &
      38              :       array_list, get_array_elements, destroy_array_list, sizes_of_arrays, create_array_list, &
      39              :       get_arrays
      40              :    USE dbt_types, ONLY: &
      41              :       dbt_type, ndims_tensor, dbt_blk_sizes, dbt_get_num_blocks, dbt_get_info, &
      42              :       dbt_finalize, ndims_matrix_row, ndims_matrix_column
      43              : 
      44              : #include "../base/base_uses.f90"
      45              : 
      46              :    IMPLICIT NONE
      47              :    PRIVATE
      48              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'dbt_block'
      49              : 
      50              :    PUBLIC :: &
      51              :       dbt_get_block_pattern, &
      52              :       block_nd, &
      53              :       create_block, &
      54              :       dbt_get_block, &
      55              :       dbt_iterator_num_blocks, &
      56              :       dbt_iterator_blocks_left, &
      57              :       dbt_iterator_next_block, &
      58              :       dbt_iterator_start, &
      59              :       dbt_iterator_stop, &
      60              :       dbt_iterator_type, &
      61              :       dbt_put_block, &
      62              :       dbt_reserve_blocks, &
      63              :       destroy_block, &
      64              :       checker_tr, &
      65              :       dbt_copy_block, &
      66              :       dbt_get_block_data, &
      67              :       dbt_put_block_data, &
      68              :       ndims_iterator
      69              : 
      70              :    TYPE dbt_iterator_type
      71              :       TYPE(dbt_tas_iterator)      :: iter
      72              :       TYPE(dbt_type), POINTER     :: tensor => NULL()
      73              :    END TYPE dbt_iterator_type
      74              : 
      75              :    TYPE block_nd
      76              :       INTEGER, DIMENSION(:), ALLOCATABLE   :: sizes
      77              :       REAL(dp), DIMENSION(:), ALLOCATABLE :: blk
      78              :    END TYPE block_nd
      79              : 
      80              :    INTERFACE create_block
      81              :       MODULE PROCEDURE create_block_data
      82              :       MODULE PROCEDURE create_block_nodata
      83              :    END INTERFACE create_block
      84              : 
      85              :    INTERFACE dbt_put_block
      86              :       #:for ndim in ndims
      87              :          MODULE PROCEDURE dbt_put_${ndim}$d_block
      88              :       #:endfor
      89              :       MODULE PROCEDURE dbt_put_anyd_block
      90              :    END INTERFACE dbt_put_block
      91              : 
      92              :    INTERFACE dbt_get_block
      93              :       #:for ndim in ndims
      94              :          MODULE PROCEDURE dbt_get_${ndim}$d_block
      95              :          MODULE PROCEDURE dbt_allocate_and_get_${ndim}$d_block
      96              :       #:endfor
      97              :       MODULE PROCEDURE dbt_get_anyd_block
      98              :    END INTERFACE dbt_get_block
      99              : 
     100              :    INTERFACE dbt_reserve_blocks
     101              :       MODULE PROCEDURE dbt_reserve_blocks_index
     102              :       MODULE PROCEDURE dbt_reserve_blocks_index_array
     103              :       MODULE PROCEDURE dbt_reserve_blocks_template
     104              :       MODULE PROCEDURE dbt_reserve_blocks_tensor_to_matrix
     105              :       MODULE PROCEDURE dbt_reserve_blocks_matrix_to_tensor
     106              :    END INTERFACE dbt_reserve_blocks
     107              : 
     108              : CONTAINS
     109              : 
     110              : ! **************************************************************************************************
     111              : !> \brief block size
     112              : !> \author Patrick Seewald
     113              : ! **************************************************************************************************
     114            0 :    FUNCTION block_size(block)
     115              :       TYPE(block_nd), INTENT(IN)         :: block
     116              :       INTEGER, ALLOCATABLE, DIMENSION(:) :: block_size
     117              : 
     118            0 :       ALLOCATE (block_size, source=block%sizes)
     119              :    END FUNCTION block_size
     120              : 
     121              : ! **************************************************************************************************
     122              : !> \brief Generalization of block_iterator_start for tensors.
     123              : !> \author Patrick Seewald
     124              : ! **************************************************************************************************
     125      2418760 :    SUBROUTINE dbt_iterator_start(iterator, tensor)
     126              :       TYPE(dbt_iterator_type), INTENT(OUT)           :: iterator
     127              :       TYPE(dbt_type), INTENT(IN), TARGET             :: tensor
     128              : 
     129      2418760 :       CPASSERT(tensor%valid)
     130      2418760 :       CALL dbt_tas_iterator_start(iterator%iter, tensor%matrix_rep)
     131      2418760 :       iterator%tensor => tensor
     132      2418760 :    END SUBROUTINE dbt_iterator_start
     133              : 
     134              : ! **************************************************************************************************
     135              : !> \brief Generalization of block_iterator_stop for tensors.
     136              : !> \author Patrick Seewald
     137              : ! **************************************************************************************************
     138      2418760 :    SUBROUTINE dbt_iterator_stop(iterator)
     139              :       TYPE(dbt_iterator_type), INTENT(INOUT) :: iterator
     140              : 
     141      2418760 :       CALL dbt_tas_iterator_stop(iterator%iter)
     142      2418760 :    END SUBROUTINE dbt_iterator_stop
     143              : 
     144              : ! **************************************************************************************************
     145              : !> \brief Number of dimensions.
     146              : !> \note specification function below must be defined before it is used in
     147              : !>       the source due to a bug in the IBM XL Fortran compiler (compilation fails)
     148              : !> \author Patrick Seewald
     149              : ! **************************************************************************************************
     150     57153330 :    PURE FUNCTION ndims_iterator(iterator)
     151              :       TYPE(dbt_iterator_type), INTENT(IN) :: iterator
     152              :       INTEGER                                 :: ndims_iterator
     153              : 
     154     57153330 :       ndims_iterator = iterator%tensor%nd_index%ndim_nd
     155     57153330 :    END FUNCTION ndims_iterator
     156              : 
     157              : ! **************************************************************************************************
     158              : !> \brief iterate over nd blocks of an nd rank tensor, index only (blocks must be retrieved by
     159              : !>        calling dbt_get_block on tensor).
     160              : !> \param ind_nd nd index of block
     161              : !> \param blk_size blk size in each dimension
     162              : !> \param blk_offset blk offset in each dimension
     163              : !> \author Patrick Seewald
     164              : ! **************************************************************************************************
     165     80896072 :    SUBROUTINE dbt_iterator_next_block(iterator, ind_nd, blk_size, blk_offset)
     166              :       !!
     167              :       TYPE(dbt_iterator_type), INTENT(INOUT)     :: iterator
     168              :       INTEGER, DIMENSION(ndims_iterator(iterator)), &
     169              :          INTENT(OUT)                                 :: ind_nd
     170              :       INTEGER, DIMENSION(ndims_iterator(iterator)), &
     171              :          INTENT(OUT), OPTIONAL                       :: blk_size, blk_offset
     172              : 
     173              :       INTEGER(KIND=int_8), DIMENSION(2)              :: ind_2d
     174              : 
     175     57153330 :       CALL dbt_tas_iterator_next_block(iterator%iter, ind_2d(1), ind_2d(2))
     176              : 
     177     57153330 :       ind_nd(:) = get_nd_indices_tensor(iterator%tensor%nd_index_blk, ind_2d)
     178     57153330 :       IF (PRESENT(blk_size)) blk_size(:) = get_array_elements(iterator%tensor%blk_sizes, ind_nd)
     179              :       ! note: blk_offset needs to be determined by tensor metadata, can not be derived from 2d row/col
     180              :       ! offset since block index mapping is not consistent with element index mapping
     181     57153330 :       IF (PRESENT(blk_offset)) blk_offset(:) = get_array_elements(iterator%tensor%blk_offsets, ind_nd)
     182              : 
     183     99537147 :    END SUBROUTINE dbt_iterator_next_block
     184              : 
     185              : ! **************************************************************************************************
     186              : !> \brief Generalization of block_iterator_num_blocks for tensors.
     187              : !> \author Ole Schuett
     188              : ! **************************************************************************************************
     189       208793 :    FUNCTION dbt_iterator_num_blocks(iterator)
     190              :       TYPE(dbt_iterator_type), INTENT(IN) :: iterator
     191              :       INTEGER                             :: dbt_iterator_num_blocks
     192              : 
     193       208793 :       dbt_iterator_num_blocks = dbt_tas_iterator_num_blocks(iterator%iter)
     194              : 
     195       208793 :    END FUNCTION dbt_iterator_num_blocks
     196              : 
     197              : ! **************************************************************************************************
     198              : !> \brief Generalization of block_iterator_blocks_left for tensors.
     199              : !> \author Patrick Seewald
     200              : ! **************************************************************************************************
     201     58944714 :    FUNCTION dbt_iterator_blocks_left(iterator)
     202              :       TYPE(dbt_iterator_type), INTENT(IN) :: iterator
     203              :       LOGICAL                                 :: dbt_iterator_blocks_left
     204              : 
     205     58944714 :       dbt_iterator_blocks_left = dbt_tas_iterator_blocks_left(iterator%iter)
     206              : 
     207     58944714 :    END FUNCTION dbt_iterator_blocks_left
     208              : 
     209              : ! **************************************************************************************************
     210              : !> \brief reserve blocks from indices as array object
     211              : !>        A serial caller starts an OpenMP team internally. An existing team calls collectively,
     212              : !>        with each thread providing its own part of the block list.
     213              : !> \author Patrick Seewald
     214              : ! **************************************************************************************************
     215       682592 :    RECURSIVE SUBROUTINE dbt_reserve_blocks_index_array(tensor, blk_ind)
     216              :       TYPE(dbt_type), INTENT(INOUT)   :: tensor
     217              :       INTEGER, DIMENSION(:, :), INTENT(IN) :: blk_ind
     218              :       INTEGER                             :: handle, block_range(2)
     219              :       LOGICAL                             :: inside_team
     220              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'dbt_reserve_blocks_index_array'
     221              : 
     222       682592 :       CALL timeset(routineN, handle)
     223              :       ! The array interface accepts a serial caller and keeps collective team calls intact.
     224       682592 :       inside_team = .TRUE.
     225       682592 : !$    inside_team = omp_get_level() > 0
     226       682592 :       IF (.NOT. inside_team) THEN
     227          136 : !$OMP PARALLEL DEFAULT(NONE) SHARED(tensor,blk_ind) PRIVATE(block_range)
     228              :          block_range = get_limit(SIZE(blk_ind, 1), omp_get_num_threads(), omp_get_thread_num())
     229              :          CALL dbt_reserve_blocks_index_array(tensor, blk_ind(block_range(1):block_range(2), :))
     230              : !$OMP END PARALLEL
     231              :       ELSE
     232              :          #:for ndim in ndims
     233      1364620 :             IF (ndims_tensor(tensor) == ${ndim}$) THEN
     234       682456 :                CALL dbt_reserve_blocks(tensor, ${arrlist("blk_ind", nmax=ndim, ndim_pre=1)}$)
     235              :             END IF
     236              :          #:endfor
     237              :       END IF
     238       682592 :       CALL timestop(handle)
     239              : 
     240       682592 :    END SUBROUTINE dbt_reserve_blocks_index_array
     241              : 
     242              : ! **************************************************************************************************
     243              : !> \brief Collect the global stored-block pattern projected onto two tensor dimensions.
     244              : !>        Called outside an OpenMP team; iteration and reduction are internal.
     245              : !> \param tensor source tensor
     246              : !> \param dimensions tensor dimensions retained in the projection
     247              : !> \param pattern output pattern, one for present entries and zero otherwise
     248              : ! **************************************************************************************************
     249          136 :    SUBROUTINE dbt_get_block_pattern(tensor, dimensions, pattern)
     250              :       TYPE(dbt_type), INTENT(IN) :: tensor
     251              :       INTEGER, INTENT(IN) :: dimensions(2)
     252              :       INTEGER, INTENT(OUT) :: pattern(:, :)
     253              : 
     254          272 :       INTEGER :: ind(ndims_tensor(tensor)), nblks(ndims_tensor(tensor))
     255              :       TYPE(dbt_iterator_type) :: iter
     256              : 
     257          136 :       CPASSERT(omp_get_level() == 0)
     258          680 :       CPASSERT(ALL(dimensions >= 1) .AND. ALL(dimensions <= SIZE(ind)))
     259          136 :       CALL dbt_get_info(tensor, nblks_total=nblks)
     260          408 :       CPASSERT(ALL(SHAPE(pattern) == nblks(dimensions)))
     261        38280 :       pattern = 0
     262          136 : !$OMP PARALLEL DEFAULT(NONE) SHARED(tensor,dimensions,pattern) PRIVATE(iter,ind)
     263              :       CALL dbt_iterator_start(iter, tensor)
     264              :       DO WHILE (dbt_iterator_blocks_left(iter))
     265              :          CALL dbt_iterator_next_block(iter, ind)
     266              : !$OMP ATOMIC WRITE
     267              :          pattern(ind(dimensions(1)), ind(dimensions(2))) = 1
     268              :       END DO
     269              :       CALL dbt_iterator_stop(iter)
     270              : !$OMP END PARALLEL
     271        76424 :       CALL tensor%pgrid%mp_comm_2d%max(pattern)
     272          136 :    END SUBROUTINE dbt_get_block_pattern
     273              : 
     274              : ! **************************************************************************************************
     275              : !> \brief reserve tensor blocks using block indices
     276              : !> \param blk_ind index of blocks to reserve in each dimension
     277              : !> \author Patrick Seewald
     278              : ! **************************************************************************************************
     279       798919 :    SUBROUTINE dbt_reserve_blocks_index(tensor, ${varlist("blk_ind")}$)
     280              :       TYPE(dbt_type), INTENT(INOUT)           :: tensor
     281              :       INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: ${varlist("blk_ind")}$
     282              :       INTEGER                                     :: iblk, nblk, handle
     283              :       INTEGER(KIND=int_8), ALLOCATABLE, DIMENSION(:)          :: cols, rows
     284              :       INTEGER(KIND=int_8), DIMENSION(2)                       :: ind_2d
     285       798919 :       TYPE(array_list)                            :: blks
     286      1597838 :       INTEGER, DIMENSION(ndims_tensor(tensor))   :: iblk_nd, ind_nd, nblk_tmp
     287              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'dbt_reserve_blocks_index'
     288              : 
     289       798919 :       CALL timeset(routineN, handle)
     290       798919 :       CPASSERT(tensor%valid)
     291              : 
     292              :       CALL create_array_list(blks, ndims_tensor(tensor), &
     293      1916251 :                              ${varlist("blk_ind")}$)
     294              : 
     295      2877263 :       nblk_tmp(:) = sizes_of_arrays(blks)
     296       798919 :       nblk = nblk_tmp(1)
     297      2929916 :       ALLOCATE (cols(nblk), rows(nblk))
     298     15783896 :       DO iblk = 1, nblk
     299     56718504 :          iblk_nd(:) = iblk
     300     14984977 :          ind_nd(:) = get_array_elements(blks, iblk_nd)
     301     14984977 :          ind_2d(:) = get_2d_indices_tensor(tensor%nd_index_blk, ind_nd)
     302     15783896 :          rows(iblk) = ind_2d(1); cols(iblk) = ind_2d(2)
     303              :       END DO
     304              : 
     305       798919 :       CALL dbt_tas_reserve_blocks(tensor%matrix_rep, rows=rows, columns=cols)
     306       798919 :       CALL dbt_finalize(tensor)
     307       798919 :       CALL timestop(handle)
     308      1597838 :    END SUBROUTINE dbt_reserve_blocks_index
     309              : 
     310              : ! **************************************************************************************************
     311              : !> \brief reserve tensor blocks using template
     312              : !> \param tensor_in template tensor
     313              : !> \author Patrick Seewald
     314              : ! **************************************************************************************************
     315        24382 :    SUBROUTINE dbt_reserve_blocks_template(tensor_in, tensor_out)
     316              :       TYPE(dbt_type), INTENT(IN)           :: tensor_in
     317              :       TYPE(dbt_type), INTENT(INOUT)        :: tensor_out
     318              : 
     319              :       CHARACTER(LEN=*), PARAMETER          :: routineN = 'dbt_reserve_blocks_template'
     320              : 
     321              :       TYPE(dbt_iterator_type)              :: iter
     322              :       INTEGER                              :: handle, nblk, iblk
     323        24382 :       INTEGER, DIMENSION(:, :), ALLOCATABLE :: blk_ind
     324              : 
     325        24382 :       CALL timeset(routineN, handle)
     326              : 
     327              : !$OMP PARALLEL DEFAULT(NONE) SHARED(tensor_in,tensor_out) &
     328        24382 : !$OMP PRIVATE(iter,nblk,iblk,blk_ind)
     329              :       CALL dbt_iterator_start(iter, tensor_in)
     330              :       nblk = dbt_iterator_num_blocks(iter)
     331              :       ALLOCATE (blk_ind(nblk, ndims_tensor(tensor_in)))
     332              :       DO iblk = 1, nblk
     333              :          CALL dbt_iterator_next_block(iter, ind_nd=blk_ind(iblk, :))
     334              :       END DO
     335              :       CPASSERT(.NOT. dbt_iterator_blocks_left(iter))
     336              :       CALL dbt_iterator_stop(iter)
     337              : 
     338              :       CALL dbt_reserve_blocks(tensor_out, blk_ind)
     339              : !$OMP END PARALLEL
     340              : 
     341        24382 :       CALL timestop(handle)
     342        48764 :    END SUBROUTINE dbt_reserve_blocks_template
     343              : 
     344              : ! **************************************************************************************************
     345              : !> \brief reserve tensor blocks using matrix template
     346              : !> \author Patrick Seewald
     347              : ! **************************************************************************************************
     348        97109 :    SUBROUTINE dbt_reserve_blocks_matrix_to_tensor(matrix_in, tensor_out)
     349              :       TYPE(dbcsr_type), TARGET, INTENT(IN)    :: matrix_in
     350              :       TYPE(dbt_type), INTENT(INOUT)  :: tensor_out
     351              :       TYPE(dbcsr_type), POINTER               :: matrix_in_desym
     352              : 
     353              :       INTEGER                            :: iblk, nblk, nblk_per_thread, a, b
     354        97109 :       INTEGER, ALLOCATABLE, DIMENSION(:) :: blk_ind_1, blk_ind_2
     355              :       INTEGER, DIMENSION(2)              :: ind_2d
     356              :       TYPE(dbcsr_iterator_type)          :: iter
     357              :       INTEGER                            :: handle
     358              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'dbt_reserve_blocks_matrix_to_tensor'
     359              : 
     360        97109 :       CALL timeset(routineN, handle)
     361              : 
     362        97109 :       IF (dbcsr_has_symmetry(matrix_in)) THEN
     363            0 :          ALLOCATE (matrix_in_desym)
     364            0 :          CALL dbcsr_desymmetrize(matrix_in, matrix_in_desym)
     365              :       ELSE
     366              :          matrix_in_desym => matrix_in
     367              :       END IF
     368              : 
     369        97109 :       nblk = dbcsr_get_num_blocks(matrix_in_desym)
     370       378704 :       ALLOCATE (blk_ind_1(nblk), blk_ind_2(nblk))
     371        97109 :       CALL dbcsr_iterator_start(iter, matrix_in_desym)
     372       392654 :       DO iblk = 1, nblk
     373       295545 :          CALL dbcsr_iterator_next_block(iter, ind_2d(1), ind_2d(2))
     374       392654 :          blk_ind_1(iblk) = ind_2d(1); blk_ind_2(iblk) = ind_2d(2)
     375              :       END DO
     376        97109 :       CALL dbcsr_iterator_stop(iter)
     377              : 
     378              : !TODO: Parallelize creation of block list.
     379              : !$OMP PARALLEL DEFAULT(NONE) SHARED(tensor_out,nblk,blk_ind_1,blk_ind_2) &
     380        97109 : !$OMP PRIVATE(nblk_per_thread,a,b)
     381              :       nblk_per_thread = nblk/omp_get_num_threads() + 1
     382              :       a = omp_get_thread_num()*nblk_per_thread + 1
     383              :       b = MIN(a + nblk_per_thread, nblk)
     384              :       CALL dbt_reserve_blocks(tensor_out, blk_ind_1(a:b), blk_ind_2(a:b))
     385              : !$OMP END PARALLEL
     386              : 
     387        97109 :       IF (dbcsr_has_symmetry(matrix_in)) THEN
     388            0 :          CALL dbcsr_release(matrix_in_desym)
     389            0 :          DEALLOCATE (matrix_in_desym)
     390              :       END IF
     391              : 
     392        97109 :       CALL timestop(handle)
     393       291327 :    END SUBROUTINE dbt_reserve_blocks_matrix_to_tensor
     394              : 
     395              : ! **************************************************************************************************
     396              : !> \brief reserve matrix blocks using tensor template
     397              : !> \author Patrick Seewald
     398              : ! **************************************************************************************************
     399        65292 :    SUBROUTINE dbt_reserve_blocks_tensor_to_matrix(tensor_in, matrix_out)
     400              :       TYPE(dbt_type), INTENT(IN)        :: tensor_in
     401              :       TYPE(dbcsr_type), INTENT(INOUT)            :: matrix_out
     402              :       TYPE(dbt_iterator_type)           :: iter
     403        65292 :       INTEGER, ALLOCATABLE, DIMENSION(:) :: blk_ind_1, blk_ind_2
     404              : 
     405              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'dbt_reserve_blocks_tensor_to_matrix'
     406              :       INTEGER :: handle, iblk, nblk
     407              :       INTEGER, DIMENSION(2)              :: ind_2d
     408              : 
     409        65292 :       CALL timeset(routineN, handle)
     410              : 
     411        65292 :       nblk = dbt_get_num_blocks(tensor_in)
     412       224420 :       ALLOCATE (blk_ind_1(nblk), blk_ind_2(nblk))
     413        65292 :       iblk = 0
     414              : 
     415              : !$OMP PARALLEL DEFAULT(NONE) SHARED(tensor_in,matrix_out,iblk,blk_ind_1,blk_ind_2) &
     416        65292 : !$OMP PRIVATE(iter,ind_2d)
     417              :       CALL dbt_iterator_start(iter, tensor_in)
     418              :       DO WHILE (dbt_iterator_blocks_left(iter))
     419              :          CALL dbt_iterator_next_block(iter, ind_2d)
     420              :          IF (dbcsr_has_symmetry(matrix_out)) THEN
     421              :             IF (checker_tr(ind_2d(1), ind_2d(2))) CYCLE
     422              :             IF (ind_2d(1) > ind_2d(2)) CALL swap(ind_2d(1), ind_2d(2))
     423              :          END IF
     424              : !$OMP CRITICAL(omp_dbt_reserve_blocks_tensor_to_matrix)
     425              :          iblk = iblk + 1
     426              :          blk_ind_1(iblk) = ind_2d(1)
     427              :          blk_ind_2(iblk) = ind_2d(2)
     428              : !$OMP END CRITICAL(omp_dbt_reserve_blocks_tensor_to_matrix)
     429              :       END DO
     430              :       CALL dbt_iterator_stop(iter)
     431              : !$OMP END PARALLEL
     432              : 
     433        65292 :       CALL dbcsr_reserve_blocks(matrix_out, blk_ind_1(:iblk), blk_ind_2(:iblk))
     434        65292 :       CALL dbcsr_finalize(matrix_out)
     435              : 
     436        65292 :       CALL timestop(handle)
     437       130584 :    END SUBROUTINE dbt_reserve_blocks_tensor_to_matrix
     438              : 
     439              : ! **************************************************************************************************
     440              : !> \brief Swaps two integers
     441              : !> \author Patrick Seewald
     442              : ! **************************************************************************************************
     443         5008 :    ELEMENTAL SUBROUTINE swap(a, b)
     444              :       INTEGER, INTENT(INOUT)                             :: a, b
     445              :       INTEGER                                            :: tmp
     446              : 
     447         5008 :       tmp = a
     448         5008 :       a = b
     449         5008 :       b = tmp
     450         5008 :    END SUBROUTINE swap
     451              : 
     452              : ! **************************************************************************************************
     453              : !> \brief Create block from array, array can be n-dimensional.
     454              : !> \author Patrick Seewald
     455              : ! **************************************************************************************************
     456            0 :    SUBROUTINE create_block_data(block, sizes, array)
     457              :       TYPE(block_nd), INTENT(OUT)                       :: block
     458              :       INTEGER, DIMENSION(:), INTENT(IN)                 :: sizes
     459              :       REAL(dp), DIMENSION(PRODUCT(sizes)), INTENT(IN) :: array
     460              : 
     461            0 :       ALLOCATE (block%sizes, source=sizes)
     462            0 :       ALLOCATE (block%blk, source=array)
     463            0 :    END SUBROUTINE create_block_data
     464              : 
     465              : ! **************************************************************************************************
     466              : !> \brief Create and allocate block, but no data.
     467              : !> \author Patrick Seewald
     468              : ! **************************************************************************************************
     469       206995 :    SUBROUTINE create_block_nodata(block, sizes)
     470              :       INTEGER, INTENT(IN), DIMENSION(:)       :: sizes
     471              :       TYPE(block_nd), INTENT(OUT) :: block
     472      1244696 :       ALLOCATE (block%sizes, source=sizes)
     473      1244098 :       ALLOCATE (block%blk(PRODUCT(sizes)))
     474       206995 :    END SUBROUTINE create_block_nodata
     475              : 
     476              : ! **************************************************************************************************
     477              : !> \brief
     478              : !> \author Patrick Seewald
     479              : ! **************************************************************************************************
     480       204067 :    SUBROUTINE destroy_block(block)
     481              :       TYPE(block_nd), INTENT(INOUT) :: block
     482       204067 :       DEALLOCATE (block%blk)
     483       204067 :       DEALLOCATE (block%sizes)
     484       204067 :    END SUBROUTINE destroy_block
     485              : 
     486              : ! **************************************************************************************************
     487              : !> \brief Determines whether a transpose must be applied
     488              : !> \param row The absolute matrix row.
     489              : !> \param column The absolute matrix column
     490              : !> \param
     491              : !> \param
     492              : !> \param
     493              : !> \param
     494              : !> \param
     495              : !> \param
     496              : !> \author Patrick Seewald
     497              : ! **************************************************************************************************
     498        43292 :    ELEMENTAL FUNCTION checker_tr(row, column) RESULT(transpose)
     499              :       INTEGER, INTENT(IN)                                :: row, column
     500              :       LOGICAL                                            :: transpose
     501              : 
     502        43292 :       transpose = BTEST(column + row, 0) .EQV. column >= row
     503              : 
     504        43292 :    END FUNCTION checker_tr
     505              : 
     506              : ! **************************************************************************************************
     507              : !> \brief Generic implementation of dbt_put_block, template for datatype
     508              : !> \param block block to put
     509              : !> \param summation whether block should be summed to existing block
     510              : !> \param ind block index
     511              : !> \param
     512              : !> \param
     513              : !> \param
     514              : !> \param
     515              : !> \param
     516              : !> \author Patrick Seewald
     517              : ! **************************************************************************************************
     518       204067 :    SUBROUTINE dbt_put_anyd_block(tensor, ind, block, summation)
     519              :       TYPE(block_nd), INTENT(IN)       :: block
     520              :       TYPE(dbt_type), INTENT(INOUT)            :: tensor
     521              :       LOGICAL, INTENT(IN), OPTIONAL                :: summation
     522              :       INTEGER, DIMENSION(ndims_tensor(tensor)), &
     523              :          INTENT(IN)                                :: ind
     524              : 
     525       204067 :       CALL dbt_put_block_data(tensor, ind, block%sizes, block%blk, summation=summation)
     526       204067 :    END SUBROUTINE dbt_put_anyd_block
     527              : 
     528              : ! **************************************************************************************************
     529              : !> \brief Generic implementation of dbt_get_block (arbitrary tensor rank)
     530              : !> \param block block to get
     531              : !> \param found whether block was found
     532              : !> \param ind block index
     533              : !> \param
     534              : !> \param
     535              : !> \param
     536              : !> \param
     537              : !> \param
     538              : !> \author Patrick Seewald
     539              : ! **************************************************************************************************
     540       206995 :    SUBROUTINE dbt_get_anyd_block(tensor, ind, block, found)
     541              :       TYPE(block_nd), INTENT(OUT)                  :: block
     542              :       LOGICAL, INTENT(OUT)                         :: found
     543              :       TYPE(dbt_type), INTENT(INOUT)            :: tensor
     544              :       INTEGER, DIMENSION(ndims_tensor(tensor)), &
     545              :          INTENT(IN)                                :: ind
     546       206995 :       INTEGER, DIMENSION(ndims_tensor(tensor))    :: blk_size
     547              : 
     548       206995 :       CALL dbt_blk_sizes(tensor, ind, blk_size)
     549       206995 :       CALL create_block(block, blk_size)
     550       206995 :       CALL dbt_get_block_data(tensor, ind, blk_size, block%blk, found)
     551       206995 :    END SUBROUTINE dbt_get_anyd_block
     552              : 
     553              : ! **************************************************************************************************
     554              : !> \brief Get a block into the given contiguous data (arbitrary tensor rank), without allocating
     555              : !>        any intermediate block.
     556              : !> \param ind block index
     557              : !> \param sizes block size
     558              : !> \param data block data
     559              : !> \param found whether block was found
     560              : !> \author Hans Pabst
     561              : ! **************************************************************************************************
     562     19535032 :    SUBROUTINE dbt_get_block_data(tensor, ind, sizes, data, found)
     563              :       TYPE(dbt_type), INTENT(INOUT)                        :: tensor
     564              :       INTEGER, DIMENSION(ndims_tensor(tensor)), INTENT(IN) :: ind, sizes
     565              :       REAL(dp), DIMENSION(PRODUCT(sizes)), INTENT(OUT)     :: data
     566              :       LOGICAL, INTENT(OUT)                                 :: found
     567              : 
     568      5150372 :       found = .FALSE.
     569      1070603 :       SELECT CASE (ndims_tensor(tensor))
     570              :          #:for ndim in ndims
     571              :             CASE (${ndim}$)
     572      5150372 :             CALL dbt_get_${ndim}$d_block(tensor, ind, sizes, data, found)
     573              :          #:endfor
     574              :       END SELECT
     575      5150372 :    END SUBROUTINE dbt_get_block_data
     576              : 
     577              : ! **************************************************************************************************
     578              : !> \brief Put a block from the given contiguous data (arbitrary tensor rank), without allocating
     579              : !>        any intermediate block.
     580              : !> \param ind block index
     581              : !> \param sizes block size
     582              : !> \param data block data
     583              : !> \param summation whether block should be summed to existing block
     584              : !> \author Hans Pabst
     585              : ! **************************************************************************************************
     586     19922532 :    SUBROUTINE dbt_put_block_data(tensor, ind, sizes, data, summation)
     587              :       TYPE(dbt_type), INTENT(INOUT)                        :: tensor
     588              :       INTEGER, DIMENSION(ndims_tensor(tensor)), INTENT(IN) :: ind, sizes
     589              :       REAL(dp), DIMENSION(PRODUCT(sizes)), INTENT(IN)      :: data
     590              :       LOGICAL, INTENT(IN), OPTIONAL                        :: summation
     591              : 
     592      1070555 :       SELECT CASE (ndims_tensor(tensor))
     593              :          #:for ndim in ndims
     594              :             CASE (${ndim}$)
     595      5247919 :             CALL dbt_put_${ndim}$d_block(tensor, ind, sizes, data, summation=summation)
     596              :          #:endfor
     597              :       END SELECT
     598      5247919 :    END SUBROUTINE dbt_put_block_data
     599              : 
     600              : ! **************************************************************************************************
     601              : !> \brief Copy a block between tensors with the same index mapping and block sizes (e.g., one
     602              : !>        created from the other), which needs no reshape since the matrix blocks are equal.
     603              : !> \param ind block index
     604              : !> \param summation whether block should be summed to existing block
     605              : !> \author Hans Pabst
     606              : ! **************************************************************************************************
     607      1185885 :    SUBROUTINE dbt_copy_block(tensor_in, tensor_out, ind, summation)
     608              :       TYPE(dbt_type), INTENT(INOUT)                           :: tensor_in, tensor_out
     609              :       INTEGER, DIMENSION(ndims_tensor(tensor_in)), INTENT(IN) :: ind
     610              :       LOGICAL, INTENT(IN), OPTIONAL                           :: summation
     611              : 
     612              :       INTEGER(KIND=int_8), DIMENSION(2)                       :: ind_2d
     613      1185885 :       REAL(dp), DIMENSION(:, :), POINTER, CONTIGUOUS          :: block_2d
     614              : 
     615      1185885 :       NULLIFY (block_2d)
     616      1185885 :       ind_2d(:) = get_2d_indices_tensor(tensor_in%nd_index_blk, ind)
     617      1185885 :       CALL dbt_tas_get_block_p(tensor_in%matrix_rep, ind_2d(1), ind_2d(2), block_2d)
     618      1185885 :       IF (ASSOCIATED(block_2d)) THEN
     619      1185885 :          CALL dbt_tas_put_block(tensor_out%matrix_rep, ind_2d(1), ind_2d(2), block_2d, summation=summation)
     620              :       END IF
     621      1185885 :    END SUBROUTINE dbt_copy_block
     622              : 
     623              :    #:for ndim in ndims
     624              : ! **************************************************************************************************
     625              : !> \brief Template for dbt_put_block.
     626              : !> \param ind block index
     627              : !> \param sizes block size
     628              : !> \param block block to put
     629              : !> \param summation whether block should be summed to existing block
     630              : !> \param
     631              : !> \param
     632              : !> \param
     633              : !> \param
     634              : !> \author Patrick Seewald
     635              : ! **************************************************************************************************
     636     17592085 :       SUBROUTINE dbt_put_${ndim}$d_block(tensor, ind, sizes, block, summation)
     637              :          TYPE(dbt_type), INTENT(INOUT)                     :: tensor
     638              :          INTEGER, DIMENSION(${ndim}$), INTENT(IN) :: ind
     639              :          INTEGER, DIMENSION(${ndim}$), INTENT(IN) :: sizes
     640              :          REAL(dp), DIMENSION(${arrlist("sizes", nmax=ndim)}$), &
     641              :             INTENT(IN), TARGET                                 :: block
     642              :          LOGICAL, INTENT(IN), OPTIONAL                         :: summation
     643              :          INTEGER(KIND=int_8), DIMENSION(2)                     :: ind_2d
     644              :          INTEGER, DIMENSION(2)                                 :: shape_2d
     645     17592085 :          REAL(dp), POINTER, DIMENSION(:, :)                   :: block_2d
     646              :          INTEGER, DIMENSION(${ndim}$)                          :: shape_nd
     647              :          LOGICAL :: found, new_block
     648     17592085 :          REAL(dp), DIMENSION(${arrlist("sizes", nmax=ndim)}$) :: block_check
     649              : 
     650              :          LOGICAL, PARAMETER :: debug = .FALSE.
     651              :          INTEGER :: i
     652              : 
     653     17592085 :          new_block = .FALSE.
     654              : 
     655              :          IF (debug) THEN
     656              :             CALL dbt_get_block(tensor, ind, sizes, block_check, found=found)
     657              :             CPASSERT(found)
     658              :          END IF
     659              : 
     660              :          ASSOCIATE (map_nd => tensor%nd_index_blk%map_nd, &
     661              :                     map1_2d => tensor%nd_index_blk%map1_2d, &
     662              :                     map2_2d => tensor%nd_index_blk%map2_2d)
     663              : 
     664    102267627 :             shape_2d = [PRODUCT(sizes(map1_2d)), PRODUCT(sizes(map2_2d))]
     665              : 
     666    150660896 :             IF (ALL([map1_2d, map2_2d] == [(i, i=1, ${ndim}$)])) THEN
     667              :                ! to avoid costly reshape can do pointer bounds remapping as long as arrays are equivalent in memory
     668     17134430 :                block_2d(1:shape_2d(1), 1:shape_2d(2)) => block(${shape_colon(ndim)}$)
     669              :             ELSE
     670              :                ! need reshape due to rank reordering
     671      1830620 :                ALLOCATE (block_2d(shape_2d(1), shape_2d(2)))
     672       457655 :                new_block = .TRUE.
     673      1819705 :                shape_nd(map_nd) = sizes
     674      4097065 :                block_2d(:, :) = RESHAPE(RESHAPE(block, SHAPE=shape_nd, order=map_nd), SHAPE=shape_2d)
     675              :             END IF
     676              : 
     677     35184170 :             ind_2d(:) = get_2d_indices_tensor(tensor%nd_index_blk, ind)
     678              : 
     679              :          END ASSOCIATE
     680              : 
     681     17592085 :          CALL dbt_tas_put_block(tensor%matrix_rep, ind_2d(1), ind_2d(2), block_2d, summation=summation)
     682              : 
     683     17592085 :          IF (new_block) DEALLOCATE (block_2d)
     684              : 
     685     17592085 :       END SUBROUTINE dbt_put_${ndim}$d_block
     686              :    #:endfor
     687              : 
     688              :    #:for ndim in ndims
     689              : ! **************************************************************************************************
     690              : !> \brief allocate and get block
     691              : !> \param ind block index
     692              : !> \param block block to get
     693              : !> \param found whether block was found
     694              : !> \param
     695              : !> \param
     696              : !> \param
     697              : !> \param
     698              : !> \param
     699              : !> \author Patrick Seewald
     700              : ! **************************************************************************************************
     701     26031678 :       SUBROUTINE dbt_allocate_and_get_${ndim}$d_block(tensor, ind, block, found)
     702              :          TYPE(dbt_type), INTENT(INOUT)                     :: tensor
     703              :          INTEGER, DIMENSION(${ndim}$), INTENT(IN)  :: ind
     704              :          REAL(dp), DIMENSION(${shape_colon(ndim)}$), &
     705              :             ALLOCATABLE, INTENT(OUT)                           :: block
     706              :          LOGICAL, INTENT(OUT)                                  :: found
     707              :          INTEGER, DIMENSION(${ndim}$)                          :: blk_size
     708              : 
     709     13015839 :          CALL dbt_blk_sizes(tensor, ind, blk_size)
     710     13015839 :          CALL allocate_any(block, shape_spec=blk_size)
     711     13015839 :          CALL dbt_get_${ndim}$d_block(tensor, ind, blk_size, block, found)
     712              : 
     713     13015839 :       END SUBROUTINE dbt_allocate_and_get_${ndim}$d_block
     714              :    #:endfor
     715              : 
     716              :    #:for ndim in ndims
     717              : ! **************************************************************************************************
     718              : !> \brief Template for dbt_get_block.
     719              : !> \param ind block index
     720              : !> \param sizes block size
     721              : !> \param block block to get
     722              : !> \param found whether block was found
     723              : !> \author Patrick Seewald
     724              : ! **************************************************************************************************
     725     18166723 :       SUBROUTINE dbt_get_${ndim}$d_block(tensor, ind, sizes, block, found)
     726              :          TYPE(dbt_type), INTENT(INOUT)                     :: tensor
     727              :          INTEGER, DIMENSION(${ndim}$), INTENT(IN) :: ind
     728              :          INTEGER, DIMENSION(${ndim}$), INTENT(IN) :: sizes
     729              :          REAL(dp), DIMENSION(${arrlist("sizes", nmax=ndim)}$), &
     730              :             INTENT(OUT)                                        :: block
     731              :          LOGICAL, INTENT(OUT)                                  :: found
     732              : 
     733              :          INTEGER(KIND=int_8), DIMENSION(2)                     :: ind_2d
     734     18166723 :          REAL(dp), DIMENSION(:, :), POINTER, CONTIGUOUS       :: block_2d_ptr
     735              :          INTEGER                                               :: i
     736     18166723 :          REAL(dp), DIMENSION(${shape_colon(ndim)}$), POINTER  :: block_ptr
     737              : 
     738     18166723 :          NULLIFY (block_2d_ptr)
     739              : 
     740     18166723 :          ind_2d(:) = get_2d_indices_tensor(tensor%nd_index_blk, ind)
     741              : 
     742              :          ASSOCIATE (map1_2d => tensor%nd_index_blk%map1_2d, &
     743              :                     map2_2d => tensor%nd_index_blk%map2_2d)
     744              : 
     745     18166723 :             CALL dbt_tas_get_block_p(tensor%matrix_rep, ind_2d(1), ind_2d(2), block_2d_ptr)
     746     18166723 :             found = ASSOCIATED(block_2d_ptr)
     747              : 
     748     18166723 :             IF (found) THEN
     749    137202733 :                IF (ALL([map1_2d, map2_2d] == [(i, i=1, ${ndim}$)])) THEN
     750              :                   ! to avoid costly reshape can do pointer bounds remapping as long as arrays are equivalent in memory
     751     40348680 :                   block_ptr(${shape_explicit('block', ndim)}$) => block_2d_ptr(:, :)
     752   6755277801 :                   block(${shape_colon(ndim)}$) = block_ptr(${shape_colon(ndim)}$)
     753              :                ELSE
     754              :                   ! need reshape due to rank reordering
     755     24982536 :                   block(${shape_colon(ndim)}$) = RESHAPE(block_2d_ptr, SHAPE=SHAPE(block), ORDER=[map1_2d, map2_2d])
     756              :                END IF
     757              :             END IF
     758              : 
     759              :          END ASSOCIATE
     760              : 
     761     18166723 :       END SUBROUTINE dbt_get_${ndim}$d_block
     762              :    #:endfor
     763              : 
     764            0 : END MODULE dbt_block
        

Generated by: LCOV version 2.0-1