LCOV - code coverage report
Current view: top level - src - qs_wf_history_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 91.4 % 1240 1133
Test Date: 2026-10-15 00:55:44 Functions: 94.7 % 19 18

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

Generated by: LCOV version 2.0-1