LCOV - code coverage report
Current view: top level - src - qs_wf_history_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:06f838d) Lines: 91.1 % 1415 1289
Test Date: 2026-06-05 07:04:50 Functions: 94.7 % 19 18

            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 Storage of past states of the qs_env.
      10              : !>      Methods to interpolate (or actually normally extrapolate) the
      11              : !>      new guess for density and wavefunctions.
      12              : !> \note
      13              : !>      Most of the last snapshot should actually be in qs_env, but taking
      14              : !>      advantage of it would make the programming much convoluted
      15              : !> \par History
      16              : !>      02.2003 created [fawzi]
      17              : !>      11.2003 Joost VandeVondele : Implemented Nth order PS extrapolation
      18              : !>      02.2005 modified for KG_GPW [MI]
      19              : !> \author fawzi
      20              : ! **************************************************************************************************
      21              : MODULE qs_wf_history_methods
      22              :    USE bibliography,                    ONLY: Kolafa2004,&
      23              :                                               Kuhne2007,&
      24              :                                               VandeVondele2005a,&
      25              :                                               cite_reference
      26              :    USE cell_types,                      ONLY: cell_type,&
      27              :                                               pbc,&
      28              :                                               real_to_scaled
      29              :    USE cp_cfm_basic_linalg,             ONLY: cp_cfm_column_scale,&
      30              :                                               cp_cfm_gemm,&
      31              :                                               cp_cfm_scale_and_add,&
      32              :                                               cp_cfm_scale_and_add_fm,&
      33              :                                               cp_cfm_trace,&
      34              :                                               cp_cfm_triangular_multiply
      35              :    USE cp_cfm_cholesky,                 ONLY: cp_cfm_cholesky_decompose
      36              :    USE cp_cfm_diag,                     ONLY: cp_cfm_heevd
      37              :    USE cp_cfm_types,                    ONLY: &
      38              :         cp_cfm_create, cp_cfm_get_info, cp_cfm_get_submatrix, cp_cfm_release, cp_cfm_set_all, &
      39              :         cp_cfm_set_submatrix, cp_cfm_to_cfm, cp_cfm_to_fm, cp_cfm_type, cp_fm_to_cfm
      40              :    USE cp_control_types,                ONLY: dft_control_type
      41              :    USE cp_dbcsr_api,                    ONLY: &
      42              :         dbcsr_add, dbcsr_copy, dbcsr_create, dbcsr_deallocate_matrix, dbcsr_desymmetrize, &
      43              :         dbcsr_get_info, dbcsr_multiply, dbcsr_p_type, dbcsr_release, dbcsr_set, dbcsr_type, &
      44              :         dbcsr_type_antisymmetric, dbcsr_type_no_symmetry, dbcsr_type_symmetric
      45              :    USE cp_dbcsr_contrib,                ONLY: dbcsr_frobenius_norm,&
      46              :                                               dbcsr_trace
      47              :    USE cp_dbcsr_cp2k_link,              ONLY: cp_dbcsr_alloc_block_from_nbl
      48              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      49              :                                               cp_dbcsr_sm_fm_multiply,&
      50              :                                               dbcsr_allocate_matrix_set,&
      51              :                                               dbcsr_deallocate_matrix_set
      52              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_scale,&
      53              :                                               cp_fm_scale_and_add
      54              :    USE cp_fm_pool_types,                ONLY: cp_fm_pool_p_type,&
      55              :                                               cp_fm_pool_type,&
      56              :                                               fm_pool_create_fm,&
      57              :                                               fm_pool_give_back_fm,&
      58              :                                               fm_pools_create_fm_vect,&
      59              :                                               fm_pools_give_back_fm_vect
      60              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      61              :                                               cp_fm_struct_release,&
      62              :                                               cp_fm_struct_type
      63              :    USE cp_fm_types,                     ONLY: &
      64              :         copy_info_type, cp_fm_cleanup_copy_general, cp_fm_create, cp_fm_finish_copy_general, &
      65              :         cp_fm_get_info, cp_fm_get_submatrix, cp_fm_release, cp_fm_set_all, cp_fm_set_submatrix, &
      66              :         cp_fm_start_copy_general, cp_fm_to_fm, cp_fm_type
      67              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      68              :                                               cp_logger_type,&
      69              :                                               cp_to_string
      70              :    USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
      71              :                                               cp_print_key_unit_nr,&
      72              :                                               low_print_level
      73              :    USE input_constants,                 ONLY: &
      74              :         wfi_aspc_nr, wfi_frozen_method_nr, wfi_gext_proj_nr, wfi_gext_proj_qtr_nr, &
      75              :         wfi_linear_p_method_nr, wfi_linear_ps_method_nr, wfi_linear_wf_method_nr, &
      76              :         wfi_ps_method_nr, wfi_use_guess_method_nr, wfi_use_prev_p_method_nr, &
      77              :         wfi_use_prev_rho_r_method_nr, wfi_use_prev_wf_method_nr
      78              :    USE kinds,                           ONLY: dp
      79              :    USE kpoint_methods,                  ONLY: kpoint_density_matrices,&
      80              :                                               kpoint_density_transform,&
      81              :                                               kpoint_set_mo_occupation,&
      82              :                                               rskp_transform
      83              :    USE kpoint_types,                    ONLY: get_kpoint_info,&
      84              :                                               kpoint_env_type,&
      85              :                                               kpoint_type
      86              :    USE mathconstants,                   ONLY: gaussi,&
      87              :                                               twopi,&
      88              :                                               z_one,&
      89              :                                               z_zero
      90              :    USE mathlib,                         ONLY: binomial
      91              :    USE message_passing,                 ONLY: mp_para_env_type
      92              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      93              :    USE particle_types,                  ONLY: particle_type
      94              :    USE pw_env_types,                    ONLY: pw_env_get,&
      95              :                                               pw_env_type
      96              :    USE pw_methods,                      ONLY: pw_copy
      97              :    USE pw_pool_types,                   ONLY: pw_pool_type
      98              :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      99              :                                               pw_r3d_rs_type
     100              :    USE qs_density_matrices,             ONLY: calculate_density_matrix
     101              :    USE qs_environment_types,            ONLY: get_qs_env,&
     102              :                                               qs_environment_type,&
     103              :                                               set_qs_env
     104              :    USE qs_ks_types,                     ONLY: qs_ks_did_change
     105              :    USE qs_matrix_pools,                 ONLY: mpools_get,&
     106              :                                               qs_matrix_pools_type
     107              :    USE qs_mo_methods,                   ONLY: make_basis_cholesky,&
     108              :                                               make_basis_lowdin,&
     109              :                                               make_basis_simple,&
     110              :                                               make_basis_sm
     111              :    USE qs_mo_types,                     ONLY: get_mo_set,&
     112              :                                               mo_set_type
     113              :    USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type
     114              :    USE qs_rho_methods,                  ONLY: qs_rho_update_rho
     115              :    USE qs_rho_types,                    ONLY: qs_rho_get,&
     116              :                                               qs_rho_type
     117              :    USE qs_scf_types,                    ONLY: ot_method_nr,&
     118              :                                               qs_scf_env_type
     119              :    USE qs_wf_history_types,             ONLY: qs_wf_history_type,&
     120              :                                               qs_wf_snapshot_type,&
     121              :                                               wfi_get_snapshot,&
     122              :                                               wfi_release
     123              :    USE scf_control_types,               ONLY: scf_control_type
     124              : #include "./base/base_uses.f90"
     125              : 
     126              :    IMPLICIT NONE
     127              :    PRIVATE
     128              : 
     129              :    LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .TRUE.
     130              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_wf_history_methods'
     131              : 
     132              :    PUBLIC :: wfi_create, wfi_update, wfi_create_for_kp, &
     133              :              wfi_extrapolate, wfi_get_method_label, &
     134              :              reorthogonalize_vectors, wfi_purge_history
     135              : 
     136              : CONTAINS
     137              : 
     138              : ! **************************************************************************************************
     139              : !> \brief allocates and initialize a wavefunction snapshot
     140              : !> \param snapshot the snapshot to create
     141              : !> \par History
     142              : !>      02.2003 created [fawzi]
     143              : !>      02.2005 added wf_mol [MI]
     144              : !> \author fawzi
     145              : ! **************************************************************************************************
     146        14010 :    SUBROUTINE wfs_create(snapshot)
     147              :       TYPE(qs_wf_snapshot_type), INTENT(OUT)             :: snapshot
     148              : 
     149              :       NULLIFY (snapshot%wf, snapshot%rho_r, &
     150              :                snapshot%rho_g, snapshot%rho_ao, snapshot%rho_ao_kp, &
     151              :                snapshot%overlap, snapshot%wf_kp, snapshot%overlap_cfm_kp, &
     152              :                snapshot%kp_pbc_shift, snapshot%rho_frozen)
     153        14010 :       snapshot%dt = 1.0_dp
     154        14010 :    END SUBROUTINE wfs_create
     155              : 
     156              : ! **************************************************************************************************
     157              : !> \brief updates the given snapshot
     158              : !> \param snapshot the snapshot to be updated
     159              : !> \param wf_history the history
     160              : !> \param qs_env the qs_env that should be snapshotted
     161              : !> \param dt the time of the snapshot (wrt. to the previous snapshot)
     162              : !> \par History
     163              : !>      02.2003 created [fawzi]
     164              : !>      02.2005 added kg_fm_mol_set for KG_GPW [MI]
     165              : !> \author fawzi
     166              : ! **************************************************************************************************
     167        24206 :    SUBROUTINE wfs_update(snapshot, wf_history, qs_env, dt)
     168              :       TYPE(qs_wf_snapshot_type), POINTER                 :: snapshot
     169              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
     170              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     171              :       REAL(KIND=dp), INTENT(in), OPTIONAL                :: dt
     172              : 
     173              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'wfs_update'
     174              : 
     175              :       INTEGER                                            :: handle, ic, igroup, ik, ikp, img, &
     176              :                                                             indx_ft, ispin, kplocal, nc, nimg, &
     177              :                                                             nkp_all, nkp_grps, nspin_kp, nspins
     178              :       INTEGER, DIMENSION(2)                              :: kp_range
     179        24206 :       INTEGER, DIMENSION(:, :), POINTER                  :: kp_dist
     180        24206 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
     181              :       LOGICAL                                            :: my_kpgrp
     182        24206 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: xkp
     183              :       TYPE(cell_type), POINTER                           :: cell
     184        24206 :       TYPE(copy_info_type), ALLOCATABLE, DIMENSION(:, :) :: info_ft
     185        24206 :       TYPE(cp_fm_pool_p_type), DIMENSION(:), POINTER     :: ao_ao_fm_pools, ao_mo_pools
     186              :       TYPE(cp_fm_struct_type), POINTER                   :: ao_ao_struct_ft
     187              :       TYPE(cp_fm_type)                                   :: fmdummy_ft, fmlocal_ft
     188              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     189        24206 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s, rho_ao
     190        24206 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_s_kp, rho_ao_kp
     191              :       TYPE(dbcsr_type), POINTER                          :: cmat_ft, rmat_ft, tmpmat_ft
     192              :       TYPE(dft_control_type), POINTER                    :: dft_control
     193              :       TYPE(kpoint_env_type), POINTER                     :: kp
     194              :       TYPE(kpoint_type), POINTER                         :: kpoints
     195        24206 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     196              :       TYPE(mp_para_env_type), POINTER                    :: para_env_ft
     197              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     198        24206 :          POINTER                                         :: sab_nl
     199        24206 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     200        24206 :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER        :: rho_g
     201              :       TYPE(pw_env_type), POINTER                         :: pw_env
     202              :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
     203        24206 :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER        :: rho_r
     204              :       TYPE(qs_matrix_pools_type), POINTER                :: mpools_kp
     205              :       TYPE(qs_rho_type), POINTER                         :: rho
     206              :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
     207              : 
     208        24206 :       CALL timeset(routineN, handle)
     209              : 
     210        24206 :       NULLIFY (pw_env, auxbas_pw_pool, ao_mo_pools, ao_ao_fm_pools, dft_control, mos, mo_coeff, &
     211        24206 :                rho, rho_r, rho_g, rho_ao, matrix_s, matrix_s_kp, kpoints, kp, cell, &
     212        24206 :                particle_set, kp_dist, cell_to_index, xkp, sab_nl, scf_env, mpools_kp, para_env_ft, &
     213        24206 :                rmat_ft, cmat_ft, tmpmat_ft, ao_ao_struct_ft)
     214              :       CALL get_qs_env(qs_env, pw_env=pw_env, &
     215        24206 :                       dft_control=dft_control, rho=rho, cell=cell, particle_set=particle_set)
     216        24206 :       CALL mpools_get(qs_env%mpools, ao_mo_fm_pools=ao_mo_pools)
     217        24206 :       CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
     218              : 
     219        24206 :       CPASSERT(ASSOCIATED(wf_history))
     220        24206 :       CPASSERT(ASSOCIATED(dft_control))
     221        24206 :       IF (.NOT. ASSOCIATED(snapshot)) THEN
     222        14010 :          ALLOCATE (snapshot)
     223        14010 :          CALL wfs_create(snapshot)
     224              :       END IF
     225        24206 :       CPASSERT(wf_history%ref_count > 0)
     226              : 
     227        24206 :       nspins = dft_control%nspins
     228        24206 :       snapshot%dt = 1.0_dp
     229        24206 :       IF (PRESENT(dt)) snapshot%dt = dt
     230        24206 :       IF (wf_history%store_wf) THEN
     231        21164 :          CALL get_qs_env(qs_env, mos=mos)
     232        21164 :          IF (.NOT. ASSOCIATED(snapshot%wf)) THEN
     233              :             CALL fm_pools_create_fm_vect(ao_mo_pools, snapshot%wf, &
     234        11770 :                                          name="ws_snap-ws")
     235        11770 :             CPASSERT(nspins == SIZE(snapshot%wf))
     236              :          END IF
     237        45120 :          DO ispin = 1, nspins
     238        23956 :             CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff)
     239        45120 :             CALL cp_fm_to_fm(mo_coeff, snapshot%wf(ispin))
     240              :          END DO
     241              :       ELSE
     242         3042 :          CALL fm_pools_give_back_fm_vect(ao_mo_pools, snapshot%wf)
     243              :       END IF
     244              : 
     245        24206 :       IF (wf_history%store_rho_r) THEN
     246            0 :          CALL qs_rho_get(rho, rho_r=rho_r)
     247            0 :          CPASSERT(ASSOCIATED(rho_r))
     248            0 :          IF (.NOT. ASSOCIATED(snapshot%rho_r)) THEN
     249            0 :             ALLOCATE (snapshot%rho_r(nspins))
     250            0 :             DO ispin = 1, nspins
     251            0 :                CALL auxbas_pw_pool%create_pw(snapshot%rho_r(ispin))
     252              :             END DO
     253              :          END IF
     254            0 :          DO ispin = 1, nspins
     255            0 :             CALL pw_copy(rho_r(ispin), snapshot%rho_r(ispin))
     256              :          END DO
     257        24206 :       ELSE IF (ASSOCIATED(snapshot%rho_r)) THEN
     258            0 :          DO ispin = 1, SIZE(snapshot%rho_r)
     259            0 :             CALL auxbas_pw_pool%give_back_pw(snapshot%rho_r(ispin))
     260              :          END DO
     261            0 :          DEALLOCATE (snapshot%rho_r)
     262              :       END IF
     263              : 
     264        24206 :       IF (wf_history%store_rho_g) THEN
     265            0 :          CALL qs_rho_get(rho, rho_g=rho_g)
     266            0 :          CPASSERT(ASSOCIATED(rho_g))
     267            0 :          IF (.NOT. ASSOCIATED(snapshot%rho_g)) THEN
     268            0 :             ALLOCATE (snapshot%rho_g(nspins))
     269            0 :             DO ispin = 1, nspins
     270            0 :                CALL auxbas_pw_pool%create_pw(snapshot%rho_g(ispin))
     271              :             END DO
     272              :          END IF
     273            0 :          DO ispin = 1, nspins
     274            0 :             CALL pw_copy(rho_g(ispin), snapshot%rho_g(ispin))
     275              :          END DO
     276        24206 :       ELSE IF (ASSOCIATED(snapshot%rho_g)) THEN
     277            0 :          DO ispin = 1, SIZE(snapshot%rho_g)
     278            0 :             CALL auxbas_pw_pool%give_back_pw(snapshot%rho_g(ispin))
     279              :          END DO
     280            0 :          DEALLOCATE (snapshot%rho_g)
     281              :       END IF
     282              : 
     283        24206 :       IF (ASSOCIATED(snapshot%rho_ao)) THEN ! the sparsity might be different
     284              :          ! (future struct:check)
     285          270 :          CALL dbcsr_deallocate_matrix_set(snapshot%rho_ao)
     286              :       END IF
     287        24206 :       IF (wf_history%store_rho_ao) THEN
     288          338 :          CALL qs_rho_get(rho, rho_ao=rho_ao)
     289          338 :          CPASSERT(ASSOCIATED(rho_ao))
     290              : 
     291          338 :          CALL dbcsr_allocate_matrix_set(snapshot%rho_ao, nspins)
     292          836 :          DO ispin = 1, nspins
     293          498 :             ALLOCATE (snapshot%rho_ao(ispin)%matrix)
     294          836 :             CALL dbcsr_copy(snapshot%rho_ao(ispin)%matrix, rho_ao(ispin)%matrix)
     295              :          END DO
     296              :       END IF
     297              : 
     298        24206 :       IF (ASSOCIATED(snapshot%rho_ao_kp)) THEN ! the sparsity might be different
     299              :          ! (future struct:check)
     300          220 :          CALL dbcsr_deallocate_matrix_set(snapshot%rho_ao_kp)
     301              :       END IF
     302        24206 :       IF (wf_history%store_rho_ao_kp) THEN
     303          232 :          CALL qs_rho_get(rho, rho_ao_kp=rho_ao_kp)
     304          232 :          CPASSERT(ASSOCIATED(rho_ao_kp))
     305              : 
     306          232 :          nimg = dft_control%nimages
     307          232 :          CALL dbcsr_allocate_matrix_set(snapshot%rho_ao_kp, nspins, nimg)
     308          554 :          DO ispin = 1, nspins
     309        34092 :             DO img = 1, nimg
     310        33538 :                ALLOCATE (snapshot%rho_ao_kp(ispin, img)%matrix)
     311              :                CALL dbcsr_copy(snapshot%rho_ao_kp(ispin, img)%matrix, &
     312        33860 :                                rho_ao_kp(ispin, img)%matrix)
     313              :             END DO
     314              :          END DO
     315              :       END IF
     316              : 
     317        24206 :       IF (ASSOCIATED(snapshot%overlap)) THEN ! the sparsity might be different
     318              :          ! (future struct:check)
     319         6786 :          CALL dbcsr_deallocate_matrix(snapshot%overlap)
     320              :       END IF
     321        24206 :       IF (wf_history%store_overlap) THEN
     322        17522 :          CALL get_qs_env(qs_env, matrix_s=matrix_s)
     323        17522 :          CPASSERT(ASSOCIATED(matrix_s))
     324        17522 :          CPASSERT(ASSOCIATED(matrix_s(1)%matrix))
     325        17522 :          ALLOCATE (snapshot%overlap)
     326        17522 :          CALL dbcsr_copy(snapshot%overlap, matrix_s(1)%matrix)
     327              :       END IF
     328              : 
     329        24206 :       CALL get_qs_env(qs_env, kpoints=kpoints)
     330        24206 :       IF (ASSOCIATED(kpoints)) THEN
     331        24206 :          IF (ASSOCIATED(kpoints%kp_env)) THEN
     332              :             ! --- k-point WFN snapshot: store complex MO coefficients per local k-point ---
     333         2688 :             IF (wf_history%store_wf_kp) THEN
     334         2456 :                CALL get_kpoint_info(kpoints, kp_range=kp_range)
     335         2456 :                kplocal = kp_range(2) - kp_range(1) + 1
     336         2456 :                nspin_kp = SIZE(kpoints%kp_env(1)%kpoint_env%mos, 2)
     337         2456 :                nc = SIZE(kpoints%kp_env(1)%kpoint_env%mos, 1) ! 2=complex, 1=real
     338              : 
     339         2456 :                CALL wfi_store_kp_pbc_shift(snapshot, cell, particle_set)
     340              : 
     341         2456 :                IF (ASSOCIATED(snapshot%wf_kp)) THEN
     342          842 :                   DO ikp = 1, SIZE(snapshot%wf_kp, 1)
     343         1926 :                      DO ic = 1, SIZE(snapshot%wf_kp, 2)
     344         2710 :                         DO ispin = 1, SIZE(snapshot%wf_kp, 3)
     345         2168 :                            CALL cp_fm_release(snapshot%wf_kp(ikp, ic, ispin))
     346              :                         END DO
     347              :                      END DO
     348              :                   END DO
     349          300 :                   DEALLOCATE (snapshot%wf_kp)
     350              :                END IF
     351              : 
     352        29902 :                ALLOCATE (snapshot%wf_kp(kplocal, nc, nspin_kp))
     353         7194 :                DO ikp = 1, kplocal
     354         4738 :                   kp => kpoints%kp_env(ikp)%kpoint_env
     355        12290 :                   DO ispin = 1, nspin_kp
     356        20024 :                      DO ic = 1, nc
     357        10190 :                         CALL get_mo_set(kp%mos(ic, ispin), mo_coeff=mo_coeff)
     358              :                         CALL cp_fm_create(snapshot%wf_kp(ikp, ic, ispin), &
     359              :                                           mo_coeff%matrix_struct, &
     360        10190 :                                           name="wfkp_snap")
     361        15286 :                         CALL cp_fm_to_fm(mo_coeff, snapshot%wf_kp(ikp, ic, ispin))
     362              :                      END DO
     363              :                   END DO
     364              :                END DO
     365              :             END IF
     366              : 
     367              :             ! --- k-point overlap snapshot: Fourier-transform S(R)→S(k) NOW and store as cfm ---
     368              :             ! This is critical: we MUST transform at snapshot time using the CURRENT neighbor
     369              :             ! list. Storing S(R) and re-transforming later would use a stale neighbor list,
     370              :             ! producing wrong S(k) when the neighbor list changes during MD.
     371         2688 :             IF (wf_history%store_overlap_kp) THEN
     372         2450 :                CALL get_qs_env(qs_env, matrix_s_kp=matrix_s_kp, scf_env=scf_env)
     373              :                CALL get_kpoint_info(kpoints, nkp=nkp_all, xkp=xkp, kp_range=kp_range, &
     374              :                                     nkp_groups=nkp_grps, kp_dist=kp_dist, &
     375         2450 :                                     sab_nl=sab_nl, cell_to_index=cell_to_index)
     376         2450 :                kplocal = kp_range(2) - kp_range(1) + 1
     377         2450 :                para_env_ft => kpoints%blacs_env_all%para_env
     378              : 
     379              :                ! Allocate dbcsr work matrices for FT (same pattern as do_general_diag_kp)
     380         2450 :                ALLOCATE (rmat_ft, cmat_ft, tmpmat_ft)
     381              :                CALL dbcsr_create(rmat_ft, template=matrix_s_kp(1, 1)%matrix, &
     382         2450 :                                  matrix_type=dbcsr_type_symmetric)
     383              :                CALL dbcsr_create(cmat_ft, template=matrix_s_kp(1, 1)%matrix, &
     384         2450 :                                  matrix_type=dbcsr_type_antisymmetric)
     385              :                CALL dbcsr_create(tmpmat_ft, template=matrix_s_kp(1, 1)%matrix, &
     386         2450 :                                  matrix_type=dbcsr_type_no_symmetry)
     387         2450 :                CALL cp_dbcsr_alloc_block_from_nbl(rmat_ft, sab_nl)
     388         2450 :                CALL cp_dbcsr_alloc_block_from_nbl(cmat_ft, sab_nl)
     389              : 
     390              :                ! Get kp-subgroup FM from pool
     391         2450 :                CALL get_kpoint_info(kpoints, mpools=mpools_kp)
     392         2450 :                CALL mpools_get(mpools_kp, ao_ao_fm_pools=ao_ao_fm_pools)
     393         2450 :                CALL fm_pool_create_fm(ao_ao_fm_pools(1)%pool, fmlocal_ft)
     394              : 
     395              :                ! Release old snapshot if present
     396         2450 :                IF (ASSOCIATED(snapshot%overlap_cfm_kp)) THEN
     397          822 :                   DO ikp = 1, SIZE(snapshot%overlap_cfm_kp)
     398          822 :                      CALL cp_cfm_release(snapshot%overlap_cfm_kp(ikp))
     399              :                   END DO
     400          296 :                   DEALLOCATE (snapshot%overlap_cfm_kp)
     401              :                END IF
     402        12064 :                ALLOCATE (snapshot%overlap_cfm_kp(kplocal))
     403              : 
     404         2450 :                CALL cp_fm_get_info(fmlocal_ft, matrix_struct=ao_ao_struct_ft)
     405              : 
     406              :                ! Communication info array
     407        48410 :                ALLOCATE (info_ft(kplocal*nkp_grps, 2))
     408              : 
     409              :                ! Phase A: Start async FT + redistribute for each k-point
     410         2450 :                indx_ft = 0
     411         7164 :                DO ikp = 1, kplocal
     412        15444 :                   DO igroup = 1, nkp_grps
     413         8280 :                      ik = kp_dist(1, igroup) + ikp - 1
     414         8280 :                      my_kpgrp = (ik >= kp_range(1) .AND. ik <= kp_range(2))
     415         8280 :                      indx_ft = indx_ft + 1
     416              : 
     417         8280 :                      CALL dbcsr_set(rmat_ft, 0.0_dp)
     418         8280 :                      CALL dbcsr_set(cmat_ft, 0.0_dp)
     419              :                      CALL rskp_transform(rmatrix=rmat_ft, cmatrix=cmat_ft, rsmat=matrix_s_kp, &
     420              :                                          ispin=1, xkp=xkp(1:3, ik), &
     421         8280 :                                          cell_to_index=cell_to_index, sab_nl=sab_nl)
     422         8280 :                      CALL dbcsr_desymmetrize(rmat_ft, tmpmat_ft)
     423         8280 :                      CALL copy_dbcsr_to_fm(tmpmat_ft, scf_env%scf_work1(1))
     424         8280 :                      CALL dbcsr_desymmetrize(cmat_ft, tmpmat_ft)
     425         8280 :                      CALL copy_dbcsr_to_fm(tmpmat_ft, scf_env%scf_work1(2))
     426              : 
     427        12994 :                      IF (my_kpgrp) THEN
     428              :                         CALL cp_fm_start_copy_general(scf_env%scf_work1(1), fmlocal_ft, &
     429         4714 :                                                       para_env_ft, info_ft(indx_ft, 1))
     430              :                         CALL cp_fm_start_copy_general(scf_env%scf_work1(2), fmlocal_ft, &
     431         4714 :                                                       para_env_ft, info_ft(indx_ft, 2))
     432              :                      ELSE
     433              :                         CALL cp_fm_start_copy_general(scf_env%scf_work1(1), fmdummy_ft, &
     434         3566 :                                                       para_env_ft, info_ft(indx_ft, 1))
     435              :                         CALL cp_fm_start_copy_general(scf_env%scf_work1(2), fmdummy_ft, &
     436         3566 :                                                       para_env_ft, info_ft(indx_ft, 2))
     437              :                      END IF
     438              :                   END DO
     439              :                END DO
     440              : 
     441              :                ! Phase B: Finish communication and assemble S(k) as cfm
     442              :                indx_ft = 0
     443         7164 :                DO ikp = 1, kplocal
     444         4714 :                   CALL cp_cfm_create(snapshot%overlap_cfm_kp(ikp), ao_ao_struct_ft)
     445         4714 :                   CALL cp_cfm_set_all(snapshot%overlap_cfm_kp(ikp), z_zero)
     446        15444 :                   DO igroup = 1, nkp_grps
     447         8280 :                      ik = kp_dist(1, igroup) + ikp - 1
     448         8280 :                      my_kpgrp = (ik >= kp_range(1) .AND. ik <= kp_range(2))
     449         3566 :                      indx_ft = indx_ft + 1
     450         4714 :                      IF (my_kpgrp) THEN
     451         4714 :                         CALL cp_fm_finish_copy_general(fmlocal_ft, info_ft(indx_ft, 1))
     452              :                         CALL cp_cfm_scale_and_add_fm(z_zero, snapshot%overlap_cfm_kp(ikp), &
     453         4714 :                                                      z_one, fmlocal_ft)
     454         4714 :                         CALL cp_fm_finish_copy_general(fmlocal_ft, info_ft(indx_ft, 2))
     455              :                         CALL cp_cfm_scale_and_add_fm(z_one, snapshot%overlap_cfm_kp(ikp), &
     456         4714 :                                                      gaussi, fmlocal_ft)
     457              :                      END IF
     458              :                   END DO
     459              :                END DO
     460              : 
     461              :                ! Cleanup
     462        10730 :                DO indx_ft = 1, kplocal*nkp_grps
     463         8280 :                   CALL cp_fm_cleanup_copy_general(info_ft(indx_ft, 1))
     464        10730 :                   CALL cp_fm_cleanup_copy_general(info_ft(indx_ft, 2))
     465              :                END DO
     466        21460 :                DEALLOCATE (info_ft)
     467         2450 :                CALL fm_pool_give_back_fm(ao_ao_fm_pools(1)%pool, fmlocal_ft)
     468         2450 :                CALL dbcsr_deallocate_matrix(rmat_ft)
     469         2450 :                CALL dbcsr_deallocate_matrix(cmat_ft)
     470         4900 :                CALL dbcsr_deallocate_matrix(tmpmat_ft)
     471              :             END IF
     472              :          END IF
     473              :       END IF
     474              : 
     475              :       IF (wf_history%store_frozen_density) THEN
     476              :          ! do nothing
     477              :          ! CALL deallocate_matrix_set(snapshot%rho_frozen%rho_ao)
     478              :       END IF
     479              : 
     480        24206 :       CALL timestop(handle)
     481              : 
     482        24206 :    END SUBROUTINE wfs_update
     483              : 
     484              : ! **************************************************************************************************
     485              : !> \brief ...
     486              : !> \param wf_history ...
     487              : !> \param interpolation_method_nr the tag of the method used for
     488              : !>        the extrapolation of the initial density for the next md step
     489              : !>        (see qs_wf_history_types:wfi_*_method_nr)
     490              : !> \param extrapolation_order ...
     491              : !> \param has_unit_metric ...
     492              : !> \par History
     493              : !>      02.2003 created [fawzi]
     494              : !> \author fawzi
     495              : ! **************************************************************************************************
     496         8436 :    SUBROUTINE wfi_create(wf_history, interpolation_method_nr, extrapolation_order, &
     497              :                          has_unit_metric)
     498              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
     499              :       INTEGER, INTENT(in)                                :: interpolation_method_nr, &
     500              :                                                             extrapolation_order
     501              :       LOGICAL, INTENT(IN)                                :: has_unit_metric
     502              : 
     503              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'wfi_create'
     504              : 
     505              :       INTEGER                                            :: handle, i
     506              : 
     507         8436 :       CALL timeset(routineN, handle)
     508              : 
     509         8436 :       ALLOCATE (wf_history)
     510         8436 :       wf_history%ref_count = 1
     511         8436 :       wf_history%memory_depth = 0
     512         8436 :       wf_history%snapshot_count = 0
     513         8436 :       wf_history%last_state_index = 1
     514              :       wf_history%store_wf = .FALSE.
     515              :       wf_history%store_rho_r = .FALSE.
     516              :       wf_history%store_rho_g = .FALSE.
     517              :       wf_history%store_rho_ao = .FALSE.
     518              :       wf_history%store_rho_ao_kp = .FALSE.
     519              :       wf_history%store_overlap = .FALSE.
     520              :       wf_history%store_wf_kp = .FALSE.
     521              :       wf_history%store_overlap_kp = .FALSE.
     522              :       wf_history%store_frozen_density = .FALSE.
     523              :       NULLIFY (wf_history%past_states)
     524              : 
     525         8436 :       wf_history%interpolation_method_nr = interpolation_method_nr
     526              : 
     527              :       SELECT CASE (wf_history%interpolation_method_nr)
     528              :       CASE (wfi_use_guess_method_nr)
     529              :          wf_history%memory_depth = 0
     530              :       CASE (wfi_use_prev_wf_method_nr)
     531           68 :          wf_history%memory_depth = 0
     532              :       CASE (wfi_use_prev_rho_r_method_nr, wfi_use_prev_p_method_nr)
     533           68 :          wf_history%memory_depth = 1
     534           68 :          wf_history%store_rho_ao = .TRUE.
     535              :       CASE (wfi_linear_wf_method_nr)
     536            4 :          wf_history%memory_depth = 2
     537            4 :          wf_history%store_wf = .TRUE.
     538              :       CASE (wfi_linear_p_method_nr)
     539            6 :          wf_history%memory_depth = 2
     540            6 :          wf_history%store_rho_ao = .TRUE.
     541              :       CASE (wfi_linear_ps_method_nr)
     542            6 :          wf_history%memory_depth = 2
     543            6 :          wf_history%store_wf = .TRUE.
     544            6 :          IF (.NOT. has_unit_metric) wf_history%store_overlap = .TRUE.
     545              :       CASE (wfi_ps_method_nr)
     546          345 :          CALL cite_reference(VandeVondele2005a)
     547          345 :          wf_history%memory_depth = extrapolation_order + 1
     548          345 :          wf_history%store_wf = .TRUE.
     549          345 :          wf_history%store_wf_kp = .TRUE.
     550          345 :          IF (.NOT. has_unit_metric) THEN
     551          341 :             wf_history%store_overlap = .TRUE.
     552          341 :             wf_history%store_overlap_kp = .TRUE.
     553              :          END IF
     554              :       CASE (wfi_frozen_method_nr)
     555            4 :          wf_history%memory_depth = 1
     556            4 :          wf_history%store_frozen_density = .TRUE.
     557              :       CASE (wfi_aspc_nr)
     558         7703 :          wf_history%memory_depth = extrapolation_order + 2
     559         7703 :          wf_history%store_wf = .TRUE.
     560         7703 :          wf_history%store_wf_kp = .TRUE.
     561         7703 :          IF (.NOT. has_unit_metric) THEN
     562         6721 :             wf_history%store_overlap = .TRUE.
     563         6721 :             wf_history%store_overlap_kp = .TRUE.
     564              :          END IF
     565              :       CASE (wfi_gext_proj_nr)
     566           22 :          wf_history%memory_depth = extrapolation_order
     567           22 :          wf_history%store_wf = .TRUE.
     568           22 :          wf_history%store_wf_kp = .TRUE.
     569           22 :          wf_history%store_overlap = .TRUE.
     570           22 :          wf_history%store_overlap_kp = .TRUE.
     571              :       CASE (wfi_gext_proj_qtr_nr)
     572            6 :          wf_history%memory_depth = extrapolation_order
     573            6 :          wf_history%store_wf = .TRUE.
     574            6 :          wf_history%store_wf_kp = .TRUE.
     575            6 :          wf_history%store_overlap = .TRUE.
     576            6 :          wf_history%store_overlap_kp = .TRUE.
     577              :       CASE default
     578              :          CALL cp_abort(__LOCATION__, &
     579              :                        "Unknown interpolation method: "// &
     580         8436 :                        TRIM(ADJUSTL(cp_to_string(interpolation_method_nr))))
     581              :       END SELECT
     582        64813 :       ALLOCATE (wf_history%past_states(wf_history%memory_depth))
     583              : 
     584        48213 :       DO i = 1, SIZE(wf_history%past_states)
     585        48213 :          NULLIFY (wf_history%past_states(i)%snapshot)
     586              :       END DO
     587              : 
     588         8436 :       CALL timestop(handle)
     589         8436 :    END SUBROUTINE wfi_create
     590              : 
     591              : ! **************************************************************************************************
     592              : !> \brief Adapts wf_history storage flags for k-point calculations.
     593              : !>        For ASPC, switches from Gamma WFN storage to k-point WFN storage.
     594              : !>        Other WFN-based methods remain blocked.
     595              : !> \param wf_history ...
     596              : !> \par History
     597              : !>      06.2015 created [jhu]
     598              : !> \author jhu
     599              : ! **************************************************************************************************
     600          456 :    SUBROUTINE wfi_create_for_kp(wf_history)
     601              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
     602              : 
     603              :       INTEGER                                            :: i
     604              : 
     605          456 :       CPASSERT(ASSOCIATED(wf_history))
     606          456 :       IF (wf_history%store_rho_ao) THEN
     607           10 :          wf_history%store_rho_ao_kp = .TRUE.
     608           10 :          wf_history%store_rho_ao = .FALSE.
     609              :       END IF
     610              :       ! KP-compatible WFN history: store complex k-point MOs in snapshots.
     611              :       ! USE_PREV_WF needs one snapshot as well, since the PBC image convention
     612              :       ! of the saved WFN has to be known before reorthogonalization.
     613          456 :       IF (wf_history%interpolation_method_nr == wfi_use_prev_wf_method_nr) THEN
     614            2 :          wf_history%memory_depth = 1
     615            2 :          wf_history%store_wf_kp = .TRUE.
     616            2 :          wf_history%store_wf = .FALSE.
     617            2 :          wf_history%store_overlap = .FALSE.
     618            2 :          IF (ASSOCIATED(wf_history%past_states)) DEALLOCATE (wf_history%past_states)
     619            8 :          ALLOCATE (wf_history%past_states(wf_history%memory_depth))
     620            4 :          DO i = 1, SIZE(wf_history%past_states)
     621            4 :             NULLIFY (wf_history%past_states(i)%snapshot)
     622              :          END DO
     623          454 :       ELSE IF (wf_history%store_wf_kp) THEN
     624          310 :          wf_history%store_wf = .FALSE.
     625          310 :          wf_history%store_overlap = .FALSE.
     626              :          ! store_wf_kp and store_overlap_kp remain TRUE
     627              :       ELSE
     628              :          ! Linear methods (except LINEAR_P) are still blocked
     629          144 :          IF (wf_history%store_wf .OR. wf_history%store_overlap) THEN
     630            0 :             CPABORT("Linear WFN-based extrapolation methods not implemented for k-points.")
     631              :          END IF
     632              :       END IF
     633          456 :       IF (wf_history%store_frozen_density) THEN
     634            0 :          CPABORT("Frozen density initialization method not possible for kpoints.")
     635              :       END IF
     636              : 
     637          456 :    END SUBROUTINE wfi_create_for_kp
     638              : 
     639              : ! **************************************************************************************************
     640              : !> \brief returns a string describing the interpolation method
     641              : !> \param method_nr ...
     642              : !> \return ...
     643              : !> \par History
     644              : !>      02.2003 created [fawzi]
     645              : !> \author fawzi
     646              : ! **************************************************************************************************
     647        12794 :    FUNCTION wfi_get_method_label(method_nr) RESULT(res)
     648              :       INTEGER, INTENT(in)                                :: method_nr
     649              :       CHARACTER(len=30)                                  :: res
     650              : 
     651        12794 :       res = "unknown"
     652        13032 :       SELECT CASE (method_nr)
     653              :       CASE (wfi_use_prev_p_method_nr)
     654          238 :          res = "previous_p"
     655              :       CASE (wfi_use_prev_wf_method_nr)
     656          221 :          res = "previous_wf"
     657              :       CASE (wfi_use_prev_rho_r_method_nr)
     658            4 :          res = "previous_rho_r"
     659              :       CASE (wfi_use_guess_method_nr)
     660         4693 :          res = "initial_guess"
     661              :       CASE (wfi_linear_wf_method_nr)
     662            2 :          res = "mo linear"
     663              :       CASE (wfi_linear_p_method_nr)
     664            3 :          res = "P linear"
     665              :       CASE (wfi_linear_ps_method_nr)
     666            6 :          res = "PS linear"
     667              :       CASE (wfi_ps_method_nr)
     668          188 :          res = "PS Nth order"
     669              :       CASE (wfi_frozen_method_nr)
     670            4 :          res = "frozen density approximation"
     671              :       CASE (wfi_aspc_nr)
     672         7351 :          res = "ASPC"
     673              :       CASE (wfi_gext_proj_nr)
     674           70 :          res = "GEXT_PROJ"
     675              :       CASE (wfi_gext_proj_qtr_nr)
     676           14 :          res = "GEXT_PROJ_QTR"
     677              :       CASE default
     678              :          CALL cp_abort(__LOCATION__, &
     679              :                        "Unknown interpolation method: "// &
     680        12794 :                        TRIM(ADJUSTL(cp_to_string(method_nr))))
     681              :       END SELECT
     682        12794 :    END FUNCTION wfi_get_method_label
     683              : 
     684              : ! **************************************************************************************************
     685              : !> \brief calculates the new starting state for the scf for the next
     686              : !>      wf optimization
     687              : !> \param wf_history the previous history needed to extrapolate
     688              : !> \param qs_env the qs env with the latest result, and that will contain
     689              : !>        the new starting state
     690              : !> \param dt the time at which to extrapolate (wrt. to the last snapshot)
     691              : !> \param extrapolation_method_nr returns the extrapolation method used
     692              : !> \param orthogonal_wf ...
     693              : !> \par History
     694              : !>      02.2003 created [fawzi]
     695              : !>      11.2003 Joost VandeVondele : Implemented Nth order PS extrapolation
     696              : !>      04.2026 Michele Nottoli : Added GEXT_PROJ and GEXT_PROJ_QTR extrapolations
     697              : !> \author fawzi
     698              : ! **************************************************************************************************
     699        25263 :    SUBROUTINE wfi_extrapolate(wf_history, qs_env, dt, extrapolation_method_nr, &
     700              :                               orthogonal_wf)
     701              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
     702              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     703              :       REAL(KIND=dp), INTENT(IN)                          :: dt
     704              :       INTEGER, INTENT(OUT), OPTIONAL                     :: extrapolation_method_nr
     705              :       LOGICAL, INTENT(OUT), OPTIONAL                     :: orthogonal_wf
     706              : 
     707              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'wfi_extrapolate'
     708              : 
     709              :       INTEGER                                            :: actual_extrapolation_method_nr, handle, &
     710              :                                                             i, img, io_unit, ispin, k, n, nmo, &
     711              :                                                             nvec, print_level
     712              :       LOGICAL                                            :: do_kpoints, my_orthogonal_wf, use_overlap
     713              :       REAL(KIND=dp)                                      :: alpha, t0, t1, t2
     714        25263 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: coeffs
     715        25263 :       TYPE(cp_fm_pool_p_type), DIMENSION(:), POINTER     :: ao_mo_fm_pools
     716              :       TYPE(cp_fm_struct_type), POINTER                   :: matrix_struct, matrix_struct_new
     717              :       TYPE(cp_fm_type)                                   :: csc, fm_tmp
     718              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     719              :       TYPE(cp_logger_type), POINTER                      :: logger
     720        25263 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s, rho_ao, rho_frozen_ao
     721        25263 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: rho_ao_kp
     722        25263 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     723              :       TYPE(qs_rho_type), POINTER                         :: rho
     724              :       TYPE(qs_wf_snapshot_type), POINTER                 :: t0_state, t1_state
     725              : 
     726        25263 :       NULLIFY (mos, ao_mo_fm_pools, t0_state, t1_state, mo_coeff, &
     727        25263 :                rho, rho_ao, rho_frozen_ao)
     728              : 
     729        25263 :       use_overlap = wf_history%store_overlap
     730              : 
     731        25263 :       CALL timeset(routineN, handle)
     732        25263 :       logger => cp_get_default_logger()
     733        25263 :       print_level = logger%iter_info%print_level
     734              :       io_unit = cp_print_key_unit_nr(logger, qs_env%input, "DFT%SCF%PRINT%PROGRAM_RUN_INFO", &
     735        25263 :                                      extension=".scfLog")
     736              : 
     737        25263 :       CPASSERT(ASSOCIATED(wf_history))
     738        25263 :       CPASSERT(wf_history%ref_count > 0)
     739        25263 :       CPASSERT(ASSOCIATED(qs_env))
     740        25263 :       CALL get_qs_env(qs_env, mos=mos, rho=rho, do_kpoints=do_kpoints)
     741        25263 :       CALL mpools_get(qs_env%mpools, ao_mo_fm_pools=ao_mo_fm_pools)
     742              :       ! chooses the method for this extrapolation
     743        25263 :       IF (wf_history%snapshot_count < 1) THEN
     744              :          actual_extrapolation_method_nr = wfi_use_guess_method_nr
     745              :       ELSE
     746        16006 :          actual_extrapolation_method_nr = wf_history%interpolation_method_nr
     747              :       END IF
     748              : 
     749            8 :       SELECT CASE (actual_extrapolation_method_nr)
     750              :       CASE (wfi_linear_wf_method_nr)
     751            8 :          IF (wf_history%snapshot_count < 2) THEN
     752            4 :             actual_extrapolation_method_nr = wfi_use_prev_wf_method_nr
     753              :          END IF
     754              :       CASE (wfi_linear_p_method_nr)
     755           12 :          IF (wf_history%snapshot_count < 2) THEN
     756            6 :             actual_extrapolation_method_nr = wfi_use_prev_wf_method_nr
     757              :          END IF
     758              :       CASE (wfi_linear_ps_method_nr)
     759        16006 :          IF (wf_history%snapshot_count < 2) THEN
     760            6 :             actual_extrapolation_method_nr = wfi_use_prev_wf_method_nr
     761              :          END IF
     762              :       END SELECT
     763              : 
     764        25263 :       IF (PRESENT(extrapolation_method_nr)) &
     765        25263 :          extrapolation_method_nr = actual_extrapolation_method_nr
     766        25263 :       my_orthogonal_wf = .FALSE.
     767              : 
     768            8 :       SELECT CASE (actual_extrapolation_method_nr)
     769              :       CASE (wfi_frozen_method_nr)
     770            8 :          CPASSERT(.NOT. do_kpoints)
     771            8 :          t0_state => wfi_get_snapshot(wf_history, wf_index=1)
     772            8 :          CPASSERT(ASSOCIATED(t0_state%rho_frozen))
     773              : 
     774            8 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
     775            8 :          CALL wfi_set_history_variables(qs_env=qs_env, nvec=nvec)
     776              : 
     777            8 :          CALL qs_rho_get(t0_state%rho_frozen, rho_ao=rho_frozen_ao)
     778            8 :          CALL qs_rho_get(rho, rho_ao=rho_ao)
     779           16 :          DO ispin = 1, SIZE(rho_frozen_ao)
     780              :             CALL dbcsr_copy(rho_ao(ispin)%matrix, &
     781              :                             rho_frozen_ao(ispin)%matrix, &
     782           16 :                             keep_sparsity=.TRUE.)
     783              :          END DO
     784              :          !FM updating rho_ao directly with t0_state%rho_ao would have the
     785              :          !FM wrong matrix structure
     786            8 :          CALL qs_rho_update_rho(rho, qs_env=qs_env)
     787            8 :          CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
     788              : 
     789            8 :          my_orthogonal_wf = .FALSE.
     790              :       CASE (wfi_use_prev_rho_r_method_nr, wfi_use_prev_p_method_nr)
     791          484 :          IF (actual_extrapolation_method_nr == wfi_use_prev_rho_r_method_nr) THEN
     792              :             CALL cp_warn(__LOCATION__, &
     793              :                          "USE_PREV_RHO_R is deprecated and will be removed in a future "// &
     794            8 :                          "release; it is now an alias of USE_PREV_P.")
     795              :          END IF
     796          484 :          t0_state => wfi_get_snapshot(wf_history, wf_index=1)
     797          484 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
     798          484 :          CALL wfi_set_history_variables(qs_env=qs_env, nvec=nvec)
     799          484 :          IF (do_kpoints) THEN
     800          218 :             CPASSERT(ASSOCIATED(t0_state%rho_ao_kp))
     801          218 :             CALL qs_rho_get(rho, rho_ao_kp=rho_ao_kp)
     802          524 :             DO ispin = 1, SIZE(t0_state%rho_ao_kp, 1)
     803        31248 :                DO img = 1, SIZE(t0_state%rho_ao_kp, 2)
     804        31030 :                   IF (img > SIZE(rho_ao_kp, 2)) THEN
     805           18 :                      CPWARN("Change in cell neighborlist: might affect quality of initial guess")
     806              :                   ELSE
     807              :                      CALL dbcsr_copy(rho_ao_kp(ispin, img)%matrix, &
     808              :                                      t0_state%rho_ao_kp(ispin, img)%matrix, &
     809        30706 :                                      keep_sparsity=.TRUE.)
     810              :                   END IF
     811              :                END DO
     812              :             END DO
     813              :          ELSE
     814          266 :             CPASSERT(ASSOCIATED(t0_state%rho_ao))
     815          266 :             CALL qs_rho_get(rho, rho_ao=rho_ao)
     816          662 :             DO ispin = 1, SIZE(t0_state%rho_ao)
     817              :                CALL dbcsr_copy(rho_ao(ispin)%matrix, &
     818              :                                t0_state%rho_ao(ispin)%matrix, &
     819          662 :                                keep_sparsity=.TRUE.)
     820              :             END DO
     821              :          END IF
     822              :          !FM updating rho_ao directly with t0_state%rho_ao would have the
     823              :          !FM wrong matrix structure
     824          484 :          CALL qs_rho_update_rho(rho, qs_env=qs_env)
     825          484 :          CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
     826              :       CASE (wfi_use_prev_wf_method_nr)
     827          442 :          my_orthogonal_wf = .TRUE.
     828          442 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
     829          442 :          CALL wfi_set_history_variables(qs_env=qs_env, nvec=nvec)
     830              : 
     831          442 :          IF (do_kpoints) THEN
     832            6 :             CALL wfi_use_prev_wf_kp(qs_env, io_unit, print_level)
     833              :          ELSE
     834          436 :             CALL qs_rho_get(rho, rho_ao=rho_ao)
     835          924 :             DO ispin = 1, SIZE(mos)
     836          488 :                CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, nmo=nmo)
     837          488 :                CALL reorthogonalize_vectors(qs_env, v_matrix=mo_coeff, n_col=nmo)
     838         1412 :                CALL calculate_density_matrix(mo_set=mos(ispin), density_matrix=rho_ao(ispin)%matrix)
     839              :             END DO
     840          436 :             CALL qs_rho_update_rho(rho, qs_env=qs_env)
     841          436 :             CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
     842              :          END IF
     843              : 
     844              :       CASE (wfi_use_guess_method_nr)
     845              :          !FM more clean to do it here, but it
     846              :          !FM might need to read a file (restart) and thus globenv
     847              :          !FM I do not want globenv here, thus done by the caller
     848              :          !FM (btw. it also needs the eigensolver, and unless you relocate it
     849              :          !FM gives circular dependencies)
     850         9341 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
     851         9341 :          CALL wfi_set_history_variables(qs_env=qs_env, nvec=nvec)
     852              :       CASE (wfi_linear_wf_method_nr)
     853            4 :          CPASSERT(.NOT. do_kpoints)
     854            4 :          t0_state => wfi_get_snapshot(wf_history, wf_index=2)
     855            4 :          t1_state => wfi_get_snapshot(wf_history, wf_index=1)
     856            4 :          CPASSERT(ASSOCIATED(t0_state))
     857            4 :          CPASSERT(ASSOCIATED(t1_state))
     858            4 :          CPASSERT(ASSOCIATED(t0_state%wf))
     859            4 :          CPASSERT(ASSOCIATED(t1_state%wf))
     860            4 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
     861            4 :          CALL wfi_set_history_variables(qs_env=qs_env, nvec=nvec)
     862              : 
     863            4 :          my_orthogonal_wf = .TRUE.
     864            4 :          t0 = 0.0_dp
     865            4 :          t1 = t1_state%dt
     866            4 :          t2 = t1 + dt
     867            4 :          CALL qs_rho_get(rho, rho_ao=rho_ao)
     868            8 :          DO ispin = 1, SIZE(mos)
     869              :             CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, &
     870            4 :                             nmo=nmo)
     871              :             CALL cp_fm_scale_and_add(alpha=0.0_dp, &
     872              :                                      matrix_a=mo_coeff, &
     873              :                                      matrix_b=t1_state%wf(ispin), &
     874            4 :                                      beta=(t2 - t0)/(t1 - t0))
     875              :             ! this copy should be unnecessary
     876              :             CALL cp_fm_scale_and_add(alpha=1.0_dp, &
     877              :                                      matrix_a=mo_coeff, &
     878            4 :                                      beta=(t1 - t2)/(t1 - t0), matrix_b=t0_state%wf(ispin))
     879              :             CALL reorthogonalize_vectors(qs_env, &
     880              :                                          v_matrix=mo_coeff, &
     881            4 :                                          n_col=nmo)
     882              :             CALL calculate_density_matrix(mo_set=mos(ispin), &
     883           12 :                                           density_matrix=rho_ao(ispin)%matrix)
     884              :          END DO
     885            4 :          CALL qs_rho_update_rho(rho, qs_env=qs_env)
     886              : 
     887              :          CALL qs_ks_did_change(qs_env%ks_env, &
     888            4 :                                rho_changed=.TRUE.)
     889              :       CASE (wfi_linear_p_method_nr)
     890            6 :          t0_state => wfi_get_snapshot(wf_history, wf_index=2)
     891            6 :          t1_state => wfi_get_snapshot(wf_history, wf_index=1)
     892            6 :          CPASSERT(ASSOCIATED(t0_state))
     893            6 :          CPASSERT(ASSOCIATED(t1_state))
     894            6 :          IF (do_kpoints) THEN
     895            2 :             CPASSERT(ASSOCIATED(t0_state%rho_ao_kp))
     896            2 :             CPASSERT(ASSOCIATED(t1_state%rho_ao_kp))
     897              :          ELSE
     898            4 :             CPASSERT(ASSOCIATED(t0_state%rho_ao))
     899            4 :             CPASSERT(ASSOCIATED(t1_state%rho_ao))
     900              :          END IF
     901            6 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
     902            6 :          CALL wfi_set_history_variables(qs_env=qs_env, nvec=nvec)
     903              : 
     904            6 :          t0 = 0.0_dp
     905            6 :          t1 = t1_state%dt
     906            6 :          t2 = t1 + dt
     907            6 :          IF (do_kpoints) THEN
     908            2 :             CALL qs_rho_get(rho, rho_ao_kp=rho_ao_kp)
     909            4 :             DO ispin = 1, SIZE(rho_ao_kp, 1)
     910          528 :                DO img = 1, SIZE(rho_ao_kp, 2)
     911          524 :                   IF (img > SIZE(t0_state%rho_ao_kp, 2) .OR. &
     912            2 :                       img > SIZE(t1_state%rho_ao_kp, 2)) THEN
     913           22 :                      CPWARN("Change in cell neighborlist: might affect quality of initial guess")
     914              :                   ELSE
     915              :                      CALL dbcsr_add(rho_ao_kp(ispin, img)%matrix, t1_state%rho_ao_kp(ispin, img)%matrix, &
     916          502 :                                     alpha_scalar=0.0_dp, beta_scalar=(t2 - t0)/(t1 - t0)) ! this copy should be unnecessary
     917              :                      CALL dbcsr_add(rho_ao_kp(ispin, img)%matrix, t0_state%rho_ao_kp(ispin, img)%matrix, &
     918          502 :                                     alpha_scalar=1.0_dp, beta_scalar=(t1 - t2)/(t1 - t0))
     919              :                   END IF
     920              :                END DO
     921              :             END DO
     922              :          ELSE
     923            4 :             CALL qs_rho_get(rho, rho_ao=rho_ao)
     924            8 :             DO ispin = 1, SIZE(rho_ao)
     925              :                CALL dbcsr_add(rho_ao(ispin)%matrix, t1_state%rho_ao(ispin)%matrix, &
     926            4 :                               alpha_scalar=0.0_dp, beta_scalar=(t2 - t0)/(t1 - t0)) ! this copy should be unnecessary
     927              :                CALL dbcsr_add(rho_ao(ispin)%matrix, t0_state%rho_ao(ispin)%matrix, &
     928            8 :                               alpha_scalar=1.0_dp, beta_scalar=(t1 - t2)/(t1 - t0))
     929              :             END DO
     930              :          END IF
     931            6 :          CALL qs_rho_update_rho(rho, qs_env=qs_env)
     932            6 :          CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
     933              :       CASE (wfi_linear_ps_method_nr)
     934              :          ! wf not calculated, extract with PSC renormalized?
     935              :          ! use wf_linear?
     936           12 :          CPASSERT(.NOT. do_kpoints)
     937           12 :          t0_state => wfi_get_snapshot(wf_history, wf_index=2)
     938           12 :          t1_state => wfi_get_snapshot(wf_history, wf_index=1)
     939           12 :          CPASSERT(ASSOCIATED(t0_state))
     940           12 :          CPASSERT(ASSOCIATED(t1_state))
     941           12 :          CPASSERT(ASSOCIATED(t0_state%wf))
     942           12 :          CPASSERT(ASSOCIATED(t1_state%wf))
     943           12 :          IF (wf_history%store_overlap) THEN
     944            4 :             CPASSERT(ASSOCIATED(t0_state%overlap))
     945            4 :             CPASSERT(ASSOCIATED(t1_state%overlap))
     946              :          END IF
     947           12 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
     948           12 :          IF (nvec >= wf_history%memory_depth) THEN
     949           12 :             IF ((qs_env%scf_control%max_scf_hist /= 0) .AND. (qs_env%scf_control%eps_scf_hist /= 0)) THEN
     950            0 :                qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
     951            0 :                qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
     952            0 :                qs_env%scf_control%outer_scf%have_scf = .FALSE.
     953           12 :             ELSE IF (qs_env%scf_control%max_scf_hist /= 0) THEN
     954            0 :                qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
     955            0 :                qs_env%scf_control%outer_scf%have_scf = .FALSE.
     956           12 :             ELSE IF (qs_env%scf_control%eps_scf_hist /= 0) THEN
     957            0 :                qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
     958              :             END IF
     959              :          END IF
     960              : 
     961           12 :          my_orthogonal_wf = .TRUE.
     962              :          ! use PS_2=2 PS_1-PS_0
     963              :          ! C_2 comes from using PS_2 as a projector acting on C_1
     964           12 :          CALL qs_rho_get(rho, rho_ao=rho_ao)
     965           24 :          DO ispin = 1, SIZE(mos)
     966           12 :             NULLIFY (mo_coeff, matrix_struct, matrix_struct_new)
     967           12 :             CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff)
     968              :             CALL cp_fm_get_info(mo_coeff, nrow_global=n, ncol_global=k, &
     969           12 :                                 matrix_struct=matrix_struct)
     970              :             CALL cp_fm_struct_create(matrix_struct_new, template_fmstruct=matrix_struct, &
     971           12 :                                      nrow_global=k, ncol_global=k)
     972           12 :             CALL cp_fm_create(csc, matrix_struct_new)
     973           12 :             CALL cp_fm_struct_release(matrix_struct_new)
     974              : 
     975           12 :             IF (use_overlap) THEN
     976            4 :                CALL cp_dbcsr_sm_fm_multiply(t0_state%overlap, t1_state%wf(ispin), mo_coeff, k)
     977            4 :                CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, t0_state%wf(ispin), mo_coeff, 0.0_dp, csc)
     978              :             ELSE
     979              :                CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, t0_state%wf(ispin), &
     980            8 :                                   t1_state%wf(ispin), 0.0_dp, csc)
     981              :             END IF
     982           12 :             CALL parallel_gemm('N', 'N', n, k, k, 1.0_dp, t0_state%wf(ispin), csc, 0.0_dp, mo_coeff)
     983           12 :             CALL cp_fm_release(csc)
     984           12 :             CALL cp_fm_scale_and_add(-1.0_dp, mo_coeff, 2.0_dp, t1_state%wf(ispin))
     985              :             CALL reorthogonalize_vectors(qs_env, &
     986              :                                          v_matrix=mo_coeff, &
     987           12 :                                          n_col=k)
     988              :             CALL calculate_density_matrix(mo_set=mos(ispin), &
     989           48 :                                           density_matrix=rho_ao(ispin)%matrix)
     990              :          END DO
     991           12 :          CALL qs_rho_update_rho(rho, qs_env=qs_env)
     992           12 :          CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
     993              : 
     994              :       CASE (wfi_ps_method_nr)
     995              :          ! figure out the actual number of vectors to use in the extrapolation:
     996          376 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
     997          376 :          CPASSERT(nvec > 0)
     998          376 :          IF (nvec >= wf_history%memory_depth) THEN
     999          178 :             IF ((qs_env%scf_control%max_scf_hist /= 0) .AND. (qs_env%scf_control%eps_scf_hist /= 0)) THEN
    1000            0 :                qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1001            0 :                qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1002            0 :                qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1003          178 :             ELSE IF (qs_env%scf_control%max_scf_hist /= 0) THEN
    1004            0 :                qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1005            0 :                qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1006          178 :             ELSE IF (qs_env%scf_control%eps_scf_hist /= 0) THEN
    1007            0 :                qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1008              :             END IF
    1009              :          END IF
    1010              : 
    1011          376 :          IF (do_kpoints) THEN
    1012            4 :             CALL wfi_extrapolate_ps_aspc_kp(wf_history, qs_env, nvec, io_unit, print_level)
    1013            4 :             my_orthogonal_wf = .TRUE.
    1014              :          ELSE
    1015          372 :             my_orthogonal_wf = .TRUE.
    1016          822 :             DO ispin = 1, SIZE(mos)
    1017          450 :                NULLIFY (mo_coeff, matrix_struct, matrix_struct_new)
    1018          450 :                CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff)
    1019              :                CALL cp_fm_get_info(mo_coeff, nrow_global=n, ncol_global=k, &
    1020          450 :                                    matrix_struct=matrix_struct)
    1021          450 :                CALL cp_fm_create(fm_tmp, matrix_struct)
    1022              :                CALL cp_fm_struct_create(matrix_struct_new, template_fmstruct=matrix_struct, &
    1023          450 :                                         nrow_global=k, ncol_global=k)
    1024          450 :                CALL cp_fm_create(csc, matrix_struct_new)
    1025          450 :                CALL cp_fm_struct_release(matrix_struct_new)
    1026              :                ! first the most recent
    1027          450 :                t1_state => wfi_get_snapshot(wf_history, wf_index=1)
    1028          450 :                CALL cp_fm_to_fm(t1_state%wf(ispin), mo_coeff)
    1029          450 :                alpha = nvec
    1030          450 :                CALL cp_fm_scale(alpha, mo_coeff)
    1031          450 :                CALL qs_rho_get(rho, rho_ao=rho_ao)
    1032          962 :                DO i = 2, nvec
    1033          512 :                   t0_state => wfi_get_snapshot(wf_history, wf_index=i)
    1034          512 :                   IF (use_overlap) THEN
    1035          474 :                      CALL cp_dbcsr_sm_fm_multiply(t0_state%overlap, t1_state%wf(ispin), fm_tmp, k)
    1036          474 :                      CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, t0_state%wf(ispin), fm_tmp, 0.0_dp, csc)
    1037              :                   ELSE
    1038              :                      CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, t0_state%wf(ispin), &
    1039           38 :                                         t1_state%wf(ispin), 0.0_dp, csc)
    1040              :                   END IF
    1041          512 :                   CALL parallel_gemm('N', 'N', n, k, k, 1.0_dp, t0_state%wf(ispin), csc, 0.0_dp, fm_tmp)
    1042          512 :                   alpha = -1.0_dp*alpha*REAL(nvec - i + 1, dp)/REAL(i, dp)
    1043          962 :                   CALL cp_fm_scale_and_add(1.0_dp, mo_coeff, alpha, fm_tmp)
    1044              :                END DO
    1045              : 
    1046          450 :                CALL cp_fm_release(csc)
    1047          450 :                CALL cp_fm_release(fm_tmp)
    1048              :                CALL reorthogonalize_vectors(qs_env, &
    1049              :                                             v_matrix=mo_coeff, &
    1050          450 :                                             n_col=k)
    1051              :                CALL calculate_density_matrix(mo_set=mos(ispin), &
    1052         1722 :                                              density_matrix=rho_ao(ispin)%matrix)
    1053              :             END DO
    1054          372 :             CALL qs_rho_update_rho(rho, qs_env=qs_env)
    1055          372 :             CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
    1056              :          END IF
    1057              : 
    1058              :       CASE (wfi_aspc_nr)
    1059        14422 :          CALL cite_reference(Kolafa2004)
    1060        14422 :          CALL cite_reference(Kuhne2007)
    1061              :          ! figure out the actual number of vectors to use in the extrapolation:
    1062        14422 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
    1063        14422 :          CPASSERT(nvec > 0)
    1064        14422 :          IF (nvec >= wf_history%memory_depth) THEN
    1065         9400 :             IF ((qs_env%scf_control%max_scf_hist /= 0) .AND. &
    1066              :                 (qs_env%scf_control%eps_scf_hist /= 0)) THEN
    1067           18 :                qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1068           18 :                qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1069           18 :                qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1070         9382 :             ELSE IF (qs_env%scf_control%max_scf_hist /= 0) THEN
    1071           62 :                qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1072           62 :                qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1073         9320 :             ELSE IF (qs_env%scf_control%eps_scf_hist /= 0) THEN
    1074            8 :                qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1075              :             END IF
    1076              :          END IF
    1077              : 
    1078        14422 :          IF (do_kpoints) THEN
    1079          392 :             CALL wfi_extrapolate_ps_aspc_kp(wf_history, qs_env, nvec, io_unit, print_level)
    1080          392 :             my_orthogonal_wf = .TRUE.
    1081              :          ELSE
    1082        14030 :             my_orthogonal_wf = .TRUE.
    1083        14030 :             CALL qs_rho_get(rho, rho_ao=rho_ao)
    1084        29167 :             DO ispin = 1, SIZE(mos)
    1085        15137 :                NULLIFY (mo_coeff, matrix_struct, matrix_struct_new)
    1086        15137 :                CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff)
    1087              :                CALL cp_fm_get_info(mo_coeff, &
    1088              :                                    nrow_global=n, &
    1089              :                                    ncol_global=k, &
    1090        15137 :                                    matrix_struct=matrix_struct)
    1091        15137 :                CALL cp_fm_create(fm_tmp, matrix_struct, set_zero=.TRUE.)
    1092              :                CALL cp_fm_struct_create(matrix_struct_new, &
    1093              :                                         template_fmstruct=matrix_struct, &
    1094              :                                         nrow_global=k, &
    1095        15137 :                                         ncol_global=k)
    1096        15137 :                CALL cp_fm_create(csc, matrix_struct_new, set_zero=.TRUE.)
    1097        15137 :                CALL cp_fm_struct_release(matrix_struct_new)
    1098              :                ! first the most recent
    1099              :                t1_state => wfi_get_snapshot(wf_history, &
    1100        15137 :                                             wf_index=1)
    1101        15137 :                CALL cp_fm_to_fm(t1_state%wf(ispin), mo_coeff)
    1102        15137 :                alpha = REAL(4*nvec - 2, KIND=dp)/REAL(nvec + 1, KIND=dp)
    1103        15137 :                IF ((io_unit > 0) .AND. (print_level > low_print_level)) THEN
    1104              :                   WRITE (UNIT=io_unit, FMT="(/,T2,A,/,/,T3,A,I0,/,/,T3,A2,I0,A4,F10.6)") &
    1105         3146 :                      "Parameters for the always stable predictor-corrector (ASPC) method:", &
    1106         3146 :                      "ASPC order: ", MAX(nvec - 2, 0), &
    1107         6292 :                      "B(", 1, ") = ", alpha
    1108              :                END IF
    1109        15137 :                CALL cp_fm_scale(alpha, mo_coeff)
    1110              : 
    1111        59273 :                DO i = 2, nvec
    1112        44136 :                   t0_state => wfi_get_snapshot(wf_history, wf_index=i)
    1113        44136 :                   IF (use_overlap) THEN
    1114        32596 :                      CALL cp_dbcsr_sm_fm_multiply(t0_state%overlap, t1_state%wf(ispin), fm_tmp, k)
    1115        32596 :                      CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, t0_state%wf(ispin), fm_tmp, 0.0_dp, csc)
    1116              :                   ELSE
    1117              :                      CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, t0_state%wf(ispin), &
    1118        11540 :                                         t1_state%wf(ispin), 0.0_dp, csc)
    1119              :                   END IF
    1120        44136 :                   CALL parallel_gemm('N', 'N', n, k, k, 1.0_dp, t0_state%wf(ispin), csc, 0.0_dp, fm_tmp)
    1121              :                   alpha = (-1.0_dp)**(i + 1)*REAL(i, KIND=dp)* &
    1122        44136 :                           binomial(2*nvec, nvec - i)/binomial(2*nvec - 2, nvec - 1)
    1123        44136 :                   IF ((io_unit > 0) .AND. (print_level > low_print_level)) THEN
    1124              :                      WRITE (UNIT=io_unit, FMT="(T3,A2,I0,A4,F10.6)") &
    1125         9440 :                         "B(", i, ") = ", alpha
    1126              :                   END IF
    1127        59273 :                   CALL cp_fm_scale_and_add(1.0_dp, mo_coeff, alpha, fm_tmp)
    1128              :                END DO
    1129        15137 :                CALL cp_fm_release(csc)
    1130        15137 :                CALL cp_fm_release(fm_tmp)
    1131              :                CALL reorthogonalize_vectors(qs_env, &
    1132              :                                             v_matrix=mo_coeff, &
    1133        15137 :                                             n_col=k)
    1134              :                CALL calculate_density_matrix(mo_set=mos(ispin), &
    1135        44304 :                                              density_matrix=rho_ao(ispin)%matrix)
    1136              :             END DO
    1137        14030 :             CALL qs_rho_update_rho(rho, qs_env=qs_env)
    1138        14030 :             CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
    1139              :          END IF ! do_kpoints
    1140              : 
    1141              :       CASE (wfi_gext_proj_nr)
    1142          140 :          IF (do_kpoints) THEN
    1143            4 :             nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
    1144            4 :             CPASSERT(nvec > 0)
    1145            4 :             CALL wfi_extrapolate_gext_proj_kp(wf_history, qs_env, nvec, io_unit, print_level)
    1146              :          ELSE
    1147              : 
    1148              :             ! figure out the actual number of vectors to use in the extrapolation:
    1149          136 :             nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
    1150          136 :             IF (nvec >= wf_history%memory_depth) THEN
    1151           88 :                IF ((qs_env%scf_control%max_scf_hist /= 0) .AND. &
    1152              :                    (qs_env%scf_control%eps_scf_hist /= 0)) THEN
    1153            0 :                   qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1154            0 :                   qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1155            0 :                   qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1156           88 :                ELSE IF (qs_env%scf_control%max_scf_hist /= 0) THEN
    1157            0 :                   qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1158            0 :                   qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1159           88 :                ELSE IF (qs_env%scf_control%eps_scf_hist /= 0) THEN
    1160            0 :                   qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1161              :                END IF
    1162              :             END IF
    1163          136 :             CPASSERT(nvec > 0)
    1164              : 
    1165              :             ! get the coefficients for the fitting
    1166          408 :             ALLOCATE (coeffs(nvec))
    1167          136 :             NULLIFY (matrix_s)
    1168          136 :             CALL get_qs_env(qs_env, matrix_s=matrix_s)
    1169              :             CALL diff_fitting(wf_history, matrix_s(1)%matrix, coeffs, nvec, &
    1170          136 :                               1e-4_dp, io_unit, print_level)
    1171              : 
    1172          136 :             my_orthogonal_wf = .TRUE.
    1173          136 :             CALL qs_rho_get(rho, rho_ao=rho_ao)
    1174          328 :             DO ispin = 1, SIZE(mos)
    1175          192 :                NULLIFY (mo_coeff, matrix_struct, matrix_struct_new)
    1176          192 :                CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff)
    1177              :                CALL cp_fm_get_info(mo_coeff, &
    1178              :                                    nrow_global=n, &
    1179              :                                    ncol_global=k, &
    1180          192 :                                    matrix_struct=matrix_struct)
    1181          192 :                CALL cp_fm_create(fm_tmp, matrix_struct)
    1182              :                CALL cp_fm_struct_create(matrix_struct_new, &
    1183              :                                         template_fmstruct=matrix_struct, &
    1184              :                                         nrow_global=k, &
    1185          192 :                                         ncol_global=k)
    1186          192 :                CALL cp_fm_create(csc, matrix_struct_new)
    1187          192 :                CALL cp_fm_struct_release(matrix_struct_new)
    1188              : 
    1189          192 :                t1_state => wfi_get_snapshot(wf_history, wf_index=1)
    1190              : 
    1191              :                ! do the linear combination of previous PSs
    1192          192 :                CALL cp_fm_set_all(mo_coeff, 0.0_dp)
    1193          704 :                DO i = 1, nvec
    1194          512 :                   t0_state => wfi_get_snapshot(wf_history, wf_index=i)
    1195          512 :                   CALL cp_dbcsr_sm_fm_multiply(t0_state%overlap, t1_state%wf(ispin), fm_tmp, k)
    1196          512 :                   CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, t0_state%wf(ispin), fm_tmp, 0.0_dp, csc)
    1197          512 :                   CALL parallel_gemm('N', 'N', n, k, k, 1.0_dp, t0_state%wf(ispin), csc, 0.0_dp, fm_tmp)
    1198          704 :                   CALL cp_fm_scale_and_add(1.0_dp, mo_coeff, coeffs(i), fm_tmp)
    1199              :                END DO
    1200          192 :                CALL cp_fm_release(csc)
    1201          192 :                CALL cp_fm_release(fm_tmp)
    1202              :                CALL reorthogonalize_vectors(qs_env, &
    1203              :                                             v_matrix=mo_coeff, &
    1204          192 :                                             n_col=k)
    1205              :                CALL calculate_density_matrix(mo_set=mos(ispin), &
    1206          712 :                                              density_matrix=rho_ao(ispin)%matrix)
    1207              :             END DO
    1208          136 :             CALL qs_rho_update_rho(rho, qs_env=qs_env)
    1209          136 :             CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
    1210              : 
    1211          136 :             DEALLOCATE (coeffs)
    1212              : 
    1213              :          END IF
    1214              : 
    1215              :       CASE (wfi_gext_proj_qtr_nr)
    1216           28 :          IF (do_kpoints) THEN
    1217            4 :             nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
    1218            4 :             CPASSERT(nvec > 0)
    1219            4 :             CALL wfi_extrapolate_gext_proj_kp(wf_history, qs_env, nvec, io_unit, print_level)
    1220              :          ELSE
    1221              : 
    1222              :             ! figure out the actual number of vectors to use in the extrapolation:
    1223           24 :             nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
    1224           24 :             IF (nvec >= wf_history%memory_depth) THEN
    1225            8 :                IF ((qs_env%scf_control%max_scf_hist /= 0) .AND. &
    1226              :                    (qs_env%scf_control%eps_scf_hist /= 0)) THEN
    1227            0 :                   qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1228            0 :                   qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1229            0 :                   qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1230            8 :                ELSE IF (qs_env%scf_control%max_scf_hist /= 0) THEN
    1231            0 :                   qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1232            0 :                   qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1233            8 :                ELSE IF (qs_env%scf_control%eps_scf_hist /= 0) THEN
    1234            0 :                   qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1235              :                END IF
    1236              :             END IF
    1237           24 :             CPASSERT(nvec > 0)
    1238              : 
    1239              :             ! get the coefficients for the fitting
    1240           72 :             ALLOCATE (coeffs(nvec))
    1241           24 :             NULLIFY (matrix_s)
    1242           24 :             CALL get_qs_env(qs_env, matrix_s=matrix_s)
    1243              :             CALL tr_fitting(wf_history, matrix_s(1)%matrix, coeffs, nvec, &
    1244           24 :                             1e-4_dp, io_unit, print_level)
    1245              : 
    1246           24 :             my_orthogonal_wf = .TRUE.
    1247           24 :             CALL qs_rho_get(rho, rho_ao=rho_ao)
    1248           48 :             DO ispin = 1, SIZE(mos)
    1249           24 :                NULLIFY (mo_coeff, matrix_struct, matrix_struct_new)
    1250           24 :                CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff)
    1251              :                CALL cp_fm_get_info(mo_coeff, &
    1252              :                                    nrow_global=n, &
    1253              :                                    ncol_global=k, &
    1254           24 :                                    matrix_struct=matrix_struct)
    1255           24 :                CALL cp_fm_create(fm_tmp, matrix_struct)
    1256              :                CALL cp_fm_struct_create(matrix_struct_new, &
    1257              :                                         template_fmstruct=matrix_struct, &
    1258              :                                         nrow_global=k, &
    1259           24 :                                         ncol_global=k)
    1260           24 :                CALL cp_fm_create(csc, matrix_struct_new)
    1261           24 :                CALL cp_fm_struct_release(matrix_struct_new)
    1262              : 
    1263           24 :                t1_state => wfi_get_snapshot(wf_history, wf_index=1)
    1264              : 
    1265              :                ! do the linear combination of previous PSs
    1266           24 :                CALL cp_fm_set_all(mo_coeff, 0.0_dp)
    1267          104 :                DO i = 1, nvec
    1268           80 :                   t0_state => wfi_get_snapshot(wf_history, wf_index=i)
    1269           80 :                   CALL cp_dbcsr_sm_fm_multiply(t0_state%overlap, t1_state%wf(ispin), fm_tmp, k)
    1270           80 :                   CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, t0_state%wf(ispin), fm_tmp, 0.0_dp, csc)
    1271           80 :                   CALL parallel_gemm('N', 'N', n, k, k, 1.0_dp, t0_state%wf(ispin), csc, 0.0_dp, fm_tmp)
    1272          104 :                   CALL cp_fm_scale_and_add(1.0_dp, mo_coeff, coeffs(i), fm_tmp)
    1273              :                END DO
    1274           24 :                CALL cp_fm_release(csc)
    1275           24 :                CALL cp_fm_release(fm_tmp)
    1276              :                CALL reorthogonalize_vectors(qs_env, &
    1277              :                                             v_matrix=mo_coeff, &
    1278           24 :                                             n_col=k)
    1279              :                CALL calculate_density_matrix(mo_set=mos(ispin), &
    1280           96 :                                              density_matrix=rho_ao(ispin)%matrix)
    1281              :             END DO
    1282           24 :             CALL qs_rho_update_rho(rho, qs_env=qs_env)
    1283           24 :             CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
    1284              : 
    1285           24 :             DEALLOCATE (coeffs)
    1286              : 
    1287              :          END IF
    1288              : 
    1289              :       CASE default
    1290              :          CALL cp_abort(__LOCATION__, &
    1291              :                        "Unknown interpolation method: "// &
    1292        25263 :                        TRIM(ADJUSTL(cp_to_string(wf_history%interpolation_method_nr))))
    1293              :       END SELECT
    1294        25263 :       IF (PRESENT(orthogonal_wf)) orthogonal_wf = my_orthogonal_wf
    1295              :       CALL cp_print_key_finished_output(io_unit, logger, qs_env%input, &
    1296        25263 :                                         "DFT%SCF%PRINT%PROGRAM_RUN_INFO")
    1297        25263 :       CALL timestop(handle)
    1298        25263 :    END SUBROUTINE wfi_extrapolate
    1299              : 
    1300              : ! **************************************************************************************************
    1301              : !> \brief Reorthogonalizes the wavefunctions from the previous step for k-points
    1302              : !>        using the current S(k) metric and rebuilds the density matrix.
    1303              : !> \param qs_env The QS environment
    1304              : !> \param io_unit output unit
    1305              : !> \param print_level print level
    1306              : !> \param pbc_shift_ref ...
    1307              : !> \param load_snapshot_wf ...
    1308              : ! **************************************************************************************************
    1309          410 :    SUBROUTINE wfi_use_prev_wf_kp(qs_env, io_unit, print_level, pbc_shift_ref, load_snapshot_wf)
    1310              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1311              :       INTEGER, INTENT(IN)                                :: io_unit, print_level
    1312              :       INTEGER, DIMENSION(:, :), INTENT(IN), OPTIONAL     :: pbc_shift_ref
    1313              :       LOGICAL, INTENT(IN), OPTIONAL                      :: load_snapshot_wf
    1314              : 
    1315              :       CHARACTER(len=*), PARAMETER :: routineN = 'wfi_use_prev_wf_kp'
    1316              : 
    1317          410 :       COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:)        :: col_scaling
    1318              :       INTEGER                                            :: chol_info, handle, igroup, ik, ikp, &
    1319              :                                                             indx, ispin, j, kplocal, nao, nkp, &
    1320              :                                                             nkp_groups, nmo, nspin
    1321          410 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: pbc_shift_cur, pbc_shift_src
    1322              :       INTEGER, DIMENSION(2)                              :: kp_range
    1323          410 :       INTEGER, DIMENSION(:, :), POINTER                  :: kp_dist
    1324          410 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
    1325              :       LOGICAL                                            :: my_kpgrp, reload_snapshot_wf, &
    1326              :                                                             use_pbc_phase_ref, use_real_wfn
    1327              :       REAL(KIND=dp)                                      :: eval_thresh
    1328          410 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenvalues
    1329          410 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: xkp
    1330          410 :       TYPE(copy_info_type), ALLOCATABLE, DIMENSION(:, :) :: info
    1331              :       TYPE(cp_cfm_type)                                  :: cfm_evecs, cfm_mhalf, cfm_nao_nmo_work, &
    1332              :                                                             cmos_new, csc_cfm
    1333          410 :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:)       :: csmat_cur
    1334          410 :       TYPE(cp_fm_pool_p_type), DIMENSION(:), POINTER     :: ao_ao_fm_pools_kp
    1335              :       TYPE(cp_fm_struct_type), POINTER                   :: ao_ao_struct, nmo_nmo_struct
    1336              :       TYPE(cp_fm_type)                                   :: fmdummy, fmlocal
    1337              :       TYPE(cp_fm_type), POINTER                          :: imos, mo_coeff, rmos
    1338          410 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_s_kp, rho_ao_kp
    1339              :       TYPE(dbcsr_type), POINTER                          :: cmatrix_db, rmatrix, tmpmat
    1340              :       TYPE(dft_control_type), POINTER                    :: dft_control
    1341              :       TYPE(kpoint_env_type), POINTER                     :: kp
    1342              :       TYPE(kpoint_type), POINTER                         :: kpoints
    1343              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1344              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    1345          410 :          POINTER                                         :: sab_nl
    1346              :       TYPE(qs_matrix_pools_type), POINTER                :: mpools_kp
    1347              :       TYPE(qs_rho_type), POINTER                         :: rho
    1348              :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
    1349              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
    1350              :       TYPE(qs_wf_snapshot_type), POINTER                 :: t1_state
    1351              :       TYPE(scf_control_type), POINTER                    :: scf_control
    1352              : 
    1353          410 :       CALL timeset(routineN, handle)
    1354              : 
    1355          410 :       NULLIFY (kpoints, dft_control, matrix_s_kp, scf_env, scf_control, rho, sab_nl, kp, &
    1356          410 :                mo_coeff, rmos, imos, wf_history, t1_state)
    1357              : 
    1358              :       CALL get_qs_env(qs_env, kpoints=kpoints, dft_control=dft_control, &
    1359              :                       matrix_s_kp=matrix_s_kp, scf_env=scf_env, &
    1360          410 :                       scf_control=scf_control, rho=rho)
    1361              :       CALL get_kpoint_info(kpoints, nkp=nkp, xkp=xkp, use_real_wfn=use_real_wfn, &
    1362              :                            kp_range=kp_range, nkp_groups=nkp_groups, kp_dist=kp_dist, &
    1363          410 :                            sab_nl=sab_nl, cell_to_index=cell_to_index)
    1364          410 :       kplocal = kp_range(2) - kp_range(1) + 1
    1365              : 
    1366          410 :       IF (use_real_wfn) THEN
    1367            0 :          CALL timestop(handle)
    1368            0 :          RETURN
    1369              :       END IF
    1370              : 
    1371          410 :       wf_history => qs_env%wf_history
    1372          410 :       reload_snapshot_wf = .FALSE.
    1373          410 :       IF (PRESENT(load_snapshot_wf)) reload_snapshot_wf = load_snapshot_wf
    1374          410 :       IF (PRESENT(pbc_shift_ref)) THEN
    1375         1212 :          ALLOCATE (pbc_shift_src(3, SIZE(pbc_shift_ref, 2)))
    1376        11636 :          pbc_shift_src(:, :) = pbc_shift_ref(:, :)
    1377          408 :          use_pbc_phase_ref = .TRUE.
    1378              :       ELSE
    1379            6 :          use_pbc_phase_ref = .FALSE.
    1380            6 :          IF (ASSOCIATED(wf_history)) THEN
    1381            6 :             IF (wf_history%store_wf_kp .AND. wf_history%snapshot_count > 0) THEN
    1382            4 :                t1_state => wfi_get_snapshot(wf_history, wf_index=1)
    1383            4 :                CPASSERT(ASSOCIATED(t1_state%wf_kp))
    1384            4 :                CPASSERT(ASSOCIATED(t1_state%kp_pbc_shift))
    1385            4 :                reload_snapshot_wf = .TRUE.
    1386           12 :                ALLOCATE (pbc_shift_src(3, SIZE(t1_state%kp_pbc_shift, 2)))
    1387          132 :                pbc_shift_src(:, :) = t1_state%kp_pbc_shift(:, :)
    1388              :                use_pbc_phase_ref = .TRUE.
    1389              :             END IF
    1390              :          END IF
    1391              :       END IF
    1392          408 :       IF (use_pbc_phase_ref) CALL wfi_compute_kp_pbc_shift(qs_env, pbc_shift_cur)
    1393              : 
    1394          410 :       kp => kpoints%kp_env(1)%kpoint_env
    1395          410 :       nspin = SIZE(kp%mos, 2)
    1396          410 :       CALL get_mo_set(kp%mos(1, 1), nao=nao, nmo=nmo, mo_coeff=mo_coeff)
    1397              : 
    1398          410 :       IF ((io_unit > 0) .AND. (print_level > low_print_level)) THEN
    1399              :          WRITE (UNIT=io_unit, FMT="(/,T2,A)") &
    1400            0 :             "Using previous wavefunctions as initial guess for k-points (with reorthogonalization)"
    1401              :       END IF
    1402              : 
    1403              :       ! Allocate dbcsr work matrices
    1404          410 :       ALLOCATE (rmatrix, cmatrix_db, tmpmat)
    1405          410 :       CALL dbcsr_create(rmatrix, template=matrix_s_kp(1, 1)%matrix, matrix_type=dbcsr_type_symmetric)
    1406          410 :       CALL dbcsr_create(cmatrix_db, template=matrix_s_kp(1, 1)%matrix, matrix_type=dbcsr_type_antisymmetric)
    1407          410 :       CALL dbcsr_create(tmpmat, template=matrix_s_kp(1, 1)%matrix, matrix_type=dbcsr_type_no_symmetry)
    1408          410 :       CALL cp_dbcsr_alloc_block_from_nbl(rmatrix, sab_nl)
    1409          410 :       CALL cp_dbcsr_alloc_block_from_nbl(cmatrix_db, sab_nl)
    1410              : 
    1411          410 :       CALL get_kpoint_info(kpoints, mpools=mpools_kp)
    1412          410 :       CALL mpools_get(mpools_kp, ao_ao_fm_pools=ao_ao_fm_pools_kp)
    1413          410 :       CALL fm_pool_create_fm(ao_ao_fm_pools_kp(1)%pool, fmlocal)
    1414          410 :       CALL cp_fm_get_info(fmlocal, matrix_struct=ao_ao_struct)
    1415              : 
    1416          410 :       CALL cp_cfm_create(cmos_new, mo_coeff%matrix_struct)
    1417          410 :       CALL cp_cfm_create(cfm_nao_nmo_work, mo_coeff%matrix_struct)
    1418              : 
    1419          410 :       NULLIFY (nmo_nmo_struct)
    1420              :       CALL cp_fm_struct_create(nmo_nmo_struct, template_fmstruct=mo_coeff%matrix_struct, &
    1421          410 :                                nrow_global=nmo, ncol_global=nmo)
    1422          410 :       CALL cp_cfm_create(csc_cfm, nmo_nmo_struct)
    1423          410 :       CALL cp_fm_struct_release(nmo_nmo_struct)
    1424              : 
    1425          410 :       para_env => kpoints%blacs_env_all%para_env
    1426         8254 :       ALLOCATE (info(kplocal*nkp_groups, 2))
    1427              : 
    1428         2322 :       ALLOCATE (csmat_cur(kplocal))
    1429         1502 :       DO ikp = 1, kplocal
    1430         1502 :          CALL cp_cfm_create(csmat_cur(ikp), ao_ao_struct)
    1431              :       END DO
    1432              : 
    1433              :       ! Phase A: Fourier Transform S(R) -> S(k)
    1434              :       indx = 0
    1435         1502 :       DO ikp = 1, kplocal
    1436         3374 :          DO igroup = 1, nkp_groups
    1437         1872 :             ik = kp_dist(1, igroup) + ikp - 1
    1438         1872 :             my_kpgrp = (ik >= kp_range(1) .AND. ik <= kp_range(2))
    1439         1872 :             indx = indx + 1
    1440              : 
    1441         1872 :             CALL dbcsr_set(rmatrix, 0.0_dp)
    1442         1872 :             CALL dbcsr_set(cmatrix_db, 0.0_dp)
    1443              :             CALL rskp_transform(rmatrix=rmatrix, cmatrix=cmatrix_db, rsmat=matrix_s_kp, &
    1444         1872 :                                 ispin=1, xkp=xkp(1:3, ik), cell_to_index=cell_to_index, sab_nl=sab_nl)
    1445         1872 :             CALL dbcsr_desymmetrize(rmatrix, tmpmat)
    1446         1872 :             CALL copy_dbcsr_to_fm(tmpmat, scf_env%scf_work1(1))
    1447         1872 :             CALL dbcsr_desymmetrize(cmatrix_db, tmpmat)
    1448         1872 :             CALL copy_dbcsr_to_fm(tmpmat, scf_env%scf_work1(2))
    1449              : 
    1450         2964 :             IF (my_kpgrp) THEN
    1451         1092 :                CALL cp_fm_start_copy_general(scf_env%scf_work1(1), fmlocal, para_env, info(indx, 1))
    1452         1092 :                CALL cp_fm_start_copy_general(scf_env%scf_work1(2), fmlocal, para_env, info(indx, 2))
    1453              :             ELSE
    1454          780 :                CALL cp_fm_start_copy_general(scf_env%scf_work1(1), fmdummy, para_env, info(indx, 1))
    1455          780 :                CALL cp_fm_start_copy_general(scf_env%scf_work1(2), fmdummy, para_env, info(indx, 2))
    1456              :             END IF
    1457              :          END DO
    1458              :       END DO
    1459              : 
    1460              :       ! Finish Communication
    1461              :       indx = 0
    1462         1502 :       DO ikp = 1, kplocal
    1463         3374 :          DO igroup = 1, nkp_groups
    1464         1872 :             ik = kp_dist(1, igroup) + ikp - 1
    1465         1872 :             my_kpgrp = (ik >= kp_range(1) .AND. ik <= kp_range(2))
    1466          780 :             indx = indx + 1
    1467         1092 :             IF (my_kpgrp) THEN
    1468         1092 :                CALL cp_fm_finish_copy_general(fmlocal, info(indx, 1))
    1469         1092 :                CALL cp_cfm_scale_and_add_fm(z_zero, csmat_cur(ikp), z_one, fmlocal)
    1470         1092 :                CALL cp_fm_finish_copy_general(fmlocal, info(indx, 2))
    1471         1092 :                CALL cp_cfm_scale_and_add_fm(z_one, csmat_cur(ikp), gaussi, fmlocal)
    1472              :             END IF
    1473              :          END DO
    1474              :       END DO
    1475              : 
    1476         2282 :       DO indx = 1, kplocal*nkp_groups
    1477         1872 :          CALL cp_fm_cleanup_copy_general(info(indx, 1))
    1478         2282 :          CALL cp_fm_cleanup_copy_general(info(indx, 2))
    1479              :       END DO
    1480              : 
    1481              :       ! Phase B: bring the WFN from its saved/internal PBC image convention to
    1482              :       ! the current convention, then orthogonalize it with respect to S(k).
    1483         1230 :       ALLOCATE (eigenvalues(nmo))
    1484          410 :       eval_thresh = 1.0E-12_dp
    1485              : 
    1486         1502 :       DO ikp = 1, kplocal
    1487         1092 :          kp => kpoints%kp_env(ikp)%kpoint_env
    1488         2786 :          DO ispin = 1, nspin
    1489         1284 :             CALL get_mo_set(kp%mos(1, ispin), mo_coeff=rmos)
    1490         1284 :             CALL get_mo_set(kp%mos(2, ispin), mo_coeff=imos)
    1491         1284 :             IF (reload_snapshot_wf) THEN
    1492           16 :                CALL cp_fm_to_fm(t1_state%wf_kp(ikp, 1, ispin), rmos)
    1493           16 :                CALL cp_fm_to_fm(t1_state%wf_kp(ikp, 2, ispin), imos)
    1494              :             END IF
    1495         1284 :             IF (use_pbc_phase_ref) THEN
    1496         1276 :                ik = kp_range(1) + ikp - 1
    1497              :                CALL wfi_apply_kp_pbc_phase_fm(rmos, imos, pbc_shift_cur - pbc_shift_src, &
    1498        24980 :                                               xkp(1:3, ik), matrix_s_kp(1, 1)%matrix)
    1499              :             END IF
    1500         1284 :             CALL cp_fm_to_cfm(rmos, imos, cmos_new)
    1501              : 
    1502              :             CALL cp_cfm_gemm('N', 'N', nao, nmo, nao, z_one, &
    1503         1284 :                              csmat_cur(ikp), cmos_new, z_zero, cfm_nao_nmo_work)
    1504              :             CALL cp_cfm_gemm('C', 'N', nmo, nmo, nao, z_one, &
    1505         1284 :                              cmos_new, cfm_nao_nmo_work, z_zero, csc_cfm)
    1506              : 
    1507         1284 :             CALL cp_cfm_cholesky_decompose(csc_cfm, info_out=chol_info)
    1508         1284 :             IF (chol_info == 0) THEN
    1509         1284 :                CALL cp_cfm_triangular_multiply(csc_cfm, cmos_new, side='R', invert_tr=.TRUE., uplo_tr='U')
    1510              :             ELSE
    1511            0 :                CALL cp_cfm_gemm('C', 'N', nmo, nmo, nao, z_one, cmos_new, cfm_nao_nmo_work, z_zero, csc_cfm)
    1512            0 :                CALL cp_cfm_create(cfm_evecs, csc_cfm%matrix_struct)
    1513            0 :                CALL cp_cfm_create(cfm_mhalf, csc_cfm%matrix_struct)
    1514            0 :                CALL cp_cfm_heevd(csc_cfm, cfm_evecs, eigenvalues)
    1515            0 :                CALL cp_cfm_to_cfm(cfm_evecs, cfm_mhalf)
    1516            0 :                ALLOCATE (col_scaling(nmo))
    1517            0 :                DO j = 1, nmo
    1518            0 :                   IF (eigenvalues(j) > eval_thresh) THEN
    1519            0 :                      col_scaling(j) = CMPLX(1.0_dp/SQRT(eigenvalues(j)), 0.0_dp, KIND=dp)
    1520              :                   ELSE
    1521            0 :                      col_scaling(j) = z_zero
    1522              :                   END IF
    1523              :                END DO
    1524            0 :                CALL cp_cfm_column_scale(cfm_mhalf, col_scaling)
    1525            0 :                DEALLOCATE (col_scaling)
    1526            0 :                CALL cp_cfm_gemm('N', 'C', nmo, nmo, nmo, z_one, cfm_mhalf, cfm_evecs, z_zero, csc_cfm)
    1527            0 :                CALL cp_cfm_gemm('N', 'N', nao, nmo, nmo, z_one, cmos_new, csc_cfm, z_zero, cfm_nao_nmo_work)
    1528            0 :                CALL cp_cfm_to_cfm(cfm_nao_nmo_work, cmos_new)
    1529            0 :                CALL cp_cfm_release(cfm_evecs)
    1530            0 :                CALL cp_cfm_release(cfm_mhalf)
    1531              :             END IF
    1532         3660 :             CALL cp_cfm_to_fm(cmos_new, rmos, imos)
    1533              :          END DO
    1534              :       END DO
    1535          410 :       DEALLOCATE (eigenvalues)
    1536              : 
    1537              :       ! Phase C: Rebuild Density Matrix P(R)
    1538          410 :       CALL kpoint_set_mo_occupation(kpoints, scf_control%smear)
    1539          410 :       CALL kpoint_density_matrices(kpoints)
    1540          410 :       CALL qs_rho_get(rho, rho_ao_kp=rho_ao_kp)
    1541              :       CALL kpoint_density_transform(kpoints, rho_ao_kp, .FALSE., &
    1542          410 :                                     matrix_s_kp(1, 1)%matrix, sab_nl, scf_env%scf_work1)
    1543          410 :       CALL qs_rho_update_rho(rho, qs_env=qs_env)
    1544          410 :       CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
    1545              : 
    1546              :       ! Cleanup
    1547         1502 :       DO ikp = 1, kplocal
    1548         1502 :          CALL cp_cfm_release(csmat_cur(ikp))
    1549              :       END DO
    1550          410 :       DEALLOCATE (csmat_cur)
    1551         4154 :       DEALLOCATE (info)
    1552          410 :       CALL cp_cfm_release(cmos_new)
    1553          410 :       CALL cp_cfm_release(cfm_nao_nmo_work)
    1554          410 :       CALL cp_cfm_release(csc_cfm)
    1555          410 :       CALL fm_pool_give_back_fm(ao_ao_fm_pools_kp(1)%pool, fmlocal)
    1556          410 :       CALL dbcsr_deallocate_matrix(rmatrix)
    1557          410 :       CALL dbcsr_deallocate_matrix(cmatrix_db)
    1558          410 :       CALL dbcsr_deallocate_matrix(tmpmat)
    1559          410 :       IF (ALLOCATED(pbc_shift_cur)) DEALLOCATE (pbc_shift_cur)
    1560          410 :       IF (ALLOCATED(pbc_shift_src)) DEALLOCATE (pbc_shift_src)
    1561              : 
    1562          410 :       CALL timestop(handle)
    1563         2460 :    END SUBROUTINE wfi_use_prev_wf_kp
    1564              : 
    1565              : ! **************************************************************************************************
    1566              : !> \brief Stores the internal PBC image shift used for k-point neighbor-list construction.
    1567              : !>        shift = scaled(pbc(r))-scaled(r), i.e. the integer image displacement caused by pbc().
    1568              : !> \param snapshot ...
    1569              : !> \param cell ...
    1570              : !> \param particle_set ...
    1571              : ! **************************************************************************************************
    1572         2456 :    SUBROUTINE wfi_store_kp_pbc_shift(snapshot, cell, particle_set)
    1573              :       TYPE(qs_wf_snapshot_type), POINTER                 :: snapshot
    1574              :       TYPE(cell_type), POINTER                           :: cell
    1575              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1576              : 
    1577              :       INTEGER                                            :: iatom, natom
    1578              :       REAL(KIND=dp), DIMENSION(3)                        :: frac_pbc, frac_raw, r_pbc
    1579              : 
    1580         2456 :       CPASSERT(ASSOCIATED(snapshot))
    1581         2456 :       CPASSERT(ASSOCIATED(cell))
    1582         2456 :       CPASSERT(ASSOCIATED(particle_set))
    1583              : 
    1584         2456 :       natom = SIZE(particle_set)
    1585         2456 :       IF (ASSOCIATED(snapshot%kp_pbc_shift)) THEN
    1586          300 :          DEALLOCATE (snapshot%kp_pbc_shift)
    1587              :       END IF
    1588         7368 :       ALLOCATE (snapshot%kp_pbc_shift(3, natom))
    1589        13876 :       DO iatom = 1, natom
    1590        11420 :          r_pbc(1:3) = pbc(particle_set(iatom)%r(1:3), cell)
    1591        11420 :          CALL real_to_scaled(frac_raw, particle_set(iatom)%r(1:3), cell)
    1592        11420 :          CALL real_to_scaled(frac_pbc, r_pbc(1:3), cell)
    1593        48136 :          snapshot%kp_pbc_shift(1:3, iatom) = NINT(frac_pbc(1:3) - frac_raw(1:3))
    1594              :       END DO
    1595         2456 :    END SUBROUTINE wfi_store_kp_pbc_shift
    1596              : 
    1597              : ! **************************************************************************************************
    1598              : !> \brief Computes the current internal PBC image shift used by pbc().
    1599              : !> \param qs_env ...
    1600              : !> \param pbc_shift ...
    1601              : ! **************************************************************************************************
    1602          408 :    SUBROUTINE wfi_compute_kp_pbc_shift(qs_env, pbc_shift)
    1603              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1604              :       INTEGER, ALLOCATABLE, DIMENSION(:, :), INTENT(OUT) :: pbc_shift
    1605              : 
    1606              :       INTEGER                                            :: iatom, natom
    1607              :       REAL(KIND=dp), DIMENSION(3)                        :: frac_pbc, frac_raw, r_pbc
    1608              :       TYPE(cell_type), POINTER                           :: cell
    1609          408 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1610              : 
    1611          408 :       NULLIFY (cell, particle_set)
    1612          408 :       CALL get_qs_env(qs_env, cell=cell, particle_set=particle_set)
    1613          408 :       CPASSERT(ASSOCIATED(cell))
    1614          408 :       CPASSERT(ASSOCIATED(particle_set))
    1615              : 
    1616          408 :       natom = SIZE(particle_set)
    1617         1224 :       ALLOCATE (pbc_shift(3, natom))
    1618         3248 :       DO iatom = 1, natom
    1619         2840 :          r_pbc(1:3) = pbc(particle_set(iatom)%r(1:3), cell)
    1620         2840 :          CALL real_to_scaled(frac_raw, particle_set(iatom)%r(1:3), cell)
    1621         2840 :          CALL real_to_scaled(frac_pbc, r_pbc(1:3), cell)
    1622        11768 :          pbc_shift(1:3, iatom) = NINT(frac_pbc(1:3) - frac_raw(1:3))
    1623              :       END DO
    1624          408 :    END SUBROUTINE wfi_compute_kp_pbc_shift
    1625              : 
    1626              : ! **************************************************************************************************
    1627              : !> \brief Applies the atom-wise Bloch phase associated with a change of the internal
    1628              : !>        k-point PBC image convention to real/imaginary MO coefficient matrices.
    1629              : !> \param rmos real part of the MO coefficients
    1630              : !> \param imos imaginary part of the MO coefficients
    1631              : !> \param pbc_shift_delta target shift minus source shift for each atom
    1632              : !> \param xk fractional k-point coordinates
    1633              : !> \param matrix_template AO block structure used to map rows to atoms
    1634              : ! **************************************************************************************************
    1635         1276 :    SUBROUTINE wfi_apply_kp_pbc_phase_fm(rmos, imos, pbc_shift_delta, xk, matrix_template)
    1636              :       TYPE(cp_fm_type), POINTER                          :: rmos, imos
    1637              :       INTEGER, DIMENSION(:, :), INTENT(IN)               :: pbc_shift_delta
    1638              :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: xk
    1639              :       TYPE(dbcsr_type), POINTER                          :: matrix_template
    1640              : 
    1641              :       INTEGER                                            :: iatom, icol, irow, natom, nmo, nrow, &
    1642              :                                                             row_start
    1643         1276 :       INTEGER, DIMENSION(:), POINTER                     :: row_blk_size
    1644              :       REAL(KIND=dp)                                      :: ci, cr, i_old, r_old, theta
    1645         1276 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: iblock, rblock
    1646              : 
    1647            0 :       CPASSERT(ASSOCIATED(rmos))
    1648         1276 :       CPASSERT(ASSOCIATED(imos))
    1649         1276 :       CPASSERT(ASSOCIATED(matrix_template))
    1650              : 
    1651         1276 :       natom = SIZE(pbc_shift_delta, 2)
    1652         1276 :       CALL cp_fm_get_info(rmos, ncol_global=nmo)
    1653         1276 :       NULLIFY (row_blk_size)
    1654         1276 :       CALL dbcsr_get_info(matrix_template, row_blk_size=row_blk_size)
    1655         1276 :       CPASSERT(SIZE(row_blk_size) >= natom)
    1656              : 
    1657         1276 :       row_start = 1
    1658         7202 :       DO iatom = 1, natom
    1659         5926 :          nrow = row_blk_size(iatom)
    1660        23480 :          IF (ANY(pbc_shift_delta(1:3, iatom) /= 0)) THEN
    1661          528 :             theta = twopi*SUM(xk(1:3)*REAL(pbc_shift_delta(1:3, iatom), KIND=dp))
    1662          132 :             cr = COS(theta)
    1663          132 :             ci = SIN(theta)
    1664          792 :             ALLOCATE (rblock(nrow, nmo), iblock(nrow, nmo))
    1665          132 :             CALL cp_fm_get_submatrix(rmos, rblock, row_start, 1, nrow, nmo)
    1666          132 :             CALL cp_fm_get_submatrix(imos, iblock, row_start, 1, nrow, nmo)
    1667         4956 :             DO icol = 1, nmo
    1668        36612 :                DO irow = 1, nrow
    1669        31656 :                   r_old = rblock(irow, icol)
    1670        31656 :                   i_old = iblock(irow, icol)
    1671        31656 :                   rblock(irow, icol) = cr*r_old - ci*i_old
    1672        36480 :                   iblock(irow, icol) = ci*r_old + cr*i_old
    1673              :                END DO
    1674              :             END DO
    1675          132 :             CALL cp_fm_set_submatrix(rmos, rblock, row_start, 1, nrow, nmo)
    1676          132 :             CALL cp_fm_set_submatrix(imos, iblock, row_start, 1, nrow, nmo)
    1677          132 :             DEALLOCATE (rblock, iblock)
    1678              :          END IF
    1679         7202 :          row_start = row_start + nrow
    1680              :       END DO
    1681         2552 :    END SUBROUTINE wfi_apply_kp_pbc_phase_fm
    1682              : 
    1683              : ! **************************************************************************************************
    1684              : !> \brief Applies the atom-wise Bloch phase associated with a change of the internal
    1685              : !>        k-point PBC image convention to a complex MO coefficient matrix.
    1686              : !> \param cmos complex MO coefficients
    1687              : !> \param pbc_shift_delta target shift minus source shift for each atom
    1688              : !> \param xk fractional k-point coordinates
    1689              : !> \param matrix_template AO block structure used to map rows to atoms
    1690              : ! **************************************************************************************************
    1691         5344 :    SUBROUTINE wfi_apply_kp_pbc_phase_cfm(cmos, pbc_shift_delta, xk, matrix_template)
    1692              :       TYPE(cp_cfm_type), INTENT(INOUT)                   :: cmos
    1693              :       INTEGER, DIMENSION(:, :), INTENT(IN)               :: pbc_shift_delta
    1694              :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: xk
    1695              :       TYPE(dbcsr_type), POINTER                          :: matrix_template
    1696              : 
    1697              :       COMPLEX(KIND=dp)                                   :: phase
    1698         5344 :       COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :)     :: zblock
    1699              :       INTEGER                                            :: iatom, natom, nmo, nrow, row_start
    1700         5344 :       INTEGER, DIMENSION(:), POINTER                     :: row_blk_size
    1701              :       REAL(KIND=dp)                                      :: theta
    1702              : 
    1703            0 :       CPASSERT(ASSOCIATED(matrix_template))
    1704              : 
    1705         5344 :       natom = SIZE(pbc_shift_delta, 2)
    1706         5344 :       CALL cp_cfm_get_info(cmos, ncol_global=nmo)
    1707         5344 :       NULLIFY (row_blk_size)
    1708         5344 :       CALL dbcsr_get_info(matrix_template, row_blk_size=row_blk_size)
    1709         5344 :       CPASSERT(SIZE(row_blk_size) >= natom)
    1710              : 
    1711         5344 :       row_start = 1
    1712        37244 :       DO iatom = 1, natom
    1713        31900 :          nrow = row_blk_size(iatom)
    1714       126768 :          IF (ANY(pbc_shift_delta(1:3, iatom) /= 0)) THEN
    1715         1856 :             theta = twopi*SUM(xk(1:3)*REAL(pbc_shift_delta(1:3, iatom), KIND=dp))
    1716          464 :             phase = CMPLX(COS(theta), SIN(theta), KIND=dp)
    1717         1856 :             ALLOCATE (zblock(nrow, nmo))
    1718          464 :             CALL cp_cfm_get_submatrix(cmos, zblock, row_start, 1, nrow, nmo)
    1719       197224 :             zblock = phase*zblock
    1720          464 :             CALL cp_cfm_set_submatrix(cmos, zblock, row_start, 1, nrow, nmo)
    1721          464 :             DEALLOCATE (zblock)
    1722              :          END IF
    1723        37244 :          row_start = row_start + nrow
    1724              :       END DO
    1725        10688 :    END SUBROUTINE wfi_apply_kp_pbc_phase_cfm
    1726              : 
    1727              : ! **************************************************************************************************
    1728              : !> \brief Performs PS/ASPC wavefunction extrapolation for k-point calculations.
    1729              : !>        Applies PS/ASPC coefficients to complex MO coefficients at each k-point,
    1730              : !>        with subspace alignment via historical overlap matrices.
    1731              : !>        Delegates final orthogonalization and density building to wfi_use_prev_wf_kp.
    1732              : !> \param wf_history  wavefunction history buffer
    1733              : !> \param qs_env      QS environment
    1734              : !> \param nvec        number of history snapshots to use
    1735              : !> \param io_unit     output unit for logging
    1736              : !> \param print_level current print level
    1737              : ! **************************************************************************************************
    1738          792 :    SUBROUTINE wfi_extrapolate_ps_aspc_kp(wf_history, qs_env, nvec, io_unit, print_level)
    1739              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
    1740              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1741              :       INTEGER, INTENT(IN)                                :: nvec, io_unit, print_level
    1742              : 
    1743              :       CHARACTER(len=*), PARAMETER :: routineN = 'wfi_extrapolate_ps_aspc_kp'
    1744              : 
    1745              :       INTEGER                                            :: handle, i, ik, ikp, ispin, kplocal, &
    1746              :                                                             method_nr, nao, nmo, nspin
    1747              :       INTEGER, DIMENSION(2)                              :: kp_range
    1748              :       LOGICAL                                            :: use_real_wfn
    1749              :       REAL(KIND=dp)                                      :: alpha_coeff
    1750          396 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: xkp
    1751              :       TYPE(cp_cfm_type)                                  :: cfm_nao_nmo_work, cmos_1, cmos_i, &
    1752              :                                                             cmos_new, csc_cfm
    1753              :       TYPE(cp_fm_struct_type), POINTER                   :: nmo_nmo_struct
    1754              :       TYPE(cp_fm_type), POINTER                          :: imos, mo_coeff, rmos
    1755          396 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_s_kp
    1756              :       TYPE(kpoint_env_type), POINTER                     :: kp
    1757              :       TYPE(kpoint_type), POINTER                         :: kpoints
    1758              :       TYPE(qs_wf_snapshot_type), POINTER                 :: t0_state, t1_state
    1759              : 
    1760          396 :       method_nr = wf_history%interpolation_method_nr
    1761              : 
    1762          396 :       CALL timeset(routineN, handle)
    1763          396 :       NULLIFY (kpoints, kp, mo_coeff, rmos, imos, t0_state, t1_state, nmo_nmo_struct, &
    1764          396 :                matrix_s_kp, xkp)
    1765              : 
    1766          396 :       CALL get_qs_env(qs_env, kpoints=kpoints, matrix_s_kp=matrix_s_kp)
    1767          396 :       CALL get_kpoint_info(kpoints, use_real_wfn=use_real_wfn, kp_range=kp_range, xkp=xkp)
    1768          396 :       kplocal = kp_range(2) - kp_range(1) + 1
    1769              : 
    1770          396 :       IF (use_real_wfn) THEN
    1771            0 :          IF (method_nr == wfi_aspc_nr) THEN
    1772              :             CALL cp_warn(__LOCATION__, "ASPC with k-points requires complex wavefunctions; "// &
    1773            0 :                          "falling back to USE_PREV_WF.")
    1774              :          ELSE
    1775              :             CALL cp_warn(__LOCATION__, "PS with k-points requires complex wavefunctions; "// &
    1776            0 :                          "falling back to USE_PREV_WF.")
    1777              :          END IF
    1778            0 :          CALL wfi_use_prev_wf_kp(qs_env, io_unit, print_level)
    1779            0 :          CALL timestop(handle)
    1780            0 :          RETURN
    1781              :       END IF
    1782              : 
    1783          396 :       kp => kpoints%kp_env(1)%kpoint_env
    1784          396 :       nspin = SIZE(kp%mos, 2)
    1785          396 :       CALL get_mo_set(kp%mos(1, 1), nao=nao, nmo=nmo, mo_coeff=mo_coeff)
    1786              : 
    1787          396 :       IF (method_nr == wfi_aspc_nr) THEN
    1788          392 :          IF ((io_unit > 0) .AND. (print_level > low_print_level)) THEN
    1789              :             WRITE (UNIT=io_unit, FMT="(/,T2,A,/,T3,A,I0)") &
    1790           26 :                "Parameters for the always stable predictor-corrector (ASPC) method:", &
    1791           52 :                "ASPC order: ", MAX(nvec - 2, 0)
    1792              :          END IF
    1793              :       END IF
    1794              : 
    1795           16 :       IF (method_nr == wfi_aspc_nr) THEN
    1796          392 :          CALL cp_cfm_create(cmos_new, mo_coeff%matrix_struct, set_zero=.TRUE.)
    1797          392 :          CALL cp_cfm_create(cmos_1, mo_coeff%matrix_struct, set_zero=.TRUE.)
    1798          392 :          CALL cp_cfm_create(cmos_i, mo_coeff%matrix_struct, set_zero=.TRUE.)
    1799          392 :          CALL cp_cfm_create(cfm_nao_nmo_work, mo_coeff%matrix_struct, set_zero=.TRUE.)
    1800              :       ELSE
    1801            4 :          CALL cp_cfm_create(cmos_new, mo_coeff%matrix_struct)
    1802            4 :          CALL cp_cfm_create(cmos_1, mo_coeff%matrix_struct)
    1803            4 :          CALL cp_cfm_create(cmos_i, mo_coeff%matrix_struct)
    1804            4 :          CALL cp_cfm_create(cfm_nao_nmo_work, mo_coeff%matrix_struct)
    1805              :       END IF
    1806              : 
    1807              :       CALL cp_fm_struct_create(nmo_nmo_struct, template_fmstruct=mo_coeff%matrix_struct, &
    1808          396 :                                nrow_global=nmo, ncol_global=nmo)
    1809          396 :       IF (method_nr == wfi_aspc_nr) THEN
    1810          392 :          CALL cp_cfm_create(csc_cfm, nmo_nmo_struct, set_zero=.TRUE.)
    1811              :       ELSE
    1812            4 :          CALL cp_cfm_create(csc_cfm, nmo_nmo_struct)
    1813              :       END IF
    1814          396 :       CALL cp_fm_struct_release(nmo_nmo_struct)
    1815              : 
    1816              :       ! Phase 1: Initialize C_new(k) = B(1) * C_1(k)
    1817          396 :       t1_state => wfi_get_snapshot(wf_history, wf_index=1)
    1818          396 :       IF (method_nr == wfi_aspc_nr) THEN
    1819          392 :          alpha_coeff = REAL(4*nvec - 2, KIND=dp)/REAL(nvec + 1, KIND=dp)
    1820          392 :          IF ((io_unit > 0) .AND. (print_level > low_print_level)) THEN
    1821           26 :             WRITE (UNIT=io_unit, FMT="(T3,A2,I0,A4,F10.6)") "B(", 1, ") = ", alpha_coeff
    1822              :          END IF
    1823              :       ELSE
    1824            4 :          alpha_coeff = nvec
    1825              :       END IF
    1826              : 
    1827         1432 :       DO ikp = 1, kplocal
    1828         1036 :          kp => kpoints%kp_env(ikp)%kpoint_env
    1829         2660 :          DO ispin = 1, nspin
    1830         1228 :             CALL get_mo_set(kp%mos(1, ispin), mo_coeff=rmos)
    1831         1228 :             CALL get_mo_set(kp%mos(2, ispin), mo_coeff=imos)
    1832         1228 :             CALL cp_fm_to_fm(t1_state%wf_kp(ikp, 1, ispin), rmos)
    1833         1228 :             CALL cp_fm_to_fm(t1_state%wf_kp(ikp, 2, ispin), imos)
    1834         1228 :             CALL cp_fm_scale(alpha_coeff, rmos)
    1835         2264 :             CALL cp_fm_scale(alpha_coeff, imos)
    1836              :          END DO
    1837              :       END DO
    1838              : 
    1839              :       ! Phase 2: Accumulate historical snapshots C_new += B(i) * C_proj(k)
    1840         1708 :       DO i = 2, nvec
    1841         1312 :          t0_state => wfi_get_snapshot(wf_history, wf_index=i)
    1842         1312 :          IF (method_nr == wfi_aspc_nr) THEN
    1843              :             alpha_coeff = (-1.0_dp)**(i + 1)*REAL(i, KIND=dp)* &
    1844         1310 :                           binomial(2*nvec, nvec - i)/binomial(2*nvec - 2, nvec - 1)
    1845         1310 :             IF ((io_unit > 0) .AND. (print_level > low_print_level)) THEN
    1846           71 :                WRITE (UNIT=io_unit, FMT="(T3,A2,I0,A4,F10.6)") "B(", i, ") = ", alpha_coeff
    1847              :             END IF
    1848              :          ELSE
    1849            2 :             alpha_coeff = -1.0_dp*alpha_coeff*REAL(nvec - i + 1, dp)/REAL(i, dp)
    1850              :          END IF
    1851              : 
    1852         4236 :          DO ikp = 1, kplocal
    1853         2528 :             kp => kpoints%kp_env(ikp)%kpoint_env
    1854         6464 :             DO ispin = 1, nspin
    1855         2624 :                ik = kp_range(1) + ikp - 1
    1856         2624 :                CALL cp_fm_to_cfm(t1_state%wf_kp(ikp, 1, ispin), t1_state%wf_kp(ikp, 2, ispin), cmos_1)
    1857         2624 :                CALL cp_fm_to_cfm(t0_state%wf_kp(ikp, 1, ispin), t0_state%wf_kp(ikp, 2, ispin), cmos_i)
    1858              : 
    1859              :                ! Express the reference snapshot in the image convention of snapshot i,
    1860              :                ! because the historical overlap below belongs to snapshot i.
    1861              :                CALL wfi_apply_kp_pbc_phase_cfm(cmos_1, t0_state%kp_pbc_shift - t1_state%kp_pbc_shift, &
    1862        64888 :                                                xkp(1:3, ik), matrix_s_kp(1, 1)%matrix)
    1863              : 
    1864              :                ! Subspace projection: C_proj = C_i * (C_i^dag S_i C_1)
    1865              :                CALL cp_cfm_gemm('N', 'N', nao, nmo, nao, z_one, &
    1866         2624 :                                 t0_state%overlap_cfm_kp(ikp), cmos_1, z_zero, cfm_nao_nmo_work)
    1867              :                CALL cp_cfm_gemm('C', 'N', nmo, nmo, nao, z_one, &
    1868         2624 :                                 cmos_i, cfm_nao_nmo_work, z_zero, csc_cfm)
    1869              :                CALL cp_cfm_gemm('N', 'N', nao, nmo, nmo, z_one, &
    1870         2624 :                                 cmos_i, csc_cfm, z_zero, cfm_nao_nmo_work)
    1871              : 
    1872              :                ! Convert the projected contribution from snapshot i to the reference
    1873              :                ! image convention of snapshot 1. The final conversion to the current
    1874              :                ! convention is centralized in wfi_use_prev_wf_kp.
    1875              :                CALL wfi_apply_kp_pbc_phase_cfm(cfm_nao_nmo_work, t1_state%kp_pbc_shift - t0_state%kp_pbc_shift, &
    1876        64888 :                                                xkp(1:3, ik), matrix_s_kp(1, 1)%matrix)
    1877              : 
    1878         2624 :                CALL get_mo_set(kp%mos(1, ispin), mo_coeff=rmos)
    1879         2624 :                CALL get_mo_set(kp%mos(2, ispin), mo_coeff=imos)
    1880         2624 :                CALL cp_fm_to_cfm(rmos, imos, cmos_new)
    1881         2624 :                CALL cp_cfm_scale_and_add(z_one, cmos_new, CMPLX(alpha_coeff, 0.0_dp, KIND=dp), cfm_nao_nmo_work)
    1882         5152 :                CALL cp_cfm_to_fm(cmos_new, rmos, imos)
    1883              :             END DO
    1884              :          END DO
    1885              :       END DO
    1886              : 
    1887          396 :       CALL cp_cfm_release(cmos_new)
    1888          396 :       CALL cp_cfm_release(cmos_1)
    1889          396 :       CALL cp_cfm_release(cmos_i)
    1890          396 :       CALL cp_cfm_release(cfm_nao_nmo_work)
    1891          396 :       CALL cp_cfm_release(csc_cfm)
    1892              : 
    1893              :       ! Phase 3: Convert the extrapolated WFN from the reference snapshot image
    1894              :       ! convention to the current k-point PBC convention, then reorthogonalize and
    1895              :       ! rebuild the density. Keep the actual phase handling centralized in
    1896              :       ! wfi_use_prev_wf_kp so that USE_PREV_WF and ASPC/PS share the same path.
    1897              :       CALL wfi_use_prev_wf_kp(qs_env, 0, print_level, pbc_shift_ref=t1_state%kp_pbc_shift, &
    1898          396 :                               load_snapshot_wf=.FALSE.)
    1899              : 
    1900          396 :       CALL timestop(handle)
    1901              : 
    1902          396 :    END SUBROUTINE wfi_extrapolate_ps_aspc_kp
    1903              : 
    1904              : ! **************************************************************************************************
    1905              : !> \brief GEXT_PROJ/GEXT_PROJ_QTR wavefunction extrapolation for complex k-points.
    1906              : !>        This follows the existing ASPC/PS k-point projection path, but uses
    1907              : !>        the GEXT-fitted coefficients.
    1908              : !> \param wf_history wavefunction history buffer
    1909              : !> \param qs_env The QS environment
    1910              : !> \param nvec number of previous wavefunctions
    1911              : !> \param io_unit output unit
    1912              : !> \param print_level current print level
    1913              : ! **************************************************************************************************
    1914            8 :    SUBROUTINE wfi_extrapolate_gext_proj_kp(wf_history, qs_env, nvec, io_unit, print_level)
    1915              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
    1916              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1917              :       INTEGER, INTENT(IN)                                :: nvec, io_unit, print_level
    1918              : 
    1919              :       CHARACTER(len=*), PARAMETER :: routineN = 'wfi_extrapolate_gext_proj_kp'
    1920              : 
    1921              :       INTEGER                                            :: handle, i, igroup, ik, ikp, indx, ispin, &
    1922              :                                                             kplocal, method_nr, nao, nkp, &
    1923              :                                                             nkp_groups, nmo, nspin
    1924              :       INTEGER, DIMENSION(2)                              :: kp_range
    1925            8 :       INTEGER, DIMENSION(:, :), POINTER                  :: kp_dist
    1926            8 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
    1927              :       LOGICAL                                            :: my_kpgrp, use_real_wfn
    1928            8 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: coeffs, weight_kp
    1929            8 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: wkp
    1930            8 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: xkp
    1931            8 :       TYPE(copy_info_type), ALLOCATABLE, DIMENSION(:, :) :: info
    1932              :       TYPE(cp_cfm_type)                                  :: cfm_nao_nmo_work, cmos_1, cmos_i, &
    1933              :                                                             cmos_new, csc_cfm
    1934            8 :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:)       :: csmat_cur
    1935            8 :       TYPE(cp_fm_pool_p_type), DIMENSION(:), POINTER     :: ao_ao_fm_pools_kp
    1936              :       TYPE(cp_fm_struct_type), POINTER                   :: ao_ao_struct, nmo_nmo_struct
    1937              :       TYPE(cp_fm_type)                                   :: fmdummy, fmlocal
    1938              :       TYPE(cp_fm_type), POINTER                          :: imos, mo_coeff, rmos
    1939            8 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_s_kp
    1940              :       TYPE(dbcsr_type), POINTER                          :: cmatrix_db, rmatrix, tmpmat
    1941              :       TYPE(kpoint_env_type), POINTER                     :: kp
    1942              :       TYPE(kpoint_type), POINTER                         :: kpoints
    1943              :       TYPE(mp_para_env_type), POINTER                    :: para_env, para_env_inter_kp
    1944              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    1945            8 :          POINTER                                         :: sab_nl
    1946              :       TYPE(qs_matrix_pools_type), POINTER                :: mpools_kp
    1947              :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
    1948              :       TYPE(qs_wf_snapshot_type), POINTER                 :: t0_state, t1_state
    1949              : 
    1950            8 :       method_nr = wf_history%interpolation_method_nr
    1951              : 
    1952            8 :       CALL timeset(routineN, handle)
    1953            8 :       NULLIFY (ao_ao_struct, cell_to_index, cmatrix_db, imos, kp, kpoints, matrix_s_kp, &
    1954            8 :                mo_coeff, mpools_kp, para_env, para_env_inter_kp, rmatrix, rmos, sab_nl, &
    1955            8 :                scf_env, t0_state, t1_state, tmpmat, xkp, kp_dist, wkp, nmo_nmo_struct, &
    1956            8 :                ao_ao_fm_pools_kp)
    1957              : 
    1958            8 :       CALL get_qs_env(qs_env, kpoints=kpoints, matrix_s_kp=matrix_s_kp, scf_env=scf_env)
    1959              :       CALL get_kpoint_info(kpoints, use_real_wfn=use_real_wfn, kp_range=kp_range, &
    1960              :                            nkp=nkp, xkp=xkp, wkp=wkp, nkp_groups=nkp_groups, &
    1961              :                            kp_dist=kp_dist, cell_to_index=cell_to_index, sab_nl=sab_nl, &
    1962            8 :                            mpools=mpools_kp, para_env_inter_kp=para_env_inter_kp)
    1963            8 :       kplocal = kp_range(2) - kp_range(1) + 1
    1964              : 
    1965            8 :       IF (use_real_wfn) THEN
    1966              :          CALL cp_warn(__LOCATION__, "GExt with k-points requires complex wavefunctions; "// &
    1967            0 :                       "falling back to USE_PREV_WF.")
    1968            0 :          CALL wfi_use_prev_wf_kp(qs_env, io_unit, print_level)
    1969            0 :          CALL timestop(handle)
    1970            0 :          RETURN
    1971              :       END IF
    1972              : 
    1973            8 :       IF (nvec >= wf_history%memory_depth) THEN
    1974            0 :          IF ((qs_env%scf_control%max_scf_hist /= 0) .AND. &
    1975              :              (qs_env%scf_control%eps_scf_hist /= 0)) THEN
    1976            0 :             qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1977            0 :             qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1978            0 :             qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1979            0 :          ELSE IF (qs_env%scf_control%max_scf_hist /= 0) THEN
    1980            0 :             qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1981            0 :             qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1982            0 :          ELSE IF (qs_env%scf_control%eps_scf_hist /= 0) THEN
    1983            0 :             qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1984              :          END IF
    1985              :       END IF
    1986              : 
    1987            8 :       kp => kpoints%kp_env(1)%kpoint_env
    1988            8 :       nspin = SIZE(kp%mos, 2)
    1989            8 :       CALL get_mo_set(kp%mos(1, 1), nao=nao, nmo=nmo, mo_coeff=mo_coeff)
    1990              : 
    1991              :       ! Build the current S(k), using the same Fourier-transform pattern as
    1992              :       ! wfi_use_prev_wf_kp.  This is only needed for the GEXT coefficient fitting.
    1993            8 :       ALLOCATE (rmatrix, cmatrix_db, tmpmat)
    1994            8 :       CALL dbcsr_create(rmatrix, template=matrix_s_kp(1, 1)%matrix, matrix_type=dbcsr_type_symmetric)
    1995            8 :       CALL dbcsr_create(cmatrix_db, template=matrix_s_kp(1, 1)%matrix, matrix_type=dbcsr_type_antisymmetric)
    1996            8 :       CALL dbcsr_create(tmpmat, template=matrix_s_kp(1, 1)%matrix, matrix_type=dbcsr_type_no_symmetry)
    1997            8 :       CALL cp_dbcsr_alloc_block_from_nbl(rmatrix, sab_nl)
    1998            8 :       CALL cp_dbcsr_alloc_block_from_nbl(cmatrix_db, sab_nl)
    1999              : 
    2000            8 :       CALL mpools_get(mpools_kp, ao_ao_fm_pools=ao_ao_fm_pools_kp)
    2001            8 :       CALL fm_pool_create_fm(ao_ao_fm_pools_kp(1)%pool, fmlocal)
    2002            8 :       CALL cp_fm_get_info(fmlocal, matrix_struct=ao_ao_struct)
    2003              : 
    2004            8 :       para_env => kpoints%blacs_env_all%para_env
    2005          152 :       ALLOCATE (info(kplocal*nkp_groups, 2))
    2006           72 :       ALLOCATE (csmat_cur(kplocal), weight_kp(kplocal))
    2007           40 :       DO ikp = 1, kplocal
    2008           32 :          CALL cp_cfm_create(csmat_cur(ikp), ao_ao_struct)
    2009           40 :          weight_kp(ikp) = wkp(kp_range(1) + ikp - 1)
    2010              :       END DO
    2011              : 
    2012              :       indx = 0
    2013           40 :       DO ikp = 1, kplocal
    2014           72 :          DO igroup = 1, nkp_groups
    2015           32 :             ik = kp_dist(1, igroup) + ikp - 1
    2016           32 :             my_kpgrp = (ik >= kp_range(1) .AND. ik <= kp_range(2))
    2017           32 :             indx = indx + 1
    2018              : 
    2019           32 :             CALL dbcsr_set(rmatrix, 0.0_dp)
    2020           32 :             CALL dbcsr_set(cmatrix_db, 0.0_dp)
    2021              :             CALL rskp_transform(rmatrix=rmatrix, cmatrix=cmatrix_db, rsmat=matrix_s_kp, &
    2022           32 :                                 ispin=1, xkp=xkp(1:3, ik), cell_to_index=cell_to_index, sab_nl=sab_nl)
    2023           32 :             CALL dbcsr_desymmetrize(rmatrix, tmpmat)
    2024           32 :             CALL copy_dbcsr_to_fm(tmpmat, scf_env%scf_work1(1))
    2025           32 :             CALL dbcsr_desymmetrize(cmatrix_db, tmpmat)
    2026           32 :             CALL copy_dbcsr_to_fm(tmpmat, scf_env%scf_work1(2))
    2027              : 
    2028           64 :             IF (my_kpgrp) THEN
    2029           32 :                CALL cp_fm_start_copy_general(scf_env%scf_work1(1), fmlocal, para_env, info(indx, 1))
    2030           32 :                CALL cp_fm_start_copy_general(scf_env%scf_work1(2), fmlocal, para_env, info(indx, 2))
    2031              :             ELSE
    2032            0 :                CALL cp_fm_start_copy_general(scf_env%scf_work1(1), fmdummy, para_env, info(indx, 1))
    2033            0 :                CALL cp_fm_start_copy_general(scf_env%scf_work1(2), fmdummy, para_env, info(indx, 2))
    2034              :             END IF
    2035              :          END DO
    2036              :       END DO
    2037              : 
    2038              :       indx = 0
    2039           40 :       DO ikp = 1, kplocal
    2040           72 :          DO igroup = 1, nkp_groups
    2041           32 :             ik = kp_dist(1, igroup) + ikp - 1
    2042           32 :             my_kpgrp = (ik >= kp_range(1) .AND. ik <= kp_range(2))
    2043            0 :             indx = indx + 1
    2044           32 :             IF (my_kpgrp) THEN
    2045           32 :                CALL cp_fm_finish_copy_general(fmlocal, info(indx, 1))
    2046           32 :                CALL cp_cfm_scale_and_add_fm(z_zero, csmat_cur(ikp), z_one, fmlocal)
    2047           32 :                CALL cp_fm_finish_copy_general(fmlocal, info(indx, 2))
    2048           32 :                CALL cp_cfm_scale_and_add_fm(z_one, csmat_cur(ikp), gaussi, fmlocal)
    2049              :             END IF
    2050              :          END DO
    2051              :       END DO
    2052              : 
    2053           40 :       DO indx = 1, kplocal*nkp_groups
    2054           32 :          CALL cp_fm_cleanup_copy_general(info(indx, 1))
    2055           40 :          CALL cp_fm_cleanup_copy_general(info(indx, 2))
    2056              :       END DO
    2057              : 
    2058           24 :       ALLOCATE (coeffs(nvec))
    2059            8 :       IF (method_nr == wfi_gext_proj_nr) THEN
    2060              :          CALL diff_fitting(wf_history, matrix_s_kp(1, 1)%matrix, coeffs, nvec, &
    2061              :                            1e-4_dp, io_unit, print_level, current_overlap_kp=csmat_cur, &
    2062            4 :                            kpoint_weights=weight_kp, para_env_inter_kp=para_env_inter_kp)
    2063              :       ELSE
    2064              :          CALL tr_fitting(wf_history, matrix_s_kp(1, 1)%matrix, coeffs, nvec, &
    2065              :                          1e-4_dp, io_unit, print_level, current_overlap_kp=csmat_cur, &
    2066            4 :                          kpoint_weights=weight_kp, para_env_inter_kp=para_env_inter_kp)
    2067              :       END IF
    2068              : 
    2069              :       ! Accumulate the extrapolated WFN using the same projected-WFN path as ASPC/PS.
    2070            8 :       CALL cp_cfm_create(cmos_new, mo_coeff%matrix_struct)
    2071            8 :       CALL cp_cfm_create(cmos_1, mo_coeff%matrix_struct)
    2072            8 :       CALL cp_cfm_create(cmos_i, mo_coeff%matrix_struct)
    2073            8 :       CALL cp_cfm_create(cfm_nao_nmo_work, mo_coeff%matrix_struct)
    2074              :       CALL cp_fm_struct_create(nmo_nmo_struct, template_fmstruct=mo_coeff%matrix_struct, &
    2075            8 :                                nrow_global=nmo, ncol_global=nmo)
    2076            8 :       CALL cp_cfm_create(csc_cfm, nmo_nmo_struct)
    2077            8 :       CALL cp_fm_struct_release(nmo_nmo_struct)
    2078              : 
    2079            8 :       t1_state => wfi_get_snapshot(wf_history, wf_index=1)
    2080           40 :       DO ikp = 1, kplocal
    2081           32 :          kp => kpoints%kp_env(ikp)%kpoint_env
    2082           72 :          DO ispin = 1, nspin
    2083           32 :             CALL get_mo_set(kp%mos(1, ispin), mo_coeff=rmos)
    2084           32 :             CALL get_mo_set(kp%mos(2, ispin), mo_coeff=imos)
    2085           32 :             CALL cp_fm_set_all(rmos, 0.0_dp)
    2086           64 :             CALL cp_fm_set_all(imos, 0.0_dp)
    2087              :          END DO
    2088              :       END DO
    2089              : 
    2090           20 :       DO i = 1, nvec
    2091           12 :          t0_state => wfi_get_snapshot(wf_history, wf_index=i)
    2092           68 :          DO ikp = 1, kplocal
    2093           48 :             kp => kpoints%kp_env(ikp)%kpoint_env
    2094           48 :             ik = kp_range(1) + ikp - 1
    2095          108 :             DO ispin = 1, nspin
    2096           48 :                CALL cp_fm_to_cfm(t1_state%wf_kp(ikp, 1, ispin), t1_state%wf_kp(ikp, 2, ispin), cmos_1)
    2097           48 :                CALL cp_fm_to_cfm(t0_state%wf_kp(ikp, 1, ispin), t0_state%wf_kp(ikp, 2, ispin), cmos_i)
    2098              : 
    2099              :                CALL wfi_apply_kp_pbc_phase_cfm(cmos_1, t0_state%kp_pbc_shift - t1_state%kp_pbc_shift, &
    2100         1584 :                                                xkp(1:3, ik), matrix_s_kp(1, 1)%matrix)
    2101              : 
    2102              :                CALL cp_cfm_gemm('N', 'N', nao, nmo, nao, z_one, &
    2103           48 :                                 t0_state%overlap_cfm_kp(ikp), cmos_1, z_zero, cfm_nao_nmo_work)
    2104              :                CALL cp_cfm_gemm('C', 'N', nmo, nmo, nao, z_one, &
    2105           48 :                                 cmos_i, cfm_nao_nmo_work, z_zero, csc_cfm)
    2106              :                CALL cp_cfm_gemm('N', 'N', nao, nmo, nmo, z_one, &
    2107           48 :                                 cmos_i, csc_cfm, z_zero, cfm_nao_nmo_work)
    2108              : 
    2109              :                CALL wfi_apply_kp_pbc_phase_cfm(cfm_nao_nmo_work, t1_state%kp_pbc_shift - t0_state%kp_pbc_shift, &
    2110         1584 :                                                xkp(1:3, ik), matrix_s_kp(1, 1)%matrix)
    2111              : 
    2112           48 :                CALL get_mo_set(kp%mos(1, ispin), mo_coeff=rmos)
    2113           48 :                CALL get_mo_set(kp%mos(2, ispin), mo_coeff=imos)
    2114           48 :                CALL cp_fm_to_cfm(rmos, imos, cmos_new)
    2115           48 :                CALL cp_cfm_scale_and_add(z_one, cmos_new, CMPLX(coeffs(i), 0.0_dp, KIND=dp), cfm_nao_nmo_work)
    2116           96 :                CALL cp_cfm_to_fm(cmos_new, rmos, imos)
    2117              :             END DO
    2118              :          END DO
    2119              :       END DO
    2120              : 
    2121            8 :       CALL cp_cfm_release(cmos_new)
    2122            8 :       CALL cp_cfm_release(cmos_1)
    2123            8 :       CALL cp_cfm_release(cmos_i)
    2124            8 :       CALL cp_cfm_release(cfm_nao_nmo_work)
    2125            8 :       CALL cp_cfm_release(csc_cfm)
    2126              : 
    2127              :       CALL wfi_use_prev_wf_kp(qs_env, 0, print_level, pbc_shift_ref=t1_state%kp_pbc_shift, &
    2128            8 :                               load_snapshot_wf=.FALSE.)
    2129              : 
    2130           40 :       DO ikp = 1, kplocal
    2131           40 :          CALL cp_cfm_release(csmat_cur(ikp))
    2132              :       END DO
    2133           72 :       DEALLOCATE (csmat_cur, coeffs, weight_kp, info)
    2134            8 :       CALL fm_pool_give_back_fm(ao_ao_fm_pools_kp(1)%pool, fmlocal)
    2135            8 :       CALL dbcsr_deallocate_matrix(rmatrix)
    2136            8 :       CALL dbcsr_deallocate_matrix(cmatrix_db)
    2137            8 :       CALL dbcsr_deallocate_matrix(tmpmat)
    2138              : 
    2139            8 :       CALL timestop(handle)
    2140              : 
    2141           48 :    END SUBROUTINE wfi_extrapolate_gext_proj_kp
    2142              : 
    2143              : ! **************************************************************************************************
    2144              : !> \brief Decides if scf control variables has to changed due
    2145              : !>      to using a WF extrapolation.
    2146              : !> \param qs_env The QS environment
    2147              : !> \param nvec ...
    2148              : !> \par History
    2149              : !>      11.2006 created [TdK]
    2150              : !> \author Thomas D. Kuehne (tkuehne@phys.chem.ethz.ch)
    2151              : ! **************************************************************************************************
    2152        10285 :    ELEMENTAL SUBROUTINE wfi_set_history_variables(qs_env, nvec)
    2153              :       TYPE(qs_environment_type), INTENT(INOUT)           :: qs_env
    2154              :       INTEGER, INTENT(IN)                                :: nvec
    2155              : 
    2156        10285 :       IF (nvec >= qs_env%wf_history%memory_depth) THEN
    2157         1567 :          IF ((qs_env%scf_control%max_scf_hist /= 0) .AND. (qs_env%scf_control%eps_scf_hist /= 0)) THEN
    2158            0 :             qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    2159            0 :             qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    2160            0 :             qs_env%scf_control%outer_scf%have_scf = .FALSE.
    2161         1567 :          ELSE IF (qs_env%scf_control%max_scf_hist /= 0) THEN
    2162            0 :             qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    2163            0 :             qs_env%scf_control%outer_scf%have_scf = .FALSE.
    2164         1567 :          ELSE IF (qs_env%scf_control%eps_scf_hist /= 0) THEN
    2165            0 :             qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    2166            0 :             qs_env%scf_control%outer_scf%eps_scf = qs_env%scf_control%eps_scf_hist
    2167              :          END IF
    2168              :       END IF
    2169              : 
    2170        10285 :    END SUBROUTINE wfi_set_history_variables
    2171              : 
    2172              : ! **************************************************************************************************
    2173              : !> \brief updates the snapshot buffer, taking a new snapshot
    2174              : !> \param wf_history the history buffer to update
    2175              : !> \param qs_env the qs_env we get the info from
    2176              : !> \param dt ...
    2177              : !> \par History
    2178              : !>      02.2003 created [fawzi]
    2179              : !> \author fawzi
    2180              : ! **************************************************************************************************
    2181        25267 :    SUBROUTINE wfi_update(wf_history, qs_env, dt)
    2182              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
    2183              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2184              :       REAL(KIND=dp), INTENT(in)                          :: dt
    2185              : 
    2186        25267 :       CPASSERT(ASSOCIATED(wf_history))
    2187        25267 :       CPASSERT(wf_history%ref_count > 0)
    2188        25267 :       CPASSERT(ASSOCIATED(qs_env))
    2189              : 
    2190        25267 :       wf_history%snapshot_count = wf_history%snapshot_count + 1
    2191        25267 :       IF (wf_history%memory_depth > 0) THEN
    2192              :          wf_history%last_state_index = MODULO(wf_history%snapshot_count, &
    2193        24206 :                                               wf_history%memory_depth) + 1
    2194              :          CALL wfs_update(snapshot=wf_history%past_states &
    2195              :                          (wf_history%last_state_index)%snapshot, wf_history=wf_history, &
    2196        24206 :                          qs_env=qs_env, dt=dt)
    2197              :       END IF
    2198        25267 :    END SUBROUTINE wfi_update
    2199              : 
    2200              : ! **************************************************************************************************
    2201              : !> \brief reorthogonalizes the mos
    2202              : !> \param qs_env the qs_env in which to orthogonalize
    2203              : !> \param v_matrix the vectors to orthogonalize
    2204              : !> \param n_col number of column of v to orthogonalize
    2205              : !> \par History
    2206              : !>      04.2003 created [fawzi]
    2207              : !> \author Fawzi Mohamed
    2208              : ! **************************************************************************************************
    2209        32614 :    SUBROUTINE reorthogonalize_vectors(qs_env, v_matrix, n_col)
    2210              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2211              :       TYPE(cp_fm_type), INTENT(IN)                       :: v_matrix
    2212              :       INTEGER, INTENT(in), OPTIONAL                      :: n_col
    2213              : 
    2214              :       CHARACTER(len=*), PARAMETER :: routineN = 'reorthogonalize_vectors'
    2215              : 
    2216              :       INTEGER                                            :: handle, my_n_col
    2217              :       LOGICAL                                            :: has_unit_metric, &
    2218              :                                                             ortho_contains_cholesky, &
    2219              :                                                             smearing_is_used
    2220              :       TYPE(cp_fm_pool_type), POINTER                     :: maxao_maxmo_fm_pool
    2221        16307 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
    2222              :       TYPE(dft_control_type), POINTER                    :: dft_control
    2223              :       TYPE(qs_matrix_pools_type), POINTER                :: mpools
    2224              :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
    2225              :       TYPE(scf_control_type), POINTER                    :: scf_control
    2226              : 
    2227        16307 :       NULLIFY (scf_env, scf_control, maxao_maxmo_fm_pool, matrix_s, mpools, dft_control)
    2228        16307 :       CALL timeset(routineN, handle)
    2229              : 
    2230        16307 :       CPASSERT(ASSOCIATED(qs_env))
    2231              : 
    2232        16307 :       CALL cp_fm_get_info(v_matrix, ncol_global=my_n_col)
    2233        16307 :       IF (PRESENT(n_col)) my_n_col = n_col
    2234              :       CALL get_qs_env(qs_env, mpools=mpools, &
    2235              :                       scf_env=scf_env, &
    2236              :                       scf_control=scf_control, &
    2237              :                       matrix_s=matrix_s, &
    2238        16307 :                       dft_control=dft_control)
    2239        16307 :       CALL mpools_get(mpools, maxao_maxmo_fm_pool=maxao_maxmo_fm_pool)
    2240        16307 :       IF (ASSOCIATED(scf_env)) THEN
    2241              :          ortho_contains_cholesky = (scf_env%method /= ot_method_nr) .AND. &
    2242              :                                    (scf_env%cholesky_method > 0) .AND. &
    2243        16307 :                                    ASSOCIATED(scf_env%ortho)
    2244              :       ELSE
    2245              :          ortho_contains_cholesky = .FALSE.
    2246              :       END IF
    2247              : 
    2248        16307 :       CALL get_qs_env(qs_env, has_unit_metric=has_unit_metric)
    2249        16307 :       smearing_is_used = .FALSE.
    2250        16307 :       IF (dft_control%smear) THEN
    2251         1742 :          smearing_is_used = .TRUE.
    2252              :       END IF
    2253              : 
    2254        16307 :       IF (has_unit_metric) THEN
    2255         3410 :          CALL make_basis_simple(v_matrix, my_n_col)
    2256        12897 :       ELSE IF (smearing_is_used) THEN
    2257              :          CALL make_basis_lowdin(vmatrix=v_matrix, ncol=my_n_col, &
    2258         1742 :                                 matrix_s=matrix_s(1)%matrix)
    2259        11155 :       ELSE IF (ortho_contains_cholesky) THEN
    2260              :          CALL make_basis_cholesky(vmatrix=v_matrix, ncol=my_n_col, &
    2261         7774 :                                   ortho=scf_env%ortho)
    2262              :       ELSE
    2263         3381 :          CALL make_basis_sm(v_matrix, my_n_col, matrix_s(1)%matrix)
    2264              :       END IF
    2265        16307 :       CALL timestop(handle)
    2266        16307 :    END SUBROUTINE reorthogonalize_vectors
    2267              : 
    2268              : ! **************************************************************************************************
    2269              : !> \brief purges wf_history retaining only the latest snapshot
    2270              : !> \param qs_env the qs env with the latest result, and that will contain
    2271              : !>        the purged wf_history
    2272              : !> \par History
    2273              : !>      05.2016 created [Nico Holmberg]
    2274              : !> \author Nico Holmberg
    2275              : ! **************************************************************************************************
    2276            0 :    SUBROUTINE wfi_purge_history(qs_env)
    2277              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2278              : 
    2279              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'wfi_purge_history'
    2280              : 
    2281              :       INTEGER                                            :: handle, io_unit, print_level
    2282              :       TYPE(cp_logger_type), POINTER                      :: logger
    2283              :       TYPE(dft_control_type), POINTER                    :: dft_control
    2284              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
    2285              : 
    2286            0 :       NULLIFY (dft_control, wf_history)
    2287              : 
    2288            0 :       CALL timeset(routineN, handle)
    2289            0 :       logger => cp_get_default_logger()
    2290            0 :       print_level = logger%iter_info%print_level
    2291              :       io_unit = cp_print_key_unit_nr(logger, qs_env%input, "DFT%SCF%PRINT%PROGRAM_RUN_INFO", &
    2292            0 :                                      extension=".scfLog")
    2293              : 
    2294            0 :       CPASSERT(ASSOCIATED(qs_env))
    2295            0 :       CPASSERT(ASSOCIATED(qs_env%wf_history))
    2296            0 :       CPASSERT(qs_env%wf_history%ref_count > 0)
    2297            0 :       CALL get_qs_env(qs_env, dft_control=dft_control)
    2298              : 
    2299            0 :       SELECT CASE (qs_env%wf_history%interpolation_method_nr)
    2300              :       CASE (wfi_use_guess_method_nr, wfi_use_prev_wf_method_nr, &
    2301              :             wfi_use_prev_p_method_nr, wfi_use_prev_rho_r_method_nr, &
    2302              :             wfi_frozen_method_nr)
    2303              :          ! do nothing
    2304              :       CASE (wfi_linear_wf_method_nr, wfi_linear_p_method_nr, &
    2305              :             wfi_linear_ps_method_nr, wfi_ps_method_nr, &
    2306              :             wfi_aspc_nr, wfi_gext_proj_nr, wfi_gext_proj_qtr_nr)
    2307            0 :          IF (qs_env%wf_history%snapshot_count >= 2) THEN
    2308            0 :             IF (debug_this_module .AND. io_unit > 0) &
    2309            0 :                WRITE (io_unit, FMT="(T2,A)") "QS| Purging WFN history"
    2310              :             CALL wfi_create(wf_history, interpolation_method_nr= &
    2311              :                             dft_control%qs_control%wf_interpolation_method_nr, &
    2312              :                             extrapolation_order=dft_control%qs_control%wf_extrapolation_order, &
    2313            0 :                             has_unit_metric=qs_env%has_unit_metric)
    2314              :             CALL set_qs_env(qs_env=qs_env, &
    2315            0 :                             wf_history=wf_history)
    2316            0 :             CALL wfi_release(wf_history)
    2317            0 :             CALL wfi_update(qs_env%wf_history, qs_env=qs_env, dt=1.0_dp)
    2318              :          END IF
    2319              :       CASE DEFAULT
    2320            0 :          CPABORT("Unknown extrapolation method.")
    2321              :       END SELECT
    2322            0 :       CALL timestop(handle)
    2323              : 
    2324            0 :    END SUBROUTINE wfi_purge_history
    2325              : 
    2326              : ! **************************************************************************************************
    2327              : !> \brief Gives the coefficients that best approximate the new overlap
    2328              : !>        as a linear combination of the previous overlaps in the
    2329              : !>        wf_history buffer. This is done by solving
    2330              : !>        argmin_a || S_{n+1} - S_{n} - \sum_i^{nvec-1} a_i (S_{n-q+i} - S_{n}) ||^2
    2331              : !> \param wf_history wavefunction history buffer, containing the previous overlaps
    2332              : !> \param current_overlap current overlap in dbcsr format
    2333              : !> \param coeffs resulting nvec coefficients
    2334              : !> \param nvec number of previous overlaps
    2335              : !> \param eps Tikhonov regularization
    2336              : !> \param io_unit output unit
    2337              : !> \param print_level print level
    2338              : !> \param current_overlap_kp ...
    2339              : !> \param kpoint_weights ...
    2340              : !> \param para_env_inter_kp ...
    2341              : !> \par History
    2342              : !>      04.2026 created [Michele Nottoli]
    2343              : !> \author Michele Nottoli
    2344              : ! **************************************************************************************************
    2345          140 :    SUBROUTINE diff_fitting(wf_history, current_overlap, coeffs, nvec, eps, io_unit, print_level, &
    2346          140 :                            current_overlap_kp, kpoint_weights, para_env_inter_kp)
    2347              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
    2348              :       TYPE(dbcsr_type), INTENT(IN)                       :: current_overlap
    2349              :       INTEGER, INTENT(IN)                                :: nvec
    2350              :       REAL(KIND=dp), INTENT(OUT)                         :: coeffs(nvec)
    2351              :       REAL(KIND=dp), INTENT(IN)                          :: eps
    2352              :       INTEGER, INTENT(IN)                                :: io_unit, print_level
    2353              :       TYPE(cp_cfm_type), DIMENSION(:), INTENT(IN), &
    2354              :          OPTIONAL                                        :: current_overlap_kp
    2355              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL  :: kpoint_weights
    2356              :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env_inter_kp
    2357              : 
    2358              :       COMPLEX(KIND=dp)                                   :: ztrace
    2359              :       INTEGER                                            :: i, icol_local, ikp, info, irow_local, j
    2360              :       REAL(KIND=dp)                                      :: error, norm_ref, weight
    2361          140 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: b
    2362          140 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: A
    2363              :       TYPE(cp_cfm_type)                                  :: target_diff_cfm, tmp_conj_cfm, &
    2364              :                                                             tmp_i_cfm, tmp_j_cfm
    2365              :       TYPE(dbcsr_type)                                   :: target_diff, tmp_i, tmp_j, tmp_k
    2366              :       TYPE(qs_wf_snapshot_type), POINTER                 :: ref_state, state
    2367              : 
    2368          140 :       IF (nvec <= 0) THEN
    2369            0 :          CPABORT("Not enough vectors to do the fitting")
    2370          140 :       ELSE IF (nvec == 1) THEN
    2371           22 :          coeffs(1) = 1.0_dp
    2372           70 :          RETURN
    2373              :       END IF
    2374              : 
    2375          118 :       IF (PRESENT(current_overlap_kp)) THEN
    2376           12 :          ALLOCATE (A(nvec - 1, nvec - 1), b(nvec - 1))
    2377            2 :          A = 0.0_dp
    2378            2 :          b = 0.0_dp
    2379              : 
    2380            2 :          ref_state => wfi_get_snapshot(wf_history, wf_index=1)
    2381            2 :          CALL cp_cfm_create(target_diff_cfm, current_overlap_kp(1)%matrix_struct)
    2382            2 :          CALL cp_cfm_create(tmp_i_cfm, current_overlap_kp(1)%matrix_struct)
    2383            2 :          CALL cp_cfm_create(tmp_j_cfm, current_overlap_kp(1)%matrix_struct)
    2384            2 :          CALL cp_cfm_create(tmp_conj_cfm, current_overlap_kp(1)%matrix_struct)
    2385              : 
    2386           10 :          DO ikp = 1, SIZE(current_overlap_kp)
    2387            8 :             weight = 1.0_dp
    2388            8 :             IF (PRESENT(kpoint_weights)) weight = kpoint_weights(ikp)
    2389              : 
    2390            8 :             CALL cp_cfm_to_cfm(current_overlap_kp(ikp), target_diff_cfm)
    2391              :             CALL cp_cfm_scale_and_add(z_one, target_diff_cfm, CMPLX(-1.0_dp, 0.0_dp, KIND=dp), &
    2392            8 :                                       ref_state%overlap_cfm_kp(ikp))
    2393           18 :             DO i = 2, nvec
    2394            8 :                state => wfi_get_snapshot(wf_history, wf_index=i)
    2395            8 :                CALL cp_cfm_to_cfm(state%overlap_cfm_kp(ikp), tmp_i_cfm)
    2396              :                CALL cp_cfm_scale_and_add(z_one, tmp_i_cfm, CMPLX(-1.0_dp, 0.0_dp, KIND=dp), &
    2397            8 :                                          ref_state%overlap_cfm_kp(ikp))
    2398            8 :                CALL cp_cfm_to_cfm(tmp_i_cfm, tmp_conj_cfm)
    2399          264 :                DO icol_local = 1, SIZE(tmp_conj_cfm%local_data, 2)
    2400         4360 :                   DO irow_local = 1, SIZE(tmp_conj_cfm%local_data, 1)
    2401              :                      tmp_conj_cfm%local_data(irow_local, icol_local) = &
    2402         4352 :                         CONJG(tmp_conj_cfm%local_data(irow_local, icol_local))
    2403              :                   END DO
    2404              :                END DO
    2405            8 :                CALL cp_cfm_trace(tmp_conj_cfm, target_diff_cfm, ztrace)
    2406            8 :                b(i - 1) = b(i - 1) + weight*REAL(ztrace, KIND=dp)
    2407              : 
    2408           24 :                DO j = 2, i
    2409            8 :                   state => wfi_get_snapshot(wf_history, wf_index=j)
    2410            8 :                   CALL cp_cfm_to_cfm(state%overlap_cfm_kp(ikp), tmp_j_cfm)
    2411              :                   CALL cp_cfm_scale_and_add(z_one, tmp_j_cfm, CMPLX(-1.0_dp, 0.0_dp, KIND=dp), &
    2412            8 :                                             ref_state%overlap_cfm_kp(ikp))
    2413            8 :                   CALL cp_cfm_trace(tmp_conj_cfm, tmp_j_cfm, ztrace)
    2414           16 :                   A(j - 1, i - 1) = A(j - 1, i - 1) + weight*REAL(ztrace, KIND=dp)
    2415              :                END DO
    2416              :             END DO
    2417              :          END DO
    2418              : 
    2419            4 :          DO i = 2, nvec
    2420            6 :             DO j = 2, i
    2421            4 :                A(i - 1, j - 1) = A(j - 1, i - 1)
    2422              :             END DO
    2423              :          END DO
    2424              : 
    2425            2 :          IF (PRESENT(para_env_inter_kp)) THEN
    2426            2 :             IF (ASSOCIATED(para_env_inter_kp)) THEN
    2427            2 :                CALL para_env_inter_kp%sum(A)
    2428            2 :                CALL para_env_inter_kp%sum(b)
    2429              :             END IF
    2430              :          END IF
    2431              : 
    2432            4 :          DO i = 1, nvec - 1
    2433            4 :             A(i, i) = A(i, i) + eps**2
    2434              :          END DO
    2435              : 
    2436            2 :          CALL dposv('u', nvec - 1, 1, A, nvec - 1, b, nvec - 1, info)
    2437            2 :          IF (info /= 0) THEN
    2438            0 :             CPABORT("DPOSV failed.")
    2439              :          END IF
    2440              : 
    2441            4 :          coeffs(1) = 1.0_dp - SUM(b)
    2442            4 :          coeffs(2:nvec) = b(:)
    2443              : 
    2444            2 :          IF (print_level > low_print_level) THEN
    2445            2 :             error = 0.0_dp
    2446            2 :             norm_ref = 0.0_dp
    2447           10 :             DO ikp = 1, SIZE(current_overlap_kp)
    2448            8 :                weight = 1.0_dp
    2449            8 :                IF (PRESENT(kpoint_weights)) weight = kpoint_weights(ikp)
    2450            8 :                CALL cp_cfm_to_cfm(current_overlap_kp(ikp), tmp_i_cfm)
    2451           24 :                DO i = 1, nvec
    2452           16 :                   state => wfi_get_snapshot(wf_history, wf_index=i)
    2453              :                   CALL cp_cfm_scale_and_add(z_one, tmp_i_cfm, CMPLX(-coeffs(i), 0.0_dp, KIND=dp), &
    2454           24 :                                             state%overlap_cfm_kp(ikp))
    2455              :                END DO
    2456            8 :                CALL cp_cfm_to_cfm(tmp_i_cfm, tmp_conj_cfm)
    2457          264 :                DO icol_local = 1, SIZE(tmp_conj_cfm%local_data, 2)
    2458         4360 :                   DO irow_local = 1, SIZE(tmp_conj_cfm%local_data, 1)
    2459              :                      tmp_conj_cfm%local_data(irow_local, icol_local) = &
    2460         4352 :                         CONJG(tmp_conj_cfm%local_data(irow_local, icol_local))
    2461              :                   END DO
    2462              :                END DO
    2463            8 :                CALL cp_cfm_trace(tmp_conj_cfm, tmp_i_cfm, ztrace)
    2464            8 :                error = error + weight*REAL(ztrace, KIND=dp)
    2465            8 :                CALL cp_cfm_to_cfm(ref_state%overlap_cfm_kp(ikp), tmp_conj_cfm)
    2466          264 :                DO icol_local = 1, SIZE(tmp_conj_cfm%local_data, 2)
    2467         4360 :                   DO irow_local = 1, SIZE(tmp_conj_cfm%local_data, 1)
    2468              :                      tmp_conj_cfm%local_data(irow_local, icol_local) = &
    2469         4352 :                         CONJG(tmp_conj_cfm%local_data(irow_local, icol_local))
    2470              :                   END DO
    2471              :                END DO
    2472            8 :                CALL cp_cfm_trace(tmp_conj_cfm, ref_state%overlap_cfm_kp(ikp), ztrace)
    2473           18 :                norm_ref = norm_ref + weight*REAL(ztrace, KIND=dp)
    2474              :             END DO
    2475            2 :             IF (PRESENT(para_env_inter_kp)) THEN
    2476            2 :                IF (ASSOCIATED(para_env_inter_kp)) THEN
    2477            2 :                   CALL para_env_inter_kp%sum(error)
    2478            2 :                   CALL para_env_inter_kp%sum(norm_ref)
    2479              :                END IF
    2480              :             END IF
    2481            2 :             IF (io_unit > 0) THEN
    2482            1 :                WRITE (UNIT=io_unit, FMT="(/,T2,A,F20.10)") "GEXT overlap fitting error:", &
    2483            2 :                   SQRT(error/MAX(norm_ref, TINY(1.0_dp)))
    2484              :             END IF
    2485              :          END IF
    2486              : 
    2487            2 :          CALL cp_cfm_release(target_diff_cfm)
    2488            2 :          CALL cp_cfm_release(tmp_i_cfm)
    2489            2 :          CALL cp_cfm_release(tmp_j_cfm)
    2490            2 :          CALL cp_cfm_release(tmp_conj_cfm)
    2491            2 :          DEALLOCATE (A, b)
    2492            2 :          RETURN
    2493              :       END IF
    2494              : 
    2495          696 :       ALLOCATE (A(nvec - 1, nvec - 1), b(nvec - 1))
    2496              : 
    2497              :       ! get the reference for the difference fitting
    2498          116 :       ref_state => wfi_get_snapshot(wf_history, wf_index=1)
    2499              : 
    2500              :       ! assemble the target difference
    2501          116 :       CALL dbcsr_copy(target_diff, current_overlap)
    2502          116 :       CALL dbcsr_add(target_diff, ref_state%overlap, 1.0_dp, -1.0_dp)
    2503              : 
    2504              :       ! allocate tmp_k
    2505          116 :       CALL dbcsr_copy(tmp_k, current_overlap)
    2506              : 
    2507              :       ! assemble the matrix A and the RHS b
    2508          348 :       DO i = 2, nvec
    2509          232 :          state => wfi_get_snapshot(wf_history, wf_index=i)
    2510          232 :          CALL dbcsr_copy(tmp_i, state%overlap)
    2511          232 :          CALL dbcsr_add(tmp_i, ref_state%overlap, 1.0_dp, -1.0_dp)
    2512          232 :          CALL dbcsr_multiply("N", "N", 1.0_dp, tmp_i, target_diff, 0.0_dp, tmp_k)
    2513          232 :          CALL dbcsr_trace(tmp_k, b(i - 1))
    2514              : 
    2515          724 :          DO j = 2, i
    2516          376 :             state => wfi_get_snapshot(wf_history, wf_index=j)
    2517          376 :             CALL dbcsr_copy(tmp_j, state%overlap)
    2518          376 :             CALL dbcsr_add(tmp_j, ref_state%overlap, 1.0_dp, -1.0_dp)
    2519          376 :             CALL dbcsr_multiply("N", "N", 1.0_dp, tmp_i, tmp_j, 0.0_dp, tmp_k)
    2520          376 :             CALL dbcsr_trace(tmp_k, A(j - 1, i - 1))
    2521          608 :             A(i - 1, j - 1) = A(j - 1, i - 1)
    2522              :          END DO
    2523              :       END DO
    2524              : 
    2525              :       ! add the Tikhonov regularization
    2526          348 :       DO i = 1, nvec - 1
    2527          348 :          A(i, i) = A(i, i) + eps**2
    2528              :       END DO
    2529              : 
    2530              :       ! solve the linear system
    2531          116 :       CALL dposv('u', nvec - 1, 1, A, nvec - 1, b, nvec - 1, info)
    2532          116 :       IF (info /= 0) THEN
    2533            0 :          CPABORT("DPOSV failed.")
    2534              :       END IF
    2535              : 
    2536              :       ! set the coefficient for the reference snapshot
    2537          348 :       coeffs(1) = 1.0_dp - SUM(b)
    2538          348 :       coeffs(2:nvec) = b(:)
    2539              : 
    2540              :       ! as a consistency check, print how well the current overlap
    2541              :       ! is approximated by the linear combination of previous overlaps
    2542          116 :       IF (print_level > low_print_level) THEN
    2543           20 :          CALL dbcsr_copy(tmp_i, current_overlap)
    2544           96 :          DO i = 1, nvec
    2545           76 :             state => wfi_get_snapshot(wf_history, wf_index=i)
    2546           96 :             CALL dbcsr_add(tmp_i, state%overlap, 1.0_dp, -coeffs(i))
    2547              :          END DO
    2548           20 :          error = dbcsr_frobenius_norm(tmp_i)/dbcsr_frobenius_norm(state%overlap)
    2549           20 :          IF (io_unit > 0) THEN
    2550           10 :             WRITE (UNIT=io_unit, FMT="(/,T2,A,F20.10)") "GEXT overlap fitting error:", error
    2551              :          END IF
    2552              :       END IF
    2553              : 
    2554              :       ! free the memory
    2555          116 :       CALL dbcsr_release(tmp_i)
    2556          116 :       CALL dbcsr_release(tmp_j)
    2557          116 :       CALL dbcsr_release(tmp_k)
    2558          116 :       CALL dbcsr_release(target_diff)
    2559          116 :       DEALLOCATE (A, b)
    2560              : 
    2561          188 :    END SUBROUTINE diff_fitting
    2562              : 
    2563              : ! **************************************************************************************************
    2564              : !> \brief Gives the coefficients that best approximate the new overlap
    2565              : !>        as a time reversible linear combination of the previous overlaps in the
    2566              : !>        wf_history buffer. This is done by solving
    2567              : !>        argmin_a || S_{n+1} + S_{n+1-nvec}
    2568              : !>                    - \sum_{i=1}^q a_i (S_{n+1-nvec+i} + S_{n+1-i}) ||^2
    2569              : !>        with q = nvec/2 if nvec is even, or q = (nvec-1)/2 if odd.
    2570              : !> \param wf_history wavefunction history buffer, containing the previous overlaps
    2571              : !> \param current_overlap current overlap in dbcsr format
    2572              : !> \param coeffs resulting nvec coefficients
    2573              : !> \param nvec number of previous overlaps
    2574              : !> \param eps Tikhonov regularization
    2575              : !> \param io_unit output unit
    2576              : !> \param print_level print level
    2577              : !> \param current_overlap_kp ...
    2578              : !> \param kpoint_weights ...
    2579              : !> \param para_env_inter_kp ...
    2580              : !> \par History
    2581              : !>      04.2026 created [Michele Nottoli]
    2582              : ! **************************************************************************************************
    2583           28 :    SUBROUTINE tr_fitting(wf_history, current_overlap, coeffs, nvec, eps, io_unit, print_level, &
    2584           28 :                          current_overlap_kp, kpoint_weights, para_env_inter_kp)
    2585              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
    2586              :       TYPE(dbcsr_type), INTENT(IN)                       :: current_overlap
    2587              :       INTEGER, INTENT(IN)                                :: nvec
    2588              :       REAL(KIND=dp), INTENT(OUT)                         :: coeffs(nvec)
    2589              :       REAL(KIND=dp), INTENT(IN)                          :: eps
    2590              :       INTEGER, INTENT(IN)                                :: io_unit, print_level
    2591              :       TYPE(cp_cfm_type), DIMENSION(:), INTENT(IN), &
    2592              :          OPTIONAL                                        :: current_overlap_kp
    2593              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL  :: kpoint_weights
    2594              :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env_inter_kp
    2595              : 
    2596              :       COMPLEX(KIND=dp)                                   :: ztrace
    2597              :       INTEGER                                            :: i, icol_local, ikp, info, irow_local, j, &
    2598              :                                                             ntr
    2599              :       REAL(KIND=dp)                                      :: error, norm_ref, weight
    2600           28 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: b
    2601           28 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: A
    2602              :       TYPE(cp_cfm_type)                                  :: target_overlap_cfm, tmp_conj_cfm, &
    2603              :                                                             tmp_i_cfm, tmp_j_cfm
    2604              :       TYPE(dbcsr_type)                                   :: target_overlap, tmp_i, tmp_j, tmp_k
    2605              :       TYPE(qs_wf_snapshot_type), POINTER                 :: ref_state, state
    2606              : 
    2607           28 :       IF (nvec <= 0) THEN
    2608            0 :          CPABORT("Not enough vectors to do the fitting")
    2609           28 :       ELSE IF (nvec == 1) THEN
    2610            6 :          coeffs(1) = 1.0_dp
    2611           22 :          RETURN
    2612              :       END IF
    2613              : 
    2614           22 :       IF (MOD(nvec, 2) == 0) THEN
    2615           10 :          ntr = nvec/2
    2616              :       ELSE
    2617           12 :          ntr = (nvec - 1)/2
    2618              :       END IF
    2619              : 
    2620           22 :       IF (PRESENT(current_overlap_kp)) THEN
    2621           12 :          ALLOCATE (A(ntr, ntr), b(ntr))
    2622            2 :          A = 0.0_dp
    2623            2 :          b = 0.0_dp
    2624              : 
    2625            2 :          ref_state => wfi_get_snapshot(wf_history, wf_index=nvec)
    2626            2 :          CALL cp_cfm_create(target_overlap_cfm, current_overlap_kp(1)%matrix_struct)
    2627            2 :          CALL cp_cfm_create(tmp_i_cfm, current_overlap_kp(1)%matrix_struct)
    2628            2 :          CALL cp_cfm_create(tmp_j_cfm, current_overlap_kp(1)%matrix_struct)
    2629            2 :          CALL cp_cfm_create(tmp_conj_cfm, current_overlap_kp(1)%matrix_struct)
    2630              : 
    2631           10 :          DO ikp = 1, SIZE(current_overlap_kp)
    2632            8 :             weight = 1.0_dp
    2633            8 :             IF (PRESENT(kpoint_weights)) weight = kpoint_weights(ikp)
    2634              : 
    2635            8 :             CALL cp_cfm_to_cfm(current_overlap_kp(ikp), target_overlap_cfm)
    2636            8 :             CALL cp_cfm_scale_and_add(z_one, target_overlap_cfm, z_one, ref_state%overlap_cfm_kp(ikp))
    2637           18 :             DO i = 1, ntr
    2638            8 :                state => wfi_get_snapshot(wf_history, wf_index=i)
    2639            8 :                CALL cp_cfm_to_cfm(state%overlap_cfm_kp(ikp), tmp_i_cfm)
    2640            8 :                state => wfi_get_snapshot(wf_history, wf_index=nvec - i)
    2641            8 :                CALL cp_cfm_scale_and_add(z_one, tmp_i_cfm, z_one, state%overlap_cfm_kp(ikp))
    2642              : 
    2643            8 :                CALL cp_cfm_to_cfm(tmp_i_cfm, tmp_conj_cfm)
    2644          264 :                DO icol_local = 1, SIZE(tmp_conj_cfm%local_data, 2)
    2645         4360 :                   DO irow_local = 1, SIZE(tmp_conj_cfm%local_data, 1)
    2646              :                      tmp_conj_cfm%local_data(irow_local, icol_local) = &
    2647         4352 :                         CONJG(tmp_conj_cfm%local_data(irow_local, icol_local))
    2648              :                   END DO
    2649              :                END DO
    2650            8 :                CALL cp_cfm_trace(tmp_conj_cfm, target_overlap_cfm, ztrace)
    2651            8 :                b(i) = b(i) + weight*REAL(ztrace, KIND=dp)
    2652           24 :                DO j = 1, i
    2653            8 :                   state => wfi_get_snapshot(wf_history, wf_index=j)
    2654            8 :                   CALL cp_cfm_to_cfm(state%overlap_cfm_kp(ikp), tmp_j_cfm)
    2655            8 :                   state => wfi_get_snapshot(wf_history, wf_index=nvec - j)
    2656            8 :                   CALL cp_cfm_scale_and_add(z_one, tmp_j_cfm, z_one, state%overlap_cfm_kp(ikp))
    2657            8 :                   CALL cp_cfm_trace(tmp_conj_cfm, tmp_j_cfm, ztrace)
    2658           16 :                   A(j, i) = A(j, i) + weight*REAL(ztrace, KIND=dp)
    2659              :                END DO
    2660              :             END DO
    2661              :          END DO
    2662              : 
    2663            4 :          DO i = 1, ntr
    2664            6 :             DO j = 1, i
    2665            4 :                A(i, j) = A(j, i)
    2666              :             END DO
    2667              :          END DO
    2668              : 
    2669            2 :          IF (PRESENT(para_env_inter_kp)) THEN
    2670            2 :             IF (ASSOCIATED(para_env_inter_kp)) THEN
    2671            2 :                CALL para_env_inter_kp%sum(A)
    2672            2 :                CALL para_env_inter_kp%sum(b)
    2673              :             END IF
    2674              :          END IF
    2675              : 
    2676            4 :          DO i = 1, ntr
    2677            4 :             A(i, i) = A(i, i) + eps**2
    2678              :          END DO
    2679              : 
    2680            2 :          CALL dposv('u', ntr, 1, A, ntr, b, ntr, info)
    2681            2 :          IF (info /= 0) THEN
    2682            0 :             CPABORT("DPOSV failed.")
    2683              :          END IF
    2684              : 
    2685            6 :          coeffs = 0.0_dp
    2686            2 :          coeffs(nvec) = -1.0_dp
    2687            4 :          DO i = 1, ntr
    2688            2 :             coeffs(i) = coeffs(i) + b(i)
    2689            4 :             coeffs(nvec - i) = coeffs(nvec - i) + b(i)
    2690              :          END DO
    2691              : 
    2692            2 :          IF (print_level > low_print_level) THEN
    2693            2 :             error = 0.0_dp
    2694            2 :             norm_ref = 0.0_dp
    2695           10 :             DO ikp = 1, SIZE(current_overlap_kp)
    2696            8 :                weight = 1.0_dp
    2697            8 :                IF (PRESENT(kpoint_weights)) weight = kpoint_weights(ikp)
    2698            8 :                CALL cp_cfm_to_cfm(current_overlap_kp(ikp), tmp_i_cfm)
    2699           24 :                DO i = 1, nvec
    2700           16 :                   state => wfi_get_snapshot(wf_history, wf_index=i)
    2701              :                   CALL cp_cfm_scale_and_add(z_one, tmp_i_cfm, CMPLX(-coeffs(i), 0.0_dp, KIND=dp), &
    2702           24 :                                             state%overlap_cfm_kp(ikp))
    2703              :                END DO
    2704            8 :                CALL cp_cfm_to_cfm(tmp_i_cfm, tmp_conj_cfm)
    2705          264 :                DO icol_local = 1, SIZE(tmp_conj_cfm%local_data, 2)
    2706         4360 :                   DO irow_local = 1, SIZE(tmp_conj_cfm%local_data, 1)
    2707              :                      tmp_conj_cfm%local_data(irow_local, icol_local) = &
    2708         4352 :                         CONJG(tmp_conj_cfm%local_data(irow_local, icol_local))
    2709              :                   END DO
    2710              :                END DO
    2711            8 :                CALL cp_cfm_trace(tmp_conj_cfm, tmp_i_cfm, ztrace)
    2712            8 :                error = error + weight*REAL(ztrace, KIND=dp)
    2713            8 :                CALL cp_cfm_to_cfm(ref_state%overlap_cfm_kp(ikp), tmp_conj_cfm)
    2714          264 :                DO icol_local = 1, SIZE(tmp_conj_cfm%local_data, 2)
    2715         4360 :                   DO irow_local = 1, SIZE(tmp_conj_cfm%local_data, 1)
    2716              :                      tmp_conj_cfm%local_data(irow_local, icol_local) = &
    2717         4352 :                         CONJG(tmp_conj_cfm%local_data(irow_local, icol_local))
    2718              :                   END DO
    2719              :                END DO
    2720            8 :                CALL cp_cfm_trace(tmp_conj_cfm, ref_state%overlap_cfm_kp(ikp), ztrace)
    2721           18 :                norm_ref = norm_ref + weight*REAL(ztrace, KIND=dp)
    2722              :             END DO
    2723            2 :             IF (PRESENT(para_env_inter_kp)) THEN
    2724            2 :                IF (ASSOCIATED(para_env_inter_kp)) THEN
    2725            2 :                   CALL para_env_inter_kp%sum(error)
    2726            2 :                   CALL para_env_inter_kp%sum(norm_ref)
    2727              :                END IF
    2728              :             END IF
    2729            2 :             IF (io_unit > 0) THEN
    2730            1 :                WRITE (UNIT=io_unit, FMT="(/,T2,A,F20.10)") "GEXT overlap fitting error:", &
    2731            2 :                   SQRT(error/MAX(norm_ref, TINY(1.0_dp)))
    2732              :             END IF
    2733              :          END IF
    2734              : 
    2735            2 :          CALL cp_cfm_release(target_overlap_cfm)
    2736            2 :          CALL cp_cfm_release(tmp_i_cfm)
    2737            2 :          CALL cp_cfm_release(tmp_j_cfm)
    2738            2 :          CALL cp_cfm_release(tmp_conj_cfm)
    2739            2 :          DEALLOCATE (A, b)
    2740            2 :          RETURN
    2741              :       END IF
    2742              : 
    2743          120 :       ALLOCATE (A(ntr, ntr), b(ntr))
    2744              : 
    2745              :       ! get the reference for the difference fitting
    2746           20 :       ref_state => wfi_get_snapshot(wf_history, wf_index=nvec)
    2747              : 
    2748              :       ! assemble the target sum
    2749           20 :       CALL dbcsr_copy(target_overlap, current_overlap)
    2750           20 :       CALL dbcsr_add(target_overlap, ref_state%overlap, 1.0_dp, 1.0_dp)
    2751              : 
    2752              :       ! allocate tmp_k
    2753           20 :       CALL dbcsr_copy(tmp_k, current_overlap)
    2754              : 
    2755              :       ! assemble the matrix A and the RHS b
    2756           52 :       DO i = 1, ntr
    2757           32 :          state => wfi_get_snapshot(wf_history, wf_index=i)
    2758           32 :          CALL dbcsr_copy(tmp_i, state%overlap)
    2759           32 :          state => wfi_get_snapshot(wf_history, wf_index=nvec - i)
    2760           32 :          CALL dbcsr_add(tmp_i, state%overlap, 1.0_dp, 1.0_dp)
    2761              : 
    2762              :          CALL dbcsr_multiply("N", "N", 1.0_dp, tmp_i, target_overlap, &
    2763           32 :                              0.0_dp, tmp_k)
    2764           32 :          CALL dbcsr_trace(tmp_k, b(i))
    2765           96 :          DO j = 1, i
    2766           44 :             state => wfi_get_snapshot(wf_history, wf_index=j)
    2767           44 :             CALL dbcsr_copy(tmp_j, state%overlap)
    2768           44 :             state => wfi_get_snapshot(wf_history, wf_index=nvec - j)
    2769           44 :             CALL dbcsr_add(tmp_j, state%overlap, 1.0_dp, 1.0_dp)
    2770           44 :             CALL dbcsr_multiply("N", "N", 1.0_dp, tmp_i, tmp_j, 0.0_dp, tmp_k)
    2771           44 :             CALL dbcsr_trace(tmp_k, A(j, i))
    2772           76 :             A(i, j) = A(j, i)
    2773              :          END DO
    2774              :       END DO
    2775              : 
    2776              :       ! add the Tikhonov regularization
    2777           52 :       DO i = 1, ntr
    2778           52 :          A(i, i) = A(i, i) + eps**2
    2779              :       END DO
    2780              : 
    2781              :       ! solve the linear system
    2782           20 :       CALL dposv('u', ntr, 1, A, ntr, b, ntr, info)
    2783           20 :       IF (info /= 0) THEN
    2784            0 :          CPABORT("DPOSV failed.")
    2785              :       END IF
    2786              : 
    2787              :       ! reorder the coefficients
    2788           96 :       coeffs = 0.0_dp
    2789           20 :       coeffs(nvec) = -1.0_dp
    2790           52 :       DO i = 1, ntr
    2791           32 :          coeffs(i) = coeffs(i) + b(i)
    2792           52 :          coeffs(nvec - i) = coeffs(nvec - i) + b(i)
    2793              :       END DO
    2794              : 
    2795              :       ! as a consistency check, print how well the current overlap
    2796              :       ! is approximated by the linear combination of previous overlaps
    2797           20 :       IF (print_level > low_print_level) THEN
    2798           20 :          CALL dbcsr_copy(tmp_i, current_overlap)
    2799           96 :          DO i = 1, nvec
    2800           76 :             state => wfi_get_snapshot(wf_history, wf_index=i)
    2801           96 :             CALL dbcsr_add(tmp_i, state%overlap, 1.0_dp, -coeffs(i))
    2802              :          END DO
    2803           20 :          error = dbcsr_frobenius_norm(tmp_i)/dbcsr_frobenius_norm(state%overlap)
    2804           20 :          IF (io_unit > 0) THEN
    2805           10 :             WRITE (UNIT=io_unit, FMT="(/,T2,A,F20.10)") "GEXT overlap fitting error:", error
    2806              :          END IF
    2807              :       END IF
    2808              : 
    2809              :       ! free the memory
    2810           20 :       CALL dbcsr_release(tmp_i)
    2811           20 :       CALL dbcsr_release(tmp_j)
    2812           20 :       CALL dbcsr_release(tmp_k)
    2813           20 :       CALL dbcsr_release(target_overlap)
    2814           20 :       DEALLOCATE (A, b)
    2815              : 
    2816           44 :    END SUBROUTINE tr_fitting
    2817              : 
    2818              : END MODULE qs_wf_history_methods
        

Generated by: LCOV version 2.0-1