LCOV - code coverage report
Current view: top level - src - qs_tensors.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 94.8 % 1143 1084
Test Date: 2025-12-04 06:27:48 Functions: 90.5 % 21 19

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Utility methods to build 3-center integral tensors of various types.
      10              : ! **************************************************************************************************
      11              : MODULE qs_tensors
      12              :    USE OMP_LIB,                         ONLY: omp_get_num_threads,&
      13              :                                               omp_get_thread_num
      14              :    USE ai_contraction,                  ONLY: block_add
      15              :    USE ai_contraction_sphi,             ONLY: ab_contract,&
      16              :                                               abc_contract_xsmm
      17              :    USE atomic_kind_types,               ONLY: atomic_kind_type
      18              :    USE basis_set_types,                 ONLY: get_gto_basis_set,&
      19              :                                               gto_basis_set_p_type,&
      20              :                                               gto_basis_set_type
      21              :    USE block_p_types,                   ONLY: block_p_type
      22              :    USE cell_types,                      ONLY: cell_type,&
      23              :                                               real_to_scaled
      24              :    USE cp_array_utils,                  ONLY: cp_2d_r_p_type
      25              :    USE cp_control_types,                ONLY: dft_control_type
      26              :    USE cp_dbcsr_api,                    ONLY: dbcsr_filter,&
      27              :                                               dbcsr_finalize,&
      28              :                                               dbcsr_get_block_p,&
      29              :                                               dbcsr_get_matrix_type,&
      30              :                                               dbcsr_has_symmetry,&
      31              :                                               dbcsr_type,&
      32              :                                               dbcsr_type_antisymmetric,&
      33              :                                               dbcsr_type_no_symmetry
      34              :    USE cp_dbcsr_cp2k_link,              ONLY: cp_dbcsr_alloc_block_from_nbl
      35              :    USE cp_files,                        ONLY: close_file,&
      36              :                                               open_file
      37              :    USE dbt_api,                         ONLY: &
      38              :         dbt_blk_sizes, dbt_clear, dbt_copy, dbt_create, dbt_destroy, dbt_filter, dbt_get_block, &
      39              :         dbt_get_info, dbt_get_num_blocks, dbt_get_nze_total, dbt_iterator_next_block, &
      40              :         dbt_iterator_num_blocks, dbt_iterator_start, dbt_iterator_stop, dbt_iterator_type, &
      41              :         dbt_ndims, dbt_put_block, dbt_reserve_blocks, dbt_type
      42              :    USE distribution_1d_types,           ONLY: distribution_1d_type
      43              :    USE distribution_2d_types,           ONLY: distribution_2d_type
      44              :    USE gamma,                           ONLY: init_md_ftable
      45              :    USE hfx_compression_methods,         ONLY: hfx_add_mult_cache_elements,&
      46              :                                               hfx_add_single_cache_element,&
      47              :                                               hfx_decompress_first_cache,&
      48              :                                               hfx_flush_last_cache,&
      49              :                                               hfx_get_mult_cache_elements,&
      50              :                                               hfx_get_single_cache_element,&
      51              :                                               hfx_reset_cache_and_container
      52              :    USE hfx_types,                       ONLY: alloc_containers,&
      53              :                                               dealloc_containers,&
      54              :                                               hfx_cache_type,&
      55              :                                               hfx_compression_type,&
      56              :                                               hfx_container_type,&
      57              :                                               hfx_init_container
      58              :    USE input_constants,                 ONLY: do_potential_coulomb,&
      59              :                                               do_potential_id,&
      60              :                                               do_potential_mix_cl_trunc,&
      61              :                                               do_potential_short,&
      62              :                                               do_potential_truncated
      63              :    USE input_section_types,             ONLY: section_vals_val_get
      64              :    USE kinds,                           ONLY: dp,&
      65              :                                               int_8
      66              :    USE kpoint_types,                    ONLY: get_kpoint_info,&
      67              :                                               kpoint_type
      68              :    USE libint_2c_3c,                    ONLY: cutoff_screen_factor,&
      69              :                                               eri_2center,&
      70              :                                               eri_2center_derivs,&
      71              :                                               eri_3center,&
      72              :                                               eri_3center_derivs,&
      73              :                                               libint_potential_type
      74              :    USE libint_wrapper,                  ONLY: &
      75              :         cp_libint_cleanup_2eri, cp_libint_cleanup_2eri1, cp_libint_cleanup_3eri, &
      76              :         cp_libint_cleanup_3eri1, cp_libint_init_2eri, cp_libint_init_2eri1, cp_libint_init_3eri, &
      77              :         cp_libint_init_3eri1, cp_libint_set_contrdepth, cp_libint_t
      78              :    USE message_passing,                 ONLY: mp_para_env_type
      79              :    USE molecule_types,                  ONLY: molecule_type
      80              :    USE orbital_pointers,                ONLY: ncoset
      81              :    USE particle_types,                  ONLY: particle_type
      82              :    USE qs_environment_types,            ONLY: get_qs_env,&
      83              :                                               qs_environment_type
      84              :    USE qs_kind_types,                   ONLY: qs_kind_type
      85              :    USE qs_neighbor_list_types,          ONLY: &
      86              :         get_iterator_info, get_neighbor_list_set_p, neighbor_list_iterate, &
      87              :         neighbor_list_iterator_create, neighbor_list_iterator_p_type, &
      88              :         neighbor_list_iterator_release, neighbor_list_set_p_type, nl_sub_iterate, &
      89              :         release_neighbor_list_sets
      90              :    USE qs_neighbor_lists,               ONLY: atom2d_build,&
      91              :                                               atom2d_cleanup,&
      92              :                                               build_neighbor_lists,&
      93              :                                               local_atoms_type,&
      94              :                                               pair_radius_setup
      95              :    USE qs_tensors_types,                ONLY: &
      96              :         distribution_3d_destroy, distribution_3d_type, neighbor_list_3c_iterator_type, &
      97              :         neighbor_list_3c_type, symmetric_ij, symmetric_ijk, symmetric_jk, symmetric_none, &
      98              :         symmetrik_ik
      99              :    USE t_c_g0,                          ONLY: get_lmax_init,&
     100              :                                               init
     101              :    USE util,                            ONLY: get_limit
     102              : 
     103              : !$ USE OMP_LIB, ONLY: omp_get_max_threads, omp_get_thread_num
     104              : #include "./base/base_uses.f90"
     105              : 
     106              :    IMPLICIT NONE
     107              : 
     108              :    PRIVATE
     109              : 
     110              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_tensors'
     111              : 
     112              :    PUBLIC :: build_3c_neighbor_lists, &
     113              :              neighbor_list_3c_destroy, neighbor_list_3c_iterate, neighbor_list_3c_iterator_create, &
     114              :              neighbor_list_3c_iterator_destroy, get_3c_iterator_info, build_3c_integrals, &
     115              :              build_2c_neighbor_lists, build_2c_integrals, cutoff_screen_factor, &
     116              :              get_tensor_occupancy, compress_tensor, decompress_tensor, &
     117              :              build_3c_derivatives, build_2c_derivatives, calc_2c_virial, calc_3c_virial
     118              : 
     119              :    TYPE one_dim_int_array
     120              :       INTEGER, DIMENSION(:), ALLOCATABLE    :: array
     121              :    END TYPE one_dim_int_array
     122              : 
     123              :    ! cache size for integral compression
     124              :    INTEGER, PARAMETER, PRIVATE :: cache_size = 1024
     125              : 
     126              : CONTAINS
     127              : 
     128              : ! **************************************************************************************************
     129              : !> \brief Build 2-center neighborlists adapted to different operators
     130              : !>        This mainly wraps build_neighbor_lists for consistency with build_3c_neighbor_lists
     131              : !> \param ij_list 2c neighbor list for atom pairs i, j
     132              : !> \param basis_i basis object for atoms i
     133              : !> \param basis_j basis object for atoms j
     134              : !> \param potential_parameter ...
     135              : !> \param name name of 2c neighbor list
     136              : !> \param qs_env ...
     137              : !> \param sym_ij Symmetry in i, j (default .TRUE.)
     138              : !> \param molecular ...
     139              : !> \param dist_2d optionally a custom 2d distribution
     140              : !> \param pot_to_rad which radius (1 for i, 2 for j) should be adapted to incorporate potential
     141              : ! **************************************************************************************************
     142        11908 :    SUBROUTINE build_2c_neighbor_lists(ij_list, basis_i, basis_j, potential_parameter, name, qs_env, &
     143              :                                       sym_ij, molecular, dist_2d, pot_to_rad)
     144              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     145              :          POINTER                                         :: ij_list
     146              :       TYPE(gto_basis_set_p_type), DIMENSION(:)           :: basis_i, basis_j
     147              :       TYPE(libint_potential_type), INTENT(IN)            :: potential_parameter
     148              :       CHARACTER(LEN=*), INTENT(IN)                       :: name
     149              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     150              :       LOGICAL, INTENT(IN), OPTIONAL                      :: sym_ij, molecular
     151              :       TYPE(distribution_2d_type), OPTIONAL, POINTER      :: dist_2d
     152              :       INTEGER, INTENT(IN), OPTIONAL                      :: pot_to_rad
     153              : 
     154              :       INTEGER                                            :: ikind, nkind, pot_to_rad_prv
     155              :       LOGICAL, ALLOCATABLE, DIMENSION(:)                 :: i_present, j_present
     156        11908 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: pair_radius
     157              :       REAL(kind=dp)                                      :: subcells
     158              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: i_radius, j_radius
     159        11908 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     160              :       TYPE(cell_type), POINTER                           :: cell
     161              :       TYPE(distribution_1d_type), POINTER                :: local_particles
     162              :       TYPE(distribution_2d_type), POINTER                :: dist_2d_prv
     163        11908 :       TYPE(local_atoms_type), ALLOCATABLE, DIMENSION(:)  :: atom2d
     164        11908 :       TYPE(molecule_type), DIMENSION(:), POINTER         :: molecule_set
     165        11908 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     166              : 
     167        11908 :       NULLIFY (atomic_kind_set, cell, local_particles, molecule_set, &
     168        11908 :                particle_set, dist_2d_prv)
     169              : 
     170        11908 :       IF (PRESENT(pot_to_rad)) THEN
     171         1392 :          pot_to_rad_prv = pot_to_rad
     172              :       ELSE
     173              :          pot_to_rad_prv = 1
     174              :       END IF
     175              : 
     176              :       CALL get_qs_env(qs_env, &
     177              :                       nkind=nkind, &
     178              :                       cell=cell, &
     179              :                       particle_set=particle_set, &
     180              :                       atomic_kind_set=atomic_kind_set, &
     181              :                       local_particles=local_particles, &
     182              :                       distribution_2d=dist_2d_prv, &
     183        11908 :                       molecule_set=molecule_set)
     184              : 
     185        11908 :       CALL section_vals_val_get(qs_env%input, "DFT%SUBCELLS", r_val=subcells)
     186              : 
     187        53577 :       ALLOCATE (i_present(nkind), SOURCE=.FALSE.)
     188        41669 :       ALLOCATE (j_present(nkind), SOURCE=.FALSE.)
     189        53577 :       ALLOCATE (i_radius(nkind), SOURCE=0.0_dp)
     190        41669 :       ALLOCATE (j_radius(nkind), SOURCE=0.0_dp)
     191              : 
     192        11908 :       IF (PRESENT(dist_2d)) dist_2d_prv => dist_2d
     193              : 
     194              :       !  Set up the radii, depending on the operator type
     195        11908 :       IF (potential_parameter%potential_type == do_potential_id) THEN
     196              : 
     197              :          !overlap => use the kind radius for both i and j
     198        25295 :          DO ikind = 1, nkind
     199        15133 :             IF (ASSOCIATED(basis_i(ikind)%gto_basis_set)) THEN
     200        15133 :                i_present(ikind) = .TRUE.
     201        15133 :                CALL get_gto_basis_set(basis_i(ikind)%gto_basis_set, kind_radius=i_radius(ikind))
     202              :             END IF
     203        25295 :             IF (ASSOCIATED(basis_j(ikind)%gto_basis_set)) THEN
     204        15133 :                j_present(ikind) = .TRUE.
     205        15133 :                CALL get_gto_basis_set(basis_j(ikind)%gto_basis_set, kind_radius=j_radius(ikind))
     206              :             END IF
     207              :          END DO
     208              : 
     209              :       ELSE IF (potential_parameter%potential_type == do_potential_coulomb) THEN
     210              : 
     211              :          !Coulomb operator, virtually infinite range => set j_radius to arbitrarily large number
     212         1110 :          DO ikind = 1, nkind
     213          736 :             IF (ASSOCIATED(basis_i(ikind)%gto_basis_set)) THEN
     214          736 :                i_present(ikind) = .TRUE.
     215          736 :                IF (pot_to_rad_prv == 1) i_radius(ikind) = 1000000.0_dp
     216              :             END IF
     217         1110 :             IF (ASSOCIATED(basis_j(ikind)%gto_basis_set)) THEN
     218          736 :                j_present(ikind) = .TRUE.
     219          736 :                IF (pot_to_rad_prv == 2) j_radius(ikind) = 1000000.0_dp
     220              :             END IF
     221              :          END DO !ikind
     222              : 
     223              :       ELSE IF (potential_parameter%potential_type == do_potential_truncated .OR. &
     224              :                potential_parameter%potential_type == do_potential_short .OR. &
     225              :                potential_parameter%potential_type == do_potential_mix_cl_trunc) THEN
     226              : 
     227              :          !Truncated coulomb/short range: set j_radius to r_cutoff + the kind_radii
     228         3356 :          DO ikind = 1, nkind
     229         1984 :             IF (ASSOCIATED(basis_i(ikind)%gto_basis_set)) THEN
     230         1984 :                i_present(ikind) = .TRUE.
     231         1984 :                CALL get_gto_basis_set(basis_i(ikind)%gto_basis_set, kind_radius=i_radius(ikind))
     232         1984 :                IF (pot_to_rad_prv == 1) i_radius(ikind) = i_radius(ikind) + cutoff_screen_factor*potential_parameter%cutoff_radius
     233              :             END IF
     234         3356 :             IF (ASSOCIATED(basis_j(ikind)%gto_basis_set)) THEN
     235         1984 :                j_present(ikind) = .TRUE.
     236         1984 :                CALL get_gto_basis_set(basis_j(ikind)%gto_basis_set, kind_radius=j_radius(ikind))
     237         1984 :                IF (pot_to_rad_prv == 2) j_radius(ikind) = j_radius(ikind) + cutoff_screen_factor*potential_parameter%cutoff_radius
     238              :             END IF
     239              :          END DO
     240              : 
     241              :       ELSE
     242            0 :          CPABORT("Operator not implemented.")
     243              :       END IF
     244              : 
     245        95264 :       ALLOCATE (pair_radius(nkind, nkind), SOURCE=0.0_dp)
     246        11908 :       CALL pair_radius_setup(i_present, j_present, i_radius, j_radius, pair_radius)
     247              : 
     248        53577 :       ALLOCATE (atom2d(nkind))
     249              : 
     250              :       CALL atom2d_build(atom2d, local_particles, dist_2d_prv, atomic_kind_set, &
     251        11908 :                         molecule_set, molecule_only=.FALSE., particle_set=particle_set)
     252              :       CALL build_neighbor_lists(ij_list, particle_set, atom2d, cell, pair_radius, subcells, &
     253        11908 :                                 symmetric=sym_ij, molecular=molecular, nlname=TRIM(name))
     254              : 
     255        11908 :       CALL atom2d_cleanup(atom2d)
     256              : 
     257        35724 :    END SUBROUTINE build_2c_neighbor_lists
     258              : 
     259              : ! **************************************************************************************************
     260              : !> \brief Build a 3-center neighbor list
     261              : !> \param ijk_list 3c neighbor list for atom triples i, j, k
     262              : !> \param basis_i basis object for atoms i
     263              : !> \param basis_j basis object for atoms j
     264              : !> \param basis_k basis object for atoms k
     265              : !> \param dist_3d 3d distribution object
     266              : !> \param potential_parameter ...
     267              : !> \param name name of 3c neighbor list
     268              : !> \param qs_env ...
     269              : !> \param sym_ij Symmetry in i, j (default .FALSE.)
     270              : !> \param sym_jk Symmetry in j, k (default .FALSE.)
     271              : !> \param sym_ik Symmetry in i, k (default .FALSE.)
     272              : !> \param molecular ??? not tested
     273              : !> \param op_pos ...
     274              : !> \param own_dist ...
     275              : ! **************************************************************************************************
     276          696 :    SUBROUTINE build_3c_neighbor_lists(ijk_list, basis_i, basis_j, basis_k, &
     277              :                                       dist_3d, potential_parameter, name, qs_env, &
     278              :                                       sym_ij, sym_jk, sym_ik, molecular, op_pos, &
     279              :                                       own_dist)
     280              :       TYPE(neighbor_list_3c_type), INTENT(OUT)           :: ijk_list
     281              :       TYPE(gto_basis_set_p_type), DIMENSION(:)           :: basis_i, basis_j, basis_k
     282              :       TYPE(distribution_3d_type), INTENT(IN)             :: dist_3d
     283              :       TYPE(libint_potential_type), INTENT(IN)            :: potential_parameter
     284              :       CHARACTER(LEN=*), INTENT(IN)                       :: name
     285              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     286              :       LOGICAL, INTENT(IN), OPTIONAL                      :: sym_ij, sym_jk, sym_ik, molecular
     287              :       INTEGER, INTENT(IN), OPTIONAL                      :: op_pos
     288              :       LOGICAL, INTENT(IN), OPTIONAL                      :: own_dist
     289              : 
     290              :       CHARACTER(len=*), PARAMETER :: routineN = 'build_3c_neighbor_lists'
     291              : 
     292              :       INTEGER                                            :: handle, op_pos_prv, sym_level
     293              :       TYPE(libint_potential_type)                        :: pot_par_1, pot_par_2
     294              : 
     295          696 :       CALL timeset(routineN, handle)
     296              : 
     297          696 :       IF (PRESENT(op_pos)) THEN
     298          512 :          op_pos_prv = op_pos
     299              :       ELSE
     300              :          op_pos_prv = 1
     301              :       END IF
     302              : 
     303          490 :       SELECT CASE (op_pos_prv)
     304              :       CASE (1)
     305          490 :          pot_par_1 = potential_parameter
     306          490 :          pot_par_2%potential_type = do_potential_id
     307              :       CASE (2)
     308          206 :          pot_par_2 = potential_parameter
     309          512 :          pot_par_1%potential_type = do_potential_id
     310              :       END SELECT
     311              : 
     312              :       CALL build_2c_neighbor_lists(ijk_list%ij_list, basis_i, basis_j, pot_par_1, TRIM(name)//"_sub_1", &
     313              :                                    qs_env, sym_ij=.FALSE., molecular=molecular, &
     314          696 :                                    dist_2d=dist_3d%dist_2d_1, pot_to_rad=1)
     315              : 
     316              :       CALL build_2c_neighbor_lists(ijk_list%jk_list, basis_j, basis_k, pot_par_2, TRIM(name)//"_sub_2", &
     317              :                                    qs_env, sym_ij=.FALSE., molecular=molecular, &
     318          696 :                                    dist_2d=dist_3d%dist_2d_2, pot_to_rad=2)
     319              : 
     320          696 :       ijk_list%sym = symmetric_none
     321              : 
     322          696 :       sym_level = 0
     323          696 :       IF (PRESENT(sym_ij)) THEN
     324          160 :          IF (sym_ij) THEN
     325            0 :             ijk_list%sym = symmetric_ij
     326            0 :             sym_level = sym_level + 1
     327              :          END IF
     328              :       END IF
     329              : 
     330          696 :       IF (PRESENT(sym_jk)) THEN
     331          486 :          IF (sym_jk) THEN
     332          428 :             ijk_list%sym = symmetric_jk
     333          428 :             sym_level = sym_level + 1
     334              :          END IF
     335              :       END IF
     336              : 
     337          696 :       IF (PRESENT(sym_ik)) THEN
     338            0 :          IF (sym_ik) THEN
     339            0 :             ijk_list%sym = symmetrik_ik
     340            0 :             sym_level = sym_level + 1
     341              :          END IF
     342              :       END IF
     343              : 
     344          696 :       IF (sym_level >= 2) THEN
     345            0 :          ijk_list%sym = symmetric_ijk
     346              :       END IF
     347              : 
     348          696 :       ijk_list%dist_3d = dist_3d
     349          696 :       IF (PRESENT(own_dist)) THEN
     350          696 :          ijk_list%owns_dist = own_dist
     351              :       ELSE
     352            0 :          ijk_list%owns_dist = .FALSE.
     353              :       END IF
     354              : 
     355          696 :       CALL timestop(handle)
     356          696 :    END SUBROUTINE build_3c_neighbor_lists
     357              : 
     358              : ! **************************************************************************************************
     359              : !> \brief Symmetry criterion
     360              : !> \param a ...
     361              : !> \param b ...
     362              : !> \return ...
     363              : ! **************************************************************************************************
     364      4207758 :    PURE FUNCTION include_symmetric(a, b)
     365              :       INTEGER, INTENT(IN)                                :: a, b
     366              :       LOGICAL                                            :: include_symmetric
     367              : 
     368      4207758 :       IF (a > b) THEN
     369      1691358 :          include_symmetric = (MODULO(a + b, 2) /= 0)
     370              :       ELSE
     371      2516400 :          include_symmetric = (MODULO(a + b, 2) == 0)
     372              :       END IF
     373              : 
     374      4207758 :    END FUNCTION include_symmetric
     375              : 
     376              : ! **************************************************************************************************
     377              : !> \brief Destroy 3c neighborlist
     378              : !> \param ijk_list ...
     379              : ! **************************************************************************************************
     380          696 :    SUBROUTINE neighbor_list_3c_destroy(ijk_list)
     381              :       TYPE(neighbor_list_3c_type), INTENT(INOUT)         :: ijk_list
     382              : 
     383          696 :       CALL release_neighbor_list_sets(ijk_list%ij_list)
     384          696 :       CALL release_neighbor_list_sets(ijk_list%jk_list)
     385              : 
     386          696 :       IF (ijk_list%owns_dist) THEN
     387          696 :          CALL distribution_3d_destroy(ijk_list%dist_3d)
     388              :       END IF
     389              : 
     390          696 :    END SUBROUTINE neighbor_list_3c_destroy
     391              : 
     392              : ! **************************************************************************************************
     393              : !> \brief Create a 3-center neighborlist iterator
     394              : !> \param iterator ...
     395              : !> \param ijk_nl ...
     396              : ! **************************************************************************************************
     397        69768 :    SUBROUTINE neighbor_list_3c_iterator_create(iterator, ijk_nl)
     398              :       TYPE(neighbor_list_3c_iterator_type), INTENT(OUT)  :: iterator
     399              :       TYPE(neighbor_list_3c_type), INTENT(IN)            :: ijk_nl
     400              : 
     401              :       CHARACTER(len=*), PARAMETER :: routineN = 'neighbor_list_3c_iterator_create'
     402              : 
     403              :       INTEGER                                            :: handle
     404              : 
     405         7752 :       CALL timeset(routineN, handle)
     406              : 
     407         7752 :       CALL neighbor_list_iterator_create(iterator%iter_ij, ijk_nl%ij_list)
     408         7752 :       CALL neighbor_list_iterator_create(iterator%iter_jk, ijk_nl%jk_list, search=.TRUE.)
     409              : 
     410         7752 :       iterator%iter_level = 0
     411         7752 :       iterator%ijk_nl = ijk_nl
     412              : 
     413        23256 :       iterator%bounds_i = 0
     414        23256 :       iterator%bounds_j = 0
     415        23256 :       iterator%bounds_k = 0
     416              : 
     417         7752 :       CALL timestop(handle)
     418         7752 :    END SUBROUTINE neighbor_list_3c_iterator_create
     419              : 
     420              : ! **************************************************************************************************
     421              : !> \brief impose atomic upper and lower bounds
     422              : !> \param iterator ...
     423              : !> \param bounds_i ...
     424              : !> \param bounds_j ...
     425              : !> \param bounds_k ...
     426              : ! **************************************************************************************************
     427         7672 :    SUBROUTINE nl_3c_iter_set_bounds(iterator, bounds_i, bounds_j, bounds_k)
     428              :       TYPE(neighbor_list_3c_iterator_type), &
     429              :          INTENT(INOUT)                                   :: iterator
     430              :       INTEGER, DIMENSION(2), INTENT(IN), OPTIONAL        :: bounds_i, bounds_j, bounds_k
     431              : 
     432        24190 :       IF (PRESENT(bounds_i)) iterator%bounds_i = bounds_i
     433        14260 :       IF (PRESENT(bounds_j)) iterator%bounds_j = bounds_j
     434        18292 :       IF (PRESENT(bounds_k)) iterator%bounds_k = bounds_k
     435              : 
     436         7672 :    END SUBROUTINE nl_3c_iter_set_bounds
     437              : 
     438              : ! **************************************************************************************************
     439              : !> \brief Destroy 3c-nl iterator
     440              : !> \param iterator ...
     441              : ! **************************************************************************************************
     442         7752 :    SUBROUTINE neighbor_list_3c_iterator_destroy(iterator)
     443              :       TYPE(neighbor_list_3c_iterator_type), &
     444              :          INTENT(INOUT)                                   :: iterator
     445              : 
     446              :       CHARACTER(len=*), PARAMETER :: routineN = 'neighbor_list_3c_iterator_destroy'
     447              : 
     448              :       INTEGER                                            :: handle
     449              : 
     450         7752 :       CALL timeset(routineN, handle)
     451         7752 :       CALL neighbor_list_iterator_release(iterator%iter_ij)
     452         7752 :       CALL neighbor_list_iterator_release(iterator%iter_jk)
     453         7752 :       NULLIFY (iterator%iter_ij)
     454         7752 :       NULLIFY (iterator%iter_jk)
     455              : 
     456         7752 :       CALL timestop(handle)
     457         7752 :    END SUBROUTINE neighbor_list_3c_iterator_destroy
     458              : 
     459              : ! **************************************************************************************************
     460              : !> \brief Iterate 3c-nl iterator
     461              : !> \param iterator ...
     462              : !> \return 0 if successful; 1 if end was reached
     463              : ! **************************************************************************************************
     464      5706732 :    RECURSIVE FUNCTION neighbor_list_3c_iterate(iterator) RESULT(iter_stat)
     465              :       TYPE(neighbor_list_3c_iterator_type), &
     466              :          INTENT(INOUT)                                   :: iterator
     467              :       INTEGER                                            :: iter_stat
     468              : 
     469              :       INTEGER                                            :: iatom, iter_level, jatom, jatom_1, &
     470              :                                                             jatom_2, katom
     471              :       LOGICAL                                            :: skip_this
     472              : 
     473      5706732 :       iter_level = iterator%iter_level
     474              : 
     475      5706732 :       IF (iter_level == 0) THEN
     476       195772 :          iter_stat = neighbor_list_iterate(iterator%iter_ij)
     477              : 
     478       195772 :          IF (iter_stat /= 0) THEN
     479              :             RETURN
     480              :          END IF
     481              : 
     482       188020 :          CALL get_iterator_info(iterator%iter_ij, iatom=iatom, jatom=jatom)
     483       188020 :          skip_this = .FALSE.
     484              :          IF ((iterator%bounds_i(1) > 0 .AND. iatom < iterator%bounds_i(1)) &
     485       188020 :              .OR. (iterator%bounds_i(2) > 0 .AND. iatom > iterator%bounds_i(2))) skip_this = .TRUE.
     486              :          IF ((iterator%bounds_j(1) > 0 .AND. jatom < iterator%bounds_j(1)) &
     487       188020 :              .OR. (iterator%bounds_j(2) > 0 .AND. jatom > iterator%bounds_j(2))) skip_this = .TRUE.
     488              : 
     489       188020 :          IF (skip_this) THEN
     490        85323 :             iter_stat = neighbor_list_3c_iterate(iterator)
     491        85323 :             RETURN
     492              :          END IF
     493              :       END IF
     494              : 
     495      5613657 :       iter_stat = nl_sub_iterate(iterator%iter_jk, iterator%iter_ij)
     496      5613657 :       IF (iter_stat /= 0) THEN
     497       102697 :          iterator%iter_level = 0
     498       102697 :          iter_stat = neighbor_list_3c_iterate(iterator)
     499       102697 :          RETURN
     500              :       ELSE
     501      5510960 :          iterator%iter_level = 1
     502              :       END IF
     503              : 
     504              :       CPASSERT(iter_stat == 0)
     505              :       CPASSERT(iterator%iter_level == 1)
     506      5510960 :       CALL get_iterator_info(iterator%iter_ij, iatom=iatom, jatom=jatom_1)
     507      5510960 :       CALL get_iterator_info(iterator%iter_jk, iatom=jatom_2, jatom=katom)
     508              : 
     509      5510960 :       CPASSERT(jatom_1 == jatom_2)
     510      5510960 :       jatom = jatom_1
     511              : 
     512      5510960 :       skip_this = .FALSE.
     513              :       IF ((iterator%bounds_k(1) > 0 .AND. katom < iterator%bounds_k(1)) &
     514      5510960 :           .OR. (iterator%bounds_k(2) > 0 .AND. katom > iterator%bounds_k(2))) skip_this = .TRUE.
     515              : 
     516              :       IF (skip_this) THEN
     517       312756 :          iter_stat = neighbor_list_3c_iterate(iterator)
     518       312756 :          RETURN
     519              :       END IF
     520              : 
     521      5198204 :       SELECT CASE (iterator%ijk_nl%sym)
     522              :       CASE (symmetric_none)
     523            0 :          skip_this = .FALSE.
     524              :       CASE (symmetric_ij)
     525            0 :          skip_this = .NOT. include_symmetric(iatom, jatom)
     526              :       CASE (symmetric_jk)
     527      4207758 :          skip_this = .NOT. include_symmetric(jatom, katom)
     528              :       CASE (symmetrik_ik)
     529            0 :          skip_this = .NOT. include_symmetric(iatom, katom)
     530              :       CASE (symmetric_ijk)
     531            0 :          skip_this = .NOT. include_symmetric(iatom, jatom) .OR. .NOT. include_symmetric(jatom, katom)
     532              :       CASE DEFAULT
     533      5198204 :          CPABORT("should not happen")
     534              :       END SELECT
     535              : 
     536      4207758 :       IF (skip_this) THEN
     537      1692660 :          iter_stat = neighbor_list_3c_iterate(iterator)
     538      1692660 :          RETURN
     539              :       END IF
     540              : 
     541              :    END FUNCTION neighbor_list_3c_iterate
     542              : 
     543              : ! **************************************************************************************************
     544              : !> \brief Get info of current iteration
     545              : !> \param iterator ...
     546              : !> \param ikind ...
     547              : !> \param jkind ...
     548              : !> \param kkind ...
     549              : !> \param nkind ...
     550              : !> \param iatom ...
     551              : !> \param jatom ...
     552              : !> \param katom ...
     553              : !> \param rij ...
     554              : !> \param rjk ...
     555              : !> \param rik ...
     556              : !> \param cell_j ...
     557              : !> \param cell_k ...
     558              : !> \return ...
     559              : ! **************************************************************************************************
     560      3505544 :    SUBROUTINE get_3c_iterator_info(iterator, ikind, jkind, kkind, nkind, iatom, jatom, katom, &
     561              :                                    rij, rjk, rik, cell_j, cell_k)
     562              :       TYPE(neighbor_list_3c_iterator_type), &
     563              :          INTENT(INOUT)                                   :: iterator
     564              :       INTEGER, INTENT(OUT), OPTIONAL                     :: ikind, jkind, kkind, nkind, iatom, &
     565              :                                                             jatom, katom
     566              :       REAL(KIND=dp), DIMENSION(3), INTENT(OUT), OPTIONAL :: rij, rjk, rik
     567              :       INTEGER, DIMENSION(3), INTENT(OUT), OPTIONAL       :: cell_j, cell_k
     568              : 
     569              :       INTEGER, DIMENSION(2)                              :: atoms_1, atoms_2, kinds_1, kinds_2
     570              :       INTEGER, DIMENSION(3)                              :: cell_1, cell_2
     571              :       REAL(KIND=dp), DIMENSION(3)                        :: r_1, r_2
     572              : 
     573      3505544 :       CPASSERT(iterator%iter_level == 1)
     574              : 
     575              :       CALL get_iterator_info(iterator%iter_ij, &
     576              :                              ikind=kinds_1(1), jkind=kinds_1(2), nkind=nkind, &
     577              :                              iatom=atoms_1(1), jatom=atoms_1(2), r=r_1, &
     578      3505544 :                              cell=cell_1)
     579              : 
     580              :       CALL get_iterator_info(iterator%iter_jk, &
     581              :                              ikind=kinds_2(1), jkind=kinds_2(2), &
     582              :                              iatom=atoms_2(1), jatom=atoms_2(2), r=r_2, &
     583      3505544 :                              cell=cell_2)
     584              : 
     585      3505544 :       IF (PRESENT(ikind)) ikind = kinds_1(1)
     586      3505544 :       IF (PRESENT(jkind)) jkind = kinds_1(2)
     587      3505544 :       IF (PRESENT(kkind)) kkind = kinds_2(2)
     588      3505544 :       IF (PRESENT(iatom)) iatom = atoms_1(1)
     589      3505544 :       IF (PRESENT(jatom)) jatom = atoms_1(2)
     590      3505544 :       IF (PRESENT(katom)) katom = atoms_2(2)
     591              : 
     592      3505544 :       IF (PRESENT(rij)) rij = r_1
     593      3505544 :       IF (PRESENT(rjk)) rjk = r_2
     594     17527720 :       IF (PRESENT(rik)) rik = r_1 + r_2
     595              : 
     596      3505544 :       IF (PRESENT(cell_j)) cell_j = cell_1
     597     16848520 :       IF (PRESENT(cell_k)) cell_k = cell_1 + cell_2
     598              : 
     599      3505544 :    END SUBROUTINE get_3c_iterator_info
     600              : 
     601              : ! **************************************************************************************************
     602              : !> \brief Allocate blocks of a 3-center tensor based on neighborlist
     603              : !> \param t3c empty DBCSR tensor
     604              : !>            Should be of shape (1,1) if no kpoints are used and of shape (nimages, nimages)
     605              : !>            if k-points are used
     606              : !> \param nl_3c 3-center neighborlist
     607              : !> \param basis_i ...
     608              : !> \param basis_j ...
     609              : !> \param basis_k ...
     610              : !> \param qs_env ...
     611              : !> \param potential_parameter ...
     612              : !> \param op_pos ...
     613              : !> \param do_kpoints ...
     614              : !> \param do_hfx_kpoints ...
     615              : !> \param bounds_i ...
     616              : !> \param bounds_j ...
     617              : !> \param bounds_k ...
     618              : !> \param RI_range ...
     619              : !> \param img_to_RI_cell ...
     620              : !> \param cell_to_index ...
     621              : !> \param cell_sym ...
     622              : ! **************************************************************************************************
     623         2552 :    SUBROUTINE alloc_block_3c(t3c, nl_3c, basis_i, basis_j, basis_k, qs_env, potential_parameter, op_pos, &
     624              :                              do_kpoints, do_hfx_kpoints, bounds_i, bounds_j, bounds_k, RI_range, &
     625         2552 :                              img_to_RI_cell, cell_to_index, cell_sym)
     626              :       TYPE(dbt_type), DIMENSION(:, :), INTENT(INOUT)     :: t3c
     627              :       TYPE(neighbor_list_3c_type), INTENT(INOUT)         :: nl_3c
     628              :       TYPE(gto_basis_set_p_type), DIMENSION(:)           :: basis_i, basis_j, basis_k
     629              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     630              :       TYPE(libint_potential_type), INTENT(IN)            :: potential_parameter
     631              :       INTEGER, INTENT(IN), OPTIONAL                      :: op_pos
     632              :       LOGICAL, INTENT(IN), OPTIONAL                      :: do_kpoints, do_hfx_kpoints
     633              :       INTEGER, DIMENSION(2), INTENT(IN), OPTIONAL        :: bounds_i, bounds_j, bounds_k
     634              :       REAL(dp), INTENT(IN), OPTIONAL                     :: RI_range
     635              :       INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL        :: img_to_RI_cell
     636              :       INTEGER, DIMENSION(:, :, :), OPTIONAL, POINTER     :: cell_to_index
     637              :       LOGICAL, INTENT(IN), OPTIONAL                      :: cell_sym
     638              : 
     639              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'alloc_block_3c'
     640              : 
     641              :       INTEGER                                            :: handle, iatom, ikind, j_img, jatom, &
     642              :                                                             jcell, jkind, k_img, katom, kcell, &
     643              :                                                             kkind, natom, ncell_RI, nimg, op_ij, &
     644              :                                                             op_jk, op_pos_prv
     645              :       INTEGER(int_8)                                     :: a, b, nblk_per_thread
     646         2552 :       INTEGER(int_8), ALLOCATABLE, DIMENSION(:, :)       :: nblk
     647         2552 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: img_to_RI_cell_prv
     648              :       INTEGER, DIMENSION(3)                              :: blk_idx, cell_j, cell_k, &
     649              :                                                             kp_index_lbounds, kp_index_ubounds
     650              :       LOGICAL                                            :: cell_sym_prv, do_hfx_kpoints_prv, &
     651              :                                                             do_kpoints_prv
     652              :       REAL(KIND=dp)                                      :: dij, dik, djk, dr_ij, dr_ik, dr_jk, &
     653              :                                                             kind_radius_i, kind_radius_j, &
     654              :                                                             kind_radius_k
     655              :       REAL(KIND=dp), DIMENSION(3)                        :: rij, rik, rjk
     656         2552 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     657              :       TYPE(cell_type), POINTER                           :: cell
     658              :       TYPE(dft_control_type), POINTER                    :: dft_control
     659              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     660              :       TYPE(neighbor_list_3c_iterator_type)               :: nl_3c_iter
     661              :       TYPE(one_dim_int_array), ALLOCATABLE, &
     662         2552 :          DIMENSION(:, :)                                 :: alloc_i, alloc_j, alloc_k
     663         2552 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     664              : 
     665         2552 :       CALL timeset(routineN, handle)
     666         2552 :       NULLIFY (qs_kind_set, atomic_kind_set, cell)
     667              : 
     668         2552 :       IF (PRESENT(do_kpoints)) THEN
     669          464 :          do_kpoints_prv = do_kpoints
     670              :       ELSE
     671              :          do_kpoints_prv = .FALSE.
     672              :       END IF
     673         2552 :       IF (PRESENT(do_hfx_kpoints)) THEN
     674          222 :          do_hfx_kpoints_prv = do_hfx_kpoints
     675              :       ELSE
     676              :          do_hfx_kpoints_prv = .FALSE.
     677              :       END IF
     678          222 :       IF (do_hfx_kpoints_prv) THEN
     679          222 :          CPASSERT(do_kpoints_prv)
     680          222 :          CPASSERT(PRESENT(RI_range))
     681          222 :          CPASSERT(PRESENT(img_to_RI_cell))
     682              :       END IF
     683              : 
     684         2330 :       IF (PRESENT(img_to_RI_cell)) THEN
     685          666 :          ALLOCATE (img_to_RI_cell_prv(SIZE(img_to_RI_cell)))
     686        10432 :          img_to_RI_cell_prv(:) = img_to_RI_cell
     687              :       END IF
     688              : 
     689         2552 :       IF (PRESENT(cell_sym)) THEN
     690         1978 :          cell_sym_prv = cell_sym
     691              :       ELSE
     692              :          cell_sym_prv = .FALSE.
     693              :       END IF
     694              : 
     695         2552 :       dr_ij = 0.0_dp; dr_jk = 0.0_dp; dr_ik = 0.0_dp
     696              : 
     697         2552 :       op_ij = do_potential_id; op_jk = do_potential_id
     698              : 
     699         2552 :       IF (PRESENT(op_pos)) THEN
     700         2552 :          op_pos_prv = op_pos
     701              :       ELSE
     702              :          op_pos_prv = 1
     703              :       END IF
     704              : 
     705         2330 :       SELECT CASE (op_pos_prv)
     706              :       CASE (1)
     707         2330 :          op_ij = potential_parameter%potential_type
     708              :       CASE (2)
     709         2552 :          op_jk = potential_parameter%potential_type
     710              :       END SELECT
     711              : 
     712              :       IF (op_ij == do_potential_truncated .OR. op_ij == do_potential_short &
     713         2552 :           .OR. op_ij == do_potential_mix_cl_trunc) THEN
     714         1488 :          dr_ij = potential_parameter%cutoff_radius*cutoff_screen_factor
     715         1488 :          dr_ik = potential_parameter%cutoff_radius*cutoff_screen_factor
     716         1064 :       ELSEIF (op_ij == do_potential_coulomb) THEN
     717          436 :          dr_ij = 1000000.0_dp
     718          436 :          dr_ik = 1000000.0_dp
     719              :       END IF
     720              : 
     721              :       IF (op_jk == do_potential_truncated .OR. op_jk == do_potential_short &
     722         2552 :           .OR. op_jk == do_potential_mix_cl_trunc) THEN
     723           20 :          dr_jk = potential_parameter%cutoff_radius*cutoff_screen_factor
     724           20 :          dr_ik = potential_parameter%cutoff_radius*cutoff_screen_factor
     725         2532 :       ELSEIF (op_jk == do_potential_coulomb) THEN
     726            0 :          dr_jk = 1000000.0_dp
     727            0 :          dr_ik = 1000000.0_dp
     728              :       END IF
     729              : 
     730              :       CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, qs_kind_set=qs_kind_set, natom=natom, &
     731         2552 :                       dft_control=dft_control, para_env=para_env, cell=cell)
     732              : 
     733         2552 :       IF (do_kpoints_prv) THEN
     734          234 :          CPASSERT(PRESENT(cell_to_index))
     735          234 :          CPASSERT(ASSOCIATED(cell_to_index))
     736              : !         nimg = dft_control%nimages
     737        33696 :          nimg = MAXVAL(cell_to_index)
     738          234 :          ncell_RI = nimg
     739          234 :          IF (do_hfx_kpoints_prv) THEN
     740          222 :             nimg = SIZE(t3c, 1)
     741          222 :             ncell_RI = SIZE(t3c, 2)
     742              :          END IF
     743              :       ELSE
     744              :          nimg = 1
     745              :          ncell_RI = 1
     746              :       END IF
     747              : 
     748         2552 :       IF (do_kpoints_prv) THEN
     749          936 :          kp_index_lbounds = LBOUND(cell_to_index)
     750          936 :          kp_index_ubounds = UBOUND(cell_to_index)
     751              :       END IF
     752              : 
     753              :       !Do a first loop over the nl and count the blocks present
     754        10208 :       ALLOCATE (nblk(nimg, ncell_RI))
     755        14156 :       nblk(:, :) = 0
     756              : 
     757         2552 :       CALL neighbor_list_3c_iterator_create(nl_3c_iter, nl_3c)
     758              : 
     759         2552 :       CALL nl_3c_iter_set_bounds(nl_3c_iter, bounds_i, bounds_j, bounds_k)
     760              : 
     761      1089046 :       DO WHILE (neighbor_list_3c_iterate(nl_3c_iter) == 0)
     762              :          CALL get_3c_iterator_info(nl_3c_iter, iatom=iatom, ikind=ikind, jkind=jkind, kkind=kkind, &
     763      1086494 :                                    rij=rij, rjk=rjk, rik=rik, cell_j=cell_j, cell_k=cell_k)
     764              : 
     765      4345976 :          djk = NORM2(rjk)
     766      4345976 :          dij = NORM2(rij)
     767      4345976 :          dik = NORM2(rik)
     768              : 
     769      1086494 :          IF (do_kpoints_prv) THEN
     770              : 
     771       801066 :             IF (ANY([cell_j(1), cell_j(2), cell_j(3)] < kp_index_lbounds) .OR. &
     772              :                 ANY([cell_j(1), cell_j(2), cell_j(3)] > kp_index_ubounds)) CYCLE
     773              : 
     774       114438 :             jcell = cell_to_index(cell_j(1), cell_j(2), cell_j(3))
     775       114438 :             IF (jcell > nimg .OR. jcell < 1) CYCLE
     776              : 
     777       702612 :             IF (ANY([cell_k(1), cell_k(2), cell_k(3)] < kp_index_lbounds) .OR. &
     778              :                 ANY([cell_k(1), cell_k(2), cell_k(3)] > kp_index_ubounds)) CYCLE
     779              : 
     780        96315 :             kcell = cell_to_index(cell_k(1), cell_k(2), cell_k(3))
     781        96315 :             IF (kcell > nimg .OR. kcell < 1) CYCLE
     782        66939 :             IF (do_hfx_kpoints_prv) THEN
     783        63309 :                IF (dik > RI_range) CYCLE
     784              :                kcell = 1
     785              :             END IF
     786              :          ELSE
     787              :             jcell = 1; kcell = 1
     788              :          END IF
     789              : 
     790       985236 :          CALL get_gto_basis_set(basis_i(ikind)%gto_basis_set, kind_radius=kind_radius_i)
     791       985236 :          CALL get_gto_basis_set(basis_j(jkind)%gto_basis_set, kind_radius=kind_radius_j)
     792       985236 :          CALL get_gto_basis_set(basis_k(kkind)%gto_basis_set, kind_radius=kind_radius_k)
     793              : 
     794       985236 :          IF (kind_radius_j + kind_radius_i + dr_ij < dij) CYCLE
     795       985236 :          IF (kind_radius_j + kind_radius_k + dr_jk < djk) CYCLE
     796       985236 :          IF (kind_radius_k + kind_radius_i + dr_ik < dik) CYCLE
     797              : 
     798      1080522 :          nblk(jcell, kcell) = nblk(jcell, kcell) + 1
     799              :       END DO
     800         2552 :       CALL neighbor_list_3c_iterator_destroy(nl_3c_iter)
     801              : 
     802              :       !Do a second loop over the nl to give block indices
     803        21812 :       ALLOCATE (alloc_i(nimg, ncell_RI))
     804        19260 :       ALLOCATE (alloc_j(nimg, ncell_RI))
     805        19260 :       ALLOCATE (alloc_k(nimg, ncell_RI))
     806         5180 :       DO k_img = 1, ncell_RI
     807        14156 :          DO j_img = 1, nimg
     808        23711 :             ALLOCATE (alloc_i(j_img, k_img)%array(nblk(j_img, k_img)))
     809        23711 :             ALLOCATE (alloc_j(j_img, k_img)%array(nblk(j_img, k_img)))
     810        26339 :             ALLOCATE (alloc_k(j_img, k_img)%array(nblk(j_img, k_img)))
     811              :          END DO
     812              :       END DO
     813        14156 :       nblk(:, :) = 0
     814              : 
     815         2552 :       CALL neighbor_list_3c_iterator_create(nl_3c_iter, nl_3c)
     816              : 
     817         2552 :       CALL nl_3c_iter_set_bounds(nl_3c_iter, bounds_i, bounds_j, bounds_k)
     818              : 
     819      1089046 :       DO WHILE (neighbor_list_3c_iterate(nl_3c_iter) == 0)
     820              :          CALL get_3c_iterator_info(nl_3c_iter, ikind=ikind, jkind=jkind, kkind=kkind, &
     821              :                                    iatom=iatom, jatom=jatom, katom=katom, &
     822      1086494 :                                    rij=rij, rjk=rjk, rik=rik, cell_j=cell_j, cell_k=cell_k)
     823              : 
     824      4345976 :          djk = NORM2(rjk)
     825      4345976 :          dij = NORM2(rij)
     826      4345976 :          dik = NORM2(rik)
     827              : 
     828      1086494 :          IF (do_kpoints_prv) THEN
     829              : 
     830       801066 :             IF (ANY([cell_j(1), cell_j(2), cell_j(3)] < kp_index_lbounds) .OR. &
     831              :                 ANY([cell_j(1), cell_j(2), cell_j(3)] > kp_index_ubounds)) CYCLE
     832              : 
     833       114438 :             jcell = cell_to_index(cell_j(1), cell_j(2), cell_j(3))
     834       114438 :             IF (jcell > nimg .OR. jcell < 1) CYCLE
     835              : 
     836       702612 :             IF (ANY([cell_k(1), cell_k(2), cell_k(3)] < kp_index_lbounds) .OR. &
     837              :                 ANY([cell_k(1), cell_k(2), cell_k(3)] > kp_index_ubounds)) CYCLE
     838              : 
     839        96315 :             kcell = cell_to_index(cell_k(1), cell_k(2), cell_k(3))
     840        96315 :             IF (kcell > nimg .OR. kcell < 1) CYCLE
     841        66939 :             IF (do_hfx_kpoints_prv) THEN
     842        63309 :                IF (dik > RI_range) CYCLE
     843         9550 :                kcell = img_to_RI_cell_prv(kcell)
     844              :             END IF
     845              :          ELSE
     846              :             jcell = 1; kcell = 1
     847              :          END IF
     848              : 
     849      3940944 :          blk_idx = [iatom, jatom, katom]
     850       985236 :          IF (do_hfx_kpoints_prv) THEN
     851         9550 :             blk_idx(3) = (kcell - 1)*natom + katom
     852         9550 :             kcell = 1
     853              :          END IF
     854              : 
     855       985236 :          CALL get_gto_basis_set(basis_i(ikind)%gto_basis_set, kind_radius=kind_radius_i)
     856       985236 :          CALL get_gto_basis_set(basis_j(jkind)%gto_basis_set, kind_radius=kind_radius_j)
     857       985236 :          CALL get_gto_basis_set(basis_k(kkind)%gto_basis_set, kind_radius=kind_radius_k)
     858              : 
     859       985236 :          IF (kind_radius_j + kind_radius_i + dr_ij < dij) CYCLE
     860       985236 :          IF (kind_radius_j + kind_radius_k + dr_jk < djk) CYCLE
     861       985236 :          IF (kind_radius_k + kind_radius_i + dr_ik < dik) CYCLE
     862              : 
     863       497535 :          nblk(jcell, kcell) = nblk(jcell, kcell) + 1
     864              : 
     865              :          !Note: there may be repeated indices due to periodic images => dbt_reserve_blocks takes care of it
     866       497535 :          alloc_i(jcell, kcell)%array(nblk(jcell, kcell)) = blk_idx(1)
     867       497535 :          alloc_j(jcell, kcell)%array(nblk(jcell, kcell)) = blk_idx(2)
     868      1080522 :          alloc_k(jcell, kcell)%array(nblk(jcell, kcell)) = blk_idx(3)
     869              : 
     870              :       END DO
     871         2552 :       CALL neighbor_list_3c_iterator_destroy(nl_3c_iter)
     872              : 
     873              : !TODO: Parallelize creation of block list.
     874              : !$OMP PARALLEL DEFAULT(NONE) SHARED(t3c,nimg,nblk,alloc_i,alloc_j,alloc_k,ncell_RI,cell_sym_prv) &
     875         2552 : !$OMP PRIVATE(k_img,j_img,nblk_per_thread,A,b)
     876              :       DO k_img = 1, ncell_RI
     877              :          DO j_img = 1, nimg
     878              :             IF (cell_sym_prv .AND. j_img < k_img) CYCLE
     879              :             IF (ALLOCATED(alloc_i(j_img, k_img)%array)) THEN
     880              :                nblk_per_thread = nblk(j_img, k_img)/omp_get_num_threads() + 1
     881              :                a = omp_get_thread_num()*nblk_per_thread + 1
     882              :                b = MIN(a + nblk_per_thread, nblk(j_img, k_img))
     883              :                CALL dbt_reserve_blocks(t3c(j_img, k_img), &
     884              :                                        alloc_i(j_img, k_img)%array(a:b), &
     885              :                                        alloc_j(j_img, k_img)%array(a:b), &
     886              :                                        alloc_k(j_img, k_img)%array(a:b))
     887              :             END IF
     888              :          END DO
     889              :       END DO
     890              : !$OMP END PARALLEL
     891              : 
     892         2552 :       CALL timestop(handle)
     893              : 
     894        52448 :    END SUBROUTINE alloc_block_3c
     895              : 
     896              : ! **************************************************************************************************
     897              : !> \brief Build 3-center derivative tensors
     898              : !> \param t3c_der_i empty DBCSR tensor which will contain the 1st center derivatives
     899              : !> \param t3c_der_k empty DBCSR tensor which will contain the 3rd center derivatives
     900              : !> \param filter_eps Filter threshold for tensor blocks
     901              : !> \param qs_env ...
     902              : !> \param nl_3c 3-center neighborlist
     903              : !> \param basis_i ...
     904              : !> \param basis_j ...
     905              : !> \param basis_k ...
     906              : !> \param potential_parameter ...
     907              : !> \param der_eps neglect integrals smaller than der_eps
     908              : !> \param op_pos operator position.
     909              : !>        1: calculate (i|jk) integrals,
     910              : !>        2: calculate (ij|k) integrals
     911              : !> \param do_kpoints ...
     912              : !> this routine requires that libint has been static initialised somewhere else
     913              : !> \param do_hfx_kpoints ...
     914              : !> \param bounds_i ...
     915              : !> \param bounds_j ...
     916              : !> \param bounds_k ...
     917              : !> \param RI_range ...
     918              : !> \param img_to_RI_cell ...
     919              : ! **************************************************************************************************
     920          574 :    SUBROUTINE build_3c_derivatives(t3c_der_i, t3c_der_k, filter_eps, qs_env, &
     921          574 :                                    nl_3c, basis_i, basis_j, basis_k, &
     922              :                                    potential_parameter, der_eps, &
     923              :                                    op_pos, do_kpoints, do_hfx_kpoints, &
     924              :                                    bounds_i, bounds_j, bounds_k, &
     925          574 :                                    RI_range, img_to_RI_cell)
     926              : 
     927              :       TYPE(dbt_type), DIMENSION(:, :, :), INTENT(INOUT)  :: t3c_der_i, t3c_der_k
     928              :       REAL(KIND=dp), INTENT(IN)                          :: filter_eps
     929              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     930              :       TYPE(neighbor_list_3c_type), INTENT(INOUT)         :: nl_3c
     931              :       TYPE(gto_basis_set_p_type), DIMENSION(:)           :: basis_i, basis_j, basis_k
     932              :       TYPE(libint_potential_type), INTENT(IN)            :: potential_parameter
     933              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: der_eps
     934              :       INTEGER, INTENT(IN), OPTIONAL                      :: op_pos
     935              :       LOGICAL, INTENT(IN), OPTIONAL                      :: do_kpoints, do_hfx_kpoints
     936              :       INTEGER, DIMENSION(2), INTENT(IN), OPTIONAL        :: bounds_i, bounds_j, bounds_k
     937              :       REAL(dp), INTENT(IN), OPTIONAL                     :: RI_range
     938              :       INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL        :: img_to_RI_cell
     939              : 
     940              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'build_3c_derivatives'
     941              : 
     942              :       INTEGER :: block_end_i, block_end_j, block_end_k, block_start_i, block_start_j, &
     943              :          block_start_k, egfi, handle, handle2, i, i_img, i_xyz, iatom, ibasis, ikind, ilist, imax, &
     944              :          iset, j_img, jatom, jcell, jkind, jset, katom, kcell, kkind, kset, m_max, max_ncoj, &
     945              :          max_nset, max_nsgfi, maxli, maxlj, maxlk, mepos, natom, nbasis, ncell_RI, ncoi, ncoj, &
     946              :          ncok, nimg, nseti, nsetj, nsetk, nthread, op_ij, op_jk, op_pos_prv, sgfi, sgfj, sgfk, &
     947              :          unit_id
     948          574 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: img_to_RI_cell_prv
     949              :       INTEGER, DIMENSION(2)                              :: bo
     950              :       INTEGER, DIMENSION(3)                              :: blk_idx, blk_size, cell_j, cell_k, &
     951              :                                                             kp_index_lbounds, kp_index_ubounds, sp
     952          574 :       INTEGER, DIMENSION(:), POINTER                     :: lmax_i, lmax_j, lmax_k, lmin_i, lmin_j, &
     953         1148 :                                                             lmin_k, npgfi, npgfj, npgfk, nsgfi, &
     954          574 :                                                             nsgfj, nsgfk
     955          574 :       INTEGER, DIMENSION(:, :), POINTER                  :: first_sgf_i, first_sgf_j, first_sgf_k
     956          574 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
     957              :       LOGICAL                                            :: do_hfx_kpoints_prv, do_kpoints_prv, &
     958              :                                                             found, skip
     959              :       LOGICAL, DIMENSION(3)                              :: block_j_not_zero, block_k_not_zero, &
     960              :                                                             der_j_zero, der_k_zero
     961              :       REAL(dp), DIMENSION(3)                             :: der_ext_i, der_ext_j, der_ext_k
     962              :       REAL(KIND=dp)                                      :: dij, dik, djk, dr_ij, dr_ik, dr_jk, &
     963              :                                                             kind_radius_i, kind_radius_j, &
     964              :                                                             kind_radius_k, prefac
     965          574 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: ccp_buffer, cpp_buffer, &
     966          574 :                                                             max_contraction_i, max_contraction_j, &
     967          574 :                                                             max_contraction_k
     968          574 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: dijk_contr, dummy_block_t
     969          574 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :, :)  :: block_t_i, block_t_j, block_t_k, dijk_j, &
     970         1148 :                                                             dijk_k, tmp_ijk_i, tmp_ijk_j
     971              :       REAL(KIND=dp), DIMENSION(3)                        :: ri, rij, rik, rj, rjk, rk
     972          574 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: set_radius_i, set_radius_j, set_radius_k
     973          574 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: rpgf_i, rpgf_j, rpgf_k, sphi_i, sphi_j, &
     974         1148 :                                                             sphi_k, zeti, zetj, zetk
     975          574 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     976         1148 :       TYPE(cp_2d_r_p_type), DIMENSION(:, :), POINTER     :: spi, spk, tspj
     977              :       TYPE(cp_libint_t)                                  :: lib
     978         4018 :       TYPE(dbt_type)                                     :: t3c_tmp
     979          574 :       TYPE(dbt_type), ALLOCATABLE, DIMENSION(:, :)       :: t3c_template
     980          574 :       TYPE(dbt_type), ALLOCATABLE, DIMENSION(:, :, :)    :: t3c_der_j
     981              :       TYPE(dft_control_type), POINTER                    :: dft_control
     982              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set
     983              :       TYPE(kpoint_type), POINTER                         :: kpoints
     984              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     985              :       TYPE(neighbor_list_3c_iterator_type)               :: nl_3c_iter
     986          574 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     987              : 
     988          574 :       CALL timeset(routineN, handle)
     989              : 
     990          574 :       IF (PRESENT(do_kpoints)) THEN
     991           82 :          do_kpoints_prv = do_kpoints
     992              :       ELSE
     993              :          do_kpoints_prv = .FALSE.
     994              :       END IF
     995              : 
     996          574 :       IF (PRESENT(do_hfx_kpoints)) THEN
     997           82 :          do_hfx_kpoints_prv = do_hfx_kpoints
     998              :       ELSE
     999              :          do_hfx_kpoints_prv = .FALSE.
    1000              :       END IF
    1001           82 :       IF (do_hfx_kpoints_prv) THEN
    1002           82 :          CPASSERT(do_kpoints_prv)
    1003           82 :          CPASSERT(PRESENT(RI_range))
    1004           82 :          CPASSERT(PRESENT(img_to_RI_cell))
    1005              :       END IF
    1006              : 
    1007          492 :       IF (PRESENT(img_to_RI_cell)) THEN
    1008          246 :          ALLOCATE (img_to_RI_cell_prv(SIZE(img_to_RI_cell)))
    1009         3834 :          img_to_RI_cell_prv(:) = img_to_RI_cell
    1010              :       END IF
    1011              : 
    1012          574 :       op_ij = do_potential_id; op_jk = do_potential_id
    1013              : 
    1014          574 :       IF (PRESENT(op_pos)) THEN
    1015          574 :          op_pos_prv = op_pos
    1016              :       ELSE
    1017            0 :          op_pos_prv = 1
    1018              :       END IF
    1019              : 
    1020          492 :       SELECT CASE (op_pos_prv)
    1021              :       CASE (1)
    1022          492 :          op_ij = potential_parameter%potential_type
    1023              :       CASE (2)
    1024          574 :          op_jk = potential_parameter%potential_type
    1025              :       END SELECT
    1026              : 
    1027          574 :       dr_ij = 0.0_dp; dr_jk = 0.0_dp; dr_ik = 0.0_dp
    1028              : 
    1029              :       IF (op_ij == do_potential_truncated .OR. op_ij == do_potential_short &
    1030          574 :           .OR. op_ij == do_potential_mix_cl_trunc) THEN
    1031           50 :          dr_ij = potential_parameter%cutoff_radius*cutoff_screen_factor
    1032           50 :          dr_ik = potential_parameter%cutoff_radius*cutoff_screen_factor
    1033          524 :       ELSEIF (op_ij == do_potential_coulomb) THEN
    1034          244 :          dr_ij = 1000000.0_dp
    1035          244 :          dr_ik = 1000000.0_dp
    1036              :       END IF
    1037              : 
    1038              :       IF (op_jk == do_potential_truncated .OR. op_jk == do_potential_short &
    1039          574 :           .OR. op_jk == do_potential_mix_cl_trunc) THEN
    1040            8 :          dr_jk = potential_parameter%cutoff_radius*cutoff_screen_factor
    1041            8 :          dr_ik = potential_parameter%cutoff_radius*cutoff_screen_factor
    1042          566 :       ELSEIF (op_jk == do_potential_coulomb) THEN
    1043            0 :          dr_jk = 1000000.0_dp
    1044            0 :          dr_ik = 1000000.0_dp
    1045              :       END IF
    1046              : 
    1047          574 :       NULLIFY (qs_kind_set, atomic_kind_set)
    1048              : 
    1049              :       ! get stuff
    1050              :       CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, qs_kind_set=qs_kind_set, &
    1051          574 :                       natom=natom, kpoints=kpoints, dft_control=dft_control, para_env=para_env)
    1052              : 
    1053          574 :       IF (do_kpoints_prv) THEN
    1054           82 :          nimg = dft_control%nimages
    1055           82 :          ncell_RI = nimg
    1056           82 :          IF (do_hfx_kpoints_prv) THEN
    1057           82 :             nimg = SIZE(t3c_der_k, 1)
    1058           82 :             ncell_RI = SIZE(t3c_der_k, 2)
    1059              :          END IF
    1060           82 :          CALL get_kpoint_info(kpoints, cell_to_index=cell_to_index)
    1061              :       ELSE
    1062              :          nimg = 1
    1063              :          ncell_RI = 1
    1064              :       END IF
    1065              : 
    1066          574 :       IF (do_hfx_kpoints_prv) THEN
    1067           82 :          CPASSERT(op_pos_prv == 2)
    1068              :       ELSE
    1069         1968 :          CPASSERT(ALL(SHAPE(t3c_der_k) == [nimg, ncell_RI, 3]))
    1070              :       END IF
    1071              : 
    1072         8910 :       ALLOCATE (t3c_template(nimg, ncell_RI))
    1073         1148 :       DO j_img = 1, ncell_RI
    1074         3744 :          DO i_img = 1, nimg
    1075         3170 :             CALL dbt_create(t3c_der_i(i_img, j_img, 1), t3c_template(i_img, j_img))
    1076              :          END DO
    1077              :       END DO
    1078              : 
    1079              :       CALL alloc_block_3c(t3c_template, nl_3c, basis_i, basis_j, basis_k, qs_env, potential_parameter, &
    1080              :                           op_pos=op_pos_prv, do_kpoints=do_kpoints, do_hfx_kpoints=do_hfx_kpoints, &
    1081              :                           bounds_i=bounds_i, bounds_j=bounds_j, bounds_k=bounds_k, &
    1082         1066 :                           RI_range=RI_range, img_to_RI_cell=img_to_RI_cell, cell_to_index=cell_to_index)
    1083         2296 :       DO i_xyz = 1, 3
    1084         4018 :          DO j_img = 1, ncell_RI
    1085        11232 :             DO i_img = 1, nimg
    1086         7788 :                CALL dbt_copy(t3c_template(i_img, j_img), t3c_der_i(i_img, j_img, i_xyz))
    1087         9510 :                CALL dbt_copy(t3c_template(i_img, j_img), t3c_der_k(i_img, j_img, i_xyz))
    1088              :             END DO
    1089              :          END DO
    1090              :       END DO
    1091              : 
    1092         1148 :       DO j_img = 1, ncell_RI
    1093         3744 :          DO i_img = 1, nimg
    1094         3170 :             CALL dbt_destroy(t3c_template(i_img, j_img))
    1095              :          END DO
    1096              :       END DO
    1097         3170 :       DEALLOCATE (t3c_template)
    1098              : 
    1099          574 :       IF (nl_3c%sym == symmetric_jk) THEN
    1100         9840 :          ALLOCATE (t3c_der_j(nimg, ncell_RI, 3))
    1101         1968 :          DO i_xyz = 1, 3
    1102         3444 :             DO j_img = 1, ncell_RI
    1103         4428 :                DO i_img = 1, nimg
    1104         1476 :                   CALL dbt_create(t3c_der_k(i_img, j_img, i_xyz), t3c_der_j(i_img, j_img, i_xyz))
    1105         2952 :                   CALL dbt_copy(t3c_der_k(i_img, j_img, i_xyz), t3c_der_j(i_img, j_img, i_xyz))
    1106              :                END DO
    1107              :             END DO
    1108              :          END DO
    1109              :       END IF
    1110              : 
    1111              :       !Need the max l for each basis for libint and max nset, nco and nsgf for LIBXSMM contraction
    1112          574 :       nbasis = SIZE(basis_i)
    1113          574 :       max_nsgfi = 0
    1114          574 :       max_nset = 0
    1115          574 :       maxli = 0
    1116         1638 :       DO ibasis = 1, nbasis
    1117              :          CALL get_gto_basis_set(gto_basis_set=basis_i(ibasis)%gto_basis_set, maxl=imax, &
    1118         1064 :                                 nset=iset, nsgf_set=nsgfi, npgf=npgfi)
    1119         1064 :          maxli = MAX(maxli, imax)
    1120         1064 :          max_nset = MAX(max_nset, iset)
    1121         5792 :          max_nsgfi = MAX(max_nsgfi, MAXVAL(nsgfi))
    1122              :       END DO
    1123              :       max_ncoj = 0
    1124              :       maxlj = 0
    1125         1638 :       DO ibasis = 1, nbasis
    1126              :          CALL get_gto_basis_set(gto_basis_set=basis_j(ibasis)%gto_basis_set, maxl=imax, &
    1127         1064 :                                 nset=jset, nsgf_set=nsgfj, npgf=npgfj)
    1128         1064 :          maxlj = MAX(maxlj, imax)
    1129         1064 :          max_nset = MAX(max_nset, jset)
    1130         4484 :          max_ncoj = MAX(max_ncoj, MAXVAL(npgfj)*ncoset(maxlj))
    1131              :       END DO
    1132              :       maxlk = 0
    1133         1638 :       DO ibasis = 1, nbasis
    1134              :          CALL get_gto_basis_set(gto_basis_set=basis_k(ibasis)%gto_basis_set, maxl=imax, &
    1135         1064 :                                 nset=kset, nsgf_set=nsgfk, npgf=npgfk)
    1136         1064 :          maxlk = MAX(maxlk, imax)
    1137         1638 :          max_nset = MAX(max_nset, kset)
    1138              :       END DO
    1139          574 :       m_max = maxli + maxlj + maxlk + 1
    1140              : 
    1141              :       !To minimize expensive memory ops and generally optimize contraction, pre-allocate
    1142              :       !contiguous sphi arrays (and transposed in the case of sphi_i)
    1143              : 
    1144          574 :       NULLIFY (tspj, spi, spk)
    1145        26756 :       ALLOCATE (spi(max_nset, nbasis), tspj(max_nset, nbasis), spk(max_nset, nbasis))
    1146              : 
    1147         1638 :       DO ibasis = 1, nbasis
    1148         7962 :          DO iset = 1, max_nset
    1149         6324 :             NULLIFY (spi(iset, ibasis)%array)
    1150         6324 :             NULLIFY (tspj(iset, ibasis)%array)
    1151         7388 :             NULLIFY (spk(iset, ibasis)%array)
    1152              :          END DO
    1153              :       END DO
    1154              : 
    1155         2296 :       DO ilist = 1, 3
    1156         5488 :          DO ibasis = 1, nbasis
    1157         3192 :             IF (ilist == 1) basis_set => basis_i(ibasis)%gto_basis_set
    1158         3192 :             IF (ilist == 2) basis_set => basis_j(ibasis)%gto_basis_set
    1159         3192 :             IF (ilist == 3) basis_set => basis_k(ibasis)%gto_basis_set
    1160              : 
    1161        14608 :             DO iset = 1, basis_set%nset
    1162              : 
    1163         9694 :                ncoi = basis_set%npgf(iset)*ncoset(basis_set%lmax(iset))
    1164         9694 :                sgfi = basis_set%first_sgf(1, iset)
    1165         9694 :                egfi = sgfi + basis_set%nsgf_set(iset) - 1
    1166              : 
    1167        12886 :                IF (ilist == 1) THEN
    1168        16616 :                   ALLOCATE (spi(iset, ibasis)%array(ncoi, basis_set%nsgf_set(iset)))
    1169      3075498 :                   spi(iset, ibasis)%array(:, :) = basis_set%sphi(1:ncoi, sgfi:egfi)
    1170              : 
    1171         5540 :                ELSE IF (ilist == 2) THEN
    1172        11384 :                   ALLOCATE (tspj(iset, ibasis)%array(basis_set%nsgf_set(iset), ncoi))
    1173       177774 :                   tspj(iset, ibasis)%array(:, :) = TRANSPOSE(basis_set%sphi(1:ncoi, sgfi:egfi))
    1174              : 
    1175              :                ELSE
    1176        10776 :                   ALLOCATE (spk(iset, ibasis)%array(ncoi, basis_set%nsgf_set(iset)))
    1177       838246 :                   spk(iset, ibasis)%array(:, :) = basis_set%sphi(1:ncoi, sgfi:egfi)
    1178              :                END IF
    1179              : 
    1180              :             END DO !iset
    1181              :          END DO !ibasis
    1182              :       END DO !ilist
    1183              : 
    1184              :       !Init the truncated Coulomb operator
    1185              :       IF (op_ij == do_potential_truncated .OR. op_jk == do_potential_truncated .OR. &
    1186          574 :           op_ij == do_potential_mix_cl_trunc .OR. op_jk == do_potential_mix_cl_trunc) THEN
    1187              : 
    1188           58 :          IF (m_max > get_lmax_init()) THEN
    1189            8 :             IF (para_env%mepos == 0) THEN
    1190            4 :                CALL open_file(unit_number=unit_id, file_name=potential_parameter%filename)
    1191              :             END IF
    1192            8 :             CALL init(m_max, unit_id, para_env%mepos, para_env)
    1193            8 :             IF (para_env%mepos == 0) THEN
    1194            4 :                CALL close_file(unit_id)
    1195              :             END IF
    1196              :          END IF
    1197              :       END IF
    1198              : 
    1199          574 :       CALL init_md_ftable(nmax=m_max)
    1200              : 
    1201          574 :       IF (do_kpoints_prv) THEN
    1202          328 :          kp_index_lbounds = LBOUND(cell_to_index)
    1203          328 :          kp_index_ubounds = UBOUND(cell_to_index)
    1204              :       END IF
    1205              : 
    1206          574 :       nthread = 1
    1207          574 : !$    nthread = omp_get_max_threads()
    1208              : 
    1209              : !$OMP PARALLEL DEFAULT(NONE) &
    1210              : !$OMP SHARED (nthread,do_kpoints_prv,kp_index_lbounds,kp_index_ubounds,maxli,maxlk,maxlj,bounds_i,&
    1211              : !$OMP         bounds_j,bounds_k,nimg,basis_i,basis_j,basis_k,dr_ij,dr_jk,dr_ik,ncoset,op_pos_prv,&
    1212              : !$OMP         potential_parameter,der_eps,tspj,spi,spk,cell_to_index,RI_range,natom,nl_3c,&
    1213              : !$OMP         t3c_der_i,t3c_der_k,t3c_der_j,ncell_RI,img_to_RI_cell_prv,do_hfx_kpoints_prv) &
    1214              : !$OMP PRIVATE (lib,nl_3c_iter,ikind,jkind,kkind,iatom,jatom,katom,rij,rjk,rik,cell_j,cell_k,&
    1215              : !$OMP          prefac,jcell,kcell,first_sgf_i,lmax_i,lmin_i,npgfi,nseti,nsgfi,rpgf_i,set_radius_i,&
    1216              : !$OMP          sphi_i,zeti,kind_radius_i,first_sgf_j,lmax_j,lmin_j,npgfj,nsetj,nsgfj,rpgf_j,&
    1217              : !$OMP          set_radius_j,sphi_j,zetj,kind_radius_j,first_sgf_k,lmax_k,lmin_k,npgfk,nsetk,nsgfk,&
    1218              : !$OMP          rpgf_k,set_radius_k,sphi_k,zetk,kind_radius_k,djk,dij,dik,ncoi,ncoj,ncok,sgfi,sgfj,&
    1219              : !$OMP          sgfk,dijk_j,dijk_k,ri,rj,rk,max_contraction_i,max_contraction_j,blk_idx,&
    1220              : !$OMP          max_contraction_k,iset,jset,kset,block_t_i,blk_size,dijk_contr,cpp_buffer,ccp_buffer,&
    1221              : !$OMP          block_start_j,block_end_j,block_start_k,block_end_k,block_start_i,block_end_i,found,&
    1222              : !$OMP          dummy_block_t,sp,handle2,mepos,bo,block_t_k,der_ext_i,der_ext_j,der_ext_k,tmp_ijk_i,&
    1223          574 : !$OMP          block_k_not_zero,der_k_zero,skip,der_j_zero,block_t_j,block_j_not_zero,tmp_ijk_j,i)
    1224              : 
    1225              :       mepos = 0
    1226              : !$    mepos = omp_get_thread_num()
    1227              : 
    1228              :       CALL cp_libint_init_3eri1(lib, MAX(maxli, maxlj, maxlk))
    1229              :       CALL cp_libint_set_contrdepth(lib, 1)
    1230              :       CALL neighbor_list_3c_iterator_create(nl_3c_iter, nl_3c)
    1231              : 
    1232              :       !We split the provided bounds among the threads such that each threads works on a different set of atoms
    1233              :       IF (PRESENT(bounds_i)) THEN
    1234              :          bo = get_limit(bounds_i(2) - bounds_i(1) + 1, nthread, mepos)
    1235              :          bo(:) = bo(:) + bounds_i(1) - 1
    1236              :          CALL nl_3c_iter_set_bounds(nl_3c_iter, bo, bounds_j, bounds_k)
    1237              :       ELSE IF (PRESENT(bounds_j)) THEN
    1238              :          bo = get_limit(bounds_j(2) - bounds_j(1) + 1, nthread, mepos)
    1239              :          bo(:) = bo(:) + bounds_j(1) - 1
    1240              :          CALL nl_3c_iter_set_bounds(nl_3c_iter, bounds_i, bo, bounds_k)
    1241              :       ELSE IF (PRESENT(bounds_k)) THEN
    1242              :          bo = get_limit(bounds_k(2) - bounds_k(1) + 1, nthread, mepos)
    1243              :          bo(:) = bo(:) + bounds_k(1) - 1
    1244              :          CALL nl_3c_iter_set_bounds(nl_3c_iter, bounds_i, bounds_j, bo)
    1245              :       ELSE
    1246              :          bo = get_limit(natom, nthread, mepos)
    1247              :          CALL nl_3c_iter_set_bounds(nl_3c_iter, bo, bounds_j, bounds_k)
    1248              :       END IF
    1249              : 
    1250              :       skip = .FALSE.
    1251              :       IF (bo(1) > bo(2)) skip = .TRUE.
    1252              : 
    1253              :       DO WHILE (neighbor_list_3c_iterate(nl_3c_iter) == 0)
    1254              :          CALL get_3c_iterator_info(nl_3c_iter, ikind=ikind, jkind=jkind, kkind=kkind, &
    1255              :                                    iatom=iatom, jatom=jatom, katom=katom, &
    1256              :                                    rij=rij, rjk=rjk, rik=rik, cell_j=cell_j, cell_k=cell_k)
    1257              :          IF (skip) EXIT
    1258              : 
    1259              :          djk = NORM2(rjk)
    1260              :          dij = NORM2(rij)
    1261              :          dik = NORM2(rik)
    1262              : 
    1263              :          IF (do_kpoints_prv) THEN
    1264              :             prefac = 0.5_dp
    1265              :          ELSEIF (nl_3c%sym == symmetric_jk) THEN
    1266              :             IF (jatom == katom) THEN
    1267              :                prefac = 0.5_dp
    1268              :             ELSE
    1269              :                prefac = 1.0_dp
    1270              :             END IF
    1271              :          ELSE
    1272              :             prefac = 1.0_dp
    1273              :          END IF
    1274              :          IF (do_hfx_kpoints_prv) prefac = 1.0_dp
    1275              : 
    1276              :          IF (do_kpoints_prv) THEN
    1277              : 
    1278              :             IF (ANY([cell_j(1), cell_j(2), cell_j(3)] < kp_index_lbounds) .OR. &
    1279              :                 ANY([cell_j(1), cell_j(2), cell_j(3)] > kp_index_ubounds)) CYCLE
    1280              : 
    1281              :             jcell = cell_to_index(cell_j(1), cell_j(2), cell_j(3))
    1282              :             IF (jcell > nimg .OR. jcell < 1) CYCLE
    1283              : 
    1284              :             IF (ANY([cell_k(1), cell_k(2), cell_k(3)] < kp_index_lbounds) .OR. &
    1285              :                 ANY([cell_k(1), cell_k(2), cell_k(3)] > kp_index_ubounds)) CYCLE
    1286              : 
    1287              :             kcell = cell_to_index(cell_k(1), cell_k(2), cell_k(3))
    1288              :             IF (kcell > nimg .OR. kcell < 1) CYCLE
    1289              :             !In case of HFX k-points, we only consider P^k if d_ik <= RI_range
    1290              :             IF (do_hfx_kpoints_prv) THEN
    1291              :                IF (dik > RI_range) CYCLE
    1292              :                kcell = img_to_RI_cell_prv(kcell)
    1293              :             END IF
    1294              :          ELSE
    1295              :             jcell = 1; kcell = 1
    1296              :          END IF
    1297              : 
    1298              :          blk_idx = [iatom, jatom, katom]
    1299              :          IF (do_hfx_kpoints_prv) THEN
    1300              :             blk_idx(3) = (kcell - 1)*natom + katom
    1301              :             kcell = 1
    1302              :          END IF
    1303              : 
    1304              :          CALL get_gto_basis_set(basis_i(ikind)%gto_basis_set, first_sgf=first_sgf_i, lmax=lmax_i, lmin=lmin_i, &
    1305              :                                 npgf=npgfi, nset=nseti, nsgf_set=nsgfi, pgf_radius=rpgf_i, set_radius=set_radius_i, &
    1306              :                                 sphi=sphi_i, zet=zeti, kind_radius=kind_radius_i)
    1307              : 
    1308              :          CALL get_gto_basis_set(basis_j(jkind)%gto_basis_set, first_sgf=first_sgf_j, lmax=lmax_j, lmin=lmin_j, &
    1309              :                                 npgf=npgfj, nset=nsetj, nsgf_set=nsgfj, pgf_radius=rpgf_j, set_radius=set_radius_j, &
    1310              :                                 sphi=sphi_j, zet=zetj, kind_radius=kind_radius_j)
    1311              : 
    1312              :          CALL get_gto_basis_set(basis_k(kkind)%gto_basis_set, first_sgf=first_sgf_k, lmax=lmax_k, lmin=lmin_k, &
    1313              :                                 npgf=npgfk, nset=nsetk, nsgf_set=nsgfk, pgf_radius=rpgf_k, set_radius=set_radius_k, &
    1314              :                                 sphi=sphi_k, zet=zetk, kind_radius=kind_radius_k)
    1315              : 
    1316              :          IF (kind_radius_j + kind_radius_i + dr_ij < dij) CYCLE
    1317              :          IF (kind_radius_j + kind_radius_k + dr_jk < djk) CYCLE
    1318              :          IF (kind_radius_k + kind_radius_i + dr_ik < dik) CYCLE
    1319              : 
    1320              :          IF (PRESENT(der_eps)) THEN
    1321              :             ALLOCATE (max_contraction_i(nseti))
    1322              :             DO iset = 1, nseti
    1323              :                sgfi = first_sgf_i(1, iset)
    1324              :                max_contraction_i(iset) = MAXVAL([(SUM(ABS(sphi_i(:, i))), i=sgfi, sgfi + nsgfi(iset) - 1)])
    1325              :             END DO
    1326              : 
    1327              :             ALLOCATE (max_contraction_j(nsetj))
    1328              :             DO jset = 1, nsetj
    1329              :                sgfj = first_sgf_j(1, jset)
    1330              :                max_contraction_j(jset) = MAXVAL([(SUM(ABS(sphi_j(:, i))), i=sgfj, sgfj + nsgfj(jset) - 1)])
    1331              :             END DO
    1332              : 
    1333              :             ALLOCATE (max_contraction_k(nsetk))
    1334              :             DO kset = 1, nsetk
    1335              :                sgfk = first_sgf_k(1, kset)
    1336              :                max_contraction_k(kset) = MAXVAL([(SUM(ABS(sphi_k(:, i))), i=sgfk, sgfk + nsgfk(kset) - 1)])
    1337              :             END DO
    1338              :          END IF
    1339              : 
    1340              :          CALL dbt_blk_sizes(t3c_der_i(jcell, kcell, 1), blk_idx, blk_size)
    1341              : 
    1342              :          ALLOCATE (block_t_i(blk_size(2), blk_size(3), blk_size(1), 3), SOURCE=0.0_dp)
    1343              :          ALLOCATE (block_t_j(blk_size(2), blk_size(3), blk_size(1), 3), SOURCE=0.0_dp)
    1344              :          ALLOCATE (block_t_k(blk_size(2), blk_size(3), blk_size(1), 3), SOURCE=0.0_dp)
    1345              : 
    1346              :          block_j_not_zero = .FALSE.
    1347              :          block_k_not_zero = .FALSE.
    1348              : 
    1349              :          DO iset = 1, nseti
    1350              : 
    1351              :             DO jset = 1, nsetj
    1352              : 
    1353              :                IF (set_radius_j(jset) + set_radius_i(iset) + dr_ij < dij) CYCLE
    1354              : 
    1355              :                DO kset = 1, nsetk
    1356              : 
    1357              :                   IF (set_radius_j(jset) + set_radius_k(kset) + dr_jk < djk) CYCLE
    1358              :                   IF (set_radius_k(kset) + set_radius_i(iset) + dr_ik < dik) CYCLE
    1359              : 
    1360              :                   ncoi = npgfi(iset)*ncoset(lmax_i(iset))
    1361              :                   ncoj = npgfj(jset)*ncoset(lmax_j(jset))
    1362              :                   ncok = npgfk(kset)*ncoset(lmax_k(kset))
    1363              : 
    1364              :                   sgfi = first_sgf_i(1, iset)
    1365              :                   sgfj = first_sgf_j(1, jset)
    1366              :                   sgfk = first_sgf_k(1, kset)
    1367              : 
    1368              :                   IF (ncoj*ncok*ncoi > 0) THEN
    1369              :                      ALLOCATE (dijk_j(ncoj, ncok, ncoi, 3), SOURCE=0.0_dp)
    1370              :                      ALLOCATE (dijk_k(ncoj, ncok, ncoi, 3), SOURCE=0.0_dp)
    1371              : 
    1372              :                      der_j_zero = .FALSE.
    1373              :                      der_k_zero = .FALSE.
    1374              : 
    1375              :                      !need positions for libint. Only relative positions are needed => set ri to 0.0
    1376              :                      ri = 0.0_dp
    1377              :                      rj = rij ! ri + rij
    1378              :                      rk = rik ! ri + rik
    1379              : 
    1380              :                      IF (op_pos_prv == 1) THEN
    1381              :                         CALL eri_3center_derivs(dijk_j, dijk_k, &
    1382              :                                                 lmin_j(jset), lmax_j(jset), npgfj(jset), zetj(:, jset), rpgf_j(:, jset), rj, &
    1383              :                                                 lmin_k(kset), lmax_k(kset), npgfk(kset), zetk(:, kset), rpgf_k(:, kset), rk, &
    1384              :                                                 lmin_i(iset), lmax_i(iset), npgfi(iset), zeti(:, iset), rpgf_i(:, iset), ri, &
    1385              :                                                 djk, dij, dik, lib, potential_parameter, &
    1386              :                                                 der_abc_1_ext=der_ext_j, der_abc_2_ext=der_ext_k)
    1387              :                      ELSE
    1388              :                         ALLOCATE (tmp_ijk_i(ncoi, ncoj, ncok, 3), SOURCE=0.0_dp)
    1389              :                         ALLOCATE (tmp_ijk_j(ncoi, ncoj, ncok, 3), SOURCE=0.0_dp)
    1390              : 
    1391              :                         CALL eri_3center_derivs(tmp_ijk_i, tmp_ijk_j, &
    1392              :                                                 lmin_i(iset), lmax_i(iset), npgfi(iset), zeti(:, iset), rpgf_i(:, iset), ri, &
    1393              :                                                 lmin_j(jset), lmax_j(jset), npgfj(jset), zetj(:, jset), rpgf_j(:, jset), rj, &
    1394              :                                                 lmin_k(kset), lmax_k(kset), npgfk(kset), zetk(:, kset), rpgf_k(:, kset), rk, &
    1395              :                                                 dij, dik, djk, lib, potential_parameter, &
    1396              :                                                 der_abc_1_ext=der_ext_i, der_abc_2_ext=der_ext_j)
    1397              : 
    1398              :                         !TODO: is that inefficient?
    1399              :                         der_ext_k = 0
    1400              :                         DO i_xyz = 1, 3
    1401              :                            DO i = 1, ncoi
    1402              :                               dijk_j(:, :, i, i_xyz) = tmp_ijk_j(i, :, :, i_xyz)
    1403              :                               dijk_k(:, :, i, i_xyz) = -(dijk_j(:, :, i, i_xyz) + tmp_ijk_i(i, :, :, i_xyz))
    1404              :                               der_ext_k(i_xyz) = MAX(der_ext_k(i_xyz), MAXVAL(ABS(dijk_k(:, :, i, i_xyz))))
    1405              :                            END DO
    1406              :                         END DO
    1407              :                         DEALLOCATE (tmp_ijk_i, tmp_ijk_j)
    1408              : 
    1409              :                      END IF
    1410              : 
    1411              :                      IF (PRESENT(der_eps)) THEN
    1412              :                         DO i_xyz = 1, 3
    1413              :                            IF (der_eps > der_ext_j(i_xyz)*(max_contraction_i(iset)* &
    1414              :                                                            max_contraction_j(jset)* &
    1415              :                                                            max_contraction_k(kset))) THEN
    1416              :                               der_j_zero(i_xyz) = .TRUE.
    1417              :                            END IF
    1418              :                         END DO
    1419              : 
    1420              :                         DO i_xyz = 1, 3
    1421              :                            IF (der_eps > der_ext_k(i_xyz)*(max_contraction_i(iset)* &
    1422              :                                                            max_contraction_j(jset)* &
    1423              :                                                            max_contraction_k(kset))) THEN
    1424              :                               der_k_zero(i_xyz) = .TRUE.
    1425              :                            END IF
    1426              :                         END DO
    1427              :                         IF (ALL(der_j_zero) .AND. ALL(der_k_zero)) THEN
    1428              :                            DEALLOCATE (dijk_j, dijk_k)
    1429              :                            CYCLE
    1430              :                         END IF
    1431              :                      END IF
    1432              : 
    1433              :                      ALLOCATE (dijk_contr(nsgfj(jset), nsgfk(kset), nsgfi(iset)))
    1434              : 
    1435              :                      block_start_j = sgfj
    1436              :                      block_end_j = sgfj + nsgfj(jset) - 1
    1437              :                      block_start_k = sgfk
    1438              :                      block_end_k = sgfk + nsgfk(kset) - 1
    1439              :                      block_start_i = sgfi
    1440              :                      block_end_i = sgfi + nsgfi(iset) - 1
    1441              : 
    1442              :                      DO i_xyz = 1, 3
    1443              :                         IF (der_j_zero(i_xyz)) CYCLE
    1444              : 
    1445              :                         block_j_not_zero(i_xyz) = .TRUE.
    1446              :                         CALL abc_contract_xsmm(dijk_contr, dijk_j(:, :, :, i_xyz), tspj(jset, jkind)%array, &
    1447              :                                                spk(kset, kkind)%array, spi(iset, ikind)%array, &
    1448              :                                                ncoj, ncok, ncoi, nsgfj(jset), nsgfk(kset), &
    1449              :                                                nsgfi(iset), cpp_buffer, ccp_buffer, prefac)
    1450              : 
    1451              :                         block_t_j(block_start_j:block_end_j, &
    1452              :                                   block_start_k:block_end_k, &
    1453              :                                   block_start_i:block_end_i, i_xyz) = &
    1454              :                            block_t_j(block_start_j:block_end_j, &
    1455              :                                      block_start_k:block_end_k, &
    1456              :                                      block_start_i:block_end_i, i_xyz) + &
    1457              :                            dijk_contr(:, :, :)
    1458              : 
    1459              :                      END DO
    1460              : 
    1461              :                      DO i_xyz = 1, 3
    1462              :                         IF (der_k_zero(i_xyz)) CYCLE
    1463              : 
    1464              :                         block_k_not_zero(i_xyz) = .TRUE.
    1465              :                         CALL abc_contract_xsmm(dijk_contr, dijk_k(:, :, :, i_xyz), tspj(jset, jkind)%array, &
    1466              :                                                spk(kset, kkind)%array, spi(iset, ikind)%array, &
    1467              :                                                ncoj, ncok, ncoi, nsgfj(jset), nsgfk(kset), &
    1468              :                                                nsgfi(iset), cpp_buffer, ccp_buffer, prefac)
    1469              : 
    1470              :                         block_t_k(block_start_j:block_end_j, &
    1471              :                                   block_start_k:block_end_k, &
    1472              :                                   block_start_i:block_end_i, i_xyz) = &
    1473              :                            block_t_k(block_start_j:block_end_j, &
    1474              :                                      block_start_k:block_end_k, &
    1475              :                                      block_start_i:block_end_i, i_xyz) + &
    1476              :                            dijk_contr(:, :, :)
    1477              : 
    1478              :                      END DO
    1479              : 
    1480              :                      DEALLOCATE (dijk_j, dijk_k, dijk_contr)
    1481              :                   END IF ! number of triples > 0
    1482              :                END DO
    1483              :             END DO
    1484              :          END DO
    1485              : 
    1486              :          CALL timeset(routineN//"_put_dbcsr", handle2)
    1487              : !$OMP CRITICAL(qs_tensors_t3c_der_i)
    1488              :          sp = SHAPE(block_t_i(:, :, :, 1))
    1489              :          sp([2, 3, 1]) = sp
    1490              : 
    1491              :          DO i_xyz = 1, 3
    1492              :             !Derivatives wrt to center i can be obtained by translational invariance
    1493              :             IF ((.NOT. block_j_not_zero(i_xyz)) .AND. (.NOT. block_k_not_zero(i_xyz))) CYCLE
    1494              :             block_t_i(:, :, :, i_xyz) = -(block_t_j(:, :, :, i_xyz) + block_t_k(:, :, :, i_xyz))
    1495              : 
    1496              :             CALL dbt_put_block(t3c_der_i(jcell, kcell, i_xyz), blk_idx, sp, &
    1497              :                                RESHAPE(block_t_i(:, :, :, i_xyz), SHAPE=sp, ORDER=[2, 3, 1]), &
    1498              :                                summation=.TRUE.)
    1499              :          END DO
    1500              : 
    1501              :          sp = SHAPE(block_t_k(:, :, :, 1))
    1502              :          sp([2, 3, 1]) = sp
    1503              : 
    1504              :          DO i_xyz = 1, 3
    1505              :             IF (.NOT. block_k_not_zero(i_xyz)) CYCLE
    1506              :             CALL dbt_put_block(t3c_der_k(jcell, kcell, i_xyz), blk_idx, sp, &
    1507              :                                RESHAPE(block_t_k(:, :, :, i_xyz), SHAPE=sp, ORDER=[2, 3, 1]), &
    1508              :                                summation=.TRUE.)
    1509              :          END DO
    1510              : !$OMP END CRITICAL(qs_tensors_t3c_der_i)
    1511              : 
    1512              :          IF (nl_3c%sym == symmetric_jk) THEN
    1513              :             sp = SHAPE(block_t_j(:, :, :, 1))
    1514              :             sp([2, 3, 1]) = sp
    1515              : !$OMP CRITICAL(qs_tensors_t3c_der_j)
    1516              :             DO i_xyz = 1, 3
    1517              :                IF (.NOT. block_j_not_zero(i_xyz)) CYCLE
    1518              :                CALL dbt_put_block(t3c_der_j(jcell, kcell, i_xyz), blk_idx, sp, &
    1519              :                                   RESHAPE(block_t_j(:, :, :, i_xyz), SHAPE=sp, ORDER=[2, 3, 1]), &
    1520              :                                   summation=.TRUE.)
    1521              :             END DO
    1522              : !$OMP END CRITICAL(qs_tensors_t3c_der_j)
    1523              :          END IF
    1524              : 
    1525              :          CALL timestop(handle2)
    1526              : 
    1527              :          DEALLOCATE (block_t_i, block_t_j, block_t_k)
    1528              :          IF (PRESENT(der_eps)) THEN
    1529              :             DEALLOCATE (max_contraction_i, max_contraction_j, max_contraction_k)
    1530              :          END IF
    1531              :       END DO
    1532              : 
    1533              :       IF (ALLOCATED(ccp_buffer)) DEALLOCATE (ccp_buffer)
    1534              :       IF (ALLOCATED(cpp_buffer)) DEALLOCATE (cpp_buffer)
    1535              : 
    1536              :       CALL cp_libint_cleanup_3eri1(lib)
    1537              :       CALL neighbor_list_3c_iterator_destroy(nl_3c_iter)
    1538              : !$OMP END PARALLEL
    1539              : 
    1540          574 :       IF (do_kpoints_prv .AND. .NOT. do_hfx_kpoints_prv) THEN
    1541            0 :          DO i_xyz = 1, 3
    1542            0 :             DO kcell = 1, nimg
    1543            0 :                DO jcell = 1, nimg
    1544              :                   ! need half of filter eps because afterwards we add transposed tensor
    1545            0 :                   CALL dbt_filter(t3c_der_i(jcell, kcell, i_xyz), filter_eps/2)
    1546            0 :                   CALL dbt_filter(t3c_der_k(jcell, kcell, i_xyz), filter_eps/2)
    1547              :                END DO
    1548              :             END DO
    1549              :          END DO
    1550              : 
    1551          574 :       ELSEIF (nl_3c%sym == symmetric_jk) THEN
    1552              :          !Add the transpose of t3c_der_j to t3c_der_k to get the fully populated tensor
    1553          492 :          CALL dbt_create(t3c_der_k(1, 1, 1), t3c_tmp)
    1554         1968 :          DO i_xyz = 1, 3
    1555         3444 :             DO kcell = 1, nimg
    1556         4428 :                DO jcell = 1, nimg
    1557              :                   CALL dbt_copy(t3c_der_j(jcell, kcell, i_xyz), t3c_der_k(jcell, kcell, i_xyz), &
    1558         1476 :                                 order=[1, 3, 2], move_data=.TRUE., summation=.TRUE.)
    1559         1476 :                   CALL dbt_filter(t3c_der_k(jcell, kcell, i_xyz), filter_eps)
    1560              : 
    1561         1476 :                   CALL dbt_copy(t3c_der_i(jcell, kcell, i_xyz), t3c_tmp)
    1562              :                   CALL dbt_copy(t3c_tmp, t3c_der_i(jcell, kcell, i_xyz), &
    1563         1476 :                                 order=[1, 3, 2], move_data=.TRUE., summation=.TRUE.)
    1564         2952 :                   CALL dbt_filter(t3c_der_i(jcell, kcell, i_xyz), filter_eps)
    1565              :                END DO
    1566              :             END DO
    1567              :          END DO
    1568          492 :          CALL dbt_destroy(t3c_tmp)
    1569              : 
    1570           82 :       ELSEIF (nl_3c%sym == symmetric_none) THEN
    1571          328 :          DO i_xyz = 1, 3
    1572          574 :             DO kcell = 1, ncell_RI
    1573         6804 :                DO jcell = 1, nimg
    1574         6312 :                   CALL dbt_filter(t3c_der_i(jcell, kcell, i_xyz), filter_eps)
    1575         6558 :                   CALL dbt_filter(t3c_der_k(jcell, kcell, i_xyz), filter_eps)
    1576              :                END DO
    1577              :             END DO
    1578              :          END DO
    1579              :       ELSE
    1580            0 :          CPABORT("requested symmetric case not implemented")
    1581              :       END IF
    1582              : 
    1583          574 :       IF (nl_3c%sym == symmetric_jk) THEN
    1584         1968 :          DO i_xyz = 1, 3
    1585         3444 :             DO j_img = 1, nimg
    1586         4428 :                DO i_img = 1, nimg
    1587         2952 :                   CALL dbt_destroy(t3c_der_j(i_img, j_img, i_xyz))
    1588              :                END DO
    1589              :             END DO
    1590              :          END DO
    1591              :       END IF
    1592              : 
    1593         3934 :       DO iset = 1, max_nset
    1594        10258 :          DO ibasis = 1, nbasis
    1595         6324 :             IF (ASSOCIATED(spi(iset, ibasis)%array)) DEALLOCATE (spi(iset, ibasis)%array)
    1596         6324 :             IF (ASSOCIATED(tspj(iset, ibasis)%array)) DEALLOCATE (tspj(iset, ibasis)%array)
    1597         9684 :             IF (ASSOCIATED(spk(iset, ibasis)%array)) DEALLOCATE (spk(iset, ibasis)%array)
    1598              :          END DO
    1599              :       END DO
    1600              : 
    1601          574 :       DEALLOCATE (spi, tspj, spk)
    1602              : 
    1603          574 :       CALL timestop(handle)
    1604         6642 :    END SUBROUTINE build_3c_derivatives
    1605              : 
    1606              : ! **************************************************************************************************
    1607              : !> \brief Calculates the 3c virial contributions on the fly
    1608              : !> \param work_virial ...
    1609              : !> \param t3c_trace the tensor with which the trace should be taken
    1610              : !> \param pref ...
    1611              : !> \param qs_env ...
    1612              : !> \param nl_3c 3-center neighborlist, with a distribution matching that of t3c_trace
    1613              : !> \param basis_i ...
    1614              : !> \param basis_j ...
    1615              : !> \param basis_k ...
    1616              : !> \param potential_parameter ...
    1617              : !> \param der_eps neglect integrals smaller than der_eps
    1618              : !> \param op_pos operator position.
    1619              : !>        1: calculate (i|jk) integrals,
    1620              : !>        2: calculate (ij|k) integrals
    1621              : !> this routine requires that libint has been static initialised somewhere else
    1622              : ! **************************************************************************************************
    1623           16 :    SUBROUTINE calc_3c_virial(work_virial, t3c_trace, pref, qs_env, &
    1624           16 :                              nl_3c, basis_i, basis_j, basis_k, &
    1625              :                              potential_parameter, der_eps, op_pos)
    1626              : 
    1627              :       REAL(dp), DIMENSION(3, 3), INTENT(INOUT)           :: work_virial
    1628              :       TYPE(dbt_type), INTENT(INOUT)                      :: t3c_trace
    1629              :       REAL(KIND=dp), INTENT(IN)                          :: pref
    1630              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1631              :       TYPE(neighbor_list_3c_type), INTENT(INOUT)         :: nl_3c
    1632              :       TYPE(gto_basis_set_p_type), DIMENSION(:)           :: basis_i, basis_j, basis_k
    1633              :       TYPE(libint_potential_type), INTENT(IN)            :: potential_parameter
    1634              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: der_eps
    1635              :       INTEGER, INTENT(IN), OPTIONAL                      :: op_pos
    1636              : 
    1637              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'calc_3c_virial'
    1638              : 
    1639              :       INTEGER :: block_end_i, block_end_j, block_end_k, block_start_i, block_start_j, &
    1640              :          block_start_k, egfi, handle, i, i_xyz, iatom, ibasis, ikind, ilist, imax, iset, j_xyz, &
    1641              :          jatom, jkind, jset, katom, kkind, kset, m_max, max_ncoj, max_nset, max_nsgfi, maxli, &
    1642              :          maxlj, maxlk, mepos, natom, nbasis, ncoi, ncoj, ncok, nseti, nsetj, nsetk, nthread, &
    1643              :          op_ij, op_jk, op_pos_prv, sgfi, sgfj, sgfk, unit_id
    1644              :       INTEGER, DIMENSION(2)                              :: bo
    1645              :       INTEGER, DIMENSION(3)                              :: blk_size, sp
    1646           16 :       INTEGER, DIMENSION(:), POINTER                     :: lmax_i, lmax_j, lmax_k, lmin_i, lmin_j, &
    1647           32 :                                                             lmin_k, npgfi, npgfj, npgfk, nsgfi, &
    1648           16 :                                                             nsgfj, nsgfk
    1649           16 :       INTEGER, DIMENSION(:, :), POINTER                  :: first_sgf_i, first_sgf_j, first_sgf_k
    1650              :       LOGICAL                                            :: found, skip
    1651              :       LOGICAL, DIMENSION(3)                              :: block_j_not_zero, block_k_not_zero, &
    1652              :                                                             der_j_zero, der_k_zero
    1653              :       REAL(dp)                                           :: force
    1654              :       REAL(dp), DIMENSION(3)                             :: der_ext_i, der_ext_j, der_ext_k
    1655              :       REAL(KIND=dp)                                      :: dij, dik, djk, dr_ij, dr_ik, dr_jk, &
    1656              :                                                             kind_radius_i, kind_radius_j, &
    1657              :                                                             kind_radius_k
    1658           16 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: ccp_buffer, cpp_buffer, &
    1659           16 :                                                             max_contraction_i, max_contraction_j, &
    1660           16 :                                                             max_contraction_k
    1661           32 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: ablock, dijk_contr, tmp_block
    1662           16 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :, :)  :: block_t_i, block_t_j, block_t_k, dijk_j, &
    1663           16 :                                                             dijk_k
    1664              :       REAL(KIND=dp), DIMENSION(3)                        :: ri, rij, rik, rj, rjk, rk, scoord
    1665           16 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: set_radius_i, set_radius_j, set_radius_k
    1666           16 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: rpgf_i, rpgf_j, rpgf_k, sphi_i, sphi_j, &
    1667           16 :                                                             sphi_k, zeti, zetj, zetk
    1668           16 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    1669              :       TYPE(cell_type), POINTER                           :: cell
    1670           16 :       TYPE(cp_2d_r_p_type), DIMENSION(:, :), POINTER     :: spi, spk, tspj
    1671              :       TYPE(cp_libint_t)                                  :: lib
    1672              :       TYPE(dft_control_type), POINTER                    :: dft_control
    1673              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set
    1674              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1675              :       TYPE(neighbor_list_3c_iterator_type)               :: nl_3c_iter
    1676           16 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1677           16 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    1678              : 
    1679           16 :       CALL timeset(routineN, handle)
    1680              : 
    1681           16 :       op_ij = do_potential_id; op_jk = do_potential_id
    1682              : 
    1683           16 :       IF (PRESENT(op_pos)) THEN
    1684           16 :          op_pos_prv = op_pos
    1685              :       ELSE
    1686              :          op_pos_prv = 1
    1687              :       END IF
    1688           16 :       CPASSERT(op_pos == 1)
    1689           16 :       CPASSERT(.NOT. nl_3c%sym == symmetric_jk)
    1690              : 
    1691           16 :       SELECT CASE (op_pos_prv)
    1692              :       CASE (1)
    1693           16 :          op_ij = potential_parameter%potential_type
    1694              :       CASE (2)
    1695           16 :          op_jk = potential_parameter%potential_type
    1696              :       END SELECT
    1697              : 
    1698           16 :       dr_ij = 0.0_dp; dr_jk = 0.0_dp; dr_ik = 0.0_dp
    1699              : 
    1700              :       IF (op_ij == do_potential_truncated .OR. op_ij == do_potential_short &
    1701           16 :           .OR. op_ij == do_potential_mix_cl_trunc) THEN
    1702            6 :          dr_ij = potential_parameter%cutoff_radius*cutoff_screen_factor
    1703            6 :          dr_ik = potential_parameter%cutoff_radius*cutoff_screen_factor
    1704           10 :       ELSEIF (op_ij == do_potential_coulomb) THEN
    1705            0 :          dr_ij = 1000000.0_dp
    1706            0 :          dr_ik = 1000000.0_dp
    1707              :       END IF
    1708              : 
    1709              :       IF (op_jk == do_potential_truncated .OR. op_jk == do_potential_short &
    1710           16 :           .OR. op_jk == do_potential_mix_cl_trunc) THEN
    1711            0 :          dr_jk = potential_parameter%cutoff_radius*cutoff_screen_factor
    1712            0 :          dr_ik = potential_parameter%cutoff_radius*cutoff_screen_factor
    1713           16 :       ELSEIF (op_jk == do_potential_coulomb) THEN
    1714            0 :          dr_jk = 1000000.0_dp
    1715            0 :          dr_ik = 1000000.0_dp
    1716              :       END IF
    1717              : 
    1718           16 :       NULLIFY (qs_kind_set, atomic_kind_set)
    1719              : 
    1720              :       ! get stuff
    1721              :       CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, qs_kind_set=qs_kind_set, &
    1722              :                       natom=natom, dft_control=dft_control, para_env=para_env, &
    1723           16 :                       particle_set=particle_set, cell=cell)
    1724              : 
    1725              :       !Need the max l for each basis for libint and max nset, nco and nsgf for LIBXSMM contraction
    1726           16 :       nbasis = SIZE(basis_i)
    1727           16 :       max_nsgfi = 0
    1728           16 :       max_nset = 0
    1729           16 :       maxli = 0
    1730           48 :       DO ibasis = 1, nbasis
    1731              :          CALL get_gto_basis_set(gto_basis_set=basis_i(ibasis)%gto_basis_set, maxl=imax, &
    1732           32 :                                 nset=iset, nsgf_set=nsgfi, npgf=npgfi)
    1733           32 :          maxli = MAX(maxli, imax)
    1734           32 :          max_nset = MAX(max_nset, iset)
    1735          182 :          max_nsgfi = MAX(max_nsgfi, MAXVAL(nsgfi))
    1736              :       END DO
    1737              :       max_ncoj = 0
    1738              :       maxlj = 0
    1739           48 :       DO ibasis = 1, nbasis
    1740              :          CALL get_gto_basis_set(gto_basis_set=basis_j(ibasis)%gto_basis_set, maxl=imax, &
    1741           32 :                                 nset=jset, nsgf_set=nsgfj, npgf=npgfj)
    1742           32 :          maxlj = MAX(maxlj, imax)
    1743           32 :          max_nset = MAX(max_nset, jset)
    1744          138 :          max_ncoj = MAX(max_ncoj, MAXVAL(npgfj)*ncoset(maxlj))
    1745              :       END DO
    1746              :       maxlk = 0
    1747           48 :       DO ibasis = 1, nbasis
    1748              :          CALL get_gto_basis_set(gto_basis_set=basis_k(ibasis)%gto_basis_set, maxl=imax, &
    1749           32 :                                 nset=kset, nsgf_set=nsgfk, npgf=npgfk)
    1750           32 :          maxlk = MAX(maxlk, imax)
    1751           48 :          max_nset = MAX(max_nset, kset)
    1752              :       END DO
    1753           16 :       m_max = maxli + maxlj + maxlk + 1
    1754              : 
    1755              :       !To minimize expensive memory ops and generally optimize contraction, pre-allocate
    1756              :       !contiguous sphi arrays (and transposed in the case of sphi_i)
    1757              : 
    1758           16 :       NULLIFY (tspj, spi, spk)
    1759          920 :       ALLOCATE (spi(max_nset, nbasis), tspj(max_nset, nbasis), spk(max_nset, nbasis))
    1760              : 
    1761           48 :       DO ibasis = 1, nbasis
    1762          280 :          DO iset = 1, max_nset
    1763          232 :             NULLIFY (spi(iset, ibasis)%array)
    1764          232 :             NULLIFY (tspj(iset, ibasis)%array)
    1765              : 
    1766          264 :             NULLIFY (spk(iset, ibasis)%array)
    1767              :          END DO
    1768              :       END DO
    1769              : 
    1770           64 :       DO ilist = 1, 3
    1771          160 :          DO ibasis = 1, nbasis
    1772           96 :             IF (ilist == 1) basis_set => basis_i(ibasis)%gto_basis_set
    1773           96 :             IF (ilist == 2) basis_set => basis_j(ibasis)%gto_basis_set
    1774           96 :             IF (ilist == 3) basis_set => basis_k(ibasis)%gto_basis_set
    1775              : 
    1776          458 :             DO iset = 1, basis_set%nset
    1777              : 
    1778          314 :                ncoi = basis_set%npgf(iset)*ncoset(basis_set%lmax(iset))
    1779          314 :                sgfi = basis_set%first_sgf(1, iset)
    1780          314 :                egfi = sgfi + basis_set%nsgf_set(iset) - 1
    1781              : 
    1782          410 :                IF (ilist == 1) THEN
    1783          536 :                   ALLOCATE (spi(iset, ibasis)%array(ncoi, basis_set%nsgf_set(iset)))
    1784       177990 :                   spi(iset, ibasis)%array(:, :) = basis_set%sphi(1:ncoi, sgfi:egfi)
    1785              : 
    1786          180 :                ELSE IF (ilist == 2) THEN
    1787          360 :                   ALLOCATE (tspj(iset, ibasis)%array(basis_set%nsgf_set(iset), ncoi))
    1788         5194 :                   tspj(iset, ibasis)%array(:, :) = TRANSPOSE(basis_set%sphi(1:ncoi, sgfi:egfi))
    1789              : 
    1790              :                ELSE
    1791          360 :                   ALLOCATE (spk(iset, ibasis)%array(ncoi, basis_set%nsgf_set(iset)))
    1792         4442 :                   spk(iset, ibasis)%array(:, :) = basis_set%sphi(1:ncoi, sgfi:egfi)
    1793              :                END IF
    1794              : 
    1795              :             END DO !iset
    1796              :          END DO !ibasis
    1797              :       END DO !ilist
    1798              : 
    1799              :       !Init the truncated Coulomb operator
    1800              :       IF (op_ij == do_potential_truncated .OR. op_jk == do_potential_truncated .OR. &
    1801           16 :           op_ij == do_potential_mix_cl_trunc .OR. op_jk == do_potential_mix_cl_trunc) THEN
    1802              : 
    1803            6 :          IF (m_max > get_lmax_init()) THEN
    1804            0 :             IF (para_env%mepos == 0) THEN
    1805            0 :                CALL open_file(unit_number=unit_id, file_name=potential_parameter%filename)
    1806              :             END IF
    1807            0 :             CALL init(m_max, unit_id, para_env%mepos, para_env)
    1808            0 :             IF (para_env%mepos == 0) THEN
    1809            0 :                CALL close_file(unit_id)
    1810              :             END IF
    1811              :          END IF
    1812              :       END IF
    1813              : 
    1814           16 :       CALL init_md_ftable(nmax=m_max)
    1815              : 
    1816           16 :       nthread = 1
    1817           16 : !$    nthread = omp_get_max_threads()
    1818              : 
    1819              : !$OMP PARALLEL DEFAULT(NONE) &
    1820              : !$OMP SHARED (nthread,maxli,maxlk,maxlj,work_virial,pref,basis_i,basis_j,basis_k,dr_ij,dr_jk,dr_ik,&
    1821              : !$OMP         ncoset,potential_parameter,der_eps,tspj,spi,spk,natom,nl_3c,t3c_trace,cell,particle_set) &
    1822              : !$OMP PRIVATE (lib,nl_3c_iter,ikind,jkind,kkind,iatom,jatom,katom,rij,rjk,rik,i_xyz,j_xyz,first_sgf_i,&
    1823              : !$OMP          lmax_i,lmin_i,npgfi,nseti,nsgfi,rpgf_i,set_radius_i,sphi_i,zeti,kind_radius_i,first_sgf_j,&
    1824              : !$OMP          lmax_j,lmin_j,npgfj,nsetj,nsgfj,rpgf_j,set_radius_j,sphi_j,zetj,kind_radius_j,first_sgf_k,&
    1825              : !$OMP          lmax_k,lmin_k,npgfk,nsetk,nsgfk,rpgf_k,set_radius_k,sphi_k,zetk,kind_radius_k,djk,dij,dik,&
    1826              : !$OMP          ncoi,ncoj,ncok,sgfi,sgfj,sgfk,dijk_j,dijk_k,ri,rj,rk,max_contraction_i,max_contraction_j,&
    1827              : !$OMP          tmp_block,max_contraction_k,iset,jset,kset,block_t_i,blk_size,dijk_contr,found,sp,mepos,&
    1828              : !$OMP          block_start_j,block_end_j,block_start_k,block_end_k,block_start_i,block_end_i,block_t_k,&
    1829              : !$OMP          bo,der_ext_i,der_ext_j,der_ext_k,ablock,force,scoord,skip,cpp_buffer,ccp_buffer,&
    1830           16 : !$OMP          block_k_not_zero,der_k_zero,der_j_zero,block_t_j,block_j_not_zero,i)
    1831              : 
    1832              :       mepos = 0
    1833              : !$    mepos = omp_get_thread_num()
    1834              : 
    1835              :       CALL cp_libint_init_3eri1(lib, MAX(maxli, maxlj, maxlk))
    1836              :       CALL cp_libint_set_contrdepth(lib, 1)
    1837              :       CALL neighbor_list_3c_iterator_create(nl_3c_iter, nl_3c)
    1838              : 
    1839              :       !We split the provided bounds among the threads such that each threads works on a different set of atoms
    1840              : 
    1841              :       bo = get_limit(natom, nthread, mepos)
    1842              :       CALL nl_3c_iter_set_bounds(nl_3c_iter, bounds_i=bo)
    1843              : 
    1844              :       skip = .FALSE.
    1845              :       IF (bo(1) > bo(2)) skip = .TRUE.
    1846              : 
    1847              :       DO WHILE (neighbor_list_3c_iterate(nl_3c_iter) == 0)
    1848              :          CALL get_3c_iterator_info(nl_3c_iter, ikind=ikind, jkind=jkind, kkind=kkind, &
    1849              :                                    iatom=iatom, jatom=jatom, katom=katom, &
    1850              :                                    rij=rij, rjk=rjk, rik=rik)
    1851              :          IF (skip) EXIT
    1852              : 
    1853              :          CALL dbt_get_block(t3c_trace, [iatom, jatom, katom], tmp_block, found)
    1854              :          IF (.NOT. found) CYCLE
    1855              : 
    1856              :          CALL get_gto_basis_set(basis_i(ikind)%gto_basis_set, first_sgf=first_sgf_i, lmax=lmax_i, lmin=lmin_i, &
    1857              :                                 npgf=npgfi, nset=nseti, nsgf_set=nsgfi, pgf_radius=rpgf_i, set_radius=set_radius_i, &
    1858              :                                 sphi=sphi_i, zet=zeti, kind_radius=kind_radius_i)
    1859              : 
    1860              :          CALL get_gto_basis_set(basis_j(jkind)%gto_basis_set, first_sgf=first_sgf_j, lmax=lmax_j, lmin=lmin_j, &
    1861              :                                 npgf=npgfj, nset=nsetj, nsgf_set=nsgfj, pgf_radius=rpgf_j, set_radius=set_radius_j, &
    1862              :                                 sphi=sphi_j, zet=zetj, kind_radius=kind_radius_j)
    1863              : 
    1864              :          CALL get_gto_basis_set(basis_k(kkind)%gto_basis_set, first_sgf=first_sgf_k, lmax=lmax_k, lmin=lmin_k, &
    1865              :                                 npgf=npgfk, nset=nsetk, nsgf_set=nsgfk, pgf_radius=rpgf_k, set_radius=set_radius_k, &
    1866              :                                 sphi=sphi_k, zet=zetk, kind_radius=kind_radius_k)
    1867              : 
    1868              :          djk = NORM2(rjk)
    1869              :          dij = NORM2(rij)
    1870              :          dik = NORM2(rik)
    1871              : 
    1872              :          IF (kind_radius_j + kind_radius_i + dr_ij < dij) CYCLE
    1873              :          IF (kind_radius_j + kind_radius_k + dr_jk < djk) CYCLE
    1874              :          IF (kind_radius_k + kind_radius_i + dr_ik < dik) CYCLE
    1875              : 
    1876              :          IF (PRESENT(der_eps)) THEN
    1877              :             ALLOCATE (max_contraction_i(nseti))
    1878              :             DO iset = 1, nseti
    1879              :                sgfi = first_sgf_i(1, iset)
    1880              :                max_contraction_i(iset) = MAXVAL([(SUM(ABS(sphi_i(:, i))), i=sgfi, sgfi + nsgfi(iset) - 1)])
    1881              :             END DO
    1882              : 
    1883              :             ALLOCATE (max_contraction_j(nsetj))
    1884              :             DO jset = 1, nsetj
    1885              :                sgfj = first_sgf_j(1, jset)
    1886              :                max_contraction_j(jset) = MAXVAL([(SUM(ABS(sphi_j(:, i))), i=sgfj, sgfj + nsgfj(jset) - 1)])
    1887              :             END DO
    1888              : 
    1889              :             ALLOCATE (max_contraction_k(nsetk))
    1890              :             DO kset = 1, nsetk
    1891              :                sgfk = first_sgf_k(1, kset)
    1892              :                max_contraction_k(kset) = MAXVAL([(SUM(ABS(sphi_k(:, i))), i=sgfk, sgfk + nsgfk(kset) - 1)])
    1893              :             END DO
    1894              :          END IF
    1895              : 
    1896              :          CALL dbt_blk_sizes(t3c_trace, [iatom, jatom, katom], blk_size)
    1897              : 
    1898              :          ALLOCATE (block_t_i(blk_size(2), blk_size(3), blk_size(1), 3))
    1899              :          ALLOCATE (block_t_j(blk_size(2), blk_size(3), blk_size(1), 3))
    1900              :          ALLOCATE (block_t_k(blk_size(2), blk_size(3), blk_size(1), 3))
    1901              : 
    1902              :          ALLOCATE (ablock(blk_size(2), blk_size(3), blk_size(1)))
    1903              :          DO i = 1, blk_size(1)
    1904              :             ablock(:, :, i) = tmp_block(i, :, :)
    1905              :          END DO
    1906              :          DEALLOCATE (tmp_block)
    1907              : 
    1908              :          block_t_i = 0.0_dp
    1909              :          block_t_j = 0.0_dp
    1910              :          block_t_k = 0.0_dp
    1911              :          block_j_not_zero = .FALSE.
    1912              :          block_k_not_zero = .FALSE.
    1913              : 
    1914              :          DO iset = 1, nseti
    1915              : 
    1916              :             DO jset = 1, nsetj
    1917              : 
    1918              :                IF (set_radius_j(jset) + set_radius_i(iset) + dr_ij < dij) CYCLE
    1919              : 
    1920              :                DO kset = 1, nsetk
    1921              : 
    1922              :                   IF (set_radius_j(jset) + set_radius_k(kset) + dr_jk < djk) CYCLE
    1923              :                   IF (set_radius_k(kset) + set_radius_i(iset) + dr_ik < dik) CYCLE
    1924              : 
    1925              :                   ncoi = npgfi(iset)*ncoset(lmax_i(iset))
    1926              :                   ncoj = npgfj(jset)*ncoset(lmax_j(jset))
    1927              :                   ncok = npgfk(kset)*ncoset(lmax_k(kset))
    1928              : 
    1929              :                   sgfi = first_sgf_i(1, iset)
    1930              :                   sgfj = first_sgf_j(1, jset)
    1931              :                   sgfk = first_sgf_k(1, kset)
    1932              : 
    1933              :                   IF (ncoj*ncok*ncoi > 0) THEN
    1934              :                      ALLOCATE (dijk_j(ncoj, ncok, ncoi, 3), SOURCE=0.0_dp)
    1935              :                      ALLOCATE (dijk_k(ncoj, ncok, ncoi, 3), SOURCE=0.0_dp)
    1936              : 
    1937              :                      der_j_zero = .FALSE.
    1938              :                      der_k_zero = .FALSE.
    1939              : 
    1940              :                      !need positions for libint. Only relative positions are needed => set ri to 0.0
    1941              :                      ri = 0.0_dp
    1942              :                      rj = rij ! ri + rij
    1943              :                      rk = rik ! ri + rik
    1944              : 
    1945              :                      CALL eri_3center_derivs(dijk_j, dijk_k, &
    1946              :                                              lmin_j(jset), lmax_j(jset), npgfj(jset), zetj(:, jset), rpgf_j(:, jset), rj, &
    1947              :                                              lmin_k(kset), lmax_k(kset), npgfk(kset), zetk(:, kset), rpgf_k(:, kset), rk, &
    1948              :                                              lmin_i(iset), lmax_i(iset), npgfi(iset), zeti(:, iset), rpgf_i(:, iset), ri, &
    1949              :                                              djk, dij, dik, lib, potential_parameter, &
    1950              :                                              der_abc_1_ext=der_ext_j, der_abc_2_ext=der_ext_k)
    1951              : 
    1952              :                      IF (PRESENT(der_eps)) THEN
    1953              :                         DO i_xyz = 1, 3
    1954              :                            IF (der_eps > der_ext_j(i_xyz)*(max_contraction_i(iset)* &
    1955              :                                                            max_contraction_j(jset)* &
    1956              :                                                            max_contraction_k(kset))) THEN
    1957              :                               der_j_zero(i_xyz) = .TRUE.
    1958              :                            END IF
    1959              :                         END DO
    1960              : 
    1961              :                         DO i_xyz = 1, 3
    1962              :                            IF (der_eps > der_ext_k(i_xyz)*(max_contraction_i(iset)* &
    1963              :                                                            max_contraction_j(jset)* &
    1964              :                                                            max_contraction_k(kset))) THEN
    1965              :                               der_k_zero(i_xyz) = .TRUE.
    1966              :                            END IF
    1967              :                         END DO
    1968              :                         IF (ALL(der_j_zero) .AND. ALL(der_k_zero)) THEN
    1969              :                            DEALLOCATE (dijk_j, dijk_k)
    1970              :                            CYCLE
    1971              :                         END IF
    1972              :                      END IF
    1973              : 
    1974              :                      ALLOCATE (dijk_contr(nsgfj(jset), nsgfk(kset), nsgfi(iset)))
    1975              : 
    1976              :                      block_start_j = sgfj
    1977              :                      block_end_j = sgfj + nsgfj(jset) - 1
    1978              :                      block_start_k = sgfk
    1979              :                      block_end_k = sgfk + nsgfk(kset) - 1
    1980              :                      block_start_i = sgfi
    1981              :                      block_end_i = sgfi + nsgfi(iset) - 1
    1982              : 
    1983              :                      DO i_xyz = 1, 3
    1984              :                         IF (der_j_zero(i_xyz)) CYCLE
    1985              : 
    1986              :                         block_j_not_zero(i_xyz) = .TRUE.
    1987              :                         CALL abc_contract_xsmm(dijk_contr, dijk_j(:, :, :, i_xyz), tspj(jset, jkind)%array, &
    1988              :                                                spk(kset, kkind)%array, spi(iset, ikind)%array, &
    1989              :                                                ncoj, ncok, ncoi, nsgfj(jset), nsgfk(kset), &
    1990              :                                                nsgfi(iset), cpp_buffer, ccp_buffer)
    1991              : 
    1992              :                         block_t_j(block_start_j:block_end_j, &
    1993              :                                   block_start_k:block_end_k, &
    1994              :                                   block_start_i:block_end_i, i_xyz) = &
    1995              :                            block_t_j(block_start_j:block_end_j, &
    1996              :                                      block_start_k:block_end_k, &
    1997              :                                      block_start_i:block_end_i, i_xyz) + &
    1998              :                            dijk_contr(:, :, :)
    1999              : 
    2000              :                      END DO
    2001              : 
    2002              :                      DO i_xyz = 1, 3
    2003              :                         IF (der_k_zero(i_xyz)) CYCLE
    2004              : 
    2005              :                         block_k_not_zero(i_xyz) = .TRUE.
    2006              :                         CALL abc_contract_xsmm(dijk_contr, dijk_k(:, :, :, i_xyz), tspj(jset, jkind)%array, &
    2007              :                                                spk(kset, kkind)%array, spi(iset, ikind)%array, &
    2008              :                                                ncoj, ncok, ncoi, nsgfj(jset), nsgfk(kset), &
    2009              :                                                nsgfi(iset), cpp_buffer, ccp_buffer)
    2010              : 
    2011              :                         block_t_k(block_start_j:block_end_j, &
    2012              :                                   block_start_k:block_end_k, &
    2013              :                                   block_start_i:block_end_i, i_xyz) = &
    2014              :                            block_t_k(block_start_j:block_end_j, &
    2015              :                                      block_start_k:block_end_k, &
    2016              :                                      block_start_i:block_end_i, i_xyz) + &
    2017              :                            dijk_contr(:, :, :)
    2018              : 
    2019              :                      END DO
    2020              : 
    2021              :                      DEALLOCATE (dijk_j, dijk_k, dijk_contr)
    2022              :                   END IF ! number of triples > 0
    2023              :                END DO
    2024              :             END DO
    2025              :          END DO
    2026              : 
    2027              :          !We obtain the derivative wrt to first center using translational invariance
    2028              :          DO i_xyz = 1, 3
    2029              :             block_t_i(:, :, :, i_xyz) = -block_t_j(:, :, :, i_xyz) - block_t_k(:, :, :, i_xyz)
    2030              :          END DO
    2031              : 
    2032              :          !virial contribution coming from deriv wrt to first center
    2033              :          DO i_xyz = 1, 3
    2034              :             force = pref*SUM(ablock(:, :, :)*block_t_i(:, :, :, i_xyz))
    2035              :             CALL real_to_scaled(scoord, particle_set(iatom)%r, cell)
    2036              :             DO j_xyz = 1, 3
    2037              : !$OMP ATOMIC
    2038              :                work_virial(i_xyz, j_xyz) = work_virial(i_xyz, j_xyz) + force*scoord(j_xyz)
    2039              :             END DO
    2040              :          END DO
    2041              : 
    2042              :          !second center
    2043              :          DO i_xyz = 1, 3
    2044              :             force = pref*SUM(ablock(:, :, :)*block_t_j(:, :, :, i_xyz))
    2045              :             CALL real_to_scaled(scoord, particle_set(iatom)%r + rij, cell)
    2046              :             DO j_xyz = 1, 3
    2047              : !$OMP ATOMIC
    2048              :                work_virial(i_xyz, j_xyz) = work_virial(i_xyz, j_xyz) + force*scoord(j_xyz)
    2049              :             END DO
    2050              :          END DO
    2051              : 
    2052              :          !third center
    2053              :          DO i_xyz = 1, 3
    2054              :             force = pref*SUM(ablock(:, :, :)*block_t_k(:, :, :, i_xyz))
    2055              :             CALL real_to_scaled(scoord, particle_set(iatom)%r + rik, cell)
    2056              :             DO j_xyz = 1, 3
    2057              : !$OMP ATOMIC
    2058              :                work_virial(i_xyz, j_xyz) = work_virial(i_xyz, j_xyz) + force*scoord(j_xyz)
    2059              :             END DO
    2060              :          END DO
    2061              : 
    2062              :          DEALLOCATE (block_t_i, block_t_j, block_t_k)
    2063              :          IF (PRESENT(der_eps)) THEN
    2064              :             DEALLOCATE (max_contraction_i, max_contraction_j, max_contraction_k, ablock)
    2065              :          END IF
    2066              :       END DO
    2067              : 
    2068              :       IF (ALLOCATED(ccp_buffer)) DEALLOCATE (ccp_buffer)
    2069              :       IF (ALLOCATED(cpp_buffer)) DEALLOCATE (cpp_buffer)
    2070              : 
    2071              :       CALL cp_libint_cleanup_3eri1(lib)
    2072              :       CALL neighbor_list_3c_iterator_destroy(nl_3c_iter)
    2073              : !$OMP END PARALLEL
    2074              : 
    2075          132 :       DO iset = 1, max_nset
    2076          364 :          DO ibasis = 1, nbasis
    2077          232 :             IF (ASSOCIATED(spi(iset, ibasis)%array)) DEALLOCATE (spi(iset, ibasis)%array)
    2078          232 :             IF (ASSOCIATED(tspj(iset, ibasis)%array)) DEALLOCATE (tspj(iset, ibasis)%array)
    2079          348 :             IF (ASSOCIATED(spk(iset, ibasis)%array)) DEALLOCATE (spk(iset, ibasis)%array)
    2080              :          END DO
    2081              :       END DO
    2082              : 
    2083           16 :       DEALLOCATE (spi, tspj, spk)
    2084              : 
    2085           16 :       CALL timestop(handle)
    2086          128 :    END SUBROUTINE calc_3c_virial
    2087              : 
    2088              : ! **************************************************************************************************
    2089              : !> \brief Build 3-center integral tensor
    2090              : !> \param t3c empty DBCSR tensor
    2091              : !>            Should be of shape (1,1) if no kpoints are used and of shape (nimages, nimages)
    2092              : !>            if k-points are used
    2093              : !> \param filter_eps Filter threshold for tensor blocks
    2094              : !> \param qs_env ...
    2095              : !> \param nl_3c 3-center neighborlist
    2096              : !> \param basis_i ...
    2097              : !> \param basis_j ...
    2098              : !> \param basis_k ...
    2099              : !> \param potential_parameter ...
    2100              : !> \param int_eps neglect integrals smaller than int_eps
    2101              : !> \param op_pos operator position.
    2102              : !>        1: calculate (i|jk) integrals,
    2103              : !>        2: calculate (ij|k) integrals
    2104              : !> \param do_kpoints ...
    2105              : !> this routine requires that libint has been static initialised somewhere else
    2106              : !> \param do_hfx_kpoints ...
    2107              : !> \param desymmetrize ...
    2108              : !> \param cell_sym ...
    2109              : !> \param bounds_i ...
    2110              : !> \param bounds_j ...
    2111              : !> \param bounds_k ...
    2112              : !> \param RI_range ...
    2113              : !> \param img_to_RI_cell ...
    2114              : !> \param cell_to_index_ext ...
    2115              : ! **************************************************************************************************
    2116         1978 :    SUBROUTINE build_3c_integrals(t3c, filter_eps, qs_env, &
    2117         1978 :                                  nl_3c, basis_i, basis_j, basis_k, &
    2118              :                                  potential_parameter, int_eps, &
    2119              :                                  op_pos, do_kpoints, do_hfx_kpoints, desymmetrize, cell_sym, &
    2120              :                                  bounds_i, bounds_j, bounds_k, &
    2121         1978 :                                  RI_range, img_to_RI_cell, cell_to_index_ext)
    2122              : 
    2123              :       TYPE(dbt_type), DIMENSION(:, :), INTENT(INOUT)     :: t3c
    2124              :       REAL(KIND=dp), INTENT(IN)                          :: filter_eps
    2125              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2126              :       TYPE(neighbor_list_3c_type), INTENT(INOUT)         :: nl_3c
    2127              :       TYPE(gto_basis_set_p_type), DIMENSION(:)           :: basis_i, basis_j, basis_k
    2128              :       TYPE(libint_potential_type), INTENT(IN)            :: potential_parameter
    2129              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: int_eps
    2130              :       INTEGER, INTENT(IN), OPTIONAL                      :: op_pos
    2131              :       LOGICAL, INTENT(IN), OPTIONAL                      :: do_kpoints, do_hfx_kpoints, &
    2132              :                                                             desymmetrize, cell_sym
    2133              :       INTEGER, DIMENSION(2), INTENT(IN), OPTIONAL        :: bounds_i, bounds_j, bounds_k
    2134              :       REAL(dp), INTENT(IN), OPTIONAL                     :: RI_range
    2135              :       INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL        :: img_to_RI_cell
    2136              :       INTEGER, DIMENSION(:, :, :), OPTIONAL, POINTER     :: cell_to_index_ext
    2137              : 
    2138              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'build_3c_integrals'
    2139              : 
    2140              :       INTEGER :: block_end_i, block_end_j, block_end_k, block_start_i, block_start_j, &
    2141              :          block_start_k, egfi, handle, handle2, i, iatom, ibasis, ikind, ilist, imax, iset, jatom, &
    2142              :          jcell, jkind, jset, katom, kcell, kkind, kset, m_max, max_ncoj, max_nset, max_nsgfi, &
    2143              :          maxli, maxlj, maxlk, mepos, natom, nbasis, ncell_RI, ncoi, ncoj, ncok, nimg, nseti, &
    2144              :          nsetj, nsetk, nthread, op_ij, op_jk, op_pos_prv, sgfi, sgfj, sgfk, unit_id
    2145         1978 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: img_to_RI_cell_prv
    2146              :       INTEGER, DIMENSION(2)                              :: bo
    2147              :       INTEGER, DIMENSION(3)                              :: blk_idx, blk_size, cell_j, cell_k, &
    2148              :                                                             kp_index_lbounds, kp_index_ubounds, sp
    2149         1978 :       INTEGER, DIMENSION(:), POINTER                     :: lmax_i, lmax_j, lmax_k, lmin_i, lmin_j, &
    2150         3956 :                                                             lmin_k, npgfi, npgfj, npgfk, nsgfi, &
    2151         1978 :                                                             nsgfj, nsgfk
    2152         1978 :       INTEGER, DIMENSION(:, :), POINTER                  :: first_sgf_i, first_sgf_j, first_sgf_k
    2153         1978 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
    2154              :       LOGICAL                                            :: block_not_zero, cell_sym_prv, debug, &
    2155              :                                                             desymmetrize_prv, do_hfx_kpoints_prv, &
    2156              :                                                             do_kpoints_prv, found, skip
    2157              :       REAL(KIND=dp)                                      :: dij, dik, djk, dr_ij, dr_ik, dr_jk, &
    2158              :                                                             kind_radius_i, kind_radius_j, &
    2159              :                                                             kind_radius_k, max_contraction_i, &
    2160              :                                                             prefac, sijk_ext
    2161         1978 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: ccp_buffer, cpp_buffer, &
    2162         1978 :                                                             max_contraction_j, max_contraction_k
    2163         3956 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: block_t, dummy_block_t, sijk, &
    2164         3956 :                                                             sijk_contr, tmp_ijk
    2165              :       REAL(KIND=dp), DIMENSION(1, 1, 1)                  :: counter
    2166              :       REAL(KIND=dp), DIMENSION(3)                        :: ri, rij, rik, rj, rjk, rk
    2167         1978 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: set_radius_i, set_radius_j, set_radius_k
    2168         1978 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: rpgf_i, rpgf_j, rpgf_k, sphi_i, sphi_j, &
    2169         3956 :                                                             sphi_k, zeti, zetj, zetk
    2170         1978 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    2171              :       TYPE(cell_type), POINTER                           :: cell
    2172         3956 :       TYPE(cp_2d_r_p_type), DIMENSION(:, :), POINTER     :: spi, spk, tspj
    2173              :       TYPE(cp_libint_t)                                  :: lib
    2174        13846 :       TYPE(dbt_type)                                     :: t_3c_tmp
    2175              :       TYPE(dft_control_type), POINTER                    :: dft_control
    2176              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set
    2177              :       TYPE(kpoint_type), POINTER                         :: kpoints
    2178              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    2179              :       TYPE(neighbor_list_3c_iterator_type)               :: nl_3c_iter
    2180         1978 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    2181              : 
    2182         1978 :       CALL timeset(routineN, handle)
    2183              : 
    2184         1978 :       debug = .FALSE.
    2185              : 
    2186         1978 :       IF (PRESENT(do_kpoints)) THEN
    2187          382 :          do_kpoints_prv = do_kpoints
    2188              :       ELSE
    2189              :          do_kpoints_prv = .FALSE.
    2190              :       END IF
    2191              : 
    2192         1978 :       IF (PRESENT(do_hfx_kpoints)) THEN
    2193          140 :          do_hfx_kpoints_prv = do_hfx_kpoints
    2194              :       ELSE
    2195              :          do_hfx_kpoints_prv = .FALSE.
    2196              :       END IF
    2197          140 :       IF (do_hfx_kpoints_prv) THEN
    2198          140 :          CPASSERT(do_kpoints_prv)
    2199          140 :          CPASSERT(PRESENT(RI_range))
    2200          140 :          CPASSERT(PRESENT(img_to_RI_cell))
    2201              :       END IF
    2202              : 
    2203         1838 :       IF (PRESENT(img_to_RI_cell)) THEN
    2204          420 :          ALLOCATE (img_to_RI_cell_prv(SIZE(img_to_RI_cell)))
    2205         6598 :          img_to_RI_cell_prv(:) = img_to_RI_cell
    2206              :       END IF
    2207              : 
    2208         1978 :       IF (PRESENT(desymmetrize)) THEN
    2209         1978 :          desymmetrize_prv = desymmetrize
    2210              :       ELSE
    2211              :          desymmetrize_prv = .TRUE.
    2212              :       END IF
    2213              : 
    2214         1978 :       IF (PRESENT(cell_sym)) THEN
    2215            6 :          cell_sym_prv = cell_sym
    2216              :       ELSE
    2217         1972 :          cell_sym_prv = .FALSE.
    2218              :       END IF
    2219              : 
    2220         1978 :       op_ij = do_potential_id; op_jk = do_potential_id
    2221              : 
    2222         1978 :       IF (PRESENT(op_pos)) THEN
    2223          474 :          op_pos_prv = op_pos
    2224              :       ELSE
    2225         1504 :          op_pos_prv = 1
    2226              :       END IF
    2227              : 
    2228         1838 :       SELECT CASE (op_pos_prv)
    2229              :       CASE (1)
    2230         1838 :          op_ij = potential_parameter%potential_type
    2231              :       CASE (2)
    2232         1978 :          op_jk = potential_parameter%potential_type
    2233              :       END SELECT
    2234              : 
    2235         1978 :       dr_ij = 0.0_dp; dr_jk = 0.0_dp; dr_ik = 0.0_dp
    2236              : 
    2237              :       IF (op_ij == do_potential_truncated .OR. op_ij == do_potential_short &
    2238         1978 :           .OR. op_ij == do_potential_mix_cl_trunc) THEN
    2239         1438 :          dr_ij = potential_parameter%cutoff_radius*cutoff_screen_factor
    2240         1438 :          dr_ik = potential_parameter%cutoff_radius*cutoff_screen_factor
    2241          540 :       ELSEIF (op_ij == do_potential_coulomb) THEN
    2242          192 :          dr_ij = 1000000.0_dp
    2243          192 :          dr_ik = 1000000.0_dp
    2244              :       END IF
    2245              : 
    2246              :       IF (op_jk == do_potential_truncated .OR. op_jk == do_potential_short &
    2247         1978 :           .OR. op_jk == do_potential_mix_cl_trunc) THEN
    2248           12 :          dr_jk = potential_parameter%cutoff_radius*cutoff_screen_factor
    2249           12 :          dr_ik = potential_parameter%cutoff_radius*cutoff_screen_factor
    2250         1966 :       ELSEIF (op_jk == do_potential_coulomb) THEN
    2251            0 :          dr_jk = 1000000.0_dp
    2252            0 :          dr_ik = 1000000.0_dp
    2253              :       END IF
    2254              : 
    2255         1978 :       NULLIFY (qs_kind_set, atomic_kind_set)
    2256              : 
    2257              :       ! get stuff
    2258              :       CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, qs_kind_set=qs_kind_set, cell=cell, &
    2259         1978 :                       natom=natom, dft_control=dft_control, para_env=para_env)
    2260              : 
    2261         1978 :       IF (do_kpoints_prv) THEN
    2262          152 :          IF (PRESENT(cell_to_index_ext)) THEN
    2263            6 :             cell_to_index => cell_to_index_ext
    2264          288 :             nimg = MAXVAL(cell_to_index)
    2265              :          ELSE
    2266          146 :             CALL get_qs_env(qs_env, kpoints=kpoints)
    2267          146 :             CALL get_kpoint_info(kpoints, cell_to_index=cell_to_index)
    2268          146 :             nimg = dft_control%nimages
    2269              :          END IF
    2270          152 :          ncell_RI = nimg
    2271          152 :          IF (do_hfx_kpoints_prv) THEN
    2272          140 :             nimg = SIZE(t3c, 1)
    2273          140 :             ncell_RI = SIZE(t3c, 2)
    2274              :          END IF
    2275              :       ELSE
    2276              :          nimg = 1
    2277              :          ncell_RI = 1
    2278              :       END IF
    2279              : 
    2280              :       CALL alloc_block_3c(t3c, nl_3c, basis_i, basis_j, basis_k, qs_env, potential_parameter, &
    2281              :                           op_pos=op_pos_prv, do_kpoints=do_kpoints, do_hfx_kpoints=do_hfx_kpoints, &
    2282              :                           bounds_i=bounds_i, bounds_j=bounds_j, bounds_k=bounds_k, &
    2283              :                           RI_range=RI_range, img_to_RI_cell=img_to_RI_cell, cell_sym=cell_sym_prv, &
    2284         3816 :                           cell_to_index=cell_to_index)
    2285              : 
    2286         1978 :       IF (do_hfx_kpoints_prv) THEN
    2287          140 :          CPASSERT(op_pos_prv == 2)
    2288          140 :          CPASSERT(.NOT. desymmetrize_prv)
    2289         1838 :       ELSE IF (do_kpoints_prv) THEN
    2290           36 :          CPASSERT(ALL(SHAPE(t3c) == [nimg, ncell_RI]))
    2291              :       END IF
    2292              : 
    2293              :       !Need the max l for each basis for libint and max nset, nco and nsgf for LIBXSMM contraction
    2294         1978 :       nbasis = SIZE(basis_i)
    2295         1978 :       max_nsgfi = 0
    2296         1978 :       max_nset = 0
    2297         1978 :       maxli = 0
    2298         4932 :       DO ibasis = 1, nbasis
    2299              :          CALL get_gto_basis_set(gto_basis_set=basis_i(ibasis)%gto_basis_set, maxl=imax, &
    2300         2954 :                                 nset=iset, nsgf_set=nsgfi, npgf=npgfi)
    2301         2954 :          maxli = MAX(maxli, imax)
    2302         2954 :          max_nset = MAX(max_nset, iset)
    2303        17516 :          max_nsgfi = MAX(max_nsgfi, MAXVAL(nsgfi))
    2304              :       END DO
    2305              :       max_ncoj = 0
    2306              :       maxlj = 0
    2307         4932 :       DO ibasis = 1, nbasis
    2308              :          CALL get_gto_basis_set(gto_basis_set=basis_j(ibasis)%gto_basis_set, maxl=imax, &
    2309         2954 :                                 nset=jset, nsgf_set=nsgfj, npgf=npgfj)
    2310         2954 :          maxlj = MAX(maxlj, imax)
    2311         2954 :          max_nset = MAX(max_nset, jset)
    2312        11314 :          max_ncoj = MAX(max_ncoj, MAXVAL(npgfj)*ncoset(maxlj))
    2313              :       END DO
    2314              :       maxlk = 0
    2315         4932 :       DO ibasis = 1, nbasis
    2316              :          CALL get_gto_basis_set(gto_basis_set=basis_k(ibasis)%gto_basis_set, maxl=imax, &
    2317         2954 :                                 nset=kset, nsgf_set=nsgfk, npgf=npgfk)
    2318         2954 :          maxlk = MAX(maxlk, imax)
    2319         4932 :          max_nset = MAX(max_nset, kset)
    2320              :       END DO
    2321         1978 :       m_max = maxli + maxlj + maxlk
    2322              : 
    2323              :       !To minimize expensive memory ops and generally optimize contraction, pre-allocate
    2324              :       !contiguous sphi arrays (and transposed in the case of sphi_i)
    2325              : 
    2326         1978 :       NULLIFY (tspj, spi, spk)
    2327        75842 :       ALLOCATE (spi(max_nset, nbasis), tspj(max_nset, nbasis), spk(max_nset, nbasis))
    2328              : 
    2329         4932 :       DO ibasis = 1, nbasis
    2330        21984 :          DO iset = 1, max_nset
    2331        17052 :             NULLIFY (spi(iset, ibasis)%array)
    2332        17052 :             NULLIFY (tspj(iset, ibasis)%array)
    2333              : 
    2334        20006 :             NULLIFY (spk(iset, ibasis)%array)
    2335              :          END DO
    2336              :       END DO
    2337              : 
    2338         7912 :       DO ilist = 1, 3
    2339        16774 :          DO ibasis = 1, nbasis
    2340         8862 :             IF (ilist == 1) basis_set => basis_i(ibasis)%gto_basis_set
    2341         8862 :             IF (ilist == 2) basis_set => basis_j(ibasis)%gto_basis_set
    2342         8862 :             IF (ilist == 3) basis_set => basis_k(ibasis)%gto_basis_set
    2343              : 
    2344        39876 :             DO iset = 1, basis_set%nset
    2345              : 
    2346        25080 :                ncoi = basis_set%npgf(iset)*ncoset(basis_set%lmax(iset))
    2347        25080 :                sgfi = basis_set%first_sgf(1, iset)
    2348        25080 :                egfi = sgfi + basis_set%nsgf_set(iset) - 1
    2349              : 
    2350        33942 :                IF (ilist == 1) THEN
    2351        50336 :                   ALLOCATE (spi(iset, ibasis)%array(ncoi, basis_set%nsgf_set(iset)))
    2352      3349236 :                   spi(iset, ibasis)%array(:, :) = basis_set%sphi(1:ncoi, sgfi:egfi)
    2353              : 
    2354        12496 :                ELSE IF (ilist == 2) THEN
    2355        25528 :                   ALLOCATE (tspj(iset, ibasis)%array(basis_set%nsgf_set(iset), ncoi))
    2356       358742 :                   tspj(iset, ibasis)%array(:, :) = TRANSPOSE(basis_set%sphi(1:ncoi, sgfi:egfi))
    2357              : 
    2358              :                ELSE
    2359        24456 :                   ALLOCATE (spk(iset, ibasis)%array(ncoi, basis_set%nsgf_set(iset)))
    2360      1495290 :                   spk(iset, ibasis)%array(:, :) = basis_set%sphi(1:ncoi, sgfi:egfi)
    2361              :                END IF
    2362              : 
    2363              :             END DO !iset
    2364              :          END DO !ibasis
    2365              :       END DO !ilist
    2366              : 
    2367              :       !Init the truncated Coulomb operator
    2368              :       IF (op_ij == do_potential_truncated .OR. op_jk == do_potential_truncated &
    2369         1978 :           .OR. op_ij == do_potential_mix_cl_trunc .OR. op_jk == do_potential_mix_cl_trunc) THEN
    2370              : 
    2371         1444 :          IF (m_max > get_lmax_init()) THEN
    2372           84 :             IF (para_env%mepos == 0) THEN
    2373           42 :                CALL open_file(unit_number=unit_id, file_name=potential_parameter%filename)
    2374              :             END IF
    2375           84 :             CALL init(m_max, unit_id, para_env%mepos, para_env)
    2376           84 :             IF (para_env%mepos == 0) THEN
    2377           42 :                CALL close_file(unit_id)
    2378              :             END IF
    2379              :          END IF
    2380              :       END IF
    2381              : 
    2382         1978 :       CALL init_md_ftable(nmax=m_max)
    2383              : 
    2384         1978 :       IF (do_kpoints_prv) THEN
    2385          608 :          kp_index_lbounds = LBOUND(cell_to_index)
    2386          608 :          kp_index_ubounds = UBOUND(cell_to_index)
    2387              :       END IF
    2388              : 
    2389         7912 :       counter = 1.0_dp
    2390              : 
    2391         1978 :       nthread = 1
    2392         1978 : !$    nthread = omp_get_max_threads()
    2393              : 
    2394              : !$OMP PARALLEL DEFAULT(NONE) &
    2395              : !$OMP SHARED (nthread,do_kpoints_prv,kp_index_lbounds,kp_index_ubounds,maxli,maxlk,maxlj,bounds_i,&
    2396              : !$OMP         bounds_j,bounds_k,nimg,basis_i,basis_j,basis_k,dr_ij,dr_jk,dr_ik,ncoset,&
    2397              : !$OMP         potential_parameter,int_eps,t3c,tspj,spi,spk,debug,cell_to_index,&
    2398              : !$OMP         natom,nl_3c,cell,op_pos_prv,do_hfx_kpoints_prv,RI_range,ncell_RI, &
    2399              : !$OMP         img_to_RI_cell_prv, cell_sym_prv) &
    2400              : !$OMP PRIVATE (lib,nl_3c_iter,ikind,jkind,kkind,iatom,jatom,katom,rij,rjk,rik,cell_j,cell_k,&
    2401              : !$OMP          prefac,jcell,kcell,first_sgf_i,lmax_i,lmin_i,npgfi,nseti,nsgfi,rpgf_i,set_radius_i,&
    2402              : !$OMP          sphi_i,zeti,kind_radius_i,first_sgf_j,lmax_j,lmin_j,npgfj,nsetj,nsgfj,rpgf_j,&
    2403              : !$OMP          set_radius_j,sphi_j,zetj,kind_radius_j,first_sgf_k,lmax_k,lmin_k,npgfk,nsetk,nsgfk,&
    2404              : !$OMP          rpgf_k,set_radius_k,sphi_k,zetk,kind_radius_k,djk,dij,dik,ncoi,ncoj,ncok,sgfi,sgfj,&
    2405              : !$OMP          sgfk,sijk,ri,rj,rk,sijk_ext,block_not_zero,max_contraction_i,max_contraction_j,&
    2406              : !$OMP          max_contraction_k,iset,jset,kset,block_t,blk_size,sijk_contr,cpp_buffer,ccp_buffer,&
    2407              : !$OMP          block_start_j,block_end_j,block_start_k,block_end_k,block_start_i,block_end_i,found,&
    2408         1978 : !$OMP          dummy_block_t,sp,handle2,mepos,bo,skip,tmp_ijk,i,blk_idx)
    2409              : 
    2410              :       mepos = 0
    2411              : !$    mepos = omp_get_thread_num()
    2412              : 
    2413              :       CALL cp_libint_init_3eri(lib, MAX(maxli, maxlj, maxlk))
    2414              :       CALL cp_libint_set_contrdepth(lib, 1)
    2415              :       CALL neighbor_list_3c_iterator_create(nl_3c_iter, nl_3c)
    2416              : 
    2417              :       !We split the provided bounds among the threads such that each threads works on a different set of atoms
    2418              :       IF (PRESENT(bounds_i)) THEN
    2419              :          bo = get_limit(bounds_i(2) - bounds_i(1) + 1, nthread, mepos)
    2420              :          bo(:) = bo(:) + bounds_i(1) - 1
    2421              :          CALL nl_3c_iter_set_bounds(nl_3c_iter, bo, bounds_j, bounds_k)
    2422              :       ELSE IF (PRESENT(bounds_j)) THEN
    2423              : 
    2424              :          bo = get_limit(bounds_j(2) - bounds_j(1) + 1, nthread, mepos)
    2425              :          bo(:) = bo(:) + bounds_j(1) - 1
    2426              :          CALL nl_3c_iter_set_bounds(nl_3c_iter, bounds_i, bo, bounds_k)
    2427              :       ELSE IF (PRESENT(bounds_k)) THEN
    2428              :          bo = get_limit(bounds_k(2) - bounds_k(1) + 1, nthread, mepos)
    2429              :          bo(:) = bo(:) + bounds_k(1) - 1
    2430              :          CALL nl_3c_iter_set_bounds(nl_3c_iter, bounds_i, bounds_j, bo)
    2431              :       ELSE
    2432              :          bo = get_limit(natom, nthread, mepos)
    2433              :          CALL nl_3c_iter_set_bounds(nl_3c_iter, bo, bounds_j, bounds_k)
    2434              :       END IF
    2435              : 
    2436              :       skip = .FALSE.
    2437              :       IF (bo(1) > bo(2)) skip = .TRUE.
    2438              : 
    2439              :       DO WHILE (neighbor_list_3c_iterate(nl_3c_iter) == 0)
    2440              :          CALL get_3c_iterator_info(nl_3c_iter, ikind=ikind, jkind=jkind, kkind=kkind, &
    2441              :                                    iatom=iatom, jatom=jatom, katom=katom, &
    2442              :                                    rij=rij, rjk=rjk, rik=rik, cell_j=cell_j, cell_k=cell_k)
    2443              :          IF (skip) EXIT
    2444              : 
    2445              :          djk = NORM2(rjk)
    2446              :          dij = NORM2(rij)
    2447              :          dik = NORM2(rik)
    2448              : 
    2449              :          IF (nl_3c%sym == symmetric_jk) THEN
    2450              :             IF (jatom == katom) THEN
    2451              :                ! factor 0.5 due to double-counting of diagonal blocks
    2452              :                ! (we desymmetrize by adding transpose)
    2453              :                prefac = 0.5_dp
    2454              :             ELSE
    2455              :                prefac = 1.0_dp
    2456              :             END IF
    2457              :          ELSEIF (nl_3c%sym == symmetric_ij) THEN
    2458              :             IF (iatom == jatom) THEN
    2459              :                ! factor 0.5 due to double-counting of diagonal blocks
    2460              :                ! (we desymmetrize by adding transpose)
    2461              :                prefac = 0.5_dp
    2462              :             ELSE
    2463              :                prefac = 1.0_dp
    2464              :             END IF
    2465              :          ELSE
    2466              :             prefac = 1.0_dp
    2467              :          END IF
    2468              :          IF (do_kpoints_prv) prefac = 1.0_dp
    2469              : 
    2470              :          IF (do_kpoints_prv) THEN
    2471              : 
    2472              :             IF (ANY([cell_j(1), cell_j(2), cell_j(3)] < kp_index_lbounds) .OR. &
    2473              :                 ANY([cell_j(1), cell_j(2), cell_j(3)] > kp_index_ubounds)) CYCLE
    2474              : 
    2475              :             jcell = cell_to_index(cell_j(1), cell_j(2), cell_j(3))
    2476              :             IF (jcell > nimg .OR. jcell < 1) CYCLE
    2477              : 
    2478              :             IF (ANY([cell_k(1), cell_k(2), cell_k(3)] < kp_index_lbounds) .OR. &
    2479              :                 ANY([cell_k(1), cell_k(2), cell_k(3)] > kp_index_ubounds)) CYCLE
    2480              : 
    2481              :             kcell = cell_to_index(cell_k(1), cell_k(2), cell_k(3))
    2482              :             IF (kcell > nimg .OR. kcell < 1) CYCLE
    2483              :             !In case of HFX k-points, we only consider P^k if d_ik <= RI_range
    2484              :             IF (do_hfx_kpoints_prv) THEN
    2485              :                IF (dik > RI_range) CYCLE
    2486              :                kcell = img_to_RI_cell_prv(kcell)
    2487              :             END IF
    2488              :          ELSE
    2489              :             jcell = 1; kcell = 1
    2490              :          END IF
    2491              : 
    2492              :          IF (cell_sym_prv .AND. jcell < kcell) CYCLE
    2493              : 
    2494              :          blk_idx = [iatom, jatom, katom]
    2495              :          IF (do_hfx_kpoints_prv) THEN
    2496              :             blk_idx(3) = (kcell - 1)*natom + katom
    2497              :             kcell = 1
    2498              :          END IF
    2499              : 
    2500              :          CALL get_gto_basis_set(basis_i(ikind)%gto_basis_set, first_sgf=first_sgf_i, lmax=lmax_i, lmin=lmin_i, &
    2501              :                                 npgf=npgfi, nset=nseti, nsgf_set=nsgfi, pgf_radius=rpgf_i, set_radius=set_radius_i, &
    2502              :                                 sphi=sphi_i, zet=zeti, kind_radius=kind_radius_i)
    2503              :          CALL get_gto_basis_set(basis_j(jkind)%gto_basis_set, first_sgf=first_sgf_j, lmax=lmax_j, lmin=lmin_j, &
    2504              :                                 npgf=npgfj, nset=nsetj, nsgf_set=nsgfj, pgf_radius=rpgf_j, set_radius=set_radius_j, &
    2505              :                                 sphi=sphi_j, zet=zetj, kind_radius=kind_radius_j)
    2506              :          IF (kind_radius_j + kind_radius_i + dr_ij < dij) CYCLE
    2507              : 
    2508              :          CALL get_gto_basis_set(basis_k(kkind)%gto_basis_set, first_sgf=first_sgf_k, lmax=lmax_k, lmin=lmin_k, &
    2509              :                                 npgf=npgfk, nset=nsetk, nsgf_set=nsgfk, pgf_radius=rpgf_k, set_radius=set_radius_k, &
    2510              :                                 sphi=sphi_k, zet=zetk, kind_radius=kind_radius_k)
    2511              :          IF (kind_radius_j + kind_radius_k + dr_jk < djk) CYCLE
    2512              :          IF (kind_radius_k + kind_radius_i + dr_ik < dik) CYCLE
    2513              : 
    2514              :          IF (PRESENT(int_eps)) THEN
    2515              :             ALLOCATE (max_contraction_j(nsetj))
    2516              :             DO jset = 1, nsetj
    2517              :                sgfj = first_sgf_j(1, jset)
    2518              :                max_contraction_j(jset) = MAXVAL([(SUM(ABS(sphi_j(:, i))), i=sgfj, sgfj + nsgfj(jset) - 1)])
    2519              :             END DO
    2520              : 
    2521              :             ALLOCATE (max_contraction_k(nsetk))
    2522              :             DO kset = 1, nsetk
    2523              :                sgfk = first_sgf_k(1, kset)
    2524              :                max_contraction_k(kset) = MAXVAL([(SUM(ABS(sphi_k(:, i))), i=sgfk, sgfk + nsgfk(kset) - 1)])
    2525              :             END DO
    2526              :          END IF
    2527              : 
    2528              :          CALL dbt_blk_sizes(t3c(jcell, kcell), blk_idx, blk_size)
    2529              : 
    2530              :          ALLOCATE (block_t(blk_size(2), blk_size(3), blk_size(1)), SOURCE=0.0_dp)
    2531              : 
    2532              :          block_not_zero = .FALSE.
    2533              :          DO iset = 1, nseti
    2534              : 
    2535              :             sgfi = first_sgf_i(1, iset)
    2536              :             max_contraction_i = MAXVAL([(SUM(ABS(sphi_i(:, i))), i=sgfi, sgfi + nsgfi(iset) - 1)])
    2537              : 
    2538              :             DO jset = 1, nsetj
    2539              : 
    2540              :                IF (set_radius_j(jset) + set_radius_i(iset) + dr_ij < dij) CYCLE
    2541              : 
    2542              :                DO kset = 1, nsetk
    2543              : 
    2544              :                   IF (set_radius_j(jset) + set_radius_k(kset) + dr_jk < djk) CYCLE
    2545              :                   IF (set_radius_k(kset) + set_radius_i(iset) + dr_ik < dik) CYCLE
    2546              : 
    2547              :                   ncoi = npgfi(iset)*ncoset(lmax_i(iset))
    2548              :                   ncoj = npgfj(jset)*ncoset(lmax_j(jset))
    2549              :                   ncok = npgfk(kset)*ncoset(lmax_k(kset))
    2550              : 
    2551              :                   !ensure non-zero number of triples below
    2552              :                   IF (ncoj*ncok*ncoi == 0) CYCLE
    2553              : 
    2554              :                   !need positions for libint. Only relative positions are needed => set ri to 0.0
    2555              :                   ri = 0.0_dp
    2556              :                   rj = rij ! ri + rij
    2557              :                   rk = rik ! ri + rik
    2558              : 
    2559              :                   ALLOCATE (sijk(ncoj, ncok, ncoi))
    2560              :                   IF (op_pos_prv == 1) THEN
    2561              :                      sijk(:, :, :) = 0.0_dp
    2562              :                      CALL eri_3center(sijk, &
    2563              :                                       lmin_j(jset), lmax_j(jset), npgfj(jset), zetj(:, jset), rpgf_j(:, jset), rj, &
    2564              :                                       lmin_k(kset), lmax_k(kset), npgfk(kset), zetk(:, kset), rpgf_k(:, kset), rk, &
    2565              :                                       lmin_i(iset), lmax_i(iset), npgfi(iset), zeti(:, iset), rpgf_i(:, iset), ri, &
    2566              :                                       djk, dij, dik, lib, potential_parameter, int_abc_ext=sijk_ext)
    2567              :                   ELSE
    2568              :                      ALLOCATE (tmp_ijk(ncoi, ncoj, ncok), SOURCE=0.0_dp)
    2569              :                      CALL eri_3center(tmp_ijk, &
    2570              :                                       lmin_i(iset), lmax_i(iset), npgfi(iset), zeti(:, iset), rpgf_i(:, iset), ri, &
    2571              :                                       lmin_j(jset), lmax_j(jset), npgfj(jset), zetj(:, jset), rpgf_j(:, jset), rj, &
    2572              :                                       lmin_k(kset), lmax_k(kset), npgfk(kset), zetk(:, kset), rpgf_k(:, kset), rk, &
    2573              :                                       dij, dik, djk, lib, potential_parameter, int_abc_ext=sijk_ext)
    2574              : 
    2575              :                      !F08: sijk = RESHAPE(tmp_ijk, [ncoj, ncok, ncoi], ORDER=[2, 3, 1]) with sijk not allocated
    2576              :                      DO i = 1, ncoi !TODO: revise/check for efficiency
    2577              :                         sijk(:, :, i) = tmp_ijk(i, :, :)
    2578              :                      END DO
    2579              :                      DEALLOCATE (tmp_ijk)
    2580              :                   END IF
    2581              : 
    2582              :                   IF (PRESENT(int_eps)) THEN
    2583              :                      IF (int_eps > sijk_ext*(max_contraction_i* &
    2584              :                                              max_contraction_j(jset)* &
    2585              :                                              max_contraction_k(kset))) THEN
    2586              :                         DEALLOCATE (sijk)
    2587              :                         CYCLE
    2588              :                      END IF
    2589              :                   END IF
    2590              : 
    2591              :                   block_not_zero = .TRUE.
    2592              :                   ALLOCATE (sijk_contr(nsgfj(jset), nsgfk(kset), nsgfi(iset)))
    2593              :                   CALL abc_contract_xsmm(sijk_contr, sijk, tspj(jset, jkind)%array, &
    2594              :                                          spk(kset, kkind)%array, spi(iset, ikind)%array, &
    2595              :                                          ncoj, ncok, ncoi, nsgfj(jset), nsgfk(kset), &
    2596              :                                          nsgfi(iset), cpp_buffer, ccp_buffer, prefac)
    2597              :                   DEALLOCATE (sijk)
    2598              : 
    2599              :                   sgfj = first_sgf_j(1, jset)
    2600              :                   sgfk = first_sgf_k(1, kset)
    2601              : 
    2602              :                   block_start_j = sgfj
    2603              :                   block_end_j = sgfj + nsgfj(jset) - 1
    2604              :                   block_start_k = sgfk
    2605              :                   block_end_k = sgfk + nsgfk(kset) - 1
    2606              :                   block_start_i = sgfi
    2607              :                   block_end_i = sgfi + nsgfi(iset) - 1
    2608              : 
    2609              :                   block_t(block_start_j:block_end_j, &
    2610              :                           block_start_k:block_end_k, &
    2611              :                           block_start_i:block_end_i) = &
    2612              :                      block_t(block_start_j:block_end_j, &
    2613              :                              block_start_k:block_end_k, &
    2614              :                              block_start_i:block_end_i) + &
    2615              :                      sijk_contr(:, :, :)
    2616              :                   DEALLOCATE (sijk_contr)
    2617              : 
    2618              :                END DO
    2619              : 
    2620              :             END DO
    2621              : 
    2622              :          END DO
    2623              : 
    2624              :          IF (block_not_zero) THEN
    2625              : !$OMP CRITICAL(qs_tensors_t3c)
    2626              :             CALL timeset(routineN//"_put_dbcsr", handle2)
    2627              :             IF (debug) THEN
    2628              :                CALL dbt_get_block(t3c(jcell, kcell), blk_idx, dummy_block_t, found=found)
    2629              :                CPASSERT(found)
    2630              :             END IF
    2631              : 
    2632              :             sp = SHAPE(block_t)
    2633              :             sp([2, 3, 1]) = sp ! sp = sp([2, 3, 1]) performs worse
    2634              : 
    2635              :             CALL dbt_put_block(t3c(jcell, kcell), blk_idx, sp, &
    2636              :                                RESHAPE(block_t, SHAPE=sp, ORDER=[2, 3, 1]), summation=.TRUE.)
    2637              : 
    2638              :             CALL timestop(handle2)
    2639              : !$OMP END CRITICAL(qs_tensors_t3c)
    2640              :          END IF
    2641              : 
    2642              :          DEALLOCATE (block_t)
    2643              :          IF (PRESENT(int_eps)) THEN
    2644              :             DEALLOCATE (max_contraction_j, max_contraction_k)
    2645              :          END IF
    2646              :       END DO
    2647              : 
    2648              :       IF (ALLOCATED(ccp_buffer)) DEALLOCATE (ccp_buffer)
    2649              :       IF (ALLOCATED(cpp_buffer)) DEALLOCATE (cpp_buffer)
    2650              : 
    2651              :       CALL cp_libint_cleanup_3eri(lib)
    2652              :       CALL neighbor_list_3c_iterator_destroy(nl_3c_iter)
    2653              : !$OMP END PARALLEL
    2654              : 
    2655              :       !TODO: deal with hfx_kpoints, because should not filter by 1/2
    2656         1978 :       IF (nl_3c%sym == symmetric_jk .OR. do_kpoints_prv) THEN
    2657              : 
    2658          716 :          IF (.NOT. do_hfx_kpoints_prv) THEN
    2659         1228 :             DO kcell = 1, nimg
    2660         2568 :                DO jcell = 1, nimg
    2661              :                   ! need half of filter eps because afterwards we add transposed tensor
    2662         1992 :                   CALL dbt_filter(t3c(jcell, kcell), filter_eps/2)
    2663              :                END DO
    2664              :             END DO
    2665              :          ELSE
    2666          280 :             DO kcell = 1, ncell_RI
    2667         4058 :                DO jcell = 1, nimg
    2668         3918 :                   CALL dbt_filter(t3c(jcell, kcell), filter_eps)
    2669              :                END DO
    2670              :             END DO
    2671              :          END IF
    2672              : 
    2673          716 :          IF (desymmetrize_prv) THEN
    2674              :             ! add transposed of overlap integrals
    2675            0 :             CALL dbt_create(t3c(1, 1), t_3c_tmp)
    2676            0 :             DO kcell = 1, jcell
    2677            0 :                DO jcell = 1, nimg
    2678            0 :                   CALL dbt_copy(t3c(jcell, kcell), t_3c_tmp)
    2679            0 :                   CALL dbt_copy(t_3c_tmp, t3c(kcell, jcell), order=[1, 3, 2], summation=.TRUE., move_data=.TRUE.)
    2680            0 :                   CALL dbt_filter(t3c(kcell, jcell), filter_eps)
    2681              :                END DO
    2682              :             END DO
    2683            0 :             DO kcell = jcell + 1, nimg
    2684            0 :                DO jcell = 1, nimg
    2685            0 :                   CALL dbt_copy(t3c(jcell, kcell), t_3c_tmp)
    2686            0 :                   CALL dbt_copy(t_3c_tmp, t3c(kcell, jcell), order=[1, 3, 2], summation=.FALSE., move_data=.TRUE.)
    2687            0 :                   CALL dbt_filter(t3c(kcell, jcell), filter_eps)
    2688              :                END DO
    2689              :             END DO
    2690            0 :             CALL dbt_destroy(t_3c_tmp)
    2691              :          END IF
    2692         1262 :       ELSEIF (nl_3c%sym == symmetric_ij) THEN
    2693            0 :          DO kcell = 1, nimg
    2694            0 :             DO jcell = 1, nimg
    2695            0 :                CALL dbt_filter(t3c(jcell, kcell), filter_eps/2)
    2696              :             END DO
    2697              :          END DO
    2698         1262 :       ELSEIF (nl_3c%sym == symmetric_none) THEN
    2699         2524 :          DO kcell = 1, nimg
    2700         3786 :             DO jcell = 1, nimg
    2701         2524 :                CALL dbt_filter(t3c(jcell, kcell), filter_eps)
    2702              :             END DO
    2703              :          END DO
    2704              :       ELSE
    2705            0 :          CPABORT("requested symmetric case not implemented")
    2706              :       END IF
    2707              : 
    2708         4932 :       DO ibasis = 1, nbasis
    2709        21984 :          DO iset = 1, max_nset
    2710        17052 :             IF (ASSOCIATED(spi(iset, ibasis)%array)) DEALLOCATE (spi(iset, ibasis)%array)
    2711        17052 :             IF (ASSOCIATED(tspj(iset, ibasis)%array)) DEALLOCATE (tspj(iset, ibasis)%array)
    2712        20006 :             IF (ASSOCIATED(spk(iset, ibasis)%array)) DEALLOCATE (spk(iset, ibasis)%array)
    2713              :          END DO
    2714              :       END DO
    2715         1978 :       DEALLOCATE (spi, tspj, spk)
    2716              : 
    2717         1978 :       CALL timestop(handle)
    2718        17802 :    END SUBROUTINE build_3c_integrals
    2719              : 
    2720              : ! **************************************************************************************************
    2721              : !> \brief Calculates the derivatives of 2-center integrals, wrt to the first center
    2722              : !> \param t2c_der ...
    2723              : !> this routine requires that libint has been static initialised somewhere else
    2724              : !> \param filter_eps Filter threshold for matrix blocks
    2725              : !> \param qs_env ...
    2726              : !> \param nl_2c 2-center neighborlist
    2727              : !> \param basis_i ...
    2728              : !> \param basis_j ...
    2729              : !> \param potential_parameter ...
    2730              : !> \param do_kpoints ...
    2731              : ! **************************************************************************************************
    2732          384 :    SUBROUTINE build_2c_derivatives(t2c_der, filter_eps, qs_env, &
    2733          384 :                                    nl_2c, basis_i, basis_j, &
    2734              :                                    potential_parameter, do_kpoints)
    2735              : 
    2736              :       TYPE(dbcsr_type), DIMENSION(:, :), INTENT(INOUT)   :: t2c_der
    2737              :       REAL(KIND=dp), INTENT(IN)                          :: filter_eps
    2738              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2739              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    2740              :          POINTER                                         :: nl_2c
    2741              :       TYPE(gto_basis_set_p_type), DIMENSION(:)           :: basis_i, basis_j
    2742              :       TYPE(libint_potential_type), INTENT(IN)            :: potential_parameter
    2743              :       LOGICAL, INTENT(IN), OPTIONAL                      :: do_kpoints
    2744              : 
    2745              :       CHARACTER(len=*), PARAMETER :: routineN = 'build_2c_derivatives'
    2746              : 
    2747              :       INTEGER :: handle, i_xyz, iatom, ibasis, icol, ikind, imax, img, irow, iset, jatom, jkind, &
    2748              :          jset, m_max, maxli, maxlj, natom, ncoi, ncoj, nimg, nseti, nsetj, op_prv, sgfi, sgfj, &
    2749              :          unit_id
    2750              :       INTEGER, DIMENSION(3)                              :: cell_j, kp_index_lbounds, &
    2751              :                                                             kp_index_ubounds
    2752          384 :       INTEGER, DIMENSION(:), POINTER                     :: lmax_i, lmax_j, lmin_i, lmin_j, npgfi, &
    2753          384 :                                                             npgfj, nsgfi, nsgfj
    2754          384 :       INTEGER, DIMENSION(:, :), POINTER                  :: first_sgf_i, first_sgf_j
    2755          384 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
    2756              :       LOGICAL                                            :: do_kpoints_prv, do_symmetric, found, &
    2757              :                                                             trans
    2758              :       REAL(KIND=dp)                                      :: dab
    2759          384 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: dij_contr, dij_rs
    2760          384 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: dij
    2761              :       REAL(KIND=dp), DIMENSION(3)                        :: ri, rij, rj
    2762          384 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: set_radius_i, set_radius_j
    2763          384 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: rpgf_i, rpgf_j, sphi_i, sphi_j, zeti, &
    2764          384 :                                                             zetj
    2765          384 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    2766         1536 :       TYPE(block_p_type), DIMENSION(3)                   :: block_t
    2767              :       TYPE(cp_libint_t)                                  :: lib
    2768              :       TYPE(dft_control_type), POINTER                    :: dft_control
    2769              :       TYPE(kpoint_type), POINTER                         :: kpoints
    2770              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    2771              :       TYPE(neighbor_list_iterator_p_type), &
    2772          384 :          DIMENSION(:), POINTER                           :: nl_iterator
    2773          384 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    2774              : 
    2775          384 :       CALL timeset(routineN, handle)
    2776              : 
    2777          384 :       IF (PRESENT(do_kpoints)) THEN
    2778           92 :          do_kpoints_prv = do_kpoints
    2779              :       ELSE
    2780              :          do_kpoints_prv = .FALSE.
    2781              :       END IF
    2782              : 
    2783          384 :       op_prv = potential_parameter%potential_type
    2784              : 
    2785          384 :       NULLIFY (qs_kind_set, atomic_kind_set, block_t(1)%block, block_t(2)%block, block_t(3)%block, cell_to_index)
    2786              : 
    2787              :       ! get stuff
    2788              :       CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, qs_kind_set=qs_kind_set, &
    2789          384 :                       natom=natom, kpoints=kpoints, dft_control=dft_control, para_env=para_env)
    2790              : 
    2791          384 :       IF (do_kpoints_prv) THEN
    2792           92 :          nimg = SIZE(t2c_der, 1)
    2793           92 :          CALL get_kpoint_info(kpoints, cell_to_index=cell_to_index)
    2794          368 :          kp_index_lbounds = LBOUND(cell_to_index)
    2795          368 :          kp_index_ubounds = UBOUND(cell_to_index)
    2796              :       ELSE
    2797              :          nimg = 1
    2798              :       END IF
    2799              : 
    2800              :       ! check for symmetry
    2801          384 :       CPASSERT(SIZE(nl_2c) > 0)
    2802          384 :       CALL get_neighbor_list_set_p(neighbor_list_sets=nl_2c, symmetric=do_symmetric)
    2803              : 
    2804          384 :       IF (do_symmetric) THEN
    2805          584 :          DO img = 1, nimg
    2806              :             !Derivtive matrix is assymetric
    2807         1460 :             DO i_xyz = 1, 3
    2808         1168 :                CPASSERT(dbcsr_get_matrix_type(t2c_der(img, i_xyz)) == dbcsr_type_antisymmetric)
    2809              :             END DO
    2810              :          END DO
    2811              :       ELSE
    2812         2296 :          DO img = 1, nimg
    2813         8908 :             DO i_xyz = 1, 3
    2814         8816 :                CPASSERT(dbcsr_get_matrix_type(t2c_der(img, i_xyz)) == dbcsr_type_no_symmetry)
    2815              :             END DO
    2816              :          END DO
    2817              :       END IF
    2818              : 
    2819         2880 :       DO img = 1, nimg
    2820        10368 :          DO i_xyz = 1, 3
    2821         9984 :             CALL cp_dbcsr_alloc_block_from_nbl(t2c_der(img, i_xyz), nl_2c)
    2822              :          END DO
    2823              :       END DO
    2824              : 
    2825          384 :       maxli = 0
    2826         1086 :       DO ibasis = 1, SIZE(basis_i)
    2827          702 :          CALL get_gto_basis_set(gto_basis_set=basis_i(ibasis)%gto_basis_set, maxl=imax)
    2828         1086 :          maxli = MAX(maxli, imax)
    2829              :       END DO
    2830          384 :       maxlj = 0
    2831         1086 :       DO ibasis = 1, SIZE(basis_j)
    2832          702 :          CALL get_gto_basis_set(gto_basis_set=basis_j(ibasis)%gto_basis_set, maxl=imax)
    2833         1086 :          maxlj = MAX(maxlj, imax)
    2834              :       END DO
    2835              : 
    2836          384 :       m_max = maxli + maxlj + 1
    2837              : 
    2838              :       !Init the truncated Coulomb operator
    2839          384 :       IF (op_prv == do_potential_truncated .OR. op_prv == do_potential_mix_cl_trunc) THEN
    2840              : 
    2841           60 :          IF (m_max > get_lmax_init()) THEN
    2842           22 :             IF (para_env%mepos == 0) THEN
    2843           11 :                CALL open_file(unit_number=unit_id, file_name=potential_parameter%filename)
    2844              :             END IF
    2845           22 :             CALL init(m_max, unit_id, para_env%mepos, para_env)
    2846           22 :             IF (para_env%mepos == 0) THEN
    2847           11 :                CALL close_file(unit_id)
    2848              :             END IF
    2849              :          END IF
    2850              :       END IF
    2851              : 
    2852          384 :       CALL init_md_ftable(nmax=m_max)
    2853              : 
    2854          384 :       CALL cp_libint_init_2eri1(lib, MAX(maxli, maxlj))
    2855          384 :       CALL cp_libint_set_contrdepth(lib, 1)
    2856              : 
    2857          384 :       CALL neighbor_list_iterator_create(nl_iterator, nl_2c)
    2858        14908 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
    2859              : 
    2860              :          CALL get_iterator_info(nl_iterator, ikind=ikind, jkind=jkind, &
    2861        14524 :                                 iatom=iatom, jatom=jatom, r=rij, cell=cell_j)
    2862        14524 :          IF (do_kpoints_prv) THEN
    2863        11326 :             IF (ANY([cell_j(1), cell_j(2), cell_j(3)] < kp_index_lbounds) .OR. &
    2864              :                 ANY([cell_j(1), cell_j(2), cell_j(3)] > kp_index_ubounds)) CYCLE
    2865         1618 :             img = cell_to_index(cell_j(1), cell_j(2), cell_j(3))
    2866         1618 :             IF (img > nimg .OR. img < 1) CYCLE
    2867              :          ELSE
    2868              :             img = 1
    2869              :          END IF
    2870              : 
    2871              :          CALL get_gto_basis_set(basis_i(ikind)%gto_basis_set, first_sgf=first_sgf_i, lmax=lmax_i, lmin=lmin_i, &
    2872              :                                 npgf=npgfi, nset=nseti, nsgf_set=nsgfi, pgf_radius=rpgf_i, set_radius=set_radius_i, &
    2873        14496 :                                 sphi=sphi_i, zet=zeti)
    2874              : 
    2875              :          CALL get_gto_basis_set(basis_j(jkind)%gto_basis_set, first_sgf=first_sgf_j, lmax=lmax_j, lmin=lmin_j, &
    2876              :                                 npgf=npgfj, nset=nsetj, nsgf_set=nsgfj, pgf_radius=rpgf_j, set_radius=set_radius_j, &
    2877        14496 :                                 sphi=sphi_j, zet=zetj)
    2878              : 
    2879        14496 :          IF (do_symmetric) THEN
    2880        12906 :             IF (iatom <= jatom) THEN
    2881         7900 :                irow = iatom
    2882         7900 :                icol = jatom
    2883              :             ELSE
    2884         5006 :                irow = jatom
    2885         5006 :                icol = iatom
    2886              :             END IF
    2887              :          ELSE
    2888         1590 :             irow = iatom
    2889         1590 :             icol = jatom
    2890              :          END IF
    2891              : 
    2892        57984 :          dab = NORM2(rij)
    2893        14496 :          trans = do_symmetric .AND. (iatom > jatom)
    2894              : 
    2895        57984 :          DO i_xyz = 1, 3
    2896              :             CALL dbcsr_get_block_p(matrix=t2c_der(img, i_xyz), &
    2897        43488 :                                    row=irow, col=icol, BLOCK=block_t(i_xyz)%block, found=found)
    2898        57984 :             CPASSERT(found)
    2899              :          END DO
    2900              : 
    2901        49556 :          DO iset = 1, nseti
    2902              : 
    2903        34676 :             ncoi = npgfi(iset)*ncoset(lmax_i(iset))
    2904        34676 :             sgfi = first_sgf_i(1, iset)
    2905              : 
    2906       172652 :             DO jset = 1, nsetj
    2907              : 
    2908       123452 :                ncoj = npgfj(jset)*ncoset(lmax_j(jset))
    2909       123452 :                sgfj = first_sgf_j(1, jset)
    2910              : 
    2911       158128 :                IF (ncoi*ncoj > 0) THEN
    2912       493808 :                   ALLOCATE (dij_contr(nsgfi(iset), nsgfj(jset)))
    2913    313937563 :                   ALLOCATE (dij(ncoi, ncoj, 3), SOURCE=0.0_dp)
    2914              : 
    2915       123452 :                   ri = 0.0_dp
    2916       123452 :                   rj = rij
    2917              : 
    2918              :                   CALL eri_2center_derivs(dij, lmin_i(iset), lmax_i(iset), npgfi(iset), zeti(:, iset), &
    2919              :                                           rpgf_i(:, iset), ri, lmin_j(jset), lmax_j(jset), npgfj(jset), zetj(:, jset), &
    2920       123452 :                                           rpgf_j(:, jset), rj, dab, lib, potential_parameter)
    2921              : 
    2922       493808 :                   DO i_xyz = 1, 3
    2923              : 
    2924    123412836 :                      dij_contr(:, :) = 0.0_dp
    2925              :                      CALL ab_contract(dij_contr, dij(:, :, i_xyz), &
    2926              :                                       sphi_i(:, sgfi:), sphi_j(:, sgfj:), &
    2927       370356 :                                       ncoi, ncoj, nsgfi(iset), nsgfj(jset))
    2928              : 
    2929       370356 :                      IF (trans) THEN
    2930              :                         !if transpose, then -1 factor for antisymmetry
    2931       449508 :                         ALLOCATE (dij_rs(nsgfj(jset), nsgfi(iset)))
    2932     44948634 :                         dij_rs(:, :) = -1.0_dp*TRANSPOSE(dij_contr)
    2933              :                      ELSE
    2934      1031916 :                         ALLOCATE (dij_rs(nsgfi(iset), nsgfj(jset)))
    2935     78355215 :                         dij_rs(:, :) = dij_contr
    2936              :                      END IF
    2937              : 
    2938              :                      CALL block_add("IN", dij_rs, &
    2939              :                                     nsgfi(iset), nsgfj(jset), block_t(i_xyz)%block, &
    2940       370356 :                                     sgfi, sgfj, trans=trans)
    2941       493808 :                      DEALLOCATE (dij_rs)
    2942              :                   END DO
    2943              : 
    2944       123452 :                   DEALLOCATE (dij, dij_contr)
    2945              :                END IF
    2946              :             END DO
    2947              :          END DO
    2948              :       END DO
    2949              : 
    2950          384 :       CALL cp_libint_cleanup_2eri1(lib)
    2951          384 :       CALL neighbor_list_iterator_release(nl_iterator)
    2952              : 
    2953         2880 :       DO img = 1, nimg
    2954        10368 :          DO i_xyz = 1, 3
    2955         7488 :             CALL dbcsr_finalize(t2c_der(img, i_xyz))
    2956         9984 :             CALL dbcsr_filter(t2c_der(img, i_xyz), filter_eps)
    2957              :          END DO
    2958              :       END DO
    2959              : 
    2960          384 :       CALL timestop(handle)
    2961              : 
    2962         1152 :    END SUBROUTINE build_2c_derivatives
    2963              : 
    2964              : ! **************************************************************************************************
    2965              : !> \brief Calculates the virial coming from 2c derivatives on the fly
    2966              : !> \param work_virial ...
    2967              : !> \param t2c_trace the 2c tensor that we should trace with the derivatives
    2968              : !> \param pref ...
    2969              : !> \param qs_env ...
    2970              : !> \param nl_2c 2-center neighborlist. Assumed to have compatible distribution with t2c_trace,
    2971              : !>              and to be non-symmetric
    2972              : !> \param basis_i ...
    2973              : !> \param basis_j ...
    2974              : !> \param potential_parameter ...
    2975              : ! **************************************************************************************************
    2976           12 :    SUBROUTINE calc_2c_virial(work_virial, t2c_trace, pref, qs_env, nl_2c, basis_i, basis_j, potential_parameter)
    2977              :       REAL(dp), DIMENSION(3, 3), INTENT(INOUT)           :: work_virial
    2978              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: t2c_trace
    2979              :       REAL(KIND=dp), INTENT(IN)                          :: pref
    2980              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2981              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    2982              :          POINTER                                         :: nl_2c
    2983              :       TYPE(gto_basis_set_p_type), DIMENSION(:)           :: basis_i, basis_j
    2984              :       TYPE(libint_potential_type), INTENT(IN)            :: potential_parameter
    2985              : 
    2986              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'calc_2c_virial'
    2987              : 
    2988              :       INTEGER :: handle, i_xyz, iatom, ibasis, ikind, imax, iset, j_xyz, jatom, jkind, jset, &
    2989              :          m_max, maxli, maxlj, natom, ncoi, ncoj, nseti, nsetj, op_prv, sgfi, sgfj, unit_id
    2990           12 :       INTEGER, DIMENSION(:), POINTER                     :: lmax_i, lmax_j, lmin_i, lmin_j, npgfi, &
    2991           12 :                                                             npgfj, nsgfi, nsgfj
    2992           12 :       INTEGER, DIMENSION(:, :), POINTER                  :: first_sgf_i, first_sgf_j
    2993              :       LOGICAL                                            :: do_symmetric, found
    2994              :       REAL(dp)                                           :: force
    2995           12 :       REAL(dp), DIMENSION(:, :), POINTER                 :: pblock
    2996              :       REAL(KIND=dp)                                      :: dab
    2997           12 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: dij_contr
    2998           12 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: dij
    2999              :       REAL(KIND=dp), DIMENSION(3)                        :: ri, rij, rj, scoord
    3000           12 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: set_radius_i, set_radius_j
    3001           12 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: rpgf_i, rpgf_j, sphi_i, sphi_j, zeti, &
    3002           12 :                                                             zetj
    3003           12 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    3004              :       TYPE(cell_type), POINTER                           :: cell
    3005              :       TYPE(cp_libint_t)                                  :: lib
    3006              :       TYPE(dft_control_type), POINTER                    :: dft_control
    3007              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    3008              :       TYPE(neighbor_list_iterator_p_type), &
    3009           12 :          DIMENSION(:), POINTER                           :: nl_iterator
    3010           12 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    3011           12 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    3012              : 
    3013           12 :       CALL timeset(routineN, handle)
    3014              : 
    3015           12 :       op_prv = potential_parameter%potential_type
    3016              : 
    3017           12 :       NULLIFY (qs_kind_set, atomic_kind_set, pblock, particle_set, cell)
    3018              : 
    3019              :       ! get stuff
    3020              :       CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, qs_kind_set=qs_kind_set, &
    3021              :                       natom=natom, dft_control=dft_control, para_env=para_env, &
    3022           12 :                       particle_set=particle_set, cell=cell)
    3023              : 
    3024              :       ! check for symmetry
    3025           12 :       CPASSERT(SIZE(nl_2c) > 0)
    3026           12 :       CALL get_neighbor_list_set_p(neighbor_list_sets=nl_2c, symmetric=do_symmetric)
    3027           12 :       CPASSERT(.NOT. do_symmetric)
    3028              : 
    3029           12 :       maxli = 0
    3030           36 :       DO ibasis = 1, SIZE(basis_i)
    3031           24 :          CALL get_gto_basis_set(gto_basis_set=basis_i(ibasis)%gto_basis_set, maxl=imax)
    3032           36 :          maxli = MAX(maxli, imax)
    3033              :       END DO
    3034           12 :       maxlj = 0
    3035           36 :       DO ibasis = 1, SIZE(basis_j)
    3036           24 :          CALL get_gto_basis_set(gto_basis_set=basis_j(ibasis)%gto_basis_set, maxl=imax)
    3037           36 :          maxlj = MAX(maxlj, imax)
    3038              :       END DO
    3039              : 
    3040           12 :       m_max = maxli + maxlj + 1
    3041              : 
    3042              :       !Init the truncated Coulomb operator
    3043           12 :       IF (op_prv == do_potential_truncated .OR. op_prv == do_potential_mix_cl_trunc) THEN
    3044              : 
    3045            2 :          IF (m_max > get_lmax_init()) THEN
    3046            0 :             IF (para_env%mepos == 0) THEN
    3047            0 :                CALL open_file(unit_number=unit_id, file_name=potential_parameter%filename)
    3048              :             END IF
    3049            0 :             CALL init(m_max, unit_id, para_env%mepos, para_env)
    3050            0 :             IF (para_env%mepos == 0) THEN
    3051            0 :                CALL close_file(unit_id)
    3052              :             END IF
    3053              :          END IF
    3054              :       END IF
    3055              : 
    3056           12 :       CALL init_md_ftable(nmax=m_max)
    3057              : 
    3058           12 :       CALL cp_libint_init_2eri1(lib, MAX(maxli, maxlj))
    3059           12 :       CALL cp_libint_set_contrdepth(lib, 1)
    3060              : 
    3061           12 :       CALL neighbor_list_iterator_create(nl_iterator, nl_2c)
    3062         1644 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
    3063              : 
    3064              :          CALL get_iterator_info(nl_iterator, ikind=ikind, jkind=jkind, &
    3065         1632 :                                 iatom=iatom, jatom=jatom, r=rij)
    3066              : 
    3067              :          CALL get_gto_basis_set(basis_i(ikind)%gto_basis_set, first_sgf=first_sgf_i, lmax=lmax_i, lmin=lmin_i, &
    3068              :                                 npgf=npgfi, nset=nseti, nsgf_set=nsgfi, pgf_radius=rpgf_i, set_radius=set_radius_i, &
    3069         1632 :                                 sphi=sphi_i, zet=zeti)
    3070              : 
    3071              :          CALL get_gto_basis_set(basis_j(jkind)%gto_basis_set, first_sgf=first_sgf_j, lmax=lmax_j, lmin=lmin_j, &
    3072              :                                 npgf=npgfj, nset=nsetj, nsgf_set=nsgfj, pgf_radius=rpgf_j, set_radius=set_radius_j, &
    3073         1632 :                                 sphi=sphi_j, zet=zetj)
    3074              : 
    3075         6528 :          dab = NORM2(rij)
    3076              : 
    3077         1632 :          CALL dbcsr_get_block_p(t2c_trace, iatom, jatom, pblock, found)
    3078         1632 :          IF (.NOT. found) CYCLE
    3079              : 
    3080         6113 :          DO iset = 1, nseti
    3081              : 
    3082         4469 :             ncoi = npgfi(iset)*ncoset(lmax_i(iset))
    3083         4469 :             sgfi = first_sgf_i(1, iset)
    3084              : 
    3085        25808 :             DO jset = 1, nsetj
    3086              : 
    3087        19707 :                ncoj = npgfj(jset)*ncoset(lmax_j(jset))
    3088        19707 :                sgfj = first_sgf_j(1, jset)
    3089              : 
    3090        24176 :                IF (ncoi*ncoj > 0) THEN
    3091        78828 :                   ALLOCATE (dij_contr(nsgfi(iset), nsgfj(jset)))
    3092      5728014 :                   ALLOCATE (dij(ncoi, ncoj, 3), SOURCE=0.0_dp)
    3093              : 
    3094        19707 :                   ri = 0.0_dp
    3095        19707 :                   rj = rij
    3096              : 
    3097              :                   CALL eri_2center_derivs(dij, lmin_i(iset), lmax_i(iset), npgfi(iset), zeti(:, iset), &
    3098              :                                           rpgf_i(:, iset), ri, lmin_j(jset), lmax_j(jset), npgfj(jset), zetj(:, jset), &
    3099        19707 :                                           rpgf_j(:, jset), rj, dab, lib, potential_parameter)
    3100              : 
    3101        78828 :                   DO i_xyz = 1, 3
    3102              : 
    3103      2522610 :                      dij_contr(:, :) = 0.0_dp
    3104              :                      CALL ab_contract(dij_contr, dij(:, :, i_xyz), &
    3105              :                                       sphi_i(:, sgfi:), sphi_j(:, sgfj:), &
    3106        59121 :                                       ncoi, ncoj, nsgfi(iset), nsgfj(jset))
    3107              : 
    3108      2522610 :                      force = SUM(pblock(sgfi:sgfi + nsgfi(iset) - 1, sgfj:sgfj + nsgfj(jset) - 1)*dij_contr(:, :))
    3109        59121 :                      force = pref*force
    3110              : 
    3111              :                      !iatom virial
    3112        59121 :                      CALL real_to_scaled(scoord, particle_set(iatom)%r, cell)
    3113       236484 :                      DO j_xyz = 1, 3
    3114       236484 :                         work_virial(i_xyz, j_xyz) = work_virial(i_xyz, j_xyz) + force*scoord(j_xyz)
    3115              :                      END DO
    3116              : 
    3117              :                      !jatom virial
    3118       236484 :                      CALL real_to_scaled(scoord, particle_set(iatom)%r + rij, cell)
    3119       256191 :                      DO j_xyz = 1, 3
    3120       236484 :                         work_virial(i_xyz, j_xyz) = work_virial(i_xyz, j_xyz) - force*scoord(j_xyz)
    3121              :                      END DO
    3122              :                   END DO
    3123              : 
    3124        19707 :                   DEALLOCATE (dij, dij_contr)
    3125              :                END IF
    3126              :             END DO
    3127              :          END DO
    3128              :       END DO
    3129              : 
    3130           12 :       CALL neighbor_list_iterator_release(nl_iterator)
    3131           12 :       CALL cp_libint_cleanup_2eri1(lib)
    3132              : 
    3133           12 :       CALL timestop(handle)
    3134              : 
    3135           24 :    END SUBROUTINE calc_2c_virial
    3136              : 
    3137              : ! **************************************************************************************************
    3138              : !> \brief ...
    3139              : !> \param t2c empty DBCSR matrix
    3140              : !> \param filter_eps Filter threshold for matrix blocks
    3141              : !> \param qs_env ...
    3142              : !> \param nl_2c 2-center neighborlist
    3143              : !> \param basis_i ...
    3144              : !> \param basis_j ...
    3145              : !> \param potential_parameter ...
    3146              : !> \param do_kpoints ...
    3147              : !> \param do_hfx_kpoints ...
    3148              : !> this routine requires that libint has been static initialised somewhere else
    3149              : !> \param ext_kpoints ...
    3150              : !> \param regularization_RI ...
    3151              : ! **************************************************************************************************
    3152          882 :    SUBROUTINE build_2c_integrals(t2c, filter_eps, qs_env, &
    3153          882 :                                  nl_2c, basis_i, basis_j, &
    3154              :                                  potential_parameter, do_kpoints, &
    3155              :                                  do_hfx_kpoints, ext_kpoints, regularization_RI)
    3156              : 
    3157              :       TYPE(dbcsr_type), DIMENSION(:), INTENT(INOUT)      :: t2c
    3158              :       REAL(KIND=dp), INTENT(IN)                          :: filter_eps
    3159              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    3160              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    3161              :          POINTER                                         :: nl_2c
    3162              :       TYPE(gto_basis_set_p_type), DIMENSION(:)           :: basis_i, basis_j
    3163              :       TYPE(libint_potential_type), INTENT(IN)            :: potential_parameter
    3164              :       LOGICAL, INTENT(IN), OPTIONAL                      :: do_kpoints, do_hfx_kpoints
    3165              :       TYPE(kpoint_type), OPTIONAL, POINTER               :: ext_kpoints
    3166              :       REAL(KIND=dp), OPTIONAL                            :: regularization_RI
    3167              : 
    3168              :       CHARACTER(len=*), PARAMETER :: routineN = 'build_2c_integrals'
    3169              : 
    3170              :       INTEGER :: handle, i_diag, iatom, ibasis, icol, ikind, imax, img, irow, iset, jatom, jkind, &
    3171              :          jset, m_max, maxli, maxlj, natom, ncoi, ncoj, nimg, nseti, nsetj, op_prv, sgfi, sgfj, &
    3172              :          unit_id
    3173              :       INTEGER, DIMENSION(3)                              :: cell_j, kp_index_lbounds, &
    3174              :                                                             kp_index_ubounds
    3175          882 :       INTEGER, DIMENSION(:), POINTER                     :: lmax_i, lmax_j, lmin_i, lmin_j, npgfi, &
    3176          882 :                                                             npgfj, nsgfi, nsgfj
    3177          882 :       INTEGER, DIMENSION(:, :), POINTER                  :: first_sgf_i, first_sgf_j
    3178          882 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
    3179              :       LOGICAL                                            :: do_hfx_kpoints_prv, do_kpoints_prv, &
    3180              :                                                             do_symmetric, found, trans
    3181              :       REAL(KIND=dp)                                      :: dab, min_zet
    3182          882 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: sij, sij_contr, sij_rs
    3183              :       REAL(KIND=dp), DIMENSION(3)                        :: ri, rij, rj
    3184          882 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: set_radius_i, set_radius_j
    3185          882 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: rpgf_i, rpgf_j, sphi_i, sphi_j, zeti, &
    3186          882 :                                                             zetj
    3187          882 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    3188              :       TYPE(block_p_type)                                 :: block_t
    3189              :       TYPE(cell_type), POINTER                           :: cell
    3190              :       TYPE(cp_libint_t)                                  :: lib
    3191              :       TYPE(dft_control_type), POINTER                    :: dft_control
    3192              :       TYPE(kpoint_type), POINTER                         :: kpoints
    3193              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    3194              :       TYPE(neighbor_list_iterator_p_type), &
    3195          882 :          DIMENSION(:), POINTER                           :: nl_iterator
    3196          882 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    3197              : 
    3198          882 :       CALL timeset(routineN, handle)
    3199              : 
    3200          882 :       IF (PRESENT(do_kpoints)) THEN
    3201          832 :          do_kpoints_prv = do_kpoints
    3202              :       ELSE
    3203              :          do_kpoints_prv = .FALSE.
    3204              :       END IF
    3205              : 
    3206          882 :       IF (PRESENT(do_hfx_kpoints)) THEN
    3207          302 :          do_hfx_kpoints_prv = do_hfx_kpoints
    3208              :       ELSE
    3209              :          do_hfx_kpoints_prv = .FALSE.
    3210              :       END IF
    3211          302 :       IF (do_hfx_kpoints_prv) THEN
    3212          160 :          CPASSERT(do_kpoints_prv)
    3213              :       END IF
    3214              : 
    3215          882 :       op_prv = potential_parameter%potential_type
    3216              : 
    3217          882 :       NULLIFY (qs_kind_set, atomic_kind_set, block_t%block, cell_to_index)
    3218              : 
    3219              :       ! get stuff
    3220              :       CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, qs_kind_set=qs_kind_set, cell=cell, &
    3221          882 :                       natom=natom, dft_control=dft_control, para_env=para_env, kpoints=kpoints)
    3222              : 
    3223          882 :       IF (PRESENT(ext_kpoints)) kpoints => ext_kpoints
    3224              : 
    3225          882 :       IF (do_kpoints_prv) THEN
    3226          464 :          nimg = SIZE(t2c)
    3227          464 :          CALL get_kpoint_info(kpoints, cell_to_index=cell_to_index)
    3228         1856 :          kp_index_lbounds = LBOUND(cell_to_index)
    3229         1856 :          kp_index_ubounds = UBOUND(cell_to_index)
    3230              :       ELSE
    3231              :          nimg = 1
    3232              :       END IF
    3233              : 
    3234              :       ! check for symmetry
    3235          882 :       CPASSERT(SIZE(nl_2c) > 0)
    3236          882 :       CALL get_neighbor_list_set_p(neighbor_list_sets=nl_2c, symmetric=do_symmetric)
    3237              : 
    3238          882 :       IF (do_symmetric) THEN
    3239         2154 :          DO img = 1, nimg
    3240         2154 :             CPASSERT(dbcsr_has_symmetry(t2c(img)))
    3241              :          END DO
    3242              :       ELSE
    3243         4884 :          DO img = 1, nimg
    3244         4884 :             CPASSERT(.NOT. dbcsr_has_symmetry(t2c(img)))
    3245              :          END DO
    3246              :       END IF
    3247              : 
    3248         7038 :       DO img = 1, nimg
    3249         7038 :          CALL cp_dbcsr_alloc_block_from_nbl(t2c(img), nl_2c)
    3250              :       END DO
    3251              : 
    3252          882 :       maxli = 0
    3253         2470 :       DO ibasis = 1, SIZE(basis_i)
    3254         1588 :          CALL get_gto_basis_set(gto_basis_set=basis_i(ibasis)%gto_basis_set, maxl=imax)
    3255         2470 :          maxli = MAX(maxli, imax)
    3256              :       END DO
    3257          882 :       maxlj = 0
    3258         2470 :       DO ibasis = 1, SIZE(basis_j)
    3259         1588 :          CALL get_gto_basis_set(gto_basis_set=basis_j(ibasis)%gto_basis_set, maxl=imax)
    3260         2470 :          maxlj = MAX(maxlj, imax)
    3261              :       END DO
    3262              : 
    3263          882 :       m_max = maxli + maxlj
    3264              : 
    3265              :       !Init the truncated Coulomb operator
    3266          882 :       IF (op_prv == do_potential_truncated .OR. op_prv == do_potential_mix_cl_trunc) THEN
    3267              : 
    3268          544 :          IF (m_max > get_lmax_init()) THEN
    3269          106 :             IF (para_env%mepos == 0) THEN
    3270           53 :                CALL open_file(unit_number=unit_id, file_name=potential_parameter%filename)
    3271              :             END IF
    3272          106 :             CALL init(m_max, unit_id, para_env%mepos, para_env)
    3273          106 :             IF (para_env%mepos == 0) THEN
    3274           53 :                CALL close_file(unit_id)
    3275              :             END IF
    3276              :          END IF
    3277              :       END IF
    3278              : 
    3279          882 :       CALL init_md_ftable(nmax=m_max)
    3280              : 
    3281          882 :       CALL cp_libint_init_2eri(lib, MAX(maxli, maxlj))
    3282          882 :       CALL cp_libint_set_contrdepth(lib, 1)
    3283              : 
    3284          882 :       CALL neighbor_list_iterator_create(nl_iterator, nl_2c)
    3285        29975 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
    3286              : 
    3287              :          CALL get_iterator_info(nl_iterator, ikind=ikind, jkind=jkind, &
    3288        29093 :                                 iatom=iatom, jatom=jatom, r=rij, cell=cell_j)
    3289        29093 :          IF (do_kpoints_prv) THEN
    3290        37009 :             IF (ANY([cell_j(1), cell_j(2), cell_j(3)] < kp_index_lbounds) .OR. &
    3291              :                 ANY([cell_j(1), cell_j(2), cell_j(3)] > kp_index_ubounds)) CYCLE
    3292         5247 :             img = cell_to_index(cell_j(1), cell_j(2), cell_j(3))
    3293         5247 :             IF (img > nimg .OR. img < 1) CYCLE
    3294              :          ELSE
    3295              :             img = 1
    3296              :          END IF
    3297              : 
    3298              :          CALL get_gto_basis_set(basis_i(ikind)%gto_basis_set, first_sgf=first_sgf_i, lmax=lmax_i, lmin=lmin_i, &
    3299              :                                 npgf=npgfi, nset=nseti, nsgf_set=nsgfi, pgf_radius=rpgf_i, set_radius=set_radius_i, &
    3300        28985 :                                 sphi=sphi_i, zet=zeti)
    3301              : 
    3302              :          CALL get_gto_basis_set(basis_j(jkind)%gto_basis_set, first_sgf=first_sgf_j, lmax=lmax_j, lmin=lmin_j, &
    3303              :                                 npgf=npgfj, nset=nsetj, nsgf_set=nsgfj, pgf_radius=rpgf_j, set_radius=set_radius_j, &
    3304        28985 :                                 sphi=sphi_j, zet=zetj)
    3305              : 
    3306        28985 :          IF (do_symmetric) THEN
    3307        25105 :             IF (iatom <= jatom) THEN
    3308        14962 :                irow = iatom
    3309        14962 :                icol = jatom
    3310              :             ELSE
    3311        10143 :                irow = jatom
    3312        10143 :                icol = iatom
    3313              :             END IF
    3314              :          ELSE
    3315         3880 :             irow = iatom
    3316         3880 :             icol = jatom
    3317              :          END IF
    3318              : 
    3319       115940 :          dab = NORM2(rij)
    3320              : 
    3321              :          CALL dbcsr_get_block_p(matrix=t2c(img), &
    3322        28985 :                                 row=irow, col=icol, BLOCK=block_t%block, found=found)
    3323        28985 :          CPASSERT(found)
    3324        28985 :          trans = do_symmetric .AND. (iatom > jatom)
    3325              : 
    3326       110025 :          DO iset = 1, nseti
    3327              : 
    3328        80158 :             ncoi = npgfi(iset)*ncoset(lmax_i(iset))
    3329        80158 :             sgfi = first_sgf_i(1, iset)
    3330              : 
    3331       507394 :             DO jset = 1, nsetj
    3332              : 
    3333       398195 :                ncoj = npgfj(jset)*ncoset(lmax_j(jset))
    3334       398195 :                sgfj = first_sgf_j(1, jset)
    3335              : 
    3336       478353 :                IF (ncoi*ncoj > 0) THEN
    3337     80841058 :                   ALLOCATE (sij_contr(nsgfi(iset), nsgfj(jset)), SOURCE=0.0_dp)
    3338    207189999 :                   ALLOCATE (sij(ncoi, ncoj), SOURCE=0.0_dp)
    3339              : 
    3340       398195 :                   ri = 0.0_dp
    3341       398195 :                   rj = rij
    3342              : 
    3343              :                   CALL eri_2center(sij, lmin_i(iset), lmax_i(iset), npgfi(iset), zeti(:, iset), &
    3344              :                                    rpgf_i(:, iset), ri, lmin_j(jset), lmax_j(jset), npgfj(jset), zetj(:, jset), &
    3345       398195 :                                    rpgf_j(:, jset), rj, dab, lib, potential_parameter)
    3346              : 
    3347              :                   CALL ab_contract(sij_contr, sij, &
    3348              :                                    sphi_i(:, sgfi:), sphi_j(:, sgfj:), &
    3349       398195 :                                    ncoi, ncoj, nsgfi(iset), nsgfj(jset))
    3350              : 
    3351       398195 :                   DEALLOCATE (sij)
    3352       398195 :                   IF (trans) THEN
    3353       492840 :                      ALLOCATE (sij_rs(nsgfj(jset), nsgfi(iset)))
    3354     30206681 :                      sij_rs(:, :) = TRANSPOSE(sij_contr)
    3355              :                   ELSE
    3356      1099940 :                      ALLOCATE (sij_rs(nsgfi(iset), nsgfj(jset)))
    3357     49354022 :                      sij_rs(:, :) = sij_contr
    3358              :                   END IF
    3359              : 
    3360       398195 :                   DEALLOCATE (sij_contr)
    3361              : 
    3362              :                   ! RI regularization
    3363              :                   IF (.NOT. do_hfx_kpoints_prv .AND. PRESENT(regularization_RI) .AND. &
    3364              :                       iatom == jatom .AND. iset == jset .AND. &
    3365       398195 :                       cell_j(1) == 0 .AND. cell_j(2) == 0 .AND. cell_j(3) == 0) THEN
    3366        11990 :                      DO i_diag = 1, nsgfi(iset)
    3367        26016 :                         min_zet = MINVAL(zeti(:, iset))
    3368         8672 :                         CPASSERT(min_zet > 1.0E-10_dp)
    3369              :                         sij_rs(i_diag, i_diag) = sij_rs(i_diag, i_diag) + &
    3370        11990 :                                                  regularization_RI*MAX(1.0_dp, 1.0_dp/min_zet)
    3371              :                      END DO
    3372              :                   END IF
    3373              : 
    3374              :                   CALL block_add("IN", sij_rs, &
    3375              :                                  nsgfi(iset), nsgfj(jset), block_t%block, &
    3376       398195 :                                  sgfi, sgfj, trans=trans)
    3377       398195 :                   DEALLOCATE (sij_rs)
    3378              : 
    3379              :                END IF
    3380              :             END DO
    3381              :          END DO
    3382              :       END DO
    3383              : 
    3384          882 :       CALL cp_libint_cleanup_2eri(lib)
    3385              : 
    3386          882 :       CALL neighbor_list_iterator_release(nl_iterator)
    3387         7038 :       DO img = 1, nimg
    3388         6156 :          CALL dbcsr_finalize(t2c(img))
    3389         7038 :          CALL dbcsr_filter(t2c(img), filter_eps)
    3390              :       END DO
    3391              : 
    3392          882 :       CALL timestop(handle)
    3393              : 
    3394         1764 :    END SUBROUTINE build_2c_integrals
    3395              : 
    3396              : ! **************************************************************************************************
    3397              : !> \brief ...
    3398              : !> \param tensor tensor with data. Data is cleared after compression.
    3399              : !> \param blk_indices ...
    3400              : !> \param compressed compressed tensor data
    3401              : !> \param eps all entries < eps are discarded
    3402              : !> \param memory ...
    3403              : ! **************************************************************************************************
    3404        22202 :    SUBROUTINE compress_tensor(tensor, blk_indices, compressed, eps, memory)
    3405              :       TYPE(dbt_type), INTENT(INOUT)                      :: tensor
    3406              :       INTEGER, ALLOCATABLE, DIMENSION(:, :), &
    3407              :          INTENT(INOUT)                                   :: blk_indices
    3408              :       TYPE(hfx_compression_type), INTENT(INOUT)          :: compressed
    3409              :       REAL(dp), INTENT(IN)                               :: eps
    3410              :       REAL(dp), INTENT(INOUT)                            :: memory
    3411              : 
    3412              :       INTEGER                                            :: buffer_left, buffer_size, buffer_start, &
    3413              :                                                             i, iblk, memory_usage, nbits, nblk, &
    3414              :                                                             nints, offset, shared_offset
    3415              :       INTEGER(int_8)                                     :: estimate_to_store_int, &
    3416              :                                                             storage_counter_integrals
    3417              :       INTEGER, DIMENSION(3)                              :: ind
    3418              :       LOGICAL                                            :: found
    3419              :       REAL(dp)                                           :: spherical_estimate
    3420        22202 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :, :), TARGET  :: blk_data
    3421        22202 :       REAL(dp), DIMENSION(:), POINTER                    :: blk_data_1d
    3422              :       TYPE(dbt_iterator_type)                            :: iter
    3423        22202 :       TYPE(hfx_cache_type), DIMENSION(:), POINTER        :: integral_caches
    3424              :       TYPE(hfx_cache_type), POINTER                      :: maxval_cache
    3425        22202 :       TYPE(hfx_container_type), DIMENSION(:), POINTER    :: integral_containers
    3426              :       TYPE(hfx_container_type), POINTER                  :: maxval_container
    3427              : 
    3428        22202 :       CALL dealloc_containers(compressed, memory_usage)
    3429        22202 :       CALL alloc_containers(compressed, 1)
    3430              : 
    3431        22202 :       maxval_container => compressed%maxval_container(1)
    3432        22202 :       integral_containers => compressed%integral_containers(:, 1)
    3433              : 
    3434        22202 :       CALL hfx_init_container(maxval_container, memory_usage, .FALSE.)
    3435      1443130 :       DO i = 1, 64
    3436      1443130 :          CALL hfx_init_container(integral_containers(i), memory_usage, .FALSE.)
    3437              :       END DO
    3438              : 
    3439        22202 :       maxval_cache => compressed%maxval_cache(1)
    3440        22202 :       integral_caches => compressed%integral_caches(:, 1)
    3441              : 
    3442        22202 :       IF (ALLOCATED(blk_indices)) DEALLOCATE (blk_indices)
    3443        59132 :       ALLOCATE (blk_indices(dbt_get_num_blocks(tensor), 3))
    3444        22202 :       shared_offset = 0
    3445              : !$OMP PARALLEL DEFAULT(NONE) SHARED(tensor,blk_indices,shared_offset) &
    3446        22202 : !$OMP PRIVATE(iter,ind,offset,nblk,iblk)
    3447              :       CALL dbt_iterator_start(iter, tensor)
    3448              :       nblk = dbt_iterator_num_blocks(iter)
    3449              : !$OMP CRITICAL(qs_tensors_offset)
    3450              :       offset = shared_offset
    3451              :       shared_offset = shared_offset + nblk
    3452              : !$OMP END CRITICAL(qs_tensors_offset)
    3453              :       DO iblk = 1, nblk
    3454              :          CALL dbt_iterator_next_block(iter, ind)
    3455              :          blk_indices(offset + iblk, :) = ind(:)
    3456              :       END DO
    3457              :       CALL dbt_iterator_stop(iter)
    3458              : !$OMP END PARALLEL
    3459              : 
    3460              :       ! Can not use the tensor iterator here because the order of the blocks is not guaranteed.
    3461       449765 :       DO i = 1, SIZE(blk_indices, 1)
    3462      1710252 :          ind = blk_indices(i, :)
    3463       427563 :          CALL dbt_get_block(tensor, ind, blk_data, found)
    3464       427563 :          CPASSERT(found)
    3465      1710252 :          nints = SIZE(blk_data)
    3466       427563 :          blk_data_1d(1:nints) => blk_data
    3467    225399711 :          spherical_estimate = MAXVAL(ABS(blk_data_1d))
    3468       427563 :          IF (spherical_estimate == 0.0_dp) spherical_estimate = TINY(spherical_estimate)
    3469       427563 :          estimate_to_store_int = EXPONENT(spherical_estimate)
    3470       427563 :          estimate_to_store_int = MAX(estimate_to_store_int, -15_int_8)
    3471              : 
    3472              :          CALL hfx_add_single_cache_element(estimate_to_store_int, 6, &
    3473              :                                            maxval_cache, maxval_container, memory_usage, &
    3474       427563 :                                            .FALSE.)
    3475              : 
    3476       427563 :          spherical_estimate = SET_EXPONENT(1.0_dp, estimate_to_store_int + 1)
    3477              : 
    3478       427563 :          nbits = EXPONENT(ANINT(spherical_estimate/eps)) + 1
    3479       427563 :          IF (nbits > 64) THEN
    3480              :             CALL cp_abort(__LOCATION__, &
    3481            0 :                           "Overflow during tensor compression. Please use a larger EPS_FILTER or EPS_STORAGE_SCALING")
    3482              :          END IF
    3483              : 
    3484              :          buffer_left = nints
    3485              :          buffer_start = 1
    3486              : 
    3487       953780 :          DO WHILE (buffer_left > 0)
    3488       526217 :             buffer_size = MIN(buffer_left, cache_size)
    3489              :             CALL hfx_add_mult_cache_elements(blk_data_1d(buffer_start:), &
    3490              :                                              buffer_size, nbits, &
    3491              :                                              integral_caches(nbits), &
    3492              :                                              integral_containers(nbits), &
    3493              :                                              eps, 1.0_dp, &
    3494              :                                              memory_usage, &
    3495       526217 :                                              .FALSE.)
    3496       526217 :             buffer_left = buffer_left - buffer_size
    3497       526217 :             buffer_start = buffer_start + buffer_size
    3498              :          END DO
    3499              : 
    3500       877328 :          NULLIFY (blk_data_1d); DEALLOCATE (blk_data)
    3501              :       END DO
    3502              : 
    3503        22202 :       CALL dbt_clear(tensor)
    3504              : 
    3505        22202 :       storage_counter_integrals = memory_usage*cache_size
    3506        22202 :       memory = memory + REAL(storage_counter_integrals, dp)/1024/128
    3507              :       !WRITE (UNIT=iw, FMT="((T3,A,T60,I21))") &
    3508              :       !   "HFX_MEM_INFO| Total memory consumption ERI's RAM [MiB]:            ", memory
    3509              : 
    3510              :       CALL hfx_flush_last_cache(6, maxval_cache, maxval_container, memory_usage, &
    3511        22202 :                                 .FALSE.)
    3512      1443130 :       DO i = 1, 64
    3513              :          CALL hfx_flush_last_cache(i, integral_caches(i), integral_containers(i), &
    3514      1443130 :                                    memory_usage, .FALSE.)
    3515              :       END DO
    3516              : 
    3517        22202 :       CALL hfx_reset_cache_and_container(maxval_cache, maxval_container, memory_usage, .FALSE.)
    3518      1443130 :       DO i = 1, 64
    3519              :          CALL hfx_reset_cache_and_container(integral_caches(i), integral_containers(i), &
    3520      1443130 :                                             memory_usage, .FALSE.)
    3521              :       END DO
    3522              : 
    3523        44404 :    END SUBROUTINE compress_tensor
    3524              : 
    3525              : ! **************************************************************************************************
    3526              : !> \brief ...
    3527              : !> \param tensor empty tensor which is filled by decompressed data
    3528              : !> \param blk_indices indices of blocks to be reserved
    3529              : !> \param compressed compressed data
    3530              : !> \param eps all entries < eps are discarded
    3531              : ! **************************************************************************************************
    3532        63866 :    SUBROUTINE decompress_tensor(tensor, blk_indices, compressed, eps)
    3533              : 
    3534              :       TYPE(dbt_type), INTENT(INOUT)                      :: tensor
    3535              :       INTEGER, DIMENSION(:, :)                           :: blk_indices
    3536              :       TYPE(hfx_compression_type), INTENT(INOUT)          :: compressed
    3537              :       REAL(dp), INTENT(IN)                               :: eps
    3538              : 
    3539              :       INTEGER                                            :: A, b, buffer_left, buffer_size, &
    3540              :                                                             buffer_start, i, memory_usage, nbits, &
    3541              :                                                             nblk_per_thread, nints
    3542              :       INTEGER(int_8)                                     :: estimate_to_store_int
    3543              :       INTEGER, DIMENSION(3)                              :: blk_size, ind
    3544              :       REAL(dp)                                           :: spherical_estimate
    3545        63866 :       REAL(dp), ALLOCATABLE, DIMENSION(:), TARGET        :: blk_data
    3546        63866 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: blk_data_3d
    3547        63866 :       TYPE(hfx_cache_type), DIMENSION(:), POINTER        :: integral_caches
    3548              :       TYPE(hfx_cache_type), POINTER                      :: maxval_cache
    3549        63866 :       TYPE(hfx_container_type), DIMENSION(:), POINTER    :: integral_containers
    3550              :       TYPE(hfx_container_type), POINTER                  :: maxval_container
    3551              : 
    3552        63866 :       maxval_cache => compressed%maxval_cache(1)
    3553        63866 :       maxval_container => compressed%maxval_container(1)
    3554        63866 :       integral_caches => compressed%integral_caches(:, 1)
    3555        63866 :       integral_containers => compressed%integral_containers(:, 1)
    3556              : 
    3557        63866 :       memory_usage = 0
    3558              : 
    3559        63866 :       CALL hfx_decompress_first_cache(6, maxval_cache, maxval_container, memory_usage, .FALSE.)
    3560              : 
    3561      4151290 :       DO i = 1, 64
    3562              :          CALL hfx_decompress_first_cache(i, integral_caches(i), integral_containers(i), &
    3563      4151290 :                                          memory_usage, .FALSE.)
    3564              :       END DO
    3565              : 
    3566              : !TODO: Parallelize creation of block list.
    3567        63866 : !$OMP PARALLEL DEFAULT(NONE) SHARED(tensor,blk_indices) PRIVATE(nblk_per_thread,A,b)
    3568              :       nblk_per_thread = SIZE(blk_indices, 1)/omp_get_num_threads() + 1
    3569              :       a = omp_get_thread_num()*nblk_per_thread + 1
    3570              :       b = MIN(a + nblk_per_thread, SIZE(blk_indices, 1))
    3571              :       CALL dbt_reserve_blocks(tensor, blk_indices(a:b, :))
    3572              : !$OMP END PARALLEL
    3573              : 
    3574              :       ! Can not use the tensor iterator here because the order of the blocks is not guaranteed.
    3575      1527616 :       DO i = 1, SIZE(blk_indices, 1)
    3576      5855000 :          ind = blk_indices(i, :)
    3577      1463750 :          CALL dbt_blk_sizes(tensor, ind, blk_size)
    3578      5855000 :          nints = PRODUCT(blk_size)
    3579              :          CALL hfx_get_single_cache_element( &
    3580              :             estimate_to_store_int, 6, &
    3581              :             maxval_cache, maxval_container, memory_usage, &
    3582      1463750 :             .FALSE.)
    3583              : 
    3584      1463750 :          spherical_estimate = SET_EXPONENT(1.0_dp, estimate_to_store_int + 1)
    3585              : 
    3586      1463750 :          nbits = EXPONENT(ANINT(spherical_estimate/eps)) + 1
    3587              : 
    3588      1463750 :          buffer_left = nints
    3589      1463750 :          buffer_start = 1
    3590              : 
    3591      4391250 :          ALLOCATE (blk_data(nints))
    3592      3122039 :          DO WHILE (buffer_left > 0)
    3593      1658289 :             buffer_size = MIN(buffer_left, cache_size)
    3594              :             CALL hfx_get_mult_cache_elements(blk_data(buffer_start), &
    3595              :                                              buffer_size, nbits, &
    3596              :                                              integral_caches(nbits), &
    3597              :                                              integral_containers(nbits), &
    3598              :                                              eps, 1.0_dp, &
    3599              :                                              memory_usage, &
    3600      1658289 :                                              .FALSE.)
    3601      1658289 :             buffer_left = buffer_left - buffer_size
    3602      1658289 :             buffer_start = buffer_start + buffer_size
    3603              :          END DO
    3604              : 
    3605      1463750 :          blk_data_3d(1:blk_size(1), 1:blk_size(2), 1:blk_size(3)) => blk_data
    3606      1463750 :          CALL dbt_put_block(tensor, ind, blk_size, blk_data_3d)
    3607      1527616 :          NULLIFY (blk_data_3d); DEALLOCATE (blk_data)
    3608              :       END DO
    3609              : 
    3610        63866 :       CALL hfx_reset_cache_and_container(maxval_cache, maxval_container, memory_usage, .FALSE.)
    3611      4151290 :       DO i = 1, 64
    3612              :          CALL hfx_reset_cache_and_container(integral_caches(i), integral_containers(i), &
    3613      4151290 :                                             memory_usage, .FALSE.)
    3614              :       END DO
    3615       127732 :    END SUBROUTINE decompress_tensor
    3616              : 
    3617              : ! **************************************************************************************************
    3618              : !> \brief ...
    3619              : !> \param tensor ...
    3620              : !> \param nze ...
    3621              : !> \param occ ...
    3622              : ! **************************************************************************************************
    3623       139344 :    SUBROUTINE get_tensor_occupancy(tensor, nze, occ)
    3624              :       TYPE(dbt_type), INTENT(IN)                         :: tensor
    3625              :       INTEGER(int_8), INTENT(OUT)                        :: nze
    3626              :       REAL(dp), INTENT(OUT)                              :: occ
    3627              : 
    3628       278688 :       INTEGER, DIMENSION(dbt_ndims(tensor))              :: dims
    3629              : 
    3630       139344 :       nze = dbt_get_nze_total(tensor)
    3631       139344 :       CALL dbt_get_info(tensor, nfull_total=dims)
    3632       529578 :       occ = REAL(nze, dp)/PRODUCT(REAL(dims, dp))
    3633              : 
    3634       139344 :    END SUBROUTINE get_tensor_occupancy
    3635              : 
    3636            0 : END MODULE qs_tensors
        

Generated by: LCOV version 2.0-1