LCOV - code coverage report
Current view: top level - src - qs_linres_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:8ebf9ad) Lines: 96.3 % 410 395
Test Date: 2026-01-22 06:43:13 Functions: 100.0 % 9 9

            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 localize wavefunctions
      10              : !>      linear response scf
      11              : !> \par History
      12              : !>      created 07-2005 [MI]
      13              : !> \author MI
      14              : ! **************************************************************************************************
      15              : MODULE qs_linres_methods
      16              :    USE cp_control_types,                ONLY: dft_control_type
      17              :    USE cp_dbcsr_api,                    ONLY: dbcsr_copy,&
      18              :                                               dbcsr_p_type,&
      19              :                                               dbcsr_set,&
      20              :                                               dbcsr_type
      21              :    USE cp_dbcsr_contrib,                ONLY: dbcsr_checksum
      22              :    USE cp_dbcsr_operations,             ONLY: cp_dbcsr_sm_fm_multiply
      23              :    USE cp_external_control,             ONLY: external_control
      24              :    USE cp_files,                        ONLY: close_file,&
      25              :                                               open_file
      26              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_scale_and_add,&
      27              :                                               cp_fm_trace
      28              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      29              :                                               cp_fm_struct_release,&
      30              :                                               cp_fm_struct_type
      31              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      32              :                                               cp_fm_get_info,&
      33              :                                               cp_fm_get_submatrix,&
      34              :                                               cp_fm_release,&
      35              :                                               cp_fm_set_submatrix,&
      36              :                                               cp_fm_to_fm,&
      37              :                                               cp_fm_type
      38              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      39              :                                               cp_logger_type,&
      40              :                                               cp_to_string
      41              :    USE cp_output_handling,              ONLY: cp_p_file,&
      42              :                                               cp_print_key_finished_output,&
      43              :                                               cp_print_key_generate_filename,&
      44              :                                               cp_print_key_should_output,&
      45              :                                               cp_print_key_unit_nr
      46              :    USE input_constants,                 ONLY: do_loc_none,&
      47              :                                               op_loc_berry,&
      48              :                                               ot_precond_none,&
      49              :                                               ot_precond_solver_default,&
      50              :                                               state_loc_all
      51              :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      52              :                                               section_vals_type,&
      53              :                                               section_vals_val_get
      54              :    USE kinds,                           ONLY: default_path_length,&
      55              :                                               default_string_length,&
      56              :                                               dp
      57              :    USE machine,                         ONLY: m_flush,&
      58              :                                               m_walltime
      59              :    USE message_passing,                 ONLY: mp_para_env_type
      60              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      61              :    USE preconditioner,                  ONLY: apply_preconditioner,&
      62              :                                               make_preconditioner
      63              :    USE qs_2nd_kernel_ao,                ONLY: build_dm_response
      64              :    USE qs_environment_types,            ONLY: get_qs_env,&
      65              :                                               qs_environment_type
      66              :    USE qs_gapw_densities,               ONLY: prepare_gapw_den
      67              :    USE qs_linres_kernel,                ONLY: apply_op_2
      68              :    USE qs_linres_types,                 ONLY: linres_control_type
      69              :    USE qs_loc_main,                     ONLY: qs_loc_driver
      70              :    USE qs_loc_types,                    ONLY: get_qs_loc_env,&
      71              :                                               localized_wfn_control_type,&
      72              :                                               qs_loc_env_create,&
      73              :                                               qs_loc_env_type
      74              :    USE qs_loc_utils,                    ONLY: loc_write_restart,&
      75              :                                               qs_loc_control_init,&
      76              :                                               qs_loc_init
      77              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      78              :                                               mo_set_type
      79              :    USE qs_p_env_methods,                ONLY: p_env_check_i_alloc,&
      80              :                                               p_env_update_rho
      81              :    USE qs_p_env_types,                  ONLY: qs_p_env_type
      82              :    USE qs_rho_methods,                  ONLY: qs_rho_update_rho
      83              :    USE qs_rho_types,                    ONLY: qs_rho_type
      84              :    USE string_utilities,                ONLY: xstring
      85              : #include "./base/base_uses.f90"
      86              : 
      87              :    IMPLICIT NONE
      88              : 
      89              :    PRIVATE
      90              : 
      91              :    ! *** Public subroutines ***
      92              :    PUBLIC :: linres_localize, linres_solver
      93              :    PUBLIC :: linres_write_restart, linres_read_restart
      94              :    PUBLIC :: build_dm_response
      95              : 
      96              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_linres_methods'
      97              : 
      98              : ! **************************************************************************************************
      99              : 
     100              : CONTAINS
     101              : 
     102              : ! **************************************************************************************************
     103              : !> \brief Find the centers and spreads of the wfn,
     104              : !>      if required apply a localization algorithm
     105              : !> \param qs_env ...
     106              : !> \param linres_control ...
     107              : !> \param nspins ...
     108              : !> \param centers_only ...
     109              : !> \par History
     110              : !>      07.2005 created [MI]
     111              : !> \author MI
     112              : ! **************************************************************************************************
     113          190 :    SUBROUTINE linres_localize(qs_env, linres_control, nspins, centers_only)
     114              : 
     115              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     116              :       TYPE(linres_control_type), POINTER                 :: linres_control
     117              :       INTEGER, INTENT(IN)                                :: nspins
     118              :       LOGICAL, INTENT(IN), OPTIONAL                      :: centers_only
     119              : 
     120              :       INTEGER                                            :: iounit, ispin, istate, nmoloc(2)
     121              :       LOGICAL                                            :: my_centers_only
     122          190 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)        :: mos_localized
     123              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     124              :       TYPE(cp_logger_type), POINTER                      :: logger
     125              :       TYPE(localized_wfn_control_type), POINTER          :: localized_wfn_control
     126          190 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     127              :       TYPE(qs_loc_env_type), POINTER                     :: qs_loc_env
     128              :       TYPE(section_vals_type), POINTER                   :: loc_print_section, loc_section, &
     129              :                                                             lr_section
     130              : 
     131          190 :       NULLIFY (logger, lr_section, loc_section, loc_print_section, localized_wfn_control)
     132          380 :       logger => cp_get_default_logger()
     133          190 :       lr_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%LINRES")
     134          190 :       loc_section => section_vals_get_subs_vals(lr_section, "LOCALIZE")
     135          190 :       loc_print_section => section_vals_get_subs_vals(lr_section, "LOCALIZE%PRINT")
     136              :       iounit = cp_print_key_unit_nr(logger, lr_section, "PRINT%PROGRAM_RUN_INFO", &
     137          190 :                                     extension=".linresLog")
     138          190 :       my_centers_only = .FALSE.
     139          190 :       IF (PRESENT(centers_only)) my_centers_only = centers_only
     140              : 
     141          190 :       NULLIFY (mos, mo_coeff, qs_loc_env)
     142          190 :       CALL get_qs_env(qs_env=qs_env, mos=mos)
     143         1520 :       ALLOCATE (qs_loc_env)
     144          190 :       CALL qs_loc_env_create(qs_loc_env)
     145          190 :       linres_control%qs_loc_env => qs_loc_env
     146          190 :       CALL qs_loc_control_init(qs_loc_env, loc_section, do_homo=.TRUE.)
     147          190 :       CALL get_qs_loc_env(qs_loc_env, localized_wfn_control=localized_wfn_control)
     148              : 
     149          838 :       ALLOCATE (mos_localized(nspins))
     150          458 :       DO ispin = 1, nspins
     151          268 :          CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff)
     152          268 :          CALL cp_fm_create(mos_localized(ispin), mo_coeff%matrix_struct)
     153          458 :          CALL cp_fm_to_fm(mo_coeff, mos_localized(ispin))
     154              :       END DO
     155              : 
     156              :       nmoloc(1:2) = 0
     157          190 :       IF (my_centers_only) THEN
     158            0 :          localized_wfn_control%set_of_states = state_loc_all
     159            0 :          localized_wfn_control%localization_method = do_loc_none
     160            0 :          localized_wfn_control%operator_type = op_loc_berry
     161              :       END IF
     162              : 
     163              :       CALL qs_loc_init(qs_env, qs_loc_env, loc_section, mos_localized=mos_localized, &
     164          190 :                        do_homo=.TRUE.)
     165              : 
     166              :       ! The orbital centers are stored in linres_control%localized_wfn_control
     167          458 :       DO ispin = 1, nspins
     168              :          CALL qs_loc_driver(qs_env, qs_loc_env, loc_print_section, myspin=ispin, &
     169          268 :                             ext_mo_coeff=mos_localized(ispin))
     170          268 :          CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff)
     171          458 :          CALL cp_fm_to_fm(mos_localized(ispin), mo_coeff)
     172              :       END DO
     173              : 
     174              :       CALL loc_write_restart(qs_loc_env, loc_print_section, mos, &
     175          190 :                              mos_localized, do_homo=.TRUE.)
     176          190 :       CALL cp_fm_release(mos_localized)
     177              : 
     178              :       ! Write Centers and Spreads on std out
     179          190 :       IF (iounit > 0) THEN
     180          229 :          DO ispin = 1, nspins
     181              :             WRITE (iounit, "(/,T2,A,I2)") &
     182          134 :                "WANNIER CENTERS for spin ", ispin
     183              :             WRITE (iounit, "(/,T18,A,3X,A)") &
     184          134 :                "--------------- Centers --------------- ", &
     185          268 :                "--- Spreads ---"
     186         1102 :             DO istate = 1, SIZE(localized_wfn_control%centers_set(ispin)%array, 2)
     187              :                WRITE (iounit, "(T5,A6,I6,2X,3f12.6,5X,f12.6)") &
     188         3492 :                   'state ', istate, localized_wfn_control%centers_set(ispin)%array(1:3, istate), &
     189         1880 :                   localized_wfn_control%centers_set(ispin)%array(4, istate)
     190              :             END DO
     191              :          END DO
     192           95 :          CALL m_flush(iounit)
     193              :       END IF
     194              : 
     195          570 :    END SUBROUTINE linres_localize
     196              : 
     197              : ! **************************************************************************************************
     198              : !> \brief scf loop to optimize the first order wavefunctions (psi1)
     199              : !>      given a perturbation as an operator applied to the ground
     200              : !>      state orbitals (h1_psi0)
     201              : !>      psi1 is defined wrt psi0_order (can be a subset of the occupied space)
     202              : !>      The reference ground state is defined through qs_env (density and ground state MOs)
     203              : !>      psi1 is orthogonal to the occupied orbitals in the ground state MO set (qs_env%mos)
     204              : !> \param p_env ...
     205              : !> \param qs_env ...
     206              : !> \param psi1 ...
     207              : !> \param h1_psi0 ...
     208              : !> \param psi0_order ...
     209              : !> \param iounit ...
     210              : !> \param should_stop ...
     211              : !> \param silent ...
     212              : !> \par History
     213              : !>      07.2005 created [MI]
     214              : !> \author MI
     215              : ! **************************************************************************************************
     216         5100 :    SUBROUTINE linres_solver(p_env, qs_env, psi1, h1_psi0, psi0_order, iounit, &
     217              :                             should_stop, silent)
     218              :       TYPE(qs_p_env_type)                                :: p_env
     219              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     220              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: psi1, h1_psi0, psi0_order
     221              :       INTEGER, INTENT(IN)                                :: iounit
     222              :       LOGICAL, INTENT(OUT)                               :: should_stop
     223              :       LOGICAL, INTENT(IN), OPTIONAL                      :: silent
     224              : 
     225              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'linres_solver'
     226              : 
     227              :       INTEGER                                            :: handle, ispin, iter, maxnmo, nao, ncol, &
     228              :                                                             nmo, nocc, nspins
     229              :       LOGICAL                                            :: my_silent, restart
     230              :       REAL(dp)                                           :: alpha, beta, norm_res, t1, t2
     231         5100 :       REAL(dp), DIMENSION(:), POINTER                    :: tr_pAp, tr_rz0, tr_rz00, tr_rz1
     232              :       TYPE(cp_fm_struct_type), POINTER                   :: tmp_fm_struct
     233              :       TYPE(cp_fm_type)                                   :: buf
     234         5100 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)        :: Ap, chc, mo_coeff_array, p, r, z
     235         5100 :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: Sc
     236              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     237         5100 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_s, matrix_t
     238              :       TYPE(dbcsr_type), POINTER                          :: matrix_x
     239              :       TYPE(dft_control_type), POINTER                    :: dft_control
     240              :       TYPE(linres_control_type), POINTER                 :: linres_control
     241         5100 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     242              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     243              : 
     244         5100 :       CALL timeset(routineN, handle)
     245              : 
     246         5100 :       my_silent = .FALSE.
     247         5100 :       IF (PRESENT(silent)) my_silent = silent
     248              : 
     249         5100 :       NULLIFY (dft_control, linres_control, matrix_s, matrix_t, matrix_ks, para_env)
     250         5100 :       NULLIFY (mos, tmp_fm_struct, mo_coeff)
     251              : 
     252         5100 :       t1 = m_walltime()
     253              : 
     254              :       CALL get_qs_env(qs_env=qs_env, &
     255              :                       matrix_ks=matrix_ks, &
     256              :                       matrix_s=matrix_s, &
     257              :                       kinetic=matrix_t, &
     258              :                       dft_control=dft_control, &
     259              :                       linres_control=linres_control, &
     260              :                       para_env=para_env, &
     261         5100 :                       mos=mos)
     262              : 
     263         5100 :       nspins = dft_control%nspins
     264         5100 :       CALL cp_fm_get_info(psi1(1), nrow_global=nao)
     265         5100 :       maxnmo = 0
     266        12264 :       DO ispin = 1, nspins
     267         7164 :          CALL cp_fm_get_info(psi1(ispin), ncol_global=ncol)
     268        12264 :          maxnmo = MAX(maxnmo, ncol)
     269              :       END DO
     270              :       !
     271         5100 :       CALL check_p_env_init(p_env, linres_control, nspins)
     272              :       !
     273              :       ! allocate the vectors
     274              :       ALLOCATE (tr_pAp(nspins), tr_rz0(nspins), tr_rz00(nspins), tr_rz1(nspins), &
     275        84756 :                 r(nspins), p(nspins), z(nspins), Ap(nspins))
     276              :       !
     277        12264 :       DO ispin = 1, nspins
     278         7164 :          CALL cp_fm_create(r(ispin), psi1(ispin)%matrix_struct)
     279         7164 :          CALL cp_fm_create(p(ispin), psi1(ispin)%matrix_struct)
     280         7164 :          CALL cp_fm_create(z(ispin), psi1(ispin)%matrix_struct)
     281        12264 :          CALL cp_fm_create(Ap(ispin), psi1(ispin)%matrix_struct)
     282              :       END DO
     283              :       !
     284              :       ! build C0 occupied vectors and S*C0 matrix
     285        34728 :       ALLOCATE (Sc(nspins), mo_coeff_array(nspins))
     286        12264 :       DO ispin = 1, nspins
     287         7164 :          CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, homo=nocc)
     288         7164 :          NULLIFY (tmp_fm_struct)
     289              :          CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nao, &
     290              :                                   ncol_global=nocc, para_env=para_env, &
     291         7164 :                                   context=mo_coeff%matrix_struct%context)
     292         7164 :          CALL cp_fm_create(mo_coeff_array(ispin), tmp_fm_struct)
     293         7164 :          CALL cp_fm_to_fm(mo_coeff, mo_coeff_array(ispin), nocc)
     294         7164 :          CALL cp_fm_create(Sc(ispin), tmp_fm_struct)
     295        19428 :          CALL cp_fm_struct_release(tmp_fm_struct)
     296              :       END DO
     297              :       !
     298              :       ! Allocate C0_order'*H*C0_order
     299        22464 :       ALLOCATE (chc(nspins))
     300        12264 :       DO ispin = 1, nspins
     301         7164 :          CALL cp_fm_get_info(psi1(ispin), ncol_global=nmo)
     302         7164 :          NULLIFY (tmp_fm_struct)
     303              :          CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nmo, &
     304              :                                   ncol_global=nmo, para_env=para_env, &
     305         7164 :                                   context=mo_coeff%matrix_struct%context)
     306         7164 :          CALL cp_fm_create(chc(ispin), tmp_fm_struct, set_zero=.TRUE.)
     307        19428 :          CALL cp_fm_struct_release(tmp_fm_struct)
     308              :       END DO
     309              :       !
     310        12264 :       DO ispin = 1, nspins
     311              :          !
     312              :          ! C0_order' * H * C0_order
     313              :          ASSOCIATE (mo_coeff => psi0_order(ispin))
     314         7164 :             CALL cp_fm_create(buf, mo_coeff%matrix_struct)
     315         7164 :             CALL cp_fm_get_info(mo_coeff, ncol_global=ncol)
     316         7164 :             CALL cp_dbcsr_sm_fm_multiply(matrix_ks(ispin)%matrix, mo_coeff, buf, ncol)
     317         7164 :             CALL parallel_gemm('T', 'N', ncol, ncol, nao, -1.0_dp, mo_coeff, buf, 0.0_dp, chc(ispin))
     318         7164 :             CALL cp_fm_release(buf)
     319              :          END ASSOCIATE
     320              :          !
     321              :          ! S * C0
     322         7164 :          CALL cp_fm_get_info(mo_coeff_array(ispin), ncol_global=ncol)
     323        19428 :          CALL cp_dbcsr_sm_fm_multiply(matrix_s(1)%matrix, mo_coeff_array(ispin), Sc(ispin), ncol)
     324              :       END DO
     325              :       !
     326              :       ! header
     327         5100 :       IF (iounit > 0 .AND. .NOT. my_silent) THEN
     328              :          WRITE (iounit, "(/,T3,A,T16,A,T25,A,T38,A,T52,A,T72,A,/,T3,A)") &
     329         2537 :             "Iteration", "Method", "Restart", "Stepsize", "Convergence", "Time", &
     330         5074 :             REPEAT("-", 78)
     331              :       END IF
     332              :       !
     333              :       ! orthogonalize x with respect to the psi0
     334         5100 :       CALL preortho(psi1, mo_coeff_array, Sc)
     335              :       !
     336              :       ! build the preconditioner
     337         5100 :       IF (linres_control%preconditioner_type /= ot_precond_none) THEN
     338         5100 :          IF (p_env%new_preconditioner) THEN
     339         2796 :             DO ispin = 1, nspins
     340         2796 :                IF (ASSOCIATED(matrix_t)) THEN
     341              :                   CALL make_preconditioner(p_env%preconditioner(ispin), &
     342              :                                            linres_control%preconditioner_type, ot_precond_solver_default, &
     343              :                                            matrix_ks(ispin)%matrix, matrix_s(1)%matrix, matrix_t(1)%matrix, &
     344         1478 :                                            mos(ispin), linres_control%energy_gap)
     345              :                ELSE
     346           24 :                   NULLIFY (matrix_x)
     347              :                   CALL make_preconditioner(p_env%preconditioner(ispin), &
     348              :                                            linres_control%preconditioner_type, ot_precond_solver_default, &
     349              :                                            matrix_ks(ispin)%matrix, matrix_s(1)%matrix, matrix_x, &
     350           24 :                                            mos(ispin), linres_control%energy_gap)
     351              :                END IF
     352              :             END DO
     353         1294 :             p_env%new_preconditioner = .FALSE.
     354              :          END IF
     355              :       END IF
     356              :       !
     357              :       ! initialization of the linear solver
     358              :       !
     359              :       ! A * x0
     360         5100 :       CALL apply_op(qs_env, p_env, psi0_order, psi1, Ap, chc)
     361              :       !
     362              :       !
     363              :       ! r_0 = b - Ax0
     364        12264 :       DO ispin = 1, nspins
     365         7164 :          CALL cp_fm_to_fm(h1_psi0(ispin), r(ispin))
     366        12264 :          CALL cp_fm_scale_and_add(-1.0_dp, r(ispin), -1.0_dp, Ap(ispin))
     367              :       END DO
     368              :       !
     369              :       ! proj r
     370         5100 :       CALL postortho(r, mo_coeff_array, Sc)
     371              :       !
     372              :       ! preconditioner
     373         5100 :       linres_control%flag = ""
     374         5100 :       IF (linres_control%preconditioner_type == ot_precond_none) THEN
     375              :          !
     376              :          ! z_0 = r_0
     377            0 :          DO ispin = 1, nspins
     378            0 :             CALL cp_fm_to_fm(r(ispin), z(ispin))
     379              :          END DO
     380            0 :          linres_control%flag = "CG"
     381              :       ELSE
     382              :          !
     383              :          ! z_0 = M * r_0
     384        12264 :          DO ispin = 1, nspins
     385              :             CALL apply_preconditioner(p_env%preconditioner(ispin), r(ispin), &
     386        12264 :                                       z(ispin))
     387              :          END DO
     388         5100 :          linres_control%flag = "PCG"
     389              :       END IF
     390              :       !
     391        12264 :       DO ispin = 1, nspins
     392              :          !
     393              :          ! p_0 = z_0
     394         7164 :          CALL cp_fm_to_fm(z(ispin), p(ispin))
     395              :          !
     396              :          ! trace(r_0 * z_0)
     397        12264 :          CALL cp_fm_trace(r(ispin), z(ispin), tr_rz0(ispin))
     398              :       END DO
     399        12264 :       IF (SUM(tr_rz0) < 0.0_dp) CPABORT("tr(r_j*z_j) < 0")
     400        12264 :       norm_res = ABS(SUM(tr_rz0))/SQRT(REAL(nspins*nao*maxnmo, dp))
     401              :       !
     402         5100 :       alpha = 0.0_dp
     403         5100 :       restart = .FALSE.
     404         5100 :       should_stop = .FALSE.
     405        33746 :       iteration: DO iter = 1, linres_control%max_iter
     406              :          !
     407              :          ! check convergence
     408        32426 :          linres_control%converged = .FALSE.
     409        32426 :          IF (norm_res < linres_control%eps) THEN
     410         3780 :             linres_control%converged = .TRUE.
     411              :          END IF
     412              :          !
     413        32426 :          t2 = m_walltime()
     414              :          IF (iter == 1 .OR. MOD(iter, 1) == 0 .OR. linres_control%converged &
     415              :              .OR. restart .OR. should_stop) THEN
     416        32426 :             IF (iounit > 0 .AND. .NOT. my_silent) THEN
     417              :                WRITE (iounit, "(T5,I5,T18,A3,T28,L1,T38,1E8.2,T48,F16.10,T68,F8.2)") &
     418        16111 :                   iter, linres_control%flag, restart, alpha, norm_res, t2 - t1
     419        16111 :                CALL m_flush(iounit)
     420              :             END IF
     421              :          END IF
     422              :          !
     423        32426 :          IF (linres_control%converged) THEN
     424         3780 :             IF (iounit > 0) THEN
     425         1882 :                WRITE (iounit, "(T3,A,I4,A,T73,F8.2)") "The linear solver converged in ", &
     426         3764 :                   iter, " iterations.", t2 - t1
     427         1882 :                CALL m_flush(iounit)
     428              :             END IF
     429              :             EXIT iteration
     430        28646 :          ELSE IF (should_stop) THEN
     431            0 :             IF (iounit > 0) THEN
     432            0 :                WRITE (iounit, "(T3,A,I4,A)") "The linear solver did NOT converge! External stop"
     433            0 :                CALL m_flush(iounit)
     434              :             END IF
     435              :             EXIT iteration
     436              :          END IF
     437              :          !
     438              :          ! Max number of iteration reached
     439        28646 :          IF (iter == linres_control%max_iter) THEN
     440         1320 :             IF (iounit > 0) THEN
     441              :                CALL cp_warn(__LOCATION__, &
     442          660 :                             "The linear solver didn't converge! Maximum number of iterations reached.")
     443          660 :                CALL m_flush(iounit)
     444              :             END IF
     445         1320 :             linres_control%converged = .FALSE.
     446              :          END IF
     447              :          !
     448              :          ! Apply the operators that do not depend on the perturbation
     449        28646 :          CALL apply_op(qs_env, p_env, psi0_order, p, Ap, chc)
     450              :          !
     451              :          ! proj Ap onto the virtual subspace
     452        28646 :          CALL postortho(Ap, mo_coeff_array, Sc)
     453              :          !
     454        70224 :          DO ispin = 1, nspins
     455              :             !
     456              :             ! tr(Ap_j*p_j)
     457        70224 :             CALL cp_fm_trace(Ap(ispin), p(ispin), tr_pAp(ispin))
     458              :          END DO
     459              :          !
     460              :          ! alpha = tr(r_j*z_j) / tr(Ap_j*p_j)
     461        70224 :          IF (SUM(tr_pAp) < 1.0e-10_dp) THEN
     462          176 :             alpha = 1.0_dp
     463              :          ELSE
     464       111274 :             alpha = SUM(tr_rz0)/SUM(tr_pAp)
     465              :          END IF
     466        70224 :          DO ispin = 1, nspins
     467              :             !
     468              :             ! x_j+1 = x_j + alpha * p_j
     469        70224 :             CALL cp_fm_scale_and_add(1.0_dp, psi1(ispin), alpha, p(ispin))
     470              :          END DO
     471              :          !
     472              :          ! need to recompute the residue
     473        28646 :          restart = .FALSE.
     474        28646 :          IF (MOD(iter, linres_control%restart_every) == 0) THEN
     475              :             !
     476              :             ! r_j+1 = b - A * x_j+1
     477          206 :             CALL apply_op(qs_env, p_env, psi0_order, psi1, Ap, chc)
     478              :             !
     479          446 :             DO ispin = 1, nspins
     480          240 :                CALL cp_fm_to_fm(h1_psi0(ispin), r(ispin))
     481          446 :                CALL cp_fm_scale_and_add(-1.0_dp, r(ispin), -1.0_dp, Ap(ispin))
     482              :             END DO
     483          206 :             CALL postortho(r, mo_coeff_array, Sc)
     484              :             !
     485          206 :             restart = .TRUE.
     486              :          ELSE
     487              :             ! proj Ap onto the virtual subspace
     488        28440 :             CALL postortho(Ap, mo_coeff_array, Sc)
     489              :             !
     490              :             ! r_j+1 = r_j - alpha * Ap_j
     491        69778 :             DO ispin = 1, nspins
     492        69778 :                CALL cp_fm_scale_and_add(1.0_dp, r(ispin), -alpha, Ap(ispin))
     493              :             END DO
     494        28440 :             restart = .FALSE.
     495              :          END IF
     496              :          !
     497              :          ! preconditioner
     498        28646 :          linres_control%flag = ""
     499        28646 :          IF (linres_control%preconditioner_type == ot_precond_none) THEN
     500              :             !
     501              :             ! z_j+1 = r_j+1
     502            0 :             DO ispin = 1, nspins
     503            0 :                CALL cp_fm_to_fm(r(ispin), z(ispin))
     504              :             END DO
     505            0 :             linres_control%flag = "CG"
     506              :          ELSE
     507              :             !
     508              :             ! z_j+1 = M * r_j+1
     509        70224 :             DO ispin = 1, nspins
     510              :                CALL apply_preconditioner(p_env%preconditioner(ispin), r(ispin), &
     511        70224 :                                          z(ispin))
     512              :             END DO
     513        28646 :             linres_control%flag = "PCG"
     514              :          END IF
     515              :          !
     516        70224 :          DO ispin = 1, nspins
     517              :             !
     518              :             ! tr(r_j+1*z_j+1)
     519        70224 :             CALL cp_fm_trace(r(ispin), z(ispin), tr_rz1(ispin))
     520              :          END DO
     521        70224 :          IF (SUM(tr_rz1) < 0.0_dp) CPABORT("tr(r_j+1*z_j+1) < 0")
     522        70224 :          norm_res = SUM(tr_rz1)/SQRT(REAL(nspins*nao*maxnmo, dp))
     523              :          !
     524              :          ! beta = tr(r_j+1*z_j+1) / tr(r_j*z_j)
     525        70224 :          IF (SUM(tr_rz0) < 1.0e-10_dp) THEN
     526          218 :             beta = 0.0_dp
     527              :          ELSE
     528       111148 :             beta = SUM(tr_rz1)/SUM(tr_rz0)
     529              :          END IF
     530        70224 :          DO ispin = 1, nspins
     531              :             !
     532              :             ! p_j+1 = z_j+1 + beta * p_j
     533        41578 :             CALL cp_fm_scale_and_add(beta, p(ispin), 1.0_dp, z(ispin))
     534        41578 :             tr_rz00(ispin) = tr_rz0(ispin)
     535        70224 :             tr_rz0(ispin) = tr_rz1(ispin)
     536              :          END DO
     537              :          !
     538              :          ! Can we exit the SCF loop?
     539              :          CALL external_control(should_stop, "LINRES", target_time=qs_env%target_time, &
     540        29966 :                                start_time=qs_env%start_time)
     541              : 
     542              :       END DO iteration
     543              :       !
     544              :       ! proj psi1
     545         5100 :       CALL preortho(psi1, mo_coeff_array, Sc)
     546              :       !
     547              :       !
     548              :       ! clean up
     549         5100 :       CALL cp_fm_release(r)
     550         5100 :       CALL cp_fm_release(p)
     551         5100 :       CALL cp_fm_release(z)
     552         5100 :       CALL cp_fm_release(Ap)
     553              :       !
     554         5100 :       CALL cp_fm_release(mo_coeff_array)
     555         5100 :       CALL cp_fm_release(Sc)
     556         5100 :       CALL cp_fm_release(chc)
     557              :       !
     558         5100 :       DEALLOCATE (tr_pAp, tr_rz0, tr_rz00, tr_rz1)
     559              :       !
     560         5100 :       CALL timestop(handle)
     561              :       !
     562        15300 :    END SUBROUTINE linres_solver
     563              : 
     564              : ! **************************************************************************************************
     565              : !> \brief ...
     566              : !> \param qs_env ...
     567              : !> \param p_env ...
     568              : !> \param c0 ...
     569              : !> \param v ...
     570              : !> \param Av ...
     571              : !> \param chc ...
     572              : ! **************************************************************************************************
     573        33952 :    SUBROUTINE apply_op(qs_env, p_env, c0, v, Av, chc)
     574              :       !
     575              :       TYPE(qs_environment_type), INTENT(IN), POINTER     :: qs_env
     576              :       TYPE(qs_p_env_type)                                :: p_env
     577              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: c0, v
     578              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(INOUT)      :: Av
     579              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: chc
     580              : 
     581              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'apply_op'
     582              : 
     583              :       INTEGER                                            :: handle, ispin, nc1, nc2, nc3, nc4, nr1, &
     584              :                                                             nr2, nr3, nr4, nspins
     585              :       REAL(dp)                                           :: chksum
     586        33952 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_s
     587              :       TYPE(dft_control_type), POINTER                    :: dft_control
     588              :       TYPE(linres_control_type), POINTER                 :: linres_control
     589              :       TYPE(qs_rho_type), POINTER                         :: rho
     590              : 
     591        33952 :       CALL timeset(routineN, handle)
     592              : 
     593        33952 :       NULLIFY (dft_control, matrix_ks, matrix_s, linres_control)
     594              :       CALL get_qs_env(qs_env=qs_env, &
     595              :                       matrix_ks=matrix_ks, &
     596              :                       matrix_s=matrix_s, &
     597              :                       dft_control=dft_control, &
     598        33952 :                       linres_control=linres_control)
     599              : 
     600        33952 :       nspins = dft_control%nspins
     601              : 
     602        82934 :       DO ispin = 1, nspins
     603              :          !c0, v, Av, chc
     604        48982 :          CALL cp_fm_get_info(c0(ispin), ncol_global=nc1, nrow_global=nr1)
     605        48982 :          CALL cp_fm_get_info(v(ispin), ncol_global=nc2, nrow_global=nr2)
     606        48982 :          CALL cp_fm_get_info(Av(ispin), ncol_global=nc3, nrow_global=nr3)
     607        48982 :          CALL cp_fm_get_info(chc(ispin), ncol_global=nc4, nrow_global=nr4)
     608        48982 :          IF (.NOT. (nc1 == nc2 .AND. nr1 == nr2 .AND. nc1 == nc3 .AND. nr1 == nr3 &
     609        82934 :                     .AND. nc4 == nr4 .AND. nc1 <= nc4)) THEN
     610              :             CALL cp_abort(__LOCATION__, &
     611            0 :                           "Number of vectors inconsistent or CHC matrix too small")
     612              :          END IF
     613              :       END DO
     614              : 
     615              :       ! apply the uncoupled operator
     616        82934 :       DO ispin = 1, nspins
     617              :          CALL apply_op_1(v(ispin), Av(ispin), matrix_ks(ispin)%matrix, &
     618        82934 :                          matrix_s(1)%matrix, chc(ispin))
     619              :       END DO
     620              : 
     621        33952 :       IF (linres_control%do_kernel) THEN
     622              : 
     623              :          ! build DM, refill p1, build_dm_response keeps sparse structure
     624        20382 :          DO ispin = 1, nspins
     625        20382 :             CALL dbcsr_copy(p_env%p1(ispin)%matrix, matrix_s(1)%matrix)
     626              :          END DO
     627         9622 :          CALL build_dm_response(c0, v, p_env%p1)
     628              : 
     629         9622 :          chksum = 0.0_dp
     630        20382 :          DO ispin = 1, nspins
     631        20382 :             chksum = chksum + dbcsr_checksum(p_env%p1(ispin)%matrix)
     632              :          END DO
     633              : 
     634              :          ! skip the kernel if the DM is very small
     635         9622 :          IF (chksum > 1.0E-14_dp) THEN
     636              : 
     637         8134 :             CALL p_env_check_i_alloc(p_env, qs_env)
     638              : 
     639         8134 :             CALL p_env_update_rho(p_env, qs_env)
     640              : 
     641         8134 :             CALL get_qs_env(qs_env, rho=rho) ! that could be called before
     642         8134 :             CALL qs_rho_update_rho(rho, qs_env=qs_env) ! that could be called before
     643         8134 :             IF (dft_control%qs_control%gapw) THEN
     644         1014 :                CALL prepare_gapw_den(qs_env)
     645         7120 :             ELSEIF (dft_control%qs_control%gapw_xc) THEN
     646          414 :                CALL prepare_gapw_den(qs_env, do_rho0=.FALSE.)
     647              :             END IF
     648              : 
     649        17244 :             DO ispin = 1, nspins
     650         9110 :                CALL dbcsr_set(p_env%kpp1(ispin)%matrix, 0.0_dp)
     651        17244 :                IF (ASSOCIATED(p_env%kpp1_admm)) CALL dbcsr_set(p_env%kpp1_admm(ispin)%matrix, 0.0_dp)
     652              :             END DO
     653              : 
     654         8134 :             CALL apply_op_2(qs_env, p_env, c0, Av)
     655              : 
     656              :          END IF
     657              : 
     658              :       END IF
     659              : 
     660        33952 :       CALL timestop(handle)
     661              : 
     662        33952 :    END SUBROUTINE apply_op
     663              : 
     664              : ! **************************************************************************************************
     665              : !> \brief ...
     666              : !> \param v ...
     667              : !> \param Av ...
     668              : !> \param matrix_ks ...
     669              : !> \param matrix_s ...
     670              : !> \param chc ...
     671              : ! **************************************************************************************************
     672       146946 :    SUBROUTINE apply_op_1(v, Av, matrix_ks, matrix_s, chc)
     673              :       !
     674              :       TYPE(cp_fm_type), INTENT(IN)                       :: v
     675              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: Av
     676              :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_ks, matrix_s
     677              :       TYPE(cp_fm_type), INTENT(IN)                       :: chc
     678              : 
     679              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'apply_op_1'
     680              : 
     681              :       INTEGER                                            :: handle, ncol, nrow
     682              :       TYPE(cp_fm_type)                                   :: buf
     683              : 
     684        48982 :       CALL timeset(routineN, handle)
     685              :       !
     686        48982 :       CALL cp_fm_create(buf, v%matrix_struct)
     687              :       !
     688        48982 :       CALL cp_fm_get_info(v, ncol_global=ncol, nrow_global=nrow)
     689              :       ! H * v
     690        48982 :       CALL cp_dbcsr_sm_fm_multiply(matrix_ks, v, Av, ncol)
     691              :       ! v * e  (chc already multiplied by -1)
     692        48982 :       CALL parallel_gemm('N', 'N', nrow, ncol, ncol, 1.0_dp, v, chc, 0.0_dp, buf)
     693              :       ! S * ve
     694        48982 :       CALL cp_dbcsr_sm_fm_multiply(matrix_s, buf, Av, ncol, alpha=1.0_dp, beta=1.0_dp)
     695              :       !Results is H*C1 - S*<iHj>*C1
     696              :       !
     697        48982 :       CALL cp_fm_release(buf)
     698              :       !
     699        48982 :       CALL timestop(handle)
     700              :       !
     701        48982 :    END SUBROUTINE apply_op_1
     702              : 
     703              : !MERGE
     704              : ! **************************************************************************************************
     705              : !> \brief ...
     706              : !> \param v ...
     707              : !> \param psi0 ...
     708              : !> \param S_psi0 ...
     709              : ! **************************************************************************************************
     710        10200 :    SUBROUTINE preortho(v, psi0, S_psi0)
     711              :       !v = (I-PS)v
     712              :       !
     713              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: v, psi0, S_psi0
     714              : 
     715              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'preortho'
     716              : 
     717              :       INTEGER                                            :: handle, ispin, mp, mt, mv, np, nspins, &
     718              :                                                             nt, nv
     719              :       TYPE(cp_fm_struct_type), POINTER                   :: tmp_fm_struct
     720              :       TYPE(cp_fm_type)                                   :: buf
     721              : 
     722        10200 :       CALL timeset(routineN, handle)
     723              :       !
     724        10200 :       NULLIFY (tmp_fm_struct)
     725              :       !
     726        10200 :       nspins = SIZE(v, 1)
     727              :       !
     728        24528 :       DO ispin = 1, nspins
     729        14328 :          CALL cp_fm_get_info(v(ispin), ncol_global=mv, nrow_global=nv)
     730        14328 :          CALL cp_fm_get_info(psi0(ispin), ncol_global=mp, nrow_global=np)
     731              :          !
     732              :          CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nv, ncol_global=mp, &
     733              :                                   para_env=v(ispin)%matrix_struct%para_env, &
     734        14328 :                                   context=v(ispin)%matrix_struct%context)
     735        14328 :          CALL cp_fm_create(buf, tmp_fm_struct)
     736        14328 :          CALL cp_fm_struct_release(tmp_fm_struct)
     737              :          !
     738        14328 :          CALL cp_fm_get_info(buf, ncol_global=mt, nrow_global=nt)
     739        14328 :          CPASSERT(nv == np)
     740        14328 :          CPASSERT(mt >= mv)
     741        14328 :          CPASSERT(mt >= mp)
     742        14328 :          CPASSERT(nt == nv)
     743              :          !
     744              :          ! buf = v' * S_psi0
     745        14328 :          CALL parallel_gemm('T', 'N', mv, mp, nv, 1.0_dp, v(ispin), S_psi0(ispin), 0.0_dp, buf)
     746              :          ! v = v - psi0 * buf'
     747        14328 :          CALL parallel_gemm('N', 'T', nv, mv, mp, -1.0_dp, psi0(ispin), buf, 1.0_dp, v(ispin))
     748              :          !
     749        67512 :          CALL cp_fm_release(buf)
     750              :       END DO
     751              :       !
     752        10200 :       CALL timestop(handle)
     753              :       !
     754        10200 :    END SUBROUTINE preortho
     755              : 
     756              : ! **************************************************************************************************
     757              : !> \brief projects first index of v onto the virtual subspace
     758              : !> \param v matrix to be projected
     759              : !> \param psi0 matrix with occupied orbitals
     760              : !> \param S_psi0 matrix containing product of metric and occupied orbitals
     761              : ! **************************************************************************************************
     762        62392 :    SUBROUTINE postortho(v, psi0, S_psi0)
     763              :       !v = (I-SP)v
     764              :       !
     765              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: v, psi0, S_psi0
     766              : 
     767              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'postortho'
     768              : 
     769              :       INTEGER                                            :: handle, ispin, mp, mt, mv, np, nspins, &
     770              :                                                             nt, nv
     771              :       TYPE(cp_fm_struct_type), POINTER                   :: tmp_fm_struct
     772              :       TYPE(cp_fm_type)                                   :: buf
     773              : 
     774        62392 :       CALL timeset(routineN, handle)
     775              :       !
     776        62392 :       NULLIFY (tmp_fm_struct)
     777              :       !
     778        62392 :       nspins = SIZE(v, 1)
     779              :       !
     780       152712 :       DO ispin = 1, nspins
     781        90320 :          CALL cp_fm_get_info(v(ispin), ncol_global=mv, nrow_global=nv)
     782        90320 :          CALL cp_fm_get_info(psi0(ispin), ncol_global=mp, nrow_global=np)
     783              :          !
     784              :          CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nv, ncol_global=mp, &
     785              :                                   para_env=v(ispin)%matrix_struct%para_env, &
     786        90320 :                                   context=v(ispin)%matrix_struct%context)
     787        90320 :          CALL cp_fm_create(buf, tmp_fm_struct)
     788        90320 :          CALL cp_fm_struct_release(tmp_fm_struct)
     789              :          !
     790        90320 :          CALL cp_fm_get_info(buf, ncol_global=mt, nrow_global=nt)
     791        90320 :          CPASSERT(nv == np)
     792        90320 :          CPASSERT(mt >= mv)
     793        90320 :          CPASSERT(mt >= mp)
     794        90320 :          CPASSERT(nt == nv)
     795              :          !
     796              :          ! buf = v' * psi0
     797        90320 :          CALL parallel_gemm('T', 'N', mv, mp, nv, 1.0_dp, v(ispin), psi0(ispin), 0.0_dp, buf)
     798              :          ! v = v - S_psi0 * buf'
     799        90320 :          CALL parallel_gemm('N', 'T', nv, mv, mp, -1.0_dp, S_psi0(ispin), buf, 1.0_dp, v(ispin))
     800              :          !
     801       423672 :          CALL cp_fm_release(buf)
     802              :       END DO
     803              :       !
     804        62392 :       CALL timestop(handle)
     805              :       !
     806        62392 :    END SUBROUTINE postortho
     807              : 
     808              : ! **************************************************************************************************
     809              : !> \brief ...
     810              : !> \param qs_env ...
     811              : !> \param linres_section ...
     812              : !> \param vec ...
     813              : !> \param ivec ...
     814              : !> \param tag ...
     815              : !> \param ind ...
     816              : ! **************************************************************************************************
     817         3522 :    SUBROUTINE linres_write_restart(qs_env, linres_section, vec, ivec, tag, ind)
     818              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     819              :       TYPE(section_vals_type), POINTER                   :: linres_section
     820              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: vec
     821              :       INTEGER, INTENT(IN)                                :: ivec
     822              :       CHARACTER(LEN=*)                                   :: tag
     823              :       INTEGER, INTENT(IN), OPTIONAL                      :: ind
     824              : 
     825              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'linres_write_restart'
     826              : 
     827              :       CHARACTER(LEN=default_path_length)                 :: filename
     828              :       CHARACTER(LEN=default_string_length)               :: my_middle, my_pos, my_status
     829              :       INTEGER                                            :: handle, i, i_block, ia, ie, iounit, &
     830              :                                                             ispin, j, max_block, nao, nmo, nspins, &
     831              :                                                             rst_unit
     832         3522 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: vecbuffer
     833              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     834              :       TYPE(cp_logger_type), POINTER                      :: logger
     835         3522 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     836              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     837              :       TYPE(section_vals_type), POINTER                   :: print_key
     838              : 
     839         3522 :       NULLIFY (logger, mo_coeff, mos, para_env, print_key, vecbuffer)
     840              : 
     841         3522 :       CALL timeset(routineN, handle)
     842              : 
     843         3522 :       logger => cp_get_default_logger()
     844              : 
     845         3522 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, linres_section, "PRINT%RESTART", &
     846              :                                            used_print_key=print_key), &
     847              :                 cp_p_file)) THEN
     848              : 
     849              :          iounit = cp_print_key_unit_nr(logger, linres_section, &
     850         3522 :                                        "PRINT%PROGRAM_RUN_INFO", extension=".Log")
     851              : 
     852              :          CALL get_qs_env(qs_env=qs_env, &
     853              :                          mos=mos, &
     854         3522 :                          para_env=para_env)
     855              : 
     856         3522 :          nspins = SIZE(mos)
     857              : 
     858         3522 :          my_status = "REPLACE"
     859         3522 :          my_pos = "REWIND"
     860         3522 :          CALL XSTRING(tag, ia, ie)
     861         3522 :          IF (PRESENT(ind)) THEN
     862         2460 :             my_middle = "RESTART-"//tag(ia:ie)//TRIM(ADJUSTL(cp_to_string(ivec)))
     863              :          ELSE
     864         1062 :             my_middle = "RESTART-"//tag(ia:ie)
     865         1062 :             IF (ivec > 1) THEN
     866          708 :                my_status = "OLD"
     867          708 :                my_pos = "APPEND"
     868              :             END IF
     869              :          END IF
     870              :          rst_unit = cp_print_key_unit_nr(logger, linres_section, "PRINT%RESTART", &
     871              :                                          extension=".lr", middle_name=TRIM(my_middle), file_status=TRIM(my_status), &
     872         3522 :                                          file_position=TRIM(my_pos), file_action="WRITE", file_form="UNFORMATTED")
     873              : 
     874              :          filename = cp_print_key_generate_filename(logger, print_key, &
     875         3522 :                                                    extension=".lr", middle_name=TRIM(my_middle), my_local=.FALSE.)
     876              : 
     877         3522 :          IF (iounit > 0) THEN
     878              :             WRITE (UNIT=iounit, FMT="(T2,A)") &
     879         1761 :                "LINRES| Writing response functions to the restart file <"//TRIM(ADJUSTL(filename))//">"
     880              :          END IF
     881              : 
     882              :          !
     883              :          ! write data to file
     884              :          ! use the scalapack block size as a default for buffering columns
     885         3522 :          CALL get_mo_set(mos(1), mo_coeff=mo_coeff)
     886         3522 :          CALL cp_fm_get_info(mo_coeff, nrow_global=nao, ncol_block=max_block)
     887        14088 :          ALLOCATE (vecbuffer(nao, max_block))
     888              : 
     889         3522 :          IF (PRESENT(ind)) THEN
     890         2460 :             IF (rst_unit > 0) WRITE (rst_unit) ind, ivec, nspins, nao
     891              :          ELSE
     892         1062 :             IF (rst_unit > 0) WRITE (rst_unit) ivec, nspins, nao
     893              :          END IF
     894              : 
     895         8934 :          DO ispin = 1, nspins
     896         5412 :             CALL cp_fm_get_info(vec(ispin), ncol_global=nmo)
     897              : 
     898         5412 :             IF (rst_unit > 0) WRITE (rst_unit) nmo
     899              : 
     900        22494 :             DO i = 1, nmo, MAX(max_block, 1)
     901         8148 :                i_block = MIN(max_block, nmo - i + 1)
     902         8148 :                CALL cp_fm_get_submatrix(vec(ispin), vecbuffer, 1, i, nao, i_block)
     903              :                ! doing this in one write would increase efficiency, but breaks RESTART compatibility.
     904              :                ! to old ones, and in cases where max_block is different between runs, as might happen during
     905              :                ! restarts with a different number of CPUs
     906        50352 :                DO j = 1, i_block
     907        44940 :                   IF (rst_unit > 0) WRITE (rst_unit) vecbuffer(1:nao, j)
     908              :                END DO
     909              :             END DO
     910              :          END DO
     911              : 
     912         3522 :          DEALLOCATE (vecbuffer)
     913              : 
     914              :          CALL cp_print_key_finished_output(rst_unit, logger, linres_section, &
     915         7044 :                                            "PRINT%RESTART")
     916              :       END IF
     917              : 
     918         3522 :       CALL timestop(handle)
     919              : 
     920         3522 :    END SUBROUTINE linres_write_restart
     921              : 
     922              : ! **************************************************************************************************
     923              : !> \brief ...
     924              : !> \param qs_env ...
     925              : !> \param linres_section ...
     926              : !> \param vec ...
     927              : !> \param ivec ...
     928              : !> \param tag ...
     929              : !> \param ind ...
     930              : ! **************************************************************************************************
     931           72 :    SUBROUTINE linres_read_restart(qs_env, linres_section, vec, ivec, tag, ind)
     932              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     933              :       TYPE(section_vals_type), POINTER                   :: linres_section
     934              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: vec
     935              :       INTEGER, INTENT(IN)                                :: ivec
     936              :       CHARACTER(LEN=*)                                   :: tag
     937              :       INTEGER, INTENT(INOUT), OPTIONAL                   :: ind
     938              : 
     939              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'linres_read_restart'
     940              : 
     941              :       CHARACTER(LEN=default_path_length)                 :: filename
     942              :       CHARACTER(LEN=default_string_length)               :: my_middle
     943              :       INTEGER :: handle, i, i_block, ia, ie, iostat, iounit, ispin, iv, iv1, ivec_tmp, j, &
     944              :          max_block, n_rep_val, nao, nao_tmp, nmo, nmo_tmp, nspins, nspins_tmp, rst_unit
     945              :       LOGICAL                                            :: file_exists
     946           72 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: vecbuffer
     947              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     948              :       TYPE(cp_logger_type), POINTER                      :: logger
     949           72 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     950              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     951              :       TYPE(section_vals_type), POINTER                   :: print_key
     952              : 
     953           72 :       file_exists = .FALSE.
     954              : 
     955           72 :       CALL timeset(routineN, handle)
     956              : 
     957           72 :       NULLIFY (mos, para_env, logger, print_key, vecbuffer)
     958           72 :       logger => cp_get_default_logger()
     959              : 
     960              :       iounit = cp_print_key_unit_nr(logger, linres_section, &
     961           72 :                                     "PRINT%PROGRAM_RUN_INFO", extension=".Log")
     962              : 
     963              :       CALL get_qs_env(qs_env=qs_env, &
     964              :                       para_env=para_env, &
     965           72 :                       mos=mos)
     966              : 
     967           72 :       nspins = SIZE(mos)
     968              : 
     969           72 :       rst_unit = -1
     970           72 :       IF (para_env%is_source()) THEN
     971              :          CALL section_vals_val_get(linres_section, "WFN_RESTART_FILE_NAME", &
     972           36 :                                    n_rep_val=n_rep_val)
     973              : 
     974           36 :          CALL XSTRING(tag, ia, ie)
     975           36 :          IF (PRESENT(ind)) THEN
     976            9 :             my_middle = "RESTART-"//tag(ia:ie)//TRIM(ADJUSTL(cp_to_string(ivec)))
     977              :          ELSE
     978           27 :             my_middle = "RESTART-"//tag(ia:ie)
     979              :          END IF
     980              : 
     981           36 :          IF (n_rep_val > 0) THEN
     982           18 :             CALL section_vals_val_get(linres_section, "WFN_RESTART_FILE_NAME", c_val=filename)
     983           18 :             CALL xstring(filename, ia, ie)
     984           18 :             filename = filename(ia:ie)//TRIM(my_middle)//".lr"
     985              :          ELSE
     986              :             ! try to read from the filename that is generated automatically from the printkey
     987           18 :             print_key => section_vals_get_subs_vals(linres_section, "PRINT%RESTART")
     988              :             filename = cp_print_key_generate_filename(logger, print_key, &
     989           18 :                                                       extension=".lr", middle_name=TRIM(my_middle), my_local=.FALSE.)
     990              :          END IF
     991           36 :          INQUIRE (FILE=filename, exist=file_exists)
     992              :          !
     993              :          ! open file
     994           36 :          IF (file_exists) THEN
     995              :             CALL open_file(file_name=TRIM(filename), &
     996              :                            file_action="READ", &
     997              :                            file_form="UNFORMATTED", &
     998              :                            file_position="REWIND", &
     999              :                            file_status="OLD", &
    1000           15 :                            unit_number=rst_unit)
    1001              : 
    1002           15 :             IF (iounit > 0) WRITE (iounit, "(T2,A)") &
    1003           15 :                "LINRES| Reading response wavefunctions from the restart file <"//TRIM(ADJUSTL(filename))//">"
    1004              :          ELSE
    1005           21 :             IF (iounit > 0) WRITE (iounit, "(T2,A)") &
    1006           21 :                "LINRES| Restart file  <"//TRIM(ADJUSTL(filename))//"> not found"
    1007              :          END IF
    1008              :       END IF
    1009              : 
    1010           72 :       CALL para_env%bcast(file_exists)
    1011              : 
    1012           72 :       IF (file_exists) THEN
    1013              : 
    1014           30 :          CALL get_mo_set(mos(1), mo_coeff=mo_coeff)
    1015           30 :          CALL cp_fm_get_info(mo_coeff, nrow_global=nao, ncol_block=max_block)
    1016              : 
    1017          120 :          ALLOCATE (vecbuffer(nao, max_block))
    1018              :          !
    1019              :          ! read headers
    1020           30 :          IF (PRESENT(ind)) THEN
    1021            6 :             iv1 = ivec
    1022              :          ELSE
    1023              :             iv1 = 1
    1024              :          END IF
    1025           54 :          DO iv = iv1, ivec
    1026              : 
    1027           54 :             IF (PRESENT(ind)) THEN
    1028            6 :                IF (rst_unit > 0) READ (rst_unit, IOSTAT=iostat) ind, ivec_tmp, nspins_tmp, nao_tmp
    1029            6 :                CALL para_env%bcast(iostat)
    1030            6 :                CALL para_env%bcast(ind)
    1031              :             ELSE
    1032           48 :                IF (rst_unit > 0) READ (rst_unit, IOSTAT=iostat) ivec_tmp, nspins_tmp, nao_tmp
    1033           48 :                CALL para_env%bcast(iostat)
    1034              :             END IF
    1035              : 
    1036           54 :             IF (iostat /= 0) EXIT
    1037           54 :             CALL para_env%bcast(ivec_tmp)
    1038           54 :             CALL para_env%bcast(nspins_tmp)
    1039           54 :             CALL para_env%bcast(nao_tmp)
    1040              : 
    1041              :             ! check that the number nao, nmo and nspins are
    1042              :             ! the same as in the current mos
    1043           54 :             IF (nspins_tmp /= nspins) CPABORT("nspins not consistent")
    1044           54 :             IF (nao_tmp /= nao) CPABORT("nao not consistent")
    1045              :             !
    1046          108 :             DO ispin = 1, nspins
    1047           54 :                CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff)
    1048           54 :                CALL cp_fm_get_info(mo_coeff, ncol_global=nmo)
    1049              :                !
    1050           54 :                IF (rst_unit > 0) READ (rst_unit) nmo_tmp
    1051           54 :                CALL para_env%bcast(nmo_tmp)
    1052           54 :                IF (nmo_tmp /= nmo) CPABORT("nmo not consistent")
    1053              :                !
    1054              :                ! read the response
    1055          216 :                DO i = 1, nmo, MAX(max_block, 1)
    1056           54 :                   i_block = MIN(max_block, nmo - i + 1)
    1057          270 :                   DO j = 1, i_block
    1058          270 :                      IF (rst_unit > 0) READ (rst_unit) vecbuffer(1:nao, j)
    1059              :                   END DO
    1060          108 :                   IF (iv == ivec_tmp) THEN
    1061        10422 :                      CALL para_env%bcast(vecbuffer)
    1062           54 :                      CALL cp_fm_set_submatrix(vec(ispin), vecbuffer, 1, i, nao, i_block)
    1063              :                   END IF
    1064              :                END DO
    1065              :             END DO
    1066           54 :             IF (ivec == ivec_tmp) EXIT
    1067              :          END DO
    1068              : 
    1069           30 :          IF (iostat /= 0) THEN
    1070            0 :             IF (iounit > 0) WRITE (iounit, "(T2,A)") &
    1071            0 :                "LINRES| Restart file <"//TRIM(ADJUSTL(filename))//"> not found"
    1072              :          END IF
    1073              : 
    1074           60 :          DEALLOCATE (vecbuffer)
    1075              : 
    1076              :       END IF
    1077              : 
    1078           72 :       IF (para_env%is_source()) THEN
    1079           36 :          IF (file_exists) CALL close_file(unit_number=rst_unit)
    1080              :       END IF
    1081              : 
    1082           72 :       CALL timestop(handle)
    1083              : 
    1084           72 :    END SUBROUTINE linres_read_restart
    1085              : 
    1086              : ! **************************************************************************************************
    1087              : !> \brief ...
    1088              : !> \param p_env ...
    1089              : !> \param linres_control ...
    1090              : !> \param nspins ...
    1091              : ! **************************************************************************************************
    1092         5100 :    SUBROUTINE check_p_env_init(p_env, linres_control, nspins)
    1093              :       !
    1094              :       TYPE(qs_p_env_type)                                :: p_env
    1095              :       TYPE(linres_control_type), INTENT(IN)              :: linres_control
    1096              :       INTEGER, INTENT(IN)                                :: nspins
    1097              : 
    1098              :       INTEGER                                            :: ispin, ncol, nrow
    1099              : 
    1100         5100 :       IF (linres_control%preconditioner_type /= ot_precond_none) THEN
    1101         5100 :          CPASSERT(ASSOCIATED(p_env%preconditioner))
    1102        12264 :          DO ispin = 1, nspins
    1103         7164 :             CALL cp_fm_get_info(p_env%PS_psi0(ispin), nrow_global=nrow, ncol_global=ncol)
    1104         7164 :             CPASSERT(nrow == p_env%n_ao(ispin))
    1105        19428 :             CPASSERT(ncol == p_env%n_mo(ispin))
    1106              :          END DO
    1107              :       END IF
    1108              : 
    1109         5100 :    END SUBROUTINE check_p_env_init
    1110              : 
    1111              : END MODULE qs_linres_methods
        

Generated by: LCOV version 2.0-1