dbcsr_tensor_test.F Source File


Source Code

# 1 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F" 1
!--------------------------------------------------------------------------------------------------!
! Copyright (C) by the DBCSR developers group - All rights reserved                                !
! This file is part of the DBCSR library.                                                          !
!                                                                                                  !
! For information on the license, see the LICENSE file.                                            !
! For further information please visit https://dbcsr.cp2k.org                                      !
! SPDX-License-Identifier: GPL-2.0+                                                                !
!--------------------------------------------------------------------------------------------------!

MODULE dbcsr_tensor_test
   !! General methods for testing DBCSR tensors.

# 1 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor.fypp" 1
# 9 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor.fypp"

# 241 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor.fypp"
# 14 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F" 2
# 15 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
# 16 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

   USE dbcsr_api, ONLY: dbcsr_type_real_4, dbcsr_type_complex_4, dbcsr_type_complex_8, dbcsr_type_real_8
   USE dbcsr_tensor, ONLY: &
      dbcsr_t_copy, dbcsr_t_get_block, dbcsr_t_iterator_type, dbcsr_t_iterator_blocks_left, &
      dbcsr_t_iterator_next_block, dbcsr_t_iterator_start, dbcsr_t_iterator_stop, &
      dbcsr_t_reserve_blocks, dbcsr_t_get_stored_coordinates, dbcsr_t_put_block, &
      dbcsr_t_contract, dbcsr_t_inverse_order
   USE dbcsr_tensor_block, ONLY: block_nd
   USE dbcsr_tensor_types, ONLY: &
      dbcsr_t_create, dbcsr_t_destroy, dbcsr_t_type, dbcsr_t_distribution_type, dbcsr_t_distribution_destroy, &
      dims_tensor, ndims_tensor, dbcsr_t_distribution_new, dbcsr_t_get_data_type, &
      mp_environ_pgrid, dbcsr_t_pgrid_type, dbcsr_t_pgrid_create, dbcsr_t_pgrid_destroy, dbcsr_t_get_info, &
      dbcsr_t_default_distvec
   USE dbcsr_tensor_io, ONLY: &
      dbcsr_t_write_blocks, dbcsr_t_write_block_indices
   USE dbcsr_kinds, ONLY: real_8, real_4, &
                          default_string_length, &
                          int_8
   USE dbcsr_mpiwrap, ONLY: mp_environ, &
                            mp_comm_free, &
                            mp_sum, &
                            mp_comm_type
   USE dbcsr_allocate_wrap, ONLY: allocate_any
   USE dbcsr_tensor_index, ONLY: &
      combine_tensor_index, get_2d_indices_tensor, dbcsr_t_get_mapping_info
   USE dbcsr_tas_test, ONLY: dbcsr_tas_checksum
   USE dbcsr_data_types, ONLY: dbcsr_scalar_type
   USE dbcsr_blas_operations, ONLY: &
      set_larnv_seed
#include "base/dbcsr_base_uses.f90"

   IMPLICIT NONE
   PRIVATE
   CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'dbcsr_tensor_test'

   PUBLIC :: &
      dbcsr_t_setup_test_tensor, &
      dbcsr_t_contract_test, &
      dbcsr_t_test_formats, &
      dbcsr_t_checksum, &
      dbcsr_t_reset_randmat_seed

   INTERFACE dist_sparse_tensor_to_repl_dense_array
# 60 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
# 61 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            MODULE PROCEDURE dist_sparse_tensor_to_repl_dense_2d_array_r_dp
# 61 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            MODULE PROCEDURE dist_sparse_tensor_to_repl_dense_3d_array_r_dp
# 61 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            MODULE PROCEDURE dist_sparse_tensor_to_repl_dense_4d_array_r_dp
# 63 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
# 64 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
   END INTERFACE

   INTEGER, SAVE :: randmat_counter = 0
   INTEGER, PARAMETER, PRIVATE :: rand_seed_init = 12341313

CONTAINS

   FUNCTION dbcsr_t_equal(tensor1, tensor2)
      !! check if two (arbitrarily mapped and distributed) tensors are equal.
      TYPE(dbcsr_t_type), INTENT(INOUT)          :: tensor1, tensor2
      LOGICAL                                    :: dbcsr_t_equal

      INTEGER                                    :: blk
      TYPE(dbcsr_t_type)                         :: tensor2_tmp
      TYPE(dbcsr_t_iterator_type)                :: iter
      TYPE(block_nd)                             :: blk_data1, blk_data2
      INTEGER, DIMENSION(ndims_tensor(tensor1)) :: blk_size, ind_nd
      LOGICAL :: found

      ! create a copy of tensor2 that has exact same data format as tensor1
      CALL dbcsr_t_create(tensor1, tensor2_tmp)

      CALL dbcsr_t_reserve_blocks(tensor1, tensor2_tmp)
      CALL dbcsr_t_copy(tensor2, tensor2_tmp)

      dbcsr_t_equal = .TRUE.

      CALL dbcsr_t_iterator_start(iter, tensor1)

      DO WHILE (dbcsr_t_iterator_blocks_left(iter))
         CALL dbcsr_t_iterator_next_block(iter, ind_nd, blk, blk_size=blk_size)
         CALL dbcsr_t_get_block(tensor1, ind_nd, blk_data1, found)
         DBCSR_ASSERT(found)
         CALL dbcsr_t_get_block(tensor2_tmp, ind_nd, blk_data2, found)
         DBCSR_ASSERT(found)

         IF (.NOT. blocks_equal(blk_data1, blk_data2)) THEN
            dbcsr_t_equal = .FALSE.
         END IF
      END DO

      CALL dbcsr_t_iterator_stop(iter)

      CALL dbcsr_t_destroy(tensor2_tmp)
   END FUNCTION

   PURE FUNCTION blocks_equal(block1, block2)
      !! check if two blocks are equal
      TYPE(block_nd), INTENT(IN) :: block1, block2
      LOGICAL                    :: blocks_equal

      SELECT CASE (block1%data_type)
# 117 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            CASE (dbcsr_type_real_8)
            blocks_equal = MAXVAL(ABS(block1%r_dp%blk - block2%r_dp%blk)) .LT. 1.0E-12_real_8
# 117 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            CASE (dbcsr_type_real_4)
            blocks_equal = MAXVAL(ABS(block1%r_sp%blk - block2%r_sp%blk)) .LT. 1.0E-12_real_4
# 117 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            CASE (dbcsr_type_complex_8)
            blocks_equal = MAXVAL(ABS(block1%c_dp%blk - block2%c_dp%blk)) .LT. 1.0E-12_real_8
# 117 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            CASE (dbcsr_type_complex_4)
            blocks_equal = MAXVAL(ABS(block1%c_sp%blk - block2%c_sp%blk)) .LT. 1.0E-12_real_4
