LCOV - code coverage report
Current view: top level - src - qs_wf_history_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:cb5d5fc) Lines: 88.5 % 994 880
Test Date: 2026-04-24 07:01:27 Functions: 92.9 % 14 13

            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 cp_cfm_basic_linalg,             ONLY: cp_cfm_column_scale,&
      27              :                                               cp_cfm_gemm,&
      28              :                                               cp_cfm_scale_and_add,&
      29              :                                               cp_cfm_scale_and_add_fm,&
      30              :                                               cp_cfm_triangular_multiply
      31              :    USE cp_cfm_cholesky,                 ONLY: cp_cfm_cholesky_decompose
      32              :    USE cp_cfm_diag,                     ONLY: cp_cfm_heevd
      33              :    USE cp_cfm_types,                    ONLY: cp_cfm_create,&
      34              :                                               cp_cfm_release,&
      35              :                                               cp_cfm_set_all,&
      36              :                                               cp_cfm_to_cfm,&
      37              :                                               cp_cfm_to_fm,&
      38              :                                               cp_cfm_type,&
      39              :                                               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_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_release, cp_fm_set_all, cp_fm_start_copy_general, cp_fm_to_fm, &
      66              :         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              :                                               z_one,&
      88              :                                               z_zero
      89              :    USE mathlib,                         ONLY: binomial
      90              :    USE message_passing,                 ONLY: mp_para_env_type
      91              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      92              :    USE pw_env_types,                    ONLY: pw_env_get,&
      93              :                                               pw_env_type
      94              :    USE pw_methods,                      ONLY: pw_copy
      95              :    USE pw_pool_types,                   ONLY: pw_pool_type
      96              :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      97              :                                               pw_r3d_rs_type
      98              :    USE qs_density_matrices,             ONLY: calculate_density_matrix
      99              :    USE qs_environment_types,            ONLY: get_qs_env,&
     100              :                                               qs_environment_type,&
     101              :                                               set_qs_env
     102              :    USE qs_ks_types,                     ONLY: qs_ks_did_change
     103              :    USE qs_matrix_pools,                 ONLY: mpools_get,&
     104              :                                               qs_matrix_pools_type
     105              :    USE qs_mo_methods,                   ONLY: make_basis_cholesky,&
     106              :                                               make_basis_lowdin,&
     107              :                                               make_basis_simple,&
     108              :                                               make_basis_sm
     109              :    USE qs_mo_types,                     ONLY: get_mo_set,&
     110              :                                               mo_set_type
     111              :    USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type
     112              :    USE qs_rho_methods,                  ONLY: qs_rho_update_rho
     113              :    USE qs_rho_types,                    ONLY: qs_rho_get,&
     114              :                                               qs_rho_set,&
     115              :                                               qs_rho_type
     116              :    USE qs_scf_types,                    ONLY: ot_method_nr,&
     117              :                                               qs_scf_env_type
     118              :    USE qs_wf_history_types,             ONLY: qs_wf_history_type,&
     119              :                                               qs_wf_snapshot_type,&
     120              :                                               wfi_get_snapshot,&
     121              :                                               wfi_release
     122              :    USE scf_control_types,               ONLY: scf_control_type
     123              : #include "./base/base_uses.f90"
     124              : 
     125              :    IMPLICIT NONE
     126              :    PRIVATE
     127              : 
     128              :    LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .TRUE.
     129              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_wf_history_methods'
     130              : 
     131              :    PUBLIC :: wfi_create, wfi_update, wfi_create_for_kp, &
     132              :              wfi_extrapolate, wfi_get_method_label, &
     133              :              reorthogonalize_vectors, wfi_purge_history
     134              : 
     135              : CONTAINS
     136              : 
     137              : ! **************************************************************************************************
     138              : !> \brief allocates and initialize a wavefunction snapshot
     139              : !> \param snapshot the snapshot to create
     140              : !> \par History
     141              : !>      02.2003 created [fawzi]
     142              : !>      02.2005 added wf_mol [MI]
     143              : !> \author fawzi
     144              : ! **************************************************************************************************
     145        11434 :    SUBROUTINE wfs_create(snapshot)
     146              :       TYPE(qs_wf_snapshot_type), INTENT(OUT)             :: snapshot
     147              : 
     148              :       NULLIFY (snapshot%wf, snapshot%rho_r, &
     149              :                snapshot%rho_g, snapshot%rho_ao, snapshot%rho_ao_kp, &
     150              :                snapshot%overlap, snapshot%wf_kp, snapshot%overlap_cfm_kp, &
     151              :                snapshot%rho_frozen)
     152        11434 :       snapshot%dt = 1.0_dp
     153        11434 :    END SUBROUTINE wfs_create
     154              : 
     155              : ! **************************************************************************************************
     156              : !> \brief updates the given snapshot
     157              : !> \param snapshot the snapshot to be updated
     158              : !> \param wf_history the history
     159              : !> \param qs_env the qs_env that should be snapshotted
     160              : !> \param dt the time of the snapshot (wrt. to the previous snapshot)
     161              : !> \par History
     162              : !>      02.2003 created [fawzi]
     163              : !>      02.2005 added kg_fm_mol_set for KG_GPW [MI]
     164              : !> \author fawzi
     165              : ! **************************************************************************************************
     166        20512 :    SUBROUTINE wfs_update(snapshot, wf_history, qs_env, dt)
     167              :       TYPE(qs_wf_snapshot_type), POINTER                 :: snapshot
     168              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
     169              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     170              :       REAL(KIND=dp), INTENT(in), OPTIONAL                :: dt
     171              : 
     172              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'wfs_update'
     173              : 
     174              :       INTEGER                                            :: handle, ic, igroup, ik, ikp, img, &
     175              :                                                             indx_ft, ispin, kplocal, nc, nimg, &
     176              :                                                             nkp_all, nkp_grps, nspin_kp, nspins
     177              :       INTEGER, DIMENSION(2)                              :: kp_range
     178        20512 :       INTEGER, DIMENSION(:, :), POINTER                  :: kp_dist
     179        20512 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
     180              :       LOGICAL                                            :: my_kpgrp
     181        20512 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: xkp
     182        20512 :       TYPE(copy_info_type), ALLOCATABLE, DIMENSION(:, :) :: info_ft
     183        20512 :       TYPE(cp_fm_pool_p_type), DIMENSION(:), POINTER     :: ao_ao_fm_pools, ao_mo_pools
     184              :       TYPE(cp_fm_struct_type), POINTER                   :: ao_ao_struct_ft
     185              :       TYPE(cp_fm_type)                                   :: fmdummy_ft, fmlocal_ft
     186              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     187        20512 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s, rho_ao
     188        20512 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_s_kp, rho_ao_kp
     189              :       TYPE(dbcsr_type), POINTER                          :: cmat_ft, rmat_ft, tmpmat_ft
     190              :       TYPE(dft_control_type), POINTER                    :: dft_control
     191              :       TYPE(kpoint_env_type), POINTER                     :: kp
     192              :       TYPE(kpoint_type), POINTER                         :: kpoints
     193        20512 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     194              :       TYPE(mp_para_env_type), POINTER                    :: para_env_ft
     195              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     196        20512 :          POINTER                                         :: sab_nl
     197        20512 :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER        :: rho_g
     198              :       TYPE(pw_env_type), POINTER                         :: pw_env
     199              :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
     200        20512 :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER        :: rho_r
     201              :       TYPE(qs_matrix_pools_type), POINTER                :: mpools_kp
     202              :       TYPE(qs_rho_type), POINTER                         :: rho
     203              :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
     204              : 
     205        20512 :       CALL timeset(routineN, handle)
     206              : 
     207        20512 :       NULLIFY (pw_env, auxbas_pw_pool, ao_mo_pools, ao_ao_fm_pools, dft_control, mos, mo_coeff, &
     208        20512 :                rho, rho_r, rho_g, rho_ao, matrix_s, matrix_s_kp, kpoints, kp, &
     209        20512 :                kp_dist, cell_to_index, xkp, sab_nl, scf_env, mpools_kp, para_env_ft, &
     210        20512 :                rmat_ft, cmat_ft, tmpmat_ft, ao_ao_struct_ft)
     211              :       CALL get_qs_env(qs_env, pw_env=pw_env, &
     212        20512 :                       dft_control=dft_control, rho=rho)
     213        20512 :       CALL mpools_get(qs_env%mpools, ao_mo_fm_pools=ao_mo_pools)
     214        20512 :       CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
     215              : 
     216        20512 :       CPASSERT(ASSOCIATED(wf_history))
     217        20512 :       CPASSERT(ASSOCIATED(dft_control))
     218        20512 :       IF (.NOT. ASSOCIATED(snapshot)) THEN
     219        11434 :          ALLOCATE (snapshot)
     220        11434 :          CALL wfs_create(snapshot)
     221              :       END IF
     222        20512 :       CPASSERT(wf_history%ref_count > 0)
     223              : 
     224        20512 :       nspins = dft_control%nspins
     225        20512 :       snapshot%dt = 1.0_dp
     226        20512 :       IF (PRESENT(dt)) snapshot%dt = dt
     227        20512 :       IF (wf_history%store_wf) THEN
     228        19462 :          CALL get_qs_env(qs_env, mos=mos)
     229        19462 :          IF (.NOT. ASSOCIATED(snapshot%wf)) THEN
     230              :             CALL fm_pools_create_fm_vect(ao_mo_pools, snapshot%wf, &
     231        11152 :                                          name="ws_snap-ws")
     232        11152 :             CPASSERT(nspins == SIZE(snapshot%wf))
     233              :          END IF
     234        41066 :          DO ispin = 1, nspins
     235        21604 :             CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff)
     236        41066 :             CALL cp_fm_to_fm(mo_coeff, snapshot%wf(ispin))
     237              :          END DO
     238              :       ELSE
     239         1050 :          CALL fm_pools_give_back_fm_vect(ao_mo_pools, snapshot%wf)
     240              :       END IF
     241              : 
     242        20512 :       IF (wf_history%store_rho_r) THEN
     243            0 :          CALL qs_rho_get(rho, rho_r=rho_r)
     244            0 :          CPASSERT(ASSOCIATED(rho_r))
     245            0 :          IF (.NOT. ASSOCIATED(snapshot%rho_r)) THEN
     246            0 :             ALLOCATE (snapshot%rho_r(nspins))
     247            0 :             DO ispin = 1, nspins
     248            0 :                CALL auxbas_pw_pool%create_pw(snapshot%rho_r(ispin))
     249              :             END DO
     250              :          END IF
     251            0 :          DO ispin = 1, nspins
     252            0 :             CALL pw_copy(rho_r(ispin), snapshot%rho_r(ispin))
     253              :          END DO
     254        20512 :       ELSE IF (ASSOCIATED(snapshot%rho_r)) THEN
     255            0 :          DO ispin = 1, SIZE(snapshot%rho_r)
     256            0 :             CALL auxbas_pw_pool%give_back_pw(snapshot%rho_r(ispin))
     257              :          END DO
     258            0 :          DEALLOCATE (snapshot%rho_r)
     259              :       END IF
     260              : 
     261        20512 :       IF (wf_history%store_rho_g) THEN
     262            0 :          CALL qs_rho_get(rho, rho_g=rho_g)
     263            0 :          CPASSERT(ASSOCIATED(rho_g))
     264            0 :          IF (.NOT. ASSOCIATED(snapshot%rho_g)) THEN
     265            0 :             ALLOCATE (snapshot%rho_g(nspins))
     266            0 :             DO ispin = 1, nspins
     267            0 :                CALL auxbas_pw_pool%create_pw(snapshot%rho_g(ispin))
     268              :             END DO
     269              :          END IF
     270            0 :          DO ispin = 1, nspins
     271            0 :             CALL pw_copy(rho_g(ispin), snapshot%rho_g(ispin))
     272              :          END DO
     273        20512 :       ELSE IF (ASSOCIATED(snapshot%rho_g)) THEN
     274            0 :          DO ispin = 1, SIZE(snapshot%rho_g)
     275            0 :             CALL auxbas_pw_pool%give_back_pw(snapshot%rho_g(ispin))
     276              :          END DO
     277            0 :          DEALLOCATE (snapshot%rho_g)
     278              :       END IF
     279              : 
     280        20512 :       IF (ASSOCIATED(snapshot%rho_ao)) THEN ! the sparsity might be different
     281              :          ! (future struct:check)
     282          270 :          CALL dbcsr_deallocate_matrix_set(snapshot%rho_ao)
     283              :       END IF
     284        20512 :       IF (wf_history%store_rho_ao) THEN
     285          338 :          CALL qs_rho_get(rho, rho_ao=rho_ao)
     286          338 :          CPASSERT(ASSOCIATED(rho_ao))
     287              : 
     288          338 :          CALL dbcsr_allocate_matrix_set(snapshot%rho_ao, nspins)
     289          836 :          DO ispin = 1, nspins
     290          498 :             ALLOCATE (snapshot%rho_ao(ispin)%matrix)
     291          836 :             CALL dbcsr_copy(snapshot%rho_ao(ispin)%matrix, rho_ao(ispin)%matrix)
     292              :          END DO
     293              :       END IF
     294              : 
     295        20512 :       IF (ASSOCIATED(snapshot%rho_ao_kp)) THEN ! the sparsity might be different
     296              :          ! (future struct:check)
     297          220 :          CALL dbcsr_deallocate_matrix_set(snapshot%rho_ao_kp)
     298              :       END IF
     299        20512 :       IF (wf_history%store_rho_ao_kp) THEN
     300          232 :          CALL qs_rho_get(rho, rho_ao_kp=rho_ao_kp)
     301          232 :          CPASSERT(ASSOCIATED(rho_ao_kp))
     302              : 
     303          232 :          nimg = dft_control%nimages
     304          232 :          CALL dbcsr_allocate_matrix_set(snapshot%rho_ao_kp, nspins, nimg)
     305          554 :          DO ispin = 1, nspins
     306        34092 :             DO img = 1, nimg
     307        33538 :                ALLOCATE (snapshot%rho_ao_kp(ispin, img)%matrix)
     308              :                CALL dbcsr_copy(snapshot%rho_ao_kp(ispin, img)%matrix, &
     309        33860 :                                rho_ao_kp(ispin, img)%matrix)
     310              :             END DO
     311              :          END DO
     312              :       END IF
     313              : 
     314        20512 :       IF (ASSOCIATED(snapshot%overlap)) THEN ! the sparsity might be different
     315              :          ! (future struct:check)
     316         5702 :          CALL dbcsr_deallocate_matrix(snapshot%overlap)
     317              :       END IF
     318        20512 :       IF (wf_history%store_overlap) THEN
     319        15820 :          CALL get_qs_env(qs_env, matrix_s=matrix_s)
     320        15820 :          CPASSERT(ASSOCIATED(matrix_s))
     321        15820 :          CPASSERT(ASSOCIATED(matrix_s(1)%matrix))
     322        15820 :          ALLOCATE (snapshot%overlap)
     323        15820 :          CALL dbcsr_copy(snapshot%overlap, matrix_s(1)%matrix)
     324              :       END IF
     325              : 
     326        20512 :       CALL get_qs_env(qs_env, kpoints=kpoints)
     327        20512 :       IF (ASSOCIATED(kpoints)) THEN
     328        20512 :          IF (ASSOCIATED(kpoints%kp_env)) THEN
     329              :             ! --- k-point WFN snapshot: store complex MO coefficients per local k-point ---
     330          696 :             IF (wf_history%store_wf_kp) THEN
     331          464 :                CALL get_kpoint_info(kpoints, kp_range=kp_range)
     332          464 :                kplocal = kp_range(2) - kp_range(1) + 1
     333          464 :                nspin_kp = SIZE(kpoints%kp_env(1)%kpoint_env%mos, 2)
     334          464 :                nc = SIZE(kpoints%kp_env(1)%kpoint_env%mos, 1) ! 2=complex, 1=real
     335              : 
     336          464 :                IF (ASSOCIATED(snapshot%wf_kp)) THEN
     337          732 :                   DO ikp = 1, SIZE(snapshot%wf_kp, 1)
     338         1664 :                      DO ic = 1, SIZE(snapshot%wf_kp, 2)
     339         2330 :                         DO ispin = 1, SIZE(snapshot%wf_kp, 3)
     340         1864 :                            CALL cp_fm_release(snapshot%wf_kp(ikp, ic, ispin))
     341              :                         END DO
     342              :                      END DO
     343              :                   END DO
     344          266 :                   DEALLOCATE (snapshot%wf_kp)
     345              :                END IF
     346              : 
     347         7474 :                ALLOCATE (snapshot%wf_kp(kplocal, nc, nspin_kp))
     348         1970 :                DO ikp = 1, kplocal
     349         1506 :                   kp => kpoints%kp_env(ikp)%kpoint_env
     350         3824 :                   DO ispin = 1, nspin_kp
     351         7068 :                      DO ic = 1, nc
     352         3708 :                         CALL get_mo_set(kp%mos(ic, ispin), mo_coeff=mo_coeff)
     353              :                         CALL cp_fm_create(snapshot%wf_kp(ikp, ic, ispin), &
     354              :                                           mo_coeff%matrix_struct, &
     355         3708 :                                           name="wfkp_snap")
     356         5562 :                         CALL cp_fm_to_fm(mo_coeff, snapshot%wf_kp(ikp, ic, ispin))
     357              :                      END DO
     358              :                   END DO
     359              :                END DO
     360              :             END IF
     361              : 
     362              :             ! --- k-point overlap snapshot: Fourier-transform S(R)→S(k) NOW and store as cfm ---
     363              :             ! This is critical: we MUST transform at snapshot time using the CURRENT neighbor
     364              :             ! list. Storing S(R) and re-transforming later would use a stale neighbor list,
     365              :             ! producing wrong S(k) when the neighbor list changes during MD.
     366          696 :             IF (wf_history%store_overlap_kp) THEN
     367          464 :                CALL get_qs_env(qs_env, matrix_s_kp=matrix_s_kp, scf_env=scf_env)
     368              :                CALL get_kpoint_info(kpoints, nkp=nkp_all, xkp=xkp, kp_range=kp_range, &
     369              :                                     nkp_groups=nkp_grps, kp_dist=kp_dist, &
     370          464 :                                     sab_nl=sab_nl, cell_to_index=cell_to_index)
     371          464 :                kplocal = kp_range(2) - kp_range(1) + 1
     372          464 :                para_env_ft => kpoints%blacs_env_all%para_env
     373              : 
     374              :                ! Allocate dbcsr work matrices for FT (same pattern as do_general_diag_kp)
     375          464 :                ALLOCATE (rmat_ft, cmat_ft, tmpmat_ft)
     376              :                CALL dbcsr_create(rmat_ft, template=matrix_s_kp(1, 1)%matrix, &
     377          464 :                                  matrix_type=dbcsr_type_symmetric)
     378              :                CALL dbcsr_create(cmat_ft, template=matrix_s_kp(1, 1)%matrix, &
     379          464 :                                  matrix_type=dbcsr_type_antisymmetric)
     380              :                CALL dbcsr_create(tmpmat_ft, template=matrix_s_kp(1, 1)%matrix, &
     381          464 :                                  matrix_type=dbcsr_type_no_symmetry)
     382          464 :                CALL cp_dbcsr_alloc_block_from_nbl(rmat_ft, sab_nl)
     383          464 :                CALL cp_dbcsr_alloc_block_from_nbl(cmat_ft, sab_nl)
     384              : 
     385              :                ! Get kp-subgroup FM from pool
     386          464 :                CALL get_kpoint_info(kpoints, mpools=mpools_kp)
     387          464 :                CALL mpools_get(mpools_kp, ao_ao_fm_pools=ao_ao_fm_pools)
     388          464 :                CALL fm_pool_create_fm(ao_ao_fm_pools(1)%pool, fmlocal_ft)
     389              : 
     390              :                ! Release old snapshot if present
     391          464 :                IF (ASSOCIATED(snapshot%overlap_cfm_kp)) THEN
     392          732 :                   DO ikp = 1, SIZE(snapshot%overlap_cfm_kp)
     393          732 :                      CALL cp_cfm_release(snapshot%overlap_cfm_kp(ikp))
     394              :                   END DO
     395          266 :                   DEALLOCATE (snapshot%overlap_cfm_kp)
     396              :                END IF
     397         2898 :                ALLOCATE (snapshot%overlap_cfm_kp(kplocal))
     398              : 
     399          464 :                CALL cp_fm_get_info(fmlocal_ft, matrix_struct=ao_ao_struct_ft)
     400              : 
     401              :                ! Communication info array
     402        11112 :                ALLOCATE (info_ft(kplocal*nkp_grps, 2))
     403              : 
     404              :                ! Phase A: Start async FT + redistribute for each k-point
     405          464 :                indx_ft = 0
     406         1970 :                DO ikp = 1, kplocal
     407         4510 :                   DO igroup = 1, nkp_grps
     408         2540 :                      ik = kp_dist(1, igroup) + ikp - 1
     409         2540 :                      my_kpgrp = (ik >= kp_range(1) .AND. ik <= kp_range(2))
     410         2540 :                      indx_ft = indx_ft + 1
     411              : 
     412         2540 :                      CALL dbcsr_set(rmat_ft, 0.0_dp)
     413         2540 :                      CALL dbcsr_set(cmat_ft, 0.0_dp)
     414              :                      CALL rskp_transform(rmatrix=rmat_ft, cmatrix=cmat_ft, rsmat=matrix_s_kp, &
     415              :                                          ispin=1, xkp=xkp(1:3, ik), &
     416         2540 :                                          cell_to_index=cell_to_index, sab_nl=sab_nl)
     417         2540 :                      CALL dbcsr_desymmetrize(rmat_ft, tmpmat_ft)
     418         2540 :                      CALL copy_dbcsr_to_fm(tmpmat_ft, scf_env%scf_work1(1))
     419         2540 :                      CALL dbcsr_desymmetrize(cmat_ft, tmpmat_ft)
     420         2540 :                      CALL copy_dbcsr_to_fm(tmpmat_ft, scf_env%scf_work1(2))
     421              : 
     422         4046 :                      IF (my_kpgrp) THEN
     423              :                         CALL cp_fm_start_copy_general(scf_env%scf_work1(1), fmlocal_ft, &
     424         1506 :                                                       para_env_ft, info_ft(indx_ft, 1))
     425              :                         CALL cp_fm_start_copy_general(scf_env%scf_work1(2), fmlocal_ft, &
     426         1506 :                                                       para_env_ft, info_ft(indx_ft, 2))
     427              :                      ELSE
     428              :                         CALL cp_fm_start_copy_general(scf_env%scf_work1(1), fmdummy_ft, &
     429         1034 :                                                       para_env_ft, info_ft(indx_ft, 1))
     430              :                         CALL cp_fm_start_copy_general(scf_env%scf_work1(2), fmdummy_ft, &
     431         1034 :                                                       para_env_ft, info_ft(indx_ft, 2))
     432              :                      END IF
     433              :                   END DO
     434              :                END DO
     435              : 
     436              :                ! Phase B: Finish communication and assemble S(k) as cfm
     437              :                indx_ft = 0
     438         1970 :                DO ikp = 1, kplocal
     439         1506 :                   CALL cp_cfm_create(snapshot%overlap_cfm_kp(ikp), ao_ao_struct_ft)
     440         1506 :                   CALL cp_cfm_set_all(snapshot%overlap_cfm_kp(ikp), z_zero)
     441         4510 :                   DO igroup = 1, nkp_grps
     442         2540 :                      ik = kp_dist(1, igroup) + ikp - 1
     443         2540 :                      my_kpgrp = (ik >= kp_range(1) .AND. ik <= kp_range(2))
     444         1034 :                      indx_ft = indx_ft + 1
     445         1506 :                      IF (my_kpgrp) THEN
     446         1506 :                         CALL cp_fm_finish_copy_general(fmlocal_ft, info_ft(indx_ft, 1))
     447              :                         CALL cp_cfm_scale_and_add_fm(z_zero, snapshot%overlap_cfm_kp(ikp), &
     448         1506 :                                                      z_one, fmlocal_ft)
     449         1506 :                         CALL cp_fm_finish_copy_general(fmlocal_ft, info_ft(indx_ft, 2))
     450              :                         CALL cp_cfm_scale_and_add_fm(z_one, snapshot%overlap_cfm_kp(ikp), &
     451         1506 :                                                      gaussi, fmlocal_ft)
     452              :                      END IF
     453              :                   END DO
     454              :                END DO
     455              : 
     456              :                ! Cleanup
     457         3004 :                DO indx_ft = 1, kplocal*nkp_grps
     458         2540 :                   CALL cp_fm_cleanup_copy_general(info_ft(indx_ft, 1))
     459         3004 :                   CALL cp_fm_cleanup_copy_general(info_ft(indx_ft, 2))
     460              :                END DO
     461         6008 :                DEALLOCATE (info_ft)
     462          464 :                CALL fm_pool_give_back_fm(ao_ao_fm_pools(1)%pool, fmlocal_ft)
     463          464 :                CALL dbcsr_deallocate_matrix(rmat_ft)
     464          464 :                CALL dbcsr_deallocate_matrix(cmat_ft)
     465          928 :                CALL dbcsr_deallocate_matrix(tmpmat_ft)
     466              :             END IF
     467              :          END IF
     468              :       END IF
     469              : 
     470              :       IF (wf_history%store_frozen_density) THEN
     471              :          ! do nothing
     472              :          ! CALL deallocate_matrix_set(snapshot%rho_frozen%rho_ao)
     473              :       END IF
     474              : 
     475        20512 :       CALL timestop(handle)
     476              : 
     477        20512 :    END SUBROUTINE wfs_update
     478              : 
     479              : ! **************************************************************************************************
     480              : !> \brief ...
     481              : !> \param wf_history ...
     482              : !> \param interpolation_method_nr the tag of the method used for
     483              : !>        the extrapolation of the initial density for the next md step
     484              : !>        (see qs_wf_history_types:wfi_*_method_nr)
     485              : !> \param extrapolation_order ...
     486              : !> \param has_unit_metric ...
     487              : !> \par History
     488              : !>      02.2003 created [fawzi]
     489              : !> \author fawzi
     490              : ! **************************************************************************************************
     491         7748 :    SUBROUTINE wfi_create(wf_history, interpolation_method_nr, extrapolation_order, &
     492              :                          has_unit_metric)
     493              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
     494              :       INTEGER, INTENT(in)                                :: interpolation_method_nr, &
     495              :                                                             extrapolation_order
     496              :       LOGICAL, INTENT(IN)                                :: has_unit_metric
     497              : 
     498              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'wfi_create'
     499              : 
     500              :       INTEGER                                            :: handle, i
     501              : 
     502         7748 :       CALL timeset(routineN, handle)
     503              : 
     504         7748 :       ALLOCATE (wf_history)
     505         7748 :       wf_history%ref_count = 1
     506         7748 :       wf_history%memory_depth = 0
     507         7748 :       wf_history%snapshot_count = 0
     508         7748 :       wf_history%last_state_index = 1
     509              :       wf_history%store_wf = .FALSE.
     510              :       wf_history%store_rho_r = .FALSE.
     511              :       wf_history%store_rho_g = .FALSE.
     512              :       wf_history%store_rho_ao = .FALSE.
     513              :       wf_history%store_rho_ao_kp = .FALSE.
     514              :       wf_history%store_overlap = .FALSE.
     515              :       wf_history%store_wf_kp = .FALSE.
     516              :       wf_history%store_overlap_kp = .FALSE.
     517              :       wf_history%store_frozen_density = .FALSE.
     518              :       NULLIFY (wf_history%past_states)
     519              : 
     520         7748 :       wf_history%interpolation_method_nr = interpolation_method_nr
     521              : 
     522              :       SELECT CASE (wf_history%interpolation_method_nr)
     523              :       CASE (wfi_use_guess_method_nr)
     524              :          wf_history%memory_depth = 0
     525              :       CASE (wfi_use_prev_wf_method_nr)
     526           64 :          wf_history%memory_depth = 0
     527              :       CASE (wfi_use_prev_p_method_nr)
     528           64 :          wf_history%memory_depth = 1
     529           64 :          wf_history%store_rho_ao = .TRUE.
     530              :       CASE (wfi_use_prev_rho_r_method_nr)
     531            4 :          wf_history%memory_depth = 1
     532            4 :          wf_history%store_rho_ao = .TRUE.
     533              :       CASE (wfi_linear_wf_method_nr)
     534            4 :          wf_history%memory_depth = 2
     535            4 :          wf_history%store_wf = .TRUE.
     536              :       CASE (wfi_linear_p_method_nr)
     537            6 :          wf_history%memory_depth = 2
     538            6 :          wf_history%store_rho_ao = .TRUE.
     539              :       CASE (wfi_linear_ps_method_nr)
     540            6 :          wf_history%memory_depth = 2
     541            6 :          wf_history%store_wf = .TRUE.
     542            6 :          IF (.NOT. has_unit_metric) wf_history%store_overlap = .TRUE.
     543              :       CASE (wfi_ps_method_nr)
     544          343 :          CALL cite_reference(VandeVondele2005a)
     545          343 :          wf_history%memory_depth = extrapolation_order + 1
     546          343 :          wf_history%store_wf = .TRUE.
     547          343 :          wf_history%store_wf_kp = .TRUE.
     548          343 :          IF (.NOT. has_unit_metric) THEN
     549          339 :             wf_history%store_overlap = .TRUE.
     550          339 :             wf_history%store_overlap_kp = .TRUE.
     551              :          END IF
     552              :       CASE (wfi_frozen_method_nr)
     553            4 :          wf_history%memory_depth = 1
     554            4 :          wf_history%store_frozen_density = .TRUE.
     555              :       CASE (wfi_aspc_nr)
     556         7171 :          wf_history%memory_depth = extrapolation_order + 2
     557         7171 :          wf_history%store_wf = .TRUE.
     558         7171 :          wf_history%store_wf_kp = .TRUE.
     559         7171 :          IF (.NOT. has_unit_metric) THEN
     560         6189 :             wf_history%store_overlap = .TRUE.
     561         6189 :             wf_history%store_overlap_kp = .TRUE.
     562              :          END IF
     563              :       CASE (wfi_gext_proj_nr)
     564            4 :          wf_history%memory_depth = extrapolation_order
     565            4 :          wf_history%store_wf = .TRUE.
     566            4 :          wf_history%store_overlap = .TRUE.
     567              :       CASE (wfi_gext_proj_qtr_nr)
     568            4 :          wf_history%memory_depth = extrapolation_order
     569            4 :          wf_history%store_wf = .TRUE.
     570            4 :          wf_history%store_overlap = .TRUE.
     571              :       CASE default
     572              :          CALL cp_abort(__LOCATION__, &
     573              :                        "Unknown interpolation method: "// &
     574            0 :                        TRIM(ADJUSTL(cp_to_string(interpolation_method_nr))))
     575         7748 :          wf_history%interpolation_method_nr = wfi_use_prev_rho_r_method_nr
     576              :       END SELECT
     577        60157 :       ALLOCATE (wf_history%past_states(wf_history%memory_depth))
     578              : 
     579        44799 :       DO i = 1, SIZE(wf_history%past_states)
     580        44799 :          NULLIFY (wf_history%past_states(i)%snapshot)
     581              :       END DO
     582              : 
     583         7748 :       CALL timestop(handle)
     584         7748 :    END SUBROUTINE wfi_create
     585              : 
     586              : ! **************************************************************************************************
     587              : !> \brief Adapts wf_history storage flags for k-point calculations.
     588              : !>        For ASPC, switches from Gamma WFN storage to k-point WFN storage.
     589              : !>        Other WFN-based methods remain blocked.
     590              : !> \param wf_history ...
     591              : !> \par History
     592              : !>      06.2015 created [jhu]
     593              : !> \author jhu
     594              : ! **************************************************************************************************
     595          198 :    SUBROUTINE wfi_create_for_kp(wf_history)
     596              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
     597              : 
     598          198 :       CPASSERT(ASSOCIATED(wf_history))
     599          198 :       IF (wf_history%store_rho_ao) THEN
     600           10 :          wf_history%store_rho_ao_kp = .TRUE.
     601           10 :          wf_history%store_rho_ao = .FALSE.
     602              :       END IF
     603              :       ! KP-compatible PS and ASPC: switch from Gamma WFN storage to KP WFN storage
     604          198 :       IF (wf_history%store_wf_kp) THEN
     605          104 :          wf_history%store_wf = .FALSE.
     606          104 :          wf_history%store_overlap = .FALSE.
     607              :          ! store_wf_kp and store_overlap_kp remain TRUE
     608              :       ELSE
     609              :          ! Linear methods (except LINEAR_P) are still blocked
     610           94 :          IF (wf_history%store_wf .OR. wf_history%store_overlap) THEN
     611            0 :             CPABORT("Linear WFN-based extrapolation methods not implemented for k-points.")
     612              :          END IF
     613              :       END IF
     614          198 :       IF (wf_history%store_frozen_density) THEN
     615            0 :          CPABORT("Frozen density initialization method not possible for kpoints.")
     616              :       END IF
     617              : 
     618          198 :    END SUBROUTINE wfi_create_for_kp
     619              : 
     620              : ! **************************************************************************************************
     621              : !> \brief returns a string describing the interpolation method
     622              : !> \param method_nr ...
     623              : !> \return ...
     624              : !> \par History
     625              : !>      02.2003 created [fawzi]
     626              : !> \author fawzi
     627              : ! **************************************************************************************************
     628        10815 :    FUNCTION wfi_get_method_label(method_nr) RESULT(res)
     629              :       INTEGER, INTENT(in)                                :: method_nr
     630              :       CHARACTER(len=30)                                  :: res
     631              : 
     632        10815 :       res = "unknown"
     633        11053 :       SELECT CASE (method_nr)
     634              :       CASE (wfi_use_prev_p_method_nr)
     635          238 :          res = "previous_p"
     636              :       CASE (wfi_use_prev_wf_method_nr)
     637          213 :          res = "previous_wf"
     638              :       CASE (wfi_use_prev_rho_r_method_nr)
     639            4 :          res = "previous_rho_r"
     640              :       CASE (wfi_use_guess_method_nr)
     641         3442 :          res = "initial_guess"
     642              :       CASE (wfi_linear_wf_method_nr)
     643            2 :          res = "mo linear"
     644              :       CASE (wfi_linear_p_method_nr)
     645            3 :          res = "P linear"
     646              :       CASE (wfi_linear_ps_method_nr)
     647            6 :          res = "PS linear"
     648              :       CASE (wfi_ps_method_nr)
     649          188 :          res = "PS Nth order"
     650              :       CASE (wfi_frozen_method_nr)
     651            4 :          res = "frozen density approximation"
     652              :       CASE (wfi_aspc_nr)
     653         6691 :          res = "ASPC"
     654              :       CASE (wfi_gext_proj_nr)
     655           12 :          res = "GEXT_PROJ"
     656              :       CASE (wfi_gext_proj_qtr_nr)
     657           12 :          res = "GEXT_PROJ_QTR"
     658              :       CASE default
     659              :          CALL cp_abort(__LOCATION__, &
     660              :                        "Unknown interpolation method: "// &
     661        10815 :                        TRIM(ADJUSTL(cp_to_string(method_nr))))
     662              :       END SELECT
     663        10815 :    END FUNCTION wfi_get_method_label
     664              : 
     665              : ! **************************************************************************************************
     666              : !> \brief calculates the new starting state for the scf for the next
     667              : !>      wf optimization
     668              : !> \param wf_history the previous history needed to extrapolate
     669              : !> \param qs_env the qs env with the latest result, and that will contain
     670              : !>        the new starting state
     671              : !> \param dt the time at which to extrapolate (wrt. to the last snapshot)
     672              : !> \param extrapolation_method_nr returns the extrapolation method used
     673              : !> \param orthogonal_wf ...
     674              : !> \par History
     675              : !>      02.2003 created [fawzi]
     676              : !>      11.2003 Joost VandeVondele : Implemented Nth order PS extrapolation
     677              : !>      04.2026 Michele Nottoli : Added GEXT_PROJ and GEXT_PROJ_QTR extrapolations
     678              : !> \author fawzi
     679              : ! **************************************************************************************************
     680        21295 :    SUBROUTINE wfi_extrapolate(wf_history, qs_env, dt, extrapolation_method_nr, &
     681              :                               orthogonal_wf)
     682              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
     683              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     684              :       REAL(KIND=dp), INTENT(IN)                          :: dt
     685              :       INTEGER, INTENT(OUT), OPTIONAL                     :: extrapolation_method_nr
     686              :       LOGICAL, INTENT(OUT), OPTIONAL                     :: orthogonal_wf
     687              : 
     688              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'wfi_extrapolate'
     689              : 
     690              :       INTEGER                                            :: actual_extrapolation_method_nr, handle, &
     691              :                                                             i, img, io_unit, ispin, k, n, nmo, &
     692              :                                                             nvec, print_level
     693              :       LOGICAL                                            :: do_kpoints, my_orthogonal_wf, use_overlap
     694              :       REAL(KIND=dp)                                      :: alpha, t0, t1, t2
     695        21295 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: coeffs
     696        21295 :       TYPE(cp_fm_pool_p_type), DIMENSION(:), POINTER     :: ao_mo_fm_pools
     697              :       TYPE(cp_fm_struct_type), POINTER                   :: matrix_struct, matrix_struct_new
     698              :       TYPE(cp_fm_type)                                   :: csc, fm_tmp
     699              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     700              :       TYPE(cp_logger_type), POINTER                      :: logger
     701        21295 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s, rho_ao, rho_frozen_ao
     702        21295 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: rho_ao_kp
     703        21295 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     704              :       TYPE(qs_rho_type), POINTER                         :: rho
     705              :       TYPE(qs_wf_snapshot_type), POINTER                 :: t0_state, t1_state
     706              : 
     707        21295 :       NULLIFY (mos, ao_mo_fm_pools, t0_state, t1_state, mo_coeff, &
     708        21295 :                rho, rho_ao, rho_frozen_ao)
     709              : 
     710        21295 :       use_overlap = wf_history%store_overlap
     711              : 
     712        21295 :       CALL timeset(routineN, handle)
     713        21295 :       logger => cp_get_default_logger()
     714        21295 :       print_level = logger%iter_info%print_level
     715              :       io_unit = cp_print_key_unit_nr(logger, qs_env%input, "DFT%SCF%PRINT%PROGRAM_RUN_INFO", &
     716        21295 :                                      extension=".scfLog")
     717              : 
     718        21295 :       CPASSERT(ASSOCIATED(wf_history))
     719        21295 :       CPASSERT(wf_history%ref_count > 0)
     720        21295 :       CPASSERT(ASSOCIATED(qs_env))
     721        21295 :       CALL get_qs_env(qs_env, mos=mos, rho=rho, do_kpoints=do_kpoints)
     722        21295 :       CALL mpools_get(qs_env%mpools, ao_mo_fm_pools=ao_mo_fm_pools)
     723              :       ! chooses the method for this extrapolation
     724        21295 :       IF (wf_history%snapshot_count < 1) THEN
     725              :          actual_extrapolation_method_nr = wfi_use_guess_method_nr
     726              :       ELSE
     727        14708 :          actual_extrapolation_method_nr = wf_history%interpolation_method_nr
     728              :       END IF
     729              : 
     730            8 :       SELECT CASE (actual_extrapolation_method_nr)
     731              :       CASE (wfi_linear_wf_method_nr)
     732            8 :          IF (wf_history%snapshot_count < 2) THEN
     733            4 :             actual_extrapolation_method_nr = wfi_use_prev_wf_method_nr
     734              :          END IF
     735              :       CASE (wfi_linear_p_method_nr)
     736           12 :          IF (wf_history%snapshot_count < 2) THEN
     737            6 :             actual_extrapolation_method_nr = wfi_use_prev_wf_method_nr
     738              :          END IF
     739              :       CASE (wfi_linear_ps_method_nr)
     740        14708 :          IF (wf_history%snapshot_count < 2) THEN
     741            6 :             actual_extrapolation_method_nr = wfi_use_prev_wf_method_nr
     742              :          END IF
     743              :       END SELECT
     744              : 
     745        21295 :       IF (PRESENT(extrapolation_method_nr)) &
     746        21295 :          extrapolation_method_nr = actual_extrapolation_method_nr
     747        21295 :       my_orthogonal_wf = .FALSE.
     748              : 
     749            8 :       SELECT CASE (actual_extrapolation_method_nr)
     750              :       CASE (wfi_frozen_method_nr)
     751            8 :          CPASSERT(.NOT. do_kpoints)
     752            8 :          t0_state => wfi_get_snapshot(wf_history, wf_index=1)
     753            8 :          CPASSERT(ASSOCIATED(t0_state%rho_frozen))
     754              : 
     755            8 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
     756            8 :          CALL wfi_set_history_variables(qs_env=qs_env, nvec=nvec)
     757              : 
     758            8 :          CALL qs_rho_get(t0_state%rho_frozen, rho_ao=rho_frozen_ao)
     759            8 :          CALL qs_rho_get(rho, rho_ao=rho_ao)
     760           16 :          DO ispin = 1, SIZE(rho_frozen_ao)
     761              :             CALL dbcsr_copy(rho_ao(ispin)%matrix, &
     762              :                             rho_frozen_ao(ispin)%matrix, &
     763           16 :                             keep_sparsity=.TRUE.)
     764              :          END DO
     765              :          !FM updating rho_ao directly with t0_state%rho_ao would have the
     766              :          !FM wrong matrix structure
     767            8 :          CALL qs_rho_update_rho(rho, qs_env=qs_env)
     768            8 :          CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
     769              : 
     770            8 :          my_orthogonal_wf = .FALSE.
     771              :       CASE (wfi_use_prev_rho_r_method_nr)
     772            8 :          t0_state => wfi_get_snapshot(wf_history, wf_index=1)
     773            8 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
     774            8 :          CALL wfi_set_history_variables(qs_env=qs_env, nvec=nvec)
     775            8 :          IF (do_kpoints) THEN
     776            0 :             CPASSERT(ASSOCIATED(t0_state%rho_ao_kp))
     777            0 :             CALL qs_rho_get(rho, rho_ao_kp=rho_ao_kp)
     778            0 :             DO ispin = 1, SIZE(t0_state%rho_ao_kp, 1)
     779            0 :                DO img = 1, SIZE(t0_state%rho_ao_kp, 2)
     780            0 :                   IF (img > SIZE(rho_ao_kp, 2)) THEN
     781            0 :                      CPWARN("Change in cell neighborlist: might affect quality of initial guess")
     782              :                   ELSE
     783              :                      CALL dbcsr_copy(rho_ao_kp(ispin, img)%matrix, &
     784              :                                      t0_state%rho_ao_kp(ispin, img)%matrix, &
     785            0 :                                      keep_sparsity=.TRUE.)
     786              :                   END IF
     787              :                END DO
     788              :             END DO
     789              :          ELSE
     790            8 :             CPASSERT(ASSOCIATED(t0_state%rho_ao))
     791            8 :             CALL qs_rho_get(rho, rho_ao=rho_ao)
     792           16 :             DO ispin = 1, SIZE(t0_state%rho_ao)
     793              :                CALL dbcsr_copy(rho_ao(ispin)%matrix, &
     794              :                                t0_state%rho_ao(ispin)%matrix, &
     795           16 :                                keep_sparsity=.TRUE.)
     796              :             END DO
     797              :          END IF
     798              :          ! Why is rho_g valid at this point ?
     799            8 :          CALL qs_rho_set(rho, rho_g_valid=.TRUE.)
     800              : 
     801              :          ! does nothing
     802              :       CASE (wfi_use_prev_wf_method_nr)
     803          426 :          my_orthogonal_wf = .TRUE.
     804          426 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
     805          426 :          CALL wfi_set_history_variables(qs_env=qs_env, nvec=nvec)
     806              : 
     807          426 :          IF (do_kpoints) THEN
     808            6 :             CALL wfi_use_prev_wf_kp(qs_env, io_unit, print_level)
     809              :          ELSE
     810          420 :             CALL qs_rho_get(rho, rho_ao=rho_ao)
     811          888 :             DO ispin = 1, SIZE(mos)
     812          468 :                CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, nmo=nmo)
     813          468 :                CALL reorthogonalize_vectors(qs_env, v_matrix=mo_coeff, n_col=nmo)
     814         1356 :                CALL calculate_density_matrix(mo_set=mos(ispin), density_matrix=rho_ao(ispin)%matrix)
     815              :             END DO
     816          420 :             CALL qs_rho_update_rho(rho, qs_env=qs_env)
     817          420 :             CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
     818              :          END IF
     819              : 
     820              :       CASE (wfi_use_prev_p_method_nr)
     821          476 :          t0_state => wfi_get_snapshot(wf_history, wf_index=1)
     822          476 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
     823          476 :          CALL wfi_set_history_variables(qs_env=qs_env, nvec=nvec)
     824          476 :          IF (do_kpoints) THEN
     825          218 :             CPASSERT(ASSOCIATED(t0_state%rho_ao_kp))
     826          218 :             CALL qs_rho_get(rho, rho_ao_kp=rho_ao_kp)
     827          524 :             DO ispin = 1, SIZE(t0_state%rho_ao_kp, 1)
     828        31248 :                DO img = 1, SIZE(t0_state%rho_ao_kp, 2)
     829        31030 :                   IF (img > SIZE(rho_ao_kp, 2)) THEN
     830           18 :                      CPWARN("Change in cell neighborlist: might affect quality of initial guess")
     831              :                   ELSE
     832              :                      CALL dbcsr_copy(rho_ao_kp(ispin, img)%matrix, &
     833              :                                      t0_state%rho_ao_kp(ispin, img)%matrix, &
     834        30706 :                                      keep_sparsity=.TRUE.)
     835              :                   END IF
     836              :                END DO
     837              :             END DO
     838              :          ELSE
     839          258 :             CPASSERT(ASSOCIATED(t0_state%rho_ao))
     840          258 :             CALL qs_rho_get(rho, rho_ao=rho_ao)
     841          646 :             DO ispin = 1, SIZE(t0_state%rho_ao)
     842              :                CALL dbcsr_copy(rho_ao(ispin)%matrix, &
     843              :                                t0_state%rho_ao(ispin)%matrix, &
     844          646 :                                keep_sparsity=.TRUE.)
     845              :             END DO
     846              :          END IF
     847              :          !FM updating rho_ao directly with t0_state%rho_ao would have the
     848              :          !FM wrong matrix structure
     849          476 :          CALL qs_rho_update_rho(rho, qs_env=qs_env)
     850          476 :          CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
     851              : 
     852              :       CASE (wfi_use_guess_method_nr)
     853              :          !FM more clean to do it here, but it
     854              :          !FM might need to read a file (restart) and thus globenv
     855              :          !FM I do not want globenv here, thus done by the caller
     856              :          !FM (btw. it also needs the eigensolver, and unless you relocate it
     857              :          !FM gives circular dependencies)
     858         6829 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
     859         6829 :          CALL wfi_set_history_variables(qs_env=qs_env, nvec=nvec)
     860              :       CASE (wfi_linear_wf_method_nr)
     861            4 :          CPASSERT(.NOT. do_kpoints)
     862            4 :          t0_state => wfi_get_snapshot(wf_history, wf_index=2)
     863            4 :          t1_state => wfi_get_snapshot(wf_history, wf_index=1)
     864            4 :          CPASSERT(ASSOCIATED(t0_state))
     865            4 :          CPASSERT(ASSOCIATED(t1_state))
     866            4 :          CPASSERT(ASSOCIATED(t0_state%wf))
     867            4 :          CPASSERT(ASSOCIATED(t1_state%wf))
     868            4 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
     869            4 :          CALL wfi_set_history_variables(qs_env=qs_env, nvec=nvec)
     870              : 
     871            4 :          my_orthogonal_wf = .TRUE.
     872            4 :          t0 = 0.0_dp
     873            4 :          t1 = t1_state%dt
     874            4 :          t2 = t1 + dt
     875            4 :          CALL qs_rho_get(rho, rho_ao=rho_ao)
     876            8 :          DO ispin = 1, SIZE(mos)
     877              :             CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, &
     878            4 :                             nmo=nmo)
     879              :             CALL cp_fm_scale_and_add(alpha=0.0_dp, &
     880              :                                      matrix_a=mo_coeff, &
     881              :                                      matrix_b=t1_state%wf(ispin), &
     882            4 :                                      beta=(t2 - t0)/(t1 - t0))
     883              :             ! this copy should be unnecessary
     884              :             CALL cp_fm_scale_and_add(alpha=1.0_dp, &
     885              :                                      matrix_a=mo_coeff, &
     886            4 :                                      beta=(t1 - t2)/(t1 - t0), matrix_b=t0_state%wf(ispin))
     887              :             CALL reorthogonalize_vectors(qs_env, &
     888              :                                          v_matrix=mo_coeff, &
     889            4 :                                          n_col=nmo)
     890              :             CALL calculate_density_matrix(mo_set=mos(ispin), &
     891           12 :                                           density_matrix=rho_ao(ispin)%matrix)
     892              :          END DO
     893            4 :          CALL qs_rho_update_rho(rho, qs_env=qs_env)
     894              : 
     895              :          CALL qs_ks_did_change(qs_env%ks_env, &
     896            4 :                                rho_changed=.TRUE.)
     897              :       CASE (wfi_linear_p_method_nr)
     898            6 :          t0_state => wfi_get_snapshot(wf_history, wf_index=2)
     899            6 :          t1_state => wfi_get_snapshot(wf_history, wf_index=1)
     900            6 :          CPASSERT(ASSOCIATED(t0_state))
     901            6 :          CPASSERT(ASSOCIATED(t1_state))
     902            6 :          IF (do_kpoints) THEN
     903            2 :             CPASSERT(ASSOCIATED(t0_state%rho_ao_kp))
     904            2 :             CPASSERT(ASSOCIATED(t1_state%rho_ao_kp))
     905              :          ELSE
     906            4 :             CPASSERT(ASSOCIATED(t0_state%rho_ao))
     907            4 :             CPASSERT(ASSOCIATED(t1_state%rho_ao))
     908              :          END IF
     909            6 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
     910            6 :          CALL wfi_set_history_variables(qs_env=qs_env, nvec=nvec)
     911              : 
     912            6 :          t0 = 0.0_dp
     913            6 :          t1 = t1_state%dt
     914            6 :          t2 = t1 + dt
     915            6 :          IF (do_kpoints) THEN
     916            2 :             CALL qs_rho_get(rho, rho_ao_kp=rho_ao_kp)
     917            4 :             DO ispin = 1, SIZE(rho_ao_kp, 1)
     918          528 :                DO img = 1, SIZE(rho_ao_kp, 2)
     919          524 :                   IF (img > SIZE(t0_state%rho_ao_kp, 2) .OR. &
     920            2 :                       img > SIZE(t1_state%rho_ao_kp, 2)) THEN
     921           22 :                      CPWARN("Change in cell neighborlist: might affect quality of initial guess")
     922              :                   ELSE
     923              :                      CALL dbcsr_add(rho_ao_kp(ispin, img)%matrix, t1_state%rho_ao_kp(ispin, img)%matrix, &
     924          502 :                                     alpha_scalar=0.0_dp, beta_scalar=(t2 - t0)/(t1 - t0)) ! this copy should be unnecessary
     925              :                      CALL dbcsr_add(rho_ao_kp(ispin, img)%matrix, t0_state%rho_ao_kp(ispin, img)%matrix, &
     926          502 :                                     alpha_scalar=1.0_dp, beta_scalar=(t1 - t2)/(t1 - t0))
     927              :                   END IF
     928              :                END DO
     929              :             END DO
     930              :          ELSE
     931            4 :             CALL qs_rho_get(rho, rho_ao=rho_ao)
     932            8 :             DO ispin = 1, SIZE(rho_ao)
     933              :                CALL dbcsr_add(rho_ao(ispin)%matrix, t1_state%rho_ao(ispin)%matrix, &
     934            4 :                               alpha_scalar=0.0_dp, beta_scalar=(t2 - t0)/(t1 - t0)) ! this copy should be unnecessary
     935              :                CALL dbcsr_add(rho_ao(ispin)%matrix, t0_state%rho_ao(ispin)%matrix, &
     936            8 :                               alpha_scalar=1.0_dp, beta_scalar=(t1 - t2)/(t1 - t0))
     937              :             END DO
     938              :          END IF
     939            6 :          CALL qs_rho_update_rho(rho, qs_env=qs_env)
     940            6 :          CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
     941              :       CASE (wfi_linear_ps_method_nr)
     942              :          ! wf not calculated, extract with PSC renormalized?
     943              :          ! use wf_linear?
     944           12 :          CPASSERT(.NOT. do_kpoints)
     945           12 :          t0_state => wfi_get_snapshot(wf_history, wf_index=2)
     946           12 :          t1_state => wfi_get_snapshot(wf_history, wf_index=1)
     947           12 :          CPASSERT(ASSOCIATED(t0_state))
     948           12 :          CPASSERT(ASSOCIATED(t1_state))
     949           12 :          CPASSERT(ASSOCIATED(t0_state%wf))
     950           12 :          CPASSERT(ASSOCIATED(t1_state%wf))
     951           12 :          IF (wf_history%store_overlap) THEN
     952            4 :             CPASSERT(ASSOCIATED(t0_state%overlap))
     953            4 :             CPASSERT(ASSOCIATED(t1_state%overlap))
     954              :          END IF
     955           12 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
     956           12 :          IF (nvec >= wf_history%memory_depth) THEN
     957           12 :             IF ((qs_env%scf_control%max_scf_hist /= 0) .AND. (qs_env%scf_control%eps_scf_hist /= 0)) THEN
     958            0 :                qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
     959            0 :                qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
     960            0 :                qs_env%scf_control%outer_scf%have_scf = .FALSE.
     961           12 :             ELSE IF (qs_env%scf_control%max_scf_hist /= 0) THEN
     962            0 :                qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
     963            0 :                qs_env%scf_control%outer_scf%have_scf = .FALSE.
     964           12 :             ELSE IF (qs_env%scf_control%eps_scf_hist /= 0) THEN
     965            0 :                qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
     966              :             END IF
     967              :          END IF
     968              : 
     969           12 :          my_orthogonal_wf = .TRUE.
     970              :          ! use PS_2=2 PS_1-PS_0
     971              :          ! C_2 comes from using PS_2 as a projector acting on C_1
     972           12 :          CALL qs_rho_get(rho, rho_ao=rho_ao)
     973           24 :          DO ispin = 1, SIZE(mos)
     974           12 :             NULLIFY (mo_coeff, matrix_struct, matrix_struct_new)
     975           12 :             CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff)
     976              :             CALL cp_fm_get_info(mo_coeff, nrow_global=n, ncol_global=k, &
     977           12 :                                 matrix_struct=matrix_struct)
     978              :             CALL cp_fm_struct_create(matrix_struct_new, template_fmstruct=matrix_struct, &
     979           12 :                                      nrow_global=k, ncol_global=k)
     980           12 :             CALL cp_fm_create(csc, matrix_struct_new)
     981           12 :             CALL cp_fm_struct_release(matrix_struct_new)
     982              : 
     983           12 :             IF (use_overlap) THEN
     984            4 :                CALL cp_dbcsr_sm_fm_multiply(t0_state%overlap, t1_state%wf(ispin), mo_coeff, k)
     985            4 :                CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, t0_state%wf(ispin), mo_coeff, 0.0_dp, csc)
     986              :             ELSE
     987              :                CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, t0_state%wf(ispin), &
     988            8 :                                   t1_state%wf(ispin), 0.0_dp, csc)
     989              :             END IF
     990           12 :             CALL parallel_gemm('N', 'N', n, k, k, 1.0_dp, t0_state%wf(ispin), csc, 0.0_dp, mo_coeff)
     991           12 :             CALL cp_fm_release(csc)
     992           12 :             CALL cp_fm_scale_and_add(-1.0_dp, mo_coeff, 2.0_dp, t1_state%wf(ispin))
     993              :             CALL reorthogonalize_vectors(qs_env, &
     994              :                                          v_matrix=mo_coeff, &
     995           12 :                                          n_col=k)
     996              :             CALL calculate_density_matrix(mo_set=mos(ispin), &
     997           48 :                                           density_matrix=rho_ao(ispin)%matrix)
     998              :          END DO
     999           12 :          CALL qs_rho_update_rho(rho, qs_env=qs_env)
    1000           12 :          CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
    1001              : 
    1002              :       CASE (wfi_ps_method_nr)
    1003              :          ! figure out the actual number of vectors to use in the extrapolation:
    1004          376 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
    1005          376 :          CPASSERT(nvec > 0)
    1006          376 :          IF (nvec >= wf_history%memory_depth) THEN
    1007          178 :             IF ((qs_env%scf_control%max_scf_hist /= 0) .AND. (qs_env%scf_control%eps_scf_hist /= 0)) THEN
    1008            0 :                qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1009            0 :                qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1010            0 :                qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1011          178 :             ELSE IF (qs_env%scf_control%max_scf_hist /= 0) THEN
    1012            0 :                qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1013            0 :                qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1014          178 :             ELSE IF (qs_env%scf_control%eps_scf_hist /= 0) THEN
    1015            0 :                qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1016              :             END IF
    1017              :          END IF
    1018              : 
    1019          376 :          IF (do_kpoints) THEN
    1020            4 :             CALL wfi_extrapolate_ps_aspc_kp(wf_history, qs_env, nvec, io_unit, print_level)
    1021            4 :             my_orthogonal_wf = .TRUE.
    1022              :          ELSE
    1023          372 :             my_orthogonal_wf = .TRUE.
    1024          822 :             DO ispin = 1, SIZE(mos)
    1025          450 :                NULLIFY (mo_coeff, matrix_struct, matrix_struct_new)
    1026          450 :                CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff)
    1027              :                CALL cp_fm_get_info(mo_coeff, nrow_global=n, ncol_global=k, &
    1028          450 :                                    matrix_struct=matrix_struct)
    1029          450 :                CALL cp_fm_create(fm_tmp, matrix_struct)
    1030              :                CALL cp_fm_struct_create(matrix_struct_new, template_fmstruct=matrix_struct, &
    1031          450 :                                         nrow_global=k, ncol_global=k)
    1032          450 :                CALL cp_fm_create(csc, matrix_struct_new)
    1033          450 :                CALL cp_fm_struct_release(matrix_struct_new)
    1034              :                ! first the most recent
    1035          450 :                t1_state => wfi_get_snapshot(wf_history, wf_index=1)
    1036          450 :                CALL cp_fm_to_fm(t1_state%wf(ispin), mo_coeff)
    1037          450 :                alpha = nvec
    1038          450 :                CALL cp_fm_scale(alpha, mo_coeff)
    1039          450 :                CALL qs_rho_get(rho, rho_ao=rho_ao)
    1040          962 :                DO i = 2, nvec
    1041          512 :                   t0_state => wfi_get_snapshot(wf_history, wf_index=i)
    1042          512 :                   IF (use_overlap) THEN
    1043          474 :                      CALL cp_dbcsr_sm_fm_multiply(t0_state%overlap, t1_state%wf(ispin), fm_tmp, k)
    1044          474 :                      CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, t0_state%wf(ispin), fm_tmp, 0.0_dp, csc)
    1045              :                   ELSE
    1046              :                      CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, t0_state%wf(ispin), &
    1047           38 :                                         t1_state%wf(ispin), 0.0_dp, csc)
    1048              :                   END IF
    1049          512 :                   CALL parallel_gemm('N', 'N', n, k, k, 1.0_dp, t0_state%wf(ispin), csc, 0.0_dp, fm_tmp)
    1050          512 :                   alpha = -1.0_dp*alpha*REAL(nvec - i + 1, dp)/REAL(i, dp)
    1051          962 :                   CALL cp_fm_scale_and_add(1.0_dp, mo_coeff, alpha, fm_tmp)
    1052              :                END DO
    1053              : 
    1054          450 :                CALL cp_fm_release(csc)
    1055          450 :                CALL cp_fm_release(fm_tmp)
    1056              :                CALL reorthogonalize_vectors(qs_env, &
    1057              :                                             v_matrix=mo_coeff, &
    1058          450 :                                             n_col=k)
    1059              :                CALL calculate_density_matrix(mo_set=mos(ispin), &
    1060         1722 :                                              density_matrix=rho_ao(ispin)%matrix)
    1061              :             END DO
    1062          372 :             CALL qs_rho_update_rho(rho, qs_env=qs_env)
    1063          372 :             CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
    1064              :          END IF
    1065              : 
    1066              :       CASE (wfi_aspc_nr)
    1067        13102 :          CALL cite_reference(Kolafa2004)
    1068        13102 :          CALL cite_reference(Kuhne2007)
    1069              :          ! figure out the actual number of vectors to use in the extrapolation:
    1070        13102 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
    1071        13102 :          CPASSERT(nvec > 0)
    1072        13102 :          IF (nvec >= wf_history%memory_depth) THEN
    1073         8366 :             IF ((qs_env%scf_control%max_scf_hist /= 0) .AND. &
    1074              :                 (qs_env%scf_control%eps_scf_hist /= 0)) THEN
    1075           18 :                qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1076           18 :                qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1077           18 :                qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1078         8348 :             ELSE IF (qs_env%scf_control%max_scf_hist /= 0) THEN
    1079           62 :                qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1080           62 :                qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1081         8286 :             ELSE IF (qs_env%scf_control%eps_scf_hist /= 0) THEN
    1082            8 :                qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1083              :             END IF
    1084              :          END IF
    1085              : 
    1086        13102 :          IF (do_kpoints) THEN
    1087          358 :             CALL wfi_extrapolate_ps_aspc_kp(wf_history, qs_env, nvec, io_unit, print_level)
    1088          358 :             my_orthogonal_wf = .TRUE.
    1089              :          ELSE
    1090        12744 :             my_orthogonal_wf = .TRUE.
    1091        12744 :             CALL qs_rho_get(rho, rho_ao=rho_ao)
    1092        26071 :             DO ispin = 1, SIZE(mos)
    1093        13327 :                NULLIFY (mo_coeff, matrix_struct, matrix_struct_new)
    1094        13327 :                CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff)
    1095              :                CALL cp_fm_get_info(mo_coeff, &
    1096              :                                    nrow_global=n, &
    1097              :                                    ncol_global=k, &
    1098        13327 :                                    matrix_struct=matrix_struct)
    1099        13327 :                CALL cp_fm_create(fm_tmp, matrix_struct, set_zero=.TRUE.)
    1100              :                CALL cp_fm_struct_create(matrix_struct_new, &
    1101              :                                         template_fmstruct=matrix_struct, &
    1102              :                                         nrow_global=k, &
    1103        13327 :                                         ncol_global=k)
    1104        13327 :                CALL cp_fm_create(csc, matrix_struct_new, set_zero=.TRUE.)
    1105        13327 :                CALL cp_fm_struct_release(matrix_struct_new)
    1106              :                ! first the most recent
    1107              :                t1_state => wfi_get_snapshot(wf_history, &
    1108        13327 :                                             wf_index=1)
    1109        13327 :                CALL cp_fm_to_fm(t1_state%wf(ispin), mo_coeff)
    1110        13327 :                alpha = REAL(4*nvec - 2, KIND=dp)/REAL(nvec + 1, KIND=dp)
    1111        13327 :                IF ((io_unit > 0) .AND. (print_level > low_print_level)) THEN
    1112              :                   WRITE (UNIT=io_unit, FMT="(/,T2,A,/,/,T3,A,I0,/,/,T3,A2,I0,A4,F10.6)") &
    1113         2505 :                      "Parameters for the always stable predictor-corrector (ASPC) method:", &
    1114         2505 :                      "ASPC order: ", MAX(nvec - 2, 0), &
    1115         5010 :                      "B(", 1, ") = ", alpha
    1116              :                END IF
    1117        13327 :                CALL cp_fm_scale(alpha, mo_coeff)
    1118              : 
    1119        51237 :                DO i = 2, nvec
    1120        37910 :                   t0_state => wfi_get_snapshot(wf_history, wf_index=i)
    1121        37910 :                   IF (use_overlap) THEN
    1122        26370 :                      CALL cp_dbcsr_sm_fm_multiply(t0_state%overlap, t1_state%wf(ispin), fm_tmp, k)
    1123        26370 :                      CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, t0_state%wf(ispin), fm_tmp, 0.0_dp, csc)
    1124              :                   ELSE
    1125              :                      CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, t0_state%wf(ispin), &
    1126        11540 :                                         t1_state%wf(ispin), 0.0_dp, csc)
    1127              :                   END IF
    1128        37910 :                   CALL parallel_gemm('N', 'N', n, k, k, 1.0_dp, t0_state%wf(ispin), csc, 0.0_dp, fm_tmp)
    1129              :                   alpha = (-1.0_dp)**(i + 1)*REAL(i, KIND=dp)* &
    1130        37910 :                           binomial(2*nvec, nvec - i)/binomial(2*nvec - 2, nvec - 1)
    1131        37910 :                   IF ((io_unit > 0) .AND. (print_level > low_print_level)) THEN
    1132              :                      WRITE (UNIT=io_unit, FMT="(T3,A2,I0,A4,F10.6)") &
    1133         7212 :                         "B(", i, ") = ", alpha
    1134              :                   END IF
    1135        51237 :                   CALL cp_fm_scale_and_add(1.0_dp, mo_coeff, alpha, fm_tmp)
    1136              :                END DO
    1137        13327 :                CALL cp_fm_release(csc)
    1138        13327 :                CALL cp_fm_release(fm_tmp)
    1139              :                CALL reorthogonalize_vectors(qs_env, &
    1140              :                                             v_matrix=mo_coeff, &
    1141        13327 :                                             n_col=k)
    1142              :                CALL calculate_density_matrix(mo_set=mos(ispin), &
    1143        39398 :                                              density_matrix=rho_ao(ispin)%matrix)
    1144              :             END DO
    1145        12744 :             CALL qs_rho_update_rho(rho, qs_env=qs_env)
    1146        12744 :             CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
    1147              :          END IF ! do_kpoints
    1148              : 
    1149              :       CASE (wfi_gext_proj_nr)
    1150           24 :          CPASSERT(.NOT. do_kpoints)
    1151              : 
    1152              :          ! figure out the actual number of vectors to use in the extrapolation:
    1153           24 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
    1154           24 :          IF (nvec >= wf_history%memory_depth) THEN
    1155            8 :             IF ((qs_env%scf_control%max_scf_hist /= 0) .AND. &
    1156              :                 (qs_env%scf_control%eps_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%eps_scf = qs_env%scf_control%eps_scf_hist
    1159            0 :                qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1160            8 :             ELSE IF (qs_env%scf_control%max_scf_hist /= 0) THEN
    1161            0 :                qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1162            0 :                qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1163            8 :             ELSE IF (qs_env%scf_control%eps_scf_hist /= 0) THEN
    1164            0 :                qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1165              :             END IF
    1166              :          END IF
    1167           24 :          CPASSERT(nvec > 0)
    1168              : 
    1169              :          ! get the coefficients for the fitting
    1170           72 :          ALLOCATE (coeffs(nvec))
    1171           24 :          NULLIFY (matrix_s)
    1172           24 :          CALL get_qs_env(qs_env, matrix_s=matrix_s)
    1173              :          CALL diff_fitting(wf_history, matrix_s(1)%matrix, coeffs, nvec, &
    1174           24 :                            1e-4_dp, io_unit, print_level)
    1175              : 
    1176           24 :          my_orthogonal_wf = .TRUE.
    1177           24 :          CALL qs_rho_get(rho, rho_ao=rho_ao)
    1178           48 :          DO ispin = 1, SIZE(mos)
    1179           24 :             NULLIFY (mo_coeff, matrix_struct, matrix_struct_new)
    1180           24 :             CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff)
    1181              :             CALL cp_fm_get_info(mo_coeff, &
    1182              :                                 nrow_global=n, &
    1183              :                                 ncol_global=k, &
    1184           24 :                                 matrix_struct=matrix_struct)
    1185           24 :             CALL cp_fm_create(fm_tmp, matrix_struct)
    1186              :             CALL cp_fm_struct_create(matrix_struct_new, &
    1187              :                                      template_fmstruct=matrix_struct, &
    1188              :                                      nrow_global=k, &
    1189           24 :                                      ncol_global=k)
    1190           24 :             CALL cp_fm_create(csc, matrix_struct_new)
    1191           24 :             CALL cp_fm_struct_release(matrix_struct_new)
    1192              : 
    1193           24 :             t1_state => wfi_get_snapshot(wf_history, wf_index=1)
    1194              : 
    1195              :             ! do the linear combination of previous PSs
    1196           24 :             CALL cp_fm_set_all(mo_coeff, 0.0_dp)
    1197          104 :             DO i = 1, nvec
    1198           80 :                t0_state => wfi_get_snapshot(wf_history, wf_index=i)
    1199           80 :                CALL cp_dbcsr_sm_fm_multiply(t0_state%overlap, t1_state%wf(ispin), fm_tmp, k)
    1200           80 :                CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, t0_state%wf(ispin), fm_tmp, 0.0_dp, csc)
    1201           80 :                CALL parallel_gemm('N', 'N', n, k, k, 1.0_dp, t0_state%wf(ispin), csc, 0.0_dp, fm_tmp)
    1202          104 :                CALL cp_fm_scale_and_add(1.0_dp, mo_coeff, coeffs(i), fm_tmp)
    1203              :             END DO
    1204           24 :             CALL cp_fm_release(csc)
    1205           24 :             CALL cp_fm_release(fm_tmp)
    1206              :             CALL reorthogonalize_vectors(qs_env, &
    1207              :                                          v_matrix=mo_coeff, &
    1208           24 :                                          n_col=k)
    1209              :             CALL calculate_density_matrix(mo_set=mos(ispin), &
    1210           96 :                                           density_matrix=rho_ao(ispin)%matrix)
    1211              :          END DO
    1212           24 :          CALL qs_rho_update_rho(rho, qs_env=qs_env)
    1213           24 :          CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
    1214              : 
    1215           24 :          DEALLOCATE (coeffs)
    1216              : 
    1217              :       CASE (wfi_gext_proj_qtr_nr)
    1218           24 :          CPASSERT(.NOT. do_kpoints)
    1219              : 
    1220              :          ! figure out the actual number of vectors to use in the extrapolation:
    1221           24 :          nvec = MIN(wf_history%memory_depth, wf_history%snapshot_count)
    1222           24 :          IF (nvec >= wf_history%memory_depth) THEN
    1223            8 :             IF ((qs_env%scf_control%max_scf_hist /= 0) .AND. &
    1224              :                 (qs_env%scf_control%eps_scf_hist /= 0)) THEN
    1225            0 :                qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1226            0 :                qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1227            0 :                qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1228            8 :             ELSE IF (qs_env%scf_control%max_scf_hist /= 0) THEN
    1229            0 :                qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1230            0 :                qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1231            8 :             ELSE IF (qs_env%scf_control%eps_scf_hist /= 0) THEN
    1232            0 :                qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1233              :             END IF
    1234              :          END IF
    1235           24 :          CPASSERT(nvec > 0)
    1236              : 
    1237              :          ! get the coefficients for the fitting
    1238           72 :          ALLOCATE (coeffs(nvec))
    1239           24 :          NULLIFY (matrix_s)
    1240           24 :          CALL get_qs_env(qs_env, matrix_s=matrix_s)
    1241              :          CALL tr_fitting(wf_history, matrix_s(1)%matrix, coeffs, nvec, &
    1242           24 :                          1e-4_dp, io_unit, print_level)
    1243              : 
    1244           24 :          my_orthogonal_wf = .TRUE.
    1245           24 :          CALL qs_rho_get(rho, rho_ao=rho_ao)
    1246           48 :          DO ispin = 1, SIZE(mos)
    1247           24 :             NULLIFY (mo_coeff, matrix_struct, matrix_struct_new)
    1248           24 :             CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff)
    1249              :             CALL cp_fm_get_info(mo_coeff, &
    1250              :                                 nrow_global=n, &
    1251              :                                 ncol_global=k, &
    1252           24 :                                 matrix_struct=matrix_struct)
    1253           24 :             CALL cp_fm_create(fm_tmp, matrix_struct)
    1254              :             CALL cp_fm_struct_create(matrix_struct_new, &
    1255              :                                      template_fmstruct=matrix_struct, &
    1256              :                                      nrow_global=k, &
    1257           24 :                                      ncol_global=k)
    1258           24 :             CALL cp_fm_create(csc, matrix_struct_new)
    1259           24 :             CALL cp_fm_struct_release(matrix_struct_new)
    1260              : 
    1261           24 :             t1_state => wfi_get_snapshot(wf_history, wf_index=1)
    1262              : 
    1263              :             ! do the linear combination of previous PSs
    1264           24 :             CALL cp_fm_set_all(mo_coeff, 0.0_dp)
    1265          104 :             DO i = 1, nvec
    1266           80 :                t0_state => wfi_get_snapshot(wf_history, wf_index=i)
    1267           80 :                CALL cp_dbcsr_sm_fm_multiply(t0_state%overlap, t1_state%wf(ispin), fm_tmp, k)
    1268           80 :                CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, t0_state%wf(ispin), fm_tmp, 0.0_dp, csc)
    1269           80 :                CALL parallel_gemm('N', 'N', n, k, k, 1.0_dp, t0_state%wf(ispin), csc, 0.0_dp, fm_tmp)
    1270          104 :                CALL cp_fm_scale_and_add(1.0_dp, mo_coeff, coeffs(i), fm_tmp)
    1271              :             END DO
    1272           24 :             CALL cp_fm_release(csc)
    1273           24 :             CALL cp_fm_release(fm_tmp)
    1274              :             CALL reorthogonalize_vectors(qs_env, &
    1275              :                                          v_matrix=mo_coeff, &
    1276           24 :                                          n_col=k)
    1277              :             CALL calculate_density_matrix(mo_set=mos(ispin), &
    1278           96 :                                           density_matrix=rho_ao(ispin)%matrix)
    1279              :          END DO
    1280           24 :          CALL qs_rho_update_rho(rho, qs_env=qs_env)
    1281           24 :          CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
    1282              : 
    1283           24 :          DEALLOCATE (coeffs)
    1284              : 
    1285              :       CASE default
    1286              :          CALL cp_abort(__LOCATION__, &
    1287              :                        "Unknown interpolation method: "// &
    1288        21295 :                        TRIM(ADJUSTL(cp_to_string(wf_history%interpolation_method_nr))))
    1289              :       END SELECT
    1290        21295 :       IF (PRESENT(orthogonal_wf)) orthogonal_wf = my_orthogonal_wf
    1291              :       CALL cp_print_key_finished_output(io_unit, logger, qs_env%input, &
    1292        21295 :                                         "DFT%SCF%PRINT%PROGRAM_RUN_INFO")
    1293        21295 :       CALL timestop(handle)
    1294        21295 :    END SUBROUTINE wfi_extrapolate
    1295              : 
    1296              : ! **************************************************************************************************
    1297              : !> \brief Reorthogonalizes the wavefunctions from the previous step for k-points
    1298              : !>        using the current S(k) metric and rebuilds the density matrix.
    1299              : !> \param qs_env The QS environment
    1300              : !> \param io_unit output unit
    1301              : !> \param print_level print level
    1302              : ! **************************************************************************************************
    1303          368 :    SUBROUTINE wfi_use_prev_wf_kp(qs_env, io_unit, print_level)
    1304              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1305              :       INTEGER, INTENT(IN)                                :: io_unit, print_level
    1306              : 
    1307              :       CHARACTER(len=*), PARAMETER :: routineN = 'wfi_use_prev_wf_kp'
    1308              : 
    1309          368 :       COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:)        :: col_scaling
    1310              :       INTEGER                                            :: chol_info, handle, igroup, ik, ikp, &
    1311              :                                                             indx, ispin, j, kplocal, nao, nkp, &
    1312              :                                                             nkp_groups, nmo, nspin
    1313              :       INTEGER, DIMENSION(2)                              :: kp_range
    1314          368 :       INTEGER, DIMENSION(:, :), POINTER                  :: kp_dist
    1315          368 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
    1316              :       LOGICAL                                            :: my_kpgrp, use_real_wfn
    1317              :       REAL(KIND=dp)                                      :: eval_thresh
    1318          368 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenvalues
    1319          368 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: xkp
    1320          368 :       TYPE(copy_info_type), ALLOCATABLE, DIMENSION(:, :) :: info
    1321              :       TYPE(cp_cfm_type)                                  :: cfm_evecs, cfm_mhalf, cfm_nao_nmo_work, &
    1322              :                                                             cmos_new, csc_cfm
    1323          368 :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:)       :: csmat_cur
    1324          368 :       TYPE(cp_fm_pool_p_type), DIMENSION(:), POINTER     :: ao_ao_fm_pools_kp
    1325              :       TYPE(cp_fm_struct_type), POINTER                   :: ao_ao_struct, nmo_nmo_struct
    1326              :       TYPE(cp_fm_type)                                   :: fmdummy, fmlocal
    1327              :       TYPE(cp_fm_type), POINTER                          :: imos, mo_coeff, rmos
    1328          368 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_s_kp, rho_ao_kp
    1329              :       TYPE(dbcsr_type), POINTER                          :: cmatrix_db, rmatrix, tmpmat
    1330              :       TYPE(dft_control_type), POINTER                    :: dft_control
    1331              :       TYPE(kpoint_env_type), POINTER                     :: kp
    1332              :       TYPE(kpoint_type), POINTER                         :: kpoints
    1333              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1334              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    1335          368 :          POINTER                                         :: sab_nl
    1336              :       TYPE(qs_matrix_pools_type), POINTER                :: mpools_kp
    1337              :       TYPE(qs_rho_type), POINTER                         :: rho
    1338              :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
    1339              :       TYPE(scf_control_type), POINTER                    :: scf_control
    1340              : 
    1341          368 :       CALL timeset(routineN, handle)
    1342              : 
    1343          368 :       NULLIFY (kpoints, dft_control, matrix_s_kp, scf_env, scf_control, rho, sab_nl, kp, mo_coeff, rmos, imos)
    1344              : 
    1345              :       CALL get_qs_env(qs_env, kpoints=kpoints, dft_control=dft_control, &
    1346              :                       matrix_s_kp=matrix_s_kp, scf_env=scf_env, &
    1347          368 :                       scf_control=scf_control, rho=rho)
    1348              :       CALL get_kpoint_info(kpoints, nkp=nkp, xkp=xkp, use_real_wfn=use_real_wfn, &
    1349              :                            kp_range=kp_range, nkp_groups=nkp_groups, kp_dist=kp_dist, &
    1350          368 :                            sab_nl=sab_nl, cell_to_index=cell_to_index)
    1351          368 :       kplocal = kp_range(2) - kp_range(1) + 1
    1352              : 
    1353          368 :       IF (use_real_wfn) THEN
    1354            0 :          CALL timestop(handle)
    1355            0 :          RETURN
    1356              :       END IF
    1357              : 
    1358          368 :       kp => kpoints%kp_env(1)%kpoint_env
    1359          368 :       nspin = SIZE(kp%mos, 2)
    1360          368 :       CALL get_mo_set(kp%mos(1, 1), nao=nao, nmo=nmo, mo_coeff=mo_coeff)
    1361              : 
    1362          368 :       IF ((io_unit > 0) .AND. (print_level > low_print_level)) THEN
    1363              :          WRITE (UNIT=io_unit, FMT="(/,T2,A)") &
    1364            0 :             "Using previous wavefunctions as initial guess for k-points (with reorthogonalization)"
    1365              :       END IF
    1366              : 
    1367              :       ! Allocate dbcsr work matrices
    1368          368 :       ALLOCATE (rmatrix, cmatrix_db, tmpmat)
    1369          368 :       CALL dbcsr_create(rmatrix, template=matrix_s_kp(1, 1)%matrix, matrix_type=dbcsr_type_symmetric)
    1370          368 :       CALL dbcsr_create(cmatrix_db, template=matrix_s_kp(1, 1)%matrix, matrix_type=dbcsr_type_antisymmetric)
    1371          368 :       CALL dbcsr_create(tmpmat, template=matrix_s_kp(1, 1)%matrix, matrix_type=dbcsr_type_no_symmetry)
    1372          368 :       CALL cp_dbcsr_alloc_block_from_nbl(rmatrix, sab_nl)
    1373          368 :       CALL cp_dbcsr_alloc_block_from_nbl(cmatrix_db, sab_nl)
    1374              : 
    1375          368 :       CALL get_kpoint_info(kpoints, mpools=mpools_kp)
    1376          368 :       CALL mpools_get(mpools_kp, ao_ao_fm_pools=ao_ao_fm_pools_kp)
    1377          368 :       CALL fm_pool_create_fm(ao_ao_fm_pools_kp(1)%pool, fmlocal)
    1378          368 :       CALL cp_fm_get_info(fmlocal, matrix_struct=ao_ao_struct)
    1379              : 
    1380          368 :       CALL cp_cfm_create(cmos_new, mo_coeff%matrix_struct)
    1381          368 :       CALL cp_cfm_create(cfm_nao_nmo_work, mo_coeff%matrix_struct)
    1382              : 
    1383          368 :       NULLIFY (nmo_nmo_struct)
    1384              :       CALL cp_fm_struct_create(nmo_nmo_struct, template_fmstruct=mo_coeff%matrix_struct, &
    1385          368 :                                nrow_global=nmo, ncol_global=nmo)
    1386          368 :       CALL cp_cfm_create(csc_cfm, nmo_nmo_struct)
    1387          368 :       CALL cp_fm_struct_release(nmo_nmo_struct)
    1388              : 
    1389          368 :       para_env => kpoints%blacs_env_all%para_env
    1390         7456 :       ALLOCATE (info(kplocal*nkp_groups, 2))
    1391              : 
    1392         2104 :       ALLOCATE (csmat_cur(kplocal))
    1393         1368 :       DO ikp = 1, kplocal
    1394         1368 :          CALL cp_cfm_create(csmat_cur(ikp), ao_ao_struct)
    1395              :       END DO
    1396              : 
    1397              :       ! Phase A: Fourier Transform S(R) -> S(k)
    1398              :       indx = 0
    1399         1368 :       DO ikp = 1, kplocal
    1400         3072 :          DO igroup = 1, nkp_groups
    1401         1704 :             ik = kp_dist(1, igroup) + ikp - 1
    1402         1704 :             my_kpgrp = (ik >= kp_range(1) .AND. ik <= kp_range(2))
    1403         1704 :             indx = indx + 1
    1404              : 
    1405         1704 :             CALL dbcsr_set(rmatrix, 0.0_dp)
    1406         1704 :             CALL dbcsr_set(cmatrix_db, 0.0_dp)
    1407              :             CALL rskp_transform(rmatrix=rmatrix, cmatrix=cmatrix_db, rsmat=matrix_s_kp, &
    1408         1704 :                                 ispin=1, xkp=xkp(1:3, ik), cell_to_index=cell_to_index, sab_nl=sab_nl)
    1409         1704 :             CALL dbcsr_desymmetrize(rmatrix, tmpmat)
    1410         1704 :             CALL copy_dbcsr_to_fm(tmpmat, scf_env%scf_work1(1))
    1411         1704 :             CALL dbcsr_desymmetrize(cmatrix_db, tmpmat)
    1412         1704 :             CALL copy_dbcsr_to_fm(tmpmat, scf_env%scf_work1(2))
    1413              : 
    1414         2704 :             IF (my_kpgrp) THEN
    1415         1000 :                CALL cp_fm_start_copy_general(scf_env%scf_work1(1), fmlocal, para_env, info(indx, 1))
    1416         1000 :                CALL cp_fm_start_copy_general(scf_env%scf_work1(2), fmlocal, para_env, info(indx, 2))
    1417              :             ELSE
    1418          704 :                CALL cp_fm_start_copy_general(scf_env%scf_work1(1), fmdummy, para_env, info(indx, 1))
    1419          704 :                CALL cp_fm_start_copy_general(scf_env%scf_work1(2), fmdummy, para_env, info(indx, 2))
    1420              :             END IF
    1421              :          END DO
    1422              :       END DO
    1423              : 
    1424              :       ! Finish Communication
    1425              :       indx = 0
    1426         1368 :       DO ikp = 1, kplocal
    1427         3072 :          DO igroup = 1, nkp_groups
    1428         1704 :             ik = kp_dist(1, igroup) + ikp - 1
    1429         1704 :             my_kpgrp = (ik >= kp_range(1) .AND. ik <= kp_range(2))
    1430          704 :             indx = indx + 1
    1431         1000 :             IF (my_kpgrp) THEN
    1432         1000 :                CALL cp_fm_finish_copy_general(fmlocal, info(indx, 1))
    1433         1000 :                CALL cp_cfm_scale_and_add_fm(z_zero, csmat_cur(ikp), z_one, fmlocal)
    1434         1000 :                CALL cp_fm_finish_copy_general(fmlocal, info(indx, 2))
    1435         1000 :                CALL cp_cfm_scale_and_add_fm(z_one, csmat_cur(ikp), gaussi, fmlocal)
    1436              :             END IF
    1437              :          END DO
    1438              :       END DO
    1439              : 
    1440         2072 :       DO indx = 1, kplocal*nkp_groups
    1441         1704 :          CALL cp_fm_cleanup_copy_general(info(indx, 1))
    1442         2072 :          CALL cp_fm_cleanup_copy_general(info(indx, 2))
    1443              :       END DO
    1444              : 
    1445              :       ! Phase B: Orthogonalize current MOs w.r.t. new S(k)
    1446         1104 :       ALLOCATE (eigenvalues(nmo))
    1447          368 :       eval_thresh = 1.0E-12_dp
    1448              : 
    1449         1368 :       DO ikp = 1, kplocal
    1450         1000 :          kp => kpoints%kp_env(ikp)%kpoint_env
    1451         2560 :          DO ispin = 1, nspin
    1452         1192 :             CALL get_mo_set(kp%mos(1, ispin), mo_coeff=rmos)
    1453         1192 :             CALL get_mo_set(kp%mos(2, ispin), mo_coeff=imos)
    1454         1192 :             CALL cp_fm_to_cfm(rmos, imos, cmos_new)
    1455              : 
    1456              :             CALL cp_cfm_gemm('N', 'N', nao, nmo, nao, z_one, &
    1457         1192 :                              csmat_cur(ikp), cmos_new, z_zero, cfm_nao_nmo_work)
    1458              :             CALL cp_cfm_gemm('C', 'N', nmo, nmo, nao, z_one, &
    1459         1192 :                              cmos_new, cfm_nao_nmo_work, z_zero, csc_cfm)
    1460              : 
    1461         1192 :             CALL cp_cfm_cholesky_decompose(csc_cfm, info_out=chol_info)
    1462         1192 :             IF (chol_info == 0) THEN
    1463         1192 :                CALL cp_cfm_triangular_multiply(csc_cfm, cmos_new, side='R', invert_tr=.TRUE., uplo_tr='U')
    1464              :             ELSE
    1465            0 :                CALL cp_cfm_gemm('C', 'N', nmo, nmo, nao, z_one, cmos_new, cfm_nao_nmo_work, z_zero, csc_cfm)
    1466            0 :                CALL cp_cfm_create(cfm_evecs, csc_cfm%matrix_struct)
    1467            0 :                CALL cp_cfm_create(cfm_mhalf, csc_cfm%matrix_struct)
    1468            0 :                CALL cp_cfm_heevd(csc_cfm, cfm_evecs, eigenvalues)
    1469            0 :                CALL cp_cfm_to_cfm(cfm_evecs, cfm_mhalf)
    1470            0 :                ALLOCATE (col_scaling(nmo))
    1471            0 :                DO j = 1, nmo
    1472            0 :                   IF (eigenvalues(j) > eval_thresh) THEN
    1473            0 :                      col_scaling(j) = CMPLX(1.0_dp/SQRT(eigenvalues(j)), 0.0_dp, KIND=dp)
    1474              :                   ELSE
    1475            0 :                      col_scaling(j) = z_zero
    1476              :                   END IF
    1477              :                END DO
    1478            0 :                CALL cp_cfm_column_scale(cfm_mhalf, col_scaling)
    1479            0 :                DEALLOCATE (col_scaling)
    1480            0 :                CALL cp_cfm_gemm('N', 'C', nmo, nmo, nmo, z_one, cfm_mhalf, cfm_evecs, z_zero, csc_cfm)
    1481            0 :                CALL cp_cfm_gemm('N', 'N', nao, nmo, nmo, z_one, cmos_new, csc_cfm, z_zero, cfm_nao_nmo_work)
    1482            0 :                CALL cp_cfm_to_cfm(cfm_nao_nmo_work, cmos_new)
    1483            0 :                CALL cp_cfm_release(cfm_evecs)
    1484            0 :                CALL cp_cfm_release(cfm_mhalf)
    1485              :             END IF
    1486         3384 :             CALL cp_cfm_to_fm(cmos_new, rmos, imos)
    1487              :          END DO
    1488              :       END DO
    1489          368 :       DEALLOCATE (eigenvalues)
    1490              : 
    1491              :       ! Phase C: Rebuild Density Matrix P(R)
    1492          368 :       CALL kpoint_set_mo_occupation(kpoints, scf_control%smear)
    1493          368 :       CALL kpoint_density_matrices(kpoints)
    1494          368 :       CALL qs_rho_get(rho, rho_ao_kp=rho_ao_kp)
    1495              :       CALL kpoint_density_transform(kpoints, rho_ao_kp, .FALSE., &
    1496          368 :                                     matrix_s_kp(1, 1)%matrix, sab_nl, scf_env%scf_work1)
    1497          368 :       CALL qs_rho_update_rho(rho, qs_env=qs_env)
    1498          368 :       CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
    1499              : 
    1500              :       ! Cleanup
    1501         1368 :       DO ikp = 1, kplocal
    1502         1368 :          CALL cp_cfm_release(csmat_cur(ikp))
    1503              :       END DO
    1504          368 :       DEALLOCATE (csmat_cur)
    1505         3776 :       DEALLOCATE (info)
    1506          368 :       CALL cp_cfm_release(cmos_new)
    1507          368 :       CALL cp_cfm_release(cfm_nao_nmo_work)
    1508          368 :       CALL cp_cfm_release(csc_cfm)
    1509          368 :       CALL fm_pool_give_back_fm(ao_ao_fm_pools_kp(1)%pool, fmlocal)
    1510          368 :       CALL dbcsr_deallocate_matrix(rmatrix)
    1511          368 :       CALL dbcsr_deallocate_matrix(cmatrix_db)
    1512          368 :       CALL dbcsr_deallocate_matrix(tmpmat)
    1513              : 
    1514          368 :       CALL timestop(handle)
    1515         2208 :    END SUBROUTINE wfi_use_prev_wf_kp
    1516              : 
    1517              : ! **************************************************************************************************
    1518              : !> \brief Performs PS/ASPC wavefunction extrapolation for k-point calculations.
    1519              : !>        Applies PS/ASPC coefficients to complex MO coefficients at each k-point,
    1520              : !>        with subspace alignment via historical overlap matrices.
    1521              : !>        Delegates final orthogonalization and density building to wfi_use_prev_wf_kp.
    1522              : !> \param wf_history  wavefunction history buffer
    1523              : !> \param qs_env      QS environment
    1524              : !> \param nvec        number of history snapshots to use
    1525              : !> \param io_unit     output unit for logging
    1526              : !> \param print_level current print level
    1527              : ! **************************************************************************************************
    1528          724 :    SUBROUTINE wfi_extrapolate_ps_aspc_kp(wf_history, qs_env, nvec, io_unit, print_level)
    1529              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
    1530              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1531              :       INTEGER, INTENT(IN)                                :: nvec, io_unit, print_level
    1532              : 
    1533              :       CHARACTER(len=*), PARAMETER :: routineN = 'wfi_extrapolate_ps_aspc_kp'
    1534              : 
    1535              :       INTEGER                                            :: handle, i, ikp, ispin, kplocal, &
    1536              :                                                             method_nr, nao, nmo, nspin
    1537              :       INTEGER, DIMENSION(2)                              :: kp_range
    1538              :       LOGICAL                                            :: use_real_wfn
    1539              :       REAL(KIND=dp)                                      :: alpha_coeff
    1540              :       TYPE(cp_cfm_type)                                  :: cfm_nao_nmo_work, cmos_1, cmos_i, &
    1541              :                                                             cmos_new, csc_cfm
    1542              :       TYPE(cp_fm_struct_type), POINTER                   :: nmo_nmo_struct
    1543              :       TYPE(cp_fm_type), POINTER                          :: imos, mo_coeff, rmos
    1544              :       TYPE(kpoint_env_type), POINTER                     :: kp
    1545              :       TYPE(kpoint_type), POINTER                         :: kpoints
    1546              :       TYPE(qs_wf_snapshot_type), POINTER                 :: t0_state, t1_state
    1547              : 
    1548          362 :       method_nr = wf_history%interpolation_method_nr
    1549              : 
    1550          362 :       CALL timeset(routineN, handle)
    1551          362 :       NULLIFY (kpoints, kp, mo_coeff, rmos, imos, t0_state, t1_state, nmo_nmo_struct)
    1552              : 
    1553          362 :       CALL get_qs_env(qs_env, kpoints=kpoints)
    1554          362 :       CALL get_kpoint_info(kpoints, use_real_wfn=use_real_wfn, kp_range=kp_range)
    1555          362 :       kplocal = kp_range(2) - kp_range(1) + 1
    1556              : 
    1557          362 :       IF (use_real_wfn) THEN
    1558            0 :          IF (method_nr == wfi_aspc_nr) THEN
    1559              :             CALL cp_warn(__LOCATION__, "ASPC with k-points requires complex wavefunctions; "// &
    1560            0 :                          "falling back to USE_PREV_WF.")
    1561              :          ELSE
    1562              :             CALL cp_warn(__LOCATION__, "PS with k-points requires complex wavefunctions; "// &
    1563            0 :                          "falling back to USE_PREV_WF.")
    1564              :          END IF
    1565            0 :          CALL wfi_use_prev_wf_kp(qs_env, io_unit, print_level)
    1566            0 :          CALL timestop(handle)
    1567            0 :          RETURN
    1568              :       END IF
    1569              : 
    1570          362 :       kp => kpoints%kp_env(1)%kpoint_env
    1571          362 :       nspin = SIZE(kp%mos, 2)
    1572          362 :       CALL get_mo_set(kp%mos(1, 1), nao=nao, nmo=nmo, mo_coeff=mo_coeff)
    1573              : 
    1574          362 :       IF (method_nr == wfi_aspc_nr) THEN
    1575          358 :          IF ((io_unit > 0) .AND. (print_level > low_print_level)) THEN
    1576              :             WRITE (UNIT=io_unit, FMT="(/,T2,A,/,T3,A,I0)") &
    1577            7 :                "Parameters for the always stable predictor-corrector (ASPC) method:", &
    1578           14 :                "ASPC order: ", MAX(nvec - 2, 0)
    1579              :          END IF
    1580              :       END IF
    1581              : 
    1582           16 :       IF (method_nr == wfi_aspc_nr) THEN
    1583          358 :          CALL cp_cfm_create(cmos_new, mo_coeff%matrix_struct, set_zero=.TRUE.)
    1584          358 :          CALL cp_cfm_create(cmos_1, mo_coeff%matrix_struct, set_zero=.TRUE.)
    1585          358 :          CALL cp_cfm_create(cmos_i, mo_coeff%matrix_struct, set_zero=.TRUE.)
    1586          358 :          CALL cp_cfm_create(cfm_nao_nmo_work, mo_coeff%matrix_struct, set_zero=.TRUE.)
    1587              :       ELSE
    1588            4 :          CALL cp_cfm_create(cmos_new, mo_coeff%matrix_struct)
    1589            4 :          CALL cp_cfm_create(cmos_1, mo_coeff%matrix_struct)
    1590            4 :          CALL cp_cfm_create(cmos_i, mo_coeff%matrix_struct)
    1591            4 :          CALL cp_cfm_create(cfm_nao_nmo_work, mo_coeff%matrix_struct)
    1592              :       END IF
    1593              : 
    1594              :       CALL cp_fm_struct_create(nmo_nmo_struct, template_fmstruct=mo_coeff%matrix_struct, &
    1595          362 :                                nrow_global=nmo, ncol_global=nmo)
    1596          362 :       IF (method_nr == wfi_aspc_nr) THEN
    1597          358 :          CALL cp_cfm_create(csc_cfm, nmo_nmo_struct, set_zero=.TRUE.)
    1598              :       ELSE
    1599            4 :          CALL cp_cfm_create(csc_cfm, nmo_nmo_struct)
    1600              :       END IF
    1601          362 :       CALL cp_fm_struct_release(nmo_nmo_struct)
    1602              : 
    1603              :       ! Phase 1: Initialize C_new(k) = B(1) * C_1(k)
    1604          362 :       t1_state => wfi_get_snapshot(wf_history, wf_index=1)
    1605          362 :       IF (method_nr == wfi_aspc_nr) THEN
    1606          358 :          alpha_coeff = REAL(4*nvec - 2, KIND=dp)/REAL(nvec + 1, KIND=dp)
    1607          358 :          IF ((io_unit > 0) .AND. (print_level > low_print_level)) THEN
    1608            7 :             WRITE (UNIT=io_unit, FMT="(T3,A2,I0,A4,F10.6)") "B(", 1, ") = ", alpha_coeff
    1609              :          END IF
    1610              :       ELSE
    1611            4 :          alpha_coeff = nvec
    1612              :       END IF
    1613              : 
    1614         1338 :       DO ikp = 1, kplocal
    1615          976 :          kp => kpoints%kp_env(ikp)%kpoint_env
    1616         2506 :          DO ispin = 1, nspin
    1617         1168 :             CALL get_mo_set(kp%mos(1, ispin), mo_coeff=rmos)
    1618         1168 :             CALL get_mo_set(kp%mos(2, ispin), mo_coeff=imos)
    1619         1168 :             CALL cp_fm_to_fm(t1_state%wf_kp(ikp, 1, ispin), rmos)
    1620         1168 :             CALL cp_fm_to_fm(t1_state%wf_kp(ikp, 2, ispin), imos)
    1621         1168 :             CALL cp_fm_scale(alpha_coeff, rmos)
    1622         2144 :             CALL cp_fm_scale(alpha_coeff, imos)
    1623              :          END DO
    1624              :       END DO
    1625              : 
    1626              :       ! Phase 2: Accumulate historical snapshots C_new += B(i) * C_proj(k)
    1627         1544 :       DO i = 2, nvec
    1628         1182 :          t0_state => wfi_get_snapshot(wf_history, wf_index=i)
    1629         1182 :          IF (method_nr == wfi_aspc_nr) THEN
    1630              :             alpha_coeff = (-1.0_dp)**(i + 1)*REAL(i, KIND=dp)* &
    1631         1180 :                           binomial(2*nvec, nvec - i)/binomial(2*nvec - 2, nvec - 1)
    1632         1180 :             IF ((io_unit > 0) .AND. (print_level > low_print_level)) THEN
    1633            5 :                WRITE (UNIT=io_unit, FMT="(T3,A2,I0,A4,F10.6)") "B(", i, ") = ", alpha_coeff
    1634              :             END IF
    1635              :          ELSE
    1636            2 :             alpha_coeff = -1.0_dp*alpha_coeff*REAL(nvec - i + 1, dp)/REAL(i, dp)
    1637              :          END IF
    1638              : 
    1639         3816 :          DO ikp = 1, kplocal
    1640         2272 :             kp => kpoints%kp_env(ikp)%kpoint_env
    1641         5822 :             DO ispin = 1, nspin
    1642         2368 :                CALL cp_fm_to_cfm(t1_state%wf_kp(ikp, 1, ispin), t1_state%wf_kp(ikp, 2, ispin), cmos_1)
    1643         2368 :                CALL cp_fm_to_cfm(t0_state%wf_kp(ikp, 1, ispin), t0_state%wf_kp(ikp, 2, ispin), cmos_i)
    1644              : 
    1645              :                ! Subspace projection: C_proj = C_i * (C_i^dag S_i C_1)
    1646              :                CALL cp_cfm_gemm('N', 'N', nao, nmo, nao, z_one, &
    1647         2368 :                                 t0_state%overlap_cfm_kp(ikp), cmos_1, z_zero, cfm_nao_nmo_work)
    1648              :                CALL cp_cfm_gemm('C', 'N', nmo, nmo, nao, z_one, &
    1649         2368 :                                 cmos_i, cfm_nao_nmo_work, z_zero, csc_cfm)
    1650              :                CALL cp_cfm_gemm('N', 'N', nao, nmo, nmo, z_one, &
    1651         2368 :                                 cmos_i, csc_cfm, z_zero, cfm_nao_nmo_work)
    1652              : 
    1653         2368 :                CALL get_mo_set(kp%mos(1, ispin), mo_coeff=rmos)
    1654         2368 :                CALL get_mo_set(kp%mos(2, ispin), mo_coeff=imos)
    1655         2368 :                CALL cp_fm_to_cfm(rmos, imos, cmos_new)
    1656         2368 :                CALL cp_cfm_scale_and_add(z_one, cmos_new, CMPLX(alpha_coeff, 0.0_dp, KIND=dp), cfm_nao_nmo_work)
    1657         4640 :                CALL cp_cfm_to_fm(cmos_new, rmos, imos)
    1658              :             END DO
    1659              :          END DO
    1660              :       END DO
    1661              : 
    1662          362 :       CALL cp_cfm_release(cmos_new)
    1663          362 :       CALL cp_cfm_release(cmos_1)
    1664          362 :       CALL cp_cfm_release(cmos_i)
    1665          362 :       CALL cp_cfm_release(cfm_nao_nmo_work)
    1666          362 :       CALL cp_cfm_release(csc_cfm)
    1667              : 
    1668              :       ! Phase 3: Delegate Orthogonalization and Density Building
    1669              :       ! We pass io_unit = 0 to suppress the redundant "Using previous..." print
    1670              :       ! inside wfi_use_prev_wf_kp, keeping the ASPC log output perfectly clean.
    1671          362 :       CALL wfi_use_prev_wf_kp(qs_env, 0, print_level)
    1672              : 
    1673          362 :       CALL timestop(handle)
    1674              : 
    1675          362 :    END SUBROUTINE wfi_extrapolate_ps_aspc_kp
    1676              : 
    1677              : ! **************************************************************************************************
    1678              : !> \brief Decides if scf control variables has to changed due
    1679              : !>      to using a WF extrapolation.
    1680              : !> \param qs_env The QS environment
    1681              : !> \param nvec ...
    1682              : !> \par History
    1683              : !>      11.2006 created [TdK]
    1684              : !> \author Thomas D. Kuehne (tkuehne@phys.chem.ethz.ch)
    1685              : ! **************************************************************************************************
    1686         7757 :    ELEMENTAL SUBROUTINE wfi_set_history_variables(qs_env, nvec)
    1687              :       TYPE(qs_environment_type), INTENT(INOUT)           :: qs_env
    1688              :       INTEGER, INTENT(IN)                                :: nvec
    1689              : 
    1690         7757 :       IF (nvec >= qs_env%wf_history%memory_depth) THEN
    1691         1289 :          IF ((qs_env%scf_control%max_scf_hist /= 0) .AND. (qs_env%scf_control%eps_scf_hist /= 0)) THEN
    1692            0 :             qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1693            0 :             qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1694            0 :             qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1695         1289 :          ELSE IF (qs_env%scf_control%max_scf_hist /= 0) THEN
    1696            0 :             qs_env%scf_control%max_scf = qs_env%scf_control%max_scf_hist
    1697            0 :             qs_env%scf_control%outer_scf%have_scf = .FALSE.
    1698         1289 :          ELSE IF (qs_env%scf_control%eps_scf_hist /= 0) THEN
    1699            0 :             qs_env%scf_control%eps_scf = qs_env%scf_control%eps_scf_hist
    1700            0 :             qs_env%scf_control%outer_scf%eps_scf = qs_env%scf_control%eps_scf_hist
    1701              :          END IF
    1702              :       END IF
    1703              : 
    1704         7757 :    END SUBROUTINE wfi_set_history_variables
    1705              : 
    1706              : ! **************************************************************************************************
    1707              : !> \brief updates the snapshot buffer, taking a new snapshot
    1708              : !> \param wf_history the history buffer to update
    1709              : !> \param qs_env the qs_env we get the info from
    1710              : !> \param dt ...
    1711              : !> \par History
    1712              : !>      02.2003 created [fawzi]
    1713              : !> \author fawzi
    1714              : ! **************************************************************************************************
    1715        21299 :    SUBROUTINE wfi_update(wf_history, qs_env, dt)
    1716              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
    1717              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1718              :       REAL(KIND=dp), INTENT(in)                          :: dt
    1719              : 
    1720        21299 :       CPASSERT(ASSOCIATED(wf_history))
    1721        21299 :       CPASSERT(wf_history%ref_count > 0)
    1722        21299 :       CPASSERT(ASSOCIATED(qs_env))
    1723              : 
    1724        21299 :       wf_history%snapshot_count = wf_history%snapshot_count + 1
    1725        21299 :       IF (wf_history%memory_depth > 0) THEN
    1726              :          wf_history%last_state_index = MODULO(wf_history%snapshot_count, &
    1727        20512 :                                               wf_history%memory_depth) + 1
    1728              :          CALL wfs_update(snapshot=wf_history%past_states &
    1729              :                          (wf_history%last_state_index)%snapshot, wf_history=wf_history, &
    1730        20512 :                          qs_env=qs_env, dt=dt)
    1731              :       END IF
    1732        21299 :    END SUBROUTINE wfi_update
    1733              : 
    1734              : ! **************************************************************************************************
    1735              : !> \brief reorthogonalizes the mos
    1736              : !> \param qs_env the qs_env in which to orthogonalize
    1737              : !> \param v_matrix the vectors to orthogonalize
    1738              : !> \param n_col number of column of v to orthogonalize
    1739              : !> \par History
    1740              : !>      04.2003 created [fawzi]
    1741              : !> \author Fawzi Mohamed
    1742              : ! **************************************************************************************************
    1743        28618 :    SUBROUTINE reorthogonalize_vectors(qs_env, v_matrix, n_col)
    1744              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1745              :       TYPE(cp_fm_type), INTENT(IN)                       :: v_matrix
    1746              :       INTEGER, INTENT(in), OPTIONAL                      :: n_col
    1747              : 
    1748              :       CHARACTER(len=*), PARAMETER :: routineN = 'reorthogonalize_vectors'
    1749              : 
    1750              :       INTEGER                                            :: handle, my_n_col
    1751              :       LOGICAL                                            :: has_unit_metric, &
    1752              :                                                             ortho_contains_cholesky, &
    1753              :                                                             smearing_is_used
    1754              :       TYPE(cp_fm_pool_type), POINTER                     :: maxao_maxmo_fm_pool
    1755        14309 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
    1756              :       TYPE(dft_control_type), POINTER                    :: dft_control
    1757              :       TYPE(qs_matrix_pools_type), POINTER                :: mpools
    1758              :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
    1759              :       TYPE(scf_control_type), POINTER                    :: scf_control
    1760              : 
    1761        14309 :       NULLIFY (scf_env, scf_control, maxao_maxmo_fm_pool, matrix_s, mpools, dft_control)
    1762        14309 :       CALL timeset(routineN, handle)
    1763              : 
    1764        14309 :       CPASSERT(ASSOCIATED(qs_env))
    1765              : 
    1766        14309 :       CALL cp_fm_get_info(v_matrix, ncol_global=my_n_col)
    1767        14309 :       IF (PRESENT(n_col)) my_n_col = n_col
    1768              :       CALL get_qs_env(qs_env, mpools=mpools, &
    1769              :                       scf_env=scf_env, &
    1770              :                       scf_control=scf_control, &
    1771              :                       matrix_s=matrix_s, &
    1772        14309 :                       dft_control=dft_control)
    1773        14309 :       CALL mpools_get(mpools, maxao_maxmo_fm_pool=maxao_maxmo_fm_pool)
    1774        14309 :       IF (ASSOCIATED(scf_env)) THEN
    1775              :          ortho_contains_cholesky = (scf_env%method /= ot_method_nr) .AND. &
    1776              :                                    (scf_env%cholesky_method > 0) .AND. &
    1777        14309 :                                    ASSOCIATED(scf_env%ortho)
    1778              :       ELSE
    1779              :          ortho_contains_cholesky = .FALSE.
    1780              :       END IF
    1781              : 
    1782        14309 :       CALL get_qs_env(qs_env, has_unit_metric=has_unit_metric)
    1783        14309 :       smearing_is_used = .FALSE.
    1784        14309 :       IF (dft_control%smear) THEN
    1785         1146 :          smearing_is_used = .TRUE.
    1786              :       END IF
    1787              : 
    1788        14309 :       IF (has_unit_metric) THEN
    1789         3410 :          CALL make_basis_simple(v_matrix, my_n_col)
    1790        10899 :       ELSE IF (smearing_is_used) THEN
    1791              :          CALL make_basis_lowdin(vmatrix=v_matrix, ncol=my_n_col, &
    1792         1146 :                                 matrix_s=matrix_s(1)%matrix)
    1793         9753 :       ELSE IF (ortho_contains_cholesky) THEN
    1794              :          CALL make_basis_cholesky(vmatrix=v_matrix, ncol=my_n_col, &
    1795         6342 :                                   ortho=scf_env%ortho)
    1796              :       ELSE
    1797         3411 :          CALL make_basis_sm(v_matrix, my_n_col, matrix_s(1)%matrix)
    1798              :       END IF
    1799        14309 :       CALL timestop(handle)
    1800        14309 :    END SUBROUTINE reorthogonalize_vectors
    1801              : 
    1802              : ! **************************************************************************************************
    1803              : !> \brief purges wf_history retaining only the latest snapshot
    1804              : !> \param qs_env the qs env with the latest result, and that will contain
    1805              : !>        the purged wf_history
    1806              : !> \par History
    1807              : !>      05.2016 created [Nico Holmberg]
    1808              : !> \author Nico Holmberg
    1809              : ! **************************************************************************************************
    1810            0 :    SUBROUTINE wfi_purge_history(qs_env)
    1811              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1812              : 
    1813              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'wfi_purge_history'
    1814              : 
    1815              :       INTEGER                                            :: handle, io_unit, print_level
    1816              :       TYPE(cp_logger_type), POINTER                      :: logger
    1817              :       TYPE(dft_control_type), POINTER                    :: dft_control
    1818              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
    1819              : 
    1820            0 :       NULLIFY (dft_control, wf_history)
    1821              : 
    1822            0 :       CALL timeset(routineN, handle)
    1823            0 :       logger => cp_get_default_logger()
    1824            0 :       print_level = logger%iter_info%print_level
    1825              :       io_unit = cp_print_key_unit_nr(logger, qs_env%input, "DFT%SCF%PRINT%PROGRAM_RUN_INFO", &
    1826            0 :                                      extension=".scfLog")
    1827              : 
    1828            0 :       CPASSERT(ASSOCIATED(qs_env))
    1829            0 :       CPASSERT(ASSOCIATED(qs_env%wf_history))
    1830            0 :       CPASSERT(qs_env%wf_history%ref_count > 0)
    1831            0 :       CALL get_qs_env(qs_env, dft_control=dft_control)
    1832              : 
    1833            0 :       SELECT CASE (qs_env%wf_history%interpolation_method_nr)
    1834              :       CASE (wfi_use_guess_method_nr, wfi_use_prev_wf_method_nr, &
    1835              :             wfi_use_prev_p_method_nr, wfi_use_prev_rho_r_method_nr, &
    1836              :             wfi_frozen_method_nr)
    1837              :          ! do nothing
    1838              :       CASE (wfi_linear_wf_method_nr, wfi_linear_p_method_nr, &
    1839              :             wfi_linear_ps_method_nr, wfi_ps_method_nr, &
    1840              :             wfi_aspc_nr, wfi_gext_proj_nr, wfi_gext_proj_qtr_nr)
    1841            0 :          IF (qs_env%wf_history%snapshot_count >= 2) THEN
    1842            0 :             IF (debug_this_module .AND. io_unit > 0) &
    1843            0 :                WRITE (io_unit, FMT="(T2,A)") "QS| Purging WFN history"
    1844              :             CALL wfi_create(wf_history, interpolation_method_nr= &
    1845              :                             dft_control%qs_control%wf_interpolation_method_nr, &
    1846              :                             extrapolation_order=dft_control%qs_control%wf_extrapolation_order, &
    1847            0 :                             has_unit_metric=qs_env%has_unit_metric)
    1848              :             CALL set_qs_env(qs_env=qs_env, &
    1849            0 :                             wf_history=wf_history)
    1850            0 :             CALL wfi_release(wf_history)
    1851            0 :             CALL wfi_update(qs_env%wf_history, qs_env=qs_env, dt=1.0_dp)
    1852              :          END IF
    1853              :       CASE DEFAULT
    1854            0 :          CPABORT("Unknown extrapolation method.")
    1855              :       END SELECT
    1856            0 :       CALL timestop(handle)
    1857              : 
    1858            0 :    END SUBROUTINE wfi_purge_history
    1859              : 
    1860              : ! **************************************************************************************************
    1861              : !> \brief Gives the coefficients that best approximate the new overlap
    1862              : !>        as a linear combination of the previous overlaps in the
    1863              : !>        wf_history buffer. This is done by solving
    1864              : !>        argmin_a || S_{n+1} - S_{n} - \sum_i^{nvec-1} a_i (S_{n-q+i} - S_{n}) ||^2
    1865              : !> \param wf_history wavefunction history buffer, containing the previous overlaps
    1866              : !> \param current_overlap current overlap in dbcsr format
    1867              : !> \param coeffs resulting nvec coefficients
    1868              : !> \param nvec number of previous overlaps
    1869              : !> \param eps Tikhonov regularization
    1870              : !> \param io_unit output unit
    1871              : !> \param print_level print level
    1872              : !> \par History
    1873              : !>      04.2026 created [Michele Nottoli]
    1874              : !> \author Michele Nottoli
    1875              : ! **************************************************************************************************
    1876           24 :    SUBROUTINE diff_fitting(wf_history, current_overlap, coeffs, nvec, eps, io_unit, print_level)
    1877              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
    1878              :       TYPE(dbcsr_type), INTENT(IN)                       :: current_overlap
    1879              :       INTEGER, INTENT(IN)                                :: nvec
    1880              :       REAL(KIND=dp), INTENT(OUT)                         :: coeffs(nvec)
    1881              :       REAL(KIND=dp), INTENT(IN)                          :: eps
    1882              :       INTEGER, INTENT(IN)                                :: io_unit, print_level
    1883              : 
    1884              :       INTEGER                                            :: i, info, j
    1885              :       REAL(KIND=dp)                                      :: error
    1886           24 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: b
    1887           24 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: A
    1888              :       TYPE(dbcsr_type)                                   :: target_diff, tmp_i, tmp_j, tmp_k
    1889              :       TYPE(qs_wf_snapshot_type), POINTER                 :: ref_state, state
    1890              : 
    1891           24 :       IF (nvec <= 0) THEN
    1892            0 :          CPABORT("Not enough vectors to do the fitting")
    1893           24 :       ELSE IF (nvec == 1) THEN
    1894            4 :          coeffs(1) = 1.0_dp
    1895              :          RETURN
    1896              :       END IF
    1897              : 
    1898          120 :       ALLOCATE (A(nvec - 1, nvec - 1), b(nvec - 1))
    1899              : 
    1900              :       ! get the reference for the difference fitting
    1901           20 :       ref_state => wfi_get_snapshot(wf_history, wf_index=1)
    1902              : 
    1903              :       ! assemble the target difference
    1904           20 :       CALL dbcsr_copy(target_diff, current_overlap)
    1905           20 :       CALL dbcsr_add(target_diff, ref_state%overlap, 1.0_dp, -1.0_dp)
    1906              : 
    1907              :       ! allocate tmp_k
    1908           20 :       CALL dbcsr_copy(tmp_k, current_overlap)
    1909              : 
    1910              :       ! assemble the matrix A and the RHS b
    1911           76 :       DO i = 2, nvec
    1912           56 :          state => wfi_get_snapshot(wf_history, wf_index=i)
    1913           56 :          CALL dbcsr_copy(tmp_i, state%overlap)
    1914           56 :          CALL dbcsr_add(tmp_i, ref_state%overlap, 1.0_dp, -1.0_dp)
    1915           56 :          CALL dbcsr_multiply("N", "N", 1.0_dp, tmp_i, target_diff, 0.0_dp, tmp_k)
    1916           56 :          CALL dbcsr_trace(tmp_k, b(i - 1))
    1917              : 
    1918          196 :          DO j = 2, i
    1919          120 :             state => wfi_get_snapshot(wf_history, wf_index=j)
    1920          120 :             CALL dbcsr_copy(tmp_j, state%overlap)
    1921          120 :             CALL dbcsr_add(tmp_j, ref_state%overlap, 1.0_dp, -1.0_dp)
    1922          120 :             CALL dbcsr_multiply("N", "N", 1.0_dp, tmp_i, tmp_j, 0.0_dp, tmp_k)
    1923          120 :             CALL dbcsr_trace(tmp_k, A(j - 1, i - 1))
    1924          176 :             A(i - 1, j - 1) = A(j - 1, i - 1)
    1925              :          END DO
    1926              :       END DO
    1927              : 
    1928              :       ! add the Tikhonov regularization
    1929           76 :       DO i = 1, nvec - 1
    1930           76 :          A(i, i) = A(i, i) + eps**2
    1931              :       END DO
    1932              : 
    1933              :       ! solve the linear system
    1934           20 :       CALL dposv('u', nvec - 1, 1, A, nvec - 1, b, nvec - 1, info)
    1935           20 :       IF (info /= 0) THEN
    1936            0 :          CPABORT("DPOSV failed.")
    1937              :       END IF
    1938              : 
    1939              :       ! set the coefficient for the reference snapshot
    1940           76 :       coeffs(1) = 1.0_dp - SUM(b)
    1941           76 :       coeffs(2:nvec) = b(:)
    1942              : 
    1943              :       ! as a consistency check, print how well the current overlap
    1944              :       ! is approximated by the linear combination of previous overlaps
    1945           20 :       IF (print_level > low_print_level) THEN
    1946           20 :          CALL dbcsr_copy(tmp_i, current_overlap)
    1947           96 :          DO i = 1, nvec
    1948           76 :             state => wfi_get_snapshot(wf_history, wf_index=i)
    1949           96 :             CALL dbcsr_add(tmp_i, state%overlap, 1.0_dp, -coeffs(i))
    1950              :          END DO
    1951           20 :          error = dbcsr_frobenius_norm(tmp_i)/dbcsr_frobenius_norm(state%overlap)
    1952           20 :          IF (io_unit > 0) THEN
    1953           10 :             WRITE (UNIT=io_unit, FMT="(/,T2,A,F20.10)") "GEXT overlap fitting error:", error
    1954              :          END IF
    1955              :       END IF
    1956              : 
    1957              :       ! free the memory
    1958           20 :       CALL dbcsr_release(tmp_i)
    1959           20 :       CALL dbcsr_release(tmp_j)
    1960           20 :       CALL dbcsr_release(tmp_k)
    1961           20 :       CALL dbcsr_release(target_diff)
    1962           20 :       DEALLOCATE (A, b)
    1963              : 
    1964           24 :    END SUBROUTINE diff_fitting
    1965              : 
    1966              : ! **************************************************************************************************
    1967              : !> \brief Gives the coefficients that best approximate the new overlap
    1968              : !>        as a time reversible linear combination of the previous overlaps in the
    1969              : !>        wf_history buffer. This is done by solving
    1970              : !>        argmin_a || S_{n+1} + S_{n+1-nvec}
    1971              : !>                    - \sum_{i=1}^q a_i (S_{n+1-nvec+i} + S_{n+1-i}) ||^2
    1972              : !>        with q = nvec/2 if nvec is even, or q = (nvec-1)/2 if odd.
    1973              : !> \param wf_history wavefunction history buffer, containing the previous overlaps
    1974              : !> \param current_overlap current overlap in dbcsr format
    1975              : !> \param coeffs resulting nvec coefficients
    1976              : !> \param nvec number of previous overlaps
    1977              : !> \param eps Tikhonov regularization
    1978              : !> \param io_unit output unit
    1979              : !> \param print_level print level
    1980              : !> \par History
    1981              : !>      04.2026 created [Michele Nottoli]
    1982              : ! **************************************************************************************************
    1983           24 :    SUBROUTINE tr_fitting(wf_history, current_overlap, coeffs, nvec, eps, io_unit, print_level)
    1984              :       TYPE(qs_wf_history_type), POINTER                  :: wf_history
    1985              :       TYPE(dbcsr_type), INTENT(IN)                       :: current_overlap
    1986              :       INTEGER, INTENT(IN)                                :: nvec
    1987              :       REAL(KIND=dp), INTENT(OUT)                         :: coeffs(nvec)
    1988              :       REAL(KIND=dp), INTENT(IN)                          :: eps
    1989              :       INTEGER, INTENT(IN)                                :: io_unit, print_level
    1990              : 
    1991              :       INTEGER                                            :: i, info, j, ntr
    1992              :       REAL(KIND=dp)                                      :: error
    1993           24 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: b
    1994           24 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: A
    1995              :       TYPE(dbcsr_type)                                   :: target_overlap, tmp_i, tmp_j, tmp_k
    1996              :       TYPE(qs_wf_snapshot_type), POINTER                 :: ref_state, state
    1997              : 
    1998           24 :       IF (nvec <= 0) THEN
    1999            0 :          CPABORT("Not enough vectors to do the fitting")
    2000           24 :       ELSE IF (nvec == 1) THEN
    2001            4 :          coeffs(1) = 1.0_dp
    2002              :          RETURN
    2003              :       END IF
    2004              : 
    2005           20 :       IF (MOD(nvec, 2) == 0) THEN
    2006            8 :          ntr = nvec/2
    2007              :       ELSE
    2008           12 :          ntr = (nvec - 1)/2
    2009              :       END IF
    2010              : 
    2011          120 :       ALLOCATE (A(ntr, ntr), b(ntr))
    2012              : 
    2013              :       ! get the reference for the difference fitting
    2014           20 :       ref_state => wfi_get_snapshot(wf_history, wf_index=nvec)
    2015              : 
    2016              :       ! assemble the target sum
    2017           20 :       CALL dbcsr_copy(target_overlap, current_overlap)
    2018           20 :       CALL dbcsr_add(target_overlap, ref_state%overlap, 1.0_dp, 1.0_dp)
    2019              : 
    2020              :       ! allocate tmp_k
    2021           20 :       CALL dbcsr_copy(tmp_k, current_overlap)
    2022              : 
    2023              :       ! assemble the matrix A and the RHS b
    2024           52 :       DO i = 1, ntr
    2025           32 :          state => wfi_get_snapshot(wf_history, wf_index=i)
    2026           32 :          CALL dbcsr_copy(tmp_i, state%overlap)
    2027           32 :          state => wfi_get_snapshot(wf_history, wf_index=nvec - i)
    2028           32 :          CALL dbcsr_add(tmp_i, state%overlap, 1.0_dp, 1.0_dp)
    2029              : 
    2030              :          CALL dbcsr_multiply("N", "N", 1.0_dp, tmp_i, target_overlap, &
    2031           32 :                              0.0_dp, tmp_k)
    2032           32 :          CALL dbcsr_trace(tmp_k, b(i))
    2033           96 :          DO j = 1, i
    2034           44 :             state => wfi_get_snapshot(wf_history, wf_index=j)
    2035           44 :             CALL dbcsr_copy(tmp_j, state%overlap)
    2036           44 :             state => wfi_get_snapshot(wf_history, wf_index=nvec - j)
    2037           44 :             CALL dbcsr_add(tmp_j, state%overlap, 1.0_dp, 1.0_dp)
    2038           44 :             CALL dbcsr_multiply("N", "N", 1.0_dp, tmp_i, tmp_j, 0.0_dp, tmp_k)
    2039           44 :             CALL dbcsr_trace(tmp_k, A(j, i))
    2040           76 :             A(i, j) = A(j, i)
    2041              :          END DO
    2042              :       END DO
    2043              : 
    2044              :       ! add the Tikhonov regularization
    2045           52 :       DO i = 1, ntr
    2046           52 :          A(i, i) = A(i, i) + eps**2
    2047              :       END DO
    2048              : 
    2049              :       ! solve the linear system
    2050           20 :       CALL dposv('u', ntr, 1, A, ntr, b, ntr, info)
    2051           20 :       IF (info /= 0) THEN
    2052            0 :          CPABORT("DPOSV failed.")
    2053              :       END IF
    2054              : 
    2055              :       ! reorder the coefficients
    2056           96 :       coeffs = 0.0_dp
    2057           20 :       coeffs(nvec) = -1.0_dp
    2058           52 :       DO i = 1, ntr
    2059           32 :          coeffs(i) = coeffs(i) + b(i)
    2060           52 :          coeffs(nvec - i) = coeffs(nvec - i) + b(i)
    2061              :       END DO
    2062              : 
    2063              :       ! as a consistency check, print how well the current overlap
    2064              :       ! is approximated by the linear combination of previous overlaps
    2065           20 :       IF (print_level > low_print_level) THEN
    2066           20 :          CALL dbcsr_copy(tmp_i, current_overlap)
    2067           96 :          DO i = 1, nvec
    2068           76 :             state => wfi_get_snapshot(wf_history, wf_index=i)
    2069           96 :             CALL dbcsr_add(tmp_i, state%overlap, 1.0_dp, -coeffs(i))
    2070              :          END DO
    2071           20 :          error = dbcsr_frobenius_norm(tmp_i)/dbcsr_frobenius_norm(state%overlap)
    2072           20 :          IF (io_unit > 0) THEN
    2073           10 :             WRITE (UNIT=io_unit, FMT="(/,T2,A,F20.10)") "GEXT overlap fitting error:", error
    2074              :          END IF
    2075              :       END IF
    2076              : 
    2077              :       ! free the memory
    2078           20 :       CALL dbcsr_release(tmp_i)
    2079           20 :       CALL dbcsr_release(tmp_j)
    2080           20 :       CALL dbcsr_release(tmp_k)
    2081           20 :       CALL dbcsr_release(target_overlap)
    2082           20 :       DEALLOCATE (A, b)
    2083              : 
    2084           24 :    END SUBROUTINE tr_fitting
    2085              : 
    2086              : END MODULE qs_wf_history_methods
        

Generated by: LCOV version 2.0-1