LCOV - code coverage report
Current view: top level - src - qs_tensors.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:aeba166) Lines: 1100 1264 87.0 %
Date: 2024-05-04 06:51:03 Functions: 19 22 86.4 %

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

Generated by: LCOV version 1.15