# 120 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
      END SELECT

   END FUNCTION

   PURE FUNCTION factorial(n)
      !! Compute factorial
      INTEGER, INTENT(IN) :: n
      INTEGER             :: k
      INTEGER             :: factorial
      factorial = PRODUCT((/(k, k=1, n)/))
   END FUNCTION

   SUBROUTINE permute(n, p)
      !! Compute all permutations p of (1, 2, ..., n)
      INTEGER, INTENT(IN)                              :: n
      INTEGER                                          :: i, c
      INTEGER, DIMENSION(n)                            :: pp
      INTEGER, DIMENSION(n, factorial(n)), INTENT(OUT) :: p

      pp = [(i, i=1, n)]
      c = 1
      CALL perm(1)
   CONTAINS
      RECURSIVE SUBROUTINE perm(i)
         INTEGER, INTENT(IN) :: i
         INTEGER :: j, t
         IF (i == n) THEN
            p(:, c) = pp(:)
            c = c + 1
         ELSE
            DO j = i, n
               t = pp(i)
               pp(i) = pp(j)
               pp(j) = t
               call perm(i + 1)
               t = pp(i)
               pp(i) = pp(j)
               pp(j) = t
            END DO
         END IF
      END SUBROUTINE
   END SUBROUTINE

   SUBROUTINE dbcsr_t_test_formats(ndims, mp_comm, unit_nr, verbose, &
                                   blk_size_1, blk_size_2, blk_size_3, blk_size_4, &
                                   blk_ind_1, blk_ind_2, blk_ind_3, blk_ind_4)
      !! Test equivalence of all tensor formats, using a random distribution.
      INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: blk_size_1, blk_size_2, blk_size_3, blk_size_4
         !! block sizes along respective dimension
      INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: blk_ind_1, blk_ind_2, blk_ind_3, blk_ind_4
         !! index along respective dimension of non-zero blocks
      INTEGER, INTENT(IN)                         :: ndims
         !! tensor rank
      INTEGER, INTENT(IN)                         :: unit_nr
         !! output unit, needs to be a valid unit number on all mpi ranks
      LOGICAL, INTENT(IN)                         :: verbose
         !! if .TRUE., print all tensor blocks
      TYPE(mp_comm_type), INTENT(IN)              :: mp_comm
      TYPE(dbcsr_t_distribution_type)             :: dist1, dist2
      TYPE(dbcsr_t_type)                          :: tensor1, tensor2
      INTEGER                                     :: isep, iblk
      INTEGER, DIMENSION(:), ALLOCATABLE          :: dist1_1, dist1_2, dist1_3, dist1_4, &
                                                     dist2_1, dist2_2, dist2_3, dist2_4
      INTEGER                                     :: nblks, imap
      INTEGER, DIMENSION(ndims)                   :: pdims, myploc
      LOGICAL                                     :: eql
      INTEGER                                     :: iperm, idist, icount
      INTEGER, DIMENSION(:), ALLOCATABLE          :: map1, map2, map1_ref, map2_ref
      INTEGER, DIMENSION(ndims, factorial(ndims)) :: perm
      INTEGER                                     :: io_unit
      INTEGER                                     :: mynode, numnodes
      TYPE(dbcsr_t_pgrid_type)                    :: comm_nd
      CHARACTER(LEN=default_string_length)        :: tensor_name

      ! Process grid
      pdims(:) = 0
      CALL dbcsr_t_pgrid_create(mp_comm, pdims, comm_nd)
      CALL mp_environ(numnodes, mynode, mp_comm)

      io_unit = 0
      IF (mynode .EQ. 0) io_unit = unit_nr

      CALL permute(ndims, perm)
      CALL allocate_any(map1_ref, source=perm(1:ndims/2, 1))
      CALL allocate_any(map2_ref, source=perm(ndims/2 + 1:ndims, 1))

      IF (io_unit > 0) THEN
         WRITE (io_unit, *)
         WRITE (io_unit, '(A)') repeat("-", 80)
         WRITE (io_unit, '(A,1X,I1)') "Testing matrix representations of tensor rank", ndims
         WRITE (io_unit, '(A)') repeat("-", 80)
         WRITE (io_unit, '(A)') "Block sizes:"

# 214 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            IF (ndims >= 1) THEN
               WRITE (io_unit, '(T4,A,1X,I1,A,1X)', advance='no') 'Dim', 1, ':'
               DO iblk = 1, SIZE(blk_size_1)
                  WRITE (io_unit, '(I2,1X)', advance='no') blk_size_1 (iblk)
               END DO
               WRITE (io_unit, *)
            END IF
# 214 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            IF (ndims >= 2) THEN
               WRITE (io_unit, '(T4,A,1X,I1,A,1X)', advance='no') 'Dim', 2, ':'
               DO iblk = 1, SIZE(blk_size_2)
                  WRITE (io_unit, '(I2,1X)', advance='no') blk_size_2 (iblk)
               END DO
               WRITE (io_unit, *)
            END IF
# 214 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            IF (ndims >= 3) THEN
               WRITE (io_unit, '(T4,A,1X,I1,A,1X)', advance='no') 'Dim', 3, ':'
               DO iblk = 1, SIZE(blk_size_3)
                  WRITE (io_unit, '(I2,1X)', advance='no') blk_size_3 (iblk)
               END DO
               WRITE (io_unit, *)
            END IF
# 214 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            IF (ndims >= 4) THEN
               WRITE (io_unit, '(T4,A,1X,I1,A,1X)', advance='no') 'Dim', 4, ':'
               DO iblk = 1, SIZE(blk_size_4)
                  WRITE (io_unit, '(I2,1X)', advance='no') blk_size_4 (iblk)
               END DO
               WRITE (io_unit, *)
            END IF
# 222 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

         WRITE (io_unit, '(A)') "Non-zero blocks:"
         DO iblk = 1, SIZE(blk_ind_1)
# 226 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (ndims == 2) THEN
                  WRITE (io_unit, '(T4,A, I3, A, 2I3, 1X, A)') &
                     'Block', iblk, ': (', blk_ind_1(iblk), blk_ind_2(iblk), ')'
               END IF
# 226 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (ndims == 3) THEN
                  WRITE (io_unit, '(T4,A, I3, A, 3I3, 1X, A)') &
                     'Block', iblk, ': (', blk_ind_1(iblk), blk_ind_2(iblk), blk_ind_3(iblk), ')'
               END IF
# 226 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (ndims == 4) THEN
                  WRITE (io_unit, '(T4,A, I3, A, 4I3, 1X, A)') &
                     'Block', iblk, ': (', blk_ind_1(iblk), blk_ind_2(iblk), blk_ind_3(iblk), blk_ind_4(iblk), ')'
               END IF
# 231 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         END DO

         WRITE (io_unit, *)
         WRITE (io_unit, '(A,1X)', advance='no') "Reference map:"
         WRITE (io_unit, '(A1,1X)', advance='no') "("
         DO imap = 1, SIZE(map1_ref)
            WRITE (io_unit, '(I1,1X)', advance='no') map1_ref(imap)
         END DO
         WRITE (io_unit, '(A1,1X)', advance='no') "|"
         DO imap = 1, SIZE(map2_ref)
            WRITE (io_unit, '(I1,1X)', advance='no') map2_ref(imap)
         END DO
         WRITE (io_unit, '(A1)') ")"

      END IF

      icount = 0
      DO iperm = 1, factorial(ndims)
         DO isep = 1, ndims - 1
            icount = icount + 1

            CALL allocate_any(map1, source=perm(1:isep, iperm))
            CALL allocate_any(map2, source=perm(isep + 1:ndims, iperm))

            CALL mp_environ(numnodes, mynode, mp_comm)
            CALL mp_environ_pgrid(comm_nd, pdims, myploc)

# 259 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (1 <= ndims) THEN
                  nblks = SIZE(blk_size_1)
                  ALLOCATE (dist1_1 (nblks))
                  ALLOCATE (dist2_1 (nblks))
                  CALL dbcsr_t_default_distvec(nblks, pdims(1), blk_size_1, dist1_1)
                  CALL dbcsr_t_default_distvec(nblks, pdims(1), blk_size_1, dist2_1)
               END IF
# 259 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (2 <= ndims) THEN
                  nblks = SIZE(blk_size_2)
                  ALLOCATE (dist1_2 (nblks))
                  ALLOCATE (dist2_2 (nblks))
                  CALL dbcsr_t_default_distvec(nblks, pdims(2), blk_size_2, dist1_2)
                  CALL dbcsr_t_default_distvec(nblks, pdims(2), blk_size_2, dist2_2)
               END IF
# 259 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (3 <= ndims) THEN
                  nblks = SIZE(blk_size_3)
                  ALLOCATE (dist1_3 (nblks))
                  ALLOCATE (dist2_3 (nblks))
                  CALL dbcsr_t_default_distvec(nblks, pdims(3), blk_size_3, dist1_3)
                  CALL dbcsr_t_default_distvec(nblks, pdims(3), blk_size_3, dist2_3)
               END IF
# 259 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (4 <= ndims) THEN
                  nblks = SIZE(blk_size_4)
                  ALLOCATE (dist1_4 (nblks))
                  ALLOCATE (dist2_4 (nblks))
                  CALL dbcsr_t_default_distvec(nblks, pdims(4), blk_size_4, dist1_4)
                  CALL dbcsr_t_default_distvec(nblks, pdims(4), blk_size_4, dist2_4)
               END IF
