LCOV - code coverage report
Current view: top level - src - kpoint_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:24d69ee) Lines: 79.4 % 1672 1328
Test Date: 2026-09-03 07:32:15 Functions: 68.6 % 35 24

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Routines needed for kpoint calculation
      10              : !> \par History
      11              : !>       2014.07 created [JGH]
      12              : !>       2014.11 unified k-point and gamma-point code [Ole Schuett]
      13              : !> \author JGH
      14              : ! **************************************************************************************************
      15              : MODULE kpoint_methods
      16              :    USE atomic_kind_types,               ONLY: get_atomic_kind
      17              :    USE cell_types,                      ONLY: cell_type,&
      18              :                                               pbc_stable,&
      19              :                                               real_to_scaled
      20              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_create,&
      21              :                                               cp_blacs_env_type
      22              :    USE cp_cfm_basic_linalg,             ONLY: cp_cfm_column_scale,&
      23              :                                               cp_cfm_gemm,&
      24              :                                               cp_cfm_scale_and_add,&
      25              :                                               cp_cfm_transpose
      26              :    USE cp_cfm_types,                    ONLY: cp_cfm_create,&
      27              :                                               cp_cfm_get_info,&
      28              :                                               cp_cfm_release,&
      29              :                                               cp_cfm_to_fm,&
      30              :                                               cp_cfm_type,&
      31              :                                               cp_fm_to_cfm
      32              :    USE cp_control_types,                ONLY: hairy_probes_type
      33              :    USE cp_dbcsr_api,                    ONLY: &
      34              :         dbcsr_copy, dbcsr_create, dbcsr_deallocate_matrix, dbcsr_distribute, &
      35              :         dbcsr_distribution_get, dbcsr_distribution_type, dbcsr_get_block_p, dbcsr_get_info, &
      36              :         dbcsr_get_readonly_block_p, dbcsr_get_stored_coordinates, dbcsr_iterator_blocks_left, &
      37              :         dbcsr_iterator_next_block, dbcsr_iterator_readonly_start, dbcsr_iterator_start, &
      38              :         dbcsr_iterator_stop, dbcsr_iterator_type, dbcsr_p_type, dbcsr_replicate_all, dbcsr_set, &
      39              :         dbcsr_type, dbcsr_type_antisymmetric, dbcsr_type_no_symmetry, dbcsr_type_symmetric
      40              :    USE cp_dbcsr_contrib,                ONLY: dbcsr_dot
      41              :    USE cp_dbcsr_cp2k_link,              ONLY: cp_dbcsr_alloc_block_from_nbl
      42              :    USE cp_dbcsr_operations,             ONLY: copy_fm_to_dbcsr,&
      43              :                                               cp_dbcsr_sm_fm_multiply
      44              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_column_scale
      45              :    USE cp_fm_pool_types,                ONLY: cp_fm_pool_p_type,&
      46              :                                               fm_pool_create_fm,&
      47              :                                               fm_pool_give_back_fm
      48              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_type
      49              :    USE cp_fm_types,                     ONLY: &
      50              :         copy_info_type, cp_fm_cleanup_copy_general, cp_fm_create, cp_fm_finish_copy_general, &
      51              :         cp_fm_get_diag, cp_fm_get_info, cp_fm_get_submatrix, cp_fm_release, &
      52              :         cp_fm_start_copy_general, cp_fm_to_fm, cp_fm_type
      53              :    USE cp_log_handling,                 ONLY: cp_logger_get_default_io_unit
      54              :    USE cryssym,                         ONLY: crys_sym_gen,&
      55              :                                               csym_type,&
      56              :                                               kpoint_gen,&
      57              :                                               kpoint_gen_general,&
      58              :                                               print_crys_symmetry,&
      59              :                                               print_kp_symmetry,&
      60              :                                               release_csym_type
      61              :    USE hairy_probes,                    ONLY: probe_occupancy_kp
      62              :    USE input_constants,                 ONLY: smear_fermi_dirac,&
      63              :                                               smear_gaussian,&
      64              :                                               smear_mp,&
      65              :                                               smear_mv
      66              :    USE input_cp2k_kpoints,              ONLY: use_spglib_kpoint_backend,&
      67              :                                               use_spglib_kpoint_symmetry
      68              :    USE kinds,                           ONLY: dp,&
      69              :                                               int_8
      70              :    USE kpoint_lattice_fft,              ONLY: cell_to_k_grid_fft,&
      71              :                                               regular_kpoint_grid
      72              :    USE kpoint_types,                    ONLY: get_kpoint_info,&
      73              :                                               kind_rotmat_type,&
      74              :                                               kpoint_env_create,&
      75              :                                               kpoint_env_p_type,&
      76              :                                               kpoint_env_type,&
      77              :                                               kpoint_sym_create,&
      78              :                                               kpoint_sym_type,&
      79              :                                               kpoint_type
      80              :    USE mathconstants,                   ONLY: twopi
      81              :    USE mathlib,                         ONLY: inv_3x3
      82              :    USE memory_utilities,                ONLY: reallocate
      83              :    USE message_passing,                 ONLY: mp_cart_type,&
      84              :                                               mp_para_env_type
      85              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      86              :    USE particle_types,                  ONLY: particle_type
      87              :    USE qs_matrix_pools,                 ONLY: mpools_create,&
      88              :                                               mpools_get,&
      89              :                                               mpools_rebuild_fm_pools,&
      90              :                                               qs_matrix_pools_type
      91              :    USE qs_mo_types,                     ONLY: allocate_mo_set,&
      92              :                                               get_mo_set,&
      93              :                                               init_mo_set,&
      94              :                                               mo_set_type,&
      95              :                                               set_mo_set
      96              :    USE qs_neighbor_list_types,          ONLY: get_iterator_info,&
      97              :                                               get_neighbor_list_set_p,&
      98              :                                               neighbor_list_iterate,&
      99              :                                               neighbor_list_iterator_create,&
     100              :                                               neighbor_list_iterator_p_type,&
     101              :                                               neighbor_list_iterator_release,&
     102              :                                               neighbor_list_set_p_type
     103              :    USE scf_control_types,               ONLY: smear_type
     104              :    USE smearing_utils,                  ONLY: Smearkp,&
     105              :                                               Smearkp2
     106              :    USE util,                            ONLY: get_limit,&
     107              :                                               sort
     108              : 
     109              : !$ USE OMP_LIB, ONLY: omp_get_max_threads, &
     110              : !$                    omp_get_thread_num
     111              : #include "./base/base_uses.f90"
     112              : 
     113              :    IMPLICIT NONE
     114              : 
     115              :    PRIVATE
     116              : 
     117              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'kpoint_methods'
     118              : 
     119              :    TYPE, PUBLIC :: kp_transform_plan_type
     120              :       INTEGER :: nentry = 0, ngroup = 0
     121              :       LOGICAL :: symmetric = .FALSE.
     122              :       INTEGER, ALLOCATABLE, DIMENSION(:) :: col, col_offset, group_start, image, row, row_offset
     123              :       INTEGER, ALLOCATABLE, DIMENSION(:, :) :: cell
     124              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: symmetry_sign
     125              :    END TYPE kp_transform_plan_type
     126              : 
     127              :    PUBLIC :: kpoint_initialize, kpoint_env_initialize, kpoint_initialize_mos, kpoint_initialize_mo_set
     128              :    PUBLIC :: kpoint_init_cell_index, kpoint_set_mo_occupation
     129              :    PUBLIC :: kpoint_smearing_edge_status
     130              :    PUBLIC :: kpoint_density_matrices, kpoint_density_transform
     131              :    PUBLIC :: kpoint_ot_energy_weighted_density, kpoint_ot_energy_weighted_matrices
     132              :    PUBLIC :: kp_transform_plan_create, kp_transform_plan_release
     133              :    PUBLIC :: rskp_transform, lowdin_kp_trans, lowdin_kp_mo_coeff
     134              :    PUBLIC :: rskp_grid_type, rskp_transform_grid_prepare, rskp_transform_grid_extract, &
     135              :              rskp_transform_grid_release
     136              : 
     137              : ! **************************************************************************************************
     138              : 
     139              :    TYPE rskp_grid_type
     140              :       COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: values
     141              :       INTEGER, ALLOCATABLE, DIMENSION(:)                :: block_col, block_nelem, block_offset, block_row
     142              :       LOGICAL                                           :: ready = .FALSE.
     143              :    END TYPE rskp_grid_type
     144              : 
     145              : ! **************************************************************************************************
     146              : 
     147              : CONTAINS
     148              : 
     149              : ! **************************************************************************************************
     150              : !> \brief Generate the kpoints and initialize the kpoint environment
     151              : !> \param kpoint       The kpoint environment
     152              : !> \param particle_set Particle types and coordinates
     153              : !> \param cell         Computational cell information
     154              : ! **************************************************************************************************
     155        11750 :    SUBROUTINE kpoint_initialize(kpoint, particle_set, cell)
     156              : 
     157              :       TYPE(kpoint_type), POINTER                         :: kpoint
     158              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     159              :       TYPE(cell_type), POINTER                           :: cell
     160              : 
     161              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'kpoint_initialize'
     162              : 
     163              :       INTEGER                                            :: handle, i, ic, ik, iounit, ir, ira, is, &
     164              :                                                             isign, j, natom, nkind, nr, ns
     165        11750 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atype
     166        11750 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: agauge
     167              :       INTEGER, DIMENSION(3, 3)                           :: frot, krot
     168              :       LOGICAL                                            :: spez
     169              :       REAL(KIND=dp)                                      :: eps_kpoint, wsum
     170        11750 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: coord, scoord
     171              :       REAL(KIND=dp), DIMENSION(3)                        :: diff, kgvec, r_pbc, scoord_pbc, srot
     172              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: srotmat
     173        11750 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: wkp_full
     174        11750 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: xkp_full
     175       223250 :       TYPE(csym_type)                                    :: crys_sym
     176              :       TYPE(kpoint_sym_type), POINTER                     :: kpsym
     177              : 
     178        11750 :       CALL timeset(routineN, handle)
     179              : 
     180        11750 :       CPASSERT(ASSOCIATED(kpoint))
     181              : 
     182        11770 :       SELECT CASE (kpoint%kp_scheme)
     183              :       CASE ("NONE")
     184              :          ! do nothing
     185              :       CASE ("GAMMA")
     186           20 :          kpoint%nkp = 1
     187           20 :          ALLOCATE (kpoint%xkp(3, 1), kpoint%wkp(1))
     188           80 :          kpoint%xkp(1:3, 1) = 0.0_dp
     189           20 :          kpoint%wkp(1) = 1.0_dp
     190           40 :          ALLOCATE (kpoint%kp_sym(1))
     191           20 :          NULLIFY (kpoint%kp_sym(1)%kpoint_sym)
     192           20 :          CALL kpoint_sym_create(kpoint%kp_sym(1)%kpoint_sym)
     193              :       CASE ("MONKHORST-PACK", "MACDONALD")
     194              : 
     195         3316 :          IF (.NOT. kpoint%symmetry) THEN
     196              :             ! we set up a random molecule to avoid any possible symmetry
     197          182 :             natom = 10
     198          182 :             ALLOCATE (coord(3, natom), scoord(3, natom), atype(natom))
     199         2002 :             DO i = 1, natom
     200         1820 :                atype(i) = i
     201         1820 :                coord(1, i) = SIN(i*0.12345_dp)
     202         1820 :                coord(2, i) = COS(i*0.23456_dp)
     203         1820 :                coord(3, i) = SIN(i*0.34567_dp)
     204         2002 :                CALL real_to_scaled(scoord(1:3, i), coord(1:3, i), cell)
     205              :             END DO
     206              :          ELSE
     207         3134 :             natom = SIZE(particle_set)
     208        15670 :             ALLOCATE (scoord(3, natom), atype(natom))
     209        17104 :             DO i = 1, natom
     210        13970 :                CALL get_atomic_kind(atomic_kind=particle_set(i)%atomic_kind, kind_number=atype(i))
     211        17104 :                CALL real_to_scaled(scoord(1:3, i), particle_set(i)%r(1:3), cell)
     212              :             END DO
     213              :          END IF
     214         3316 :          IF (kpoint%verbose) THEN
     215         2340 :             iounit = cp_logger_get_default_io_unit()
     216              :          ELSE
     217          976 :             iounit = -1
     218              :          END IF
     219              :          ! kind type list
     220         9948 :          ALLOCATE (kpoint%atype(natom))
     221        19106 :          kpoint%atype = atype
     222              :          ! Match the atom images used by CP2K's periodic neighbor lists.
     223         9948 :          ALLOCATE (agauge(3, natom))
     224         3316 :          agauge = 0
     225         3316 :          IF (kpoint%symmetry) THEN
     226        17104 :             DO i = 1, natom
     227        13970 :                r_pbc(1:3) = pbc_stable(particle_set(i)%r(1:3), cell)
     228        13970 :                CALL real_to_scaled(scoord_pbc, r_pbc, cell)
     229        59014 :                agauge(1:3, i) = NINT(scoord_pbc(1:3) - scoord(1:3, i))
     230              :             END DO
     231              :          END IF
     232              : 
     233              :          CALL crys_sym_gen(crys_sym, scoord, atype, cell%hmat, delta=kpoint%eps_geo, iounit=iounit, &
     234         3316 :                            use_spglib=kpoint%symmetry)
     235              :          CALL kpoint_gen(crys_sym, kpoint%nkp_grid, symm=kpoint%symmetry, shift=kpoint%kp_shift, &
     236              :                          full_grid=kpoint%full_grid, gamma_centered=kpoint%gamma_centered, &
     237              :                          inversion_symmetry_only=kpoint%inversion_symmetry_only, &
     238              :                          use_spglib_reduction= &
     239              :                          kpoint%symmetry_reduction_method == use_spglib_kpoint_symmetry, &
     240         3316 :                          use_spglib_backend=kpoint%symmetry_backend == use_spglib_kpoint_backend)
     241         3316 :          IF (crys_sym%inversion_only) kpoint%inversion_symmetry_only = .TRUE.
     242         3316 :          kpoint%nkp = crys_sym%nkpoint
     243        16580 :          ALLOCATE (kpoint%xkp(3, kpoint%nkp), kpoint%wkp(kpoint%nkp))
     244        14984 :          wsum = SUM(crys_sym%wkpoint)
     245        14984 :          DO ik = 1, kpoint%nkp
     246        46672 :             kpoint%xkp(1:3, ik) = crys_sym%xkpoint(1:3, ik)
     247        14984 :             kpoint%wkp(ik) = crys_sym%wkpoint(ik)/wsum
     248              :          END DO
     249              : 
     250         3316 :          eps_kpoint = MAX(1.e-12_dp, 10.0_dp*kpoint%eps_geo)
     251              :          ! print output
     252         3316 :          IF (kpoint%symmetry) CALL print_crys_symmetry(crys_sym)
     253         3316 :          IF (kpoint%symmetry) CALL print_kp_symmetry(crys_sym)
     254              : 
     255              :          ! transfer symmetry information
     256        21616 :          ALLOCATE (kpoint%kp_sym(kpoint%nkp))
     257        14984 :          DO ik = 1, kpoint%nkp
     258        11668 :             NULLIFY (kpoint%kp_sym(ik)%kpoint_sym)
     259        11668 :             CALL kpoint_sym_create(kpoint%kp_sym(ik)%kpoint_sym)
     260        11668 :             kpsym => kpoint%kp_sym(ik)%kpoint_sym
     261              :             IF (crys_sym%nrtot > 0 .AND. .NOT. crys_sym%fullgrid .AND. &
     262        14984 :                 crys_sym%istriz == 1 .AND. .NOT. crys_sym%inversion_only) THEN
     263              :                ! set up the symmetrization information
     264         3982 :                kpsym%nwght = NINT(crys_sym%wkpoint(ik))
     265         3982 :                ns = kpsym%nwght
     266              :                !
     267         3982 :                IF (ns > 1) THEN
     268        81538 :                   DO is = 1, SIZE(crys_sym%kplink, 2)
     269        81538 :                      IF (crys_sym%kplink(2, is) == ik) THEN
     270       557368 :                         DO ic = 1, crys_sym%nrtot
     271     42541816 :                            srotmat = MATMUL(cell%h_inv, MATMUL(crys_sym%rt(1:3, 1:3, ic), cell%hmat))
     272      7000552 :                            frot(1:3, 1:3) = NINT(srotmat(1:3, 1:3))
     273     14001104 :                            krot(1:3, 1:3) = NINT(TRANSPOSE(inv_3x3(REAL(frot(1:3, 1:3), KIND=dp))))
     274      1634376 :                            DO isign = 1, 2
     275      1077008 :                               ir = MERGE(crys_sym%ibrot(ic), -crys_sym%ibrot(ic), isign == 1)
     276      1077008 :                               IF (ir == crys_sym%kpop(is)) CYCLE
     277              :                               kgvec(1:3) = crys_sym%kpmesh(1:3, is) - &
     278              :                                            MATMUL(REAL(MERGE(krot(1:3, 1:3), -krot(1:3, 1:3), &
     279              :                                                              isign == 1), KIND=dp), &
     280     29628032 :                                                   kpoint%xkp(1:3, ik))
     281      4232576 :                               diff(1:3) = kgvec(1:3) - ANINT(kgvec(1:3))
     282      2218356 :                               IF (ALL(ABS(diff(1:3)) < eps_kpoint)) ns = ns + 1
     283              :                            END DO
     284              :                         END DO
     285              :                      END IF
     286              :                   END DO
     287         3572 :                   kpsym%apply_symmetry = .TRUE.
     288         3572 :                   natom = SIZE(particle_set)
     289        10716 :                   ALLOCATE (kpsym%rot(3, 3, ns))
     290        10716 :                   ALLOCATE (kpsym%xkp(3, ns))
     291        10716 :                   ALLOCATE (kpsym%rotp(ns))
     292        14288 :                   ALLOCATE (kpsym%f0(natom, ns))
     293        14288 :                   ALLOCATE (kpsym%fcell(3, natom, ns))
     294        10716 :                   ALLOCATE (kpsym%fcell_gauge(3, natom, ns))
     295         7144 :                   ALLOCATE (kpsym%phase_mode(ns))
     296       101760 :                   kpsym%phase_mode = 0
     297        14288 :                   ALLOCATE (kpsym%kgphase(natom, ns))
     298         3572 :                   nr = 0
     299        81538 :                   DO is = 1, SIZE(crys_sym%kplink, 2)
     300        81538 :                      IF (crys_sym%kplink(2, is) == ik) THEN
     301        18864 :                         nr = nr + 1
     302        18864 :                         ir = crys_sym%kpop(is)
     303        18864 :                         ira = ABS(ir)
     304       100776 :                         DO ic = 1, crys_sym%nrtot
     305       100776 :                            IF (crys_sym%ibrot(ic) == ira) THEN
     306        18864 :                               kpsym%rotp(nr) = ir
     307       245232 :                               kpsym%rot(1:3, 1:3, nr) = crys_sym%rt(1:3, 1:3, ic)
     308      1490256 :                               srotmat = MATMUL(cell%h_inv, MATMUL(crys_sym%rt(1:3, 1:3, ic), cell%hmat))
     309       245232 :                               frot(1:3, 1:3) = NINT(srotmat(1:3, 1:3))
     310        75456 :                               kpsym%xkp(1:3, nr) = crys_sym%kpmesh(1:3, is)
     311       490464 :                               krot(1:3, 1:3) = NINT(TRANSPOSE(inv_3x3(REAL(frot(1:3, 1:3), KIND=dp))))
     312       129960 :                               IF (ir < 0) krot(1:3, 1:3) = -krot(1:3, 1:3)
     313              :                               kgvec(1:3) = kpsym%xkp(1:3, nr) - &
     314              :                                            MATMUL(REAL(krot(1:3, 1:3), KIND=dp), &
     315       528192 :                                                   kpoint%xkp(1:3, ik))
     316        75456 :                               kgvec(1:3) = ANINT(kgvec(1:3))
     317       135952 :                               kpsym%f0(1:natom, nr) = crys_sym%f0(1:natom, ic)
     318       135952 :                               DO j = 1, natom
     319      1873408 :                                  srot(1:3) = MATMUL(srotmat, scoord(1:3, j)) + crys_sym%vt(1:3, ic)
     320              :                                  kpsym%fcell(1:3, j, nr) = &
     321       468352 :                                     NINT(srot(1:3) - scoord(1:3, kpsym%f0(j, nr)))
     322              :                                  kpsym%fcell_gauge(1:3, j, nr) = &
     323              :                                     NINT(srot(1:3) - scoord(1:3, kpsym%f0(j, nr))) + &
     324              :                                     MATMUL(frot(1:3, 1:3), agauge(1:3, j)) - &
     325      2224672 :                                     agauge(1:3, kpsym%f0(j, nr))
     326              :                                  kpsym%kgphase(j, nr) = DOT_PRODUCT(kgvec(1:3), &
     327              :                                                                     scoord(1:3, j) + &
     328       487216 :                                                                     REAL(agauge(1:3, j), KIND=dp))
     329              :                               END DO
     330              :                               EXIT
     331              :                            END IF
     332              :                         END DO
     333        18864 :                         CPASSERT(ic <= crys_sym%nrtot)
     334              :                      END IF
     335              :                   END DO
     336        81538 :                   DO is = 1, SIZE(crys_sym%kplink, 2)
     337        81538 :                      IF (crys_sym%kplink(2, is) == ik) THEN
     338       557368 :                         DO ic = 1, crys_sym%nrtot
     339     42541816 :                            srotmat = MATMUL(cell%h_inv, MATMUL(crys_sym%rt(1:3, 1:3, ic), cell%hmat))
     340      7000552 :                            frot(1:3, 1:3) = NINT(srotmat(1:3, 1:3))
     341     14001104 :                            krot(1:3, 1:3) = NINT(TRANSPOSE(inv_3x3(REAL(frot(1:3, 1:3), KIND=dp))))
     342      1634376 :                            DO isign = 1, 2
     343      1077008 :                               ir = MERGE(crys_sym%ibrot(ic), -crys_sym%ibrot(ic), isign == 1)
     344      1077008 :                               IF (ir == crys_sym%kpop(is)) CYCLE
     345              :                               kgvec(1:3) = crys_sym%kpmesh(1:3, is) - &
     346              :                                            MATMUL(REAL(MERGE(krot(1:3, 1:3), -krot(1:3, 1:3), &
     347              :                                                              isign == 1), KIND=dp), &
     348     29628032 :                                                   kpoint%xkp(1:3, ik))
     349      4232576 :                               diff(1:3) = kgvec(1:3) - ANINT(kgvec(1:3))
     350      2218356 :                               IF (ALL(ABS(diff(1:3)) < eps_kpoint)) THEN
     351        79324 :                                  nr = nr + 1
     352        79324 :                                  kpsym%rotp(nr) = ir
     353      1031212 :                                  kpsym%rot(1:3, 1:3, nr) = crys_sym%rt(1:3, 1:3, ic)
     354       317296 :                                  kpsym%xkp(1:3, nr) = crys_sym%kpmesh(1:3, is)
     355       317296 :                                  kgvec(1:3) = ANINT(kgvec(1:3))
     356       512720 :                                  kpsym%f0(1:natom, nr) = crys_sym%f0(1:natom, ic)
     357       512720 :                                  DO j = 1, natom
     358      6934336 :                                     srot(1:3) = MATMUL(srotmat, scoord(1:3, j)) + crys_sym%vt(1:3, ic)
     359              :                                     kpsym%fcell(1:3, j, nr) = &
     360      1733584 :                                        NINT(srot(1:3) - scoord(1:3, kpsym%f0(j, nr)))
     361              :                                     kpsym%fcell_gauge(1:3, j, nr) = &
     362              :                                        NINT(srot(1:3) - scoord(1:3, kpsym%f0(j, nr))) + &
     363              :                                        MATMUL(frot(1:3, 1:3), agauge(1:3, j)) - &
     364      8234524 :                                        agauge(1:3, kpsym%f0(j, nr))
     365              :                                     kpsym%kgphase(j, nr) = DOT_PRODUCT(kgvec(1:3), &
     366              :                                                                        scoord(1:3, j) + &
     367      1812908 :                                                                        REAL(agauge(1:3, j), KIND=dp))
     368              :                                  END DO
     369              :                               END IF
     370              :                            END DO
     371              :                         END DO
     372              :                      END IF
     373              :                   END DO
     374         3572 :                   kpsym%nwred = nr
     375              :                END IF
     376              :             END IF
     377              :          END DO
     378         3316 :          IF (kpoint%symmetry) THEN
     379        17104 :             nkind = MAXVAL(atype)
     380         3134 :             ns = crys_sym%nrtot
     381        40762 :             ALLOCATE (kpoint%kind_rotmat(ns, nkind))
     382        26390 :             DO i = 1, ns
     383        51690 :                DO j = 1, nkind
     384        48556 :                   NULLIFY (kpoint%kind_rotmat(i, j)%rmat)
     385              :                END DO
     386              :             END DO
     387         7942 :             ALLOCATE (kpoint%ibrot(ns))
     388        26390 :             kpoint%ibrot(1:ns) = crys_sym%ibrot(1:ns)
     389              :          END IF
     390              : 
     391         3316 :          CALL release_csym_type(crys_sym)
     392         3316 :          DEALLOCATE (scoord, atype)
     393         3316 :          DEALLOCATE (agauge)
     394              : 
     395              :       CASE ("GENERAL")
     396              :          NULLIFY (xkp_full, wkp_full)
     397           36 :          IF (ASSOCIATED(kpoint%xkp_input)) THEN
     398           36 :             xkp_full => kpoint%xkp_input
     399           36 :             wkp_full => kpoint%wkp_input
     400              :          ELSE
     401            0 :             xkp_full => kpoint%xkp
     402            0 :             wkp_full => kpoint%wkp
     403              :          END IF
     404           36 :          CPASSERT(ASSOCIATED(xkp_full))
     405           36 :          CPASSERT(ASSOCIATED(wkp_full))
     406           36 :          IF (.NOT. ASSOCIATED(kpoint%xkp_input)) THEN
     407            0 :             ALLOCATE (kpoint%xkp_input(3, SIZE(wkp_full)), kpoint%wkp_input(SIZE(wkp_full)))
     408            0 :             kpoint%xkp_input(1:3, 1:SIZE(wkp_full)) = xkp_full(1:3, 1:SIZE(wkp_full))
     409            0 :             kpoint%wkp_input(1:SIZE(wkp_full)) = wkp_full(1:SIZE(wkp_full))
     410            0 :             xkp_full => kpoint%xkp_input
     411            0 :             wkp_full => kpoint%wkp_input
     412              :          END IF
     413           36 :          IF (.NOT. kpoint%symmetry) THEN
     414           10 :             IF (.NOT. ASSOCIATED(kpoint%xkp)) THEN
     415            0 :                kpoint%nkp = SIZE(wkp_full)
     416            0 :                ALLOCATE (kpoint%xkp(3, kpoint%nkp), kpoint%wkp(kpoint%nkp))
     417            0 :                kpoint%xkp(1:3, 1:kpoint%nkp) = xkp_full(1:3, 1:kpoint%nkp)
     418            0 :                kpoint%wkp(1:kpoint%nkp) = wkp_full(1:kpoint%nkp)
     419              :             END IF
     420              :             ! default: no symmetry settings
     421           74 :             ALLOCATE (kpoint%kp_sym(kpoint%nkp))
     422           54 :             DO i = 1, kpoint%nkp
     423           44 :                NULLIFY (kpoint%kp_sym(i)%kpoint_sym)
     424           54 :                CALL kpoint_sym_create(kpoint%kp_sym(i)%kpoint_sym)
     425              :             END DO
     426              :          ELSE
     427           26 :             IF (kpoint%verbose) THEN
     428           16 :                iounit = cp_logger_get_default_io_unit()
     429              :             ELSE
     430           10 :                iounit = -1
     431              :             END IF
     432           26 :             natom = SIZE(particle_set)
     433          130 :             ALLOCATE (scoord(3, natom), atype(natom))
     434          234 :             DO i = 1, natom
     435          208 :                CALL get_atomic_kind(atomic_kind=particle_set(i)%atomic_kind, kind_number=atype(i))
     436          234 :                CALL real_to_scaled(scoord(1:3, i), particle_set(i)%r(1:3), cell)
     437              :             END DO
     438           52 :             ALLOCATE (kpoint%atype(natom))
     439          234 :             kpoint%atype = atype
     440           78 :             ALLOCATE (agauge(3, natom))
     441          234 :             DO i = 1, natom
     442          208 :                r_pbc(1:3) = pbc_stable(particle_set(i)%r(1:3), cell)
     443          208 :                CALL real_to_scaled(scoord_pbc, r_pbc, cell)
     444          858 :                agauge(1:3, i) = NINT(scoord_pbc(1:3) - scoord(1:3, i))
     445              :             END DO
     446              : 
     447              :             CALL crys_sym_gen(crys_sym, scoord, atype, cell%hmat, delta=kpoint%eps_geo, iounit=iounit, &
     448              :                               use_spglib=(kpoint%symmetry_backend == use_spglib_kpoint_backend .OR. &
     449           30 :                                           kpoint%symmetry_reduction_method == use_spglib_kpoint_symmetry))
     450              :             CALL kpoint_gen_general(crys_sym, xkp_full, wkp_full, symm=kpoint%symmetry, &
     451              :                                     full_grid=kpoint%full_grid, &
     452              :                                     inversion_symmetry_only=kpoint%inversion_symmetry_only, &
     453              :                                     use_spglib_reduction= &
     454              :                                     kpoint%symmetry_reduction_method == use_spglib_kpoint_symmetry, &
     455           26 :                                     use_spglib_backend=kpoint%symmetry_backend == use_spglib_kpoint_backend)
     456           26 :             IF (crys_sym%inversion_only) kpoint%inversion_symmetry_only = .TRUE.
     457           26 :             IF (ASSOCIATED(kpoint%xkp)) THEN
     458           26 :                DEALLOCATE (kpoint%xkp)
     459           26 :                NULLIFY (kpoint%xkp)
     460              :             END IF
     461           26 :             IF (ASSOCIATED(kpoint%wkp)) THEN
     462           26 :                DEALLOCATE (kpoint%wkp)
     463           26 :                NULLIFY (kpoint%wkp)
     464              :             END IF
     465           26 :             kpoint%nkp = crys_sym%nkpoint
     466          130 :             ALLOCATE (kpoint%xkp(3, kpoint%nkp), kpoint%wkp(kpoint%nkp))
     467           52 :             wsum = SUM(crys_sym%wkpoint)
     468           52 :             DO ik = 1, kpoint%nkp
     469          104 :                kpoint%xkp(1:3, ik) = crys_sym%xkpoint(1:3, ik)
     470           52 :                kpoint%wkp(ik) = crys_sym%wkpoint(ik)/wsum
     471              :             END DO
     472              : 
     473           26 :             eps_kpoint = MAX(1.e-12_dp, 10.0_dp*kpoint%eps_geo)
     474           26 :             CALL print_crys_symmetry(crys_sym)
     475           26 :             CALL print_kp_symmetry(crys_sym)
     476              : 
     477          104 :             ALLOCATE (kpoint%kp_sym(kpoint%nkp))
     478           52 :             DO ik = 1, kpoint%nkp
     479           26 :                NULLIFY (kpoint%kp_sym(ik)%kpoint_sym)
     480           26 :                CALL kpoint_sym_create(kpoint%kp_sym(ik)%kpoint_sym)
     481           26 :                kpsym => kpoint%kp_sym(ik)%kpoint_sym
     482              :                IF (crys_sym%nrtot > 0 .AND. .NOT. crys_sym%fullgrid .AND. &
     483           52 :                    crys_sym%istriz == 1 .AND. .NOT. crys_sym%inversion_only) THEN
     484           26 :                   kpsym%nwght = NINT(crys_sym%wkpoint(ik))
     485           26 :                   ns = kpsym%nwght
     486           26 :                   IF (ns > 1) THEN
     487          234 :                      DO is = 1, SIZE(crys_sym%kplink, 2)
     488          234 :                         IF (crys_sym%kplink(2, is) == ik) THEN
     489        10192 :                            DO ic = 1, crys_sym%nrtot
     490       788736 :                               srotmat = MATMUL(cell%h_inv, MATMUL(crys_sym%rt(1:3, 1:3, ic), cell%hmat))
     491       129792 :                               frot(1:3, 1:3) = NINT(srotmat(1:3, 1:3))
     492       259584 :                               krot(1:3, 1:3) = NINT(TRANSPOSE(inv_3x3(REAL(frot(1:3, 1:3), KIND=dp))))
     493        30160 :                               DO isign = 1, 2
     494        19968 :                                  ir = MERGE(crys_sym%ibrot(ic), -crys_sym%ibrot(ic), isign == 1)
     495        19968 :                                  IF (ir == crys_sym%kpop(is)) CYCLE
     496              :                                  kgvec(1:3) = crys_sym%kpmesh(1:3, is) - &
     497              :                                               MATMUL(REAL(MERGE(krot(1:3, 1:3), -krot(1:3, 1:3), &
     498              :                                                                 isign == 1), KIND=dp), &
     499       553280 :                                                      kpoint%xkp(1:3, ik))
     500        79040 :                                  diff(1:3) = kgvec(1:3) - ANINT(kgvec(1:3))
     501        46592 :                                  IF (ALL(ABS(diff(1:3)) < eps_kpoint)) ns = ns + 1
     502              :                               END DO
     503              :                            END DO
     504              :                         END IF
     505              :                      END DO
     506           26 :                      kpsym%apply_symmetry = .TRUE.
     507           78 :                      ALLOCATE (kpsym%rot(3, 3, ns))
     508           78 :                      ALLOCATE (kpsym%xkp(3, ns))
     509           78 :                      ALLOCATE (kpsym%rotp(ns))
     510          104 :                      ALLOCATE (kpsym%f0(natom, ns))
     511          104 :                      ALLOCATE (kpsym%fcell(3, natom, ns))
     512           78 :                      ALLOCATE (kpsym%fcell_gauge(3, natom, ns))
     513           52 :                      ALLOCATE (kpsym%phase_mode(ns))
     514         2522 :                      kpsym%phase_mode = 0
     515          104 :                      ALLOCATE (kpsym%kgphase(natom, ns))
     516           26 :                      nr = 0
     517          234 :                      DO is = 1, SIZE(crys_sym%kplink, 2)
     518          234 :                         IF (crys_sym%kplink(2, is) == ik) THEN
     519          208 :                            nr = nr + 1
     520          208 :                            ir = crys_sym%kpop(is)
     521          208 :                            ira = ABS(ir)
     522          628 :                            DO ic = 1, crys_sym%nrtot
     523          628 :                               IF (crys_sym%ibrot(ic) == ira) THEN
     524          208 :                                  kpsym%rotp(nr) = ir
     525         2704 :                                  kpsym%rot(1:3, 1:3, nr) = crys_sym%rt(1:3, 1:3, ic)
     526        16432 :                                  srotmat = MATMUL(cell%h_inv, MATMUL(crys_sym%rt(1:3, 1:3, ic), cell%hmat))
     527         2704 :                                  frot(1:3, 1:3) = NINT(srotmat(1:3, 1:3))
     528          832 :                                  kpsym%xkp(1:3, nr) = crys_sym%kpmesh(1:3, is)
     529         5408 :                                  krot(1:3, 1:3) = NINT(TRANSPOSE(inv_3x3(REAL(frot(1:3, 1:3), KIND=dp))))
     530         1456 :                                  IF (ir < 0) krot(1:3, 1:3) = -krot(1:3, 1:3)
     531              :                                  kgvec(1:3) = kpsym%xkp(1:3, nr) - &
     532              :                                               MATMUL(REAL(krot(1:3, 1:3), KIND=dp), &
     533         5824 :                                                      kpoint%xkp(1:3, ik))
     534          832 :                                  kgvec(1:3) = ANINT(kgvec(1:3))
     535         1872 :                                  kpsym%f0(1:natom, nr) = crys_sym%f0(1:natom, ic)
     536         1872 :                                  DO j = 1, natom
     537        26624 :                                     srot(1:3) = MATMUL(srotmat, scoord(1:3, j)) + crys_sym%vt(1:3, ic)
     538              :                                     kpsym%fcell(1:3, j, nr) = &
     539         6656 :                                        NINT(srot(1:3) - scoord(1:3, kpsym%f0(j, nr)))
     540              :                                     kpsym%fcell_gauge(1:3, j, nr) = &
     541              :                                        NINT(srot(1:3) - scoord(1:3, kpsym%f0(j, nr))) + &
     542              :                                        MATMUL(frot(1:3, 1:3), agauge(1:3, j)) - &
     543        31616 :                                        agauge(1:3, kpsym%f0(j, nr))
     544              :                                     kpsym%kgphase(j, nr) = DOT_PRODUCT(kgvec(1:3), &
     545              :                                                                        scoord(1:3, j) + &
     546         6864 :                                                                        REAL(agauge(1:3, j), KIND=dp))
     547              :                                  END DO
     548              :                                  EXIT
     549              :                               END IF
     550              :                            END DO
     551          208 :                            CPASSERT(ic <= crys_sym%nrtot)
     552              :                         END IF
     553              :                      END DO
     554          234 :                      DO is = 1, SIZE(crys_sym%kplink, 2)
     555          234 :                         IF (crys_sym%kplink(2, is) == ik) THEN
     556        10192 :                            DO ic = 1, crys_sym%nrtot
     557       788736 :                               srotmat = MATMUL(cell%h_inv, MATMUL(crys_sym%rt(1:3, 1:3, ic), cell%hmat))
     558       129792 :                               frot(1:3, 1:3) = NINT(srotmat(1:3, 1:3))
     559       259584 :                               krot(1:3, 1:3) = NINT(TRANSPOSE(inv_3x3(REAL(frot(1:3, 1:3), KIND=dp))))
     560        30160 :                               DO isign = 1, 2
     561        19968 :                                  ir = MERGE(crys_sym%ibrot(ic), -crys_sym%ibrot(ic), isign == 1)
     562        19968 :                                  IF (ir == crys_sym%kpop(is)) CYCLE
     563              :                                  kgvec(1:3) = crys_sym%kpmesh(1:3, is) - &
     564              :                                               MATMUL(REAL(MERGE(krot(1:3, 1:3), -krot(1:3, 1:3), &
     565              :                                                                 isign == 1), KIND=dp), &
     566       553280 :                                                      kpoint%xkp(1:3, ik))
     567        79040 :                                  diff(1:3) = kgvec(1:3) - ANINT(kgvec(1:3))
     568        46592 :                                  IF (ALL(ABS(diff(1:3)) < eps_kpoint)) THEN
     569         2288 :                                     nr = nr + 1
     570         2288 :                                     kpsym%rotp(nr) = ir
     571        29744 :                                     kpsym%rot(1:3, 1:3, nr) = crys_sym%rt(1:3, 1:3, ic)
     572         9152 :                                     kpsym%xkp(1:3, nr) = crys_sym%kpmesh(1:3, is)
     573         9152 :                                     kgvec(1:3) = ANINT(kgvec(1:3))
     574        20592 :                                     kpsym%f0(1:natom, nr) = crys_sym%f0(1:natom, ic)
     575        20592 :                                     DO j = 1, natom
     576       292864 :                                        srot(1:3) = MATMUL(srotmat, scoord(1:3, j)) + crys_sym%vt(1:3, ic)
     577              :                                        kpsym%fcell(1:3, j, nr) = &
     578        73216 :                                           NINT(srot(1:3) - scoord(1:3, kpsym%f0(j, nr)))
     579              :                                        kpsym%fcell_gauge(1:3, j, nr) = &
     580              :                                           NINT(srot(1:3) - scoord(1:3, kpsym%f0(j, nr))) + &
     581              :                                           MATMUL(frot(1:3, 1:3), agauge(1:3, j)) - &
     582       347776 :                                           agauge(1:3, kpsym%f0(j, nr))
     583              :                                        kpsym%kgphase(j, nr) = DOT_PRODUCT(kgvec(1:3), &
     584              :                                                                           scoord(1:3, j) + &
     585        75504 :                                                                           REAL(agauge(1:3, j), KIND=dp))
     586              :                                     END DO
     587              :                                  END IF
     588              :                               END DO
     589              :                            END DO
     590              :                         END IF
     591              :                      END DO
     592           26 :                      kpsym%nwred = nr
     593              :                   END IF
     594              :                END IF
     595              :             END DO
     596          234 :             nkind = MAXVAL(atype)
     597           26 :             ns = crys_sym%nrtot
     598         1378 :             ALLOCATE (kpoint%kind_rotmat(ns, nkind))
     599         1274 :             DO i = 1, ns
     600         2522 :                DO j = 1, nkind
     601         2496 :                   NULLIFY (kpoint%kind_rotmat(i, j)%rmat)
     602              :                END DO
     603              :             END DO
     604           78 :             ALLOCATE (kpoint%ibrot(ns))
     605         1274 :             kpoint%ibrot(1:ns) = crys_sym%ibrot(1:ns)
     606              : 
     607           26 :             CALL release_csym_type(crys_sym)
     608           26 :             DEALLOCATE (scoord, atype)
     609           26 :             DEALLOCATE (agauge)
     610              :          END IF
     611              :       CASE DEFAULT
     612        11750 :          CPABORT("Option invalid or unavailable for kpoint%kp_scheme")
     613              :       END SELECT
     614              : 
     615              :       ! check for consistency of options
     616        11770 :       SELECT CASE (kpoint%kp_scheme)
     617              :       CASE ("NONE")
     618              :          ! don't use k-point code
     619              :       CASE ("GAMMA")
     620           20 :          CPASSERT(kpoint%nkp == 1)
     621          100 :          CPASSERT(SUM(ABS(kpoint%xkp)) <= 1.e-12_dp)
     622           20 :          CPASSERT(kpoint%wkp(1) == 1.0_dp)
     623           20 :          CPASSERT(.NOT. kpoint%symmetry)
     624              :       CASE ("GENERAL")
     625           36 :          CPASSERT(kpoint%nkp >= 1)
     626              :       CASE ("MONKHORST-PACK", "MACDONALD")
     627        11750 :          CPASSERT(kpoint%nkp >= 1)
     628              :       END SELECT
     629        11750 :       IF (kpoint%use_real_wfn) THEN
     630              :          ! what about inversion symmetry?
     631           40 :          ikloop: DO ik = 1, kpoint%nkp
     632          100 :             DO i = 1, 3
     633           60 :                spez = (kpoint%xkp(i, ik) == 0.0_dp .OR. kpoint%xkp(i, ik) == 0.5_dp)
     634           20 :                IF (.NOT. spez) EXIT ikloop
     635              :             END DO
     636              :          END DO ikloop
     637           20 :          IF (.NOT. spez) THEN
     638              :             ! Warning: real wfn might be wrong for this system
     639              :             CALL cp_warn(__LOCATION__, &
     640              :                          "A calculation using real wavefunctions is requested. "// &
     641            0 :                          "We could not determine if the symmetry of the system allows real wavefunctions. ")
     642              :          END IF
     643              :       END IF
     644              : 
     645        11750 :       CALL timestop(handle)
     646              : 
     647        23500 :    END SUBROUTINE kpoint_initialize
     648              : 
     649              : ! **************************************************************************************************
     650              : !> \brief Initialize the kpoint environment
     651              : !> \param kpoint       Kpoint environment
     652              : !> \param para_env ...
     653              : !> \param blacs_env ...
     654              : !> \param with_aux_fit ...
     655              : ! **************************************************************************************************
     656         3126 :    SUBROUTINE kpoint_env_initialize(kpoint, para_env, blacs_env, with_aux_fit)
     657              : 
     658              :       TYPE(kpoint_type), INTENT(INOUT)                   :: kpoint
     659              :       TYPE(mp_para_env_type), INTENT(IN), TARGET         :: para_env
     660              :       TYPE(cp_blacs_env_type), INTENT(IN), TARGET        :: blacs_env
     661              :       LOGICAL, INTENT(IN), OPTIONAL                      :: with_aux_fit
     662              : 
     663              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'kpoint_env_initialize'
     664              : 
     665              :       INTEGER                                            :: handle, igr, ik, ikk, ngr, niogrp, nkp, &
     666              :                                                             nkp_grp, nkp_loc, npe, unit_nr
     667              :       INTEGER, DIMENSION(2)                              :: dims, pos
     668              :       LOGICAL                                            :: aux_fit
     669         3126 :       TYPE(kpoint_env_p_type), DIMENSION(:), POINTER     :: kp_aux_env, kp_env
     670              :       TYPE(kpoint_env_type), POINTER                     :: kp
     671         3126 :       TYPE(mp_cart_type)                                 :: comm_cart
     672              :       TYPE(mp_para_env_type), POINTER                    :: para_env_inter_kp, para_env_kp
     673              : 
     674         3126 :       CALL timeset(routineN, handle)
     675              : 
     676         3126 :       IF (PRESENT(with_aux_fit)) THEN
     677         3018 :          aux_fit = with_aux_fit
     678              :       ELSE
     679              :          aux_fit = .FALSE.
     680              :       END IF
     681              : 
     682         3126 :       kpoint%para_env => para_env
     683         3126 :       CALL kpoint%para_env%retain()
     684         3126 :       kpoint%blacs_env_all => blacs_env
     685         3126 :       CALL kpoint%blacs_env_all%retain()
     686              : 
     687         3126 :       CPASSERT(.NOT. ASSOCIATED(kpoint%kp_env))
     688         3126 :       IF (aux_fit) THEN
     689           32 :          CPASSERT(.NOT. ASSOCIATED(kpoint%kp_aux_env))
     690              :       END IF
     691              : 
     692         3126 :       NULLIFY (kp_env, kp_aux_env)
     693         3126 :       nkp = kpoint%nkp
     694         3126 :       npe = para_env%num_pe
     695         3126 :       IF (npe == 1) THEN
     696              :          ! only one process available -> owns all kpoints
     697            0 :          ALLOCATE (kp_env(nkp))
     698            0 :          DO ik = 1, nkp
     699            0 :             NULLIFY (kp_env(ik)%kpoint_env)
     700            0 :             CALL kpoint_env_create(kp_env(ik)%kpoint_env)
     701            0 :             kp => kp_env(ik)%kpoint_env
     702            0 :             kp%nkpoint = ik
     703            0 :             kp%wkp = kpoint%wkp(ik)
     704            0 :             kp%xkp(1:3) = kpoint%xkp(1:3, ik)
     705            0 :             kp%is_local = .TRUE.
     706              :          END DO
     707            0 :          kpoint%kp_env => kp_env
     708              : 
     709            0 :          IF (aux_fit) THEN
     710            0 :             ALLOCATE (kp_aux_env(nkp))
     711            0 :             DO ik = 1, nkp
     712            0 :                NULLIFY (kp_aux_env(ik)%kpoint_env)
     713            0 :                CALL kpoint_env_create(kp_aux_env(ik)%kpoint_env)
     714            0 :                kp => kp_aux_env(ik)%kpoint_env
     715            0 :                kp%nkpoint = ik
     716            0 :                kp%wkp = kpoint%wkp(ik)
     717            0 :                kp%xkp(1:3) = kpoint%xkp(1:3, ik)
     718            0 :                kp%is_local = .TRUE.
     719              :             END DO
     720              : 
     721            0 :             kpoint%kp_aux_env => kp_aux_env
     722              :          END IF
     723              : 
     724            0 :          ALLOCATE (kpoint%kp_dist(2, 1))
     725            0 :          kpoint%kp_dist(1, 1) = 1
     726            0 :          kpoint%kp_dist(2, 1) = nkp
     727            0 :          kpoint%kp_range(1) = 1
     728            0 :          kpoint%kp_range(2) = nkp
     729              : 
     730              :          ! parallel environments
     731            0 :          kpoint%para_env_kp => para_env
     732            0 :          CALL kpoint%para_env_kp%retain()
     733            0 :          kpoint%para_env_inter_kp => para_env
     734            0 :          CALL kpoint%para_env_inter_kp%retain()
     735            0 :          kpoint%iogrp = .TRUE.
     736            0 :          kpoint%nkp_groups = 1
     737              :       ELSE
     738         3126 :          IF (kpoint%parallel_group_size == -1) THEN
     739              :             ! maximum parallelization over kpoints
     740              :             ! making sure that the group size divides the npe and the nkp_grp the nkp
     741              :             ! in the worst case, there will be no parallelism over kpoints.
     742         8106 :             DO igr = npe, 1, -1
     743         5404 :                IF (MOD(npe, igr) /= 0) CYCLE
     744         5404 :                nkp_grp = npe/igr
     745         5404 :                IF (MOD(nkp, nkp_grp) /= 0) CYCLE
     746         8106 :                ngr = igr
     747              :             END DO
     748          424 :          ELSE IF (kpoint%parallel_group_size == 0) THEN
     749              :             ! no parallelization over kpoints
     750          332 :             ngr = npe
     751           92 :          ELSE IF (kpoint%parallel_group_size > 0) THEN
     752           92 :             ngr = MIN(kpoint%parallel_group_size, npe)
     753              :          ELSE
     754            0 :             CPABORT("kpoint%parallel_group_size cannot be smaller than -1")
     755              :          END IF
     756         3126 :          nkp_grp = npe/ngr
     757              :          ! processor dimensions
     758         3126 :          dims(1) = ngr
     759         3126 :          dims(2) = nkp_grp
     760         3126 :          CPASSERT(MOD(nkp, nkp_grp) == 0)
     761         3126 :          nkp_loc = nkp/nkp_grp
     762              : 
     763         3126 :          IF ((dims(1)*dims(2) /= npe)) THEN
     764            0 :             CPABORT("Number of processors is not divisible by the kpoint group size.")
     765              :          END IF
     766              : 
     767              :          ! Create the subgroups, one for each k-point group and one interconnecting group
     768         3126 :          CALL comm_cart%create(comm_old=para_env, ndims=2, dims=dims)
     769         9378 :          pos = comm_cart%mepos_cart
     770         3126 :          ALLOCATE (para_env_kp)
     771         3126 :          CALL para_env_kp%from_split(comm_cart, pos(2))
     772         3126 :          ALLOCATE (para_env_inter_kp)
     773         3126 :          CALL para_env_inter_kp%from_split(comm_cart, pos(1))
     774         3126 :          CALL comm_cart%free()
     775              : 
     776         3126 :          niogrp = 0
     777         3126 :          IF (para_env%is_source()) niogrp = 1
     778         3126 :          CALL para_env_kp%sum(niogrp)
     779         3126 :          kpoint%iogrp = (niogrp == 1)
     780              : 
     781              :          ! parallel groups
     782         3126 :          kpoint%para_env_kp => para_env_kp
     783         3126 :          kpoint%para_env_inter_kp => para_env_inter_kp
     784              : 
     785              :          ! distribution of kpoints
     786         9378 :          ALLOCATE (kpoint%kp_dist(2, nkp_grp))
     787         8202 :          DO igr = 1, nkp_grp
     788        18354 :             kpoint%kp_dist(1:2, igr) = get_limit(nkp, nkp_grp, igr - 1)
     789              :          END DO
     790              :          ! local kpoints
     791         9378 :          kpoint%kp_range(1:2) = kpoint%kp_dist(1:2, para_env_inter_kp%mepos + 1)
     792              : 
     793        16422 :          ALLOCATE (kp_env(nkp_loc))
     794        10170 :          DO ik = 1, nkp_loc
     795         7044 :             NULLIFY (kp_env(ik)%kpoint_env)
     796         7044 :             ikk = kpoint%kp_range(1) + ik - 1
     797         7044 :             CALL kpoint_env_create(kp_env(ik)%kpoint_env)
     798         7044 :             kp => kp_env(ik)%kpoint_env
     799         7044 :             kp%nkpoint = ikk
     800         7044 :             kp%wkp = kpoint%wkp(ikk)
     801        28176 :             kp%xkp(1:3) = kpoint%xkp(1:3, ikk)
     802        10170 :             kp%is_local = (ngr == 1)
     803              :          END DO
     804         3126 :          kpoint%kp_env => kp_env
     805              : 
     806         3126 :          IF (aux_fit) THEN
     807          282 :             ALLOCATE (kp_aux_env(nkp_loc))
     808          250 :             DO ik = 1, nkp_loc
     809          218 :                NULLIFY (kp_aux_env(ik)%kpoint_env)
     810          218 :                ikk = kpoint%kp_range(1) + ik - 1
     811          218 :                CALL kpoint_env_create(kp_aux_env(ik)%kpoint_env)
     812          218 :                kp => kp_aux_env(ik)%kpoint_env
     813          218 :                kp%nkpoint = ikk
     814          218 :                kp%wkp = kpoint%wkp(ikk)
     815          872 :                kp%xkp(1:3) = kpoint%xkp(1:3, ikk)
     816          250 :                kp%is_local = (ngr == 1)
     817              :             END DO
     818           32 :             kpoint%kp_aux_env => kp_aux_env
     819              :          END IF
     820              : 
     821         3126 :          unit_nr = cp_logger_get_default_io_unit()
     822              : 
     823         3126 :          IF (unit_nr > 0 .AND. kpoint%verbose) THEN
     824         1179 :             WRITE (unit_nr, *)
     825         1179 :             WRITE (unit_nr, FMT="(T2,A,T71,I10)") "KPOINTS| Number of kpoint groups ", nkp_grp
     826         1179 :             WRITE (unit_nr, FMT="(T2,A,T71,I10)") "KPOINTS| Size of each kpoint group", ngr
     827         1179 :             WRITE (unit_nr, FMT="(T2,A,T71,I10)") "KPOINTS| Number of kpoints per group", nkp_loc
     828              :          END IF
     829         3126 :          kpoint%nkp_groups = nkp_grp
     830              : 
     831              :       END IF
     832              : 
     833         3126 :       CALL timestop(handle)
     834              : 
     835         6252 :    END SUBROUTINE kpoint_env_initialize
     836              : 
     837              : ! **************************************************************************************************
     838              : !> \brief Initialize a set of MOs and density matrix for each kpoint (kpoint group)
     839              : !> \param kpoint  Kpoint environment
     840              : !> \param mos     Reference MOs (global)
     841              : !> \param added_mos ...
     842              : !> \param for_aux_fit ...
     843              : ! **************************************************************************************************
     844         3164 :    SUBROUTINE kpoint_initialize_mos(kpoint, mos, added_mos, for_aux_fit)
     845              : 
     846              :       TYPE(kpoint_type), POINTER                         :: kpoint
     847              :       TYPE(mo_set_type), DIMENSION(:), INTENT(INOUT)     :: mos
     848              :       INTEGER, INTENT(IN), OPTIONAL                      :: added_mos
     849              :       LOGICAL, OPTIONAL                                  :: for_aux_fit
     850              : 
     851              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'kpoint_initialize_mos'
     852              : 
     853              :       INTEGER                                            :: handle, ic, ik, is, nadd, nao, nc, &
     854              :                                                             nelectron, nkp_loc, nmo, nmorig(2), &
     855              :                                                             nspin
     856              :       LOGICAL                                            :: aux_fit
     857              :       REAL(KIND=dp)                                      :: flexible_electron_count, maxocc, n_el_f
     858              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     859         3164 :       TYPE(cp_fm_pool_p_type), DIMENSION(:), POINTER     :: ao_ao_fm_pools
     860              :       TYPE(cp_fm_struct_type), POINTER                   :: matrix_struct
     861              :       TYPE(cp_fm_type), POINTER                          :: fmlocal
     862              :       TYPE(kpoint_env_type), POINTER                     :: kp
     863              :       TYPE(qs_matrix_pools_type), POINTER                :: mpools
     864              : 
     865         3164 :       CALL timeset(routineN, handle)
     866              : 
     867         3164 :       IF (PRESENT(for_aux_fit)) THEN
     868           32 :          aux_fit = for_aux_fit
     869              :       ELSE
     870              :          aux_fit = .FALSE.
     871              :       END IF
     872              : 
     873         3164 :       CPASSERT(ASSOCIATED(kpoint))
     874              : 
     875              :       IF (.TRUE. .OR. ASSOCIATED(mos(1)%mo_coeff)) THEN
     876         3164 :          IF (aux_fit) THEN
     877           32 :             CPASSERT(ASSOCIATED(kpoint%kp_aux_env))
     878              :          END IF
     879              : 
     880         3164 :          IF (PRESENT(added_mos)) THEN
     881           90 :             nadd = added_mos
     882              :          ELSE
     883              :             nadd = 0
     884              :          END IF
     885              : 
     886         3164 :          IF (kpoint%use_real_wfn) THEN
     887              :             nc = 1
     888              :          ELSE
     889         3146 :             nc = 2
     890              :          END IF
     891         3164 :          nspin = SIZE(mos, 1)
     892         3164 :          nkp_loc = kpoint%kp_range(2) - kpoint%kp_range(1) + 1
     893         3164 :          IF (nkp_loc > 0) THEN
     894         3164 :             IF (aux_fit) THEN
     895           32 :                CPASSERT(SIZE(kpoint%kp_aux_env) == nkp_loc)
     896              :             ELSE
     897         3132 :                CPASSERT(SIZE(kpoint%kp_env) == nkp_loc)
     898              :             END IF
     899              :             ! allocate the mo sets, correct number of kpoints (local), real/complex, spin
     900        10434 :             DO ik = 1, nkp_loc
     901         7270 :                IF (aux_fit) THEN
     902          218 :                   kp => kpoint%kp_aux_env(ik)%kpoint_env
     903              :                ELSE
     904         7052 :                   kp => kpoint%kp_env(ik)%kpoint_env
     905              :                END IF
     906        52910 :                ALLOCATE (kp%mos(nc, nspin))
     907        15220 :                DO is = 1, nspin
     908              :                   CALL get_mo_set(mos(is), nao=nao, nmo=nmo, nelectron=nelectron, &
     909         7950 :                                   n_el_f=n_el_f, maxocc=maxocc, flexible_electron_count=flexible_electron_count)
     910         7950 :                   nmo = MIN(nao, nmo + nadd)
     911        31100 :                   DO ic = 1, nc
     912              :                      CALL allocate_mo_set(kp%mos(ic, is), nao, nmo, nelectron, n_el_f, maxocc, &
     913        23830 :                                           flexible_electron_count)
     914              :                   END DO
     915              :                END DO
     916              :                ! freshly allocated MOS carry no coefficients: solvers must
     917              :                ! cold-start again until an extrapolation refills them
     918        10434 :                kp%mos_prefilled = .FALSE.
     919              :             END DO
     920              : 
     921              :             ! generate the blacs environment for the kpoint group
     922              :             ! we generate a blacs env for each kpoint group in parallel
     923              :             ! we assume here that the group para_env_inter_kp will connect
     924              :             ! equivalent parts of fm matrices, i.e. no reshuffeling of processors
     925         3164 :             NULLIFY (blacs_env)
     926         3164 :             IF (ASSOCIATED(kpoint%blacs_env)) THEN
     927           38 :                blacs_env => kpoint%blacs_env
     928              :             ELSE
     929         3126 :                CALL cp_blacs_env_create(blacs_env=blacs_env, para_env=kpoint%para_env_kp)
     930         3126 :                kpoint%blacs_env => blacs_env
     931              :             END IF
     932              : 
     933              :             ! set possible new number of MOs
     934         6530 :             DO is = 1, nspin
     935         3366 :                CALL get_mo_set(mos(is), nmo=nmorig(is))
     936         3366 :                nmo = MIN(nao, nmorig(is) + nadd)
     937         6530 :                CALL set_mo_set(mos(is), nmo=nmo)
     938              :             END DO
     939              :             ! matrix pools for the kpoint group, information on MOs is transferred using
     940              :             ! generic mos structure
     941         3164 :             NULLIFY (mpools)
     942         3164 :             CALL mpools_create(mpools=mpools)
     943              :             CALL mpools_rebuild_fm_pools(mpools=mpools, mos=mos, &
     944         3164 :                                          blacs_env=blacs_env, para_env=kpoint%para_env_kp)
     945              : 
     946         3164 :             IF (aux_fit) THEN
     947           32 :                kpoint%mpools_aux_fit => mpools
     948              :             ELSE
     949         3132 :                kpoint%mpools => mpools
     950              :             END IF
     951              : 
     952              :             ! reset old number of MOs
     953         6530 :             DO is = 1, nspin
     954         6530 :                CALL set_mo_set(mos(is), nmo=nmorig(is))
     955              :             END DO
     956              : 
     957              :             ! allocate density matrices
     958         3164 :             CALL mpools_get(mpools, ao_ao_fm_pools=ao_ao_fm_pools)
     959         3164 :             ALLOCATE (fmlocal)
     960         3164 :             CALL fm_pool_create_fm(ao_ao_fm_pools(1)%pool, fmlocal)
     961         3164 :             CALL cp_fm_get_info(fmlocal, matrix_struct=matrix_struct)
     962        10434 :             DO ik = 1, nkp_loc
     963         7270 :                IF (aux_fit) THEN
     964          218 :                   kp => kpoint%kp_aux_env(ik)%kpoint_env
     965              :                ELSE
     966         7052 :                   kp => kpoint%kp_env(ik)%kpoint_env
     967              :                END IF
     968              :                ! density matrix
     969         7270 :                CALL cp_fm_release(kp%pmat)
     970        52910 :                ALLOCATE (kp%pmat(nc, nspin))
     971        15220 :                DO is = 1, nspin
     972        31100 :                   DO ic = 1, nc
     973        23830 :                      CALL cp_fm_create(kp%pmat(ic, is), matrix_struct)
     974              :                   END DO
     975              :                END DO
     976              :                ! energy weighted density matrix
     977         7270 :                CALL cp_fm_release(kp%wmat)
     978        45640 :                ALLOCATE (kp%wmat(nc, nspin))
     979        18384 :                DO is = 1, nspin
     980        31100 :                   DO ic = 1, nc
     981        23830 :                      CALL cp_fm_create(kp%wmat(ic, is), matrix_struct)
     982              :                   END DO
     983              :                END DO
     984              :             END DO
     985         3164 :             CALL fm_pool_give_back_fm(ao_ao_fm_pools(1)%pool, fmlocal)
     986         3164 :             DEALLOCATE (fmlocal)
     987              : 
     988              :          END IF
     989              : 
     990              :       END IF
     991              : 
     992         3164 :       CALL timestop(handle)
     993              : 
     994         3164 :    END SUBROUTINE kpoint_initialize_mos
     995              : 
     996              : ! **************************************************************************************************
     997              : !> \brief ...
     998              : !> \param kpoint ...
     999              : ! **************************************************************************************************
    1000          114 :    SUBROUTINE kpoint_initialize_mo_set(kpoint)
    1001              :       TYPE(kpoint_type), POINTER                         :: kpoint
    1002              : 
    1003              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'kpoint_initialize_mo_set'
    1004              : 
    1005              :       INTEGER                                            :: handle, ic, ik, ikk, ispin
    1006          114 :       TYPE(cp_fm_pool_p_type), DIMENSION(:), POINTER     :: ao_mo_fm_pools
    1007              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
    1008          114 :       TYPE(mo_set_type), DIMENSION(:, :), POINTER        :: moskp
    1009              : 
    1010          114 :       CALL timeset(routineN, handle)
    1011              : 
    1012         1008 :       DO ik = 1, SIZE(kpoint%kp_env)
    1013          894 :          CALL mpools_get(kpoint%mpools, ao_mo_fm_pools=ao_mo_fm_pools)
    1014          894 :          moskp => kpoint%kp_env(ik)%kpoint_env%mos
    1015          894 :          ikk = kpoint%kp_range(1) + ik - 1
    1016          894 :          CPASSERT(ASSOCIATED(moskp))
    1017         1940 :          DO ispin = 1, SIZE(moskp, 2)
    1018         3690 :             DO ic = 1, SIZE(moskp, 1)
    1019         1864 :                CALL get_mo_set(moskp(ic, ispin), mo_coeff=mo_coeff)
    1020         2796 :                IF (.NOT. ASSOCIATED(mo_coeff)) THEN
    1021              :                   CALL init_mo_set(moskp(ic, ispin), &
    1022         1864 :                                    fm_pool=ao_mo_fm_pools(ispin)%pool, name="kpoints")
    1023              :                END IF
    1024              :             END DO
    1025              :          END DO
    1026              :       END DO
    1027              : 
    1028          114 :       CALL timestop(handle)
    1029              : 
    1030          114 :    END SUBROUTINE kpoint_initialize_mo_set
    1031              : 
    1032              : ! **************************************************************************************************
    1033              : !> \brief Generates the mapping of cell indices and linear RS index
    1034              : !>        CELL (0,0,0) is always mapped to index 1
    1035              : !> \param kpoint    Kpoint environment
    1036              : !> \param sab_nl    Defining neighbour list
    1037              : !> \param para_env  Parallel environment
    1038              : !> \param nimages   [output]
    1039              : ! **************************************************************************************************
    1040         3898 :    SUBROUTINE kpoint_init_cell_index(kpoint, sab_nl, para_env, nimages)
    1041              : 
    1042              :       TYPE(kpoint_type), POINTER                         :: kpoint
    1043              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    1044              :          POINTER                                         :: sab_nl
    1045              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1046              :       INTEGER, INTENT(OUT)                               :: nimages
    1047              : 
    1048              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'kpoint_init_cell_index'
    1049              : 
    1050              :       INTEGER                                            :: handle, i1, i2, i3, ic, icount, it, &
    1051              :                                                             ncount
    1052              :       INTEGER, DIMENSION(3)                              :: cell, itm
    1053         3898 :       INTEGER, DIMENSION(:, :), POINTER                  :: index_to_cell, list
    1054         3898 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index, cti
    1055              :       LOGICAL                                            :: new
    1056              :       TYPE(neighbor_list_iterator_p_type), &
    1057         3898 :          DIMENSION(:), POINTER                           :: nl_iterator
    1058              : 
    1059         3898 :       NULLIFY (cell_to_index, index_to_cell)
    1060              : 
    1061         3898 :       CALL timeset(routineN, handle)
    1062              : 
    1063         3898 :       CPASSERT(ASSOCIATED(kpoint))
    1064              : 
    1065         3898 :       ALLOCATE (list(3, 125))
    1066      1952898 :       list = 0
    1067         3898 :       icount = 1
    1068              : 
    1069         3898 :       CALL neighbor_list_iterator_create(nl_iterator, sab_nl)
    1070      1326902 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
    1071      1323004 :          CALL get_iterator_info(nl_iterator, cell=cell)
    1072              : 
    1073      1323004 :          new = .TRUE.
    1074     78922169 :          DO ic = 1, icount
    1075     78719072 :             IF (cell(1) == list(1, ic) .AND. cell(2) == list(2, ic) .AND. &
    1076       203097 :                 cell(3) == list(3, ic)) THEN
    1077              :                new = .FALSE.
    1078              :                EXIT
    1079              :             END IF
    1080              :          END DO
    1081      1326902 :          IF (new) THEN
    1082       203097 :             icount = icount + 1
    1083       203097 :             IF (icount > SIZE(list, 2)) THEN
    1084          607 :                CALL reallocate(list, 1, 3, 1, 2*SIZE(list, 2))
    1085              :             END IF
    1086       812388 :             list(1:3, icount) = cell(1:3)
    1087              :          END IF
    1088              : 
    1089              :       END DO
    1090         3898 :       CALL neighbor_list_iterator_release(nl_iterator)
    1091              : 
    1092       210893 :       itm(1) = MAXVAL(ABS(list(1, 1:icount)))
    1093       210893 :       itm(2) = MAXVAL(ABS(list(2, 1:icount)))
    1094       210893 :       itm(3) = MAXVAL(ABS(list(3, 1:icount)))
    1095         3898 :       CALL para_env%max(itm)
    1096        15592 :       it = MAXVAL(itm(1:3))
    1097         3898 :       IF (ASSOCIATED(kpoint%cell_to_index)) THEN
    1098         3894 :          DEALLOCATE (kpoint%cell_to_index)
    1099              :       END IF
    1100        19490 :       ALLOCATE (kpoint%cell_to_index(-itm(1):itm(1), -itm(2):itm(2), -itm(3):itm(3)))
    1101         3898 :       cell_to_index => kpoint%cell_to_index
    1102         3898 :       cti => cell_to_index
    1103       570260 :       cti(:, :, :) = 0
    1104       210893 :       DO ic = 1, icount
    1105       206995 :          i1 = list(1, ic)
    1106       206995 :          i2 = list(2, ic)
    1107       206995 :          i3 = list(3, ic)
    1108       210893 :          cti(i1, i2, i3) = ic
    1109              :       END DO
    1110      1136622 :       CALL para_env%sum(cti)
    1111         3898 :       ncount = 0
    1112        20528 :       DO i1 = -itm(1), itm(1)
    1113       106530 :          DO i2 = -itm(2), itm(2)
    1114       572290 :             DO i3 = -itm(3), itm(3)
    1115       555660 :                IF (cti(i1, i2, i3) == 0) THEN
    1116       221234 :                   cti(i1, i2, i3) = 1000000
    1117              :                ELSE
    1118       248424 :                   ncount = ncount + 1
    1119       248424 :                   cti(i1, i2, i3) = (ABS(i1) + ABS(i2) + ABS(i3))*1000 + ABS(i3)*100 + ABS(i2)*10 + ABS(i1)
    1120       248424 :                   cti(i1, i2, i3) = cti(i1, i2, i3) + (i1 + i2 + i3)
    1121              :                END IF
    1122              :             END DO
    1123              :          END DO
    1124              :       END DO
    1125              : 
    1126         3898 :       IF (ASSOCIATED(kpoint%index_to_cell)) THEN
    1127         3898 :          DEALLOCATE (kpoint%index_to_cell)
    1128              :       END IF
    1129        11694 :       ALLOCATE (kpoint%index_to_cell(3, ncount))
    1130         3898 :       index_to_cell => kpoint%index_to_cell
    1131       252322 :       DO ic = 1, ncount
    1132    160754864 :          cell = MINLOC(cti)
    1133       248424 :          i1 = cell(1) - 1 - itm(1)
    1134       248424 :          i2 = cell(2) - 1 - itm(2)
    1135       248424 :          i3 = cell(3) - 1 - itm(3)
    1136       248424 :          cti(i1, i2, i3) = 1000000
    1137       248424 :          index_to_cell(1, ic) = i1
    1138       248424 :          index_to_cell(2, ic) = i2
    1139       252322 :          index_to_cell(3, ic) = i3
    1140              :       END DO
    1141       570260 :       cti(:, :, :) = 0
    1142       252322 :       DO ic = 1, ncount
    1143       248424 :          i1 = index_to_cell(1, ic)
    1144       248424 :          i2 = index_to_cell(2, ic)
    1145       248424 :          i3 = index_to_cell(3, ic)
    1146       252322 :          cti(i1, i2, i3) = ic
    1147              :       END DO
    1148              : 
    1149              :       ! keep pointer to this neighborlist
    1150         3898 :       kpoint%sab_nl => sab_nl
    1151              : 
    1152              :       ! set number of images
    1153         3898 :       nimages = SIZE(index_to_cell, 2)
    1154              : 
    1155         3898 :       DEALLOCATE (list)
    1156              : 
    1157         3898 :       CALL timestop(handle)
    1158              : 
    1159         3898 :    END SUBROUTINE kpoint_init_cell_index
    1160              : 
    1161              : ! **************************************************************************************************
    1162              : !> \brief Transformation of real space matrices to a kpoint
    1163              : !> \param rmatrix  Real part of kpoint matrix
    1164              : !> \param cmatrix  Complex part of kpoint matrix (optional)
    1165              : !> \param rsmat    Real space matrices
    1166              : !> \param ispin    Spin index
    1167              : !> \param xkp      Kpoint coordinates
    1168              : !> \param cell_to_index   mapping of cell indices to RS index
    1169              : !> \param sab_nl   Defining neighbor list
    1170              : !> \param is_complex  Matrix to be transformed is imaginary
    1171              : !> \param rs_sign  Matrix to be transformed is csaled by rs_sign
    1172              : ! **************************************************************************************************
    1173       586752 :    SUBROUTINE rskp_transform(rmatrix, cmatrix, rsmat, ispin, &
    1174              :                              xkp, cell_to_index, sab_nl, is_complex, rs_sign)
    1175              : 
    1176              :       TYPE(dbcsr_type)                                   :: rmatrix
    1177              :       TYPE(dbcsr_type), OPTIONAL                         :: cmatrix
    1178              :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: rsmat
    1179              :       INTEGER, INTENT(IN)                                :: ispin
    1180              :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: xkp
    1181              :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
    1182              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    1183              :          POINTER                                         :: sab_nl
    1184              :       LOGICAL, INTENT(IN), OPTIONAL                      :: is_complex
    1185              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: rs_sign
    1186              : 
    1187              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'rskp_transform'
    1188              : 
    1189              :       INTEGER                                            :: handle, iatom, ic, icol, irow, jatom, &
    1190              :                                                             nimg
    1191              :       INTEGER, DIMENSION(3)                              :: cell
    1192              :       LOGICAL                                            :: do_symmetric, found, my_complex, &
    1193              :                                                             wfn_real_only
    1194              :       REAL(KIND=dp)                                      :: arg, coskl, fsign, fsym, sinkl
    1195       293376 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: cblock, rblock, rsblock
    1196              :       TYPE(neighbor_list_iterator_p_type), &
    1197       293376 :          DIMENSION(:), POINTER                           :: nl_iterator
    1198              : 
    1199       293376 :       CALL timeset(routineN, handle)
    1200              : 
    1201       293376 :       my_complex = .FALSE.
    1202       293376 :       IF (PRESENT(is_complex)) my_complex = is_complex
    1203              : 
    1204       293376 :       fsign = 1.0_dp
    1205       293376 :       IF (PRESENT(rs_sign)) fsign = rs_sign
    1206              : 
    1207       293376 :       wfn_real_only = .TRUE.
    1208       293376 :       IF (PRESENT(cmatrix)) wfn_real_only = .FALSE.
    1209              : 
    1210       293376 :       nimg = SIZE(rsmat, 2)
    1211              : 
    1212       293376 :       CALL get_neighbor_list_set_p(neighbor_list_sets=sab_nl, symmetric=do_symmetric)
    1213              : 
    1214       293376 :       CALL neighbor_list_iterator_create(nl_iterator, sab_nl)
    1215    104270755 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
    1216    103977379 :          CALL get_iterator_info(nl_iterator, iatom=iatom, jatom=jatom, cell=cell)
    1217              : 
    1218              :          ! fsym = +- 1 is due to real space matrices being non-symmetric (although in a symmtric type)
    1219              :          ! with the link S_mu^0,nu^b = S_nu^0,mu^-b, and the KP matrices beeing Hermitian
    1220    103977379 :          fsym = 1.0_dp
    1221    103977379 :          irow = iatom
    1222    103977379 :          icol = jatom
    1223    103977379 :          IF (do_symmetric .AND. (iatom > jatom)) THEN
    1224     44285608 :             irow = jatom
    1225     44285608 :             icol = iatom
    1226     44285608 :             fsym = -1.0_dp
    1227              :          END IF
    1228              : 
    1229    103977379 :          ic = cell_to_index(cell(1), cell(2), cell(3))
    1230    103977379 :          IF (ic < 1 .OR. ic > nimg) CYCLE
    1231              : 
    1232    103976635 :          arg = REAL(cell(1), dp)*xkp(1) + REAL(cell(2), dp)*xkp(2) + REAL(cell(3), dp)*xkp(3)
    1233    103976635 :          IF (my_complex) THEN
    1234      3466896 :             coskl = fsign*fsym*COS(twopi*arg)
    1235      3466896 :             sinkl = fsign*SIN(twopi*arg)
    1236              :          ELSE
    1237    100509739 :             coskl = fsign*COS(twopi*arg)
    1238    100509739 :             sinkl = fsign*fsym*SIN(twopi*arg)
    1239              :          END IF
    1240              : 
    1241              :          CALL dbcsr_get_block_p(matrix=rsmat(ispin, ic)%matrix, row=irow, col=icol, &
    1242    103976635 :                                 block=rsblock, found=found)
    1243    103976635 :          IF (.NOT. found) CYCLE
    1244              : 
    1245    104270011 :          IF (wfn_real_only) THEN
    1246              :             CALL dbcsr_get_block_p(matrix=rmatrix, row=irow, col=icol, &
    1247       529850 :                                    block=rblock, found=found)
    1248       529850 :             IF (.NOT. found) CYCLE
    1249    249444630 :             rblock = rblock + coskl*rsblock
    1250              :          ELSE
    1251              :             CALL dbcsr_get_block_p(matrix=rmatrix, row=irow, col=icol, &
    1252    103446785 :                                    block=rblock, found=found)
    1253    103446785 :             IF (.NOT. found) CYCLE
    1254              :             CALL dbcsr_get_block_p(matrix=cmatrix, row=irow, col=icol, &
    1255    103446785 :                                    block=cblock, found=found)
    1256    103446785 :             IF (.NOT. found) CYCLE
    1257  13238731357 :             rblock = rblock + coskl*rsblock
    1258  13238731357 :             cblock = cblock + sinkl*rsblock
    1259              :          END IF
    1260              : 
    1261              :       END DO
    1262       293376 :       CALL neighbor_list_iterator_release(nl_iterator)
    1263              : 
    1264       293376 :       CALL timestop(handle)
    1265              : 
    1266       293376 :    END SUBROUTINE rskp_transform
    1267              : 
    1268              : ! **************************************************************************************************
    1269              : !> \brief Prepare a batched real-cell to complete reciprocal-grid transform for local DBCSR blocks.
    1270              : !>        The stored blocks remain MPI local.  Irregular or too-large grids return used_fft=.FALSE.
    1271              : !> \param grid cached transformed local blocks and their DBCSR coordinates
    1272              : !> \param rmatrix allocated output template defining the local block layout
    1273              : !> \param rsmat real-space matrix set
    1274              : !> \param ispin spin component of rsmat
    1275              : !> \param xkp complete reciprocal grid in arbitrary order
    1276              : !> \param nkp_grid reciprocal grid dimensions
    1277              : !> \param cell_to_index real-cell coordinate mapping
    1278              : !> \param sab_nl neighbor list defining the stored block orientation
    1279              : !> \param used_fft whether the cache was prepared
    1280              : !> \param is_complex whether the real-space operator is imaginary
    1281              : !> \param rs_sign optional overall sign
    1282              : !> \param max_storage_bytes optional conservative per-rank memory limit
    1283              : ! **************************************************************************************************
    1284          216 :    SUBROUTINE rskp_transform_grid_prepare(grid, rmatrix, rsmat, ispin, xkp, nkp_grid, &
    1285              :                                           cell_to_index, sab_nl, used_fft, is_complex, rs_sign, &
    1286              :                                           max_storage_bytes)
    1287              : 
    1288              :       TYPE(rskp_grid_type), INTENT(INOUT)                :: grid
    1289              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: rmatrix
    1290              :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: rsmat
    1291              :       INTEGER, INTENT(IN)                                :: ispin
    1292              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: xkp
    1293              :       INTEGER, DIMENSION(3), INTENT(IN)                  :: nkp_grid
    1294              :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
    1295              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    1296              :          POINTER                                         :: sab_nl
    1297              :       LOGICAL, INTENT(OUT)                               :: used_fft
    1298              :       LOGICAL, INTENT(IN), OPTIONAL                      :: is_complex
    1299              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: rs_sign
    1300              :       INTEGER(KIND=int_8), INTENT(IN), OPTIONAL          :: max_storage_bytes
    1301              : 
    1302              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'rskp_transform_grid_prepare'
    1303              : 
    1304              :       INTEGER                                            :: handle, i1, i2, i3, iatom, iblock, ic, &
    1305              :                                                             icol, irow, jatom, nblkcols, nblkrows, &
    1306              :                                                             nblocks, ncell, nelem, nimg, nkp, &
    1307              :                                                             nvalues
    1308              :       INTEGER(KIND=int_8)                                :: memory_limit, storage_bytes
    1309          216 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: block_map, index_to_cell
    1310          216 :       INTEGER, ALLOCATABLE, DIMENSION(:, :, :)           :: fft_cell_to_index
    1311              :       INTEGER, DIMENSION(3)                              :: cell, fft_cell
    1312              :       LOGICAL                                            :: do_symmetric, found, my_complex
    1313              :       REAL(KIND=dp)                                      :: fsign, fsym, value_sign
    1314          216 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: values_rs
    1315          216 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: rblock, rsblock
    1316              :       TYPE(dbcsr_iterator_type)                          :: iter
    1317              :       TYPE(neighbor_list_iterator_p_type), &
    1318          216 :          DIMENSION(:), POINTER                           :: nl_iterator
    1319              : 
    1320          216 :       CALL timeset(routineN, handle)
    1321          216 :       CALL rskp_transform_grid_release(grid)
    1322          216 :       used_fft = .FALSE.
    1323              : 
    1324          216 :       nkp = SIZE(xkp, 2)
    1325          216 :       nimg = SIZE(rsmat, 2)
    1326          864 :       IF (nkp < 2 .OR. PRODUCT(nkp_grid) /= nkp) THEN
    1327          208 :          CALL timestop(handle)
    1328          208 :          RETURN
    1329              :       END IF
    1330            8 :       IF (.NOT. regular_kpoint_grid(xkp, nkp_grid)) THEN
    1331            0 :          CALL timestop(handle)
    1332            0 :          RETURN
    1333              :       END IF
    1334              : 
    1335            8 :       nblocks = 0
    1336            8 :       nvalues = 0
    1337            8 :       CALL dbcsr_iterator_start(iter, rmatrix)
    1338          152 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
    1339          144 :          CALL dbcsr_iterator_next_block(iter, irow, icol, rblock)
    1340          144 :          nblocks = nblocks + 1
    1341          440 :          nvalues = nvalues + SIZE(rblock)
    1342              :       END DO
    1343            8 :       CALL dbcsr_iterator_stop(iter)
    1344            8 :       IF (nblocks == 0 .OR. nvalues == 0) THEN
    1345            0 :          CALL timestop(handle)
    1346            0 :          RETURN
    1347              :       END IF
    1348              : 
    1349            8 :       CALL dbcsr_get_info(rmatrix, nblkrows_total=nblkrows, nblkcols_total=nblkcols)
    1350           32 :       ALLOCATE (block_map(nblkrows, nblkcols), source=0)
    1351            0 :       ALLOCATE (grid%block_row(nblocks), grid%block_col(nblocks), &
    1352           48 :                 grid%block_offset(nblocks), grid%block_nelem(nblocks))
    1353            8 :       iblock = 0
    1354            8 :       nelem = 0
    1355            8 :       CALL dbcsr_iterator_start(iter, rmatrix)
    1356          152 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
    1357          144 :          CALL dbcsr_iterator_next_block(iter, irow, icol, rblock)
    1358          144 :          iblock = iblock + 1
    1359          144 :          grid%block_row(iblock) = irow
    1360          144 :          grid%block_col(iblock) = icol
    1361          144 :          grid%block_offset(iblock) = nelem + 1
    1362          432 :          grid%block_nelem(iblock) = SIZE(rblock)
    1363          144 :          block_map(irow, icol) = iblock
    1364          440 :          nelem = nelem + SIZE(rblock)
    1365              :       END DO
    1366            8 :       CALL dbcsr_iterator_stop(iter)
    1367              : 
    1368              :       ALLOCATE (fft_cell_to_index(LBOUND(cell_to_index, 1):UBOUND(cell_to_index, 1), &
    1369              :                                   LBOUND(cell_to_index, 2):UBOUND(cell_to_index, 2), &
    1370           40 :                                   LBOUND(cell_to_index, 3):UBOUND(cell_to_index, 3)), source=0)
    1371            8 :       ncell = 0
    1372           80 :       DO i3 = LBOUND(cell_to_index, 3), UBOUND(cell_to_index, 3)
    1373          568 :          DO i2 = LBOUND(cell_to_index, 2), UBOUND(cell_to_index, 2)
    1374         3976 :             DO i1 = LBOUND(cell_to_index, 1), UBOUND(cell_to_index, 1)
    1375         2744 :                IF (cell_to_index(i1, i2, i3) < 1 .OR. cell_to_index(i1, i2, i3) > nimg) CYCLE
    1376         1360 :                IF (fft_cell_to_index(i1, i2, i3) == 0) THEN
    1377          720 :                   ncell = ncell + 1
    1378          720 :                   fft_cell_to_index(i1, i2, i3) = ncell
    1379              :                END IF
    1380         1752 :                IF (fft_cell_to_index(-i1, -i2, -i3) == 0) THEN
    1381          712 :                   ncell = ncell + 1
    1382          712 :                   fft_cell_to_index(-i1, -i2, -i3) = ncell
    1383              :                END IF
    1384              :             END DO
    1385              :          END DO
    1386              :       END DO
    1387            8 :       IF (ncell == 0) THEN
    1388            0 :          CALL rskp_transform_grid_release(grid)
    1389            0 :          CALL timestop(handle)
    1390            0 :          RETURN
    1391              :       END IF
    1392              : 
    1393            8 :       memory_limit = 512_int_8*1024_int_8**2
    1394            8 :       IF (PRESENT(max_storage_bytes)) memory_limit = max_storage_bytes
    1395              :       ! Include the real-cell input, complex result and conservative FFT work/padding allowance.
    1396              :       storage_bytes = INT(nvalues, int_8)*(8_int_8*INT(ncell, int_8) + &
    1397            8 :                                            80_int_8*INT(nkp, int_8))
    1398            8 :       IF (storage_bytes > memory_limit) THEN
    1399            0 :          CALL rskp_transform_grid_release(grid)
    1400            0 :          CALL timestop(handle)
    1401            0 :          RETURN
    1402              :       END IF
    1403              : 
    1404           24 :       ALLOCATE (index_to_cell(3, ncell), source=0)
    1405           80 :       DO i3 = LBOUND(fft_cell_to_index, 3), UBOUND(fft_cell_to_index, 3)
    1406          568 :          DO i2 = LBOUND(fft_cell_to_index, 2), UBOUND(fft_cell_to_index, 2)
    1407         3976 :             DO i1 = LBOUND(fft_cell_to_index, 1), UBOUND(fft_cell_to_index, 1)
    1408         2744 :                ic = fft_cell_to_index(i1, i2, i3)
    1409         7432 :                IF (ic > 0) index_to_cell(:, ic) = [i1, i2, i3]
    1410              :             END DO
    1411              :          END DO
    1412              :       END DO
    1413              : 
    1414           32 :       ALLOCATE (values_rs(nvalues, 1, ncell), source=0.0_dp)
    1415           32 :       ALLOCATE (grid%values(nvalues, 1, nkp))
    1416            8 :       my_complex = .FALSE.
    1417            8 :       IF (PRESENT(is_complex)) my_complex = is_complex
    1418            8 :       fsign = 1.0_dp
    1419            8 :       IF (PRESENT(rs_sign)) fsign = rs_sign
    1420              : 
    1421            8 :       CALL get_neighbor_list_set_p(neighbor_list_sets=sab_nl, symmetric=do_symmetric)
    1422            8 :       CALL neighbor_list_iterator_create(nl_iterator, sab_nl)
    1423        11432 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
    1424        11424 :          CALL get_iterator_info(nl_iterator, iatom=iatom, jatom=jatom, cell=cell)
    1425              : 
    1426        11424 :          fsym = 1.0_dp
    1427        11424 :          irow = iatom
    1428        11424 :          icol = jatom
    1429        11424 :          IF (do_symmetric .AND. iatom > jatom) THEN
    1430         5056 :             irow = jatom
    1431         5056 :             icol = iatom
    1432         5056 :             fsym = -1.0_dp
    1433              :          END IF
    1434        11424 :          IF (irow < 1 .OR. irow > nblkrows .OR. icol < 1 .OR. icol > nblkcols) CYCLE
    1435        11424 :          iblock = block_map(irow, icol)
    1436        11424 :          IF (iblock == 0) CYCLE
    1437              : 
    1438        11424 :          ic = cell_to_index(cell(1), cell(2), cell(3))
    1439        11424 :          IF (ic < 1 .OR. ic > nimg) CYCLE
    1440              :          CALL dbcsr_get_block_p(matrix=rsmat(ispin, ic)%matrix, row=irow, col=icol, &
    1441        11424 :                                 block=rsblock, found=found)
    1442        11424 :          IF (.NOT. found) CYCLE
    1443              : 
    1444        11424 :          fft_cell = cell
    1445        11424 :          value_sign = fsign
    1446        26592 :          IF (fsym < 0.0_dp) fft_cell = -cell
    1447        11424 :          IF (my_complex) value_sign = value_sign*fsym
    1448        11424 :          ic = fft_cell_to_index(fft_cell(1), fft_cell(2), fft_cell(3))
    1449        11424 :          nelem = grid%block_nelem(iblock)
    1450        11424 :          i1 = grid%block_offset(iblock)
    1451              :          values_rs(i1:i1 + nelem - 1, 1, ic) = values_rs(i1:i1 + nelem - 1, 1, ic) + &
    1452       308456 :                                                value_sign*RESHAPE(rsblock, [nelem])
    1453              :       END DO
    1454            8 :       CALL neighbor_list_iterator_release(nl_iterator)
    1455              : 
    1456            8 :       CALL cell_to_k_grid_fft(values_rs, index_to_cell, xkp, nkp_grid, grid%values, used_fft)
    1457            8 :       IF (used_fft) THEN
    1458            8 :          grid%ready = .TRUE.
    1459              :       ELSE
    1460            0 :          CALL rskp_transform_grid_release(grid)
    1461              :       END IF
    1462              : 
    1463            8 :       CALL timestop(handle)
    1464              : 
    1465          464 :    END SUBROUTINE rskp_transform_grid_prepare
    1466              : 
    1467              : ! **************************************************************************************************
    1468              : !> \brief Extract one reciprocal-grid matrix from a prepared local DBCSR block cache.
    1469              : !> \param grid ...
    1470              : !> \param ikp ...
    1471              : !> \param rmatrix ...
    1472              : !> \param cmatrix ...
    1473              : ! **************************************************************************************************
    1474          512 :    SUBROUTINE rskp_transform_grid_extract(grid, ikp, rmatrix, cmatrix)
    1475              : 
    1476              :       TYPE(rskp_grid_type), INTENT(IN)                   :: grid
    1477              :       INTEGER, INTENT(IN)                                :: ikp
    1478              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: rmatrix
    1479              :       TYPE(dbcsr_type), INTENT(INOUT), OPTIONAL          :: cmatrix
    1480              : 
    1481              :       INTEGER                                            :: iblock, ioffset, nelem
    1482              :       LOGICAL                                            :: found
    1483          512 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: cblock, rblock
    1484              : 
    1485            0 :       CPASSERT(grid%ready)
    1486          512 :       CPASSERT(ikp >= 1 .AND. ikp <= SIZE(grid%values, 3))
    1487          512 :       CALL dbcsr_set(rmatrix, 0.0_dp)
    1488          512 :       IF (PRESENT(cmatrix)) CALL dbcsr_set(cmatrix, 0.0_dp)
    1489              : 
    1490         9728 :       DO iblock = 1, SIZE(grid%block_row)
    1491         9216 :          ioffset = grid%block_offset(iblock)
    1492         9216 :          nelem = grid%block_nelem(iblock)
    1493              :          CALL dbcsr_get_block_p(rmatrix, grid%block_row(iblock), grid%block_col(iblock), &
    1494         9216 :                                 rblock, found=found)
    1495         9216 :          CPASSERT(found)
    1496              :          rblock = RESHAPE(REAL(grid%values(ioffset:ioffset + nelem - 1, 1, ikp), KIND=dp), &
    1497       258048 :                           SHAPE(rblock))
    1498        18944 :          IF (PRESENT(cmatrix)) THEN
    1499              :             CALL dbcsr_get_block_p(cmatrix, grid%block_row(iblock), grid%block_col(iblock), &
    1500         9216 :                                    cblock, found=found)
    1501         9216 :             CPASSERT(found)
    1502       258048 :             cblock = RESHAPE(AIMAG(grid%values(ioffset:ioffset + nelem - 1, 1, ikp)), SHAPE(cblock))
    1503              :          END IF
    1504              :       END DO
    1505              : 
    1506          512 :    END SUBROUTINE rskp_transform_grid_extract
    1507              : 
    1508              : ! **************************************************************************************************
    1509              : !> \brief Release a reciprocal-grid transformation cache.
    1510              : !> \param grid ...
    1511              : ! **************************************************************************************************
    1512       141072 :    SUBROUTINE rskp_transform_grid_release(grid)
    1513              : 
    1514              :       TYPE(rskp_grid_type), INTENT(INOUT)                :: grid
    1515              : 
    1516       141072 :       IF (ALLOCATED(grid%values)) DEALLOCATE (grid%values)
    1517       141072 :       IF (ALLOCATED(grid%block_row)) DEALLOCATE (grid%block_row)
    1518       141072 :       IF (ALLOCATED(grid%block_col)) DEALLOCATE (grid%block_col)
    1519       141072 :       IF (ALLOCATED(grid%block_offset)) DEALLOCATE (grid%block_offset)
    1520       141072 :       IF (ALLOCATED(grid%block_nelem)) DEALLOCATE (grid%block_nelem)
    1521       141072 :       grid%ready = .FALSE.
    1522              : 
    1523       141072 :    END SUBROUTINE rskp_transform_grid_release
    1524              : 
    1525              : ! **************************************************************************************************
    1526              : !> \brief Given the eigenvalues of all kpoints, calculates the occupation numbers
    1527              : !> \param kpoint  Kpoint environment
    1528              : !> \param smear   Smearing information
    1529              : !> \param probe ...
    1530              : !> \param added_mos_auto ...
    1531              : !> \param added_mos_auto_grow ...
    1532              : !> \param separate_spin_occupations enforce the electron count of each spin channel
    1533              : ! **************************************************************************************************
    1534        36112 :    SUBROUTINE kpoint_set_mo_occupation( &
    1535        36112 :       kpoint, smear, probe, added_mos_auto, added_mos_auto_grow, separate_spin_occupations)
    1536              : 
    1537              :       TYPE(kpoint_type), POINTER                         :: kpoint
    1538              :       TYPE(smear_type)                                   :: smear
    1539              :       TYPE(hairy_probes_type), DIMENSION(:), OPTIONAL, &
    1540              :          POINTER                                         :: probe
    1541              :       LOGICAL, DIMENSION(:), INTENT(IN), OPTIONAL        :: added_mos_auto
    1542              :       LOGICAL, INTENT(OUT), OPTIONAL                     :: added_mos_auto_grow
    1543              :       LOGICAL, INTENT(IN), OPTIONAL                      :: separate_spin_occupations
    1544              : 
    1545              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'kpoint_set_mo_occupation'
    1546              : 
    1547              :       INTEGER                                            :: handle, ik, ikpgr, ispin, kplocal, nao, &
    1548              :                                                             nb, ncol_global, ne_a, ne_b, &
    1549              :                                                             nelectron, nkp, nmo, nrow_global, nspin
    1550              :       INTEGER, DIMENSION(2)                              :: kp_range
    1551              :       LOGICAL                                            :: my_added_mos_auto_grow, &
    1552              :                                                             my_separate_spin_occupations
    1553              :       REAL(KIND=dp)                                      :: kTS, kTS_spin(2), mu, mus(2), nel
    1554        36112 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: smatrix
    1555        36112 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: weig, wocc
    1556        36112 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :, :)  :: icoeff, rcoeff
    1557        36112 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: eigenvalues, occupation, wkp
    1558              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
    1559              :       TYPE(kpoint_env_type), POINTER                     :: kp
    1560              :       TYPE(mo_set_type), POINTER                         :: mo_set
    1561              :       TYPE(mp_para_env_type), POINTER                    :: para_env_inter_kp
    1562              : 
    1563        36112 :       CALL timeset(routineN, handle)
    1564              : 
    1565        36112 :       my_added_mos_auto_grow = .FALSE.
    1566        36112 :       IF (PRESENT(added_mos_auto_grow)) added_mos_auto_grow = .FALSE.
    1567              : 
    1568              :       ! first collect all the eigenvalues
    1569        36112 :       CALL get_kpoint_info(kpoint, nkp=nkp)
    1570        36112 :       kp => kpoint%kp_env(1)%kpoint_env
    1571        36112 :       nspin = SIZE(kp%mos, 2)
    1572        36112 :       my_separate_spin_occupations = smear%fixed_mag_mom > 0.0_dp
    1573        36112 :       IF (PRESENT(separate_spin_occupations)) THEN
    1574         2092 :          my_separate_spin_occupations = my_separate_spin_occupations .OR. separate_spin_occupations
    1575              :       END IF
    1576        36112 :       mo_set => kp%mos(1, 1)
    1577        36112 :       CALL get_mo_set(mo_set, nmo=nmo, nao=nao, nelectron=nelectron)
    1578        36112 :       ne_a = nelectron
    1579        36112 :       IF (nspin == 2) THEN
    1580         2222 :          CALL get_mo_set(kp%mos(1, 2), nmo=nb, nelectron=ne_b)
    1581         2222 :          CPASSERT(nmo == nb)
    1582              :       END IF
    1583       288896 :       ALLOCATE (weig(nmo, nkp, nspin), wocc(nmo, nkp, nspin))
    1584        36112 :       weig = 0.0_dp
    1585        36112 :       wocc = 0.0_dp
    1586        36112 :       IF (PRESENT(probe)) THEN
    1587            0 :          ALLOCATE (rcoeff(nao, nmo, nkp, nspin), icoeff(nao, nmo, nkp, nspin))
    1588            0 :          rcoeff = 0.0_dp !coeff, real part
    1589            0 :          icoeff = 0.0_dp !coeff, imaginary part
    1590              :       END IF
    1591        36112 :       CALL get_kpoint_info(kpoint, kp_range=kp_range)
    1592        36112 :       kplocal = kp_range(2) - kp_range(1) + 1
    1593       102274 :       DO ikpgr = 1, kplocal
    1594        66162 :          ik = kp_range(1) + ikpgr - 1
    1595        66162 :          kp => kpoint%kp_env(ikpgr)%kpoint_env
    1596       174970 :          DO ispin = 1, nspin
    1597        72696 :             mo_set => kp%mos(1, ispin)
    1598        72696 :             CALL get_mo_set(mo_set, eigenvalues=eigenvalues)
    1599      1301550 :             weig(1:nmo, ik, ispin) = eigenvalues(1:nmo)
    1600       138858 :             IF (PRESENT(probe)) THEN
    1601            0 :                CALL get_mo_set(mo_set, mo_coeff=mo_coeff)
    1602              :                CALL cp_fm_get_info(mo_coeff, &
    1603              :                                    nrow_global=nrow_global, &
    1604            0 :                                    ncol_global=ncol_global)
    1605            0 :                ALLOCATE (smatrix(nrow_global, ncol_global))
    1606            0 :                CALL cp_fm_get_submatrix(mo_coeff, smatrix)
    1607              : 
    1608            0 :                rcoeff(1:nao, 1:nmo, ik, ispin) = smatrix(1:nrow_global, 1:ncol_global)
    1609              : 
    1610            0 :                DEALLOCATE (smatrix)
    1611              : 
    1612            0 :                mo_set => kp%mos(2, ispin)
    1613              : 
    1614            0 :                CALL get_mo_set(mo_set, mo_coeff=mo_coeff)
    1615              :                CALL cp_fm_get_info(mo_coeff, &
    1616              :                                    nrow_global=nrow_global, &
    1617            0 :                                    ncol_global=ncol_global)
    1618            0 :                ALLOCATE (smatrix(nrow_global, ncol_global))
    1619            0 :                CALL cp_fm_get_submatrix(mo_coeff, smatrix)
    1620              : 
    1621            0 :                icoeff(1:nao, 1:nmo, ik, ispin) = smatrix(1:nrow_global, 1:ncol_global)
    1622              : 
    1623            0 :                mo_set => kp%mos(1, ispin)
    1624              : 
    1625            0 :                DEALLOCATE (smatrix)
    1626              :             END IF
    1627              :          END DO
    1628              :       END DO
    1629        36112 :       CALL get_kpoint_info(kpoint, para_env_inter_kp=para_env_inter_kp)
    1630        36112 :       CALL para_env_inter_kp%sum(weig)
    1631              : 
    1632        36112 :       IF (PRESENT(probe)) THEN
    1633            0 :          CALL para_env_inter_kp%sum(rcoeff)
    1634            0 :          CALL para_env_inter_kp%sum(icoeff)
    1635              :       END IF
    1636              : 
    1637        36112 :       CALL get_kpoint_info(kpoint, wkp=wkp)
    1638        36112 :       kTS_spin = 0.0_dp
    1639              : 
    1640              : !calling of HP module HERE, before smear
    1641        36112 :       IF (PRESENT(probe)) THEN
    1642            0 :          smear%do_smear = .FALSE. !ensures smearing is switched off
    1643              : 
    1644            0 :          IF (nspin == 1) THEN
    1645            0 :             nel = REAL(nelectron, KIND=dp)
    1646              :             CALL probe_occupancy_kp(wocc(:, :, :), mus(1), kTS, weig(:, :, :), rcoeff(:, :, :, :), icoeff(:, :, :, :), 2.0d0, &
    1647            0 :                                     probe, nel, wkp)
    1648              :          ELSE
    1649            0 :             nel = REAL(ne_a, KIND=dp) + REAL(ne_b, KIND=dp)
    1650              :             CALL probe_occupancy_kp(wocc(:, :, :), mu, kTS, weig(:, :, :), rcoeff(:, :, :, :), icoeff(:, :, :, :), 1.0d0, &
    1651            0 :                                     probe, nel, wkp)
    1652            0 :             kTS = kTS/2._dp
    1653            0 :             mus(1:2) = mu
    1654              :          END IF
    1655              : 
    1656            0 :          DO ikpgr = 1, kplocal
    1657            0 :             ik = kp_range(1) + ikpgr - 1
    1658            0 :             kp => kpoint%kp_env(ikpgr)%kpoint_env
    1659            0 :             DO ispin = 1, nspin
    1660            0 :                mo_set => kp%mos(1, ispin)
    1661            0 :                CALL get_mo_set(mo_set, eigenvalues=eigenvalues, occupation_numbers=occupation)
    1662            0 :                eigenvalues(1:nmo) = weig(1:nmo, ik, ispin)
    1663            0 :                occupation(1:nmo) = wocc(1:nmo, ik, ispin)
    1664            0 :                mo_set%kTS = kTS
    1665            0 :                mo_set%mu = mus(ispin)
    1666              : 
    1667            0 :                CALL get_mo_set(mo_set, mo_coeff=mo_coeff)
    1668              :                !get smatrix for kpoint_env ikp
    1669              :                CALL cp_fm_get_info(mo_coeff, &
    1670              :                                    nrow_global=nrow_global, &
    1671            0 :                                    ncol_global=ncol_global)
    1672            0 :                ALLOCATE (smatrix(nrow_global, ncol_global))
    1673            0 :                CALL cp_fm_get_submatrix(mo_coeff, smatrix)
    1674              : 
    1675            0 :                smatrix(1:nrow_global, 1:ncol_global) = rcoeff(1:nao, 1:nmo, ik, ispin)
    1676            0 :                DEALLOCATE (smatrix)
    1677              : 
    1678            0 :                mo_set => kp%mos(2, ispin)
    1679              : 
    1680            0 :                CALL get_mo_set(mo_set, mo_coeff=mo_coeff)
    1681              :                !get smatrix for kpoint_env ikp
    1682              :                CALL cp_fm_get_info(mo_coeff, &
    1683              :                                    nrow_global=nrow_global, &
    1684            0 :                                    ncol_global=ncol_global)
    1685            0 :                ALLOCATE (smatrix(nrow_global, ncol_global))
    1686            0 :                CALL cp_fm_get_submatrix(mo_coeff, smatrix)
    1687              : 
    1688            0 :                smatrix(1:nrow_global, 1:ncol_global) = icoeff(1:nao, 1:nmo, ik, ispin)
    1689            0 :                DEALLOCATE (smatrix)
    1690              : 
    1691            0 :                mo_set => kp%mos(1, ispin)
    1692              : 
    1693              :             END DO
    1694              :          END DO
    1695              : 
    1696            0 :          DEALLOCATE (weig, wocc, rcoeff, icoeff)
    1697              : 
    1698              :       END IF
    1699              : 
    1700              :       IF (PRESENT(probe) .EQV. .FALSE.) THEN
    1701        36112 :          IF (smear%do_smear) THEN
    1702        28356 :             SELECT CASE (smear%method)
    1703              :             CASE (smear_fermi_dirac)
    1704              :                ! finite electronic temperature
    1705        14036 :                IF (nspin == 1) THEN
    1706        13362 :                   nel = REAL(nelectron, KIND=dp)
    1707              :                   CALL Smearkp(wocc(:, :, 1), mus(1), kTS, weig(:, :, 1), nel, wkp, &
    1708        13362 :                                smear%electronic_temperature, 2.0_dp, smear_fermi_dirac)
    1709        13362 :                   kTS_spin(1) = kTS
    1710          674 :                ELSE IF (my_separate_spin_occupations) THEN
    1711           86 :                   nel = REAL(ne_a, KIND=dp)
    1712              :                   CALL Smearkp(wocc(:, :, 1), mus(1), kTS, weig(:, :, 1), nel, wkp, &
    1713           86 :                                smear%electronic_temperature, 1.0_dp, smear_fermi_dirac)
    1714           86 :                   kTS_spin(1) = kTS
    1715           86 :                   nel = REAL(ne_b, KIND=dp)
    1716              :                   CALL Smearkp(wocc(:, :, 2), mus(2), kTS, weig(:, :, 2), nel, wkp, &
    1717           86 :                                smear%electronic_temperature, 1.0_dp, smear_fermi_dirac)
    1718           86 :                   kTS_spin(2) = kTS
    1719              :                ELSE
    1720          588 :                   nel = REAL(ne_a, KIND=dp) + REAL(ne_b, KIND=dp)
    1721              :                   CALL Smearkp2(wocc(:, :, :), mu, kTS, weig(:, :, :), nel, wkp, &
    1722          588 :                                 smear%electronic_temperature, smear_fermi_dirac)
    1723          588 :                   kTS = kTS/2._dp
    1724         1764 :                   kTS_spin(1:2) = kTS
    1725         1764 :                   mus(1:2) = mu
    1726              :                END IF
    1727              :             CASE (smear_gaussian, smear_mp, smear_mv)
    1728          284 :                IF (nspin == 1) THEN
    1729          252 :                   nel = REAL(nelectron, KIND=dp)
    1730              :                   CALL Smearkp(wocc(:, :, 1), mus(1), kTS, weig(:, :, 1), nel, wkp, &
    1731          252 :                                smear%smearing_width, 2.0_dp, smear%method)
    1732          252 :                   kTS_spin(1) = kTS
    1733           32 :                ELSE IF (my_separate_spin_occupations) THEN
    1734            0 :                   nel = REAL(ne_a, KIND=dp)
    1735              :                   CALL Smearkp(wocc(:, :, 1), mus(1), kTS, weig(:, :, 1), nel, wkp, &
    1736            0 :                                smear%smearing_width, 1.0_dp, smear%method)
    1737            0 :                   kTS_spin(1) = kTS
    1738            0 :                   nel = REAL(ne_b, KIND=dp)
    1739              :                   CALL Smearkp(wocc(:, :, 2), mus(2), kTS, weig(:, :, 2), nel, wkp, &
    1740            0 :                                smear%smearing_width, 1.0_dp, smear%method)
    1741            0 :                   kTS_spin(2) = kTS
    1742              :                ELSE
    1743           32 :                   nel = REAL(ne_a, KIND=dp) + REAL(ne_b, KIND=dp)
    1744              :                   CALL Smearkp2(wocc(:, :, :), mu, kTS, weig(:, :, :), nel, wkp, &
    1745           32 :                                 smear%smearing_width, smear%method)
    1746           32 :                   kTS = kTS/2._dp
    1747           96 :                   kTS_spin(1:2) = kTS
    1748           96 :                   mus(1:2) = mu
    1749              :                END IF
    1750              :             CASE DEFAULT
    1751        14320 :                CPABORT("kpoints: Selected smearing not (yet) supported")
    1752              :             END SELECT
    1753              :          ELSE
    1754              :             ! fixed occupations (2/1)
    1755        21792 :             IF (nspin == 1) THEN
    1756        20276 :                nel = REAL(nelectron, KIND=dp)
    1757              :                CALL Smearkp(wocc(:, :, 1), mus(1), kTS, weig(:, :, 1), nel, wkp, &
    1758        20276 :                             0.0_dp, 2.0_dp, smear_gaussian)
    1759        20276 :                kTS_spin(1) = kTS
    1760              :             ELSE
    1761         1516 :                nel = REAL(ne_a, KIND=dp)
    1762              :                CALL Smearkp(wocc(:, :, 1), mus(1), kTS, weig(:, :, 1), nel, wkp, &
    1763         1516 :                             0.0_dp, 1.0_dp, smear_gaussian)
    1764         1516 :                kTS_spin(1) = kTS
    1765         1516 :                nel = REAL(ne_b, KIND=dp)
    1766              :                CALL Smearkp(wocc(:, :, 2), mus(2), kTS, weig(:, :, 2), nel, wkp, &
    1767         1516 :                             0.0_dp, 1.0_dp, smear_gaussian)
    1768         1516 :                kTS_spin(2) = kTS
    1769              :             END IF
    1770              :          END IF
    1771        36112 :          IF (smear%do_smear .AND. PRESENT(added_mos_auto)) THEN
    1772              :             CALL kpoint_check_added_mos_auto_occupation( &
    1773        13780 :                wocc, wkp, smear, nspin, added_mos_auto, nao, my_added_mos_auto_grow)
    1774              :          END IF
    1775        36112 :          IF (my_added_mos_auto_grow) THEN
    1776            6 :             IF (PRESENT(added_mos_auto_grow)) THEN
    1777            6 :                added_mos_auto_grow = .TRUE.
    1778            6 :                DEALLOCATE (weig, wocc)
    1779            6 :                CALL timestop(handle)
    1780            6 :                RETURN
    1781              :             ELSE
    1782              :                CALL cp_abort(__LOCATION__, &
    1783              :                              "K-point ADDED_MOS AUTO needs a larger virtual-space buffer, "// &
    1784            0 :                              "but this call path cannot grow it.")
    1785              :             END IF
    1786              :          END IF
    1787       102260 :          DO ikpgr = 1, kplocal
    1788        66154 :             ik = kp_range(1) + ikpgr - 1
    1789        66154 :             kp => kpoint%kp_env(ikpgr)%kpoint_env
    1790       174944 :             DO ispin = 1, nspin
    1791        72684 :                mo_set => kp%mos(1, ispin)
    1792        72684 :                CALL get_mo_set(mo_set, eigenvalues=eigenvalues, occupation_numbers=occupation)
    1793      1301466 :                eigenvalues(1:nmo) = weig(1:nmo, ik, ispin)
    1794      1301466 :                occupation(1:nmo) = wocc(1:nmo, ik, ispin)
    1795        72684 :                mo_set%kTS = kTS_spin(ispin)
    1796       138838 :                mo_set%mu = mus(ispin)
    1797              :             END DO
    1798              :          END DO
    1799              : 
    1800        36106 :          DEALLOCATE (weig, wocc)
    1801              : 
    1802              :       END IF
    1803              : 
    1804        36106 :       CALL timestop(handle)
    1805              : 
    1806       108336 :    END SUBROUTINE kpoint_set_mo_occupation
    1807              : 
    1808              : ! **************************************************************************************************
    1809              : !> \brief summarize whether weighted k-point smearing reaches the available band edges
    1810              : !> \param wocc ...
    1811              : !> \param wkp ...
    1812              : !> \param smear ...
    1813              : !> \param nspin ...
    1814              : !> \param has_weight ...
    1815              : !> \param first_fractional ...
    1816              : !> \param last_occupied ...
    1817              : !> \param last_occupied_spin ...
    1818              : ! **************************************************************************************************
    1819          788 :    SUBROUTINE kpoint_smearing_edge_status(wocc, wkp, smear, nspin, has_weight, &
    1820          788 :                                           first_fractional, last_occupied, last_occupied_spin)
    1821              : 
    1822              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: wocc
    1823              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: wkp
    1824              :       TYPE(smear_type), INTENT(IN)                       :: smear
    1825              :       INTEGER, INTENT(IN)                                :: nspin
    1826              :       LOGICAL, INTENT(OUT)                               :: has_weight, first_fractional, &
    1827              :                                                             last_occupied
    1828              :       LOGICAL, DIMENSION(:), INTENT(OUT), OPTIONAL       :: last_occupied_spin
    1829              : 
    1830              :       INTEGER                                            :: ik, ispin, nmo
    1831              :       LOGICAL                                            :: band_occupied
    1832              :       REAL(KIND=dp)                                      :: eps_occ, maxocc, weight, weight_threshold
    1833              : 
    1834          788 :       has_weight = .FALSE.
    1835          788 :       first_fractional = .FALSE.
    1836          788 :       last_occupied = .FALSE.
    1837         1756 :       IF (PRESENT(last_occupied_spin)) last_occupied_spin(:) = .FALSE.
    1838          788 :       IF (.NOT. smear%do_smear) RETURN
    1839              : 
    1840          786 :       nmo = SIZE(wocc, 1)
    1841          786 :       IF (nmo < 1) RETURN
    1842          786 :       eps_occ = MAX(smear%eps_fermi_dirac, 10.0_dp*EPSILON(1.0_dp))
    1843          786 :       weight_threshold = 10.0_dp*EPSILON(1.0_dp)
    1844              : 
    1845         1752 :       DO ispin = 1, MIN(nspin, SIZE(wocc, 3))
    1846          966 :          maxocc = MERGE(2.0_dp, 1.0_dp, nspin == 1)
    1847         2946 :          DO ik = 1, MIN(SIZE(wkp), SIZE(wocc, 2))
    1848         1194 :             weight = ABS(wkp(ik))
    1849         1194 :             IF (weight <= weight_threshold) CYCLE
    1850         1182 :             has_weight = .TRUE.
    1851              :             first_fractional = first_fractional .OR. &
    1852         1182 :                                ABS(wocc(1, ik, ispin) - maxocc) > eps_occ
    1853         1182 :             band_occupied = ABS(wocc(nmo, ik, ispin)) > eps_occ
    1854         1182 :             last_occupied = last_occupied .OR. band_occupied
    1855         2148 :             IF (band_occupied .AND. PRESENT(last_occupied_spin)) THEN
    1856            8 :                IF (ispin <= SIZE(last_occupied_spin)) last_occupied_spin(ispin) = .TRUE.
    1857              :             END IF
    1858              :          END DO
    1859              :       END DO
    1860              : 
    1861              :    END SUBROUTINE kpoint_smearing_edge_status
    1862              : 
    1863              : ! **************************************************************************************************
    1864              : !> \brief request ADDED_MOS AUTO growth if weighted k-point smearing occupies the last band
    1865              : !> \param wocc ...
    1866              : !> \param wkp ...
    1867              : !> \param smear ...
    1868              : !> \param nspin ...
    1869              : !> \param added_mos_auto ...
    1870              : !> \param nao ...
    1871              : !> \param added_mos_auto_grow ...
    1872              : ! **************************************************************************************************
    1873        13780 :    SUBROUTINE kpoint_check_added_mos_auto_occupation(wocc, wkp, smear, nspin, &
    1874        13780 :                                                      added_mos_auto, nao, added_mos_auto_grow)
    1875              : 
    1876              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: wocc
    1877              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: wkp
    1878              :       TYPE(smear_type), INTENT(IN)                       :: smear
    1879              :       INTEGER, INTENT(IN)                                :: nspin
    1880              :       LOGICAL, DIMENSION(:), INTENT(IN)                  :: added_mos_auto
    1881              :       INTEGER, INTENT(IN)                                :: nao
    1882              :       LOGICAL, INTENT(OUT)                               :: added_mos_auto_grow
    1883              : 
    1884              :       INTEGER                                            :: ispin, nmo
    1885              :       LOGICAL                                            :: first_fractional, has_weight, &
    1886              :                                                             last_occupied
    1887        13780 :       LOGICAL, DIMENSION(nspin)                          :: last_occupied_spin
    1888              : 
    1889        13780 :       added_mos_auto_grow = .FALSE.
    1890        39784 :       IF (.NOT. ANY(added_mos_auto) .OR. .NOT. smear%do_smear) RETURN
    1891              : 
    1892              :       CALL kpoint_smearing_edge_status(wocc, wkp, smear, nspin, has_weight, &
    1893              :                                        first_fractional, last_occupied, &
    1894          778 :                                        last_occupied_spin=last_occupied_spin)
    1895          778 :       IF (.NOT. has_weight) RETURN
    1896              : 
    1897          778 :       nmo = SIZE(wocc, 1)
    1898         1720 :       DO ispin = 1, MIN(nspin, SIZE(added_mos_auto))
    1899          948 :          IF (.NOT. added_mos_auto(ispin) .OR. .NOT. last_occupied_spin(ispin)) CYCLE
    1900            6 :          IF (nmo >= nao) THEN
    1901              :             CALL cp_abort(__LOCATION__, &
    1902              :                           "K-point ADDED_MOS AUTO exhausted the AO basis but the highest band "// &
    1903            0 :                           "is still occupied. Use a larger basis or reduce the smearing width.")
    1904              :          END IF
    1905            6 :          added_mos_auto_grow = .TRUE.
    1906         1714 :          RETURN
    1907              :       END DO
    1908              : 
    1909              :    END SUBROUTINE kpoint_check_added_mos_auto_occupation
    1910              : 
    1911              : ! **************************************************************************************************
    1912              : !> \brief Calculate kpoint density matrices (rho(k), owned by kpoint groups)
    1913              : !> \param kpoint    kpoint environment
    1914              : !> \param energy_weighted  calculate energy weighted density matrix
    1915              : !> \param for_aux_fit ...
    1916              : ! **************************************************************************************************
    1917       113370 :    SUBROUTINE kpoint_density_matrices(kpoint, energy_weighted, for_aux_fit)
    1918              : 
    1919              :       TYPE(kpoint_type), POINTER                         :: kpoint
    1920              :       LOGICAL, OPTIONAL                                  :: energy_weighted, for_aux_fit
    1921              : 
    1922              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'kpoint_density_matrices'
    1923              : 
    1924              :       INTEGER                                            :: handle, ikpgr, ispin, kplocal, nao, nmo, &
    1925              :                                                             nspin, omp_threads
    1926              :       INTEGER, DIMENSION(2)                              :: kp_range
    1927              :       LOGICAL                                            :: aux_fit, wtype
    1928        37790 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: eigenvalues, occupation
    1929              :       TYPE(cp_fm_struct_type), POINTER                   :: matrix_struct
    1930              :       TYPE(cp_fm_type)                                   :: fwork
    1931              :       TYPE(cp_fm_type), POINTER                          :: cpmat, pmat, rpmat
    1932              :       TYPE(kpoint_env_type), POINTER                     :: kp
    1933              :       TYPE(mo_set_type), POINTER                         :: mo_set
    1934              : 
    1935        37790 :       CALL timeset(routineN, handle)
    1936              : 
    1937        37790 :       IF (PRESENT(energy_weighted)) THEN
    1938          454 :          wtype = energy_weighted
    1939              :       ELSE
    1940              :          ! default is normal density matrix
    1941        37336 :          wtype = .FALSE.
    1942              :       END IF
    1943              : 
    1944        37790 :       IF (PRESENT(for_aux_fit)) THEN
    1945          124 :          aux_fit = for_aux_fit
    1946              :       ELSE
    1947        37666 :          aux_fit = .FALSE.
    1948              :       END IF
    1949              : 
    1950        37790 :       IF (aux_fit) THEN
    1951          124 :          CPASSERT(ASSOCIATED(kpoint%kp_aux_env))
    1952              :       END IF
    1953              : 
    1954              :       ! work matrix
    1955        37790 :       IF (aux_fit) THEN
    1956          124 :          mo_set => kpoint%kp_aux_env(1)%kpoint_env%mos(1, 1)
    1957              :       ELSE
    1958        37666 :          mo_set => kpoint%kp_env(1)%kpoint_env%mos(1, 1)
    1959              :       END IF
    1960        37790 :       CALL get_mo_set(mo_set, nao=nao, nmo=nmo)
    1961        37790 :       CALL cp_fm_get_info(mo_set%mo_coeff, matrix_struct=matrix_struct)
    1962              : 
    1963        37790 :       CALL get_kpoint_info(kpoint, kp_range=kp_range)
    1964        37790 :       kplocal = kp_range(2) - kp_range(1) + 1
    1965        37790 :       IF (aux_fit) THEN
    1966          124 :          kp => kpoint%kp_aux_env(1)%kpoint_env
    1967              :       ELSE
    1968        37666 :          kp => kpoint%kp_env(1)%kpoint_env
    1969              :       END IF
    1970        37790 :       nspin = SIZE(kp%mos, 2)
    1971        37790 :       omp_threads = 1
    1972        37790 : !$    omp_threads = omp_get_max_threads()
    1973        37790 :       IF (kpoint%blacs_env_all%para_env%num_pe == 1 .AND. omp_threads > 1 .AND. &
    1974              :           kplocal*nspin > 1) THEN
    1975            0 :          CALL kpoint_density_matrices_omp(kpoint, wtype, aux_fit, nao, nmo, kplocal, nspin)
    1976            0 :          CALL timestop(handle)
    1977            0 :          RETURN
    1978              :       END IF
    1979              : 
    1980        37790 :       CALL cp_fm_create(fwork, matrix_struct)
    1981       109502 :       DO ikpgr = 1, kplocal
    1982        71712 :          IF (aux_fit) THEN
    1983         1876 :             kp => kpoint%kp_aux_env(ikpgr)%kpoint_env
    1984              :          ELSE
    1985        69836 :             kp => kpoint%kp_env(ikpgr)%kpoint_env
    1986              :          END IF
    1987        71712 :          nspin = SIZE(kp%mos, 2)
    1988       188262 :          DO ispin = 1, nspin
    1989        78760 :             mo_set => kp%mos(1, ispin)
    1990        78760 :             IF (wtype) THEN
    1991         1550 :                CALL get_mo_set(mo_set, eigenvalues=eigenvalues)
    1992              :             END IF
    1993       150472 :             IF (kpoint%use_real_wfn) THEN
    1994          168 :                IF (wtype) THEN
    1995           12 :                   pmat => kp%wmat(1, ispin)
    1996              :                ELSE
    1997          156 :                   pmat => kp%pmat(1, ispin)
    1998              :                END IF
    1999          168 :                CALL get_mo_set(mo_set, occupation_numbers=occupation)
    2000          168 :                CALL cp_fm_to_fm(mo_set%mo_coeff, fwork)
    2001          168 :                CALL cp_fm_column_scale(fwork, occupation)
    2002          168 :                IF (wtype) THEN
    2003           12 :                   CALL cp_fm_column_scale(fwork, eigenvalues)
    2004              :                END IF
    2005          168 :                CALL parallel_gemm("N", "T", nao, nao, nmo, 1.0_dp, mo_set%mo_coeff, fwork, 0.0_dp, pmat)
    2006              :             ELSE
    2007        78592 :                IF (wtype) THEN
    2008         1538 :                   rpmat => kp%wmat(1, ispin)
    2009         1538 :                   cpmat => kp%wmat(2, ispin)
    2010              :                ELSE
    2011        77054 :                   rpmat => kp%pmat(1, ispin)
    2012        77054 :                   cpmat => kp%pmat(2, ispin)
    2013              :                END IF
    2014        78592 :                CALL get_mo_set(mo_set, occupation_numbers=occupation)
    2015        78592 :                CALL cp_fm_to_fm(mo_set%mo_coeff, fwork)
    2016        78592 :                CALL cp_fm_column_scale(fwork, occupation)
    2017        78592 :                IF (wtype) THEN
    2018         1538 :                   CALL cp_fm_column_scale(fwork, eigenvalues)
    2019              :                END IF
    2020              :                ! Re(c)*Re(c)
    2021        78592 :                CALL parallel_gemm("N", "T", nao, nao, nmo, 1.0_dp, mo_set%mo_coeff, fwork, 0.0_dp, rpmat)
    2022        78592 :                mo_set => kp%mos(2, ispin)
    2023              :                ! Im(c)*Re(c)
    2024        78592 :                CALL parallel_gemm("N", "T", nao, nao, nmo, 1.0_dp, mo_set%mo_coeff, fwork, 0.0_dp, cpmat)
    2025              :                ! Re(c)*Im(c)
    2026        78592 :                CALL parallel_gemm("N", "T", nao, nao, nmo, -1.0_dp, fwork, mo_set%mo_coeff, 1.0_dp, cpmat)
    2027        78592 :                CALL cp_fm_to_fm(mo_set%mo_coeff, fwork)
    2028        78592 :                CALL cp_fm_column_scale(fwork, occupation)
    2029        78592 :                IF (wtype) THEN
    2030         1538 :                   CALL cp_fm_column_scale(fwork, eigenvalues)
    2031              :                END IF
    2032              :                ! Im(c)*Im(c)
    2033        78592 :                CALL parallel_gemm("N", "T", nao, nao, nmo, 1.0_dp, mo_set%mo_coeff, fwork, 1.0_dp, rpmat)
    2034              :             END IF
    2035              :          END DO
    2036              :       END DO
    2037              : 
    2038        37790 :       CALL cp_fm_release(fwork)
    2039              : 
    2040        37790 :       CALL timestop(handle)
    2041              : 
    2042        37790 :    END SUBROUTINE kpoint_density_matrices
    2043              : 
    2044              : ! **************************************************************************************************
    2045              : !> \brief Build W(k) for noncanonical complex OT orbitals from H(k) C(k).
    2046              : !>        The occupied-space Lagrange multiplier is
    2047              : !>        Hermitian[(C^H H C) f], which reduces to the usual eigenvalue-weighted
    2048              : !>        expression for canonical orbitals.
    2049              : !> \param coeff_re real part of C(k)
    2050              : !> \param coeff_im imaginary part of C(k)
    2051              : !> \param hc_re real part of H(k) C(k)
    2052              : !> \param hc_im imaginary part of H(k) C(k)
    2053              : !> \param occupation orbital occupations
    2054              : !> \param wmat_re real part of W(k)
    2055              : !> \param wmat_im imaginary part of W(k)
    2056              : ! **************************************************************************************************
    2057           34 :    SUBROUTINE kpoint_ot_energy_weighted_density(coeff_re, coeff_im, hc_re, hc_im, occupation, &
    2058              :                                                 wmat_re, wmat_im)
    2059              : 
    2060              :       TYPE(cp_fm_type), INTENT(IN)                       :: coeff_re, coeff_im, hc_re, hc_im
    2061              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: occupation
    2062              :       TYPE(cp_fm_type), INTENT(IN)                       :: wmat_re, wmat_im
    2063              : 
    2064              :       COMPLEX(KIND=dp), PARAMETER                        :: zhalf = (0.5_dp, 0.0_dp), &
    2065              :                                                             zone = (1.0_dp, 0.0_dp), &
    2066              :                                                             zzero = (0.0_dp, 0.0_dp)
    2067              : 
    2068              :       COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:)        :: occupation_complex
    2069              :       INTEGER                                            :: nao, nmo
    2070              :       TYPE(cp_cfm_type)                                  :: coeff, hblock, hblock_h, hc, weighted, &
    2071              :                                                             wmat
    2072              : 
    2073           34 :       CALL cp_fm_get_info(coeff_re, nrow_global=nao, ncol_global=nmo)
    2074           34 :       CPASSERT(nmo >= 1)
    2075           34 :       CPASSERT(SIZE(occupation) >= nmo)
    2076              : 
    2077           34 :       CALL cp_cfm_create(coeff, coeff_re%matrix_struct)
    2078           34 :       CALL cp_cfm_create(hc, hc_re%matrix_struct)
    2079           34 :       CALL cp_cfm_create(weighted, coeff_re%matrix_struct)
    2080           34 :       CALL cp_cfm_create(hblock, coeff_re%matrix_struct, nrow=nmo, ncol=nmo)
    2081           34 :       CALL cp_cfm_create(hblock_h, coeff_re%matrix_struct, nrow=nmo, ncol=nmo)
    2082           34 :       CALL cp_cfm_create(wmat, wmat_re%matrix_struct)
    2083              : 
    2084           34 :       CALL cp_fm_to_cfm(coeff_re, coeff_im, coeff)
    2085           34 :       CALL cp_fm_to_cfm(hc_re, hc_im, hc)
    2086           34 :       CALL cp_cfm_gemm("C", "N", nmo, nmo, nao, zone, coeff, hc, zzero, hblock)
    2087              : 
    2088          102 :       ALLOCATE (occupation_complex(nmo))
    2089          158 :       occupation_complex(:) = CMPLX(occupation(1:nmo), 0.0_dp, KIND=dp)
    2090           34 :       CALL cp_cfm_column_scale(hblock, occupation_complex)
    2091           34 :       DEALLOCATE (occupation_complex)
    2092           34 :       CALL cp_cfm_transpose(hblock, "C", hblock_h)
    2093           34 :       CALL cp_cfm_scale_and_add(zhalf, hblock, zhalf, hblock_h)
    2094              : 
    2095           34 :       CALL cp_cfm_gemm("N", "N", nao, nmo, nmo, zone, coeff, hblock, zzero, weighted)
    2096           34 :       CALL cp_cfm_gemm("N", "C", nao, nao, nmo, zone, weighted, coeff, zzero, wmat)
    2097           34 :       CALL cp_cfm_to_fm(wmat, wmat_re, wmat_im)
    2098              : 
    2099           34 :       CALL cp_cfm_release(wmat)
    2100           34 :       CALL cp_cfm_release(hblock_h)
    2101           34 :       CALL cp_cfm_release(hblock)
    2102           34 :       CALL cp_cfm_release(weighted)
    2103           34 :       CALL cp_cfm_release(hc)
    2104           34 :       CALL cp_cfm_release(coeff)
    2105              : 
    2106           68 :    END SUBROUTINE kpoint_ot_energy_weighted_density
    2107              : 
    2108              : ! **************************************************************************************************
    2109              : !> \brief Build energy-weighted density matrices for complex K-point OT.
    2110              : !>        H(k) is transformed only while W(k) is needed, avoiding a persistent
    2111              : !>        dense AO-by-AO Hamiltonian for every spin and K point.
    2112              : !> \param kpoint K-point environment
    2113              : !> \param matrix_ks real-space Kohn-Sham matrices
    2114              : ! **************************************************************************************************
    2115           18 :    SUBROUTINE kpoint_ot_energy_weighted_matrices(kpoint, matrix_ks)
    2116              : 
    2117              :       TYPE(kpoint_type), POINTER                         :: kpoint
    2118              :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_ks
    2119              : 
    2120              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'kpoint_ot_energy_weighted_matrices'
    2121              : 
    2122              :       INTEGER                                            :: handle, ikpgr, ikpoint, ispin, nmo, nspin
    2123           18 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
    2124              :       LOGICAL                                            :: use_real_wfn
    2125           18 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: occupation
    2126           18 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: xkp
    2127              :       TYPE(cp_fm_type)                                   :: hc_im, hc_re
    2128              :       TYPE(cp_fm_type), POINTER                          :: coeff_im, coeff_re
    2129              :       TYPE(dbcsr_type), POINTER                          :: matrix_k_im, matrix_k_re
    2130              :       TYPE(kpoint_env_type), POINTER                     :: kp
    2131              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    2132           18 :          POINTER                                         :: sab_nl
    2133              : 
    2134           18 :       CALL timeset(routineN, handle)
    2135           18 :       NULLIFY (cell_to_index, coeff_im, coeff_re, matrix_k_im, matrix_k_re, occupation, sab_nl, xkp)
    2136              : 
    2137              :       CALL get_kpoint_info(kpoint, xkp=xkp, use_real_wfn=use_real_wfn, &
    2138           18 :                            cell_to_index=cell_to_index, sab_nl=sab_nl)
    2139           18 :       CPASSERT(.NOT. use_real_wfn)
    2140           18 :       CPASSERT(ASSOCIATED(cell_to_index))
    2141           18 :       CPASSERT(ASSOCIATED(sab_nl))
    2142           18 :       CPASSERT(ASSOCIATED(matrix_ks))
    2143              : 
    2144           18 :       ALLOCATE (matrix_k_re, matrix_k_im)
    2145              :       CALL dbcsr_create(matrix_k_re, template=matrix_ks(1, 1)%matrix, &
    2146           18 :                         matrix_type=dbcsr_type_symmetric)
    2147              :       CALL dbcsr_create(matrix_k_im, template=matrix_ks(1, 1)%matrix, &
    2148           18 :                         matrix_type=dbcsr_type_antisymmetric)
    2149           18 :       CALL cp_dbcsr_alloc_block_from_nbl(matrix_k_re, sab_nl)
    2150           18 :       CALL cp_dbcsr_alloc_block_from_nbl(matrix_k_im, sab_nl)
    2151              : 
    2152           42 :       DO ikpgr = 1, SIZE(kpoint%kp_env)
    2153           24 :          kp => kpoint%kp_env(ikpgr)%kpoint_env
    2154           24 :          ikpoint = kp%nkpoint
    2155           24 :          nspin = SIZE(kp%mos, 2)
    2156           72 :          DO ispin = 1, nspin
    2157           30 :             CALL dbcsr_set(matrix_k_re, 0.0_dp)
    2158           30 :             CALL dbcsr_set(matrix_k_im, 0.0_dp)
    2159              :             CALL rskp_transform(rmatrix=matrix_k_re, cmatrix=matrix_k_im, rsmat=matrix_ks, &
    2160              :                                 ispin=ispin, xkp=xkp(1:3, ikpoint), &
    2161           30 :                                 cell_to_index=cell_to_index, sab_nl=sab_nl)
    2162              : 
    2163              :             CALL get_mo_set(kp%mos(1, ispin), mo_coeff=coeff_re, nmo=nmo, &
    2164           30 :                             occupation_numbers=occupation)
    2165           30 :             CALL get_mo_set(kp%mos(2, ispin), mo_coeff=coeff_im)
    2166           30 :             CPASSERT(nmo >= 1)
    2167           30 :             CPASSERT(SIZE(occupation) >= nmo)
    2168              : 
    2169              :             ! Smearing occupations are k-point resolved, whereas mo_set%homo is not.
    2170           30 :             CALL cp_fm_create(hc_re, coeff_re%matrix_struct, set_zero=.TRUE.)
    2171           30 :             CALL cp_fm_create(hc_im, coeff_im%matrix_struct, set_zero=.TRUE.)
    2172           30 :             CALL cp_dbcsr_sm_fm_multiply(matrix_k_re, coeff_re, hc_re, nmo)
    2173              :             CALL cp_dbcsr_sm_fm_multiply(matrix_k_im, coeff_im, hc_re, nmo, &
    2174           30 :                                          alpha=-1.0_dp, beta=1.0_dp)
    2175           30 :             CALL cp_dbcsr_sm_fm_multiply(matrix_k_re, coeff_im, hc_im, nmo)
    2176              :             CALL cp_dbcsr_sm_fm_multiply(matrix_k_im, coeff_re, hc_im, nmo, &
    2177           30 :                                          alpha=1.0_dp, beta=1.0_dp)
    2178              : 
    2179              :             CALL kpoint_ot_energy_weighted_density( &
    2180              :                coeff_re, coeff_im, hc_re, hc_im, occupation, &
    2181           30 :                kp%wmat(1, ispin), kp%wmat(2, ispin))
    2182              : 
    2183           30 :             CALL cp_fm_release(hc_im)
    2184           84 :             CALL cp_fm_release(hc_re)
    2185              :          END DO
    2186              :       END DO
    2187              : 
    2188           18 :       CALL dbcsr_deallocate_matrix(matrix_k_im)
    2189           18 :       CALL dbcsr_deallocate_matrix(matrix_k_re)
    2190           18 :       CALL timestop(handle)
    2191              : 
    2192           18 :    END SUBROUTINE kpoint_ot_energy_weighted_matrices
    2193              : 
    2194              : ! **************************************************************************************************
    2195              : !> \brief Thread k-point density-matrix construction on a one-rank BLACS grid.
    2196              : !>        The local BLAS path avoids concurrent ScaLAPACK calls and gives every
    2197              : !>        worker a private column-scaled MO buffer.
    2198              : !> \param kpoint ...
    2199              : !> \param wtype ...
    2200              : !> \param aux_fit ...
    2201              : !> \param nao ...
    2202              : !> \param nmo ...
    2203              : !> \param kplocal ...
    2204              : !> \param nspin ...
    2205              : ! **************************************************************************************************
    2206            0 :    SUBROUTINE kpoint_density_matrices_omp(kpoint, wtype, aux_fit, nao, nmo, kplocal, nspin)
    2207              : 
    2208              :       TYPE(kpoint_type), POINTER                         :: kpoint
    2209              :       LOGICAL, INTENT(IN)                                :: wtype, aux_fit
    2210              :       INTEGER, INTENT(IN)                                :: nao, nmo, kplocal, nspin
    2211              : 
    2212              :       INTEGER                                            :: ikpgr, ispin, nworkers, thread
    2213            0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: work
    2214              : 
    2215            0 :       nworkers = 1
    2216            0 : !$    nworkers = MIN(omp_get_max_threads(), kplocal*nspin)
    2217            0 :       ALLOCATE (work(nao, nmo, nworkers))
    2218              : 
    2219              : !$OMP PARALLEL DO COLLAPSE(2) DEFAULT(NONE) SCHEDULE(DYNAMIC, 1) NUM_THREADS(nworkers) &
    2220            0 : !$OMP SHARED(kpoint,wtype,aux_fit,nao,nmo,kplocal,nspin,nworkers,work) PRIVATE(ikpgr,ispin,thread)
    2221              :       DO ikpgr = 1, kplocal
    2222              :          DO ispin = 1, nspin
    2223              :             thread = 1
    2224              : !$          thread = omp_get_thread_num() + 1
    2225              :             CALL kpoint_density_matrix_job(kpoint, ikpgr, ispin, wtype, aux_fit, nao, nmo, &
    2226              :                                            work(:, :, thread))
    2227              :          END DO
    2228              :       END DO
    2229              : !$OMP END PARALLEL DO
    2230              : 
    2231            0 :       DEALLOCATE (work)
    2232              : 
    2233            0 :    END SUBROUTINE kpoint_density_matrices_omp
    2234              : 
    2235              : ! **************************************************************************************************
    2236              : !> \brief Construct one (k-point,spin) density matrix using local BLAS.
    2237              : !> \param kpoint ...
    2238              : !> \param ikpgr ...
    2239              : !> \param ispin ...
    2240              : !> \param wtype ...
    2241              : !> \param aux_fit ...
    2242              : !> \param nao ...
    2243              : !> \param nmo ...
    2244              : !> \param work ...
    2245              : ! **************************************************************************************************
    2246            0 :    SUBROUTINE kpoint_density_matrix_job(kpoint, ikpgr, ispin, wtype, aux_fit, nao, nmo, work)
    2247              : 
    2248              :       TYPE(kpoint_type), POINTER                         :: kpoint
    2249              :       INTEGER, INTENT(IN)                                :: ikpgr, ispin
    2250              :       LOGICAL, INTENT(IN)                                :: wtype, aux_fit
    2251              :       INTEGER, INTENT(IN)                                :: nao, nmo
    2252              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: work
    2253              : 
    2254              :       INTEGER                                            :: imo
    2255              :       REAL(KIND=dp)                                      :: scale
    2256              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    2257            0 :          POINTER                                         :: ci, cmat, cr, rmat
    2258            0 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: eigenvalues, occupation
    2259              :       TYPE(cp_fm_type), POINTER                          :: cpmat, rpmat
    2260              :       TYPE(kpoint_env_type), POINTER                     :: kp
    2261              :       TYPE(mo_set_type), POINTER                         :: mo_set
    2262              : 
    2263            0 :       IF (aux_fit) THEN
    2264            0 :          kp => kpoint%kp_aux_env(ikpgr)%kpoint_env
    2265              :       ELSE
    2266            0 :          kp => kpoint%kp_env(ikpgr)%kpoint_env
    2267              :       END IF
    2268            0 :       mo_set => kp%mos(1, ispin)
    2269            0 :       IF (wtype) THEN
    2270            0 :          CALL get_mo_set(mo_set, occupation_numbers=occupation, eigenvalues=eigenvalues)
    2271              :       ELSE
    2272            0 :          CALL get_mo_set(mo_set, occupation_numbers=occupation)
    2273              :       END IF
    2274            0 :       CALL cp_fm_get_info(mo_set%mo_coeff, local_data=cr)
    2275              : 
    2276            0 :       IF (wtype) THEN
    2277            0 :          rpmat => kp%wmat(1, ispin)
    2278              :       ELSE
    2279            0 :          rpmat => kp%pmat(1, ispin)
    2280              :       END IF
    2281            0 :       CALL cp_fm_get_info(rpmat, local_data=rmat)
    2282              : 
    2283            0 :       DO imo = 1, nmo
    2284            0 :          scale = occupation(imo)
    2285            0 :          IF (wtype) scale = scale*eigenvalues(imo)
    2286            0 :          work(1:nao, imo) = scale*cr(1:nao, imo)
    2287              :       END DO
    2288              :       CALL dgemm('N', 'T', nao, nao, nmo, 1.0_dp, cr, SIZE(cr, 1), &
    2289            0 :                  work, SIZE(work, 1), 0.0_dp, rmat, SIZE(rmat, 1))
    2290              : 
    2291            0 :       IF (.NOT. kpoint%use_real_wfn) THEN
    2292            0 :          mo_set => kp%mos(2, ispin)
    2293            0 :          CALL cp_fm_get_info(mo_set%mo_coeff, local_data=ci)
    2294            0 :          IF (wtype) THEN
    2295            0 :             cpmat => kp%wmat(2, ispin)
    2296              :          ELSE
    2297            0 :             cpmat => kp%pmat(2, ispin)
    2298              :          END IF
    2299            0 :          CALL cp_fm_get_info(cpmat, local_data=cmat)
    2300              : 
    2301              :          CALL dgemm('N', 'T', nao, nao, nmo, 1.0_dp, ci, SIZE(ci, 1), &
    2302            0 :                     work, SIZE(work, 1), 0.0_dp, cmat, SIZE(cmat, 1))
    2303              :          CALL dgemm('N', 'T', nao, nao, nmo, -1.0_dp, work, SIZE(work, 1), &
    2304            0 :                     ci, SIZE(ci, 1), 1.0_dp, cmat, SIZE(cmat, 1))
    2305              : 
    2306            0 :          DO imo = 1, nmo
    2307            0 :             scale = occupation(imo)
    2308            0 :             IF (wtype) scale = scale*eigenvalues(imo)
    2309            0 :             work(1:nao, imo) = scale*ci(1:nao, imo)
    2310              :          END DO
    2311              :          CALL dgemm('N', 'T', nao, nao, nmo, 1.0_dp, ci, SIZE(ci, 1), &
    2312            0 :                     work, SIZE(work, 1), 1.0_dp, rmat, SIZE(rmat, 1))
    2313              :       END IF
    2314              : 
    2315            0 :    END SUBROUTINE kpoint_density_matrix_job
    2316              : 
    2317              : ! **************************************************************************************************
    2318              : !> \brief Calculate Lowdin transformation of density matrix S^1/2 P S^1/2
    2319              : !>        Integrate diagonal elements over k-points to get Lowdin charges
    2320              : !> \param kpoint    kpoint environment
    2321              : !> \param pmat_diag Sum over kpoints of diagonal elements
    2322              : !> \par History
    2323              : !>      04.2026 created [JGH]
    2324              : ! **************************************************************************************************
    2325           12 :    SUBROUTINE lowdin_kp_trans(kpoint, pmat_diag)
    2326              : 
    2327              :       TYPE(kpoint_type), POINTER                         :: kpoint
    2328              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: pmat_diag
    2329              : 
    2330              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'lowdin_kp_trans'
    2331              :       COMPLEX(KIND=dp), PARAMETER                        :: cone = (1.0_dp, 0.0_dp), &
    2332              :                                                             czero = (0.0_dp, 0.0_dp)
    2333              : 
    2334              :       INTEGER                                            :: handle, ikpgr, ispin, kplocal, nao, nspin
    2335              :       INTEGER, DIMENSION(2)                              :: kp_range
    2336           12 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: dele
    2337              :       TYPE(cp_cfm_type)                                  :: cf1work, cf2work
    2338              :       TYPE(cp_cfm_type), POINTER                         :: cshalf
    2339              :       TYPE(cp_fm_struct_type), POINTER                   :: matrix_struct
    2340              :       TYPE(cp_fm_type)                                   :: f1work, f2work
    2341              :       TYPE(cp_fm_type), POINTER                          :: cpmat, pmat, rpmat, shalf
    2342              :       TYPE(kpoint_env_type), POINTER                     :: kp
    2343              :       TYPE(mp_para_env_type), POINTER                    :: para_env_inter_kp
    2344              : 
    2345           12 :       CALL timeset(routineN, handle)
    2346              : 
    2347           12 :       nspin = SIZE(pmat_diag, 2)
    2348          822 :       pmat_diag = 0.0_dp
    2349              : 
    2350              :       ! work matrix
    2351              :       CALL cp_fm_get_info(kpoint%kp_env(1)%kpoint_env%pmat(1, 1), &
    2352           12 :                           matrix_struct=matrix_struct, nrow_global=nao)
    2353           12 :       IF (kpoint%use_real_wfn) THEN
    2354            0 :          CALL cp_fm_create(f1work, matrix_struct, nrow=nao, ncol=nao)
    2355            0 :          CALL cp_fm_create(f2work, matrix_struct, nrow=nao, ncol=nao)
    2356              :       ELSE
    2357           12 :          CALL cp_fm_create(f2work, matrix_struct, nrow=nao, ncol=nao)
    2358           12 :          CALL cp_cfm_create(cf1work, matrix_struct, nrow=nao, ncol=nao)
    2359           12 :          CALL cp_cfm_create(cf2work, matrix_struct, nrow=nao, ncol=nao)
    2360              :       END IF
    2361           36 :       ALLOCATE (dele(nao))
    2362              : 
    2363           12 :       CALL get_kpoint_info(kpoint, kp_range=kp_range)
    2364           12 :       kplocal = kp_range(2) - kp_range(1) + 1
    2365          268 :       DO ikpgr = 1, kplocal
    2366          256 :          kp => kpoint%kp_env(ikpgr)%kpoint_env
    2367          564 :          DO ispin = 1, nspin
    2368          296 :             IF (kpoint%use_real_wfn) THEN
    2369            0 :                pmat => kp%pmat(1, ispin)
    2370            0 :                shalf => kp%shalf
    2371            0 :                CALL parallel_gemm("N", "N", nao, nao, nao, 1.0_dp, pmat, shalf, 0.0_dp, f1work)
    2372            0 :                CALL parallel_gemm("N", "N", nao, nao, nao, 1.0_dp, shalf, f1work, 0.0_dp, f2work)
    2373              :             ELSE
    2374          296 :                rpmat => kp%pmat(1, ispin)
    2375          296 :                cpmat => kp%pmat(2, ispin)
    2376          296 :                cshalf => kp%cshalf
    2377          296 :                CALL cp_fm_to_cfm(rpmat, cpmat, cf1work)
    2378          296 :                CALL parallel_gemm("N", "N", nao, nao, nao, cone, cf1work, cshalf, czero, cf2work)
    2379          296 :                CALL parallel_gemm("N", "N", nao, nao, nao, cone, cshalf, cf2work, czero, cf1work)
    2380          296 :                CALL cp_cfm_to_fm(cf1work, mtargetr=f2work)
    2381              :             END IF
    2382          296 :             CALL cp_fm_get_diag(f2work, dele)
    2383         4536 :             pmat_diag(1:nao, ispin) = pmat_diag(1:nao, ispin) + kp%wkp*dele(1:nao)
    2384              :          END DO
    2385              :       END DO
    2386              : 
    2387           12 :       CALL get_kpoint_info(kpoint, para_env_inter_kp=para_env_inter_kp)
    2388         1632 :       CALL para_env_inter_kp%sum(pmat_diag)
    2389              : 
    2390           12 :       IF (kpoint%use_real_wfn) THEN
    2391            0 :          CALL cp_fm_release(f1work)
    2392            0 :          CALL cp_fm_release(f2work)
    2393              :       ELSE
    2394           12 :          CALL cp_fm_release(f2work)
    2395           12 :          CALL cp_cfm_release(cf1work)
    2396           12 :          CALL cp_cfm_release(cf2work)
    2397              :       END IF
    2398           12 :       DEALLOCATE (dele)
    2399              : 
    2400           12 :       CALL timestop(handle)
    2401              : 
    2402           24 :    END SUBROUTINE lowdin_kp_trans
    2403              : 
    2404              : ! **************************************************************************************************
    2405              : !> \brief Calculate S(k)^1/2 C(k) for real or complex k-point wavefunctions
    2406              : !> \param kp           K-point environment for one local k point
    2407              : !> \param ispin        Spin index
    2408              : !> \param use_real_wfn Use real k-point wavefunctions
    2409              : !> \param shalfc       Output matrix containing S(k)^1/2 C(k) for real wavefunctions
    2410              : !> \param cshalfc      Output matrix containing S(k)^1/2 C(k) for complex wavefunctions
    2411              : ! **************************************************************************************************
    2412            0 :    SUBROUTINE lowdin_kp_mo_coeff(kp, ispin, use_real_wfn, shalfc, cshalfc)
    2413              : 
    2414              :       TYPE(kpoint_env_type), POINTER                     :: kp
    2415              :       INTEGER, INTENT(IN)                                :: ispin
    2416              :       LOGICAL, INTENT(IN)                                :: use_real_wfn
    2417              :       TYPE(cp_fm_type), INTENT(INOUT), OPTIONAL          :: shalfc
    2418              :       TYPE(cp_cfm_type), INTENT(INOUT), OPTIONAL         :: cshalfc
    2419              : 
    2420              :       INTEGER                                            :: nao, nmo
    2421              :       TYPE(cp_fm_struct_type), POINTER                   :: matrix_struct_mo, matrix_struct_shalf
    2422              :       TYPE(cp_fm_type)                                   :: cshalf_im, cshalf_re, shalf_im, shalf_re
    2423              :       TYPE(mo_set_type), POINTER                         :: mo_set, mo_set_im, mo_set_re
    2424              : 
    2425            0 :       IF (use_real_wfn) THEN
    2426            0 :          CPASSERT(PRESENT(shalfc))
    2427            0 :          mo_set => kp%mos(1, ispin)
    2428            0 :          CALL get_mo_set(mo_set, nao=nao, nmo=nmo)
    2429              : 
    2430              :          CALL parallel_gemm("N", "N", nao, nmo, nao, 1.0_dp, kp%shalf, &
    2431            0 :                             mo_set%mo_coeff, 0.0_dp, shalfc)
    2432              :       ELSE
    2433            0 :          CPASSERT(PRESENT(cshalfc))
    2434            0 :          mo_set_re => kp%mos(1, ispin)
    2435            0 :          mo_set_im => kp%mos(2, ispin)
    2436            0 :          CALL get_mo_set(mo_set_re, nao=nao, nmo=nmo)
    2437            0 :          CALL cp_fm_get_info(mo_set_re%mo_coeff, matrix_struct=matrix_struct_mo)
    2438            0 :          CALL cp_cfm_get_info(kp%cshalf, matrix_struct=matrix_struct_shalf)
    2439              : 
    2440            0 :          CALL cp_fm_create(shalf_re, matrix_struct_shalf, nrow=nao, ncol=nao)
    2441            0 :          CALL cp_fm_create(shalf_im, matrix_struct_shalf, nrow=nao, ncol=nao)
    2442            0 :          CALL cp_fm_create(cshalf_re, matrix_struct_mo, nrow=nao, ncol=nmo)
    2443            0 :          CALL cp_fm_create(cshalf_im, matrix_struct_mo, nrow=nao, ncol=nmo)
    2444              : 
    2445            0 :          CALL cp_cfm_to_fm(kp%cshalf, mtargetr=shalf_re, mtargeti=shalf_im)
    2446              : 
    2447              :          ! Re[S(k)^1/2 C(k)] = Re[S(k)^1/2] C_re(k) - Im[S(k)^1/2] C_im(k)
    2448              :          CALL parallel_gemm("N", "N", nao, nmo, nao, 1.0_dp, shalf_re, &
    2449            0 :                             mo_set_re%mo_coeff, 0.0_dp, cshalf_re)
    2450              :          CALL parallel_gemm("N", "N", nao, nmo, nao, -1.0_dp, shalf_im, &
    2451            0 :                             mo_set_im%mo_coeff, 1.0_dp, cshalf_re)
    2452              : 
    2453              :          ! Im[S(k)^1/2 C(k)] = Re[S(k)^1/2] C_im(k) + Im[S(k)^1/2] C_re(k)
    2454              :          CALL parallel_gemm("N", "N", nao, nmo, nao, 1.0_dp, shalf_re, &
    2455            0 :                             mo_set_im%mo_coeff, 0.0_dp, cshalf_im)
    2456              :          CALL parallel_gemm("N", "N", nao, nmo, nao, 1.0_dp, shalf_im, &
    2457            0 :                             mo_set_re%mo_coeff, 1.0_dp, cshalf_im)
    2458              : 
    2459            0 :          CALL cp_fm_to_cfm(cshalf_re, cshalf_im, cshalfc)
    2460              : 
    2461            0 :          CALL cp_fm_release(shalf_re)
    2462            0 :          CALL cp_fm_release(shalf_im)
    2463            0 :          CALL cp_fm_release(cshalf_re)
    2464            0 :          CALL cp_fm_release(cshalf_im)
    2465              :       END IF
    2466              : 
    2467            0 :    END SUBROUTINE lowdin_kp_mo_coeff
    2468              : 
    2469              : ! **************************************************************************************************
    2470              : !> \brief generate real space density matrices in DBCSR format
    2471              : !> \param kpoint  Kpoint environment
    2472              : !> \param denmat  Real space (DBCSR) density matrices
    2473              : !> \param wtype   True = energy weighted density matrix
    2474              : !>                False = normal density matrix
    2475              : !> \param tempmat DBCSR matrix to be used as template
    2476              : !> \param sab_nl ...
    2477              : !> \param fmwork  FM work matrices (kpoint group)
    2478              : !> \param for_aux_fit ...
    2479              : !> \param pmat_ext ...
    2480              : !> \param overlap_rs ...
    2481              : ! **************************************************************************************************
    2482        38254 :    SUBROUTINE kpoint_density_transform(kpoint, denmat, wtype, tempmat, sab_nl, fmwork, for_aux_fit, &
    2483        38254 :                                        pmat_ext, overlap_rs)
    2484              : 
    2485              :       TYPE(kpoint_type), POINTER                         :: kpoint
    2486              :       TYPE(dbcsr_p_type), DIMENSION(:, :)                :: denmat
    2487              :       LOGICAL, INTENT(IN)                                :: wtype
    2488              :       TYPE(dbcsr_type), POINTER                          :: tempmat
    2489              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    2490              :          POINTER                                         :: sab_nl
    2491              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: fmwork
    2492              :       LOGICAL, OPTIONAL                                  :: for_aux_fit
    2493              :       TYPE(cp_fm_type), DIMENSION(:, :, :), INTENT(IN), &
    2494              :          OPTIONAL                                        :: pmat_ext
    2495              :       TYPE(dbcsr_p_type), DIMENSION(:, :), OPTIONAL, &
    2496              :          POINTER                                         :: overlap_rs
    2497              : 
    2498              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'kpoint_density_transform'
    2499              : 
    2500              :       INTEGER                                            :: handle, ic, ik, ikk, indx, ispin, nc, &
    2501              :                                                             nimg, nkp, nspin, omp_threads
    2502        38254 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
    2503              :       LOGICAL                                            :: aux_fit, do_ext, do_symmetric, my_kpgrp, &
    2504              :                                                             real_only
    2505        38254 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: wkp
    2506        38254 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: xkp
    2507        38254 :       TYPE(copy_info_type), ALLOCATABLE, DIMENSION(:)    :: info
    2508              :       TYPE(cp_fm_type)                                   :: fmdummy
    2509              :       TYPE(dbcsr_type), POINTER                          :: cpmat, rpmat, scpmat, srpmat
    2510        38254 :       TYPE(kp_transform_plan_type)                       :: transform_plan
    2511              :       TYPE(kpoint_env_type), POINTER                     :: kp
    2512              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    2513              : 
    2514        38254 :       CALL timeset(routineN, handle)
    2515              : 
    2516        38254 :       CALL get_neighbor_list_set_p(neighbor_list_sets=sab_nl, symmetric=do_symmetric)
    2517              : 
    2518        38254 :       IF (PRESENT(for_aux_fit)) THEN
    2519          372 :          aux_fit = for_aux_fit
    2520              :       ELSE
    2521        37882 :          aux_fit = .FALSE.
    2522              :       END IF
    2523              : 
    2524        38254 :       do_ext = .FALSE.
    2525        38254 :       IF (PRESENT(pmat_ext)) do_ext = .TRUE.
    2526              : 
    2527        38254 :       IF (aux_fit) THEN
    2528          216 :          CPASSERT(ASSOCIATED(kpoint%kp_aux_env))
    2529              :       END IF
    2530              : 
    2531              :       ! work storage
    2532        38254 :       ALLOCATE (rpmat)
    2533              :       CALL dbcsr_create(rpmat, template=tempmat, &
    2534        38314 :                         matrix_type=MERGE(dbcsr_type_symmetric, dbcsr_type_no_symmetry, do_symmetric))
    2535        38254 :       CALL cp_dbcsr_alloc_block_from_nbl(rpmat, sab_nl)
    2536        38254 :       CALL dbcsr_set(rpmat, 0.0_dp)
    2537        38254 :       ALLOCATE (cpmat)
    2538              :       CALL dbcsr_create(cpmat, template=tempmat, &
    2539        38314 :                         matrix_type=MERGE(dbcsr_type_antisymmetric, dbcsr_type_no_symmetry, do_symmetric))
    2540        38254 :       CALL cp_dbcsr_alloc_block_from_nbl(cpmat, sab_nl)
    2541        38254 :       CALL dbcsr_set(cpmat, 0.0_dp)
    2542        38254 :       IF (.NOT. kpoint%full_grid) THEN
    2543        35012 :          ALLOCATE (srpmat)
    2544        35012 :          CALL dbcsr_create(srpmat, template=rpmat)
    2545        35012 :          CALL cp_dbcsr_alloc_block_from_nbl(srpmat, sab_nl)
    2546        35012 :          CALL dbcsr_set(srpmat, 0.0_dp)
    2547        35012 :          ALLOCATE (scpmat)
    2548        35012 :          CALL dbcsr_create(scpmat, template=cpmat)
    2549        35012 :          CALL cp_dbcsr_alloc_block_from_nbl(scpmat, sab_nl)
    2550        35012 :          CALL dbcsr_set(scpmat, 0.0_dp)
    2551              :       END IF
    2552              : 
    2553              :       CALL get_kpoint_info(kpoint, nkp=nkp, xkp=xkp, wkp=wkp, &
    2554        38254 :                            cell_to_index=cell_to_index)
    2555        38254 :       IF (PRESENT(overlap_rs)) THEN
    2556        37218 :          CALL calibrate_symmetry_phases(kpoint, overlap_rs, tempmat, sab_nl, cell_to_index)
    2557              :       END IF
    2558              :       ! initialize real space density matrices
    2559        38254 :       IF (aux_fit) THEN
    2560          216 :          kp => kpoint%kp_aux_env(1)%kpoint_env
    2561              :       ELSE
    2562        38038 :          kp => kpoint%kp_env(1)%kpoint_env
    2563              :       END IF
    2564        38254 :       nspin = SIZE(kp%mos, 2)
    2565        38254 :       nc = SIZE(kp%mos, 1)
    2566        38254 :       nimg = SIZE(denmat, 2)
    2567        38254 :       real_only = (nc == 1)
    2568              :       CALL kp_transform_plan_create(transform_plan, sab_nl, cell_to_index, nimg, &
    2569        38254 :                                     group_entries=.TRUE.)
    2570              : 
    2571        38254 :       para_env => kpoint%blacs_env_all%para_env
    2572        38254 :       omp_threads = 1
    2573        38254 : !$    omp_threads = omp_get_max_threads()
    2574        38254 :       IF (para_env%num_pe == 1 .AND. omp_threads > 1) THEN
    2575              :          CALL kpoint_density_transform_local(kpoint, denmat, wtype, aux_fit, do_ext, pmat_ext, &
    2576              :                                              rpmat, cpmat, srpmat, scpmat, real_only, nspin, nimg, &
    2577            0 :                                              nkp, xkp, wkp, transform_plan)
    2578            0 :          CALL kp_transform_plan_release(transform_plan)
    2579            0 :          CALL dbcsr_deallocate_matrix(rpmat)
    2580            0 :          CALL dbcsr_deallocate_matrix(cpmat)
    2581            0 :          IF (.NOT. kpoint%full_grid) THEN
    2582            0 :             CALL dbcsr_deallocate_matrix(srpmat)
    2583            0 :             CALL dbcsr_deallocate_matrix(scpmat)
    2584              :          END IF
    2585            0 :          CALL timestop(handle)
    2586            0 :          RETURN
    2587              :       END IF
    2588              : 
    2589       598710 :       ALLOCATE (info(nspin*nkp*nc))
    2590              : 
    2591              :       ! Start all the communication
    2592        38254 :       indx = 0
    2593        78994 :       DO ispin = 1, nspin
    2594      2408242 :          DO ic = 1, nimg
    2595      2408242 :             CALL dbcsr_set(denmat(ispin, ic)%matrix, 0.0_dp)
    2596              :          END DO
    2597              :          !
    2598       206290 :          DO ik = 1, nkp
    2599       127296 :             my_kpgrp = (ik >= kpoint%kp_range(1) .AND. ik <= kpoint%kp_range(2))
    2600              :             IF (my_kpgrp) THEN
    2601        82088 :                ikk = ik - kpoint%kp_range(1) + 1
    2602        82088 :                IF (aux_fit) THEN
    2603         2714 :                   kp => kpoint%kp_aux_env(ikk)%kpoint_env
    2604              :                ELSE
    2605        79374 :                   kp => kpoint%kp_env(ikk)%kpoint_env
    2606              :                END IF
    2607              :             ELSE
    2608              :                NULLIFY (kp)
    2609              :             END IF
    2610              :             ! collect this density matrix on all processors
    2611       127296 :             CPASSERT(SIZE(fmwork) >= nc)
    2612              : 
    2613       168036 :             IF (my_kpgrp) THEN
    2614       246096 :                DO ic = 1, nc
    2615       164008 :                   indx = indx + 1
    2616       246096 :                   IF (do_ext) THEN
    2617         6064 :                      CALL cp_fm_start_copy_general(pmat_ext(ikk, ic, ispin), fmwork(ic), para_env, info(indx))
    2618              :                   ELSE
    2619       157944 :                      IF (wtype) THEN
    2620         3148 :                         CALL cp_fm_start_copy_general(kp%wmat(ic, ispin), fmwork(ic), para_env, info(indx))
    2621              :                      ELSE
    2622       154796 :                         CALL cp_fm_start_copy_general(kp%pmat(ic, ispin), fmwork(ic), para_env, info(indx))
    2623              :                      END IF
    2624              :                   END IF
    2625              :                END DO
    2626              :             ELSE
    2627       135624 :                DO ic = 1, nc
    2628        90416 :                   indx = indx + 1
    2629       135624 :                   CALL cp_fm_start_copy_general(fmdummy, fmwork(ic), para_env, info(indx))
    2630              :                END DO
    2631              :             END IF
    2632              :          END DO
    2633              :       END DO
    2634              : 
    2635              :       ! Finish communication and transform the received matrices
    2636        38254 :       indx = 0
    2637        78994 :       DO ispin = 1, nspin
    2638       206290 :          DO ik = 1, nkp
    2639       381720 :             DO ic = 1, nc
    2640       254424 :                indx = indx + 1
    2641       381720 :                CALL cp_fm_finish_copy_general(fmwork(ic), info(indx))
    2642              :             END DO
    2643              : 
    2644              :             ! reduce to dbcsr storage
    2645       127296 :             IF (real_only) THEN
    2646          168 :                CALL copy_fm_to_dbcsr(fmwork(1), rpmat, keep_sparsity=.TRUE.)
    2647              :             ELSE
    2648       127128 :                CALL copy_fm_to_dbcsr(fmwork(1), rpmat, keep_sparsity=.TRUE.)
    2649       127128 :                CALL copy_fm_to_dbcsr(fmwork(2), cpmat, keep_sparsity=.TRUE.)
    2650              :             END IF
    2651              : 
    2652              :             CALL kp_transform_density_matrix(kpoint, denmat, rpmat, cpmat, srpmat, scpmat, &
    2653              :                                              ispin, real_only, ik, xkp(1:3, ik), wkp(ik), &
    2654       168036 :                                              transform_plan)
    2655              :          END DO
    2656              :       END DO
    2657              : 
    2658              :       ! Clean up communication
    2659        38254 :       indx = 0
    2660        78994 :       DO ispin = 1, nspin
    2661       206290 :          DO ik = 1, nkp
    2662       127296 :             my_kpgrp = (ik >= kpoint%kp_range(1) .AND. ik <= kpoint%kp_range(2))
    2663        40740 :             IF (my_kpgrp) THEN
    2664       246096 :                ikk = ik - kpoint%kp_range(1) + 1
    2665              :                IF (aux_fit) THEN
    2666       246096 :                   kp => kpoint%kp_aux_env(ikk)%kpoint_env
    2667              :                ELSE
    2668       246096 :                   kp => kpoint%kp_env(ikk)%kpoint_env
    2669              :                END IF
    2670              : 
    2671       246096 :                DO ic = 1, nc
    2672       164008 :                   indx = indx + 1
    2673       246096 :                   CALL cp_fm_cleanup_copy_general(info(indx))
    2674              :                END DO
    2675              :             ELSE
    2676              :                ! calls with dummy arguments, so not included
    2677              :                ! therefore just increment counter by trip count
    2678        45208 :                indx = indx + nc
    2679              :             END IF
    2680              :          END DO
    2681              :       END DO
    2682              : 
    2683              :       ! All done
    2684        38254 :       CALL kp_transform_plan_release(transform_plan)
    2685       292678 :       DEALLOCATE (info)
    2686              : 
    2687        38254 :       CALL dbcsr_deallocate_matrix(rpmat)
    2688        38254 :       CALL dbcsr_deallocate_matrix(cpmat)
    2689        38254 :       IF (.NOT. kpoint%full_grid) THEN
    2690        35012 :          CALL dbcsr_deallocate_matrix(srpmat)
    2691        35012 :          CALL dbcsr_deallocate_matrix(scpmat)
    2692              :       END IF
    2693              : 
    2694        38254 :       CALL timestop(handle)
    2695              : 
    2696        76508 :    END SUBROUTINE kpoint_density_transform
    2697              : 
    2698              : ! **************************************************************************************************
    2699              : !> \brief One-rank K-to-R density transform without full-matrix redistribution.
    2700              : !>        MPI communication remains on the generic path; this routine is called
    2701              : !>        only when every k-point is local to the current rank.
    2702              : !> \param kpoint ...
    2703              : !> \param denmat ...
    2704              : !> \param wtype ...
    2705              : !> \param aux_fit ...
    2706              : !> \param do_ext ...
    2707              : !> \param pmat_ext ...
    2708              : !> \param rpmat ...
    2709              : !> \param cpmat ...
    2710              : !> \param srpmat ...
    2711              : !> \param scpmat ...
    2712              : !> \param real_only ...
    2713              : !> \param nspin ...
    2714              : !> \param nimg ...
    2715              : !> \param nkp ...
    2716              : !> \param xkp ...
    2717              : !> \param wkp ...
    2718              : !> \param plan ...
    2719              : ! **************************************************************************************************
    2720            0 :    SUBROUTINE kpoint_density_transform_local(kpoint, denmat, wtype, aux_fit, do_ext, pmat_ext, &
    2721              :                                              rpmat, cpmat, srpmat, scpmat, real_only, nspin, nimg, &
    2722              :                                              nkp, xkp, wkp, plan)
    2723              : 
    2724              :       TYPE(kpoint_type), POINTER                         :: kpoint
    2725              :       TYPE(dbcsr_p_type), DIMENSION(:, :)                :: denmat
    2726              :       LOGICAL, INTENT(IN)                                :: wtype, aux_fit, do_ext
    2727              :       TYPE(cp_fm_type), DIMENSION(:, :, :), INTENT(IN), &
    2728              :          OPTIONAL                                        :: pmat_ext
    2729              :       TYPE(dbcsr_type), POINTER                          :: rpmat, cpmat, srpmat, scpmat
    2730              :       LOGICAL, INTENT(IN)                                :: real_only
    2731              :       INTEGER, INTENT(IN)                                :: nspin, nimg, nkp
    2732              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: xkp
    2733              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: wkp
    2734              :       TYPE(kp_transform_plan_type), INTENT(IN)           :: plan
    2735              : 
    2736              :       INTEGER                                            :: ic, ik, ispin
    2737              :       TYPE(cp_fm_type), POINTER                          :: source_c, source_r
    2738              :       TYPE(kpoint_env_type), POINTER                     :: kp
    2739              : 
    2740            0 :       CPASSERT(kpoint%kp_range(1) == 1 .AND. kpoint%kp_range(2) == nkp)
    2741            0 :       CPASSERT(.NOT. do_ext .OR. PRESENT(pmat_ext))
    2742              : 
    2743            0 :       DO ispin = 1, nspin
    2744            0 :          DO ic = 1, nimg
    2745            0 :             CALL dbcsr_set(denmat(ispin, ic)%matrix, 0.0_dp)
    2746              :          END DO
    2747              : 
    2748            0 :          DO ik = 1, nkp
    2749            0 :             IF (aux_fit) THEN
    2750            0 :                kp => kpoint%kp_aux_env(ik)%kpoint_env
    2751              :             ELSE
    2752            0 :                kp => kpoint%kp_env(ik)%kpoint_env
    2753              :             END IF
    2754              : 
    2755            0 :             IF (do_ext) THEN
    2756            0 :                CALL kp_copy_fm_to_dbcsr_local(pmat_ext(ik, 1, ispin), rpmat)
    2757            0 :                IF (.NOT. real_only) CALL kp_copy_fm_to_dbcsr_local(pmat_ext(ik, 2, ispin), cpmat)
    2758              :             ELSE
    2759            0 :                IF (wtype) THEN
    2760            0 :                   source_r => kp%wmat(1, ispin)
    2761            0 :                   IF (.NOT. real_only) source_c => kp%wmat(2, ispin)
    2762              :                ELSE
    2763            0 :                   source_r => kp%pmat(1, ispin)
    2764            0 :                   IF (.NOT. real_only) source_c => kp%pmat(2, ispin)
    2765              :                END IF
    2766            0 :                CALL kp_copy_fm_to_dbcsr_local(source_r, rpmat)
    2767            0 :                IF (.NOT. real_only) CALL kp_copy_fm_to_dbcsr_local(source_c, cpmat)
    2768              :             END IF
    2769              : 
    2770              :             CALL kp_transform_density_matrix(kpoint, denmat, rpmat, cpmat, srpmat, scpmat, &
    2771            0 :                                              ispin, real_only, ik, xkp(1:3, ik), wkp(ik), plan)
    2772              :          END DO
    2773              :       END DO
    2774              : 
    2775            0 :    END SUBROUTINE kpoint_density_transform_local
    2776              : 
    2777              : ! **************************************************************************************************
    2778              : !> \brief Apply k-point symmetry and accumulate one reciprocal-space density matrix in real space.
    2779              : !> \param kpoint ...
    2780              : !> \param denmat ...
    2781              : !> \param rpmat ...
    2782              : !> \param cpmat ...
    2783              : !> \param srpmat ...
    2784              : !> \param scpmat ...
    2785              : !> \param ispin ...
    2786              : !> \param real_only ...
    2787              : !> \param ik ...
    2788              : !> \param xkp ...
    2789              : !> \param wkp ...
    2790              : !> \param plan ...
    2791              : ! **************************************************************************************************
    2792       127296 :    SUBROUTINE kp_transform_density_matrix(kpoint, denmat, rpmat, cpmat, srpmat, scpmat, &
    2793              :                                           ispin, real_only, ik, xkp, wkp, plan)
    2794              : 
    2795              :       TYPE(kpoint_type), POINTER                         :: kpoint
    2796              :       TYPE(dbcsr_p_type), DIMENSION(:, :)                :: denmat
    2797              :       TYPE(dbcsr_type), POINTER                          :: rpmat, cpmat, srpmat, scpmat
    2798              :       INTEGER, INTENT(IN)                                :: ispin
    2799              :       LOGICAL, INTENT(IN)                                :: real_only
    2800              :       INTEGER, INTENT(IN)                                :: ik
    2801              :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: xkp
    2802              :       REAL(KIND=dp), INTENT(IN)                          :: wkp
    2803              :       TYPE(kp_transform_plan_type), INTENT(IN)           :: plan
    2804              : 
    2805              :       INTEGER                                            :: ir, ira, is, jr
    2806              :       LOGICAL                                            :: reverse_phase
    2807              :       REAL(KIND=dp)                                      :: symmetry_weight
    2808       127296 :       TYPE(kind_rotmat_type), DIMENSION(:), POINTER      :: kind_rot
    2809              :       TYPE(kpoint_sym_type), POINTER                     :: kpsym
    2810              : 
    2811       127296 :       kpsym => kpoint%kp_sym(ik)%kpoint_sym
    2812            0 :       CPASSERT(ASSOCIATED(kpsym))
    2813       127296 :       IF (kpsym%apply_symmetry) THEN
    2814        33070 :          symmetry_weight = wkp/REAL(kpsym%nwght, KIND=dp)
    2815       170518 :          DO is = 1, kpsym%nwght
    2816       137448 :             ir = ABS(kpsym%rotp(is))
    2817       137448 :             ira = 0
    2818      3538096 :             DO jr = 1, SIZE(kpoint%ibrot)
    2819      3538096 :                IF (ir == kpoint%ibrot(jr)) ira = jr
    2820              :             END DO
    2821       137448 :             CPASSERT(ira > 0)
    2822       137448 :             kind_rot => kpoint%kind_rotmat(ira, :)
    2823       137448 :             CPASSERT(kpsym%phase_mode(is) > 0)
    2824       137448 :             reverse_phase = kpsym%phase_mode(is) == 2
    2825              :             CALL symtrans_phase(srpmat, scpmat, rpmat, cpmat, real_only, kind_rot, &
    2826              :                                 kpsym%rot(1:3, 1:3, is), kpsym%f0(:, is), &
    2827              :                                 kpsym%fcell_gauge(:, :, is), kpoint%atype, &
    2828       137448 :                                 kpsym%xkp(1:3, is), kpsym%rotp(is) < 0, reverse_phase)
    2829              :             CALL transform_dmat(denmat, srpmat, scpmat, ispin, real_only, plan, &
    2830       170518 :                                 kpsym%xkp(1:3, is), symmetry_weight)
    2831              :          END DO
    2832              :       ELSE
    2833        94226 :          CALL transform_dmat(denmat, rpmat, cpmat, ispin, real_only, plan, xkp, wkp)
    2834              :       END IF
    2835              : 
    2836       127296 :    END SUBROUTINE kp_transform_density_matrix
    2837              : 
    2838              : ! **************************************************************************************************
    2839              : !> \brief Copy a one-rank full matrix directly into existing DBCSR blocks.
    2840              : !> \param fm ...
    2841              : !> \param matrix ...
    2842              : ! **************************************************************************************************
    2843            0 :    SUBROUTINE kp_copy_fm_to_dbcsr_local(fm, matrix)
    2844              : 
    2845              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm
    2846              :       TYPE(dbcsr_type), POINTER                          :: matrix
    2847              : 
    2848              :       INTEGER                                            :: col_offset, row_offset
    2849              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    2850            0 :          POINTER                                         :: full
    2851            0 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: block
    2852              :       TYPE(dbcsr_iterator_type)                          :: iterator
    2853              : 
    2854            0 :       CALL cp_fm_get_info(fm, local_data=full)
    2855            0 :       CALL dbcsr_iterator_start(iterator, matrix, shared=.FALSE.)
    2856            0 :       DO WHILE (dbcsr_iterator_blocks_left(iterator))
    2857              :          CALL dbcsr_iterator_next_block(iterator, block=block, row_offset=row_offset, &
    2858            0 :                                         col_offset=col_offset)
    2859              :          block(:, :) = full(row_offset:row_offset + SIZE(block, 1) - 1, &
    2860            0 :                             col_offset:col_offset + SIZE(block, 2) - 1)
    2861              :       END DO
    2862            0 :       CALL dbcsr_iterator_stop(iterator)
    2863              : 
    2864            0 :    END SUBROUTINE kp_copy_fm_to_dbcsr_local
    2865              : 
    2866              : ! **************************************************************************************************
    2867              : !> \brief Build the immutable neighbor-list traversal shared by R-to-K and K-to-R transforms.
    2868              : !> \param plan ...
    2869              : !> \param sab_nl ...
    2870              : !> \param cell_to_index ...
    2871              : !> \param nimg ...
    2872              : !> \param block_template ...
    2873              : !> \param group_entries ...
    2874              : ! **************************************************************************************************
    2875        38254 :    SUBROUTINE kp_transform_plan_create(plan, sab_nl, cell_to_index, nimg, block_template, group_entries)
    2876              : 
    2877              :       TYPE(kp_transform_plan_type), INTENT(OUT)          :: plan
    2878              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    2879              :          POINTER                                         :: sab_nl
    2880              :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
    2881              :       INTEGER, INTENT(IN)                                :: nimg
    2882              :       TYPE(dbcsr_type), INTENT(IN), OPTIONAL             :: block_template
    2883              :       LOGICAL, INTENT(IN), OPTIONAL                      :: group_entries
    2884              : 
    2885              :       INTEGER                                            :: i, iatom, icell, icol, igroup, irow, &
    2886              :                                                             jatom, nblock
    2887        38254 :       INTEGER(KIND=int_8), ALLOCATABLE, DIMENSION(:)     :: key
    2888        38254 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: order
    2889              :       INTEGER, DIMENSION(3)                              :: cell
    2890        38254 :       INTEGER, DIMENSION(:), POINTER                     :: col_offsets, row_offsets
    2891              :       LOGICAL                                            :: do_grouping, do_symmetric, store_offsets
    2892              :       TYPE(neighbor_list_iterator_p_type), &
    2893        38254 :          DIMENSION(:), POINTER                           :: iterator
    2894              : 
    2895        38254 :       CALL get_neighbor_list_set_p(neighbor_list_sets=sab_nl, symmetric=do_symmetric)
    2896        38254 :       plan%symmetric = do_symmetric
    2897        38254 :       do_grouping = .FALSE.
    2898        38254 :       IF (PRESENT(group_entries)) do_grouping = group_entries
    2899        38254 :       store_offsets = PRESENT(block_template)
    2900        38254 :       IF (store_offsets) THEN
    2901            0 :          CALL dbcsr_get_info(block_template, row_blk_offset=row_offsets, col_blk_offset=col_offsets)
    2902              :       END IF
    2903        38254 :       plan%nentry = 0
    2904        38254 :       plan%ngroup = 0
    2905        38254 :       CALL neighbor_list_iterator_create(iterator, sab_nl)
    2906      9130919 :       DO WHILE (neighbor_list_iterate(iterator) == 0)
    2907      9092665 :          CALL get_iterator_info(iterator, cell=cell)
    2908      9092665 :          icell = cell_to_index(cell(1), cell(2), cell(3))
    2909      9130919 :          IF (icell >= 1 .AND. icell <= nimg) plan%nentry = plan%nentry + 1
    2910              :       END DO
    2911        38254 :       CALL neighbor_list_iterator_release(iterator)
    2912              : 
    2913            0 :       ALLOCATE (plan%row(plan%nentry), plan%col(plan%nentry), plan%image(plan%nentry), &
    2914       339371 :                 plan%cell(3, plan%nentry), plan%symmetry_sign(plan%nentry))
    2915        38254 :       IF (store_offsets) THEN
    2916            0 :          ALLOCATE (plan%row_offset(plan%nentry), plan%col_offset(plan%nentry))
    2917              :       END IF
    2918              : 
    2919        38254 :       i = 0
    2920        38254 :       CALL neighbor_list_iterator_create(iterator, sab_nl)
    2921      9130919 :       DO WHILE (neighbor_list_iterate(iterator) == 0)
    2922      9092665 :          CALL get_iterator_info(iterator, iatom=iatom, jatom=jatom, cell=cell)
    2923      9092665 :          icell = cell_to_index(cell(1), cell(2), cell(3))
    2924      9092665 :          IF (icell < 1 .OR. icell > nimg) CYCLE
    2925      9092577 :          i = i + 1
    2926      9092577 :          irow = iatom
    2927      9092577 :          icol = jatom
    2928      9092577 :          plan%symmetry_sign(i) = 1.0_dp
    2929      9092577 :          IF (do_symmetric .AND. iatom > jatom) THEN
    2930      3842507 :             irow = jatom
    2931      3842507 :             icol = iatom
    2932      3842507 :             plan%symmetry_sign(i) = -1.0_dp
    2933              :          END IF
    2934      9092577 :          plan%row(i) = irow
    2935      9092577 :          plan%col(i) = icol
    2936      9092577 :          IF (store_offsets) THEN
    2937            0 :             plan%row_offset(i) = row_offsets(irow)
    2938            0 :             plan%col_offset(i) = col_offsets(icol)
    2939              :          END IF
    2940      9092577 :          plan%image(i) = icell
    2941     36408650 :          plan%cell(:, i) = cell
    2942              :       END DO
    2943        38254 :       CALL neighbor_list_iterator_release(iterator)
    2944        38254 :       CPASSERT(i == plan%nentry)
    2945              : 
    2946        38254 :       IF (do_grouping .AND. plan%nentry > 0) THEN
    2947     18222425 :          nblock = MAX(MAXVAL(plan%row), MAXVAL(plan%col))
    2948       186355 :          ALLOCATE (key(plan%nentry), order(plan%nentry))
    2949      9129848 :          DO i = 1, plan%nentry
    2950              :             key(i) = INT(plan%image(i), KIND=int_8) + INT(nimg, KIND=int_8)* &
    2951              :                      (INT(plan%row(i) - 1, KIND=int_8) + INT(nblock, KIND=int_8)* &
    2952      9129848 :                       INT(plan%col(i) - 1, KIND=int_8))
    2953              :          END DO
    2954        37271 :          CALL sort(key, plan%nentry, order)
    2955     18259696 :          plan%row(:) = plan%row(order)
    2956     18259696 :          plan%col(:) = plan%col(order)
    2957        37271 :          IF (store_offsets) THEN
    2958            0 :             plan%row_offset(:) = plan%row_offset(order)
    2959            0 :             plan%col_offset(:) = plan%col_offset(order)
    2960              :          END IF
    2961     18259696 :          plan%image(:) = plan%image(order)
    2962     72815158 :          plan%cell(:, :) = plan%cell(:, order)
    2963     18259696 :          plan%symmetry_sign(:) = plan%symmetry_sign(order)
    2964              : 
    2965        37271 :          plan%ngroup = 1
    2966      9092577 :          DO i = 2, plan%nentry
    2967      9092577 :             IF (key(i) /= key(i - 1)) plan%ngroup = plan%ngroup + 1
    2968              :          END DO
    2969       111813 :          ALLOCATE (plan%group_start(plan%ngroup + 1))
    2970        37271 :          igroup = 1
    2971        37271 :          plan%group_start(igroup) = 1
    2972      9092577 :          DO i = 2, plan%nentry
    2973      9092577 :             IF (key(i) /= key(i - 1)) THEN
    2974      9055306 :                igroup = igroup + 1
    2975      9055306 :                plan%group_start(igroup) = i
    2976              :             END IF
    2977              :          END DO
    2978        37271 :          plan%group_start(plan%ngroup + 1) = plan%nentry + 1
    2979        37271 :          DEALLOCATE (key, order)
    2980              :       END IF
    2981              : 
    2982        76508 :    END SUBROUTINE kp_transform_plan_create
    2983              : 
    2984              : ! **************************************************************************************************
    2985              : !> \brief Release a K-to-R traversal plan.
    2986              : !> \param plan ...
    2987              : ! **************************************************************************************************
    2988        38254 :    SUBROUTINE kp_transform_plan_release(plan)
    2989              : 
    2990              :       TYPE(kp_transform_plan_type), INTENT(INOUT)        :: plan
    2991              : 
    2992        38254 :       DEALLOCATE (plan%row, plan%col, plan%image, plan%cell, plan%symmetry_sign)
    2993        38254 :       IF (ALLOCATED(plan%row_offset)) DEALLOCATE (plan%row_offset, plan%col_offset)
    2994        38254 :       IF (ALLOCATED(plan%group_start)) DEALLOCATE (plan%group_start)
    2995        38254 :       plan%nentry = 0
    2996        38254 :       plan%ngroup = 0
    2997        38254 :       plan%symmetric = .FALSE.
    2998              : 
    2999        38254 :    END SUBROUTINE kp_transform_plan_release
    3000              : 
    3001              : ! **************************************************************************************************
    3002              : !> \brief real space density matrices in DBCSR format
    3003              : !> \param denmat  Real space (DBCSR) density matrix
    3004              : !> \param rpmat ...
    3005              : !> \param cpmat ...
    3006              : !> \param ispin ...
    3007              : !> \param real_only ...
    3008              : !> \param plan precomputed neighbor-list traversal
    3009              : !> \param xkp ...
    3010              : !> \param wkp ...
    3011              : ! **************************************************************************************************
    3012       231674 :    SUBROUTINE transform_dmat(denmat, rpmat, cpmat, ispin, real_only, plan, xkp, wkp)
    3013              : 
    3014              :       TYPE(dbcsr_p_type), DIMENSION(:, :)                :: denmat
    3015              :       TYPE(dbcsr_type), POINTER                          :: rpmat, cpmat
    3016              :       INTEGER, INTENT(IN)                                :: ispin
    3017              :       LOGICAL, INTENT(IN)                                :: real_only
    3018              :       TYPE(kp_transform_plan_type), INTENT(IN)           :: plan
    3019              :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: xkp
    3020              :       REAL(KIND=dp), INTENT(IN)                          :: wkp
    3021              : 
    3022              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'transform_dmat'
    3023              : 
    3024              :       INTEGER                                            :: handle, i, ifirst, igroup, ilast, &
    3025              :                                                             nthreads
    3026              :       LOGICAL                                            :: found
    3027              :       REAL(KIND=dp)                                      :: arg, coskl, sinkl
    3028       231674 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: cblock, dblock, rblock
    3029              : 
    3030       231674 :       CALL timeset(routineN, handle)
    3031              : 
    3032       231674 :       nthreads = 1
    3033       231674 : !$    nthreads = MAX(1, MIN(omp_get_max_threads(), plan%ngroup))
    3034              :       ! Entries are grouped by (image,row-block,col-block), hence workers
    3035              :       ! update disjoint DBCSR blocks without atomics or false sharing.
    3036              : !$OMP PARALLEL DO DEFAULT(NONE) SCHEDULE(DYNAMIC, 4) NUM_THREADS(nthreads) &
    3037              : !$OMP SHARED(plan,denmat,rpmat,cpmat,ispin,real_only,xkp,wkp,nthreads) &
    3038       231674 : !$OMP PRIVATE(igroup,ifirst,ilast,i,arg,coskl,sinkl,found,dblock,rblock,cblock)
    3039              :       DO igroup = 1, plan%ngroup
    3040              :          ifirst = plan%group_start(igroup)
    3041              :          ilast = plan%group_start(igroup + 1) - 1
    3042              : 
    3043              :          !We have a FT from KP to real-space: S(R) = sum_k S(k)*exp(-i*k*R), with S(k) a complex number
    3044              :          !Therefore, we have: S(R) = sum_k Re(S(k))*cos(k*R) -i^2*Im(S(k))*sin(k*R)
    3045              :          !                         = sum_k Re(S(k))*cos(k*R) + Im(S(k))*sin(k*R)
    3046              :          !fc = +- 1 is due to the usual non-symmetric real-space matrices stored as symmetric ones
    3047              :          coskl = 0.0_dp
    3048              :          sinkl = 0.0_dp
    3049              :          DO i = ifirst, ilast
    3050              :             arg = DOT_PRODUCT(REAL(plan%cell(:, i), KIND=dp), xkp)
    3051              :             coskl = coskl + wkp*COS(twopi*arg)
    3052              :             sinkl = sinkl + wkp*plan%symmetry_sign(i)*SIN(twopi*arg)
    3053              :          END DO
    3054              : 
    3055              :          CALL dbcsr_get_block_p(matrix=denmat(ispin, plan%image(ifirst))%matrix, &
    3056              :                                 row=plan%row(ifirst), col=plan%col(ifirst), &
    3057              :                                 block=dblock, found=found)
    3058              :          IF (.NOT. found) CYCLE
    3059              : 
    3060              :          IF (real_only) THEN
    3061              :             CALL dbcsr_get_readonly_block_p(matrix=rpmat, row=plan%row(ifirst), col=plan%col(ifirst), &
    3062              :                                             block=rblock, found=found)
    3063              :             IF (.NOT. found) CYCLE
    3064              :             dblock = dblock + coskl*rblock
    3065              :          ELSE
    3066              :             CALL dbcsr_get_readonly_block_p(matrix=rpmat, row=plan%row(ifirst), col=plan%col(ifirst), &
    3067              :                                             block=rblock, found=found)
    3068              :             IF (.NOT. found) CYCLE
    3069              :             CALL dbcsr_get_readonly_block_p(matrix=cpmat, row=plan%row(ifirst), col=plan%col(ifirst), &
    3070              :                                             block=cblock, found=found)
    3071              :             IF (.NOT. found) CYCLE
    3072              :             dblock = dblock + coskl*rblock
    3073              :             dblock = dblock + sinkl*cblock
    3074              :          END IF
    3075              :       END DO
    3076              : !$OMP END PARALLEL DO
    3077              : 
    3078       231674 :       CALL timestop(handle)
    3079              : 
    3080       231674 :    END SUBROUTINE transform_dmat
    3081              : 
    3082              : ! **************************************************************************************************
    3083              : !> \brief Allocate a dense work matrix with the requested shape
    3084              : !> \param work dense work matrix
    3085              : !> \param nrow number of rows
    3086              : !> \param ncol number of columns
    3087              : ! **************************************************************************************************
    3088      3066398 :    SUBROUTINE ensure_work_matrix(work, nrow, ncol)
    3089              : 
    3090              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
    3091              :          INTENT(INOUT)                                   :: work
    3092              :       INTEGER, INTENT(IN)                                :: nrow, ncol
    3093              : 
    3094      3066398 :       IF (ALLOCATED(work)) THEN
    3095      2955155 :          IF (SIZE(work, 1) == nrow .AND. SIZE(work, 2) == ncol) RETURN
    3096        47397 :          DEALLOCATE (work)
    3097              :       END IF
    3098       634560 :       ALLOCATE (work(nrow, ncol))
    3099              : 
    3100              :    END SUBROUTINE ensure_work_matrix
    3101              : 
    3102              : ! **************************************************************************************************
    3103              : !> \brief Select the Bloch-phase convention that preserves overlap covariance.
    3104              : !> \param kpoint ...
    3105              : !> \param overlap_rs ...
    3106              : !> \param tempmat ...
    3107              : !> \param sab_nl ...
    3108              : !> \param cell_to_index ...
    3109              : ! **************************************************************************************************
    3110        37218 :    SUBROUTINE calibrate_symmetry_phases(kpoint, overlap_rs, tempmat, sab_nl, cell_to_index)
    3111              : 
    3112              :       TYPE(kpoint_type), POINTER                         :: kpoint
    3113              :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: overlap_rs
    3114              :       TYPE(dbcsr_type), POINTER                          :: tempmat
    3115              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    3116              :          POINTER                                         :: sab_nl
    3117              :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
    3118              : 
    3119              :       CHARACTER(LEN=256)                                 :: phase_error
    3120              :       INTEGER                                            :: best_mode, ik, ir, ira, is, jr, mode
    3121              :       LOGICAL                                            :: needs_calibration, reverse
    3122              :       REAL(KIND=dp)                                      :: best_residual, candidate_norm, &
    3123              :                                                             direct_norm, overlap_dot, &
    3124              :                                                             phase_tolerance, relative_residual
    3125              :       TYPE(dbcsr_type), POINTER                          :: direct_c, direct_r, source_c, source_r, &
    3126              :                                                             sym_c, sym_r
    3127        37218 :       TYPE(kind_rotmat_type), DIMENSION(:), POINTER      :: kind_rot
    3128              :       TYPE(kpoint_sym_type), POINTER                     :: kpsym
    3129              : 
    3130        37218 :       needs_calibration = .FALSE.
    3131       127178 :       DO ik = 1, kpoint%nkp
    3132        97858 :          kpsym => kpoint%kp_sym(ik)%kpoint_sym
    3133       127178 :          IF (kpsym%apply_symmetry) THEN
    3134        92236 :             IF (ANY(kpsym%phase_mode == 0)) THEN
    3135              :                needs_calibration = .TRUE.
    3136              :                EXIT
    3137              :             END IF
    3138              :          END IF
    3139              :       END DO
    3140        37218 :       IF (.NOT. needs_calibration) RETURN
    3141              : 
    3142         7898 :       ALLOCATE (source_r, source_c, direct_r, direct_c, sym_r, sym_c)
    3143         7898 :       CALL dbcsr_create(source_r, template=tempmat, matrix_type=dbcsr_type_symmetric)
    3144         7898 :       CALL dbcsr_create(source_c, template=tempmat, matrix_type=dbcsr_type_antisymmetric)
    3145         7898 :       CALL dbcsr_create(direct_r, template=tempmat, matrix_type=dbcsr_type_symmetric)
    3146         7898 :       CALL dbcsr_create(direct_c, template=tempmat, matrix_type=dbcsr_type_antisymmetric)
    3147         7898 :       CALL dbcsr_create(sym_r, template=tempmat, matrix_type=dbcsr_type_symmetric)
    3148         7898 :       CALL dbcsr_create(sym_c, template=tempmat, matrix_type=dbcsr_type_antisymmetric)
    3149         7898 :       CALL cp_dbcsr_alloc_block_from_nbl(source_r, sab_nl)
    3150         7898 :       CALL cp_dbcsr_alloc_block_from_nbl(source_c, sab_nl)
    3151         7898 :       CALL cp_dbcsr_alloc_block_from_nbl(direct_r, sab_nl)
    3152         7898 :       CALL cp_dbcsr_alloc_block_from_nbl(direct_c, sab_nl)
    3153         7898 :       CALL cp_dbcsr_alloc_block_from_nbl(sym_r, sab_nl)
    3154         7898 :       CALL cp_dbcsr_alloc_block_from_nbl(sym_c, sab_nl)
    3155              : 
    3156         7898 :       phase_tolerance = MAX(1.0e-6_dp, 100.0_dp*kpoint%eps_geo)
    3157        28380 :       DO ik = 1, kpoint%nkp
    3158        20482 :          kpsym => kpoint%kp_sym(ik)%kpoint_sym
    3159        20482 :          IF (.NOT. kpsym%apply_symmetry) CYCLE
    3160        97480 :          IF (ALL(kpsym%phase_mode > 0)) CYCLE
    3161              : 
    3162        15652 :          CALL dbcsr_set(source_r, 0.0_dp)
    3163        15652 :          CALL dbcsr_set(source_c, 0.0_dp)
    3164              :          CALL rskp_transform(source_r, source_c, overlap_rs, 1, kpoint%xkp(1:3, ik), &
    3165        15652 :                              cell_to_index, sab_nl)
    3166              : 
    3167       114114 :          DO is = 1, kpsym%nwght
    3168        90564 :             IF (kpsym%phase_mode(is) > 0) CYCLE
    3169        12424 :             CALL dbcsr_set(direct_r, 0.0_dp)
    3170        12424 :             CALL dbcsr_set(direct_c, 0.0_dp)
    3171              :             CALL rskp_transform(direct_r, direct_c, overlap_rs, 1, kpsym%xkp(1:3, is), &
    3172        12424 :                                 cell_to_index, sab_nl)
    3173        12424 :             CALL dbcsr_dot(direct_r, direct_r, direct_norm)
    3174        12424 :             CALL dbcsr_dot(direct_c, direct_c, candidate_norm)
    3175        12424 :             direct_norm = direct_norm + candidate_norm
    3176              : 
    3177        12424 :             ir = ABS(kpsym%rotp(is))
    3178        12424 :             ira = 0
    3179       310008 :             DO jr = 1, SIZE(kpoint%ibrot)
    3180       310008 :                IF (ir == kpoint%ibrot(jr)) ira = jr
    3181              :             END DO
    3182        12424 :             CPASSERT(ira > 0)
    3183        12424 :             kind_rot => kpoint%kind_rotmat(ira, :)
    3184              : 
    3185        12424 :             best_mode = 0
    3186        12424 :             best_residual = HUGE(1.0_dp)
    3187        37272 :             DO mode = 1, 2
    3188        24848 :                reverse = mode == 2
    3189              :                CALL symtrans_phase(sym_r, sym_c, source_r, source_c, .FALSE., kind_rot, &
    3190              :                                    kpsym%rot(1:3, 1:3, is), kpsym%f0(:, is), &
    3191              :                                    kpsym%fcell_gauge(:, :, is), kpoint%atype, &
    3192        24848 :                                    kpsym%xkp(1:3, is), kpsym%rotp(is) < 0, reverse)
    3193        24848 :                CALL dbcsr_dot(sym_r, sym_r, candidate_norm)
    3194        24848 :                CALL dbcsr_dot(sym_c, sym_c, relative_residual)
    3195        24848 :                candidate_norm = candidate_norm + relative_residual
    3196        24848 :                CALL dbcsr_dot(sym_r, direct_r, overlap_dot)
    3197        24848 :                CALL dbcsr_dot(sym_c, direct_c, relative_residual)
    3198        24848 :                overlap_dot = overlap_dot + relative_residual
    3199              :                relative_residual = SQRT(MAX(0.0_dp, candidate_norm + direct_norm - &
    3200        24848 :                                             2.0_dp*overlap_dot)/MAX(direct_norm, TINY(1.0_dp)))
    3201        37272 :                IF (relative_residual < best_residual) THEN
    3202        16928 :                   best_residual = relative_residual
    3203        16928 :                   best_mode = mode
    3204              :                END IF
    3205              :             END DO
    3206        12424 :             IF (best_residual > phase_tolerance) THEN
    3207              :                WRITE (phase_error, '(A,ES12.4,A,I0,A,I0)') &
    3208            0 :                   "No Bloch-phase direction preserves overlap covariance; residual=", &
    3209            0 :                   best_residual, ", irreducible k-point=", ik, ", operation=", is
    3210            0 :                CALL cp_abort(__LOCATION__, TRIM(phase_error))
    3211              :             END IF
    3212       123470 :             kpsym%phase_mode(is) = best_mode
    3213              :          END DO
    3214              :       END DO
    3215              : 
    3216         7898 :       CALL dbcsr_deallocate_matrix(source_r)
    3217         7898 :       CALL dbcsr_deallocate_matrix(source_c)
    3218         7898 :       CALL dbcsr_deallocate_matrix(direct_r)
    3219         7898 :       CALL dbcsr_deallocate_matrix(direct_c)
    3220         7898 :       CALL dbcsr_deallocate_matrix(sym_r)
    3221         7898 :       CALL dbcsr_deallocate_matrix(sym_c)
    3222              : 
    3223        37218 :    END SUBROUTINE calibrate_symmetry_phases
    3224              : 
    3225              : ! **************************************************************************************************
    3226              : !> \brief Symmetrize a complex k-point matrix including Bloch phase shifts
    3227              : !> \param srpmat real part of transformed matrix
    3228              : !> \param scpmat imaginary part of transformed matrix
    3229              : !> \param rpmat real part of reference matrix
    3230              : !> \param cpmat imaginary part of reference matrix
    3231              : !> \param real_only ...
    3232              : !> \param kmat kind type rotation matrix
    3233              : !> \param rot rotation matrix
    3234              : !> \param f0 atom permutation
    3235              : !> \param fcell atom cell shifts generated by the symmetry operation
    3236              : !> \param atype atom to kind pointer
    3237              : !> \param xkp target k-point coordinates
    3238              : !> \param time_reversal ...
    3239              : !> \param reverse_phase ...
    3240              : ! **************************************************************************************************
    3241       162296 :    SUBROUTINE symtrans_phase(srpmat, scpmat, rpmat, cpmat, real_only, kmat, rot, f0, fcell, atype, &
    3242              :                              xkp, time_reversal, reverse_phase)
    3243              : 
    3244              :       TYPE(dbcsr_type), POINTER                          :: srpmat, scpmat, rpmat, cpmat
    3245              :       LOGICAL, INTENT(IN)                                :: real_only
    3246              :       TYPE(kind_rotmat_type), DIMENSION(:), POINTER      :: kmat
    3247              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN)         :: rot
    3248              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: f0
    3249              :       INTEGER, DIMENSION(:, :), INTENT(IN)               :: fcell
    3250              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: atype
    3251              :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: xkp
    3252              :       LOGICAL, INTENT(IN)                                :: time_reversal, reverse_phase
    3253              : 
    3254              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'symtrans_phase'
    3255              : 
    3256              :       INTEGER                                            :: handle, iatom, icol, ikind, ip, irow, &
    3257              :                                                             jcol, jkind, jp, jrow, mynode, natom, &
    3258              :                                                             nthreads, numnodes, owner
    3259              :       INTEGER, DIMENSION(3)                              :: shift
    3260              :       LOGICAL                                            :: byrows, dorot, found, has_phase, perm, &
    3261              :                                                             trans
    3262              :       REAL(KIND=dp)                                      :: arg, coskl, dr, sinkl
    3263       162296 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: cwork, rwork, twork
    3264       162296 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: cblock, kroti, krotj, rblock, scblock, &
    3265       162296 :                                                             srblock
    3266              :       TYPE(dbcsr_distribution_type)                      :: dist
    3267              :       TYPE(dbcsr_iterator_type)                          :: iter
    3268              : 
    3269       162296 :       CALL timeset(routineN, handle)
    3270              : 
    3271       162296 :       natom = SIZE(f0)
    3272       162296 :       perm = .FALSE.
    3273       653304 :       DO iatom = 1, natom
    3274       549400 :          IF (f0(iatom) == iatom) CYCLE
    3275              :          perm = .TRUE.
    3276       594912 :          EXIT
    3277              :       END DO
    3278              : 
    3279       162296 :       dorot = .FALSE.
    3280      2109848 :       IF (ABS(SUM(ABS(rot)) - 3.0_dp) > 1.e-12_dp) dorot = .TRUE.
    3281       162296 :       dr = ABS(rot(1, 1) - 1.0_dp) + ABS(rot(2, 2) - 1.0_dp) + ABS(rot(3, 3) - 1.0_dp)
    3282       162296 :       IF (ABS(dr) > 1.e-12_dp) dorot = .TRUE.
    3283      2218444 :       has_phase = ANY(fcell /= 0) .OR. time_reversal
    3284              : 
    3285       162296 :       IF (.NOT. (dorot .OR. perm .OR. has_phase)) THEN
    3286        38494 :          CALL dbcsr_copy(srpmat, rpmat)
    3287        38494 :          IF (.NOT. real_only) CALL dbcsr_copy(scpmat, cpmat)
    3288        38494 :          CALL timestop(handle)
    3289        38494 :          RETURN
    3290              :       END IF
    3291              : 
    3292       123802 :       CALL dbcsr_get_info(rpmat, distribution=dist)
    3293       123802 :       CALL dbcsr_distribution_get(dist, mynode=mynode, numnodes=numnodes)
    3294       123802 :       IF (numnodes /= 1 .AND. (perm .OR. has_phase)) THEN
    3295       116958 :          CALL dbcsr_replicate_all(rpmat)
    3296       116958 :          IF (.NOT. real_only) CALL dbcsr_replicate_all(cpmat)
    3297              :       END IF
    3298              : 
    3299       123802 :       CALL dbcsr_set(srpmat, 0.0_dp)
    3300       123802 :       IF (.NOT. real_only) CALL dbcsr_set(scpmat, 0.0_dp)
    3301              : 
    3302       123802 :       nthreads = 1
    3303       123802 : !$    nthreads = omp_get_max_threads()
    3304              :       ! Atom permutations preserve row ownership, while block scheduling can race on a target row.
    3305       123802 :       byrows = .TRUE.
    3306              : !$OMP PARALLEL DEFAULT(NONE) NUM_THREADS(nthreads) &
    3307              : !$OMP SHARED(rpmat,cpmat,srpmat,scpmat,real_only,kmat,rot,f0,fcell,atype,xkp,time_reversal, &
    3308              : !$OMP        reverse_phase,natom,perm,dorot,has_phase,mynode,numnodes,nthreads,byrows) &
    3309              : !$OMP PRIVATE(iter,irow,icol,rblock,rwork,cwork,twork,ikind,jkind,kroti,krotj,shift,arg,coskl, &
    3310              : !$OMP         sinkl,cblock,found,ip,jp,jrow,jcol,trans,srblock,scblock,owner)
    3311              :       CALL dbcsr_iterator_readonly_start(iter, rpmat, dynamic=.TRUE., dynamic_byrows=byrows)
    3312              :       DO WHILE (dbcsr_iterator_blocks_left(iter))
    3313              :          CALL dbcsr_iterator_next_block(iter, irow, icol, rblock)
    3314              :          IF (.NOT. ALLOCATED(rwork)) THEN
    3315              :             ALLOCATE (rwork(SIZE(rblock, 1), SIZE(rblock, 2)))
    3316              :          ELSE IF (SIZE(rwork, 1) /= SIZE(rblock, 1) .OR. SIZE(rwork, 2) /= SIZE(rblock, 2)) THEN
    3317              :             DEALLOCATE (rwork)
    3318              :             ALLOCATE (rwork(SIZE(rblock, 1), SIZE(rblock, 2)))
    3319              :          END IF
    3320              :          IF (.NOT. real_only) THEN
    3321              :             IF (.NOT. ALLOCATED(cwork)) THEN
    3322              :                ALLOCATE (cwork(SIZE(rblock, 1), SIZE(rblock, 2)))
    3323              :             ELSE IF (SIZE(cwork, 1) /= SIZE(rblock, 1) .OR. SIZE(cwork, 2) /= SIZE(rblock, 2)) THEN
    3324              :                DEALLOCATE (cwork)
    3325              :                ALLOCATE (cwork(SIZE(rblock, 1), SIZE(rblock, 2)))
    3326              :             END IF
    3327              :          END IF
    3328              : 
    3329              :          ikind = atype(irow)
    3330              :          jkind = atype(icol)
    3331              :          kroti => kmat(ikind)%rmat
    3332              :          krotj => kmat(jkind)%rmat
    3333              : 
    3334              :          IF (reverse_phase) THEN
    3335              :             shift = fcell(1:3, irow) - fcell(1:3, icol)
    3336              :          ELSE
    3337              :             shift = fcell(1:3, icol) - fcell(1:3, irow)
    3338              :          END IF
    3339              :          arg = REAL(shift(1), dp)*xkp(1) + REAL(shift(2), dp)*xkp(2) + &
    3340              :                REAL(shift(3), dp)*xkp(3)
    3341              :          coskl = COS(twopi*arg)
    3342              :          sinkl = SIN(twopi*arg)
    3343              :          IF (real_only) THEN
    3344              :             IF (ABS(sinkl) > 1.e-12_dp) THEN
    3345              :                CALL cp_abort(__LOCATION__, "Real k-point wavefunctions cannot represent symmetry phases")
    3346              :             END IF
    3347              :             rwork(:, :) = coskl*rblock
    3348              :          ELSE
    3349              :             CALL dbcsr_get_readonly_block_p(matrix=cpmat, row=irow, col=icol, block=cblock, found=found)
    3350              :             rwork(:, :) = coskl*rblock
    3351              :             IF (time_reversal) THEN
    3352              :                cwork(:, :) = -sinkl*rblock
    3353              :                IF (found) THEN
    3354              :                   rwork(:, :) = rwork - sinkl*cblock
    3355              :                   cwork(:, :) = cwork - coskl*cblock
    3356              :                END IF
    3357              :             ELSE
    3358              :                cwork(:, :) = -sinkl*rblock
    3359              :                IF (found) THEN
    3360              :                   rwork(:, :) = rwork + sinkl*cblock
    3361              :                   cwork(:, :) = cwork + coskl*cblock
    3362              :                END IF
    3363              :             END IF
    3364              :          END IF
    3365              : 
    3366              :          ip = f0(irow)
    3367              :          jp = f0(icol)
    3368              :          IF (ip <= jp) THEN
    3369              :             jrow = ip
    3370              :             jcol = jp
    3371              :             trans = .FALSE.
    3372              :          ELSE
    3373              :             jrow = jp
    3374              :             jcol = ip
    3375              :             trans = .TRUE.
    3376              :          END IF
    3377              : 
    3378              :          CALL dbcsr_get_block_p(matrix=srpmat, row=jrow, col=jcol, block=srblock, found=found)
    3379              :          IF (.NOT. found) THEN
    3380              :             CALL dbcsr_get_stored_coordinates(srpmat, jrow, jcol, owner)
    3381              :             CPASSERT(owner /= mynode)
    3382              :             CYCLE
    3383              :          END IF
    3384              :          IF (trans) THEN
    3385              :             CALL ensure_work_matrix(twork, SIZE(krotj, 1), SIZE(rwork, 1))
    3386              :             CALL dgemm('N', 'T', SIZE(krotj, 1), SIZE(rwork, 1), SIZE(krotj, 2), &
    3387              :                        1.0_dp, krotj, SIZE(krotj, 1), rwork, SIZE(rwork, 1), &
    3388              :                        0.0_dp, twork, SIZE(twork, 1))
    3389              :             CALL dgemm('N', 'T', SIZE(twork, 1), SIZE(kroti, 1), SIZE(twork, 2), &
    3390              :                        1.0_dp, twork, SIZE(twork, 1), kroti, SIZE(kroti, 1), &
    3391              :                        1.0_dp, srblock, SIZE(srblock, 1))
    3392              :          ELSE
    3393              :             CALL ensure_work_matrix(twork, SIZE(kroti, 1), SIZE(rwork, 2))
    3394              :             CALL dgemm('N', 'N', SIZE(kroti, 1), SIZE(rwork, 2), SIZE(kroti, 2), &
    3395              :                        1.0_dp, kroti, SIZE(kroti, 1), rwork, SIZE(rwork, 1), &
    3396              :                        0.0_dp, twork, SIZE(twork, 1))
    3397              :             CALL dgemm('N', 'T', SIZE(twork, 1), SIZE(krotj, 1), SIZE(twork, 2), &
    3398              :                        1.0_dp, twork, SIZE(twork, 1), krotj, SIZE(krotj, 1), &
    3399              :                        1.0_dp, srblock, SIZE(srblock, 1))
    3400              :          END IF
    3401              : 
    3402              :          IF (.NOT. real_only) THEN
    3403              :             CALL dbcsr_get_block_p(matrix=scpmat, row=jrow, col=jcol, block=scblock, found=found)
    3404              :             CPASSERT(found)
    3405              :             IF (trans) THEN
    3406              :                CALL ensure_work_matrix(twork, SIZE(krotj, 1), SIZE(cwork, 1))
    3407              :                CALL dgemm('N', 'T', SIZE(krotj, 1), SIZE(cwork, 1), SIZE(krotj, 2), &
    3408              :                           1.0_dp, krotj, SIZE(krotj, 1), cwork, SIZE(cwork, 1), &
    3409              :                           0.0_dp, twork, SIZE(twork, 1))
    3410              :                CALL dgemm('N', 'T', SIZE(twork, 1), SIZE(kroti, 1), SIZE(twork, 2), &
    3411              :                           -1.0_dp, twork, SIZE(twork, 1), kroti, SIZE(kroti, 1), &
    3412              :                           1.0_dp, scblock, SIZE(scblock, 1))
    3413              :             ELSE
    3414              :                CALL ensure_work_matrix(twork, SIZE(kroti, 1), SIZE(cwork, 2))
    3415              :                CALL dgemm('N', 'N', SIZE(kroti, 1), SIZE(cwork, 2), SIZE(kroti, 2), &
    3416              :                           1.0_dp, kroti, SIZE(kroti, 1), cwork, SIZE(cwork, 1), &
    3417              :                           0.0_dp, twork, SIZE(twork, 1))
    3418              :                CALL dgemm('N', 'T', SIZE(twork, 1), SIZE(krotj, 1), SIZE(twork, 2), &
    3419              :                           1.0_dp, twork, SIZE(twork, 1), krotj, SIZE(krotj, 1), &
    3420              :                           1.0_dp, scblock, SIZE(scblock, 1))
    3421              :             END IF
    3422              :          END IF
    3423              :       END DO
    3424       123802 :       CALL dbcsr_iterator_stop(iter)
    3425              : !$OMP END PARALLEL
    3426       123802 :       IF (numnodes /= 1 .AND. (perm .OR. has_phase)) THEN
    3427       116958 :          CALL dbcsr_distribute(rpmat)
    3428       116958 :          IF (.NOT. real_only) CALL dbcsr_distribute(cpmat)
    3429              :       END IF
    3430              : 
    3431       123802 :       CALL timestop(handle)
    3432              : 
    3433       324592 :    END SUBROUTINE symtrans_phase
    3434              : 
    3435              : ! **************************************************************************************************
    3436              : !> \brief Symmetrization of density matrix - transform to new k-point
    3437              : !> \param smat density matrix at new kpoint
    3438              : !> \param pmat reference density matrix
    3439              : !> \param kmat Kind type rotation matrix
    3440              : !> \param rot Rotation matrix
    3441              : !> \param f0 Permutation of atoms under transformation
    3442              : !> \param atype Atom to kind pointer
    3443              : !> \param symmetric Symmetric matrix
    3444              : !> \param antisymmetric Anti-Symmetric matrix
    3445              : ! **************************************************************************************************
    3446            0 :    SUBROUTINE symtrans(smat, pmat, kmat, rot, f0, atype, symmetric, antisymmetric)
    3447              :       TYPE(dbcsr_type), POINTER                          :: smat, pmat
    3448              :       TYPE(kind_rotmat_type), DIMENSION(:), POINTER      :: kmat
    3449              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN)         :: rot
    3450              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: f0, atype
    3451              :       LOGICAL, INTENT(IN), OPTIONAL                      :: symmetric, antisymmetric
    3452              : 
    3453              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'symtrans'
    3454              : 
    3455              :       INTEGER                                            :: handle, iatom, icol, ikind, ip, irow, &
    3456              :                                                             jcol, jkind, jp, jrow, natom, numnodes
    3457              :       LOGICAL                                            :: asym, dorot, found, perm, sym, trans
    3458              :       REAL(KIND=dp)                                      :: dr, fsign
    3459            0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: work
    3460            0 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: kroti, krotj, pblock, sblock
    3461              :       TYPE(dbcsr_distribution_type)                      :: dist
    3462              :       TYPE(dbcsr_iterator_type)                          :: iter
    3463              : 
    3464            0 :       CALL timeset(routineN, handle)
    3465              : 
    3466              :       ! check symmetry options
    3467            0 :       sym = .FALSE.
    3468            0 :       IF (PRESENT(symmetric)) sym = symmetric
    3469            0 :       asym = .FALSE.
    3470            0 :       IF (PRESENT(antisymmetric)) asym = antisymmetric
    3471              : 
    3472            0 :       CPASSERT(.NOT. (sym .AND. asym))
    3473            0 :       CPASSERT((sym .OR. asym))
    3474              : 
    3475              :       ! do we have permutation of atoms
    3476            0 :       natom = SIZE(f0)
    3477            0 :       perm = .FALSE.
    3478            0 :       DO iatom = 1, natom
    3479            0 :          IF (f0(iatom) == iatom) CYCLE
    3480              :          perm = .TRUE.
    3481            0 :          EXIT
    3482              :       END DO
    3483              : 
    3484              :       ! do we have a real rotation
    3485            0 :       dorot = .FALSE.
    3486            0 :       IF (ABS(SUM(ABS(rot)) - 3.0_dp) > 1.e-12_dp) dorot = .TRUE.
    3487            0 :       dr = ABS(rot(1, 1) - 1.0_dp) + ABS(rot(2, 2) - 1.0_dp) + ABS(rot(3, 3) - 1.0_dp)
    3488            0 :       IF (ABS(dr) > 1.e-12_dp) dorot = .TRUE.
    3489              : 
    3490            0 :       fsign = 1.0_dp
    3491            0 :       IF (asym) fsign = -1.0_dp
    3492              : 
    3493            0 :       IF (dorot .OR. perm) THEN
    3494              :          CALL cp_abort(__LOCATION__, "k-points need FULL_GRID currently. "// &
    3495            0 :                        "Reduced grids not yet working correctly")
    3496            0 :          CALL dbcsr_set(smat, 0.0_dp)
    3497            0 :          IF (perm) THEN
    3498            0 :             CALL dbcsr_get_info(pmat, distribution=dist)
    3499            0 :             CALL dbcsr_distribution_get(dist, numnodes=numnodes)
    3500            0 :             IF (numnodes == 1) THEN
    3501              :                ! the matrices are local to this process
    3502            0 :                CALL dbcsr_iterator_start(iter, pmat)
    3503            0 :                DO WHILE (dbcsr_iterator_blocks_left(iter))
    3504            0 :                   CALL dbcsr_iterator_next_block(iter, irow, icol, pblock)
    3505            0 :                   ip = f0(irow)
    3506            0 :                   jp = f0(icol)
    3507            0 :                   IF (ip <= jp) THEN
    3508            0 :                      jrow = ip
    3509            0 :                      jcol = jp
    3510            0 :                      trans = .FALSE.
    3511              :                   ELSE
    3512            0 :                      jrow = jp
    3513            0 :                      jcol = ip
    3514            0 :                      trans = .TRUE.
    3515              :                   END IF
    3516            0 :                   CALL dbcsr_get_block_p(matrix=smat, row=jrow, col=jcol, BLOCK=sblock, found=found)
    3517            0 :                   CPASSERT(found)
    3518            0 :                   ikind = atype(irow)
    3519            0 :                   jkind = atype(icol)
    3520            0 :                   kroti => kmat(ikind)%rmat
    3521            0 :                   krotj => kmat(jkind)%rmat
    3522              :                   ! rotation
    3523            0 :                   IF (trans) THEN
    3524            0 :                      CALL ensure_work_matrix(work, SIZE(krotj, 2), SIZE(pblock, 1))
    3525              :                      CALL dgemm('T', 'T', SIZE(krotj, 2), SIZE(pblock, 1), SIZE(krotj, 1), &
    3526              :                                 1.0_dp, krotj, SIZE(krotj, 1), pblock, SIZE(pblock, 1), &
    3527            0 :                                 0.0_dp, work, SIZE(work, 1))
    3528              :                      CALL dgemm('N', 'N', SIZE(work, 1), SIZE(kroti, 2), SIZE(work, 2), &
    3529              :                                 fsign, work, SIZE(work, 1), kroti, SIZE(kroti, 1), &
    3530            0 :                                 0.0_dp, sblock, SIZE(sblock, 1))
    3531              :                   ELSE
    3532            0 :                      CALL ensure_work_matrix(work, SIZE(kroti, 2), SIZE(pblock, 2))
    3533              :                      CALL dgemm('T', 'N', SIZE(kroti, 2), SIZE(pblock, 2), SIZE(kroti, 1), &
    3534              :                                 1.0_dp, kroti, SIZE(kroti, 1), pblock, SIZE(pblock, 1), &
    3535            0 :                                 0.0_dp, work, SIZE(work, 1))
    3536              :                      CALL dgemm('N', 'N', SIZE(work, 1), SIZE(krotj, 2), SIZE(work, 2), &
    3537              :                                 fsign, work, SIZE(work, 1), krotj, SIZE(krotj, 1), &
    3538            0 :                                 0.0_dp, sblock, SIZE(sblock, 1))
    3539              :                   END IF
    3540              :                END DO
    3541            0 :                CALL dbcsr_iterator_stop(iter)
    3542              :                !
    3543              :             ELSE
    3544              :                ! distributed matrices, most general code needed
    3545              :                CALL cp_abort(__LOCATION__, "k-points need FULL_GRID currently. "// &
    3546            0 :                              "Reduced grids not yet working correctly")
    3547              :             END IF
    3548              :          ELSE
    3549              :             ! no atom permutations, this is always local
    3550            0 :             CALL dbcsr_copy(smat, pmat)
    3551            0 :             CALL dbcsr_iterator_start(iter, smat)
    3552            0 :             DO WHILE (dbcsr_iterator_blocks_left(iter))
    3553            0 :                CALL dbcsr_iterator_next_block(iter, irow, icol, sblock)
    3554            0 :                ip = f0(irow)
    3555            0 :                jp = f0(icol)
    3556            0 :                IF (ip <= jp) THEN
    3557              :                   jrow = ip
    3558              :                   jcol = jp
    3559            0 :                   trans = .FALSE.
    3560              :                ELSE
    3561              :                   jrow = jp
    3562              :                   jcol = ip
    3563            0 :                   trans = .TRUE.
    3564              :                END IF
    3565            0 :                ikind = atype(irow)
    3566            0 :                jkind = atype(icol)
    3567            0 :                kroti => kmat(ikind)%rmat
    3568            0 :                krotj => kmat(jkind)%rmat
    3569              :                ! rotation
    3570            0 :                IF (trans) THEN
    3571            0 :                   CALL ensure_work_matrix(work, SIZE(krotj, 2), SIZE(sblock, 1))
    3572              :                   CALL dgemm('T', 'T', SIZE(krotj, 2), SIZE(sblock, 1), SIZE(krotj, 1), &
    3573              :                              1.0_dp, krotj, SIZE(krotj, 1), sblock, SIZE(sblock, 1), &
    3574            0 :                              0.0_dp, work, SIZE(work, 1))
    3575              :                   CALL dgemm('N', 'N', SIZE(work, 1), SIZE(kroti, 2), SIZE(work, 2), &
    3576              :                              fsign, work, SIZE(work, 1), kroti, SIZE(kroti, 1), &
    3577            0 :                              0.0_dp, sblock, SIZE(sblock, 1))
    3578              :                ELSE
    3579            0 :                   CALL ensure_work_matrix(work, SIZE(kroti, 2), SIZE(sblock, 2))
    3580              :                   CALL dgemm('T', 'N', SIZE(kroti, 2), SIZE(sblock, 2), SIZE(kroti, 1), &
    3581              :                              1.0_dp, kroti, SIZE(kroti, 1), sblock, SIZE(sblock, 1), &
    3582            0 :                              0.0_dp, work, SIZE(work, 1))
    3583              :                   CALL dgemm('N', 'N', SIZE(work, 1), SIZE(krotj, 2), SIZE(work, 2), &
    3584              :                              fsign, work, SIZE(work, 1), krotj, SIZE(krotj, 1), &
    3585            0 :                              0.0_dp, sblock, SIZE(sblock, 1))
    3586              :                END IF
    3587              :             END DO
    3588            0 :             CALL dbcsr_iterator_stop(iter)
    3589              :             !
    3590              :          END IF
    3591              :       ELSE
    3592              :          ! this is the identity operation, just copy the matrix
    3593            0 :          CALL dbcsr_copy(smat, pmat)
    3594              :       END IF
    3595              : 
    3596            0 :       CALL timestop(handle)
    3597              : 
    3598            0 :    END SUBROUTINE symtrans
    3599              : 
    3600              : ! **************************************************************************************************
    3601              : !> \brief ...
    3602              : !> \param mat ...
    3603              : ! **************************************************************************************************
    3604            0 :    SUBROUTINE matprint(mat)
    3605              :       TYPE(dbcsr_type), POINTER                          :: mat
    3606              : 
    3607              :       INTEGER                                            :: i, icol, iounit, irow
    3608            0 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: mblock
    3609              :       TYPE(dbcsr_iterator_type)                          :: iter
    3610              : 
    3611            0 :       iounit = cp_logger_get_default_io_unit()
    3612            0 :       CALL dbcsr_iterator_start(iter, mat)
    3613            0 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
    3614            0 :          CALL dbcsr_iterator_next_block(iter, irow, icol, mblock)
    3615              :          !
    3616            0 :          IF (iounit > 0) THEN
    3617            0 :             WRITE (iounit, '(A,2I4)') 'BLOCK  ', irow, icol
    3618            0 :             DO i = 1, SIZE(mblock, 1)
    3619            0 :                WRITE (iounit, '(8F12.6)') mblock(i, :)
    3620              :             END DO
    3621              :          END IF
    3622              :          !
    3623              :       END DO
    3624            0 :       CALL dbcsr_iterator_stop(iter)
    3625              : 
    3626            0 :    END SUBROUTINE matprint
    3627              : ! **************************************************************************************************
    3628              : 
    3629            0 : END MODULE kpoint_methods
        

Generated by: LCOV version 2.0-1