# 267 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

            WRITE (tensor_name, '(A,1X,I3,1X)') "Test", icount

            IF (io_unit > 0) THEN
               WRITE (io_unit, *)
               WRITE (io_unit, '(A,A,1X)', advance='no') TRIM(tensor_name), ':'
               WRITE (io_unit, '(A1,1X)', advance='no') "("
               DO imap = 1, SIZE(map1)
                  WRITE (io_unit, '(I1,1X)', advance='no') map1(imap)
               END DO
               WRITE (io_unit, '(A1,1X)', advance='no') "|"
               DO imap = 1, SIZE(map2)
                  WRITE (io_unit, '(I1,1X)', advance='no') map2(imap)
               END DO
               WRITE (io_unit, '(A1)') ")"

               WRITE (io_unit, '(T4,A)') "Reference distribution:"
# 285 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  IF (1 <= ndims) THEN
                     WRITE (io_unit, '(T7,A,1X)', advance='no') "Dist vec 1:"
                     DO idist = 1, SIZE(dist2_1)
                        WRITE (io_unit, '(I2,1X)', advance='no') dist2_1 (idist)
                     END DO
                     WRITE (io_unit, *)
                  END IF
# 285 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  IF (2 <= ndims) THEN
                     WRITE (io_unit, '(T7,A,1X)', advance='no') "Dist vec 2:"
                     DO idist = 1, SIZE(dist2_2)
                        WRITE (io_unit, '(I2,1X)', advance='no') dist2_2 (idist)
                     END DO
                     WRITE (io_unit, *)
                  END IF
# 285 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  IF (3 <= ndims) THEN
                     WRITE (io_unit, '(T7,A,1X)', advance='no') "Dist vec 3:"
                     DO idist = 1, SIZE(dist2_3)
                        WRITE (io_unit, '(I2,1X)', advance='no') dist2_3 (idist)
                     END DO
                     WRITE (io_unit, *)
                  END IF
# 285 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  IF (4 <= ndims) THEN
                     WRITE (io_unit, '(T7,A,1X)', advance='no') "Dist vec 4:"
                     DO idist = 1, SIZE(dist2_4)
                        WRITE (io_unit, '(I2,1X)', advance='no') dist2_4 (idist)
                     END DO
                     WRITE (io_unit, *)
                  END IF
# 293 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

               WRITE (io_unit, '(T4,A)') "Test distribution:"
# 296 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  IF (1 <= ndims) THEN
                     WRITE (io_unit, '(T7,A,1X)', advance='no') "Dist vec 1:"
                     DO idist = 1, SIZE(dist2_1)
                        WRITE (io_unit, '(I2,1X)', advance='no') dist1_1 (idist)
                     END DO
                     WRITE (io_unit, *)
                  END IF
# 296 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  IF (2 <= ndims) THEN
                     WRITE (io_unit, '(T7,A,1X)', advance='no') "Dist vec 2:"
                     DO idist = 1, SIZE(dist2_2)
                        WRITE (io_unit, '(I2,1X)', advance='no') dist1_2 (idist)
                     END DO
                     WRITE (io_unit, *)
                  END IF
# 296 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  IF (3 <= ndims) THEN
                     WRITE (io_unit, '(T7,A,1X)', advance='no') "Dist vec 3:"
                     DO idist = 1, SIZE(dist2_3)
                        WRITE (io_unit, '(I2,1X)', advance='no') dist1_3 (idist)
                     END DO
                     WRITE (io_unit, *)
                  END IF
# 296 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  IF (4 <= ndims) THEN
                     WRITE (io_unit, '(T7,A,1X)', advance='no') "Dist vec 4:"
                     DO idist = 1, SIZE(dist2_4)
                        WRITE (io_unit, '(I2,1X)', advance='no') dist1_4 (idist)
                     END DO
                     WRITE (io_unit, *)
                  END IF
# 304 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            END IF

# 307 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (ndims == 2) THEN
                  CALL dbcsr_t_distribution_new(dist2, comm_nd, dist2_1, dist2_2)
                  CALL dbcsr_t_create(tensor2, "Ref", dist2, map1_ref, map2_ref, &
                                      dbcsr_type_real_8, blk_size_1, blk_size_2)
                  CALL dbcsr_t_setup_test_tensor(tensor2, comm_nd%mp_comm_2d, .TRUE., blk_ind_1, blk_ind_2)
               END IF
# 307 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (ndims == 3) THEN
                  CALL dbcsr_t_distribution_new(dist2, comm_nd, dist2_1, dist2_2, dist2_3)
                  CALL dbcsr_t_create(tensor2, "Ref", dist2, map1_ref, map2_ref, &
                                      dbcsr_type_real_8, blk_size_1, blk_size_2, blk_size_3)
                  CALL dbcsr_t_setup_test_tensor(tensor2, comm_nd%mp_comm_2d, .TRUE., blk_ind_1, blk_ind_2, blk_ind_3)
               END IF
# 307 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (ndims == 4) THEN
                  CALL dbcsr_t_distribution_new(dist2, comm_nd, dist2_1, dist2_2, dist2_3, dist2_4)
                  CALL dbcsr_t_create(tensor2, "Ref", dist2, map1_ref, map2_ref, &
                                      dbcsr_type_real_8, blk_size_1, blk_size_2, blk_size_3, blk_size_4)
                  CALL dbcsr_t_setup_test_tensor(tensor2, comm_nd%mp_comm_2d, .TRUE., blk_ind_1, blk_ind_2, blk_ind_3, blk_ind_4)
               END IF
# 314 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

            IF (verbose) CALL dbcsr_t_write_blocks(tensor2, io_unit, unit_nr)

# 318 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (ndims == 2) THEN
                  CALL dbcsr_t_distribution_new(dist1, comm_nd, dist1_1, dist1_2)
                  CALL dbcsr_t_create(tensor1, tensor_name, dist1, map1, map2, &
                                      dbcsr_type_real_8, blk_size_1, blk_size_2)
                  CALL dbcsr_t_setup_test_tensor(tensor1, comm_nd%mp_comm_2d, .TRUE., blk_ind_1, blk_ind_2)
               END IF
# 318 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (ndims == 3) THEN
                  CALL dbcsr_t_distribution_new(dist1, comm_nd, dist1_1, dist1_2, dist1_3)
                  CALL dbcsr_t_create(tensor1, tensor_name, dist1, map1, map2, &
                                      dbcsr_type_real_8, blk_size_1, blk_size_2, blk_size_3)
                  CALL dbcsr_t_setup_test_tensor(tensor1, comm_nd%mp_comm_2d, .TRUE., blk_ind_1, blk_ind_2, blk_ind_3)
               END IF
# 318 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (ndims == 4) THEN
                  CALL dbcsr_t_distribution_new(dist1, comm_nd, dist1_1, dist1_2, dist1_3, dist1_4)
                  CALL dbcsr_t_create(tensor1, tensor_name, dist1, map1, map2, &
                                      dbcsr_type_real_8, blk_size_1, blk_size_2, blk_size_3, blk_size_4)
                  CALL dbcsr_t_setup_test_tensor(tensor1, comm_nd%mp_comm_2d, .TRUE., blk_ind_1, blk_ind_2, blk_ind_3, blk_ind_4)
               END IF
# 325 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

            IF (verbose) CALL dbcsr_t_write_blocks(tensor1, io_unit, unit_nr)

            eql = dbcsr_t_equal(tensor1, tensor2)

            IF (.NOT. eql) THEN
               IF (io_unit > 0) WRITE (io_unit, '(A,1X,A)') TRIM(tensor_name), 'Test failed!'
               DBCSR_ABORT('')
            ELSE
               IF (io_unit > 0) WRITE (io_unit, '(A,1X,A)') TRIM(tensor_name), 'Test passed!'
            END IF
            DEALLOCATE (map1, map2)

            CALL dbcsr_t_destroy(tensor1)
            CALL dbcsr_t_distribution_destroy(dist1)

            CALL dbcsr_t_destroy(tensor2)
            CALL dbcsr_t_distribution_destroy(dist2)

# 345 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (1 <= ndims) THEN
                  DEALLOCATE (dist1_1, dist2_1)
               END IF
# 345 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (2 <= ndims) THEN
                  DEALLOCATE (dist1_2, dist2_2)
               END IF
# 345 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (3 <= ndims) THEN
                  DEALLOCATE (dist1_3, dist2_3)
               END IF
# 345 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (4 <= ndims) THEN
                  DEALLOCATE (dist1_4, dist2_4)
               END IF
# 349 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

         END DO
      END DO
      CALL dbcsr_t_pgrid_destroy(comm_nd)
   END SUBROUTINE

   SUBROUTINE dbcsr_t_setup_test_tensor(tensor, mp_comm, enumerate, blk_ind_1, blk_ind_2, blk_ind_3, blk_ind_4)
      !! Allocate and fill test tensor - entries are enumerated by their index s.t. they only depend
      !! on global properties of the tensor but not on distribution, matrix representation, etc.
      TYPE(dbcsr_t_type), INTENT(INOUT)                  :: tensor
      TYPE(mp_comm_type), INTENT(IN)                                :: mp_comm
         !! communicator
      LOGICAL, INTENT(IN)                                :: enumerate
      INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL        :: blk_ind_1, blk_ind_2, blk_ind_3, blk_ind_4
         !! index along respective dimension of non-zero blocks
      INTEGER                                            :: blk, numnodes, mynode

      INTEGER                                            :: i, ib, my_nblks_alloc, nblks_alloc, proc, nze
      INTEGER, ALLOCATABLE, DIMENSION(:)                 :: my_blk_ind_1, my_blk_ind_2, my_blk_ind_3, my_blk_ind_4
      INTEGER, DIMENSION(ndims_tensor(tensor))          :: blk_index, blk_offset, blk_size, &
                                                           tensor_dims
      INTEGER, DIMENSION(:, :), ALLOCATABLE               :: ind_nd
# 372 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         REAL(KIND=real_8), ALLOCATABLE, &
            DIMENSION(:,:)                :: blk_values_2
# 372 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         REAL(KIND=real_8), ALLOCATABLE, &
            DIMENSION(:,:,:)                :: blk_values_3
# 372 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         REAL(KIND=real_8), ALLOCATABLE, &
            DIMENSION(:,:,:,:)                :: blk_values_4
# 375 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
      TYPE(dbcsr_t_iterator_type)                        :: iterator
      INTEGER, DIMENSION(4)                              :: iseed
      INTEGER, DIMENSION(2)                              :: blk_index_2d, nblks_2d

      nblks_alloc = SIZE(blk_ind_1)
      CALL mp_environ(numnodes, mynode, mp_comm)

      IF (.NOT. enumerate) THEN
         DBCSR_ASSERT(randmat_counter .NE. 0)

         randmat_counter = randmat_counter + 1
      END IF

      ALLOCATE (ind_nd(nblks_alloc, ndims_tensor(tensor)))
      my_nblks_alloc = 0
      DO ib = 1, nblks_alloc
# 392 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            IF (ndims_tensor(tensor) == 2) THEN
               ind_nd(ib, :) = [blk_ind_1(ib), blk_ind_2(ib)]
            END IF
# 392 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            IF (ndims_tensor(tensor) == 3) THEN
               ind_nd(ib, :) = [blk_ind_1(ib), blk_ind_2(ib), blk_ind_3(ib)]
            END IF
# 392 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            IF (ndims_tensor(tensor) == 4) THEN
               ind_nd(ib, :) = [blk_ind_1(ib), blk_ind_2(ib), blk_ind_3(ib), blk_ind_4(ib)]
            END IF
# 396 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         CALL dbcsr_t_get_stored_coordinates(tensor, ind_nd(ib, :), proc)
         IF (proc == mynode) THEN
            my_nblks_alloc = my_nblks_alloc + 1
         END IF
      END DO

# 403 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         IF (ndims_tensor(tensor) >= 1) THEN
            ALLOCATE (my_blk_ind_1 (my_nblks_alloc))
         END IF
# 403 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         IF (ndims_tensor(tensor) >= 2) THEN
            ALLOCATE (my_blk_ind_2 (my_nblks_alloc))
         END IF
# 403 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         IF (ndims_tensor(tensor) >= 3) THEN
            ALLOCATE (my_blk_ind_3 (my_nblks_alloc))
         END IF
# 403 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         IF (ndims_tensor(tensor) >= 4) THEN
            ALLOCATE (my_blk_ind_4 (my_nblks_alloc))
         END IF
# 407 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

      i = 0
      DO ib = 1, nblks_alloc
         CALL dbcsr_t_get_stored_coordinates(tensor, ind_nd(ib, :), proc)
         IF (proc == mynode) THEN
            i = i + 1
# 414 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (ndims_tensor(tensor) >= 1) THEN
                  my_blk_ind_1 (i) = blk_ind_1 (ib)
               END IF
# 414 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (ndims_tensor(tensor) >= 2) THEN
                  my_blk_ind_2 (i) = blk_ind_2 (ib)
               END IF
# 414 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (ndims_tensor(tensor) >= 3) THEN
                  my_blk_ind_3 (i) = blk_ind_3 (ib)
               END IF
# 414 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               IF (ndims_tensor(tensor) >= 4) THEN
                  my_blk_ind_4 (i) = blk_ind_4 (ib)
               END IF
# 418 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         END IF
      END DO

# 422 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         IF (ndims_tensor(tensor) == 2) THEN
            CALL dbcsr_t_reserve_blocks(tensor, my_blk_ind_1, my_blk_ind_2)
         END IF
# 422 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         IF (ndims_tensor(tensor) == 3) THEN
            CALL dbcsr_t_reserve_blocks(tensor, my_blk_ind_1, my_blk_ind_2, my_blk_ind_3)
         END IF
# 422 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         IF (ndims_tensor(tensor) == 4) THEN
            CALL dbcsr_t_reserve_blocks(tensor, my_blk_ind_1, my_blk_ind_2, my_blk_ind_3, my_blk_ind_4)
         END IF
# 426 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

      CALL dbcsr_t_iterator_start(iterator, tensor)
      DO WHILE (dbcsr_t_iterator_blocks_left(iterator))
         CALL dbcsr_t_iterator_next_block(iterator, blk_index, blk, blk_size=blk_size, blk_offset=blk_offset)

         IF (.NOT. enumerate) THEN
            blk_index_2d = INT(get_2d_indices_tensor(tensor%nd_index_blk, blk_index))
            CALL dbcsr_t_get_mapping_info(tensor%nd_index_blk, dims_2d=nblks_2d)
            CALL set_larnv_seed(blk_index_2d(1), nblks_2d(1), blk_index_2d(2), nblks_2d(2), randmat_counter, iseed)
            nze = PRODUCT(blk_size)
         END IF

# 439 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            IF (ndims_tensor(tensor) == 2) THEN
               CALL allocate_any(blk_values_2, shape_spec=blk_size)
               CALL dims_tensor(tensor, tensor_dims)
               IF (enumerate) THEN
                  CALL enumerate_block_elements(blk_size, blk_offset, tensor_dims, blk_2=blk_values_2)
               ELSE
                  CALL dlarnv(1, iseed, nze, blk_values_2)
               END IF
               CALL dbcsr_t_put_block(tensor, blk_index, blk_size, blk_values_2)
               DEALLOCATE (blk_values_2)
            END IF
# 439 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            IF (ndims_tensor(tensor) == 3) THEN
               CALL allocate_any(blk_values_3, shape_spec=blk_size)
               CALL dims_tensor(tensor, tensor_dims)
               IF (enumerate) THEN
                  CALL enumerate_block_elements(blk_size, blk_offset, tensor_dims, blk_3=blk_values_3)
               ELSE
                  CALL dlarnv(1, iseed, nze, blk_values_3)
               END IF
               CALL dbcsr_t_put_block(tensor, blk_index, blk_size, blk_values_3)
               DEALLOCATE (blk_values_3)
            END IF
# 439 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            IF (ndims_tensor(tensor) == 4) THEN
               CALL allocate_any(blk_values_4, shape_spec=blk_size)
               CALL dims_tensor(tensor, tensor_dims)
               IF (enumerate) THEN
                  CALL enumerate_block_elements(blk_size, blk_offset, tensor_dims, blk_4=blk_values_4)
               ELSE
                  CALL dlarnv(1, iseed, nze, blk_values_4)
               END IF
               CALL dbcsr_t_put_block(tensor, blk_index, blk_size, blk_values_4)
               DEALLOCATE (blk_values_4)
            END IF
# 451 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
      END DO
      CALL dbcsr_t_iterator_stop(iterator)

   END SUBROUTINE

   SUBROUTINE enumerate_block_elements(blk_size, blk_offset, tensor_size, blk_2, blk_3, blk_4)
      !! Enumerate tensor entries in block
      !! \blk_2 block values for 2 dimensions
      !! \blk_3 block values for 3 dimensions

      INTEGER, DIMENSION(:), INTENT(IN)                  :: blk_size, blk_offset, tensor_size
         !! size of block
         !! block offset (indices of first element)
         !! global tensor sizes
# 466 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         REAL(KIND=real_8), DIMENSION(:,:), &
            OPTIONAL, INTENT(OUT)                           :: blk_2
# 466 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         REAL(KIND=real_8), DIMENSION(:,:,:), &
            OPTIONAL, INTENT(OUT)                           :: blk_3
# 466 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         REAL(KIND=real_8), DIMENSION(:,:,:,:), &
            OPTIONAL, INTENT(OUT)                           :: blk_4
# 469 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
      INTEGER                                            :: ndim
      INTEGER, DIMENSION(SIZE(blk_size))                 :: arr_ind, tens_ind
      INTEGER                                            :: i_1, i_2, i_3, i_4

      ndim = SIZE(tensor_size)

# 476 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         IF (ndim == 2) THEN
# 478 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               DO i_2 = 1, blk_size(2)
# 478 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               DO i_1 = 1, blk_size(1)
# 480 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  arr_ind(:) = [i_1, i_2]
                  tens_ind(:) = arr_ind(:) + blk_offset(:) - 1
                  blk_2 (arr_ind(1), arr_ind(2)) = combine_tensor_index(tens_ind, tensor_size)
# 484 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     END DO
# 484 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     END DO
# 486 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               END IF
# 476 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         IF (ndim == 3) THEN
# 478 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               DO i_3 = 1, blk_size(3)
# 478 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               DO i_2 = 1, blk_size(2)
# 478 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               DO i_1 = 1, blk_size(1)
# 480 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  arr_ind(:) = [i_1, i_2, i_3]
                  tens_ind(:) = arr_ind(:) + blk_offset(:) - 1
                  blk_3 (arr_ind(1), arr_ind(2), arr_ind(3)) = combine_tensor_index(tens_ind, tensor_size)
# 484 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     END DO
# 484 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     END DO
# 484 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     END DO
# 486 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               END IF
# 476 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
         IF (ndim == 4) THEN
# 478 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               DO i_4 = 1, blk_size(4)
# 478 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               DO i_3 = 1, blk_size(3)
# 478 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               DO i_2 = 1, blk_size(2)
# 478 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               DO i_1 = 1, blk_size(1)
# 480 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  arr_ind(:) = [i_1, i_2, i_3, i_4]
                  tens_ind(:) = arr_ind(:) + blk_offset(:) - 1
                  blk_4 (arr_ind(1), arr_ind(2), arr_ind(3), arr_ind(4)) = combine_tensor_index(tens_ind, tensor_size)
# 484 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     END DO
# 484 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     END DO
# 484 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     END DO
# 484 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     END DO
# 486 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               END IF
# 488 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

         END SUBROUTINE

# 492 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
# 493 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               SUBROUTINE dist_sparse_tensor_to_repl_dense_2d_array_r_dp (tensor, array)
      !! Transform a distributed sparse tensor to a replicated dense array. This is only useful for
      !! testing tensor contraction by matrix multiplication of dense arrays.

                  TYPE(dbcsr_t_type), INTENT(INOUT)                          :: tensor
                  REAL(kind=real_8), ALLOCATABLE, DIMENSION(:,:), &
                     INTENT(OUT)                                             :: array
                  REAL(kind=real_8), ALLOCATABLE, DIMENSION(:,:)   :: block
                  INTEGER, DIMENSION(ndims_tensor(tensor))                  :: dims_nd, ind_nd, blk_size, blk_offset
                  TYPE(dbcsr_t_iterator_type)                                     :: iterator
                  INTEGER                                                    :: blk, idim
                  INTEGER, DIMENSION(ndims_tensor(tensor))                  :: blk_start, blk_end
                  LOGICAL                                                    :: found

                  DBCSR_ASSERT(ndims_tensor(tensor) .EQ. 2)
                  CALL dbcsr_t_get_info(tensor, nfull_total=dims_nd)
                  CALL allocate_any(array, shape_spec=dims_nd)
                  array(:,:) = 0.0_real_8

                  CALL dbcsr_t_iterator_start(iterator, tensor)
                  DO WHILE (dbcsr_t_iterator_blocks_left(iterator))
                     CALL dbcsr_t_iterator_next_block(iterator, ind_nd, blk, blk_size=blk_size, blk_offset=blk_offset)
                     CALL dbcsr_t_get_block(tensor, ind_nd, block, found)
                     DBCSR_ASSERT(found)

                     DO idim = 1, ndims_tensor(tensor)
                        blk_start(idim) = blk_offset(idim)
                        blk_end(idim) = blk_offset(idim) + blk_size(idim) - 1
                     END DO
                     array(blk_start(1):blk_end(1), blk_start(2):blk_end(2)) = &
                        block(:,:)

                     DEALLOCATE (block)
                  END DO
                  CALL dbcsr_t_iterator_stop(iterator)
                  CALL mp_sum(array, tensor%pgrid%mp_comm_2d)

               END SUBROUTINE
# 493 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               SUBROUTINE dist_sparse_tensor_to_repl_dense_3d_array_r_dp (tensor, array)
      !! Transform a distributed sparse tensor to a replicated dense array. This is only useful for
      !! testing tensor contraction by matrix multiplication of dense arrays.

                  TYPE(dbcsr_t_type), INTENT(INOUT)                          :: tensor
                  REAL(kind=real_8), ALLOCATABLE, DIMENSION(:,:,:), &
                     INTENT(OUT)                                             :: array
                  REAL(kind=real_8), ALLOCATABLE, DIMENSION(:,:,:)   :: block
                  INTEGER, DIMENSION(ndims_tensor(tensor))                  :: dims_nd, ind_nd, blk_size, blk_offset
                  TYPE(dbcsr_t_iterator_type)                                     :: iterator
                  INTEGER                                                    :: blk, idim
                  INTEGER, DIMENSION(ndims_tensor(tensor))                  :: blk_start, blk_end
                  LOGICAL                                                    :: found

                  DBCSR_ASSERT(ndims_tensor(tensor) .EQ. 3)
                  CALL dbcsr_t_get_info(tensor, nfull_total=dims_nd)
                  CALL allocate_any(array, shape_spec=dims_nd)
                  array(:,:,:) = 0.0_real_8

                  CALL dbcsr_t_iterator_start(iterator, tensor)
                  DO WHILE (dbcsr_t_iterator_blocks_left(iterator))
                     CALL dbcsr_t_iterator_next_block(iterator, ind_nd, blk, blk_size=blk_size, blk_offset=blk_offset)
                     CALL dbcsr_t_get_block(tensor, ind_nd, block, found)
                     DBCSR_ASSERT(found)

                     DO idim = 1, ndims_tensor(tensor)
                        blk_start(idim) = blk_offset(idim)
                        blk_end(idim) = blk_offset(idim) + blk_size(idim) - 1
                     END DO
                     array(blk_start(1):blk_end(1), blk_start(2):blk_end(2), blk_start(3):blk_end(3)) = &
                        block(:,:,:)

                     DEALLOCATE (block)
                  END DO
                  CALL dbcsr_t_iterator_stop(iterator)
                  CALL mp_sum(array, tensor%pgrid%mp_comm_2d)

               END SUBROUTINE
# 493 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               SUBROUTINE dist_sparse_tensor_to_repl_dense_4d_array_r_dp (tensor, array)
      !! Transform a distributed sparse tensor to a replicated dense array. This is only useful for
      !! testing tensor contraction by matrix multiplication of dense arrays.

                  TYPE(dbcsr_t_type), INTENT(INOUT)                          :: tensor
                  REAL(kind=real_8), ALLOCATABLE, DIMENSION(:,:,:,:), &
                     INTENT(OUT)                                             :: array
                  REAL(kind=real_8), ALLOCATABLE, DIMENSION(:,:,:,:)   :: block
                  INTEGER, DIMENSION(ndims_tensor(tensor))                  :: dims_nd, ind_nd, blk_size, blk_offset
                  TYPE(dbcsr_t_iterator_type)                                     :: iterator
                  INTEGER                                                    :: blk, idim
                  INTEGER, DIMENSION(ndims_tensor(tensor))                  :: blk_start, blk_end
                  LOGICAL                                                    :: found

                  DBCSR_ASSERT(ndims_tensor(tensor) .EQ. 4)
                  CALL dbcsr_t_get_info(tensor, nfull_total=dims_nd)
                  CALL allocate_any(array, shape_spec=dims_nd)
                  array(:,:,:,:) = 0.0_real_8

                  CALL dbcsr_t_iterator_start(iterator, tensor)
                  DO WHILE (dbcsr_t_iterator_blocks_left(iterator))
                     CALL dbcsr_t_iterator_next_block(iterator, ind_nd, blk, blk_size=blk_size, blk_offset=blk_offset)
                     CALL dbcsr_t_get_block(tensor, ind_nd, block, found)
                     DBCSR_ASSERT(found)

                     DO idim = 1, ndims_tensor(tensor)
                        blk_start(idim) = blk_offset(idim)
                        blk_end(idim) = blk_offset(idim) + blk_size(idim) - 1
                     END DO
                     array(blk_start(1):blk_end(1), blk_start(2):blk_end(2), blk_start(3):blk_end(3), blk_start(4):blk_end(4)) = &
                        block(:,:,:,:)

                     DEALLOCATE (block)
                  END DO
                  CALL dbcsr_t_iterator_stop(iterator)
                  CALL mp_sum(array, tensor%pgrid%mp_comm_2d)

               END SUBROUTINE
# 532 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
# 533 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

         SUBROUTINE dbcsr_t_contract_test(alpha, tensor_1, tensor_2, beta, tensor_3, &
                                          contract_1, notcontract_1, &
                                          contract_2, notcontract_2, &
                                          map_1, map_2, &
                                          unit_nr, &
                                          bounds_1, bounds_2, bounds_3, &
                                          log_verbose, write_int)
      !! test tensor contraction
      !! @note for testing/debugging, simply replace a call to dbcsr_t_contract with a call to this routine
      !! @endnote

            TYPE(dbcsr_scalar_type), INTENT(IN) :: alpha
            TYPE(dbcsr_t_type), INTENT(INOUT)    :: tensor_1, tensor_2, tensor_3
            TYPE(dbcsr_scalar_type), INTENT(IN) :: beta
            INTEGER, DIMENSION(:), INTENT(IN)    :: contract_1, contract_2, &
                                                    notcontract_1, notcontract_2, &
                                                    map_1, map_2
            INTEGER, INTENT(IN)                  :: unit_nr
            INTEGER, DIMENSION(2, SIZE(contract_1)), &
               OPTIONAL                          :: bounds_1
            INTEGER, DIMENSION(2, SIZE(notcontract_1)), &
               OPTIONAL                          :: bounds_2
            INTEGER, DIMENSION(2, SIZE(notcontract_2)), &
               OPTIONAL                          :: bounds_3
            LOGICAL, INTENT(IN), OPTIONAL        :: log_verbose
            LOGICAL, INTENT(IN), OPTIONAL        :: write_int
            INTEGER                              :: io_unit, mynode, numnodes
            INTEGER, DIMENSION(:), ALLOCATABLE   :: size_1, size_2, size_3, &
                                                    order_t1, order_t2, order_t3
            INTEGER, DIMENSION(2, ndims_tensor(tensor_1)) :: bounds_t1
            INTEGER, DIMENSION(2, ndims_tensor(tensor_2)) :: bounds_t2
            TYPE(mp_comm_type)                   :: mp_comm

# 568 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               REAL(KIND=real_8), ALLOCATABLE, &
                  DIMENSION(:,:) :: array_1_2d, &
                                                      array_2_2d, &
                                                      array_3_2d, &
                                                      array_1_2d_full, &
                                                      array_2_2d_full, &
                                                      array_3_0_2d, &
                                                      array_1_rs2d, &
                                                      array_2_rs2d, &
                                                      array_3_rs2d, &
                                                      array_3_0_rs2d
# 568 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               REAL(KIND=real_8), ALLOCATABLE, &
                  DIMENSION(:,:,:) :: array_1_3d, &
                                                      array_2_3d, &
                                                      array_3_3d, &
                                                      array_1_3d_full, &
                                                      array_2_3d_full, &
                                                      array_3_0_3d, &
                                                      array_1_rs3d, &
                                                      array_2_rs3d, &
                                                      array_3_rs3d, &
                                                      array_3_0_rs3d
# 568 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               REAL(KIND=real_8), ALLOCATABLE, &
                  DIMENSION(:,:,:,:) :: array_1_4d, &
                                                      array_2_4d, &
                                                      array_3_4d, &
                                                      array_1_4d_full, &
                                                      array_2_4d_full, &
                                                      array_3_0_4d, &
                                                      array_1_rs4d, &
                                                      array_2_rs4d, &
                                                      array_3_rs4d, &
                                                      array_3_0_rs4d
# 580 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            REAL(KIND=real_8), ALLOCATABLE, &
               DIMENSION(:, :)                   :: array_1_mm, &
                                                    array_2_mm, &
                                                    array_3_mm, &
                                                    array_3_test_mm
            LOGICAL                             :: eql, notzero
            LOGICAL, PARAMETER                  :: debug = .FALSE.
            REAL(KIND=real_8)                   :: cs_1, cs_2, cs_3, eql_diff
            LOGICAL                             :: do_crop_1, do_crop_2

            mp_comm = tensor_1%pgrid%mp_comm_2d
            CALL mp_environ(numnodes, mynode, mp_comm)
            io_unit = -1
            IF (mynode .EQ. 0) io_unit = unit_nr

            cs_1 = dbcsr_t_checksum(tensor_1)
            cs_2 = dbcsr_t_checksum(tensor_2)
            cs_3 = dbcsr_t_checksum(tensor_3)

            IF (io_unit > 0) THEN
               WRITE (io_unit, *)
               WRITE (io_unit, '(A)') repeat("-", 80)
               WRITE (io_unit, '(A,1X,A,1X,A,1X,A,1X,A,1X,A)') "Testing tensor contraction", &
                  TRIM(tensor_1%name), "x", TRIM(tensor_2%name), "=", TRIM(tensor_3%name)
               WRITE (io_unit, '(A)') repeat("-", 80)
            END IF

            IF (debug) THEN
               IF (io_unit > 0) THEN
                  WRITE (io_unit, "(A, E9.2)") "checksum ", TRIM(tensor_1%name), cs_1
                  WRITE (io_unit, "(A, E9.2)") "checksum ", TRIM(tensor_2%name), cs_2
                  WRITE (io_unit, "(A, E9.2)") "checksum ", TRIM(tensor_3%name), cs_3
               END IF
            END IF

            IF (debug) THEN
               CALL dbcsr_t_write_block_indices(tensor_1, io_unit, unit_nr)
               CALL dbcsr_t_write_blocks(tensor_1, io_unit, unit_nr, write_int)
            END IF

            SELECT CASE (ndims_tensor(tensor_3))
# 622 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  CASE (2)
                  CALL dist_sparse_tensor_to_repl_dense_array(tensor_3, array_3_0_2d)
# 622 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  CASE (3)
                  CALL dist_sparse_tensor_to_repl_dense_array(tensor_3, array_3_0_3d)
# 622 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  CASE (4)
                  CALL dist_sparse_tensor_to_repl_dense_array(tensor_3, array_3_0_4d)
# 625 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
            END SELECT

            CALL dbcsr_t_contract(alpha, tensor_1, tensor_2, beta, tensor_3, &
                                  contract_1, notcontract_1, &
                                  contract_2, notcontract_2, &
                                  map_1, map_2, &
                                  bounds_1=bounds_1, bounds_2=bounds_2, bounds_3=bounds_3, &
                                  filter_eps=1.0E-12_real_8, &
                                  unit_nr=io_unit, log_verbose=log_verbose)

            cs_3 = dbcsr_t_checksum(tensor_3)

            IF (debug) THEN
               IF (io_unit > 0) THEN
                  WRITE (io_unit, "(A, E9.2)") "checksum ", TRIM(tensor_3%name), cs_3
               END IF
            END IF

            do_crop_1 = .FALSE.; do_crop_2 = .FALSE.!; do_crop_3 = .FALSE.

            ! crop tensor as first step
            bounds_t1(1, :) = 1
            CALL dbcsr_t_get_info(tensor_1, nfull_total=bounds_t1(2, :))

            bounds_t2(1, :) = 1
            CALL dbcsr_t_get_info(tensor_2, nfull_total=bounds_t2(2, :))

            IF (PRESENT(bounds_1)) THEN
               bounds_t1(:, contract_1) = bounds_1
               do_crop_1 = .TRUE.
               bounds_t2(:, contract_2) = bounds_1
               do_crop_2 = .TRUE.
            END IF

            IF (PRESENT(bounds_2)) THEN
               bounds_t1(:, notcontract_1) = bounds_2
               do_crop_1 = .TRUE.
            END IF

            IF (PRESENT(bounds_3)) THEN
               bounds_t2(:, notcontract_2) = bounds_3
               do_crop_2 = .TRUE.
            END IF

            ! Convert tensors to simple multidimensional arrays
# 671 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               SELECT CASE (ndims_tensor(tensor_1))
# 673 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (2)
# 675 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CALL dist_sparse_tensor_to_repl_dense_array(tensor_1, array_1_2d_full)
                        CALL allocate_any(array_1_2d, shape_spec=SHAPE(array_1_2d_full))
                        array_1_2d = 0.0_real_8
         array_1_2d(bounds_t1(1, 1):bounds_t1(2, 1), bounds_t1(1, 2):bounds_t1(2, 2)) = &
         array_1_2d_full(bounds_t1(1, 1):bounds_t1(2, 1), bounds_t1(1, 2):bounds_t1(2, 2))
# 683 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

# 673 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (3)
# 675 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CALL dist_sparse_tensor_to_repl_dense_array(tensor_1, array_1_3d_full)
                        CALL allocate_any(array_1_3d, shape_spec=SHAPE(array_1_3d_full))
                        array_1_3d = 0.0_real_8
         array_1_3d(bounds_t1(1, 1):bounds_t1(2, 1), bounds_t1(1, 2):bounds_t1(2, 2), bounds_t1(1, 3):bounds_t1(2, 3)) = &
         array_1_3d_full(bounds_t1(1, 1):bounds_t1(2, 1), bounds_t1(1, 2):bounds_t1(2, 2), bounds_t1(1, 3):bounds_t1(2, 3))
# 683 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

# 673 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (4)
# 675 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CALL dist_sparse_tensor_to_repl_dense_array(tensor_1, array_1_4d_full)
                        CALL allocate_any(array_1_4d, shape_spec=SHAPE(array_1_4d_full))
                        array_1_4d = 0.0_real_8
         array_1_4d(bounds_t1(1, 1):bounds_t1(2, 1), bounds_t1(1, 2):bounds_t1(2, 2), bounds_t1(1, 3):bounds_t1(2, 3),&
# 678 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
             & bounds_t1(1, 4):bounds_t1(2, 4)) = &
         array_1_4d_full(bounds_t1(1, 1):bounds_t1(2, 1), bounds_t1(1, 2):bounds_t1(2, 2), bounds_t1(1, 3):bounds_t1(2, 3),&
# 679 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
             & bounds_t1(1, 4):bounds_t1(2, 4))
# 683 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

# 685 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               END SELECT
# 671 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               SELECT CASE (ndims_tensor(tensor_2))
# 673 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (2)
# 675 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CALL dist_sparse_tensor_to_repl_dense_array(tensor_2, array_2_2d_full)
                        CALL allocate_any(array_2_2d, shape_spec=SHAPE(array_2_2d_full))
                        array_2_2d = 0.0_real_8
         array_2_2d(bounds_t2(1, 1):bounds_t2(2, 1), bounds_t2(1, 2):bounds_t2(2, 2)) = &
         array_2_2d_full(bounds_t2(1, 1):bounds_t2(2, 1), bounds_t2(1, 2):bounds_t2(2, 2))
# 683 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

# 673 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (3)
# 675 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CALL dist_sparse_tensor_to_repl_dense_array(tensor_2, array_2_3d_full)
                        CALL allocate_any(array_2_3d, shape_spec=SHAPE(array_2_3d_full))
                        array_2_3d = 0.0_real_8
         array_2_3d(bounds_t2(1, 1):bounds_t2(2, 1), bounds_t2(1, 2):bounds_t2(2, 2), bounds_t2(1, 3):bounds_t2(2, 3)) = &
         array_2_3d_full(bounds_t2(1, 1):bounds_t2(2, 1), bounds_t2(1, 2):bounds_t2(2, 2), bounds_t2(1, 3):bounds_t2(2, 3))
# 683 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

# 673 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (4)
# 675 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CALL dist_sparse_tensor_to_repl_dense_array(tensor_2, array_2_4d_full)
                        CALL allocate_any(array_2_4d, shape_spec=SHAPE(array_2_4d_full))
                        array_2_4d = 0.0_real_8
         array_2_4d(bounds_t2(1, 1):bounds_t2(2, 1), bounds_t2(1, 2):bounds_t2(2, 2), bounds_t2(1, 3):bounds_t2(2, 3),&
# 678 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
             & bounds_t2(1, 4):bounds_t2(2, 4)) = &
         array_2_4d_full(bounds_t2(1, 1):bounds_t2(2, 1), bounds_t2(1, 2):bounds_t2(2, 2), bounds_t2(1, 3):bounds_t2(2, 3),&
# 679 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
             & bounds_t2(1, 4):bounds_t2(2, 4))
# 683 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

# 685 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               END SELECT
# 671 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               SELECT CASE (ndims_tensor(tensor_3))
# 673 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (2)
# 681 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CALL dist_sparse_tensor_to_repl_dense_array(tensor_3, array_3_2d)
# 683 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

# 673 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (3)
# 681 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CALL dist_sparse_tensor_to_repl_dense_array(tensor_3, array_3_3d)
# 683 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

# 673 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (4)
# 681 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CALL dist_sparse_tensor_to_repl_dense_array(tensor_3, array_3_4d)
# 683 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

# 685 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               END SELECT
# 687 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

            ! Get array sizes

# 691 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               SELECT CASE (ndims_tensor(tensor_1))
# 693 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (2)
                     CALL allocate_any(size_1, source=SHAPE(array_1_2d))

# 693 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (3)
                     CALL allocate_any(size_1, source=SHAPE(array_1_3d))

# 693 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (4)
                     CALL allocate_any(size_1, source=SHAPE(array_1_4d))

# 697 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               END SELECT
# 691 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               SELECT CASE (ndims_tensor(tensor_2))
# 693 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (2)
                     CALL allocate_any(size_2, source=SHAPE(array_2_2d))

# 693 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (3)
                     CALL allocate_any(size_2, source=SHAPE(array_2_3d))

# 693 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (4)
                     CALL allocate_any(size_2, source=SHAPE(array_2_4d))

# 697 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               END SELECT
# 691 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               SELECT CASE (ndims_tensor(tensor_3))
# 693 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (2)
                     CALL allocate_any(size_3, source=SHAPE(array_3_2d))

# 693 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (3)
                     CALL allocate_any(size_3, source=SHAPE(array_3_3d))

# 693 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (4)
                     CALL allocate_any(size_3, source=SHAPE(array_3_4d))

# 697 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               END SELECT
# 699 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

# 701 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               ALLOCATE (order_t1 (ndims_tensor(tensor_1)))
# 701 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               ALLOCATE (order_t2 (ndims_tensor(tensor_2)))
# 701 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               ALLOCATE (order_t3 (ndims_tensor(tensor_3)))
# 703 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

            ASSOCIATE (map_t1_1 => notcontract_1, map_t1_2 => contract_1, &
                       map_t2_1 => notcontract_2, map_t2_2 => contract_2, &
                       map_t3_1 => map_1, map_t3_2 => map_2)

# 709 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  order_t1 (:) = dbcsr_t_inverse_order([map_t1_1, map_t1_2])

                  SELECT CASE (ndims_tensor(tensor_1))
# 713 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CASE (2)
                        CALL allocate_any(array_1_rs2d, source=array_1_2d, order=order_t1)
                        CALL allocate_any(array_1_mm, sizes_2d(size_1, map_t1_1, map_t1_2))
                        array_1_mm(:, :) = RESHAPE(array_1_rs2d, SHAPE(array_1_mm))
# 713 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CASE (3)
                        CALL allocate_any(array_1_rs3d, source=array_1_3d, order=order_t1)
                        CALL allocate_any(array_1_mm, sizes_2d(size_1, map_t1_1, map_t1_2))
                        array_1_mm(:, :) = RESHAPE(array_1_rs3d, SHAPE(array_1_mm))
# 713 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CASE (4)
                        CALL allocate_any(array_1_rs4d, source=array_1_4d, order=order_t1)
                        CALL allocate_any(array_1_mm, sizes_2d(size_1, map_t1_1, map_t1_2))
                        array_1_mm(:, :) = RESHAPE(array_1_rs4d, SHAPE(array_1_mm))
# 718 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  END SELECT
# 709 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  order_t2 (:) = dbcsr_t_inverse_order([map_t2_1, map_t2_2])

                  SELECT CASE (ndims_tensor(tensor_2))
# 713 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CASE (2)
                        CALL allocate_any(array_2_rs2d, source=array_2_2d, order=order_t2)
                        CALL allocate_any(array_2_mm, sizes_2d(size_2, map_t2_1, map_t2_2))
                        array_2_mm(:, :) = RESHAPE(array_2_rs2d, SHAPE(array_2_mm))
# 713 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CASE (3)
                        CALL allocate_any(array_2_rs3d, source=array_2_3d, order=order_t2)
                        CALL allocate_any(array_2_mm, sizes_2d(size_2, map_t2_1, map_t2_2))
                        array_2_mm(:, :) = RESHAPE(array_2_rs3d, SHAPE(array_2_mm))
# 713 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CASE (4)
                        CALL allocate_any(array_2_rs4d, source=array_2_4d, order=order_t2)
                        CALL allocate_any(array_2_mm, sizes_2d(size_2, map_t2_1, map_t2_2))
                        array_2_mm(:, :) = RESHAPE(array_2_rs4d, SHAPE(array_2_mm))
# 718 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  END SELECT
# 709 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  order_t3 (:) = dbcsr_t_inverse_order([map_t3_1, map_t3_2])

                  SELECT CASE (ndims_tensor(tensor_3))
# 713 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CASE (2)
                        CALL allocate_any(array_3_rs2d, source=array_3_2d, order=order_t3)
                        CALL allocate_any(array_3_mm, sizes_2d(size_3, map_t3_1, map_t3_2))
                        array_3_mm(:, :) = RESHAPE(array_3_rs2d, SHAPE(array_3_mm))
# 713 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CASE (3)
                        CALL allocate_any(array_3_rs3d, source=array_3_3d, order=order_t3)
                        CALL allocate_any(array_3_mm, sizes_2d(size_3, map_t3_1, map_t3_2))
                        array_3_mm(:, :) = RESHAPE(array_3_rs3d, SHAPE(array_3_mm))
# 713 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                        CASE (4)
                        CALL allocate_any(array_3_rs4d, source=array_3_4d, order=order_t3)
                        CALL allocate_any(array_3_mm, sizes_2d(size_3, map_t3_1, map_t3_2))
                        array_3_mm(:, :) = RESHAPE(array_3_rs4d, SHAPE(array_3_mm))
# 718 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                  END SELECT
# 720 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"

               SELECT CASE (ndims_tensor(tensor_3))
# 723 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (2)
                     CALL allocate_any(array_3_0_rs2d, source=array_3_0_2d, order=order_t3)
                     CALL allocate_any(array_3_test_mm, sizes_2d(size_3, map_t3_1, map_t3_2))
                     array_3_test_mm(:, :) = RESHAPE(array_3_0_rs2d, SHAPE(array_3_mm))
# 723 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (3)
                     CALL allocate_any(array_3_0_rs3d, source=array_3_0_3d, order=order_t3)
                     CALL allocate_any(array_3_test_mm, sizes_2d(size_3, map_t3_1, map_t3_2))
                     array_3_test_mm(:, :) = RESHAPE(array_3_0_rs3d, SHAPE(array_3_mm))
# 723 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
                     CASE (4)
                     CALL allocate_any(array_3_0_rs4d, source=array_3_0_4d, order=order_t3)
                     CALL allocate_any(array_3_test_mm, sizes_2d(size_3, map_t3_1, map_t3_2))
                     array_3_test_mm(:, :) = RESHAPE(array_3_0_rs4d, SHAPE(array_3_mm))
# 728 "/__w/dbcsr/dbcsr/src/tensors/dbcsr_tensor_test.F"
               END SELECT

               array_3_test_mm(:, :) = beta%r_dp*array_3_test_mm(:, :) + alpha%r_dp*MATMUL(array_1_mm, transpose(array_2_mm))

            END ASSOCIATE

            eql_diff = MAXVAL(ABS(array_3_test_mm(:, :) - array_3_mm(:, :)))
            notzero = MAXVAL(ABS(array_3_test_mm(:, :))) .GT. 1.0E-12_real_8

            eql = eql_diff .LT. 1.0E-11_real_8

            IF (.NOT. eql .OR. .NOT. notzero) THEN
               IF (io_unit > 0) WRITE (io_unit, *) 'Test failed!', eql_diff
               DBCSR_ABORT('')
            ELSE
               IF (io_unit > 0) WRITE (io_unit, *) 'Test passed!', eql_diff
            END IF

         END SUBROUTINE

         FUNCTION sizes_2d(nd_sizes, map1, map2)
      !! mapped sizes in 2d
            INTEGER, DIMENSION(:), INTENT(IN) :: nd_sizes, map1, map2
            INTEGER, DIMENSION(2)             :: sizes_2d
            sizes_2d(1) = PRODUCT(nd_sizes(map1))
            sizes_2d(2) = PRODUCT(nd_sizes(map2))
         END FUNCTION

         FUNCTION dbcsr_t_checksum(tensor, local, pos)
      !! checksum of a tensor consistent with dbcsr_checksum
            TYPE(dbcsr_t_type), INTENT(IN) :: tensor
            REAL(KIND=real_8) :: dbcsr_t_checksum
            LOGICAL, INTENT(IN), OPTIONAL     :: local, pos
            dbcsr_t_checksum = dbcsr_tas_checksum(tensor%matrix_rep, local, pos)
         END FUNCTION

         SUBROUTINE dbcsr_t_reset_randmat_seed()
      !! Reset the seed used for generating random matrices to default value
            randmat_counter = rand_seed_init
         END SUBROUTINE

      END MODULE